Since region programming sees all components in the topology as a port,
it's required that endpoints are treated equally. The easiest way to go
from endpoint to port is to simply cache it at creation time.

Signed-off-by: Ben Widawsky <[email protected]>

---
Changes since v2:
- Rebased on Dan's latest port/mem changes
- Keep a reference to the port until the memdev goes away
- add action to release device reference for the port
---
 drivers/cxl/cxlmem.h |  2 ++
 drivers/cxl/mem.c    | 35 ++++++++++++++++++++++++++++-------
 2 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 7ba0edb4a1ab..2b8c66616d4e 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -37,6 +37,7 @@
  * @id: id number of this memdev instance.
  * @detach_work: active memdev lost a port in its ancestry
  * @component_reg_phys: register base of component registers
+ * @port: The port created by this device
  */
 struct cxl_memdev {
        struct device dev;
@@ -44,6 +45,7 @@ struct cxl_memdev {
        struct cxl_dev_state *cxlds;
        struct work_struct detach_work;
        int id;
+       struct cxl_port *port;
 };
 
 static inline struct cxl_memdev *to_cxl_memdev(struct device *dev)
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index 27f9dd0d55b6..c36219193886 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -45,26 +45,31 @@ static int wait_for_media(struct cxl_memdev *cxlmd)
        return 0;
 }
 
-static int create_endpoint(struct cxl_memdev *cxlmd,
-                          struct cxl_port *parent_port)
+static struct cxl_port *create_endpoint(struct cxl_memdev *cxlmd,
+                                       struct cxl_port *parent_port)
 {
        struct cxl_dev_state *cxlds = cxlmd->cxlds;
        struct cxl_port *endpoint;
+       int rc;
 
        endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
                                     cxlds->component_reg_phys, parent_port);
        if (IS_ERR(endpoint))
-               return PTR_ERR(endpoint);
+               return endpoint;
 
        dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev));
 
        if (!endpoint->dev.driver) {
                dev_err(&cxlmd->dev, "%s failed probe\n",
                        dev_name(&endpoint->dev));
-               return -ENXIO;
+               return ERR_PTR(-ENXIO);
        }
 
-       return cxl_endpoint_autoremove(cxlmd, endpoint);
+       rc = cxl_endpoint_autoremove(cxlmd, endpoint);
+       if (rc)
+               return ERR_PTR(rc);
+
+       return endpoint;
 }
 
 /**
@@ -127,11 +132,18 @@ __mock bool cxl_dvsec_decode_init(struct cxl_dev_state 
*cxlds)
        return do_hdm_init;
 }
 
+static void delete_memdev(void *dev)
+{
+       struct cxl_memdev *cxlmd = dev;
+
+       put_device(&cxlmd->port->dev);
+}
+
 static int cxl_mem_probe(struct device *dev)
 {
        struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
        struct cxl_dev_state *cxlds = cxlmd->cxlds;
-       struct cxl_port *parent_port;
+       struct cxl_port *parent_port, *ep_port;
        int rc;
 
        /*
@@ -201,7 +213,16 @@ static int cxl_mem_probe(struct device *dev)
                goto out;
        }
 
-       rc = create_endpoint(cxlmd, parent_port);
+       ep_port = create_endpoint(cxlmd, parent_port);
+       if (IS_ERR(ep_port)) {
+               rc = PTR_ERR(ep_port);
+               goto out;
+       }
+
+       get_device(&ep_port->dev);
+       cxlmd->port = ep_port;
+
+       rc = devm_add_action_or_reset(dev, delete_memdev, cxlmd);
 out:
        cxl_device_unlock(&parent_port->dev);
        put_device(&parent_port->dev);
-- 
2.35.0


Reply via email to