📄 le1vefpgadma.c
字号:
/* le1veFpgaDma.c - LE1VE DMA(FPGA) controller libary file
*
* Copyright 2004-2007 ZTE, Inc.
* author: ZhengQishan
* date: 2004.03
*
* modification history
*------------------------------
*
*/
#include "le1veLib.h"
#include "le1veFpgaDma.h"
#include "Driver/drvLib/include/drv_comm.h"
#define DRV_DEBUG_ALL 0xFF
#define DRV_DEBUG_INT 0x01
#define DRV_DEBUG_RX 0x02
#define DRV_DEBUG_TX 0x04
int le1veDebugFlag = 0;
#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \
if (le1veDebugFlag & FLG) \
logMsg((char *)X0, (int)X1, (int)X2, (int)X3, (int)X4, \
(int)X5, (int)X6);
#if INSTALL_ON_IXP1200
#define LE1VE_BUFFER_CACHE_INVALIDATE(address, len) \
CACHE_DRV_INVALIDATE (&cacheUserFuncs, (address), (len))
#define LE1VE_BUFFER_CACHE_FLUSH(address, len) \
CACHE_DRV_FLUSH (&cacheUserFuncs, (address), (len))
#else
#define LE1VE_BUFFER_CACHE_INVALIDATE(address, len)
#define LE1VE_BUFFER_CACHE_FLUSH(address, len)
#endif
extern struct net* if_search(GLOBAL_PORT gport);
LOCAL void cleanRmd(LE1VE_PCI_DRV_CTRL *pDrv);
LOCAL void cleanTmd(LE1VE_PCI_DRV_CTRL *pDrv);
LOCAL void le1veFpgaPciDevModInit(void);
LOCAL void le1veFpgaPciDevInt(LE1VE_PCI_DRV_CTRL *pDrv);
LOCAL STATUS le1veMemInit(LE1VE_PCI_DRV_CTRL *pDrv);
LOCAL STATUS le1veMemConfig(LE1VE_PCI_DRV_CTRL *pDrv);
LOCAL LE1VE_RMD * le1veReadyRMDGet (LE1VE_PCI_DRV_CTRL * pDrv);
void le1veFpgaPciDevRec(LE1VE_PCI_DRV_CTRL *pDrv);
void le1ve_miiCtrlCrcCfg(LE1VE_PCI_DRV_CTRL *pDrv, int mode);
void le1ve_miiCtrlLoopBackCfg(LE1VE_PCI_DRV_CTRL *pDrv, int mode);
void le1ve_miiCtrlRxCfg(LE1VE_PCI_DRV_CTRL *pDrv, int mode);
void le1ve_miiCtrlTxCfg(LE1VE_PCI_DRV_CTRL *pDrv, int mode);
void le1ve_miiCtrlReset(LE1VE_PCI_DRV_CTRL *pDrv);
void le1ve_miiCtrlPreamCfg(LE1VE_PCI_DRV_CTRL *pDrv, int mode);
void le1ve_miiCtrlFullDuplexCfg(LE1VE_PCI_DRV_CTRL *pDrv, int mode);
/*LE1E设备指针与槽位号一一对应,中间不用转换*/
LE1VE_PCI_DRV_CTRL *gpLe1veDrvCtrl[LE1VE_PCI_MAX_NUM] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
/*-----------------------------
*le1veFpgaPciDevInit - 初始化LE1VE的PCI设备
*
*Argument: int slot - 槽位号
*
*Return:OK or ERROR if something is wrong
*/
STATUS le1veFpgaPciDevInit(int slot)
{
LE1VE_PCI_DRV_CTRL *pDrv;
STATUS result = OK;
static STATUS firstTime = OK;
UINT32 baseAddr;
if (firstTime == OK)
{
/*读取所有LE1VE PCI设备,并为每一个设备申请一个数据结构*/
le1veFpgaPciDevModInit();
firstTime = ERROR;
}
if (slot <= 0 || slot > LE1VE_PCI_MAX_NUM)
{
printf("le1veFpgaPciDevInit: slot Number Error!\n");
return ERROR;
}
if (NULL == (pDrv = gpLe1veDrvCtrl[slot - 1]))
{
printf("No LE1VE FPGA PCI device!\n");
return ERROR;
}
/*Init memory*/
if (OK != le1veMemInit (pDrv))
{
printf("Memory init failed!\n");
return ERROR;
}
le1veMemConfig(pDrv);
/*connect and enable PCI interrupt*/
b_pciUnitIntConnect((UINT8)pDrv->slotNo, (VOIDFUNCPTR)le1veFpgaPciDevInt, (int)pDrv);
b_pciUnitIntEnable((UINT8)pDrv->slotNo);
/*Enable all PCI int*/
pDrv->pMem->pciIntMask = Drv_Swap32(~LE1VE_INT_ALL_MASK);
/*setup to little endian*/
baseAddr = IF_CARD_CPU_REG_BASE(pDrv->slotNo);
*((UINT32 *)(baseAddr + LE1VE_PCI_CONTROL_REG)) &= Drv_Swap32(~LE1VE_BIG_ENDIAN);
#if 1
le1ve_miiCtrlTxCfg(pDrv, LE1VE_CTRL_TX_ENABLE);
le1ve_miiCtrlRxCfg(pDrv, LE1VE_CTRL_RX_ENABLE);
#else
le1ve_miiCtrlLoopBackCfg(pDrv, LE1VE_CTRL_LOOP_BACK);
#endif
le1ve_miiCtrlCrcCfg(pDrv, LE1VE_CTRL_CRC_ENABLE);
return(result);
}
/*-----------------------------
*le1veFpgaPciDevInt - LE1VE的PCI设备中断处理函数
*
*Argument: LE1VE_PCI_DRV_CTRL *pDrv - pointer to the LE1VE PCI Device
*
*Return:void
*/
LOCAL void le1veFpgaPciDevInt(LE1VE_PCI_DRV_CTRL *pDrv)
{
UINT32 intStatus;
/*read PCI int state*/
intStatus = pDrv->pMem->pciIntState;
intStatus = Drv_Swap32(intStatus);
DRV_LOG(DRV_DEBUG_INT, "isr: int state = 0x%x!\n", intStatus, 2, 3, 4, 5, 6);
pDrv->le1vePciInt ++;
if (0!= (intStatus & LE1VE_RX_PKT_INT))
{
pDrv->le1veRxInt++;
if (pDrv->rxFlag != RX_PKT_JOB_ADDED)
{
if(fwdJobAdd ((FUNCPTR)le1veFpgaPciDevRec, (int)pDrv,0,0,0,0)==OK)
{
/*disable Rx int*/
pDrv->pMem->pciIntMask &= Drv_Swap32(~LE1VE_RX_PKT_INT);
pDrv->rxFlag = RX_PKT_JOB_ADDED;
}
else
{
pDrv->le1veErrorAddJob++;
}
}
}
/*接收BD表满,处理流程与收包中断相似,如果把它与接收中断放到一起处理会多一次判断,为了
提高性能,所以将它们分开处理*/
if (0!= (intStatus & LE1VE_RX_BD_FULL_INT))
{
pDrv->pMem->pciIntMask &= Drv_Swap32(~LE1VE_RX_BD_FULL_INT);
pDrv->le1vePciFpgaMode = LE1VE_RX_BD_FULL;
pDrv->le1vePciRxFullInt++;
if (pDrv->rxFlag != RX_PKT_JOB_ADDED)
{
if(fwdJobAdd ((FUNCPTR)le1veFpgaPciDevRec, (int)pDrv,0,0,0,0)==OK)
{
/*disable Rx int*/
pDrv->pMem->pciIntMask &= Drv_Swap32(~LE1VE_RX_BD_FULL_INT);
pDrv->rxFlag = RX_PKT_JOB_ADDED;
}
else
{
pDrv->le1veErrorAddJob++;
}
}
}
if(intStatus & LE1VE_TX_BD_OPT_ERR_INT)
{
pDrv->le1vePciTxEmptyInt++;
}
if(intStatus & LE1VE_TX_TRANS_ERR_INT)
pDrv->le1vePciTxMemErr++;
if(intStatus & LE1VE_RX_TRANS_ERR_INT)
pDrv->le1vePciRxMemErr++;
}
/*-----------------------------
*le1vePktRcv - LE1VE的PCI设备收包处理函数
*
*Argument:
* LE1VE_PCI_DRV_CTRL * pDrv - pointer to the PCI device
* LE1VE_RMD * pRmd - pointer to the Rx BD description
*
*Return:OK or ERROR if something is wrong
*/
STATUS le1vePktRcv(
LE1VE_PCI_DRV_CTRL * pDrv, /* device to be initialized */
LE1VE_RMD * pRmd )
{
int len;
int oldLevel;
char *pBuf;
char *pNewBuf;
void *pNet = NULL;
void *pkt;
UINT32 rmd0Tmp;
UINT32 gPort;
/* 检查接收的包有无错误 */
rmd0Tmp = Drv_Swap32 (pRmd->RMD0);
DRV_LOG(DRV_DEBUG_RX, "le1vePktRcv : rmd1 = %X index = %d\n", rmd0Tmp,
pDrv->rmdIndex, 3, 4, 5, 6);
/* If error flag OR if packet is not completely in one buffer */
if (rmd0Tmp & RMD0_ERR)
{
DRV_LOG(DRV_DEBUG_RX, "le1vePktRcv: RMD error!\n", 1, 2, 3, 4, 5, 6);
pDrv->le1vePciRxErrorPkt++;
goto cleanLe1veRXD;
}
len = rmd0Tmp & RMD0_PKT_LEN;
/*判断有没有收到包长为0*/
if (len == 0)
{
DRV_LOG(DRV_DEBUG_RX, "le1vePktRcv: recieve a length = 0 packer\n",1,2,3,4,5,6);
goto cleanLe1veRXD;
}
/*Alloc a new buffer for RX BD*/
pNewBuf = (char*)endPktAlloc();
if (pNewBuf == NULL)
{
DRV_LOG(DRV_DEBUG_RX, "le1vePktRcv: Cannot loan!\n", 1, 2, 3, 4, 5, 6);
pDrv->le1veErrorAlloc++;
goto cleanLe1veRXD;
}
pBuf = (char *)Drv_Swap32(mapPhysToVirt((UINT32)pRmd->RMD1));
/* Give receiver a new buffer */
pRmd->RMD1 = Drv_Swap32(mapVirtToPhys((UINT32)pNewBuf));
gPort = Ros_GlobalPort(pDrv->slotNo, 5, 0);
if (pDrv->pNet != NULL)
pNet = pDrv->pNet;
else
{
if (NULL != (pNet = (void *)if_search(gPort)))
pDrv->pNet = pNet;
}
pDrv->le1vepciRx ++;
drv_DebugRcvSndPkt(gPort, (char *)pBuf, len, RX_DIRECTION);
#if 0 /*only for debug*/
endPktFree(pBuf);
#else
if (pNet == NULL)
endPktFree(pBuf);
else
{
END_BUF_GET_PKT(pBuf, pkt);
etherPktProcess(pkt, pBuf, pNet, len);
}
#endif
cleanLe1veRXD:
LE1VE_CLEAN_RXD(pRmd);
oldLevel = intLock();
/* Advance our management index */
pDrv->rmdIndex = (pDrv->rmdIndex + 1) & (pDrv->rringSize - 1);
intUnlock(oldLevel);
return (OK);
}
/*-----------------------------
* le1veFpgaPciDevRec - LE1VE的PCI设备中断收包处理函数
*
* 说明:将中断收包转换为任务进行处理,读取接收BD表,处理已经接收完成的
* 数据包
*
* Argument:
* LE1VE_PCI_DRV_CTRL * pDrv - pointer to the PCI device
*
*
* Return:
* void
*/
void le1veFpgaPciDevRec(LE1VE_PCI_DRV_CTRL *pDrv)
{
int rxCnt = 0;
LE1VE_RMD *pRmd;
while (NULL != (pRmd = le1veReadyRMDGet(pDrv)))
{
le1vePktRcv(pDrv, pRmd);
rxCnt ++;
if (rxCnt >= DEV_LE1VE_PCI_QLEN)
{
if(fwdJobAdd ((FUNCPTR)le1veFpgaPciDevRec, (int)pDrv,0,0,0,0)==OK)
{
return;
}
else
{
pDrv->le1veErrorAddJob++;
}
}
}
pDrv->rxFlag &= ~RX_PKT_JOB_ADDED;
/*enable Recieve interrupt*/
pDrv->pMem->pciIntMask |= Drv_Swap32(LE1VE_RX_PKT_INT);
/*如果上行BD表满,FPGA处于阻塞状态,则取走一个包后重新启动FPGA上行*/
if (pDrv->le1vePciFpgaMode == LE1VE_RX_BD_FULL)
{
pDrv->le1vePciFpgaMode &= (~LE1VE_RX_BD_FULL);
pDrv->pMem->rxEnable |= Drv_Swap32(LE1VE_RX_PKT_ENABLE);
pDrv->pMem->pciIntMask |= Drv_Swap32(LE1VE_RX_BD_FULL_INT);
}
}
/*-----------------------------
* le1veFpgaPciDevSend - LE1VE的PCI设备发包处理函数
*
* Argument:
* UINT32 gPort - global port number
* char *pBuf - pointer to the send data buffer header
* int size - the size of send data
* char *pData - pointer to the manage buffer
*
* Return:
* OK or ERROR if something is wrong
*/
STATUS le1veFpgaPciDevSend(UINT32 gPort, char *pBuf, int size, char *pData)
{
int slot, oldLevel;
int nextIndex;
UINT32 tmd0;
void **pParm;
LE1VE_TMD *pTmd;
LE1VE_TMD *pTmdFree;
LE1VE_PCI_DRV_CTRL *pDrv;
slot = LE1VE_SLOT_NUM(gPort);
pDrv = gpLe1veDrvCtrl[slot - 1];
if ((slot < 1) || (slot > LE1VE_PCI_MAX_NUM) ||
(pDrv == NULL) || (pBuf == NULL) ||
(size > LE1VE_MTU) || (size <= 0))
{
DRV_LOG(DRV_DEBUG_TX, "%s: Error argument!!\n", __FUNCTION__, 2, 3, 4, 5, 6);
return ERROR;
}
semTake(pDrv->TxSemaphore, WAIT_FOREVER);
nextIndex = (pDrv->tmdIndex + 1) & (pDrv->tringSize - 1);
pTmd = pDrv->pTring + pDrv->tmdIndex;
tmd0= Drv_Swap32(pTmd->TMD0);
LE1VE_BUFFER_CACHE_FLUSH ((pBuf), (size));
/*队列已经满,要求释放BD表项*/
if(nextIndex == pDrv->tmdIndexC)
{
pTmdFree = pDrv->pTring + nextIndex;
if (!(Drv_Swap32 (pTmdFree->TMD0) & TMD0_OWN))
{
pParm = &(pDrv->freeData [nextIndex].arg2);
if (*pParm != NULL)
{
endPktFree(*pParm);
*pParm = NULL;
DRV_LOG(DRV_DEBUG_TX, "%s:Free a memory space!!\n", __FUNCTION__, 2, 3, 4, 5, 6);
}
pDrv->tmdIndexC = (pDrv->tmdIndexC + 1) & (pDrv->tringSize - 1);
LE1VE_TMD_CLR_ERR (pTmdFree);
}
else
{
semGive (pDrv->TxSemaphore);
pDrv->le1vePciTxNoTmd++;
DRV_LOG(DRV_DEBUG_TX, "%s:no Tmd!!\n", __FUNCTION__, 2, 3, 4, 5, 6);
return (ERROR);
}
}
pTmd->TMD1 = Drv_Swap32(mapVirtToPhys((UINT32)pBuf));
tmd0 = size;
tmd0 |= TMD0_OWN;
/* write to actual register */
pTmd->TMD0 = Drv_Swap32 (tmd0);
oldLevel=intLock();
pDrv->freeData [pDrv->tmdIndex].arg2 = pData;
/* Advance our management index */
pDrv->tmdIndex = nextIndex;
intUnlock(oldLevel);
pDrv->le1vepciTx++;
drv_DebugRcvSndPkt(gPort, (char *)pBuf, size, TX_DIRECTION);
/*enabe transmit*/
pDrv->pMem->txEnable = Drv_Swap32(LE1VE_TX_PKT_ENABLE);
/*释放信号量*/
semGive (pDrv->TxSemaphore);
return (OK);
}
STATUS readFpgaDmaStatis(int slot, LE1VE_FPGA_CNT_CTRL_MODE mode, LE1VE_FPGA_DMA_STATIS *pCnt)
{
volatile char *baseAddr;
CHECK_CNT_CTRL_MODE(mode);
baseAddr = (volatile char *)(IF_CARD_CPU_REG_BASE(slot));
pCnt->MiiRxCnt = READ_CNT_REG(baseAddr + LE1VE_MII_RX_CNT_REG);
pCnt->MiiRxErrCnt = READ_CNT_REG(baseAddr + LE1VE_MII_RX_ERR_CNT_REG);
pCnt->MiiTxCnt = READ_CNT_REG(baseAddr + LE1VE_MII_TX_CNT_REG);
pCnt->MiiTxErrCnt = READ_CNT_REG(baseAddr + LE1VE_MII_TX_ERR_CNT_REG);
pCnt->PciRxCnt = READ_CNT_REG(baseAddr + LE1VE_PCI_RX_CNT_REG);
pCnt->PciRxErrCnt = READ_CNT_REG(baseAddr + LE1VE_PCI_RX_ERR_CNT_REG);
pCnt->PciTxCnt = READ_CNT_REG(baseAddr + LE1VE_PCI_TX_CNT_REG);
pCnt->PciTxErrCnt = READ_CNT_REG(baseAddr + LE1VE_PCI_TX_ERR_CNT_REG);
*(baseAddr + LE1VE_COUNT_CONTROL_REG) |= Drv_Swap32(mode);
*(baseAddr + LE1VE_COUNT_CONTROL_REG) &= Drv_Swap32(~CLEAR_TO_ZERO);
return(OK);
}
/*-----------------------------
*
* le1veReadyRMDGet - get next received message RMD
*
* Returns ptr to next Rx desc to process, or NULL if none ready.
*/
LOCAL LE1VE_RMD * le1veReadyRMDGet (LE1VE_PCI_DRV_CTRL * pDrv)
{
LE1VE_RMD *pRmd;
pRmd = pDrv->pRring + pDrv->rmdIndex; /* form ptr to Rx desc */
/* If receive buffer has been released to us, return it */
if ((Drv_Swap32 (pRmd->RMD0) & RMD0_OWN) != 0)/*OWN位为1,返回该描述符,否则NULL*/
return (pRmd);
else
return ((LE1VE_RMD *) NULL);
}
/*------------------------------
* le1veMemInit - initialize memory
*
* Using data in the control structure, setup and initialize the memory
* areas needed. allocate cache safe memory.
*
* Argument: LE1VE_PCI_DRV_CTRL *pDrv - pointer to the LE1VE PCI Device
*
* 此处只分配内存 并填充pDrv结构中的与描述符相关内容,
* 并不初始化描述符,初始化描述符在le1veMemConfig中进行
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS le1veMemInit(LE1VE_PCI_DRV_CTRL *pDrv)
{
char *pBuf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -