1 From: Alex Williamson <alex.williamson@redhat.com>
2 Subject: [PATCH 2/2] PCI: Quirk PCH root port ACS for Sunrise Point
4 As noted in the comments, these root ports attempted to implement ACS
5 but used dwords for the capability and control registers, putting the
6 control register at the wrong offset. We use quirks to enable and
7 test ACS for these devices, which match the standard functions modulo
8 the broken control register offset.
10 Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
12 drivers/pci/quirks.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++
13 1 file changed, 78 insertions(+)
15 diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
16 index 701fad6..d6606e4 100644
17 --- a/drivers/pci/quirks.c
18 +++ b/drivers/pci/quirks.c
19 @@ -3992,6 +3992,55 @@ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
20 return acs_flags & ~flags ? 0 : 1;
24 + * Sunrise Point PCH root ports implement ACS, but unfortunately as shown in
25 + * the datasheet (Intel 100 Series Chipset Family PCH Datasheet, Vol. 2,
26 + * 12.1.46, 12.1.47)[1] this chipset uses dwords for the ACS capability and
27 + * control registers whereas the PCIe spec packs them into words (Rev 3.0,
28 + * 7.16 ACS Extended Capability). The bit definitions are correct, but the
29 + * control register is at offset 8 instead of 6 and we should probably use
30 + * dword accesses to them. This applies to the following PCI Device IDs, as
31 + * found in volume 1 of the datasheet[2]:
33 + * 0xa110-0xa11f Sunrise Point-H PCI Express Root Port #{0-16}
34 + * 0xa167-0xa16a Sunrise Point-H PCI Express Root Port #{17-20}
36 + * NB. This doesn't fix what lspci shows.
38 + * [1] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-2.html
39 + * [2] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-1.html
41 +static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev)
43 + return pci_is_pcie(dev) &&
44 + pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT &&
45 + ((dev->device & ~0xf) == 0xa110 ||
46 + (dev->device >= 0xa167 && dev->device <= 0xa16a));
49 +#define INTEL_SPT_ACS_CTRL (PCI_ACS_CAP + 4)
51 +static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u16 acs_flags)
56 + if (!pci_quirk_intel_spt_pch_acs_match(dev))
59 + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
63 + /* see pci_acs_flags_enabled() */
64 + pci_read_config_dword(dev, pos + PCI_ACS_CAP, &cap);
65 + acs_flags &= (cap | PCI_ACS_EC);
67 + pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl);
69 + return acs_flags & ~ctrl ? 0 : 1;
72 static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
75 @@ -4024,6 +4073,7 @@ static const struct pci_dev_acs_enabled {
76 { PCI_VENDOR_ID_INTEL, 0x15b8, pci_quirk_mf_endpoint_acs },
77 /* Intel PCH root ports */
78 { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
79 + { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_spt_pch_acs },
80 { 0x19a2, 0x710, pci_quirk_mf_endpoint_acs }, /* Emulex BE3-R */
81 { 0x10df, 0x720, pci_quirk_mf_endpoint_acs }, /* Emulex Skyhawk-R */
83 @@ -4159,12 +4209,40 @@ static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev)
87 +static int pci_quirk_enable_intel_spt_pch_acs(struct pci_dev *dev)
92 + if (!pci_quirk_intel_spt_pch_acs_match(dev))
95 + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
99 + pci_read_config_dword(dev, pos + PCI_ACS_CAP, &cap);
100 + pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl);
102 + ctrl |= (cap & PCI_ACS_SV);
103 + ctrl |= (cap & PCI_ACS_RR);
104 + ctrl |= (cap & PCI_ACS_CR);
105 + ctrl |= (cap & PCI_ACS_UF);
107 + pci_write_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, ctrl);
109 + dev_info(&dev->dev, "Intel SPT PCH root port ACS workaround enabled\n");
114 static const struct pci_dev_enable_acs {
117 int (*enable_acs)(struct pci_dev *dev);
118 } pci_dev_enable_acs[] = {
119 { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_pch_acs },
120 + { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_spt_pch_acs },