本文仅讨论在vxworks6.9下I对支持MSI的支持,vxworks7.0对MSI的支持方式有变化,不在本文涉及范围内
开发环境
vxworks6.9
vscode
修改的文件
- g64120aPci.c 所使用的PCI总线控制器
- hwconf.c
- vxbxxxIntCtlr.c 所使用的中断控制器
PCI设备
PCI配置空间寄存器
PCI设备的三种中断方式:
- 中断线方式,根据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寄存器
- 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
- 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:
- 需要添加内核组件VxBus Dynamic Interrupt Controller Library
- vx6.9的设备驱动一般使用vxbIntConnect,7.0以后的设备驱动直接调用vxbIntAlloc申请驱动
参考
- vxbQorIQPciEx.c
- vxbLoApicIntr.c





1784

被折叠的 条评论
为什么被折叠?



