original files of m241
This commit is contained in:
@@ -0,0 +1,635 @@
|
||||
/* ambaIntrCtl.c - AMBA interrupt controller driver */
|
||||
|
||||
/* Copyright 1984-2005, Wind River Systems, Inc. */
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01k,01apr05,rec rmove warnings
|
||||
01j,09feb05,rec fix manual autogenerate format problems
|
||||
01i,03dec01,rec fix compiler warnings
|
||||
01h,21sep98,cdp fixed intEnable/Disable(0) (TSR#115062);
|
||||
corrected range check in ambaIntLvlEnable/Disable;
|
||||
made AMBA_INT_CSR_MASK optional;
|
||||
added configurable interrupt priorities.
|
||||
01f,10mar98,jpd layout tidying.
|
||||
01e,13nov97,cdp include intLib.h and remove things pulled in from it;
|
||||
make default I/O access 32 (not 16) bits wide; documentation.
|
||||
01d,15aug97,cdp rewritten for new interrupt structure (template 01d).
|
||||
01c,14may97,jpd added conditional use of valid interrupts mask.
|
||||
01b,18feb97,cdp renamed sysIntEnable/Disable and made global with result.
|
||||
Tidyup for mangen. intEnable/Disable now return int.
|
||||
01a,13dec96,cdp created from target/config/pid7t/intPid.c.
|
||||
*/
|
||||
|
||||
/*
|
||||
This module implements the AMBA interrupt controller driver.
|
||||
|
||||
The AMBA interrupt controller is a simple, generic interrupt controller
|
||||
described in full in the ARM Reference Peripherals Specification. The
|
||||
interrupt controller has status and request registers, separate enable
|
||||
and disable registers and supports level-sensitive interrupts. This
|
||||
library provides the routines to manage interrupts multiplexed by the
|
||||
AMBA interrupt controller.
|
||||
|
||||
The AMBA interrupt controller has a number of registers. Those used by
|
||||
this driver are described below under the symbolic names used herein.
|
||||
|
||||
AMBA_INT_CSR_ENB (write): this is the "Enable Set" register described
|
||||
in the ARM Reference Peripherals Specification. When this register is
|
||||
written, each data bit that is set (1) causes the corresponding
|
||||
interrupt to be enabled. Bits that are clear (0) have no effect.
|
||||
|
||||
AMBA_INT_CSR_DIS (write): this is the "Enable Clear" register which has
|
||||
the opposite effect. When this register is written, each data bit that
|
||||
is set (1) causes the corresponding interrupt to be disabled. Bits
|
||||
that are clear (0) have no effect.
|
||||
|
||||
AMBA_INT_CSR_PEND (read): this is the "Interrupt Request" register.
|
||||
When this register is read, each data bit that is set (1) indicates an
|
||||
interrupt source that is both active and enabled i.e. can interrupt the
|
||||
processor. This driver provides a means by which bits in this register
|
||||
can be masked if the particular implementation of AMBA returns bits in
|
||||
an undefined state. Setting AMBA_INT_CSR_MASK to be a bitwise OR of
|
||||
all the valid bits achieves the required effect. If
|
||||
AMBA_INT_PRIORITY_MAP is not #defined (see below), the driver also uses
|
||||
an external array ambaIntLvlMask[] to determine what should be written
|
||||
to AMBA_INT_CSR_ENB to change interrupt levels. This should be defined
|
||||
by the BSP such that ambaIntLvlMask[n] has a bit set (1) for each
|
||||
interrupt source that should be enabled for interrupt level <n>. For
|
||||
example, ambaIntLvlMask[0] should be 0 so that all interrupts are
|
||||
disabled when interrupt level 0 is selected.
|
||||
|
||||
The number of interrupts supported by the device i.e. the number of
|
||||
bits in the AMBA_INT_CSR_PEND register, is specified by
|
||||
AMBA_INT_NUM_LEVELS.
|
||||
|
||||
We assume that config.h or <bsp>.h has defined the addresses of the
|
||||
controller chips registers: AMBA_INT_CSR_ENB, AMBA_INT_CSR_DIS and
|
||||
AMBA_INT_CSR_PEND and also the driver constants AMBA_INT_CSR_MASK (if
|
||||
required) and AMBA_INT_NUM_LEVELS.
|
||||
|
||||
This driver assumes that the chip is memory-mapped and does direct
|
||||
memory accesses to the registers which are assumed to be 32 bits wide.
|
||||
If a different access method is needed, the BSP can redefine the macros
|
||||
AMBA_INT_REG_READ(addr,result) and AMBA_INT_REG_WRITE(addr,data).
|
||||
|
||||
This driver assumes that interrupt vector numbers are calculated and
|
||||
not the result of a special cycle on the bus. Vector numbers are
|
||||
generated by adding the current interrupt level number to
|
||||
AMBA_INT_VEC_BASE to generate a vector number which the architecture
|
||||
level will use to invoke the proper handling routine. If a different
|
||||
mapping scheme, or a special hardware routine is needed, then the BSP
|
||||
should redefine the macro AMBA_INT_LVL_VEC_MAP(level,vector) to
|
||||
override the version defined in this file.
|
||||
|
||||
This driver was designed to support a single instance of a real
|
||||
device. At some point it should be upgraded to operate on an object
|
||||
model and to support any number of real devices.
|
||||
|
||||
Priorities
|
||||
==========
|
||||
The order of interrupt level priority is undefined at the architecture
|
||||
level. In this driver, level 0 is highest and and indicates that all
|
||||
levels are disabled; level <AMBA_INT_NUM_LEVELS> is the lowest and
|
||||
indicates that all levels are enabled.
|
||||
|
||||
By default, this driver implements a least-significant bit first
|
||||
interrupt priority scheme (this is compatible with earlier versions of
|
||||
this driver) which requires a definition of ambaIntLvlMask (see above).
|
||||
If required, the driver can be compiled to implement a BSP-configurable
|
||||
interrupt priority scheme by #defining AMBA_INT_PRIORITY_MAP. For this
|
||||
model, the BSP should define an array of int called ambaIntLvlPriMap,
|
||||
each element of which is a bit number to be polled. The list should be
|
||||
terminated with an entry containing -1. This list is used in the
|
||||
interrupt handler to check bits in the requested order and is also used
|
||||
to generate a map of interrupt source to new interrupt level such that
|
||||
whilst servicing an interrupt, all interrupts defined by the BSP to be
|
||||
of lower priority than that interrupt are disabled. Interrupt sources
|
||||
not in the list are serviced after all others in least-significant bit
|
||||
first priority. (Note that the list is a list of ints rather than
|
||||
bytes because it causes the current compiler to generate faster code.)
|
||||
|
||||
Note that in this priority system, intLevelSet(n) does not necessarily
|
||||
disable interrupt bit n and all lower-priority ones but uses
|
||||
ambaIntLvlPriMap to determine which interrupts should be masked e.g.
|
||||
if ambaIntLvlPriMap[] contains { 9, 4, 8, 5, -1 }, intLevelSet(0)
|
||||
disables all interrupt bits; intLevelSet(1) enables interrupt bit 9 but
|
||||
disables interrupts 4, 8, 5 and all others not listed; intLevelSet(3)
|
||||
enables interrupt bits 9, 4 and 8 but disables all others. This
|
||||
enabling of interrupts only occurs if the interrupt has been explicitly
|
||||
enabled via a call to ambaIntLvlEnable().
|
||||
|
||||
If the list is empty (contains just a terminator) or ambaIntLvlPriMap
|
||||
is declared as an int pointer of value 0 (this is more efficient),
|
||||
interrupts are handled as least-significant bit is highest priority.
|
||||
|
||||
The BSP will initialize this driver in sysHwInit2(), after initializing
|
||||
the main interrupt library, usually intLibInit(). The initialization
|
||||
routine, ambaIntDevInit() will setup the interrupt controller device,
|
||||
it will mask off all individual interrupt sources and then set the
|
||||
interrupt level to enable all interrupts. See ambaIntDevInit for more
|
||||
information.
|
||||
|
||||
All of the functions in this library are global. This allows them to
|
||||
be used by the BSP if it is necessary to create wrapper routines or to
|
||||
incorporate several drivers together as one.
|
||||
*/
|
||||
|
||||
#include "vxWorks.h"
|
||||
#include "config.h"
|
||||
#include "intLib.h"
|
||||
|
||||
IMPORT int ffsLsb (UINT32);
|
||||
|
||||
|
||||
/* Defines from config.h, or <bsp>.h */
|
||||
|
||||
#if !defined (AMBA_INT_CSR_PEND) || !defined (AMBA_INT_CSR_ENB) || \
|
||||
!defined (AMBA_INT_NUM_LEVELS) || !defined (AMBA_INT_CSR_DIS)
|
||||
# error missing AMBA interrupt definitions
|
||||
#endif
|
||||
|
||||
#define AMBA_INT_VEC_BASE (0x0)
|
||||
|
||||
|
||||
/* hardware access methods */
|
||||
|
||||
#ifndef AMBA_INT_REG_READ
|
||||
#define AMBA_INT_REG_READ(reg,result) \
|
||||
((result) = *(volatile UINT32 *)(reg))
|
||||
#endif /*AMBA_INT_REG_READ*/
|
||||
|
||||
#ifndef AMBA_INT_REG_WRITE
|
||||
#define AMBA_INT_REG_WRITE(reg,data) \
|
||||
(*((volatile UINT32 *)(reg)) = (data))
|
||||
#endif /*AMBA_INT_REG_WRITE*/
|
||||
|
||||
|
||||
/* Convert level number to vector number */
|
||||
|
||||
#ifndef AMBA_INT_LVL_VEC_MAP
|
||||
#define AMBA_INT_LVL_VEC_MAP(level, vector) \
|
||||
((vector) = ((level) + AMBA_INT_VEC_BASE))
|
||||
#endif /* AMBA_INT_LVL_VEC_MAP */
|
||||
|
||||
|
||||
#ifndef AMBA_INT_PRIORITY_MAP
|
||||
/* Convert pending register value, to a level number */
|
||||
|
||||
#ifndef AMBA_INT_PEND_LVL_MAP
|
||||
#define AMBA_INT_PEND_LVL_MAP(pendReg, level) \
|
||||
((level) = (pendReg))
|
||||
#endif /* AMBA_INT_PEND_LVL_MAP */
|
||||
#endif /* AMBA_INT_PRIORITY_MAP */
|
||||
|
||||
|
||||
/* driver constants */
|
||||
|
||||
#define AMBA_INT_ALL_ENABLED (AMBA_INT_NUM_LEVELS)
|
||||
#define AMBA_INT_ALL_DISABLED 0
|
||||
|
||||
|
||||
/* Local data */
|
||||
|
||||
/* Current interrupt level setting (ambaIntLvlChg). */
|
||||
|
||||
LOCAL UINT32 ambaIntLvlCurrent = AMBA_INT_ALL_DISABLED; /* all levels disabled*/
|
||||
|
||||
/*
|
||||
* A mask word. Bits are set in this word when a specific level
|
||||
* is enabled. It is used to mask off individual levels that have
|
||||
* not been explicitly enabled.
|
||||
*/
|
||||
|
||||
LOCAL UINT32 ambaIntLvlEnabled;
|
||||
|
||||
|
||||
#ifdef AMBA_INT_PRIORITY_MAP
|
||||
/*
|
||||
* Controller masks: for each interrupt level, this provides a mask for
|
||||
* the controller (see IntLvlChg).
|
||||
* Mask is 32 bits * (levels + 1)
|
||||
*/
|
||||
|
||||
LOCAL UINT32 ambaIntLvlMask[(1 + AMBA_INT_NUM_LEVELS) * sizeof(UINT32)];
|
||||
|
||||
|
||||
/*
|
||||
* Map of interrupt bit number to level: if bit n is set, ambaIntLvlMap[n]
|
||||
* is the interrupt level to change to such that interrupt n and all lower
|
||||
* priority ones are disabled.
|
||||
*/
|
||||
|
||||
LOCAL int ambaIntLvlMap[AMBA_INT_NUM_LEVELS * sizeof(int)];
|
||||
#endif /* AMBA_INT_PRIORITY_MAP */
|
||||
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
STATUS ambaIntLvlVecChk (int*, int*);
|
||||
STATUS ambaIntLvlVecAck (int, int);
|
||||
int ambaIntLvlChg (int);
|
||||
STATUS ambaIntLvlEnable (int);
|
||||
STATUS ambaIntLvlDisable (int);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ambaIntDevInit - initialize the interrupt controller
|
||||
*
|
||||
* This routine will initialize the interrupt controller device, disabling all
|
||||
* interrupt sources. It will also connect the device driver specific routines
|
||||
* into the architecture level hooks. If the BSP needs to create a wrapper
|
||||
* routine around any of the arhitecture level routines, it should install the
|
||||
* pointer to the wrapper routine after calling this routine.
|
||||
*
|
||||
* If used with configurable priorities (#define AMBA_INT_PRIORITY_MAP),
|
||||
* before this routine is called, ambaIntLvlPriMap should be initialised
|
||||
* as a list of interrupt bits to poll in order of decreasing priority and
|
||||
* terminated by an entry containing -1. If ambaIntLvlPriMap is a null
|
||||
* pointer (or an empty list), the priority scheme used will be
|
||||
* least-significant bit first. This is equivalent to the scheme used if
|
||||
* AMBA_INT_PRIORITY_MAP is not defined but slightly less efficient.
|
||||
*
|
||||
* The return value ERROR indicates that the contents of
|
||||
* ambaIntLvlPriMap (if used) were invalid.
|
||||
*
|
||||
* RETURNS: OK or ERROR if ambaIntLvlPriMap invalid.
|
||||
*/
|
||||
|
||||
int ambaIntDevInit (void)
|
||||
{
|
||||
#ifdef AMBA_INT_PRIORITY_MAP
|
||||
int i, j;
|
||||
int level;
|
||||
UINT32 bit;
|
||||
|
||||
/* if priorities are supplied, validate the supplied list */
|
||||
|
||||
if (ambaIntLvlPriMap != 0)
|
||||
{
|
||||
/* first check the list is terminated (VecChk requires this) */
|
||||
|
||||
for (i = 0; i < AMBA_INT_NUM_LEVELS; ++i)
|
||||
if (ambaIntLvlPriMap[i] == -1)
|
||||
break;
|
||||
|
||||
if (!(i < AMBA_INT_NUM_LEVELS))
|
||||
return ERROR; /* no terminator */
|
||||
|
||||
|
||||
/* now check that all are in range and that there are no duplicates */
|
||||
|
||||
for (i = 0; ambaIntLvlPriMap[i] != -1; ++i)
|
||||
if (ambaIntLvlPriMap[i] < 0 ||
|
||||
ambaIntLvlPriMap[i] >= AMBA_INT_NUM_LEVELS)
|
||||
{
|
||||
return ERROR; /* out of range */
|
||||
}
|
||||
else
|
||||
for (j = i + 1; ambaIntLvlPriMap[j] != -1; ++j)
|
||||
if (ambaIntLvlPriMap[j] == ambaIntLvlPriMap[i])
|
||||
{
|
||||
return ERROR; /* duplicate */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Now initialise the mask array.
|
||||
* For each level (in ascending order), the mask is the mask of the
|
||||
* previous level with the bit for the current level set to enable it.
|
||||
*/
|
||||
|
||||
ambaIntLvlMask[0] = 0; /* mask for level 0 = all disabled */
|
||||
|
||||
|
||||
/* do the levels for which priority has been specified */
|
||||
|
||||
level = 1;
|
||||
if (ambaIntLvlPriMap != 0)
|
||||
{
|
||||
for ( ; level <= AMBA_INT_NUM_LEVELS &&
|
||||
(i = ambaIntLvlPriMap[level - 1], i >= 0); ++level)
|
||||
{
|
||||
/* copy previous level's mask to this one's */
|
||||
|
||||
ambaIntLvlMask[level] = ambaIntLvlMask[level - 1];
|
||||
|
||||
|
||||
/* OR in the bit indicated by the next entry in PriMap[] */
|
||||
|
||||
ambaIntLvlMask[level] |= 1 << i;
|
||||
|
||||
/*
|
||||
* set index in level map: to disable this interrupt and all
|
||||
* lower-priority ones, select the level one less than this
|
||||
*/
|
||||
|
||||
ambaIntLvlMap[i] = level - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* do the rest of the levels */
|
||||
|
||||
i = 0; /* lowest-numbered interrupt bit */
|
||||
|
||||
for ( ; level <= AMBA_INT_NUM_LEVELS; ++level)
|
||||
{
|
||||
/* copy previous level's mask to this one's */
|
||||
|
||||
ambaIntLvlMask[level] = ambaIntLvlMask[level - 1];
|
||||
|
||||
|
||||
/* try to find a bit that has not yet been set */
|
||||
|
||||
for ( ; ; ++i)
|
||||
{
|
||||
bit = 1 << i;
|
||||
|
||||
if ((ambaIntLvlMask[level] & bit) == 0)
|
||||
{
|
||||
/* this bit not set so put it in the mask */
|
||||
|
||||
ambaIntLvlMask[level] |= bit;
|
||||
|
||||
/*
|
||||
* set index in level map: to disable this interrupt and all
|
||||
* lower-priority ones, select the level one less than this
|
||||
*/
|
||||
|
||||
ambaIntLvlMap[i] = level - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* install the driver routines in the architecture hooks */
|
||||
|
||||
sysIntLvlVecChkRtn = ambaIntLvlVecChk;
|
||||
sysIntLvlVecAckRtn = ambaIntLvlVecAck;
|
||||
sysIntLvlChgRtn = ambaIntLvlChg;
|
||||
sysIntLvlEnableRtn = ambaIntLvlEnable;
|
||||
sysIntLvlDisableRtn = ambaIntLvlDisable;
|
||||
|
||||
ambaIntLvlEnabled = 0; /* all sources disabled */
|
||||
|
||||
ambaIntLvlChg (AMBA_INT_ALL_ENABLED); /* enable all levels */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ambaIntLvlVecChk - check for and return any pending interrupts
|
||||
*
|
||||
* This routine interrogates the hardware to determine the highest priority
|
||||
* interrupt pending. It returns the vector associated with that interrupt, and
|
||||
* also the interrupt priority level prior to the interrupt (not the
|
||||
* level of the interrupt). The current interrupt priority level is then
|
||||
* raised to the level of the current interrupt so that only higher priority
|
||||
* interrupts will be accepted until this interrupt is finished.
|
||||
*
|
||||
* This routine must be called with CPU interrupts disabled.
|
||||
*
|
||||
* The return value ERROR indicates that no pending interrupt was found and
|
||||
* that the level and vector values were not returned.
|
||||
*
|
||||
* RETURNS: OK or ERROR if no interrupt is pending.
|
||||
*/
|
||||
|
||||
STATUS ambaIntLvlVecChk
|
||||
(
|
||||
int* pLevel, /* ptr to receive old interrupt level */
|
||||
int* pVector /* ptr to receive current interrupt vector */
|
||||
)
|
||||
{
|
||||
int newLevel;
|
||||
UINT32 isr;
|
||||
#ifdef AMBA_INT_PRIORITY_MAP
|
||||
UINT32 *priPtr;
|
||||
int bitNum;
|
||||
#endif
|
||||
|
||||
|
||||
/* Read pending interrupt register and mask undefined bits */
|
||||
|
||||
AMBA_INT_REG_READ (AMBA_INT_CSR_PEND, isr);
|
||||
#ifdef AMBA_INT_CSR_MASK
|
||||
isr &= AMBA_INT_CSR_MASK;
|
||||
#endif
|
||||
|
||||
/* If no interrupt is pending, return ERROR */
|
||||
|
||||
if (isr == 0)
|
||||
return ERROR;
|
||||
|
||||
|
||||
#ifdef AMBA_INT_PRIORITY_MAP
|
||||
priPtr = (UINT32 *)ambaIntLvlPriMap;
|
||||
|
||||
/* service interrupts according to priority specifed in map */
|
||||
|
||||
while (bitNum = *priPtr++, bitNum != -1)
|
||||
{
|
||||
/* bitNum = interrupt bit from priority map */
|
||||
|
||||
if (isr & (1 << bitNum))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* if priority scan didn't find anything, look for any bit set,
|
||||
* starting with the lowest-numbered bit
|
||||
*/
|
||||
|
||||
if (bitNum == -1)
|
||||
bitNum = ffsLsb (isr) - 1; /* ffsLsb returns numbers from 1, not 0 */
|
||||
|
||||
|
||||
/* if no interrupt is pending, return ERROR */
|
||||
|
||||
if (bitNum == -1)
|
||||
return ERROR;
|
||||
|
||||
|
||||
/* map the interrupting device to an interrupt level number */
|
||||
|
||||
newLevel = ambaIntLvlMap[bitNum];
|
||||
#else
|
||||
/* find first bit set in ISR, starting from lowest-numbered bit */
|
||||
|
||||
if (newLevel = ffsLsb (isr), newLevel == 0)
|
||||
return ERROR;
|
||||
|
||||
--newLevel; /* ffsLsb returns numbers from 1, not 0 */
|
||||
|
||||
|
||||
/* map the interrupting device to an interrupt level number */
|
||||
|
||||
AMBA_INT_PEND_LVL_MAP (newLevel, newLevel);
|
||||
#endif /* ifdef AMBA_INT_PRIORITY_MAP */
|
||||
|
||||
|
||||
/* change to new interrupt level, returning previous level to caller */
|
||||
|
||||
*pLevel = ambaIntLvlChg (newLevel);
|
||||
|
||||
|
||||
/* fetch, or compute the interrupt vector number */
|
||||
|
||||
#ifdef AMBA_INT_PRIORITY_MAP
|
||||
AMBA_INT_LVL_VEC_MAP (bitNum, *pVector);
|
||||
#else
|
||||
AMBA_INT_LVL_VEC_MAP (newLevel, *pVector);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ambaIntLvlVecAck - acknowledge the current interrupt
|
||||
*
|
||||
* Acknowledge the current interrupt cycle. The level and vector values are
|
||||
* those generated during the ambaIntLvlVecChk() routine for this interrupt
|
||||
* cycle. The basic action is to reset the current interrupt and return
|
||||
* the interrupt level to its previous setting. Note that the AMBA interrupt
|
||||
* controller does not need an acknowledge cycle.
|
||||
*
|
||||
* RETURNS: OK or ERROR if a hardware fault is detected.
|
||||
*/
|
||||
|
||||
STATUS ambaIntLvlVecAck
|
||||
(
|
||||
int level, /* old interrupt level to be restored */
|
||||
int vector /* current interrupt vector, if needed */
|
||||
)
|
||||
{
|
||||
/* restore the previous interrupt level */
|
||||
|
||||
ambaIntLvlChg (level);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ambaIntLvlChg - change the interrupt level value
|
||||
*
|
||||
* This routine implements the overall interrupt setting. All levels
|
||||
* up to and including the specifed level are disabled. All levels above
|
||||
* the specified level will be enabled, but only if they were specifically
|
||||
* enabled by the ambaIntLvlEnable() routine.
|
||||
*
|
||||
* The specific priority level AMBA_INT_NUM_LEVELS is valid and represents
|
||||
* all levels enabled.
|
||||
*
|
||||
* RETURNS: Previous interrupt level.
|
||||
*/
|
||||
|
||||
int ambaIntLvlChg
|
||||
(
|
||||
int level /* new interrupt level */
|
||||
)
|
||||
{
|
||||
int oldLevel;
|
||||
|
||||
oldLevel = ambaIntLvlCurrent;
|
||||
|
||||
if (level >= 0 &&
|
||||
level <= AMBA_INT_NUM_LEVELS)
|
||||
{
|
||||
/* change current interrupt level */
|
||||
|
||||
ambaIntLvlCurrent = level;
|
||||
}
|
||||
|
||||
/* Switch off all interrupts */
|
||||
|
||||
AMBA_INT_REG_WRITE (AMBA_INT_CSR_DIS, (UINT32)-1);
|
||||
|
||||
/* Activate the enabled interrupts */
|
||||
|
||||
AMBA_INT_REG_WRITE (AMBA_INT_CSR_ENB,
|
||||
(ambaIntLvlMask[ambaIntLvlCurrent] & ambaIntLvlEnabled));
|
||||
|
||||
return oldLevel;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ambaIntLvlEnable - enable a single interrupt level
|
||||
*
|
||||
* Enable a specific interrupt level. The enabled level will be allowed
|
||||
* to generate an interrupt when the overall interrupt level is set to
|
||||
* enable interrupts of this priority (as configured by ambaIntLvlPriMap,
|
||||
* if appropriate). Without being enabled, the interrupt is blocked
|
||||
* regardless of the overall interrupt level setting.
|
||||
*
|
||||
* RETURNS: OK or ERROR if the specified level cannot be enabled.
|
||||
*/
|
||||
|
||||
STATUS ambaIntLvlEnable
|
||||
(
|
||||
int level /* level to be enabled */
|
||||
)
|
||||
{
|
||||
int key;
|
||||
|
||||
if (level < 0 ||
|
||||
level >= AMBA_INT_NUM_LEVELS)
|
||||
return ERROR;
|
||||
|
||||
|
||||
/* set bit in enable mask */
|
||||
|
||||
key = intLock ();
|
||||
ambaIntLvlEnabled |= (1 << level);
|
||||
intUnlock (key);
|
||||
|
||||
ambaIntLvlChg (-1); /* reset current mask */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ambaIntLvlDisable - disable a single interrupt level
|
||||
*
|
||||
* Disable a specific interrupt level. The disabled level is prevented
|
||||
* from generating an interrupt even if the overall interrupt level is
|
||||
* set to enable interrupts of this priority (as configured by
|
||||
* ambaIntLvlPriMap, if appropriate).
|
||||
*
|
||||
* RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
|
||||
*/
|
||||
|
||||
STATUS ambaIntLvlDisable
|
||||
(
|
||||
int level /* level to be disabled */
|
||||
)
|
||||
{
|
||||
int key;
|
||||
|
||||
if (level < 0 ||
|
||||
level >= AMBA_INT_NUM_LEVELS)
|
||||
return ERROR;
|
||||
|
||||
|
||||
/* clear bit in enable mask */
|
||||
|
||||
key = intLock ();
|
||||
ambaIntLvlEnabled &= ~(1 << level);
|
||||
intUnlock (key);
|
||||
|
||||
ambaIntLvlChg (-1); /* reset current mask */
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -0,0 +1,466 @@
|
||||
/* i82378Ibc.c - Intel i82378 ISA Bridge Controller (IBC) driver */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1984-1996, 2008 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use of this
|
||||
* software may be licensed only pursuant to the terms of an applicable Wind
|
||||
* River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01t,27aug08,jpb Renamed VSB header file
|
||||
01s,18jun08,jpb Added include path for kernel configurations options set in
|
||||
vsb.
|
||||
01r,12may08,jpb Modifications for source build. Renamed
|
||||
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
|
||||
01q,24aug98,cjtc windview 2.0 event logging is now single step. Timestamp no
|
||||
longer stored by intEnt. Avoids out-of-sequence timestamps in
|
||||
event log (SPR 21868)
|
||||
01p,16apr98,pr moved triggering support from arch/ppc
|
||||
01o,05mar98,pr added WV_ON mask to WV 2.0 code
|
||||
01n,22feb98,pr modified windview support for WV 2.0
|
||||
01m,22dec96,tpr removed intUnlock() at the end of sysIbcIntHandler() SPR(#7679)
|
||||
01l,08dec96,tpr changed _func_intEnableRtn() return value from void to int.
|
||||
01o,09jul97,dat fixed SPR 8866, intDisable did not work for lvls 8 to 15.
|
||||
01n,17jan97,mas fixed IRQ number to IRQ level mapping (SPR 7752) and
|
||||
deleted unused SEM_ID extIntHandlerSem.
|
||||
01m,22dec96,tpr removed intUnlock() at the end of sysIbcIntHandler() SPR(#7679)
|
||||
01l,08dec96,tpr changed _func_intEnableRtn() return value from void to int.
|
||||
added sysIbcIntEnable() return value code.
|
||||
01k,30oct96,dat replaced sysInByte and sysOutByte by IBC_BYTE_READ and
|
||||
tam IBC_BYTE_WRITE macros (spr #7415). Added description.
|
||||
01j,29oct96,wlf doc: cleanup.
|
||||
01i,24sep96,mas changed MV1305 to MV1300.
|
||||
01h,23jul96,tam fixed sysIbcIntLevelSet() to mask int. level <intLevel> too
|
||||
01g,08jul96,ms merged in pr's WindView instrumentation
|
||||
01f,01jul96,tam added code to respect interrupt priorities (spr #6212).
|
||||
01e,11jun96,tam fixed sysIbcIntConnect() to enable multiple int. handlers
|
||||
connected to a same vector (spr #6588).
|
||||
01d,05may96,mas fix IBC interrupt mappings for MV1305 vs. ULTRA/MV1600.
|
||||
01c,16apr96,jds fix IBC interrupt mappings for ULTRA vs. MV1600
|
||||
01b,06mar96,tpr clean-up
|
||||
01a,29jan96,tam written from i8259Pic.c.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This module implements the Intel i82378 ISA Bridge Controller (IBC) driver.
|
||||
The i82378 IBC chip includes many functions. This driver only implements
|
||||
the interrupt control functions. In fact this driver provides the
|
||||
complete interrupt architecture functionality (which it shouldn't).
|
||||
|
||||
The macros IBC_BYTE_READ and IBC_BYTE_WRITE control the actual access
|
||||
to the PIC registers. By default, these macros assume memory mapped
|
||||
access to the registers. The default write macro includes an eieio
|
||||
instruction to insure write-ordering is preserved. The BSP can redefine
|
||||
these macros in config.h or <bsp>.h to specify some other access means
|
||||
such as i/o mapping.
|
||||
|
||||
The IBC_BYTE_READ macro takes two arguments, the register address and
|
||||
the data address. Data is read from the register address and stored
|
||||
at the data address. Defining the macro to return a value is not preferred
|
||||
because if the macro has to be defined within a code block, then data
|
||||
cannot easily be returned.
|
||||
|
||||
The IBC_BYTE_WRITE macro also takes two arguments, the register address
|
||||
and the data to be written. Including an eieio instruction after the
|
||||
actual data write is recommended.
|
||||
|
||||
Neither macro returns any values.
|
||||
*/
|
||||
|
||||
#include <vsbConfig.h>
|
||||
|
||||
#include "drv/intrCtl/i82378Ibc.h"
|
||||
#include "private/funcBindP.h"
|
||||
|
||||
/* globals */
|
||||
|
||||
IMPORT UINT sysVectorIRQ0; /* vector for IRQ0 */
|
||||
IMPORT STATUS (*_func_intConnectRtn) (VOIDFUNCPTR *, VOIDFUNCPTR, int);
|
||||
IMPORT int (*_func_intEnableRtn) (int);
|
||||
IMPORT int (*_func_intDisableRtn) (int);
|
||||
IMPORT STATUS excIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR);
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
#include "private/eventP.h"
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
/* system interrupt table */
|
||||
|
||||
INT_HANDLER_DESC * sysIntTbl [256];
|
||||
|
||||
/* locals */
|
||||
|
||||
/* PIC1 & PIC2 IRQ masks ordered by IRQ# */
|
||||
|
||||
UCHAR ibcIRQ2Pic1Mask[16] = {0xFB,0xFA,0xF8,0xF8,0xF0,0xE0,0xC0,0x80,
|
||||
0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8};
|
||||
UCHAR ibcIRQ2Pic2Mask[16] = {0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,
|
||||
0xFF,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80};
|
||||
|
||||
/* forward static functions */
|
||||
|
||||
LOCAL void sysIbcEndOfInt (void);
|
||||
LOCAL STATUS sysIbcIntConnect (VOIDFUNCPTR * vector, VOIDFUNCPTR routine,
|
||||
int parameter);
|
||||
LOCAL int sysIbcIntEnable (int);
|
||||
LOCAL int sysIbcIntDisable (int);
|
||||
LOCAL void sysIbcIntLevelSet (UCHAR intNumber, UCHAR pic1Mask,
|
||||
UCHAR pic2Mask);
|
||||
|
||||
void sysIbcIntHandler (void);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIbcInit - initialize the ISA Bridge Controller
|
||||
*
|
||||
* This routine initializes the Intel i82378 ISA Bridge Controller (IBC).
|
||||
*
|
||||
* RETURNS: OK, always.
|
||||
*/
|
||||
|
||||
STATUS sysIbcInit (void)
|
||||
|
||||
{
|
||||
UINT vector;
|
||||
UCHAR intVec;
|
||||
|
||||
|
||||
/* initialize the interrupt table */
|
||||
|
||||
for (vector = 0; vector < 256; vector++)
|
||||
sysIntTbl[vector] = NULL;
|
||||
|
||||
/* connect the interrupt demultiplexer to the PowerPC external interrupt */
|
||||
|
||||
excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, sysIbcIntHandler);
|
||||
|
||||
#ifdef ULTRA
|
||||
/*
|
||||
* route PCI interrupts to ISA IRQs and other initialization
|
||||
* PCI IRQ0: routed to LN_INT_LVL
|
||||
* PCI IRQ1: routed to NOTHING (no device supported)
|
||||
* PCI IRQ2: routed to SCSI_INT_LVL
|
||||
* PCI IRQ3: routed to NOTHING (no device supported)
|
||||
*/
|
||||
|
||||
*(ULONG *)(CNFG_IBC_ADRS + 0x60) = LONGSWAP((0x00000000 << 24) |
|
||||
(SCSI_INT_LVL << 16) |
|
||||
(0x00000000 << 8) |
|
||||
LN_INT_LVL);
|
||||
|
||||
/* make the IRQ 15,14,11,10, 9 level sensitive */
|
||||
|
||||
(*(char *)i82378_INT2_ELC) = 0x80 | 0x40 | 0x08 | 0x04 | 0x02 ;
|
||||
#endif /* #ifdef ULTRA */
|
||||
|
||||
#ifdef MV1300
|
||||
/*
|
||||
* route PCI interrupts to ISA IRQs and other initialization
|
||||
* PCI IRQ0: routed to NOTHING (no device supported)
|
||||
* PCI IRQ1: routed to VME2PCI_INT_LVL
|
||||
* PCI IRQ2: routed to NOTHING (no device supported)
|
||||
* PCI IRQ3: routed to IRQ15
|
||||
*/
|
||||
|
||||
*(ULONG *)(CNFG_IBC_ADRS + 0x60) = LONGSWAP(0x0f000000 |
|
||||
(0x00000000 << 16) |
|
||||
(VME2PCI_INT_LVL << 8) |
|
||||
0x00000000);
|
||||
|
||||
/* make the IRQ 15,14,11,10, 9 level sensitive */
|
||||
|
||||
(*(char *)i82378_INT2_ELC) = 0x80 | 0x40 | 0x08 | 0x04 | 0x02 ;
|
||||
#endif /* #ifdef MV1300 */
|
||||
|
||||
#ifdef MV1600
|
||||
/*
|
||||
* route PCI interrupts to ISA IRQs and other initialization
|
||||
* PCI IRQ0: routed to LN_INT_LVL
|
||||
* PCI IRQ1: routed to VME2PCI_INT_LVL
|
||||
* PCI IRQ2: routed to SCSI_INT_LVL
|
||||
* PCI IRQ3: routed to IRQ15
|
||||
*/
|
||||
|
||||
*(ULONG *)(CNFG_IBC_ADRS + 0x60) = LONGSWAP(0x0f000000 |
|
||||
(SCSI_INT_LVL << 16) |
|
||||
(VME2PCI_INT_LVL << 8) |
|
||||
LN_INT_LVL);
|
||||
|
||||
/* make the IRQ 15,14,11,10, 9 level sensitive */
|
||||
|
||||
(*(char *)i82378_INT2_ELC) = 0x80 | 0x40 | 0x08 | 0x04 | 0x02 ;
|
||||
#endif /* #ifdef MV1600 */
|
||||
|
||||
|
||||
/* initialize the IBC (ISA Bridge Controller) */
|
||||
|
||||
IBC_BYTE_WRITE (PIC_port1 (PIC1_BASE_ADR),0x11); /* ICW1 */
|
||||
IBC_BYTE_WRITE (PIC_port2 (PIC1_BASE_ADR),sysVectorIRQ0); /* ICW2 */
|
||||
IBC_BYTE_WRITE (PIC_port2 (PIC1_BASE_ADR),0x04); /* ICW3 */
|
||||
IBC_BYTE_WRITE (PIC_port2 (PIC1_BASE_ADR),0x01); /* ICW4 */
|
||||
|
||||
IBC_BYTE_WRITE (PIC_port1 (PIC2_BASE_ADR),0x11); /* ICW1 */
|
||||
IBC_BYTE_WRITE (PIC_port2 (PIC2_BASE_ADR),sysVectorIRQ0+8); /* ICW2 */
|
||||
IBC_BYTE_WRITE (PIC_port2 (PIC2_BASE_ADR),0x02); /* ICW3 */
|
||||
IBC_BYTE_WRITE (PIC_port2 (PIC2_BASE_ADR),0x01); /* ICW4 */
|
||||
|
||||
/* disable interrupts */
|
||||
|
||||
IBC_BYTE_WRITE (PIC_IMASK (PIC1_BASE_ADR),0xfb);
|
||||
IBC_BYTE_WRITE (PIC_IMASK (PIC2_BASE_ADR),0xff);
|
||||
|
||||
/* set the BSP driver specific Interrupt Handler and intConnect routines */
|
||||
|
||||
_func_intConnectRtn = sysIbcIntConnect;
|
||||
_func_intEnableRtn = sysIbcIntEnable;
|
||||
_func_intDisableRtn = sysIbcIntDisable;
|
||||
|
||||
/* clear the pending interrupts */
|
||||
|
||||
intVec = (*(char *)ISA_INTR_ACK_REG);
|
||||
|
||||
sysIbcEndOfInt (); /* perform the end of interrupt procedure */
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIbcIntEnable - enable an IBC interrupt number
|
||||
*
|
||||
* This routine enables a specified IBC interrupt number.
|
||||
*
|
||||
* RETURNS: OK.
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL int sysIbcIntEnable
|
||||
(
|
||||
int intNumber /* interrupt number to enable */
|
||||
)
|
||||
{
|
||||
UINT8 temp;
|
||||
UINT8 *pReg;
|
||||
|
||||
if (intNumber < 8)
|
||||
{
|
||||
pReg = (UINT8 *) PIC_IMASK (PIC1_BASE_ADR);
|
||||
}
|
||||
else
|
||||
{
|
||||
pReg = (UINT8 *) PIC_IMASK (PIC2_BASE_ADR);
|
||||
intNumber -= 8;
|
||||
}
|
||||
|
||||
IBC_BYTE_READ (pReg, &temp);
|
||||
IBC_BYTE_WRITE (pReg, temp & ~(1 << intNumber));
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIbcIntDisable - disable an IBC interrupt number
|
||||
*
|
||||
* This routine disables a specified IBC interrupt number.
|
||||
*
|
||||
* RETURNS: OK.
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL int sysIbcIntDisable
|
||||
(
|
||||
int intNumber /* interrupt number to disable */
|
||||
)
|
||||
{
|
||||
UINT8* pReg;
|
||||
UINT8 temp;
|
||||
|
||||
if (intNumber < 8)
|
||||
{
|
||||
pReg = (UINT8 *) PIC_IMASK (PIC1_BASE_ADR);
|
||||
}
|
||||
else
|
||||
{
|
||||
pReg = (UINT8 *) PIC_IMASK (PIC2_BASE_ADR);
|
||||
intNumber -= 8;
|
||||
}
|
||||
|
||||
IBC_BYTE_READ (pReg, &temp);
|
||||
IBC_BYTE_WRITE (pReg, temp | (1 << intNumber));
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* sysIbcIntConnect - connect an interrupt handler to the system vector table
|
||||
*
|
||||
* This function connects an interrupt handler to the system vector table.
|
||||
*
|
||||
* RETURNS: OK/ERROR.
|
||||
*/
|
||||
|
||||
LOCAL STATUS sysIbcIntConnect
|
||||
(
|
||||
VOIDFUNCPTR * vector, /* interrupt vector to attach */
|
||||
VOIDFUNCPTR routine, /* routine to be called */
|
||||
int parameter /* parameter to be passed to routine */
|
||||
)
|
||||
{
|
||||
INT_HANDLER_DESC * newHandler;
|
||||
INT_HANDLER_DESC * currHandler;
|
||||
|
||||
if (((int)vector < 0) || ((int)vector > 0xff)) /* Out of Range? */
|
||||
return (ERROR);
|
||||
|
||||
/* create a new interrupt handler */
|
||||
|
||||
newHandler = malloc (sizeof (INT_HANDLER_DESC));
|
||||
|
||||
/* check if the memory allocation succeed */
|
||||
|
||||
if (newHandler == NULL)
|
||||
return (ERROR);
|
||||
|
||||
/* initialize the new handler */
|
||||
|
||||
newHandler->vec = routine;
|
||||
newHandler->arg = parameter;
|
||||
newHandler->next = NULL;
|
||||
|
||||
if (sysIntTbl[(int) vector] == NULL)
|
||||
sysIntTbl [(int ) vector] = newHandler; /* single int. handler case */
|
||||
else
|
||||
{
|
||||
currHandler = sysIntTbl[(int) vector]; /* multiple int. handler case */
|
||||
while (currHandler->next != NULL)
|
||||
{
|
||||
currHandler = currHandler->next;
|
||||
}
|
||||
currHandler->next = newHandler;
|
||||
}
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* sysIbcIntHandler - handle an i82378 IBC interrupt
|
||||
*
|
||||
* This routine is called to handle an Intel i82378 ISA Bridge Controller
|
||||
* (IBC) interrupt exception.
|
||||
*
|
||||
* This routine generates the PCI IACK cycle to get the interrupt vector from
|
||||
* the PIC chips. Once the vector is obtained, it is used as an index into
|
||||
* the system vector table to locate the user-defined interrupt routine for
|
||||
* that vector. Each entry in the vector table is a part of a singly-linked
|
||||
* list and all routines on that list are executed in order.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void sysIbcIntHandler (void)
|
||||
{
|
||||
UCHAR intVec;
|
||||
INT_HANDLER_DESC * currHandler;
|
||||
char intReg1;
|
||||
char intReg2;
|
||||
int lock;
|
||||
|
||||
/*
|
||||
* Reading ISA_INTR_ACK_REG would generate PCI IACK cycles on the
|
||||
* PCI bus which would cause the IBC to put out vector from the 82378
|
||||
* on the PCI bus.
|
||||
* Bit 5 of PCI control register in the IBC i82378 should be
|
||||
* programmed to 1 (By default it is 1) if the IBC should respond with
|
||||
* a vector when PCI IACK cycles are generated.
|
||||
*/
|
||||
|
||||
intVec = (*(char *)ISA_INTR_ACK_REG);
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
WV_EVT_INT_ENT(intVec)
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
/* Record current interrupt mask settings */
|
||||
|
||||
IBC_BYTE_READ (PIC_IMASK (PIC1_BASE_ADR), &intReg1);
|
||||
IBC_BYTE_READ (PIC_IMASK (PIC2_BASE_ADR), &intReg2);
|
||||
|
||||
/* Mask this and lower priority interrupt levels */
|
||||
|
||||
sysIbcIntLevelSet (intVec, intReg1, intReg2);
|
||||
|
||||
/*
|
||||
* Now the interrupt acknowledge is made, the interrupt can be re-enabled
|
||||
*/
|
||||
|
||||
intUnlock (_PPC_MSR_EE);
|
||||
|
||||
/* call EACH respective interrupt handler */
|
||||
|
||||
if ((currHandler = sysIntTbl [intVec]) == NULL)
|
||||
logMsg ("uninitialized interrupt %d\n", intVec, 0,0,0,0,0);
|
||||
|
||||
else
|
||||
{
|
||||
while (currHandler != NULL)
|
||||
{
|
||||
currHandler->vec (currHandler->arg);
|
||||
currHandler = currHandler->next;
|
||||
}
|
||||
}
|
||||
|
||||
sysIbcEndOfInt (); /* perform the end of interrupt procedure */
|
||||
|
||||
/* Set the original interrupt masks back */
|
||||
|
||||
lock = intLock ();
|
||||
|
||||
IBC_BYTE_WRITE (PIC_IMASK (PIC1_BASE_ADR), intReg1);
|
||||
IBC_BYTE_WRITE (PIC_IMASK (PIC2_BASE_ADR), intReg2);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIbcEndOfInt - send EOI(end of interrupt) signal.
|
||||
*
|
||||
* This routine is called at the end of the interrupt handler.
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL void sysIbcEndOfInt (void)
|
||||
{
|
||||
IBC_BYTE_WRITE (PIC_IACK (PIC1_BASE_ADR), 0x20);
|
||||
IBC_BYTE_WRITE (PIC_IACK (PIC2_BASE_ADR), 0x20);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIbcIntLevelSet - set the interrupt mask
|
||||
*
|
||||
* This routine masks interrupts from the level of 'intNumber' to 15.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
LOCAL void sysIbcIntLevelSet
|
||||
(
|
||||
UCHAR intNumber, /* interrupt level where to mask from */
|
||||
UCHAR pic1Mask, /* state of Pic1 mask at IRQ */
|
||||
UCHAR pic2Mask /* state of Pic2 mask at IRQ */
|
||||
)
|
||||
{
|
||||
pic1Mask |= ibcIRQ2Pic1Mask[intNumber]; /* make new masks */
|
||||
pic2Mask |= ibcIRQ2Pic2Mask[intNumber];
|
||||
IBC_BYTE_WRITE (PIC_IMASK (PIC1_BASE_ADR), pic1Mask); /* set new masks */
|
||||
IBC_BYTE_WRITE (PIC_IMASK (PIC2_BASE_ADR), pic2Mask);
|
||||
}
|
||||
@@ -0,0 +1,736 @@
|
||||
/* i8259Intr.c - Intel 8259A PIC (Programmable Interrupt Controller) driver */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993-2008,2014 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01x,24sep14,j_l VXW6-83369 - Use INCLUDE_SYMMETRIC_IO_MODE
|
||||
01w,27aug08,jpb Renamed VSB header file
|
||||
01v,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
|
||||
for kernel configurations options set in vsb.
|
||||
01u,18jun07,scm remove reference to sysCpuNumGet, replace with
|
||||
vxCpuIndexGet...
|
||||
01t,09oct06,scm remove sysBp dependencey for SMP...
|
||||
01s,09nov05,mdo Fixes for apigen
|
||||
01r,07may04,zmm Fix diab compiler warnings.
|
||||
01q,11nov02,hdn fixed the IRQ15 spurious interrupt handling (spr 74209)
|
||||
01p,16apr02,hdn added support for the Special Fully Nested Mode, IRQ0 Early
|
||||
EOI Mode, IRQ0 Special Mask Mode, AEOI Mode (spr 76411)
|
||||
01o,29mar02,hdn added forgotten back slash to the optimized code
|
||||
01n,21mar02,hdn fixed doc build by removing comments in the optimized code
|
||||
01m,25feb02,hdn updated i8259Init() for HTT (spr 73738)
|
||||
added optimized version of EOI routines
|
||||
01l,11sep01,hdn updated comment regarding the spr-28547 fix.
|
||||
01k,27aug99,hdn fixed a bug for stray interrupt in i8259IntBoi(SPR 28547).
|
||||
01j,11oct98,ms fixed compiler warning via typecast
|
||||
01i,04jun98,hdn changed a method to exit i8259IntBoi().
|
||||
01h,25may98,hdn changed function name starting from "i8259".
|
||||
added i8259IntEoiMaster(), i8259IntEoiSlave(), i8259IntBoi().
|
||||
removed sysIntEOI().
|
||||
01g,17mar97,hdn added sysIntLock(), sysIntUnlock() for the system mode.
|
||||
01f,25jun96,hdn added sysIntLevel() for windview.
|
||||
01e,23may96,wlf doc: cleanup.
|
||||
01d,14jun95,hdn renamed sysEndOfInt to sysIntEOI.
|
||||
moved global function prototypes to sysLib.h.
|
||||
01c,08aug94,hdn stopped toggling IRQ9 in enabling and disabling.
|
||||
01b,22apr94,hdn made IRQ9 off in the initialization.
|
||||
moved sysVectorIRQ0 to sysLib.c.
|
||||
01a,05sep93,hdn written.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This module is a driver for the Intel 8259A PIC (Programmable Interrupt
|
||||
Controller). The Intel 8259A handles up to 8 vectored priority interrupts
|
||||
for the CPU. It is cascadable for up to 64 vectored priority interrupts,
|
||||
though this driver assumes two cascaded 8259A. It is initialized for
|
||||
"Fully Nested Mode", "Non-Specific EOI" mode.
|
||||
|
||||
Fully Nested Mode.
|
||||
In this mode, interrupt requests are ordered in priority
|
||||
from 0 through 7 (0 is the highest priority). When an interrupt is
|
||||
acknowledged, the highest priority request is determined and its vector is
|
||||
placed on the bus. Additionally, a bit of the Interrupt Service (IS)
|
||||
register is set. This bit remains set until the microprocessor issues an
|
||||
EOI command immediately before returning from the service routine. While
|
||||
the IS bit is set, all further interrupts of the same or lower priority
|
||||
are inhibited, while higher level interrupts are allowed. The
|
||||
i8259IntEoiSlaveNfnm() routine is used to issue the EOI command. The PICs
|
||||
in a PC typically operate in this mode (normal nested mode). In this mode,
|
||||
while the slave PIC is being serviced by the master PIC, the slave PIC blocks
|
||||
all higher priority interrupt requests. Alternatively, to allow interrupts of
|
||||
a higher priority, enable the Special Fully Nested Mode.
|
||||
|
||||
Special Fully Nested Mode: I8259_SPECIAL_FULLY_NESTED_MODE.
|
||||
This mode is similar to the Fully Nested Mode with the following exceptions:
|
||||
1) When an interrupt request from a slave PIC is in service, the slave is
|
||||
not locked out from the master's priority logic and further interrupt
|
||||
requests from higher priority IRs within the slave will be recognized by
|
||||
the master and will initiate interrupts to the processor. 2) When exiting
|
||||
the interrupt service routine, the software must check whether or not the
|
||||
interrupt serviced was the only interrupt request from the slave. If it
|
||||
was the only interrupt request, a non-specific EOI is sent to the master.
|
||||
If not, no EOI is sent. This is implemented by the i8259EoiSlaveSfnm()
|
||||
routine.
|
||||
|
||||
Non-Specific EOI: When the 8259A is operated in the Fully Nested Mode, it
|
||||
can determine which IS bit to reset on EOI. When a non-specific EOI
|
||||
command is issued, the 8259A will automatically reset the highest IS bit of
|
||||
those that are set, since in the fully nested mode the highest IS level is
|
||||
the last level acknowledged and serviced.
|
||||
|
||||
Spurious/Phantom Interrupt: The IR inputs must remain high until after the
|
||||
falling edge of the first INTA. If the IR input goes low before this time,
|
||||
a DEFAULT(Spurious/Phantom) IR7 will occur when the CPU acknowledges the
|
||||
interrupt. The interrupt handler should simply return without sending
|
||||
an EOI command.
|
||||
|
||||
The PIC(8259A) IRQ0 is hard wired to the PIT(8253) channel 0 in a PC
|
||||
motherboard. IRQ0 is the highest priority in the 8259A interrupt
|
||||
controller. Thus, the system clock interrupt handler blocks all lower
|
||||
level interrupts. This may cause a delay of the lower level interrupts in
|
||||
some situations even though the system clock interrupt handler finishes its
|
||||
job without any delay. This is quite natural from the hardware point of
|
||||
view, but may not be ideal from the application software standpoint. The
|
||||
following modes are supplied to mitigate this situation by providing
|
||||
corresponding configuration macros in the BSP. The three modes are mutually
|
||||
exclusive.
|
||||
|
||||
Early EOI Issue in IRQ0 ISR.
|
||||
In this mode, the EOI command is issued before the IRQ0 system clock interrupt
|
||||
service routine starts the kernel work. This lowers the IRQ0 ISR blocking
|
||||
level to the next lower level. If no IRQs are in service, the next lower
|
||||
level is the lowest level. If IRQn is in service, the next lower level
|
||||
corresponds to the next lower priority. As a result, the kernel work in the
|
||||
system clock interrupt service routine can be interrupted by an interrupt
|
||||
with a higher priority than the blocking level. The i8259IntBoiEem() routine
|
||||
is called before the interrupt service routine, and no EOI is sent after
|
||||
the interrupt service routine.
|
||||
|
||||
Special Mask Mode in IRQ0 ISR.
|
||||
In this mode, the Special Mask Mode is used in the IRQ0 system clock
|
||||
service routine. This lowers the blocking level to the specified level
|
||||
(currently hard coded to the lowest level). The i8259IntBoiSmm() routine
|
||||
is called before the interrupt service routine, and the i8259IntEoiSmm()
|
||||
routine is called after the interrupt service routine.
|
||||
|
||||
Automatic EOI Mode: I8259_AUTO_EOI.
|
||||
This mode provides no nested multi-level interrupt structure in PIC1. The
|
||||
EOI command is automatically sent to the master PIC at the end of the
|
||||
interrupt acknowledge cycle. Thus, no software intervention is needed. The
|
||||
i8259IntBoi() routine is called before the IRQ7 and IRQ15 interrupt service
|
||||
routines. Either the i8259IntEoiSlaveNfnm() routine or the
|
||||
i8259IntEoiSlaveSfnm() routine is called after the slave PIC's interrupt
|
||||
service routine.
|
||||
|
||||
SEE ALSO: pc386/target.ref
|
||||
|
||||
INCLUDE FILES: i8259.h
|
||||
*/
|
||||
|
||||
#include <vsbConfig.h>
|
||||
|
||||
#include <drv/intrCtl/i8259.h>
|
||||
|
||||
|
||||
/* externs */
|
||||
|
||||
IMPORT void intBoiExit ();
|
||||
IMPORT UINT32 sysStrayIntCount;
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP */
|
||||
#endif /* _WRS_CONFIG_SMP */
|
||||
|
||||
|
||||
/* defines */
|
||||
|
||||
#define I8259_EOI_OPTIMIZED /* use the optimized version */
|
||||
|
||||
|
||||
/* globals */
|
||||
|
||||
|
||||
/* local */
|
||||
|
||||
#if !defined(SYMMETRIC_IO_MODE) && !defined(INCLUDE_SYMMETRIC_IO_MODE)
|
||||
LOCAL INT8 i8259IntMask1; /* interrupt mask for PIC1 */
|
||||
LOCAL INT8 i8259IntMask2; /* interrupt mask for PIC2 */
|
||||
LOCAL INT8 i8259Mask = 0; /* interrupt mask for PIC1 */
|
||||
#endif /* !SYMMETRIC_IO_MODE && !INCLUDE_SYMMETRIC_IO_MODE */
|
||||
|
||||
|
||||
/* forward static functions */
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259Init - initialize the PIC
|
||||
*
|
||||
* This routine initializes the PIC.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
VOID i8259Init (void)
|
||||
{
|
||||
UINT8 icw4 = 0x01;
|
||||
|
||||
/* return if it is not the Boot Processor (BP) */
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
if (sysBp == FALSE)
|
||||
#else
|
||||
if (vxCpuIndexGet() != 0)
|
||||
#endif /* _WRS_CONFIG_SMP */
|
||||
return;
|
||||
|
||||
/* initialize the PIC (Programmable Interrupt Controller) */
|
||||
|
||||
sysOutByte (PIC_port1 (PIC1_BASE_ADR),0x11); /* ICW1 */
|
||||
sysOutByte (PIC_port2 (PIC1_BASE_ADR),INT_NUM_IRQ0); /* ICW2 */
|
||||
sysOutByte (PIC_port2 (PIC1_BASE_ADR),0x04); /* ICW3 */
|
||||
|
||||
#ifdef I8259_SPECIAL_FULLY_NESTED_MODE
|
||||
icw4 |= 0x10; /* SFNM */
|
||||
#endif /* I8259_SPECIAL_FULLY_NESTED_MODE */
|
||||
|
||||
#ifdef I8259_AUTO_EOI
|
||||
icw4 |= 0x02; /* AEOI */
|
||||
#endif /* I8259_AUTO_EOI */
|
||||
|
||||
sysOutByte (PIC_port2 (PIC1_BASE_ADR),icw4); /* ICW4 */
|
||||
|
||||
sysOutByte (PIC_port1 (PIC2_BASE_ADR),0x11); /* ICW1 */
|
||||
sysOutByte (PIC_port2 (PIC2_BASE_ADR),(char) (INT_NUM_IRQ0+8)); /* ICW2 */
|
||||
sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x02); /* ICW3 */
|
||||
sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x01); /* ICW4 */
|
||||
|
||||
/* disable interrupts */
|
||||
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), (char)0xfb);
|
||||
sysOutByte (PIC_IMASK (PIC2_BASE_ADR), (char)0xff);
|
||||
}
|
||||
|
||||
#if !defined(SYMMETRIC_IO_MODE) && !defined(INCLUDE_SYMMETRIC_IO_MODE)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntBoiEem - issue EOI before the IRQ0 interrupt handler
|
||||
*
|
||||
* This routine is called before the IRQ0 interrupt handler that is PIT(8253)
|
||||
* channel 0 system clock interrupt handler in the Early EOI Mode.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
VOID i8259IntBoiEem
|
||||
(
|
||||
int irqNo /* IRQ number of the interrupt */
|
||||
)
|
||||
{
|
||||
INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
|
||||
|
||||
sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20); /* NS EOI to PIC1 */
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntBoiSmm - enable Special Mask Mode before the IRQ0 interrupt handler
|
||||
*
|
||||
* This routine is called before the IRQ0 interrupt handler that is PIT(8253)
|
||||
* channel 0 system clock interrupt handler, in the Special Mask Mode.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
VOID i8259IntBoiSmm
|
||||
(
|
||||
int irqNo /* IRQ number of the interrupt */
|
||||
)
|
||||
{
|
||||
INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
|
||||
|
||||
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x68); /* enable SMM PIC1 */
|
||||
i8259Mask = sysInByte (PIC_IMASK (PIC1_BASE_ADR)); /* save int mask */
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), 0x01); /* unlock except IRQ0 */
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntBoi - detect whether it is spurious interrupt or not
|
||||
*
|
||||
* This routine is called before the user's interrupt handler to detect the
|
||||
* spurious interrupt.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
VOID i8259IntBoi
|
||||
(
|
||||
INT32 irqNo /* IRQ number of the interrupt */
|
||||
)
|
||||
{
|
||||
INT32 oldLevel;
|
||||
INT8 inserviceReg;
|
||||
|
||||
/* we are interested in IRQ7 and IRQ15 */
|
||||
|
||||
if ((irqNo != 7) && (irqNo != 15))
|
||||
return;
|
||||
|
||||
/* if ISR bit is not set, we change the return address */
|
||||
|
||||
oldLevel = intLock (); /* LOCK INTERRUPT */
|
||||
|
||||
if (irqNo == 7)
|
||||
{
|
||||
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b);
|
||||
inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR));
|
||||
}
|
||||
else
|
||||
{
|
||||
sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b);
|
||||
inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR));
|
||||
|
||||
/* check bit7 for spurious interrupt from the slave PIC IRQ15 */
|
||||
|
||||
if ((inserviceReg & 0x80) == 0)
|
||||
{
|
||||
|
||||
/* make sure no IRQs in the slave PIC are in service */
|
||||
|
||||
if (inserviceReg == 0)
|
||||
{
|
||||
|
||||
/* check the master PIC's in-service register */
|
||||
|
||||
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b);
|
||||
inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR));
|
||||
|
||||
/* send non-specific EOI to the master PIC IRQ2 */
|
||||
|
||||
if (inserviceReg & 0x04)
|
||||
sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
|
||||
|
||||
/*
|
||||
* another implementation idea...
|
||||
*
|
||||
* *((UINT32 *)&irqNo - 1) = (UINT32)intBoiExit;
|
||||
* This changes the return addr on the stack. This is architecture
|
||||
* specific and tricky. Thus making following change may be good idea.
|
||||
*
|
||||
* - let this routine return OK or ERROR
|
||||
* - let interrupt stub code check the ret value and jump to intExit.
|
||||
*
|
||||
* New code would be like this:
|
||||
* :
|
||||
* if ((irqNo != 7) && (irqNo != 15))
|
||||
* return (OK);
|
||||
* :
|
||||
* if ((inserviceReg & 0x80) == 0) * check bit7 for IRQ7 and IRQ15 *
|
||||
* {
|
||||
* sysStrayIntCount++; * increment the counter *
|
||||
* return (ERROR);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* 00 e8 kk kk kk kk call _intEnt * tell kernel
|
||||
* 05 50 pushl %eax * save regs
|
||||
* 06 52 pushl %edx
|
||||
* 07 51 pushl %ecx
|
||||
* 08 68 pp pp pp pp pushl $_parameterBoi * push BOI param
|
||||
* 13 e8 rr rr rr rr call _routineBoi * call BOI routine
|
||||
* addl $4, %esp
|
||||
* cmpl $0, %eax
|
||||
* jne intConnectCode0
|
||||
* 18 68 pp pp pp pp pushl $_parameter * push param
|
||||
* 23 e8 rr rr rr rr call _routine * call C routine
|
||||
* addl $4, %esp
|
||||
* 28 68 pp pp pp pp pushl $_parameterEoi * push EOI param
|
||||
* 33 e8 rr rr rr rr call _routineEoi * call EOI routine
|
||||
* 38 83 c4 04 addl $4, %esp * pop param
|
||||
* intConnectCode0:
|
||||
* 41 59 popl %ecx * restore regs
|
||||
* 42 5a popl %edx
|
||||
* 43 58 popl %eax
|
||||
* 44 e9 kk kk kk kk jmp _intExit * exit via kernel
|
||||
*/
|
||||
|
||||
if ((inserviceReg & 0x80) == 0) /* check bit7 for IRQ7 and IRQ15 */
|
||||
{
|
||||
sysStrayIntCount++; /* increment the counter */
|
||||
*((UINT32 *)&irqNo - 1) = (UINT32)intBoiExit; /* change return addr */
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntEoiSmm - disable Special Mask Mode with EOI signal to the master PIC
|
||||
*
|
||||
* This routine is called at the end of the IRQ0 interrupt handler that is
|
||||
* PIT(8253) channel 0 system clock interrupt handler in the Special Mask Mode.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
VOID i8259IntEoiSmm
|
||||
(
|
||||
int irqNo /* IRQ number to send EOI */
|
||||
)
|
||||
{
|
||||
INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
|
||||
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), i8259Mask); /* restore old mask */
|
||||
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x08); /* disable SMM PIC1 */
|
||||
sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20); /* NS EOI to PIC1 */
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntEoiMaster - send EOI(end of interrupt) signal to the master PIC.
|
||||
*
|
||||
* This routine is called at the end of the interrupt handler.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
VOID i8259IntEoiMaster
|
||||
(
|
||||
INT32 irqNo /* IRQ number to send EOI */
|
||||
)
|
||||
{
|
||||
#ifdef I8259_EOI_OPTIMIZED /* optimized version */
|
||||
|
||||
WRS_ASM (" \
|
||||
pushfl; \
|
||||
cli; \
|
||||
movl $0x20, %edx; \
|
||||
movl $0x20, %eax; \
|
||||
outb %al, %dx; \
|
||||
popfl; \
|
||||
");
|
||||
|
||||
#else /* portable version */
|
||||
|
||||
INT32 oldLevel = intLock (); /* LOCK INTERRUPTS */
|
||||
|
||||
sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI); /* non-specific EOI */
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
|
||||
|
||||
#endif /* I8259_EOI_OPTIMIZED */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntEoiSlave - send EOI(end of interrupt) signal to the slave PIC.
|
||||
*
|
||||
* This routine is called at the end of the interrupt handler in the Normal
|
||||
* Fully Nested Mode. This is kept for the backward compatibility.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
VOID i8259IntEoiSlave
|
||||
(
|
||||
INT32 irqNo /* IRQ number to send EOI */
|
||||
)
|
||||
{
|
||||
#ifdef I8259_EOI_OPTIMIZED /* optimized version */
|
||||
|
||||
WRS_ASM (" \
|
||||
pushfl; \
|
||||
cli; \
|
||||
movl $0xa0, %edx; \
|
||||
movl $0x20, %eax; \
|
||||
outb %al, %dx; \
|
||||
movl $0x20, %edx; \
|
||||
outb %al, %dx; \
|
||||
popfl; \
|
||||
");
|
||||
|
||||
#else /* portable version */
|
||||
|
||||
INT32 oldLevel = intLock (); /* LOCK INTERRUPTS */
|
||||
|
||||
sysOutByte (PIC_IACK (PIC2_BASE_ADR), I8259_EOI); /* non-specific EOI */
|
||||
sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI); /* non-specific EOI */
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
|
||||
|
||||
#endif /* I8259_EOI_OPTIMIZED */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntEoiSlaveNfnm - send EOI(end of interrupt) signal to the slave PIC.
|
||||
*
|
||||
* This routine is called at the end of the interrupt handler in the Normal
|
||||
* Fully Nested Mode.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
VOID i8259IntEoiSlaveNfnm
|
||||
(
|
||||
INT32 irqNo /* IRQ number to send EOI */
|
||||
)
|
||||
{
|
||||
#ifdef I8259_EOI_OPTIMIZED /* optimized version */
|
||||
|
||||
WRS_ASM (" \
|
||||
pushfl; \
|
||||
cli; \
|
||||
movl $0xa0, %edx; \
|
||||
movl $0x20, %eax; \
|
||||
outb %al, %dx; \
|
||||
movl $0x20, %edx; \
|
||||
outb %al, %dx; \
|
||||
popfl; \
|
||||
");
|
||||
|
||||
#else /* portable version */
|
||||
|
||||
INT32 oldLevel = intLock (); /* LOCK INTERRUPTS */
|
||||
|
||||
sysOutByte (PIC_IACK (PIC2_BASE_ADR), I8259_EOI); /* non-specific EOI */
|
||||
sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI); /* non-specific EOI */
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
|
||||
|
||||
#endif /* I8259_EOI_OPTIMIZED */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntEoiSlaveSfnm - send EOI(end of interrupt) signal to the slave PIC.
|
||||
*
|
||||
* This routine is called at the end of the interrupt handler in the Special
|
||||
* Fully Nested Mode.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
VOID i8259IntEoiSlaveSfnm
|
||||
(
|
||||
int irqNo /* IRQ number to send EOI */
|
||||
)
|
||||
{
|
||||
INT8 inserviceReg;
|
||||
INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
|
||||
|
||||
sysOutByte (PIC_IACK (PIC2_BASE_ADR), 0x20); /* NS EOI to PIC2 */
|
||||
|
||||
sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b); /* issue OCW3 */
|
||||
inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR)); /* read ISR */
|
||||
if (inserviceReg == 0)
|
||||
sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20); /* NS EOI to PIC1 */
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntDisable - disable a specified PIC interrupt input line
|
||||
*
|
||||
* This routine disables a specified PIC interrupt input line.
|
||||
*
|
||||
* RETURNS: OK, always.
|
||||
*
|
||||
* SEE ALSO: i8259IntEnable()
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
LOCAL STATUS i8259IntDisable
|
||||
(
|
||||
INT32 irqNo /* IRQ number to disable */
|
||||
)
|
||||
{
|
||||
|
||||
if (irqNo < 8)
|
||||
{
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR),
|
||||
sysInByte (PIC_IMASK (PIC1_BASE_ADR)) | (1 << irqNo));
|
||||
}
|
||||
else
|
||||
{
|
||||
sysOutByte (PIC_IMASK (PIC2_BASE_ADR),
|
||||
sysInByte (PIC_IMASK (PIC2_BASE_ADR)) | (1 << (irqNo - 8)));
|
||||
}
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntEnable - enable a specified PIC interrupt input line
|
||||
*
|
||||
* This routine enables a specified PIC interrupt input line.
|
||||
*
|
||||
* RETURNS: OK, always.
|
||||
*
|
||||
* SEE ALSO: i8259IntDisable()
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
LOCAL STATUS i8259IntEnable
|
||||
(
|
||||
INT32 irqNo /* IRQ number to enable */
|
||||
)
|
||||
{
|
||||
|
||||
if (irqNo < 8)
|
||||
{
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR),
|
||||
sysInByte (PIC_IMASK (PIC1_BASE_ADR)) & ~(1 << irqNo));
|
||||
}
|
||||
else
|
||||
{
|
||||
sysOutByte (PIC_IMASK (PIC2_BASE_ADR),
|
||||
sysInByte (PIC_IMASK (PIC2_BASE_ADR)) & ~(1 << (irqNo - 8)));
|
||||
}
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntLock - lock out all PIC interrupts
|
||||
*
|
||||
* This routine saves the mask and locks out all PIC interrupts.
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: i8259IntUnlock()
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
LOCAL VOID i8259IntLock (void)
|
||||
|
||||
{
|
||||
|
||||
i8259IntMask1 = sysInByte (PIC_IMASK (PIC1_BASE_ADR));
|
||||
i8259IntMask2 = sysInByte (PIC_IMASK (PIC2_BASE_ADR));
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), (char)0xff);
|
||||
sysOutByte (PIC_IMASK (PIC2_BASE_ADR), (char)0xff);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntUnlock - unlock the PIC interrupts
|
||||
*
|
||||
* This routine restores the mask and unlocks the PIC interrupts
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: i8259IntLock()
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
LOCAL VOID i8259IntUnlock (void)
|
||||
|
||||
{
|
||||
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), i8259IntMask1);
|
||||
sysOutByte (PIC_IMASK (PIC2_BASE_ADR), i8259IntMask2);
|
||||
}
|
||||
|
||||
#if FALSE
|
||||
|
||||
/*
|
||||
* There is a function sysIntLevel() which gets the interrupt level from the
|
||||
* interrupt stub, so we don't need it anymore.
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* i8259IntLevel - Get IRQ number by reading Interrupt Service Register.
|
||||
*
|
||||
* This routine is called to get an IRQ number in service.
|
||||
*
|
||||
* RETURNS: 0 - 15
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
LOCAL INT32 i8259IntLevel (void)
|
||||
|
||||
{
|
||||
INT32 inserviceReg;
|
||||
INT32 irq;
|
||||
INT32 oldLevel;
|
||||
INT32 retry;
|
||||
|
||||
oldLevel = intLock ();
|
||||
|
||||
for (retry=0; retry < 1; retry ++)
|
||||
{
|
||||
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b);
|
||||
inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR));
|
||||
for (irq=0; irq < 8; irq++)
|
||||
if ((inserviceReg & 1) && (irq != 2))
|
||||
goto i8259IntLevelExit;
|
||||
else
|
||||
inserviceReg >>= 1;
|
||||
|
||||
sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b);
|
||||
inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR));
|
||||
for (irq=8; irq < 16; irq++)
|
||||
if (inserviceReg & 1)
|
||||
goto i8259IntLevelExit;
|
||||
else
|
||||
inserviceReg >>= 1;
|
||||
}
|
||||
|
||||
i8259IntLevelExit:
|
||||
intUnlock (oldLevel);
|
||||
|
||||
return (irq);
|
||||
}
|
||||
|
||||
#endif /* FALSE */
|
||||
|
||||
#endif /* !SYMMETRIC_IO_MODE && !INCLUDE_SYMMETRIC_IO_MODE */
|
||||
@@ -0,0 +1,269 @@
|
||||
/* i8259Pic.c - Intel 8259A PIC (Programmable Interrupt Controller) driver */
|
||||
|
||||
/* Copyright (c) 1993-2005 Wind River Systems, Inc. */
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01k,09nov05,mdo Fixes for apigen
|
||||
01j,26oct04,jb Really fix SPR 102687
|
||||
01i,14oct04,jb Fix compiler warnings
|
||||
01h,20sep04,pes added conditional compilation of sysIntInitPic and
|
||||
sysIntEOI functions to allow them to be excluded when not
|
||||
being used. This eliminates compilation warnings about
|
||||
local functions not being used.
|
||||
01g,17mar97,hdn added sysIntLock(), sysIntUnlock() for the system mode.
|
||||
01f,25jun96,hdn added sysIntLevel() for windview.
|
||||
01e,23may96,wlf doc: cleanup.
|
||||
01d,14jun95,hdn renamed sysEndOfInt to sysIntEOI.
|
||||
moved global function prototypes to sysLib.h.
|
||||
01c,08aug94,hdn stopped toggling IRQ9 in enabling and disabling.
|
||||
01b,22apr94,hdn made IRQ9 off in the initialization.
|
||||
moved sysVectorIRQ0 to sysLib.c.
|
||||
01a,05sep93,hdn written.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This module implements the Intel 8259A PIC driver.
|
||||
|
||||
INCLUDE FILES: i8259a.h
|
||||
*/
|
||||
|
||||
#include <drv/intrCtl/i8259a.h>
|
||||
|
||||
|
||||
/* globals */
|
||||
|
||||
IMPORT UINT sysVectorIRQ0; /* vector for IRQ0 */
|
||||
|
||||
|
||||
/* local */
|
||||
|
||||
char sysIntMask1; /* interrupt mask for PIC1 */
|
||||
char sysIntMask2; /* interrupt mask for PIC2 */
|
||||
|
||||
|
||||
/* forward static functions */
|
||||
|
||||
|
||||
|
||||
#if !defined (_WRS_SYS_INT_INIT_PIC_NOT_USED)
|
||||
LOCAL void sysIntInitPIC (void);
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIntInitPIC - initialize the PIC
|
||||
*
|
||||
* This routine initializes the PIC.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
LOCAL void sysIntInitPIC (void)
|
||||
|
||||
{
|
||||
|
||||
/* initialize the PIC (Programmable Interrupt Controller) */
|
||||
|
||||
sysOutByte (PIC_port1 (PIC1_BASE_ADR),0x11); /* ICW1 */
|
||||
sysOutByte (PIC_port2 (PIC1_BASE_ADR),sysVectorIRQ0); /* ICW2 */
|
||||
sysOutByte (PIC_port2 (PIC1_BASE_ADR),0x04); /* ICW3 */
|
||||
sysOutByte (PIC_port2 (PIC1_BASE_ADR),0x01); /* ICW4 */
|
||||
|
||||
sysOutByte (PIC_port1 (PIC2_BASE_ADR),0x11); /* ICW1 */
|
||||
sysOutByte (PIC_port2 (PIC2_BASE_ADR),sysVectorIRQ0+8); /* ICW2 */
|
||||
sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x02); /* ICW3 */
|
||||
sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x01); /* ICW4 */
|
||||
|
||||
/* disable interrupts */
|
||||
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR),(_WRS_IOCHAR)0xfb);
|
||||
sysOutByte (PIC_IMASK (PIC2_BASE_ADR),(_WRS_IOCHAR)0xff);
|
||||
}
|
||||
#endif /* !defined (_WRS_SYS_INT_INIT_PIC_NOT_USED) */
|
||||
|
||||
#if !defined (_WRS_SYS_INT_EOI_NOT_USED)
|
||||
LOCAL void sysIntEOI (void);
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIntEOI - send EOI(end of interrupt) signal.
|
||||
*
|
||||
* This routine is called at the end of the interrupt handler.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
LOCAL void sysIntEOI (void)
|
||||
|
||||
{
|
||||
int oldLevel;
|
||||
|
||||
oldLevel = intLock ();
|
||||
sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20);
|
||||
sysOutByte (PIC_IACK (PIC2_BASE_ADR), 0x20);
|
||||
intUnlock (oldLevel);
|
||||
}
|
||||
#endif /* !defined (_WRS_SYS_INT_EOI_NOT_USED) */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIntDisablePIC - disable a PIC interrupt level
|
||||
*
|
||||
* This routine disables a specified PIC interrupt level.
|
||||
*
|
||||
* RETURNS: OK, always.
|
||||
*
|
||||
* SEE ALSO: sysIntEnablePIC()
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
STATUS sysIntDisablePIC
|
||||
(
|
||||
int intLevel /* interrupt level to disable */
|
||||
)
|
||||
{
|
||||
|
||||
if (intLevel < 8)
|
||||
{
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR),
|
||||
sysInByte (PIC_IMASK (PIC1_BASE_ADR)) | (1 << intLevel));
|
||||
}
|
||||
else
|
||||
{
|
||||
sysOutByte (PIC_IMASK (PIC2_BASE_ADR),
|
||||
sysInByte (PIC_IMASK (PIC2_BASE_ADR)) | (1 << (intLevel - 8)));
|
||||
}
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIntEnablePIC - enable a PIC interrupt level
|
||||
*
|
||||
* This routine enables a specified PIC interrupt level.
|
||||
*
|
||||
* RETURNS: OK, always.
|
||||
*
|
||||
* SEE ALSO: sysIntDisablePIC()
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
STATUS sysIntEnablePIC
|
||||
(
|
||||
int intLevel /* interrupt level to enable */
|
||||
)
|
||||
{
|
||||
|
||||
if (intLevel < 8)
|
||||
{
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR),
|
||||
sysInByte (PIC_IMASK (PIC1_BASE_ADR)) & ~(1 << intLevel));
|
||||
}
|
||||
else
|
||||
{
|
||||
sysOutByte (PIC_IMASK (PIC2_BASE_ADR),
|
||||
sysInByte (PIC_IMASK (PIC2_BASE_ADR)) & ~(1 << (intLevel - 8)));
|
||||
}
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIntLevel - Get interrupt level by reading Interrupt Service Register.
|
||||
*
|
||||
* This routine is called to get an interrupt level in service.
|
||||
*
|
||||
* RETURNS: 0 - 15
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
int sysIntLevel (void)
|
||||
|
||||
{
|
||||
int inserviceReg;
|
||||
int level;
|
||||
int oldLevel;
|
||||
int retry;
|
||||
|
||||
oldLevel = intLock ();
|
||||
|
||||
level = 0;
|
||||
for (retry=0; retry < 1; retry ++)
|
||||
{
|
||||
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b);
|
||||
inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR));
|
||||
for (level=0; level < 8; level++)
|
||||
if ((inserviceReg & 1) && (level != 2))
|
||||
goto sysIntLevelExit;
|
||||
else
|
||||
inserviceReg >>= 1;
|
||||
|
||||
sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b);
|
||||
inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR));
|
||||
for (level=8; level < 16; level++)
|
||||
if (inserviceReg & 1)
|
||||
goto sysIntLevelExit;
|
||||
else
|
||||
inserviceReg >>= 1;
|
||||
}
|
||||
|
||||
sysIntLevelExit:
|
||||
intUnlock (oldLevel);
|
||||
|
||||
return (level);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIntLock - lock out all PIC interrupts
|
||||
*
|
||||
* This routine saves the mask and locks out all PIC interrupts.
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: sysIntUnlock()
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
VOID sysIntLock (void)
|
||||
|
||||
{
|
||||
|
||||
sysIntMask1 = sysInByte (PIC_IMASK (PIC1_BASE_ADR));
|
||||
sysIntMask2 = sysInByte (PIC_IMASK (PIC2_BASE_ADR));
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), (_WRS_IOCHAR)0xff);
|
||||
sysOutByte (PIC_IMASK (PIC2_BASE_ADR), (_WRS_IOCHAR)0xff);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysIntUnlock - unlock the PIC interrupts
|
||||
*
|
||||
* This routine restores the mask and unlocks the PIC interrupts
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: sysIntLock()
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
VOID sysIntUnlock (void)
|
||||
|
||||
{
|
||||
|
||||
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), sysIntMask1);
|
||||
sysOutByte (PIC_IMASK (PIC2_BASE_ADR), sysIntMask2);
|
||||
}
|
||||
@@ -0,0 +1,691 @@
|
||||
/* ioApicIntr.c - Intel IO APIC/xAPIC driver */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997-1998, 2000-2002, 2004, 2006-2008 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use of this
|
||||
* software may be licensed only pursuant to the terms of an applicable Wind
|
||||
* River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01n,27aug08,jpb Renamed VSB header file
|
||||
01m,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
|
||||
for kernel configurations options set in vsb.
|
||||
01l,26apr07,dlk PCI interrupt temporary workaround for SMP --
|
||||
For VXBUS case, ioApicInit() allocates memory using
|
||||
hwMemAlloc().
|
||||
01k,09oct06,scm remove sysBp dependencey for SMP...
|
||||
01j,26jul06,scm update for pentium/xeon support...
|
||||
01i,18aug04,dmh parameter checking
|
||||
01h,01apr04,dmh add support for multiple APICs
|
||||
01g,08mar02,hdn updated ioApicInit(), added ioApicEnable()
|
||||
removed redTable, added ioApicRedS/G(HTT (spr 73738)
|
||||
01f,29nov01,hdn doc update for 5.5
|
||||
01e,07nov01,hdn updated the interrupt delivery type setting
|
||||
added new routine ioApicIrqMove ()
|
||||
01d,26jun01,hdn added support for Pentium4 IO xAPIC
|
||||
moved show routine to ioApicIntrShow.c
|
||||
01c,17nov00,mks importing loApicBase and loApicId for successful compilation,
|
||||
added redTablePtr and made redTableNumEnt global. SPR 35733.
|
||||
01b,25mar98,hdn re-written.
|
||||
01a,20jun97,sub written.
|
||||
*/
|
||||
|
||||
/*
|
||||
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 (define SYMMETRIC_IO_MODE in the BSP).
|
||||
The base address of IO APIC is determined in loApicInit() and stored in the
|
||||
global variable ioApicBase and ioApicData. ioApicInit() initializes the IO
|
||||
APIC with information stored in ioApicRed0_15 and ioApicRed16_23.
|
||||
The ioApicRed0_15 is the default lower 32 bit value of the redirection table
|
||||
entries for IRQ 0 to 15 that are edge triggered positive high, and
|
||||
the ioApicRed16_23 is for IRQ 16 to 23 that are level triggered positive low.
|
||||
ioApicRedSet() and ioApicRedGet() are used to access the redirection table.
|
||||
ioApicEnable() enables the IO APIC or xAPIC. ioApicIrqSet() set the specific
|
||||
IRQ to be delivered to the specific Local APIC.
|
||||
This implementation doesn't support multiple IO APIC configuration.
|
||||
|
||||
INCLUDE FILES: loApic.h, ioApic.h
|
||||
|
||||
SEE ALSO: loApicIntr.c
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
#include <vsbConfig.h>
|
||||
|
||||
#include "intLib.h"
|
||||
#include "drv/intrCtl/loApic.h"
|
||||
#include "drv/intrCtl/ioApic.h"
|
||||
|
||||
/* externs */
|
||||
|
||||
IMPORT UINT32 loApicBase; /* addr of Local APIC */
|
||||
IMPORT UINT32 loApicId; /* local APIC Id */
|
||||
IMPORT UINT32 sysProcessor; /* 0=386, 1=486, 2=P5, 4=P6, 5=P7 */
|
||||
IMPORT INT8 excCallTbl []; /* table of Calls in excALib.s */
|
||||
IMPORT INT32 sysCsInt; /* CS for interrupt */
|
||||
IMPORT VOIDFUNCPTR intEoiGet; /* function used in intConnect() for B/EOI */
|
||||
IMPORT UINT32 sysIntIdtType; /* IDT entry type */
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP */
|
||||
#else
|
||||
IMPORT int sysCpuNumGet (); /* define in sysLib.c of BSP */
|
||||
#endif
|
||||
|
||||
IMPORT void sysPciIoApicEnable(); /* enable/disable the IO APIC */
|
||||
IMPORT void sysPciPirqEnable(); /* enable/disable the PCI PIRQ */
|
||||
|
||||
#ifdef INCLUDE_VXBUS
|
||||
IMPORT char * hwMemAlloc (int reqSize);
|
||||
#endif
|
||||
|
||||
/* globals */
|
||||
|
||||
const UINT32 ioApicRed0_15 = IOAPIC_EDGE | IOAPIC_HIGH | IOAPIC_FIXED;
|
||||
const UINT32 ioApicRed16_23 = IOAPIC_LEVEL | IOAPIC_LOW | IOAPIC_FIXED;
|
||||
|
||||
UINT32 ioApicVersion[MAX_IOAPICS]; /* IO APIC version register per APIC */
|
||||
UINT8 ioApicRedNum[MAX_IOAPICS]; /* IO APIC redirection table number per APIC */
|
||||
UINT32 ioApicRedEntries = 24;
|
||||
|
||||
/* locals */
|
||||
|
||||
LOCAL UINT32 * ioApicIntTable;
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
STATUS ioApicIrqMove (INT32 srcIrq, INT32 dstIrq); /* not published yet */
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicInit - initialize the IO APIC or xAPIC
|
||||
*
|
||||
* This routine initializes the IO APIC or xAPIC.
|
||||
*
|
||||
*/
|
||||
|
||||
STATUS ioApicInit (void)
|
||||
{
|
||||
INT32 ix,ioApicId;
|
||||
UINT32 ioApicBase,ioApicData;
|
||||
UINT32 entries = 0;
|
||||
|
||||
/* enable the IOAPIC */
|
||||
|
||||
if (MAX_IOAPICS < NUM_IOAPICS)
|
||||
return (ERROR);
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
if (sysBp)
|
||||
#else
|
||||
if (sysCpuNumGet() == 0)
|
||||
#endif
|
||||
ioApicEnable (TRUE);
|
||||
|
||||
|
||||
for (ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
|
||||
{
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
|
||||
/* get the IOAPIC version */
|
||||
|
||||
ioApicVersion[ioApicId] = ioApicGet (ioApicBase, ioApicData, IOAPIC_VERS);
|
||||
|
||||
/* get a number of redirection table entries */
|
||||
ioApicRedNum[ioApicId] = ((ioApicVersion[ioApicId] & IOAPIC_MRE_MASK) >> 16) + 1;
|
||||
}
|
||||
|
||||
for (ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
|
||||
entries += ioApicRedNum[ioApicId];
|
||||
|
||||
ioApicRedEntries = entries;
|
||||
|
||||
/* allocate memory for saving the interrupt mask bit */
|
||||
|
||||
#if !defined (INCLUDE_VXBUS)
|
||||
|
||||
ioApicIntTable = (UINT32 *) memalign (_CACHE_ALIGN_SIZE, entries * sizeof (UINT32));
|
||||
|
||||
#else /* defined (INCLUDE_VXBUS) */
|
||||
|
||||
/* Note, hwMemAlloc() doesn't return on failure. */
|
||||
ioApicIntTable = (UINT32 *)
|
||||
hwMemAlloc (_CACHE_ALIGN_SIZE + entries * sizeof (UINT32));
|
||||
ioApicIntTable = (UINT32 *)(((UINT32)ioApicIntTable + _CACHE_ALIGN_SIZE - 1) &
|
||||
~(_CACHE_ALIGN_SIZE - 1));
|
||||
|
||||
#endif /* defined (INCLUDE_VXBUS) */
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
if (sysBp == FALSE)
|
||||
#else
|
||||
if (sysCpuNumGet() != 0)
|
||||
#endif /* _WRS_CONFIG_SMP */
|
||||
return (OK);
|
||||
|
||||
for (ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
|
||||
{
|
||||
int lastentry = 0;
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
entries = ioApicRedNum[ioApicId];
|
||||
|
||||
/* set the IOAPIC bus arbitration ID */
|
||||
|
||||
ioApicSet (ioApicBase, ioApicData, IOAPIC_ID,
|
||||
ioApicGet (ioApicBase, ioApicData, IOAPIC_ID));
|
||||
|
||||
/* set the int-delivery type to Front Side Bus, not APIC Serial Bus */
|
||||
|
||||
if (sysProcessor == X86CPU_PENTIUM4)
|
||||
ioApicSet (ioApicBase, ioApicData, IOAPIC_BOOT, IOAPIC_DT_FS);
|
||||
|
||||
/* initialize the redirection table for the first ioapic with the default values */
|
||||
if(ioApicId == 0)
|
||||
{
|
||||
for (ix = 0; ix < entries; ix++)
|
||||
{
|
||||
UINT32 lower32;
|
||||
UINT32 upper32 = (loApicId << 24);
|
||||
UINT32 vector = (IOAPIC_INT_MASK | IOAPIC_PHYSICAL | sysInumTbl[ix]);
|
||||
|
||||
if (ix < 16)
|
||||
lower32 = (ioApicRed0_15 | vector);
|
||||
else
|
||||
lower32 = (ioApicRed16_23 | vector);
|
||||
|
||||
ioApicRedSet (ix, upper32, lower32, ioApicId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ix = 0; ix < entries; ix++)
|
||||
{
|
||||
UINT32 lower32, vector;
|
||||
UINT32 upper32 = (loApicId << 24);
|
||||
if(ix < NUM_REDIRECTION_ENTRIES(ioApicId))
|
||||
{
|
||||
vector = (IOAPIC_INT_MASK | IOAPIC_PHYSICAL | sysInumTbl[ix + IRQ_OFFSET(ioApicId)]);
|
||||
lower32 = (IOAPIC_INT_MASK | IOAPIC_PHYSICAL | ioApicRed16_23 | vector);
|
||||
}
|
||||
else
|
||||
lower32 = IOAPIC_INT_MASK;
|
||||
|
||||
ioApicRedSet (IRQ_TO_BIRQ(ioApicId, ix), upper32, lower32, ioApicId);
|
||||
}
|
||||
}
|
||||
lastentry += entries;
|
||||
}
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicEnable - enable or disable the IO xAPIC in ICHx
|
||||
*
|
||||
* This routine enables or disables the IO xAPIC in ICHx. If the parameter is
|
||||
* TRUE, the IO xAPIC in ICHx is enabled and the default ISA IRQ routing
|
||||
* information is saved in the table. If the parameter is FALSE, the IO xAPIC
|
||||
* in ICHx is disabled.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void ioApicEnable
|
||||
(
|
||||
BOOL enable /* enable the IO xAPIC in ICHx */
|
||||
)
|
||||
{
|
||||
/* enables or disables the IO APIC */
|
||||
|
||||
sysPciIoApicEnable (enable);
|
||||
|
||||
/* enables or disables the PIRQ direct handling */
|
||||
|
||||
sysPciPirqEnable (enable);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIntEoi - 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
|
||||
*/
|
||||
|
||||
LOCAL void ioApicIntEoi
|
||||
(
|
||||
INT32 irqNo /* INTIN number to send EOI */
|
||||
)
|
||||
{
|
||||
UINT32 ioApicId;
|
||||
#ifdef SYS_INT_DEBUG
|
||||
extern UINT32 sysIntCount [];
|
||||
sysIntCount [irqNo]++;
|
||||
#endif /* SYS_INT_DEBUG */
|
||||
for(ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
|
||||
{
|
||||
|
||||
if (ioApicVersion[ioApicId] & IOAPIC_PRQ)
|
||||
{
|
||||
*(int *)(LID_TO_BASE(ioApicId) + IOAPIC_EOI) = INT_NUM_GET(irqNo);
|
||||
#ifdef SYS_INT_DEBUG
|
||||
/* do not log console interrupts */
|
||||
if(irqNo != (devParas[CONSOLE_TTY].intLevel))
|
||||
logMsg ("IRQ(%d), serviced by IOAPIC(%d), Vector(%x)\n",
|
||||
irqNo, 0, INT_NUM_GET(irqNo), 4,5,6);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
*(int *)(loApicBase + LOAPIC_EOI) = 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIntEnable - enable a specified APIC interrupt input line
|
||||
*
|
||||
* This routine enables a specified APIC interrupt input line.
|
||||
*
|
||||
* RETURNS: OK or ERROR if the interrupt input line number is invalid
|
||||
*
|
||||
* SEE ALSO: ioApicIntDisable()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
STATUS ioApicIntEnable
|
||||
(
|
||||
INT32 irqNo /* INTIN number to enable */
|
||||
)
|
||||
{
|
||||
UINT32 ioApicBase,ioApicData, ioApicId;
|
||||
UINT32 lower32, upper32;
|
||||
|
||||
ioApicId = irqNo / 24;
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
|
||||
ioApicRedGet((INT32) (IRQ_TO_BIRQ(ioApicId, irqNo)), (INT32 *) &upper32,
|
||||
(INT32 *) &lower32, (INT32) ioApicId);
|
||||
upper32 = (loApicId << 24);
|
||||
|
||||
/* enable the interrupt */
|
||||
return ioApicRedSet(IRQ_TO_BIRQ(ioApicId, irqNo), upper32, lower32 & ~IOAPIC_INT_MASK, ioApicId);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIntDisable - disable a specified APIC interrupt input line
|
||||
*
|
||||
* This routine disables a specified APIC interrupt input line.
|
||||
*
|
||||
* RETURNS: OK or ERROR if the interrupt input line number is invalid
|
||||
*
|
||||
* SEE ALSO: ioApicIntEnable()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL STATUS ioApicIntDisable
|
||||
(
|
||||
INT32 irqNo /* INTIN number to disable */
|
||||
)
|
||||
{
|
||||
UINT32 ioApicBase,ioApicData, ioApicId;
|
||||
UINT32 lower32, upper32;
|
||||
ioApicId = irqNo / 24;
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
|
||||
ioApicRedGet((INT32) (IRQ_TO_BIRQ(ioApicId, irqNo)), (INT32 *) &upper32,
|
||||
(INT32 *) &lower32, (INT32) ioApicId);
|
||||
|
||||
/* disable the interrupt */
|
||||
return ioApicRedSet(IRQ_TO_BIRQ(ioApicId, irqNo), upper32, lower32 | IOAPIC_INT_MASK, ioApicId);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIntLock - lock out all IO APIC interrupts
|
||||
*
|
||||
* This routine saves the mask and locks out all IO APIC interrupts.
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: ioApicIntUnlock()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL VOID ioApicIntLock (void)
|
||||
|
||||
{
|
||||
INT32 ix;
|
||||
INT32 upper32;
|
||||
INT32 lower32;
|
||||
INT32 ioApicId = 0;
|
||||
|
||||
for (ix = 0; ix < 24; ix++)
|
||||
{
|
||||
ioApicRedGet (IRQ_TO_BIRQ(ioApicId, ix), &upper32, &lower32, ioApicId);
|
||||
|
||||
/* lock if the destination is my Local APIC and unlocked */
|
||||
|
||||
if ((((upper32 & IOAPIC_DESTINATION) >> 24) == loApicId) &&
|
||||
((lower32 & IOAPIC_INT_MASK) == 0))
|
||||
{
|
||||
ioApicRedSet(IRQ_TO_BIRQ(ioApicId, ix), upper32, lower32 | IOAPIC_INT_MASK, ioApicId);
|
||||
ioApicIntTable[ix] = lower32; /* save the old state */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIntUnlock - unlock the IO APIC interrupts
|
||||
*
|
||||
* This routine restores the mask and unlocks the IO APIC interrupts
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: ioApicIntLock()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL VOID ioApicIntUnlock (void)
|
||||
|
||||
{
|
||||
INT32 ix;
|
||||
INT32 upper32;
|
||||
INT32 lower32;
|
||||
INT32 ioApicId = 0;
|
||||
|
||||
for (ix = 0; ix < 24; ix++)
|
||||
{
|
||||
ioApicRedGet (IRQ_TO_BIRQ(ioApicId, ix), &upper32, &lower32, ioApicId);
|
||||
|
||||
/* unlock if the destination is my Local APIC and unlocked */
|
||||
|
||||
if ((((upper32 & IOAPIC_DESTINATION) >> 24) == loApicId)
|
||||
&& ((ioApicIntTable[ix] & IOAPIC_INT_MASK) == 0))
|
||||
{
|
||||
ioApicRedSet(IRQ_TO_BIRQ(ioApicId, ix), upper32, lower32 & ~IOAPIC_INT_MASK, ioApicId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicGet - get a value from the IO APIC register.
|
||||
*
|
||||
* This routine gets a value from the IO APIC register.
|
||||
*
|
||||
* RETURNS: A value of the IO APIC register.
|
||||
*/
|
||||
|
||||
INT32 ioApicGet
|
||||
(
|
||||
UINT32 index, /* IO register select (index) */
|
||||
UINT32 data, /* IO window (data) */
|
||||
INT32 offset /* offset to the register */
|
||||
)
|
||||
{
|
||||
INT32 value;
|
||||
INT32 oldLevel;
|
||||
|
||||
oldLevel = intLock (); /* LOCK INTERRUPT */
|
||||
*(char *)index = (char)offset; /* select the register */
|
||||
value = *(int *)data; /* must be a 32bit read */
|
||||
intUnlock (oldLevel); /* UNLOCK */
|
||||
|
||||
return (value);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicSet - set a value into the IO APIC register.
|
||||
*
|
||||
* This routine sets a value into the IO APIC register.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void ioApicSet
|
||||
(
|
||||
UINT32 index, /* IO register select (index) */
|
||||
UINT32 data, /* IO window (data) */
|
||||
INT32 offset, /* offset to the register */
|
||||
INT32 value /* value to set the register */
|
||||
)
|
||||
{
|
||||
INT32 oldLevel;
|
||||
|
||||
oldLevel = intLock (); /* LOCK INTERRUPT */
|
||||
*(char *)index = (char)offset; /* select the register */
|
||||
*(int *)data = value; /* must be a 32bit write */
|
||||
intUnlock (oldLevel); /* UNLOCK */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicRedGet - get a specified entry in the Redirection Table
|
||||
*
|
||||
* This routine gets a specified entry in the Redirection Table
|
||||
*
|
||||
* RETURNS: OK, or ERROR if intNum is out of range
|
||||
*/
|
||||
|
||||
STATUS ioApicRedGet
|
||||
(
|
||||
INT32 irq, /* index of the table */
|
||||
INT32 * pUpper32, /* upper 32 bit (MS LONG) */
|
||||
INT32 * pLower32, /* lower 32 bit (LS LONG) */
|
||||
INT32 ioApicId
|
||||
)
|
||||
{
|
||||
UINT32 ioApicBase,ioApicData;
|
||||
INT32 offset;
|
||||
|
||||
if (irq >= ioApicRedNum[ioApicId])
|
||||
return (ERROR);
|
||||
|
||||
offset = IOAPIC_REDTBL + (irq << 1);
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
|
||||
|
||||
*pUpper32 = ioApicGet (ioApicBase, ioApicData, offset + 1);
|
||||
*pLower32 = ioApicGet (ioApicBase, ioApicData, offset);
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicRedSet - set a specified entry in the Redirection Table
|
||||
*
|
||||
* This routine sets a specified entry in the Redirection Table
|
||||
*
|
||||
* RETURNS: OK, or ERROR if intNum is out of range
|
||||
*/
|
||||
|
||||
STATUS ioApicRedSet
|
||||
(
|
||||
INT32 irq, /* index of the table */
|
||||
INT32 upper32, /* upper 32 bit (MS LONG) */
|
||||
INT32 lower32, /* lower 32 bit (LS LONG) */
|
||||
INT32 ioApicId
|
||||
)
|
||||
{
|
||||
UINT32 ioApicBase, ioApicData;
|
||||
INT32 offset;
|
||||
|
||||
if (irq >= ioApicRedNum[ioApicId])
|
||||
return (ERROR);
|
||||
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
offset = IOAPIC_REDTBL + (irq << 1);
|
||||
|
||||
ioApicSet (ioApicBase, ioApicData, offset + 1, upper32);
|
||||
ioApicSet (ioApicBase, ioApicData, offset, lower32);
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIrqMove - move interrupt handler from source IRQ to destination IRQ
|
||||
*
|
||||
* This routine moves the interrupt handler from the source IRQ to the
|
||||
* destination IRQ. If the source IRQ's interrupt handler is the default
|
||||
* handler, it just returns. Otherwise it is moved and the destination IRQ's
|
||||
* vector table entry will be overridden. This routine is for the chipset
|
||||
* that have programmable IRQ capability. This routine should be called at
|
||||
* the initialization time, otherwise there are no guarantee for losing
|
||||
* interrupts. The polarity and the trigger mode of the IRQ is not changed.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if the source intHandler is the default handler.
|
||||
*/
|
||||
|
||||
STATUS ioApicIrqMove
|
||||
(
|
||||
INT32 srcIrq, /* source IRQ moving from */
|
||||
INT32 dstIrq /* destination IRQ moving to */
|
||||
)
|
||||
{
|
||||
FUNCPTR intHandler; /* interrupt handler */
|
||||
INT32 idtType; /* IDT type */
|
||||
INT32 selector; /* code selector */
|
||||
INT32 srcInum = INT_NUM_GET (srcIrq);
|
||||
INT32 dstInum = INT_NUM_GET (dstIrq);
|
||||
INT8 * pCode; /* pointer to intConnect code */
|
||||
INT32 oldLevel;
|
||||
|
||||
/* lock interrupts */
|
||||
|
||||
oldLevel = intLock (); /* LOCK INTERRUPTS */
|
||||
ioApicIntDisable (srcIrq);
|
||||
ioApicIntDisable (dstIrq);
|
||||
|
||||
/* get the info from the source IRQ vector table entry */
|
||||
|
||||
intVecGet2 ((FUNCPTR *)INUM_TO_IVEC (srcInum), &intHandler,
|
||||
&idtType, &selector);
|
||||
|
||||
/* return if the intHandler is the default handler */
|
||||
|
||||
if (intHandler == (FUNCPTR)&excCallTbl[srcInum * 5])
|
||||
return (ERROR);
|
||||
|
||||
/* set the info to the destination IRQ vector table entry */
|
||||
|
||||
intVecSet2 ((FUNCPTR *)INUM_TO_IVEC (dstInum), intHandler,
|
||||
idtType, selector);
|
||||
|
||||
/* update the IRQ (parameter of EOI routine) in the intConnect code */
|
||||
|
||||
if (intEoiGet != NULL)
|
||||
{
|
||||
pCode = (INT8 *)intHandler;
|
||||
*(INT32 *)(pCode + ICC_EOI_PARAM) = dstIrq;
|
||||
}
|
||||
|
||||
/* set the default interrupt handler to the source IRQ */
|
||||
|
||||
intVecSet2 ((FUNCPTR *)INUM_TO_IVEC (srcInum),
|
||||
(FUNCPTR)&excCallTbl[srcInum * 5],
|
||||
sysIntIdtType, sysCsInt);
|
||||
|
||||
/* unlock interrupts */
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
|
||||
ioApicIntEnable (dstIrq);
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIrqSet - set the Local APIC ID of the specified IRQ
|
||||
*
|
||||
* This routine sets the Local APIC ID of the specified IRQ in the IO APIC
|
||||
* Redirection Table.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if the IRQ is out of bound
|
||||
*/
|
||||
|
||||
STATUS ioApicIrqSet
|
||||
(
|
||||
INT32 irq, /* IRQ */
|
||||
INT32 destApicId, /* Local APIC ID */
|
||||
INT32 sourceApicId
|
||||
)
|
||||
{
|
||||
INT32 upper32;
|
||||
INT32 oldLevel;
|
||||
UINT32 ioApicBase,ioApicData;
|
||||
INT32 offset = IOAPIC_REDTBL + (irq * 2);
|
||||
ioApicBase = LID_TO_BASE(sourceApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
|
||||
if (irq >= ioApicRedNum[destApicId])
|
||||
return (ERROR);
|
||||
|
||||
/* lock interrupts */
|
||||
|
||||
oldLevel = intLock (); /* LOCK INTERRUPTS */
|
||||
ioApicIntDisable (irq);
|
||||
|
||||
/* set the loApicId */
|
||||
|
||||
upper32 = ioApicGet (ioApicBase, ioApicData, offset + 1);
|
||||
upper32 = (upper32 & ~IOAPIC_DESTINATION) | (destApicId << 24);
|
||||
ioApicSet (ioApicBase, ioApicData, offset + 1, upper32);
|
||||
|
||||
/* unlock interrupts */
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
|
||||
ioApicIntEnable (irq);
|
||||
|
||||
return (OK);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/* ioApicIntrShow.c - Intel IO APIC/xAPIC driver show routines */
|
||||
|
||||
/* Copyright 1984-2002 Wind River Systems, Inc. */
|
||||
|
||||
#include "copyright_wrs.h"
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01d,26jul06,scm update for pentium/xeon support...
|
||||
01c,01apr04,dmh add support for multiple APICs
|
||||
01b,08mar02,hdn added the description
|
||||
01a,25jun01,hdn extracted from 01d version of ioApicIntr.c
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This module is a show routine for the IO APIC/xAPIC (Advanced
|
||||
Programmable Interrupt Controller) for P6 (PentiumPro, II, III)
|
||||
family processors and P7 (Pentium4) family processors.
|
||||
ioApicShow() shows content of the IO APIC registers.
|
||||
|
||||
INCLUDE FILES: loApic.h, ioApic.h
|
||||
|
||||
SEE ALSO: ioApicIntr.c
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include "drv/intrCtl/loApic.h"
|
||||
#include "drv/intrCtl/ioApic.h"
|
||||
|
||||
/* externs */
|
||||
|
||||
|
||||
/* globals */
|
||||
|
||||
|
||||
/* locals */
|
||||
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicShow - show IO APIC registers
|
||||
*
|
||||
* This routine shows IO APIC registers
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void ioApicShow (void)
|
||||
{
|
||||
int ix,id;
|
||||
int version;
|
||||
UINT32 ioApicBase,ioApicData;
|
||||
|
||||
for(id = 0; id < NUM_IOAPICS; id++)
|
||||
{
|
||||
ioApicBase = LID_TO_BASE(id);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
|
||||
printf ("IOAPIC_ID = 0x%08x\n",
|
||||
ioApicGet (ioApicBase, ioApicData, IOAPIC_ID));
|
||||
|
||||
version = ioApicGet (ioApicBase, ioApicData, IOAPIC_VERS);
|
||||
printf ("IOAPIC_VER = 0x%08x\n", version);
|
||||
|
||||
printf ("IOAPIC_ARB = 0x%08x\n",
|
||||
ioApicGet (ioApicBase, ioApicData, IOAPIC_ARB));
|
||||
|
||||
if (ioApicVersion[id] & IOAPIC_PRQ) /* use PRQ bit XXX */
|
||||
printf ("IOAPIC_BOOT = 0x%08x\n",
|
||||
ioApicGet (ioApicBase, ioApicData, IOAPIC_BOOT));
|
||||
|
||||
for (ix = 0; ix <= ((version & IOAPIC_MRE_MASK) >> 16); ix++)
|
||||
{
|
||||
printf ("IOAPIC_TBL%02d = 0x%08x ", ix,
|
||||
ioApicGet (ioApicBase, ioApicData, IOAPIC_REDTBL + ix * 2 + 1));
|
||||
printf ("%08x\n",
|
||||
ioApicGet (ioApicBase, ioApicData, IOAPIC_REDTBL + ix * 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,493 @@
|
||||
/* ixp400IntrCtl.c - interrupt controller driver for the ixp400 */
|
||||
|
||||
/*
|
||||
Copyright (c) 2002, 2004, 2005 Wind River Systems, Inc. All rights reserved.
|
||||
Certain portions of these files may be copyright (c) 2002-2004 Intel
|
||||
Corporation.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01d,23jun05,m_h SPR 109992 ixp400IntLvlChg while intLock
|
||||
01c,28jan05,pai Unconditionally compile for ixp465.
|
||||
01b,20dec04,pai Updated copyright notice.
|
||||
01a,05jun02,jb initial version...
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This module implements the Ixp400 interrupt controller driver.
|
||||
|
||||
The Ixp400 interrupt controller is a simple, generic interrupt controller
|
||||
described in full Ixp400 Data Book [Reference[]]. The
|
||||
interrupt controller has status and request registers, separate enable
|
||||
and disable registers and supports level-sensitive interrupts. This
|
||||
library provides the routines to manage interrupts multiplexed by the
|
||||
Ixp400 interrupt controller.
|
||||
|
||||
The Ixp400 interrupt controller has a number of registers. Those used by
|
||||
this driver are described below under the symbolic names used herein.
|
||||
|
||||
IXP400_ICMR (write): this is the "Enable Set" register. When this register is
|
||||
written, each data bit that is set (1) causes the corresponding
|
||||
interrupt to be enabled. Bits that are clear (0) have no effect.
|
||||
|
||||
IXP400_ICIP (read): this is the "Interrupt Request" register.
|
||||
When this register is read, each data bit that is set (1) indicates an
|
||||
interrupt source that is both active and enabled i.e. can interrupt the
|
||||
processor.
|
||||
|
||||
The number of interrupts supported by the device i.e. the number of
|
||||
bits in the IXP400_ICIP register, is specified by
|
||||
IXP400_INT_NUM_LEVELS.
|
||||
|
||||
We assume that config.h or <bsp>.h has defined the addresses of the
|
||||
controller chips registers: IXP400_ICMR,
|
||||
IXP400_ICIP and also the driver constant IXP400_INT_NUM_LEVELS.
|
||||
|
||||
This driver assumes that the chip is memory-mapped and does direct
|
||||
memory accesses to the registers which are assumed to be 32 bits wide.
|
||||
If a different access method is needed, the BSP can redefine the macros
|
||||
IXP400_INT_REG_READ(addr,result) and IXP400_INT_REG_WRITE(addr,data).
|
||||
|
||||
This driver assumes that interrupt vector numbers are calculated and
|
||||
not the result of a special cycle on the bus. Vector numbers are
|
||||
generated by adding the current interrupt level number to
|
||||
AMBA_INT_VEC_BASE to generate a vector number which the architecture
|
||||
level will use to invoke the proper handling routine. If a different
|
||||
mapping scheme, or a special hardware routine is needed, then the BSP
|
||||
should redefine the macro IXP400_INT_LVL_VEC_MAP(level,vector) to
|
||||
override the version defined in this file.
|
||||
|
||||
|
||||
Priorities
|
||||
==========
|
||||
The order of interrupt level priority is undefined at the architecture
|
||||
level. In this driver, level 0 is highest and and indicates that all
|
||||
levels are disabled; level <IXP400_INT_NUM_LEVELS> is the lowest and
|
||||
indicates that all levels are enabled.
|
||||
|
||||
By default, this driver implements a least-significant bit first
|
||||
interrupt priority scheme (this is compatible with earlier versions of
|
||||
this driver) which requires a definition of ambaIntLvlMask (see above).
|
||||
|
||||
Note: The IXP400 interrupt controller provides a mechanism to reorder the
|
||||
priority order of the top 8 interrupts sources. The IXP400_ICHR may
|
||||
be programmed to change the default behaviour. To change the default
|
||||
priority IXP400_ICHR_INIT_VALUE should be redefined.
|
||||
|
||||
The BSP will initialize this driver in sysHwInit2(), after initializing
|
||||
the main interrupt library, usually intLibInit(). The initialization
|
||||
routine, ixp400IntDevInit() will setup the interrupt controller device,
|
||||
it will mask off all individual interrupt sources and then set the
|
||||
interrupt level to enable all interrupts. See ixp400IntDevInit for more
|
||||
information.
|
||||
|
||||
All of the functions in this library are global. This allows them to
|
||||
be used by the BSP if it is necessary to create wrapper routines or to
|
||||
incorporate several drivers together as one.
|
||||
|
||||
.SH INCLUDE FILES:
|
||||
drv/intrCtl/ixp400IntrCtl.h
|
||||
|
||||
SEE ALSO:
|
||||
.I "Ixp400 Data Sheet,"
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "vxWorks.h"
|
||||
#include "config.h"
|
||||
#include "ixp400.h"
|
||||
#include "drv/intrCtl/ixp400IntrCtl.h"
|
||||
#include "intLib.h"
|
||||
|
||||
IMPORT int ffsLsb (UINT32);
|
||||
|
||||
/* Defines from config.h, or <bsp>.h */
|
||||
|
||||
#if !defined (IXP400_ICIP) || !defined (IXP400_ICMR) || \
|
||||
!defined (IXP400_INT_NUM_LEVELS)
|
||||
#error missing IXP400 interrupt definitions
|
||||
#endif
|
||||
|
||||
#define IXP400_INT_VEC_BASE (0x0)
|
||||
|
||||
|
||||
|
||||
|
||||
/* Convert level number to vector number */
|
||||
|
||||
#ifndef IXP400_INT_LVL_VEC_MAP
|
||||
#define IXP400_INT_LVL_VEC_MAP(level, vector) \
|
||||
((vector) = ((level) + IXP400_INT_VEC_BASE))
|
||||
#endif /* IXP400_INT_LVL_VEC_MAP */
|
||||
|
||||
|
||||
/* Convert pending register value, to a level number */
|
||||
|
||||
#ifndef IXP400_INT_PEND_LVL_MAP
|
||||
#define IXP400_INT_PEND_LVL_MAP(pendReg, level) \
|
||||
((level) = (pendReg))
|
||||
#endif /* IXP400_INT_PEND_LVL_MAP */
|
||||
|
||||
|
||||
/* driver constants */
|
||||
|
||||
#define IXP400_INT_ALL_ENABLED (IXP400_INT_NUM_LEVELS)
|
||||
#define IXP400_INT_ALL_DISABLED 0
|
||||
|
||||
#define IXP400_MASK_ALL_INTERRUPTS() IXP400_REG_INT_WRITE (IXP400_ICMR,0x00000000);\
|
||||
IXP400_REG_INT_WRITE (IXP400_ICMR_UPPER,0x00000000);
|
||||
|
||||
/* Local data */
|
||||
|
||||
/* Current interrupt level setting (ixp400IntLvlChg). */
|
||||
|
||||
LOCAL UINT32 ixp400IntLvlCurrent = IXP400_INT_ALL_DISABLED; /* all levels disabled*/
|
||||
|
||||
/*
|
||||
* A mask word. Bits are set in this word when a specific level
|
||||
* is enabled. It is used to mask off individual levels that have
|
||||
* not been explicitly enabled.
|
||||
*/
|
||||
|
||||
LOCAL UINT32 ixp400IntLvlEnabled;
|
||||
LOCAL UINT32 ixp400IntLvlEnabledUpper;
|
||||
|
||||
/* use this table for INT 0-31*/
|
||||
LOCAL UINT32 ixp400IntLvlMask [IXP400_INT_NUM_LEVELS_LOWER + 1] = /* int lvl mask */
|
||||
{
|
||||
0x0000, /* level 0, all disabled */
|
||||
0x00000001, 0x00000003, 0x00000007, 0x0000000f,
|
||||
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
|
||||
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
|
||||
0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
|
||||
0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
|
||||
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
|
||||
0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
|
||||
0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff,
|
||||
/* level 1-32 all enabled */
|
||||
};
|
||||
|
||||
LOCAL UINT32 ixp400IntLvlMaskUpper[(IXP400_INT_NUM_LEVELS-IXP400_INT_NUM_LEVELS_LOWER) + 1] = /* int lvl mask */
|
||||
/* use this table for INT 32-63*/
|
||||
{
|
||||
0x0000, /* 33-64 all disabled */
|
||||
0x00000001, 0x00000003, 0x00000007, 0x0000000f,
|
||||
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
|
||||
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
|
||||
0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
|
||||
0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
|
||||
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
|
||||
0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
|
||||
0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff,
|
||||
/* level 33-64 all enabled */
|
||||
};
|
||||
#if IXP400_INT_NUM_LEVELS != 64
|
||||
#error ixp400IntLvlMask is wrong size for number of levels
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
STATUS ixp400IntLvlVecChk (int*, int*);
|
||||
STATUS ixp400IntLvlVecAck (int, int);
|
||||
int ixp400IntLvlChg (int);
|
||||
STATUS ixp400IntLvlEnable (int);
|
||||
STATUS ixp400IntLvlDisable (int);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ixp400IntDevInit - initialize the interrupt controller
|
||||
*
|
||||
* This routine will initialize the interrupt controller device, disabling all
|
||||
* interrupt sources. It will also connect the device driver specific routines
|
||||
* into the architecture level hooks. If the BSP needs to create a wrapper
|
||||
* routine around any of the arhitecture level routines, it should install the
|
||||
* pointer to the wrapper routine after calling this routine.
|
||||
*
|
||||
* RETURNS: OK
|
||||
*/
|
||||
|
||||
STATUS ixp400IntDevInit (void)
|
||||
{
|
||||
|
||||
/* install the driver routines in the architecture hooks */
|
||||
|
||||
sysIntLvlVecChkRtn = ixp400IntLvlVecChk;
|
||||
sysIntLvlVecAckRtn = ixp400IntLvlVecAck;
|
||||
sysIntLvlChgRtn = ixp400IntLvlChg;
|
||||
sysIntLvlEnableRtn = ixp400IntLvlEnable;
|
||||
sysIntLvlDisableRtn = ixp400IntLvlDisable;
|
||||
|
||||
ixp400IntLvlEnabled = 0; /* all sources disabled 0-31*/
|
||||
|
||||
ixp400IntLvlEnabledUpper = 0; /* all sources disabled 32-63*/
|
||||
|
||||
/*
|
||||
* Set default interrupty priority.
|
||||
*/
|
||||
|
||||
IXP400_REG_INT_WRITE (IXP400_ICHR, IXP400_ICHR_INIT_VALUE);
|
||||
|
||||
ixp400IntLvlChg (IXP400_INT_ALL_ENABLED); /* enable all levels */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ixp400IntLvlVecChk - check for and return any pending interrupts
|
||||
*
|
||||
* This routine interrogates the hardware to determine the highest priority
|
||||
* interrupt pending. It returns the vector associated with that interrupt, and
|
||||
* also the interrupt priority level prior to the interrupt (not the
|
||||
* level of the interrupt). The current interrupt priority level is then
|
||||
* raised to the level of the current interrupt so that only higher priority
|
||||
* interrupts will be accepted until this interrupt is finished.
|
||||
*
|
||||
* This routine must be called with CPU interrupts disabled.
|
||||
*
|
||||
* The return value ERROR indicates that no pending interrupt was found and
|
||||
* that the level and vector values were not returned.
|
||||
*
|
||||
* RETURNS: OK or ERROR if no interrupt is pending.
|
||||
*
|
||||
*
|
||||
* Note:
|
||||
* This routine does not employ the INTR_IRQ_ENC_ST (aka register IXP400_ICIH) which encodes
|
||||
* the highest priority interrupt (incremented by 1) since the interrupt priority regsiter
|
||||
* INTR_PRTY (aka IXP400_ICHR) is programmed to its default priorities
|
||||
*/
|
||||
|
||||
STATUS ixp400IntLvlVecChk
|
||||
(
|
||||
int* pLevel, /* ptr to receive old interrupt level */
|
||||
int* pVector /* ptr to receive current interrupt vector */
|
||||
)
|
||||
{
|
||||
int newLevel;
|
||||
int newLevelTmp;
|
||||
UINT32 isr;
|
||||
UINT32 isrUpper = 0;
|
||||
|
||||
/* Read pending interrupt register and mask undefined bits */
|
||||
isr = IXP400_REG_INT_READ (IXP400_ICIP);
|
||||
|
||||
isrUpper = IXP400_REG_INT_READ (IXP400_ICIP_UPPER);
|
||||
|
||||
/* If no interrupt is pending, return ERROR */
|
||||
if ((0==isr) && (0==isrUpper))
|
||||
return ERROR;
|
||||
|
||||
|
||||
/* find first bit set in ISR, starting from lowest-numbered bit */
|
||||
|
||||
if (0 == (newLevel = ffsLsb (isr)))
|
||||
{
|
||||
if (0 == (newLevel = ffsLsb (isrUpper)))
|
||||
{return ERROR;}
|
||||
else
|
||||
{
|
||||
/* newlevel is 1 to 32, add lower level offset */
|
||||
newLevel += IXP400_INT_NUM_LEVELS_LOWER;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
--newLevel; /* ffsLsb returns numbers from 1, not 0 */
|
||||
|
||||
/* map the interrupting device to an interrupt level number */
|
||||
|
||||
IXP400_INT_PEND_LVL_MAP (newLevel, newLevelTmp);
|
||||
|
||||
/* change to new interrupt level, returning previous level to caller */
|
||||
|
||||
*pLevel = ixp400IntLvlChg (newLevelTmp);
|
||||
|
||||
|
||||
/* fetch, or compute the interrupt vector number */
|
||||
|
||||
IXP400_INT_LVL_VEC_MAP (newLevelTmp, *pVector);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ixp400IntLvlVecAck - acknowledge the current interrupt
|
||||
*
|
||||
* Acknowledge the current interrupt cycle. The level and vector values are
|
||||
* those generated during the ixp400IntLvlVecChk() routine for this interrupt
|
||||
* cycle. The basic action is to reset the current interrupt and return
|
||||
* the interrupt level to its previous setting. Note that the Ixp400 interrupt
|
||||
* controller does not need an acknowledge cycle.
|
||||
*
|
||||
* RETURNS: OK or ERROR if a hardware fault is detected.
|
||||
*/
|
||||
|
||||
STATUS ixp400IntLvlVecAck
|
||||
(
|
||||
int level, /* old interrupt level to be restored */
|
||||
int vector /* current interrupt vector, if needed */
|
||||
)
|
||||
{
|
||||
/* restore the previous interrupt level */
|
||||
|
||||
ixp400IntLvlChg (level);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ixp400IntLvlChg - change the interrupt level value
|
||||
*
|
||||
* This routine implements the overall interrupt setting. All levels
|
||||
* up to and including the specifed level are disabled. All levels above
|
||||
* the specified level will be enabled, but only if they were specifically
|
||||
* enabled by the ixp400IntLvlEnable() routine.
|
||||
*
|
||||
* The specific priority level IXP400_INT_NUM_LEVELS is valid and represents
|
||||
* all levels enabled.
|
||||
*
|
||||
* Passing a value of -1 will reset the current interrupt level mask.
|
||||
*
|
||||
* RETURNS: Previous interrupt level.
|
||||
*/
|
||||
|
||||
int ixp400IntLvlChg
|
||||
(
|
||||
int level /* new interrupt level */
|
||||
)
|
||||
{
|
||||
int oldLevel;
|
||||
|
||||
oldLevel = ixp400IntLvlCurrent;
|
||||
|
||||
if (level >= 0 &&
|
||||
level <= IXP400_INT_NUM_LEVELS)
|
||||
{
|
||||
/* change current interrupt level */
|
||||
|
||||
ixp400IntLvlCurrent = level;
|
||||
}
|
||||
|
||||
|
||||
if (ixp400IntLvlCurrent >= IXP400_INT_NUM_LEVELS_LOWER)
|
||||
{
|
||||
/* Activate all the enabled interrupts for INT 0-31*/
|
||||
IXP400_REG_INT_WRITE (IXP400_ICMR,
|
||||
(ixp400IntLvlMask[IXP400_INT_NUM_LEVELS_LOWER] & ixp400IntLvlEnabled));
|
||||
|
||||
/* Activate the enabled interrupts for INTR 31-63 */
|
||||
IXP400_REG_INT_WRITE (IXP400_ICMR_UPPER,
|
||||
(ixp400IntLvlMaskUpper[ixp400IntLvlCurrent-IXP400_INT_NUM_LEVELS_LOWER] & ixp400IntLvlEnabledUpper));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Activate the enabled interrupts for INT 0-31 */
|
||||
IXP400_REG_INT_WRITE (IXP400_ICMR,
|
||||
(ixp400IntLvlMask[ixp400IntLvlCurrent] & ixp400IntLvlEnabled));
|
||||
|
||||
/* disable all interrupts for INTR 31-63 */
|
||||
IXP400_REG_INT_WRITE (IXP400_ICMR_UPPER, ixp400IntLvlMaskUpper[0]);
|
||||
}
|
||||
|
||||
return oldLevel;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ixp400IntLvlEnable - enable a single interrupt level
|
||||
*
|
||||
* Enable a specific interrupt level. The enabled level will be allowed
|
||||
* to generate an interrupt when the overall interrupt level is set to
|
||||
* enable interrupts of this priority (as configured by ixp400IntLvlPriMap,
|
||||
* if appropriate). Without being enabled, the interrupt is blocked
|
||||
* regardless of the overall interrupt level setting.
|
||||
*
|
||||
* RETURNS: OK or ERROR if the specified level cannot be enabled.
|
||||
*/
|
||||
|
||||
STATUS ixp400IntLvlEnable
|
||||
(
|
||||
int level /* level to be enabled */
|
||||
)
|
||||
{
|
||||
int key;
|
||||
|
||||
if (level < 0 ||
|
||||
level >= IXP400_INT_NUM_LEVELS)
|
||||
return ERROR;
|
||||
|
||||
|
||||
/* set bit in enable mask */
|
||||
|
||||
key = intLock ();
|
||||
|
||||
if (level >=IXP400_INT_NUM_LEVELS_LOWER)
|
||||
{
|
||||
ixp400IntLvlEnabledUpper |= (1 << (level-IXP400_INT_NUM_LEVELS_LOWER));
|
||||
}
|
||||
else
|
||||
{
|
||||
ixp400IntLvlEnabled |= (1 << level);
|
||||
}
|
||||
|
||||
|
||||
ixp400IntLvlChg (-1); /* reset current mask */
|
||||
|
||||
intUnlock (key);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ixp400IntLvlDisable - disable a single interrupt level
|
||||
*
|
||||
* Disable a specific interrupt level. The disabled level is prevented
|
||||
* from generating an interrupt even if the overall interrupt level is
|
||||
* set to enable interrupts of this priority.
|
||||
*
|
||||
* RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
|
||||
*/
|
||||
|
||||
STATUS ixp400IntLvlDisable
|
||||
(
|
||||
int level /* level to be disabled */
|
||||
)
|
||||
{
|
||||
int key;
|
||||
|
||||
if (level < 0 ||
|
||||
level >= IXP400_INT_NUM_LEVELS)
|
||||
return ERROR;
|
||||
|
||||
|
||||
/* clear bit in enable mask */
|
||||
|
||||
key = intLock ();
|
||||
|
||||
if (level >=IXP400_INT_NUM_LEVELS_LOWER)
|
||||
{
|
||||
ixp400IntLvlEnabledUpper &=
|
||||
~(1 << (level-IXP400_INT_NUM_LEVELS_LOWER));
|
||||
}
|
||||
else
|
||||
{
|
||||
ixp400IntLvlEnabled &= ~(1 << level);
|
||||
}
|
||||
|
||||
ixp400IntLvlChg (-1); /* reset current mask */
|
||||
|
||||
intUnlock (key);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,561 @@
|
||||
/* loApicIntr.c - Intel Pentium[234] Local APIC/xAPIC driver */
|
||||
|
||||
/*
|
||||
* Copyright 1984-2008 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01p,27aug08,jpb Renamed VSB header file
|
||||
01o,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
|
||||
for kernel configurations options set in vsb.
|
||||
01n,15mar07,scm correct mask in loApicIpi...
|
||||
01m,07dec06,scm smp:adjust loApicIpi for shorthand support...
|
||||
01l,15nov06,scm adjust loApicIpi for shortHand delivery...
|
||||
01k,13oct06,scm AP work...
|
||||
01j,09oct06,scm remove sysBp dependencey for SMP...
|
||||
01i,06sep06,scm debug for SMP...
|
||||
01h,26jul06,scm update for pentium/xeon support...
|
||||
01g,01apr04,dmh add support for multiple APICs
|
||||
01f,15may02,hdn changed apicId 8 bit to 16 bit, added DBG_MSG.
|
||||
added Error Status Register checking
|
||||
01e,08mar02,hdn updated loApicInit() and loApicIpi()
|
||||
added loApicEnable() for HTT (spr 73738)
|
||||
01d,29nov01,hdn doc update for 5.5
|
||||
01c,21jun01,hdn added support for Pentium4 Local xAPIC
|
||||
moved show routines to loApicIntrShow.c
|
||||
01b,25mar98,hdn re-written.
|
||||
01a,20jun97,sub written.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This module is a driver for the local APIC/xAPIC (Advanced Programmable
|
||||
Interrupt Controller) in P6 (PentiumPro, II, III) family processors
|
||||
and P7 (Pentium4) family processors. The local APIC/xAPIC is included
|
||||
in selected P6 (PentiumPro, II, III) and P7 (Pentium4) family processors.
|
||||
Beginning with the P6 family processors, the presence or absence of an
|
||||
on-chip local APIC can be detected using the CPUID instruction. When the
|
||||
CPUID instruction is executed, bit 9 of the feature flags returned in the
|
||||
EDX register indicates the presence (set) or absence (clear) of an on-chip
|
||||
local APIC.
|
||||
|
||||
The local APIC performs two main functions for the processor:
|
||||
- It processes local external interrupts that the processor receives at its
|
||||
interrupt pins and local internal interrupts that software generates.
|
||||
- In multiple-processor systems, it communicates with an external IO APIC
|
||||
chip. The external IO APIC receives external interrupt events from the
|
||||
system and interprocessor interrupts from the processors on the system bus
|
||||
and distributes them to the processors on the system bus. The IO APIC is
|
||||
part of Intel's system chip set.
|
||||
The local APIC controls the dispatching of interrupts (to its associated
|
||||
processor) that it receives either locally or from the IO APIC. It provides
|
||||
facilities for queuing, nesting and masking of interrupts. It handles the
|
||||
interrupt delivery protocol with its local processor and accesses to APIC
|
||||
registers, and also manages interprocessor interrupts and remote APIC register
|
||||
reads. A timer on the local APIC allows local generation of interrupts, and
|
||||
local interrupt pins permit local reception of processor-specific interrupts.
|
||||
The local APIC can be disabled and used in conjunction with a standard 8259A
|
||||
style interrupt controller. Disabling the local APIC can be done in hardware
|
||||
for the Pentium processors or in software for the P6 and P7 (Pentium4) family
|
||||
processors.
|
||||
|
||||
The local APIC in the Pentium4 processors (called the xAPIC) is an extension
|
||||
of the local APIC found in the P6 family processors. The primary difference
|
||||
between the APIC architecture and xAPIC architecture is that with Pentium4
|
||||
processors, the local xAPICs and IO xAPIC communicate with one another through
|
||||
the processors system bus; whereas, with the P6 family processors, communication
|
||||
between the local APICs and the IO APIC is handled through a dedicated 3-wire
|
||||
APIC bus. Also, some of the architectural features of the local APIC have been
|
||||
extended and/or modified in the local xAPIC.
|
||||
|
||||
The base address of the local APIC and IO APIC is taken from the MP configuration
|
||||
table (see Intel MP Specification Version 1.4) or the IA32_APIC_BASE MSR.
|
||||
It uses LOAPIC_BASE and IOAPIC_INDEX_BASE defined in the BSP, if it is not able
|
||||
to find the addresses. This driver contains three routines for use. They are:
|
||||
loApicInit() initializes the Local APIC for the interrupt mode chosen.
|
||||
loApicEnable() enables or disables the Local APIC.
|
||||
loApicIpi() delivers the inter processor interrupt to the specified local APIC.
|
||||
|
||||
Local APIC is used in the Virtual Wire Mode (define VIRTUAL_WIRE_MODE in the
|
||||
BSP) and the Symmetric IO Mode (define SYMMETRIC_IO_MODE in the BSP), but not
|
||||
in the PIC Mode which is the default interrupt mode and uses 8259A PIC.
|
||||
|
||||
Virtual Wire Mode is one of three interrupt modes defined by the MP
|
||||
specification. In this mode, interrupts are generated by the 8259A equivalent
|
||||
PICs, but delivered to the Boot Strap Processor by the local APIC that is
|
||||
programmed to act as a "virtual Wire"; that is, the local APIC is logically
|
||||
indistinguishable from a hardware connection. This is a uniprocessor
|
||||
compatibility mode.
|
||||
|
||||
Symmetric IO Mode is one of three interrupt modes defined by the MP
|
||||
specification. In this mode, the local and IO APICs are fully functional,
|
||||
and interrupts are generated and delivered to the processors by the APICs.
|
||||
Any interrupt can be delivered to any processor. This is the only
|
||||
multiprocessor interrupt mode.
|
||||
The local and IO APICs support interrupts in the range of 32 to 255.
|
||||
Interrupt priority is implied by its vector, according to the following
|
||||
relationship: "priority = vector / 16".
|
||||
Here the quotient is rounded down to the nearest integer value to determine
|
||||
the priority, with 1 being the lowest and 15 is the highest. Because vectors
|
||||
0 through 31 are reserved for exclusive use by the processor, the priority of
|
||||
user defined interrupts range from 2 to 15. A value of 15 in the Interrupt
|
||||
Class field of the Task Priority Register (TPR) will mask off all interrupts,
|
||||
which require interrupt service.
|
||||
The P6 family processor's local APIC includes an in-service entry and a holding
|
||||
entry for each priority level. To avoid losing interrupts, software should
|
||||
allocate no more than 2 interrupt vectors per priority. The Pentium4 processor
|
||||
expands this support of all acceptance of two interrupts per vector rather than
|
||||
per priority level.
|
||||
|
||||
INCLUDE FILES: loApic.h
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vsbConfig.h>
|
||||
|
||||
#include "drv/intrCtl/loApic.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
#undef LOAPIC_DBG
|
||||
|
||||
#ifdef LOAPIC_DBG
|
||||
# define LOAPIC_DBG_MSG(STR,VALUE) logMsg(STR,VALUE,0,0,0,0,0);
|
||||
#else
|
||||
# define LOAPIC_DBG_MSG(STR,VALUE)
|
||||
#endif /* IPI_DEBUG */
|
||||
|
||||
|
||||
/* externs */
|
||||
|
||||
IMPORT CPUID sysCpuId; /* CPUID structure */
|
||||
IMPORT UINT sysProcessor; /* CPU family */
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP */
|
||||
#endif /* !_WRS_CONFIG_SMP */
|
||||
|
||||
/* globals */
|
||||
|
||||
UINT32 loApicBase = LOAPIC_BASE; /* def Local APIC addr */
|
||||
UINT32 loApicId; /* local APIC Id */
|
||||
UINT32 loApicVersion; /* local APIC Version */
|
||||
UINT32 loApicMaxLvt; /* local APIC Max LVT */
|
||||
UINT32 loApicBusy = 0; /* counter for not sending IPI */
|
||||
|
||||
/* locals */
|
||||
|
||||
LOCAL UINT32 sysIntMaskLocalApic = 0;
|
||||
LOCAL UINT32 loApicOldSvr = 0; /* original SVR */
|
||||
LOCAL UINT32 loApicOldLint0 = 0; /* original LINT0 */
|
||||
LOCAL UINT32 loApicOldLint1 = 0; /* original LINT1 */
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
LOCAL void loApicIntEoi (INT32 irq);
|
||||
|
||||
#ifdef _WRS_CONFIG_SMP
|
||||
IMPORT int sysCpuNumGet (); /* define in sysLib.c of BSP */
|
||||
#endif /* _WRS_CONFIG_SMP */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicInit - initialize the Local APIC or xAPIC
|
||||
*
|
||||
* This routine initializes Local APIC or xAPIC.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
*/
|
||||
|
||||
void loApicInit (void)
|
||||
{
|
||||
UINT32 apicBase[2];
|
||||
|
||||
/* override loApicBase, sysBp from MSR if available */
|
||||
|
||||
if (sysCpuId.featuresEdx & CPUID_APIC)
|
||||
{
|
||||
pentiumMsrGet (IA32_APIC_BASE, (long long int *)&apicBase);
|
||||
loApicBase = apicBase[0] & LOAPIC_BASE_MASK; /* override */
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
sysBp = apicBase[0] & LOAPIC_BSP ? TRUE : FALSE; /* override */
|
||||
#endif /* !_WRS_CONFIG_SMP */
|
||||
|
||||
/* enable the Local APIC explicitly */
|
||||
|
||||
apicBase[0] |= LOAPIC_GLOBAL_ENABLE; /* set E(nable) bit */
|
||||
pentiumMsrSet (IA32_APIC_BASE, (long long int *)&apicBase);
|
||||
}
|
||||
|
||||
/* remember the original state : SVR, LINT0, LINT1 for now */
|
||||
|
||||
loApicOldSvr = *(int *)(loApicBase + LOAPIC_SVR);
|
||||
loApicOldLint0 = *(int *)(loApicBase + LOAPIC_LINT0);
|
||||
loApicOldLint1 = *(int *)(loApicBase + LOAPIC_LINT1);
|
||||
|
||||
/* enable the Local APIC */
|
||||
|
||||
loApicEnable (TRUE);
|
||||
*(int *)(loApicBase + LOAPIC_SVR) |= LOAPIC_FOCUS_DISABLE |
|
||||
INT_NUM_LOAPIC_SPURIOUS;
|
||||
|
||||
/* get the Local APIC ID from Local APIC ID register */
|
||||
|
||||
loApicId = (*(int *)(loApicBase + LOAPIC_ID) & LOAPIC_ID_MASK) >> 24;
|
||||
|
||||
/* get the Local APIC Version from Local APIC Version register */
|
||||
|
||||
loApicVersion = *(int *)(loApicBase + LOAPIC_VER) & LOAPIC_VERSION_MASK;
|
||||
loApicMaxLvt = (*(int *)(loApicBase + LOAPIC_VER) & LOAPIC_MAXLVT_MASK)
|
||||
>> 16;
|
||||
|
||||
/* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_DFR) = (int)0xffffffff;
|
||||
*(int *)(loApicBase + LOAPIC_TPR) = (int)0x0;
|
||||
*(int *)(loApicBase + LOAPIC_TIMER_CONFIG) = (int)0x0;
|
||||
*(int *)(loApicBase + LOAPIC_TIMER_ICR) = (int)0x0;
|
||||
|
||||
#if defined(VIRTUAL_WIRE_MODE)
|
||||
|
||||
/* program Local Vector Table for the Virtual Wire Mode */
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
if (sysBp)
|
||||
#else
|
||||
if (sysCpuNumGet() == 0)
|
||||
#endif /* !_WRS_CONFIG_SMP */
|
||||
{
|
||||
/* set LINT0: extInt, high-polarity, edge-trigger, not-masked */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) =
|
||||
(*(int *)(loApicBase + LOAPIC_LINT0) &
|
||||
~(LOAPIC_MODE | LOAPIC_LOW | LOAPIC_LEVEL | LOAPIC_MASK)) |
|
||||
(LOAPIC_EXT | LOAPIC_HIGH | LOAPIC_EDGE);
|
||||
|
||||
/* set LINT1: NMI, high-polarity, edge-trigger, not-masked */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) =
|
||||
(*(int *)(loApicBase + LOAPIC_LINT1) &
|
||||
~(LOAPIC_MODE | LOAPIC_LOW | LOAPIC_LEVEL | LOAPIC_MASK)) |
|
||||
(LOAPIC_NMI | LOAPIC_HIGH | LOAPIC_EDGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) = LOAPIC_MASK;
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) = LOAPIC_MASK;
|
||||
}
|
||||
|
||||
#elif defined(SYMMETRIC_IO_MODE)
|
||||
|
||||
/* program Local Vector Table for the Symmetric IO Mode */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) = LOAPIC_MASK;
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) = LOAPIC_MASK;
|
||||
|
||||
#endif /* defined(VIRTUAL_WIRE_MODE) */
|
||||
|
||||
/* lock the Local APIC interrupts */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_TIMER) = LOAPIC_MASK;
|
||||
*(int *)(loApicBase + LOAPIC_ERROR) = LOAPIC_MASK;
|
||||
|
||||
if (loApicMaxLvt >= LOAPIC_LVT_P6)
|
||||
*(int *)(loApicBase + LOAPIC_PMC) = LOAPIC_MASK;
|
||||
|
||||
if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4)
|
||||
*(int *)(loApicBase + LOAPIC_THERMAL) = LOAPIC_MASK;
|
||||
|
||||
/* discard a pending interrupt if any */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_EOI) = 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicEnable - enable or disable the Local xAPIC
|
||||
*
|
||||
* This routine enables or disables the Local xAPIC. If the parameter is TRUE,
|
||||
* the Local xAPIC is enabled. If the parameter is FALSE, the Local xAPIC
|
||||
* is disabled.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void loApicEnable
|
||||
(
|
||||
BOOL enable /* enable the Local xAPIC */
|
||||
)
|
||||
{
|
||||
INT32 oldLevel;
|
||||
BOOL loApicImcr = FALSE; /* TRUE if IMCR exist (MP Table) */
|
||||
MP_FPS *pFps = mpApicFps;
|
||||
|
||||
/* check if the IMCR exists or not */
|
||||
|
||||
loApicImcr = (pFps->featureByte[1] & 0x80) ? TRUE : FALSE;
|
||||
|
||||
oldLevel = intLock (); /* LOCK INTERRUPTS */
|
||||
|
||||
/* enable or disable the Local APIC */
|
||||
|
||||
if (enable)
|
||||
{
|
||||
/* if the original mode is PIC mode, enable the Local APIC */
|
||||
|
||||
if ((loApicOldSvr & LOAPIC_ENABLE) == 0)
|
||||
{
|
||||
*(int *)(loApicBase + LOAPIC_SVR) |= LOAPIC_ENABLE;
|
||||
}
|
||||
|
||||
#if defined (SYMMETRIC_IO_MODE)
|
||||
|
||||
/* switch to SYMMETRIC_IO mode from PIC/VIRTUAL_WIRE mode */
|
||||
|
||||
if (loApicImcr)
|
||||
{
|
||||
sysOutByte (IMCR_ADRS, IMCR_REG_SEL);
|
||||
sysOutByte (IMCR_DATA, IMCR_IOAPIC_ON);
|
||||
}
|
||||
|
||||
#endif /* defined (SYMMETRIC_IO_MODE) */
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#if defined (SYMMETRIC_IO_MODE)
|
||||
|
||||
/* switch from SYMMETRIC_IO mode to PIC/VIRTUAL_WIRE mode */
|
||||
|
||||
if (loApicImcr)
|
||||
{
|
||||
sysOutByte (IMCR_ADRS, IMCR_REG_SEL);
|
||||
sysOutByte (IMCR_DATA, IMCR_IOAPIC_OFF);
|
||||
}
|
||||
|
||||
#endif /* defined (SYMMETRIC_IO_MODE) */
|
||||
|
||||
/* if the original mode is PIC mode, disable the Local APIC */
|
||||
|
||||
if ((loApicOldSvr & LOAPIC_ENABLE) == 0)
|
||||
{
|
||||
*(int *)(loApicBase + LOAPIC_SVR) &= ~LOAPIC_ENABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* restore the original value */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_SVR) = loApicOldSvr;
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) = loApicOldLint0;
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) = loApicOldLint1;
|
||||
}
|
||||
}
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicIntLock - lock out all Local APIC interrupts
|
||||
*
|
||||
* This routine locks out all Local APIC interrupts
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: loApicIntUnlock()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL void loApicIntLock (void)
|
||||
{
|
||||
|
||||
if (!(*(int *)(loApicBase + LOAPIC_TIMER) & LOAPIC_MASK))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_TIMER;
|
||||
*(int *)(loApicBase + LOAPIC_TIMER) |= LOAPIC_MASK;
|
||||
}
|
||||
if (!(*(int *)(loApicBase + LOAPIC_LINT0) & LOAPIC_MASK))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_LINT0;
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) |= LOAPIC_MASK;
|
||||
}
|
||||
if (!(*(int *)(loApicBase + LOAPIC_LINT1) & LOAPIC_MASK))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_LINT1;
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) |= LOAPIC_MASK;
|
||||
}
|
||||
if (!(*(int *)(loApicBase + LOAPIC_ERROR) & LOAPIC_MASK))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_ERROR;
|
||||
*(int *)(loApicBase + LOAPIC_ERROR) |= LOAPIC_MASK;
|
||||
}
|
||||
if ((loApicMaxLvt >= LOAPIC_LVT_P6) &&
|
||||
(!(*(int *)(loApicBase + LOAPIC_PMC) & LOAPIC_MASK)))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_PMC;
|
||||
*(int *)(loApicBase + LOAPIC_PMC) |= LOAPIC_MASK;
|
||||
}
|
||||
if ((loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) &&
|
||||
(!(*(int *)(loApicBase + LOAPIC_THERMAL) & LOAPIC_MASK)))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_THERMAL;
|
||||
*(int *)(loApicBase + LOAPIC_THERMAL) |= LOAPIC_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicIntUnlock - unlock the Local APIC interrupts
|
||||
*
|
||||
* This routine unlocks the Local APIC interrupts
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: loApicIntLock()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL void loApicIntUnlock (void)
|
||||
{
|
||||
|
||||
if (sysIntMaskLocalApic & LOCKED_TIMER)
|
||||
*(int *)(loApicBase + LOAPIC_TIMER) &= ~LOAPIC_MASK;
|
||||
if (sysIntMaskLocalApic & LOCKED_LINT0)
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) &= ~LOAPIC_MASK;
|
||||
if (sysIntMaskLocalApic & LOCKED_LINT1)
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) &= ~LOAPIC_MASK;
|
||||
if (sysIntMaskLocalApic & LOCKED_ERROR)
|
||||
*(int *)(loApicBase + LOAPIC_ERROR) &= ~LOAPIC_MASK;
|
||||
if ((loApicMaxLvt >= LOAPIC_LVT_P6) &&
|
||||
(sysIntMaskLocalApic & LOCKED_PMC))
|
||||
*(int *)(loApicBase + LOAPIC_PMC) &= ~LOAPIC_MASK;
|
||||
if ((loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) &&
|
||||
(sysIntMaskLocalApic & LOCKED_THERMAL))
|
||||
*(int *)(loApicBase + LOAPIC_THERMAL) &= ~LOAPIC_MASK;
|
||||
|
||||
sysIntMaskLocalApic = 0; /* reset the flags */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicIntEoi - send EOI (End Of Interrupt) signal to Local APIC
|
||||
*
|
||||
* This routine sends an EOI signal to the Local APIC's interrupting source.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
LOCAL void loApicIntEoi
|
||||
(
|
||||
INT32 irqNo /* INIIN number to send EOI */
|
||||
)
|
||||
{
|
||||
#ifdef SYS_INT_DEBUG
|
||||
extern UINT32 sysIntCount [];
|
||||
sysIntCount [irqNo]++;
|
||||
#endif /* SYS_INT_DEBUG */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_EOI) = 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* loApicIpi - generate a Inter Processor Interrupt
|
||||
*
|
||||
* This routine delivers an Inter-Processor interrupt to the specified CPU
|
||||
* in the specified mode, with the specified vectorNo. Level should always
|
||||
* be 1 except INIT De-assert mode.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if the delivery status is not idle
|
||||
*/
|
||||
|
||||
STATUS loApicIpi
|
||||
(
|
||||
INT32 apicId, /* APIC ID number to send the interrupt */
|
||||
INT32 shortHand, /* destination short hand */
|
||||
INT32 trigger, /* trigger mode. 0: edge or 1: level */
|
||||
INT32 level, /* level. 0: de-assert or 1: assert */
|
||||
INT32 destMode, /* destination mode. 0: physical or 1: logical */
|
||||
INT32 deliMode, /* delivery mode. 000: fixed ... 110: startup */
|
||||
INT32 vectorNo /* vector number */
|
||||
)
|
||||
{
|
||||
UINT32 icrHi = (*(int *)(loApicBase + LOAPIC_ICRHI)) & 0x00ffffff;
|
||||
UINT32 icrLo = (*(int *)(loApicBase + LOAPIC_ICRLO)) & 0xfff32000;
|
||||
|
||||
/* ShortHand, Trigger, Level, DeliveryMode and Vector */
|
||||
|
||||
icrLo |= ((shortHand << 18) & 0xc0000) |
|
||||
((trigger << 15) & 0x8000) |
|
||||
((level << 14) & 0x4000) |
|
||||
((destMode << 11) & 0x800) |
|
||||
((deliMode << 8) & 0x700) |
|
||||
(vectorNo & 0xff);
|
||||
|
||||
/* Destination Apic Id */
|
||||
|
||||
icrHi |= (apicId << 24) & 0xff000000;
|
||||
|
||||
/* is the interrupt idle? */
|
||||
|
||||
if (*(int *)(loApicBase + LOAPIC_ICRLO) & STATUS_PEND)
|
||||
{
|
||||
loApicBusy++;
|
||||
LOAPIC_DBG_MSG ("ipi: LOAPIC busy 0x%x\n",
|
||||
*(int *)(loApicBase + LOAPIC_ESR))
|
||||
return (ERROR);
|
||||
}
|
||||
|
||||
/* reset the error status register */
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
*(int *)(loApicBase + LOAPIC_ESR) = 0;
|
||||
*(int *)(loApicBase + LOAPIC_ESR) = 0;
|
||||
#endif /* !_WRS_CONFIG_SMP */
|
||||
|
||||
if (*(int *)(loApicBase + LOAPIC_ESR) != 0)
|
||||
{
|
||||
LOAPIC_DBG_MSG ("ipi: 0. ESR=0x%x\n",
|
||||
*(int *)(loApicBase + LOAPIC_ESR))
|
||||
return (ERROR);
|
||||
}
|
||||
|
||||
/* Send it! */
|
||||
|
||||
#ifdef _WRS_CONFIG_SMP
|
||||
/* Can send shorthand message by performing a single
|
||||
* 32-bit memory write to the low half of the ICR.
|
||||
*/
|
||||
if ((shortHand == 0x00) || (destMode == 0x01))
|
||||
*(int *)(loApicBase + LOAPIC_ICRHI) = icrHi;
|
||||
#else
|
||||
*(int *)(loApicBase + LOAPIC_ICRHI) = icrHi;
|
||||
#endif
|
||||
*(int *)(loApicBase + LOAPIC_ICRLO) = icrLo;
|
||||
|
||||
/* Wait till interrupt is sent */
|
||||
|
||||
while (*(int *)(loApicBase + LOAPIC_ICRLO) & STATUS_PEND)
|
||||
if (*(int *)(loApicBase + LOAPIC_ESR) != 0)
|
||||
{
|
||||
LOAPIC_DBG_MSG ("ipi: 1. ESR=0x%x\n",
|
||||
*(int *)(loApicBase + LOAPIC_ESR))
|
||||
return (ERROR);
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,590 @@
|
||||
/* loApicIntrShow.c - Intel Local APIC/xAPIC driver show routines */
|
||||
|
||||
/* Copyright 1984-2002 Wind River Systems, Inc. */
|
||||
|
||||
#include "copyright_wrs.h"
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01e,26jul06,scm update for pentium/xeon support...
|
||||
01d,18aug04,dmh improved mptable debugging information
|
||||
01c,01apr04,dmh add support for multiple APICs
|
||||
01b,08mar02,hdn added the description
|
||||
01a,25jun01,hdn extracted from 01c version of loApicIntr.c
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This module is a show routine for the Local APIC/xAPIC (Advanced
|
||||
Programmable Interrupt Controller) for P6 (PentiumPro, II, III)
|
||||
family processors and P7 (Pentium4) family processors.
|
||||
loApicShow() shows content of the Local APIC registers.
|
||||
loApicMpShow() shows the MP configuration table.
|
||||
|
||||
INCLUDE FILES: loApic.h
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include "drv/intrCtl/loApic.h"
|
||||
|
||||
/* externs */
|
||||
|
||||
/* globals */
|
||||
|
||||
/* locals */
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicIntrShowScan - scans given memory range for the string match
|
||||
*
|
||||
* This routine scans the memory areas specified in its argument for the
|
||||
* Intel MP signature string "_MP_", or other signature strings.
|
||||
*
|
||||
* RETURNS: pointer to address of matching string in the range , or NULL
|
||||
*
|
||||
*/
|
||||
|
||||
INT8 * loApicIntrShowScan
|
||||
(
|
||||
INT8 * match,
|
||||
INT8 * start, /* start address to scan */
|
||||
INT8 * end /* end address to scan */
|
||||
)
|
||||
{
|
||||
INT8 * p;
|
||||
|
||||
for (p = start; (p+16) < end; p+=16)
|
||||
{
|
||||
if (strncmp (p, match, strlen(match)) == 0)
|
||||
return (p);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicStatusShow - show Local APIC TMR, IRR, ISR registers
|
||||
*
|
||||
* This routine shows Local APIC TMR, IRR, ISR registers
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
LOCAL void loApicStatusShow (void)
|
||||
{
|
||||
int ix;
|
||||
|
||||
for (ix = 0; ix < 8; ix++)
|
||||
{
|
||||
printf ("LOAPIC_TMR%02d = 0x%08x ", ix,
|
||||
*(UINT32 *)(loApicBase + LOAPIC_TMR + (ix * 0x10)));
|
||||
printf ("LOAPIC_IRR%02d = 0x%08x ", ix,
|
||||
*(UINT32 *)(loApicBase + LOAPIC_IRR + (ix * 0x10)));
|
||||
printf ("LOAPIC_ISR%02d = 0x%08x\n", ix,
|
||||
*(UINT32 *)(loApicBase + LOAPIC_ISR + (ix * 0x10)));
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicShow - show Local APIC registers
|
||||
*
|
||||
* This routine shows Local APIC registers
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void loApicShow (void)
|
||||
{
|
||||
UINT32 localApicReg;
|
||||
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_ID);
|
||||
printf ("local Apic ID = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_VER);
|
||||
printf ("local Apic Version = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_TPR);
|
||||
printf ("Task Priority = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_APR);
|
||||
printf ("Arbitration Priority = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_PPR);
|
||||
printf ("Processor Priority = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_LDR);
|
||||
printf ("Logical Destination = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_DFR);
|
||||
printf ("Destination Format = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_SVR);
|
||||
printf ("Spurious Interrupt Vector = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_ESR);
|
||||
printf ("Error Status = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_ICRLO);
|
||||
printf ("Interrupt Command 00-31 = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_ICRHI);
|
||||
printf ("Interrupt Command 32-63 = 0x%08x\n", localApicReg);
|
||||
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_TIMER);
|
||||
printf ("Local Vector Table (Timer) = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_LINT0);
|
||||
printf ("Local Vector Table (LINT0) = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_LINT1);
|
||||
printf ("Local Vector Table (LINT1) = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_ERROR);
|
||||
printf ("Local Vector Table (Error) = 0x%08x\n", localApicReg);
|
||||
|
||||
if (loApicMaxLvt >= LOAPIC_LVT_P6)
|
||||
{
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_PMC);
|
||||
printf ("Local Vector Table (PMC) = 0x%08x\n", localApicReg);
|
||||
}
|
||||
if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4)
|
||||
{
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_THERMAL);
|
||||
printf ("Local Vector Table (Therm) = 0x%08x\n", localApicReg);
|
||||
}
|
||||
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_TIMER_ICR);
|
||||
printf ("Timer Initial Count = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_TIMER_CCR);
|
||||
printf ("Timer Current Count = 0x%08x\n", localApicReg);
|
||||
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_TIMER_CONFIG);
|
||||
printf ("Timer Divide Configuration = 0x%08x\n", localApicReg);
|
||||
|
||||
loApicStatusShow ();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicMpShow - show MP configuration table
|
||||
*
|
||||
* This routine shows MP configuration table.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void loApicMpShow (void)
|
||||
{
|
||||
MP_FPS * pFps = NULL;
|
||||
MP_HEADER * pTbl;
|
||||
MP_CPU * pCpu;
|
||||
MP_IOAPIC * pIoApic;
|
||||
MP_BUS * pBus;
|
||||
char * p;
|
||||
int ix, iy;
|
||||
|
||||
/* MP Floating Point Structure */
|
||||
|
||||
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)EBDA_START, (char *)EBDA_END);
|
||||
if (pFps == NULL)
|
||||
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)BIOS_ROM_START,
|
||||
(char *)BIOS_ROM_END);
|
||||
|
||||
if (pFps == NULL)
|
||||
{
|
||||
printf ("Not MP Compliant\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf ("MP Floating Point Structure\n");
|
||||
printf (" Address Pointer = 0x%08x\n", pFps->configTableAddr);
|
||||
printf (" Spec Version = 0x%02x\n", pFps->specRev);
|
||||
printf (" Feature byte-1 = 0x%02x\n", pFps->featureByte[0]);
|
||||
printf (" Feature byte-2 = 0x%02x\n", pFps->featureByte[1]);
|
||||
printf (" Feature byte-3 = 0x%02x\n", pFps->featureByte[2]);
|
||||
printf (" Feature byte-4 = 0x%02x\n", pFps->featureByte[3]);
|
||||
printf (" Feature byte-5 = 0x%02x\n", pFps->featureByte[4]);
|
||||
|
||||
if ((pFps->featureByte[0] != 0) || (pFps->configTableAddr == 0))
|
||||
{
|
||||
printf ("MP Configuration Table does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
/* show MP Configuration Table Header */
|
||||
|
||||
pTbl = (MP_HEADER *)pFps->configTableAddr;
|
||||
|
||||
printf ("MP Configuration Table\n");
|
||||
printf (" Base Table Length = 0x%04x\n", pTbl->tableLength);
|
||||
printf (" OEM ID String = ");
|
||||
for (ix = 0; ix < sizeof (pTbl->oemId); ix++)
|
||||
printf ("%c", pTbl->oemId[ix]);
|
||||
printf ("\n");
|
||||
printf (" Product ID String = ");
|
||||
for (ix = 0; ix < sizeof (pTbl->prodId); ix++)
|
||||
printf ("%c", pTbl->prodId[ix]);
|
||||
printf ("\n");
|
||||
printf (" OEM Table Pointer = 0x%08x\n", pTbl->oemTablePtr);
|
||||
printf (" OEM Table Size = 0x%04x\n", pTbl->oemTableSize);
|
||||
printf (" Entry Count = 0x%04x\n", pTbl->entryCount);
|
||||
printf (" Address of local APIC = 0x%08x\n", pTbl->localApicBaseAddr);
|
||||
printf (" Extended Table Length = 0x%04x\n", pTbl->extendedTableLength);
|
||||
|
||||
/* show MP Configuration Table Entry */
|
||||
|
||||
p = (char *)pTbl + sizeof(MP_HEADER);
|
||||
for (ix = 0; ix < pTbl->entryCount; ix++)
|
||||
switch (*p)
|
||||
{
|
||||
case MP_ENTRY_CPU: /* Processor Entry */
|
||||
pCpu = (MP_CPU *)p;
|
||||
printf ("Processor Entry\n");
|
||||
printf (" Local Apic ID = 0x%02x\n",
|
||||
pCpu->localApicId);
|
||||
printf (" Local Apic Ver = 0x%02x\n",
|
||||
pCpu->localApicVersion);
|
||||
printf (" CPU Flags = %s|%s\n",
|
||||
(pCpu->cpuFlags&0x01)?"EN":"~EN",
|
||||
(pCpu->cpuFlags&0x02)?"BP":"~BP");
|
||||
printf (" CPU Signature = 0x%08x\n", pCpu->cpuSig);
|
||||
printf (" Feature Flags = 0x%08x\n",
|
||||
pCpu->featureFlags);
|
||||
|
||||
p += sizeof (MP_CPU);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_BUS: /* Bus Entry */
|
||||
pBus = (MP_BUS *)p;
|
||||
{
|
||||
int busId = pBus->busId;
|
||||
printf ("Bus Entry\n");
|
||||
printf (" Bus ID = 0x%02x\n", busId);
|
||||
}
|
||||
printf (" Bus Type String = ");
|
||||
for (iy = 0; iy < 6; iy++)
|
||||
printf ("%c", pBus->busType[iy]);
|
||||
printf ("\n");
|
||||
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
case MP_ENTRY_IOAPIC: /* IO APIC Entry */
|
||||
pIoApic = (MP_IOAPIC *)p;
|
||||
printf ("IO Apic Entry\n");
|
||||
printf (" IO Apic ID = 0x%02x\n",
|
||||
pIoApic->ioApicId);
|
||||
printf (" IO Apic Ver = 0x%02x\n",
|
||||
pIoApic->ioApicVersion);
|
||||
printf (" IO Apic Flags = %s\n",
|
||||
(pIoApic->ioApicFlags&0x01)?"EN":"~EN");
|
||||
printf (" IO Apic Address = 0x%08x\n",
|
||||
pIoApic->ioApicBaseAddress);
|
||||
|
||||
p += sizeof (MP_IOAPIC);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_IOINTERRUPT: /* IO Interrupt Entry */
|
||||
printf ("IO Interrupt Entry\n");
|
||||
printf (" Interrupt Type = 0x%02x\n", *(UINT8 *)(p + 1));
|
||||
printf (" IO Interrupt Flag = InPol(");
|
||||
switch( (*(UINT16 *)(p + 2))& 0x02)
|
||||
{
|
||||
case 0:
|
||||
printf ("Bus");
|
||||
break;
|
||||
case 1:
|
||||
printf ("AH");
|
||||
break;
|
||||
case 2:
|
||||
printf ("RSV");
|
||||
break;
|
||||
case 3:
|
||||
printf ("AL");
|
||||
break;
|
||||
}
|
||||
printf (")|Trig(");
|
||||
switch (((*(UINT16 *)(p + 2)) >> 2)& 0x02)
|
||||
{
|
||||
case 0:
|
||||
printf ("Bus");
|
||||
break;
|
||||
case 1:
|
||||
printf ("Edge");
|
||||
break;
|
||||
case 2:
|
||||
printf ("RSV");
|
||||
break;
|
||||
case 3:
|
||||
printf ("Lvl");
|
||||
break;
|
||||
}
|
||||
printf (")\n");
|
||||
printf (" Source Bus ID = 0x%02x\n", *(UINT8 *)(p + 4));
|
||||
printf (" Source Bus IRQ = 0x%02x\n", *(UINT8 *)(p + 5));
|
||||
printf (" Dest IO Apic ID = 0x%02x\n", *(UINT8 *)(p + 6));
|
||||
printf (" Dest IO Apic INTIN = 0x%02x\n", *(UINT8 *)(p + 7));
|
||||
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
case MP_ENTRY_LOINTERRUPT: /* Local Interrupt Entry */
|
||||
printf ("Local Interrupt Entry\n");
|
||||
printf (" Interrupt Type = 0x%02x\n", *(UINT8 *)(p + 1));
|
||||
printf (" IO Interrupt Flag = InPol(");
|
||||
switch( (*(UINT16 *)(p + 2))& 0x02)
|
||||
{
|
||||
case 0:
|
||||
printf ("Bus");
|
||||
break;
|
||||
case 1:
|
||||
printf ("AH");
|
||||
break;
|
||||
case 2:
|
||||
printf ("RSV");
|
||||
break;
|
||||
case 3:
|
||||
printf ("AL");
|
||||
break;
|
||||
}
|
||||
printf (")|Trig(");
|
||||
switch (((*(UINT16 *)(p + 2)) >> 2)& 0x02)
|
||||
{
|
||||
case 0:
|
||||
printf ("Bus");
|
||||
break;
|
||||
case 1:
|
||||
printf ("Edge");
|
||||
break;
|
||||
case 2:
|
||||
printf ("RSV");
|
||||
break;
|
||||
case 3:
|
||||
printf ("Lvl");
|
||||
break;
|
||||
}
|
||||
printf (")\n");
|
||||
printf (" Source Bus ID = 0x%02x\n", *(UINT8 *)(p + 4));
|
||||
printf (" Source Bus IRQ = 0x%02x\n", *(UINT8 *)(p + 5));
|
||||
printf (" Dest Local Apic ID = 0x%02x\n", *(UINT8 *)(p + 6));
|
||||
printf (" Dest Local Apic INTIN = 0x%02x\n", *(UINT8 *)(p + 7));
|
||||
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
default: /* Unknown Entry */
|
||||
p += 8; /* wild guess */
|
||||
}
|
||||
/* p now pointing to the begining of the extended MP configuration table */
|
||||
ix = 0;
|
||||
while ( ix < (int) pTbl->extendedTableLength)
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case EXT_MP_ENTRY_SASM: /* System Address Space Map Entry */
|
||||
printf ("System Address Space Map Entry\n");
|
||||
printf (" Entry Length = 0x%02x\n", *(UINT8 *)(p + 1));
|
||||
printf (" Bus ID = 0x%02x\n", *(UINT8 *)(p + 2));
|
||||
printf (" Address Type = 0x%02x\n", *(UINT8 *)(p + 3));
|
||||
printf (" Address Base (LOW) = 0x%04x\n",
|
||||
*(UINT32 *)(p + 4));
|
||||
printf (" Address Base (HIGH) = 0x%04x\n",
|
||||
*(UINT32 *)(p + 8));
|
||||
printf (" Address Length (LOW) = 0x%04x\n",
|
||||
*(UINT32 *)(p + 4));
|
||||
printf (" Address Length (HIGH) = 0x%04x\n",
|
||||
*(UINT32 *)(p + 8));
|
||||
|
||||
p += 20;
|
||||
ix += 20;
|
||||
break;
|
||||
|
||||
case EXT_MP_ENTRY_BHD: /* Bus Hierarchy Descriptor Entry */
|
||||
printf ("Bus Hierarchy Descriptor Entry\n");
|
||||
printf (" Entry Length = 0x%02x\n", *(UINT8 *)(p + 1));
|
||||
printf (" Bus ID = 0x%02x\n", *(UINT8 *)(p + 2));
|
||||
printf (" Bus Info = 0x%02x\n", *(UINT8 *)(p + 3));
|
||||
printf (" Parent Bus = 0x%02x\n", *(UINT8 *)(p + 4));
|
||||
|
||||
p += 8;
|
||||
ix += 8;
|
||||
break;
|
||||
|
||||
case EXT_MP_ENTRY_CBASM: /* Comp Address Space Modifier Entry */
|
||||
printf ("Comp Address Space Modifier\n");
|
||||
printf (" Entry Length = 0x%02x\n", *(UINT8 *)(p + 1));
|
||||
printf (" Bus ID = 0x%02x\n", *(UINT8 *)(p + 2));
|
||||
printf (" Address Mod = 0x%02x\n", *(UINT8 *)(p + 3));
|
||||
printf (" Predefined Range List = 0x%04x\n",
|
||||
*(UINT32 *)(p + 4));
|
||||
|
||||
p += 8;
|
||||
ix += 8;
|
||||
break;
|
||||
|
||||
default: /* Unknown Entry */
|
||||
p += 8; /* wild guess */
|
||||
ix += 8; /* wild guess */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* biosIoIntMapShow - show MP configuration table
|
||||
*
|
||||
* This routine shows MP configuration table.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void biosIoIntMapShow (void)
|
||||
{
|
||||
MP_FPS * pFps = NULL;
|
||||
MP_HEADER * pTbl;
|
||||
char * p;
|
||||
int ix;
|
||||
|
||||
/* MP Floating Point Structure */
|
||||
|
||||
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)EBDA_START, (char *)EBDA_END);
|
||||
if (pFps == NULL)
|
||||
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)BIOS_ROM_START,
|
||||
(char *)BIOS_ROM_END);
|
||||
|
||||
if (pFps == NULL)
|
||||
{
|
||||
printf ("Not MP Compliant\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((pFps->featureByte[0] != 0) || (pFps->configTableAddr == 0))
|
||||
{
|
||||
printf ("MP Configuration Table does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
/* show MP Configuration Table Header */
|
||||
|
||||
pTbl = (MP_HEADER *)pFps->configTableAddr;
|
||||
|
||||
/* show Interrupt Configuration Table Entry */
|
||||
|
||||
printf ("BIOS I/O Interrupt Configuration Table\n");
|
||||
printf (" Type Flags Bus ID Bus IRQ APIC ID APIC INT In Org Dev INT_n#\n");
|
||||
printf (" ==== ====== ====== ======= ======= =========== ======= ======\n");
|
||||
p = (char *)pTbl + sizeof(MP_HEADER);
|
||||
for (ix = 0; ix < pTbl->entryCount; ix++)
|
||||
switch (*p)
|
||||
{
|
||||
case MP_ENTRY_CPU: /* Processor Entry */
|
||||
p += sizeof (MP_CPU);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_BUS: /* Bus Entry */
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
case MP_ENTRY_IOAPIC: /* IO APIC Entry */
|
||||
p += sizeof (MP_IOAPIC);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_IOINTERRUPT: /* IO Interrupt Entry */
|
||||
printf(" 0x%02x 0x%04x %2d %3d %d %2d 0x%02x ",
|
||||
*(p + 1), *(UINT16*)(p+2), *(p+4), *(p+5), *(p+6), *(p + 7), (*(p+5)) >> 2);
|
||||
switch(*(p+5)&0x3)
|
||||
{
|
||||
case 0:
|
||||
printf("A\n");
|
||||
break;
|
||||
case 1:
|
||||
printf("B\n");
|
||||
break;
|
||||
case 2:
|
||||
printf("C\n");
|
||||
break;
|
||||
case 3:
|
||||
printf("D\n");
|
||||
break;
|
||||
}
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
case MP_ENTRY_LOINTERRUPT: /* Local Interrupt Entry */
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
default: /* Unknown Entry */
|
||||
p += 8; /* wild guess */
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* biosLocalIntMapShow - show MP configuration table
|
||||
*
|
||||
* This routine shows MP configuration table.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void biosLocalIntMapShow (void)
|
||||
{
|
||||
MP_FPS * pFps = NULL;
|
||||
MP_HEADER * pTbl;
|
||||
char * p;
|
||||
int ix;
|
||||
|
||||
/* MP Floating Point Structure */
|
||||
|
||||
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)EBDA_START, (char *)EBDA_END);
|
||||
if (pFps == NULL)
|
||||
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)BIOS_ROM_START,
|
||||
(char *)BIOS_ROM_END);
|
||||
|
||||
if (pFps == NULL)
|
||||
{
|
||||
printf ("Not MP Compliant\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((pFps->featureByte[0] != 0) || (pFps->configTableAddr == 0))
|
||||
{
|
||||
printf ("MP Configuration Table does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
/* show MP Configuration Table Header */
|
||||
|
||||
pTbl = (MP_HEADER *)pFps->configTableAddr;
|
||||
|
||||
/* show Interrupt Configuration Table Entry */
|
||||
|
||||
printf ("BIOS Local Interrupt Configuration Table\n");
|
||||
printf (" Type Flags Bus ID Bus IRQ APIC ID APIC INT In\n");
|
||||
printf (" ==== ====== ====== ======= ========== ===========\n");
|
||||
p = (char *)pTbl + sizeof(MP_HEADER);
|
||||
for (ix = 0; ix < pTbl->entryCount; ix++)
|
||||
switch (*p)
|
||||
{
|
||||
case MP_ENTRY_CPU: /* Processor Entry */
|
||||
p += sizeof (MP_CPU);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_BUS: /* Bus Entry */
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
case MP_ENTRY_IOAPIC: /* IO APIC Entry */
|
||||
p += sizeof (MP_IOAPIC);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_IOINTERRUPT: /* IO Interrupt Entry */
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
case MP_ENTRY_LOINTERRUPT: /* Local Interrupt Entry */
|
||||
printf(" 0x%02x 0x%04x %2d %3d %d %2d\n",
|
||||
*(p + 1), *(UINT16 *)(p + 2), *(p + 4), *(p + 5), *(p + 6), *(p + 7));
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
default: /* Unknown Entry */
|
||||
p += 8; /* wild guess */
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,618 @@
|
||||
/* m8260Int.c - Motorola Voyager MPC 8260 interrupt controller driver */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1984-2004, 2008 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use of this
|
||||
* software may be licensed only pursuant to the terms of an applicable Wind
|
||||
* River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
02b,03sep08,jpb Renamed VSB header file
|
||||
02a,08apr08,tcr fix SV macro invocation
|
||||
01z,18jun08,jpb Added include path for kernel configurations options set in
|
||||
vsb.
|
||||
01y,12may08,jpb Modifications for source build. Renamed
|
||||
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
|
||||
01x,22sep04,mdo Documentation fixes for apigen
|
||||
01w,20apr04,dtr SPR 96472 sync required when loading mask values.
|
||||
01v,04apr04,rec SPR 95018 - Aux timer hangs system
|
||||
01u,24oct03,rec change Timer 2 to highest priority for PWR MGMT
|
||||
01t,24nov03,to compilation fix and some style and spell fixes
|
||||
01s,06nov03,kam added intDisconnect() functionality
|
||||
01r,31jan03,dtr Adding PCI Interrupt for MPC8266 et al.
|
||||
01q,14jan03,gjc Fix SPR#85215 - m8260IntrDeMux() Fails to break out of while
|
||||
loop.
|
||||
01p,28mar02,dtr Fix typo.
|
||||
01o,28mar02,jrs Correct loop bounds check for attaching ISR's to int no's.
|
||||
01n,12jan02,g_h Remove calling to intLock() in m8260IntrDeMux()
|
||||
01m,07dec01,rcs masked vxImmrGet() value with IMMR_ISB_MASK SPR# 72027
|
||||
01l,22oct01,g_h Change the m8260IntrDeMux function to check for interrupt 0
|
||||
as indication for no interrupt. As long as reading the SIVEC
|
||||
register different from 0 we have pending interrupt and
|
||||
we need to server it, this fix SPR 71119.
|
||||
01k,22oct01,g_h Clean compilation warning from m8260IntDisable function, and
|
||||
change the declaration of intVec in m8260IntrDeMux to VINT32
|
||||
from UINT32 to prevent optimization problem.
|
||||
01j,16sep99,ms_ m8260IntrCtl.h comes from h/drv/intrCtl
|
||||
01i,16sep99,ms_ rename m8260Int.h to m8260IntrCtl.h
|
||||
01h,15jul99,ms_ make compliant with our coding standards
|
||||
01g,13may99,ms_ minor fixes
|
||||
01f,17apr99,ms_ final cleanup for EAR
|
||||
01e,15apr99,ms_ disable only lower priority interrupts while processing
|
||||
interrupt
|
||||
01d,13apr99,ms_ redefine IVEC_TO_INUM and INUM_TO_IVEC to use the numbers as
|
||||
shown in the MPC8260 user's manual
|
||||
01c,12apr99,ms_ remove any sio specific items; that is handled in the sio
|
||||
driver
|
||||
01b,29mar99,ms_ add ability to mask out lower priority interrupts when
|
||||
processing an interrupt
|
||||
01a,22feb99,ms_ adapted from ppc8260Intr.c version 01f
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
The PowerPC 8260 CPU is divided in three units: PowerPC core, System
|
||||
Interface Unit (SIU) and Communication Processor Unit (CPM). The PowerPC
|
||||
core accepts only one external interrupt exception (vector 0x500). The SIU
|
||||
provides an interrupt controller which provides 55 interrupt sources
|
||||
The Interrupt controller is connected to the PowerPC core external
|
||||
interrupt. This library provides the routines to manage this interrupt
|
||||
controllers.
|
||||
|
||||
m8260IntrInit() connects the default demultiplexer, m8260IntrDeMux(), to the
|
||||
external interrupt vector and initializes a table containing a function pointer
|
||||
and an associated parameter for each interrupt source. m8260IntrInit() is called
|
||||
by sysHwInit() from sysLib.c.
|
||||
|
||||
The default demultiplexer, m8260IntrDeMux() detects which peripheral or
|
||||
controller has raised an interrupt and calls the associated routine with its
|
||||
parameter.
|
||||
|
||||
INCLUDE FILES: m8260IntrCtl.h
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vsbConfig.h>
|
||||
|
||||
#include "intLib.h"
|
||||
#include "iv.h"
|
||||
#include "drv/intrCtl/m8260IntrCtl.h"
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
#include "private/funcBindP.h"
|
||||
#include "private/eventP.h"
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
/* local */
|
||||
|
||||
LOCAL INTR_HANDLER intrVecTable[IVEC_MAX+1]; /* Intr vector table */
|
||||
LOCAL VOIDFUNCPTR defaultVec; /* INTR3 default vector */
|
||||
|
||||
/* SIU Interrupt Mask structure; a value for the high and low parts */
|
||||
typedef struct siu_int_mask
|
||||
{
|
||||
UINT32 simr_h;
|
||||
UINT32 simr_l;
|
||||
} SIU_INT_MASK;
|
||||
|
||||
/*
|
||||
* For a given inum, return a pair of masks, one for SIMR_H and one for SIMR_L,
|
||||
* which will enable only higher priority interrupts.
|
||||
* REF: MPC8269 PowerQuiccII Family Reference Manual - Figs 4-16, 4-17
|
||||
*/
|
||||
|
||||
LOCAL SIU_INT_MASK enableHighPriInts[] =
|
||||
{
|
||||
{0x00000000, 0x00000000}, /* interrupt 0 error - enable nothing */
|
||||
{0x003F7C06, 0xECF0264A}, /* I2C */
|
||||
{0x0FFF7F06, 0xECF0A7DA}, /* SPI */
|
||||
{0x003F7C06, 0xECF0064A}, /* RISC Timer Table */
|
||||
{0x3FFF7F06, 0xECF0E7DA}, /* SMC1 */
|
||||
{0x3FFF7F06, 0xECF0F7DA}, /* SMC2 */
|
||||
{0x00077C06, 0xECF00048}, /* IDMA1 */
|
||||
{0x001F7C06, 0xECF00448}, /* IDMA2 */
|
||||
{0x00FF7E06, 0xECF0A64A}, /* IDMA3 */
|
||||
{0x0FFF7F06, 0xECF0A74A}, /* IDMA4 */
|
||||
{0x00077C06, 0xECF00008}, /* SDMA Bus Error */
|
||||
{0xFFFFFFFF, 0xFFFFFFEA}, /* interrupt 11 reserved - enable everything */
|
||||
{0xFFFFFFFF, 0xFFFFFFEA}, /* Timer 1 - not used */
|
||||
{0x00000000, 0x00000000}, /* Timer 2 - system timer, - enable nothing */
|
||||
{0xFFFFFFFF, 0xFFFFFFEA}, /* Timer 3 - not used */
|
||||
{0x07FF7F06, 0xECF0A748}, /* Timer 4 */
|
||||
{0x00000000, 0x00000008}, /* TMCNT */
|
||||
{0x00000004, 0x00000008}, /* PIT */
|
||||
{0x00000000, 0x00000008}, /* PCI Interrupt */
|
||||
{0x00000006, 0x00000008}, /* IRQ1 XXXX */
|
||||
{0x00004006, 0xEC000008}, /* IRQ2 */
|
||||
{0x00006006, 0xEC000008}, /* IRQ3 */
|
||||
{0x00007006, 0xEC000008}, /* IRQ4 */
|
||||
{0x00007806, 0xEC000008}, /* IRQ5 */
|
||||
{0x00FF7C06, 0xECF0A64A}, /* IRQ6 */
|
||||
{0x00FF7E06, 0xECF0A74A}, /* IRQ7 */
|
||||
{0xFFFFFFFF, 0xFFFFFFEA}, /* interrupt 26 reserved - enable everything */
|
||||
{0x00004006, 0x00000008}, /* FCC1 */
|
||||
{0x00004006, 0x80000008}, /* FCC2 */
|
||||
{0x00004006, 0xC0000008}, /* FCC3 */
|
||||
{0xFFFFFFFF, 0xFFFFFFEA}, /* interrupt 30 reserved - enable everything */
|
||||
{0x00004006, 0xE0000008}, /* MCC1 */
|
||||
{0x00004006, 0xE8000008}, /* MCC2 */
|
||||
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 33 reserved - enable everything */
|
||||
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 34 reserved - enable everything */
|
||||
{0x00007C06, 0xEC000008}, /* SCC1 */
|
||||
{0x00007C06, 0xEC800008}, /* SCC2 */
|
||||
{0x00007C06, 0xECC00008}, /* SCC3 */
|
||||
{0x00007C06, 0xECE00008}, /* SCC4 */
|
||||
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 39 reserved - enable everything */
|
||||
{0x00007C06, 0xECF00008}, /* PC15 */
|
||||
{0x00017C06, 0xECF00008}, /* PC14 */
|
||||
{0x00037C06, 0xECF00008}, /* PC13 */
|
||||
{0x00077C06, 0xECF00448}, /* PC12 */
|
||||
{0x000F7C06, 0xECF00448}, /* PC11 */
|
||||
{0x001F7C06, 0xECF0064A}, /* PC10 */
|
||||
{0x003F7C06, 0xECF0A64A}, /* PC9 */
|
||||
{0x007F7C06, 0xECF0A64A}, /* PC8 */
|
||||
{0x00FF7F06, 0xECF0A74A}, /* PC7 */
|
||||
{0x01FF7F06, 0xECF0A74A}, /* PC6 */
|
||||
{0x03FF7F06, 0xECF0A74A}, /* PC5 */
|
||||
{0x07FF7F06, 0xECF0A74A}, /* PC4 */
|
||||
{0x0FFF7F06, 0xECF0E7DA}, /* PC3 */
|
||||
{0x1FFF7F06, 0xECF0E7DA}, /* PC2 */
|
||||
{0x3FFF7F06, 0xECF0FFDA}, /* PC1 */
|
||||
{0x7FFF7F06, 0xECF0FFDA}, /* PC0 */
|
||||
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 56 reserved - enable everything */
|
||||
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 57 reserved - enable everything */
|
||||
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 58 reserved - enable everything */
|
||||
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 59 reserved - enable everything */
|
||||
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 60 reserved - enable everything */
|
||||
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 61 reserved - enable everything */
|
||||
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 62 reserved - enable everything */
|
||||
{0xFFFFFFFF, 0xFFFFFFDA} /* interrupt 63 reserved - enable everything */
|
||||
};
|
||||
|
||||
|
||||
|
||||
LOCAL UINT32 iNumToMaskPattern[] =
|
||||
{
|
||||
0x00000000, /* interrupt number 0: Error */
|
||||
0x00008000, /* interrupt number 1: I2C */
|
||||
0x00004000, /* interrupt number 2: SPI */
|
||||
0x00002000, /* interrupt number 3: Risc Timer Table */
|
||||
0x00001000, /* interrupt number 4: SMC 1 */
|
||||
0x00000800, /* interrupt number 5: SMC 2 */
|
||||
0x00000400, /* interrupt number 6: IDMA1 */
|
||||
0x00000200, /* interrupt number 7: IDMA2 */
|
||||
0x00000100, /* interrupt number 8: IDMA3 */
|
||||
0x00000080, /* interrupt number 9: IDMA4 */
|
||||
0x00000040, /* interrupt number 10: SDMA */
|
||||
0x00000000, /* interrupt number 11: reserved */
|
||||
0x00000010, /* interrupt number 12: Timer 1 */
|
||||
0x00000008, /* interrupt number 13: Timer 2 */
|
||||
0x00000004, /* interrupt number 14: Timer 3 */
|
||||
0x00000002, /* interrupt number 15: Timer 4 */
|
||||
0x00000004, /* interrupt number 16: TMCNT */
|
||||
0x00000002, /* interrupt number 17: PIT */
|
||||
0x00000001, /* interrupt number 18: PCI */
|
||||
0x00004000, /* interrupt number 19: IRQ 1 interrupt */
|
||||
0x00002000, /* interrupt number 20: IRQ 2 interrupt */
|
||||
0x00001000, /* interrupt number 21: IRQ 3 interrupt */
|
||||
0x00000800, /* interrupt number 22: IRQ 4 interrupt */
|
||||
0x00000400, /* interrupt number 23: IRQ 5 interrupt */
|
||||
0x00000200, /* interrupt number 24: IRQ 6 interrupt */
|
||||
0x00000100, /* interrupt number 25: IRQ 7 interrupt */
|
||||
0x00000000, /* interrupt number 26: reserved */
|
||||
0x80000000, /* interrupt number 27: FCC1 */
|
||||
0x40000000, /* interrupt number 28: FCC2 */
|
||||
0x20000000, /* interrupt number 29: FCC3 */
|
||||
0x00000000, /* interrupt number 30: reserved */
|
||||
0x08000000, /* interrupt number 31: MCC1 */
|
||||
0x04000000, /* interrupt number 32: MCC2 */
|
||||
0x00000000, /* interrupt number 33: reserved */
|
||||
0x00000000, /* interrupt number 34: reserved */
|
||||
0x00800000, /* interrupt number 35: SCC1 */
|
||||
0x00400000, /* interrupt number 36: SCC2 */
|
||||
0x00200000, /* interrupt number 37: SCC3 */
|
||||
0x00100000, /* interrupt number 38: SCC4 */
|
||||
0x00000000, /* interrupt number 39: reserved */
|
||||
0x00010000, /* interrupt number 40: Parallel I/O [15] */
|
||||
0x00020000, /* interrupt number 41: Parallel I/O [14] */
|
||||
0x00040000, /* interrupt number 42: Parallel I/O [13] */
|
||||
0x00080000, /* interrupt number 43: Parallel I/O [12] */
|
||||
0x00100000, /* interrupt number 44: Parallel I/O [11] */
|
||||
0x00200000, /* interrupt number 45: Parallel I/O [10] */
|
||||
0x00400000, /* interrupt number 46: Parallel I/O [9] */
|
||||
0x00800000, /* interrupt number 47: Parallel I/O [8] */
|
||||
0x01000000, /* interrupt number 48: Parallel I/O [7] */
|
||||
0x02000000, /* interrupt number 49: Parallel I/O [6] */
|
||||
0x04000000, /* interrupt number 50: Parallel I/O [5] */
|
||||
0x08000000, /* interrupt number 51: Parallel I/O [4] */
|
||||
0x10000000, /* interrupt number 52: Parallel I/O [3] */
|
||||
0x20000000, /* interrupt number 53: Parallel I/O [2] */
|
||||
0x40000000, /* interrupt number 54: Parallel I/O [1] */
|
||||
0x80000000, /* interrupt number 55: Parallel I/O [0] */
|
||||
0x00000000, /* interrupt number 56: reserved */
|
||||
0x00000000, /* interrupt number 57: reserved */
|
||||
0x00000000, /* interrupt number 58: reserved */
|
||||
0x00000000, /* interrupt number 59: reserved */
|
||||
0x00000000, /* interrupt number 60: reserved */
|
||||
0x00000000, /* interrupt number 61: reserved */
|
||||
0x00000000, /* interrupt number 62: reserved */
|
||||
0x00000000 /* interrupt number 63: reserved */
|
||||
};
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
LOCAL void m8260IntrDeMux (void);
|
||||
LOCAL STATUS m8260IntConnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
|
||||
LOCAL STATUS m8260IntDisconnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* m8260IntrInit - initialize the interrupt manager for the PowerPC 8260
|
||||
*
|
||||
* This routine connects the default demultiplexer, m8260IntrDeMux(), to the
|
||||
* external interrupt vector and associates all
|
||||
* interrupt sources with the default interrupt handler. This routine is
|
||||
* called by sysHwInit() in sysLib.c.
|
||||
*
|
||||
* NOTE: All interrupts from the SIU unit are enabled, CICR is setup so
|
||||
* that SCC1 has the highest relative interrupt priority, through SCC4 with the
|
||||
* lowest.
|
||||
*
|
||||
* RETURNS: OK always
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
STATUS m8260IntrInit (void)
|
||||
{
|
||||
int vector;
|
||||
|
||||
UINT32 immrVal = (vxImmrGet()& IMMR_ISB_MASK);
|
||||
|
||||
/* Get the default vector connected to the External Interrupt (0x500) */
|
||||
|
||||
defaultVec = (VOIDFUNCPTR) excVecGet ((FUNCPTR *) _EXC_OFF_INTR);
|
||||
|
||||
/* Connect the interrupt demultiplexer to External Interrupt (0x500) */
|
||||
|
||||
excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, m8260IntrDeMux);
|
||||
|
||||
/* Install `system' intConnect routine */
|
||||
|
||||
if (_func_intConnectRtn == NULL)
|
||||
_func_intConnectRtn = m8260IntConnect;
|
||||
|
||||
if (_func_intDisconnectRtn == NULL)
|
||||
_func_intDisconnectRtn = m8260IntDisconnect;
|
||||
|
||||
if (_func_intEnableRtn == NULL)
|
||||
_func_intEnableRtn = m8260IntEnable;
|
||||
|
||||
if (_func_intDisableRtn == NULL)
|
||||
_func_intDisableRtn = m8260IntDisable;
|
||||
|
||||
/* Set all vectors to default handler */
|
||||
|
||||
for (vector = 0; vector <= IVEC_MAX; vector++)
|
||||
intConnect (INUM_TO_IVEC(vector), (VOIDFUNCPTR) defaultVec, 0);
|
||||
|
||||
/* disable all interrupts */
|
||||
|
||||
*M8260_SIMR_L(immrVal) = 0x00000000;
|
||||
*M8260_SIMR_H(immrVal) = 0x00000000;
|
||||
|
||||
return (OK);
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* m8260IntConnect - connect a routine to an interrupt
|
||||
*
|
||||
* This routine connects any C or assembly routine to one of the multiple
|
||||
* sources of interrupts.
|
||||
*
|
||||
* The connected routine can be any normal C code, except that it must not
|
||||
* invoke certain operating system functions that may block or perform I/O
|
||||
* operations.
|
||||
*
|
||||
* <vector> types are defined in h/drv/intrClt/m8260Intr.h.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if <vector> is unknown.
|
||||
*
|
||||
* ERRNO
|
||||
*
|
||||
* SEE ALSO: m8260Intr.h
|
||||
*/
|
||||
|
||||
LOCAL STATUS m8260IntConnect
|
||||
(
|
||||
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
|
||||
VOIDFUNCPTR routine, /* routine to be called */
|
||||
int parameter /* parameter to be passed to routine */
|
||||
)
|
||||
{
|
||||
|
||||
/* test the vector */
|
||||
|
||||
if ((int)(vector) > IVEC_MAX)
|
||||
return (ERROR);
|
||||
|
||||
intrVecTable[(int)(vector)].vec = routine;
|
||||
intrVecTable[(int)(vector)].arg = parameter;
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* m8260IntDisconnect - disconnect a routine from an interrupt
|
||||
*
|
||||
* This routine disconnects any C or assembly routine from one of the multiple
|
||||
* sources of interrupts.
|
||||
*
|
||||
* <vector> types are defined in h/drv/intrClt/m8260Intr.h.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if <vector> is unknown.
|
||||
*
|
||||
* ERRNO
|
||||
*
|
||||
* SEE ALSO: m8260Intr.h
|
||||
*/
|
||||
|
||||
LOCAL STATUS m8260IntDisconnect
|
||||
(
|
||||
VOIDFUNCPTR * vector, /* interrupt vector to detach from */
|
||||
VOIDFUNCPTR routine, /* routine to be disconnected */
|
||||
int parameter /* parameter to be matched */
|
||||
)
|
||||
{
|
||||
/* test the vector */
|
||||
|
||||
if ((int)(vector) > IVEC_MAX)
|
||||
return (ERROR);
|
||||
|
||||
/* set the entry back to the default */
|
||||
|
||||
intrVecTable[(int)(vector)].vec = (VOIDFUNCPTR)defaultVec;
|
||||
intrVecTable[(int)(vector)].arg = 0;
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* m8260IntrDeMux - SIU interrupt demultiplexer
|
||||
*
|
||||
* This routine must be bound to an external interrupt exception (vector 0x500).
|
||||
* It is used to call the appropriate handler with its argument when an
|
||||
* interrupt occurs.
|
||||
*
|
||||
* The interrupts are prioritized in the following order:
|
||||
*
|
||||
* NOTE: when this function is called the interrupts are still locked. It's
|
||||
* this function's responsibility to unlock the interrupt.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
LOCAL void m8260IntrDeMux (void)
|
||||
{
|
||||
VINT32 intVec; /* interrupt vector */
|
||||
UINT32 oldIntMask_L; /* current interrupt mask */
|
||||
UINT32 oldIntMask_H; /* current interrupt mask */
|
||||
UINT32 immrVal;
|
||||
UINT32 intLevel = _PPC_MSR_EE;
|
||||
int dummy;
|
||||
|
||||
immrVal = (vxImmrGet() & IMMR_ISB_MASK);
|
||||
|
||||
/* read the interrupt vector register */
|
||||
|
||||
intVec = (0x0000003f & ((* M8260_SIVEC(immrVal)) >> 26));
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
EVT_CTX_1(EVENT_INT_ENT(0),intVec);
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
if ( intVec != 0 )
|
||||
{
|
||||
/* save the current interrupt mask */
|
||||
|
||||
oldIntMask_L = * M8260_SIMR_L(immrVal);
|
||||
oldIntMask_H = * M8260_SIMR_H(immrVal);
|
||||
|
||||
/* enable only the higher priority interrupts */
|
||||
|
||||
* M8260_SIMR_L(immrVal)&=
|
||||
enableHighPriInts[IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].simr_l;
|
||||
* M8260_SIMR_H(immrVal)&=
|
||||
enableHighPriInts[IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].simr_h;
|
||||
|
||||
/* New: read last written value into 'dummy' to enforce a sync */
|
||||
dummy = * M8260_SIMR_H(immrVal);
|
||||
|
||||
/* unlock the interrupt */
|
||||
|
||||
intUnlock (_PPC_MSR_EE);
|
||||
|
||||
/* call the Interrupt Handler */
|
||||
|
||||
/* table is indexed by vector */
|
||||
|
||||
intrVecTable[intVec].vec (intrVecTable[intVec].arg);
|
||||
|
||||
/* restore the interrupt mask */
|
||||
|
||||
intLevel = intLock ();
|
||||
* M8260_SIMR_L(immrVal) = oldIntMask_L;
|
||||
* M8260_SIMR_H(immrVal) = oldIntMask_H;
|
||||
intUnlock (intLevel);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* m8260IntEnable - enable the indicated interrupt
|
||||
*
|
||||
* This routine enables the indicated interrupt by setting the appropriate
|
||||
* bit in the SIU Interrupt Mask Registers.
|
||||
*
|
||||
* The design of the 8260 presents the following design requirements:
|
||||
*
|
||||
* 1. the mapping from interrupt number to mask bit can not be represented by
|
||||
* a function. An array, indexed by interrupt number (INUM), is used to map
|
||||
* the interrupt number to the appropriate mask.
|
||||
*
|
||||
* 2. There are two 32 bit mask registers (SIMR_L and SIMR_H). The interrupt
|
||||
* number must be compared to 4 ranges to determine which register contains
|
||||
* its mask bit:
|
||||
*
|
||||
* \cs
|
||||
* interrupt number
|
||||
* in m8260IntrCtl.h register
|
||||
* ---------------- -------
|
||||
* 0-15 SIMR_L
|
||||
* 16-31 SIMR_H
|
||||
* 32-47 SIMR_L
|
||||
* 48-63 SIMR_H
|
||||
* \ce
|
||||
*
|
||||
* RETURNS: 0, always.
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
int m8260IntEnable
|
||||
(
|
||||
int intNum /* interrupt level to enable */
|
||||
)
|
||||
{
|
||||
UINT32 immrVal = (vxImmrGet() & IMMR_ISB_MASK);
|
||||
|
||||
if ((intNum > 0) && (intNum <= IVEC_MAX))
|
||||
{
|
||||
if (((intNum >= 0) && (intNum <= 15)) ||
|
||||
((intNum >= 27) && (intNum <= 38)))
|
||||
*M8260_SIMR_L(immrVal) |= iNumToMaskPattern[intNum];
|
||||
else
|
||||
*M8260_SIMR_H(immrVal) |= iNumToMaskPattern[intNum];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* m8260IntDisable - Disable one of the Level or IRQ interrupts into the SIU
|
||||
*
|
||||
* This routine masks the bit in the SIMASK register corresponding to
|
||||
* the requested interrupt level.
|
||||
*
|
||||
* RETURNS: 0, always.
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
int m8260IntDisable
|
||||
(
|
||||
int intNum /* interrupt level to disable */
|
||||
)
|
||||
{
|
||||
UINT32 immrVal = (vxImmrGet() & IMMR_ISB_MASK);
|
||||
|
||||
if ((intNum >= 0) && (intNum <= IVEC_MAX))
|
||||
{
|
||||
if (((intNum >= 0) && (intNum <= 15)) ||
|
||||
((intNum >= 27) && (intNum <= 38)))
|
||||
*M8260_SIMR_L(immrVal) &= ~iNumToMaskPattern[intNum];
|
||||
else
|
||||
*M8260_SIMR_H(immrVal) &= ~iNumToMaskPattern[intNum];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
VOIDFUNCPTR * m8260InumToIvec
|
||||
(
|
||||
int intNum
|
||||
)
|
||||
{
|
||||
|
||||
if (intNum <0) /* error */
|
||||
return ((VOIDFUNCPTR *) 0);
|
||||
|
||||
else if (intNum <= 25)
|
||||
return ((VOIDFUNCPTR *) intNum);
|
||||
|
||||
else if (intNum == 26) /* error */
|
||||
return ((VOIDFUNCPTR *) 0);
|
||||
|
||||
else if (intNum <= 38)
|
||||
return ((VOIDFUNCPTR *) (intNum + 5));
|
||||
|
||||
else if (intNum == 39) /* error */
|
||||
return ((VOIDFUNCPTR *) 0);
|
||||
|
||||
else if (intNum <= 55)
|
||||
return ((VOIDFUNCPTR *) (intNum + 8));
|
||||
|
||||
else /* error */
|
||||
return ((VOIDFUNCPTR *) 0);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* m8260IvecToInum - get the relevant interrupt number
|
||||
*
|
||||
* This routine finds out the interrupt number associated with the vector
|
||||
* in <vector>.
|
||||
*
|
||||
* <vector> types are defined in h/drv/intrClt/m8260Intr.h.
|
||||
*
|
||||
* RETURNS: the interrupt number for the vector
|
||||
*
|
||||
* ERRNO
|
||||
*
|
||||
* SEE ALSO: m8260Intr.h
|
||||
*/
|
||||
|
||||
int m8260IvecToInum
|
||||
(
|
||||
VOIDFUNCPTR * vector /* interrupt vector to attach to */
|
||||
)
|
||||
{
|
||||
|
||||
/* test the vector */
|
||||
|
||||
if ((int) (vector) <= 0)
|
||||
return ((int ) 0);
|
||||
|
||||
else if ((int) vector < INUM_RESERVED26)
|
||||
return ((int) vector);
|
||||
|
||||
else if ((int) vector < 32)
|
||||
return (INUM_RESERVED26);
|
||||
|
||||
else if ((int) vector < 44)
|
||||
return ((int) vector - 5);
|
||||
|
||||
else if ((int) vector < 48)
|
||||
return ((int) INUM_RESERVED39);
|
||||
|
||||
else if ((int) vector <= IVEC_MAX)
|
||||
return ((int) vector - 8);
|
||||
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
/* mpApic.c - Intel MP APIC/xAPIC (Advanced PIC) */
|
||||
|
||||
/* Copyright 2006, 2008, 2015 Wind River Systems, Inc. */
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01g,29jun15,ten VXW6-84526 - Do not allocate space for disabled IO Apics.
|
||||
Sort staticMpApicAddrTable and staticMpApicLogicalTable by
|
||||
IO APIC ID
|
||||
01f,27aug08,jpb Renamed VSB header file
|
||||
01e,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
|
||||
for kernel configurations options set in vsb.
|
||||
01d,30oct06,scm rename mpApicNcpu to vxCpuCount...
|
||||
01c,31aug06,scm add support for CPU ID translation table...
|
||||
01b,26jul06,scm update for pentium/xeon support...
|
||||
01a,26jul06,hdn written...
|
||||
*/
|
||||
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vsbConfig.h>
|
||||
|
||||
#include "private/vxSmpP.h"
|
||||
|
||||
#include "drv/intrCtl/loApic.h"
|
||||
#include "drv/intrCtl/ioApic.h"
|
||||
#include "drv/intrCtl/mpApic.h"
|
||||
|
||||
/* externs */
|
||||
|
||||
IMPORT UINT32 sysIrqToPciIrq(UINT32 physApicId, UINT32 irq);
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
STATUS mpApicMpConfigTableInit(void);
|
||||
|
||||
INT8 *mpApicScan(INT8* match, INT8 * start, INT8 * end);
|
||||
|
||||
/* globals */
|
||||
|
||||
UINT32 mpApicNioApic = 0; /* number of IO APICs (MP Table) */
|
||||
UINT32 mpApicNbus = 0; /* number of buses (MP Table) */
|
||||
UINT32 mpApicNioint = 0; /* number of io interrupts (MP Table) */
|
||||
UINT32 mpApicNloint = 0; /* number of local interrupts (MP Table) */
|
||||
|
||||
MP_FPS* mpApicFps = NULL;
|
||||
|
||||
UINT32 *mpApicAddrTable[MAX_IOAPICS]; /* logical apic id to address mapping */
|
||||
|
||||
UINT8 mpApicLogicalTable[MAX_IOAPICS]; /* recorded id mapping */
|
||||
|
||||
#ifdef _WRS_CONFIG_SMP
|
||||
UINT8 mpCpuIndexTable[256]; /* cpu Id translation */
|
||||
UINT8 mploApicIndexTable[VX_MAX_SMP_CPUS]; /* loApic Id translation */
|
||||
#endif /* _WRS_CONFIG_SMP */
|
||||
|
||||
MP_INTERRUPT *mpApicInterruptTable; /* */
|
||||
|
||||
MP_BUS *mpApicBusTable; /* */
|
||||
|
||||
UINT8 mpApicBaseIrq[MAX_IOAPICS];
|
||||
UINT8 mpApicRedEntries[MAX_IOAPICS];
|
||||
|
||||
#ifdef MPTABLE_OVER_RIDE /* in case maybe the bios has it all wrong */
|
||||
|
||||
IMPORT MP_FPS *sysFps;
|
||||
IMPORT MP_BUS *sysBusTable;
|
||||
|
||||
IMPORT UINT32 sysNcpu;
|
||||
IMPORT UINT32 sysNioApic;
|
||||
IMPORT UINT32 sysNbus;
|
||||
IMPORT UINT32 sysNioint;
|
||||
IMPORT UINT32 sysNloint;
|
||||
|
||||
IMPORT MP_INTERRUPT sysIntTable[];
|
||||
|
||||
IMPORT MP_INTERRUPT *sysInterruptTable;
|
||||
|
||||
typedef struct apic_info
|
||||
{
|
||||
UINT8 id;
|
||||
UINT32 *addr;
|
||||
} APIC_INFO;
|
||||
|
||||
IMPORT APIC_INFO sysApicTable[];
|
||||
|
||||
IMPORT UINT8 sysBaseIrq[];
|
||||
IMPORT UINT8 sysRedEntries[];
|
||||
|
||||
#endif /* MPTABLE_OVER_RIDE */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* mpApicMpConfigTableInit - initialize pointers to MP configuration table
|
||||
*
|
||||
* This routine scans the memory areas specified in MP ver1.4, to find the
|
||||
* MP signature and initializes pointers to MP configuration tables. This
|
||||
* is not comprehensive and the only data used by VxWorks is the
|
||||
* APIC IDs and APIC base addresses.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if not MP compliant
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef MPTABLE_OVER_RIDE /* some MP tables are broken, allow for override */
|
||||
STATUS mpApicMpConfigTableInit (void)
|
||||
{
|
||||
int apicId;
|
||||
|
||||
#ifdef _WRS_CONFIG_SMP
|
||||
vxCpuCount = sysNcpu;
|
||||
#endif /* _WRS_CONFIG_SMP */
|
||||
mpApicNioApic = sysNioApic;
|
||||
mpApicNbus = sysNbus;
|
||||
mpApicNioint = sysNioint;
|
||||
mpApicNloint = sysNloint;
|
||||
mpApicInterruptTable = sysInterruptTable;
|
||||
mpApicBusTable = sysBusTable;
|
||||
mpApicFps = sysFps;
|
||||
|
||||
for(apicId = 0; apicId < sysNioApic; apicId++)
|
||||
{
|
||||
mpApicLogicalTable[apicId] = sysApicTable[apicId].id;
|
||||
mpApicAddrTable[apicId] = sysApicTable[apicId].addr;
|
||||
mpApicRedEntries[apicId] = sysRedEntries[apicId];
|
||||
mpApicBaseIrq[apicId] = sysBaseIrq[apicId];
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#else
|
||||
STATUS mpApicMpConfigTableInit (void)
|
||||
{
|
||||
MP_HEADER * hdr;
|
||||
MP_LOINTERRUPT * loint;
|
||||
MP_IOINTERRUPT * ioint;
|
||||
MP_CPU * cpu;
|
||||
MP_IOAPIC * ioapic;
|
||||
MP_BUS * bus;
|
||||
MP_IOAPIC * pIoApic;
|
||||
INT8 * p;
|
||||
INT32 ix, numEntries;
|
||||
UINT32 temp32;
|
||||
UINT8 outerIndex, innerIndex;
|
||||
|
||||
/* scan for the MP Floating Point Structure */
|
||||
|
||||
mpApicFps = (MP_FPS *)mpApicScan ("_MP_", (char *)EBDA_START, (char *)EBDA_END);
|
||||
if (mpApicFps == NULL)
|
||||
mpApicFps = (MP_FPS *)mpApicScan ("_MP_", (char *)BIOS_ROM_START,
|
||||
(char *)BIOS_ROM_END);
|
||||
|
||||
if (mpApicFps == NULL)
|
||||
return (ERROR);
|
||||
|
||||
/*
|
||||
* If featurebyte1 (array element 0) is non-zero, then we use
|
||||
* standard configuration return ERROR and let the error handle use
|
||||
* standard addresses and Local and IO APIC ID's.
|
||||
*/
|
||||
|
||||
if ((mpApicFps->featureByte[0] != 0) || (mpApicFps->configTableAddr == 0))
|
||||
return (ERROR);
|
||||
|
||||
/* get MP header pointer */
|
||||
|
||||
hdr = (MP_HEADER *) mpApicFps->configTableAddr;
|
||||
|
||||
/* First Pass identifies the number of each important entry */
|
||||
p = (char *)hdr + sizeof(MP_HEADER);
|
||||
for(ix = 0; ix < hdr->entryCount; ix++)
|
||||
{
|
||||
switch(*p)
|
||||
{
|
||||
case MP_ENTRY_CPU: /* Processor Configuration Entry */
|
||||
#ifdef _WRS_CONFIG_SMP
|
||||
vxCpuCount++; /* increment the CPU counter */
|
||||
#endif /* _WRS_CONFIG_SMP */
|
||||
p += sizeof (MP_CPU);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_IOAPIC: /* IO Apic Configuration Entry */
|
||||
pIoApic = (MP_IOAPIC *)p;
|
||||
|
||||
/* Check to see if the IO APIC is enabled */
|
||||
|
||||
if (pIoApic->ioApicFlags & 0x01)
|
||||
mpApicNioApic++; /* increment the IO APIC counter */
|
||||
|
||||
p += sizeof (MP_IOAPIC);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_BUS:
|
||||
mpApicNbus++;
|
||||
p += sizeof (MP_BUS);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_IOINTERRUPT: /* IO Interrupt Entry */
|
||||
mpApicNioint++;
|
||||
p += sizeof (MP_IOINTERRUPT);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_LOINTERRUPT: /* Local Interrupt Entry */
|
||||
mpApicNloint++;
|
||||
p += sizeof (MP_LOINTERRUPT);
|
||||
break;
|
||||
|
||||
default:
|
||||
p += 8; /* "maybe" it is 8 bytes till the next entry */
|
||||
}
|
||||
}
|
||||
|
||||
/* reset the counters */
|
||||
numEntries = ix;
|
||||
#ifdef _WRS_CONFIG_SMP
|
||||
vxCpuCount = 0;
|
||||
#endif /* _WRS_CONFIG_SMP */
|
||||
mpApicNioApic = 0;
|
||||
mpApicNbus = 0;
|
||||
mpApicNioint = 0;
|
||||
mpApicNloint = 0;
|
||||
|
||||
/* Second Pass takes action on each important entry */
|
||||
p = (char *)hdr + sizeof(MP_HEADER);
|
||||
for(ix = 0; ix < numEntries; ix++)
|
||||
{
|
||||
switch(*p)
|
||||
{
|
||||
case MP_ENTRY_CPU: /* Processor Configuration Entry */
|
||||
cpu = (MP_CPU *)p;
|
||||
#ifdef _WRS_CONFIG_SMP
|
||||
/* build cpu/loApic Id translation tbls */
|
||||
mpCpuIndexTable[cpu->localApicId] = vxCpuCount;
|
||||
mploApicIndexTable[vxCpuCount] = cpu->localApicId;
|
||||
vxCpuCount++; /* increment the CPU counter */
|
||||
#endif /* _WRS_CONFIG_SMP */
|
||||
p += sizeof (MP_CPU);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_IOAPIC: /* IO Apic Configuration Entry */
|
||||
ioapic = (MP_IOAPIC *)p;
|
||||
if ((ioapic->ioApicFlags & 0x1) && (mpApicNioApic < MAX_IOAPICS))
|
||||
{
|
||||
mpApicLogicalTable[mpApicNioApic] = ioapic->ioApicId;
|
||||
mpApicAddrTable[mpApicNioApic] = (UINT32*)ioapic->ioApicBaseAddress;
|
||||
mpApicNioApic++; /* increment the IO APIC counter */
|
||||
}
|
||||
p += sizeof (MP_IOAPIC);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_BUS: /* Bus Identifier Entry */
|
||||
if (mpApicNbus == 0)
|
||||
mpApicBusTable =(MP_BUS *)p;
|
||||
mpApicNbus++;
|
||||
bus = (MP_BUS *)p;
|
||||
p += sizeof (MP_BUS);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_IOINTERRUPT: /* IO Interrupt Entry */
|
||||
if (mpApicNioint == 0)
|
||||
mpApicInterruptTable = (MP_IOINTERRUPT *)p;
|
||||
mpApicNioint++;
|
||||
ioint = (MP_IOINTERRUPT *)p;
|
||||
p += sizeof (MP_IOINTERRUPT);
|
||||
break;
|
||||
|
||||
case MP_ENTRY_LOINTERRUPT: /* Local Interrupt Entry */
|
||||
loint = (MP_LOINTERRUPT *)p;
|
||||
mpApicNloint++;
|
||||
p += sizeof (MP_LOINTERRUPT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (outerIndex = 0; outerIndex < pMpApicData->mpApicNioApic; outerIndex++)
|
||||
for (innerIndex = 0; innerIndex < pMpApicData->mpApicNioApic - 1; innerIndex++)
|
||||
if (mpApicLogicalTable[innerIndex] >
|
||||
mpApicLogicalTable[innerIndex+1])
|
||||
{
|
||||
|
||||
/* swap entries */
|
||||
|
||||
temp32 = mpApicAddrTable[innerIndex+1];
|
||||
mpApicAddrTable[innerIndex+1] =
|
||||
mpApicAddrTable[innerIndex];
|
||||
mpApicAddrTable[innerIndex] = temp32;
|
||||
|
||||
tmp = mpApicLogicalTable[innerIndex+1];
|
||||
mpApicLogicalTable[innerIndex+1] =
|
||||
mpApicLogicalTable[innerIndex];
|
||||
mpApicLogicalTable[innerIndex] = tmp;
|
||||
}
|
||||
|
||||
/* Set up the Local APIC */
|
||||
loApicBase = (UINT32)(hdr->localApicBaseAddr);
|
||||
return(OK);
|
||||
}
|
||||
#endif /* OVER RIDE */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* mpApicScan - scans given memory range for the string match
|
||||
*
|
||||
* This routine scans the memory areas specified in its argument for the
|
||||
* Intel MP signature string "_MP_", or other signature strings.
|
||||
*
|
||||
* RETURNS: pointer to address of matching string in the range , or NULL
|
||||
*
|
||||
*/
|
||||
|
||||
INT8 * mpApicScan
|
||||
(
|
||||
INT8 * match,
|
||||
INT8 * start, /* start address to scan */
|
||||
INT8 * end /* end address to scan */
|
||||
)
|
||||
{
|
||||
INT8 * p;
|
||||
|
||||
for (p = start; (p+16) < end; p+=16)
|
||||
{
|
||||
if (strncmp (p, match, strlen(match)) == 0)
|
||||
return (p);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
UINT32 mpApicIrqToBusIrq(UINT32 ioApicId, UINT32 irq)
|
||||
{
|
||||
UINT32 physApicId = mpApicLogicalTable[ioApicId];
|
||||
return sysIrqToPciIrq(physApicId, irq);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,328 @@
|
||||
/* ppc403Intr.c - IBM 403 EVB-specific interrupt handling library */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1984-2003, 2008 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use of this
|
||||
* software may be licensed only pursuant to the terms of an applicable Wind
|
||||
* River license agreement.
|
||||
*/
|
||||
|
||||
/* modification history
|
||||
-----------------------
|
||||
01u,27aug08,jpb Renamed VSB header file
|
||||
01t,18jul08,kk added inclusion of private/vsbConfigP.h to pick up macros
|
||||
01s,14may08,jpb Modifications for source build. Renamed
|
||||
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
|
||||
01r,19nov03,to added intDisconnect() functionality
|
||||
01q,24jan02,pch Fix Diab warnings
|
||||
01p,24aug98,cjtc windview 2.0 event logging is now single step. Timestamp no
|
||||
longer stored by intEnt. Avoids out-of-sequence timestamps in
|
||||
event log (SPR 21868)
|
||||
01o,16apr98,pr moved triggering support from arch/ppc
|
||||
01n,08apr98,pr modified support for WindView 20
|
||||
01m,07aug97,tam fixed critical exception handling (SPR #8964).
|
||||
01l,10jun97,wlf doc: more cleanup.
|
||||
01k,31mar97,tam clear DMA interrupts properly in sysPpc403IntHandler(SPR 8285)
|
||||
01j,19mar97,tam mask CE bit as well (SPR 8192). Removed while loop in
|
||||
sysPpc403IntEnable() & sysPpc403IntDisable().
|
||||
01i,09dec96,tpr changed _func_intEnableRtn() & _func_intDisableRtn() return
|
||||
type from void to int.
|
||||
Added sysPpc403IntEnable() & sysPpc403IntDisable() return
|
||||
code.
|
||||
01h,15nov96,wlf doc: cleanup.
|
||||
01g,11jul96,pr included eventP.h
|
||||
01f,11jul96,pr added windview instrumentation
|
||||
01e,11jul96,tam modified sysPpc403IntHandler to enable nested interrupt.
|
||||
01d,18mar96,tam added sysPpc403IntEnable/Disable and cleanup.
|
||||
01c,28feb96,tam renamed and moved src/arch/ppc/intPpp403Lib.c to
|
||||
src/drv/intrCtl/ppc403Intr.c.
|
||||
01b,09feb95,yao enabled nested interrupt.
|
||||
01a,28nov94,yao created.
|
||||
*/
|
||||
|
||||
/*
|
||||
This library provides various interface routines to manipulate and connect
|
||||
to external hardware interrupts for the PPC403GA Embedded Controller.
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <vsbConfig.h>
|
||||
#include <logLib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
#include <private/eventP.h>
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
/* defines */
|
||||
|
||||
#define INT_LEVEL_MAX 31
|
||||
#define INT_LEVEL_MIN 0
|
||||
|
||||
/* externals */
|
||||
|
||||
/* globals */
|
||||
|
||||
void sysPpc403IntHandler (void);
|
||||
|
||||
/* locals */
|
||||
|
||||
LOCAL VOIDFUNCPTR sysIntBlTbl [32] = {(VOIDFUNCPTR) NULL};
|
||||
LOCAL int sysIntArg [32] = {0};
|
||||
|
||||
/* forward LOCAL functions declarations */
|
||||
|
||||
LOCAL STATUS sysPpc403IntConnect (VOIDFUNCPTR * vector, VOIDFUNCPTR routine,
|
||||
int parameter);
|
||||
LOCAL STATUS sysPpc403IntDisconnect (VOIDFUNCPTR * vector,
|
||||
VOIDFUNCPTR routine, int parameter);
|
||||
LOCAL int sysPpc403IntEnable (int intLevel);
|
||||
LOCAL int sysPpc403IntDisable (int intLevel);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysPpc403IntrInit - initialize the PPC403GA interrupt facility
|
||||
*
|
||||
* This routine initializes the interrupt facility for the PPC403GA Embedded
|
||||
* Controller.
|
||||
*
|
||||
* RETURNS: OK, always.
|
||||
*/
|
||||
|
||||
STATUS sysPpc403IntrInit (void)
|
||||
|
||||
{
|
||||
/* set the BSP driver specific Interrupt Handler and intConnect routines */
|
||||
|
||||
_func_intConnectRtn = sysPpc403IntConnect;
|
||||
_func_intDisconnectRtn = sysPpc403IntDisconnect;
|
||||
_func_intEnableRtn = sysPpc403IntEnable;
|
||||
_func_intDisableRtn = sysPpc403IntDisable;
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysPpc403IntConnect - connect a C routine to a hardware interrupt
|
||||
*
|
||||
* This routine connects a specified C routine to a specified
|
||||
* interrupt vector. It is called by intConnect().
|
||||
*
|
||||
* The PPC403GA Embedded Controller does not provide vectors for external
|
||||
* interrupts. Instead, vectors are assigned according to the bits in the
|
||||
* External Interrupt Enable Register (EXIER).
|
||||
* In case of DMA interrupts, the DMA Status register is always passed to
|
||||
* the ISR as the argument <parameter>.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if <vector> is out of range.
|
||||
*
|
||||
* SEE ALSO: intConnect(), sysPpc403IntHandler()
|
||||
*/
|
||||
|
||||
LOCAL STATUS sysPpc403IntConnect
|
||||
(
|
||||
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
|
||||
VOIDFUNCPTR routine, /* routine to be called */
|
||||
int parameter /* parameter to be passed to routine */
|
||||
)
|
||||
{
|
||||
if (((int)vector > INT_LEVEL_MAX) || ((int)vector < INT_LEVEL_MIN))
|
||||
return (ERROR);
|
||||
else
|
||||
{
|
||||
sysIntBlTbl[(int)vector] = routine;
|
||||
sysIntArg[(int)vector] = parameter;
|
||||
return (OK);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysPpc403IntDisconnect - disconnect a C routine from a hardware interrupt
|
||||
*
|
||||
* This routine disconnects a specified C routine from a specified
|
||||
* interrupt vector. It is called by intDisconnect().
|
||||
*
|
||||
* RETURNS: OK, or ERROR if <vector> is out of range.
|
||||
*
|
||||
* SEE ALSO: intDisconnect(), sysPpc403IntHandler()
|
||||
*/
|
||||
|
||||
LOCAL STATUS sysPpc403IntDisconnect
|
||||
(
|
||||
VOIDFUNCPTR * vector, /* interrupt vector to detach from */
|
||||
VOIDFUNCPTR routine, /* routine to be disconnected */
|
||||
int parameter /* parameter to be matched */
|
||||
)
|
||||
{
|
||||
if (((int)vector > INT_LEVEL_MAX) || ((int)vector < INT_LEVEL_MIN))
|
||||
return (ERROR);
|
||||
else
|
||||
{
|
||||
sysIntBlTbl[(int)vector] = (VOIDFUNCPTR) NULL;
|
||||
sysIntArg[(int)vector] = 0;
|
||||
return (OK);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysPpc403IntHandler - PPC403GA external interrupt handler
|
||||
*
|
||||
* This is the external interrupt handler for the PPC403GA
|
||||
* Embedded Controller.
|
||||
* In case of DMA interrupts, the DMA Status register is always passed to
|
||||
* the ISR, that was connected to the DMA interrupt via intConnect(), as an
|
||||
* argument.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void sysPpc403IntHandler (void)
|
||||
{
|
||||
int vector;
|
||||
INT32 exisr;
|
||||
INT32 exier;
|
||||
UINT32 dmaSrVal = 0; /* DMA Status reg. value */
|
||||
|
||||
/* get interrupts status and interrupt control register */
|
||||
|
||||
exisr = vxExisrGet ();
|
||||
exier = vxExierGet ();
|
||||
exisr = exisr & exier;
|
||||
|
||||
/* get interrupt number */
|
||||
|
||||
vector = vxFirstBit (exisr);
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
WV_EVT_INT_ENT(vector)
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
if (vector <= INT_LEVEL_MAX)
|
||||
{
|
||||
/* is this a DMA interrupt ? */
|
||||
|
||||
if ((vector > 7) && (vector < 12))
|
||||
{
|
||||
/*
|
||||
* got a DMA interrupt: clear DMASR[CSX,TSX,RIX,CTX] bits for
|
||||
* DMA channel X before interrupts are re-enabled.
|
||||
* Pass the DMA status register to the ISR that processes the
|
||||
* DMA interrupt for channel X.
|
||||
* This does prevent passing another argument than DMASR to the
|
||||
* ISR via intConnect, only for the DMA interrupts. However it
|
||||
* enables the ISR to detect the cause of the interrupt according
|
||||
* to DMASR.
|
||||
*/
|
||||
|
||||
dmaSrVal = vxDmasrGet();
|
||||
|
||||
vxDmasrSet (dmaSrVal & ((0x88880040 >> (vector -8)) & 0xfff80070));
|
||||
|
||||
sysIntArg[vector] = (UINT32) dmaSrVal;
|
||||
}
|
||||
|
||||
/* clear the interrupt status bit */
|
||||
|
||||
vxExisrClear (1 << (INT_LEVEL_MAX - vector));
|
||||
|
||||
/*
|
||||
* Mask this and lower priority interrupt levels:
|
||||
* the critical interrupt has the highest priority while the
|
||||
* external interrupt 4 has the lowest priority (cf EXIER reg.).
|
||||
*/
|
||||
|
||||
vxExierSet ((0xFFFFFFFF << (INT_LEVEL_MAX+1 - vector)) & vxExierGet());
|
||||
|
||||
/*
|
||||
* enable interrupt nesting: an external interrupt cannot be nested
|
||||
* with a critical interrupt (CINT or watchdog int.) due to the
|
||||
* implementation of the support for critical interrupt. However
|
||||
* critical interrupts may be nested with each other.
|
||||
*/
|
||||
|
||||
if (vector == 0)
|
||||
intUnlock (_PPC_MSR_CE);
|
||||
else
|
||||
intUnlock (_PPC_MSR_EE | _PPC_MSR_CE);
|
||||
|
||||
if (sysIntBlTbl [vector] != (VOIDFUNCPTR) NULL)
|
||||
(*sysIntBlTbl [vector]) (sysIntArg[vector]);
|
||||
else
|
||||
logMsg ("uninitialized interrupt vector %d\n", vector, 0,0,0,0,0);
|
||||
|
||||
/* re-enable interrupt mask */
|
||||
|
||||
vxExierSet (exier);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysPpc403IntDisable - disable an external interrupt level
|
||||
*
|
||||
* This routine disables a specified external interrupt for the PPC403GA
|
||||
* Embedded Controller.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if <intLevel> is not in the range 0 - 31.
|
||||
*
|
||||
* SEE ALSO: sysPpc403IntEnable()
|
||||
*/
|
||||
|
||||
LOCAL int sysPpc403IntDisable
|
||||
(
|
||||
int intLevel /* interrupt level to disable */
|
||||
)
|
||||
{
|
||||
UINT32 intMask;
|
||||
|
||||
if (intLevel > INT_LEVEL_MAX || intLevel < INT_LEVEL_MIN)
|
||||
return (ERROR);
|
||||
|
||||
intMask = 1 << (INT_LEVEL_MAX - intLevel);
|
||||
|
||||
/* disable the interrupt level */
|
||||
|
||||
vxExierDisable (intMask);
|
||||
|
||||
vxExisrClear (intMask); /* clear pending interrupts */
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* sysPpc403IntEnable - enable an external interrupt level
|
||||
*
|
||||
* This routine enables a specified external interrupt for the PPC403GA
|
||||
* Embedded Controller.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if <intLevel> is not in the range 0 - 31.
|
||||
*
|
||||
* SEE ALSO: sysPpc403IntDisable()
|
||||
*/
|
||||
|
||||
LOCAL int sysPpc403IntEnable
|
||||
(
|
||||
int intLevel /* interrupt level to enable */
|
||||
)
|
||||
{
|
||||
UINT32 intMask;
|
||||
|
||||
if (intLevel > INT_LEVEL_MAX || intLevel < INT_LEVEL_MIN)
|
||||
return (ERROR);
|
||||
|
||||
intMask = 1 << (INT_LEVEL_MAX - intLevel);
|
||||
|
||||
vxExisrClear (intMask); /* clear pending interrupts */
|
||||
|
||||
/* enable the interrupt level */
|
||||
|
||||
vxExierEnable (intMask);
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,520 @@
|
||||
/* ppc860Intr.c - PowerPC 800 series interrupt driver */
|
||||
|
||||
/* Copyright 1997,1998 Motorola, Inc., All Rights Reserved */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1984-2005, 2008 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use of this
|
||||
* software may be licensed only pursuant to the terms of an applicable Wind
|
||||
* River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01n,27aug08,jpb Renamed VSB header file
|
||||
01m,18jul08,kk added inclusion of private/vsbConfigP.h to pick up macros
|
||||
01l,14may08,jpb Modifications for source build. Renamed
|
||||
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
|
||||
01k,08mar05,mig do not allow equal or lower priority interrupts [SPR# 106795]
|
||||
01j,17nov03,to added intDisconnect() functionality
|
||||
01i,28jan02,dtr Removing diab warnings.
|
||||
01h,15sep01,dat Removed special def of CACHE_PIPE_FLUSH
|
||||
01g,28apr99,dat Merge from 2_0_0
|
||||
01o,30jan99,cn fixed SPR #22321.
|
||||
01n,24aug98,cjtc windview 2.0 event logging is now single step. Timestamp no
|
||||
longer stored by intEnt. Avoids out-of-sequence timestamps in
|
||||
event log (SPR 21868)
|
||||
0lm,12aug98,gls corrected assignment of evtIntNum
|
||||
01l,04aug98,gls fixed SPR #21239, kernel locks on boot when instrumented
|
||||
01k,16apr98,pr added WindView 20 instrumentation.
|
||||
01j,30mar98,map initialize _func_int{Enable,Disable}Rtn [SPR# 20447]
|
||||
01i,26mar98,map added ppc860IntEnable, ppc860IntDisable, removed duplicate
|
||||
#ifdef'd code, reworked ppc860IntrInit(). [SPR# 20447]
|
||||
01h,11nov97,map redo clearing CISR bits [SPR# 8781], and default SCC
|
||||
interrupt priority
|
||||
01g,23jun97,map added default SCC interrupt priority [SPR# 8692]
|
||||
01f,19jun97,map added IV_SCC[34] definitions [SPR# 8450]
|
||||
01e,17jun97,map fixed clearing CISR bits [SPR# 8781]
|
||||
01d,06mar97,tpr fixed properly SPR #8042.
|
||||
01c,21feb97,tpr fixed interrupt bit clearing in CISR (SPR #8042).
|
||||
01b,18sep96,pr added WindView instrumentation.
|
||||
01a,17feb96,tpr written.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
The PowerPC 800 CPU series is divided in three units: PowerPC core, System
|
||||
Interface Unit (SIU) and Communication Processor Unit (CPM). The PowerPC
|
||||
core accepts only one external interrupt exception (vector 0x500). The SIU
|
||||
provides an interrupt controller which provides 32 levels but only 16 are
|
||||
used. The Interrupt controller is connected to the PowerPC core external
|
||||
interrupt. The CPM unit also provides an interrupt controller which can
|
||||
be connected to one of the SIU interrupt controller entries. This library
|
||||
provides the routines to manage these interrupt controllers
|
||||
|
||||
|
||||
ppc860IntrInit() connects the default demultiplexers, ppc860IntrDeMux() and
|
||||
ppc860CpmIntrDeMux(), to the external interrupt vector and initializes a table
|
||||
containing a function pointer and an associated parameter for each interrupt
|
||||
source. ppc860IntrInit() is called by sysHwInit() from sysLib.c.
|
||||
|
||||
The default demultiplexer, ppc860IntrDeMux() detects which peripheral or
|
||||
controller has raised an interrupt and calls the associated routine with its
|
||||
parameter. If the interrupt comes from the CPM interrupt controller, the
|
||||
ppc860CpmIntDeMux() function is called. As ppc860IntrDeMux(), this function
|
||||
detects which peripheral or controller has raised an interrupt and calls the
|
||||
associated routine with its parameter.
|
||||
|
||||
INCLUDE FILES: drv/intrCtl/ppc860Intr.h, drv/multi/ppc860Siu.h,
|
||||
drv/multi/ppc860Cpm.h
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vsbConfig.h>
|
||||
#include <intLib.h>
|
||||
#include <iv.h>
|
||||
#include <drv/intrCtl/ppc860Intr.h>
|
||||
#include <drv/multi/ppc860Siu.h>
|
||||
#include <drv/multi/ppc860Cpm.h>
|
||||
|
||||
/* default SCC relative interrupt priority */
|
||||
|
||||
#define CICR_SCCP_DEF (CICR_SCCDP_SCC4 | CICR_SCCCP_SCC3 | \
|
||||
CICR_SCCBP_SCC2 | CICR_SCCAP_SCC1 )
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
|
||||
#include <private/funcBindP.h>
|
||||
#include <private/eventP.h>
|
||||
|
||||
LOCAL int cpmIntNum;
|
||||
LOCAL int cpmVecNum;
|
||||
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
/* local */
|
||||
|
||||
LOCAL INTR_HANDLER intrVecTable[NUM_VEC_MAX]; /* Intr vector table */
|
||||
LOCAL VOIDFUNCPTR defaultVec; /* INTR3 default vector */
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
LOCAL void ppc860IntrDeMux (void);
|
||||
LOCAL void ppc860CpmIntrDeMux (int);
|
||||
LOCAL STATUS ppc860IntConnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
|
||||
LOCAL STATUS ppc860IntDisconnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
|
||||
LOCAL int ppc860IntEnable (int);
|
||||
LOCAL int ppc860IntDisable (int);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ppc860IntrInit - initialize the interrupt manager for the PowerPC 800 series
|
||||
*
|
||||
* This routine connects the default demultiplexers, ppc860IntrDeMux() and
|
||||
* ppc860CpmIntrDeMux, to the external interrupt vector and associates all
|
||||
* interrupt sources with the default interrupt handler. This routine is
|
||||
* called by sysHwInit() in sysLib.c.
|
||||
*
|
||||
* NOTE: All interrupt from the SIU and CPM unit are enabled, CICR is setup so
|
||||
* that SCC1 has the highest relative interrupt priority, through SCC4 with the
|
||||
* lowest.
|
||||
*
|
||||
* RETURN : OK or ERROR if the SUI interrupt level to connect the CPM
|
||||
* interrupt controller is wrong.
|
||||
*/
|
||||
|
||||
STATUS ppc860IntrInit
|
||||
(
|
||||
VOIDFUNCPTR * cpmIntrVec /* Intr level of the CPM Intr ctrl */
|
||||
)
|
||||
{
|
||||
UINT32 regBase; /* device register base address */
|
||||
UINT32 cicrIntLevel; /* CICR interrupt level */
|
||||
UINT32 simaskIntLevel;
|
||||
int vector;
|
||||
|
||||
/* Get the default vector connected to the External Interrupt (0x500) */
|
||||
|
||||
defaultVec = (VOIDFUNCPTR) excVecGet ((FUNCPTR *) _EXC_OFF_INTR);
|
||||
|
||||
/* Connect the interrupt demultiplexer to External Interrupt (0x500) */
|
||||
|
||||
excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, ppc860IntrDeMux);
|
||||
|
||||
/* Install `system' intConnect routine */
|
||||
|
||||
if (_func_intConnectRtn == NULL)
|
||||
_func_intConnectRtn = ppc860IntConnect;
|
||||
|
||||
if (_func_intDisconnectRtn == NULL)
|
||||
_func_intDisconnectRtn = ppc860IntDisconnect;
|
||||
|
||||
if (_func_intEnableRtn == NULL)
|
||||
_func_intEnableRtn = ppc860IntEnable;
|
||||
|
||||
if (_func_intDisableRtn == NULL)
|
||||
_func_intDisableRtn = ppc860IntDisable;
|
||||
|
||||
/* Set all vectors to default handler */
|
||||
|
||||
for (vector = 0; vector < NUM_VEC_MAX; vector++)
|
||||
ppc860IntConnect (INUM_TO_IVEC(vector), defaultVec, 0);
|
||||
|
||||
/* Get the CPM interrupt level */
|
||||
|
||||
switch (IVEC_TO_INUM(cpmIntrVec))
|
||||
{
|
||||
case IVEC_TO_INUM(IV_LEVEL0):
|
||||
cicrIntLevel = CICR_IRL_LVL0;
|
||||
simaskIntLevel = SIMASK_LVM0;
|
||||
break;
|
||||
|
||||
case IVEC_TO_INUM(IV_LEVEL1):
|
||||
cicrIntLevel = CICR_IRL_LVL1;
|
||||
simaskIntLevel = SIMASK_LVM1;
|
||||
break;
|
||||
|
||||
case IVEC_TO_INUM(IV_LEVEL2):
|
||||
cicrIntLevel = CICR_IRL_LVL2;
|
||||
simaskIntLevel = SIMASK_LVM2;
|
||||
break;
|
||||
|
||||
case IVEC_TO_INUM(IV_LEVEL3):
|
||||
cicrIntLevel = CICR_IRL_LVL3;
|
||||
simaskIntLevel = SIMASK_LVM3;
|
||||
break;
|
||||
|
||||
case IVEC_TO_INUM(IV_LEVEL4):
|
||||
cicrIntLevel = CICR_IRL_LVL4;
|
||||
simaskIntLevel = SIMASK_LVM4;
|
||||
break;
|
||||
|
||||
case IVEC_TO_INUM(IV_LEVEL5):
|
||||
cicrIntLevel = CICR_IRL_LVL5;
|
||||
simaskIntLevel = SIMASK_LVM5;
|
||||
break;
|
||||
|
||||
case IVEC_TO_INUM(IV_LEVEL6):
|
||||
cicrIntLevel = CICR_IRL_LVL6;
|
||||
simaskIntLevel = SIMASK_LVM6;
|
||||
break;
|
||||
|
||||
case IVEC_TO_INUM(IV_LEVEL7):
|
||||
cicrIntLevel = CICR_IRL_LVL7;
|
||||
simaskIntLevel = SIMASK_LVM7;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect the CPM interrupt demultiplexer at the level specified by
|
||||
* `cpmIntLevel'
|
||||
*/
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
cpmVecNum = IVEC_TO_INUM(cpmIntrVec);
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
intConnect (cpmIntrVec, ppc860CpmIntrDeMux, simaskIntLevel);
|
||||
|
||||
/* Get the register base address */
|
||||
|
||||
regBase = vxImmrGet();
|
||||
|
||||
/*
|
||||
* Set the request interrupt level from the CPM and enable CPM interrupt
|
||||
* generation.
|
||||
*/
|
||||
|
||||
* CICR(regBase) = (CICR_SCCP_DEF | cicrIntLevel | CICR_IEN | CICR_HP_MSK);
|
||||
|
||||
/* Enable required CPM interrupt */
|
||||
|
||||
* SIMASK(regBase) = simaskIntLevel;
|
||||
|
||||
return (OK);
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ppc860IntConnect - connect a routine to an interrupt
|
||||
*
|
||||
* This routine connects any C or assembly routine to one of the multiple
|
||||
* sources of interrupts.
|
||||
*
|
||||
* The connected routine can be any normal C code, except that it must not
|
||||
* invoke certain operating system functions that may block or perform I/O
|
||||
* operations.
|
||||
*
|
||||
* <vector> types are defined in h/drv/intrClt/ppc860Intr.h.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if <vector> is unknown.
|
||||
*
|
||||
* SEE ALSO: ppc860Intr.h
|
||||
*/
|
||||
|
||||
LOCAL STATUS ppc860IntConnect
|
||||
(
|
||||
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
|
||||
VOIDFUNCPTR routine, /* routine to be called */
|
||||
int parameter /* parameter to be passed to routine */
|
||||
)
|
||||
{
|
||||
|
||||
/* test the vector */
|
||||
|
||||
if (IVEC_TO_INUM(vector) >= NUM_VEC_MAX)
|
||||
return (ERROR);
|
||||
|
||||
intrVecTable[IVEC_TO_INUM(vector)].vec = routine;
|
||||
intrVecTable[IVEC_TO_INUM(vector)].arg = parameter;
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ppc860IntDisconnect - disconnect a routine from an interrupt
|
||||
*
|
||||
* This routine disconnects a routine from one of the multiple sources of
|
||||
* interrupts.
|
||||
*
|
||||
* <vector> types are defined in h/drv/intrClt/ppc860Intr.h.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if <vector> is unknown.
|
||||
*
|
||||
* SEE ALSO: ppc860Intr.h
|
||||
*/
|
||||
|
||||
LOCAL STATUS ppc860IntDisconnect
|
||||
(
|
||||
VOIDFUNCPTR * vector, /* interrupt vector to detach from */
|
||||
VOIDFUNCPTR routine, /* routine to be disconnected */
|
||||
int parameter /* parameter to be matched */
|
||||
)
|
||||
{
|
||||
|
||||
/* test the vector */
|
||||
|
||||
if (IVEC_TO_INUM(vector) >= NUM_VEC_MAX)
|
||||
return (ERROR);
|
||||
|
||||
intrVecTable[IVEC_TO_INUM(vector)].vec = defaultVec;
|
||||
intrVecTable[IVEC_TO_INUM(vector)].arg = 0;
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ppc860IntrDeMux - SIU interrupt demultiplexer
|
||||
*
|
||||
* This routine must be bound to external interrupt exception (vector 0x500).
|
||||
* It is used to call the appropriate handler with its argument when an
|
||||
* interrupt occurs.
|
||||
*
|
||||
* The interrupts are prioritized in the following order:
|
||||
*
|
||||
* NOTE: when this function is called the interrupts are still locked. It's
|
||||
* this function's responsibility to unlock the interrupt.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
LOCAL void ppc860IntrDeMux (void)
|
||||
{
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
UINT32 evtIntNum; /* windview interrupt vector */
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
UINT8 intVec; /* interrupt vector */
|
||||
UINT32 regBase; /* register Base Address */
|
||||
UINT32 intMask; /* current interrupt mask */
|
||||
|
||||
|
||||
regBase = vxImmrGet();
|
||||
|
||||
/* read the interrupt vector register */
|
||||
|
||||
intVec = (* SIVEC(regBase)) >> 26;
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
|
||||
/*
|
||||
* if it is a cpm interrupt we need to know the corresponding cpm
|
||||
* level, that we should get from the CPM demultiplexer. But we
|
||||
* need the value here and the value can be read only once. We
|
||||
* save the value here so that once the CPM demultiplexer is called,
|
||||
* it will read the value from the global variable cpmIntNum.
|
||||
*
|
||||
* Since we do not know the CPM level a priori, we have to leave
|
||||
* enough space for the cpm interrupts in the windview list.
|
||||
* Therefore, any interrupt number bigger than the CPM level will
|
||||
* be increased of 15 so to leave those spots to the corresponding
|
||||
* CPM interrupts.
|
||||
*/
|
||||
|
||||
if (intVec == cpmVecNum)
|
||||
{
|
||||
/* acknowledge the interrupt */
|
||||
|
||||
*CIVR(regBase) = CIVR_IACK;
|
||||
|
||||
CACHE_PIPE_FLUSH ();
|
||||
|
||||
cpmIntNum = * CIVR(regBase) >> 11;
|
||||
evtIntNum = cpmIntNum + 32;
|
||||
}
|
||||
else
|
||||
evtIntNum = intVec;
|
||||
|
||||
WV_EVT_INT_ENT(evtIntNum)
|
||||
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
/* save the current interrupt mask */
|
||||
|
||||
intMask = * SIMASK(regBase);
|
||||
|
||||
/* lock all levels inferior to the interrupt detected */
|
||||
|
||||
* SIMASK(regBase) &= (0xffffffff << (32 - intVec));
|
||||
|
||||
/* unlock the interrupt */
|
||||
|
||||
intUnlock (_PPC_MSR_EE);
|
||||
|
||||
/* call the Interrupt Handler */
|
||||
|
||||
intrVecTable[intVec].vec (intrVecTable[intVec].arg);
|
||||
|
||||
/*
|
||||
* lock interrupts to ensure no equal or lower priority interrupts
|
||||
* occur prior to exiting the isr. SPR 106795
|
||||
*/
|
||||
|
||||
intLock();
|
||||
|
||||
/* restore the interrupt mask */
|
||||
|
||||
* SIMASK(regBase) = intMask;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ppc860CpmIntrDeMux - CPM interrupt demultiplexer
|
||||
*
|
||||
* This routine must be bound to external interrupt exception (vector 0x500).
|
||||
* It is used to call the appropriate handler with its argument when an
|
||||
* interrupt occurs.
|
||||
*
|
||||
* The interrupts are prioritized in the following order:
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
LOCAL void ppc860CpmIntrDeMux
|
||||
(
|
||||
int simaskLevel
|
||||
)
|
||||
{
|
||||
int intNum; /* interrupt number */
|
||||
UINT32 regBase; /* register Base Address */
|
||||
UINT32 intOldMask; /* interrupt mask before the interrupt*/
|
||||
|
||||
/* get the device register base address */
|
||||
|
||||
regBase = vxImmrGet();
|
||||
|
||||
/* get the interrupt vector */
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
intNum = cpmIntNum;
|
||||
#else
|
||||
/* acknowledge the interrupt */
|
||||
|
||||
* CIVR(regBase) = CIVR_IACK;
|
||||
|
||||
intNum = * CIVR(regBase) >> 11;
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
/* save the interrupt mask before the interrupt */
|
||||
|
||||
intOldMask = * CIMR(regBase);
|
||||
|
||||
/* lock all levels inferior to the interrupt detected */
|
||||
|
||||
* CIMR(regBase) &= (0xffffffff << (intNum + 1));
|
||||
|
||||
/* enable the CPM interrupt in the SIU controller */
|
||||
|
||||
* SIMASK(regBase) |= simaskLevel;
|
||||
|
||||
/* call the Interrupt Handler */
|
||||
|
||||
intrVecTable[intNum + 32].vec (intrVecTable[intNum + 32].arg);
|
||||
|
||||
/* clear the bit in the CISR */
|
||||
|
||||
* CISR(regBase) = (1 << intNum);
|
||||
|
||||
/* restore the interrupt mask */
|
||||
|
||||
* CIMR(regBase) = intOldMask;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ppc860IntEnable - enable one of the Level or IRQ interrupts into the SIU
|
||||
*
|
||||
* This routine will unmask the bit in the SIMASK register corresponding to
|
||||
* the requested interrupt level. The interrupt level must be in the range
|
||||
* of 0 - 31.
|
||||
*
|
||||
* RETURNS: 0, always.
|
||||
*/
|
||||
|
||||
LOCAL int ppc860IntEnable
|
||||
(
|
||||
int intNum /* interrupt level to enable (0 - 31) */
|
||||
)
|
||||
{
|
||||
UINT32 regBase;
|
||||
|
||||
regBase = vxImmrGet();
|
||||
if ((intNum >= 0) && (intNum < 32))
|
||||
* SIMASK(regBase) |= (1 << (31 - intNum));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ppc860IntDisable - Disable one of the Level or IRQ interrupts into the SIU
|
||||
*
|
||||
* This routine will mask the bit in the SIMASK register corresponding to
|
||||
* the requested interrupt level. The interrupt level must be in the range
|
||||
* of 0 - 31.
|
||||
*
|
||||
* RETURNS: 0, always.
|
||||
*/
|
||||
|
||||
LOCAL int ppc860IntDisable
|
||||
(
|
||||
int intNum /* interrupt level to disable (0 - 31) */
|
||||
)
|
||||
{
|
||||
UINT32 regBase;
|
||||
|
||||
regBase = vxImmrGet();
|
||||
if ((intNum >= 0) && (intNum < 32))
|
||||
* SIMASK(regBase) &= ~(1 << (31 - intNum));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,485 @@
|
||||
/* qeIntrCtl.c - Quicc Engine interrupt controller driver */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2009 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify, or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01e,09oct09,rgo Fix quicc interrupt range for both enable/disable func(
|
||||
CQ:156433 )
|
||||
01d,27aug08,jpb Renamed VSB header file
|
||||
01c,18jul08,kk added inclusion of private/vsbConfigP.h to pick up macros
|
||||
01b,14may08,jpb Modifications for source build. Renamed
|
||||
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
|
||||
01a,20sep07,z_l Fix interrupt number error(WIND00105278)
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
INCLUDE FILES: qeIntrCtl.h
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vsbConfig.h>
|
||||
#include <intLib.h>
|
||||
#include <iv.h>
|
||||
#include <drv/intrCtl/quiccIntrCtl.h>
|
||||
#include <drv/intrCtl/qeIntrCtl.h>
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
#include "private/funcBindP.h"
|
||||
#include "private/eventP.h"
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
/* defines */
|
||||
|
||||
#define QE_CIMR_MASK_GTEQ_L 0
|
||||
#define QE_CIMR_MASK_LTEQ_L 15
|
||||
#define QE_CIMR_MASK_GTEQ_U 32
|
||||
#define QE_CIMR_MASK_LTEQ_U 47
|
||||
#error "included"
|
||||
/* local */
|
||||
|
||||
LOCAL QE_INTR_HANDLER qeIntrVecTable[QE_IVEC_MAX+1]; /* Intr vector table */
|
||||
|
||||
/* SIU Interrupt Mask structure; a value for the high and low parts */
|
||||
typedef struct qe_siu_int_mask
|
||||
{
|
||||
UINT32 crimr;
|
||||
UINT32 cimr;
|
||||
} QE_SIU_INT_MASK;
|
||||
|
||||
/*
|
||||
* for now do not allow interruption of interrupt processing
|
||||
*/
|
||||
|
||||
LOCAL QE_SIU_INT_MASK qeEnableHighPriInts[] =
|
||||
{
|
||||
{0x00000000, 0x00000000}, /* interrupt 0 error - enable nothing */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000}, /* */
|
||||
{0x00000000, 0x00000000},
|
||||
{0x00000000, 0x00000000}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
LOCAL UINT32 qeINumToMaskPattern[] =
|
||||
{
|
||||
0x00000000, /* interrupt number 0: Error */
|
||||
0x00008000, /* interrupt number 1: I2C */
|
||||
0x00004000, /* interrupt number 2: SPI */
|
||||
0x00002000, /* interrupt number 3: Risc Timer Table */
|
||||
0x00000000, /* interrupt number 4: */
|
||||
0x00000000, /* interrupt number 5: */
|
||||
0x00000000, /* interrupt number 6: */
|
||||
0x00000000, /* interrupt number 7: */
|
||||
0x00000000, /* interrupt number 8: */
|
||||
0x00000000, /* interrupt number 9: */
|
||||
0x00000040, /* interrupt number 10: SDMA */
|
||||
0x00000020, /* interrupt number 11: USB */
|
||||
0x00000010, /* interrupt number 12: Timer 1 */
|
||||
0x00000008, /* interrupt number 13: Timer 2 */
|
||||
0x00000004, /* interrupt number 14: Timer 3 */
|
||||
0x00000002, /* interrupt number 15: Timer 4 */
|
||||
0x00000000, /* interrupt number 16: */
|
||||
0x00000000, /* interrupt number 17: */
|
||||
0x00000000, /* interrupt number 18: */
|
||||
0x00000000, /* interrupt number 19: */
|
||||
0x10000000, /* interrupt number 20: VT*/
|
||||
0x00000000, /* interrupt number 21: */
|
||||
0x00000000, /* interrupt number 22: */
|
||||
0x00000000, /* interrupt number 23: */
|
||||
0x00000000, /* interrupt number 24: */
|
||||
0x00800000, /* interrupt number 25: EXT1 */
|
||||
0x00400000, /* interrupt number 26: EXT2 */
|
||||
0x00200000, /* interrupt number 27: EXT3 */
|
||||
0x00100000, /* interrupt number 28: EXT4 */
|
||||
0x00000000, /* interrupt number 29: */
|
||||
0x00000000, /* interrupt number 30: */
|
||||
0x00000000, /* interrupt number 31: */
|
||||
0x80000000, /* interrupt number 32: UCC1 */
|
||||
0x40000000, /* interrupt number 33: UCC2 */
|
||||
0x20000000, /* interrupt number 34: UCC3 */
|
||||
0x10000000, /* interrupt number 35: UCC4 */
|
||||
0x08000000, /* interrupt number 36: MCC1 */
|
||||
0x00000000, /* interrupt number 37: */
|
||||
0x00000000, /* interrupt number 38: */
|
||||
0x00000000, /* interrupt number 39: */
|
||||
0x00800000, /* interrupt number 40: UCC5 */
|
||||
0x00400000, /* interrupt number 41: UCC6 */
|
||||
0x00200000, /* interrupt number 42: UCC7 */
|
||||
0x00100000, /* interrupt number 43: UCC8 */
|
||||
0x00000000, /* interrupt number 44: */
|
||||
0x00000000, /* interrupt number 45: */
|
||||
0x00000000, /* interrupt number 46: */
|
||||
0x00000000, /* interrupt number 47: */
|
||||
0x00000000, /* interrupt number 48: */
|
||||
0x00000000, /* interrupt number 49: */
|
||||
0x00000000, /* interrupt number 50: */
|
||||
0x00000000, /* interrupt number 51: */
|
||||
0x00000000, /* interrupt number 52: */
|
||||
0x00000000, /* interrupt number 53: */
|
||||
0x00000000, /* interrupt number 54: */
|
||||
0x00000000, /* interrupt number 55: */
|
||||
0x00000000, /* interrupt number 56: reserved */
|
||||
0x00000000, /* interrupt number 57: reserved */
|
||||
0x00000000, /* interrupt number 58: reserved */
|
||||
0x00000000, /* interrupt number 59: reserved */
|
||||
0x00000000, /* interrupt number 60: reserved */
|
||||
0x00000000, /* interrupt number 61: reserved */
|
||||
0x00000000, /* interrupt number 62: reserved */
|
||||
0x00000000 /* interrupt number 63: reserved */
|
||||
};
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
LOCAL void qeIntrDeMux (void);
|
||||
LOCAL STATUS qeIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
|
||||
LOCAL BOOL qeIntFirstTime = TRUE;
|
||||
|
||||
void qeDefaultISR(int vector)
|
||||
{
|
||||
logMsg("Spurious interrupt 0x%x\n",vector,0,0,0,0,0);
|
||||
}
|
||||
|
||||
BOOL qeTest1=0;
|
||||
|
||||
BOOL qeTest2=0;
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* qeIntrInit - initialize the interrupt manager for the PowerPC 8260
|
||||
*
|
||||
* This routine connects the default demultiplexer, qeIntrDeMux(), to the
|
||||
* external interrupt vector and associates all
|
||||
* interrupt sources with the default interrupt handler. This routine is
|
||||
* called by sysHwInit() in sysLib.c.
|
||||
*
|
||||
* NOTE: All interrupt from the SIU unit are enabled, CICR is setup so
|
||||
* that SCC1 has the highest relative interrupt priority, through SCC4 with the
|
||||
* lowest.
|
||||
*
|
||||
* RETURN : OK always
|
||||
*/
|
||||
|
||||
STATUS qeIntrInit
|
||||
(
|
||||
)
|
||||
{
|
||||
VOIDFUNCPTR defaultVec; /* INTR3 default vector */
|
||||
int vector;
|
||||
|
||||
|
||||
/* Get the default vector connected to the External Interrupt (0x500) */
|
||||
|
||||
defaultVec = qeDefaultISR;
|
||||
|
||||
/* disable all interrupts */
|
||||
*QE_CIMR(CCSBAR) = 0x00000000;
|
||||
*QE_CRIMR(CCSBAR) = 0x00000000;
|
||||
|
||||
/* Set all vectors to default handler */
|
||||
|
||||
memset (qeIntrVecTable,0,(sizeof(QE_INTR_HANDLER) * QE_IVEC_MAX));
|
||||
|
||||
/* Set all vectors to default handler */
|
||||
for (vector = 0; vector < QE_IVEC_MAX; vector++)
|
||||
qeIntConnect ((VOIDFUNCPTR*)vector, (VOIDFUNCPTR) defaultVec, 0);
|
||||
|
||||
|
||||
return (OK);
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* qeIntConnect - connect a routine to an interrupt
|
||||
*
|
||||
* This routine connects any C or assembly routine to one of the multiple
|
||||
* sources of interrupts.
|
||||
*
|
||||
* The connected routine can be any normal C code, except that it must not
|
||||
* invoke certain operating system functions that may block or perform I/O
|
||||
* operations.
|
||||
*
|
||||
* <vector> types are defined in h/drv/intrClt/qeIntr.h.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if <vector> is unknown.
|
||||
*
|
||||
* SEE ALSO: qeIntr.h
|
||||
*/
|
||||
|
||||
LOCAL STATUS qeIntConnect
|
||||
(
|
||||
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
|
||||
VOIDFUNCPTR routine, /* routine to be called */
|
||||
int parameter /* parameter to be passed to routine */
|
||||
)
|
||||
{
|
||||
|
||||
if ((int)(vector) >= QE_IVEC_MAX)
|
||||
return (ERROR);
|
||||
|
||||
|
||||
/* test the vector */
|
||||
|
||||
if(qeIntFirstTime)
|
||||
{
|
||||
intConnect((VOIDFUNCPTR*)INUM_QE_HIGH,qeIntrDeMux,0);
|
||||
intConnect((VOIDFUNCPTR*)INUM_QE_LOW,qeIntrDeMux,0);
|
||||
intEnable(INUM_QE_HIGH);
|
||||
intEnable(INUM_QE_LOW);
|
||||
qeIntFirstTime=FALSE;
|
||||
}
|
||||
|
||||
|
||||
qeIntrVecTable[(int)(vector)].vec = routine;
|
||||
qeIntrVecTable[(int)(vector)].arg = parameter;
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* qeIntrDeMux - SIU interrupt demultiplexer
|
||||
*
|
||||
* This routine must be bound to external interrupt exception (vector 0x500).
|
||||
* It is used to call the appropriate handler with its argument when an
|
||||
* interrupt occurs.
|
||||
*
|
||||
* The interrupts are prioritized in the following order:
|
||||
*
|
||||
* NOTE: when this function is called the interrupts are still locked. It's
|
||||
* this function responsability to unlock the interrupt.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
LOCAL void qeIntrDeMux (void)
|
||||
{
|
||||
VINT32 intVec; /* interrupt vector */
|
||||
UINT32 oldIntMask_L; /* current interrupt mask */
|
||||
UINT32 oldIntMask_H; /* current interrupt mask */
|
||||
UINT32 intLevel = _PPC_MSR_EE;
|
||||
|
||||
/* read the interrupt vector register */
|
||||
intVec = (0x0000003f & *QE_CIVEC(CCSBAR));
|
||||
|
||||
*(VUINT32*)(0x3000) = intVec;
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
WV_EVT_INT_ENT(intVec)
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
if ( intVec != 0 )
|
||||
{
|
||||
/* save the current interrupt mask */
|
||||
|
||||
oldIntMask_L = * QE_CIMR(CCSBAR);
|
||||
oldIntMask_H = * QE_CRIMR(CCSBAR);
|
||||
|
||||
/* enable only the higher priority interrupts */
|
||||
|
||||
* QE_CIMR(CCSBAR)&=
|
||||
qeEnableHighPriInts[QE_IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].cimr;
|
||||
* QE_CRIMR(CCSBAR)&=
|
||||
qeEnableHighPriInts[QE_IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].crimr;
|
||||
|
||||
intUnlock (_PPC_MSR_EE);
|
||||
|
||||
/* call the Interrupt Handler */
|
||||
|
||||
/* table is indexed by vector */
|
||||
|
||||
qeIntrVecTable[intVec].vec (qeIntrVecTable[intVec].arg);
|
||||
|
||||
|
||||
/* restore the interrupt mask */
|
||||
intLevel = intLock ();
|
||||
|
||||
/* restore the interrupt mask */
|
||||
|
||||
* QE_CIMR(CCSBAR) = oldIntMask_L;
|
||||
* QE_CRIMR(CCSBAR) = oldIntMask_H;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
/*******************************************************************************
|
||||
*
|
||||
* qeIntEnable - enable the indicated interrupt
|
||||
*
|
||||
* This routine will enable the indicated interrupt by setting the appropriate
|
||||
* bit in the SIU Interrupt Mask Registers.
|
||||
*
|
||||
* The design of the 8260 presents the following design requirements:
|
||||
*
|
||||
* 1. the mapping from interrupt number to mask bit can not be represented by
|
||||
* a function. An array, indexed by interrupt number (QE_INUM), is used to map
|
||||
* the interrupt number to the appropriate mask.
|
||||
*
|
||||
* 2. There are two 32 bit mask registers (CIMR and CRIMR). The interrupt
|
||||
* number must be compared to 4 ranges to determine which register contains
|
||||
* its mask bit:
|
||||
*
|
||||
* .CS
|
||||
* interrupt number
|
||||
* in qeIntrCtl.h register
|
||||
* ---------------- -------
|
||||
* 0-15 CIMR
|
||||
* 16-31 CRIMR
|
||||
* 32-47 CIMR
|
||||
* 48-63 CRIMR
|
||||
* .CE
|
||||
*
|
||||
* RETURNS: 0, always.
|
||||
*/
|
||||
|
||||
int qeIntEnable
|
||||
(
|
||||
int intNum /* interrupt level to enable */
|
||||
)
|
||||
{
|
||||
|
||||
if ((intNum > 0) && (intNum <= QE_IVEC_MAX))
|
||||
{
|
||||
if (((intNum >= QE_CIMR_MASK_GTEQ_L) && (intNum <= QE_CIMR_MASK_LTEQ_L)) ||
|
||||
((intNum >= QE_CIMR_MASK_GTEQ_U) && (intNum <= QE_CIMR_MASK_LTEQ_U)))
|
||||
*QE_CIMR(CCSBAR) |= qeINumToMaskPattern[intNum];
|
||||
else
|
||||
*QE_CRIMR(CCSBAR) |= qeINumToMaskPattern[intNum];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* qeIntDisable - Disable one of the Level or IRQ interrupts into the SIU
|
||||
*
|
||||
* This routine will mask the bit in the SIMASK register corresponding to
|
||||
* the requested interrupt level.
|
||||
*
|
||||
* RETURNS: 0, always.
|
||||
*/
|
||||
|
||||
int qeIntDisable
|
||||
(
|
||||
int intNum /* interrupt level to disable */
|
||||
)
|
||||
{
|
||||
|
||||
if ((intNum >= 0) && (intNum <= QE_IVEC_MAX))
|
||||
{
|
||||
if (((intNum >= QE_CIMR_MASK_GTEQ_L) && (intNum <= QE_CIMR_MASK_LTEQ_L)) ||
|
||||
((intNum >= QE_CIMR_MASK_GTEQ_U) && (intNum <= QE_CIMR_MASK_LTEQ_U)))
|
||||
*QE_CIMR(CCSBAR) &= ~qeINumToMaskPattern[intNum];
|
||||
else
|
||||
*QE_CRIMR(CCSBAR) &= ~qeINumToMaskPattern[intNum];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
VOIDFUNCPTR * qeInumToIvec
|
||||
(
|
||||
int intNum
|
||||
)
|
||||
{
|
||||
|
||||
return((void*)intNum);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* qeIvecToInum - get the relevant interrupt number
|
||||
*
|
||||
* This routine finds out the interrupt number associated with the vector
|
||||
* in <vector>.
|
||||
*
|
||||
* <vector> types are defined in h/drv/intrClt/qeIntr.h.
|
||||
*
|
||||
* RETURNS: the interrupt number for the vector
|
||||
*
|
||||
* SEE ALSO: qeIntr.h
|
||||
*/
|
||||
|
||||
int qeIvecToInum
|
||||
(
|
||||
VOIDFUNCPTR * vector /* interrupt vector to attach to */
|
||||
)
|
||||
{
|
||||
return ((int)vector);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,721 @@
|
||||
/* quiccIntrCtl.c - Motorola MPC 83XX interrupt controller driver */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005-2009, 2011, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01l,13jun13,d_l restore TSECn interrupt priority. (WIND00414331)
|
||||
01k,19may11,swu Fix interrupt mask enableHighPriInts[].(WIND00270355)
|
||||
01j,05feb09,jc0 removed internal interrupt acknowledge which does no effect
|
||||
01i,07jan09,jc0 fix WIND00148619
|
||||
01h,27aug08,jpb Renamed VSB header file
|
||||
01g,18jul08,kk added inclusion of private/vsbConfigP.h to pick up macros
|
||||
01f,14may08,jpb Modifications for source build. Renamed
|
||||
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
|
||||
01e,05sep07,dtr WIND0092393 - Fix GTM masks.
|
||||
01d,21mar06,mdo Fix overrun of array
|
||||
01d,25may06,dtr Add support for 8360 processor.
|
||||
01c,16may05,dtr IRQ0 mask in wrong vector - SPR 109357.
|
||||
01b,19apr05,dtr Fix mask for USB - SPR 108220.
|
||||
01a,10jan05,dtr adapted from m8260IntrCtl.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
The PowerPC 83XX CPU is divided in three units: PowerPC core, System
|
||||
Interface Unit (SIU) and Communication Engine (CE). The PowerPC
|
||||
core accepts only one external interrupt exception (vector 0x500). The SIU
|
||||
provides an interrupt controller which provides 92 interrupt sources
|
||||
The Interrupt controller is connected to the PowerPC core external
|
||||
interrupt. This library provides the routines to manage this interrupt
|
||||
controllers.
|
||||
|
||||
quiccIntrInit() connects the default demultiplexer, quiccIntrDeMux(), to the
|
||||
external interrupt vector and initializes a table containing a function pointer
|
||||
and an associated parameter for each interrupt source. quiccIntrInit() is called
|
||||
by sysHwInit() from sysLib.c.
|
||||
|
||||
The default demultimplexer, quiccIntrDeMux() detects which peripheral or
|
||||
controller has raised an interrupt and calls the associated routine with its
|
||||
parameter.
|
||||
|
||||
INCLUDE FILES: quiccIntrCtl.h
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vsbConfig.h>
|
||||
#include <intLib.h>
|
||||
#include <iv.h>
|
||||
#include <drv/intrCtl/quiccIntrCtl.h>
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
#include <private/funcBindP.h>
|
||||
#include <private/eventP.h>
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
/* local */
|
||||
|
||||
INTR_HANDLER intrVecTable[IVEC_MAX+1]; /* Intr vector table */
|
||||
|
||||
/* SIU Interrupt Mask structure; a value for the high and low parts */
|
||||
typedef struct siu_int_mask
|
||||
{
|
||||
UINT32 simr_h;
|
||||
UINT32 simr_l;
|
||||
UINT32 semr;
|
||||
} SIU_INT_MASK;
|
||||
|
||||
/*
|
||||
* For a give inum, return a pair of masks, one for SIMR_H and one for SIMR_L,
|
||||
* which enables only higher priority interrupts.
|
||||
*/
|
||||
|
||||
LOCAL SIU_INT_MASK enableHighPriInts[] =
|
||||
{
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* interrupt 0 error - enable nothing */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0xFF000000, 0xFF000000, 0xFF000000}, /* UART1 */
|
||||
{0xFF000080, 0xFF000000, 0xFF000000}, /* UART2 */
|
||||
{0xFF0000C0, 0xFF000000, 0xFF000000}, /* SEC */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0xFF0000E0, 0xFF000000, 0xFF000000}, /* I2C1 */
|
||||
{0xFF0000E4, 0xFF000000, 0xFF000000}, /* I2C2 */
|
||||
{0xFF0000E6, 0xFF000000, 0xFF000000}, /* SPI */
|
||||
{0xFF000000, 0xFF000000, 0x80000000}, /* IRQ1 */
|
||||
{0xFF000000, 0xFF000000, 0xC0000000}, /* IRQ2 */
|
||||
{0xFF000000, 0xFF000000, 0xE0000000}, /* IRQ3 */
|
||||
{0xFF000000, 0xFF000000, 0xF0000000}, /* IRQ4 */
|
||||
{0xFF000000, 0xFF000000, 0xF8000000}, /* IRQ5 */
|
||||
{0xFF000000, 0xFF000000, 0xFC000000}, /* IRQ6 */
|
||||
{0xFF000000, 0xFF000000, 0xFE000000}, /* IRQ7 **23**/
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
#ifndef QUICC_ENGINE
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* TSEC1 Tx */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* TSEC1 Rx */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* TSEC1 Err */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* TSEC2 Tx */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* TSEC2 Rx */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* TSEC2 Err */
|
||||
#else
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* QE HOGH */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* QE LOW */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved*/
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
#endif /* !QUICC_ENGINE */
|
||||
{0xFC000000, 0xFF000000, 0x00000000}, /* USB2 DR */
|
||||
{0xFE000000, 0xFF000000, 0x00000000}, /* USB2 MPH */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0xFF000000, 0xFF000000, 0x00000000}, /* IRQ0 ***48**/
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* RTC SEC */
|
||||
{0x00000000, 0x80000000, 0x00000000}, /* PIT */
|
||||
{0x00000000, 0xC0000000, 0x00000000}, /* PCI1 */
|
||||
#ifndef QUICC_ENGINE
|
||||
{0x00000000, 0xE0000000, 0x00000000}, /* PCI2 */
|
||||
#else
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
#endif /* !QUICC_ENGINE */
|
||||
{0x00000000, 0xF0000000, 0x00000000}, /* RTC ALR */
|
||||
{0x00000000, 0xF8000000, 0x00000000}, /* MU */
|
||||
{0x00000000, 0xFC000000, 0x00000000}, /* SBA */
|
||||
{0x00000000, 0xFE000000, 0x00000000}, /* DMA */
|
||||
{0xFF0000E7, 0xFF000000, 0xFF000000}, /* GTM4 */
|
||||
{0xFF0000E7, 0xFF800000, 0xFF000000}, /* GTM8 */
|
||||
{0xFF0000E7, 0xFFC00000, 0xFF000000}, /* CPIO1 */
|
||||
{0xFF0000E7, 0xFFE00000, 0xFF000000}, /* GPIO2 */
|
||||
{0xFF0000E7, 0xFFF00000, 0xFF000000}, /* DDR */
|
||||
{0xFF0000E7, 0xFFF80000, 0xFF000000}, /* LBC */
|
||||
{0xFF0000E7, 0xFFFC0000, 0xFF000000}, /* GTM2 */
|
||||
{0xFF0000E7, 0xFFFE0000, 0xFF000000}, /* GTM6 */
|
||||
{0xFF0000E7, 0xFFFF0000, 0xFF000000}, /* PMC */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0xFF0000E7, 0xFFFF8000, 0xFF000000}, /* GTM3 */
|
||||
{0xFF0000E7, 0xFFFF8800, 0xFF000000}, /* GTM7 */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0xFF0000E7, 0xFFFF8C00, 0xFF000000}, /* GTM1 */
|
||||
{0xFF0000E7, 0xFFFF8C20, 0xFF000000}, /* GTM5 */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
|
||||
{0x00000000, 0x00000000, 0x00000000} /* Reserved */
|
||||
};
|
||||
|
||||
|
||||
|
||||
LOCAL UINT32 iNumToMaskPattern[] =
|
||||
{
|
||||
0x00000000, /* interrupt number 0: Error */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000080, /* UART1 */
|
||||
0x00000040, /* UART2 */
|
||||
0x00000020, /* SEC */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000004, /* I2C1 */
|
||||
0x00000002, /* I2C2 */
|
||||
0x00000001, /* SPI */
|
||||
0x40000000, /* IRQ1 */
|
||||
0x20000000, /* IRQ2 */
|
||||
0x10000000, /* IRQ3 */
|
||||
0x08000000, /* IRQ4 */
|
||||
0x04000000, /* IRQ5 */
|
||||
0x02000000, /* IRQ6 */
|
||||
0x01000000, /* IRQ7 **23**/
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x80000000, /* TSEC1 Tx */
|
||||
0x40000000, /* TSEC1 Rx */
|
||||
0x20000000, /* TSEC1 Err */
|
||||
0x10000000, /* TSEC2 Tx */
|
||||
0x08000000, /* TSEC2 Rx */
|
||||
0x04000000, /* TSEC2 Err */
|
||||
0x02000000, /* USB2 DR */
|
||||
0x01000000, /* USB2 MPH */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x80000000, /* IRQ0 ***48**/
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x80000000, /* RTC SEC */
|
||||
0x40000000, /* PIT */
|
||||
0x20000000, /* PCI1 */
|
||||
0x10000000, /* PCI2 */
|
||||
0x08000000, /* RTC ALR */
|
||||
0x04000000, /* MU */
|
||||
0x02000000, /* SBA */
|
||||
0x01000000, /* DMA */
|
||||
0x00800000, /* GTM4 */
|
||||
0x00400000, /* GTM8 */
|
||||
0x00200000, /* CPIO1 */
|
||||
0x00100000, /* GPIO2 */
|
||||
0x00080000, /* DDR */
|
||||
0x00040000, /* LBC */
|
||||
0x00020000, /* GTM2 */
|
||||
0x00010000, /* GTM6 */
|
||||
0x00008000, /* PMC */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000800, /* GTM3 */
|
||||
0x00000400, /* GTM7 */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000020, /* GTM1 */
|
||||
0x00000010, /* GTM5 */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000, /* Reserved */
|
||||
0x00000000 /* Reserved */
|
||||
};
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
LOCAL void quiccIntrDeMux (void);
|
||||
LOCAL STATUS quiccIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
|
||||
LOCAL VOIDFUNCPTR defaultVec; /* INTR3 default vector */
|
||||
|
||||
void defaultISR(int vector)
|
||||
{
|
||||
logMsg("Spurious interrupt 0x%x\n",vector,0,0,0,0,0);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* quiccIntrInit - initialize the interrupt manager for the PowerPC 83XX
|
||||
*
|
||||
* This routine connects the default demultiplexer, quiccIntrDeMux(), to the
|
||||
* external interrupt vector and associates all
|
||||
* interrupt sources with the default interrupt handler. This routine is
|
||||
* called by sysHwInit() in sysLib.c.
|
||||
*
|
||||
* NOTE: All interrupt from the SIU unit are enabled, CICR is setup so
|
||||
* that SCC1 has the highest relative interrupt priority, through SCC4 with the
|
||||
* lowest.
|
||||
*
|
||||
* RETURNS: OK always
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
STATUS quiccIntrInit (void)
|
||||
{
|
||||
int vector;
|
||||
|
||||
/* Get the default vector connected to the External Interrupt (0x500) */
|
||||
|
||||
defaultVec = defaultISR;
|
||||
|
||||
/* Connect the interrupt demultiplexer to External Interrupt (0x500) */
|
||||
|
||||
excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, quiccIntrDeMux);
|
||||
|
||||
#ifndef USE_MUX_LAYER
|
||||
/* Install `system' intConnect routine */
|
||||
|
||||
if (_func_intConnectRtn == NULL)
|
||||
_func_intConnectRtn = quiccIntConnect;
|
||||
|
||||
if (_func_intEnableRtn == NULL)
|
||||
_func_intEnableRtn = quiccIntEnable;
|
||||
|
||||
if (_func_intDisableRtn == NULL)
|
||||
_func_intDisableRtn = quiccIntDisable;
|
||||
#endif /* !USE_MUX_LAYER */
|
||||
/* Set all vectors to default handler */
|
||||
|
||||
memset (intrVecTable,0,(sizeof(INTR_HANDLER) * (IVEC_MAX + 1)));
|
||||
|
||||
|
||||
for (vector = 0; vector <= IVEC_MAX; vector++)
|
||||
quiccIntConnect (INUM_TO_IVEC(vector), (VOIDFUNCPTR) defaultVec, vector);
|
||||
|
||||
/* disable all interrupts */
|
||||
*QUICC_SIMR_L(CCSBAR) = 0x00000000;
|
||||
*QUICC_SIMR_H(CCSBAR) = 0x00000000;
|
||||
*QUICC_SEMSR(CCSBAR) = 0x00000000;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* quiccIntConnect - connect a routine to an interrupt
|
||||
*
|
||||
* This routine connects any C or assembly routine to one of the multiple
|
||||
* sources of interrupts.
|
||||
*
|
||||
* The connected routine can be any normal C code, except that it must not
|
||||
* invoke certain operating system functions that may block or perform I/O
|
||||
* operations.
|
||||
*
|
||||
* <vector> types are defined in h/drv/intrClt/quiccIntr.h.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if <vector> is unknown or memory can't be allocated.
|
||||
*
|
||||
* ERRNO
|
||||
*
|
||||
* SEE ALSO: quiccIntr.h
|
||||
*/
|
||||
|
||||
LOCAL STATUS quiccIntConnect
|
||||
(
|
||||
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
|
||||
VOIDFUNCPTR routine, /* routine to be called */
|
||||
int parameter /* parameter to be passed to routine */
|
||||
)
|
||||
{
|
||||
|
||||
/* test the vector */
|
||||
|
||||
if ((int)(vector) > IVEC_MAX)
|
||||
return(ERROR);
|
||||
|
||||
if ((intrVecTable[(int)(vector)].vec == defaultVec) ||
|
||||
(intrVecTable[(int)(vector)].vec == NULL))
|
||||
{
|
||||
intrVecTable[(int)(vector)].vec = routine;
|
||||
intrVecTable[(int)(vector)].arg = parameter;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (intrVecTable[(int)(vector)].pNext!=NULL)
|
||||
{
|
||||
INTR_HANDLER *temp1Next,*temp2Next;
|
||||
|
||||
temp2Next = (INTR_HANDLER*)intrVecTable[(int)(vector)].pNext;
|
||||
temp1Next = (INTR_HANDLER*)intrVecTable[(int)(vector)].pNext;
|
||||
|
||||
while (temp1Next !=NULL)
|
||||
{
|
||||
temp2Next = temp1Next;
|
||||
temp1Next = (INTR_HANDLER*)temp2Next->pNext;
|
||||
}
|
||||
|
||||
temp2Next->pNext = (void*)malloc (sizeof(INTR_HANDLER));
|
||||
if (temp2Next->pNext == NULL)
|
||||
return(ERROR);
|
||||
((INTR_HANDLER*)temp2Next->pNext)->vec = routine;
|
||||
((INTR_HANDLER*)temp2Next->pNext)->arg = parameter;
|
||||
}
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* quiccIntrDeMux - SIU interrupt demultiplexer
|
||||
*
|
||||
* This routine must be bound to external interrupt exception (vector 0x500).
|
||||
* It is used to call the appropriate handler with its argument when an
|
||||
* interrupt occurs.
|
||||
*
|
||||
* The interrupts are prioritized in the following order:
|
||||
*
|
||||
* NOTE: when this function is called the interrupts are still locked. It's
|
||||
* this function responsibility to unlock the interrupt.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
LOCAL void quiccIntrDeMux (void)
|
||||
{
|
||||
VINT32 intVec; /* interrupt vector */
|
||||
UINT32 oldIntMask_L; /* current interrupt mask */
|
||||
UINT32 oldIntMask_H; /* current interrupt mask */
|
||||
UINT32 oldIntMask_E; /* current interrupt mask */
|
||||
|
||||
/* read the interrupt vector register */
|
||||
|
||||
intVec = (0x0000007f & (*QUICC_SIVEC(CCSBAR)));
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
WV_EVT_INT_ENT(intVec)
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
if ( intVec != 0 )
|
||||
{
|
||||
/* save the current interrupt mask */
|
||||
|
||||
oldIntMask_L = * QUICC_SIMR_L(CCSBAR);
|
||||
oldIntMask_H = * QUICC_SIMR_H(CCSBAR);
|
||||
oldIntMask_E = * QUICC_SEMSR(CCSBAR);
|
||||
|
||||
/* enable only the higher priority interrupts */
|
||||
|
||||
* QUICC_SIMR_L(CCSBAR) = oldIntMask_L &
|
||||
enableHighPriInts[IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].simr_l;
|
||||
* QUICC_SIMR_H(CCSBAR) = oldIntMask_H &
|
||||
enableHighPriInts[IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].simr_h;
|
||||
* QUICC_SEMSR(CCSBAR) = oldIntMask_E &
|
||||
enableHighPriInts[IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].semr;
|
||||
|
||||
/* ensure the interrupt mask registers are updated */
|
||||
|
||||
_WRS_ASM ("eieio");
|
||||
|
||||
intUnlock (_PPC_MSR_EE);
|
||||
|
||||
/* call the Interrupt Handler */
|
||||
|
||||
/* table is indexed by vector */
|
||||
|
||||
intrVecTable[intVec].vec (intrVecTable[intVec].arg);
|
||||
|
||||
if (intrVecTable[intVec].pNext !=NULL)
|
||||
{
|
||||
INTR_HANDLER *pNext;
|
||||
pNext = (INTR_HANDLER*)intrVecTable[intVec].pNext;
|
||||
while (pNext !=NULL)
|
||||
{
|
||||
pNext->vec (pNext->arg);
|
||||
pNext = (INTR_HANDLER*)pNext->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ((intVec >= 17) && (intVec <= 23)) || (intVec == 48) )
|
||||
{
|
||||
*QUICC_SEPNR(CCSBAR) = iNumToMaskPattern[intVec] ;
|
||||
}
|
||||
|
||||
/* restore the interrupt mask */
|
||||
|
||||
intLock ();
|
||||
|
||||
* QUICC_SIMR_L(CCSBAR) = oldIntMask_L;
|
||||
* QUICC_SIMR_H(CCSBAR) = oldIntMask_H;
|
||||
* QUICC_SEMSR(CCSBAR) = oldIntMask_E;
|
||||
|
||||
/*
|
||||
* Ensure the external interrupt is acknowledged and the
|
||||
* interrupt mask registers are restored.
|
||||
*/
|
||||
|
||||
_WRS_ASM ("eieio");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
*
|
||||
* quiccIntEnable - enable the indicated interrupt
|
||||
*
|
||||
* This routine will enable the indicated interrupt by setting the appropriate
|
||||
* bit in the SIU Interrupt Mask Registers.
|
||||
*
|
||||
* The design of the 83XX presents the following design requirements:
|
||||
*
|
||||
* 1. the mapping from interrupt number to mask bit can not be represented by
|
||||
* a function. An array, indexed by interrupt number (INUM), is used to map
|
||||
* the interrupt number to the appropriate mask.
|
||||
*
|
||||
* 2. There are two 32 bit mask registers (SIMR_L and SIMR_H). The interrupt
|
||||
* number must be compared to 4 ranges to determine which register contains
|
||||
* its mask bit:
|
||||
*
|
||||
* \cs
|
||||
* interrupt number
|
||||
* in quiccIntrCtl.h register
|
||||
* ---------------- -------
|
||||
* 0-15 SIMR_L
|
||||
* 16-31 SIMR_H
|
||||
* 32-47 SIMR_L
|
||||
* 48-63 SIMR_H
|
||||
* \ce
|
||||
*
|
||||
* RETURNS: 0, always.
|
||||
*/
|
||||
|
||||
int quiccIntEnable
|
||||
(
|
||||
int intNum /* interrupt level to enable */
|
||||
)
|
||||
{
|
||||
if ((intNum >= 0) && (intNum < IVEC_MAX))
|
||||
{
|
||||
if ((intNum >= 64) && (intNum < 128))
|
||||
*QUICC_SIMR_L(CCSBAR) |= iNumToMaskPattern[intNum];
|
||||
else
|
||||
{
|
||||
if ( ((intNum>=17) && (intNum<=31)) || (intNum == 48))
|
||||
{
|
||||
/* Use as external Mask */
|
||||
*QUICC_SEMSR(CCSBAR) |= iNumToMaskPattern[intNum];
|
||||
}
|
||||
else
|
||||
{
|
||||
*QUICC_SIMR_H(CCSBAR) |= iNumToMaskPattern[intNum];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* quiccIntDisable - Disable one of the Level or IRQ interrupts into the SIU
|
||||
*
|
||||
* This routine will mask the bit in the SIMASK register corresponding to
|
||||
* the requested interrupt level.
|
||||
*
|
||||
* RETURNS: 0, always.
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
int quiccIntDisable
|
||||
(
|
||||
int intNum /* interrupt level to disable */
|
||||
)
|
||||
{
|
||||
if ((intNum >= 0) && (intNum < IVEC_MAX))
|
||||
{
|
||||
if ((intNum >= 64) && (intNum < 128))
|
||||
*QUICC_SIMR_L(CCSBAR) &= ~iNumToMaskPattern[intNum];
|
||||
else
|
||||
{
|
||||
if ( ((intNum>=17) && (intNum<=31)) || (intNum == 48))
|
||||
{
|
||||
/* Use as external Mask */
|
||||
*QUICC_SEMSR(CCSBAR) &= ~iNumToMaskPattern[intNum];
|
||||
}
|
||||
else
|
||||
{
|
||||
*QUICC_SIMR_H(CCSBAR) &= ~iNumToMaskPattern[intNum];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
VOIDFUNCPTR * quiccInumToIvec
|
||||
(
|
||||
int intNum
|
||||
)
|
||||
{
|
||||
|
||||
return ((VOIDFUNCPTR *) intNum);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* quiccIvecToInum - get the relevant interrupt number
|
||||
*
|
||||
* This routine finds out the interrupt number associated with the vector
|
||||
* in <vector>.
|
||||
*
|
||||
* <vector> types are defined in h/drv/intrClt/quiccIntr.h.
|
||||
*
|
||||
* RETURNS: the interrupt number for the vector
|
||||
*
|
||||
* ERRNO
|
||||
*
|
||||
* SEE ALSO: quiccIntr.h
|
||||
*/
|
||||
|
||||
int quiccIvecToInum
|
||||
(
|
||||
VOIDFUNCPTR * vector /* interrupt vector to attach to */
|
||||
)
|
||||
{
|
||||
|
||||
/* test the vector */
|
||||
|
||||
return ((int) vector);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,422 @@
|
||||
/* templateIntrCtl.c - template interrupt controller driver */
|
||||
|
||||
/* Copyright 1984-1997, Wind River Systems, Inc. */
|
||||
|
||||
/*
|
||||
TODO - Remove the template modification history and begin a new history
|
||||
starting with version 01a and growing the history upward with
|
||||
each revision.
|
||||
|
||||
modification history
|
||||
--------------------
|
||||
01e,23nov97,dat suggestions from Chris and arm code review.
|
||||
01d,12aug97,dat more suggestions from Chris
|
||||
01c,05aug97,dat suggestions from Chris Partington at CSD.
|
||||
01b,06may97,dat added more documentation
|
||||
01a,03apr97,dat written
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO - This is a template driver for an interrupt controller. Each hardware
|
||||
dependent function, variable, or macro name begins with TEMPLATE or template.
|
||||
These names should be changed to a name based upon the final module name.
|
||||
|
||||
TODO - If this device is a sub-section of a larger device, describe the
|
||||
entire larger device in one paragraph.
|
||||
|
||||
TODO - Describe this device including all possible operating modes and
|
||||
limitations.
|
||||
|
||||
TODO - Describe the device modes and any limitations applicable to this driver.
|
||||
If this driver interacts with any other driver describe that interaction.
|
||||
|
||||
TODO - Update the remainder of this documentation as appropriate.
|
||||
|
||||
This template driver presents a standard interface between the architecture
|
||||
level interrupt system, and the BSP and hardware level functions. One
|
||||
purpose of this interface model is to make it easy for BSPs to use standard
|
||||
interrupt controller devices in both simple and complex situations. Previous
|
||||
interfaces assumed that the device driver would be the only device in the
|
||||
system. We need more flexibility than that. This model allows the BSP
|
||||
to provide complex wrapper functions around any of the hardware level
|
||||
routines supporting the architecture level functions (see templateIntr.c).
|
||||
|
||||
In a simple system with only one controller device, the BSP would initialize
|
||||
the single device. The driver will attach itself to the sysIntLvlXXX
|
||||
entry points used by the higher level functions to call the hardware layer.
|
||||
Nothing else would be needed by such a simple BSP.
|
||||
|
||||
In a complex system the BSP would initialize all the controller devices
|
||||
individually. It would then declare a special version of each function
|
||||
and install those special versions into the entry point variables. An
|
||||
example would be a system using 8259's for ISA bus interrupts and had a
|
||||
separate device for handling VMEbus interrupts. The BSP would initialize
|
||||
the two individual drivers. For each hardware function, sysIntLvlXXX,
|
||||
the BSP would create a routine that would interact with both drivers
|
||||
as needed. This new wrapper routine would be installed as the actual
|
||||
sysIntLvlXXX routine that is called from the architecture layer.
|
||||
|
||||
In this template driver, priority level 0 is lowest, and priority level
|
||||
16 is the highest. A priority level of 0 indicates all 16 levels enabled.
|
||||
|
||||
The order of interrupt level is undefined at the architecture level.
|
||||
Whether it goes upward from 0 to 16, or downward is immaterial. We presume
|
||||
that the BSP will define the necessary level numbers and will enable them
|
||||
individually as needed. The architecture should take no notice of their
|
||||
numeric values per se.
|
||||
|
||||
If the hardware device implements a different scheme from above,
|
||||
then some of the logic of this template driver will have to be changed
|
||||
to reflect lower numeric values representing higher priority levels.
|
||||
|
||||
The template chip has a TEMPLATE_CSR_ENB register where each bit enables
|
||||
a specific level, the bit pattern 0x1 enables interrupt level 1, the lowest
|
||||
level real interrupt. Level 0 is artificial and indicates all levels
|
||||
enabled. Level 16 is the highest level, and all levels are disabled.
|
||||
|
||||
Not all devices will support individual interrupt level enabling. If that
|
||||
is the case, then templateLvlEnable() should always return OK, and
|
||||
templateLvlDisable() should always return ERROR.
|
||||
|
||||
We presume that config.h or <bsp>.h has defined the addresses of the
|
||||
template chips registers: TEMPLATE_CSR_PEND, TEMPLATE_CSR_ENB, and
|
||||
TEMPLATE_CSR_ACK. This template code presumes that the chip is memory
|
||||
mapped and does direct memory accesses to the registers. If a different
|
||||
access method is needed, the BSP can redefine the macros
|
||||
TEMPLATE_REG_READ(addr,result) and TEMPLATE_REG_WRITE(addr,data).
|
||||
|
||||
This template chip driver presumes that interrupt vector numbers are
|
||||
calculated and not the result of a special cycle on the bus. Vector
|
||||
numbers are generated by adding the current interrupt level number to
|
||||
TEMPLATE_VEC_BASE to generate a vector number which the architecture
|
||||
level will use to invoke the proper handling routine. If a different
|
||||
mapping scheme, or a special hardware routine is needed, then the BSP
|
||||
should redefine the macro TEMPLATE_LVL_VEC_MAP(level,vector).
|
||||
|
||||
This driver was designed to support a single instance of a real device.
|
||||
At some point it should be upgraded to operate on an object model and to
|
||||
support any number of real devices.
|
||||
|
||||
The BSP will initialize this driver in sysHwInit2(), after initializing
|
||||
the main interrupt library, usually intLibInit(). The initialization
|
||||
routine, templateDevInit() will setup the interrupt controller device,
|
||||
it will mask off all individual interrupt sources and then set the
|
||||
interrupt level to enable all interrupts. See templateDevInit
|
||||
for more information.
|
||||
|
||||
All of the functions in this library are global. This allows them to be
|
||||
used by the BSP if it is necessary to create wrapper routines or to
|
||||
incorporate several drivers together as one.
|
||||
*/
|
||||
|
||||
#include "vxWorks.h"
|
||||
#include "config.h"
|
||||
|
||||
/*
|
||||
* TODO - These declarations should come from an architecture level
|
||||
* header file
|
||||
*/
|
||||
|
||||
IMPORT FUNCPTR sysIntLvlVecChkRtn;
|
||||
IMPORT FUNCPTR sysIntLvlVecAckRtn;
|
||||
IMPORT FUNCPTR sysIntLvlChgRtn;
|
||||
IMPORT FUNCPTR sysIntLvlEnableRtn;
|
||||
IMPORT FUNCPTR sysIntLvlDisableRtn;
|
||||
|
||||
/* Defines from config.h, or <bsp>.h */
|
||||
|
||||
#define TEMPLATE_CSR_PEND (0x0)
|
||||
#define TEMPLATE_CSR_ENB (0x1)
|
||||
#define TEMPLATE_CSR_ACK (0x2)
|
||||
#define TEMPLATE_VEC_BASE (0x0)
|
||||
|
||||
|
||||
/* hardware access methods */
|
||||
|
||||
#ifndef TEMPLATE_REG_READ
|
||||
# define TEMPLATE_REG_READ(x,result) \
|
||||
((result) = *(volatile UINT16 *)(x))
|
||||
#endif /*TEMPLATE_REG_READ*/
|
||||
|
||||
#ifndef TEMPLATE_REG_WRITE
|
||||
# define TEMPLATE_REG_WRITE(x,data) \
|
||||
(*((volatile UINT16 *)(x)) = (data))
|
||||
#endif /*TEMPLATE_REG_WRITE*/
|
||||
|
||||
/* Convert level number to vector number */
|
||||
|
||||
#ifndef TEMPLATE_LVL_VEC_MAP
|
||||
# define TEMPLATE_LVL_VEC_MAP(level, vector) \
|
||||
((vector) = ((level) + TEMPLATE_VEC_BASE))
|
||||
#endif
|
||||
|
||||
/* Convert pending register value, to a level number */
|
||||
|
||||
#ifndef TEMPLATE_PEND_LVL_MAP
|
||||
# define TEMPLATE_PEND_LVL_MAP(pendReg, level) \
|
||||
((level) = (pendReg))
|
||||
#endif
|
||||
|
||||
/* driver constants */
|
||||
|
||||
#define TEMPLATE_NUM_LEVELS 16
|
||||
#define TEMPLATE_ALL_ENABLED (TEMPLATE_NUM_LEVELS)
|
||||
#define TEMPLATE_ALL_DISABLED 0
|
||||
|
||||
/* Local data */
|
||||
|
||||
/* Current interrupt level setting (templateLvlChg). */
|
||||
|
||||
LOCAL UINT32 templateLvlCurrent = TEMPLATE_ALL_DISABLED; /* all levels disabled */
|
||||
|
||||
/*
|
||||
* A mask word. Bits are set in this word when a specific level
|
||||
* is enabled. It is used to mask off individual levels that have
|
||||
* not been explicitly enabled.
|
||||
*/
|
||||
|
||||
LOCAL UINT32 templateLvlEnabled;
|
||||
|
||||
/*
|
||||
* This array maps interrupt levels to mask patterns. The interrupt level
|
||||
* is the index, the data is the mask value. A mask bit enables one
|
||||
* level. The mask value is 'and'd with the templateLvlEnabled value
|
||||
* before writing to the chip.
|
||||
*/
|
||||
|
||||
LOCAL UINT32 templateLvlMask[TEMPLATE_NUM_LEVELS + 1] = /* int level mask */
|
||||
{
|
||||
0x0000, /* level 0, all disabled */
|
||||
0x0001, 0x0003, 0x0007, 0x000f,
|
||||
0x001f, 0x003f, 0x007f, 0x00ff,
|
||||
0x01ff, 0x03ff, 0x07ff, 0x0fff,
|
||||
0x1fff, 0x3fff, 0x7fff, 0xffff /* level 16, all enabled */
|
||||
};
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
STATUS templateLvlVecChk (int*, int*);
|
||||
STATUS templateLvlVecAck (int, int);
|
||||
int templateLvlChg (int);
|
||||
STATUS templateLvlEnable (int);
|
||||
STATUS templateLvlDisable (int);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* templateDevInit - initialize the interrupt controller
|
||||
*
|
||||
* This routine will initialize the interrupt controller device, disabling all
|
||||
* interrupt sources. It will also connect the device driver specific routines
|
||||
* into the architecture level hooks. If the BSP needs to create a wrapper
|
||||
* routine around any of the arhitecture level routines, it should install the
|
||||
* pointer to the wrapper routine after calling this routine.
|
||||
*
|
||||
* RETURNS: N/A.
|
||||
*/
|
||||
|
||||
void templateDevInit (void)
|
||||
{
|
||||
/* install the driver routines in the architecture hooks */
|
||||
|
||||
sysIntLvlVecChkRtn = templateLvlVecChk;
|
||||
sysIntLvlVecAckRtn = templateLvlVecAck;
|
||||
sysIntLvlChgRtn = templateLvlChg;
|
||||
sysIntLvlEnableRtn = templateLvlEnable;
|
||||
sysIntLvlDisableRtn = templateLvlDisable;
|
||||
|
||||
templateLvlEnabled = 0; /* all sources disabled */
|
||||
|
||||
templateLvlChg (TEMPLATE_ALL_ENABLED); /* enable all levels */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* templateLvlVecChk - check for and return any pending interrupts
|
||||
*
|
||||
* This routine interrogates the hardware to determine the highest priority
|
||||
* interrupt pending. It returns the vector associated with that interrupt, and
|
||||
* also the interrupt priority level prior to the interrupt (not the
|
||||
* level of the interrupt). The current interrupt priority level is then
|
||||
* raised to the level of the current interrupt so that only higher priority
|
||||
* interrupts will be accepted until this interrupt is finished.
|
||||
*
|
||||
* The return value ERROR indicates that no pending interrupt was found and
|
||||
* that the level and vector values were not returned.
|
||||
*
|
||||
* RETURNS: OK or ERROR if no interrupt is pending.
|
||||
*/
|
||||
|
||||
STATUS templateLvlVecChk
|
||||
(
|
||||
int* pLevel, /* ptr to receive old interrupt level */
|
||||
int* pVector /* ptr to receive current interrupt vector */
|
||||
)
|
||||
{
|
||||
int newLevel;
|
||||
|
||||
/* Read pending interrupt register */
|
||||
|
||||
TEMPLATE_REG_READ (TEMPLATE_CSR_PEND, newLevel);
|
||||
|
||||
/* If no interrupt is pending, return ERROR */
|
||||
|
||||
if (newLevel == 0)
|
||||
return ERROR;
|
||||
|
||||
/* map the return value to an interrupt level number */
|
||||
|
||||
TEMPLATE_PEND_LVL_MAP (newLevel, newLevel);
|
||||
|
||||
/* change to new interrupt level, returning previous level to caller */
|
||||
|
||||
*pLevel = templateLvlChg (newLevel);
|
||||
|
||||
/* fetch, or compute the interrupt vector number */
|
||||
|
||||
TEMPLATE_LVL_VEC_MAP (newLevel, *pVector);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* templateLvlVecAck - acknowledge the current interrupt
|
||||
*
|
||||
* Acknowledge the current interrupt cycle. The level and vector values are
|
||||
* those generated during the templateLvlVecChk() routine for this interrupt
|
||||
* cycle. The basic action is to reset the current interrupt and return
|
||||
* the interrupt level to its previous setting.
|
||||
*
|
||||
* RETURNS: OK or ERROR if a hardware fault is detected.
|
||||
* ARGSUSED
|
||||
*/
|
||||
|
||||
STATUS templateLvlVecAck
|
||||
(
|
||||
int level, /* old interrupt level to be restored */
|
||||
int vector /* current interrupt vector, if needed */
|
||||
)
|
||||
{
|
||||
/* acknowledge the current interrupt cycle */
|
||||
|
||||
TEMPLATE_REG_WRITE (TEMPLATE_CSR_ACK, (1 << (templateLvlCurrent)));
|
||||
|
||||
/* restore the previous interrupt level */
|
||||
|
||||
templateLvlChg (level);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* templateLvlChg - change the interrupt level value
|
||||
*
|
||||
* This routine implements the overall interrupt setting. All levels
|
||||
* up to and including the specifed level are disabled. All levels above
|
||||
* the specified level will be enabled, but only if they were specifically
|
||||
* enabled by the templateLvlEnable() routine.
|
||||
*
|
||||
* The specific priority level TEMPLATE_NUM_LEVELS is valid and represents
|
||||
* all levels enabled.
|
||||
*
|
||||
* RETURNS: Previous interrupt level.
|
||||
*/
|
||||
|
||||
int templateLvlChg
|
||||
(
|
||||
int level /* new interrupt level */
|
||||
)
|
||||
{
|
||||
int oldLevel;
|
||||
|
||||
oldLevel = templateLvlCurrent;
|
||||
|
||||
if (level >= 0 &&
|
||||
level <= TEMPLATE_NUM_LEVELS)
|
||||
{
|
||||
/* change current interrupt level */
|
||||
|
||||
templateLvlCurrent = level;
|
||||
}
|
||||
|
||||
/* Activate the enabled interrupts */
|
||||
|
||||
TEMPLATE_REG_WRITE (TEMPLATE_CSR_ENB,
|
||||
(templateLvlMask[templateLvlCurrent] & templateLvlEnabled));
|
||||
|
||||
return oldLevel;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* templateLvlEnable - enable a single interrupt level
|
||||
*
|
||||
* Enable a specific interrupt level. The enabled level will be allowed to
|
||||
* generate an interrupt, when the overall interrupt level is set below the
|
||||
* specified level. Without being enabled, the interrupt is blocked regardless
|
||||
* of the overall interrupt level setting.
|
||||
*
|
||||
* RETURNS: OK or ERROR if the specified level cannot be enabled.
|
||||
*/
|
||||
|
||||
STATUS templateLvlEnable
|
||||
(
|
||||
int level /* level to be enabled */
|
||||
)
|
||||
{
|
||||
if (level < 0 ||
|
||||
level > TEMPLATE_NUM_LEVELS)
|
||||
return ERROR;
|
||||
|
||||
/* set bit in enable mask */
|
||||
|
||||
if (level > 0)
|
||||
{
|
||||
int key;
|
||||
|
||||
key = intLock ();
|
||||
templateLvlEnabled |= (1 << level);
|
||||
intUnlock (key);
|
||||
}
|
||||
|
||||
templateLvlChg (-1); /* reset current mask */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* templateLvlDisable - disable a single interrupt level
|
||||
*
|
||||
* Disable a specific interrupt level. The disabled level is prevented
|
||||
* from generating an interrupt even if the overall interrupt level is set
|
||||
* below the specified level.
|
||||
*
|
||||
* RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
|
||||
*/
|
||||
|
||||
STATUS templateLvlDisable
|
||||
(
|
||||
int level /* level to be disabled */
|
||||
)
|
||||
{
|
||||
if (level < 0 ||
|
||||
level > TEMPLATE_NUM_LEVELS)
|
||||
return ERROR;
|
||||
|
||||
/* clear bit in enable mask */
|
||||
|
||||
if (level > 0)
|
||||
{
|
||||
int key;
|
||||
|
||||
key = intLock ();
|
||||
templateLvlEnabled &= ~(1 << level);
|
||||
intUnlock (key);
|
||||
}
|
||||
|
||||
templateLvlChg (-1); /* reset current mask */
|
||||
|
||||
return OK;
|
||||
}
|
||||
Reference in New Issue
Block a user