Subject: kern/17193: mb86960 driver supports word more only
To: None <gnats-bugs@gnats.netbsd.org>
From: Christian Groessler <cpg@aladdin.de>
List: netbsd-bugs
Date: 06/08/2002 15:59:52
>Number:         17193
>Category:       kern
>Synopsis:       mb86960 driver supports word more only
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Jun 08 07:01:01 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Christian Groessler
>Release:        NetBSD 1.6_BETA1
>Organization:
at home
>Environment:
	
	
System: NetBSD power.cnet.aladdin.de 1.6_BETA1 NetBSD 1.6_BETA1 (POWER) #0: Fri May 31 20:10:13 CEST 2002 chris@power.cnet.aladdin.de:/local/netbsdsrc-1.6/src/sys/arch/macppc/compile/POWER macppc
Architecture: powerpc
Machine: macppc
>Description:
	The mb86960 driver supports only the word (16 bit) mode bus
interface of the chip. The upcoming Dreamcast LAN adapter driver needs
byte mode. I've attached a patch which implements this support.
There is still one unniceness in the mb86960_attach() function - it
always sets word size, maybe this should become a parameter to the
function. Currently it's no real problem, since there are only 2 byte
sized i/os made afterwards in this function.

>How-To-Repeat:
	look at mb86960.c source code.
>Fix:
	
--- old/sys/dev/ic/mb86960.c	Tue Nov 13 14:14:41 2001
+++ new/sys/dev/ic/mb86960.c	Sat Jun  8 15:43:25 2002
@@ -222,7 +222,7 @@ mb86960_config(sc, media, nmedia, defmed
 
 #if FE_SINGLE_TRANSMISSION
 	/* Override txb config to allocate minimum. */
-	sc->proto_dlcr6 &= ~FE_D6_TXBSIZ
+	sc->proto_dlcr6 &= ~FE_D6_TXBSIZ;
 	sc->proto_dlcr6 |=  FE_D6_TXBSIZ_2x2KB;
 #endif
 
@@ -988,11 +988,15 @@ mb86960_rint(sc, rstat)
 		    sc->sc_dev.dv_xname, sbuf);
 #endif
 		ifp->if_ierrors++;
+#if FE_DEBUG >= 2
+		printf("rint: error (%02X)\n", rstat);
+#endif
+		return;
 	}
 
 	/*
 	 * 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 infinite loop.
@@ -1011,7 +1015,14 @@ mb86960_rint(sc, rstat)
 		 * use inw() to get the status byte.  The significant
 		 * value is returned in lower 8 bits.
 		 */
-		status = (u_char)bus_space_read_2(bst, bsh, FE_BMPR8);
+
+		if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) {
+			status = bus_space_read_1(bst, bsh, FE_BMPR8);
+			(void) bus_space_read_1(bst, bsh, FE_BMPR8);
+		}
+		else {
+			status = (u_char)bus_space_read_2(bst, bsh, FE_BMPR8);
+		}
 #if FE_DEBUG >= 4
 		log(LOG_INFO, "%s: receive status = %02x\n",
 		    sc->sc_dev.dv_xname, status);
@@ -1035,7 +1046,13 @@ mb86960_rint(sc, rstat)
 		 * It is a sum of a header (14 bytes) and a payload.
 		 * CRC has been stripped off by the 86960.
 		 */
-		len = bus_space_read_2(bst, bsh, FE_BMPR8);
+		if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) {
+			len = bus_space_read_1(bst, bsh, FE_BMPR8);
+			len |= bus_space_read_1(bst, bsh, FE_BMPR8) << 8;
+		}
+		else {
+			len = (u_char)bus_space_read_2(bst, bsh, FE_BMPR8);
+		}
 
 		/*
 		 * MB86965 checks the packet length and drop big packet
@@ -1126,8 +1143,6 @@ mb86960_intr(arg)
 	 */
 	tstat = bus_space_read_1(bst, bsh, FE_DLCR0) & FE_TMASK;
 	rstat = bus_space_read_1(bst, bsh, FE_DLCR1) & FE_RMASK;
-	if (tstat == 0 && rstat == 0)
-		return (0);
 
 	/*
 	 * Loop until there are no more new interrupt conditions.
@@ -1374,8 +1389,13 @@ mb86960_get_packet(sc, len)
 	m->m_len = len;
 
 	/* Get a packet. */
-	bus_space_read_multi_stream_2(bst, bsh, FE_BMPR8, mtod(m, u_int16_t *),
-			       (len + 1) >> 1);
+	if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) {
+		bus_space_read_multi_stream_1(bst, bsh, FE_BMPR8, mtod(m, u_int8_t *), len);
+	}
+	else {
+		bus_space_read_multi_stream_2(bst, bsh, FE_BMPR8, mtod(m, u_int16_t *),
+					      (len + 1) >> 1);
+	}
 
 #if NBPFILTER > 0
 	/*
@@ -1426,11 +1446,21 @@ mb86960_write_mbufs(sc, m)
 
 #if FE_DELAYED_PADDING
 	/* Do the "delayed padding." */
-	len = sc->txb_padding >> 1;
-	if (len > 0) {
-		while (--len >= 0)
-			bus_space_write_2(bst, bsh, FE_BMPR8, 0);
-		sc->txb_padding = 0;
+	if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) {
+		len = sc->txb_padding;
+		if (len > 0) {
+			while (--len >= 0)
+				bus_space_write_1(bst, bsh, FE_BMPR8, 0);
+			sc->txb_padding = 0;
+		}
+	}
+	else {
+		len = sc->txb_padding >> 1;
+		if (len > 0) {
+			while (--len >= 0)
+				bus_space_write_2(bst, bsh, FE_BMPR8, 0);
+			sc->txb_padding = 0;
+		}
 	}
 #endif
 
@@ -1475,8 +1505,16 @@ mb86960_write_mbufs(sc, m)
 	 * packet in the transmission buffer, we can skip the
 	 * padding process.  It may gain performance slightly.  FIXME.
 	 */
-	bus_space_write_2(bst, bsh, FE_BMPR8,
-	    max(totlen, (ETHER_MIN_LEN - ETHER_CRC_LEN)));
+	if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) {
+		bus_space_write_1(bst, bsh, FE_BMPR8,
+				  max(totlen, (ETHER_MIN_LEN - ETHER_CRC_LEN)));
+		bus_space_write_1(bst, bsh, FE_BMPR8,
+				  max(totlen, (ETHER_MIN_LEN - ETHER_CRC_LEN)) >> 8);
+	}
+	else {
+		bus_space_write_2(bst, bsh, FE_BMPR8,
+				  max(totlen, (ETHER_MIN_LEN - ETHER_CRC_LEN)));
+	}
 
 	/*
 	 * Update buffer status now.
@@ -1495,9 +1533,9 @@ mb86960_write_mbufs(sc, m)
 
 	/*
 	 * Transfer the data from mbuf chain to the transmission buffer. 
-	 * MB86960 seems to require that data be transferred as words, and
-	 * only words.  So that we require some extra code to patch
-	 * over odd-length mbufs.
+	 * If the MB86960 is configured in word mode, data needs to be
+	 * transferred as words, and only words.  So that we require some
+	 * extra code to patch over odd-length mbufs.
 	 */
 	wantbyte = 0;
 	for (; m != 0; m = m->m_next) {
@@ -1509,25 +1547,33 @@ mb86960_write_mbufs(sc, m)
 		/* Find the actual data to send. */
 		data = mtod(m, caddr_t);
 
-		/* Finish the last byte. */
-		if (wantbyte) {
-			bus_space_write_2(bst, bsh, FE_BMPR8,
-			    savebyte | (*data << 8));
-			data++;
-			len--;
-			wantbyte = 0;
-		}
-
-		/* Output contiguous words. */
-		if (len > 1)
-			bus_space_write_multi_stream_2(bst, bsh, FE_BMPR8,
-						(u_int16_t *)data, len >> 1);
-
-		/* Save remaining byte, if there is one. */
-		if (len & 1) {
-			data += len & ~1;
-			savebyte = *data;
-			wantbyte = 1;
+		if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) {
+			bus_space_write_multi_stream_1(bst, bsh, FE_BMPR8,
+						       (u_int8_t *)data, len);
+			if (len & 1)
+				bus_space_write_1(bst, bsh, FE_BMPR8, 0);
+		}
+		else {
+			/* Finish the last byte. */
+			if (wantbyte) {
+				bus_space_write_2(bst, bsh, FE_BMPR8,
+						  savebyte | (*data << 8));
+				data++;
+				len--;
+				wantbyte = 0;
+			}
+
+			/* Output contiguous words. */
+			if (len > 1)
+				bus_space_write_multi_stream_2(bst, bsh, FE_BMPR8,
+							       (u_int16_t *)data, len >> 1);
+
+			/* Save remaining byte, if there is one. */
+			if (len & 1) {
+				data += len & ~1;
+				savebyte = *data;
+				wantbyte = 1;
+			}
 		}
 	}
 
@@ -1539,9 +1585,16 @@ mb86960_write_mbufs(sc, m)
 	/*
 	 * Pad the packet to the minimum length if necessary.
 	 */
-	len = ((ETHER_MIN_LEN - ETHER_CRC_LEN) >> 1) - (totlen >> 1);
-	while (--len >= 0)
-		bus_space_write_2(bst, bsh, FE_BMPR8, 0);
+	if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) {
+		len = (ETHER_MIN_LEN - ETHER_CRC_LEN) - totlen;
+		while (--len >= 0)
+			bus_space_write_1(bst, bsh, FE_BMPR8, 0);
+	}
+	else {
+		len = ((ETHER_MIN_LEN - ETHER_CRC_LEN) >> 1) - (totlen >> 1);
+		while (--len >= 0)
+			bus_space_write_2(bst, bsh, FE_BMPR8, 0);
+	}
 #endif
 }
 
@@ -1677,7 +1730,7 @@ mb86960_setmode(sc)
 	 *
 	 * Note that the DLC (Data Linc 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

>Release-Note:
>Audit-Trail:
>Unformatted: