1/* 2 * File: arch/blackfin/kernel/irqchip.c 3 * Based on: 4 * Author: 5 * 6 * Created: 7 * Description: This file contains the simple DMA Implementation for Blackfin 8 * 9 * Modified: 10 * Copyright 2004-2006 Analog Devices Inc. 11 * 12 * Bugs: Enter bugs at http://blackfin.uclinux.org/ 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2 of the License, or 17 * (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, see the file COPYING, or write 26 * to the Free Software Foundation, Inc., 27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 28 */ 29 30#include <linux/kernel_stat.h> 31#include <linux/module.h> 32#include <linux/random.h> 33#include <linux/seq_file.h> 34#include <linux/kallsyms.h> 35#include <linux/interrupt.h> 36#include <linux/irq.h> 37 38static unsigned long irq_err_count; 39static spinlock_t irq_controller_lock; 40 41/* 42 * Dummy mask/unmask handler 43 */ 44void dummy_mask_unmask_irq(unsigned int irq) 45{ 46} 47 48void ack_bad_irq(unsigned int irq) 49{ 50 irq_err_count += 1; 51 printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); 52} 53EXPORT_SYMBOL(ack_bad_irq); 54 55static struct irq_chip bad_chip = { 56 .ack = dummy_mask_unmask_irq, 57 .mask = dummy_mask_unmask_irq, 58 .unmask = dummy_mask_unmask_irq, 59}; 60 61static struct irq_desc bad_irq_desc = { 62 .chip = &bad_chip, 63 .handle_irq = handle_bad_irq, 64 .depth = 1, 65}; 66 67int show_interrupts(struct seq_file *p, void *v) 68{ 69 int i = *(loff_t *) v; 70 struct irqaction *action; 71 unsigned long flags; 72 73 if (i < NR_IRQS) { 74 spin_lock_irqsave(&irq_desc[i].lock, flags); 75 action = irq_desc[i].action; 76 if (!action) 77 goto unlock; 78 79 seq_printf(p, "%3d: %10u ", i, kstat_irqs(i)); 80 seq_printf(p, " %s", action->name); 81 for (action = action->next; action; action = action->next) 82 seq_printf(p, ", %s", action->name); 83 84 seq_putc(p, '\n'); 85 unlock: 86 spin_unlock_irqrestore(&irq_desc[i].lock, flags); 87 } else if (i == NR_IRQS) { 88 seq_printf(p, "Err: %10lu\n", irq_err_count); 89 } 90 return 0; 91} 92 93/* 94 * do_IRQ handles all hardware IRQs. Decoded IRQs should not 95 * come via this function. Instead, they should provide their 96 * own 'handler' 97 */ 98 99#ifdef CONFIG_DO_IRQ_L1 100asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)__attribute__((l1_text)); 101#endif 102 103asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) 104{ 105 struct pt_regs *old_regs; 106 struct irq_desc *desc = irq_desc + irq; 107 unsigned short pending, other_ints; 108 109 old_regs = set_irq_regs(regs); 110 111 /* 112 * Some hardware gives randomly wrong interrupts. Rather 113 * than crashing, do something sensible. 114 */ 115 if (irq >= NR_IRQS) 116 desc = &bad_irq_desc; 117 118 irq_enter(); 119 120 generic_handle_irq(irq); 121 122 /* If we're the only interrupt running (ignoring IRQ15 which is for 123 syscalls), lower our priority to IRQ14 so that softirqs run at 124 that level. If there's another, lower-level interrupt, irq_exit 125 will defer softirqs to that. */ 126 CSYNC(); 127 pending = bfin_read_IPEND() & ~0x8000; 128 other_ints = pending & (pending - 1); 129 if (other_ints == 0) 130 lower_to_irq14(); 131 irq_exit(); 132 133 set_irq_regs(old_regs); 134} 135 136void __init init_IRQ(void) 137{ 138 struct irq_desc *desc; 139 int irq; 140 141 spin_lock_init(&irq_controller_lock); 142 for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) { 143 *desc = bad_irq_desc; 144 } 145 146 init_arch_irq(); 147} 148