aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Puthukattukaran <james.puthukattukaran@oracle.com>2018-07-09 11:31:25 -0400
committerBjorn Helgaas <helgaas@kernel.org>2018-07-12 17:54:35 -0400
commitaa667c6408d20a84c7637420bc3b7aa0abab59a2 (patch)
treed009885df95a599732f81416174e515ac9a7dfb4
parentce397d215ccd07b8ae3f71db689aedb85d56ab40 (diff)
PCI: Workaround IDT switch ACS Source Validation erratum
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. Workaround: Issue a CfgWr1 to the downstream device before issuing the first CfgRd1 to the device. This allows the downstream device to capture its bus number; ACS Source Validation no longer stops completions from being forwarded by the downstream port. It has been observed that Microsoft Windows implements this workaround already; however, some versions of Linux and other operating systems may not. When doing the first config read to probe for a device, if the device is behind an IDT switch with this erratum: 1. Disable ACS Source Validation if enabled 2. Wait for device to become ready to accept config accesses (by using the Config Request Retry Status mechanism) 3. Do a config write to the endpoint 4. Enable ACS Source Validation (if it was enabled to begin with) The workaround suggested by IDT is basically only step 3, but we don't know when the device is ready to accept config requests. That means we need to do config reads until we receive a non-Config Request Retry Status, which means we need to disable ACS SV temporarily. Signed-off-by: James Puthukattukaran <james.puthukattukaran@oracle.com> [bhelgaas: changelog, clean up whitespace, fold in unused variable fix from Anders Roxell <anders.roxell@linaro.org>] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
-rw-r--r--drivers/pci/pci.h4
-rw-r--r--drivers/pci/probe.c22
-rw-r--r--drivers/pci/quirks.c55
3 files changed, 79 insertions, 2 deletions
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index c358e7a07f3f..70808c168fb9 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -225,6 +225,10 @@ enum pci_bar_type {
225int pci_configure_extended_tags(struct pci_dev *dev, void *ign); 225int pci_configure_extended_tags(struct pci_dev *dev, void *ign);
226bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl, 226bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
227 int crs_timeout); 227 int crs_timeout);
228bool pci_bus_generic_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
229 int crs_timeout);
230int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *pl, int crs_timeout);
231
228int pci_setup_device(struct pci_dev *dev); 232int pci_setup_device(struct pci_dev *dev);
229int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, 233int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
230 struct resource *res, unsigned int reg); 234 struct resource *res, unsigned int reg);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ac876e32de4b..7c0c8ab94bcf 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2156,8 +2156,8 @@ static bool pci_bus_wait_crs(struct pci_bus *bus, int devfn, u32 *l,
2156 return true; 2156 return true;
2157} 2157}
2158 2158
2159bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l, 2159bool pci_bus_generic_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
2160 int timeout) 2160 int timeout)
2161{ 2161{
2162 if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l)) 2162 if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
2163 return false; 2163 return false;
@@ -2172,6 +2172,24 @@ bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
2172 2172
2173 return true; 2173 return true;
2174} 2174}
2175
2176bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
2177 int timeout)
2178{
2179#ifdef CONFIG_PCI_QUIRKS
2180 struct pci_dev *bridge = bus->self;
2181
2182 /*
2183 * Certain IDT switches have an issue where they improperly trigger
2184 * ACS Source Validation errors on completions for config reads.
2185 */
2186 if (bridge && bridge->vendor == PCI_VENDOR_ID_IDT &&
2187 bridge->device == 0x80b5)
2188 return pci_idt_bus_quirk(bus, devfn, l, timeout);
2189#endif
2190
2191 return pci_bus_generic_read_dev_vendor_id(bus, devfn, l, timeout);
2192}
2175EXPORT_SYMBOL(pci_bus_read_dev_vendor_id); 2193EXPORT_SYMBOL(pci_bus_read_dev_vendor_id);
2176 2194
2177/* 2195/*
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index f439de848658..cab2d5f922a9 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4753,3 +4753,58 @@ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMD, PCI_ANY_ID,
4753 PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda); 4753 PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
4754DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, 4754DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
4755 PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda); 4755 PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
4756
4757/*
4758 * Some IDT switches incorrectly flag an ACS Source Validation error on
4759 * completions for config read requests even though PCIe r4.0, sec
4760 * 6.12.1.1, says that completions are never affected by ACS Source
4761 * Validation. Here's the text of IDT 89H32H8G3-YC, erratum #36:
4762 *
4763 * Item #36 - Downstream port applies ACS Source Validation to Completions
4764 * Section 6.12.1.1 of the PCI Express Base Specification 3.1 states that
4765 * completions are never affected by ACS Source Validation. However,
4766 * completions received by a downstream port of the PCIe switch from a
4767 * device that has not yet captured a PCIe bus number are incorrectly
4768 * dropped by ACS Source Validation by the switch downstream port.
4769 *
4770 * The workaround suggested by IDT is to issue a config write to the
4771 * downstream device before issuing the first config read. This allows the
4772 * downstream device to capture its bus and device numbers (see PCIe r4.0,
4773 * sec 2.2.9), thus avoiding the ACS error on the completion.
4774 *
4775 * However, we don't know when the device is ready to accept the config
4776 * write, so we do config reads until we receive a non-Config Request Retry
4777 * Status, then do the config write.
4778 *
4779 * To avoid hitting the erratum when doing the config reads, we disable ACS
4780 * SV around this process.
4781 */
4782int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *l, int timeout)
4783{
4784 int pos;
4785 u16 ctrl = 0;
4786 bool found;
4787 struct pci_dev *bridge = bus->self;
4788
4789 pos = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ACS);
4790
4791 /* Disable ACS SV before initial config reads */
4792 if (pos) {
4793 pci_read_config_word(bridge, pos + PCI_ACS_CTRL, &ctrl);
4794 if (ctrl & PCI_ACS_SV)
4795 pci_write_config_word(bridge, pos + PCI_ACS_CTRL,
4796 ctrl & ~PCI_ACS_SV);
4797 }
4798
4799 found = pci_bus_generic_read_dev_vendor_id(bus, devfn, l, timeout);
4800
4801 /* Write Vendor ID (read-only) so the endpoint latches its bus/dev */
4802 if (found)
4803 pci_bus_write_config_word(bus, devfn, PCI_VENDOR_ID, 0);
4804
4805 /* Re-enable ACS_SV if it was previously enabled */
4806 if (ctrl & PCI_ACS_SV)
4807 pci_write_config_word(bridge, pos + PCI_ACS_CTRL, ctrl);
4808
4809 return found;
4810}