[Skiboot] [PATCH 04/11] core/timer: Always update hardware timer
Nicholas Piggin
npiggin at gmail.com
Sat Nov 16 15:07:20 AEDT 2024
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 | 27 +++++++++++++++++++--------
include/cpu.h | 1 +
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/core/timer.c b/core/timer.c
index cd7112199..f512972eb 100644
--- a/core/timer.c
+++ b/core/timer.c
@@ -119,15 +119,18 @@ static void __schedule_timer_at(struct timer *t, uint64_t when)
if (when >= lt->target)
continue;
list_add_before(&timer_list, <->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()->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 +193,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()->running_timer = true;
/* Now we can unlock and call it's expiry */
unlock(&timer_lock);
@@ -197,6 +201,7 @@ static void __check_poll_timers(uint64_t now)
/* Re-lock and mark not running */
lock(&timer_lock);
+ this_cpu()->running_timer = false;
t->running = NULL;
}
timer_in_poll = false;
@@ -210,8 +215,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 +234,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()->running_timer = true;
/* Now we can unlock and call it's expiry */
unlock(&timer_lock);
@@ -232,6 +242,7 @@ static void __check_timers(uint64_t now)
/* Re-lock and mark not running */
lock(&timer_lock);
+ this_cpu()->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