From ca70ce555a1eb8edf5fb1d5575f1fe19c9ae17f4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 15:59:50 +0200 Subject: [PATCH 01/17] ACPI: bus: Introduce devm_acpi_install_notify_handler() Introduce devm_acpi_install_notify_handler() for installing an ACPI notify handler managed by devres that will be removed automatically on driver detach. It installs the notify handler on the device object in the ACPI namespace that corresponds to the owner device's ACPI companion, if present (an error is returned if the owner device doesn't have an ACPI companion). Currently, there is no way to manually remove the notify handler installed by it because none of its users brought on subsequently will need to do that. Signed-off-by: Rafael J. Wysocki [ rjw: Kerneldoc comment refinement ] Link: https://patch.msgid.link/2268031.irdbgypaU6@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 66 +++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 2 ++ 2 files changed, 68 insertions(+) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2ec095e2009e..e9eee0d1f0da 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -679,6 +679,72 @@ void acpi_dev_remove_notify_handler(struct acpi_device *adev, } EXPORT_SYMBOL_GPL(acpi_dev_remove_notify_handler); +struct acpi_notify_handler_devres { + acpi_notify_handler handler; + u32 handler_type; +}; + +static void devm_acpi_notify_handler_release(struct device *dev, void *res) +{ + struct acpi_notify_handler_devres *dr = res; + + acpi_dev_remove_notify_handler(ACPI_COMPANION(dev), dr->handler_type, + dr->handler); +} + +/** + * devm_acpi_install_notify_handler - Install an ACPI notify handler for a + * managed device + * @dev: Device to install a notify handler for + * @handler_type: Type of the notify handler + * @handler: Handler function to install + * @context: Data passed back to the handler function + * + * This function performs the same function as acpi_dev_install_notify_handler() + * called for the ACPI companion of @dev with the same @handler_type, @handler, + * and @context arguments, but the ACPI notify handler installed by it will be + * automatically removed on driver detach. + * + * Callers should ensure that all resources used by @handler have been allocated + * prior to invoking this function, in which case those resources should be + * devres-managed so that they won't be released before the notify handler + * removal. Otherwise, special synchronization between @handler and the + * management of those resources is required. + * + * When the request fails, an error message is printed. Don't add extra error + * messages at the call sites. + * + * Return: 0 on success or a negative error number. + */ +int devm_acpi_install_notify_handler(struct device *dev, u32 handler_type, + acpi_notify_handler handler, void *context) +{ + struct acpi_notify_handler_devres *dr; + struct acpi_device *adev; + int ret; + + adev = ACPI_COMPANION(dev); + if (!adev) + return dev_err_probe(dev, -ENODEV, "No ACPI companion in %s()\n", __func__); + + dr = devres_alloc(devm_acpi_notify_handler_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + ret = acpi_dev_install_notify_handler(adev, handler_type, handler, context); + if (ret) { + devres_free(dr); + return dev_err_probe(dev, ret, "Failed to install an ACPI notify handler\n"); + } + + dr->handler = handler; + dr->handler_type = handler_type; + devres_add(dev, dr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_acpi_install_notify_handler); + /* Handle events targeting \_SB device (at present only graceful shutdown) */ #define ACPI_SB_NOTIFY_SHUTDOWN_REQUEST 0x81 diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c41d9a7565cf..7e57f9698f7c 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -629,6 +629,8 @@ int acpi_dev_install_notify_handler(struct acpi_device *adev, void acpi_dev_remove_notify_handler(struct acpi_device *adev, u32 handler_type, acpi_notify_handler handler); +int devm_acpi_install_notify_handler(struct device *dev, u32 handler_type, + acpi_notify_handler handler, void *context); extern int acpi_notifier_call_chain(const char *device_class, const char *bus_id, u32 type, u32 data); extern int register_acpi_notifier(struct notifier_block *); From 198541ad53c0d0d891fedea4098f9953a0f566c0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:01:16 +0200 Subject: [PATCH 02/17] ACPI: NFIT: core: Use devm_acpi_install_notify_handler() Now that devm_acpi_install_notify_handler() is available, use it in acpi_nfit_probe() instead of a custom devm action removing an ACPI notify handler installed via acpi_dev_install_notify_handler(). Also drop the explicit ACPI_COMPANION() check against NULL that is not necessary any more becuase devm_acpi_install_notify_handler() carries out an equivalent check internally and use ACPI_HANDLE() to retrieve the platform device's ACPI handle. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3048737.e9J7NaK4W3@rafael.j.wysocki --- drivers/acpi/nfit/core.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 9304ac996d41..5cab62f618c8 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -3298,14 +3298,6 @@ static void acpi_nfit_notify(acpi_handle handle, u32 event, void *data) device_unlock(dev); } -static void acpi_nfit_remove_notify_handler(void *data) -{ - struct acpi_device *adev = data; - - acpi_dev_remove_notify_handler(adev, ACPI_DEVICE_NOTIFY, - acpi_nfit_notify); -} - void acpi_nfit_shutdown(void *data) { struct acpi_nfit_desc *acpi_desc = data; @@ -3342,22 +3334,12 @@ static int acpi_nfit_probe(struct platform_device *pdev) struct acpi_nfit_desc *acpi_desc; struct device *dev = &pdev->dev; struct acpi_table_header *tbl; - struct acpi_device *adev; acpi_status status = AE_OK; acpi_size sz; int rc = 0; - adev = ACPI_COMPANION(&pdev->dev); - if (!adev) - return -ENODEV; - - rc = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY, - acpi_nfit_notify, dev); - if (rc) - return rc; - - rc = devm_add_action_or_reset(dev, acpi_nfit_remove_notify_handler, - adev); + rc = devm_acpi_install_notify_handler(dev, ACPI_DEVICE_NOTIFY, + acpi_nfit_notify, dev); if (rc) return rc; @@ -3388,7 +3370,7 @@ static int acpi_nfit_probe(struct platform_device *pdev) acpi_desc->acpi_header = *tbl; /* Evaluate _FIT and override with that if present */ - status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf); + status = acpi_evaluate_object(ACPI_HANDLE(dev), "_FIT", NULL, &buf); if (ACPI_SUCCESS(status) && buf.length > 0) { union acpi_object *obj = buf.pointer; From 026a7835bfda409661aafd5fcdf6b97878b21dc7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:02:00 +0200 Subject: [PATCH 03/17] ACPI: AC: Switch over to devres-based resource management Use devm_kzalloc() for allocating memory, devm_power_supply_register() for registering a power supply class device and the newly introduced devm_acpi_install_notify_handler() for installing an ACPI notify handler. Note that the code ordering change related to the third of the above modifications does not matter because there is no order dependency between the battery notifier and the ACPI notify handler. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3422377.44csPzL39Z@rafael.j.wysocki --- drivers/acpi/ac.c | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 27f31744f29e..f19d6dd43473 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -193,6 +193,7 @@ static const struct dmi_system_id ac_dmi_table[] __initconst = { static int acpi_ac_probe(struct platform_device *pdev) { struct power_supply_config psy_cfg = {}; + struct device *dev = &pdev->dev; struct acpi_device *adev; struct acpi_ac *ac; int result; @@ -201,7 +202,7 @@ static int acpi_ac_probe(struct platform_device *pdev) if (!adev) return -ENODEV; - ac = kzalloc_obj(struct acpi_ac); + ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL); if (!ac) return -ENOMEM; @@ -211,7 +212,7 @@ static int acpi_ac_probe(struct platform_device *pdev) result = acpi_ac_get_state(ac); if (result) - goto err_release_ac; + return result; psy_cfg.drv_data = ac; @@ -220,33 +221,22 @@ static int acpi_ac_probe(struct platform_device *pdev) ac->charger_desc.properties = ac_props; ac->charger_desc.num_properties = ARRAY_SIZE(ac_props); ac->charger_desc.get_property = get_ac_property; - ac->charger = power_supply_register(&pdev->dev, - &ac->charger_desc, &psy_cfg); - if (IS_ERR(ac->charger)) { - result = PTR_ERR(ac->charger); - goto err_release_ac; - } + ac->charger = devm_power_supply_register(dev, &ac->charger_desc, &psy_cfg); + if (IS_ERR(ac->charger)) + return PTR_ERR(ac->charger); pr_info("AC Adapter [%s] (%s-line)\n", acpi_device_bid(adev), str_on_off(ac->state)); + result = devm_acpi_install_notify_handler(dev, ACPI_ALL_NOTIFY, + acpi_ac_notify, ac); + if (result) + return result; + ac->battery_nb.notifier_call = acpi_ac_battery_notify; register_acpi_notifier(&ac->battery_nb); - result = acpi_dev_install_notify_handler(adev, ACPI_ALL_NOTIFY, - acpi_ac_notify, ac); - if (result) - goto err_unregister; - return 0; - -err_unregister: - power_supply_unregister(ac->charger); - unregister_acpi_notifier(&ac->battery_nb); -err_release_ac: - kfree(ac); - - return result; } #ifdef CONFIG_PM_SLEEP @@ -271,12 +261,7 @@ static void acpi_ac_remove(struct platform_device *pdev) { struct acpi_ac *ac = platform_get_drvdata(pdev); - acpi_dev_remove_notify_handler(ac->device, ACPI_ALL_NOTIFY, - acpi_ac_notify); - power_supply_unregister(ac->charger); unregister_acpi_notifier(&ac->battery_nb); - - kfree(ac); } static struct platform_driver acpi_ac_driver = { From ca50aff41fc3ef006f0e809f455be107eb07b919 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:02:44 +0200 Subject: [PATCH 04/17] ACPI: battery: Switch over to devres-based resource management The ACPI battery driver already uses devm_kzalloc() for allocating memory and devm_mutex_init() for mutex initialization, but it still carries out some manual rollback in acpi_battery_probe(). Switch it over to devres-based resource management completely by making three changes: * Rename acpi_battery_update_retry() to devm_acpi_battery_update_retry(), turn sysfs_battery_cleanup() into a devm action and modify the former to add it. * Add devm_acpi_battery_init_wakeup() for initializing the wakeup source and make it add a custom devm action to automatically remove the wakeup source registered by it. * Make acpi_battery_probe() use devm_acpi_install_notify_handler() that has just been introduced for installing an ACPI notify handler. Note that the code ordering change related to the last of the above changes does not matter because there is no functional dependency between the PM notifier and the wakeup source or the ACPI notify handler. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/10856906.nUPlyArG6x@rafael.j.wysocki --- drivers/acpi/battery.c | 81 ++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index b82dd67d98c9..f5e0eb299610 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -1182,6 +1182,26 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = { {}, }; +static void acpi_battery_wakeup_cleanup(void *data) +{ + device_init_wakeup(data, false); +} + +static int devm_acpi_battery_init_wakeup(struct device *dev) +{ + device_init_wakeup(dev, true); + return devm_add_action_or_reset(dev, acpi_battery_wakeup_cleanup, dev); +} + +static void sysfs_battery_cleanup(void *data) +{ + struct acpi_battery *battery = data; + + guard(mutex)(&battery->update_lock); + + sysfs_remove_battery(battery); +} + /* * Some machines'(E,G Lenovo Z480) ECs are not stable * during boot up and this causes battery driver fails to be @@ -1190,10 +1210,15 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = { * may work. So add retry code here and 20ms sleep between * every retries. */ -static int acpi_battery_update_retry(struct acpi_battery *battery) +static int devm_acpi_battery_update_retry(struct device *dev, + struct acpi_battery *battery) { int retry, ret; + ret = devm_add_action(dev, sysfs_battery_cleanup, battery); + if (ret) + return ret; + guard(mutex)(&battery->update_lock); for (retry = 5; retry; retry--) { @@ -1206,27 +1231,21 @@ static int acpi_battery_update_retry(struct acpi_battery *battery) return ret; } -static void sysfs_battery_cleanup(struct acpi_battery *battery) -{ - guard(mutex)(&battery->update_lock); - - sysfs_remove_battery(battery); -} - static int acpi_battery_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct acpi_battery *battery; struct acpi_device *device; int result; - device = ACPI_COMPANION(&pdev->dev); + device = ACPI_COMPANION(dev); if (!device) return -ENODEV; if (device->dep_unmet) return -EPROBE_DEFER; - battery = devm_kzalloc(&pdev->dev, sizeof(*battery), GFP_KERNEL); + battery = devm_kzalloc(dev, sizeof(*battery), GFP_KERNEL); if (!battery) return -ENOMEM; @@ -1235,54 +1254,38 @@ static int acpi_battery_probe(struct platform_device *pdev) battery->phys_dev = &pdev->dev; battery->device = device; - result = devm_mutex_init(&pdev->dev, &battery->update_lock); + result = devm_mutex_init(dev, &battery->update_lock); if (result) return result; if (acpi_has_method(battery->device->handle, "_BIX")) set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); - result = acpi_battery_update_retry(battery); + result = devm_acpi_battery_update_retry(dev, battery); if (result) - goto fail; + return result; pr_info("Slot [%s] (battery %s)\n", acpi_device_bid(device), device->status.battery_present ? "present" : "absent"); + result = devm_acpi_battery_init_wakeup(dev); + if (result) + return result; + + result = devm_acpi_install_notify_handler(dev, ACPI_ALL_NOTIFY, + acpi_battery_notify, battery); + if (result) + return result; + battery->pm_nb.notifier_call = battery_notify; - result = register_pm_notifier(&battery->pm_nb); - if (result) - goto fail; - - device_init_wakeup(&pdev->dev, true); - - result = acpi_dev_install_notify_handler(device, ACPI_ALL_NOTIFY, - acpi_battery_notify, battery); - if (result) - goto fail_pm; - - return 0; - -fail_pm: - device_init_wakeup(&pdev->dev, false); - unregister_pm_notifier(&battery->pm_nb); -fail: - sysfs_battery_cleanup(battery); - - return result; + return register_pm_notifier(&battery->pm_nb); } static void acpi_battery_remove(struct platform_device *pdev) { struct acpi_battery *battery = platform_get_drvdata(pdev); - acpi_dev_remove_notify_handler(battery->device, ACPI_ALL_NOTIFY, - acpi_battery_notify); - - device_init_wakeup(&pdev->dev, false); unregister_pm_notifier(&battery->pm_nb); - - sysfs_battery_cleanup(battery); } /* this is needed to learn about changes made in suspended state */ From 97e6c73c6b79396c93dc117f9dbe37a6869e1b7f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:03:23 +0200 Subject: [PATCH 05/17] ACPI: HED: Refine guarding against adding a second instance There can be only one ACPI hardware event device (HED) in use at a time, so acpi_hed_probe() uses static variable hed_handle for guarding against adding a second HED instance, but there is no reason for that variable to hold an ACPI handle, so change it to a bool one. While at it also set that variable at the end of acpi_hed_probe() to avouid the need to clear it when installing the ACPI notify handler fails. Note that ACPI devices are enumerated sequentially, so there's no need for additional locking around the accesses to that variable. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/2042970.PYKUYFuaPT@rafael.j.wysocki --- drivers/acpi/hed.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index 060e8d670f5d..4b5dc95922ea 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -22,7 +22,7 @@ static const struct acpi_device_id acpi_hed_ids[] = { }; MODULE_DEVICE_TABLE(acpi, acpi_hed_ids); -static acpi_handle hed_handle; +static bool hed_present; static BLOCKING_NOTIFIER_HEAD(acpi_hed_notify_list); @@ -58,25 +58,25 @@ static int acpi_hed_probe(struct platform_device *pdev) return -ENODEV; /* Only one hardware error device */ - if (hed_handle) + if (hed_present) return -EINVAL; - hed_handle = device->handle; err = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, acpi_hed_notify, device); if (err) - hed_handle = NULL; + return err; - return err; + hed_present = true; + return 0; } static void acpi_hed_remove(struct platform_device *pdev) { struct acpi_device *device = ACPI_COMPANION(&pdev->dev); + hed_present = false; acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, acpi_hed_notify); - hed_handle = NULL; } static struct platform_driver acpi_hed_driver = { From 3159c5fcdd3a5eae70b45cbdf453d408266f547d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:04:03 +0200 Subject: [PATCH 06/17] ACPI: HED: Switch over to devres-based resource management Use the newly introduced devm_acpi_install_notify_handler() for installing an ACPI notify handler and since that function checks the ACPI companion of the owner device against NULL internally, remove the the explicit ACPI companion check from acpi_hed_probe(). No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/7950702.EvYhyI6sBW@rafael.j.wysocki --- drivers/acpi/hed.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index 4b5dc95922ea..48562f53d3ab 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -50,19 +50,14 @@ static void acpi_hed_notify(acpi_handle handle, u32 event, void *data) static int acpi_hed_probe(struct platform_device *pdev) { - struct acpi_device *device; int err; - device = ACPI_COMPANION(&pdev->dev); - if (!device) - return -ENODEV; - /* Only one hardware error device */ if (hed_present) return -EINVAL; - err = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, - acpi_hed_notify, device); + err = devm_acpi_install_notify_handler(&pdev->dev, ACPI_DEVICE_NOTIFY, + acpi_hed_notify, NULL); if (err) return err; @@ -72,11 +67,7 @@ static int acpi_hed_probe(struct platform_device *pdev) static void acpi_hed_remove(struct platform_device *pdev) { - struct acpi_device *device = ACPI_COMPANION(&pdev->dev); - hed_present = false; - acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, - acpi_hed_notify); } static struct platform_driver acpi_hed_driver = { From d3f13e75bf2c781b23b8fa8320e5ecb3a0b4df2e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:04:45 +0200 Subject: [PATCH 07/17] ACPI: thermal: Switch over to devres-based resource management Switch over the ACPI thermal zone driver to devres-based resource management by making the following changes: * Turn acpi_thermal_zone_free() into a devm action added from acpi_thermal_probe() after allocating the struct acpi_thermal object. * Rename acpi_thermal_unregister_thermal_zone() to acpi_thermal_zone_unregister(), add acpi_thermal_pm_queue flushing to it, and turn it into a devm action added by acpi_thermal_probe() after calling acpi_thermal_register_thermal_zone(). * Use the newly introduced devm_acpi_install_notify_handler() for installing an ACPI notify handler. * Drop acpi_thermal_remove() that is not necessary any more. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3698719.iIbC2pHGDl@rafael.j.wysocki --- drivers/acpi/thermal.c | 53 +++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index dfc7daa809b5..dd7666c176a0 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -655,8 +655,12 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz, return result; } -static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) +static void acpi_thermal_zone_unregister(void *data) { + struct acpi_thermal *tz = data; + + flush_workqueue(acpi_thermal_pm_queue); + thermal_zone_device_disable(tz->thermal_zone); acpi_thermal_zone_sysfs_remove(tz); thermal_zone_device_unregister(tz->thermal_zone); @@ -765,8 +769,9 @@ static void acpi_thermal_check_fn(struct work_struct *work) mutex_unlock(&tz->thermal_check_lock); } -static void acpi_thermal_free_thermal_zone(struct acpi_thermal *tz) +static void acpi_thermal_zone_free(void *data) { + struct acpi_thermal *tz = data; int i; acpi_handle_list_free(&tz->trips.passive.trip.devices); @@ -779,7 +784,8 @@ static void acpi_thermal_free_thermal_zone(struct acpi_thermal *tz) static int acpi_thermal_probe(struct platform_device *pdev) { struct thermal_trip trip_table[ACPI_THERMAL_MAX_NR_TRIPS] = { 0 }; - struct acpi_device *device = ACPI_COMPANION(&pdev->dev); + struct device *dev = &pdev->dev; + struct acpi_device *device = ACPI_COMPANION(dev); struct acpi_thermal_trip *acpi_trip; struct thermal_trip *trip; struct acpi_thermal *tz; @@ -795,6 +801,10 @@ static int acpi_thermal_probe(struct platform_device *pdev) if (!tz) return -ENOMEM; + result = devm_add_action_or_reset(dev, acpi_thermal_zone_free, tz); + if (result) + return result; + platform_set_drvdata(pdev, tz); tz->device = device; @@ -817,7 +827,7 @@ static int acpi_thermal_probe(struct platform_device *pdev) /* Get temperature [_TMP] (required). */ result = acpi_thermal_get_temperature(tz); if (result) - goto free_memory; + return result; /* Determine the default polling frequency [_TZP]. */ if (tzp) @@ -870,7 +880,11 @@ static int acpi_thermal_probe(struct platform_device *pdev) trip - trip_table, passive_delay); if (result) - goto free_memory; + return result; + + result = devm_add_action_or_reset(dev, acpi_thermal_zone_unregister, tz); + if (result) + return result; refcount_set(&tz->thermal_check_count, 3); mutex_init(&tz->thermal_check_lock); @@ -879,32 +893,8 @@ static int acpi_thermal_probe(struct platform_device *pdev) pr_info("Thermal Zone [%s] (%ld C)\n", acpi_device_bid(device), deci_kelvin_to_celsius(tz->temp_dk)); - result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, - acpi_thermal_notify, tz); - if (result) - goto flush_wq; - - return 0; - -flush_wq: - flush_workqueue(acpi_thermal_pm_queue); - acpi_thermal_unregister_thermal_zone(tz); -free_memory: - acpi_thermal_free_thermal_zone(tz); - - return result; -} - -static void acpi_thermal_remove(struct platform_device *pdev) -{ - struct acpi_thermal *tz = platform_get_drvdata(pdev); - - acpi_dev_remove_notify_handler(tz->device, ACPI_DEVICE_NOTIFY, - acpi_thermal_notify); - - flush_workqueue(acpi_thermal_pm_queue); - acpi_thermal_unregister_thermal_zone(tz); - acpi_thermal_free_thermal_zone(tz); + return devm_acpi_install_notify_handler(dev, ACPI_DEVICE_NOTIFY, + acpi_thermal_notify, tz); } #ifdef CONFIG_PM_SLEEP @@ -937,7 +927,6 @@ MODULE_DEVICE_TABLE(acpi, thermal_device_ids); static struct platform_driver acpi_thermal_driver = { .probe = acpi_thermal_probe, - .remove = acpi_thermal_remove, .driver = { .name = "acpi-thermal", .acpi_match_table = thermal_device_ids, From dd32e1966f42417ffad9b64b3837a0bbb0c2d035 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:05:22 +0200 Subject: [PATCH 08/17] ACPI: PAD: Rearrange acpi_pad_notify() Use an if () in acpi_pad_notify() instead of a switch () statement to make the code somewhat easier to follow and reduce its indentation level. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3345485.5fSG56mABF@rafael.j.wysocki --- drivers/acpi/acpi_pad.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index ec94b09bb747..91d32da76f8f 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -409,16 +409,13 @@ static void acpi_pad_notify(acpi_handle handle, u32 event, void *data) { struct acpi_device *adev = data; - switch (event) { - case ACPI_PROCESSOR_AGGREGATOR_NOTIFY: - acpi_pad_handle_notify(handle); - acpi_bus_generate_netlink_event("acpi_pad", - dev_name(&adev->dev), event, 0); - break; - default: + if (event != ACPI_PROCESSOR_AGGREGATOR_NOTIFY) { pr_warn("Unsupported event [0x%x]\n", event); - break; + return; } + + acpi_pad_handle_notify(handle); + acpi_bus_generate_netlink_event("acpi_pad", dev_name(&adev->dev), event, 0); } static int acpi_pad_probe(struct platform_device *pdev) From cf700a6df5ce6505d7b21a0b39bb5b85a7c01f33 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:06:05 +0200 Subject: [PATCH 09/17] ACPI: PAD: Pass struct device pointer to acpi_pad_notify() Use the struct device pointer to the dev member in the struct platform_device object representing the platform device used for driver binding as the last argument of acpi_dev_install_notify_handler() and accordingly update acpi_pad_notify() to pass that pointer directly to dev_name() when generating the netlink event. Since the dev_name() value for an ACPI-enumerated platform device is the same as the dev_name() value for the dev member of its ACPI companion object, as per acpi_create_platform_device(), the above code modification is not expected to cause functionality to change. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/1862521.VLH7GnMWUR@rafael.j.wysocki --- drivers/acpi/acpi_pad.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 91d32da76f8f..b0a6723fb854 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -407,15 +407,13 @@ static void acpi_pad_handle_notify(acpi_handle handle) static void acpi_pad_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_device *adev = data; - if (event != ACPI_PROCESSOR_AGGREGATOR_NOTIFY) { pr_warn("Unsupported event [0x%x]\n", event); return; } acpi_pad_handle_notify(handle); - acpi_bus_generate_netlink_event("acpi_pad", dev_name(&adev->dev), event, 0); + acpi_bus_generate_netlink_event("acpi_pad", dev_name(data), event, 0); } static int acpi_pad_probe(struct platform_device *pdev) @@ -427,7 +425,7 @@ static int acpi_pad_probe(struct platform_device *pdev) return -ENODEV; return acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY, - acpi_pad_notify, adev); + acpi_pad_notify, &pdev->dev); } static void acpi_pad_remove(struct platform_device *pdev) From 5776575d9a7e50e77c45e0ab0271c000496f341d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:06:48 +0200 Subject: [PATCH 10/17] ACPI: PAD: Fix teardown ordering in acpi_pad_remove() The ACPI notify handler installed by acpi_pad_probe() needs to be removed before calling acpi_pad_idle_cpus() in acpi_pad_remove() so it doesn't schedule idle time injection on some CPUs again. Fixes: 8e0af5141ab9 ("ACPI: create Processor Aggregator Device driver") Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/2064153.usQuhbGJ8B@rafael.j.wysocki --- drivers/acpi/acpi_pad.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index b0a6723fb854..48c00ee61ed2 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -430,12 +430,12 @@ static int acpi_pad_probe(struct platform_device *pdev) static void acpi_pad_remove(struct platform_device *pdev) { + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, acpi_pad_notify); + mutex_lock(&isolated_cpus_lock); acpi_pad_idle_cpus(0); mutex_unlock(&isolated_cpus_lock); - - acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), - ACPI_DEVICE_NOTIFY, acpi_pad_notify); } static const struct acpi_device_id pad_device_ids[] = { From 8813d20d32a7a066731d3f3f0f73f325bcd9ae86 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:07:29 +0200 Subject: [PATCH 11/17] ACPI: PAD: Switch over to devres-based resource management Use the newly introduced devm_acpi_install_notify_handler() for installing an ACPI notify handler and since that function checks the ACPI companion of the owner device against NULL internally, remove the the explicit ACPI companion check from acpi_pad_probe(). However, to prevent the notify handler from running acpi_pad_idle_cpus() with the number of idle CPUs greater than zero after acpi_pad_remove() has returned, add a bool static variable for synchronization between the two. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/1964581.CQOukoFCf9@rafael.j.wysocki --- drivers/acpi/acpi_pad.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 48c00ee61ed2..5792f93d3534 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -31,6 +31,8 @@ static DEFINE_MUTEX(isolated_cpus_lock); static DEFINE_MUTEX(round_robin_lock); +static bool acpi_pad_teardown; + static unsigned int power_saving_mwait_eax; static unsigned char tsc_detected_unstable; @@ -359,6 +361,9 @@ static int acpi_pad_pur(acpi_handle handle) union acpi_object *package; int num = -1; + if (unlikely(acpi_pad_teardown)) + return -1; + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PUR", NULL, &buffer))) return num; @@ -418,22 +423,16 @@ static void acpi_pad_notify(acpi_handle handle, u32 event, void *data) static int acpi_pad_probe(struct platform_device *pdev) { - struct acpi_device *adev; + acpi_pad_teardown = false; - adev = ACPI_COMPANION(&pdev->dev); - if (!adev) - return -ENODEV; - - return acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY, - acpi_pad_notify, &pdev->dev); + return devm_acpi_install_notify_handler(&pdev->dev, ACPI_DEVICE_NOTIFY, + acpi_pad_notify, &pdev->dev); } static void acpi_pad_remove(struct platform_device *pdev) { - acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), - ACPI_DEVICE_NOTIFY, acpi_pad_notify); - mutex_lock(&isolated_cpus_lock); + acpi_pad_teardown = true; acpi_pad_idle_cpus(0); mutex_unlock(&isolated_cpus_lock); } From 0849acee2f532d4be3ca2368874ad88b5dab6dca Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:08:16 +0200 Subject: [PATCH 12/17] ACPI: video: Reduce the number of auxiliary device dereferences Store the &aux_dev->dev pointer in a separate local variable in acpi_video_bus_probe() to avoid dereferencing aux_dev many times. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/2707186.Lt9SDvczpP@rafael.j.wysocki --- drivers/acpi/acpi_video.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 05793ddef787..bdc3f4933abf 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1978,7 +1978,8 @@ static bool acpi_video_bus_dev_is_duplicate(struct device *dev) static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, const struct auxiliary_device_id *id_unused) { - struct acpi_device *device = ACPI_COMPANION(&aux_dev->dev); + struct device *dev = &aux_dev->dev; + struct acpi_device *device = ACPI_COMPANION(dev); static DEFINE_MUTEX(probe_lock); struct acpi_video_bus *video; static int instance; @@ -1988,7 +1989,7 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, /* Probe one video bus device at a time in case there are duplicates. */ guard(mutex)(&probe_lock); - if (!allow_duplicates && acpi_video_bus_dev_is_duplicate(&aux_dev->dev)) { + if (!allow_duplicates && acpi_video_bus_dev_is_duplicate(dev)) { pr_info(FW_BUG "Duplicate ACPI video bus devices for the" " same VGA controller, please try module " @@ -2059,7 +2060,7 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, !auto_detect) acpi_video_bus_register_backlight(video); - error = acpi_video_bus_add_notify_handler(video, &aux_dev->dev); + error = acpi_video_bus_add_notify_handler(video, dev); if (error) goto err_del; From 73ae2b1f395802d78929df2f1f1da301468f6df3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:08:51 +0200 Subject: [PATCH 13/17] ACPI: video: Rearrange probe and remove code Rearrange some ACPI video bus probe and remove code so that it is more clear that the probe and removal are carried in reverse orders, which will also facilitate subsequent changes. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/2276683.Mh6RI2rZIc@rafael.j.wysocki --- drivers/acpi/acpi_video.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index bdc3f4933abf..ca2bee967946 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -2002,6 +2002,9 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, if (!video) return -ENOMEM; + video->device = device; + device->driver_data = video; + /* * A hack to fix the duplicate name "VID" problem on T61 and the * duplicate name "VGA" problem on Pa 3553. @@ -2016,9 +2019,6 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, auxiliary_set_drvdata(aux_dev, video); - video->device = device; - device->driver_data = video; - acpi_video_bus_find_cap(video); error = acpi_video_bus_check(video); if (error) @@ -2041,10 +2041,6 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, acpi_device_bid(device), str_yes_no(video->flags.multihead), str_yes_no(video->flags.rom), str_yes_no(video->flags.post)); - mutex_lock(&video_list_lock); - list_add_tail(&video->entry, &video_bus_head); - mutex_unlock(&video_list_lock); - /* * If backlight-type auto-detection is used then a native backlight may * show up later and this may change the result from video to native. @@ -2060,6 +2056,10 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, !auto_detect) acpi_video_bus_register_backlight(video); + mutex_lock(&video_list_lock); + list_add_tail(&video->entry, &video_bus_head); + mutex_unlock(&video_list_lock); + error = acpi_video_bus_add_notify_handler(video, dev); if (error) goto err_del; @@ -2096,15 +2096,15 @@ static void acpi_video_bus_remove(struct auxiliary_device *aux_dev) acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, acpi_video_bus_notify); + acpi_video_bus_remove_notify_handler(video); + mutex_lock(&video_list_lock); list_del(&video->entry); mutex_unlock(&video_list_lock); - - acpi_video_bus_remove_notify_handler(video); acpi_video_bus_unregister_backlight(video); acpi_video_bus_put_devices(video); - kfree(video->attached_array); + kfree(video); device->driver_data = NULL; } From aad090a11389e17cacfbda62b963ddf709e5cc34 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:09:35 +0200 Subject: [PATCH 14/17] ACPI: video: Use devm action for video bus object cleanup Introduce acpi_video_bus_free() for freeing video bus object memory and reversing changes related to it made during ACPI video bus device probe, modify acpi_video_bus_probe() to add acpi_video_bus_free() as a devm action, and remove the code superseded by it from acpi_video_bus_remove(). No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3892168.MHq7AAxBmi@rafael.j.wysocki --- drivers/acpi/acpi_video.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index ca2bee967946..11dd00614f6b 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1953,6 +1953,14 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video) return 0; } +static void acpi_video_bus_free(void *data) +{ + struct acpi_video_bus *video = data; + + video->device->driver_data = NULL; + kfree(video); +} + static int duplicate_dev_check(struct device *sibling, void *data) { struct acpi_video_bus *video; @@ -2005,6 +2013,10 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, video->device = device; device->driver_data = video; + error = devm_add_action_or_reset(dev, acpi_video_bus_free, video); + if (error) + return error; + /* * A hack to fix the duplicate name "VID" problem on T61 and the * duplicate name "VGA" problem on Pa 3553. @@ -2022,7 +2034,7 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, acpi_video_bus_find_cap(video); error = acpi_video_bus_check(video); if (error) - goto err_free_video; + return error; mutex_init(&video->device_list_lock); INIT_LIST_HEAD(&video->video_device_list); @@ -2081,9 +2093,6 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, err_put_video: acpi_video_bus_put_devices(video); kfree(video->attached_array); -err_free_video: - kfree(video); - device->driver_data = NULL; return error; } @@ -2104,9 +2113,6 @@ static void acpi_video_bus_remove(struct auxiliary_device *aux_dev) acpi_video_bus_unregister_backlight(video); acpi_video_bus_put_devices(video); kfree(video->attached_array); - - kfree(video); - device->driver_data = NULL; } static int __init is_i740(struct pci_dev *dev) From 677a3b5333ed80d89fb70f0f5d8db8bd6c916031 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:10:13 +0200 Subject: [PATCH 15/17] ACPI: video: Use devm action for freeing video devices Rename acpi_video_bus_put_devices() to devm_acpi_video_bus_get_devices() and turn acpi_video_bus_put_devices() into a devm action added by it for freeing the video devices allocated by it and the attached_array memory. Accordingly, remove the acpi_video_bus_put_devices() calls and attached_array freeing from acpi_video_bus_remove() and the rollback path in acpi_video_bus_probe(). No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/1932803.atdPhlSkOF@rafael.j.wysocki --- drivers/acpi/acpi_video.c | 53 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 11dd00614f6b..a02eaf13f5d8 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1494,10 +1494,31 @@ int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, } EXPORT_SYMBOL(acpi_video_get_edid); -static int -acpi_video_bus_get_devices(struct acpi_video_bus *video, - struct acpi_device *device) +static void acpi_video_bus_put_devices(void *data) { + struct acpi_video_bus *video = data; + struct acpi_video_device *dev, *next; + + mutex_lock(&video->device_list_lock); + list_for_each_entry_safe(dev, next, &video->video_device_list, entry) { + list_del(&dev->entry); + kfree(dev); + } + mutex_unlock(&video->device_list_lock); + + kfree(video->attached_array); + video->attached_array = NULL; +} + +static int devm_acpi_video_bus_get_devices(struct device *dev, + struct acpi_video_bus *video) +{ + int ret; + + ret = devm_add_action(dev, acpi_video_bus_put_devices, video); + if (ret) + return ret; + /* * There are systems where video module known to work fine regardless * of broken _DOD and ignoring returned value here doesn't cause @@ -1505,7 +1526,8 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video, */ acpi_video_device_enumerate(video); - return acpi_dev_for_each_child(device, acpi_video_bus_get_one_device, video); + return acpi_dev_for_each_child(video->device, + acpi_video_bus_get_one_device, video); } /* acpi_video interface */ @@ -1939,20 +1961,6 @@ static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video) video->input = NULL; } -static int acpi_video_bus_put_devices(struct acpi_video_bus *video) -{ - struct acpi_video_device *dev, *next; - - mutex_lock(&video->device_list_lock); - list_for_each_entry_safe(dev, next, &video->video_device_list, entry) { - list_del(&dev->entry); - kfree(dev); - } - mutex_unlock(&video->device_list_lock); - - return 0; -} - static void acpi_video_bus_free(void *data) { struct acpi_video_bus *video = data; @@ -2039,9 +2047,9 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, mutex_init(&video->device_list_lock); INIT_LIST_HEAD(&video->video_device_list); - error = acpi_video_bus_get_devices(video, device); + error = devm_acpi_video_bus_get_devices(dev, video); if (error) - goto err_put_video; + return error; /* * HP ZBook Fury 16 G10 requires ACPI video's child devices have _PS0 @@ -2090,9 +2098,6 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, list_del(&video->entry); mutex_unlock(&video_list_lock); acpi_video_bus_unregister_backlight(video); -err_put_video: - acpi_video_bus_put_devices(video); - kfree(video->attached_array); return error; } @@ -2111,8 +2116,6 @@ static void acpi_video_bus_remove(struct auxiliary_device *aux_dev) list_del(&video->entry); mutex_unlock(&video_list_lock); acpi_video_bus_unregister_backlight(video); - acpi_video_bus_put_devices(video); - kfree(video->attached_array); } static int __init is_i740(struct pci_dev *dev) From e60407db77294431b8f332626dd3b2a2d5d66d57 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:10:55 +0200 Subject: [PATCH 16/17] ACPI: video: Use devm for video->entry and backlight cleanup Introduce acpi_video_bus_del() for removing the video bus object from the video_bus_head list and unregistering backlight and make acpi_video_bus_probe() add it as a devm action after adding the video bus object to the video_bus_head list. Accordingly, remove the code superseded by it from acpi_video_bus_remove() and from the rollback path in acpi_video_bus_probe(). No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/2279582.Icojqenx9y@rafael.j.wysocki --- drivers/acpi/acpi_video.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index a02eaf13f5d8..e0da168a1df3 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1969,6 +1969,17 @@ static void acpi_video_bus_free(void *data) kfree(video); } +static void acpi_video_bus_del(void *data) +{ + struct acpi_video_bus *video = data; + + mutex_lock(&video_list_lock); + list_del(&video->entry); + mutex_unlock(&video_list_lock); + + acpi_video_bus_unregister_backlight(video); +} + static int duplicate_dev_check(struct device *sibling, void *data) { struct acpi_video_bus *video; @@ -2080,9 +2091,13 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, list_add_tail(&video->entry, &video_bus_head); mutex_unlock(&video_list_lock); + error = devm_add_action_or_reset(dev, acpi_video_bus_del, video); + if (error) + return error; + error = acpi_video_bus_add_notify_handler(video, dev); if (error) - goto err_del; + return error; error = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, acpi_video_bus_notify, video); @@ -2093,11 +2108,6 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, err_remove: acpi_video_bus_remove_notify_handler(video); -err_del: - mutex_lock(&video_list_lock); - list_del(&video->entry); - mutex_unlock(&video_list_lock); - acpi_video_bus_unregister_backlight(video); return error; } @@ -2111,11 +2121,6 @@ static void acpi_video_bus_remove(struct auxiliary_device *aux_dev) acpi_video_bus_notify); acpi_video_bus_remove_notify_handler(video); - - mutex_lock(&video_list_lock); - list_del(&video->entry); - mutex_unlock(&video_list_lock); - acpi_video_bus_unregister_backlight(video); } static int __init is_i740(struct pci_dev *dev) From 0ce680af25aa70ab021d4ba706f2c060285a041a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 21 May 2026 16:11:34 +0200 Subject: [PATCH 17/17] ACPI: video: Switch over to devres-based resource management Turn acpi_video_bus_remove_notify_handler() into a devm action added by acpi_video_bus_probe() after calling acpi_video_bus_add_notify_handler and use the newly introduced devm_acpi_install_notify_handler() to install an ACPI notify handler for the video bus device. This replaces the rollback path remnant in acpi_video_bus_probe() and allows acpi_video_bus_remove() to be dropped altogether. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/2556320.jE0xQCEvom@rafael.j.wysocki --- drivers/acpi/acpi_video.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index e0da168a1df3..e5a0b03f06b3 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -76,7 +76,6 @@ static DEFINE_MUTEX(video_list_lock); static LIST_HEAD(video_bus_head); static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, const struct auxiliary_device_id *id); -static void acpi_video_bus_remove(struct auxiliary_device *aux); static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data); /* @@ -99,7 +98,6 @@ MODULE_DEVICE_TABLE(auxiliary, video_bus_auxiliary_id_table); static struct auxiliary_driver acpi_video_bus = { .probe = acpi_video_bus_probe, - .remove = acpi_video_bus_remove, .id_table = video_bus_auxiliary_id_table, }; @@ -1945,8 +1943,9 @@ static void acpi_video_dev_remove_notify_handler(struct acpi_video_device *dev) } } -static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video) +static void acpi_video_bus_remove_notify_handler(void *data) { + struct acpi_video_bus *video = data; struct acpi_video_device *dev; mutex_lock(&video->device_list_lock); @@ -2099,28 +2098,13 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, if (error) return error; - error = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, - acpi_video_bus_notify, video); + error = devm_add_action_or_reset(dev, acpi_video_bus_remove_notify_handler, + video); if (error) - goto err_remove; + return error; - return 0; - -err_remove: - acpi_video_bus_remove_notify_handler(video); - - return error; -} - -static void acpi_video_bus_remove(struct auxiliary_device *aux_dev) -{ - struct acpi_video_bus *video = auxiliary_get_drvdata(aux_dev); - struct acpi_device *device = ACPI_COMPANION(&aux_dev->dev); - - acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, - acpi_video_bus_notify); - - acpi_video_bus_remove_notify_handler(video); + return devm_acpi_install_notify_handler(dev, ACPI_DEVICE_NOTIFY, + acpi_video_bus_notify, video); } static int __init is_i740(struct pci_dev *dev)