summaryrefslogtreecommitdiffstats
path: root/sys/dev/bge
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2010-10-11 23:07:12 +0000
committeryongari <yongari@FreeBSD.org>2010-10-11 23:07:12 +0000
commit085f670a14180dd3ed16eb9cd2bd473429f4dad3 (patch)
treeac9c2758357762de7017b04f8f186c15bae52026 /sys/dev/bge
parent5e785f1b246399f8245fb9f7e746740fab93110a (diff)
downloadFreeBSD-src-085f670a14180dd3ed16eb9cd2bd473429f4dad3.zip
FreeBSD-src-085f670a14180dd3ed16eb9cd2bd473429f4dad3.tar.gz
The IFF_DRV_RUNNING flag is set at the end of bge_init_locked. But
before setting the flag, interrupt was already enabled such that interrupt handler could be run before setting IFF_DRV_RUNNING flag. This can lose initial link state change interrupt which in turn make bge(4) think that it still does not have valid link. Fix this race by protecting the taskqueue with a driver lock. While I'm here move reenabling interrupt code after handling of link state chage. Reviewed by: davidch
Diffstat (limited to 'sys/dev/bge')
-rw-r--r--sys/dev/bge/if_bge.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c
index f408338..a439ad3 100644
--- a/sys/dev/bge/if_bge.c
+++ b/sys/dev/bge/if_bge.c
@@ -3629,8 +3629,11 @@ bge_intr_task(void *arg, int pending)
sc = (struct bge_softc *)arg;
ifp = sc->bge_ifp;
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ BGE_LOCK(sc);
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ BGE_UNLOCK(sc);
return;
+ }
/* Get updated status block. */
bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
@@ -3645,26 +3648,27 @@ bge_intr_task(void *arg, int pending)
bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
sc->bge_cdata.bge_status_map,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ if ((status & BGE_STATFLAG_LINKSTATE_CHANGED) != 0)
+ bge_link_upd(sc);
+
/* Let controller work. */
bge_writembx(sc, BGE_MBX_IRQ0_LO, 0);
- if ((status & BGE_STATFLAG_LINKSTATE_CHANGED) != 0) {
- BGE_LOCK(sc);
- bge_link_upd(sc);
- BGE_UNLOCK(sc);
- }
- if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
+ sc->bge_rx_saved_considx != rx_prod) {
/* Check RX return ring producer/consumer. */
+ BGE_UNLOCK(sc);
bge_rxeof(sc, rx_prod, 0);
+ BGE_LOCK(sc);
}
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- BGE_LOCK(sc);
/* Check TX ring producer/consumer. */
bge_txeof(sc, tx_cons);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
bge_start_locked(ifp);
- BGE_UNLOCK(sc);
}
+ BGE_UNLOCK(sc);
}
static void
OpenPOWER on IntegriCloud