📄 if_lnisa.c
字号:
printf ("Lance Error during initialization:\t0x%x\n", stat); } } /* log chip initialization failure */ if ( (stat & CSR0_ERR) || (timeoutCount >= 0x10000) ) { printf ("lnIsa%d: Device initialization failed\n", pDrvCtrl->idr.ac_if.if_unit); return (ERROR); } /* Device is initialized. Start transmitter and receiver. The device * RAP register is left selecting CSR 0. */ lnCsrWrite(pDrvCtrl, 0, CSR0_IDON | CSR0_IENA | CSR0_STRT); } sysIntEnablePIC (ilevel); /* enable LANCE interrupts */ pDrvCtrl->idr.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_NOTRAILERS); } /* Block end; device initialization */ /* Set our flag */ pDrvCtrl->attached = TRUE; return (OK);}/********************************************************************************* lnReset - reset the interface** Mark interface as inactive & reset the chip*/static void lnReset ( int unit ) { DRV_CTRL *pDrvCtrl = & drvCtrl [unit]; pDrvCtrl->idr.ac_if.if_flags = 0; lnChipReset (pDrvCtrl); /* reset LANCE */ }/********************************************************************************* lnInt - handle controller interrupt** This routine is called at interrupt level in response to an interrupt from* the controller.*/static void lnInt ( DRV_CTRL *pDrvCtrl ) { ln_tmd *tmd; int *pDindex; int *pTindex; int *pTsize; ln_tmd *pTring; USHORT stat; /* Read the device status register */ stat = lnCsrRead (pDrvCtrl, 0); /* If false interrupt, return. */ if ( ! (stat & CSR0_INTR) ) return; /* * enable interrupts, clear receive and/or transmit interrupts, and clear * any errors that may be set. */ lnCsrWrite (pDrvCtrl, 0, ((stat & (CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR| CSR0_RINT|CSR0_TINT|CSR0_IDON)) | CSR0_IENA)); /* Check for errors */ if (stat & (CSR0_BABL | CSR0_MISS | CSR0_MERR)) { ++pDrvCtrl->idr.ac_if.if_ierrors; /* restart chip on fatal error */ if (stat & CSR0_MERR) /* memory error */ { pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); (void) netJobAdd ( (FUNCPTR)lnRestart, pDrvCtrl->idr.ac_if.if_unit, 1,(int)stat,0,0 ); } } /* Have netTask handle any input packets */ if ((stat & CSR0_RINT) && (stat & CSR0_RXON)) { if ( ! (pDrvCtrl->flags & LS_RCV_HANDLING_FLAG) ) { pDrvCtrl->flags |= LS_RCV_HANDLING_FLAG; (void) netJobAdd ( (FUNCPTR)lnHandleRecvInt, (int)pDrvCtrl, 0,0,0,0 ); } } /* * Did LANCE update any of the TMD's? * If not then don't bother continuing with transmitter stuff */ if (!(stat & CSR0_TINT)) return; pDindex = &pDrvCtrl->dindex; pTindex = &pDrvCtrl->tindex; pTsize = &pDrvCtrl->tsize; pTring = pDrvCtrl->tring; while (*pDindex != *pTindex) { /* disposal has not caught up */ tmd = pTring + *pDindex; /* if the buffer is still owned by LANCE, don't touch it */ LN_CACHE_INVALIDATE (tmd, TMD_SIZ); if (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 ((tmd->tbuf_tmd1 & TMD1_ERR) || (tmd->tbuf_tmd3 & TMD3_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_tmd3 & TMD3_RTRY) pDrvCtrl->idr.ac_if.if_collisions++; /* check for no carrier */ if (tmd->tbuf_tmd3 & TMD3_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 ((tmd->tbuf_tmd3 & TMD3_BUFF) || (tmd->tbuf_tmd3 & TMD3_UFLO)) { pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); (void) netJobAdd ( (FUNCPTR)lnRestart, pDrvCtrl->idr.ac_if.if_unit, 2,(int)(tmd->tbuf_tmd3),0,0 ); return; } } tmd->tbuf_tmd1 &= 0x00ff; /* clear status/err bits, keep hadr bits */ tmd->tbuf_tmd3 = 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 ((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 ) { ENET_HDR *pEnetHdr; MBUF *pMbuf; u_char *pData; int len; u_short ether_type; BOOL hookAte; /* Packet must be checked for errors. */ if ( /* If error flag */ (rmd->rbuf_rmd1 & (RMD1_ERR | RMD1_FRAM)) || /* OR if packet is not completely in one buffer */ ( (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 */ } ++pDrvCtrl->idr.ac_if.if_ipackets; /* bump statistic */ len = rmd->rbuf_mcnt & RMD3_MCNT_MSK; /* get packet length */ /* Get pointer to packet */ pEnetHdr = (ENET_HDR *) (pDrvCtrl->rmd_ring.r_bufs + (pDrvCtrl->rindex * LN_BUFSIZ)); LN_CACHE_INVALIDATE (pEnetHdr, len); /* make the packet data coherent */ /* 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->type ); /* 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); } /* Done with descriptor, clean up and give it to the device. */ cleanRXD: /* clear status bits */ rmd->rbuf_rmd1 &= 0x00ff; /* clear status/err bits, keep address */ rmd->rbuf_mcnt = 0; /* reset count */ rmd->rbuf_rmd1 |= RMD1_OWN; /* give device ownership */ /* Flush the write pipe */ CACHE_PIPE_FLUSH (); /* Advance our management index */ pDrvCtrl->rindex = (pDrvCtrl->rindex + 1) & (pDrvCtrl->rsize - 1); return (OK); }/********************************************************************************* 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; BOOL hookAte; /* 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 (((tmd->tbuf_tmd1 & TMD1_OWN) != 0) || (((pDrvCtrl->tindex + 1) & (pDrvCtrl->tsize - 1)) == pDrvCtrl->dindex)) { m_freem (pMbuf); /* Discard data */ 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -