Skip to content

Commit 71da201

Browse files
committed
ACPI: scan: Defer enumeration of devices with _DEP lists
In some cases ACPI control methods used during device enumeration (such as _HID or _STA) may rely on Operation Region handlers supplied by the drivers of other devices [1]: An example of this is the Acer Switch 10E SW3-016 model. The _HID method of the ACPI node for the UART attached Bluetooth, reads GPIOs to detect the installed wifi chip and update the _HID for the Bluetooth's ACPI node accordingly. The current ACPI scan code calls _HID before the GPIO controller's OpRegions are available, leading to the wrong _HID being used and Bluetooth not working. In principle, in those cases there should be a _DEP control method under the device object with OpRegion enumeration dependencies, so deferring the enumeration of devices with _DEP returning a non-empty list of suppliers of OpRegions depended on by the given device (modulo some known exceptions that don't really supply any OpRegions and are listed by _DEP for other reasons irrelevant for Linux) should at least address the first-order dependencies by allowing the OpRegion suppliers to be enumerated before their consumers. Implement the above idea by modifying acpi_bus_scan() to enumerate devices in the given scope of the ACPI namespace in two passes, where the first pass covers the devices without "significant" lists of dependencies coming from _DEP only and the second pass covers all of the devices that were not enumerated in the first pass. Take _DEP into account only for device objects with _HID, mostly in order to avoid deferring the creation of ACPI device objects that represent PCI devices and must be present during the enumeration of the PCI bus (which takes place during the processing of the ACPI device object that represents the host bridge), so that they can be properly associated with the corresponding PCI devices. Link: https://lore.kernel.org/linux-acpi/[email protected]/ # [1] Reported-by: Hans de Goede <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]> Reviewed-by: Hans de Goede <[email protected]> Tested-by: Hans de Goede <[email protected]> Reviewed-by: Mika Westerberg <[email protected]>
1 parent 6fc2508 commit 71da201

File tree

1 file changed

+78
-25
lines changed

1 file changed

+78
-25
lines changed

drivers/acpi/scan.c

Lines changed: 78 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,8 +1635,6 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
16351635
device_initialize(&device->dev);
16361636
dev_set_uevent_suppress(&device->dev, true);
16371637
acpi_init_coherency(device);
1638-
/* Assume there are unmet deps until acpi_device_dep_initialize() runs */
1639-
device->dep_unmet = 1;
16401638
}
16411639

16421640
void acpi_device_add_finalize(struct acpi_device *device)
@@ -1849,7 +1847,13 @@ static u32 acpi_scan_check_dep(acpi_handle handle)
18491847
u32 count;
18501848
int i;
18511849

1852-
if (!acpi_has_method(handle, "_DEP"))
1850+
/*
1851+
* Check for _HID here to avoid deferring the enumeration of:
1852+
* 1. PCI devices.
1853+
* 2. ACPI nodes describing USB ports.
1854+
* Still, checking for _HID catches more then just these cases ...
1855+
*/
1856+
if (!acpi_has_method(handle, "_DEP") || !acpi_has_method(handle, "_HID"))
18531857
return 0;
18541858

18551859
status = acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices);
@@ -1892,11 +1896,24 @@ static u32 acpi_scan_check_dep(acpi_handle handle)
18921896
return count;
18931897
}
18941898

1895-
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
1896-
void *not_used, void **return_value)
1899+
static void acpi_scan_dep_init(struct acpi_device *adev)
1900+
{
1901+
struct acpi_dep_data *dep;
1902+
1903+
mutex_lock(&acpi_dep_list_lock);
1904+
1905+
list_for_each_entry(dep, &acpi_dep_list, node) {
1906+
if (dep->consumer == adev->handle)
1907+
adev->dep_unmet++;
1908+
}
1909+
1910+
mutex_unlock(&acpi_dep_list_lock);
1911+
}
1912+
1913+
static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep,
1914+
struct acpi_device **adev_p)
18971915
{
18981916
struct acpi_device *device = NULL;
1899-
u32 dep_count = 0;
19001917
unsigned long long sta;
19011918
int type;
19021919
int result;
@@ -1914,24 +1931,40 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
19141931
return AE_OK;
19151932
}
19161933

1917-
if (type == ACPI_BUS_TYPE_DEVICE)
1918-
dep_count = acpi_scan_check_dep(handle);
1934+
if (type == ACPI_BUS_TYPE_DEVICE && check_dep) {
1935+
u32 count = acpi_scan_check_dep(handle);
1936+
/* Bail out if the number of recorded dependencies is not 0. */
1937+
if (count > 0)
1938+
return AE_CTRL_DEPTH;
1939+
}
19191940

19201941
acpi_add_single_object(&device, handle, type, sta);
19211942
if (!device)
19221943
return AE_CTRL_DEPTH;
19231944

1924-
device->dep_unmet = dep_count;
1925-
19261945
acpi_scan_init_hotplug(device);
1946+
if (!check_dep)
1947+
acpi_scan_dep_init(device);
19271948

1928-
out:
1929-
if (!*return_value)
1930-
*return_value = device;
1949+
out:
1950+
if (!*adev_p)
1951+
*adev_p = device;
19311952

19321953
return AE_OK;
19331954
}
19341955

1956+
static acpi_status acpi_bus_check_add_1(acpi_handle handle, u32 lvl_not_used,
1957+
void *not_used, void **ret_p)
1958+
{
1959+
return acpi_bus_check_add(handle, true, (struct acpi_device **)ret_p);
1960+
}
1961+
1962+
static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used,
1963+
void *not_used, void **ret_p)
1964+
{
1965+
return acpi_bus_check_add(handle, false, (struct acpi_device **)ret_p);
1966+
}
1967+
19351968
static void acpi_default_enumeration(struct acpi_device *device)
19361969
{
19371970
/*
@@ -1999,12 +2032,16 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
19992032
return ret;
20002033
}
20012034

2002-
static void acpi_bus_attach(struct acpi_device *device)
2035+
static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
20032036
{
20042037
struct acpi_device *child;
2038+
bool skip = !first_pass && device->flags.visited;
20052039
acpi_handle ejd;
20062040
int ret;
20072041

2042+
if (skip)
2043+
goto ok;
2044+
20082045
if (ACPI_SUCCESS(acpi_bus_get_ejd(device->handle, &ejd)))
20092046
register_dock_dependent_device(device, ejd);
20102047

@@ -2051,9 +2088,9 @@ static void acpi_bus_attach(struct acpi_device *device)
20512088

20522089
ok:
20532090
list_for_each_entry(child, &device->children, node)
2054-
acpi_bus_attach(child);
2091+
acpi_bus_attach(child, first_pass);
20552092

2056-
if (device->handler && device->handler->hotplug.notify_online)
2093+
if (!skip && device->handler && device->handler->hotplug.notify_online)
20572094
device->handler->hotplug.notify_online(device);
20582095
}
20592096

@@ -2071,7 +2108,8 @@ void acpi_walk_dep_device_list(acpi_handle handle)
20712108

20722109
adev->dep_unmet--;
20732110
if (!adev->dep_unmet)
2074-
acpi_bus_attach(adev);
2111+
acpi_bus_attach(adev, true);
2112+
20752113
list_del(&dep->node);
20762114
kfree(dep);
20772115
}
@@ -2096,17 +2134,32 @@ EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list);
20962134
*/
20972135
int acpi_bus_scan(acpi_handle handle)
20982136
{
2099-
void *device = NULL;
2137+
struct acpi_device *device = NULL;
2138+
2139+
/* Pass 1: Avoid enumerating devices with missing dependencies. */
21002140

2101-
if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device)))
2141+
if (ACPI_SUCCESS(acpi_bus_check_add(handle, true, &device)))
21022142
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
2103-
acpi_bus_check_add, NULL, NULL, &device);
2143+
acpi_bus_check_add_1, NULL, NULL,
2144+
(void **)&device);
21042145

2105-
if (device) {
2106-
acpi_bus_attach(device);
2107-
return 0;
2108-
}
2109-
return -ENODEV;
2146+
if (!device)
2147+
return -ENODEV;
2148+
2149+
acpi_bus_attach(device, true);
2150+
2151+
/* Pass 2: Enumerate all of the remaining devices. */
2152+
2153+
device = NULL;
2154+
2155+
if (ACPI_SUCCESS(acpi_bus_check_add(handle, false, &device)))
2156+
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
2157+
acpi_bus_check_add_2, NULL, NULL,
2158+
(void **)&device);
2159+
2160+
acpi_bus_attach(device, false);
2161+
2162+
return 0;
21102163
}
21112164
EXPORT_SYMBOL(acpi_bus_scan);
21122165

0 commit comments

Comments
 (0)