[PATCH v2] cxl/core: Create einj_types when EINJ becomes available

From: Yongxin Yang

Date: Wed Oct 28 2026 - 04:51:32 EST


From: Yang Yongxin <yangyongxin@xxxxxxxxxx>

The einj_types file under the CXL debugfs directory is never created.

cxl_core_init() runs at subsys_initcall level, while EINJ registers itself
from einj_init() at module_init level. When cxl_core_init() evaluates
einj_cxl_is_initialized() the built-in EINJ driver has not been initialized
yet, so the value is always false and the debugfs_create_file("einj_types")
call below it is never reached. Users have no way to discover which CXL
error types the platform supports from debugfs.

Create the file from both places that can know EINJ is up: cxl_core_init(),
which covers the case where cxl_core is a module and einj has already been
initialized by the time the module is loaded, and the dport probe path,
which covers the built-in case. The dport probe path can run concurrently
for different parent ports, each holding only its own device lock, so
serialize the check and the create to avoid a duplicate
debugfs_create_file() attempt that would only fail with -EEXIST.

Note that this is still a partial fix: an RCH platform returns early from
devm_cxl_enumerate_ports() before any dport is added, so einj_types does
not appear there. Fixing that requires moving cxl_core_init() after EINJ
is probed, or creating the file from cxl_acpi_probe(), both of which are
out of scope here.

Fixes: 8039804cfa73 ("cxl/core: Add CXL EINJ debugfs files")
Cc: <stable@xxxxxxxxxxxxxxx>
Signed-off-by: Yang Yongxin <yangyongxin@xxxxxxxxxx>
---
Changes in v2:
- Create einj_types from cxl_core_init() as well, so that the module case,
where einj is already initialized when cxl_core is loaded, keeps working
and is not regressed by the lazy path alone.
- Serialize the check and the create with a mutex, as the dport probe path
can run concurrently for different parent ports.
- Spell out that RCH platforms are still not covered, and why.
- Rebase onto mainline, so the diff no longer carries the CXL fixes that
are queued in linux-next.

drivers/cxl/core/port.c | 34 ++++++++++++++++++++++++++++------
1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 625e4aa427db..c1736a00f22f 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -802,6 +802,30 @@ static int cxl_dport_setup_regs(struct device *host, struct cxl_dport *dport,

DEFINE_SHOW_ATTRIBUTE(einj_cxl_available_error_type);

+static struct dentry *cxl_debugfs;
+static struct dentry *einj_types_dentry;
+
+/*
+ * einj_types is created from two places: cxl_core_init() catches the case
+ * where cxl_core is a module and einj is already up, while the dport probe
+ * path catches the built-in case, where cxl_core_init() runs at
+ * subsys_initcall level before einj_init() has set einj_initialized.
+ *
+ * The dport probe path can run concurrently for different parent ports, each
+ * holding only its own device lock, so the check and the create need to be
+ * serialized to avoid a duplicate debugfs_create_file() attempt.
+ */
+static DEFINE_MUTEX(einj_types_lock);
+static void cxl_einj_debugfs_add_types(void)
+{
+ mutex_lock(&einj_types_lock);
+ if (!einj_types_dentry && einj_cxl_is_initialized())
+ einj_types_dentry = debugfs_create_file("einj_types", 0400,
+ cxl_debugfs, NULL,
+ &einj_cxl_available_error_type_fops);
+ mutex_unlock(&einj_types_lock);
+}
+
static int cxl_einj_inject(void *data, u64 type)
{
struct cxl_dport *dport = data;
@@ -819,6 +843,8 @@ static void cxl_debugfs_create_dport_dir(struct cxl_dport *dport)
struct cxl_port *parent = parent_port_of(dport->port);
struct dentry *dir;

+ cxl_einj_debugfs_add_types();
+
if (!einj_cxl_is_initialized())
return;

@@ -2501,8 +2527,6 @@ const struct bus_type cxl_bus_type = {
};
EXPORT_SYMBOL_NS_GPL(cxl_bus_type, "CXL");

-static struct dentry *cxl_debugfs;
-
struct dentry *cxl_debugfs_create_dir(const char *dir)
{
return debugfs_create_dir(dir, cxl_debugfs);
@@ -2515,10 +2539,6 @@ static __init int cxl_core_init(void)

cxl_debugfs = debugfs_create_dir("cxl", NULL);

- if (einj_cxl_is_initialized())
- debugfs_create_file("einj_types", 0400, cxl_debugfs, NULL,
- &einj_cxl_available_error_type_fops);
-
cxl_mbox_init();

rc = cxl_memdev_init();
@@ -2541,6 +2561,8 @@ static __init int cxl_core_init(void)

cxl_ras_init();

+ cxl_einj_debugfs_add_types();
+
return 0;

err_region:
--
2.25.1