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

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