📄 if_lnpci.c
字号:
/* if the buffer is still owned by LANCE, don't touch it */ LN_CACHE_INVALIDATE (tmd, TMD_SIZ); if (PCISWAP(tmd->tbuf_tmd1) & TMD1_OWN) break; /* * tbuf_err (TMD1.ERR) is an "OR" of LCOL, LCAR, UFLO or RTRY. * Note that BUFF is not indicated in TMD1.ERR. * We should therefore check both tbuf_err and tbuf_buff * here for error conditions. */ if ((PCISWAP(tmd->tbuf_tmd1) & TMD1_ERR) || (PCISWAP(tmd->tbuf_tmd2) & TMD2_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 (PCISWAP(tmd->tbuf_tmd2) & TMD2_RTRY) pDrvCtrl->idr.ac_if.if_collisions++; /* check for no carrier */ if (PCISWAP(tmd->tbuf_tmd2) & TMD2_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 * implementation 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 ((PCISWAP(tmd->tbuf_tmd2) & TMD2_BUFF) || (PCISWAP(tmd->tbuf_tmd2) & TMD2_UFLO)) { pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); (void) netJobAdd ( (FUNCPTR)lnRestart, pDrvCtrl->idr.ac_if.if_unit, 0,0,0,0 ); return; } } tmd->tbuf_tmd1 = 0; /* clear tmd1 */ tmd->tbuf_tmd2 = 0; /* clear all error & stat stuff */ /* now bump the tmd disposal index pointer around the ring */ *pDindex = (*pDindex + 1) & (*pTsize - 1); } /* Flush the write pipe */ CACHE_PIPE_FLUSH (); }/********************************************************************************* 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.*/static void lnHandleRecvInt ( DRV_CTRL *pDrvCtrl ) { ln_rmd *rmd; do { pDrvCtrl->flags |= LS_RCV_HANDLING_FLAG; while ((rmd = lnGetFullRMD (pDrvCtrl)) != NULL) lnRecv (pDrvCtrl, rmd); /* * 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 &= ~LS_RCV_HANDLING_FLAG; } while (lnGetFullRMD (pDrvCtrl) != NULL); /* this double check solves the RACE */ }/********************************************************************************* lnGetFullRMD - get next received message RMD** Returns ptr to next Rx desc to process, or NULL if none ready.*/static ln_rmd *lnGetFullRMD ( DRV_CTRL *pDrvCtrl ) { ln_rmd *rmd; /* Refuse to do anything if flags are down */ if ( (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING) ) != (IFF_UP | IFF_RUNNING) ) return ((ln_rmd *) NULL); rmd = pDrvCtrl->rring + pDrvCtrl->rindex; /* form ptr to Rx desc */ LN_CACHE_INVALIDATE (rmd, RMD_SIZ); if ((PCISWAP(rmd->rbuf_rmd1) & RMD1_OWN) == 0) return (rmd); else return ((ln_rmd *) NULL); }/********************************************************************************* lnRecv - process the next incoming packet**/static STATUS lnRecv ( DRV_CTRL *pDrvCtrl, ln_rmd *rmd ) { struct ether_header * pEnetHdr; MBUF *pMbuf; u_char *pData; int len; u_short ether_type; BOOL hookAte; /* Packet must be checked for errors. */ if ( /* If error flag */ (PCISWAP(rmd->rbuf_rmd1) & (RMD1_ERR | RMD1_FRAM)) || /* OR if packet is not completely in one buffer */ ( (PCISWAP(rmd->rbuf_rmd1) & (RMD1_STP | RMD1_ENP) ) != (RMD1_STP | RMD1_ENP) ) ) { ++pDrvCtrl->idr.ac_if.if_ierrors; /* bump error stat */ goto cleanRXD; /* skip to clean up */ } len = PCISWAP(rmd->rbuf_mcnt) & RMD2_MCNT_MSK; /* get packet length */ /* Get pointer to packet */ pEnetHdr = (struct ether_header *) (pDrvCtrl->rmd_ring.r_bufs + (pDrvCtrl->rindex * LN_BUFSIZ)); LN_CACHE_INVALIDATE (pEnetHdr, len); /* make the packet data coherent */ ++pDrvCtrl->idr.ac_if.if_ipackets; /* bump statistic */ /* call input hook if any */ hookAte = FALSE; if (etherInputHookRtn != NULL) { if ( (* etherInputHookRtn) (&pDrvCtrl->idr.ac_if, (char *)pEnetHdr, len) ) hookAte = TRUE; } /* Normal path; send packet upstairs */ if (hookAte == FALSE) { /* Adjust length to size of data only */ len -= ENET_HDR_REAL_SIZ; /* Get pointer to packet data */ pData = ((u_char *) pEnetHdr) + ENET_HDR_REAL_SIZ; ether_type = ntohs ( pEnetHdr->ether_type );#ifdef BSD43_DRIVER /* Copy packet data into MBUFs, using the specified width */ pMbuf = bcopy_to_mbufs (pData, len, 0, (IFNET *) & pDrvCtrl->idr.ac_if, pDrvCtrl->memWidth); if (pMbuf != NULL) do_protocol_with_type (ether_type, pMbuf, & pDrvCtrl->idr, len); else ++pDrvCtrl->idr.ac_if.if_ierrors; /* bump error statistic */#else pMbuf = bcopy_to_mbufs (pData, len, 0, &pDrvCtrl->idr.ac_if, pDrvCtrl->memWidth); if (pMbuf != NULL) do_protocol (pEnetHdr, pMbuf, &pDrvCtrl->idr, len); else ++pDrvCtrl->idr.ac_if.if_ierrors; /* bump error statistic */#endif } /* Done with descriptor, clean up and give it to the device. */ cleanRXD: /* reset statistics counters and message byte count */ rmd->rbuf_mcnt = 0; /* reset status bits, reinitialize buffer size, and give device ownership */ rmd->rbuf_rmd1 = PCISWAP((RMD1_BCNT_MSK & - (pDrvCtrl->bufSize)) | RMD1_CNST | RMD1_OWN); /* Flush the write pipe */ CACHE_PIPE_FLUSH (); /* Advance our management index */ pDrvCtrl->rindex = (pDrvCtrl->rindex + 1) & (pDrvCtrl->rsize - 1); return (OK); }#ifdef BSD43_DRIVER/********************************************************************************* lnOutput - the driver output routine**/static int lnOutput ( IDR *pIDR, MBUF *pMbuf, SOCK *pDest ) { char destEnetAddr [6]; /* space for enet addr */ u_short packetType; /* type field for the packet */ DRV_CTRL *pDrvCtrl; ln_tmd *tmd; char *buf; int len; int oldLevel; /* 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); pDrvCtrl->flags |= LS_START_OUTPUT_FLAG; /* See if next TXD is available */ tmd = pDrvCtrl->tring + pDrvCtrl->tindex; LN_CACHE_INVALIDATE (tmd, TMD_SIZ); if ( ((PCISWAP(tmd->tbuf_tmd1) & TMD1_OWN) != 0) || ( ((pDrvCtrl->tindex + 1) & (pDrvCtrl->tsize - 1)) == pDrvCtrl->dindex ) ) { m_freem (pMbuf); /* Discard data */ pIDR->ac_if.if_oerrors++; goto outputDone; } /* Get pointer to transmit buffer */ buf = (char *) (pDrvCtrl->tmd_ring.t_bufs + (pDrvCtrl->tindex * LN_BUFSIZ)); /* Fill in the Ethernet header */ bcopy (destEnetAddr, buf, 6); bcopy ( (char *) pIDR->ac_enaddr, (buf + 6), 6); ((ENET_HDR *)buf)->type = htons (packetType); /* Copy packet from MBUFs to our transmit buffer. MBUFs are * transparently freed. */ bcopy_from_mbufs ( (buf + ENET_HDR_REAL_SIZ), pMbuf, len, /* stuffed by macro */ pDrvCtrl->memWidth ); /* Ensure we send a legal size frame. */ len += ENET_HDR_REAL_SIZ; len = max (ETHERSMALL, len); /* place a transmit request */ oldLevel = intLock (); /* disable ints during update */ tmd->tbuf_tmd3 = 0; /* clear buffer error status */ /* negative message byte count */ tmd->tbuf_tmd1 &= PCISWAP(~TMD1_BCNT_MSK); tmd->tbuf_tmd1 |= PCISWAP((TMD1_CNST | TMD1_BCNT_MSK) & -len); tmd->tbuf_tmd1 |= PCISWAP(TMD1_ENP); /* buffer is end of packet */ tmd->tbuf_tmd1 |= PCISWAP(TMD1_STP); /* buffer is start of packet */ tmd->tbuf_tmd1 &= PCISWAP(~TMD1_DEF); /* clear status bit */ tmd->tbuf_tmd1 &= PCISWAP(~TMD1_MORE); tmd->tbuf_tmd1 &= PCISWAP(~TMD1_ERR); tmd->tbuf_tmd1 |= PCISWAP(TMD1_OWN); /* Flush the write pipe */ CACHE_PIPE_FLUSH (); intUnlock (oldLevel); /* now lnInt won't get confused */ /* Advance our management index */ pDrvCtrl->tindex = (pDrvCtrl->tindex + 1) & (pDrvCtrl->tsize - 1); /* kick start the transmitter, if selected */ if (lnKickStartTx) lnCsrWrite (pDrvCtrl, 0, (CSR0_INEA | CSR0_TDMD)); pDrvCtrl->flags &= ~LS_START_OUTPUT_FLAG; /* Bump the statistic counter. */ pIDR->ac_if.if_opackets++; outputDone: /* Release exclusive access. */ semGive (pDrvCtrl->TxSem); return (OK); }#else /* BSD43_DRIVER *//********************************************************************************* lnPciStartOutput - the driver output routine**/LOCAL void lnPciStartOutput ( DRV_CTRL * pDrvCtrl /* pointer to driver control structure */ ) { struct mbuf * pMbuf; ln_tmd *tmd; char *buf; int len; int oldLevel; pDrvCtrl->flags |= LS_START_OUTPUT_FLAG; /* ??? */ /* See if next TXD is available */ 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -