From 5b6a8f1445bc86e221da85bb67f389c3ab6d2037 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 16 Nov 2021 21:06:17 +0100 Subject: [PATCH 01/11] ACPI: PM: Emit debug messages when enabling/disabling wakeup power Print additional debug messages when enabling and disabling wakeup power for an ACPI device object to facilitate more fine-grained debugging of problems in that area. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/power.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 5dcb02ededbc..7945e60f9b6a 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -716,6 +716,9 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) mutex_lock(&acpi_device_lock); + dev_dbg(&dev->dev, "Enabling wakeup power (count %d)\n", + dev->wakeup.prepare_count); + if (dev->wakeup.prepare_count++) goto out; @@ -734,8 +737,11 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) if (err) { acpi_power_off_list(&dev->wakeup.resources); dev->wakeup.prepare_count = 0; + goto out; } + dev_dbg(&dev->dev, "Wakeup power enabled\n"); + out: mutex_unlock(&acpi_device_lock); return err; @@ -757,6 +763,9 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) mutex_lock(&acpi_device_lock); + dev_dbg(&dev->dev, "Disabling wakeup power (count %d)\n", + dev->wakeup.prepare_count); + /* Do nothing if wakeup power has not been enabled for this device. */ if (dev->wakeup.prepare_count <= 0) goto out; @@ -782,8 +791,11 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) if (err) { dev_err(&dev->dev, "Cannot turn off wakeup power resources\n"); dev->wakeup.flags.valid = 0; + goto out; } + dev_dbg(&dev->dev, "Wakeup power disabled\n"); + out: mutex_unlock(&acpi_device_lock); return err; From e38f9ff63e6d403f8e52302d223e3c5c110872ee Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 26 Oct 2021 20:57:31 +0200 Subject: [PATCH 02/11] ACPI: scan: Do not add device IDs from _CID if _HID is not valid Section 6.1.2 of ACPI 6.4 explicitly requires _HID to be present for _CID to be defined, so don't add device IDs from _CID to the device IDs list of a device if _HID is not valid. Link: https://uefi.org/specs/ACPI/6.4/06_Device_Configuration/Device_Configuration.html#cid-compatible-id Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Reviewed-by: Hans de Goede --- drivers/acpi/scan.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2c80765670bc..5991dddbc9ce 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1340,11 +1340,11 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, if (info->valid & ACPI_VALID_HID) { acpi_add_id(pnp, info->hardware_id.string); pnp->type.platform_id = 1; - } - if (info->valid & ACPI_VALID_CID) { - cid_list = &info->compatible_id_list; - for (i = 0; i < cid_list->count; i++) - acpi_add_id(pnp, cid_list->ids[i].string); + if (info->valid & ACPI_VALID_CID) { + cid_list = &info->compatible_id_list; + for (i = 0; i < cid_list->count; i++) + acpi_add_id(pnp, cid_list->ids[i].string); + } } if (info->valid & ACPI_VALID_ADR) { pnp->bus_address = info->address; From 53d01e2016d77ff647fb2056c39c67df18ee86bf Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Mon, 6 Dec 2021 15:29:52 +0300 Subject: [PATCH 03/11] ACPI: PM: Avoid CPU cache flush when entering S4 According to ACPI 6.4, Section 16.2, the CPU cache flushing is required on entering to S1, S2, and S3. No need to flush the caches during hibernation (S4). Signed-off-by: Kirill A. Shutemov [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index eaa47753b758..5bcf82fcb5f3 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -903,8 +903,6 @@ static int acpi_hibernation_enter(void) { acpi_status status = AE_OK; - ACPI_FLUSH_CPU_CACHE(); - /* This shouldn't return. If it returns, we have a problem */ status = acpi_enter_sleep_state(ACPI_STATE_S4); /* Reprogram control registers */ From e3c963c498871e0d4b2eceb32e2b989493838ccc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 3 Dec 2021 17:36:20 +0100 Subject: [PATCH 04/11] ACPI: scan: Introduce acpi_fetch_acpi_dev() Introduce acpi_fetch_acpi_dev() as a more reasonable replacement for acpi_bus_get_device() and modify the code in scan.c to use it instead of the latter. No expected functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg Reviewed-by: Hans de Goede --- drivers/acpi/scan.c | 34 ++++++++++++++++++++++++---------- include/acpi/acpi_bus.h | 1 + 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5991dddbc9ce..a9adcda39d40 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -135,12 +135,12 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, void **ret_p) { - struct acpi_device *device = NULL; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_device_physical_node *pn; bool second_pass = (bool)data; acpi_status status = AE_OK; - if (acpi_bus_get_device(handle, &device)) + if (!device) return AE_OK; if (device->handler && !device->handler->hotplug.enabled) { @@ -180,10 +180,10 @@ static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data, void **ret_p) { - struct acpi_device *device = NULL; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_device_physical_node *pn; - if (acpi_bus_get_device(handle, &device)) + if (!device) return AE_OK; mutex_lock(&device->physical_node_lock); @@ -599,6 +599,19 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) } EXPORT_SYMBOL(acpi_bus_get_device); +/** + * acpi_fetch_acpi_dev - Retrieve ACPI device object. + * @handle: ACPI handle associated with the requested ACPI device object. + * + * Return a pointer to the ACPI device object associated with @handle, if + * present, or NULL otherwise. + */ +struct acpi_device *acpi_fetch_acpi_dev(acpi_handle handle) +{ + return handle_to_device(handle, NULL); +} +EXPORT_SYMBOL_GPL(acpi_fetch_acpi_dev); + static void get_acpi_device(void *dev) { acpi_dev_get(dev); @@ -799,7 +812,7 @@ static const char * const acpi_ignore_dep_ids[] = { static struct acpi_device *acpi_bus_get_parent(acpi_handle handle) { - struct acpi_device *device = NULL; + struct acpi_device *device; acpi_status status; /* @@ -814,7 +827,9 @@ static struct acpi_device *acpi_bus_get_parent(acpi_handle handle) status = acpi_get_parent(handle, &handle); if (ACPI_FAILURE(status)) return status == AE_NULL_ENTRY ? NULL : acpi_root; - } while (acpi_bus_get_device(handle, &device)); + + device = acpi_fetch_acpi_dev(handle); + } while (!device); return device; } @@ -2003,11 +2018,10 @@ static bool acpi_bus_scan_second_pass; static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, struct acpi_device **adev_p) { - struct acpi_device *device = NULL; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); acpi_object_type acpi_type; int type; - acpi_bus_get_device(handle, &device); if (device) goto out; @@ -2548,8 +2562,8 @@ int __init acpi_scan_init(void) if (result) goto out; - result = acpi_bus_get_device(ACPI_ROOT_OBJECT, &acpi_root); - if (result) + acpi_root = acpi_fetch_acpi_dev(ACPI_ROOT_OBJECT); + if (!acpi_root) goto out; /* Fixed feature devices do not exist on HW-reduced platform */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 480f9207a4c6..17f700c9a4f9 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -505,6 +505,7 @@ extern int unregister_acpi_notifier(struct notifier_block *); */ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device); +struct acpi_device *acpi_fetch_acpi_dev(acpi_handle handle); acpi_status acpi_bus_get_status_handle(acpi_handle handle, unsigned long long *sta); int acpi_bus_get_status(struct acpi_device *device); From 99ece713773bfa17fdb4ee2a1fb3b7bee82e4b1a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 3 Dec 2021 17:37:10 +0100 Subject: [PATCH 05/11] ACPI: Use acpi_fetch_acpi_dev() instead of acpi_bus_get_device() Modify the ACPI code to use acpi_fetch_acpi_dev() instead of acpi_bus_get_device() where applicable. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg Reviewed-by: Hans de Goede --- drivers/acpi/acpi_video.c | 5 ++--- drivers/acpi/device_pm.c | 31 +++++++++++++------------------ drivers/acpi/dock.c | 3 +-- drivers/acpi/pci_link.c | 12 ++++-------- drivers/acpi/pci_root.c | 10 ++++------ drivers/acpi/power.c | 7 +++---- drivers/acpi/processor_driver.c | 10 +++++++--- drivers/acpi/processor_idle.c | 2 +- drivers/acpi/property.c | 11 +++++------ drivers/acpi/resource.c | 4 ++-- drivers/acpi/thermal.c | 9 ++++----- drivers/acpi/video_detect.c | 6 ++---- drivers/acpi/x86/s2idle.c | 4 ++-- 13 files changed, 50 insertions(+), 64 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 42ede059728c..990ff5b0aeb8 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1733,13 +1733,12 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context, { struct acpi_device *device = context; struct acpi_device *sibling; - int result; if (handle == device->handle) return AE_CTRL_TERMINATE; - result = acpi_bus_get_device(handle, &sibling); - if (result) + sibling = acpi_fetch_acpi_dev(handle); + if (!sibling) return AE_OK; if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME)) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 19b33c028f35..cc6c97e7dcae 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -285,14 +285,12 @@ EXPORT_SYMBOL(acpi_device_set_power); int acpi_bus_set_power(acpi_handle handle, int state) { - struct acpi_device *device; - int result; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); - result = acpi_bus_get_device(handle, &device); - if (result) - return result; + if (device) + return acpi_device_set_power(device, state); - return acpi_device_set_power(device, state); + return -ENODEV; } EXPORT_SYMBOL(acpi_bus_set_power); @@ -410,21 +408,20 @@ EXPORT_SYMBOL_GPL(acpi_device_update_power); int acpi_bus_update_power(acpi_handle handle, int *state_p) { - struct acpi_device *device; - int result; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); - result = acpi_bus_get_device(handle, &device); - return result ? result : acpi_device_update_power(device, state_p); + if (device) + return acpi_device_update_power(device, state_p); + + return -ENODEV; } EXPORT_SYMBOL_GPL(acpi_bus_update_power); bool acpi_bus_power_manageable(acpi_handle handle) { - struct acpi_device *device; - int result; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); - result = acpi_bus_get_device(handle, &device); - return result ? false : device->flags.power_manageable; + return device && device->flags.power_manageable; } EXPORT_SYMBOL(acpi_bus_power_manageable); @@ -543,11 +540,9 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev) bool acpi_bus_can_wakeup(acpi_handle handle) { - struct acpi_device *device; - int result; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); - result = acpi_bus_get_device(handle, &device); - return result ? false : device->wakeup.flags.valid; + return device && device->wakeup.flags.valid; } EXPORT_SYMBOL(acpi_bus_can_wakeup); diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c8e9b962e18c..a89bdbe00184 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -489,9 +489,8 @@ static ssize_t docked_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dock_station *dock_station = dev->platform_data; - struct acpi_device *adev = NULL; + struct acpi_device *adev = acpi_fetch_acpi_dev(dock_station->handle); - acpi_bus_get_device(dock_station->handle, &adev); return sysfs_emit(buf, "%u\n", acpi_device_enumerated(adev)); } static DEVICE_ATTR_RO(docked); diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index cb7b900d9466..d54fb8e54671 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -606,12 +606,10 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link) int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, int *polarity, char **name) { - int result; - struct acpi_device *device; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_pci_link *link; - result = acpi_bus_get_device(handle, &device); - if (result) { + if (!device) { acpi_handle_err(handle, "Invalid link device\n"); return -1; } @@ -658,12 +656,10 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, */ int acpi_pci_link_free_irq(acpi_handle handle) { - struct acpi_device *device; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_pci_link *link; - acpi_status result; - result = acpi_bus_get_device(handle, &device); - if (result) { + if (!device) { acpi_handle_err(handle, "Invalid link device\n"); return -1; } diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index ab2f7dfb0c44..41a8fef06534 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -67,11 +67,10 @@ static struct acpi_scan_handler pci_root_handler = { */ int acpi_is_root_bridge(acpi_handle handle) { + struct acpi_device *device = acpi_fetch_acpi_dev(handle); int ret; - struct acpi_device *device; - ret = acpi_bus_get_device(handle, &device); - if (ret) + if (!device) return 0; ret = acpi_match_device_ids(device, root_device_ids); @@ -215,11 +214,10 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) { + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_pci_root *root; - struct acpi_device *device; - if (acpi_bus_get_device(handle, &device) || - acpi_match_device_ids(device, root_device_ids)) + if (!device || acpi_match_device_ids(device, root_device_ids)) return NULL; root = acpi_driver_data(device); diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 5dcb02ededbc..7e50bbfff1e0 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -81,9 +81,9 @@ struct acpi_power_resource *to_power_resource(struct acpi_device *device) static struct acpi_power_resource *acpi_power_get_context(acpi_handle handle) { - struct acpi_device *device; + struct acpi_device *device = acpi_fetch_acpi_dev(handle); - if (acpi_bus_get_device(handle, &device)) + if (!device) return NULL; return to_power_resource(device); @@ -916,15 +916,14 @@ static void acpi_power_add_resource_to_list(struct acpi_power_resource *resource struct acpi_device *acpi_add_power_resource(acpi_handle handle) { + struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_power_resource *resource; - struct acpi_device *device = NULL; union acpi_object acpi_object; struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object }; acpi_status status; u8 state_dummy; int result; - acpi_bus_get_device(handle, &device); if (device) return device; diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 77541f939be3..368a9edefd0c 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -98,8 +98,13 @@ static int acpi_soft_cpu_online(unsigned int cpu) struct acpi_processor *pr = per_cpu(processors, cpu); struct acpi_device *device; - if (!pr || acpi_bus_get_device(pr->handle, &device)) + if (!pr) return 0; + + device = acpi_fetch_acpi_dev(pr->handle); + if (!device) + return 0; + /* * CPU got physically hotplugged and onlined for the first time: * Initialize missing things. @@ -125,9 +130,8 @@ static int acpi_soft_cpu_online(unsigned int cpu) static int acpi_soft_cpu_dead(unsigned int cpu) { struct acpi_processor *pr = per_cpu(processors, cpu); - struct acpi_device *device; - if (!pr || acpi_bus_get_device(pr->handle, &device)) + if (!pr || !acpi_fetch_acpi_dev(pr->handle)) return 0; acpi_processor_reevaluate_tstate(pr, true); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 76ef1bcc8848..ef17b95e5f37 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1101,7 +1101,7 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr) status = acpi_get_parent(handle, &pr_ahandle); while (ACPI_SUCCESS(status)) { - acpi_bus_get_device(pr_ahandle, &d); + d = acpi_fetch_acpi_dev(pr_ahandle); handle = pr_ahandle; if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID)) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index e312ebaed8db..86987f903eb1 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -687,9 +687,9 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, if (index) return -EINVAL; - ret = acpi_bus_get_device(obj->reference.handle, &device); - if (ret) - return ret == -ENODEV ? -EINVAL : ret; + device = acpi_fetch_acpi_dev(obj->reference.handle); + if (!device) + return -EINVAL; args->fwnode = acpi_fwnode_handle(device); args->nargs = 0; @@ -719,9 +719,8 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, if (element->type == ACPI_TYPE_LOCAL_REFERENCE) { struct fwnode_handle *ref_fwnode; - ret = acpi_bus_get_device(element->reference.handle, - &device); - if (ret) + device = acpi_fetch_acpi_dev(element->reference.handle); + if (!device) return -EINVAL; nargs = 0; diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 3c25ce8c95ba..c2d494784425 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -791,9 +791,9 @@ static acpi_status acpi_res_consumer_cb(acpi_handle handle, u32 depth, { struct resource *res = context; struct acpi_device **consumer = (struct acpi_device **) ret; - struct acpi_device *adev; + struct acpi_device *adev = acpi_fetch_acpi_dev(handle); - if (acpi_bus_get_device(handle, &adev)) + if (!adev) return AE_OK; if (acpi_dev_consumes_res(adev, res)) { diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 95105db642b9..75cda1315235 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -697,7 +697,6 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, struct acpi_device *device = cdev->devdata; struct acpi_thermal *tz = thermal->devdata; struct acpi_device *dev; - acpi_status status; acpi_handle handle; int i; int j; @@ -715,8 +714,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, for (i = 0; i < tz->trips.passive.devices.count; i++) { handle = tz->trips.passive.devices.handles[i]; - status = acpi_bus_get_device(handle, &dev); - if (ACPI_FAILURE(status) || dev != device) + dev = acpi_fetch_acpi_dev(handle); + if (dev != device) continue; if (bind) result = @@ -741,8 +740,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, j < tz->trips.active[i].devices.count; j++) { handle = tz->trips.active[i].devices.handles[j]; - status = acpi_bus_get_device(handle, &dev); - if (ACPI_FAILURE(status) || dev != device) + dev = acpi_fetch_acpi_dev(handle); + if (dev != device) continue; if (bind) result = thermal_zone_bind_cooling_device diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 068e393ea0c6..4f64713e9917 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -59,18 +59,16 @@ static void acpi_video_parse_cmdline(void) static acpi_status find_video(acpi_handle handle, u32 lvl, void *context, void **rv) { + struct acpi_device *acpi_dev = acpi_fetch_acpi_dev(handle); long *cap = context; struct pci_dev *dev; - struct acpi_device *acpi_dev; static const struct acpi_device_id video_ids[] = { {ACPI_VIDEO_HID, 0}, {"", 0}, }; - if (acpi_bus_get_device(handle, &acpi_dev)) - return AE_OK; - if (!acpi_match_device_ids(acpi_dev, video_ids)) { + if (acpi_dev && !acpi_match_device_ids(acpi_dev, video_ids)) { dev = acpi_get_pci_dev(handle); if (!dev) return AE_OK; diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 1c48358b43ba..abc06e7f89d8 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -293,9 +293,9 @@ static void lpi_check_constraints(void) for (i = 0; i < lpi_constraints_table_size; ++i) { acpi_handle handle = lpi_constraints_table[i].handle; - struct acpi_device *adev; + struct acpi_device *adev = acpi_fetch_acpi_dev(handle); - if (!handle || acpi_bus_get_device(handle, &adev)) + if (!adev) continue; acpi_handle_debug(handle, From 3c89857a66ef15bcf54c8fd255a1fd70dbc823a6 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Thu, 9 Dec 2021 16:08:02 +0300 Subject: [PATCH 06/11] ACPI: PM: Remove redundant cache flushing ACPICA code takes care about cache flushing on S1/S2/S3 in acpi_hw_extended_sleep() and acpi_hw_legacy_sleep(). acpi_suspend_enter() calls into ACPICA code via acpi_enter_sleep_state() for S1 or x86_acpi_suspend_lowlevel() for S3. acpi_sleep_prepare() call tree: __acpi_pm_prepare() acpi_pm_prepare() acpi_suspend_ops::prepare_late() acpi_hibernation_ops::pre_snapshot() acpi_hibernation_ops::prepare() acpi_suspend_begin_old() acpi_suspend_begin_old::begin() acpi_hibernation_begin_old() acpi_hibernation_ops_old::acpi_hibernation_begin_old() acpi_power_off_prepare() pm_power_off_prepare() Hibernation (S4) and Power Off (S5) don't require cache flushing, so the only interesting callsites are acpi_suspend_ops::prepare_late() and acpi_suspend_begin_old::begin(). Both of them have cache flush on ->enter() operation in acpi_suspend_enter(). Remove redundant ACPI_FLUSH_CPU_CACHE() in acpi_sleep_prepare() and acpi_suspend_enter(). Signed-off-by: Kirill A. Shutemov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 5bcf82fcb5f3..4b8454f26ca1 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -73,7 +73,6 @@ static int acpi_sleep_prepare(u32 acpi_state) acpi_set_waking_vector(acpi_wakeup_address); } - ACPI_FLUSH_CPU_CACHE(); #endif pr_info("Preparing to enter system sleep state S%d\n", acpi_state); acpi_enable_wakeup_devices(acpi_state); @@ -566,8 +565,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) u32 acpi_state = acpi_target_sleep_state; int error; - ACPI_FLUSH_CPU_CACHE(); - trace_suspend_resume(TPS("acpi_suspend"), acpi_state, true); switch (acpi_state) { case ACPI_STATE_S1: From 843438deebe247fcf7e4d3dd5655c9df4b5412fd Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 23 Dec 2021 10:28:56 +0800 Subject: [PATCH 07/11] PCI/ACPI: Fix acpi_pci_osc_control_set() kernel-doc comment Add the description of @support and remove @req in acpi_pci_osc_control_set() kernel-doc comment to remove warnings found by running scripts/kernel-doc, which is caused by using 'make W=1'. drivers/acpi/pci_root.c:337: warning: Excess function parameter 'req' description in 'acpi_pci_osc_control_set' drivers/acpi/pci_root.c:337: warning: Function parameter or member 'support' not described in 'acpi_pci_osc_control_set' Reported-by: Abaci Robot Fixes: 6bc779ee05d4 ("PCI/ACPI: Check for _OSC support in acpi_pci_osc_control_set()") Signed-off-by: Yang Li Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index ab2f7dfb0c44..b0f19f3fc798 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -324,7 +324,7 @@ EXPORT_SYMBOL_GPL(acpi_get_pci_dev); * acpi_pci_osc_control_set - Request control of PCI root _OSC features. * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex). * @mask: Mask of _OSC bits to request control of, place to store control mask. - * @req: Mask of _OSC bits the control of is essential to the caller. + * @support: _OSC supported capability. * * Run _OSC query for @mask and if that is successful, compare the returned * mask of control bits with @req. If all of the @req bits are set in the From f85196bdd5a50da74670250564740fc852b3c239 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 30 Dec 2021 12:57:47 +0100 Subject: [PATCH 08/11] ACPI: scan: Create platform device for BCM4752 and LNV4752 ACPI nodes BCM4752 and LNV4752 ACPI nodes describe a Broadcom 4752 GPS module attached to an UART of the system. The GPS modules talk a custom protocol which only works with a closed- source Android gpsd daemon which knows this protocol. The ACPI nodes also describe GPIOs to turn the GPS on/off these are handled by the net/rfkill/rfkill-gpio.c code. This handling predates the addition of enumeration of ACPI instantiated serdevs to the kernel and was broken by that addition, because the ACPI scan code now no longer instantiates platform_device-s for these nodes. Rename the i2c_multi_instantiate_ids HID list to ignore_serial_bus_ids and add the BCM4752 and LNV4752 HIDs, so that rfkill-gpio gets a platform_device to bind to again; and so that a tty cdev for gpsd gets created for these. Fixes: e361d1f85855 ("ACPI / scan: Fix enumeration for special UART devices") Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index a9adcda39d40..4dd3a9efcd0f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1710,6 +1710,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) { struct list_head resource_list; bool is_serial_bus_slave = false; + static const struct acpi_device_id ignore_serial_bus_ids[] = { /* * These devices have multiple I2cSerialBus resources and an i2c-client * must be instantiated for each, each with its own i2c_device_id. @@ -1718,11 +1719,18 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) * drivers/platform/x86/i2c-multi-instantiate.c driver, which knows * which i2c_device_id to use for each resource. */ - static const struct acpi_device_id i2c_multi_instantiate_ids[] = { {"BSG1160", }, {"BSG2150", }, {"INT33FE", }, {"INT3515", }, + /* + * HIDs of device with an UartSerialBusV2 resource for which userspace + * expects a regular tty cdev to be created (instead of the in kernel + * serdev) and which have a kernel driver which expects a platform_dev + * such as the rfkill-gpio driver. + */ + {"BCM4752", }, + {"LNV4752", }, {} }; @@ -1736,8 +1744,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) fwnode_property_present(&device->fwnode, "baud"))) return true; - /* Instantiate a pdev for the i2c-multi-instantiate drv to bind to */ - if (!acpi_match_device_ids(device, i2c_multi_instantiate_ids)) + if (!acpi_match_device_ids(device, ignore_serial_bus_ids)) return false; INIT_LIST_HEAD(&resource_list); From 35f9e773bb883a1be87410570f92c8c438e0478b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 30 Dec 2021 15:17:20 +0100 Subject: [PATCH 09/11] ACPI / x86: Add acpi_quirk_skip_[i2c_client|serdev]_enumeration() helpers x86 ACPI boards which ship with only Android as their factory image usually declare a whole bunch of bogus I2C devs in their ACPI tables and sometimes there are issues with serdev devices on these boards too, e.g. the resource points to the wrong serdev_controller. Instantiating I2C / serdev devs for these bogus devs causes various issues, e.g. GPIO/IRQ resource conflicts because sometimes drivers do bind to them. The Android x86 kernel fork shipped on these devices has some special code to remove the bogus I2C clients (and serdevs are ignored completely). Introduce acpi_quirk_skip_i2c_client_enumeration() and acpi_quirk_skip_serdev_enumeration() helpers. Which can be used by the I2C/ serdev code to skip instantiating any I2C or serdev devs on broken boards. These 2 helpers are added to drivers/acpi/x86/utils.c so that the DMI table can be shared between the I2C and serdev code. Note these boards typically do actually have I2C and serdev devices, just different ones then the ones described in their DSDT. The devices which are actually present are manually instantiated by the drivers/platform/x86/x86-android-tablets.c kernel module. The new helpers are only build if CONFIG_X86_ANDROID_TABLETS is enabled, otherwise they are empty stubs to not unnecessarily grow the kernel size. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/x86/utils.c | 111 +++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 16 ++++++ 2 files changed, 127 insertions(+) diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index f22f23933063..ef9ee8bbe4e6 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include "../internal.h" @@ -160,3 +161,113 @@ bool force_storage_d3(void) { return x86_match_cpu(storage_d3_cpu_ids); } + +#if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS) +/* + * x86 ACPI boards which ship with only Android as their factory image usually + * declare a whole bunch of bogus I2C devices in their ACPI tables and sometimes + * there are issues with serdev devices on these boards too, e.g. the resource + * points to the wrong serdev_controller. + * + * Instantiating I2C / serdev devs for these bogus devs causes various issues, + * e.g. GPIO/IRQ resource conflicts because sometimes drivers do bind to them. + * The Android x86 kernel fork shipped on these devices has some special code + * to remove the bogus I2C clients (and AFAICT serdevs are ignored completely). + * + * The acpi_quirk_skip_*_enumeration() functions below are used by the I2C or + * serdev code to skip instantiating any I2C or serdev devs on broken boards. + * + * In case of I2C an exception is made for HIDs on the i2c_acpi_known_good_ids + * list. These are known to always be correct (and in case of the audio-codecs + * the drivers heavily rely on the codec being enumerated through ACPI). + * + * Note these boards typically do actually have I2C and serdev devices, + * just different ones then the ones described in their DSDT. The devices + * which are actually present are manually instantiated by the + * drivers/platform/x86/x86-android-tablets.c kernel module. + */ +#define ACPI_QUIRK_SKIP_I2C_CLIENTS BIT(0) +#define ACPI_QUIRK_UART1_TTY_UART2_SKIP BIT(1) + +static const struct dmi_system_id acpi_skip_serial_bus_enumeration_ids[] = { + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), + }, + .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS | + ACPI_QUIRK_UART1_TTY_UART2_SKIP), + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"), + }, + .driver_data = (void *)ACPI_QUIRK_SKIP_I2C_CLIENTS, + }, + { + /* Whitelabel (sold as various brands) TM800A550L */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are too generic, also match on BIOS version */ + DMI_MATCH(DMI_BIOS_VERSION, "ZY-8-BI-PX4S70VTR400-X423B-005-D"), + }, + .driver_data = (void *)ACPI_QUIRK_SKIP_I2C_CLIENTS, + }, + {} +}; + +static const struct acpi_device_id i2c_acpi_known_good_ids[] = { + { "10EC5640", 0 }, /* RealTek ALC5640 audio codec */ + { "INT33F4", 0 }, /* X-Powers AXP288 PMIC */ + { "INT33FD", 0 }, /* Intel Crystal Cove PMIC */ + { "NPCE69A", 0 }, /* Asus Transformer keyboard dock */ + {} +}; + +bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev) +{ + const struct dmi_system_id *dmi_id; + long quirks; + + dmi_id = dmi_first_match(acpi_skip_serial_bus_enumeration_ids); + if (!dmi_id) + return false; + + quirks = (unsigned long)dmi_id->driver_data; + if (!(quirks & ACPI_QUIRK_SKIP_I2C_CLIENTS)) + return false; + + return acpi_match_device_ids(adev, i2c_acpi_known_good_ids); +} +EXPORT_SYMBOL_GPL(acpi_quirk_skip_i2c_client_enumeration); + +int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) +{ + struct acpi_device *adev = ACPI_COMPANION(controller_parent); + const struct dmi_system_id *dmi_id; + long quirks = 0; + + *skip = false; + + /* !dev_is_platform() to not match on PNP enumerated debug UARTs */ + if (!adev || !adev->pnp.unique_id || !dev_is_platform(controller_parent)) + return 0; + + dmi_id = dmi_first_match(acpi_skip_serial_bus_enumeration_ids); + if (dmi_id) + quirks = (unsigned long)dmi_id->driver_data; + + if (quirks & ACPI_QUIRK_UART1_TTY_UART2_SKIP) { + if (!strcmp(adev->pnp.unique_id, "1")) + return -ENODEV; /* Create tty cdev instead of serdev */ + + if (!strcmp(adev->pnp.unique_id, "2")) + *skip = true; + } + + return 0; +} +EXPORT_SYMBOL_GPL(acpi_quirk_skip_serdev_enumeration); +#endif diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 17f700c9a4f9..88f21780447b 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -622,6 +622,22 @@ static inline bool acpi_device_always_present(struct acpi_device *adev) } #endif +#if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS) +bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev); +int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip); +#else +static inline bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev) +{ + return false; +} +static inline int +acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) +{ + *skip = false; + return 0; +} +#endif + #ifdef CONFIG_PM void acpi_pm_wakeup_event(struct device *dev); acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, From a6e1445c445678f211f0aac79713e8c2fcab0c13 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 30 Dec 2021 15:17:21 +0100 Subject: [PATCH 10/11] i2c: acpi: Do not instantiate I2C-clients on boards with known bogus DSDT entries x86 ACPI devices which ship with only Android as their factory image usually declare a whole bunch of bogus I2C devices in their ACPI tables. Instantiating I2C clients for these bogus devices causes various issues, e.g. GPIO/IRQ resource conflicts because sometimes drivers do bind to them. The Android x86 kernel fork shipped on these devices has some special code to remove these bogus devices, instead of just fixing the DSDT . Use the new acpi_quirk_skip_i2c_client_enumeration() helper to identify known boards / acpi devices with this issue, and skip enumerating these. Note these boards typically do actually have I2C devices, just different ones then the ones described in their DSDT. The devices which are actually present are manually instantiated by the drivers/platform/x86/x86-android-tablets.c kernel module. Reviewed-by: Mika Westerberg Signed-off-by: Hans de Goede Reviewed-by: Wolfram Sang Signed-off-by: Rafael J. Wysocki --- drivers/i2c/i2c-core-acpi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 92c1cc07ed46..15332baa9e85 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -254,6 +254,13 @@ static void i2c_acpi_register_device(struct i2c_adapter *adapter, struct acpi_device *adev, struct i2c_board_info *info) { + /* + * Skip registration on boards where the ACPI tables are + * known to contain bogus I2C devices. + */ + if (acpi_quirk_skip_i2c_client_enumeration(adev)) + return; + adev->power.flags.ignore_parent = true; acpi_device_set_enumerated(adev); From 0890186a965868fa464582d5610c74eeff252c93 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 30 Dec 2021 15:17:22 +0100 Subject: [PATCH 11/11] serdev: Do not instantiate serdevs on boards with known bogus DSDT entries x86 ACPI devices which ship with only Android as their factory image use older kernels which do not yet support ACPI serdev enumeration, as such the serdev information in their ACPI tables is not reliable. For example on the Asus ME176C tablet the serdev describing the Bluetooth HCI points to the serdev_controller connected to the GPS and the other way around. Use the new acpi_quirk_skip_serdev_enumeration() helper to identify known boards with this issue and then either abort adding the serdev controller (creating a tty cdev instead) or only create the controller leaving the instantation of the serdev itself up to platform code. In the case where only the serdev controller is created the necessary serdevs will instead be instantiated by the drivers/platform/x86/x86-android-tablets.c kernel module. Acked-by: Greg Kroah-Hartman Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/tty/serdev/core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index f1324fe99378..92e3433276f8 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -727,10 +727,24 @@ static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, static int acpi_serdev_register_devices(struct serdev_controller *ctrl) { acpi_status status; + bool skip; + int ret; if (!has_acpi_companion(ctrl->dev.parent)) return -ENODEV; + /* + * Skip registration on boards where the ACPI tables are known to + * contain buggy devices. Note serdev_controller_add() must still + * succeed in this case, so that the proper serdev devices can be + * added "manually" later. + */ + ret = acpi_quirk_skip_serdev_enumeration(ctrl->dev.parent, &skip); + if (ret) + return ret; + if (skip) + return 0; + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, SERDEV_ACPI_MAX_SCAN_DEPTH, acpi_serdev_add_device, NULL, ctrl, NULL);