From d21b57003041a5a5d28933fd2dfd1c5183fb23af Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:05:17 +0200 Subject: ACPI: glue: Use acpi_dev_for_each_child() Instead of walking the list of children of an ACPI device directly, use acpi_dev_for_each_child() to carry out an action for all of the given ACPI device's children. This will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/glue.c | 101 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 8d769114a048..552d82dfa476 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -105,51 +105,74 @@ 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 find_child_walk_data { + struct acpi_device *adev; + u64 address; + int score; + bool check_children; +}; + +static int check_one_child(struct acpi_device *adev, void *data) { - struct acpi_device *adev, *ret = NULL; - int ret_score = 0; + struct find_child_walk_data *wd = data; + int score; - if (!parent) - return NULL; + if (!adev->pnp.type.bus_address || acpi_device_adr(adev) != wd->address) + return 0; - list_for_each_entry(adev, &parent->children, node) { - acpi_bus_address addr = acpi_device_adr(adev); - int score; + if (!wd->adev) { + /* This is the first matching object. Save it and continue. */ + wd->adev = adev; + return 0; + } - if (!adev->pnp.type.bus_address || addr != address) - continue; + /* + * 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; - if (!ret) { - /* This is the first matching object. Save it. */ - ret = adev; - continue; - } - /* - * 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. - */ - 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->score = score; } - return ret; + + /* Continue, because there may be better matches. */ + return 0; +} + +struct acpi_device *acpi_find_child_device(struct acpi_device *parent, + u64 address, bool check_children) +{ + struct find_child_walk_data wd = { + .address = address, + .check_children = check_children, + .adev = NULL, + .score = 0, + }; + + if (parent) + acpi_dev_for_each_child(parent, check_one_child, &wd); + + return wd.adev; } EXPORT_SYMBOL_GPL(acpi_find_child_device); -- cgit v1.2.3 From f5122be80daad8e53e6876add5ccbf9db7ca809c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:06:18 +0200 Subject: ACPI: glue: Introduce acpi_dev_has_children() Define acpi_dev_has_children() as a wrapper around acpi_dev_for_each_child() and use it to check if the given ACPI device has any children instead of checking the children list head in struct acpi_device. This will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/glue.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 552d82dfa476..5203a7c60daa 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); -- cgit v1.2.3 From 2f6fe93fede802acfe010752db461ccd34745745 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:10:03 +0200 Subject: ACPI: glue: Introduce acpi_find_child_by_adr() Rearrange the ACPI device lookup code used internally by acpi_find_child_device() so it can avoid extra checks after finding one object with a matching _ADR and use it for defining acpi_find_child_by_adr() that will allow the callers to find a given ACPI device's child matching a given bus address without doing any other checks in check_one_child(). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/glue.c | 28 ++++++++++++++++++++++++---- include/acpi/acpi_bus.h | 2 ++ 2 files changed, 26 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 5203a7c60daa..204fe94c7e45 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -119,6 +119,7 @@ struct find_child_walk_data { struct acpi_device *adev; u64 address; int score; + bool check_sta; bool check_children; }; @@ -131,9 +132,13 @@ static int check_one_child(struct acpi_device *adev, void *data) return 0; if (!wd->adev) { - /* This is the first matching object. Save it and continue. */ + /* + * This is the first matching object, so save it. If it is not + * necessary to look for any other matching objects, stop the + * search. + */ wd->adev = adev; - return 0; + return !(wd->check_sta || wd->check_children); } /* @@ -169,12 +174,14 @@ static int check_one_child(struct acpi_device *adev, void *data) return 0; } -struct acpi_device *acpi_find_child_device(struct acpi_device *parent, - u64 address, bool check_children) +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, }; @@ -184,8 +191,21 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, 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/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 0dc1ea0b52f5..597961969ca1 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -622,6 +622,8 @@ static inline int acpi_dma_configure(struct device *dev, } struct acpi_device *acpi_find_child_device(struct acpi_device *parent, u64 address, bool check_children); +struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev, + acpi_bus_address adr); int acpi_is_root_bridge(acpi_handle); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); -- cgit v1.2.3 From a73a204b44586c07876f18e329be3fcb713af29b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 20 Jun 2022 20:32:26 +0200 Subject: thunderbolt: ACPI: Replace tb_acpi_find_port() with acpi_find_child_by_adr() Use acpi_find_child_by_adr() to find the child matching a given bus address instead of tb_acpi_find_port() that walks the list of children of an ACPI device directly for this purpose and drop the latter. Apart from simplifying the code, this will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Acked-by: Mika Westerberg Reviewed-by: Heikki Krogerus --- drivers/thunderbolt/acpi.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) (limited to 'drivers') 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; } -- cgit v1.2.3 From bf5fb8ae8248c30422e50a30c73e88a4590ed74e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:39:37 +0200 Subject: USB: ACPI: Replace usb_acpi_find_port() with acpi_find_child_by_adr() Instead of walking the list of children of an ACPI device directly in order to find the child matching a given bus address, use acpi_find_child_by_adr() for this purpose. Also notice that if acpi_find_child_by_adr() doesn't find a matching child, acpi_find_child_device() will not find it too, so directly replace usb_acpi_find_port() in usb_acpi_get_companion_for_port() with acpi_find_child_by_adr() and drop it entirely. Apart from simplifying the code, this will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Reviewed-by: Heikki Krogerus --- drivers/usb/core/usb-acpi.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'drivers') 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 * -- cgit v1.2.3 From abda0af4cd3b4703649ca78abf8d283f279a3f90 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:15:26 +0200 Subject: ACPI: container: Use acpi_dev_for_each_child() Instead of walking the list of children of an ACPI device directly, use acpi_dev_for_each_child() to carry out an action for all of the given ACPI device's children. This will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/container.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') 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) -- cgit v1.2.3 From fa98b3985a4a6de6d40b2469b30a3452575f6acf Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:16:30 +0200 Subject: ACPI: property: Use acpi_dev_for_each_child() for child lookup Instead of using the list of children of an ACPI device directly, use acpi_dev_for_each_child() to find the next child of a given ACPI device. This will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/property.c | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers') 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; /* -- cgit v1.2.3 From f8128c390e58928b16f197416d417cfa4c65f610 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:26:03 +0200 Subject: ACPI: bus: Export acpi_dev_for_each_child() to modules Some pieces of modular code can benefit from using acpi_dev_for_each_child(), so export it to modules. Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/bus.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 86fa61a21826..7027ff2edfba 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1102,6 +1102,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) -- cgit v1.2.3 From 0ea3ef240c49113cefbaab1f3dbf5b7f46837fc0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:26:28 +0200 Subject: ACPI: video: Use acpi_dev_for_each_child() Instead of walking the list of children of an ACPI device directly, use acpi_dev_for_each_child() to carry out an action for all of the given ACPI device's children. This will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/acpi_video.c | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index e07782b1fbb6..7e3cab70b718 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1149,24 +1149,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); @@ -1226,7 +1227,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; } /* @@ -1538,9 +1541,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 @@ -1548,16 +1548,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 */ -- cgit v1.2.3 From ff32e59947c87b01dc25a8b5763d609c1a8f56eb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:26:47 +0200 Subject: ACPI: bus: Introduce acpi_dev_for_each_child_reverse() Make it possible to walk the children of an ACPI device in the revese order by defining acpi_dev_for_each_child_reverse() in analogy with acpi_dev_for_each_child(). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/bus.c | 12 ++++++++++++ include/acpi/acpi_bus.h | 3 +++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 7027ff2edfba..4d7c51a33b01 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1115,6 +1115,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/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 597961969ca1..76de1aa5d221 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -483,6 +483,9 @@ extern struct bus_type acpi_bus_type; int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data); int acpi_dev_for_each_child(struct acpi_device *adev, int (*fn)(struct acpi_device *, void *), void *data); +int acpi_dev_for_each_child_reverse(struct acpi_device *adev, + int (*fn)(struct acpi_device *, void *), + void *data); /* * Events -- cgit v1.2.3 From a976a2ac7708c63257d42707c8423047136797a0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 21 Jun 2022 14:34:28 +0200 Subject: ACPI: scan: Walk ACPI device's children using driver core Instead of walking the list of children of an ACPI device directly, use acpi_dev_for_each_child() or acpi_dev_for_each_child_reverse() to carry out an action for all of the given ACPI device's children. This will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/scan.c | 59 ++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 762b61f67e6c..7b085826d881 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: @@ -2187,9 +2181,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 +2199,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 +2217,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 +2227,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 +2268,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 +2426,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 +2440,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 +2468,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); -- cgit v1.2.3 From 0b1bd1e356643319809903034ffd2e6b5834271e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:30:19 +0200 Subject: platform/x86/thinkpad_acpi: Use acpi_dev_for_each_child() Instead of walking the list of children of an ACPI device directly, use acpi_dev_for_each_child() to carry out an action for all of the given ACPI device's children. This will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Reviewed-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 53 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e6cb4a14cdd4..242542db644a 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6841,6 +6841,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. @@ -6848,37 +6873,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); } -- cgit v1.2.3 From 9089d1a41aab0298aaed04f24572035db351db7b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:35:26 +0200 Subject: soundwire: Use acpi_dev_for_each_child() Instead of walking the list of children of an ACPI device directly, use acpi_dev_for_each_child() to carry out an action for all of the given ACPI device's children. This will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Pierre-Louis Bossart Tested-by: Pierre-Louis Bossart Acked-By: Vinod Koul --- drivers/soundwire/slave.c | 117 ++++++++++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 50 deletions(-) (limited to 'drivers') 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 -- cgit v1.2.3 From a22f18bddd824e96db839ccda75ff7e035e938ca Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:36:06 +0200 Subject: ACPI / MMC: PM: Unify fixing up device power Introduce acpi_device_fix_up_power_extended() for fixing up power of a device having an ACPI companion in a manner that takes the device's children into account and make the MMC code use it in two places instead of walking the list of the device ACPI companion's children directly. This will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Acked-by: Adrian Hunter Acked-by: Ulf Hansson --- drivers/acpi/device_pm.c | 22 ++++++++++++++++++++++ drivers/mmc/host/sdhci-acpi.c | 7 ++----- drivers/mmc/host/sdhci-pci-core.c | 11 +++-------- include/acpi/acpi_bus.h | 1 + 4 files changed, 28 insertions(+), 13 deletions(-) (limited to 'drivers') 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/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/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 76de1aa5d221..54c5566df9fe 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -524,6 +524,7 @@ const char *acpi_power_state_string(int state); int acpi_device_set_power(struct acpi_device *device, int state); int acpi_bus_init_power(struct acpi_device *device); int acpi_device_fix_up_power(struct acpi_device *device); +void acpi_device_fix_up_power_extended(struct acpi_device *adev); int acpi_bus_update_power(acpi_handle handle, int *state_p); int acpi_device_update_power(struct acpi_device *device, int *state_p); bool acpi_bus_power_manageable(acpi_handle handle); -- cgit v1.2.3 From 0c9b9c2ac0df57b6b5949a51c45043b345698428 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:31:08 +0200 Subject: mfd: core: Use acpi_dev_for_each_child() Instead of walking the list of children of an ACPI device directly, use acpi_dev_for_each_child() to carry out an action for all of the given ACPI device's children. This will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/2726954.BEx9A2HvPv@kreacher --- drivers/mfd/mfd-core.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers') 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); } -- cgit v1.2.3 From e5ed878ddb7cd95cd7886a0298fcb080eeab5e90 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sat, 18 Jun 2022 13:23:10 +0200 Subject: ACPI: bus: Drop redundant check in acpi_device_remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bus remove callback is only ever called by the device core with a bound driver. So there is no need to check if the driver is non-NULL. Signed-off-by: Uwe Kleine-König [ rjw: Added empty code line after if () ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 4d7c51a33b01..479eec8a1ec6 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1062,12 +1062,12 @@ 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; - 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); - } + 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; -- cgit v1.2.3 From d6fb6ee1820cb9c49717b8d28c5b2e940cb2e439 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sat, 18 Jun 2022 13:23:11 +0200 Subject: ACPI: bus: Drop driver member of struct acpi_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit struct acpi_device::driver tracks the same information as the driver member of struct acpi_device::dev. Fix all users of the former to use the latter and drop the redundant data from struct acpi_device. Signed-off-by: Uwe Kleine-König Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 21 ++++++++++----------- drivers/acpi/device_sysfs.c | 2 +- include/acpi/acpi_bus.h | 1 - 3 files changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 479eec8a1ec6..90cabe4fd4d0 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -465,7 +465,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; @@ -517,10 +516,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); @@ -539,8 +541,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) @@ -1033,8 +1036,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); @@ -1044,7 +1045,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; } @@ -1060,7 +1060,7 @@ 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); @@ -1068,7 +1068,6 @@ static void acpi_device_remove(struct device *dev) if (acpi_drv->ops.remove) acpi_drv->ops.remove(acpi_dev); - acpi_dev->driver = NULL; acpi_dev->driver_data = NULL; put_device(dev); 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/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 54c5566df9fe..ab239a35cb2a 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -379,7 +379,6 @@ struct acpi_device { struct acpi_device_data data; struct acpi_scan_handler *handler; struct acpi_hotplug_context *hp; - struct acpi_driver *driver; const struct acpi_gpio_mapping *driver_gpios; void *driver_data; struct device dev; -- cgit v1.2.3 From 54872fea6a5ac967ec2272aea525d1438ac6735a Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 1 Jul 2022 17:43:52 +0800 Subject: bus: hisi_lpc: fix missing platform_device_put() in hisi_lpc_acpi_probe() In error case in hisi_lpc_acpi_probe() after calling platform_device_add(), hisi_lpc_acpi_remove() can't release the failed 'pdev', so it will be leak, call platform_device_put() to fix this problem. I'v constructed this error case and tested this patch on D05 board. Fixes: 99c0228d6ff1 ("HISI LPC: Re-Add ACPI child enumeration support") Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Acked-by: John Garry Signed-off-by: Rafael J. Wysocki --- drivers/bus/hisi_lpc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c index 378f5d62a991..e7eaa8784fee 100644 --- a/drivers/bus/hisi_lpc.c +++ b/drivers/bus/hisi_lpc.c @@ -503,13 +503,13 @@ static int hisi_lpc_acpi_probe(struct device *hostdev) { struct acpi_device *adev = ACPI_COMPANION(hostdev); struct acpi_device *child; + struct platform_device *pdev; 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; @@ -571,22 +571,24 @@ static int hisi_lpc_acpi_probe(struct device *hostdev) ret = platform_device_add_resources(pdev, res, num_res); if (ret) - goto fail; + goto fail_put_device; ret = platform_device_add_data(pdev, cell->pdata, cell->pdata_size); if (ret) - goto fail; + goto fail_put_device; ret = platform_device_add(pdev); if (ret) - goto fail; + goto fail_put_device; acpi_device_set_enumerated(child); } return 0; +fail_put_device: + platform_device_put(pdev); fail: hisi_lpc_acpi_remove(hostdev); return ret; -- cgit v1.2.3 From d674553009afc9b24cab2bbec71628609edbbb27 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 30 Jun 2022 20:13:52 +0200 Subject: hisi_lpc: Use acpi_dev_for_each_child() Instead of walking the list of children of an ACPI device directly, use acpi_dev_for_each_child() to carry out an action for all of the given ACPI device's children. This will help to eliminate the children list head from struct acpi_device as it is redundant and it is used in questionable ways in some places (in particular, locking is needed for walking the list pointed to it safely, but it is often missing). While at it, simplify hisi_lpc_acpi_set_io_res() by making it accept a struct acpi_device pointer from the caller, instead of going to struct device and back to get the same result, and clean up confusion regarding hostdev and its ACPI companion in that function. Also remove a redundant check from it. Signed-off-by: Rafael J. Wysocki Reviewed-by: Greg Kroah-Hartman Reviewed-by: John Garry --- drivers/bus/hisi_lpc.c | 204 ++++++++++++++++++++++++------------------------- 1 file changed, 100 insertions(+), 104 deletions(-) (limited to 'drivers') diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c index e7eaa8784fee..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,117 +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; - 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_put_device; + 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_put_device; + ret = platform_device_add_resources(pdev, res, num_res); + if (ret) + goto fail; - ret = platform_device_add(pdev); - if (ret) - goto fail_put_device; + 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_put_device: - platform_device_put(pdev); 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; } -- cgit v1.2.3 From e6bdbcc764af822ff7172a4a78d437dc433a0c74 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:38:00 +0200 Subject: ACPI: bus: Drop unused list heads from struct acpi_device Drop the children and node list heads that have no more users from struct acpi_device and the code manipulating them from __acpi_device_add() and acpi_device_del(). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/scan.c | 11 +---------- include/acpi/acpi_bus.h | 2 -- 2 files changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7b085826d881..b100e6ca9bb4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -465,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, @@ -482,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); @@ -674,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); @@ -715,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); @@ -746,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: diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index ab239a35cb2a..48f0fd499274 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -365,8 +365,6 @@ struct acpi_device { acpi_handle handle; /* no handle for fixed hardware */ struct fwnode_handle fwnode; struct acpi_device *parent; - struct list_head children; - struct list_head node; struct list_head wakeup_list; struct list_head del_list; struct acpi_device_status status; -- cgit v1.2.3