From 03ebb419b896e0fb2da3f34b57d45e62cafe4009 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Fri, 9 Feb 2018 09:39:16 +0530 Subject: cxl: Enable NORST bit in PSL_DEBUG register for PSL9 We enable the NORST bit by default for debug afu images to prevent reset of AFU trace-data on a PCI link drop. For production AFU images this bit is always ignored and PSL gets reconfigured anyways thereby resetting the trace data. So setting this bit for non-debug images doesn't have any impact. Signed-off-by: Vaibhav Jain Reviewed-by: Christophe Lombard Acked-by: Frederic Barrat Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/pci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 758842f65a1b..c983f23cc2ed 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -503,8 +503,12 @@ static int init_implementation_adapter_regs_psl9(struct cxl *adapter, if (cxl_is_power9_dd1()) { /* Disabling deadlock counter CAR */ cxl_p1_write(adapter, CXL_PSL9_GP_CT, 0x0020000000000001ULL); - } else - cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0x4000000000000000ULL); + /* Enable NORST */ + cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0x8000000000000000ULL); + } else { + /* Enable NORST and DD2 features */ + cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0xC000000000000000ULL); + } return 0; } -- cgit From 02b63b420223db3e33e19cc0aaf346371e8efe48 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Thu, 15 Feb 2018 11:49:36 +0530 Subject: cxl: Remove function write_timebase_ctrl_psl9() for PSL9 For PSL9 the contents of PSL_TB_CTLSTAT register have changed in PSL9 and all of the register is now readonly. Hence we don't need an sl_ops implementation for 'write_timebase_ctrl' for to populate this register for PSL9. Hence this patch removes function write_timebase_ctrl_psl9() and its references from the code. Signed-off-by: Vaibhav Jain Acked-by: Andrew Donnellan Acked-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/cxl/pci.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index c983f23cc2ed..9bc30c20b66b 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -572,12 +572,6 @@ static int init_implementation_adapter_regs_xsl(struct cxl *adapter, struct pci_ /* For the PSL this is a multiple for 0 < n <= 7: */ #define PSL_2048_250MHZ_CYCLES 1 -static void write_timebase_ctrl_psl9(struct cxl *adapter) -{ - cxl_p1_write(adapter, CXL_PSL9_TB_CTLSTAT, - TBSYNC_CNT(2 * PSL_2048_250MHZ_CYCLES)); -} - static void write_timebase_ctrl_psl8(struct cxl *adapter) { cxl_p1_write(adapter, CXL_PSL_TB_CTLSTAT, @@ -639,7 +633,8 @@ static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev) * Setup PSL Timebase Control and Status register * with the recommended Timebase Sync Count value */ - adapter->native->sl_ops->write_timebase_ctrl(adapter); + if (adapter->native->sl_ops->write_timebase_ctrl) + adapter->native->sl_ops->write_timebase_ctrl(adapter); /* Enable PSL Timebase */ cxl_p1_write(adapter, CXL_PSL_Control, 0x0000000000000000); @@ -1805,7 +1800,6 @@ static const struct cxl_service_layer_ops psl9_ops = { .psl_irq_dump_registers = cxl_native_irq_dump_regs_psl9, .err_irq_dump_registers = cxl_native_err_irq_dump_regs_psl9, .debugfs_stop_trace = cxl_stop_trace_psl9, - .write_timebase_ctrl = write_timebase_ctrl_psl9, .timebase_read = timebase_read_psl9, .capi_mode = OPAL_PHB_CAPI_MODE_CAPI, .needs_reset_before_disable = true, -- cgit From 94322ed8e857e3b2a33cf75118051af9baaa110f Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Thu, 15 Feb 2018 21:19:24 +0530 Subject: cxl: Check if PSL data-cache is available before issue flush request PSL9D doesn't have a data-cache that needs to be flushed before resetting the card. However when cxl tries to flush data-cache on such a card, it times-out as PSL_Control register never indicates flush operation complete due to missing data-cache. This is usually indicated in the kernel logs with this message: "WARNING: cache flush timed out" To fix this the patch checks PSL_Debug register CDC-Field(BIT:27) which indicates the absence of a data-cache and sets a flag 'no_data_cache' in 'struct cxl_native' to indicate this. When cxl_data_cache_flush() is called it checks the flag and if set bails out early without requesting a data-cache flush operation to the PSL. Signed-off-by: Vaibhav Jain Acked-by: Andrew Donnellan Acked-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/cxl/cxl.h | 4 ++++ drivers/misc/cxl/native.c | 11 ++++++++++- drivers/misc/cxl/pci.c | 19 +++++++++++++------ 3 files changed, 27 insertions(+), 7 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index 4f015da78f28..4949b8d5a748 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -369,6 +369,9 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; #define CXL_PSL_TFC_An_AE (1ull << (63-30)) /* Restart PSL with address error */ #define CXL_PSL_TFC_An_R (1ull << (63-31)) /* Restart PSL transaction */ +/****** CXL_PSL_DEBUG *****************************************************/ +#define CXL_PSL_DEBUG_CDC (1ull << (63-27)) /* Coherent Data cache support */ + /****** CXL_XSL9_IERAT_ERAT - CAIA 2 **********************************/ #define CXL_XSL9_IERAT_MLPID (1ull << (63-0)) /* Match LPID */ #define CXL_XSL9_IERAT_MPID (1ull << (63-1)) /* Match PID */ @@ -669,6 +672,7 @@ struct cxl_native { irq_hw_number_t err_hwirq; unsigned int err_virq; u64 ps_off; + bool no_data_cache; /* set if no data cache on the card */ const struct cxl_service_layer_ops *sl_ops; }; diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index 1b3d7c65ea3f..98f867fcef24 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -353,8 +353,17 @@ int cxl_data_cache_flush(struct cxl *adapter) u64 reg; unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); - pr_devel("Flushing data cache\n"); + /* + * Do a datacache flush only if datacache is available. + * In case of PSL9D datacache absent hence flush operation. + * would timeout. + */ + if (adapter->native->no_data_cache) { + pr_devel("No PSL data cache. Ignoring cache flush req.\n"); + return 0; + } + pr_devel("Flushing data cache\n"); reg = cxl_p1_read(adapter, CXL_PSL_Control); reg |= CXL_PSL_Control_Fr; cxl_p1_write(adapter, CXL_PSL_Control, reg); diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 9bc30c20b66b..35f486912ddc 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -456,6 +456,7 @@ static int init_implementation_adapter_regs_psl9(struct cxl *adapter, u64 chipid; u32 phb_index; u64 capp_unit_id; + u64 psl_debug; int rc; rc = cxl_calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); @@ -510,6 +511,16 @@ static int init_implementation_adapter_regs_psl9(struct cxl *adapter, cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0xC000000000000000ULL); } + /* + * Check if PSL has data-cache. We need to flush adapter datacache + * when as its about to be removed. + */ + psl_debug = cxl_p1_read(adapter, CXL_PSL9_DEBUG); + if (psl_debug & CXL_PSL_DEBUG_CDC) { + dev_dbg(&dev->dev, "No data-cache present\n"); + adapter->native->no_data_cache = true; + } + return 0; } @@ -1448,10 +1459,8 @@ int cxl_pci_reset(struct cxl *adapter) /* * The adapter is about to be reset, so ignore errors. - * Not supported on P9 DD1 */ - if ((cxl_is_power8()) || (!(cxl_is_power9_dd1()))) - cxl_data_cache_flush(adapter); + cxl_data_cache_flush(adapter); /* pcie_warm_reset requests a fundamental pci reset which includes a * PERST assert/deassert. PERST triggers a loading of the image @@ -1934,10 +1943,8 @@ static void cxl_pci_remove_adapter(struct cxl *adapter) /* * Flush adapter datacache as its about to be removed. - * Not supported on P9 DD1. */ - if ((cxl_is_power8()) || (!(cxl_is_power9_dd1()))) - cxl_data_cache_flush(adapter); + cxl_data_cache_flush(adapter); cxl_deconfigure_adapter(adapter); -- cgit From 9dbcbfa1fe0c3b556e889ea213a73eb80d74307b Mon Sep 17 00:00:00 2001 From: Philippe Bergheaud Date: Fri, 2 Mar 2018 10:56:12 +0100 Subject: cxl: read PHB indications from the device tree Configure the P9 XSL_DSNCTL register with PHB indications found in the device tree, or else use legacy hard-coded values. Signed-off-by: Philippe Bergheaud Reviewed-by: Frederic Barrat Reviewed-by: Christophe Lombard Signed-off-by: Michael Ellerman --- drivers/misc/cxl/cxl.h | 2 +- drivers/misc/cxl/cxllib.c | 2 +- drivers/misc/cxl/pci.c | 48 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 45 insertions(+), 7 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index 4949b8d5a748..a4c9c8297a6d 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -1069,7 +1069,7 @@ int cxl_psl_purge(struct cxl_afu *afu); int cxl_calc_capp_routing(struct pci_dev *dev, u64 *chipid, u32 *phb_index, u64 *capp_unit_id); int cxl_slot_is_switched(struct pci_dev *dev); -int cxl_get_xsl9_dsnctl(u64 capp_unit_id, u64 *reg); +int cxl_get_xsl9_dsnctl(struct pci_dev *dev, u64 capp_unit_id, u64 *reg); u64 cxl_calculate_sr(bool master, bool kernel, bool real_mode, bool p9); void cxl_native_irq_dump_regs_psl9(struct cxl_context *ctx); diff --git a/drivers/misc/cxl/cxllib.c b/drivers/misc/cxl/cxllib.c index 30ccba436b3b..bea1eb004b49 100644 --- a/drivers/misc/cxl/cxllib.c +++ b/drivers/misc/cxl/cxllib.c @@ -99,7 +99,7 @@ int cxllib_get_xsl_config(struct pci_dev *dev, struct cxllib_xsl_config *cfg) if (rc) return rc; - rc = cxl_get_xsl9_dsnctl(capp_unit_id, &cfg->dsnctl); + rc = cxl_get_xsl9_dsnctl(dev, capp_unit_id, &cfg->dsnctl); if (rc) return rc; if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 35f486912ddc..e7ac78e85494 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -407,21 +407,59 @@ int cxl_calc_capp_routing(struct pci_dev *dev, u64 *chipid, return 0; } -int cxl_get_xsl9_dsnctl(u64 capp_unit_id, u64 *reg) +static DEFINE_MUTEX(indications_mutex); + +static int get_phb_indications(struct pci_dev *dev, u64 *capiind, u64 *asnind, + u64 *nbwind) +{ + static u64 nbw, asn, capi = 0; + struct device_node *np; + const __be32 *prop; + + mutex_lock(&indications_mutex); + if (!capi) { + if (!(np = pnv_pci_get_phb_node(dev))) { + mutex_unlock(&indications_mutex); + return -ENODEV; + } + + prop = of_get_property(np, "ibm,phb-indications", NULL); + if (!prop) { + nbw = 0x0300UL; /* legacy values */ + asn = 0x0400UL; + capi = 0x0200UL; + } else { + nbw = (u64)be32_to_cpu(prop[2]); + asn = (u64)be32_to_cpu(prop[1]); + capi = (u64)be32_to_cpu(prop[0]); + } + of_node_put(np); + } + *capiind = capi; + *asnind = asn; + *nbwind = nbw; + mutex_unlock(&indications_mutex); + return 0; +} + +int cxl_get_xsl9_dsnctl(struct pci_dev *dev, u64 capp_unit_id, u64 *reg) { u64 xsl_dsnctl; + u64 capiind, asnind, nbwind; /* * CAPI Identifier bits [0:7] * bit 61:60 MSI bits --> 0 * bit 59 TVT selector --> 0 */ + if (get_phb_indications(dev, &capiind, &asnind, &nbwind)) + return -ENODEV; /* * Tell XSL where to route data to. * The field chipid should match the PHB CAPI_CMPM register */ - xsl_dsnctl = ((u64)0x2 << (63-7)); /* Bit 57 */ + xsl_dsnctl = (capiind << (63-15)); /* Bit 57 */ xsl_dsnctl |= (capp_unit_id << (63-15)); /* nMMU_ID Defaults to: b’000001001’*/ @@ -435,14 +473,14 @@ int cxl_get_xsl9_dsnctl(u64 capp_unit_id, u64 *reg) * nbwind=0x03, bits [57:58], must include capi indicator. * Not supported on P9 DD1. */ - xsl_dsnctl |= ((u64)0x03 << (63-47)); + xsl_dsnctl |= (nbwind << (63-55)); /* * Upper 16b address bits of ASB_Notify messages sent to the * system. Need to match the PHB’s ASN Compare/Mask Register. * Not supported on P9 DD1. */ - xsl_dsnctl |= ((u64)0x04 << (63-55)); + xsl_dsnctl |= asnind; } *reg = xsl_dsnctl; @@ -463,7 +501,7 @@ static int init_implementation_adapter_regs_psl9(struct cxl *adapter, if (rc) return rc; - rc = cxl_get_xsl9_dsnctl(capp_unit_id, &xsl_dsnctl); + rc = cxl_get_xsl9_dsnctl(dev, capp_unit_id, &xsl_dsnctl); if (rc) return rc; -- cgit From c2be663d5307fb9751a562ac664fa78cd7a00e2b Mon Sep 17 00:00:00 2001 From: Christophe Lombard Date: Tue, 20 Feb 2018 14:48:56 +0100 Subject: cxl: Fix timebase synchronization status on P9 The PSL Timebase register is updated by the PSL to maintain the timebase. On P9, the Timebase value is only provided by the CAPP as received the last time a timebase request was performed. The timebase requests are initiated through the adapter configuration or application registers. The specific sysfs entry "/sys/class/cxl/cardxx/psl_timebase_synced" is now dynamically updated according the content of the PSL Timebase register. Fixes: f24be42aab37 ("cxl: Add psl9 specific code") Signed-off-by: Christophe Lombard Reviewed-by: Vaibhav Jain Acked-by: Andrew Donnellan Acked-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/cxl/pci.c | 17 ----------------- drivers/misc/cxl/sysfs.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index e7ac78e85494..83f1d08058fc 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -659,9 +659,6 @@ static u64 timebase_read_xsl(struct cxl *adapter) static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev) { - u64 psl_tb; - int delta; - unsigned int retry = 0; struct device_node *np; adapter->psl_timebase_synced = false; @@ -689,20 +686,6 @@ static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev) cxl_p1_write(adapter, CXL_PSL_Control, 0x0000000000000000); cxl_p1_write(adapter, CXL_PSL_Control, CXL_PSL_Control_tb); - /* Wait until CORE TB and PSL TB difference <= 16usecs */ - do { - msleep(1); - if (retry++ > 5) { - dev_info(&dev->dev, "PSL timebase can't synchronize\n"); - return; - } - psl_tb = adapter->native->sl_ops->timebase_read(adapter); - delta = mftb() - psl_tb; - if (delta < 0) - delta = -delta; - } while (tb_to_ns(delta) > 16000); - - adapter->psl_timebase_synced = true; return; } diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c index a8b6d6a635e9..95285b7f636f 100644 --- a/drivers/misc/cxl/sysfs.c +++ b/drivers/misc/cxl/sysfs.c @@ -62,7 +62,19 @@ static ssize_t psl_timebase_synced_show(struct device *device, char *buf) { struct cxl *adapter = to_cxl_adapter(device); + u64 psl_tb, delta; + /* Recompute the status only in native mode */ + if (cpu_has_feature(CPU_FTR_HVMODE)) { + psl_tb = adapter->native->sl_ops->timebase_read(adapter); + delta = abs(mftb() - psl_tb); + + /* CORE TB and PSL TB difference <= 16usecs ? */ + adapter->psl_timebase_synced = (tb_to_ns(delta) < 16000) ? true : false; + pr_devel("PSL timebase %s - delta: 0x%016llx\n", + (tb_to_ns(delta) < 16000) ? "synchronized" : + "not synchronized", tb_to_ns(delta)); + } return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced); } -- cgit From ad7b4e8022b9864c075fe71e1328b1d25cad82f6 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Tue, 3 Apr 2018 15:54:02 +0200 Subject: cxl: Fix possible deadlock when processing page faults from cxllib cxllib_handle_fault() is called by an external driver when it needs to have the host resolve page faults for a buffer. The buffer can cover several pages and VMAs. The function iterates over all the pages used by the buffer, based on the page size of the VMA. To ensure some stability while processing the faults, the thread T1 grabs the mm->mmap_sem semaphore with read access (R1). However, when processing a page fault for a single page, one of the underlying functions, copro_handle_mm_fault(), also grabs the same semaphore with read access (R2). So the thread T1 takes the semaphore twice. If another thread T2 tries to access the semaphore in write mode W1 (say, because it wants to allocate memory and calls 'brk'), then that thread T2 will have to wait because there's a reader (R1). If the thread T1 is processing a new page at that time, it won't get an automatic grant at R2, because there's now a writer thread waiting (T2). And we have a deadlock. The timeline is: 1. thread T1 owns the semaphore with read access R1 2. thread T2 requests write access W1 and waits 3. thread T1 requests read access R2 and waits The fix is for the thread T1 to release the semaphore R1 once it got the information it needs from the current VMA. The address space/VMAs could evolve while T1 iterates over the full buffer, but in the unlikely case where T1 misses a page, the external driver will raise a new page fault when retrying the memory access. Fixes: 3ced8d730063 ("cxl: Export library to support IBM XSL") Cc: stable@vger.kernel.org # 4.13+ Signed-off-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/cxl/cxllib.c | 85 ++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 30 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cxl/cxllib.c b/drivers/misc/cxl/cxllib.c index bea1eb004b49..0bc7c31cf739 100644 --- a/drivers/misc/cxl/cxllib.c +++ b/drivers/misc/cxl/cxllib.c @@ -208,49 +208,74 @@ int cxllib_get_PE_attributes(struct task_struct *task, } EXPORT_SYMBOL_GPL(cxllib_get_PE_attributes); -int cxllib_handle_fault(struct mm_struct *mm, u64 addr, u64 size, u64 flags) +static int get_vma_info(struct mm_struct *mm, u64 addr, + u64 *vma_start, u64 *vma_end, + unsigned long *page_size) { - int rc; - u64 dar; struct vm_area_struct *vma = NULL; - unsigned long page_size; - - if (mm == NULL) - return -EFAULT; + int rc = 0; down_read(&mm->mmap_sem); vma = find_vma(mm, addr); if (!vma) { - pr_err("Can't find vma for addr %016llx\n", addr); rc = -EFAULT; goto out; } - /* get the size of the pages allocated */ - page_size = vma_kernel_pagesize(vma); - - for (dar = (addr & ~(page_size - 1)); dar < (addr + size); dar += page_size) { - if (dar < vma->vm_start || dar >= vma->vm_end) { - vma = find_vma(mm, addr); - if (!vma) { - pr_err("Can't find vma for addr %016llx\n", addr); - rc = -EFAULT; - goto out; - } - /* get the size of the pages allocated */ - page_size = vma_kernel_pagesize(vma); + *page_size = vma_kernel_pagesize(vma); + *vma_start = vma->vm_start; + *vma_end = vma->vm_end; +out: + up_read(&mm->mmap_sem); + return rc; +} + +int cxllib_handle_fault(struct mm_struct *mm, u64 addr, u64 size, u64 flags) +{ + int rc; + u64 dar, vma_start, vma_end; + unsigned long page_size; + + if (mm == NULL) + return -EFAULT; + + /* + * The buffer we have to process can extend over several pages + * and may also cover several VMAs. + * We iterate over all the pages. The page size could vary + * between VMAs. + */ + rc = get_vma_info(mm, addr, &vma_start, &vma_end, &page_size); + if (rc) + return rc; + + for (dar = (addr & ~(page_size - 1)); dar < (addr + size); + dar += page_size) { + if (dar < vma_start || dar >= vma_end) { + /* + * We don't hold the mm->mmap_sem semaphore + * while iterating, since the semaphore is + * required by one of the lower-level page + * fault processing functions and it could + * create a deadlock. + * + * It means the VMAs can be altered between 2 + * loop iterations and we could theoretically + * miss a page (however unlikely). But that's + * not really a problem, as the driver will + * retry access, get another page fault on the + * missing page and call us again. + */ + rc = get_vma_info(mm, dar, &vma_start, &vma_end, + &page_size); + if (rc) + return rc; } rc = cxl_handle_mm_fault(mm, flags, dar); - if (rc) { - pr_err("cxl_handle_mm_fault failed %d", rc); - rc = -EFAULT; - goto out; - } + if (rc) + return -EFAULT; } - rc = 0; -out: - up_read(&mm->mmap_sem); - return rc; + return 0; } EXPORT_SYMBOL_GPL(cxllib_handle_fault); -- cgit