original files of m241

This commit is contained in:
neelimap
2026-07-30 11:19:44 +05:30
parent 170c2b3f3a
commit afc7070c1f
12254 changed files with 7655111 additions and 0 deletions
@@ -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);
}
+336
View File
@@ -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;
}