[pve-devel] [PATCH kernel 2/2] fix #981: backport Skylake ACS quirk patches from 4.7

Fabian Grünbichler f.gruenbichler at proxmox.com
Mon May 9 08:49:48 CEST 2016


---
 ...ndard-ACS-vs-device-specific-ACS-enabling.patch | 110 ++++++++++++++++++
 ...Quirk-PCH-root-port-ACS-for-Sunrise-Point.patch | 123 +++++++++++++++++++++
 Makefile                                           |   2 +
 3 files changed, 235 insertions(+)
 create mode 100644 981-1-PCI-Reverse-standard-ACS-vs-device-specific-ACS-enabling.patch
 create mode 100644 981-2-PCI-Quirk-PCH-root-port-ACS-for-Sunrise-Point.patch

diff --git a/981-1-PCI-Reverse-standard-ACS-vs-device-specific-ACS-enabling.patch b/981-1-PCI-Reverse-standard-ACS-vs-device-specific-ACS-enabling.patch
new file mode 100644
index 0000000..8543bc3
--- /dev/null
+++ b/981-1-PCI-Reverse-standard-ACS-vs-device-specific-ACS-enabling.patch
@@ -0,0 +1,110 @@
+From: Alex Williamson <alex.williamson at redhat.com>
+Subject: [PATCH 1/2] PCI: Reverse standard ACS vs device specific ACS enabling
+
+The original thought was that if a device implemented ACS, then surely
+we want to use that... well, it turns out that devices can make an ACS
+capability so broken that we still need to fall back to quirks.
+Reverse the order of ACS enabling to give quirks first shot at it.
+
+Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
+---
+ drivers/pci/pci.c    |   10 ++++------
+ drivers/pci/quirks.c |    6 ++++--
+ include/linux/pci.h  |    7 +++++--
+ 3 files changed, 13 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index 25e0327..c98c4e2 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -2548,7 +2548,7 @@ void pci_request_acs(void)
+  * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
+  * @dev: the PCI device
+  */
+-static int pci_std_enable_acs(struct pci_dev *dev)
++static void pci_std_enable_acs(struct pci_dev *dev)
+ {
+ 	int pos;
+ 	u16 cap;
+@@ -2556,7 +2556,7 @@ static int pci_std_enable_acs(struct pci_dev *dev)
+ 
+ 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+ 	if (!pos)
+-		return -ENODEV;
++		return;
+ 
+ 	pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
+ 	pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
+@@ -2574,8 +2574,6 @@ static int pci_std_enable_acs(struct pci_dev *dev)
+ 	ctrl |= (cap & PCI_ACS_UF);
+ 
+ 	pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
+-
+-	return 0;
+ }
+ 
+ /**
+@@ -2585,10 +2585,10 @@ void pci_enable_acs(struct pci_dev *dev)
+ 	if (!pci_acs_enable)
+ 		return;
+ 
+-	if (!pci_std_enable_acs(dev))
++	if (!pci_dev_specific_enable_acs(dev))
+ 		return;
+ 
+-	pci_dev_specific_enable_acs(dev);
++	pci_std_enable_acs(dev);
+ }
+ 
+ static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 8e67802..701fad6 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -4224,7 +4224,7 @@ static const struct pci_dev_enable_acs {
+ 	{ 0 }
+ };
+ 
+-void pci_dev_specific_enable_acs(struct pci_dev *dev)
++int pci_dev_specific_enable_acs(struct pci_dev *dev)
+ {
+ 	const struct pci_dev_enable_acs *i;
+ 	int ret;
+@@ -4236,9 +4236,11 @@ void pci_dev_specific_enable_acs(struct pci_dev *dev)
+ 		     i->device == (u16)PCI_ANY_ID)) {
+ 			ret = i->enable_acs(dev);
+ 			if (ret >= 0)
+-				return;
++				return ret;
+ 		}
+ 	}
++
++	return -ENOTTY;
+ }
+ 
+ /*
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index 004b813..aaec79a 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -1657,7 +1657,7 @@ enum pci_fixup_pass {
+ #ifdef CONFIG_PCI_QUIRKS
+ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
+ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
+-void pci_dev_specific_enable_acs(struct pci_dev *dev);
++int pci_dev_specific_enable_acs(struct pci_dev *dev);
+ #else
+ static inline void pci_fixup_device(enum pci_fixup_pass pass,
+ 				    struct pci_dev *dev) { }
+@@ -1666,7 +1666,10 @@ static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev,
+ {
+ 	return -ENOTTY;
+ }
+-static inline void pci_dev_specific_enable_acs(struct pci_dev *dev) { }
++static inline int pci_dev_specific_enable_acs(struct pci_dev *dev)
++{
++	return -ENOTTY;
++}
+ #endif
+ 
+ void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
diff --git a/981-2-PCI-Quirk-PCH-root-port-ACS-for-Sunrise-Point.patch b/981-2-PCI-Quirk-PCH-root-port-ACS-for-Sunrise-Point.patch
new file mode 100644
index 0000000..9c3dd24
--- /dev/null
+++ b/981-2-PCI-Quirk-PCH-root-port-ACS-for-Sunrise-Point.patch
@@ -0,0 +1,123 @@
+From: Alex Williamson <alex.williamson at redhat.com>
+Subject: [PATCH 2/2] PCI: Quirk PCH root port ACS for Sunrise Point
+
+As noted in the comments, these root ports attempted to implement ACS
+but used dwords for the capability and control registers, putting the
+control register at the wrong offset.  We use quirks to enable and
+test ACS for these devices, which match the standard functions modulo
+the broken control register offset.
+
+Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
+---
+ drivers/pci/quirks.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 78 insertions(+)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 701fad6..d6606e4 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -3992,6 +3992,55 @@ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
+ 	return acs_flags & ~flags ? 0 : 1;
+ }
+ 
++/*
++ * Sunrise Point PCH root ports implement ACS, but unfortunately as shown in
++ * the datasheet (Intel 100 Series Chipset Family PCH Datasheet, Vol. 2,
++ * 12.1.46, 12.1.47)[1] this chipset uses dwords for the ACS capability and
++ * control registers whereas the PCIe spec packs them into words (Rev 3.0,
++ * 7.16 ACS Extended Capability).  The bit definitions are correct, but the
++ * control register is at offset 8 instead of 6 and we should probably use
++ * dword accesses to them.  This applies to the following PCI Device IDs, as
++ * found in volume 1 of the datasheet[2]:
++ *
++ * 0xa110-0xa11f Sunrise Point-H PCI Express Root Port #{0-16}
++ * 0xa167-0xa16a Sunrise Point-H PCI Express Root Port #{17-20}
++ *
++ * NB. This doesn't fix what lspci shows.
++ *
++ * [1] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-2.html
++ * [2] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-1.html
++ */
++static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev)
++{
++	return pci_is_pcie(dev) &&
++		pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT &&
++		((dev->device & ~0xf) == 0xa110 ||
++		 (dev->device >= 0xa167 && dev->device <= 0xa16a));
++}
++
++#define INTEL_SPT_ACS_CTRL (PCI_ACS_CAP + 4)
++
++static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u16 acs_flags)
++{
++	int pos;
++	u32 cap, ctrl;
++
++	if (!pci_quirk_intel_spt_pch_acs_match(dev))
++		return -ENOTTY;
++
++	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
++	if (!pos)
++		return -ENOTTY;
++
++	/* see pci_acs_flags_enabled() */
++	pci_read_config_dword(dev, pos + PCI_ACS_CAP, &cap);
++	acs_flags &= (cap | PCI_ACS_EC);
++
++	pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl);
++
++	return acs_flags & ~ctrl ? 0 : 1;
++}
++
+ static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
+ {
+ 	/*
+@@ -4024,6 +4073,7 @@ static const struct pci_dev_acs_enabled {
+ 	{ PCI_VENDOR_ID_INTEL, 0x15b8, pci_quirk_mf_endpoint_acs },
+ 	/* Intel PCH root ports */
+ 	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
++	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_spt_pch_acs },
+ 	{ 0x19a2, 0x710, pci_quirk_mf_endpoint_acs }, /* Emulex BE3-R */
+ 	{ 0x10df, 0x720, pci_quirk_mf_endpoint_acs }, /* Emulex Skyhawk-R */
+ 	/* Cavium ThunderX */
+@@ -4159,12 +4209,40 @@ static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev)
+ 	return 0;
+ }
+ 
++static int pci_quirk_enable_intel_spt_pch_acs(struct pci_dev *dev)
++{
++	int pos;
++	u32 cap, ctrl;
++
++	if (!pci_quirk_intel_spt_pch_acs_match(dev))
++		return -ENOTTY;
++
++	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
++	if (!pos)
++		return -ENOTTY;
++
++	pci_read_config_dword(dev, pos + PCI_ACS_CAP, &cap);
++	pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl);
++
++	ctrl |= (cap & PCI_ACS_SV);
++	ctrl |= (cap & PCI_ACS_RR);
++	ctrl |= (cap & PCI_ACS_CR);
++	ctrl |= (cap & PCI_ACS_UF);
++
++	pci_write_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, ctrl);
++
++	dev_info(&dev->dev, "Intel SPT PCH root port ACS workaround enabled\n");
++
++	return 0;
++}
++
+ static const struct pci_dev_enable_acs {
+ 	u16 vendor;
+ 	u16 device;
+ 	int (*enable_acs)(struct pci_dev *dev);
+ } pci_dev_enable_acs[] = {
+ 	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_pch_acs },
++	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_spt_pch_acs },
+ 	{ 0 }
+ };
+ 
diff --git a/Makefile b/Makefile
index 74205c0..e1c20c1 100644
--- a/Makefile
+++ b/Makefile
@@ -237,6 +237,8 @@ ${KERNEL_SRC}/README ${KERNEL_CFG_ORG}: ${KERNELSRCTAR}
 	cd ${KERNEL_SRC}; patch -p1 <../override_for_missing_acs_capabilities.patch
 	#cd ${KERNEL_SRC}; patch -p1 <../vhost-net-extend-device-allocation-to-vmalloc.patch
 	cd ${KERNEL_SRC}; patch -p1 <../bug-950-tcp-fix-tcp_mark_head_lost-to-check-skb-len-before-f.patch
+	cd ${KERNEL_SRC}; patch -p1 < ../981-1-PCI-Reverse-standard-ACS-vs-device-specific-ACS-enabling.patch
+	cd ${KERNEL_SRC}; patch -p1 < ../981-2-PCI-Quirk-PCH-root-port-ACS-for-Sunrise-Point.patch
 	sed -i ${KERNEL_SRC}/Makefile -e 's/^EXTRAVERSION.*$$/EXTRAVERSION=${EXTRAVERSION}/'
 	touch $@
 
-- 
2.1.4





More information about the pve-devel mailing list