Skip to content

Commit

Permalink
parisc: fix irq stack on UP and SMP
Browse files Browse the repository at this point in the history
The logic to detect if the irq stack was already in use with
raw_spin_trylock() is wrong, because it will generate a "trylock failure
on UP" error message with CONFIG_SMP=n and CONFIG_DEBUG_SPINLOCK=y.

arch_spin_trylock() can't be used either since in the CONFIG_SMP=n case
no atomic protection is given and we are reentrant here. A mutex didn't
worked either and brings more overhead by turning off interrupts.

So, let's use the fastest path for parisc which is the ldcw instruction.

Counting how often the irq stack was used is pretty useless, so just
drop this piece of code.

Signed-off-by: Helge Deller <deller@gmx.de>
  • Loading branch information
Helge Deller committed May 24, 2013
1 parent 2c2d32b commit d96b51e
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 41 deletions.
5 changes: 0 additions & 5 deletions arch/parisc/include/asm/hardirq.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,8 @@

typedef struct {
unsigned int __softirq_pending;
#ifdef CONFIG_DEBUG_STACKOVERFLOW
unsigned int kernel_stack_usage;
#ifdef CONFIG_IRQSTACKS
unsigned int irq_stack_usage;
unsigned int irq_stack_counter;
#endif
#endif
#ifdef CONFIG_SMP
unsigned int irq_resched_count;
unsigned int irq_call_count;
Expand Down
21 changes: 0 additions & 21 deletions arch/parisc/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include <asm/ptrace.h>
#include <asm/types.h>
#include <asm/percpu.h>

#endif /* __ASSEMBLY__ */

/*
Expand Down Expand Up @@ -58,26 +57,6 @@

#ifndef __ASSEMBLY__

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

#include <linux/spinlock_types.h>

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

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

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: 26 additions & 15 deletions arch/parisc/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm/io.h>

#include <asm/smp.h>
#include <asm/ldcw.h>

#undef PARISC_IRQ_CR16_COUNTS

Expand Down Expand Up @@ -172,10 +172,6 @@ int arch_show_interrupts(struct seq_file *p, int prec)
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->irq_stack_usage);
seq_puts(p, " Interrupt stack usage\n");
seq_printf(p, "%*s: ", prec, "ISC");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->irq_stack_counter);
seq_puts(p, " Interrupt stack usage counter\n");
# endif
#endif
#ifdef CONFIG_SMP
Expand Down Expand Up @@ -384,6 +380,24 @@ static inline int eirr_to_irq(unsigned long eirr)
return (BITS_PER_LONG - bit) + TIMER_IRQ;
}

#ifdef CONFIG_IRQSTACKS
/*
* IRQ STACK - used for irq handler
*/
#define IRQ_STACK_SIZE (4096 << 2) /* 16k irq stack size */

union irq_stack_union {
unsigned long stack[IRQ_STACK_SIZE/sizeof(unsigned long)];
volatile unsigned int slock[4];
volatile unsigned int lock[1];
};

DEFINE_PER_CPU(union irq_stack_union, irq_stack_union) = {
.slock = { 1,1,1,1 },
};
#endif


int sysctl_panic_on_stackoverflow = 1;

static inline void stack_overflow_check(struct pt_regs *regs)
Expand Down Expand Up @@ -450,27 +464,26 @@ static inline void stack_overflow_check(struct pt_regs *regs)
}

#ifdef CONFIG_IRQSTACKS
DEFINE_PER_CPU(union irq_stack_union, irq_stack_union) = {
.lock = __RAW_SPIN_LOCK_UNLOCKED((irq_stack_union).lock)
};
/* in entry.S: */
void call_on_stack(unsigned long p1, void *func, unsigned long new_stack);

static void execute_on_irq_stack(void *func, unsigned long param1)
{
union irq_stack_union *union_ptr;
unsigned long irq_stack;
raw_spinlock_t *irq_stack_in_use;
volatile unsigned int *irq_stack_in_use;

union_ptr = &per_cpu(irq_stack_union, smp_processor_id());
irq_stack = (unsigned long) &union_ptr->stack;
irq_stack = ALIGN(irq_stack + sizeof(irq_stack_union.lock),
irq_stack = ALIGN(irq_stack + sizeof(irq_stack_union.slock),
64); /* align for stack frame usage */

/* We may be called recursive. If we are already using the irq stack,
* just continue to use it. Use spinlocks to serialize
* the irq stack usage.
*/
irq_stack_in_use = &union_ptr->lock;
if (!raw_spin_trylock(irq_stack_in_use)) {
irq_stack_in_use = (volatile unsigned int *)__ldcw_align(union_ptr);
if (!__ldcw(irq_stack_in_use)) {
void (*direct_call)(unsigned long p1) = func;

/* We are using the IRQ stack already.
Expand All @@ -482,10 +495,8 @@ static void execute_on_irq_stack(void *func, unsigned long param1)
/* This is where we switch to the IRQ stack. */
call_on_stack(param1, func, irq_stack);

__inc_irq_stat(irq_stack_counter);

/* free up irq stack usage. */
do_raw_spin_unlock(irq_stack_in_use);
*irq_stack_in_use = 1;
}

asmlinkage void do_softirq(void)
Expand Down

0 comments on commit d96b51e

Please sign in to comment.