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: