📄 if_nic.c
字号:
pDrvCtrl->idr.ac_if.if_oerrors++; } /* handle packet received */ if ((isr & PRX) && (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) && (!pDrvCtrl->taskRcvActive)) { pDrvCtrl->taskRcvActive = TRUE; /* set flag */ /* defer to netTask */ netJobAdd ((FUNCPTR) nicHandleInt, (int) pDrvCtrl, 0, 0, 0, 0); } /* handle packet transmitted */ if ((isr & PTX) && (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) && /* copy ptr, safety check it */ ((pTxDesc = (TX_DESC *) pDrvCtrl->pTxActive) != NULL)) { tsr = pNic->Tsr; /* read Tx status reg */ pTxDesc->ready = FALSE; /* active pkt completed */ if (pTxDesc->next->ready) /* if next pkt ready to go */ { pTxDesc = pTxDesc->next; /* use next desc */ pDrvCtrl->pTxActive = pTxDesc; /* update active ptr */ pNic->Tpsr = pTxDesc->addr >> 8; pNic->Tbcr0 = pTxDesc->len & 0xff; pNic->Tbcr1 = pTxDesc->len >> 8; /* Start NIC transmitting. Note that since we could be doing * a NIC remote DMA transfer at this time, we must maintain the * state of these bits. */ pNic->Cr = TXP | (pNic->Cr & (RREAD | RWRITE)); } else pDrvCtrl->pTxActive = NULL; /* transmitter idle */ if (tsr & COL) /* collision */ pDrvCtrl->idr.ac_if.if_collisions++; } /* handle DMA complete */ if (isr & RDC) pDrvCtrl->dmaWait = FALSE; /* clr the waiting flag */ }/********************************************************************************* nicRestart - restart the device after fatal error*/LOCAL void nicRestart ( int unit ) { int temp; int loopy; DRV_CTRL *pDrvCtrl; NIC_DEVICE *pNic; /* address of device */ pDrvCtrl = & drvCtrl [unit]; pNic = pDrvCtrl->nicAddr; /* The device has all interrupts disabled and the interface flags are down. * Our job is to reset the device and our dynamic driver variables, * bring the device back to life, and put the interface online. */ temp = RESET_ON; /* Issue a hardware reset */ temp = RESET_OFF; /* release the reset */ /* Wait for device reset indication */ while ( ! (pNic->Isr & RST) ) ; pNic->Cr = RPAGE0 | STP; /* select page 0 and stop */ pNic->Dcr = NOTLS | FIFO8; pNic->Rbcr0 = 0; /* clear remote DMA byte count registers */ pNic->Rbcr1 = 0; for (loopy = 0; loopy < MAXXMT; loopy++) pDrvCtrl->txDesc[loopy].ready = FALSE; pDrvCtrl->pTxNext = pDrvCtrl->txDesc; /* reset "next Tx" ptr */ pDrvCtrl->pTxActive = NULL; /* no active Tx desc */ pDrvCtrl->taskRcvActive = FALSE; /* reset flag */ pDrvCtrl->NextPkt = CURR; /* reset to initial value */ pNic->Rcr = AB; /* accept broadcast, but not runt or multicast */ pNic->Tcr = MODE1; /* internal loopback mode */ pNic->Pstart = PSTART; pNic->Pstop = PSTOP; pNic->Bnry = BNRY; pNic->Cr = RPAGE1; /* map in page 1 */ pNic->Par0 = pDrvCtrl->idr.ac_enaddr [0]; pNic->Par1 = pDrvCtrl->idr.ac_enaddr [1]; pNic->Par2 = pDrvCtrl->idr.ac_enaddr [2]; pNic->Par3 = pDrvCtrl->idr.ac_enaddr [3]; pNic->Par4 = pDrvCtrl->idr.ac_enaddr [4]; pNic->Par5 = pDrvCtrl->idr.ac_enaddr [5]; pNic->nic_pg1.mar0 = 0xff; pNic->nic_pg1.mar1 = 0xff; pNic->nic_pg1.mar2 = 0xff; pNic->nic_pg1.mar3 = 0xff; pNic->nic_pg1.mar4 = 0xff; pNic->nic_pg1.mar5 = 0xff; pNic->nic_pg1.mar6 = 0xff; pNic->nic_pg1.mar7 = 0xff; pNic->Curr = CURR; pNic->Cr = RPAGE0; /* back to page 0 */ pNic->Tcr = MODE0; /* put Tx into normal mode */ pNic->Cr = STA; /* start the beast running */ pNic->Isr = 0xff; /* clr any pending ints */ pNic->Imr = PRXE|PTXE|TXEE|OVWE|RDCE; /* enable these ints */ /* Raise the interface flags */ pDrvCtrl->idr.ac_if.if_flags |= IFF_UP | IFF_RUNNING | IFF_NOTRAILERS; }/********************************************************************************* nicHandleInt - defered recv 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.*/LOCAL void nicHandleInt ( DRV_CTRL *pDrvCtrl ) { do { pDrvCtrl->taskRcvActive = TRUE; while (nicRead (pDrvCtrl)) /* process a received frame */ ; pDrvCtrl->taskRcvActive = FALSE; } while (nicRead (pDrvCtrl)); }/********************************************************************************* nicRead - read a packet off the interface** nicRead copies packets from local memory into an mbuf and hands it to* the next higher layer.*/LOCAL BOOL nicRead ( DRV_CTRL *pDrvCtrl ) { MBUF *m; NIC_DEVICE *pNic; /* ptr to the NIC registers */ RX_FRAME *pRxFrame; /* ptr to our frame storage */ ETH_HDR *eh; /* ptr to enet hdr */ u_int len; /* length of the enet pkt */ u_short curr; /* current page NIC using */ int oldLevel; if (!(pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING))) return (FALSE); pNic = pDrvCtrl->nicAddr; pRxFrame = &pDrvCtrl->rxFrame; eh = &pRxFrame->enetHdr; /* * See if any unprocessed frames in NIC buffer. Unfortunately, there * is no reliable way of doing this other than reading the CURR register. * The NIC designers, in their infinite wisdom, put this register in * page 1. To access page 1, we need to temporarily disable our interrupt * handler. */ oldLevel = intLock (); pNic->Cr = RPAGE1; /* select page 1 */ curr = pNic->Curr; /* get current page */ pNic->Cr = RPAGE0; /* restore page 0 */ intUnlock (oldLevel); if (pDrvCtrl->NextPkt == curr) /* if NIC has not moved ahead */ return (FALSE); pDrvCtrl->idr.ac_if.if_ipackets++; /* * 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. */ while ( pktBufRead ( pDrvCtrl, pDrvCtrl->NextPkt << 8, RX_HDR_SIZ, (char *) pRxFrame ) == ERROR ) ; len = pRxFrame->rxHdr.cntL + (pRxFrame->rxHdr.cntH << 8) - 4 /* FCS */;#if 0 /* valid frame checks, for paranoia */ if ( ((pRxFrame->rxHdr.status & ~PHY) != PRX) || (pRxFrame->rxHdr.nextRxPage < PSTART) || (pRxFrame->rxHdr.nextRxPage >= PSTOP) || (len < 60) || (len > 1514) ) return (FALSE);#endif /* copy Ethernet packet section of the frame */ while ( pktBufRead ( pDrvCtrl, (pDrvCtrl->NextPkt << 8) + RX_HDR_SIZ, len, (char *) eh ) == ERROR ) ; /* done with frame in NIC buf, so update vars */ pDrvCtrl->NextPkt = pRxFrame->rxHdr.nextRxPage;/* where dev will use next */ pNic->Bnry = (pDrvCtrl->NextPkt == PSTART) ? /* if dev is at beginning */ (PSTOP - 1) : /* boundary is 1 before end */ (pDrvCtrl->NextPkt - 1); /* else it's 1 before next */ /* call input hook if any */ if (etherInputHookRtn != NULL) if ( (* etherInputHookRtn) (&pDrvCtrl->idr.ac_if, (char *)eh, len)) return (TRUE); len -= sizeof (ETH_HDR); /* now equals length of data only */ m = copy_to_mbufs ( pRxFrame->data, len, 0, (IFNET *) & pDrvCtrl->idr.ac_if ); if (m != NULL)#ifdef BSD43_DRIVER do_protocol_with_type (eh->ether_type, m, &pDrvCtrl->idr, len);#else do_protocol (eh, m, &pDrvCtrl->idr, len);#endif else pDrvCtrl->idr.ac_if.if_ierrors++; return (TRUE); }#ifdef BSD43_DRIVER/********************************************************************************* nicOutput - the driver's output routine** This function attempts to copy the data from the mbuf chain to the buffer* that NIC transmits from. If successfull, and the NIC is not currently busy* transmitting, it then attempts to start the NIC transmitting.*/LOCAL int nicOutput ( IDR *pIDR, MBUF *pMbuf, SOCK *pDest ) { int unit; int oldLevel; u_long nicBufAddr; MBUF *pTempMbuf; DRV_CTRL *pDrvCtrl; NIC_DEVICE *pNic; TX_DESC *pTxNext; /* ptr to next desc to use */ ETH_HDR enetHdr; /* space for the packet header */ /* init ptrs */ unit = pIDR->ac_if.if_unit; pDrvCtrl = & drvCtrl [unit]; pNic = pDrvCtrl->nicAddr; /* copy it, due to frequent use */ /* Check ifnet flags. Return error if incorrect. */ if ( (pIDR->ac_if.if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING) ) { m_freem (pMbuf); /* release MBUFs */ 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, &enetHdr.ether_dhost, /* fill our local header */ &enetHdr.ether_type, /* fill our local header */ pMbuf ) == FALSE ) return (OK); /* Get next transmit resource */ pTxNext = pDrvCtrl->pTxNext; /* copy it, due to frequent use */ if (pTxNext->ready) /* if still in use */ { m_freem (pMbuf); /* release MBUFs */ return (ENETDOWN); } /* Fill in the source address of the Ethernet header */ bcopy ( (char *) pIDR->ac_enaddr, &enetHdr.ether_shost, 6 ); /* copy Ethernet header to NIC buffer */ nicBufAddr = pTxNext->addr; while ( pktBufWrite ( pDrvCtrl, nicBufAddr, ENET_HDR_REAL_SIZ, (char *) & enetHdr ) == ERROR ) ; /* copy mbufs to NIC buffer */ pTempMbuf = pMbuf; /* copy head of MBUF chain */ for ( nicBufAddr += (u_long) ENET_HDR_REAL_SIZ; pTempMbuf != NULL; nicBufAddr += (u_long) pTempMbuf->m_len, pTempMbuf = pTempMbuf->m_next) { while ( pktBufWrite ( pDrvCtrl, nicBufAddr, pTempMbuf->m_len, mtod (pTempMbuf, caddr_t) ) == ERROR ) ; } pTxNext->len = max (MINPKTSIZE, (nicBufAddr - pTxNext->addr)); m_freem (pMbuf); /* free the mbufs */ oldLevel = intLock (); /* keep our int handler out */ pTxNext->ready = TRUE; /* mark packet as "ready" */ if (pDrvCtrl->pTxActive == NULL) /* if transmitter not active */ { pDrvCtrl->pTxActive = pTxNext; /* set active ptr */ pNic->Tpsr = pTxNext->addr >> 8; pNic->Tbcr0 = pTxNext->len & 0xff; pNic->Tbcr1 = pTxNext->len >> 8; pNic->Cr = TXP; /* start NIC transmitting */ } pDrvCtrl->pTxNext = pTxNext->next; /* move ptr to next desc */ intUnlock (oldLevel); /* allow interrupts again */ /* Bump packet counter */ pIDR->ac_if.if_opackets++; return (0); }#else/********************************************************************************* nicTxStartup - the driver's output routine** This function attempts to copy the data from the mbuf chain to the buffer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -