summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/iwlwifi/iwl-agn.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c556
1 files changed, 381 insertions, 175 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index cc15e929a987..aef4f71f1981 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -157,7 +157,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret);
return ret;
}
- iwl_clear_ucode_stations(priv, false);
+ iwl_clear_ucode_stations(priv);
iwl_restore_stations(priv);
ret = iwl_restore_default_wep_keys(priv);
if (ret) {
@@ -189,7 +189,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
}
IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n");
memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
- iwl_clear_ucode_stations(priv, false);
+ iwl_clear_ucode_stations(priv);
iwl_restore_stations(priv);
ret = iwl_restore_default_wep_keys(priv);
if (ret) {
@@ -1506,9 +1506,13 @@ static void iwl_nic_start(struct iwl_priv *priv)
iwl_write32(priv, CSR_RESET, 0);
}
+struct iwlagn_ucode_capabilities {
+ u32 max_probe_length;
+};
static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
-static int iwl_mac_setup_register(struct iwl_priv *priv);
+static int iwl_mac_setup_register(struct iwl_priv *priv,
+ struct iwlagn_ucode_capabilities *capa);
static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
{
@@ -1535,6 +1539,199 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
iwl_ucode_callback);
}
+struct iwlagn_firmware_pieces {
+ const void *inst, *data, *init, *init_data, *boot;
+ size_t inst_size, data_size, init_size, init_data_size, boot_size;
+
+ u32 build;
+};
+
+static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
+ const struct firmware *ucode_raw,
+ struct iwlagn_firmware_pieces *pieces)
+{
+ struct iwl_ucode_header *ucode = (void *)ucode_raw->data;
+ u32 api_ver, hdr_size;
+ const u8 *src;
+
+ priv->ucode_ver = le32_to_cpu(ucode->ver);
+ api_ver = IWL_UCODE_API(priv->ucode_ver);
+
+ switch (api_ver) {
+ default:
+ /*
+ * 4965 doesn't revision the firmware file format
+ * along with the API version, it always uses v1
+ * file format.
+ */
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) !=
+ CSR_HW_REV_TYPE_4965) {
+ hdr_size = 28;
+ if (ucode_raw->size < hdr_size) {
+ IWL_ERR(priv, "File size too small!\n");
+ return -EINVAL;
+ }
+ pieces->build = le32_to_cpu(ucode->u.v2.build);
+ pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
+ pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
+ pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
+ pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size);
+ pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size);
+ src = ucode->u.v2.data;
+ break;
+ }
+ /* fall through for 4965 */
+ case 0:
+ case 1:
+ case 2:
+ hdr_size = 24;
+ if (ucode_raw->size < hdr_size) {
+ IWL_ERR(priv, "File size too small!\n");
+ return -EINVAL;
+ }
+ pieces->build = 0;
+ pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size);
+ pieces->data_size = le32_to_cpu(ucode->u.v1.data_size);
+ pieces->init_size = le32_to_cpu(ucode->u.v1.init_size);
+ pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size);
+ pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size);
+ src = ucode->u.v1.data;
+ break;
+ }
+
+ /* Verify size of file vs. image size info in file's header */
+ if (ucode_raw->size != hdr_size + pieces->inst_size +
+ pieces->data_size + pieces->init_size +
+ pieces->init_data_size + pieces->boot_size) {
+
+ IWL_ERR(priv,
+ "uCode file size %d does not match expected size\n",
+ (int)ucode_raw->size);
+ return -EINVAL;
+ }
+
+ pieces->inst = src;
+ src += pieces->inst_size;
+ pieces->data = src;
+ src += pieces->data_size;
+ pieces->init = src;
+ src += pieces->init_size;
+ pieces->init_data = src;
+ src += pieces->init_data_size;
+ pieces->boot = src;
+ src += pieces->boot_size;
+
+ return 0;
+}
+
+static int iwlagn_wanted_ucode_alternative = 1;
+
+static int iwlagn_load_firmware(struct iwl_priv *priv,
+ const struct firmware *ucode_raw,
+ struct iwlagn_firmware_pieces *pieces,
+ struct iwlagn_ucode_capabilities *capa)
+{
+ struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data;
+ struct iwl_ucode_tlv *tlv;
+ size_t len = ucode_raw->size;
+ const u8 *data;
+ int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp;
+ u64 alternatives;
+
+ if (len < sizeof(*ucode))
+ return -EINVAL;
+
+ if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC))
+ return -EINVAL;
+
+ /*
+ * Check which alternatives are present, and "downgrade"
+ * when the chosen alternative is not present, warning
+ * the user when that happens. Some files may not have
+ * any alternatives, so don't warn in that case.
+ */
+ alternatives = le64_to_cpu(ucode->alternatives);
+ tmp = wanted_alternative;
+ if (wanted_alternative > 63)
+ wanted_alternative = 63;
+ while (wanted_alternative && !(alternatives & BIT(wanted_alternative)))
+ wanted_alternative--;
+ if (wanted_alternative && wanted_alternative != tmp)
+ IWL_WARN(priv,
+ "uCode alternative %d not available, choosing %d\n",
+ tmp, wanted_alternative);
+
+ priv->ucode_ver = le32_to_cpu(ucode->ver);
+ pieces->build = le32_to_cpu(ucode->build);
+ data = ucode->data;
+
+ len -= sizeof(*ucode);
+
+ while (len >= sizeof(*tlv)) {
+ u32 tlv_len;
+ enum iwl_ucode_tlv_type tlv_type;
+ u16 tlv_alt;
+ const u8 *tlv_data;
+
+ len -= sizeof(*tlv);
+ tlv = (void *)data;
+
+ tlv_len = le32_to_cpu(tlv->length);
+ tlv_type = le16_to_cpu(tlv->type);
+ tlv_alt = le16_to_cpu(tlv->alternative);
+ tlv_data = tlv->data;
+
+ if (len < tlv_len)
+ return -EINVAL;
+ len -= ALIGN(tlv_len, 4);
+ data += sizeof(*tlv) + ALIGN(tlv_len, 4);
+
+ /*
+ * Alternative 0 is always valid.
+ *
+ * Skip alternative TLVs that are not selected.
+ */
+ if (tlv_alt != 0 && tlv_alt != wanted_alternative)
+ continue;
+
+ switch (tlv_type) {
+ case IWL_UCODE_TLV_INST:
+ pieces->inst = tlv_data;
+ pieces->inst_size = tlv_len;
+ break;
+ case IWL_UCODE_TLV_DATA:
+ pieces->data = tlv_data;
+ pieces->data_size = tlv_len;
+ break;
+ case IWL_UCODE_TLV_INIT:
+ pieces->init = tlv_data;
+ pieces->init_size = tlv_len;
+ break;
+ case IWL_UCODE_TLV_INIT_DATA:
+ pieces->init_data = tlv_data;
+ pieces->init_data_size = tlv_len;
+ break;
+ case IWL_UCODE_TLV_BOOT:
+ pieces->boot = tlv_data;
+ pieces->boot_size = tlv_len;
+ break;
+ case IWL_UCODE_TLV_PROBE_MAX_LEN:
+ if (tlv_len != 4)
+ return -EINVAL;
+ capa->max_probe_length =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (len)
+ return -EINVAL;
+
+ return 0;
+}
+
/**
* iwl_ucode_callback - callback when firmware was loaded
*
@@ -1545,14 +1742,18 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
{
struct iwl_priv *priv = context;
struct iwl_ucode_header *ucode;
+ int err;
+ struct iwlagn_firmware_pieces pieces;
const unsigned int api_max = priv->cfg->ucode_api_max;
const unsigned int api_min = priv->cfg->ucode_api_min;
- u8 *src;
- size_t len;
- u32 api_ver, build;
- u32 inst_size, data_size, init_size, init_data_size, boot_size;
- int err;
- u16 eeprom_ver;
+ u32 api_ver;
+ char buildstr[25];
+ u32 build;
+ struct iwlagn_ucode_capabilities ucode_capa = {
+ .max_probe_length = 200,
+ };
+
+ memset(&pieces, 0, sizeof(pieces));
if (!ucode_raw) {
IWL_ERR(priv, "request for firmware file '%s' failed.\n",
@@ -1563,8 +1764,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n",
priv->firmware_name, ucode_raw->size);
- /* Make sure that we got at least the v1 header! */
- if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
+ /* Make sure that we got at least the API version number */
+ if (ucode_raw->size < 4) {
IWL_ERR(priv, "File size way too small!\n");
goto try_again;
}
@@ -1572,21 +1773,23 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
/* Data from ucode file: header followed by uCode images */
ucode = (struct iwl_ucode_header *)ucode_raw->data;
- priv->ucode_ver = le32_to_cpu(ucode->ver);
+ if (ucode->ver)
+ err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces);
+ else
+ err = iwlagn_load_firmware(priv, ucode_raw, &pieces,
+ &ucode_capa);
+
+ if (err)
+ goto try_again;
+
api_ver = IWL_UCODE_API(priv->ucode_ver);
- build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
- inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
- data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
- init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
- init_data_size =
- priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
- boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
- src = priv->cfg->ops->ucode->get_data(ucode, api_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 */
+ build = pieces.build;
+ /*
+ * 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
+ */
if (api_ver < api_min || api_ver > api_max) {
IWL_ERR(priv, "Driver unable to support your firmware API. "
"Driver supports v%u, firmware is v%u.\n",
@@ -1600,40 +1803,26 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
"from http://www.intellinuxwireless.org.\n",
api_max, api_ver);
- IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u\n",
- IWL_UCODE_MAJOR(priv->ucode_ver),
- IWL_UCODE_MINOR(priv->ucode_ver),
- IWL_UCODE_API(priv->ucode_ver),
- IWL_UCODE_SERIAL(priv->ucode_ver));
+ if (build)
+ sprintf(buildstr, " build %u", build);
+ else
+ buildstr[0] = '\0';
+
+ IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u%s\n",
+ IWL_UCODE_MAJOR(priv->ucode_ver),
+ IWL_UCODE_MINOR(priv->ucode_ver),
+ IWL_UCODE_API(priv->ucode_ver),
+ IWL_UCODE_SERIAL(priv->ucode_ver),
+ buildstr);
snprintf(priv->hw->wiphy->fw_version,
sizeof(priv->hw->wiphy->fw_version),
- "%u.%u.%u.%u",
+ "%u.%u.%u.%u%s",
IWL_UCODE_MAJOR(priv->ucode_ver),
IWL_UCODE_MINOR(priv->ucode_ver),
IWL_UCODE_API(priv->ucode_ver),
- IWL_UCODE_SERIAL(priv->ucode_ver));
-
- if (build)
- IWL_DEBUG_INFO(priv, "Build %u\n", build);
-
- eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
- IWL_DEBUG_INFO(priv, "NVM Type: %s, version: 0x%x\n",
- (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
- ? "OTP" : "EEPROM", eeprom_ver);
-
- IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
- priv->ucode_ver);
- IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
- inst_size);
- IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %u\n",
- data_size);
- IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %u\n",
- init_size);
- IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %u\n",
- init_data_size);
- IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %u\n",
- boot_size);
+ IWL_UCODE_SERIAL(priv->ucode_ver),
+ buildstr);
/*
* For any of the failures below (before allocating pci memory)
@@ -1641,43 +1830,47 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
* user just got a corrupted version of the latest API.
*/
- /* Verify size of file vs. image size info in file's header */
- if (ucode_raw->size !=
- priv->cfg->ops->ucode->get_header_size(api_ver) +
- inst_size + data_size + init_size +
- init_data_size + boot_size) {
-
- IWL_DEBUG_INFO(priv,
- "uCode file size %d does not match expected size\n",
- (int)ucode_raw->size);
- goto try_again;
- }
+ IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
+ priv->ucode_ver);
+ IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %Zd\n",
+ pieces.inst_size);
+ IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %Zd\n",
+ pieces.data_size);
+ IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %Zd\n",
+ pieces.init_size);
+ IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n",
+ pieces.init_data_size);
+ IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n",
+ pieces.boot_size);
/* Verify that uCode images will fit in card's SRAM */
- if (inst_size > priv->hw_params.max_inst_size) {
- IWL_DEBUG_INFO(priv, "uCode instr len %d too large to fit in\n",
- inst_size);
+ if (pieces.inst_size > priv->hw_params.max_inst_size) {
+ IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n",
+ pieces.inst_size);
goto try_again;
}
- if (data_size > priv->hw_params.max_data_size) {
- IWL_DEBUG_INFO(priv, "uCode data len %d too large to fit in\n",
- data_size);
+ if (pieces.data_size > priv->hw_params.max_data_size) {
+ IWL_ERR(priv, "uCode data len %Zd too large to fit in\n",
+ pieces.data_size);
goto try_again;
}
- if (init_size > priv->hw_params.max_inst_size) {
- IWL_INFO(priv, "uCode init instr len %d too large to fit in\n",
- init_size);
+
+ if (pieces.init_size > priv->hw_params.max_inst_size) {
+ IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n",
+ pieces.init_size);
goto try_again;
}
- if (init_data_size > priv->hw_params.max_data_size) {
- IWL_INFO(priv, "uCode init data len %d too large to fit in\n",
- init_data_size);
+
+ if (pieces.init_data_size > priv->hw_params.max_data_size) {
+ IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n",
+ pieces.init_data_size);
goto try_again;
}
- if (boot_size > priv->hw_params.max_bsm_size) {
- IWL_INFO(priv, "uCode boot instr len %d too large to fit in\n",
- boot_size);
+
+ if (pieces.boot_size > priv->hw_params.max_bsm_size) {
+ IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n",
+ pieces.boot_size);
goto try_again;
}
@@ -1686,13 +1879,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
/* Runtime instructions and 2 copies of data:
* 1) unmodified from disk
* 2) backup cache for save/restore during power-downs */
- priv->ucode_code.len = inst_size;
+ priv->ucode_code.len = pieces.inst_size;
iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
- priv->ucode_data.len = data_size;
+ priv->ucode_data.len = pieces.data_size;
iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
- priv->ucode_data_backup.len = data_size;
+ priv->ucode_data_backup.len = pieces.data_size;
iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
@@ -1700,11 +1893,11 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
goto err_pci_alloc;
/* Initialization instructions and data */
- if (init_size && init_data_size) {
- priv->ucode_init.len = init_size;
+ if (pieces.init_size && pieces.init_data_size) {
+ priv->ucode_init.len = pieces.init_size;
iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
- priv->ucode_init_data.len = init_data_size;
+ priv->ucode_init_data.len = pieces.init_data_size;
iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
@@ -1712,8 +1905,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
}
/* Bootstrap (instructions only, no data) */
- if (boot_size) {
- priv->ucode_boot.len = boot_size;
+ if (pieces.boot_size) {
+ priv->ucode_boot.len = pieces.boot_size;
iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
if (!priv->ucode_boot.v_addr)
@@ -1723,51 +1916,48 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
- len = inst_size;
- IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
- memcpy(priv->ucode_code.v_addr, src, len);
- src += len;
+ IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n",
+ pieces.inst_size);
+ memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size);
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
- /* Runtime data (2nd block)
- * NOTE: Copy into backup buffer will be done in iwl_up() */
- len = data_size;
- IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
- memcpy(priv->ucode_data.v_addr, src, len);
- memcpy(priv->ucode_data_backup.v_addr, src, len);
- src += len;
-
- /* Initialization instructions (3rd block) */
- if (init_size) {
- len = init_size;
+ /*
+ * Runtime data
+ * NOTE: Copy into backup buffer will be done in iwl_up()
+ */
+ IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n",
+ pieces.data_size);
+ memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size);
+ memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size);
+
+ /* Initialization instructions */
+ if (pieces.init_size) {
IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
- len);
- memcpy(priv->ucode_init.v_addr, src, len);
- src += len;
+ pieces.init_size);
+ memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size);
}
- /* Initialization data (4th block) */
- if (init_data_size) {
- len = init_data_size;
+ /* Initialization data */
+ if (pieces.init_data_size) {
IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
- len);
- memcpy(priv->ucode_init_data.v_addr, src, len);
- src += len;
+ pieces.init_data_size);
+ memcpy(priv->ucode_init_data.v_addr, pieces.init_data,
+ pieces.init_data_size);
}
- /* Bootstrap instructions (5th block) */
- len = boot_size;
- IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
- memcpy(priv->ucode_boot.v_addr, src, len);
+ /* Bootstrap instructions */
+ IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n",
+ pieces.boot_size);
+ memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size);
/**************************************************
* This is still part of probe() in a sense...
*
* 9. Setup and register with mac80211 and debugfs
**************************************************/
- err = iwl_mac_setup_register(priv);
+ err = iwl_mac_setup_register(priv, &ucode_capa);
if (err)
goto out_unbind;
@@ -1777,6 +1967,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
/* We have our copies now, allow OS release its copies */
release_firmware(ucode_raw);
+ complete(&priv->_agn.firmware_loading_complete);
return;
try_again:
@@ -1790,6 +1981,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
IWL_ERR(priv, "failed to allocate pci memory\n");
iwl_dealloc_ucode_pci(priv);
out_unbind:
+ complete(&priv->_agn.firmware_loading_complete);
device_release_driver(&priv->pci_dev->dev);
release_firmware(ucode_raw);
}
@@ -2165,7 +2357,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
} else {
/* Initialize our rx_config data */
- iwl_connection_init_rx_config(priv, priv->iw_mode);
+ iwl_connection_init_rx_config(priv, NULL);
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
@@ -2212,7 +2404,9 @@ static void __iwl_down(struct iwl_priv *priv)
if (!exit_pending)
set_bit(STATUS_EXIT_PENDING, &priv->status);
- iwl_clear_ucode_stations(priv, true);
+ iwl_clear_ucode_stations(priv);
+ iwl_dealloc_bcast_station(priv);
+ iwl_clear_driver_stations(priv);
/* Unblock any waiting calls */
wake_up_interruptible_all(&priv->wait_command_queue);
@@ -2359,6 +2553,10 @@ static int __iwl_up(struct iwl_priv *priv)
return -EIO;
}
+ ret = iwl_alloc_bcast_station(priv, true);
+ if (ret)
+ return ret;
+
iwl_prepare_card_hw(priv);
if (!priv->hw_ready) {
@@ -2537,12 +2735,15 @@ static void iwl_bg_rx_replenish(struct work_struct *data)
#define IWL_DELAY_NEXT_SCAN (HZ*2)
-void iwl_post_associate(struct iwl_priv *priv)
+void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
struct ieee80211_conf *conf = NULL;
int ret = 0;
- if (priv->iw_mode == NL80211_IFTYPE_AP) {
+ if (!vif || !priv->is_open)
+ return;
+
+ if (vif->type == NL80211_IFTYPE_AP) {
IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
return;
}
@@ -2550,10 +2751,6 @@ void iwl_post_associate(struct iwl_priv *priv)
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
-
- if (!priv->vif || !priv->is_open)
- return;
-
iwl_scan_cancel_timeout(priv, 200);
conf = ieee80211_get_hw_conf(priv->hw);
@@ -2561,7 +2758,7 @@ void iwl_post_associate(struct iwl_priv *priv)
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
iwlcore_commit_rxon(priv);
- iwl_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv, vif);
ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing), &priv->rxon_timing);
if (ret)
@@ -2575,49 +2772,41 @@ void iwl_post_associate(struct iwl_priv *priv)
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
- priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+ priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
- priv->assoc_id, priv->beacon_int);
+ vif->bss_conf.aid, vif->bss_conf.beacon_int);
- if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
- if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif->bss_conf.assoc_capability &
+ WLAN_CAPABILITY_SHORT_SLOT_TIME)
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
- if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+ if (vif->type == NL80211_IFTYPE_ADHOC)
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
}
iwlcore_commit_rxon(priv);
IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
- priv->assoc_id, priv->active_rxon.bssid_addr);
+ vif->bss_conf.aid, priv->active_rxon.bssid_addr);
- switch (priv->iw_mode) {
+ switch (vif->type) {
case NL80211_IFTYPE_STATION:
break;
-
case NL80211_IFTYPE_ADHOC:
-
- /* assume default assoc id */
- priv->assoc_id = 1;
-
- iwl_add_local_station(priv, priv->bssid, true);
iwl_send_beacon_cmd(priv);
-
break;
-
default:
IWL_ERR(priv, "%s Should not be called in %d mode\n",
- __func__, priv->iw_mode);
+ __func__, vif->type);
break;
}
@@ -2645,7 +2834,8 @@ void iwl_post_associate(struct iwl_priv *priv)
* Not a mac80211 entry point function, but it fits in with all the
* other mac80211 functions grouped here.
*/
-static int iwl_mac_setup_register(struct iwl_priv *priv)
+static int iwl_mac_setup_register(struct iwl_priv *priv,
+ struct iwlagn_ucode_capabilities *capa)
{
int ret;
struct ieee80211_hw *hw = priv->hw;
@@ -2665,6 +2855,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv)
IEEE80211_HW_SUPPORTS_STATIC_SMPS;
hw->sta_data_size = sizeof(struct iwl_station_priv);
+ hw->vif_data_size = sizeof(struct iwl_vif_priv);
+
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
@@ -2680,7 +2872,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv)
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
/* we create the 802.11 header and a zero-length SSID element */
- hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
+ hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
@@ -2793,7 +2985,7 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
-void iwl_config_ap(struct iwl_priv *priv)
+void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
int ret = 0;
@@ -2808,7 +3000,7 @@ void iwl_config_ap(struct iwl_priv *priv)
iwlcore_commit_rxon(priv);
/* RXON Timing */
- iwl_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv, vif);
ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing), &priv->rxon_timing);
if (ret)
@@ -2822,9 +3014,10 @@ void iwl_config_ap(struct iwl_priv *priv)
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
- /* FIXME: what should be the assoc_id for AP? */
- priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
- if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ priv->staging_rxon.assoc_id = 0;
+
+ if (vif->bss_conf.assoc_capability &
+ WLAN_CAPABILITY_SHORT_PREAMBLE)
priv->staging_rxon.flags |=
RXON_FLG_SHORT_PREAMBLE_MSK;
else
@@ -2832,22 +3025,21 @@ void iwl_config_ap(struct iwl_priv *priv)
~RXON_FLG_SHORT_PREAMBLE_MSK;
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
- if (priv->assoc_capability &
- WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif->bss_conf.assoc_capability &
+ WLAN_CAPABILITY_SHORT_SLOT_TIME)
priv->staging_rxon.flags |=
RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
- if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+ if (vif->type == NL80211_IFTYPE_ADHOC)
priv->staging_rxon.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
}
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
iwlcore_commit_rxon(priv);
- iwl_add_bcast_station(priv);
}
iwl_send_beacon_cmd(priv);
@@ -2866,8 +3058,7 @@ static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
struct iwl_priv *priv = hw->priv;
IWL_DEBUG_MAC80211(priv, "enter\n");
- iwl_update_tkip_key(priv, keyconf,
- sta ? sta->addr : iwl_bcast_addr,
+ iwl_update_tkip_key(priv, keyconf, sta,
iv32, phase1key);
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2879,7 +3070,6 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_key_conf *key)
{
struct iwl_priv *priv = hw->priv;
- const u8 *addr;
int ret;
u8 sta_id;
bool is_default_wep_key = false;
@@ -2890,13 +3080,17 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
return -EOPNOTSUPP;
}
- addr = sta ? sta->addr : iwl_bcast_addr;
- sta_id = iwl_find_station(priv, addr);
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
- addr);
- return -EINVAL;
+ if (sta) {
+ sta_id = iwl_sta_id(sta);
+
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
+ sta->addr);
+ return -EINVAL;
+ }
+ } else {
+ sta_id = priv->hw_params.bcast_sta_id;
}
mutex_lock(&priv->mutex);
@@ -2945,8 +3139,8 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- enum ieee80211_ampdu_mlme_action action,
- struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
struct iwl_priv *priv = hw->priv;
int ret;
@@ -2960,17 +3154,17 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
switch (action) {
case IEEE80211_AMPDU_RX_START:
IWL_DEBUG_HT(priv, "start Rx\n");
- return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn);
+ return iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
case IEEE80211_AMPDU_RX_STOP:
IWL_DEBUG_HT(priv, "stop Rx\n");
- ret = iwl_sta_rx_agg_stop(priv, sta->addr, tid);
+ ret = iwl_sta_rx_agg_stop(priv, sta, tid);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return 0;
else
return ret;
case IEEE80211_AMPDU_TX_START:
IWL_DEBUG_HT(priv, "start Tx\n");
- ret = iwlagn_tx_agg_start(priv, sta->addr, tid, ssn);
+ ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
if (ret == 0) {
priv->_agn.agg_tids_count++;
IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
@@ -2979,7 +3173,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
return ret;
case IEEE80211_AMPDU_TX_STOP:
IWL_DEBUG_HT(priv, "stop Tx\n");
- ret = iwlagn_tx_agg_stop(priv, sta->addr, tid);
+ ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
if ((ret == 0) && (priv->_agn.agg_tids_count > 0)) {
priv->_agn.agg_tids_count--;
IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
@@ -3021,7 +3215,7 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
if (!sta_priv->asleep)
break;
sta_priv->asleep = false;
- sta_id = iwl_find_station(priv, sta->addr);
+ sta_id = iwl_sta_id(sta);
if (sta_id != IWL_INVALID_STATION)
iwl_sta_modify_ps_wake(priv, sta_id);
break;
@@ -3036,10 +3230,12 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
{
struct iwl_priv *priv = hw->priv;
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
- bool is_ap = priv->iw_mode == NL80211_IFTYPE_STATION;
+ bool is_ap = vif->type == NL80211_IFTYPE_STATION;
int ret;
u8 sta_id;
+ sta_priv->common.sta_id = IWL_INVALID_STATION;
+
IWL_DEBUG_INFO(priv, "received request to add station %pM\n",
sta->addr);
@@ -3056,12 +3252,14 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
return ret;
}
+ sta_priv->common.sta_id = sta_id;
+
/* Initialize rate scaling */
IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
sta->addr);
iwl_rs_rate_init(priv, sta, sta_id);
- return ret;
+ return 0;
}
/*****************************************************************************
@@ -3586,6 +3784,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
iwl_power_initialize(priv);
iwl_tt_initialize(priv);
+ init_completion(&priv->_agn.firmware_loading_complete);
+
err = iwl_request_firmware(priv, true);
if (err)
goto out_remove_sysfs;
@@ -3626,6 +3826,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
if (!priv)
return;
+ wait_for_completion(&priv->_agn.firmware_loading_complete);
+
IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
iwl_dbgfs_unregister(priv);
@@ -3783,11 +3985,10 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
{IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
-/* 6x00 Series Gen2 */
- {IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6000g2_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6000g2_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6000g2_2agn_cfg)},
+/* 6x00 Series Gen2a */
+ {IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2a_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0085, 0x1211, iwl6000g2a_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1221, iwl6000g2a_2agn_cfg)},
/* 6x50 WiFi/WiMax Series */
{IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
@@ -3900,3 +4101,8 @@ MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
module_param_named(
disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+
+module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int,
+ S_IRUGO);
+MODULE_PARM_DESC(ucode_alternative,
+ "specify ucode alternative to use from ucode file");