wifi: ath12k: add support for collecting firmware log
authorBaochen Qiang <quic_bqiang@quicinc.com>
Thu, 18 Jan 2024 05:53:48 +0000 (07:53 +0200)
committerKalle Valo <quic_kvalo@quicinc.com>
Fri, 19 Jan 2024 17:40:29 +0000 (19:40 +0200)
Currently there is no way to collect firmware log because firmware
does not send it to host. Also host does not handle WMI_DIAG_EVENTID
which is used by firmware to upload firmware log.

So add support for it by firstly enabling firmware log upload via a
QMI message, and secondly processing WMI DIAG event to expose it to
userspace via trace event.

This change applies to both WCN7850 and QCN9274.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240115023726.2866-1-quic_bqiang@quicinc.com
drivers/net/wireless/ath/ath12k/qmi.c
drivers/net/wireless/ath/ath12k/qmi.h
drivers/net/wireless/ath/ath12k/trace.h
drivers/net/wireless/ath/ath12k/wmi.c

index d20d08023c8178dfe6e7120d9a1a625a3fd38a30..69f56400367cda1028cd208c7371f8d5f3a3904f 100644 (file)
@@ -1954,6 +1954,50 @@ static const struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = {
        },
 };
 
+static const struct qmi_elem_info qmi_wlanfw_wlan_ini_req_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01,
+                                          enable_fwlog_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01,
+                                          enable_fwlog),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static const struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = 1,
+               .elem_size      = sizeof(struct qmi_response_type_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x02,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_ini_resp_msg_v01,
+                                          resp),
+               .ei_array       = qmi_response_type_v01_ei,
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
 static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab,
                                      struct qmi_wlanfw_host_cap_req_msg_v01 *req)
 {
@@ -2853,6 +2897,49 @@ out:
        return ret;
 }
 
+static int ath12k_qmi_wlanfw_wlan_ini_send(struct ath12k_base *ab)
+{
+       struct qmi_wlanfw_wlan_ini_resp_msg_v01 resp = {};
+       struct qmi_wlanfw_wlan_ini_req_msg_v01 req = {};
+       struct qmi_txn txn;
+       int ret;
+
+       req.enable_fwlog_valid = true;
+       req.enable_fwlog = 1;
+
+       ret = qmi_txn_init(&ab->qmi.handle, &txn,
+                          qmi_wlanfw_wlan_ini_resp_msg_v01_ei, &resp);
+       if (ret < 0)
+               goto out;
+
+       ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+                              ATH12K_QMI_WLANFW_WLAN_INI_REQ_V01,
+                              QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN,
+                              qmi_wlanfw_wlan_ini_req_msg_v01_ei, &req);
+       if (ret < 0) {
+               qmi_txn_cancel(&txn);
+               ath12k_warn(ab, "failed to send QMI wlan ini request: %d\n",
+                           ret);
+               goto out;
+       }
+
+       ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH12K_QMI_WLANFW_TIMEOUT_MS));
+       if (ret < 0) {
+               ath12k_warn(ab, "failed to receive QMI wlan ini request: %d\n", ret);
+               goto out;
+       }
+
+       if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+               ath12k_warn(ab, "QMI wlan ini response failure: %d %d\n",
+                           resp.resp.result, resp.resp.error);
+               ret = -EINVAL;
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
 void ath12k_qmi_firmware_stop(struct ath12k_base *ab)
 {
        int ret;
@@ -2869,6 +2956,12 @@ int ath12k_qmi_firmware_start(struct ath12k_base *ab,
 {
        int ret;
 
+       ret = ath12k_qmi_wlanfw_wlan_ini_send(ab);
+       if (ret < 0) {
+               ath12k_warn(ab, "qmi failed to send wlan fw ini: %d\n", ret);
+               return ret;
+       }
+
        ret = ath12k_qmi_wlanfw_wlan_cfg_send(ab);
        if (ret < 0) {
                ath12k_warn(ab, "qmi failed to send wlan cfg:%d\n", ret);
index bfed22c310be4ae6d1a10a07fdf15ada5b39ae32..828ab2bf037df477e18b26d1493a2e2a73e57ef0 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
 /*
  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef ATH12K_QMI_H
@@ -576,6 +576,21 @@ struct qmi_wlanfw_wlan_cfg_resp_msg_v01 {
        struct qmi_response_type_v01 resp;
 };
 
+#define ATH12K_QMI_WLANFW_WLAN_INI_REQ_V01     0x002F
+#define ATH12K_QMI_WLANFW_WLAN_INI_RESP_V01    0x002F
+#define QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN                7
+#define QMI_WLANFW_WLAN_INI_RESP_MSG_V01_MAX_LEN       7
+
+struct qmi_wlanfw_wlan_ini_req_msg_v01 {
+       /* Must be set to true if enable_fwlog is being passed */
+       u8 enable_fwlog_valid;
+       u8 enable_fwlog;
+};
+
+struct qmi_wlanfw_wlan_ini_resp_msg_v01 {
+       struct qmi_response_type_v01 resp;
+};
+
 int ath12k_qmi_firmware_start(struct ath12k_base *ab,
                              u32 mode);
 void ath12k_qmi_firmware_stop(struct ath12k_base *ab);
index f72096684b7468403104af14a96776eeb966dd46..240737e1542d4e714de4bd05959e701ada51255a 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
 /*
  * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
@@ -140,6 +140,33 @@ TRACE_EVENT(ath12k_htt_rxdesc,
         )
 );
 
+TRACE_EVENT(ath12k_wmi_diag,
+           TP_PROTO(struct ath12k_base *ab, const void *data, size_t len),
+
+       TP_ARGS(ab, data, len),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(ab->dev))
+               __string(driver, dev_driver_string(ab->dev))
+               __field(u16, len)
+               __dynamic_array(u8, data, len)
+       ),
+
+       TP_fast_assign(
+               __assign_str(device, dev_name(ab->dev));
+               __assign_str(driver, dev_driver_string(ab->dev));
+               __entry->len = len;
+               memcpy(__get_dynamic_array(data), data, len);
+       ),
+
+       TP_printk(
+               "%s %s tlv diag len %d",
+               __get_str(driver),
+               __get_str(device),
+               __entry->len
+       )
+);
+
 #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
 
 /* we don't want to use include/trace/events */
index 4d41c335ef34e444e19600fa4024b2e1bec4cb72..2fa724e5851a90f767dc7ed8d3e48698cb60fbcb 100644 (file)
@@ -6664,6 +6664,12 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
        kfree(tb);
 }
 
+static void
+ath12k_wmi_diag_event(struct ath12k_base *ab, struct sk_buff *skb)
+{
+       trace_ath12k_wmi_diag(ab, skb->data, skb->len);
+}
+
 static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
 {
        struct wmi_cmd_hdr *cmd_hdr;
@@ -6774,6 +6780,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
        case WMI_VDEV_DELETE_RESP_EVENTID:
                ath12k_vdev_delete_resp_event(ab, skb);
                break;
+       case WMI_DIAG_EVENTID:
+               ath12k_wmi_diag_event(ab, skb);
+               break;
        /* TODO: Add remaining events */
        default:
                ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id);