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 * SPDX-License-Identifier: GPL-2.0+ 21 */ 22 23 /* 24 * This file contains the high-level API for the interrupt sub-system 25 * of the x86 port of U-Boot. Most of the functionality has been 26 * shamelessly stolen from the leon2 / leon3 ports of U-Boot. 27 * Daniel Hellstrom, Detlev Zundel, Wolfgang Denk and Josh Huber are 28 * credited for the corresponding work on those ports. The original 29 * interrupt handling routines for the x86 port were written by 30 * Daniel Engström 31 */ 32 33 #include <common.h> 34 #include <asm/interrupt.h> 35 36 #if !CONFIG_IS_ENABLED(X86_64) 37 38 struct irq_action { 39 interrupt_handler_t *handler; 40 void *arg; 41 unsigned int count; 42 }; 43 44 static struct irq_action irq_handlers[SYS_NUM_IRQS] = { {0} }; 45 static int spurious_irq_cnt; 46 static int spurious_irq; 47 48 void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg) 49 { 50 int status; 51 52 if (irq < 0 || irq >= SYS_NUM_IRQS) { 53 printf("irq_install_handler: bad irq number %d\n", irq); 54 return; 55 } 56 57 if (irq_handlers[irq].handler != NULL) 58 printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n", 59 (ulong) handler, 60 (ulong) irq_handlers[irq].handler); 61 62 status = disable_interrupts(); 63 64 irq_handlers[irq].handler = handler; 65 irq_handlers[irq].arg = arg; 66 irq_handlers[irq].count = 0; 67 68 unmask_irq(irq); 69 70 if (status) 71 enable_interrupts(); 72 73 return; 74 } 75 76 void irq_free_handler(int irq) 77 { 78 int status; 79 80 if (irq < 0 || irq >= SYS_NUM_IRQS) { 81 printf("irq_free_handler: bad irq number %d\n", irq); 82 return; 83 } 84 85 status = disable_interrupts(); 86 87 mask_irq(irq); 88 89 irq_handlers[irq].handler = NULL; 90 irq_handlers[irq].arg = NULL; 91 92 if (status) 93 enable_interrupts(); 94 95 return; 96 } 97 98 void do_irq(int hw_irq) 99 { 100 int irq = hw_irq - 0x20; 101 102 if (irq < 0 || irq >= SYS_NUM_IRQS) { 103 printf("do_irq: bad irq number %d\n", irq); 104 return; 105 } 106 107 if (irq_handlers[irq].handler) { 108 mask_irq(irq); 109 110 irq_handlers[irq].handler(irq_handlers[irq].arg); 111 irq_handlers[irq].count++; 112 113 unmask_irq(irq); 114 specific_eoi(irq); 115 116 } else { 117 if ((irq & 7) != 7) { 118 spurious_irq_cnt++; 119 spurious_irq = irq; 120 } 121 } 122 } 123 #endif 124 125 #if defined(CONFIG_CMD_IRQ) 126 int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 127 { 128 #if !CONFIG_IS_ENABLED(X86_64) 129 int irq; 130 131 printf("Spurious IRQ: %u, last unknown IRQ: %d\n", 132 spurious_irq_cnt, spurious_irq); 133 134 printf("Interrupt-Information:\n"); 135 printf("Nr Routine Arg Count\n"); 136 137 for (irq = 0; irq < SYS_NUM_IRQS; irq++) { 138 if (irq_handlers[irq].handler != NULL) { 139 printf("%02d %08lx %08lx %d\n", 140 irq, 141 (ulong)irq_handlers[irq].handler, 142 (ulong)irq_handlers[irq].arg, 143 irq_handlers[irq].count); 144 } 145 } 146 #endif 147 148 return 0; 149 } 150 #endif 151