Marvell xCat 系列交换芯片中断机制
--by handawei :QQ:1328990789
Marvell Xcat 系列交换芯片作为FE/GE/XE交换机的主方案来讲,性价比很高。
本文以AC3 : 98DX3236 作为对象,介绍CPSS SDK中断机制。
AC3 交换芯片内部有一个ARM V7 双核800MHz 的CPU。 因此产品不需要额外的处理器。整个方案功耗方面做得很小。
有两路serdes可以作为连接到CPU内部,当CPU的管理网口,也可以作为连接PP的业务口。
AC3 serdes资源如下:
如果出电口的话, 推荐方案使用88E1685。光口则可以使用Serdes 直接引出。如果想做Combo,推荐方案88E1548 。都可以接2路QSGMII,出8个口。
与Drake(BC2系列)不同, AC3 的内部只有一个包处理器(简称PP)。整体最多出24个GE,4个XE。 PP作为内部交换芯片,中断部分也直接连到CPU内部,而不是像Lion/Lion2 作为PCIE从设备,通过PCIE中断进入CPU。
下面是AC3 部分中断源信息:
可以看到, 中断33 是第一个switch core的中断号。 AC3内部的PP的中断号就是33。但在CPSS SDK中,这个资源并不是直接写在代码中(兼容性)。也不是是像其他Linux下的platform设备一样,使用platform_get_resource(pdev, IORESOURCE_IRQ,0) 这种方式获。而是将PP作为一个PCIE设备,读取其PCIE配置空间的头部信息,获取到中断号。但PP并不是作为PCIE从设备,显式地挂载到PCIE总线下,因此在Linux 下,并不能通过cat /proc/bus/pci/devices 这种方式直接看到PP设备的存在,只能通过在内核态下对PCIE总线进行遍历,匹配到设备ID之后,再按照配置空间的头部的固定格式将中断号解析出来。
拿到中断号后,再交由内核态的通过request_irq进行中断服务函数的注册。在中断来临后,该中断服务函数调用一个tasklet软中断,软中断再触发事件对应的监听线程。在事件监听线程里面,通过对具体事件枚举的判断,再执行对应的逻辑。比如端口Link 状态变化的Link status change事件,或者PP交给CPU的的报文触发的RX事件。
下面观察一下Marecll CPSS SDK中具体软件流程:
一,中断初始化部分:
交换芯片入口 : cpssInitSystem , 先调用appDemoBoardPhase1Init 进行第一阶段硬件初始化,
appDemoBoardPhase1Init 调用 boardCfgFuncs->boardGetPpPh1Params 对应的各个具体平台的 getPpPhase1Config ,获取各个具体的硬件参数(中断号):
getPpPhase1Config 使用 extDrvGetPciIntVec ,通过 PRESTERA_IOC_GETINTVEC ioctl 系统调用, 获取到硬件中断号, 保存到localPpPh1Config.intVecNum 中。
appDemoBoardPhase1Init 再调用 sysCfgFuncs->cpssHwPpPhase1Init(appDemoDxHwPpPhase1Init),
appDemoDxHwPpPhase1Init 调用 cpssDxChHwPpPhase1Init ,
cpssDxChHwPpPhase1Init 调用 prvCpssDrvInterruptsInit 初始化中断部分,同时传入中断号,
在 prvCpssDrvInterruptsInit 中,
对芯片中断控制器 prvCpssDrvPpConfig[devNum]->intCtrl 数据结构进行初始化
包括 prvCpssDrvInterruptPpSR 地址赋值给prvCpssDrvPpConfig[devNum]->intCtrl.isrFuncPtr ,
prvCpssDrvInterruptsInit 调用 prvCpssDrvGenExMxDxObjPtr->drvHwPpInterruptInit (drvInterruptsInit)初始化各个端口组(Port Group)的中断,
drvInterruptsInit 调用prvCpssDrvInterruptConnect, 同时将函数 prvCpssDrvInterruptPpSR 地址作为参数,传给prvCpssDrvInterruptConnect,
prvCpssDrvInterruptConnect 将 prvCpssDrvInterruptPpSR 地址 保存到对应的 prvCpssDrvComIntSvcRtnDb.intVecMap中,
再调用 cpssExtDrvIntConnect(地址为 extDrvIntConnect),将interruptMainSr 地址作为参数传入,
extDrvIntConnect中, 将interruptMainSr 地址赋值给intTask 中的函数指针。
再调用 PRESTERA_IOC_INTCONNECT ioctl 系统接口,
mvPP.ko 中的prestera_ioctl 对应调用prestera_int_connect 申请软中断和硬中断的中断服务函数。
调用 tasklet_init 申请软中断服务函数 : prestera_bh
调用request_irq 申请硬号33的中断服务函数 : prestera_tl_isr
调用完成后, 创建 intTask 线程,通过 PRESTERA_IOC_WAIT 系统调用, 等待中断来临,
mvPP.ko 中, PRESTERA_IOC_WAIT 调用down_interruptible, 根据信号量实现阻塞,等待中断来临。
第二,中断分发过程:
硬中断33到来,CPU 进入异常向量表, 找到中断地址 irq_handler, irq_handler 宏是 arch_irq_handler_default 的封装,
通过get_irqnr_preamble 保留进程地址,
通过 get_irqnr_and_base 获取到中断号,将中断号和寄存器列表传给C函数: asm_do_IRQ ,
asm_do_IRQ 调用handle_IRQ,
handle_IRQ 调用中断顶部 generic_handle_irq 处理硬中断, 调用中断号33 对应的中断处理函数prestera_tl_isr ,调用testklet_schdule(),唤醒HI_SOFTIRQ 类型的软中断 ,
里面调用 中断底部 irq_exit 唤醒软中断服务主函数 invoke_softirq, invoke_softirq 调用do_softirq ,
do_softirq 调用__do_softirq,__do_softirq 根据pending 标记调用对应的软中断服务函数, 这里是 HI_SOFTIRQ 类型的中断服务函数tasklet_hi_action .
tasklet_hi_action 调用具体软中断服务函数 prestera_bh, 将信号量恢复。
信号量恢复后intTask 中PRESTERA_IOC_WAIT 的阻塞就会退出, 再调用 interruptMainSr,
interruptMainSr 调用 prvCpssDrvInterruptPpSR,
prvCpssDrvInterruptPpSR调用 prvCpssDrvIntEvReqDrvnScan 遍历各个中断原因寄存器, 调用prvCpssDrvEvReqQInsert 插入具体事件。
prvCpssDrvEvReqQInsert 调用 prvCpssDrvEvReqNotify ,向指定信号量ID发送信号,监听该信号量ID的等待线程结束等待。
cpssOsSigSemSignal , 即osSemSignal ,进行MVKERNELEXT_IOC_SEMSIGNAL 系统调用,
mv_KernelExt.ko 内核模块中, 对应调用mvKernelExt_SemSignal ,发送指定的信号量。
这样cpssEventSelect 的等待退出,实现了监听指定事件的功能。
第三,事件处理部分:
芯片初始化入口 cpssInitSystem , 结尾阶段调用cpssInitSystem_afterBasicConfig,
cpssInitSystem_afterBasicConfig 调用appDemoEventRequestDrvnModeInit
appDemoEventRequestDrvnModeInit里初始化evHndlrCauseAllArr数组,为10个数组成员绑定不同的事件组,
比如
evHndlrCauseAllArr[9] 里,包含了CPSS_PP_PORT_LINK_STATUS_CHANGED_E --------- 44
evHndlrCauseAllArr[1]里, 包含CPSS_PP_RX_BUFFER_QUEUE0_E --------- 155
evHndlrCauseAllArr[0] 里, 包含 CPSS_PP_PORT_SYNC_STATUS_CHANGED_E ---------------- 52
调用10次 cpssEventBind ,通过事件列表创建了事件处理信息数据结构,将10个事件组成员依次封装位为事件处理信息结构类型,
cpssEventBind调用
prvCpssEventBind ,调用
cpssOsSigSemBinCreate , 即osSemCCreate 申请信号量ID,
osSemCCreate 通过 CREATE_SEM 宏创建信号量ID 。
最后,结合事件evHndlrCauseAllArr[]和信号量ID,创建事件处理信息 PRV_CPSS_DRV_EVENT_HNDL_STC 指针,将地址保存到taskParamArr[] 中。
调用osTaskCreate 创建10个线程, 线程地址appDemoEvHndlr ,依次传入taskParamArr[] 各个成员,将事件处理信息交给appDemoEvHndlr 。
appDemoEvHndlr 调用 cpssEventSelect 监听各个事件参数,等待各事件的到来。
cpssEventSelect 通过调用 cpssOsSigSemWait, 即osSemWait, 进行 MVKERNELEXT_IOC_SEMWAIT 系统调用,
mv_KernelExt.ko 内核模块中, 对应调用mvKernelExt_SemWait ,等待指定的信号量,实现事件等待。
当 prvCpssDrvIntEvReqDrvnScan 插入新事件后,调用prvCpssDrvEvReqNotify 唤醒该事件监听的线程,
进而 appDemoEvHndlr 的cpssEventSelect的监听等待结束。
cpssEventSelect内部 通过cpssOsSigSemWait 实现等待指定信号量ID, prvCpssDrvEvReqNotify 发送该信号量之后,等待退出,
cpssEventSelect 再调用prvCpssDrvEvReqQBitmapGet 获取到具体事件类型(比如 CPSS_PP_PORT_LINK_STATUS_CHANGED_E)后返回appDemoEvHndlr,
appDemoEvHndlr 调用cpssEventRecv 获取到具体物理端口号, 再调用 appDemoEnPpEvTreat 处理具体事件.
appDemoEnPpEvTreat 里面, 根据事件类型, 如果是CPSS_PP_RX_BUFFER_QUEUE0_E 类型, 调用cpssEnRxPacketGet 处理收包逻辑。
如果是CPSS_PP_PORT_LINK_STATUS_CHANGED_E 类型, 打印出具体物理端口的 LINK UP/DOWN 的情况
*******************************************
部分代码简介:
appDemoEvHndlr 定义:
appDemoEvHndlr(GT_VOID * param ){
...
GT_U32 evBitmapArr[CPSS_UNI_EV_BITMAP_SIZE_CNS];
cpssEventSelect(evHndl, NULL, evBitmapArr, (GT_U32)CPSS_UNI_EV_BITMAP_SIZE_CNS);
CPSS_UNI_EV_BITMAP_SIZE_CNS 定义:
...
CPSS_DRAGONITE_ERROR_E , /* 408 */
CPSS_DRAGONITE_UNI_EV_DUMMY_MAX_E,/* dummy -- must be 1 before CPSS_DRAGONITE_UNI_EV_MAX_E */ ---> 409
CPSS_DRAGONITE_UNI_EV_MAX_E = (CPSS_DRAGONITE_UNI_EV_DUMMY_MAX_E-1), -------> 408
/************************** End of events *********************************/
CPSS_UNI_EV_DUMMY_MAX_E,/* dummy -- must be 1 before CPSS_UNI_EVENT_COUNT_E */ ---------> 409
CPSS_UNI_EVENT_COUNT_E = (CPSS_UNI_EV_DUMMY_MAX_E), --------------> 409
} CPSS_UNI_EV_CAUSE_ENT;
#define CPSS_UNI_EV_BITMAP_SIZE_CNS ((CPSS_UNI_EVENT_COUNT_E + 31) / 32)
将全部的事件, 作为一个32位的bitmap, 每次只有一个bit 是为1 的,长度 CPSS_UNI_EV_BITMAP_SIZE_CNS = (409 + 31) / 32 = 13
evBitmapArr 是一个13 成员的数组, 里面的每一个bit, 表示一个具体的事件
事件匹配算法:
for (evCauseIdx = 0; evCauseIdx < CPSS_UNI_EV_BITMAP_SIZE_CNS; evCauseIdx++)
{
if (evBitmapArr[evCauseIdx] == 0) --------------------> 先找到当前非0 的成员
{
continue;
}
evBitmap = evBitmapArr[evCauseIdx];
for (i = 0; evBitmap; evBitmap >>= 1, i++) --------------> 再在当前成员里面, 找到具体的bit
{
if ((evBitmap & 1) == 0) ------------------------> 找到非0 的bit,i 表示个数,i 表示在当前的数组里面的偏移
{
continue;
}
uniEv = (evCauseIdx << 5) + i; --> 事件类型就是evCauseIdx 索引 * 32 + 偏移,这个就是在整个事件类型枚举里面的数值
if (cpssEventRecv(evHndl, uniEv, &evExtData, &devNum) == GT_OK){ ------------> 获取到具体的物理端口号
....
appDemoEnPpEvTreat(evHndl, uniEv, &evExtData, &devNum) -------------> 传入端口号,处理具体事件
}
**********************************************
1,prvCpssDrvIntEvReqDrvnScan , 插入的就是具体事件类型原理
2, prvCpssDrvEvReqQInsert, 插入事件原理 -->将事件插入事件控制队列尾部,向事件处理信息中的信号量ID发送信号,实现监听线程等待结束
typedef struct PRV_CPSS_DRV_EV_REQ_Q_CTRL_STCT
{
PRV_CPSS_DRV_EV_REQ_NODE_STC *evNodeList; --------------> 事件头节点信息
GT_U32 uniEvCause; ----------------> 事件原因
PRV_CPSS_DRV_EVENT_HNDL_STC *userHndlPtr; ----------------> 事件处理信息
struct PRV_CPSS_DRV_EV_REQ_Q_CTRL_STCT *nextPtr; -------------> 事件控制队列中下一节点
} PRV_CPSS_DRV_EV_REQ_Q_CTRL_STC; ----------------> 事件控制队列
typedef struct PRV_CPSS_DRV_EV_REQ_NODE_STCT --------------> 事件节点数据结构
{
GT_U8 devNum; --------------> 设备ID
GT_U32 portGroupId; --------------> 端口组ID
GT_U8 intStatus; --------------> 中断状态
GT_U8 intRecStatus; --------------> 中断接收时间
GT_U32 intCause; --------------> 中断原因索引值
GT_U32 uniEvCause; --------------> 事件原因索引值
GT_U32 uniEvExt; --------------> 事件附带信息(如物理端口ID)
PRV_CPSS_DRV_REQ_DRVN_MASK_SET_FUNC intMaskSetFptr; ---------------> 事件掩码方法
PRV_CPSS_DRV_EV_DRVN_INT_REC_CB intCbFuncPtr; -----------------> 回调函数, 向指定任务发送信号
GT_U32 intMaskReg; ----------> 掩码后的中断寄存器
GT_U32 intBitMask; ----------> 掩码后的中断寄存器的bit
struct PRV_CPSS_DRV_EV_REQ_NODE_STCT *prevPtr; ---------> 事件链表中前一节点
struct PRV_CPSS_DRV_EV_REQ_NODE_STCT *nextPtr; --------> 事件链表中后一节点
}PRV_CPSS_DRV_EV_REQ_NODE_STC;
事件插入函数: prvCpssDrvEvReqQInsert : 向事件控制队列尾部插入新事件
GT_STATUS prvCpssDrvEvReqQInsert
(
IN PRV_CPSS_DRV_EV_REQ_NODE_STC evNodePool[], ----> 中断节点池地址
IN GT_U32 intIndex, ----> 中断池中的索引值
IN GT_BOOL masked ----> 是否需要掩码
)
{
PRV_CPSS_DRV_EV_REQ_NODE_STC *newNode; -------> 要插入的新事件节点
PRV_CPSS_DRV_EV_REQ_Q_CTRL_STC *evQueue; -------> 事件控制队列
newNode = &(evNodePool[intIndex]); ------> 中断节点池中的节点地址,就是要插入的新事件节点
switch (newNode->intRecStatus) -------> 判断节点的中断状态(正常进入至此的状态是: PRV_CPSS_DRV_EV_DRVN_INT_IDLE_E)
{
case PRV_CPSS_DRV_EV_DRVN_INT_RCVD_E: -------> 中断在系统正常操作下接受
newNode->intRecStatus = PRV_CPSS_DRV_EV_DRVN_INT_MASKED_E; -------> 标记为中断被掩盖,函数退出
return GT_OK;
case PRV_CPSS_DRV_EV_DRVN_INT_MASKED_E: ------> 中断是被掩盖的,直接退出
return GT_OK;
default:
break;
}
if (GT_TRUE == masked) { -----------> 如果标记为掩码,退出
if(newNode->intRecStatus == PRV_CPSS_DRV_EV_DRVN_INT_IDLE_READY_E) {
newNode->intRecStatus = PRV_CPSS_DRV_EV_DRVN_INT_MASKED_E;
}
return GT_OK;
}
evQueue = &(prvCpssDrvComIntEvReqQueuesDb.uniEvQArr[newNode->uniEvCause]); ------------> 在事件数据库里获取到事件的控制队列
if(newNode->intRecStatus != PRV_CPSS_DRV_EV_DRVN_INT_IDLE_READY_E)
{
newNode->intRecStatus = PRV_CPSS_DRV_EV_DRVN_INT_RCVD_E;
if (NULL == evQueue->evNodeList) { ----------------> 头节点为空, 将新节点作为头节点
evQueue->evNodeList = newNode;
newNode->nextPtr = newNode;
newNode->prevPtr = newNode;
} else {
evQueue->evNodeList->prevPtr->nextPtr = newNode; ----> 将新节点添加到事件链表尾部,由于双向链表,头节点上一个节点就是原尾节点
newNode->nextPtr = evQueue->evNodeList; ----> 新节点的下一节点指向头节点
newNode->prevPtr = evQueue->evNodeList->prevPtr; ----> 新节点前节点指向原头节点的上节点(原尾节点)
evQueue->evNodeList->prevPtr = newNode; ------> 头节点的新前节点指向新节点, 完成新节点的插入
}
}
else {
newNode->intRecStatus = PRV_CPSS_DRV_EV_DRVN_INT_MASKED_E;
}
if (NULL != evQueue->userHndlPtr){
prvCpssDrvEvReqNotify(evQueue->userHndlPtr); -----------> 将事件的处理信息传给事件通知函数
}
return GT_OK;
}
GT_VOID prvCpssDrvEvReqNotify
(
IN PRV_CPSS_DRV_EVENT_HNDL_STC *hndlEvPtr
)
{
...
cpssOsSigSemSignal((CPSS_OS_SIG_SEM) PRV_CPSS_DRV_HANDEL_SEM_MAC(hndlEvPtr)); ----> cpssOsSigSemSignal :osSemSignal
-----------> PRV_CPSS_DRV_HANDEL_SEM_MAC: (handlerPtr)->hndlBindInfo.semInfo.semId
-----------> 发送事件处理信息中的信号量ID,等待该信号量的线程实现等待结束
...
}
***********************
cpssEventSelect :
调用cpssOsSigSemWait 等待指定信号量,
等待完成后, 调用prvCpssDrvEvReqQBitmapGet 获取到事件具体,并转化位bitmap, 返回获取到的事件个数。
GT_U32 prvCpssDrvEvReqQBitmapGet
(
IN GT_UINTPTR hndl, -------> PRV_CPSS_DRV_EVENT_HNDL_STC 事件处理信息数据结构的地址
INOUT GT_U32 evBitmapArr[], -------> bitmap
IN GT_U32 evBitmapLength ---------> bitmap 长度
)
{
GT_U32 evCount; ------> 新事件计数
PRV_CPSS_DRV_EVENT_HNDL_STC *hndlEvPtr; -------> 事件处理信息指针
PRV_CPSS_DRV_EV_REQ_Q_CTRL_STC *evReqPtr; ---------> 事件控制队列
evCount = 0;
hndlEvPtr = (PRV_CPSS_DRV_EVENT_HNDL_STC*)hndl; -------> 获取到事件处理信息结构
evReqPtr = hndlEvPtr->evListPtr;
if (NULL != evBitmapArr)
{
cpssOsBzero((GT_VOID*)evBitmapArr, evBitmapLength * sizeof(evBitmapArr[0])); -------> 将bmp 清零
}
if (PRV_CPSS_DRV_TX_BUFF_QUEUE_EVENT_E == hndlEvPtr->evType) ------> 事件处理类型为2类,一类是“TX buffer ”事件, 另一类是普通事件
{
if (NULL != ((PRV_CPSS_TX_BUF_QUEUE_FIFO_STC *)hndlEvPtr->extDataPtr)->headPtr)
{
/* at least one TxBufferQueue in FIFO */
if (NULL != evBitmapArr)
{
evBitmapArr[evReqPtr->uniEvCause >> 5] |=
(1 << (evReqPtr->uniEvCause & 0x1F));
}
evCount = 1;
}
}
else
{
if (NULL == evBitmapArr) ----> evBitmapArr指针为空, 仅统计事件个数
{
while (evReqPtr)
{
if (evReqPtr->evNodeList != NULL) ----> 统计事件处理信息中,事件控制队列的长度表示有多少事件等待被处理
{
evCount++;
}
evReqPtr = evReqPtr->nextPtr;
}
}
else
{
while (evReqPtr)
{
if (evReqPtr->evNodeList != NULL && ----> 如果事件控制列表头节点不为空, 事件原因在事件类型枚举里
(evReqPtr->uniEvCause >> 5) < evBitmapLength)
{ -----------> 这说明当接收到这个事件处理信息后,事件原因就是确定的
evBitmapArr[evReqPtr->uniEvCause >> 5] |= ----> prvCpssDrvEvReqQBitmapGet作用就是将事件原因转化到bitmap中
(1 << (evReqPtr->uniEvCause & 0x1F)); ------------> evReqPtr->uniEvCause >> 5 作用计算事件类型所在的 bit组,
--------> (1 << (evReqPtr->uniEvCause & 0x1F) 作用获取到具体的bit,存入bit[] 中
evCount++;
}
/* move to the next binded event */
evReqPtr = evReqPtr->nextPtr;
}
}
}
return evCount;
}
GT_U8 prvCpssDrvIntEvReqDrvnScan
(
GT_U8 devNum,
GT_U32 portGroupId,
PRV_CPSS_DRV_EV_REQ_NODE_STC *intNodesPool,
GT_U32 *intMaskShadow,
PRV_CPSS_DRV_INTERRUPT_SCAN_STC *pIntScanNode
)
{
PRV_CPSS_DRV_EV_REQ_NODE_STC *evNodesPool; ------------> 事件节点
PRV_CPSS_DRV_INTERRUPT_SCAN_STC *intScanStackPtr[PRV_CPSS_DRV_SCAN_STACK_SIZE_CNS]; ---> 中断寄存器查询树指针
PRV_CPSS_DRV_INTERRUPT_SCAN_STC *currIntScanPtr; ----> 当前树节点
PRV_CPSS_DRV_INTERRUPT_SCAN_STC **intStackTopPtr; ----> 树顶
GT_U32 i;
GT_U32 tmpCauseBits;
GT_U32 intMaskBits;
GT_U32 intMaskBit;
GT_U32 *maskShdwValPtr;
GT_BOOL intMasked;
GT_U32 intCause;
GT_U32 newInt;
evNodesPool = intNodesPool;
newInt = 0;
/* push */
intScanStackPtr[0] = pIntScanNode;
intStackTopPtr = &intScanStackPtr[0];
while (intStackTopPtr >= &intScanStackPtr[0]) {
currIntScanPtr = *intStackTopPtr;
intStackTopPtr--;
...
--------> currIntScanPtr->pRegReadFunc 的地址是: prvCpssDrvHwPpPortGroupIsrRead
------------->currIntScanPtr->causeRegAddr 地址是 0x30,将图1 ( Global Interrupts Summary Cause Register )
currIntScanPtr->pRegReadFunc(devNum, portGroupId,currIntScanPtr->causeRegAddr,
&intCause);
maskShdwValPtr = &intMaskShadow[currIntScanPtr->startIdx >> 5]; --------> 转换到对应的bitmap掩码
tmpCauseBits = intCause & currIntScanPtr->nonSumBitMask; ---------->经过掩码后的数值
intMaskBits = 0;
if (tmpCauseBits != 0) ------------> 经过掩码后的数值不为0,则获取到具体的事件
{
tmpCauseBits >>= currIntScanPtr->startIdx & 0x1f; -------> 转化为 0-31 bit 之间
获取到事件类型算法:
for (i = currIntScanPtr->startIdx;
(i <= currIntScanPtr->endIdx && tmpCauseBits); ----------------> 循环遍历
i++, tmpCauseBits >>= 1)
{
if (tmpCauseBits & 1)
{
...
--------------> evNodesPool[i].uniEvCause 就是具体的事件枚举
if (NULL != prvCpssDrvEvReqQUserHndlGet(evNodesPool[i].uniEvCause)) ----> 获取到事件处理信息
{
/* insert the event into queue */
intMaskBit = 1 << (i & 0x1f);
intMaskBits |= intMaskBit;
if (*maskShdwValPtr & intMaskBit)
{
intMasked = GT_FALSE;
newInt = 1;
}
else
{
intMasked = GT_TRUE;
}
prvCpssDrvEvReqQInsert(evNodesPool, i, intMasked); ---------> 插入新事件,当前事件处理信息中附带具体事件枚举
}
else
{
newInt = 1;
}
}
}
*maskShdwValPtr &= ~(intMaskBits & currIntScanPtr->maskRcvIntrEn);
currIntScanPtr->pRegWriteFunc(devNum,portGroupId,
currIntScanPtr->maskRegAddr,
*maskShdwValPtr);
}
/* Scan summary interrupt bits. */
tmpCauseBits = (intCause & ~(currIntScanPtr->nonSumBitMask) &
*maskShdwValPtr);
if(tmpCauseBits != 0)
{
for(i = 0; i < currIntScanPtr->subIntrListLen; i++)
{
if (((tmpCauseBits >> ((currIntScanPtr->subIntrScan[i]->bitNum)
& 0x1f)) & 1) == 1)
{
intStackTopPtr++;
if (intStackTopPtr > &intScanStackPtr[PRV_CPSS_DRV_SCAN_STACK_LAST_ENTRY_CNS])
{
DBG_LOG(("scan stack overflow !!\n",1,2,3,4,5,6));
return 0;
}
*intStackTopPtr = currIntScanPtr->subIntrScan[i];
}
}
}
if(currIntScanPtr->rwBitMask != 0)
{
currIntScanPtr->pRegWriteFunc(devNum,portGroupId,currIntScanPtr->causeRegAddr,
~(intCause & currIntScanPtr->rwBitMask));
}
} &nb