Re: [PATCH v4 08/15] cxl/pci: Map CXL PCIe Root Port and Downstream Switch Port RAS registers

Bowman, Terry
2024-12-13T15:10:44Z

On 12/12/2024 4:36 AM, Alejandro Lucero Palau wrote:
> On 12/11/24 23:39, 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 CXL 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@amd.com>
>
> Reviewed-by: Alejandro Lucero <alucerop@amd.com>
>
>
> Just a nit but, regs mapping could fail, what is properly reported, and
> the __cxl_handle_ras function checks for the regs iomem being there
> before using them. But if the mapping failed, any report there is
> silently dropped. If the AER is happening, maybe to add a WARN_ONCE there?
>

Good point. I'll add the WARN_ONCE().

- Terry
>> ---
>> drivers/cxl/core/pci.c | 37 +++++++++++++++----------------------
>> drivers/cxl/cxl.h | 6 ++----
>> drivers/cxl/mem.c | 31 +++++++++++++++++++++++++++++--
>> 3 files changed, 46 insertions(+), 28 deletions(-)
>>
>> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
>> index 5b46bc46aaa9..8540d1fd2e25 100644
>> --- a/drivers/cxl/core/pci.c
>> +++ b/drivers/cxl/core/pci.c
>> @@ -749,18 +749,6 @@ static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
>> }
>> }
>>
>> -static void cxl_dport_map_ras(struct cxl_dport *dport)
>> -{
>> - struct cxl_register_map *map = &dport->reg_map;
>> - struct device *dev = dport->dport_dev;
>> -
>> - if (!map->component_map.ras.valid)
>> - dev_dbg(dev, "RAS registers not found\n");
>> - else if (cxl_map_component_regs(map, &dport->regs.component,
>> - BIT(CXL_CM_CAP_CAP_ID_RAS)))
>> - dev_dbg(dev, "Failed to map RAS capability.\n");
>> -}
>> -
>> static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
>> {
>> void __iomem *aer_base = dport->regs.dport_aer;
>> @@ -788,22 +776,27 @@ static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
>> /**
>> * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
>> * @dport: the cxl_dport that needs to be initialized
>> - * @host: host device for devm operations
>> */
>> -void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
>> +void cxl_dport_init_ras_reporting(struct cxl_dport *dport)
>> {
>> - dport->reg_map.host = host;
>> - cxl_dport_map_ras(dport);
>> -
>> - if (dport->rch) {
>> - struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev);
>> -
>> - if (!host_bridge->native_aer)
>> - return;
>> + struct device *dport_dev = dport->dport_dev;
>> + struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport_dev);
>>
>> + dport->reg_map.host = dport_dev;
>> + if (dport->rch && host_bridge->native_aer) {
>> cxl_dport_map_rch_aer(dport);
>> cxl_disable_rch_root_ints(dport);
>> }
>> +
>> + /* dport may have more than 1 downstream EP. Check if already mapped. */
>> + if (dport->regs.ras)
>> + return;
>> +
>> + if (cxl_map_component_regs(&dport->reg_map, &dport->regs.component,
>> + BIT(CXL_CM_CAP_CAP_ID_RAS))) {
>> + dev_err(dport_dev, "Failed to map RAS capability.\n");
>> + return;
>> + }
>> }
>> EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, CXL);
>>
>> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
>> index 5406e3ab3d4a..51acca3415b4 100644
>> --- a/drivers/cxl/cxl.h
>> +++ b/drivers/cxl/cxl.h
>> @@ -763,11 +763,9 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
>> resource_size_t rcrb);
>>
>> #ifdef CONFIG_PCIEAER_CXL
>> -void cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport);
>> -void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>> +void cxl_dport_init_ras_reporting(struct cxl_dport *dport);
>> #else
>> -static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>> - struct device *host) { }
>> +static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport) { }
>> #endif
>>
>> struct cxl_decoder *to_cxl_decoder(struct device *dev);
>> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
>> index a9fd5cd5a0d2..0ae89c9da71e 100644
>> --- a/drivers/cxl/mem.c
>> +++ b/drivers/cxl/mem.c
>> @@ -45,6 +45,31 @@ static int cxl_mem_dpa_show(struct seq_file *file, void *data)
>> return 0;
>> }
>>
>> +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);
>> + }
>> +}
>> +
>> static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
>> struct cxl_dport *parent_dport)
>> {
>> @@ -52,6 +77,9 @@ static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
>> struct cxl_port *endpoint, *iter, *down;
>> int rc;
>>
>> + if (parent_dport->rch)
>> + cxl_dport_init_ras_reporting(parent_dport);
>> +
>> /*
>> * Now that the path to the root is established record all the
>> * intervening ports in the chain.
>> @@ -62,6 +90,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 +195,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",