/* * Copyright (c) 2013-2015, Wind River Systems, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * @brief system module for variants with LOAPIC * */ #include #include "board.h" #include #include #include #include #include #if !defined(LOAPIC_IRQ_BASE) && !defined (LOAPIC_IRQ_COUNT) /* Default IA32 system APIC definitions with local APIC IRQs after IO APIC. */ #define LOAPIC_IRQ_BASE CONFIG_IOAPIC_NUM_RTES #define LOAPIC_IRQ_COUNT 6 /* Default to LOAPIC_TIMER to LOAPIC_ERROR */ #define IS_IOAPIC_IRQ(irq) (irq < LOAPIC_IRQ_BASE) #define HARDWARE_IRQ_LIMIT ((LOAPIC_IRQ_BASE + LOAPIC_IRQ_COUNT) - 1) #else /* Assumption for boards that define LOAPIC_IRQ_BASE & LOAPIC_IRQ_COUNT that local APIC IRQs are within IOAPIC RTE range. */ #define IS_IOAPIC_IRQ(irq) ((irq < LOAPIC_IRQ_BASE) || \ (irq >= (LOAPIC_IRQ_BASE + LOAPIC_IRQ_COUNT))) #define HARDWARE_IRQ_LIMIT (CONFIG_IOAPIC_NUM_RTES - 1) #endif /* forward declarations */ static int __LocalIntVecAlloc(unsigned int irq, unsigned int priority); /** * * @brief Allocate interrupt vector * * This routine is used by the x86's irq_connect_dynamic(). It performs the * following functions: * * a) Allocates a vector satisfying the requested priority. The utility * routine _IntVecAlloc() provided by the nanokernel will be used to * perform the the allocation since the local APIC prioritizes interrupts * as assumed by _IntVecAlloc(). * b) If an interrupt vector can be allocated, the IOAPIC redirection table * (RED) or the LOAPIC local vector table (LVT) will be updated with the * allocated interrupt vector. * * The board virtualizes IRQs as follows: * * - The first CONFIG_IOAPIC_NUM_RTES IRQs are provided by the IOAPIC * - The remaining IRQs are provided by the LOAPIC. * * Thus, for example, if the IOAPIC supports 24 IRQs: * * - IRQ0 to IRQ23 map to IOAPIC IRQ0 to IRQ23 * - IRQ24 to IRQ29 map to LOAPIC LVT entries as follows: * * IRQ24 -> LOAPIC_TIMER * IRQ25 -> LOAPIC_THERMAL * IRQ26 -> LOAPIC_PMC * IRQ27 -> LOAPIC_LINT0 * IRQ28 -> LOAPIC_LINT1 * IRQ29 -> LOAPIC_ERROR * * @param irq virtualized IRQ * @param priority get vector from group * @param flags Interrupt flags * * @return the allocated interrupt vector * * @internal * For debug kernels, this routine will return -1 if there are no vectors * remaining in the specified level, or if the or * parameters are invalid. * @endinternal */ int _SysIntVecAlloc( unsigned int irq, /* virtualized IRQ */ unsigned int priority, /* get vector from group */ uint32_t flags /* interrupt flags */ ) { int vector; __ASSERT(priority < 14, "invalid priority"); __ASSERT(irq >= 0 && irq <= HARDWARE_IRQ_LIMIT, "invalid irq line"); vector = __LocalIntVecAlloc(irq, priority); /* * Set up the appropriate interrupt controller to generate the allocated * interrupt vector for the specified IRQ */ __ASSERT(vector != -1, "bad vector id"); _SysIntVecProgram(vector, irq, flags); return vector; } /** * * @brief Program interrupt controller * * This routine programs the interrupt controller with the given vector * based on the given IRQ parameter. * * Drivers call this routine instead of IRQ_CONNECT() when interrupts are * configured statically. * * The Galileo board virtualizes IRQs as follows: * * - The first CONFIG_IOAPIC_NUM_RTES IRQs are provided by the IOAPIC so the * IOAPIC is programmed for these IRQs * - The remaining IRQs are provided by the LOAPIC and hence the LOAPIC is * programmed. * * @param vector the vector number * @param irq the virtualized IRQ * @param flags interrupt flags * */ void _SysIntVecProgram(unsigned int vector, unsigned int irq, uint32_t flags) { if (IS_IOAPIC_IRQ(irq)) { _ioapic_irq_set(irq, vector, flags); } else { _loapic_int_vec_set(irq - LOAPIC_IRQ_BASE, vector); } } /** * * @brief Enable an individual interrupt (IRQ) * * The public interface for enabling/disabling a specific IRQ for the IA-32 * architecture is defined as follows in include/arch/x86/arch.h * * extern void irq_enable (unsigned int irq); * extern void irq_disable (unsigned int irq); * * The irq_enable() routine is provided by the interrupt controller driver due * to the IRQ virtualization that is performed by this platform. See the * comments in _SysIntVecAlloc() for more information regarding IRQ * virtualization. * * @return N/A */ void _arch_irq_enable(unsigned int irq) { if (IS_IOAPIC_IRQ(irq)) { _ioapic_irq_enable(irq); } else { _loapic_irq_enable(irq - LOAPIC_IRQ_BASE); } } /** * * @brief Disable an individual interrupt (IRQ) * * The irq_disable() routine is provided by the interrupt controller driver due * to the IRQ virtualization that is performed by this platform. See the * comments in _SysIntVecAlloc() for more information regarding IRQ * virtualization. * * @return N/A */ void _arch_irq_disable(unsigned int irq) { if (IS_IOAPIC_IRQ(irq)) { _ioapic_irq_disable(irq); } else { _loapic_irq_disable(irq - LOAPIC_IRQ_BASE); } } #ifdef FIXED_HARDWARE_IRQ_TO_VEC_MAPPING static inline int handle_fixed_mapping(int irq, int *vector) { /* * On this board Hardware IRQs are fixed and not programmable. */ *vector = FIXED_HARDWARE_IRQ_TO_VEC_MAPPING(irq); /* mark vector as allocated */ _IntVecMarkAllocated(*vector); return *vector; } #else static inline int handle_fixed_mapping(int irq, int *vector) { ARG_UNUSED(irq); ARG_UNUSED(vector); return 0; } #endif /** * * @brief Local allocate interrupt vector. * * @returns The allocated interrupt vector * */ static int __LocalIntVecAlloc( unsigned int irq, /* virtualized IRQ */ unsigned int priority /* get vector from group */ ) { int vector; if (handle_fixed_mapping(irq, &vector)) { return vector; } /* * Use the nanokernel utility function _IntVecAlloc(). A value of * -1 will be returned if there are no free vectors in the requested * priority. */ vector = _IntVecAlloc(priority); __ASSERT(vector != -1, "No free vectors in the requested priority"); return vector; }