📄 ei82596end.c
字号:
SYS_INT_ENABLE (pDrvCtrl); return (OK); }/********************************************************************************* ei82596Send - arrange to transmit a packet** This routine takes a NET_BUFFER and a NET_ADDRESS and sends the data in the* NET_BUFFER to the NET_ADDRESS.** RETURNS:*/LOCAL STATUS ei82596Send ( END_CTRL *pDrvCtrl, M_BLK_ID pMblk ) { TFD * pTfd; int len; DRV_PRINT (DRV_DEBUG_TX, ("t "));#if 0 SYS_INT_DISABLE (pDrvCtrl); if (pDrvCtrl->txBlocked) { SYS_INT_ENABLE (pDrvCtrl); return (END_ERR_BLOCK); } SYS_INT_ENABLE (pDrvCtrl);#endif /* check device mode */ if (DRV_FLAGS_ISSET(EI_POLLING)) {#if 0#ifdef DRV_DEBUG if (eiDebug & DRV_DEBUG_POLL_REDIR) { ei82596PollSend (pDrvCtrl, pNetBuf); return (OK); }#endif /*DRV_DEBUG*/ #endif netMblkClChainFree (pMblk); /* free the given mBlk chain */ errno = EINVAL; return (ERROR); } SYS_INT_DISABLE( pDrvCtrl ); if ((pTfd = (TFD *) ei82596QGet (&pDrvCtrl->freeQueue)) != NULL) { SYS_INT_ENABLE( pDrvCtrl ); len = netMblkToBufCopy (pMblk, (char *)pTfd->enetHdr, NULL); netMblkClChainFree (pMblk); /* set up the byte count field; use a min frame size of ETHERSMALL */ pTfd->count = max (ETHERSMALL, len); pTfd->count &= ~0xc000; /* arrange to to transmit the buffer */ SYS_INT_DISABLE( pDrvCtrl ); ei82596TxQPut (pDrvCtrl, pTfd); SYS_INT_ENABLE( pDrvCtrl ); } else /* case if the pfd is equal to NULL */ { pDrvCtrl->txBlocked = TRUE; SYS_INT_ENABLE( pDrvCtrl ); return (END_ERR_BLOCK); } return (OK); }/********************************************************************************* ei82596Int - entry point for handling interrupts from the 82596** The interrupting events are acknowledged to the device, so that the device* will deassert its interrupt signal. The amount of work done here is kept* to a minimum; the bulk of the work is defered to the netTask. Several flags* are used here to synchronize with task level code and eliminate races.*/LOCAL void ei82596Int ( END_CTRL *pDrvCtrl ) { SCB *pScb=pDrvCtrl->pScb; int unit=pDrvCtrl->unit; UINT16 event; event = pScb->scbStatus & (SCB_S_CX | SCB_S_FR | SCB_S_CNA | SCB_S_RNR); DRV_PRINT (DRV_DEBUG_INT, ("eiInt: event=0x%x\n", event)); ei82596Command (pDrvCtrl, event); /* ack the events */ sys596IntAck (unit); /* ack 596 interrupt */ /* Handle transmitter interrupt */ if (event & SCB_S_CNA) /* reclaim tx tfds */ { pDrvCtrl->wdTxTimeout = 0; /* reset timeout count */ ei82596QCat (&pDrvCtrl->cleanQueue, &pDrvCtrl->cblQueue); ei82596QInit (&pDrvCtrl->cblQueue); if (! pDrvCtrl->txCleaning) /* not cleaning? */ { pDrvCtrl->txCleaning = TRUE; /* defer cleanup */ netJobAdd ((FUNCPTR) ei82596TxCleanQ, (int) pDrvCtrl, 0, 0, 0, 0); } if (pDrvCtrl->txBlocked) { /* potential race condition ??? */ pDrvCtrl->txBlocked = FALSE; netJobAdd ((FUNCPTR) muxTxRestart, (int) &pDrvCtrl->endObj, 0, 0, 0, 0); } if (pDrvCtrl->txQueue.head != NULL) /* anything to flush? */ ei82596TxQFlush (pDrvCtrl); /* flush the tx q */ else pDrvCtrl->txIdle = TRUE; /* transmitter idle */ } /* Handle receiver interrupt */ if (event & SCB_S_FR) { pDrvCtrl->wdRxTimeout = 0; /* reset timeout count */ if (! pDrvCtrl->rxHandling) { pDrvCtrl->rxHandling = TRUE; (void) netJobAdd ((FUNCPTR) ei82596RxIntHandle, (int) pDrvCtrl,0, 0, 0, 0);/* netTask processes */ } } }/********************************************************************************* ei82596TxCleanQ - checks errors in completed TFDs and moves TFDs to free queue** This routine is executed by netTask. It "cleans" the TFDs on the clean-up* queue by checking each one for errors and then returning the TFD to the* "free TFD" queue. The startup routine is sometimes called here to eliminate* the lock-out case where the driver input queue is full but there are no* TFDs available.*/LOCAL void ei82596TxCleanQ ( END_CTRL *pDrvCtrl ) { TFD * pTfd; do { pDrvCtrl->txCleaning = TRUE; /* process transmitted frames */ while (1) { /* INT and SEM locks while manipulating this queue */ END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER); SYS_INT_DISABLE( pDrvCtrl ); pTfd = (TFD*) ei82596QGet ((EI_LIST *)&pDrvCtrl->cleanQueue); SYS_INT_ENABLE( pDrvCtrl ); END_TX_SEM_GIVE (&pDrvCtrl->endObj); if (pTfd == NULL) break; if (!(pTfd->status & CFD_S_OK)) /* packet not sent */ { END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1); END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, -1); } /* return to tfdQ */ END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER); ei82596QPut (pDrvCtrl,(EI_LIST *)&pDrvCtrl->freeQueue, (EI_NODE*)pTfd);#ifdef DRV_DEBUG nLoan--;#endif END_TX_SEM_GIVE (&pDrvCtrl->endObj); } pDrvCtrl->txCleaning = FALSE; } while (pDrvCtrl->cleanQueue.head != NULL); /* check again */ }/********************************************************************************* ei82596RxIntHandle - 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 ei82596RxIntHandle ( END_CTRL *pDrvCtrl ) { RFD *pRfd; do { pDrvCtrl->rxHandling = TRUE; /* interlock with ei82596Int()*/ while ((pRfd = ei82596RxQGet (pDrvCtrl)) != NULL) ei82596Recv (pDrvCtrl, pRfd); pDrvCtrl->rxHandling = FALSE; /* interlock with ei82596Int()*/ } while (ei82596RxQFull (pDrvCtrl)); /* make sure rx q still empty */ }/********************************************************************************* ei82596Recv - pass a received frame to the upper layer*** RETURNS: */LOCAL void ei82596Recv ( END_CTRL * pDrvCtrl, RFD * pRfd ) { RFD * pRfdLoaned = NULL; M_BLK_ID pMblk = NULL; CL_BLK_ID pClBlk = NULL; /* process the frame, if there are no errors */ if ((pRfd->status & (RFD_S_OK | RFD_S_COMPLETE)) != (RFD_S_OK | RFD_S_COMPLETE)) goto eiRecvError; if ((pMblk = netMblkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT, MT_DATA)) == NULL) goto eiRecvError; if ((pClBlk = netClBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT)) == NULL) goto eiRecvError; if ((pRfdLoaned = (RFD *) netClusterGet (pDrvCtrl->endObj.pNetPool, pDrvCtrl->pClPoolId)) == NULL) goto eiRecvError; /* offset pRfdLoaned if needed */ pRfdLoaned = (RFD *) (((char *) pRfdLoaned) + pDrvCtrl->offset); DRV_PRINT (DRV_DEBUG_RX, ("r ")); netClBlkJoin (pClBlk, ((char *)pRfd) - pDrvCtrl->offset, sizeof (RFD) + pDrvCtrl->offset, NULL, 0, 0, 0); netMblkClJoin (pMblk, pClBlk); END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1); pMblk->mBlkHdr.mFlags |= M_PKTHDR; pMblk->mBlkHdr.mData = (char *)&pRfd->enetHdr [0]; pMblk->mBlkHdr.mLen = pRfd->count & ~0xc000; pMblk->mBlkPktHdr.len = pMblk->mBlkHdr.mLen; /* return the buffer to the receive queue */ ei82596RxQPut (pDrvCtrl, (RFD *)pRfdLoaned); END_RCV_RTN_CALL (&pDrvCtrl->endObj, pMblk); return; eiRecvError: END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1); /* return the buffer to the receive queue */ ei82596RxQPut (pDrvCtrl, (RFD *)pRfd); if (pClBlk) netClBlkFree (pDrvCtrl->endObj.pNetPool, pClBlk); if (pMblk) netMblkFree (pDrvCtrl->endObj.pNetPool, pMblk); return; }/********************************************************************************* ei82596PollStart - start polling mode** RETURNS:*/LOCAL STATUS ei82596PollStart ( END_CTRL *pDrvCtrl ) { int intLevel; DRV_LOG (DRV_DEBUG_POLL, "PollStart", 0, 1, 2, 3, 4, 5 ); intLevel = intLock(); /* lock interrupts */ SYS_INT_DISABLE( pDrvCtrl ); DRV_FLAGS_SET (EI_POLLING); intUnlock (intLevel); /* unlock interupts */ return (OK); }/********************************************************************************* ei82596PollStop - stop polling mode** RETURNS:*/LOCAL STATUS ei82596PollStop ( END_CTRL *pDrvCtrl ) { int intLevel; DRV_LOG (DRV_DEBUG_POLL, "PollStop", 0, 1, 2, 3, 4, 5); intLevel = intLock(); SYS_INT_ENABLE( pDrvCtrl ); DRV_FLAGS_CLR (EI_POLLING); intUnlock (intLevel); return (OK); }/********************************************************************************* ei82596PollSend - transmit a packet in polled mode** RETURNS:*/LOCAL STATUS ei82596PollSend ( END_CTRL *pDrvCtrl, M_BLK_ID pMblk /* pointer to the mBlk/cluster pair */ ) { TFD *pTfd; char *pTemp; int len; DRV_LOG (DRV_DEBUG_POLL_TX, "T", 0, 1, 2, 3, 4, 5); /* check if the command unit is active */ if (pDrvCtrl->pScb->scbStatus & SCB_S_CUACTIVE) { DRV_LOG (DRV_DEBUG_POLL_TX, "e ", 0, 1, 2, 3, 4, 5); return (EAGAIN); } /* Is this ours? */ pTfd = pDrvCtrl->pPollTfd; len = netMblkToBufCopy (pMblk, (char *)pTfd->enetHdr, NULL); DRV_LOG (DRV_DEBUG_POLL_TX, "h ", 0, 1, 2, 3, 4, 5); pTfd->count = max (len, ETHERSMALL) & ~0xc000; /* transmit the buffer */ pTfd->status = 0; pTfd->command = CFD_C_XMIT | CFD_C_EL; pTfd->count |= TFD_CNT_EOF; pTfd->reserved = 0; LINK_WR (&pTfd->lBufDesc, NULL); pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pTfd); LINK_WR (&pDrvCtrl->pScb->pCB, pTemp); ei82596Command (pDrvCtrl, SCB_C_CUSTART); /* wait for the command to complete */ while (pDrvCtrl->pScb->scbStatus & SCB_S_CUACTIVE) ; /* HELP: timeout */ /* update statistics */ if (pTfd->status & CFD_S_OK) END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1); if (pTfd->status & CFD_S_RETRY) END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1); return (OK); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -