--- v6
+++ v4
@@ -1,125 +1,144 @@
From: Robert Richter <rrichter@amd.com>
-Just moving code to reorder functions to later share cxl_get_chbs()
-with add_host_bridge_uport().
+CXL RAS capabilities must be enabled and accessible as soon as the CXL
+endpoint is detected in the PCI hierarchy and bound to the cxl_pci
+driver. This needs to be independent of other modules such as cxl_port
+or cxl_mem.
-This makes changes in the next patch visible. No other changes at all.
+CXL RAS capabilities reside in the Component Registers. For an RCH
+this is determined by probing RCRB which is implemented very late once
+the CXL Memory Device is created.
+
+Change this by moving the RCRB probe to the cxl_pci driver. Do this by
+using a new introduced function cxl_pci_find_port() similar to
+cxl_mem_find_port() to determine the involved dport by the endpoint's
+PCI handle. Plug this into the existing cxl_pci_setup_regs() function
+to setup Component Registers. Probe the RCRB in case the Component
+Registers cannot be located through the CXL Register Locator
+capability.
+
+This unifies code and early sets up the Component Registers at the
+same time for both, VH and RCH mode. Only the cxl_pci driver is
+involved for this. This allows an early mapping of the CXL RAS
+capability registers.
Signed-off-by: Robert Richter <rrichter@amd.com>
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
-Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
- drivers/cxl/acpi.c | 90 +++++++++++++++++++++++-----------------------
- 1 file changed, 45 insertions(+), 45 deletions(-)
+ drivers/cxl/core/port.c | 7 +++++++
+ drivers/cxl/cxl.h | 2 ++
+ drivers/cxl/mem.c | 12 ------------
+ drivers/cxl/pci.c | 37 ++++++++++++++++++++++++++++++++++++-
+ 4 files changed, 45 insertions(+), 13 deletions(-)
-diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
-index 70cd9ac73a8b..0c975ee684b0 100644
---- a/drivers/cxl/acpi.c
-+++ b/drivers/cxl/acpi.c
-@@ -327,51 +327,6 @@ __mock struct acpi_device *to_cxl_host_bridge(struct device *host,
- return NULL;
+diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
+index 66f567480238..eff91f141fde 100644
+--- a/drivers/cxl/core/port.c
++++ b/drivers/cxl/core/port.c
+@@ -1477,6 +1477,13 @@ int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd)
}
+ EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, CXL);
--/*
-- * A host bridge is a dport to a CFMWS decode and it is a uport to the
-- * dport (PCIe Root Ports) in the host bridge.
-- */
--static int add_host_bridge_uport(struct device *match, void *arg)
--{
-- struct cxl_port *root_port = arg;
-- struct device *host = root_port->dev.parent;
-- struct acpi_device *hb = to_cxl_host_bridge(host, match);
-- struct acpi_pci_root *pci_root;
-- struct cxl_dport *dport;
-- struct cxl_port *port;
-- struct device *bridge;
-- int rc;
--
-- if (!hb)
-- return 0;
--
-- pci_root = acpi_pci_find_root(hb->handle);
-- bridge = pci_root->bus->bridge;
-- dport = cxl_find_dport_by_dev(root_port, bridge);
-- if (!dport) {
-- dev_dbg(host, "host bridge expected and not found\n");
-- return 0;
++struct cxl_port *cxl_pci_find_port(struct pci_dev *pdev,
++ struct cxl_dport **dport)
++{
++ return find_cxl_port(pdev->dev.parent, dport);
++}
++EXPORT_SYMBOL_NS_GPL(cxl_pci_find_port, CXL);
++
+ struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
+ struct cxl_dport **dport)
+ {
+diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
+index 1c6fe53e9dc7..e5ae5f4e6669 100644
+--- a/drivers/cxl/cxl.h
++++ b/drivers/cxl/cxl.h
+@@ -670,6 +670,8 @@ struct cxl_port *find_cxl_root(struct cxl_port *port);
+ int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
+ void cxl_bus_rescan(void);
+ void cxl_bus_drain(void);
++struct cxl_port *cxl_pci_find_port(struct pci_dev *pdev,
++ struct cxl_dport **dport);
+ struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
+ struct cxl_dport **dport);
+ bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd);
+diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
+index 7ecdaa7f9315..0643852444f3 100644
+--- a/drivers/cxl/mem.c
++++ b/drivers/cxl/mem.c
+@@ -65,18 +65,6 @@ static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
+ ep->next = down;
+ }
+
+- /*
+- * 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) {
+- cxlds->component_reg_phys =
+- cxl_probe_rcrb(&cxlmd->dev, parent_dport->rcrb.base,
+- NULL, CXL_RCRB_UPSTREAM);
- }
-
-- if (dport->rch) {
-- dev_info(bridge, "host supports CXL (restricted)\n");
-- return 0;
-- }
--
-- rc = devm_cxl_register_pci_bus(host, bridge, pci_root->bus);
-- if (rc)
-- return rc;
--
-- port = devm_cxl_add_port(host, bridge, dport->component_reg_phys,
-- dport);
-- if (IS_ERR(port))
-- return PTR_ERR(port);
--
-- dev_info(bridge, "host supports CXL\n");
--
-- return 0;
--}
--
- /* Note, @dev is used by mock_acpi_table_parse_cedt() */
- struct cxl_chbs_context {
- struct device *dev;
-@@ -467,6 +422,51 @@ static int add_host_bridge_dport(struct device *match, void *arg)
+ endpoint = devm_cxl_add_port(host, &cxlmd->dev,
+ cxlds->component_reg_phys,
+ parent_dport);
+diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
+index 945ca0304d68..54c486cd65dd 100644
+--- a/drivers/cxl/pci.c
++++ b/drivers/cxl/pci.c
+@@ -274,13 +274,48 @@ static int cxl_pci_setup_mailbox(struct cxl_dev_state *cxlds)
return 0;
}
-+/*
-+ * A host bridge is a dport to a CFMWS decode and it is a uport to the
-+ * dport (PCIe Root Ports) in the host bridge.
-+ */
-+static int add_host_bridge_uport(struct device *match, void *arg)
++/* Extract RCRB, use same function interface as cxl_find_regblock(). */
++static int cxl_rcrb_get_comp_regs(struct pci_dev *pdev,
++ enum cxl_regloc_type type,
++ struct cxl_register_map *map)
+{
-+ struct cxl_port *root_port = arg;
-+ struct device *host = root_port->dev.parent;
-+ struct acpi_device *hb = to_cxl_host_bridge(host, match);
-+ struct acpi_pci_root *pci_root;
+ struct cxl_dport *dport;
-+ struct cxl_port *port;
-+ struct device *bridge;
-+ int rc;
++ resource_size_t component_reg_phys;
+
-+ if (!hb)
-+ return 0;
++ memset(map, 0, sizeof(*map));
++ map->dev = &pdev->dev;
++ map->resource = CXL_RESOURCE_NONE;
+
-+ pci_root = acpi_pci_find_root(hb->handle);
-+ bridge = pci_root->bus->bridge;
-+ dport = cxl_find_dport_by_dev(root_port, bridge);
-+ if (!dport) {
-+ dev_dbg(host, "host bridge expected and not found\n");
-+ return 0;
-+ }
++ if (type != CXL_REGLOC_RBI_COMPONENT)
++ return -ENODEV;
+
-+ if (dport->rch) {
-+ dev_info(bridge, "host supports CXL (restricted)\n");
-+ return 0;
-+ }
++ if (!cxl_pci_find_port(pdev, &dport) || !dport->rch)
++ return -ENXIO;
+
-+ rc = devm_cxl_register_pci_bus(host, bridge, pci_root->bus);
-+ if (rc)
-+ return rc;
++ component_reg_phys = cxl_probe_rcrb(&pdev->dev, dport->rcrb.base,
++ NULL, CXL_RCRB_UPSTREAM);
++ if (component_reg_phys == CXL_RESOURCE_NONE)
++ return -ENXIO;
+
-+ port = devm_cxl_add_port(host, bridge, dport->component_reg_phys,
-+ dport);
-+ if (IS_ERR(port))
-+ return PTR_ERR(port);
-+
-+ dev_info(bridge, "host supports CXL\n");
++ map->resource = component_reg_phys;
++ map->reg_type = type;
++ map->max_size = CXL_COMPONENT_REG_BLOCK_SIZE;
+
+ return 0;
+}
+
- static int add_root_nvdimm_bridge(struct device *match, void *data)
+ static int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
+ struct cxl_register_map *map)
{
- struct cxl_decoder *cxld;
+ int rc;
+
++ /*
++ * If the Register Locator DVSEC does not contain the
++ * Component Registers, try to extract them from the RCRB if
++ * it is an RCH.
++ */
+ rc = cxl_find_regblock(pdev, type, map);
+- if (rc)
++ if (rc && cxl_rcrb_get_comp_regs(pdev, type, map))
+ return rc;
+
+ return cxl_setup_regs(map);
--
2.34.1