diff options
Diffstat (limited to 'drivers/misc/cxl/pci.c')
| -rw-r--r-- | drivers/misc/cxl/pci.c | 30 | 
1 files changed, 28 insertions, 2 deletions
| diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 02c85160bfe9..85761d7eb333 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -1035,6 +1035,32 @@ static int cxl_read_vsec(struct cxl *adapter, struct pci_dev *dev)  	return 0;  } +/* + * Workaround a PCIe Host Bridge defect on some cards, that can cause + * malformed Transaction Layer Packet (TLP) errors to be erroneously + * reported. Mask this error in the Uncorrectable Error Mask Register. + * + * The upper nibble of the PSL revision is used to distinguish between + * different cards. The affected ones have it set to 0. + */ +static void cxl_fixup_malformed_tlp(struct cxl *adapter, struct pci_dev *dev) +{ +	int aer; +	u32 data; + +	if (adapter->psl_rev & 0xf000) +		return; +	if (!(aer = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))) +		return; +	pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, &data); +	if (data & PCI_ERR_UNC_MALF_TLP) +		if (data & PCI_ERR_UNC_INTN) +			return; +	data |= PCI_ERR_UNC_MALF_TLP; +	data |= PCI_ERR_UNC_INTN; +	pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, data); +} +  static int cxl_vsec_looks_ok(struct cxl *adapter, struct pci_dev *dev)  {  	if (adapter->vsec_status & CXL_STATUS_SECOND_PORT) @@ -1134,6 +1160,8 @@ static int cxl_configure_adapter(struct cxl *adapter, struct pci_dev *dev)  	if ((rc = cxl_vsec_looks_ok(adapter, dev)))  	        return rc; +	cxl_fixup_malformed_tlp(adapter, dev); +  	if ((rc = setup_cxl_bars(dev)))  		return rc; @@ -1249,8 +1277,6 @@ static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id)  	int slice;  	int rc; -	pci_dev_get(dev); -  	if (cxl_verbose)  		dump_cxl_config_space(dev); |