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 unmask_irq(irq); 68 69 if (status) 70 enable_interrupts(); 71 72 return; 73 } 74 75 void irq_free_handler(int irq) 76 { 77 int status; 78 79 if (irq < 0 || irq >= SYS_NUM_IRQS) { 80 printf("irq_free_handler: bad irq number %d\n", irq); 81 return; 82 } 83 84 status = disable_interrupts(); 85 86 mask_irq(irq); 87 88 irq_handlers[irq].handler = NULL; 89 irq_handlers[irq].arg = NULL; 90 91 if (status) 92 enable_interrupts(); 93 94 return; 95 } 96 97 void do_irq(int hw_irq) 98 { 99 int irq = hw_irq - 0x20; 100 101 if (irq < 0 || irq >= SYS_NUM_IRQS) { 102 printf("do_irq: bad irq number %d\n", irq); 103 return; 104 } 105 106 if (irq_handlers[irq].handler) { 107 mask_irq(irq); 108 109 irq_handlers[irq].handler(irq_handlers[irq].arg); 110 irq_handlers[irq].count++; 111 112 unmask_irq(irq); 113 specific_eoi(irq); 114 115 } else { 116 if ((irq & 7) != 7) { 117 spurious_irq_cnt++; 118 spurious_irq = irq; 119 } 120 } 121 } 122 #endif 123 124 #if defined(CONFIG_CMD_IRQ) 125 int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 126 { 127 #if !CONFIG_IS_ENABLED(X86_64) 128 int irq; 129 130 printf("Spurious IRQ: %u, last unknown IRQ: %d\n", 131 spurious_irq_cnt, spurious_irq); 132 133 printf("Interrupt-Information:\n"); 134 printf("Nr Routine Arg Count\n"); 135 136 for (irq = 0; irq < SYS_NUM_IRQS; irq++) { 137 if (irq_handlers[irq].handler != NULL) { 138 printf("%02d %08lx %08lx %d\n", 139 irq, 140 (ulong)irq_handlers[irq].handler, 141 (ulong)irq_handlers[irq].arg, 142 irq_handlers[irq].count); 143 } 144 } 145 #endif 146 147 return 0; 148 } 149 #endif 150