summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2006-11-24 19:46:18 +0900
committerPaul Mundt <lethal@linux-sh.org>2006-12-06 10:45:39 +0900
commit1dc41e58a553e612e3d0349bb60eef08f9462bde (patch)
treee45934bbe3367119861912458cf669a004565297
parentdb9b99d461ddbbaa43c1e3581b1677b82c960948 (diff)
downloadlinux-1dc41e58a553e612e3d0349bb60eef08f9462bde.tar.gz
linux-1dc41e58a553e612e3d0349bb60eef08f9462bde.tar.bz2
linux-1dc41e58a553e612e3d0349bb60eef08f9462bde.zip
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>
-rw-r--r--arch/sh/kernel/irq.c25
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 {
u32 stack[THREAD_SIZE/sizeof(u32)];
};
-static union irq_ctx *hardirq_ctx[NR_CPUS];
-static union irq_ctx *softirq_ctx[NR_CPUS];
+static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
+static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
#endif
asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
@@ -136,17 +136,24 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
irqctx->tinfo.task = curctx->tinfo.task;
irqctx->tinfo.previous_sp = current_stack_pointer;
+ /*
+ * Copy the softirq bits in preempt_count so that the
+ * softirq checks work in the hardirq context.
+ */
+ irqctx->tinfo.preempt_count =
+ (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
+ (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
+
__asm__ __volatile__ (
"mov %0, r4 \n"
- "mov r15, r9 \n"
+ "mov r15, r8 \n"
"jsr @%1 \n"
/* swith to the irq stack */
" mov %2, r15 \n"
/* restore the stack (ring zero) */
- "mov r9, r15 \n"
+ "mov r8, r15 \n"
: /* no outputs */
: "r" (irq), "r" (generic_handle_irq), "r" (isp)
- /* XXX: A somewhat excessive clobber list? -PFM */
: "memory", "r0", "r1", "r2", "r3", "r4",
"r5", "r6", "r7", "r8", "t", "pr"
);
@@ -194,7 +201,7 @@ void irq_ctx_init(int cpu)
irqctx->tinfo.task = NULL;
irqctx->tinfo.exec_domain = NULL;
irqctx->tinfo.cpu = cpu;
- irqctx->tinfo.preempt_count = SOFTIRQ_OFFSET;
+ irqctx->tinfo.preempt_count = 0;
irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
softirq_ctx[cpu] = irqctx;
@@ -240,10 +247,14 @@ asmlinkage void do_softirq(void)
"mov r9, r15 \n"
: /* no outputs */
: "r" (__do_softirq), "r" (isp)
- /* XXX: A somewhat excessive clobber list? -PFM */
: "memory", "r0", "r1", "r2", "r3", "r4",
"r5", "r6", "r7", "r8", "r9", "r15", "t", "pr"
);
+
+ /*
+ * Shouldnt happen, we returned above if in_interrupt():
+ */
+ WARN_ON_ONCE(softirq_count());
}
local_irq_restore(flags);