From e399037e06beec6d190a302ff5e4fee4aae77c50 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Thu, 19 Nov 2015 11:05:25 +0800 Subject: [PATCH 1/8] ACPI / scan: set status to 0 if _STA failed Some ACPI node's _STA will touch operation region field, since the evaluation of _STA in acpi_bus_type_and_status is very early, the operation region handler is not ready yet. Instead of fail that function and not creating the acpi_device node consequently, set status to 0 so that later when the driver for that device is probing, it can find the acpi_device node and proceed normally. And at that time, the handler for the operation region is ready and its _STA evaluation will succeed, its present status can be checked there. Even there will be no driver using this node later, it doesn't seem hurt to have one more acpi_device node created with status set to 0. This happens on Microsoft Surface 3, where the SPI device node NTRG's _STA touches GPIO fields and the SPI core driver will only enumerate SPI devices from ACPI if the acpi_device node is 1: created; 2: _STA indicates it's present. Note that due to another problem in SPI driver, for NTRG to be actually enumerated, some changes have to be made in the SPI layer, which is addressed by Mika(not send out yet): https://bugzilla.kernel.org/show_bug.cgi?id=104291#c23 Link: https://bugzilla.kernel.org/show_bug.cgi?id=104291 Reported-by: Bastien Nocera Signed-off-by: Aaron Lu Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 78d5f02a073b..ddfed0d407e5 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1461,7 +1461,7 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, *type = ACPI_BUS_TYPE_DEVICE; status = acpi_bus_get_status_handle(handle, sta); if (ACPI_FAILURE(status)) - return -ENODEV; + *sta = 0; break; case ACPI_TYPE_PROCESSOR: *type = ACPI_BUS_TYPE_PROCESSOR; From ca9dc8d42b30e2d766b471fe5ecf0c71fd309c8f Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 25 Nov 2015 21:19:55 +0100 Subject: [PATCH 2/8] ACPI / scan: Fix acpi_bus_id_list bookkeeping acpi_device_add() allocates and adds an element to acpi_bus_id_list (or increments the instance count if the device's HID is already present in the list), but the element is never deleted from the list nor freed. Fix it. Signed-off-by: Lukas Wunner Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ddfed0d407e5..be1fc12a17ee 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -471,10 +471,24 @@ static void acpi_device_release(struct device *dev) static void acpi_device_del(struct acpi_device *device) { + struct acpi_device_bus_id *acpi_device_bus_id; + mutex_lock(&acpi_device_lock); if (device->parent) list_del(&device->node); + list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) + if (!strcmp(acpi_device_bus_id->bus_id, + acpi_device_hid(device))) { + if (acpi_device_bus_id->instance_no > 0) + acpi_device_bus_id->instance_no--; + else { + list_del(&acpi_device_bus_id->node); + kfree(acpi_device_bus_id); + } + break; + } + list_del(&device->wakeup_list); mutex_unlock(&acpi_device_lock); From 2d12b6b381ba059d5f92798f5ea739672a2f5fcf Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 25 Nov 2015 21:19:55 +0100 Subject: [PATCH 3/8] ACPI / utils: Add acpi_dev_present() There's an idiom in use by 7 Linux drivers to detect the presence of a particular ACPI HID by walking the namespace with acpi_get_devices(). The callback passed to acpi_get_devices() is mostly identical across the drivers, leading to lots of duplicate code. Add acpi_dev_present(), the ACPI equivalent to pci_dev_present(), allowing us to deduplicate all that boilerplate in the drivers. Signed-off-by: Lukas Wunner Reviewed-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki --- drivers/acpi/internal.h | 8 ++++++++ drivers/acpi/scan.c | 8 +------- drivers/acpi/utils.c | 31 +++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 2 ++ 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 11d87bf67e73..60bda0d2cf9a 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -86,6 +86,14 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) +extern struct list_head acpi_bus_id_list; + +struct acpi_device_bus_id{ + char bus_id[15]; + unsigned int instance_no; + struct list_head node; +}; + int acpi_device_add(struct acpi_device *device, void (*release)(struct device *)); void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index be1fc12a17ee..407a3760e8de 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -39,7 +39,7 @@ static const char *dummy_hid = "device"; static LIST_HEAD(acpi_dep_list); static DEFINE_MUTEX(acpi_dep_list_lock); -static LIST_HEAD(acpi_bus_id_list); +LIST_HEAD(acpi_bus_id_list); static DEFINE_MUTEX(acpi_scan_lock); static LIST_HEAD(acpi_scan_handlers_list); DEFINE_MUTEX(acpi_device_lock); @@ -52,12 +52,6 @@ struct acpi_dep_data { acpi_handle slave; }; -struct acpi_device_bus_id{ - char bus_id[15]; - unsigned int instance_no; - struct list_head node; -}; - void acpi_scan_lock_acquire(void) { mutex_lock(&acpi_scan_lock); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 475c9079bf85..f2f9873bb5c3 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -29,6 +29,7 @@ #include #include "internal.h" +#include "sleep.h" #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME("utils"); @@ -709,6 +710,36 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs) } EXPORT_SYMBOL(acpi_check_dsm); +/** + * acpi_dev_present - Detect presence of a given ACPI device in the system. + * @hid: Hardware ID of the device. + * + * Return %true if the device was present at the moment of invocation. + * Note that if the device is pluggable, it may since have disappeared. + * + * For this function to work, acpi_bus_scan() must have been executed + * which happens in the subsys_initcall() subsection. Hence, do not + * call from a subsys_initcall() or earlier (use acpi_get_devices() + * instead). Calling from module_init() is fine (which is synonymous + * with device_initcall()). + */ +bool acpi_dev_present(const char *hid) +{ + struct acpi_device_bus_id *acpi_device_bus_id; + bool found = false; + + mutex_lock(&acpi_device_lock); + list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) + if (!strcmp(acpi_device_bus_id->bus_id, hid)) { + found = true; + break; + } + mutex_unlock(&acpi_device_lock); + + return found; +} +EXPORT_SYMBOL(acpi_dev_present); + /* * acpi_backlight= handling, this is done here rather then in video_detect.c * because __setup cannot be used in modules. diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index ad0a5ff3d4cd..0fe7babf9c24 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -87,6 +87,8 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, int rev, int func, .package.elements = (eles) \ } +bool acpi_dev_present(const char *hid); + #ifdef CONFIG_ACPI #include From cd7f84c02825cfca6cc86826395167479bdc1a05 Mon Sep 17 00:00:00 2001 From: Ken Xue Date: Wed, 9 Dec 2015 16:17:30 +0800 Subject: [PATCH 4/8] ACPI / PM: Support D3 COLD device in old BIOS for ZPODD D3cold is only regarded as valid if the "_PR3" object is present for the given device after the commit 20dacb71ad28 ("ACPI/PM: Rework device power management to follow ACPI 6"). But some old BIOS only defined "_PS3" for the D3COLD device, such as ZPODD device. And old kernel also believes the device with "_PS3" is a D3COLD device. So, add some logics for supporting D3 COLD device with old BIOS which is compatible with earlier ACPI spec and kernel behavior. Link: http://marc.info/?l=linux-acpi&m=144946938709759&w=2 Signed-off-by: Ken Xue Reported-and-tested-by: Gang Long Signed-off-by: Rafael J. Wysocki --- include/acpi/acpi_bus.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index ad0a5ff3d4cd..9894b752cbb1 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -631,7 +631,9 @@ static inline bool acpi_device_can_wakeup(struct acpi_device *adev) static inline bool acpi_device_can_poweroff(struct acpi_device *adev) { - return adev->power.states[ACPI_STATE_D3_COLD].flags.valid; + return adev->power.states[ACPI_STATE_D3_COLD].flags.valid || + ((acpi_gbl_FADT.header.revision < 6) && + adev->power.states[ACPI_STATE_D3_HOT].flags.explicit_set); } #else /* CONFIG_ACPI */ From 50fe763cc8fa00bef9ff78e58645dbfdcaa998da Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 15 Dec 2015 08:37:39 -0800 Subject: [PATCH 5/8] ACPI / bus: Tidy up _OSC error spacing The whitespace in _OSC error reports is weird. Improve it. Acked-by: Bjorn Helgaas Signed-off-by: Andy Lutomirski Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a212cefae524..2177ef0b16e4 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -182,12 +182,12 @@ static void acpi_print_osc_error(acpi_handle handle, if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) printk(KERN_DEBUG "%s\n", error); else { - printk(KERN_DEBUG "%s:%s\n", (char *)buffer.pointer, error); + printk(KERN_DEBUG "%s: %s\n", (char *)buffer.pointer, error); kfree(buffer.pointer); } - printk(KERN_DEBUG"_OSC request data:"); + printk(KERN_DEBUG "_OSC request data:"); for (i = 0; i < context->cap.length; i += sizeof(u32)) - printk("%x ", *((u32 *)(context->cap.pointer + i))); + printk(" %x", *((u32 *)(context->cap.pointer + i))); printk("\n"); } From 76c599bcab26795b0669694e1e32a78274cb901b Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 15 Dec 2015 08:37:40 -0800 Subject: [PATCH 6/8] ACPI / bus: Show _OSC UUID when _OSC fails When _OSC fails and especially when it fails due to an invalid UUID, it's helpful to show the UUID that we tried. Acked-by: Bjorn Helgaas Signed-off-by: Andy Lutomirski Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2177ef0b16e4..fcfdf6cbc6a8 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -180,9 +180,10 @@ static void acpi_print_osc_error(acpi_handle handle, int i; if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) - printk(KERN_DEBUG "%s\n", error); + printk(KERN_DEBUG "%s: %s\n", context->uuid_str, error); else { - printk(KERN_DEBUG "%s: %s\n", (char *)buffer.pointer, error); + printk(KERN_DEBUG "%s (%s): %s\n", + (char *)buffer.pointer, context->uuid_str, error); kfree(buffer.pointer); } printk(KERN_DEBUG "_OSC request data:"); From 9d128ed17c672b1dffde4a328e9b3ee26d87a8f0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 2 Jan 2016 03:10:29 +0100 Subject: [PATCH 7/8] ACPI / OSL: Add kerneldoc comments to memory mapping functions Add kerneldoc comments to acpi_os_map_iomem() and acpi_os_unmap_iomem() and explain why the latter needs the __ref annotation in one of them (as suggested by Mathias Krause). Signed-off-by: Rafael J. Wysocki Acked-by: Mathias Krause --- drivers/acpi/osl.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 32d684af0ec7..d0ecf4efd79d 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -364,6 +364,19 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr) iounmap(vaddr); } +/** + * acpi_os_map_iomem - Get a virtual address for a given physical address range. + * @phys: Start of the physical address range to map. + * @size: Size of the physical address range to map. + * + * Look up the given physical address range in the list of existing ACPI memory + * mappings. If found, get a reference to it and return a pointer to it (its + * virtual address). If not found, map it, add it to that list and return a + * pointer to it. + * + * During early init (when acpi_gbl_permanent_mmap has not been set yet) this + * routine simply calls __acpi_map_table() to get the job done. + */ void __iomem *__init_refok acpi_os_map_iomem(acpi_physical_address phys, acpi_size size) { @@ -439,6 +452,20 @@ static void acpi_os_map_cleanup(struct acpi_ioremap *map) } } +/** + * acpi_os_unmap_iomem - Drop a memory mapping reference. + * @virt: Start of the address range to drop a reference to. + * @size: Size of the address range to drop a reference to. + * + * Look up the given virtual address range in the list of existing ACPI memory + * mappings, drop a reference to it and unmap it if there are no more active + * references to it. + * + * During early init (when acpi_gbl_permanent_mmap has not been set yet) this + * routine simply calls __acpi_unmap_table() to get the job done. Since + * __acpi_unmap_table() is an __init function, the __ref annotation is needed + * here. + */ void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size) { struct acpi_ioremap *map; From edc345d88462c78cd43d44e38efc9cadae4266f1 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 1 Jan 2016 22:52:15 +0100 Subject: [PATCH 8/8] ACPI: Fix white space in a structure definition Add a missing space in the definition of struct acpi_device_bus_id. Signed-off-by: Lukas Wunner [ rjw: Subject and changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 60bda0d2cf9a..1e6833a5cd44 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -88,7 +88,7 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); extern struct list_head acpi_bus_id_list; -struct acpi_device_bus_id{ +struct acpi_device_bus_id { char bus_id[15]; unsigned int instance_no; struct list_head node;