Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 9 Jan 1997 05:56:14 +0900 (JST)
From:      seki@sysrap.cs.fujitsu.co.jp
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   i386/2421: Update of fe driver, fixing miscellaneous bugs
Message-ID:  <199701082056.FAA16579@nile.sysrap.cs.fujitsu.co.jp>
Resent-Message-ID: <199701082110.NAA29495@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         2421
>Category:       i386
>Synopsis:       Update of fe driver, fixing miscellaneous bugs
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jan  8 13:10:01 PST 1997
>Last-Modified:
>Originator:     Masahiro Sekiguchi
>Organization:
Fujitsu Limited
>Release:        FreeBSD 2.2-BETA_A i386
>Environment:

	FreeBSD 2.2 Beta (and -current) with fe supported Ethernet cards.

>Description:

	Miscellaneous bugs are fixed, as well as typo and/or out-of-dated
	comments.  Fixed bugs are:

	Probe for fe compatible PC cards sometimes failed under some
	condition.  ->  It was confused by ISA probe code.  PC card
	probe and ISA probe is now separated.

	Recovery routine from a "should-never-happen" condition of
	out-of-sync receive buffer had a bug.  ->  Recovery strategy
	has been modified to make the process more reliable.

	I have reported that the driver misses receiver interrupts.  ->
	I could not repeat it with my machines, but I added a code to
	detect and recover the case.

	If an mbuf structure for transmission has a wrong m_pkthdr.len
	value, and the network load is heavy, fe crushes.  (Refer to
	kern/2415.)  ->  A code	to verify the packet length is made
	enabled as a default.

>How-To-Repeat:

	N/A

>Fix:
	
	Please apply the following patch.

	Note that the patch fixes two files; sys/i386/isa/ic/mb86960.h and
	sys/i386/isa/if_fe.c.  Run patch on the directory sys/i386/isa with
	the option -p0.

--- ic/mb86960.old.h	Mon Apr 24 03:31:50 1995
+++ ic/mb86960.h	Wed Jan  8 16:14:55 1997
@@ -20,10 +20,8 @@
  * SUCH DAMAGE.
  */
 
-#define FE_MB86960_H_VERSION "mb86960.h ver. 0.8"
-
 /*
- * Registers of Fujitsu MB86960A/MB86965A Ethernet controller.
+ * Registers of Fujitsu MB86960A/MB86965A series Ethernet controllers.
  * Written and contributed by M.S. <seki@sysrap.cs.fujitsu.co.jp>
  */
 
@@ -84,7 +82,7 @@
 #define FE_BMPR14	14
 #define FE_BMPR15	15
 
-/* More BMPRs, only on MB86965A, accessible only when JLI mode.  */
+/* More BMPRs, only on 86965, accessible only when JLI mode.  */
 #define FE_BMPR16	16
 #define FE_BMPR17	17
 #define FE_BMPR18	18
@@ -96,16 +94,20 @@
  * know the official names for each flags and fields.  The following
  * names are assigned by me (the author of this file,) since I cannot
  * mnemorize hexadecimal constants for all of these functions.
- * Comments?  FIXME.
+ * Comments?
+ *
+ * I've got documents from Fujitsu web site, recently.  However, it's
+ * too late.  Names for some fields (bits) are kept different from
+ * those used in the Fujitsu documents...
  */
 
 /* DLCR0 -- transmitter status */
-#define FE_D0_BUSERR	0x01	/* Bus write error			*/
+#define FE_D0_BUSERR	0x01	/* Bus write error?			*/
 #define FE_D0_COLL16	0x02	/* Collision limit (16) encountered	*/
 #define FE_D0_COLLID	0x04	/* Collision on last transmission	*/
 #define FE_D0_JABBER	0x08	/* Jabber				*/
 #define FE_D0_CRLOST	0x10	/* Carrier lost on last transmission	*/
-#define FE_D0_PKTRCD	0x20	/* No corrision on last transmission	*/
+#define FE_D0_PKTRCD	0x20	/* Last packet looped back correctly	*/
 #define FE_D0_NETBSY	0x40	/* Network Busy (Carrier Detected)	*/
 #define FE_D0_TXDONE	0x80	/* Transmission complete		*/
 
@@ -141,7 +143,7 @@
 /* DLCR4 -- transmitter operation mode */
 #define FE_D4_DSC	0x01	/* Disable carrier sense on trans.	*/
 #define FE_D4_LBC	0x02	/* Loop back test control		*/
-#define FE_D4_CNTRL	0x04	/* - ???				*/
+#define FE_D4_CNTRL	0x04	/* - tied to CNTRL pin of the chip	*/
 #define FE_D4_TEST1	0x08	/* Test output #1			*/
 #define FE_D4_COL	0xF0	/* Collision counter			*/
 
@@ -208,12 +210,13 @@
 #define FE_D7_POWER_DOWN	0x00	/* Power down (stand-by) mode	*/
 #define FE_D7_POWER_UP		0x20	/* Normal operation		*/
 
-#define FE_D7_IDENT_NICE	0x80
-#define FE_D7_IDENT_EC		0xC0
+#define FE_D7_IDENT_TDK		0x00	/* TDK chips?			*/
+#define FE_D7_IDENT_NICE	0x80	/* Fujitsu NICE (86960)		*/
+#define FE_D7_IDENT_EC		0xC0	/* Fujitsu EtherCoupler (86965)	*/
 
 /* DLCR8 thru DLCR13 are for Ethernet station address.  */
 
-/* DLCR14 and DLCR15 are for TDR.  (BTW, what is TDR?  FIXME.)  */
+/* DLCR14 and DLCR15 are for TDR.  (TDR is used for cable diagnostic.)  */
 
 /* MAR8 thru MAR15 are for Multicast address filter.  */
 
@@ -241,7 +244,7 @@
 #define FE_B13_PORT	0x18	/* Port (TP/AUI) selection		*/
 #define FE_B13_LNKTST	0x20	/* Link test enable			*/
 #define FE_B13_SQTHLD	0x40	/* Lower squelch threshold		*/
-#define FE_B13_IOUNLK	0x80	/* Change I/O base address		*/
+#define FE_B13_IOUNLK	0x80	/* Change I/O base address, on JLI mode	*/
 
 #define FE_B13_BSTCTL_1		0x00
 #define FE_B13_BSTCTL_4		0x01
@@ -280,9 +283,9 @@
 /* BMPR17 -- EEPROM data */
 #define FE_B17_DATA	0x80	/* EEPROM data bit			*/
 
-/* BMPR18 ??? */
+/* BMPR18 -- cycle I/O address setting in JLI mode */
 
-/* BMPR19 -- ISA interface configuration */
+/* BMPR19 -- ISA interface configuration in JLI mode */
 #define FE_B19_IRQ		0xC0
 #define FE_B19_IRQ_SHIFT	6
 
@@ -293,6 +296,21 @@
 #define FE_B19_ADDR_SHIFT	0
 
 /*
+ * An extra I/O port address to reset 86965.  This location is called
+ * "ID ROM area" by Fujitsu document.
+ */
+
+/*
+ * Flags in Receive Packet Header... Basically same layout as DLCR1.
+ */
+#define FE_RPH_OVRFLO	FE_D1_OVRFLO
+#define FE_RPH_CRCERR	FE_D1_CRCERR
+#define FE_RPH_ALGERR	FE_D1_ALGERR
+#define FE_RPH_SRTPKT	FE_D1_SRTPKT
+#define FE_RPH_RMTRST	FE_D1_RMTRST
+#define FE_RPH_GOOD	0x20	/* Good packet follows			*/
+
+/*
  * EEPROM specification (of JLI mode).
  */
 
@@ -303,7 +321,7 @@
 #define FE_EEPROM_CONF	0
 
 /*
- * Some 86960 specific constants.
+ * Some 8696x specific constants.
  */
 
 /* Length (in bytes) of a Multicast Address Filter.  */
--- if_fe.old.c	Sun Nov 17 06:34:19 1996
+++ if_fe.c	Wed Jan  8 16:15:04 1997
@@ -380,9 +380,24 @@
 #if FE_DEBUG >= 2
		printf("Start Probe\n");
 #endif
+		/* Initialize "minimum" parts of our softc.  */
		sc = &fe_softc[dp->isahd.id_unit];
-		memcpy( sc->sc_enaddr, dp->misc, ETHER_ADDR_LEN );
-		if (fe_probe(&dp->isahd) == 0)
+		sc->sc_unit = dp->isahd.id_unit;
+		sc->iobase = dp->isahd.id_iobase;
+
+		/* Use Ethernet address got from CIS, if one is available.  */
+		if ((dp->misc[0] & 0x03) == 0x00
+		    && (dp->misc[0] | dp->misc[1] | dp->misc[2]) != 0) {
+		       /* Yes, it looks like a valid Ether address.  */
+			bcopy(dp->misc, sc->sc_enaddr, ETHER_ADDR_LEN);
+		} else {
+			/* Indicate we have no Ether address in CIS.  */
+			bzero(sc->sc_enaddr, ETHER_ADDR_LEN);
+		}
+
+		/* Probe supported PC card models.  */
+		if (fe_probe_tdk(&dp->isahd, sc) == 0
+		 && fe_probe_mbh(&dp->isahd, sc) == 0)
			return (ENXIO);
 #if FE_DEBUG >= 2
		printf("Start attach\n");
@@ -451,10 +466,7 @@
 {
	{ 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
+	{ fe_probe_gwy, NULL },		/* GWYs cannot be auto detected.  */
	{ NULL, NULL }
 };
 
@@ -1166,7 +1178,7 @@
		{ FE_DLCR2, 0x70, 0x00 },
		{ FE_DLCR4, 0x08, 0x00 },
		{ FE_DLCR7, 0xC0, 0x00 },
-	/*
+		/*
		 * 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
@@ -1236,7 +1248,7 @@
 }
 
 #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().
  */
@@ -1377,8 +1389,8 @@
  * (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. :-)
+ * *generic* PC card implementation of Fujitsu MB8696x and compatibles.
+ * The name _tdk is just for a historical reason.  <seki> :-)
  */
 static int
 fe_probe_tdk ( DEVICE * dev, struct fe_softc * sc )
@@ -1392,13 +1404,25 @@
                 { 0 }
         };
 
+	/* We need an IRQ.  */
         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;
+	/* Generic driver needs Ethernet address taken from CIS.  */
+	if (sc->arpcom.ac_enaddr[0] == 0
+	 && sc->arpcom.ac_enaddr[1] == 0
+	 && sc->arpcom.ac_enaddr[2] == 0) {
+		return 0;
+	}
+
+        /* Setup an I/O address mapping table; we need only 16 ports.  */
+        for (i = 0; i < 16; i++) {
+                sc->ioaddr[i] = sc->iobase + i;
+        }
+	/* Fill unused slots with a safe address.  */
+        for (i = 16; i < MAXREGISTERS; i++) {
+                sc->ioaddr[i] = sc->iobase;
         }
 
         /*
@@ -1447,8 +1471,17 @@
 
         /*
          * That's all.  C-NET(PC)C occupies 16 I/O addresses.
-	 * XXX: Are there any card with 32 I/O addresses?  FIXME.
-         */
+	 *
+	 * Some PC cards (e.g., TDK and Contec) have 16 I/O addresses,
+	 * while some others (e.g., Fujitsu) have 32.  Fortunately,
+	 * this generic driver never accesses latter 16 ports in 32
+	 * ports cards.  So, we can assume the *generic* PC cards
+	 * always have 16 ports.
+	 *
+	 * Moreover, PC card probe is isolated from ISA probe, and PC
+	 * card probe routine doesn't use "# of ports" returned by this
+	 * function.  16 v.s. 32 is not important now.
+	 */
         return 16;
 }
 #endif
@@ -2078,7 +2111,7 @@
	int i;
	u_char saved_dlcr5;
 
-#if FE_DEBUG >= 1
+#if FE_DEBUG >= 2
	log( LOG_WARNING, "fe%d: emptying receive buffer", sc->sc_unit );
 #endif
	/*
@@ -2086,12 +2119,14 @@
	 */
	saved_dlcr5 = inb( sc->ioaddr[ FE_DLCR5 ] );
	outb( sc->ioaddr[ FE_DLCR5 ], sc->proto_dlcr5 );
+	DELAY(1300);
 
	/*
	 * When we come here, the receive buffer management should
	 * have been broken.  So, we cannot use skip operation.
+	 * Just discard everything in the buffer.
	 */
-	for ( i = 0; i < sc->txb_size; i += 2 ) {
+	for (i = 0; i < 32768; i++) {
		if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) break;
		( void )inw( sc->ioaddr[ FE_BMPR8 ] );
	}
@@ -2259,7 +2294,7 @@
	 */
	if ( rstat & ( FE_D1_OVRFLO | FE_D1_CRCERR
		     | FE_D1_ALGERR | FE_D1_SRTPKT ) ) {
-#if FE_DEBUG >= 3
+#if FE_DEBUG >= 2
		log( LOG_WARNING,
			"fe%d: receive error: %s%s%s%s(%02x)\n",
			sc->sc_unit,
@@ -2278,11 +2313,9 @@
	 * packets.
	 *
	 * 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.
+	 * The upper bound is set to unrealistic high value.
	 */
-	for ( i = 0; i < FE_MAX_RECV_COUNT; i++ ) {
+	for (i = 0; i < FE_MAX_RECV_COUNT * 2; i++) {
 
		/* Stop the iteration if 86960 indicates no packets.  */
		if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) break;
@@ -2306,19 +2339,25 @@
		 */
		len = inw( sc->ioaddr[ FE_BMPR8 ] );
 
+#if FE_DEBUG >= 1
		/*
-		 * If there was an error, update statistics and drop
-		 * the packet, unless the interface is in promiscuous
-		 * mode.
-		 */
-		if ( ( status & 0xF0 ) != 0x20 ) {
-			if ( !( sc->sc_if.if_flags & IFF_PROMISC ) ) {
-				sc->sc_if.if_ierrors++;
-				fe_droppacket( sc, len );
-				continue;
-			}
+		 * If there was an error with the received packet, it
+		 * must be an indication of out-of-sync on receive
+		 * buffer, because we have programmed the 8696x to
+		 * to discard errored packets, even when the interface
+		 * is in promiscuous mode.  We have to re-synchronize.
+		 */
+		if (!(status & FE_RPH_GOOD)) {
+			log(LOG_ERR,
+			    "fe%d: corrupted receive status byte (%02x)\n",
+			    sc->arpcom.ac_if.if_unit, status);
+			sc->arpcom.ac_if.if_ierrors++;
+			fe_emptybuffer( sc );
+			break;
		}
+#endif
 
+#if FE_DEBUG >= 1
		/*
		 * MB86960 checks the packet length and drop big packet
		 * before passing it to us.  There are no chance we can
@@ -2332,38 +2371,40 @@
		 */
		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_LEN - ETHER_CRC_LEN
					? "partial" : "big",
				len );
-#endif
			sc->sc_if.if_ierrors++;
			fe_emptybuffer( sc );
-			continue;
+			break;
		}
+#endif
 
		/*
		 * Go get a packet.
		 */
		if ( fe_get_packet( sc, len ) < 0 ) {
-			/* Skip a packet, updating statistics.  */
+
 #if FE_DEBUG >= 2
			log( LOG_WARNING, "%s%d: out of mbuf;"
			    " dropping a packet (%u bytes)\n",
			    sc->sc_unit, len );
 #endif
+
+			/* Skip a packet, updating statistics.  */
			sc->sc_if.if_ierrors++;
			fe_droppacket( sc, len );
 
			/*
-			 * We stop receiving packets, even if there are
-			 * more in the buffer.  We hope we can get more
-			 * mbuf next time.
+			 * Try extracting other packets, although they will
+			 * cause out-of-mbuf error again.  This is required
+			 * to keep receiver interrupt comming.
+			 * (Earlier versions had a bug on this point.)
			 */
-			return;
+			continue;
		}
 
		/* Successfully received a packet.  Update stat.  */
@@ -2394,6 +2435,26 @@
		 */
		tstat = inb( sc->ioaddr[ FE_DLCR0 ] ) & FE_TMASK;
		rstat = inb( sc->ioaddr[ FE_DLCR1 ] ) & FE_RMASK;
+
+#if FE_DEBUG >= 1
+		/* Test for a "dead-lock" condition.  */
+		if ((rstat & FE_D1_PKTRDY) == 0
+		    && (inb(sc->ioaddr[FE_DLCR5]) & FE_D5_BUFEMP) == 0
+		    && (inb(sc->ioaddr[FE_DLCR1]) & FE_D1_PKTRDY) == 0) {
+			/*
+			 * PKTRDY is off, while receive buffer is not empty.
+			 * We did a double check to avoid a race condition...
+			 * So, we should have missed an interrupt.
+			 */
+			log(LOG_WARNING,
+			    "fe%d: missed a receiver interrupt?\n",
+			    sc->arpcom.ac_if.if_unit);
+			/* Simulate the missed interrupt condition.  */
+			rstat |= FE_D1_PKTRDY;
+		}
+#endif
+
+		/* Stop processing if there are no interrupts to handle.  */
		if ( tstat == 0 && rstat == 0 ) break;
 
		/*
@@ -2823,20 +2884,23 @@
 
	static u_char padding [ ETHER_MIN_LEN - ETHER_CRC_LEN - ETHER_HDR_LEN ];
 
-#if FE_DEBUG >= 2
+#if FE_DEBUG >= 1
	/* First, count up the total number of bytes to copy */
	length = 0;
	for ( mp = m; mp != NULL; mp = mp->m_next ) {
		length += mp->m_len;
	}
+#else
+	/* Just use the length value in the packet header.  */
+	length = m->m_pkthdr.len;
+#endif
+
+#if FE_DEBUG >= 2
	/* Check if this matches the one in the packet header.  */
	if ( length != m->m_pkthdr.len ) {
		log( LOG_WARNING, "fe%d: packet length mismatch? (%d/%d)\n",
			sc->sc_unit, length, m->m_pkthdr.len );
	}
-#else
-	/* Just use the length value in the packet header.  */
-	length = m->m_pkthdr.len;
 #endif
 
 #if FE_DEBUG >= 1
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199701082056.FAA16579>