1 /*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7 #pragma once
8
9 #include <config.h>
10 #include <types.h>
11 #include <util.h>
12
13 #include <arch/object/structures.h>
14 #include <arch/model/statedata.h>
15 #include <arch/kernel/apic.h>
16 #include <machine/interrupt.h>
17 #include <plat/machine/acpi.h>
18 #include <plat/machine/ioapic.h>
19 #include <plat/machine/pic.h>
20 #include <plat/machine/intel-vtd.h>
21
handleReservedIRQ(irq_t irq)22 static inline void handleReservedIRQ(irq_t irq)
23 {
24 #ifdef CONFIG_IOMMU
25 if (irq == irq_iommu) {
26 vtd_handle_fault();
27 return;
28 }
29 #endif
30
31 #ifdef CONFIG_IRQ_REPORTING
32 printf("Received unhandled reserved IRQ: %d\n", (int)irq);
33 #endif
34 }
35
receivePendingIRQ(void)36 static inline void receivePendingIRQ(void)
37 {
38 assert(ARCH_NODE_STATE(x86KSPendingInterrupt) == int_invalid);
39 asm volatile("sti\n"
40 "nop\n"
41 "cli\n"
42 : "=m"(ARCH_NODE_STATE(x86KSPendingInterrupt)));
43 }
44
servicePendingIRQ(void)45 static inline interrupt_t servicePendingIRQ(void)
46 {
47 assert(ARCH_NODE_STATE(x86KScurInterrupt) == int_invalid);
48 assert(ARCH_NODE_STATE(x86KSPendingInterrupt) != int_invalid);
49 interrupt_t ret = ARCH_NODE_STATE(x86KSPendingInterrupt);
50 ARCH_NODE_STATE(x86KSPendingInterrupt) = int_invalid;
51 return ret;
52 }
53
54 /* Get the IRQ number currently working on. */
getActiveIRQ(void)55 static inline irq_t getActiveIRQ(void)
56 {
57 if (ARCH_NODE_STATE(x86KScurInterrupt) == int_invalid) {
58 /* If we tried to get the active IRQ when we don't have one then
59 * we are polling for an interrupt for some reason, in which case
60 * we should try to get a pending interrupt if there isn't already
61 * one.
62 * This logic is here and not in the main call sites in handleSyscall
63 * because this is only relevant on some interrupt controllers (notably
64 * the x86 APIC) and is cleaner to have here */
65 if (ARCH_NODE_STATE(x86KSPendingInterrupt) == int_invalid) {
66 receivePendingIRQ();
67 /* Check if there was no pending IRQ */
68 if (ARCH_NODE_STATE(x86KSPendingInterrupt) == int_invalid) {
69 return irqInvalid;
70 }
71 }
72 /* Prepare to handle pending IRQ */
73 ARCH_NODE_STATE(x86KScurInterrupt) = servicePendingIRQ();
74 }
75 return ARCH_NODE_STATE(x86KScurInterrupt) - IRQ_INT_OFFSET;
76 }
77
78 /* Checks for pending IRQ */
isIRQPending(void)79 static inline bool_t isIRQPending(void)
80 {
81 if (apic_is_interrupt_pending()) {
82 return true;
83 }
84
85 if (config_set(CONFIG_IRQ_PIC) && pic_is_irq_pending()) {
86 return true;
87 }
88
89 return false;
90 }
91
ackInterrupt(irq_t irq)92 static inline void ackInterrupt(irq_t irq)
93 {
94 if (config_set(CONFIG_IRQ_PIC) && irq <= irq_isa_max) {
95 pic_ack_active_irq();
96 } else {
97 apic_ack_active_interrupt();
98 }
99
100 ARCH_NODE_STATE(x86KScurInterrupt) = int_invalid;
101 }
102
handleSpuriousIRQ(void)103 static inline void handleSpuriousIRQ(void)
104 {
105 /* do nothing */
106 }
107
updateIRQState(irq_t irq,x86_irq_state_t state)108 static void inline updateIRQState(irq_t irq, x86_irq_state_t state)
109 {
110 assert(irq <= maxIRQ);
111 x86KSIRQState[irq] = state;
112 }
113
maskInterrupt(bool_t disable,irq_t irq)114 static inline void maskInterrupt(bool_t disable, irq_t irq)
115 {
116 if (irq >= irq_isa_min && irq <= irq_isa_max) {
117 if (config_set(CONFIG_IRQ_PIC)) {
118 pic_mask_irq(disable, irq);
119 } else {
120 /* We shouldn't receive interrupts on the PIC range
121 * if not using the PIC, but soldier on anyway */
122 }
123 } else if (irq >= irq_user_min && irq <= irq_user_max) {
124 x86_irq_state_t state = x86KSIRQState[irq];
125 switch (x86_irq_state_get_irqType(state)) {
126 case x86_irq_state_irq_ioapic: {
127 uint32_t ioapic = x86_irq_state_irq_ioapic_get_id(state);
128 uint32_t pin = x86_irq_state_irq_ioapic_get_pin(state);
129 ioapic_mask(disable, ioapic, pin);
130 state = x86_irq_state_irq_ioapic_set_masked(state, disable);
131 updateIRQState(irq, state);
132 }
133 break;
134 case x86_irq_state_irq_msi:
135 /* currently MSI interrupts can not be disabled */
136 break;
137 case x86_irq_state_irq_free:
138 /* A spurious interrupt, and the resulting mask here,
139 * could be from a user ripping out a vector before
140 * the interrupt reached the kernel. Silently ignore */
141 break;
142 }
143 } else {
144 /* masking some other kind of interrupt source, this probably
145 * shouldn't happen, but soldier on */
146 }
147 }
148
149