📄 kahluaepic.c
字号:
/* kahluaEpic.c - EPIC Interrupt Controller driver *//* Copyright 1984-2002 Wind River Systems, Inc. *//* Copyright 1996,1997,1998,1999 Motorola, Inc., All Rights Reserved */#include "copyright_wrs.h"/*modification history--------------------01f,25apr02,dat SPR 62758, incorrent timer setup, added comment about external src's not being active.01e,15jun00,dmw updated following WRS code review.01d,28may99,dmw Updated to WindRiver coding standards.01c,19feb99,dmw Added code to wait for EPIC reset to complete.01b,17feb99,dmw Changed sysIn/OutLongs to sysPciIn/OutLongs.01a,12feb99,dmw Created.*//*DESCRIPTIONThis module implements the EPIC interrupt controller functionality.*//* includes */#include "kahlua.h"#include "kahluaEpic.h"/* defines *//* globals */IMPORT STATUS (*_func_intConnectRtn) (VOIDFUNCPTR *, VOIDFUNCPTR, int);IMPORT int (*_func_intEnableRtn) (int);IMPORT int (*_func_intDisableRtn) (int);IMPORT UINT32 sysPciInLong (UINT32);IMPORT void sysPciOutLong (UINT32, UINT32);IMPORT STATUS excIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR);IMPORT UINT sysGetMpuSpd(void);IMPORT void sysDecDelay (UINT usDelay);void sysEpicIntHandler (void);/* system interrupt table */#define SYSTEM_INTERRUPT_TABLE_SIZE 256INT_HANDLER_DESC * sysIntTbl [SYSTEM_INTERRUPT_TABLE_SIZE];#ifdef INCLUDE_INSTRUMENTATION IMPORT int evtTimeStamp;#endif /* INCLUDE_INSTRUMENTATION *//* forward declarations */LOCAL int getEpicVecAddr (int);LOCAL STATUS sysEpicIntConnect (VOIDFUNCPTR * vector, VOIDFUNCPTR routine, int parameter);LOCAL int sysEpicIntEnable (int);LOCAL int sysEpicIntDisable (int);#ifndef CPU_INT_LOCK# define CPU_INT_LOCK(x) \ (*x = intLock ())#endif /* CPU_INT_LOCK */#ifndef CPU_INT_UNLOCK# define CPU_INT_UNLOCK(data) \ (intUnlock (data))#endif /* CPU_INT_UNLOCK *//******************************************************************************** sysEpicInit - initialize the EPIC** This function initializes the Embedded Programmable Interrupt Controller * (EPIC) contained in the Kahlua chip.** 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,* and enables interrupt handling by the EPIC.** RETURNS: OK always*/STATUS sysEpicInit (void) { int i; UINT32 temp = 0; /* Initialize the interrupt table */ for (i = 0; i < SYSTEM_INTERRUPT_TABLE_SIZE; i++) sysIntTbl[i] = NULL; /* connect the interrupt demultiplexer to the PowerPC external interrupt */ excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, sysEpicIntHandler); /* attach the BSP specific routines to the operating system. */ _func_intConnectRtn = sysEpicIntConnect; _func_intEnableRtn = sysEpicIntEnable; _func_intDisableRtn = sysEpicIntDisable; /* Initialze the global timer frequency to the MPU speed. */ sysPciOutLong((UINT32)EPIC_TIMER_FREQ_REG, sysGetMpuSpd()); /* Initialze the 4 global timer interrupt sources */ sysPciOutLong((UINT32)EPIC_TIMER0_VEC_PRI_REG, INIT_TMR_SRC0); sysPciOutLong((UINT32)EPIC_TIMER1_VEC_PRI_REG, INIT_TMR_SRC1); sysPciOutLong((UINT32)EPIC_TIMER2_VEC_PRI_REG, INIT_TMR_SRC2); sysPciOutLong((UINT32)EPIC_TIMER3_VEC_PRI_REG, INIT_TMR_SRC3); /* Initialize the 16 serial interrupt sources */ sysPciOutLong((UINT32)EPIC_SER_SRC0_VEC_PRI_REG, INIT_SER_SRC0); sysPciOutLong((UINT32)EPIC_SER_SRC1_VEC_PRI_REG, INIT_SER_SRC1); sysPciOutLong((UINT32)EPIC_SER_SRC2_VEC_PRI_REG, INIT_SER_SRC2); sysPciOutLong((UINT32)EPIC_SER_SRC3_VEC_PRI_REG, INIT_SER_SRC3); sysPciOutLong((UINT32)EPIC_SER_SRC4_VEC_PRI_REG, INIT_SER_SRC4); sysPciOutLong((UINT32)EPIC_SER_SRC5_VEC_PRI_REG, INIT_SER_SRC5); sysPciOutLong((UINT32)EPIC_SER_SRC6_VEC_PRI_REG, INIT_SER_SRC6); sysPciOutLong((UINT32)EPIC_SER_SRC7_VEC_PRI_REG, INIT_SER_SRC7); sysPciOutLong((UINT32)EPIC_SER_SRC8_VEC_PRI_REG, INIT_SER_SRC8); sysPciOutLong((UINT32)EPIC_SER_SRC9_VEC_PRI_REG, INIT_SER_SRC9); sysPciOutLong((UINT32)EPIC_SER_SRC10_VEC_PRI_REG, INIT_SER_SRC10); sysPciOutLong((UINT32)EPIC_SER_SRC11_VEC_PRI_REG, INIT_SER_SRC11); sysPciOutLong((UINT32)EPIC_SER_SRC12_VEC_PRI_REG, INIT_SER_SRC12); sysPciOutLong((UINT32)EPIC_SER_SRC13_VEC_PRI_REG, INIT_SER_SRC13); sysPciOutLong((UINT32)EPIC_SER_SRC14_VEC_PRI_REG, INIT_SER_SRC14); sysPciOutLong((UINT32)EPIC_SER_SRC15_VEC_PRI_REG, INIT_SER_SRC15); /* Initialize the 4 external interrupt sources */ /* These may not do anything since the device is in serial mode */ sysPciOutLong((UINT32)EPIC_EXT_SRC0_VEC_PRI_REG, INIT_EXT_SRC0); sysPciOutLong((UINT32)EPIC_EXT_SRC1_VEC_PRI_REG, INIT_EXT_SRC1); sysPciOutLong((UINT32)EPIC_EXT_SRC2_VEC_PRI_REG, INIT_EXT_SRC2); sysPciOutLong((UINT32)EPIC_EXT_SRC3_VEC_PRI_REG, INIT_EXT_SRC3); /* Initialize the 2 DMA interrupt sources */ sysPciOutLong((UINT32)EPIC_DMA_CHAN0_INTR_VEC_SRC, INIT_DMA_SRC0); sysPciOutLong((UINT32)EPIC_DMA_CHAN1_INTR_VEC_SRC, INIT_DMA_SRC1); /* Initialize the I2C unit interrupt source */ sysPciOutLong((UINT32)EPIC_I2C_INTR_VEC_SRC, INIT_I2C_SRC); /* Initialize the message unit interrupt source. */ sysPciOutLong((UINT32)EPIC_MSG_UNIT_INTR_VEC_SRC, INIT_MSGUNIT_SRC); /* Setup the EPIC to mixed mode. */ temp = sysPciInLong((UINT32)EPIC_GLOBAL_CONFIG_REG ); sysPciOutLong((UINT32)EPIC_GLOBAL_CONFIG_REG, (temp | EPIC_GC_MIXED)); /* Set to serial-interrupt mode (16 sources) and clock ratio to 4. */ temp = sysPciInLong((UINT32)EPIC_INTR_CONFIG_REG); sysPciOutLong((UINT32)EPIC_INTR_CONFIG_REG, (temp | (EPIC_IC_R_VALUE << EPIC_IC_R_SHFT) | EPIC_IC_SIE)); /* Enable interrupts for this processor (1 and above). */ sysPciOutLong((UINT32)EPIC_CUR_TASK_PRI_REG, EPIC_TASK_PRI_1); 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; /* validate the vector */ if (((int)vector < 0) || ((int)vector > (SYSTEM_INTERRUPT_TABLE_SIZE - 1))) return (ERROR); /* 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 = getEpicVecAddr((int)vector); if (connect.regAddr > 0) { /* read the vector register */ connect.regVal = sysPciInLong((UINT32)(connect.regAddr)); /* store the interrupt vector number */ connect.regVal |= (int)vector; /* write the contents of the vector register back */ sysPciOutLong((UINT32)(connect.regAddr), connect.regVal); } return (OK); }/******************************************************************************** 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; /* Validate vector. */ if (intLevel < 0) return (ERROR); enable.regAddr = getEpicVecAddr(intLevel); if (enable.regAddr > 0) { /* read the vector register */ enable.regVal = sysPciInLong((UINT32)(enable.regAddr)); /* enable the interrupt */ enable.regVal &= (~INT_MASK_BIT); /* write the contents of the vector register back */ sysPciOutLong((UINT32)(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; /* Validate vector. */ if (intLevel < 0) return (ERROR); /* get the vector reg. offset value */ disable.regAddr = getEpicVecAddr(intLevel); if (disable.regAddr > 0) { /* read the vector register */ disable.regVal = sysPciInLong((UINT32)(disable.regAddr)); /* disable the interrupt */ disable.regVal |= INT_MASK_BIT; /* write the contents of the vector register back */ sysPciOutLong((UINT32)(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; /* get the vector from the EPIC IACK reg. */ vecNum = sysPciInLong((UINT32)EPIC_IACK_REG); vecNum &= VECTOR_MASK; /* Check for spurious interrupt. */ if (vecNum == 0xFF) { logMsg ("EPIC Spurious Interrupt!\n", 0,0,0,0,0,0); 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);#ifdef INCLUDE_INSTRUMENTATION if (evtLogTIsOn) (* _func_evtLogT1_noTS) (EVENT_INT_ENT((int)vecNum), evtTimeStamp);#endif /* INCLUDE_INSTRUMENTATION */ /* call the necessary interrupt handlers */ if ((currHandler = sysIntTbl[vecNum]) == NULL) { logMsg ("uninitialized EPIC interrupt %d\r\n", vecNum, 0,0,0,0,0); } else { /* Call EACH respective chained interrupt handler */ while (currHandler != NULL) { currHandler->vec (currHandler->arg); currHandler = currHandler->next; } } /* Disable external interrupts. */ CPU_INT_LOCK(&dontCare); /* * ERRATA FIX: * sysDecDelay() is needed for Kahlua(MPC8240) Revision 1.0/1.1 * Errata #2, EPIC Serial Mode Interrupt Twice from Single Source. * See Kahlua Errata Sheet - Version 1.0.3 */ sysDecDelay(4); /* Issue an end-of-interrupt to the EPIC */ sysPciOutLong((UINT32)EPIC_EOI_REG, 0); return; }/******************************************************************************** getEpicVecAddr - get the vector address of an EPIC register ** This routine returns the appropriate EPIC register address based on the* specified EPIC interrupt level.** RETURNS: EPIC register address or zero if not a supported level.*/LOCAL int getEpicVecAddr ( int intLevel /* interrupt level to translate */ ) { int offset = 0; /* check for a timer interrupt level */ if ((intLevel >= TIMER_INTERRUPT_BASE) && (intLevel < EXTERNAL_INTERRUPT_BASE)) { offset = intLevel - TIMER_INTERRUPT_BASE; offset = (int)EPIC_TIMER0_VEC_PRI_REG + (offset * REG_OFFSET * 4); } /* check for external interrupt level */ if ((intLevel >= EXTERNAL_INTERRUPT_BASE) && (intLevel < INTERNAL_INTERRUPT_BASE)) { offset = intLevel - EXTERNAL_INTERRUPT_BASE; offset = (int)EPIC_EXT_SRC0_VEC_PRI_REG + (offset * REG_OFFSET * 2); } /* check for a serial interrupt level */ if (intLevel >= SERIAL_INTERRUPT_BASE) { offset = intLevel - SERIAL_INTERRUPT_BASE; offset = (int)EPIC_SER_SRC0_VEC_PRI_REG + (offset * REG_OFFSET * 2); } return (offset); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -