Marvell xcat 系列交换芯片Linux下的中断机制

转载 2017年10月13日 17:22:36

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




################################################################
原文 http://blog.csdn.net/hdw10/article/details/52355131

相关文章推荐

Marvell 98DX51xx / 98DX81xx 系列交换芯片 内部初始化

//以下仅是本人的一些的理解 /* Marvell 98DX51xx / 98DX81xx 系列交换芯片 内部初始化 现在一些高端防火墙,流量管理等工业级网络设备使用的交换芯片几乎都来自于bro...
  • hdw10
  • hdw10
  • 2012-09-27 18:43
  • 3882

Marvell发布4核A53芯片 基带支持Cat.7 LTE---ESM

美满电子科技(Marvell)宣布推出业界首款高性价比、支持20+20MHz的R10 LTE载波聚合(CA)平台——4核64位ARMAED Mobile PXA1918单芯片系统(SoC)。该平台提供...

Marvell 88E1145PHY芯片的初始化配置

PHY芯片的初始化配置有硬件配置和软件配置两种途径,当系统上电之后默认采用硬件配置的模式,如需要更改配置,可以通过软件写寄存器的方式来更改模式。本文主要说明硬件配置的方法,以Marvell 88E11...

Marvell 千兆PHY芯片88E1340S/88E1340/88E1322

<!-- @page {margin:2cm} pre.western {font-family:"DejaVu Sans",sans-serif} pre.cjk {font-fa...
  • hdw10
  • hdw10
  • 2013-01-30 18:44
  • 4015

linux下i2c与时钟芯片pcf8563通信(二)

linux 下 i2c 的驱动 以及 与时钟芯片 pcf8563之间的通信(二) 2012/7/10 linux下i2c驱动与通信(二) by:韩大卫 @吉林师范大学
  • hdw10
  • hdw10
  • 2012-07-13 18:19
  • 2668

linux下i2c与时钟芯片pcf8563的通信

linux下的i2c驱动以及与时钟芯片pcf8563通信过程              为更深入的了解linux下的i2c总线驱动以及通信原理,可以用一个用户程序模拟, 这个程序,可...
  • hdw10
  • hdw10
  • 2012-07-06 18:15
  • 2979
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)