www.pudn.com > vxworks0108.rar > vg4Intr.c
/* vg4Intr.c - MPC107 EPIC and M1543C-8259 driver */
/* Copyright 1984-1997 Wind River Systems, Inc. */
/*
Description:
This module implements the Chaparral Epic and the ALI M1543C PCI-ISA Bridge
(PIB) drivers.
These merged drivers provide support for initializing their respective devices
and handling interrupts from them.
/*---------------------------------------------------------------- +includes+-*/
#include "type.h"
#include "asm.h"
#include "reg.h"
#include "vg4Intr.h"
#include "vg4.h"
#include "mpc107.h"
#include "esf.h"
#include "config.h"
#include "syslib.h"
#include "ivppc.h"
#include "vxworks.h"
/*-----------------------------------------------------------------(includes)-*/
/*------------------------------------------------------------------+defines+-*/
#undef EPIC_INT_DEBUG
#undef IBC_INT_DEBUG
#define EPIC_EOI sysPciWrite32(EPIC_ADDR(EPIC_CPU_EOI_REG), 0)
#define IBC_INT_PENDING 0x80
#define IBC_INT_LVL2 2
#define IBC_INT_LVL7 7
#define IBC_INT_LVL15 15
#define IBC_INT_PENDING 0x80
/* size of system interrupt table */
#define INT_TBL_SIZE 256
/*------------------------------------------------------------------(defines)-*/
/*-----------------------------------------------------------------+typedefs+-*/
/*-----------------------------------------------------------------(typedefs)-*/
/*------------------------------------------------------------------+globals+-*/
IMPORT UINT sysVectorIRQ0; /* vector for IRQ0 */
INT_HANDLER_DESC * sysIntTbl [INT_TBL_SIZE]; /* system interrupt table */
/* Mask values are the currently disabled sources */
LOCAL UINT8 sysPicMask1 = 0xfb; /* all levels disabled */
LOCAL UINT8 sysPicMask2 = 0xff;
/* Level values are the interrupt level masks */
LOCAL UINT8 sysPicLevel1;
LOCAL UINT8 sysPicLevel2;
LOCAL UINT8 sysPicLevelCur; /* current priority level, 0 to 16 */
LOCAL UCHAR sysIbcPhantomInt (UCHAR *intNum, int lvl7Int, int lvl15Int);
/* level values by real priority */
LOCAL UCHAR sysPicPriMask1[17] = {0xFB,0xFA,0xF8,0xF8,0xF0,0xE0,0xC0,0x80,
0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0x0};
LOCAL UCHAR sysPicPriMask2[17] = {0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,
0xFF,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80,0x0};
LOCAL UCHAR pirtTable[16] = {0x00, 0x08, 0x00, 0x02,
0x04, 0x05, 0x07, 0x06,
0x00, 0x01, 0x03, 0x09,
0x0b, 0x00, 0x0d, 0x0f};
/* sysIbcIntHandler() already connected ? */
LOCAL BOOL ibcIntHandlerConnected = FALSE;
#if defined (IBC_INT_DEBUG)
UINT8 gIsr1,
gIsr2,
gImr1,
gImr2,
gIrr1,
gIrr2;
void i8259RegsGet (void);
int sysIbcIntCnt;
int sysIbcPhantomIntCnt;
int sysIbcAdjInt7Cnt;
int sysIbcAdjInt15Cnt;
int sysIbcIntCntTbl[16];
#endif /* defined (IBC_INT_DEBUG) */
void (*_func_spuriousIntHook)(void *arg, UINT32 vecNum) = NULL;
LOCAL void * spuriousHandlerArg;
void (*_func_uninitIntHook)(void *arg, UINT32 vecNum) = NULL;
LOCAL void * uninitIntHandlerArg;
#if defined (EPIC_INT_DEBUG)
unsigned long sysEpicIntCnt = 0;
unsigned long sysEpicUninitIntCnt = 0;
unsigned long sysEpicSpuriousIntCnt = 0;
#endif /* defined (EPIC_INT_DEBUG) */
#if defined (EPIC_INT_DEBUG) || defined (IBC_INT_DEBUG)
unsigned long sysIntVecCnt[INT_TBL_SIZE];
#endif /* defined (EPIC_INT_DEBUG) || defined (IBC_INT_DEBUG) */
/*------------------------------------------------------------------(globals)-*/
/*-------------------------------------------------------------+declarations+-*/
IMPORT STATUS (*_func_intConnectRtn) (VOIDFUNCPTR *, VOIDFUNCPTR, int);
IMPORT int (*_func_intEnableRtn) (int);
IMPORT int (*_func_intDisableRtn) (int);
IMPORT void sysPciRead32 (UINT32, UINT32 *);
IMPORT void sysPciWrite32 (UINT32, UINT32);
IMPORT STATUS excIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR);
void sysIbcIntEnable (int);
void sysIbcIntDisable (int);
void sysIbcIntHandler (void);
void sysEpicIntHandler (void);
void sysIbcIntLevelSet (int);
STATUS sysSpuriousIntConnect (VOIDFUNCPTR routine, void *arg);
LOCAL int getEpicVecOffset (int);
LOCAL STATUS sysEpicIntConnect (VOIDFUNCPTR * vector, VOIDFUNCPTR routine,
int parameter);
LOCAL STATUS sysEpicExtIntConnect (VOIDFUNCPTR * vector, VOIDFUNCPTR routine,
int parameter, int position);
LOCAL int sysEpicIntEnable (int);
LOCAL int sysEpicIntDisable (int);
LOCAL void sysIbcEpicConnect (void);
LOCAL void sysIbcEndOfInt (int);
/*-------------------------------------------------------------(declarations)-*/
void sysEpicReset (void)
{
/* Reset the EPIC. */
sysPciWrite32 ( EPIC_ADDR (EPIC_GLOBAL_CONFIG_REG), RESET_CNTRLR );
}
/*******************************************************************************
*
* sysEpicInit - initialize the EPIC in the MPC107
*
* This function initializes the Embedded Programmable Interrupt Controller (EPIC)
* contained in the Chaparral.
*
* It first initializes the system vector table, connects the EPIC interrupt
* handler to the PPC external interrupt and attaches the local EPIC routines
* for interrupt connecting, enabling and disabling to the corresponding system
* routine pointers.
*
* It then initializes the EPIC registers, clears any pending EPIC interrupts,
* enables interrupt handling by the EPIC and enables external ISA interrupts
* (from the M1543C).
*
* RETURNS: OK always
*/
STATUS sysEpicInit (void)
{
int i;
LOCAL_INT_DATA init;
/* Reset the EPIC. */
sysPciWrite32 ( EPIC_ADDR (EPIC_GLOBAL_CONFIG_REG), RESET_CNTRLR );
/* Initialize the interrupt table */
for (i = 0; i < 256; i++)
sysIntTbl[i] = NULL;
#if defined (EPIC_INT_DEBUG) || defined (IBC_INT_DEBUG)
/* Reset interrupt vector count table (for debugging only) */
for ( i = 0; i < INT_TBL_SIZE; i++ )
{
sysIntVecCnt[i] = 0;
}
#endif /* defined (EPIC_INT_DEBUG) || defined (IBC_INT_DEBUG) */
/* Connect the interrupt demultiplexer to the PowerPC external interrupt */
excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, sysEpicIntHandler);
/*
* Set up the BSP specific routines
* Attach the local routines to the vxWorks system calls
*/
_func_intConnectRtn = sysEpicIntConnect;
_func_intEnableRtn = sysEpicIntEnable;
_func_intDisableRtn = sysEpicIntDisable;
/*
* Initialize the EPIC
*/
/* generate a PCI IACK to clear any pending interrupts */
sysPciRead32 ( EPIC_ADDR (EPIC_CPU_IACK_REG), &init.temp );
/*
* Set the timer frequency reporting register.
* This register is used to report the frequency of the clock
* source for the global timers (in ticks/seconds (Hz)) which is always the
* SDRAM_CLK signal. The timers operate at 1/8th the speed of the
* SDRAM_CLK signal.
*/
sysPciWrite32 ( EPIC_ADDR (EPIC_TIMER_FREQ_REG), MEMORY_BUS_SPEED);
/* Clear the timer counter register and setup the timer vector/priority registers */
sysPciWrite32 ( EPIC_ADDR (EPIC_TIMER0_BASE_CT_REG), TIMER_INHIBIT );
sysPciWrite32 ( EPIC_ADDR (EPIC_TIMER0_VEC_PRI_REG), INIT_GLOBAL_TIMER0 );
sysPciWrite32 ( EPIC_ADDR (EPIC_TIMER1_BASE_CT_REG), TIMER_INHIBIT );
sysPciWrite32 ( EPIC_ADDR (EPIC_TIMER1_VEC_PRI_REG), INIT_GLOBAL_TIMER1 );
sysPciWrite32 ( EPIC_ADDR (EPIC_TIMER2_BASE_CT_REG), TIMER_INHIBIT );
sysPciWrite32 ( EPIC_ADDR (EPIC_TIMER2_VEC_PRI_REG), INIT_GLOBAL_TIMER2 );
sysPciWrite32 ( EPIC_ADDR (EPIC_TIMER3_BASE_CT_REG), TIMER_INHIBIT );
sysPciWrite32 ( EPIC_ADDR (EPIC_TIMER3_VEC_PRI_REG), INIT_GLOBAL_TIMER3 );
/* setup the external source vector/priority registers */
sysPciWrite32 ( EPIC_ADDR (EPIC_EXT_SRC0_VEC_PRI_REG), INIT_EXT_SRC0 );
sysPciWrite32 ( EPIC_ADDR (EPIC_EXT_SRC1_VEC_PRI_REG), INIT_EXT_SRC1 );
sysPciWrite32 ( EPIC_ADDR (EPIC_EXT_SRC2_VEC_PRI_REG), INIT_EXT_SRC2 );
sysPciWrite32 ( EPIC_ADDR (EPIC_EXT_SRC3_VEC_PRI_REG), INIT_EXT_SRC3 );
sysPciWrite32 ( EPIC_ADDR (EPIC_EXT_SRC4_VEC_PRI_REG), INIT_EXT_SRC4 );
/* setup the Ext source 0 reg (8259 input) for normal operation */
sysPciRead32 ( EPIC_ADDR (EPIC_EXT_SRC0_VEC_PRI_REG), &init.regVal );
init.regVal |= PIB_INT_VEC;
init.regVal &= (~INT_MASK_BIT);
sysPciWrite32 ( EPIC_ADDR (EPIC_EXT_SRC0_VEC_PRI_REG), init.regVal );
/* enable interrupts for this processor */
sysPciWrite32 ( EPIC_ADDR (EPIC_CPU_CUR_TASK_PRI_REG), 1 );
/* setup the EPIC to process the 8259 interrupts ( mixed mode ) */
sysPciWrite32 ( EPIC_ADDR (EPIC_GLOBAL_CONFIG_REG), SET_MIXED_MODE );
return (OK);
}
/******************************************************************************
*
* sysEpicIntConnect - 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 sysEpicIntConnect
(
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;
LOCAL_INT_DATA connect;
if (((int)vector < 0) || ((int)vector > 0xff)) /* Out of Range? */
return (ERROR);
/* connect ibc interrupt handler */
if (!ibcIntHandlerConnected)
{
ibcIntHandlerConnected = TRUE;
sysIbcEpicConnect (); /* calls this rtn, recursively */
}
/* create a new interrupt handler */
if ((newHandler = (INT_HANDLER_DESC *)calloc (1, sizeof (INT_HANDLER_DESC)))
== NULL)
return (ERROR);
/* initialize the new handler */
newHandler->vec = routine;
newHandler->arg = parameter;
newHandler->next = NULL;
/* install the handler in the system interrupt table */
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;
}
/*
* if the connect is for an EPIC interrupt,
* then store the vector into the appropriate EPIC vector register
*/
connect.regAddr = getEpicVecOffset ( (int)vector );
if ( connect.regAddr > 0 )
{
/* read the vector register */
sysPciRead32 ( EPIC_ADDR (connect.regAddr), &connect.regVal );
/* store the interrupt vector number */
connect.regVal |= (int)vector;
/* write the contents of the vector register back */
sysPciWrite32 ( EPIC_ADDR (connect.regAddr), connect.regVal );
}
return (OK);
}
/******************************************************************************
*
* sysEpicExtIntConnect - connect an interrupt handler to the system vector table
*
* This function connects an interrupt handler with extended options to the
* system vector table. This routine allows to add an interrupt handler at the
* specified position within the interrupt handler list.
* Special values for position parameter:
* 0: add handler as first handler in the list
* -1: add handler as last handler in the list
*
* RETURNS: OK/ERROR.
*/
LOCAL STATUS sysEpicExtIntConnect
(
VOIDFUNCPTR * vector, /* interrupt vector to attach */
VOIDFUNCPTR routine, /* routine to be called */
int parameter, /* parameter to be passed to routine */
int position /* position within interrupt handler list */
)
{
INT_HANDLER_DESC * newHandler;
INT_HANDLER_DESC * currHandler;
LOCAL_INT_DATA connect;
int index;
if (((int)vector < 0) || ((int)vector > 0xff)) /* Out of Range? */
{
return (ERROR);
}
/* connect the PIB to EPIC, before any other connections */
if (!ibcIntHandlerConnected)
{
ibcIntHandlerConnected = TRUE;
sysIbcEpicConnect (); /* calls this rtn, recursively */
}
/* create a new interrupt handler */
if ((newHandler = (INT_HANDLER_DESC *)calloc (1, sizeof (INT_HANDLER_DESC)))
== NULL)
return (ERROR);
/* initialize the new handler */
newHandler->vec = routine;
newHandler->arg = parameter;
newHandler->next = NULL;
/* install the handler in the system interrupt table */
if (sysIntTbl[(int) vector] == NULL)
{
/*
* This is the first handler for this vector.
* Check position parameter (only 0 and -1 allowed for first handler)
* and insert new handler.
*/
if (0 != position && -1 != position)
{
free (newHandler);
return (ERROR);
}
else
{
sysIntTbl[(int) vector] = newHandler;
}
sysIntTbl [(int ) vector] = newHandler; /* single int. handler case */
/*
* if the connect is for an EPIC interrupt,
* then store the vector into the appropriate EPIC vector register
*/
connect.regAddr = getEpicVecOffset ( (int)vector );
if ( connect.regAddr > 0 )
{
/* read the vector register */
sysPciRead32 ( EPIC_ADDR (connect.regAddr), &connect.regVal );
/* store the interrupt vector number */
connect.regVal |= (int)vector;
/* write the contents of the vector register back */
sysPciWrite32 ( EPIC_ADDR (connect.regAddr), connect.regVal );
}
}
else
{
/*
* One or more handler already in list.
*/
currHandler = sysIntTbl[(int) vector]; /* multiple int. handler case */
/*
* Special case: connect new handler as first handler in list.
*/
if (0 == position)
{
newHandler->next = currHandler;
sysIntTbl[(int) vector] = newHandler;
}
/*
* Special case: connect new handler as last handler in list.
* Search end of list and add new handler.
*/
else if (-1 == position)
{
while (currHandler->next != NULL)
{
currHandler = currHandler->next;
}
currHandler->next = newHandler;
}
/*
* Connect new handler at specified position in list.
*/
else
{
/* Search for specified position in handler list. */
index = 0;
while (currHandler->next != NULL)
{
index++;
if (index == position)
{
/* Position found. Insert new handler */
newHandler->next = currHandler->next;
currHandler->next = newHandler;
break;
}
else
{
currHandler = currHandler->next;
}
}
/* If position not yet found, return error */
if (index < position)
{
free (newHandler);
return (ERROR);
}
}
}
return (OK);
}
/******************************************************************************
*
* sysEpicIntConnectFirst - connect an interrupt handler as first handler in list
*
* This function connects an interrupt handler as first handler in the interrupt
* handler list.
*
* RETURNS: OK/ERROR.
*/
STATUS sysEpicIntConnectFirst
(
VOIDFUNCPTR * vector, /* interrupt vector to attach */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
return (sysEpicExtIntConnect (vector, routine, parameter, 0));
}
/******************************************************************************
*
* sysEpicIntConnectLast - connect an interrupt handler as last handler in list
*
* This function connects an interrupt handler as first handler in the interrupt
* handler list.
*
* RETURNS: OK/ERROR.
*/
STATUS sysEpicIntConnectLast
(
VOIDFUNCPTR * vector, /* interrupt vector to attach */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
return (sysEpicExtIntConnect (vector, routine, parameter, -1));
}
/*******************************************************************************
*
* sysEpicIntEnable - enable an EPIC interrupt level
*
* This routine enables a specified EPIC interrupt level.
*
* RETURNS: OK or ERROR if interrupt level not supported
*/
LOCAL int sysEpicIntEnable
(
int intLevel /* interrupt level to enable */
)
{
LOCAL_INT_DATA enable;
/*
* if the int. level is not for ISA or EPIC, then it is not supported.
* If not supported, just return.
*/
if ((intLevel < 0) || (intLevel > ERR_INTERRUPT_BASE))
{
return (ERROR);
}
/* If ISA interrupt level,call the IBC driver enable routine, */
if ( intLevel < EXT_INTERRUPT_BASE )
{
sysIbcIntEnable ( intLevel );
}
enable.regAddr = getEpicVecOffset ( intLevel );
if ( enable.regAddr > 0 )
{
/* read the vector register */
sysPciRead32 ( EPIC_ADDR (enable.regAddr), &enable.regVal );
/* enable the interrupt */
enable.regVal &= (~INT_MASK_BIT);
/* write the contents of the vector register back */
sysPciWrite32 ( EPIC_ADDR (enable.regAddr), enable.regVal );
}
return (OK);
}
/*******************************************************************************
*
* sysEpicIntDisable - disable an EPIC interrupt level
*
* This routine disables a specified EPIC interrupt level.
*
* RETURNS: OK or ERROR if interrupt level not supported
*/
LOCAL int sysEpicIntDisable
(
int intLevel /* interrupt level to disable */
)
{
LOCAL_INT_DATA disable;
/*
* if the int. level is not for ISA or EPIC, then it is not supported.
* If not supported, just return.
*/
if ((intLevel < 0) || (intLevel > ERR_INTERRUPT_BASE))
{
return (ERROR);
}
/* If ISA interrupt level, call the IBC driver disable routine, */
if ( intLevel < EXT_INTERRUPT_BASE )
{
sysIbcIntDisable ( intLevel );
}
/* else, it is an EPIC interrupt level */
else
{
/* get the vector reg. offset value */
disable.regAddr = getEpicVecOffset ( intLevel );
if ( disable.regAddr > 0 )
{
/* read the vector register */
sysPciRead32 ( EPIC_ADDR (disable.regAddr), &disable.regVal );
/* disable the interrupt */
disable.regVal |= INT_MASK_BIT;
/* write the contents of the vector register back */
sysPciWrite32 ( EPIC_ADDR (disable.regAddr), disable.regVal );
}
}
return (OK);
}
/******************************************************************************
*
* sysEpicIntHandler - handle an interrupt received at the EPIC
*
* This routine will process interrupts received from PCI or ISA devices as
* these interrupts arrive via the EPIC. This routine supports EPIC interrupt
* nesting.
*
* RETURNS: N/A
*/
void sysEpicIntHandler (void)
{
INT_HANDLER_DESC * currHandler;
UINT32 vecNum;
int dontCare;
#ifdef EPIC_INT_DEBUG
sysEpicIntCnt++;
#endif
/* get the vector from the EPIC IACK reg. */
sysPciRead32 (EPIC_ADDR (EPIC_CPU_IACK_REG), &vecNum);
vecNum &= VECTOR_MASK;
/* Ignore spurious interrupts */
if (vecNum == 0xFF)
{
if (_func_spuriousIntHook != NULL) {
_func_spuriousIntHook (spuriousHandlerArg, vecNum);
}
#if defined (EPIC_INT_DEBUG)
sysEpicSpuriousIntCnt++;
printf ("EPIC Spurious Interrupt!\n", 0,0,0,0,0,0);
#endif /* defined (EPIC_INT_DEBUG) */
return;
}
/*
* Allow maskable interrupts to the CPU. EPIC will hold off
* lower and equal interrupts until EPIC_EOI is performed.
*/
CPU_INT_UNLOCK (_PPC_MSR_EE);
/* call the necessary interrupt handlers */
if ((currHandler = sysIntTbl [vecNum]) == NULL)
{
if (_func_uninitIntHook != NULL) {
_func_uninitIntHook (uninitIntHandlerArg, vecNum);
}
#if defined (EPIC_INT_DEBUG)
sysEpicUninitIntCnt++;
printf ("uninitialized EPIC interrupt %d\r\n", vecNum, 0,0,0,0,0);
#endif /* defined (EPIC_INT_DEBUG) */
}
else
{
#if defined (EPIC_INT_DEBUG)
sysIntVecCnt[vecNum]++;
#endif /* defined (EPIC_INT_DEBUG) */
/* Call EACH respective chained interrupt handler */
while (currHandler != NULL)
{
currHandler->vec (currHandler->arg);
currHandler = currHandler->next;
}
}
CPU_INT_LOCK (&dontCare);
/* issue an end-of-interrupt to the EPIC */
EPIC_EOI;
return;
}
/*******************************************************************************
*
* getEpicVecOffset - get the vector offset value of an EPIC register
*
* This routine calculates the appropriate EPIC register offset based on the
* specified EPIC interrupt level.
*
* RETURNS: EPIC register offset or zero if not a supported level.
*/
LOCAL int getEpicVecOffset
(
int intLevel
)
{
int offset = 0;
/* check for external interrupt level */
if ((intLevel >= EXT_INTERRUPT_BASE) && (intLevel < TIMER_INTERRUPT_BASE))
{
offset = intLevel - EXT_INTERRUPT_BASE;
offset = EPIC_EXT_SRC0_VEC_PRI_REG + ( offset * EPIC_REG_OFFSET * 2 );
}
/* check for a timer interrupt level */
if ((intLevel >= TIMER_INTERRUPT_BASE) && (intLevel < ERR_INTERRUPT_BASE))
{
offset = intLevel - TIMER_INTERRUPT_BASE;
offset = EPIC_TIMER0_VEC_PRI_REG + ( offset * EPIC_REG_OFFSET * 4 );
}
return (offset);
}
/*******************************************************************************
*
* sysPciExtIbcInit - initialize the extended portion of the IBC PCI header
*
* This routine initializes the extended portion of the ISA Bridge Controller
* (IBC) PCI header.
*
* RETURNS: OK or ERROR.
*
* SEE ALSO:
*/
STATUS sysPciExtIbcInit
(
int pciBusNo, /* PCI bus number */
int pciDevNo, /* PCI device number */
int pciFuncNo /* PCI function number */
)
{
/*
* route M1543C PCI interrupt inputs to 8259 ISA IRQs
* PCI INTA: routed to Z85230_INT_LVL
* PCI INTB: routed to Z8536_INT_LVL
*/
pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_IBC_PIRT1,
(UINT8)(pirtTable[Z8536_INT_LVL] << 4) | pirtTable[Z85230_INT_LVL]);
/*
* M1543C PCI interrupts to ISA IRQ edge/level control
* INTA..INTD level triggered: 0x00
*/
pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_IBC_PILET, 0x00);
/*
* M1543C PCI interface
*
* Bit 5= BusRequest only when ISA-Master asserts Command
* Bit 4= Pass.Release ; \
* Bit 3= Delayed Transaction ; / needs SMCCI (5E) bit0=1
* Bit 2= PCI to ISA posted WR buffer
* Bit 1= ISA Master Line Buffer
* Bit 0= DMA Line Buffer Enable
*/
pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, M1543C_PIC, 0x03);
/*
* M1543C Suspend Mode Clock Control I
*
* Bit 0= Passive Release control during delayed transaction cycle (0=disable, 1=enable).
*/
pciConfigModifyByte (pciBusNo, pciDevNo, pciFuncNo, M1543C_SMCCI, 0x01, 0x01);
/*
* M1543C I/O recovery control
*
* Bit 5-2= I/O Recovery Period (0001b = 0.25us)
* Bit 1= On-Chip I/O Recovery Feature (0=disable, 1=enable)
* Bit 0= ISA I/O Recovery Feature (0=disable, 1=enable)
*/
pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, M1543C_IORC, 0x07);
return (OK);
}
/*******************************************************************************
*
* sysIbcInit - Initialize the IBC
*
* This routine initializes the non-PCI Header configuration registers of the
* IBC within the W83C553 PIB.
*
* RETURNS: OK always
*/
STATUS sysIbcInit (void)
{
UCHAR intNum;
BOOL spurious;
/* Initialize the Interrupt Controller #1 */
IBC_BYTE_OUT (PIC_port1 (PIC1_BASE_ADR),0x11); /* ICW1 */
IBC_BYTE_OUT (PIC_port2 (PIC1_BASE_ADR),sysVectorIRQ0); /* ICW2 */
IBC_BYTE_OUT (PIC_port2 (PIC1_BASE_ADR),0x04); /* ICW3 */
IBC_BYTE_OUT (PIC_port2 (PIC1_BASE_ADR),0x01); /* ICW4 */
/*
* Mask interrupts IRQ 0, 1, and 3-7 by writing to OCW1 register
* IRQ 2 is the cascade input
*/
IBC_BYTE_OUT (PIC_IMASK (PIC1_BASE_ADR),0xfb);
/* Insure that all controller interrupts are edge sensitive */
IBC_BYTE_OUT (M1543C_INT1_ELC, 0x00);
/* Initialize the Interrupt Controller #2 */
IBC_BYTE_OUT (PIC_port1 (PIC2_BASE_ADR),0x11); /* ICW1 */
IBC_BYTE_OUT (PIC_port2 (PIC2_BASE_ADR),sysVectorIRQ0+8); /* ICW2 */
IBC_BYTE_OUT (PIC_port2 (PIC2_BASE_ADR),0x02); /* ICW3 */
IBC_BYTE_OUT (PIC_port2 (PIC2_BASE_ADR),0x01); /* ICW4 */
/* Mask interrupts IRQ 8-15 by writing to OCW1 register */
IBC_BYTE_OUT (PIC_IMASK (PIC2_BASE_ADR),0xff);
/* Make IRQ 11, and 10 level sensitive */
IBC_BYTE_OUT (M1543C_INT2_ELC, 0x08 | 0x04);
/* Perform the PCI Interrupt Ack cycle */
do
{
intNum = (*(char *)ISA_INTR_ACK_REG);
spurious = sysIbcPhantomInt (&intNum, 0, 0);
if (!spurious)
{
/* Perform the end of interrupt procedure */
sysIbcEndOfInt (15);
}
}
while(!spurious);
sysIbcIntLevelSet (16);
#if defined (IBC_INT_DEBUG)
{
int i;
sysIbcPhantomIntCnt = 0;
sysIbcIntCnt = 0;
for (i = 0; i < 16; i++)
{
sysIbcIntCntTbl[i] = 0;
}
}
#endif /* defined (IBC_INT_DEBUG) */
return (OK);
}
/*******************************************************************************
*
* sysIbcIntEnable - enable a IBC interrupt level
*
* This routine enables a specified IBC interrupt level.
*
* RETURNS: N/A
*/
void sysIbcIntEnable
(
int intNum /* interrupt level to enable */
)
{
if (intNum < 8)
{
sysPicMask1 &= ~(1 << intNum);
IBC_BYTE_OUT (PIC_IMASK (PIC1_BASE_ADR), sysPicMask1 | sysPicLevel1);
}
else
{
sysPicMask2 &= ~(1 << (intNum - 8));
IBC_BYTE_OUT (PIC_IMASK (PIC2_BASE_ADR), sysPicMask2 | sysPicLevel2);
}
}
/*******************************************************************************
*
* sysIbcIntDisable - disable a IBC interrupt level
*
* This routine disables a specified IBC interrupt level.
*
* RETURNS: N/A
*/
void sysIbcIntDisable
(
int intNum /* interrupt level to disable */
)
{
if (intNum < 8)
{
sysPicMask1 |= (1 << intNum);
IBC_BYTE_OUT (PIC_IMASK (PIC1_BASE_ADR), sysPicMask1 | sysPicLevel1 );
}
else
{
sysPicMask2 |= (1 << (intNum - 8));
IBC_BYTE_OUT (PIC_IMASK (PIC2_BASE_ADR), sysPicMask2 | sysPicLevel2);
}
}
/******************************************************************************
*
* sysIbcIntHandler - handler of the sl82565 IBC interrupt.
*
* This routine handles interrupts originating from the M1543C PIB ISA Bus
* Controller (IBC). This device implements the functional equivalent of two
* cascaded 8259 PICs.
*
* This routine is entered with CPU external interrupts enabled.
*
* Because the ISA bus is only accessible via the PCI bus, this driver first
* initiates a PCI interrupt acknowledge cycle to read the interrupt number
* (vector) coming from the IBC.
*
* This routine then processes the interrupt by calling all interrupt service
* routines chained to the vector.
*
* Finally, this routine re-arms the interrupt at the IBC by performing a
* IBC EOI.
*
* RETURNS: N/A
*/
void sysIbcIntHandler (void)
{
UCHAR intNum;
INT_HANDLER_DESC * currHandler;
static int lvl7Int = 0,
lvl15Int = 0;
#if defined (IBC_INT_DEBUG)
sysIbcIntCnt++;
#endif /* defined (IBC_INT_DEBUG) */
/*
* Reading ISA_INTR_ACK_REG would generate PCI IACK cycles on the
* PCI bus which would cause the IBC to put out vector on the PCI bus.
*/
intNum = (*(char *)ISA_INTR_ACK_REG);
#if defined (IBC_INT_DEBUG)
sysIbcIntCntTbl[intNum]++;
#endif /* defined (IBC_INT_DEBUG) */
/* Special check for phantom interrupts */
if ((intNum & IBC_INT_LVL7) == IBC_INT_LVL7)
{
if (sysIbcPhantomInt (&intNum, lvl7Int, lvl15Int) == TRUE)
{
#if defined (IBC_INT_DEBUG)
sysIbcPhantomIntCnt++;
#endif /* defined (IBC_INT_DEBUG) */
return; /* It's phantom so just return. */
}
}
/*
* If cascade from IBC2 just EIO and return. It has been seen on
* certain PCI ISA bridge devices, that it is possible to see the
* cascade IRQ2. In particular, this has been observed on the
* Winbond W83C553F on certain revs of the chip prior to Rev G.
*/
if (intNum == IBC_INT_LVL2)
{
sysIbcEndOfInt (intNum);
return;
}
/* Keep track of level 7 and 15 nesting for phantom interrupt handling */
if (intNum == IBC_INT_LVL7)
{
lvl7Int++;
}
else if (intNum == IBC_INT_LVL15)
{
lvl15Int++;
}
if ((currHandler = sysIntTbl [intNum]) == NULL)
{
printf ("uninitialized IBC interrupt level %x\r\n", intNum, 0,0,0,0,0);
}
else
{
#if defined (IBC_INT_DEBUG)
sysIntVecCnt[intNum]++;
#endif /* defined (IBC_INT_DEBUG) */
/* Call EACH respective chained interrupt handler */
while (currHandler != NULL)
{
currHandler->vec (currHandler->arg);
currHandler = currHandler->next;
}
}
/* Keep track of level 7 and 15 nesting for phantom interrupt handling */
if (intNum == IBC_INT_LVL7)
{
lvl7Int--;
}
else if (intNum == IBC_INT_LVL15)
{
lvl15Int--;
}
/* Re-arm (enable) the interrupt on the IBC */
sysIbcEndOfInt (intNum);
}
/*******************************************************************************
*
* sysIbcPhantomInt - Determine if IRQ interrupt number 7 or 15 is "phantom".
*
* This routine determines if an IRQ number of 7 or 15 is a phantom
* interrupt. According to Intel 82C59A-2 documentation, the IR (interrupt
* request) inputs must remain high until after the falling edge of the first
* INTA (interrupt acknowledge). If the IR goes low before this, a DEFAULT
* (phantom) IRQ7 will occur when the CPU acknowledges the interrupt. Note
* that if an IRQ7 is generated it may really be another interrupt, IRQ4 for
* example. IRQ 7 is associated with the master 8259, IRQ 15 is associated
* with the slave 8259. This function should only be called if the
* acknowledged IRQ number is 7 or 15 but does behave sanely if called with
* other IRQ numbers.
*
* As mentioned above, IRQ 7 is supposed to be associated with the master
* 8259. However, it has been observed that a phantom IRQ 7 was caused by
* an interrupt on the slave 8259. Thus, the algorithm now implemented is
* to scan both the master and the slave 8259 in the correct priority order
* (from highest to lowest: 0 1 8 9 10 11 12 13 14 15 3 4 5 6 7).
*
* RETURNS: TRUE if phantom IRQ, *intNum unaltered.
* FALSE if no phantom interrupt, *intNum is "real" IRQ number.
*/
LOCAL UCHAR sysIbcPhantomInt
(
UCHAR *intNum, /* interrupt number received on acknowledge */
int lvl7Int, /* interrupt 7 nesting level */
int lvl15Int /* interrupt 15 nesting level */
)
{
UCHAR irqBit;
UINT irqNum;
#if defined (IBC_INT_DEBUG)
UCHAR isr;
#endif /* defined (IBC_INT_DEBUG) */
/* Read the master in-service register (ISR) */
IBC_BYTE_OUT (PIC_port1 (PIC1_BASE_ADR), PIC_OCW3_SEL + PIC_ISR_READ);
IBC_BYTE_IN (PIC_port1 (PIC1_BASE_ADR), &irqBit);
#if defined (IBC_INT_DEBUG)
isr = irqBit;
#endif /* defined (IBC_INT_DEBUG) */
if (irqBit == 0)
{
return (TRUE); /* No in-service int so it MUST be phantom */
}
for (irqNum = 0; ((irqBit & 1) == 0) ; irqNum++, irqBit >>= 1)
;
if (irqNum == IBC_INT_LVL7)
if (lvl7Int > 1)
{
return (TRUE); /* We're nested so it MUST be phantom */
}
/* if irqNum isn't 2 we have an interrupt on the master */
if (irqNum != IBC_INT_LVL2)
{
*intNum = irqNum;
#if defined (IBC_INT_DEBUG)
sysIbcAdjInt7Cnt++;
printf ("sysIbcPhantomInt: IRQ adjusted to %d (master ISR: %02x)\n", *intNum, isr,0,0,0,0);
#endif /* defined (IBC_INT_DEBUG) */
return (FALSE);
}
/* Read the slave in-service register (ISR) */
IBC_BYTE_OUT (PIC_port1 (PIC2_BASE_ADR), PIC_OCW3_SEL + PIC_ISR_READ);
IBC_BYTE_IN (PIC_port1 (PIC2_BASE_ADR), &irqBit);
#if defined (IBC_INT_DEBUG)
isr = irqBit;
#endif /* defined (IBC_INT_DEBUG) */
if (irqBit == 0) /* should never happen, really */
{
#if defined (IBC_INT_DEBUG)
printf ("sysIbcPhantomInt: no interrupt in slave\n", 0,0,0,0,0,0);
#endif /* defined (IBC_INT_DEBUG) */
return (TRUE); /* No in-service int so it MUST be phantom */
}
for (irqNum = 8; ((irqBit & 1) == 0) ; irqNum++, irqBit >>= 1)
;
if (irqNum == 15)
if (lvl15Int > 1)
{
#if defined (IBC_INT_DEBUG)
printf ("sysIbcPhantomInt: nested interrupt in slave\n",
0,0,0,0,0,0);
#endif /* defined (IBC_INT_DEBUG) */
return (TRUE); /* We're nested so it MUST be phantom */
}
*intNum = irqNum;
#if defined (IBC_INT_DEBUG)
sysIbcAdjInt15Cnt++;
printf ("sysIbcPhantomInt: IRQ adjusted to %d (slave ISR: %02x)\n", *intNum, isr,0,0,0,0);
#endif /* defined (IBC_INT_DEBUG) */
return (FALSE);
}
/*******************************************************************************
*
* sysIbcEndOfInt - send EOI (end of interrupt) signal.
*
* This routine is called at the end of the interrupt handler to
* send a non-specific end of interrupt (EOI) signal.
*
* The second PIC is acked only if the interrupt came from that PIC.
* The first PIC is always acked.
*/
LOCAL void sysIbcEndOfInt
(
int intNum
)
{
if (intNum > IBC_INT_LVL7)
{
IBC_BYTE_OUT (PIC_IACK (PIC2_BASE_ADR), 0x20);
}
IBC_BYTE_OUT (PIC_IACK (PIC1_BASE_ADR), 0x20);
#if defined (IBC_INT_DEBUG)
{
UINT8 isr1,
isr2;
int irqBit;
if (intNum > IBC_INT_LVL7)
{
IBC_BYTE_OUT (PIC_port1 (PIC2_BASE_ADR), PIC_OCW3_SEL + PIC_ISR_READ);
IBC_BYTE_IN (PIC_port1 (PIC2_BASE_ADR), &isr2);
irqBit = 1 << (intNum & 0x7);
if (isr2 & irqBit)
{
printf ("sysIbcEndOfInt: In-service bit for IRQ %d not reset (ISR2: %02x)\n", intNum,isr2,0,0,0,0);
}
}
else if (intNum != IBC_INT_LVL2)
{
IBC_BYTE_OUT (PIC_port1 (PIC1_BASE_ADR), PIC_OCW3_SEL + PIC_ISR_READ);
IBC_BYTE_IN (PIC_port1 (PIC1_BASE_ADR), &isr1);
irqBit = 1 << intNum;
if (isr1 & irqBit)
{
printf ("sysIbcEndOfInt: In-service bit for IRQ %d not reset (ISR1: %02x)\n", intNum,isr1,0,0,0,0);
}
}
}
#endif /* defined (IBC_INT_DEBUG) */
}
/*******************************************************************************
*
* sysIbcIntLevelSet - set the interrupt priority level
*
* This routine masks interrupts with real priority equal to or lower than
* . The special
* value 16 indicates all interrupts are enabled. Individual interrupt
* numbers have to be specifically enabled by sysIbcIntEnable() before they
* are ever enabled by setting the interrupt level value.
*
* Note because of the IBM cascade scheme, the actual priority order for
* interrupt numbers is (high to low) 0, 1, 8, 9, 10, 11, 12, 13, 14, 15,
* 3, 4, 5, 6, 7, 16 (all enabled)
*
* INTERNAL: It is possible that we need to determine if we are raising
* or lowering our priority level. It may be that the order of loading the
* two mask registers is dependent upon raising or lowering the priority.
*
* RETURNS: N/A
*/
void sysIbcIntLevelSet
(
int intNum /* interrupt level to implement */
)
{
if (intNum > 16)
intNum = 16;
sysPicLevelCur = intNum;
if (sysPicLevel2 != sysPicPriMask2[intNum])
{
sysPicLevel2 = sysPicPriMask2[intNum];
IBC_BYTE_OUT (PIC_IMASK (PIC2_BASE_ADR), sysPicMask2 | sysPicLevel2);
}
if (sysPicLevel1 != sysPicPriMask1[intNum])
{
sysPicLevel1 = sysPicPriMask1[intNum];
IBC_BYTE_OUT (PIC_IMASK (PIC1_BASE_ADR), sysPicMask1 | sysPicLevel1);
}
}
/*******************************************************************************
*
* sysIbcEpicConnect - routine to connect IBC interrupts to EPIC
*
* This function is called from sysHwInit2 and sets the IBC interrupt
* handler into the EPIC interrupt vector table.
*
* RETURNS: N/A
*/
LOCAL void sysIbcEpicConnect (void)
{
intConnect (INUM_TO_IVEC (PIB_INT_VEC), sysIbcIntHandler, 0);
intEnable (PIB_INT_LVL);
}
/******************************************************************************
*
* intTableShow - display the interrupt routine for a vector.
*
* This function displays the interrupt routines for the associated vector.
*
* RETURNS: OK always.
*/
STATUS sysIntTableShow
(
int vector /* display interrupt vector to attach */
)
{
INT_HANDLER_DESC * currHandler;
currHandler = sysIntTbl[(int) vector];
if ( sysIntTbl[(int) vector] == NULL )
{
printf ("empty list \n");
return (OK);
}
else
{
do
{
printf ("\nRoutine address : 0x%x \n", (unsigned int) currHandler->vec);
printf ("Routine parameter : 0x%x \n", currHandler->arg);
currHandler = currHandler->next;
}
while ( currHandler != NULL );
}
return (OK);
}
/******************************************************************************
*
* intTableShowAll - display the interrupt routines for a all vectors.
*
* This function displays the interrupt routines for the all vectors in the
* system interrupt table.
*
* RETURNS: OK always.
*/
STATUS sysIntTableShowAll
(
void
)
{
INT_HANDLER_DESC *currHandler;
int vector,
first,
last,
i;
printf ("system interrupt table:\n\n");
printf ("vector routine address parameter(s) \n");
printf ("--------------------------------------------- \n");
for (vector = 0, first = last = -1; vector < INT_TBL_SIZE; vector++)
{
currHandler = sysIntTbl[vector];
if ( sysIntTbl[vector] == NULL )
{
if (-1 == first)
{
first = vector;
}
else
{
last = vector;
}
}
else
{
/* Print empty vector(s) */
if (-1 != first)
{
if (-1 != last)
{
printf (" 0x%02x - 0x%02x ", first, last);
}
else
{
printf (" 0x%02x ", first);
}
printf (" --- --- \n");
first = last = -1;
}
/* Print linked list of interrupt handlers for this vector */
printf (" 0x%02x ", vector);
i = 0;
do
{
if (i > 0)
{
printf (" ** ");
}
printf (" 0x%08x ", (unsigned int) currHandler->vec);
printf (" 0x%08x \n", currHandler->arg);
currHandler = currHandler->next;
i++;
}
while ( currHandler != NULL );
}
}
return (OK);
}
/******************************************************************************
*
* sysEpicIntDisconnect - disconnect an interrupt handler fromthe system vector table
*
* This function disconnects an interrupt handler from the system vector table.
* If a multiple calls were previously made to intConnect() with the same
* , combination then only the first matched * found would be
* removed.
* Note that at the moment only the parameter and not the
* must match the arguments used at a previous sysEpicConnect call.
*
* RETURNS: OK/ERROR if either routine or parameter doesn't match.
*/
STATUS sysEpicIntDisconnect
(
VOIDFUNCPTR * vector, /* disconnect interrupt vector to attach */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine (currently not used) */
)
{
UINT lockKey;
INT_HANDLER_DESC * currHandler;
INT_HANDLER_DESC * tempHandler=0;
if ( ((int)vector < 0) || ((int)vector > 0xff) ) /* Out of Range? */
{
return (ERROR);
}
if ( sysIntTbl[(int) vector] == NULL )
{
return (OK);
}
else
{
tempHandler = NULL;
currHandler = sysIntTbl[(int) vector];
do
{
if ( ((UINT) routine == (UINT) currHandler->vec)
#if 0
/* The check of the parameter has been commented out, since the
SYS_INT_DISCONNECT macro in target/h/drv/end/fei82557End.h calls the
disconnect routine without the third argument (=parameter).*/
&& (parameter == currHandler->arg)
#endif
)
{
lockKey = intLock ();
if (NULL != tempHandler)
{
tempHandler->next = currHandler->next;
}
else
{
sysIntTbl[(int) vector] = currHandler->next;
}
/* Disable interupt if all handlers removed */
if (NULL == sysIntTbl[(int) vector])
{
(void)sysEpicIntDisable ((int) vector);
}
intUnlock (lockKey);
free (currHandler);
return (OK);
}
tempHandler = currHandler;
currHandler = currHandler->next;
}
while ( currHandler != NULL );
}
return (ERROR);
}
/******************************************************************************
*
* sysEpicExtSourceShow - display all external interrupt sources adjustments.
*
* This function displays vector, mask, activity, polarity, sense and
* priority adjustments of the EPIC external interrupt sources.
*
* RETURNS: OK always.
*/
void
sysEpicExtSourceShow(void)
{
int ix;
UINT32 regVal,
epicReg;
printf("\nEPIC External Direct/Serial Interrupt Sources:\n");
printf(" # address value vector mask act. pol. sense priority\n");
epicReg = EPIC_ADDR (EPIC_EXT_SRC0_VEC_PRI_REG);
for (ix = 0; ix < EPIC_EXT_SRC_CNT; ix++)
{
sysPciRead32 (epicReg, ®Val);
printf("%2d %8x %08x %3d %4d %4d %4d %5d %8d\n",
ix,
epicReg,
regVal,
regVal & 0x000000FF,
regVal >> 31,
(regVal & 40000000) >> 30,
(regVal & 0x00800000) >> 23,
(regVal & 0x00400000) >> 22,
(regVal & 0x000F0000) >> 16
);
epicReg += EPIC_REG_OFFSET * 2;
}
}
#if defined (IBC_INT_DEBUG)
void sysIbcIntShow (void)
{
UINT8 isr1,
isr2,
imr1,
imr2,
irr1,
irr2;
int oldLevel;
int retry,
i;
oldLevel = intLock ();
for (retry=0; retry < 1; retry ++)
{
IBC_BYTE_OUT (PIC_port1 (PIC1_BASE_ADR), PIC_OCW3_SEL + PIC_IRR_READ);
IBC_BYTE_IN (PIC_port1 (PIC1_BASE_ADR), &irr1);
IBC_BYTE_OUT (PIC_port1 (PIC2_BASE_ADR), PIC_OCW3_SEL + PIC_IRR_READ);
IBC_BYTE_IN (PIC_port1 (PIC2_BASE_ADR), &irr2);
IBC_BYTE_OUT (PIC_port1 (PIC1_BASE_ADR), PIC_OCW3_SEL + PIC_ISR_READ);
IBC_BYTE_IN (PIC_port1 (PIC1_BASE_ADR), &isr1);
IBC_BYTE_OUT (PIC_port1 (PIC2_BASE_ADR), PIC_OCW3_SEL + PIC_ISR_READ);
IBC_BYTE_IN (PIC_port1 (PIC2_BASE_ADR), &isr2);
IBC_BYTE_IN (PIC_port2 (PIC1_BASE_ADR), &imr1);
IBC_BYTE_IN (PIC_port2 (PIC2_BASE_ADR), &imr2);
}
intUnlock (oldLevel);
printf ("\nCascaded i8259 Registers:\n\n");
printf (" PIC1 PIC2\n");
printf ("------------------\n");
printf ("IMR %02x %02x\n", imr1, imr2);
printf ("IRR %02x %02x\n", irr1, irr2);
printf ("ISR %02x %02x\n", isr1, isr2);
printf ("\ni8259 interrupt count:\n");
printf ("# of i8259 interrupts: %d\n", sysIbcIntCnt);
printf ("# of i8259 spurious interrupts: %d\n", sysIbcPhantomIntCnt);
printf ("# of adjusted IRQ7 interrupts: %d\n", sysIbcAdjInt7Cnt);
printf ("# of adjusted IRQ15 interrupts: %d\n", sysIbcAdjInt15Cnt);
for (i = 0; i < 16; i++)
{
printf ("IRQ%02d: %d\n", i, sysIbcIntCntTbl[i]);
}
}
/******************************************************************************
*
* sysIbcIntShow - display interrupt debug information for IBC (i8259)
*
* This function displays the number of interrupts handled by the IBC interrupt
* handler. The macro IBC_INT_DEBUG must be defined to include this routine.
*
* RETURNS: none
*/
void i8259RegsGet (void)
{
int oldLevel;
int retry;
oldLevel = intLock ();
for (retry=0; retry < 1; retry ++)
{
IBC_BYTE_OUT (PIC_port1 (PIC1_BASE_ADR), PIC_OCW3_SEL + PIC_IRR_READ);
IBC_BYTE_IN (PIC_port1 (PIC1_BASE_ADR), &gIrr1);
IBC_BYTE_OUT (PIC_port1 (PIC2_BASE_ADR), PIC_OCW3_SEL + PIC_IRR_READ);
IBC_BYTE_IN (PIC_port1 (PIC2_BASE_ADR), &gIrr2);
IBC_BYTE_OUT (PIC_port1 (PIC1_BASE_ADR), PIC_OCW3_SEL + PIC_ISR_READ);
IBC_BYTE_IN (PIC_port1 (PIC1_BASE_ADR), &gIsr1);
IBC_BYTE_OUT (PIC_port1 (PIC2_BASE_ADR), PIC_OCW3_SEL + PIC_ISR_READ);
IBC_BYTE_IN (PIC_port1 (PIC2_BASE_ADR), &gIsr2);
IBC_BYTE_IN (PIC_port2 (PIC1_BASE_ADR), &gImr1);
IBC_BYTE_IN (PIC_port2 (PIC2_BASE_ADR), &gImr2);
}
intUnlock (oldLevel);
}
void i8259RegsShow (void)
{
printf ("\nCascaded i8259 Registers:\n\n");
printf (" PIC1 PIC2\n");
printf ("------------------\n");
printf ("IMR %02x %02x\n", gImr1, gImr2);
printf ("IRR %02x %02x\n", gIrr1, gIrr2);
printf ("ISR %02x %02x\n", gIsr1, gIsr2);
printf ("\n\n");
}
#endif /* defined (IBC_INT_DEBUG) */
#if defined (EPIC_INT_DEBUG)
/******************************************************************************
*
* sysEpicIntShow - display interrupt debug information for EPIC
*
* This function displays the number of interrupts handled by the EPIC interrupt
* handler. The macro EPIC_INT_DEBUG must be defined to include this routine.
*
* RETURNS: none
*/
void
sysEpicIntShow (void)
{
int lockKey,
i;
unsigned long localEpicIntCnt = 0;
unsigned long localEpicSpuriousIntCnt = 0;
unsigned long localEpicUninitIntCnt = 0;
unsigned long localIntVecCnt[INT_TBL_SIZE];
lockKey = intLock ();
localEpicIntCnt = sysEpicIntCnt;
localEpicSpuriousIntCnt = sysEpicSpuriousIntCnt;
localEpicUninitIntCnt = sysEpicUninitIntCnt;
memcpy (&localIntVecCnt, &sysIntVecCnt, sizeof(localIntVecCnt));
intUnlock (lockKey);
printf ("\nEPIC Interrupt Count Summary:\n");
printf (" # of total EPIC interrupts: %8ld\n", localEpicIntCnt);
printf (" # of spurious EPIC interrupts: %8ld\n", localEpicSpuriousIntCnt);
printf (" # of uninitialized EPIC interrupts: %8ld\n", localEpicUninitIntCnt);
/* Print interrupt vector count table */
printf ("\nInterrupt Vector Count Summary:\n");
for ( i = 0; i < INT_TBL_SIZE; i++ )
{
if (localIntVecCnt[i] != 0)
{
printf (" # of interrupts for vector 0x%02x: %8ld\n", i, localIntVecCnt[i]);
}
}
}
#endif /* defined (EPIC_INT_DEBUG) */
/******************************************************************************
*
* sysSpuriousIntConnect - connect handler for spurious interrupts
*
* This function connects an interrupt handler for spurious
* interrupts. It is done by setting the _func_spuriousIntHook.
* Upon a spurious interrupt the handler will be called with 2 parameter:
* the supplied and the interrupt vector number.
*
* RETURNS: OK, or ERROR if the cannot be connected.
*/
STATUS sysSpuriousIntConnect
(
VOIDFUNCPTR routine, /* routine called upon spurious or un-initialised */
void *arg /* argument with which to call routine */
)
{
_func_spuriousIntHook = routine;
spuriousHandlerArg = arg;
return OK;
}
/******************************************************************************
*
* sysUninitIntConnect - connect handler for uninitialised interrupts
*
* This function connects an interrupt handler for un-initialised
* interrupts. It is done by setting the _func_uninitIntHook.
* Upon an un-intialised interrupt the handler will be called with 2 parameter:
* the supplied and the interrupt vector number.
*
* RETURNS: OK, or ERROR if the cannot be connected.
*/
STATUS sysUninitIntConnect
(
VOIDFUNCPTR routine, /* routine called upon un-initialised IRQs */
void *arg /* argument with which to call routine */
)
{
_func_uninitIntHook = routine;
uninitIntHandlerArg = arg;
return OK;
}