📄 ln97xend.c
字号:
) { LN_RMD * pRmd = (LN_RMD *)NULL; do { pDrvCtrl->flags |= LS_RCV_HANDLING_FLAG; while ((pRmd = ln97xFullRMDGet (pDrvCtrl)) != (LN_RMD *)NULL) { 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 */ LN_CACHE_INVALIDATE (pRmd, RMD_SIZ); /* If receive buffer has been released to us, return it */ if (LN_RMD_OWNED (pRmd) == 0) return (pRmd); else return ((LN_RMD *) NULL); }/********************************************************************************* ln97xRecv - process the next incoming packet** RETURNS: OK/ERROR*/LOCAL STATUS ln97xRecv ( LN_97X_DRV_CTRL * pDrvCtrl, /* device to be initialized */ LN_RMD * pRmd ) { int len; M_BLK_ID pMblk; char * pCluster; char * pNewCluster; char * pTemp; CL_BLK_ID pClBlk; UINT32 rmd1Tmp; /* Packet must be checked for errors, Read rmd1 once only */ rmd1Tmp = PCI_SWAP (pRmd->rBufRmd1); DRV_LOG (DRV_DEBUG_TX, "Recv : rmd1 = %X index = %d\n", rmd1Tmp, pDrvCtrl->rmdIndex, 3, 4, 5, 6); /* If error flag OR if packet is not completely in one buffer */ if ((rmd1Tmp & RMD1_ERR) || (rmd1Tmp & (RMD1_STP | RMD1_ENP)) != (RMD1_STP | RMD1_ENP)) { DRV_LOG (DRV_DEBUG_RX, "RMD error!\n", 1, 2, 3, 4, 5, 6); END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1); goto cleanRXD; /* skip to clean up */ } /* If we cannot get a buffer to loan then bail out. */ pNewCluster = netClusterGet (pDrvCtrl->endObj.pNetPool, pDrvCtrl->pClPoolId); if (pNewCluster == NULL) { DRV_LOG (DRV_DEBUG_RX, "Cannot loan!\n", 1, 2, 3, 4, 5, 6); END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1); goto cleanRXD; } if ((pClBlk = netClBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT)) == NULL) { netClFree (pDrvCtrl->endObj.pNetPool, pNewCluster); DRV_LOG (DRV_DEBUG_RX, "Out of Cluster Blocks!\n", 1, 2, 3, 4, 5, 6); END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1); goto cleanRXD; } /* * OK we've got a spare, let's get an M_BLK_ID and marry it to the * one in the ring. */ if ((pMblk = mBlkGet(pDrvCtrl->endObj.pNetPool, M_DONTWAIT, MT_DATA)) == NULL) { netClBlkFree (pDrvCtrl->endObj.pNetPool, pClBlk); netClFree (pDrvCtrl->endObj.pNetPool, pNewCluster); DRV_LOG (DRV_DEBUG_RX, "Out of M Blocks!\n", 1, 2, 3, 4, 5, 6); END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1); goto cleanRXD; } END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1); len = LN_PKT_LEN_GET (pRmd); /* get packet length */ LN_RMD_TO_ADDR (pRmd, pCluster); /* Get pointer to packet */ pCluster -= pDrvCtrl->offset; DRV_LOG (DRV_DEBUG_RX, "Packet @ 0x%X for %d bytes!\n", pCluster, len, 3, 4, 5, 6); /* Join the cluster to the MBlock */ netClBlkJoin (pClBlk, pCluster, len, NULL, 0, 0, 0); netMblkClJoin (pMblk, pClBlk); /* make the packet data coherent */ LN_CACHE_INVALIDATE (pMblk->mBlkHdr.mData, len); pMblk->mBlkHdr.mData += pDrvCtrl->offset; pMblk->mBlkHdr.mLen = len; pMblk->mBlkHdr.mFlags |= M_PKTHDR; pMblk->mBlkPktHdr.len = len; DRV_LOG (DRV_DEBUG_RX, "Calling upper layer!\n", 1, 2, 3, 4, 5, 6); /* Deal with memory alignment. */ pNewCluster += pDrvCtrl->offset; /* Give receiver a new buffer */ LN_RMD_BUF_TO_ADDR (pRmd, pTemp, pNewCluster); /* Call the upper layer's receive routine. */ END_RCV_RTN_CALL(&pDrvCtrl->endObj, pMblk);cleanRXD: /* clear status bits */ LN_CLEAN_RXD (pRmd); /* Flush the write pipe */ CACHE_PIPE_FLUSH (); /* Advance our management index */ pDrvCtrl->rmdIndex = (pDrvCtrl->rmdIndex + 1) & (pDrvCtrl->rringSize - 1); return (OK); }/********************************************************************************* lnSend - the driver send routine** This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.* The buffer must already have the addressing information properly installed* in it. This is done by a higher layer. The last arguments are a free* routine to be called when the device is done with the buffer and a pointer* to the argument to pass to the free routine. ** RETURNS: OK or ERROR.*/LOCAL STATUS ln97xSend ( LN_97X_DRV_CTRL * pDrvCtrl, /* device to be initialized */ M_BLK_ID pMblk /* data to send */ ) { LN_TMD * pTmd; UINT32 ltmd1; void * pTemp; char * pBuf; char * pOrig; int len = 0; /* check device mode */ if (pDrvCtrl->flags & LS_POLLING) { netMblkClChainFree (pMblk); errno = EINVAL; return (ERROR); } /* * Obtain exclusive access to transmitter. This is necessary because * we might have more than one stack transmitting at once. */ END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER); pTmd = pDrvCtrl->pTring + pDrvCtrl->tmdIndex; LN_CACHE_INVALIDATE (pTmd, TMD_SIZ); DRV_LOG (DRV_DEBUG_TX, "Send : index %d tmd = 0x%X\n", pDrvCtrl->tmdIndex, (int)pTmd, 3, 4, 5, 6); ltmd1 = PCI_SWAP (pTmd->tBufTmd1); if ((ltmd1 & TMD1_OWN) || (((pDrvCtrl->tmdIndex + 1) & (pDrvCtrl->tringSize - 1)) == pDrvCtrl->tmdIndexC)) { /* Are we still on the first chunk? */ DRV_LOG (DRV_DEBUG_TX, "Out of TMDs!\n", 1, 2, 3, 4, 5, 6); pDrvCtrl->txBlocked = TRUE; END_TX_SEM_GIVE (&pDrvCtrl->endObj); return (END_ERR_BLOCK); } DRV_LOG (DRV_DEBUG_TX, "before cluster get %d %d\n", pDrvCtrl->endObj.pNetPool, pDrvCtrl->pClPoolId, 3, 4, 5, 6); pOrig = pBuf = netClusterGet (pDrvCtrl->endObj.pNetPool, pDrvCtrl->pClPoolId); DRV_LOG (DRV_DEBUG_TX, "after cluster get pBuf = 0x%X\n", (int)pBuf, 2, 3, 4, 5, 6); if (pBuf == NULL) { pDrvCtrl->txBlocked = TRUE; END_TX_SEM_GIVE (&pDrvCtrl->endObj); return (END_ERR_BLOCK); } pBuf += pDrvCtrl->offset; /* take care of the alignment */ len = netMblkToBufCopy (pMblk, pBuf, NULL); netMblkClChainFree(pMblk); LN_TMD_BUF_TO_ADDR(pTmd, pTemp, pBuf); len = max (len, ETHERSMALL); pTmd->tBufTmd2 = 0; /* clear buffer error status */ ltmd1 = TMD1_STP | TMD1_ENP | TMD1_CNST; ltmd1 |= (TMD1_BCNT_MSK & -len); ltmd1 |= TMD1_OWN; /* set ownership bit in software */ DRV_LOG (DRV_DEBUG_TX, "TMD1 = 0x%X\n", ltmd1, 2, 3, 4, 5, 6); /* Advance our management index */ pDrvCtrl->tmdIndex = (pDrvCtrl->tmdIndex + 1) & (pDrvCtrl->tringSize - 1); /* write transmit descriptor (with OWN-bit set) to actual register */ pTmd->tBufTmd1 = PCI_SWAP (ltmd1); /* Flush the write pipe */ CACHE_PIPE_FLUSH (); if (lnKickStartTx) { ln97xCsrWrite (pDrvCtrl, 0, (CSR0_INEA | CSR0_TDMD)); } /* Bump the statistic counter. */ END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1); END_TX_SEM_GIVE (&pDrvCtrl->endObj); return (OK); }/********************************************************************************* ln97xIoctl - the driver I/O control routine** Process an ioctl request.** RETURNS OK or ERROR value*/LOCAL int ln97xIoctl ( LN_97X_DRV_CTRL * pDrvCtrl, /* device to be initialized */ int cmd, /* ioctl command to execute */ caddr_t data /* date to get or set */ ) { long value; int error = 0; switch (cmd) { case EIOCSADDR: if (data == NULL) return (EINVAL); bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->endObj), END_HADDR_LEN (&pDrvCtrl->endObj)); break; case EIOCGADDR: if (data == NULL) return (EINVAL); bcopy ((char *)END_HADDR (&pDrvCtrl->endObj), (char *)data, END_HADDR_LEN (&pDrvCtrl->endObj)); break; case EIOCSFLAGS: value = (long)data; if (value < 0) { value = -value; value--; /* HELP: WHY ??? */ END_FLAGS_CLR (&pDrvCtrl->endObj, value); } else { END_FLAGS_SET (&pDrvCtrl->endObj, value); } ln97xConfig (pDrvCtrl); break; case EIOCGFLAGS: *(int *)data = END_FLAGS_GET (&pDrvCtrl->endObj); break; case EIOCMULTIADD: error = ln97xMCastAddrAdd (pDrvCtrl, (char *) data); break; case EIOCMULTIDEL: error = ln97xMCastAddrDel (pDrvCtrl, (char *) data); break; case EIOCMULTIGET: error = ln97xMCastAddrGet (pDrvCtrl, (MULTI_TABLE *) data); break; case EIOCPOLLSTART: error = ln97xPollStart (pDrvCtrl); break; case EIOCPOLLSTOP: error = ln97xPollStop (pDrvCtrl); break; case EIOCGMIB2: if (data == NULL) return (EINVAL); bcopy((char *)&pDrvCtrl->endObj.mib2Tbl, (char *)data, sizeof(pDrvCtrl->endObj.mib2Tbl)); break; case EIOCGFBUF: if (data == NULL) return (EINVAL); *(int *)data = LN_MIN_FBUF; break; case EIOCGMWIDTH: if (data == NULL) return (EINVAL); *(int *)data = pDrvCtrl->memWidth; break; case EIOCGHDRLEN: if (data == NULL) return (EINVAL); *(int *)data = 14; break; default: error = EINVAL; } return (error); }/********************************************************************************* ln97xReset - hardware reset of chip (stop it)** This routine is responsible for resetting the device and switching into* 32 bit mode.** RETURNS: OK/ERROR*/LOCAL int ln97xReset ( LN_97X_DRV_CTRL * pDrvCtrl /* device to be initialized */ ) { UINT32 resetTmp; /* Enable 32 bit access by doing a 32 bit write */ SYS_OUT_LONG (pDrvCtrl, pDrvCtrl->pRdp, 0); ln97xCsrWrite (pDrvCtrl, CSR(0), CSR0_STOP); /* Generate a soft-reset of the controller */ SYS_IN_LONG(pDrvCtrl, pDrvCtrl->pReset, resetTmp); /* This isn't a real test - it just stops the compiler ignoring the read */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -