2015-04-11 01:44:37 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2013-2015, Wind River Systems, Inc.
|
|
|
|
*
|
2015-10-06 18:00:37 +02:00
|
|
|
* 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
|
2015-04-11 01:44:37 +02:00
|
|
|
*
|
2015-10-06 18:00:37 +02:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2015-04-11 01:44:37 +02:00
|
|
|
*
|
2015-10-06 18:00:37 +02:00
|
|
|
* 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.
|
2015-04-11 01:44:37 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2015-09-07 14:22:55 +02:00
|
|
|
* @file
|
|
|
|
* @brief system module for variants with LOAPIC
|
|
|
|
*
|
|
|
|
* This module provides routines to initialize and support
|
|
|
|
* board-level hardware for the basic_atom configuration of
|
|
|
|
* ia32 platform.
|
2015-07-01 23:22:39 +02:00
|
|
|
*/
|
2015-04-11 01:44:37 +02:00
|
|
|
|
|
|
|
#include <misc/__assert.h>
|
|
|
|
#include "board.h"
|
|
|
|
#include <nanokernel.h>
|
2015-05-28 19:56:47 +02:00
|
|
|
#include <arch/cpu.h>
|
2015-04-11 01:44:37 +02:00
|
|
|
#include <drivers/ioapic.h>
|
|
|
|
#include <drivers/loapic.h>
|
|
|
|
|
2015-07-01 23:22:39 +02:00
|
|
|
/**
|
|
|
|
*
|
2015-07-01 23:51:40 +02:00
|
|
|
* @brief Allocate interrupt vector
|
2015-07-01 23:22:39 +02:00
|
|
|
*
|
2015-07-27 17:02:41 +02:00
|
|
|
* This routine is used by the x86's irq_connect(). 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().
|
x86: remove dynamically generated IRQ and exception code
We are interested in supporting some XIP x86 platforms which are
unable to fetch CPU instructions from system RAM. This requires
refactoring our dynamic IRQ/exc code which currently synthesizes
assembly language instructions to create IRQ stubs on-the-fly.
Instead, a new approach is taken. Given that the configuration at
build time specifies the number of required stubs, use this
to generate a build time a set of tiny stub functions which simply
push a 'stub id' and then call common dynamic interrupt code.
The handler function and handler argument is saved in a table keyed by
this stub id.
CONFIG_EOI_HANDLER_SUPPORTED removed, the code hasn't been conditionally
compiled for some time and in all cases we call _loapic_eoi() when
finished with an interrupt.
Some other out-of-date verbiage in comments related to supporting
non-APIC removed.
Previously, when dynamic exceptions were created a pointer would
be passed in by the caller reserving ram for the stub code. Since
this is no longer feasible, two new Kconfig options have been added.
CONFIG_NUM_DYNAMIC_EXC_STUBS and CONFIG_NUM_DYNAMIC_EXC_NO_ERR_STUBS
control how many stubs are created for exceptions that push
an error code, and no error code, respectively.
SW Interrupts are no longer triggered by "int <vector>" hard-coded
assembly instructions. Instead this is done by sending a self-directed
inter-processor interrupt from the LOAPIC, using a new API
loapic_int_vect_trigger(). In this way we get rid of dynamically
generated code in irq_test_common.h.
All interrupts call _loapic_eoi() when finished, since this is now
the right thing to do for all IRQs, including SW interrupts.
_irq_handler_set() for x86 no longer requires the old function pointer
to be supplied.
Change-Id: I78993d3d00dd153c9051c518b417cce8d3acee9e
Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2015-10-19 23:10:53 +02:00
|
|
|
* b) If an interrupt vector can be allocated, and the <irq> argument is not
|
2015-07-01 23:22:39 +02:00
|
|
|
* equal to NANO_SOFT_IRQ, 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:
|
|
|
|
*
|
2015-07-28 20:39:12 +02:00
|
|
|
* - The first CONFIG_IOAPIC_NUM_RTES IRQs are provided by the IOAPIC
|
2015-07-01 23:51:40 +02:00
|
|
|
* - The remaining IRQs are provided by the LOAPIC.
|
2015-07-01 23:22:39 +02:00
|
|
|
*
|
|
|
|
* Thus, for example, if the IOAPIC supports 24 IRQs:
|
|
|
|
*
|
2015-07-01 23:51:40 +02:00
|
|
|
* - IRQ0 to IRQ23 map to IOAPIC IRQ0 to IRQ23
|
|
|
|
* - IRQ24 to IRQ29 map to LOAPIC LVT entries as follows:
|
2015-07-01 23:22:39 +02:00
|
|
|
*
|
|
|
|
* IRQ24 -> LOAPIC_TIMER
|
|
|
|
* IRQ25 -> LOAPIC_THERMAL
|
|
|
|
* IRQ26 -> LOAPIC_PMC
|
|
|
|
* IRQ27 -> LOAPIC_LINT0
|
|
|
|
* IRQ28 -> LOAPIC_LINT1
|
|
|
|
* IRQ29 -> LOAPIC_ERROR
|
|
|
|
*
|
2015-10-20 18:42:33 +02:00
|
|
|
* @param irq virtualized IRQ
|
|
|
|
* @param priority get vector from <priority> group
|
|
|
|
*
|
2015-07-01 23:29:04 +02:00
|
|
|
* @return the allocated interrupt vector
|
2015-07-01 23:22:39 +02:00
|
|
|
*
|
2015-09-07 14:22:55 +02:00
|
|
|
* @internal
|
2015-07-01 23:22:39 +02:00
|
|
|
* For debug kernels, this routine will return -1 if there are no vectors
|
|
|
|
* remaining in the specified <priority> level, or if the <priority> or <irq>
|
|
|
|
* parameters are invalid.
|
2015-09-07 14:22:55 +02:00
|
|
|
* @endinternal
|
2015-07-01 23:22:39 +02:00
|
|
|
*/
|
2015-10-19 19:03:23 +02:00
|
|
|
int _SysIntVecAlloc(
|
|
|
|
unsigned int irq, /* virtualized IRQ */
|
x86: remove dynamically generated IRQ and exception code
We are interested in supporting some XIP x86 platforms which are
unable to fetch CPU instructions from system RAM. This requires
refactoring our dynamic IRQ/exc code which currently synthesizes
assembly language instructions to create IRQ stubs on-the-fly.
Instead, a new approach is taken. Given that the configuration at
build time specifies the number of required stubs, use this
to generate a build time a set of tiny stub functions which simply
push a 'stub id' and then call common dynamic interrupt code.
The handler function and handler argument is saved in a table keyed by
this stub id.
CONFIG_EOI_HANDLER_SUPPORTED removed, the code hasn't been conditionally
compiled for some time and in all cases we call _loapic_eoi() when
finished with an interrupt.
Some other out-of-date verbiage in comments related to supporting
non-APIC removed.
Previously, when dynamic exceptions were created a pointer would
be passed in by the caller reserving ram for the stub code. Since
this is no longer feasible, two new Kconfig options have been added.
CONFIG_NUM_DYNAMIC_EXC_STUBS and CONFIG_NUM_DYNAMIC_EXC_NO_ERR_STUBS
control how many stubs are created for exceptions that push
an error code, and no error code, respectively.
SW Interrupts are no longer triggered by "int <vector>" hard-coded
assembly instructions. Instead this is done by sending a self-directed
inter-processor interrupt from the LOAPIC, using a new API
loapic_int_vect_trigger(). In this way we get rid of dynamically
generated code in irq_test_common.h.
All interrupts call _loapic_eoi() when finished, since this is now
the right thing to do for all IRQs, including SW interrupts.
_irq_handler_set() for x86 no longer requires the old function pointer
to be supplied.
Change-Id: I78993d3d00dd153c9051c518b417cce8d3acee9e
Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2015-10-19 23:10:53 +02:00
|
|
|
unsigned int priority /* get vector from <priority> group */
|
2015-10-19 19:03:23 +02:00
|
|
|
)
|
2015-04-11 01:44:37 +02:00
|
|
|
{
|
|
|
|
int vector;
|
|
|
|
|
2015-09-07 14:25:45 +02:00
|
|
|
#if defined(CONFIG_LOAPIC_DEBUG)
|
2015-04-11 01:44:37 +02:00
|
|
|
if ((priority > 15) ||
|
2015-07-28 20:39:12 +02:00
|
|
|
((irq > (CONFIG_IOAPIC_NUM_RTES + 5)) && (irq != NANO_SOFT_IRQ)))
|
2015-04-11 01:44:37 +02:00
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up the appropriate interrupt controller to generate the allocated
|
|
|
|
* interrupt vector for the specified IRQ. Also, provide the required
|
2015-10-19 19:03:23 +02:00
|
|
|
* EOI related information for the interrupt stub code generation
|
|
|
|
* step.
|
2015-04-11 01:44:37 +02:00
|
|
|
*
|
|
|
|
* For software interrupts (NANO_SOFT_IRQ), skip the interrupt
|
2015-10-19 19:03:23 +02:00
|
|
|
* controller programming step, and indicate that an EOI handler is not
|
|
|
|
* required.
|
2015-04-11 01:44:37 +02:00
|
|
|
*/
|
|
|
|
|
2015-09-07 14:25:45 +02:00
|
|
|
#if defined(CONFIG_LOAPIC_DEBUG)
|
2015-04-11 01:44:37 +02:00
|
|
|
if ((vector != -1) && (irq != NANO_SOFT_IRQ))
|
|
|
|
#else
|
|
|
|
if (irq != NANO_SOFT_IRQ)
|
|
|
|
#endif
|
|
|
|
{
|
2015-10-19 19:03:23 +02:00
|
|
|
_SysIntVecProgram(vector, irq);
|
2015-04-11 01:44:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return vector;
|
|
|
|
}
|
|
|
|
|
2015-07-01 23:22:39 +02:00
|
|
|
/**
|
|
|
|
*
|
2015-07-01 23:51:40 +02:00
|
|
|
* @brief Program interrupt controller
|
2015-07-01 23:22:39 +02:00
|
|
|
*
|
2015-07-27 17:02:41 +02:00
|
|
|
* This routine programs the interrupt controller with the given vector
|
|
|
|
* based on the given IRQ parameter.
|
2015-07-01 23:22:39 +02:00
|
|
|
*
|
|
|
|
* Drivers call this routine instead of irq_connect() when interrupts are
|
|
|
|
* configured statically.
|
|
|
|
*
|
|
|
|
* The Clanton board virtualizes IRQs as follows:
|
|
|
|
*
|
2015-07-28 20:39:12 +02:00
|
|
|
* - The first CONFIG_IOAPIC_NUM_RTES IRQs are provided by the IOAPIC so the
|
|
|
|
* IOAPIC is programmed for these IRQs
|
2015-07-01 23:51:40 +02:00
|
|
|
* - The remaining IRQs are provided by the LOAPIC and hence the LOAPIC is
|
2015-07-01 23:22:39 +02:00
|
|
|
* programmed.
|
2015-10-20 18:42:33 +02:00
|
|
|
*
|
|
|
|
* @param vector the vector number
|
|
|
|
* @param irq the virtualized IRQ
|
|
|
|
*
|
2015-07-01 23:22:39 +02:00
|
|
|
*/
|
2015-10-20 18:42:33 +02:00
|
|
|
void _SysIntVecProgram(unsigned int vector, unsigned int irq)
|
2015-04-11 01:44:37 +02:00
|
|
|
{
|
|
|
|
|
2015-07-28 20:39:12 +02:00
|
|
|
if (irq < CONFIG_IOAPIC_NUM_RTES) {
|
2015-04-11 01:44:37 +02:00
|
|
|
_ioapic_int_vec_set(irq, vector);
|
|
|
|
} else {
|
2015-07-28 20:39:12 +02:00
|
|
|
_loapic_int_vec_set(irq - CONFIG_IOAPIC_NUM_RTES, vector);
|
2015-04-11 01:44:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-01 23:22:39 +02:00
|
|
|
/**
|
|
|
|
*
|
2015-07-01 23:51:40 +02:00
|
|
|
* @brief Enable an individual interrupt (IRQ)
|
2015-07-01 23:22:39 +02:00
|
|
|
*
|
|
|
|
* The public interface for enabling/disabling a specific IRQ for the IA-32
|
2015-07-27 17:02:41 +02:00
|
|
|
* architecture is defined as follows in include/arch/x86/arch.h
|
2015-07-01 23:22:39 +02:00
|
|
|
*
|
|
|
|
* extern void irq_enable (unsigned int irq);
|
|
|
|
* extern void irq_disable (unsigned int irq);
|
|
|
|
*
|
2015-07-27 17:02:41 +02:00
|
|
|
* 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.
|
2015-07-01 23:22:39 +02:00
|
|
|
*
|
2015-07-01 23:29:04 +02:00
|
|
|
* @return N/A
|
2015-07-01 23:22:39 +02:00
|
|
|
*/
|
2015-04-11 01:44:37 +02:00
|
|
|
void irq_enable(unsigned int irq)
|
|
|
|
{
|
2015-07-28 20:39:12 +02:00
|
|
|
if (irq < CONFIG_IOAPIC_NUM_RTES) {
|
2015-04-11 01:44:37 +02:00
|
|
|
_ioapic_irq_enable(irq);
|
|
|
|
} else {
|
2015-07-28 20:39:12 +02:00
|
|
|
_loapic_irq_enable(irq - CONFIG_IOAPIC_NUM_RTES);
|
2015-04-11 01:44:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-01 23:22:39 +02:00
|
|
|
/**
|
|
|
|
*
|
2015-07-01 23:51:40 +02:00
|
|
|
* @brief Disable an individual interrupt (IRQ)
|
2015-07-01 23:22:39 +02:00
|
|
|
*
|
2015-07-27 17:02:41 +02:00
|
|
|
* 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.
|
2015-07-01 23:22:39 +02:00
|
|
|
*
|
2015-07-01 23:29:04 +02:00
|
|
|
* @return N/A
|
2015-07-01 23:22:39 +02:00
|
|
|
*/
|
2015-04-11 01:44:37 +02:00
|
|
|
void irq_disable(unsigned int irq)
|
|
|
|
{
|
2015-07-28 20:39:12 +02:00
|
|
|
if (irq < CONFIG_IOAPIC_NUM_RTES) {
|
2015-04-11 01:44:37 +02:00
|
|
|
_ioapic_irq_disable(irq);
|
|
|
|
} else {
|
2015-07-28 20:39:12 +02:00
|
|
|
_loapic_irq_disable(irq - CONFIG_IOAPIC_NUM_RTES);
|
2015-04-11 01:44:37 +02:00
|
|
|
}
|
|
|
|
}
|