We adding 16.0 uCode support which has different TLV layout.
We are continue the driver re-factor works to separate the driver into
upper(op-mode) and lower layers.
David Spinadel (6):
iwlwifi: avoid some operations if no uCode loaded
iwlwifi: explicitly track whether INIT uCode was run
iwlwifi: more modularity in fw images and sections
iwlwifi: Add TLVs and fields for 16.0 uCode
iwlwifi: change struct iwl_fw
iwlwifi: Add bool mvm_ucode to iwl_fw
Johannes Berg (3):
iwlwifi: remove TX hex debug
iwlwifi: abstract out missing SEQ_RX_FRAME workaround
iwlwifi: convert bad state message into warning
Meenakshi Venkataraman (1):
iwlwifi: move wait_command_queue from shared to trans
these patches are also available from wireless-next branch on
git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 1 +
drivers/net/wireless/iwlwifi/iwl-agn-rx.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-agn.c | 14 +-
drivers/net/wireless/iwlwifi/iwl-core.c | 5 +-
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 14 +-
drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +
drivers/net/wireless/iwlwifi/iwl-drv.c | 430 ++++++++++++++++-----
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 5 +
drivers/net/wireless/iwlwifi/iwl-fw.h | 49 ++-
drivers/net/wireless/iwlwifi/iwl-mac80211.c | 15 +-
drivers/net/wireless/iwlwifi/iwl-shared.h | 20 -
drivers/net/wireless/iwlwifi/iwl-testmode.c | 27 +-
drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h | 2 +
drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | 31 +-
drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c | 4 +-
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 44 ++-
drivers/net/wireless/iwlwifi/iwl-trans.h | 40 ++-
drivers/net/wireless/iwlwifi/iwl-ucode.c | 39 +-
18 files changed, 511 insertions(+), 233 deletions(-)
From: David Spinadel <[email protected]>
Changed iwl_firmware_pieces structure to support an array of
separate images, and an array of sections for each image.
In fw_sec and fw_desc structures, added a field for
offset from the HW address, to support 16.0 uCode that
provides an offset instead of any other data about the section.
This field is filled with default values when parsing instruction
or data section.
Signed-off-by: David Spinadel <[email protected]>
Signed-off-by: Wey-Yi Guy <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-drv.c | 280 +++++++++++++++++++++--------
drivers/net/wireless/iwlwifi/iwl-fw.h | 3 +-
drivers/net/wireless/iwlwifi/iwl-shared.h | 1 +
3 files changed, 207 insertions(+), 77 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index 29a3ae4..a21af3d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -69,6 +69,7 @@
#include "iwl-trans.h"
#include "iwl-shared.h"
#include "iwl-op-mode.h"
+#include "iwl-agn-hw.h"
/* private includes */
#include "iwl-fw-file.h"
@@ -96,6 +97,16 @@ struct iwl_drv {
+/*
+ * struct fw_sec: Just for the image parsing proccess.
+ * For the fw storage we are using struct fw_desc.
+ */
+struct fw_sec {
+ const void *data; /* the sec data */
+ size_t size; /* section size */
+ u32 offset; /* offset of writing in the device */
+};
+
static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc)
{
if (desc->v_addr)
@@ -119,20 +130,21 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
}
static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc,
- const void *data, size_t len)
+ struct fw_sec *sec)
{
- if (!len) {
+ if (!sec || !sec->size) {
desc->v_addr = NULL;
return -EINVAL;
}
- desc->v_addr = dma_alloc_coherent(trans(drv)->dev, len,
+ desc->v_addr = dma_alloc_coherent(trans(drv)->dev, sec->size,
&desc->p_addr, GFP_KERNEL);
if (!desc->v_addr)
return -ENOMEM;
- desc->len = len;
- memcpy(desc->v_addr, data, len);
+ desc->len = sec->size;
+ desc->offset = sec->offset;
+ memcpy(desc->v_addr, sec->data, sec->size);
return 0;
}
@@ -177,18 +189,77 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
GFP_KERNEL, drv, 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;
+/*
+ * enumeration of ucode section.
+ * This enumeration is used for legacy tlv style (before 16.0 uCode).
+ */
+enum iwl_ucode_sec {
+ IWL_UCODE_SECTION_INST,
+ IWL_UCODE_SECTION_DATA,
+};
+/*
+ * For 16.0 uCode and above, there is no differentiation between section,
+ * just an offset to the HW address.
+ */
+#define UCODE_SECTION_MAX 4
+
+struct fw_img_parsing {
+ struct fw_sec sec[UCODE_SECTION_MAX];
+ int sec_counter;
+};
+
+struct iwl_firmware_pieces {
+ struct fw_img_parsing img[IWL_UCODE_TYPE_MAX];
u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
};
+/*
+ * These functions are just to extract uCode section data from the pieces
+ * structure.
+ */
+static struct fw_sec *get_sec(struct iwl_firmware_pieces *pieces,
+ enum iwl_ucode_type type,
+ int sec)
+{
+ return &pieces->img[type].sec[sec];
+}
+
+static void set_sec_data(struct iwl_firmware_pieces *pieces,
+ enum iwl_ucode_type type,
+ int sec,
+ const void *data)
+{
+ pieces->img[type].sec[sec].data = data;
+}
+
+static void set_sec_size(struct iwl_firmware_pieces *pieces,
+ enum iwl_ucode_type type,
+ int sec,
+ size_t size)
+{
+ pieces->img[type].sec[sec].size = size;
+}
+
+static size_t get_sec_size(struct iwl_firmware_pieces *pieces,
+ enum iwl_ucode_type type,
+ int sec)
+{
+ return pieces->img[type].sec[sec].size;
+}
+
+static void set_sec_offset(struct iwl_firmware_pieces *pieces,
+ enum iwl_ucode_type type,
+ int sec,
+ u32 offset)
+{
+ pieces->img[type].sec[sec].offset = offset;
+}
+
static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
- const struct firmware *ucode_raw,
- struct iwlagn_firmware_pieces *pieces)
+ const struct firmware *ucode_raw,
+ struct iwl_firmware_pieces *pieces)
{
struct iwl_ucode_header *ucode = (void *)ucode_raw->data;
u32 api_ver, hdr_size, build;
@@ -206,11 +277,14 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
return -EINVAL;
}
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);
+ set_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST,
+ le32_to_cpu(ucode->u.v2.inst_size));
+ set_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA,
+ le32_to_cpu(ucode->u.v2.data_size));
+ set_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST,
+ le32_to_cpu(ucode->u.v2.init_size));
+ set_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA,
+ le32_to_cpu(ucode->u.v2.init_data_size));
src = ucode->u.v2.data;
break;
case 0:
@@ -222,11 +296,14 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
return -EINVAL;
}
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);
+ set_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST,
+ le32_to_cpu(ucode->u.v1.inst_size));
+ set_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA,
+ le32_to_cpu(ucode->u.v1.data_size));
+ set_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST,
+ le32_to_cpu(ucode->u.v1.init_size));
+ set_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA,
+ le32_to_cpu(ucode->u.v1.init_data_size));
src = ucode->u.v1.data;
break;
}
@@ -248,9 +325,12 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
buildstr);
/* 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) {
+
+ if (ucode_raw->size != hdr_size +
+ get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) +
+ get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) +
+ get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) +
+ get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA)) {
IWL_ERR(drv,
"uCode file size %d does not match expected size\n",
@@ -258,21 +338,29 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
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;
+ set_sec_data(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST, src);
+ src += get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST);
+ set_sec_offset(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST,
+ IWLAGN_RTC_INST_LOWER_BOUND);
+ set_sec_data(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA, src);
+ src += get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA);
+ set_sec_offset(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA,
+ IWLAGN_RTC_DATA_LOWER_BOUND);
+ set_sec_data(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST, src);
+ src += get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST);
+ set_sec_offset(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST,
+ IWLAGN_RTC_INST_LOWER_BOUND);
+ set_sec_data(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA, src);
+ src += get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA);
+ set_sec_offset(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA,
+ IWLAGN_RTC_DATA_LOWER_BOUND);
return 0;
}
static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
const struct firmware *ucode_raw,
- struct iwlagn_firmware_pieces *pieces,
+ struct iwl_firmware_pieces *pieces,
struct iwl_ucode_capabilities *capa)
{
struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data;
@@ -368,20 +456,40 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
switch (tlv_type) {
case IWL_UCODE_TLV_INST:
- pieces->inst = tlv_data;
- pieces->inst_size = tlv_len;
+ set_sec_data(pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_INST, tlv_data);
+ set_sec_size(pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_INST, tlv_len);
+ set_sec_offset(pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_INST,
+ IWLAGN_RTC_INST_LOWER_BOUND);
break;
case IWL_UCODE_TLV_DATA:
- pieces->data = tlv_data;
- pieces->data_size = tlv_len;
+ set_sec_data(pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_DATA, tlv_data);
+ set_sec_size(pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_DATA, tlv_len);
+ set_sec_offset(pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_DATA,
+ IWLAGN_RTC_DATA_LOWER_BOUND);
break;
case IWL_UCODE_TLV_INIT:
- pieces->init = tlv_data;
- pieces->init_size = tlv_len;
+ set_sec_data(pieces, IWL_UCODE_INIT,
+ IWL_UCODE_SECTION_INST, tlv_data);
+ set_sec_size(pieces, IWL_UCODE_INIT,
+ IWL_UCODE_SECTION_INST, tlv_len);
+ set_sec_offset(pieces, IWL_UCODE_INIT,
+ IWL_UCODE_SECTION_INST,
+ IWLAGN_RTC_INST_LOWER_BOUND);
break;
case IWL_UCODE_TLV_INIT_DATA:
- pieces->init_data = tlv_data;
- pieces->init_data_size = tlv_len;
+ set_sec_data(pieces, IWL_UCODE_INIT,
+ IWL_UCODE_SECTION_DATA, tlv_data);
+ set_sec_size(pieces, IWL_UCODE_INIT,
+ IWL_UCODE_SECTION_DATA, tlv_len);
+ set_sec_offset(pieces, IWL_UCODE_INIT,
+ IWL_UCODE_SECTION_DATA,
+ IWLAGN_RTC_DATA_LOWER_BOUND);
break;
case IWL_UCODE_TLV_BOOT:
IWL_ERR(drv, "Found unexpected BOOT ucode\n");
@@ -455,12 +563,22 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
drv->fw.enhance_sensitivity_table = true;
break;
case IWL_UCODE_TLV_WOWLAN_INST:
- pieces->wowlan_inst = tlv_data;
- pieces->wowlan_inst_size = tlv_len;
+ set_sec_data(pieces, IWL_UCODE_WOWLAN,
+ IWL_UCODE_SECTION_INST, tlv_data);
+ set_sec_size(pieces, IWL_UCODE_WOWLAN,
+ IWL_UCODE_SECTION_INST, tlv_len);
+ set_sec_offset(pieces, IWL_UCODE_WOWLAN,
+ IWL_UCODE_SECTION_INST,
+ IWLAGN_RTC_INST_LOWER_BOUND);
break;
case IWL_UCODE_TLV_WOWLAN_DATA:
- pieces->wowlan_data = tlv_data;
- pieces->wowlan_data_size = tlv_len;
+ set_sec_data(pieces, IWL_UCODE_WOWLAN,
+ IWL_UCODE_SECTION_DATA, tlv_data);
+ set_sec_size(pieces, IWL_UCODE_WOWLAN,
+ IWL_UCODE_SECTION_DATA, tlv_len);
+ set_sec_offset(pieces, IWL_UCODE_WOWLAN,
+ IWL_UCODE_SECTION_DATA,
+ IWLAGN_RTC_DATA_LOWER_BOUND);
break;
case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE:
if (tlv_len != sizeof(u32))
@@ -502,7 +620,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
struct iwl_fw *fw = &drv->fw;
struct iwl_ucode_header *ucode;
int err;
- struct iwlagn_firmware_pieces pieces;
+ 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;
@@ -588,36 +706,46 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
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",
- pieces.inst_size);
+ get_sec_size(&pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_INST));
IWL_DEBUG_INFO(drv, "f/w package hdr runtime data size = %Zd\n",
- pieces.data_size);
+ get_sec_size(&pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_DATA));
IWL_DEBUG_INFO(drv, "f/w package hdr init inst size = %Zd\n",
- pieces.init_size);
+ get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST));
IWL_DEBUG_INFO(drv, "f/w package hdr init data size = %Zd\n",
- pieces.init_data_size);
+ get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA));
/* Verify that uCode images will fit in card's SRAM */
- if (pieces.inst_size > cfg->max_inst_size) {
+ 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",
- pieces.inst_size);
+ get_sec_size(&pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_INST));
goto try_again;
}
- if (pieces.data_size > cfg->max_data_size) {
+ 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",
- pieces.data_size);
+ get_sec_size(&pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_DATA));
goto try_again;
}
- if (pieces.init_size > 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",
- pieces.init_size);
+ get_sec_size(&pieces, IWL_UCODE_INIT,
+ IWL_UCODE_SECTION_INST));
goto try_again;
}
- if (pieces.init_data_size > cfg->max_data_size) {
+ if (get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA) >
+ cfg->max_data_size) {
IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n",
- pieces.init_data_size);
+ get_sec_size(&pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_DATA));
goto try_again;
}
@@ -627,35 +755,35 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
* 1) unmodified from disk
* 2) backup cache for save/restore during power-downs */
if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_rt.code,
- pieces.inst, pieces.inst_size))
+ get_sec(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST)))
goto err_pci_alloc;
if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_rt.data,
- pieces.data, pieces.data_size))
+ get_sec(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA)))
goto err_pci_alloc;
/* Initialization instructions and data */
- if (pieces.init_size && pieces.init_data_size) {
- if (iwl_alloc_fw_desc(drv,
- &drv->fw.ucode_init.code,
- pieces.init, pieces.init_size))
+ if (get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) &&
+ get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA)) {
+ if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_init.code,
+ get_sec(&pieces, IWL_UCODE_INIT,
+ IWL_UCODE_SECTION_INST)))
goto err_pci_alloc;
- if (iwl_alloc_fw_desc(drv,
- &drv->fw.ucode_init.data,
- pieces.init_data, pieces.init_data_size))
+ if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_init.data,
+ get_sec(&pieces, IWL_UCODE_INIT,
+ IWL_UCODE_SECTION_DATA)))
goto err_pci_alloc;
}
/* WoWLAN instructions and data */
- if (pieces.wowlan_inst_size && pieces.wowlan_data_size) {
- if (iwl_alloc_fw_desc(drv,
- &drv->fw.ucode_wowlan.code,
- pieces.wowlan_inst,
- pieces.wowlan_inst_size))
+ if (get_sec_size(&pieces, IWL_UCODE_WOWLAN, IWL_UCODE_SECTION_INST) &&
+ get_sec_size(&pieces, IWL_UCODE_WOWLAN, IWL_UCODE_SECTION_DATA)) {
+ if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_wowlan.code,
+ get_sec(&pieces, IWL_UCODE_WOWLAN,
+ IWL_UCODE_SECTION_INST)))
goto err_pci_alloc;
- if (iwl_alloc_fw_desc(drv,
- &drv->fw.ucode_wowlan.data,
- pieces.wowlan_data,
- pieces.wowlan_data_size))
+ if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_wowlan.data,
+ get_sec(&pieces, IWL_UCODE_WOWLAN,
+ IWL_UCODE_SECTION_DATA)))
goto err_pci_alloc;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 453812a..253f7e5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -91,11 +91,12 @@ struct iwl_ucode_capabilities {
u32 flags;
};
-/* one for each uCode image (inst/data, boot/init/runtime) */
+/* one for each uCode image (inst/data, init/runtime/wowlan) */
struct fw_desc {
dma_addr_t p_addr; /* hardware address */
void *v_addr; /* software address */
u32 len; /* size in bytes */
+ u32 offset; /* offset in the device */
};
struct fw_img {
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h
index 4cd2ece..d899c5c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-shared.h
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -205,6 +205,7 @@ enum iwl_ucode_type {
IWL_UCODE_REGULAR,
IWL_UCODE_INIT,
IWL_UCODE_WOWLAN,
+ IWL_UCODE_TYPE_MAX,
};
/*
--
1.7.0.4
From: David Spinadel <[email protected]>
New TLVs for ucode sections that are not known as
instruction or data.
New TLVs for phy-configuration and default calibrations.
Add default calib and phy config fields to iwl_fw.
Signed-off-by: David Spinadel <[email protected]>
Signed-off-by: Wey-Yi Guy <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-drv.c | 84 ++++++++++++++++++++++++++++
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 5 ++
drivers/net/wireless/iwlwifi/iwl-fw.h | 19 ++++++
drivers/net/wireless/iwlwifi/iwl-shared.h | 16 -----
4 files changed, 108 insertions(+), 16 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index a21af3d..19ccd36 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -208,6 +208,25 @@ struct fw_img_parsing {
int sec_counter;
};
+/*
+ * struct fw_sec_parsing: to extract fw section and it's offset from tlv
+ */
+struct fw_sec_parsing {
+ __le32 offset;
+ const u8 data[];
+} __packed;
+
+/**
+ * struct iwl_tlv_calib_data - parse the default calib data from TLV
+ *
+ * @ucode_type: the uCode to which the following default calib relates.
+ * @calib: default calibrations.
+ */
+struct iwl_tlv_calib_data {
+ __le32 ucode_type;
+ __le64 calib;
+} __packed;
+
struct iwl_firmware_pieces {
struct fw_img_parsing img[IWL_UCODE_TYPE_MAX];
@@ -257,6 +276,47 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces,
pieces->img[type].sec[sec].offset = offset;
}
+/*
+ * Gets uCode section from tlv.
+ */
+static int iwl_store_ucode_sec(struct iwl_firmware_pieces *pieces,
+ const void *data, enum iwl_ucode_type type,
+ int size)
+{
+ struct fw_img_parsing *img;
+ struct fw_sec *sec;
+ struct fw_sec_parsing *sec_parse;
+
+ if (WARN_ON(!pieces || !data || type >= IWL_UCODE_TYPE_MAX))
+ return -1;
+
+ sec_parse = (struct fw_sec_parsing *)data;
+
+ img = &pieces->img[type];
+ sec = &img->sec[img->sec_counter];
+
+ sec->offset = le32_to_cpu(sec_parse->offset);
+ sec->data = sec_parse->data;
+
+ ++img->sec_counter;
+
+ return 0;
+}
+
+static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data)
+{
+ struct iwl_tlv_calib_data *def_calib =
+ (struct iwl_tlv_calib_data *)data;
+ u32 ucode_type = le32_to_cpu(def_calib->ucode_type);
+ if (ucode_type >= IWL_UCODE_TYPE_MAX) {
+ IWL_ERR(drv, "Wrong ucode_type %u for default calibration.\n",
+ ucode_type);
+ return -EINVAL;
+ }
+ drv->fw.default_calib[ucode_type] = le64_to_cpu(def_calib->calib);
+ return 0;
+}
+
static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
const struct firmware *ucode_raw,
struct iwl_firmware_pieces *pieces)
@@ -586,6 +646,29 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
capa->standard_phy_calibration_size =
le32_to_cpup((__le32 *)tlv_data);
break;
+ case IWL_UCODE_TLV_SEC_RT:
+ iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
+ tlv_len);
+ break;
+ case IWL_UCODE_TLV_SEC_INIT:
+ iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
+ tlv_len);
+ break;
+ case IWL_UCODE_TLV_SEC_WOWLAN:
+ iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
+ tlv_len);
+ break;
+ case IWL_UCODE_TLV_DEF_CALIB:
+ if (tlv_len != sizeof(struct iwl_tlv_calib_data))
+ goto invalid_tlv_len;
+ if (iwl_set_default_calib(drv, tlv_data))
+ goto tlv_error;
+ break;
+ case IWL_UCODE_TLV_PHY_SKU:
+ if (tlv_len != sizeof(u32))
+ goto invalid_tlv_len;
+ drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data);
+ break;
default:
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
break;
@@ -602,6 +685,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
invalid_tlv_len:
IWL_ERR(drv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len);
+ tlv_error:
iwl_print_hex_dump(drv, IWL_DL_FW, tlv_data, tlv_len);
return -EINVAL;
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 7ca6c95..c924ccb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -124,6 +124,11 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_WOWLAN_INST = 16,
IWL_UCODE_TLV_WOWLAN_DATA = 17,
IWL_UCODE_TLV_FLAGS = 18,
+ IWL_UCODE_TLV_SEC_RT = 19,
+ IWL_UCODE_TLV_SEC_INIT = 20,
+ IWL_UCODE_TLV_SEC_WOWLAN = 21,
+ IWL_UCODE_TLV_DEF_CALIB = 22,
+ IWL_UCODE_TLV_PHY_SKU = 23,
};
struct iwl_ucode_tlv {
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 253f7e5..c99a7fd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -85,6 +85,22 @@ enum iwl_ucode_tlv_flag {
#define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19
#define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253
+/**
+ * enum iwl_ucode_type
+ *
+ * The type of ucode.
+ *
+ * @IWL_UCODE_REGULAR: Normal runtime ucode
+ * @IWL_UCODE_INIT: Initial ucode
+ * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode
+ */
+enum iwl_ucode_type {
+ IWL_UCODE_REGULAR,
+ IWL_UCODE_INIT,
+ IWL_UCODE_WOWLAN,
+ IWL_UCODE_TYPE_MAX,
+};
+
struct iwl_ucode_capabilities {
u32 max_probe_length;
u32 standard_phy_calibration_size;
@@ -142,6 +158,9 @@ struct iwl_fw {
u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
+
+ u64 default_calib[IWL_UCODE_TYPE_MAX];
+ u32 phy_config;
};
#endif /* __iwl_fw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h
index d899c5c..b515d65 100644
--- a/drivers/net/wireless/iwlwifi/iwl-shared.h
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -192,22 +192,6 @@ struct iwl_hw_params {
const struct iwl_sensitivity_ranges *sens;
};
-/**
- * enum iwl_ucode_type
- *
- * The type of ucode.
- *
- * @IWL_UCODE_REGULAR: Normal runtime ucode
- * @IWL_UCODE_INIT: Initial ucode
- * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode
- */
-enum iwl_ucode_type {
- IWL_UCODE_REGULAR,
- IWL_UCODE_INIT,
- IWL_UCODE_WOWLAN,
- IWL_UCODE_TYPE_MAX,
-};
-
/*
* LED mode
* IWL_LED_DEFAULT: use device default
--
1.7.0.4
From: David Spinadel <[email protected]>
Change iwl_fw struct to hold an array of fw_img instead of
three separated instances.
Change fw_img to hold an array of fw_desc instead of two
separate descriptors for instructions and data.
Change load_given_ucode, load_section, verification functions
etc. to support this structure.
Signed-off-by: David Spinadel <[email protected]>
Signed-off-by: Wey-Yi Guy <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 17 +--
drivers/net/wireless/iwlwifi/iwl-drv.c | 141 +++++++++++++-----------
drivers/net/wireless/iwlwifi/iwl-fw.h | 25 +++--
drivers/net/wireless/iwlwifi/iwl-mac80211.c | 15 ++-
drivers/net/wireless/iwlwifi/iwl-testmode.c | 21 +---
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 32 +++---
drivers/net/wireless/iwlwifi/iwl-ucode.c | 29 ++---
7 files changed, 139 insertions(+), 141 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 89cb9a7..b7b1c04 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -230,6 +230,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
int pos = 0;
int sram;
struct iwl_priv *priv = file->private_data;
+ const struct fw_img *img;
size_t bufsz;
/* default is to dump the entire data segment */
@@ -239,17 +240,8 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
IWL_ERR(priv, "No uCode has been loadded.\n");
return -EINVAL;
}
- if (priv->shrd->ucode_type == IWL_UCODE_INIT) {
- priv->dbgfs_sram_len = priv->fw->ucode_init.data.len;
- } else if (priv->shrd->ucode_type == IWL_UCODE_REGULAR) {
- priv->dbgfs_sram_len = priv->fw->ucode_rt.data.len;
- } else if (priv->shrd->ucode_type == IWL_UCODE_WOWLAN) {
- priv->dbgfs_sram_len = priv->fw->ucode_wowlan.data.len;
- } else {
- IWL_ERR(priv, "Unsupported type of uCode loaded?"
- " that shouldn't happen.\n");
- return -EINVAL;
- }
+ img = &priv->fw->img[priv->shrd->ucode_type];
+ priv->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
}
len = priv->dbgfs_sram_len;
@@ -346,13 +338,14 @@ static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = file->private_data;
+ const struct fw_img *img = &priv->fw->img[IWL_UCODE_WOWLAN];
if (!priv->wowlan_sram)
return -ENODATA;
return simple_read_from_buffer(user_buf, count, ppos,
priv->wowlan_sram,
- priv->fw->ucode_wowlan.data.len);
+ img->sec[IWL_UCODE_SECTION_DATA].len);
}
static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index 19ccd36..54e0969 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -118,15 +118,16 @@ static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc)
static void iwl_free_fw_img(struct iwl_drv *drv, struct fw_img *img)
{
- iwl_free_fw_desc(drv, &img->code);
- iwl_free_fw_desc(drv, &img->data);
+ int i;
+ for (i = 0; i < IWL_UCODE_SECTION_MAX; i++)
+ iwl_free_fw_desc(drv, &img->sec[i]);
}
static void iwl_dealloc_ucode(struct iwl_drv *drv)
{
- iwl_free_fw_img(drv, &drv->fw.ucode_rt);
- iwl_free_fw_img(drv, &drv->fw.ucode_init);
- iwl_free_fw_img(drv, &drv->fw.ucode_wowlan);
+ int i;
+ for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
+ iwl_free_fw_img(drv, drv->fw.img + i);
}
static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc,
@@ -189,22 +190,8 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
GFP_KERNEL, drv, iwl_ucode_callback);
}
-/*
- * enumeration of ucode section.
- * This enumeration is used for legacy tlv style (before 16.0 uCode).
- */
-enum iwl_ucode_sec {
- IWL_UCODE_SECTION_INST,
- IWL_UCODE_SECTION_DATA,
-};
-/*
- * For 16.0 uCode and above, there is no differentiation between section,
- * just an offset to the HW address.
- */
-#define UCODE_SECTION_MAX 4
-
struct fw_img_parsing {
- struct fw_sec sec[UCODE_SECTION_MAX];
+ struct fw_sec sec[IWL_UCODE_SECTION_MAX];
int sec_counter;
};
@@ -691,6 +678,71 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
return -EINVAL;
}
+static int alloc_pci_desc(struct iwl_drv *drv,
+ struct iwl_firmware_pieces *pieces,
+ enum iwl_ucode_type type)
+{
+ int i;
+ for (i = 0;
+ i < IWL_UCODE_SECTION_MAX && get_sec_size(pieces, type, i);
+ i++)
+ if (iwl_alloc_fw_desc(drv, &(drv->fw.img[type].sec[i]),
+ get_sec(pieces, type, i)))
+ return -1;
+ return 0;
+}
+
+static int validate_sec_sizes(struct iwl_drv *drv,
+ struct iwl_firmware_pieces *pieces,
+ const struct iwl_cfg *cfg)
+{
+ 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));
+
+ /* 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) {
+ IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n",
+ get_sec_size(pieces, IWL_UCODE_REGULAR,
+ IWL_UCODE_SECTION_INST));
+ return -1;
+ }
+
+ 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));
+ return -1;
+ }
+
+ 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));
+ return -1;
+ }
+
+ if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA) >
+ 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));
+ return -1;
+ }
+ return 0;
+}
+
+
/**
* iwl_ucode_callback - callback when firmware was loaded
*
@@ -709,6 +761,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
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 =
@@ -817,59 +870,17 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
goto try_again;
}
- 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));
+ if (validate_sec_sizes(drv, &pieces, cfg))
goto try_again;
- }
-
- if (get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA) >
- 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));
- 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(drv, &drv->fw.ucode_rt.code,
- get_sec(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST)))
- goto err_pci_alloc;
- if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_rt.data,
- get_sec(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA)))
- goto err_pci_alloc;
-
- /* Initialization instructions and data */
- if (get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) &&
- get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA)) {
- if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_init.code,
- get_sec(&pieces, IWL_UCODE_INIT,
- IWL_UCODE_SECTION_INST)))
- goto err_pci_alloc;
- if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_init.data,
- get_sec(&pieces, IWL_UCODE_INIT,
- IWL_UCODE_SECTION_DATA)))
+ for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
+ if (alloc_pci_desc(drv, &pieces, i))
goto err_pci_alloc;
- }
-
- /* WoWLAN instructions and data */
- if (get_sec_size(&pieces, IWL_UCODE_WOWLAN, IWL_UCODE_SECTION_INST) &&
- get_sec_size(&pieces, IWL_UCODE_WOWLAN, IWL_UCODE_SECTION_DATA)) {
- if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_wowlan.code,
- get_sec(&pieces, IWL_UCODE_WOWLAN,
- IWL_UCODE_SECTION_INST)))
- goto err_pci_alloc;
- if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_wowlan.data,
- get_sec(&pieces, IWL_UCODE_WOWLAN,
- IWL_UCODE_SECTION_DATA)))
- goto err_pci_alloc;
- }
/* Now that we can no longer fail, copy information */
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index c99a7fd..5d634f3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -101,6 +101,20 @@ enum iwl_ucode_type {
IWL_UCODE_TYPE_MAX,
};
+/*
+ * enumeration of ucode section.
+ * This enumeration is used for legacy tlv style (before 16.0 uCode).
+ */
+enum iwl_ucode_sec {
+ IWL_UCODE_SECTION_INST,
+ IWL_UCODE_SECTION_DATA,
+};
+/*
+ * For 16.0 uCode and above, there is no differentiation between sections,
+ * just an offset to the HW address.
+ */
+#define IWL_UCODE_SECTION_MAX 4
+
struct iwl_ucode_capabilities {
u32 max_probe_length;
u32 standard_phy_calibration_size;
@@ -116,8 +130,7 @@ struct fw_desc {
};
struct fw_img {
- struct fw_desc code; /* firmware code image */
- struct fw_desc data; /* firmware data image */
+ struct fw_desc sec[IWL_UCODE_SECTION_MAX];
};
/* uCode version contains 4 values: Major/Minor/API/Serial */
@@ -131,9 +144,7 @@ struct fw_img {
*
* @ucode_ver: ucode version from the ucode file
* @fw_version: firmware version string
- * @ucode_rt: run time ucode image
- * @ucode_init: init ucode image
- * @ucode_wowlan: wake on wireless ucode image (optional)
+ * @img: ucode image like ucode_rt, ucode_init, ucode_wowlan.
* @ucode_capa: capabilities parsed from the ucode file.
* @enhance_sensitivity_table: device can do enhanced sensitivity.
* @init_evtlog_ptr: event log offset for init ucode.
@@ -149,9 +160,7 @@ struct iwl_fw {
char fw_version[ETHTOOL_BUSINFO_LEN];
/* ucode images */
- struct fw_img ucode_rt;
- struct fw_img ucode_init;
- struct fw_img ucode_wowlan;
+ struct fw_img img[IWL_UCODE_TYPE_MAX];
struct iwl_ucode_capabilities ucode_capa;
bool enhance_sensitivity_table;
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
index 9212ee3..b6805f8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c
+++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
@@ -196,7 +196,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
- if (priv->fw->ucode_wowlan.code.len &&
+ if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
trans(priv)->ops->wowlan_suspend &&
device_can_wakeup(trans(priv)->dev)) {
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
@@ -437,6 +437,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
unsigned long flags;
u32 base, status = 0xffffffff;
int ret = -EIO;
+ const struct fw_img *img;
IWL_DEBUG_MAC80211(priv, "enter\n");
mutex_lock(&priv->mutex);
@@ -457,16 +458,18 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (ret == 0) {
- if (!priv->wowlan_sram)
+ img = &(priv->fw->img[IWL_UCODE_WOWLAN]);
+ if (!priv->wowlan_sram) {
priv->wowlan_sram =
- kzalloc(priv->fw->ucode_wowlan.data.len,
+ kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
GFP_KERNEL);
+ }
if (priv->wowlan_sram)
_iwl_read_targ_mem_words(
- trans(priv), 0x800000,
- priv->wowlan_sram,
- priv->fw->ucode_wowlan.data.len / 4);
+ trans(priv), 0x800000,
+ priv->wowlan_sram,
+ img->sec[IWL_UCODE_SECTION_DATA].len / 4);
}
#endif
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c
index c6c084f..76f7f92 100644
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c
@@ -466,6 +466,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
unsigned char *rsp_data_ptr = NULL;
int status = 0, rsp_data_len = 0;
u32 devid, inst_size = 0, data_size = 0;
+ const struct fw_img *img;
switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
@@ -597,23 +598,9 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
IWL_ERR(priv, "No uCode has not been loaded\n");
return -EINVAL;
} else {
- switch (priv->shrd->ucode_type) {
- case IWL_UCODE_REGULAR:
- inst_size = priv->fw->ucode_rt.code.len;
- data_size = priv->fw->ucode_rt.data.len;
- break;
- case IWL_UCODE_INIT:
- inst_size = priv->fw->ucode_init.code.len;
- data_size = priv->fw->ucode_init.data.len;
- break;
- case IWL_UCODE_WOWLAN:
- inst_size = priv->fw->ucode_wowlan.code.len;
- data_size = priv->fw->ucode_wowlan.data.len;
- break;
- default:
- IWL_ERR(priv, "Unsupported uCode type\n");
- break;
- }
+ img = &priv->fw->img[priv->shrd->ucode_type];
+ inst_size = img->sec[IWL_UCODE_SECTION_INST].len;
+ data_size = img->sec[IWL_UCODE_SECTION_DATA].len;
}
NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type);
NLA_PUT_U32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size);
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index 0e8e31a..b4f796c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -951,12 +951,13 @@ static const u8 iwlagn_pan_ac_to_queue[] = {
/*
* ucode
*/
-static int iwl_load_section(struct iwl_trans *trans, const char *name,
- const struct fw_desc *image, u32 dst_addr)
+static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
+ const struct fw_desc *section)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- dma_addr_t phy_addr = image->p_addr;
- u32 byte_cnt = image->len;
+ dma_addr_t phy_addr = section->p_addr;
+ u32 byte_cnt = section->len;
+ u32 dst_addr = section->offset;
int ret;
trans_pcie->ucode_write_complete = false;
@@ -989,12 +990,13 @@ static int iwl_load_section(struct iwl_trans *trans, const char *name,
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
- IWL_DEBUG_FW(trans, "%s uCode section being loaded...\n", name);
+ IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
+ section_num);
ret = wait_event_timeout(trans_pcie->ucode_write_waitq,
trans_pcie->ucode_write_complete, 5 * HZ);
if (!ret) {
- IWL_ERR(trans, "Could not load the %s uCode section\n",
- name);
+ IWL_ERR(trans, "Could not load the [%d] uCode section\n",
+ section_num);
return -ETIMEDOUT;
}
@@ -1005,16 +1007,16 @@ static int iwl_load_given_ucode(struct iwl_trans *trans,
const struct fw_img *image)
{
int ret = 0;
+ int i;
- ret = iwl_load_section(trans, "INST", &image->code,
- IWLAGN_RTC_INST_LOWER_BOUND);
- if (ret)
- return ret;
+ for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) {
+ if (!image->sec[i].p_addr)
+ break;
- ret = iwl_load_section(trans, "DATA", &image->data,
- IWLAGN_RTC_DATA_LOWER_BOUND);
- if (ret)
- return ret;
+ ret = iwl_load_section(trans, i, &image->sec[i]);
+ if (ret)
+ return ret;
+ }
/* Remove all resets to allow NIC to operate */
iwl_write32(trans, CSR_RESET, 0);
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c
index 0908880..2528287 100644
--- a/drivers/net/wireless/iwlwifi/iwl-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c
@@ -80,17 +80,10 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
static inline const struct fw_img *
iwl_get_ucode_image(struct iwl_priv *priv, enum iwl_ucode_type ucode_type)
{
- switch (ucode_type) {
- case IWL_UCODE_INIT:
- return &priv->fw->ucode_init;
- case IWL_UCODE_WOWLAN:
- return &priv->fw->ucode_wowlan;
- case IWL_UCODE_REGULAR:
- return &priv->fw->ucode_rt;
- default:
- break;
- }
- return NULL;
+ if (ucode_type >= IWL_UCODE_TYPE_MAX)
+ return NULL;
+
+ return &priv->fw->img[ucode_type];
}
/*
@@ -342,7 +335,7 @@ static int iwl_alive_notify(struct iwl_priv *priv)
* using sample data 100 bytes apart. If these sample points are good,
* it's a pretty good bet that everything between them is good, too.
*/
-static int iwl_verify_inst_sparse(struct iwl_priv *priv,
+static int iwl_verify_sec_sparse(struct iwl_priv *priv,
const struct fw_desc *fw_desc)
{
__le32 *image = (__le32 *)fw_desc->v_addr;
@@ -357,7 +350,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv,
/* NOTE: Use the debugless read so we don't flood kernel log
* if IWL_DL_IO is set */
iwl_write_direct32(trans(priv), HBUS_TARG_MEM_RADDR,
- i + IWLAGN_RTC_INST_LOWER_BOUND);
+ i + fw_desc->offset);
val = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
if (val != le32_to_cpu(*image))
return -EIO;
@@ -366,7 +359,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv,
return 0;
}
-static void iwl_print_mismatch_inst(struct iwl_priv *priv,
+static void iwl_print_mismatch_sec(struct iwl_priv *priv,
const struct fw_desc *fw_desc)
{
__le32 *image = (__le32 *)fw_desc->v_addr;
@@ -378,7 +371,7 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
iwl_write_direct32(trans(priv), HBUS_TARG_MEM_RADDR,
- IWLAGN_RTC_INST_LOWER_BOUND);
+ fw_desc->offset);
for (offs = 0;
offs < len && errors < 20;
@@ -408,14 +401,14 @@ static int iwl_verify_ucode(struct iwl_priv *priv,
return -EINVAL;
}
- if (!iwl_verify_inst_sparse(priv, &img->code)) {
+ if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) {
IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
return 0;
}
IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
- iwl_print_mismatch_inst(priv, &img->code);
+ iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]);
return -EIO;
}
@@ -534,7 +527,7 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
lockdep_assert_held(&priv->mutex);
/* No init ucode required? Curious, but maybe ok */
- if (!priv->fw->ucode_init.code.len)
+ if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len)
return 0;
if (priv->init_ucode_run)
--
1.7.0.4
From: David Spinadel <[email protected]>
Printing the SRAM and similar testmode operations could
be triggered when no uCode is loaded; prevent those
invalid operations by tracking whether uCode is loaded.
Signed-off-by: David Spinadel <[email protected]>
Signed-off-by: Wey-Yi Guy <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 1 +
drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +
drivers/net/wireless/iwlwifi/iwl-core.c | 3 ++
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 15 +++++++++-
drivers/net/wireless/iwlwifi/iwl-dev.h | 1 +
drivers/net/wireless/iwlwifi/iwl-testmode.c | 40 +++++++++++++++------------
drivers/net/wireless/iwlwifi/iwl-ucode.c | 6 ++++
7 files changed, 48 insertions(+), 20 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 915183a..3e1698d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -1189,6 +1189,7 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
memcpy(&rxon, &ctx->active, sizeof(rxon));
+ priv->ucode_loaded = false;
iwl_trans_stop_device(trans(priv));
priv->wowlan = true;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 66d7446..f1226db 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -816,6 +816,7 @@ void iwl_down(struct iwl_priv *priv)
if (priv->mac80211_registered)
ieee80211_stop_queues(priv->hw);
+ priv->ucode_loaded = false;
iwl_trans_stop_device(trans(priv));
/* Clear out all status bits but a few that are stable across reset */
@@ -1406,6 +1407,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
iwl_tt_exit(priv);
/*This will stop the queues, move the device to low power state */
+ priv->ucode_loaded = false;
iwl_trans_stop_device(trans(priv));
iwl_eeprom_free(priv->shrd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index e3eda50..46490d3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -838,6 +838,9 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
#endif
+ /* uCode is no longer loaded. */
+ priv->ucode_loaded = false;
+
/* Set the FW error flag -- cleared on iwl_down */
set_bit(STATUS_FW_ERROR, &priv->shrd->status);
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 9b71c87..89cb9a7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -235,10 +235,21 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
/* default is to dump the entire data segment */
if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
priv->dbgfs_sram_offset = 0x800000;
- if (priv->shrd->ucode_type == IWL_UCODE_INIT)
+ if (!priv->ucode_loaded) {
+ IWL_ERR(priv, "No uCode has been loadded.\n");
+ return -EINVAL;
+ }
+ if (priv->shrd->ucode_type == IWL_UCODE_INIT) {
priv->dbgfs_sram_len = priv->fw->ucode_init.data.len;
- else
+ } else if (priv->shrd->ucode_type == IWL_UCODE_REGULAR) {
priv->dbgfs_sram_len = priv->fw->ucode_rt.data.len;
+ } else if (priv->shrd->ucode_type == IWL_UCODE_WOWLAN) {
+ priv->dbgfs_sram_len = priv->fw->ucode_wowlan.data.len;
+ } else {
+ IWL_ERR(priv, "Unsupported type of uCode loaded?"
+ " that shouldn't happen.\n");
+ return -EINVAL;
+ }
}
len = priv->dbgfs_sram_len;
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index aa4b3b1..01dbe11 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -769,6 +769,7 @@ struct iwl_priv {
/* firmware reload counter and timestamp */
unsigned long reload_jiffies;
int reload_count;
+ bool ucode_loaded;
/* we allocate array of iwl_channel_info for NIC's valid channels.
* Access via channel # using indirect index array */
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c
index b06c676..c6c084f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c
@@ -494,6 +494,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
iwl_testmode_cfg_init_calib(priv);
+ priv->ucode_loaded = false;
iwl_trans_stop_device(trans);
break;
@@ -512,6 +513,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
iwl_scan_cancel_timeout(priv, 200);
+ priv->ucode_loaded = false;
iwl_trans_stop_device(trans);
status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
if (status) {
@@ -591,25 +593,27 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
IWL_ERR(priv, "Memory allocation fail\n");
return -ENOMEM;
}
- switch (priv->shrd->ucode_type) {
- case IWL_UCODE_REGULAR:
- inst_size = priv->fw->ucode_rt.code.len;
- data_size = priv->fw->ucode_rt.data.len;
- break;
- case IWL_UCODE_INIT:
- inst_size = priv->fw->ucode_init.code.len;
- data_size = priv->fw->ucode_init.data.len;
- break;
- case IWL_UCODE_WOWLAN:
- inst_size = priv->fw->ucode_wowlan.code.len;
- data_size = priv->fw->ucode_wowlan.data.len;
- break;
- case IWL_UCODE_NONE:
+ if (!priv->ucode_loaded) {
IWL_ERR(priv, "No uCode has not been loaded\n");
- break;
- default:
- IWL_ERR(priv, "Unsupported uCode type\n");
- break;
+ return -EINVAL;
+ } else {
+ switch (priv->shrd->ucode_type) {
+ case IWL_UCODE_REGULAR:
+ inst_size = priv->fw->ucode_rt.code.len;
+ data_size = priv->fw->ucode_rt.data.len;
+ break;
+ case IWL_UCODE_INIT:
+ inst_size = priv->fw->ucode_init.code.len;
+ data_size = priv->fw->ucode_init.data.len;
+ break;
+ case IWL_UCODE_WOWLAN:
+ inst_size = priv->fw->ucode_wowlan.code.len;
+ data_size = priv->fw->ucode_wowlan.data.len;
+ break;
+ default:
+ IWL_ERR(priv, "Unsupported uCode type\n");
+ break;
+ }
}
NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type);
NLA_PUT_U32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size);
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c
index d97cf44..ae935c0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c
@@ -465,6 +465,8 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
priv->shrd->ucode_type = ucode_type;
fw = iwl_get_ucode_image(priv, ucode_type);
+ priv->ucode_loaded = false;
+
if (!fw)
return -EINVAL;
@@ -519,6 +521,8 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
return ret;
}
+ priv->ucode_loaded = true;
+
return 0;
}
@@ -563,5 +567,7 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
out:
/* Whatever happened, stop the device */
iwl_trans_stop_device(trans(priv));
+ priv->ucode_loaded = false;
+
return ret;
}
--
1.7.0.4
From: Johannes Berg <[email protected]>
Looking at logs, I see that we did get the bad
state message a few times for some reason, but
it doesn't indicate why or where it came from,
so make it a warning in order to identify it.
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Wey-Yi Guy <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-trans.h | 28 ++++++++++++++--------------
1 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 95f3faf..782cb0d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -497,8 +497,8 @@ static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans)
static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
struct iwl_host_cmd *cmd)
{
- if (trans->state != IWL_TRANS_FW_ALIVE)
- IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+ WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
+ "%s bad state = %d", __func__, trans->state);
return trans->ops->send_cmd(trans, cmd);
}
@@ -517,8 +517,8 @@ static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id,
int tid, int txq_id, int ssn,
struct sk_buff_head *skbs)
{
- if (trans->state != IWL_TRANS_FW_ALIVE)
- IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+ WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
+ "%s bad state = %d", __func__, trans->state);
return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, skbs);
}
@@ -526,8 +526,8 @@ static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id,
static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans,
int sta_id, int tid)
{
- if (trans->state != IWL_TRANS_FW_ALIVE)
- IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+ WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
+ "%s bad state = %d", __func__, trans->state);
return trans->ops->tx_agg_disable(trans, sta_id, tid);
}
@@ -535,8 +535,8 @@ static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans,
static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans,
int sta_id, int tid)
{
- if (trans->state != IWL_TRANS_FW_ALIVE)
- IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+ WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
+ "%s bad state = %d", __func__, trans->state);
return trans->ops->tx_agg_alloc(trans, sta_id, tid);
}
@@ -549,8 +549,8 @@ static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans,
{
might_sleep();
- if (trans->state != IWL_TRANS_FW_ALIVE)
- IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+ WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
+ "%s bad state = %d", __func__, trans->state);
trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn);
}
@@ -562,16 +562,16 @@ static inline void iwl_trans_free(struct iwl_trans *trans)
static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
{
- if (trans->state != IWL_TRANS_FW_ALIVE)
- IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+ WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
+ "%s bad state = %d", __func__, trans->state);
return trans->ops->wait_tx_queue_empty(trans);
}
static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q)
{
- if (trans->state != IWL_TRANS_FW_ALIVE)
- IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
+ WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
+ "%s bad state = %d", __func__, trans->state);
return trans->ops->check_stuck_queue(trans, q);
}
--
1.7.0.4
From: David Spinadel <[email protected]>
mvm_ucode is true when mvm TLVs arive.
Signed-off-by: David Spinadel <[email protected]>
Signed-off-by: Wey-Yi Guy <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-drv.c | 9 ++++++++-
drivers/net/wireless/iwlwifi/iwl-fw.h | 2 ++
2 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index 54e0969..6f312c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -636,14 +636,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
case IWL_UCODE_TLV_SEC_RT:
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
tlv_len);
+ drv->fw.mvm_fw = true;
break;
case IWL_UCODE_TLV_SEC_INIT:
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
tlv_len);
+ drv->fw.mvm_fw = true;
break;
case IWL_UCODE_TLV_SEC_WOWLAN:
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
tlv_len);
+ drv->fw.mvm_fw = true;
break;
case IWL_UCODE_TLV_DEF_CALIB:
if (tlv_len != sizeof(struct iwl_tlv_calib_data))
@@ -870,7 +873,11 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
goto try_again;
}
- if (validate_sec_sizes(drv, &pieces, cfg))
+ /*
+ * In mvm uCode there is no difference between data and instructions
+ * sections.
+ */
+ if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, cfg))
goto try_again;
/* Allocate ucode buffers for card's bus-master loading ... */
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 5d634f3..8e36bdc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -170,6 +170,8 @@ struct iwl_fw {
u64 default_calib[IWL_UCODE_TYPE_MAX];
u32 phy_config;
+
+ bool mvm_fw;
};
#endif /* __iwl_fw_h__ */
--
1.7.0.4
From: David Spinadel <[email protected]>
Remove IWL_UCODE_NONE from enum iwl_ucode_type which,
by being the default value in 0-initialized memory,
implicitly allowed us to track whether any uCode had
ever been loaded successfully (which would have been
the INIT uCode) and instead explicitly track whether
or not INIT uCode has been run.
Signed-off-by: David Spinadel <[email protected]>
Signed-off-by: Wey-Yi Guy <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-dev.h | 1 +
drivers/net/wireless/iwlwifi/iwl-shared.h | 4 +---
drivers/net/wireless/iwlwifi/iwl-ucode.c | 6 ++++--
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 01dbe11..16956b7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -770,6 +770,7 @@ struct iwl_priv {
unsigned long reload_jiffies;
int reload_count;
bool ucode_loaded;
+ bool init_ucode_run; /* Don't run init uCode again */
/* we allocate array of iwl_channel_info for NIC's valid channels.
* Access via channel # using indirect index array */
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h
index 29d2a85..4cd2ece 100644
--- a/drivers/net/wireless/iwlwifi/iwl-shared.h
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -195,15 +195,13 @@ struct iwl_hw_params {
/**
* enum iwl_ucode_type
*
- * The type of ucode currently loaded on the hardware.
+ * The type of ucode.
*
- * @IWL_UCODE_NONE: No ucode loaded
* @IWL_UCODE_REGULAR: Normal runtime ucode
* @IWL_UCODE_INIT: Initial ucode
* @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode
*/
enum iwl_ucode_type {
- IWL_UCODE_NONE,
IWL_UCODE_REGULAR,
IWL_UCODE_INIT,
IWL_UCODE_WOWLAN,
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c
index ae935c0..0908880 100644
--- a/drivers/net/wireless/iwlwifi/iwl-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c
@@ -87,7 +87,7 @@ iwl_get_ucode_image(struct iwl_priv *priv, enum iwl_ucode_type ucode_type)
return &priv->fw->ucode_wowlan;
case IWL_UCODE_REGULAR:
return &priv->fw->ucode_rt;
- case IWL_UCODE_NONE:
+ default:
break;
}
return NULL;
@@ -537,7 +537,7 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
if (!priv->fw->ucode_init.code.len)
return 0;
- if (priv->shrd->ucode_type != IWL_UCODE_NONE)
+ if (priv->init_ucode_run)
return 0;
iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
@@ -559,6 +559,8 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
*/
ret = iwl_wait_notification(&priv->notif_wait, &calib_wait,
UCODE_CALIB_TIMEOUT);
+ if (!ret)
+ priv->init_ucode_run = true;
goto out;
--
1.7.0.4
From: Johannes Berg <[email protected]>
Mohammed Shafi ran into [1] the SEQ_RX_FRAME workaround
warning with a statistics notification, this means we
can't just remove it as we'd hoped.
Abstract it out so that the higher layer can configure
this as a kind of "filter" in the transport.
[1] http://mid.gmane.org/CAD2nsn1_DzbRHuSbS_1rFNzuux_9pW1-pABEasQ01_y7-ndO5w@mail.gmail.com
Reported-by: Mohammed Shafi <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Wey-Yi Guy <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 10 +++++++
drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h | 2 +
drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | 29 ++++++++-------------
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 7 +++++
drivers/net/wireless/iwlwifi/iwl-trans.h | 9 ++++++
5 files changed, 39 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 28422c0..5ef1585 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1186,6 +1186,14 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
u16 num_mac;
u32 ucode_flags;
struct iwl_trans_config trans_cfg;
+ static const u8 no_reclaim_cmds[] = {
+ REPLY_RX_PHY_CMD,
+ REPLY_RX,
+ REPLY_RX_MPDU_CMD,
+ REPLY_COMPRESSED_BA,
+ STATISTICS_NOTIFICATION,
+ REPLY_TX,
+ };
/************************
* 1. Allocating HW data
@@ -1211,6 +1219,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
* to know about.
*/
trans_cfg.op_mode = op_mode;
+ trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
+ trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
ucode_flags = fw->ucode_capa.flags;
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
index 6796559..1c2fe87 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
@@ -291,6 +291,8 @@ struct iwl_trans_pcie {
wait_queue_head_t ucode_write_waitq;
unsigned long status;
u8 cmd_queue;
+ u8 n_no_reclaim_cmds;
+ u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
};
#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
index 9bc3c73..8bec0e1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
@@ -395,13 +395,17 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
* there is no command buffer to reclaim.
* Ucode should set SEQ_RX_FRAME bit if ucode-originated,
* but apparently a few don't get set; catch them here. */
- reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
- (pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
- (pkt->hdr.cmd != REPLY_RX) &&
- (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) &&
- (pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
- (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
- (pkt->hdr.cmd != REPLY_TX);
+ reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME);
+ if (reclaim) {
+ int i;
+
+ for (i = 0; i < trans_pcie->n_no_reclaim_cmds; i++) {
+ if (trans_pcie->no_reclaim_cmds[i] == pkt->hdr.cmd) {
+ reclaim = false;
+ break;
+ }
+ }
+ }
sequence = le16_to_cpu(pkt->hdr.sequence);
index = SEQ_TO_INDEX(sequence);
@@ -412,17 +416,6 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
else
cmd = NULL;
- /* warn if this is cmd response / notification and the uCode
- * didn't set the SEQ_RX_FRAME for a frame that is
- * uCode-originated
- * If you saw this code after the second half of 2012, then
- * please remove it
- */
- WARN(pkt->hdr.cmd != REPLY_TX && reclaim == false &&
- (!(pkt->hdr.sequence & SEQ_RX_FRAME)),
- "reclaim is false, SEQ_RX_FRAME unset: %s\n",
- get_cmd_string(pkt->hdr.cmd));
-
err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index 14b0361..4900dfa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -1626,6 +1626,13 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
trans_pcie->cmd_queue = trans_cfg->cmd_queue;
+ if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS))
+ trans_pcie->n_no_reclaim_cmds = 0;
+ else
+ trans_pcie->n_no_reclaim_cmds = trans_cfg->n_no_reclaim_cmds;
+ if (trans_pcie->n_no_reclaim_cmds)
+ memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds,
+ trans_pcie->n_no_reclaim_cmds * sizeof(u8));
}
static void iwl_trans_pcie_free(struct iwl_trans *trans)
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 7d1990c..95f3faf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -274,6 +274,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
return p;
}
+#define MAX_NO_RECLAIM_CMDS 6
+
/**
* struct iwl_trans_config - transport configuration
*
@@ -281,10 +283,17 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
* Must be set before any other call.
* @cmd_queue: the index of the command queue.
* Must be set before start_fw.
+ * @no_reclaim_cmds: Some devices erroneously don't set the
+ * SEQ_RX_FRAME bit on some notifications, this is the
+ * list of such notifications to filter. Max length is
+ * %MAX_NO_RECLAIM_CMDS.
+ * @n_no_reclaim_cmds: # of commands in list
*/
struct iwl_trans_config {
struct iwl_op_mode *op_mode;
u8 cmd_queue;
+ const u8 *no_reclaim_cmds;
+ int n_no_reclaim_cmds;
};
/**
--
1.7.0.4
From: Johannes Berg <[email protected]>
Tracing is much better for this, so
remove the hex printk debug for the
TX command.
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Wey-Yi Guy <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index 9162856..14b0361 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -1466,8 +1466,6 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
le16_to_cpu(dev_cmd->hdr.sequence));
IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
- iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
- iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
/* Set up entry for this TFD in Tx byte-count array */
iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
--
1.7.0.4
From: Meenakshi Venkataraman <[email protected]>
This wait queue really belongs to the transport
layer, as it is used for sending synchronous
commands to the HW.
However, only op_mode knows about errors and
exceptional conditions, so make this queue
accessible by the op_mode.
Signed-off-by: Meenakshi Venkataraman <[email protected]>
Signed-off-by: Wey-Yi Guy <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn-rx.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-agn.c | 2 --
drivers/net/wireless/iwlwifi/iwl-core.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-shared.h | 3 ---
drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c | 4 ++--
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 3 +++
drivers/net/wireless/iwlwifi/iwl-trans.h | 3 +++
8 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
index cc0227c..44c6f71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -671,7 +671,7 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,
wiphy_rfkill_set_hw_state(priv->hw->wiphy,
test_bit(STATUS_RF_KILL_HW, &priv->status));
else
- wake_up(&priv->shrd->wait_command_queue);
+ wake_up(&trans(priv)->wait_command_queue);
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 5ef1585..66d7446 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -962,8 +962,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
{
priv->workqueue = create_singlethread_workqueue(DRV_NAME);
- init_waitqueue_head(&priv->shrd->wait_command_queue);
-
INIT_WORK(&priv->restart, iwl_bg_restart);
INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 8b85940..e3eda50 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -850,7 +850,7 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
* commands by clearing the ready bit */
clear_bit(STATUS_READY, &priv->status);
- wake_up(&priv->shrd->wait_command_queue);
+ wake_up(&trans(priv)->wait_command_queue);
if (!ondemand) {
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h
index cf34087..29d2a85 100644
--- a/drivers/net/wireless/iwlwifi/iwl-shared.h
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -376,7 +376,6 @@ struct iwl_cfg {
* @nic: pointer to the nic data
* @hw_params: see struct iwl_hw_params
* @lock: protect general shared data
- * @wait_command_queue: the wait_queue for SYNC host commands
* @eeprom: pointer to the eeprom/OTP image
* @ucode_type: indicator of loaded ucode image
* @device_pointers: pointers to ucode event tables
@@ -391,8 +390,6 @@ struct iwl_shared {
struct iwl_hw_params hw_params;
const struct iwl_fw *fw;
- wait_queue_head_t wait_command_queue;
-
/* eeprom -- this is in the card's little endian byte order */
u8 *eeprom;
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
index 8bec0e1..8b1a798 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
@@ -684,7 +684,7 @@ static void iwl_irq_handle_error(struct iwl_trans *trans)
*/
clear_bit(STATUS_READY, &trans->shrd->status);
clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
- wake_up(&trans->shrd->wait_command_queue);
+ wake_up(&trans->wait_command_queue);
IWL_ERR(trans, "RF is used by WiMAX\n");
return;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
index 565c664..a66ad9b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
@@ -928,7 +928,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
get_cmd_string(cmd->hdr.cmd));
- wake_up(&trans->shrd->wait_command_queue);
+ wake_up(&trans->wait_command_queue);
}
meta->flags = 0;
@@ -992,7 +992,7 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
return ret;
}
- ret = wait_event_timeout(trans->shrd->wait_command_queue,
+ ret = wait_event_timeout(trans->wait_command_queue,
!test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status),
HOST_COMPLETE_TIMEOUT);
if (!ret) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index 4900dfa..0e8e31a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -2327,6 +2327,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd,
pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
}
+ /* Initialize the wait queue for commands */
+ init_waitqueue_head(&trans->wait_command_queue);
+
return trans;
out_pci_release_regions:
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 782cb0d..0c81cba 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -413,6 +413,7 @@ enum iwl_trans_state {
* @hw_id_str: a string with info about HW ID. Set during transport allocation.
* @nvm_device_type: indicates OTP or eeprom
* @pm_support: set to true in start_hw if link pm is supported
+ * @wait_command_queue: the wait_queue for SYNC host commands
*/
struct iwl_trans {
const struct iwl_trans_ops *ops;
@@ -429,6 +430,8 @@ struct iwl_trans {
int nvm_device_type;
bool pm_support;
+ wait_queue_head_t wait_command_queue;
+
/* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */
char trans_specific[0] __aligned(sizeof(void *));
--
1.7.0.4