612 lines
19 KiB
C
612 lines
19 KiB
C
/* ioApicIntr.c - Intel IO APIC/xAPIC driver */
|
|
|
|
/*
|
|
* Copyright (c) 1997-1998, 2000-2002, 2004, 2006-2008, 2011-2015 Wind River
|
|
*Systems, Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1) Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2) Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3) Neither the name of Wind River Systems nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
DESCRIPTION
|
|
This module is a driver for the IO APIC/xAPIC (Advanced Programmable
|
|
Interrupt Controller) for P6 (PentiumPro, II, III) family processors
|
|
and P7 (Pentium4) family processors. The IO APIC/xAPIC is included
|
|
in the Intel's system chip set, such as ICH2. Software intervention
|
|
may be required to enable the IO APIC/xAPIC in some chip sets.
|
|
The 8259A interrupt controller is intended for use in a uni-processor
|
|
system, IO APIC can be used in either a uni-processor or multi-processor
|
|
system. The IO APIC handles interrupts very differently than the 8259A.
|
|
Briefly, these differences are:
|
|
- Method of Interrupt Transmission. The IO APIC transmits interrupts
|
|
through a 3-wire bus and interrupts are handled without the need for
|
|
the processor to run an interrupt acknowledge cycle.
|
|
- Interrupt Priority. The priority of interrupts in the IO APIC is
|
|
independent of the interrupt number. For example, interrupt 10 can
|
|
be given a higher priority than interrupt 3.
|
|
- More Interrupts. The IO APIC supports a total of 24 interrupts.
|
|
|
|
The IO APIC unit consists of a set of interrupt input signals, a 24-entry
|
|
by 64-bit Interrupt Redirection Table, programmable registers, and a message
|
|
unit for sending and receiving APIC messages over the APIC bus or the
|
|
Front-Side (system) bus. IO devices inject interrupts into the system by
|
|
asserting one of the interrupt lines to the IO APIC. The IO APIC selects the
|
|
corresponding entry in the Redirection Table and uses the information in that
|
|
entry to format an interrupt request message. Each entry in the Redirection
|
|
Table can be individually programmed to indicate edge/level sensitive interrupt
|
|
signals, the interrupt vector and priority, the destination processor, and how
|
|
the processor is selected (statically and dynamically). The information in
|
|
the table is used to transmit a message to other APIC units (via the APIC bus
|
|
or the Front-Side (system) bus). IO APIC is used in the Symmetric IO Mode.
|
|
The base address of IO APIC is determined in loapic_init() and stored in the
|
|
global variable ioApicBase and ioApicData.
|
|
The lower 32 bit value of the redirection table entries for IRQ 0
|
|
to 15 are edge triggered positive high, and for IRQ 16 to 23 are level
|
|
triggered positive low.
|
|
|
|
This implementation doesn't support multiple IO APICs.
|
|
|
|
INCLUDE FILES: ioapic.h loapic.h
|
|
|
|
SEE ALSO: loApicIntr.c
|
|
*/
|
|
|
|
/* includes */
|
|
|
|
#include <nanokernel.h>
|
|
#include <nanokernel/cpu.h>
|
|
|
|
#include "board.h"
|
|
|
|
#include <toolchain.h>
|
|
#include <sections.h>
|
|
|
|
#include <drivers/ioapic.h> /* public API declarations */
|
|
#include <drivers/loapic.h> /* public API declarations and registers */
|
|
|
|
/* defines */
|
|
|
|
/* IO APIC direct register offsets */
|
|
|
|
#define IOAPIC_IND 0x00 /* Index Register */
|
|
#define IOAPIC_DATA 0x10 /* IO window (data) - pc.h */
|
|
#define IOAPIC_IRQPA 0x20 /* IRQ Pin Assertion Register */
|
|
#define IOAPIC_EOI 0x40 /* EOI Register */
|
|
|
|
#ifdef IOAPIC_MSI_REDIRECT
|
|
|
|
/* direct addressing of the RTEs; including the "configuration register" */
|
|
|
|
#define IOAPIC_RTE0_LOW 0x1000
|
|
#define IOAPIC_RTE0_HIGH 0x1004
|
|
#define IOAPIC_RTE0_CONFIG 0x1008
|
|
#define IOAPIC_RTE1_LOW 0x1010
|
|
#define IOAPIC_RTE1_HIGH 0x1014
|
|
#define IOAPIC_RTE1_CONFIG 0x1018
|
|
#define IOAPIC_RTE2_LOW 0x1020
|
|
#define IOAPIC_RTE2_HIGH 0x1024
|
|
#define IOAPIC_RTE2_CONFIG 0x1028
|
|
|
|
/*
|
|
* etc., etc. until IOAPIC_RTE63_LOW/IOAPIC_RTE63_HIGH/IOAPIC_RTE63_CONFIG
|
|
*
|
|
* rteLowOffset = IOAPIC_RTE0_LOW + (irq * 0x10)
|
|
* rteHighOffset = IOAPIC_RTE0_HIGH + (irq * 0x10)
|
|
* rteConfigOffset = IOAPIC_RTE0_CONFIG + (irq * 0x10)
|
|
*/
|
|
|
|
/*
|
|
* An extention to the "standard" IOAPIC design supports a redirection
|
|
* capability that allows each RTE to specify which of the 8 "redirection
|
|
* registers" to use for determining the MSI address.
|
|
*/
|
|
|
|
#define IOAPIC_REDIR_ADDR0 0x2000 /* Dummy entry; reads return all 0's */
|
|
#define IOAPIC_REDIR_ADDR1 0x2004 /* MSI redirection selection reg 1 */
|
|
#define IOAPIC_REDIR_ADDR2 0x2008 /* MSI redirection selection reg 2 */
|
|
#define IOAPIC_REDIR_ADDR3 0x200c /* MSI redirection selection reg 3 */
|
|
#define IOAPIC_REDIR_ADDR4 0x2010 /* MSI redirection selection reg 4 */
|
|
#define IOAPIC_REDIR_ADDR5 0x2014 /* MSI redirection selection reg 5 */
|
|
#define IOAPIC_REDIR_ADDR6 0x2018 /* MSI redirection selection reg 6 */
|
|
#define IOAPIC_REDIR_ADDR7 0x201c /* MSI redirection selection reg 7 */
|
|
|
|
/* interrupt status for line interrupts generated via RTE0 through RTE31 */
|
|
|
|
#define IOAPIC_LINE_INT_STAT0 0x2040
|
|
|
|
/* interrupt status for line interrupts generated via RTE32 through RTE64 */
|
|
|
|
#define IOAPIC_LINE_INT_STAT1 0x2044
|
|
|
|
/* interrupt mask for line interrupts generated via RTE0 to RTE31 */
|
|
|
|
#define IOAPIC_LINE_INT_MASK0 0x2048
|
|
|
|
/* interrupt mask for line interrupts generated via RTE32 to RTE63 */
|
|
|
|
#define IOAPIC_LINE_INT_MASK1 0x204c
|
|
|
|
#endif /* IOAPIC_MSI_REDIRECT */
|
|
|
|
/* IO APIC indirect register offset */
|
|
|
|
#define IOAPIC_ID 0x00 /* IOAPIC ID */
|
|
#define IOAPIC_VERS 0x01 /* IOAPIC Version */
|
|
#define IOAPIC_ARB 0x02 /* IOAPIC Arbitration ID */
|
|
#define IOAPIC_BOOT 0x03 /* IOAPIC Boot Configuration */
|
|
#define IOAPIC_REDTBL 0x10 /* Redirection Table (24 * 64bit) */
|
|
|
|
/* Interrupt delivery type */
|
|
|
|
#define IOAPIC_DT_APIC 0x0 /* APIC serial bus */
|
|
#define IOAPIC_DT_FS 0x1 /* Front side bus message*/
|
|
|
|
/* Version register bits */
|
|
|
|
#define IOAPIC_MRE_MASK 0x00ff0000 /* Max Red. entry mask */
|
|
#define IOAPIC_PRQ 0x00008000 /* this has IRQ reg */
|
|
#define IOAPIC_VERSION 0x000000ff /* version number */
|
|
|
|
/* Redirection table entry number */
|
|
|
|
#define MAX_REDTABLE_ENTRIES 24
|
|
|
|
/* Redirection table entry bits: upper 32 bit */
|
|
|
|
#define IOAPIC_DESTINATION 0xff000000
|
|
|
|
/* Redirection table entry bits: lower 32 bit */
|
|
|
|
#define IOAPIC_VEC_MASK 0x000000ff
|
|
|
|
#ifdef IOAPIC_MSI_REDIRECT
|
|
|
|
/* RTE configuration register bits */
|
|
|
|
#define IOAPIC_RTE_CONFIG_REDIR_SEL 0x7
|
|
#define IOAPIC_RTE_CONFIG_LI0EN 0x8
|
|
#define IOAPIC_RTE_CONFIG_LI1EN 0x10
|
|
#define IOAPIC_RTE_CONFIG_LI2EN 0x20
|
|
#define IOAPIC_RTE_CONFIG_BYPASS_MSI_DISABLE 0x40
|
|
#define IOAPIC_RTE_CONFIG_DISABLE_INT_EXT 0x80
|
|
|
|
#endif /* IOAPIC_MSI_REDIRECT */
|
|
|
|
/* forward declarations */
|
|
|
|
#ifndef XIOAPIC_DIRECT_ADDRESSING
|
|
static uint32_t __IoApicGet(int32_t offset);
|
|
static void __IoApicSet(int32_t offset, uint32_t value);
|
|
#endif
|
|
|
|
static void ioApicRedSetHi(unsigned int irq, uint32_t upper32);
|
|
static void ioApicRedSetLo(unsigned int irq, uint32_t lower32);
|
|
static uint32_t ioApicRedGetLo(unsigned int irq);
|
|
static void _IoApicRedUpdateLo(unsigned int irq, uint32_t value,
|
|
uint32_t mask);
|
|
|
|
/*
|
|
* The functions irq_enable() and irq_disable() are implemented
|
|
* in the BSPs that incorporate this interrupt controller driver due to the
|
|
* IRQ virtualization imposed by the BSP.
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _ioapic_init - initialize the IO APIC or xAPIC
|
|
*
|
|
* This routine initializes the IO APIC or xAPIC.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
void _ioapic_init(void)
|
|
{
|
|
int32_t ix; /* redirection table index */
|
|
uint32_t rteValue; /* value to copy into redirection table entry */
|
|
|
|
#ifdef IOAPIC_MSI_REDIRECT
|
|
_IoApicRedirRegSet(MSI_REDIRECT_SELECT_ID, MSI_REDIRECT_TARGET_ADDR);
|
|
#endif
|
|
|
|
/*
|
|
* The BSP must define the IOAPIC_NUM_RTES macro to indicate the number
|
|
* of redirection table entries supported by the IOAPIC on the board.
|
|
*
|
|
* Note: The number of actual IRQs supported by the IOAPIC can be
|
|
*determined
|
|
* at runtime by computing:
|
|
*
|
|
* ((__IoApicGet(IOAPIC_VERS) & IOAPIC_MRE_MASK) >> 16) + 1
|
|
*
|
|
* however, storing the number of IRQs supported in a nanokernel global
|
|
* variable is not feasible since any references to this global variable
|
|
* from a microkernel-split image would not be able to directly access
|
|
*the
|
|
* variable; access via an indirection would be needed.
|
|
*/
|
|
|
|
/*
|
|
* Initialize the redirection table entries with default settings;
|
|
* actual interrupt vectors are specified during irq_connect().
|
|
*
|
|
* A future enhancement should make this initialization "table driven":
|
|
* use data provided by a BSP to specify the initial state
|
|
*/
|
|
|
|
rteValue = IOAPIC_EDGE | IOAPIC_HIGH | IOAPIC_FIXED | IOAPIC_INT_MASK |
|
|
IOAPIC_PHYSICAL | 0 /* dummy vector */;
|
|
|
|
for (ix = 0; ix < IOAPIC_NUM_RTES; ix++) {
|
|
ioApicRedSetHi(ix, 0);
|
|
ioApicRedSetLo(ix, rteValue);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _ioapic_eoi - send EOI (End Of Interrupt) signal to IO APIC
|
|
*
|
|
* This routine sends an EOI signal to the IO APIC's interrupting source.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
void _ioapic_eoi(unsigned int irq /* INT number to send EOI */
|
|
)
|
|
{
|
|
*(volatile unsigned int *)(IOAPIC_BASE_ADRS + IOAPIC_EOI) = irq;
|
|
*(volatile unsigned int *)(LOAPIC_BASE_ADRS + LOAPIC_EOI) = 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _ioapic_eoi_get - get EOI (End Of Interrupt) information
|
|
*
|
|
* This routine returns EOI signalling information for a specific IRQ.
|
|
*
|
|
* RETURNS: address of routine to be called to signal EOI;
|
|
* as a side effect, also passes back indication if routine requires
|
|
* an interrupt vector argument and what the argument value should be
|
|
*/
|
|
|
|
void *_ioapic_eoi_get(unsigned int irq, /* INTIN number of interest */
|
|
char *argRequired, /* ptr to "argument required" result
|
|
area */
|
|
void **arg /* ptr to "argument value" result area */
|
|
)
|
|
{
|
|
#ifndef XIOAPIC_DIRECT_ADDRESSING
|
|
if (!(__IoApicGet(IOAPIC_VERS) & IOAPIC_PRQ)) {
|
|
*argRequired = 0;
|
|
return _loapic_eoi;
|
|
}
|
|
#endif
|
|
|
|
/* indicate that an argument to the EOI handler is required */
|
|
|
|
*argRequired = 1;
|
|
|
|
/*
|
|
* The parameter to the ioApicIntEoi() routine is the vector programmed
|
|
* into the redirection table. The BSPs _SysIntVecAlloc() routine
|
|
* must invoke _IoApicIntEoiGet() after _IoApicRedVecSet() to ensure the
|
|
* redirection table contains the desired interrupt vector.
|
|
*/
|
|
|
|
*arg = (void *)(ioApicRedGetLo(irq) & IOAPIC_VEC_MASK);
|
|
|
|
return _ioapic_eoi;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _ioapic_irq_enable - enable a specified APIC interrupt input line
|
|
*
|
|
* This routine enables a specified APIC interrupt input line.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
void _ioapic_irq_enable(unsigned int irq /* INTIN number to enable */
|
|
)
|
|
{
|
|
_IoApicRedUpdateLo(irq, 0, IOAPIC_INT_MASK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _ioapic_irq_disable - disable a specified APIC interrupt input line
|
|
*
|
|
* This routine disables a specified APIC interrupt input line.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
void _ioapic_irq_disable(unsigned int irq /* INTIN number to disable */
|
|
)
|
|
{
|
|
_IoApicRedUpdateLo(irq, IOAPIC_INT_MASK, IOAPIC_INT_MASK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _ioapic_irq_set - programs the interrupt redirection table
|
|
*
|
|
* This routine sets up the redirection table entry for the specified IRQ
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
void _ioapic_irq_set(unsigned int irq, /* virtualized IRQ */
|
|
unsigned int vector, /* vector number */
|
|
uint32_t flags /* interrupt flags */
|
|
)
|
|
{
|
|
uint32_t rteValue; /* value to copy into redirection table entry */
|
|
|
|
rteValue = IOAPIC_FIXED | IOAPIC_INT_MASK | IOAPIC_PHYSICAL |
|
|
(vector & IOAPIC_VEC_MASK) | flags;
|
|
ioApicRedSetHi(irq, 0);
|
|
ioApicRedSetLo(irq, rteValue);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _ioapic_int_vec_set - program interrupt vector for specified irq
|
|
*
|
|
* The routine writes the interrupt vector in the Interrupt Redirection
|
|
* Table for specified irq number
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
void _ioapic_int_vec_set(unsigned int irq, /* INT number */
|
|
unsigned int vector /* vector number */
|
|
)
|
|
{
|
|
_IoApicRedUpdateLo(irq, vector, IOAPIC_VEC_MASK);
|
|
}
|
|
|
|
#ifndef XIOAPIC_DIRECT_ADDRESSING
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* __IoApicGet - read a 32 bit IO APIC register
|
|
*
|
|
* This routine reads the specified IO APIC register using indirect addressing.
|
|
*
|
|
* RETURNS: register value
|
|
*/
|
|
|
|
static uint32_t __IoApicGet(
|
|
int32_t offset /* register offset (8 bits) */
|
|
)
|
|
{
|
|
uint32_t value; /* value */
|
|
int key; /* interrupt lock level */
|
|
|
|
/* lock interrupts to ensure indirect addressing works "atomically" */
|
|
|
|
key = irq_lock();
|
|
|
|
*((volatile char *)(IOAPIC_BASE_ADRS + IOAPIC_IND)) = (char)offset;
|
|
value = *((volatile uint32_t *)(IOAPIC_BASE_ADRS + IOAPIC_DATA));
|
|
|
|
irq_unlock(key);
|
|
|
|
return value;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* __IoApicSet - write a 32 bit IO APIC register
|
|
*
|
|
* This routine writes the specified IO APIC register using indirect addressing.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
static void __IoApicSet(
|
|
int32_t offset, /* register offset (8 bits) */
|
|
uint32_t value /* value to set the register */
|
|
)
|
|
{
|
|
int key; /* interrupt lock level */
|
|
|
|
/* lock interrupts to ensure indirect addressing works "atomically" */
|
|
|
|
key = irq_lock();
|
|
|
|
*(volatile char *)(IOAPIC_BASE_ADRS + IOAPIC_IND) = (char)offset;
|
|
*((volatile uint32_t *)(IOAPIC_BASE_ADRS + IOAPIC_DATA)) = value;
|
|
|
|
irq_unlock(key);
|
|
}
|
|
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ioApicRedGetLo - get low 32 bits of Redirection Table entry
|
|
*
|
|
* This routine reads the low-order 32 bits of a Redirection Table entry.
|
|
*
|
|
* RETURNS: 32 low-order bits
|
|
*/
|
|
|
|
static uint32_t ioApicRedGetLo(unsigned int irq /* INTIN number */
|
|
)
|
|
{
|
|
#ifdef XIOAPIC_DIRECT_ADDRESSING
|
|
volatile uint32_t *pEntry; /* pointer to redirection table entry */
|
|
|
|
pEntry = (volatile uint32_t *)(IOAPIC_BASE_ADRS + (irq * 0x10) +
|
|
IOAPIC_RTE0_LOW);
|
|
|
|
return *pEntry;
|
|
#else
|
|
int32_t offset = IOAPIC_REDTBL + (irq << 1); /* register offset */
|
|
|
|
return __IoApicGet(offset);
|
|
#endif
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ioApicRedSetLo - set low 32 bits of Redirection Table entry
|
|
*
|
|
* This routine writes the low-order 32 bits of a Redirection Table entry.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
static void ioApicRedSetLo(unsigned int irq, /* INTIN number */
|
|
uint32_t lower32 /* value to be written */
|
|
)
|
|
{
|
|
#ifdef XIOAPIC_DIRECT_ADDRESSING
|
|
volatile uint32_t *pEntry; /* pointer to redirection table entry */
|
|
|
|
pEntry = (volatile uint32_t *)(IOAPIC_BASE_ADRS + (irq * 0x10) +
|
|
IOAPIC_RTE0_LOW);
|
|
|
|
*pEntry = lower32;
|
|
#else
|
|
int32_t offset = IOAPIC_REDTBL + (irq << 1); /* register offset */
|
|
|
|
__IoApicSet(offset, lower32);
|
|
#endif
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ioApicRedSetHi - set high 32 bits of Redirection Table entry
|
|
*
|
|
* This routine writes the high-order 32 bits of a Redirection Table entry.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
static void ioApicRedSetHi(unsigned int irq, /* INTIN number */
|
|
uint32_t upper32 /* value to be written */
|
|
)
|
|
{
|
|
#ifdef XIOAPIC_DIRECT_ADDRESSING
|
|
volatile uint32_t *pEntry; /* pointer to redirection table entry */
|
|
|
|
pEntry = (volatile uint32_t *)(IOAPIC_BASE_ADRS + (irq * 0x10) +
|
|
IOAPIC_RTE0_HIGH);
|
|
|
|
*pEntry = upper32;
|
|
#else
|
|
int32_t offset = IOAPIC_REDTBL + (irq << 1) + 1; /* register offset */
|
|
|
|
__IoApicSet(offset, upper32);
|
|
#endif
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _IoApicRedUpdateLo - modify low 32 bits of Redirection Table entry
|
|
*
|
|
* This routine modifies selected portions of the low-order 32 bits of a
|
|
* Redirection Table entry, as indicated by the associate bit mask.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
static void _IoApicRedUpdateLo(
|
|
unsigned int irq, /* INTIN number */
|
|
uint32_t value, /* value to be written */
|
|
uint32_t mask /* mask of bits to be modified */
|
|
)
|
|
{
|
|
ioApicRedSetLo(irq, (ioApicRedGetLo(irq) & ~mask) | (value & mask));
|
|
}
|
|
|
|
#ifdef IOAPIC_MSI_REDIRECT
|
|
|
|
/*
|
|
* A BSP's board.h file is responsible for setting the IOAPIC_MSI_REDIRECT
|
|
* macro if the I/O APIC supports the MSI redirect capability.
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _IoApicRteConfigSet - write to the RTE config register for specified IRQ
|
|
*
|
|
* This routine writes the specified 32-bit <value> into the RTE configuration
|
|
* register for the specified <irq> (0 to (IOAPIC_NUM_RTES - 1))
|
|
*
|
|
* RETURNS: void
|
|
*/
|
|
|
|
static void _IoApicRteConfigSet(unsigned int irq, /* INTIN number */
|
|
uint32_t value /* value to be written */
|
|
)
|
|
{
|
|
unsigned int offset; /* register offset */
|
|
|
|
#ifdef DEBUG
|
|
if (irq >= IOAPIC_NUM_RTES)
|
|
return; /* do nothing if <irq> is invalid */
|
|
#endif
|
|
|
|
offset = IOAPIC_RTE0_CONFIG + (irq * 0x10);
|
|
|
|
/* use direct addressing when writing to RTE config register */
|
|
|
|
*((volatile uint32_t *)(IOAPIC_BASE_ADRS + offset)) = value;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _IoApicRedirRegSet - write to the specified MSI redirection register
|
|
*
|
|
* This routine writes the 32-bit <value> into the redirection register
|
|
* specified by <reg>.
|
|
*
|
|
* RETURNS: void
|
|
*/
|
|
|
|
static void _IoApicRedirRegSet(unsigned int reg, uint32_t value)
|
|
{
|
|
unsigned int offset; /* register offset */
|
|
|
|
#ifdef DEBUG
|
|
if ((reg > 7) || (reg == 0))
|
|
return; /* do nothing if <reg> is invalid */
|
|
#endif
|
|
|
|
offset = IOAPIC_REDIR_ADDR0 + (reg * 4);
|
|
|
|
/* use direct addressing when writing to RTE config register */
|
|
|
|
*((volatile uint32_t *)(IOAPIC_BASE_ADRS + offset)) = value;
|
|
}
|
|
|
|
#endif /* IOAPIC_MSI_REDIRECT */
|