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 <command.h> 34#include <irq_func.h> 35#include <asm/interrupt.h> 36 37#if !CONFIG_IS_ENABLED(X86_64) 38 39struct irq_action { 40 interrupt_handler_t *handler; 41 void *arg; 42 unsigned int count; 43}; 44 45static struct irq_action irq_handlers[SYS_NUM_IRQS] = { {0} }; 46static int spurious_irq_cnt; 47static int spurious_irq; 48 49void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg) 50{ 51 int status; 52 53 if (irq < 0 || irq >= SYS_NUM_IRQS) { 54 printf("irq_install_handler: bad irq number %d\n", irq); 55 return; 56 } 57 58 if (irq_handlers[irq].handler != NULL) 59 printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n", 60 (ulong) handler, 61 (ulong) irq_handlers[irq].handler); 62 63 status = disable_interrupts(); 64 65 irq_handlers[irq].handler = handler; 66 irq_handlers[irq].arg = arg; 67 irq_handlers[irq].count = 0; 68 69 if (CONFIG_IS_ENABLED(I8259_PIC)) 70 unmask_irq(irq); 71 72 if (status) 73 enable_interrupts(); 74 75 return; 76} 77 78void irq_free_handler(int irq) 79{ 80 int status; 81 82 if (irq < 0 || irq >= SYS_NUM_IRQS) { 83 printf("irq_free_handler: bad irq number %d\n", irq); 84 return; 85 } 86 87 status = disable_interrupts(); 88 89 if (CONFIG_IS_ENABLED(I8259_PIC)) 90 mask_irq(irq); 91 92 irq_handlers[irq].handler = NULL; 93 irq_handlers[irq].arg = NULL; 94 95 if (status) 96 enable_interrupts(); 97 98 return; 99} 100 101void do_irq(int hw_irq) 102{ 103 int irq = hw_irq - 0x20; 104 105 if (irq < 0 || irq >= SYS_NUM_IRQS) { 106 printf("do_irq: bad irq number %d\n", irq); 107 return; 108 } 109 110 if (irq_handlers[irq].handler) { 111 if (CONFIG_IS_ENABLED(I8259_PIC)) 112 mask_irq(irq); 113 114 irq_handlers[irq].handler(irq_handlers[irq].arg); 115 irq_handlers[irq].count++; 116 117 if (CONFIG_IS_ENABLED(I8259_PIC)) { 118 unmask_irq(irq); 119 specific_eoi(irq); 120 } 121 } else { 122 if ((irq & 7) != 7) { 123 spurious_irq_cnt++; 124 spurious_irq = irq; 125 } 126 } 127} 128#endif 129 130#if defined(CONFIG_CMD_IRQ) 131int do_irqinfo(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) 132{ 133#if !CONFIG_IS_ENABLED(X86_64) 134 struct idt_ptr ptr; 135 int irq; 136 137 interrupt_read_idt(&ptr); 138 printf("IDT at %lx, size %x\n", ptr.address, ptr.size); 139 printf("Spurious IRQ: %u, last unknown IRQ: %d\n", 140 spurious_irq_cnt, spurious_irq); 141 142 printf("Interrupt-Information:\n"); 143 printf("Nr Routine Arg Count\n"); 144 145 for (irq = 0; irq < SYS_NUM_IRQS; irq++) { 146 if (irq_handlers[irq].handler != NULL) { 147 printf("%02d %08lx %08lx %d\n", 148 irq, 149 (ulong)irq_handlers[irq].handler, 150 (ulong)irq_handlers[irq].arg, 151 irq_handlers[irq].count); 152 } 153 } 154#endif 155 156 return 0; 157} 158#endif 159