Add a workaround for hardware ip4csum-tx bug on re(4) chips.
See discussion on tech-kern and tech-net for details: http://mail-index.netbsd.org/tech-net/2006/10/21/0000.html http://mail-index.netbsd.org/tech-net/2006/11/04/0003.html http://mail-index.netbsd.org/tech-net/2006/11/07/0002.html http://mail-index.netbsd.org/tech-net/2006/11/12/0000.html etc.
This commit is contained in:
parent
77c6811b1b
commit
f48e88ab0d
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: rtl8169.c,v 1.62 2006/11/16 01:32:52 christos Exp $ */
|
/* $NetBSD: rtl8169.c,v 1.63 2006/11/17 21:29:36 tsutsui Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 1998-2003
|
* Copyright (c) 1997, 1998-2003
|
||||||
@ -690,7 +690,8 @@ re_attach(struct rtk_softc *sc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate DMA'able memory for the RX ring */
|
/* Allocate DMA'able memory for the RX ring */
|
||||||
if ((error = bus_dmamem_alloc(sc->sc_dmat, RE_RX_LIST_SZ,
|
if ((error = bus_dmamem_alloc(sc->sc_dmat,
|
||||||
|
RE_RX_LIST_SZ + RE_IP4CSUMTX_PADLEN,
|
||||||
RE_RING_ALIGN, 0, &sc->re_ldata.re_rx_listseg, 1,
|
RE_RING_ALIGN, 0, &sc->re_ldata.re_rx_listseg, 1,
|
||||||
&sc->re_ldata.re_rx_listnseg, BUS_DMA_NOWAIT)) != 0) {
|
&sc->re_ldata.re_rx_listnseg, BUS_DMA_NOWAIT)) != 0) {
|
||||||
aprint_error("%s: can't allocate rx listseg, error = %d\n",
|
aprint_error("%s: can't allocate rx listseg, error = %d\n",
|
||||||
@ -700,17 +701,18 @@ re_attach(struct rtk_softc *sc)
|
|||||||
|
|
||||||
/* Load the map for the RX ring. */
|
/* Load the map for the RX ring. */
|
||||||
if ((error = bus_dmamem_map(sc->sc_dmat, &sc->re_ldata.re_rx_listseg,
|
if ((error = bus_dmamem_map(sc->sc_dmat, &sc->re_ldata.re_rx_listseg,
|
||||||
sc->re_ldata.re_rx_listnseg, RE_RX_LIST_SZ,
|
sc->re_ldata.re_rx_listnseg, RE_RX_LIST_SZ + RE_IP4CSUMTX_PADLEN,
|
||||||
(caddr_t *)&sc->re_ldata.re_rx_list,
|
(caddr_t *)&sc->re_ldata.re_rx_list,
|
||||||
BUS_DMA_COHERENT | BUS_DMA_NOWAIT)) != 0) {
|
BUS_DMA_COHERENT | BUS_DMA_NOWAIT)) != 0) {
|
||||||
aprint_error("%s: can't map rx list, error = %d\n",
|
aprint_error("%s: can't map rx list, error = %d\n",
|
||||||
sc->sc_dev.dv_xname, error);
|
sc->sc_dev.dv_xname, error);
|
||||||
goto fail_5;
|
goto fail_5;
|
||||||
}
|
}
|
||||||
memset(sc->re_ldata.re_rx_list, 0, RE_RX_LIST_SZ);
|
memset(sc->re_ldata.re_rx_list, 0, RE_RX_LIST_SZ + RE_IP4CSUMTX_PADLEN);
|
||||||
|
|
||||||
if ((error = bus_dmamap_create(sc->sc_dmat, RE_RX_LIST_SZ, 1,
|
if ((error = bus_dmamap_create(sc->sc_dmat,
|
||||||
RE_RX_LIST_SZ, 0, 0,
|
RE_RX_LIST_SZ + RE_IP4CSUMTX_PADLEN, 1,
|
||||||
|
RE_RX_LIST_SZ + RE_IP4CSUMTX_PADLEN, 0, 0,
|
||||||
&sc->re_ldata.re_rx_list_map)) != 0) {
|
&sc->re_ldata.re_rx_list_map)) != 0) {
|
||||||
aprint_error("%s: can't create rx list map, error = %d\n",
|
aprint_error("%s: can't create rx list map, error = %d\n",
|
||||||
sc->sc_dev.dv_xname, error);
|
sc->sc_dev.dv_xname, error);
|
||||||
@ -719,7 +721,7 @@ re_attach(struct rtk_softc *sc)
|
|||||||
|
|
||||||
if ((error = bus_dmamap_load(sc->sc_dmat,
|
if ((error = bus_dmamap_load(sc->sc_dmat,
|
||||||
sc->re_ldata.re_rx_list_map, sc->re_ldata.re_rx_list,
|
sc->re_ldata.re_rx_list_map, sc->re_ldata.re_rx_list,
|
||||||
RE_RX_LIST_SZ, NULL, BUS_DMA_NOWAIT)) != 0) {
|
RE_RX_LIST_SZ + RE_IP4CSUMTX_PADLEN, NULL, BUS_DMA_NOWAIT)) != 0) {
|
||||||
aprint_error("%s: can't load rx list, error = %d\n",
|
aprint_error("%s: can't load rx list, error = %d\n",
|
||||||
sc->sc_dev.dv_xname, error);
|
sc->sc_dev.dv_xname, error);
|
||||||
goto fail_7;
|
goto fail_7;
|
||||||
@ -765,7 +767,7 @@ re_attach(struct rtk_softc *sc)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ifp->if_capabilities |=
|
ifp->if_capabilities |=
|
||||||
/* IFCAP_CSUM_IPv4_Tx | */ IFCAP_CSUM_IPv4_Rx |
|
IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx |
|
||||||
IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx |
|
IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx |
|
||||||
IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx |
|
IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx |
|
||||||
IFCAP_TSOv4;
|
IFCAP_TSOv4;
|
||||||
@ -1324,7 +1326,7 @@ re_txeof(struct rtk_softc *sc)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sc->re_ldata.re_tx_free += txq->txq_dmamap->dm_nsegs;
|
sc->re_ldata.re_tx_free += txq->txq_nsegs;
|
||||||
KASSERT(sc->re_ldata.re_tx_free <= RE_TX_DESC_CNT(sc));
|
KASSERT(sc->re_ldata.re_tx_free <= RE_TX_DESC_CNT(sc));
|
||||||
bus_dmamap_sync(sc->sc_dmat, txq->txq_dmamap,
|
bus_dmamap_sync(sc->sc_dmat, txq->txq_dmamap,
|
||||||
0, txq->txq_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
|
0, txq->txq_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
|
||||||
@ -1514,8 +1516,9 @@ re_start(struct ifnet *ifp)
|
|||||||
struct m_tag *mtag;
|
struct m_tag *mtag;
|
||||||
#endif
|
#endif
|
||||||
uint32_t cmdstat, re_flags;
|
uint32_t cmdstat, re_flags;
|
||||||
int ofree, idx, error, seg;
|
int ofree, idx, error, nsegs, seg;
|
||||||
int startdesc, curdesc, lastdesc;
|
int startdesc, curdesc, lastdesc;
|
||||||
|
boolean_t pad;
|
||||||
|
|
||||||
sc = ifp->if_softc;
|
sc = ifp->if_softc;
|
||||||
ofree = sc->re_ldata.re_txq_free;
|
ofree = sc->re_ldata.re_txq_free;
|
||||||
@ -1581,7 +1584,15 @@ re_start(struct ifnet *ifp)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map->dm_nsegs > sc->re_ldata.re_tx_free - RE_NTXDESC_RSVD) {
|
nsegs = map->dm_nsegs;
|
||||||
|
pad = FALSE;
|
||||||
|
if (m->m_pkthdr.len <= RE_IP4CSUMTX_PADLEN &&
|
||||||
|
(re_flags & RE_TDESC_CMD_IPCSUM) != 0) {
|
||||||
|
pad = TRUE;
|
||||||
|
nsegs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nsegs > sc->re_ldata.re_tx_free - RE_NTXDESC_RSVD) {
|
||||||
/*
|
/*
|
||||||
* Not enough free descriptors to transmit this packet.
|
* Not enough free descriptors to transmit this packet.
|
||||||
*/
|
*/
|
||||||
@ -1640,7 +1651,7 @@ re_start(struct ifnet *ifp)
|
|||||||
cmdstat |= RE_TDESC_CMD_OWN;
|
cmdstat |= RE_TDESC_CMD_OWN;
|
||||||
if (curdesc == (RE_TX_DESC_CNT(sc) - 1))
|
if (curdesc == (RE_TX_DESC_CNT(sc) - 1))
|
||||||
cmdstat |= RE_TDESC_CMD_EOR;
|
cmdstat |= RE_TDESC_CMD_EOR;
|
||||||
if (seg == map->dm_nsegs - 1) {
|
if (seg == nsegs - 1) {
|
||||||
cmdstat |= RE_TDESC_CMD_EOF;
|
cmdstat |= RE_TDESC_CMD_EOF;
|
||||||
lastdesc = curdesc;
|
lastdesc = curdesc;
|
||||||
}
|
}
|
||||||
@ -1648,6 +1659,24 @@ re_start(struct ifnet *ifp)
|
|||||||
RE_TXDESCSYNC(sc, curdesc,
|
RE_TXDESCSYNC(sc, curdesc,
|
||||||
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
||||||
}
|
}
|
||||||
|
if (pad) {
|
||||||
|
bus_addr_t paddaddr;
|
||||||
|
|
||||||
|
d = &sc->re_ldata.re_tx_list[curdesc];
|
||||||
|
paddaddr = RE_TXPADDADDR(sc);
|
||||||
|
d->re_bufaddr_lo = htole32(RE_ADDR_LO(paddaddr));
|
||||||
|
d->re_bufaddr_hi = htole32(RE_ADDR_HI(paddaddr));
|
||||||
|
cmdstat = re_flags |
|
||||||
|
RE_TDESC_CMD_OWN | RE_TDESC_CMD_EOF |
|
||||||
|
(RE_IP4CSUMTX_PADLEN + 1 - m->m_pkthdr.len);
|
||||||
|
if (curdesc == (RE_TX_DESC_CNT(sc) - 1))
|
||||||
|
cmdstat |= RE_TDESC_CMD_EOR;
|
||||||
|
d->re_cmdstat = htole32(cmdstat);
|
||||||
|
RE_TXDESCSYNC(sc, curdesc,
|
||||||
|
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
||||||
|
lastdesc = curdesc;
|
||||||
|
curdesc = RE_NEXT_TX_DESC(sc, curdesc);
|
||||||
|
}
|
||||||
KASSERT(lastdesc != -1);
|
KASSERT(lastdesc != -1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1674,9 +1703,10 @@ re_start(struct ifnet *ifp)
|
|||||||
/* update info of TX queue and descriptors */
|
/* update info of TX queue and descriptors */
|
||||||
txq->txq_mbuf = m;
|
txq->txq_mbuf = m;
|
||||||
txq->txq_descidx = lastdesc;
|
txq->txq_descidx = lastdesc;
|
||||||
|
txq->txq_nsegs = nsegs;
|
||||||
|
|
||||||
sc->re_ldata.re_txq_free--;
|
sc->re_ldata.re_txq_free--;
|
||||||
sc->re_ldata.re_tx_free -= map->dm_nsegs;
|
sc->re_ldata.re_tx_free -= nsegs;
|
||||||
sc->re_ldata.re_tx_nextfree = curdesc;
|
sc->re_ldata.re_tx_nextfree = curdesc;
|
||||||
|
|
||||||
#if NBPFILTER > 0
|
#if NBPFILTER > 0
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: rtl81x9var.h,v 1.34 2006/11/12 03:09:37 tsutsui Exp $ */
|
/* $NetBSD: rtl81x9var.h,v 1.35 2006/11/17 21:29:36 tsutsui Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 1998
|
* Copyright (c) 1997, 1998
|
||||||
@ -148,6 +148,7 @@ struct re_txq {
|
|||||||
struct mbuf *txq_mbuf;
|
struct mbuf *txq_mbuf;
|
||||||
bus_dmamap_t txq_dmamap;
|
bus_dmamap_t txq_dmamap;
|
||||||
int txq_descidx;
|
int txq_descidx;
|
||||||
|
int txq_nsegs;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct re_list_data {
|
struct re_list_data {
|
||||||
@ -244,6 +245,22 @@ struct rtk_softc {
|
|||||||
sizeof(struct re_desc), \
|
sizeof(struct re_desc), \
|
||||||
(ops))
|
(ops))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* re(4) hardware ip4csum-tx could be mangled with 28 byte or less IP packets
|
||||||
|
*/
|
||||||
|
#define RE_IP4CSUMTX_MINLEN 28
|
||||||
|
#define RE_IP4CSUMTX_PADLEN (ETHER_HDR_LEN + RE_IP4CSUMTX_MINLEN)
|
||||||
|
/*
|
||||||
|
* XXX
|
||||||
|
* We are allocating pad DMA buffer after RX DMA descs for now
|
||||||
|
* because RE_TX_LIST_SZ(sc) always occupies whole page but
|
||||||
|
* RE_RX_LIST_SZ is less than PAGE_SIZE so there is some unused region.
|
||||||
|
*/
|
||||||
|
#define RE_TXPADOFF RE_RX_LIST_SZ
|
||||||
|
#define RE_TXPADDADDR(sc) \
|
||||||
|
((sc)->re_ldata.re_rx_list_map->dm_segs[0].ds_addr + RE_TXPADOFF)
|
||||||
|
|
||||||
|
|
||||||
#define RTK_ATTACHED 0x00000001 /* attach has succeeded */
|
#define RTK_ATTACHED 0x00000001 /* attach has succeeded */
|
||||||
#define RTK_ENABLED 0x00000002 /* chip is enabled */
|
#define RTK_ENABLED 0x00000002 /* chip is enabled */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user