📄 ln97xend.c
字号:
/***** Establish a region of shared memory *****/
/* OK. We now know how much shared memory we need. If the caller
* provides a specific memory region, we check to see if the provided
* region is large enough for our needs. If the caller did not
* provide a specific region, then we attempt to allocate the memory
* from the system, using the cache aware allocation system call.
*/
switch ((int) pDrvCtrl->memAdrs)
{
default : /* caller provided memory */
if (pDrvCtrl->memSize < sz) /* not enough space */
{
DRV_LOG (DRV_DEBUG_LOAD, "ln97x: not enough memory provided\n"
"ln97x: need %ul got %d\n",
sz, pDrvCtrl->memSize, 3, 4, 5, 6);
return (NULL);
}
/* set the beginning of pool */
pDrvCtrl->pShMem = pDrvCtrl->memAdrs;
/* assume pool is cache coherent, copy null structure */
pDrvCtrl->cacheFuncs = cacheNullFuncs;
DRV_LOG (DRV_DEBUG_LOAD, "Memory checks out\n", 1, 2, 3, 4, 5, 6);
break;
case NONE : /* get our own memory */
/* Because the structures that are shared between the device
* and the driver may share cache lines, the possibility exists
* that the driver could flush a cache line for a structure and
* wipe out an asynchronous change by the device to a neighboring
* structure. Therefore, this driver cannot operate with memory
* that is not write coherent. We check for the availability of
* such memory here, and abort if the system did not give us what
* we need.
*/
if (!CACHE_DMA_IS_WRITE_COHERENT ())
{
printf ( "ln97x: device requires cache coherent memory\n" );
return (ERROR);
}
pDrvCtrl->pShMem = (char *) cacheDmaMalloc (sz);
if ((int)pDrvCtrl->pShMem == NULL)
{
printf ( "ln97x: system memory unavailable\n" );
return (ERROR);
}
/* copy the DMA structure */
pDrvCtrl->cacheFuncs = cacheDmaFuncs;
break;
}
/* Turkey Carving
* --------------
*
* LOW MEMORY
*
* |-------------------------------------|
* | The initialization block |
* | (sizeof (LN_IB)) |
* |-------------------------------------|
* | The Rx descriptors |
* | (1 << lnRsize) * sizeof (LN_RMD)|
* |-------------------------------------|
* | The Tx descriptors |
* | (1 << lnTsize) * sizeof (LN_TMD)|
* |-------------------------------------|
*/
/* Save some things */
pDrvCtrl->memBase = (char *)((UINT32)pDrvCtrl->pShMem & 0xff000000);
if ((int) pDrvCtrl->memAdrs == NONE)
pDrvCtrl->flags |= LS_MEM_ALLOC_FLAG;
/* first let's clear memory */
bzero ( (char *) pDrvCtrl->pShMem, (int) sz );
/* setup Rx memory pointers */
pDrvCtrl->pRring = (LN_RMD *) ((int)pDrvCtrl->pShMem + IB_SIZ);
pDrvCtrl->rringLen = lnRsize;
pDrvCtrl->rringSize = 1 << lnRsize;
pDrvCtrl->rmdIndex = 0;
/* setup Tx memory pointers. */
/* Note: +2 is to round up to alignment. */
pDrvCtrl->pTring = (LN_TMD *) (int)(pDrvCtrl->pShMem + IB_SIZ +
((1 << lnRsize) + 1) * RMD_SIZ + 0xf);
pDrvCtrl->pTring = (LN_TMD *) (((int)pDrvCtrl->pTring + 0xf) & ~0xf);
pDrvCtrl->tringSize = 1 << lnTsize;
pDrvCtrl->tringLen = lnTsize;
pDrvCtrl->tmdIndex = 0;
pDrvCtrl->tmdIndexC = 0;
/* Set up the structures to allow us to free data after sending it. */
for (ix = 0; ix < pDrvCtrl->rringSize; ix++)
{
pDrvCtrl->freeRtn[ix] = NULL;
pDrvCtrl->freeData[ix].arg1 = NULL;
pDrvCtrl->freeData[ix].arg2 = NULL;
}
/* allocate pool structure for mblks, clBlk, and clusters */
if ((pDrvCtrl->endObj.pNetPool = malloc (sizeof(NET_POOL))) == NULL)
return (ERROR);
#ifdef DRV_DEBUG
pLan97xNetPool = pDrvCtrl->endObj.pNetPool;
#endif
pDrvCtrl->clDesc.clNum = pDrvCtrl->rringSize * 2;
pDrvCtrl->mClCfg.clBlkNum = pDrvCtrl->clDesc.clNum;
pDrvCtrl->mClCfg.mBlkNum = pDrvCtrl->mClCfg.clBlkNum * 2;
/* total memory size for mBlks and clBlks */
pDrvCtrl->mClCfg.memSize =
(pDrvCtrl->mClCfg.mBlkNum * (MSIZE + sizeof (long))) +
(pDrvCtrl->mClCfg.clBlkNum * (CL_BLK_SZ + sizeof (long)));
/* total memory for mBlks and clBlks */
if ((pDrvCtrl->mClCfg.memArea =
(char *) memalign (sizeof(long), pDrvCtrl->mClCfg.memSize)) == NULL)
return (ERROR);
/* total memory size for all clusters */
pDrvCtrl->clDesc.clSize = LN_BUFSIZ;
pDrvCtrl->clDesc.memSize =
(pDrvCtrl->clDesc.clNum * (pDrvCtrl->clDesc.clSize + 8)) + sizeof(int);
/* Do we hand over our own memory? */
if (pDrvCtrl->memAdrs != (char *)NONE)
{
pDrvCtrl->clDesc.memArea =
(char *)(pDrvCtrl->pTring + pDrvCtrl->tringSize);
}
else
{
pDrvCtrl->clDesc.memArea = cacheDmaMalloc (pDrvCtrl->clDesc.memSize);
if ((int)pDrvCtrl->clDesc.memArea == NULL)
{
DRV_LOG(DRV_DEBUG_LOAD,
"system memory unavailable\n", 1, 2, 3, 4, 5, 6);
return (ERROR);
}
}
/* initialize the device net pool */
if (netPoolInit (pDrvCtrl->endObj.pNetPool, &pDrvCtrl->mClCfg,
&pDrvCtrl->clDesc, 1, NULL) == ERROR)
{
DRV_LOG (DRV_DEBUG_LOAD, "Could not init buffering\n",
1, 2, 3, 4, 5, 6);
return (ERROR);
}
/* Store the cluster pool id as others need it later. */
pDrvCtrl->pClPoolId = clPoolIdGet (pDrvCtrl->endObj.pNetPool,
LN_BUFSIZ, FALSE);
/* Longword align rmd ring */
pDrvCtrl->pRring = (LN_RMD *) (((int)pDrvCtrl->pRring + 0xf) & ~0xf);
pDrvCtrl->pRring = (LN_RMD *) (((int)pDrvCtrl->pRring + 0xf) & ~0xf);
pRmd = pDrvCtrl->pRring;
DRV_LOG (DRV_DEBUG_LOAD, "Using %d RX buffers from 0x%X\n",
pDrvCtrl->rringSize, (int)pRmd, 3, 4, 5, 6);
for (ix = 0; ix < pDrvCtrl->rringSize; ix++, pRmd++)
{
if ((pTempBuf = (char *)netClusterGet (pDrvCtrl->endObj.pNetPool,
pDrvCtrl->pClPoolId)) == NULL)
{
DRV_LOG (DRV_DEBUG_LOAD, "Could not get a buffer\n",
1, 2, 3, 4, 5, 6);
return (ERROR);
}
pTempBuf += pDrvCtrl->offset;
LN_RMD_BUF_TO_ADDR (pRmd, pTemp, pTempBuf);
}
return OK;
}
/*******************************************************************************
*
* ln97xStart - start the device
*
* This function calls BSP functions to connect interrupts and start the
* device running in interrupt mode.
*
* RETURNS: OK or ERROR
*/
LOCAL STATUS ln97xStart
(
LN_97X_DRV_CTRL * pDrvCtrl /* device to be initialized */
)
{
int tValue;
tValue = pDrvCtrl->ilevel;
if(tValue == 0)
tValue = pDrvCtrl->ivec;
pDrvCtrl->txCleaning = FALSE;
pDrvCtrl->txBlocked = FALSE;
(void) intConnect (INUM_TO_IVEC ((int)tValue), ln97xInt, (int)pDrvCtrl);
/* SYS_INT_CONNECT (pDrvCtrl, ln97xInt, (int)pDrvCtrl, &result); */
/*if (result == ERROR)
return ERROR;*/
DRV_LOG (DRV_DEBUG_LOAD, "Interrupt connected.\n", 1, 2, 3, 4, 5, 6);
SYS_INT_ENABLE ();
DRV_LOG (DRV_DEBUG_LOAD, "interrupt enabled.\n", 1, 2, 3, 4, 5, 6);
return (OK);
}
/*******************************************************************************
*
* ln97xInt - handle controller interrupt
*
* This routine is called at interrupt level in response to an interrupt from
* the controller.
*/
LOCAL void ln97xInt
(
LN_97X_DRV_CTRL * pDrvCtrl /* device to be initialized */
)
{
UINT32 stat;
/* Read the device status register */
stat = ln97xCsrRead (pDrvCtrl, 0);
DRV_LOG (DRV_DEBUG_INT, "i=0x%x:\n", stat, 2, 3, 4, 5, 6);
/* If false interrupt, return. */
if (! (stat & CSR0_INTR))
{
DRV_LOG (DRV_DEBUG_INT, "False interrupt.\n", 1, 2, 3, 4, 5, 6);
return;
}
/*
* enable interrupts, clear receive and/or transmit interrupts, and clear
* any errors that may be set.
* Writing back what was read clears all interrupts
*/
ln97xCsrWrite (pDrvCtrl, 0, stat);
/* Check for errors */
if (stat & (CSR0_BABL | CSR0_MISS | CSR0_MERR))
{
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
if (stat & CSR0_BABL)
{
pDrvCtrl->lastError.errCode = END_ERR_WARN;
pDrvCtrl->lastError.pMesg = "Babbling";
netJobAdd ((FUNCPTR) muxError, (int) &pDrvCtrl->endObj,
(int) &pDrvCtrl->lastError,
0, 0, 0);
DRV_LOG (DRV_DEBUG_INT, "Babbling\n", 1, 2, 3, 4, 5, 6);
}
if (stat & CSR0_MISS)
{
pDrvCtrl->lastError.errCode = END_ERR_WARN;
pDrvCtrl->lastError.pMesg = "Missing";
netJobAdd ((FUNCPTR) muxError, (int) &pDrvCtrl->endObj,
(int) &pDrvCtrl->lastError,
0, 0, 0);
DRV_LOG (DRV_DEBUG_INT, "Missing\n", 1, 2, 3, 4, 5, 6);
}
/* restart chip on fatal error */
if (stat & CSR0_MERR) /* memory error */
{
pDrvCtrl->lastError.errCode = END_ERR_RESET;
pDrvCtrl->lastError.pMesg = "Memory error.";
netJobAdd ((FUNCPTR)muxError, (int) &pDrvCtrl->endObj,
(int)&pDrvCtrl->lastError,
0, 0, 0);
DRV_LOG (DRV_DEBUG_INT, "Memory error, restarting.\n",
1, 2, 3, 4, 5, 6);
END_FLAGS_CLR (&pDrvCtrl->endObj, (IFF_UP | IFF_RUNNING));
ln97xRestart (pDrvCtrl);
return;
}
}
/* Have netTask handle any input packets */
if ((stat & CSR0_RINT) && (stat & CSR0_RXON))
{
if (!(pDrvCtrl->flags & LS_RCV_HANDLING_FLAG))
{
pDrvCtrl->flags |= LS_RCV_HANDLING_FLAG;
(void) netJobAdd ((FUNCPTR)ln97xHandleRecvInt, (int)pDrvCtrl,
0,0,0,0);
}
}
/*
* Did LANCE update any of the TMD's?
* If not then don't bother continuing with transmitter stuff
*/
if (!(stat & CSR0_TINT))
return;
DRV_LOG (DRV_DEBUG_INT, "t ", 1, 2, 3, 4, 5, 6);
if (!pDrvCtrl->txCleaning)
{
pDrvCtrl->txCleaning = TRUE;
netJobAdd ((FUNCPTR)ln97xTRingScrub, (int) pDrvCtrl, 0, 0, 0, 0);
}
if (pDrvCtrl->txBlocked) /* cause a restart */
{
pDrvCtrl->txBlocked = FALSE;
netJobAdd ((FUNCPTR)muxTxRestart, (int) &pDrvCtrl->endObj, 0, 0, 0, 0);
}
/* Flush the write pipe */
CACHE_PIPE_FLUSH ();
return;
}
/*******************************************************************************
*
* ln97xHandleRecvInt - task level interrupt service for input packets
*
* This routine is called at task level indirectly by the interrupt
* service routine to do any message received processing.
*/
LOCAL void ln97xHandleRecvInt
(
LN_97X_DRV_CTRL * pDrvCtrl /* device to be initialized */
)
{
LN_RMD * pRmd = (LN_RMD *)NULL;
do
{
pDrvCtrl->flags |= LS_RCV_HANDLING_FLAG;
while ((pRmd = ln97xFullRMDGet (pDrvCtrl)) != (LN_RMD *)NULL)
{
LN_CACHE_INVALIDATE (pRmd, RMD_SIZ);
ln97xRecv (pDrvCtrl, pRmd);
};
/*
* There is a RACE right here. The ISR could add a receive packet
* and check the boolean below, and decide to exit. Thus the
* packet could be dropped if we don't double check before we
* return.
*/
pDrvCtrl->flags &= ~LS_RCV_HANDLING_FLAG;
}
while (ln97xFullRMDGet (pDrvCtrl) != NULL);
/* this double check solves the RACE */
}
/*******************************************************************************
*
* ln97xFullRMDGet - get next received message RMD
*
* Returns ptr to next Rx desc to process, or NULL if none ready.
*/
LOCAL LN_RMD * ln97xFullRMDGet
(
LN_97X_DRV_CTRL * pDrvCtrl /* device to be initialized */
)
{
LN_RMD * pRmd;
pRmd = pDrvCtrl->pRring + pDrvCtrl->rmdIndex; /* form ptr to Rx desc */
/* If receive buffer has been released to us, return it */
if ((PCI_SWAP (pRmd->rBufRmd1) & RMD1_OWN) == 0)
return (pRmd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -