Subject: kern/7279: ex 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: 03/30/1999 01:42:32
>Number:         7279
>Category:       kern
>Synopsis:       ex 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:   Mon Mar 29 08:50:01 1999
>Last-Modified:
>Originator:     Izumi Tsutsui
>Organization:
Izumi Tsutsui	Himeji City, JAPAN
>Release:        NetBSD-current 19990328
>Environment:
System: NetBSD lancer 1.3K NetBSD 1.3K (LANCER) #452: Sun Mar 28 16:07:35 \
JST 1999 root@lancer:/usr/src/sys/arch/macppc/compile/LANCER macppc
and 3Com 3c905B-TX

>Description:
Current ex 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 ex 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 ex 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/ic/elinkxl.c.orig	Mon Mar 29 18:01:50 1999
+++ sys/dev/ic/elinkxl.c	Tue Mar 30 00:27:07 1999
@@ -81,6 +81,14 @@
 #include <machine/cpu.h>
 #include <machine/bus.h>
 #include <machine/intr.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
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
@@ -333,7 +341,8 @@
 	for (i = 0; i < EX_NUPD; i++) {
 		sc->sc_rxdescs[i].rx_dmamap = sc->sc_rx_dmamaps[i];
 		sc->sc_rxdescs[i].rx_upd = &sc->sc_upd[i];
-		sc->sc_upd[i].upd_frags[0].fr_len = (MCLBYTES - 2) | EX_FR_LAST;
+		sc->sc_upd[i].upd_frags[0].fr_len =
+			htopci((MCLBYTES - 2) | EX_FR_LAST);
 		if (ex_add_rxbuf(sc, &sc->sc_rxdescs[i]) != 0) {
 			printf("%s: can't allocate or map rx buffers\n",
 			    sc->sc_dev.dv_xname);
@@ -977,12 +986,12 @@
 		fr = &txp->tx_dpd->dpd_frags[0];
 		totlen = 0;
 		for (segment = 0; segment < dmamap->dm_nsegs; segment++, fr++) {
-			fr->fr_addr = dmamap->dm_segs[segment].ds_addr;
-			fr->fr_len = dmamap->dm_segs[segment].ds_len;
-			totlen += fr->fr_len;
+			fr->fr_addr = htopci(dmamap->dm_segs[segment].ds_addr);
+			fr->fr_len = htopci(dmamap->dm_segs[segment].ds_len);
+			totlen += dmamap->dm_segs[segment].ds_len;
 		}
 		fr--;
-		fr->fr_len |= EX_FR_LAST;
+		fr->fr_len |= htopci(EX_FR_LAST);
 		txp->tx_mbhead = mb_head;
 
 		bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize,
@@ -990,7 +999,7 @@
 
 		dpd = txp->tx_dpd;
 		dpd->dpd_nextptr = 0;
-		dpd->dpd_fsh = totlen;
+		dpd->dpd_fsh = htopci(totlen);
 
 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dpd_dmamap,
 		    ((caddr_t)dpd - (caddr_t)sc->sc_dpd),
@@ -1010,7 +1019,7 @@
 			bus_dmamap_sync(sc->sc_dmat, sc->sc_dpd_dmamap,
 			    offset, sizeof (struct ex_dpd),
 			    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
-			prevdpd->dpd_nextptr = DPD_DMADDR(sc, txp);
+			prevdpd->dpd_nextptr = htopci(DPD_DMADDR(sc, txp));
 			bus_dmamap_sync(sc->sc_dmat, sc->sc_dpd_dmamap,
 			    offset, sizeof (struct ex_dpd),
 			    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 
@@ -1030,7 +1039,7 @@
 	}
  out:
 	if (sc->tx_head) {
-		sc->tx_tail->tx_dpd->dpd_fsh |= EX_DPD_DNIND;
+		sc->tx_tail->tx_dpd->dpd_fsh |= htopci(EX_DPD_DNIND);
 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dpd_dmamap,
 		    ((caddr_t)sc->tx_tail->tx_dpd - (caddr_t)sc->sc_dpd),
 		    sizeof (struct ex_dpd),
@@ -1133,7 +1142,7 @@
 			rxmap = rxd->rx_dmamap;
 			m = rxd->rx_mbhead;
 			upd = rxd->rx_upd;
-			pktstat = upd->upd_pktstatus;
+			pktstat = pcitoh(upd->upd_pktstatus);
 
 			bus_dmamap_sync(sc->sc_dmat, rxmap, 0,
 			    rxmap->dm_mapsize,
@@ -1602,8 +1611,9 @@
 	m->m_data += 2;
 
 	rxd->rx_mbhead = m;
-	rxd->rx_upd->upd_pktstatus = MCLBYTES - 2;
-	rxd->rx_upd->upd_frags[0].fr_addr = rxmap->dm_segs[0].ds_addr + 2;
+	rxd->rx_upd->upd_pktstatus = htopci(MCLBYTES - 2);
+	rxd->rx_upd->upd_frags[0].fr_addr =
+		htopci(rxmap->dm_segs[0].ds_addr + 2);
 	rxd->rx_upd->upd_nextptr = 0;
 
 	/*
@@ -1611,8 +1621,8 @@
 	 */
 	if (sc->rx_head != NULL) {
 		sc->rx_tail->rx_next = rxd;
-		sc->rx_tail->rx_upd->upd_nextptr = sc->sc_upddma +
-		    ((caddr_t)rxd->rx_upd - (caddr_t)sc->sc_upd);
+		sc->rx_tail->rx_upd->upd_nextptr = htopci(sc->sc_upddma +
+		    ((caddr_t)rxd->rx_upd - (caddr_t)sc->sc_upd));
 		bus_dmamap_sync(sc->sc_dmat, sc->sc_upd_dmamap,
 		    (caddr_t)sc->rx_tail->rx_upd - (caddr_t)sc->sc_upd,
 		    sizeof (struct ex_upd),

>Audit-Trail:
>Unformatted: