|
@@ -4753,3 +4753,58 @@ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMD, PCI_ANY_ID,
|
|
|
PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
|
|
|
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
|
|
|
PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Some IDT switches incorrectly flag an ACS Source Validation error on
|
|
|
+ * completions for config read requests even though PCIe r4.0, sec
|
|
|
+ * 6.12.1.1, says that completions are never affected by ACS Source
|
|
|
+ * Validation. Here's the text of IDT 89H32H8G3-YC, erratum #36:
|
|
|
+ *
|
|
|
+ * Item #36 - Downstream port applies ACS Source Validation to Completions
|
|
|
+ * Section 6.12.1.1 of the PCI Express Base Specification 3.1 states that
|
|
|
+ * completions are never affected by ACS Source Validation. However,
|
|
|
+ * completions received by a downstream port of the PCIe switch from a
|
|
|
+ * device that has not yet captured a PCIe bus number are incorrectly
|
|
|
+ * dropped by ACS Source Validation by the switch downstream port.
|
|
|
+ *
|
|
|
+ * The workaround suggested by IDT is to issue a config write to the
|
|
|
+ * downstream device before issuing the first config read. This allows the
|
|
|
+ * downstream device to capture its bus and device numbers (see PCIe r4.0,
|
|
|
+ * sec 2.2.9), thus avoiding the ACS error on the completion.
|
|
|
+ *
|
|
|
+ * However, we don't know when the device is ready to accept the config
|
|
|
+ * write, so we do config reads until we receive a non-Config Request Retry
|
|
|
+ * Status, then do the config write.
|
|
|
+ *
|
|
|
+ * To avoid hitting the erratum when doing the config reads, we disable ACS
|
|
|
+ * SV around this process.
|
|
|
+ */
|
|
|
+int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *l, int timeout)
|
|
|
+{
|
|
|
+ int pos;
|
|
|
+ u16 ctrl = 0;
|
|
|
+ bool found;
|
|
|
+ struct pci_dev *bridge = bus->self;
|
|
|
+
|
|
|
+ pos = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ACS);
|
|
|
+
|
|
|
+ /* Disable ACS SV before initial config reads */
|
|
|
+ if (pos) {
|
|
|
+ pci_read_config_word(bridge, pos + PCI_ACS_CTRL, &ctrl);
|
|
|
+ if (ctrl & PCI_ACS_SV)
|
|
|
+ pci_write_config_word(bridge, pos + PCI_ACS_CTRL,
|
|
|
+ ctrl & ~PCI_ACS_SV);
|
|
|
+ }
|
|
|
+
|
|
|
+ found = pci_bus_generic_read_dev_vendor_id(bus, devfn, l, timeout);
|
|
|
+
|
|
|
+ /* Write Vendor ID (read-only) so the endpoint latches its bus/dev */
|
|
|
+ if (found)
|
|
|
+ pci_bus_write_config_word(bus, devfn, PCI_VENDOR_ID, 0);
|
|
|
+
|
|
|
+ /* Re-enable ACS_SV if it was previously enabled */
|
|
|
+ if (ctrl & PCI_ACS_SV)
|
|
|
+ pci_write_config_word(bridge, pos + PCI_ACS_CTRL, ctrl);
|
|
|
+
|
|
|
+ return found;
|
|
|
+}
|