summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/cxl/core/port.c7
-rw-r--r--drivers/cxl/cxlmem.h2
-rw-r--r--drivers/cxl/mem.c33
-rw-r--r--drivers/cxl/pci.c10
4 files changed, 44 insertions, 8 deletions
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 4982b6902ef5..50bdbd9f8da3 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -1369,6 +1369,13 @@ int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd)
struct device *iter;
int rc;
+ /*
+ * Skip intermediate port enumeration in the RCH case, there
+ * are no ports in between a host bridge and an endpoint.
+ */
+ if (cxlmd->cxlds->rcd)
+ return 0;
+
rc = devm_add_action_or_reset(&cxlmd->dev, cxl_detach_ep, cxlmd);
if (rc)
return rc;
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index e082991bc58c..35d485d041f0 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -201,6 +201,7 @@ struct cxl_endpoint_dvsec_info {
* @dev: The device associated with this CXL state
* @regs: Parsed register blocks
* @cxl_dvsec: Offset to the PCIe device DVSEC
+ * @rcd: operating in RCD mode (CXL 3.0 9.11.8 CXL Devices Attached to an RCH)
* @payload_size: Size of space for payload
* (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register)
* @lsa_size: Size of Label Storage Area
@@ -235,6 +236,7 @@ struct cxl_dev_state {
struct cxl_regs regs;
int cxl_dvsec;
+ bool rcd;
size_t payload_size;
size_t lsa_size;
struct mutex mbox_mutex; /* Protects device mailbox and firmware */
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index aa63ce8c7ca6..39c4b54f0715 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -45,12 +45,13 @@ static int cxl_mem_dpa_show(struct seq_file *file, void *data)
return 0;
}
-static int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd,
+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_dev_state *cxlds = cxlmd->cxlds;
struct cxl_port *endpoint, *iter, *down;
+ resource_size_t component_reg_phys;
int rc;
/*
@@ -65,8 +66,18 @@ static int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd,
ep->next = down;
}
- endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
- cxlds->component_reg_phys, parent_dport);
+ /*
+ * The component registers for an RCD might come from the
+ * host-bridge RCRB if they are not already mapped via the
+ * typical register locator mechanism.
+ */
+ if (parent_dport->rch && cxlds->component_reg_phys == CXL_RESOURCE_NONE)
+ component_reg_phys = cxl_rcrb_to_component(
+ &cxlmd->dev, parent_dport->rcrb, CXL_RCRB_UPSTREAM);
+ else
+ component_reg_phys = cxlds->component_reg_phys;
+ endpoint = devm_cxl_add_port(host, &cxlmd->dev, component_reg_phys,
+ parent_dport);
if (IS_ERR(endpoint))
return PTR_ERR(endpoint);
@@ -87,6 +98,7 @@ static int cxl_mem_probe(struct device *dev)
{
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct device *endpoint_parent;
struct cxl_port *parent_port;
struct cxl_dport *dport;
struct dentry *dentry;
@@ -119,17 +131,22 @@ static int cxl_mem_probe(struct device *dev)
return -ENXIO;
}
- device_lock(&parent_port->dev);
- if (!parent_port->dev.driver) {
+ if (dport->rch)
+ endpoint_parent = parent_port->uport;
+ else
+ endpoint_parent = &parent_port->dev;
+
+ device_lock(endpoint_parent);
+ if (!endpoint_parent->driver) {
dev_err(dev, "CXL port topology %s not enabled\n",
- dev_name(&parent_port->dev));
+ dev_name(endpoint_parent));
rc = -ENXIO;
goto unlock;
}
- rc = devm_cxl_add_endpoint(cxlmd, dport);
+ rc = devm_cxl_add_endpoint(endpoint_parent, cxlmd, dport);
unlock:
- device_unlock(&parent_port->dev);
+ device_unlock(endpoint_parent);
put_device(&parent_port->dev);
if (rc)
return rc;
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index e15da405b948..73ff6c33a0c0 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -433,6 +433,15 @@ static void devm_cxl_pci_create_doe(struct cxl_dev_state *cxlds)
}
}
+/*
+ * Assume that any RCIEP that emits the CXL memory expander class code
+ * is an RCD
+ */
+static bool is_cxl_restricted(struct pci_dev *pdev)
+{
+ return pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END;
+}
+
static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct cxl_register_map map;
@@ -455,6 +464,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (IS_ERR(cxlds))
return PTR_ERR(cxlds);
+ cxlds->rcd = is_cxl_restricted(pdev);
cxlds->serial = pci_get_dsn(pdev);
cxlds->cxl_dvsec = pci_find_dvsec_capability(
pdev, PCI_DVSEC_VENDOR_ID_CXL, CXL_DVSEC_PCIE_DEVICE);