lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250107035708.1134954-2-ming.li@zohomail.com>
Date: Tue,  7 Jan 2025 11:57:01 +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 1/8] cxl/port: Enumerate port component regs when endpoint attaching

In some hardware platform, CXL host bridge does not expose its component
registers if no CXL device/switch is under it. in this case, CXL
subsystem will fail to enumerate component registers on such CXL host
bridge during CXL host bridge port attaching, because a CXL port
component registers are enumerated during adding the port to the
hierarchy.

To solve above issue, CXL port component registers enumeration should be
delayed until the first endpoint attaching, the implementations is
moving port component registers enumeration from devm_cxl_add_port() to
devm_cxl_add_endpoint().

Signed-off-by: Li Ming <ming.li@...omail.com>
---
 drivers/cxl/core/port.c | 102 ++++++++++++++++++++++++++--------------
 drivers/cxl/cxl.h       |   4 ++
 drivers/cxl/port.c      |  19 ++++++++
 3 files changed, 91 insertions(+), 34 deletions(-)

diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 78a5c2c25982..1022c0775daa 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -596,6 +596,12 @@ struct cxl_port *to_cxl_port(const struct device *dev)
 }
 EXPORT_SYMBOL_NS_GPL(to_cxl_port, "CXL");
 
+static void cxl_register_map_reset(struct cxl_register_map *map)
+{
+	*map = (struct cxl_register_map){ 0 };
+	map->resource = CXL_RESOURCE_NONE;
+}
+
 static void unregister_port(void *_port)
 {
 	struct cxl_port *port = _port;
@@ -735,6 +741,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev,
 	ida_init(&port->decoder_ida);
 	port->hdm_end = -1;
 	port->commit_end = -1;
+	cxl_register_map_reset(&port->reg_map);
 	xa_init(&port->dports);
 	xa_init(&port->endpoints);
 	xa_init(&port->regions);
@@ -766,14 +773,52 @@ static int cxl_setup_comp_regs(struct device *host, struct cxl_register_map *map
 	return cxl_setup_regs(map);
 }
 
-static int cxl_port_setup_regs(struct cxl_port *port,
-			resource_size_t component_reg_phys)
+static resource_size_t find_component_registers(struct device *dev)
 {
+	struct cxl_register_map map;
+	struct pci_dev *pdev;
+
+	/*
+	 * Theoretically, CXL component registers can be hosted on a
+	 * non-PCI device, in practice, only cxl_test hits this case.
+	 */
+	if (!dev_is_pci(dev))
+		return CXL_RESOURCE_NONE;
+
+	pdev = to_pci_dev(dev);
+
+	cxl_find_regblock(pdev, CXL_REGLOC_RBI_COMPONENT, &map);
+	return map.resource;
+}
+
+/**
+ * cxl_port_setup_regs - probe all component registers of a cxl port
+ * @port: target cxl port
+ */
+int cxl_port_setup_regs(struct cxl_port *port)
+{
+	resource_size_t component_reg_phys;
+
 	if (dev_is_platform(port->uport_dev))
 		return 0;
+	/* component registers have been set up */
+	if (port->reg_map.resource != CXL_RESOURCE_NONE)
+		return 0;
+
+	if (is_cxl_root(to_cxl_port(port->dev.parent)))
+		component_reg_phys = port->chbcr;
+	else
+		component_reg_phys = find_component_registers(port->uport_dev);
+
+	if (component_reg_phys == CXL_RESOURCE_NONE) {
+		dev_warn(&port->dev, "Invalid Component Registers");
+		return -ENXIO;
+	}
+
 	return cxl_setup_comp_regs(&port->dev, &port->reg_map,
 				   component_reg_phys);
 }
+EXPORT_SYMBOL_NS_GPL(cxl_port_setup_regs, "CXL");
 
 static int cxl_dport_setup_regs(struct device *host, struct cxl_dport *dport,
 				resource_size_t component_reg_phys)
@@ -856,9 +901,8 @@ static int cxl_port_add(struct cxl_port *port,
 		if (rc)
 			return rc;
 
-		rc = cxl_port_setup_regs(port, component_reg_phys);
-		if (rc)
-			return rc;
+		if (is_cxl_root(parent_dport->port))
+			port->chbcr = component_reg_phys;
 	} else {
 		rc = dev_set_name(dev, "root%d", port->id);
 		if (rc)
@@ -1499,16 +1543,26 @@ static void cxl_detach_ep(void *data)
 		dev_dbg(&cxlmd->dev, "disconnect %s from %s\n",
 			ep ? dev_name(ep->ep) : "", dev_name(&port->dev));
 		cxl_ep_remove(port, ep);
-		if (ep && !port->dead && xa_empty(&port->endpoints) &&
-		    !is_cxl_root(parent_port) && parent_port->dev.driver) {
+		if (ep && xa_empty(&port->endpoints)) {
 			/*
-			 * This was the last ep attached to a dynamically
-			 * enumerated port. Block new cxl_add_ep() and garbage
-			 * collect the port.
+			 * Reset component registers information on the port
+			 * during the last ep detaching. So that the next ep
+			 * attaching can trigger component registers probing
+			 * again.
 			 */
-			died = true;
-			port->dead = true;
-			reap_dports(port);
+			cxl_register_map_reset(&port->reg_map);
+
+			if (!port->dead && !is_cxl_root(parent_port) &&
+			    parent_port->dev.driver) {
+				/*
+				 * This was the last ep attached to a dynamically
+				 * enumerated port. Block new cxl_add_ep() and garbage
+				 * collect the port.
+				 */
+				died = true;
+				port->dead = true;
+				reap_dports(port);
+			}
 		}
 		device_unlock(&port->dev);
 
@@ -1521,31 +1575,12 @@ static void cxl_detach_ep(void *data)
 	}
 }
 
-static resource_size_t find_component_registers(struct device *dev)
-{
-	struct cxl_register_map map;
-	struct pci_dev *pdev;
-
-	/*
-	 * Theoretically, CXL component registers can be hosted on a
-	 * non-PCI device, in practice, only cxl_test hits this case.
-	 */
-	if (!dev_is_pci(dev))
-		return CXL_RESOURCE_NONE;
-
-	pdev = to_pci_dev(dev);
-
-	cxl_find_regblock(pdev, CXL_REGLOC_RBI_COMPONENT, &map);
-	return map.resource;
-}
-
 static int add_port_attach_ep(struct cxl_memdev *cxlmd,
 			      struct device *uport_dev,
 			      struct device *dport_dev)
 {
 	struct device *dparent = grandparent(dport_dev);
 	struct cxl_dport *dport, *parent_dport;
-	resource_size_t component_reg_phys;
 	int rc;
 
 	if (!dparent) {
@@ -1581,9 +1616,8 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd,
 
 		port = find_cxl_port_at(parent_port, dport_dev, &dport);
 		if (!port) {
-			component_reg_phys = find_component_registers(uport_dev);
 			port = devm_cxl_add_port(&parent_port->dev, uport_dev,
-						 component_reg_phys, parent_dport);
+						 CXL_RESOURCE_NONE, parent_dport);
 			if (IS_ERR(port))
 				return PTR_ERR(port);
 
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index f6015f24ad38..9877a0ddb5e9 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -601,6 +601,7 @@ struct cxl_dax_region {
  * @parent_dport: dport that points to this port in the parent
  * @decoder_ida: allocator for decoder ids
  * @reg_map: component and ras register mapping parameters
+ * @chbcr: physical address of CXL host bridge component registers
  * @nr_dports: number of entries in @dports
  * @hdm_end: track last allocated HDM decoder instance for allocation ordering
  * @commit_end: cursor to track highest committed decoder for commit ordering
@@ -621,6 +622,7 @@ struct cxl_port {
 	struct cxl_dport *parent_dport;
 	struct ida decoder_ida;
 	struct cxl_register_map reg_map;
+	resource_size_t chbcr;
 	int nr_dports;
 	int hdm_end;
 	int commit_end;
@@ -771,6 +773,8 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
 					 struct device *dport_dev, int port_id,
 					 resource_size_t rcrb);
 
+int cxl_port_setup_regs(struct cxl_port *port);
+
 #ifdef CONFIG_PCIEAER_CXL
 void cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport);
 void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 4c83f6a22e58..ae09bbbe0a17 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -91,6 +91,7 @@ static int cxl_switch_port_probe(struct cxl_port *port)
 
 static int cxl_endpoint_port_probe(struct cxl_port *port)
 {
+	struct cxl_port *iter, *parent_port = to_cxl_port(port->dev.parent);
 	struct cxl_endpoint_dvsec_info info = { .port = port };
 	struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
 	struct cxl_dev_state *cxlds = cxlmd->cxlds;
@@ -98,6 +99,24 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 	struct cxl_port *root;
 	int rc;
 
+	for (iter = parent_port; !is_cxl_root(iter);
+	     iter = to_cxl_port(iter->dev.parent)) {
+		/*
+		 * The parent port of endpoint has been locked
+		 * during endpoint port attaching.
+		 * Holding the device lock of port to make sure
+		 * the setup not invoked in parallel.
+		 */
+		if (iter != parent_port) {
+			guard(device)(&iter->dev);
+			rc = cxl_port_setup_regs(iter);
+		} else {
+			rc = cxl_port_setup_regs(iter);
+		}
+		if (rc)
+			return rc;
+	}
+
 	rc = cxl_dvsec_rr_decode(cxlds->dev, port, &info);
 	if (rc < 0)
 		return rc;
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ