📄 if_fe.c
字号:
/* * Program the 86960 as follows: * SRAM: 32KB, 100ns, byte-wide access. * Transmission buffer: 4KB x 2. * System bus interface: 16 bits. * We cannot change these values but TXBSIZE, because they * are hard-wired on the board. Modifying TXBSIZE will affect * the driver performance. */ sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x4KB | FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns;#if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "ATI found" );#endif /* Initialize 86965. */ OUTB( sc->addr, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); DELAY(200); /* Disable all interrupts. */ OUTB( sc->addr, FE_DLCR2, 0 ); OUTB( sc->addr, FE_DLCR3, 0 );#if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "end of fe_probe_ati()" );#endif /* * That's all. AT1700 occupies 32 I/O addresses, by the way. */ return 32;}/* * Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface. */static intfe_probe_mbh ( struct isa_device * isa_dev, struct fe_softc * sc ){ static struct fe_simple_probe_struct probe_table [] = { { FE_DLCR2, 0x70, 0x00 }, { FE_DLCR4, 0x08, 0x00 }, /* { FE_DLCR5, 0x80, 0x00 }, Does not work well. */#if 0 /* * Test *vendor* part of the address for Fujitsu. * The test will gain reliability of probe process, but * it rejects clones by other vendors, or OEM product * supplied by resalers other than Fujitsu. */ { FE_MBH10, 0xFF, 0x00 }, { FE_MBH11, 0xFF, 0x00 }, { FE_MBH12, 0xFF, 0x0E },#else /* * We can always verify the *first* 2 bits (in Ehternet * bit order) are "global" and "unicast" even for * unknown vendors. */ { FE_MBH10, 0x03, 0x00 },#endif /* Just a gap? Seems reliable, anyway. */ { 0x12, 0xFF, 0x00 }, { 0x13, 0xFF, 0x00 }, { 0x14, 0xFF, 0x00 }, { 0x15, 0xFF, 0x00 }, { 0x16, 0xFF, 0x00 }, { 0x17, 0xFF, 0x00 }, { 0x18, 0xFF, 0xFF }, { 0x19, 0xFF, 0xFF }, { 0 } };#if 0 /* * We need a PCMCIA flag. */ if ( ( isa_dev->id_flags & FE_FLAGS_PCMCIA ) == 0 ) return ( 0 );#endif /* * We need explicit IRQ and supported address. */ if ( isa_dev->id_irq == 0 || ( sc->addr & ~0x3E0 ) != 0 ) return ( 0 );#if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "top of probe" );#endif /* * See if MBH10302 is on its address. * I'm not sure the following probe code works. FIXME. */ if ( !fe_simple_probe( sc->addr, probe_table ) ) return 0; /* Determine the card type. */ sc->type = FE_TYPE_MBH10302; sc->typestr = "MBH10302 (PCMCIA)"; sc->sc_description = "Ethernet adapter: MBH10302 (PCMCIA)"; /* * Initialize constants in the per-line structure. */ /* Get our station address from EEPROM. */ inblk( sc->addr, FE_MBH10, sc->sc_enaddr, ETHER_ADDR_LEN ); /* Make sure we got a valid station address. */ if ( ( sc->sc_enaddr[ 0 ] & 0x03 ) != 0x00 || ( sc->sc_enaddr[ 0 ] == 0x00 && sc->sc_enaddr[ 1 ] == 0x00 && sc->sc_enaddr[ 2 ] == 0x00 ) ) return 0; /* Should find all register prototypes here. FIXME. */ sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL; sc->proto_dlcr5 = 0; sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_NICE; /* * Program the 86960 as follows: * SRAM: 32KB, 100ns, byte-wide access. * Transmission buffer: 4KB x 2. * System bus interface: 16 bits. * We cannot change these values but TXBSIZE, because they * are hard-wired on the board. Modifying TXBSIZE will affect * the driver performance. */ sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x4KB | FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns; /* Setup hooks. We need a special initialization procedure. */ sc->init = fe_init_mbh; /* * Minimum initialization. */ /* Wait for a while. I'm not sure this is necessary. FIXME. */ DELAY(200); /* Minimul initialization of 86960. */ OUTB( sc->addr, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); DELAY( 200 ); /* Disable all interrupts. */ OUTB( sc->addr, FE_DLCR2, 0 ); OUTB( sc->addr, FE_DLCR3, 0 );#if 1 /* FIXME. */ /* Initialize system bus interface and encoder/decoder operation. */ OUTB( sc->addr, FE_MBH0, FE_MBH0_MAGIC | FE_MBH0_INTR_DISABLE );#endif /* * That's all. MBH10302 occupies 32 I/O addresses, by the way. */ return 32;}/* MBH specific initialization routine. */static voidfe_init_mbh ( struct fe_softc * sc ){ /* Probably required after hot-insertion... */ /* Wait for a while. I'm not sure this is necessary. FIXME. */ DELAY(200); /* Minimul initialization of 86960. */ OUTB( sc->addr, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); DELAY( 200 ); /* Disable all interrupts. */ OUTB( sc->addr, FE_DLCR2, 0 ); OUTB( sc->addr, FE_DLCR3, 0 ); /* Enable master interrupt flag. */ OUTB( sc->addr, FE_MBH0, FE_MBH0_MAGIC | FE_MBH0_INTR_ENABLE );}/* * Install interface into kernel networking data structures */intfe_attach ( struct isa_device *isa_dev ){ struct fe_softc *sc = &fe_softc[isa_dev->id_unit]; /* * Initialize ifnet structure */ sc->sc_if.if_unit = sc->sc_unit; sc->sc_if.if_name = "fe"; sc->sc_if.if_init = fe_init; sc->sc_if.if_output = ether_output; sc->sc_if.if_start = fe_start; sc->sc_if.if_ioctl = fe_ioctl; sc->sc_if.if_reset = fe_reset; sc->sc_if.if_watchdog = fe_watchdog; /* * Set default interface flags. */ sc->sc_if.if_flags = IFF_BROADCAST | IFF_NOTRAILERS | IFF_MULTICAST; /* * Set maximum size of output queue, if it has not been set. * It is done here as this driver may be started after the * system intialization (i.e., the interface is PCMCIA.) * * I'm not sure this is really necessary, but, even if it is, * it should be done somewhere else, e.g., in if_attach(), * since it must be a common workaround for all network drivers. * FIXME. */ if ( sc->sc_if.if_snd.ifq_maxlen == 0 ) { sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen; }#if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "attach()" );#endif#if FE_SINGLE_TRANSMISSION /* Override txb config to allocate minimum. */ sc->proto_dlcr6 &= ~FE_D6_TXBSIZ sc->proto_dlcr6 |= FE_D6_TXBSIZ_2x2KB;#endif /* Modify hardware config if it is requested. */ if ( isa_dev->id_flags & FE_FLAGS_OVERRIDE_DLCR6 ) { sc->proto_dlcr6 = isa_dev->id_flags & FE_FLAGS_DLCR6_VALUE; } /* Find TX buffer size, based on the hardware dependent proto. */ switch ( sc->proto_dlcr6 & FE_D6_TXBSIZ ) { case FE_D6_TXBSIZ_2x2KB: sc->txb_size = 2048; break; case FE_D6_TXBSIZ_2x4KB: sc->txb_size = 4096; break; case FE_D6_TXBSIZ_2x8KB: sc->txb_size = 8192; break; default: /* Oops, we can't work with single buffer configuration. */#if FE_DEBUG >= 2 log( LOG_WARNING, "fe%d: strange TXBSIZ config; fixing\n", sc->sc_unit );#endif sc->proto_dlcr6 &= ~FE_D6_TXBSIZ; sc->proto_dlcr6 |= FE_D6_TXBSIZ_2x2KB; sc->txb_size = 2048; break; } /* Attach and stop the interface. */ if_attach( &sc->sc_if ); fe_stop( sc->sc_unit ); /* This changes the state to IDLE. */#ifdef PROM if_newaddr(ifp, IFT_ETHER, (caddr_t)((struct arpcom *)ifp)->ac_enaddr);#else fe_setlinkaddr( sc );#endif /* Print additional info when attached. */ printf( "fe%d: address %s, type %s\n", sc->sc_unit, ether_sprintf( sc->sc_enaddr ), sc->typestr );#if FE_DEBUG >= 3 { int buf, txb, bbw, sbw, ram; buf = txb = bbw = sbw = ram = -1; switch ( sc->proto_dlcr6 & FE_D6_BUFSIZ ) { case FE_D6_BUFSIZ_8KB: buf = 8; break; case FE_D6_BUFSIZ_16KB: buf = 16; break; case FE_D6_BUFSIZ_32KB: buf = 32; break; case FE_D6_BUFSIZ_64KB: buf = 64; break; } switch ( sc->proto_dlcr6 & FE_D6_TXBSIZ ) { case FE_D6_TXBSIZ_2x2KB: txb = 2; break; case FE_D6_TXBSIZ_2x4KB: txb = 4; break; case FE_D6_TXBSIZ_2x8KB: txb = 8; break; } switch ( sc->proto_dlcr6 & FE_D6_BBW ) { case FE_D6_BBW_BYTE: bbw = 8; break; case FE_D6_BBW_WORD: bbw = 16; break; } switch ( sc->proto_dlcr6 & FE_D6_SBW ) { case FE_D6_SBW_BYTE: sbw = 8; break; case FE_D6_SBW_WORD: sbw = 16; break; } switch ( sc->proto_dlcr6 & FE_D6_SRAM ) { case FE_D6_SRAM_100ns: ram = 100; break; case FE_D6_SRAM_150ns: ram = 150; break; } printf( "fe%d: SRAM %dKB %dbit %dns, TXB %dKBx2, %dbit I/O\n", sc->sc_unit, buf, bbw, ram, txb, sbw ); }#endif#if NBPFILTER > 0 /* If BPF is in the kernel, call the attach for it. */ bpfattach(&sc->bpf, &sc->sc_if, DLT_EN10MB, sizeof(struct ether_header));#endif return 1;}#else /* PROM *//* * eninit(): initialise ethernet */inteninit (){ int unit = 0; struct fe_softc *sc = &fe_softc[unit]; struct ifnet *ifp = &sc->sc_if; int timeout; /* check for presence */ /* config it */ ifp->if_name = "en"; ifp->if_unit = unit; if (sbdethaddr (sc->sc_enaddr) < 0) return; log (LOG_INFO, "%s%d: ethernet address: %s\n", sc->sc_if.if_name, sc->sc_if.if_unit, ether_sprintf (sc->sc_enaddr)); sc->addr = PHYS_TO_K1(NIC_BASE); /* network management */ ifp->if_type = IFT_ETHER; ifp->if_addrlen = 6; ifp->if_hdrlen = 14; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS;#ifdef DEBUG ifp->if_flags |= IFF_DEBUG;#endif ifp->if_init = fe_init; ifp->if_output = ether_output; ifp->if_start = fe_start; ifp->if_ioctl = fe_ioctl; ifp->if_watchdog = fe_watchdog; ifp->if_reset = fe_reset; ifp->if_timer = 0; sc->type = FE_TYPE_FMV181; sc->typestr = "mb86964"; /* Register values which depend on board design. */ sc->proto_dlcr4 = FE_D4_INIT; sc->proto_dlcr5 = FE_D5_INIT; sc->proto_dlcr6 = FE_D6_INIT; sc->proto_dlcr7 = FE_D7_INIT;#if FE_SINGLE_TRANSMISSION /* Override txb config to allocate minimum. */ sc->proto_dlcr6 &= ~FE_D6_TXBSIZ; sc->proto_dlcr6 |= FE_D6_TXBSIZ_2x2KB;#endif /* Find TX buffer size, based on the hardware dependent proto. */ switch ( sc->proto_dlcr6 & FE_D6_TXBSIZ ) { case FE_D6_TXBSIZ_2x2KB: sc->txb_size = 2048; break; case FE_D6_TXBSIZ_2x4KB: sc->txb_size = 4096; break; case FE_D6_TXBSIZ_2x8KB: sc->txb_size = 8192; break; default: /* Oops, we can't work with single buffer configuration. */#if FE_DEBUG >= 2 log( LOG_WARNING, "fe%d: strange TXBSIZ config; fixing\n", sc->sc_unit );#endif sc->proto_dlcr6 &= ~FE_D6_TXBSIZ; sc->proto_dlcr6 |= FE_D6_TXBSIZ_2x2KB; sc->txb_size = 2048; break; } if_attach (ifp);#ifdef PROM if_newaddr(ifp, IFT_ETHER, (caddr_t)((struct arpcom *)ifp)->ac_enaddr);#else fe_stop( sc->sc_unit ); /* This changes the state to IDLE. */#if defined(IP_NET) && defined(USEINTS) sbd_setvec (IP_NET, 0, feintr, unit);#endif}#endif/* * Reset interface. */voidfe_reset ( int unit ){ /* * Stop interface and re-initialize. */ fe_stop(unit); fe_init(unit);}/* * Stop everything on the interface. * * All buffered packets, both transmitting and receiving, * if any, will be lost by stopping the interface. */voidfe_stop ( int unit ){ struct fe_softc *sc = &fe_softc[unit]; int s; s = splimp();#if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "stop()" );#endif /* Disable interrupts. */ OUTB( sc->addr, FE_DLCR2, 0x00 ); OUTB( sc->addr, FE_DLCR3, 0x00 ); /* Stop interface hardware. */ DELAY( 200 ); OUTB( sc->addr, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); DELAY( 200 ); /* Clear all interrupt status. */ OUTB( sc->addr, FE_DLCR0, 0xFF ); OUTB( sc->addr, FE_DLCR1, 0xFF ); /* Put the chip in stand-by mode. */ DELAY( 200 ); OUTB( sc->addr, FE_DLCR7, sc->proto_dlcr7 | FE_D7_POWER_DOWN ); DELAY( 200 ); /* Reset transmitter variables and interface flags. */ sc->sc_if.if_flags &= ~( IFF_OACTIVE | IFF_RUNNING ); sc->sc_if.if_timer = 0; sc->txb_free = sc->txb_size; sc->txb_count = 0; sc->txb_sched = 0;#ifdef MULTICAST /* MAR loading can be delayed. */ sc->filter_change = 0;#endif#ifndef PROM /* Update config status also. */ sc->sc_dcstate = DC_IDLE;#endif /* Call a hook. */ if ( sc->stop ) sc->stop( sc );#if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "end of stop()" );#endif (void) splx(s);}/* * Device timeout/watchdog routine. Entered if the device neglects to * generate an interrupt after a transmit has been started on it. */voidfe_watchdog ( int unit ){ struct fe_softc *sc = &fe_softc[unit];#if FE_DEBUG >= 1 log( LOG_ERR, "fe%d: transmission timeout (%d+%d)%s\n", unit, sc->txb_sched, sc->txb_count, ( sc->sc_if.if_flags & IFF_UP ) ? "" : " when down" );#endif#if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, NULL );#endif /* Record how many packets are lost by this accident. */ sc->sc_if.if_oerrors += sc->txb_sched + sc->txb_count;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -