From 512bb03f4957b0ea6ebcd82f6d34147fc7f83128 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Wed, 26 Jul 2017 18:40:12 +0800 Subject: ACPI: processor: use dev_dbg() instead of dev_warn() when CPPC probe failed _CPC is a optinal object for processor device so it's fine for processor devices in DSDT without CPPC data, but when booting the system with CPPC enabled in the kernel but without its support in the firmware, I got lots of warnings on a 64 core system: [ 6.346016] acpi ACPI0007:00: CPPC data invalid or not present [ 6.346028] acpi ACPI0007:01: CPPC data invalid or not present [ 6.346039] acpi ACPI0007:02: CPPC data invalid or not present [ 6.346050] acpi ACPI0007:03: CPPC data invalid or not present [ 6.346063] acpi ACPI0007:04: CPPC data invalid or not present ... [ 6.346737] acpi ACPI0007:3f: CPPC data invalid or not present This isn't much useful and a little bit noise, so switch the dev_warn() to dev_dbg(). Signed-off-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 591d1dd3f04e..9d6aff22684e 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -237,7 +237,7 @@ static int __acpi_processor_start(struct acpi_device *device) result = acpi_cppc_processor_probe(pr); if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS)) - dev_warn(&device->dev, "CPPC data invalid or not present\n"); + dev_dbg(&device->dev, "CPPC data invalid or not present\n"); if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) acpi_processor_power_init(pr); -- cgit From 4f0450af530e62b0217522cab4803b5a65dccc46 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Thu, 3 Aug 2017 13:32:36 +0100 Subject: ACPI: Make acpi_dev_get_resources() method agnostic The function acpi_dev_get_resources() is completely generic and can be used to parse resource objects that are not necessarily coming from the _CRS method but also from other objects eg _DMA that have the same _CRS resource format. Create an acpi_dev_get_resources() helper, internal to the ACPI resources parsing compilation unit, __acpi_dev_get_resources(), that takes a const char* parameter to detect which ACPI method should be called to retrieve the resources list and make acpi_dev_get_resources() call it with a method name _CRS leaving the API behaviour unchanged. Signed-off-by: Lorenzo Pieralisi Tested-by: Nate Watterson Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 53 +++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index cd4c4271dc4c..93f1b5ce89b9 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -573,6 +573,35 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, return AE_OK; } +static int __acpi_dev_get_resources(struct acpi_device *adev, + struct list_head *list, + int (*preproc)(struct acpi_resource *, void *), + void *preproc_data, char *method) +{ + struct res_proc_context c; + acpi_status status; + + if (!adev || !adev->handle || !list_empty(list)) + return -EINVAL; + + if (!acpi_has_method(adev->handle, method)) + return 0; + + c.list = list; + c.preproc = preproc; + c.preproc_data = preproc_data; + c.count = 0; + c.error = 0; + status = acpi_walk_resources(adev->handle, method, + acpi_dev_process_resource, &c); + if (ACPI_FAILURE(status)) { + acpi_dev_free_resource_list(list); + return c.error ? c.error : -EIO; + } + + return c.count; +} + /** * acpi_dev_get_resources - Get current resources of a device. * @adev: ACPI device node to get the resources for. @@ -601,28 +630,8 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, int (*preproc)(struct acpi_resource *, void *), void *preproc_data) { - struct res_proc_context c; - acpi_status status; - - if (!adev || !adev->handle || !list_empty(list)) - return -EINVAL; - - if (!acpi_has_method(adev->handle, METHOD_NAME__CRS)) - return 0; - - c.list = list; - c.preproc = preproc; - c.preproc_data = preproc_data; - c.count = 0; - c.error = 0; - status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, - acpi_dev_process_resource, &c); - if (ACPI_FAILURE(status)) { - acpi_dev_free_resource_list(list); - return c.error ? c.error : -EIO; - } - - return c.count; + return __acpi_dev_get_resources(adev, list, preproc, preproc_data, + METHOD_NAME__CRS); } EXPORT_SYMBOL_GPL(acpi_dev_get_resources); -- cgit From c04ac679c6b86e4e36fbb675c6c061b4091f5810 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 7 Aug 2017 11:29:48 +0100 Subject: ACPI: Introduce DMA ranges parsing Some devices have limited addressing capabilities and cannot reference the whole memory address space while carrying out DMA operations (eg some devices with bus address bits range smaller than system bus - which prevents them from using bus addresses that are otherwise valid for the system). The ACPI _DMA object allows bus devices to define the DMA window that is actually addressable by devices that sit upstream the bus, therefore providing a means to parse and initialize the devices DMA masks and addressable DMA range size. By relying on the generic ACPI kernel layer to retrieve and parse resources, introduce ACPI core code to parse the _DMA object. Signed-off-by: Lorenzo Pieralisi Tested-by: Nate Watterson Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 35 ++++++++++++++++++++++ drivers/acpi/scan.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 2 ++ include/linux/acpi.h | 8 +++++ 4 files changed, 124 insertions(+) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 93f1b5ce89b9..d85e010ee2cc 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -635,6 +635,41 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, } EXPORT_SYMBOL_GPL(acpi_dev_get_resources); +static int is_memory(struct acpi_resource *ares, void *not_used) +{ + struct resource_win win; + struct resource *res = &win.res; + + memset(&win, 0, sizeof(win)); + + return !(acpi_dev_resource_memory(ares, res) + || acpi_dev_resource_address_space(ares, &win) + || acpi_dev_resource_ext_address_space(ares, &win)); +} + +/** + * acpi_dev_get_dma_resources - Get current DMA resources of a device. + * @adev: ACPI device node to get the resources for. + * @list: Head of the resultant list of resources (must be empty). + * + * Evaluate the _DMA method for the given device node and process its + * output. + * + * The resultant struct resource objects are put on the list pointed to + * by @list, that must be empty initially, as members of struct + * resource_entry objects. Callers of this routine should use + * %acpi_dev_free_resource_list() to free that list. + * + * The number of resources in the output list is returned on success, + * an error code reflecting the error condition is returned otherwise. + */ +int acpi_dev_get_dma_resources(struct acpi_device *adev, struct list_head *list) +{ + return __acpi_dev_get_resources(adev, list, is_memory, NULL, + METHOD_NAME__DMA); +} +EXPORT_SYMBOL_GPL(acpi_dev_get_dma_resources); + /** * acpi_dev_filter_resource_type - Filter ACPI resource according to resource * types diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 33897298f03e..94500d99f2d6 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1359,6 +1359,85 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) return DEV_DMA_NON_COHERENT; } +/** + * acpi_dma_get_range() - Get device DMA parameters. + * + * @dev: device to configure + * @dma_addr: pointer device DMA address result + * @offset: pointer to the DMA offset result + * @size: pointer to DMA range size result + * + * Evaluate DMA regions and return respectively DMA region start, offset + * and size in dma_addr, offset and size on parsing success; it does not + * update the passed in values on failure. + * + * Return 0 on success, < 0 on failure. + */ +int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset, + u64 *size) +{ + struct acpi_device *adev; + LIST_HEAD(list); + struct resource_entry *rentry; + int ret; + struct device *dma_dev = dev; + u64 len, dma_start = U64_MAX, dma_end = 0, dma_offset = 0; + + /* + * Walk the device tree chasing an ACPI companion with a _DMA + * object while we go. Stop if we find a device with an ACPI + * companion containing a _DMA method. + */ + do { + adev = ACPI_COMPANION(dma_dev); + if (adev && acpi_has_method(adev->handle, METHOD_NAME__DMA)) + break; + + dma_dev = dma_dev->parent; + } while (dma_dev); + + if (!dma_dev) + return -ENODEV; + + if (!acpi_has_method(adev->handle, METHOD_NAME__CRS)) { + acpi_handle_warn(adev->handle, "_DMA is valid only if _CRS is present\n"); + return -EINVAL; + } + + ret = acpi_dev_get_dma_resources(adev, &list); + if (ret > 0) { + list_for_each_entry(rentry, &list, node) { + if (dma_offset && rentry->offset != dma_offset) { + ret = -EINVAL; + dev_warn(dma_dev, "Can't handle multiple windows with different offsets\n"); + goto out; + } + dma_offset = rentry->offset; + + /* Take lower and upper limits */ + if (rentry->res->start < dma_start) + dma_start = rentry->res->start; + if (rentry->res->end > dma_end) + dma_end = rentry->res->end; + } + + if (dma_start >= dma_end) { + ret = -EINVAL; + dev_dbg(dma_dev, "Invalid DMA regions configuration\n"); + goto out; + } + + *dma_addr = dma_start - dma_offset; + len = dma_end - dma_start; + *size = max(len, len + 1); + *offset = dma_offset; + } + out: + acpi_dev_free_resource_list(&list); + + return ret >= 0 ? 0 : ret; +} + /** * acpi_dma_configure - Set-up DMA configuration for the device. * @dev: The pointer to the device diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 68bc6be447fd..07eb963b5026 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -578,6 +578,8 @@ struct acpi_pci_root { bool acpi_dma_supported(struct acpi_device *adev); enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev); +int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset, + u64 *size); int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr); void acpi_dma_deconfigure(struct device *dev); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c749eef1daa1..a5eaff9f2c6d 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -427,6 +427,8 @@ void acpi_dev_free_resource_list(struct list_head *list); int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, int (*preproc)(struct acpi_resource *, void *), void *preproc_data); +int acpi_dev_get_dma_resources(struct acpi_device *adev, + struct list_head *list); int acpi_dev_filter_resource_type(struct acpi_resource *ares, unsigned long types); @@ -774,6 +776,12 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) return DEV_DMA_NOT_SUPPORTED; } +static inline int acpi_dma_get_range(struct device *dev, u64 *dma_addr, + u64 *offset, u64 *size) +{ + return -ENODEV; +} + static inline int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) { -- cgit From 7ad4263980826e8b02e121af22f4f4c9103fe86d Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 7 Aug 2017 11:29:49 +0100 Subject: ACPI: Make acpi_dma_configure() DMA regions aware Current ACPI DMA configuration set-up device DMA capabilities through kernel defaults that do not take into account platform specific DMA configurations reported by firmware. By leveraging the ACPI acpi_dev_get_dma_resources() API, add code in acpi_dma_configure() to retrieve the DMA regions to correctly set-up PCI devices DMA parameters. Rework the ACPI IORT kernel API to make sure they can accommodate the DMA set-up required by firmware. By making PCI devices DMA set-up ACPI IORT specific, the kernel is shielded from unwanted regressions that could be triggered by parsing DMA resources on arches that were previously ignoring them (ie x86/ia64), leaving kernel behaviour unchanged on those arches. Signed-off-by: Lorenzo Pieralisi Acked-by: Will Deacon Tested-by: Nate Watterson Signed-off-by: Rafael J. Wysocki --- drivers/acpi/arm64/iort.c | 37 +++++++++++++++++++++++++++++++++++-- drivers/acpi/scan.c | 12 ++++-------- include/linux/acpi_iort.h | 5 +++-- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index a3215ee671c1..606af87c425f 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -681,12 +681,17 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev, } /** - * iort_set_dma_mask - Set-up dma mask for a device. + * iort_dma_setup() - Set-up device DMA parameters. * * @dev: device to configure + * @dma_addr: device DMA address result pointer + * @size: DMA range size result pointer */ -void iort_set_dma_mask(struct device *dev) +void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) { + u64 mask, dmaaddr = 0, size = 0, offset = 0; + int ret, msb; + /* * Set default coherent_dma_mask to 32 bit. Drivers are expected to * setup the correct supported mask. @@ -700,6 +705,34 @@ void iort_set_dma_mask(struct device *dev) */ if (!dev->dma_mask) dev->dma_mask = &dev->coherent_dma_mask; + + size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); + + if (dev_is_pci(dev)) { + ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size); + if (!ret) { + msb = fls64(dmaaddr + size - 1); + /* + * Round-up to the power-of-two mask or set + * the mask to the whole 64-bit address space + * in case the DMA region covers the full + * memory window. + */ + mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1; + /* + * Limit coherent and dma mask based on size + * retrieved from firmware. + */ + dev->coherent_dma_mask = mask; + *dev->dma_mask = mask; + } + } + + *dma_addr = dmaaddr; + *dma_size = size; + + dev->dma_pfn_offset = PFN_DOWN(offset); + dev_dbg(dev, "dma_pfn_offset(%#08llx)\n", offset); } /** diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 94500d99f2d6..0483d36433ac 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1446,20 +1446,16 @@ int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset, int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) { const struct iommu_ops *iommu; - u64 size; + u64 dma_addr = 0, size = 0; - iort_set_dma_mask(dev); + iort_dma_setup(dev, &dma_addr, &size); iommu = iort_iommu_configure(dev); if (IS_ERR(iommu) && PTR_ERR(iommu) == -EPROBE_DEFER) return -EPROBE_DEFER; - size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); - /* - * Assume dma valid range starts at 0 and covers the whole - * coherent_dma_mask. - */ - arch_setup_dma_ops(dev, 0, size, iommu, attr == DEV_DMA_COHERENT); + arch_setup_dma_ops(dev, dma_addr, size, + iommu, attr == DEV_DMA_COHERENT); return 0; } diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index 8379d406ad2e..8d3f0bf80379 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -36,7 +36,7 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id); void acpi_configure_pmsi_domain(struct device *dev); int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id); /* IOMMU interface */ -void iort_set_dma_mask(struct device *dev); +void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *size); const struct iommu_ops *iort_iommu_configure(struct device *dev); #else static inline void acpi_iort_init(void) { } @@ -47,7 +47,8 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev, { return NULL; } static inline void acpi_configure_pmsi_domain(struct device *dev) { } /* IOMMU interface */ -static inline void iort_set_dma_mask(struct device *dev) { } +static inline void iort_dma_setup(struct device *dev, u64 *dma_addr, + u64 *size) { } static inline const struct iommu_ops *iort_iommu_configure(struct device *dev) { return NULL; } -- cgit From 10d8ab2c15b9ef2f46c35e7c36781399d6f2cc82 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Thu, 3 Aug 2017 13:32:39 +0100 Subject: ACPI/IORT: Add IORT named component memory address limits IORT named components provide firmware configuration describing how many address bits a given device is capable of generating to address memory. Add code to the kernel to retrieve memory address limits configuration for IORT named components and configure DMA masks accordingly. Signed-off-by: Lorenzo Pieralisi Acked-by: Will Deacon Tested-by: Nate Watterson Signed-off-by: Rafael J. Wysocki --- drivers/acpi/arm64/iort.c | 54 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 606af87c425f..5b9e8dc29c09 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -680,6 +680,24 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev, return ret ? NULL : ops; } +static int nc_dma_get_range(struct device *dev, u64 *size) +{ + struct acpi_iort_node *node; + struct acpi_iort_named_component *ncomp; + + node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT, + iort_match_node_callback, dev); + if (!node) + return -ENODEV; + + ncomp = (struct acpi_iort_named_component *)node->node_data; + + *size = ncomp->memory_address_limit >= 64 ? U64_MAX : + 1ULL<memory_address_limit; + + return 0; +} + /** * iort_dma_setup() - Set-up device DMA parameters. * @@ -708,24 +726,26 @@ void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); - if (dev_is_pci(dev)) { + if (dev_is_pci(dev)) ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size); - if (!ret) { - msb = fls64(dmaaddr + size - 1); - /* - * Round-up to the power-of-two mask or set - * the mask to the whole 64-bit address space - * in case the DMA region covers the full - * memory window. - */ - mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1; - /* - * Limit coherent and dma mask based on size - * retrieved from firmware. - */ - dev->coherent_dma_mask = mask; - *dev->dma_mask = mask; - } + else + ret = nc_dma_get_range(dev, &size); + + if (!ret) { + msb = fls64(dmaaddr + size - 1); + /* + * Round-up to the power-of-two mask or set + * the mask to the whole 64-bit address space + * in case the DMA region covers the full + * memory window. + */ + mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1; + /* + * Limit coherent and dma mask based on size + * retrieved from firmware. + */ + dev->coherent_dma_mask = mask; + *dev->dma_mask = mask; } *dma_addr = dmaaddr; -- cgit From 66ed4cac669cae8870b13511492ff1d41f49179a Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 1 Aug 2017 13:43:57 +0100 Subject: mailbox: pcc: Drop uninformative output during boot When booting on an ACPI enabled system that does not provide the Platform Communications Channel Table (PCCT), the pcc mailbox driver prints - [ 0.484261] PCCT header not found. during probe before returning -ENODEV. This message clutters the bootlog and doesn't provide any useful information. Drop this message. Signed-off-by: Punit Agrawal Acked-by: Alexey Klimov Signed-off-by: Rafael J. Wysocki --- drivers/mailbox/pcc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index cbca5e51b975..9b7005e1345e 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -457,10 +457,8 @@ static int __init acpi_pcc_probe(void) /* Search for PCCT */ status = acpi_get_table(ACPI_SIG_PCCT, 0, &pcct_tbl); - if (ACPI_FAILURE(status) || !pcct_tbl) { - pr_warn("PCCT header not found.\n"); + if (ACPI_FAILURE(status) || !pcct_tbl) return -ENODEV; - } count = acpi_table_parse_entries(ACPI_SIG_PCCT, sizeof(struct acpi_table_pcct), -- cgit From 69b957c26b32c3407d1b8cc0d2390b271728db8a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 17 Aug 2017 10:21:12 +0800 Subject: ACPI: EC: Fix possible issues related to EC initialization order Use the observation that the EC command/data register addresses are sufficient to determine if two EC devices are equivelent to modify acpi_is_boot_ec(). Then, for the removed comparison factors, EC ID and EC GPE, they need to be synchronized for the boot_ec: 1. Before registering the BIOS-provided EC event handlers in acpi_ec_register_query_methods(), the namespace node holding _Qxx methods should be located. The real namespace PNP0C09 device location then is apparently more trustworthy than the ECDT EC ID. 2. Because of the ASUS quirks, the ECDT EC GPE is more trustworthy than the namespace PNP0C09 device's _GPE setting. Use the above observations to synchronize the boot_ec settings in acpi_ec_add(). Finally, change the order of acpi_ec_ecdt_start() and acpi_ec_add(), called from acpi_bus_register_driver(), so as to follow the fast path of determining the location of _Qxx. Signed-off-by: Lv Zheng [ rjw : Changelog & comments ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index ae3d6d152633..7ea7aa9701e3 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1586,9 +1586,7 @@ static bool acpi_is_boot_ec(struct acpi_ec *ec) { if (!boot_ec) return false; - if (ec->handle == boot_ec->handle && - ec->gpe == boot_ec->gpe && - ec->command_addr == boot_ec->command_addr && + if (ec->command_addr == boot_ec->command_addr && ec->data_addr == boot_ec->data_addr) return true; return false; @@ -1613,6 +1611,13 @@ static int acpi_ec_add(struct acpi_device *device) if (acpi_is_boot_ec(ec)) { boot_ec_is_ecdt = false; + /* + * Trust PNP0C09 namespace location rather than ECDT ID. + * + * But trust ECDT GPE rather than _GPE because of ASUS quirks, + * so do not change boot_ec->gpe to ec->gpe. + */ + boot_ec->handle = ec->handle; acpi_handle_debug(ec->handle, "duplicated.\n"); acpi_ec_free(ec); ec = boot_ec; @@ -1747,18 +1752,20 @@ static int __init acpi_ec_ecdt_start(void) if (!boot_ec) return -ENODEV; - /* - * The DSDT EC should have already been started in - * acpi_ec_add(). - */ + /* In case acpi_ec_ecdt_start() is called after acpi_ec_add() */ if (!boot_ec_is_ecdt) return -ENODEV; /* * At this point, the namespace and the GPE is initialized, so * start to find the namespace objects and handle the events. + * + * Note: ec->handle can be valid if this function is called after + * acpi_ec_add(), hence the fast path. */ - if (!acpi_ec_ecdt_get_handle(&handle)) + if (boot_ec->handle != ACPI_ROOT_OBJECT) + handle = boot_ec->handle; + else if (!acpi_ec_ecdt_get_handle(&handle)) return -ENODEV; return acpi_config_boot_ec(boot_ec, handle, true, true); } @@ -2011,8 +2018,8 @@ int __init acpi_ec_init(void) return result; /* Drivers must be started after acpi_ec_query_init() */ - ecdt_fail = acpi_ec_ecdt_start(); dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver); + ecdt_fail = acpi_ec_ecdt_start(); return ecdt_fail && dsdt_fail ? -ENODEV : 0; } -- cgit From 56f77eeb6bcae29871d33b8328c6834340ee8a41 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 11 Aug 2017 14:36:28 +0800 Subject: ACPI / EC: Clean up EC GPE mask flag EC_FLAGS_COMMAND_STORM is actually used to mask GPE during IRQ processing. This patch cleans it up using more readable flag/function names. Signed-off-by: Lv Zheng Tested-by: Tomislav Ivek Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7ea7aa9701e3..fdfae6f3c0b1 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -112,8 +112,7 @@ enum { EC_FLAGS_EVT_HANDLER_INSTALLED, /* _Qxx handlers installed */ EC_FLAGS_STARTED, /* Driver is started */ EC_FLAGS_STOPPED, /* Driver is stopped */ - EC_FLAGS_COMMAND_STORM, /* GPE storms occurred to the - * current command processing */ + EC_FLAGS_GPE_MASKED, /* GPE masked */ }; #define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ @@ -425,19 +424,19 @@ static void acpi_ec_complete_request(struct acpi_ec *ec) wake_up(&ec->wait); } -static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag) +static void acpi_ec_mask_gpe(struct acpi_ec *ec) { - if (!test_bit(flag, &ec->flags)) { + if (!test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) { acpi_ec_disable_gpe(ec, false); ec_dbg_drv("Polling enabled"); - set_bit(flag, &ec->flags); + set_bit(EC_FLAGS_GPE_MASKED, &ec->flags); } } -static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag) +static void acpi_ec_unmask_gpe(struct acpi_ec *ec) { - if (test_bit(flag, &ec->flags)) { - clear_bit(flag, &ec->flags); + if (test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) { + clear_bit(EC_FLAGS_GPE_MASKED, &ec->flags); acpi_ec_enable_gpe(ec, false); ec_dbg_drv("Polling disabled"); } @@ -464,7 +463,7 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec) static void acpi_ec_submit_query(struct acpi_ec *ec) { - acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM); + acpi_ec_mask_gpe(ec); if (!acpi_ec_event_enabled(ec)) return; if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { @@ -480,7 +479,7 @@ static void acpi_ec_complete_query(struct acpi_ec *ec) if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) ec_dbg_evt("Command(%s) unblocked", acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); - acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM); + acpi_ec_unmask_gpe(ec); } static inline void __acpi_ec_enable_event(struct acpi_ec *ec) @@ -700,7 +699,7 @@ err: ++t->irq_count; /* Allow triggering on 0 threshold */ if (t->irq_count == ec_storm_threshold) - acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM); + acpi_ec_mask_gpe(ec); } } out: @@ -798,7 +797,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, spin_lock_irqsave(&ec->lock, tmp); if (t->irq_count == ec_storm_threshold) - acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM); + acpi_ec_unmask_gpe(ec); ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command)); ec->curr = NULL; /* Disable GPE for command processing (IBF=0/OBF=1) */ -- cgit From 0ed780e316f48e38b9dc33d783440da7a22c044d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 15 Aug 2017 10:46:30 +0100 Subject: ACPI / processor: make function acpi_processor_check_duplicates() static The function acpi_processor_check_duplicates() is local to the source and does not need to be in global scope, so make it static. Cleans up sparse warnings: symbol 'acpi_processor_check_duplicates' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_processor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index f098e25b6b41..86c10599d9f8 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -670,7 +670,7 @@ err: } -void __init acpi_processor_check_duplicates(void) +static void __init acpi_processor_check_duplicates(void) { /* check the correctness for all processors in ACPI namespace */ acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, -- cgit