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 = { diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index ec94b09bb747..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; @@ -407,40 +412,29 @@ 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; - - 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(data), event, 0); } 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, adev); + 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) { mutex_lock(&isolated_cpus_lock); + acpi_pad_teardown = true; 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[] = { diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index e8880a2113cb..f93e877f87f6 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, }; @@ -1494,10 +1492,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 +1524,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 */ @@ -1923,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); @@ -1939,18 +1960,23 @@ 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) +static void acpi_video_bus_free(void *data) { - struct acpi_video_device *dev, *next; + struct acpi_video_bus *video = data; - 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); + video->device->driver_data = NULL; + kfree(video); +} - return 0; +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) @@ -1978,7 +2004,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 +2015,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 " @@ -2001,6 +2028,13 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, if (!video) return -ENOMEM; + 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. @@ -2015,20 +2049,17 @@ 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) - goto err_free_video; + return error; 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 @@ -2040,10 +2071,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. @@ -2059,53 +2086,25 @@ 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); - if (error) - goto err_del; + mutex_lock(&video_list_lock); + list_add_tail(&video->entry, &video_bus_head); + mutex_unlock(&video_list_lock); - error = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + 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) + return error; + + error = devm_add_action_or_reset(dev, acpi_video_bus_remove_notify_handler, + video); + if (error) + return error; + + return devm_acpi_install_notify_handler(dev, ACPI_DEVICE_NOTIFY, acpi_video_bus_notify, video); - if (error) - goto err_remove; - - return 0; - -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); -err_put_video: - acpi_video_bus_put_devices(video); - kfree(video->attached_array); -err_free_video: - kfree(video); - device->driver_data = NULL; - - 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); - - 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; } static int __init is_i740(struct pci_dev *dev) 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 */ 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/drivers/acpi/hed.c b/drivers/acpi/hed.c index 060e8d670f5d..48562f53d3ab 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); @@ -50,33 +50,24 @@ 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_handle) + if (hed_present) return -EINVAL; - hed_handle = device->handle; - 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) - 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); - - acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, - acpi_hed_notify); - hed_handle = NULL; + hed_present = false; } static struct platform_driver acpi_hed_driver = { 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; 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, 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 *);