summaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
authorArmin Wolf <W_Armin@gmx.de>2023-10-21 00:10:01 +0300
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>2023-10-25 12:46:35 +0300
commit4186a47dbfbce2f97b0c025a7eac32bb5130df05 (patch)
tree6fa704a255ebad243f0e3e3dfd8eb1845075f6a2 /drivers/platform
parent02a258ac3ebf8a530d340ec24a694c13ac9d25c0 (diff)
downloadlinux-4186a47dbfbce2f97b0c025a7eac32bb5130df05.tar.xz
platform/x86: wmi: Decouple probe deferring from wmi_block_list
Many aggregate WMI drivers do not use -EPROBE_DEFER when they cannot find a WMI device during probe, instead they require all WMI devices associated with an platform device to become available at once. This is currently achieved by adding those WMI devices to the wmi_block_list before they are registered, which is then used by the deprecated GUID-based functions to search for WMI devices. Replace this approach with a device link which defers probing of the WMI device until the associated platform device has finished probing (and has registered all WMI devices). New aggregate WMI drivers should not rely on this behaviour. Signed-off-by: Armin Wolf <W_Armin@gmx.de> Link: https://lore.kernel.org/r/20231020211005.38216-2-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/wmi.c39
1 files changed, 26 insertions, 13 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index a78ddd83cda0..1dbef16acdeb 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -1221,6 +1221,26 @@ static int wmi_create_device(struct device *wmi_bus_dev,
return 0;
}
+static int wmi_add_device(struct platform_device *pdev, struct wmi_device *wdev)
+{
+ struct device_link *link;
+
+ /*
+ * Many aggregate WMI drivers do not use -EPROBE_DEFER when they
+ * are unable to find a WMI device during probe, instead they require
+ * all WMI devices associated with an platform device to become available
+ * at once. This device link thus prevents WMI drivers from probing until
+ * the associated platform device has finished probing (and has registered
+ * all discovered WMI devices).
+ */
+
+ link = device_link_add(&wdev->dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
+ if (!link)
+ return -EINVAL;
+
+ return device_add(&wdev->dev);
+}
+
static void wmi_free_devices(struct acpi_device *device)
{
struct wmi_block *wblock, *next;
@@ -1263,11 +1283,12 @@ static bool guid_already_parsed_for_legacy(struct acpi_device *device, const gui
/*
* Parse the _WDG method for the GUID data blocks
*/
-static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
+static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
{
+ struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
const struct guid_block *gblock;
- struct wmi_block *wblock, *next;
+ struct wmi_block *wblock;
union acpi_object *obj;
acpi_status status;
int retval = 0;
@@ -1317,22 +1338,14 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
wblock->handler = wmi_notify_debug;
wmi_method_enable(wblock, true);
}
- }
- /*
- * Now that all of the devices are created, add them to the
- * device tree and probe subdrivers.
- */
- list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
- if (wblock->acpi_device != device)
- continue;
-
- retval = device_add(&wblock->dev.dev);
+ retval = wmi_add_device(pdev, &wblock->dev);
if (retval) {
dev_err(wmi_bus_dev, "failed to register %pUL\n",
&wblock->gblock.guid);
if (debug_event)
wmi_method_enable(wblock, false);
+
list_del(&wblock->list);
put_device(&wblock->dev.dev);
}
@@ -1487,7 +1500,7 @@ static int acpi_wmi_probe(struct platform_device *device)
}
dev_set_drvdata(&device->dev, wmi_bus_dev);
- error = parse_wdg(wmi_bus_dev, acpi_device);
+ error = parse_wdg(wmi_bus_dev, device);
if (error) {
pr_err("Failed to parse WDG method\n");
goto err_remove_busdev;