summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2011-03-05 13:39:27 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2011-03-05 13:39:27 +0000
commit6dcf994cd13b7d40e8dcede8b3829e9e4d6b0bcd (patch)
tree9d842047de9d22816e18f7bbc09ed4b09ea87550 /sys/dev
parent1275466d50991b94b25f51b2a3487e63bdea1a96 (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.c25
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);