Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPI: video: Switch over to auxiliary bus type

Commit 02c057ddefef ("ACPI: video: Convert the driver to a platform one")
switched over the ACPI video bus driver from an ACPI driver to a platform
driver, but that change introduced an unwanted and unexpected side effect.
Namely, on some systems, the ACPI device object of the ACPI video bus
device is an ACPI companion of multiple platform devices and, after
adding video_device_ids[] as an acpi_match_table to the acpi_video_bus
platform driver, all of those devices started to match that driver and
its probe callback is invoked for all of them (it fails, but it leaves
a confusing message in the log). Moreover, the MODULE_DEVICE_TABLE()
of the ACPI video driver module matches all of the devices sharing the
ACPI companion with the ACPI video bus device.

To address this, make the core ACPI device enumeration code create an
auxiliary device for the ACPI video bus device object instead of a
platform device and switch over the ACPI video bus driver (once more)
to an auxiliary driver.

Auxiliary driver generally is a better match for ACPI video bus than
platform driver, among other things because the ACPI video bus device
does not require any resources to be allocated for it during
enumeration. It also allows the ACPI video bus driver to stop abusing
device matching based on ACPI device IDs and it allows a special case
to be dropped from acpi_create_platform_device() because that function
need not worry about the ACPI video bus device any more.

Fixes: 02c057ddefef ("ACPI: video: Convert the driver to a platform one")
Reported-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
Closes: https://lore.kernel.org/linux-acpi/007e3390-6b2b-457e-83c7-c794c5952018@amd.com/
Tested-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
[ rjw: Added AUXILIARY_BUS selection to CONFIG_ACPI to fix build issue ]
[ rjw: Fixed error path in acpi_create_video_bus_device() ]
Link: https://patch.msgid.link/5986516.DvuYhMxLoT@rafael.j.wysocki
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

+69 -24
+1
drivers/acpi/Kconfig
··· 9 9 menuconfig ACPI 10 10 bool "ACPI (Advanced Configuration and Power Interface) Support" 11 11 depends on ARCH_SUPPORTS_ACPI 12 + select AUXILIARY_BUS 12 13 select PNP 13 14 select NLS 14 15 select CRC32
+1 -1
drivers/acpi/acpi_platform.c
··· 135 135 } 136 136 } 137 137 138 - if (adev->device_type == ACPI_BUS_TYPE_DEVICE && !adev->pnp.type.backlight) { 138 + if (adev->device_type == ACPI_BUS_TYPE_DEVICE) { 139 139 LIST_HEAD(resource_list); 140 140 141 141 count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+22 -23
drivers/acpi/acpi_video.c
··· 9 9 10 10 #define pr_fmt(fmt) "ACPI: video: " fmt 11 11 12 + #include <linux/auxiliary_bus.h> 12 13 #include <linux/kernel.h> 13 14 #include <linux/module.h> 14 15 #include <linux/init.h> ··· 22 21 #include <linux/sort.h> 23 22 #include <linux/pci.h> 24 23 #include <linux/pci_ids.h> 25 - #include <linux/platform_device.h> 26 24 #include <linux/slab.h> 27 25 #include <linux/dmi.h> 28 26 #include <linux/suspend.h> ··· 77 77 static DEFINE_MUTEX(register_count_mutex); 78 78 static DEFINE_MUTEX(video_list_lock); 79 79 static LIST_HEAD(video_bus_head); 80 - static int acpi_video_bus_probe(struct platform_device *pdev); 81 - static void acpi_video_bus_remove(struct platform_device *pdev); 80 + static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, 81 + const struct auxiliary_device_id *id); 82 + static void acpi_video_bus_remove(struct auxiliary_device *aux); 82 83 static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data); 83 84 84 85 /* ··· 94 93 ACPI_VIDEO_FIRST_LEVEL, /* actual supported levels begin here */ 95 94 }; 96 95 97 - static const struct acpi_device_id video_device_ids[] = { 98 - {ACPI_VIDEO_HID, 0}, 99 - {"", 0}, 96 + static const struct auxiliary_device_id video_bus_auxiliary_id_table[] = { 97 + { .name = "acpi.video_bus" }, 98 + {}, 100 99 }; 101 - MODULE_DEVICE_TABLE(acpi, video_device_ids); 100 + MODULE_DEVICE_TABLE(auxiliary, video_bus_auxiliary_id_table); 102 101 103 - static struct platform_driver acpi_video_bus = { 102 + static struct auxiliary_driver acpi_video_bus = { 104 103 .probe = acpi_video_bus_probe, 105 104 .remove = acpi_video_bus_remove, 106 - .driver = { 107 - .name = "acpi-video", 108 - .acpi_match_table = video_device_ids, 109 - }, 105 + .id_table = video_bus_auxiliary_id_table, 110 106 }; 111 107 112 108 struct acpi_video_bus_flags { ··· 1883 1885 } 1884 1886 1885 1887 static int acpi_video_bus_add_notify_handler(struct acpi_video_bus *video, 1886 - struct platform_device *pdev) 1888 + struct device *parent) 1887 1889 { 1888 1890 struct input_dev *input; 1889 1891 struct acpi_video_device *dev; ··· 1906 1908 input->phys = video->phys; 1907 1909 input->id.bustype = BUS_HOST; 1908 1910 input->id.product = 0x06; 1909 - input->dev.parent = &pdev->dev; 1911 + input->dev.parent = parent; 1910 1912 input->evbit[0] = BIT(EV_KEY); 1911 1913 set_bit(KEY_SWITCHVIDEOMODE, input->keybit); 1912 1914 set_bit(KEY_VIDEO_NEXT, input->keybit); ··· 1978 1980 1979 1981 static int instance; 1980 1982 1981 - static int acpi_video_bus_probe(struct platform_device *pdev) 1983 + static int acpi_video_bus_probe(struct auxiliary_device *aux_dev, 1984 + const struct auxiliary_device_id *id_unused) 1982 1985 { 1983 - struct acpi_device *device = ACPI_COMPANION(&pdev->dev); 1986 + struct acpi_device *device = ACPI_COMPANION(&aux_dev->dev); 1984 1987 struct acpi_video_bus *video; 1985 1988 bool auto_detect; 1986 1989 int error; ··· 2018 2019 instance++; 2019 2020 } 2020 2021 2021 - platform_set_drvdata(pdev, video); 2022 + auxiliary_set_drvdata(aux_dev, video); 2022 2023 2023 2024 video->device = device; 2024 2025 strscpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME); ··· 2067 2068 !auto_detect) 2068 2069 acpi_video_bus_register_backlight(video); 2069 2070 2070 - error = acpi_video_bus_add_notify_handler(video, pdev); 2071 + error = acpi_video_bus_add_notify_handler(video, &aux_dev->dev); 2071 2072 if (error) 2072 2073 goto err_del; 2073 2074 ··· 2095 2096 return error; 2096 2097 } 2097 2098 2098 - static void acpi_video_bus_remove(struct platform_device *pdev) 2099 + static void acpi_video_bus_remove(struct auxiliary_device *aux_dev) 2099 2100 { 2100 - struct acpi_video_bus *video = platform_get_drvdata(pdev); 2101 - struct acpi_device *device = ACPI_COMPANION(&pdev->dev); 2101 + struct acpi_video_bus *video = auxiliary_get_drvdata(aux_dev); 2102 + struct acpi_device *device = ACPI_COMPANION(&aux_dev->dev); 2102 2103 2103 2104 acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, 2104 2105 acpi_video_bus_notify); ··· 2162 2163 2163 2164 dmi_check_system(video_dmi_table); 2164 2165 2165 - ret = platform_driver_register(&acpi_video_bus); 2166 + ret = auxiliary_driver_register(&acpi_video_bus); 2166 2167 if (ret) 2167 2168 goto leave; 2168 2169 ··· 2182 2183 { 2183 2184 mutex_lock(&register_count_mutex); 2184 2185 if (register_count) { 2185 - platform_driver_unregister(&acpi_video_bus); 2186 + auxiliary_driver_unregister(&acpi_video_bus); 2186 2187 register_count = 0; 2187 2188 may_report_brightness_keys = false; 2188 2189 }
+45
drivers/acpi/scan.c
··· 6 6 #define pr_fmt(fmt) "ACPI: " fmt 7 7 8 8 #include <linux/async.h> 9 + #include <linux/auxiliary_bus.h> 9 10 #include <linux/module.h> 10 11 #include <linux/init.h> 11 12 #include <linux/slab.h> ··· 2193 2192 return acpi_bus_check_add(handle, false, (struct acpi_device **)ret_p); 2194 2193 } 2195 2194 2195 + static void acpi_video_bus_device_release(struct device *dev) 2196 + { 2197 + struct auxiliary_device *aux_dev = to_auxiliary_dev(dev); 2198 + 2199 + kfree(aux_dev); 2200 + } 2201 + 2202 + static void acpi_create_video_bus_device(struct acpi_device *adev, 2203 + struct acpi_device *parent) 2204 + { 2205 + struct auxiliary_device *aux_dev; 2206 + static unsigned int aux_dev_id; 2207 + 2208 + aux_dev = kzalloc_obj(*aux_dev); 2209 + if (!aux_dev) 2210 + return; 2211 + 2212 + aux_dev->id = aux_dev_id++; 2213 + aux_dev->name = "video_bus"; 2214 + aux_dev->dev.parent = acpi_get_first_physical_node(parent); 2215 + if (!aux_dev->dev.parent) 2216 + goto err; 2217 + 2218 + aux_dev->dev.release = acpi_video_bus_device_release; 2219 + 2220 + if (auxiliary_device_init(aux_dev)) 2221 + goto err; 2222 + 2223 + ACPI_COMPANION_SET(&aux_dev->dev, adev); 2224 + if (__auxiliary_device_add(aux_dev, "acpi")) 2225 + auxiliary_device_uninit(aux_dev); 2226 + 2227 + return; 2228 + 2229 + err: 2230 + kfree(aux_dev); 2231 + } 2232 + 2196 2233 struct acpi_scan_system_dev { 2197 2234 struct list_head node; 2198 2235 struct acpi_device *adev; ··· 2268 2229 sd->adev = device; 2269 2230 list_add_tail(&sd->node, &acpi_scan_system_dev_list); 2270 2231 } 2232 + } else if (device->pnp.type.backlight) { 2233 + struct acpi_device *parent; 2234 + 2235 + parent = acpi_dev_parent(device); 2236 + if (parent) 2237 + acpi_create_video_bus_device(device, parent); 2271 2238 } else { 2272 2239 /* For a regular device object, create a platform device. */ 2273 2240 acpi_create_platform_device(device, NULL);