--- zzzz-none-000/linux-3.10.107/drivers/net/wireless/iwlwifi/iwl-drv.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/net/wireless/iwlwifi/iwl-drv.c 2021-02-04 17:41:59.000000000 +0000 @@ -5,7 +5,8 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +31,8 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,6 +69,7 @@ #include #include "iwl-drv.h" +#include "iwl-csr.h" #include "iwl-debug.h" #include "iwl-trans.h" #include "iwl-op-mode.h" @@ -75,30 +78,14 @@ #include "iwl-config.h" #include "iwl-modparams.h" -/* private includes */ -#include "iwl-fw-file.h" - /****************************************************************************** * * module boiler plate * ******************************************************************************/ -/* - * module name, copyright, version, etc. - */ #define DRV_DESCRIPTION "Intel(R) Wireless WiFi driver for Linux" - -#ifdef CONFIG_IWLWIFI_DEBUG -#define VD "d" -#else -#define VD -#endif - -#define DRV_VERSION IWLWIFI_VERSION VD - MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); @@ -128,7 +115,7 @@ const struct iwl_cfg *cfg; int fw_index; /* firmware we're trying to load */ - char firmware_name[25]; /* name of firmware file to load */ + char firmware_name[32]; /* name of firmware file to load */ struct completion request_firmware_complete; @@ -155,8 +142,10 @@ [MVM_OP_MODE] = { .name = "iwlmvm", .ops = NULL }, }; +#define IWL_DEFAULT_SCAN_CHANNELS 40 + /* - * struct fw_sec: Just for the image parsing proccess. + * struct fw_sec: Just for the image parsing process. * For the fw storage we are using struct fw_desc. */ struct fw_sec { @@ -182,6 +171,13 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv) { int i; + + kfree(drv->fw.dbg_dest_tlv); + for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) + kfree(drv->fw.dbg_conf_tlv[i]); + for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++) + kfree(drv->fw.dbg_trigger_tlv[i]); + for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) iwl_free_fw_img(drv, drv->fw.img + i); } @@ -237,7 +233,19 @@ return -ENOENT; } - sprintf(drv->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); + snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode", + name_pre, tag); + + /* + * Starting 8000B - FW name format has changed. This overwrites the + * previous name and uses the new format. + */ + if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + char rev_step = 'A' + CSR_HW_REV_STEP(drv->trans->hw_rev); + + snprintf(drv->firmware_name, sizeof(drv->firmware_name), + "%s%c-%s.ucode", name_pre, rev_step, tag); + } IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n", (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) @@ -278,6 +286,13 @@ u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; + + /* FW debug data parsed for driver usage */ + struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; + struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX]; + size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX]; + struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX]; + size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX]; }; /* @@ -322,6 +337,65 @@ pieces->img[type].sec[sec].offset = offset; } +static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len) +{ + int i, j; + struct iwl_fw_cscheme_list *l = (struct iwl_fw_cscheme_list *)data; + struct iwl_fw_cipher_scheme *fwcs; + struct ieee80211_cipher_scheme *cs; + u32 cipher; + + if (len < sizeof(*l) || + len < sizeof(l->size) + l->size * sizeof(l->cs[0])) + return -EINVAL; + + for (i = 0, j = 0; i < IWL_UCODE_MAX_CS && i < l->size; i++) { + fwcs = &l->cs[j]; + cipher = le32_to_cpu(fwcs->cipher); + + /* we skip schemes with zero cipher suite selector */ + if (!cipher) + continue; + + cs = &fw->cs[j++]; + cs->cipher = cipher; + cs->iftype = BIT(NL80211_IFTYPE_STATION); + cs->hdr_len = fwcs->hdr_len; + cs->pn_len = fwcs->pn_len; + cs->pn_off = fwcs->pn_off; + cs->key_idx_off = fwcs->key_idx_off; + cs->key_idx_mask = fwcs->key_idx_mask; + cs->key_idx_shift = fwcs->key_idx_shift; + cs->mic_len = fwcs->mic_len; + } + + return 0; +} + +static int iwl_store_gscan_capa(struct iwl_fw *fw, const u8 *data, + const u32 len) +{ + struct iwl_fw_gscan_capabilities *fw_capa = (void *)data; + struct iwl_gscan_capabilities *capa = &fw->gscan_capa; + + if (len < sizeof(*fw_capa)) + return -EINVAL; + + capa->max_scan_cache_size = le32_to_cpu(fw_capa->max_scan_cache_size); + capa->max_scan_buckets = le32_to_cpu(fw_capa->max_scan_buckets); + capa->max_ap_cache_per_scan = + le32_to_cpu(fw_capa->max_ap_cache_per_scan); + capa->max_rssi_sample_size = le32_to_cpu(fw_capa->max_rssi_sample_size); + capa->max_scan_reporting_threshold = + le32_to_cpu(fw_capa->max_scan_reporting_threshold); + capa->max_hotlist_aps = le32_to_cpu(fw_capa->max_hotlist_aps); + capa->max_significant_change_aps = + le32_to_cpu(fw_capa->max_significant_change_aps); + capa->max_bssid_history_entries = + le32_to_cpu(fw_capa->max_bssid_history_entries); + return 0; +} + /* * Gets uCode section from tlv. */ @@ -368,6 +442,50 @@ return 0; } +static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data, + struct iwl_ucode_capabilities *capa) +{ + const struct iwl_ucode_api *ucode_api = (void *)data; + u32 api_index = le32_to_cpu(ucode_api->api_index); + u32 api_flags = le32_to_cpu(ucode_api->api_flags); + int i; + + if (api_index >= DIV_ROUND_UP(NUM_IWL_UCODE_TLV_API, 32)) { + IWL_ERR(drv, "api_index larger than supported by driver\n"); + /* don't return an error so we can load FW that has more bits */ + return 0; + } + + for (i = 0; i < 32; i++) { + if (api_flags & BIT(i)) + __set_bit(i + 32 * api_index, capa->_api); + } + + return 0; +} + +static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data, + struct iwl_ucode_capabilities *capa) +{ + const struct iwl_ucode_capa *ucode_capa = (void *)data; + u32 api_index = le32_to_cpu(ucode_capa->api_index); + u32 api_flags = le32_to_cpu(ucode_capa->api_capa); + int i; + + if (api_index >= DIV_ROUND_UP(NUM_IWL_UCODE_TLV_CAPA, 32)) { + IWL_ERR(drv, "api_index larger than supported by driver\n"); + /* don't return an error so we can load FW that has more bits */ + return 0; + } + + for (i = 0; i < 32; i++) { + if (api_flags & BIT(i)) + __set_bit(i + 32 * api_index, capa->_capa); + } + + return 0; +} + static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, const struct firmware *ucode_raw, struct iwl_firmware_pieces *pieces) @@ -479,10 +597,15 @@ size_t len = ucode_raw->size; const u8 *data; u32 tlv_len; + u32 usniffer_img; enum iwl_ucode_tlv_type tlv_type; const u8 *tlv_data; char buildstr[25]; - u32 build; + u32 build, paging_mem_size; + int num_of_cpus; + bool usniffer_images = false; + bool usniffer_req = false; + bool gscan_capa = false; if (len < sizeof(*ucode)) { IWL_ERR(drv, "uCode has invalid length: %zd\n", len); @@ -496,6 +619,8 @@ } drv->fw.ucode_ver = le32_to_cpu(ucode->ver); + memcpy(drv->fw.human_readable, ucode->human_readable, + sizeof(drv->fw.human_readable)); build = le32_to_cpu(ucode->build); if (build) @@ -601,6 +726,18 @@ */ capa->flags = le32_to_cpup((__le32 *)tlv_data); break; + case IWL_UCODE_TLV_API_CHANGES_SET: + if (tlv_len != sizeof(struct iwl_ucode_api)) + goto invalid_tlv_len; + if (iwl_set_ucode_api_flags(drv, tlv_data, capa)) + goto tlv_error; + break; + case IWL_UCODE_TLV_ENABLED_CAPABILITIES: + if (tlv_len != sizeof(struct iwl_ucode_capa)) + goto invalid_tlv_len; + if (iwl_set_ucode_capabilities(drv, tlv_data, capa)) + goto tlv_error; + break; case IWL_UCODE_TLV_INIT_EVTLOG_PTR: if (tlv_len != sizeof(u32)) goto invalid_tlv_len; @@ -691,6 +828,198 @@ if (tlv_len != sizeof(u32)) goto invalid_tlv_len; drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data); + drv->fw.valid_tx_ant = (drv->fw.phy_config & + FW_PHY_CFG_TX_CHAIN) >> + FW_PHY_CFG_TX_CHAIN_POS; + drv->fw.valid_rx_ant = (drv->fw.phy_config & + FW_PHY_CFG_RX_CHAIN) >> + FW_PHY_CFG_RX_CHAIN_POS; + break; + case IWL_UCODE_TLV_SECURE_SEC_RT: + iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR, + tlv_len); + drv->fw.mvm_fw = true; + break; + case IWL_UCODE_TLV_SECURE_SEC_INIT: + iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT, + tlv_len); + drv->fw.mvm_fw = true; + break; + case IWL_UCODE_TLV_SECURE_SEC_WOWLAN: + iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN, + tlv_len); + drv->fw.mvm_fw = true; + break; + case IWL_UCODE_TLV_NUM_OF_CPU: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + num_of_cpus = + le32_to_cpup((__le32 *)tlv_data); + + if (num_of_cpus == 2) { + drv->fw.img[IWL_UCODE_REGULAR].is_dual_cpus = + true; + drv->fw.img[IWL_UCODE_INIT].is_dual_cpus = + true; + drv->fw.img[IWL_UCODE_WOWLAN].is_dual_cpus = + true; + } else if ((num_of_cpus > 2) || (num_of_cpus < 1)) { + IWL_ERR(drv, "Driver support upto 2 CPUs\n"); + return -EINVAL; + } + break; + case IWL_UCODE_TLV_CSCHEME: + if (iwl_store_cscheme(&drv->fw, tlv_data, tlv_len)) + goto invalid_tlv_len; + break; + case IWL_UCODE_TLV_N_SCAN_CHANNELS: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + capa->n_scan_channels = + le32_to_cpup((__le32 *)tlv_data); + break; + case IWL_UCODE_TLV_FW_VERSION: { + __le32 *ptr = (void *)tlv_data; + u32 major, minor; + u8 local_comp; + + if (tlv_len != sizeof(u32) * 3) + goto invalid_tlv_len; + + major = le32_to_cpup(ptr++); + minor = le32_to_cpup(ptr++); + local_comp = le32_to_cpup(ptr); + + snprintf(drv->fw.fw_version, + sizeof(drv->fw.fw_version), "%u.%u.%u", + major, minor, local_comp); + break; + } + case IWL_UCODE_TLV_FW_DBG_DEST: { + struct iwl_fw_dbg_dest_tlv *dest = (void *)tlv_data; + + if (pieces->dbg_dest_tlv) { + IWL_ERR(drv, + "dbg destination ignored, already exists\n"); + break; + } + + pieces->dbg_dest_tlv = dest; + IWL_INFO(drv, "Found debug destination: %s\n", + get_fw_dbg_mode_string(dest->monitor_mode)); + + drv->fw.dbg_dest_reg_num = + tlv_len - offsetof(struct iwl_fw_dbg_dest_tlv, + reg_ops); + drv->fw.dbg_dest_reg_num /= + sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]); + + break; + } + case IWL_UCODE_TLV_FW_DBG_CONF: { + struct iwl_fw_dbg_conf_tlv *conf = (void *)tlv_data; + + if (!pieces->dbg_dest_tlv) { + IWL_ERR(drv, + "Ignore dbg config %d - no destination configured\n", + conf->id); + break; + } + + if (conf->id >= ARRAY_SIZE(drv->fw.dbg_conf_tlv)) { + IWL_ERR(drv, + "Skip unknown configuration: %d\n", + conf->id); + break; + } + + if (pieces->dbg_conf_tlv[conf->id]) { + IWL_ERR(drv, + "Ignore duplicate dbg config %d\n", + conf->id); + break; + } + + if (conf->usniffer) + usniffer_req = true; + + IWL_INFO(drv, "Found debug configuration: %d\n", + conf->id); + + pieces->dbg_conf_tlv[conf->id] = conf; + pieces->dbg_conf_tlv_len[conf->id] = tlv_len; + break; + } + case IWL_UCODE_TLV_FW_DBG_TRIGGER: { + struct iwl_fw_dbg_trigger_tlv *trigger = + (void *)tlv_data; + u32 trigger_id = le32_to_cpu(trigger->id); + + if (trigger_id >= ARRAY_SIZE(drv->fw.dbg_trigger_tlv)) { + IWL_ERR(drv, + "Skip unknown trigger: %u\n", + trigger->id); + break; + } + + if (pieces->dbg_trigger_tlv[trigger_id]) { + IWL_ERR(drv, + "Ignore duplicate dbg trigger %u\n", + trigger->id); + break; + } + + IWL_INFO(drv, "Found debug trigger: %u\n", trigger->id); + + pieces->dbg_trigger_tlv[trigger_id] = trigger; + pieces->dbg_trigger_tlv_len[trigger_id] = tlv_len; + break; + } + case IWL_UCODE_TLV_SEC_RT_USNIFFER: + usniffer_images = true; + iwl_store_ucode_sec(pieces, tlv_data, + IWL_UCODE_REGULAR_USNIFFER, + tlv_len); + break; + case IWL_UCODE_TLV_PAGING: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + paging_mem_size = le32_to_cpup((__le32 *)tlv_data); + + IWL_DEBUG_FW(drv, + "Paging: paging enabled (size = %u bytes)\n", + paging_mem_size); + + if (paging_mem_size > MAX_PAGING_IMAGE_SIZE) { + IWL_ERR(drv, + "Paging: driver supports up to %lu bytes for paging image\n", + MAX_PAGING_IMAGE_SIZE); + return -EINVAL; + } + + if (paging_mem_size & (FW_PAGING_SIZE - 1)) { + IWL_ERR(drv, + "Paging: image isn't multiple %lu\n", + FW_PAGING_SIZE); + return -EINVAL; + } + + drv->fw.img[IWL_UCODE_REGULAR].paging_mem_size = + paging_mem_size; + usniffer_img = IWL_UCODE_REGULAR_USNIFFER; + drv->fw.img[usniffer_img].paging_mem_size = + paging_mem_size; + break; + case IWL_UCODE_TLV_SDIO_ADMA_ADDR: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + drv->fw.sdio_adma_addr = + le32_to_cpup((__le32 *)tlv_data); + break; + case IWL_UCODE_TLV_FW_GSCAN_CAPA: + if (iwl_store_gscan_capa(&drv->fw, tlv_data, tlv_len)) + goto invalid_tlv_len; + gscan_capa = true; break; default: IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); @@ -698,12 +1027,28 @@ } } + if (usniffer_req && !usniffer_images) { + IWL_ERR(drv, + "user selected to work with usniffer but usniffer image isn't available in ucode package\n"); + return -EINVAL; + } + if (len) { IWL_ERR(drv, "invalid TLV after parsing: %zd\n", len); iwl_print_hex_dump(drv, IWL_DL_FW, (u8 *)data, len); return -EINVAL; } + /* + * If ucode advertises that it supports GSCAN but GSCAN + * capabilities TLV is not present, warn and continue without GSCAN. + */ + if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT) && + WARN(!gscan_capa, + "GSCAN is supported but capabilities TLV is unavailable\n")) + __clear_bit((__force long)IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT, + capa->_capa); + return 0; invalid_tlv_len: @@ -745,34 +1090,34 @@ /* Verify that uCode images will fit in card's SRAM. */ if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) > - cfg->max_inst_size) { + 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)); + IWL_UCODE_SECTION_INST)); return -1; } if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) > - cfg->max_data_size) { + 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)); + IWL_UCODE_SECTION_DATA)); return -1; } - if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) > - cfg->max_inst_size) { + if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) > + cfg->max_inst_size) { IWL_ERR(drv, "uCode init instr len %Zd too large to fit in\n", get_sec_size(pieces, IWL_UCODE_INIT, - IWL_UCODE_SECTION_INST)); + IWL_UCODE_SECTION_INST)); return -1; } if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA) > - cfg->max_data_size) { + cfg->max_data_size) { IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n", get_sec_size(pieces, IWL_UCODE_REGULAR, - IWL_UCODE_SECTION_DATA)); + IWL_UCODE_SECTION_DATA)); return -1; } return 0; @@ -835,22 +1180,26 @@ struct iwl_ucode_header *ucode; struct iwlwifi_opmode_table *op; int err; - struct iwl_firmware_pieces pieces; + 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; + size_t trigger_tlv_sz[FW_DBG_TRIGGER_MAX]; u32 api_ver; int i; bool load_module = false; - fw->ucode_capa.max_probe_length = 200; + fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH; fw->ucode_capa.standard_phy_calibration_size = IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; + fw->ucode_capa.n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS; if (!api_ok) api_ok = api_max; - memset(&pieces, 0, sizeof(pieces)); + pieces = kzalloc(sizeof(*pieces), GFP_KERNEL); + if (!pieces) + return; if (!ucode_raw) { if (drv->fw_index <= api_ok) @@ -873,15 +1222,18 @@ ucode = (struct iwl_ucode_header *)ucode_raw->data; if (ucode->ver) - err = iwl_parse_v1_v2_firmware(drv, ucode_raw, &pieces); + err = iwl_parse_v1_v2_firmware(drv, ucode_raw, pieces); else - err = iwl_parse_tlv_firmware(drv, ucode_raw, &pieces, - &fw->ucode_capa); + 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 (fw_has_api(&drv->fw.ucode_capa, IWL_UCODE_TLV_API_NEW_VERSION)) + api_ver = drv->fw.ucode_ver; + else + api_ver = IWL_UCODE_API(drv->fw.ucode_ver); /* * api_ver should match the api version forming part of the @@ -916,7 +1268,7 @@ * In mvm uCode there is no difference between data and instructions * sections. */ - if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, drv->cfg)) + if (!fw->mvm_fw && validate_sec_sizes(drv, pieces, drv->cfg)) goto try_again; /* Allocate ucode buffers for card's bus-master loading ... */ @@ -925,8 +1277,76 @@ * 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)) + if (iwl_alloc_ucode(drv, pieces, i)) + goto out_free_fw; + + if (pieces->dbg_dest_tlv) { + drv->fw.dbg_dest_tlv = + kmemdup(pieces->dbg_dest_tlv, + sizeof(*pieces->dbg_dest_tlv) + + sizeof(pieces->dbg_dest_tlv->reg_ops[0]) * + drv->fw.dbg_dest_reg_num, GFP_KERNEL); + + if (!drv->fw.dbg_dest_tlv) goto out_free_fw; + } + + for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) { + if (pieces->dbg_conf_tlv[i]) { + drv->fw.dbg_conf_tlv_len[i] = + pieces->dbg_conf_tlv_len[i]; + drv->fw.dbg_conf_tlv[i] = + kmemdup(pieces->dbg_conf_tlv[i], + drv->fw.dbg_conf_tlv_len[i], + GFP_KERNEL); + if (!drv->fw.dbg_conf_tlv[i]) + goto out_free_fw; + } + } + + memset(&trigger_tlv_sz, 0xff, sizeof(trigger_tlv_sz)); + + trigger_tlv_sz[FW_DBG_TRIGGER_MISSED_BEACONS] = + sizeof(struct iwl_fw_dbg_trigger_missed_bcon); + trigger_tlv_sz[FW_DBG_TRIGGER_CHANNEL_SWITCH] = 0; + trigger_tlv_sz[FW_DBG_TRIGGER_FW_NOTIF] = + sizeof(struct iwl_fw_dbg_trigger_cmd); + trigger_tlv_sz[FW_DBG_TRIGGER_MLME] = + sizeof(struct iwl_fw_dbg_trigger_mlme); + trigger_tlv_sz[FW_DBG_TRIGGER_STATS] = + sizeof(struct iwl_fw_dbg_trigger_stats); + trigger_tlv_sz[FW_DBG_TRIGGER_RSSI] = + sizeof(struct iwl_fw_dbg_trigger_low_rssi); + trigger_tlv_sz[FW_DBG_TRIGGER_TXQ_TIMERS] = + sizeof(struct iwl_fw_dbg_trigger_txq_timer); + trigger_tlv_sz[FW_DBG_TRIGGER_TIME_EVENT] = + sizeof(struct iwl_fw_dbg_trigger_time_event); + trigger_tlv_sz[FW_DBG_TRIGGER_BA] = + sizeof(struct iwl_fw_dbg_trigger_ba); + + for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++) { + if (pieces->dbg_trigger_tlv[i]) { + /* + * If the trigger isn't long enough, WARN and exit. + * Someone is trying to debug something and he won't + * be able to catch the bug he is trying to chase. + * We'd better be noisy to be sure he knows what's + * going on. + */ + if (WARN_ON(pieces->dbg_trigger_tlv_len[i] < + (trigger_tlv_sz[i] + + sizeof(struct iwl_fw_dbg_trigger_tlv)))) + goto out_free_fw; + drv->fw.dbg_trigger_tlv_len[i] = + pieces->dbg_trigger_tlv_len[i]; + drv->fw.dbg_trigger_tlv[i] = + kmemdup(pieces->dbg_trigger_tlv[i], + drv->fw.dbg_trigger_tlv_len[i], + GFP_KERNEL); + if (!drv->fw.dbg_trigger_tlv[i]) + goto out_free_fw; + } + } /* Now that we can no longer fail, copy information */ @@ -935,20 +1355,20 @@ * 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; + 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; + 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; + fw->inst_errlog_ptr = pieces->inst_errlog_ptr; /* * figure out the offset of chain noise reset and gain commands @@ -1007,6 +1427,7 @@ op->name, err); #endif } + kfree(pieces); return; try_again: @@ -1014,6 +1435,7 @@ release_firmware(ucode_raw); if (iwl_request_firmware(drv, false)) goto out_unbind; + kfree(pieces); return; out_free_fw: @@ -1021,6 +1443,7 @@ iwl_dealloc_ucode(drv); release_firmware(ucode_raw); out_unbind: + kfree(pieces); complete(&drv->request_firmware_complete); device_release_driver(drv->trans->dev); } @@ -1032,8 +1455,10 @@ int ret; drv = kzalloc(sizeof(*drv), GFP_KERNEL); - if (!drv) - return NULL; + if (!drv) { + ret = -ENOMEM; + goto err; + } drv->trans = trans; drv->dev = trans->dev; @@ -1078,7 +1503,7 @@ err_free_drv: #endif kfree(drv); - +err: return ERR_PTR(ret); } @@ -1111,12 +1536,12 @@ /* shared module parameters */ struct iwl_mod_params iwlwifi_mod_params = { .restart_fw = true, - .plcp_check = true, .bt_coex_active = true, .power_level = IWL_POWER_INDEX_1, - .bt_ch_announce = true, - .auto_agg = true, - .wd_disable = true, + .d0i3_disable = true, +#ifndef CONFIG_IWLWIFI_UAPSD + .uapsd_disable = true, +#endif /* CONFIG_IWLWIFI_UAPSD */ /* the rest are 0 by default */ }; IWL_EXPORT_SYMBOL(iwlwifi_mod_params); @@ -1176,7 +1601,7 @@ for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv); - pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); + pr_info(DRV_DESCRIPTION "\n"); pr_info(DRV_COPYRIGHT "\n"); #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1221,20 +1646,26 @@ module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, int, S_IRUGO); MODULE_PARM_DESC(antenna_coupling, - "specify antenna coupling in dB (defualt: 0 dB)"); + "specify antenna coupling in dB (default: 0 dB)"); + +module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); +MODULE_PARM_DESC(nvm_file, "NVM file name"); -module_param_named(bt_ch_inhibition, iwlwifi_mod_params.bt_ch_announce, +module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable, bool, S_IRUGO); -MODULE_PARM_DESC(bt_ch_inhibition, - "Enable BT channel inhibition (default: enable)"); +MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)"); -module_param_named(plcp_check, iwlwifi_mod_params.plcp_check, bool, S_IRUGO); -MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); +module_param_named(lar_disable, iwlwifi_mod_params.lar_disable, + bool, S_IRUGO); +MODULE_PARM_DESC(lar_disable, "disable LAR functionality (default: N)"); -module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); -MODULE_PARM_DESC(wd_disable, - "Disable stuck queue watchdog timer 0=system default, " - "1=disable, 2=enable (default: 0)"); +module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, + bool, S_IRUGO | S_IWUSR); +#ifdef CONFIG_IWLWIFI_UAPSD +MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)"); +#else +MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: Y)"); +#endif /* * set bt_coex_active to true, uCode will do kill/defer @@ -1270,7 +1701,6 @@ MODULE_PARM_DESC(power_level, "default power save level (range from 1 - 5, default: 1)"); -module_param_named(auto_agg, iwlwifi_mod_params.auto_agg, - bool, S_IRUGO); -MODULE_PARM_DESC(auto_agg, - "enable agg w/o check traffic load (default: enable)"); +module_param_named(fw_monitor, iwlwifi_mod_params.fw_monitor, bool, S_IRUGO); +MODULE_PARM_DESC(fw_monitor, + "firmware monitor - to debug FW (default: false - needs lots of memory)");