summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_bge.c
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2004-12-11 05:57:05 +0000
committerBrad Smith <brad@cvs.openbsd.org>2004-12-11 05:57:05 +0000
commit2343c314131ff44848240ff6f8b2a4af3a341b54 (patch)
treeba3502bc4f67ed9ec0f3e89f7983c06301faa17a /sys/dev/pci/if_bge.c
parentb04ba64d0d548aba0f6a2887458c06a5de25a17f (diff)
rev 1.11
When stopping the various functional blocks of the chip, clear the bit and then read it back in a loop (with appropriate delays) waiting for it to read back clear. This fixes a problem where the bus would hang when bringing down the interface or changing interface flags on a system with a sufficiently fast CPU (e.g. 2GHz P4 Xeon). From NetBSD ok krw@
Diffstat (limited to 'sys/dev/pci/if_bge.c')
-rw-r--r--sys/dev/pci/if_bge.c60
1 files changed, 40 insertions, 20 deletions
diff --git a/sys/dev/pci/if_bge.c b/sys/dev/pci/if_bge.c
index ec5a788015c..0afebaa1a94 100644
--- a/sys/dev/pci/if_bge.c
+++ b/sys/dev/pci/if_bge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bge.c,v 1.40 2004/12/10 05:04:23 brad Exp $ */
+/* $OpenBSD: if_bge.c,v 1.41 2004/12/11 05:57:04 brad Exp $ */
/*
* Copyright (c) 2001 Wind River Systems
* Copyright (c) 1997, 1998, 1999, 2001
@@ -132,6 +132,7 @@ int bge_intr(void *);
void bge_start(struct ifnet *);
int bge_ioctl(struct ifnet *, u_long, caddr_t);
void bge_init(void *);
+void bge_stop_block(struct bge_softc *, bus_addr_t, uint32_t);
void bge_stop(struct bge_softc *);
void bge_watchdog(struct ifnet *);
void bge_shutdown(void *);
@@ -2893,6 +2894,23 @@ bge_watchdog(ifp)
ifp->if_oerrors++;
}
+void
+bge_stop_block(struct bge_softc *sc, bus_addr_t reg, uint32_t bit)
+{
+ int i;
+
+ BGE_CLRBIT(sc, reg, bit);
+
+ for (i = 0; i < BGE_TIMEOUT; i++) {
+ if ((CSR_READ_4(sc, reg) & bit) == 0)
+ return;
+ delay(100);
+ }
+
+ printf("%s: block failed to stop: reg 0x%lx, bit 0x%08x\n",
+ sc->bge_dev.dv_xname, (u_long) reg, bit);
+}
+
/*
* Stop the adapter and free any mbufs allocated to the
* RX and TX lists.
@@ -2911,44 +2929,46 @@ bge_stop(sc)
/*
* Disable all of the receiver blocks
*/
- BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_RBDI_MODE, BGE_RBDIMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_RXLP_MODE, BGE_RXLPMODE_ENABLE);
+ bge_stop_block(sc, BGE_RX_MODE, BGE_RXMODE_ENABLE);
+ bge_stop_block(sc, BGE_RBDI_MODE, BGE_RBDIMODE_ENABLE);
+ bge_stop_block(sc, BGE_RXLP_MODE, BGE_RXLPMODE_ENABLE);
if (sc->bge_asicrev != BGE_ASICREV_BCM5705 &&
sc->bge_asicrev != BGE_ASICREV_BCM5750)
- BGE_CLRBIT(sc, BGE_RXLS_MODE, BGE_RXLSMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_RDBDI_MODE, BGE_RBDIMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_RDC_MODE, BGE_RDCMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_RBDC_MODE, BGE_RBDCMODE_ENABLE);
+ bge_stop_block(sc, BGE_RXLS_MODE, BGE_RXLSMODE_ENABLE);
+ bge_stop_block(sc, BGE_RDBDI_MODE, BGE_RBDIMODE_ENABLE);
+ bge_stop_block(sc, BGE_RDC_MODE, BGE_RDCMODE_ENABLE);
+ bge_stop_block(sc, BGE_RBDC_MODE, BGE_RBDCMODE_ENABLE);
/*
* Disable all of the transmit blocks
*/
- BGE_CLRBIT(sc, BGE_SRS_MODE, BGE_SRSMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_SBDI_MODE, BGE_SBDIMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_RDMA_MODE, BGE_RDMAMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_SDC_MODE, BGE_SDCMODE_ENABLE);
+ bge_stop_block(sc, BGE_SRS_MODE, BGE_SRSMODE_ENABLE);
+ bge_stop_block(sc, BGE_SBDI_MODE, BGE_SBDIMODE_ENABLE);
+ bge_stop_block(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE);
+ bge_stop_block(sc, BGE_RDMA_MODE, BGE_RDMAMODE_ENABLE);
+ bge_stop_block(sc, BGE_SDC_MODE, BGE_SDCMODE_ENABLE);
if (sc->bge_asicrev != BGE_ASICREV_BCM5705 &&
sc->bge_asicrev != BGE_ASICREV_BCM5750)
- BGE_CLRBIT(sc, BGE_DMAC_MODE, BGE_DMACMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_SBDC_MODE, BGE_SBDCMODE_ENABLE);
+ bge_stop_block(sc, BGE_DMAC_MODE, BGE_DMACMODE_ENABLE);
+ bge_stop_block(sc, BGE_SBDC_MODE, BGE_SBDCMODE_ENABLE);
/*
* Shut down all of the memory managers and related
* state machines.
*/
- BGE_CLRBIT(sc, BGE_HCC_MODE, BGE_HCCMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_WDMA_MODE, BGE_WDMAMODE_ENABLE);
+ bge_stop_block(sc, BGE_HCC_MODE, BGE_HCCMODE_ENABLE);
+ bge_stop_block(sc, BGE_WDMA_MODE, BGE_WDMAMODE_ENABLE);
if (sc->bge_asicrev != BGE_ASICREV_BCM5705 &&
sc->bge_asicrev != BGE_ASICREV_BCM5750)
- BGE_CLRBIT(sc, BGE_MBCF_MODE, BGE_MBCFMODE_ENABLE);
+ bge_stop_block(sc, BGE_MBCF_MODE, BGE_MBCFMODE_ENABLE);
+
CSR_WRITE_4(sc, BGE_FTQ_RESET, 0xFFFFFFFF);
CSR_WRITE_4(sc, BGE_FTQ_RESET, 0);
+
if (sc->bge_asicrev != BGE_ASICREV_BCM5705 &&
sc->bge_asicrev != BGE_ASICREV_BCM5750) {
- BGE_CLRBIT(sc, BGE_BMAN_MODE, BGE_BMANMODE_ENABLE);
- BGE_CLRBIT(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE);
+ bge_stop_block(sc, BGE_BMAN_MODE, BGE_BMANMODE_ENABLE);
+ bge_stop_block(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE);
}
/* Disable host interrupts. */