On 2024/11/14 5:54, Terry Bowman wrote:
The CXL mem driver (cxl_mem) currently maps and caches a pointer to RAS
registers for the endpoint's root port. The same needs to be done for
each of the CXL downstream switch ports and CXL root ports found between
the endpoint and CXL host bridge.
Introduce cxl_init_ep_ports_aer() to be called for each port in the
sub-topology between the endpoint and the CXL host bridge. This function
will determine if there are CXL downstream switch ports or CXL root ports
associated with this port. The same check will be added in the future for
upstream switch ports.
Move the RAS register map logic from cxl_dport_map_ras() into
cxl_dport_init_ras_reporting(). This eliminates the need for the helper
function, cxl_dport_map_ras().
cxl_init_ep_ports_aer() calls cxl_dport_init_ras_reporting() to map
the RAS registers for CXL downstream switch ports and CXL root ports.
cxl_dport_init_ras_reporting() must check for previously mapped registers
before mapping. This is necessary because endpoints under a CXL switch
may share CXL downstream switch ports or CXL root ports. Ensure the port
registers are only mapped once.
Signed-off-by: Terry Bowman <terry.bowman@xxxxxxx>
[snip]
+static bool dev_is_cxl_pci(struct device *dev, u32 pcie_type)
+{
+ struct pci_dev *pdev;
+
+ if (!dev || !dev_is_pci(dev))
+ return false;
+
+ pdev = to_pci_dev(dev);
+
+ return (pci_pcie_type(pdev) == pcie_type);
+}
+
+static void cxl_init_ep_ports_aer(struct cxl_ep *ep)
+{
+ struct cxl_dport *dport = ep->dport;
+
+ if (dport) {
+ struct device *dport_dev = dport->dport_dev;
+
+ if (dev_is_cxl_pci(dport_dev, PCI_EXP_TYPE_DOWNSTREAM) ||
+ dev_is_cxl_pci(dport_dev, PCI_EXP_TYPE_ROOT_PORT))
+ cxl_dport_init_ras_reporting(dport);
I think cxl_dport_init_ras_reporting() is needed for both VH case and
RCH case. My understanding is that dport_dev could not be a DSP nor a RP
in RCH case.
Ming
+ }
+}
+
static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
struct cxl_dport *parent_dport)
{
@@ -62,6 +87,7 @@ static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
ep = cxl_ep_load(iter, cxlmd);
ep->next = down;
+ cxl_init_ep_ports_aer(ep);
}
/* Note: endpoint port component registers are derived from @cxlds */
@@ -166,8 +192,6 @@ static int cxl_mem_probe(struct device *dev)
else
endpoint_parent = &parent_port->dev;
- cxl_dport_init_ras_reporting(dport, dev);
-
scoped_guard(device, endpoint_parent) {
if (!endpoint_parent->driver) {
dev_err(dev, "CXL port topology %s not enabled\n",