📄 if_eihk.c
字号:
LINK_WR (&pScb->pCB, pTemp); /* point chip at CFD */ sys596ChanAtn (unit); /* notify device of new command */ } while (1) /* wait for command acceptance and interrupt */ { if ((pScb->scbCommand == 0) && (pScb->scbStatus & SCB_S_CNA)) break; } /* Acknowledge the event to the device */ pScb->scbCommand = (SCB_S_CX | SCB_S_CNA); sys596ChanAtn (unit); while (1) /* wait for acknowledge acceptance */ { if (pScb->scbCommand == 0) break; } }/********************************************************************************* eiCommand - deliver a command to the 82596 via SCB** This function causes the device to execute a command. It should be called* with interrupts from the device disabled. An error status is returned if* the command field does not return to zero, from a previous command, in a* reasonable amount of time.*/static STATUS eiCommand ( DRV_CTRL *pDrvCtrl, UINT16 cmd ) { int loopy; SCB * pScb; pScb = pDrvCtrl->pScb; for (loopy = 0x8000; loopy--;) { if (pScb->scbCommand == 0) /* wait for cmd zero */ break; } if (loopy > 0) { pScb->scbCommand = cmd; /* fill in command */ sys596ChanAtn (pDrvCtrl->idr.ac_if.if_unit); /* channel attention */ return (OK); } else { logMsg("ei driver: command field frozen\n", 0, 0, 0, 0, 0, 0); return (ERROR); } }/********************************************************************************* eiTxQPut - place a transmit frame on the transmit queue** The TFD has been filled in with the network pertinent data. This* routine will enqueue the TFD for transmission and attempt to feed* the queue to the device.*/static void eiTxQPut ( DRV_CTRL *pDrvCtrl, TFD *pTfd ) { int unit; unit = pDrvCtrl->idr.ac_if.if_unit; pTfd->status = 0; /* fill in TFD fields */ pTfd->command = CFD_C_XMIT; /* EL set later */ pTfd->count |= TFD_CNT_EOF; /* data kept in frame */ pTfd->reserved = 0; /* must be zero */ LINK_WR (& pTfd->lBufDesc, NULL); /* TBDs not used */ sys596IntDisable (pDrvCtrl->idr.ac_if.if_unit); /* disable dev ints */ /* enqueue the TFD */ eiQPut (unit,(EI_LIST *)&pDrvCtrl->txQueue, (EI_NODE*)pTfd); if (pDrvCtrl->txIdle) /* transmitter idle */ eiTxQFlush (pDrvCtrl); /* flush txQueue */ sys596IntEnable (pDrvCtrl->idr.ac_if.if_unit); /* enable dev ints */ }/********************************************************************************* eiTxQFlush - make cmd unit of device start processing cmds** This routine flushes the contents of the txQ to the cblQ and starts the* device transmitting the cblQ. Called only if transmit queue is not empty.* Sometimes called from interrupt handler.*/static void eiTxQFlush ( DRV_CTRL *pDrvCtrl ) { void * pTemp; extern int sysClkRateGet(); /* we call this */ ((TFD*)pDrvCtrl->txQueue.tail)->command |= CFD_C_EL; /* EL terminate q */ pDrvCtrl->cblQueue.head = pDrvCtrl->txQueue.head; /* remember cbl head */ pDrvCtrl->cblQueue.tail = pDrvCtrl->txQueue.tail; /* remember cbl tail */ eiQInit ((EI_LIST *)&pDrvCtrl->txQueue); /* tx queue now empty */ pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pDrvCtrl->cblQueue.head); LINK_WR (&pDrvCtrl->pScb->pCB, pTemp); /* point CU to head */ pDrvCtrl->txIdle = FALSE; /* transmitter busy */ /* start command unit */ eiCommand (pDrvCtrl, SCB_C_CUSTART); }/********************************************************************************* eiRxQPut - return a RFD to the receive queue for use by the device*/static void eiRxQPut ( DRV_CTRL *pDrvCtrl, RFD *pRfd ) { int unit; RFD *pTail; RBD *pRbd; void *pTemp; unit = pDrvCtrl->idr.ac_if.if_unit; pRbd = &pRfd->rbd; /* Initialize the RFD */ pRfd->status = 0; pRfd->command = RFD_M_EL | RFD_M_FLEXMODE; pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pRbd); LINK_WR (&pRfd->lBufDesc, pTemp); pRfd->actualCnt = 0; pRfd->bufSize = EH_SIZE; /* Initialize the RBD */ pRbd->actualCnt = 0; pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pRfd->enetData); LINK_WR (&pRbd->pData, pTemp); pRbd->size = RBD_EL | ETHERMTU; pTail = (RFD *) pDrvCtrl->rxQueue.tail; /* remember tail */ /* Put the RFD on the list */ eiQPut (unit, (EI_LIST *) & pDrvCtrl->rxQueue, (EI_NODE *) pRfd); if (pTail != NULL) { pDrvCtrl->wdRxTimeout = 0; /* reset timeout count */ /* update RBD links */ pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pRbd); LINK_WR (&pTail->rbd.lNext, pTemp); pTail->rbd.size &= ~RBD_EL; pTail->command &= ~CFD_C_EL; /* clear old tail EL */ if (pTail->status & (CFD_S_COMPLETE | CFD_S_BUSY)) { pDrvCtrl->pFreeRfd = pRfd; /* link questionable */ } else if (!(pDrvCtrl->pScb->scbStatus & SCB_S_RUREADY)) /* receiver dormant */ { eiRxStartup (pDrvCtrl); /* start receive unit */ } } else { pDrvCtrl->pFreeRfd = pRfd; /* first free RFD */ } }/********************************************************************************* eiRxQGet - get a successfully received frame from the receive queue** RETURNS: ptr to valid RFD, or NULL if none available*/static RFD *eiRxQGet ( DRV_CTRL *pDrvCtrl ) { RFD *pRfd = NULL; if (eiRxQFull (pDrvCtrl)) pRfd = (RFD *) eiQGet ((EI_LIST *)&pDrvCtrl->rxQueue); return (pRfd); }/********************************************************************************* eiRxQFull - boolean function to determine fullness of receive queue** RETURNS: TRUE if completely received frame is available, FALSE otherwise.*/static BOOL eiRxQFull ( DRV_CTRL *pDrvCtrl ) { return ((pDrvCtrl->rxQueue.head != NULL) && (((RFD*)pDrvCtrl->rxQueue.head)->status & CFD_S_COMPLETE)); }/********************************************************************************* eiQInit - initialize a singly linked node queue*/static void eiQInit ( EI_LIST *pQueue ) { pQueue->head = pQueue->tail = NULL; /* init head & tail */ }/********************************************************************************* eiQGet - get a node from the head of a node queue** RETURNS: ptr to useable node, or NULL ptr if none available*/static EI_NODE *eiQGet ( EI_LIST *pQueue ) { EI_NODE *pNode; if ((pNode = (EI_NODE *) pQueue->head) != NULL) /* if list not empty */ pQueue->head = pNode->pNext; /* advance ptr */ return (pNode); }/********************************************************************************* eiQPut - put a node on the tail of a node queue*/static void eiQPut ( int unit, EI_LIST *pQueue, EI_NODE *pNode ) { void * pTemp; DRV_CTRL *pDrvCtrl; pDrvCtrl = & drvCtrl [unit]; LINK_WR (&pNode->lNext, NULL); /* mark "end of list" */ pNode->pNext = NULL; if (pQueue->head == NULL) /* if list empty */ pQueue->tail = pQueue->head = pNode; /* set both ptrs */ else { pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pNode); LINK_WR (&pQueue->tail->lNext, pTemp); /* link node on tail */ pQueue->tail->pNext = pNode; pQueue->tail = pNode; /* update tail ptr */ } }/********************************************************************************* eiWatchDog - if the watchdog timer fired off, we've hung during a transmit** Check the scb command to verify and if so, reinit.*/static void eiWatchDog ( int unit /* unit number */ ) { DRV_CTRL *pDrvCtrl = &drvCtrl [unit]; SCB *pScb; int reset = FALSE; pScb = pDrvCtrl->pScb; /* Test for transmit timeout. * * Timeout occurs if the scb status indicates that CU (transmit) * remains active for EI_TX_TIMEOUT iterations of eiWatchDog. * It might make sense to loop through the cfd's to look for * a complete bit as a sanity check, but given that transmit * was active, we will go ahead and do a reset. */ if ((pDrvCtrl->txIdle == FALSE) && (pScb->scbStatus & SCB_S_CUACTIVE)) { if (++(pDrvCtrl->wdTxTimeout) > EI_TX_TIMEOUT) { pDrvCtrl->transLocks++; /* failure count */ pDrvCtrl->idr.ac_if.if_oerrors++; /* incr err count */ pDrvCtrl->idr.ac_if.if_opackets--; /* decr sent count */ reset = TRUE; } } /* Test for receive timeout. * * Timeout occurs if the scb status indicates that RU (receive) * remains out of resources for EI_RX_TIMEOUT iterations of eiWatchDog. */ if (pScb->scbStatus & SCB_S_RUNORSRC) { if (++(pDrvCtrl->wdRxTimeout) > EI_RX_TIMEOUT) { pDrvCtrl->recvLocks++; /* failure count */ reset = TRUE; } } /* reinitialize the unit or restart the watchdog */ if (reset) netJobAdd ((FUNCPTR) eiInit, unit,0, 0, 0, 0); else wdStart (pDrvCtrl->wid, (int) pDrvCtrl->wdInterval, (FUNCPTR) eiWatchDog, unit); }/******************************************************************************//* END OF FILE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -