Skip to content

Commit a6017b9

Browse files
golanIntelegrumbach
authored andcommitted
iwlwifi: store fw memory segments length and addresses in run-time
Currently reading the fw memory segments is done according to addresses and data length that are hard-coded. Lately a new tlv was appended to the ucode, that contains the data type, length and address. Parse this tlv, and in run-time store the memory segments length and addresses that would be dumped upon a fw error. Signed-off-by: Golan Ben-Ami <[email protected]> Signed-off-by: Emmanuel Grumbach <[email protected]>
1 parent 8d80717 commit a6017b9

File tree

4 files changed

+125
-15
lines changed

4 files changed

+125
-15
lines changed

drivers/net/wireless/intel/iwlwifi/iwl-drv.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
179179
kfree(drv->fw.dbg_conf_tlv[i]);
180180
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++)
181181
kfree(drv->fw.dbg_trigger_tlv[i]);
182+
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_mem_tlv); i++)
183+
kfree(drv->fw.dbg_mem_tlv[i]);
182184

183185
for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
184186
iwl_free_fw_img(drv, drv->fw.img + i);
@@ -297,6 +299,7 @@ struct iwl_firmware_pieces {
297299
size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
298300
struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
299301
size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
302+
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv[FW_DBG_MEM_MAX];
300303
};
301304

302305
/*
@@ -1041,6 +1044,37 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
10411044
iwl_store_gscan_capa(&drv->fw, tlv_data, tlv_len);
10421045
gscan_capa = true;
10431046
break;
1047+
case IWL_UCODE_TLV_FW_MEM_SEG: {
1048+
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem =
1049+
(void *)tlv_data;
1050+
u32 type;
1051+
1052+
if (tlv_len != (sizeof(*dbg_mem)))
1053+
goto invalid_tlv_len;
1054+
1055+
type = le32_to_cpu(dbg_mem->data_type);
1056+
drv->fw.dbg_dynamic_mem = true;
1057+
1058+
if (type >= ARRAY_SIZE(drv->fw.dbg_mem_tlv)) {
1059+
IWL_ERR(drv,
1060+
"Skip unknown dbg mem segment: %u\n",
1061+
dbg_mem->data_type);
1062+
break;
1063+
}
1064+
1065+
if (pieces->dbg_mem_tlv[type]) {
1066+
IWL_ERR(drv,
1067+
"Ignore duplicate mem segment: %u\n",
1068+
dbg_mem->data_type);
1069+
break;
1070+
}
1071+
1072+
IWL_DEBUG_INFO(drv, "Found debug memory segment: %u\n",
1073+
dbg_mem->data_type);
1074+
1075+
pieces->dbg_mem_tlv[type] = dbg_mem;
1076+
break;
1077+
}
10441078
default:
10451079
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
10461080
break;
@@ -1350,6 +1384,17 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
13501384
}
13511385
}
13521386

1387+
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_mem_tlv); i++) {
1388+
if (pieces->dbg_mem_tlv[i]) {
1389+
drv->fw.dbg_mem_tlv[i] =
1390+
kmemdup(pieces->dbg_mem_tlv[i],
1391+
sizeof(*drv->fw.dbg_mem_tlv[i]),
1392+
GFP_KERNEL);
1393+
if (!drv->fw.dbg_mem_tlv[i])
1394+
goto out_free_fw;
1395+
}
1396+
}
1397+
13531398
/* Now that we can no longer fail, copy information */
13541399

13551400
/*

drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ enum iwl_ucode_tlv_type {
142142
IWL_UCODE_TLV_FW_DBG_CONF = 39,
143143
IWL_UCODE_TLV_FW_DBG_TRIGGER = 40,
144144
IWL_UCODE_TLV_FW_GSCAN_CAPA = 50,
145+
IWL_UCODE_TLV_FW_MEM_SEG = 51,
145146
};
146147

147148
struct iwl_ucode_tlv {
@@ -491,6 +492,37 @@ enum iwl_fw_dbg_monitor_mode {
491492
MIPI_MODE = 3,
492493
};
493494

495+
/**
496+
* enum iwl_fw_mem_seg_type - data types for dumping on error
497+
*
498+
* @FW_DBG_MEM_SMEM: the data type is SMEM
499+
* @FW_DBG_MEM_DCCM_LMAC: the data type is DCCM_LMAC
500+
* @FW_DBG_MEM_DCCM_UMAC: the data type is DCCM_UMAC
501+
*/
502+
enum iwl_fw_dbg_mem_seg_type {
503+
FW_DBG_MEM_DCCM_LMAC = 0,
504+
FW_DBG_MEM_DCCM_UMAC,
505+
FW_DBG_MEM_SMEM,
506+
507+
/* Must be last */
508+
FW_DBG_MEM_MAX,
509+
};
510+
511+
/**
512+
* struct iwl_fw_dbg_mem_seg_tlv - configures the debug data memory segments
513+
*
514+
* @data_type: enum %iwl_fw_mem_seg_type
515+
* @ofs: the memory segment offset
516+
* @len: the memory segment length, in bytes
517+
*
518+
* This parses IWL_UCODE_TLV_FW_MEM_SEG
519+
*/
520+
struct iwl_fw_dbg_mem_seg_tlv {
521+
__le32 data_type;
522+
__le32 ofs;
523+
__le32 len;
524+
} __packed;
525+
494526
/**
495527
* struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data
496528
*

drivers/net/wireless/intel/iwlwifi/iwl-fw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ struct iwl_fw {
286286
struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
287287
size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
288288
struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
289+
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv[FW_DBG_MEM_MAX];
290+
bool dbg_dynamic_mem;
289291
size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
290292
u8 dbg_dest_reg_num;
291293
struct iwl_gscan_capabilities gscan_capa;

drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -488,9 +488,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
488488
struct iwl_fw_error_dump_trigger_desc *dump_trig;
489489
struct iwl_mvm_dump_ptrs *fw_error_dump;
490490
u32 sram_len, sram_ofs;
491+
struct iwl_fw_dbg_mem_seg_tlv * const *fw_dbg_mem =
492+
mvm->fw->dbg_mem_tlv;
491493
u32 file_len, fifo_data_len = 0, prph_len = 0, radio_len = 0;
492-
u32 smem_len = mvm->cfg->smem_len;
493-
u32 sram2_len = mvm->cfg->dccm2_len;
494+
u32 smem_len = mvm->fw->dbg_dynamic_mem ? 0 : mvm->cfg->smem_len;
495+
u32 sram2_len = mvm->fw->dbg_dynamic_mem ? 0 : mvm->cfg->dccm2_len;
494496
bool monitor_dump_only = false;
495497
int i;
496498

@@ -586,7 +588,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
586588

587589
file_len = sizeof(*dump_file) +
588590
sizeof(*dump_data) * 2 +
589-
sram_len + sizeof(*dump_mem) +
590591
fifo_data_len +
591592
prph_len +
592593
radio_len +
@@ -600,6 +601,13 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
600601
if (sram2_len)
601602
file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len;
602603

604+
/* Make room for MEM segments */
605+
for (i = 0; i < ARRAY_SIZE(mvm->fw->dbg_mem_tlv); i++) {
606+
if (fw_dbg_mem[i])
607+
file_len += sizeof(*dump_data) + sizeof(*dump_mem) +
608+
le32_to_cpu(fw_dbg_mem[i]->len);
609+
}
610+
603611
/* Make room for fw's virtual image pages, if it exists */
604612
if (mvm->fw->img[mvm->cur_ucode].paging_mem_size)
605613
file_len += mvm->num_of_paging_blk *
@@ -625,6 +633,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
625633
file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
626634
mvm->fw_dump_desc->len;
627635

636+
if (!mvm->fw->dbg_dynamic_mem)
637+
file_len += sram_len + sizeof(*dump_mem);
638+
628639
dump_file = vzalloc(file_len);
629640
if (!dump_file) {
630641
kfree(fw_error_dump);
@@ -674,39 +685,59 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
674685
if (monitor_dump_only)
675686
goto dump_trans_data;
676687

677-
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
678-
dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
679-
dump_mem = (void *)dump_data->data;
680-
dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
681-
dump_mem->offset = cpu_to_le32(sram_ofs);
682-
iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_mem->data,
683-
sram_len);
688+
if (!mvm->fw->dbg_dynamic_mem) {
689+
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
690+
dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
691+
dump_mem = (void *)dump_data->data;
692+
dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
693+
dump_mem->offset = cpu_to_le32(sram_ofs);
694+
iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_mem->data,
695+
sram_len);
696+
dump_data = iwl_fw_error_next_data(dump_data);
697+
}
698+
699+
for (i = 0; i < ARRAY_SIZE(mvm->fw->dbg_mem_tlv); i++) {
700+
if (fw_dbg_mem[i]) {
701+
u32 len = le32_to_cpu(fw_dbg_mem[i]->len);
702+
u32 ofs = le32_to_cpu(fw_dbg_mem[i]->ofs);
703+
704+
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
705+
dump_data->len = cpu_to_le32(len +
706+
sizeof(*dump_mem));
707+
dump_mem = (void *)dump_data->data;
708+
dump_mem->type = fw_dbg_mem[i]->data_type;
709+
dump_mem->offset = cpu_to_le32(ofs);
710+
iwl_trans_read_mem_bytes(mvm->trans, ofs,
711+
dump_mem->data,
712+
len);
713+
dump_data = iwl_fw_error_next_data(dump_data);
714+
}
715+
}
684716

685717
if (smem_len) {
686-
dump_data = iwl_fw_error_next_data(dump_data);
687718
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
688719
dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem));
689720
dump_mem = (void *)dump_data->data;
690721
dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM);
691722
dump_mem->offset = cpu_to_le32(mvm->cfg->smem_offset);
692723
iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->smem_offset,
693724
dump_mem->data, smem_len);
725+
dump_data = iwl_fw_error_next_data(dump_data);
694726
}
695727

696728
if (sram2_len) {
697-
dump_data = iwl_fw_error_next_data(dump_data);
698729
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
699730
dump_data->len = cpu_to_le32(sram2_len + sizeof(*dump_mem));
700731
dump_mem = (void *)dump_data->data;
701732
dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
702733
dump_mem->offset = cpu_to_le32(mvm->cfg->dccm2_offset);
703734
iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->dccm2_offset,
704735
dump_mem->data, sram2_len);
736+
dump_data = iwl_fw_error_next_data(dump_data);
705737
}
706738

707739
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
708740
CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP) {
709-
dump_data = iwl_fw_error_next_data(dump_data);
710741
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
711742
dump_data->len = cpu_to_le32(IWL8260_ICCM_LEN +
712743
sizeof(*dump_mem));
@@ -715,6 +746,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
715746
dump_mem->offset = cpu_to_le32(IWL8260_ICCM_OFFSET);
716747
iwl_trans_read_mem_bytes(mvm->trans, IWL8260_ICCM_OFFSET,
717748
dump_mem->data, IWL8260_ICCM_LEN);
749+
dump_data = iwl_fw_error_next_data(dump_data);
718750
}
719751

720752
/* Dump fw's virtual image */
@@ -724,18 +756,17 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
724756
struct page *pages =
725757
mvm->fw_paging_db[i].fw_paging_block;
726758

727-
dump_data = iwl_fw_error_next_data(dump_data);
728759
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING);
729760
dump_data->len = cpu_to_le32(sizeof(*paging) +
730761
PAGING_BLOCK_SIZE);
731762
paging = (void *)dump_data->data;
732763
paging->index = cpu_to_le32(i);
733764
memcpy(paging->data, page_address(pages),
734765
PAGING_BLOCK_SIZE);
766+
dump_data = iwl_fw_error_next_data(dump_data);
735767
}
736768
}
737769

738-
dump_data = iwl_fw_error_next_data(dump_data);
739770
if (prph_len)
740771
iwl_dump_prph(mvm->trans, &dump_data);
741772

0 commit comments

Comments
 (0)