[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250107035708.1134954-5-ming.li@zohomail.com>
Date: Tue, 7 Jan 2025 11:57:04 +0800
From: Li Ming <ming.li@...omail.com>
To: dave@...olabs.net,
jonathan.cameron@...wei.com,
dave.jiang@...el.com,
alison.schofield@...el.com,
vishal.l.verma@...el.com,
ira.weiny@...el.com,
dan.j.williams@...el.com
Cc: linux-cxl@...r.kernel.org,
linux-kernel@...r.kernel.org,
Li Ming <ming.li@...omail.com>
Subject: [RFC PATCH 4/8] cxl/port: Remove port HDM during the last endpoint detaching
HDM is set up on a CXL port when the first endpoint under the port
attaching. The HDM should be released when no endpoint is under the port
so that the first endpoint attaching can trigger HDM setup on the port
again next time. So remove HDM and decoders on a CXL port if no endpoint
is working under it.
Signed-off-by: Li Ming <ming.li@...omail.com>
---
drivers/cxl/core/port.c | 60 +++++++++++++++++++++++++++++++----------
drivers/cxl/core/regs.c | 9 ++++++-
2 files changed, 54 insertions(+), 15 deletions(-)
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 1022c0775daa..57ed152d96d7 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -1517,6 +1517,49 @@ static int port_has_memdev(struct device *dev, const void *data)
return !!cxl_ep_load(port, ctx->cxlmd);
}
+static void cxld_unregister(void *dev)
+{
+ struct cxl_endpoint_decoder *cxled;
+
+ if (is_endpoint_decoder(dev)) {
+ cxled = to_cxl_endpoint_decoder(dev);
+ cxl_decoder_kill_region(cxled);
+ }
+
+ device_unregister(dev);
+}
+
+static int cxl_decoder_remove(struct device *dev, void *data)
+{
+ struct cxl_port *port = (struct cxl_port *)data;
+
+ if (!is_switch_decoder(dev) && !is_endpoint_decoder(dev))
+ return 0;
+
+ devm_release_action(&port->dev, cxld_unregister, dev);
+ return 0;
+}
+
+static void cxl_port_remove_hdm(struct cxl_port *port)
+{
+ const struct cxl_reg_map *rmap = &port->reg_map.component_map.hdm_decoder;
+ struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
+ resource_size_t addr, length;
+
+ if (!cxlhdm)
+ return;
+
+ device_for_each_child(&port->dev, port, cxl_decoder_remove);
+ if (cxlhdm->regs.hdm_decoder) {
+ devm_iounmap(&port->dev, cxlhdm->regs.hdm_decoder);
+ addr = port->reg_map.resource + rmap->offset;
+ length = rmap->size;
+ devm_release_mem_region(&port->dev, addr, length);
+ }
+ devm_kfree(&port->dev, cxlhdm);
+ dev_set_drvdata(&port->dev, NULL);
+}
+
static void cxl_detach_ep(void *data)
{
struct cxl_memdev *cxlmd = data;
@@ -1545,11 +1588,12 @@ static void cxl_detach_ep(void *data)
cxl_ep_remove(port, ep);
if (ep && xa_empty(&port->endpoints)) {
/*
- * Reset component registers information on the port
+ * Reset HDM and component registers information on the port
* during the last ep detaching. So that the next ep
* attaching can trigger component registers probing
- * again.
+ * and HDM setup again.
*/
+ cxl_port_remove_hdm(port);
cxl_register_map_reset(&port->reg_map);
if (!port->dead && !is_cxl_root(parent_port) &&
@@ -2031,18 +2075,6 @@ int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map)
}
EXPORT_SYMBOL_NS_GPL(cxl_decoder_add, "CXL");
-static void cxld_unregister(void *dev)
-{
- struct cxl_endpoint_decoder *cxled;
-
- if (is_endpoint_decoder(dev)) {
- cxled = to_cxl_endpoint_decoder(dev);
- cxl_decoder_kill_region(cxled);
- }
-
- device_unregister(dev);
-}
-
int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld)
{
return devm_add_action_or_reset(host, cxld_unregister, &cxld->dev);
diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index 59cb35b40c7e..7aba68785287 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -194,8 +194,15 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
}
ret_val = devm_ioremap(dev, addr, length);
- if (!ret_val)
+ if (!ret_val) {
dev_err(dev, "Failed to map region %pr\n", res);
+ /*
+ * Explicitly release mem region in failure case
+ * so that no need to consider the case of devm_request_mem_region()
+ * success but devm_ioremap() failure in cxl_port_remove_hdm().
+ */
+ devm_release_mem_region(dev, addr, length);
+ }
return ret_val;
}
--
2.34.1
Powered by blists - more mailing lists