From e7242595bb6c17981d01f6c99f0564c62e82ddfa Mon Sep 17 00:00:00 2001 From: jkh Date: Sun, 17 Mar 1996 08:36:38 +0000 Subject: This is a revised fe, Ethernet driver for MB8696x based adapters. --- sys/i386/isa/if_fe.c | 1195 +++++++++++++++++++++++++++++++------------------- 1 file changed, 733 insertions(+), 462 deletions(-) (limited to 'sys/i386/isa/if_fe.c') diff --git a/sys/i386/isa/if_fe.c b/sys/i386/isa/if_fe.c index e07970a..2578867 100644 --- a/sys/i386/isa/if_fe.c +++ b/sys/i386/isa/if_fe.c @@ -20,21 +20,29 @@ * SUCH DAMAGE. */ -#define FE_VERSION "if_fe.c ver. 0.8a" - /* + * $Id:$ + * * Device driver for Fujitsu MB86960A/MB86965A based Ethernet cards. - * To be used with FreeBSD 2.0 RELEASE. - * Contributed by M.S. + * To be used with FreeBSD 2.x + * Contributed by M. Sekiguchi. * * This version is intended to be a generic template for various * MB86960A/MB86965A based Ethernet cards. It currently supports - * Fujitsu FMV-180 series (i.e., FMV-181 and FMV-182) and Allied- - * Telesis AT1700 series and RE2000 series. There are some - * unnecessary hooks embedded, which are primarily intended to support + * Fujitsu FMV-180 series for ISA and Allied-Telesis AT1700/RE2000 + * series for ISA, as well as Fujitsu MBH10302 PC card. + * There are some currently- + * unused hooks embedded, which are primarily intended to support * other types of Ethernet cards, but the author is not sure whether * they are useful. * + * This version also includes some alignments for + * RE1000/RE1000+/ME1500 support. It is incomplete, however, since the + * cards are not for AT-compatibles. (They are for PC98 bus -- a + * proprietary bus architecture available only in Japan.) Further + * work for PC98 version will be available as a part of FreeBSD(98) + * project. + * * This software is a derivative work of if_ed.c version 1.56 by David * Greenman available as a part of FreeBSD 2.0 RELEASE source distribution. * @@ -48,12 +56,28 @@ * for damages incurred with its use. */ +/* + * TODO: + * o To support MBH10304 PC card. It is another MB8696x based + * PCMCIA Ethernet card by Fujitsu, which is not compatible with + * MBH10302. + * o To merge FreeBSD(98) efforts into a single source file. + * o To support ISA PnP auto configuration for FMV-183/184. + * o To reconsider mbuf usage. + * o To reconsider transmission buffer usage, including + * transmission buffer size (currently 4KB x 2) and pros-and- + * cons of multiple frame transmission. + * o To test IPX codes. + */ + #include "fe.h" #include "bpfilter.h" #include #include + #include + #include #include #include @@ -73,11 +97,19 @@ #include #endif +/* IPX code is not tested. FIXME. */ #ifdef IPX #include #include #endif +/* To be used with IPv6 package of INRIA. */ +#ifdef INET6 +/* IPv6 added by shin 96.2.6 */ +#include +#endif + +/* XNS code is not tested. FIXME. */ #ifdef NS #include #include @@ -94,14 +126,28 @@ #include #include +/* PCCARD suport */ +#include "crd.h" +#if NCRD > 0 +#include +#include +#include +#include +#endif /* NCRD > 0 */ + #include #include -#ifdef __GNUC__ -#define INLINE inline -#else -#define INLINE -#endif +#if NCRD > 0 +#include +#endif /* NCRD > 0 */ + +/* + * This version of fe is an ISA device driver. + * Override the following macro to adapt it to another bus. + * (E.g., PC98.) + */ +#define DEVICE struct isa_device /* * Default settings for fe driver specific options. @@ -121,15 +167,7 @@ #endif /* - * Delay padding of short transmission packets to minimum Ethernet size. - * This may or may not gain performance. An EXPERIMENTAL option. - */ -#ifndef FE_DELAYED_PADDING -#define FE_DELAYED_PADDING 0 -#endif - -/* - * Transmit just one packet per a "send"command to 86960. + * Transmit just one packet per a "send" command to 86960. * This option is intended for performance test. An EXPERIMENTAL option. */ #ifndef FE_SINGLE_TRANSMISSION @@ -146,40 +184,12 @@ /* Force DLCR6 override. */ #define FE_FLAGS_OVERRIDE_DLCR6 0x0080 -/* A cludge for PCMCIA support. */ -#define FE_FLAGS_PCMCIA 0x8000 - -/* Shouldn't this be defined somewhere else such as isa_device.h? */ -#define NO_IOADDR 0xFFFFFFFF - -/* Identification of the driver version. */ -static char const fe_version [] = FE_VERSION " / " FE_REG_VERSION; - -/* - * Supported hardware (Ethernet card) types - * This information is currently used only for debugging - */ -enum fe_type -{ - /* For cards which are successfully probed but not identified. */ - FE_TYPE_UNKNOWN, - - /* Fujitsu FMV-180 series. */ - FE_TYPE_FMV181, - FE_TYPE_FMV182, - - /* Allied-Telesis AT1700 series and RE2000 series. */ - FE_TYPE_AT1700, - - /* PCMCIA by Fujitsu. */ - FE_TYPE_MBH10302, - FE_TYPE_MBH10304, - - /* More can be here. */ -}; +/* Shouldn't these be defined somewhere else such as isa_device.h? */ +#define NO_IOADDR 0xFFFFFFFF +#define NO_IRQ 0 /* - * Data type for a multicast address filter on 86960. + * Data type for a multicast address filter on 8696x. */ struct fe_filter { u_char data [ FE_FILTER_LEN ]; }; @@ -189,26 +199,30 @@ struct fe_filter { u_char data [ FE_FILTER_LEN ]; }; static struct fe_filter const fe_filter_nothing = { FE_FILTER_NOTHING }; static struct fe_filter const fe_filter_all = { FE_FILTER_ALL }; +/* How many registers does an fe-supported adapter have at maximum? */ +#define MAXREGISTERS 32 + /* * fe_softc: per line info and status */ static struct fe_softc { /* Used by "common" codes. */ - struct arpcom arpcom; /* ethernet common */ + struct arpcom arpcom; /* Ethernet common */ /* Used by config codes. */ struct kern_devconf kdc;/* Kernel configuration database info. */ /* Set by probe() and not modified in later phases. */ - enum fe_type type; /* interface type code */ char * typestr; /* printable name of the interface. */ - u_short addr; /* MB86960A I/O base address */ + u_short iobase; /* base I/O address of the adapter. */ + u_short ioaddr [ MAXREGISTERS ]; /* I/O addresses of register. */ u_short txb_size; /* size of TX buffer, in bytes */ u_char proto_dlcr4; /* DLCR4 prototype. */ u_char proto_dlcr5; /* DLCR5 prototype. */ u_char proto_dlcr6; /* DLCR6 prototype. */ u_char proto_dlcr7; /* DLCR7 prototype. */ + u_char proto_bmpr13; /* BMPR13 prototype. */ /* Vendor specific hooks. */ void ( * init )( struct fe_softc * ); /* Just before fe_init(). */ @@ -233,8 +247,6 @@ static struct fe_softc { #define sc_dcstate kdc.kdc_state #define sc_description kdc.kdc_description -#define IFNET2SOFTC(P) (P)->if_softc - /* Standard driver entry points. These can be static. */ static int fe_probe ( struct isa_device * ); static int fe_attach ( struct isa_device * ); @@ -245,9 +257,10 @@ static void fe_reset ( int ); static void fe_watchdog ( struct ifnet * ); /* Local functions. Order of declaration is confused. FIXME. */ -static int fe_probe_fmv ( struct isa_device *, struct fe_softc * ); -static int fe_probe_ati ( struct isa_device *, struct fe_softc * ); -static int fe_probe_mbh ( struct isa_device *, struct fe_softc * ); +static void fe_registerdev ( struct fe_softc *, DEVICE * ); +static int fe_probe_fmv ( DEVICE *, struct fe_softc * ); +static int fe_probe_ati ( DEVICE *, struct fe_softc * ); +static int fe_probe_mbh ( DEVICE *, struct fe_softc * ); static void fe_init_mbh ( struct fe_softc * ); static int fe_get_packet ( struct fe_softc *, u_short ); static void fe_stop ( int ); @@ -278,7 +291,7 @@ struct isa_driver fedriver = fe_probe, fe_attach, "fe", - 0 /* Assume we are insensitive. FIXME. */ + 1 /* It's safe to mark as "sensitive" */ }; /* Initial value for a kdc struct. */ @@ -287,22 +300,15 @@ static struct kern_devconf const fe_kdc_template = 0, 0, 0, "fe", 0, { MDDT_ISA, 0, "net" }, isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, - &kdc_isa0, /* We are an ISA device. */ + &kdc_isa0, /* This is an ISA device. */ 0, DC_UNCONFIGURED, /* Not yet configured. */ - "Ethernet (fe)", /* Tentative description (filled in later.) */ - DC_CLS_NETIF /* We are a network interface. */ + "Ethernet (MB8696x)", /* Tentative description (filled in later.) */ + DC_CLS_NETIF /* This is a network interface. */ }; /* * Fe driver specific constants which relate to 86960/86965. - * They are here (not in if_fereg.h), since selection of those - * values depend on driver design. I want to keep definitions in - * if_fereg.h "clean", so that if someone wrote another driver - * for 86960/86965, if_fereg.h were usable unchanged. - * - * The above statement sounds somothing like it's better to name - * it "ic/mb86960.h" but "if_fereg.h"... Should I do so? FIXME. */ /* Interrupt masks */ @@ -310,35 +316,143 @@ static struct kern_devconf const fe_kdc_template = #define FE_RMASK ( FE_D3_OVRFLO | FE_D3_CRCERR \ | FE_D3_ALGERR | FE_D3_SRTPKT | FE_D3_PKTRDY ) -/* Maximum number of iterrations for a receive interrupt. */ +/* Maximum number of iterations for a receive interrupt. */ #define FE_MAX_RECV_COUNT ( ( 65536 - 2048 * 2 ) / 64 ) - /* Maximum size of SRAM is 65536, + /* + * Maximum size of SRAM is 65536, * minimum size of transmission buffer in fe is 2x2KB, * and minimum amount of received packet including headers * added by the chip is 64 bytes. * Hence FE_MAX_RECV_COUNT is the upper limit for number - * of packets in the receive buffer. */ + * of packets in the receive buffer. + */ /* - * Convenient routines to access contiguous I/O ports. + * Routines to access contiguous I/O ports. */ -static INLINE void -inblk ( u_short addr, u_char * mem, int len ) +static void +inblk ( struct fe_softc * sc, int offs, u_char * mem, int len ) { while ( --len >= 0 ) { - *mem++ = inb( addr++ ); + *mem++ = inb( sc->ioaddr[ offs++ ] ); } } -static INLINE void -outblk ( u_short addr, u_char const * mem, int len ) +static void +outblk ( struct fe_softc * sc, int offs, u_char const * mem, int len ) { while ( --len >= 0 ) { - outb( addr++, *mem++ ); + outb( sc->ioaddr[ offs++ ], *mem++ ); } } +/* PCCARD Support */ +#if NCRD > 0 +/* + * PC-Card (PCMCIA) specific code. + */ +static int fe_card_intr(struct pccard_dev *); /* Interrupt handler */ +static void feunload(struct pccard_dev *); /* Disable driver */ +static void fesuspend(struct pccard_dev *); /* Suspend driver */ +static int feinit(struct pccard_dev *, int); /* init device */ + +static struct pccard_drv fe_info = + { + "fe", + fe_card_intr, + feunload, + fesuspend, + feinit, + 0, /* Attributes - presently unused */ + &net_imask /* Interrupt mask for device */ + /* This should also include net_imask?? */ + }; +/* + * Called when a power down is requested. Shuts down the + * device and configures the device as unavailable (but + * still loaded...). A resume is done by calling + * feinit with first=0. This is called when the user suspends + * the system, or the APM code suspends the system. + */ +static void +fesuspend(struct pccard_dev *dp) +{ + printf("fe%d: suspending\n", dp->isahd.id_unit); +} + +/* + * Initialize the device - called from Slot manager. + * if first is set, then initially check for + * the device's existence before initializing it. + * Once initialized, the device table may be set up. + */ +static int +feinit(struct pccard_dev *dp, int first) +{ +/* + * validate unit number. + */ + struct fe_softc *sc; + if (first) + { + if (dp->isahd.id_unit >= NFE) + return(ENODEV); +/* + * Probe the device. If a value is returned, the + * device was found at the location. + */ +#if FE_DEBUG >= 2 + printf("Start Probe\n"); +#endif + if (fe_probe(&dp->isahd)==0) + return(ENXIO); +#if FE_DEBUG >= 2 + printf("Start attach\n"); +#endif + if (fe_attach(&dp->isahd)==0) + return(ENXIO); + + } +/* + * XXX TODO: + * If it was already init'ed before, the device structure + * should be already initialized. Here we should + * reset (and possibly restart) the hardware, but + * I am not sure of the best way to do this... + */ + return(0); +} + +/* + * feunload - unload the driver and clear the table. + * XXX TODO: + * This is called usually when the card is ejected, but + * can be caused by the modunload of a controller driver. + * The idea is reset the driver's view of the device + * and ensure that any driver entry points such as + * read and write do not hang. + */ +static void +feunload(struct pccard_dev *dp) +{ + printf("fe%d: unload\n", dp->isahd.id_unit); + fe_stop(dp->isahd.id_unit); +} + +/* + * card_intr - Shared interrupt called from + * front end of PC-Card handler. + */ +static int +fe_card_intr(struct pccard_dev *dp) +{ + feintr(dp->isahd.id_unit); + return(1); +} +#endif /* NCRD > 0 */ + + /* * Hardware probe routines. */ @@ -346,7 +460,7 @@ outblk ( u_short addr, u_char const * mem, int len ) /* How and where to probe; to support automatic I/O address detection. */ struct fe_probe_list { - int ( * probe ) ( struct isa_device *, struct fe_softc * ); + int ( * probe ) ( DEVICE *, struct fe_softc * ); u_short const * addresses; }; @@ -364,6 +478,16 @@ static struct fe_probe_list const fe_probe_list [] = { NULL, NULL } }; +static void +fe_registerdev ( struct fe_softc * sc, DEVICE * dev ) +{ + /* Fill the device config data and register it. */ + sc->kdc = fe_kdc_template; + sc->kdc.kdc_unit = sc->sc_unit; + sc->kdc.kdc_parentdata = dev; + dev_attach( &sc->kdc ); +} + /* * Determine if the device is present * @@ -375,36 +499,48 @@ static struct fe_probe_list const fe_probe_list [] = */ static int -fe_probe ( struct isa_device * isa_dev ) +fe_probe ( DEVICE * dev ) { - struct fe_softc * sc, * u; +#if NCRD > 0 + static int fe_already_init; +#endif /* NCRD > 0 */ + struct fe_softc * sc; + int u; int nports; struct fe_probe_list const * list; u_short const * addr; u_short single [ 2 ]; /* Initialize "minimum" parts of our softc. */ - sc = &fe_softc[ isa_dev->id_unit ]; - sc->sc_unit = isa_dev->id_unit; - -#if FE_DEBUG >= 2 - log( LOG_INFO, "fe%d: %s\n", sc->sc_unit, fe_version ); -#endif + sc = &fe_softc[ dev->id_unit ]; + sc->sc_unit = dev->id_unit; +#if NCRD == 0 #ifndef DEV_LKM - /* Fill the device config data and register it. */ - sc->kdc = fe_kdc_template; - sc->kdc.kdc_unit = sc->sc_unit; - sc->kdc.kdc_parentdata = isa_dev; - dev_attach( &sc->kdc ); -#endif + fe_registerdev( sc, dev ); +#endif +#endif /* NCRD == 0 */ + +#if NCRD > 0 +/* + * If PC-Card probe required, then register driver with + * slot manager. + */ + if (fe_already_init != 1) + { + fe_registerdev(sc,dev); + pccard_add_driver(&fe_info); + fe_already_init = 1; +/* return ( 0 ); */ + } +#endif /* NCRD > 0 */ /* Probe each possibility, one at a time. */ for ( list = fe_probe_list; list->probe != NULL; list++ ) { - if ( isa_dev->id_iobase != NO_IOADDR ) { + if ( dev->id_iobase != NO_IOADDR ) { /* Probe one specific address. */ - single[ 0 ] = isa_dev->id_iobase; + single[ 0 ] = dev->id_iobase; single[ 1 ] = 0; addr = single; } else if ( list->addresses != NULL ) { @@ -418,23 +554,39 @@ fe_probe ( struct isa_device * isa_dev ) /* Probe all possible addresses for the board. */ while ( *addr != 0 ) { - /* Don't probe already used address. */ - for ( u = &fe_softc[0]; u < &fe_softc[NFE]; u++ ) { - if ( u->addr == *addr ) break; + /* See if the address is already in use. */ + for ( u = 0; u < NFE; u++ ) { + if ( fe_softc[u].iobase == *addr ) break; } - if ( u < &fe_softc[NFE] ) continue; - - /* Probe an address. */ - sc->addr = *addr; - nports = list->probe( isa_dev, sc ); - if ( nports > 0 ) { - /* Found. */ - isa_dev->id_iobase = *addr; - return ( nports ); + +#if FE_DEBUG >= 3 + if ( u == NFE ) { + log( LOG_INFO, "fe%d: probing %d at 0x%x\n", + sc->sc_unit, list - fe_probe_list, *addr ); + } else if ( u == sc->sc_unit ) { + log( LOG_INFO, "fe%d: re-probing %d at 0x%x?\n", + sc->sc_unit, list - fe_probe_list, *addr ); + } else { + log( LOG_INFO, "fe%d: skipping %d at 0x%x\n", + sc->sc_unit, list - fe_probe_list, *addr ); + } +#endif + + /* Probe the address if it is free. */ + if ( u == NFE || u == sc->sc_unit ) { + + /* Probe an address. */ + sc->iobase = *addr; + nports = list->probe( dev, sc ); + if ( nports > 0 ) { + /* Found. */ + dev->id_iobase = *addr; + return ( nports ); + } + sc->iobase = 0; } /* Try next. */ - sc->addr = 0; addr++; } } @@ -453,13 +605,19 @@ struct fe_simple_probe_struct u_char bits; /* Values to be compared against. */ }; -static INLINE int -fe_simple_probe ( u_short addr, struct fe_simple_probe_struct const * sp ) +static int +fe_simple_probe ( struct fe_softc const * sc, + struct fe_simple_probe_struct const * sp ) { struct fe_simple_probe_struct const * p; for ( p = sp; p->mask != 0; p++ ) { - if ( ( inb( addr + p->port ) & p->mask ) != p->bits ) { +#if FE_DEBUG >=2 + printf("Probe Port:%x,Value:%x,Mask:%x.Bits:%x\n", + p->port,inb(sc->ioaddr[ p->port]),p->mask,p->bits); +#endif + if ( ( inb( sc->ioaddr[ p->port ] ) & p->mask ) != p->bits ) + { return ( 0 ); } } @@ -474,11 +632,14 @@ fe_simple_probe ( u_short addr, struct fe_simple_probe_struct const * sp ) * work.) FIXME. */ -static INLINE void -strobe ( u_short bmpr16 ) +static void +fe_strobe_eeprom ( u_short bmpr16 ) { /* - * Output same value twice. To speed-down execution? + * We must guarantee 800ns (or more) interval to access slow + * EEPROMs. The following redundant code provides enough + * delay with ISA timing. (Even if the bus clock is "tuned.") + * Some modification will be needed on faster busses. */ outb( bmpr16, FE_B16_SELECT ); outb( bmpr16, FE_B16_SELECT ); @@ -491,39 +652,34 @@ strobe ( u_short bmpr16 ) static void fe_read_eeprom ( struct fe_softc * sc, u_char * data ) { - u_short bmpr16 = sc->addr + FE_BMPR16; - u_short bmpr17 = sc->addr + FE_BMPR17; + u_short bmpr16 = sc->ioaddr[ FE_BMPR16 ]; + u_short bmpr17 = sc->ioaddr[ FE_BMPR17 ]; u_char n, val, bit; - u_char save16, save17; - /* Save old values of the registers. */ - save16 = inb( bmpr16 ); - save17 = inb( bmpr17 ); - - /* Read bytes from EEPROM; two bytes per an iterration. */ + /* Read bytes from EEPROM; two bytes per an iteration. */ for ( n = 0; n < FE_EEPROM_SIZE / 2; n++ ) { /* Reset the EEPROM interface. */ outb( bmpr16, 0x00 ); outb( bmpr17, 0x00 ); - outb( bmpr16, FE_B16_SELECT ); /* Start EEPROM access. */ + outb( bmpr16, FE_B16_SELECT ); outb( bmpr17, FE_B17_DATA ); - strobe( bmpr16 ); + fe_strobe_eeprom( bmpr16 ); - /* Pass the iterration count to the chip. */ + /* Pass the iteration count to the chip. */ val = 0x80 | n; for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { outb( bmpr17, ( val & bit ) ? FE_B17_DATA : 0 ); - strobe( bmpr16 ); + fe_strobe_eeprom( bmpr16 ); } outb( bmpr17, 0x00 ); /* Read a byte. */ val = 0; for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { - strobe( bmpr16 ); + fe_strobe_eeprom( bmpr16 ); if ( inb( bmpr17 ) & FE_B17_DATA ) { val |= bit; } @@ -533,7 +689,7 @@ fe_read_eeprom ( struct fe_softc * sc, u_char * data ) /* Read one more byte. */ val = 0; for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { - strobe( bmpr16 ); + fe_strobe_eeprom( bmpr16 ); if ( inb( bmpr17 ) & FE_B17_DATA ) { val |= bit; } @@ -541,9 +697,9 @@ fe_read_eeprom ( struct fe_softc * sc, u_char * data ) *data++ = val; } - /* Restore register values, in the case we had no 86965. */ - outb( bmpr16, save16 ); - outb( bmpr17, save17 ); + /* Reset the EEPROM interface, again. */ + outb( bmpr16, 0x00 ); + outb( bmpr17, 0x00 ); #if FE_DEBUG >= 3 /* Report what we got. */ @@ -573,11 +729,11 @@ fe_read_eeprom ( struct fe_softc * sc, u_char * data ) * Probe and initialization for Fujitsu FMV-180 series boards */ static int -fe_probe_fmv ( struct isa_device *isa_dev, struct fe_softc * sc ) +fe_probe_fmv ( DEVICE * dev, struct fe_softc * sc ) { int i, n; - static u_short const ioaddr [ 8 ] = + static u_short const baseaddr [ 8 ] = { 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x300, 0x340 }; static u_short const irqmap [ 4 ] = { IRQ3, IRQ7, IRQ10, IRQ15 }; @@ -587,9 +743,9 @@ fe_probe_fmv ( struct isa_device *isa_dev, struct fe_softc * sc ) { FE_DLCR4, 0x08, 0x00 }, /* { FE_DLCR5, 0x80, 0x00 }, Doesn't work. */ - { FE_FMV0, FE_FMV0_MAGIC_MASK, FE_FMV0_MAGIC_VALUE }, - { FE_FMV1, FE_FMV1_CARDID_MASK, FE_FMV1_CARDID_ID }, - { FE_FMV3, FE_FMV3_EXTRA_MASK, FE_FMV3_EXTRA_VALUE }, + { FE_FMV0, 0x78, 0x50 }, /* ERRDY+PRRDY */ + { FE_FMV1, 0xB0, 0x00 }, /* FMV-183/184 has 0x48 bits. */ + { FE_FMV3, 0x7F, 0x00 }, #if 1 /* * Test *vendor* part of the station address for Fujitsu. @@ -602,7 +758,7 @@ fe_probe_fmv ( struct isa_device *isa_dev, struct fe_softc * sc ) { FE_FMV6, 0xFF, 0x0E }, #else /* - * We can always verify the *first* 2 bits (in Ehternet + * We can always verify the *first* 2 bits (in Ethernet * bit order) are "no multicast" and "no local" even for * unknown vendors. */ @@ -611,62 +767,131 @@ fe_probe_fmv ( struct isa_device *isa_dev, struct fe_softc * sc ) { 0 } }; -#if 0 - /* - * Dont probe at all if the config says we are PCMCIA... - */ - if ( isa_dev->id_flags & FE_FLAGS_PCMCIA ) return ( 0 ); -#endif + /* "Hardware revision ID" */ + int revision; /* - * See if the sepcified address is possible for FMV-180 series. + * See if the specified address is possible for FMV-180 series. */ for ( i = 0; i < 8; i++ ) { - if ( ioaddr[ i ] == sc->addr ) break; + if ( baseaddr[ i ] == sc->iobase ) break; } if ( i == 8 ) return 0; + /* Setup an I/O address mapping table. */ + for ( i = 0; i < MAXREGISTERS; i++ ) { + sc->ioaddr[ i ] = sc->iobase + i; + } + /* Simple probe. */ - if ( !fe_simple_probe( sc->addr, probe_table ) ) return 0; + if ( !fe_simple_probe( sc, probe_table ) ) return 0; + + /* Check if our I/O address matches config info. on EEPROM. */ + n = ( inb( sc->ioaddr[ FE_FMV2 ] ) & FE_FMV2_IOS ) + >> FE_FMV2_IOS_SHIFT; + if ( baseaddr[ n ] != sc->iobase ) return 0; - /* Check if our I/O address matches config info on EEPROM. */ - n = ( inb( sc->addr + FE_FMV2 ) & FE_FMV2_ADDR ) >> FE_FMV2_ADDR_SHIFT; - if ( ioaddr[ n ] != sc->addr ) return 0; + /* Find the "hardware revision." */ + revision = inb( sc->ioaddr[ FE_FMV1 ] ) & FE_FMV1_REV; /* Determine the card type. */ - switch ( inb( sc->addr + FE_FMV0 ) & FE_FMV0_MODEL ) { - case FE_FMV0_MODEL_FMV181: - sc->type = FE_TYPE_FMV181; - sc->typestr = "FMV-181"; - sc->sc_description = "Ethernet adapter: FMV-181"; + sc->typestr = NULL; + switch ( inb( sc->ioaddr[ FE_FMV0 ] ) & FE_FMV0_MEDIA ) { + case 0: + /* No interface? This doesn't seem to be an FMV-180... */ + return 0; + case FE_FMV0_MEDIUM_T: + switch ( revision ) { + case 8: + sc->typestr = "FMV-183"; + sc->sc_description = "Ethernet adapter: FMV-183"; + break; + } break; - case FE_FMV0_MODEL_FMV182: - sc->type = FE_TYPE_FMV182; - sc->typestr = "FMV-182"; - sc->sc_description = "Ethernet adapter: FMV-182"; + case FE_FMV0_MEDIUM_T | FE_FMV0_MEDIUM_5: + switch ( revision ) { + case 0: + sc->typestr = "FMV-181"; + sc->sc_description = "Ethernet adapter: FMV-181"; + break; + case 1: + sc->typestr = "FMV-181A"; + sc->sc_description = "Ethernet adapter: FMV-181A"; + break; + } + break; + case FE_FMV0_MEDIUM_2: + switch ( revision ) { + case 8: + sc->typestr = "FMV-184 (CSR = 2)"; + sc->sc_description = "Ethernet adapter: FMV-184"; + break; + } + break; + case FE_FMV0_MEDIUM_5: + switch ( revision ) { + case 8: + sc->typestr = "FMV-184 (CSR = 1)"; + sc->sc_description = "Ethernet adapter: FMV-184"; + break; + } + break; + case FE_FMV0_MEDIUM_2 | FE_FMV0_MEDIUM_5: + switch ( revision ) { + case 0: + sc->typestr = "FMV-182"; + sc->sc_description = "Ethernet adapter: FMV-182"; + break; + case 1: + sc->typestr = "FMV-182A"; + sc->sc_description = "Ethernet adapter: FMV-182A"; + break; + case 8: + sc->typestr = "FMV-184 (CSR = 3)"; + sc->sc_description = "Ethernet adapter: FMV-184"; + break; + } break; - default: - /* Unknown card type: maybe a new model, but... */ - return 0; + } + if ( sc->typestr == NULL ) { + /* Unknown card type... Hope the driver works. */ + sc->typestr = "unknown FMV-180 version"; + sc->sc_description + = "Ethernet adapter: unknown FMV-180 version"; + log( LOG_WARNING, "fe%d: %s: %x-%x-%x-%x\n", + sc->sc_unit, sc->typestr, + inb( sc->ioaddr[ FE_FMV0 ] ), + inb( sc->ioaddr[ FE_FMV1 ] ), + inb( sc->ioaddr[ FE_FMV2 ] ), + inb( sc->ioaddr[ FE_FMV3 ] ) ); } /* - * An FMV-180 has successfully been proved. + * An FMV-180 has been proved. * Determine which IRQ to be used. * - * In this version, we always get an IRQ assignment from the - * FMV-180's configuration EEPROM, ignoring that specified in - * config file. + * In this version, we give a priority to the kernel config file. + * If the EEPROM and config don't match, say it to the user for + * an attention. */ - n = ( inb( sc->addr + FE_FMV2 ) & FE_FMV2_IRQ ) >> FE_FMV2_IRQ_SHIFT; - isa_dev->id_irq = irqmap[ n ]; + n = ( inb( sc->ioaddr[ FE_FMV2 ] ) & FE_FMV2_IRS ) + >> FE_FMV2_IRS_SHIFT; + if ( dev->id_irq == NO_IRQ ) { + /* Just use the probed value. */ + dev->id_irq = irqmap[ n ]; + } else if ( dev->id_irq != irqmap[ n ] ) { + /* Don't match. */ + log( LOG_WARNING, + "fe%d: check IRQ in config; it may be incorrect", + sc->sc_unit ); + } /* * Initialize constants in the per-line structure. */ /* Get our station address from EEPROM. */ - inblk( sc->addr + FE_FMV4, sc->sc_enaddr, ETHER_ADDR_LEN ); + inblk( sc, FE_FMV4, sc->sc_enaddr, ETHER_ADDR_LEN ); /* Make sure we got a valid station address. */ if ( ( sc->sc_enaddr[ 0 ] & 0x03 ) != 0x00 @@ -674,22 +899,20 @@ fe_probe_fmv ( struct isa_device *isa_dev, struct fe_softc * sc ) && sc->sc_enaddr[ 1 ] == 0x00 && sc->sc_enaddr[ 2 ] == 0x00 ) ) return 0; - /* Register values which depend on board design. */ - sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL; - sc->proto_dlcr5 = 0; - sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_EC; - /* + * Register values which (may) depend on board design. + * * 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_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL; + sc->proto_dlcr5 = 0; sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x4KB | FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns; + sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_EC; + sc->proto_bmpr13 = FE_B13_TPTYPE_UTP | FE_B13_PORT_AUTO; /* * Minimum initialization of the hardware. @@ -698,22 +921,23 @@ fe_probe_fmv ( struct isa_device *isa_dev, struct fe_softc * sc ) */ /* Initialize ASIC. */ - outb( sc->addr + FE_FMV3, 0 ); - outb( sc->addr + FE_FMV10, 0 ); - - /* Wait for a while. I'm not sure this is necessary. FIXME. */ - DELAY(200); + outb( sc->ioaddr[ FE_FMV3 ], 0 ); + outb( sc->ioaddr[ FE_FMV10 ], 0 ); /* Initialize 86960. */ - outb( sc->addr + FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); - DELAY(200); + DELAY( 200 ); + outb( sc->ioaddr[ 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 ); + outb( sc->ioaddr[ FE_DLCR2 ], 0 ); + outb( sc->ioaddr[ FE_DLCR3 ], 0 ); + + /* "Refresh" hardware configuration. FIXME. */ + outb( sc->ioaddr[ FE_FMV2 ], inb( sc->ioaddr[ FE_FMV2 ] ) ); /* Turn the "master interrupt control" flag of ASIC on. */ - outb( sc->addr + FE_FMV3, FE_FMV3_ENABLE_FLAG ); + outb( sc->ioaddr[ FE_FMV3 ], FE_FMV3_IRQENB ); /* * That's all. FMV-180 occupies 32 I/O addresses, by the way. @@ -725,17 +949,21 @@ fe_probe_fmv ( struct isa_device *isa_dev, struct fe_softc * sc ) * Probe and initialization for Allied-Telesis AT1700/RE2000 series. */ static int -fe_probe_ati ( struct isa_device * isa_dev, struct fe_softc * sc ) +fe_probe_ati ( DEVICE * dev, struct fe_softc * sc ) { int i, n; u_char eeprom [ FE_EEPROM_SIZE ]; + u_char save16, save17; - static u_short const ioaddr [ 8 ] = + static u_short const baseaddr [ 8 ] = { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300 }; - static u_short const irqmap_lo [ 4 ] = - { IRQ3, IRQ4, IRQ5, IRQ9 }; - static u_short const irqmap_hi [ 4 ] = - { IRQ10, IRQ11, IRQ12, IRQ15 }; + static u_short const irqmaps [ 4 ][ 4 ] = + { + { IRQ3, IRQ4, IRQ5, IRQ9 }, + { IRQ10, IRQ11, IRQ12, IRQ15 }, + { IRQ3, IRQ11, IRQ5, IRQ15 }, + { IRQ10, IRQ11, IRQ14, IRQ15 }, + }; static struct fe_simple_probe_struct const probe_table [] = { { FE_DLCR2, 0x70, 0x00 }, { FE_DLCR4, 0x08, 0x00 }, @@ -747,25 +975,28 @@ fe_probe_ati ( struct isa_device * isa_dev, struct fe_softc * sc ) { 0 } }; -#if 0 - /* - * Don't probe at all if the config says we are PCMCIA... - */ - if ( isa_dev->id_flags & FE_FLAGS_PCMCIA ) return ( 0 ); -#endif + /* Assume we have 86965 and no need to restore these. */ + save16 = 0; + save17 = 0; #if FE_DEBUG >= 3 - log( LOG_INFO, "fe%d: probe (0x%x) for ATI\n", sc->sc_unit, sc->addr ); + log( LOG_INFO, "fe%d: probe (0x%x) for ATI\n", + sc->sc_unit, sc->iobase ); fe_dump( LOG_INFO, sc, NULL ); #endif /* - * See if the sepcified address is possible for MB86965A JLI mode. + * See if the specified address is possible for MB86965A JLI mode. */ for ( i = 0; i < 8; i++ ) { - if ( ioaddr[ i ] == sc->addr ) break; + if ( baseaddr[ i ] == sc->iobase ) break; + } + if ( i == 8 ) goto NOTFOUND; + + /* Setup an I/O address mapping table. */ + for ( i = 0; i < MAXREGISTERS; i++ ) { + sc->ioaddr[ i ] = sc->iobase + i; } - if ( i == 8 ) return 0; /* * We should test if MB86965A is on the base address now. @@ -775,63 +1006,99 @@ fe_probe_ati ( struct isa_device * isa_dev, struct fe_softc * sc ) * described in the Fujitsu document. On warm boot, however, * we can predict almost nothing about register values. */ - if ( !fe_simple_probe( sc->addr, probe_table ) ) return 0; + if ( !fe_simple_probe( sc, probe_table ) ) goto NOTFOUND; /* Check if our I/O address matches config info on 86965. */ - n = ( inb( sc->addr + FE_BMPR19 ) & FE_B19_ADDR ) >> FE_B19_ADDR_SHIFT; - if ( ioaddr[ n ] != sc->addr ) return 0; + n = ( inb( sc->ioaddr[ FE_BMPR19 ] ) & FE_B19_ADDR ) + >> FE_B19_ADDR_SHIFT; + if ( baseaddr[ n ] != sc->iobase ) goto NOTFOUND; /* * We are now almost sure we have an AT1700 at the given * address. So, read EEPROM through 86965. We have to write * into LSI registers to read from EEPROM. I want to avoid it - * at this stage, but I cannot test the presense of the chip + * at this stage, but I cannot test the presence of the chip * any further without reading EEPROM. FIXME. */ + save16 = inb( sc->ioaddr[ FE_BMPR16 ] ); + save17 = inb( sc->ioaddr[ FE_BMPR17 ] ); fe_read_eeprom( sc, eeprom ); + /* Make sure the EEPROM is turned off. */ + outb( sc->ioaddr[ FE_BMPR16 ], 0 ); + outb( sc->ioaddr[ FE_BMPR17 ], 0 ); + /* Make sure that config info in EEPROM and 86965 agree. */ - if ( eeprom[ FE_EEPROM_CONF ] != inb( sc->addr + FE_BMPR19 ) ) { - return 0; + if ( eeprom[ FE_EEPROM_CONF ] != inb( sc->ioaddr[ FE_BMPR19 ] ) ) { + goto NOTFOUND; } /* - * Determine the card type. - * There may be a way to identify various models. FIXME. + * The following model identification codes are stolen from + * from the NetBSD port of the fe driver. My reviewers + * suggested minor revision. */ - sc->type = FE_TYPE_AT1700; - sc->typestr = "AT1700/RE2000"; - sc->sc_description = "Ethernet adapter: AT1700 or RE2000"; + + /* Determine the card type. */ + switch (eeprom[FE_ATI_EEP_MODEL]) { + case FE_ATI_MODEL_AT1700T: + sc->typestr = "AT-1700T/RE2001"; + sc->sc_description = "Ethernet adapter: AT1700T or RE2001"; + break; + case FE_ATI_MODEL_AT1700BT: + sc->typestr = "AT-1700BT/RE2003"; + sc->sc_description = "Ethernet adapter: AT1700BT or RE2003"; + break; + case FE_ATI_MODEL_AT1700FT: + sc->typestr = "AT-1700FT/RE2009"; + sc->sc_description = "Ethernet adapter: AT1700FT or RE2009"; + break; + case FE_ATI_MODEL_AT1700AT: + sc->typestr = "AT-1700AT/RE2005"; + sc->sc_description = "Ethernet adapter: AT1700AT or RE2005"; + break; + default: + sc->typestr = "unknown AT-1700/RE2000 ?"; + sc->sc_description = "Ethernet adapter: AT1700 or RE2000 ?"; + break; + } /* - * I was told that RE2000 series has two variants on IRQ - * selection. They are 3/4/5/9 and 10/11/12/15. I don't know - * how we can distinguish which model is which. For now, we - * just trust irq setting in config. FIXME. - * - * I've heard that ATI puts an identification between these - * two models in the EEPROM. Sounds reasonable. I've also - * heard that Linux driver for AT1700 tests it. O.K. Let's - * try using it and see what happens. Anyway, we will use an - * IRQ value passed by config (i.e., user), if one is - * available. FIXME. + * Try to determine IRQ settings. + * Different models use different ranges of IRQs. */ - n = ( inb( sc->addr + FE_BMPR19 ) & FE_B19_IRQ ) >> FE_B19_IRQ_SHIFT; - if ( isa_dev->id_irq == 0 ) { - /* Try to determine IRQ settings. */ - if ( eeprom[ FE_EEP_ATI_TYPE ] & FE_EEP_ATI_TYPE_HIGHIRQ ) { - isa_dev->id_irq = irqmap_hi[ n ]; - } else { - isa_dev->id_irq = irqmap_lo[ n ]; + if ( dev->id_irq == NO_IRQ ) { + n = ( inb( sc->ioaddr[ FE_BMPR19 ] ) & FE_B19_IRQ ) + >> FE_B19_IRQ_SHIFT; + switch ( eeprom[ FE_ATI_EEP_REVISION ] & 0xf0 ) { + case 0x30: + dev->id_irq = irqmaps[ 3 ][ n ]; + break; + case 0x10: + case 0x50: + dev->id_irq = irqmaps[ 2 ][ n ]; + break; + case 0x40: + case 0x60: + if ( eeprom[ FE_ATI_EEP_MAGIC ] & 0x04 ) { + dev->id_irq = irqmaps[ 1 ][ n ]; + } else { + dev->id_irq = irqmaps[ 0 ][ n ]; + } + break; + default: + dev->id_irq = irqmaps[ 0 ][ n ]; + break; } } + /* * Initialize constants in the per-line structure. */ /* Get our station address from EEPROM. */ - bcopy( eeprom + FE_EEP_ATI_ADDR, sc->sc_enaddr, ETHER_ADDR_LEN ); + bcopy( eeprom + FE_ATI_EEP_ADDR, sc->sc_enaddr, ETHER_ADDR_LEN ); #if 1 /* @@ -851,34 +1118,35 @@ fe_probe_ati ( struct isa_device * isa_dev, struct fe_softc * sc ) && sc->sc_enaddr[ 2 ] == 0x00 ) ) return 0; #endif - /* Should find all register prototypes here. FIXME. */ - sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL; /* FIXME */ - sc->proto_dlcr5 = 0; - sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_EC; - /* * 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_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL; /* FIXME */ + sc->proto_dlcr5 = 0; sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x4KB | FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns; + sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_EC; +#if 0 /* XXXX Should we use this? FIXME. */ + sc->proto_bmpr13 = eeprom[ FE_ATI_EEP_MEDIA ]; +#else + sc->proto_bmpr13 = FE_B13_TPTYPE_UTP | FE_B13_PORT_AUTO; +#endif #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); + DELAY( 200 ); + outb( sc->ioaddr[ 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 ); + outb( sc->ioaddr[ FE_DLCR2 ], 0 ); + outb( sc->ioaddr[ FE_DLCR3 ], 0 ); #if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "end of fe_probe_ati()" ); @@ -888,14 +1156,29 @@ fe_probe_ati ( struct isa_device * isa_dev, struct fe_softc * sc ) * That's all. AT1700 occupies 32 I/O addresses, by the way. */ return 32; + + NOTFOUND: + /* + * We have no AT1700 at a given address. + * Restore BMPR16 and BMPR17 if we have destroyed them, + * hoping that the hardware on the address didn't get + * bad side effect. + */ + if ( save16 != 0 | save17 != 0 ) { + outb( sc->ioaddr[ FE_BMPR16 ], save16 ); + outb( sc->ioaddr[ FE_BMPR17 ], save17 ); + } + return ( 0 ); } /* * Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface. */ static int -fe_probe_mbh ( struct isa_device * isa_dev, struct fe_softc * sc ) +fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc ) { + int i; + static struct fe_simple_probe_struct probe_table [] = { { FE_DLCR2, 0x70, 0x00 }, { FE_DLCR4, 0x08, 0x00 }, @@ -905,14 +1188,14 @@ fe_probe_mbh ( struct isa_device * isa_dev, struct fe_softc * sc ) * 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. + * supplied by retailer 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 + * We can always verify the *first* 2 bits (in Ethernet * bit order) are "global" and "unicast" even for * unknown vendors. */ @@ -925,36 +1208,37 @@ fe_probe_mbh ( struct isa_device * isa_dev, struct fe_softc * sc ) { 0x15, 0xFF, 0x00 }, { 0x16, 0xFF, 0x00 }, { 0x17, 0xFF, 0x00 }, +#if 0 { 0x18, 0xFF, 0xFF }, { 0x19, 0xFF, 0xFF }, +#endif /* 0 */ { 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 ( dev->id_irq == NO_IRQ || ( sc->iobase & ~0x3E0 ) != 0 ) { + return ( 0 ); + } #if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "top of probe" ); #endif + /* Setup an I/O address mapping table. */ + for ( i = 0; i < MAXREGISTERS; i++ ) { + sc->ioaddr[ i ] = sc->iobase + i; + } + /* * 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; + if ( !fe_simple_probe( sc, probe_table ) ) return 0; /* Determine the card type. */ - sc->type = FE_TYPE_MBH10302; sc->typestr = "MBH10302 (PCMCIA)"; sc->sc_description = "Ethernet adapter: MBH10302 (PCMCIA)"; @@ -963,7 +1247,7 @@ fe_probe_mbh ( struct isa_device * isa_dev, struct fe_softc * sc ) */ /* Get our station address from EEPROM. */ - inblk( sc->addr + FE_MBH10, sc->sc_enaddr, ETHER_ADDR_LEN ); + inblk( sc, FE_MBH10, sc->sc_enaddr, ETHER_ADDR_LEN ); /* Make sure we got a valid station address. */ if ( ( sc->sc_enaddr[ 0 ] & 0x03 ) != 0x00 @@ -971,22 +1255,18 @@ fe_probe_mbh ( struct isa_device * isa_dev, struct fe_softc * sc ) && 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_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL; + sc->proto_dlcr5 = 0; sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x4KB | FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns; + sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_NICE; + sc->proto_bmpr13 = FE_B13_TPTYPE_UTP | FE_B13_PORT_AUTO; /* Setup hooks. We need a special initialization procedure. */ sc->init = fe_init_mbh; @@ -995,20 +1275,18 @@ fe_probe_mbh ( struct isa_device * isa_dev, struct fe_softc * sc ) * 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 ); + /* Minimal initialization of 86960. */ + DELAY( 200 ); + outb( sc->ioaddr[ 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 ); + outb( sc->ioaddr[ FE_DLCR2 ], 0 ); + outb( sc->ioaddr[ 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 ); + outb( sc->ioaddr[ FE_MBH0 ], FE_MBH0_MAGIC | FE_MBH0_INTR_DISABLE ); #endif /* @@ -1021,35 +1299,34 @@ fe_probe_mbh ( struct isa_device * isa_dev, struct fe_softc * sc ) static void fe_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 ); + /* Minimal initialization of 86960. */ + DELAY( 200 ); + outb( sc->ioaddr[ 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 ); + outb( sc->ioaddr[ FE_DLCR2 ], 0 ); + outb( sc->ioaddr[ FE_DLCR3 ], 0 ); /* Enable master interrupt flag. */ - outb( sc->addr + FE_MBH0, FE_MBH0_MAGIC | FE_MBH0_INTR_ENABLE ); + outb( sc->ioaddr[ FE_MBH0 ], FE_MBH0_MAGIC | FE_MBH0_INTR_ENABLE ); } /* * Install interface into kernel networking data structures */ static int -fe_attach ( struct isa_device *isa_dev ) +fe_attach ( DEVICE * dev ) { - struct fe_softc *sc = &fe_softc[isa_dev->id_unit]; +#if NCRD > 0 +static int alredy_ifatch[NFE]; +#endif + struct fe_softc *sc = &fe_softc[dev->id_unit]; /* * Initialize ifnet structure */ - sc->sc_if.if_softc = sc; + sc->sc_if.if_softc = sc; sc->sc_if.if_unit = sc->sc_unit; sc->sc_if.if_name = "fe"; sc->sc_if.if_output = ether_output; @@ -1060,12 +1337,12 @@ fe_attach ( struct isa_device *isa_dev ) /* * Set default interface flags. */ - sc->sc_if.if_flags = IFF_BROADCAST | IFF_MULTICAST; + sc->sc_if.if_flags = IFF_BROADCAST | IFF_SIMPLEX | 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.) + * system initialization (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(), @@ -1087,8 +1364,8 @@ fe_attach ( struct isa_device *isa_dev ) #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; + if ( dev->id_flags & FE_FLAGS_OVERRIDE_DLCR6 ) { + sc->proto_dlcr6 = dev->id_flags & FE_FLAGS_DLCR6_VALUE; } /* Find TX buffer size, based on the hardware dependent proto. */ @@ -1109,13 +1386,21 @@ fe_attach ( struct isa_device *isa_dev ) } /* Attach and stop the interface. */ - if_attach( &sc->sc_if ); +#if NCRD > 0 + if (alredy_ifatch[dev->id_unit] != 1) + { + if_attach( &sc->sc_if ); + alredy_ifatch[dev->id_unit] = 1; + } +#else + if_attach( &sc->sc_if ); +#endif /* NCRD > 0 */ fe_stop( sc->sc_unit ); /* This changes the state to IDLE. */ - ether_ifattach(&sc->sc_if); - - /* Print additional info when attached. */ - printf( "fe%d: address %6D, type %s\n", sc->sc_unit, - sc->sc_enaddr, ":" , sc->typestr ); + ether_ifattach(&sc->sc_if); + + /* Print additional info when attached. */ + printf( "fe%d: address %6D, type %s\n", sc->sc_unit, + sc->sc_enaddr, ":" , sc->typestr ); #if FE_DEBUG >= 3 { int buf, txb, bbw, sbw, ram; @@ -1151,7 +1436,7 @@ fe_attach ( struct isa_device *isa_dev ) #if NBPFILTER > 0 /* If BPF is in the kernel, call the attach for it. */ - bpfattach(&sc->sc_if, DLT_EN10MB, sizeof(struct ether_header)); + bpfattach( &sc->sc_if, DLT_EN10MB, sizeof(struct ether_header)); #endif return 1; } @@ -1188,21 +1473,21 @@ fe_stop ( int unit ) #endif /* Disable interrupts. */ - outb( sc->addr + FE_DLCR2, 0x00 ); - outb( sc->addr + FE_DLCR3, 0x00 ); + outb( sc->ioaddr[ FE_DLCR2 ], 0x00 ); + outb( sc->ioaddr[ FE_DLCR3 ], 0x00 ); /* Stop interface hardware. */ DELAY( 200 ); - outb( sc->addr + FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); + outb( sc->ioaddr[ 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 ); + outb( sc->ioaddr[ FE_DLCR0 ], 0xFF ); + outb( sc->ioaddr[ FE_DLCR1 ], 0xFF ); /* Put the chip in stand-by mode. */ DELAY( 200 ); - outb( sc->addr + FE_DLCR7, sc->proto_dlcr7 | FE_D7_POWER_DOWN ); + outb( sc->ioaddr[ FE_DLCR7 ], sc->proto_dlcr7 | FE_D7_POWER_DOWN ); DELAY( 200 ); /* Reset transmitter variables and interface flags. */ @@ -1238,10 +1523,18 @@ fe_watchdog ( struct ifnet *ifp ) struct fe_softc *sc = (struct fe_softc *)ifp; #if FE_DEBUG >= 1 + /* A "debug" message. */ log( LOG_ERR, "fe%d: transmission timeout (%d+%d)%s\n", ifp->if_unit, sc->txb_sched, sc->txb_count, - ( ifp->if_flags & IFF_UP ) ? "" : " when down" ); + ( ifp->if_flags & IFF_UP ) ? "" : " when down" ); #endif + + /* Suggest users a possible cause. */ + if ( ifp->if_oerrors > 0 ) { + log( LOG_WARNING, "fe%d: wrong IRQ setting in config?", + ifp->if_unit ); + } + #if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, NULL ); #endif @@ -1310,52 +1603,54 @@ fe_init ( int unit ) * This may also help re-programming the chip after * hot insertion of PCMCIAs. */ - outb( sc->addr + FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); + DELAY( 200 ); + outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); + DELAY( 200 ); /* Power up the chip and select register bank for DLCRs. */ - DELAY(200); - outb( sc->addr + FE_DLCR7, + DELAY( 200 ); + outb( sc->ioaddr[ FE_DLCR7 ], sc->proto_dlcr7 | FE_D7_RBS_DLCR | FE_D7_POWER_UP ); - DELAY(200); + DELAY( 200 ); /* Feed the station address. */ - outblk( sc->addr + FE_DLCR8, sc->sc_enaddr, ETHER_ADDR_LEN ); + outblk( sc, FE_DLCR8, sc->sc_enaddr, ETHER_ADDR_LEN ); /* Clear multicast address filter to receive nothing. */ - outb( sc->addr + FE_DLCR7, + outb( sc->ioaddr[ FE_DLCR7 ], sc->proto_dlcr7 | FE_D7_RBS_MAR | FE_D7_POWER_UP ); - outblk( sc->addr + FE_MAR8, fe_filter_nothing.data, FE_FILTER_LEN ); + outblk( sc, FE_MAR8, fe_filter_nothing.data, FE_FILTER_LEN ); /* Select the BMPR bank for runtime register access. */ - outb( sc->addr + FE_DLCR7, + outb( sc->ioaddr[ FE_DLCR7 ], sc->proto_dlcr7 | FE_D7_RBS_BMPR | FE_D7_POWER_UP ); /* Initialize registers. */ - outb( sc->addr + FE_DLCR0, 0xFF ); /* Clear all bits. */ - outb( sc->addr + FE_DLCR1, 0xFF ); /* ditto. */ - outb( sc->addr + FE_DLCR2, 0x00 ); - outb( sc->addr + FE_DLCR3, 0x00 ); - outb( sc->addr + FE_DLCR4, sc->proto_dlcr4 ); - outb( sc->addr + FE_DLCR5, sc->proto_dlcr5 ); - outb( sc->addr + FE_BMPR10, 0x00 ); - outb( sc->addr + FE_BMPR11, FE_B11_CTRL_SKIP ); - outb( sc->addr + FE_BMPR12, 0x00 ); - outb( sc->addr + FE_BMPR13, FE_B13_TPTYPE_UTP | FE_B13_PORT_AUTO ); - outb( sc->addr + FE_BMPR14, 0x00 ); - outb( sc->addr + FE_BMPR15, 0x00 ); + outb( sc->ioaddr[ FE_DLCR0 ], 0xFF ); /* Clear all bits. */ + outb( sc->ioaddr[ FE_DLCR1 ], 0xFF ); /* ditto. */ + outb( sc->ioaddr[ FE_DLCR2 ], 0x00 ); + outb( sc->ioaddr[ FE_DLCR3 ], 0x00 ); + outb( sc->ioaddr[ FE_DLCR4 ], sc->proto_dlcr4 ); + outb( sc->ioaddr[ FE_DLCR5 ], sc->proto_dlcr5 ); + outb( sc->ioaddr[ FE_BMPR10 ], 0x00 ); + outb( sc->ioaddr[ FE_BMPR11 ], FE_B11_CTRL_SKIP | FE_B11_MODE1 ); + outb( sc->ioaddr[ FE_BMPR12 ], 0x00 ); + outb( sc->ioaddr[ FE_BMPR13 ], sc->proto_bmpr13 ); + outb( sc->ioaddr[ FE_BMPR14 ], 0x00 ); + outb( sc->ioaddr[ FE_BMPR15 ], 0x00 ); #if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "just before enabling DLC" ); #endif /* Enable interrupts. */ - outb( sc->addr + FE_DLCR2, FE_TMASK ); - outb( sc->addr + FE_DLCR3, FE_RMASK ); + outb( sc->ioaddr[ FE_DLCR2 ], FE_TMASK ); + outb( sc->ioaddr[ FE_DLCR3 ], FE_RMASK ); /* Enable transmitter and receiver. */ - DELAY(200); - outb( sc->addr + FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_ENABLE ); - DELAY(200); + DELAY( 200 ); + outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_ENABLE ); + DELAY( 200 ); #if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "just after enabling DLC" ); @@ -1365,7 +1660,7 @@ fe_init ( int unit ) * * This may be redundant, but *if* the receive buffer were full * at this point, the driver would hang. I have experienced - * some strange hangups just after UP. I hope the following + * some strange hang-up just after UP. I hope the following * code solve the problem. * * I have changed the order of hardware initialization. @@ -1374,8 +1669,8 @@ fe_init ( int unit ) * redundant now. FIXME. */ for ( i = 0; i < FE_MAX_RECV_COUNT; i++ ) { - if ( inb( sc->addr + FE_DLCR5 ) & FE_D5_BUFEMP ) break; - outb( sc->addr + FE_BMPR14, FE_B14_SKIP ); + if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) break; + outb( sc->ioaddr[ FE_BMPR14 ], FE_B14_SKIP ); } #if FE_DEBUG >= 1 if ( i >= FE_MAX_RECV_COUNT ) { @@ -1394,9 +1689,9 @@ fe_init ( int unit ) fe_dump( LOG_INFO, sc, "after ERB loop" ); #endif - /* Do we need this here? */ - outb( sc->addr + FE_DLCR0, 0xFF ); /* Clear all bits. */ - outb( sc->addr + FE_DLCR1, 0xFF ); /* ditto. */ + /* Do we need this here? FIXME. */ + outb( sc->ioaddr[ FE_DLCR0 ], 0xFF ); /* Clear all bits. */ + outb( sc->ioaddr[ FE_DLCR1 ], 0xFF ); /* ditto. */ #if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "after FIXME" ); @@ -1408,7 +1703,7 @@ fe_init ( int unit ) sc->sc_dcstate = DC_BUSY; /* - * At this point, the interface is runnung properly, + * At this point, the interface is running properly, * except that it receives *no* packets. we then call * fe_setmode() to tell the chip what packets to be * received, based on the if_flags and multicast group @@ -1433,7 +1728,7 @@ fe_init ( int unit ) /* * This routine actually starts the transmission on the interface */ -static INLINE void +static void fe_xmit ( struct fe_softc * sc ) { /* @@ -1448,13 +1743,8 @@ fe_xmit ( struct fe_softc * sc ) sc->txb_count = 0; sc->txb_free = sc->txb_size; -#if FE_DELAYED_PADDING - /* Omit the postponed padding process. */ - sc->txb_padding = 0; -#endif - /* Start transmitter, passing packets in TX buffer. */ - outb( sc->addr + FE_BMPR10, sc->txb_sched | FE_B10_START ); + outb( sc->ioaddr[ FE_BMPR10 ], sc->txb_sched | FE_B10_START ); } /* @@ -1469,7 +1759,7 @@ fe_xmit ( struct fe_softc * sc ) void fe_start ( struct ifnet *ifp ) { - struct fe_softc *sc = IFNET2SOFTC( ifp ); + struct fe_softc *sc = ifp->if_softc; struct mbuf *m; #if FE_DEBUG >= 1 @@ -1494,8 +1784,8 @@ fe_start ( struct ifnet *ifp ) * reset the transmission buffer. (In fact, we can * reset the entire interface. I don't want to do it.) * - * If txb_count is incorrect, leaving it as is will cause - * sending of gabages after next interrupt. We have to + * If txb_count is incorrect, leaving it as-is will cause + * sending of garbage after next interrupt. We have to * avoid it. Hence, we reset the txb_count here. If * txb_free was incorrect, resetting txb_count just loose * some packets. We can live with it. @@ -1520,13 +1810,13 @@ fe_start ( struct ifnet *ifp ) /* * Stop accepting more transmission packets temporarily, when * a filter change request is delayed. Updating the MARs on - * 86960 flushes the transmisstion buffer, so it is delayed + * 86960 flushes the transmission buffer, so it is delayed * until all buffered transmission packets have been sent * out. */ if ( sc->filter_change ) { /* - * Filter change requst is delayed only when the DLC is + * Filter change request is delayed only when the DLC is * working. DLC soon raise an interrupt after finishing * the work. */ @@ -1579,13 +1869,18 @@ fe_start ( struct ifnet *ifp ) /* Start transmitter if it's idle. */ if ( sc->txb_sched == 0 ) fe_xmit( sc ); -#if 0 /* Turned of, since our interface is now duplex. */ /* - * Tap off here if there is a bpf listener. + * Tap off here if there is a bpf listener, + * and the device is *not* in promiscuous mode. + * (86960 receives self-generated packets if + * and only if it is in "receive everything" + * mode.) */ #if NBPFILTER > 0 - if ( sc->bpf ) bpf_mtap( sc->bpf, m ); -#endif + if ( sc->sc_if.if_bpf + && !( sc->sc_if.if_flags & IFF_PROMISC ) ) { + bpf_mtap( &sc->sc_if, m ); + } #endif m_freem( m ); @@ -1616,10 +1911,10 @@ fe_start ( struct ifnet *ifp ) /* * Drop (skip) a packet from receive buffer in 86960 memory. */ -static INLINE void +static void fe_droppacket ( struct fe_softc * sc ) { - outb( sc->addr + FE_BMPR14, FE_B14_SKIP ); + outb( sc->ioaddr[ FE_BMPR14 ], FE_B14_SKIP ); } /* @@ -1641,7 +1936,7 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) * Find how many packets (including this collided one) * are left unsent in transmission buffer. */ - left = inb( sc->addr + FE_BMPR10 ); + left = inb( sc->ioaddr[ FE_BMPR10 ] ); #if FE_DEBUG >= 2 log( LOG_WARNING, "fe%d: excessive collision (%d/%d)\n", @@ -1662,7 +1957,7 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) * Collision statistics has been updated. * Clear the collision flag on 86960 now to avoid confusion. */ - outb( sc->addr + FE_DLCR0, FE_D0_COLLID ); + outb( sc->ioaddr[ FE_DLCR0 ], FE_D0_COLLID ); /* * Restart transmitter, skipping the @@ -1677,7 +1972,7 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) * to reliable transport (such as TCP) are resent * by some upper layer. */ - outb( sc->addr + FE_BMPR11, + outb( sc->ioaddr[ FE_BMPR11 ], FE_B11_CTRL_SKIP | FE_B11_MODE1 ); sc->txb_sched = left - 1; } @@ -1695,8 +1990,8 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) * 86960 has a design flaw on collision count on multiple * packet transmission. When we send two or more packets * with one start command (that's what we do when the - * transmission queue is clauded), 86960 informs us number - * of collisions occured on the last packet on the + * transmission queue is crowded), 86960 informs us number + * of collisions occurred on the last packet on the * transmission only. Number of collisions on previous * packets are lost. I have told that the fact is clearly * stated in the Fujitsu document. @@ -1705,13 +2000,13 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) * count is not so important, anyway. Any comments? FIXME. */ - if ( inb( sc->addr + FE_DLCR0 ) & FE_D0_COLLID ) { + if ( inb( sc->ioaddr[ FE_DLCR0 ] ) & FE_D0_COLLID ) { /* Clear collision flag. */ - outb( sc->addr + FE_DLCR0, FE_D0_COLLID ); + outb( sc->ioaddr[ FE_DLCR0 ], FE_D0_COLLID ); /* Extract collision count from 86960. */ - col = inb( sc->addr + FE_DLCR4 ); + col = inb( sc->ioaddr[ FE_DLCR4 ] ); col = ( col & FE_D4_COL ) >> FE_D4_COL_SHIFT; if ( col == 0 ) { /* @@ -1788,18 +2083,18 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) /* * MB86960 has a flag indicating "receive queue empty." - * We just loop cheking the flag to pull out all received + * We just loop, checking the flag, to pull out all received * packets. * - * We limit the number of iterrations to avoid inifnit-loop. + * We limit the number of iterations to avoid infinite-loop. * It can be caused by a very slow CPU (some broken * peripheral may insert incredible number of wait cycles) * or, worse, by a broken MB86960 chip. */ for ( i = 0; i < FE_MAX_RECV_COUNT; i++ ) { - /* Stop the iterration if 86960 indicates no packets. */ - if ( inb( sc->addr + FE_DLCR5 ) & FE_D5_BUFEMP ) break; + /* Stop the iteration if 86960 indicates no packets. */ + if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) break; /* * Extract A receive status byte. @@ -1807,7 +2102,7 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) * use inw() to get the status byte. The significant * value is returned in lower 8 bits. */ - status = ( u_char )inw( sc->addr + FE_BMPR8 ); + status = ( u_char )inw( sc->ioaddr[ FE_BMPR8 ] ); #if FE_DEBUG >= 4 log( LOG_INFO, "fe%d: receive status = %04x\n", sc->sc_unit, status ); @@ -1831,12 +2126,13 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) * It is a sum of a header (14 bytes) and a payload. * CRC has been stripped off by the 86960. */ - len = inw( sc->addr + FE_BMPR8 ); + len = inw( sc->ioaddr[ FE_BMPR8 ] ); /* * MB86965 checks the packet length and drop big packet * before passing it to us. There are no chance we can - * get [crufty] packets. Hence, if the length exceeds + * get big packets through it, even if they are actually + * sent over a line. Hence, if the length exceeds * the specified limit, it means some serious failure, * such as out-of-sync on receive buffer management. * @@ -1875,8 +2171,8 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) if ( fe_get_packet( sc, len ) < 0 ) { /* Skip a packet, updating statistics. */ #if FE_DEBUG >= 2 - log( LOG_WARNING, "%s%d: no enough mbuf;" - " a packet (%u bytes) dropped\n", + log( LOG_WARNING, "%s%d: out of mbuf;" + " dropping a packet (%u bytes)\n", sc->sc_unit, len ); #endif sc->sc_if.if_ierrors++; @@ -1916,15 +2212,15 @@ feintr ( int unit ) /* * Get interrupt conditions, masking unneeded flags. */ - tstat = inb( sc->addr + FE_DLCR0 ) & FE_TMASK; - rstat = inb( sc->addr + FE_DLCR1 ) & FE_RMASK; + tstat = inb( sc->ioaddr[ FE_DLCR0 ] ) & FE_TMASK; + rstat = inb( sc->ioaddr[ FE_DLCR1 ] ) & FE_RMASK; if ( tstat == 0 && rstat == 0 ) break; /* * Reset the conditions we are acknowledging. */ - outb( sc->addr + FE_DLCR0, tstat ); - outb( sc->addr + FE_DLCR1, rstat ); + outb( sc->ioaddr[ FE_DLCR0 ], tstat ); + outb( sc->ioaddr[ FE_DLCR1 ], rstat ); /* * Handle transmitter interrupts. Handle these first because @@ -1947,7 +2243,7 @@ feintr ( int unit ) * we can make sure the transmission buffer is empty, * and there is a good chance that the receive queue * is empty. It will minimize the possibility of - * packet lossage. + * packet loss. */ if ( sc->filter_change && sc->txb_count == 0 && sc->txb_sched == 0 ) { @@ -1979,10 +2275,10 @@ feintr ( int unit ) * Process an ioctl request. This code needs some work - it looks * pretty ugly. */ -int -fe_ioctl ( struct ifnet *ifp, int command, caddr_t data ) +static int +fe_ioctl ( struct ifnet * ifp, int command, caddr_t data ) { - struct fe_softc *sc = IFNET2SOFTC( ifp ); + struct fe_softc *sc = ifp->if_softc; int s, error = 0; #if FE_DEBUG >= 3 @@ -2002,12 +2298,11 @@ fe_ioctl ( struct ifnet *ifp, int command, caddr_t data ) switch (ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: - fe_init( sc->sc_unit ); /* before arpwhohas */ + fe_init( sc->sc_unit ); /* before arp_ifinit */ arp_ifinit( &sc->arpcom, ifa ); break; #endif #ifdef IPX - /* * XXX - This code is probably wrong */ @@ -2018,8 +2313,7 @@ fe_ioctl ( struct ifnet *ifp, int command, caddr_t data ) if (ipx_nullhost(*ina)) ina->x_host = - *(union ipx_host *) (sc->sc_enaddr); - else { + *(union ipx_host *) (sc->sc_enaddr); else { bcopy((caddr_t) ina->x_host.c_host, (caddr_t) sc->sc_enaddr, sizeof(sc->sc_enaddr)); @@ -2032,6 +2326,13 @@ fe_ioctl ( struct ifnet *ifp, int command, caddr_t data ) break; } #endif +#ifdef INET6 + case AF_INET6: + /* IPV6 added by shin 96.2.6 */ + fe_init(sc->sc_unit); + ndp6_ifinit(&sc->arpcom, ifa); + break; +#endif #ifdef NS /* @@ -2093,7 +2394,7 @@ fe_ioctl ( struct ifnet *ifp, int command, caddr_t data ) case SIOCSIFPHYSADDR: { /* - * Set the physical (Ehternet) address of the interface. + * Set the physical (Ethernet) address of the interface. * When and by whom is this command used? FIXME. */ struct ifreq * ifr = ( struct ifreq * )data; @@ -2191,7 +2492,7 @@ fe_ioctl ( struct ifnet *ifp, int command, caddr_t data ) } /* - * Retreive packet from receive buffer and send to the next level up via + * Retrieve packet from receive buffer and send to the next level up via * ether_input(). If there is a BPF listener, give a copy to BPF, too. * Returns 0 if success, -1 if error (i.e., mbuf allocation failure). */ @@ -2227,7 +2528,7 @@ fe_get_packet ( struct fe_softc * sc, u_short len ) * least MINCLSIZE (208 bytes on FreeBSD 2.0 for x86) to * allocate a cluster. For a packet of a size between * (MHLEN - 2) to (MINCLSIZE - 2), our code violates the rule... - * On the other hand, the current code is short, simle, + * On the other hand, the current code is short, simple, * and fast, however. It does no harmful thing, just waists * some memory. Any comments? FIXME. */ @@ -2252,11 +2553,11 @@ fe_get_packet ( struct fe_softc * sc, u_short len ) /* Set the length of this packet. */ m->m_len = len; - /* The following sillines is to make NFS happy */ + /* The following silliness is to make NFS happy */ m->m_data += NFS_MAGIC_OFFSET; /* Get a packet. */ - insw( sc->addr + FE_BMPR8, m->m_data, ( len + 1 ) >> 1 ); + insw( sc->ioaddr[ FE_BMPR8 ], m->m_data, ( len + 1 ) >> 1 ); /* Get (actually just point to) the header part. */ eh = mtod( m, struct ether_header *); @@ -2305,8 +2606,7 @@ fe_get_packet ( struct fe_softc * sc, u_short len ) */ log( LOG_WARNING, "fe%d: got an unwanted packet, dst = %6D\n", - sc->sc_unit, - eh->ether_dhost , ":" ); + sc->sc_unit, eh->ether_dhost , ":" ); m_freem( m ); return 0; } @@ -2333,8 +2633,8 @@ fe_get_packet ( struct fe_softc * sc, u_short len ) * * I wrote a code for an experimental "delayed padding" technique. * When employed, it postpones the padding process for short packets. - * If xmit() occured at the moment, the padding process is omitted, and - * garbages are sent as pad data. If next packet is stored in the + * If xmit() occurred at the moment, the padding process is omitted, and + * garbage is sent as pad data. If next packet is stored in the * transmission buffer before xmit(), write_mbuf() pads the previous * packet before transmitting new packet. This *may* gain the * system performance (slightly). @@ -2342,7 +2642,7 @@ fe_get_packet ( struct fe_softc * sc, u_short len ) static void fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) { - u_short addr_bmpr8 = sc->addr + FE_BMPR8; + u_short addr_bmpr8 = sc->ioaddr[ FE_BMPR8 ]; u_short length, len; short pad; struct mbuf *mp; @@ -2350,17 +2650,6 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) u_short savebyte; /* WARNING: Architecture dependent! */ #define NO_PENDING_BYTE 0xFFFF -#if FE_DELAYED_PADDING - /* Do the "delayed padding." */ - pad = sc->txb_padding >> 1; - if ( pad > 0 ) { - while ( --pad >= 0 ) { - outw( addr_bmpr8, 0 ); - } - sc->txb_padding = 0; - } -#endif - #if FE_DEBUG >= 2 /* First, count up the total number of bytes to copy */ length = 0; @@ -2411,13 +2700,6 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) sc->txb_free -= FE_DATA_LEN_LEN + max( length, ETHER_MIN_LEN ); sc->txb_count++; -#if FE_DELAYED_PADDING - /* Postpone the packet padding if necessary. */ - if ( length < ETHER_MIN_LEN ) { - sc->txb_padding = ETHER_MIN_LEN - length; - } -#endif - /* * Transfer the data from mbuf chain to the transmission buffer. * MB86960 seems to require that data be transferred as words, and @@ -2459,16 +2741,6 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) if ( savebyte != NO_PENDING_BYTE ) { outw( addr_bmpr8, savebyte ); } - -#if ! FE_DELAYED_PADDING - /* - * Pad the packet to the minimum length if necessary. - */ - pad = ( ETHER_MIN_LEN >> 1 ) - ( length >> 1 ); - while ( --pad >= 0 ) { - outw( addr_bmpr8, 0 ); - } -#endif } /* @@ -2559,10 +2831,10 @@ fe_setmode ( struct fe_softc *sc ) * * Promiscuous mode in FreeBSD 2 is used solely by * BPF, and BPF only listens to valid (no error) packets. - * So, we ignore errornous ones even in this mode. + * So, we ignore erroneous ones even in this mode. * (Older versions of fe driver mistook the point.) */ - outb( sc->addr + FE_DLCR5, + outb( sc->ioaddr[ FE_DLCR5 ], sc->proto_dlcr5 | FE_D5_AFM0 | FE_D5_AFM1 ); sc->filter_change = 0; @@ -2575,7 +2847,7 @@ fe_setmode ( struct fe_softc *sc ) /* * Turn the chip to the normal (non-promiscuous) mode. */ - outb( sc->addr + FE_DLCR5, sc->proto_dlcr5 | FE_D5_AFM1 ); + outb( sc->ioaddr[ FE_DLCR5 ], sc->proto_dlcr5 | FE_D5_AFM1 ); /* * Find the new multicast filter value. @@ -2592,31 +2864,26 @@ fe_setmode ( struct fe_softc *sc ) sc->filter_change = 1; #if FE_DEBUG >= 3 - log( LOG_INFO, "fe%d: address filter:" - " [%02x %02x %02x %02x %02x %02x %02x %02x]\n", - sc->sc_unit, - sc->filter.data[0], sc->filter.data[1], - sc->filter.data[2], sc->filter.data[3], - sc->filter.data[4], sc->filter.data[5], - sc->filter.data[6], sc->filter.data[7] ); + log( LOG_INFO, "fe%d: address filter: [%8D]\n", + sc->sc_unit, sc->filter.data, " " ); #endif /* * We have to update the multicast filter in the 86960, A.S.A.P. * - * Note that the DLC (Data Linc Control unit, i.e. transmitter + * Note that the DLC (Data Link Control unit, i.e. transmitter * and receiver) must be stopped when feeding the filter, and - * DLC trushes all packets in both transmission and receive + * DLC trashes all packets in both transmission and receive * buffers when stopped. * - * ... Are the above sentenses correct? I have to check the + * ... Are the above sentences correct? I have to check the * manual of the MB86960A. FIXME. * - * To reduce the packet lossage, we delay the filter update + * To reduce the packet loss, we delay the filter update * process until buffers are empty. */ if ( sc->txb_sched == 0 && sc->txb_count == 0 - && !( inb( sc->addr + FE_DLCR1 ) & FE_D1_PKTRDY ) ) { + && !( inb( sc->ioaddr[ FE_DLCR1 ] ) & FE_D1_PKTRDY ) ) { /* * Buffers are (apparently) empty. Load * the new filter value into MARs now. @@ -2637,7 +2904,7 @@ fe_setmode ( struct fe_softc *sc ) /* * Load a new multicast address filter into MARs. * - * The caller must have splimp'ed befor fe_loadmar. + * The caller must have splimp'ed before fe_loadmar. * This function starts the DLC upon return. So it can be called only * when the chip is working, i.e., from the driver's point of view, when * a device is RUNNING. (I mistook the point in previous versions.) @@ -2646,21 +2913,25 @@ static void fe_loadmar ( struct fe_softc * sc ) { /* Stop the DLC (transmitter and receiver). */ - outb( sc->addr + FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); + DELAY( 200 ); + outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); + DELAY( 200 ); /* Select register bank 1 for MARs. */ - outb( sc->addr + FE_DLCR7, + outb( sc->ioaddr[ FE_DLCR7 ], sc->proto_dlcr7 | FE_D7_RBS_MAR | FE_D7_POWER_UP ); /* Copy filter value into the registers. */ - outblk( sc->addr + FE_MAR8, sc->filter.data, FE_FILTER_LEN ); + outblk( sc, FE_MAR8, sc->filter.data, FE_FILTER_LEN ); /* Restore the bank selection for BMPRs (i.e., runtime registers). */ - outb( sc->addr + FE_DLCR7, + outb( sc->ioaddr[ FE_DLCR7 ], sc->proto_dlcr7 | FE_D7_RBS_BMPR | FE_D7_POWER_UP ); /* Restart the DLC. */ - outb( sc->addr + FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_ENABLE ); + DELAY( 200 ); + outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_ENABLE ); + DELAY( 200 ); /* We have just updated the filter. */ sc->filter_change = 0; @@ -2680,20 +2951,20 @@ fe_dump ( int level, struct fe_softc * sc, char * message ) " asic = %02x %02x %02x %02x %02x %02x %02x %02x" " + %02x %02x %02x %02x %02x %02x %02x %02x\n", sc->sc_unit, message ? message : "registers", - inb( sc->addr + FE_DLCR0 ), inb( sc->addr + FE_DLCR1 ), - inb( sc->addr + FE_DLCR2 ), inb( sc->addr + FE_DLCR3 ), - inb( sc->addr + FE_DLCR4 ), inb( sc->addr + FE_DLCR5 ), - inb( sc->addr + FE_DLCR6 ), inb( sc->addr + FE_DLCR7 ), - inb( sc->addr + FE_BMPR10 ), inb( sc->addr + FE_BMPR11 ), - inb( sc->addr + FE_BMPR12 ), inb( sc->addr + FE_BMPR13 ), - inb( sc->addr + FE_BMPR14 ), inb( sc->addr + FE_BMPR15 ), - inb( sc->addr + 0x10 ), inb( sc->addr + 0x11 ), - inb( sc->addr + 0x12 ), inb( sc->addr + 0x13 ), - inb( sc->addr + 0x14 ), inb( sc->addr + 0x15 ), - inb( sc->addr + 0x16 ), inb( sc->addr + 0x17 ), - inb( sc->addr + 0x18 ), inb( sc->addr + 0x19 ), - inb( sc->addr + 0x1A ), inb( sc->addr + 0x1B ), - inb( sc->addr + 0x1C ), inb( sc->addr + 0x1D ), - inb( sc->addr + 0x1E ), inb( sc->addr + 0x1F ) ); + inb( sc->ioaddr[ FE_DLCR0 ] ), inb( sc->ioaddr[ FE_DLCR1 ] ), + inb( sc->ioaddr[ FE_DLCR2 ] ), inb( sc->ioaddr[ FE_DLCR3 ] ), + inb( sc->ioaddr[ FE_DLCR4 ] ), inb( sc->ioaddr[ FE_DLCR5 ] ), + inb( sc->ioaddr[ FE_DLCR6 ] ), inb( sc->ioaddr[ FE_DLCR7 ] ), + inb( sc->ioaddr[ FE_BMPR10 ] ), inb( sc->ioaddr[ FE_BMPR11 ] ), + inb( sc->ioaddr[ FE_BMPR12 ] ), inb( sc->ioaddr[ FE_BMPR13 ] ), + inb( sc->ioaddr[ FE_BMPR14 ] ), inb( sc->ioaddr[ FE_BMPR15 ] ), + inb( sc->ioaddr[ 0x10 ] ), inb( sc->ioaddr[ 0x11 ] ), + inb( sc->ioaddr[ 0x12 ] ), inb( sc->ioaddr[ 0x13 ] ), + inb( sc->ioaddr[ 0x14 ] ), inb( sc->ioaddr[ 0x15 ] ), + inb( sc->ioaddr[ 0x16 ] ), inb( sc->ioaddr[ 0x17 ] ), + inb( sc->ioaddr[ 0x18 ] ), inb( sc->ioaddr[ 0x19 ] ), + inb( sc->ioaddr[ 0x1A ] ), inb( sc->ioaddr[ 0x1B ] ), + inb( sc->ioaddr[ 0x1C ] ), inb( sc->ioaddr[ 0x1D ] ), + inb( sc->ioaddr[ 0x1E ] ), inb( sc->ioaddr[ 0x1F ] ) ); } #endif -- cgit v1.1