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 22static 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 36static 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 45static 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. */ 55static 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 */ 79static 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 92static 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 101static inline void handleSpuriousIRQ(void) 102{ 103 /* do nothing */ 104} 105 106static void inline updateIRQState(irq_t irq, x86_irq_state_t state) 107{ 108 assert(irq <= maxIRQ); 109 x86KSIRQState[irq] = state; 110} 111 112static inline void maskInterrupt(bool_t disable, irq_t irq) 113{ 114 if (irq >= irq_isa_min && irq <= irq_isa_max) { 115 if (config_set(CONFIG_IRQ_PIC)) { 116 pic_mask_irq(disable, irq); 117 } else { 118 /* We shouldn't receive interrupts on the PIC range 119 * if not using the PIC, but soldier on anyway */ 120 } 121 } else if (irq >= irq_user_min && irq <= irq_user_max) { 122 x86_irq_state_t state = x86KSIRQState[irq]; 123 switch (x86_irq_state_get_irqType(state)) { 124 case x86_irq_state_irq_ioapic: { 125 uint32_t ioapic = x86_irq_state_irq_ioapic_get_id(state); 126 uint32_t pin = x86_irq_state_irq_ioapic_get_pin(state); 127 ioapic_mask(disable, ioapic, pin); 128 state = x86_irq_state_irq_ioapic_set_masked(state, disable); 129 updateIRQState(irq, state); 130 } 131 break; 132 case x86_irq_state_irq_msi: 133 /* currently MSI interrupts can not be disabled */ 134 break; 135 case x86_irq_state_irq_free: 136 /* A spurious interrupt, and the resulting mask here, 137 * could be from a user ripping out a vector before 138 * the interrupt reached the kernel. Silently ignore */ 139 break; 140 } 141 } else { 142 /* masking some other kind of interrupt source, this probably 143 * shouldn't happen, but soldier on */ 144 } 145} 146 147