Skip to content

Commit

Permalink
parisc: implement irq stacks
Browse files Browse the repository at this point in the history
Default kernel stack size on parisc is 16k.  During tests we found that the
kernel stack can easily grow beyond 13k, which leaves 3k left for irq
processing.

This patch adds the possibility to activate an additional stack of 16k per CPU
which is being used during irq processing.  This implementation does not yet
uses this irq stack for the irq bh handler.

The assembler code for call_on_stack was heavily cleaned up by John
David Anglin.

CC: John David Anglin <[email protected]>
Signed-off-by: Helge Deller <[email protected]>
  • Loading branch information
hdeller committed May 7, 2013
1 parent 9372450 commit 200c880
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 2 deletions.
8 changes: 8 additions & 0 deletions arch/parisc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,14 @@ config SMP

If you don't know what to do here, say N.

config IRQSTACKS
bool "Use separate kernel stacks when processing interrupts"
default n
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.

config HOTPLUG_CPU
bool
default y if SMP
Expand Down
19 changes: 17 additions & 2 deletions arch/parisc/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@

#endif /* __ASSEMBLY__ */

#define KERNEL_STACK_SIZE (4*PAGE_SIZE)

/*
* Default implementation of macro that returns current
* instruction pointer ("program counter").
Expand Down Expand Up @@ -60,6 +58,23 @@

#ifndef __ASSEMBLY__

/*
* IRQ STACK - used for irq handler
*/
#ifdef __KERNEL__

#define IRQ_STACK_SIZE (4096 << 2) /* 16k irq stack size */

union irq_stack_union {
unsigned long stack[IRQ_STACK_SIZE/sizeof(unsigned long)];
};

DECLARE_PER_CPU(union irq_stack_union, irq_stack_union);

void call_on_stack(unsigned long p1, void *func, unsigned long new_stack);

#endif /* __KERNEL__ */

/*
* Data detected about CPUs at boot time which is the same for all CPU's.
* HP boxes are SMP - ie identical processors.
Expand Down
41 changes: 41 additions & 0 deletions arch/parisc/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -2010,6 +2010,47 @@ ftrace_stub:
ENDPROC(return_to_handler)
#endif /* CONFIG_FUNCTION_TRACER */

#ifdef CONFIG_IRQSTACKS
/* void call_on_stack(unsigned long param1, void *func,
unsigned long new_stack) */
ENTRY(call_on_stack)
copy %sp, %r1

/* Regarding the HPPA calling conventions for function pointers,
we assume the PIC register is not changed across call. For
CONFIG_64BIT, the argument pointer is left to point at the
argument region allocated for the call to call_on_stack. */
# ifdef CONFIG_64BIT
/* Switch to new stack. We allocate two 128 byte frames. */
ldo 256(%arg2), %sp
/* Save previous stack pointer and return pointer in frame marker */
STREG %rp, -144(%sp)
/* Calls always use function descriptor */
LDREG 16(%arg1), %arg1
bve,l (%arg1), %rp
STREG %r1, -136(%sp)
LDREG -144(%sp), %rp
bve (%rp)
LDREG -136(%sp), %sp
# else
/* Switch to new stack. We allocate two 64 byte frames. */
ldo 128(%arg2), %sp
/* Save previous stack pointer and return pointer in frame marker */
STREG %r1, -68(%sp)
STREG %rp, -84(%sp)
/* Calls use function descriptor if PLABEL bit is set */
bb,>=,n %arg1, 30, 1f
depwi 0,31,2, %arg1
LDREG 0(%arg1), %arg1
1:
be,l 0(%sr4,%arg1), %sr0, %r31
copy %r31, %rp
LDREG -84(%sp), %rp
bv (%rp)
LDREG -68(%sp), %sp
# endif /* CONFIG_64BIT */
ENDPROC(call_on_stack)
#endif /* CONFIG_IRQSTACKS */

get_register:
/*
Expand Down
28 changes: 28 additions & 0 deletions arch/parisc/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,29 @@ static inline void stack_overflow_check(struct pt_regs *regs)
#endif
}

#ifdef CONFIG_IRQSTACKS
DEFINE_PER_CPU(union irq_stack_union, irq_stack_union);

static void execute_on_irq_stack(void *func, unsigned long param1)
{
unsigned long *irq_stack_start;
unsigned long irq_stack;
int cpu = smp_processor_id();

irq_stack_start = &per_cpu(irq_stack_union, cpu).stack[0];
irq_stack = (unsigned long) irq_stack_start;
irq_stack = ALIGN(irq_stack, 16); /* align for stack frame usage */

BUG_ON(*irq_stack_start); /* report bug if we were called recursive. */
*irq_stack_start = 1;

/* This is where we switch to the IRQ stack. */
call_on_stack(param1, func, irq_stack);

*irq_stack_start = 0;
}
#endif /* CONFIG_IRQSTACKS */

/* ONLY called from entry.S:intr_extint() */
void do_cpu_irq_mask(struct pt_regs *regs)
{
Expand Down Expand Up @@ -393,7 +416,12 @@ void do_cpu_irq_mask(struct pt_regs *regs)
}
#endif
stack_overflow_check(regs);

#ifdef CONFIG_IRQSTACKS
execute_on_irq_stack(&generic_handle_irq, irq);
#else
generic_handle_irq(irq);
#endif /* CONFIG_IRQSTACKS */

out:
irq_exit();
Expand Down

0 comments on commit 200c880

Please sign in to comment.