1/* 2 * Copyright 2005-2009 Analog Devices Inc. 3 * 4 * Licensed under the GPL-2 or later 5 */ 6 7#include <linux/kernel_stat.h> 8#include <linux/module.h> 9#include <linux/random.h> 10#include <linux/seq_file.h> 11#include <linux/kallsyms.h> 12#include <linux/interrupt.h> 13#include <linux/irq.h> 14#include <linux/seq_file.h> 15#include <asm/irq_handler.h> 16#include <asm/trace.h> 17#include <asm/pda.h> 18 19static atomic_t irq_err_count; 20void ack_bad_irq(unsigned int irq) 21{ 22 atomic_inc(&irq_err_count); 23 printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); 24} 25 26static struct irq_desc bad_irq_desc = { 27 .handle_irq = handle_bad_irq, 28 .lock = __RAW_SPIN_LOCK_UNLOCKED(bad_irq_desc.lock), 29}; 30 31#ifdef CONFIG_CPUMASK_OFFSTACK 32/* We are not allocating a variable-sized bad_irq_desc.affinity */ 33#error "Blackfin architecture does not support CONFIG_CPUMASK_OFFSTACK." 34#endif 35 36#ifdef CONFIG_PROC_FS 37int arch_show_interrupts(struct seq_file *p, int prec) 38{ 39 int j; 40 41 seq_printf(p, "%*s: ", prec, "NMI"); 42 for_each_online_cpu(j) 43 seq_printf(p, "%10u ", cpu_pda[j].__nmi_count); 44 seq_printf(p, " CORE Non Maskable Interrupt\n"); 45 seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); 46 return 0; 47} 48#endif 49 50#ifdef CONFIG_DEBUG_STACKOVERFLOW 51static void check_stack_overflow(int irq) 52{ 53 /* Debugging check for stack overflow: is there less than STACK_WARN free? */ 54 long sp = __get_SP() & (THREAD_SIZE - 1); 55 56 if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) { 57 dump_stack(); 58 pr_emerg("irq%i: possible stack overflow only %ld bytes free\n", 59 irq, sp - sizeof(struct thread_info)); 60 } 61} 62#else 63static inline void check_stack_overflow(int irq) { } 64#endif 65 66#ifndef CONFIG_IPIPE 67static void maybe_lower_to_irq14(void) 68{ 69 unsigned short pending, other_ints; 70 71 /* 72 * If we're the only interrupt running (ignoring IRQ15 which 73 * is for syscalls), lower our priority to IRQ14 so that 74 * softirqs run at that level. If there's another, 75 * lower-level interrupt, irq_exit will defer softirqs to 76 * that. If the interrupt pipeline is enabled, we are already 77 * running at IRQ14 priority, so we don't need this code. 78 */ 79 CSYNC(); 80 pending = bfin_read_IPEND() & ~0x8000; 81 other_ints = pending & (pending - 1); 82 if (other_ints == 0) 83 lower_to_irq14(); 84} 85#else 86static inline void maybe_lower_to_irq14(void) { } 87#endif 88 89/* 90 * do_IRQ handles all hardware IRQs. Decoded IRQs should not 91 * come via this function. Instead, they should provide their 92 * own 'handler' 93 */ 94#ifdef CONFIG_DO_IRQ_L1 95__attribute__((l1_text)) 96#endif 97asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) 98{ 99 struct pt_regs *old_regs = set_irq_regs(regs); 100 101 irq_enter(); 102 103 check_stack_overflow(irq); 104 105 /* 106 * Some hardware gives randomly wrong interrupts. Rather 107 * than crashing, do something sensible. 108 */ 109 if (irq >= NR_IRQS) 110 handle_bad_irq(&bad_irq_desc); 111 else 112 generic_handle_irq(irq); 113 114 maybe_lower_to_irq14(); 115 116 irq_exit(); 117 118 set_irq_regs(old_regs); 119} 120 121void __init init_IRQ(void) 122{ 123 init_arch_irq(); 124 125#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND 126 /* Now that evt_ivhw is set up, turn this on */ 127 trace_buff_offset = 0; 128 bfin_write_TBUFCTL(BFIN_TRACE_ON); 129 printk(KERN_INFO "Hardware Trace expanded to %ik\n", 130 1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN); 131#endif 132} 133