aboutsummaryrefslogtreecommitdiffstats
path: root/arch/parisc/kernel/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/parisc/kernel/irq.c')
-rw-r--r--arch/parisc/kernel/irq.c122
1 files changed, 107 insertions, 15 deletions
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index e255db0bb761..2e6443b1e922 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -27,11 +27,11 @@
27#include <linux/interrupt.h> 27#include <linux/interrupt.h>
28#include <linux/kernel_stat.h> 28#include <linux/kernel_stat.h>
29#include <linux/seq_file.h> 29#include <linux/seq_file.h>
30#include <linux/spinlock.h>
31#include <linux/types.h> 30#include <linux/types.h>
32#include <asm/io.h> 31#include <asm/io.h>
33 32
34#include <asm/smp.h> 33#include <asm/smp.h>
34#include <asm/ldcw.h>
35 35
36#undef PARISC_IRQ_CR16_COUNTS 36#undef PARISC_IRQ_CR16_COUNTS
37 37
@@ -166,22 +166,36 @@ int arch_show_interrupts(struct seq_file *p, int prec)
166 seq_printf(p, "%*s: ", prec, "STK"); 166 seq_printf(p, "%*s: ", prec, "STK");
167 for_each_online_cpu(j) 167 for_each_online_cpu(j)
168 seq_printf(p, "%10u ", irq_stats(j)->kernel_stack_usage); 168 seq_printf(p, "%10u ", irq_stats(j)->kernel_stack_usage);
169 seq_printf(p, " Kernel stack usage\n"); 169 seq_puts(p, " Kernel stack usage\n");
170# ifdef CONFIG_IRQSTACKS
171 seq_printf(p, "%*s: ", prec, "IST");
172 for_each_online_cpu(j)
173 seq_printf(p, "%10u ", irq_stats(j)->irq_stack_usage);
174 seq_puts(p, " Interrupt stack usage\n");
175# endif
170#endif 176#endif
171#ifdef CONFIG_SMP 177#ifdef CONFIG_SMP
172 seq_printf(p, "%*s: ", prec, "RES"); 178 seq_printf(p, "%*s: ", prec, "RES");
173 for_each_online_cpu(j) 179 for_each_online_cpu(j)
174 seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count); 180 seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count);
175 seq_printf(p, " Rescheduling interrupts\n"); 181 seq_puts(p, " Rescheduling interrupts\n");
176 seq_printf(p, "%*s: ", prec, "CAL"); 182 seq_printf(p, "%*s: ", prec, "CAL");
177 for_each_online_cpu(j) 183 for_each_online_cpu(j)
178 seq_printf(p, "%10u ", irq_stats(j)->irq_call_count); 184 seq_printf(p, "%10u ", irq_stats(j)->irq_call_count);
179 seq_printf(p, " Function call interrupts\n"); 185 seq_puts(p, " Function call interrupts\n");
180#endif 186#endif
187 seq_printf(p, "%*s: ", prec, "UAH");
188 for_each_online_cpu(j)
189 seq_printf(p, "%10u ", irq_stats(j)->irq_unaligned_count);
190 seq_puts(p, " Unaligned access handler traps\n");
191 seq_printf(p, "%*s: ", prec, "FPA");
192 for_each_online_cpu(j)
193 seq_printf(p, "%10u ", irq_stats(j)->irq_fpassist_count);
194 seq_puts(p, " Floating point assist traps\n");
181 seq_printf(p, "%*s: ", prec, "TLB"); 195 seq_printf(p, "%*s: ", prec, "TLB");
182 for_each_online_cpu(j) 196 for_each_online_cpu(j)
183 seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count); 197 seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count);
184 seq_printf(p, " TLB shootdowns\n"); 198 seq_puts(p, " TLB shootdowns\n");
185 return 0; 199 return 0;
186} 200}
187 201
@@ -366,6 +380,24 @@ static inline int eirr_to_irq(unsigned long eirr)
366 return (BITS_PER_LONG - bit) + TIMER_IRQ; 380 return (BITS_PER_LONG - bit) + TIMER_IRQ;
367} 381}
368 382
383#ifdef CONFIG_IRQSTACKS
384/*
385 * IRQ STACK - used for irq handler
386 */
387#define IRQ_STACK_SIZE (4096 << 2) /* 16k irq stack size */
388
389union irq_stack_union {
390 unsigned long stack[IRQ_STACK_SIZE/sizeof(unsigned long)];
391 volatile unsigned int slock[4];
392 volatile unsigned int lock[1];
393};
394
395DEFINE_PER_CPU(union irq_stack_union, irq_stack_union) = {
396 .slock = { 1,1,1,1 },
397 };
398#endif
399
400
369int sysctl_panic_on_stackoverflow = 1; 401int sysctl_panic_on_stackoverflow = 1;
370 402
371static inline void stack_overflow_check(struct pt_regs *regs) 403static inline void stack_overflow_check(struct pt_regs *regs)
@@ -378,6 +410,7 @@ static inline void stack_overflow_check(struct pt_regs *regs)
378 unsigned long sp = regs->gr[30]; 410 unsigned long sp = regs->gr[30];
379 unsigned long stack_usage; 411 unsigned long stack_usage;
380 unsigned int *last_usage; 412 unsigned int *last_usage;
413 int cpu = smp_processor_id();
381 414
382 /* if sr7 != 0, we interrupted a userspace process which we do not want 415 /* if sr7 != 0, we interrupted a userspace process which we do not want
383 * to check for stack overflow. We will only check the kernel stack. */ 416 * to check for stack overflow. We will only check the kernel stack. */
@@ -386,7 +419,31 @@ static inline void stack_overflow_check(struct pt_regs *regs)
386 419
387 /* calculate kernel stack usage */ 420 /* calculate kernel stack usage */
388 stack_usage = sp - stack_start; 421 stack_usage = sp - stack_start;
389 last_usage = &per_cpu(irq_stat.kernel_stack_usage, smp_processor_id()); 422#ifdef CONFIG_IRQSTACKS
423 if (likely(stack_usage <= THREAD_SIZE))
424 goto check_kernel_stack; /* found kernel stack */
425
426 /* check irq stack usage */
427 stack_start = (unsigned long) &per_cpu(irq_stack_union, cpu).stack;
428 stack_usage = sp - stack_start;
429
430 last_usage = &per_cpu(irq_stat.irq_stack_usage, cpu);
431 if (unlikely(stack_usage > *last_usage))
432 *last_usage = stack_usage;
433
434 if (likely(stack_usage < (IRQ_STACK_SIZE - STACK_MARGIN)))
435 return;
436
437 pr_emerg("stackcheck: %s will most likely overflow irq stack "
438 "(sp:%lx, stk bottom-top:%lx-%lx)\n",
439 current->comm, sp, stack_start, stack_start + IRQ_STACK_SIZE);
440 goto panic_check;
441
442check_kernel_stack:
443#endif
444
445 /* check kernel stack usage */
446 last_usage = &per_cpu(irq_stat.kernel_stack_usage, cpu);
390 447
391 if (unlikely(stack_usage > *last_usage)) 448 if (unlikely(stack_usage > *last_usage))
392 *last_usage = stack_usage; 449 *last_usage = stack_usage;
@@ -398,31 +455,66 @@ static inline void stack_overflow_check(struct pt_regs *regs)
398 "(sp:%lx, stk bottom-top:%lx-%lx)\n", 455 "(sp:%lx, stk bottom-top:%lx-%lx)\n",
399 current->comm, sp, stack_start, stack_start + THREAD_SIZE); 456 current->comm, sp, stack_start, stack_start + THREAD_SIZE);
400 457
458#ifdef CONFIG_IRQSTACKS
459panic_check:
460#endif
401 if (sysctl_panic_on_stackoverflow) 461 if (sysctl_panic_on_stackoverflow)
402 panic("low stack detected by irq handler - check messages\n"); 462 panic("low stack detected by irq handler - check messages\n");
403#endif 463#endif
404} 464}
405 465
406#ifdef CONFIG_IRQSTACKS 466#ifdef CONFIG_IRQSTACKS
407DEFINE_PER_CPU(union irq_stack_union, irq_stack_union); 467/* in entry.S: */
468void call_on_stack(unsigned long p1, void *func, unsigned long new_stack);
408 469
409static void execute_on_irq_stack(void *func, unsigned long param1) 470static void execute_on_irq_stack(void *func, unsigned long param1)
410{ 471{
411 unsigned long *irq_stack_start; 472 union irq_stack_union *union_ptr;
412 unsigned long irq_stack; 473 unsigned long irq_stack;
413 int cpu = smp_processor_id(); 474 volatile unsigned int *irq_stack_in_use;
475
476 union_ptr = &per_cpu(irq_stack_union, smp_processor_id());
477 irq_stack = (unsigned long) &union_ptr->stack;
478 irq_stack = ALIGN(irq_stack + sizeof(irq_stack_union.slock),
479 64); /* align for stack frame usage */
414 480
415 irq_stack_start = &per_cpu(irq_stack_union, cpu).stack[0]; 481 /* We may be called recursive. If we are already using the irq stack,
416 irq_stack = (unsigned long) irq_stack_start; 482 * just continue to use it. Use spinlocks to serialize
417 irq_stack = ALIGN(irq_stack, 16); /* align for stack frame usage */ 483 * the irq stack usage.
484 */
485 irq_stack_in_use = (volatile unsigned int *)__ldcw_align(union_ptr);
486 if (!__ldcw(irq_stack_in_use)) {
487 void (*direct_call)(unsigned long p1) = func;
418 488
419 BUG_ON(*irq_stack_start); /* report bug if we were called recursive. */ 489 /* We are using the IRQ stack already.
420 *irq_stack_start = 1; 490 * Do direct call on current stack. */
491 direct_call(param1);
492 return;
493 }
421 494
422 /* This is where we switch to the IRQ stack. */ 495 /* This is where we switch to the IRQ stack. */
423 call_on_stack(param1, func, irq_stack); 496 call_on_stack(param1, func, irq_stack);
424 497
425 *irq_stack_start = 0; 498 /* free up irq stack usage. */
499 *irq_stack_in_use = 1;
500}
501
502asmlinkage void do_softirq(void)
503{
504 __u32 pending;
505 unsigned long flags;
506
507 if (in_interrupt())
508 return;
509
510 local_irq_save(flags);
511
512 pending = local_softirq_pending();
513
514 if (pending)
515 execute_on_irq_stack(__do_softirq, 0);
516
517 local_irq_restore(flags);
426} 518}
427#endif /* CONFIG_IRQSTACKS */ 519#endif /* CONFIG_IRQSTACKS */
428 520