[PATCH v3] PCI: Add ACS errata for Pericom PI7C9X2G switches

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Nathan Rossi <nathan.rossi@xxxxxxxx>

The Pericom PI7C9X2G404/PI7C9X2G304/PI7C9X2G303 PCIe switches have an
errata for ACS P2P Request Redirect behaviour when used in the
cut-through forwarding mode. The recommended work around for this issue
is to use the switch in store and forward mode. The errata results in
packets being queued and not being delivered upstream, this can be
observed as very poor downstream device performance and/or dropped
device generated data/interrupts.

This change adds a fixup specific to this switch that when enabling or
resuming the downstream port it checks if it has enabled ACS P2P Request
Redirect, and if so changes the device (via the upstream port) to use
the store and forward operating mode.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=177471
Signed-off-by: Nathan Rossi <nathan.rossi@xxxxxxxx>
Tested-by: Alex Williamson <alex.williamson@xxxxxxxxxx>
---
Changes in v2:
- Added DECLARE_PCI_FIXUP_RESUME to handle applying fixup upon resume as
  switch operation may have been reset or ACS configuration may have
  changed
Changes in v3:
- Apply fixup to PI7C9X2G303 and PI7C9X2G304 switch models, these models
  are also covered by the errata, although have not been validated
- Rename PI7C9X2G404 defines to more generic PI7C9X2Gxxx
---
 drivers/pci/quirks.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index e5089af8ad..f7cbc4fa40 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -5790,3 +5790,59 @@ static void apex_pci_fixup_class(struct pci_dev *pdev)
 }
 DECLARE_PCI_FIXUP_CLASS_HEADER(0x1ac1, 0x089a,
 			       PCI_CLASS_NOT_DEFINED, 8, apex_pci_fixup_class);
+
+/*
+ * Pericom PI7C9X2G404/PI7C9X2G304/PI7C9X2G303 switch errata E5 - ACS P2P Request
+ * Redirect is not functional
+ *
+ * When ACS P2P Request Redirect is enabled and bandwidth is not balanced
+ * between upstream and downstream ports, packets are queued in an internal
+ * buffer until CPLD packet. The workaround is to use the switch in store and
+ * forward mode.
+ */
+#define PI7C9X2Gxxx_MODE_REG		0x74
+#define PI7C9X2Gxxx_STORE_FORWARD_MODE	BIT(0)
+static void pci_fixup_pericom_acs_store_forward(struct pci_dev *pdev)
+{
+	struct pci_dev *upstream;
+	u16 val;
+
+	/* Downstream ports only */
+	if (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM)
+		return;
+
+	/* Check for ACS P2P Request Redirect use */
+	if (!pdev->acs_cap)
+		return;
+	pci_read_config_word(pdev, pdev->acs_cap + PCI_ACS_CTRL, &val);
+	if (!(val & PCI_ACS_RR))
+		return;
+
+	upstream = pci_upstream_bridge(pdev);
+	if (!upstream)
+		return;
+
+	pci_read_config_word(upstream, PI7C9X2Gxxx_MODE_REG, &val);
+	if (!(val & PI7C9X2Gxxx_STORE_FORWARD_MODE)) {
+		pci_info(upstream, "Setting PI7C9X2Gxxx store-forward mode\n");
+		/* Enable store-foward mode */
+		pci_write_config_word(upstream, PI7C9X2Gxxx_MODE_REG, val |
+				      PI7C9X2Gxxx_STORE_FORWARD_MODE);
+	}
+}
+/*
+ * Apply fixup on enable and on resume, in order to apply the fix up whenever
+ * ACS configuration changes or switch mode is reset
+ */
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2404,
+			 pci_fixup_pericom_acs_store_forward);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2404,
+			 pci_fixup_pericom_acs_store_forward);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2304,
+			 pci_fixup_pericom_acs_store_forward);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2304,
+			 pci_fixup_pericom_acs_store_forward);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2303,
+			 pci_fixup_pericom_acs_store_forward);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2303,
+			 pci_fixup_pericom_acs_store_forward);
---
2.33.0



[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux