linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] PCI: Skylake PCH ACS quirks
@ 2016-03-31 22:34 Alex Williamson
  2016-03-31 22:34 ` [PATCH 1/2] PCI: Reverse standard ACS vs device specific ACS enabling Alex Williamson
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Alex Williamson @ 2016-03-31 22:34 UTC (permalink / raw)
  To: linux-pci; +Cc: bhelgaas, linux-kernel

Intel Skylake systems attempted to implement ACS on the PCH root
ports, but it came out a wee bit off.  As noted in the second patch
and the datasheets from Intel, dwords were used for the ACS
capability and control words, so we see the capabilities correctly
but the control register is an extra 2 bytes offset.  With this
quirk we can fix the kernel, unfortunately lspci will still show
the wrong ACS control bits though.  Thanks,

Alex

---

Alex Williamson (2):
      PCI: Reverse standard ACS vs device specific ACS enabling
      PCI: Quirk PCH root port ACS for Sunrise Point


 drivers/pci/pci.c    |   10 ++----
 drivers/pci/quirks.c |   84 +++++++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/pci.h  |    7 +++-
 3 files changed, 91 insertions(+), 10 deletions(-)

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] PCI: Reverse standard ACS vs device specific ACS enabling
  2016-03-31 22:34 [PATCH 0/2] PCI: Skylake PCH ACS quirks Alex Williamson
@ 2016-03-31 22:34 ` Alex Williamson
  2016-03-31 22:34 ` [PATCH 2/2] PCI: Quirk PCH root port ACS for Sunrise Point Alex Williamson
  2016-04-19 23:53 ` [PATCH 0/2] PCI: Skylake PCH ACS quirks Bjorn Helgaas
  2 siblings, 0 replies; 4+ messages in thread
From: Alex Williamson @ 2016-03-31 22:34 UTC (permalink / raw)
  To: linux-pci; +Cc: bhelgaas, linux-kernel

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@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
@@ -2547,7 +2547,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;
@@ -2555,7 +2555,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);
@@ -2573,8 +2573,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;
 }
 
 /**
@@ -2586,10 +2584,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
@@ -4168,7 +4168,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;
@@ -4180,9 +4180,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
@@ -1663,7 +1663,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) { }
@@ -1672,7 +1672,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);

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] PCI: Quirk PCH root port ACS for Sunrise Point
  2016-03-31 22:34 [PATCH 0/2] PCI: Skylake PCH ACS quirks Alex Williamson
  2016-03-31 22:34 ` [PATCH 1/2] PCI: Reverse standard ACS vs device specific ACS enabling Alex Williamson
@ 2016-03-31 22:34 ` Alex Williamson
  2016-04-19 23:53 ` [PATCH 0/2] PCI: Skylake PCH ACS quirks Bjorn Helgaas
  2 siblings, 0 replies; 4+ messages in thread
From: Alex Williamson @ 2016-03-31 22:34 UTC (permalink / raw)
  To: linux-pci; +Cc: bhelgaas, linux-kernel

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@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
@@ -3936,6 +3936,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 }
 };
 

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/2] PCI: Skylake PCH ACS quirks
  2016-03-31 22:34 [PATCH 0/2] PCI: Skylake PCH ACS quirks Alex Williamson
  2016-03-31 22:34 ` [PATCH 1/2] PCI: Reverse standard ACS vs device specific ACS enabling Alex Williamson
  2016-03-31 22:34 ` [PATCH 2/2] PCI: Quirk PCH root port ACS for Sunrise Point Alex Williamson
@ 2016-04-19 23:53 ` Bjorn Helgaas
  2 siblings, 0 replies; 4+ messages in thread
From: Bjorn Helgaas @ 2016-04-19 23:53 UTC (permalink / raw)
  To: Alex Williamson; +Cc: linux-pci, bhelgaas, linux-kernel

On Thu, Mar 31, 2016 at 04:34:26PM -0600, Alex Williamson wrote:
> Intel Skylake systems attempted to implement ACS on the PCH root
> ports, but it came out a wee bit off.  As noted in the second patch
> and the datasheets from Intel, dwords were used for the ACS
> capability and control words, so we see the capabilities correctly
> but the control register is an extra 2 bytes offset.  With this
> quirk we can fix the kernel, unfortunately lspci will still show
> the wrong ACS control bits though.  Thanks,
> 
> Alex
> 
> ---
> 
> Alex Williamson (2):
>       PCI: Reverse standard ACS vs device specific ACS enabling
>       PCI: Quirk PCH root port ACS for Sunrise Point

Wow, hard to imagine how that got through validation.

Applied to pci/virtualization for v4.7, thanks, Alex!

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2016-04-19 23:53 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-31 22:34 [PATCH 0/2] PCI: Skylake PCH ACS quirks Alex Williamson
2016-03-31 22:34 ` [PATCH 1/2] PCI: Reverse standard ACS vs device specific ACS enabling Alex Williamson
2016-03-31 22:34 ` [PATCH 2/2] PCI: Quirk PCH root port ACS for Sunrise Point Alex Williamson
2016-04-19 23:53 ` [PATCH 0/2] PCI: Skylake PCH ACS quirks Bjorn Helgaas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).