]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cxl/port: Arrange for always synchronous endpoint attach
authorDan Williams <dan.j.williams@intel.com>
Tue, 16 Dec 2025 00:56:13 +0000 (16:56 -0800)
committerDave Jiang <dave.jiang@intel.com>
Mon, 5 Jan 2026 17:14:10 +0000 (10:14 -0700)
Make it so that upon return from devm_cxl_add_endpoint() that
cxl_mem_probe() can assume that the endpoint has had a chance to complete
cxl_port_probe().  I.e. cxl_port module loading has completed prior to
device registration.

Delete the MODULE_SOFTDEP() as it is not sufficient for this purpose, but a
hard link-time dependency is reliable. Specifically MODULE_SOFTDEP() does
not guarantee that the module loading has completed prior to the completion
of the current module's init.

Cc: Smita Koralahalli <Smita.KoralahalliChannabasappa@amd.com>
Cc: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Tested-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Tested-by: Alejandro Lucero <alucerop@amd.com>
Link: https://patch.msgid.link/20251216005616.3090129-4-dan.j.williams@intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
drivers/cxl/cxl.h
drivers/cxl/mem.c
drivers/cxl/port.c

index ba17fa86d249ebd097198f5e8cf053d48fde54b7..c796c3db36e0bea22c4c4c635e87d171b367b7d1 100644 (file)
@@ -780,6 +780,8 @@ struct cxl_port *devm_cxl_add_port(struct device *host,
                                   struct cxl_dport *parent_dport);
 struct cxl_root *devm_cxl_add_root(struct device *host,
                                   const struct cxl_root_ops *ops);
+int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
+                         struct cxl_dport *parent_dport);
 struct cxl_root *find_cxl_root(struct cxl_port *port);
 
 DEFINE_FREE(put_cxl_root, struct cxl_root *, if (_T) put_device(&_T->port.dev))
index 55883797ab2db0e013552426e1ad0b41c9bd7124..d62931526fd413d1a9462e3b6ffc7f27a1eed0ed 100644 (file)
@@ -45,44 +45,6 @@ static int cxl_mem_dpa_show(struct seq_file *file, void *data)
        return 0;
 }
 
-static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
-                                struct cxl_dport *parent_dport)
-{
-       struct cxl_port *parent_port = parent_dport->port;
-       struct cxl_port *endpoint, *iter, *down;
-       int rc;
-
-       /*
-        * Now that the path to the root is established record all the
-        * intervening ports in the chain.
-        */
-       for (iter = parent_port, down = NULL; !is_cxl_root(iter);
-            down = iter, iter = to_cxl_port(iter->dev.parent)) {
-               struct cxl_ep *ep;
-
-               ep = cxl_ep_load(iter, cxlmd);
-               ep->next = down;
-       }
-
-       /* Note: endpoint port component registers are derived from @cxlds */
-       endpoint = devm_cxl_add_port(host, &cxlmd->dev, CXL_RESOURCE_NONE,
-                                    parent_dport);
-       if (IS_ERR(endpoint))
-               return PTR_ERR(endpoint);
-
-       rc = cxl_endpoint_autoremove(cxlmd, endpoint);
-       if (rc)
-               return rc;
-
-       if (!endpoint->dev.driver) {
-               dev_err(&cxlmd->dev, "%s failed probe\n",
-                       dev_name(&endpoint->dev));
-               return -ENXIO;
-       }
-
-       return 0;
-}
-
 static int cxl_debugfs_poison_inject(void *data, u64 dpa)
 {
        struct cxl_memdev *cxlmd = data;
@@ -275,8 +237,3 @@ MODULE_DESCRIPTION("CXL: Memory Expansion");
 MODULE_LICENSE("GPL v2");
 MODULE_IMPORT_NS("CXL");
 MODULE_ALIAS_CXL(CXL_DEVICE_MEMORY_EXPANDER);
-/*
- * create_endpoint() wants to validate port driver attach immediately after
- * endpoint registration.
- */
-MODULE_SOFTDEP("pre: cxl_port");
index 51c8f2f84717ac018ab02e9bf0365d9df1261be5..7937e7e53797c96462765a37eb7198f9b8c649a0 100644 (file)
@@ -156,10 +156,50 @@ static struct cxl_driver cxl_port_driver = {
        .probe = cxl_port_probe,
        .id = CXL_DEVICE_PORT,
        .drv = {
+               .probe_type = PROBE_FORCE_SYNCHRONOUS,
                .dev_groups = cxl_port_attribute_groups,
        },
 };
 
+int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
+                         struct cxl_dport *parent_dport)
+{
+       struct cxl_port *parent_port = parent_dport->port;
+       struct cxl_port *endpoint, *iter, *down;
+       int rc;
+
+       /*
+        * Now that the path to the root is established record all the
+        * intervening ports in the chain.
+        */
+       for (iter = parent_port, down = NULL; !is_cxl_root(iter);
+            down = iter, iter = to_cxl_port(iter->dev.parent)) {
+               struct cxl_ep *ep;
+
+               ep = cxl_ep_load(iter, cxlmd);
+               ep->next = down;
+       }
+
+       /* Note: endpoint port component registers are derived from @cxlds */
+       endpoint = devm_cxl_add_port(host, &cxlmd->dev, CXL_RESOURCE_NONE,
+                                    parent_dport);
+       if (IS_ERR(endpoint))
+               return PTR_ERR(endpoint);
+
+       rc = cxl_endpoint_autoremove(cxlmd, endpoint);
+       if (rc)
+               return rc;
+
+       if (!endpoint->dev.driver) {
+               dev_err(&cxlmd->dev, "%s failed probe\n",
+                       dev_name(&endpoint->dev));
+               return -ENXIO;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_FOR_MODULES(devm_cxl_add_endpoint, "cxl_mem");
+
 static int __init cxl_port_init(void)
 {
        return cxl_driver_register(&cxl_port_driver);