1 /* 2 * (C) Copyright 2009 3 * Graeme Russ, <graeme.russ@gmail.com> 4 * 5 * (C) Copyright 2007 6 * Daniel Hellstrom, Gaisler Research, <daniel@gaisler.com> 7 * 8 * (C) Copyright 2006 9 * Detlev Zundel, DENX Software Engineering, <dzu@denx.de> 10 * 11 * (C) Copyright -2003 12 * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> 13 * 14 * (C) Copyright 2002 15 * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> 16 * 17 * (C) Copyright 2001 18 * Josh Huber, Mission Critical Linux, Inc, <huber@mclx.com> 19 * 20 * See file CREDITS for list of people who contributed to this 21 * project. 22 * 23 * This program is free software; you can redistribute it and/or 24 * modify it under the terms of the GNU General Public License as 25 * published by the Free Software Foundation; either version 2 of 26 * the License, or (at your option) any later version. 27 * 28 * This program is distributed in the hope that it will be useful, 29 * but WITHOUT ANY WARRANTY; without even the implied warranty of 30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 * GNU General Public License for more details. 32 * 33 * You should have received a copy of the GNU General Public License 34 * along with this program; if not, write to the Free Software 35 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 36 * MA 02111-1307 USA 37 */ 38 39 /* 40 * This file contains the high-level API for the interrupt sub-system 41 * of the x86 port of U-Boot. Most of the functionality has been 42 * shamelessly stolen from the leon2 / leon3 ports of U-Boot. 43 * Daniel Hellstrom, Detlev Zundel, Wolfgang Denk and Josh Huber are 44 * credited for the corresponding work on those ports. The original 45 * interrupt handling routines for the x86 port were written by 46 * Daniel Engström 47 */ 48 49 #include <common.h> 50 #include <asm/interrupt.h> 51 52 struct irq_action { 53 interrupt_handler_t *handler; 54 void *arg; 55 unsigned int count; 56 }; 57 58 static struct irq_action irq_handlers[CONFIG_SYS_NUM_IRQS] = { {0} }; 59 static int spurious_irq_cnt; 60 static int spurious_irq; 61 62 void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg) 63 { 64 int status; 65 66 if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) { 67 printf("irq_install_handler: bad irq number %d\n", irq); 68 return; 69 } 70 71 if (irq_handlers[irq].handler != NULL) 72 printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n", 73 (ulong) handler, 74 (ulong) irq_handlers[irq].handler); 75 76 status = disable_interrupts(); 77 78 irq_handlers[irq].handler = handler; 79 irq_handlers[irq].arg = arg; 80 irq_handlers[irq].count = 0; 81 82 unmask_irq(irq); 83 84 if (status) 85 enable_interrupts(); 86 87 return; 88 } 89 90 void irq_free_handler(int irq) 91 { 92 int status; 93 94 if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) { 95 printf("irq_free_handler: bad irq number %d\n", irq); 96 return; 97 } 98 99 status = disable_interrupts(); 100 101 mask_irq(irq); 102 103 irq_handlers[irq].handler = NULL; 104 irq_handlers[irq].arg = NULL; 105 106 if (status) 107 enable_interrupts(); 108 109 return; 110 } 111 112 void do_irq(int hw_irq) 113 { 114 int irq = hw_irq - 0x20; 115 116 if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) { 117 printf("do_irq: bad irq number %d\n", irq); 118 return; 119 } 120 121 if (irq_handlers[irq].handler) { 122 mask_irq(irq); 123 124 irq_handlers[irq].handler(irq_handlers[irq].arg); 125 irq_handlers[irq].count++; 126 127 unmask_irq(irq); 128 specific_eoi(irq); 129 130 } else { 131 if ((irq & 7) != 7) { 132 spurious_irq_cnt++; 133 spurious_irq = irq; 134 } 135 } 136 } 137 138 #if defined(CONFIG_CMD_IRQ) 139 int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 140 { 141 int irq; 142 143 printf("Spurious IRQ: %u, last unknown IRQ: %d\n", 144 spurious_irq_cnt, spurious_irq); 145 146 printf("Interrupt-Information:\n"); 147 printf("Nr Routine Arg Count\n"); 148 149 for (irq = 0; irq <= CONFIG_SYS_NUM_IRQS; irq++) { 150 if (irq_handlers[irq].handler != NULL) { 151 printf("%02d %08lx %08lx %d\n", 152 irq, 153 (ulong)irq_handlers[irq].handler, 154 (ulong)irq_handlers[irq].arg, 155 irq_handlers[irq].count); 156 } 157 } 158 159 return 0; 160 } 161 #endif 162