📄 if_med.c
字号:
switch (cmd) { case SIOCSIFADDR: ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN (data)->sin_addr; arpwhohas (ifp, &IA_SIN (data)->sin_addr); break; case SIOCGIFADDR: bcopy((caddr_t) es->es_enaddr, (caddr_t) ((struct ifreq *) data)->ifr_addr.sa_data, 6); break; case SIOCGIFFLAGS: *(short *) data = ifp->if_flags; break; case SIOCSIFFLAGS: { flags = ifp->if_flags;#ifdef BSD43_DRIVER if (ifp->if_flags & IFF_PROMISC) es->bPromisc = TRUE; else es->bPromisc = FALSE;#endif if (ifp->if_flags & IFF_UP) flags |= (IFF_UP | IFF_RUNNING); else flags &= ~(IFF_UP | IFF_RUNNING); ifp->if_flags = flags; } break; default: error = EINVAL; } splx (s); return (error); }/********************************************************************************* medXmitIntrHandler - handler for transmit interrupts**/LOCAL void medXmitIntrHandler ( FAST struct med_softc *es, FAST u_char xmitStatus ) { FAST xmitQCB_s * pXmitQCB = &(es->xmitQCB); FAST XBIdx_t headPkt; /* * The following flags indicate packet transmission error: * * ABT - excess collisions, transmission was aborted * FU - NIC FIFO underrun, transmission was aborted (should never occur) * * Retransmit the packet. * * The following flags indicate a collision occurred but the packet * was eventually transmitted. * * CRS - carrier lost (lost due to a collision) * OWC - out-of-window-collision * */ if (xmitStatus & (ABT | FU)) { es->es_if.if_oerrors++; /* log transmit error */ if (xmitStatus & ABT) { med_Stats.excessColl++; /* update statistics monitor */ logMsg("med%d: ERROR - excessive collisions, transmission aborted\n" , es->es_if.if_unit, 0,0,0,0,0); } if (xmitStatus & FU) { med_Stats.FIFO_UdrRun++; /* update statistics monitor */ logMsg("med%d: ERROR - NIC FIFO underrun, transmission aborted\n", es->es_if.if_unit, 0,0,0,0,0); } headPkt = pXmitQCB->head; 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 /* no transmission error */ { if (xmitStatus & CRS) med_Stats.carrierLost++; /* update statistics monitor */ if (xmitStatus & OWC) med_Stats.outOfWndColl++; /* update statistics monitor */ es->es_if.if_opackets++; /* log packet output */ pXmitQCB->xmitBCB [pXmitQCB->head].bPktRdy = FALSE; medXmitBfrDealloc (pXmitQCB); /* could be a macro */ headPkt = pXmitQCB->head; /* new head index after buf dealloc */ 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)); if (es->es_if.if_snd.ifq_head != NULL) /* if packet(s) on queue */#ifdef BSD43_DRIVER netJobAdd ( (FUNCPTR)medStartOutput, es->es_if.if_unit, 0, 0, 0, 0);#else netJobAdd ( (FUNCPTR)medStartOutput, (int)es, 0, 0, 0, 0);#endif } } }/********************************************************************************* medIntr - top level DB-ETH interrupt service routine*/LOCAL void medIntr ( FAST int unit ) { FAST u_char intrStatus; FAST struct med_softc *es = med_softc [unit]; FAST NIC_DEVICE *pNIC = es->nicAddr; med_Stats.intrCount++; /* retrieve interrupt status */ intrStatus = pNIC->Isr; if (intrStatus & OVW) /* overflow warning, no recv buffers */ { medSetNIC_IMR (es, UNMASK_NONE, nic_RECV_BFR_OVF_WARN | nic_PKT_RECV_NO_ERRORS | nic_PKT_RECV_ERROR); es->bRecvBfrOvfl = TRUE; /* flag for medRecvIntrHandler() */ intrStatus &= ~(OVW | PRX | RXE); /* ignore these interrupts */ logMsg ("med%d: receive buffer overflow, all buffers cleared.\n", unit, 0,0,0,0,0); med_Stats.OVW_intrCount++; /* update statistics monitor */ (void) netJobAdd (medInit, unit, 0,0,0,0); } if (intrStatus & PRX) /* packet reception, no error */ { /* * Handle packet reception interrupts (with and without errors) * at task level, until none remaining. * Mask further PRX (nic_PKT_RECV_NO_ERRORS) interrupts. * Mask further RXE (nic_PKT_RECV_ERROR) interrupts. */ medSetNIC_IMR (es, UNMASK_NONE, nic_PKT_RECV_NO_ERRORS | nic_PKT_RECV_ERROR); pNIC->Isr = PRX; /* clear interrupt flag */ med_Stats.PRX_intrCount++; /* update statistics monitor */ (void) netJobAdd ((FUNCPTR)medRecvIntrHandler, (int)es, 0,0,0,0); } if (intrStatus & PTX) /* packet transmission, not aborted */ { pNIC->Isr = PTX; /* clear interrupt flag */ med_Stats.PTX_intrCount++; /* update statistics monitor */ medXmitIntrHandler(es, pNIC->Tsr); } if (intrStatus & TXE) /* packet transmission aborted */ { pNIC->Isr = TXE; /* clear interrupt flag */ med_Stats.TXE_intrCount++; /* update statistics monitor */ medXmitIntrHandler(es, pNIC->Tsr); } if (intrStatus & RXE) /* packet received with error(s) */ { pNIC->Isr = RXE; /* clear interrupt flag */ medRecordRecvError (es); } if (intrStatus & CNT) /* tally counter MSB set */ { pNIC->Isr = CNT; /* clear interrupt flag */ med_Stats.CNT_intrCount++; /* update statistics monitor */ (void) netJobAdd ((FUNCPTR)medReadTallyCntrs, (int)es,0,0,0,0); } }/********************************************************************************* medRecordRecvError - record packet reception errors*/LOCAL void medRecordRecvError ( FAST struct med_softc *es ) { med_Stats.RXE_intrCount++; /* update statistics monitor */ /* * Packets received with errors are not saved. Therefore, * es->pktNextToRead is not updated. */ es->es_if.if_ierrors++; /* log every medLogCount errors */ if (medLogCount > 0 && (es->es_if.if_ierrors % medLogCount) == 0) logMsg ("med%d: receive error\n", es->es_if.if_unit,0,0,0,0,0); }/********************************************************************************* medIntEnable - enables/disables the DB-ETH interrupt**/LOCAL void medIntEnable ( BOOL bEnable ) { int oldLevel; /* * In an attempt to avoid spurious interrupts * on Dbus interrupt disable... */ if (!bEnable) { oldLevel = intLock (); sysDbusEtherIntEnable (bEnable); intUnlock (oldLevel); } else sysDbusEtherIntEnable (bEnable); }/********************************************************************************* medReset - reset the interface** Mark interface as inactive and reset the NIC.*/LOCAL void medReset ( int unit ) { struct med_softc *es = med_softc [unit]; NIC_DEVICE *pNIC = es->nicAddr; es->es_if.if_flags &= ~IFF_RUNNING; /* * The following sequence is required when disabling the NIC from * an active network. (This sequence was derived from the DP8390 * Datasheet Addendum, dated December, 1988, section 2.1.) */ pNIC->Cr = RPAGE0 | STP | ABORT; /* clear remote DMA byte count registers */ pNIC->Rbcr0 = 0; pNIC->Rbcr1 = 0; /* if the NIC not yet stopped, wait for approximately 2ms */ if ((pNIC->Isr & RST) != nic_STOP_MODE) medNIC_AwaitStop (pNIC); }/********************************************************************************* medInit - initialize NIC.** Restart the NIC chip and mark the interface as up.**/LOCAL int medInit ( int unit ) { struct med_softc *es = med_softc [unit]; struct ifnet *ifp = &es->es_if; medIntEnable (FALSE); /* disable DB-ETH interrupt */ ifp->if_flags &= ~(IFF_UP | IFF_RUNNING | IFF_PROMISC); /* stop all operations, reset the NIC */ medReset (unit); /* Clear all driver statistics on first initialization, but * not on subsequent calls of medInit(), e.g. after receive * buffer overflow. */ if (es->bFirstInit) { bzero((char *) &med_Stats, sizeof (med_Stats)); es->bFirstInit = FALSE; } /* configure and start NIC operations */ medConfigNIC (unit); /* initialize the NIC IMR shadow register */ es->currentIMR = NIC_INTERRUPTS_HANDLED; /* flag for medRecvIntrHandler(), no receive buffer overflow */ es->bRecvBfrOvfl = FALSE; /* * Initialize the "next-packet-to-read" pointer. * The NIC's remote DMA capability is not supported by the DB-ETH. * Therefore, the BNRY register is not maintained by the NIC, and * it must be maintained by software. However, BNRY must never * equal CURR. * * pktNextToRead: This page pointer is required to determine where * to retrieve the next received packet. */ es->pktNextToRead = CURR; /* * Initialize the xmitQCB and xmitBfrCB structures. */ { xmitQCB_s *pXmitQCB = &(es->xmitQCB); int idx; pXmitQCB->head = 0; pXmitQCB->tail = 0; pXmitQCB->bEmpty = TRUE; pXmitQCB->bFull = FALSE; for (idx = 0; idx < NUM_XMIT_BFRS; idx++) { pXmitQCB->xmitBCB [idx].bPktRdy = FALSE; pXmitQCB->xmitBCB [idx].pPktBfr = (char *) (NIC_XMIT_BFR_ADRS + XMIT_BFR_SIZE * idx); } for (idx = 1; idx < NUM_XMIT_BFRS; idx++) pXmitQCB->xmitBCB [idx - 1].next = idx; /* * Close the ring. Assign the next index parameter of the last buffer * control block to the index of the first buffer control block in * the ring. */ pXmitQCB->xmitBCB [NUM_XMIT_BFRS - 1].next = 0; /* allow access to the NIC transmitter */ medXmtrUnlock (&(pXmitQCB->lockNIC_Xmtr)); } ifp->if_flags |= (IFF_UP | IFF_RUNNING);#ifdef BSD43_DRIVER if (es->bPromisc) ifp->if_flags |= (IFF_PROMISC);#endif medIntEnable (TRUE); return (0); }/********************************************************************************* bitReverse - reverse the position of the bits in a byte**/LOCAL u_char bitReverse ( u_char in ) { int bit; u_char fromBitMask; u_char toBitMask; u_char out = 0; fromBitMask = 0x01; toBitMask = 0x80; for (bit = 0; bit < 8; bit++) { if (in & fromBitMask) out |= toBitMask; fromBitMask = fromBitMask << 1; toBitMask = toBitMask >> 1; } return (out); }/********************************************************************************* medEthAddrGet - Get hardwired ethernet address from DB-ETH.** Read the ethernet address out of the ROM, one byte at a time.* put it in med_softc** INTERNAL* The DB-ETH prototype boards have the 8 data lines reversed to the* Ethernet address PROM. Using the assigned Ethernet address (1st 3* octets), this function determines if the data lines are reversed on* the DB-ETH board it is controling and makes the appropriate* conversion if necessary. Note that this function will fail if each* of the 3 octets are made-up of nybbles which are mirror images of* each other. For example, the following bytes (in hex):* 00, 81, 66, 99, E7, ... The third octet assigned to Matrix Corp.* is 0x0b. This octet in PROM will be determine whether to reverse* the data values.*/LOCAL void medEthAddrGet ( int unit ) { u_char octet; u_int octetSel; BOOL bReversed; struct med_softc *es = med_softc [unit]; u_char *pEthOctet = (u_char *) (ETH_ADRS_PROM_ADRS); /* XXX optimize by saving result in static variable then just test var. ? */ bReversed = FALSE; if (*(pEthOctet + 2) != 0x0b) bReversed = TRUE; for (octetSel = 0; octetSel < 6; octetSel++ ) { octet = *pEthOctet; if (bReversed) octet = bitReverse (octet); es->es_enaddr [octetSel] = octet; pEthOctet++; } }/********************************************************************************* medConfigNIC - Configure the NIC for operation** INTERNAL* This NIC initialization/configuration sequence was derived from the* DP8390 Datasheet Addendum, dated December, 1988, section 2.0. This
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -