📄 ln97xend.c
字号:
LOCAL void ln97xHandleError ( LN_97X_DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */ UINT32 csr0Errors /* holds error bits read from CSR0 */ ) { pDrvCtrl->errorHandling = FALSE; if (csr0Errors & CSR0_MERR) { pDrvCtrl->lastError.errCode = END_ERR_WARN; pDrvCtrl->lastError.pMesg = "Bus master REQ timeout"; muxError (&pDrvCtrl->endObj, &pDrvCtrl->lastError); } if (csr0Errors & CSR0_BABL) { END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1); pDrvCtrl->lastError.errCode = END_ERR_WARN; pDrvCtrl->lastError.pMesg = "Babbling"; muxError (&pDrvCtrl->endObj, &pDrvCtrl->lastError); } if (csr0Errors & CSR0_MISS) { END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1); pDrvCtrl->lastError.errCode = END_ERR_WARN; pDrvCtrl->lastError.pMesg = "Missing"; muxError (&pDrvCtrl->endObj, &pDrvCtrl->lastError); } }/********************************************************************************* ln97xInt - handle controller interrupt** This routine is called at interrupt level in response to an interrupt from* the controller.** RETURNS: N/A*/LOCAL void ln97xInt ( LN_97X_DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */ ) { /* assume no errors */ UINT32 errs = 0; /* Read the device status register */ UINT32 stat = csrLockedRead (pDrvCtrl, CSR(0)); /* If false interrupt, return. */ if (! (stat & CSR0_INTR)) { return; } /* clear interrupt status, error status, and interrupt enable bits */ csrLockedWrite (pDrvCtrl, CSR(0), stat & (~CSR0_INEA)); /* check for any one, or a combination, of (3) error types */ errs = (stat & (CSR0_BABL | CSR0_MISS | CSR0_MERR)); if ((errs) && !(pDrvCtrl->errorHandling)) { /* put a task level error handler on the netTask job queue */ if (netJobAdd ((FUNCPTR) ln97xHandleError, (int) pDrvCtrl, (int) errs, 0, 0, 0) == OK) { pDrvCtrl->errorHandling = TRUE; } } /* process received frame descriptors */ if ((stat & CSR0_RINT) && !(pDrvCtrl->flags & LS_RCV_HANDLING_FLAG)) { /* put a task level input packet handler on the netTask job queue */ if (netJobAdd ((FUNCPTR) ln97xHandleRecvInt, (int) pDrvCtrl, 0,0,0,0) == OK) { pDrvCtrl->flags |= LS_RCV_HANDLING_FLAG; } } /* process transmitted frame descriptors */ if ((stat & CSR0_TINT) && !(pDrvCtrl->txCleaning)) { if (netJobAdd ((FUNCPTR) ln97xTRingScrub, (int) pDrvCtrl, 0, 0, 0, 0) == OK) { pDrvCtrl->txCleaning = TRUE; } } if (pDrvCtrl->txBlocked) /* cause a MUX restart */ { if (netJobAdd ((FUNCPTR) muxTxRestart, (int) &pDrvCtrl->endObj, 0, 0, 0, 0) == OK) { pDrvCtrl->txBlocked = FALSE; } } /* reenable device-side interrupts */ csrWrite (pDrvCtrl, CSR(0), CSR0_INEA); /* Flush the write pipe */ CACHE_PIPE_FLUSH (); }/********************************************************************************* 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 /* points to DRV_CTRL structure */ ) { 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 */ }/********************************************************************************* ln97xRecv - process the next incoming packet** RETURNS: OK or ERROR.*/LOCAL STATUS ln97xRecv ( LN_97X_DRV_CTRL * pDrvCtrl, /* points to device control structure */ LN_RMD * pRmd ) { int len; CL_BLK_ID pClBlk; M_BLK_ID pMblk; char * pCluster; char * pNewCluster; /* alias frequently referenced device control fields */ const int offset = pDrvCtrl->offset; END_OBJ * const pEndObj = &(pDrvCtrl->endObj); NET_POOL_ID const pNetPool = pEndObj->pNetPool; DRV_LOG (DRV_DEBUG_RX, "Recv : index %d rmd = 0x%X\n", pDrvCtrl->rmdIndex, (int) pRmd, 3, 4, 5, 6); /* If error flag OR if packet is not completely in one buffer */ if (rmdHasErrors (pRmd)) { END_ERR_ADD (pEndObj, MIB2_IN_ERRS, +1); goto cleanRXD; } /* If we cannot get a buffer to loan then bail out */ if ((pNewCluster = netClusterGet (pNetPool, pDrvCtrl->pClPoolId)) == NULL) {#if defined(END_ERR_NO_BUF) pDrvCtrl->lastError.errCode = END_ERR_NO_BUF; muxError (pEndObj, &pDrvCtrl->lastError);#endif /* defined(END_ERR_NO_BUF) */ END_ERR_ADD (pEndObj, MIB2_IN_ERRS, +1); goto cleanRXD; } if ((pClBlk = netClBlkGet (pNetPool, M_DONTWAIT)) == NULL) { netClFree (pNetPool, (UCHAR *) pNewCluster); END_ERR_ADD (pEndObj, MIB2_IN_ERRS, +1); goto cleanRXD; } /* get an <mBlk> and join it to the cluster from the RMD */ if ((pMblk = mBlkGet (pNetPool, M_DONTWAIT, MT_DATA)) == NULL) { netClBlkFree (pNetPool, pClBlk); netClFree (pNetPool, (UCHAR *) pNewCluster); END_ERR_ADD (pEndObj, MIB2_IN_ERRS, +1); goto cleanRXD; } /* get the packet length & a pointer to the packet */ len = LN_PKT_LEN_GET (pRmd); pCluster = rmdBuffAddrGet (pDrvCtrl, pRmd); pCluster -= offset; END_ERR_ADD (pEndObj, MIB2_IN_UCAST, +1); /* 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 += offset; pMblk->mBlkHdr.mLen = len; pMblk->mBlkHdr.mFlags |= M_PKTHDR; pMblk->mBlkPktHdr.len = len; /* Give receiver a new buffer */ pNewCluster += offset; rmdBuffAddrSet (pDrvCtrl, pRmd, pNewCluster); /* Call the upper layer's receive routine */ END_RCV_RTN_CALL (pEndObj, pMblk);cleanRXD: /* return a clean descriptor to the controller */ rxDescClean (pRmd); CACHE_PIPE_FLUSH (); /* increment index to RMD ring */ pDrvCtrl->rmdIndex = ((pDrvCtrl->rmdIndex + 1) % (pDrvCtrl->rringSize)); return (OK); }/********************************************************************************* ln97xSend - 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.** CAVEATS* Assumes that the TMD returned from ln97xTMDGet() has been "cleaned".* Assumes that the TMD will not be inadvertently cleaned while the* TMD is being constructed and before the controller has been given* ownersip of the TMD.** RETURNS: OK or ERROR.*/LOCAL STATUS ln97xSend ( LN_97X_DRV_CTRL * pDrvCtrl, /* device to be initialized */ M_BLK_ID pMblk /* data to send */ ) { volatile LN_TMD * pTmd; UINT32 ltmd1; char * pBuf; 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 = ln97xTMDGet (pDrvCtrl); DRV_LOG (DRV_DEBUG_TX, "Send : index %d tmd = 0x%X\n", pDrvCtrl->tmdIndex, (int) pTmd, 3, 4, 5, 6); if (pTmd == NULL) { pDrvCtrl->txBlocked = TRUE; END_TX_SEM_GIVE (&pDrvCtrl->endObj); return (END_ERR_BLOCK); } if ((pBuf = netClusterGet (pDrvCtrl->endObj.pNetPool, pDrvCtrl->pClPoolId)) == NULL) { pDrvCtrl->txBlocked = TRUE; END_TX_SEM_GIVE (&pDrvCtrl->endObj); return (END_ERR_BLOCK); } pBuf += pDrvCtrl->offset; len = netMblkToBufCopy (pMblk, pBuf, NULL); /* increment the unicast output counter */ END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1); netMblkClChainFree (pMblk); tmdBuffAddrSet (pDrvCtrl, pTmd, pBuf); ltmd1 = (TMD1_BCNT_MSK & -(max (len, ETHERSMALL))) | (TMD1_OWN | TMD1_CNST | TMD1_STP | TMD1_ENP); /* increment index to TMD ring */ pDrvCtrl->tmdIndex = ((pDrvCtrl->tmdIndex + 1) % (pDrvCtrl->tringSize)); /* write transmit descriptor (with OWN-bit set) to actual register */ pTmd->lnTMD1 = PCI_SWAP (ltmd1); CACHE_PIPE_FLUSH (); if (lnKickStartTx) { csrLockedWrite (pDrvCtrl, CSR(0), (CSR0_INEA | CSR0_TDMD)); } 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 /* data to get or set */ ) { int error = 0; switch ((UINT)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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -