diff options
author | wollman <wollman@FreeBSD.org> | 1996-11-15 16:15:56 +0000 |
---|---|---|
committer | wollman <wollman@FreeBSD.org> | 1996-11-15 16:15:56 +0000 |
commit | ae9003a65660da13e2ba2fc4d43fe29200ebe7b7 (patch) | |
tree | 0eccdd037c81e455168c41fa218d395a41022fd5 /sys/dev/fe | |
parent | 0791e05433dac0a238aa8a0c9dd5da5bce0c73b3 (diff) | |
download | FreeBSD-src-ae9003a65660da13e2ba2fc4d43fe29200ebe7b7.zip FreeBSD-src-ae9003a65660da13e2ba2fc4d43fe29200ebe7b7.tar.gz |
Patches from driver author in PR#2010.
Submitter requests that this patch be merged into 2.2.
Submitted by: seki@sysrap.cs.fujitsu.co.jp
Diffstat (limited to 'sys/dev/fe')
-rw-r--r-- | sys/dev/fe/if_fe.c | 440 |
1 files changed, 349 insertions, 91 deletions
diff --git a/sys/dev/fe/if_fe.c b/sys/dev/fe/if_fe.c index 9a6ed58..a8fdc3c 100644 --- a/sys/dev/fe/if_fe.c +++ b/sys/dev/fe/if_fe.c @@ -21,7 +21,7 @@ */ /* - * $Id: if_fe.c,v 1.19 1996/09/08 10:44:11 phk Exp $ + * $Id: if_fe.c,v 1.20 1996/10/07 17:50:00 wollman Exp $ * * Device driver for Fujitsu MB86960A/MB86965A based Ethernet cards. * To be used with FreeBSD 2.x @@ -70,7 +70,9 @@ * o To test IPX codes. */ +#include "isa.h" #include "fe.h" +#include "crd.h" #include "bpfilter.h" #include <sys/param.h> @@ -121,11 +123,11 @@ #include <machine/clock.h> +#include <i386/isa/isa.h> #include <i386/isa/isa_device.h> #include <i386/isa/icu.h> /* PCCARD suport */ -#include "crd.h" #if NCRD > 0 #include <sys/select.h> #include <pccard/card.h> @@ -179,7 +181,7 @@ #define FE_FLAGS_OVERRIDE_DLCR6 0x0080 /* Shouldn't these be defined somewhere else such as isa_device.h? */ -#define NO_IOADDR 0xFFFFFFFF +#define NO_IOADDR (-1) #define NO_IRQ 0 /* @@ -226,6 +228,9 @@ static struct fe_softc { u_char txb_count; /* number of packets in TX buffer */ u_char txb_sched; /* number of scheduled packets */ + /* Excessive collision counter (see fe_tint() for details. */ + u_char tx_excolls; /* # of excessive collisions. */ + /* Multicast address filter management. */ u_char filter_change; /* MARs must be changed ASAP. */ struct fe_filter filter;/* new filter value. */ @@ -248,13 +253,19 @@ static void fe_watchdog ( struct ifnet * ); /* Local functions. Order of declaration is confused. FIXME. */ static int fe_probe_fmv ( DEVICE *, struct fe_softc * ); static int fe_probe_ati ( DEVICE *, struct fe_softc * ); +static void fe_init_ati ( struct fe_softc * ); +static int fe_probe_gwy ( DEVICE *, struct fe_softc * ); +#if NCRD > 0 static int fe_probe_mbh ( DEVICE *, struct fe_softc * ); static void fe_init_mbh ( struct fe_softc * ); +static int fe_probe_tdk ( DEVICE *, struct fe_softc * ); +#endif static int fe_get_packet ( struct fe_softc *, u_short ); static void fe_stop ( int ); static void fe_tint ( struct fe_softc *, u_char ); static void fe_rint ( struct fe_softc *, u_char ); static void fe_xmit ( struct fe_softc * ); +static void fe_emptybuffer ( struct fe_softc * ); static void fe_write_mbufs ( struct fe_softc *, struct mbuf * ); static struct fe_filter fe_mcaf ( struct fe_softc * ); @@ -358,6 +369,7 @@ 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); @@ -368,6 +380,8 @@ feinit(struct pccard_dev *dp, int first) #if FE_DEBUG >= 2 printf("Start Probe\n"); #endif + sc = &fe_softc[dp->isahd.id_unit]; + memcpy( sc->sc_enaddr, dp->misc, ETHER_ADDR_LEN ); if (fe_probe(&dp->isahd) == 0) return (ENXIO); #if FE_DEBUG >= 2 @@ -398,6 +412,7 @@ feinit(struct pccard_dev *dp, int first) static void feunload(struct pccard_dev *dp) { + struct fe_softc *sc = &fe_softc[dp->isahd.id_unit]; printf("fe%d: unload\n", dp->isahd.id_unit); fe_stop(dp->isahd.id_unit); } @@ -436,7 +451,10 @@ static struct fe_probe_list const fe_probe_list [] = { { fe_probe_fmv, fe_fmv_addr }, { fe_probe_ati, fe_ati_addr }, +#if NCRD > 0 { fe_probe_mbh, NULL }, /* PCMCIAs cannot be auto-detected. */ + { fe_probe_tdk, NULL }, +#endif { NULL, NULL } }; @@ -733,7 +751,15 @@ fe_probe_fmv ( DEVICE * dev, struct fe_softc * sc ) /* 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; + if ( baseaddr[ n ] != sc->iobase ) { +#if 0 + /* May not work on some revisions of the cards... FIXME. */ + return 0; +#else + /* Just log the fact and see what happens... FIXME. */ + log( LOG_WARNING, "fe%d: strange I/O config?n", sc->sc_unit ); +#endif + } /* Find the "hardware revision." */ revision = inb( sc->ioaddr[ FE_FMV1 ] ) & FE_FMV1_REV; @@ -749,6 +775,9 @@ fe_probe_fmv ( DEVICE * dev, struct fe_softc * sc ) case 8: sc->typestr = "FMV-183"; break; + case 12: + sc->typestr = "FMV-183 (on-board)"; + break; } break; case FE_FMV0_MEDIUM_T | FE_FMV0_MEDIUM_5: @@ -1068,6 +1097,9 @@ fe_probe_ati ( DEVICE * dev, struct fe_softc * sc ) fe_dump( LOG_INFO, sc, "ATI found" ); #endif + /* Setup hooks. This may solves a nasty bug. FIXME. */ + sc->init = fe_init_ati; + /* Initialize 86965. */ DELAY( 200 ); outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); @@ -1100,36 +1132,132 @@ fe_probe_ati ( DEVICE * dev, struct fe_softc * sc ) return ( 0 ); } +/* ATI specific initialization routine. */ +static void +fe_init_ati ( struct fe_softc * sc ) +{ /* - * Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface. + * I've told that the following operation "Resets" the chip. + * Hope this solve a bug which hangs up the driver under + * heavy load... FIXME. + */ + + /* Minimal initialization of 86965. */ + DELAY( 200 ); + outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); + DELAY( 200 ); + + /* "Reset" by wrting into an undocument register location. */ + outb( sc->ioaddr[ 0x1F ], 0 ); + + /* How long do we have to wait after the reset? FIXME. */ + DELAY( 300 ); +} + +/* + * Probe and initialization for Gateway Communications' old cards. */ static int -fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc ) +fe_probe_gwy ( DEVICE * dev, struct fe_softc * sc ) { - int i; + int i,type; 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 + { FE_DLCR7, 0xC0, 0x00 }, /* - * 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 retailer other than Fujitsu. + * Test *vendor* part of the address for Gateway. + * This test is essential to identify Gateway's cards. + * We shuld define some symbolic names for the + * following offsets. FIXME. + */ + { 0x18, 0xFF, 0x00 }, + { 0x19, 0xFF, 0x00 }, + { 0x1A, 0xFF, 0x61 }, + { 0 } + }; + + /* + * We need explicit IRQ and supported address. + * I'm not sure which address and IRQ is possible for Gateway + * Ethernet family. The following accepts everything. FIXME. */ - { FE_MBH10, 0xFF, 0x00 }, - { FE_MBH11, 0xFF, 0x00 }, - { FE_MBH12, 0xFF, 0x0E }, -#else + 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 the card is on its address. */ + if ( !fe_simple_probe( sc, probe_table ) ) { + return 0; + } + + /* Determine the card type. */ + sc->typestr = "Gateway Ethernet w/ Fujitsu chipset"; + + /* Get our station address from EEPROM. */ + inblk( sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN ); + /* + * Program the 86960 as follows: + * SRAM: 16KB, 100ns, byte-wide access. + * Transmission buffer: 2KB x 2. + * System bus interface: 16 bits. + * Make sure to clear out ID bits in DLCR7 + * (They actually are Encoder/Decoder control in NICE.) + */ + sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL; + sc->proto_dlcr5 = 0; + sc->proto_dlcr6 = FE_D6_BUFSIZ_16KB | FE_D6_TXBSIZ_2x2KB + | FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns; + sc->proto_dlcr7 = FE_D7_BYTSWP_LH; + sc->proto_bmpr13 = 0; + + /* 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->ioaddr[ FE_DLCR2 ], 0 ); + outb( sc->ioaddr[ FE_DLCR3 ], 0 ); + + /* That's all. The card occupies 32 I/O addresses, as always. */ + return 32; +} + +#if NCRD > 0 + /* + * Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface. + * Note that this is for 10302 only; MBH10304 is handled by fe_probe_tdk(). + */ +static int +fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc ) +{ + int i,type; + + static struct fe_simple_probe_struct probe_table [] = { + { FE_DLCR0, 0x09, 0x00 }, + { FE_DLCR2, 0x79, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { FE_DLCR6, 0xFF, 0xB6 }, + /* + * The following location has the first byte of the card's + * Ethernet (MAC) address. * We can always verify the *first* 2 bits (in Ethernet - * bit order) are "global" and "unicast" even for - * unknown vendors. + * bit order) are "global" and "unicast" for any vendors'. */ { FE_MBH10, 0x03, 0x00 }, -#endif + /* Just a gap? Seems reliable, anyway. */ { 0x12, 0xFF, 0x00 }, { 0x13, 0xFF, 0x00 }, @@ -1140,7 +1268,7 @@ fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc ) #if 0 { 0x18, 0xFF, 0xFF }, { 0x19, 0xFF, 0xFF }, -#endif /* 0 */ +#endif { 0 } }; @@ -1178,10 +1306,9 @@ fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc ) 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 - || ( sc->sc_enaddr[ 0 ] == 0x00 + if ( sc->sc_enaddr[ 0 ] == 0x00 && sc->sc_enaddr[ 1 ] == 0x00 - && sc->sc_enaddr[ 2 ] == 0x00 ) ) return 0; + && sc->sc_enaddr[ 2 ] == 0x00 ) return 0; /* * Program the 86960 as follows: @@ -1240,6 +1367,92 @@ fe_init_mbh ( struct fe_softc * sc ) outb( sc->ioaddr[ FE_MBH0 ], FE_MBH0_MAGIC | FE_MBH0_INTR_ENABLE ); } +#endif /* NCRD > 0 */ + +#if NCRD > 0 +/* + * Probe and initialization for TDK/CONTEC PCMCIA Ethernet interface. + * by MASUI Kenji <masui@cs.titech.ac.jp> + * + * (Contec uses TDK Ethenet chip -- hosokawa) + * + * This version of fe_probe_tdk has been rewrote to handle + * *generic* PC card implementation of Fujitsu MB8696x family. The + * name _tdk is just for a historical reason. :-) + */ +static int +fe_probe_tdk ( DEVICE * dev, struct fe_softc * sc ) +{ + int i; + + static struct fe_simple_probe_struct probe_table [] = { + { FE_DLCR2, 0x70, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + /* { FE_DLCR5, 0x80, 0x00 }, Does not work well. */ + { 0 } + }; + + if ( dev->id_irq == NO_IRQ ) { + return ( 0 ); + } + + /* Setup an I/O address mapping table. */ + for ( i = 0; i < MAXREGISTERS; i++ ) { + sc->ioaddr[ i ] = sc->iobase + i; + } + + /* + * See if C-NET(PC)C is on its address. + */ + + if ( !fe_simple_probe( sc, probe_table ) ) return 0; + + /* Determine the card type. */ + sc->typestr = "Generic MB8696x Ethernet (PCMCIA)"; + + /* + * Initialize constants in the per-line structure. + */ + + /* The station address *must*be* already in sc_enaddr; + 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; + + /* + * Program the 86965 as follows: + * SRAM: 32KB, 100ns, byte-wide access. + * Transmission buffer: 4KB x 2. + * System bus interface: 16 bits. + * XXX: Should we remove IDENT_NICE from DLCR7? Or, + * even add IDENT_EC instead? FIXME. + */ + 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; + + /* Minimul initialization of 86960. */ + DELAY( 200 ); + outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); + DELAY( 200 ); + + /* Disable all interrupts. */ + outb( sc->ioaddr[ FE_DLCR2 ], 0 ); + outb( sc->ioaddr[ FE_DLCR3 ], 0 ); + + /* + * That's all. C-NET(PC)C occupies 16 I/O addresses. + * XXX: Are there any card with 32 I/O addresses? FIXME. + */ + return 16; +} +#endif + /* * Install interface into kernel networking data structures */ @@ -1453,13 +1666,11 @@ fe_watchdog ( struct ifnet *ifp ) 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" ); -#endif - - /* Suggest users a possible cause. */ - if ( ifp->if_oerrors > 0 ) { - log( LOG_WARNING, "fe%d: wrong IRQ setting in config?", + if ( sc->sc_if.if_opackets == 0 && sc->sc_if.if_ipackets == 0 ) { + log( LOG_WARNING, "fe%d: wrong IRQ setting in config?\n", ifp->if_unit ); } +#endif #if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, NULL ); @@ -1581,11 +1792,12 @@ fe_init ( int unit ) #if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "just after enabling DLC" ); #endif + /* * Make sure to empty the receive buffer. * * This may be redundant, but *if* the receive buffer were full - * at this point, the driver would hang. I have experienced + * at this point, then the driver would hang. I have experienced * some strange hang-up just after UP. I hope the following * code solve the problem. * @@ -1593,29 +1805,24 @@ fe_init ( int unit ) * I think the receive buffer cannot have any packets at this * point in this version. The following code *must* be * redundant now. FIXME. + * + * I've heard a rumore that on some PC card implementation of + * 8696x, the receive buffer can have some data at this point. + * The following message helps discovering the fact. FIXME. */ - for ( i = 0; i < FE_MAX_RECV_COUNT; i++ ) { - 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 ) { - log( LOG_ERR, "fe%d: cannot empty receive buffer\n", + if ( !( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) ) { + log( LOG_WARNING, + "fe%d: receive buffer has some data after reset\n", sc->sc_unit ); + + fe_emptybuffer( sc ); } -#endif -#if FE_DEBUG >= 3 - if ( i < FE_MAX_RECV_COUNT ) { - log( LOG_INFO, "fe%d: receive buffer emptied (%d)\n", - sc->sc_unit, i ); - } -#endif #if FE_DEBUG >= 3 fe_dump( LOG_INFO, sc, "after ERB loop" ); #endif - /* Do we need this here? FIXME. */ + /* Do we need this here? Actually, no. I must be paranoia. */ outb( sc->ioaddr[ FE_DLCR0 ], 0xFF ); /* Clear all bits. */ outb( sc->ioaddr[ FE_DLCR1 ], 0xFF ); /* ditto. */ @@ -1665,6 +1872,7 @@ fe_xmit ( struct fe_softc * sc ) sc->txb_sched = sc->txb_count; sc->txb_count = 0; sc->txb_free = sc->txb_size; + sc->tx_excolls = 0; /* Start transmitter, passing packets in TX buffer. */ outb( sc->ioaddr[ FE_BMPR10 ], sc->txb_sched | FE_B10_START ); @@ -1762,7 +1970,8 @@ fe_start ( struct ifnet *ifp ) * (i.e., minimum packet sized) packets rapidly. An 8KB * buffer can hold 130 blocks of 62 bytes long... */ - if ( sc->txb_free < ETHER_MAX_LEN - ETHER_CRC_LEN + FE_DATA_LEN_LEN ) { + if ( sc->txb_free + < ETHER_MAX_LEN - ETHER_CRC_LEN + FE_DATA_LEN_LEN ) { /* No room. */ goto indicate_active; } @@ -1790,7 +1999,9 @@ fe_start ( struct ifnet *ifp ) fe_write_mbufs( sc, m ); /* Start transmitter if it's idle. */ - if ( sc->txb_sched == 0 ) fe_xmit( sc ); + if ( ( sc->txb_count > 0 ) && ( sc->txb_sched == 0 ) ) { + fe_xmit( sc ); + } /* * Tap off here if there is a bpf listener, @@ -1835,9 +2046,69 @@ fe_start ( struct ifnet *ifp ) * Drop (skip) a packet from receive buffer in 86960 memory. */ static void -fe_droppacket ( struct fe_softc * sc ) +fe_droppacket ( struct fe_softc * sc, int len ) { + int i; + + /* + * 86960 manual says that we have to read 8 bytes from the buffer + * before skip the packets and that there must be more than 8 bytes + * remaining in the buffer when issue a skip command. + * Remember, we have already read 4 bytes before come here. + */ + if ( len > 12 ) { + /* Read 4 more bytes, and skip the rest of the packet. */ + ( void )inw( sc->ioaddr[ FE_BMPR8 ] ); + ( void )inw( sc->ioaddr[ FE_BMPR8 ] ); outb( sc->ioaddr[ FE_BMPR14 ], FE_B14_SKIP ); + } else { + /* We should not come here unless receiving RUNTs. */ + for ( i = 0; i < len; i += 2 ) { + ( void )inw( sc->ioaddr[ FE_BMPR8 ] ); + } + } +} + +/* + * Empty receiving buffer. + */ +static void +fe_emptybuffer ( struct fe_softc * sc ) +{ + int i; + u_char saved_dlcr5; + +#if FE_DEBUG >= 1 + log( LOG_WARNING, "fe%d: emptying receive buffer", sc->sc_unit ); +#endif + /* + * Stop receiving packets, temporarily. + */ + saved_dlcr5 = inb( sc->ioaddr[ FE_DLCR5 ] ); + outb( sc->ioaddr[ FE_DLCR5 ], sc->proto_dlcr5 ); + + /* + * When we come here, the receive buffer management should + * have been broken. So, we cannot use skip operation. + */ + for ( i = 0; i < sc->txb_size; i += 2 ) { + if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) break; + ( void )inw( sc->ioaddr[ FE_BMPR8 ] ); + } + + /* + * Double check. + */ + if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) { + log( LOG_ERR, "fe%d: could not empty receive buffer\n", + sc->sc_unit ); + /* Hmm. What should I do if this happens? FIXME. */ + } + + /* + * Restart receiving packets. + */ + outb( sc->ioaddr[ FE_DLCR5 ], saved_dlcr5 ); } /* @@ -1870,15 +2141,8 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) #endif /* - * Update statistics. - */ - sc->sc_if.if_collisions += 16; - sc->sc_if.if_oerrors++; - sc->sc_if.if_opackets += sc->txb_sched - left; - - /* - * Collision statistics has been updated. - * Clear the collision flag on 86960 now to avoid confusion. + * Clear the collision flag (in 86960) here + * to avoid confusing statistics. */ outb( sc->ioaddr[ FE_DLCR0 ], FE_D0_COLLID ); @@ -1897,7 +2161,9 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) */ outb( sc->ioaddr[ FE_BMPR11 ], FE_B11_CTRL_SKIP | FE_B11_MODE1 ); - sc->txb_sched = left - 1; + + /* Update statistics. */ + sc->tx_excolls++; } /* @@ -1953,10 +2219,12 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) } /* - * Update total number of successfully - * transmitted packets. + * Update transmission statistics. + * Be sure to reflect number of excessive collisions. */ - sc->sc_if.if_opackets += sc->txb_sched; + sc->sc_if.if_opackets += sc->txb_sched - sc->tx_excolls; + sc->sc_if.if_oerrors += sc->tx_excolls; + sc->sc_if.if_collisions += sc->tx_excolls * 16; sc->txb_sched = 0; /* @@ -2032,6 +2300,13 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) #endif /* + * Extract the packet length. + * It is a sum of a header (14 bytes) and a payload. + * CRC has been stripped off by the 86960. + */ + len = inw( sc->ioaddr[ FE_BMPR8 ] ); + + /* * If there was an error, update statistics and drop * the packet, unless the interface is in promiscuous * mode. @@ -2039,56 +2314,38 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) if ( ( status & 0xF0 ) != 0x20 ) { if ( !( sc->sc_if.if_flags & IFF_PROMISC ) ) { sc->sc_if.if_ierrors++; - fe_droppacket(sc); + fe_droppacket( sc, len ); continue; } } /* - * Extract the packet length. - * It is a sum of a header (14 bytes) and a payload. - * CRC has been stripped off by the 86960. - */ - len = inw( sc->ioaddr[ FE_BMPR8 ] ); - - /* - * MB86965 checks the packet length and drop big packet + * MB86960 checks the packet length and drop big packet * before passing it to us. There are no chance we can * 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. * - * Is this statement true? FIXME. + * Same for short packets, since we have programmed + * 86960 to drop short packets. */ - if ( len > ETHER_MAX_LEN - ETHER_CRC_LEN || len < ETHER_MIN_LEN- ETHER_CRC_LEN ) { -#if FE_DEBUG >= 2 + if ( len > ETHER_MAX_LEN - ETHER_CRC_LEN + || len < ETHER_MIN_LEN - ETHER_CRC_LEN ) { +#if FE_DEBUG >= 1 log( LOG_WARNING, "fe%d: received a %s packet? (%u bytes)\n", sc->sc_unit, - len < ETHER_MIN_SIZE- ETHER_CRC_SIZE ? "partial" : "big", + len < ETHER_MIN_LEN - ETHER_CRC_LEN + ? "partial" : "big", len ); #endif sc->sc_if.if_ierrors++; - fe_droppacket( sc ); + fe_emptybuffer( sc ); continue; } /* - * Check for a short (RUNT) packet. We *do* check - * but do nothing other than print a message. - * Short packets are illegal, but does nothing bad - * if it carries data for upper layer. - */ -#if FE_DEBUG >= 2 - if ( len < ETHER_MIN_LEN - ETHER_CRC_LEN) { - log( LOG_WARNING, - "fe%d: received a short packet? (%u bytes)\n", - sc->sc_unit, len ); - } -#endif - - /* * Go get a packet. */ if ( fe_get_packet( sc, len ) < 0 ) { @@ -2099,7 +2356,7 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) sc->sc_unit, len ); #endif sc->sc_if.if_ierrors++; - fe_droppacket( sc ); + fe_droppacket( sc, len ); /* * We stop receiving packets, even if there are @@ -2588,7 +2845,8 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) * it should be a bug of upper layer. We just ignore it. * ... Partial (too short) packets, neither. */ - if ( ! ETHER_IS_VALID_LEN(length + ETHER_CRC_LEN)) { + if ( length < ETHER_HDR_LEN + || length > ETHER_MAX_LEN - ETHER_CRC_LEN ) { log( LOG_ERR, "fe%d: got an out-of-spec packet (%u bytes) to send\n", sc->sc_unit, length ); |