From a545cf032d11437ed86e62f00d499108d91cae54 Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Tue, 12 Jun 2018 01:59:04 +0530 Subject: ocxl: Change return type for fault handler Use new return type vm_fault_t for fault handler. For now, this is just documenting that the function returns a VM_FAULT value rather than an errno. Once all instances are converted, vm_fault_t will become a distinct type. Ref-> commit 1c8f422059ae ("mm: change return type to vm_fault_t") There is an existing bug when vm_insert_pfn() can return ENOMEM which was ignored and VM_FAULT_NOPAGE returned as default. The new inline vmf_insert_pfn() has removed this inefficiency by returning correct vm_fault_ type. Signed-off-by: Souptick Joarder Acked-by: Andrew Donnellan Acked-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/ocxl/context.c | 22 +++++++++++----------- drivers/misc/ocxl/sysfs.c | 5 ++--- 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ocxl/context.c b/drivers/misc/ocxl/context.c index 95f74623113e..c10a940e3b38 100644 --- a/drivers/misc/ocxl/context.c +++ b/drivers/misc/ocxl/context.c @@ -86,7 +86,7 @@ out: return rc; } -static int map_afu_irq(struct vm_area_struct *vma, unsigned long address, +static vm_fault_t map_afu_irq(struct vm_area_struct *vma, unsigned long address, u64 offset, struct ocxl_context *ctx) { u64 trigger_addr; @@ -95,15 +95,15 @@ static int map_afu_irq(struct vm_area_struct *vma, unsigned long address, if (!trigger_addr) return VM_FAULT_SIGBUS; - vm_insert_pfn(vma, address, trigger_addr >> PAGE_SHIFT); - return VM_FAULT_NOPAGE; + return vmf_insert_pfn(vma, address, trigger_addr >> PAGE_SHIFT); } -static int map_pp_mmio(struct vm_area_struct *vma, unsigned long address, +static vm_fault_t map_pp_mmio(struct vm_area_struct *vma, unsigned long address, u64 offset, struct ocxl_context *ctx) { u64 pp_mmio_addr; int pasid_off; + vm_fault_t ret; if (offset >= ctx->afu->config.pp_mmio_stride) return VM_FAULT_SIGBUS; @@ -121,27 +121,27 @@ static int map_pp_mmio(struct vm_area_struct *vma, unsigned long address, pasid_off * ctx->afu->config.pp_mmio_stride + offset; - vm_insert_pfn(vma, address, pp_mmio_addr >> PAGE_SHIFT); + ret = vmf_insert_pfn(vma, address, pp_mmio_addr >> PAGE_SHIFT); mutex_unlock(&ctx->status_mutex); - return VM_FAULT_NOPAGE; + return ret; } -static int ocxl_mmap_fault(struct vm_fault *vmf) +static vm_fault_t ocxl_mmap_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct ocxl_context *ctx = vma->vm_file->private_data; u64 offset; - int rc; + vm_fault_t ret; offset = vmf->pgoff << PAGE_SHIFT; pr_debug("%s: pasid %d address 0x%lx offset 0x%llx\n", __func__, ctx->pasid, vmf->address, offset); if (offset < ctx->afu->irq_base_offset) - rc = map_pp_mmio(vma, vmf->address, offset, ctx); + ret = map_pp_mmio(vma, vmf->address, offset, ctx); else - rc = map_afu_irq(vma, vmf->address, offset, ctx); - return rc; + ret = map_afu_irq(vma, vmf->address, offset, ctx); + return ret; } static const struct vm_operations_struct ocxl_vmops = { diff --git a/drivers/misc/ocxl/sysfs.c b/drivers/misc/ocxl/sysfs.c index d9753a1db14b..0ab1fd1b2682 100644 --- a/drivers/misc/ocxl/sysfs.c +++ b/drivers/misc/ocxl/sysfs.c @@ -64,7 +64,7 @@ static ssize_t global_mmio_read(struct file *filp, struct kobject *kobj, return count; } -static int global_mmio_fault(struct vm_fault *vmf) +static vm_fault_t global_mmio_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct ocxl_afu *afu = vma->vm_private_data; @@ -75,8 +75,7 @@ static int global_mmio_fault(struct vm_fault *vmf) offset = vmf->pgoff; offset += (afu->global_mmio_start >> PAGE_SHIFT); - vm_insert_pfn(vma, vmf->address, offset); - return VM_FAULT_NOPAGE; + return vmf_insert_pfn(vma, vmf->address, offset); } static const struct vm_operations_struct global_mmio_vmops = { -- cgit v1.2.3 From c5828150067c47a97f30e690a472e0548d3ac97d Mon Sep 17 00:00:00 2001 From: Alastair D'Silva Date: Thu, 28 Jun 2018 12:05:00 +0200 Subject: Revert "cxl: Add kernel API to allow a context to operate with relocate disabled" Remove abandonned capi support for the Mellanox CX4. The symbol 'cxl_set_translation_mode' is never called, so ctx->real_mode is always false. This reverts commit 7a0d85d313c2066712e530e668bc02bb741a685c. Signed-off-by: Alastair D'Silva Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/api.c | 19 ------------------- drivers/misc/cxl/cxl.h | 1 - drivers/misc/cxl/guest.c | 3 --- drivers/misc/cxl/native.c | 3 ++- include/misc/cxl.h | 8 -------- 5 files changed, 2 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index 753b1a698fc4..21d620e29fea 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -324,7 +324,6 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed, if (task) { ctx->pid = get_task_pid(task, PIDTYPE_PID); kernel = false; - ctx->real_mode = false; /* acquire a reference to the task's mm */ ctx->mm = get_task_mm(current); @@ -388,24 +387,6 @@ void cxl_set_master(struct cxl_context *ctx) } EXPORT_SYMBOL_GPL(cxl_set_master); -int cxl_set_translation_mode(struct cxl_context *ctx, bool real_mode) -{ - if (ctx->status == STARTED) { - /* - * We could potentially update the PE and issue an update LLCMD - * to support this, but it doesn't seem to have a good use case - * since it's trivial to just create a second kernel context - * with different translation modes, so until someone convinces - * me otherwise: - */ - return -EBUSY; - } - - ctx->real_mode = real_mode; - return 0; -} -EXPORT_SYMBOL_GPL(cxl_set_translation_mode); - /* wrappers around afu_* file ops which are EXPORTED */ int cxl_fd_open(struct inode *inode, struct file *file) { diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index 918d4fb742d1..af8794719956 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -613,7 +613,6 @@ struct cxl_context { bool pe_inserted; bool master; bool kernel; - bool real_mode; bool pending_irq; bool pending_fault; bool pending_afu_err; diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c index 4644f16606a3..f5dc740fcd13 100644 --- a/drivers/misc/cxl/guest.c +++ b/drivers/misc/cxl/guest.c @@ -623,9 +623,6 @@ static int guest_attach_process(struct cxl_context *ctx, bool kernel, u64 wed, u { pr_devel("in %s\n", __func__); - if (ctx->real_mode) - return -EPERM; - ctx->kernel = kernel; if (ctx->afu->current_mode == CXL_MODE_DIRECTED) return attach_afu_directed(ctx, wed, amr); diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index 98f867fcef24..c9d5d82dce8e 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -605,6 +605,7 @@ u64 cxl_calculate_sr(bool master, bool kernel, bool real_mode, bool p9) sr |= CXL_PSL_SR_An_MP; if (mfspr(SPRN_LPCR) & LPCR_TC) sr |= CXL_PSL_SR_An_TC; + if (kernel) { if (!real_mode) sr |= CXL_PSL_SR_An_R; @@ -629,7 +630,7 @@ u64 cxl_calculate_sr(bool master, bool kernel, bool real_mode, bool p9) static u64 calculate_sr(struct cxl_context *ctx) { - return cxl_calculate_sr(ctx->master, ctx->kernel, ctx->real_mode, + return cxl_calculate_sr(ctx->master, ctx->kernel, false, cxl_is_power9()); } diff --git a/include/misc/cxl.h b/include/misc/cxl.h index b712be544f8c..82cc6ffafe2d 100644 --- a/include/misc/cxl.h +++ b/include/misc/cxl.h @@ -173,14 +173,6 @@ int cxl_afu_reset(struct cxl_context *ctx); */ void cxl_set_master(struct cxl_context *ctx); -/* - * Sets the context to use real mode memory accesses to operate with - * translation disabled. Note that this only makes sense for kernel contexts - * under bare metal, and will not work with virtualisation. May only be - * performed on stopped contexts. - */ -int cxl_set_translation_mode(struct cxl_context *ctx, bool real_mode); - /* * Map and unmap the AFU Problem Space area. The amount and location mapped * depends on if this context is a master or slave. -- cgit v1.2.3 From 0cfd7335d1ebea42cf113fd22452f6a10d3960fe Mon Sep 17 00:00:00 2001 From: Alastair D'Silva Date: Thu, 28 Jun 2018 12:05:01 +0200 Subject: Revert "cxl: Add support for interrupts on the Mellanox CX4" Remove abandonned capi support for the Mellanox CX4. This reverts commit a2f67d5ee8d950caaa7a6144cf0bfb256500b73e. Signed-off-by: Alastair D'Silva Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/pci-cxl.c | 84 ------------------------------- arch/powerpc/platforms/powernv/pci-ioda.c | 4 -- arch/powerpc/platforms/powernv/pci.h | 2 - drivers/misc/cxl/api.c | 71 -------------------------- drivers/misc/cxl/base.c | 31 ------------ drivers/misc/cxl/cxl.h | 4 -- drivers/misc/cxl/main.c | 2 - include/misc/cxl-base.h | 4 -- 8 files changed, 202 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/platforms/powernv/pci-cxl.c b/arch/powerpc/platforms/powernv/pci-cxl.c index cee003de63af..c447b7f03c09 100644 --- a/arch/powerpc/platforms/powernv/pci-cxl.c +++ b/arch/powerpc/platforms/powernv/pci-cxl.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include @@ -292,86 +291,3 @@ void pnv_cxl_disable_device(struct pci_dev *dev) cxl_pci_disable_device(dev); cxl_afu_put(afu); } - -/* - * This is a special version of pnv_setup_msi_irqs for cards in cxl mode. This - * function handles setting up the IVTE entries for the XSL to use. - * - * We are currently not filling out the MSIX table, since the only currently - * supported adapter (CX4) uses a custom MSIX table format in cxl mode and it - * is up to their driver to fill that out. In the future we may fill out the - * MSIX table (and change the IVTE entries to be an index to the MSIX table) - * for adapters implementing the Full MSI-X mode described in the CAIA. - */ -int pnv_cxl_cx4_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) -{ - struct pci_controller *hose = pci_bus_to_host(pdev->bus); - struct pnv_phb *phb = hose->private_data; - struct msi_desc *entry; - struct cxl_context *ctx = NULL; - unsigned int virq; - int hwirq; - int afu_irq = 0; - int rc; - - if (WARN_ON(!phb) || !phb->msi_bmp.bitmap) - return -ENODEV; - - if (pdev->no_64bit_msi && !phb->msi32_support) - return -ENODEV; - - rc = cxl_cx4_setup_msi_irqs(pdev, nvec, type); - if (rc) - return rc; - - for_each_pci_msi_entry(entry, pdev) { - if (!entry->msi_attrib.is_64 && !phb->msi32_support) { - pr_warn("%s: Supports only 64-bit MSIs\n", - pci_name(pdev)); - return -ENXIO; - } - - hwirq = cxl_next_msi_hwirq(pdev, &ctx, &afu_irq); - if (WARN_ON(hwirq <= 0)) - return (hwirq ? hwirq : -ENOMEM); - - virq = irq_create_mapping(NULL, hwirq); - if (!virq) { - pr_warn("%s: Failed to map cxl mode MSI to linux irq\n", - pci_name(pdev)); - return -ENOMEM; - } - - rc = pnv_cxl_ioda_msi_setup(pdev, hwirq, virq); - if (rc) { - pr_warn("%s: Failed to setup cxl mode MSI\n", pci_name(pdev)); - irq_dispose_mapping(virq); - return rc; - } - - irq_set_msi_desc(virq, entry); - } - - return 0; -} - -void pnv_cxl_cx4_teardown_msi_irqs(struct pci_dev *pdev) -{ - struct pci_controller *hose = pci_bus_to_host(pdev->bus); - struct pnv_phb *phb = hose->private_data; - struct msi_desc *entry; - irq_hw_number_t hwirq; - - if (WARN_ON(!phb)) - return; - - for_each_pci_msi_entry(entry, pdev) { - if (!entry->irq) - continue; - hwirq = virq_to_hw(entry->irq); - irq_set_msi_desc(entry->irq, NULL); - irq_dispose_mapping(entry->irq); - } - - cxl_cx4_teardown_msi_irqs(pdev); -} diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index ab678177d36e..5b819c55868d 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -3847,10 +3847,6 @@ static const struct pci_controller_ops pnv_npu_ocapi_ioda_controller_ops = { const struct pci_controller_ops pnv_cxl_cx4_ioda_controller_ops = { .dma_dev_setup = pnv_pci_dma_dev_setup, .dma_bus_setup = pnv_pci_dma_bus_setup, -#ifdef CONFIG_PCI_MSI - .setup_msi_irqs = pnv_cxl_cx4_setup_msi_irqs, - .teardown_msi_irqs = pnv_cxl_cx4_teardown_msi_irqs, -#endif .enable_device_hook = pnv_cxl_enable_device_hook, .disable_device = pnv_cxl_disable_device, .release_device = pnv_pci_release_device, diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index eada4b6068cb..ba41913c7e21 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -265,8 +265,6 @@ extern int pnv_npu2_init(struct pnv_phb *phb); /* cxl functions */ extern bool pnv_cxl_enable_device_hook(struct pci_dev *dev); extern void pnv_cxl_disable_device(struct pci_dev *dev); -extern int pnv_cxl_cx4_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type); -extern void pnv_cxl_cx4_teardown_msi_irqs(struct pci_dev *pdev); /* phb ops (cxl switches these when enabling the kernel api on the phb) */ diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index 21d620e29fea..2e5862b7a074 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -595,73 +594,3 @@ int cxl_get_max_irqs_per_process(struct pci_dev *dev) return afu->irqs_max; } EXPORT_SYMBOL_GPL(cxl_get_max_irqs_per_process); - -/* - * This is a special interrupt allocation routine called from the PHB's MSI - * setup function. When capi interrupts are allocated in this manner they must - * still be associated with a running context, but since the MSI APIs have no - * way to specify this we use the default context associated with the device. - * - * The Mellanox CX4 has a hardware limitation that restricts the maximum AFU - * interrupt number, so in order to overcome this their driver informs us of - * the restriction by setting the maximum interrupts per context, and we - * allocate additional contexts as necessary so that we can keep the AFU - * interrupt number within the supported range. - */ -int _cxl_cx4_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) -{ - struct cxl_context *ctx, *new_ctx, *default_ctx; - int remaining; - int rc; - - ctx = default_ctx = cxl_get_context(pdev); - if (WARN_ON(!default_ctx)) - return -ENODEV; - - remaining = nvec; - while (remaining > 0) { - rc = cxl_allocate_afu_irqs(ctx, min(remaining, ctx->afu->irqs_max)); - if (rc) { - pr_warn("%s: Failed to find enough free MSIs\n", pci_name(pdev)); - return rc; - } - remaining -= ctx->afu->irqs_max; - - if (ctx != default_ctx && default_ctx->status == STARTED) { - WARN_ON(cxl_start_context(ctx, - be64_to_cpu(default_ctx->elem->common.wed), - NULL)); - } - - if (remaining > 0) { - new_ctx = cxl_dev_context_init(pdev); - if (IS_ERR(new_ctx)) { - pr_warn("%s: Failed to allocate enough contexts for MSIs\n", pci_name(pdev)); - return -ENOSPC; - } - list_add(&new_ctx->extra_irq_contexts, &ctx->extra_irq_contexts); - ctx = new_ctx; - } - } - - return 0; -} -/* Exported via cxl_base */ - -void _cxl_cx4_teardown_msi_irqs(struct pci_dev *pdev) -{ - struct cxl_context *ctx, *pos, *tmp; - - ctx = cxl_get_context(pdev); - if (WARN_ON(!ctx)) - return; - - cxl_free_afu_irqs(ctx); - list_for_each_entry_safe(pos, tmp, &ctx->extra_irq_contexts, extra_irq_contexts) { - cxl_stop_context(pos); - cxl_free_afu_irqs(pos); - list_del(&pos->extra_irq_contexts); - cxl_release_context(pos); - } -} -/* Exported via cxl_base */ diff --git a/drivers/misc/cxl/base.c b/drivers/misc/cxl/base.c index cd54ce6f6230..fe90f895bb10 100644 --- a/drivers/misc/cxl/base.c +++ b/drivers/misc/cxl/base.c @@ -158,37 +158,6 @@ int cxl_next_msi_hwirq(struct pci_dev *pdev, struct cxl_context **ctx, int *afu_ } EXPORT_SYMBOL_GPL(cxl_next_msi_hwirq); -int cxl_cx4_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) -{ - int ret; - struct cxl_calls *calls; - - calls = cxl_calls_get(); - if (!calls) - return false; - - ret = calls->cxl_cx4_setup_msi_irqs(pdev, nvec, type); - - cxl_calls_put(calls); - - return ret; -} -EXPORT_SYMBOL_GPL(cxl_cx4_setup_msi_irqs); - -void cxl_cx4_teardown_msi_irqs(struct pci_dev *pdev) -{ - struct cxl_calls *calls; - - calls = cxl_calls_get(); - if (!calls) - return; - - calls->cxl_cx4_teardown_msi_irqs(pdev); - - cxl_calls_put(calls); -} -EXPORT_SYMBOL_GPL(cxl_cx4_teardown_msi_irqs); - static int __init cxl_base_init(void) { struct device_node *np; diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index af8794719956..9688fe8b4d80 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -879,16 +879,12 @@ ssize_t cxl_pci_afu_read_err_buffer(struct cxl_afu *afu, char *buf, bool _cxl_pci_associate_default_context(struct pci_dev *dev, struct cxl_afu *afu); void _cxl_pci_disable_device(struct pci_dev *dev); int _cxl_next_msi_hwirq(struct pci_dev *pdev, struct cxl_context **ctx, int *afu_irq); -int _cxl_cx4_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type); -void _cxl_cx4_teardown_msi_irqs(struct pci_dev *pdev); struct cxl_calls { void (*cxl_slbia)(struct mm_struct *mm); bool (*cxl_pci_associate_default_context)(struct pci_dev *dev, struct cxl_afu *afu); void (*cxl_pci_disable_device)(struct pci_dev *dev); int (*cxl_next_msi_hwirq)(struct pci_dev *pdev, struct cxl_context **ctx, int *afu_irq); - int (*cxl_cx4_setup_msi_irqs)(struct pci_dev *pdev, int nvec, int type); - void (*cxl_cx4_teardown_msi_irqs)(struct pci_dev *pdev); struct module *owner; }; diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c index c1ba0d42cbc8..59a904efd104 100644 --- a/drivers/misc/cxl/main.c +++ b/drivers/misc/cxl/main.c @@ -107,8 +107,6 @@ static struct cxl_calls cxl_calls = { .cxl_pci_associate_default_context = _cxl_pci_associate_default_context, .cxl_pci_disable_device = _cxl_pci_disable_device, .cxl_next_msi_hwirq = _cxl_next_msi_hwirq, - .cxl_cx4_setup_msi_irqs = _cxl_cx4_setup_msi_irqs, - .cxl_cx4_teardown_msi_irqs = _cxl_cx4_teardown_msi_irqs, .owner = THIS_MODULE, }; diff --git a/include/misc/cxl-base.h b/include/misc/cxl-base.h index b2ebc91fe09a..bb7e629ae492 100644 --- a/include/misc/cxl-base.h +++ b/include/misc/cxl-base.h @@ -43,8 +43,6 @@ void cxl_afu_put(struct cxl_afu *afu); void cxl_slbia(struct mm_struct *mm); bool cxl_pci_associate_default_context(struct pci_dev *dev, struct cxl_afu *afu); void cxl_pci_disable_device(struct pci_dev *dev); -int cxl_cx4_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type); -void cxl_cx4_teardown_msi_irqs(struct pci_dev *pdev); #else /* CONFIG_CXL_BASE */ @@ -54,8 +52,6 @@ static inline void cxl_afu_put(struct cxl_afu *afu) {} static inline void cxl_slbia(struct mm_struct *mm) {} static inline bool cxl_pci_associate_default_context(struct pci_dev *dev, struct cxl_afu *afu) { return false; } static inline void cxl_pci_disable_device(struct pci_dev *dev) {} -static inline int cxl_cx4_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { return -ENODEV; } -static inline void cxl_cx4_teardown_msi_irqs(struct pci_dev *pdev) {} #endif /* CONFIG_CXL_BASE */ -- cgit v1.2.3 From 17d29039388807305ab02a4d6eae7cbe09f81f90 Mon Sep 17 00:00:00 2001 From: Alastair D'Silva Date: Thu, 28 Jun 2018 12:05:02 +0200 Subject: Revert "cxl: Add preliminary workaround for CX4 interrupt limitation" Remove abandonned capi support for the Mellanox CX4. This reverts commit cbce0917e2e47d4bf5aa3b5fd6b1247f33e1a126. Signed-off-by: Alastair D'Silva Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/api.c | 15 --------------- drivers/misc/cxl/base.c | 17 ----------------- drivers/misc/cxl/context.c | 1 - drivers/misc/cxl/cxl.h | 10 ---------- drivers/misc/cxl/main.c | 1 - include/misc/cxl.h | 20 -------------------- 6 files changed, 64 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index 2e5862b7a074..34ba67bc41bd 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -181,21 +181,6 @@ static irq_hw_number_t cxl_find_afu_irq(struct cxl_context *ctx, int num) return 0; } -int _cxl_next_msi_hwirq(struct pci_dev *pdev, struct cxl_context **ctx, int *afu_irq) -{ - if (*ctx == NULL || *afu_irq == 0) { - *afu_irq = 1; - *ctx = cxl_get_context(pdev); - } else { - (*afu_irq)++; - if (*afu_irq > cxl_get_max_irqs_per_process(pdev)) { - *ctx = list_next_entry(*ctx, extra_irq_contexts); - *afu_irq = 1; - } - } - return cxl_find_afu_irq(*ctx, *afu_irq); -} -/* Exported via cxl_base */ int cxl_set_priv(struct cxl_context *ctx, void *priv) { diff --git a/drivers/misc/cxl/base.c b/drivers/misc/cxl/base.c index fe90f895bb10..e1e80cb99ad9 100644 --- a/drivers/misc/cxl/base.c +++ b/drivers/misc/cxl/base.c @@ -141,23 +141,6 @@ void cxl_pci_disable_device(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(cxl_pci_disable_device); -int cxl_next_msi_hwirq(struct pci_dev *pdev, struct cxl_context **ctx, int *afu_irq) -{ - int ret; - struct cxl_calls *calls; - - calls = cxl_calls_get(); - if (!calls) - return -EBUSY; - - ret = calls->cxl_next_msi_hwirq(pdev, ctx, afu_irq); - - cxl_calls_put(calls); - - return ret; -} -EXPORT_SYMBOL_GPL(cxl_next_msi_hwirq); - static int __init cxl_base_init(void) { struct device_node *np; diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index c6ec872800a2..0355d42d367f 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -74,7 +74,6 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master) ctx->pending_afu_err = false; INIT_LIST_HEAD(&ctx->irq_names); - INIT_LIST_HEAD(&ctx->extra_irq_contexts); /* * When we have to destroy all contexts in cxl_context_detach_all() we diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index 9688fe8b4d80..d95c2c98f2ab 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -623,14 +623,6 @@ struct cxl_context { struct rcu_head rcu; - /* - * Only used when more interrupts are allocated via - * pci_enable_msix_range than are supported in the default context, to - * use additional contexts to overcome the limitation. i.e. Mellanox - * CX4 only: - */ - struct list_head extra_irq_contexts; - struct mm_struct *mm; u16 tidr; @@ -878,13 +870,11 @@ ssize_t cxl_pci_afu_read_err_buffer(struct cxl_afu *afu, char *buf, /* Internal functions wrapped in cxl_base to allow PHB to call them */ bool _cxl_pci_associate_default_context(struct pci_dev *dev, struct cxl_afu *afu); void _cxl_pci_disable_device(struct pci_dev *dev); -int _cxl_next_msi_hwirq(struct pci_dev *pdev, struct cxl_context **ctx, int *afu_irq); struct cxl_calls { void (*cxl_slbia)(struct mm_struct *mm); bool (*cxl_pci_associate_default_context)(struct pci_dev *dev, struct cxl_afu *afu); void (*cxl_pci_disable_device)(struct pci_dev *dev); - int (*cxl_next_msi_hwirq)(struct pci_dev *pdev, struct cxl_context **ctx, int *afu_irq); struct module *owner; }; diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c index 59a904efd104..a7e83624034b 100644 --- a/drivers/misc/cxl/main.c +++ b/drivers/misc/cxl/main.c @@ -106,7 +106,6 @@ static struct cxl_calls cxl_calls = { .cxl_slbia = cxl_slbia_core, .cxl_pci_associate_default_context = _cxl_pci_associate_default_context, .cxl_pci_disable_device = _cxl_pci_disable_device, - .cxl_next_msi_hwirq = _cxl_next_msi_hwirq, .owner = THIS_MODULE, }; diff --git a/include/misc/cxl.h b/include/misc/cxl.h index 82cc6ffafe2d..6a3711a2e217 100644 --- a/include/misc/cxl.h +++ b/include/misc/cxl.h @@ -183,26 +183,6 @@ void cxl_psa_unmap(void __iomem *addr); /* Get the process element for this context */ int cxl_process_element(struct cxl_context *ctx); -/* - * Limit the number of interrupts that a single context can allocate via - * cxl_start_work. If using the api with a real phb, this may be used to - * request that additional default contexts be created when allocating - * interrupts via pci_enable_msix_range. These will be set to the same running - * state as the default context, and if that is running it will reuse the - * parameters previously passed to cxl_start_context for the default context. - */ -int cxl_set_max_irqs_per_process(struct pci_dev *dev, int irqs); -int cxl_get_max_irqs_per_process(struct pci_dev *dev); - -/* - * Use to simultaneously iterate over hardware interrupt numbers, contexts and - * afu interrupt numbers allocated for the device via pci_enable_msix_range and - * is a useful convenience function when working with hardware that has - * limitations on the number of interrupts per process. *ctx and *afu_irq - * should be NULL and 0 to start the iteration. - */ -int cxl_next_msi_hwirq(struct pci_dev *pdev, struct cxl_context **ctx, int *afu_irq); - /* * These calls allow drivers to create their own file descriptors and make them * identical to the cxl file descriptor user API. An example use case: -- cgit v1.2.3 From 82c6ae67fbbef68c80c2a39d559dd649d7530cd6 Mon Sep 17 00:00:00 2001 From: Alastair D'Silva Date: Thu, 28 Jun 2018 12:05:03 +0200 Subject: Revert "cxl: Add kernel APIs to get & set the max irqs per context" Remove abandonned capi support for the Mellanox CX4. This reverts commit 79384e4b71240abf50c375eea56060b0d79c242a. Signed-off-by: Alastair D'Silva Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/api.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index 34ba67bc41bd..a535c1e6aa92 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -552,30 +552,3 @@ ssize_t cxl_read_adapter_vpd(struct pci_dev *dev, void *buf, size_t count) return cxl_ops->read_adapter_vpd(afu->adapter, buf, count); } EXPORT_SYMBOL_GPL(cxl_read_adapter_vpd); - -int cxl_set_max_irqs_per_process(struct pci_dev *dev, int irqs) -{ - struct cxl_afu *afu = cxl_pci_to_afu(dev); - if (IS_ERR(afu)) - return -ENODEV; - - if (irqs > afu->adapter->user_irqs) - return -EINVAL; - - /* Limit user_irqs to prevent the user increasing this via sysfs */ - afu->adapter->user_irqs = irqs; - afu->irqs_max = irqs; - - return 0; -} -EXPORT_SYMBOL_GPL(cxl_set_max_irqs_per_process); - -int cxl_get_max_irqs_per_process(struct pci_dev *dev) -{ - struct cxl_afu *afu = cxl_pci_to_afu(dev); - if (IS_ERR(afu)) - return -ENODEV; - - return afu->irqs_max; -} -EXPORT_SYMBOL_GPL(cxl_get_max_irqs_per_process); -- cgit v1.2.3 From 29fea8aa21a69418386e3e08fa546a0ba9bee96d Mon Sep 17 00:00:00 2001 From: Alastair D'Silva Date: Thu, 28 Jun 2018 12:05:04 +0200 Subject: Revert "cxl: Add cxl_check_and_switch_mode() API to switch bi-modal cards" Remove abandonned capi support for the Mellanox CX4. This reverts commit b0b5e5918ad1babfd1d43d98c7281926a7b57b9f. Signed-off-by: Alastair D'Silva Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/Kconfig | 8 -- drivers/misc/cxl/pci.c | 236 ++++------------------------------------------- include/misc/cxl.h | 25 ----- 3 files changed, 18 insertions(+), 251 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/Kconfig b/drivers/misc/cxl/Kconfig index 93397cb05b15..3ce933707828 100644 --- a/drivers/misc/cxl/Kconfig +++ b/drivers/misc/cxl/Kconfig @@ -33,11 +33,3 @@ config CXL CAPI adapters are found in POWER8 based systems. If unsure, say N. - -config CXL_BIMODAL - bool "Support for bi-modal CAPI cards" - depends on HOTPLUG_PCI_POWERNV = y && CXL || HOTPLUG_PCI_POWERNV = m && CXL = m - default y - help - Select this option to enable support for bi-modal CAPI cards, such as - the Mellanox CX-4. diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 429d6de1dde7..9c5a21fee835 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -55,8 +55,6 @@ pci_read_config_byte(dev, vsec + 0xa, dest) #define CXL_WRITE_VSEC_MODE_CONTROL(dev, vsec, val) \ pci_write_config_byte(dev, vsec + 0xa, val) -#define CXL_WRITE_VSEC_MODE_CONTROL_BUS(bus, devfn, vsec, val) \ - pci_bus_write_config_byte(bus, devfn, vsec + 0xa, val) #define CXL_VSEC_PROTOCOL_MASK 0xe0 #define CXL_VSEC_PROTOCOL_1024TB 0x80 #define CXL_VSEC_PROTOCOL_512TB 0x40 @@ -800,234 +798,36 @@ static int setup_cxl_bars(struct pci_dev *dev) return 0; } -#ifdef CONFIG_CXL_BIMODAL - -struct cxl_switch_work { - struct pci_dev *dev; - struct work_struct work; - int vsec; - int mode; -}; - -static void switch_card_to_cxl(struct work_struct *work) +/* pciex node: ibm,opal-m64-window = <0x3d058 0x0 0x3d058 0x0 0x8 0x0>; */ +static int switch_card_to_cxl(struct pci_dev *dev) { - struct cxl_switch_work *switch_work = - container_of(work, struct cxl_switch_work, work); - struct pci_dev *dev = switch_work->dev; - struct pci_bus *bus = dev->bus; - struct pci_controller *hose = pci_bus_to_host(bus); - struct pci_dev *bridge; - struct pnv_php_slot *php_slot; - unsigned int devfn; + int vsec; u8 val; int rc; - dev_info(&bus->dev, "cxl: Preparing for mode switch...\n"); - bridge = list_first_entry_or_null(&hose->bus->devices, struct pci_dev, - bus_list); - if (!bridge) { - dev_WARN(&bus->dev, "cxl: Couldn't find root port!\n"); - goto err_dev_put; - } + dev_info(&dev->dev, "switch card to CXL\n"); - php_slot = pnv_php_find_slot(pci_device_to_OF_node(bridge)); - if (!php_slot) { - dev_err(&bus->dev, "cxl: Failed to find slot hotplug " - "information. You may need to upgrade " - "skiboot. Aborting.\n"); - goto err_dev_put; - } - - rc = CXL_READ_VSEC_MODE_CONTROL(dev, switch_work->vsec, &val); - if (rc) { - dev_err(&bus->dev, "cxl: Failed to read CAPI mode control: %i\n", rc); - goto err_dev_put; - } - devfn = dev->devfn; - - /* Release the reference obtained in cxl_check_and_switch_mode() */ - pci_dev_put(dev); - - dev_dbg(&bus->dev, "cxl: Removing PCI devices from kernel\n"); - pci_lock_rescan_remove(); - pci_hp_remove_devices(bridge->subordinate); - pci_unlock_rescan_remove(); - - /* Switch the CXL protocol on the card */ - if (switch_work->mode == CXL_BIMODE_CXL) { - dev_info(&bus->dev, "cxl: Switching card to CXL mode\n"); - val &= ~CXL_VSEC_PROTOCOL_MASK; - val |= CXL_VSEC_PROTOCOL_256TB | CXL_VSEC_PROTOCOL_ENABLE; - rc = pnv_cxl_enable_phb_kernel_api(hose, true); - if (rc) { - dev_err(&bus->dev, "cxl: Failed to enable kernel API" - " on real PHB, aborting\n"); - goto err_free_work; - } - } else { - dev_WARN(&bus->dev, "cxl: Switching card to PCI mode not supported!\n"); - goto err_free_work; - } - - rc = CXL_WRITE_VSEC_MODE_CONTROL_BUS(bus, devfn, switch_work->vsec, val); - if (rc) { - dev_err(&bus->dev, "cxl: Failed to configure CXL protocol: %i\n", rc); - goto err_free_work; - } - - /* - * The CAIA spec (v1.1, Section 10.6 Bi-modal Device Support) states - * we must wait 100ms after this mode switch before touching PCIe config - * space. - */ - msleep(100); - - /* - * Hot reset to cause the card to come back in cxl mode. A - * OPAL_RESET_PCI_LINK would be sufficient, but currently lacks support - * in skiboot, so we use a hot reset instead. - * - * We call pci_set_pcie_reset_state() on the bridge, as a CAPI card is - * guaranteed to sit directly under the root port, and setting the reset - * state on a device directly under the root port is equivalent to doing - * it on the root port iself. - */ - dev_info(&bus->dev, "cxl: Configuration write complete, resetting card\n"); - pci_set_pcie_reset_state(bridge, pcie_hot_reset); - pci_set_pcie_reset_state(bridge, pcie_deassert_reset); - - dev_dbg(&bus->dev, "cxl: Offlining slot\n"); - rc = pnv_php_set_slot_power_state(&php_slot->slot, OPAL_PCI_SLOT_OFFLINE); - if (rc) { - dev_err(&bus->dev, "cxl: OPAL offlining call failed: %i\n", rc); - goto err_free_work; - } - - dev_dbg(&bus->dev, "cxl: Onlining and probing slot\n"); - rc = pnv_php_set_slot_power_state(&php_slot->slot, OPAL_PCI_SLOT_ONLINE); - if (rc) { - dev_err(&bus->dev, "cxl: OPAL onlining call failed: %i\n", rc); - goto err_free_work; - } - - pci_lock_rescan_remove(); - pci_hp_add_devices(bridge->subordinate); - pci_unlock_rescan_remove(); - - dev_info(&bus->dev, "cxl: CAPI mode switch completed\n"); - kfree(switch_work); - return; - -err_dev_put: - /* Release the reference obtained in cxl_check_and_switch_mode() */ - pci_dev_put(dev); -err_free_work: - kfree(switch_work); -} - -int cxl_check_and_switch_mode(struct pci_dev *dev, int mode, int vsec) -{ - struct cxl_switch_work *work; - u8 val; - int rc; - - if (!cpu_has_feature(CPU_FTR_HVMODE)) + if (!(vsec = find_cxl_vsec(dev))) { + dev_err(&dev->dev, "ABORTING: CXL VSEC not found!\n"); return -ENODEV; - - if (!vsec) { - vsec = find_cxl_vsec(dev); - if (!vsec) { - dev_info(&dev->dev, "CXL VSEC not found\n"); - return -ENODEV; - } } - rc = CXL_READ_VSEC_MODE_CONTROL(dev, vsec, &val); - if (rc) { - dev_err(&dev->dev, "Failed to read current mode control: %i", rc); + if ((rc = CXL_READ_VSEC_MODE_CONTROL(dev, vsec, &val))) { + dev_err(&dev->dev, "failed to read current mode control: %i", rc); return rc; } - - if (mode == CXL_BIMODE_PCI) { - if (!(val & CXL_VSEC_PROTOCOL_ENABLE)) { - dev_info(&dev->dev, "Card is already in PCI mode\n"); - return 0; - } - /* - * TODO: Before it's safe to switch the card back to PCI mode - * we need to disable the CAPP and make sure any cachelines the - * card holds have been flushed out. Needs skiboot support. - */ - dev_WARN(&dev->dev, "CXL mode switch to PCI unsupported!\n"); - return -EIO; - } - - if (val & CXL_VSEC_PROTOCOL_ENABLE) { - dev_info(&dev->dev, "Card is already in CXL mode\n"); - return 0; + val &= ~CXL_VSEC_PROTOCOL_MASK; + val |= CXL_VSEC_PROTOCOL_256TB | CXL_VSEC_PROTOCOL_ENABLE; + if ((rc = CXL_WRITE_VSEC_MODE_CONTROL(dev, vsec, val))) { + dev_err(&dev->dev, "failed to enable CXL protocol: %i", rc); + return rc; } - - dev_info(&dev->dev, "Card is in PCI mode, scheduling kernel thread " - "to switch to CXL mode\n"); - - work = kmalloc(sizeof(struct cxl_switch_work), GFP_KERNEL); - if (!work) - return -ENOMEM; - - pci_dev_get(dev); - work->dev = dev; - work->vsec = vsec; - work->mode = mode; - INIT_WORK(&work->work, switch_card_to_cxl); - - schedule_work(&work->work); - /* - * We return a failure now to abort the driver init. Once the - * link has been cycled and the card is in cxl mode we will - * come back (possibly using the generic cxl driver), but - * return success as the card should then be in cxl mode. - * - * TODO: What if the card comes back in PCI mode even after - * the switch? Don't want to spin endlessly. + * The CAIA spec (v0.12 11.6 Bi-modal Device Support) states + * we must wait 100ms after this mode switch before touching + * PCIe config space. */ - return -EBUSY; -} -EXPORT_SYMBOL_GPL(cxl_check_and_switch_mode); - -#endif /* CONFIG_CXL_BIMODAL */ - -static int setup_cxl_protocol_area(struct pci_dev *dev) -{ - u8 val; - int rc; - int vsec = find_cxl_vsec(dev); - - if (!vsec) { - dev_info(&dev->dev, "CXL VSEC not found\n"); - return -ENODEV; - } - - rc = CXL_READ_VSEC_MODE_CONTROL(dev, vsec, &val); - if (rc) { - dev_err(&dev->dev, "Failed to read current mode control: %i\n", rc); - return rc; - } - - if (!(val & CXL_VSEC_PROTOCOL_ENABLE)) { - dev_err(&dev->dev, "Card not in CAPI mode!\n"); - return -EIO; - } - - if ((val & CXL_VSEC_PROTOCOL_MASK) != CXL_VSEC_PROTOCOL_256TB) { - val &= ~CXL_VSEC_PROTOCOL_MASK; - val |= CXL_VSEC_PROTOCOL_256TB; - rc = CXL_WRITE_VSEC_MODE_CONTROL(dev, vsec, val); - if (rc) { - dev_err(&dev->dev, "Failed to set CXL protocol area: %i\n", rc); - return rc; - } - } + msleep(100); return 0; } @@ -1724,7 +1524,7 @@ static int cxl_configure_adapter(struct cxl *adapter, struct pci_dev *dev) if ((rc = setup_cxl_bars(dev))) return rc; - if ((rc = setup_cxl_protocol_area(dev))) + if ((rc = switch_card_to_cxl(dev))) return rc; if ((rc = cxl_update_image_control(adapter))) diff --git a/include/misc/cxl.h b/include/misc/cxl.h index 6a3711a2e217..74da2e440763 100644 --- a/include/misc/cxl.h +++ b/include/misc/cxl.h @@ -39,31 +39,6 @@ bool cxl_slot_is_supported(struct pci_dev *dev, int flags); -#define CXL_BIMODE_CXL 1 -#define CXL_BIMODE_PCI 2 - -/* - * Check the mode that the given bi-modal CXL adapter is currently in and - * change it if necessary. This does not apply to AFU drivers. - * - * If the mode matches the requested mode this function will return 0 - if the - * driver was expecting the generic CXL driver to have bound to the adapter and - * it gets this return value it should fail the probe function to give the CXL - * driver a chance to probe it. - * - * If the mode does not match it will start a background task to unplug the - * device from Linux and switch its mode, and will return -EBUSY. At this - * point the calling driver should make sure it has released the device and - * fail its probe function. - * - * The offset of the CXL VSEC can be provided to this function. If 0 is passed, - * this function will search for a CXL VSEC with ID 0x1280 and return -ENODEV - * if it is not found. - */ -#ifdef CONFIG_CXL_BIMODAL -int cxl_check_and_switch_mode(struct pci_dev *dev, int mode, int vsec); -#endif - /* Get the AFU associated with a pci_dev */ struct cxl_afu *cxl_pci_to_afu(struct pci_dev *dev); -- cgit v1.2.3 From c8d43cf08ab8c0b8829e67f7711bc72a3be6503f Mon Sep 17 00:00:00 2001 From: Alastair D'Silva Date: Thu, 28 Jun 2018 12:05:05 +0200 Subject: Revert "cxl: Add support for using the kernel API with a real PHB" Remove abandonned capi support for the Mellanox CX4. This reverts commit 317f5ef1b363417b6f1e93b90dfd2ffd6be6e867. Signed-off-by: Alastair D'Silva Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/pci.c | 3 --- drivers/misc/cxl/vphb.c | 16 ++-------------- 2 files changed, 2 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 9c5a21fee835..193ff22f610b 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -1886,9 +1886,6 @@ static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id) dev_err(&dev->dev, "AFU %i failed to start: %i\n", slice, rc); } - if (pnv_pci_on_cxl_phb(dev) && adapter->slices >= 1) - pnv_cxl_phb_set_peer_afu(dev, adapter->afu[0]); - return 0; } diff --git a/drivers/misc/cxl/vphb.c b/drivers/misc/cxl/vphb.c index 7fd0bdc1436a..1a99c9c7a6fb 100644 --- a/drivers/misc/cxl/vphb.c +++ b/drivers/misc/cxl/vphb.c @@ -9,7 +9,6 @@ #include #include -#include #include "cxl.h" static int cxl_dma_set_mask(struct pci_dev *pdev, u64 dma_mask) @@ -284,18 +283,13 @@ void cxl_pci_vphb_remove(struct cxl_afu *afu) */ } -static bool _cxl_pci_is_vphb_device(struct pci_controller *phb) -{ - return (phb->ops == &cxl_pcie_pci_ops); -} - bool cxl_pci_is_vphb_device(struct pci_dev *dev) { struct pci_controller *phb; phb = pci_bus_to_host(dev->bus); - return _cxl_pci_is_vphb_device(phb); + return (phb->ops == &cxl_pcie_pci_ops); } struct cxl_afu *cxl_pci_to_afu(struct pci_dev *dev) @@ -304,13 +298,7 @@ struct cxl_afu *cxl_pci_to_afu(struct pci_dev *dev) phb = pci_bus_to_host(dev->bus); - if (_cxl_pci_is_vphb_device(phb)) - return (struct cxl_afu *)phb->private_data; - - if (pnv_pci_on_cxl_phb(dev)) - return pnv_cxl_phb_to_afu(phb); - - return ERR_PTR(-ENODEV); + return (struct cxl_afu *)phb->private_data; } EXPORT_SYMBOL_GPL(cxl_pci_to_afu); -- cgit v1.2.3 From 322dc4af6c95cddc4f9d806197fe6b376cfae350 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Thu, 28 Jun 2018 12:05:07 +0200 Subject: Revert "cxl: Add cxl_slot_is_supported API" Remove abandonned capi support for the Mellanox CX4. This reverts commit 4e56f858bdde5cbfb70f61baddfaa56a8ed851bf. Signed-off-by: Frederic Barrat Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/pci.c | 37 ------------------------------------- include/misc/cxl.h | 15 --------------- 2 files changed, 52 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 193ff22f610b..0ca818396524 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -1808,43 +1808,6 @@ int cxl_slot_is_switched(struct pci_dev *dev) return (depth > CXL_MAX_PCIEX_PARENT); } -bool cxl_slot_is_supported(struct pci_dev *dev, int flags) -{ - if (!cpu_has_feature(CPU_FTR_HVMODE)) - return false; - - if ((flags & CXL_SLOT_FLAG_DMA) && (!pvr_version_is(PVR_POWER8NVL))) { - /* - * CAPP DMA mode is technically supported on regular P8, but - * will EEH if the card attempts to access memory < 4GB, which - * we cannot realistically avoid. We might be able to work - * around the issue, but until then return unsupported: - */ - return false; - } - - if (cxl_slot_is_switched(dev)) - return false; - - /* - * XXX: This gets a little tricky on regular P8 (not POWER8NVL) since - * the CAPP can be connected to PHB 0, 1 or 2 on a first come first - * served basis, which is racy to check from here. If we need to - * support this in future we might need to consider having this - * function effectively reserve it ahead of time. - * - * Currently, the only user of this API is the Mellanox CX4, which is - * only supported on P8NVL due to the above mentioned limitation of - * CAPP DMA mode and therefore does not need to worry about this. If the - * issue with CAPP DMA mode is later worked around on P8 we might need - * to revisit this. - */ - - return true; -} -EXPORT_SYMBOL_GPL(cxl_slot_is_supported); - - static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct cxl *adapter; diff --git a/include/misc/cxl.h b/include/misc/cxl.h index 74da2e440763..ea9ff4a1a9ca 100644 --- a/include/misc/cxl.h +++ b/include/misc/cxl.h @@ -24,21 +24,6 @@ * generic PCI API. This API is agnostic to the actual AFU. */ -#define CXL_SLOT_FLAG_DMA 0x1 - -/* - * Checks if the given card is in a cxl capable slot. Pass CXL_SLOT_FLAG_DMA if - * the card requires CAPP DMA mode to also check if the system supports it. - * This is intended to be used by bi-modal devices to determine if they can use - * cxl mode or if they should continue running in PCI mode. - * - * Note that this only checks if the slot is cxl capable - it does not - * currently check if the CAPP is currently available for chips where it can be - * assigned to different PHBs on a first come first serve basis (i.e. P8) - */ -bool cxl_slot_is_supported(struct pci_dev *dev, int flags); - - /* Get the AFU associated with a pci_dev */ struct cxl_afu *cxl_pci_to_afu(struct pci_dev *dev); -- cgit v1.2.3 From f18a4e1d973bc69a50419eb8918f458ea89c6c3f Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Thu, 28 Jun 2018 12:05:08 +0200 Subject: Revert "cxl: Allow a default context to be associated with an external pci_dev" Remove abandonned capi support for the Mellanox CX4. This reverts commit a19bd79e31769626d288cc016e21a31b6f47bf6f. Signed-off-by: Frederic Barrat Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/Makefile | 2 +- drivers/misc/cxl/base.c | 35 ----------------------------------- drivers/misc/cxl/cxl.h | 6 ------ drivers/misc/cxl/main.c | 2 -- drivers/misc/cxl/phb.c | 44 -------------------------------------------- drivers/misc/cxl/vphb.c | 30 +++++++++++++++++++++++++++--- include/misc/cxl-base.h | 6 ------ 7 files changed, 28 insertions(+), 97 deletions(-) delete mode 100644 drivers/misc/cxl/phb.c (limited to 'drivers') diff --git a/drivers/misc/cxl/Makefile b/drivers/misc/cxl/Makefile index 502d41fc9ea5..5eea61b9584f 100644 --- a/drivers/misc/cxl/Makefile +++ b/drivers/misc/cxl/Makefile @@ -4,7 +4,7 @@ ccflags-$(CONFIG_PPC_WERROR) += -Werror cxl-y += main.o file.o irq.o fault.o native.o cxl-y += context.o sysfs.o pci.o trace.o -cxl-y += vphb.o phb.o api.o cxllib.o +cxl-y += vphb.o api.o cxllib.o cxl-$(CONFIG_PPC_PSERIES) += flash.o guest.o of.o hcalls.o cxl-$(CONFIG_DEBUG_FS) += debugfs.o obj-$(CONFIG_CXL) += cxl.o diff --git a/drivers/misc/cxl/base.c b/drivers/misc/cxl/base.c index e1e80cb99ad9..7557835cdfcd 100644 --- a/drivers/misc/cxl/base.c +++ b/drivers/misc/cxl/base.c @@ -106,41 +106,6 @@ int cxl_update_properties(struct device_node *dn, } EXPORT_SYMBOL_GPL(cxl_update_properties); -/* - * API calls into the driver that may be called from the PHB code and must be - * built in. - */ -bool cxl_pci_associate_default_context(struct pci_dev *dev, struct cxl_afu *afu) -{ - bool ret; - struct cxl_calls *calls; - - calls = cxl_calls_get(); - if (!calls) - return false; - - ret = calls->cxl_pci_associate_default_context(dev, afu); - - cxl_calls_put(calls); - - return ret; -} -EXPORT_SYMBOL_GPL(cxl_pci_associate_default_context); - -void cxl_pci_disable_device(struct pci_dev *dev) -{ - struct cxl_calls *calls; - - calls = cxl_calls_get(); - if (!calls) - return; - - calls->cxl_pci_disable_device(dev); - - cxl_calls_put(calls); -} -EXPORT_SYMBOL_GPL(cxl_pci_disable_device); - static int __init cxl_base_init(void) { struct device_node *np; diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index d95c2c98f2ab..aa453448201d 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -867,15 +867,9 @@ static inline bool cxl_is_power9_dd1(void) ssize_t cxl_pci_afu_read_err_buffer(struct cxl_afu *afu, char *buf, loff_t off, size_t count); -/* Internal functions wrapped in cxl_base to allow PHB to call them */ -bool _cxl_pci_associate_default_context(struct pci_dev *dev, struct cxl_afu *afu); -void _cxl_pci_disable_device(struct pci_dev *dev); struct cxl_calls { void (*cxl_slbia)(struct mm_struct *mm); - bool (*cxl_pci_associate_default_context)(struct pci_dev *dev, struct cxl_afu *afu); - void (*cxl_pci_disable_device)(struct pci_dev *dev); - struct module *owner; }; int register_cxl_calls(struct cxl_calls *calls); diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c index a7e83624034b..334223b802ee 100644 --- a/drivers/misc/cxl/main.c +++ b/drivers/misc/cxl/main.c @@ -104,8 +104,6 @@ static inline void cxl_slbia_core(struct mm_struct *mm) static struct cxl_calls cxl_calls = { .cxl_slbia = cxl_slbia_core, - .cxl_pci_associate_default_context = _cxl_pci_associate_default_context, - .cxl_pci_disable_device = _cxl_pci_disable_device, .owner = THIS_MODULE, }; diff --git a/drivers/misc/cxl/phb.c b/drivers/misc/cxl/phb.c deleted file mode 100644 index 6ec69ada19f4..000000000000 --- a/drivers/misc/cxl/phb.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2014-2016 IBM Corp. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include "cxl.h" - -bool _cxl_pci_associate_default_context(struct pci_dev *dev, struct cxl_afu *afu) -{ - struct cxl_context *ctx; - - /* - * Allocate a context to do cxl things to. This is used for interrupts - * in the peer model using a real phb, and if we eventually do DMA ops - * in the virtual phb, we'll need a default context to attach them to. - */ - ctx = cxl_dev_context_init(dev); - if (IS_ERR(ctx)) - return false; - dev->dev.archdata.cxl_ctx = ctx; - - return (cxl_ops->afu_check_and_enable(afu) == 0); -} -/* exported via cxl_base */ - -void _cxl_pci_disable_device(struct pci_dev *dev) -{ - struct cxl_context *ctx = cxl_get_context(dev); - - if (ctx) { - if (ctx->status == STARTED) { - dev_err(&dev->dev, "Default context started\n"); - return; - } - dev->dev.archdata.cxl_ctx = NULL; - cxl_release_context(ctx); - } -} -/* exported via cxl_base */ diff --git a/drivers/misc/cxl/vphb.c b/drivers/misc/cxl/vphb.c index 1a99c9c7a6fb..7908633d9204 100644 --- a/drivers/misc/cxl/vphb.c +++ b/drivers/misc/cxl/vphb.c @@ -44,6 +44,7 @@ static bool cxl_pci_enable_device_hook(struct pci_dev *dev) { struct pci_controller *phb; struct cxl_afu *afu; + struct cxl_context *ctx; phb = pci_bus_to_host(dev->bus); afu = (struct cxl_afu *)phb->private_data; @@ -56,7 +57,30 @@ static bool cxl_pci_enable_device_hook(struct pci_dev *dev) set_dma_ops(&dev->dev, &dma_nommu_ops); set_dma_offset(&dev->dev, PAGE_OFFSET); - return _cxl_pci_associate_default_context(dev, afu); + /* + * Allocate a context to do cxl things too. If we eventually do real + * DMA ops, we'll need a default context to attach them to + */ + ctx = cxl_dev_context_init(dev); + if (IS_ERR(ctx)) + return false; + dev->dev.archdata.cxl_ctx = ctx; + + return (cxl_ops->afu_check_and_enable(afu) == 0); +} + +static void cxl_pci_disable_device(struct pci_dev *dev) +{ + struct cxl_context *ctx = cxl_get_context(dev); + + if (ctx) { + if (ctx->status == STARTED) { + dev_err(&dev->dev, "Default context started\n"); + return; + } + dev->dev.archdata.cxl_ctx = NULL; + cxl_release_context(ctx); + } } static resource_size_t cxl_pci_window_alignment(struct pci_bus *bus, @@ -190,8 +214,8 @@ static struct pci_controller_ops cxl_pci_controller_ops = { .probe_mode = cxl_pci_probe_mode, .enable_device_hook = cxl_pci_enable_device_hook, - .disable_device = _cxl_pci_disable_device, - .release_device = _cxl_pci_disable_device, + .disable_device = cxl_pci_disable_device, + .release_device = cxl_pci_disable_device, .window_alignment = cxl_pci_window_alignment, .reset_secondary_bus = cxl_pci_reset_secondary_bus, .setup_msi_irqs = cxl_setup_msi_irqs, diff --git a/include/misc/cxl-base.h b/include/misc/cxl-base.h index bb7e629ae492..f53808fa638a 100644 --- a/include/misc/cxl-base.h +++ b/include/misc/cxl-base.h @@ -10,8 +10,6 @@ #ifndef _MISC_CXL_BASE_H #define _MISC_CXL_BASE_H -#include - #ifdef CONFIG_CXL_BASE #define CXL_IRQ_RANGES 4 @@ -41,8 +39,6 @@ static inline void cxl_ctx_put(void) struct cxl_afu *cxl_afu_get(struct cxl_afu *afu); void cxl_afu_put(struct cxl_afu *afu); void cxl_slbia(struct mm_struct *mm); -bool cxl_pci_associate_default_context(struct pci_dev *dev, struct cxl_afu *afu); -void cxl_pci_disable_device(struct pci_dev *dev); #else /* CONFIG_CXL_BASE */ @@ -50,8 +46,6 @@ static inline bool cxl_ctx_in_use(void) { return false; } static inline struct cxl_afu *cxl_afu_get(struct cxl_afu *afu) { return NULL; } static inline void cxl_afu_put(struct cxl_afu *afu) {} static inline void cxl_slbia(struct mm_struct *mm) {} -static inline bool cxl_pci_associate_default_context(struct pci_dev *dev, struct cxl_afu *afu) { return false; } -static inline void cxl_pci_disable_device(struct pci_dev *dev) {} #endif /* CONFIG_CXL_BASE */ -- cgit v1.2.3 From f3988ca4c74e136e49487b51231d324d0c923495 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Thu, 28 Jun 2018 12:05:09 +0200 Subject: cxl: Remove abandonned capi support for the Mellanox CX4, final cleanup Remove a few XSL/CX4 oddities which are no longer needed. A simple revert of the initial commits was not possible (or not worth it) due to the history of the code. Signed-off-by: Frederic Barrat Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/context.c | 2 +- drivers/misc/cxl/cxl.h | 12 -------- drivers/misc/cxl/debugfs.c | 5 ---- drivers/misc/cxl/pci.c | 75 ++++------------------------------------------ 4 files changed, 7 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index 0355d42d367f..5fe529b43ebe 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -95,7 +95,7 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master) */ mutex_lock(&afu->contexts_lock); idr_preload(GFP_KERNEL); - i = idr_alloc(&ctx->afu->contexts_idr, ctx, ctx->afu->adapter->min_pe, + i = idr_alloc(&ctx->afu->contexts_idr, ctx, 0, ctx->afu->num_procs, GFP_NOWAIT); idr_preload_end(); mutex_unlock(&afu->contexts_lock); diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index aa453448201d..44bcfafbb579 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -93,11 +93,6 @@ static const cxl_p1_reg_t CXL_PSL_FIR_CNTL = {0x0148}; static const cxl_p1_reg_t CXL_PSL_DSNDCTL = {0x0150}; static const cxl_p1_reg_t CXL_PSL_SNWRALLOC = {0x0158}; static const cxl_p1_reg_t CXL_PSL_TRACE = {0x0170}; -/* XSL registers (Mellanox CX4) */ -static const cxl_p1_reg_t CXL_XSL_Timebase = {0x0100}; -static const cxl_p1_reg_t CXL_XSL_TB_CTLSTAT = {0x0108}; -static const cxl_p1_reg_t CXL_XSL_FEC = {0x0158}; -static const cxl_p1_reg_t CXL_XSL_DSNCTL = {0x0168}; /* PSL registers - CAIA 2 */ static const cxl_p1_reg_t CXL_PSL9_CONTROL = {0x0020}; static const cxl_p1_reg_t CXL_XSL9_INV = {0x0110}; @@ -695,7 +690,6 @@ struct cxl { struct bin_attribute cxl_attr; int adapter_num; int user_irqs; - int min_pe; u64 ps_size; u16 psl_rev; u16 base_image; @@ -934,7 +928,6 @@ int cxl_debugfs_afu_add(struct cxl_afu *afu); void cxl_debugfs_afu_remove(struct cxl_afu *afu); void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir); void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir); -void cxl_debugfs_add_adapter_regs_xsl(struct cxl *adapter, struct dentry *dir); void cxl_debugfs_add_afu_regs_psl9(struct cxl_afu *afu, struct dentry *dir); void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir); @@ -977,11 +970,6 @@ static inline void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, { } -static inline void cxl_debugfs_add_adapter_regs_xsl(struct cxl *adapter, - struct dentry *dir) -{ -} - static inline void cxl_debugfs_add_afu_regs_psl9(struct cxl_afu *afu, struct dentry *dir) { } diff --git a/drivers/misc/cxl/debugfs.c b/drivers/misc/cxl/debugfs.c index 1643850d2302..a1921d81593a 100644 --- a/drivers/misc/cxl/debugfs.c +++ b/drivers/misc/cxl/debugfs.c @@ -58,11 +58,6 @@ void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir) debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_TRACE)); } -void cxl_debugfs_add_adapter_regs_xsl(struct cxl *adapter, struct dentry *dir) -{ - debugfs_create_io_x64("fec", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_XSL_FEC)); -} - int cxl_debugfs_adapter_add(struct cxl *adapter) { struct dentry *dir; diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 0ca818396524..6dfb4ed345d3 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -593,27 +593,7 @@ static int init_implementation_adapter_regs_psl8(struct cxl *adapter, struct pci return 0; } -static int init_implementation_adapter_regs_xsl(struct cxl *adapter, struct pci_dev *dev) -{ - u64 xsl_dsnctl; - u64 chipid; - u32 phb_index; - u64 capp_unit_id; - int rc; - - rc = cxl_calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); - if (rc) - return rc; - - /* Tell XSL where to route data to */ - xsl_dsnctl = 0x0000600000000000ULL | (chipid << (63-5)); - xsl_dsnctl |= (capp_unit_id << (63-13)); - cxl_p1_write(adapter, CXL_XSL_DSNCTL, xsl_dsnctl); - - return 0; -} - -/* PSL & XSL */ +/* PSL */ #define TBSYNC_CAL(n) (((u64)n & 0x7) << (63-3)) #define TBSYNC_CNT(n) (((u64)n & 0x7) << (63-6)) /* For the PSL this is a multiple for 0 < n <= 7: */ @@ -625,21 +605,6 @@ static void write_timebase_ctrl_psl8(struct cxl *adapter) TBSYNC_CNT(2 * PSL_2048_250MHZ_CYCLES)); } -/* XSL */ -#define TBSYNC_ENA (1ULL << 63) -/* For the XSL this is 2**n * 2000 clocks for 0 < n <= 6: */ -#define XSL_2000_CLOCKS 1 -#define XSL_4000_CLOCKS 2 -#define XSL_8000_CLOCKS 3 - -static void write_timebase_ctrl_xsl(struct cxl *adapter) -{ - cxl_p1_write(adapter, CXL_XSL_TB_CTLSTAT, - TBSYNC_ENA | - TBSYNC_CAL(3) | - TBSYNC_CNT(XSL_4000_CLOCKS)); -} - static u64 timebase_read_psl9(struct cxl *adapter) { return cxl_p1_read(adapter, CXL_PSL9_Timebase); @@ -650,11 +615,6 @@ static u64 timebase_read_psl8(struct cxl *adapter) return cxl_p1_read(adapter, CXL_PSL_Timebase); } -static u64 timebase_read_xsl(struct cxl *adapter) -{ - return cxl_p1_read(adapter, CXL_XSL_Timebase); -} - static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev) { struct device_node *np; @@ -1671,37 +1631,14 @@ static const struct cxl_service_layer_ops psl8_ops = { .needs_reset_before_disable = true, }; -static const struct cxl_service_layer_ops xsl_ops = { - .adapter_regs_init = init_implementation_adapter_regs_xsl, - .invalidate_all = cxl_invalidate_all_psl8, - .sanitise_afu_regs = sanitise_afu_regs_psl8, - .handle_interrupt = cxl_irq_psl8, - .fail_irq = cxl_fail_irq_psl, - .activate_dedicated_process = cxl_activate_dedicated_process_psl8, - .attach_afu_directed = cxl_attach_afu_directed_psl8, - .attach_dedicated_process = cxl_attach_dedicated_process_psl8, - .update_dedicated_ivtes = cxl_update_dedicated_ivtes_psl8, - .debugfs_add_adapter_regs = cxl_debugfs_add_adapter_regs_xsl, - .write_timebase_ctrl = write_timebase_ctrl_xsl, - .timebase_read = timebase_read_xsl, - .capi_mode = OPAL_PHB_CAPI_MODE_DMA, -}; - static void set_sl_ops(struct cxl *adapter, struct pci_dev *dev) { - if (dev->vendor == PCI_VENDOR_ID_MELLANOX && dev->device == 0x1013) { - /* Mellanox CX-4 */ - dev_info(&dev->dev, "Device uses an XSL\n"); - adapter->native->sl_ops = &xsl_ops; - adapter->min_pe = 1; /* Workaround for CX-4 hardware bug */ + if (cxl_is_power8()) { + dev_info(&dev->dev, "Device uses a PSL8\n"); + adapter->native->sl_ops = &psl8_ops; } else { - if (cxl_is_power8()) { - dev_info(&dev->dev, "Device uses a PSL8\n"); - adapter->native->sl_ops = &psl8_ops; - } else { - dev_info(&dev->dev, "Device uses a PSL9\n"); - adapter->native->sl_ops = &psl9_ops; - } + dev_info(&dev->dev, "Device uses a PSL9\n"); + adapter->native->sl_ops = &psl9_ops; } } -- cgit v1.2.3 From d497ebf5fb3a026c0817f8c96cde578787f24093 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Mon, 18 Jun 2018 14:14:36 +0200 Subject: ocxl: Fix page fault handler in case of fault on dying process If a process exits without doing proper cleanup, there's a window where an opencapi device can try to access the memory of the dying process and may trigger a page fault. That's an expected scenario and the ocxl driver holds a reference on the mm_struct of the process until the opencapi device is notified of the process exiting. However, if mm_users is already at 0, i.e. the address space of the process has already been destroyed, the driver shouldn't try resolving the page fault, as it will fail, but it can also try accessing already freed data. It is fixed by only calling the bottom half of the page fault handler if mm_users is greater than 0 and get a reference on mm_users instead of mm_count. Otherwise, we can safely return a translation fault to the device, as its associated memory context is being removed. The opencapi device will be properly cleaned up shortly after when closing the file descriptors. Fixes: 5ef3166e8a32 ("ocxl: Driver code for 'generic' opencapi devices") Cc: stable@vger.kernel.org # v4.16+ Signed-off-by: Frederic Barrat Reviewed-By: Alastair D'Silva Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/ocxl/link.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ocxl/link.c b/drivers/misc/ocxl/link.c index 88876ae8f330..a963b0a4a3c5 100644 --- a/drivers/misc/ocxl/link.c +++ b/drivers/misc/ocxl/link.c @@ -136,7 +136,7 @@ static void xsl_fault_handler_bh(struct work_struct *fault_work) int rc; /* - * We need to release a reference on the mm whenever exiting this + * We must release a reference on mm_users whenever exiting this * function (taken in the memory fault interrupt handler) */ rc = copro_handle_mm_fault(fault->pe_data.mm, fault->dar, fault->dsisr, @@ -172,7 +172,7 @@ static void xsl_fault_handler_bh(struct work_struct *fault_work) } r = RESTART; ack: - mmdrop(fault->pe_data.mm); + mmput(fault->pe_data.mm); ack_irq(spa, r); } @@ -184,6 +184,7 @@ static irqreturn_t xsl_fault_handler(int irq, void *data) struct pe_data *pe_data; struct ocxl_process_element *pe; int lpid, pid, tid; + bool schedule = false; read_irq(spa, &dsisr, &dar, &pe_handle); trace_ocxl_fault(spa->spa_mem, pe_handle, dsisr, dar, -1); @@ -226,14 +227,19 @@ static irqreturn_t xsl_fault_handler(int irq, void *data) } WARN_ON(pe_data->mm->context.id != pid); - spa->xsl_fault.pe = pe_handle; - spa->xsl_fault.dar = dar; - spa->xsl_fault.dsisr = dsisr; - spa->xsl_fault.pe_data = *pe_data; - mmgrab(pe_data->mm); /* mm count is released by bottom half */ - + if (mmget_not_zero(pe_data->mm)) { + spa->xsl_fault.pe = pe_handle; + spa->xsl_fault.dar = dar; + spa->xsl_fault.dsisr = dsisr; + spa->xsl_fault.pe_data = *pe_data; + schedule = true; + /* mm_users count released by bottom half */ + } rcu_read_unlock(); - schedule_work(&spa->xsl_fault.fault_work); + if (schedule) + schedule_work(&spa->xsl_fault.fault_work); + else + ack_irq(spa, ADDRESS_ERROR); return IRQ_HANDLED; } -- cgit v1.2.3 From dcb14337e0f2adb227c376e6327ef0c3e4cce6f9 Mon Sep 17 00:00:00 2001 From: Shilpasri G Bhat Date: Wed, 25 Apr 2018 11:44:55 +0530 Subject: cpufreq: powernv: Remove global pstate ramp-down timer in POWER9 POWER9 does not support global pstate requests for the chip. So remove the timer logic which slowly ramps down the global pstate in P9 platforms. Signed-off-by: Shilpasri G Bhat Acked-by: Viresh Kumar [mpe: Drop NULL check before kfree(policy->driver_data)] Signed-off-by: Michael Ellerman --- drivers/cpufreq/powernv-cpufreq.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 54edaec1e608..bf6519cf64bc 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -758,8 +758,13 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy, cur_msec = jiffies_to_msecs(get_jiffies_64()); - spin_lock(&gpstates->gpstate_lock); freq_data.pstate_id = idx_to_pstate(new_index); + if (!gpstates) { + freq_data.gpstate_id = freq_data.pstate_id; + goto no_gpstate; + } + + spin_lock(&gpstates->gpstate_lock); if (!gpstates->last_sampled_time) { gpstate_idx = new_index; @@ -809,6 +814,7 @@ gpstates_done: spin_unlock(&gpstates->gpstate_lock); +no_gpstate: /* * Use smp_call_function to send IPI and execute the * mtspr on target CPU. We could do that without IPI @@ -843,6 +849,13 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy) kernfs_put(kn); } + policy->freq_table = powernv_freqs; + policy->fast_switch_possible = true; + + if (pvr_version_is(PVR_POWER9)) + return 0; + + /* Initialise Gpstate ramp-down timer only on POWER8 */ gpstates = kzalloc(sizeof(*gpstates), GFP_KERNEL); if (!gpstates) return -ENOMEM; @@ -857,8 +870,6 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy) msecs_to_jiffies(GPSTATE_TIMER_INTERVAL); spin_lock_init(&gpstates->gpstate_lock); - policy->freq_table = powernv_freqs; - policy->fast_switch_possible = true; return 0; } @@ -998,7 +1009,8 @@ static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy) freq_data.pstate_id = idx_to_pstate(powernv_pstate_info.min); freq_data.gpstate_id = idx_to_pstate(powernv_pstate_info.min); smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1); - del_timer_sync(&gpstates->timer); + if (gpstates) + del_timer_sync(&gpstates->timer); } static unsigned int powernv_fast_switch(struct cpufreq_policy *policy, -- cgit v1.2.3 From 2bf1071a8d50928a4ae366bb3108833166c2b70c Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 5 Jul 2018 18:47:00 +1000 Subject: powerpc/64s: Remove POWER9 DD1 support POWER9 DD1 was never a product. It is no longer supported by upstream firmware, and it is not effectively supported in Linux due to lack of testing. Signed-off-by: Nicholas Piggin Reviewed-by: Michael Ellerman [mpe: Remove arch_make_huge_pte() entirely] Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/hugetlb.h | 20 -------- arch/powerpc/include/asm/book3s/64/pgtable.h | 5 +- arch/powerpc/include/asm/book3s/64/radix.h | 35 ++----------- .../powerpc/include/asm/book3s/64/tlbflush-radix.h | 2 - arch/powerpc/include/asm/cputable.h | 13 ++--- arch/powerpc/include/asm/paca.h | 5 -- arch/powerpc/kernel/asm-offsets.c | 1 - arch/powerpc/kernel/cputable.c | 19 ------- arch/powerpc/kernel/dt_cpu_ftrs.c | 4 +- arch/powerpc/kernel/exceptions-64s.S | 4 +- arch/powerpc/kernel/idle_book3s.S | 50 ------------------ arch/powerpc/kernel/process.c | 10 +--- arch/powerpc/kvm/book3s_64_mmu_radix.c | 15 +----- arch/powerpc/kvm/book3s_hv.c | 10 ---- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 16 +----- arch/powerpc/kvm/book3s_xive_template.c | 39 +++++--------- arch/powerpc/mm/hash_utils_64.c | 30 ----------- arch/powerpc/mm/hugetlbpage.c | 9 ++-- arch/powerpc/mm/mmu_context_book3s64.c | 12 +---- arch/powerpc/mm/pgtable-radix.c | 60 +--------------------- arch/powerpc/mm/tlb-radix.c | 18 ------- arch/powerpc/perf/core-book3s.c | 34 ------------ arch/powerpc/perf/isa207-common.c | 12 ++--- arch/powerpc/perf/isa207-common.h | 5 -- arch/powerpc/perf/power9-pmu.c | 54 +------------------ arch/powerpc/platforms/powernv/idle.c | 28 ---------- arch/powerpc/platforms/powernv/smp.c | 27 ++-------- arch/powerpc/sysdev/xive/common.c | 8 +-- arch/powerpc/xmon/xmon.c | 1 - drivers/misc/cxl/cxl.h | 8 --- drivers/misc/cxl/cxllib.c | 4 -- drivers/misc/cxl/pci.c | 41 ++++++--------- 32 files changed, 66 insertions(+), 533 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/book3s/64/hugetlb.h b/arch/powerpc/include/asm/book3s/64/hugetlb.h index c459f937d484..50888388a359 100644 --- a/arch/powerpc/include/asm/book3s/64/hugetlb.h +++ b/arch/powerpc/include/asm/book3s/64/hugetlb.h @@ -32,26 +32,6 @@ static inline int hstate_get_psize(struct hstate *hstate) } } -#define arch_make_huge_pte arch_make_huge_pte -static inline pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma, - struct page *page, int writable) -{ - unsigned long page_shift; - - if (!cpu_has_feature(CPU_FTR_POWER9_DD1)) - return entry; - - page_shift = huge_page_shift(hstate_vma(vma)); - /* - * We don't support 1G hugetlb pages yet. - */ - VM_WARN_ON(page_shift == mmu_psize_defs[MMU_PAGE_1G].shift); - if (page_shift == mmu_psize_defs[MMU_PAGE_2M].shift) - return __pte(pte_val(entry) | R_PAGE_LARGE); - else - return entry; -} - #ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE static inline bool gigantic_page_supported(void) { diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 63cee159022b..d334e6b9a46d 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -474,9 +474,8 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, { if (full && radix_enabled()) { /* - * Let's skip the DD1 style pte update here. We know that - * this is a full mm pte clear and hence can be sure there is - * no parallel set_pte. + * We know that this is a full mm pte clear and + * hence can be sure there is no parallel set_pte. */ return radix__ptep_get_and_clear_full(mm, addr, ptep, full); } diff --git a/arch/powerpc/include/asm/book3s/64/radix.h b/arch/powerpc/include/asm/book3s/64/radix.h index ef9f96742ce1..3ab3f7aef022 100644 --- a/arch/powerpc/include/asm/book3s/64/radix.h +++ b/arch/powerpc/include/asm/book3s/64/radix.h @@ -12,12 +12,6 @@ #include #endif -/* - * For P9 DD1 only, we need to track whether the pte's huge. - */ -#define R_PAGE_LARGE _RPAGE_RSV1 - - #ifndef __ASSEMBLY__ #include #include @@ -154,20 +148,7 @@ static inline unsigned long radix__pte_update(struct mm_struct *mm, { unsigned long old_pte; - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { - - unsigned long new_pte; - - old_pte = __radix_pte_update(ptep, ~0ul, 0); - /* - * new value of pte - */ - new_pte = (old_pte | set) & ~clr; - radix__flush_tlb_pte_p9_dd1(old_pte, mm, addr); - if (new_pte) - __radix_pte_update(ptep, 0, new_pte); - } else - old_pte = __radix_pte_update(ptep, clr, set); + old_pte = __radix_pte_update(ptep, clr, set); if (!huge) assert_pte_locked(mm, addr); @@ -253,8 +234,6 @@ static inline int radix__pmd_trans_huge(pmd_t pmd) static inline pmd_t radix__pmd_mkhuge(pmd_t pmd) { - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) - return __pmd(pmd_val(pmd) | _PAGE_PTE | R_PAGE_LARGE); return __pmd(pmd_val(pmd) | _PAGE_PTE); } @@ -285,18 +264,14 @@ static inline unsigned long radix__get_tree_size(void) unsigned long rts_field; /* * We support 52 bits, hence: - * DD1 52-28 = 24, 0b11000 - * Others 52-31 = 21, 0b10101 + * bits 52 - 31 = 21, 0b10101 * RTS encoding details * bits 0 - 3 of rts -> bits 6 - 8 unsigned long * bits 4 - 5 of rts -> bits 62 - 63 of unsigned long */ - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) - rts_field = (0x3UL << 61); - else { - rts_field = (0x5UL << 5); /* 6 - 8 bits */ - rts_field |= (0x2UL << 61); - } + rts_field = (0x5UL << 5); /* 6 - 8 bits */ + rts_field |= (0x2UL << 61); + return rts_field; } diff --git a/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h b/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h index ef5c3f2994c9..1154a6dc6d26 100644 --- a/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h +++ b/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h @@ -48,8 +48,6 @@ extern void radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmad extern void radix__flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr); extern void radix__flush_tlb_collapsed_pmd(struct mm_struct *mm, unsigned long addr); extern void radix__flush_tlb_all(void); -extern void radix__flush_tlb_pte_p9_dd1(unsigned long old_pte, struct mm_struct *mm, - unsigned long address); extern void radix__flush_tlb_lpid_page(unsigned int lpid, unsigned long addr, diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 9c0a3083571b..f980f91cad8a 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -210,7 +210,6 @@ static inline void cpu_feature_keys_init(void) { } #define CPU_FTR_DAWR LONG_ASM_CONST(0x0000008000000000) #define CPU_FTR_DABRX LONG_ASM_CONST(0x0000010000000000) #define CPU_FTR_PMAO_BUG LONG_ASM_CONST(0x0000020000000000) -#define CPU_FTR_POWER9_DD1 LONG_ASM_CONST(0x0000040000000000) #define CPU_FTR_POWER9_DD2_1 LONG_ASM_CONST(0x0000080000000000) #define CPU_FTR_P9_TM_HV_ASSIST LONG_ASM_CONST(0x0000100000000000) #define CPU_FTR_P9_TM_XER_SO_BUG LONG_ASM_CONST(0x0000200000000000) @@ -464,8 +463,6 @@ static inline void cpu_feature_keys_init(void) { } CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_ARCH_207S | \ CPU_FTR_TM_COMP | CPU_FTR_ARCH_300 | CPU_FTR_PKEY | \ CPU_FTR_P9_TLBIE_BUG | CPU_FTR_P9_TIDR) -#define CPU_FTRS_POWER9_DD1 ((CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD1) & \ - (~CPU_FTR_SAO)) #define CPU_FTRS_POWER9_DD2_0 CPU_FTRS_POWER9 #define CPU_FTRS_POWER9_DD2_1 (CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD2_1) #define CPU_FTRS_POWER9_DD2_2 (CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD2_1 | \ @@ -489,16 +486,14 @@ static inline void cpu_feature_keys_init(void) { } #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_POWER7 | CPU_FTRS_POWER8E | CPU_FTRS_POWER8 | \ CPU_FTRS_POWER8_DD1 | CPU_FTR_ALTIVEC_COMP | CPU_FTR_VSX_COMP | \ - CPU_FTRS_POWER9 | CPU_FTRS_POWER9_DD1 | CPU_FTRS_POWER9_DD2_1 | \ - CPU_FTRS_POWER9_DD2_2) + CPU_FTRS_POWER9 | CPU_FTRS_POWER9_DD2_1 | CPU_FTRS_POWER9_DD2_2) #else #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | \ CPU_FTRS_POWER6 | CPU_FTRS_POWER7 | CPU_FTRS_POWER8E | \ CPU_FTRS_POWER8 | CPU_FTRS_POWER8_DD1 | CPU_FTRS_CELL | \ CPU_FTRS_PA6T | CPU_FTR_VSX_COMP | CPU_FTR_ALTIVEC_COMP | \ - CPU_FTRS_POWER9 | CPU_FTRS_POWER9_DD1 | CPU_FTRS_POWER9_DD2_1 | \ - CPU_FTRS_POWER9_DD2_2) + CPU_FTRS_POWER9 | CPU_FTRS_POWER9_DD2_1 | CPU_FTRS_POWER9_DD2_2) #endif /* CONFIG_CPU_LITTLE_ENDIAN */ #endif #else @@ -567,7 +562,7 @@ enum { #define CPU_FTRS_ALWAYS \ (CPU_FTRS_POSSIBLE & ~CPU_FTR_HVMODE & CPU_FTRS_POWER7 & \ CPU_FTRS_POWER8E & CPU_FTRS_POWER8 & CPU_FTRS_POWER8_DD1 & \ - CPU_FTRS_POWER9 & CPU_FTRS_POWER9_DD1 & CPU_FTRS_POWER9_DD2_1 & \ + CPU_FTRS_POWER9 & CPU_FTRS_POWER9_DD2_1 & \ CPU_FTRS_DT_CPU_BASE) #else #define CPU_FTRS_ALWAYS \ @@ -575,7 +570,7 @@ enum { CPU_FTRS_POWER6 & CPU_FTRS_POWER7 & CPU_FTRS_CELL & \ CPU_FTRS_PA6T & CPU_FTRS_POWER8 & CPU_FTRS_POWER8E & \ CPU_FTRS_POWER8_DD1 & ~CPU_FTR_HVMODE & CPU_FTRS_POSSIBLE & \ - CPU_FTRS_POWER9 & CPU_FTRS_POWER9_DD1 & CPU_FTRS_POWER9_DD2_1 & \ + CPU_FTRS_POWER9 & CPU_FTRS_POWER9_DD2_1 & \ CPU_FTRS_DT_CPU_BASE) #endif /* CONFIG_CPU_LITTLE_ENDIAN */ #endif diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 6d34bd71139d..4e9cede5a7e7 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -187,11 +187,6 @@ struct paca_struct { u8 subcore_sibling_mask; /* Flag to request this thread not to stop */ atomic_t dont_stop; - /* - * Pointer to an array which contains pointer - * to the sibling threads' paca. - */ - struct paca_struct **thread_sibling_pacas; /* The PSSCR value that the kernel requested before going to stop */ u64 requested_psscr; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 0a0544335950..89cf15566c4e 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -766,7 +766,6 @@ int main(void) OFFSET(PACA_THREAD_IDLE_STATE, paca_struct, thread_idle_state); OFFSET(PACA_THREAD_MASK, paca_struct, thread_mask); OFFSET(PACA_SUBCORE_SIBLING_MASK, paca_struct, subcore_sibling_mask); - OFFSET(PACA_SIBLING_PACA_PTRS, paca_struct, thread_sibling_pacas); OFFSET(PACA_REQ_PSSCR, paca_struct, requested_psscr); OFFSET(PACA_DONT_STOP, paca_struct, dont_stop); #define STOP_SPR(x, f) OFFSET(x, paca_struct, stop_sprs.f) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index c8fc9691f8c7..bc75a2908a7e 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -485,25 +485,6 @@ static struct cpu_spec __initdata cpu_specs[] = { .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, - { /* Power9 DD1*/ - .pvr_mask = 0xffffff00, - .pvr_value = 0x004e0100, - .cpu_name = "POWER9 (raw)", - .cpu_features = CPU_FTRS_POWER9_DD1, - .cpu_user_features = COMMON_USER_POWER9, - .cpu_user_features2 = COMMON_USER2_POWER9, - .mmu_features = MMU_FTRS_POWER9, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 6, - .pmc_type = PPC_PMC_IBM, - .oprofile_cpu_type = "ppc64/power9", - .oprofile_type = PPC_OPROFILE_INVALID, - .cpu_setup = __setup_cpu_power9, - .cpu_restore = __restore_cpu_power9, - .machine_check_early = __machine_check_early_realmode_p9, - .platform = "power9", - }, { /* Power9 DD2.0 */ .pvr_mask = 0xffffefff, .pvr_value = 0x004e0200, diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c index 4be1c0de9406..98c373a4c1cf 100644 --- a/arch/powerpc/kernel/dt_cpu_ftrs.c +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c @@ -701,9 +701,7 @@ static __init void cpufeatures_cpu_quirks(void) /* * Not all quirks can be derived from the cpufeatures device tree. */ - if ((version & 0xffffff00) == 0x004e0100) - cur_cpu_spec->cpu_features |= CPU_FTR_POWER9_DD1; - else if ((version & 0xffffefff) == 0x004e0200) + if ((version & 0xffffefff) == 0x004e0200) ; /* DD2.0 has no feature flag */ else if ((version & 0xffffefff) == 0x004e0201) cur_cpu_spec->cpu_features |= CPU_FTR_POWER9_DD2_1; diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 285c6465324a..76a14702cb9c 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -276,9 +276,7 @@ BEGIN_FTR_SECTION * * This interrupt can wake directly from idle. If that is the case, * the machine check is handled then the idle wakeup code is called - * to restore state. In that case, the POWER9 DD1 idle PACA workaround - * is not applied in the early machine check code, which will cause - * bugs. + * to restore state. */ mr r11,r1 /* Save r1 */ lhz r10,PACA_IN_MCE(r13) diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S index e734f6e45abc..d85d5515a091 100644 --- a/arch/powerpc/kernel/idle_book3s.S +++ b/arch/powerpc/kernel/idle_book3s.S @@ -466,43 +466,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_XER_SO_BUG) blr /* return 0 for wakeup cause / SRR1 value */ #endif -/* - * On waking up from stop 0,1,2 with ESL=1 on POWER9 DD1, - * HSPRG0 will be set to the HSPRG0 value of one of the - * threads in this core. Thus the value we have in r13 - * may not be this thread's paca pointer. - * - * Fortunately, the TIR remains invariant. Since this thread's - * paca pointer is recorded in all its sibling's paca, we can - * correctly recover this thread's paca pointer if we - * know the index of this thread in the core. - * - * This index can be obtained from the TIR. - * - * i.e, thread's position in the core = TIR. - * If this value is i, then this thread's paca is - * paca->thread_sibling_pacas[i]. - */ -power9_dd1_recover_paca: - mfspr r4, SPRN_TIR - /* - * Since each entry in thread_sibling_pacas is 8 bytes - * we need to left-shift by 3 bits. Thus r4 = i * 8 - */ - sldi r4, r4, 3 - /* Get &paca->thread_sibling_pacas[0] in r5 */ - ld r5, PACA_SIBLING_PACA_PTRS(r13) - /* Load paca->thread_sibling_pacas[i] into r13 */ - ldx r13, r4, r5 - SET_PACA(r13) - /* - * Indicate that we have lost NVGPR state - * which needs to be restored from the stack. - */ - li r3, 1 - stb r3,PACA_NAPSTATELOST(r13) - blr - /* * Called from machine check handler for powersave wakeups. * Low level machine check processing has already been done. Now just @@ -537,9 +500,6 @@ pnv_powersave_wakeup: ld r2, PACATOC(r13) BEGIN_FTR_SECTION -BEGIN_FTR_SECTION_NESTED(70) - bl power9_dd1_recover_paca -END_FTR_SECTION_NESTED_IFSET(CPU_FTR_POWER9_DD1, 70) bl pnv_restore_hyp_resource_arch300 FTR_SECTION_ELSE bl pnv_restore_hyp_resource_arch207 @@ -602,22 +562,12 @@ END_FTR_SECTION_IFCLR(CPU_FTR_POWER9_DD2_1) LOAD_REG_ADDRBASE(r5,pnv_first_deep_stop_state) ld r4,ADDROFF(pnv_first_deep_stop_state)(r5) -BEGIN_FTR_SECTION_NESTED(71) - /* - * Assume that we are waking up from the state - * same as the Requested Level (RL) in the PSSCR - * which are Bits 60-63 - */ - ld r5,PACA_REQ_PSSCR(r13) - rldicl r5,r5,0,60 -FTR_SECTION_ELSE_NESTED(71) /* * 0-3 bits correspond to Power-Saving Level Status * which indicates the idle state we are waking up from */ mfspr r5, SPRN_PSSCR rldicl r5,r5,4,60 -ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_POWER9_DD1, 71) li r0, 0 /* clear requested_psscr to say we're awake */ std r0, PACA_REQ_PSSCR(r13) cmpd cr4,r5,r4 diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 9ef4aea9fffe..27f0caee55ea 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1250,17 +1250,9 @@ struct task_struct *__switch_to(struct task_struct *prev, * mappings. If the new process has the foreign real address * mappings, we must issue a cp_abort to clear any state and * prevent snooping, corruption or a covert channel. - * - * DD1 allows paste into normal system memory so we do an - * unpaired copy, rather than cp_abort, to clear the buffer, - * since cp_abort is quite expensive. */ - if (current_thread_info()->task->thread.used_vas) { + if (current_thread_info()->task->thread.used_vas) asm volatile(PPC_CP_ABORT); - } else if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { - asm volatile(PPC_COPY(%0, %1) - : : "r"(dummy_copy_buffer), "r"(0)); - } } #endif /* CONFIG_PPC_BOOK3S_64 */ diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index 176f911ee983..0af1c0aea1fe 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -66,10 +66,7 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, bits = root & RPDS_MASK; root = root & RPDB_MASK; - /* P9 DD1 interprets RTS (radix tree size) differently */ offset = rts + 31; - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) - offset -= 3; /* current implementations only support 52-bit space */ if (offset != 52) @@ -160,17 +157,7 @@ static unsigned long kvmppc_radix_update_pte(struct kvm *kvm, pte_t *ptep, unsigned long clr, unsigned long set, unsigned long addr, unsigned int shift) { - unsigned long old = 0; - - if (!(clr & _PAGE_PRESENT) && cpu_has_feature(CPU_FTR_POWER9_DD1) && - pte_present(*ptep)) { - /* have to invalidate it first */ - old = __radix_pte_update(ptep, _PAGE_PRESENT, 0); - kvmppc_radix_tlbie_page(kvm, addr, shift); - set |= _PAGE_PRESENT; - old &= _PAGE_PRESENT; - } - return __radix_pte_update(ptep, clr, set) | old; + return __radix_pte_update(ptep, clr, set); } void kvmppc_radix_set_pte_at(struct kvm *kvm, unsigned long addr, diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index de686b340f4a..b568582120a3 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -1693,14 +1693,6 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, r = set_vpa(vcpu, &vcpu->arch.dtl, addr, len); break; case KVM_REG_PPC_TB_OFFSET: - /* - * POWER9 DD1 has an erratum where writing TBU40 causes - * the timebase to lose ticks. So we don't let the - * timebase offset be changed on P9 DD1. (It is - * initialized to zero.) - */ - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) - break; /* round up to multiple of 2^24 */ vcpu->arch.vcore->tb_offset = ALIGN(set_reg_val(id, *val), 1UL << 24); @@ -2026,8 +2018,6 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm, /* * Set the default HFSCR for the guest from the host value. * This value is only used on POWER9. - * On POWER9 DD1, TM doesn't work, so we make sure to - * prevent the guest from using it. * On POWER9, we want to virtualize the doorbell facility, so we * turn off the HFSCR bit, which causes those instructions to trap. */ diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 153988d878e8..6e4554b273f1 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -916,9 +916,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_DAWR) mtspr SPRN_BESCR, r6 mtspr SPRN_PID, r7 mtspr SPRN_WORT, r8 -BEGIN_FTR_SECTION - PPC_INVALIDATE_ERAT -END_FTR_SECTION_IFSET(CPU_FTR_POWER9_DD1) BEGIN_FTR_SECTION /* POWER8-only registers */ ld r5, VCPU_TCSCR(r4) @@ -1912,7 +1909,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) ld r5, VCPU_KVM(r9) lbz r0, KVM_RADIX(r5) cmpwi cr2, r0, 0 - beq cr2, 4f + beq cr2, 2f /* * Radix: do eieio; tlbsync; ptesync sequence in case we @@ -1952,11 +1949,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) bdnz 1b ptesync -2: /* Flush the ERAT on radix P9 DD1 guest exit */ -BEGIN_FTR_SECTION - PPC_INVALIDATE_ERAT -END_FTR_SECTION_IFSET(CPU_FTR_POWER9_DD1) -4: +2: #endif /* CONFIG_PPC_RADIX_MMU */ /* @@ -3367,11 +3360,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300) mtspr SPRN_CIABR, r0 mtspr SPRN_DAWRX, r0 - /* Flush the ERAT on radix P9 DD1 guest exit */ -BEGIN_FTR_SECTION - PPC_INVALIDATE_ERAT -END_FTR_SECTION_IFSET(CPU_FTR_POWER9_DD1) - BEGIN_MMU_FTR_SECTION b 4f END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX) diff --git a/arch/powerpc/kvm/book3s_xive_template.c b/arch/powerpc/kvm/book3s_xive_template.c index 6e41ba7ec8f4..4171ede8722b 100644 --- a/arch/powerpc/kvm/book3s_xive_template.c +++ b/arch/powerpc/kvm/book3s_xive_template.c @@ -25,18 +25,6 @@ static void GLUE(X_PFX,ack_pending)(struct kvmppc_xive_vcpu *xc) */ eieio(); - /* - * DD1 bug workaround: If PIPR is less favored than CPPR - * ignore the interrupt or we might incorrectly lose an IPB - * bit. - */ - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { - __be64 qw1 = __x_readq(__x_tima + TM_QW1_OS); - u8 pipr = be64_to_cpu(qw1) & 0xff; - if (pipr >= xc->hw_cppr) - return; - } - /* Perform the acknowledge OS to register cycle. */ ack = be16_to_cpu(__x_readw(__x_tima + TM_SPC_ACK_OS_REG)); @@ -89,8 +77,15 @@ static void GLUE(X_PFX,source_eoi)(u32 hw_irq, struct xive_irq_data *xd) /* If the XIVE supports the new "store EOI facility, use it */ if (xd->flags & XIVE_IRQ_FLAG_STORE_EOI) __x_writeq(0, __x_eoi_page(xd) + XIVE_ESB_STORE_EOI); - else if (hw_irq && xd->flags & XIVE_IRQ_FLAG_EOI_FW) { + else if (hw_irq && xd->flags & XIVE_IRQ_FLAG_EOI_FW) opal_int_eoi(hw_irq); + else if (xd->flags & XIVE_IRQ_FLAG_LSI) { + /* + * For LSIs the HW EOI cycle is used rather than PQ bits, + * as they are automatically re-triggred in HW when still + * pending. + */ + __x_readq(__x_eoi_page(xd) + XIVE_ESB_LOAD_EOI); } else { uint64_t eoi_val; @@ -102,20 +97,12 @@ static void GLUE(X_PFX,source_eoi)(u32 hw_irq, struct xive_irq_data *xd) * * This allows us to then do a re-trigger if Q was set * rather than synthetizing an interrupt in software - * - * For LSIs, using the HW EOI cycle works around a problem - * on P9 DD1 PHBs where the other ESB accesses don't work - * properly. */ - if (xd->flags & XIVE_IRQ_FLAG_LSI) - __x_readq(__x_eoi_page(xd) + XIVE_ESB_LOAD_EOI); - else { - eoi_val = GLUE(X_PFX,esb_load)(xd, XIVE_ESB_SET_PQ_00); - - /* Re-trigger if needed */ - if ((eoi_val & 1) && __x_trig_page(xd)) - __x_writeq(0, __x_trig_page(xd)); - } + eoi_val = GLUE(X_PFX,esb_load)(xd, XIVE_ESB_SET_PQ_00); + + /* Re-trigger if needed */ + if ((eoi_val & 1) && __x_trig_page(xd)) + __x_writeq(0, __x_trig_page(xd)); } } diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 8318716e5075..5a72e980e25a 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -808,31 +808,6 @@ int hash__remove_section_mapping(unsigned long start, unsigned long end) } #endif /* CONFIG_MEMORY_HOTPLUG */ -static void update_hid_for_hash(void) -{ - unsigned long hid0; - unsigned long rb = 3UL << PPC_BITLSHIFT(53); /* IS = 3 */ - - asm volatile("ptesync": : :"memory"); - /* prs = 0, ric = 2, rs = 0, r = 1 is = 3 */ - asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) - : : "r"(rb), "i"(0), "i"(0), "i"(2), "r"(0) : "memory"); - asm volatile("eieio; tlbsync; ptesync; isync; slbia": : :"memory"); - trace_tlbie(0, 0, rb, 0, 2, 0, 0); - - /* - * now switch the HID - */ - hid0 = mfspr(SPRN_HID0); - hid0 &= ~HID0_POWER9_RADIX; - mtspr(SPRN_HID0, hid0); - asm volatile("isync": : :"memory"); - - /* Wait for it to happen */ - while ((mfspr(SPRN_HID0) & HID0_POWER9_RADIX)) - cpu_relax(); -} - static void __init hash_init_partition_table(phys_addr_t hash_table, unsigned long htab_size) { @@ -845,8 +820,6 @@ static void __init hash_init_partition_table(phys_addr_t hash_table, htab_size = __ilog2(htab_size) - 18; mmu_partition_table_set_entry(0, hash_table | htab_size, 0); pr_info("Partition table %p\n", partition_tb); - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) - update_hid_for_hash(); } static void __init htab_initialize(void) @@ -1077,9 +1050,6 @@ void hash__early_init_mmu_secondary(void) /* Initialize hash table for that CPU */ if (!firmware_has_feature(FW_FEATURE_LPAR)) { - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) - update_hid_for_hash(); - if (!cpu_has_feature(CPU_FTR_ARCH_300)) mtspr(SPRN_SDR1, _SDR1); else diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 7c5f479c5c00..ec7538a802f9 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -620,15 +620,12 @@ static int __init add_huge_page_size(unsigned long long size) * firmware we only add hugetlb support for page sizes that can be * supported by linux page table layout. * For now we have - * Radix: 2M + * Radix: 2M and 1G * Hash: 16M and 16G */ if (radix_enabled()) { - if (mmu_psize != MMU_PAGE_2M) { - if (cpu_has_feature(CPU_FTR_POWER9_DD1) || - (mmu_psize != MMU_PAGE_1G)) - return -EINVAL; - } + if (mmu_psize != MMU_PAGE_2M && mmu_psize != MMU_PAGE_1G) + return -EINVAL; } else { if (mmu_psize != MMU_PAGE_16M && mmu_psize != MMU_PAGE_16G) return -EINVAL; diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c index f3d4b4a0e561..39e9ef0eb78b 100644 --- a/arch/powerpc/mm/mmu_context_book3s64.c +++ b/arch/powerpc/mm/mmu_context_book3s64.c @@ -273,15 +273,7 @@ void arch_exit_mmap(struct mm_struct *mm) #ifdef CONFIG_PPC_RADIX_MMU void radix__switch_mmu_context(struct mm_struct *prev, struct mm_struct *next) { - - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { - isync(); - mtspr(SPRN_PID, next->context.id); - isync(); - asm volatile(PPC_INVALIDATE_ERAT : : :"memory"); - } else { - mtspr(SPRN_PID, next->context.id); - isync(); - } + mtspr(SPRN_PID, next->context.id); + isync(); } #endif diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c index 96f68c5aa1f5..bba168d02235 100644 --- a/arch/powerpc/mm/pgtable-radix.c +++ b/arch/powerpc/mm/pgtable-radix.c @@ -226,16 +226,6 @@ void radix__mark_rodata_ro(void) { unsigned long start, end; - /* - * mark_rodata_ro() will mark itself as !writable at some point. - * Due to DD1 workaround in radix__pte_update(), we'll end up with - * an invalid pte and the system will crash quite severly. - */ - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { - pr_warn("Warning: Unable to mark rodata read only on P9 DD1\n"); - return; - } - start = (unsigned long)_stext; end = (unsigned long)__init_begin; @@ -533,35 +523,6 @@ found: return; } -static void update_hid_for_radix(void) -{ - unsigned long hid0; - unsigned long rb = 3UL << PPC_BITLSHIFT(53); /* IS = 3 */ - - asm volatile("ptesync": : :"memory"); - /* prs = 0, ric = 2, rs = 0, r = 1 is = 3 */ - asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) - : : "r"(rb), "i"(1), "i"(0), "i"(2), "r"(0) : "memory"); - /* prs = 1, ric = 2, rs = 0, r = 1 is = 3 */ - asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) - : : "r"(rb), "i"(1), "i"(1), "i"(2), "r"(0) : "memory"); - asm volatile("eieio; tlbsync; ptesync; isync; slbia": : :"memory"); - trace_tlbie(0, 0, rb, 0, 2, 0, 1); - trace_tlbie(0, 0, rb, 0, 2, 1, 1); - - /* - * now switch the HID - */ - hid0 = mfspr(SPRN_HID0); - hid0 |= HID0_POWER9_RADIX; - mtspr(SPRN_HID0, hid0); - asm volatile("isync": : :"memory"); - - /* Wait for it to happen */ - while (!(mfspr(SPRN_HID0) & HID0_POWER9_RADIX)) - cpu_relax(); -} - static void radix_init_amor(void) { /* @@ -576,22 +537,12 @@ static void radix_init_amor(void) static void radix_init_iamr(void) { - unsigned long iamr; - - /* - * The IAMR should set to 0 on DD1. - */ - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) - iamr = 0; - else - iamr = (1ul << 62); - /* * Radix always uses key0 of the IAMR to determine if an access is * allowed. We set bit 0 (IBM bit 1) of key0, to prevent instruction * fetch. */ - mtspr(SPRN_IAMR, iamr); + mtspr(SPRN_IAMR, (1ul << 62)); } void __init radix__early_init_mmu(void) @@ -644,8 +595,6 @@ void __init radix__early_init_mmu(void) if (!firmware_has_feature(FW_FEATURE_LPAR)) { radix_init_native(); - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) - update_hid_for_radix(); lpcr = mfspr(SPRN_LPCR); mtspr(SPRN_LPCR, lpcr | LPCR_UPRT | LPCR_HR); radix_init_partition_table(); @@ -671,10 +620,6 @@ void radix__early_init_mmu_secondary(void) * update partition table control register and UPRT */ if (!firmware_has_feature(FW_FEATURE_LPAR)) { - - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) - update_hid_for_radix(); - lpcr = mfspr(SPRN_LPCR); mtspr(SPRN_LPCR, lpcr | LPCR_UPRT | LPCR_HR); @@ -1095,8 +1040,7 @@ void radix__ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep, * To avoid NMMU hang while relaxing access, we need mark * the pte invalid in between. */ - if (cpu_has_feature(CPU_FTR_POWER9_DD1) || - atomic_read(&mm->context.copros) > 0) { + if (atomic_read(&mm->context.copros) > 0) { unsigned long old_pte, new_pte; old_pte = __radix_pte_update(ptep, ~0, 0); diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c index 67a6e86d3e7e..902767b8a9c1 100644 --- a/arch/powerpc/mm/tlb-radix.c +++ b/arch/powerpc/mm/tlb-radix.c @@ -994,24 +994,6 @@ void radix__flush_tlb_all(void) asm volatile("eieio; tlbsync; ptesync": : :"memory"); } -void radix__flush_tlb_pte_p9_dd1(unsigned long old_pte, struct mm_struct *mm, - unsigned long address) -{ - /* - * We track page size in pte only for DD1, So we can - * call this only on DD1. - */ - if (!cpu_has_feature(CPU_FTR_POWER9_DD1)) { - VM_WARN_ON(1); - return; - } - - if (old_pte & R_PAGE_LARGE) - radix__flush_tlb_page_psize(mm, address, MMU_PAGE_2M); - else - radix__flush_tlb_page_psize(mm, address, mmu_virtual_psize); -} - #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE extern void radix_kvm_prefetch_workaround(struct mm_struct *mm) { diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 3f66fcf8ad99..01f92c4a9f02 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -128,10 +128,6 @@ static inline void power_pmu_bhrb_disable(struct perf_event *event) {} static void power_pmu_sched_task(struct perf_event_context *ctx, bool sched_in) {} static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {} static void pmao_restore_workaround(bool ebb) { } -static bool use_ic(u64 event) -{ - return false; -} #endif /* CONFIG_PPC32 */ static bool regs_use_siar(struct pt_regs *regs) @@ -714,14 +710,6 @@ static void pmao_restore_workaround(bool ebb) mtspr(SPRN_PMC6, pmcs[5]); } -static bool use_ic(u64 event) -{ - if (cpu_has_feature(CPU_FTR_POWER9_DD1) && - (event == 0x200f2 || event == 0x300f2)) - return true; - - return false; -} #endif /* CONFIG_PPC64 */ static void perf_event_interrupt(struct pt_regs *regs); @@ -1046,7 +1034,6 @@ static u64 check_and_compute_delta(u64 prev, u64 val) static void power_pmu_read(struct perf_event *event) { s64 val, delta, prev; - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); if (event->hw.state & PERF_HES_STOPPED) return; @@ -1056,13 +1043,6 @@ static void power_pmu_read(struct perf_event *event) if (is_ebb_event(event)) { val = read_pmc(event->hw.idx); - if (use_ic(event->attr.config)) { - val = mfspr(SPRN_IC); - if (val > cpuhw->ic_init) - val = val - cpuhw->ic_init; - else - val = val + (0 - cpuhw->ic_init); - } local64_set(&event->hw.prev_count, val); return; } @@ -1076,13 +1056,6 @@ static void power_pmu_read(struct perf_event *event) prev = local64_read(&event->hw.prev_count); barrier(); val = read_pmc(event->hw.idx); - if (use_ic(event->attr.config)) { - val = mfspr(SPRN_IC); - if (val > cpuhw->ic_init) - val = val - cpuhw->ic_init; - else - val = val + (0 - cpuhw->ic_init); - } delta = check_and_compute_delta(prev, val); if (!delta) return; @@ -1535,13 +1508,6 @@ nocheck: event->attr.branch_sample_type); } - /* - * Workaround for POWER9 DD1 to use the Instruction Counter - * register value for instruction counting - */ - if (use_ic(event->attr.config)) - cpuhw->ic_init = mfspr(SPRN_IC); - perf_pmu_enable(event->pmu); local_irq_restore(flags); return ret; diff --git a/arch/powerpc/perf/isa207-common.c b/arch/powerpc/perf/isa207-common.c index 2efee3f196f5..177de814286f 100644 --- a/arch/powerpc/perf/isa207-common.c +++ b/arch/powerpc/perf/isa207-common.c @@ -59,7 +59,7 @@ static bool is_event_valid(u64 event) { u64 valid_mask = EVENT_VALID_MASK; - if (cpu_has_feature(CPU_FTR_ARCH_300) && !cpu_has_feature(CPU_FTR_POWER9_DD1)) + if (cpu_has_feature(CPU_FTR_ARCH_300)) valid_mask = p9_EVENT_VALID_MASK; return !(event & ~valid_mask); @@ -86,8 +86,6 @@ static void mmcra_sdar_mode(u64 event, unsigned long *mmcra) * Incase of Power9: * Marked event: MMCRA[SDAR_MODE] will be set to 0b00 ('No Updates'), * or if group already have any marked events. - * Non-Marked events (for DD1): - * MMCRA[SDAR_MODE] will be set to 0b01 * For rest * MMCRA[SDAR_MODE] will be set from event code. * If sdar_mode from event is zero, default to 0b01. Hardware @@ -96,7 +94,7 @@ static void mmcra_sdar_mode(u64 event, unsigned long *mmcra) if (cpu_has_feature(CPU_FTR_ARCH_300)) { if (is_event_marked(event) || (*mmcra & MMCRA_SAMPLE_ENABLE)) *mmcra &= MMCRA_SDAR_MODE_NO_UPDATES; - else if (!cpu_has_feature(CPU_FTR_POWER9_DD1) && p9_SDAR_MODE(event)) + else if (p9_SDAR_MODE(event)) *mmcra |= p9_SDAR_MODE(event) << MMCRA_SDAR_MODE_SHIFT; else *mmcra |= MMCRA_SDAR_MODE_DCACHE; @@ -106,7 +104,7 @@ static void mmcra_sdar_mode(u64 event, unsigned long *mmcra) static u64 thresh_cmp_val(u64 value) { - if (cpu_has_feature(CPU_FTR_ARCH_300) && !cpu_has_feature(CPU_FTR_POWER9_DD1)) + if (cpu_has_feature(CPU_FTR_ARCH_300)) return value << p9_MMCRA_THR_CMP_SHIFT; return value << MMCRA_THR_CMP_SHIFT; @@ -114,7 +112,7 @@ static u64 thresh_cmp_val(u64 value) static unsigned long combine_from_event(u64 event) { - if (cpu_has_feature(CPU_FTR_ARCH_300) && !cpu_has_feature(CPU_FTR_POWER9_DD1)) + if (cpu_has_feature(CPU_FTR_ARCH_300)) return p9_EVENT_COMBINE(event); return EVENT_COMBINE(event); @@ -122,7 +120,7 @@ static unsigned long combine_from_event(u64 event) static unsigned long combine_shift(unsigned long pmc) { - if (cpu_has_feature(CPU_FTR_ARCH_300) && !cpu_has_feature(CPU_FTR_POWER9_DD1)) + if (cpu_has_feature(CPU_FTR_ARCH_300)) return p9_MMCR1_COMBINE_SHIFT(pmc); return MMCR1_COMBINE_SHIFT(pmc); diff --git a/arch/powerpc/perf/isa207-common.h b/arch/powerpc/perf/isa207-common.h index 6a0b586c935a..0028f4b9490d 100644 --- a/arch/powerpc/perf/isa207-common.h +++ b/arch/powerpc/perf/isa207-common.h @@ -158,11 +158,6 @@ CNST_PMC_VAL(1) | CNST_PMC_VAL(2) | CNST_PMC_VAL(3) | \ CNST_PMC_VAL(4) | CNST_PMC_VAL(5) | CNST_PMC_VAL(6) | CNST_NC_VAL -/* - * Lets restrict use of PMC5 for instruction counting. - */ -#define P9_DD1_TEST_ADDER (ISA207_TEST_ADDER | CNST_PMC_VAL(5)) - /* Bits in MMCR1 for PowerISA v2.07 */ #define MMCR1_UNIT_SHIFT(pmc) (60 - (4 * ((pmc) - 1))) #define MMCR1_COMBINE_SHIFT(pmc) (35 - ((pmc) - 1)) diff --git a/arch/powerpc/perf/power9-pmu.c b/arch/powerpc/perf/power9-pmu.c index 2ca0b33b4efb..e012b1030a5b 100644 --- a/arch/powerpc/perf/power9-pmu.c +++ b/arch/powerpc/perf/power9-pmu.c @@ -219,12 +219,6 @@ static struct attribute_group power9_pmu_events_group = { .attrs = power9_events_attr, }; -static const struct attribute_group *power9_isa207_pmu_attr_groups[] = { - &isa207_pmu_format_group, - &power9_pmu_events_group, - NULL, -}; - PMU_FORMAT_ATTR(event, "config:0-51"); PMU_FORMAT_ATTR(pmcxsel, "config:0-7"); PMU_FORMAT_ATTR(mark, "config:8"); @@ -267,17 +261,6 @@ static const struct attribute_group *power9_pmu_attr_groups[] = { NULL, }; -static int power9_generic_events_dd1[] = { - [PERF_COUNT_HW_CPU_CYCLES] = PM_CYC, - [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = PM_ICT_NOSLOT_CYC, - [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = PM_CMPLU_STALL, - [PERF_COUNT_HW_INSTRUCTIONS] = PM_INST_DISP, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = PM_BR_CMPL_ALT, - [PERF_COUNT_HW_BRANCH_MISSES] = PM_BR_MPRED_CMPL, - [PERF_COUNT_HW_CACHE_REFERENCES] = PM_LD_REF_L1, - [PERF_COUNT_HW_CACHE_MISSES] = PM_LD_MISS_L1_FIN, -}; - static int power9_generic_events[] = { [PERF_COUNT_HW_CPU_CYCLES] = PM_CYC, [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = PM_ICT_NOSLOT_CYC, @@ -439,25 +422,6 @@ static int power9_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { #undef C -static struct power_pmu power9_isa207_pmu = { - .name = "POWER9", - .n_counter = MAX_PMU_COUNTERS, - .add_fields = ISA207_ADD_FIELDS, - .test_adder = P9_DD1_TEST_ADDER, - .compute_mmcr = isa207_compute_mmcr, - .config_bhrb = power9_config_bhrb, - .bhrb_filter_map = power9_bhrb_filter_map, - .get_constraint = isa207_get_constraint, - .get_alternatives = power9_get_alternatives, - .disable_pmc = isa207_disable_pmc, - .flags = PPMU_NO_SIAR | PPMU_ARCH_207S, - .n_generic = ARRAY_SIZE(power9_generic_events_dd1), - .generic_events = power9_generic_events_dd1, - .cache_events = &power9_cache_events, - .attr_groups = power9_isa207_pmu_attr_groups, - .bhrb_nr = 32, -}; - static struct power_pmu power9_pmu = { .name = "POWER9", .n_counter = MAX_PMU_COUNTERS, @@ -500,23 +464,7 @@ static int __init init_power9_pmu(void) } } - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { - /* - * Since PM_INST_CMPL may not provide right counts in all - * sampling scenarios in power9 DD1, instead use PM_INST_DISP. - */ - EVENT_VAR(PM_INST_CMPL, _g).id = PM_INST_DISP; - /* - * Power9 DD1 should use PM_BR_CMPL_ALT event code for - * "branches" to provide correct counter value. - */ - EVENT_VAR(PM_BR_CMPL, _g).id = PM_BR_CMPL_ALT; - EVENT_VAR(PM_BR_CMPL, _c).id = PM_BR_CMPL_ALT; - rc = register_power_pmu(&power9_isa207_pmu); - } else { - rc = register_power_pmu(&power9_pmu); - } - + rc = register_power_pmu(&power9_pmu); if (rc) return rc; diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c index 1c5d0675b43c..12f13acee1f6 100644 --- a/arch/powerpc/platforms/powernv/idle.c +++ b/arch/powerpc/platforms/powernv/idle.c @@ -177,11 +177,6 @@ static void pnv_alloc_idle_core_states(void) paca_ptrs[cpu]->core_idle_state_ptr = core_idle_state; paca_ptrs[cpu]->thread_idle_state = PNV_THREAD_RUNNING; paca_ptrs[cpu]->thread_mask = 1 << j; - if (!cpu_has_feature(CPU_FTR_POWER9_DD1)) - continue; - paca_ptrs[cpu]->thread_sibling_pacas = - kmalloc_node(paca_ptr_array_size, - GFP_KERNEL, node); } } @@ -805,29 +800,6 @@ static int __init pnv_init_idle_states(void) pnv_alloc_idle_core_states(); - /* - * For each CPU, record its PACA address in each of it's - * sibling thread's PACA at the slot corresponding to this - * CPU's index in the core. - */ - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { - int cpu; - - pr_info("powernv: idle: Saving PACA pointers of all CPUs in their thread sibling PACA\n"); - for_each_present_cpu(cpu) { - int base_cpu = cpu_first_thread_sibling(cpu); - int idx = cpu_thread_in_core(cpu); - int i; - - for (i = 0; i < threads_per_core; i++) { - int j = base_cpu + i; - - paca_ptrs[j]->thread_sibling_pacas[idx] = - paca_ptrs[cpu]; - } - } - } - if (supported_cpuidle_states & OPAL_PM_NAP_ENABLED) ppc_md.power_save = power7_idle; diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index b80909957792..0d354e19ef92 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c @@ -283,23 +283,6 @@ static void pnv_cause_ipi(int cpu) ic_cause_ipi(cpu); } -static void pnv_p9_dd1_cause_ipi(int cpu) -{ - int this_cpu = get_cpu(); - - /* - * POWER9 DD1 has a global addressed msgsnd, but for now we restrict - * IPIs to same core, because it requires additional synchronization - * for inter-core doorbells which we do not implement. - */ - if (cpumask_test_cpu(cpu, cpu_sibling_mask(this_cpu))) - doorbell_global_ipi(cpu); - else - ic_cause_ipi(cpu); - - put_cpu(); -} - static void __init pnv_smp_probe(void) { if (xive_enabled()) @@ -311,14 +294,10 @@ static void __init pnv_smp_probe(void) ic_cause_ipi = smp_ops->cause_ipi; WARN_ON(!ic_cause_ipi); - if (cpu_has_feature(CPU_FTR_ARCH_300)) { - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) - smp_ops->cause_ipi = pnv_p9_dd1_cause_ipi; - else - smp_ops->cause_ipi = doorbell_global_ipi; - } else { + if (cpu_has_feature(CPU_FTR_ARCH_300)) + smp_ops->cause_ipi = doorbell_global_ipi; + else smp_ops->cause_ipi = pnv_cause_ipi; - } } } diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index 3459015092fa..4758173df426 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -319,7 +319,7 @@ void xive_do_source_eoi(u32 hw_irq, struct xive_irq_data *xd) * The FW told us to call it. This happens for some * interrupt sources that need additional HW whacking * beyond the ESB manipulation. For example LPC interrupts - * on P9 DD1.0 need a latch to be clared in the LPC bridge + * on P9 DD1.0 needed a latch to be clared in the LPC bridge * itself. The Firmware will take care of it. */ if (WARN_ON_ONCE(!xive_ops->eoi)) @@ -337,9 +337,9 @@ void xive_do_source_eoi(u32 hw_irq, struct xive_irq_data *xd) * This allows us to then do a re-trigger if Q was set * rather than synthesizing an interrupt in software * - * For LSIs, using the HW EOI cycle works around a problem - * on P9 DD1 PHBs where the other ESB accesses don't work - * properly. + * For LSIs the HW EOI cycle is used rather than PQ bits, + * as they are automatically re-triggred in HW when still + * pending. */ if (xd->flags & XIVE_IRQ_FLAG_LSI) xive_esb_read(xd, XIVE_ESB_LOAD_EOI); diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 47166ad2a669..21119cfe8474 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2429,7 +2429,6 @@ static void dump_one_paca(int cpu) DUMP(p, thread_idle_state, "%#-*x"); DUMP(p, thread_mask, "%#-*x"); DUMP(p, subcore_sibling_mask, "%#-*x"); - DUMP(p, thread_sibling_pacas, "%-*px"); DUMP(p, requested_psscr, "%#-*llx"); DUMP(p, stop_sprs.pid, "%#-*llx"); DUMP(p, stop_sprs.ldbar, "%#-*llx"); diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index 918d4fb742d1..505f973e13f3 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -865,14 +865,6 @@ static inline bool cxl_is_power9(void) return false; } -static inline bool cxl_is_power9_dd1(void) -{ - if ((pvr_version_is(PVR_POWER9)) && - cpu_has_feature(CPU_FTR_POWER9_DD1)) - return true; - return false; -} - ssize_t cxl_pci_afu_read_err_buffer(struct cxl_afu *afu, char *buf, loff_t off, size_t count); diff --git a/drivers/misc/cxl/cxllib.c b/drivers/misc/cxl/cxllib.c index 0bc7c31cf739..5a3f91255258 100644 --- a/drivers/misc/cxl/cxllib.c +++ b/drivers/misc/cxl/cxllib.c @@ -102,10 +102,6 @@ int cxllib_get_xsl_config(struct pci_dev *dev, struct cxllib_xsl_config *cfg) rc = cxl_get_xsl9_dsnctl(dev, capp_unit_id, &cfg->dsnctl); if (rc) return rc; - if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { - /* workaround for DD1 - nbwind = capiind */ - cfg->dsnctl |= ((u64)0x02 << (63-47)); - } cfg->version = CXL_XSL_CONFIG_CURRENT_VERSION; cfg->log_bar_size = CXL_CAPI_WINDOW_LOG_SIZE; diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 429d6de1dde7..2af0d4c47b76 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -465,23 +465,21 @@ int cxl_get_xsl9_dsnctl(struct pci_dev *dev, u64 capp_unit_id, u64 *reg) /* nMMU_ID Defaults to: b’000001001’*/ xsl_dsnctl |= ((u64)0x09 << (63-28)); - if (!(cxl_is_power9_dd1())) { - /* - * Used to identify CAPI packets which should be sorted into - * the Non-Blocking queues by the PHB. This field should match - * the PHB PBL_NBW_CMPM register - * nbwind=0x03, bits [57:58], must include capi indicator. - * Not supported on P9 DD1. - */ - xsl_dsnctl |= (nbwind << (63-55)); + /* + * Used to identify CAPI packets which should be sorted into + * the Non-Blocking queues by the PHB. This field should match + * the PHB PBL_NBW_CMPM register + * nbwind=0x03, bits [57:58], must include capi indicator. + * Not supported on P9 DD1. + */ + 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 |= asnind; - } + /* + * 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 |= asnind; *reg = xsl_dsnctl; return 0; @@ -539,15 +537,8 @@ static int init_implementation_adapter_regs_psl9(struct cxl *adapter, /* Snoop machines */ cxl_p1_write(adapter, CXL_PSL9_APCDEDALLOC, 0x800F000200000000ULL); - if (cxl_is_power9_dd1()) { - /* Disabling deadlock counter CAR */ - cxl_p1_write(adapter, CXL_PSL9_GP_CT, 0x0020000000000001ULL); - /* Enable NORST */ - cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0x8000000000000000ULL); - } else { - /* Enable NORST and DD2 features */ - cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0xC000000000000000ULL); - } + /* Enable NORST and DD2 features */ + cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0xC000000000000000ULL); /* * Check if PSL has data-cache. We need to flush adapter datacache -- cgit v1.2.3 From 00a5c58d9499bd0c290b57205f43a70f2e69d3f6 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 4 Jul 2018 16:13:46 +1000 Subject: KVM: PPC: Make iommu_table::it_userspace big endian We are going to reuse multilevel TCE code for the userspace copy of the TCE table and since it is big endian, let's make the copy big endian too. Reviewed-by: David Gibson Signed-off-by: Alexey Kardashevskiy Acked-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/iommu.h | 2 +- arch/powerpc/kvm/book3s_64_vio.c | 11 ++++++----- arch/powerpc/kvm/book3s_64_vio_hv.c | 10 +++++----- drivers/vfio/vfio_iommu_spapr_tce.c | 19 +++++++++---------- 4 files changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h index 20febe0b7f32..803ac70ecedf 100644 --- a/arch/powerpc/include/asm/iommu.h +++ b/arch/powerpc/include/asm/iommu.h @@ -117,7 +117,7 @@ struct iommu_table { unsigned long *it_map; /* A simple allocation bitmap for now */ unsigned long it_page_shift;/* table iommu page size */ struct list_head it_group_list;/* List of iommu_table_group_link */ - unsigned long *it_userspace; /* userspace view of the table */ + __be64 *it_userspace; /* userspace view of the table */ struct iommu_table_ops *it_ops; struct kref it_kref; }; diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index d066e37551ec..8b9aaf24b0a2 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -378,19 +378,19 @@ static long kvmppc_tce_iommu_mapped_dec(struct kvm *kvm, { struct mm_iommu_table_group_mem_t *mem = NULL; const unsigned long pgsize = 1ULL << tbl->it_page_shift; - unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); + __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); if (!pua) /* it_userspace allocation might be delayed */ return H_TOO_HARD; - mem = mm_iommu_lookup(kvm->mm, *pua, pgsize); + mem = mm_iommu_lookup(kvm->mm, be64_to_cpu(*pua), pgsize); if (!mem) return H_TOO_HARD; mm_iommu_mapped_dec(mem); - *pua = 0; + *pua = cpu_to_be64(0); return H_SUCCESS; } @@ -437,7 +437,8 @@ long kvmppc_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl, enum dma_data_direction dir) { long ret; - unsigned long hpa, *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); + unsigned long hpa; + __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); struct mm_iommu_table_group_mem_t *mem; if (!pua) @@ -464,7 +465,7 @@ long kvmppc_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl, if (dir != DMA_NONE) kvmppc_tce_iommu_mapped_dec(kvm, tbl, entry); - *pua = ua; + *pua = cpu_to_be64(ua); return 0; } diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c index 925fc316a104..236f74b210a7 100644 --- a/arch/powerpc/kvm/book3s_64_vio_hv.c +++ b/arch/powerpc/kvm/book3s_64_vio_hv.c @@ -200,7 +200,7 @@ static long kvmppc_rm_tce_iommu_mapped_dec(struct kvm *kvm, { struct mm_iommu_table_group_mem_t *mem = NULL; const unsigned long pgsize = 1ULL << tbl->it_page_shift; - unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); + __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); if (!pua) /* it_userspace allocation might be delayed */ @@ -210,13 +210,13 @@ static long kvmppc_rm_tce_iommu_mapped_dec(struct kvm *kvm, if (WARN_ON_ONCE_RM(!pua)) return H_HARDWARE; - mem = mm_iommu_lookup_rm(kvm->mm, *pua, pgsize); + mem = mm_iommu_lookup_rm(kvm->mm, be64_to_cpu(*pua), pgsize); if (!mem) return H_TOO_HARD; mm_iommu_mapped_dec(mem); - *pua = 0; + *pua = cpu_to_be64(0); return H_SUCCESS; } @@ -268,7 +268,7 @@ static long kvmppc_rm_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl, { long ret; unsigned long hpa = 0; - unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); + __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); struct mm_iommu_table_group_mem_t *mem; if (!pua) @@ -302,7 +302,7 @@ static long kvmppc_rm_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl, if (dir != DMA_NONE) kvmppc_rm_tce_iommu_mapped_dec(kvm, tbl, entry); - *pua = ua; + *pua = cpu_to_be64(ua); return 0; } diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 759a5bdd40e1..8ab124a67311 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -230,7 +230,7 @@ static long tce_iommu_userspace_view_alloc(struct iommu_table *tbl, decrement_locked_vm(mm, cb >> PAGE_SHIFT); return -ENOMEM; } - tbl->it_userspace = uas; + tbl->it_userspace = (__be64 *) uas; return 0; } @@ -482,20 +482,20 @@ static void tce_iommu_unuse_page_v2(struct tce_container *container, struct mm_iommu_table_group_mem_t *mem = NULL; int ret; unsigned long hpa = 0; - unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); + __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); if (!pua) return; - ret = tce_iommu_prereg_ua_to_hpa(container, *pua, IOMMU_PAGE_SIZE(tbl), - &hpa, &mem); + ret = tce_iommu_prereg_ua_to_hpa(container, be64_to_cpu(*pua), + IOMMU_PAGE_SIZE(tbl), &hpa, &mem); if (ret) - pr_debug("%s: tce %lx at #%lx was not cached, ret=%d\n", - __func__, *pua, entry, ret); + pr_debug("%s: tce %llx at #%lx was not cached, ret=%d\n", + __func__, be64_to_cpu(*pua), entry, ret); if (mem) mm_iommu_mapped_dec(mem); - *pua = 0; + *pua = cpu_to_be64(0); } static int tce_iommu_clear(struct tce_container *container, @@ -607,8 +607,7 @@ static long tce_iommu_build_v2(struct tce_container *container, for (i = 0; i < pages; ++i) { struct mm_iommu_table_group_mem_t *mem = NULL; - unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, - entry + i); + __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry + i); ret = tce_iommu_prereg_ua_to_hpa(container, tce, IOMMU_PAGE_SIZE(tbl), &hpa, &mem); @@ -642,7 +641,7 @@ static long tce_iommu_build_v2(struct tce_container *container, if (dirtmp != DMA_NONE) tce_iommu_unuse_page_v2(container, tbl, entry + i); - *pua = tce; + *pua = cpu_to_be64(tce); tce += IOMMU_PAGE_SIZE(tbl); } -- cgit v1.2.3 From 090bad39b237aad92d8e01baa033699cf0c81cbe Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 4 Jul 2018 16:13:47 +1000 Subject: powerpc/powernv: Add indirect levels to it_userspace We want to support sparse memory and therefore huge chunks of DMA windows do not need to be mapped. If a DMA window big enough to require 2 or more indirect levels, and a DMA window is used to map all RAM (which is a default case for 64bit window), we can actually save some memory by not allocation TCE for regions which we are not going to map anyway. The hardware tables alreary support indirect levels but we also keep host-physical-to-userspace translation array which is allocated by vmalloc() and is a flat array which might use quite some memory. This converts it_userspace from vmalloc'ed array to a multi level table. As the format becomes platform dependend, this replaces the direct access to it_usespace with a iommu_table_ops::useraddrptr hook which returns a pointer to the userspace copy of a TCE; future extension will return NULL if the level was not allocated. This should not change non-KVM handling of TCE tables and it_userspace will not be allocated for non-KVM tables. Reviewed-by: David Gibson Signed-off-by: Alexey Kardashevskiy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/iommu.h | 6 +-- arch/powerpc/kvm/book3s_64_vio_hv.c | 8 ---- arch/powerpc/platforms/powernv/pci-ioda-tce.c | 65 +++++++++++++++++++++------ arch/powerpc/platforms/powernv/pci-ioda.c | 23 +++++++--- arch/powerpc/platforms/powernv/pci.h | 3 +- drivers/vfio/vfio_iommu_spapr_tce.c | 46 ------------------- 6 files changed, 73 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h index 803ac70ecedf..4bdcf22509e6 100644 --- a/arch/powerpc/include/asm/iommu.h +++ b/arch/powerpc/include/asm/iommu.h @@ -69,6 +69,8 @@ struct iommu_table_ops { long index, unsigned long *hpa, enum dma_data_direction *direction); + + __be64 *(*useraddrptr)(struct iommu_table *tbl, long index); #endif void (*clear)(struct iommu_table *tbl, long index, long npages); @@ -123,9 +125,7 @@ struct iommu_table { }; #define IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry) \ - ((tbl)->it_userspace ? \ - &((tbl)->it_userspace[(entry) - (tbl)->it_offset]) : \ - NULL) + ((tbl)->it_ops->useraddrptr((tbl), (entry))) /* Pure 2^n version of get_order */ static inline __attribute_const__ diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c index 236f74b210a7..ee98cf6180d7 100644 --- a/arch/powerpc/kvm/book3s_64_vio_hv.c +++ b/arch/powerpc/kvm/book3s_64_vio_hv.c @@ -206,10 +206,6 @@ static long kvmppc_rm_tce_iommu_mapped_dec(struct kvm *kvm, /* it_userspace allocation might be delayed */ return H_TOO_HARD; - pua = (void *) vmalloc_to_phys(pua); - if (WARN_ON_ONCE_RM(!pua)) - return H_HARDWARE; - mem = mm_iommu_lookup_rm(kvm->mm, be64_to_cpu(*pua), pgsize); if (!mem) return H_TOO_HARD; @@ -282,10 +278,6 @@ static long kvmppc_rm_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl, if (WARN_ON_ONCE_RM(mm_iommu_ua_to_hpa_rm(mem, ua, &hpa))) return H_HARDWARE; - pua = (void *) vmalloc_to_phys(pua); - if (WARN_ON_ONCE_RM(!pua)) - return H_HARDWARE; - if (WARN_ON_ONCE_RM(mm_iommu_mapped_inc(mem))) return H_CLOSED; diff --git a/arch/powerpc/platforms/powernv/pci-ioda-tce.c b/arch/powerpc/platforms/powernv/pci-ioda-tce.c index 726b8693f5ae..88cecc1815d9 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda-tce.c +++ b/arch/powerpc/platforms/powernv/pci-ioda-tce.c @@ -31,9 +31,9 @@ void pnv_pci_setup_iommu_table(struct iommu_table *tbl, tbl->it_type = TCE_PCI; } -static __be64 *pnv_tce(struct iommu_table *tbl, long idx) +static __be64 *pnv_tce(struct iommu_table *tbl, bool user, long idx) { - __be64 *tmp = ((__be64 *)tbl->it_base); + __be64 *tmp = user ? tbl->it_userspace : (__be64 *) tbl->it_base; int level = tbl->it_indirect_levels; const long shift = ilog2(tbl->it_level_size); unsigned long mask = (tbl->it_level_size - 1) << (level * shift); @@ -67,7 +67,7 @@ int pnv_tce_build(struct iommu_table *tbl, long index, long npages, ((rpn + i) << tbl->it_page_shift); unsigned long idx = index - tbl->it_offset + i; - *(pnv_tce(tbl, idx)) = cpu_to_be64(newtce); + *(pnv_tce(tbl, false, idx)) = cpu_to_be64(newtce); } return 0; @@ -86,12 +86,21 @@ int pnv_tce_xchg(struct iommu_table *tbl, long index, if (newtce & TCE_PCI_WRITE) newtce |= TCE_PCI_READ; - oldtce = be64_to_cpu(xchg(pnv_tce(tbl, idx), cpu_to_be64(newtce))); + oldtce = be64_to_cpu(xchg(pnv_tce(tbl, false, idx), + cpu_to_be64(newtce))); *hpa = oldtce & ~(TCE_PCI_READ | TCE_PCI_WRITE); *direction = iommu_tce_direction(oldtce); return 0; } + +__be64 *pnv_tce_useraddrptr(struct iommu_table *tbl, long index) +{ + if (WARN_ON_ONCE(!tbl->it_userspace)) + return NULL; + + return pnv_tce(tbl, true, index - tbl->it_offset); +} #endif void pnv_tce_free(struct iommu_table *tbl, long index, long npages) @@ -101,13 +110,15 @@ void pnv_tce_free(struct iommu_table *tbl, long index, long npages) for (i = 0; i < npages; i++) { unsigned long idx = index - tbl->it_offset + i; - *(pnv_tce(tbl, idx)) = cpu_to_be64(0); + *(pnv_tce(tbl, false, idx)) = cpu_to_be64(0); } } unsigned long pnv_tce_get(struct iommu_table *tbl, long index) { - return be64_to_cpu(*(pnv_tce(tbl, index - tbl->it_offset))); + __be64 *ptce = pnv_tce(tbl, false, index - tbl->it_offset); + + return be64_to_cpu(*ptce); } static void pnv_pci_ioda2_table_do_free_pages(__be64 *addr, @@ -144,6 +155,10 @@ void pnv_pci_ioda2_table_free_pages(struct iommu_table *tbl) pnv_pci_ioda2_table_do_free_pages((__be64 *)tbl->it_base, size, tbl->it_indirect_levels); + if (tbl->it_userspace) { + pnv_pci_ioda2_table_do_free_pages(tbl->it_userspace, size, + tbl->it_indirect_levels); + } } static __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned int shift, @@ -191,10 +206,11 @@ static __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned int shift, long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, __u32 page_shift, __u64 window_size, __u32 levels, - struct iommu_table *tbl) + bool alloc_userspace_copy, struct iommu_table *tbl) { - void *addr; + void *addr, *uas = NULL; unsigned long offset = 0, level_shift, total_allocated = 0; + unsigned long total_allocated_uas = 0; const unsigned int window_shift = ilog2(window_size); unsigned int entries_shift = window_shift - page_shift; unsigned int table_shift = max_t(unsigned int, entries_shift + 3, @@ -228,10 +244,20 @@ long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, * we did not allocate as much as we wanted, * release partially allocated table. */ - if (offset < tce_table_size) { - pnv_pci_ioda2_table_do_free_pages(addr, - 1ULL << (level_shift - 3), levels - 1); - return -ENOMEM; + if (offset < tce_table_size) + goto free_tces_exit; + + /* Allocate userspace view of the TCE table */ + if (alloc_userspace_copy) { + offset = 0; + uas = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift, + levels, tce_table_size, &offset, + &total_allocated_uas); + if (!uas) + goto free_tces_exit; + if (offset < tce_table_size || + total_allocated_uas != total_allocated) + goto free_uas_exit; } /* Setup linux iommu table */ @@ -240,11 +266,22 @@ long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, tbl->it_level_size = 1ULL << (level_shift - 3); tbl->it_indirect_levels = levels - 1; tbl->it_allocated_size = total_allocated; + tbl->it_userspace = uas; - pr_devel("Created TCE table: ws=%08llx ts=%lx @%08llx\n", - window_size, tce_table_size, bus_offset); + pr_debug("Created TCE table: ws=%08llx ts=%lx @%08llx base=%lx uas=%p levels=%d\n", + window_size, tce_table_size, bus_offset, tbl->it_base, + tbl->it_userspace, levels); return 0; + +free_uas_exit: + pnv_pci_ioda2_table_do_free_pages(uas, + 1ULL << (level_shift - 3), levels - 1); +free_tces_exit: + pnv_pci_ioda2_table_do_free_pages(addr, + 1ULL << (level_shift - 3), levels - 1); + + return -ENOMEM; } static void pnv_iommu_table_group_link_free(struct rcu_head *head) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 4abf1175626e..fc38f06ee41d 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -2036,6 +2036,7 @@ static struct iommu_table_ops pnv_ioda1_iommu_ops = { #ifdef CONFIG_IOMMU_API .exchange = pnv_ioda1_tce_xchg, .exchange_rm = pnv_ioda1_tce_xchg_rm, + .useraddrptr = pnv_tce_useraddrptr, #endif .clear = pnv_ioda1_tce_free, .get = pnv_tce_get, @@ -2200,6 +2201,7 @@ static struct iommu_table_ops pnv_ioda2_iommu_ops = { #ifdef CONFIG_IOMMU_API .exchange = pnv_ioda2_tce_xchg, .exchange_rm = pnv_ioda2_tce_xchg_rm, + .useraddrptr = pnv_tce_useraddrptr, #endif .clear = pnv_ioda2_tce_free, .get = pnv_tce_get, @@ -2455,7 +2457,7 @@ void pnv_pci_ioda2_set_bypass(struct pnv_ioda_pe *pe, bool enable) static long pnv_pci_ioda2_create_table(struct iommu_table_group *table_group, int num, __u32 page_shift, __u64 window_size, __u32 levels, - struct iommu_table **ptbl) + bool alloc_userspace_copy, struct iommu_table **ptbl) { struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe, table_group); @@ -2472,7 +2474,7 @@ static long pnv_pci_ioda2_create_table(struct iommu_table_group *table_group, ret = pnv_pci_ioda2_table_alloc_pages(nid, bus_offset, page_shift, window_size, - levels, tbl); + levels, alloc_userspace_copy, tbl); if (ret) { iommu_tce_table_put(tbl); return ret; @@ -2505,7 +2507,7 @@ static long pnv_pci_ioda2_setup_default_config(struct pnv_ioda_pe *pe) rc = pnv_pci_ioda2_create_table(&pe->table_group, 0, IOMMU_PAGE_SHIFT_4K, window_size, - POWERNV_IOMMU_DEFAULT_LEVELS, &tbl); + POWERNV_IOMMU_DEFAULT_LEVELS, false, &tbl); if (rc) { pe_err(pe, "Failed to create 32-bit TCE table, err %ld", rc); @@ -2592,7 +2594,16 @@ static unsigned long pnv_pci_ioda2_get_table_size(__u32 page_shift, tce_table_size, direct_table_size); } - return bytes; + return bytes + bytes; /* one for HW table, one for userspace copy */ +} + +static long pnv_pci_ioda2_create_table_userspace( + struct iommu_table_group *table_group, + int num, __u32 page_shift, __u64 window_size, __u32 levels, + struct iommu_table **ptbl) +{ + return pnv_pci_ioda2_create_table(table_group, + num, page_shift, window_size, levels, true, ptbl); } static void pnv_ioda2_take_ownership(struct iommu_table_group *table_group) @@ -2621,7 +2632,7 @@ static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group) static struct iommu_table_group_ops pnv_pci_ioda2_ops = { .get_table_size = pnv_pci_ioda2_get_table_size, - .create_table = pnv_pci_ioda2_create_table, + .create_table = pnv_pci_ioda2_create_table_userspace, .set_window = pnv_pci_ioda2_set_window, .unset_window = pnv_pci_ioda2_unset_window, .take_ownership = pnv_ioda2_take_ownership, @@ -2726,7 +2737,7 @@ static void pnv_ioda2_npu_take_ownership(struct iommu_table_group *table_group) static struct iommu_table_group_ops pnv_pci_ioda2_npu_ops = { .get_table_size = pnv_pci_ioda2_get_table_size, - .create_table = pnv_pci_ioda2_create_table, + .create_table = pnv_pci_ioda2_create_table_userspace, .set_window = pnv_pci_ioda2_npu_set_window, .unset_window = pnv_pci_ioda2_npu_unset_window, .take_ownership = pnv_ioda2_npu_take_ownership, diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index fa90f60e89ce..2962f6ddb2a8 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -267,11 +267,12 @@ extern int pnv_tce_build(struct iommu_table *tbl, long index, long npages, extern void pnv_tce_free(struct iommu_table *tbl, long index, long npages); extern int pnv_tce_xchg(struct iommu_table *tbl, long index, unsigned long *hpa, enum dma_data_direction *direction); +extern __be64 *pnv_tce_useraddrptr(struct iommu_table *tbl, long index); extern unsigned long pnv_tce_get(struct iommu_table *tbl, long index); extern long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, __u32 page_shift, __u64 window_size, __u32 levels, - struct iommu_table *tbl); + bool alloc_userspace_copy, struct iommu_table *tbl); extern void pnv_pci_ioda2_table_free_pages(struct iommu_table *tbl); extern long pnv_pci_link_table_and_group(int node, int num, diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 8ab124a67311..54ae6c2be1b7 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -211,44 +211,6 @@ static long tce_iommu_register_pages(struct tce_container *container, return 0; } -static long tce_iommu_userspace_view_alloc(struct iommu_table *tbl, - struct mm_struct *mm) -{ - unsigned long cb = _ALIGN_UP(sizeof(tbl->it_userspace[0]) * - tbl->it_size, PAGE_SIZE); - unsigned long *uas; - long ret; - - BUG_ON(tbl->it_userspace); - - ret = try_increment_locked_vm(mm, cb >> PAGE_SHIFT); - if (ret) - return ret; - - uas = vzalloc(cb); - if (!uas) { - decrement_locked_vm(mm, cb >> PAGE_SHIFT); - return -ENOMEM; - } - tbl->it_userspace = (__be64 *) uas; - - return 0; -} - -static void tce_iommu_userspace_view_free(struct iommu_table *tbl, - struct mm_struct *mm) -{ - unsigned long cb = _ALIGN_UP(sizeof(tbl->it_userspace[0]) * - tbl->it_size, PAGE_SIZE); - - if (!tbl->it_userspace) - return; - - vfree(tbl->it_userspace); - tbl->it_userspace = NULL; - decrement_locked_vm(mm, cb >> PAGE_SHIFT); -} - static bool tce_page_is_contained(struct page *page, unsigned page_shift) { /* @@ -599,12 +561,6 @@ static long tce_iommu_build_v2(struct tce_container *container, unsigned long hpa; enum dma_data_direction dirtmp; - if (!tbl->it_userspace) { - ret = tce_iommu_userspace_view_alloc(tbl, container->mm); - if (ret) - return ret; - } - for (i = 0; i < pages; ++i) { struct mm_iommu_table_group_mem_t *mem = NULL; __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry + i); @@ -685,7 +641,6 @@ static void tce_iommu_free_table(struct tce_container *container, { unsigned long pages = tbl->it_allocated_size >> PAGE_SHIFT; - tce_iommu_userspace_view_free(tbl, container->mm); iommu_tce_table_put(tbl); decrement_locked_vm(container->mm, pages); } @@ -1200,7 +1155,6 @@ static void tce_iommu_release_ownership(struct tce_container *container, continue; tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size); - tce_iommu_userspace_view_free(tbl, container->mm); if (tbl->it_map) iommu_release_ownership(tbl); -- cgit v1.2.3 From a68bd1267b7286b1687905651b404e765046de25 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 4 Jul 2018 16:13:49 +1000 Subject: powerpc/powernv/ioda: Allocate indirect TCE levels on demand At the moment we allocate the entire TCE table, twice (hardware part and userspace translation cache). This normally works as we normally have contigous memory and the guest will map entire RAM for 64bit DMA. However if we have sparse RAM (one example is a memory device), then we will allocate TCEs which will never be used as the guest only maps actual memory for DMA. If it is a single level TCE table, there is nothing we can really do but if it a multilevel table, we can skip allocating TCEs we know we won't need. This adds ability to allocate only first level, saving memory. This changes iommu_table::free() to avoid allocating of an extra level; iommu_table::set() will do this when needed. This adds @alloc parameter to iommu_table::exchange() to tell the callback if it can allocate an extra level; the flag is set to "false" for the realmode KVM handlers of H_PUT_TCE hcalls and the callback returns H_TOO_HARD. This still requires the entire table to be counted in mm::locked_vm. To be conservative, this only does on-demand allocation when the usespace cache table is requested which is the case of VFIO. The example math for a system replicating a powernv setup with NVLink2 in a guest: 16GB RAM mapped at 0x0 128GB GPU RAM window (16GB of actual RAM) mapped at 0x244000000000 the table to cover that all with 64K pages takes: (((0x244000000000 + 0x2000000000) >> 16)*8)>>20 = 4556MB If we allocate only necessary TCE levels, we will only need: (((0x400000000 + 0x400000000) >> 16)*8)>>20 = 4MB (plus some for indirect levels). Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/iommu.h | 7 ++- arch/powerpc/kvm/book3s_64_vio_hv.c | 4 +- arch/powerpc/platforms/powernv/pci-ioda-tce.c | 73 +++++++++++++++++++++------ arch/powerpc/platforms/powernv/pci-ioda.c | 8 +-- arch/powerpc/platforms/powernv/pci.h | 6 ++- drivers/vfio/vfio_iommu_spapr_tce.c | 2 +- 6 files changed, 73 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h index 4bdcf22509e6..daa3ee5d7ad2 100644 --- a/arch/powerpc/include/asm/iommu.h +++ b/arch/powerpc/include/asm/iommu.h @@ -70,7 +70,7 @@ struct iommu_table_ops { unsigned long *hpa, enum dma_data_direction *direction); - __be64 *(*useraddrptr)(struct iommu_table *tbl, long index); + __be64 *(*useraddrptr)(struct iommu_table *tbl, long index, bool alloc); #endif void (*clear)(struct iommu_table *tbl, long index, long npages); @@ -122,10 +122,13 @@ struct iommu_table { __be64 *it_userspace; /* userspace view of the table */ struct iommu_table_ops *it_ops; struct kref it_kref; + int it_nid; }; +#define IOMMU_TABLE_USERSPACE_ENTRY_RM(tbl, entry) \ + ((tbl)->it_ops->useraddrptr((tbl), (entry), false)) #define IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry) \ - ((tbl)->it_ops->useraddrptr((tbl), (entry))) + ((tbl)->it_ops->useraddrptr((tbl), (entry), true)) /* Pure 2^n version of get_order */ static inline __attribute_const__ diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c index ee98cf6180d7..d4bcd1b17b09 100644 --- a/arch/powerpc/kvm/book3s_64_vio_hv.c +++ b/arch/powerpc/kvm/book3s_64_vio_hv.c @@ -200,7 +200,7 @@ static long kvmppc_rm_tce_iommu_mapped_dec(struct kvm *kvm, { struct mm_iommu_table_group_mem_t *mem = NULL; const unsigned long pgsize = 1ULL << tbl->it_page_shift; - __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); + __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY_RM(tbl, entry); if (!pua) /* it_userspace allocation might be delayed */ @@ -264,7 +264,7 @@ static long kvmppc_rm_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl, { long ret; unsigned long hpa = 0; - __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); + __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY_RM(tbl, entry); struct mm_iommu_table_group_mem_t *mem; if (!pua) diff --git a/arch/powerpc/platforms/powernv/pci-ioda-tce.c b/arch/powerpc/platforms/powernv/pci-ioda-tce.c index 123c49925b46..6c5db1acbe8d 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda-tce.c +++ b/arch/powerpc/platforms/powernv/pci-ioda-tce.c @@ -48,7 +48,7 @@ static __be64 *pnv_alloc_tce_level(int nid, unsigned int shift) return addr; } -static __be64 *pnv_tce(struct iommu_table *tbl, bool user, long idx) +static __be64 *pnv_tce(struct iommu_table *tbl, bool user, long idx, bool alloc) { __be64 *tmp = user ? tbl->it_userspace : (__be64 *) tbl->it_base; int level = tbl->it_indirect_levels; @@ -57,7 +57,23 @@ static __be64 *pnv_tce(struct iommu_table *tbl, bool user, long idx) while (level) { int n = (idx & mask) >> (level * shift); - unsigned long tce = be64_to_cpu(tmp[n]); + unsigned long tce; + + if (tmp[n] == 0) { + __be64 *tmp2; + + if (!alloc) + return NULL; + + tmp2 = pnv_alloc_tce_level(tbl->it_nid, + ilog2(tbl->it_level_size) + 3); + if (!tmp2) + return NULL; + + tmp[n] = cpu_to_be64(__pa(tmp2) | + TCE_PCI_READ | TCE_PCI_WRITE); + } + tce = be64_to_cpu(tmp[n]); tmp = __va(tce & ~(TCE_PCI_READ | TCE_PCI_WRITE)); idx &= ~mask; @@ -84,7 +100,7 @@ int pnv_tce_build(struct iommu_table *tbl, long index, long npages, ((rpn + i) << tbl->it_page_shift); unsigned long idx = index - tbl->it_offset + i; - *(pnv_tce(tbl, false, idx)) = cpu_to_be64(newtce); + *(pnv_tce(tbl, false, idx, true)) = cpu_to_be64(newtce); } return 0; @@ -92,31 +108,46 @@ int pnv_tce_build(struct iommu_table *tbl, long index, long npages, #ifdef CONFIG_IOMMU_API int pnv_tce_xchg(struct iommu_table *tbl, long index, - unsigned long *hpa, enum dma_data_direction *direction) + unsigned long *hpa, enum dma_data_direction *direction, + bool alloc) { u64 proto_tce = iommu_direction_to_tce_perm(*direction); unsigned long newtce = *hpa | proto_tce, oldtce; unsigned long idx = index - tbl->it_offset; + __be64 *ptce = NULL; BUG_ON(*hpa & ~IOMMU_PAGE_MASK(tbl)); + if (*direction == DMA_NONE) { + ptce = pnv_tce(tbl, false, idx, false); + if (!ptce) { + *hpa = 0; + return 0; + } + } + + if (!ptce) { + ptce = pnv_tce(tbl, false, idx, alloc); + if (!ptce) + return alloc ? H_HARDWARE : H_TOO_HARD; + } + if (newtce & TCE_PCI_WRITE) newtce |= TCE_PCI_READ; - oldtce = be64_to_cpu(xchg(pnv_tce(tbl, false, idx), - cpu_to_be64(newtce))); + oldtce = be64_to_cpu(xchg(ptce, cpu_to_be64(newtce))); *hpa = oldtce & ~(TCE_PCI_READ | TCE_PCI_WRITE); *direction = iommu_tce_direction(oldtce); return 0; } -__be64 *pnv_tce_useraddrptr(struct iommu_table *tbl, long index) +__be64 *pnv_tce_useraddrptr(struct iommu_table *tbl, long index, bool alloc) { if (WARN_ON_ONCE(!tbl->it_userspace)) return NULL; - return pnv_tce(tbl, true, index - tbl->it_offset); + return pnv_tce(tbl, true, index - tbl->it_offset, alloc); } #endif @@ -126,14 +157,19 @@ void pnv_tce_free(struct iommu_table *tbl, long index, long npages) for (i = 0; i < npages; i++) { unsigned long idx = index - tbl->it_offset + i; + __be64 *ptce = pnv_tce(tbl, false, idx, false); - *(pnv_tce(tbl, false, idx)) = cpu_to_be64(0); + if (ptce) + *ptce = cpu_to_be64(0); } } unsigned long pnv_tce_get(struct iommu_table *tbl, long index) { - __be64 *ptce = pnv_tce(tbl, false, index - tbl->it_offset); + __be64 *ptce = pnv_tce(tbl, false, index - tbl->it_offset, false); + + if (!ptce) + return 0; return be64_to_cpu(*ptce); } @@ -224,6 +260,7 @@ long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, unsigned int table_shift = max_t(unsigned int, entries_shift + 3, PAGE_SHIFT); const unsigned long tce_table_size = 1UL << table_shift; + unsigned int tmplevels = levels; if (!levels || (levels > POWERNV_IOMMU_MAX_LEVELS)) return -EINVAL; @@ -231,6 +268,9 @@ long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, if (!is_power_of_2(window_size)) return -EINVAL; + if (alloc_userspace_copy && (window_size > (1ULL << 32))) + tmplevels = 1; + /* Adjust direct table size from window_size and levels */ entries_shift = (entries_shift + levels - 1) / levels; level_shift = entries_shift + 3; @@ -241,7 +281,7 @@ long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, /* Allocate TCE table */ addr = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift, - levels, tce_table_size, &offset, &total_allocated); + tmplevels, tce_table_size, &offset, &total_allocated); /* addr==NULL means that the first level allocation failed */ if (!addr) @@ -252,7 +292,7 @@ long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, * we did not allocate as much as we wanted, * release partially allocated table. */ - if (offset < tce_table_size) + if (tmplevels == levels && offset < tce_table_size) goto free_tces_exit; /* Allocate userspace view of the TCE table */ @@ -263,8 +303,8 @@ long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, &total_allocated_uas); if (!uas) goto free_tces_exit; - if (offset < tce_table_size || - total_allocated_uas != total_allocated) + if (tmplevels == levels && (offset < tce_table_size || + total_allocated_uas != total_allocated)) goto free_uas_exit; } @@ -275,10 +315,11 @@ long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, tbl->it_indirect_levels = levels - 1; tbl->it_allocated_size = total_allocated; tbl->it_userspace = uas; + tbl->it_nid = nid; - pr_debug("Created TCE table: ws=%08llx ts=%lx @%08llx base=%lx uas=%p levels=%d\n", + pr_debug("Created TCE table: ws=%08llx ts=%lx @%08llx base=%lx uas=%p levels=%d/%d\n", window_size, tce_table_size, bus_offset, tbl->it_base, - tbl->it_userspace, levels); + tbl->it_userspace, tmplevels, levels); return 0; diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index fc38f06ee41d..b4475f71a0b4 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -2003,7 +2003,7 @@ static int pnv_ioda1_tce_build(struct iommu_table *tbl, long index, static int pnv_ioda1_tce_xchg(struct iommu_table *tbl, long index, unsigned long *hpa, enum dma_data_direction *direction) { - long ret = pnv_tce_xchg(tbl, index, hpa, direction); + long ret = pnv_tce_xchg(tbl, index, hpa, direction, true); if (!ret) pnv_pci_p7ioc_tce_invalidate(tbl, index, 1, false); @@ -2014,7 +2014,7 @@ static int pnv_ioda1_tce_xchg(struct iommu_table *tbl, long index, static int pnv_ioda1_tce_xchg_rm(struct iommu_table *tbl, long index, unsigned long *hpa, enum dma_data_direction *direction) { - long ret = pnv_tce_xchg(tbl, index, hpa, direction); + long ret = pnv_tce_xchg(tbl, index, hpa, direction, false); if (!ret) pnv_pci_p7ioc_tce_invalidate(tbl, index, 1, true); @@ -2168,7 +2168,7 @@ static int pnv_ioda2_tce_build(struct iommu_table *tbl, long index, static int pnv_ioda2_tce_xchg(struct iommu_table *tbl, long index, unsigned long *hpa, enum dma_data_direction *direction) { - long ret = pnv_tce_xchg(tbl, index, hpa, direction); + long ret = pnv_tce_xchg(tbl, index, hpa, direction, true); if (!ret) pnv_pci_ioda2_tce_invalidate(tbl, index, 1, false); @@ -2179,7 +2179,7 @@ static int pnv_ioda2_tce_xchg(struct iommu_table *tbl, long index, static int pnv_ioda2_tce_xchg_rm(struct iommu_table *tbl, long index, unsigned long *hpa, enum dma_data_direction *direction) { - long ret = pnv_tce_xchg(tbl, index, hpa, direction); + long ret = pnv_tce_xchg(tbl, index, hpa, direction, false); if (!ret) pnv_pci_ioda2_tce_invalidate(tbl, index, 1, true); diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 2962f6ddb2a8..0020937fc694 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -266,8 +266,10 @@ extern int pnv_tce_build(struct iommu_table *tbl, long index, long npages, unsigned long attrs); extern void pnv_tce_free(struct iommu_table *tbl, long index, long npages); extern int pnv_tce_xchg(struct iommu_table *tbl, long index, - unsigned long *hpa, enum dma_data_direction *direction); -extern __be64 *pnv_tce_useraddrptr(struct iommu_table *tbl, long index); + unsigned long *hpa, enum dma_data_direction *direction, + bool alloc); +extern __be64 *pnv_tce_useraddrptr(struct iommu_table *tbl, long index, + bool alloc); extern unsigned long pnv_tce_get(struct iommu_table *tbl, long index); extern long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 54ae6c2be1b7..11a4c194d6e3 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -631,7 +631,7 @@ static long tce_iommu_create_table(struct tce_container *container, page_shift, window_size, levels, ptbl); WARN_ON(!ret && !(*ptbl)->it_ops->free); - WARN_ON(!ret && ((*ptbl)->it_allocated_size != table_size)); + WARN_ON(!ret && ((*ptbl)->it_allocated_size > table_size)); return ret; } -- cgit v1.2.3 From ef6cb5f1a048fdf91ccee6d63d2bfa293338502d Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Wed, 4 Jul 2018 20:58:33 +0530 Subject: cxl: Fix wrong comparison in cxl_adapter_context_get() Function atomic_inc_unless_negative() returns a bool to indicate success/failure. However cxl_adapter_context_get() wrongly compares the return value against '>=0' which will always be true. The patch fixes this comparison to '==0' there by also fixing this compile time warning: drivers/misc/cxl/main.c:290 cxl_adapter_context_get() warn: 'atomic_inc_unless_negative(&adapter->contexts_num)' is unsigned Fixes: 70b565bbdb91 ("cxl: Prevent adapter reset if an active context exists") Cc: stable@vger.kernel.org # v4.9+ Reported-by: Dan Carpenter Signed-off-by: Vaibhav Jain Acked-by: Andrew Donnellan Acked-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/cxl/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c index 334223b802ee..f35406be465a 100644 --- a/drivers/misc/cxl/main.c +++ b/drivers/misc/cxl/main.c @@ -282,7 +282,7 @@ int cxl_adapter_context_get(struct cxl *adapter) int rc; rc = atomic_inc_unless_negative(&adapter->contexts_num); - return rc >= 0 ? 0 : -EBUSY; + return rc ? 0 : -EBUSY; } void cxl_adapter_context_put(struct cxl *adapter) -- cgit v1.2.3 From 48e91846865cd61bfdb701eb737de222d7f08c74 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Wed, 18 Jul 2018 15:08:33 -0700 Subject: powerpc/ps3: Set driver coherent_dma_mask Set the coherent_dma_mask for the PS3 ehci, ohci, and snd devices. Silences WARN_ON_ONCE messages emitted by the dma_alloc_attrs() routine. Reported-by: Fredrik Noring Signed-off-by: Geoff Levand Acked-by: Greg Kroah-Hartman Acked-by: Alan Stern Signed-off-by: Michael Ellerman --- drivers/usb/host/ehci-ps3.c | 6 ++++-- drivers/usb/host/ohci-ps3.c | 6 ++++-- sound/ppc/snd_ps3.c | 5 +++++ 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 8c733492d8fe..454d8c624a3f 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -86,7 +86,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev) int result; struct usb_hcd *hcd; unsigned int virq; - static u64 dummy_mask = DMA_BIT_MASK(32); + static u64 dummy_mask; if (usb_disabled()) { result = -ENODEV; @@ -131,7 +131,9 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev) goto fail_irq; } - dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ + dummy_mask = DMA_BIT_MASK(32); + dev->core.dma_mask = &dummy_mask; + dma_set_coherent_mask(&dev->core, dummy_mask); hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev_name(&dev->core)); diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c index 20a23d795adf..395f9d3bc849 100644 --- a/drivers/usb/host/ohci-ps3.c +++ b/drivers/usb/host/ohci-ps3.c @@ -69,7 +69,7 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev) int result; struct usb_hcd *hcd; unsigned int virq; - static u64 dummy_mask = DMA_BIT_MASK(32); + static u64 dummy_mask; if (usb_disabled()) { result = -ENODEV; @@ -115,7 +115,9 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev) goto fail_irq; } - dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ + dummy_mask = DMA_BIT_MASK(32); + dev->core.dma_mask = &dummy_mask; + dma_set_coherent_mask(&dev->core, dummy_mask); hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev_name(&dev->core)); diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 36f34f434ecb..abe031c9d592 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -930,6 +930,7 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev) { int i, ret; u64 lpar_addr, lpar_size; + static u64 dummy_mask; if (WARN_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1))) return -ENODEV; @@ -970,6 +971,10 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev) goto clean_mmio; } + dummy_mask = DMA_BIT_MASK(32); + dev->core.dma_mask = &dummy_mask; + dma_set_coherent_mask(&dev->core, dummy_mask); + snd_ps3_audio_set_base_addr(dev->d_region->bus_addr); /* CONFIG_SND_PS3_DEFAULT_START_DELAY */ -- cgit v1.2.3 From a9bf5c8a271b9a954709b7ada1bd258f5cadf7ff Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 1 May 2018 00:55:53 +1000 Subject: tty: hvc: use mutex instead of spinlock for hvc_structs lock This allows hvc operations to sleep under the lock. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- drivers/tty/hvc/hvc_console.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 7709fcc707f4..fddb63322c67 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -73,7 +73,7 @@ static LIST_HEAD(hvc_structs); * Protect the list of hvc_struct instances from inserts and removals during * list traversal. */ -static DEFINE_SPINLOCK(hvc_structs_lock); +static DEFINE_MUTEX(hvc_structs_mutex); /* * This value is used to assign a tty->index value to a hvc_struct based @@ -83,7 +83,7 @@ static DEFINE_SPINLOCK(hvc_structs_lock); static int last_hvc = -1; /* - * Do not call this function with either the hvc_structs_lock or the hvc_struct + * Do not call this function with either the hvc_structs_mutex or the hvc_struct * lock held. If successful, this function increments the kref reference * count against the target hvc_struct so it should be released when finished. */ @@ -92,25 +92,24 @@ static struct hvc_struct *hvc_get_by_index(int index) struct hvc_struct *hp; unsigned long flags; - spin_lock(&hvc_structs_lock); + mutex_lock(&hvc_structs_mutex); list_for_each_entry(hp, &hvc_structs, next) { spin_lock_irqsave(&hp->lock, flags); if (hp->index == index) { tty_port_get(&hp->port); spin_unlock_irqrestore(&hp->lock, flags); - spin_unlock(&hvc_structs_lock); + mutex_unlock(&hvc_structs_mutex); return hp; } spin_unlock_irqrestore(&hp->lock, flags); } hp = NULL; + mutex_unlock(&hvc_structs_mutex); - spin_unlock(&hvc_structs_lock); return hp; } - /* * Initial console vtermnos for console API usage prior to full console * initialization. Any vty adapter outside this range will not have usable @@ -224,13 +223,13 @@ static void hvc_port_destruct(struct tty_port *port) struct hvc_struct *hp = container_of(port, struct hvc_struct, port); unsigned long flags; - spin_lock(&hvc_structs_lock); + mutex_lock(&hvc_structs_mutex); spin_lock_irqsave(&hp->lock, flags); list_del(&(hp->next)); spin_unlock_irqrestore(&hp->lock, flags); - spin_unlock(&hvc_structs_lock); + mutex_unlock(&hvc_structs_mutex); kfree(hp); } @@ -733,11 +732,11 @@ static int khvcd(void *unused) try_to_freeze(); wmb(); if (!cpus_are_in_xmon()) { - spin_lock(&hvc_structs_lock); + mutex_lock(&hvc_structs_mutex); list_for_each_entry(hp, &hvc_structs, next) { poll_mask |= hvc_poll(hp); } - spin_unlock(&hvc_structs_lock); + mutex_unlock(&hvc_structs_mutex); } else poll_mask |= HVC_POLL_READ; if (hvc_kicked) @@ -871,7 +870,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, INIT_WORK(&hp->tty_resize, hvc_set_winsz); spin_lock_init(&hp->lock); - spin_lock(&hvc_structs_lock); + mutex_lock(&hvc_structs_mutex); /* * find index to use: @@ -891,7 +890,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, vtermnos[i] = vtermno; list_add_tail(&(hp->next), &hvc_structs); - spin_unlock(&hvc_structs_lock); + mutex_unlock(&hvc_structs_mutex); /* check if we need to re-register the kernel console */ hvc_check_console(i); -- cgit v1.2.3 From ec97eaad1383ab2500fcf9a07ade6044fbcc67f5 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 1 May 2018 00:55:54 +1000 Subject: tty: hvc: hvc_poll() break hv read loop Avoid looping with the spinlock held while there is read data being returned from the hv driver. Instead note if the entire size returned by tty_buffer_request_room was read, and request another read poll. This limits the critical section lengths, and provides more even service to other consoles in case there is a pathological condition. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- drivers/tty/hvc/hvc_console.c | 88 ++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index fddb63322c67..745ac220fce8 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -592,7 +592,7 @@ static u32 timeout = MIN_TIMEOUT; int hvc_poll(struct hvc_struct *hp) { struct tty_struct *tty; - int i, n, poll_mask = 0; + int i, n, count, poll_mask = 0; char buf[N_INBUF] __ALIGNED__; unsigned long flags; int read_total = 0; @@ -618,7 +618,7 @@ int hvc_poll(struct hvc_struct *hp) /* Now check if we can get data (are we throttled ?) */ if (tty_throttled(tty)) - goto throttled; + goto out; /* If we aren't notifier driven and aren't throttled, we always * request a reschedule @@ -627,56 +627,58 @@ int hvc_poll(struct hvc_struct *hp) poll_mask |= HVC_POLL_READ; /* Read data if any */ - for (;;) { - int count = tty_buffer_request_room(&hp->port, N_INBUF); - /* If flip is full, just reschedule a later read */ - if (count == 0) { + count = tty_buffer_request_room(&hp->port, N_INBUF); + + /* If flip is full, just reschedule a later read */ + if (count == 0) { + poll_mask |= HVC_POLL_READ; + goto out; + } + + n = hp->ops->get_chars(hp->vtermno, buf, count); + if (n <= 0) { + /* Hangup the tty when disconnected from host */ + if (n == -EPIPE) { + spin_unlock_irqrestore(&hp->lock, flags); + tty_hangup(tty); + spin_lock_irqsave(&hp->lock, flags); + } else if ( n == -EAGAIN ) { + /* + * Some back-ends can only ensure a certain min + * num of bytes read, which may be > 'count'. + * Let the tty clear the flip buff to make room. + */ poll_mask |= HVC_POLL_READ; - break; } + goto out; + } - n = hp->ops->get_chars(hp->vtermno, buf, count); - if (n <= 0) { - /* Hangup the tty when disconnected from host */ - if (n == -EPIPE) { - spin_unlock_irqrestore(&hp->lock, flags); - tty_hangup(tty); - spin_lock_irqsave(&hp->lock, flags); - } else if ( n == -EAGAIN ) { - /* - * Some back-ends can only ensure a certain min - * num of bytes read, which may be > 'count'. - * Let the tty clear the flip buff to make room. - */ - poll_mask |= HVC_POLL_READ; - } - break; - } - for (i = 0; i < n; ++i) { + for (i = 0; i < n; ++i) { #ifdef CONFIG_MAGIC_SYSRQ - if (hp->index == hvc_console.index) { - /* Handle the SysRq Hack */ - /* XXX should support a sequence */ - if (buf[i] == '\x0f') { /* ^O */ - /* if ^O is pressed again, reset - * sysrq_pressed and flip ^O char */ - sysrq_pressed = !sysrq_pressed; - if (sysrq_pressed) - continue; - } else if (sysrq_pressed) { - handle_sysrq(buf[i]); - sysrq_pressed = 0; + if (hp->index == hvc_console.index) { + /* Handle the SysRq Hack */ + /* XXX should support a sequence */ + if (buf[i] == '\x0f') { /* ^O */ + /* if ^O is pressed again, reset + * sysrq_pressed and flip ^O char */ + sysrq_pressed = !sysrq_pressed; + if (sysrq_pressed) continue; - } + } else if (sysrq_pressed) { + handle_sysrq(buf[i]); + sysrq_pressed = 0; + continue; } -#endif /* CONFIG_MAGIC_SYSRQ */ - tty_insert_flip_char(&hp->port, buf[i], 0); } - - read_total += n; +#endif /* CONFIG_MAGIC_SYSRQ */ + tty_insert_flip_char(&hp->port, buf[i], 0); } - throttled: + if (n == count) + poll_mask |= HVC_POLL_READ; + read_total = n; + + out: /* Wakeup write queue if necessary */ if (hp->do_wakeup) { hp->do_wakeup = 0; -- cgit v1.2.3 From cfb5946b55f1dfd19e042feae1fbff6041e25a98 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 1 May 2018 00:55:55 +1000 Subject: tty: hvc: hvc_poll() may sleep Introduce points where hvc_poll drops the lock, enables interrupts, and reschedules. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- drivers/tty/hvc/hvc_console.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 745ac220fce8..2abfc0b15fbb 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -589,7 +589,7 @@ static u32 timeout = MIN_TIMEOUT; #define HVC_POLL_READ 0x00000001 #define HVC_POLL_WRITE 0x00000002 -int hvc_poll(struct hvc_struct *hp) +static int __hvc_poll(struct hvc_struct *hp, bool may_sleep) { struct tty_struct *tty; int i, n, count, poll_mask = 0; @@ -611,6 +611,12 @@ int hvc_poll(struct hvc_struct *hp) timeout = (written_total) ? 0 : MIN_TIMEOUT; } + if (may_sleep) { + spin_unlock_irqrestore(&hp->lock, flags); + cond_resched(); + spin_lock_irqsave(&hp->lock, flags); + } + /* No tty attached, just skip */ tty = tty_port_tty_get(&hp->port); if (tty == NULL) @@ -698,6 +704,11 @@ int hvc_poll(struct hvc_struct *hp) return poll_mask; } + +int hvc_poll(struct hvc_struct *hp) +{ + return __hvc_poll(hp, false); +} EXPORT_SYMBOL_GPL(hvc_poll); /** @@ -736,7 +747,8 @@ static int khvcd(void *unused) if (!cpus_are_in_xmon()) { mutex_lock(&hvc_structs_mutex); list_for_each_entry(hp, &hvc_structs, next) { - poll_mask |= hvc_poll(hp); + poll_mask |= __hvc_poll(hp, true); + cond_resched(); } mutex_unlock(&hvc_structs_mutex); } else -- cgit v1.2.3 From 550ddadcc7580ec2a6c22d4ed04291bc6e2428fb Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 1 May 2018 00:55:56 +1000 Subject: tty: hvc: hvc_write() may sleep Rework the hvc_write loop to drop and re-take the spinlock on each iteration, add a cond_resched. Don't bother with an initial hvc_push initially, which makes the logic simpler -- just do a hvc_push on each time around the loop. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- drivers/tty/hvc/hvc_console.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 2abfc0b15fbb..6131d5084c42 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -493,23 +493,29 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count if (hp->port.count <= 0) return -EIO; - spin_lock_irqsave(&hp->lock, flags); + while (count > 0) { + spin_lock_irqsave(&hp->lock, flags); - /* Push pending writes */ - if (hp->n_outbuf > 0) - hvc_push(hp); - - while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) { - if (rsize > count) - rsize = count; - memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); - count -= rsize; - buf += rsize; - hp->n_outbuf += rsize; - written += rsize; - hvc_push(hp); + rsize = hp->outbuf_size - hp->n_outbuf; + + if (rsize) { + if (rsize > count) + rsize = count; + memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); + count -= rsize; + buf += rsize; + hp->n_outbuf += rsize; + written += rsize; + } + + if (hp->n_outbuf > 0) + hvc_push(hp); + + spin_unlock_irqrestore(&hp->lock, flags); + + if (count) + cond_resched(); } - spin_unlock_irqrestore(&hp->lock, flags); /* * Racy, but harmless, kick thread if there is still pending data. -- cgit v1.2.3 From 9f65b81f36e31563c5a5e4df3b3b8bc7550b6030 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 1 May 2018 00:55:57 +1000 Subject: tty: hvc: introduce the hv_ops.flush operation for hvc drivers Use .flush to wait for drivers to flush their console outside of the spinlock, to reduce lock/irq latencies. Flush the hvc console driver after each write, which can help messages make it out to the console after a crash. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- drivers/tty/hvc/hvc_console.c | 35 +++++++++++++++++++++++++++++++++-- drivers/tty/hvc/hvc_console.h | 1 + 2 files changed, 34 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 6131d5084c42..5414c4a87bea 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -110,6 +110,29 @@ static struct hvc_struct *hvc_get_by_index(int index) return hp; } +static int __hvc_flush(const struct hv_ops *ops, uint32_t vtermno, bool wait) +{ + if (wait) + might_sleep(); + + if (ops->flush) + return ops->flush(vtermno, wait); + return 0; +} + +static int hvc_console_flush(const struct hv_ops *ops, uint32_t vtermno) +{ + return __hvc_flush(ops, vtermno, false); +} + +/* + * Wait for the console to flush before writing more to it. This sleeps. + */ +static int hvc_flush(struct hvc_struct *hp) +{ + return __hvc_flush(hp->ops, hp->vtermno, true); +} + /* * Initial console vtermnos for console API usage prior to full console * initialization. Any vty adapter outside this range will not have usable @@ -155,8 +178,12 @@ static void hvc_console_print(struct console *co, const char *b, if (r <= 0) { /* throw away characters on error * but spin in case of -EAGAIN */ - if (r != -EAGAIN) + if (r != -EAGAIN) { i = 0; + } else { + hvc_console_flush(cons_ops[index], + vtermnos[index]); + } } else if (r > 0) { i -= r; if (i > 0) @@ -164,6 +191,7 @@ static void hvc_console_print(struct console *co, const char *b, } } } + hvc_console_flush(cons_ops[index], vtermnos[index]); } static struct tty_driver *hvc_console_device(struct console *c, int *index) @@ -513,8 +541,11 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count spin_unlock_irqrestore(&hp->lock, flags); - if (count) + if (count) { + if (hp->n_outbuf > 0) + hvc_flush(hp); cond_resched(); + } } /* diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index ea63090e013f..e9319954c832 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -54,6 +54,7 @@ struct hvc_struct { struct hv_ops { int (*get_chars)(uint32_t vtermno, char *buf, int count); int (*put_chars)(uint32_t vtermno, const char *buf, int count); + int (*flush)(uint32_t vtermno, bool wait); /* Callbacks for notification. Called in open, close and hangup */ int (*notifier_add)(struct hvc_struct *hp, int irq); -- cgit v1.2.3 From ac4ac788fdadc6b703ff3322de07dee442e08e1c Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 1 May 2018 00:55:50 +1000 Subject: powerpc/powernv: move opal console flushing to udbg OPAL console writes do not have to synchronously flush firmware / hardware buffers unless they are going through the udbg path. Remove the unconditional flushing from opal_put_chars. Flush if there was no space in the buffer as an optimisation (callers loop waiting for success in that case). udbg flushing is moved to udbg_opal_putc. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/opal.c | 12 +++++++----- drivers/tty/hvc/hvc_opal.c | 5 +++++ 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index e18472757617..cf02e602237a 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -400,12 +400,14 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) out: spin_unlock_irqrestore(&opal_write_lock, flags); - /* This is a bit nasty but we need that for the console to - * flush when there aren't any interrupts. We will clean - * things a bit later to limit that to synchronous path - * such as the kernel console and xmon/udbg + /* In the -EAGAIN case, callers loop, so we have to flush the console + * here in case they have interrupts off (and we don't want to wait + * for async flushing if we can make immediate progress here). If + * necessary the API could be made entirely non-flushing if the + * callers had a ->flush API to use. */ - opal_flush_console(vtermno); + if (written == -EAGAIN) + opal_flush_console(vtermno); return written; } diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 9645c0062a90..958c61c8f35a 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -275,6 +275,11 @@ static void udbg_opal_putc(char c) count = hvc_opal_hvsi_put_chars(termno, &c, 1); break; } + + /* This is needed for the cosole to flush + * when there aren't any interrupts. + */ + opal_flush_console(termno); } while(count == 0 || count == -EAGAIN); } -- cgit v1.2.3 From 17cc1dd4924391b54fb179d0868b89dc96f2ee80 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 1 May 2018 00:55:51 +1000 Subject: powerpc/powernv: implement opal_put_chars_atomic The RAW console does not need writes to be atomic, so relax opal_put_chars to be able to do partial writes, and implement an _atomic variant which does not take a spinlock. This API is used in xmon, so the less locking that is used, the better chance there is that a crash can be debugged. Cc: Benjamin Herrenschmidt Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/opal.h | 1 + arch/powerpc/platforms/powernv/opal.c | 37 +++++++++++++++++++++++++---------- drivers/tty/hvc/hvc_opal.c | 18 ++++++++++++----- 3 files changed, 41 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 33ab95a4ac0f..cd1acc8be8ee 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -305,6 +305,7 @@ extern void opal_configure_cores(void); extern int opal_get_chars(uint32_t vtermno, char *buf, int count); extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len); +extern int opal_put_chars_atomic(uint32_t vtermno, const char *buf, int total_len); extern int opal_flush_console(uint32_t vtermno); extern void hvc_opal_init_early(void); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index cf02e602237a..6405b6f20193 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -344,9 +344,9 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count) return 0; } -int opal_put_chars(uint32_t vtermno, const char *data, int total_len) +static int __opal_put_chars(uint32_t vtermno, const char *data, int total_len, bool atomic) { - unsigned long flags; + unsigned long flags = 0 /* shut up gcc */; int written; __be64 olen; s64 rc; @@ -354,11 +354,8 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) if (!opal.entry) return -ENODEV; - /* We want put_chars to be atomic to avoid mangling of hvsi - * packets. To do that, we first test for room and return - * -EAGAIN if there isn't enough. - */ - spin_lock_irqsave(&opal_write_lock, flags); + if (atomic) + spin_lock_irqsave(&opal_write_lock, flags); rc = opal_console_write_buffer_space(vtermno, &olen); if (rc || be64_to_cpu(olen) < total_len) { /* Closed -> drop characters */ @@ -391,14 +388,18 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) written = be64_to_cpu(olen); if (written < total_len) { - /* Should not happen */ - pr_warn("atomic console write returned partial len=%d written=%d\n", total_len, written); + if (atomic) { + /* Should not happen */ + pr_warn("atomic console write returned partial " + "len=%d written=%d\n", total_len, written); + } if (!written) written = -EAGAIN; } out: - spin_unlock_irqrestore(&opal_write_lock, flags); + if (atomic) + spin_unlock_irqrestore(&opal_write_lock, flags); /* In the -EAGAIN case, callers loop, so we have to flush the console * here in case they have interrupts off (and we don't want to wait @@ -412,6 +413,22 @@ out: return written; } +int opal_put_chars(uint32_t vtermno, const char *data, int total_len) +{ + return __opal_put_chars(vtermno, data, total_len, false); +} + +/* + * opal_put_chars_atomic will not perform partial-writes. Data will be + * atomically written to the terminal or not at all. This is not strictly + * true at the moment because console space can race with OPAL's console + * writes. + */ +int opal_put_chars_atomic(uint32_t vtermno, const char *data, int total_len) +{ + return __opal_put_chars(vtermno, data, total_len, true); +} + int opal_flush_console(uint32_t vtermno) { s64 rc; diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 958c61c8f35a..810fd42904c3 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -183,9 +183,15 @@ static int hvc_opal_probe(struct platform_device *dev) return -ENOMEM; pv->proto = proto; hvc_opal_privs[termno] = pv; - if (proto == HV_PROTOCOL_HVSI) - hvsilib_init(&pv->hvsi, opal_get_chars, opal_put_chars, + if (proto == HV_PROTOCOL_HVSI) { + /* + * We want put_chars to be atomic to avoid mangling of + * hvsi packets. + */ + hvsilib_init(&pv->hvsi, + opal_get_chars, opal_put_chars_atomic, termno, 0); + } /* Instanciate now to establish a mapping index==vtermno */ hvc_instantiate(termno, termno, ops); @@ -375,8 +381,9 @@ void __init hvc_opal_init_early(void) else if (of_device_is_compatible(stdout_node,"ibm,opal-console-hvsi")) { hvc_opal_boot_priv.proto = HV_PROTOCOL_HVSI; ops = &hvc_opal_hvsi_ops; - hvsilib_init(&hvc_opal_boot_priv.hvsi, opal_get_chars, - opal_put_chars, index, 1); + hvsilib_init(&hvc_opal_boot_priv.hvsi, + opal_get_chars, opal_put_chars_atomic, + index, 1); /* HVSI, perform the handshake now */ hvsilib_establish(&hvc_opal_boot_priv.hvsi); pr_devel("hvc_opal: Found HVSI console\n"); @@ -408,7 +415,8 @@ void __init udbg_init_debug_opal_hvsi(void) hvc_opal_privs[index] = &hvc_opal_boot_priv; hvc_opal_boot_termno = index; udbg_init_opal_common(); - hvsilib_init(&hvc_opal_boot_priv.hvsi, opal_get_chars, opal_put_chars, + hvsilib_init(&hvc_opal_boot_priv.hvsi, + opal_get_chars, opal_put_chars_atomic, index, 1); hvsilib_establish(&hvc_opal_boot_priv.hvsi); } -- cgit v1.2.3 From cca3d5290ede73b01144aa522910c88b1e02fcef Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 1 May 2018 00:55:52 +1000 Subject: tty: hvc: remove unexplained "just in case" spin delay This delay was in the very first OPAL console commit 6.5 years ago, and came from the vio hvc driver. The firmware console has hardened sufficiently to remove it. Reviewed-by: Benjamin Herrenschmidt Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- drivers/tty/hvc/hvc_opal.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 810fd42904c3..f631f8bee308 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -313,14 +313,8 @@ static int udbg_opal_getc(void) int ch; for (;;) { ch = udbg_opal_getc_poll(); - if (ch == -1) { - /* This shouldn't be needed...but... */ - volatile unsigned long delay; - for (delay=0; delay < 2000000; delay++) - ; - } else { + if (ch != -1) return ch; - } } } -- cgit v1.2.3 From 73f4447d43484224d7abfba0d9468de4982ef889 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 2 Jul 2018 04:21:18 -0400 Subject: macintosh/via-pmu: Fix section mismatch warning The pmu_init() function has the __init qualifier, but the ops struct that holds a pointer to it does not. This causes a build warning. The driver works fine because the pointer is only dereferenced early. The function is so small that there's negligible benefit from using the __init qualifier. Remove it to fix the warning, consistent with the other ADB drivers. Tested-by: Stan Johnson Signed-off-by: Finn Thain Reviewed-by: Geert Uytterhoeven Signed-off-by: Michael Ellerman --- drivers/macintosh/via-pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 25c1ce811053..f8a2c917201f 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -378,7 +378,7 @@ static int pmu_probe(void) return vias == NULL? -ENODEV: 0; } -static int __init pmu_init(void) +static int pmu_init(void) { if (vias == NULL) return -ENODEV; -- cgit v1.2.3 From 576d5290d678a651b9f36050fc1717e0573aca13 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 2 Jul 2018 04:21:18 -0400 Subject: macintosh/via-pmu: Add missing mmio accessors Add missing in_8() accessors to init_pmu() and pmu_sr_intr(). This fixes several sparse warnings: drivers/macintosh/via-pmu.c:536:29: warning: dereference of noderef expression drivers/macintosh/via-pmu.c:537:33: warning: dereference of noderef expression drivers/macintosh/via-pmu.c:1455:17: warning: dereference of noderef expression drivers/macintosh/via-pmu.c:1456:69: warning: dereference of noderef expression Tested-by: Stan Johnson Signed-off-by: Finn Thain Reviewed-by: Geert Uytterhoeven Signed-off-by: Michael Ellerman --- drivers/macintosh/via-pmu.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index f8a2c917201f..ba41220f618e 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -534,8 +534,9 @@ init_pmu(void) int timeout; struct adb_request req; - out_8(&via[B], via[B] | TREQ); /* negate TREQ */ - out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ + /* Negate TREQ. Set TACK to input and TREQ to output. */ + out_8(&via[B], in_8(&via[B]) | TREQ); + out_8(&via[DIRB], (in_8(&via[DIRB]) | TREQ) & ~TACK); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); timeout = 100000; @@ -1418,8 +1419,8 @@ pmu_sr_intr(void) struct adb_request *req; int bite = 0; - if (via[B] & TREQ) { - printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]); + if (in_8(&via[B]) & TREQ) { + printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via[B])); out_8(&via[IFR], SR_INT); return NULL; } -- cgit v1.2.3 From 7ad94699a94b388780e40158e6954a22b68e9d20 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 2 Jul 2018 04:21:18 -0400 Subject: macintosh/via-pmu: Don't clear shift register interrupt flag twice The shift register interrupt flag gets cleared in via_pmu_interrupt() and once again in pmu_sr_intr(). Fix this theoretical race condition. Tested-by: Stan Johnson Signed-off-by: Finn Thain Reviewed-by: Geert Uytterhoeven Signed-off-by: Michael Ellerman --- drivers/macintosh/via-pmu.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index ba41220f618e..c313ddfdb17a 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -1421,7 +1421,6 @@ pmu_sr_intr(void) if (in_8(&via[B]) & TREQ) { printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via[B])); - out_8(&via[IFR], SR_INT); return NULL; } /* The ack may not yet be low when we get the interrupt */ -- cgit v1.2.3 From c57902d52e2d61299872ddc89645d3aa299f1b91 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 2 Jul 2018 04:21:18 -0400 Subject: macintosh/via-pmu: Enhance state machine with new 'uninitialized' state On 68k Macs, the via/vias pointer can't be used to determine whether the PMU driver has been initialized. For portability, add a new state to indicate that via_find_pmu() succeeded. After via_find_pmu() executes, testing vias == NULL is equivalent to testing via == NULL. Replace these tests with pmu_state == uninitialized which is simpler and more consistent. No functional change. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Michael Ellerman --- drivers/macintosh/via-pmu.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index c313ddfdb17a..6a6f1666712e 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -114,6 +114,7 @@ static volatile unsigned char __iomem *via; #define CB1_INT 0x10 /* transition on CB1 input */ static volatile enum pmu_state { + uninitialized = 0, idle, sending, intack, @@ -274,7 +275,7 @@ int __init find_via_pmu(void) u64 taddr; const u32 *reg; - if (via) + if (pmu_state != uninitialized) return 1; vias = of_find_node_by_name(NULL, "via-pmu"); if (vias == NULL) @@ -369,20 +370,19 @@ int __init find_via_pmu(void) fail: of_node_put(vias); vias = NULL; + pmu_state = uninitialized; return 0; } #ifdef CONFIG_ADB static int pmu_probe(void) { - return vias == NULL? -ENODEV: 0; + return pmu_state == uninitialized ? -ENODEV : 0; } static int pmu_init(void) { - if (vias == NULL) - return -ENODEV; - return 0; + return pmu_state == uninitialized ? -ENODEV : 0; } #endif /* CONFIG_ADB */ @@ -397,7 +397,7 @@ static int __init via_pmu_start(void) { unsigned int irq; - if (vias == NULL) + if (pmu_state == uninitialized) return -ENODEV; batt_req.complete = 1; @@ -463,7 +463,7 @@ arch_initcall(via_pmu_start); */ static int __init via_pmu_dev_init(void) { - if (vias == NULL) + if (pmu_state == uninitialized) return -ENODEV; #ifdef CONFIG_PMAC_BACKLIGHT @@ -929,7 +929,7 @@ static int pmu_send_request(struct adb_request *req, int sync) { int i, ret; - if ((vias == NULL) || (!pmu_fully_inited)) { + if (pmu_state == uninitialized || !pmu_fully_inited) { req->complete = 1; return -ENXIO; } @@ -1023,7 +1023,7 @@ static int __pmu_adb_autopoll(int devs) static int pmu_adb_autopoll(int devs) { - if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb) + if (pmu_state == uninitialized || !pmu_fully_inited || !pmu_has_adb) return -ENXIO; adb_dev_map = devs; @@ -1036,7 +1036,7 @@ static int pmu_adb_reset_bus(void) struct adb_request req; int save_autopoll = adb_dev_map; - if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb) + if (pmu_state == uninitialized || !pmu_fully_inited || !pmu_has_adb) return -ENXIO; /* anyone got a better idea?? */ @@ -1072,7 +1072,7 @@ pmu_request(struct adb_request *req, void (*done)(struct adb_request *), va_list list; int i; - if (vias == NULL) + if (pmu_state == uninitialized) return -ENXIO; if (nbytes < 0 || nbytes > 32) { @@ -1097,7 +1097,7 @@ pmu_queue_request(struct adb_request *req) unsigned long flags; int nsend; - if (via == NULL) { + if (pmu_state == uninitialized) { req->complete = 1; return -ENXIO; } @@ -1210,7 +1210,7 @@ pmu_start(void) void pmu_poll(void) { - if (!via) + if (pmu_state == uninitialized) return; if (disable_poll) return; @@ -1220,7 +1220,7 @@ pmu_poll(void) void pmu_poll_adb(void) { - if (!via) + if (pmu_state == uninitialized) return; if (disable_poll) return; @@ -1235,7 +1235,7 @@ pmu_poll_adb(void) void pmu_wait_complete(struct adb_request *req) { - if (!via) + if (pmu_state == uninitialized) return; while((pmu_state != idle && pmu_state != locked) || !req->complete) via_pmu_interrupt(0, NULL); @@ -1251,7 +1251,7 @@ pmu_suspend(void) { unsigned long flags; - if (!via) + if (pmu_state == uninitialized) return; spin_lock_irqsave(&pmu_lock, flags); @@ -1282,7 +1282,7 @@ pmu_resume(void) { unsigned long flags; - if (!via || (pmu_suspended < 1)) + if (pmu_state == uninitialized || pmu_suspended < 1) return; spin_lock_irqsave(&pmu_lock, flags); @@ -1644,7 +1644,7 @@ pmu_enable_irled(int on) { struct adb_request req; - if (vias == NULL) + if (pmu_state == uninitialized) return ; if (pmu_kind == PMU_KEYLARGO_BASED) return ; @@ -1659,7 +1659,7 @@ pmu_restart(void) { struct adb_request req; - if (via == NULL) + if (pmu_state == uninitialized) return; local_irq_disable(); @@ -1684,7 +1684,7 @@ pmu_shutdown(void) { struct adb_request req; - if (via == NULL) + if (pmu_state == uninitialized) return; local_irq_disable(); @@ -1712,7 +1712,7 @@ pmu_shutdown(void) int pmu_present(void) { - return via != NULL; + return pmu_state != uninitialized; } #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) @@ -2378,7 +2378,7 @@ static struct miscdevice pmu_device = { static int pmu_device_init(void) { - if (!via) + if (pmu_state == uninitialized) return 0; if (misc_register(&pmu_device) < 0) printk(KERN_ERR "via-pmu: cannot register misc device.\n"); -- cgit v1.2.3 From c70c35da52c064983199b1b1cbd4daa5a07ef60c Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 2 Jul 2018 04:21:18 -0400 Subject: macintosh/via-pmu: Replace via pointer with via1 and via2 pointers On most PowerPC Macs, the PMU driver uses the shift register and IO port B from a single VIA chip. On 68k and early PowerPC PowerBooks, the driver uses the shift register from one VIA chip together with IO port B from another. Replace via with via1 and via2 to accommodate this. For the CONFIG_PPC_PMAC case, set via1 = via2 so there is no change. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Michael Ellerman --- drivers/macintosh/via-pmu.c | 142 +++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 6a6f1666712e..2557f3e49f18 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -76,7 +76,6 @@ #define BATTERY_POLLING_COUNT 2 static DEFINE_MUTEX(pmu_info_proc_mutex); -static volatile unsigned char __iomem *via; /* VIA registers - spaced 0x200 bytes apart */ #define RS 0x200 /* skip between registers */ @@ -145,6 +144,8 @@ static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited; static int pmu_has_adb; +static volatile unsigned char __iomem *via1; +static volatile unsigned char __iomem *via2; static struct device_node *gpio_node; static unsigned char __iomem *gpio_reg; static int gpio_irq = 0; @@ -340,14 +341,14 @@ int __init find_via_pmu(void) } else pmu_kind = PMU_UNKNOWN; - via = ioremap(taddr, 0x2000); - if (via == NULL) { + via1 = via2 = ioremap(taddr, 0x2000); + if (via1 == NULL) { printk(KERN_ERR "via-pmu: Can't map address !\n"); goto fail_via_remap; } - out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ - out_8(&via[IFR], 0x7f); /* clear IFR */ + out_8(&via1[IER], IER_CLR | 0x7f); /* disable all intrs */ + out_8(&via1[IFR], 0x7f); /* clear IFR */ pmu_state = idle; @@ -362,8 +363,8 @@ int __init find_via_pmu(void) return 1; fail_init: - iounmap(via); - via = NULL; + iounmap(via1); + via1 = via2 = NULL; fail_via_remap: iounmap(gpio_reg); gpio_reg = NULL; @@ -437,7 +438,7 @@ static int __init via_pmu_start(void) } /* Enable interrupts */ - out_8(&via[IER], IER_SET | SR_INT | CB1_INT); + out_8(&via1[IER], IER_SET | SR_INT | CB1_INT); pmu_fully_inited = 1; @@ -535,8 +536,8 @@ init_pmu(void) struct adb_request req; /* Negate TREQ. Set TACK to input and TREQ to output. */ - out_8(&via[B], in_8(&via[B]) | TREQ); - out_8(&via[DIRB], (in_8(&via[DIRB]) | TREQ) & ~TACK); + out_8(&via2[B], in_8(&via2[B]) | TREQ); + out_8(&via2[DIRB], (in_8(&via2[DIRB]) | TREQ) & ~TACK); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); timeout = 100000; @@ -1137,7 +1138,7 @@ wait_for_ack(void) * reported */ int timeout = 4000; - while ((in_8(&via[B]) & TACK) == 0) { + while ((in_8(&via2[B]) & TACK) == 0) { if (--timeout < 0) { printk(KERN_ERR "PMU not responding (!ack)\n"); return; @@ -1151,23 +1152,19 @@ wait_for_ack(void) static inline void send_byte(int x) { - volatile unsigned char __iomem *v = via; - - out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT); - out_8(&v[SR], x); - out_8(&v[B], in_8(&v[B]) & ~TREQ); /* assert TREQ */ - (void)in_8(&v[B]); + out_8(&via1[ACR], in_8(&via1[ACR]) | SR_OUT | SR_EXT); + out_8(&via1[SR], x); + out_8(&via2[B], in_8(&via2[B]) & ~TREQ); /* assert TREQ */ + (void)in_8(&via2[B]); } static inline void recv_byte(void) { - volatile unsigned char __iomem *v = via; - - out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT); - in_8(&v[SR]); /* resets SR */ - out_8(&v[B], in_8(&v[B]) & ~TREQ); - (void)in_8(&v[B]); + out_8(&via1[ACR], (in_8(&via1[ACR]) & ~SR_OUT) | SR_EXT); + in_8(&via1[SR]); /* resets SR */ + out_8(&via2[B], in_8(&via2[B]) & ~TREQ); + (void)in_8(&via2[B]); } static inline void @@ -1270,7 +1267,7 @@ pmu_suspend(void) if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) { if (gpio_irq >= 0) disable_irq_nosync(gpio_irq); - out_8(&via[IER], CB1_INT | IER_CLR); + out_8(&via1[IER], CB1_INT | IER_CLR); spin_unlock_irqrestore(&pmu_lock, flags); break; } @@ -1294,7 +1291,7 @@ pmu_resume(void) adb_int_pending = 1; if (gpio_irq >= 0) enable_irq(gpio_irq); - out_8(&via[IER], CB1_INT | IER_SET); + out_8(&via1[IER], CB1_INT | IER_SET); spin_unlock_irqrestore(&pmu_lock, flags); pmu_poll(); } @@ -1419,20 +1416,20 @@ pmu_sr_intr(void) struct adb_request *req; int bite = 0; - if (in_8(&via[B]) & TREQ) { - printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via[B])); + if (in_8(&via2[B]) & TREQ) { + printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via2[B])); return NULL; } /* The ack may not yet be low when we get the interrupt */ - while ((in_8(&via[B]) & TACK) != 0) + while ((in_8(&via2[B]) & TACK) != 0) ; /* if reading grab the byte, and reset the interrupt */ if (pmu_state == reading || pmu_state == reading_intr) - bite = in_8(&via[SR]); + bite = in_8(&via1[SR]); /* reset TREQ and wait for TACK to go high */ - out_8(&via[B], in_8(&via[B]) | TREQ); + out_8(&via2[B], in_8(&via2[B]) | TREQ); wait_for_ack(); switch (pmu_state) { @@ -1533,17 +1530,17 @@ via_pmu_interrupt(int irq, void *arg) ++disable_poll; for (;;) { - intr = in_8(&via[IFR]) & (SR_INT | CB1_INT); + intr = in_8(&via1[IFR]) & (SR_INT | CB1_INT); if (intr == 0) break; handled = 1; if (++nloop > 1000) { printk(KERN_DEBUG "PMU: stuck in intr loop, " "intr=%x, ier=%x pmu_state=%d\n", - intr, in_8(&via[IER]), pmu_state); + intr, in_8(&via1[IER]), pmu_state); break; } - out_8(&via[IFR], intr); + out_8(&via1[IFR], intr); if (intr & CB1_INT) { adb_int_pending = 1; pmu_irq_stats[0]++; @@ -1725,29 +1722,29 @@ static u32 save_via[8]; static void save_via_state(void) { - save_via[0] = in_8(&via[ANH]); - save_via[1] = in_8(&via[DIRA]); - save_via[2] = in_8(&via[B]); - save_via[3] = in_8(&via[DIRB]); - save_via[4] = in_8(&via[PCR]); - save_via[5] = in_8(&via[ACR]); - save_via[6] = in_8(&via[T1CL]); - save_via[7] = in_8(&via[T1CH]); + save_via[0] = in_8(&via1[ANH]); + save_via[1] = in_8(&via1[DIRA]); + save_via[2] = in_8(&via1[B]); + save_via[3] = in_8(&via1[DIRB]); + save_via[4] = in_8(&via1[PCR]); + save_via[5] = in_8(&via1[ACR]); + save_via[6] = in_8(&via1[T1CL]); + save_via[7] = in_8(&via1[T1CH]); } static void restore_via_state(void) { - out_8(&via[ANH], save_via[0]); - out_8(&via[DIRA], save_via[1]); - out_8(&via[B], save_via[2]); - out_8(&via[DIRB], save_via[3]); - out_8(&via[PCR], save_via[4]); - out_8(&via[ACR], save_via[5]); - out_8(&via[T1CL], save_via[6]); - out_8(&via[T1CH], save_via[7]); - out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ - out_8(&via[IFR], 0x7f); /* clear IFR */ - out_8(&via[IER], IER_SET | SR_INT | CB1_INT); + out_8(&via1[ANH], save_via[0]); + out_8(&via1[DIRA], save_via[1]); + out_8(&via1[B], save_via[2]); + out_8(&via1[DIRB], save_via[3]); + out_8(&via1[PCR], save_via[4]); + out_8(&via1[ACR], save_via[5]); + out_8(&via1[T1CL], save_via[6]); + out_8(&via1[T1CH], save_via[7]); + out_8(&via1[IER], IER_CLR | 0x7f); /* disable all intrs */ + out_8(&via1[IFR], 0x7f); /* clear IFR */ + out_8(&via1[IER], IER_SET | SR_INT | CB1_INT); } #define GRACKLE_PM (1<<7) @@ -2389,33 +2386,33 @@ device_initcall(pmu_device_init); #ifdef DEBUG_SLEEP static inline void -polled_handshake(volatile unsigned char __iomem *via) +polled_handshake(void) { - via[B] &= ~TREQ; eieio(); - while ((via[B] & TACK) != 0) + via2[B] &= ~TREQ; eieio(); + while ((via2[B] & TACK) != 0) ; - via[B] |= TREQ; eieio(); - while ((via[B] & TACK) == 0) + via2[B] |= TREQ; eieio(); + while ((via2[B] & TACK) == 0) ; } static inline void -polled_send_byte(volatile unsigned char __iomem *via, int x) +polled_send_byte(int x) { - via[ACR] |= SR_OUT | SR_EXT; eieio(); - via[SR] = x; eieio(); - polled_handshake(via); + via1[ACR] |= SR_OUT | SR_EXT; eieio(); + via1[SR] = x; eieio(); + polled_handshake(); } static inline int -polled_recv_byte(volatile unsigned char __iomem *via) +polled_recv_byte(void) { int x; - via[ACR] = (via[ACR] & ~SR_OUT) | SR_EXT; eieio(); - x = via[SR]; eieio(); - polled_handshake(via); - x = via[SR]; eieio(); + via1[ACR] = (via1[ACR] & ~SR_OUT) | SR_EXT; eieio(); + x = via1[SR]; eieio(); + polled_handshake(); + x = via1[SR]; eieio(); return x; } @@ -2424,7 +2421,6 @@ pmu_polled_request(struct adb_request *req) { unsigned long flags; int i, l, c; - volatile unsigned char __iomem *v = via; req->complete = 1; c = req->data[0]; @@ -2436,21 +2432,21 @@ pmu_polled_request(struct adb_request *req) while (pmu_state != idle) pmu_poll(); - while ((via[B] & TACK) == 0) + while ((via2[B] & TACK) == 0) ; - polled_send_byte(v, c); + polled_send_byte(c); if (l < 0) { l = req->nbytes - 1; - polled_send_byte(v, l); + polled_send_byte(l); } for (i = 1; i <= l; ++i) - polled_send_byte(v, req->data[i]); + polled_send_byte(req->data[i]); l = pmu_data_len[c][1]; if (l < 0) - l = polled_recv_byte(v); + l = polled_recv_byte(); for (i = 0; i < l; ++i) - req->reply[i + req->reply_len] = polled_recv_byte(v); + req->reply[i + req->reply_len] = polled_recv_byte(); if (req->done) (*req->done)(req); -- cgit v1.2.3 From c16a85a5aad47d712860b42f0ca989b0cb62257a Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 2 Jul 2018 04:21:19 -0400 Subject: macintosh/via-pmu: Add support for m68k PowerBooks Put #ifdefs around the Open Firmware, xmon, interrupt dispatch, battery and suspend code. Add the necessary interrupt handling to support m68k PowerBooks. The pmu_kind value is available to userspace using the PMU_IOC_GET_MODEL ioctl. It is not clear yet what hardware classes are be needed to describe m68k PowerBook models, so pmu_kind is given the provisional value PMU_UNKNOWN. To find out about the hardware, user programs can use /proc/bootinfo or /proc/hardware, or send the PMU_GET_VERSION command using /dev/adb. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Michael Ellerman --- drivers/macintosh/Kconfig | 2 +- drivers/macintosh/via-pmu.c | 101 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 91 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 97a420c11eed..9c6452b38c36 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -65,7 +65,7 @@ config ADB_CUDA If unsure say Y. config ADB_PMU - bool "Support for PMU based PowerMacs" + bool "Support for PMU based PowerMacs and PowerBooks" depends on PPC_PMAC help On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 2557f3e49f18..a68e7a6f00cc 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Device driver for the via-pmu on Apple Powermacs. + * Device driver for the PMU in Apple PowerBooks and PowerMacs. * * The VIA (versatile interface adapter) interfaces to the PMU, * a 6805 microprocessor core whose primary function is to control @@ -49,20 +49,26 @@ #include #include #include -#include +#include #include #include #include #include #include +#ifdef CONFIG_PPC_PMAC #include #include #include -#include +#include #include #include #include #include +#else +#include +#include +#include +#endif #include "via-pmu-event.h" @@ -97,8 +103,13 @@ static DEFINE_MUTEX(pmu_info_proc_mutex); #define ANH (15*RS) /* A-side data, no handshake */ /* Bits in B data register: both active low */ +#ifdef CONFIG_PPC_PMAC #define TACK 0x08 /* Transfer acknowledge (input) */ #define TREQ 0x10 /* Transfer request (output) */ +#else +#define TACK 0x02 +#define TREQ 0x04 +#endif /* Bits in ACR */ #define SR_CTRL 0x1c /* Shift register control bits */ @@ -140,13 +151,15 @@ static int data_index; static int data_len; static volatile int adb_int_pending; static volatile int disable_poll; -static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited; static int pmu_has_adb; +#ifdef CONFIG_PPC_PMAC static volatile unsigned char __iomem *via1; static volatile unsigned char __iomem *via2; +static struct device_node *vias; static struct device_node *gpio_node; +#endif static unsigned char __iomem *gpio_reg; static int gpio_irq = 0; static int gpio_irq_enabled = -1; @@ -273,6 +286,7 @@ static char *pbook_type[] = { int __init find_via_pmu(void) { +#ifdef CONFIG_PPC_PMAC u64 taddr; const u32 *reg; @@ -355,9 +369,6 @@ int __init find_via_pmu(void) if (!init_pmu()) goto fail_init; - printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n", - PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version); - sys_ctrler = SYS_CTRLER_PMU; return 1; @@ -373,6 +384,30 @@ int __init find_via_pmu(void) vias = NULL; pmu_state = uninitialized; return 0; +#else + if (macintosh_config->adb_type != MAC_ADB_PB2) + return 0; + + pmu_kind = PMU_UNKNOWN; + + spin_lock_init(&pmu_lock); + + pmu_has_adb = 1; + + pmu_intr_mask = PMU_INT_PCEJECT | + PMU_INT_SNDBRT | + PMU_INT_ADB | + PMU_INT_TICK; + + pmu_state = idle; + + if (!init_pmu()) { + pmu_state = uninitialized; + return 0; + } + + return 1; +#endif /* !CONFIG_PPC_PMAC */ } #ifdef CONFIG_ADB @@ -396,13 +431,14 @@ static int pmu_init(void) */ static int __init via_pmu_start(void) { - unsigned int irq; + unsigned int __maybe_unused irq; if (pmu_state == uninitialized) return -ENODEV; batt_req.complete = 1; +#ifdef CONFIG_PPC_PMAC irq = irq_of_parse_and_map(vias, 0); if (!irq) { printk(KERN_ERR "via-pmu: can't map interrupt\n"); @@ -439,6 +475,19 @@ static int __init via_pmu_start(void) /* Enable interrupts */ out_8(&via1[IER], IER_SET | SR_INT | CB1_INT); +#else + if (request_irq(IRQ_MAC_ADB_SR, via_pmu_interrupt, IRQF_NO_SUSPEND, + "VIA-PMU-SR", NULL)) { + pr_err("%s: couldn't get SR irq\n", __func__); + return -ENODEV; + } + if (request_irq(IRQ_MAC_ADB_CL, via_pmu_interrupt, IRQF_NO_SUSPEND, + "VIA-PMU-CL", NULL)) { + pr_err("%s: couldn't get CL irq\n", __func__); + free_irq(IRQ_MAC_ADB_SR, NULL); + return -ENODEV; + } +#endif /* !CONFIG_PPC_PMAC */ pmu_fully_inited = 1; @@ -589,6 +638,10 @@ init_pmu(void) option_server_mode ? "enabled" : "disabled"); } } + + printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n", + PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version); + return 1; } @@ -627,6 +680,7 @@ static void pmu_set_server_mode(int server_mode) static void done_battery_state_ohare(struct adb_request* req) { +#ifdef CONFIG_PPC_PMAC /* format: * [0] : flags * 0x01 : AC indicator @@ -708,6 +762,7 @@ done_battery_state_ohare(struct adb_request* req) pmu_batteries[pmu_cur_battery].amperage = amperage; pmu_batteries[pmu_cur_battery].voltage = voltage; pmu_batteries[pmu_cur_battery].time_remaining = time; +#endif /* CONFIG_PPC_PMAC */ clear_bit(0, &async_req_locks); } @@ -1356,6 +1411,7 @@ next: } pmu_done(req); } else { +#ifdef CONFIG_XMON if (len == 4 && data[1] == 0x2c) { extern int xmon_wants_key, xmon_adb_keycode; if (xmon_wants_key) { @@ -1363,6 +1419,7 @@ next: return; } } +#endif /* CONFIG_XMON */ #ifdef CONFIG_ADB /* * XXX On the [23]400 the PMU gives us an up @@ -1530,7 +1587,25 @@ via_pmu_interrupt(int irq, void *arg) ++disable_poll; for (;;) { - intr = in_8(&via1[IFR]) & (SR_INT | CB1_INT); + /* On 68k Macs, VIA interrupts are dispatched individually. + * Unless we are polling, the relevant IRQ flag has already + * been cleared. + */ + intr = 0; + if (IS_ENABLED(CONFIG_PPC_PMAC) || !irq) { + intr = in_8(&via1[IFR]) & (SR_INT | CB1_INT); + out_8(&via1[IFR], intr); + } +#ifndef CONFIG_PPC_PMAC + switch (irq) { + case IRQ_MAC_ADB_CL: + intr = CB1_INT; + break; + case IRQ_MAC_ADB_SR: + intr = SR_INT; + break; + } +#endif if (intr == 0) break; handled = 1; @@ -1540,7 +1615,6 @@ via_pmu_interrupt(int irq, void *arg) intr, in_8(&via1[IER]), pmu_state); break; } - out_8(&via1[IFR], intr); if (intr & CB1_INT) { adb_int_pending = 1; pmu_irq_stats[0]++; @@ -1550,6 +1624,9 @@ via_pmu_interrupt(int irq, void *arg) if (req) break; } +#ifndef CONFIG_PPC_PMAC + break; +#endif } recheck: @@ -1616,7 +1693,7 @@ pmu_unlock(void) } -static irqreturn_t +static __maybe_unused irqreturn_t gpio1_interrupt(int irq, void *arg) { unsigned long flags; @@ -2250,6 +2327,7 @@ static int pmu_ioctl(struct file *filp, int error = -EINVAL; switch (cmd) { +#ifdef CONFIG_PPC_PMAC case PMU_IOC_SLEEP: if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -2259,6 +2337,7 @@ static int pmu_ioctl(struct file *filp, return put_user(0, argp); else return put_user(1, argp); +#endif #ifdef CONFIG_PMAC_BACKLIGHT_LEGACY /* Compatibility ioctl's for backlight */ -- cgit v1.2.3 From c2f028b6a0b241d1b18d8d0ebcb13d21659dcfe7 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 2 Jul 2018 04:21:19 -0400 Subject: macintosh/via-pmu: Explicitly specify CONFIG_PPC_PMAC dependencies At present, CONFIG_ADB_PMU depends on CONFIG_PPC_PMAC. When this gets relaxed to CONFIG_PPC_PMAC || CONFIG_MAC, those Kconfig symbols with implicit deps on PPC_PMAC will need explicit deps. Add them now. No functional change. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Michael Ellerman --- drivers/macintosh/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 9c6452b38c36..26abae4c899d 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -79,7 +79,7 @@ config ADB_PMU config ADB_PMU_LED bool "Support for the Power/iBook front LED" - depends on ADB_PMU + depends on PPC_PMAC && ADB_PMU select NEW_LEDS select LEDS_CLASS help @@ -122,7 +122,7 @@ config PMAC_MEDIABAY config PMAC_BACKLIGHT bool "Backlight control for LCD screens" - depends on ADB_PMU && FB = y && (BROKEN || !PPC64) + depends on PPC_PMAC && ADB_PMU && FB = y && (BROKEN || !PPC64) select FB_BACKLIGHT help Say Y here to enable Macintosh specific extensions of the generic -- cgit v1.2.3 From 54c990775f78113a708f24e15877f6b7bd9a1277 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 2 Jul 2018 04:21:19 -0400 Subject: macintosh/via-pmu68k: Don't load driver on unsupported hardware Don't load the via-pmu68k driver on early PowerBooks. The M50753 PMU device found in those models was never supported by this driver. Attempting to load the driver usually causes a boot hang. Signed-off-by: Finn Thain Reviewed-by: Michael Schmitz Acked-by: Geert Uytterhoeven Signed-off-by: Michael Ellerman --- arch/m68k/mac/misc.c | 6 ++---- drivers/macintosh/via-pmu68k.c | 4 ---- include/uapi/linux/pmu.h | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c index c68054361615..7ccb799eeb57 100644 --- a/arch/m68k/mac/misc.c +++ b/arch/m68k/mac/misc.c @@ -478,8 +478,7 @@ void mac_poweroff(void) cuda_shutdown(); #endif #ifdef CONFIG_ADB_PMU68K - } else if (macintosh_config->adb_type == MAC_ADB_PB1 - || macintosh_config->adb_type == MAC_ADB_PB2) { + } else if (macintosh_config->adb_type == MAC_ADB_PB2) { pmu_shutdown(); #endif } @@ -520,8 +519,7 @@ void mac_reset(void) cuda_restart(); #endif #ifdef CONFIG_ADB_PMU68K - } else if (macintosh_config->adb_type == MAC_ADB_PB1 - || macintosh_config->adb_type == MAC_ADB_PB2) { + } else if (macintosh_config->adb_type == MAC_ADB_PB2) { pmu_restart(); #endif } else if (CPU_IS_030) { diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index d545ed45e482..bec8e1837d7d 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -175,9 +175,6 @@ static s8 pmu_data_len[256][2] = { int __init find_via_pmu(void) { switch (macintosh_config->adb_type) { - case MAC_ADB_PB1: - pmu_kind = PMU_68K_V1; - break; case MAC_ADB_PB2: pmu_kind = PMU_68K_V2; break; @@ -785,7 +782,6 @@ pmu_enable_backlight(int on) /* first call: get current backlight value */ if (backlight_level < 0) { switch(pmu_kind) { - case PMU_68K_V1: case PMU_68K_V2: pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe); while (!req.complete) diff --git a/include/uapi/linux/pmu.h b/include/uapi/linux/pmu.h index 89cb1acea93a..e128f609281a 100644 --- a/include/uapi/linux/pmu.h +++ b/include/uapi/linux/pmu.h @@ -93,7 +93,7 @@ enum { PMU_HEATHROW_BASED, /* PowerBook G3 series */ PMU_PADDINGTON_BASED, /* 1999 PowerBook G3 */ PMU_KEYLARGO_BASED, /* Core99 motherboard (PMU99) */ - PMU_68K_V1, /* 68K PMU, version 1 */ + PMU_68K_V1, /* Unused/deprecated */ PMU_68K_V2, /* 68K PMU, version 2 */ }; -- cgit v1.2.3 From ebd722275f9cfc6752e29d2412fa3816ca05764b Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 2 Jul 2018 04:21:19 -0400 Subject: macintosh/via-pmu: Replace via-pmu68k driver with via-pmu driver Now that the PowerMac via-pmu driver supports m68k PowerBooks, switch over to that driver and remove the via-pmu68k driver. Tested-by: Stan Johnson Signed-off-by: Finn Thain Reviewed-by: Geert Uytterhoeven Acked-by: Geert Uytterhoeven Signed-off-by: Michael Ellerman --- arch/m68k/configs/mac_defconfig | 2 +- arch/m68k/configs/multi_defconfig | 2 +- arch/m68k/mac/config.c | 2 +- arch/m68k/mac/misc.c | 48 +-- drivers/macintosh/Kconfig | 13 +- drivers/macintosh/Makefile | 1 - drivers/macintosh/adb.c | 2 +- drivers/macintosh/via-pmu68k.c | 846 -------------------------------------- include/uapi/linux/pmu.h | 2 +- 9 files changed, 14 insertions(+), 904 deletions(-) delete mode 100644 drivers/macintosh/via-pmu68k.c (limited to 'drivers') diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index b52e597899eb..087ca15e32f1 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -369,7 +369,7 @@ CONFIG_TCM_PSCSI=m CONFIG_ADB=y CONFIG_ADB_MACII=y CONFIG_ADB_IOP=y -CONFIG_ADB_PMU68K=y +CONFIG_ADB_PMU=y CONFIG_ADB_CUDA=y CONFIG_INPUT_ADBHID=y CONFIG_MAC_EMUMOUSEBTN=y diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index 2a84eeec5b02..3f9334084d55 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -402,7 +402,7 @@ CONFIG_TCM_PSCSI=m CONFIG_ADB=y CONFIG_ADB_MACII=y CONFIG_ADB_IOP=y -CONFIG_ADB_PMU68K=y +CONFIG_ADB_PMU=y CONFIG_ADB_CUDA=y CONFIG_INPUT_ADBHID=y CONFIG_MAC_EMUMOUSEBTN=y diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index e522307db47c..92e80cf0d8aa 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -891,7 +891,7 @@ static void __init mac_identify(void) #ifdef CONFIG_ADB_CUDA find_via_cuda(); #endif -#ifdef CONFIG_ADB_PMU68K +#ifdef CONFIG_ADB_PMU find_via_pmu(); #endif } diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c index 7ccb799eeb57..28090a44fa09 100644 --- a/arch/m68k/mac/misc.c +++ b/arch/m68k/mac/misc.c @@ -85,7 +85,7 @@ static void cuda_write_pram(int offset, __u8 data) } #endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_ADB_PMU68K +#ifdef CONFIG_ADB_PMU static long pmu_read_time(void) { struct adb_request req; @@ -136,7 +136,7 @@ static void pmu_write_pram(int offset, __u8 data) while (!req.complete) pmu_poll(); } -#endif /* CONFIG_ADB_PMU68K */ +#endif /* CONFIG_ADB_PMU */ /* * VIA PRAM/RTC access routines @@ -367,38 +367,6 @@ static void cuda_shutdown(void) } #endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_ADB_PMU68K - -void pmu_restart(void) -{ - struct adb_request req; - if (pmu_request(&req, NULL, - 2, PMU_SET_INTR_MASK, PMU_INT_ADB|PMU_INT_TICK) < 0) - return; - while (!req.complete) - pmu_poll(); - if (pmu_request(&req, NULL, 1, PMU_RESET) < 0) - return; - while (!req.complete) - pmu_poll(); -} - -void pmu_shutdown(void) -{ - struct adb_request req; - if (pmu_request(&req, NULL, - 2, PMU_SET_INTR_MASK, PMU_INT_ADB|PMU_INT_TICK) < 0) - return; - while (!req.complete) - pmu_poll(); - if (pmu_request(&req, NULL, 5, PMU_SHUTDOWN, 'M', 'A', 'T', 'T') < 0) - return; - while (!req.complete) - pmu_poll(); -} - -#endif - /* *------------------------------------------------------------------- * Below this point are the generic routines; they'll dispatch to the @@ -423,7 +391,7 @@ void mac_pram_read(int offset, __u8 *buffer, int len) func = cuda_read_pram; break; #endif -#ifdef CONFIG_ADB_PMU68K +#ifdef CONFIG_ADB_PMU case MAC_ADB_PB2: func = pmu_read_pram; break; @@ -453,7 +421,7 @@ void mac_pram_write(int offset, __u8 *buffer, int len) func = cuda_write_pram; break; #endif -#ifdef CONFIG_ADB_PMU68K +#ifdef CONFIG_ADB_PMU case MAC_ADB_PB2: func = pmu_write_pram; break; @@ -477,7 +445,7 @@ void mac_poweroff(void) macintosh_config->adb_type == MAC_ADB_CUDA) { cuda_shutdown(); #endif -#ifdef CONFIG_ADB_PMU68K +#ifdef CONFIG_ADB_PMU } else if (macintosh_config->adb_type == MAC_ADB_PB2) { pmu_shutdown(); #endif @@ -518,7 +486,7 @@ void mac_reset(void) macintosh_config->adb_type == MAC_ADB_CUDA) { cuda_restart(); #endif -#ifdef CONFIG_ADB_PMU68K +#ifdef CONFIG_ADB_PMU } else if (macintosh_config->adb_type == MAC_ADB_PB2) { pmu_restart(); #endif @@ -670,7 +638,7 @@ int mac_hwclk(int op, struct rtc_time *t) now = cuda_read_time(); break; #endif -#ifdef CONFIG_ADB_PMU68K +#ifdef CONFIG_ADB_PMU case MAC_ADB_PB2: now = pmu_read_time(); break; @@ -706,7 +674,7 @@ int mac_hwclk(int op, struct rtc_time *t) cuda_write_time(now); break; #endif -#ifdef CONFIG_ADB_PMU68K +#ifdef CONFIG_ADB_PMU case MAC_ADB_PB2: pmu_write_time(now); break; diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 26abae4c899d..47c350cdfb12 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -39,17 +39,6 @@ config ADB_IOP to enable direct support for it, say 'Y' here. -config ADB_PMU68K - bool "Include PMU (Powerbook) ADB driver" - depends on ADB && MAC - help - Say Y here if want your kernel to support the m68k based Powerbooks. - This includes the PowerBook 140, PowerBook 145, PowerBook 150, - PowerBook 160, PowerBook 165, PowerBook 165c, PowerBook 170, - PowerBook 180, PowerBook, 180c, PowerBook 190cs, PowerBook 520, - PowerBook Duo 210, PowerBook Duo 230, PowerBook Duo 250, - PowerBook Duo 270c, PowerBook Duo 280 and PowerBook Duo 280c. - # we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU config ADB_CUDA bool "Support for Cuda/Egret based Macs and PowerMacs" @@ -66,7 +55,7 @@ config ADB_CUDA config ADB_PMU bool "Support for PMU based PowerMacs and PowerBooks" - depends on PPC_PMAC + depends on PPC_PMAC || MAC help On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the PMU is an embedded microprocessor whose primary function is to diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index ee803638e595..49819b1b6f20 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -22,7 +22,6 @@ obj-$(CONFIG_PMAC_SMU) += smu.o obj-$(CONFIG_ADB) += adb.o obj-$(CONFIG_ADB_MACII) += via-macii.o obj-$(CONFIG_ADB_IOP) += adb-iop.o -obj-$(CONFIG_ADB_PMU68K) += via-pmu68k.o obj-$(CONFIG_ADB_MACIO) += macio-adb.o obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 4c8097e0e6fe..76e98f0f7a3e 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -65,7 +65,7 @@ static struct adb_driver *adb_driver_list[] = { #ifdef CONFIG_ADB_IOP &adb_iop_driver, #endif -#if defined(CONFIG_ADB_PMU) || defined(CONFIG_ADB_PMU68K) +#ifdef CONFIG_ADB_PMU &via_pmu_driver, #endif #ifdef CONFIG_ADB_MACIO diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c deleted file mode 100644 index bec8e1837d7d..000000000000 --- a/drivers/macintosh/via-pmu68k.c +++ /dev/null @@ -1,846 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Device driver for the PMU on 68K-based Apple PowerBooks - * - * The VIA (versatile interface adapter) interfaces to the PMU, - * a 6805 microprocessor core whose primary function is to control - * battery charging and system power on the PowerBooks. - * The PMU also controls the ADB (Apple Desktop Bus) which connects - * to the keyboard and mouse, as well as the non-volatile RAM - * and the RTC (real time clock) chip. - * - * Adapted for 68K PMU by Joshua M. Thompson - * - * Based largely on the PowerMac PMU code by Paul Mackerras and - * Fabio Riccardi. - * - * Also based on the PMU driver from MkLinux by Apple Computer, Inc. - * and the Open Software Foundation, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -/* Misc minor number allocated for /dev/pmu */ -#define PMU_MINOR 154 - -/* VIA registers - spaced 0x200 bytes apart */ -#define RS 0x200 /* skip between registers */ -#define B 0 /* B-side data */ -#define A RS /* A-side data */ -#define DIRB (2*RS) /* B-side direction (1=output) */ -#define DIRA (3*RS) /* A-side direction (1=output) */ -#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ -#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ -#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ -#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ -#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */ -#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */ -#define SR (10*RS) /* Shift register */ -#define ACR (11*RS) /* Auxiliary control register */ -#define PCR (12*RS) /* Peripheral control register */ -#define IFR (13*RS) /* Interrupt flag register */ -#define IER (14*RS) /* Interrupt enable register */ -#define ANH (15*RS) /* A-side data, no handshake */ - -/* Bits in B data register: both active low */ -#define TACK 0x02 /* Transfer acknowledge (input) */ -#define TREQ 0x04 /* Transfer request (output) */ - -/* Bits in ACR */ -#define SR_CTRL 0x1c /* Shift register control bits */ -#define SR_EXT 0x0c /* Shift on external clock */ -#define SR_OUT 0x10 /* Shift out if 1 */ - -/* Bits in IFR and IER */ -#define SR_INT 0x04 /* Shift register full/empty */ -#define CB1_INT 0x10 /* transition on CB1 input */ - -static enum pmu_state { - idle, - sending, - intack, - reading, - reading_intr, -} pmu_state; - -static struct adb_request *current_req; -static struct adb_request *last_req; -static struct adb_request *req_awaiting_reply; -static unsigned char interrupt_data[32]; -static unsigned char *reply_ptr; -static int data_index; -static int data_len; -static int adb_int_pending; -static int pmu_adb_flags; -static int adb_dev_map; -static struct adb_request bright_req_1, bright_req_2, bright_req_3; -static int pmu_kind = PMU_UNKNOWN; -static int pmu_fully_inited; - -int asleep; - -static int pmu_probe(void); -static int pmu_init(void); -static void pmu_start(void); -static irqreturn_t pmu_interrupt(int irq, void *arg); -static int pmu_send_request(struct adb_request *req, int sync); -static int pmu_autopoll(int devs); -void pmu_poll(void); -static int pmu_reset_bus(void); - -static int init_pmu(void); -static void pmu_start(void); -static void send_byte(int x); -static void recv_byte(void); -static void pmu_done(struct adb_request *req); -static void pmu_handle_data(unsigned char *data, int len); -static void set_volume(int level); -static void pmu_enable_backlight(int on); -static void pmu_set_brightness(int level); - -struct adb_driver via_pmu_driver = { - .name = "68K PMU", - .probe = pmu_probe, - .init = pmu_init, - .send_request = pmu_send_request, - .autopoll = pmu_autopoll, - .poll = pmu_poll, - .reset_bus = pmu_reset_bus, -}; - -/* - * This table indicates for each PMU opcode: - * - the number of data bytes to be sent with the command, or -1 - * if a length byte should be sent, - * - the number of response bytes which the PMU will return, or - * -1 if it will send a length byte. - */ -static s8 pmu_data_len[256][2] = { -/* 0 1 2 3 4 5 6 7 */ -/*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, -/*10*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*18*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0}, -/*20*/ {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*28*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1}, -/*30*/ { 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*38*/ { 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0}, -/*40*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*48*/ { 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1}, -/*50*/ { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0}, -/*58*/ { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1}, -/*60*/ { 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*68*/ { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1}, -/*70*/ { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1}, -/*80*/ { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*88*/ { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, -/*90*/ { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*98*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, -/*a0*/ { 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0}, -/*a8*/ { 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, -/*b0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*b8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, -/*c0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*c8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, -/*d0*/ { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*d8*/ { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1}, -/*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0}, -/*e8*/ { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0}, -/*f0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, -}; - -int __init find_via_pmu(void) -{ - switch (macintosh_config->adb_type) { - case MAC_ADB_PB2: - pmu_kind = PMU_68K_V2; - break; - default: - pmu_kind = PMU_UNKNOWN; - return -ENODEV; - } - - pmu_state = idle; - - if (!init_pmu()) - goto fail_init; - - pr_info("adb: PMU 68K driver v0.5 for Unified ADB\n"); - - return 1; - -fail_init: - pmu_kind = PMU_UNKNOWN; - return 0; -} - -static int pmu_probe(void) -{ - if (pmu_kind == PMU_UNKNOWN) - return -ENODEV; - return 0; -} - -static int pmu_init(void) -{ - if (pmu_kind == PMU_UNKNOWN) - return -ENODEV; - return 0; -} - -static int __init via_pmu_start(void) -{ - if (pmu_kind == PMU_UNKNOWN) - return -ENODEV; - - if (request_irq(IRQ_MAC_ADB_SR, pmu_interrupt, 0, "PMU_SR", - pmu_interrupt)) { - pr_err("%s: can't get SR irq\n", __func__); - return -ENODEV; - } - if (request_irq(IRQ_MAC_ADB_CL, pmu_interrupt, 0, "PMU_CL", - pmu_interrupt)) { - pr_err("%s: can't get CL irq\n", __func__); - free_irq(IRQ_MAC_ADB_SR, pmu_interrupt); - return -ENODEV; - } - - pmu_fully_inited = 1; - - /* Enable backlight */ - pmu_enable_backlight(1); - - return 0; -} - -arch_initcall(via_pmu_start); - -static int __init init_pmu(void) -{ - int timeout; - volatile struct adb_request req; - - via2[B] |= TREQ; /* negate TREQ */ - via2[DIRB] = (via2[DIRB] | TREQ) & ~TACK; /* TACK in, TREQ out */ - - pmu_request((struct adb_request *) &req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB); - timeout = 100000; - while (!req.complete) { - if (--timeout < 0) { - printk(KERN_ERR "pmu_init: no response from PMU\n"); - return -EAGAIN; - } - udelay(10); - pmu_poll(); - } - - /* ack all pending interrupts */ - timeout = 100000; - interrupt_data[0] = 1; - while (interrupt_data[0] || pmu_state != idle) { - if (--timeout < 0) { - printk(KERN_ERR "pmu_init: timed out acking intrs\n"); - return -EAGAIN; - } - if (pmu_state == idle) { - adb_int_pending = 1; - pmu_interrupt(0, NULL); - } - pmu_poll(); - udelay(10); - } - - pmu_request((struct adb_request *) &req, NULL, 2, PMU_SET_INTR_MASK, - PMU_INT_ADB_AUTO|PMU_INT_SNDBRT|PMU_INT_ADB); - timeout = 100000; - while (!req.complete) { - if (--timeout < 0) { - printk(KERN_ERR "pmu_init: no response from PMU\n"); - return -EAGAIN; - } - udelay(10); - pmu_poll(); - } - - bright_req_1.complete = 1; - bright_req_2.complete = 1; - bright_req_3.complete = 1; - - return 1; -} - -int -pmu_get_model(void) -{ - return pmu_kind; -} - -/* Send an ADB command */ -static int -pmu_send_request(struct adb_request *req, int sync) -{ - int i, ret; - - if (!pmu_fully_inited) - { - req->complete = 1; - return -ENXIO; - } - - ret = -EINVAL; - - switch (req->data[0]) { - case PMU_PACKET: - for (i = 0; i < req->nbytes - 1; ++i) - req->data[i] = req->data[i+1]; - --req->nbytes; - if (pmu_data_len[req->data[0]][1] != 0) { - req->reply[0] = ADB_RET_OK; - req->reply_len = 1; - } else - req->reply_len = 0; - ret = pmu_queue_request(req); - break; - case CUDA_PACKET: - switch (req->data[1]) { - case CUDA_GET_TIME: - if (req->nbytes != 2) - break; - req->data[0] = PMU_READ_RTC; - req->nbytes = 1; - req->reply_len = 3; - req->reply[0] = CUDA_PACKET; - req->reply[1] = 0; - req->reply[2] = CUDA_GET_TIME; - ret = pmu_queue_request(req); - break; - case CUDA_SET_TIME: - if (req->nbytes != 6) - break; - req->data[0] = PMU_SET_RTC; - req->nbytes = 5; - for (i = 1; i <= 4; ++i) - req->data[i] = req->data[i+1]; - req->reply_len = 3; - req->reply[0] = CUDA_PACKET; - req->reply[1] = 0; - req->reply[2] = CUDA_SET_TIME; - ret = pmu_queue_request(req); - break; - case CUDA_GET_PRAM: - if (req->nbytes != 4) - break; - req->data[0] = PMU_READ_NVRAM; - req->data[1] = req->data[2]; - req->data[2] = req->data[3]; - req->nbytes = 3; - req->reply_len = 3; - req->reply[0] = CUDA_PACKET; - req->reply[1] = 0; - req->reply[2] = CUDA_GET_PRAM; - ret = pmu_queue_request(req); - break; - case CUDA_SET_PRAM: - if (req->nbytes != 5) - break; - req->data[0] = PMU_WRITE_NVRAM; - req->data[1] = req->data[2]; - req->data[2] = req->data[3]; - req->data[3] = req->data[4]; - req->nbytes = 4; - req->reply_len = 3; - req->reply[0] = CUDA_PACKET; - req->reply[1] = 0; - req->reply[2] = CUDA_SET_PRAM; - ret = pmu_queue_request(req); - break; - } - break; - case ADB_PACKET: - for (i = req->nbytes - 1; i > 1; --i) - req->data[i+2] = req->data[i]; - req->data[3] = req->nbytes - 2; - req->data[2] = pmu_adb_flags; - /*req->data[1] = req->data[1];*/ - req->data[0] = PMU_ADB_CMD; - req->nbytes += 2; - req->reply_expected = 1; - req->reply_len = 0; - ret = pmu_queue_request(req); - break; - } - if (ret) - { - req->complete = 1; - return ret; - } - - if (sync) { - while (!req->complete) - pmu_poll(); - } - - return 0; -} - -/* Enable/disable autopolling */ -static int -pmu_autopoll(int devs) -{ - struct adb_request req; - - if (!pmu_fully_inited) return -ENXIO; - - if (devs) { - adb_dev_map = devs; - pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86, - adb_dev_map >> 8, adb_dev_map); - pmu_adb_flags = 2; - } else { - pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF); - pmu_adb_flags = 0; - } - while (!req.complete) - pmu_poll(); - return 0; -} - -/* Reset the ADB bus */ -static int -pmu_reset_bus(void) -{ - struct adb_request req; - long timeout; - int save_autopoll = adb_dev_map; - - if (!pmu_fully_inited) return -ENXIO; - - /* anyone got a better idea?? */ - pmu_autopoll(0); - - req.nbytes = 5; - req.done = NULL; - req.data[0] = PMU_ADB_CMD; - req.data[1] = 0; - req.data[2] = 3; /* ADB_BUSRESET ??? */ - req.data[3] = 0; - req.data[4] = 0; - req.reply_len = 0; - req.reply_expected = 1; - if (pmu_queue_request(&req) != 0) - { - printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n"); - return -EIO; - } - while (!req.complete) - pmu_poll(); - timeout = 100000; - while (!req.complete) { - if (--timeout < 0) { - printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n"); - return -EIO; - } - udelay(10); - pmu_poll(); - } - - if (save_autopoll != 0) - pmu_autopoll(save_autopoll); - - return 0; -} - -/* Construct and send a pmu request */ -int -pmu_request(struct adb_request *req, void (*done)(struct adb_request *), - int nbytes, ...) -{ - va_list list; - int i; - - if (nbytes < 0 || nbytes > 32) { - printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes); - req->complete = 1; - return -EINVAL; - } - req->nbytes = nbytes; - req->done = done; - va_start(list, nbytes); - for (i = 0; i < nbytes; ++i) - req->data[i] = va_arg(list, int); - va_end(list); - if (pmu_data_len[req->data[0]][1] != 0) { - req->reply[0] = ADB_RET_OK; - req->reply_len = 1; - } else - req->reply_len = 0; - req->reply_expected = 0; - return pmu_queue_request(req); -} - -int -pmu_queue_request(struct adb_request *req) -{ - unsigned long flags; - int nsend; - - if (req->nbytes <= 0) { - req->complete = 1; - return 0; - } - nsend = pmu_data_len[req->data[0]][0]; - if (nsend >= 0 && req->nbytes != nsend + 1) { - req->complete = 1; - return -EINVAL; - } - - req->next = NULL; - req->sent = 0; - req->complete = 0; - local_irq_save(flags); - - if (current_req != 0) { - last_req->next = req; - last_req = req; - } else { - current_req = req; - last_req = req; - if (pmu_state == idle) - pmu_start(); - } - - local_irq_restore(flags); - return 0; -} - -static void -send_byte(int x) -{ - via1[ACR] |= SR_CTRL; - via1[SR] = x; - via2[B] &= ~TREQ; /* assert TREQ */ -} - -static void -recv_byte(void) -{ - char c; - - via1[ACR] = (via1[ACR] | SR_EXT) & ~SR_OUT; - c = via1[SR]; /* resets SR */ - via2[B] &= ~TREQ; -} - -static void -pmu_start(void) -{ - unsigned long flags; - struct adb_request *req; - - /* assert pmu_state == idle */ - /* get the packet to send */ - local_irq_save(flags); - req = current_req; - if (req == 0 || pmu_state != idle - || (req->reply_expected && req_awaiting_reply)) - goto out; - - pmu_state = sending; - data_index = 1; - data_len = pmu_data_len[req->data[0]][0]; - - /* set the shift register to shift out and send a byte */ - send_byte(req->data[0]); - -out: - local_irq_restore(flags); -} - -void -pmu_poll(void) -{ - unsigned long flags; - - local_irq_save(flags); - if (via1[IFR] & SR_INT) { - via1[IFR] = SR_INT; - pmu_interrupt(IRQ_MAC_ADB_SR, NULL); - } - if (via1[IFR] & CB1_INT) { - via1[IFR] = CB1_INT; - pmu_interrupt(IRQ_MAC_ADB_CL, NULL); - } - local_irq_restore(flags); -} - -static irqreturn_t -pmu_interrupt(int irq, void *dev_id) -{ - struct adb_request *req; - int timeout, bite = 0; /* to prevent compiler warning */ - -#if 0 - printk("pmu_interrupt: irq %d state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n", - irq, pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending); -#endif - - if (irq == IRQ_MAC_ADB_CL) { /* CB1 interrupt */ - adb_int_pending = 1; - } else if (irq == IRQ_MAC_ADB_SR) { /* SR interrupt */ - if (via2[B] & TACK) { - printk(KERN_DEBUG "PMU: SR_INT but ack still high! (%x)\n", via2[B]); - } - - /* if reading grab the byte */ - if ((via1[ACR] & SR_OUT) == 0) bite = via1[SR]; - - /* reset TREQ and wait for TACK to go high */ - via2[B] |= TREQ; - timeout = 3200; - while (!(via2[B] & TACK)) { - if (--timeout < 0) { - printk(KERN_ERR "PMU not responding (!ack)\n"); - goto finish; - } - udelay(10); - } - - switch (pmu_state) { - case sending: - req = current_req; - if (data_len < 0) { - data_len = req->nbytes - 1; - send_byte(data_len); - break; - } - if (data_index <= data_len) { - send_byte(req->data[data_index++]); - break; - } - req->sent = 1; - data_len = pmu_data_len[req->data[0]][1]; - if (data_len == 0) { - pmu_state = idle; - current_req = req->next; - if (req->reply_expected) - req_awaiting_reply = req; - else - pmu_done(req); - } else { - pmu_state = reading; - data_index = 0; - reply_ptr = req->reply + req->reply_len; - recv_byte(); - } - break; - - case intack: - data_index = 0; - data_len = -1; - pmu_state = reading_intr; - reply_ptr = interrupt_data; - recv_byte(); - break; - - case reading: - case reading_intr: - if (data_len == -1) { - data_len = bite; - if (bite > 32) - printk(KERN_ERR "PMU: bad reply len %d\n", - bite); - } else { - reply_ptr[data_index++] = bite; - } - if (data_index < data_len) { - recv_byte(); - break; - } - - if (pmu_state == reading_intr) { - pmu_handle_data(interrupt_data, data_index); - } else { - req = current_req; - current_req = req->next; - req->reply_len += data_index; - pmu_done(req); - } - pmu_state = idle; - - break; - - default: - printk(KERN_ERR "pmu_interrupt: unknown state %d?\n", - pmu_state); - } - } -finish: - if (pmu_state == idle) { - if (adb_int_pending) { - pmu_state = intack; - send_byte(PMU_INT_ACK); - adb_int_pending = 0; - } else if (current_req) { - pmu_start(); - } - } - -#if 0 - printk("pmu_interrupt: exit state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n", - pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending); -#endif - return IRQ_HANDLED; -} - -static void -pmu_done(struct adb_request *req) -{ - req->complete = 1; - if (req->done) - (*req->done)(req); -} - -/* Interrupt data could be the result data from an ADB cmd */ -static void -pmu_handle_data(unsigned char *data, int len) -{ - static int show_pmu_ints = 1; - - asleep = 0; - if (len < 1) { - adb_int_pending = 0; - return; - } - if (data[0] & PMU_INT_ADB) { - if ((data[0] & PMU_INT_ADB_AUTO) == 0) { - struct adb_request *req = req_awaiting_reply; - if (req == 0) { - printk(KERN_ERR "PMU: extra ADB reply\n"); - return; - } - req_awaiting_reply = NULL; - if (len <= 2) - req->reply_len = 0; - else { - memcpy(req->reply, data + 1, len - 1); - req->reply_len = len - 1; - } - pmu_done(req); - } else { - adb_input(data+1, len-1, 1); - } - } else { - if (data[0] == 0x08 && len == 3) { - /* sound/brightness buttons pressed */ - pmu_set_brightness(data[1] >> 3); - set_volume(data[2]); - } else if (show_pmu_ints - && !(data[0] == PMU_INT_TICK && len == 1)) { - int i; - printk(KERN_DEBUG "pmu intr"); - for (i = 0; i < len; ++i) - printk(" %.2x", data[i]); - printk("\n"); - } - } -} - -static int backlight_level = -1; -static int backlight_enabled = 0; - -#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1)) - -static void -pmu_enable_backlight(int on) -{ - struct adb_request req; - - if (on) { - /* first call: get current backlight value */ - if (backlight_level < 0) { - switch(pmu_kind) { - case PMU_68K_V2: - pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe); - while (!req.complete) - pmu_poll(); - printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", (int)req.reply[1]); - backlight_level = req.reply[1]; - break; - default: - backlight_enabled = 0; - return; - } - } - pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, - LEVEL_TO_BRIGHT(backlight_level)); - while (!req.complete) - pmu_poll(); - } - pmu_request(&req, NULL, 2, PMU_POWER_CTRL, - PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF)); - while (!req.complete) - pmu_poll(); - backlight_enabled = on; -} - -static void -pmu_set_brightness(int level) -{ - int bright; - - backlight_level = level; - bright = LEVEL_TO_BRIGHT(level); - if (!backlight_enabled) - return; - if (bright_req_1.complete) - pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, - bright); - if (bright_req_2.complete) - pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, - PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF)); -} - -void -pmu_enable_irled(int on) -{ - struct adb_request req; - - pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED | - (on ? PMU_POW_ON : PMU_POW_OFF)); - while (!req.complete) - pmu_poll(); -} - -static void -set_volume(int level) -{ -} - -int -pmu_present(void) -{ - return (pmu_kind != PMU_UNKNOWN); -} diff --git a/include/uapi/linux/pmu.h b/include/uapi/linux/pmu.h index e128f609281a..97256f90e6df 100644 --- a/include/uapi/linux/pmu.h +++ b/include/uapi/linux/pmu.h @@ -94,7 +94,7 @@ enum { PMU_PADDINGTON_BASED, /* 1999 PowerBook G3 */ PMU_KEYLARGO_BASED, /* Core99 motherboard (PMU99) */ PMU_68K_V1, /* Unused/deprecated */ - PMU_68K_V2, /* 68K PMU, version 2 */ + PMU_68K_V2, /* Unused/deprecated */ }; /* PMU PMU_POWER_EVENTS commands */ -- cgit v1.2.3 From b5c7cccaacdfa8d707da3e65970b15070f56df5e Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 2 Jul 2018 04:21:19 -0400 Subject: macintosh/via-pmu: Clean up interrupt statistics Replace an open-coded ffs() with the function call. Simplify an if-else cascade using a switch statement. Correct a typo and an indentation issue. Tested-by: Stan Johnson Signed-off-by: Finn Thain Reviewed-by: Geert Uytterhoeven Signed-off-by: Michael Ellerman --- drivers/macintosh/via-pmu.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index a68e7a6f00cc..3da5d40309d4 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -1355,7 +1355,8 @@ pmu_resume(void) static void pmu_handle_data(unsigned char *data, int len) { - unsigned char ints, pirq; + unsigned char ints; + int idx; int i = 0; asleep = 0; @@ -1377,25 +1378,24 @@ pmu_handle_data(unsigned char *data, int len) ints &= ~(PMU_INT_ADB_AUTO | PMU_INT_AUTO_SRQ_POLL); next: - if (ints == 0) { if (i > pmu_irq_stats[10]) pmu_irq_stats[10] = i; return; } - - for (pirq = 0; pirq < 8; pirq++) - if (ints & (1 << pirq)) - break; - pmu_irq_stats[pirq]++; i++; - ints &= ~(1 << pirq); + + idx = ffs(ints) - 1; + ints &= ~BIT(idx); + + pmu_irq_stats[idx]++; /* Note: for some reason, we get an interrupt with len=1, * data[0]==0 after each normal ADB interrupt, at least * on the Pismo. Still investigating... --BenH */ - if ((1 << pirq) & PMU_INT_ADB) { + switch (BIT(idx)) { + case PMU_INT_ADB: if ((data[0] & PMU_INT_ADB_AUTO) == 0) { struct adb_request *req = req_awaiting_reply; if (!req) { @@ -1433,25 +1433,28 @@ next: adb_input(data+1, len-1, 1); #endif /* CONFIG_ADB */ } - } + break; + /* Sound/brightness button pressed */ - else if ((1 << pirq) & PMU_INT_SNDBRT) { + case PMU_INT_SNDBRT: #ifdef CONFIG_PMAC_BACKLIGHT if (len == 3) pmac_backlight_set_legacy_brightness_pmu(data[1] >> 4); #endif - } + break; + /* Tick interrupt */ - else if ((1 << pirq) & PMU_INT_TICK) { - /* Environement or tick interrupt, query batteries */ + case PMU_INT_TICK: + /* Environment or tick interrupt, query batteries */ if (pmu_battery_count) { if ((--query_batt_timer) == 0) { query_battery_state(); query_batt_timer = BATTERY_POLLING_COUNT; } } - } - else if ((1 << pirq) & PMU_INT_ENVIRONMENT) { + break; + + case PMU_INT_ENVIRONMENT: if (pmu_battery_count) query_battery_state(); pmu_pass_intr(data, len); @@ -1461,7 +1464,9 @@ next: via_pmu_event(PMU_EVT_POWER, !!(data[1]&8)); via_pmu_event(PMU_EVT_LID, data[1]&1); } - } else { + break; + + default: pmu_pass_intr(data, len); } goto next; -- cgit v1.2.3 From 6edc22fc9cbb80fdf929df3e5b912d8c42e0ff3a Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 2 Jul 2018 04:21:19 -0400 Subject: macintosh/via-pmu: Disambiguate interrupt statistics Some of the event counters are overloaded which makes it very difficult to interpret their values. Counter 0 is supposed to report CB1 interrupts but it can also count PMU_INT_WAITING_CHARGER events. Counter 1 is supposed to report GPIO interrupts but it can also count other events (depending upon the value of the PMU_INT_ADB bit). Disambiguate these statistics with dedicated counters for GPIO and CB1 interrupts. Comments in the MkLinux source code say that the type 0 and type 1 interrupts are model-specific. Label them as "unknown". This change to the contents of /proc/pmu/interrupts is by necessity visible in userland. However, packages which interact with the PMU (that is, pbbuttonsd, pmac-utils and pmud) don't open this file. AFAIK, user software has no need to poll these counters. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Michael Ellerman --- drivers/macintosh/via-pmu.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 3da5d40309d4..d72c450aebe5 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -172,7 +172,9 @@ static int drop_interrupts; static int option_lid_wakeup = 1; #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ static unsigned long async_req_locks; -static unsigned int pmu_irq_stats[11]; + +#define NUM_IRQ_STATS 13 +static unsigned int pmu_irq_stats[NUM_IRQ_STATS]; static struct proc_dir_entry *proc_pmu_root; static struct proc_dir_entry *proc_pmu_info; @@ -873,9 +875,9 @@ static int pmu_info_proc_show(struct seq_file *m, void *v) static int pmu_irqstats_proc_show(struct seq_file *m, void *v) { int i; - static const char *irq_names[] = { - "Total CB1 triggered events", - "Total GPIO1 triggered events", + static const char *irq_names[NUM_IRQ_STATS] = { + "Unknown interrupt (type 0)", + "Unknown interrupt (type 1)", "PC-Card eject button", "Sound/Brightness button", "ADB message", @@ -884,10 +886,12 @@ static int pmu_irqstats_proc_show(struct seq_file *m, void *v) "Tick timer", "Ghost interrupt (zero len)", "Empty interrupt (empty mask)", - "Max irqs in a row" + "Max irqs in a row", + "Total CB1 triggered events", + "Total GPIO1 triggered events", }; - for (i=0; i<11; i++) { + for (i = 0; i < NUM_IRQ_STATS; i++) { seq_printf(m, " %2u: %10u (%s)\n", i, pmu_irq_stats[i], irq_names[i]); } @@ -1622,7 +1626,7 @@ via_pmu_interrupt(int irq, void *arg) } if (intr & CB1_INT) { adb_int_pending = 1; - pmu_irq_stats[0]++; + pmu_irq_stats[11]++; } if (intr & SR_INT) { req = pmu_sr_intr(); @@ -1709,7 +1713,7 @@ gpio1_interrupt(int irq, void *arg) disable_irq_nosync(gpio_irq); gpio_irq_enabled = 0; } - pmu_irq_stats[1]++; + pmu_irq_stats[12]++; adb_int_pending = 1; spin_unlock_irqrestore(&pmu_lock, flags); via_pmu_interrupt(0, NULL); -- cgit v1.2.3 From 1961acad2f88559c2cdd2ef67c58c3627f1f6e54 Mon Sep 17 00:00:00 2001 From: Akshay Adiga Date: Thu, 5 Jul 2018 17:10:22 +0530 Subject: powernv/cpuidle: Use parsed device tree values for cpuidle_init Export pnv_idle_states and nr_pnv_idle_states so that its accessible to cpuidle driver. Use properties from pnv_idle_states structure for powernv cpuidle_init. Signed-off-by: Akshay Adiga Reviewed-by: Nicholas Piggin Reviewed-by: Gautham R. Shenoy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/cpuidle.h | 2 + drivers/cpuidle/cpuidle-powernv.c | 158 ++++++------------------------------- 2 files changed, 28 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/cpuidle.h b/arch/powerpc/include/asm/cpuidle.h index 574b0ce1d671..43e5f31fe64d 100644 --- a/arch/powerpc/include/asm/cpuidle.h +++ b/arch/powerpc/include/asm/cpuidle.h @@ -90,6 +90,8 @@ struct pnv_idle_states_t { bool valid; }; +extern struct pnv_idle_states_t *pnv_idle_states; +extern int nr_pnv_idle_states; extern u32 pnv_fastsleep_workaround_at_entry[]; extern u32 pnv_fastsleep_workaround_at_exit[]; diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c index d29e4f041efe..84b1ebe212b3 100644 --- a/drivers/cpuidle/cpuidle-powernv.c +++ b/drivers/cpuidle/cpuidle-powernv.c @@ -242,6 +242,7 @@ static inline void add_powernv_state(int index, const char *name, powernv_states[index].target_residency = target_residency; powernv_states[index].exit_latency = exit_latency; powernv_states[index].enter = idle_fn; + /* For power8 and below psscr_* will be 0 */ stop_psscr_table[index].val = psscr_val; stop_psscr_table[index].mask = psscr_mask; } @@ -263,186 +264,80 @@ static inline int validate_dt_prop_sizes(const char *prop1, int prop1_len, extern u32 pnv_get_supported_cpuidle_states(void); static int powernv_add_idle_states(void) { - struct device_node *power_mgt; int nr_idle_states = 1; /* Snooze */ - int dt_idle_states, count; - u32 latency_ns[CPUIDLE_STATE_MAX]; - u32 residency_ns[CPUIDLE_STATE_MAX]; - u32 flags[CPUIDLE_STATE_MAX]; - u64 psscr_val[CPUIDLE_STATE_MAX]; - u64 psscr_mask[CPUIDLE_STATE_MAX]; - const char *names[CPUIDLE_STATE_MAX]; + int dt_idle_states; u32 has_stop_states = 0; - int i, rc; + int i; u32 supported_flags = pnv_get_supported_cpuidle_states(); /* Currently we have snooze statically defined */ - - power_mgt = of_find_node_by_path("/ibm,opal/power-mgt"); - if (!power_mgt) { - pr_warn("opal: PowerMgmt Node not found\n"); - goto out; - } - - /* Read values of any property to determine the num of idle states */ - dt_idle_states = of_property_count_u32_elems(power_mgt, "ibm,cpu-idle-state-flags"); - if (dt_idle_states < 0) { - pr_warn("cpuidle-powernv: no idle states found in the DT\n"); + if (nr_pnv_idle_states <= 0) { + pr_warn("cpuidle-powernv : Only Snooze is available\n"); goto out; } - count = of_property_count_u32_elems(power_mgt, - "ibm,cpu-idle-state-latencies-ns"); - - if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", dt_idle_states, - "ibm,cpu-idle-state-latencies-ns", - count) != 0) - goto out; - - count = of_property_count_strings(power_mgt, - "ibm,cpu-idle-state-names"); - if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", dt_idle_states, - "ibm,cpu-idle-state-names", - count) != 0) - goto out; + /* TODO: Count only states which are eligible for cpuidle */ + dt_idle_states = nr_pnv_idle_states; /* * Since snooze is used as first idle state, max idle states allowed is * CPUIDLE_STATE_MAX -1 */ - if (dt_idle_states > CPUIDLE_STATE_MAX - 1) { + if (nr_pnv_idle_states > CPUIDLE_STATE_MAX - 1) { pr_warn("cpuidle-powernv: discovered idle states more than allowed"); dt_idle_states = CPUIDLE_STATE_MAX - 1; } - if (of_property_read_u32_array(power_mgt, - "ibm,cpu-idle-state-flags", flags, dt_idle_states)) { - pr_warn("cpuidle-powernv : missing ibm,cpu-idle-state-flags in DT\n"); - goto out; - } - - if (of_property_read_u32_array(power_mgt, - "ibm,cpu-idle-state-latencies-ns", latency_ns, - dt_idle_states)) { - pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT\n"); - goto out; - } - if (of_property_read_string_array(power_mgt, - "ibm,cpu-idle-state-names", names, dt_idle_states) < 0) { - pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-names in DT\n"); - goto out; - } - /* * If the idle states use stop instruction, probe for psscr values * and psscr mask which are necessary to specify required stop level. */ - has_stop_states = (flags[0] & + has_stop_states = (pnv_idle_states[0].flags & (OPAL_PM_STOP_INST_FAST | OPAL_PM_STOP_INST_DEEP)); - if (has_stop_states) { - count = of_property_count_u64_elems(power_mgt, - "ibm,cpu-idle-state-psscr"); - if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", - dt_idle_states, - "ibm,cpu-idle-state-psscr", - count) != 0) - goto out; - - count = of_property_count_u64_elems(power_mgt, - "ibm,cpu-idle-state-psscr-mask"); - if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", - dt_idle_states, - "ibm,cpu-idle-state-psscr-mask", - count) != 0) - goto out; - - if (of_property_read_u64_array(power_mgt, - "ibm,cpu-idle-state-psscr", psscr_val, dt_idle_states)) { - pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr in DT\n"); - goto out; - } - - if (of_property_read_u64_array(power_mgt, - "ibm,cpu-idle-state-psscr-mask", - psscr_mask, dt_idle_states)) { - pr_warn("cpuidle-powernv:Missing ibm,cpu-idle-state-psscr-mask in DT\n"); - goto out; - } - } - - count = of_property_count_u32_elems(power_mgt, - "ibm,cpu-idle-state-residency-ns"); - - if (count < 0) { - rc = count; - } else if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", - dt_idle_states, - "ibm,cpu-idle-state-residency-ns", - count) != 0) { - goto out; - } else { - rc = of_property_read_u32_array(power_mgt, - "ibm,cpu-idle-state-residency-ns", - residency_ns, dt_idle_states); - } for (i = 0; i < dt_idle_states; i++) { unsigned int exit_latency, target_residency; bool stops_timebase = false; + struct pnv_idle_states_t *state = &pnv_idle_states[i]; /* * Skip the platform idle state whose flag isn't in * the supported_cpuidle_states flag mask. */ - if ((flags[i] & supported_flags) != flags[i]) + if ((state->flags & supported_flags) != state->flags) continue; /* * If an idle state has exit latency beyond * POWERNV_THRESHOLD_LATENCY_NS then don't use it * in cpu-idle. */ - if (latency_ns[i] > POWERNV_THRESHOLD_LATENCY_NS) + if (state->latency_ns > POWERNV_THRESHOLD_LATENCY_NS) continue; /* * Firmware passes residency and latency values in ns. * cpuidle expects it in us. */ - exit_latency = DIV_ROUND_UP(latency_ns[i], 1000); - if (!rc) - target_residency = DIV_ROUND_UP(residency_ns[i], 1000); - else - target_residency = 0; - - if (has_stop_states) { - int err = validate_psscr_val_mask(&psscr_val[i], - &psscr_mask[i], - flags[i]); - if (err) { - report_invalid_psscr_val(psscr_val[i], err); + exit_latency = DIV_ROUND_UP(state->latency_ns, 1000); + target_residency = DIV_ROUND_UP(state->residency_ns, 1000); + + if (has_stop_states && !(state->valid)) continue; - } - } - if (flags[i] & OPAL_PM_TIMEBASE_STOP) + if (state->flags & OPAL_PM_TIMEBASE_STOP) stops_timebase = true; - /* - * For nap and fastsleep, use default target_residency - * values if f/w does not expose it. - */ - if (flags[i] & OPAL_PM_NAP_ENABLED) { - if (!rc) - target_residency = 100; + if (state->flags & OPAL_PM_NAP_ENABLED) { /* Add NAP state */ add_powernv_state(nr_idle_states, "Nap", CPUIDLE_FLAG_NONE, nap_loop, target_residency, exit_latency, 0, 0); } else if (has_stop_states && !stops_timebase) { - add_powernv_state(nr_idle_states, names[i], + add_powernv_state(nr_idle_states, state->name, CPUIDLE_FLAG_NONE, stop_loop, target_residency, exit_latency, - psscr_val[i], psscr_mask[i]); + state->psscr_val, + state->psscr_mask); } /* @@ -450,20 +345,19 @@ static int powernv_add_idle_states(void) * within this config dependency check. */ #ifdef CONFIG_TICK_ONESHOT - else if (flags[i] & OPAL_PM_SLEEP_ENABLED || - flags[i] & OPAL_PM_SLEEP_ENABLED_ER1) { - if (!rc) - target_residency = 300000; + else if (state->flags & OPAL_PM_SLEEP_ENABLED || + state->flags & OPAL_PM_SLEEP_ENABLED_ER1) { /* Add FASTSLEEP state */ add_powernv_state(nr_idle_states, "FastSleep", CPUIDLE_FLAG_TIMER_STOP, fastsleep_loop, target_residency, exit_latency, 0, 0); } else if (has_stop_states && stops_timebase) { - add_powernv_state(nr_idle_states, names[i], + add_powernv_state(nr_idle_states, state->name, CPUIDLE_FLAG_TIMER_STOP, stop_loop, target_residency, exit_latency, - psscr_val[i], psscr_mask[i]); + state->psscr_val, + state->psscr_mask); } #endif else -- cgit v1.2.3 From e0da99123f3c80f679d1b40a4321c1478bef14f7 Mon Sep 17 00:00:00 2001 From: Shilpasri G Bhat Date: Tue, 24 Jul 2018 14:43:09 +0530 Subject: hwmon: (ibmpowernv) Add attributes to enable/disable sensor groups OPAL firmware provides the facility for some groups of sensors to be enabled/disabled at runtime to give the user the option of using the system resources for collecting these sensors or not. For example, on POWER9 systems, the On Chip Controller (OCC) gathers various system and chip level sensors and maintains their values in main memory. This patch provides support for enabling/disabling the sensor groups like power, temperature, current and voltage. Signed-off-by: Shilpasri G Bhat [stewart@linux.vnet.ibm.com: Commit message] Acked-by: Guenter Roeck Signed-off-by: Michael Ellerman --- Documentation/hwmon/ibmpowernv | 43 +++++++- drivers/hwmon/ibmpowernv.c | 238 +++++++++++++++++++++++++++++++++++------ 2 files changed, 247 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/ibmpowernv b/Documentation/hwmon/ibmpowernv index 8826ba29db36..56468258711f 100644 --- a/Documentation/hwmon/ibmpowernv +++ b/Documentation/hwmon/ibmpowernv @@ -33,9 +33,48 @@ fanX_input Measured RPM value. fanX_min Threshold RPM for alert generation. fanX_fault 0: No fail condition 1: Failing fan + tempX_input Measured ambient temperature. tempX_max Threshold ambient temperature for alert generation. -inX_input Measured power supply voltage +tempX_highest Historical maximum temperature +tempX_lowest Historical minimum temperature +tempX_enable Enable/disable all temperature sensors belonging to the + sub-group. In POWER9, this attribute corresponds to + each OCC. Using this attribute each OCC can be asked to + disable/enable all of its temperature sensors. + 1: Enable + 0: Disable + +inX_input Measured power supply voltage (millivolt) inX_fault 0: No fail condition. 1: Failing power supply. -power1_input System power consumption (microWatt) +inX_highest Historical maximum voltage +inX_lowest Historical minimum voltage +inX_enable Enable/disable all voltage sensors belonging to the + sub-group. In POWER9, this attribute corresponds to + each OCC. Using this attribute each OCC can be asked to + disable/enable all of its voltage sensors. + 1: Enable + 0: Disable + +powerX_input Power consumption (microWatt) +powerX_input_highest Historical maximum power +powerX_input_lowest Historical minimum power +powerX_enable Enable/disable all power sensors belonging to the + sub-group. In POWER9, this attribute corresponds to + each OCC. Using this attribute each OCC can be asked to + disable/enable all of its power sensors. + 1: Enable + 0: Disable + +currX_input Measured current (milliampere) +currX_highest Historical maximum current +currX_lowest Historical minimum current +currX_enable Enable/disable all current sensors belonging to the + sub-group. In POWER9, this attribute corresponds to + each OCC. Using this attribute each OCC can be asked to + disable/enable all of its current sensors. + 1: Enable + 0: Disable + +energyX_input Cumulative energy (microJoule) diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c index f829dadfd5a0..83472808c816 100644 --- a/drivers/hwmon/ibmpowernv.c +++ b/drivers/hwmon/ibmpowernv.c @@ -90,11 +90,20 @@ struct sensor_data { char label[MAX_LABEL_LEN]; char name[MAX_ATTR_LEN]; struct device_attribute dev_attr; + struct sensor_group_data *sgrp_data; +}; + +struct sensor_group_data { + struct mutex mutex; + u32 gid; + bool enable; }; struct platform_data { const struct attribute_group *attr_groups[MAX_SENSOR_TYPE + 1]; + struct sensor_group_data *sgrp_data; u32 sensors_count; /* Total count of sensors from each group */ + u32 nr_sensor_groups; /* Total number of sensor groups */ }; static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr, @@ -105,6 +114,9 @@ static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr, ssize_t ret; u64 x; + if (sdata->sgrp_data && !sdata->sgrp_data->enable) + return -ENODATA; + ret = opal_get_sensor_data_u64(sdata->id, &x); if (ret) @@ -120,6 +132,46 @@ static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr, return sprintf(buf, "%llu\n", x); } +static ssize_t show_enable(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_data *sdata = container_of(devattr, struct sensor_data, + dev_attr); + + return sprintf(buf, "%u\n", sdata->sgrp_data->enable); +} + +static ssize_t store_enable(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_data *sdata = container_of(devattr, struct sensor_data, + dev_attr); + struct sensor_group_data *sgrp_data = sdata->sgrp_data; + int ret; + bool data; + + ret = kstrtobool(buf, &data); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&sgrp_data->mutex); + if (ret) + return ret; + + if (data != sgrp_data->enable) { + ret = sensor_group_enable(sgrp_data->gid, data); + if (!ret) + sgrp_data->enable = data; + } + + if (!ret) + ret = count; + + mutex_unlock(&sgrp_data->mutex); + return ret; +} + static ssize_t show_label(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -292,12 +344,115 @@ static u32 get_sensor_hwmon_index(struct sensor_data *sdata, return ++sensor_groups[sdata->type].hwmon_index; } +static int init_sensor_group_data(struct platform_device *pdev, + struct platform_data *pdata) +{ + struct sensor_group_data *sgrp_data; + struct device_node *groups, *sgrp; + int count = 0, ret = 0; + enum sensors type; + + groups = of_find_compatible_node(NULL, NULL, "ibm,opal-sensor-group"); + if (!groups) + return ret; + + for_each_child_of_node(groups, sgrp) { + type = get_sensor_type(sgrp); + if (type != MAX_SENSOR_TYPE) + pdata->nr_sensor_groups++; + } + + if (!pdata->nr_sensor_groups) + goto out; + + sgrp_data = devm_kcalloc(&pdev->dev, pdata->nr_sensor_groups, + sizeof(*sgrp_data), GFP_KERNEL); + if (!sgrp_data) { + ret = -ENOMEM; + goto out; + } + + for_each_child_of_node(groups, sgrp) { + u32 gid; + + type = get_sensor_type(sgrp); + if (type == MAX_SENSOR_TYPE) + continue; + + if (of_property_read_u32(sgrp, "sensor-group-id", &gid)) + continue; + + if (of_count_phandle_with_args(sgrp, "sensors", NULL) <= 0) + continue; + + sensor_groups[type].attr_count++; + sgrp_data[count].gid = gid; + mutex_init(&sgrp_data[count].mutex); + sgrp_data[count++].enable = false; + } + + pdata->sgrp_data = sgrp_data; +out: + of_node_put(groups); + return ret; +} + +static struct sensor_group_data *get_sensor_group(struct platform_data *pdata, + struct device_node *node, + enum sensors gtype) +{ + struct sensor_group_data *sgrp_data = pdata->sgrp_data; + struct device_node *groups, *sgrp; + + groups = of_find_compatible_node(NULL, NULL, "ibm,opal-sensor-group"); + if (!groups) + return NULL; + + for_each_child_of_node(groups, sgrp) { + struct of_phandle_iterator it; + u32 gid; + int rc, i; + enum sensors type; + + type = get_sensor_type(sgrp); + if (type != gtype) + continue; + + if (of_property_read_u32(sgrp, "sensor-group-id", &gid)) + continue; + + of_for_each_phandle(&it, rc, sgrp, "sensors", NULL, 0) + if (it.phandle == node->phandle) { + of_node_put(it.node); + break; + } + + if (rc) + continue; + + for (i = 0; i < pdata->nr_sensor_groups; i++) + if (gid == sgrp_data[i].gid) { + of_node_put(sgrp); + of_node_put(groups); + return &sgrp_data[i]; + } + } + + of_node_put(groups); + return NULL; +} + static int populate_attr_groups(struct platform_device *pdev) { struct platform_data *pdata = platform_get_drvdata(pdev); const struct attribute_group **pgroups = pdata->attr_groups; struct device_node *opal, *np; enum sensors type; + int ret; + + ret = init_sensor_group_data(pdev, pdata); + if (ret) + return ret; opal = of_find_node_by_path("/ibm,opal/sensors"); for_each_child_of_node(opal, np) { @@ -344,7 +499,10 @@ static int populate_attr_groups(struct platform_device *pdev) static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name, ssize_t (*show)(struct device *dev, struct device_attribute *attr, - char *buf)) + char *buf), + ssize_t (*store)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count)) { snprintf(sdata->name, MAX_ATTR_LEN, "%s%d_%s", sensor_groups[sdata->type].name, sdata->hwmon_index, @@ -352,23 +510,33 @@ static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name, sysfs_attr_init(&sdata->dev_attr.attr); sdata->dev_attr.attr.name = sdata->name; - sdata->dev_attr.attr.mode = S_IRUGO; sdata->dev_attr.show = show; + if (store) { + sdata->dev_attr.store = store; + sdata->dev_attr.attr.mode = 0664; + } else { + sdata->dev_attr.attr.mode = 0444; + } } static void populate_sensor(struct sensor_data *sdata, int od, int hd, int sid, const char *attr_name, enum sensors type, const struct attribute_group *pgroup, + struct sensor_group_data *sgrp_data, ssize_t (*show)(struct device *dev, struct device_attribute *attr, - char *buf)) + char *buf), + ssize_t (*store)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count)) { sdata->id = sid; sdata->type = type; sdata->opal_index = od; sdata->hwmon_index = hd; - create_hwmon_attr(sdata, attr_name, show); + create_hwmon_attr(sdata, attr_name, show, store); pgroup->attrs[sensor_groups[type].attr_count++] = &sdata->dev_attr.attr; + sdata->sgrp_data = sgrp_data; } static char *get_max_attr(enum sensors type) @@ -403,24 +571,23 @@ static int create_device_attrs(struct platform_device *pdev) const struct attribute_group **pgroups = pdata->attr_groups; struct device_node *opal, *np; struct sensor_data *sdata; - u32 sensor_id; - enum sensors type; u32 count = 0; - int err = 0; + u32 group_attr_id[MAX_SENSOR_TYPE] = {0}; - opal = of_find_node_by_path("/ibm,opal/sensors"); sdata = devm_kcalloc(&pdev->dev, pdata->sensors_count, sizeof(*sdata), GFP_KERNEL); - if (!sdata) { - err = -ENOMEM; - goto exit_put_node; - } + if (!sdata) + return -ENOMEM; + opal = of_find_node_by_path("/ibm,opal/sensors"); for_each_child_of_node(opal, np) { + struct sensor_group_data *sgrp_data; const char *attr_name; - u32 opal_index; + u32 opal_index, hw_id; + u32 sensor_id; const char *label; + enum sensors type; if (np->name == NULL) continue; @@ -456,14 +623,12 @@ static int create_device_attrs(struct platform_device *pdev) opal_index = INVALID_INDEX; } - sdata[count].opal_index = opal_index; - sdata[count].hwmon_index = - get_sensor_hwmon_index(&sdata[count], sdata, count); - - create_hwmon_attr(&sdata[count], attr_name, show_sensor); - - pgroups[type]->attrs[sensor_groups[type].attr_count++] = - &sdata[count++].dev_attr.attr; + hw_id = get_sensor_hwmon_index(&sdata[count], sdata, count); + sgrp_data = get_sensor_group(pdata, np, type); + populate_sensor(&sdata[count], opal_index, hw_id, sensor_id, + attr_name, type, pgroups[type], sgrp_data, + show_sensor, NULL); + count++; if (!of_property_read_string(np, "label", &label)) { /* @@ -474,35 +639,43 @@ static int create_device_attrs(struct platform_device *pdev) */ make_sensor_label(np, &sdata[count], label); - populate_sensor(&sdata[count], opal_index, - sdata[count - 1].hwmon_index, + populate_sensor(&sdata[count], opal_index, hw_id, sensor_id, "label", type, pgroups[type], - show_label); + NULL, show_label, NULL); count++; } if (!of_property_read_u32(np, "sensor-data-max", &sensor_id)) { attr_name = get_max_attr(type); - populate_sensor(&sdata[count], opal_index, - sdata[count - 1].hwmon_index, + populate_sensor(&sdata[count], opal_index, hw_id, sensor_id, attr_name, type, - pgroups[type], show_sensor); + pgroups[type], sgrp_data, show_sensor, + NULL); count++; } if (!of_property_read_u32(np, "sensor-data-min", &sensor_id)) { attr_name = get_min_attr(type); - populate_sensor(&sdata[count], opal_index, - sdata[count - 1].hwmon_index, + populate_sensor(&sdata[count], opal_index, hw_id, sensor_id, attr_name, type, - pgroups[type], show_sensor); + pgroups[type], sgrp_data, show_sensor, + NULL); + count++; + } + + if (sgrp_data && !sgrp_data->enable) { + sgrp_data->enable = true; + hw_id = ++group_attr_id[type]; + populate_sensor(&sdata[count], opal_index, hw_id, + sgrp_data->gid, "enable", type, + pgroups[type], sgrp_data, show_enable, + store_enable); count++; } } -exit_put_node: of_node_put(opal); - return err; + return 0; } static int ibmpowernv_probe(struct platform_device *pdev) @@ -517,6 +690,7 @@ static int ibmpowernv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pdata); pdata->sensors_count = 0; + pdata->nr_sensor_groups = 0; err = populate_attr_groups(pdev); if (err) return err; -- cgit v1.2.3 From a0ac3687fb404d59296ecba4642071424d153569 Mon Sep 17 00:00:00 2001 From: Parth Y Shah Date: Fri, 3 Aug 2018 15:50:38 +0530 Subject: misc: cxl: changed asterisk position Resolved <"foo* bar" should be "foo *bar"> error Signed-off-by: Parth Y Shah Signed-off-by: Michael Ellerman --- drivers/misc/cxl/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c index 70dbb6de102c..d45f3e6b17d2 100644 --- a/drivers/misc/cxl/fault.c +++ b/drivers/misc/cxl/fault.c @@ -33,7 +33,7 @@ static bool sste_matches(struct cxl_sste *sste, struct copro_slb *slb) * This finds a free SSTE for the given SLB, or returns NULL if it's already in * the segment table. */ -static struct cxl_sste* find_free_sste(struct cxl_context *ctx, +static struct cxl_sste *find_free_sste(struct cxl_context *ctx, struct copro_slb *slb) { struct cxl_sste *primary, *sste, *ret = NULL; -- cgit v1.2.3 From 656ecc16e8fc2ab44b3d70e3fcc197a7020d0ca5 Mon Sep 17 00:00:00 2001 From: Haren Myneni Date: Wed, 13 Jun 2018 00:32:40 -0700 Subject: crypto/nx: Initialize 842 high and normal RxFIFO control registers NX increments readOffset by FIFO size in receive FIFO control register when CRB is read. But the index in RxFIFO has to match with the corresponding entry in FIFO maintained by VAS in kernel. Otherwise NX may be processing incorrect CRBs and can cause CRB timeout. VAS FIFO offset is 0 when the receive window is opened during initialization. When the module is reloaded or in kexec boot, readOffset in FIFO control register may not match with VAS entry. This patch adds nx_coproc_init OPAL call to reset readOffset and queued entries in FIFO control register for both high and normal FIFOs. Signed-off-by: Haren Myneni [mpe: Fixup uninitialized variable warning] Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/opal-api.h | 3 ++- arch/powerpc/include/asm/opal.h | 1 + arch/powerpc/platforms/powernv/opal-wrappers.S | 1 + arch/powerpc/platforms/powernv/opal.c | 2 ++ drivers/crypto/nx/nx-842-powernv.c | 31 +++++++++++++++++++++++--- 5 files changed, 34 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h index 56a94a1bd754..8365353330b4 100644 --- a/arch/powerpc/include/asm/opal-api.h +++ b/arch/powerpc/include/asm/opal-api.h @@ -209,7 +209,8 @@ #define OPAL_SENSOR_GROUP_ENABLE 163 #define OPAL_PCI_GET_PBCQ_TUNNEL_BAR 164 #define OPAL_PCI_SET_PBCQ_TUNNEL_BAR 165 -#define OPAL_LAST 165 +#define OPAL_NX_COPROC_INIT 167 +#define OPAL_LAST 167 #define QUIESCE_HOLD 1 /* Spin all calls at entry */ #define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */ diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 2e81555de643..834e7e29f1e4 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -293,6 +293,7 @@ int opal_get_power_shift_ratio(u32 handle, int token, u32 *psr); int opal_set_power_shift_ratio(u32 handle, int token, u32 psr); int opal_sensor_group_clear(u32 group_hndl, int token); int opal_sensor_group_enable(u32 group_hndl, int token, bool enable); +int opal_nx_coproc_init(uint32_t chip_id, uint32_t ct); s64 opal_signal_system_reset(s32 cpu); s64 opal_quiesce(u64 shutdown_type, s32 cpu); diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index 029b37c04f35..251528231a9e 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -330,3 +330,4 @@ OPAL_CALL(opal_pci_get_pbcq_tunnel_bar, OPAL_PCI_GET_PBCQ_TUNNEL_BAR); OPAL_CALL(opal_pci_set_pbcq_tunnel_bar, OPAL_PCI_SET_PBCQ_TUNNEL_BAR); OPAL_CALL(opal_sensor_read_u64, OPAL_SENSOR_READ_U64); OPAL_CALL(opal_sensor_group_enable, OPAL_SENSOR_GROUP_ENABLE); +OPAL_CALL(opal_nx_coproc_init, OPAL_NX_COPROC_INIT); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 46f58ff80bcf..404c379db168 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -1090,3 +1090,5 @@ EXPORT_SYMBOL_GPL(opal_write_oppanel_async); EXPORT_SYMBOL_GPL(opal_int_set_mfrr); EXPORT_SYMBOL_GPL(opal_int_eoi); EXPORT_SYMBOL_GPL(opal_error_code); +/* Export the below symbol for NX compression */ +EXPORT_SYMBOL(opal_nx_coproc_init); diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c index 36afd6d8753c..c68df7e8bee1 100644 --- a/drivers/crypto/nx/nx-842-powernv.c +++ b/drivers/crypto/nx/nx-842-powernv.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dan Streetman "); @@ -753,7 +755,7 @@ static int nx842_open_percpu_txwins(void) } static int __init vas_cfg_coproc_info(struct device_node *dn, int chip_id, - int vasid) + int vasid, int *ct) { struct vas_window *rxwin = NULL; struct vas_rx_win_attr rxattr; @@ -837,6 +839,15 @@ static int __init vas_cfg_coproc_info(struct device_node *dn, int chip_id, coproc->vas.id = vasid; nx842_add_coprocs_list(coproc, chip_id); + /* + * (lpid, pid, tid) combination has to be unique for each + * coprocessor instance in the system. So to make it + * unique, skiboot uses coprocessor type such as 842 or + * GZIP for pid and provides this value to kernel in pid + * device-tree property. + */ + *ct = pid; + return 0; err_out: @@ -850,6 +861,7 @@ static int __init nx842_powernv_probe_vas(struct device_node *pn) struct device_node *dn; int chip_id, vasid, ret = 0; int nx_fifo_found = 0; + int uninitialized_var(ct); chip_id = of_get_ibm_chip_id(pn); if (chip_id < 0) { @@ -865,7 +877,7 @@ static int __init nx842_powernv_probe_vas(struct device_node *pn) for_each_child_of_node(pn, dn) { if (of_device_is_compatible(dn, "ibm,p9-nx-842")) { - ret = vas_cfg_coproc_info(dn, chip_id, vasid); + ret = vas_cfg_coproc_info(dn, chip_id, vasid, &ct); if (ret) { of_node_put(dn); return ret; @@ -876,9 +888,22 @@ static int __init nx842_powernv_probe_vas(struct device_node *pn) if (!nx_fifo_found) { pr_err("NX842 FIFO nodes are missing\n"); - ret = -EINVAL; + return -EINVAL; } + /* + * Initialize NX instance for both high and normal priority FIFOs. + */ + if (opal_check_token(OPAL_NX_COPROC_INIT)) { + ret = opal_nx_coproc_init(chip_id, ct); + if (ret) { + pr_err("Failed to initialize NX for chip(%d): %d\n", + chip_id, ret); + ret = opal_error_code(ret); + } + } else + pr_warn("Firmware doesn't support NX initialization\n"); + return ret; } -- cgit v1.2.3 From e4ecafb14fd9cd77d8f4320af1922e700db56d2b Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Thu, 22 Mar 2018 22:05:28 +0100 Subject: cxl: remove a dead branch In commit 14baf4d9c739 ("cxl: Add guest-specific code") the following code was added: if (afu->crs_len < 0) { dev_err(&afu->dev, "Unexpected configuration record size value\n"); return -EINVAL; } However the variable `crs_len` is of type u64 and cannot be compared < 0. Remove the dead code section. Fix the following warning treated as error with W=1: ../drivers/misc/cxl/guest.c:919:19: error: comparison of unsigned expression < 0 is always false [-Werror=type-limits] Signed-off-by: Mathieu Malaterre Signed-off-by: Michael Ellerman --- drivers/misc/cxl/guest.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c index f5dc740fcd13..3bc0c15d4d85 100644 --- a/drivers/misc/cxl/guest.c +++ b/drivers/misc/cxl/guest.c @@ -913,11 +913,6 @@ static int afu_properties_look_ok(struct cxl_afu *afu) return -EINVAL; } - if (afu->crs_len < 0) { - dev_err(&afu->dev, "Unexpected configuration record size value\n"); - return -EINVAL; - } - return 0; } -- cgit v1.2.3