aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ipw
diff options
context:
space:
mode:
authorIan Dowse <iedowse@FreeBSD.org>2006-06-10 17:29:40 +0000
committerIan Dowse <iedowse@FreeBSD.org>2006-06-10 17:29:40 +0000
commitcbe2bd55ad7d0bd0ae26b0bd453ee9ba374d683a (patch)
tree8374e26acc630943f274f2945e5994506c6dfb44 /sys/dev/ipw
parenteb1030c4fd5dbda71009b4345e83c7324a6b8875 (diff)
downloadsrc-cbe2bd55ad7d0bd0ae26b0bd453ee9ba374d683a.tar.gz
src-cbe2bd55ad7d0bd0ae26b0bd453ee9ba374d683a.zip
Hold on to firmware images until the interface detaches since
firmware_get() will not work while resuming. Note that we can't simply drop the FIRMWARE_UNLOAD flag, because that will result in a firmware image that can never be unloaded by the user since the firmware subsystem will hold a linker reference to it (it's not clear that firmware_put() without FIRMWARE_UNLOAD ever does quite what you'd want).
Notes
Notes: svn path=/head/; revision=159487
Diffstat (limited to 'sys/dev/ipw')
-rw-r--r--sys/dev/ipw/if_ipw.c21
-rw-r--r--sys/dev/ipw/if_ipwvar.h1
2 files changed, 17 insertions, 5 deletions
diff --git a/sys/dev/ipw/if_ipw.c b/sys/dev/ipw/if_ipw.c
index bdde37c608f4..69761f652fed 100644
--- a/sys/dev/ipw/if_ipw.c
+++ b/sys/dev/ipw/if_ipw.c
@@ -390,6 +390,11 @@ ipw_detach(device_t dev)
if (ifp != NULL)
if_free(ifp);
+ if (sc->sc_firmware != NULL) {
+ firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD);
+ sc->sc_firmware = NULL;
+ }
+
mtx_destroy(&sc->sc_mtx);
return 0;
@@ -2002,16 +2007,22 @@ ipw_init(void *priv)
* Load firmware image using the firmware(9) subsystem. We need to
* release the driver's lock first.
*/
- mtx_unlock(&sc->sc_mtx);
- fp = firmware_get(imagename);
- mtx_lock(&sc->sc_mtx);
+ if (sc->sc_firmware == NULL || strcmp(sc->sc_firmware->name,
+ imagename) != 0) {
+ mtx_unlock(&sc->sc_mtx);
+ if (sc->sc_firmware != NULL)
+ firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD);
+ sc->sc_firmware = firmware_get(imagename);
+ mtx_lock(&sc->sc_mtx);
+ }
- if (fp == NULL) {
+ if (sc->sc_firmware == NULL) {
device_printf(sc->sc_dev,
"could not load firmware image '%s'\n", imagename);
goto fail1;
}
+ fp = sc->sc_firmware;
if (fp->datasize < sizeof *hdr) {
device_printf(sc->sc_dev,
"firmware image too short %zu\n", fp->datasize);
@@ -2061,7 +2072,6 @@ ipw_init(void *priv)
goto fail2;
}
- firmware_put(fp, FIRMWARE_UNLOAD);
sc->flags |= IPW_FLAG_FW_INITED;
/* retrieve information tables base addresses */
@@ -2086,6 +2096,7 @@ ipw_init(void *priv)
return;
fail2: firmware_put(fp, FIRMWARE_UNLOAD);
+ sc->sc_firmware = NULL;
fail1: ifp->if_flags &= ~IFF_UP;
ipw_stop(sc);
sc->flags &=~ IPW_FLAG_INIT_LOCKED;
diff --git a/sys/dev/ipw/if_ipwvar.h b/sys/dev/ipw/if_ipwvar.h
index aaf1a0a3cf3c..3cfb77e017cd 100644
--- a/sys/dev/ipw/if_ipwvar.h
+++ b/sys/dev/ipw/if_ipwvar.h
@@ -99,6 +99,7 @@ struct ipw_softc {
bus_space_tag_t sc_st;
bus_space_handle_t sc_sh;
void *sc_ih;
+ struct firmware *sc_firmware;
int sc_tx_timer;