Skip to content

Commit 202317a

Browse files
committed
ACPI / scan: Add acpi_device objects for all device nodes in the namespace
Modify the ACPI namespace scanning code to register a struct acpi_device object for every namespace node representing a device, processor and so on, even if the device represented by that namespace node is reported to be not present and not functional by _STA. There are multiple reasons to do that. First of all, it avoids quite a lot of overhead when struct acpi_device objects are deleted every time acpi_bus_trim() is run and then added again by a subsequent acpi_bus_scan() for the same scope, although the namespace objects they correspond to stay in memory all the time (which always is the case on a vast majority of systems). Second, it will allow user space to see that there are namespace nodes representing devices that are not present at the moment and may be added to the system. It will also allow user space to evaluate _SUN for those nodes to check what physical slots the "missing" devices may be put into and it will make sense to add a sysfs attribute for _STA evaluation after this change (that will be useful for thermal management on some systems). Next, it will help to consolidate the ACPI hotplug handling among subsystems by making it possible to store hotplug-related information in struct acpi_device objects in a standard common way. Finally, it will help to avoid a race condition related to the deletion of ACPI namespace nodes. Namely, namespace nodes may be deleted as a result of a table unload triggered by _EJ0 or _DCK. If a hotplug notification for one of those nodes is triggered right before the deletion and it executes a hotplug callback via acpi_hotplug_execute(), the ACPI handle passed to that callback may be stale when the callback actually runs. One way to work around that is to always pass struct acpi_device pointers to hotplug callbacks after doing a get_device() on the objects in question which eliminates the use-after-free possibility (the ACPI handles in those objects are invalidated by acpi_scan_drop_device(), so they will trigger ACPICA errors on attempts to use them). Signed-off-by: Rafael J. Wysocki <[email protected]> Tested-by: Mika Westerberg <[email protected]>
1 parent d783156 commit 202317a

File tree

10 files changed

+97
-84
lines changed

10 files changed

+97
-84
lines changed

Documentation/acpi/namespace.txt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,6 @@ Wysocki <[email protected]>.
235235
named object's type in the second column). In that case the object's
236236
directory in sysfs will contain the 'path' attribute whose value is
237237
the full path to the node from the namespace root.
238-
struct acpi_device objects are created for the ACPI namespace nodes
239-
whose _STA control methods return PRESENT or FUNCTIONING. The power
240-
resource nodes or nodes without _STA are assumed to be both PRESENT
241-
and FUNCTIONING.
242238
F:
243239
The struct acpi_device object is created for a fixed hardware
244240
feature (as indicated by the fixed feature flag's name in the second
@@ -340,7 +336,7 @@ Wysocki <[email protected]>.
340336
| +-------------+-------+----------------+
341337
| |
342338
| | +- - - - - - - +- - - - - - +- - - - - - - -+
343-
| +-| * PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: |
339+
| +-| PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: |
344340
| | +- - - - - - - +- - - - - - +- - - - - - - -+
345341
| |
346342
| | +------------+------------+-----------------------+
@@ -390,6 +386,3 @@ Wysocki <[email protected]>.
390386
attribute (as described earlier in this document).
391387
NOTE: N/A indicates the device object does not have the 'path' or the
392388
'modalias' attribute.
393-
NOTE: The PNP0C0D device listed above is highlighted (marked by "*")
394-
to indicate it will be created only when its _STA methods return
395-
PRESENT or FUNCTIONING.

drivers/acpi/device_pm.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ int acpi_bus_init_power(struct acpi_device *device)
256256
return -EINVAL;
257257

258258
device->power.state = ACPI_STATE_UNKNOWN;
259+
if (!acpi_device_is_present(device))
260+
return 0;
259261

260262
result = acpi_device_get_power(device, &state);
261263
if (result)
@@ -302,15 +304,18 @@ int acpi_device_fix_up_power(struct acpi_device *device)
302304
return ret;
303305
}
304306

305-
int acpi_bus_update_power(acpi_handle handle, int *state_p)
307+
int acpi_device_update_power(struct acpi_device *device, int *state_p)
306308
{
307-
struct acpi_device *device;
308309
int state;
309310
int result;
310311

311-
result = acpi_bus_get_device(handle, &device);
312-
if (result)
312+
if (device->power.state == ACPI_STATE_UNKNOWN) {
313+
result = acpi_bus_init_power(device);
314+
if (!result && state_p)
315+
*state_p = device->power.state;
316+
313317
return result;
318+
}
314319

315320
result = acpi_device_get_power(device, &state);
316321
if (result)
@@ -338,6 +343,15 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p)
338343

339344
return 0;
340345
}
346+
347+
int acpi_bus_update_power(acpi_handle handle, int *state_p)
348+
{
349+
struct acpi_device *device;
350+
int result;
351+
352+
result = acpi_bus_get_device(handle, &device);
353+
return result ? result : acpi_device_update_power(device, state_p);
354+
}
341355
EXPORT_SYMBOL_GPL(acpi_bus_update_power);
342356

343357
bool acpi_bus_power_manageable(acpi_handle handle)

drivers/acpi/dock.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -323,14 +323,11 @@ static int dock_present(struct dock_station *ds)
323323
*/
324324
static void dock_create_acpi_device(acpi_handle handle)
325325
{
326-
struct acpi_device *device;
326+
struct acpi_device *device = NULL;
327327
int ret;
328328

329-
if (acpi_bus_get_device(handle, &device)) {
330-
/*
331-
* no device created for this object,
332-
* so we should create one.
333-
*/
329+
acpi_bus_get_device(handle, &device);
330+
if (!acpi_device_enumerated(device)) {
334331
ret = acpi_bus_scan(handle);
335332
if (ret)
336333
pr_debug("error adding bus, %x\n", -ret);

drivers/acpi/internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
9090
int acpi_bind_one(struct device *dev, acpi_handle handle);
9191
int acpi_unbind_one(struct device *dev);
9292
void acpi_bus_device_eject(void *data, u32 ost_src);
93+
bool acpi_device_is_present(struct acpi_device *adev);
9394

9495
/* --------------------------------------------------------------------------
9596
Power Resource
@@ -107,6 +108,8 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
107108
int acpi_power_on_resources(struct acpi_device *device, int state);
108109
int acpi_power_transition(struct acpi_device *device, int state);
109110

111+
int acpi_device_update_power(struct acpi_device *device, int *state_p);
112+
110113
int acpi_wakeup_device_init(void);
111114
void acpi_early_processor_set_pdc(void);
112115

drivers/acpi/pci_root.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,9 +634,10 @@ void __init acpi_pci_root_init(void)
634634

635635
static void handle_root_bridge_insertion(acpi_handle handle)
636636
{
637-
struct acpi_device *device;
637+
struct acpi_device *device = NULL;
638638

639-
if (!acpi_bus_get_device(handle, &device)) {
639+
acpi_bus_get_device(handle, &device);
640+
if (acpi_device_enumerated(device)) {
640641
dev_printk(KERN_DEBUG, &device->dev,
641642
"acpi device already exists; ignoring notify\n");
642643
return;

drivers/acpi/scan.c

Lines changed: 51 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
259259

260260
acpi_bus_trim(device);
261261

262-
/* Device node has been unregistered. */
263262
put_device(&device->dev);
264263
device = NULL;
265264

@@ -328,16 +327,17 @@ void acpi_bus_device_eject(void *data, u32 ost_src)
328327
static void acpi_scan_bus_device_check(void *data, u32 ost_source)
329328
{
330329
acpi_handle handle = data;
331-
struct acpi_device *device = NULL;
330+
struct acpi_device *device;
332331
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
333332
int error;
334333

335334
lock_device_hotplug();
336335
mutex_lock(&acpi_scan_lock);
337336

338337
if (ost_source != ACPI_NOTIFY_BUS_CHECK) {
338+
device = NULL;
339339
acpi_bus_get_device(handle, &device);
340-
if (device) {
340+
if (acpi_device_enumerated(device)) {
341341
dev_warn(&device->dev, "Attempt to re-insert\n");
342342
goto out;
343343
}
@@ -347,9 +347,10 @@ static void acpi_scan_bus_device_check(void *data, u32 ost_source)
347347
acpi_handle_warn(handle, "Namespace scan failure\n");
348348
goto out;
349349
}
350-
error = acpi_bus_get_device(handle, &device);
351-
if (error) {
352-
acpi_handle_warn(handle, "Missing device node object\n");
350+
device = NULL;
351+
acpi_bus_get_device(handle, &device);
352+
if (!acpi_device_enumerated(device)) {
353+
acpi_handle_warn(handle, "Device not enumerated\n");
353354
goto out;
354355
}
355356
ost_code = ACPI_OST_SC_SUCCESS;
@@ -1111,20 +1112,6 @@ int acpi_device_add(struct acpi_device *device,
11111112
return result;
11121113
}
11131114

1114-
static void acpi_device_unregister(struct acpi_device *device)
1115-
{
1116-
acpi_detach_data(device->handle, acpi_scan_drop_device);
1117-
acpi_device_del(device);
1118-
/*
1119-
* Transition the device to D3cold to drop the reference counts of all
1120-
* power resources the device depends on and turn off the ones that have
1121-
* no more references.
1122-
*/
1123-
acpi_device_set_power(device, ACPI_STATE_D3_COLD);
1124-
device->handle = NULL;
1125-
put_device(&device->dev);
1126-
}
1127-
11281115
/* --------------------------------------------------------------------------
11291116
Driver Management
11301117
-------------------------------------------------------------------------- */
@@ -1703,6 +1690,8 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
17031690
acpi_set_pnp_ids(handle, &device->pnp, type);
17041691
acpi_bus_get_flags(device);
17051692
device->flags.match_driver = false;
1693+
device->flags.initialized = true;
1694+
device->flags.visited = false;
17061695
device_initialize(&device->dev);
17071696
dev_set_uevent_suppress(&device->dev, true);
17081697
}
@@ -1787,6 +1776,15 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type,
17871776
return 0;
17881777
}
17891778

1779+
bool acpi_device_is_present(struct acpi_device *adev)
1780+
{
1781+
if (adev->status.present || adev->status.functional)
1782+
return true;
1783+
1784+
adev->flags.initialized = false;
1785+
return false;
1786+
}
1787+
17901788
static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
17911789
char *idstr,
17921790
const struct acpi_device_id **matchid)
@@ -1880,18 +1878,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
18801878

18811879
acpi_scan_init_hotplug(handle, type);
18821880

1883-
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
1884-
!(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
1885-
struct acpi_device_wakeup wakeup;
1886-
1887-
if (acpi_has_method(handle, "_PRW")) {
1888-
acpi_bus_extract_wakeup_device_power_package(handle,
1889-
&wakeup);
1890-
acpi_power_resources_list_free(&wakeup.resources);
1891-
}
1892-
return AE_CTRL_DEPTH;
1893-
}
1894-
18951881
acpi_add_single_object(&device, handle, type, sta);
18961882
if (!device)
18971883
return AE_CTRL_DEPTH;
@@ -1930,32 +1916,50 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
19301916
void *not_used, void **ret_not_used)
19311917
{
19321918
struct acpi_device *device;
1933-
unsigned long long sta_not_used;
1919+
unsigned long long sta;
19341920
int ret;
19351921

19361922
/*
19371923
* Ignore errors ignored by acpi_bus_check_add() to avoid terminating
19381924
* namespace walks prematurely.
19391925
*/
1940-
if (acpi_bus_type_and_status(handle, &ret, &sta_not_used))
1926+
if (acpi_bus_type_and_status(handle, &ret, &sta))
19411927
return AE_OK;
19421928

19431929
if (acpi_bus_get_device(handle, &device))
19441930
return AE_CTRL_DEPTH;
19451931

1932+
STRUCT_TO_INT(device->status) = sta;
1933+
/* Skip devices that are not present. */
1934+
if (!acpi_device_is_present(device))
1935+
goto err;
1936+
19461937
if (device->handler)
19471938
return AE_OK;
19481939

1940+
if (!device->flags.initialized) {
1941+
acpi_bus_update_power(device, NULL);
1942+
device->flags.initialized = true;
1943+
}
19491944
ret = acpi_scan_attach_handler(device);
19501945
if (ret < 0)
1951-
return AE_CTRL_DEPTH;
1946+
goto err;
19521947

19531948
device->flags.match_driver = true;
19541949
if (ret > 0)
1955-
return AE_OK;
1950+
goto ok;
19561951

19571952
ret = device_attach(&device->dev);
1958-
return ret >= 0 ? AE_OK : AE_CTRL_DEPTH;
1953+
if (ret < 0)
1954+
goto err;
1955+
1956+
ok:
1957+
device->flags.visited = true;
1958+
return AE_OK;
1959+
1960+
err:
1961+
device->flags.visited = false;
1962+
return AE_CTRL_DEPTH;
19591963
}
19601964

19611965
/**
@@ -2007,21 +2011,17 @@ static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
20072011
} else {
20082012
device_release_driver(&device->dev);
20092013
}
2014+
/*
2015+
* Most likely, the device is going away, so put it into D3cold
2016+
* before that.
2017+
*/
2018+
acpi_device_set_power(device, ACPI_STATE_D3_COLD);
2019+
device->flags.initialized = false;
2020+
device->flags.visited = false;
20102021
}
20112022
return AE_OK;
20122023
}
20132024

2014-
static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
2015-
void *not_used, void **ret_not_used)
2016-
{
2017-
struct acpi_device *device = NULL;
2018-
2019-
if (!acpi_bus_get_device(handle, &device))
2020-
acpi_device_unregister(device);
2021-
2022-
return AE_OK;
2023-
}
2024-
20252025
/**
20262026
* acpi_bus_trim - Remove ACPI device node and all of its descendants
20272027
* @start: Root of the ACPI device nodes subtree to remove.
@@ -2037,13 +2037,6 @@ void acpi_bus_trim(struct acpi_device *start)
20372037
acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
20382038
acpi_bus_device_detach, NULL, NULL);
20392039
acpi_bus_device_detach(start->handle, 0, NULL, NULL);
2040-
/*
2041-
* Execute acpi_bus_remove() as a post-order callback to remove device
2042-
* nodes in the given namespace scope.
2043-
*/
2044-
acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
2045-
acpi_bus_remove, NULL, NULL);
2046-
acpi_bus_remove(start->handle, 0, NULL, NULL);
20472040
}
20482041
EXPORT_SYMBOL_GPL(acpi_bus_trim);
20492042

@@ -2121,7 +2114,9 @@ int __init acpi_scan_init(void)
21212114

21222115
result = acpi_bus_scan_fixed();
21232116
if (result) {
2124-
acpi_device_unregister(acpi_root);
2117+
acpi_detach_data(acpi_root->handle, acpi_scan_drop_device);
2118+
acpi_device_del(acpi_root);
2119+
put_device(&acpi_root->dev);
21252120
goto out;
21262121
}
21272122

drivers/pci/hotplug/acpiphp_glue.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ static void acpiphp_bus_add(acpi_handle handle)
489489

490490
acpi_bus_scan(handle);
491491
acpi_bus_get_device(handle, &adev);
492-
if (adev)
492+
if (acpi_device_enumerated(adev))
493493
acpi_device_set_power(adev, ACPI_STATE_D0);
494494
}
495495

drivers/xen/xen-acpi-cpuhotplug.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,16 +269,18 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
269269
if (!is_processor_present(handle))
270270
break;
271271

272-
if (!acpi_bus_get_device(handle, &device))
272+
acpi_bus_get_device(handle, &device);
273+
if (acpi_device_enumerated(device))
273274
break;
274275

275276
result = acpi_bus_scan(handle);
276277
if (result) {
277278
pr_err(PREFIX "Unable to add the device\n");
278279
break;
279280
}
280-
result = acpi_bus_get_device(handle, &device);
281-
if (result) {
281+
device = NULL;
282+
acpi_bus_get_device(handle, &device);
283+
if (!acpi_device_enumerated(device)) {
282284
pr_err(PREFIX "Missing device object\n");
283285
break;
284286
}

drivers/xen/xen-acpi-memhotplug.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ static int acpi_memory_get_device(acpi_handle handle,
169169
acpi_scan_lock_acquire();
170170

171171
acpi_bus_get_device(handle, &device);
172-
if (device)
172+
if (acpi_device_enumerated(device))
173173
goto end;
174174

175175
/*
@@ -182,8 +182,9 @@ static int acpi_memory_get_device(acpi_handle handle,
182182
result = -EINVAL;
183183
goto out;
184184
}
185-
result = acpi_bus_get_device(handle, &device);
186-
if (result) {
185+
device = NULL;
186+
acpi_bus_get_device(handle, &device);
187+
if (!acpi_device_enumerated(device)) {
187188
pr_warn(PREFIX "Missing device object\n");
188189
result = -EINVAL;
189190
goto out;

0 commit comments

Comments
 (0)