diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/parisc/Kconfig | 8 | ||||
-rw-r--r-- | arch/parisc/include/asm/processor.h | 19 | ||||
-rw-r--r-- | arch/parisc/kernel/entry.S | 41 | ||||
-rw-r--r-- | arch/parisc/kernel/irq.c | 28 |
4 files changed, 94 insertions, 2 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index fe4afb0f152f..cad060f288cf 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig | |||
@@ -243,6 +243,14 @@ config SMP | |||
243 | 243 | ||
244 | If you don't know what to do here, say N. | 244 | If you don't know what to do here, say N. |
245 | 245 | ||
246 | config IRQSTACKS | ||
247 | bool "Use separate kernel stacks when processing interrupts" | ||
248 | default n | ||
249 | help | ||
250 | If you say Y here the kernel will use separate kernel stacks | ||
251 | for handling hard and soft interrupts. This can help avoid | ||
252 | overflowing the process kernel stacks. | ||
253 | |||
246 | config HOTPLUG_CPU | 254 | config HOTPLUG_CPU |
247 | bool | 255 | bool |
248 | default y if SMP | 256 | default y if SMP |
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h index 09b54a57a48d..242f06a5fbd8 100644 --- a/arch/parisc/include/asm/processor.h +++ b/arch/parisc/include/asm/processor.h | |||
@@ -20,8 +20,6 @@ | |||
20 | 20 | ||
21 | #endif /* __ASSEMBLY__ */ | 21 | #endif /* __ASSEMBLY__ */ |
22 | 22 | ||
23 | #define KERNEL_STACK_SIZE (4*PAGE_SIZE) | ||
24 | |||
25 | /* | 23 | /* |
26 | * Default implementation of macro that returns current | 24 | * Default implementation of macro that returns current |
27 | * instruction pointer ("program counter"). | 25 | * instruction pointer ("program counter"). |
@@ -61,6 +59,23 @@ | |||
61 | #ifndef __ASSEMBLY__ | 59 | #ifndef __ASSEMBLY__ |
62 | 60 | ||
63 | /* | 61 | /* |
62 | * IRQ STACK - used for irq handler | ||
63 | */ | ||
64 | #ifdef __KERNEL__ | ||
65 | |||
66 | #define IRQ_STACK_SIZE (4096 << 2) /* 16k irq stack size */ | ||
67 | |||
68 | union irq_stack_union { | ||
69 | unsigned long stack[IRQ_STACK_SIZE/sizeof(unsigned long)]; | ||
70 | }; | ||
71 | |||
72 | DECLARE_PER_CPU(union irq_stack_union, irq_stack_union); | ||
73 | |||
74 | void call_on_stack(unsigned long p1, void *func, unsigned long new_stack); | ||
75 | |||
76 | #endif /* __KERNEL__ */ | ||
77 | |||
78 | /* | ||
64 | * Data detected about CPUs at boot time which is the same for all CPU's. | 79 | * Data detected about CPUs at boot time which is the same for all CPU's. |
65 | * HP boxes are SMP - ie identical processors. | 80 | * HP boxes are SMP - ie identical processors. |
66 | * | 81 | * |
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 3f3326d876f7..4bb96ad9b0b1 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S | |||
@@ -2010,6 +2010,47 @@ ftrace_stub: | |||
2010 | ENDPROC(return_to_handler) | 2010 | ENDPROC(return_to_handler) |
2011 | #endif /* CONFIG_FUNCTION_TRACER */ | 2011 | #endif /* CONFIG_FUNCTION_TRACER */ |
2012 | 2012 | ||
2013 | #ifdef CONFIG_IRQSTACKS | ||
2014 | /* void call_on_stack(unsigned long param1, void *func, | ||
2015 | unsigned long new_stack) */ | ||
2016 | ENTRY(call_on_stack) | ||
2017 | copy %sp, %r1 | ||
2018 | |||
2019 | /* Regarding the HPPA calling conventions for function pointers, | ||
2020 | we assume the PIC register is not changed across call. For | ||
2021 | CONFIG_64BIT, the argument pointer is left to point at the | ||
2022 | argument region allocated for the call to call_on_stack. */ | ||
2023 | # ifdef CONFIG_64BIT | ||
2024 | /* Switch to new stack. We allocate two 128 byte frames. */ | ||
2025 | ldo 256(%arg2), %sp | ||
2026 | /* Save previous stack pointer and return pointer in frame marker */ | ||
2027 | STREG %rp, -144(%sp) | ||
2028 | /* Calls always use function descriptor */ | ||
2029 | LDREG 16(%arg1), %arg1 | ||
2030 | bve,l (%arg1), %rp | ||
2031 | STREG %r1, -136(%sp) | ||
2032 | LDREG -144(%sp), %rp | ||
2033 | bve (%rp) | ||
2034 | LDREG -136(%sp), %sp | ||
2035 | # else | ||
2036 | /* Switch to new stack. We allocate two 64 byte frames. */ | ||
2037 | ldo 128(%arg2), %sp | ||
2038 | /* Save previous stack pointer and return pointer in frame marker */ | ||
2039 | STREG %r1, -68(%sp) | ||
2040 | STREG %rp, -84(%sp) | ||
2041 | /* Calls use function descriptor if PLABEL bit is set */ | ||
2042 | bb,>=,n %arg1, 30, 1f | ||
2043 | depwi 0,31,2, %arg1 | ||
2044 | LDREG 0(%arg1), %arg1 | ||
2045 | 1: | ||
2046 | be,l 0(%sr4,%arg1), %sr0, %r31 | ||
2047 | copy %r31, %rp | ||
2048 | LDREG -84(%sp), %rp | ||
2049 | bv (%rp) | ||
2050 | LDREG -68(%sp), %sp | ||
2051 | # endif /* CONFIG_64BIT */ | ||
2052 | ENDPROC(call_on_stack) | ||
2053 | #endif /* CONFIG_IRQSTACKS */ | ||
2013 | 2054 | ||
2014 | get_register: | 2055 | get_register: |
2015 | /* | 2056 | /* |
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 61e51ac85659..810f9cf89e48 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c | |||
@@ -358,6 +358,29 @@ static inline void stack_overflow_check(struct pt_regs *regs) | |||
358 | #endif | 358 | #endif |
359 | } | 359 | } |
360 | 360 | ||
361 | #ifdef CONFIG_IRQSTACKS | ||
362 | DEFINE_PER_CPU(union irq_stack_union, irq_stack_union); | ||
363 | |||
364 | static void execute_on_irq_stack(void *func, unsigned long param1) | ||
365 | { | ||
366 | unsigned long *irq_stack_start; | ||
367 | unsigned long irq_stack; | ||
368 | int cpu = smp_processor_id(); | ||
369 | |||
370 | irq_stack_start = &per_cpu(irq_stack_union, cpu).stack[0]; | ||
371 | irq_stack = (unsigned long) irq_stack_start; | ||
372 | irq_stack = ALIGN(irq_stack, 16); /* align for stack frame usage */ | ||
373 | |||
374 | BUG_ON(*irq_stack_start); /* report bug if we were called recursive. */ | ||
375 | *irq_stack_start = 1; | ||
376 | |||
377 | /* This is where we switch to the IRQ stack. */ | ||
378 | call_on_stack(param1, func, irq_stack); | ||
379 | |||
380 | *irq_stack_start = 0; | ||
381 | } | ||
382 | #endif /* CONFIG_IRQSTACKS */ | ||
383 | |||
361 | /* ONLY called from entry.S:intr_extint() */ | 384 | /* ONLY called from entry.S:intr_extint() */ |
362 | void do_cpu_irq_mask(struct pt_regs *regs) | 385 | void do_cpu_irq_mask(struct pt_regs *regs) |
363 | { | 386 | { |
@@ -393,7 +416,12 @@ void do_cpu_irq_mask(struct pt_regs *regs) | |||
393 | } | 416 | } |
394 | #endif | 417 | #endif |
395 | stack_overflow_check(regs); | 418 | stack_overflow_check(regs); |
419 | |||
420 | #ifdef CONFIG_IRQSTACKS | ||
421 | execute_on_irq_stack(&generic_handle_irq, irq); | ||
422 | #else | ||
396 | generic_handle_irq(irq); | 423 | generic_handle_irq(irq); |
424 | #endif /* CONFIG_IRQSTACKS */ | ||
397 | 425 | ||
398 | out: | 426 | out: |
399 | irq_exit(); | 427 | irq_exit(); |