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