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).
This commit is contained in:
parent
eb1030c4fd
commit
cbe2bd55ad
@ -390,6 +390,11 @@ ipw_detach(device_t dev)
|
|||||||
if (ifp != NULL)
|
if (ifp != NULL)
|
||||||
if_free(ifp);
|
if_free(ifp);
|
||||||
|
|
||||||
|
if (sc->sc_firmware != NULL) {
|
||||||
|
firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD);
|
||||||
|
sc->sc_firmware = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
mtx_destroy(&sc->sc_mtx);
|
mtx_destroy(&sc->sc_mtx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2002,16 +2007,22 @@ ipw_init(void *priv)
|
|||||||
* Load firmware image using the firmware(9) subsystem. We need to
|
* Load firmware image using the firmware(9) subsystem. We need to
|
||||||
* release the driver's lock first.
|
* release the driver's lock first.
|
||||||
*/
|
*/
|
||||||
|
if (sc->sc_firmware == NULL || strcmp(sc->sc_firmware->name,
|
||||||
|
imagename) != 0) {
|
||||||
mtx_unlock(&sc->sc_mtx);
|
mtx_unlock(&sc->sc_mtx);
|
||||||
fp = firmware_get(imagename);
|
if (sc->sc_firmware != NULL)
|
||||||
|
firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD);
|
||||||
|
sc->sc_firmware = firmware_get(imagename);
|
||||||
mtx_lock(&sc->sc_mtx);
|
mtx_lock(&sc->sc_mtx);
|
||||||
|
}
|
||||||
|
|
||||||
if (fp == NULL) {
|
if (sc->sc_firmware == NULL) {
|
||||||
device_printf(sc->sc_dev,
|
device_printf(sc->sc_dev,
|
||||||
"could not load firmware image '%s'\n", imagename);
|
"could not load firmware image '%s'\n", imagename);
|
||||||
goto fail1;
|
goto fail1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fp = sc->sc_firmware;
|
||||||
if (fp->datasize < sizeof *hdr) {
|
if (fp->datasize < sizeof *hdr) {
|
||||||
device_printf(sc->sc_dev,
|
device_printf(sc->sc_dev,
|
||||||
"firmware image too short %zu\n", fp->datasize);
|
"firmware image too short %zu\n", fp->datasize);
|
||||||
@ -2061,7 +2072,6 @@ ipw_init(void *priv)
|
|||||||
goto fail2;
|
goto fail2;
|
||||||
}
|
}
|
||||||
|
|
||||||
firmware_put(fp, FIRMWARE_UNLOAD);
|
|
||||||
sc->flags |= IPW_FLAG_FW_INITED;
|
sc->flags |= IPW_FLAG_FW_INITED;
|
||||||
|
|
||||||
/* retrieve information tables base addresses */
|
/* retrieve information tables base addresses */
|
||||||
@ -2086,6 +2096,7 @@ ipw_init(void *priv)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
fail2: firmware_put(fp, FIRMWARE_UNLOAD);
|
fail2: firmware_put(fp, FIRMWARE_UNLOAD);
|
||||||
|
sc->sc_firmware = NULL;
|
||||||
fail1: ifp->if_flags &= ~IFF_UP;
|
fail1: ifp->if_flags &= ~IFF_UP;
|
||||||
ipw_stop(sc);
|
ipw_stop(sc);
|
||||||
sc->flags &=~ IPW_FLAG_INIT_LOCKED;
|
sc->flags &=~ IPW_FLAG_INIT_LOCKED;
|
||||||
|
@ -99,6 +99,7 @@ struct ipw_softc {
|
|||||||
bus_space_tag_t sc_st;
|
bus_space_tag_t sc_st;
|
||||||
bus_space_handle_t sc_sh;
|
bus_space_handle_t sc_sh;
|
||||||
void *sc_ih;
|
void *sc_ih;
|
||||||
|
struct firmware *sc_firmware;
|
||||||
|
|
||||||
int sc_tx_timer;
|
int sc_tx_timer;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user