1 /* 2 * linux/arch/xtensa/kernel/irq.c 3 * 4 * Xtensa built-in interrupt controller and some generic functions copied 5 * from i386. 6 * 7 * Copyright (C) 2002 - 2006 Tensilica, Inc. 8 * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar 9 * 10 * 11 * Chris Zankel <chris@zankel.net> 12 * Kevin Chea 13 * 14 */ 15 16 #include <linux/module.h> 17 #include <linux/seq_file.h> 18 #include <linux/interrupt.h> 19 #include <linux/irq.h> 20 #include <linux/kernel_stat.h> 21 22 #include <asm/uaccess.h> 23 #include <asm/platform.h> 24 25 static unsigned int cached_irq_mask; 26 27 atomic_t irq_err_count; 28 29 /* 30 * 'what should we do if we get a hw irq event on an illegal vector'. 31 * each architecture has to answer this themselves. 32 */ 33 void ack_bad_irq(unsigned int irq) 34 { 35 printk("unexpected IRQ trap at vector %02x\n", irq); 36 } 37 38 /* 39 * do_IRQ handles all normal device IRQ's (the special 40 * SMP cross-CPU interrupts have their own specific 41 * handlers). 42 */ 43 44 asmlinkage void do_IRQ(int irq, struct pt_regs *regs) 45 { 46 struct pt_regs *old_regs = set_irq_regs(regs); 47 struct irq_desc *desc = irq_desc + irq; 48 49 if (irq >= NR_IRQS) { 50 printk(KERN_EMERG "%s: cannot handle IRQ %d\n", 51 __func__, irq); 52 } 53 54 irq_enter(); 55 56 #ifdef CONFIG_DEBUG_STACKOVERFLOW 57 /* Debugging check for stack overflow: is there less than 1KB free? */ 58 { 59 unsigned long sp; 60 61 __asm__ __volatile__ ("mov %0, a1\n" : "=a" (sp)); 62 sp &= THREAD_SIZE - 1; 63 64 if (unlikely(sp < (sizeof(thread_info) + 1024))) 65 printk("Stack overflow in do_IRQ: %ld\n", 66 sp - sizeof(struct thread_info)); 67 } 68 #endif 69 desc->handle_irq(irq, desc); 70 71 irq_exit(); 72 set_irq_regs(old_regs); 73 } 74 75 /* 76 * Generic, controller-independent functions: 77 */ 78 79 int show_interrupts(struct seq_file *p, void *v) 80 { 81 int i = *(loff_t *) v, j; 82 struct irqaction * action; 83 unsigned long flags; 84 85 if (i == 0) { 86 seq_printf(p, " "); 87 for_each_online_cpu(j) 88 seq_printf(p, "CPU%d ",j); 89 seq_putc(p, '\n'); 90 } 91 92 if (i < NR_IRQS) { 93 raw_spin_lock_irqsave(&irq_desc[i].lock, flags); 94 action = irq_desc[i].action; 95 if (!action) 96 goto skip; 97 seq_printf(p, "%3d: ",i); 98 #ifndef CONFIG_SMP 99 seq_printf(p, "%10u ", kstat_irqs(i)); 100 #else 101 for_each_online_cpu(j) 102 seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); 103 #endif 104 seq_printf(p, " %14s", irq_desc[i].chip->typename); 105 seq_printf(p, " %s", action->name); 106 107 for (action=action->next; action; action = action->next) 108 seq_printf(p, ", %s", action->name); 109 110 seq_putc(p, '\n'); 111 skip: 112 raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); 113 } else if (i == NR_IRQS) { 114 seq_printf(p, "NMI: "); 115 for_each_online_cpu(j) 116 seq_printf(p, "%10u ", nmi_count(j)); 117 seq_putc(p, '\n'); 118 seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); 119 } 120 return 0; 121 } 122 123 static void xtensa_irq_mask(unsigned int irq) 124 { 125 cached_irq_mask &= ~(1 << irq); 126 set_sr (cached_irq_mask, INTENABLE); 127 } 128 129 static void xtensa_irq_unmask(unsigned int irq) 130 { 131 cached_irq_mask |= 1 << irq; 132 set_sr (cached_irq_mask, INTENABLE); 133 } 134 135 static void xtensa_irq_enable(unsigned int irq) 136 { 137 variant_irq_enable(irq); 138 xtensa_irq_unmask(irq); 139 } 140 141 static void xtensa_irq_disable(unsigned int irq) 142 { 143 xtensa_irq_mask(irq); 144 variant_irq_disable(irq); 145 } 146 147 static void xtensa_irq_ack(unsigned int irq) 148 { 149 set_sr(1 << irq, INTCLEAR); 150 } 151 152 static int xtensa_irq_retrigger(unsigned int irq) 153 { 154 set_sr (1 << irq, INTSET); 155 return 1; 156 } 157 158 159 static struct irq_chip xtensa_irq_chip = { 160 .name = "xtensa", 161 .enable = xtensa_irq_enable, 162 .disable = xtensa_irq_disable, 163 .mask = xtensa_irq_mask, 164 .unmask = xtensa_irq_unmask, 165 .ack = xtensa_irq_ack, 166 .retrigger = xtensa_irq_retrigger, 167 }; 168 169 void __init init_IRQ(void) 170 { 171 int index; 172 173 for (index = 0; index < XTENSA_NR_IRQS; index++) { 174 int mask = 1 << index; 175 176 if (mask & XCHAL_INTTYPE_MASK_SOFTWARE) 177 set_irq_chip_and_handler(index, &xtensa_irq_chip, 178 handle_simple_irq); 179 180 else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE) 181 set_irq_chip_and_handler(index, &xtensa_irq_chip, 182 handle_edge_irq); 183 184 else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL) 185 set_irq_chip_and_handler(index, &xtensa_irq_chip, 186 handle_level_irq); 187 188 else if (mask & XCHAL_INTTYPE_MASK_TIMER) 189 set_irq_chip_and_handler(index, &xtensa_irq_chip, 190 handle_edge_irq); 191 192 else /* XCHAL_INTTYPE_MASK_WRITE_ERROR */ 193 /* XCHAL_INTTYPE_MASK_NMI */ 194 195 set_irq_chip_and_handler(index, &xtensa_irq_chip, 196 handle_level_irq); 197 } 198 199 cached_irq_mask = 0; 200 201 variant_init_irq(); 202 } 203