Skip to content

Commit 3ba12d8

Browse files
committed
ACPI: scan: Reduce overhead related to devices with dependencies
Notice that all of the objects for which the acpi_scan_check_dep() return value is greater than 0 are present in acpi_dep_list as consumers (there may be multiple entries for one object, but that is not a problem), so after carrying out the initial ACPI namespace walk in which devices with dependencies are skipped, acpi_bus_scan() can simply walk acpi_dep_list and enumerate all of the unique consumer objects from there and their descendants instead of walking the entire target branch of the ACPI namespace and looking for device objects that have not been enumerated yet in it. Because walking acpi_dep_list is generally less overhead than walking the entire ACPI namespace, use the observation above to reduce the system initialization overhead related to ACPI, which is particularly important on large systems. Signed-off-by: Rafael J. Wysocki <[email protected]> Reviewed-by: Hans de Goede <[email protected]>
1 parent 9561de3 commit 3ba12d8

File tree

2 files changed

+63
-20
lines changed

2 files changed

+63
-20
lines changed

drivers/acpi/scan.c

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,8 +2029,6 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
20292029
return count;
20302030
}
20312031

2032-
static bool acpi_bus_scan_second_pass;
2033-
20342032
static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep,
20352033
struct acpi_device **adev_p)
20362034
{
@@ -2050,10 +2048,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep,
20502048
return AE_OK;
20512049

20522050
/* Bail out if there are dependencies. */
2053-
if (acpi_scan_check_dep(handle, check_dep) > 0) {
2054-
acpi_bus_scan_second_pass = true;
2051+
if (acpi_scan_check_dep(handle, check_dep) > 0)
20552052
return AE_CTRL_DEPTH;
2056-
}
20572053

20582054
fallthrough;
20592055
case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */
@@ -2301,6 +2297,12 @@ static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
23012297
return true;
23022298
}
23032299

2300+
static void acpi_scan_delete_dep_data(struct acpi_dep_data *dep)
2301+
{
2302+
list_del(&dep->node);
2303+
kfree(dep);
2304+
}
2305+
23042306
static int acpi_scan_clear_dep(struct acpi_dep_data *dep, void *data)
23052307
{
23062308
struct acpi_device *adev = acpi_get_acpi_dev(dep->consumer);
@@ -2311,8 +2313,10 @@ static int acpi_scan_clear_dep(struct acpi_dep_data *dep, void *data)
23112313
acpi_dev_put(adev);
23122314
}
23132315

2314-
list_del(&dep->node);
2315-
kfree(dep);
2316+
if (dep->free_when_met)
2317+
acpi_scan_delete_dep_data(dep);
2318+
else
2319+
dep->met = true;
23162320

23172321
return 0;
23182322
}
@@ -2406,6 +2410,55 @@ struct acpi_device *acpi_dev_get_next_consumer_dev(struct acpi_device *supplier,
24062410
}
24072411
EXPORT_SYMBOL_GPL(acpi_dev_get_next_consumer_dev);
24082412

2413+
static void acpi_scan_postponed_branch(acpi_handle handle)
2414+
{
2415+
struct acpi_device *adev = NULL;
2416+
2417+
if (ACPI_FAILURE(acpi_bus_check_add(handle, false, &adev)))
2418+
return;
2419+
2420+
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
2421+
acpi_bus_check_add_2, NULL, NULL, (void **)&adev);
2422+
acpi_bus_attach(adev, NULL);
2423+
}
2424+
2425+
static void acpi_scan_postponed(void)
2426+
{
2427+
struct acpi_dep_data *dep, *tmp;
2428+
2429+
mutex_lock(&acpi_dep_list_lock);
2430+
2431+
list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) {
2432+
acpi_handle handle = dep->consumer;
2433+
2434+
/*
2435+
* In case there are multiple acpi_dep_list entries with the
2436+
* same consumer, skip the current entry if the consumer device
2437+
* object corresponding to it is present already.
2438+
*/
2439+
if (!acpi_fetch_acpi_dev(handle)) {
2440+
/*
2441+
* Even though the lock is released here, tmp is
2442+
* guaranteed to be valid, because none of the list
2443+
* entries following dep is marked as "free when met"
2444+
* and so they cannot be deleted.
2445+
*/
2446+
mutex_unlock(&acpi_dep_list_lock);
2447+
2448+
acpi_scan_postponed_branch(handle);
2449+
2450+
mutex_lock(&acpi_dep_list_lock);
2451+
}
2452+
2453+
if (dep->met)
2454+
acpi_scan_delete_dep_data(dep);
2455+
else
2456+
dep->free_when_met = true;
2457+
}
2458+
2459+
mutex_unlock(&acpi_dep_list_lock);
2460+
}
2461+
24092462
/**
24102463
* acpi_bus_scan - Add ACPI device node objects in a given namespace scope.
24112464
* @handle: Root of the namespace scope to scan.
@@ -2424,8 +2477,6 @@ int acpi_bus_scan(acpi_handle handle)
24242477
{
24252478
struct acpi_device *device = NULL;
24262479

2427-
acpi_bus_scan_second_pass = false;
2428-
24292480
/* Pass 1: Avoid enumerating devices with missing dependencies. */
24302481

24312482
if (ACPI_SUCCESS(acpi_bus_check_add(handle, true, &device)))
@@ -2438,19 +2489,9 @@ int acpi_bus_scan(acpi_handle handle)
24382489

24392490
acpi_bus_attach(device, (void *)true);
24402491

2441-
if (!acpi_bus_scan_second_pass)
2442-
return 0;
2443-
24442492
/* Pass 2: Enumerate all of the remaining devices. */
24452493

2446-
device = NULL;
2447-
2448-
if (ACPI_SUCCESS(acpi_bus_check_add(handle, false, &device)))
2449-
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
2450-
acpi_bus_check_add_2, NULL, NULL,
2451-
(void **)&device);
2452-
2453-
acpi_bus_attach(device, NULL);
2494+
acpi_scan_postponed();
24542495

24552496
return 0;
24562497
}

include/acpi/acpi_bus.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ struct acpi_dep_data {
289289
acpi_handle supplier;
290290
acpi_handle consumer;
291291
bool honor_dep;
292+
bool met;
293+
bool free_when_met;
292294
};
293295

294296
/* Performance Management */

0 commit comments

Comments
 (0)