diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2004-12-11 05:57:05 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2004-12-11 05:57:05 +0000 |
commit | 2343c314131ff44848240ff6f8b2a4af3a341b54 (patch) | |
tree | ba3502bc4f67ed9ec0f3e89f7983c06301faa17a /sys/dev/pci/if_bge.c | |
parent | b04ba64d0d548aba0f6a2887458c06a5de25a17f (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.c | 60 |
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. */ |