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: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250107035708.1134954-7-ming.li@zohomail.com>
Date: Tue,  7 Jan 2025 11:57:06 +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 6/8] cxl/port: Enumerate dport component registers when endpoint attaching

In some hardware platform, dport's component registers are exposed only
when the dport is working on CXL mode and connecting to a CXL switch/CXL
device.

Currently, CXL subsystem will probe a dport's component registers when
the dport added to its port. In VH case, a root port's component
registers are probed during the host bridge the root port belongs to
attaching. As mentioned above, if no CXL/switch/CXL device connected to
the root port, root port component registers setup will failed.

The solution is delaying all CXL non-RCH dport component registers
enumeration until the first endpoint attaching.

Signed-off-by: Li Ming <ming.li@...omail.com>
---
 drivers/cxl/core/pci.c  |  8 +------
 drivers/cxl/core/port.c | 53 ++++++++++++++++++++++++++---------------
 drivers/cxl/cxl.h       |  1 +
 drivers/cxl/port.c      | 20 ++++++++++------
 4 files changed, 49 insertions(+), 33 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 9d58ab9d33c5..3b22f3033484 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -37,10 +37,8 @@ static int match_add_dports(struct pci_dev *pdev, void *data)
 	struct cxl_walk_context *ctx = data;
 	struct cxl_port *port = ctx->port;
 	int type = pci_pcie_type(pdev);
-	struct cxl_register_map map;
 	struct cxl_dport *dport;
 	u32 lnkcap, port_num;
-	int rc;
 
 	if (pdev->bus != ctx->bus)
 		return 0;
@@ -52,12 +50,8 @@ static int match_add_dports(struct pci_dev *pdev, void *data)
 				  &lnkcap))
 		return 0;
 
-	rc = cxl_find_regblock(pdev, CXL_REGLOC_RBI_COMPONENT, &map);
-	if (rc)
-		dev_dbg(&port->dev, "failed to find component registers\n");
-
 	port_num = FIELD_GET(PCI_EXP_LNKCAP_PN, lnkcap);
-	dport = devm_cxl_add_dport(port, &pdev->dev, port_num, map.resource);
+	dport = devm_cxl_add_dport(port, &pdev->dev, port_num, CXL_RESOURCE_NONE);
 	if (IS_ERR(dport)) {
 		ctx->error = PTR_ERR(dport);
 		return PTR_ERR(dport);
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index b406ba64f6bc..04617ab825ee 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -626,6 +626,8 @@ static void unregister_port(void *_port)
 		lock_dev = &parent->dev;
 
 	device_lock_assert(lock_dev);
+	if (port->parent_dport && !port->parent_dport->rch)
+		cxl_register_map_reset(&port->parent_dport->reg_map);
 	port->dead = true;
 	device_unregister(&port->dev);
 }
@@ -820,13 +822,39 @@ int cxl_port_setup_regs(struct cxl_port *port)
 }
 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)
+/**
+ * cxl_dport_setup_regs - probe all component registers of a cxl dport
+ * @dport: target cxl dport
+ */
+int cxl_dport_setup_regs(struct cxl_dport *dport)
 {
+	resource_size_t component_reg_phys;
+	struct device *host;
 	int rc;
 
 	if (dev_is_platform(dport->dport_dev))
 		return 0;
+	/* component registers have been set up */
+	if (dport->reg_map.resource != CXL_RESOURCE_NONE)
+		return 0;
+
+	if (dport->rcrb.base) {
+		component_reg_phys = __rcrb_to_component(dport->dport_dev, &dport->rcrb,
+							 CXL_RCRB_DOWNSTREAM);
+		host = NULL;
+	} else {
+		component_reg_phys = find_component_registers(dport->dport_dev);
+		host = &dport->port->dev;
+	}
+
+	if (component_reg_phys == CXL_RESOURCE_NONE) {
+		dev_warn(dport->dport_dev, "Invalid Component Registers%s",
+			 dport->rcrb.base ? " in RCRB" : "");
+		return -ENXIO;
+	}
+
+	dev_dbg(dport->dport_dev, "Component Registers found for dport: %pa\n",
+		&component_reg_phys);
 
 	/*
 	 * use @dport->dport_dev for the context for error messages during
@@ -838,6 +866,7 @@ static int cxl_dport_setup_regs(struct device *host, struct cxl_dport *dport,
 	dport->reg_map.host = host;
 	return rc;
 }
+EXPORT_SYMBOL_NS_GPL(cxl_dport_setup_regs, "CXL");
 
 DEFINE_SHOW_ATTRIBUTE(einj_cxl_available_error_type);
 
@@ -1176,39 +1205,25 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
 	if (!dport)
 		return ERR_PTR(-ENOMEM);
 
+	cxl_register_map_reset(&dport->reg_map);
 	dport->dport_dev = dport_dev;
 	dport->port_id = port_id;
 	dport->port = port;
 
-	if (rcrb == CXL_RESOURCE_NONE) {
-		rc = cxl_dport_setup_regs(&port->dev, dport,
-					  component_reg_phys);
-		if (rc)
-			return ERR_PTR(rc);
-	} else {
+	if (rcrb != CXL_RESOURCE_NONE) {
 		dport->rcrb.base = rcrb;
-		component_reg_phys = __rcrb_to_component(dport_dev, &dport->rcrb,
-							 CXL_RCRB_DOWNSTREAM);
-		if (component_reg_phys == CXL_RESOURCE_NONE) {
-			dev_warn(dport_dev, "Invalid Component Registers in RCRB");
-			return ERR_PTR(-ENXIO);
-		}
 
 		/*
 		 * RCH @dport is not ready to map until associated with its
 		 * memdev
 		 */
-		rc = cxl_dport_setup_regs(NULL, dport, component_reg_phys);
+		rc = cxl_dport_setup_regs(dport);
 		if (rc)
 			return ERR_PTR(rc);
 
 		dport->rch = true;
 	}
 
-	if (component_reg_phys != CXL_RESOURCE_NONE)
-		dev_dbg(dport_dev, "Component Registers found for dport: %pa\n",
-			&component_reg_phys);
-
 	cond_cxl_root_lock(port);
 	rc = add_dport(port, dport);
 	cond_cxl_root_unlock(port);
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 7763be02ef81..601818861441 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -773,6 +773,7 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
 					 resource_size_t rcrb);
 
 int cxl_port_setup_regs(struct cxl_port *port);
+int cxl_dport_setup_regs(struct cxl_dport *dport);
 
 #ifdef CONFIG_PCIEAER_CXL
 void cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport);
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index c59f198f6cb0..ec135628edcb 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -100,7 +100,7 @@ static int cxl_switch_port_setup_hdm(struct cxl_port *port)
 	return -ENXIO;
 }
 
-static int cxl_switch_port_setup(struct cxl_port *port)
+static int cxl_switch_port_setup(struct cxl_port *port, struct cxl_dport *dport)
 {
 	int rc;
 
@@ -108,12 +108,16 @@ static int cxl_switch_port_setup(struct cxl_port *port)
 	if (rc)
 		return rc;
 
-	return cxl_switch_port_setup_hdm(port);
+	rc = cxl_switch_port_setup_hdm(port);
+	if (rc)
+		return rc;
+
+	return cxl_dport_setup_regs(dport);
 }
 
 static int cxl_endpoint_port_probe(struct cxl_port *port)
 {
-	struct cxl_port *iter, *parent_port = to_cxl_port(port->dev.parent);
+	struct cxl_port *iter, *prev, *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;
@@ -121,8 +125,10 @@ 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)) {
+	for (iter = parent_port, prev = NULL; !is_cxl_root(iter);
+	     prev = iter, iter = to_cxl_port(iter->dev.parent)) {
+		struct cxl_dport *dport = prev ? prev->parent_dport :
+					port->parent_dport;
 		/*
 		 * The parent port of endpoint has been locked
 		 * during endpoint port attaching.
@@ -131,9 +137,9 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 		 */
 		if (iter != parent_port) {
 			guard(device)(&iter->dev);
-			rc = cxl_switch_port_setup(iter);
+			rc = cxl_switch_port_setup(iter, dport);
 		} else {
-			rc = cxl_switch_port_setup(iter);
+			rc = cxl_switch_port_setup(iter, dport);
 		}
 		if (rc)
 			return rc;
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ