Currently iwm(4) reads the firmware image from disk once and
then keeps using its in-memory copy of the firmware image.
This diff makes it possible to load a new fw image from disk
without a reboot in case the firmware is upgraded in the future.
While here, remove some unused fields from the fw info structure.
Can iwm users please test this?
Index: if_iwm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
retrieving revision 1.21
diff -u -p -r1.21 if_iwm.c
--- if_iwm.c 21 Feb 2015 09:53:49 -0000 1.21
+++ if_iwm.c 21 Feb 2015 11:13:20 -0000
@@ -210,7 +210,8 @@ int iwm_store_cscheme(struct iwm_softc *
int iwm_firmware_store_section(struct iwm_softc *, enum iwm_ucode_type,
uint8_t *, size_t);
int iwm_set_default_calib(struct iwm_softc *, const void *);
-int iwm_read_firmware(struct iwm_softc *);
+void iwm_fw_info_free(struct iwm_fw_info *);
+int iwm_read_firmware(struct iwm_softc *, enum iwm_ucode_type);
uint32_t iwm_read_prph(struct iwm_softc *, uint32_t);
void iwm_write_prph(struct iwm_softc *, uint32_t, uint32_t);
int iwm_read_mem(struct iwm_softc *, uint32_t, void *, int);
@@ -472,10 +473,6 @@ iwm_firmware_store_section(struct iwm_so
fwone->fws_data = data + sizeof(uint32_t);
fwone->fws_len = dlen - sizeof(uint32_t);
- /* for freeing the buffer during driver unload */
- fwone->fws_alloc = data;
- fwone->fws_allocsize = dlen;
-
fws->fw_count++;
fws->fw_totlen += fwone->fws_len;
@@ -508,28 +505,38 @@ iwm_set_default_calib(struct iwm_softc *
return 0;
}
+void
+iwm_fw_info_free(struct iwm_fw_info *fw)
+{
+ free(fw->fw_rawdata, M_DEVBUF, fw->fw_rawsize);
+ fw->fw_rawdata = NULL;
+ fw->fw_rawsize = 0;
+ /* don't touch fw->fw_status */
+ memset(fw->fw_sects, 0, sizeof(fw->fw_sects));
+}
+
int
-iwm_read_firmware(struct iwm_softc *sc)
+iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
{
struct iwm_fw_info *fw = &sc->sc_fw;
struct iwm_tlv_ucode_header *uhdr;
struct iwm_ucode_tlv tlv;
enum iwm_ucode_tlv_type tlv_type;
uint8_t *data;
- int error, status;
+ int error;
size_t len;
- if (fw->fw_status == IWM_FW_STATUS_NONE) {
- fw->fw_status = IWM_FW_STATUS_INPROGRESS;
- } else {
- while (fw->fw_status == IWM_FW_STATUS_INPROGRESS)
- tsleep(&sc->sc_fw, 0, "iwmfwp", 0);
- }
- status = fw->fw_status;
-
- if (status == IWM_FW_STATUS_DONE)
+ if (fw->fw_status == IWM_FW_STATUS_DONE &&
+ ucode_type != IWM_UCODE_TYPE_INIT)
return 0;
+ while (fw->fw_status == IWM_FW_STATUS_INPROGRESS)
+ tsleep(&sc->sc_fw, 0, "iwmfwp", 0);
+ fw->fw_status = IWM_FW_STATUS_INPROGRESS;
+
+ if (fw->fw_rawdata != NULL)
+ iwm_fw_info_free(fw);
+
/*
* Load firmware into driver memory.
* fw_rawdata and fw_rawsize will be set.
@@ -687,8 +694,8 @@ iwm_read_firmware(struct iwm_softc *sc)
parse_out:
if (error) {
- printf("%s: firmware parse error, "
- "section type %d\n", DEVNAME(sc), tlv_type);
+ printf("%s: firmware parse error %d, "
+ "section type %d\n", DEVNAME(sc), error, tlv_type);
}
if (!(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) {
@@ -697,16 +704,14 @@ iwm_read_firmware(struct iwm_softc *sc)
}
out:
- if (error)
+ if (error) {
fw->fw_status = IWM_FW_STATUS_NONE;
- else
+ if (fw->fw_rawdata != NULL)
+ iwm_fw_info_free(fw);
+ } else
fw->fw_status = IWM_FW_STATUS_DONE;
wakeup(&sc->sc_fw);
- if (error) {
- free(fw->fw_rawdata, M_DEVBUF, fw->fw_rawsize);
- fw->fw_rawdata = NULL;
- }
return error;
}
@@ -2778,7 +2783,7 @@ iwm_mvm_load_ucode_wait_alive(struct iwm
enum iwm_ucode_type old_type = sc->sc_uc_current;
int error;
- if ((error = iwm_read_firmware(sc)) != 0)
+ if ((error = iwm_read_firmware(sc, ucode_type)) != 0)
return error;
sc->sc_uc_current = ucode_type;
Index: if_iwmvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwmvar.h,v
retrieving revision 1.3
diff -u -p -r1.3 if_iwmvar.h
--- if_iwmvar.h 7 Feb 2015 07:10:44 -0000 1.3
+++ if_iwmvar.h 21 Feb 2015 11:01:12 -0000
@@ -169,9 +169,6 @@ struct iwm_fw_info {
void *fws_data;
uint32_t fws_len;
uint32_t fws_devoff;
-
- void *fws_alloc;
- size_t fws_allocsize;
} fw_sect[IWM_UCODE_SECT_MAX];
size_t fw_totlen;
int fw_count;