📄 if_ln.c
字号:
} while (pDrvCtrl->tmdIndexC != pDrvCtrl->tmdIndex) { /* disposal has not caught up */ tmd = pDrvCtrl->tring + pDrvCtrl->tmdIndexC; /* if the buffer is still owned by LANCE, don't touch it */ LN_CACHE_INVALIDATE (tmd, TMD_SIZ); if (tmd->tbuf_stat & TMD_OWN) break; /* * lntmd1_ERR is an "OR" of LCOL, LCAR, UFLO or RTRY. * Note that BUFF is not indicated in lntmd1_ERR. * We should therefore check both lntmd1_ERR and lntmd3_BUFF * here for error conditions. */ if ((tmd->tbuf_stat & lntmd1_ERR) || (tmd->tbuf_err & lntmd3_BUFF)) { pDrvCtrl->idr.ac_if.if_oerrors++; /* output error */ pDrvCtrl->idr.ac_if.if_opackets--; /* * If error was due to excess collisions, bump the collision * counter. The LANCE does not keep an individual counter of * collisions, so in this driver, the collision statistic is not * an accurate count of total collisions. */ if (tmd->tbuf_err & lntmd3_RTRY) /* assume DRTY bit not set */ pDrvCtrl->idr.ac_if.if_collisions += 16; /* check for no carrier */ if (tmd->tbuf_err & TMD_LCAR) logMsg ("ln%d: no carrier\n", pDrvCtrl->idr.ac_if.if_unit, 0, 0, 0, 0, 0); /* Restart chip on fatal errors. * The following code handles the situation where the transmitter * shuts down due to an underflow error. This is a situation that * will occur if the DMA cannot keep up with the transmitter. * It will occur if the LANCE is being held off from DMA access * for too long or due to significant memory latency. DRAM * refresh or slow memory could influence this. Many * implementations use a dedicated LANCE buffer. This can be * static RAM to eliminate refresh conflicts; or dual-port RAM * so that the LANCE can have free run of this memory during its * DMA transfers. */ if ((tmd->tbuf_err & lntmd3_BUFF) || (tmd->tbuf_err & TMD_UFLO)) { pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); logMsg ("lnInt: transmitter underflow\n", 0, 0, 0, 0, 0, 0); (void) netJobAdd ((FUNCPTR) lnRestart, pDrvCtrl->idr.ac_if.if_unit, 0,0,0,0); /* Flush the write pipe */ CACHE_PIPE_FLUSH (); /* allow interrupt line to go inactive */ i = 3; while (i-- && (lnCsr0Read (pDrvCtrl) & lncsr_INTR)) ; return; } } tmd->tbuf_stat &= 0x00ff; /* reset status bits */ tmd->tbuf_err = 0; /* clear error bits */ /* now bump the tmd disposal index pointer around the ring */ pDrvCtrl->tmdIndexC = (pDrvCtrl->tmdIndexC + 1) & (pDrvCtrl->tringSize - 1); } CACHE_PIPE_FLUSH (); /* flush the write pipe */ /* allow interrupt line to go inactive */ i = 3; while (i-- && (lnCsr0Read (pDrvCtrl) & lncsr_INTR)) ; }/********************************************************************************* lnHandleRecvInt - 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 lnHandleRecvInt ( DRV_CTRL *pDrvCtrl ) { do { pDrvCtrl->flags |= LN_RX_HANDLING_FLAG; while (lnGetFullRMD (pDrvCtrl)) lnRecv (pDrvCtrl); /* * 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 &= ~LN_RX_HANDLING_FLAG; } while (lnGetFullRMD (pDrvCtrl)); /* double check for RACE */ }/********************************************************************************* lnGetFullRMD - check next RMD for ownership**/LOCAL BOOL lnGetFullRMD ( DRV_CTRL *pDrvCtrl ) { int status = FALSE; ln_rmd *rmd; if ((pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) { rmd = pDrvCtrl->rring + pDrvCtrl->rmdIndex; LN_CACHE_INVALIDATE (rmd, RMD_SIZ); if ((rmd->rbuf_stat & lnrmd1_OWN) == 0) status = TRUE; } return (status); }/********************************************************************************* lnRecv - process the next incoming packet**/LOCAL STATUS lnRecv ( DRV_CTRL *pDrvCtrl ) { ETH_HDR *pEnetHdr; MBUF *pMbuf = NULL; ln_rmd *rmd = pDrvCtrl->rring + pDrvCtrl->rmdIndex; u_char *pData; u_long pPhys; int len; u_short type; /* packet must be checked for errors or possible data chaining */ if ((rmd->rbuf_stat & lnrmd1_ERR) || ((rmd->rbuf_stat & (lnrmd1_STP | lnrmd1_ENP)) != (lnrmd1_STP | lnrmd1_ENP))) { ++pDrvCtrl->idr.ac_if.if_ierrors; /* bump error stat */ goto cleanRXD; /* skip to clean up */ } len = rmd->rbuf_mcnt; /* get packet length */ len = len - 4; /* omit frame check sequence */ /* get pointer to the receive buffer */ pPhys = ((ULONG)pDrvCtrl->pMemPool & 0xff000000) | ((rmd->rbuf_ladr | (rmd->rbuf_hadr << 16)) & 0x00ffffff); pEnetHdr = (ETH_HDR *) LN_CACHE_PHYS_TO_VIRT (pPhys); LN_CACHE_INVALIDATE (pEnetHdr, len); /* make the pkt data coherent */ /* call input hook if any */ if ((etherInputHookRtn == NULL) || ((*etherInputHookRtn) (& pDrvCtrl->idr.ac_if, (char *) pEnetHdr, len)) == 0) { len -= SIZEOF_ETHERHEADER; /* adjust length to size of data only */ type = ntohs (pEnetHdr->ether_type); /* save type field */ pData = ((u_char *) pEnetHdr) + SIZEOF_ETHERHEADER; /* OK to loan out buffer ? -> build an mbuf cluster */#ifdef BSD43_DRIVER if ((pDrvCtrl->nLoanRx > 0) && (USE_CLUSTER (len))) pMbuf = build_cluster (pData, len, & pDrvCtrl->idr, MC_LANCE, pDrvCtrl->pRefCnt[(pDrvCtrl->nLoanRx - 1)], lnLoanFree, (int) pDrvCtrl, (int) pEnetHdr, (int) pDrvCtrl->pRefCnt[(pDrvCtrl->nLoanRx - 1)]); /* if buffer was successfully turned into mbuf cluster */ if (pMbuf != NULL) { pPhys = (u_long) LN_CACHE_VIRT_TO_PHYS (pDrvCtrl->lPool[--pDrvCtrl->nLoanRx]); rmd->rbuf_ladr = pPhys; rmd->rbuf_hadr = (pPhys >> 16) & lnrmd1_HADR; } else { if ((pMbuf = bcopy_to_mbufs (pData, len, 0, & pDrvCtrl->idr.ac_if, pDrvCtrl->memWidth)) == NULL) { ++pDrvCtrl->idr.ac_if.if_ierrors; /* bump error stat */ goto cleanRXD; } } /* send on up... */ do_protocol_with_type (type, pMbuf, & pDrvCtrl->idr, len);#else /* BSD43_DRIVER */ if ((pDrvCtrl->nLoanRx > 0) && (USE_CLUSTER (len)) && ((pMbuf = build_cluster (pData, len, &pDrvCtrl->idr.ac_if, MC_LANCE, pDrvCtrl->pRefCnt[(pDrvCtrl->nLoanRx - 1)], (FUNCPTR)lnLoanFree, (int)pDrvCtrl, (int)pEnetHdr, (int)pDrvCtrl->pRefCnt[(pDrvCtrl->nLoanRx - 1)])) != NULL)) { pPhys = (u_long) LN_CACHE_VIRT_TO_PHYS (pDrvCtrl->lPool[--pDrvCtrl->nLoanRx]); rmd->rbuf_ladr = pPhys; rmd->rbuf_hadr = (pPhys >> 16) & lnrmd1_HADR; } else pMbuf = bcopy_to_mbufs (pData, len, 0, &pDrvCtrl->idr.ac_if, pDrvCtrl->memWidth); if (pMbuf != NULL) do_protocol (pEnetHdr, pMbuf, &pDrvCtrl->idr, len);#endif /* BSD43_DRIVER */ ++pDrvCtrl->idr.ac_if.if_ipackets; /* bump statistic */ } /* Done with descriptor, clean up and give it to the device. */cleanRXD: rmd->rbuf_mcnt = 0; /* reset count */ rmd->rbuf_stat &= 0xff; /* reset status bits */ rmd->rbuf_stat |= lnrmd1_OWN; /* give device ownership */ CACHE_PIPE_FLUSH (); /* flush the write pipe */ /* advance our management index */ pDrvCtrl->rmdIndex = (pDrvCtrl->rmdIndex + 1) & (pDrvCtrl->rringSize - 1); return (OK); }#ifdef BSD43_DRIVER/********************************************************************************* lnOutput - the driver output routine**/LOCAL int lnOutput ( IDR *pIDR, MBUF *pMbuf, SOCK *pDest ) { DRV_CTRL *pDrvCtrl; char destEnetAddr [6]; /* space for enet addr */ u_short packetType; /* type field for the packet */ ln_tmd *tmd; char *buf; int len; /* check ifnet flags - return error if incorrect. */ if ((pIDR->ac_if.if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) return (ENETDOWN); /* * Attempt to convert socket addr into enet addr and packet type. * Note that if ARP resolution of the address is required, the ARP * module will call our routine again to transmit the ARP request * packet. This means we may actually call ourselves recursively! */ if (convertDestAddr (pIDR,pDest, destEnetAddr, &packetType, pMbuf) == FALSE) return (OK); /* I KNOW returning OK is stupid, but it is correct */ /* get driver control pointer */ pDrvCtrl = & drvCtrl [pIDR->ac_if.if_unit]; /* * Obtain exclusive access to transmitter. This is necessary because * certain events can cause netTask to run a job that attempts to transmit * a packet. We can only allow one task here at a time. */ semTake (pDrvCtrl->TxSem, WAIT_FOREVER); tmd = pDrvCtrl->tring + pDrvCtrl->tmdIndex; LN_CACHE_INVALIDATE (tmd, TMD_SIZ); if ((tmd->tbuf_stat & lntmd1_OWN) || (((pDrvCtrl->tmdIndex + 1) & (pDrvCtrl->tringSize - 1)) == pDrvCtrl->tmdIndexC)) { m_freem (pMbuf); /* discard data */ pDrvCtrl->idr.ac_if.if_oerrors++; /* output error */ goto outputDone; } buf = pDrvCtrl->tBufBase + (pDrvCtrl->tmdIndex * LN_BUFSIZ); bcopy_from_mbufs ((buf + SIZEOF_ETHERHEADER), pMbuf, len, pDrvCtrl->memWidth); bcopy (destEnetAddr, buf, 6); bcopy ((char *) pIDR->ac_enaddr, (buf + 6), 6); ((ETH_HDR *) buf)->ether_type = packetType; len += SIZEOF_ETHERHEADER; len = max (ETHERSMALL, len); if ((etherOutputHookRtn != NULL) && (* etherOutputHookRtn) (&pDrvCtrl->idr.ac_if,buf,len)) { CACHE_PIPE_FLUSH (); /* done as a safety */ goto outputDone; /* goto the end */ } tmd->tbuf_bcnt = -len; tmd->tbuf_err = 0; /* advance our management index */ pDrvCtrl->tmdIndex = (pDrvCtrl->tmdIndex + 1) & (pDrvCtrl->tringSize - 1); tmd->tbuf_stat |= lntmd1_OWN | lntmd1_STP | lntmd1_ENP; tmd->tbuf_stat &= ~lntmd1_DEF & ~lntmd1_MORE & ~lntmd1_ERR; CACHE_PIPE_FLUSH (); /* flush the write pipe */ /* kick start the transmitter, if selected */ if (lnKickStartTx) lnCsr0Write (pDrvCtrl, (lncsr_INEA | lncsr_TDMD)); pIDR->ac_if.if_opackets++; /* bump the statistic counter. */outputDone: semGive (pDrvCtrl->TxSem); /* release exclusive access. */ return (OK); }#else /* BSD43_DRIVER *//********************************************************************************* lnStartOutput - the driver output routine**/LOCAL void lnStartOutput ( DRV_CTRL * pDrvCtrl /* pointer to driver control structure */ ) { struct mbuf * pMbuf = NULL; ln_tmd * tmd; char * buf; int len; while (pDrvCtrl->idr.ac_if.if_snd.ifq_head) { /* dequeue a packet from the transmit queue */ IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf); tmd = pDrvCtrl->tring + pDrvCtrl->tmdIndex; LN_CACHE_INVALIDATE (tmd, TMD_SIZ); if ((tmd->tbuf_stat & lntmd1_OWN) || (((pDrvCtrl->tmdIndex + 1) & (pDrvCtrl->tringSize - 1)) == pDrvCtrl->tmdIndexC)) { pDrvCtrl->idr.ac_if.if_oerrors++; /* output error */ if (pMbuf != NULL) m_freem (pMbuf); /* drop the packet */ break; } buf = pDrvCtrl->tBufBase + (pDrvCtrl->tmdIndex * LN_BUFSIZ);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -