From: David Miller <davem@xxxxxxxxxxxxx> Date: Fri, 20 Jun 2008 14:41:28 -0700 (PDT) > Next week I'll make one of my primary projects the implementation of > IRQ stacks for sparc64. Next week came real fast :-) Amazingly this patch worked the first time I booted it up on my dual-cpu workstation (using SMP + PREEMPT). I'm worried that maybe gcc can do some clever things and not allow my extremely simple approach to work, but anyways it might work for you and it's worth giving a try. sparc64: Implement support for IRQ stacks. Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx> diff --git a/arch/sparc64/Kconfig.debug b/arch/sparc64/Kconfig.debug index 6a4d28a..df80962 100644 --- a/arch/sparc64/Kconfig.debug +++ b/arch/sparc64/Kconfig.debug @@ -41,4 +41,11 @@ config FRAME_POINTER depends on MCOUNT 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 --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index b441a26..24820fa 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -674,10 +674,42 @@ void ack_bad_irq(unsigned int virt_irq) ino, virt_irq); } +#ifdef CONFIG_IRQSTACKS +void *hardirq_stack[NR_CPUS]; +void *softirq_stack[NR_CPUS]; + +static void *set_hardirq_stack(void) +{ + void *orig_sp, *sp = hardirq_stack[smp_processor_id()]; + + __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp)); + if (orig_sp < sp || + orig_sp > (sp + THREAD_SIZE)) { + sp += THREAD_SIZE - 192 - STACK_BIAS; + __asm__ __volatile__("mov %0, %%sp" : : "r" (sp)); + } + + return orig_sp; +} +static void restore_hardirq_stack(void *orig_sp) +{ + __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp)); +} +#else +static void *set_hardirq_stack(void) +{ + return NULL; +} +static void restore_hardirq_stack(void *orig_sp) +{ +} +#endif + void handler_irq(int irq, struct pt_regs *regs) { unsigned long pstate, bucket_pa; struct pt_regs *old_regs; + void *orig_sp; clear_softint(1 << irq); @@ -695,6 +727,8 @@ void handler_irq(int irq, struct pt_regs *regs) "i" (PSTATE_IE) : "memory"); + orig_sp = set_hardirq_stack(); + while (bucket_pa) { struct irq_desc *desc; unsigned long next_pa; @@ -711,10 +745,40 @@ void handler_irq(int irq, struct pt_regs *regs) bucket_pa = next_pa; } + restore_hardirq_stack(orig_sp); + irq_exit(); set_irq_regs(old_regs); } +#ifdef CONFIG_IRQSTACKS +void do_softirq(void) +{ + unsigned long flags; + + if (in_interrupt()) + return; + + local_irq_save(flags); + + if (local_softirq_pending()) { + void *orig_sp, *sp = softirq_stack[smp_processor_id()]; + + sp += THREAD_SIZE - 192 - STACK_BIAS; + + __asm__ __volatile__("mov %%sp, %0\n\t" + "mov %1, %%sp" + : "=&r" (orig_sp) + : "r" (sp)); + __do_softirq(); + __asm__ __volatile__("mov %0, %%sp" + : : "r" (orig_sp)); + } + + local_irq_restore(flags); +} +#endif + #ifdef CONFIG_HOTPLUG_CPU void fixup_irqs(void) { diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 84898c4..56e22f4 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -49,6 +49,7 @@ #include <asm/sstate.h> #include <asm/mdesc.h> #include <asm/cpudata.h> +#include <asm/irq.h> #define MAX_PHYS_ADDRESS (1UL << 42UL) #define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL) @@ -1817,6 +1818,18 @@ void __init paging_init(void) if (tlb_type == hypervisor) sun4v_mdesc_init(); +#ifdef CONFIG_IRQSTACKS + /* Once the OF device tree and MDESC have been setup, we know + * the list of possible cpus. Therefore we can allocate the + * IRQ stacks. + */ + for_each_possible_cpu(i) { + /* XXX Use node local allocations... XXX */ + softirq_stack[i] = __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE)); + hardirq_stack[i] = __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE)); + } +#endif + /* Setup bootmem... */ last_valid_pfn = end_pfn = bootmem_init(phys_base); diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index 0bb9bf5..d71b5ff 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -90,4 +90,10 @@ static inline unsigned long get_softint(void) return retval; } +#ifdef CONFIG_IRQSTACKS +extern void *hardirq_stack[NR_CPUS]; +extern void *softirq_stack[NR_CPUS]; +#define __ARCH_HAS_DO_SOFTIRQ +#endif + #endif -- To unsubscribe from this list: send the line "unsubscribe sparclinux" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html