Merge tag 'u-boot-atmel-fixes-2020.07-a' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / arch / x86 / lib / interrupts.c
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
39 struct irq_action {
40         interrupt_handler_t *handler;
41         void *arg;
42         unsigned int count;
43 };
44
45 static struct irq_action irq_handlers[SYS_NUM_IRQS] = { {0} };
46 static int spurious_irq_cnt;
47 static int spurious_irq;
48
49 void 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
78 void 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
101 void 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)
131 int do_irqinfo(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
132 {
133 #if !CONFIG_IS_ENABLED(X86_64)
134         int irq;
135
136         printf("Spurious IRQ: %u, last unknown IRQ: %d\n",
137                         spurious_irq_cnt, spurious_irq);
138
139         printf("Interrupt-Information:\n");
140         printf("Nr  Routine   Arg       Count\n");
141
142         for (irq = 0; irq < SYS_NUM_IRQS; irq++) {
143                 if (irq_handlers[irq].handler != NULL) {
144                         printf("%02d  %08lx  %08lx  %d\n",
145                                         irq,
146                                         (ulong)irq_handlers[irq].handler,
147                                         (ulong)irq_handlers[irq].arg,
148                                         irq_handlers[irq].count);
149                 }
150         }
151 #endif
152
153         return 0;
154 }
155 #endif