diff options
author | Ian Dowse <iedowse@FreeBSD.org> | 2006-06-10 17:29:40 +0000 |
---|---|---|
committer | Ian Dowse <iedowse@FreeBSD.org> | 2006-06-10 17:29:40 +0000 |
commit | cbe2bd55ad7d0bd0ae26b0bd453ee9ba374d683a (patch) | |
tree | 8374e26acc630943f274f2945e5994506c6dfb44 /sys/dev/ipw | |
parent | eb1030c4fd5dbda71009b4345e83c7324a6b8875 (diff) | |
download | src-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.c | 21 | ||||
-rw-r--r-- | sys/dev/ipw/if_ipwvar.h | 1 |
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; |