vxWorks6.9下的PCI MSI支持

本文仅讨论在vxworks6.9下I对支持MSI的支持,vxworks7.0对MSI的支持方式有变化,不在本文涉及范围内

开发环境

vxworks6.9
vscode

修改的文件

  1. g64120aPci.c 所使用的PCI总线控制器
  2. hwconf.c
  3. vxbxxxIntCtlr.c 所使用的中断控制器

PCI设备

PCI配置空间寄存器

在这里插入图片描述

PCI设备的三种中断方式:

  1. 中断线方式,根据Interrupt Pin寄存器的值,分配中断号填入Interrupt Line(0x3C)寄存器中;并将Command寄存器中的bit10(Interrupt Disable)置0,同时,MSI/MSI-X Capabilities的Message Control寄存器的bit0(MSI/MSI-X Enable)置0,即三种方式只能使用一种

Command寄存器

在这里插入图片描述

MSI capabilities

在这里插入图片描述

MSI-X capabilities

Message control寄存器

在这里插入图片描述

  1. MSI方式,需要填写MSI capabilities的Message Data和Message Address寄存器,Message Address寄存器为产生中断时发送的MSI消息的目的地址(PCI域地址),Message Data为MSI消息的内容,一般按照处理器需要的格式填写,但基本都将分配的中断号包含在其中,有些会包含触发方式等bit;Command寄存器Interrupt Disable位置1,MSI capabilities的Message control寄存器Enable置1,同时MSI-X 的Message control的Enable置0
  2. MSI-X方式,需要填写MSI-X Table Offset、BAR Indicator等;Command寄存器Interrupt Disable位置1,MSI capabilities的Message control寄存器Enable置0,同时MSI-X 的Message control的Enable置1

PCI总线控制器

​ g64120aPci是不支持msi的,需要修改添加如下代码:

 #include <drv/multi/gt64120a.h>
 #include <../src/hwif/h/busCtlr/g64120aPci.h>

+#include <../src/hwif/intCtlr/vxbIntCtlrLib.h>
+#include <../src/hwif/intCtlr/vxbIntDynaCtlrLib.h>
+

+LOCAL STATUS   g64120aPciMSIProgram (VXB_DEVICE_ID, struct vxbIntDynaVecInfo *);
 LOCAL device_method_t g64120aPci_methods[] =
     {
 #ifdef VXB_LEGACY_ACCESS
@@ -152,6 +156,14 @@ LOCAL device_method_t g64120aPci_methods[] =
 #ifdef LSNINT_LEGACY_SUPPORT
        DEVMETHOD(g64120aPciIntEnable, sysIntEnablePIC),
 #endif
+
+    DEVMETHOD(vxbIntDynaVecProgram, g64120aPciMSIProgram),
+    DEVMETHOD(vxbIntDynaVecEnable, vxbPciMSIEnable),
+    DEVMETHOD(vxbIntDynaVecDisable, vxbPciMSIDisable),
+    DEVMETHOD(vxbIntDynaVecErase, vxbPciMSIErase),
+    DEVMETHOD(vxbIntDynaVecGet, vxbPciMSIGet),
+    DEVMETHOD(vxbDevIntCapabCheck, vxbPciDevIntCapabCheck),
+
        { 0, 0}
     };
@@ -526,7 +538,16 @@ LOCAL void g64120aPciInstInit
      */

     devResourceGet(pHcf, "autoConfig", HCF_RES_INT, (void*)&pDrvCtrl->autoConfig);
-    }
+
+    /*
+     * resourceDesc {
+     * The msiEnable resource specifies the
+     * MSI is enabled or not. }
+     */
+
+    (void)devResourceGet(pHcf, "msiEnable", HCF_RES_INT, (void*)&pDrvCtrl->pexMsi);
+
+       }

     /* initialize PCI configuration library */
     pDrvCtrl->pIntInfo = (struct vxbPciInt *)hwMemAlloc(sizeof(struct vxbPciInt));

@@ -1107,68 +1128,118 @@ LOCAL STATUS g64120aPciDevControl
     pVXB_ACCESS_INTERRUPT_INFO accessIntrInfo;
     struct pciIntrEntry *pIntInfo;
     UINT8 idx;
+       VXB_DEVICE_ID pBusDev;
+    VOIDFUNCPTR * ivec;
+    struct vxbIntDynaVecInfo dynaArg;

     VXB_ASSERT(pDev != NULL && pBusDevControl != NULL, ERROR)

+
+    if (pBusDevControl->vxbAccessId != VXB_ACCESS_INT_VEC_GET)
+        {
+        accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
+               pIntInfo = (struct pciIntrEntry *)pDev->pIntrInfo;
+
+        /* check if the index is valid */
+        if (accessIntrInfo->intIndex >= 255)
+            return (ERROR);
+
+        ivec =
+            (VOIDFUNCPTR *)pIntInfo->intVecInfo[accessIntrInfo->intIndex].intVector;
+        }
+
+
     switch (pBusDevControl->vxbAccessId)
         {
         case VXB_ACCESS_INT_VEC_GET:
             accessVectorGet = (pVXB_ACCESS_INT_VECTOR_GET) pBusDevControl;
             pIntInfo = (struct pciIntrEntry *)pDev->pIntrInfo;

-            /* check if the index is valid */
-
-            if (accessVectorGet->intIndex >= 255)
-                rc = ERROR;
-            else
-                accessVectorGet->pIntVector =
-                    INUM_TO_IVEC(pIntInfo->intVecInfo[accessVectorGet->intIndex].index);
+                       pBusDev = vxbDevParent (pDev);
+                       pDrvCtrl = pBusDev->pDrvCtrl;
+            if (pDrvCtrl->pexMsi == TRUE && vxbPciMSIIsCap (pDev) == TRUE){
+                accessVectorGet->pIntVector = (VOIDFUNCPTR *)VXB_INTR_DYNAMIC;
+            }
+                       else{
+
+                   /* check if the index is valid */
+
+                   if (accessVectorGet->intIndex >= 255)
+                       rc = ERROR;
+                   else
+                       accessVectorGet->pIntVector =
+                           INUM_TO_IVEC(pIntInfo->intVecInfo[accessVectorGet->intIndex].index);
+                       }
             break;

         case VXB_ACCESS_INT_ENABLE:
             accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
             pIntInfo = (struct pciIntrEntry *)pDev->pIntrInfo;
             idx = accessIntrInfo->intIndex;
-
-            if (accessIntrInfo->intIndex >= 255)
-                rc = ERROR;
-            else
-                {
-                pDev = vxbDevParent (pDev);
-                pDrvCtrl = pDev->pDrvCtrl;
-
-                if (pDrvCtrl->gtIntEnable != NULL)
-                (*pDrvCtrl->gtIntEnable)(pIntInfo->intVecInfo[idx].intVector);
-                else{
-                    /*intEnable ((int)pIntInfo->intVecInfo[idx].intVector);*/
-                }
-                }
+
+            if (ivec == (VOIDFUNCPTR *)VXB_INTR_DYNAMIC){
+                rc = vxbIntEnable (pDev, 0, accessIntrInfo->pISR, accessIntrInfo->pParameter);
+            }
+                       else{
+
+                   if (accessIntrInfo->intIndex >= 255)
+                       rc = ERROR;
+                   else{
+                       pDev = vxbDevParent (pDev);
+                       pDrvCtrl = pDev->pDrvCtrl;
+
+                       if (pDrvCtrl->gtIntEnable != NULL)
+                       (*pDrvCtrl->gtIntEnable)(pIntInfo->intVecInfo[idx].intVector);
+                       else{
+                           /*intEnable ((int)pIntInfo->intVecInfo[idx].intVector);*/
+                       }
+                   }
+                       }
             break;
 #ifdef notdef
         case VXB_ACCESS_INT_DISABLE:
             accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
             pIntInfo = (struct pciIntrEntry *)pDev->pIntrInfo;
             idx = accessIntrInfo->intIndex;
-
-            if (accessIntrInfo->intIndex >= 255)
-                rc = ERROR;
-            else
-                intDisable (pIntInfo->intVecInfo[idx].intVector);
+
+            if (ivec == (VOIDFUNCPTR *)VXB_INTR_DYNAMIC){
+                rc = vxbIntDisable (pDev, 0, accessIntrInfo->pISR, accessIntrInfo->pParameter);
+            }
+                       else{
+                   if (accessIntrInfo->intIndex >= 255)
+                       rc = ERROR;
+                   else
+                       intDisable (pIntInfo->intVecInfo[idx].intVector);
+               }
             break;
 #endif
         case VXB_ACCESS_INT_CONNECT:
             accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
             pIntInfo = (struct pciIntrEntry *)pDev->pIntrInfo;
             idx = accessIntrInfo->intIndex;
+
+            if (ivec == (VOIDFUNCPTR *)VXB_INTR_DYNAMIC){
+                dynaArg.isr = accessIntrInfo->pISR;
+                dynaArg.pArg = accessIntrInfo->pParameter;
+                rc = _func_vxbIntDynaConnect (pDev, 1, &dynaArg);
+            }
+            else{
             rc = vxbPciIntConnect (pDev,(VOIDFUNCPTR *)pIntInfo->intVecInfo[idx].intVector,
                 accessIntrInfo->pISR, (long)accessIntrInfo->pParameter);
+            }
             break;
         case VXB_ACCESS_INT_DISCONN:
             accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
             pIntInfo = (struct pciIntrEntry *)pDev->pIntrInfo;
             idx = accessIntrInfo->intIndex;
-            rc = vxbPciIntDisconnect (pDev,(VOIDFUNCPTR *)pIntInfo->intVecInfo[idx].intVector,
-                accessIntrInfo->pISR);
+
+            if (ivec == (VOIDFUNCPTR *)VXB_INTR_DYNAMIC){
+                rc = OK;
+            }
+                       else{
+                   rc = vxbPciIntDisconnect (pDev,(VOIDFUNCPTR *)pIntInfo->intVecInfo[idx].intVector,
+                       accessIntrInfo->pISR);
+                       }
             break;
         case VXB_ACCESS_INT_ACKNOWLEDGE:
             break;
@@ -1237,3 +1308,24 @@ LOCAL STATUS g64120aPciMethodConvertBaseAddress
     return (OK);
     }

+LOCAL STATUS g64120aPciMSIProgram
+    (
+    VXB_DEVICE_ID pDev,
+    struct vxbIntDynaVecInfo *dynaVec
+    )
+    {
+    VXB_DEVICE_ID busCtrlID = vxbDevParent(pDev);
+    GT_DRV_CTRL * pDrvCtrl;
+
+    if (busCtrlID == NULL)
+        return ERROR;
+
+    pDrvCtrl = busCtrlID->pDrvCtrl;
+    if (pDrvCtrl == NULL)
+        return ERROR;
+
+
+    return (vxbPciMSIProgram(pDev, dynaVec));
+    }
+

主要是添加这几个方法:

+    DEVMETHOD(vxbIntDynaVecProgram, g64120aPciMSIProgram),写PCI设备的MSI寄存器
+    DEVMETHOD(vxbIntDynaVecEnable, vxbPciMSIEnable),写PCI设备的MSI Enable
+    DEVMETHOD(vxbIntDynaVecDisable, vxbPciMSIDisable),写PCI设备的MSI Disable
+    DEVMETHOD(vxbIntDynaVecErase, vxbPciMSIErase),擦写写入的MSI Vectors
+    DEVMETHOD(vxbIntDynaVecGet, vxbPciMSIGet),获取PCI设备的Message Address and data
+    DEVMETHOD(vxbDevIntCapabCheck, vxbPciDevIntCapabCheck),检查设备是否具备MSI或MSI-X能力

在g64120aPciInstInit中会获取hwconf中的g64120a配置,根据"msiEnable"选项为"TRUE"或者为"FALSE"决定是否开启PCI总线控制器的MSI支持

中断控制器

+#include <../src/hwif/intCtlr/vxbIntCtlrLib.h>
+#include <../src/hwif/intCtlr/vxbIntDynaCtlrLib.h>

+#define LSN_DYN_VECTOR_START  32    /* LSN dynamic vector start (197) */
+#define LSN_DYN_VECTOR_END    37    /* LSN dynamic vector start (223) */
+
+#define LSN_NUM_DYN_VECTORS (LSN_DYN_VECTOR_END - LSN_DYN_VECTOR_START + 1)
+
+/* MSI address fields */
+
+#define VXB_LSN_MSI_BASE             0x000000002FF00000L
+#define VXB_LSN_MSI_DESTID_MASK      0x00000000000FF000L
+#define VXB_LSN_MSI_REDIRHINT        0x0000000000000008L
+#define VXB_LSN_MSI_DEST_MASK        0x0000000000000004L
+#define VXB_LSN_MSI_DEST_LOG         0x0000000000000004L
+#define VXB_LSN_MSI_DEST_PHYS        0x0000000000000000L
+
+/* MSI data fields */
+
+#define VXB_LSN_MSI_TRG_MASK         0x00008000
+#define VXB_LSN_MSI_TRG_LEVEL        0x00008000
+#define VXB_LSN_MSI_TRG_EDGE         0x00000000
+#define VXB_LSN_MSI_DELYSTAT         0x00004000
+#define VXB_LSN_MSI_DESTMODE_MASK    0x00000800
+#define VXB_LSN_MSI_DESTMODE_LOGICAL 0x00000800
+#define VXB_LSN_MSI_DESTMODE_PHYS    0x00000000
+#define VXB_LSN_MSI_DELY_MASK        0x00000700
+#define VXB_LSN_MSI_DELY_FIXED       0x00000000
+#define VXB_LSN_MSI_IRQ_MASK         0x000000FF
+
+#define VXB_LSN_MSI_ADDR(cpu)        ( VXB_LSN_MSI_BASE | \
+                               (((cpu)<<12)&VXB_LSN_MSI_DESTID_MASK) | \
+                               VXB_LSN_MSI_DEST_PHYS )
+
+#define VXB_LSN_MSI_DATA(irq)        ( ((irq)&VXB_LSN_MSI_IRQ_MASK) | \
+                                       VXB_LSN_MSI_TRG_EDGE | \
+                                       VXB_LSN_MSI_DESTMODE_PHYS )
+
+#define xxx_INT_INDEX_SET(pEnt,inputPin, index)      \
+        {                                                \
+        struct vxbIntCtlrPin * pPin =                    \
+           vxbIntCtlrPinEntryGet(pEnt,inputPin);         \
+        pPin->intIndex = index;                          \
+        }
+
+/* save MSI use information */
+
+LOCAL UINT32 xxxIntBitmap [LSN_NUM_DYN_VECTORS /32 +1];
+
+LOCAL VXB_DEVICE_ID xxxDevID;

 LOCAL device_method_t xxxIntCtlr_methods[] =
     {
@@ -182,6 +314,10 @@ LOCAL device_method_t xxxIntCtlr_methods[] =
     DEVMETHOD(vxbIntCtlrDisable, vxbxxxIntCtlrDevIsrDisable),
     DEVMETHOD(vxbIntCtlrAck, vxbxxxIntCtlrAck),
     DEVMETHOD(vxbIntLevelGet, vxbxxxIntLevelGet),
+
+    DEVMETHOD(vxbIntDynaVecConnect, vxbxxxIntCtlrDynaVecConnect),
+    DEVMETHOD(vxbIntCtlrAlloc, vxbxxxIntCtlrAlloc),
+    DEVMETHOD(vxbIntCtlrFree, vxbxxxIntCtlrFree),
     DEVMETHOD_END
     };

@@ -427,6 +592,21 @@ LOCAL STATUS vxbxxxIntCtlrDevIsrConnect
     pVXB_LSN_HT_INT_DRV_CTRL pDrvCtrl = pIntCtlr->pDrvCtrl;
     int                 inputPin = ERROR;
     struct intCtlrHwConf * pIsrHandle = NULL;
+    VXB_INTR_ENTRY   *          pIntInfo = (VXB_INTR_ENTRY *)pDev->pIntrInfo;
+    STATUS                      retVal = ERROR;
+
+    if ((VXB_IS_MSI_INT(pIntInfo->intrFlag) == TRUE) &&
+        ((ULONG)pIntInfo->intVecList[indx] != INVALD_INDEX))
+        {
+        retVal = vxbxxxIntCtlrMsiConnect (pIntCtlr, pDev,
+            (UINT32)(ULONG)pIntInfo->intVecList[indx], indx, pIsr, pArg);
+
+        *pInputPin = (int)(ULONG)pIntInfo->intVecList[indx];
+        return retVal;
+        }
+
+
     /* call the intCtlrPinFind routine to get the pin information */
     inputPin = intCtlrPinFind (pDev, indx, pIntCtlr, &pDrvCtrl->isrHandle);

@@ -434,6 +614,21 @@ LOCAL STATUS vxbxxxIntCtlrDevIsrConnect
         /*  input pin not found, return ERROR */
         return(ERROR);

+
+    /* Legacy MSI entry */
+
+    if (inputPin == VXB_INTR_DYNAMIC)
+        {
+        if (vxbIntAlloc (pDev, VXB_INT_PCI_LEGACY_MSI, 1) <= 0)
+            return ERROR;
+
+        retVal = vxbxxxIntCtlrMsiConnect (pIntCtlr, pDev,
+            (UINT32)(ULONG)pIntInfo->intVecList[indx], indx, pIsr, pArg);
+
+        *pInputPin = (int)(ULONG)pIntInfo->intVecList[indx];
+        return retVal;
+        }
+
     pIsrHandle = &(pDrvCtrl->isrHandle);

     /* connect the isr with the vxBus interrupt library */

 * vxbxxxIntCtlrDevIsrDisconnect - disconnects the ISR to the interrupt pin
@@ -520,6 +807,7 @@ LOCAL STATUS vxbxxxIntCtlrDevIsrDisconnect

     pVXB_LSN_HT_INT_DRV_CTRL pDrvCtrl = pIntCtlr->pDrvCtrl;
     int                 inputPin = ERROR;
+    VXB_INTR_ENTRY        * pIntInfo = pDev->pIntrInfo;

     /* call the intCtlrPinFind routine to get the pin information */

@@ -529,6 +817,12 @@ LOCAL STATUS vxbxxxIntCtlrDevIsrDisconnect
         /*  input pin not found, return ERROR */
         return(ERROR);

+    /* Legacy MSI */
+
+    if (pIntInfo->intrFlag == VXB_INT_PCI_LEGACY_MSI)
+        vxbIntFree(pDev);
+
+
     intCtlrISRRemove(&(pDrvCtrl->isrHandle), inputPin, pIsr, pArg);

     /* the function is not yet implemented, returns ERROR */
@@ -560,12 +854,30 @@ LOCAL STATUS vxbxxxIntCtlrDevIsrEnable
     )
     {
     pVXB_LSN_HT_INT_DRV_CTRL pDrvCtrl = pIntCtlr->pDrvCtrl;
-    int                 inputPin = ERROR;
+    int inputPin = ERROR, inputPin2 = ERROR;
+    struct vxbIntDynaVecInfo dynaVec;
+    VXB_INTR_ENTRY * pIntInfo = pDev->pIntrInfo;

     inputPin = intCtlrPinFind(pDev, indx, pIntCtlr, &pDrvCtrl->isrHandle);
     if ( inputPin == -1 )
         return(ERROR);

+
+
+       /* only proces dynamic vector */
+
+       if ((inputPin >= LSN_DYN_VECTOR_START) &&
+               (inputPin <= LSN_DYN_VECTOR_END))
+               {
+               dynaVec.index = indx;
+               dynaVec.vecType = VXB_INT_TYPE(pIntInfo->intrFlag);
+
+               if (_func_vxbIntDynaVecEnable != NULL)
+                       {
+                       if (_func_vxbIntDynaVecEnable(pIntCtlr, pDev, &dynaVec) == ERROR)
+                               return ERROR;
+                       }
+               }
     /* call the routine to enable the ISR */

     intCtlrISREnable(&(pDrvCtrl->isrHandle), inputPin, pIsr, pArg);
@@ -601,11 +913,26 @@ LOCAL STATUS vxbxxxIntCtlrDevIsrDisable
     {
     pVXB_LSN_HT_INT_DRV_CTRL pDrvCtlr = pIntCtlr->pDrvCtrl;
     int                 inputPin = ERROR;
+    struct vxbIntDynaVecInfo dynaVec;
+    VXB_INTR_ENTRY *    pIntInfo = pDev->pIntrInfo;

     inputPin = intCtlrPinFind(pDev, indx, pIntCtlr, &pDrvCtlr->isrHandle);
     if ( inputPin == ERROR)
         return(ERROR);

+    if ((inputPin >= LSN_DYN_VECTOR_START) &&
+        (inputPin <= LSN_DYN_VECTOR_END))
+        {
+        dynaVec.index = indx;
+        dynaVec.vecType = VXB_INT_TYPE(pIntInfo->intrFlag);
+
+        if (_func_vxbIntDynaVecDisable != NULL)
+            {
+            if (_func_vxbIntDynaVecDisable(pIntCtlr, pDev, &dynaVec) == ERROR)
+               return ERROR;
+            }
+        }
+
     /* call the routine to disable the ISR */

     intCtlrISRDisable(&(pDrvCtlr->isrHandle), inputPin, pIsr, pArg);
+LOCAL BOOL vxbxxxMsgFreeChk
+    (
+    int resource
+    )
+    {
+    UINT32 resOffset = resource - LSN_DYN_VECTOR_START;
+
+    if ((resource < LSN_DYN_VECTOR_START) ||
+       (resource > LSN_DYN_VECTOR_END))
+        return FALSE;
+
+    if (xxxIntBitmap[resOffset/LSN_NUM_DYN_VECTORS] & (1 << (resOffset%32)))
+        return FALSE;
+    else
+        return TRUE;
+    }
+
+/*******************************************************************************
+*
+* vxbxxxMsgResourceGet - get free continuous vectors begin with startRes
+*
+* This function try to get number of continuous free vector.
+*
+* RETURNS: ERROR,  first vector
+*/
+
+LOCAL int vxbxxxMsgResourceGet
+    (
+    int reqcnt,
+    int startRes
+    )
+    {
+    int endRes;
+
+    endRes = startRes;
+
+    while (endRes < LSN_DYN_VECTOR_END)
+        {
+        while (!vxbxxxMsgFreeChk (startRes))
+           startRes += 1;
+
+        if (startRes > LSN_DYN_VECTOR_END)
+            return ERROR;
+
+        endRes = startRes;
+
+        while (vxbxxxMsgFreeChk (endRes))
+            {
+            endRes += 1;
+
+            if (endRes > (LSN_DYN_VECTOR_END + 1))
+                return ERROR;
+
+            if (reqcnt == (endRes - startRes))
+                return startRes;
+            }
+
+        if (reqcnt == (endRes - startRes))
+            return startRes;
+        else
+            startRes = endRes;
+       }
+
+    return ERROR;
+    }
+/*******************************************************************************
+*
+* vxbxxxMsgResBitMapSet - set dynamic vector bit map.
+*
+* This function set dynamic vector bitmap. 1 means this vecotr is used.
+*
+* RETURNS:N/A
+*/
+
+LOCAL void vxbxxxMsgResBitMapSet
+    (
+    UINT32 req,
+    UINT32 cnt
+    )
+    {
+    UINT32 resOffset = req - LSN_DYN_VECTOR_START;
+    int j;
+
+    for (j = 0; j < cnt; j++ )
+        xxxIntBitmap[resOffset / LSN_NUM_DYN_VECTORS] |=
+           (1 << ((resOffset + j ) % 32));
+    }
+
+/*******************************************************************************
+*
+* vxbxxxIntCtlrMsgVectorAlloc - get number of continuous free vectors
+*
+* This function try to get number of continuous free vectors.
+*
+* RETURNS: ERROR,  first vector
+*/
+
+LOCAL int vxbxxxIntCtlrMsgVectorAlloc
+    (
+    UINT32 vecCount
+    )
+    {
+    int firstReq;
+
+    if ((vecCount == 0) || (vecCount > LSN_NUM_DYN_VECTORS))
+        return ERROR;
+
+    firstReq = vxbxxxMsgResourceGet(vecCount, LSN_DYN_VECTOR_START);
+
+    if (firstReq == ERROR)
+        firstReq = LSN_DYN_VECTOR_START;
+
+    vxbxxxMsgResBitMapSet (firstReq, vecCount);
+
+    return firstReq;
+    }
+
+/*******************************************************************************
+*
+* vxbxxxIntCtlrMsgVectorFree - clear dynamic vector bit map set.
+*
+* This function clear dynamic vector bitmap.
+*
+* RETURNS:N/A
+*/
+
+LOCAL void vxbxxxIntCtlrMsgVectorFree
+    (
+    UINT32 startReq,
+    UINT32 count
+    )
+    {
+    UINT32 resOffset = startReq - LSN_DYN_VECTOR_START;
+    int j;
+
+    for (j = 0; j < count; j++ )
+        xxxIntBitmap[resOffset / LSN_NUM_DYN_VECTORS] &=
+           ~(1 << ((resOffset + j ) % 32));
+    }
+/*******************************************************************************
+*
+* vxbxxxIntCtlrDynaVecConnect - handle vxbIntConnect() request, dynamic vector
+*
+* This routine connects the specified ISR(s) to one or more dynamically
+* generated vector(s).
+*
+* RETURNS: OK/ERROR
+*
+* ERRNO
+*/
+
+LOCAL STATUS vxbxxxIntCtlrDynaVecConnect
+       (
+       VXB_DEVICE_ID                            intCtlr,
+       VXB_DEVICE_ID                            svcDev,
+       int                                              vecCount,
+       struct vxbIntDynaVecInfo *       dynaVec
+       )
+       {
+       int i;
+       STATUS ret;
+
+       if (vecCount == 1)
+               dynaVec->vecType = VXB_INT_PCI_LEGACY_MSI;
+
+       if (vxbIntAlloc (svcDev, dynaVec->vecType, vecCount) <= 0)
+               return ERROR;
+
+       if (dynaVec->vecType == VXB_INT_PCI_LEGACY_MSI)
+               {
+               UINT32 vec = (UINT32)(ULONG)(((VXB_INTR_ENTRY *)(svcDev->pIntrInfo))->intVecList[0]);
+               dynaVec->vecVal = VXB_LSN_MSI_DATA(vec);
+               dynaVec->vecAddr = VXB_LSN_MSI_ADDR(0);
+               dynaVec->inputPin = dynaVec->vecVal;
+               }
+
+       for (i = 0; i < vecCount; i++)
+               {
+               ret = vxbIntConnect (svcDev, 0, dynaVec->isr, dynaVec->pArg);
+               if (ret != OK)
+                       return ERROR;
+               dynaVec ++;
+               }
+       return OK;
+       }
+
+/*******************************************************************************
+*
+* vxbxxxIntCtlrMsiConnect - connect a MSI interrupt
+*
+* This routine connects the specified MSI ISR interrupt handler.
+*
+* RETURNS: OK/ERROR
+*
+* ERRNO
+*/
+
+LOCAL STATUS vxbxxxIntCtlrMsiConnect
+       (
+       VXB_DEVICE_ID           pIntCtlr,
+       VXB_DEVICE_ID           pDev,
+       UINT32                          resStart,
+       UINT32                          index,
+       void                            (*pIsr)(void * pArg),
+       void *                          pArg
+       )
+       {
+       pVXB_LSN_HT_INT_DRV_CTRL pDrvCtrl = pIntCtlr->pDrvCtrl;
+       STATUS            retVal;
+       void              (*pLocalIsr)(void * pArg);
+       void *            pLocalArg;
+       BOOL              flag;
+       int               inputPin = resStart;
+       struct intCtlrHwConf * isrHandle;
+
+       if (pDev->busID == VXB_BUSID_PCI)
+               {
+               /* update table with device info */
+
+               intCtlrTableUserSet(&pDrvCtrl->isrHandle, inputPin,
+                       (char*)pDev->pName, pDev->unitNumber, 0);
+
+               xxx_INT_INDEX_SET(&pDrvCtrl->isrHandle, inputPin, index);
+
+
+               (void)intCtlrISRAdd (&pDrvCtrl->isrHandle, inputPin, pIsr, pArg);
+
+               return (OK);
+               }
+       return ERROR;
+       }
+
+/*******************************************************************************
+*
+* vxbxxxIntCtlrAlloc - allocate number of MSI/MSI-X resource.
+*
+* Allocate number of MSI/MSI-X index from interrupt controller
+*
+* RETURNS: ERROR/OK
+*/
+
+LOCAL STATUS vxbxxxIntCtlrAlloc
+    (
+    VXB_DEVICE_ID    pDev,
+    UINT32           type,
+    UINT32           reqCount
+    )
+    {
+    VXB_INTR_ENTRY * pIntInfo;
+    int startIndex, i;
+    struct vxbIntDynaVecInfo dynaVec;
+
+    if ((pDev == NULL) || (reqCount == 0))
+        return ERROR;
+
+    if (_func_vxbIntDynaVecProgram == NULL)
+        return ERROR;
+
+    pIntInfo = pDev->pIntrInfo;
+
+    if (pDev->busID == VXB_BUSID_PLB)
+        {
+        /* TODO PLB MSI */
+        return (ERROR);
+        }
+
+    if (VXB_IS_MSI_INT(type)== FALSE)
+        return ERROR;
+
+    if ((VXB_IS_CONTINUOUS_MSI(type) == TRUE))
+        {
+        /* mulitple msi must continuous */
+
+        if((startIndex = vxbxxxIntCtlrMsgVectorAlloc (reqCount)) == ERROR)
+            return ERROR;
+
+        for (i = 0; i < reqCount; i++)
+            pIntInfo->intVecList[i] = (void *)(ULONG)(startIndex + i);
+
+        dynaVec.vecAddr = VXB_LSN_MSI_ADDR(0);
+        dynaVec.vecVal  = VXB_LSN_MSI_DATA(startIndex);
+        dynaVec.vecType = VXB_INT_TYPE(type);
+        dynaVec.index   = 0 ;
+        dynaVec.count   = reqCount | VXB_MULTIPLE_MSI_CNT_FLAG;
+
+        /* program the vector(s) into the device */
+
+        if ((*_func_vxbIntDynaVecProgram)(xxxDevID,
+            pDev, &dynaVec) != OK)
+            {
+            vxbxxxIntCtlrMsgVectorFree(startIndex, reqCount);
+            return(ERROR);
+            }
+
+        return  reqCount;
+        }
+    else
+        {
+        for (i = 0; i < reqCount; i++)
+            {
+            if((startIndex = vxbxxxIntCtlrMsgVectorAlloc (1))
+                 == ERROR)
+                 break;
+            pIntInfo->intVecList[i] = (void *)(ULONG)startIndex;
+
+            dynaVec.vecAddr = VXB_LSN_MSI_ADDR(0);
+            dynaVec.vecVal  = VXB_LSN_MSI_DATA(startIndex);
+            dynaVec.vecType = VXB_INT_TYPE(type);
+            dynaVec.index   = i;
+
+            /* program the vector into the device */
+
+            if ((*_func_vxbIntDynaVecProgram)(xxxDevID, pDev, &dynaVec) != OK)
+                {
+                vxbxxxIntCtlrMsgVectorFree(startIndex, 1);
+                return i;
+                }
+             }
+
+        return i;
+        }
+    }
+
+/*******************************************************************************
+*
+* vxbxxxIntCtlrFree - free device's MSI resource
+*
+* This routine free all MSI resource of the device.
+*
+* RETURNS: OK/ERROR
+*
+* ERRNO
+*/
+
+LOCAL STATUS vxbxxxIntCtlrFree
+    (
+    VXB_DEVICE_ID pDev
+    )
+    {
+    VXB_INTR_ENTRY * pIntInfo;
+    UINT32 i;
+    struct vxbIntDynaVecInfo dynaVec;
+
+    if (pDev == NULL)
+        return ERROR;
+
+    if (_func_vxbIntDynaVecErase == NULL)
+        return ERROR;
+
+    if (pDev->busID == VXB_BUSID_PLB)
+        {
+        /* TODO */
+        return (ERROR);
+        }
+
+    pIntInfo = pDev->pIntrInfo;
+
+    if (pIntInfo->numVectors == 0)
+        return ERROR;
+
+    if (pDev->busID == VXB_BUSID_PCI)
+        {
+        for (i = 0; i < pIntInfo->numVectors; i++)
+            {
+            vxbxxxIntCtlrMsgVectorFree ((UINT32)(ULONG)pIntInfo->intVecList[i],1);
+
+            dynaVec.index = i;
+            dynaVec.inputPin = (UINT32)(ULONG)pIntInfo->intVecList[i];
+            dynaVec.vecType = VXB_INT_TYPE(pIntInfo->intrFlag);
+
+            if ((*_func_vxbIntDynaVecErase)(xxxDevID, pDev, &dynaVec) != OK)
+                {
+                VXB_xxxINTR_DBG_MSG(1, "vxbxxxIntCtlrFree(): "
+                    "Failed to erase for %s%d\n",
+                    pDev->pName, pDev->unitNumber,3,4,5,6);
+                return(ERROR);
+                }
+            }
+        }
+
+    return ERROR;
+    }

主要是实现几个方法:

+    DEVMETHOD(vxbIntDynaVecConnect, vxbxxxIntCtlrDynaVecConnect),
+    DEVMETHOD(vxbIntCtlrAlloc, vxbxxxIntCtlrAlloc),
+    DEVMETHOD(vxbIntCtlrFree, vxbxxxIntCtlrFree),

修改几个方法,以支持MSI中断:

    DEVMETHOD(vxbIntCtlrConnect, vxbxxxIntCtlrDevIsrConnect),
    DEVMETHOD(vxbIntCtlrEnable, vxbxxxIntCtlrDevIsrEnable),
    DEVMETHOD(vxbIntCtlrDisconnect, vxbxxxIntCtlrDevIsrDisconnect),
    DEVMETHOD(vxbIntCtlrDisable, vxbxxxIntCtlrDevIsrDisable),

PCI MSI中断申请流程

首先vxworks在启动阶段会通过PCI总线控制器探测设备,完成设备的资源分配,如果采用MSI的方式,不会在探测时候分配中断号资源;中断控制器实例化时,会初始化一个bitmap,用来标记使用的中断,作为动态中断池;

调用流程:

g64120aPciInstInit->vxbPciBusTypeInit->pciBusAnnounceDevices->pciDeviceAnnounce->pciIntrInfoFind->vxbIntVectorGet:该函数会调用g64120aPciDevControl的VXB_ACCESS_INT_VEC_GET选项,检查PCI设备是否支持MSI,如果支持,将该intVector置为VXB_INTR_DYNAMIC,此时并没有分配中断号,而中断线方式此时已经分配过了中断号

PCI设备驱动调用vxbIntConnect时,会调用g64120aPciDevControl的VXB_ACCESS_INT_CONNECT选项,判断intVerctor为VXB_INTR_DYNAMIC时,会调用_func_vxbIntDynaConnect->vxbIntDynaConnect进而通过vxBus总线,查找到中断控制器的vxbIntDynaVecConnect方法,在这里对应为vxbxxxIntCtlrDynaVecConnect,进而调用vxbIntAlloc方法从bitmap中找到空闲bit进而对应中断号或者无空闲bit返回第一个中断号,并通过_func_vxbIntDynaVecProgram将中断号转化为Message Data,随Message Address一同写入PCI设备的MSI capabilities寄存器,后面通过vxbIntConnect将isr挂接到相应的中断向量结构体上

PCI设备驱动调用vxbIntEnable时,会查找到对应的中断控制器的vxbxxxIntCtlrDevIsrEnable,进而调用_func_vxbIntDynaVecEnable,通过g64120aPci的vxbIntDynaVecEnable方法,写PCI设备的MSI enable

NOTE:

  1. 需要添加内核组件VxBus Dynamic Interrupt Controller Library
  2. vx6.9的设备驱动一般使用vxbIntConnect,7.0以后的设备驱动直接调用vxbIntAlloc申请驱动

参考

  1. vxbQorIQPciEx.c
  2. vxbLoApicIntr.c
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值