git: b30d06409e5f - stable/15 - powerpc: add a best-effort SMP time base sync for G5's that need it
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 30 Jan 2026 05:02:57 UTC
The branch stable/15 has been updated by adrian:
URL: https://cgit.FreeBSD.org/src/commit/?id=b30d06409e5f8851c0505929f4f3999f7bc65b1d
commit b30d06409e5f8851c0505929f4f3999f7bc65b1d
Author: Adrian Chadd <adrian@FreeBSD.org>
AuthorDate: 2026-01-20 02:38:43 +0000
Commit: Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-01-30 05:02:49 +0000
powerpc: add a best-effort SMP time base sync for G5's that need it
There's no timebase freeze platform routine registered on my dual 2.3GHz
G5 PPC970FX Apple PowerMac.
For platforms without an explicit timebase freeze/unfreeze, we'll have to
make do with what we have - which for now is an explicit hand-crafted
spinlock/rendezvous method.
* For existing platforms, they'll still continue to clock freeze /
rendezvous; albeit with some stronger atomic bits now (from jhibbits@.)
* Instead of the fallback being "no timesync", implement a
best-effort one which does a similar rendezvous barrier between
BSP and APs, but instead of freeze/unfreeze the first instruction
after the CPUs all register they're ready is to set the timebase.
This has resulted in many reboots of my Powermac G5 dual-socket device
correctly starting and running in SMP mode.
Differential Revision: https://reviews.freebsd.org/D54821
Reviewed by: jhibbits
(cherry picked from commit 422c8719eab2b8a01b49f748a88dd372db25f888)
---
sys/powerpc/powermac/platform_powermac.c | 99 +++++++++++++++++++++++++++++---
1 file changed, 90 insertions(+), 9 deletions(-)
diff --git a/sys/powerpc/powermac/platform_powermac.c b/sys/powerpc/powermac/platform_powermac.c
index c63ef521ca8f..cbb2e212a00d 100644
--- a/sys/powerpc/powermac/platform_powermac.c
+++ b/sys/powerpc/powermac/platform_powermac.c
@@ -405,21 +405,88 @@ powermac_register_timebase(device_t dev, powermac_tb_disable_t cb)
freeze_timebase = cb;
}
+/**
+ * @brief Implement a default platform AP/BSP SMP timebase synchronisation
+ *
+ * Some powermac platforms don't have a freeze/unfreeze method.
+ * Here just try our best to force synchronisation.
+ */
static void
-powermac_smp_timebase_sync(platform_t plat, u_long tb, int ap)
+powermac_smp_timebase_sync_fallback(platform_t plat, u_long tb, int ap)
+{
+ static volatile bool tb_ready = false;
+ static volatile int cpu_done;
+
+ if (bootverbose)
+ printf("[%d] %s: called, AP tb=0x%lx tb=0x%lx\n",
+ ap, __func__, tb, mftb());
+
+ /* Do initial timebase sync */
+ mttb(tb);
+
+ if (ap) {
+ /*
+ * APs - wait until the BSP signals its ready to sync,
+ * then wait for all CPUs to be ready.
+ */
+ critical_enter();
+ while (!tb_ready)
+ atomic_thread_fence_seq_cst();
+ atomic_add_int(&cpu_done, 1);
+ do {
+ atomic_thread_fence_seq_cst();
+ } while (cpu_done < mp_ncpus);
+ mttb(tb);
+ critical_exit();
+ } else {
+ /*
+ * BSP - signify that the timebase sync is about to start,
+ * then wait for other CPUs to be ready.
+ */
+ critical_enter();
+ /* Ensure cpu_done is zeroed so we can resync at runtime */
+ atomic_store_int(&cpu_done, 0);
+ tb_ready = true;
+ atomic_add_int(&cpu_done, 1);
+ do {
+ atomic_thread_fence_seq_cst();
+ } while (cpu_done < mp_ncpus);
+ mttb(tb);
+ /* Reset tb_ready so we can resync at runtime */
+ tb_ready = false;
+ critical_exit();
+ }
+ if (bootverbose)
+ printf("[%d] %s: finished; AP tb=0x%lx called tb=0x%lx\n",
+ ap, __func__, tb, mftb());
+}
+
+/**
+ * @brief Implement freeze/unfreeze AP/BSP SMP timebase synchronisation
+ *
+ * This implements SMP timebase synchronisation for hardware that
+ * implements freezing a shared timebase clock source.
+ *
+ * The BSP will freeze the timebase and signal the APs to program their
+ * local timebase with the shared timebase value. The BSP will then
+ * unfreeze the timebase clock, allowing all CPUs to march forward
+ * from the same base timebase value.
+ */
+static void
+powermac_smp_timebase_sync_freeze(platform_t plat, u_long tb, int ap)
{
- static volatile bool tb_ready;
+ static volatile bool tb_ready = false;
static volatile int cpu_done;
+ if (bootverbose)
+ printf("[%d] %s: called, AP tb=0x%lx tb=0x%lx\n",
+ ap, __func__, tb, mftb());
+
/*
- * XXX Temporary fallback for platforms we don't know how to freeze.
- *
* This needs to be replaced with a cpu-to-cpu software sync
* protocol, because this is not a consistent way to sync timebase.
*/
mttb(tb);
- if (freeze_timebase == dummy_timebase)
- return;
if (ap) {
/* APs. Hold off until we get a stable timebase. */
@@ -428,25 +495,39 @@ powermac_smp_timebase_sync(platform_t plat, u_long tb, int ap)
atomic_thread_fence_seq_cst();
mttb(tb);
atomic_add_int(&cpu_done, 1);
- while (cpu_done < mp_ncpus)
+ do {
atomic_thread_fence_seq_cst();
+ } while (cpu_done < mp_ncpus);
critical_exit();
} else {
/* BSP */
critical_enter();
/* Ensure cpu_done is zeroed so we can resync at runtime */
- atomic_set_int(&cpu_done, 0);
+ atomic_store_int(&cpu_done, 0);
freeze_timebase(powermac_tb_dev, true);
tb_ready = true;
mttb(tb);
atomic_add_int(&cpu_done, 1);
- while (cpu_done < mp_ncpus)
+ do {
atomic_thread_fence_seq_cst();
+ } while (cpu_done < mp_ncpus);
freeze_timebase(powermac_tb_dev, false);
/* Reset tb_ready so we can resync at runtime */
tb_ready = false;
critical_exit();
}
+ if (bootverbose)
+ printf("[%d] %s: finished; AP tb=0x%lx called tb=0x%lx\n",
+ ap, __func__, tb, mftb());
+}
+
+static void
+powermac_smp_timebase_sync(platform_t plat, u_long tb, int ap)
+{
+ if (freeze_timebase == dummy_timebase)
+ powermac_smp_timebase_sync_fallback(plat, tb, ap);
+ else
+ powermac_smp_timebase_sync_freeze(plat, tb, ap);
}
/* Fallback freeze. In case no real handler is found in the device tree. */