* @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
        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 */
 
        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;
 
        /*
                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);
 
 {
        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;
                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;
 
        }
 }
 
+/*
+ * 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;
        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);