Commit e550b43a authored by Robert Richter's avatar Robert Richter Committed by Wenkuan Wang
Browse files

PCI/AER: Unmask RCEC internal errors to enable RCH downstream port error handling

mainline inclusion
from mainline-v6.7-rc1
commit b7e9392d5d46a67fb5b66dbb2c257dd0d48eec70
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8ZZ5K


CVE: NA

--------------------------------

AER corrected and uncorrectable internal errors (CIE/UIE) are masked
in their corresponding mask registers per default once in power-up
state. [1][2] Enable internal errors for RCECs to receive CXL
downstream port errors of Restricted CXL Hosts (RCHs).

[1] CXL 3.0 Spec, 12.2.1.1 - RCH Downstream Port Detected Errors
[2] PCIe Base Spec r6.0, 7.8.4.3 Uncorrectable Error Mask Register,
    7.8.4.6 Correctable Error Mask Register

Co-developed-by: default avatarTerry Bowman <terry.bowman@amd.com>
Signed-off-by: default avatarTerry Bowman <terry.bowman@amd.com>
Signed-off-by: default avatarRobert Richter <rrichter@amd.com>
Acked-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: default avatarDave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/20231018171713.1883517-19-rrichter@amd.com


Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Signed-off-by: default avatarWenkuan Wang <Wenkuan.Wang@amd.com>
parent be89671b
Loading
Loading
Loading
Loading
+57 −0
Original line number Diff line number Diff line
@@ -937,6 +937,30 @@ static bool find_source_device(struct pci_dev *parent,

#ifdef CONFIG_PCIEAER_CXL

/**
 * pci_aer_unmask_internal_errors - unmask internal errors
 * @dev: pointer to the pcie_dev data structure
 *
 * Unmasks internal errors in the Uncorrectable and Correctable Error
 * Mask registers.
 *
 * Note: AER must be enabled and supported by the device which must be
 * checked in advance, e.g. with pcie_aer_is_native().
 */
static void pci_aer_unmask_internal_errors(struct pci_dev *dev)
{
	int aer = dev->aer_cap;
	u32 mask;

	pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, &mask);
	mask &= ~PCI_ERR_UNC_INTN;
	pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, mask);

	pci_read_config_dword(dev, aer + PCI_ERR_COR_MASK, &mask);
	mask &= ~PCI_ERR_COR_INTERNAL;
	pci_write_config_dword(dev, aer + PCI_ERR_COR_MASK, mask);
}

static bool is_cxl_mem_dev(struct pci_dev *dev)
{
	/*
@@ -1013,7 +1037,39 @@ static void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_info *info)
		pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
}

static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
{
	bool *handles_cxl = data;

	if (!*handles_cxl)
		*handles_cxl = is_cxl_mem_dev(dev) && cxl_error_is_native(dev);

	/* Non-zero terminates iteration */
	return *handles_cxl;
}

static bool handles_cxl_errors(struct pci_dev *rcec)
{
	bool handles_cxl = false;

	if (pci_pcie_type(rcec) == PCI_EXP_TYPE_RC_EC &&
	    pcie_aer_is_native(rcec))
		pcie_walk_rcec(rcec, handles_cxl_error_iter, &handles_cxl);

	return handles_cxl;
}

static void cxl_rch_enable_rcec(struct pci_dev *rcec)
{
	if (!handles_cxl_errors(rcec))
		return;

	pci_aer_unmask_internal_errors(rcec);
	pci_info(rcec, "CXL: Internal errors unmasked");
}

#else
static inline void cxl_rch_enable_rcec(struct pci_dev *dev) { }
static inline void cxl_rch_handle_error(struct pci_dev *dev,
					struct aer_err_info *info) { }
#endif
@@ -1422,6 +1478,7 @@ static int aer_probe(struct pcie_device *dev)
		return status;
	}

	cxl_rch_enable_rcec(port);
	aer_enable_rootport(rpc);
	pci_info(port, "enabled with IRQ %d\n", dev->irq);
	return 0;