Skip to content

Commit 9dc11fa

Browse files
committed
ACPI: video: Rework checking for duplicate video bus devices
The current way of checking for duplicate video bus devices in acpi_video_bus_probe() is based on walking the ACPI namespace which is not necessary after recent driver conversions. It is also susceptible to race conditions (for example, if two video bus devices are probed at the same time) and ordering issues. Instead of doing it the old way, inspect the children of the parent of the device being probed, excluding the latter and the children that are not auxiliary devices. For each of the remaining children, check if any of the entries in the video_bus_head list is equal to its driver data which can only happen if the given child has been processed by acpi_video_bus_probe() successfully and so it is a duplicate of the one being probed. Moreover, to prevent acpi_video_bus_probe() from processing two devices concurrently, which might defeat the above check, use a new internal mutex in it. Also, print the FW_BUG message only if allow_duplicates is unset which allows the entire duplicates check to be skipped in that case (doing it just to print the message about the case that is going to be ignored anyway is kind of pointless). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Danilo Krummrich <dakr@kernel.org> Link: https://patch.msgid.link/3058492.e9J7NaK4W3@rafael.j.wysocki
1 parent 97e6fab commit 9dc11fa

1 file changed

Lines changed: 28 additions & 28 deletions

File tree

drivers/acpi/acpi_video.c

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,26 +1681,6 @@ static int acpi_video_resume(struct notifier_block *nb,
16811681
return NOTIFY_DONE;
16821682
}
16831683

1684-
static acpi_status
1685-
acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
1686-
void **return_value)
1687-
{
1688-
struct acpi_device *device = context;
1689-
struct acpi_device *sibling;
1690-
1691-
if (handle == device->handle)
1692-
return AE_CTRL_TERMINATE;
1693-
1694-
sibling = acpi_fetch_acpi_dev(handle);
1695-
if (!sibling)
1696-
return AE_OK;
1697-
1698-
if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME))
1699-
return AE_ALREADY_EXISTS;
1700-
1701-
return AE_OK;
1702-
}
1703-
17041684
static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
17051685
{
17061686
struct backlight_properties props;
@@ -1976,29 +1956,49 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
19761956
return 0;
19771957
}
19781958

1959+
static int duplicate_dev_check(struct device *sibling, void *data)
1960+
{
1961+
struct acpi_video_bus *video;
1962+
1963+
if (sibling == data || !dev_is_auxiliary(sibling))
1964+
return 0;
1965+
1966+
guard(mutex)(&video_list_lock);
1967+
1968+
list_for_each_entry(video, &video_bus_head, entry) {
1969+
if (video == dev_get_drvdata(sibling))
1970+
return -EEXIST;
1971+
}
1972+
1973+
return 0;
1974+
}
1975+
1976+
static bool acpi_video_bus_dev_is_duplicate(struct device *dev)
1977+
{
1978+
return device_for_each_child(dev->parent, dev, duplicate_dev_check);
1979+
}
1980+
19791981
static int instance;
19801982

19811983
static int acpi_video_bus_probe(struct auxiliary_device *aux_dev,
19821984
const struct auxiliary_device_id *id_unused)
19831985
{
19841986
struct acpi_device *device = ACPI_COMPANION(&aux_dev->dev);
1987+
static DEFINE_MUTEX(probe_lock);
19851988
struct acpi_video_bus *video;
19861989
bool auto_detect;
19871990
int error;
1988-
acpi_status status;
19891991

1990-
status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
1991-
acpi_dev_parent(device)->handle, 1,
1992-
acpi_video_bus_match, NULL,
1993-
device, NULL);
1994-
if (status == AE_ALREADY_EXISTS) {
1992+
/* Probe one video bus device at a time in case there are duplicates. */
1993+
guard(mutex)(&probe_lock);
1994+
1995+
if (!allow_duplicates && acpi_video_bus_dev_is_duplicate(&aux_dev->dev)) {
19951996
pr_info(FW_BUG
19961997
"Duplicate ACPI video bus devices for the"
19971998
" same VGA controller, please try module "
19981999
"parameter \"video.allow_duplicates=1\""
19992000
"if the current driver doesn't work.\n");
2000-
if (!allow_duplicates)
2001-
return -ENODEV;
2001+
return -ENODEV;
20022002
}
20032003

20042004
video = kzalloc_obj(struct acpi_video_bus);

0 commit comments

Comments
 (0)