ath10k: Add WMI diag fw logging support for WCN3990
authorGovind Singh <govinds@codeaurora.org>
Mon, 3 Jun 2019 15:14:52 +0000 (18:14 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 25 Jun 2019 13:16:54 +0000 (16:16 +0300)
Integrated WiFi chipset ex:WCN399x supports fw logging
using WMI copy engine and shared mem DIAG based fw logging.
By default shared mem DIAG based fw logging is enabled.
To support WMI copy engine based fw logging add QMI
control message to enable WMI copy engine based fw logging.

Enable WMI based fw logging using fw_diag_log module parameter.

insmod ath10k_core.ko fw_diag_log=1

DIAG utility(https://github.com/andersson/diag) implements extraction
of diagnostics related messages between application processor and
various subsystems while shared mem DIAG based fw logging is enabled.

Testing: Tested on WCN3990/QCA6174 HW
Tested FW: WLAN.HL.3.1-00959-QCAHLSWMTPLZ-1

Signed-off-by: Govind Singh <govinds@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/hif.h
drivers/net/wireless/ath/ath10k/qmi.c
drivers/net/wireless/ath/ath10k/qmi.h
drivers/net/wireless/ath/ath10k/snoc.c

index a26e6cb9fea874e9f3c21a4d5ef68a83fa628245..c047f479e3a9448728ff323d78006b45c9773a90 100644 (file)
@@ -32,6 +32,7 @@ static unsigned int ath10k_cryptmode_param;
 static bool uart_print;
 static bool skip_otp;
 static bool rawmode;
+static bool fw_diag_log;
 
 unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) |
                                     BIT(ATH10K_FW_CRASH_DUMP_CE_DATA);
@@ -42,6 +43,7 @@ module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);
 module_param(uart_print, bool, 0644);
 module_param(skip_otp, bool, 0644);
 module_param(rawmode, bool, 0644);
+module_param(fw_diag_log, bool, 0644);
 module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444);
 
 MODULE_PARM_DESC(debug_mask, "Debugging mask");
@@ -50,6 +52,7 @@ MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
 MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software");
 MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath");
 MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file");
+MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging");
 
 static const struct ath10k_hw_params ath10k_hw_params_list[] = {
        {
@@ -2779,6 +2782,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
        if (status)
                goto err_hif_stop;
 
+       status = ath10k_hif_set_target_log_mode(ar, fw_diag_log);
+       if (status && status != -EOPNOTSUPP) {
+               ath10k_warn(ar, "set traget log mode faileds: %d\n", status);
+               goto err_hif_stop;
+       }
+
        return 0;
 
 err_hif_stop:
index 4443f8732d2f910e118980cf0803e69ed5552d9a..4d7db07db6ba23c87c8291c9c24da1b3a40d08c4 100644 (file)
@@ -645,6 +645,7 @@ struct ath10k_debug {
        u32 nf_cal_period;
        void *cal_data;
        u32 enable_extd_tx_stats;
+       u8 fw_dbglog_mode;
 };
 
 enum ath10k_state {
index fe5417962f40f45816c4397ef1ed3ee0d14abdb3..496ee34a4d782b7ee96e15734b5a0fef1d821f07 100644 (file)
 #include "bmi.h"
 #include "debug.h"
 
+/* Types of fw logging mode */
+enum ath_dbg_mode {
+       ATH10K_ENABLE_FW_LOG_DIAG,
+       ATH10K_ENABLE_FW_LOG_CE,
+};
+
 struct ath10k_hif_sg_item {
        u16 transfer_id;
        void *transfer_context; /* NULL = tx completion callback not called */
@@ -88,6 +94,7 @@ struct ath10k_hif_ops {
 
        int (*get_target_info)(struct ath10k *ar,
                               struct bmi_target_info *target_info);
+       int (*set_target_log_mode)(struct ath10k *ar, u8 fw_log_mode);
 };
 
 static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
@@ -230,4 +237,12 @@ static inline int ath10k_hif_get_target_info(struct ath10k *ar,
        return ar->hif.ops->get_target_info(ar, tgt_info);
 }
 
+static inline int ath10k_hif_set_target_log_mode(struct ath10k *ar,
+                                                u8 fw_log_mode)
+{
+       if (!ar->hif.ops->set_target_log_mode)
+               return -EOPNOTSUPP;
+
+       return ar->hif.ops->set_target_log_mode(ar, fw_log_mode);
+}
 #endif /* _HIF_H_ */
index 2e678780df5dac704784d1045a506839aa4278a7..e94173ece3ca08f5613761c78b97192f2438ddf5 100644 (file)
@@ -620,6 +620,51 @@ out:
        return ret;
 }
 
+int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode)
+{
+       struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+       struct wlfw_ini_resp_msg_v01 resp = {};
+       struct ath10k_qmi *qmi = ar_snoc->qmi;
+       struct wlfw_ini_req_msg_v01 req = {};
+       struct qmi_txn txn;
+       int ret;
+
+       req.enablefwlog_valid = 1;
+       req.enablefwlog = fw_log_mode;
+
+       ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_ini_resp_msg_v01_ei,
+                          &resp);
+       if (ret < 0)
+               goto out;
+
+       ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
+                              QMI_WLFW_INI_REQ_V01,
+                              WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN,
+                              wlfw_ini_req_msg_v01_ei, &req);
+       if (ret < 0) {
+               qmi_txn_cancel(&txn);
+               ath10k_err(ar, "fail to send fw log reqest: %d\n", ret);
+               goto out;
+       }
+
+       ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
+       if (ret < 0)
+               goto out;
+
+       if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+               ath10k_err(ar, "fw log request rejectedr: %d\n",
+                          resp.resp.error);
+               ret = -EINVAL;
+               goto out;
+       }
+       ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi fw log request completed, mode: %d\n",
+                  fw_log_mode);
+       return 0;
+
+out:
+       return ret;
+}
+
 static int
 ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi)
 {
index e4aa2044566637709ea48f5d4d63e63efdee7516..40aafb875ed0123a9e527b701b52dded073b1753 100644 (file)
@@ -114,5 +114,6 @@ int ath10k_qmi_wlan_disable(struct ath10k *ar);
 int ath10k_qmi_register_service_notifier(struct notifier_block *nb);
 int ath10k_qmi_init(struct ath10k *ar, u32 msa_size);
 int ath10k_qmi_deinit(struct ath10k *ar);
+int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode);
 
 #endif /* ATH10K_QMI_H */
index ca1186ec4129971e05621a00c96cdfbdcd206d49..b491361e6ed4540f2b53ee782d5a2c5ec8b2ef0b 100644 (file)
@@ -1050,6 +1050,19 @@ err_wlan_enable:
        return ret;
 }
 
+static int ath10k_snoc_hif_set_target_log_mode(struct ath10k *ar,
+                                              u8 fw_log_mode)
+{
+       u8 fw_dbg_mode;
+
+       if (fw_log_mode)
+               fw_dbg_mode = ATH10K_ENABLE_FW_LOG_CE;
+       else
+               fw_dbg_mode = ATH10K_ENABLE_FW_LOG_DIAG;
+
+       return ath10k_qmi_set_fw_log_mode(ar, fw_dbg_mode);
+}
+
 #ifdef CONFIG_PM
 static int ath10k_snoc_hif_suspend(struct ath10k *ar)
 {
@@ -1103,6 +1116,8 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = {
        .send_complete_check    = ath10k_snoc_hif_send_complete_check,
        .get_free_queue_number  = ath10k_snoc_hif_get_free_queue_number,
        .get_target_info        = ath10k_snoc_hif_get_target_info,
+       .set_target_log_mode    = ath10k_snoc_hif_set_target_log_mode,
+
 #ifdef CONFIG_PM
        .suspend                = ath10k_snoc_hif_suspend,
        .resume                 = ath10k_snoc_hif_resume,