From caf585b0a1523be44de8522019bc989ce66bcd2e Mon Sep 17 00:00:00 2001 From: Lephe Date: Mon, 15 Nov 2021 06:42:11 +0100 Subject: [PATCH] tmu: fix freeze when using sleep_us_spin() with interrupts on Because of timing the interrupt handler could run before the flag is checked. --- include/gint/timer.h | 7 ++++--- src/tmu/sleep.c | 6 ++++-- src/tmu/tmu.c | 7 ++++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/gint/timer.h b/include/gint/timer.h index da010bc..9602ae8 100644 --- a/include/gint/timer.h +++ b/include/gint/timer.h @@ -162,10 +162,11 @@ void timer_stop(int timer); it may have only paused. If the timer never stops, you're in trouble. */ void timer_wait(int timer); -/* timer_spinwait(): Actively wait for a timer to raise UNF +/* timer_spinwait(): Start a timer and actively wait for UNF Waits until the timer raises UNF, without sleeping. This is useful for - delays in driver code that is run when interrupts are disabled. This relies - neither on the interrupt signal nor on the UNIE flag. */ + delays in driver code that is run when interrupts are disabled. UNIE is + disabled before starting the timer and waiting, so the callback is never + called. */ void timer_spinwait(int timer); //--- diff --git a/src/tmu/sleep.c b/src/tmu/sleep.c index 7677990..19bfb05 100644 --- a/src/tmu/sleep.c +++ b/src/tmu/sleep.c @@ -13,12 +13,14 @@ static void do_sleep(uint64_t delay_us, int spin) GINT_CALL_SET_STOP(&flag)); if(timer < 0) return; - timer_start(timer); if(spin) { timer_spinwait(timer); timer_stop(timer); } - else timer_wait(timer); + else { + timer_start(timer); + timer_wait(timer); + } } /* sleep_us(): Sleep for a fixed duration in microseconds */ diff --git a/src/tmu/tmu.c b/src/tmu/tmu.c index bcc3c71..8e57eb3 100644 --- a/src/tmu/tmu.c +++ b/src/tmu/tmu.c @@ -209,6 +209,7 @@ void timer_stop(int id) if(id < 3) { TMU[id].TCR.UNIE = 0; + TMU[id].TCR.UNF = 0; TMU[id].TCOR = 0xffffffff; TMU[id].TCNT = 0xffffffff; } @@ -240,17 +241,21 @@ void timer_wait(int id) } } -/* timer_spinwait(): Actively wait for a timer to raise UNF */ +/* timer_spinwait(): Start a timer and actively wait for UNF */ void timer_spinwait(int id) { if(id < 3) { tmu_t *T = &TMU[id]; + T->TCR.UNIE = 0; + timer_start(id); while(!T->TCR.UNF) {} } else { etmu_t *T = &ETMU[id-3]; + set(T->TCR.UNIE, 0); + timer_start(id); while(!T->TCR.UNF) {} } }