Blame SOURCES/seabios-reset-force-standard-PCI-configuration-access.patch

bde9c9
From a7e5f1d8f1f874434f8b3e6d6eac784d5e3e3971 Mon Sep 17 00:00:00 2001
bde9c9
From: =?UTF-8?q?Volker=20R=C3=BCmelin?= <vr_qemu@t-online.de>
bde9c9
Date: Sat, 2 Apr 2022 20:28:39 +0200
bde9c9
Subject: [PATCH 3/3] reset: force standard PCI configuration access
bde9c9
MIME-Version: 1.0
bde9c9
Content-Type: text/plain; charset=UTF-8
bde9c9
Content-Transfer-Encoding: 8bit
bde9c9
bde9c9
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
bde9c9
RH-MergeRequest: 7: pci: fix reset for q35 and tcg
bde9c9
RH-Commit: [2/2] 693fbb9148c81f344dc9f64e7a36e51b42ee1a95
bde9c9
RH-Bugzilla: 2083884
bde9c9
RH-Acked-by: Pawel Polawski <ppolawsk@redhat.com>
bde9c9
RH-Acked-by: Oliver Steffen <osteffen@redhat.com>
bde9c9
RH-Acked-by: Igor Mammedov <imammedo@redhat.com>
bde9c9
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
bde9c9
bde9c9
After a reset of a QEMU -machine q35 guest, the PCI Express
bde9c9
Enhanced Configuration Mechanism is disabled and the variable
bde9c9
mmconfig no longer matches the configuration register PCIEXBAR
bde9c9
of the Q35 chipset. Until the variable mmconfig is reset to 0,
bde9c9
all pci_config_*() functions no longer work.
bde9c9
bde9c9
The variable mmconfig is located in one of the read-only C-F
bde9c9
segments. To reset it the pci_config_*() functions are needed,
bde9c9
but they do not work.
bde9c9
bde9c9
Replace all pci_config_*() calls with Standard PCI Configuration
bde9c9
Mechanism pci_ioconfig_*() calls until mmconfig is overwritten
bde9c9
with 0 by a fresh copy of the BIOS.
bde9c9
bde9c9
This fixes
bde9c9
bde9c9
In resume (status=0)
bde9c9
In 32bit resume
bde9c9
Attempting a hard reboot
bde9c9
Unable to unlock ram - bridge not found
bde9c9
bde9c9
and a reset loop with QEMU -accel tcg.
bde9c9
bde9c9
Signed-off-by: Volker RĂ¼melin <vr_qemu@t-online.de>
bde9c9
(cherry picked from commit 01774004c7f7fdc9c1e8f1715f70d3b913f8d491)
bde9c9
---
bde9c9
 src/fw/shadow.c | 14 +++++++-------
bde9c9
 src/hw/pci.c    | 27 +++++++++++++++++++++++++++
bde9c9
 src/hw/pci.h    |  6 ++++++
bde9c9
 3 files changed, 40 insertions(+), 7 deletions(-)
bde9c9
bde9c9
diff --git a/src/fw/shadow.c b/src/fw/shadow.c
bde9c9
index 4c627a8f..8930616e 100644
bde9c9
--- a/src/fw/shadow.c
bde9c9
+++ b/src/fw/shadow.c
bde9c9
@@ -32,8 +32,8 @@ __make_bios_writable_intel(u16 bdf, u32 pam0)
bde9c9
 {
bde9c9
     // Read in current PAM settings from pci config space
bde9c9
     union pamdata_u pamdata;
bde9c9
-    pamdata.data32[0] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4));
bde9c9
-    pamdata.data32[1] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4) + 4);
bde9c9
+    pamdata.data32[0] = pci_ioconfig_readl(bdf, ALIGN_DOWN(pam0, 4));
bde9c9
+    pamdata.data32[1] = pci_ioconfig_readl(bdf, ALIGN_DOWN(pam0, 4) + 4);
bde9c9
     u8 *pam = &pamdata.data8[pam0 & 0x03];
bde9c9
 
bde9c9
     // Make ram from 0xc0000-0xf0000 writable
bde9c9
@@ -46,8 +46,8 @@ __make_bios_writable_intel(u16 bdf, u32 pam0)
bde9c9
     pam[0] = 0x30;
bde9c9
 
bde9c9
     // Write PAM settings back to pci config space
bde9c9
-    pci_config_writel(bdf, ALIGN_DOWN(pam0, 4), pamdata.data32[0]);
bde9c9
-    pci_config_writel(bdf, ALIGN_DOWN(pam0, 4) + 4, pamdata.data32[1]);
bde9c9
+    pci_ioconfig_writel(bdf, ALIGN_DOWN(pam0, 4), pamdata.data32[0]);
bde9c9
+    pci_ioconfig_writel(bdf, ALIGN_DOWN(pam0, 4) + 4, pamdata.data32[1]);
bde9c9
 
bde9c9
     if (!ram_present)
bde9c9
         // Copy bios.
bde9c9
@@ -59,7 +59,7 @@ __make_bios_writable_intel(u16 bdf, u32 pam0)
bde9c9
 static void
bde9c9
 make_bios_writable_intel(u16 bdf, u32 pam0)
bde9c9
 {
bde9c9
-    int reg = pci_config_readb(bdf, pam0);
bde9c9
+    int reg = pci_ioconfig_readb(bdf, pam0);
bde9c9
     if (!(reg & 0x10)) {
bde9c9
         // QEMU doesn't fully implement the piix shadow capabilities -
bde9c9
         // if ram isn't backing the bios segment when shadowing is
bde9c9
@@ -125,8 +125,8 @@ make_bios_writable(void)
bde9c9
     // At this point, statically allocated variables can't be written,
bde9c9
     // so do this search manually.
bde9c9
     int bdf;
bde9c9
-    foreachbdf(bdf, 0) {
bde9c9
-        u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
bde9c9
+    pci_ioconfig_foreachbdf(bdf, 0) {
bde9c9
+        u32 vendev = pci_ioconfig_readl(bdf, PCI_VENDOR_ID);
bde9c9
         u16 vendor = vendev & 0xffff, device = vendev >> 16;
bde9c9
         if (vendor == PCI_VENDOR_ID_INTEL
bde9c9
             && device == PCI_DEVICE_ID_INTEL_82441) {
bde9c9
diff --git a/src/hw/pci.c b/src/hw/pci.c
bde9c9
index f13cbdea..8eda84b2 100644
bde9c9
--- a/src/hw/pci.c
bde9c9
+++ b/src/hw/pci.c
bde9c9
@@ -157,6 +157,33 @@ u8 pci_find_capability(u16 bdf, u8 cap_id, u8 cap)
bde9c9
     return 0;
bde9c9
 }
bde9c9
 
bde9c9
+// Helper function for pci_ioconfig_foreachbdf() macro - return next device
bde9c9
+int pci_ioconfig_next(int bdf, int bus)
bde9c9
+{
bde9c9
+    if (pci_bdf_to_fn(bdf) == 0
bde9c9
+        && (pci_ioconfig_readb(bdf, PCI_HEADER_TYPE) & 0x80) == 0)
bde9c9
+        // Last found device wasn't a multi-function device - skip to
bde9c9
+        // the next device.
bde9c9
+        bdf += 8;
bde9c9
+    else
bde9c9
+        bdf += 1;
bde9c9
+
bde9c9
+    for (;;) {
bde9c9
+        if (pci_bdf_to_bus(bdf) != bus)
bde9c9
+            return -1;
bde9c9
+
bde9c9
+        u16 v = pci_ioconfig_readw(bdf, PCI_VENDOR_ID);
bde9c9
+        if (v != 0x0000 && v != 0xffff)
bde9c9
+            // Device is present.
bde9c9
+            return bdf;
bde9c9
+
bde9c9
+        if (pci_bdf_to_fn(bdf) == 0)
bde9c9
+            bdf += 8;
bde9c9
+        else
bde9c9
+            bdf += 1;
bde9c9
+    }
bde9c9
+}
bde9c9
+
bde9c9
 // Helper function for foreachbdf() macro - return next device
bde9c9
 int
bde9c9
 pci_next(int bdf, int bus)
bde9c9
diff --git a/src/hw/pci.h b/src/hw/pci.h
bde9c9
index ee6acafc..b2f5baf4 100644
bde9c9
--- a/src/hw/pci.h
bde9c9
+++ b/src/hw/pci.h
bde9c9
@@ -27,6 +27,11 @@ static inline u16 pci_bus_devfn_to_bdf(int bus, u16 devfn) {
bde9c9
     return (bus << 8) | devfn;
bde9c9
 }
bde9c9
 
bde9c9
+#define pci_ioconfig_foreachbdf(BDF, BUS)                               \
bde9c9
+    for (BDF=pci_ioconfig_next(pci_bus_devfn_to_bdf((BUS), 0)-1, (BUS)) \
bde9c9
+         ; BDF >= 0                                                     \
bde9c9
+         ; BDF=pci_ioconfig_next(BDF, (BUS)))
bde9c9
+
bde9c9
 #define foreachbdf(BDF, BUS)                                    \
bde9c9
     for (BDF=pci_next(pci_bus_devfn_to_bdf((BUS), 0)-1, (BUS))  \
bde9c9
          ; BDF >= 0                                             \
bde9c9
@@ -39,6 +44,7 @@ void pci_ioconfig_writeb(u16 bdf, u32 addr, u8 val);
bde9c9
 u32 pci_ioconfig_readl(u16 bdf, u32 addr);
bde9c9
 u16 pci_ioconfig_readw(u16 bdf, u32 addr);
bde9c9
 u8 pci_ioconfig_readb(u16 bdf, u32 addr);
bde9c9
+int pci_ioconfig_next(int bdf, int bus);
bde9c9
 
bde9c9
 // PCI configuration access using either PCI CAM or PCIe ECAM
bde9c9
 void pci_config_writel(u16 bdf, u32 addr, u32 val);
bde9c9
-- 
bde9c9
2.35.3
bde9c9