[Skiboot] [PATCH 4/4] core/pci: Avoid wait for hardware running on QEMU

Nicholas Piggin npiggin at gmail.com
Sun Nov 10 23:56:37 AEDT 2024


Waiting for PCI reset is the most costly component of a QEMU boot,
mostly due to 1s delay between PERST deassert and device config
space access. These PCI hardware delays are not required with QEMU,
so skip them on that platform.

On a single-CPU QEMU powernv10 machine where PCI probing is not well
parallelised, this reduces skiboot boot time from 6.3s to 0.4s. This is
important for testing and CI.

Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
 core/pci.c         | 36 +++++++++++++++++++++++++++---------
 include/pci-slot.h |  4 ++++
 2 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/core/pci.c b/core/pci.c
index 0a146c833..f297e6d2a 100644
--- a/core/pci.c
+++ b/core/pci.c
@@ -7,6 +7,7 @@
 
 #include <skiboot.h>
 #include <cpu.h>
+#include <chip.h>
 #include <pci.h>
 #include <pci-cfg.h>
 #include <pci-slot.h>
@@ -21,6 +22,23 @@ int last_phb_id = 0;
 /*
  * Generic PCI utilities
  */
+static void pci_time_wait(unsigned long duration)
+{
+	/* QEMU doesn't need to wait */
+	if (!chip_quirk(QUIRK_QEMU)) {
+		backtrace();
+		time_wait(duration);
+	}
+}
+
+static void pci_time_wait_ms(unsigned long ms)
+{
+	/* QEMU doesn't need to wait */
+	if (!chip_quirk(QUIRK_QEMU)) {
+		backtrace();
+		time_wait_ms(ms);
+	}
+}
 
 static int64_t __pci_find_cap(struct phb *phb, uint16_t bdfn,
 			      uint8_t want, bool check_cap_indicator)
@@ -205,7 +223,7 @@ bool pci_wait_crs(struct phb *phb, uint16_t bdfn, uint32_t *out_vdid)
 		if (vdid != 0xffff0001)
 			break;
 		had_crs = true;
-		time_wait_ms(100);
+		pci_time_wait_ms(100);
 	}
 	if (vdid == 0xffff0001) {
 		PCIERR(phb, bdfn, "CRS timeout !\n");
@@ -412,7 +430,7 @@ static void pci_slot_set_power_state(struct phb *phb,
 			break;
 
 		check_timers(false);
-		time_wait_ms(10);
+		pci_time_wait_ms(10);
 	} while (--wait >= 0);
 
 	if (wait < 0) {
@@ -497,7 +515,7 @@ static bool pci_bridge_power_on(struct phb *phb, struct pci_device *pd)
 				ecap + PCICAP_EXP_SLOTCTL, slot_ctl);
 
 		/* Wait a couple of seconds */
-		time_wait_ms(2000);
+		pci_time_wait_ms(2000);
 	}
 
 	/* Enable link */
@@ -528,7 +546,7 @@ static bool pci_bridge_wait_link(struct phb *phb,
 	 */
 	if (!(link_cap & PCICAP_EXP_LCAP_DL_ACT_REP)) {
 		if (was_reset)
-			time_wait_ms(1000);
+			pci_time_wait_ms(1000);
 
 		return true;
 	}
@@ -544,7 +562,7 @@ static bool pci_bridge_wait_link(struct phb *phb,
 		if (link_sts & PCICAP_EXP_LSTAT_DLLL_ACT)
 			break;
 
-		time_wait_ms(100);
+		pci_time_wait_ms(100);
 	}
 
 	if (!(link_sts & PCICAP_EXP_LSTAT_DLLL_ACT)) {
@@ -553,7 +571,7 @@ static bool pci_bridge_wait_link(struct phb *phb,
 	}
 
 	/* Need another 100ms before touching the config space */
-	time_wait_ms(100);
+	pci_time_wait_ms(100);
 	PCIDBG(phb, pd->bdfn, "link is up\n");
 
 	return true;
@@ -623,7 +641,7 @@ static bool pci_enable_bridge(struct phb *phb, struct pci_device *pd)
 		       "Bridge secondary reset is on, clearing it ...\n");
 		bctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET;
 		pci_cfg_write16(phb, pd->bdfn, PCI_CFG_BRCTL, bctl);
-		time_wait_ms(1000);
+		pci_time_wait_ms(1000);
 		was_reset = true;
 	}
 
@@ -973,7 +991,7 @@ static void pci_reset_phb(void *data)
 	rc = slot->ops.run_sm(slot);
 	while (rc > 0) {
 		PCITRACE(phb, 0, "Waiting %ld ms\n", tb_to_msecs(rc));
-		time_wait(rc);
+		pci_time_wait(rc);
 		rc = slot->ops.run_sm(slot);
 	}
 	pci_slot_remove_flags(slot, PCI_SLOT_FLAG_BOOTUP);
@@ -1675,7 +1693,7 @@ static void __pci_init_slots(void)
 	 */
 	for (i = 0; i < ARRAY_SIZE(phbs); i++) {
 		if (phbs[i]) {
-			time_wait_ms(20);
+			pci_time_wait_ms(20);
 			break;
 		}
 	}
diff --git a/include/pci-slot.h b/include/pci-slot.h
index 5eabd5af5..10b4142e8 100644
--- a/include/pci-slot.h
+++ b/include/pci-slot.h
@@ -5,6 +5,7 @@
 #define __PCI_SLOT_H
 
 #include <opal.h>
+#include <chip.h>
 #include <device.h>
 #include <timebase.h>
 #include <timer.h>
@@ -233,6 +234,9 @@ static inline void pci_slot_set_state(struct pci_slot *slot, uint32_t state)
 static inline uint64_t pci_slot_set_sm_timeout(struct pci_slot *slot,
 					       uint64_t dur)
 {
+	/* QEMU doesn't need to wait */
+	if (chip_quirk(QUIRK_QEMU))
+		return 0;
 	if (slot)
 		slot->delay_tgt_tb = mftb() + dur;
 	return dur;
-- 
2.45.2



More information about the Skiboot mailing list