Add a workaround for a hardware ip4csum-tx bug which would sometimes put
wrong IPv4 checksum on sending 21 or 22 byte IP packets. See discussion on tech-kern and tech-net for details: http://mail-index.netbsd.org/tech-kern/2006/11/04/0004.html
This commit is contained in:
parent
1bb72362cf
commit
cad156cdf4
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: elinkxl.c,v 1.92 2006/11/05 07:59:21 itohy Exp $ */
|
||||
/* $NetBSD: elinkxl.c,v 1.93 2006/11/12 02:49:46 tsutsui Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
@ -37,7 +37,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: elinkxl.c,v 1.92 2006/11/05 07:59:21 itohy Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: elinkxl.c,v 1.93 2006/11/12 02:49:46 tsutsui Exp $");
|
||||
|
||||
#include "bpfilter.h"
|
||||
#include "rnd.h"
|
||||
@ -279,7 +279,7 @@ ex_config(sc)
|
||||
* map for them.
|
||||
*/
|
||||
if ((error = bus_dmamem_alloc(sc->sc_dmat,
|
||||
EX_NDPD * sizeof (struct ex_dpd), PAGE_SIZE, 0, &sc->sc_dseg, 1,
|
||||
DPDMEM_SIZE + EX_IP4CSUMTX_PADLEN, PAGE_SIZE, 0, &sc->sc_dseg, 1,
|
||||
&sc->sc_drseg, BUS_DMA_NOWAIT)) != 0) {
|
||||
aprint_error(
|
||||
"%s: can't allocate download descriptors, error = %d\n",
|
||||
@ -290,19 +290,19 @@ ex_config(sc)
|
||||
attach_stage = 5;
|
||||
|
||||
if ((error = bus_dmamem_map(sc->sc_dmat, &sc->sc_dseg, sc->sc_drseg,
|
||||
EX_NDPD * sizeof (struct ex_dpd), (caddr_t *)&sc->sc_dpd,
|
||||
DPDMEM_SIZE + EX_IP4CSUMTX_PADLEN, (caddr_t *)&sc->sc_dpd,
|
||||
BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
|
||||
aprint_error("%s: can't map download descriptors, error = %d\n",
|
||||
sc->sc_dev.dv_xname, error);
|
||||
goto fail;
|
||||
}
|
||||
memset(sc->sc_dpd, 0, EX_NDPD * sizeof (struct ex_dpd));
|
||||
memset(sc->sc_dpd, 0, DPDMEM_SIZE + EX_IP4CSUMTX_PADLEN);
|
||||
|
||||
attach_stage = 6;
|
||||
|
||||
if ((error = bus_dmamap_create(sc->sc_dmat,
|
||||
EX_NDPD * sizeof (struct ex_dpd), 1,
|
||||
EX_NDPD * sizeof (struct ex_dpd), 0, BUS_DMA_NOWAIT,
|
||||
DPDMEM_SIZE + EX_IP4CSUMTX_PADLEN, 1,
|
||||
DPDMEM_SIZE + EX_IP4CSUMTX_PADLEN, 0, BUS_DMA_NOWAIT,
|
||||
&sc->sc_dpd_dmamap)) != 0) {
|
||||
aprint_error(
|
||||
"%s: can't create download desc. DMA map, error = %d\n",
|
||||
@ -313,13 +313,15 @@ ex_config(sc)
|
||||
attach_stage = 7;
|
||||
|
||||
if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dpd_dmamap,
|
||||
sc->sc_dpd, EX_NDPD * sizeof (struct ex_dpd), NULL,
|
||||
sc->sc_dpd, DPDMEM_SIZE + EX_IP4CSUMTX_PADLEN, NULL,
|
||||
BUS_DMA_NOWAIT)) != 0) {
|
||||
aprint_error(
|
||||
"%s: can't load download desc. DMA map, error = %d\n",
|
||||
sc->sc_dev.dv_xname, error);
|
||||
goto fail;
|
||||
}
|
||||
bus_dmamap_sync(sc->sc_dmat, sc->sc_dpd_dmamap,
|
||||
DPDMEMPAD_OFF, EX_IP4CSUMTX_PADLEN, BUS_DMASYNC_PREWRITE);
|
||||
|
||||
attach_stage = 8;
|
||||
|
||||
@ -1053,7 +1055,7 @@ ex_start(ifp)
|
||||
struct ex_txdesc *txp;
|
||||
struct mbuf *mb_head;
|
||||
bus_dmamap_t dmamap;
|
||||
int m_csumflags, offset, totlen, segment, error;
|
||||
int m_csumflags, offset, seglen, totlen, segment, error;
|
||||
u_int32_t csum_flags;
|
||||
|
||||
if (sc->tx_head || sc->tx_free == NULL)
|
||||
@ -1153,11 +1155,28 @@ ex_start(ifp)
|
||||
totlen = 0;
|
||||
for (segment = 0; segment < dmamap->dm_nsegs; segment++, fr++) {
|
||||
fr->fr_addr = htole32(dmamap->dm_segs[segment].ds_addr);
|
||||
fr->fr_len = htole32(dmamap->dm_segs[segment].ds_len);
|
||||
totlen += dmamap->dm_segs[segment].ds_len;
|
||||
seglen = dmamap->dm_segs[segment].ds_len;
|
||||
fr->fr_len = htole32(seglen);
|
||||
totlen += seglen;
|
||||
}
|
||||
if (__predict_false(totlen <= EX_IP4CSUMTX_PADLEN &&
|
||||
(m_csumflags & M_CSUM_IPv4) != 0)) {
|
||||
/*
|
||||
* Pad short packets to avoid ip4csum-tx bug.
|
||||
*
|
||||
* XXX Should we still consider if such short
|
||||
* (36 bytes or less) packets might already
|
||||
* occupy EX_NTFRAG (== 32) fragements here?
|
||||
*/
|
||||
KASSERT(segment < EX_NTFRAGS);
|
||||
fr->fr_addr = htole32(DPDMEMPAD_DMADDR(sc));
|
||||
seglen = EX_IP4CSUMTX_PADLEN + 1 - totlen;
|
||||
fr->fr_len = htole32(EX_FR_LAST | seglen);
|
||||
totlen += seglen;
|
||||
} else {
|
||||
fr--;
|
||||
fr->fr_len |= htole32(EX_FR_LAST);
|
||||
}
|
||||
fr--;
|
||||
fr->fr_len |= htole32(EX_FR_LAST);
|
||||
txp->tx_mbhead = mb_head;
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: elinkxlreg.h,v 1.11 2002/11/09 11:45:19 enami Exp $ */
|
||||
/* $NetBSD: elinkxlreg.h,v 1.12 2006/11/12 02:49:46 tsutsui Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
@ -268,6 +268,19 @@ struct ex_txdesc {
|
||||
struct ex_dpd *tx_dpd;
|
||||
};
|
||||
|
||||
/*
|
||||
* hardware ip4csum-tx on ex(4) sometimes seems to set wrong IP checksums
|
||||
* if the TX IP packet length is 21 or 22 bytes which requires autopadding.
|
||||
* To avoid this bug, we have to pad such very short packets manually.
|
||||
*/
|
||||
#define EX_IP4CSUMTX_MINLEN 22
|
||||
#define EX_IP4CSUMTX_PADLEN \
|
||||
(sizeof(struct ether_header) + EX_IP4CSUMTX_MINLEN)
|
||||
|
||||
#define DPDMEM_SIZE (sizeof(struct ex_dpd) * EX_NDPD)
|
||||
#define DPDMEMPAD_OFF DPDMEM_SIZE
|
||||
#define DPDMEMPAD_DMADDR(sc) ((sc)->sc_dpddma + DPDMEMPAD_OFF)
|
||||
|
||||
#define DPD_DMADDR(s,t) \
|
||||
((s)->sc_dpddma + ((caddr_t)((t)->tx_dpd) - (caddr_t)((s)->sc_dpd)))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user