diff options
author | Liad Kaufman <liad.kaufman@intel.com> | 2014-09-16 08:06:54 -0400 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-12-02 09:50:51 -0500 |
commit | 490fefebb6db4c5f80c12ae2c1c6230e24733b2a (patch) | |
tree | cd8b107fd058e075deefa5433c8febbcd40d0f92 | |
parent | b4c82adcba8cb4b23068a6b800ca98da3bee6888 (diff) |
iwlwifi: define the .ucode file format for debug
Debug information can be appended to the firmware file. This
information will be used by the driver to enable / disable
debugging features in the firmware.
Signed-off-by: Liad Kaufman <liad.kaufman@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-drv.c | 121 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-fw-file.h | 124 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-fw.h | 55 |
3 files changed, 285 insertions, 15 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 2c6e8309ad30..a53b534aa232 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -184,6 +184,11 @@ static void iwl_free_fw_img(struct iwl_drv *drv, struct fw_img *img) | |||
184 | static void iwl_dealloc_ucode(struct iwl_drv *drv) | 184 | static void iwl_dealloc_ucode(struct iwl_drv *drv) |
185 | { | 185 | { |
186 | int i; | 186 | int i; |
187 | |||
188 | kfree(drv->fw.dbg_dest_tlv); | ||
189 | for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) | ||
190 | kfree(drv->fw.dbg_conf_tlv[i]); | ||
191 | |||
187 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) | 192 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) |
188 | iwl_free_fw_img(drv, drv->fw.img + i); | 193 | iwl_free_fw_img(drv, drv->fw.img + i); |
189 | } | 194 | } |
@@ -308,6 +313,11 @@ struct iwl_firmware_pieces { | |||
308 | 313 | ||
309 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | 314 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; |
310 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | 315 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; |
316 | |||
317 | /* FW debug data parsed for driver usage */ | ||
318 | struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; | ||
319 | struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; | ||
320 | size_t dbg_conf_tlv_len[FW_DBG_MAX]; | ||
311 | }; | 321 | }; |
312 | 322 | ||
313 | /* | 323 | /* |
@@ -853,6 +863,58 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
853 | capa->n_scan_channels = | 863 | capa->n_scan_channels = |
854 | le32_to_cpup((__le32 *)tlv_data); | 864 | le32_to_cpup((__le32 *)tlv_data); |
855 | break; | 865 | break; |
866 | case IWL_UCODE_TLV_FW_DBG_DEST: { | ||
867 | struct iwl_fw_dbg_dest_tlv *dest = (void *)tlv_data; | ||
868 | |||
869 | if (pieces->dbg_dest_tlv) { | ||
870 | IWL_ERR(drv, | ||
871 | "dbg destination ignored, already exists\n"); | ||
872 | break; | ||
873 | } | ||
874 | |||
875 | pieces->dbg_dest_tlv = dest; | ||
876 | IWL_INFO(drv, "Found debug destination: %s\n", | ||
877 | get_fw_dbg_mode_string(dest->monitor_mode)); | ||
878 | |||
879 | drv->fw.dbg_dest_reg_num = | ||
880 | tlv_len - offsetof(struct iwl_fw_dbg_dest_tlv, | ||
881 | reg_ops); | ||
882 | drv->fw.dbg_dest_reg_num /= | ||
883 | sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]); | ||
884 | |||
885 | break; | ||
886 | } | ||
887 | case IWL_UCODE_TLV_FW_DBG_CONF: { | ||
888 | struct iwl_fw_dbg_conf_tlv *conf = (void *)tlv_data; | ||
889 | |||
890 | if (!pieces->dbg_dest_tlv) { | ||
891 | IWL_ERR(drv, | ||
892 | "Ignore dbg config %d - no destination configured\n", | ||
893 | conf->id); | ||
894 | break; | ||
895 | } | ||
896 | |||
897 | if (conf->id >= ARRAY_SIZE(drv->fw.dbg_conf_tlv)) { | ||
898 | IWL_ERR(drv, | ||
899 | "Skip unknown configuration: %d\n", | ||
900 | conf->id); | ||
901 | break; | ||
902 | } | ||
903 | |||
904 | if (pieces->dbg_conf_tlv[conf->id]) { | ||
905 | IWL_ERR(drv, | ||
906 | "Ignore duplicate dbg config %d\n", | ||
907 | conf->id); | ||
908 | break; | ||
909 | } | ||
910 | |||
911 | IWL_INFO(drv, "Found debug configuration: %d\n", | ||
912 | conf->id); | ||
913 | |||
914 | pieces->dbg_conf_tlv[conf->id] = conf; | ||
915 | pieces->dbg_conf_tlv_len[conf->id] = tlv_len; | ||
916 | break; | ||
917 | } | ||
856 | default: | 918 | default: |
857 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); | 919 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); |
858 | break; | 920 | break; |
@@ -996,7 +1058,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
996 | struct iwl_ucode_header *ucode; | 1058 | struct iwl_ucode_header *ucode; |
997 | struct iwlwifi_opmode_table *op; | 1059 | struct iwlwifi_opmode_table *op; |
998 | int err; | 1060 | int err; |
999 | struct iwl_firmware_pieces pieces; | 1061 | struct iwl_firmware_pieces *pieces; |
1000 | const unsigned int api_max = drv->cfg->ucode_api_max; | 1062 | const unsigned int api_max = drv->cfg->ucode_api_max; |
1001 | unsigned int api_ok = drv->cfg->ucode_api_ok; | 1063 | unsigned int api_ok = drv->cfg->ucode_api_ok; |
1002 | const unsigned int api_min = drv->cfg->ucode_api_min; | 1064 | const unsigned int api_min = drv->cfg->ucode_api_min; |
@@ -1013,7 +1075,9 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1013 | if (!api_ok) | 1075 | if (!api_ok) |
1014 | api_ok = api_max; | 1076 | api_ok = api_max; |
1015 | 1077 | ||
1016 | memset(&pieces, 0, sizeof(pieces)); | 1078 | pieces = kzalloc(sizeof(*pieces), GFP_KERNEL); |
1079 | if (!pieces) | ||
1080 | return; | ||
1017 | 1081 | ||
1018 | if (!ucode_raw) { | 1082 | if (!ucode_raw) { |
1019 | if (drv->fw_index <= api_ok) | 1083 | if (drv->fw_index <= api_ok) |
@@ -1036,10 +1100,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1036 | ucode = (struct iwl_ucode_header *)ucode_raw->data; | 1100 | ucode = (struct iwl_ucode_header *)ucode_raw->data; |
1037 | 1101 | ||
1038 | if (ucode->ver) | 1102 | if (ucode->ver) |
1039 | err = iwl_parse_v1_v2_firmware(drv, ucode_raw, &pieces); | 1103 | err = iwl_parse_v1_v2_firmware(drv, ucode_raw, pieces); |
1040 | else | 1104 | else |
1041 | err = iwl_parse_tlv_firmware(drv, ucode_raw, &pieces, | 1105 | err = iwl_parse_tlv_firmware(drv, ucode_raw, pieces, |
1042 | &fw->ucode_capa); | 1106 | &fw->ucode_capa); |
1043 | 1107 | ||
1044 | if (err) | 1108 | if (err) |
1045 | goto try_again; | 1109 | goto try_again; |
@@ -1079,7 +1143,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1079 | * In mvm uCode there is no difference between data and instructions | 1143 | * In mvm uCode there is no difference between data and instructions |
1080 | * sections. | 1144 | * sections. |
1081 | */ | 1145 | */ |
1082 | if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, drv->cfg)) | 1146 | if (!fw->mvm_fw && validate_sec_sizes(drv, pieces, drv->cfg)) |
1083 | goto try_again; | 1147 | goto try_again; |
1084 | 1148 | ||
1085 | /* Allocate ucode buffers for card's bus-master loading ... */ | 1149 | /* Allocate ucode buffers for card's bus-master loading ... */ |
@@ -1088,9 +1152,33 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1088 | * 1) unmodified from disk | 1152 | * 1) unmodified from disk |
1089 | * 2) backup cache for save/restore during power-downs */ | 1153 | * 2) backup cache for save/restore during power-downs */ |
1090 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) | 1154 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) |
1091 | if (iwl_alloc_ucode(drv, &pieces, i)) | 1155 | if (iwl_alloc_ucode(drv, pieces, i)) |
1092 | goto out_free_fw; | 1156 | goto out_free_fw; |
1093 | 1157 | ||
1158 | if (pieces->dbg_dest_tlv) { | ||
1159 | drv->fw.dbg_dest_tlv = | ||
1160 | kmemdup(pieces->dbg_dest_tlv, | ||
1161 | sizeof(*pieces->dbg_dest_tlv) + | ||
1162 | sizeof(pieces->dbg_dest_tlv->reg_ops[0]) * | ||
1163 | drv->fw.dbg_dest_reg_num, GFP_KERNEL); | ||
1164 | |||
1165 | if (!drv->fw.dbg_dest_tlv) | ||
1166 | goto out_free_fw; | ||
1167 | } | ||
1168 | |||
1169 | for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) { | ||
1170 | if (pieces->dbg_conf_tlv[i]) { | ||
1171 | drv->fw.dbg_conf_tlv_len[i] = | ||
1172 | pieces->dbg_conf_tlv_len[i]; | ||
1173 | drv->fw.dbg_conf_tlv[i] = | ||
1174 | kmemdup(pieces->dbg_conf_tlv[i], | ||
1175 | drv->fw.dbg_conf_tlv_len[i], | ||
1176 | GFP_KERNEL); | ||
1177 | if (!drv->fw.dbg_conf_tlv[i]) | ||
1178 | goto out_free_fw; | ||
1179 | } | ||
1180 | } | ||
1181 | |||
1094 | /* Now that we can no longer fail, copy information */ | 1182 | /* Now that we can no longer fail, copy information */ |
1095 | 1183 | ||
1096 | /* | 1184 | /* |
@@ -1098,20 +1186,20 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1098 | * for each event, which is of mode 1 (including timestamp) for all | 1186 | * for each event, which is of mode 1 (including timestamp) for all |
1099 | * new microcodes that include this information. | 1187 | * new microcodes that include this information. |
1100 | */ | 1188 | */ |
1101 | fw->init_evtlog_ptr = pieces.init_evtlog_ptr; | 1189 | fw->init_evtlog_ptr = pieces->init_evtlog_ptr; |
1102 | if (pieces.init_evtlog_size) | 1190 | if (pieces->init_evtlog_size) |
1103 | fw->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; | 1191 | fw->init_evtlog_size = (pieces->init_evtlog_size - 16)/12; |
1104 | else | 1192 | else |
1105 | fw->init_evtlog_size = | 1193 | fw->init_evtlog_size = |
1106 | drv->cfg->base_params->max_event_log_size; | 1194 | drv->cfg->base_params->max_event_log_size; |
1107 | fw->init_errlog_ptr = pieces.init_errlog_ptr; | 1195 | fw->init_errlog_ptr = pieces->init_errlog_ptr; |
1108 | fw->inst_evtlog_ptr = pieces.inst_evtlog_ptr; | 1196 | fw->inst_evtlog_ptr = pieces->inst_evtlog_ptr; |
1109 | if (pieces.inst_evtlog_size) | 1197 | if (pieces->inst_evtlog_size) |
1110 | fw->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; | 1198 | fw->inst_evtlog_size = (pieces->inst_evtlog_size - 16)/12; |
1111 | else | 1199 | else |
1112 | fw->inst_evtlog_size = | 1200 | fw->inst_evtlog_size = |
1113 | drv->cfg->base_params->max_event_log_size; | 1201 | drv->cfg->base_params->max_event_log_size; |
1114 | fw->inst_errlog_ptr = pieces.inst_errlog_ptr; | 1202 | fw->inst_errlog_ptr = pieces->inst_errlog_ptr; |
1115 | 1203 | ||
1116 | /* | 1204 | /* |
1117 | * figure out the offset of chain noise reset and gain commands | 1205 | * figure out the offset of chain noise reset and gain commands |
@@ -1213,10 +1301,12 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1213 | iwl_req_fw_callback(ucode_raw, context); | 1301 | iwl_req_fw_callback(ucode_raw, context); |
1214 | } | 1302 | } |
1215 | 1303 | ||
1304 | kfree(pieces); | ||
1216 | return; | 1305 | return; |
1217 | 1306 | ||
1218 | try_again: | 1307 | try_again: |
1219 | /* try next, if any */ | 1308 | /* try next, if any */ |
1309 | kfree(pieces); | ||
1220 | release_firmware(ucode_raw); | 1310 | release_firmware(ucode_raw); |
1221 | if (iwl_request_firmware(drv, false)) | 1311 | if (iwl_request_firmware(drv, false)) |
1222 | goto out_unbind; | 1312 | goto out_unbind; |
@@ -1227,6 +1317,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
1227 | iwl_dealloc_ucode(drv); | 1317 | iwl_dealloc_ucode(drv); |
1228 | release_firmware(ucode_raw); | 1318 | release_firmware(ucode_raw); |
1229 | out_unbind: | 1319 | out_unbind: |
1320 | kfree(pieces); | ||
1230 | complete(&drv->request_firmware_complete); | 1321 | complete(&drv->request_firmware_complete); |
1231 | device_release_driver(drv->trans->dev); | 1322 | device_release_driver(drv->trans->dev); |
1232 | } | 1323 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index df5613a8be15..9faad691c13c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h | |||
@@ -131,6 +131,8 @@ enum iwl_ucode_tlv_type { | |||
131 | IWL_UCODE_TLV_API_CHANGES_SET = 29, | 131 | IWL_UCODE_TLV_API_CHANGES_SET = 29, |
132 | IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, | 132 | IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, |
133 | IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, | 133 | IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, |
134 | IWL_UCODE_TLV_FW_DBG_DEST = 38, | ||
135 | IWL_UCODE_TLV_FW_DBG_CONF = 39, | ||
134 | }; | 136 | }; |
135 | 137 | ||
136 | struct iwl_ucode_tlv { | 138 | struct iwl_ucode_tlv { |
@@ -362,4 +364,126 @@ struct iwl_fw_cipher_scheme { | |||
362 | u8 hw_cipher; | 364 | u8 hw_cipher; |
363 | } __packed; | 365 | } __packed; |
364 | 366 | ||
367 | enum iwl_fw_dbg_reg_operator { | ||
368 | CSR_ASSIGN, | ||
369 | CSR_SETBIT, | ||
370 | CSR_CLEARBIT, | ||
371 | |||
372 | PRPH_ASSIGN, | ||
373 | PRPH_SETBIT, | ||
374 | PRPH_CLEARBIT, | ||
375 | }; | ||
376 | |||
377 | /** | ||
378 | * struct iwl_fw_dbg_reg_op - an operation on a register | ||
379 | * | ||
380 | * @op: %enum iwl_fw_dbg_reg_operator | ||
381 | * @addr: offset of the register | ||
382 | * @val: value | ||
383 | */ | ||
384 | struct iwl_fw_dbg_reg_op { | ||
385 | u8 op; | ||
386 | u8 reserved[3]; | ||
387 | __le32 addr; | ||
388 | __le32 val; | ||
389 | } __packed; | ||
390 | |||
391 | /** | ||
392 | * enum iwl_fw_dbg_monitor_mode - available monitor recording modes | ||
393 | * | ||
394 | * @SMEM_MODE: monitor stores the data in SMEM | ||
395 | * @EXTERNAL_MODE: monitor stores the data in allocated DRAM | ||
396 | * @MARBH_MODE: monitor stores the data in MARBH buffer | ||
397 | */ | ||
398 | enum iwl_fw_dbg_monitor_mode { | ||
399 | SMEM_MODE = 0, | ||
400 | EXTERNAL_MODE = 1, | ||
401 | MARBH_MODE = 2, | ||
402 | }; | ||
403 | |||
404 | /** | ||
405 | * struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data | ||
406 | * | ||
407 | * @version: version of the TLV - currently 0 | ||
408 | * @monitor_mode: %enum iwl_fw_dbg_monitor_mode | ||
409 | * @base_reg: addr of the base addr register (PRPH) | ||
410 | * @end_reg: addr of the end addr register (PRPH) | ||
411 | * @write_ptr_reg: the addr of the reg of the write pointer | ||
412 | * @wrap_count: the addr of the reg of the wrap_count | ||
413 | * @base_shift: shift right of the base addr reg | ||
414 | * @end_shift: shift right of the end addr reg | ||
415 | * @reg_ops: array of registers operations | ||
416 | * | ||
417 | * This parses IWL_UCODE_TLV_FW_DBG_DEST | ||
418 | */ | ||
419 | struct iwl_fw_dbg_dest_tlv { | ||
420 | u8 version; | ||
421 | u8 monitor_mode; | ||
422 | u8 reserved[2]; | ||
423 | __le32 base_reg; | ||
424 | __le32 end_reg; | ||
425 | __le32 write_ptr_reg; | ||
426 | __le32 wrap_count; | ||
427 | u8 base_shift; | ||
428 | u8 end_shift; | ||
429 | struct iwl_fw_dbg_reg_op reg_ops[0]; | ||
430 | } __packed; | ||
431 | |||
432 | struct iwl_fw_dbg_conf_hcmd { | ||
433 | u8 id; | ||
434 | u8 reserved; | ||
435 | __le16 len; | ||
436 | u8 data[0]; | ||
437 | } __packed; | ||
438 | |||
439 | /** | ||
440 | * struct iwl_fw_dbg_trigger - a TLV that describes a debug configuration | ||
441 | * | ||
442 | * @enabled: is this trigger enabled | ||
443 | * @reserved: | ||
444 | * @len: length, in bytes, of the %trigger field | ||
445 | * @trigger: pointer to a trigger struct | ||
446 | */ | ||
447 | struct iwl_fw_dbg_trigger { | ||
448 | u8 enabled; | ||
449 | u8 reserved; | ||
450 | u8 len; | ||
451 | u8 trigger[0]; | ||
452 | } __packed; | ||
453 | |||
454 | /** | ||
455 | * enum iwl_fw_dbg_conf - configurations available | ||
456 | * | ||
457 | * @FW_DBG_CUSTOM: take this configuration from alive | ||
458 | * Note that the trigger is NO-OP for this configuration | ||
459 | */ | ||
460 | enum iwl_fw_dbg_conf { | ||
461 | FW_DBG_CUSTOM = 0, | ||
462 | |||
463 | /* must be last */ | ||
464 | FW_DBG_MAX, | ||
465 | FW_DBG_INVALID = 0xff, | ||
466 | }; | ||
467 | |||
468 | /** | ||
469 | * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration | ||
470 | * | ||
471 | * @id: %enum iwl_fw_dbg_conf | ||
472 | * @usniffer: should the uSniffer image be used | ||
473 | * @num_of_hcmds: how many HCMDs to send are present here | ||
474 | * @hcmd: a variable length host command to be sent to apply the configuration. | ||
475 | * If there is more than one HCMD to send, they will appear one after the | ||
476 | * other and be sent in the order that they appear in. | ||
477 | * This parses IWL_UCODE_TLV_FW_DBG_CONF | ||
478 | */ | ||
479 | struct iwl_fw_dbg_conf_tlv { | ||
480 | u8 id; | ||
481 | u8 usniffer; | ||
482 | u8 reserved; | ||
483 | u8 num_of_hcmds; | ||
484 | struct iwl_fw_dbg_conf_hcmd hcmd; | ||
485 | |||
486 | /* struct iwl_fw_dbg_trigger sits after all variable length hcmds */ | ||
487 | } __packed; | ||
488 | |||
365 | #endif /* __iwl_fw_file_h__ */ | 489 | #endif /* __iwl_fw_file_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index eaf1ff04adb9..20d44ea315ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -150,6 +150,10 @@ struct iwl_fw_cscheme_list { | |||
150 | * @mvm_fw: indicates this is MVM firmware | 150 | * @mvm_fw: indicates this is MVM firmware |
151 | * @cipher_scheme: optional external cipher scheme. | 151 | * @cipher_scheme: optional external cipher scheme. |
152 | * @human_readable: human readable version | 152 | * @human_readable: human readable version |
153 | * @dbg_dest_tlv: points to the destination TLV for debug | ||
154 | * @dbg_conf_tlv: array of pointers to configuration TLVs for debug | ||
155 | * @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries | ||
156 | * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv | ||
153 | */ | 157 | */ |
154 | struct iwl_fw { | 158 | struct iwl_fw { |
155 | u32 ucode_ver; | 159 | u32 ucode_ver; |
@@ -174,6 +178,57 @@ struct iwl_fw { | |||
174 | 178 | ||
175 | struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; | 179 | struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; |
176 | u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; | 180 | u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; |
181 | |||
182 | struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; | ||
183 | struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; | ||
184 | size_t dbg_conf_tlv_len[FW_DBG_MAX]; | ||
185 | |||
186 | u8 dbg_dest_reg_num; | ||
177 | }; | 187 | }; |
178 | 188 | ||
189 | static inline const char *get_fw_dbg_mode_string(int mode) | ||
190 | { | ||
191 | switch (mode) { | ||
192 | case SMEM_MODE: | ||
193 | return "SMEM"; | ||
194 | case EXTERNAL_MODE: | ||
195 | return "EXTERNAL_DRAM"; | ||
196 | case MARBH_MODE: | ||
197 | return "MARBH"; | ||
198 | default: | ||
199 | return "UNKNOWN"; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | static inline const struct iwl_fw_dbg_trigger * | ||
204 | iwl_fw_dbg_conf_get_trigger(const struct iwl_fw *fw, u8 id) | ||
205 | { | ||
206 | const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id]; | ||
207 | u8 *ptr; | ||
208 | int i; | ||
209 | |||
210 | if (!conf_tlv) | ||
211 | return NULL; | ||
212 | |||
213 | ptr = (void *)&conf_tlv->hcmd; | ||
214 | for (i = 0; i < conf_tlv->num_of_hcmds; i++) { | ||
215 | ptr += sizeof(conf_tlv->hcmd); | ||
216 | ptr += le16_to_cpu(conf_tlv->hcmd.len); | ||
217 | } | ||
218 | |||
219 | return (const struct iwl_fw_dbg_trigger *)ptr; | ||
220 | } | ||
221 | |||
222 | static inline bool | ||
223 | iwl_fw_dbg_conf_enabled(const struct iwl_fw *fw, u8 id) | ||
224 | { | ||
225 | const struct iwl_fw_dbg_trigger *trigger = | ||
226 | iwl_fw_dbg_conf_get_trigger(fw, id); | ||
227 | |||
228 | if (!trigger) | ||
229 | return false; | ||
230 | |||
231 | return trigger->enabled; | ||
232 | } | ||
233 | |||
179 | #endif /* __iwl_fw_h__ */ | 234 | #endif /* __iwl_fw_h__ */ |