Skip to content

Commit edb1942

Browse files
DispatchCodechenhuacai
authored andcommitted
LoongArch: Fix idle VS timer enqueue
LoongArch re-enables interrupts on its idle routine and performs a TIF_NEED_RESCHED check afterwards before putting the CPU to sleep. The IRQs firing between the check and the idle instruction may set the TIF_NEED_RESCHED flag. In order to deal with such a race, IRQs interrupting __arch_cpu_idle() rollback their return address to the beginning of __arch_cpu_idle() so that TIF_NEED_RESCHED is checked again before going back to sleep. However idle IRQs can also queue timers that may require a tick reprogramming through a new generic idle loop iteration but those timers would go unnoticed here because __arch_cpu_idle() only checks TIF_NEED_RESCHED. It doesn't check for pending timers. Fix this with fast-forwarding idle IRQs return address to the end of the idle routine instead of the beginning, so that the generic idle loop can handle both TIF_NEED_RESCHED and pending timers. Fixes: 0603839 ("LoongArch: Add exception/interrupt handling") Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Frederic Weisbecker <[email protected]> Signed-off-by: Marco Crivellari <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent a64dcfb commit edb1942

File tree

3 files changed

+19
-18
lines changed

3 files changed

+19
-18
lines changed

arch/loongarch/kernel/genex.S

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,30 @@
1818

1919
.align 5
2020
SYM_FUNC_START(__arch_cpu_idle)
21-
/* start of rollback region */
22-
LONG_L t0, tp, TI_FLAGS
23-
nop
24-
andi t0, t0, _TIF_NEED_RESCHED
25-
bnez t0, 1f
26-
nop
27-
nop
28-
nop
21+
/* start of idle interrupt region */
22+
ori t0, zero, CSR_CRMD_IE
23+
/* idle instruction needs irq enabled */
24+
csrxchg t0, t0, LOONGARCH_CSR_CRMD
25+
/*
26+
* If an interrupt lands here; between enabling interrupts above and
27+
* going idle on the next instruction, we must *NOT* go idle since the
28+
* interrupt could have set TIF_NEED_RESCHED or caused an timer to need
29+
* reprogramming. Fall through -- see handle_vint() below -- and have
30+
* the idle loop take care of things.
31+
*/
2932
idle 0
30-
/* end of rollback region */
33+
/* end of idle interrupt region */
3134
1: jr ra
3235
SYM_FUNC_END(__arch_cpu_idle)
3336

3437
SYM_CODE_START(handle_vint)
3538
UNWIND_HINT_UNDEFINED
3639
BACKUP_T0T1
3740
SAVE_ALL
38-
la_abs t1, __arch_cpu_idle
41+
la_abs t1, 1b
3942
LONG_L t0, sp, PT_ERA
40-
/* 32 byte rollback region */
41-
ori t0, t0, 0x1f
42-
xori t0, t0, 0x1f
43+
/* 3 instructions idle interrupt region */
44+
ori t0, t0, 0b1100
4345
bne t0, t1, 1f
4446
LONG_S t0, sp, PT_ERA
4547
1: move a0, sp

arch/loongarch/kernel/idle.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
void __cpuidle arch_cpu_idle(void)
1313
{
14-
raw_local_irq_enable();
15-
__arch_cpu_idle(); /* idle instruction needs irq enabled */
14+
__arch_cpu_idle();
1615
raw_local_irq_disable();
1716
}

arch/loongarch/kernel/reset.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ void machine_halt(void)
3333
console_flush_on_panic(CONSOLE_FLUSH_PENDING);
3434

3535
while (true) {
36-
__arch_cpu_idle();
36+
__asm__ __volatile__("idle 0" : : : "memory");
3737
}
3838
}
3939

@@ -53,7 +53,7 @@ void machine_power_off(void)
5353
#endif
5454

5555
while (true) {
56-
__arch_cpu_idle();
56+
__asm__ __volatile__("idle 0" : : : "memory");
5757
}
5858
}
5959

@@ -74,6 +74,6 @@ void machine_restart(char *command)
7474
acpi_reboot();
7575

7676
while (true) {
77-
__arch_cpu_idle();
77+
__asm__ __volatile__("idle 0" : : : "memory");
7878
}
7979
}

0 commit comments

Comments
 (0)