📄 sysepic.c
字号:
/* sysEpic.c - Driver for Embedded Programmable Interrupt Controller *//* Copyright 1984-2003 Wind River Systems, Inc. *//*modification history--------------------01g,19oct04,dtr SPR 102606.01f,06may04,mil Removed compiler warnings.01e,13oct03,mil Added options for polarity and sense.01d,12sep03,mil Added support for critical interrupts.01c,08jan03,mil Created based on Sandpoint MPC107.*//*DESCRIPTIONThis module implements the Embedded Programmable Interrupt Controller (EPIC)driver for the MPC8540.The EPIC is an integrated interrupt controller in the 8540 whichprovides following major capabilities: Support for twelve external interrupt sources and thirty-two internal interrupt sources Support for connection of external interrupt controller device e.g. 8259 like as implemented on a WinBond chip 12 external interrupt sources 32 internal interrupt sources 16 programmable interrupt priority levels Fully-nested interrupt delivery Spurious vector generation Route to critical interrupt destinations Route to external pin Configurable sense and polarity at initialization and runtimeThe current implementation of this EPIC controller does not supportthe following features or mode of operations: PIC global timers Inter-processor interrupts Messaging interruptsEPIC features are customized by writing into general control registersor into interrupt level specific registers (IVPRs).This driver allows a basic interface to the EPIC such as intializing it,setting interrupt vectors, priorities, level/edge sense and interruptpolarities, as well as enabling and disabling specific interrupts.This driver implements a complete interrupt architecture system, completewith vector table.Since interrupt vectors can be shared, this driver does provide foroverloading of interrupt routines (i.e. there isa list of interrupt routines for each interrupt vector (level)). To servicea vector requires that all connected interrupt routines be called in orderof their connection.The following diagram shows an example of how interrupts canbe configured in this system. EPIC Vector table0 |-------| <-- external INT0 starts |-------| |-------|------------------------------+ .... | |-------| | |-------| |12 |-------| <-- internal INT0 starts | (EPIC_MAX_EXT_IRQS) = 12 |-------| | |-------| | .... | |-------| | |-------| |44 |-------| <-- global timer INT0 starts | (EPIC_MAX_EXT_IRQS + \ |-------| | EPIC_MAX_IN_IRQS) = 44 |-------| | |-------| |48 |-------| <-- message INT0 starts | (EPIC_MAX_EXT_IRQS + \ |-------| | EPIC_MAX_IN_IRQS + \ |-------| | EPIC_MAX_GT_IRQS) = 48 |-------| |52 |-------| <-- IPI INT0 starts | (EPIC_MAX_EXT_IRQS + \ |-------| | EPIC_MAX_IN_IRQS + \ |-------| | EPIC_MAX_GT_IRQS + \55 |-------| | EPIC_MAX_MSG_IRQS) = 5256 |-------|<-----------------------------+ sysVectorIRQ0 = 56 \ .... WinBond int handler | = 52 + EPIC_MAX_IPI_IRQS |-------| +-------------+ |-------| | |-------| PCI slot 3 int handler |-------| |-------|<----- Cascaded 8259s |-------| |-------| .... |-------| |-------| |-------| |-------|256|-------|The driver is designed to put external interrupts at the beginning of thevector table. As a result, devices that route their interrupt to the EPICon the MPC8540 does not need to translate the vector number. Therefore,the macros IVEC_TO_INUM(x) and INUM_TO_IVEC(x) are not necessary. Forsome existing drivers, it may be necessary to use the following defines: #undef INUM_TO_IVEC #define INUM_TO_IVEC(x) (x) #undef IVEC_TO_INUM #define IVEC_TO_INUM(x) (x)If there are other devices in the system capable of generating their ownvectors then we presume that an appropriate interrupt handler is createdand attached to the vector associated with the correct IRQ number. Thatinterrupt handler would get a new vector directly from the device and thencall all of the handlers attached to that new vector. Vector information isstored in a linked list of INT_HANDLER_DESC structures. The sysIntTbl arraycontains a pointer to the first entry for each vector..SH INITIALIZATIONThis driver is initialized from the BSP, usually as part of sysHwInit().The first routine to be called is sysEpicInit(). The routine resets theglobal configuration register and resets the epic registers to defaultvalues.The second routine to be called is sysEpicIntrInit(). This routine takes noarguments. This routine allocates the vector table and initializes thechips to a default state. All individual interrupt sources are disabled.Each has to be individually enabled by intEnable() before it will beunmasked and allowed to generate an interrupt..SH CRITICAL INTERRUPTTo enable the EPIC to handle also critical interrupt, or if a normalinterrupt is to be rerouted to the critical input pin, INCLUDE_EPIC_CRT_INTRshould be defined. e.g. Define the following in config.h: #define INCLUDE_EPIC_CRT_INTR /@ include critical interrupt support @/The critical interrupt handler uses information from the summary registersCISR0 and CISR1. The EPIC does not manage critical interrupts and henceIack or EOI do not apply. It was seen that the summary registers gothrough a transient state before settling on the result. This causesspurious interrupts to be generated, and the vectors being called.A typical behavior is the printout of "uninitialized PIC interruptvector 0xXX". This is observed only when at least one source has beenrouted to critical pin..SH CUSTOMIZING THIS DRIVERThe BSP can change the default polarity and sensitivity for the externalinterrupt and the internal interrupt independently. They are: EPIC_EX_DFT_SENSE /@ default to EPIC_SENSE_LVL @/ EPIC_EX_DFT_POLAR /@ default to EPIC_INT_ACT_HIGH @/ EPIC_IN_DFT_POLAR /@ default to EPIC_INT_ACT_HIGH @/If any of the above is defined before the inclusion of sysEpic.h, such asin config.h, the default will be overridden. The available options are: EPIC_EX_DFT_SENSE EPIC_SENSE_LVL, EPIC_SENSE_EDG EPIC_xx_DFT_POLAR EPIC_INT_ACT_LOW, EPIC_INT_ACT_HIGH /@if level-sense @/ EPIC_INT_EDG_NEG, EPIC_INT_EDG_POS /@if edge-sense @/The macros CPU_INT_LOCK() and CPU_INT_UNLOCK provide the accessto the CPU level interrupt lock/unlock routines. We presume that thereis a single interrupt line to the CPU. By default these macros callintLock() and intUnlock() respectively.*//* includes */#include "vxWorks.h"#include "config.h"#include "sysEpic.h"#include "sysLib.h"#include "stdio.h"#include "string.h"#ifdef INCLUDE_WINDVIEW#include "private/eventP.h"#endif/* defines */#ifndef CPU_INT_LOCK# define CPU_INT_LOCK(pData) \ (*pData = intLock ())#endif#ifndef CPU_INT_UNLOCK# define CPU_INT_UNLOCK(data) \ (intUnlock (data))#endif/* externs */IMPORT STATUS excIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR);IMPORT STATUS excIntCrtConnect (VOIDFUNCPTR *, VOIDFUNCPTR);#if FALSE#if defined(INCLUDE_WINDVIEW) || defined(INCLUDE_INSTRUMENTATION)IMPORT int evtTimeStamp; /* Windview 1.0 only */#endif /* WINDVIEW||INSTRUMENTATION */#endif /* FALSE *//* get the interrupt hook routines prototypes*/IMPORT STATUS (*_func_intConnectRtn) (VOIDFUNCPTR *, VOIDFUNCPTR, int);IMPORT int (*_func_intEnableRtn) (int);IMPORT int (*_func_intdisableRtn) (int);/* globals */INT_HANDLER_DESC * sysIntTbl [INTERRUPT_TABLESIZE]; /* system interrupt tbl *//* locals *//* forward declarations */LOCAL int epicIntEnable (ULONG srcAddr);LOCAL int epicIntDisable (ULONG srcAddr);LOCAL int epicVecOptionsSet (ULONG srcAddr, UINT32 mask, UINT32 options);LOCAL UINT32 epicVecOptionsGet (ULONG srcAddr);LOCAL void sysEpicIntHandlerExec (int vector);LOCAL void sysEpicIntHandler (void);#ifdef INCLUDE_EPIC_CRT_INTRLOCAL void sysEpicCrtIntHandler (void);LOCAL int epicCrtIntSet (ULONG srcAddr);LOCAL int epicCrtIntUnset (ULONG srcAddr);LOCAL int epicCrtIntGet (ULONG srcAddr);#endif /* INCLUDE_EPIC_CRT_INTR */LOCAL int epicSrcAddrCheck (ULONG srcAddr);/********************************************************************************* sysEpicInit - initialize the epic controller** This routine resets the global Configuration Register, thus it:* - disables all interrupts* - sets epic registers to reset values** It then sets the EPIC operation mode to Mixed Mode (vs. Pass Through* mode). At this point only mixed mode is supported which means the EPIC* is not configured for the pass through mode.** Only direct interrupt sources is supported by the PIC. Serial * stype interrupt is not available.** NOMANUAL* * RETURNS: N/A*/ void sysEpicInit ( void ) { ULONG gcrVal; int irq; gcrVal = sysEpicRegRead (EPIC_GLOBAL_REG); gcrVal |= (EPIC_GCR_RESET); sysEpicRegWrite (EPIC_GLOBAL_REG, gcrVal); /* wait for the reset sequence to be completed */ while (sysEpicRegRead (EPIC_GLOBAL_REG) & EPIC_GCR_RESET) { ; /* do nothing */ } gcrVal = sysEpicRegRead (EPIC_GLOBAL_REG); gcrVal |= (EPIC_GCR_MODE_MIXED); /* configure for mixed mode */ sysEpicRegWrite (EPIC_GLOBAL_REG, gcrVal); /* Clear all pending interrupt */ while (((USHORT) epicIntAck()) != (USHORT) 0xffff) { /* do nothing */ } /* init all EIVPRs to sense = 1, polarity = defined, vec = 0, prio = 0 */ for (irq = 0; irq < EPIC_MAX_EXT_IRQS; irq++) { epicIntDisable (EPIC_EX_VEC_REG(irq)); epicIntSourceSet (EPIC_EX_VEC_REG(irq), EPIC_EX_DFT_POLAR, EPIC_EX_DFT_SENSE, 0x0, 0x0); } /* init all IIVPRs to polarity = defined, vec = 0, prio = 0 */ for (irq = 0; irq < EPIC_MAX_IN_IRQS; irq++) { epicIntDisable (EPIC_IN_VEC_REG(irq)); epicIntSourceSet (EPIC_IN_VEC_REG(irq), EPIC_IN_DFT_POLAR, 0x0, 0x0, 0x0); } /* init all GTVPRs to vec = 0, prio = 0 */ for (irq = 0; irq < EPIC_MAX_GT_IRQS; irq++) { epicIntDisable (EPIC_GT_VEC_REG(irq)); epicIntSourceSet (EPIC_GT_VEC_REG(irq), 0x0, 0x0, 0x0, 0x0); } /* init all MIVPRs to vec = 0, prio = 0 */ for (irq = 0; irq < EPIC_MAX_MSG_IRQS; irq++) { epicIntDisable (EPIC_MSG_VEC_REG(irq)); epicIntSourceSet (EPIC_MSG_VEC_REG(irq), 0x0, 0x0, 0x0, 0x0); } /* disable IPIs */ for (irq = 0; irq < EPIC_MAX_IPI_IRQS; irq++) { epicIntDisable (EPIC_IPI_VEC_REG(irq)); epicIntSourceSet (EPIC_IPI_VEC_REG(irq), 0x0, 0x0, 0x0, 0x0); } epicCurTaskPrioSet (EPIC_PRIORITY_MAX); /* set it to highest priority */ }/********************************************************************************* sysEpicIntrInit - initialize the interrupt table** This function initializes the interrupt mechanism of the board.** RETURNS: OK, always.*/STATUS sysEpicIntrInit (void) { int vector; int rc; /* initialize the interrupt table */ for (vector = 0; vector < INTERRUPT_TABLESIZE; vector++) { sysIntTbl [vector] = NULL; } /* * connect the interrupt demultiplexer to the PowerPC external * interrupt exception vector. * i. e. put the address of this interrupt handler in * the PowerPC's only external interrupt exception vector * which is _EXC_OFF_INTR = 0x500 * Also connect critical input pin handler _EXC_OFF_CRTL = 0x100. */ rc = excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, sysEpicIntHandler);#ifdef INCLUDE_EPIC_CRT_INTR rc = excIntCrtConnect ((VOIDFUNCPTR *) _EXC_OFF_CRTL, sysEpicCrtIntHandler);#endif /* INCLUDE_EPIC_CRT_INTR */ /* * set up the BSP specific interrupt routines * Attach the local routines to the VxWorks system calls * */ _func_intConnectRtn = sysEpicIntConnect; _func_intEnableRtn = sysEpicIntEnable; _func_intDisableRtn = sysEpicIntDisable; epicCurTaskPrioSet (EPIC_PRIORITY_MIN); /* set it to lowest priority */ return (rc); }/********************************************************************************* sysEpicIntEnable - enable a EPIC interrupt level** This routine enables a specified EPIC interrupt level.** NOMANUAL** RETURNS: OK, ERROR, or EPIC_INV_INTER_SOURCE.** NOTE: To allow compatibility, sysEpicIntEnable() can be used only for* external and internal interrupts, and not GT, MSG, IPI. It* assumes there are more internal IRQs than external. It also* gives priority to external over internal given the same IRQ* is valid for both external and internal.*/int sysEpicIntEnable ( int vector ) { if ((vector < 0) || (vector >= EPIC_MAX_ALL_IRQS)) return (ERROR); /* enable interrupt on EPIC */ return epicIntEnable ( epicGetVecRegAdrs (vector) ); }/********************************************************************************* sysEpicIntDisable - disable a EPIC interrupt level** This routine disables a specified EPIC interrupt level.** NOMANUAL** RETURNS: OK, ERROR, or EPIC_INV_INTER_SOURCE.** NOTE: To allow compatibility, sysEpicIntDisable() can be used only for* external and internal interrupts, and not GT, MSG, IPI. It* assumes there are more internal IRQs than external. It also* gives priority to external over internal given the same IRQ* is valid for both external and internal.*/int sysEpicIntDisable ( int vector ) { if ((vector < 0) || (vector >= EPIC_MAX_ALL_IRQS)) return (ERROR); /* disable interrupt on EPIC */ return epicIntDisable ( epicGetVecRegAdrs (vector) ); }/*******************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -