这篇blog主要分为三部分:
1,中断初始化
2,vxbus架构中断的挂接
3,非vxbus架构的中断的挂接
1,中断的初始化
函数调用:
usrInit->sysStart->palInit->palDescInit()
/*为了方便查看,这里对函数 进行了删减
*palDescInit()函数对默认的中断函数进行了初始化
*/
#ifndef _WRS_MIPS_NONCOMPLIANT_CONFIG_REG #endif /* _WRS_MIPS_NONCOMPLIANT_CONFIG_REG */ bzero((char *)&palDesc, sizeof(palDesc)); /* Hopefully code further down will be able to refine these */ palDesc.iCache.present = FALSE; palDesc.dCache.present = FALSE; palDesc.l2Cache.present = FALSE; palDesc.l3Cache.present = FALSE; if (IS_KSEGM((UINT32) &palDescInit)) /* executing a mapped kernel */ palDesc.tVec.vectorAddr = (VIRT_ADDR *)T_VEC; palDesc.tVec.excHandler = (VIRT_ADDR *)mmuMipsTlbVec; palDesc.tVec.excSize = mmuMipsTlbVecSize; palDesc.xVec.vectorAddr = (VIRT_ADDR *)X_VEC; palDesc.xVec.excHandler = (VIRT_ADDR *)mmuMipsXtlbVec; palDesc.xVec.excSize = (UINT)mmuMipsXtlbVecSize; palDesc.cVec.vectorAddr = (VIRT_ADDR *)C_VEC; palDesc.cVec.excHandler = (VIRT_ADDR*)excCacheVec; palDesc.cVec.excSize = (UINT)excCacheVecSize; palDesc.eVec.vectorAddr = (VIRT_ADDR *)E_VEC; palDesc.eVec.excHandler = (VIRT_ADDR *)excNormVmVec; palDesc.eVec.excSize = (UINT)excNormVmVecSize; /* Reasonable defaults */ palDesc.tlb.supportedPageSizes = MMU_PAGE_MASK_8K; palDesc.tlb.mmuCacheable=MMU_R4K_STATE_INVALID_STATE >> MMU_R4K_CACHE_START; palDesc.tlb.mmuUncacheable = CFG_CCA_UNCACHED; palDesc.tlb.mmuCacheCopyback = CFG_CCA_CACHEABLE; palDesc.tlb.mmuCacheWritethrough = CFG_CCA_ALIAS_CACHEABLE; palDesc.tlb.mmuCacheCoherency = CFG_CCA_COHERENT; palDesc.iCache.modes = CACHE_MODES_SUPPORTED; palDesc.dCache.modes = CACHE_MODES_SUPPORTED; #define T_VEC K0BASE /* tlbmiss vector */ #define X_VEC (K0BASE+0x80) /* xtlbmiss vector */ #define C_VEC (K1BASE+0x100) /* cache exception vector */ #define E_VEC (K0BASE+0x180) /* exception vector */ #define R_VEC (K1BASE+0x1fc00000) /* reset vector */ #define BEV_VEC (K1BASE+0x1fc00380) /* boot exception vector */ char *version; /* PAL version string */ int coreNum; /* processor number */ MIPS_EXC_VECTOR tVec; /*tlbmiss中断*/ MIPS_EXC_VECTOR xVec; /*xtlbmiss中断*/ MIPS_EXC_VECTOR cVec; /*cache异常中断*/ MIPS_EXC_VECTOR eVec; /*异常中断,包括中断(根据exccode码判别)*/ MIPS_CACHE_INFO iCache; /*指令cache相关*/ MIPS_CACHE_INFO dCache; /*数据cache相关*/ MIPS_CACHE_INFO l2Cache; /*二级cache相关*/ MIPS_CACHE_INFO l3Cache; /*三级cache相关*/ int mmuType; /* CR bits 9:7 */
默认中断函数的安装:
ULONG srValue; /* status register placeholder */ /* Load tlb and Xtlb vectors */ /* Load cache exception vector */ /* Load normal/interrupt vector */ MIPS_EXC_VECTOR * vectorDesc bcopy ((const char *) vectorDesc->excHandler, (char *) vectorDesc->vectorAddr, vectorDesc->excSize); CACHE_TEXT_UPDATE (vectorDesc->vectorAddr, vectorDesc->excSize);
这里找一个具体的中断控制器的初始化进行说明。(这是一个抽象出来的中断控制器,至于什么是抽象,也就是没有一个具体的物理硬件设备对应这个控制器,这只是一个软件层面的简化,这样对于中断的处理就更明显,直接。)
usrInit->sysHwInit->vxbMipsLsnIntCtlrRegister vxbMipsLsnIntCtlrRegister->vxbDevRegister->vxbNewDriver->vxbDevInitRun
/*vxbDevInitRun函数会调用设备对应的初始化函数对设备进行初始化*/ struct vxbDevRegInfo * pDrv if (!(devID->flags & VXB_INST_INIT_DONE)) if ( pDrv->pDrvBusFuncs->devInstanceInit != NULL ) (*(pDrv->pDrvBusFuncs->devInstanceInit))(devID); devID->flags |= VXB_INST_INIT_DONE; if (vxbInitPhase >= 2 && !(devID->flags & VXB_INST_INIT2_DONE)) if ( pDrv->pDrvBusFuncs->devInstanceInit2 != NULL ) (*(pDrv->pDrvBusFuncs->devInstanceInit2))(devID); devID->flags |= VXB_INST_INIT2_DONE; if (vxbInitPhase >= 3 && !(devID->flags & VXB_INST_CONNECT_DONE)) if ( pDrv->pDrvBusFuncs->devInstanceConnect != NULL ) (*(pDrv->pDrvBusFuncs->devInstanceConnect))(devID); devID->flags |= VXB_INST_CONNECT_DONE;
这里的pDrv->pDrvBusFuncs->devInstanceInit函数对应控制器的lsnIntCtlrInstInit函数,在lsnIntCtlrInstInit函数中调用了vxbMipsLsnIntCtlrInit对中断进行初始化。
LOCAL VOID vxbMipsLsnIntCtlrInit pVXB_LSN_INT_DRV_CTRL pDrvCtrl = pInst->pDrvCtrl; /*这里注意intCtlrHwConfGet,这是真正具体的初始化函数*/ intCtlrHwConfGet(pInst, pHcf, &(pDrvCtrl->isrHandle)); Loongson2H_interrupt_init();
intCtlrHwConfGet这个函数比较长,删减以下,可以看出来这个函数所作的工作就是从hwconf.c中得到设备对应的中断信息,并对每一个对应的引脚初始化为一个具体的结构体,结构体中包含的成员可以看一看。
struct intCtlrHwConf * pEntries struct intrCtlrInputs * pCtlrInputs; /*中断控制引脚*/ struct intrCtlrXBar * pXbar; /*xbar路由*/ struct intrCtlrCpu * pCpuTable; /*对应那个cpu*/ struct intrCtlrPriority * pPrioTable; /*优先级*/ struct intrCtlrTrigger * pTrigTable; /*引发方式,上升沿,高低电平,下降沿*/ int tableSize; /*控制引脚数组的大小*/ pEntries->ctlrDev = pInst; stat = devResourceGet(pHcf, "input", HCF_RES_ADDR, ppValue); pCtlrInputs = (struct intrCtlrInputs *)pValue; stat = devResourceGet(pHcf, "inputTableSize", HCF_RES_INT, ppValue); tableSize = (UINT32)pValue; /*遍历表中的每个元素,并为每一个对应的引脚创建相应的结构体*/ for ( i = 0 ; i < tableSize ; i++ ) stat = intCtlrTableCreate(pEntries, pCtlrInputs->inputPin); /*为创建的结构体中的元素进行赋值操作,包括引脚号(硬件上连接的引脚号),驱动名字,drvunit以及drvIndex */ intCtlrTableUserSet(pEntries, pCtlrInputs->inputPin, pCtlrInputs->drvName,pCtlrInputs->drvUnit, pCtlrInputs->drvIndex); stat = devResourceGet(pHcf, "priority", HCF_RES_ADDR, ppValue); pPrioTable = (struct intrCtlrPriority *)pValue; stat = devResourceGet(pHcf, "priorityTableSize", HCF_RES_INT, ppValue); tableSize = (UINT32)pValue; /*遍历表中所有的元素,把值填入到对应的引脚结构体中*/ for ( i = 0 ; i < tableSize ; i++ ) stat = intCtlrTableCreate(pEntries, pPrioTable->inputPin); intCtlrTablePrioSet(pEntries, pPrioTable->inputPin,pPrioTable->priority); /*下面操作基本都是类似的,获取对应的中断信息,并进行遍历填入到引脚结构体中*/ stat = devResourceGet(pHcf, "trigger", HCF_RES_ADDR, ppValue); pTrigTable = (struct intrCtlrTrigger *)pValue; stat = devResourceGet(pHcf, "triggerTableSize", HCF_RES_INT, ppValue); tableSize = (UINT32)pValue; for ( i = 0 ; i < tableSize ; i++ ) /* ensure pin record exists */ stat = intCtlrTableCreate(pEntries, pTrigTable->inputPin); intCtlrTableTrigSet(pEntries, pTrigTable->inputPin, pTrigTable->trigger); stat = devResourceGet(pHcf, "crossBar", HCF_RES_ADDR, ppValue); pXbar = (struct intrCtlrXBar *)pValue; stat = devResourceGet(pHcf, "crossBarTableSize", HCF_RES_INT, ppValue); tableSize = (UINT32)pValue; for ( i = 0 ; i < tableSize ; i++ ) /* ensure pin record exists */ stat = intCtlrTableCreate(pEntries, pXbar->inputPin); intCtlrTableOutputSet(pEntries, pXbar->inputPin, pXbar->outputPin); stat = devResourceGet(pHcf, "cpuRoute", HCF_RES_ADDR, ppValue); pCpuTable = (struct intrCtlrCpu *)pValue; stat = devResourceGet(pHcf, "cpuRouteTableSize", HCF_RES_INT, ppValue); tableSize = (UINT32)pValue; /* iterate through table */ for ( i = 0 ; i < tableSize ; i++ ) /* ensure pin record exists */ stat = intCtlrTableCreate(pEntries, pCpuTable->inputPin); /* set destination CPU for this input pin */ intCtlrTableCpuSet (pEntries, pCpuTable->inputPin, #endif /* _WRS_CONFIG_SMP */
STATUS intCtlrTableCreate struct intCtlrHwConf * pInputs, int tblIndx = VXB_INTCTLRLIB_TBL_IDX(pInputs,inputPin); int startPin = inputPin - (inputPin % VXB_INTCTLRLIB_LOWLVL_SIZE); if ( pInputs->pTop == NULL ) /*分配一个结构体vxbIntCtlrInpTop*/ pInputs->pTop = (struct vxbIntCtlrInpTop *) hwMemAlloc(sizeof(struct vxbIntCtlrInpTop)); if ( pInputs->pTop->tbl[tblIndx] == NULL ) pInputs->pTop->tbl[tblIndx] = (struct vxbIntCtlrInput *) hwMemAlloc(sizeof(struct vxbIntCtlrInput) + VXB_INTCTLRLIB_MIN_CACHE_LINE_SIZE); pInputs->pTop->tbl[tblIndx] = (struct vxbIntCtlrInput *) ROUND_UP(pInputs->pTop->tbl[tblIndx], VXB_INTCTLRLIB_MIN_CACHE_LINE_SIZE); memset(pInputs->pTop->tbl[tblIndx],0,sizeof(struct vxbIntCtlrInput)); /*为每一个引脚结构体中的中断函数以及中断函数参数赋一个系统默认的值 */ for ( i = 0 ; i < VXB_INTCTLRLIB_NUM_PINS(pInputs) ; i++ ) pInputs->pTop->tbl[tblIndx]->pins[i].isr = intCtlrStrayISR; pInputs->pTop->tbl[tblIndx]->pins[i].pArg = pInputs; pInputs->pTop->tbl[tblIndx]->pins[i].pinFlags = startPin + i;
VXB_DEVICE_ID ctlrDev; /* VXB_DEVICE_ID of int ctlr */ struct vxbIntCtlrInpTop * pTop; /* top-level table of entries */ struct vxbLock vxbIntCtlrLibLock; struct vxbIntCtlrInpTop * pNext; /* not implemented */ struct vxbIntCtlrInput * tbl[VXB_INTCTLRLIB_TOPLVL_SIZE]; #define VXB_INTCTLRLIB_TOPLVL_SIZE 496 struct vxbIntCtlrPin pins[VXB_INTCTLRLIB_LOWLVL_SIZE]; /*最后的运算就是 2^x ,这里的定义也就是8*/ #define VXB_INTCTLRLIB_LOWLVL_SIZE_POW 3 #define VXB_INTCTLRLIB_LOWLVL_SIZE ( 1<< VXB_INTCTLRLIB_LOWLVL_SIZE_POW) struct intCtlrMoreDrvName * pMoreNames; void (*isr)(void * pArg, int inputPin);
这里就相当于创建了一个两级表,第一级是496的大小,第二级分别对应于第一级的每一个元素,大小为8,到这里中断的创建以及初始化就完成了。

2,中断的挂接
vxWorks中的vxbus架构初始化分为三个阶段,第一第二阶段一般都是对设备进行初始化,到第三阶段一般是中断的挂接和使能。这里举例说明的这个有点特殊,这是在第二阶段进行的中断挂接和使能,也从另一面说名代码没有特定的规定,都是为了方便
usrRoot->sysClkInit->sysClkConnect->sysHwInit2->vxbDevInit->vxbDevInitInternal->vxbDevIterate->vxbDevInit2Helper->
LOCAL STATUS vxbDevInit2Helper if ( pInst->pDriver->pDrvBusFuncs->devInstanceInit2 == NULL ) (*pInst->pDriver->pDrvBusFuncs->devInstanceInit2)(pInst); pInst->flags |= VXB_INST_INIT2_DONE; LOCAL VOID lsnIntCtlrInstInit2 vxbIntConnect(pInst, 0, vxbMipsLsnIntCtrlIsr, (void*)pInst); vxbIntEnable(pInst, 0, vxbMipsLsnIntCtrlIsr, (void*)pInst); /*可以看出这里所作的工作就只有挂接中断和使能*/
vxbIntConnect->vxbDevIterate->vxbIntCtlrMatch->vxbIntCtlrConnect
直接看函数:熟悉流程即可:
struct vxbDev * pDev, /* Device Information */ int index, /* index of interrupt vector */ VOIDFUNCPTR pIsr, /* ISR */ void * pArg /* parameter */ VXB_ACCESS_INTERRUPT_INFO accessIntrInfo; struct vxbintCtlrMgmt info; VXB_ASSERT(pDev!=NULL, ERROR) /*这里一次把所有实例化的设备和要注册的info进行匹配*/ vxbDevIterate(vxbIntCtlrMatch, &info, VXB_ITERATE_INSTANCES); if ( info.found == TRUE ) return (vxbDevControl (pDev, (pVXB_DEVCTL_HDR)&accessIntrInfo));
LOCAL STATUS vxbIntCtlrMatch struct vxbintCtlrMgmt * pInfo = (struct vxbintCtlrMgmt *)pArg; struct plbIntrEntry * pIntrEntry; struct pIntCtlrTable * pICTab; struct plbIntCtlrTable * pICTab2; struct plbIntCtlrEntry * pEnt; /*在这里会调用匹配到的设备的中断挂接函数,换句话说对不同的中断控制器上的中断挂接会调用对应的中断控制器的额挂接函数*/ func = vxbDevMethodGet(pInst, DEVMETHOD_CALL(vxbIntCtlrConnect)); stat = (*func)(pInst, pInfo->pDev, pInfo->index, pInfo->pIsr, pInfo->pArg, &inputPin);
LOCAL STATUS vxbMipsLsnIntCtlrDevIsrConnect void (*pIsr)(void * pArg), pVXB_LSN_INT_DRV_CTRL pDrvCtrl = pIntCtlr->pDrvCtrl; struct intCtlrHwConf * pIsrHandle = NULL; inputPin = intCtlrPinFind (pDev, indx, pIntCtlr, &pDrvCtrl->isrHandle); pIsrHandle = &(pDrvCtrl->isrHandle); /*在这里调用intCtlrISRAdd函数,这个函数会真正的挂接用户的中断函数*/ if (intCtlrISRAdd(pIsrHandle, inputPin, pIsr, pArg) == ERROR)
struct intCtlrHwConf * pEntries, struct intCtlrISRChainEntry * pChain; struct intCtlrISRChainEntry * pChain2; intCtlrTableCreate(pEntries, inputPin); /*这里创建两个结构体,并初始化为用户中断,用于挂接中断时使用*/ pChain = (struct intCtlrISRChainEntry *)hwMemAlloc(sizeof(*pChain)); pChain2 = (struct intCtlrISRChainEntry *)hwMemAlloc(sizeof(*pChain)); /*获取目前表中现在挂接的中断函数,如果是函数intCtlrStrayISR说明已经初始化为默认的中断函数, 只需要替换为用户的中断函数即可,如果为函数intCtlrChainISR,说明已经至少挂接了一个用户中断函数(多个中断函数可以挂接在一个中断引脚上), 如果为空,说明没有进行过初始化,这时就使用pChain2保存要挂接的中断函数,并赋值为pChain,然后填写到对应引脚上*/ installedIsr = intCtlrTableIsrGet(pEntries, inputPin); if ( installedIsr == (void *)intCtlrStrayISR ) intCtlrTableFill(pEntries, inputPin, pChain->isr, pChain->pArg); else if ( installedIsr == (void *)intCtlrChainISR ) pChain->pNext = (struct intCtlrISRChainEntry *)intCtlrTableArgGet(pEntries, inputPin); intCtlrTableFill(pEntries, inputPin, intCtlrChainISR, pChain); /* create chain, add original entry and the new one */ pChain2->flags = intCtlrTableFlagsGet(pEntries, inputPin); pChain2->pArg = intCtlrTableArgGet(pEntries, inputPin); pChain2->isr = installedIsr; intCtlrTableFill(pEntries, inputPin, intCtlrChainISR, pChain);
struct intCtlrISRChainEntry struct intCtlrISRChainEntry * pNext; void (*isr)(void * pArg, int inputPin);
呼~~,到这里中断的额挂接就完成了。当然了这只是vxWorks系统中属于vxbus架构的函数的挂接,但是这就包含了绝大部分的中断呢。
3,非vxbus中断的挂接
下面说一下不是vxbus结构的中断函数的挂接。
不是vxbus架构的中断函数使用intConnect函数进行挂接,废话少说,看函数:
VOIDFUNCPTR * vector, /* interrupt vector to attach to */ VOIDFUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ /*这里首先看到,进行了三次判断,分别代表的三种中断的挂接,是首先第一种_func_isrConnect, 这是isrobjectn中断的挂接,目前对于isrobject还没有深入分析过,不过这必须打开#INCLUDE_ISR_OBJECT宏定义才可以, 这里不运行;intArchConnect这个函数就是结构中断的额挂接,一个中断号挂接一个中断,当然了在这里执行不到; _func_vxbIntConnect这个函数才是这次的重点,这个函数在vxbLegacyIntInit中被赋值, _func_vxbIntConnect = vxbLegacyIntConnect,看一下这个初始化函数*/ if (_func_isrConnect != NULL) if (_func_isrConnect (vector, routine, parameter) == OK) if (_func_vxbIntConnect != NULL) if (_func_vxbIntConnect(vector, routine, parameter) == OK) return (intArchConnect (vector, (VOIDFUNCPTR) routine,
struct plbIntrEntry * pIntrInfo; /*申请一个legacy设备(legacy在这里代表不是vxbus架构设备也可以说为遗留设备)*/ devID = vxbDevStructAlloc(WAIT_FOREVER); /*初始化设备,主要是名字和总线号,用于之后匹配挂接于那个中断控制器*/ devID->pParentBus = pPlbDev->u.pSubordinateBus; devID->busID = VXB_BUSID_PLB; devID->pRegBase[0] = (void *)1; pIntrInfo = (struct plbIntrEntry *)hwMemAlloc(sizeof(*pIntrInfo)); devID->pIntrInfo = pIntrInfo; if ( vxbDeviceAnnounce(devID) != OK ) vxbLegacyIntDevice = devID; _func_vxbIntConnect = vxbLegacyIntConnect; _func_vxbIntDisconnect = vxbLegacyIntDisconnect; _func_vxbIntEnable = vxbLegacyIntEnable; _func_vxbIntDisable = vxbLegacyIntDisable;
LOCAL STATUS vxbLegacyIntConnect VOIDFUNCPTR * vector, /* interrupt vector to attach to */ VOIDFUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ /*在这里调用vxbIntConnect函数把中断注册进vxbus架构的中断表中*/ if ((vxbIntConnect(vxbLegacyIntDevice,(int)vector,routine, (void *)parameter)) != OK) return(vxbIntEnable(vxbLegacyIntDevice,(int)vector,routine,
vxbIntConnect->vxbDevIterate->vxbIntCtlrMatch->vxbDevMethodGet->vxbIntCtlrConnect->vxbMipsLsnIntCtlrDevIsrConnect
OK...到这里非vxbus结构的中断挂接也完成了。
这里要说明一下:
func = vxbDevMethodGet(pInst, DEVMETHOD_CALL(vxbIntCtlrConnect));这个函数会调用所有注册进系统并实例化的设备对应的vxbIntCtlrConnect函数来进行挂接,但是这里还有一个函数,确保了中断函数会注册进对应的中断控制器中inputPin = intCtlrPinFind (pDev, indx, pIntCtlr, &pDrvCtrl->isrHandle),这个intCtlrPinFind函数只有在对应中断控制器中才可以找到对应的引脚结构体。这也就保证了会注册到对应的引脚结构体中。
ok~~,分析就先到这里,如果有什么不对地方,请留言。。。
|