Update toolchain/gdb to 7.12.1
[librecmc/librecmc.git] / target / linux / generic / patches-4.4 / 062-04-MIPS-Switch-to-the-irq_stack-in-interrupts.patch
1 From: Matt Redfearn <matt.redfearn@imgtec.com>
2 Date: Mon, 19 Dec 2016 14:20:59 +0000
3 Subject: [PATCH] MIPS: Switch to the irq_stack in interrupts
4
5 When enterring interrupt context via handle_int or except_vec_vi, switch
6 to the irq_stack of the current CPU if it is not already in use.
7
8 The current stack pointer is masked with the thread size and compared to
9 the base or the irq stack. If it does not match then the stack pointer
10 is set to the top of that stack, otherwise this is a nested irq being
11 handled on the irq stack so the stack pointer should be left as it was.
12
13 The in-use stack pointer is placed in the callee saved register s1. It
14 will be saved to the stack when plat_irq_dispatch is invoked and can be
15 restored once control returns here.
16
17 Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
18 ---
19
20 --- a/arch/mips/kernel/genex.S
21 +++ b/arch/mips/kernel/genex.S
22 @@ -188,9 +188,44 @@ NESTED(handle_int, PT_SIZE, sp)
23  
24         LONG_L  s0, TI_REGS($28)
25         LONG_S  sp, TI_REGS($28)
26 -       PTR_LA  ra, ret_from_irq
27 -       PTR_LA  v0, plat_irq_dispatch
28 -       jr      v0
29 +
30 +       /*
31 +        * SAVE_ALL ensures we are using a valid kernel stack for the thread.
32 +        * Check if we are already using the IRQ stack.
33 +        */
34 +       move    s1, sp # Preserve the sp
35 +
36 +       /* Get IRQ stack for this CPU */
37 +       ASM_CPUID_MFC0  k0, ASM_SMP_CPUID_REG
38 +#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
39 +       lui     k1, %hi(irq_stack)
40 +#else
41 +       lui     k1, %highest(irq_stack)
42 +       daddiu  k1, %higher(irq_stack)
43 +       dsll    k1, 16
44 +       daddiu  k1, %hi(irq_stack)
45 +       dsll    k1, 16
46 +#endif
47 +       LONG_SRL        k0, SMP_CPUID_PTRSHIFT
48 +       LONG_ADDU       k1, k0
49 +       LONG_L  t0, %lo(irq_stack)(k1)
50 +
51 +       # Check if already on IRQ stack
52 +       PTR_LI  t1, ~(_THREAD_SIZE-1)
53 +       and     t1, t1, sp
54 +       beq     t0, t1, 2f
55 +
56 +       /* Switch to IRQ stack */
57 +       li      t1, _IRQ_STACK_SIZE
58 +       PTR_ADD sp, t0, t1
59 +
60 +2:
61 +       jal     plat_irq_dispatch
62 +
63 +       /* Restore sp */
64 +       move    sp, s1
65 +
66 +       j       ret_from_irq
67  #ifdef CONFIG_CPU_MICROMIPS
68         nop
69  #endif
70 @@ -263,8 +298,44 @@ NESTED(except_vec_vi_handler, 0, sp)
71  
72         LONG_L  s0, TI_REGS($28)
73         LONG_S  sp, TI_REGS($28)
74 -       PTR_LA  ra, ret_from_irq
75 -       jr      v0
76 +
77 +       /*
78 +        * SAVE_ALL ensures we are using a valid kernel stack for the thread.
79 +        * Check if we are already using the IRQ stack.
80 +        */
81 +       move    s1, sp # Preserve the sp
82 +
83 +       /* Get IRQ stack for this CPU */
84 +       ASM_CPUID_MFC0  k0, ASM_SMP_CPUID_REG
85 +#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
86 +       lui     k1, %hi(irq_stack)
87 +#else
88 +       lui     k1, %highest(irq_stack)
89 +       daddiu  k1, %higher(irq_stack)
90 +       dsll    k1, 16
91 +       daddiu  k1, %hi(irq_stack)
92 +       dsll    k1, 16
93 +#endif
94 +       LONG_SRL        k0, SMP_CPUID_PTRSHIFT
95 +       LONG_ADDU       k1, k0
96 +       LONG_L  t0, %lo(irq_stack)(k1)
97 +
98 +       # Check if already on IRQ stack
99 +       PTR_LI  t1, ~(_THREAD_SIZE-1)
100 +       and     t1, t1, sp
101 +       beq     t0, t1, 2f
102 +
103 +       /* Switch to IRQ stack */
104 +       li      t1, _IRQ_STACK_SIZE
105 +       PTR_ADD sp, t0, t1
106 +
107 +2:
108 +       jal     plat_irq_dispatch
109 +
110 +       /* Restore sp */
111 +       move    sp, s1
112 +
113 +       j       ret_from_irq
114         END(except_vec_vi_handler)
115  
116  /*