diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2012-04-09 16:41:34 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2012-04-09 16:41:34 +0000 |
commit | 6eac1f37a3a47cb64783ac77aa3e4df337a42be8 (patch) | |
tree | 4e4b4fd3d01e39dfe612c0ede84d2ebd62b1537f /sys | |
parent | 7e7a33372028a4f5a3513ff918e1e3bd1b37bb50 (diff) |
Cope with strict alignment platforms, and unbreak the RX logic. Tested with
ep@eisa on sgi.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ic/elink3.c | 57 |
1 files changed, 36 insertions, 21 deletions
diff --git a/sys/dev/ic/elink3.c b/sys/dev/ic/elink3.c index d4266aa050f..8bd680971f6 100644 --- a/sys/dev/ic/elink3.c +++ b/sys/dev/ic/elink3.c @@ -1,4 +1,4 @@ -/* $OpenBSD: elink3.c,v 1.77 2012/01/11 16:22:33 dhill Exp $ */ +/* $OpenBSD: elink3.c,v 1.78 2012/04/09 16:41:33 miod Exp $ */ /* $NetBSD: elink3.c,v 1.32 1997/05/14 00:22:00 thorpej Exp $ */ /* @@ -951,6 +951,7 @@ epstart(struct ifnet *ifp) bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; struct mbuf *m, *m0; + caddr_t data; int sh, len, pad, txreg; /* Don't transmit if interface is busy or not running */ @@ -1019,24 +1020,32 @@ startagain: bus_space_write_2(iot, ioh, txreg, 0xffff); /* Second is meaningless */ if (EP_IS_BUS_32(sc->bustype)) { for (m = m0; m; ) { - if (m->m_len > 3) + data = mtod(m, u_int8_t *); + if (m->m_len > 3 && ALIGNED_POINTER(data, uint32_t)) { bus_space_write_raw_multi_4(iot, ioh, txreg, - mtod(m, u_int8_t *), m->m_len & ~3); - if (m->m_len & 3) + data, m->m_len & ~3); + if (m->m_len & 3) + bus_space_write_multi_1(iot, ioh, txreg, + data + (m->m_len & ~3), + m->m_len & 3); + } else bus_space_write_multi_1(iot, ioh, txreg, - mtod(m, u_int8_t *) + (m->m_len & ~3), - m->m_len & 3); + data, m->m_len); MFREE(m, m0); m = m0; } } else { for (m = m0; m; ) { - if (m->m_len > 1) + data = mtod(m, u_int8_t *); + if (m->m_len > 1 && ALIGNED_POINTER(data, uint16_t)) { bus_space_write_raw_multi_2(iot, ioh, txreg, - mtod(m, u_int8_t *), m->m_len & ~1); - if (m->m_len & 1) - bus_space_write_1(iot, ioh, txreg, - *(mtod(m, u_int8_t *) + m->m_len - 1)); + data, m->m_len & ~1); + if (m->m_len & 1) + bus_space_write_1(iot, ioh, txreg, + *(data + m->m_len - 1)); + } else + bus_space_write_multi_1(iot, ioh, txreg, + data, m->m_len); MFREE(m, m0); m = m0; } @@ -1346,6 +1355,7 @@ epget(struct ep_softc *sc, int totlen) bus_space_handle_t ioh = sc->sc_ioh; struct ifnet *ifp = &sc->sc_arpcom.ac_if; struct mbuf *m; + caddr_t data; int len, pad, off, sh, rxreg; splassert(IPL_NET); @@ -1386,26 +1396,31 @@ epget(struct ep_softc *sc, int totlen) if (len == 0) panic("ep_get: packet does not fit in MCLBYTES"); + data = mtod(m, u_int8_t *); if (EP_IS_BUS_32(sc->bustype)) - pad = (u_long)(mtod(m, u_int8_t *) + off) & 0x3; + pad = 4 - ((u_long)(data + off) & 0x3); else - pad = (u_long)(mtod(m, u_int8_t *) + off) & 0x1; + pad = (u_long)(data + off) & 0x1; if (pad) { + if (pad < len) + pad = len; bus_space_read_multi_1(iot, ioh, rxreg, - mtod(m, u_int8_t *) + off, pad); - } else if (EP_IS_BUS_32(sc->bustype) && len > 3) { + data + off, pad); + len = pad; + } else if (EP_IS_BUS_32(sc->bustype) && len > 3 && + ALIGNED_POINTER(data, uint32_t)) { len &= ~3; bus_space_read_raw_multi_4(iot, ioh, rxreg, - mtod(m, u_int8_t *) + off, len); - } else if (len > 1) { + data + off, len); + } else if (len > 1 && ALIGNED_POINTER(data, uint16_t)) { len &= ~1; bus_space_read_raw_multi_2(iot, ioh, rxreg, - mtod(m, u_int8_t *) + off, len); - } else { + data + off, len); + } else bus_space_read_multi_1(iot, ioh, rxreg, - mtod(m, u_int8_t *) + off, len); - } + data + off, len); + off += len; totlen -= len; } |