summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/iwl-drv.c')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.c110
1 files changed, 92 insertions, 18 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 4b224d7d967c..9c4a7f648a44 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -296,7 +296,12 @@ struct iwl_firmware_pieces {
u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
/* FW debug data parsed for driver usage */
- struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
+ bool dbg_dest_tlv_init;
+ u8 *dbg_dest_ver;
+ union {
+ struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
+ struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv_v1;
+ };
struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
@@ -919,27 +924,60 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
minor = le32_to_cpup(ptr++);
local_comp = le32_to_cpup(ptr);
- snprintf(drv->fw.fw_version,
- sizeof(drv->fw.fw_version), "%u.%u.%u",
- major, minor, local_comp);
+ if (major >= 35)
+ snprintf(drv->fw.fw_version,
+ sizeof(drv->fw.fw_version),
+ "%u.%08x.%u", major, minor, local_comp);
+ else
+ snprintf(drv->fw.fw_version,
+ sizeof(drv->fw.fw_version),
+ "%u.%u.%u", major, minor, local_comp);
break;
}
case IWL_UCODE_TLV_FW_DBG_DEST: {
- struct iwl_fw_dbg_dest_tlv *dest = (void *)tlv_data;
+ struct iwl_fw_dbg_dest_tlv *dest = NULL;
+ struct iwl_fw_dbg_dest_tlv_v1 *dest_v1 = NULL;
+ u8 mon_mode;
+
+ pieces->dbg_dest_ver = (u8 *)tlv_data;
+ if (*pieces->dbg_dest_ver == 1) {
+ dest = (void *)tlv_data;
+ } else if (*pieces->dbg_dest_ver == 0) {
+ dest_v1 = (void *)tlv_data;
+ } else {
+ IWL_ERR(drv,
+ "The version is %d, and it is invalid\n",
+ *pieces->dbg_dest_ver);
+ break;
+ }
- if (pieces->dbg_dest_tlv) {
+ if (pieces->dbg_dest_tlv_init) {
IWL_ERR(drv,
"dbg destination ignored, already exists\n");
break;
}
- pieces->dbg_dest_tlv = dest;
+ pieces->dbg_dest_tlv_init = true;
+
+ if (dest_v1) {
+ pieces->dbg_dest_tlv_v1 = dest_v1;
+ mon_mode = dest_v1->monitor_mode;
+ } else {
+ pieces->dbg_dest_tlv = dest;
+ mon_mode = dest->monitor_mode;
+ }
+
IWL_INFO(drv, "Found debug destination: %s\n",
- get_fw_dbg_mode_string(dest->monitor_mode));
+ get_fw_dbg_mode_string(mon_mode));
+
+ drv->fw.dbg_dest_reg_num = (dest_v1) ?
+ tlv_len -
+ offsetof(struct iwl_fw_dbg_dest_tlv_v1,
+ reg_ops) :
+ tlv_len -
+ offsetof(struct iwl_fw_dbg_dest_tlv,
+ reg_ops);
- drv->fw.dbg_dest_reg_num =
- tlv_len - offsetof(struct iwl_fw_dbg_dest_tlv,
- reg_ops);
drv->fw.dbg_dest_reg_num /=
sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]);
@@ -948,7 +986,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
case IWL_UCODE_TLV_FW_DBG_CONF: {
struct iwl_fw_dbg_conf_tlv *conf = (void *)tlv_data;
- if (!pieces->dbg_dest_tlv) {
+ if (!pieces->dbg_dest_tlv_init) {
IWL_ERR(drv,
"Ignore dbg config %d - no destination configured\n",
conf->id);
@@ -1335,15 +1373,51 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
if (iwl_alloc_ucode(drv, pieces, i))
goto out_free_fw;
- if (pieces->dbg_dest_tlv) {
- drv->fw.dbg_dest_tlv =
- kmemdup(pieces->dbg_dest_tlv,
- sizeof(*pieces->dbg_dest_tlv) +
- sizeof(pieces->dbg_dest_tlv->reg_ops[0]) *
- drv->fw.dbg_dest_reg_num, GFP_KERNEL);
+ if (pieces->dbg_dest_tlv_init) {
+ size_t dbg_dest_size = sizeof(*drv->fw.dbg_dest_tlv) +
+ sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
+ drv->fw.dbg_dest_reg_num;
+
+ drv->fw.dbg_dest_tlv = kmalloc(dbg_dest_size, GFP_KERNEL);
if (!drv->fw.dbg_dest_tlv)
goto out_free_fw;
+
+ if (*pieces->dbg_dest_ver == 0) {
+ memcpy(drv->fw.dbg_dest_tlv, pieces->dbg_dest_tlv_v1,
+ dbg_dest_size);
+ } else {
+ struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv =
+ drv->fw.dbg_dest_tlv;
+
+ dest_tlv->version = pieces->dbg_dest_tlv->version;
+ dest_tlv->monitor_mode =
+ pieces->dbg_dest_tlv->monitor_mode;
+ dest_tlv->size_power =
+ pieces->dbg_dest_tlv->size_power;
+ dest_tlv->wrap_count =
+ pieces->dbg_dest_tlv->wrap_count;
+ dest_tlv->write_ptr_reg =
+ pieces->dbg_dest_tlv->write_ptr_reg;
+ dest_tlv->base_shift =
+ pieces->dbg_dest_tlv->base_shift;
+ memcpy(dest_tlv->reg_ops,
+ pieces->dbg_dest_tlv->reg_ops,
+ sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
+ drv->fw.dbg_dest_reg_num);
+
+ /* In version 1 of the destination tlv, which is
+ * relevant for internal buffer exclusively,
+ * the base address is part of given with the length
+ * of the buffer, and the size shift is give instead of
+ * end shift. We now store these values in base_reg,
+ * and end shift, and when dumping the data we'll
+ * manipulate it for extracting both the length and
+ * base address */
+ dest_tlv->base_reg = pieces->dbg_dest_tlv->cfg_reg;
+ dest_tlv->end_shift =
+ pieces->dbg_dest_tlv->size_shift;
+ }
}
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) {