diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2022-07-29 20:58:52 +0300 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2022-07-29 20:58:52 +0300 |
commit | d60b6b0bc00365ab338804213437785d269f777b (patch) | |
tree | e3a56a9fc3e2cd3ebc2301bdd9058a0bc2679270 /drivers | |
parent | 4f4179fcf420873002035cf1941d844c9e0e7cb3 (diff) | |
parent | e6bdbcc764af822ff7172a4a78d437dc433a0c74 (diff) | |
download | linux-d60b6b0bc00365ab338804213437785d269f777b.tar.xz |
Merge branch 'acpi-bus'
Merge ACPI device object management changes for v5.20-rc1.
- Use the facilities provided by the driver core and some additional
helpers to handle the children of a given ACPI device object in
multiple places instead of using the children and node list heads in
struct acpi_device which is error prone (Rafael Wysocki).
- Fix ACPI-related device reference counting issue in the hisi_lpc bus
driver (Yang Yingliang).
- Drop the children and node list heads that are not needed any more
from struct acpi_device (Rafael Wysocki).
- Drop driver member from struct acpi_device (Uwe Kleine-König).
- Drop redundant check from acpi_device_remove() (Uwe Kleine-König).
* acpi-bus:
ACPI: bus: Drop unused list heads from struct acpi_device
hisi_lpc: Use acpi_dev_for_each_child()
bus: hisi_lpc: fix missing platform_device_put() in hisi_lpc_acpi_probe()
ACPI: bus: Drop driver member of struct acpi_device
ACPI: bus: Drop redundant check in acpi_device_remove()
mfd: core: Use acpi_dev_for_each_child()
ACPI / MMC: PM: Unify fixing up device power
soundwire: Use acpi_dev_for_each_child()
platform/x86/thinkpad_acpi: Use acpi_dev_for_each_child()
ACPI: scan: Walk ACPI device's children using driver core
ACPI: bus: Introduce acpi_dev_for_each_child_reverse()
ACPI: video: Use acpi_dev_for_each_child()
ACPI: bus: Export acpi_dev_for_each_child() to modules
ACPI: property: Use acpi_dev_for_each_child() for child lookup
ACPI: container: Use acpi_dev_for_each_child()
USB: ACPI: Replace usb_acpi_find_port() with acpi_find_child_by_adr()
thunderbolt: ACPI: Replace tb_acpi_find_port() with acpi_find_child_by_adr()
ACPI: glue: Introduce acpi_find_child_by_adr()
ACPI: glue: Introduce acpi_dev_has_children()
ACPI: glue: Use acpi_dev_for_each_child()
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/acpi_video.c | 41 | ||||
-rw-r--r-- | drivers/acpi/bus.c | 46 | ||||
-rw-r--r-- | drivers/acpi/container.c | 17 | ||||
-rw-r--r-- | drivers/acpi/device_pm.c | 22 | ||||
-rw-r--r-- | drivers/acpi/device_sysfs.c | 2 | ||||
-rw-r--r-- | drivers/acpi/glue.c | 133 | ||||
-rw-r--r-- | drivers/acpi/property.c | 45 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 70 | ||||
-rw-r--r-- | drivers/bus/hisi_lpc.c | 204 | ||||
-rw-r--r-- | drivers/mfd/mfd-core.c | 31 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-acpi.c | 7 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pci-core.c | 11 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 53 | ||||
-rw-r--r-- | drivers/soundwire/slave.c | 117 | ||||
-rw-r--r-- | drivers/thunderbolt/acpi.c | 29 | ||||
-rw-r--r-- | drivers/usb/core/usb-acpi.c | 18 |
16 files changed, 456 insertions, 390 deletions
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index eaea733b368a..5cbe2196176d 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1150,24 +1150,25 @@ acpi_video_get_device_type(struct acpi_video_bus *video, return 0; } -static int -acpi_video_bus_get_one_device(struct acpi_device *device, - struct acpi_video_bus *video) +static int acpi_video_bus_get_one_device(struct acpi_device *device, void *arg) { - unsigned long long device_id; - int status, device_type; - struct acpi_video_device *data; + struct acpi_video_bus *video = arg; struct acpi_video_device_attrib *attribute; + struct acpi_video_device *data; + unsigned long long device_id; + acpi_status status; + int device_type; - status = - acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); - /* Some device omits _ADR, we skip them instead of fail */ + status = acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); + /* Skip devices without _ADR instead of failing. */ if (ACPI_FAILURE(status)) - return 0; + goto exit; data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL); - if (!data) + if (!data) { + dev_dbg(&device->dev, "Cannot attach\n"); return -ENOMEM; + } strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); @@ -1230,7 +1231,9 @@ acpi_video_bus_get_one_device(struct acpi_device *device, list_add_tail(&data->entry, &video->video_device_list); mutex_unlock(&video->device_list_lock); - return status; +exit: + video->child_count++; + return 0; } /* @@ -1542,9 +1545,6 @@ static int acpi_video_bus_get_devices(struct acpi_video_bus *video, struct acpi_device *device) { - int status = 0; - struct acpi_device *dev; - /* * There are systems where video module known to work fine regardless * of broken _DOD and ignoring returned value here doesn't cause @@ -1552,16 +1552,7 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video, */ acpi_video_device_enumerate(video); - list_for_each_entry(dev, &device->children, node) { - - status = acpi_video_bus_get_one_device(dev, video); - if (status) { - dev_err(&dev->dev, "Can't attach device\n"); - break; - } - video->child_count++; - } - return status; + return acpi_dev_for_each_child(device, acpi_video_bus_get_one_device, video); } /* acpi_video interface */ diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index e2db1bdd9dd2..901b2b7ce88b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -464,7 +464,6 @@ out_free: static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { struct acpi_device *adev; - struct acpi_driver *driver; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; bool hotplug_event = false; @@ -516,10 +515,13 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) if (!adev) goto err; - driver = adev->driver; - if (driver && driver->ops.notify && - (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) - driver->ops.notify(adev, type); + if (adev->dev.driver) { + struct acpi_driver *driver = to_acpi_driver(adev->dev.driver); + + if (driver && driver->ops.notify && + (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) + driver->ops.notify(adev, type); + } if (!hotplug_event) { acpi_bus_put_acpi_device(adev); @@ -538,8 +540,9 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) static void acpi_notify_device(acpi_handle handle, u32 event, void *data) { struct acpi_device *device = data; + struct acpi_driver *acpi_drv = to_acpi_driver(device->dev.driver); - device->driver->ops.notify(device, event); + acpi_drv->ops.notify(device, event); } static void acpi_notify_device_fixed(void *data) @@ -1032,8 +1035,6 @@ static int acpi_device_probe(struct device *dev) if (ret) return ret; - acpi_dev->driver = acpi_drv; - pr_debug("Driver [%s] successfully bound to device [%s]\n", acpi_drv->name, acpi_dev->pnp.bus_id); @@ -1043,7 +1044,6 @@ static int acpi_device_probe(struct device *dev) if (acpi_drv->ops.remove) acpi_drv->ops.remove(acpi_dev); - acpi_dev->driver = NULL; acpi_dev->driver_data = NULL; return ret; } @@ -1059,15 +1059,14 @@ static int acpi_device_probe(struct device *dev) static void acpi_device_remove(struct device *dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); - struct acpi_driver *acpi_drv = acpi_dev->driver; + struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); + + if (acpi_drv->ops.notify) + acpi_device_remove_notify_handler(acpi_dev); + + if (acpi_drv->ops.remove) + acpi_drv->ops.remove(acpi_dev); - if (acpi_drv) { - if (acpi_drv->ops.notify) - acpi_device_remove_notify_handler(acpi_dev); - if (acpi_drv->ops.remove) - acpi_drv->ops.remove(acpi_dev); - } - acpi_dev->driver = NULL; acpi_dev->driver_data = NULL; put_device(dev); @@ -1101,6 +1100,7 @@ static int acpi_dev_for_one_check(struct device *dev, void *context) return adwc->fn(to_acpi_device(dev), adwc->data); } +EXPORT_SYMBOL_GPL(acpi_dev_for_each_child); int acpi_dev_for_each_child(struct acpi_device *adev, int (*fn)(struct acpi_device *, void *), void *data) @@ -1113,6 +1113,18 @@ int acpi_dev_for_each_child(struct acpi_device *adev, return device_for_each_child(&adev->dev, &adwc, acpi_dev_for_one_check); } +int acpi_dev_for_each_child_reverse(struct acpi_device *adev, + int (*fn)(struct acpi_device *, void *), + void *data) +{ + struct acpi_dev_walk_context adwc = { + .fn = fn, + .data = data, + }; + + return device_for_each_child_reverse(&adev->dev, &adwc, acpi_dev_for_one_check); +} + /* -------------------------------------------------------------------------- Initialization/Cleanup -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index ccaa647ac3d4..5b7e3b9ae370 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -23,17 +23,18 @@ static const struct acpi_device_id container_device_ids[] = { #ifdef CONFIG_ACPI_CONTAINER -static int acpi_container_offline(struct container_dev *cdev) +static int check_offline(struct acpi_device *adev, void *not_used) { - struct acpi_device *adev = ACPI_COMPANION(&cdev->dev); - struct acpi_device *child; + if (acpi_scan_is_offline(adev, false)) + return 0; - /* Check all of the dependent devices' physical companions. */ - list_for_each_entry(child, &adev->children, node) - if (!acpi_scan_is_offline(child, false)) - return -EBUSY; + return -EBUSY; +} - return 0; +static int acpi_container_offline(struct container_dev *cdev) +{ + /* Check all of the dependent devices' physical companions. */ + return acpi_dev_for_each_child(ACPI_COMPANION(&cdev->dev), check_offline, NULL); } static void acpi_container_release(struct device *dev) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 130b5f4a50a3..9dce1245689c 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -369,6 +369,28 @@ int acpi_device_fix_up_power(struct acpi_device *device) } EXPORT_SYMBOL_GPL(acpi_device_fix_up_power); +static int fix_up_power_if_applicable(struct acpi_device *adev, void *not_used) +{ + if (adev->status.present && adev->status.enabled) + acpi_device_fix_up_power(adev); + + return 0; +} + +/** + * acpi_device_fix_up_power_extended - Force device and its children into D0. + * @adev: Parent device object whose power state is to be fixed up. + * + * Call acpi_device_fix_up_power() for @adev and its children so long as they + * are reported as present and enabled. + */ +void acpi_device_fix_up_power_extended(struct acpi_device *adev) +{ + acpi_device_fix_up_power(adev); + acpi_dev_for_each_child(adev, fix_up_power_if_applicable, NULL); +} +EXPORT_SYMBOL_GPL(acpi_device_fix_up_power_extended); + int acpi_device_update_power(struct acpi_device *device, int *state_p) { int state; diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index d5d6403ba07b..120873dad2cc 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -376,7 +376,7 @@ eject_store(struct device *d, struct device_attribute *attr, return -EINVAL; if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled) - && !acpi_device->driver) + && !d->driver) return -ENODEV; status = acpi_get_type(acpi_device->handle, ¬_used); diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 8d769114a048..204fe94c7e45 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -77,12 +77,22 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev) #define FIND_CHILD_MIN_SCORE 1 #define FIND_CHILD_MAX_SCORE 2 +static int match_any(struct acpi_device *adev, void *not_used) +{ + return 1; +} + +static bool acpi_dev_has_children(struct acpi_device *adev) +{ + return acpi_dev_for_each_child(adev, match_any, NULL) > 0; +} + static int find_child_checks(struct acpi_device *adev, bool check_children) { unsigned long long sta; acpi_status status; - if (check_children && list_empty(&adev->children)) + if (check_children && !acpi_dev_has_children(adev)) return -ENODEV; status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); @@ -105,54 +115,97 @@ static int find_child_checks(struct acpi_device *adev, bool check_children) return FIND_CHILD_MAX_SCORE; } -struct acpi_device *acpi_find_child_device(struct acpi_device *parent, - u64 address, bool check_children) -{ - struct acpi_device *adev, *ret = NULL; - int ret_score = 0; - - if (!parent) - return NULL; +struct find_child_walk_data { + struct acpi_device *adev; + u64 address; + int score; + bool check_sta; + bool check_children; +}; - list_for_each_entry(adev, &parent->children, node) { - acpi_bus_address addr = acpi_device_adr(adev); - int score; +static int check_one_child(struct acpi_device *adev, void *data) +{ + struct find_child_walk_data *wd = data; + int score; - if (!adev->pnp.type.bus_address || addr != address) - continue; + if (!adev->pnp.type.bus_address || acpi_device_adr(adev) != wd->address) + return 0; - if (!ret) { - /* This is the first matching object. Save it. */ - ret = adev; - continue; - } + if (!wd->adev) { /* - * There is more than one matching device object with the same - * _ADR value. That really is unexpected, so we are kind of - * beyond the scope of the spec here. We have to choose which - * one to return, though. - * - * First, check if the previously found object is good enough - * and return it if so. Second, do the same for the object that - * we've just found. + * This is the first matching object, so save it. If it is not + * necessary to look for any other matching objects, stop the + * search. */ - if (!ret_score) { - ret_score = find_child_checks(ret, check_children); - if (ret_score == FIND_CHILD_MAX_SCORE) - return ret; - } - score = find_child_checks(adev, check_children); - if (score == FIND_CHILD_MAX_SCORE) { - return adev; - } else if (score > ret_score) { - ret = adev; - ret_score = score; - } + wd->adev = adev; + return !(wd->check_sta || wd->check_children); } - return ret; + + /* + * There is more than one matching device object with the same _ADR + * value. That really is unexpected, so we are kind of beyond the scope + * of the spec here. We have to choose which one to return, though. + * + * First, get the score for the previously found object and terminate + * the walk if it is maximum. + */ + if (!wd->score) { + score = find_child_checks(wd->adev, wd->check_children); + if (score == FIND_CHILD_MAX_SCORE) + return 1; + + wd->score = score; + } + /* + * Second, if the object that has just been found has a better score, + * replace the previously found one with it and terminate the walk if + * the new score is maximum. + */ + score = find_child_checks(adev, wd->check_children); + if (score > wd->score) { + wd->adev = adev; + if (score == FIND_CHILD_MAX_SCORE) + return 1; + + wd->score = score; + } + + /* Continue, because there may be better matches. */ + return 0; +} + +static struct acpi_device *acpi_find_child(struct acpi_device *parent, + u64 address, bool check_children, + bool check_sta) +{ + struct find_child_walk_data wd = { + .address = address, + .check_children = check_children, + .check_sta = check_sta, + .adev = NULL, + .score = 0, + }; + + if (parent) + acpi_dev_for_each_child(parent, check_one_child, &wd); + + return wd.adev; +} + +struct acpi_device *acpi_find_child_device(struct acpi_device *parent, + u64 address, bool check_children) +{ + return acpi_find_child(parent, address, check_children, true); } EXPORT_SYMBOL_GPL(acpi_find_child_device); +struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev, + acpi_bus_address adr) +{ + return acpi_find_child(adev, adr, false, false); +} +EXPORT_SYMBOL_GPL(acpi_find_child_by_adr); + static void acpi_physnode_link_name(char *buf, unsigned int node_id) { if (node_id > 0) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index d3173811614e..e764f9ac9cf8 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1012,6 +1012,22 @@ static int acpi_node_prop_read(const struct fwnode_handle *fwnode, propname, proptype, val, nval); } +static int stop_on_next(struct acpi_device *adev, void *data) +{ + struct acpi_device **ret_p = data; + + if (!*ret_p) { + *ret_p = adev; + return 1; + } + + /* Skip until the "previous" object is found. */ + if (*ret_p == adev) + *ret_p = NULL; + + return 0; +} + /** * acpi_get_next_subnode - Return the next child node handle for a fwnode * @fwnode: Firmware node to find the next child node for. @@ -1020,35 +1036,22 @@ static int acpi_node_prop_read(const struct fwnode_handle *fwnode, struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode, struct fwnode_handle *child) { - const struct acpi_device *adev = to_acpi_device_node(fwnode); - const struct list_head *head; - struct list_head *next; + struct acpi_device *adev = to_acpi_device_node(fwnode); if ((!child || is_acpi_device_node(child)) && adev) { - struct acpi_device *child_adev; + struct acpi_device *child_adev = to_acpi_device_node(child); - head = &adev->children; - if (list_empty(head)) - goto nondev; + acpi_dev_for_each_child(adev, stop_on_next, &child_adev); + if (child_adev) + return acpi_fwnode_handle(child_adev); - if (child) { - adev = to_acpi_device_node(child); - next = adev->node.next; - if (next == head) { - child = NULL; - goto nondev; - } - child_adev = list_entry(next, struct acpi_device, node); - } else { - child_adev = list_first_entry(head, struct acpi_device, - node); - } - return acpi_fwnode_handle(child_adev); + child = NULL; } - nondev: if (!child || is_acpi_data_node(child)) { const struct acpi_data_node *data = to_acpi_data_node(fwnode); + const struct list_head *head; + struct list_head *next; struct acpi_data_node *dn; /* diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 762b61f67e6c..b100e6ca9bb4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -334,10 +334,9 @@ static int acpi_scan_device_check(struct acpi_device *adev) return error; } -static int acpi_scan_bus_check(struct acpi_device *adev) +static int acpi_scan_bus_check(struct acpi_device *adev, void *not_used) { struct acpi_scan_handler *handler = adev->handler; - struct acpi_device *child; int error; acpi_bus_get_status(adev); @@ -353,19 +352,14 @@ static int acpi_scan_bus_check(struct acpi_device *adev) dev_warn(&adev->dev, "Namespace scan failure\n"); return error; } - list_for_each_entry(child, &adev->children, node) { - error = acpi_scan_bus_check(child); - if (error) - return error; - } - return 0; + return acpi_dev_for_each_child(adev, acpi_scan_bus_check, NULL); } static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) { switch (type) { case ACPI_NOTIFY_BUS_CHECK: - return acpi_scan_bus_check(adev); + return acpi_scan_bus_check(adev, NULL); case ACPI_NOTIFY_DEVICE_CHECK: return acpi_scan_device_check(adev); case ACPI_NOTIFY_EJECT_REQUEST: @@ -471,8 +465,6 @@ static void acpi_device_del(struct acpi_device *device) struct acpi_device_bus_id *acpi_device_bus_id; mutex_lock(&acpi_device_lock); - if (device->parent) - list_del(&device->node); list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) if (!strcmp(acpi_device_bus_id->bus_id, @@ -488,6 +480,7 @@ static void acpi_device_del(struct acpi_device *device) } list_del(&device->wakeup_list); + mutex_unlock(&acpi_device_lock); acpi_power_add_remove_device(device, false); @@ -680,8 +673,6 @@ static int __acpi_device_add(struct acpi_device *device, * ------- * Link this device to its parent and siblings. */ - INIT_LIST_HEAD(&device->children); - INIT_LIST_HEAD(&device->node); INIT_LIST_HEAD(&device->wakeup_list); INIT_LIST_HEAD(&device->physical_node_list); INIT_LIST_HEAD(&device->del_list); @@ -721,9 +712,6 @@ static int __acpi_device_add(struct acpi_device *device, list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); } - if (device->parent) - list_add_tail(&device->node, &device->parent->children); - if (device->wakeup.flags.valid) list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); @@ -752,9 +740,6 @@ static int __acpi_device_add(struct acpi_device *device, err: mutex_lock(&acpi_device_lock); - if (device->parent) - list_del(&device->node); - list_del(&device->wakeup_list); err_unlock: @@ -2187,9 +2172,8 @@ static int acpi_scan_attach_handler(struct acpi_device *device) return ret; } -static void acpi_bus_attach(struct acpi_device *device, bool first_pass) +static int acpi_bus_attach(struct acpi_device *device, void *first_pass) { - struct acpi_device *child; bool skip = !first_pass && device->flags.visited; acpi_handle ejd; int ret; @@ -2206,7 +2190,7 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass) device->flags.initialized = false; acpi_device_clear_enumerated(device); device->flags.power_manageable = 0; - return; + return 0; } if (device->handler) goto ok; @@ -2224,7 +2208,7 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass) ret = acpi_scan_attach_handler(device); if (ret < 0) - return; + return 0; device->flags.match_driver = true; if (ret > 0 && !device->flags.enumeration_by_parent) { @@ -2234,19 +2218,20 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass) ret = device_attach(&device->dev); if (ret < 0) - return; + return 0; if (device->pnp.type.platform_id || device->flags.enumeration_by_parent) acpi_default_enumeration(device); else acpi_device_set_enumerated(device); - ok: - list_for_each_entry(child, &device->children, node) - acpi_bus_attach(child, first_pass); +ok: + acpi_dev_for_each_child(device, acpi_bus_attach, first_pass); if (!skip && device->handler && device->handler->hotplug.notify_online) device->handler->hotplug.notify_online(device); + + return 0; } static int acpi_dev_get_first_consumer_dev_cb(struct acpi_dep_data *dep, void *data) @@ -2274,7 +2259,7 @@ static void acpi_scan_clear_dep_fn(struct work_struct *work) cdw = container_of(work, struct acpi_scan_clear_dep_work, work); acpi_scan_lock_acquire(); - acpi_bus_attach(cdw->adev, true); + acpi_bus_attach(cdw->adev, (void *)true); acpi_scan_lock_release(); acpi_dev_put(cdw->adev); @@ -2432,7 +2417,7 @@ int acpi_bus_scan(acpi_handle handle) if (!device) return -ENODEV; - acpi_bus_attach(device, true); + acpi_bus_attach(device, (void *)true); if (!acpi_bus_scan_second_pass) return 0; @@ -2446,25 +2431,17 @@ int acpi_bus_scan(acpi_handle handle) acpi_bus_check_add_2, NULL, NULL, (void **)&device); - acpi_bus_attach(device, false); + acpi_bus_attach(device, NULL); return 0; } EXPORT_SYMBOL(acpi_bus_scan); -/** - * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects. - * @adev: Root of the ACPI namespace scope to walk. - * - * Must be called under acpi_scan_lock. - */ -void acpi_bus_trim(struct acpi_device *adev) +static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used) { struct acpi_scan_handler *handler = adev->handler; - struct acpi_device *child; - list_for_each_entry_reverse(child, &adev->children, node) - acpi_bus_trim(child); + acpi_dev_for_each_child_reverse(adev, acpi_bus_trim_one, NULL); adev->flags.match_driver = false; if (handler) { @@ -2482,6 +2459,19 @@ void acpi_bus_trim(struct acpi_device *adev) acpi_device_set_power(adev, ACPI_STATE_D3_COLD); adev->flags.initialized = false; acpi_device_clear_enumerated(adev); + + return 0; +} + +/** + * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects. + * @adev: Root of the ACPI namespace scope to walk. + * + * Must be called under acpi_scan_lock. + */ +void acpi_bus_trim(struct acpi_device *adev) +{ + acpi_bus_trim_one(adev, NULL); } EXPORT_SYMBOL_GPL(acpi_bus_trim); diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c index 378f5d62a991..2e564803e786 100644 --- a/drivers/bus/hisi_lpc.c +++ b/drivers/bus/hisi_lpc.c @@ -379,7 +379,7 @@ static void hisi_lpc_acpi_fixup_child_resource(struct device *hostdev, /* * hisi_lpc_acpi_set_io_res - set the resources for a child - * @child: the device node to be updated the I/O resource + * @adev: ACPI companion of the device node to be updated the I/O resource * @hostdev: the device node associated with host controller * @res: double pointer to be set to the address of translated resources * @num_res: pointer to variable to hold the number of translated resources @@ -390,31 +390,24 @@ static void hisi_lpc_acpi_fixup_child_resource(struct device *hostdev, * host-relative address resource. This function will return the translated * logical PIO addresses for each child devices resources. */ -static int hisi_lpc_acpi_set_io_res(struct device *child, +static int hisi_lpc_acpi_set_io_res(struct acpi_device *adev, struct device *hostdev, const struct resource **res, int *num_res) { - struct acpi_device *adev; - struct acpi_device *host; + struct acpi_device *host = to_acpi_device(adev->dev.parent); struct resource_entry *rentry; LIST_HEAD(resource_list); struct resource *resources; int count; int i; - if (!child || !hostdev) - return -EINVAL; - - host = to_acpi_device(hostdev); - adev = to_acpi_device(child); - if (!adev->status.present) { - dev_dbg(child, "device is not present\n"); + dev_dbg(&adev->dev, "device is not present\n"); return -EIO; } if (acpi_device_enumerated(adev)) { - dev_dbg(child, "has been enumerated\n"); + dev_dbg(&adev->dev, "has been enumerated\n"); return -EIO; } @@ -425,7 +418,7 @@ static int hisi_lpc_acpi_set_io_res(struct device *child, */ count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); if (count <= 0) { - dev_dbg(child, "failed to get resources\n"); + dev_dbg(&adev->dev, "failed to get resources\n"); return count ? count : -EIO; } @@ -454,7 +447,7 @@ static int hisi_lpc_acpi_set_io_res(struct device *child, continue; ret = hisi_lpc_acpi_xlat_io_res(adev, host, &resources[i]); if (ret) { - dev_err(child, "translate IO range %pR failed (%d)\n", + dev_err(&adev->dev, "translate IO range %pR failed (%d)\n", &resources[i], ret); return ret; } @@ -471,6 +464,12 @@ static int hisi_lpc_acpi_remove_subdev(struct device *dev, void *unused) return 0; } +static int hisi_lpc_acpi_clear_enumerated(struct acpi_device *adev, void *not_used) +{ + acpi_device_clear_enumerated(adev); + return 0; +} + struct hisi_lpc_acpi_cell { const char *hid; const char *name; @@ -480,115 +479,114 @@ struct hisi_lpc_acpi_cell { static void hisi_lpc_acpi_remove(struct device *hostdev) { - struct acpi_device *adev = ACPI_COMPANION(hostdev); - struct acpi_device *child; - device_for_each_child(hostdev, NULL, hisi_lpc_acpi_remove_subdev); - - list_for_each_entry(child, &adev->children, node) - acpi_device_clear_enumerated(child); + acpi_dev_for_each_child(ACPI_COMPANION(hostdev), + hisi_lpc_acpi_clear_enumerated, NULL); } -/* - * hisi_lpc_acpi_probe - probe children for ACPI FW - * @hostdev: LPC host device pointer - * - * Returns 0 when successful, and a negative value for failure. - * - * Create a platform device per child, fixing up the resources - * from bus addresses to Logical PIO addresses. - * - */ -static int hisi_lpc_acpi_probe(struct device *hostdev) +static int hisi_lpc_acpi_add_child(struct acpi_device *child, void *data) { - struct acpi_device *adev = ACPI_COMPANION(hostdev); - struct acpi_device *child; + const char *hid = acpi_device_hid(child); + struct device *hostdev = data; + const struct hisi_lpc_acpi_cell *cell; + struct platform_device *pdev; + const struct resource *res; + bool found = false; + int num_res; int ret; - /* Only consider the children of the host */ - list_for_each_entry(child, &adev->children, node) { - const char *hid = acpi_device_hid(child); - const struct hisi_lpc_acpi_cell *cell; - struct platform_device *pdev; - const struct resource *res; - bool found = false; - int num_res; - - ret = hisi_lpc_acpi_set_io_res(&child->dev, &adev->dev, &res, - &num_res); - if (ret) { - dev_warn(hostdev, "set resource fail (%d)\n", ret); - goto fail; - } + ret = hisi_lpc_acpi_set_io_res(child, hostdev, &res, &num_res); + if (ret) { + dev_warn(hostdev, "set resource fail (%d)\n", ret); + return ret; + } - cell = (struct hisi_lpc_acpi_cell []){ - /* ipmi */ - { - .hid = "IPI0001", - .name = "hisi-lpc-ipmi", - }, - /* 8250-compatible uart */ - { - .hid = "HISI1031", - .name = "serial8250", - .pdata = (struct plat_serial8250_port []) { - { - .iobase = res->start, - .uartclk = 1843200, - .iotype = UPIO_PORT, - .flags = UPF_BOOT_AUTOCONF, - }, - {} + cell = (struct hisi_lpc_acpi_cell []){ + /* ipmi */ + { + .hid = "IPI0001", + .name = "hisi-lpc-ipmi", + }, + /* 8250-compatible uart */ + { + .hid = "HISI1031", + .name = "serial8250", + .pdata = (struct plat_serial8250_port []) { + { + .iobase = res->start, + .uartclk = 1843200, + .iotype = UPIO_PORT, + .flags = UPF_BOOT_AUTOCONF, }, - .pdata_size = 2 * - sizeof(struct plat_serial8250_port), + {} }, - {} - }; - - for (; cell && cell->name; cell++) { - if (!strcmp(cell->hid, hid)) { - found = true; - break; - } - } - - if (!found) { - dev_warn(hostdev, - "could not find cell for child device (%s), discarding\n", - hid); - continue; + .pdata_size = 2 * + sizeof(struct plat_serial8250_port), + }, + {} + }; + + for (; cell && cell->name; cell++) { + if (!strcmp(cell->hid, hid)) { + found = true; + break; } + } - pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO); - if (!pdev) { - ret = -ENOMEM; - goto fail; - } + if (!found) { + dev_warn(hostdev, + "could not find cell for child device (%s), discarding\n", + hid); + return 0; + } - pdev->dev.parent = hostdev; - ACPI_COMPANION_SET(&pdev->dev, child); + pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO); + if (!pdev) + return -ENOMEM; - ret = platform_device_add_resources(pdev, res, num_res); - if (ret) - goto fail; + pdev->dev.parent = hostdev; + ACPI_COMPANION_SET(&pdev->dev, child); - ret = platform_device_add_data(pdev, cell->pdata, - cell->pdata_size); - if (ret) - goto fail; + ret = platform_device_add_resources(pdev, res, num_res); + if (ret) + goto fail; - ret = platform_device_add(pdev); - if (ret) - goto fail; + ret = platform_device_add_data(pdev, cell->pdata, cell->pdata_size); + if (ret) + goto fail; - acpi_device_set_enumerated(child); - } + ret = platform_device_add(pdev); + if (ret) + goto fail; + acpi_device_set_enumerated(child); return 0; fail: - hisi_lpc_acpi_remove(hostdev); + platform_device_put(pdev); + return ret; +} + +/* + * hisi_lpc_acpi_probe - probe children for ACPI FW + * @hostdev: LPC host device pointer + * + * Returns 0 when successful, and a negative value for failure. + * + * Create a platform device per child, fixing up the resources + * from bus addresses to Logical PIO addresses. + * + */ +static int hisi_lpc_acpi_probe(struct device *hostdev) +{ + int ret; + + /* Only consider the children of the host */ + ret = acpi_dev_for_each_child(ACPI_COMPANION(hostdev), + hisi_lpc_acpi_add_child, hostdev); + if (ret) + hisi_lpc_acpi_remove(hostdev); + return ret; } diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 684a011a6396..8b058200d5ad 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -60,12 +60,29 @@ int mfd_cell_disable(struct platform_device *pdev) EXPORT_SYMBOL(mfd_cell_disable); #if IS_ENABLED(CONFIG_ACPI) +struct match_ids_walk_data { + struct acpi_device_id *ids; + struct acpi_device *adev; +}; + +static int match_device_ids(struct acpi_device *adev, void *data) +{ + struct match_ids_walk_data *wd = data; + + if (!acpi_match_device_ids(adev, wd->ids)) { + wd->adev = adev; + return 1; + } + + return 0; +} + static void mfd_acpi_add_device(const struct mfd_cell *cell, struct platform_device *pdev) { const struct mfd_cell_acpi_match *match = cell->acpi_match; - struct acpi_device *parent, *child; struct acpi_device *adev = NULL; + struct acpi_device *parent; parent = ACPI_COMPANION(pdev->dev.parent); if (!parent) @@ -83,14 +100,14 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell, if (match) { if (match->pnpid) { struct acpi_device_id ids[2] = {}; + struct match_ids_walk_data wd = { + .adev = NULL, + .ids = ids, + }; strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id)); - list_for_each_entry(child, &parent->children, node) { - if (!acpi_match_device_ids(child, ids)) { - adev = child; - break; - } - } + acpi_dev_for_each_child(parent, match_device_ids, &wd); + adev = wd.adev; } else { adev = acpi_find_child_device(parent, match->adr, false); } diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index c0350e9c03f3..4cca4c90769b 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -775,8 +775,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct sdhci_acpi_slot *slot; - struct acpi_device *device, *child; const struct dmi_system_id *id; + struct acpi_device *device; struct sdhci_acpi_host *c; struct sdhci_host *host; struct resource *iomem; @@ -796,10 +796,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev) slot = sdhci_acpi_get_slot(device); /* Power on the SDHCI controller and its children */ - acpi_device_fix_up_power(device); - list_for_each_entry(child, &device->children, node) - if (child->status.present && child->status.enabled) - acpi_device_fix_up_power(child); + acpi_device_fix_up_power_extended(device); if (sdhci_acpi_byt_defer(dev)) return -EPROBE_DEFER; diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index ed53276f6ad9..622b7de96c7f 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -1240,16 +1240,11 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { #ifdef CONFIG_ACPI static void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) { - struct acpi_device *device, *child; + struct acpi_device *device; device = ACPI_COMPANION(&slot->chip->pdev->dev); - if (!device) - return; - - acpi_device_fix_up_power(device); - list_for_each_entry(child, &device->children, node) - if (child->status.present && child->status.enabled) - acpi_device_fix_up_power(child); + if (device) + acpi_device_fix_up_power_extended(device); } #else static inline void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) {} diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a8b383051528..502dcd1c33b7 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6842,6 +6842,31 @@ static const struct backlight_ops ibm_backlight_data = { /* --------------------------------------------------------------------- */ +static int __init tpacpi_evaluate_bcl(struct acpi_device *adev, void *not_used) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + int rc; + + status = acpi_evaluate_object(adev->handle, "_BCL", NULL, &buffer); + if (ACPI_FAILURE(status)) + return 0; + + obj = buffer.pointer; + if (!obj || obj->type != ACPI_TYPE_PACKAGE) { + acpi_handle_info(adev->handle, + "Unknown _BCL data, please report this to %s\n", + TPACPI_MAIL); + rc = 0; + } else { + rc = obj->package.count; + } + kfree(obj); + + return rc; +} + /* * Call _BCL method of video device. On some ThinkPads this will * switch the firmware to the ACPI brightness control mode. @@ -6849,37 +6874,13 @@ static const struct backlight_ops ibm_backlight_data = { static int __init tpacpi_query_bcl_levels(acpi_handle handle) { - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - struct acpi_device *device, *child; - int rc; + struct acpi_device *device; device = acpi_fetch_acpi_dev(handle); if (!device) return 0; - rc = 0; - list_for_each_entry(child, &device->children, node) { - acpi_status status = acpi_evaluate_object(child->handle, "_BCL", - NULL, &buffer); - if (ACPI_FAILURE(status)) { - buffer.length = ACPI_ALLOCATE_BUFFER; - continue; - } - - obj = (union acpi_object *)buffer.pointer; - if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { - pr_err("Unknown _BCL data, please report this to %s\n", - TPACPI_MAIL); - rc = 0; - } else { - rc = obj->package.count; - } - break; - } - - kfree(buffer.pointer); - return rc; + return acpi_dev_for_each_child(device, tpacpi_evaluate_bcl, NULL); } diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index 669d7573320b..00f7b490a95d 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -127,6 +127,71 @@ static bool find_slave(struct sdw_bus *bus, return true; } +struct sdw_acpi_child_walk_data { + struct sdw_bus *bus; + struct acpi_device *adev; + struct sdw_slave_id id; + bool ignore_unique_id; +}; + +static int sdw_acpi_check_duplicate(struct acpi_device *adev, void *data) +{ + struct sdw_acpi_child_walk_data *cwd = data; + struct sdw_bus *bus = cwd->bus; + struct sdw_slave_id id; + + if (adev == cwd->adev) + return 0; + + if (!find_slave(bus, adev, &id)) + return 0; + + if (cwd->id.sdw_version != id.sdw_version || cwd->id.mfg_id != id.mfg_id || + cwd->id.part_id != id.part_id || cwd->id.class_id != id.class_id) + return 0; + + if (cwd->id.unique_id != id.unique_id) { + dev_dbg(bus->dev, + "Valid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n", + cwd->id.unique_id, id.unique_id, cwd->id.mfg_id, + cwd->id.part_id); + cwd->ignore_unique_id = false; + return 0; + } + + dev_err(bus->dev, + "Invalid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n", + cwd->id.unique_id, id.unique_id, cwd->id.mfg_id, cwd->id.part_id); + return -ENODEV; +} + +static int sdw_acpi_find_one(struct acpi_device *adev, void *data) +{ + struct sdw_bus *bus = data; + struct sdw_acpi_child_walk_data cwd = { + .bus = bus, + .adev = adev, + .ignore_unique_id = true, + }; + int ret; + + if (!find_slave(bus, adev, &cwd.id)) + return 0; + + /* Brute-force O(N^2) search for duplicates. */ + ret = acpi_dev_for_each_child(ACPI_COMPANION(bus->dev), + sdw_acpi_check_duplicate, &cwd); + if (ret) + return ret; + + if (cwd.ignore_unique_id) + cwd.id.unique_id = SDW_IGNORED_UNIQUE_ID; + + /* Ignore errors and continue. */ + sdw_slave_add(bus, &cwd.id, acpi_fwnode_handle(adev)); + return 0; +} + /* * sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node * @bus: SDW bus instance @@ -135,8 +200,7 @@ static bool find_slave(struct sdw_bus *bus, */ int sdw_acpi_find_slaves(struct sdw_bus *bus) { - struct acpi_device *adev, *parent; - struct acpi_device *adev2, *parent2; + struct acpi_device *parent; parent = ACPI_COMPANION(bus->dev); if (!parent) { @@ -144,54 +208,7 @@ int sdw_acpi_find_slaves(struct sdw_bus *bus) return -ENODEV; } - list_for_each_entry(adev, &parent->children, node) { - struct sdw_slave_id id; - struct sdw_slave_id id2; - bool ignore_unique_id = true; - - if (!find_slave(bus, adev, &id)) - continue; - - /* brute-force O(N^2) search for duplicates */ - parent2 = parent; - list_for_each_entry(adev2, &parent2->children, node) { - - if (adev == adev2) - continue; - - if (!find_slave(bus, adev2, &id2)) - continue; - - if (id.sdw_version != id2.sdw_version || - id.mfg_id != id2.mfg_id || - id.part_id != id2.part_id || - id.class_id != id2.class_id) - continue; - - if (id.unique_id != id2.unique_id) { - dev_dbg(bus->dev, - "Valid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n", - id.unique_id, id2.unique_id, id.mfg_id, id.part_id); - ignore_unique_id = false; - } else { - dev_err(bus->dev, - "Invalid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n", - id.unique_id, id2.unique_id, id.mfg_id, id.part_id); - return -ENODEV; - } - } - - if (ignore_unique_id) - id.unique_id = SDW_IGNORED_UNIQUE_ID; - - /* - * don't error check for sdw_slave_add as we want to continue - * adding Slaves - */ - sdw_slave_add(bus, &id, acpi_fwnode_handle(adev)); - } - - return 0; + return acpi_dev_for_each_child(parent, sdw_acpi_find_one, bus); } #endif diff --git a/drivers/thunderbolt/acpi.c b/drivers/thunderbolt/acpi.c index c89daac0ad8c..b1f0dc8df47c 100644 --- a/drivers/thunderbolt/acpi.c +++ b/drivers/thunderbolt/acpi.c @@ -301,37 +301,22 @@ static bool tb_acpi_bus_match(struct device *dev) return tb_is_switch(dev) || tb_is_usb4_port_device(dev); } -static struct acpi_device *tb_acpi_find_port(struct acpi_device *adev, - const struct tb_port *port) +static struct acpi_device *tb_acpi_switch_find_companion(struct tb_switch *sw) { - struct acpi_device *port_adev; - - if (!adev) - return NULL; + struct acpi_device *adev = NULL; + struct tb_switch *parent_sw; /* * Device routers exists under the downstream facing USB4 port * of the parent router. Their _ADR is always 0. */ - list_for_each_entry(port_adev, &adev->children, node) { - if (acpi_device_adr(port_adev) == port->port) - return port_adev; - } - - return NULL; -} - -static struct acpi_device *tb_acpi_switch_find_companion(struct tb_switch *sw) -{ - struct acpi_device *adev = NULL; - struct tb_switch *parent_sw; - parent_sw = tb_switch_parent(sw); if (parent_sw) { struct tb_port *port = tb_port_at(tb_route(sw), parent_sw); struct acpi_device *port_adev; - port_adev = tb_acpi_find_port(ACPI_COMPANION(&parent_sw->dev), port); + port_adev = acpi_find_child_by_adr(ACPI_COMPANION(&parent_sw->dev), + port->port); if (port_adev) adev = acpi_find_child_device(port_adev, 0, false); } else { @@ -364,8 +349,8 @@ static struct acpi_device *tb_acpi_find_companion(struct device *dev) if (tb_is_switch(dev)) return tb_acpi_switch_find_companion(tb_to_switch(dev)); else if (tb_is_usb4_port_device(dev)) - return tb_acpi_find_port(ACPI_COMPANION(dev->parent), - tb_to_usb4_port_device(dev)->port); + return acpi_find_child_by_adr(ACPI_COMPANION(dev->parent), + tb_to_usb4_port_device(dev)->port->port); return NULL; } diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index d4dcaefd0ea4..6d93428432f1 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -124,22 +124,6 @@ out: */ #define USB_ACPI_LOCATION_VALID (1 << 31) -static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent, - int raw) -{ - struct acpi_device *adev; - - if (!parent) - return NULL; - - list_for_each_entry(adev, &parent->children, node) { - if (acpi_device_adr(adev) == raw) - return adev; - } - - return acpi_find_child_device(parent, raw, false); -} - static struct acpi_device * usb_acpi_get_companion_for_port(struct usb_port *port_dev) { @@ -170,7 +154,7 @@ usb_acpi_get_companion_for_port(struct usb_port *port_dev) port1 = port_dev->portnum; } - return usb_acpi_find_port(adev, port1); + return acpi_find_child_by_adr(adev, port1); } static struct acpi_device * |