diff options
author | Paul Mundt <lethal@linux-sh.org> | 2006-11-24 05:46:18 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-12-05 20:45:39 -0500 |
commit | 1dc41e58a553e612e3d0349bb60eef08f9462bde (patch) | |
tree | e45934bbe3367119861912458cf669a004565297 /arch/sh | |
parent | db9b99d461ddbbaa43c1e3581b1677b82c960948 (diff) |
sh: Fixup 4K irq stacks.
There was a clobber issue with the register we were saving
the stack in, so we switch to a register that we handle in
the clobber list properly already.
This also follows the x86 changes for allowing the softirq
checks from hardirq context.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r-- | arch/sh/kernel/irq.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index edf4d2d21336..46a19e07abd3 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c | |||
@@ -78,8 +78,8 @@ union irq_ctx { | |||
78 | u32 stack[THREAD_SIZE/sizeof(u32)]; | 78 | u32 stack[THREAD_SIZE/sizeof(u32)]; |
79 | }; | 79 | }; |
80 | 80 | ||
81 | static union irq_ctx *hardirq_ctx[NR_CPUS]; | 81 | static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly; |
82 | static union irq_ctx *softirq_ctx[NR_CPUS]; | 82 | static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; |
83 | #endif | 83 | #endif |
84 | 84 | ||
85 | asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, | 85 | asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, |
@@ -136,17 +136,24 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, | |||
136 | irqctx->tinfo.task = curctx->tinfo.task; | 136 | irqctx->tinfo.task = curctx->tinfo.task; |
137 | irqctx->tinfo.previous_sp = current_stack_pointer; | 137 | irqctx->tinfo.previous_sp = current_stack_pointer; |
138 | 138 | ||
139 | /* | ||
140 | * Copy the softirq bits in preempt_count so that the | ||
141 | * softirq checks work in the hardirq context. | ||
142 | */ | ||
143 | irqctx->tinfo.preempt_count = | ||
144 | (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) | | ||
145 | (curctx->tinfo.preempt_count & SOFTIRQ_MASK); | ||
146 | |||
139 | __asm__ __volatile__ ( | 147 | __asm__ __volatile__ ( |
140 | "mov %0, r4 \n" | 148 | "mov %0, r4 \n" |
141 | "mov r15, r9 \n" | 149 | "mov r15, r8 \n" |
142 | "jsr @%1 \n" | 150 | "jsr @%1 \n" |
143 | /* swith to the irq stack */ | 151 | /* swith to the irq stack */ |
144 | " mov %2, r15 \n" | 152 | " mov %2, r15 \n" |
145 | /* restore the stack (ring zero) */ | 153 | /* restore the stack (ring zero) */ |
146 | "mov r9, r15 \n" | 154 | "mov r8, r15 \n" |
147 | : /* no outputs */ | 155 | : /* no outputs */ |
148 | : "r" (irq), "r" (generic_handle_irq), "r" (isp) | 156 | : "r" (irq), "r" (generic_handle_irq), "r" (isp) |
149 | /* XXX: A somewhat excessive clobber list? -PFM */ | ||
150 | : "memory", "r0", "r1", "r2", "r3", "r4", | 157 | : "memory", "r0", "r1", "r2", "r3", "r4", |
151 | "r5", "r6", "r7", "r8", "t", "pr" | 158 | "r5", "r6", "r7", "r8", "t", "pr" |
152 | ); | 159 | ); |
@@ -194,7 +201,7 @@ void irq_ctx_init(int cpu) | |||
194 | irqctx->tinfo.task = NULL; | 201 | irqctx->tinfo.task = NULL; |
195 | irqctx->tinfo.exec_domain = NULL; | 202 | irqctx->tinfo.exec_domain = NULL; |
196 | irqctx->tinfo.cpu = cpu; | 203 | irqctx->tinfo.cpu = cpu; |
197 | irqctx->tinfo.preempt_count = SOFTIRQ_OFFSET; | 204 | irqctx->tinfo.preempt_count = 0; |
198 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); | 205 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); |
199 | 206 | ||
200 | softirq_ctx[cpu] = irqctx; | 207 | softirq_ctx[cpu] = irqctx; |
@@ -240,10 +247,14 @@ asmlinkage void do_softirq(void) | |||
240 | "mov r9, r15 \n" | 247 | "mov r9, r15 \n" |
241 | : /* no outputs */ | 248 | : /* no outputs */ |
242 | : "r" (__do_softirq), "r" (isp) | 249 | : "r" (__do_softirq), "r" (isp) |
243 | /* XXX: A somewhat excessive clobber list? -PFM */ | ||
244 | : "memory", "r0", "r1", "r2", "r3", "r4", | 250 | : "memory", "r0", "r1", "r2", "r3", "r4", |
245 | "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" | 251 | "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" |
246 | ); | 252 | ); |
253 | |||
254 | /* | ||
255 | * Shouldnt happen, we returned above if in_interrupt(): | ||
256 | */ | ||
257 | WARN_ON_ONCE(softirq_count()); | ||
247 | } | 258 | } |
248 | 259 | ||
249 | local_irq_restore(flags); | 260 | local_irq_restore(flags); |