static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) { struct iwl_drv *drv = context; const struct iwl_cfg *cfg = cfg(drv); struct iwl_fw *fw = &drv->fw; struct iwl_ucode_header *ucode; int err; struct iwl_firmware_pieces pieces; const unsigned int api_max = cfg->ucode_api_max; unsigned int api_ok = cfg->ucode_api_ok; const unsigned int api_min = cfg->ucode_api_min; u32 api_ver; int i; fw->ucode_capa.max_probe_length = 200; fw->ucode_capa.standard_phy_calibration_size = IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; if (!api_ok) api_ok = api_max; memset(&pieces, 0, sizeof(pieces)); if (!ucode_raw) { if (drv->fw_index <= api_ok) IWL_ERR(drv, "request for firmware file '%s' failed.\n", drv->firmware_name); goto try_again; } IWL_DEBUG_INFO(drv, "Loaded firmware file '%s' (%zd bytes).\n", drv->firmware_name, ucode_raw->size); if (ucode_raw->size < 4) { IWL_ERR(drv, "File size way too small!\n"); goto try_again; } ucode = (struct iwl_ucode_header *)ucode_raw->data; if (ucode->ver) err = iwl_parse_v1_v2_firmware(drv, ucode_raw, &pieces); else err = iwl_parse_tlv_firmware(drv, ucode_raw, &pieces, &fw->ucode_capa); if (err) goto try_again; api_ver = IWL_UCODE_API(drv->fw.ucode_ver); if (drv->fw_index != UCODE_EXPERIMENTAL_INDEX) { if (api_ver < api_min || api_ver > api_max) { IWL_ERR(drv, "Driver unable to support your firmware API. " "Driver supports v%u, firmware is v%u.\n", api_max, api_ver); goto try_again; } if (api_ver < api_ok) { if (api_ok != api_max) IWL_ERR(drv, "Firmware has old API version, " "expected v%u through v%u, got v%u.\n", api_ok, api_max, api_ver); else IWL_ERR(drv, "Firmware has old API version, " "expected v%u, got v%u.\n", api_max, api_ver); IWL_ERR(drv, "New firmware can be obtained from " "http://www.intellinuxwireless.org/.\n"); } } IWL_INFO(drv, "loaded firmware version %s", drv->fw.fw_version); IWL_DEBUG_INFO(drv, "f/w package hdr ucode version raw = 0x%x\n", drv->fw.ucode_ver); IWL_DEBUG_INFO(drv, "f/w package hdr runtime inst size = %Zd\n", get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST)); IWL_DEBUG_INFO(drv, "f/w package hdr runtime data size = %Zd\n", get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA)); IWL_DEBUG_INFO(drv, "f/w package hdr init inst size = %Zd\n", get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST)); IWL_DEBUG_INFO(drv, "f/w package hdr init data size = %Zd\n", get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA)); if (get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) > cfg->max_inst_size) { IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n", get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST)); goto try_again; } if (get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) > cfg->max_data_size) { IWL_ERR(drv, "uCode data len %Zd too large to fit in\n", get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA)); goto try_again; } if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, cfg)) goto try_again; for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) if (alloc_pci_desc(drv, &pieces, i)) goto err_pci_alloc; fw->init_evtlog_ptr = pieces.init_evtlog_ptr; if (pieces.init_evtlog_size) fw->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; else fw->init_evtlog_size = cfg->base_params->max_event_log_size; fw->init_errlog_ptr = pieces.init_errlog_ptr; fw->inst_evtlog_ptr = pieces.inst_evtlog_ptr; if (pieces.inst_evtlog_size) fw->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; else fw->inst_evtlog_size = cfg->base_params->max_event_log_size; fw->inst_errlog_ptr = pieces.inst_errlog_ptr; if (fw->ucode_capa.standard_phy_calibration_size > IWL_MAX_PHY_CALIBRATE_TBL_SIZE) fw->ucode_capa.standard_phy_calibration_size = IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE; release_firmware(ucode_raw); complete(&drv->request_firmware_complete); drv->op_mode = iwl_dvm_ops.start(drv->shrd->trans, &drv->fw); if (!drv->op_mode) goto out_unbind; return; try_again: release_firmware(ucode_raw); if (iwl_request_firmware(drv, false)) goto out_unbind; return; err_pci_alloc: IWL_ERR(drv, "failed to allocate pci memory\n"); iwl_dealloc_ucode(drv); release_firmware(ucode_raw); out_unbind: complete(&drv->request_firmware_complete); device_release_driver(trans(drv)->dev); }
/** * iwl_ucode_callback - callback when firmware was loaded * * If loaded successfully, copies the firmware into buffers * for the card to fetch (via DMA). */ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) { struct iwl_drv *drv = context; struct iwl_fw *fw = &drv->fw; struct iwl_ucode_header *ucode; int err; struct iwl_firmware_pieces pieces; const unsigned int api_max = drv->cfg->ucode_api_max; unsigned int api_ok = drv->cfg->ucode_api_ok; const unsigned int api_min = drv->cfg->ucode_api_min; u32 api_ver; int i; fw->ucode_capa.max_probe_length = 200; fw->ucode_capa.standard_phy_calibration_size = IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; if (!api_ok) api_ok = api_max; memset(&pieces, 0, sizeof(pieces)); if (!ucode_raw) { if (drv->fw_index <= api_ok) IWL_ERR(drv, "request for firmware file '%s' failed.\n", drv->firmware_name); goto try_again; } IWL_DEBUG_INFO(drv, "Loaded firmware file '%s' (%zd bytes).\n", drv->firmware_name, ucode_raw->size); /* Make sure that we got at least the API version number */ if (ucode_raw->size < 4) { IWL_ERR(drv, "File size way too small!\n"); goto try_again; } /* Data from ucode file: header followed by uCode images */ ucode = (struct iwl_ucode_header *)ucode_raw->data; if (ucode->ver) err = iwl_parse_v1_v2_firmware(drv, ucode_raw, &pieces); else err = iwl_parse_tlv_firmware(drv, ucode_raw, &pieces, &fw->ucode_capa); if (err) goto try_again; api_ver = IWL_UCODE_API(drv->fw.ucode_ver); /* * api_ver should match the api version forming part of the * firmware filename ... but we don't check for that and only rely * on the API version read from firmware header from here on forward */ /* no api version check required for experimental uCode */ if (drv->fw_index != UCODE_EXPERIMENTAL_INDEX) { if (api_ver < api_min || api_ver > api_max) { IWL_ERR(drv, "Driver unable to support your firmware API. " "Driver supports v%u, firmware is v%u.\n", api_max, api_ver); goto try_again; } if (api_ver < api_ok) { if (api_ok != api_max) IWL_ERR(drv, "Firmware has old API version, " "expected v%u through v%u, got v%u.\n", api_ok, api_max, api_ver); else IWL_ERR(drv, "Firmware has old API version, " "expected v%u, got v%u.\n", api_max, api_ver); IWL_ERR(drv, "New firmware can be obtained from " "http://www.intellinuxwireless.org/.\n"); } } IWL_INFO(drv, "loaded firmware version %s", drv->fw.fw_version); /* * In mvm uCode there is no difference between data and instructions * sections. */ if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, drv->cfg)) goto try_again; /* Allocate ucode buffers for card's bus-master loading ... */ /* Runtime instructions and 2 copies of data: * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) if (iwl_alloc_ucode(drv, &pieces, i)) goto out_free_fw; /* Now that we can no longer fail, copy information */ /* * The (size - 16) / 12 formula is based on the information recorded * for each event, which is of mode 1 (including timestamp) for all * new microcodes that include this information. */ fw->init_evtlog_ptr = pieces.init_evtlog_ptr; if (pieces.init_evtlog_size) fw->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; else fw->init_evtlog_size = drv->cfg->base_params->max_event_log_size; fw->init_errlog_ptr = pieces.init_errlog_ptr; fw->inst_evtlog_ptr = pieces.inst_evtlog_ptr; if (pieces.inst_evtlog_size) fw->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; else fw->inst_evtlog_size = drv->cfg->base_params->max_event_log_size; fw->inst_errlog_ptr = pieces.inst_errlog_ptr; /* * figure out the offset of chain noise reset and gain commands * base on the size of standard phy calibration commands table size */ if (fw->ucode_capa.standard_phy_calibration_size > IWL_MAX_PHY_CALIBRATE_TBL_SIZE) fw->ucode_capa.standard_phy_calibration_size = IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE; /* We have our copies now, allow OS release its copies */ release_firmware(ucode_raw); drv->op_mode = iwl_dvm_ops.start(drv->trans, drv->cfg, &drv->fw); if (!drv->op_mode) goto out_unbind; /* * Complete the firmware request last so that * a driver unbind (stop) doesn't run while we * are doing the start() above. */ complete(&drv->request_firmware_complete); return; try_again: /* try next, if any */ release_firmware(ucode_raw); if (iwl_request_firmware(drv, false)) goto out_unbind; return; out_free_fw: IWL_ERR(drv, "failed to allocate pci memory\n"); iwl_dealloc_ucode(drv); release_firmware(ucode_raw); out_unbind: complete(&drv->request_firmware_complete); device_release_driver(drv->trans->dev); }