Skip to content

Commit b26d7fb

Browse files
Mani-Sadhasivambjorn-helgaas
authored andcommitted
PCI: Disable ACS SV for IDT 0x80b5 switch
Some IDT switches incorrectly flag an ACS Source Validation error on completions for config read requests before they have captured the bus number from a previous config write, even though PCIe r7.0, sec 6.12.1.1, says that completions are never affected by ACS Source Validation. The previous workaround, aa667c6 ("PCI: Workaround IDT switch ACS Source Validation erratum"), temporarily disabled ACS SV during enumeration. This was effective but didn't cover the time after switch reset, when it may lose the captured bus number. Avoid the issue by preventing use of ACS SV altogether for these switches by calling pci_disable_broken_acs_cap() from pci_acs_init() and remove the previous workaround in pci_bus_read_dev_vendor_id(). Removal of ACS SV for these switches means they no longer enforce everything in REQ_ACS_FLAGS, so downstream devices are not isolated from each other and the iommu_group may include more devices. Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> [bhelgaas: commit log, retain specific erratum details] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Tested-by: Naresh Kamboju <naresh.kamboju@linaro.org> Link: https://patch.msgid.link/20260102-pci_acs-v3-3-72280b94d288@oss.qualcomm.com
1 parent 8f05a5f commit b26d7fb

4 files changed

Lines changed: 13 additions & 47 deletions

File tree

drivers/pci/pci.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3653,6 +3653,7 @@ void pci_acs_init(struct pci_dev *dev)
36533653
return;
36543654

36553655
pci_read_config_word(dev, pos + PCI_ACS_CAP, &dev->acs_capabilities);
3656+
pci_disable_broken_acs_cap(dev);
36563657
}
36573658

36583659
/**

drivers/pci/pci.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,6 @@ bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
432432
int rrs_timeout);
433433
bool pci_bus_generic_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
434434
int rrs_timeout);
435-
int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *pl, int rrs_timeout);
436435

437436
int pci_setup_device(struct pci_dev *dev);
438437
void __pci_size_stdbars(struct pci_dev *dev, int count,
@@ -944,6 +943,7 @@ void pci_enable_acs(struct pci_dev *dev);
944943
int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
945944
int pci_dev_specific_enable_acs(struct pci_dev *dev);
946945
int pci_dev_specific_disable_acs_redir(struct pci_dev *dev);
946+
void pci_disable_broken_acs_cap(struct pci_dev *pdev);
947947
int pcie_failed_link_retrain(struct pci_dev *dev);
948948
#else
949949
static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev,
@@ -959,6 +959,7 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev)
959959
{
960960
return -ENOTTY;
961961
}
962+
static inline void pci_disable_broken_acs_cap(struct pci_dev *dev) { }
962963
static inline int pcie_failed_link_retrain(struct pci_dev *dev)
963964
{
964965
return -ENOTTY;

drivers/pci/probe.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2547,18 +2547,6 @@ bool pci_bus_generic_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
25472547
bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
25482548
int timeout)
25492549
{
2550-
#ifdef CONFIG_PCI_QUIRKS
2551-
struct pci_dev *bridge = bus->self;
2552-
2553-
/*
2554-
* Certain IDT switches have an issue where they improperly trigger
2555-
* ACS Source Validation errors on completions for config reads.
2556-
*/
2557-
if (bridge && bridge->vendor == PCI_VENDOR_ID_IDT &&
2558-
bridge->device == 0x80b5)
2559-
return pci_idt_bus_quirk(bus, devfn, l, timeout);
2560-
#endif
2561-
25622550
return pci_bus_generic_read_dev_vendor_id(bus, devfn, l, timeout);
25632551
}
25642552
EXPORT_SYMBOL(pci_bus_read_dev_vendor_id);

drivers/pci/quirks.c

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5801,7 +5801,7 @@ DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
58015801

58025802
/*
58035803
* Some IDT switches incorrectly flag an ACS Source Validation error on
5804-
* completions for config read requests even though PCIe r4.0, sec
5804+
* completions for config read requests even though PCIe r7.0, sec
58055805
* 6.12.1.1, says that completions are never affected by ACS Source
58065806
* Validation. Here's the text of IDT 89H32H8G3-YC, erratum #36:
58075807
*
@@ -5814,44 +5814,20 @@ DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
58145814
*
58155815
* The workaround suggested by IDT is to issue a config write to the
58165816
* downstream device before issuing the first config read. This allows the
5817-
* downstream device to capture its bus and device numbers (see PCIe r4.0,
5818-
* sec 2.2.9), thus avoiding the ACS error on the completion.
5817+
* downstream device to capture its bus and device numbers (see PCIe r7.0,
5818+
* sec 2.2.9.1), thus avoiding the ACS error on the completion.
58195819
*
58205820
* However, we don't know when the device is ready to accept the config
5821-
* write, so we do config reads until we receive a non-Config Request Retry
5822-
* Status, then do the config write.
5823-
*
5824-
* To avoid hitting the erratum when doing the config reads, we disable ACS
5825-
* SV around this process.
5821+
* write, and the issue affects resets of the switch as well as enumeration,
5822+
* so disable use of ACS SV for these devices altogether.
58265823
*/
5827-
int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *l, int timeout)
5824+
void pci_disable_broken_acs_cap(struct pci_dev *pdev)
58285825
{
5829-
int pos;
5830-
u16 ctrl = 0;
5831-
bool found;
5832-
struct pci_dev *bridge = bus->self;
5833-
5834-
pos = bridge->acs_cap;
5835-
5836-
/* Disable ACS SV before initial config reads */
5837-
if (pos) {
5838-
pci_read_config_word(bridge, pos + PCI_ACS_CTRL, &ctrl);
5839-
if (ctrl & PCI_ACS_SV)
5840-
pci_write_config_word(bridge, pos + PCI_ACS_CTRL,
5841-
ctrl & ~PCI_ACS_SV);
5826+
if (pdev->vendor == PCI_VENDOR_ID_IDT &&
5827+
pdev->device == 0x80b5) {
5828+
pci_info(pdev, "Disabling broken ACS SV; downstream device isolation reduced\n");
5829+
pdev->acs_capabilities &= ~PCI_ACS_SV;
58425830
}
5843-
5844-
found = pci_bus_generic_read_dev_vendor_id(bus, devfn, l, timeout);
5845-
5846-
/* Write Vendor ID (read-only) so the endpoint latches its bus/dev */
5847-
if (found)
5848-
pci_bus_write_config_word(bus, devfn, PCI_VENDOR_ID, 0);
5849-
5850-
/* Re-enable ACS_SV if it was previously enabled */
5851-
if (ctrl & PCI_ACS_SV)
5852-
pci_write_config_word(bridge, pos + PCI_ACS_CTRL, ctrl);
5853-
5854-
return found;
58555831
}
58565832

58575833
/*

0 commit comments

Comments
 (0)