summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@ozlabs.org>2008-04-09 09:21:28 +0200
committerPaul Mackerras <paulus@samba.org>2008-04-16 23:46:11 +0200
commite6768a4f392d05bc11ed508d35938932c73aac5a (patch)
tree29c04586b34437d80626222e4660926dda428cc7
parent[POWERPC] Initialize paca->current earlier (diff)
downloadlinux-e6768a4f392d05bc11ed508d35938932c73aac5a.tar.xz
linux-e6768a4f392d05bc11ed508d35938932c73aac5a.zip
[POWERPC] Fixup softirq preempt count
This fixes the handling of the preempt count when switching interrupt stacks so that HW interrupt properly get the softirq mask copied over from the previous stack. It also initializes the softirq stack preempt_count to 0 instead of SOFTIRQ_OFFSET, like x86, as __do_softirq() does the increment, and we hit some lockdep checks if we have it twice. That means we do run for a little while off the softirq stack with the preempt-count set to 0, which could be deadly if we try to take a softirq at that point, however we do so with interrupts disabled, so I think we are ok. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/kernel/irq.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 292163f5b39a..4617b65d464d 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -310,8 +310,21 @@ void do_IRQ(struct pt_regs *regs)
handler = &__do_IRQ;
irqtp->task = curtp->task;
irqtp->flags = 0;
+
+ /* Copy the softirq bits in preempt_count so that the
+ * softirq checks work in the hardirq context.
+ */
+ irqtp->preempt_count =
+ (irqtp->preempt_count & ~SOFTIRQ_MASK) |
+ (curtp->preempt_count & SOFTIRQ_MASK);
+
call_handle_irq(irq, desc, irqtp, handler);
irqtp->task = NULL;
+
+
+ /* Set any flag that may have been set on the
+ * alternate stack
+ */
if (irqtp->flags)
set_bits(irqtp->flags, &curtp->flags);
} else
@@ -357,7 +370,7 @@ void irq_ctx_init(void)
memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
tp = softirq_ctx[i];
tp->cpu = i;
- tp->preempt_count = SOFTIRQ_OFFSET;
+ tp->preempt_count = 0;
memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
tp = hardirq_ctx[i];