Merge branch 'acpi-driver'

Merge updates of core ACPI device drivers for 7.2-rc1:

 - Fix multiple issues related to probe, removal and missing NVDIMM
   device notifications in the ACPI NFIT driver (Rafael Wysocki)

 - Add support for devres-based management of ACPI notify handlers to
   the ACPI core (Rafael Wysocki)

 - Switch multiple core ACPI device drivers (including the ACPI PAD,
   ACPI video bus, ACPI HED, ACPI thermal zone, ACPI AC, ACPI battery,
   and ACPI NFIT drivers) over to using devres-based resource management
   during probe (Rafael Wysocki)

 - Replace mutex_lock/unlock() with guard()/scoped_guard() in the ACPI
   PMIC driver (Maxwell Doose)

 - Fix message kref handling in the dead device path of the ACPI IPMI
   address space handler (Yuho Choi)

 - Use sysfs_emit() in idlecpus_show() in the ACPI processor aggregator
   device (PAD) driver (Yury Norov)

 - Clean up device_id_scheme initialization in the ACPI video bus driver
   (Jean-Ralph Aviles)

* acpi-driver: (26 commits)
  ACPI: IPMI: Fix message kref handling on dead device
  ACPI: NFIT: core: Fix possible deadlock and missing notifications
  ACPI: NFIT: core: Eliminate redundant local variable
  ACPI: NFIT: core: Fix acpi_nfit_init() error cleanup
  ACPI: NFIT: core: Fix possible NULL pointer dereference
  ACPI: bus: Clean up devm_acpi_install_notify_handler()
  ACPI: PAD: Use sysfs_emit() in idlecpus_show()
  ACPI: video: Do not initialise device_id_scheme directly
  ACPI: video: Switch over to devres-based resource management
  ACPI: video: Use devm for video->entry and backlight cleanup
  ACPI: video: Use devm action for freeing video devices
  ACPI: video: Use devm action for video bus object cleanup
  ACPI: video: Rearrange probe and remove code
  ACPI: video: Reduce the number of auxiliary device dereferences
  ACPI: PAD: Switch over to devres-based resource management
  ACPI: PAD: Fix teardown ordering in acpi_pad_remove()
  ACPI: PAD: Pass struct device pointer to acpi_pad_notify()
  ACPI: PAD: Rearrange acpi_pad_notify()
  ACPI: thermal: Switch over to devres-based resource management
  ACPI: HED: Switch over to devres-based resource management
  ...
This commit is contained in:
Rafael J. Wysocki 2026-06-11 15:17:57 +02:00
commit 9a0d10fed1
11 changed files with 325 additions and 266 deletions

View File

@ -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 = {

View File

@ -550,7 +550,6 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
return AE_TYPE;
}
acpi_ipmi_msg_get(tx_msg);
mutex_lock(&driver_data.ipmi_lock);
/* Do not add a tx_msg that can not be flushed. */
if (ipmi_device->dead) {
@ -558,6 +557,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
ipmi_msg_release(tx_msg);
return AE_NOT_EXIST;
}
acpi_ipmi_msg_get(tx_msg);
spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags);
list_add_tail(&tx_msg->head, &ipmi_device->tx_msg_list);
spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags);

View File

@ -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;
@ -334,8 +336,8 @@ static ssize_t idlecpus_store(struct device *dev,
static ssize_t idlecpus_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return cpumap_print_to_pagebuf(false, buf,
to_cpumask(pad_busy_cpus_bits));
return sysfs_emit(buf, "%*pb\n",
cpumask_pr_args(to_cpumask(pad_busy_cpus_bits)));
}
static DEVICE_ATTR_RW(idlecpus);
@ -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[] = {

View File

@ -63,7 +63,7 @@ MODULE_PARM_DESC(hw_changes_brightness,
* Whether the struct acpi_video_device_attrib::device_id_scheme bit should be
* assumed even if not actually set.
*/
static bool device_id_scheme = false;
static bool device_id_scheme;
module_param(device_id_scheme, bool, 0444);
static int only_lcd;
@ -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)

View File

@ -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 */

View File

@ -679,6 +679,73 @@ void acpi_dev_remove_notify_handler(struct acpi_device *adev,
}
EXPORT_SYMBOL_GPL(acpi_dev_remove_notify_handler);
struct acpi_notify_handler_devres {
struct acpi_device *adev;
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(dr->adev, 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\n");
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->adev = adev;
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

View File

@ -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 = {

View File

@ -56,6 +56,8 @@ MODULE_PARM_DESC(force_labels, "Opt-in to labels despite missing methods");
LIST_HEAD(acpi_descs);
DEFINE_MUTEX(acpi_desc_lock);
DEFINE_MUTEX(acpi_notify_lock);
static struct workqueue_struct *nfit_wq;
struct nfit_table_prev {
@ -1680,7 +1682,6 @@ static struct nvdimm *acpi_nfit_dimm_by_handle(struct acpi_nfit_desc *acpi_desc,
void __acpi_nvdimm_notify(struct device *dev, u32 event)
{
struct nfit_mem *nfit_mem;
struct acpi_nfit_desc *acpi_desc;
dev_dbg(dev->parent, "%s: event: %d\n", dev_name(dev),
event);
@ -1691,12 +1692,11 @@ void __acpi_nvdimm_notify(struct device *dev, u32 event)
return;
}
acpi_desc = dev_get_drvdata(dev->parent);
if (!acpi_desc)
if (!dev_get_drvdata(dev->parent))
return;
/*
* If we successfully retrieved acpi_desc, then we know nfit_mem data
* If the parent's driver data pointer is not NULL, then nfit_mem data
* is still valid.
*/
nfit_mem = dev_get_drvdata(dev);
@ -1710,9 +1710,15 @@ static void acpi_nvdimm_notify(acpi_handle handle, u32 event, void *data)
struct acpi_device *adev = data;
struct device *dev = &adev->dev;
device_lock(dev->parent);
/*
* Locking is needed here for synchronization with driver probe and
* removal and the parent's driver data pointer is NULL when teardown
* is in progress (while the parent here is expected to be the ACPI
* companion of the platform device used for driver binding).
*/
guard(mutex)(&acpi_notify_lock);
__acpi_nvdimm_notify(dev, event);
device_unlock(dev->parent);
}
static bool acpi_nvdimm_has_method(struct acpi_device *adev, char *method)
@ -3069,6 +3075,8 @@ static void acpi_nfit_unregister(void *data)
struct acpi_nfit_desc *acpi_desc = data;
nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
/* The nvdimm_bus object may have been freed, so clear the pointer. */
acpi_desc->nvdimm_bus = NULL;
}
int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz)
@ -3156,11 +3164,10 @@ EXPORT_SYMBOL_GPL(acpi_nfit_init);
static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc)
{
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
struct device *dev = acpi_desc->dev;
/* Bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */
device_lock(dev);
device_unlock(dev);
/* Bounce the notify lock to flush acpi_nfit_probe / acpi_nfit_notify */
mutex_lock(&acpi_notify_lock);
mutex_unlock(&acpi_notify_lock);
/* Bounce the init_mutex to complete initial registration */
mutex_lock(&acpi_desc->init_mutex);
@ -3292,24 +3299,26 @@ static void acpi_nfit_put_table(void *table)
static void acpi_nfit_notify(acpi_handle handle, u32 event, void *data)
{
struct device *dev = data;
struct acpi_device *adev = ACPI_COMPANION(dev);
device_lock(dev);
__acpi_nfit_notify(dev, handle, event);
device_unlock(dev);
}
/*
* Locking is needed here for synchronization with driver probe and
* removal and the ACPI companion's driver data pointer is NULL when
* teardown is in progress.
*/
guard(mutex)(&acpi_notify_lock);
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);
if (dev_get_drvdata(&adev->dev))
__acpi_nfit_notify(dev, handle, event);
}
void acpi_nfit_shutdown(void *data)
{
struct acpi_nfit_desc *acpi_desc = data;
struct device *bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus);
struct device *bus_dev;
if (!acpi_desc || !acpi_desc->nvdimm_bus)
return;
/*
* Destruct under acpi_desc_lock so that nfit_handle_mce does not
@ -3324,6 +3333,7 @@ void acpi_nfit_shutdown(void *data)
mutex_unlock(&acpi_desc->init_mutex);
cancel_delayed_work_sync(&acpi_desc->dwork);
bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus);
/*
* Bounce the nvdimm bus lock to make sure any in-flight
* acpi_nfit_ars_rescan() submissions have had a chance to
@ -3341,23 +3351,20 @@ static int acpi_nfit_probe(struct platform_device *pdev)
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_nfit_desc *acpi_desc;
struct device *dev = &pdev->dev;
struct acpi_device *adev = ACPI_COMPANION(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;
/*
* Prevent acpi_nfit_notify() from progressing until the probe is
* complete in case there is a concurrent event to process.
*/
guard(mutex)(&acpi_notify_lock);
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;
@ -3371,6 +3378,11 @@ static int acpi_nfit_probe(struct platform_device *pdev)
* data in the format of a series of NFIT Structures.
*/
dev_dbg(dev, "failed to find NFIT at startup\n");
/*
* Let acpi_nfit_update_notify() run in case it will need to
* allocate the acpi_desc object.
*/
dev_set_drvdata(&adev->dev, dev);
return 0;
}
@ -3405,10 +3417,28 @@ static int acpi_nfit_probe(struct platform_device *pdev)
+ sizeof(struct acpi_table_nfit),
sz - sizeof(struct acpi_table_nfit));
if (rc)
if (rc) {
acpi_nfit_shutdown(acpi_desc);
return rc;
}
return devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc);
/*
* Let notify handlers operate (the actual value of the ACPI companion's
* driver data pointer does not matter here so long as it is not NULL).
*/
dev_set_drvdata(&adev->dev, dev);
return 0;
}
static void acpi_nfit_remove(struct platform_device *pdev)
{
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
guard(mutex)(&acpi_notify_lock);
/* Make notify handlers bail out early going forward. */
dev_set_drvdata(&adev->dev, NULL);
acpi_nfit_shutdown(platform_get_drvdata(pdev));
}
static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle)
@ -3460,6 +3490,9 @@ static void acpi_nfit_uc_error_notify(struct device *dev, acpi_handle handle)
{
struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev);
if (!acpi_desc)
return;
if (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON)
acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_LONG);
else
@ -3489,6 +3522,7 @@ MODULE_DEVICE_TABLE(acpi, acpi_nfit_ids);
static struct platform_driver acpi_nfit_driver = {
.probe = acpi_nfit_probe,
.remove = acpi_nfit_remove,
.driver = {
.name = "acpi-nfit",
.acpi_match_table = acpi_nfit_ids,

View File

@ -67,14 +67,12 @@ static acpi_status intel_pmic_power_handler(u32 function,
if (result == -ENOENT)
return AE_BAD_PARAMETER;
mutex_lock(&opregion->lock);
guard(mutex)(&opregion->lock);
result = function == ACPI_READ ?
d->get_power(regmap, reg, bit, value64) :
d->update_power(regmap, reg, bit, *value64 == 1);
mutex_unlock(&opregion->lock);
return result ? AE_ERROR : AE_OK;
}
@ -182,19 +180,16 @@ static acpi_status intel_pmic_thermal_handler(u32 function,
if (result == -ENOENT)
return AE_BAD_PARAMETER;
mutex_lock(&opregion->lock);
if (pmic_thermal_is_temp(address))
result = pmic_thermal_temp(opregion, reg, function, value64);
else if (pmic_thermal_is_aux(address))
result = pmic_thermal_aux(opregion, reg, function, value64);
else if (pmic_thermal_is_pen(address))
result = pmic_thermal_pen(opregion, reg, bit,
function, value64);
else
result = -EINVAL;
mutex_unlock(&opregion->lock);
scoped_guard(mutex, &opregion->lock) {
if (pmic_thermal_is_temp(address))
result = pmic_thermal_temp(opregion, reg, function, value64);
else if (pmic_thermal_is_aux(address))
result = pmic_thermal_aux(opregion, reg, function, value64);
else if (pmic_thermal_is_pen(address))
result = pmic_thermal_pen(opregion, reg, bit, function, value64);
else
result = -EINVAL;
}
if (result < 0) {
if (result == -EINVAL)
@ -354,13 +349,15 @@ int intel_soc_pmic_exec_mipi_pmic_seq_element(u16 i2c_address, u32 reg_address,
d = intel_pmic_opregion->data;
mutex_lock(&intel_pmic_opregion->lock);
guard(mutex)(&intel_pmic_opregion->lock);
if (d->exec_mipi_pmic_seq_element) {
ret = d->exec_mipi_pmic_seq_element(intel_pmic_opregion->regmap,
return d->exec_mipi_pmic_seq_element(intel_pmic_opregion->regmap,
i2c_address, reg_address,
value, mask);
} else if (d->pmic_i2c_address) {
}
if (d->pmic_i2c_address) {
if (i2c_address == d->pmic_i2c_address) {
ret = regmap_update_bits(intel_pmic_opregion->regmap,
reg_address, mask, value);
@ -376,8 +373,6 @@ int intel_soc_pmic_exec_mipi_pmic_seq_element(u16 i2c_address, u32 reg_address,
ret = -EOPNOTSUPP;
}
mutex_unlock(&intel_pmic_opregion->lock);
return ret;
}
EXPORT_SYMBOL_GPL(intel_soc_pmic_exec_mipi_pmic_seq_element);

View File

@ -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,

View File

@ -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 *);