wlan-ap-Telecominfraproject/feeds/wifi-ax/mac80211/patches/qca/214-ath11k-Enable-WMI-based-FW-Logging.patch
John Crispin 43d7ca31d6 wifi-ax/mac80211: make the 11.4 ath11k work inside the v5.4 kernel
Fixes: WIFI-7570
Signed-off-by: John Crispin <john@phrozen.org>
2022-05-27 10:05:52 +02:00

372 lines
11 KiB
Diff

From 653734f16158d44b1bc6977536c1a93061b74e9c Mon Sep 17 00:00:00 2001
From: Sriram R <srirrama@codeaurora.org>
Date: Mon, 5 Oct 2020 17:17:21 +0530
Subject: [PATCH] ath11k: Enable WMI based FW Logging
In devices such as QCN9000, FW log data from firmware is sent via WMI Events
(WMI_DIAG_EVENTID). This data is then posted to the userspace
via NL testmode cmd as a fwlog attribute.
The logging is enabled during bootup using qmi transaction and cannot be disabled
during runtime.
Signed-off-by: Sriram R <srirrama@codeaurora.org>
---
drivers/net/wireless/ath/ath11k/core.c | 12 ++++
drivers/net/wireless/ath/ath11k/hw.h | 1 +
drivers/net/wireless/ath/ath11k/qmi.c | 92 ++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath11k/qmi.h | 13 ++++
drivers/net/wireless/ath/ath11k/testmode.c | 40 ++++++++++++
drivers/net/wireless/ath/ath11k/testmode.h | 6 ++
drivers/net/wireless/ath/ath11k/testmode_i.h | 3 +
drivers/net/wireless/ath/ath11k/wmi.c | 26 ++++++++
8 files changed, 193 insertions(+)
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -90,6 +90,7 @@ static const struct ath11k_hw_params ath
.supports_suspend = false,
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
.reo_dest_ring_map_shift = HAL_REO_DEST_RING_CTRL_HASH_RING_SHIFT,
+ .ce_fwlog_enable = false,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -136,6 +137,7 @@ static const struct ath11k_hw_params ath
.supports_suspend = false,
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
.reo_dest_ring_map_shift = HAL_REO_DEST_RING_CTRL_HASH_RING_SHIFT,
+ .ce_fwlog_enable = false,
},
{
.name = "qca6390 hw2.0",
@@ -177,6 +179,7 @@ static const struct ath11k_hw_params ath
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
.spectral_fft_sz = 2,
.reo_dest_ring_map_shift = HAL_REO_DEST_RING_CTRL_HASH_RING_SHIFT,
+ .ce_fwlog_enable = false,
},
{
.name = "qcn9074 hw1.0",
@@ -220,6 +223,7 @@ static const struct ath11k_hw_params ath
.spectral_summary_pad_sz = 16,
.spectral_fft_hdr_len = 24,
.reo_dest_ring_map_shift = HAL_REO_DEST_RING_CTRL_HASH_RING_SHIFT,
+ .ce_fwlog_enable = true,
},
{
.hw_rev = ATH11K_HW_IPQ5018,
@@ -258,6 +262,7 @@ static const struct ath11k_hw_params ath
.spectral_summary_pad_sz = 16,
.spectral_fft_hdr_len = 24,
.reo_dest_ring_map_shift = HAL_IPQ5018_REO_DEST_RING_CTRL_HASH_RING_SHIFT,
+ .ce_fwlog_enable = false,
},
};
@@ -944,6 +949,9 @@ int ath11k_core_ssr_notifier_cb(struct n
return 0;
}
#endif
+unsigned int ce_fwlog = 1;
+module_param_named(ce_fwlog, ce_fwlog, uint, 0644);
+MODULE_PARM_DESC(ce_fwlog, "Enable/Disable CE based FW logging");
int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab)
{
@@ -1004,6 +1012,14 @@ int ath11k_core_qmi_firmware_ready(struc
ath11k_config_qdss(ab);
+ if (ab->hw_params.ce_fwlog_enable && ce_fwlog) {
+ ret = ath11k_enable_fwlog(ab);
+ if (ret < 0) {
+ ath11k_err(ab, "failed to enable fwlog: %d\n", ret);
+ goto err_core_stop;
+ }
+ }
+
mutex_unlock(&ab->core_lock);
return 0;
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -190,6 +190,7 @@ struct ath11k_hw_params {
u32 hal_desc_sz;
u32 m3_addr;
u8 reo_dest_ring_map_shift;
+ bool ce_fwlog_enable;
};
struct ath11k_hw_ops {
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -2056,6 +2056,50 @@ struct qmi_elem_info qmi_wlanfw_qdss_tra
},
};
+struct qmi_elem_info wlfw_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 wlfw_ini_req_msg_v01,
+ enablefwlog_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ini_req_msg_v01,
+ enablefwlog),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .array_type = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct qmi_elem_info wlfw_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 wlfw_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,
+ },
+};
+
int wlfw_send_qdss_trace_config_download_req(struct ath11k_base *ab,
const u8 *buffer, unsigned int file_len)
{
@@ -3949,6 +3993,55 @@ static void ath11k_qmi_driver_event_work
spin_unlock(&qmi->event_lock);
}
+int ath11k_enable_fwlog(struct ath11k_base *ab)
+{
+ struct wlfw_ini_req_msg_v01 *req;
+ struct wlfw_ini_resp_msg_v01 resp;
+ struct qmi_txn txn = {};
+ int ret = 0;
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ memset(&resp, 0, sizeof(resp));
+
+ req->enablefwlog_valid = 1;
+ req->enablefwlog = 1;
+
+ ret = qmi_txn_init(&ab->qmi.handle, &txn,
+ wlfw_ini_resp_msg_v01_ei, &resp);
+ if (ret < 0)
+ goto out;
+
+ ret = qmi_send_request(&ab->qmi.handle, 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) {
+ ath11k_warn(ab, "Failed to send init request for enabling fwlog = %d\n", ret);
+ qmi_txn_cancel(&txn);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
+ if (ret < 0) {
+ ath11k_warn(ab, "fwlog enable wait for resp failed: %d\n", ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath11k_warn(ab, "fwlog enable request failed, result: %d, err: %d\n",
+ resp.resp.result, resp.resp.error);
+ ret = -EINVAL;
+ goto out;
+ }
+out:
+ kfree(req);
+ return ret;
+}
+
int ath11k_qmi_init_service(struct ath11k_base *ab)
{
int ret;
--- a/drivers/net/wireless/ath/ath11k/qmi.h
+++ b/drivers/net/wireless/ath/ath11k/qmi.h
@@ -204,6 +204,18 @@ struct qmi_wlanfw_m3_dump_upload_done_re
struct qmi_response_type_v01 resp;
};
+struct wlfw_ini_req_msg_v01 {
+ u8 enablefwlog_valid;
+ u8 enablefwlog;
+};
+
+struct wlfw_ini_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define QMI_WLFW_INI_REQ_V01 0x002F
+#define WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN 4
+
#define QMI_WLANFW_QDSS_TRACE_MODE_REQ_V01 0x0045
#define QMI_WLANFW_QDSS_TRACE_MODE_REQ_MSG_V01_MAX_LEN 18
#define QMI_WLANFW_QDSS_TRACE_MODE_RESP_MSG_V01_MAX_LEN 7
@@ -623,6 +635,7 @@ int wlfw_send_qdss_trace_config_download
int ath11k_send_qdss_trace_mode_req(struct ath11k_base *ab,
enum wlfw_qdss_trace_mode_enum_v01 mode);
int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab);
+int ath11k_enable_fwlog(struct ath11k_base *ab);
#endif
--- a/drivers/net/wireless/ath/ath11k/testmode.c
+++ b/drivers/net/wireless/ath/ath11k/testmode.c
@@ -19,8 +19,48 @@ static const struct nla_policy ath11k_tm
[ATH11K_TM_ATTR_WMI_CMDID] = { .type = NLA_U32 },
[ATH11K_TM_ATTR_VERSION_MAJOR] = { .type = NLA_U32 },
[ATH11K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 },
+ [ATH11K_TM_ATTR_FWLOG] = { .type = NLA_BINARY,
+ .len = ATH11K_FWLOG_MAX_LEN },
};
+void ath11k_fwlog_write(struct ath11k_base *ab, u8 *data, int len)
+{
+ struct sk_buff *nl_skb;
+ int ret, i;
+ struct ath11k *ar = NULL;
+ struct ath11k_pdev *pdev;
+
+ for (i = 0; i < ab->num_radios; i++) {
+ pdev = &ab->pdevs[i];
+ if (pdev && pdev->ar) {
+ ar = pdev->ar;
+ break;
+ }
+ }
+
+ if (!ar)
+ return;
+
+ nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
+ len, GFP_ATOMIC);
+ if (!nl_skb) {
+ ath11k_warn(ab,
+ "failed to allocate skb for fwlog event\n");
+ return;
+ }
+
+ ret = nla_put(nl_skb, ATH11K_TM_ATTR_FWLOG, len, data);
+ if (ret) {
+ ath11k_warn(ab,
+ "failed to to put fwlog wmi event to nl: %d\n",
+ ret);
+ kfree_skb(nl_skb);
+ return;
+ }
+
+ cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
+}
+
/* Returns true if callee consumes the skb and the skb should be discarded.
* Returns false if skb is not used. Does not sleep.
*/
--- a/drivers/net/wireless/ath/ath11k/testmode.h
+++ b/drivers/net/wireless/ath/ath11k/testmode.h
@@ -28,6 +28,7 @@ bool ath11k_tm_event_wmi(struct ath11k_b
int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
void *data, int len);
+void ath11k_fwlog_write(struct ath11k_base *ab, u8 *data, int len);
#else
static inline bool ath11k_tm_event_wmi(struct ath11k_base *ab, u32 cmd_id,
@@ -43,4 +44,9 @@ static inline int ath11k_tm_cmd(struct i
return 0;
}
+static inline void ath11k_fwlog_write(struct ath11k_base *ab, u8 *data,
+ int len)
+{
+
+}
#endif
--- a/drivers/net/wireless/ath/ath11k/testmode_i.h
+++ b/drivers/net/wireless/ath/ath11k/testmode_i.h
@@ -16,6 +16,8 @@
#define ATH11K_TM_DATA_MAX_LEN 5000
#define ATH11K_FTM_EVENT_MAX_BUF_LENGTH 2048
+#define ATH11K_FWLOG_MAX_LEN 2048
+
enum ath11k_tm_attr {
__ATH11K_TM_ATTR_INVALID = 0,
ATH11K_TM_ATTR_CMD = 1,
@@ -24,6 +26,7 @@ enum ath11k_tm_attr {
ATH11K_TM_ATTR_VERSION_MAJOR = 4,
ATH11K_TM_ATTR_VERSION_MINOR = 5,
ATH11K_TM_ATTR_WMI_OP_VERSION = 6,
+ ATH11K_TM_ATTR_FWLOG = 7,
/* keep last */
__ATH11K_TM_ATTR_AFTER_LAST,
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -8237,6 +8237,29 @@ static void ath11k_wmi_wds_peer_event(st
wds_addr_arg.dst_macaddr);
}
+static void ath11k_wmi_diag_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+ const struct wmi_tlv *tlv;
+ u16 tlv_tag, tlv_len;
+ uint32_t *dev_id;
+ u8 *data;
+
+ tlv = (struct wmi_tlv *)skb->data;
+ tlv_tag = FIELD_GET(WMI_TLV_TAG, tlv->header);
+ tlv_len = FIELD_GET(WMI_TLV_LEN, tlv->header);
+
+ if (tlv_tag == WMI_TAG_ARRAY_BYTE) {
+ data = skb->data + sizeof(struct wmi_tlv);
+ dev_id = (uint32_t *)data;
+ *dev_id = ab->hw_params.hw_rev;
+ } else {
+ ath11k_warn(ab, "WMI Diag Event missing required tlv\n");
+ return;
+ }
+
+ ath11k_fwlog_write(ab,data, tlv_len);
+}
+
static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
{
struct wmi_cmd_hdr *cmd_hdr;
@@ -8365,6 +8388,9 @@ static void ath11k_wmi_tlv_op_rx(struct
case WMI_MUEDCA_PARAMS_CONFIG_EVENTID:
ath11k_wmi_pdev_update_muedca_params_status_event(ab, skb);
break;
+ case WMI_DIAG_EVENTID:
+ ath11k_wmi_diag_event(ab, skb);
+ break;
/* TODO: Add remaining events */
default:
ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id);