diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2011-03-05 13:39:27 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2011-03-05 13:39:27 +0000 |
commit | 6dcf994cd13b7d40e8dcede8b3829e9e4d6b0bcd (patch) | |
tree | 9d842047de9d22816e18f7bbc09ed4b09ea87550 /sys/dev | |
parent | 1275466d50991b94b25f51b2a3487e63bdea1a96 (diff) |
Wait until the DMA engine is stopped before unmapping buffers and descriptors.
Fixes DMA errors seen on sparc64.
ok miod@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ic/dc.c | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/sys/dev/ic/dc.c b/sys/dev/ic/dc.c index 19f30995b25..32d84510a0e 100644 --- a/sys/dev/ic/dc.c +++ b/sys/dev/ic/dc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dc.c,v 1.121 2010/09/07 16:21:42 deraadt Exp $ */ +/* $OpenBSD: dc.c,v 1.122 2011/03/05 13:39:26 kettenis Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -3056,6 +3056,7 @@ void dc_stop(struct dc_softc *sc, int softonly) { struct ifnet *ifp; + u_int32_t isr; int i; ifp = &sc->sc_arpcom.ac_if; @@ -3067,6 +3068,28 @@ dc_stop(struct dc_softc *sc, int softonly) if (!softonly) { DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ON|DC_NETCFG_TX_ON)); + + for (i = 0; i < DC_TIMEOUT; i++) { + isr = CSR_READ_4(sc, DC_ISR); + if ((isr & DC_ISR_TX_IDLE || + (isr & DC_ISR_TX_STATE) == DC_TXSTATE_RESET) && + (isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED) + break; + DELAY(10); + } + + if (i == DC_TIMEOUT) { + if (!((isr & DC_ISR_TX_IDLE) || + (isr & DC_ISR_TX_STATE) == DC_TXSTATE_RESET) && + !DC_IS_ASIX(sc) && !DC_IS_DAVICOM(sc)) + printf("%s: failed to force tx to idle state\n", + sc->sc_dev.dv_xname); + if (!((isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED) && + !DC_HAS_BROKEN_RXSTATE(sc)) + printf("%s: failed to force rx to idle state\n", + sc->sc_dev.dv_xname); + } + CSR_WRITE_4(sc, DC_IMR, 0x00000000); CSR_WRITE_4(sc, DC_TXADDR, 0x00000000); CSR_WRITE_4(sc, DC_RXADDR, 0x00000000); |