1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2009 4 * Graeme Russ, <graeme.russ@gmail.com> 5 * 6 * (C) Copyright 2007 7 * Daniel Hellstrom, Gaisler Research, <daniel@gaisler.com> 8 * 9 * (C) Copyright 2006 10 * Detlev Zundel, DENX Software Engineering, <dzu@denx.de> 11 * 12 * (C) Copyright -2003 13 * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> 14 * 15 * (C) Copyright 2002 16 * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> 17 * 18 * (C) Copyright 2001 19 * Josh Huber, Mission Critical Linux, Inc, <huber@mclx.com> 20 */ 21 22 /* 23 * This file contains the high-level API for the interrupt sub-system 24 * of the x86 port of U-Boot. Most of the functionality has been 25 * shamelessly stolen from the leon2 / leon3 ports of U-Boot. 26 * Daniel Hellstrom, Detlev Zundel, Wolfgang Denk and Josh Huber are 27 * credited for the corresponding work on those ports. The original 28 * interrupt handling routines for the x86 port were written by 29 * Daniel Engström 30 */ 31 32 #include <common.h> 33 #include <asm/interrupt.h> 34 35 #if !CONFIG_IS_ENABLED(X86_64) 36 37 struct irq_action { 38 interrupt_handler_t *handler; 39 void *arg; 40 unsigned int count; 41 }; 42 43 static struct irq_action irq_handlers[SYS_NUM_IRQS] = { {0} }; 44 static int spurious_irq_cnt; 45 static int spurious_irq; 46 47 void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg) 48 { 49 int status; 50 51 if (irq < 0 || irq >= SYS_NUM_IRQS) { 52 printf("irq_install_handler: bad irq number %d\n", irq); 53 return; 54 } 55 56 if (irq_handlers[irq].handler != NULL) 57 printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n", 58 (ulong) handler, 59 (ulong) irq_handlers[irq].handler); 60 61 status = disable_interrupts(); 62 63 irq_handlers[irq].handler = handler; 64 irq_handlers[irq].arg = arg; 65 irq_handlers[irq].count = 0; 66 67 if (CONFIG_IS_ENABLED(I8259_PIC)) 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 if (CONFIG_IS_ENABLED(I8259_PIC)) 88 mask_irq(irq); 89 90 irq_handlers[irq].handler = NULL; 91 irq_handlers[irq].arg = NULL; 92 93 if (status) 94 enable_interrupts(); 95 96 return; 97 } 98 99 void do_irq(int hw_irq) 100 { 101 int irq = hw_irq - 0x20; 102 103 if (irq < 0 || irq >= SYS_NUM_IRQS) { 104 printf("do_irq: bad irq number %d\n", irq); 105 return; 106 } 107 108 if (irq_handlers[irq].handler) { 109 if (CONFIG_IS_ENABLED(I8259_PIC)) 110 mask_irq(irq); 111 112 irq_handlers[irq].handler(irq_handlers[irq].arg); 113 irq_handlers[irq].count++; 114 115 if (CONFIG_IS_ENABLED(I8259_PIC)) { 116 unmask_irq(irq); 117 specific_eoi(irq); 118 } 119 } else { 120 if ((irq & 7) != 7) { 121 spurious_irq_cnt++; 122 spurious_irq = irq; 123 } 124 } 125 } 126 #endif 127 128 #if defined(CONFIG_CMD_IRQ) 129 int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 130 { 131 #if !CONFIG_IS_ENABLED(X86_64) 132 int irq; 133 134 printf("Spurious IRQ: %u, last unknown IRQ: %d\n", 135 spurious_irq_cnt, spurious_irq); 136 137 printf("Interrupt-Information:\n"); 138 printf("Nr Routine Arg Count\n"); 139 140 for (irq = 0; irq < SYS_NUM_IRQS; irq++) { 141 if (irq_handlers[irq].handler != NULL) { 142 printf("%02d %08lx %08lx %d\n", 143 irq, 144 (ulong)irq_handlers[irq].handler, 145 (ulong)irq_handlers[irq].arg, 146 irq_handlers[irq].count); 147 } 148 } 149 #endif 150 151 return 0; 152 } 153 #endif 154