From 805d410fb0dbd65e1a57a810858fa2491e75822d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:39 +0100 Subject: ACPI: Separate adding ACPI device objects from probing ACPI drivers Split the ACPI namespace scanning for devices into two passes, such that struct acpi_device objects are registerd in the first pass without probing ACPI drivers and the drivers are probed against them directly in the second pass. There are two main reasons for doing that. First, the ACPI PCI root bridge driver's .add() routine, acpi_pci_root_add(), causes struct pci_dev objects to be created for all PCI devices under the given root bridge. Usually, there are corresponding ACPI device nodes in the ACPI namespace for some of those devices and therefore there should be "companion" struct acpi_device objects to attach those struct pci_dev objects to. These struct acpi_device objects should exist when the corresponding struct pci_dev objects are created, but that is only guaranteed during boot and not during hotplug. This leads to a number of functional differences between the boot and the hotplug cases which are not strictly necessary and make the code more complicated. For example, this forces the ACPI PCI root bridge driver to defer the registration of the just created struct pci_dev objects and to use a special .start() callback routine, acpi_pci_root_start(), to make sure that all of the "companion" struct acpi_device objects will be present at PCI devices registration time during hotplug. If those differences can be eliminated, we will be able to consolidate the boot and hotplug code paths for the enumeration and registration of PCI devices and to reduce the complexity of that code quite a bit. The second reason is that, in general, it should be possible to resolve conflicts of resources assigned by the BIOS to different devices represented by ACPI namespace nodes before any drivers bind to them and before they are attached to "companion" objects representing physical devices (such as struct pci_dev). However, for this purpose we first need to enumerate all ACPI device nodes in the given namespace scope. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/scan.c | 103 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 31 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 53502d1bbf26..726f0d1ace4b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -494,7 +494,8 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv) struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = to_acpi_driver(drv); - return !acpi_match_device_ids(acpi_dev, acpi_drv->ids); + return acpi_dev->bus_ops.acpi_op_match + && !acpi_match_device_ids(acpi_dev, acpi_drv->ids); } static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) @@ -1418,6 +1419,17 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) return 0; } +/* + * acpi_hot_add_bind - Bind _ADR-based devices on hot-add. + * @device: ACPI device node to bind. + */ +static void acpi_hot_add_bind(struct acpi_device *device) +{ + if (device->flags.bus_address + && device->parent && device->parent->ops.bind) + device->parent->ops.bind(device); +} + static int acpi_add_single_object(struct acpi_device **child, acpi_handle handle, int type, unsigned long long sta, @@ -1490,13 +1502,8 @@ static int acpi_add_single_object(struct acpi_device **child, result = acpi_device_register(device); - /* - * Bind _ADR-Based Devices when hot add - */ - if (device->flags.bus_address) { - if (device->parent && device->parent->ops.bind) - device->parent->ops.bind(device); - } + if (device->bus_ops.acpi_op_match) + acpi_hot_add_bind(device); end: if (!result) { @@ -1522,6 +1529,7 @@ static void acpi_bus_add_power_resource(acpi_handle handle) struct acpi_bus_ops ops = { .acpi_op_add = 1, .acpi_op_start = 1, + .acpi_op_match = 1, }; struct acpi_device *device = NULL; @@ -1574,9 +1582,9 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, void *context, void **return_value) { struct acpi_bus_ops *ops = context; + struct acpi_device *device = NULL; int type; unsigned long long sta; - struct acpi_device *device; acpi_status status; int result; @@ -1596,52 +1604,84 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, return AE_CTRL_DEPTH; } - /* - * We may already have an acpi_device from a previous enumeration. If - * so, we needn't add it again, but we may still have to start it. - */ - device = NULL; acpi_bus_get_device(handle, &device); if (ops->acpi_op_add && !device) { - acpi_add_single_object(&device, handle, type, sta, ops); - /* Is the device a known good platform device? */ - if (device - && !acpi_match_device_ids(device, acpi_platform_device_ids)) - acpi_create_platform_device(device); - } + struct acpi_bus_ops add_ops = *ops; - if (!device) - return AE_CTRL_DEPTH; - - if (ops->acpi_op_start && !(ops->acpi_op_add)) { - status = acpi_start_single_object(device); - if (ACPI_FAILURE(status)) + add_ops.acpi_op_match = 0; + acpi_add_single_object(&device, handle, type, sta, &add_ops); + if (!device) return AE_CTRL_DEPTH; + + device->bus_ops.acpi_op_match = 1; + acpi_hot_add_bind(device); } if (!*return_value) *return_value = device; + return AE_OK; } +static acpi_status acpi_bus_probe_start(acpi_handle handle, u32 lvl, + void *context, void **not_used) +{ + struct acpi_bus_ops *ops = context; + acpi_status status = AE_OK; + struct acpi_device *device; + unsigned long long sta_not_used; + int type_not_used; + + /* + * Ignore errors ignored by acpi_bus_check_add() to avoid terminating + * namespace walks prematurely. + */ + if (acpi_bus_type_and_status(handle, &type_not_used, &sta_not_used)) + return AE_OK; + + if (acpi_bus_get_device(handle, &device)) + return AE_CTRL_DEPTH; + + if (ops->acpi_op_add) { + if (!acpi_match_device_ids(device, acpi_platform_device_ids)) { + /* This is a known good platform device. */ + acpi_create_platform_device(device); + } else if (device_attach(&device->dev)) { + status = AE_CTRL_DEPTH; + } + } else if (ops->acpi_op_start) { + if (ACPI_FAILURE(acpi_start_single_object(device))) + status = AE_CTRL_DEPTH; + } + return status; +} + static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops, struct acpi_device **child) { - acpi_status status; void *device = NULL; + acpi_status status; + int ret = -ENODEV; status = acpi_bus_check_add(handle, 0, ops, &device); if (ACPI_SUCCESS(status)) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_check_add, NULL, ops, &device); + if (!device) + goto out; + + ret = 0; + status = acpi_bus_probe_start(handle, 0, ops, NULL); + if (ACPI_SUCCESS(status)) + acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, + acpi_bus_probe_start, NULL, ops, NULL); + + out: if (child) *child = device; - if (device) - return 0; - else - return -ENODEV; + return ret; } /* @@ -1752,6 +1792,7 @@ static int acpi_bus_scan_fixed(void) memset(&ops, 0, sizeof(ops)); ops.acpi_op_add = 1; ops.acpi_op_start = 1; + ops.acpi_op_match = 1; /* * Enumerate all fixed-feature devices. -- cgit v1.2.3 From 92ef2a25c763338905dce8344a0584606f842920 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:40 +0100 Subject: ACPI: Change the ordering of PCI root bridge driver registrarion Instead of running acpi_pci_root_init() from a separate subsys initcall, call it directly from acpi_scan_init() before scanning the ACPI namespace for the first time, so that the PCI root bridge driver's .add() routine, acpi_pci_root_start(), is always run before binding ACPI drivers or attaching "companion" device objects to struct acpi_device objects below the root bridge's device node in the ACPI namespace. The first, simpler reason for doing this is that it makes the situation during boot more similar to the situation during hotplug, in which the ACPI PCI root bridge driver is always present. The second reason is that acpi_pci_root_init() causes struct pci_dev objects to be created for all PCI devices below the bridge and these objects may be necessary for whatever is done with the other ACPI device nodes in that namespace scope. For example, devices created by acpi_create_platform_device() sometimes may need to be added to the device hierarchy as children of PCI bridges. For this purpose, however, the struct pci_dev objects representing those bridges need to exist before the platform devices in question are registered. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/internal.h | 1 + drivers/acpi/pci_root.c | 4 +--- drivers/acpi/scan.c | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 3c407cdc1ec1..e050254ae143 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -67,6 +67,7 @@ struct acpi_ec { extern struct acpi_ec *first_ec; +int acpi_pci_root_init(void); int acpi_ec_init(void); int acpi_ec_ecdt_probe(void); int acpi_boot_ec_enable(void); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 7928d4dc7056..a233fe93dfac 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -699,7 +699,7 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) return 0; } -static int __init acpi_pci_root_init(void) +int __init acpi_pci_root_init(void) { acpi_hest_init(); @@ -712,5 +712,3 @@ static int __init acpi_pci_root_init(void) return 0; } - -subsys_initcall(acpi_pci_root_init); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 726f0d1ace4b..a7e81ac2cd0c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1831,6 +1831,7 @@ int __init acpi_scan_init(void) } acpi_power_init(); + acpi_pci_root_init(); /* * Enumerate devices in the ACPI namespace. -- cgit v1.2.3 From 0fc300b0537c6a6a7f2b261b6c339dc498cd1702 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:41 +0100 Subject: ACPI: Make acpi_bus_add() and acpi_bus_start() visibly different The current ACPI namespace scanning code suggests that acpi_bus_add() and acpi_bus_start() share some code. In fact, however, they are completely different code paths (except for the initial checks), so refactor the code to make that distinction visibly clear. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/scan.c | 63 +++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 28 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index a7e81ac2cd0c..f3bcaf6c6bd4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1623,10 +1623,9 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, return AE_OK; } -static acpi_status acpi_bus_probe_start(acpi_handle handle, u32 lvl, - void *context, void **not_used) +static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, + void *not_used, void **ret_not_used) { - struct acpi_bus_ops *ops = context; acpi_status status = AE_OK; struct acpi_device *device; unsigned long long sta_not_used; @@ -1642,16 +1641,11 @@ static acpi_status acpi_bus_probe_start(acpi_handle handle, u32 lvl, if (acpi_bus_get_device(handle, &device)) return AE_CTRL_DEPTH; - if (ops->acpi_op_add) { - if (!acpi_match_device_ids(device, acpi_platform_device_ids)) { - /* This is a known good platform device. */ - acpi_create_platform_device(device); - } else if (device_attach(&device->dev)) { - status = AE_CTRL_DEPTH; - } - } else if (ops->acpi_op_start) { - if (ACPI_FAILURE(acpi_start_single_object(device))) - status = AE_CTRL_DEPTH; + if (!acpi_match_device_ids(device, acpi_platform_device_ids)) { + /* This is a known good platform device. */ + acpi_create_platform_device(device); + } else if (device_attach(&device->dev)) { + status = AE_CTRL_DEPTH; } return status; } @@ -1672,10 +1666,10 @@ static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops, goto out; ret = 0; - status = acpi_bus_probe_start(handle, 0, ops, NULL); + status = acpi_bus_device_attach(handle, 0, NULL, NULL); if (ACPI_SUCCESS(status)) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, - acpi_bus_probe_start, NULL, ops, NULL); + acpi_bus_device_attach, NULL, NULL, NULL); out: if (child) @@ -1700,31 +1694,44 @@ int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type) { - struct acpi_bus_ops ops; - - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_add = 1; + struct acpi_bus_ops ops = { .acpi_op_add = 1, }; return acpi_bus_scan(handle, &ops, child); } EXPORT_SYMBOL(acpi_bus_add); -int acpi_bus_start(struct acpi_device *device) +static acpi_status acpi_bus_start_device(acpi_handle handle, u32 lvl, + void *not_used, void **ret_not_used) { - struct acpi_bus_ops ops; - int result; + struct acpi_device *device; + unsigned long long sta_not_used; + int type_not_used; + + /* + * Ignore errors ignored by acpi_bus_check_add() to avoid terminating + * namespace walks prematurely. + */ + if (acpi_bus_type_and_status(handle, &type_not_used, &sta_not_used)) + return AE_OK; + + if (acpi_bus_get_device(handle, &device)) + return AE_CTRL_DEPTH; + + return acpi_start_single_object(device); +} +int acpi_bus_start(struct acpi_device *device) +{ if (!device) return -EINVAL; - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_start = 1; - - result = acpi_bus_scan(device->handle, &ops, NULL); + if (ACPI_SUCCESS(acpi_start_single_object(device))) + acpi_walk_namespace(ACPI_TYPE_ANY, device->handle, + ACPI_UINT32_MAX, acpi_bus_start_device, + NULL, NULL, NULL); acpi_update_all_gpes(); - - return result; + return 0; } EXPORT_SYMBOL(acpi_bus_start); -- cgit v1.2.3 From ca7b3c4f3d85bf7ec225eebb43b6af0a25499c6c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:42 +0100 Subject: ACPI: Reduce the usage of struct acpi_bus_ops Objects of type struct acpi_bus_ops are currently used to pass information between different parts of the ACPI namespace scanning code, sometimes in quite convoluted ways. It turns out that that is not necessary in some cases, so simplify the code by reducing the utilization of struct acpi_bus_ops objects where clearly possible. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/scan.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index f3bcaf6c6bd4..8dde0e7f68d8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1527,7 +1527,6 @@ end: static void acpi_bus_add_power_resource(acpi_handle handle) { struct acpi_bus_ops ops = { - .acpi_op_add = 1, .acpi_op_start = 1, .acpi_op_match = 1, }; @@ -1581,7 +1580,6 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, void *context, void **return_value) { - struct acpi_bus_ops *ops = context; struct acpi_device *device = NULL; int type; unsigned long long sta; @@ -1605,11 +1603,13 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, } acpi_bus_get_device(handle, &device); - if (ops->acpi_op_add && !device) { - struct acpi_bus_ops add_ops = *ops; + if (!device) { + struct acpi_bus_ops ops = { + .acpi_op_start = !!context, + .acpi_op_match = 0, + }; - add_ops.acpi_op_match = 0; - acpi_add_single_object(&device, handle, type, sta, &add_ops); + acpi_add_single_object(&device, handle, type, sta, &ops); if (!device) return AE_CTRL_DEPTH; @@ -1650,17 +1650,18 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, return status; } -static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops, +static int acpi_bus_scan(acpi_handle handle, bool start, struct acpi_device **child) { void *device = NULL; acpi_status status; int ret = -ENODEV; - status = acpi_bus_check_add(handle, 0, ops, &device); + status = acpi_bus_check_add(handle, 0, (void *)start, &device); if (ACPI_SUCCESS(status)) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, - acpi_bus_check_add, NULL, ops, &device); + acpi_bus_check_add, NULL, (void *)start, + &device); if (!device) goto out; @@ -1694,9 +1695,7 @@ int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type) { - struct acpi_bus_ops ops = { .acpi_op_add = 1, }; - - return acpi_bus_scan(handle, &ops, child); + return acpi_bus_scan(handle, false, child); } EXPORT_SYMBOL(acpi_bus_add); @@ -1794,12 +1793,10 @@ static int acpi_bus_scan_fixed(void) { int result = 0; struct acpi_device *device = NULL; - struct acpi_bus_ops ops; - - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_add = 1; - ops.acpi_op_start = 1; - ops.acpi_op_match = 1; + struct acpi_bus_ops ops = { + .acpi_op_start = 1, + .acpi_op_match = 1, + }; /* * Enumerate all fixed-feature devices. @@ -1825,11 +1822,6 @@ static int acpi_bus_scan_fixed(void) int __init acpi_scan_init(void) { int result; - struct acpi_bus_ops ops; - - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_add = 1; - ops.acpi_op_start = 1; result = bus_register(&acpi_bus_type); if (result) { @@ -1843,7 +1835,7 @@ int __init acpi_scan_init(void) /* * Enumerate devices in the ACPI namespace. */ - result = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root); + result = acpi_bus_scan(ACPI_ROOT_OBJECT, true, &acpi_root); if (!result) result = acpi_bus_scan_fixed(); -- cgit v1.2.3 From a2d06a1a0851fb3d7e775b9d878cdffb9e0300ee Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:43 +0100 Subject: ACPI: Replace struct acpi_bus_ops with enum type Notice that one member of struct acpi_bus_ops, acpi_op_add, is not used anywhere any more and the relationship between its remaining members, acpi_op_match and acpi_op_start, is such that it doesn't make sense to set the latter without setting the former at the same time. Therefore, replace struct acpi_bus_ops with new a enum type, enum acpi_bus_add_type, with three values, ACPI_BUS_ADD_BASIC, ACPI_BUS_ADD_MATCH, ACPI_BUS_ADD_START, corresponding to both acpi_op_match and acpi_op_start unset, acpi_op_match set and acpi_op_start unset, and both acpi_op_match and acpi_op_start set, respectively. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/scan.c | 35 ++++++++++++----------------------- include/acpi/acpi_bus.h | 15 ++++++++------- 2 files changed, 20 insertions(+), 30 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 8dde0e7f68d8..7082d11ce5d2 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -494,7 +494,7 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv) struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = to_acpi_driver(drv); - return acpi_dev->bus_ops.acpi_op_match + return acpi_dev->add_type >= ACPI_BUS_ADD_MATCH && !acpi_match_device_ids(acpi_dev, acpi_drv->ids); } @@ -580,7 +580,7 @@ static int acpi_device_probe(struct device * dev) ret = acpi_bus_driver_init(acpi_dev, acpi_drv); if (!ret) { - if (acpi_dev->bus_ops.acpi_op_start) + if (acpi_dev->add_type == ACPI_BUS_ADD_START) acpi_start_single_object(acpi_dev); if (acpi_drv->ops.notify) { @@ -1433,7 +1433,7 @@ static void acpi_hot_add_bind(struct acpi_device *device) static int acpi_add_single_object(struct acpi_device **child, acpi_handle handle, int type, unsigned long long sta, - struct acpi_bus_ops *ops) + enum acpi_bus_add_type add_type) { int result; struct acpi_device *device; @@ -1449,7 +1449,7 @@ static int acpi_add_single_object(struct acpi_device **child, device->device_type = type; device->handle = handle; device->parent = acpi_bus_get_parent(handle); - device->bus_ops = *ops; /* workround for not call .start */ + device->add_type = add_type; STRUCT_TO_INT(device->status) = sta; acpi_device_get_busid(device); @@ -1502,7 +1502,7 @@ static int acpi_add_single_object(struct acpi_device **child, result = acpi_device_register(device); - if (device->bus_ops.acpi_op_match) + if (device->add_type >= ACPI_BUS_ADD_MATCH) acpi_hot_add_bind(device); end: @@ -1526,16 +1526,12 @@ end: static void acpi_bus_add_power_resource(acpi_handle handle) { - struct acpi_bus_ops ops = { - .acpi_op_start = 1, - .acpi_op_match = 1, - }; struct acpi_device *device = NULL; acpi_bus_get_device(handle, &device); if (!device) acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER, - ACPI_STA_DEFAULT, &ops); + ACPI_STA_DEFAULT, ACPI_BUS_ADD_START); } static int acpi_bus_type_and_status(acpi_handle handle, int *type, @@ -1604,16 +1600,13 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, acpi_bus_get_device(handle, &device); if (!device) { - struct acpi_bus_ops ops = { - .acpi_op_start = !!context, - .acpi_op_match = 0, - }; - - acpi_add_single_object(&device, handle, type, sta, &ops); + acpi_add_single_object(&device, handle, type, sta, + ACPI_BUS_ADD_BASIC); if (!device) return AE_CTRL_DEPTH; - device->bus_ops.acpi_op_match = 1; + device->add_type = context ? + ACPI_BUS_ADD_START : ACPI_BUS_ADD_MATCH; acpi_hot_add_bind(device); } @@ -1793,10 +1786,6 @@ static int acpi_bus_scan_fixed(void) { int result = 0; struct acpi_device *device = NULL; - struct acpi_bus_ops ops = { - .acpi_op_start = 1, - .acpi_op_match = 1, - }; /* * Enumerate all fixed-feature devices. @@ -1805,7 +1794,7 @@ static int acpi_bus_scan_fixed(void) result = acpi_add_single_object(&device, NULL, ACPI_BUS_TYPE_POWER_BUTTON, ACPI_STA_DEFAULT, - &ops); + ACPI_BUS_ADD_START); device_init_wakeup(&device->dev, true); } @@ -1813,7 +1802,7 @@ static int acpi_bus_scan_fixed(void) result = acpi_add_single_object(&device, NULL, ACPI_BUS_TYPE_SLEEP_BUTTON, ACPI_STA_DEFAULT, - &ops); + ACPI_BUS_ADD_START); } return result; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 016918c16c98..d5294798fdda 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -63,6 +63,13 @@ acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld #define ACPI_BUS_FILE_ROOT "acpi" extern struct proc_dir_entry *acpi_root_dir; +enum acpi_bus_add_type { + ACPI_BUS_ADD_BASIC = 0, + ACPI_BUS_ADD_MATCH, + ACPI_BUS_ADD_START, + ACPI_BUS_ADD_TYPE_COUNT +}; + enum acpi_bus_removal_type { ACPI_BUS_REMOVAL_NORMAL = 0, ACPI_BUS_REMOVAL_EJECT, @@ -95,12 +102,6 @@ typedef int (*acpi_op_bind) (struct acpi_device * device); typedef int (*acpi_op_unbind) (struct acpi_device * device); typedef void (*acpi_op_notify) (struct acpi_device * device, u32 event); -struct acpi_bus_ops { - u32 acpi_op_add:1; - u32 acpi_op_start:1; - u32 acpi_op_match:1; -}; - struct acpi_device_ops { acpi_op_add add; acpi_op_remove remove; @@ -284,7 +285,7 @@ struct acpi_device { struct acpi_driver *driver; void *driver_data; struct device dev; - struct acpi_bus_ops bus_ops; /* workaround for different code path for hotplug */ + enum acpi_bus_add_type add_type; /* how to handle adding */ enum acpi_bus_removal_type removal_type; /* indicate for different removal type */ u8 physical_node_count; struct list_head physical_node_list; -- cgit v1.2.3 From 4002bf384cc567a843a7d16c95db54a7d77b16c6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:44 +0100 Subject: ACPI: Change the ordering of acpi_bus_check_add() If acpi_bus_check_add() is called for a handle already having an existing struct acpi_device object attached, it is not necessary to check the type and status of the device correspondig to it, so change the ordering of acpi_bus_check_add() to avoid that. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/scan.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7082d11ce5d2..eb7ecb1f2032 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1582,6 +1582,10 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, acpi_status status; int result; + acpi_bus_get_device(handle, &device); + if (device) + goto out; + result = acpi_bus_type_and_status(handle, &type, &sta); if (result) return AE_OK; @@ -1598,18 +1602,14 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, return AE_CTRL_DEPTH; } - acpi_bus_get_device(handle, &device); - if (!device) { - acpi_add_single_object(&device, handle, type, sta, - ACPI_BUS_ADD_BASIC); - if (!device) - return AE_CTRL_DEPTH; + acpi_add_single_object(&device, handle, type, sta, ACPI_BUS_ADD_BASIC); + if (!device) + return AE_CTRL_DEPTH; - device->add_type = context ? - ACPI_BUS_ADD_START : ACPI_BUS_ADD_MATCH; - acpi_hot_add_bind(device); - } + device->add_type = context ? ACPI_BUS_ADD_START : ACPI_BUS_ADD_MATCH; + acpi_hot_add_bind(device); + out: if (!*return_value) *return_value = device; -- cgit v1.2.3 From 47525cda88f5cc4dbe24de1cc05617c08e2d7c4a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:45 +0100 Subject: ACPI / PCI: Fold acpi_pci_root_start() into acpi_pci_root_add() Move the code from the ACPI PCI root bridge's .start() callback routine, acpi_pci_root_start(), directly into acpi_pci_root_add() and drop acpi_pci_root_start(). It is safe to do that, because it is now always guaranteed that when struct pci_dev objects are created, their companion struct acpi_device objects are already present, so it is not necessary to wait for them to be created before calling pci_bus_add_devices(). This change was previously proposed in a different form by Yinghai Lu. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/pci_root.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index a233fe93dfac..0e593a203ff8 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -47,7 +47,6 @@ ACPI_MODULE_NAME("pci_root"); #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" static int acpi_pci_root_add(struct acpi_device *device); static int acpi_pci_root_remove(struct acpi_device *device, int type); -static int acpi_pci_root_start(struct acpi_device *device); #define ACPI_PCIE_REQ_SUPPORT (OSC_EXT_PCI_CONFIG_SUPPORT \ | OSC_ACTIVE_STATE_PWR_SUPPORT \ @@ -67,7 +66,6 @@ static struct acpi_driver acpi_pci_root_driver = { .ops = { .add = acpi_pci_root_add, .remove = acpi_pci_root_remove, - .start = acpi_pci_root_start, }, }; @@ -453,6 +451,7 @@ static int acpi_pci_root_add(struct acpi_device *device) struct acpi_pci_root *root; acpi_handle handle; struct acpi_device *child; + struct acpi_pci_driver *driver; u32 flags, base_flags; bool is_osc_granted = false; @@ -632,24 +631,6 @@ static int acpi_pci_root_add(struct acpi_device *device) if (device->wakeup.flags.run_wake) device_set_run_wake(root->bus->bridge, true); - return 0; - -out_del_root: - mutex_lock(&acpi_pci_root_lock); - list_del(&root->node); - mutex_unlock(&acpi_pci_root_lock); - - acpi_pci_irq_del_prt(root->segment, root->secondary.start); -end: - kfree(root); - return result; -} - -static int acpi_pci_root_start(struct acpi_device *device) -{ - struct acpi_pci_root *root = acpi_driver_data(device); - struct acpi_pci_driver *driver; - if (system_state != SYSTEM_BOOTING) pci_assign_unassigned_bus_resources(root->bus); @@ -664,8 +645,17 @@ static int acpi_pci_root_start(struct acpi_device *device) pci_enable_bridges(root->bus); pci_bus_add_devices(root->bus); - return 0; + +out_del_root: + mutex_lock(&acpi_pci_root_lock); + list_del(&root->node); + mutex_unlock(&acpi_pci_root_lock); + + acpi_pci_irq_del_prt(root->segment, root->secondary.start); +end: + kfree(root); + return result; } static int acpi_pci_root_remove(struct acpi_device *device, int type) -- cgit v1.2.3 From 02f57c67a8677ae55dcdd256a2a7abaf41e4cc1f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:46 +0100 Subject: ACPI: Remove acpi_start_single_object() and acpi_bus_start() The ACPI PCI root bridge driver was the only ACPI driver implementing the .start() callback, which isn't used by any ACPI drivers any more now. For this reason, acpi_start_single_object() has no purpose any more, so remove it and all references to it. Also remove acpi_bus_start_device(), whose only purpose was to call acpi_start_single_object(). Moreover, since after the removal of acpi_bus_start_device() the only purpose of acpi_bus_start() remains to call acpi_update_all_gpes(), move that into acpi_bus_add() and drop acpi_bus_start() too, remove its header from acpi_bus.h and update all of its former users accordingly. This change was previously proposed in a different from by Yinghai Lu. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/container.c | 16 ++------- drivers/acpi/scan.c | 66 +++++--------------------------------- drivers/pci/hotplug/acpiphp_glue.c | 4 +-- drivers/pci/hotplug/sgi_hotplug.c | 2 -- include/acpi/acpi_bus.h | 1 - 5 files changed, 12 insertions(+), 77 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 811910b50b75..98b85e3e4781 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -139,24 +139,14 @@ static int container_device_add(struct acpi_device **device, acpi_handle handle) { acpi_handle phandle; struct acpi_device *pdev; - int result; - - - if (acpi_get_parent(handle, &phandle)) { - return -ENODEV; - } - if (acpi_bus_get_device(phandle, &pdev)) { + if (acpi_get_parent(handle, &phandle)) return -ENODEV; - } - if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) { + if (acpi_bus_get_device(phandle, &pdev)) return -ENODEV; - } - - result = acpi_bus_start(*device); - return result; + return acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE); } static void container_notify_cb(acpi_handle handle, u32 type, void *context) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index eb7ecb1f2032..6321cab4e5ff 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -571,7 +571,6 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device) } static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *); -static int acpi_start_single_object(struct acpi_device *); static int acpi_device_probe(struct device * dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); @@ -580,9 +579,6 @@ static int acpi_device_probe(struct device * dev) ret = acpi_bus_driver_init(acpi_dev, acpi_drv); if (!ret) { - if (acpi_dev->add_type == ACPI_BUS_ADD_START) - acpi_start_single_object(acpi_dev); - if (acpi_drv->ops.notify) { ret = acpi_device_install_notify_handler(acpi_dev); if (ret) { @@ -761,24 +757,6 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) return 0; } -static int acpi_start_single_object(struct acpi_device *device) -{ - int result = 0; - struct acpi_driver *driver; - - - if (!(driver = device->driver)) - return 0; - - if (driver->ops.start) { - result = driver->ops.start(device); - if (result && driver->ops.remove) - driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); - } - - return result; -} - /** * acpi_bus_register_driver - register a driver with the ACPI bus * @driver: driver being registered @@ -1673,59 +1651,31 @@ static int acpi_bus_scan(acpi_handle handle, bool start, } /* - * acpi_bus_add and acpi_bus_start + * acpi_bus_add * * scan a given ACPI tree and (probably recently hot-plugged) - * create and add or starts found devices. + * create and add found devices. * * If no devices were found -ENODEV is returned which does not * mean that this is a real error, there just have been no suitable * ACPI objects in the table trunk from which the kernel could create - * a device and add/start an appropriate driver. + * a device and add an appropriate driver. */ int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type) { - return acpi_bus_scan(handle, false, child); -} -EXPORT_SYMBOL(acpi_bus_add); - -static acpi_status acpi_bus_start_device(acpi_handle handle, u32 lvl, - void *not_used, void **ret_not_used) -{ - struct acpi_device *device; - unsigned long long sta_not_used; - int type_not_used; - - /* - * Ignore errors ignored by acpi_bus_check_add() to avoid terminating - * namespace walks prematurely. - */ - if (acpi_bus_type_and_status(handle, &type_not_used, &sta_not_used)) - return AE_OK; - - if (acpi_bus_get_device(handle, &device)) - return AE_CTRL_DEPTH; - - return acpi_start_single_object(device); -} - -int acpi_bus_start(struct acpi_device *device) -{ - if (!device) - return -EINVAL; + int err; - if (ACPI_SUCCESS(acpi_start_single_object(device))) - acpi_walk_namespace(ACPI_TYPE_ANY, device->handle, - ACPI_UINT32_MAX, acpi_bus_start_device, - NULL, NULL, NULL); + err = acpi_bus_scan(handle, false, child); + if (err) + return err; acpi_update_all_gpes(); return 0; } -EXPORT_SYMBOL(acpi_bus_start); +EXPORT_SYMBOL(acpi_bus_add); int acpi_bus_trim(struct acpi_device *start, int rmdevice) { diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 3d6d4fd1e3c5..7e2bad4c2fcc 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -759,7 +759,6 @@ static int acpiphp_bus_add(struct acpiphp_func *func) -ret_val); goto acpiphp_bus_add_out; } - ret_val = acpi_bus_start(device); acpiphp_bus_add_out: return ret_val; @@ -1148,8 +1147,7 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type) err("cannot add bridge to acpi list\n"); return; } - if (!acpiphp_configure_bridge(handle) && - !acpi_bus_start(device)) + if (!acpiphp_configure_bridge(handle)) add_bridge(handle); else err("cannot configure and start bridge\n"); diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index f64ca92253da..20c960d5317d 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -457,8 +457,6 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) ret, (int)(adr>>16), (int)(adr&0xffff)); /* try to continue on */ - } else { - acpi_bus_start(device); } } } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index d5294798fdda..6d47a584c0bc 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -362,7 +362,6 @@ int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type); void acpi_bus_hot_remove_device(void *context); int acpi_bus_trim(struct acpi_device *start, int rmdevice); -int acpi_bus_start(struct acpi_device *device); acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd); int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids); -- cgit v1.2.3 From 636458de36f1fb4cdd318387d2f45604e451b17a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:47 +0100 Subject: ACPI: Remove the arguments of acpi_bus_add() that are not used Notice that acpi_bus_add() uses only 2 of its 4 arguments and redefine its header to match the body. Update all of its callers as necessary and observe that this leads to quite a number of removed lines of code (Linus will like that). Add a kerneldoc comment documenting acpi_bus_add() and wonder how its callers make wrong assumptions about the second argument (make note to self to take care of that later). Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/acpi_memhotplug.c | 19 +------------------ drivers/acpi/container.c | 16 +--------------- drivers/acpi/dock.c | 13 ++----------- drivers/acpi/processor_driver.c | 24 +----------------------- drivers/acpi/scan.c | 34 +++++++++++++++++++++------------- drivers/pci/hotplug/acpiphp_glue.c | 21 ++++----------------- drivers/pci/hotplug/sgi_hotplug.c | 3 +-- include/acpi/acpi_bus.h | 3 +-- 8 files changed, 32 insertions(+), 101 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index eb30e5ab4cab..d0a7da704d49 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -157,34 +157,17 @@ static int acpi_memory_get_device(acpi_handle handle, struct acpi_memory_device **mem_device) { - acpi_status status; - acpi_handle phandle; struct acpi_device *device = NULL; - struct acpi_device *pdevice = NULL; int result; - if (!acpi_bus_get_device(handle, &device) && device) goto end; - status = acpi_get_parent(handle, &phandle); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Cannot find acpi parent")); - return -EINVAL; - } - - /* Get the parent device */ - result = acpi_bus_get_device(phandle, &pdevice); - if (result) { - acpi_handle_warn(phandle, "Cannot get acpi bus device\n"); - return -EINVAL; - } - /* * Now add the notified device. This creates the acpi_device * and invokes .add function */ - result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE); + result = acpi_bus_add(handle, &device); if (result) { acpi_handle_warn(handle, "Cannot add acpi bus\n"); return -EINVAL; diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 98b85e3e4781..0688f83bc436 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -135,20 +135,6 @@ static int acpi_container_remove(struct acpi_device *device, int type) return status; } -static int container_device_add(struct acpi_device **device, acpi_handle handle) -{ - acpi_handle phandle; - struct acpi_device *pdev; - - if (acpi_get_parent(handle, &phandle)) - return -ENODEV; - - if (acpi_bus_get_device(phandle, &pdev)) - return -ENODEV; - - return acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE); -} - static void container_notify_cb(acpi_handle handle, u32 type, void *context) { struct acpi_device *device = NULL; @@ -180,7 +166,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context) if (!ACPI_FAILURE(status) || device) break; - result = container_device_add(&device, handle); + result = acpi_bus_add(handle, &device); if (result) { acpi_handle_warn(handle, "Failed to add container\n"); break; diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index f32bd47b35e0..ff30582d2e1d 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -310,8 +310,6 @@ static int dock_present(struct dock_station *ds) static struct acpi_device * dock_create_acpi_device(acpi_handle handle) { struct acpi_device *device; - struct acpi_device *parent_device; - acpi_handle parent; int ret; if (acpi_bus_get_device(handle, &device)) { @@ -319,16 +317,9 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle) * no device created for this object, * so we should create one. */ - acpi_get_parent(handle, &parent); - if (acpi_bus_get_device(parent, &parent_device)) - parent_device = NULL; - - ret = acpi_bus_add(&device, parent_device, handle, - ACPI_BUS_TYPE_DEVICE); - if (ret) { + ret = acpi_bus_add(handle, &device); + if (ret) pr_debug("error adding bus, %x\n", -ret); - return NULL; - } } return device; } diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index e83311bf1ebd..18b292e12b38 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -677,28 +677,6 @@ static int is_processor_present(acpi_handle handle) return 0; } -static -int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) -{ - acpi_handle phandle; - struct acpi_device *pdev; - - - if (acpi_get_parent(handle, &phandle)) { - return -ENODEV; - } - - if (acpi_bus_get_device(phandle, &pdev)) { - return -ENODEV; - } - - if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) { - return -ENODEV; - } - - return 0; -} - static void acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) { @@ -721,7 +699,7 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, if (!acpi_bus_get_device(handle, &device)) break; - result = acpi_processor_device_add(handle, &device); + result = acpi_bus_add(handle, &device); if (result) { acpi_handle_err(handle, "Unable to add the device\n"); break; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 6321cab4e5ff..25095bf57bba 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1650,25 +1650,33 @@ static int acpi_bus_scan(acpi_handle handle, bool start, return ret; } -/* - * acpi_bus_add +/** + * acpi_bus_add - Add ACPI device node objects in a given namespace scope. + * @handle: Root of the namespace scope to scan. + * @ret: Location to store a return struct acpi_device pointer. + * + * Scan a given ACPI tree (probably recently hot-plugged) and create and add + * found devices. * - * scan a given ACPI tree and (probably recently hot-plugged) - * create and add found devices. + * If no devices were found, -ENODEV is returned, but it does not mean that + * there has been a real error. There just have been no suitable ACPI objects + * in the table trunk from which the kernel could create a device and add an + * appropriate driver. * - * If no devices were found -ENODEV is returned which does not - * mean that this is a real error, there just have been no suitable - * ACPI objects in the table trunk from which the kernel could create - * a device and add an appropriate driver. + * If 0 is returned, the memory location pointed to by @ret will be populated + * with a pointer to a struct acpi_device created while scanning the namespace. + * If @handle corresponds to a device node, that will be a pointer to the struct + * acpi_device object corresponding to @handle. Otherwise, it will be a pointer + * to a struct acpi_device corresponding to one of its descendants. + * + * If an error code is returned, NULL will be stored in the memory location + * pointed to by @ret. */ - -int -acpi_bus_add(struct acpi_device **child, - struct acpi_device *parent, acpi_handle handle, int type) +int acpi_bus_add(acpi_handle handle, struct acpi_device **ret) { int err; - err = acpi_bus_scan(handle, false, child); + err = acpi_bus_scan(handle, false, ret); if (err) return err; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 7e2bad4c2fcc..dfc2df54b93a 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -734,15 +734,9 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) */ static int acpiphp_bus_add(struct acpiphp_func *func) { - acpi_handle phandle; - struct acpi_device *device, *pdevice; + struct acpi_device *device; int ret_val; - acpi_get_parent(func->handle, &phandle); - if (acpi_bus_get_device(phandle, &pdevice)) { - dbg("no parent device, assuming NULL\n"); - pdevice = NULL; - } if (!acpi_bus_get_device(func->handle, &device)) { dbg("bus exists... trim\n"); /* this shouldn't be in here, so remove @@ -752,8 +746,7 @@ static int acpiphp_bus_add(struct acpiphp_func *func) dbg("acpi_bus_trim return %x\n", ret_val); } - ret_val = acpi_bus_add(&device, pdevice, func->handle, - ACPI_BUS_TYPE_DEVICE); + ret_val = acpi_bus_add(func->handle, &device); if (ret_val) { dbg("error adding bus, %x\n", -ret_val); @@ -1129,8 +1122,7 @@ static int acpiphp_configure_bridge (acpi_handle handle) static void handle_bridge_insertion(acpi_handle handle, u32 type) { - struct acpi_device *device, *pdevice; - acpi_handle phandle; + struct acpi_device *device; if ((type != ACPI_NOTIFY_BUS_CHECK) && (type != ACPI_NOTIFY_DEVICE_CHECK)) { @@ -1138,12 +1130,7 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type) return; } - acpi_get_parent(handle, &phandle); - if (acpi_bus_get_device(phandle, &pdevice)) { - dbg("no parent device, assuming NULL\n"); - pdevice = NULL; - } - if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) { + if (acpi_bus_add(handle, &device)) { err("cannot add bridge to acpi list\n"); return; } diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 20c960d5317d..801b58d1f78e 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -448,8 +448,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) if (ACPI_SUCCESS(ret) && (adr>>16) == (slot->device_num + 1)) { - ret = acpi_bus_add(&device, pdevice, chandle, - ACPI_BUS_TYPE_DEVICE); + ret = acpi_bus_add(chandle, &device); if (ACPI_FAILURE(ret)) { printk(KERN_ERR "%s: acpi_bus_add " "failed (0x%x) for slot %d " diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 6d47a584c0bc..75c6b3f2250d 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -358,8 +358,7 @@ static inline int acpi_bus_generate_proc_event(struct acpi_device *device, u8 ty #endif int acpi_bus_register_driver(struct acpi_driver *driver); void acpi_bus_unregister_driver(struct acpi_driver *driver); -int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, - acpi_handle handle, int type); +int acpi_bus_add(acpi_handle handle, struct acpi_device **ret); void acpi_bus_hot_remove_device(void *context); int acpi_bus_trim(struct acpi_device *start, int rmdevice); acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd); -- cgit v1.2.3 From e3863094c6f9b2f980d6e7a5cad6b4d03a4dd579 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:47 +0100 Subject: ACPI: Drop the second argument of acpi_bus_scan() After the removal of acpi_start_single_object() and acpi_bus_start() the second argument of acpi_bus_scan() is not necessary any more, so drop it and update acpi_bus_check_add() accordingly. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/scan.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 25095bf57bba..eb54f98bb728 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1551,8 +1551,8 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, return 0; } -static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, - void *context, void **return_value) +static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, + void *not_used, void **return_value) { struct acpi_device *device = NULL; int type; @@ -1584,7 +1584,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, if (!device) return AE_CTRL_DEPTH; - device->add_type = context ? ACPI_BUS_ADD_START : ACPI_BUS_ADD_MATCH; + device->add_type = ACPI_BUS_ADD_START; acpi_hot_add_bind(device); out: @@ -1621,18 +1621,16 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, return status; } -static int acpi_bus_scan(acpi_handle handle, bool start, - struct acpi_device **child) +static int acpi_bus_scan(acpi_handle handle, struct acpi_device **child) { void *device = NULL; acpi_status status; int ret = -ENODEV; - status = acpi_bus_check_add(handle, 0, (void *)start, &device); + status = acpi_bus_check_add(handle, 0, NULL, &device); if (ACPI_SUCCESS(status)) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, - acpi_bus_check_add, NULL, (void *)start, - &device); + acpi_bus_check_add, NULL, NULL, &device); if (!device) goto out; @@ -1676,7 +1674,7 @@ int acpi_bus_add(acpi_handle handle, struct acpi_device **ret) { int err; - err = acpi_bus_scan(handle, false, ret); + err = acpi_bus_scan(handle, ret); if (err) return err; @@ -1782,7 +1780,7 @@ int __init acpi_scan_init(void) /* * Enumerate devices in the ACPI namespace. */ - result = acpi_bus_scan(ACPI_ROOT_OBJECT, true, &acpi_root); + result = acpi_bus_scan(ACPI_ROOT_OBJECT, &acpi_root); if (!result) result = acpi_bus_scan_fixed(); -- cgit v1.2.3 From 209d3b1743c8187c67cc75dbe9fefbcd3121fba0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:48 +0100 Subject: ACPI: Replace ACPI device add_type field with a match_driver flag After the removal of the second argument of acpi_bus_scan() there is no difference between the ACPI_BUS_ADD_MATCH and ACPI_BUS_ADD_START add types, so the add_type field in struct acpi_device may be replaced with a single flag. Do that calling the flag match_driver. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/scan.c | 21 +++++++++------------ include/acpi/acpi_bus.h | 11 ++--------- 2 files changed, 11 insertions(+), 21 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index eb54f98bb728..e3aed481aed2 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -494,7 +494,7 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv) struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = to_acpi_driver(drv); - return acpi_dev->add_type >= ACPI_BUS_ADD_MATCH + return acpi_dev->flags.match_driver && !acpi_match_device_ids(acpi_dev, acpi_drv->ids); } @@ -1410,8 +1410,7 @@ static void acpi_hot_add_bind(struct acpi_device *device) static int acpi_add_single_object(struct acpi_device **child, acpi_handle handle, int type, - unsigned long long sta, - enum acpi_bus_add_type add_type) + unsigned long long sta, bool match_driver) { int result; struct acpi_device *device; @@ -1427,7 +1426,6 @@ static int acpi_add_single_object(struct acpi_device **child, device->device_type = type; device->handle = handle; device->parent = acpi_bus_get_parent(handle); - device->add_type = add_type; STRUCT_TO_INT(device->status) = sta; acpi_device_get_busid(device); @@ -1478,9 +1476,10 @@ static int acpi_add_single_object(struct acpi_device **child, if ((result = acpi_device_set_context(device))) goto end; + device->flags.match_driver = match_driver; result = acpi_device_register(device); - if (device->add_type >= ACPI_BUS_ADD_MATCH) + if (device->flags.match_driver) acpi_hot_add_bind(device); end: @@ -1509,7 +1508,7 @@ static void acpi_bus_add_power_resource(acpi_handle handle) acpi_bus_get_device(handle, &device); if (!device) acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER, - ACPI_STA_DEFAULT, ACPI_BUS_ADD_START); + ACPI_STA_DEFAULT, true); } static int acpi_bus_type_and_status(acpi_handle handle, int *type, @@ -1580,11 +1579,11 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, return AE_CTRL_DEPTH; } - acpi_add_single_object(&device, handle, type, sta, ACPI_BUS_ADD_BASIC); + acpi_add_single_object(&device, handle, type, sta, false); if (!device) return AE_CTRL_DEPTH; - device->add_type = ACPI_BUS_ADD_START; + device->flags.match_driver = true; acpi_hot_add_bind(device); out: @@ -1749,16 +1748,14 @@ static int acpi_bus_scan_fixed(void) if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) { result = acpi_add_single_object(&device, NULL, ACPI_BUS_TYPE_POWER_BUTTON, - ACPI_STA_DEFAULT, - ACPI_BUS_ADD_START); + ACPI_STA_DEFAULT, true); device_init_wakeup(&device->dev, true); } if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { result = acpi_add_single_object(&device, NULL, ACPI_BUS_TYPE_SLEEP_BUTTON, - ACPI_STA_DEFAULT, - ACPI_BUS_ADD_START); + ACPI_STA_DEFAULT, true); } return result; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 75c6b3f2250d..056cb0cd8eff 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -63,13 +63,6 @@ acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld #define ACPI_BUS_FILE_ROOT "acpi" extern struct proc_dir_entry *acpi_root_dir; -enum acpi_bus_add_type { - ACPI_BUS_ADD_BASIC = 0, - ACPI_BUS_ADD_MATCH, - ACPI_BUS_ADD_START, - ACPI_BUS_ADD_TYPE_COUNT -}; - enum acpi_bus_removal_type { ACPI_BUS_REMOVAL_NORMAL = 0, ACPI_BUS_REMOVAL_EJECT, @@ -150,7 +143,8 @@ struct acpi_device_flags { u32 power_manageable:1; u32 performance_manageable:1; u32 eject_pending:1; - u32 reserved:24; + u32 match_driver:1; + u32 reserved:23; }; /* File System */ @@ -285,7 +279,6 @@ struct acpi_device { struct acpi_driver *driver; void *driver_data; struct device dev; - enum acpi_bus_add_type add_type; /* how to handle adding */ enum acpi_bus_removal_type removal_type; /* indicate for different removal type */ u8 physical_node_count; struct list_head physical_node_list; -- cgit v1.2.3 From 0cd6ac52b333f66ee64e50ed216ec99231092dcd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Dec 2012 00:36:49 +0100 Subject: ACPI: Make acpi_bus_scan() and acpi_bus_add() take only one argument The callers of acpi_bus_add() usually assume that if it has succeeded, then a struct acpi_device object has been attached to the handle passed as the first argument. Unfortunately, however, this assumption is wrong, because acpi_bus_scan(), and acpi_bus_add() too as a result, may return a pointer to a different struct acpi_device object on success (it may be an object corresponding to one of the descendant ACPI nodes in the namespace scope below that handle). For this reason, the callers of acpi_bus_add() who care about whether or not a struct acpi_device object has been created for its first argument need to check that using acpi_bus_get_device() anyway, so the second argument of acpi_bus_add() is not really useful for them. The same observation applies to acpi_bus_scan() executed directly from acpi_scan_init(). Therefore modify the relevant callers of acpi_bus_add() to check the existence of the struct acpi_device in question with the help of acpi_bus_get_device() and drop the no longer necessary second argument of acpi_bus_add(). Accordingly, modify acpi_scan_init() to use acpi_bus_get_device() to get acpi_root and drop the no longer needed second argument of acpi_bus_scan(). Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/acpi_memhotplug.c | 7 ++++++- drivers/acpi/container.c | 7 ++++++- drivers/acpi/dock.c | 4 +++- drivers/acpi/processor_driver.c | 8 ++++++-- drivers/acpi/scan.c | 38 +++++++++++--------------------------- drivers/pci/hotplug/acpiphp_glue.c | 19 +++++++++++-------- drivers/pci/hotplug/sgi_hotplug.c | 3 +-- include/acpi/acpi_bus.h | 2 +- 8 files changed, 45 insertions(+), 43 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index d0a7da704d49..327ab4459558 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -167,11 +167,16 @@ acpi_memory_get_device(acpi_handle handle, * Now add the notified device. This creates the acpi_device * and invokes .add function */ - result = acpi_bus_add(handle, &device); + result = acpi_bus_add(handle); if (result) { acpi_handle_warn(handle, "Cannot add acpi bus\n"); return -EINVAL; } + result = acpi_bus_get_device(handle, &device); + if (result) { + acpi_handle_warn(handle, "Missing device object\n"); + return -EINVAL; + } end: *mem_device = acpi_driver_data(device); diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 0688f83bc436..f8fb2281f34a 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -166,11 +166,16 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context) if (!ACPI_FAILURE(status) || device) break; - result = acpi_bus_add(handle, &device); + result = acpi_bus_add(handle); if (result) { acpi_handle_warn(handle, "Failed to add container\n"); break; } + result = acpi_bus_get_device(handle, &device); + if (result) { + acpi_handle_warn(handle, "Missing device object\n"); + break; + } kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); ost_code = ACPI_OST_SC_SUCCESS; diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index ff30582d2e1d..9e31b2bd93d3 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -317,9 +317,11 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle) * no device created for this object, * so we should create one. */ - ret = acpi_bus_add(handle, &device); + ret = acpi_bus_add(handle); if (ret) pr_debug("error adding bus, %x\n", -ret); + + acpi_bus_get_device(handle, &device); } return device; } diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 18b292e12b38..0777663f443e 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -699,12 +699,16 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, if (!acpi_bus_get_device(handle, &device)) break; - result = acpi_bus_add(handle, &device); + result = acpi_bus_add(handle); if (result) { acpi_handle_err(handle, "Unable to add the device\n"); break; } - + result = acpi_bus_get_device(handle, &device); + if (result) { + acpi_handle_err(handle, "Missing device object\n"); + break; + } ost_code = ACPI_OST_SC_SUCCESS; break; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e3aed481aed2..3d44c705a3a2 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1620,37 +1620,27 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, return status; } -static int acpi_bus_scan(acpi_handle handle, struct acpi_device **child) +static int acpi_bus_scan(acpi_handle handle) { void *device = NULL; - acpi_status status; - int ret = -ENODEV; - status = acpi_bus_check_add(handle, 0, NULL, &device); - if (ACPI_SUCCESS(status)) + if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device))) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_check_add, NULL, NULL, &device); if (!device) - goto out; + return -ENODEV; - ret = 0; - status = acpi_bus_device_attach(handle, 0, NULL, NULL); - if (ACPI_SUCCESS(status)) + if (ACPI_SUCCESS(acpi_bus_device_attach(handle, 0, NULL, NULL))) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_device_attach, NULL, NULL, NULL); - out: - if (child) - *child = device; - - return ret; + return 0; } /** * acpi_bus_add - Add ACPI device node objects in a given namespace scope. * @handle: Root of the namespace scope to scan. - * @ret: Location to store a return struct acpi_device pointer. * * Scan a given ACPI tree (probably recently hot-plugged) and create and add * found devices. @@ -1659,21 +1649,12 @@ static int acpi_bus_scan(acpi_handle handle, struct acpi_device **child) * there has been a real error. There just have been no suitable ACPI objects * in the table trunk from which the kernel could create a device and add an * appropriate driver. - * - * If 0 is returned, the memory location pointed to by @ret will be populated - * with a pointer to a struct acpi_device created while scanning the namespace. - * If @handle corresponds to a device node, that will be a pointer to the struct - * acpi_device object corresponding to @handle. Otherwise, it will be a pointer - * to a struct acpi_device corresponding to one of its descendants. - * - * If an error code is returned, NULL will be stored in the memory location - * pointed to by @ret. */ -int acpi_bus_add(acpi_handle handle, struct acpi_device **ret) +int acpi_bus_add(acpi_handle handle) { int err; - err = acpi_bus_scan(handle, ret); + err = acpi_bus_scan(handle); if (err) return err; @@ -1777,8 +1758,11 @@ int __init acpi_scan_init(void) /* * Enumerate devices in the ACPI namespace. */ - result = acpi_bus_scan(ACPI_ROOT_OBJECT, &acpi_root); + result = acpi_bus_scan(ACPI_ROOT_OBJECT); + if (result) + return result; + result = acpi_bus_get_device(ACPI_ROOT_OBJECT, &acpi_root); if (!result) result = acpi_bus_scan_fixed(); diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index dfc2df54b93a..91b5ad875c53 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -746,14 +746,13 @@ static int acpiphp_bus_add(struct acpiphp_func *func) dbg("acpi_bus_trim return %x\n", ret_val); } - ret_val = acpi_bus_add(func->handle, &device); - if (ret_val) { - dbg("error adding bus, %x\n", - -ret_val); - goto acpiphp_bus_add_out; - } + ret_val = acpi_bus_add(func->handle); + if (!ret_val) + ret_val = acpi_bus_get_device(func->handle, &device); + + if (ret_val) + dbg("error adding bus, %x\n", -ret_val); -acpiphp_bus_add_out: return ret_val; } @@ -1130,10 +1129,14 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type) return; } - if (acpi_bus_add(handle, &device)) { + if (acpi_bus_add(handle)) { err("cannot add bridge to acpi list\n"); return; } + if (acpi_bus_get_device(handle, &device)) { + err("ACPI device object missing\n"); + return; + } if (!acpiphp_configure_bridge(handle)) add_bridge(handle); else diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 801b58d1f78e..f3c419256d2a 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -412,7 +412,6 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) if (SN_ACPI_BASE_SUPPORT() && ssdt) { unsigned long long adr; struct acpi_device *pdevice; - struct acpi_device *device; acpi_handle phandle; acpi_handle chandle = NULL; acpi_handle rethandle; @@ -448,7 +447,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) if (ACPI_SUCCESS(ret) && (adr>>16) == (slot->device_num + 1)) { - ret = acpi_bus_add(chandle, &device); + ret = acpi_bus_add(chandle); if (ACPI_FAILURE(ret)) { printk(KERN_ERR "%s: acpi_bus_add " "failed (0x%x) for slot %d " diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 056cb0cd8eff..5e1d5a1b477f 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -351,7 +351,7 @@ static inline int acpi_bus_generate_proc_event(struct acpi_device *device, u8 ty #endif int acpi_bus_register_driver(struct acpi_driver *driver); void acpi_bus_unregister_driver(struct acpi_driver *driver); -int acpi_bus_add(acpi_handle handle, struct acpi_device **ret); +int acpi_bus_add(acpi_handle handle); void acpi_bus_hot_remove_device(void *context); int acpi_bus_trim(struct acpi_device *start, int rmdevice); acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd); -- cgit v1.2.3 From 11909ca1cf614f9396b17d366f9e3cfcba7b4a99 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 23 Dec 2012 00:02:13 +0100 Subject: ACPI: Add .setup() and .cleanup() callbacks to struct acpi_bus_type Add two new callbacks,.setup() and .cleanup(), struct acpi_bus_type and modify acpi_platform_notify() to call .setup() after executing acpi_bind_one() successfully and acpi_platform_notify_remove() to call .cleanup() before running acpi_unbind_one(). This will allow the users of struct acpi_bus_type, PCI in particular, to specify operations to be executed right after the given device has been associated with a companion struct acpi_device and right before it's going to be detached from that companion, respectively. The main motivation is to be able to get rid of acpi_pci_bind() and acpi_pci_unbind(), which are horrible horrible stuff. [In short, there are three problems with them: The way they populate the .bind() and .unbind() callbacks of ACPI devices is rather less than straightforward, they require special hotplug-specific paths to be present in the ACPI namespace scanning code and by the time acpi_pci_unbind() is called the PCI device object in question may not exist any more.] Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/glue.c | 50 ++++++++++++++++++++++++++++++++++--------------- include/acpi/acpi_bus.h | 2 ++ 2 files changed, 37 insertions(+), 15 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 01551840d236..ac00b882e75d 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -63,6 +63,9 @@ static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type) { struct acpi_bus_type *tmp, *ret = NULL; + if (!type) + return NULL; + down_read(&bus_type_sem); list_for_each_entry(tmp, &bus_type_list, list) { if (tmp->bus == type) { @@ -264,28 +267,39 @@ static int acpi_platform_notify(struct device *dev) { struct acpi_bus_type *type; acpi_handle handle; - int ret = -EINVAL; + int ret; ret = acpi_bind_one(dev, NULL); - if (!ret) - goto out; - - if (!dev->bus || !dev->parent) { + if (ret && (!dev->bus || !dev->parent)) { /* bridge devices genernally haven't bus or parent */ ret = acpi_find_bridge_device(dev, &handle); - goto end; + if (!ret) { + ret = acpi_bind_one(dev, handle); + if (ret) + goto out; + } } + type = acpi_get_bus_type(dev->bus); - if (!type) { - DBG("No ACPI bus support for %s\n", dev_name(dev)); - ret = -EINVAL; - goto end; + if (ret) { + if (!type || !type->find_device) { + DBG("No ACPI bus support for %s\n", dev_name(dev)); + ret = -EINVAL; + goto out; + } + + ret = type->find_device(dev, &handle); + if (ret) { + DBG("Unable to get handle for %s\n", dev_name(dev)); + goto out; + } + ret = acpi_bind_one(dev, handle); + if (ret) + goto out; } - if ((ret = type->find_device(dev, &handle)) != 0) - DBG("Can't get handler for %s\n", dev_name(dev)); - end: - if (!ret) - acpi_bind_one(dev, handle); + + if (type && type->setup) + type->setup(dev); out: #if ACPI_GLUE_DEBUG @@ -304,6 +318,12 @@ static int acpi_platform_notify(struct device *dev) static int acpi_platform_notify_remove(struct device *dev) { + struct acpi_bus_type *type; + + type = acpi_get_bus_type(dev->bus); + if (type && type->cleanup) + type->cleanup(dev); + acpi_unbind_one(dev); return 0; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 5e1d5a1b477f..70647313a9bc 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -383,6 +383,8 @@ struct acpi_bus_type { int (*find_device) (struct device *, acpi_handle *); /* For bridges, such as PCI root bridge, IDE controller */ int (*find_bridge) (struct device *, acpi_handle *); + void (*setup)(struct device *); + void (*cleanup)(struct device *); }; int register_acpi_bus_type(struct acpi_bus_type *); int unregister_acpi_bus_type(struct acpi_bus_type *); -- cgit v1.2.3 From d2e5f0c16ad60a7208fd371233e63b73c990ece2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 23 Dec 2012 00:02:44 +0100 Subject: ACPI / PCI: Rework the setup and cleanup of device wakeup Currently, the ACPI wakeup capability of PCI devices is set up in two different places, partially in acpi_pci_bind() where runtime wakeup is initialized and partially in platform_pci_wakeup_init(), where system wakeup is initialized. The cleanup is only done in acpi_pci_unbind() and it only covers runtime wakeup. Use the new .setup() and .cleanup() callbacks in struct acpi_bus_type to consolidate that code and do the setup and the cleanup each in one place. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/device_pm.c | 2 +- drivers/acpi/pci_bind.c | 5 ----- drivers/pci/pci-acpi.c | 30 +++++++++++++++++++++++++++++- drivers/pci/pci.c | 26 +------------------------- drivers/pci/pci.h | 5 ----- drivers/pci/probe.c | 1 - include/linux/acpi.h | 5 +++++ 7 files changed, 36 insertions(+), 38 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index f09dc987cf17..e4f6ac95595c 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -353,7 +353,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) * acpi_dev_pm_get_node - Get ACPI device node for the given physical device. * @dev: Device to get the ACPI node for. */ -static struct acpi_device *acpi_dev_pm_get_node(struct device *dev) +struct acpi_device *acpi_dev_pm_get_node(struct device *dev) { acpi_handle handle = DEVICE_ACPI_HANDLE(dev); struct acpi_device *adev; diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index a1dee29beed3..bbddcc9c894f 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -43,8 +43,6 @@ static int acpi_pci_unbind(struct acpi_device *device) if (!dev) goto out; - device_set_run_wake(&dev->dev, false); - pci_acpi_remove_pm_notifier(device); acpi_power_resource_unregister_device(&dev->dev, device->handle); if (!dev->subordinate) @@ -71,10 +69,7 @@ static int acpi_pci_bind(struct acpi_device *device) if (!dev) return 0; - pci_acpi_add_pm_notifier(device, dev); acpi_power_resource_register_device(&dev->dev, device->handle); - if (device->wakeup.flags.run_wake) - device_set_run_wake(&dev->dev, true); /* * Install the 'bind' function to facilitate callbacks for diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 1af4008182fd..b98106c110e7 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -283,7 +283,6 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = { .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .choose_state = acpi_pci_choose_state, - .can_wakeup = acpi_pci_can_wakeup, .sleep_wake = acpi_pci_sleep_wake, .run_wake = acpi_pci_run_wake, }; @@ -321,10 +320,39 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) return 0; } +static void acpi_pci_wakeup_setup(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct pci_dev *pci_dev = to_pci_dev(dev); + + if (!adev || !adev->wakeup.flags.valid) + return; + + device_set_wakeup_capable(dev, true); + acpi_pci_sleep_wake(pci_dev, false); + + pci_acpi_add_pm_notifier(adev, pci_dev); + if (adev->wakeup.flags.run_wake) + device_set_run_wake(dev, true); +} + +static void acpi_pci_wakeup_cleanup(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + + if (adev && adev->wakeup.flags.valid) { + device_set_wakeup_capable(dev, false); + device_set_run_wake(dev, false); + pci_acpi_remove_pm_notifier(adev); + } +} + static struct acpi_bus_type acpi_pci_bus = { .bus = &pci_bus_type, .find_device = acpi_pci_find_device, .find_bridge = acpi_pci_find_root_bridge, + .setup = acpi_pci_wakeup_setup, + .cleanup = acpi_pci_wakeup_cleanup, }; static int __init acpi_pci_init(void) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5cb5820fae40..0c4f641b7be1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -450,7 +450,7 @@ static struct pci_platform_pm_ops *pci_platform_pm; int pci_set_platform_pm(struct pci_platform_pm_ops *ops) { if (!ops->is_manageable || !ops->set_state || !ops->choose_state - || !ops->sleep_wake || !ops->can_wakeup) + || !ops->sleep_wake) return -EINVAL; pci_platform_pm = ops; return 0; @@ -473,11 +473,6 @@ static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev) pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR; } -static inline bool platform_pci_can_wakeup(struct pci_dev *dev) -{ - return pci_platform_pm ? pci_platform_pm->can_wakeup(dev) : false; -} - static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable) { return pci_platform_pm ? @@ -1985,25 +1980,6 @@ void pci_pm_init(struct pci_dev *dev) } } -/** - * platform_pci_wakeup_init - init platform wakeup if present - * @dev: PCI device - * - * Some devices don't have PCI PM caps but can still generate wakeup - * events through platform methods (like ACPI events). If @dev supports - * platform wakeup events, set the device flag to indicate as much. This - * may be redundant if the device also supports PCI PM caps, but double - * initialization should be safe in that case. - */ -void platform_pci_wakeup_init(struct pci_dev *dev) -{ - if (!platform_pci_can_wakeup(dev)) - return; - - device_set_wakeup_capable(&dev->dev, true); - platform_pci_sleep_wake(dev, false); -} - static void pci_add_saved_cap(struct pci_dev *pci_dev, struct pci_cap_saved_state *new_cap) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index e8518292826f..adfd172c5b9b 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -43,9 +43,6 @@ int pci_probe_reset_function(struct pci_dev *dev); * platform; to be used during system-wide transitions from a * sleeping state to the working state and vice versa * - * @can_wakeup: returns 'true' if given device is capable of waking up the - * system from a sleeping state - * * @sleep_wake: enables/disables the system wake up capability of given device * * @run_wake: enables/disables the platform to generate run-time wake-up events @@ -59,7 +56,6 @@ struct pci_platform_pm_ops { bool (*is_manageable)(struct pci_dev *dev); int (*set_state)(struct pci_dev *dev, pci_power_t state); pci_power_t (*choose_state)(struct pci_dev *dev); - bool (*can_wakeup)(struct pci_dev *dev); int (*sleep_wake)(struct pci_dev *dev, bool enable); int (*run_wake)(struct pci_dev *dev, bool enable); }; @@ -74,7 +70,6 @@ extern void pci_wakeup_bus(struct pci_bus *bus); extern void pci_config_pm_runtime_get(struct pci_dev *dev); extern void pci_config_pm_runtime_put(struct pci_dev *dev); extern void pci_pm_init(struct pci_dev *dev); -extern void platform_pci_wakeup_init(struct pci_dev *dev); extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); void pci_free_cap_save_buffers(struct pci_dev *dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6186f03d84f3..2dcd22d9c816 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1280,7 +1280,6 @@ static void pci_init_capabilities(struct pci_dev *dev) /* Power Management */ pci_pm_init(dev); - platform_pci_wakeup_init(dev); /* Vital Product Data */ pci_vpd_pci22_init(dev); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 3994d7790b23..8c1d6f2a2193 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -526,9 +526,14 @@ static inline int acpi_subsys_resume_early(struct device *dev) { return 0; } #endif #if defined(CONFIG_ACPI) && defined(CONFIG_PM) +struct acpi_device *acpi_dev_pm_get_node(struct device *dev); int acpi_dev_pm_attach(struct device *dev, bool power_on); void acpi_dev_pm_detach(struct device *dev, bool power_off); #else +static inline struct acpi_device *acpi_dev_pm_get_node(struct device *dev) +{ + return NULL; +} static inline int acpi_dev_pm_attach(struct device *dev, bool power_on) { return -ENODEV; -- cgit v1.2.3 From 38a9a67a281eeebcd7cccf87f0e371f58ae625e3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 23 Dec 2012 00:02:54 +0100 Subject: ACPI / PCI: Move the _PRT setup and cleanup code to pci-acpi.c Move the code related to _PRT setup and removal and to power resources from acpi_pci_bind() and acpi_pci_unbind() to the .setup() and .cleanup() callbacks in acpi_pci_bus and remove acpi_pci_bind() and acpi_pci_unbind() that have no purpose any more. Accordingly, remove the code related to device .bind() and .unbind() operations from the ACPI PCI root bridge driver. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/Makefile | 2 +- drivers/acpi/pci_bind.c | 117 ------------------------------------------------ drivers/acpi/pci_root.c | 31 ------------- drivers/pci/pci-acpi.c | 44 ++++++++++++++---- 4 files changed, 37 insertions(+), 157 deletions(-) delete mode 100644 drivers/acpi/pci_bind.c (limited to 'drivers/acpi') diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 2a4502becd13..4ee2e753306a 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -37,7 +37,7 @@ acpi-y += resource.o acpi-y += processor_core.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o -acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.o +acpi-y += pci_root.o pci_link.o pci_irq.o acpi-y += acpi_platform.o acpi-y += power.o acpi-y += event.o diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c deleted file mode 100644 index bbddcc9c894f..000000000000 --- a/drivers/acpi/pci_bind.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * pci_bind.c - ACPI PCI Device Binding ($Revision: 2 $) - * - * Copyright (C) 2001, 2002 Andy Grover - * Copyright (C) 2001, 2002 Paul Diefenbaugh - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_bind"); - -static int acpi_pci_unbind(struct acpi_device *device) -{ - struct pci_dev *dev; - - dev = acpi_get_pci_dev(device->handle); - if (!dev) - goto out; - - acpi_power_resource_unregister_device(&dev->dev, device->handle); - - if (!dev->subordinate) - goto out; - - acpi_pci_irq_del_prt(pci_domain_nr(dev->bus), dev->subordinate->number); - - device->ops.bind = NULL; - device->ops.unbind = NULL; - -out: - pci_dev_put(dev); - return 0; -} - -static int acpi_pci_bind(struct acpi_device *device) -{ - acpi_status status; - acpi_handle handle; - unsigned char bus; - struct pci_dev *dev; - - dev = acpi_get_pci_dev(device->handle); - if (!dev) - return 0; - - acpi_power_resource_register_device(&dev->dev, device->handle); - - /* - * Install the 'bind' function to facilitate callbacks for - * children of the P2P bridge. - */ - if (dev->subordinate) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device %04x:%02x:%02x.%d is a PCI bridge\n", - pci_domain_nr(dev->bus), dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn))); - device->ops.bind = acpi_pci_bind; - device->ops.unbind = acpi_pci_unbind; - } - - /* - * Evaluate and parse _PRT, if exists. This code allows parsing of - * _PRT objects within the scope of non-bridge devices. Note that - * _PRTs within the scope of a PCI bridge assume the bridge's - * subordinate bus number. - * - * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? - */ - status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); - if (ACPI_FAILURE(status)) - goto out; - - if (dev->subordinate) - bus = dev->subordinate->number; - else - bus = dev->bus->number; - - acpi_pci_irq_add_prt(device->handle, pci_domain_nr(dev->bus), bus); - -out: - pci_dev_put(dev); - return 0; -} - -int acpi_pci_bind_root(struct acpi_device *device) -{ - device->ops.bind = acpi_pci_bind; - device->ops.unbind = acpi_pci_unbind; - - return 0; -} diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0e593a203ff8..22a8458b4ec9 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -186,21 +186,6 @@ static acpi_status try_get_root_bridge_busnr(acpi_handle handle, return AE_OK; } -static void acpi_pci_bridge_scan(struct acpi_device *device) -{ - int status; - struct acpi_device *child = NULL; - - if (device->flags.bus_address) - if (device->parent && device->parent->ops.bind) { - status = device->parent->ops.bind(device); - if (!status) { - list_for_each_entry(child, &device->children, node) - acpi_pci_bridge_scan(child); - } - } -} - static u8 pci_osc_uuid_str[] = "33DB4D5B-1FF7-401C-9657-7441C03DD766"; static acpi_status acpi_pci_run_osc(acpi_handle handle, @@ -450,7 +435,6 @@ static int acpi_pci_root_add(struct acpi_device *device) int result; struct acpi_pci_root *root; acpi_handle handle; - struct acpi_device *child; struct acpi_pci_driver *driver; u32 flags, base_flags; bool is_osc_granted = false; @@ -602,21 +586,6 @@ static int acpi_pci_root_add(struct acpi_device *device) goto out_del_root; } - /* - * Attach ACPI-PCI Context - * ----------------------- - * Thus binding the ACPI and PCI devices. - */ - result = acpi_pci_bind_root(device); - if (result) - goto out_del_root; - - /* - * Scan and bind all _ADR-Based Devices - */ - list_for_each_entry(child, &device->children, node) - acpi_pci_bridge_scan(child); - /* ASPM setting */ if (is_osc_granted) { if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index b98106c110e7..42736e213f25 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -320,12 +320,33 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) return 0; } -static void acpi_pci_wakeup_setup(struct device *dev) +static void pci_acpi_setup(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); struct pci_dev *pci_dev = to_pci_dev(dev); + acpi_handle handle = ACPI_HANDLE(dev); + struct acpi_device *adev; + acpi_status status; + acpi_handle dummy; - if (!adev || !adev->wakeup.flags.valid) + /* + * Evaluate and parse _PRT, if exists. This code allows parsing of + * _PRT objects within the scope of non-bridge devices. Note that + * _PRTs within the scope of a PCI bridge assume the bridge's + * subordinate bus number. + * + * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? + */ + status = acpi_get_handle(handle, METHOD_NAME__PRT, &dummy); + if (ACPI_SUCCESS(status)) { + unsigned char bus; + + bus = pci_dev->subordinate ? + pci_dev->subordinate->number : pci_dev->bus->number; + acpi_pci_irq_add_prt(handle, pci_domain_nr(pci_dev->bus), bus); + } + + acpi_power_resource_register_device(dev, handle); + if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid) return; device_set_wakeup_capable(dev, true); @@ -336,23 +357,30 @@ static void acpi_pci_wakeup_setup(struct device *dev) device_set_run_wake(dev, true); } -static void acpi_pci_wakeup_cleanup(struct device *dev) +static void pci_acpi_cleanup(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct pci_dev *pci_dev = to_pci_dev(dev); + acpi_handle handle = ACPI_HANDLE(dev); + struct acpi_device *adev; - if (adev && adev->wakeup.flags.valid) { + if (!acpi_bus_get_device(handle, &adev) && adev->wakeup.flags.valid) { device_set_wakeup_capable(dev, false); device_set_run_wake(dev, false); pci_acpi_remove_pm_notifier(adev); } + acpi_power_resource_unregister_device(dev, handle); + + if (pci_dev->subordinate) + acpi_pci_irq_del_prt(pci_domain_nr(pci_dev->bus), + pci_dev->subordinate->number); } static struct acpi_bus_type acpi_pci_bus = { .bus = &pci_bus_type, .find_device = acpi_pci_find_device, .find_bridge = acpi_pci_find_root_bridge, - .setup = acpi_pci_wakeup_setup, - .cleanup = acpi_pci_wakeup_cleanup, + .setup = pci_acpi_setup, + .cleanup = pci_acpi_cleanup, }; static int __init acpi_pci_init(void) -- cgit v1.2.3 From 3eec5f7a1955ead549020ec2f60235ea6a4a2252 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 23 Dec 2012 00:03:03 +0100 Subject: ACPI: Drop ACPI device .bind() and .unbind() callbacks Drop the .bind() and .unbind() that have no more users from struct acpi_device_ops and remove all of the code referring to them from drivers/acpi/scan.c. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu Acked-by: Toshi Kani --- drivers/acpi/scan.c | 22 ---------------------- include/acpi/acpi_bus.h | 2 -- 2 files changed, 24 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 3d44c705a3a2..f8a0d0f7d197 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1385,29 +1385,11 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) if (!rmdevice) return 0; - /* - * unbind _ADR-Based Devices when hot removal - */ - if (dev->flags.bus_address) { - if ((dev->parent) && (dev->parent->ops.unbind)) - dev->parent->ops.unbind(dev); - } acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT); return 0; } -/* - * acpi_hot_add_bind - Bind _ADR-based devices on hot-add. - * @device: ACPI device node to bind. - */ -static void acpi_hot_add_bind(struct acpi_device *device) -{ - if (device->flags.bus_address - && device->parent && device->parent->ops.bind) - device->parent->ops.bind(device); -} - static int acpi_add_single_object(struct acpi_device **child, acpi_handle handle, int type, unsigned long long sta, bool match_driver) @@ -1479,9 +1461,6 @@ static int acpi_add_single_object(struct acpi_device **child, device->flags.match_driver = match_driver; result = acpi_device_register(device); - if (device->flags.match_driver) - acpi_hot_add_bind(device); - end: if (!result) { acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -1584,7 +1563,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, return AE_CTRL_DEPTH; device->flags.match_driver = true; - acpi_hot_add_bind(device); out: if (!*return_value) diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 70647313a9bc..6e9a73e05916 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -99,8 +99,6 @@ struct acpi_device_ops { acpi_op_add add; acpi_op_remove remove; acpi_op_start start; - acpi_op_bind bind; - acpi_op_unbind unbind; acpi_op_notify notify; }; -- cgit v1.2.3 From f95988de06ea62ef5bd861f06e9ef56cea405ed1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 7 Jan 2013 21:17:02 +0100 Subject: ACPI / scan: Treat power resources in a special way Commit 805d410 (ACPI: Separate adding ACPI device objects from probing ACPI drivers) introduced an ACPI power resources management regression, because it didn't ensure that the power resources driver bind to the struct acpi_device objects corresponding to power resources as soon as they were created. As a result, ACPI power management routines may attempt to access power resource objects before they are ready to use. To fix this problem, tell the acpi_add_single_object() in acpi_bus_check_add() to probe the driver for objects of type ACPI_BUS_TYPE_POWER. This fix has been verified to work on HP nx6325 where the problem was first observed. Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani --- drivers/acpi/scan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index f8a0d0f7d197..e380345b643a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1558,7 +1558,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, return AE_CTRL_DEPTH; } - acpi_add_single_object(&device, handle, type, sta, false); + acpi_add_single_object(&device, handle, type, sta, + type == ACPI_BUS_TYPE_POWER); if (!device) return AE_CTRL_DEPTH; -- cgit v1.2.3 From abe99210e0f624cea39f1dc375ba818b201c0d7f Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 11 Jan 2013 22:08:09 +0100 Subject: ACPI / scan: Fix check of device_attach() return value. Since device_attach() returns 1 on success (a driver has been bound to the device), the check against its return value in acpi_bus_device_attach() should modified to take that into accout. Make it so. [rjw: Subject and changelog.] Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e380345b643a..bac357da3f29 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1593,7 +1593,7 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, if (!acpi_match_device_ids(device, acpi_platform_device_ids)) { /* This is a known good platform device. */ acpi_create_platform_device(device); - } else if (device_attach(&device->dev)) { + } else if (device_attach(&device->dev) < 0) { status = AE_CTRL_DEPTH; } return status; -- cgit v1.2.3 From b17b537ac1429a609addb55bf985f5ebfcf4ae7b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 15 Jan 2013 13:23:44 +0100 Subject: ACPI / scan: Drop the second argument of acpi_device_unregister() Drop the second argument of acpi_device_unregister(), type, which is not used by that function. Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani Acked-by: Yinghai Lu Acked-by: Yasuaki Ishimatsu --- drivers/acpi/scan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index bac357da3f29..a26c09efc286 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -701,7 +701,7 @@ end: return result; } -static void acpi_device_unregister(struct acpi_device *device, int type) +static void acpi_device_unregister(struct acpi_device *device) { mutex_lock(&acpi_device_lock); if (device->parent) @@ -1385,7 +1385,7 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) if (!rmdevice) return 0; - acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT); + acpi_device_unregister(dev); return 0; } @@ -1746,7 +1746,7 @@ int __init acpi_scan_init(void) result = acpi_bus_scan_fixed(); if (result) - acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); + acpi_device_unregister(acpi_root); else acpi_update_all_gpes(); -- cgit v1.2.3 From ae281795ec92d35dd1631401829124acab965b1f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 15 Jan 2013 13:23:53 +0100 Subject: ACPI / scan: Drop the second argument of acpi_bus_trim() All callers of acpi_bus_trim() pass 1 (true) as the second argument of it, so remove that argument entirely and change acpi_bus_trim() to always behave as though it were 1. Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani Acked-by: Yinghai Lu Acked-by: Yasuaki Ishimatsu --- drivers/acpi/dock.c | 2 +- drivers/acpi/scan.c | 16 ++++------------ drivers/pci/hotplug/acpiphp_glue.c | 4 ++-- drivers/pci/hotplug/sgi_hotplug.c | 2 +- include/acpi/acpi_bus.h | 2 +- 5 files changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 9e31b2bd93d3..4a56a8b2e51e 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -339,7 +339,7 @@ static void dock_remove_acpi_device(acpi_handle handle) int ret; if (!acpi_bus_get_device(handle, &device)) { - ret = acpi_bus_trim(device, 1); + ret = acpi_bus_trim(device); if (ret) pr_debug("error removing bus, %x\n", -ret); } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index a26c09efc286..d14ce446b469 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -133,7 +133,7 @@ void acpi_bus_hot_remove_device(void *context) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Hot-removing device %s...\n", dev_name(&device->dev))); - if (acpi_bus_trim(device, 1)) { + if (acpi_bus_trim(device)) { printk(KERN_ERR PREFIX "Removing device failed\n"); goto err_out; @@ -1374,7 +1374,7 @@ static int acpi_device_set_context(struct acpi_device *device) return -ENODEV; } -static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) +static int acpi_bus_remove(struct acpi_device *dev) { if (!dev) return -EINVAL; @@ -1382,9 +1382,6 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) dev->removal_type = ACPI_BUS_REMOVAL_EJECT; device_release_driver(&dev->dev); - if (!rmdevice) - return 0; - acpi_device_unregister(dev); return 0; @@ -1642,7 +1639,7 @@ int acpi_bus_add(acpi_handle handle) } EXPORT_SYMBOL(acpi_bus_add); -int acpi_bus_trim(struct acpi_device *start, int rmdevice) +int acpi_bus_trim(struct acpi_device *start) { acpi_status status; struct acpi_device *parent, *child; @@ -1668,12 +1665,7 @@ int acpi_bus_trim(struct acpi_device *start, int rmdevice) acpi_get_parent(phandle, &phandle); child = parent; parent = parent->parent; - - if (level == 0) - err = acpi_bus_remove(child, rmdevice); - else - err = acpi_bus_remove(child, 1); - + err = acpi_bus_remove(child); continue; } diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 91b5ad875c53..22006f2d9dd5 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -742,7 +742,7 @@ static int acpiphp_bus_add(struct acpiphp_func *func) /* this shouldn't be in here, so remove * the bus then re-add it... */ - ret_val = acpi_bus_trim(device, 1); + ret_val = acpi_bus_trim(device); dbg("acpi_bus_trim return %x\n", ret_val); } @@ -772,7 +772,7 @@ static int acpiphp_bus_trim(acpi_handle handle) return retval; } - retval = acpi_bus_trim(device, 1); + retval = acpi_bus_trim(device); if (retval) err("cannot remove from acpi list\n"); diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index f3c419256d2a..2e006ee5738b 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -535,7 +535,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) ret = acpi_bus_get_device(chandle, &device); if (ACPI_SUCCESS(ret)) - acpi_bus_trim(device, 1); + acpi_bus_trim(device); } } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index efe5f746c561..566f1fdabbd2 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -348,7 +348,7 @@ int acpi_bus_register_driver(struct acpi_driver *driver); void acpi_bus_unregister_driver(struct acpi_driver *driver); int acpi_bus_add(acpi_handle handle); void acpi_bus_hot_remove_device(void *context); -int acpi_bus_trim(struct acpi_device *start, int rmdevice); +int acpi_bus_trim(struct acpi_device *start); acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd); int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids); -- cgit v1.2.3 From cecdb193c8d91a42d9489d00618cc3dfff92e55a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 15 Jan 2013 13:24:02 +0100 Subject: ACPI / scan: Change the implementation of acpi_bus_trim() The current acpi_bus_trim() implementation is not really straightforward and may be simplified significantly by using acpi_walk_namespace() with acpi_bus_remove() as a post-order callback. Observe that acpi_bus_remove(), as called by acpi_bus_trim(), cannot actually fail, because its first argument is guaranteed not to be NULL thanks to the acpi_bus_get_device() check in acpi_bus_trim(), so simply move the acpi_bus_get_device() check to acpi_bus_remove() and use acpi_walk_namespace() to execute it for every device under start->handle as a post-order callback. The, run it directly for start->handle itself. Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani Acked-by: Yinghai Lu Acked-by: Yasuaki Ishimatsu --- drivers/acpi/scan.c | 64 +++++++++++++---------------------------------------- 1 file changed, 15 insertions(+), 49 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index d14ce446b469..1ee62bd25828 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1374,17 +1374,20 @@ static int acpi_device_set_context(struct acpi_device *device) return -ENODEV; } -static int acpi_bus_remove(struct acpi_device *dev) +static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used, + void *not_used, void **ret_not_used) { - if (!dev) - return -EINVAL; + struct acpi_device *dev = NULL; + + if (acpi_bus_get_device(handle, &dev)) + return AE_OK; dev->removal_type = ACPI_BUS_REMOVAL_EJECT; device_release_driver(&dev->dev); acpi_device_unregister(dev); - return 0; + return AE_OK; } static int acpi_add_single_object(struct acpi_device **child, @@ -1641,51 +1644,14 @@ EXPORT_SYMBOL(acpi_bus_add); int acpi_bus_trim(struct acpi_device *start) { - acpi_status status; - struct acpi_device *parent, *child; - acpi_handle phandle, chandle; - acpi_object_type type; - u32 level = 1; - int err = 0; - - parent = start; - phandle = start->handle; - child = chandle = NULL; - - while ((level > 0) && parent && (!err)) { - status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, - chandle, &chandle); - - /* - * If this scope is exhausted then move our way back up. - */ - if (ACPI_FAILURE(status)) { - level--; - chandle = phandle; - acpi_get_parent(phandle, &phandle); - child = parent; - parent = parent->parent; - err = acpi_bus_remove(child); - continue; - } - - status = acpi_get_type(chandle, &type); - if (ACPI_FAILURE(status)) { - continue; - } - /* - * If there is a device corresponding to chandle then - * parse it (depth-first). - */ - if (acpi_bus_get_device(chandle, &child) == 0) { - level++; - phandle = chandle; - chandle = NULL; - parent = child; - } - continue; - } - return err; + /* + * Execute acpi_bus_remove() as a post-order callback to remove device + * nodes in the given namespace scope. + */ + acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, + acpi_bus_remove, NULL, NULL); + acpi_bus_remove(start->handle, 0, NULL, NULL); + return 0; } EXPORT_SYMBOL_GPL(acpi_bus_trim); -- cgit v1.2.3 From 05404d8f7b5c831e1a2c24bb782f0fe8ea02354c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 15 Jan 2013 13:24:13 +0100 Subject: ACPI / scan: Add second pass to acpi_bus_trim() Make acpi_bus_trim() work in analogy with acpi_bus_scan() and carry out two passes such that ACPI drivers will be detached from device nodes being removed in the first pass and the device nodes themselves will be removed in the second pass. For this purpose split the driver unregistration out of acpi_bus_remove() into a new routine, acpi_bus_device_detach(), that will be executed by acpi_bus_trim() in the additional first pass as a post-order callback. This is necessary, because some ACPI drivers' .remove() routines unregister struct device objects associated with the ACPI device nodes being removed and that needs to happen while the ACPI device nodes are still around (for example, in case they need to be used for power management or similar things at that time). Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani Acked-by: Yinghai Lu Acked-by: Yasuaki Ishimatsu --- drivers/acpi/scan.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 1ee62bd25828..d04d0b33656c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1374,22 +1374,6 @@ static int acpi_device_set_context(struct acpi_device *device) return -ENODEV; } -static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_not_used) -{ - struct acpi_device *dev = NULL; - - if (acpi_bus_get_device(handle, &dev)) - return AE_OK; - - dev->removal_type = ACPI_BUS_REMOVAL_EJECT; - device_release_driver(&dev->dev); - - acpi_device_unregister(dev); - - return AE_OK; -} - static int acpi_add_single_object(struct acpi_device **child, acpi_handle handle, int type, unsigned long long sta, bool match_driver) @@ -1642,8 +1626,38 @@ int acpi_bus_add(acpi_handle handle) } EXPORT_SYMBOL(acpi_bus_add); +static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used, + void *not_used, void **ret_not_used) +{ + struct acpi_device *device = NULL; + + if (!acpi_bus_get_device(handle, &device)) { + device->removal_type = ACPI_BUS_REMOVAL_EJECT; + device_release_driver(&device->dev); + } + return AE_OK; +} + +static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used, + void *not_used, void **ret_not_used) +{ + struct acpi_device *device = NULL; + + if (!acpi_bus_get_device(handle, &device)) + acpi_device_unregister(device); + + return AE_OK; +} + int acpi_bus_trim(struct acpi_device *start) { + /* + * Execute acpi_bus_device_detach() as a post-order callback to detach + * all ACPI drivers from the device nodes being removed. + */ + acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, + acpi_bus_device_detach, NULL, NULL); + acpi_bus_device_detach(start->handle, 0, NULL, NULL); /* * Execute acpi_bus_remove() as a post-order callback to remove device * nodes in the given namespace scope. -- cgit v1.2.3 From 5993c4670ea2453ef5abb45b312f150e994e6eb9 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 11 Jan 2013 22:40:41 +0000 Subject: ACPI: update ej_event interface to take acpi_device Should use acpi_device pointer directly instead of use handle and get the device pointer again later. Signed-off-by: Yinghai Lu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_memhotplug.c | 2 +- drivers/acpi/processor_driver.c | 2 +- drivers/acpi/scan.c | 14 ++++---------- include/acpi/acpi_bus.h | 2 +- 4 files changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 327ab4459558..eaddb7a89c70 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -361,7 +361,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) break; } - ej_event->handle = handle; + ej_event->device = device; ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; acpi_os_hotplug_execute(acpi_bus_hot_remove_device, (void *)ej_event); diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 0777663f443e..a24ee43e06e4 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -733,7 +733,7 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, break; } - ej_event->handle = handle; + ej_event->device = device; ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; acpi_os_hotplug_execute(acpi_bus_hot_remove_device, (void *)ej_event); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index d04d0b33656c..388b59c096dc 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -116,20 +116,14 @@ static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); void acpi_bus_hot_remove_device(void *context) { struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context; - struct acpi_device *device; - acpi_handle handle = ej_event->handle; + struct acpi_device *device = ej_event->device; + acpi_handle handle = device->handle; acpi_handle temp; struct acpi_object_list arg_list; union acpi_object arg; acpi_status status = AE_OK; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ - if (acpi_bus_get_device(handle, &device)) - goto err_out; - - if (!device) - goto err_out; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Hot-removing device %s...\n", dev_name(&device->dev))); @@ -215,7 +209,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, goto err; } - ej_event->handle = acpi_device->handle; + ej_event->device = acpi_device; if (acpi_device->flags.eject_pending) { /* event originated from ACPI eject notification */ ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; @@ -223,7 +217,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, } else { /* event originated from user */ ej_event->event = ACPI_OST_EC_OSPM_EJECT; - (void) acpi_evaluate_hotplug_ost(ej_event->handle, + (void) acpi_evaluate_hotplug_ost(acpi_device->handle, ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 566f1fdabbd2..567851b4f043 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -306,7 +306,7 @@ struct acpi_bus_event { }; struct acpi_eject_event { - acpi_handle handle; + struct acpi_device *device; u32 event; }; -- cgit v1.2.3