[Skiboot] [PATCH 11/11] hw/sbe-p9: P10 additions
Nicholas Piggin
npiggin at gmail.com
Sat Nov 16 15:07:27 AEDT 2024
P10 has a lower minimum timeout threshold than P9 (100usecs).
Some P10 SBE timers run about 6.7% slow, so use the SBE timer health
checking code to detect this and compensate for it. Speeding up timers
is dangerous because early-expiry is a bug, but the core timer code
checks against the CPU's timebase when running timers, so in case we
get this slightly wrong it won't cause trouble.
Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
hw/sbe-p9.c | 47 ++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 42 insertions(+), 5 deletions(-)
diff --git a/hw/sbe-p9.c b/hw/sbe-p9.c
index 0522c4174..a168f5409 100644
--- a/hw/sbe-p9.c
+++ b/hw/sbe-p9.c
@@ -90,11 +90,21 @@ static struct lock sbe_timer_lock;
*/
#define SBE_TIMER_MIN_US_P9 500
+/*
+ * P10 minimum timeout is 100, maximum is around 10s. Minimum is not really
+ * the minimum so we could program shorter, it's just a "minimum accurate"
+ * number where fixed errors become relatively insignificant.
+ */
+#define SBE_TIMER_MIN_US_P10 100
+
#define SBE_TIMER_MAX_US 10000000
static uint64_t sbe_timer_min_us;
static uint64_t sbe_timer_min_tb;
+/* Some P10s have a slow SBE timer */
+static bool slow_sbe_timer;
+
/*
* Rate limit continuous timer update.
* We can update inflight timer if new timer request is lesser than inflight
@@ -836,6 +846,18 @@ static void p9_sbe_timer_schedule(void)
sbe_current_timer_tb = now + usecs_to_tb(tick_us);
+ if (slow_sbe_timer) {
+ /*
+ * P10 SBE timer is 6.6% slow, speed it up about 6.3%.
+ * This should not be reflected in sbe_current_timer_tb,
+ * because that is used for the _intended_ expiry time.
+ */
+ if (tick_us > 1000) {
+ tick_us *= 240;
+ tick_us /= 256;
+ }
+ }
+
/* Clear sequence number. p9_sbe_queue_msg will add new sequene ID */
timer_ctrl_msg->reg[0] &= ~(PPC_BITMASK(32, 47));
/* Update timeout value */
@@ -875,7 +897,7 @@ void p9_sbe_update_timer_expiry(uint64_t new_target)
/* If no response, consider the SBE bad */
#define SBE_TEST_TIMEOUT_MS 20
-static bool p9_sbe_test(struct p9_sbe *sbe)
+static bool p9_sbe_test(struct p9_sbe *sbe, unsigned long delay_us)
{
struct p9_sbe_msg *msg;
u64 data;
@@ -884,7 +906,7 @@ static bool p9_sbe_test(struct p9_sbe *sbe)
/* Same as timer_ctrl_msg */
msg = p9_sbe_mkmsg(SBE_CMD_CONTROL_TIMER, CONTROL_TIMER_START,
- sbe_timer_min_us, 0, 0);
+ delay_us, 0, 0);
if (!msg) {
prlog(PR_ERR, "Failed to allocate msg\n");
return false;
@@ -925,7 +947,7 @@ static bool p9_sbe_test(struct p9_sbe *sbe)
ts = now;
timeout = now + msecs_to_tb(SBE_TEST_TIMEOUT_MS) +
- usecs_to_tb(sbe_timer_min_us);
+ usecs_to_tb(delay_us);
do {
rc = xscom_read(sbe->chip_id, PSU_HOST_DOORBELL_REG_RW, &data);
if (rc) {
@@ -970,7 +992,10 @@ static void p9_sbe_timer_init(void)
sbe_timer_good = true;
sbe_timer_target = ~0ull;
sbe_current_timer_tb = ~0ull;
- sbe_timer_min_us = SBE_TIMER_MIN_US_P9;
+ if (proc_gen == proc_gen_p9)
+ sbe_timer_min_us = SBE_TIMER_MIN_US_P9;
+ else
+ sbe_timer_min_us = SBE_TIMER_MIN_US_P10;
sbe_timer_min_tb = usecs_to_tb(sbe_timer_min_us);
prlog(PR_INFO, "Timer facility on chip %x\n", sbe_default_chip_id);
@@ -1045,7 +1070,7 @@ void p9_sbe_init(void)
chip = get_chip(sbe->chip_id);
assert(chip);
- if (!p9_sbe_test(sbe)) {
+ if (!p9_sbe_test(sbe, sbe_timer_min_us)) {
free(sbe);
continue;
}
@@ -1064,6 +1089,18 @@ void p9_sbe_init(void)
return;
}
+ if (proc_gen == proc_gen_p10) {
+ u64 tb = mftb();
+ if (!p9_sbe_test(p9_sbe_get_sbe(-1), 100 * 1000)) {
+ prlog(PR_ERR, "Error calibrating timer\n");
+ return;
+ }
+ if (mftb() - tb > usecs_to_tb(106 * 1000)) {
+ prlog(PR_INFO, "Slow P10 SBE timer detected, compensating.\n");
+ slow_sbe_timer = true;
+ }
+ }
+
/* Initiate SBE timer */
p9_sbe_timer_init();
--
2.45.2
More information about the Skiboot
mailing list