From 544b40d85ed25e5a8f6367b2c065e879d6fd13b0 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Thu, 24 Jan 2019 03:42:23 +0000 Subject: [PATCH] if_iwm - Move iwm_read_firmware() call into iwm_attach(). * We should load the firmware exactly once before the driver really initializes the hardware the first time, and unload it at detach time. There is no need to retrieve the firmware during execution of iwm_mvm_load_ucode_wait_alive(), we should make sure we already have the firmware data at hand before that. * The existing sc_preinit_hook code fails to deal with the case where if_iwm is loaded by the loader (or is statically linked) and the firmware needs to be loaded from disk. So we can just call iwm_read_firmware() from iwm_attach() directly. * A separate solution will have to be added to properly defer the firmware loading during bootup, until the necessary filesystem is mounted. Submitted by: Augustin Cavalier (Haiku) Obtained from: DragonFlyBSD (0104ee1f4cb6a2313c00c2526c6ae98d42e5041d) --- sys/dev/iwm/if_iwm.c | 108 ++++++++++++++++------------------------ sys/dev/iwm/if_iwmvar.h | 10 ---- 2 files changed, 43 insertions(+), 75 deletions(-) diff --git a/sys/dev/iwm/if_iwm.c b/sys/dev/iwm/if_iwm.c index bec08779a4a..14aca4c6d35 100644 --- a/sys/dev/iwm/if_iwm.c +++ b/sys/dev/iwm/if_iwm.c @@ -245,7 +245,7 @@ static int iwm_firmware_store_section(struct iwm_softc *, const uint8_t *, size_t); static int iwm_set_default_calib(struct iwm_softc *, const void *); static void iwm_fw_info_free(struct iwm_fw_info *); -static int iwm_read_firmware(struct iwm_softc *, enum iwm_ucode_type); +static int iwm_read_firmware(struct iwm_softc *); static int iwm_alloc_fwmem(struct iwm_softc *); static int iwm_alloc_sched(struct iwm_softc *); static int iwm_alloc_kw(struct iwm_softc *); @@ -536,12 +536,11 @@ iwm_fw_info_free(struct iwm_fw_info *fw) { firmware_put(fw->fw_fp, FIRMWARE_UNLOAD); fw->fw_fp = NULL; - /* don't touch fw->fw_status */ memset(fw->fw_sects, 0, sizeof(fw->fw_sects)); } static int -iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) +iwm_read_firmware(struct iwm_softc *sc) { struct iwm_fw_info *fw = &sc->sc_fw; const struct iwm_tlv_ucode_header *uhdr; @@ -558,24 +557,11 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) int error = 0; size_t len; - if (fw->fw_status == IWM_FW_STATUS_DONE && - ucode_type != IWM_UCODE_INIT) - return 0; - - while (fw->fw_status == IWM_FW_STATUS_INPROGRESS) - msleep(&sc->sc_fw, &sc->sc_mtx, 0, "iwmfwp", 0); - fw->fw_status = IWM_FW_STATUS_INPROGRESS; - - if (fw->fw_fp != NULL) - iwm_fw_info_free(fw); - /* * Load firmware into driver memory. * fw_fp will be set. */ - IWM_UNLOCK(sc); fwp = firmware_get(sc->cfg->fw_name); - IWM_LOCK(sc); if (fwp == NULL) { device_printf(sc->sc_dev, "could not read firmware %s (error %d)\n", @@ -634,9 +620,8 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) case IWM_UCODE_TLV_PROBE_MAX_LEN: if (tlv_len != sizeof(uint32_t)) { device_printf(sc->sc_dev, - "%s: PROBE_MAX_LEN (%d) != sizeof(uint32_t)\n", - __func__, - (int) tlv_len); + "%s: PROBE_MAX_LEN (%u) != sizeof(uint32_t)\n", + __func__, tlv_len); error = EINVAL; goto parse_out; } @@ -655,9 +640,8 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) case IWM_UCODE_TLV_PAN: if (tlv_len) { device_printf(sc->sc_dev, - "%s: IWM_UCODE_TLV_PAN: tlv_len (%d) > 0\n", - __func__, - (int) tlv_len); + "%s: IWM_UCODE_TLV_PAN: tlv_len (%u) > 0\n", + __func__, tlv_len); error = EINVAL; goto parse_out; } @@ -666,17 +650,15 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) case IWM_UCODE_TLV_FLAGS: if (tlv_len < sizeof(uint32_t)) { device_printf(sc->sc_dev, - "%s: IWM_UCODE_TLV_FLAGS: tlv_len (%d) < sizeof(uint32_t)\n", - __func__, - (int) tlv_len); + "%s: IWM_UCODE_TLV_FLAGS: tlv_len (%u) < sizeof(uint32_t)\n", + __func__, tlv_len); error = EINVAL; goto parse_out; } if (tlv_len % sizeof(uint32_t)) { device_printf(sc->sc_dev, - "%s: IWM_UCODE_TLV_FLAGS: tlv_len (%d) %% sizeof(uint32_t)\n", - __func__, - (int) tlv_len); + "%s: IWM_UCODE_TLV_FLAGS: tlv_len (%u) %% sizeof(uint32_t)\n", + __func__, tlv_len); error = EINVAL; goto parse_out; } @@ -698,17 +680,15 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) tlv_data, tlv_len)) != 0) { device_printf(sc->sc_dev, "%s: iwm_store_cscheme(): returned %d\n", - __func__, - error); + __func__, error); goto parse_out; } break; case IWM_UCODE_TLV_NUM_OF_CPU: if (tlv_len != sizeof(uint32_t)) { device_printf(sc->sc_dev, - "%s: IWM_UCODE_TLV_NUM_OF_CPU: tlv_len (%d) != sizeof(uint32_t)\n", - __func__, - (int) tlv_len); + "%s: IWM_UCODE_TLV_NUM_OF_CPU: tlv_len (%u) != sizeof(uint32_t)\n", + __func__, tlv_len); error = EINVAL; goto parse_out; } @@ -733,8 +713,7 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) IWM_UCODE_REGULAR, tlv_data, tlv_len)) != 0) { device_printf(sc->sc_dev, "%s: IWM_UCODE_REGULAR: iwm_firmware_store_section() failed; %d\n", - __func__, - error); + __func__, error); goto parse_out; } break; @@ -743,8 +722,7 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) IWM_UCODE_INIT, tlv_data, tlv_len)) != 0) { device_printf(sc->sc_dev, "%s: IWM_UCODE_INIT: iwm_firmware_store_section() failed; %d\n", - __func__, - error); + __func__, error); goto parse_out; } break; @@ -753,26 +731,23 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) IWM_UCODE_WOWLAN, tlv_data, tlv_len)) != 0) { device_printf(sc->sc_dev, "%s: IWM_UCODE_WOWLAN: iwm_firmware_store_section() failed; %d\n", - __func__, - error); + __func__, error); goto parse_out; } break; case IWM_UCODE_TLV_DEF_CALIB: if (tlv_len != sizeof(struct iwm_tlv_calib_data)) { device_printf(sc->sc_dev, - "%s: IWM_UCODE_TLV_DEV_CALIB: tlv_len (%d) < sizeof(iwm_tlv_calib_data) (%d)\n", - __func__, - (int) tlv_len, - (int) sizeof(struct iwm_tlv_calib_data)); + "%s: IWM_UCODE_TLV_DEV_CALIB: tlv_len (%u) < sizeof(iwm_tlv_calib_data) (%zu)\n", + __func__, tlv_len, + sizeof(struct iwm_tlv_calib_data)); error = EINVAL; goto parse_out; } if ((error = iwm_set_default_calib(sc, tlv_data)) != 0) { device_printf(sc->sc_dev, "%s: iwm_set_default_calib() failed: %d\n", - __func__, - error); + __func__, error); goto parse_out; } break; @@ -780,9 +755,8 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) if (tlv_len != sizeof(uint32_t)) { error = EINVAL; device_printf(sc->sc_dev, - "%s: IWM_UCODE_TLV_PHY_SKU: tlv_len (%d) < sizeof(uint32_t)\n", - __func__, - (int) tlv_len); + "%s: IWM_UCODE_TLV_PHY_SKU: tlv_len (%u) < sizeof(uint32_t)\n", + __func__, tlv_len); goto parse_out; } sc->sc_fw.phy_config = @@ -907,12 +881,9 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) out: if (error) { - fw->fw_status = IWM_FW_STATUS_NONE; if (fw->fw_fp != NULL) iwm_fw_info_free(fw); - } else - fw->fw_status = IWM_FW_STATUS_DONE; - wakeup(&sc->sc_fw); + } return error; } @@ -2858,11 +2829,6 @@ iwm_mvm_load_ucode_wait_alive(struct iwm_softc *sc, int error; static const uint16_t alive_cmd[] = { IWM_MVM_ALIVE }; - if ((error = iwm_read_firmware(sc, ucode_type)) != 0) { - device_printf(sc->sc_dev, "iwm_read_firmware: failed %d\n", - error); - return error; - } fw = &sc->sc_fw.fw_sects[ucode_type]; sc->cur_ucode = ucode_type; sc->ucode_loaded = FALSE; @@ -5849,7 +5815,7 @@ iwm_attach(device_t dev) sc->sc_wantresp = -1; - /* Check device type */ + /* Match device id */ error = iwm_dev_check(dev); if (error != 0) goto fail; @@ -5987,19 +5953,31 @@ iwm_attach(device_t dev) /* Max RSSI */ sc->sc_max_rssi = IWM_MAX_DBM - IWM_MIN_DBM; - sc->sc_preinit_hook.ich_func = iwm_preinit; - sc->sc_preinit_hook.ich_arg = sc; - if (config_intrhook_establish(&sc->sc_preinit_hook) != 0) { - device_printf(dev, "config_intrhook_establish failed\n"); - goto fail; - } - #ifdef IWM_DEBUG SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "debug", CTLFLAG_RW, &sc->sc_debug, 0, "control debugging"); #endif + error = iwm_read_firmware(sc); + if (error) { + goto fail; + } else if (sc->sc_fw.fw_fp == NULL) { + /* + * XXX Add a solution for properly deferring firmware load + * during bootup. + */ + goto fail; + } else { + sc->sc_preinit_hook.ich_func = iwm_preinit; + sc->sc_preinit_hook.ich_arg = sc; + if (config_intrhook_establish(&sc->sc_preinit_hook) != 0) { + device_printf(dev, + "config_intrhook_establish failed\n"); + goto fail; + } + } + IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_TRACE, "<-%s\n", __func__); diff --git a/sys/dev/iwm/if_iwmvar.h b/sys/dev/iwm/if_iwmvar.h index 07f0d1535e1..6dfa1b100b1 100644 --- a/sys/dev/iwm/if_iwmvar.h +++ b/sys/dev/iwm/if_iwmvar.h @@ -139,15 +139,6 @@ struct iwm_tx_radiotap_header { #define IWM_UCODE_SECTION_MAX 16 -/* - * fw_status is used to determine if we've already parsed the firmware file - * - * In addition to the following, status < 0 ==> -error - */ -#define IWM_FW_STATUS_NONE 0 -#define IWM_FW_STATUS_INPROGRESS 1 -#define IWM_FW_STATUS_DONE 2 - /** * enum iwm_ucode_type * @@ -197,7 +188,6 @@ struct iwm_fw_desc { struct iwm_fw_info { const struct firmware *fw_fp; - int fw_status; struct iwm_fw_sects { struct iwm_fw_desc fw_sect[IWM_UCODE_SECTION_MAX]; -- 2.45.0