1 | This patch aims to fix idle routine while the CPU receive an interrupt, | 1 | This patch aims to fix idle routine while the CPU receive an interrupt, |
---|---|---|---|
2 | because __r4k_wait() only checks if TIF_NEED_RESCHED is set before | 2 | because __r4k_wait() only checks if TIF_NEED_RESCHED is set before |
3 | going to sleep. | 3 | going to sleep. |
4 | The same behavior has been changed in LoongArch [1]. | 4 | The same behavior has been changed in LoongArch [1]. |
5 | 5 | ||
6 | Code (cross) compiled successfully and I manage to test it on a VM | 6 | Code (cross) compiled successfully and I manage to test it on a VM |
7 | emulating a malta board. I ran QEMU with: | 7 | emulating a malta board. I ran QEMU with: |
... | ... | ||
11 | 11 | ||
12 | rootfs generated using buildroot (malta default configuration). | 12 | rootfs generated using buildroot (malta default configuration). |
13 | 13 | ||
14 | - [1] https://github.com/chenhuacai/linux/commit/a8aa673ea46c03b3f62992ffa4ffe810ac84f6e3 | 14 | - [1] https://github.com/chenhuacai/linux/commit/a8aa673ea46c03b3f62992ffa4ffe810ac84f6e3 |
15 | 15 | ||
16 | --- | ||
17 | Changes in v3: | ||
18 | - changed "daddiu k0, 1" with PTR_ADDIU k0, 5 | ||
19 | - replaced CONFIG_CPU_MICROMIPS with 3 _ssnop followed by _ehb | ||
20 | - integrated the commit message with explanation about | ||
21 | CONFIG_CPU_MICROMIPS replacement | ||
22 | |||
23 | Changes in v2: | ||
24 | - Changes introduced by Huacai: | ||
25 | https://lore.kernel.org/linux-mips/20250214105047.150835-1-marco.crivellari@suse.com/T/#m75d9c587829e15e0d7baec13078be4e65c936408 | ||
26 | |||
16 | Marco Crivellari (1): | 27 | Marco Crivellari (1): |
17 | MIPS: Fix idle VS timer enqueue | 28 | MIPS: Fix idle VS timer enqueue |
18 | 29 | ||
19 | arch/mips/kernel/genex.S | 36 ++++++++++++++++++++---------------- | 30 | arch/mips/kernel/genex.S | 42 ++++++++++++++++++++++------------------ |
20 | arch/mips/kernel/idle.c | 1 - | 31 | arch/mips/kernel/idle.c | 1 - |
21 | 2 files changed, 20 insertions(+), 17 deletions(-) | 32 | 2 files changed, 23 insertions(+), 20 deletions(-) |
22 | 33 | ||
23 | -- | 34 | -- |
24 | 2.48.1 | 35 | 2.48.1 | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
14 | 14 | ||
15 | Fix this with fast-forwarding idle IRQs return address to the end of the | 15 | Fix this with fast-forwarding idle IRQs return address to the end of the |
16 | idle routine instead of the beginning, so that the generic idle loop | 16 | idle routine instead of the beginning, so that the generic idle loop |
17 | handles both TIF_NEED_RESCHED and pending timers. | 17 | handles both TIF_NEED_RESCHED and pending timers. |
18 | 18 | ||
19 | CONFIG_CPU_MICROMIPS has been removed along with the nop instructions. | ||
20 | There, NOPs are 2 byte in size, so change the code with 3 _ssnop which are | ||
21 | always 4 byte and remove the ifdef. Added ehb to make sure the hazard | ||
22 | is always cleared. | ||
23 | |||
19 | Signed-off-by: Marco Crivellari <marco.crivellari@suse.com> | 24 | Signed-off-by: Marco Crivellari <marco.crivellari@suse.com> |
20 | --- | 25 | --- |
21 | arch/mips/kernel/genex.S | 36 ++++++++++++++++++++---------------- | 26 | arch/mips/kernel/genex.S | 42 ++++++++++++++++++++++------------------ |
22 | arch/mips/kernel/idle.c | 1 - | 27 | arch/mips/kernel/idle.c | 1 - |
23 | 2 files changed, 20 insertions(+), 17 deletions(-) | 28 | 2 files changed, 23 insertions(+), 20 deletions(-) |
24 | 29 | ||
25 | diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S | 30 | diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S |
26 | index XXXXXXX..XXXXXXX 100644 | 31 | index XXXXXXX..XXXXXXX 100644 |
27 | --- a/arch/mips/kernel/genex.S | 32 | --- a/arch/mips/kernel/genex.S |
28 | +++ b/arch/mips/kernel/genex.S | 33 | +++ b/arch/mips/kernel/genex.S |
... | ... | ||
41 | - andi t0, _TIF_NEED_RESCHED | 46 | - andi t0, _TIF_NEED_RESCHED |
42 | - bnez t0, 1f | 47 | - bnez t0, 1f |
43 | - nop | 48 | - nop |
44 | - nop | 49 | - nop |
45 | - nop | 50 | - nop |
51 | -#ifdef CONFIG_CPU_MICROMIPS | ||
52 | - nop | ||
53 | - nop | ||
54 | - nop | ||
55 | - nop | ||
56 | -#endif | ||
46 | + /* start of idle interrupt region */ | 57 | + /* start of idle interrupt region */ |
47 | + MFC0 k0, CP0_STATUS | 58 | + MFC0 t0, CP0_STATUS |
48 | + /* Enable Interrupt */ | 59 | + /* Enable Interrput */ |
49 | + ori k0, 0x1f | 60 | + ori t0, 0x1f |
50 | + xori k0, 0x1e | 61 | + xori t0, 0x1e |
51 | + MTC0 k0, CP0_STATUS | 62 | + MTC0 t0, CP0_STATUS |
52 | #ifdef CONFIG_CPU_MICROMIPS | 63 | + _ssnop |
53 | nop | 64 | + _ssnop |
54 | nop | 65 | + _ssnop |
55 | @@ -XXX,XX +XXX,XX @@ LEAF(__r4k_wait) | 66 | + _ehb |
56 | nop | ||
57 | #endif | ||
58 | .set MIPS_ISA_ARCH_LEVEL_RAW | 67 | .set MIPS_ISA_ARCH_LEVEL_RAW |
59 | + /* | 68 | + /* |
60 | + * If an interrupt lands here, between enabling interrupts above and | 69 | + * If an interrupt lands here, between enabling interrupts above and |
61 | + * going idle on the next instruction, we must *NOT* go idle since the | 70 | + * going idle on the next instruction, we must *NOT* go idle since the |
62 | + * interrupt could have set TIF_NEED_RESCHED or caused a timer to need | 71 | + * interrupt could have set TIF_NEED_RESCHED or caused a timer to need |
63 | + * resched. Fall through -- see rollback_handler below -- and have | 72 | + * resched. Fall through -- see rollback_handler below -- and have |
64 | + * the idle loop take care of things. | 73 | + * the idle loop take care of things. |
65 | + */ | 74 | + */ |
66 | wait | 75 | wait |
67 | - /* end of rollback region (the region size must be power of two) */ | 76 | - /* end of rollback region (the region size must be power of two) */ |
68 | -1: | 77 | + /* end of rollback region */ |
69 | + /* end of idle interrupt region (the region size must be power of two) */ | 78 | 1: |
70 | +SYM_INNER_LABEL(__r4k_wait_exit, SYM_L_LOCAL) | ||
71 | jr ra | 79 | jr ra |
72 | - nop | 80 | nop |
73 | .set pop | ||
74 | END(__r4k_wait) | ||
75 | |||
76 | @@ -XXX,XX +XXX,XX @@ LEAF(__r4k_wait) | 81 | @@ -XXX,XX +XXX,XX @@ LEAF(__r4k_wait) |
77 | .set push | 82 | .set push |
78 | .set noat | 83 | .set noat |
79 | MFC0 k0, CP0_EPC | 84 | MFC0 k0, CP0_EPC |
80 | - PTR_LA k1, __r4k_wait | 85 | - PTR_LA k1, __r4k_wait |
81 | - ori k0, 0x1f /* 32 byte rollback region */ | 86 | - ori k0, 0x1f /* 32 byte rollback region */ |
82 | - xori k0, 0x1f | 87 | - xori k0, 0x1f |
83 | - bne k0, k1, \handler | 88 | + PTR_LA k1, 1b |
84 | + PTR_LA k1, __r4k_wait_exit | 89 | + /* 36 byte idle interrupt region */ |
85 | + /* 3 instructions rollback region */ | 90 | + ori k0, 0x1f |
86 | + ori k0, k0, 0x0c | 91 | + PTR_ADDIU k0, 5 |
87 | + bne k0, k1, \handler | 92 | bne k0, k1, \handler |
88 | MTC0 k0, CP0_EPC | 93 | MTC0 k0, CP0_EPC |
89 | .set pop | 94 | .set pop |
90 | .endm | ||
91 | diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c | 95 | diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c |
92 | index XXXXXXX..XXXXXXX 100644 | 96 | index XXXXXXX..XXXXXXX 100644 |
93 | --- a/arch/mips/kernel/idle.c | 97 | --- a/arch/mips/kernel/idle.c |
94 | +++ b/arch/mips/kernel/idle.c | 98 | +++ b/arch/mips/kernel/idle.c |
95 | @@ -XXX,XX +XXX,XX @@ static void __cpuidle r3081_wait(void) | 99 | @@ -XXX,XX +XXX,XX @@ static void __cpuidle r3081_wait(void) |
... | ... | diff view generated by jsdifflib |