diff options
author | jhb <jhb@FreeBSD.org> | 2008-08-04 19:19:18 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-08-04 19:19:18 +0000 |
commit | 82bee699d17057265199df7a5bc137655bdfae9e (patch) | |
tree | 3d1e8eab296c92d2e69ccb8f79d304033f98dd3a /sys/dev/snc/if_snc.c | |
parent | 448cbffe9ead78f0eef9320b85edc254321106d5 (diff) | |
download | FreeBSD-src-82bee699d17057265199df7a5bc137655bdfae9e.zip FreeBSD-src-82bee699d17057265199df7a5bc137655bdfae9e.tar.gz |
Add locking to snc(4) so it is MPSAFE:
- Add a mutex to the softc to protect the softc and device hardware.
- Use a private timer routine to drive the transmit watchdog timer instead
of using if_watchdog/if_timer.
- If if_alloc() fails during attach, fail the attach with an error rather
than panic'ing.
- Clear RUNNING and OACTIVE only in sncstop().
- Don't mess with IFF_UP.
- Don't leak 'struct ifnet' on detach.
- Setup interrupt handler after ether_ifattach().
- Call ether_ifdetach() rather than if_detach() in the pccard detach
routine.
Tested by: no one despite repeated requests
Diffstat (limited to 'sys/dev/snc/if_snc.c')
-rw-r--r-- | sys/dev/snc/if_snc.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/sys/dev/snc/if_snc.c b/sys/dev/snc/if_snc.c index 7cbdd80..e89e1c7 100644 --- a/sys/dev/snc/if_snc.c +++ b/sys/dev/snc/if_snc.c @@ -159,6 +159,10 @@ snc_release_resources(dev) sc->irq_rid, sc->irq); sc->irq = 0; } + if (sc->sc_ifp) { + if_free(sc->sc_ifp); + sc->sc_ifp = 0; + } } /**************************************************************** @@ -189,6 +193,7 @@ snc_attach(dev) { struct snc_softc *sc = device_get_softc(dev); u_int8_t myea[ETHER_ADDR_LEN]; + int error; if (snc_nec16_register_irq(sc, rman_get_start(sc->irq)) == 0 || snc_nec16_register_mem(sc, rman_get_start(sc->iomem)) == 0) { @@ -220,7 +225,25 @@ snc_attach(dev) return(ENOENT); } - sncconfig(sc, NULL, 0, 0, myea); + mtx_init(&sc->sc_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK, + MTX_DEF); + callout_init_mtx(&sc->sc_timer, &sc->sc_lock, 0); + error = sncconfig(sc, NULL, 0, 0, myea); + if (error) { + snc_release_resources(dev); + mtx_destroy(&sc->sc_lock); + return (error); + } + + error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL, sncintr, sc, &sc->irq_handle); + if (error) { + printf("snc_isa_attach: bus_setup_intr() failed\n"); + ether_ifdetach(sc->sc_ifp); + snc_release_resources(dev); + mtx_destroy(&sc->sc_lock); + return (error); + } return 0; } @@ -233,5 +256,9 @@ void snc_shutdown(dev) device_t dev; { - sncshutdown(device_get_softc(dev)); + struct snc_softc *sc = device_get_softc(dev); + + SNC_LOCK(sc); + sncshutdown(sc); + SNC_UNLOCK(sc); } |