Subject: kern/7305: vr driver does not work on big endian machines
To: None <gnats-bugs@gnats.netbsd.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: netbsd-bugs
Date: 04/02/1999 18:40:53
>Number:         7305
>Category:       kern
>Synopsis:       vr driver does not work on big endian machines
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Apr  2 01:50:01 1999
>Last-Modified:
>Originator:     Izumi Tsutsui
>Organization:
Izumi Tsutsui	Himeji City, JAPAN
>Release:        NetBSD-current supped on 19990328
>Environment:
System: NetBSD/macppc 1.3K and VIA Rhine network card

>Description:
This PR is mostly same as kern/7279,
just contains a patch for vr not ex.

Current vr driver does not work on big endian machines.
Even though the device is probed properly and its MII
media select seems to work, it could not send/receive any
packets.

>How-To-Repeat:
Put the device on big endian machine with PCI bus (like macppc),
make a kernel with vr driver and configure it.

>Fix:
There are some endian problem. When the host passes u_int32_t
args with a PCI device via DMA, the device assumes that
the host memory is little endian, which is PCI endian.
So that the hosts should access u_int32_t values on DMA buffers
as little endian.

The following patch adds some byteswap code to make vr driver work
on big endian machines. But I think it is better to use common
macros or functions which convert host-endian and little-endian.

--- sys/dev/pci/if_vr.c.orig	Wed Mar 24 21:20:45 1999
+++ sys/dev/pci/if_vr.c	Fri Apr  2 17:39:47 1999
@@ -144,6 +144,15 @@
 
 #include <dev/pci/if_vrreg.h>
 
+#if BYTE_ORDER == BIG_ENDIAN
+#include <machine/bswap.h>
+#define	htopci(x)	bswap32(x)
+#define	pcitoh(x)	bswap32(x)
+#else
+#define	htopci(x)	(x)
+#define	pcitoh(x)	(x)
+#endif
+
 #define	VR_USEIOSPACE
 
 /*
@@ -258,12 +267,12 @@
 	struct vr_desc *__d = VR_CDRX((sc), (i));			\
 	struct vr_descsoft *__ds = VR_DSRX((sc), (i));			\
 									\
-	__d->vr_next = VR_CDRXADDR((sc), VR_NEXTRX((i)));		\
-	__d->vr_status = VR_RXSTAT_FIRSTFRAG | VR_RXSTAT_LASTFRAG |	\
-	    VR_RXSTAT_OWN;						\
-	__d->vr_data = __ds->ds_dmamap->dm_segs[0].ds_addr;		\
-	__d->vr_ctl = VR_RXCTL_CHAIN | VR_RXCTL_RX_INTR |		\
-	    ((MCLBYTES - 1) & VR_RXCTL_BUFLEN);				\
+	__d->vr_next = htopci(VR_CDRXADDR((sc), VR_NEXTRX((i))));	\
+	__d->vr_status = htopci(VR_RXSTAT_FIRSTFRAG |			\
+	    VR_RXSTAT_LASTFRAG | VR_RXSTAT_OWN);			\
+	__d->vr_data = htopci(__ds->ds_dmamap->dm_segs[0].ds_addr);	\
+	__d->vr_ctl = htopci(VR_RXCTL_CHAIN | VR_RXCTL_RX_INTR |	\
+	    ((MCLBYTES - 1) & VR_RXCTL_BUFLEN));			\
 	VR_CDRXSYNC((sc), (i), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \
 } while (0)
 
@@ -711,7 +720,7 @@
 
 		VR_CDRXSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
 
-		rxstat = d->vr_status;
+		rxstat = pcitoh(d->vr_status);
 
 		if (rxstat & VR_RXSTAT_OWN) {
 			/*
@@ -768,7 +777,7 @@
 		    ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
 
 		/* No errors; receive the packet. */
-		total_len = VR_RXBYTES(d->vr_status);
+		total_len = VR_RXBYTES(pcitoh(d->vr_status));
 
 		/*
 		 * XXX The VIA Rhine chip includes the CRC with every
@@ -900,7 +909,7 @@
 
 		VR_CDTXSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
 
-		txstat = d->vr_status;
+		txstat = pcitoh(d->vr_status);
 		if (txstat & VR_TXSTAT_OWN)
 			break;
 
@@ -1114,11 +1123,11 @@
 		 * Fill in the transmit descriptor.  The Rhine
 		 * doesn't auto-pad, so we have to do this ourselves.
 		 */
-		d->vr_data = ds->ds_dmamap->dm_segs[0].ds_addr;
-		d->vr_ctl = m0->m_pkthdr.len < VR_MIN_FRAMELEN ?
-		    VR_MIN_FRAMELEN : m0->m_pkthdr.len;
+		d->vr_data = htopci(ds->ds_dmamap->dm_segs[0].ds_addr);
+		d->vr_ctl = htopci(m0->m_pkthdr.len < VR_MIN_FRAMELEN ?
+		    VR_MIN_FRAMELEN : m0->m_pkthdr.len);
 		d->vr_ctl |=
-		    VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG|VR_TXCTL_LASTFRAG;
+		    htopci(VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG|VR_TXCTL_LASTFRAG);
 		
 		/*
 		 * If this is the first descriptor we're enqueuing,
@@ -1128,7 +1137,7 @@
 		if (nexttx == firsttx)
 			d->vr_status = 0;
 		else
-			d->vr_status = VR_TXSTAT_OWN;
+			d->vr_status = htopci(VR_TXSTAT_OWN);
 
 		VR_CDTXSYNC(sc, nexttx,
 		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
@@ -1155,7 +1164,7 @@
 		 * Cause a transmit interrupt to happen on the
 		 * last packet we enqueued.
 		 */
-		VR_CDTX(sc, sc->vr_txlast)->vr_ctl |= VR_TXCTL_FINT;
+		VR_CDTX(sc, sc->vr_txlast)->vr_ctl |= htopci(VR_TXCTL_FINT);
 		VR_CDTXSYNC(sc, sc->vr_txlast,
 		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
 
@@ -1163,7 +1172,7 @@
 		 * The entire packet chain is set up.  Give the
 		 * first descriptor to the Rhine now.
 		 */
-		VR_CDTX(sc, firsttx)->vr_status = VR_TXSTAT_OWN;
+		VR_CDTX(sc, firsttx)->vr_status = htopci(VR_TXSTAT_OWN);
 		VR_CDTXSYNC(sc, firsttx,
 		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
 
@@ -1207,7 +1216,7 @@
 	for (i = 0; i < VR_NTXDESC; i++) {
 		d = VR_CDTX(sc, i);
 		memset(d, 0, sizeof(struct vr_desc));
-		d->vr_next = VR_CDTXADDR(sc, VR_NEXTTX(i));
+		d->vr_next = htopci(VR_CDTXADDR(sc, VR_NEXTTX(i)));
 		VR_CDTXSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
 	}
 	sc->vr_txpending = 0;

>Audit-Trail:
>Unformatted: