|
@@ -34,7 +34,6 @@
|
|
|
#include <linux/sched.h>
|
|
|
#include <linux/skbuff.h>
|
|
|
#include <linux/netdevice.h>
|
|
|
-#include <linux/firmware.h>
|
|
|
#include <linux/etherdevice.h>
|
|
|
#include <linux/if_arp.h>
|
|
|
|
|
@@ -42,6 +41,7 @@
|
|
|
|
|
|
#include <asm/div64.h>
|
|
|
|
|
|
+#include "iwl-ucode.h"
|
|
|
#include "iwl-eeprom.h"
|
|
|
#include "iwl-wifi.h"
|
|
|
#include "iwl-dev.h"
|
|
@@ -328,14 +328,14 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
|
|
|
ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
|
|
|
|
|
|
/* Make sure device is powered up for SRAM reads */
|
|
|
- spin_lock_irqsave(&bus(priv)->reg_lock, reg_flags);
|
|
|
- if (iwl_grab_nic_access(bus(priv))) {
|
|
|
- spin_unlock_irqrestore(&bus(priv)->reg_lock, reg_flags);
|
|
|
+ spin_lock_irqsave(&trans(priv)->reg_lock, reg_flags);
|
|
|
+ if (iwl_grab_nic_access(trans(priv))) {
|
|
|
+ spin_unlock_irqrestore(&trans(priv)->reg_lock, reg_flags);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
/* Set starting address; reads will auto-increment */
|
|
|
- iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, ptr);
|
|
|
+ iwl_write32(trans(priv), HBUS_TARG_MEM_RADDR, ptr);
|
|
|
rmb();
|
|
|
|
|
|
/*
|
|
@@ -352,19 +352,19 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
|
|
|
* place event id # at far right for easier visual parsing.
|
|
|
*/
|
|
|
for (i = 0; i < num_events; i++) {
|
|
|
- ev = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
|
|
|
- time = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
|
|
|
+ ev = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
|
|
|
+ time = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
|
|
|
if (mode == 0) {
|
|
|
trace_iwlwifi_dev_ucode_cont_event(priv, 0, time, ev);
|
|
|
} else {
|
|
|
- data = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
|
|
|
+ data = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
|
|
|
trace_iwlwifi_dev_ucode_cont_event(priv, time,
|
|
|
data, ev);
|
|
|
}
|
|
|
}
|
|
|
/* Allow device to power down */
|
|
|
- iwl_release_nic_access(bus(priv));
|
|
|
- spin_unlock_irqrestore(&bus(priv)->reg_lock, reg_flags);
|
|
|
+ iwl_release_nic_access(trans(priv));
|
|
|
+ spin_unlock_irqrestore(&trans(priv)->reg_lock, reg_flags);
|
|
|
}
|
|
|
|
|
|
static void iwl_continuous_event_trace(struct iwl_priv *priv)
|
|
@@ -383,7 +383,7 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv)
|
|
|
|
|
|
base = priv->shrd->device_pointers.log_event_table;
|
|
|
if (iwlagn_hw_valid_rtc_data_addr(base)) {
|
|
|
- iwl_read_targ_mem_words(bus(priv), base, &read, sizeof(read));
|
|
|
+ iwl_read_targ_mem_words(trans(priv), base, &read, sizeof(read));
|
|
|
|
|
|
capacity = read.capacity;
|
|
|
mode = read.mode;
|
|
@@ -490,7 +490,7 @@ static void iwl_bg_tx_flush(struct work_struct *work)
|
|
|
iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
|
|
|
}
|
|
|
|
|
|
-static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
|
|
|
+void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
|
|
|
{
|
|
|
int i;
|
|
|
|
|
@@ -513,6 +513,7 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
|
|
|
priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
|
|
|
priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
|
|
|
priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
|
|
|
+ priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
|
|
|
priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
|
|
|
BIT(NL80211_IFTYPE_ADHOC);
|
|
|
priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
|
|
@@ -547,609 +548,6 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
|
|
|
BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
|
|
|
}
|
|
|
|
|
|
-static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
|
|
|
-
|
|
|
-#define UCODE_EXPERIMENTAL_INDEX 100
|
|
|
-#define UCODE_EXPERIMENTAL_TAG "exp"
|
|
|
-
|
|
|
-static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
|
|
|
-{
|
|
|
- const char *name_pre = cfg(priv)->fw_name_pre;
|
|
|
- char tag[8];
|
|
|
-
|
|
|
- if (first) {
|
|
|
-#ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
|
|
|
- priv->fw_index = UCODE_EXPERIMENTAL_INDEX;
|
|
|
- strcpy(tag, UCODE_EXPERIMENTAL_TAG);
|
|
|
- } else if (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) {
|
|
|
-#endif
|
|
|
- priv->fw_index = cfg(priv)->ucode_api_max;
|
|
|
- sprintf(tag, "%d", priv->fw_index);
|
|
|
- } else {
|
|
|
- priv->fw_index--;
|
|
|
- sprintf(tag, "%d", priv->fw_index);
|
|
|
- }
|
|
|
-
|
|
|
- if (priv->fw_index < cfg(priv)->ucode_api_min) {
|
|
|
- IWL_ERR(priv, "no suitable firmware found!\n");
|
|
|
- return -ENOENT;
|
|
|
- }
|
|
|
-
|
|
|
- sprintf(priv->firmware_name, "%s%s%s", name_pre, tag, ".ucode");
|
|
|
-
|
|
|
- IWL_DEBUG_INFO(priv, "attempting to load firmware %s'%s'\n",
|
|
|
- (priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
|
|
|
- ? "EXPERIMENTAL " : "",
|
|
|
- priv->firmware_name);
|
|
|
-
|
|
|
- return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name,
|
|
|
- bus(priv)->dev,
|
|
|
- GFP_KERNEL, priv, iwl_ucode_callback);
|
|
|
-}
|
|
|
-
|
|
|
-struct iwlagn_firmware_pieces {
|
|
|
- const void *inst, *data, *init, *init_data, *wowlan_inst, *wowlan_data;
|
|
|
- size_t inst_size, data_size, init_size, init_data_size,
|
|
|
- wowlan_inst_size, wowlan_data_size;
|
|
|
-
|
|
|
- u32 build;
|
|
|
-
|
|
|
- u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
|
|
|
- u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
|
|
|
-};
|
|
|
-
|
|
|
-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:
|
|
|
- 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);
|
|
|
- src = ucode->u.v2.data;
|
|
|
- break;
|
|
|
- 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);
|
|
|
- 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) {
|
|
|
-
|
|
|
- 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;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-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_mod_params.wanted_ucode_alternative;
|
|
|
- int tmp;
|
|
|
- u64 alternatives;
|
|
|
- u32 tlv_len;
|
|
|
- enum iwl_ucode_tlv_type tlv_type;
|
|
|
- const u8 *tlv_data;
|
|
|
-
|
|
|
- if (len < sizeof(*ucode)) {
|
|
|
- IWL_ERR(priv, "uCode has invalid length: %zd\n", len);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) {
|
|
|
- IWL_ERR(priv, "invalid uCode magic: 0X%x\n",
|
|
|
- le32_to_cpu(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)) {
|
|
|
- u16 tlv_alt;
|
|
|
-
|
|
|
- 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) {
|
|
|
- IWL_ERR(priv, "invalid TLV len: %zd/%u\n",
|
|
|
- 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:
|
|
|
- IWL_ERR(priv, "Found unexpected BOOT ucode\n");
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_PROBE_MAX_LEN:
|
|
|
- if (tlv_len != sizeof(u32))
|
|
|
- goto invalid_tlv_len;
|
|
|
- capa->max_probe_length =
|
|
|
- le32_to_cpup((__le32 *)tlv_data);
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_PAN:
|
|
|
- if (tlv_len)
|
|
|
- goto invalid_tlv_len;
|
|
|
- capa->flags |= IWL_UCODE_TLV_FLAGS_PAN;
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_FLAGS:
|
|
|
- /* must be at least one u32 */
|
|
|
- if (tlv_len < sizeof(u32))
|
|
|
- goto invalid_tlv_len;
|
|
|
- /* and a proper number of u32s */
|
|
|
- if (tlv_len % sizeof(u32))
|
|
|
- goto invalid_tlv_len;
|
|
|
- /*
|
|
|
- * This driver only reads the first u32 as
|
|
|
- * right now no more features are defined,
|
|
|
- * if that changes then either the driver
|
|
|
- * will not work with the new firmware, or
|
|
|
- * it'll not take advantage of new features.
|
|
|
- */
|
|
|
- capa->flags = le32_to_cpup((__le32 *)tlv_data);
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
|
|
|
- if (tlv_len != sizeof(u32))
|
|
|
- goto invalid_tlv_len;
|
|
|
- pieces->init_evtlog_ptr =
|
|
|
- le32_to_cpup((__le32 *)tlv_data);
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_INIT_EVTLOG_SIZE:
|
|
|
- if (tlv_len != sizeof(u32))
|
|
|
- goto invalid_tlv_len;
|
|
|
- pieces->init_evtlog_size =
|
|
|
- le32_to_cpup((__le32 *)tlv_data);
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_INIT_ERRLOG_PTR:
|
|
|
- if (tlv_len != sizeof(u32))
|
|
|
- goto invalid_tlv_len;
|
|
|
- pieces->init_errlog_ptr =
|
|
|
- le32_to_cpup((__le32 *)tlv_data);
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_RUNT_EVTLOG_PTR:
|
|
|
- if (tlv_len != sizeof(u32))
|
|
|
- goto invalid_tlv_len;
|
|
|
- pieces->inst_evtlog_ptr =
|
|
|
- le32_to_cpup((__le32 *)tlv_data);
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE:
|
|
|
- if (tlv_len != sizeof(u32))
|
|
|
- goto invalid_tlv_len;
|
|
|
- pieces->inst_evtlog_size =
|
|
|
- le32_to_cpup((__le32 *)tlv_data);
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_RUNT_ERRLOG_PTR:
|
|
|
- if (tlv_len != sizeof(u32))
|
|
|
- goto invalid_tlv_len;
|
|
|
- pieces->inst_errlog_ptr =
|
|
|
- le32_to_cpup((__le32 *)tlv_data);
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_ENHANCE_SENS_TBL:
|
|
|
- if (tlv_len)
|
|
|
- goto invalid_tlv_len;
|
|
|
- priv->enhance_sensitivity_table = true;
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_WOWLAN_INST:
|
|
|
- pieces->wowlan_inst = tlv_data;
|
|
|
- pieces->wowlan_inst_size = tlv_len;
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_WOWLAN_DATA:
|
|
|
- pieces->wowlan_data = tlv_data;
|
|
|
- pieces->wowlan_data_size = tlv_len;
|
|
|
- break;
|
|
|
- case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE:
|
|
|
- if (tlv_len != sizeof(u32))
|
|
|
- goto invalid_tlv_len;
|
|
|
- capa->standard_phy_calibration_size =
|
|
|
- le32_to_cpup((__le32 *)tlv_data);
|
|
|
- break;
|
|
|
- default:
|
|
|
- IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (len) {
|
|
|
- IWL_ERR(priv, "invalid TLV after parsing: %zd\n", len);
|
|
|
- iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)data, len);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-
|
|
|
- invalid_tlv_len:
|
|
|
- IWL_ERR(priv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len);
|
|
|
- iwl_print_hex_dump(priv, IWL_DL_FW, tlv_data, tlv_len);
|
|
|
-
|
|
|
- return -EINVAL;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 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_priv *priv = context;
|
|
|
- struct iwl_ucode_header *ucode;
|
|
|
- int err;
|
|
|
- struct iwlagn_firmware_pieces pieces;
|
|
|
- const unsigned int api_max = cfg(priv)->ucode_api_max;
|
|
|
- unsigned int api_ok = cfg(priv)->ucode_api_ok;
|
|
|
- const unsigned int api_min = cfg(priv)->ucode_api_min;
|
|
|
- u32 api_ver;
|
|
|
- char buildstr[25];
|
|
|
- u32 build;
|
|
|
- struct iwlagn_ucode_capabilities ucode_capa = {
|
|
|
- .max_probe_length = 200,
|
|
|
- .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 (priv->fw_index <= api_ok)
|
|
|
- IWL_ERR(priv,
|
|
|
- "request for firmware file '%s' failed.\n",
|
|
|
- priv->firmware_name);
|
|
|
- goto try_again;
|
|
|
- }
|
|
|
-
|
|
|
- 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 API version number */
|
|
|
- if (ucode_raw->size < 4) {
|
|
|
- IWL_ERR(priv, "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 = 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 = 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
|
|
|
- */
|
|
|
- /* no api version check required for experimental uCode */
|
|
|
- if (priv->fw_index != UCODE_EXPERIMENTAL_INDEX) {
|
|
|
- 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",
|
|
|
- api_max, api_ver);
|
|
|
- goto try_again;
|
|
|
- }
|
|
|
-
|
|
|
- if (api_ver < api_ok) {
|
|
|
- if (api_ok != api_max)
|
|
|
- IWL_ERR(priv, "Firmware has old API version, "
|
|
|
- "expected v%u through v%u, got v%u.\n",
|
|
|
- api_ok, api_max, api_ver);
|
|
|
- else
|
|
|
- IWL_ERR(priv, "Firmware has old API version, "
|
|
|
- "expected v%u, got v%u.\n",
|
|
|
- api_max, api_ver);
|
|
|
- IWL_ERR(priv, "New firmware can be obtained from "
|
|
|
- "http://www.intellinuxwireless.org/.\n");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (build)
|
|
|
- sprintf(buildstr, " build %u%s", build,
|
|
|
- (priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
|
|
|
- ? " (EXP)" : "");
|
|
|
- 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%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),
|
|
|
- buildstr);
|
|
|
-
|
|
|
- /*
|
|
|
- * For any of the failures below (before allocating pci memory)
|
|
|
- * we will try to load a version with a smaller API -- maybe the
|
|
|
- * user just got a corrupted version of the latest API.
|
|
|
- */
|
|
|
-
|
|
|
- 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);
|
|
|
-
|
|
|
- /* Verify that uCode images will fit in card's SRAM */
|
|
|
- if (pieces.inst_size > hw_params(priv).max_inst_size) {
|
|
|
- IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n",
|
|
|
- pieces.inst_size);
|
|
|
- goto try_again;
|
|
|
- }
|
|
|
-
|
|
|
- if (pieces.data_size > hw_params(priv).max_data_size) {
|
|
|
- IWL_ERR(priv, "uCode data len %Zd too large to fit in\n",
|
|
|
- pieces.data_size);
|
|
|
- goto try_again;
|
|
|
- }
|
|
|
-
|
|
|
- if (pieces.init_size > hw_params(priv).max_inst_size) {
|
|
|
- IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n",
|
|
|
- pieces.init_size);
|
|
|
- goto try_again;
|
|
|
- }
|
|
|
-
|
|
|
- if (pieces.init_data_size > hw_params(priv).max_data_size) {
|
|
|
- IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n",
|
|
|
- pieces.init_data_size);
|
|
|
- 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 */
|
|
|
- if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.code,
|
|
|
- pieces.inst, pieces.inst_size))
|
|
|
- goto err_pci_alloc;
|
|
|
- if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.data,
|
|
|
- pieces.data, pieces.data_size))
|
|
|
- goto err_pci_alloc;
|
|
|
-
|
|
|
- /* Initialization instructions and data */
|
|
|
- if (pieces.init_size && pieces.init_data_size) {
|
|
|
- if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.code,
|
|
|
- pieces.init, pieces.init_size))
|
|
|
- goto err_pci_alloc;
|
|
|
- if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.data,
|
|
|
- pieces.init_data, pieces.init_data_size))
|
|
|
- goto err_pci_alloc;
|
|
|
- }
|
|
|
-
|
|
|
- /* WoWLAN instructions and data */
|
|
|
- if (pieces.wowlan_inst_size && pieces.wowlan_data_size) {
|
|
|
- if (iwl_alloc_fw_desc(bus(priv),
|
|
|
- &trans(priv)->ucode_wowlan.code,
|
|
|
- pieces.wowlan_inst,
|
|
|
- pieces.wowlan_inst_size))
|
|
|
- goto err_pci_alloc;
|
|
|
- if (iwl_alloc_fw_desc(bus(priv),
|
|
|
- &trans(priv)->ucode_wowlan.data,
|
|
|
- pieces.wowlan_data,
|
|
|
- pieces.wowlan_data_size))
|
|
|
- goto err_pci_alloc;
|
|
|
- }
|
|
|
-
|
|
|
- /* 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.
|
|
|
- */
|
|
|
- priv->init_evtlog_ptr = pieces.init_evtlog_ptr;
|
|
|
- if (pieces.init_evtlog_size)
|
|
|
- priv->init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
|
|
|
- else
|
|
|
- priv->init_evtlog_size =
|
|
|
- cfg(priv)->base_params->max_event_log_size;
|
|
|
- priv->init_errlog_ptr = pieces.init_errlog_ptr;
|
|
|
- priv->inst_evtlog_ptr = pieces.inst_evtlog_ptr;
|
|
|
- if (pieces.inst_evtlog_size)
|
|
|
- priv->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
|
|
|
- else
|
|
|
- priv->inst_evtlog_size =
|
|
|
- cfg(priv)->base_params->max_event_log_size;
|
|
|
- priv->inst_errlog_ptr = pieces.inst_errlog_ptr;
|
|
|
-#ifndef CONFIG_IWLWIFI_P2P
|
|
|
- ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
|
|
|
-#endif
|
|
|
-
|
|
|
- priv->new_scan_threshold_behaviour =
|
|
|
- !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
|
|
|
-
|
|
|
- if (!(cfg(priv)->sku & EEPROM_SKU_CAP_IPAN_ENABLE))
|
|
|
- ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
|
|
|
-
|
|
|
- /*
|
|
|
- * if not PAN, then don't support P2P -- might be a uCode
|
|
|
- * packaging bug or due to the eeprom check above
|
|
|
- */
|
|
|
- if (!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN))
|
|
|
- ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
|
|
|
-
|
|
|
- if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) {
|
|
|
- priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
|
|
|
- priv->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
|
|
|
- } else {
|
|
|
- priv->sta_key_max_num = STA_KEY_MAX_NUM;
|
|
|
- priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
|
|
|
- }
|
|
|
- /*
|
|
|
- * figure out the offset of chain noise reset and gain commands
|
|
|
- * base on the size of standard phy calibration commands table size
|
|
|
- */
|
|
|
- if (ucode_capa.standard_phy_calibration_size >
|
|
|
- IWL_MAX_PHY_CALIBRATE_TBL_SIZE)
|
|
|
- ucode_capa.standard_phy_calibration_size =
|
|
|
- IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE;
|
|
|
-
|
|
|
- priv->phy_calib_chain_noise_reset_cmd =
|
|
|
- ucode_capa.standard_phy_calibration_size;
|
|
|
- priv->phy_calib_chain_noise_gain_cmd =
|
|
|
- ucode_capa.standard_phy_calibration_size + 1;
|
|
|
-
|
|
|
- /* initialize all valid contexts */
|
|
|
- iwl_init_context(priv, ucode_capa.flags);
|
|
|
-
|
|
|
- /**************************************************
|
|
|
- * This is still part of probe() in a sense...
|
|
|
- *
|
|
|
- * 9. Setup and register with mac80211 and debugfs
|
|
|
- **************************************************/
|
|
|
- err = iwlagn_mac_setup_register(priv, &ucode_capa);
|
|
|
- if (err)
|
|
|
- goto out_unbind;
|
|
|
-
|
|
|
- err = iwl_dbgfs_register(priv, DRV_NAME);
|
|
|
- if (err)
|
|
|
- IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
|
|
|
-
|
|
|
- /* We have our copies now, allow OS release its copies */
|
|
|
- release_firmware(ucode_raw);
|
|
|
- complete(&priv->firmware_loading_complete);
|
|
|
- return;
|
|
|
-
|
|
|
- try_again:
|
|
|
- /* try next, if any */
|
|
|
- if (iwl_request_firmware(priv, false))
|
|
|
- goto out_unbind;
|
|
|
- release_firmware(ucode_raw);
|
|
|
- return;
|
|
|
-
|
|
|
- err_pci_alloc:
|
|
|
- IWL_ERR(priv, "failed to allocate pci memory\n");
|
|
|
- iwl_dealloc_ucode(trans(priv));
|
|
|
- out_unbind:
|
|
|
- complete(&priv->firmware_loading_complete);
|
|
|
- device_release_driver(bus(priv)->dev);
|
|
|
- release_firmware(ucode_raw);
|
|
|
-}
|
|
|
-
|
|
|
static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
|
|
{
|
|
|
struct iwl_ct_kill_config cmd;
|
|
@@ -1158,7 +556,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
|
|
int ret = 0;
|
|
|
|
|
|
spin_lock_irqsave(&priv->shrd->lock, flags);
|
|
|
- iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
|
|
|
+ iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR,
|
|
|
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
|
|
|
spin_unlock_irqrestore(&priv->shrd->lock, flags);
|
|
|
priv->thermal_throttle.ct_kill_toggle = false;
|
|
@@ -1243,9 +641,6 @@ int iwl_alive_start(struct iwl_priv *priv)
|
|
|
int ret = 0;
|
|
|
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
|
|
|
|
|
- /*TODO: this should go to the transport layer */
|
|
|
- iwl_reset_ict(trans(priv));
|
|
|
-
|
|
|
IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
|
|
|
|
|
|
/* After the ALIVE response, we can send host commands to the uCode */
|
|
@@ -1692,13 +1087,6 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-static u32 iwl_hw_detect(struct iwl_priv *priv)
|
|
|
-{
|
|
|
- return iwl_read32(bus(priv), CSR_HW_REV);
|
|
|
-}
|
|
|
-
|
|
|
/* Size of one Rx buffer in host DRAM */
|
|
|
#define IWL_RX_BUF_SIZE_4K (4 * 1024)
|
|
|
#define IWL_RX_BUF_SIZE_8K (8 * 1024)
|
|
@@ -1730,32 +1118,32 @@ static int iwl_set_hw_params(struct iwl_priv *priv)
|
|
|
|
|
|
static void iwl_debug_config(struct iwl_priv *priv)
|
|
|
{
|
|
|
- dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEBUG "
|
|
|
+ dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEBUG "
|
|
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
|
|
"enabled\n");
|
|
|
#else
|
|
|
"disabled\n");
|
|
|
#endif
|
|
|
- dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEBUGFS "
|
|
|
+ dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEBUGFS "
|
|
|
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
|
|
"enabled\n");
|
|
|
#else
|
|
|
"disabled\n");
|
|
|
#endif
|
|
|
- dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TRACING "
|
|
|
+ dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TRACING "
|
|
|
#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
|
|
|
"enabled\n");
|
|
|
#else
|
|
|
"disabled\n");
|
|
|
#endif
|
|
|
|
|
|
- dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TESTMODE "
|
|
|
+ dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TESTMODE "
|
|
|
#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
|
|
|
"enabled\n");
|
|
|
#else
|
|
|
"disabled\n");
|
|
|
#endif
|
|
|
- dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_P2P "
|
|
|
+ dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_P2P "
|
|
|
#ifdef CONFIG_IWLWIFI_P2P
|
|
|
"enabled\n");
|
|
|
#else
|
|
@@ -1770,7 +1158,6 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
|
|
|
struct iwl_priv *priv;
|
|
|
struct ieee80211_hw *hw;
|
|
|
u16 num_mac;
|
|
|
- u32 hw_rev;
|
|
|
|
|
|
/************************
|
|
|
* 1. Allocating HW data
|
|
@@ -1783,22 +1170,14 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
|
|
|
}
|
|
|
|
|
|
priv = hw->priv;
|
|
|
- priv->shrd = &priv->_shrd;
|
|
|
- bus->shrd = priv->shrd;
|
|
|
- priv->shrd->bus = bus;
|
|
|
+ priv->shrd = bus->shrd;
|
|
|
priv->shrd->priv = priv;
|
|
|
|
|
|
- priv->shrd->trans = trans_ops->alloc(priv->shrd);
|
|
|
- if (priv->shrd->trans == NULL) {
|
|
|
- err = -ENOMEM;
|
|
|
- goto out_free_traffic_mem;
|
|
|
- }
|
|
|
-
|
|
|
/* At this point both hw and priv are allocated. */
|
|
|
|
|
|
- SET_IEEE80211_DEV(hw, bus(priv)->dev);
|
|
|
+ SET_IEEE80211_DEV(hw, trans(priv)->dev);
|
|
|
|
|
|
- /* what debugging capabilities we have */
|
|
|
+ /* show what debugging capabilities we have */
|
|
|
iwl_debug_config(priv);
|
|
|
|
|
|
IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
|
|
@@ -1821,41 +1200,29 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
|
|
|
/* these spin locks will be used in apm_ops.init and EEPROM access
|
|
|
* we should init now
|
|
|
*/
|
|
|
- spin_lock_init(&bus(priv)->reg_lock);
|
|
|
+ spin_lock_init(&trans(priv)->reg_lock);
|
|
|
spin_lock_init(&priv->shrd->lock);
|
|
|
|
|
|
- /*
|
|
|
- * stop and reset the on-board processor just in case it is in a
|
|
|
- * strange state ... like being left stranded by a primary kernel
|
|
|
- * and this is now the kdump kernel trying to start up
|
|
|
- */
|
|
|
- iwl_write32(bus(priv), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
|
|
|
-
|
|
|
/***********************
|
|
|
* 3. Read REV register
|
|
|
***********************/
|
|
|
- hw_rev = iwl_hw_detect(priv);
|
|
|
IWL_INFO(priv, "Detected %s, REV=0x%X\n",
|
|
|
- cfg(priv)->name, hw_rev);
|
|
|
+ cfg(priv)->name, trans(priv)->hw_rev);
|
|
|
|
|
|
- err = iwl_trans_request_irq(trans(priv));
|
|
|
+ err = iwl_trans_start_hw(trans(priv));
|
|
|
if (err)
|
|
|
- goto out_free_trans;
|
|
|
-
|
|
|
- if (iwl_trans_prepare_card_hw(trans(priv))) {
|
|
|
- err = -EIO;
|
|
|
- IWL_WARN(priv, "Failed, HW not ready\n");
|
|
|
- goto out_free_trans;
|
|
|
- }
|
|
|
+ goto out_free_traffic_mem;
|
|
|
|
|
|
/*****************
|
|
|
* 4. Read EEPROM
|
|
|
*****************/
|
|
|
/* Read the EEPROM */
|
|
|
- err = iwl_eeprom_init(priv, hw_rev);
|
|
|
+ err = iwl_eeprom_init(priv, trans(priv)->hw_rev);
|
|
|
+ /* Reset chip to save power until we load uCode during "up". */
|
|
|
+ iwl_trans_stop_hw(trans(priv));
|
|
|
if (err) {
|
|
|
IWL_ERR(priv, "Unable to init EEPROM\n");
|
|
|
- goto out_free_trans;
|
|
|
+ goto out_free_traffic_mem;
|
|
|
}
|
|
|
err = iwl_eeprom_check_version(priv);
|
|
|
if (err)
|
|
@@ -1903,22 +1270,6 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
|
|
|
iwl_setup_rx_handlers(priv);
|
|
|
iwl_testmode_init(priv);
|
|
|
|
|
|
- /*********************************************
|
|
|
- * 8. Enable interrupts
|
|
|
- *********************************************/
|
|
|
-
|
|
|
- iwl_enable_rfkill_int(priv);
|
|
|
-
|
|
|
- /* If platform's RF_KILL switch is NOT set to KILL */
|
|
|
- if (iwl_read32(bus(priv),
|
|
|
- CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
|
|
|
- clear_bit(STATUS_RF_KILL_HW, &priv->shrd->status);
|
|
|
- else
|
|
|
- set_bit(STATUS_RF_KILL_HW, &priv->shrd->status);
|
|
|
-
|
|
|
- wiphy_rfkill_set_hw_state(priv->hw->wiphy,
|
|
|
- test_bit(STATUS_RF_KILL_HW, &priv->shrd->status));
|
|
|
-
|
|
|
iwl_power_initialize(priv);
|
|
|
iwl_tt_initialize(priv);
|
|
|
|
|
@@ -1936,8 +1287,6 @@ out_destroy_workqueue:
|
|
|
iwl_uninit_drv(priv);
|
|
|
out_free_eeprom:
|
|
|
iwl_eeprom_free(priv->shrd);
|
|
|
-out_free_trans:
|
|
|
- iwl_trans_free(trans(priv));
|
|
|
out_free_traffic_mem:
|
|
|
iwl_free_traffic_mem(priv);
|
|
|
ieee80211_free_hw(priv->hw);
|
|
@@ -1981,8 +1330,6 @@ void __devexit iwl_remove(struct iwl_priv * priv)
|
|
|
priv->shrd->workqueue = NULL;
|
|
|
iwl_free_traffic_mem(priv);
|
|
|
|
|
|
- iwl_trans_free(trans(priv));
|
|
|
-
|
|
|
iwl_uninit_drv(priv);
|
|
|
|
|
|
dev_kfree_skb(priv->beacon_skb);
|