📄 if_eidve.c
字号:
}/********************************************************************************* eiInt - 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.*/static void eiInt ( DRV_CTRL *pDrvCtrl ) { UINT16 event; SCB *pScb; int unit; pScb = pDrvCtrl->pScb; unit = pDrvCtrl->idr.ac_if.if_unit; event = pScb->scbStatus & (SCB_S_CX | SCB_S_FR | SCB_S_CNA | SCB_S_RNR);#ifdef EI_DEBUG logMsg ("ei: interrupt: event=%x\n", event, 0, 0, 0, 0, 0);#endif /* EI_DEBUG */ eiCommand (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 */ if (pDrvCtrl->cleanQueue.head == NULL) /* clean queue empty */ { pDrvCtrl->cleanQueue.head = pDrvCtrl->cblQueue.head; /* new head */ pDrvCtrl->cleanQueue.tail = pDrvCtrl->cblQueue.tail; /* new tail */ } else /* concatenate queues */ { LINK_WR ( (EI_LINK * ) &(pDrvCtrl->cleanQueue.tail->pNext), (void*) pDrvCtrl->cblQueue.head); pDrvCtrl->cleanQueue.tail = pDrvCtrl->cblQueue.tail; } if (!pDrvCtrl->txCleaning) /* not cleaning? */ { pDrvCtrl->txCleaning = TRUE; /* set flag */ netJobAdd ((FUNCPTR) eiTxCleanQ, (int) pDrvCtrl, 0, 0, 0, 0); /* defer cleanup */ } if (pDrvCtrl->txQueue.head != NULL) /* anything to flush? */ eiTxQFlush (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->rcvHandling)) { pDrvCtrl->rcvHandling = TRUE; (void) netJobAdd ((FUNCPTR) eiHandleRecvInt, (int) pDrvCtrl,0, 0, 0, 0); /* netTask processes */ } } }/********************************************************************************* eiTxCleanQ - 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.*/static void eiTxCleanQ ( DRV_CTRL *pDrvCtrl ) { TFD *pTfd; BOOL needTxStart; int unit; unit = pDrvCtrl->idr.ac_if.if_unit; do { pDrvCtrl->txCleaning = TRUE; if (pDrvCtrl->tfdQueue.head == NULL) /* tfd queue empty */ needTxStart = TRUE; /* set flag */ else needTxStart = FALSE; /* process transmitted frames */ while (1) { /* Get TFD. No ints allowed while manipulating this queue. */ sys596IntDisable (unit); pTfd = (TFD*) eiQGet ((EI_LIST *)&pDrvCtrl->cleanQueue); sys596IntEnable (unit); if (pTfd == NULL) break; pDrvCtrl->idr.ac_if.if_collisions += /* add any colls */ (pTfd->status & CFD_S_RETRY) ? 16 : /* excessive colls */ (pTfd->status & CFD_S_COLL_MASK); /* some colls */ if (!(pTfd->status & CFD_S_OK)) /* packet not sent */ { pDrvCtrl->idr.ac_if.if_oerrors++; /* incr err count */ pDrvCtrl->idr.ac_if.if_opackets--; /* decr sent count */ } /* return to tfdQ */ eiQPut (unit,(EI_LIST *)&pDrvCtrl->tfdQueue, (EI_NODE*)pTfd); } if (needTxStart) /* check flag */ eiTxStartup (pDrvCtrl); pDrvCtrl->txCleaning = FALSE; } while (pDrvCtrl->cleanQueue.head != NULL); /* check again */ }/********************************************************************************* eiHandleRecvInt - 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.*/static void eiHandleRecvInt ( DRV_CTRL *pDrvCtrl ) { RFD *pRfd; do { pDrvCtrl->rcvHandling = TRUE; /* interlock with eiInt() */ while ((pRfd = eiRxQGet (pDrvCtrl)) != NULL) if (eiReceive (pDrvCtrl, pRfd) == OK) eiRxQPut (pDrvCtrl, pRfd); pDrvCtrl->rcvHandling = FALSE; /* interlock with eiInt() */ } while (eiRxQFull (pDrvCtrl)); /* make sure rx q still empty */ }/********************************************************************************* eiReceive - pass a received frame to the next layer up** Strips the Ethernet header and passes the packet to the appropriate* protocol. The return value indicates if buffer loaning was used to hold* the data. A return value of OK means that loaning was not done, and it* is therefore 'ok' to return the RFD to the Rx queue. A return value of ERROR* means that buffer loaning was employed, and so the RFD is still in use and* should not be returned to the Rx queue. In this latter case, the RFD will* eventually be returned by the protocol, via a call to our eiLoanFree().*/static STATUS eiReceive ( DRV_CTRL *pDrvCtrl, RFD *pRfd ) { ETH_HDR *pEh; u_char *pData; int len; UINT16 etherType; MBUF *m = NULL; BOOL rfdLoaned = FALSE; /* Check packet for errors. This should be completely unnecessary, * but since Intel does not seem capable of explaining the exact * functioning of the 'save bad frames' config bit, we will look for * errors. */ if ( ( pRfd->status & ( RFD_S_OK | RFD_S_COMPLETE ) ) != ( RFD_S_OK | RFD_S_COMPLETE ) ) { ++pDrvCtrl->idr.ac_if.if_ierrors; /* bump error counter */ eiRxQPut (pDrvCtrl, pRfd); /* free the RFD */ return (ERROR); } /* Bump input packet counter. */ ++pDrvCtrl->idr.ac_if.if_ipackets; len = pRfd->actualCnt & ~0xc000; /* get frame length */ pEh = (ETH_HDR *)pRfd->enetHdr; /* get ptr to ethernet header */ /* Service input hook */ if ( (etherInputHookRtn != NULL) ) { if ( (* etherInputHookRtn) (&pDrvCtrl->idr, (char *)pEh, len) ) { eiRxQPut (pDrvCtrl, pRfd); /* free the RFD */ return (OK); } } len -= EH_SIZE; pData = (u_char *) pRfd->enetData; etherType = ntohs (pEh->ether_type); /* we can loan out receive frames from 82596 receive queue if: * * 1) the threshold of loanable frames has not been exceeded * 2) size of the input ethernet frame is large enough to be used with * clustering. */ if ((pDrvCtrl->nLoanRfds > 0) && ((m = build_cluster (pData, len, &pDrvCtrl->idr, MC_EI, &pRfd->refCnt, eiLoanFree, (int) pDrvCtrl, (int) pRfd, NULL)) != NULL)) { pDrvCtrl->nLoanRfds --; /* one less to loan */ rfdLoaned = TRUE; /* we loaned a frame */ } else m = copy_to_mbufs (pData, len, 0, &pDrvCtrl->idr); if (m != NULL)#ifdef BSD43_DRIVER do_protocol_with_type (etherType, m, &pDrvCtrl->idr, len);#else do_protocol (pEh, m, &pDrvCtrl->idr, len);#endif return ((rfdLoaned) ? ERROR : OK); }/********************************************************************************* eiLoanFree - return a loaned receive frame descriptor** This routine is called by the protocol code when it has completed use of* an RFD that we loaned to it.*/static void eiLoanFree ( DRV_CTRL *pDrvCtrl, RFD *pRfd ) { eiRxQPut (pDrvCtrl, pRfd); pDrvCtrl->nLoanRfds ++; }/********************************************************************************* eiDeviceStart - reset and start the device** This routine assumes interrupts from the device have been disabled, and* that the driver control structure has been initialized.*/static STATUS eiDeviceStart ( int unit /* physical unit number */ ) { void *pTemp; DRV_CTRL *pDrvCtrl; SCP *pScp; /* system config ptr */ ISCP *pIscp; /* intermediate system config ptr */ SCB *pScb; /* system control block ptr */ /* Get pointers */ pDrvCtrl = & drvCtrl [unit]; pScp = pDrvCtrl->pScp; pIscp = pDrvCtrl->pIscp; pScb = pDrvCtrl->pScb; /* Issue the reset operation to the device */ sys596Port (unit, PORT_RESET, NULL); /* Initialize the SCP */ pScp->scpRsv1 = pScp->scpRsv2 = pScp->scpRsv3 = 0; pScp->scpSysbus = pDrvCtrl->sysbus; pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pIscp); LINK_WR (&pScp->pIscp, pTemp); /* point SCP to ISCP */ /* Initialize the ISCP */ pIscp->iscpBusy = 1; pIscp->iscpRsv1 = 0; pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pScb); LINK_WR (&pIscp->pScb, pTemp); /* point ISCP to SCB */ /* Initialize the SCB */ bzero ((char *)pScb, sizeof (SCB)); /* Tell the device where the SCP is located */ pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pScp); sys596Port (unit, PORT_NEWSCP, (UINT32) pTemp); sys596ChanAtn (unit); /* * The device will now read our SCP and ISCP. It will clear the busy * flag in the ISCP. */ taskDelay (50); if ( pIscp->iscpBusy == 1 ) { printf ("\nei: device did not initialize\n"); return (ERROR); } return (OK); }/********************************************************************************* eiDiag - format and issue a diagnostic command*/static void eiDiag ( int unit ) { DRV_CTRL *pDrvCtrl; pDrvCtrl = & drvCtrl [unit]; bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD)); /* zero command frame */ eiAction (unit, CFD_C_DIAG); /* run diagnostics */ if (!(pDrvCtrl->pCfd->cfdStatus & CFD_S_OK)) printErr ("eiDiag: i82596 diagnostics failed.\n"); }/********************************************************************************* eiConfig - format and issue a config command*/static void eiConfig ( int unit ) { DRV_CTRL *pDrvCtrl; pDrvCtrl = & drvCtrl [unit]; bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD)); /* zero command frame */ /* Recommeded i82596 User's Manual configuration values. Note that * the original manual, #296443-001, was full of errors. Errors in the * description of the config bytes that I am aware of are noted below. * It is possible there are further errors. Intel has replaced the * manual with #296853-001, which does correct some errors, but not all. */ pDrvCtrl->pCfd->cfdConfig.ccByte8 = 0x8e; pDrvCtrl->pCfd->cfdConfig.ccByte9 = 0xc8; /* The manual is wrong about bit 7 in byte 10. * A '0' allows reception of bad packets. * A '1' causes rejection of bad packets. */ pDrvCtrl->pCfd->cfdConfig.ccByte10 = 0xc0; pDrvCtrl->pCfd->cfdConfig.ccByte11 = 0x2e; /* loopback, NSAI */ pDrvCtrl->pCfd->cfdConfig.ccByte12 = 0x00; pDrvCtrl->pCfd->cfdConfig.ccByte13 = 0x60; pDrvCtrl->pCfd->cfdConfig.ccByte14 = 0x00; pDrvCtrl->pCfd->cfdConfig.ccByte15 = 0xf2; pDrvCtrl->pCfd->cfdConfig.ccByte16 = 0x00; /* promiscuous off */ pDrvCtrl->pCfd->cfdConfig.ccByte17 = 0x00; pDrvCtrl->pCfd->cfdConfig.ccByte18 = 0x40; /* The manual is wrong about 2 bits in byte 19. * Bit 5, multicast, a '1' disables. * Bit 2, include CRC, a '1' disables. */ pDrvCtrl->pCfd->cfdConfig.ccByte19 = 0xff; pDrvCtrl->pCfd->cfdConfig.ccByte20 = 0x00; pDrvCtrl->pCfd->cfdConfig.ccByte21 = 0x3f; eiAction (unit, CFD_C_CONFIG); /* configure the chip */ }/********************************************************************************* eiIASetup - format and issue an interface address command*/static void eiIASetup ( int unit ) { DRV_CTRL *pDrvCtrl; pDrvCtrl = & drvCtrl [unit]; bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD)); /* zero command frame */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -