platform/x86/intel/tpmi/plr: Prevent fault during unbind

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: 811f67c516 ("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>
This commit is contained in:
Srinivas Pandruvada
2026-04-30 08:11:03 -07:00
committed by Ilpo Järvinen
parent 57c347a2e2
commit 14473e8c4e

View 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);
}