diff mbox series

[1/1] UBUNTU: SAUCE: PCI: Serialize TGL e1000e PM ops

Message ID 20210316131328.1616280-2-kai.heng.feng@canonical.com
State New
Headers show
Series Fix system sleep on TGL systems with Intel ME | expand

Commit Message

Kai-Heng Feng March 16, 2021, 1:13 p.m. UTC
BugLink: https://bugs.launchpad.net/bugs/1919321

On TGL systems, PCI_COMMAND may randomly flip to 0 on system resume.
This is devastating to drivers that use pci_set_master(), like NVMe and
xHCI, to enable DMA in their resume routine, as pci_set_master() can
inadvertently disable PCI_COMMAND_IO and PCI_COMMAND_MEMORY, making
resources inaccessible.

The issue is reproducible on all kernel releases, but obviously the
situation is exacerbated by commit 6cecf02e77ab ('Revert "e1000e:
disable s0ix entry and exit flows for ME systems"').

Seems like ME is out to lunch until it's finally out of ULP polling. So
ensure e1000e PM ops are serialized by enforcing device links to
workaround the issue. This is another hacky hackish hack that we can't
upstream :)

Of course this will make suspend and resume a bit slower, but at least
we protect other PCI devices by keeping ME from going full basket case.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=212039
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
 drivers/pci/quirks.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
diff mbox series

Patch

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 6c2c8dafccfd..fb13b3109a43 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -5702,3 +5702,35 @@  static void pci_fixup_enable_vmd_nvme_ltr(struct pci_dev *pdev)
 }
 DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
 			      PCI_CLASS_STORAGE_EXPRESS, 0, pci_fixup_enable_vmd_nvme_ltr);
+
+static void pci_fixup_serialize_tgl_me_pm(struct pci_dev *pdev)
+{
+	struct pci_dev *rciep = NULL;
+
+	if (!pdev->bus)
+		return;
+
+	for_each_pci_dev(rciep) {
+		/* Most of TGL RCiEPs don't have type PCI_EXP_TYPE_RC_END,
+		 * check parent bridge instead. */
+		if (!rciep->bus)
+			continue;
+
+		if (rciep->bus->self != pdev->bus->self)
+			continue;
+
+		if (&rciep->dev == &pdev->dev)
+			continue;
+
+		if (device_link_add(&rciep->dev, &pdev->dev,
+				    DL_FLAG_STATELESS))
+			pci_info(rciep, "Suspend before and resume after %s\n",
+				 pci_name(pdev));
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x15fb, pci_fixup_serialize_tgl_me_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x15fc, pci_fixup_serialize_tgl_me_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x15f9, pci_fixup_serialize_tgl_me_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x15fa, pci_fixup_serialize_tgl_me_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x15f4, pci_fixup_serialize_tgl_me_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x15f5, pci_fixup_serialize_tgl_me_pm);