]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
platform/x86/intel/tpmi/plr: Prevent fault during unbind
authorSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Thu, 30 Apr 2026 15:11:03 +0000 (08:11 -0700)
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Thu, 7 May 2026 13:06:29 +0000 (16:06 +0300)
This driver faults when intel vsec driver is unbound from PCI driver
interface. For example:

echo 0000:00:03.1 > /sys/bus/pci/drivers/intel_vsec/unbind

This is caused by accessing plr->dbgfs_dir after vsec_tpmi driver is
removed. Here vsec_tpmi driver is the parent. On unbind, the parent
device remove callback is called first which here will remove debugfs
interface. Hence plr->dbgfs_dir is no longer valid.

Register notifier for TPMI_CORE_EXIT and make this pointer to NULL,
so that debugfs_remove_recursive() is not called with bad plr->dbgfs_dir
pointer.

After notifier is returned the vsec_tpmi driver will call remove debugfs
by calling debugfs_remove_recursive().

Fixes: 811f67c51636 ("platform/x86/intel/tpmi: Add new auxiliary driver for performance limits")
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Cc: Stable@vger.kernel.org
Link: https://patch.msgid.link/20260430151103.1549733-4-srinivas.pandruvada@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
drivers/platform/x86/intel/plr_tpmi.c

index 05727169f49c14faba1727ba81eed6724c273ede..8faecc311038f914fee71e1014ee3267c56fb200 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/mutex.h>
+#include <linux/notifier.h>
 #include <linux/seq_file.h>
 #include <linux/sprintf.h>
 #include <linux/types.h>
@@ -60,6 +61,8 @@ struct tpmi_plr {
        struct tpmi_plr_die *die_info;
        int num_dies;
        struct auxiliary_device *auxdev;
+       struct notifier_block nb;
+       struct mutex lock;      /* Protect access to dbgfs_dir */
 };
 
 static const char * const plr_coarse_reasons[] = {
@@ -255,6 +258,30 @@ static ssize_t plr_status_write(struct file *filp, const char __user *ubuf,
 }
 DEFINE_SHOW_STORE_ATTRIBUTE(plr_status);
 
+static int intel_plr_notify(struct notifier_block *self, unsigned long action, void *data)
+{
+       struct tpmi_plr *plr = container_of(self, struct tpmi_plr, nb);
+
+       if (action == TPMI_CORE_EXIT) {
+               guard(mutex)(&plr->lock);
+               plr->dbgfs_dir = NULL;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static int intel_plr_register_notifier(struct notifier_block *nb)
+{
+       nb->notifier_call = intel_plr_notify;
+       nb->priority = 0;
+       return tpmi_register_notifier(nb);
+}
+
+static void intel_plr_unregister_notifier(struct notifier_block *nb)
+{
+       tpmi_unregister_notifier(nb);
+}
+
 static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)
 {
        struct oobmsm_plat_info *plat_info;
@@ -282,10 +309,18 @@ static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxilia
        if (!plr)
                return -ENOMEM;
 
+       err = devm_mutex_init(&auxdev->dev, &plr->lock);
+       if (err)
+               return err;
+
+       intel_plr_register_notifier(&plr->nb);
+
        plr->die_info = devm_kcalloc(&auxdev->dev, num_resources, sizeof(*plr->die_info),
                                     GFP_KERNEL);
-       if (!plr->die_info)
-               return -ENOMEM;
+       if (!plr->die_info) {
+               err = -ENOMEM;
+               goto err_notify;
+       }
 
        plr->num_dies = num_resources;
        plr->dbgfs_dir = debugfs_create_dir("plr", dentry);
@@ -326,6 +361,9 @@ static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxilia
 
 err:
        debugfs_remove_recursive(plr->dbgfs_dir);
+err_notify:
+       intel_plr_unregister_notifier(&plr->nb);
+
        return err;
 }
 
@@ -333,6 +371,9 @@ static void intel_plr_remove(struct auxiliary_device *auxdev)
 {
        struct tpmi_plr *plr = auxiliary_get_drvdata(auxdev);
 
+       intel_plr_unregister_notifier(&plr->nb);
+
+       guard(mutex)(&plr->lock);
        debugfs_remove_recursive(plr->dbgfs_dir);
 }