diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2006-11-10 20:46:59 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2006-11-10 20:46:59 +0000 |
commit | e7f3740f4f12ea46b396b24d250b2eb76780e1d2 (patch) | |
tree | 1e2659809d63a2cbf54e1771d26470413b6fa74e /sys | |
parent | 692f24d9c2b538d9e0cde74f8454eb56d16f2cb1 (diff) |
Defer setting of the valid bit in the first TX descriptor after
all descriptors have been setup. Otherwise, hardware may start
processing descriptors faster than us and crap out.
Fixes "watchdog timeout" errors.
Original idea from Matthew Dillon @DragonFly.
ok deraadt@ jsg@ wim@
tested by many
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pci/if_nfe.c | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/sys/dev/pci/if_nfe.c b/sys/dev/pci/if_nfe.c index 35e6871321b..5baa9d72fd1 100644 --- a/sys/dev/pci/if_nfe.c +++ b/sys/dev/pci/if_nfe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_nfe.c,v 1.65 2006/11/05 20:15:37 brad Exp $ */ +/* $OpenBSD: if_nfe.c,v 1.66 2006/11/10 20:46:58 damien Exp $ */ /*- * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> @@ -883,13 +883,13 @@ nfe_encap(struct nfe_softc *sc, struct mbuf *m0) struct nfe_desc64 *desc64; struct nfe_tx_data *data; bus_dmamap_t map; - uint16_t flags = NFE_TX_VALID; + uint16_t flags = 0; #if NVLAN > 0 uint32_t vtag = 0; #endif - int error, i; + int error, i, first = sc->txq.cur; - map = sc->txq.data[sc->txq.cur].map; + map = sc->txq.data[first].map; error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m0, BUS_DMA_NOWAIT); if (error != 0) { @@ -942,28 +942,44 @@ nfe_encap(struct nfe_softc *sc, struct mbuf *m0) desc32->flags = htole16(flags); } - /* csum flags and vtag belong to the first fragment only */ if (map->dm_nsegs > 1) { + /* + * Checksum flags and vtag belong to the first fragment + * only. + */ flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM); #if NVLAN > 0 vtag = 0; #endif + /* + * Setting of the valid bit in the first descriptor is + * deferred until the whole chain is fully setup. + */ + flags |= NFE_TX_VALID; } sc->txq.queued++; sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT; } - /* the whole mbuf chain has been DMA mapped, fix last descriptor */ + /* the whole mbuf chain has been setup */ if (sc->sc_flags & NFE_40BIT_ADDR) { + /* fix last descriptor */ flags |= NFE_TX_LASTFRAG_V2; desc64->flags = htole16(flags); + + /* finally, set the valid bit in the first descriptor */ + sc->txq.desc64[first].flags |= htole16(NFE_TX_VALID); } else { + /* fix last descriptor */ if (sc->sc_flags & NFE_JUMBO_SUP) flags |= NFE_TX_LASTFRAG_V2; else flags |= NFE_TX_LASTFRAG_V1; desc32->flags = htole16(flags); + + /* finally, set the valid bit in the first descriptor */ + sc->txq.desc32[first].flags |= htole16(NFE_TX_VALID); } data->m = m0; |