platform/x86: wmi: Do not instantiate older WMI drivers multiple times
authorArmin Wolf <W_Armin@gmx.de>
Mon, 26 Feb 2024 19:35:56 +0000 (20:35 +0100)
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Tue, 12 Mar 2024 10:47:35 +0000 (12:47 +0200)
Many older WMI drivers cannot be instantiated multiple times for
two reasons:

- they are using the legacy GUID-based WMI API
- they are singletons (with global state)

Prevent such WMI drivers from binding to WMI devices with a duplicated
GUID, as this would mean that the WMI driver will be instantiated at
least two times (one for the original GUID and one for the duplicated
GUID).
WMI drivers which can be instantiated multiple times can signal this
by setting a flag inside struct wmi_driver.

Tested on a ASUS Prime B650-Plus.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Link: https://lore.kernel.org/r/20240226193557.2888-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>
drivers/hwmon/dell-smm-hwmon.c
drivers/platform/x86/dell/dell-wmi-ddv.c
drivers/platform/x86/intel/wmi/sbl-fw-update.c
drivers/platform/x86/intel/wmi/thunderbolt.c
drivers/platform/x86/wmi-bmof.c
drivers/platform/x86/wmi.c
include/linux/wmi.h

index 6d8c0f328b7bbfd8edfa4e381879ab588c55b40f..168d669c4ecabe315ef2114eb1b5375b85c45096 100644 (file)
@@ -1587,6 +1587,7 @@ static struct wmi_driver dell_smm_wmi_driver = {
        },
        .id_table = dell_smm_wmi_id_table,
        .probe = dell_smm_wmi_probe,
+       .no_singleton = true,
 };
 
 /*
index db1e9240dd02c27e07926dd865222288632e3d4e..0b2299f7a2de5aacab3847e1956c62e71fbbc6be 100644 (file)
@@ -882,6 +882,7 @@ static struct wmi_driver dell_wmi_ddv_driver = {
        },
        .id_table = dell_wmi_ddv_id_table,
        .probe = dell_wmi_ddv_probe,
+       .no_singleton = true,
 };
 module_wmi_driver(dell_wmi_ddv_driver);
 
index 040153ad67c1cb7c36fe85616cb97d10f7f99c46..75c82c08117f5c2a7701bf95706f2030eb3467b5 100644 (file)
@@ -131,6 +131,7 @@ static struct wmi_driver intel_wmi_sbl_fw_update_driver = {
        .probe = intel_wmi_sbl_fw_update_probe,
        .remove = intel_wmi_sbl_fw_update_remove,
        .id_table = intel_wmi_sbl_id_table,
+       .no_singleton = true,
 };
 module_wmi_driver(intel_wmi_sbl_fw_update_driver);
 
index e2ad3f46f3569f97d883cb21735b6b571d87ffdd..08df560a2c7a88c0f615ac428dbcb312ea0116a6 100644 (file)
@@ -63,6 +63,7 @@ static struct wmi_driver intel_wmi_thunderbolt_driver = {
                .dev_groups = tbt_groups,
        },
        .id_table = intel_wmi_thunderbolt_id_table,
+       .no_singleton = true,
 };
 
 module_wmi_driver(intel_wmi_thunderbolt_driver);
index 644d2fd889c081bd37299b2343339dd033d80ba0..df6f0ae6e6c7904f97c125297a21166f56d0b1f0 100644 (file)
@@ -94,6 +94,7 @@ static struct wmi_driver wmi_bmof_driver = {
        .probe = wmi_bmof_probe,
        .remove = wmi_bmof_remove,
        .id_table = wmi_bmof_id_table,
+       .no_singleton = true,
 };
 
 module_wmi_driver(wmi_bmof_driver);
index 29dfe52eb802879a8c789d1b7adbe66d5aba52aa..349deced87e86b0a473d74ee5b8e6cb9a95c97d1 100644 (file)
@@ -883,6 +883,18 @@ static int wmi_dev_probe(struct device *dev)
        struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);
        int ret = 0;
 
+       /* Some older WMI drivers will break if instantiated multiple times,
+        * so they are blocked from probing WMI devices with a duplicated GUID.
+        *
+        * New WMI drivers should support being instantiated multiple times.
+        */
+       if (test_bit(WMI_GUID_DUPLICATED, &wblock->flags) && !wdriver->no_singleton) {
+               dev_warn(dev, "Legacy driver %s cannot be instantiated multiple times\n",
+                        dev->driver->name);
+
+               return -ENODEV;
+       }
+
        if (wdriver->notify) {
                if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags) && !wdriver->no_notify_data)
                        return -ENODEV;
index 781958310bfba17e84be283f982d7f6f1bc6a1f3..63cca3b58d6dfebfa7d31fa2b952944d5e57b60c 100644 (file)
@@ -49,6 +49,7 @@ u8 wmidev_instance_count(struct wmi_device *wdev);
  * @driver: Driver model structure
  * @id_table: List of WMI GUIDs supported by this driver
  * @no_notify_data: Driver supports WMI events which provide no event data
+ * @no_singleton: Driver can be instantiated multiple times
  * @probe: Callback for device binding
  * @remove: Callback for device unbinding
  * @notify: Callback for receiving WMI events
@@ -59,6 +60,7 @@ struct wmi_driver {
        struct device_driver driver;
        const struct wmi_device_id *id_table;
        bool no_notify_data;
+       bool no_singleton;
 
        int (*probe)(struct wmi_device *wdev, const void *context);
        void (*remove)(struct wmi_device *wdev);