[Skiboot] [PATCH v2 04/11] core/timer: Always update hardware timer

Nicholas Piggin npiggin at gmail.com
Tue Jan 14 22:46:45 AEDT 2025


Have the core timer code always call into the SBE timers with the
soonest time, so the SBE code can be more careful with maintaining the
hardware timer.

This fixes a bug where the SBE timer is not being set immediately on
schedule_timer. With a subsequent change to SBE code, it allows an SBE
timer that fires too early to cause a re-schedule of the SBE timer.

Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
 core/timer.c  | 46 ++++++++++++++++++++++++++++++++++++++--------
 include/cpu.h |  1 +
 2 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/core/timer.c b/core/timer.c
index cd7112199..7f8c4b667 100644
--- a/core/timer.c
+++ b/core/timer.c
@@ -20,6 +20,7 @@
 #ifdef __TEST__
 #define this_cpu()	((void *)-1)
 #define cpu_relax()
+static bool running_timer;
 #else
 #include <cpu.h>
 #endif
@@ -33,6 +34,24 @@ static LIST_HEAD(timer_poll_list);
 static bool timer_in_poll;
 static uint64_t timer_poll_gen;
 
+static inline bool this_cpu_is_running_timer(void)
+{
+#ifdef __TEST__
+	return running_timer;
+#else
+	return this_cpu()->running_timer;
+#endif
+}
+
+static inline void this_cpu_set_running_timer(bool running)
+{
+#ifdef __TEST__
+	running_timer = running;
+#else
+	this_cpu()->running_timer = running;
+#endif
+}
+
 static inline void update_timer_expiry(uint64_t target)
 {
 	if (sbe_timer_ok())
@@ -119,15 +138,18 @@ static void __schedule_timer_at(struct timer *t, uint64_t when)
 			if (when >= lt->target)
 				continue;
 			list_add_before(&timer_list, &lt->link, &t->link);
-			goto bail;
+			goto added;
 		}
 		list_add_tail(&timer_list, &t->link);
-	}
- bail:
-	/* Pick up the next timer and upddate the SBE HW timer */
-	lt = list_top(&timer_list, struct timer, link);
-	if (lt) {
-		update_timer_expiry(lt->target);
+ added:
+		/* Timer running code will update expiry at the end */
+		if (!this_cpu_is_running_timer()) {
+			/* Pick the next timer and upddate the SBE HW timer */
+			lt = list_top(&timer_list, struct timer, link);
+			if (lt && (lt == t || when < lt->target)) {
+				update_timer_expiry(lt->target);
+			}
+		}
 	}
 }
 
@@ -190,6 +212,7 @@ static void __check_poll_timers(uint64_t now)
 		/* Allright, first remove it and mark it running */
 		__remove_timer(t);
 		t->running = this_cpu();
+		this_cpu_set_running_timer(true);
 
 		/* Now we can unlock and call it's expiry */
 		unlock(&timer_lock);
@@ -197,6 +220,7 @@ static void __check_poll_timers(uint64_t now)
 
 		/* Re-lock and mark not running */
 		lock(&timer_lock);
+		this_cpu_set_running_timer(false);
 		t->running = NULL;
 	}
 	timer_in_poll = false;
@@ -210,8 +234,12 @@ static void __check_timers(uint64_t now)
 		t = list_top(&timer_list, struct timer, link);
 
 		/* Top of list not expired ? that's it ... */
-		if (!t || t->target > now)
+		if (!t)
 			break;
+		if (t->target > now) {
+			update_timer_expiry(t->target);
+			break;
+		}
 
 		/* Top of list still running, we have to delay handling it,
 		 * let's reprogram the SLW/SBE with a small delay. We chose
@@ -225,6 +253,7 @@ static void __check_timers(uint64_t now)
 		/* Allright, first remove it and mark it running */
 		__remove_timer(t);
 		t->running = this_cpu();
+		this_cpu_set_running_timer(true);
 
 		/* Now we can unlock and call it's expiry */
 		unlock(&timer_lock);
@@ -232,6 +261,7 @@ static void __check_timers(uint64_t now)
 
 		/* Re-lock and mark not running */
 		lock(&timer_lock);
+		this_cpu_set_running_timer(false);
 		t->running = NULL;
 
 		/* Update time stamp */
diff --git a/include/cpu.h b/include/cpu.h
index d0fc6ccd5..2558d31a6 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -56,6 +56,7 @@ struct cpu_thread {
 	uint32_t			con_suspend;
 	struct list_head		locks_held;
 	bool				con_need_flush;
+	bool				running_timer;
 	bool				in_mcount;
 	bool				in_poller;
 	bool				in_reinit;
-- 
2.45.2



More information about the Skiboot mailing list