aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGolan Ben Ami <golan.ben.ami@intel.com>2017-08-16 05:14:56 -0400
committerLuca Coelho <luciano.coelho@intel.com>2017-12-20 11:28:23 -0500
commitfd527eb5d2293667bfe9d9bae8eecb2967ce32f8 (patch)
tree3057247480ccd878de9cc3d2b01cb96810f34188
parentf39a5c01c3d24f2f61ec9d8c7d7e81f9aca506ce (diff)
iwlwifi: support internal debug data collection for new devices
Support internal debug data collection on 9000 and newer devices. The method for finding the base and end address has changed on new HW's, so introduce a new version of debug destination tlv. Signed-off-by: Golan Ben Ami <golan.ben.ami@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/file.h28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/img.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.c99
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c59
6 files changed, 150 insertions, 42 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index 4687d016f676..0824c007b6f8 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -7,7 +7,7 @@
7 * 7 *
8 * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. 8 * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
9 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 9 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
10 * Copyright(c) 2016 Intel Deutschland GmbH 10 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
11 * 11 *
12 * This program is free software; you can redistribute it and/or modify 12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of version 2 of the GNU General Public License as 13 * it under the terms of version 2 of the GNU General Public License as
@@ -34,7 +34,7 @@
34 * 34 *
35 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. 35 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
36 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 36 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
37 * Copyright(c) 2016 Intel Deutschland GmbH 37 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
38 * All rights reserved. 38 * All rights reserved.
39 * 39 *
40 * Redistribution and use in source and binary forms, with or without 40 * Redistribution and use in source and binary forms, with or without
@@ -540,7 +540,7 @@ struct iwl_fw_dbg_mem_seg_tlv {
540} __packed; 540} __packed;
541 541
542/** 542/**
543 * struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data 543 * struct iwl_fw_dbg_dest_tlv_v1 - configures the destination of the debug data
544 * 544 *
545 * @version: version of the TLV - currently 0 545 * @version: version of the TLV - currently 0
546 * @monitor_mode: &enum iwl_fw_dbg_monitor_mode 546 * @monitor_mode: &enum iwl_fw_dbg_monitor_mode
@@ -555,7 +555,7 @@ struct iwl_fw_dbg_mem_seg_tlv {
555 * 555 *
556 * This parses IWL_UCODE_TLV_FW_DBG_DEST 556 * This parses IWL_UCODE_TLV_FW_DBG_DEST
557 */ 557 */
558struct iwl_fw_dbg_dest_tlv { 558struct iwl_fw_dbg_dest_tlv_v1 {
559 u8 version; 559 u8 version;
560 u8 monitor_mode; 560 u8 monitor_mode;
561 u8 size_power; 561 u8 size_power;
@@ -569,6 +569,26 @@ struct iwl_fw_dbg_dest_tlv {
569 struct iwl_fw_dbg_reg_op reg_ops[0]; 569 struct iwl_fw_dbg_reg_op reg_ops[0];
570} __packed; 570} __packed;
571 571
572/* Mask of the register for defining the LDBG MAC2SMEM buffer SMEM size */
573#define IWL_LDBG_M2S_BUF_SIZE_MSK 0x0fff0000
574/* Mask of the register for defining the LDBG MAC2SMEM SMEM base address */
575#define IWL_LDBG_M2S_BUF_BA_MSK 0x00000fff
576/* The smem buffer chunks are in units of 256 bits */
577#define IWL_M2S_UNIT_SIZE 0x100
578
579struct iwl_fw_dbg_dest_tlv {
580 u8 version;
581 u8 monitor_mode;
582 u8 size_power;
583 u8 reserved;
584 __le32 cfg_reg;
585 __le32 write_ptr_reg;
586 __le32 wrap_count;
587 u8 base_shift;
588 u8 size_shift;
589 struct iwl_fw_dbg_reg_op reg_ops[0];
590} __packed;
591
572struct iwl_fw_dbg_conf_hcmd { 592struct iwl_fw_dbg_conf_hcmd {
573 u8 id; 593 u8 id;
574 u8 reserved; 594 u8 reserved;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h
index 985496cc01d0..b23ffe12ad84 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/img.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h
@@ -284,7 +284,7 @@ struct iwl_fw {
284 struct iwl_fw_cipher_scheme cs[IWL_UCODE_MAX_CS]; 284 struct iwl_fw_cipher_scheme cs[IWL_UCODE_MAX_CS];
285 u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; 285 u8 human_readable[FW_VER_HUMAN_READABLE_SZ];
286 286
287 struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; 287 struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv;
288 struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX]; 288 struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
289 size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX]; 289 size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
290 struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX]; 290 struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index de8f6ae2f51b..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 {
296 u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; 296 u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
297 297
298 /* FW debug data parsed for driver usage */ 298 /* FW debug data parsed for driver usage */
299 struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; 299 bool dbg_dest_tlv_init;
300 u8 *dbg_dest_ver;
301 union {
302 struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
303 struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv_v1;
304 };
300 struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX]; 305 struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
301 size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX]; 306 size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
302 struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX]; 307 struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
@@ -930,21 +935,49 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
930 break; 935 break;
931 } 936 }
932 case IWL_UCODE_TLV_FW_DBG_DEST: { 937 case IWL_UCODE_TLV_FW_DBG_DEST: {
933 struct iwl_fw_dbg_dest_tlv *dest = (void *)tlv_data; 938 struct iwl_fw_dbg_dest_tlv *dest = NULL;
939 struct iwl_fw_dbg_dest_tlv_v1 *dest_v1 = NULL;
940 u8 mon_mode;
941
942 pieces->dbg_dest_ver = (u8 *)tlv_data;
943 if (*pieces->dbg_dest_ver == 1) {
944 dest = (void *)tlv_data;
945 } else if (*pieces->dbg_dest_ver == 0) {
946 dest_v1 = (void *)tlv_data;
947 } else {
948 IWL_ERR(drv,
949 "The version is %d, and it is invalid\n",
950 *pieces->dbg_dest_ver);
951 break;
952 }
934 953
935 if (pieces->dbg_dest_tlv) { 954 if (pieces->dbg_dest_tlv_init) {
936 IWL_ERR(drv, 955 IWL_ERR(drv,
937 "dbg destination ignored, already exists\n"); 956 "dbg destination ignored, already exists\n");
938 break; 957 break;
939 } 958 }
940 959
941 pieces->dbg_dest_tlv = dest; 960 pieces->dbg_dest_tlv_init = true;
961
962 if (dest_v1) {
963 pieces->dbg_dest_tlv_v1 = dest_v1;
964 mon_mode = dest_v1->monitor_mode;
965 } else {
966 pieces->dbg_dest_tlv = dest;
967 mon_mode = dest->monitor_mode;
968 }
969
942 IWL_INFO(drv, "Found debug destination: %s\n", 970 IWL_INFO(drv, "Found debug destination: %s\n",
943 get_fw_dbg_mode_string(dest->monitor_mode)); 971 get_fw_dbg_mode_string(mon_mode));
972
973 drv->fw.dbg_dest_reg_num = (dest_v1) ?
974 tlv_len -
975 offsetof(struct iwl_fw_dbg_dest_tlv_v1,
976 reg_ops) :
977 tlv_len -
978 offsetof(struct iwl_fw_dbg_dest_tlv,
979 reg_ops);
944 980
945 drv->fw.dbg_dest_reg_num =
946 tlv_len - offsetof(struct iwl_fw_dbg_dest_tlv,
947 reg_ops);
948 drv->fw.dbg_dest_reg_num /= 981 drv->fw.dbg_dest_reg_num /=
949 sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]); 982 sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]);
950 983
@@ -953,7 +986,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
953 case IWL_UCODE_TLV_FW_DBG_CONF: { 986 case IWL_UCODE_TLV_FW_DBG_CONF: {
954 struct iwl_fw_dbg_conf_tlv *conf = (void *)tlv_data; 987 struct iwl_fw_dbg_conf_tlv *conf = (void *)tlv_data;
955 988
956 if (!pieces->dbg_dest_tlv) { 989 if (!pieces->dbg_dest_tlv_init) {
957 IWL_ERR(drv, 990 IWL_ERR(drv,
958 "Ignore dbg config %d - no destination configured\n", 991 "Ignore dbg config %d - no destination configured\n",
959 conf->id); 992 conf->id);
@@ -1340,15 +1373,51 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
1340 if (iwl_alloc_ucode(drv, pieces, i)) 1373 if (iwl_alloc_ucode(drv, pieces, i))
1341 goto out_free_fw; 1374 goto out_free_fw;
1342 1375
1343 if (pieces->dbg_dest_tlv) { 1376 if (pieces->dbg_dest_tlv_init) {
1344 drv->fw.dbg_dest_tlv = 1377 size_t dbg_dest_size = sizeof(*drv->fw.dbg_dest_tlv) +
1345 kmemdup(pieces->dbg_dest_tlv, 1378 sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
1346 sizeof(*pieces->dbg_dest_tlv) + 1379 drv->fw.dbg_dest_reg_num;
1347 sizeof(pieces->dbg_dest_tlv->reg_ops[0]) * 1380
1348 drv->fw.dbg_dest_reg_num, GFP_KERNEL); 1381 drv->fw.dbg_dest_tlv = kmalloc(dbg_dest_size, GFP_KERNEL);
1349 1382
1350 if (!drv->fw.dbg_dest_tlv) 1383 if (!drv->fw.dbg_dest_tlv)
1351 goto out_free_fw; 1384 goto out_free_fw;
1385
1386 if (*pieces->dbg_dest_ver == 0) {
1387 memcpy(drv->fw.dbg_dest_tlv, pieces->dbg_dest_tlv_v1,
1388 dbg_dest_size);
1389 } else {
1390 struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv =
1391 drv->fw.dbg_dest_tlv;
1392
1393 dest_tlv->version = pieces->dbg_dest_tlv->version;
1394 dest_tlv->monitor_mode =
1395 pieces->dbg_dest_tlv->monitor_mode;
1396 dest_tlv->size_power =
1397 pieces->dbg_dest_tlv->size_power;
1398 dest_tlv->wrap_count =
1399 pieces->dbg_dest_tlv->wrap_count;
1400 dest_tlv->write_ptr_reg =
1401 pieces->dbg_dest_tlv->write_ptr_reg;
1402 dest_tlv->base_shift =
1403 pieces->dbg_dest_tlv->base_shift;
1404 memcpy(dest_tlv->reg_ops,
1405 pieces->dbg_dest_tlv->reg_ops,
1406 sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
1407 drv->fw.dbg_dest_reg_num);
1408
1409 /* In version 1 of the destination tlv, which is
1410 * relevant for internal buffer exclusively,
1411 * the base address is part of given with the length
1412 * of the buffer, and the size shift is give instead of
1413 * end shift. We now store these values in base_reg,
1414 * and end shift, and when dumping the data we'll
1415 * manipulate it for extracting both the length and
1416 * base address */
1417 dest_tlv->base_reg = pieces->dbg_dest_tlv->cfg_reg;
1418 dest_tlv->end_shift =
1419 pieces->dbg_dest_tlv->size_shift;
1420 }
1352 } 1421 }
1353 1422
1354 for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) { 1423 for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) {
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 84ae1e274d38..af50d78cc193 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -744,7 +744,7 @@ struct iwl_trans {
744 struct lockdep_map sync_cmd_lockdep_map; 744 struct lockdep_map sync_cmd_lockdep_map;
745#endif 745#endif
746 746
747 const struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; 747 const struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv;
748 const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX]; 748 const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
749 struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv; 749 struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv;
750 u8 dbg_dest_reg_num; 750 u8 dbg_dest_reg_num;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 270781e13e89..037dc4a0f133 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -1221,7 +1221,7 @@ static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm,
1221 loff_t *ppos) 1221 loff_t *ppos)
1222{ 1222{
1223 struct iwl_trans *trans = mvm->trans; 1223 struct iwl_trans *trans = mvm->trans;
1224 const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv; 1224 const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv;
1225 struct iwl_continuous_record_cmd cont_rec = {}; 1225 struct iwl_continuous_record_cmd cont_rec = {};
1226 int ret, rec_mode; 1226 int ret, rec_mode;
1227 1227
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index fbc45361f0bb..2652e0992819 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -915,14 +915,9 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
915void iwl_pcie_apply_destination(struct iwl_trans *trans) 915void iwl_pcie_apply_destination(struct iwl_trans *trans)
916{ 916{
917 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 917 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
918 const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv; 918 const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv;
919 int i; 919 int i;
920 920
921 if (dest->version)
922 IWL_ERR(trans,
923 "DBG DEST version is %d - expect issues\n",
924 dest->version);
925
926 IWL_INFO(trans, "Applying debug destination %s\n", 921 IWL_INFO(trans, "Applying debug destination %s\n",
927 get_fw_dbg_mode_string(dest->monitor_mode)); 922 get_fw_dbg_mode_string(dest->monitor_mode));
928 923
@@ -2816,8 +2811,17 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
2816 * Update pointers to reflect actual values after 2811 * Update pointers to reflect actual values after
2817 * shifting 2812 * shifting
2818 */ 2813 */
2819 base = iwl_read_prph(trans, base) << 2814 if (trans->dbg_dest_tlv->version) {
2820 trans->dbg_dest_tlv->base_shift; 2815 base = (iwl_read_prph(trans, base) &
2816 IWL_LDBG_M2S_BUF_BA_MSK) <<
2817 trans->dbg_dest_tlv->base_shift;
2818 base *= IWL_M2S_UNIT_SIZE;
2819 base += trans->cfg->smem_offset;
2820 } else {
2821 base = iwl_read_prph(trans, base) <<
2822 trans->dbg_dest_tlv->base_shift;
2823 }
2824
2821 iwl_trans_read_mem(trans, base, fw_mon_data->data, 2825 iwl_trans_read_mem(trans, base, fw_mon_data->data,
2822 monitor_len / sizeof(u32)); 2826 monitor_len / sizeof(u32));
2823 } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) { 2827 } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) {
@@ -2865,21 +2869,36 @@ static struct iwl_trans_dump_data
2865 trans_pcie->fw_mon_size; 2869 trans_pcie->fw_mon_size;
2866 monitor_len = trans_pcie->fw_mon_size; 2870 monitor_len = trans_pcie->fw_mon_size;
2867 } else if (trans->dbg_dest_tlv) { 2871 } else if (trans->dbg_dest_tlv) {
2868 u32 base, end; 2872 u32 base, end, cfg_reg;
2869 2873
2870 base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); 2874 if (trans->dbg_dest_tlv->version == 1) {
2871 end = le32_to_cpu(trans->dbg_dest_tlv->end_reg); 2875 cfg_reg = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
2876 cfg_reg = iwl_read_prph(trans, cfg_reg);
2877 base = (cfg_reg & IWL_LDBG_M2S_BUF_BA_MSK) <<
2878 trans->dbg_dest_tlv->base_shift;
2879 base *= IWL_M2S_UNIT_SIZE;
2880 base += trans->cfg->smem_offset;
2872 2881
2873 base = iwl_read_prph(trans, base) << 2882 monitor_len =
2874 trans->dbg_dest_tlv->base_shift; 2883 (cfg_reg & IWL_LDBG_M2S_BUF_SIZE_MSK) >>
2875 end = iwl_read_prph(trans, end) << 2884 trans->dbg_dest_tlv->end_shift;
2876 trans->dbg_dest_tlv->end_shift; 2885 monitor_len *= IWL_M2S_UNIT_SIZE;
2886 } else {
2887 base = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
2888 end = le32_to_cpu(trans->dbg_dest_tlv->end_reg);
2877 2889
2878 /* Make "end" point to the actual end */ 2890 base = iwl_read_prph(trans, base) <<
2879 if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000 || 2891 trans->dbg_dest_tlv->base_shift;
2880 trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) 2892 end = iwl_read_prph(trans, end) <<
2881 end += (1 << trans->dbg_dest_tlv->end_shift); 2893 trans->dbg_dest_tlv->end_shift;
2882 monitor_len = end - base; 2894
2895 /* Make "end" point to the actual end */
2896 if (trans->cfg->device_family >=
2897 IWL_DEVICE_FAMILY_8000 ||
2898 trans->dbg_dest_tlv->monitor_mode == MARBH_MODE)
2899 end += (1 << trans->dbg_dest_tlv->end_shift);
2900 monitor_len = end - base;
2901 }
2883 len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + 2902 len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
2884 monitor_len; 2903 monitor_len;
2885 } else { 2904 } else {