@@ -1020,36 +1167,49 @@ int iwn_load_firmware(struct iwn_softc *sc) { + int error; + + KASSERT(sc->fw_fp == NULL, ("firmware already loaded")); + + IWN_UNLOCK(sc); + /* load firmware image from disk */ + sc->fw_fp = firmware_get("iwnfw"); + if (sc->fw_fp == NULL) { + device_printf(sc->sc_dev, + "%s: could not load firmare image \"iwnfw\"\n", __func__); + error = EINVAL; + } else + error = 0; + IWN_LOCK(sc); + return error; +} + +int +iwn_transfer_firmware(struct iwn_softc *sc) +{ struct iwn_dma_info *dma = &sc->fw_dma; const struct iwn_firmware_hdr *hdr; const uint8_t *init_text, *init_data, *main_text, *main_data; const uint8_t *boot_text; uint32_t init_textsz, init_datasz, main_textsz, main_datasz; uint32_t boot_textsz; - u_char *fw; - size_t size; - int error; - - /* load firmware image from disk */ - if ((error = loadfirmware("iwn-4965agn", &fw, &size)) != 0) { - printf("%s: error, %d, could not read firmware %s\n", - sc->sc_dev.dv_xname, error, "iwn-4965agn"); - goto fail1; - } + int error = 0; + const struct firmware *fp = sc->fw_fp; /* extract firmware header information */ - if (size < sizeof (struct iwn_firmware_hdr)) { - printf("%s: truncated firmware header: %d bytes\n", - sc->sc_dev.dv_xname, size); + if (fp->datasize < sizeof (struct iwn_firmware_hdr)) { + device_printf(sc->sc_dev, + "%s: truncated firmware header: %zu bytes, expecting %zu\n", + __func__, fp->datasize, sizeof (struct iwn_firmware_hdr)); error = EINVAL; - goto fail2; + goto fail; } - hdr = (const struct iwn_firmware_hdr *)fw; - main_textsz = letoh32(hdr->main_textsz); - main_datasz = letoh32(hdr->main_datasz); - init_textsz = letoh32(hdr->init_textsz); - init_datasz = letoh32(hdr->init_datasz); - boot_textsz = letoh32(hdr->boot_textsz); + hdr = (const struct iwn_firmware_hdr *)fp->data; + main_textsz = le32toh(hdr->main_textsz); + main_datasz = le32toh(hdr->main_datasz); + init_textsz = le32toh(hdr->init_textsz); + init_datasz = le32toh(hdr->init_datasz); + boot_textsz = le32toh(hdr->boot_textsz); /* sanity-check firmware segments sizes */ if (main_textsz > IWN_FW_MAIN_TEXT_MAXSZ || @@ -1058,18 +1218,23 @@ init_datasz > IWN_FW_INIT_DATA_MAXSZ || boot_textsz > IWN_FW_BOOT_TEXT_MAXSZ || (boot_textsz & 3) != 0) { - printf("%s: invalid firmware header\n", sc->sc_dev.dv_xname); + device_printf(sc->sc_dev, + "%s: invalid firmware header, main [%d,%d], init [%d,%d] " + "boot %d\n", __func__, main_textsz, main_datasz, + init_textsz, init_datasz, boot_textsz); error = EINVAL; - goto fail2; + goto fail; } /* check that all firmware segments are present */ - if (size < sizeof (struct iwn_firmware_hdr) + main_textsz + + if (fp->datasize < sizeof (struct iwn_firmware_hdr) + main_textsz + main_datasz + init_textsz + init_datasz + boot_textsz) { - printf("%s: firmware file too short: %d bytes\n", - sc->sc_dev.dv_xname, size); + device_printf(sc->sc_dev, "%s: firmware file too short: " + "%zu bytes, main [%d, %d], init [%d,%d] boot %d\n", + __func__, fp->datasize, main_textsz, main_datasz, + init_textsz, init_datasz, boot_textsz); error = EINVAL; - goto fail2; + goto fail; } /* get pointers to firmware segments */ @@ -1093,21 +1258,25 @@ iwn_mem_unlock(sc); /* load firmware boot code */ - if ((error = iwn_load_microcode(sc, boot_text, boot_textsz)) != 0) { - printf("%s: could not load boot firmware\n", - sc->sc_dev.dv_xname); - goto fail2; + error = iwn_transfer_microcode(sc, boot_text, boot_textsz); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not load boot firmware, error %d\n", + __func__, error); + goto fail; } /* now press "execute" ;-) */ IWN_WRITE(sc, IWN_RESET, 0); /* wait at most one second for first alive notification */ - if ((error = tsleep(sc, PCATCH, "iwninit", hz)) != 0) { + error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", hz); + if (error != 0) { /* this isn't what was supposed to happen.. */ - printf("%s: timeout waiting for adapter to initialize\n", - sc->sc_dev.dv_xname); - goto fail2; + device_printf(sc->sc_dev, + "%s: timeout waiting for first alive notice, error %d\n", + __func__, error); + goto fail; } /* copy runtime images into pre-allocated DMA-safe memory */ @@ -1124,50 +1293,50 @@ iwn_mem_unlock(sc); /* wait at most one second for second alive notification */ - if ((error = tsleep(sc, PCATCH, "iwninit", hz)) != 0) { + error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", hz); + if (error != 0) { /* this isn't what was supposed to happen.. */ - printf("%s: timeout waiting for adapter to initialize\n", - sc->sc_dev.dv_xname); + device_printf(sc->sc_dev, + "%s: timeout waiting for second alive notice, error %d\n", + __func__, error); + goto fail; } - -fail2: free(fw, M_DEVBUF); -fail1: return error; + return 0; +fail: + return error; }