summaryrefslogtreecommitdiffstats
path: root/sys/dev/snc/if_snc.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-08-04 19:19:18 +0000
committerjhb <jhb@FreeBSD.org>2008-08-04 19:19:18 +0000
commit82bee699d17057265199df7a5bc137655bdfae9e (patch)
tree3d1e8eab296c92d2e69ccb8f79d304033f98dd3a /sys/dev/snc/if_snc.c
parent448cbffe9ead78f0eef9320b85edc254321106d5 (diff)
downloadFreeBSD-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.c31
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);
}
OpenPOWER on IntegriCloud