/* vxbArmGenIntCtlrV3.c - ARM generic interrupt controller driver */ /* * * This program is OPEN SOURCE software: you can redistribute it and/or modify it; * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WRS_CONFIG_SV_INSTRUMENTATION # include #endif /* _WRS_CONFIG_SV_INSTRUMENTATION */ #include #include #include #include #include #include #include <../src/hwif/intCtlr/vxbIntCtlrLib.h> #include #include "../h/vxbus/vxbAccess.h" #include "vxbArmGenIntCtlrV3.h" #include "ft2000-4.h" #ifdef _WRS_CONFIG_SMP # include # include #endif /* define */ #ifdef ARMBE8 # define SWAP32 vxbSwap32 # define SWAP64(var64) ((SWAP32((var64) & 0x00000000FFFFFFFF) << 32) | \ (SWAP32(((var64) & 0xFFFFFFFF00000000) >> 32))) #else # define SWAP32 # define SWAP64 #endif /* ARMBE8 */ /* vxBus Driver Name */ #define GIC_NAME "armGicDev" /* Connect the interrupt handler to it's exception vector */ #define INTR_EXC_ID (EXC_OFF_IRQ) /* exception id, for external interrupt */ #define GIC_IPI_PRIORITY 0 #define GIC_PRIORITY_LEVEL_STEP 0x10 #define GIC_SPI_PRIORITY_DEFAULT 0x10101010 #ifndef EXC_CONNECT_INTR_RTN # define EXC_CONNECT_INTR_RTN(rtn) \ excIntConnect ((VOIDFUNCPTR *)INTR_EXC_ID,rtn) #endif /* This sets the CPU interrupt enable on */ #ifndef CPU_INTERRUPT_ENABLE # define CPU_INTERRUPT_ENABLE intCpuUnlock(0) #endif /* This resets the CPU interrupt enable */ #ifndef CPU_INTERRUPT_DISABLE # define CPU_INTERRUPT_DISABLE intCpuLock() #endif #define GIC_ISR(pEnt,inputPin,func) \ { \ struct vxbIntCtlrPin * pPin = \ vxbIntCtlrPinEntryGet(pEnt,inputPin); \ func = pPin->isr; \ } #define GIC_DESTCPU(pEnt,inputPin,destCpu) \ { \ struct vxbIntCtlrPin * pPin = \ vxbIntCtlrPinEntryGet(pEnt,inputPin); \ destCpu = pPin->pinCpu; \ } /* structure holding Generic Interupt Controller details */ typedef struct armGicDrvCtrl { VXB_DEVICE_ID pInst; /* instance pointer */ BOOL initialized; struct intCtlrHwConf isrHandle; int intMode; /* type of interrupt handling*/ void * gicBase; /* gic base address */ INT32 gicDistOffset; /* distributor register base offset */ INT32 gicReDistOffset; /* Rdistributor register base offset */ INT32 gicCpuOffset; /* CPU interface register base offset */ UINT32 gicLvlCurrent; void * regBase; void * handle; INT32 gicLvlNum; /* the maximum interrupt level number */ INT32 gicCpuNum; /* the maximum CPU number in system */ } ARM_GIC_DRV_CTRL; /* forward declarations */ IMPORT STATUS (*_func_intConnectRtn) (VOIDFUNCPTR *, VOIDFUNCPTR, int); IMPORT STATUS (*_func_intDisconnectRtn) (VOIDFUNCPTR *, VOIDFUNCPTR, int); IMPORT UINT32 vxCpuIdGetByIndex(UINT32 idx); LOCAL STATUS vxbArmGicDevInit (VXB_DEVICE_ID pInst); #ifdef _WRS_CONFIG_SMP STATUS vxbArmGicLvlVecChk (VXB_DEVICE_ID pInst, int*, int*, int*); STATUS vxbArmGicLvlVecAck (VXB_DEVICE_ID pInst, int, int, int); #else STATUS vxbArmGicLvlVecChk (VXB_DEVICE_ID pInst, int*, int*); STATUS vxbArmGicLvlVecAck (VXB_DEVICE_ID pInst, int, int); #endif int vxbArmGicLvlChg (VXB_DEVICE_ID pInst, int); LOCAL STATUS vxbArmGicIntDevInit (int cpuNum); #ifdef INCLUDE_SHOW_ROUTINES void vxbArmGicDataShow (VXB_DEVICE_ID pInst, int *dummy); #endif /* INCLUDE_SHOW_ROUTINES */ LOCAL void vxbArmGicCtlInit(VXB_DEVICE_ID pInst); LOCAL void vxbArmGicCtlInit2(VXB_DEVICE_ID pInst); LOCAL STATUS sysArmGicConnect ( VOIDFUNCPTR * vector, /* interrupt vector to attach to */ VOIDFUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ ); LOCAL STATUS sysArmGicDisconnect ( VOIDFUNCPTR * vector, /* interrupt vector to detach from */ VOIDFUNCPTR routine, /* routine to be disconnected */ int parameter /* parameter to be matched */ ); LOCAL STATUS sysArmGicISREnable ( struct intCtlrHwConf * pEntries, int inputPin ); LOCAL STATUS sysArmGicEnable ( int vector ); LOCAL STATUS sysArmGicISRDisable ( struct intCtlrHwConf * pEntries, int inputPin ); LOCAL STATUS sysArmGicDisable ( int vector ); LOCAL STATUS vxbArmGicConnect ( VXB_DEVICE_ID pIntCtlr, /* int Ctlr device struct */ VXB_DEVICE_ID pDev, /* device being connnected */ int index, /* device index */ void (*pIsr)(void * pArg), /* isr being connected */ void * pArg, /* isr's arg */ int * pInputPin /* input pin device is on */ ); LOCAL STATUS vxbArmGicDisconnect ( VXB_DEVICE_ID pIntCtlr, /* int Ctlr device struct */ VXB_DEVICE_ID pDev, /* device being connnected */ int index, /* device index */ VOIDFUNCPTR pIsr, /* isr being connected */ void * pArg /* isr's arg */ ); LOCAL STATUS vxbArmGicEnable ( VXB_DEVICE_ID pIntCtlr, /* int Ctlr device struct */ VXB_DEVICE_ID pDev, /* device being connnected */ int index, /* device index */ VOIDFUNCPTR pIsr, /* isr being connected */ void * pArg /* isr's arg */ ); LOCAL STATUS vxbArmGicDisable ( VXB_DEVICE_ID pIntCtlr, /* int Ctlr device struct */ VXB_DEVICE_ID pDev, /* device being connnected */ int index, /* device index */ VOIDFUNCPTR pIsr, /* isr being connected */ void * pArg /* isr's arg */ ); LOCAL STATUS vxbArmGicLvlEnable(VXB_DEVICE_ID pInst, int level); LOCAL STATUS vxbArmGicLvlDisable(VXB_DEVICE_ID pInst, int level); LOCAL int vxbArmGicHwLvlChg(int level); #ifdef _WRS_CONFIG_SMP LOCAL STATUS vxbArmGicHwEnable(int inputPin); LOCAL STATUS vxbArmGicHwDisable(int inputPin); void sysArmGicDevInit(void); LOCAL STATUS vxbArmGicIpiGen(VXB_DEVICE_ID pCtlr, INT32 ipiId, cpuset_t cpus); LOCAL STATUS vxbArmGicIpiConnect(VXB_DEVICE_ID pCtlr, INT32 ipiId, \ IPI_HANDLER_FUNC ipiHandler, void * ipiArg); LOCAL STATUS vxbArmGicIpiDisconnect(VXB_DEVICE_ID pCtlr, INT32 ipiId, \ IPI_HANDLER_FUNC ipiHandler, void * ipiArg); LOCAL STATUS vxbArmGicIpiEnable(VXB_DEVICE_ID pCtlr, INT32 ipiId); LOCAL STATUS vxbArmGicIpiDisable(VXB_DEVICE_ID pCtlr, INT32 ipiId); LOCAL INT32 vxbArmGicIpiPrioGet(VXB_DEVICE_ID pCtlr, INT32 ipiId); LOCAL STATUS vxbArmGicIpiPrioSet(VXB_DEVICE_ID pCtlr, INT32 ipiId, \ INT32 prio); LOCAL VXIPI_CTRL_INIT * vxbArmGicIpiCtlGet(VXB_DEVICE_ID pInst, \ void * pArg); LOCAL STATUS vxbArmGicIntReroute(VXB_DEVICE_ID pDev, int index, \ cpuset_t destCpu); LOCAL STATUS vxbArmGicCpuReroute(VXB_DEVICE_ID pDev,void * destCpu); METHOD_DECL(vxbArmGicIntCtlInit); DEVMETHOD_DEF(vxbArmGicIntCtlInit, "Init ARM general interrupt controller"); #endif /* _WRS_CONFIG_SMP */ /* GIC base address */ LOCAL UINT32 armGicBase = 0; /* * Distributor and CPU interface register base offsets, * with backward-compatible default values for ARM11 MPCore and Cortex-A9 cores. */ LOCAL UINT32 armGicDistOffset = 0x1000; LOCAL UINT32 armGicReDistOffset = 0x1000; LOCAL UINT32 armGicCpuOffset = 0x100; LOCAL UINT32 gicVersion = GIC_VERSION_GIC400; /* armGicLinesNum is used to reduce interrupt process time */ LOCAL UINT32 armGicLinesNum = 0; /* GIC priority levels */ LOCAL UINT32 armGicPriorityLvlMax = 0; LOCAL VXB_DEVICE_ID vxbGicId; /* GIC device ID */ LOCAL ARM_GIC_DRV_CTRL * pVxbArmGicDrvCtrl = NULL; LOCAL struct drvBusFuncs vxbArmGicCtlFuncs = { vxbArmGicCtlInit, /* devInstanceInit */ vxbArmGicCtlInit2, /* devInstanceInit2 */ NULL /* devConnect */ }; /* vxBus vxbArmGicCtl driver registration data structure */ LOCAL struct vxbDevRegInfo armGicCtlRegistration = { NULL, /* pNext */ VXB_DEVID_DEVICE, /* devID */ VXB_BUSID_PLB, /* busID = PLB */ VXB_VER_4_0_0, /* vxbVersion */ GIC_NAME, /* drvName */ &vxbArmGicCtlFuncs, /* pDrvBusFuncs */ NULL, /* pMethods */ NULL, /* devProbe */ NULL /* pParamDefaults */ }; LOCAL device_method_t gicIntCtlr_methods[] = { DEVMETHOD(vxbIntCtlrConnect, vxbArmGicConnect), DEVMETHOD(vxbIntCtlrDisconnect, vxbArmGicDisconnect), DEVMETHOD(vxbIntCtlrEnable, vxbArmGicEnable), DEVMETHOD(vxbIntCtlrDisable, vxbArmGicDisable), #ifdef _WRS_CONFIG_SMP DEVMETHOD(vxIpiControlGet, vxbArmGicIpiCtlGet), DEVMETHOD(vxbIntCtlrIntReroute, vxbArmGicIntReroute), DEVMETHOD(vxbIntCtlrCpuReroute, vxbArmGicCpuReroute), #endif /* _WRS_CONFIG_SMP */ #ifdef GIC_INTCTLR_DEBUG_ON DEVMETHOD(busDevShow, vxbArmGicShow), #endif /* GIC_INTCTLR_DEBUG_ON */ { 0, 0} }; #ifdef _WRS_CONFIG_SMP IMPORT UINT32 vxCpuIndexGet(void); /* * This structure is initialized with the control functions for the IPI * interface. This set of functions allow the CPC layer to manipulate IPI * interrupts. */ LOCAL VXIPI_CTRL_INIT_DECL (vxArmGicIpiCtrlInit, {NULL}, /* ipiList */ 0, /* pCpus */ vxbArmGicIpiGen, /* ipiEmitFunc */ vxbArmGicIpiConnect, /* ipiConnectFunc */ vxbArmGicIpiEnable, /* ipiEnableFunc */ vxbArmGicIpiDisable, /* ipiDisableFunc */ vxbArmGicIpiDisconnect, /* ipiDisconnFunc */ vxbArmGicIpiPrioGet, /* ipiPrioGetFunc */ vxbArmGicIpiPrioSet, /* ipiPrioSetFunc */ ARM_GIC_IPI_COUNT, /* ipiCount */ NULL /* pCtlr */ ); #endif /* _WRS_CONFIG_SMP */ /******************************************************************************* * * vxbArmGicNonPreempISR - non-pre-emptive interrupt exception handler * * This handler does not provide pre-emptive interrupts. If a high * priority interrupt occurs while a low priority interrupt is being * handled, the high priority interrupt must wait for the low priority * interrupt handler to finish. As soon as the low-priority handler is * done, the high priority handler will be invoked. This model has less * exception handling overhead of the fully pre-emptive model, but has a * greater worst case latency for high priority interrupts. * * RETURNS: N/A * * ERROR: N/A */ LOCAL void vxbArmGicNonPreempISR () { int level; int vector; #ifdef _WRS_CONFIG_SV_INSTRUMENTATION int loopCnt = -1; #endif #ifdef _WRS_CONFIG_SMP int srcCpuId = 0; #endif #ifdef _WRS_CONFIG_SMP if (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector, &srcCpuId) == ERROR) #else if (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector) == ERROR) #endif { return; } do { /* Loop until no more interrupts are found */ #ifdef _WRS_CONFIG_SV_INSTRUMENTATION /* * In the ARM architecture, exceptions cannot be locked out * with intCpuLock() which makes a two-stage logging approach (i.e. * timestamp saved in intEnt and then used here) dangerous...it * can lead to out-of sequence events in the event log, thus * confusing the parser. So we just use a single stage logging * here. */ WV_EVT_INT_ENT (vector) loopCnt++; #endif /* _WRS_CONFIG_SV_INSTRUMENTATION */ VXB_INTCTLR_ISR_CALL (&(pVxbArmGicDrvCtrl->isrHandle), vector) /* acknowledge the interrupt and restore interrupt level */ #ifdef _WRS_CONFIG_SMP vxbArmGicLvlVecAck (pVxbArmGicDrvCtrl->pInst, level, vector, srcCpuId); #else vxbArmGicLvlVecAck (pVxbArmGicDrvCtrl->pInst, level, vector); #endif } #ifdef _WRS_CONFIG_SMP while (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector, &srcCpuId) != ERROR); #else while (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector) != ERROR); #endif #ifdef _WRS_CONFIG_SV_INSTRUMENTATION while (loopCnt-- > 0) EVT_CTX_0(EVENT_INT_EXIT); #endif } /******************************************************************************* * * vxbArmGicPreempISR - pre-emptive interrupt exception handler * * This handler is fully pre-emptive. In this model, high priority * interrupts are enabled during the processing of low-priority * interrupts. Should a high priority interrupt occur, the low-priority * handler is interrupted and the high priority handler takes over. * * \NOMANUAL * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void vxbArmGicPreempISR() { int vector, level; #ifdef _WRS_CONFIG_SMP int srcCpuId = 0; #endif #ifdef _WRS_CONFIG_SMP if (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector, &srcCpuId) == ERROR) #else if (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector) == ERROR) #endif { return; } #ifdef _WRS_CONFIG_SV_INSTRUMENTATION /* * In the ARM architecture, exceptions cannot be locked out with intCpuLock() * which makes a two-stage logging approach (i.e. timestamp saved in intEnt * and then used here) dangerous...it can lead to out-of sequence events * in the event log, thus confusing the parser. So we just use a single * stage logging here */ WV_EVT_INT_ENT(vector) #endif /* _WRS_CONFIG_SV_INSTRUMENTATION */ CPU_INTERRUPT_ENABLE; VXB_INTCTLR_ISR_CALL (&(pVxbArmGicDrvCtrl->isrHandle), vector) CPU_INTERRUPT_DISABLE; /* acknowledge the interrupt and restore interrupt level */ #ifdef _WRS_CONFIG_SMP vxbArmGicLvlVecAck (pVxbArmGicDrvCtrl->pInst, level, vector, srcCpuId); #else vxbArmGicLvlVecAck (pVxbArmGicDrvCtrl->pInst, level, vector); #endif /* _WRS_CONFIG_SMP */ } /******************************************************************************* * * vxbFTIntCtlrRegister - register GIC driver * * This routine registers the GIC driver with vxbus as a child * of the PLB bus type. * * RETURNS: N/A * * ERRNO: N/A */ void vxbFTIntCtlrRegister(void) { vxbDevRegister ((struct vxbDevRegInfo *)&armGicCtlRegistration); } /******************************************************************************* * * vxbArmGenIntCtlrInit - initialize the device * * This is the vxbArmGenIntrClt initialization routine. It retrieves and stores * device driver control data, connects the device driver specific routines into * the architecture level hooks and initializes the interrupt controller. * If the BSP needs to create a wrapper routine around any of the architecture * level routines, it should install the pointer to the wrapper routine after * calling this routine. * * NOTE: * * This routine is called early during system initialization (sysHwInit), and * *MUST NOT* make calls to OS facilities such as memory allocation * and I/O. It is called from the vxBus routine hardWareInterFaceInit(); * * RETURNS: N/A * * ERRNO */ LOCAL void vxbArmGicCtlInit ( VXB_DEVICE_ID pInst ) { ARM_GIC_DRV_CTRL * pDrvCtrl; HCF_DEVICE * pHcf; /* get the HCF device from the instance ID */ pHcf = hcfDeviceGet (pInst); /* if pHcf is NULL, no device is present in hwconf.c */ if (pHcf == NULL) return; /* allocate memory for the data */ pDrvCtrl = (ARM_GIC_DRV_CTRL *)hwMemAlloc (sizeof(ARM_GIC_DRV_CTRL)); if (pDrvCtrl == NULL) return; pDrvCtrl->pInst = pInst; vxbGicId = pInst; /* update the driver control data pointer */ pInst->pDrvCtrl = pDrvCtrl; pVxbArmGicDrvCtrl = pDrvCtrl; /* get connectivity info from hwconf */ intCtlrHwConfGet (pInst, pHcf, &(pDrvCtrl->isrHandle)); /* * resourceDesc { * The intMode resource specifies the interrupt mode. Interrupts can be in * either preemptive or non-preemptive mode, and the associated macro * definition is INT_PREEMPT_MODEL or INT_NON_PREEMPT_MODEL. * * The maxIntLvl resource specifies the number of interrupt level. * * The maxCpuNum resource specifies the number of CPU. It is 1 for uni-core * system. It may be 2, 3 or 4 for multi-core system. } */ if (devResourceGet (pHcf, "intMode", HCF_RES_INT, (void *)&pDrvCtrl->intMode) != OK) { #ifndef _VXBUS_BASIC_HWMEMLIB hwMemFree((char *)pDrvCtrl); #endif return; } pDrvCtrl->gicBase = pInst->pRegBase[0]; armGicBase = (UINT32)pDrvCtrl->gicBase; vxbRegMap(pInst, 0, &pDrvCtrl->handle); /* * Get the distributor and CPU interface register base addresses, * using the default (for backward-compatibility with ARM11 MPCore and * Cortex-A9) if they're not supplied by the BSP. */ if (devResourceGet (pHcf, "distOffset", HCF_RES_INT, (void *)&pDrvCtrl->gicDistOffset) != OK) { /* not found, so use default */ pDrvCtrl->gicDistOffset = armGicDistOffset; } else armGicDistOffset = pDrvCtrl->gicDistOffset; if (devResourceGet (pHcf, "redistOffset", HCF_RES_INT, (void *)&pDrvCtrl->gicReDistOffset) != OK) { /* not found, so use default */ pDrvCtrl->gicReDistOffset = armGicReDistOffset; } else armGicReDistOffset = pDrvCtrl->gicReDistOffset; if (devResourceGet (pHcf, "cpuOffset", HCF_RES_INT, (void *)&pDrvCtrl->gicCpuOffset) != OK) { /* not found, so use default */ pDrvCtrl->gicCpuOffset = armGicCpuOffset; } else armGicCpuOffset = pDrvCtrl->gicCpuOffset; /* get the maximum interrupt level number from hardware register */ pDrvCtrl->gicLvlNum = ((SWAP32 (*GIC_Type) & 0x1f) + 1) * 32; armGicLinesNum = pDrvCtrl->gicLvlNum; if (armGicLinesNum > GIC_INT_MAX_NUM) { #ifndef _VXBUS_BASIC_HWMEMLIB hwMemFree((char *)pDrvCtrl); #endif return; } #ifdef _WRS_CONFIG_SMP /* get the maximum CPU numbers */ if (devResourceGet (pHcf, "maxCpuNum", HCF_RES_INT, (void *)&pDrvCtrl->gicCpuNum) != OK) { #ifndef _VXBUS_BASIC_HWMEMLIB hwMemFree((char *)pDrvCtrl); #endif return; } #else pDrvCtrl->gicCpuNum = 1; #endif /* _WRS_CONFIG_SMP */ pInst->pMethods = &gicIntCtlr_methods[0]; /* Install three pointers for legacy type intEnable/intDisable/intLevelSet */ sysIntLvlEnableRtn = (FUNCPTR)sysArmGicEnable; sysIntLvlDisableRtn = (FUNCPTR)sysArmGicDisable; sysIntLvlChgRtn = (FUNCPTR)vxbArmGicHwLvlChg; if (_func_intConnectRtn == NULL) _func_intConnectRtn = sysArmGicConnect; if (_func_intDisconnectRtn == NULL) _func_intDisconnectRtn = sysArmGicDisconnect; /* initialize the GIC */ vxbArmGicDevInit (pInst); /* assign ISR to hook (defined in excArchLib.c) */ if (pDrvCtrl->intMode & INT_PREEMPT_MODEL) EXC_CONNECT_INTR_RTN (vxbArmGicPreempISR); else EXC_CONNECT_INTR_RTN (vxbArmGicNonPreempISR); /*arm_gicv3_init(0);*/ } /******************************************************************************* * * vxbArmGenIntCtlrInit2 - second level initialization of the ARM GIC * * This is the second level ARM GIC initialization routine. Nothing needs to * be done during this level of initialization. * * RETURNS: N/A * * ERRNO */ LOCAL void vxbArmGicCtlInit2 ( VXB_DEVICE_ID pInst ) { } /******************************************************************************* * * vxbArmGicDevInit - initialize the interrupt controller * * This routine initializes the interrupt controller device, disabling all * interrupt sources. It connects the device driver specific routines * into the architecture level hooks. If the BSP needs to create a wrapper * routine around any of the architecture level routines, it should install the * pointer to the wrapper routine after calling this routine. * * RETURNS: OK or ERROR if parameter is invalid. * * ERRNO: N/A */ LOCAL STATUS vxbArmGicDevInit ( VXB_DEVICE_ID pInst ) { ARM_GIC_DRV_CTRL * pDrvCtrl; /* if parameters are invalid, return ERROR */ if ((pInst == NULL) || (pInst->pDrvCtrl == NULL)) return (ERROR); /* retrieve the data */ pDrvCtrl = (ARM_GIC_DRV_CTRL *)(pInst->pDrvCtrl); pDrvCtrl->gicLvlCurrent = GIC_INT_ALL_ENABLED; vxbArmGicIntDevInit(0); vxbArmGicLvlChg (pInst, GIC_INT_ALL_ENABLED); /* enable all levels */ return OK; } /******************************************************************************* * * vxbArmGicIntDevInit - initialize the interrupt controller * * This routine initializes the interrupt controller device, disabling all * interrupt sources. It connects the device driver specific routines into the * architecture level hooks. If the BSP needs to create a wrapper routine * around any of the architecture level routines, it should install the pointer * to the wrapper routine after calling this routine. * * Note that for multicore processor, some registers are banked for each process. * This routine uses CPU0 to initialize the common resources and banked * registers are processed by every processor. * * RETURNS: always OK * * ERRNO: N/A */ LOCAL STATUS vxbArmGicIntDevInit ( int cpuNum ) { int i; UINT32 aGicPrio = 0; UINT32 aGicCfg = 0; STATUS stat; HCF_DEVICE * pHcf; struct intrCtlrPriority * pPrioTable; struct intrCtlrTrigger * pTrigTable = NULL; int tableSize; void * pValue; UINT32 val; UINT32 count = 1000; /* 1s! */ INT32 regGicLineNum; #ifndef _WRS_CONFIG_WRHV_GUEST pHcf = hcfDeviceGet (vxbGicId); if (pHcf == NULL) { return (ERROR); } val = *GICR_WAKER_CPU(cpuNum); /* Wake up this CPU redistributor */ #define GICR_WAKER_ProcessorSleep (1U << 1) #define GICR_WAKER_ChildrenAsleep (1U << 2) val &= ~GICR_WAKER_ProcessorSleep; *GICR_WAKER_CPU(cpuNum) = val; while (--count) { val = *GICR_WAKER_CPU(cpuNum); if (1 ^ (val & GICR_WAKER_ChildrenAsleep)) break; }; /* disable distributor */ val = *GICR_IntEnable; *GICR_IntEnClr_CPU(cpuNum) = SWAP32 (ALL_PPI_INT_MASK); *GICR_IntEnable_CPU(cpuNum) = ALL_SGI_INT_MASK; if (cpuNum == 0 &&gicVersion < GIC_VERSION_GIC400) /* CPU0 */ { *GIC_Control = 0; } /* disable this processor's CPU interface */ #ifdef SUPPORT_GICC *GIC_CPU_Control = 0; #else sys_icc_pmr_set(0xf0); sys_icc_ctlr_set(0); sys_icc_igrpen1_set(1); if((sys_icc_igrpen1_get() & 1) != 1) { return (ERROR); } #endif regGicLineNum = (INT32)(SWAP32 (*GIC_Type) & 0x1f); regGicLineNum = (regGicLineNum + 1) * 32; /* disable all PPI interrupts */ if(cpuNum == 0 && gicVersion >= GIC_VERSION_GIC400) { /* The Distributor control register (GICD_CTLR) must be configured to enable the interrupt groups and to set the routing mode. Enable Affinity routing (ARE bits) The ARE bits in GICD_CTLR control whether affinity routing is enabled. If affinity routing is not enabled, GICv3 can be configured for legacy operation . Whether affinity routing is enabled or not can be controlled separately for Secure and Non-secure state. Enables GICD_CTLR contains separate enable bits for Group 0, Secure Group 1 and Non-secure Group 1: GICD_CTLR.EnableGrp1S enables distribution of Secure Group 1 interrupts. GICD_CTLR.EnableGrp1NS enables distribution of Non-secure Group 1 interrupts. GICD_CTLR.EnableGrp0 enables distribution of Group 0 interrupts. */ *GIC_Control = 0x37; *GICR_IntEnClr = SWAP32 (ALL_PPI_INT_MASK); *GICR_IntEnable = ALL_SGI_INT_MASK; /* *GICR_IGROUPR0 = SWAP32(0x0000ffff);*/ } else if (gicVersion = GIC_VERSION_GIC400) { *GICR_IntPendClr = SWAP32 (ALL_PPI_INT_MASK | ALL_SGI_INT_MASK); } else { *GIC_IntPendClr(0) = SWAP32 (ALL_PPI_INT_MASK | ALL_SGI_INT_MASK); } /* set default priority for all PPI and SGI interrupts to level 0(highest) */ for (i = 0; i < SPI_START_INT_NUM; i += PRIOS_PER_WORD) *GICR_Prio_CPU(cpuNum,i) = GIC_IPI_PRIORITY; if (cpuNum == 0) /* CPU0 */ { /* * Disable all SPI interrupts * Clear all pending SPI interrupts in the distributor */ for(i = SPI_START_INT_NUM; i < GIC_INT_MAX_NUM; i += BITS_PER_WORD) { *GIC_IntEnClr(i) = SWAP32 (0xffffffff); *GIC_IntPendClr(i) = SWAP32 (0xffffffff); } /* * set default priority for all SPI interrupts to level 0 and direct all * interrupts to go to CPU 0 */ for (i = SPI_START_INT_NUM; i < armGicLinesNum; /*i += PRIOS_PER_WORD*/) { *GIC_Prio(i) = GIC_SPI_PRIORITY_DEFAULT; if(gicVersion < GIC_VERSION_GIC400) { *GIC_CPUTarg(i) = SWAP32 ( GIC_CPU_DIR_DEFAULT ); i += 4; } else { *GIC_IntRpute(i) = (UINT64)SWAP64 (GIC_V3_CPU_DIR_DEFAULT); i ++; } } /* setting whether 1-N/N-N and Level/Edge triggered */ for (i = SPI_START_INT_NUM; i < armGicLinesNum; i += CONFIGS_PER_WORD) { *GIC_Config(i) = SWAP32 ( GIC_INT_ONEMINUS_HIGH ); /* 1-N, Level */ } /* * get trigger table from hwconf * * resourceDesc { * The trigger resource specifies a pointer to a * intrCtlrTrigger structure which configures triggering * for particular interrupt vectors. } */ stat = devResourceGet(pHcf, "trigger", HCF_RES_ADDR, &pValue); pTrigTable = (struct intrCtlrTrigger *)pValue; if (stat == OK) { stat = devResourceGet(pHcf, "triggerTableSize", HCF_RES_INT, (void *) &tableSize); if (stat == OK) { for ( i = 0 ; i < tableSize ; i++ ) { if (pTrigTable->inputPin > armGicLinesNum) { pTrigTable++; continue; } /* * The GIC does not permit use of the Interrupt * Configuration Register to program the trigger * mode of PPIs. */ if (pTrigTable->inputPin >= SPI_START_INT_NUM) { aGicCfg = SWAP32 (*GIC_Config(pTrigTable->inputPin)); /* * Trigger configure type: * * VXB_INTR_TRIG_FALLING_EDGE == edge triggered, * falling edge * VXB_INTR_TRIG_RISING_EDGE == edge triggered, * rising edge * VXB_INTR_TRIG_ACTIVE_LOW == level sensitive, * active low * VXB_INTR_TRIG_ACTIVE_HIGH == level sensitive, * active high */ if (pTrigTable->trigger & VXB_INTR_TRIG_LEVEL) { aGicCfg &= ~(BIT (((pTrigTable->inputPin % CONFIGS_PER_WORD) * GIC_INT_TRIGGER_SHIFT + 1))); } else if (pTrigTable->trigger & VXB_INTR_TRIG_EDGE) { aGicCfg |= BIT (((pTrigTable->inputPin % CONFIGS_PER_WORD) * GIC_INT_TRIGGER_SHIFT + 1)); } *GIC_Config(pTrigTable->inputPin) = SWAP32 (aGicCfg); } pTrigTable++; } } } } /* * get priority table from hwconf * * resourceDesc { * The priority resource specifies a pointer to a * intrCtlrPriority structure which assigns priority * levels to particular interrupt vectors. } */ stat = devResourceGet(pHcf, "priority", HCF_RES_ADDR, &pValue); pPrioTable = (struct intrCtlrPriority *)pValue; if (stat == OK) { stat = devResourceGet(pHcf, "priorityTableSize", HCF_RES_INT, (void *) &tableSize); if (stat == OK) { for ( i = 0 ; i < tableSize ; i++ ) { /* use CPU0 to set the common SPI priority */ if ((pPrioTable->inputPin >= SPI_START_INT_NUM) && (cpuNum != 0)) { pPrioTable++; continue; } if((gicVersion >= GIC_VERSION_GIC400) && (pPrioTable->inputPin < SPI_START_INT_NUM)) { aGicPrio = SWAP32 (*GICR_Prio_CPU(cpuNum,pPrioTable->inputPin)); } else { aGicPrio = SWAP32 (*GIC_Prio(pPrioTable->inputPin)); } /* * Priority range: * * 0x0 == GIC_INT_HIGHEST_PRIORITY, the highest priority * 0xFF == GIC_INT_LOWEST_PRIORITY, the lowest priority */ if (pPrioTable->priority > armGicPriorityLvlMax) { aGicPrio |= ((armGicPriorityLvlMax & GIC_INT_PRIORITY_MASK) << ((pPrioTable->inputPin % PRIOS_PER_WORD) * GIC_INT_PRIORITY_SHIFT)); } else if ((pPrioTable->inputPin >= SPI_START_INT_NUM) && (pPrioTable->inputPin <= armGicLinesNum) && (pPrioTable->priority < GIC_PRIORITY_LEVEL_STEP)) { aGicPrio |= ((GIC_PRIORITY_LEVEL_STEP & GIC_INT_PRIORITY_MASK) << ((pPrioTable->inputPin % PRIOS_PER_WORD) * GIC_INT_PRIORITY_SHIFT)); } else { aGicPrio |= ((pPrioTable->priority & GIC_INT_PRIORITY_MASK) << ((pPrioTable->inputPin % PRIOS_PER_WORD) * GIC_INT_PRIORITY_SHIFT)); } if((gicVersion >= GIC_VERSION_GIC400) && (pPrioTable->inputPin < SPI_START_INT_NUM)) { *GICR_Prio_CPU(cpuNum,pPrioTable->inputPin) = SWAP32 (aGicPrio); } else { *GIC_Prio(pPrioTable->inputPin) = SWAP32 (aGicPrio); } pPrioTable++; } } } /* enable all interrupt priorities */ #ifdef SUPPORT_GICC *GIC_CPU_PriMask = SWAP32 (GIC_INT_ALL_ENABLED); #else #endif /* split group priority and subpriority */ if (pVxbArmGicDrvCtrl != NULL) { if (pVxbArmGicDrvCtrl->intMode & INT_PREEMPT_MODEL) { #ifdef SUPPORT_GICC *GIC_CPU_BinPoint = GIC_CPU_BINP_PREEMPT_VAL; #else sys_icc_bpr1_set(GIC_CPU_BINP_PREEMPT_VAL); #endif } else { #ifdef SUPPORT_GICC *GIC_CPU_BinPoint = SWAP32 (GIC_CPU_BINP_DEFAULT); #else sys_icc_bpr1_set(GIC_CPU_BINP_DEFAULT); #endif } } /* enable this processor's CPU interface */ #ifdef SUPPORT_GICC *GIC_CPU_Control = SWAP32 (GIC_CONTROL_ENABLE); #else sys_icc_ctlr_set(GIC_CONTROL_ENABLE); #endif if (cpuNum == 0 && gicVersion < GIC_VERSION_GIC400) { /* enable distributor */ *GIC_Control = SWAP32(GIC_CONTROL_ENABLE); } #else /* _WRS_CONFIG_WRHV_GUEST */ /* RAB - for guest only enable distributor */ *GIC_Control = GIC_CONTROL_ENABLE; #endif /* _WRS_CONFIG_WRHV_GUEST */ return OK; } /******************************************************************************* * * sysArmGicConnect - interrupt instance connect handler * * This function implements the connection of interrupt handler. It's used to * support intConnect(...). * * NOTE: * * This routine is called somewhere by legacy driver. * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS sysArmGicConnect ( VOIDFUNCPTR * vector, /* interrupt vector to attach to */ VOIDFUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ ) { ARM_GIC_DRV_CTRL * pDrvCtrl = vxbGicId->pDrvCtrl; if ((int)(vector) >= pDrvCtrl->gicLvlNum) return(ERROR); return(intCtlrISRAdd(&pDrvCtrl->isrHandle, (int)vector, routine, (void *)parameter)); } /******************************************************************************* * * vxbArmGicConnect - VxBus instance connect handler * * This function implements the VxBus InstConnect handler for an GIC instance. * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS vxbArmGicConnect ( VXB_DEVICE_ID pIntCtlr, VXB_DEVICE_ID pDev, int index, void (*pIsr)(void * pArg), void * pArg, int * pInputPin ) { ARM_GIC_DRV_CTRL * pDrvCtrl = pIntCtlr->pDrvCtrl; int inputPin; /* get interrupt input pin */ inputPin = intCtlrPinFind (pDev, index, pIntCtlr, &pDrvCtrl->isrHandle); if (inputPin == ERROR) return (ERROR); *pInputPin = inputPin; /* assign the ISR and arg to the specified cpu input pin */ if (intCtlrISRAdd(&pDrvCtrl->isrHandle, inputPin, pIsr, pArg) != OK) return (ERROR); return (OK); } /******************************************************************************* * * sysArmGicDisconnect - disconnect a C routine from an interrupt * * This routine disconnects a specified C routine from a specified * interrupt vector. It's used to support intDisconnect(...). * * This routine is called somewhere by legacy driver. * * RETURNS: OK, or ERROR if is out of range. * * ERRNO: N/A */ LOCAL STATUS sysArmGicDisconnect ( VOIDFUNCPTR * vector, /* interrupt vector to detach from */ VOIDFUNCPTR routine, /* routine to be disconnected */ int parameter /* parameter to be matched */ ) { ARM_GIC_DRV_CTRL * pDrvCtrl = vxbGicId->pDrvCtrl; if ((int)(vector) >= pDrvCtrl->gicLvlNum) return(ERROR); return(intCtlrISRRemove(&pDrvCtrl->isrHandle, (int)vector, routine, (void *)parameter)); } /******************************************************************************* * * vxbArmGicDisconnect - disconnect device interrupt * * This routine disconnects the supplied routine and arg from the interrupt * input found with intCtlrPinFind. * * \NOMANUAL * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS vxbArmGicDisconnect ( VXB_DEVICE_ID pIntCtlr, VXB_DEVICE_ID pDev, int index, VOIDFUNCPTR pIsr, void * pArg ) { ARM_GIC_DRV_CTRL * pDrvCtrl = pIntCtlr->pDrvCtrl; int inputPin; /* get interrupt input pin */ inputPin = intCtlrPinFind (pDev, index, pIntCtlr, &pDrvCtrl->isrHandle); if (inputPin == ERROR) return (ERROR); /* remove the ISR and arg from the specified cpu input pin */ if (intCtlrISRRemove(&pDrvCtrl->isrHandle, inputPin, pIsr, pArg) != OK) return (ERROR); return (OK); } /******************************************************************************* * * sysArmGicISREnable - enable interrupt handler * * This routine enables interrupt for the configured input pin * * \NOMANUAL * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS sysArmGicISREnable ( struct intCtlrHwConf * pEntries, int inputPin ) { struct intCtlrISRChainEntry * pChain; UINT32 flagValue; VOIDFUNCPTR func; /* make sure top-level enabled */ flagValue = intCtlrTableFlagsGet(pEntries, inputPin); flagValue |= VXB_INTCTLR_FLG_ENABLE; intCtlrTableFlagsSet(pEntries, inputPin, flagValue); func = intCtlrTableIsrGet(pEntries, inputPin); if ( func == intCtlrChainISR ) { pChain = (struct intCtlrISRChainEntry *) intCtlrTableArgGet(pEntries, inputPin); while (pChain != NULL) { pChain->flags |= VXB_INTCTLR_FLG_ENABLE; pChain = pChain->pNext; } } return(OK); } /******************************************************************************* * * sysArmGicEnable - enable an interrupt handler from the vector table * * This routine enables interrupt handler from the vector table. It's used * to support intEnable(...). * * This routine is called somewhere by legacy driver. * * \NOMANUAL * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS sysArmGicEnable ( int vector ) { ARM_GIC_DRV_CTRL *pDrvCtrl = vxbGicId->pDrvCtrl; if ((int)(vector) >= pDrvCtrl->gicLvlNum) return(ERROR); if (sysArmGicISREnable(&(pDrvCtrl->isrHandle), vector) != OK) return (ERROR); vxbArmGicLvlEnable(pDrvCtrl->pInst, vector); return (OK); } /******************************************************************************* * * vxbArmGicEnable - enable device interrupt * * This routine enables interrupt for the configured input pin * * \NOMANUAL * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS vxbArmGicEnable ( VXB_DEVICE_ID pIntCtlr, VXB_DEVICE_ID pDev, int index, VOIDFUNCPTR pIsr, void * pArg ) { ARM_GIC_DRV_CTRL * pDrvCtrl = pIntCtlr->pDrvCtrl; int inputPin; /* get interrupt input pin */ inputPin = intCtlrPinFind (pDev, index, pIntCtlr, &pDrvCtrl->isrHandle); if (inputPin == ERROR) return (ERROR); /* enable ISR */ if (intCtlrISREnable(&pDrvCtrl->isrHandle, inputPin, pIsr, pArg) != OK) return (ERROR); vxbArmGicLvlEnable(pDrvCtrl->pInst, inputPin); return (OK); } /******************************************************************************* * * sysArmGicISRDisable - disable interrupt handler * * This routine disables interrupt for the configured input pin * * \NOMANUAL * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS sysArmGicISRDisable ( struct intCtlrHwConf * pEntries, int inputPin ) { struct intCtlrISRChainEntry * pChain; UINT32 flagValue; VOIDFUNCPTR func; /* make sure top-level disabled */ flagValue = intCtlrTableFlagsGet(pEntries, inputPin); flagValue &= ~VXB_INTCTLR_FLG_ENABLE; intCtlrTableFlagsSet(pEntries, inputPin, flagValue); func = intCtlrTableIsrGet(pEntries, inputPin); if ( func == intCtlrChainISR ) { pChain = (struct intCtlrISRChainEntry *) intCtlrTableArgGet(pEntries, inputPin); while (pChain != NULL) { pChain->flags &= ~VXB_INTCTLR_FLG_ENABLE; pChain = pChain->pNext; } } return(OK); } /******************************************************************************* * * sysArmGicDisable - disable an interrupt handler from the vector table * * This routine disables interrupt handler from the vector table. It's used * to support intDisable(...). * * This routine is called somewhere by legacy driver. * * \NOMANUAL * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS sysArmGicDisable ( int vector ) { ARM_GIC_DRV_CTRL *pDrvCtrl = vxbGicId->pDrvCtrl; if ((int)(vector) >= pDrvCtrl->gicLvlNum) return(ERROR); if (sysArmGicISRDisable(&(pDrvCtrl->isrHandle), vector) != OK) return (ERROR); vxbArmGicLvlDisable(pDrvCtrl->pInst, vector); return (OK); } /******************************************************************************* * * vxbArmGicDisable - disable device interrupt * * This routine disables interrupt for the configured input pin * * \NOMANUAL * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS vxbArmGicDisable ( VXB_DEVICE_ID pIntCtlr, VXB_DEVICE_ID pDev, int index, VOIDFUNCPTR pIsr, void * pArg ) { ARM_GIC_DRV_CTRL * pDrvCtrl = pIntCtlr->pDrvCtrl; BOOL allDisabled; int inputPin; /* get interrupt input pin */ inputPin = intCtlrPinFind (pDev, index, pIntCtlr, &pDrvCtrl->isrHandle); if (inputPin == ERROR) return (ERROR); /* disable ISR */ allDisabled = intCtlrISRDisable(&pDrvCtrl->isrHandle, inputPin, pIsr, pArg); if (allDisabled) vxbArmGicLvlDisable(pDrvCtrl->pInst, inputPin); return (OK); } /******************************************************************************* * * vxbArmGicLvlVecChk - 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 level of that interrupt. * * 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. * * ERRNO: N/A */ #define ARM_GICV3_ICCIAR_INTID_MASK 0x3FF #define ARM_GICV3_ICCIAR_INTID(val) \ ((val) & ARM_GICV3_ICCIAR_INTID_MASK) STATUS vxbArmGicLvlVecChk ( VXB_DEVICE_ID pInst, int * pLevel, int * pVector #ifdef _WRS_CONFIG_SMP , int * pSrcCpuId #endif ) { UINT32 currentLevel, levelBak; /* read pending interrupt register and mask undefined bits */ #ifdef SUPPORT_GICC levelBak = SWAP32(*GIC_CPU_IntAck); #else levelBak = sys_icc_iar1_get(); #endif currentLevel = levelBak & GIC_INT_SPURIOUS; /* * If no interrupt is pending, register will have a value of 1023, * return ERROR */ if (currentLevel == GIC_INT_SPURIOUS) { return ERROR; } #ifdef _WRS_CONFIG_SMP /* check if interrupt is IPI */ if(currentLevel < SGI_INT_MAX) { /* * Level for IPI is defined and processed by software. * Hardware always use 0 - SGI_INT_MAX as the IPI interrupt level. * When we find that this is a SGI interrupt, we add armGicLinesNum to * the current SGI level (0 - SGI_INT_MAX), in other words, the SGI * level is redefined by software to declare that this is a specific * interrupt, then we need save the source CPU ID to ack this interrupt. */ if (gicVersion >= GIC_VERSION_GIC400) { *pSrcCpuId = 0; } else { *pSrcCpuId = levelBak & GIC_SGI_SRC_CPU_ID_MASK; } *pLevel = (currentLevel + armGicLinesNum); *pVector = IVEC_TO_INUM(currentLevel + armGicLinesNum); } else #endif /* _WRS_CONFIG_SMP */ { *pLevel = currentLevel; /* fetch, or compute the interrupt vector number */ *pVector = IVEC_TO_INUM(currentLevel); } return OK; } /******************************************************************************* * * vxbArmGicLvlVecAck - acknowledge the current interrupt * * This routine acknowledges the current interrupt cycle. The level and vector * values are those generated during the vxbArmGicLvlVecChk() routine for this * interrupt cycle. * * RETURNS: OK or ERROR if level is invalid. * * ERRNO */ STATUS vxbArmGicLvlVecAck ( VXB_DEVICE_ID pInst, int level, /* old interrupt level to be restored */ int vector /* current interrupt vector, if needed */ #ifdef _WRS_CONFIG_SMP , int srcCpuId #endif /* _WRS_CONFIG_SMP */ ) { UINT32 maxIntLines; #ifdef _WRS_CONFIG_SMP maxIntLines = armGicLinesNum + ARM_GIC_IPI_COUNT; #else maxIntLines = armGicLinesNum; #endif /* _WRS_CONFIG_SMP */ /* Validity check for level. */ if (level < 0 || level >= maxIntLines || (level >= SGI_INT_MAX && level < PPI_START_INT_NUM)) return ERROR; /* * Ack the interrupt. It's implemented on the CPU interface to the * interrupt distributor. */ #ifdef _WRS_CONFIG_SMP if (level >= armGicLinesNum) { /* * SGI is used to implement the IPI. The source CPU ID must be carried * to acknowledge the SGI interrupts. */ level -= armGicLinesNum; if (gicVersion < GIC_VERSION_GIC400) level |= srcCpuId; } #endif /* _WRS_CONFIG_SMP */ #ifdef SUPPORT_GICC *GIC_CPU_EOInt = SWAP32( level ); #else sys_icc_eoir1_set(level); #endif return OK; } /******************************************************************************* * * vxbArmGicLvlChg - change the interrupt level value * * This routine sets the interrupt priority mask. * All levels up to the specified level are disabled. * All levels above the specified level will be enabled. * This routine must be called with interrupts disabled. * * RETURNS: previous interrupt level or ERROR if level is invalid. * * ERRNO: N/A */ int vxbArmGicLvlChg ( VXB_DEVICE_ID pInst, int level /* new interrupt level */ ) { int oldLevel; ARM_GIC_DRV_CTRL * pDrvCtrl; /* if parameters are invalid, return ERROR */ if ((pInst == NULL) || (pInst->pDrvCtrl == NULL)) return (ERROR); /* retrieve the data */ pDrvCtrl = (ARM_GIC_DRV_CTRL *)(pInst->pDrvCtrl); oldLevel = pDrvCtrl->gicLvlCurrent; if (level <= GIC_IPI_PRIORITY) level = oldLevel; if (level > armGicPriorityLvlMax) level = armGicPriorityLvlMax; /* change current interrupt level */ pDrvCtrl->gicLvlCurrent = level; #ifdef SUPPORT_GICC *GIC_CPU_PriMask = SWAP32 (level); #else #endif VX_SYNC_BARRIER(); return oldLevel; } /******************************************************************************* * * vxbArmGicLvlEnable - enable a single interrupt level * * This routine enables a specific interrupt level at the interrupt distributor. * The enabled level will be allowed to generate an interrupt to the configured * CPU(s). Without being enabled, the interrupt is blocked. * * RETURNS: OK or ERROR if level is invalid. * * ERRNO: N/A */ LOCAL STATUS vxbArmGicLvlEnable ( VXB_DEVICE_ID pInst, int level /* level to be enabled */ ) { int key; #ifdef _WRS_CONFIG_SMP /* * For SGI interrupt, we always return OK, since SGI interrupt can not be * disabled. */ if ((level >= 0 && level < SGI_INT_MAX) || (level >= armGicLinesNum&& level < (armGicLinesNum + ARM_GIC_IPI_COUNT))) { if (gicVersion >= GIC_VERSION_GIC400) { if (level >= armGicLinesNum) { level -= armGicLinesNum; } key = intCpuLock (); /* LOCK INTERRUPTS */ *GICR_IntEnable = SWAP32 (BIT(level)); /* enable interrupt */ intCpuUnlock (key); /* UNLOCK INTERRUPTS */ } return OK; } /* validity check for interrupt number */ /* req: VX7-16254 */ if (level < 0 || level >= (armGicLinesNum + ARM_GIC_IPI_COUNT)) return ERROR; #else if ((level >= 0) && (level < SGI_INT_MAX)) return OK; /* Validity check for level. */ if (level < PPI_START_INT_NUM || level >= armGicLinesNum ) return ERROR; #endif key = intCpuLock (); /* LOCK INTERRUPTS */ if ((gicVersion >= GIC_VERSION_GIC400) && (level < SPI_START_INT_NUM)) { int cpuNum = vxCpuIndexGet(); *GICR_IntEnable_CPU(cpuNum) = SWAP32 (BIT(level)); /* enable interrupt */ } else { *GIC_IntEnable (level) = SWAP32 (BIT(level)); /* enable interrupt */ } intCpuUnlock (key); /* UNLOCK INTERRUPTS */ return OK; } /******************************************************************************* * * vxbArmGicLvlDisable - disable a single interrupt level * * This routine disables a specific interrupt level at the interrupt distributor. * The disabled level is prevented from generating an interrupts. * * RETURNS: OK or ERROR if level is invalid. * * ERRNO: N/A */ LOCAL STATUS vxbArmGicLvlDisable ( VXB_DEVICE_ID pInst, int level /* level to be disabled */ ) { int key; if ((level >= 0 && level < SGI_INT_MAX) || (level >= armGicLinesNum&& level < (armGicLinesNum + ARM_GIC_IPI_COUNT))) { if (gicVersion >= GIC_VERSION_GIC400) { if (level >= armGicLinesNum) { level -= armGicLinesNum; } key = intCpuLock (); /* LOCK INTERRUPTS */ *GICR_IntEnClr = SWAP32 (BIT(level)); /* enable interrupt */ intCpuUnlock (key); /* UNLOCK INTERRUPTS */ } return OK; } /* Validity check for level. */ #ifdef _WRS_CONFIG_SMP /* req: VX7-16258 */ if (level < PPI_START_INT_NUM|| level >= (armGicLinesNum + ARM_GIC_IPI_COUNT)) return ERROR; #else if (level < PPI_START_INT_NUM || level >= armGicLinesNum) return ERROR; #endif /* _WRS_CONFIG_SMP */ key = intCpuLock (); if ((gicVersion >= GIC_VERSION_GIC400) && (level < SPI_START_INT_NUM)) { int cpuNum = vxCpuIndexGet(); *GICR_IntEnClr_CPU(cpuNum) = SWAP32 (BIT(level)); /* disable interrupt */ } else { *GIC_IntEnClr(level) = SWAP32( BIT(level)); } intCpuUnlock (key); return OK; } /****************************************************************************** * * vxbArmGicHwLvlChg - change the interrupt level value * * This routine sets the current interrupt level to the specified level. * * \NOMANUAL * * RETURNS: Previous interrupt level. * * ERRNO: N/A */ LOCAL int vxbArmGicHwLvlChg ( int level ) { return vxbArmGicLvlChg(pVxbArmGicDrvCtrl->pInst,level); } #ifdef INCLUDE_SHOW_ROUTINES /******************************************************************************* * * vxbArmGicDataShow - show data acquired by vxBus * * This routine shows data acquired by vxBus. * * RETURNS: N/A */ void vxbArmGicDataShow ( VXB_DEVICE_ID pInst, int *dummy ) { ARM_GIC_DRV_CTRL * pDrvCtrl; /* check if parameters are invalid */ if ((pInst == NULL) || (pInst->pDrvCtrl == NULL)) return; /* retrieve the data */ pDrvCtrl = (ARM_GIC_DRV_CTRL *)(pInst->pDrvCtrl); printf ("\nGIC Configuration Data acquired by vxBus\n\n"); printf ("\n ARM GIC Info : \n"); printf (" pInst = 0x%08x\n", pInst); printf (" GicBase = 0x%08x\n", pDrvCtrl->gicBase); printf (" GicLvlCurrent = 0x%08x\n", pDrvCtrl->gicLvlCurrent); printf (" gicDistOffset = 0x%08x\n", pDrvCtrl->gicDistOffset); printf (" gicCpuOffset = 0x%08x\n", pDrvCtrl->gicCpuOffset); } #endif /* INCLUDE_SHOW_ROUTINES */ #ifdef _WRS_CONFIG_SMP /******************************************************************************* * * vxbArmGicHwEnable - enable hardware interrupt * * This routine enables the interrupt for the configured input pin * * \NOMANUAL * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS vxbArmGicHwEnable ( int inputPin ) { return vxbArmGicLvlEnable(pVxbArmGicDrvCtrl->pInst, inputPin); } /****************************************************************************** * * vxbArmGicHwDisable - disable device interrupt * * This routine disables the interrupt the configured input pin * * \NOMANUAL * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS vxbArmGicHwDisable ( int inputPin ) { return vxbArmGicLvlDisable(pVxbArmGicDrvCtrl->pInst, inputPin); } /******************************************************************************* * * sysArmGicDevInit - initialize interrupt controller. * * This routine initializes interrupt controller. It may be called by non-CPU0 * routines in BSP, or somewhere else. * * RETURNS: N/A * * ERRNO: N/A */ void sysArmGicDevInit (void) { int cpuNum = vxCpuIndexGet(); (void)vxbArmGicIntDevInit(cpuNum); } /******************************************************************************* * * vxbArmGicIntReroute - reroute interrupt to specified CPU * * This routine reroutes device interrupt to requested CPU. Note that the cpu is * specified in a cpuset_t type, and this would allow for multiple cpus to be * bundled with the interrupt. Multicore processor can ensure that only one CPU * will be triggered if the interrupt occurs. * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS vxbArmGicIntReroute ( VXB_DEVICE_ID pDev, int index, cpuset_t destCpu ) { struct intCtlrHwConf * isrHandle; BOOL flag; int targCpu = 0; int bitCnt = 0; int i; int inputPin; int tmpData; UINT32 oldIntCfg; isrHandle = &(((ARM_GIC_DRV_CTRL *)(vxbGicId->pDrvCtrl))->isrHandle); /* convert cpuset_t cpu number to numeric cpu number */ for (i = 0; i < ((ARM_GIC_DRV_CTRL *)(vxbGicId->pDrvCtrl))->gicCpuNum; i++) { if (destCpu & (1 << i)) { bitCnt++; targCpu = i; } } /* make sure destCpu is a proper cpuset_t value */ if (bitCnt != 1) return (ERROR); /* find the device input pin number */ inputPin = intCtlrPinFind (pDev, index, vxbGicId, isrHandle); if (inputPin == ERROR) return (ERROR); /* make sure pin is allocated */ VXB_INTCTLR_PINENTRY_ALLOCATED(isrHandle, inputPin, flag); if (!flag) return (ERROR); oldIntCfg = SWAP32(*GIC_IntEnable(inputPin)); /* disable interrupt source */ vxbArmGicLvlDisable(pDev, inputPin); if(gicVersion < GIC_VERSION_GIC400) { /* clear the current configuration */ tmpData = 0xff << ((inputPin % TARGETS_PER_WORD) * 8); tmpData = SWAP32( *GIC_CPUTarg(inputPin) ) & ~tmpData; /* set route bit */ tmpData |= ((UINT32) (0x1 << (UINT32)targCpu) << \ ((inputPin % TARGETS_PER_WORD) * 8)); *GIC_CPUTarg(inputPin) = SWAP32( tmpData ); } else { *GIC_IntRpute(i) = GIC_AFF_LOW32_MASK & vxCpuIdGetByIndex((UINT32)destCpu); } if ((oldIntCfg & SWAP32 (BIT (inputPin))) != 0) { /* enable interrupt source */ vxbArmGicLvlEnable(pDev, inputPin); } return OK; } /******************************************************************************* * * vxbArmGicCpuReroute - reroute interrupts to specified CPU * * This routine reroutes interrupts that are configured in hwconf.c for a CPU * other than the default CPU to that CPU. * * RETURNS: OK if operation succeed else ERROR * * ERRNO: N/A */ LOCAL STATUS vxbArmGicCpuReroute ( VXB_DEVICE_ID pDev, void * destCpu ) { ARM_GIC_DRV_CTRL * pDrvCtrl = pDev->pDrvCtrl; struct intCtlrHwConf *isrHandle = &(pDrvCtrl->isrHandle); int i; int configCpu, tmpData; BOOL flag; void (*func)(); if ((int)destCpu >= pDrvCtrl->gicCpuNum) return (ERROR); /* move interrupts to requested cpu */ for (i = 0; i < armGicLinesNum; i++) { /* verify this is an allocated pin so NULL references are avoided */ VXB_INTCTLR_PINENTRY_ALLOCATED(isrHandle, i, flag); if (flag) { /* only move interrupts that are configured with an ISR */ GIC_ISR(isrHandle, i, func); if (func == NULL || func == intCtlrStrayISR) continue; /* move interrupts that are configured for the requested CPU */ GIC_DESTCPU(isrHandle, i, configCpu); if (configCpu == (int)destCpu) { /* disable interrupt source */ vxbArmGicLvlDisable(pDev, i); if(gicVersion < GIC_VERSION_GIC400) { /* clear the current configuration */ tmpData = 0xff << ((i % TARGETS_PER_WORD) * 8); tmpData = SWAP32( *GIC_CPUTarg(i) ) & ~tmpData; /* set route bit */ tmpData |= ((UINT32) (0x1 << (UINT32)destCpu) << \ ((i % TARGETS_PER_WORD) * 8)); *GIC_CPUTarg(i) = SWAP32( tmpData ); } else { *GIC_IntRpute(i) = GIC_AFF_LOW32_MASK & vxCpuIdGetByIndex((UINT32)destCpu); } /* enable interrupt source */ vxbArmGicLvlEnable(pDev, i); } } } return (OK); } /******************************************************************************* * * vxbArmGicIpiCtlGet - retrieve IPI control structure * * This routine retrieves IPI control structure. * * RETURNS: pointer of IPI control structure * * ERRNO: N/A */ LOCAL VXIPI_CTRL_INIT * vxbArmGicIpiCtlGet ( VXB_DEVICE_ID pInst, void * pArg ) { vxArmGicIpiCtrlInit.pCpus = sysCpuAvailableGet(); vxArmGicIpiCtrlInit.pCtlr = pInst; return(&vxArmGicIpiCtrlInit); } /* * The inline assembly to access generic system register on c12 follows diab's inline * assembly syntax, so diab compiler must be used. */ #ifdef __DCC__ _WRS_INLINE void armGicIpiGen ( UINT32 valLow, UINT32 valHigh ) { __inline__ArmGicIpiGen (valLow, valHigh); } #else #ifndef _WRS_CONFIG_LP64 void __inline__ArmGicIpiGen (UINT32 valLow, UINT32 valHigh) { __asm__ __volatile__ ("MCRR p15,0,%0,%1,c12" : : "r" (valLow), "r" (valHigh)); } _WRS_INLINE void armGicIpiGen ( UINT32 valLow, UINT32 valHigh ) { __inline__ArmGicIpiGen (valLow, valHigh); } #else _WRS_INLINE void armGicIpiGen (UINT32 valLow, UINT32 valHigh) { UINT64 tempVal= valLow | ((UINT64)valHigh << 32); __asm__ __volatile__ ("MSR ICC_SGI0R_EL1, %0" : : "r" (tempVal)); } #endif /* _WRS_CONFIG_LP64 */ #endif /* !__DCC__ */ /******************************************************************************* * * vxbArmGicIpiGen - generate Inter Processor Interrupt * * This routine generates Inter Processor Interrupt(IPI) through * Software Generated Interrupt(SGI) * * RETURNS: OK or ERROR if parameter is invalid. * * ERRNO: N/A */ LOCAL STATUS vxbArmGicIpiGen ( VXB_DEVICE_ID pCtlr, INT32 ipiId, cpuset_t cpus ) { int index; UINT8 aff1; UINT8 aff2; UINT8 cpuList; UINT32 cpuId; volatile UINT32 lowWord = 0; volatile UINT32 highWord = 0; if (ipiId < 0 || ipiId >= ARM_GIC_IPI_COUNT || cpus == 0) return (ERROR); if (gicVersion >= GIC_VERSION_GIC400) { for(index = 0; index < 32; index ++) { if ((cpus >> index) & 0x1) { lowWord = 0; highWord = 0 ; cpuId = vxCpuIdGetByIndex(index); cpuList = (UINT8)(cpuId & 0xff); aff1 = (UINT8)((cpuId >> 8) & 0xff); aff2 = (UINT8)((cpuId >> 16) & 0xff); cpuList = 1 <isrHandle, level, ipiHandler, ipiArg)); } /******************************************************************************* * * vxbArmGicIpiDisconnect - disconnect ISR from IPI * * This routine disconnects ISR from Inter Processor Interrupt(IPI) * * RETURNS: OK if operation succeed else ERROR * * ERRNO: */ LOCAL STATUS vxbArmGicIpiDisconnect ( VXB_DEVICE_ID pCtlr, INT32 ipiId, IPI_HANDLER_FUNC ipiHandler, void * ipiArg ) { INT32 level; level = ipiId + armGicLinesNum; return (intCtlrISRRemove(&pVxbArmGicDrvCtrl->isrHandle, level, ipiHandler, ipiArg)); } /******************************************************************************* * * vxbArmGicIpiEnable - enable specified IPI * * This routine enables specified IPI * * RETURNS: return value of intEnable() * * ERRNO: N/A */ LOCAL STATUS vxbArmGicIpiEnable ( VXB_DEVICE_ID pCtlr, INT32 ipiId ) { return (vxbArmGicHwEnable(ipiId)); } /******************************************************************************* * * vxbArmGicIpiDisable - disable specified IPI * * This routine disables specified IPI * * RETURNS: return value of intDisable() * * ERRNO: N/A */ LOCAL STATUS vxbArmGicIpiDisable ( VXB_DEVICE_ID pCtlr, INT32 ipiId ) { return (vxbArmGicHwDisable(ipiId)); } /******************************************************************************* * * vxbArmGicIpiPrioGet - retrieve IPI priority * * This routine gets the current priority of specified IPI. * * NOTE * priority configuration is currently unsupported, and we always use 0 as the * priority of all IPIs. * * RETURNS: always 0 * * ERRNO: N/A */ LOCAL INT32 vxbArmGicIpiPrioGet ( VXB_DEVICE_ID pCtlr, INT32 ipiId ) { return (0); } /******************************************************************************* * * vxbArmGicIpiPrioSet - set IPI priority * * This routine sets the priority of specified IPI. * * NOTE * priority configuration is currently unsupported, and we always use 0 as the * priority of all IPIs. * * RETURNS: always OK * * ERRNO: N/A */ LOCAL STATUS vxbArmGicIpiPrioSet ( VXB_DEVICE_ID pCtlr, INT32 ipiId, INT32 prio ) { return (OK); } #endif /* _WRS_CONFIG_SMP */ /******************************************************************************* * * sysMaxIntLvl - Get maximum Interrupt Level * * This routine retrieves maximum Interrupt Level. It is a debug function. Do not * use "maxIntLvl" in hwconf.c with immediate value. Read it from GIC register. * * RETURNS: maximum Interrupt Level * * ERRNO: N/A */ UINT32 sysMaxIntLvl(void) { return armGicLinesNum; }