[RFC] [PATCH] ppc32: Separate IRQ stacks
Josh Boyer
jwboyer at jdub.homelinux.org
Tue Sep 14 09:54:55 EST 2004
Hi,
The following patch implements separate hard and soft IRQ stacks for
PPC32. It compiles cleanly against 2.6.9-rc2, but it is untested as I
have no PPC hardware at the moment. (Working on that though).
The main reason I did this was basically just for proof-of-concept.
Eventually, I may do a 4K stack patch for PPC32 and this would be needed
then anyway. That probably won't happen until I get some hardware to
test with though.
Comments would be appreciated.
thx,
josh
Signed-off-by: Josh Boyer <jwboyer at jdub.homelinux.org>
diff -Naur linux-2.6.9-rc2/arch/ppc/Kconfig.debug linux-2.6.9-rc2.jwb/arch/ppc/Kconfig.debug
--- linux-2.6.9-rc2/arch/ppc/Kconfig.debug 2004-09-13 17:00:25.000000000 -0500
+++ linux-2.6.9-rc2.jwb/arch/ppc/Kconfig.debug 2004-09-13 18:10:18.586814816 -0500
@@ -81,4 +81,11 @@
depends on IBM_OCP || FSL_OCP
default y
+config IRQSTACKS
+ bool "Use separate kernel stacks when processing interrupts"
+ help
+ If you say Y here the kernel will use separate kernel stacks
+ for handling hard and soft interrupts. This can help avoid
+ overflowing the process kernel stacks.
+
endmenu
diff -Naur linux-2.6.9-rc2/arch/ppc/kernel/irq.c linux-2.6.9-rc2.jwb/arch/ppc/kernel/irq.c
--- linux-2.6.9-rc2/arch/ppc/kernel/irq.c 2004-09-13 17:00:26.000000000 -0500
+++ linux-2.6.9-rc2.jwb/arch/ppc/kernel/irq.c 2004-09-13 18:10:18.690799008 -0500
@@ -411,8 +411,7 @@
return 0;
}
-static inline void
-handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action)
+void handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action)
{
int status = 0;
int ret;
@@ -440,6 +439,9 @@
int status;
struct irqaction *action;
irq_desc_t *desc = irq_desc + irq;
+#ifdef CONFIG_IRQSTACKS
+ struct thread_info *curtp, *irqtp;
+#endif
kstat_this_cpu.irqs[irq]++;
spin_lock(&desc->lock);
@@ -498,6 +500,20 @@
*/
for (;;) {
spin_unlock(&desc->lock);
+
+#ifdef CONFIG_IRQSTACKS
+ /* Switch to the irq stack to handle this */
+ curtp = current_thread_info();
+ irqtp = hardirq_ctx[smp_processor_id()];
+ if (curtp != irqtp) {
+ irqtp->task = curtp->task;
+ irqtp->flags = 0;
+ call_handle_irq_event(irq, regs, action, irqtp);
+ irqtp->task = NULL;
+ if (irqtp->flags)
+ set_bits(irqtp->flags, &curtp->flags);
+ } else
+#endif
handle_irq_event(irq, regs, action);
spin_lock(&desc->lock);
@@ -682,4 +698,57 @@
irq_affinity[i] = DEFAULT_CPU_AFFINITY;
ppc_md.init_IRQ();
+ irq_ctx_init();
+}
+
+#ifdef CONFIG_IRQSTACKS
+struct thread_info *softirq_ctx[NR_CPUS];
+struct thread_info *hardirq_ctx[NR_CPUS];
+
+/* This was taken from arch/i386/kernel/irq.c. Maybe replace with kmalloc? */
+static char softirq_stack[NR_CPUS * THREAD_SIZE] __attribute__((__aligned__(THREAD_SIZE)));
+static char hardirq_stack[NR_CPUS * THREAD_SIZE] __attribute__((__aligned__(THREAD_SIZE)));
+
+void irq_ctx_init(void)
+{
+ struct thread_info *tp;
+ int i;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ softirq_ctx[i] = (struct thread_info *) &softirq_stack[i*THREAD_SIZE];
+ memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
+ tp = softirq_ctx[i];
+ tp->cpu = i;
+ tp->preempt_count = SOFTIRQ_OFFSET;
+
+ hardirq_ctx[i] = (struct thread_info *) &hardirq_stack[i*THREAD_SIZE];
+ memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
+ tp = hardirq_ctx[i];
+ tp->cpu = i;
+ tp->preempt_count = HARDIRQ_OFFSET;
+ }
}
+
+void do_softirq(void)
+{
+ unsigned long flags;
+ struct thread_info *curtp, *irqtp;
+
+ if (in_interrupt())
+ return;
+
+ local_irq_save(flags);
+
+ if (local_softirq_pending()) {
+ curtp = current_thread_info();
+ irqtp = softirq_ctx[smp_processor_id()];
+ irqtp->task = curtp->task;
+ call_do_softirq(irqtp);
+ irqtp->task = NULL;
+ }
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(do_softirq);
+
+#endif /* CONFIG_IRQSTACKS */
diff -Naur linux-2.6.9-rc2/arch/ppc/kernel/misc.S linux-2.6.9-rc2.jwb/arch/ppc/kernel/misc.S
--- linux-2.6.9-rc2/arch/ppc/kernel/misc.S 2004-09-13 17:00:26.000000000 -0500
+++ linux-2.6.9-rc2.jwb/arch/ppc/kernel/misc.S 2004-09-13 18:10:18.736792016 -0500
@@ -401,6 +401,30 @@
nop
_GLOBAL(local_irq_enable_end)
+#ifdef CONFIG_IRQSTACKS
+_GLOBAL(call_do_softirq)
+ mflr r0
+ stw r0,4(r1)
+ stwu r1,THREAD_SIZE-16(r3)
+ mr r1,r3
+ bl __do_softirq
+ lwz r1,0(r1)
+ lwz r0,4(r1)
+ mtlr r0
+ blr
+
+_GLOBAL(call_handle_irq_event)
+ mflr r0
+ stw r0,4(r1)
+ stwu r1,THREAD_SIZE-16(r6)
+ mr r1,r6
+ bl handle_irq_event
+ lwz r1,0(r1)
+ lwz r0,4(r1)
+ mtlr r0
+ blr
+#endif /* CONFIG_IRQSTACKS */
+
/*
* complement mask on the msr then "or" some values on.
* _nmask_and_or_msr(nmask, value_to_or)
diff -Naur linux-2.6.9-rc2/include/asm-ppc/bitops.h linux-2.6.9-rc2.jwb/include/asm-ppc/bitops.h
--- linux-2.6.9-rc2/include/asm-ppc/bitops.h 2004-08-14 00:36:58.000000000 -0500
+++ linux-2.6.9-rc2.jwb/include/asm-ppc/bitops.h 2004-09-13 18:10:18.000000000 -0500
@@ -23,6 +23,21 @@
#define SMP_MB
#endif /* CONFIG_SMP */
+static __inline__ void set_bits(unsigned long mask, unsigned long *addr)
+{
+ unsigned long old;
+
+ __asm__ __volatile__(
+ "1: lwarx %0,0,%3\n\
+ or %0,%0,%2 \n"
+ PPC405_ERR77(0,%3)
+ "stwcx. %0,0,%3\n\
+ bne- 1b"
+ : "=&r" (old), "=m" (*addr)
+ : "r" (mask), "r" (addr), "m" (*addr)
+ : "cc" );
+}
+
static __inline__ void set_bit(int nr, volatile unsigned long * addr)
{
unsigned long old;
diff -Naur linux-2.6.9-rc2/include/asm-ppc/irq.h linux-2.6.9-rc2.jwb/include/asm-ppc/irq.h
--- linux-2.6.9-rc2/include/asm-ppc/irq.h 2004-08-14 00:36:16.000000000 -0500
+++ linux-2.6.9-rc2.jwb/include/asm-ppc/irq.h 2004-09-13 18:10:18.000000000 -0500
@@ -3,6 +3,7 @@
#define _ASM_IRQ_H
#include <linux/config.h>
+#include <linux/threads.h> /* NR_CPUS */
#include <asm/machdep.h> /* ppc_md */
#include <asm/atomic.h>
@@ -326,5 +327,23 @@
struct pt_regs;
int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+#ifdef CONFIG_IRQSTACKS
+/*
+ * Per-cpu stacks for handling hard and soft interrupts.
+ */
+extern struct thread_info *hardirq_ctx[NR_CPUS];
+extern struct thread_info *softirq_ctx[NR_CPUS];
+
+extern void irq_ctx_init(void);
+extern void call_do_softirq(struct thread_info *tp);
+extern int call_handle_irq_event(int irq, struct pt_regs *regs,
+ struct irqaction *action, struct thread_info *tp);
+
+#define __ARCH_HAS_DO_SOFTIRQ
+
+#else
+#define irq_ctx_init()
+
+#endif /* CONFIG_IRQSTACKS */
#endif /* _ASM_IRQ_H */
#endif /* __KERNEL__ */
More information about the Linuxppc-dev
mailing list