📄 if_nicevb.c
字号:
if ((isr & OVW) && (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING))) { cr = nicReadReg (pNic, &pNic->Cr, RPAGE0); nicWriteReg(pNic, &pNic->Imr, 0, RPAGE0); /* disable all interrupts */ pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); netJobAdd ((FUNCPTR) nicRestart, (int) pDrvCtrl, cr, 0, 0, 0); return; } /* handle packet received */ if ((isr & PRX) && (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING))) netJobAdd ((FUNCPTR) nicHandleInt, (int) pDrvCtrl, 0, 0, 0, 0); }/********************************************************************************* nicRestart - restart chip after receive ring buffer overflow** This routine is the task-level handler that deals with a receive DMA* overflow condition. It gets access to the remote DMA, cleans up NIC* registers, empties the receive ring buffers, and then resends any* packet that was in the midst of transmission when the overflow hit.** RETURNS: N/A.*/LOCAL void nicRestart ( DRV_CTRL * pDrvCtrl, UINT8 cr ) { NIC_DEVICE * pNic = pDrvCtrl->nicAddr; /* NIC registers */ BOOL resend = FALSE;#ifdef NIC_INSTRUMENT nicRestartNb++;#endif nicWriteCr (pNic, STP); nicResetDelay (); /* wait at least 1.6 mSec */ if (semTake(pDrvCtrl->dmaSem, 100) == ERROR) {#ifdef NIC_DEBUG if (_func_logMsg != NULL) _func_logMsg ("nicRestart: can't obtain dmaSem\n", 0, 0, 0, 0, 0,0);#endif semTake (pDrvCtrl->dmaSem, WAIT_FOREVER); } nicWriteReg (pNic, &pNic->Rbcr0, 0, RPAGE0); nicWriteReg (pNic, &pNic->Rbcr1, 0, RPAGE0); if ((cr & TXP) && (!(nicReadReg (pNic, &pNic->Isr, RPAGE0) & (TXE | PTX)))) resend = TRUE; nicWriteReg (pNic, &pNic->Tcr, MODE1, RPAGE0); nicWriteCr (pNic, RPAGE0 | ABORT | STA); /* back to page 0 */ pDrvCtrl->idr.ac_if.if_flags |= IFF_UP | IFF_RUNNING | IFF_NOTRAILERS; while (nicRead (pDrvCtrl)) ; nicWriteReg(pNic, &pNic->Isr, OVW, RPAGE0); nicWriteReg (pNic, &pNic->Tcr, MODE0, RPAGE0); if (resend) nicWriteCr (pNic, RPAGE0 | STA | TXP | ABORT); semGive(pDrvCtrl->dmaSem); nicWriteReg (pNic, &pNic->Imr, PRXE | OVWE, RPAGE0); }/********************************************************************************* nicHandleInt - deferred receive interrupt handler** This function handles the received frames from the device. It runs in the* context of the netTask, which was triggered by a received packet interrupt.* Actual processing of the packet is done by calling nicRead().** RETURNS: N/A.*/LOCAL void nicHandleInt ( DRV_CTRL * pDrvCtrl ) { /* empties the receive ring buffer of its packets */ while (nicRead (pDrvCtrl)); }/********************************************************************************* nicRead - read a packet off the interface ring buffer** nicRead copies packets from local memory into an mbuf and hands it to* the next higher layer (IP or etherInputHook).** RETURNS: TRUE, or FALSE if the packet reception encountered errors.*/LOCAL BOOL nicRead ( DRV_CTRL * pDrvCtrl ) { NIC_DEVICE * pNic = pDrvCtrl->nicAddr;/* NIC registers */ RX_FRAME * pRx = pDrvCtrl->pRxFrame;/* free Rx buffer */ MBUF * pMbuf = NULL; UINT32 len; /* len of Rx pkt */#ifdef BSD43_DRIVER UINT16 type; /* packet type - saved */#endif int cur; if (!(pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) || (pDrvCtrl->nextPkt == (cur = nicReadReg (pNic, &pNic->Curr, RPAGE1)))) return (FALSE); /* * OK, there is work to be done. * First we copy the NIC receive status header from the NIC buffer * into our local area. This is done so that we can obtain the length * of the packet before copying out the rest of it. Note that the length * field in the NIC header includes the Ethernet header, the data, and * the 4 byte FCS field. */ if (nicPktBufRead (pDrvCtrl, pDrvCtrl->nextPkt << 8, (RX_HDR_SIZ), (char *) &pRx->rxHdr) == ERROR) {#ifdef NIC_DEBUG if (_func_logMsg != NULL) _func_logMsg("nicRead could not read packet header\n",0,0,0,0,0,0);#endif return (FALSE); } len = pRx->rxHdr.cntL + (pRx->rxHdr.cntH << 8) - 4 /* FCS */; /* valid frame checks */ /* * NOTE: if the packet's receive status byte indicates an error * the packet is discarded and the receive page pointers are updated to * point to the next packet. */#ifdef NIC_INSTRUMENT nicLen = len; nicHdrStat = pRx->rxHdr.status; nicNextPage = pRx->rxHdr.nextRxPage; nicCurrentPage = cur;#endif if ((len < 60) || (len > 1514) || ((pRx->rxHdr.status & ~PHY) != PRX)) { pDrvCtrl->idr.ac_if.if_ierrors++;#ifdef NIC_DEBUG if (_func_logMsg != NULL) _func_logMsg ("nicRead receive error: statusHeader=0x%x nextRxPage=%d currentPage=%d len=%d IntNb=%d\n",pRx->rxHdr.status, pRx->rxHdr.nextRxPage, cur,len,nicIntNb);#endif if (nicPagePtrUpdate (pDrvCtrl)) return (TRUE); else return (FALSE); } /* copy Ethernet packet section of the frame */ if (nicPktBufRead(pDrvCtrl, (pDrvCtrl->nextPkt << 8) + RX_HDR_SIZ, len, (char *) &pRx->enetHdr) == ERROR) {#ifdef NIC_DEBUG if (_func_logMsg != NULL) _func_logMsg ("nicRead: Could not read packet data\n",0,0,0,0,0,0);#endif if (nicPagePtrUpdate(pDrvCtrl)) return (TRUE); else return (FALSE); } /* update ring buffer/page pointers */ if (!nicPagePtrUpdate (pDrvCtrl)) { return (FALSE); } pDrvCtrl->idr.ac_if.if_ipackets++; if ((etherInputHookRtn != NULL) && /* call hook if installed */ ((* etherInputHookRtn) (&pDrvCtrl->idr.ac_if, (char *) &pRx->enetHdr, len))) return (TRUE); len -= sizeof (ETH_HDR); /* now equals length of data only */#ifdef BSD43_DRIVER type = pRx->enetHdr.ether_type; /* build_cluster trashes type field */#endif if ((pDrvCtrl->lIndex) && (USE_CLUSTER (len))) /* use loaning ? */ { pRx->refCnt = 0; pMbuf = build_cluster (pRx->data, len, &pDrvCtrl->idr, MC_NIC_EVB, &pRx->refCnt, nicLoanFree, (int) pDrvCtrl, (int) pRx, 0); } if (pMbuf != NULL) /* loaning worked ? */ pDrvCtrl->pRxFrame = pDrvCtrl->lPool [--pDrvCtrl->lIndex]; else { pMbuf = copy_to_mbufs (pRx->data, len, 0, &pDrvCtrl->idr.ac_if); if (pMbuf == NULL) { pDrvCtrl->idr.ac_if.if_ierrors++; return (TRUE); } }#ifdef BSD43_DRIVER do_protocol_with_type (type, pMbuf, &pDrvCtrl->idr, len); /* up to IP */#else do_protocol (&pRx->enetHdr, pMbuf, &pDrvCtrl->idr, len);#endif return (TRUE); }#ifdef BSD43_DRIVER/********************************************************************************* nicOutput - the driver's output routine** RETURNS: N/A.*/LOCAL int nicOutput ( IDR * pIDR, MBUF * pMbuf, SOCK * pDest ) { return ether_output ((IFNET *) pIDR, pMbuf, pDest, (FUNCPTR) nicTxStartup, pIDR); }#endif/********************************************************************************* nicTxStartup - the driver's actual output routine** This routine accepts outgoing packets from the if_snd queue, and then * gains exclusive access to the DMA (through a mutex semaphore),* then calls nicTransmit() to send the packet out onto the interface.** RETURNS: OK, or ERROR if the packet could not be transmitted.*/#ifdef BSD43_DRIVERLOCAL STATUS nicTxStartup ( int unit ) { DRV_CTRL * pDrvCtrl = &drvCtrl [unit];#elseLOCAL STATUS nicTxStartup ( DRV_CTRL * pDrvCtrl ) {#endif MBUF * pMbuf; MBUF * mbuf; int status = OK; int length = 0; while (pDrvCtrl->idr.ac_if.if_snd.ifq_head) { IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf);/* dequeue a packet */ if ((pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) return (ERROR); if (semTake (pDrvCtrl->dmaSem, 100) == ERROR) /* get DMA access */ { if (_func_logMsg != NULL) _func_logMsg("nicTxStartup: can't obtain dmaSem\n",0,0,0,0,0,0); semTake (pDrvCtrl->dmaSem, WAIT_FOREVER); } for (mbuf = pMbuf; mbuf != NULL; mbuf = mbuf->m_next) length += mbuf->m_len; /* find length of chain */ if (length == 0) { m_freem (pMbuf); /* empty mbuf chain */ semGive (pDrvCtrl->dmaSem); continue; }#ifndef BSD43_DRIVER /* BSD 4.4 ether_output() doesn't bump statistic */ pDrvCtrl->idr.ac_if.if_opackets++;#endif#ifdef NIC_INSTRUMENT nicTxNb++;#endif /* send packet out over interface */ if ( (status = nicTransmit (pDrvCtrl, pMbuf, length, TRUE)) == ERROR) { pDrvCtrl->idr.ac_if.if_opackets--; pDrvCtrl->idr.ac_if.if_oerrors++; } semGive (pDrvCtrl->dmaSem); } return status; }/********************************************************************************* nicIoctl - the driver's I/O control routine** Perform device-specific commands.** RETURNS: 0, or EINVAL if the command 'cmd' is not supported.*/LOCAL int nicIoctl ( IDR * pIDR, int cmd, /* command to execute */ caddr_t data /* command-specific data */ ) { int error = 0; int s = splimp (); switch (cmd) { case SIOCSIFADDR: ((struct arpcom *)pIDR)->ac_ipaddr = IA_SIN (data)->sin_addr; arpwhohas (pIDR, &IA_SIN (data)->sin_addr); break; case SIOCSIFFLAGS: /* no driver-dependent flags */ break; default: error = EINVAL; } splx (s); return (error); }/********************************************************************************* nicEnetAddrGet - get the Ethernet address.** Get ethernet address from the BSP.** RETURNS: N/A.*/LOCAL void nicEnetAddrGet ( int unit ) { DRV_CTRL * pDrvCtrl = & drvCtrl [unit]; UINT8 enetAdrs[6]; UINT8 count; sysEnetAddrGet (unit, enetAdrs); for (count=0; count<6; count++) pDrvCtrl->idr.ac_enaddr[count] = enetAdrs[5-count]; }/********************************************************************************* nicConfig - configure the NIC chip and program address** This routine follows the algorythm in the ST-NIC manual for enabling* a NIC device on an active network. Essentially, this routine initializes* the NIC device.** RETURNS: N/A.*/LOCAL void nicConfig ( int unit ) { DRV_CTRL * pDrvCtrl = &drvCtrl [unit]; NIC_DEVICE * pNic= pDrvCtrl->nicAddr; nicWriteCr (pNic, RPAGE0 | STP | ABORT); nicResetDelay (); nicWriteReg (pNic, &pNic->Dcr, NOTLS | FIFO8, RPAGE0); /* clear remote DMA byte count registers */ nicWriteReg (pNic, &pNic->Rbcr0, 0, RPAGE0); nicWriteReg (pNic, &pNic->Rbcr1, 0, RPAGE0); /* accept broadcast, but not runt or multicast */ nicWriteReg (pNic, &pNic->Rcr, AB, RPAGE0); nicWriteReg (pNic, &pNic->Tcr, MODE1, RPAGE0); /* int loopback mode */ nicWriteReg (pNic, &pNic->Pstart, PSTART, RPAGE0); nicWriteReg (pNic, &pNic->Pstop, PSTOP, RPAGE0); nicWriteReg (pNic, &pNic->Bnry, BNRY, RPAGE0); nicWriteReg (pNic, &pNic->Isr, 0xff, RPAGE0); /* clr pending ints */ nicWriteReg (pNic, &pNic->Imr, PRXE | OVWE, RPAGE0); /* enable int */ nicEnetAddrGet (unit); /* get enet address */ /* set up page 1 registers */ nicWriteReg (pNic, &pNic->Par0, pDrvCtrl->idr.ac_enaddr [0], RPAGE1); nicWriteReg (pNic, &pNic->Par1, pDrvCtrl->idr.ac_enaddr [1], RPAGE1); nicWriteReg (pNic, &pNic->Par2, pDrvCtrl->idr.ac_enaddr [2], RPAGE1); nicWriteReg (pNic, &pNic->Par3, pDrvCtrl->idr.ac_enaddr [3], RPAGE1); nicWriteReg (pNic, &pNic->Par4, pDrvCtrl->idr.ac_enaddr [4], RPAGE1); nicWriteReg (pNic, &pNic->Par5, pDrvCtrl->idr.ac_enaddr [5], RPAGE1); nicWriteReg (pNic, &pNic->nic_pg1.mar0, 0xff, RPAGE1); nicWriteReg (pNic, &pNic->nic_pg1.mar1, 0xff, RPAGE1); nicWriteReg (pNic, &pNic->nic_pg1.mar2, 0xff, RPAGE1); nicWriteReg (pNic, &pNic->nic_pg1.mar3, 0xff, RPAGE1); nicWriteReg (pNic, &pNic->nic_pg1.mar4, 0xff, RPAGE1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -