📄 if_med.c
字号:
* configuration enables the NIC onto an active network.*/LOCAL void medConfigNIC ( int unit ) { struct med_softc *es = med_softc [unit]; NIC_DEVICE *pNIC = es->nicAddr; /* get Ethernet address from ROM */ medEthAddrGet (unit); /* stop/abort all NIC operations */ pNIC->Cr = RPAGE0 | STP | ABORT; pNIC->Dcr = FT2 | BMS | BOS | WTS; /* clear remote DMA byte count registers */ pNIC->Rbcr0 = 0; pNIC->Rbcr1 = 0; /* accept broadcast, but not runt and multicast packets */ pNIC->Rcr = AB; /* configure for internal loopback mode */ pNIC->Tcr = MODE1; /* initialize receive buffer pointers */ pNIC->Bnry = BNRY; pNIC->Pstart = PSTART; pNIC->Pstop = PSTOP; /* clear the interrupt status */ pNIC->Isr = RST | RDC | CNT | OVW | TXE | RXE | PTX | PRX; /* enable selected interrupts */ pNIC->Imr = NIC_INTERRUPTS_HANDLED; /* select NIC page 1 registers */ pNIC->Cr = RPAGE1 | STP | ABORT; /* initialize the physical address, e.g. the Ethernet address */ pNIC->Par0 = es->es_enaddr [0]; pNIC->Par1 = es->es_enaddr [1]; pNIC->Par2 = es->es_enaddr [2]; pNIC->Par3 = es->es_enaddr [3]; pNIC->Par4 = es->es_enaddr [4]; pNIC->Par5 = es->es_enaddr [5]; /* * Initialize the multicast address registers. * CURRENTLY NOT SUPPORTED */ /* initialize the next packet receive buffer pointer */ pNIC->Curr = CURR; /* start NIC */ pNIC->Cr = RPAGE0 | STA | ABORT; /* enable packet transmission */ pNIC->Tcr = nic_NORMAL_XMIT_CTRL; }#ifdef BSD43_DRIVER/********************************************************************************* medOutput -** Ethernet output routine.* Encapsulate a packet of type family for the local net.* Use trailer local net encapsulation if enough data in first* packet leaves a multiple of 512 bytes of data in remainder.*/LOCAL int medOutput ( FAST struct ifnet *ifp, FAST struct mbuf *m0, struct sockaddr *dst ) { return (ether_output (ifp, m0, dst, (FUNCPTR) medStartOutput, &med_softc [ifp->if_unit]->es_ac)); }#endif/********************************************************************************* medStartOutput - start pending output** Start output to NIC.* Queue up all pending datagrams for which transmit buffers are available.* It is very important that this routine be executed with splimp set.* If this is not done, another task could allocate the same transmit buffer.*/#ifdef BSD43_DRIVERLOCAL void medStartOutput ( int unit ) { FAST struct med_softc * es = med_softc [unit];#elseLOCAL void medStartOutput ( struct med_softc * es ) {#endif FAST struct mbuf *m; FAST char *buf; int len; FAST xmitBCB_s *pXmitBCB; int s = splimp (); FAST xmitQCB_s * pXmitQCB = &(es->xmitQCB); FAST XBIdx_t headPkt = pXmitQCB->head; while (es->es_if.if_snd.ifq_head != NULL) { /* there is something to send */ if ((pXmitBCB = medXmitBfrAlloc (es)) == (xmitBCB_s *) NULL) { med_Stats.noXmitBfrs++; es->es_if.if_oerrors++; break; /* no transmit buffers available */ } buf = pXmitBCB->pPktBfr; /* get message to send */ IF_DEQUEUE (&es->es_if.if_snd, m); /* get head of next mbuf chain */ copy_from_mbufs (buf, m, len); len = max (ETHERSMALL, len); pXmitBCB->pktLen = (u_short)len; pXmitBCB->bPktRdy = TRUE; /* call output hook if any */ if (etherOutputHookRtn != NULL && (* etherOutputHookRtn) (&es->es_if, buf, len)) continue; if (medXmtrLock (&(pXmitQCB->lockNIC_Xmtr)) != ERROR) { /* * Start transmission of the next packet on the xmitQ * unless the transmit interrupt handler has already * transmitted it. * * Lock mechanism pXmitQCB->lockNIC_Xmtr is unlocked by * the transmit interrupt handler when all packets on * the xmitQ have been transmitted. */ if (pXmitQCB->xmitBCB [headPkt].bPktRdy) { if (medXmitPacket (es, pXmitQCB->xmitBCB [headPkt].pPktBfr, pXmitQCB->xmitBCB [headPkt].pktLen) == ERROR) { logMsg ("med%d: ERROR - NIC transmitter active, should \ be off.\n", es->es_if.if_unit, 0, 0, 0, 0, 0); } } else medXmtrUnlock (&(pXmitQCB->lockNIC_Xmtr)); } /* opackets statistic is incremented elsewhere after interrupt */ } splx (s); }/********************************************************************************* medXmitBfrAlloc - allocate a NIC transmit buffer** RETURNS: address of the NIC transmit buffer or NULL if none available*/LOCAL xmitBCB_s *medXmitBfrAlloc ( struct med_softc *es ) { FAST xmitQCB_s *pXmitQCB = &(es->xmitQCB); FAST xmitBCB_s *pTailXBCB; int oldLevel; if (pXmitQCB->bFull) return (xmitBCB_s *)NULL; /* block interrupt service routine access to xmitQCB */ oldLevel = intLock(); pXmitQCB->bEmpty = FALSE; pTailXBCB = &(pXmitQCB->xmitBCB [pXmitQCB->tail]); pXmitQCB->tail = pTailXBCB->next; if (pXmitQCB->head == pXmitQCB->tail) pXmitQCB->bFull = TRUE; intUnlock (oldLevel); return (pTailXBCB); }/********************************************************************************* medXmitPacket - NIC packet transmission** RETURNS: ERROR if NIC transmitter busy, otherwise OK*/LOCAL STATUS medXmitPacket ( struct med_softc *es, char *pPacket, u_short packetLen ) { NIC_DEVICE *pNIC = es->nicAddr;#if defined (med_SAVE_XMIT_PKTS) static char *pXmitPktSaveBfr = (char *) 0xffd10000; /* check for possible buffer overrun */ if (((u_long) pXmitPktSaveBfr + 1600) > 0xffd20000) pXmitPktSaveBfr = (char *) 0xffd10000; bcopy (pPacket, pXmitPktSaveBfr, (int) packetLen); pXmitPktSaveBfr = pXmitPktSaveBfr + packetLen; bcopy ("$$$$$$$$$$$$$$$$", pXmitPktSaveBfr, 16); pXmitPktSaveBfr = pXmitPktSaveBfr + 16;#endif /* med_SAVE_XMIT_PKTS */ if ((pNIC->Cr & TXP) == nic_XMTR_BUSY) return (ERROR); pNIC->Tpsr = nic_CPU_TO_NIC_ADRS (pPacket); pNIC->Tbcr1 = (u_char) (packetLen >> 8); pNIC->Tbcr0 = (u_char) packetLen; pNIC->Cr = STA | TXP | ABORT; return (OK); }/********************************************************************************* medStatsGet - output to stdout the med statictics** NOMANUAL*/void medStatsGet ( int unit ) { struct med_softc *es = med_softc [unit]; medReadTallyCntrs (es); printf("med Statistics:\n"); printf(" packets received : %ld\n", es->es_if.if_ipackets); printf(" input errors : %ld\n", es->es_if.if_ierrors); printf(" packets transmitted : %ld\n", es->es_if.if_opackets); printf(" output errors : %ld\n", es->es_if.if_oerrors); printf(" packets on send queue : %d\n", es->es_if.if_snd.ifq_len); printf(" packets dropped (not xmit) : %d\n", es->es_if.if_snd.ifq_drops); printf(" xmit bufs full, xmit delayed: %ld\n", med_Stats.noXmitBfrs); printf(" NIC total interrupts : %ld\n", med_Stats.intrCount); printf(" NIC PRX interrupts : %ld\n", med_Stats.PRX_intrCount); printf(" NIC PTX interrupts : %ld\n", med_Stats.PTX_intrCount); printf(" NIC RXE interrupts : %ld\n", med_Stats.RXE_intrCount); printf(" NIC TXE interrupts : %ld\n", med_Stats.TXE_intrCount); printf(" NIC OVW interrupts : %ld\n", med_Stats.OVW_intrCount); printf(" NIC CNT interrupts : %ld\n", med_Stats.CNT_intrCount); printf(" carrier lost on xmit : %ld\n", med_Stats.carrierLost); printf(" out of window collision : %ld\n", med_Stats.outOfWndColl); printf(" FIFO underrun : %ld\n", med_Stats.FIFO_UdrRun); printf(" excess collision : %ld\n", med_Stats.excessColl); printf(" frame alignment : %ld\n", med_Stats.frameAlign); printf(" CRC mismatch : %ld\n", med_Stats.misMatchCRC); printf(" missed packet : %ld\n", med_Stats.missedPkt); }/********************************************************************************* medReadTallyCntrs - update local counters from NIC tally counters**/LOCAL void medReadTallyCntrs ( FAST struct med_softc *es ) { NIC_DEVICE *pNIC = es->nicAddr; med_Stats.frameAlign += pNIC->FaeErr; med_Stats.misMatchCRC += pNIC->CrcErr; med_Stats.missedPkt += pNIC->MspErr; }/********************************************************************************* medMoveWrappedPacket - move a wrapped packet in the NIC receive buffer**/LOCAL void medMoveWrappedPacket ( FAST struct med_softc *es, /* for END_OF_RECV_BFR, NIC_RECV_BFR_ADRS */ FAST nic_RecvHdr_s *pRecvPacket, FAST u_long pktSize ) { FAST int byteCount; FAST char *pOvfRecvBfrMiddle; /* copy from start of packet to end of NIC receive buffer */ byteCount = (int) ((u_long) END_OF_RECV_BFR - (u_long) pRecvPacket); bcopy ((char *) pRecvPacket, (char *) (es->pOvfRecvBfr), byteCount); /* * Copy remainder of packet from the base address of the NIC * receive buffer to the current address in the buffer at * es->pOvfRecvBfr. */ pOvfRecvBfrMiddle = (char *) ((u_long) (es->pOvfRecvBfr) + (u_long) byteCount); byteCount = (int) pktSize - byteCount; bcopy ((char *) NIC_RECV_BFR_ADRS (0), pOvfRecvBfrMiddle, byteCount); }/********************************************************************************* medSetNIC_IMR - mask/unmask interrupts in the NIC Interrupt Mask Register** INTERNAL* This NIC Interrupt Mask Register (IMR) is essentially write-only.* The IMR in register page 2 cannot be accessed during normal* operation.*/LOCAL void medSetNIC_IMR ( FAST struct med_softc *es, FAST u_char unmaskBits, FAST u_char maskBits ) { FAST int oldLevel; FAST NIC_DEVICE *pNIC = es->nicAddr; FAST u_char currentIMR = es->currentIMR; oldLevel = intLock (); /* * This kludge is to ensure that the PRX and RXE interrupts are not * enabled (in task medRecvIntrHandler) after an OVW interrupt. */ if (es->bRecvBfrOvfl) unmaskBits &= ~(nic_PKT_RECV_NO_ERRORS | nic_PKT_RECV_ERROR); currentIMR = (currentIMR | unmaskBits) & (~maskBits); es->currentIMR = currentIMR; pNIC->Imr = currentIMR; intUnlock (oldLevel); }/********************************************************************************* medNIC_AwaitStop - busy-wait 2ms or until the NIC stops*/LOCAL void medNIC_AwaitStop ( FAST NIC_DEVICE *pNIC ) { FAST int ticksIn2ms; FAST ULONG tickStartCount = tickGet (); /* * Wait for NIC to complete current operation. * Determine the number of clock ticks in 2ms... * Divide the ticks/second value returned by sysClkRateGet () * by 512. (Note that 512 is approximately 500. Thus, shifting * by 9 is as if multiplying by approximately 0.002) */ ticksIn2ms = sysClkRateGet () >> 9; if (ticksIn2ms == 0) ticksIn2ms = 1; while ((pNIC->Isr & RST) != nic_STOP_MODE) if ((tickStartCount + ticksIn2ms) < tickGet ()) break; }/********************************************************************************* medXmitBfrDealloc - deallocate emptied transmit buffer(s)** This routine must execute at interrupt level only.*/LOCAL void medXmitBfrDealloc ( FAST xmitQCB_s *pXmitQCB ) { if (pXmitQCB->bEmpty) { logMsg("med: ERROR - transmit buffer deallocation failed.\n", 0,0,0,0,0,0); return; } pXmitQCB->bFull = FALSE; pXmitQCB->head = pXmitQCB->xmitBCB [pXmitQCB->head].next; if (pXmitQCB->head == pXmitQCB->tail) pXmitQCB->bEmpty = TRUE; }/********************************************************************************* medXmtrLock - lock access to the NIC transmitter** This function must only be invoked by tasks executing with splimp.* Otherwise, a race condition is possible during the LOCKED test.** RETURNS: ERROR if already locked, OK otherwise*/LOCAL STATUS medXmtrLock ( FAST lockID_t *pLock ) { FAST int oldLevel; if (*pLock == LOCKED) return ERROR; oldLevel = intLock (); *pLock = LOCKED; intUnlock (oldLevel); return (OK); }/********************************************************************************* medXmtrUnlock - unlock access to the NIC transmitter**/LOCAL void medXmtrUnlock ( FAST lockID_t *pLock ) { *pLock = UNLOCKED; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -