wlan-ap-Telecominfraproject/feeds/wifi-ax/mac80211/patches/qca/196-ath11k-add-qdss-support-for-qcn9000.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

891 lines
27 KiB
Diff

From 9e72f4fe7c8b6e98e8f4208103d57699085eeec0 Mon Sep 17 00:00:00 2001
From: Jaya Surya Mathavan <jmathava@codeaurora.org>
Date: Tue, 23 Jun 2020 14:20:39 +0530
Subject: [PATCH] ath11k: Add QDSS trace collection support in qcn9000
QDSS trace collection flow:
1. When qdss-start executed via debugfs, host will read
the qdss_trace_config.bin file and send config details to
firmware(QMI_WLANFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_V01).
Then firmware will send the response.
2. The firmware will send the memory request indication
(QMI_WLFW_QDSS_TRACE_REQ_MEM_IND_V01) to host. Then the
host will send the address,size of memory location
details to firmware(QMI_WLFW_QDSS_TRACE_MEM_INFO_REQ_V01).
Then firmware will send the response.
3. Host will send qdss trace mode on request
(QMI_WLANFW_QDSS_TRACE_MODE_REQ_V01) to firmware.After that
firmware will start writing in the memory location given by host.
4. When qdss-stop executed via debugfs, host will send qdss
trace mode off request(QMI_WLANFW_QDSS_TRACE_MODE_REQ_V01) to
firmware, then firmware will stop writing and send trace save
indication(QMI_WLFW_QDSS_TRACE_SAVE_IND_V01) to host.Then the
host will read the trace from same memory location and the dump
will be saved in /sys/class/devcoredump/devcd1/data
command to start/stop qdss trace
echo 1 > /sys/kernel/debug/ath11k/qcn9000_40/trace_qdss
echo 0 > /sys/kernel/debug/ath11k/qcn9000_40/trace_qdss
Signed-off-by: Jaya Surya Mathavan <jmathava@codeaurora.org>
---
drivers/net/wireless/ath/ath11k/core.c | 4 +-
drivers/net/wireless/ath/ath11k/core.h | 1 +
drivers/net/wireless/ath/ath11k/debugfs.c | 78 ++++++
drivers/net/wireless/ath/ath11k/qmi.c | 469 ++++++++++++++++++++++++++++++--
drivers/net/wireless/ath/ath11k/qmi.h | 39 ++-
5 files changed, 560 insertions(+), 31 deletions(-)
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -797,6 +797,7 @@ struct ath11k_base {
struct ath11k_hw_params hw_params;
struct ath11k_bus_params bus_params;
+ bool is_qdss_tracing;
const struct firmware *cal_file;
@@ -997,6 +998,8 @@ void ath11k_core_halt(struct ath11k *ar)
int ath11k_core_resume(struct ath11k_base *ab);
int ath11k_core_suspend(struct ath11k_base *ab);
+void ath11k_coredump_qdss_dump(struct ath11k_base *ab,
+ struct ath11k_qmi_event_qdss_trace_save_data *event_data);
const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,
const char *filename);
--- a/drivers/net/wireless/ath/ath11k/debugfs.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
@@ -742,6 +742,79 @@ static const struct file_operations fops
.llseek = default_llseek,
};
+static ssize_t ath11k_read_trace_qdss(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char buf[] =
+ "'1` - this will start qdss trace collection\n"
+ "`0` - this will stop and save the qdss trace collection\n";
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t
+ath11k_write_trace_qdss(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath11k_base *ab = file->private_data;
+ struct ath11k_pdev *pdev;
+ struct ath11k *ar;
+ int i, ret, radioup = 0;
+ bool qdss_enable;
+
+ if (kstrtobool_from_user(user_buf, count, &qdss_enable))
+ return -EINVAL;
+
+ for (i = 0; i < ab->num_radios; i++) {
+ pdev = &ab->pdevs[i];
+ ar = pdev->ar;
+ if (ar && ar->state == ATH11K_STATE_ON) {
+ radioup = 1;
+ break;
+ }
+ }
+ if (radioup == 0) {
+ ath11k_err(ab, "radio is not up\n");
+ ret = -ENETDOWN;
+ goto exit;
+ }
+
+ if (qdss_enable) {
+ if (ab->is_qdss_tracing) {
+ ret = count;
+ goto exit;
+ }
+ ath11k_config_qdss(ab);
+ } else {
+ if (!ab->is_qdss_tracing) {
+ ret = count;
+ goto exit;
+ }
+ if (!ab->bus_params.fixed_bdf_addr) {
+ ret = ath11k_send_qdss_trace_mode_req(ab,
+ QMI_WLANFW_QDSS_TRACE_OFF_V01);
+ if (ret < 0)
+ ath11k_warn(ab,
+ "Failed to trace QDSS: %d\n", ret);
+ }
+ }
+
+ ret = count;
+
+exit:
+ return ret;
+}
+
+static const struct file_operations fops_trace_qdss = {
+ .read = ath11k_read_trace_qdss,
+ .write = ath11k_write_trace_qdss,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static ssize_t ath11k_write_enable_extd_tx_stats(struct file *file,
const char __user *ubuf,
size_t count, loff_t *ppos)
@@ -1045,6 +1118,9 @@ int ath11k_debugfs_pdev_create(struct at
debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
&fops_simulate_fw_crash);
+ debugfs_create_file("trace_qdss", 0600, ab->debugfs_soc, ab,
+ &fops_trace_qdss);
+
debugfs_create_file("soc_dp_stats", 0600, ab->debugfs_soc, ab,
&fops_soc_dp_stats);
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -12,6 +12,7 @@
#include <linux/of.h>
#include <linux/firmware.h>
#include <linux/devcoredump.h>
+#include <linux/of_address.h>
#define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02
#define HOST_CSTATE_BIT 0x04
@@ -22,10 +23,6 @@ module_param_named(cold_boot_cal, ath11k
MODULE_PARM_DESC(cold_boot_cal,
"Decrease the channel switch time but increase the driver load time (Default: true)");
-unsigned int enable_qdss_trace = 1;
-module_param(enable_qdss_trace, uint, 0644);
-MODULE_PARM_DESC(enable_qdss_trace, "qdss trace enable:1 disable:0");
-
static struct qmi_elem_info qmi_wlanfw_qdss_trace_config_download_req_msg_v01_ei[] = {
{
.data_type = QMI_OPT_FLAG,
@@ -455,6 +452,24 @@ static struct qmi_elem_info qmi_wlanfw_h
mem_cfg_mode),
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x1D,
+ .offset = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+ cal_duration_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x1D,
+ .offset = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+ cal_duration),
+ },
+ {
.data_type = QMI_EOTI,
.array_type = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
@@ -719,20 +734,92 @@ static struct qmi_elem_info qmi_wlanfw_i
.elem_len = 1,
.elem_size = sizeof(u8),
.array_type = NO_ARRAY,
- .tlv_type = 0x20,
+ .tlv_type = 0x1C,
.offset = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
- m3_dump_upload_req_enable_valid),
+ qdss_trace_req_mem_enable_valid),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(u8),
.array_type = NO_ARRAY,
- .tlv_type = 0x20,
+ .tlv_type = 0x1C,
.offset = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
- m3_dump_upload_req_enable),
+ qdss_trace_req_mem_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x1D,
+ .offset = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+ qdss_trace_save_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x1D,
+ .offset = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+ qdss_trace_save_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x1E,
+ .offset = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+ qdss_trace_free_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x1E,
+ .offset = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+ qdss_trace_free_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x1F,
+ .offset = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+ respond_get_info_enable_valid),
},
{
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x1F,
+ .offset = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+ respond_get_info_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x20,
+ .offset = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+ m3_dump_upload_req_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x20,
+ .offset = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+ m3_dump_upload_req_enable),
+ },
+ {
.data_type = QMI_EOTI,
.array_type = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
@@ -1890,6 +1977,85 @@ static struct qmi_elem_info qmi_wlanfw_m
},
};
+struct qmi_elem_info qmi_wlanfw_qdss_trace_save_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct
+ qmi_wlanfw_qdss_trace_save_ind_msg_v01,
+ source),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct
+ qmi_wlanfw_qdss_trace_save_ind_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ qmi_wlanfw_qdss_trace_save_ind_msg_v01,
+ mem_seg_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ qmi_wlanfw_qdss_trace_save_ind_msg_v01,
+ mem_seg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01,
+ .elem_size = sizeof(struct qmi_wlanfw_mem_seg_resp_s_v01),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ qmi_wlanfw_qdss_trace_save_ind_msg_v01,
+ mem_seg),
+ .ei_array = qmi_wlanfw_mem_seg_resp_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct
+ qmi_wlanfw_qdss_trace_save_ind_msg_v01,
+ file_name_valid),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLANFW_MAX_STR_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct
+ qmi_wlanfw_qdss_trace_save_ind_msg_v01,
+ file_name),
+ },
+ {
+ .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)
{
@@ -1971,19 +2137,19 @@ int ath11k_send_qdss_trace_mode_req(stru
req.mode_valid = 1;
req.mode = mode;
req.option_valid = 1;
- req.option = 0;
-
+ req.option = mode == QMI_WLANFW_QDSS_TRACE_OFF_V01 ?
+ QMI_WLANFW_QDSS_STOP_ALL_TRACE : 0;
ret = qmi_txn_init(&ab->qmi.handle, &txn,
- qmi_wlanfw_qdss_trace_mode_resp_msg_v01_ei, &resp);
+ qmi_wlanfw_qdss_trace_mode_resp_msg_v01_ei, &resp);
if (ret < 0)
goto out;
-
ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
QMI_WLANFW_QDSS_TRACE_MODE_REQ_V01,
QMI_WLANFW_QDSS_TRACE_MODE_REQ_MSG_V01_MAX_LEN,
qmi_wlanfw_qdss_trace_mode_req_msg_v01_ei, &req);
if (ret < 0) {
ath11k_warn(ab, "Failed to send QDSS trace mode request,err = %d\n", ret);
+ qmi_txn_cancel(&txn);
goto out;
}
@@ -2001,12 +2167,6 @@ out:
return ret;
}
-static int ath11k_qmi_enable_qdss_trace(struct ath11k_base *ab,
- enum wlfw_qdss_trace_mode_enum_v01 mode)
-{
- return ath11k_send_qdss_trace_mode_req(ab, mode);
-}
-
static int ath11k_qmi_send_qdss_config(struct ath11k_base *ab)
{
struct device *dev = ab->dev;
@@ -2287,6 +2447,11 @@ static void ath11k_qmi_free_target_mem_c
}
ab->qmi.target_mem[i].vaddr = NULL;
}
+
+ if (ab->bus_params.fixed_mem_region && ab->qmi.qdss_mem[0].vaddr) {
+ iounmap(ab->qmi.qdss_mem[0].vaddr);
+ ab->qmi.qdss_mem[0].vaddr = NULL;
+ }
}
static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab)
@@ -2935,21 +3100,12 @@ int ath11k_config_qdss(struct ath11k_bas
if (ab->fw_mode == ATH11K_FIRMWARE_MODE_FTM)
return 0;
- if (enable_qdss_trace) {
- ret = ath11k_qmi_send_qdss_config(ab);
- if (ret < 0) {
- ath11k_warn(ab, "Failed to download QDSS config to FW: %d\n", ret);
- return ret;
- }
- ret = ath11k_qmi_enable_qdss_trace(ab, QMI_WLANFW_QDSS_TRACE_ON_V01);
- if (ret < 0) {
- ath11k_warn(ab, "Failed to enable QDSS trace: %d\n", ret);
- return ret;
- }
- ath11k_info(ab, "QDSS configuration is completed\n");
- }
-
- return 0;
+ ret = ath11k_qmi_send_qdss_config(ab);
+ if (ret < 0)
+ ath11k_warn(ab,
+ "Failed to download QDSS config to FW: %d\n",
+ ret);
+ return ret;
}
int ath11k_qmi_firmware_start(struct ath11k_base *ab,
@@ -3139,6 +3295,23 @@ send_resp:
return;
}
+static void ath11k_qmi_event_qdss_trace_save_hdlr(struct ath11k_qmi *qmi,
+ void *data)
+{
+ struct ath11k_qmi_event_qdss_trace_save_data *event_data = data;
+ struct ath11k_base *ab = qmi->ab;
+
+ if (!ab->qmi.qdss_mem_seg_len) {
+ ath11k_warn(ab, "Memory for QDSS trace is not available\n");
+ return;
+ }
+
+ ath11k_coredump_qdss_dump(ab, event_data);
+
+ ab->qmi.qdss_mem_seg_len = 0;
+ ab->is_qdss_tracing = false;
+}
+
static int
ath11k_qmi_driver_event_post(struct ath11k_qmi *qmi,
enum ath11k_qmi_event_type type,
@@ -3196,6 +3369,173 @@ static int ath11k_qmi_event_mem_request(
return ret;
}
+int ath11k_qmi_pci_alloc_qdss_mem(struct ath11k_qmi *qmi)
+{
+ struct ath11k_base *ab = qmi->ab;
+ struct device *dev = ab->dev;
+ int i;
+ u32 addr = 0;
+
+ if (ab->qmi.qdss_mem_seg_len > 1) {
+ ath11k_warn(ab, "%s: FW requests %d segments, max allowed is 1\n",
+ __func__, ab->qmi.qdss_mem_seg_len);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ab->qmi.qdss_mem_seg_len; i++) {
+ switch (ab->qmi.qdss_mem[i].type) {
+ case QDSS_ETR_MEM_REGION_TYPE:
+ if (ab->qmi.qdss_mem[i].size > QMI_Q6_QDSS_ETR_SIZE_QCN9074) {
+ ath11k_warn(ab, "%s: FW requests more memory 0x%x\n",
+ __func__, ab->qmi.qdss_mem[i].size);
+ return -ENOMEM;
+ }
+
+ if (of_property_read_u32(dev->of_node,
+ "etr-addr", &addr)) {
+ ath11k_warn(ab, "qmi fail to get etr-addr in dt\n");
+ return -ENOMEM;
+ }
+ ab->qmi.qdss_mem[i].paddr = (phys_addr_t)addr;
+ ab->qmi.qdss_mem[i].vaddr =
+ ioremap(ab->qmi.qdss_mem[i].paddr,
+ ab->qmi.qdss_mem[i].size);
+ if (!ab->qmi.qdss_mem[i].vaddr) {
+ ath11k_warn(ab, "WARNING etr-addr remap failed\n");
+ return -ENOMEM;
+ }
+ break;
+ default:
+ ath11k_warn(ab, "qmi ignore invalid qdss mem req type %d\n",
+ ab->qmi.qdss_mem[i].type);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+int ath11k_qmi_qdss_mem_alloc(struct ath11k_qmi *qmi)
+{
+ int ret, i;
+ struct ath11k_base *ab = qmi->ab;
+ struct device_node *dev_node = NULL;
+ struct resource q6_etr;
+
+ if (ab->bus_params.fixed_bdf_addr) {
+ dev_node = of_find_node_by_name(NULL, "q6_etr_dump");
+ if (!dev_node) {
+ ath11k_err(ab, "No q6_etr_dump available in dts\n");
+ return -ENOMEM;
+ }
+ ret = of_address_to_resource(dev_node, 0, &q6_etr);
+ if (ret) {
+ ath11k_err(ab, "Failed to get resource for q6_etr_dump\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < ab->qmi.qdss_mem_seg_len; i++) {
+ ab->qmi.qdss_mem[i].vaddr = NULL;
+ ab->qmi.qdss_mem[i].paddr = q6_etr.start;
+ ab->qmi.qdss_mem[i].size = resource_size(&q6_etr);
+ ab->qmi.qdss_mem[i].type = QDSS_ETR_MEM_REGION_TYPE;
+ }
+ } else {
+ ret = ath11k_qmi_pci_alloc_qdss_mem(qmi);
+ }
+ return ret;
+}
+
+int ath11k_qmi_qdss_trace_mem_info_send_sync(struct ath11k_base *ab)
+{
+ struct qmi_wlanfw_respond_mem_req_msg_v01 *req;
+ struct qmi_wlanfw_respond_mem_resp_msg_v01 resp;
+ struct qmi_txn txn = {};
+ int ret = 0, i;
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ memset(&resp, 0, sizeof(resp));
+ req->mem_seg_len = ab->qmi.qdss_mem_seg_len;
+
+ for (i = 0; i < req->mem_seg_len ; i++) {
+ req->mem_seg[i].addr = ab->qmi.qdss_mem[i].paddr;
+ req->mem_seg[i].size = ab->qmi.qdss_mem[i].size;
+ req->mem_seg[i].type = ab->qmi.qdss_mem[i].type;
+ }
+
+ ret = qmi_txn_init(&ab->qmi.handle, &txn,
+ qmi_wlanfw_respond_mem_resp_msg_v01_ei, &resp);
+
+ if (ret < 0) {
+ ath11k_warn(ab, "Fail to initialize txn for QDSS trace mem request: err %d\n",
+ ret);
+ goto out;
+ }
+
+ ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+ QMI_WLFW_QDSS_TRACE_MEM_INFO_REQ_V01,
+ QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN,
+ qmi_wlanfw_respond_mem_req_msg_v01_ei, req);
+
+ if (ret < 0) {
+ ath11k_warn(ab, "qmi failed to respond memory request, err = %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, "qmi failed memory request, err = %d\n", ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath11k_warn(ab, "Respond mem req failed, result: %d, err: %d\n",
+ resp.resp.result, resp.resp.error);
+ ret = -EINVAL;
+ goto out;
+ }
+out:
+ kfree(req);
+ return ret;
+}
+
+static void ath11k_qmi_event_qdss_trace_req_mem_hdlr(struct ath11k_qmi *qmi)
+{
+ int ret = 0;
+ struct ath11k_base *ab = qmi->ab;
+
+ ret = ath11k_qmi_qdss_mem_alloc(qmi);
+ if (ret < 0) {
+ ath11k_err(ab, "failed to allocate memory for qdss:%d\n", ret);
+ return;
+ }
+
+ ret = ath11k_qmi_qdss_trace_mem_info_send_sync(ab);
+ if (ret < 0) {
+ ath11k_warn(ab,
+ "qdss trace mem info send sync failed:%d\n", ret);
+ return;
+ }
+
+ /* After qdss_trace_mem_info(QMI_WLFW_QDSS_TRACE_MEM_INFO_REQ_V01),
+ * the firmware will take one second at max
+ * for its configuration. We shouldn't send qdss_trace request
+ * before that.
+ */
+ msleep(1000);
+ ret = ath11k_send_qdss_trace_mode_req(ab, QMI_WLANFW_QDSS_TRACE_ON_V01);
+ if (ret < 0) {
+ ath11k_warn(ab, "Failed to enable QDSS trace: %d\n", ret);
+ return;
+ }
+ ab->is_qdss_tracing = true;
+ ath11k_dbg(ab, ATH11K_DBG_QMI, "QDSS configuration is completed and trace started\n");
+}
+
static int ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
{
struct ath11k_base *ab = qmi->ab;
@@ -3329,6 +3669,83 @@ static void ath11k_qmi_m3_dump_upload_re
event_data);
}
+static void ath11k_wlfw_qdss_trace_req_mem_ind_cb(struct qmi_handle *qmi_hdl,
+ struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn,
+ const void *data)
+{
+ struct ath11k_qmi *qmi = container_of(qmi_hdl,
+ struct ath11k_qmi,
+ handle);
+ struct ath11k_base *ab = qmi->ab;
+ const struct qmi_wlanfw_request_mem_ind_msg_v01 *msg = data;
+ int i;
+
+ ath11k_dbg(ab, ATH11K_DBG_QMI, "qdss trace request memory from firmware\n");
+
+ ab->qmi.qdss_mem_seg_len = msg->mem_seg_len;
+ if (msg->mem_seg_len > 1) {
+ ath11k_warn(ab, "%s: FW requests %d segments, overwriting it with 1",
+ __func__, msg->mem_seg_len);
+ ab->qmi.qdss_mem_seg_len = 1;
+ }
+
+ for (i = 0; i < ab->qmi.qdss_mem_seg_len; i++) {
+ ab->qmi.qdss_mem[i].type = msg->mem_seg[i].type;
+ ab->qmi.qdss_mem[i].size = msg->mem_seg[i].size;
+ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi mem seg type %d size %d\n",
+ msg->mem_seg[i].type, msg->mem_seg[i].size);
+ }
+
+ ath11k_qmi_driver_event_post(qmi,
+ ATH11K_QMI_EVENT_QDSS_TRACE_REQ_MEM,
+ NULL);
+}
+
+static void ath11k_wlfw_qdss_trace_save_ind_cb(struct qmi_handle *qmi_hdl,
+ struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn,
+ const void *data)
+{
+ struct ath11k_qmi *qmi = container_of(qmi_hdl,
+ struct ath11k_qmi,
+ handle);
+ struct ath11k_base *ab = qmi->ab;
+ const struct qmi_wlanfw_qdss_trace_save_ind_msg_v01 *ind_msg = data;
+ struct ath11k_qmi_event_qdss_trace_save_data *event_data;
+ int i = 0;
+
+ if (ind_msg->source == 1)
+ return;
+ ath11k_dbg(ab, ATH11K_DBG_QMI, "Received qdss trace save indication\n");
+
+ event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
+ if (!event_data)
+ return;
+
+ if (ind_msg->mem_seg_valid) {
+ if (ind_msg->mem_seg_len > QDSS_TRACE_SEG_LEN_MAX) {
+ ath11k_err(ab, "Invalid seg len %u\n",
+ ind_msg->mem_seg_len);
+ goto free_event_data;
+ }
+
+ event_data->mem_seg_len = ind_msg->mem_seg_len;
+ for (i = 0; i < ind_msg->mem_seg_len; i++) {
+ event_data->mem_seg[i].addr = ind_msg->mem_seg[i].addr;
+ event_data->mem_seg[i].size = ind_msg->mem_seg[i].size;
+ }
+ }
+
+ event_data->total_size = ind_msg->total_size;
+ ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_QDSS_TRACE_SAVE,
+ event_data);
+ return;
+
+free_event_data:
+ kfree(event_data);
+}
+
static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = {
{
.type = QMI_INDICATION,
@@ -3367,6 +3784,23 @@ static const struct qmi_msg_handler ath1
sizeof(struct qmi_wlanfw_m3_dump_upload_req_ind_msg_v01),
.fn = ath11k_qmi_m3_dump_upload_req_ind_cb,
},
+ {
+ .type = QMI_INDICATION,
+ .msg_id = QMI_WLFW_QDSS_TRACE_REQ_MEM_IND_V01,
+ .ei = qmi_wlanfw_request_mem_ind_msg_v01_ei,
+ .decoded_size =
+ sizeof(struct qmi_wlanfw_request_mem_ind_msg_v01),
+ .fn = ath11k_wlfw_qdss_trace_req_mem_ind_cb,
+ },
+ {
+ .type = QMI_INDICATION,
+ .msg_id = QMI_WLFW_QDSS_TRACE_SAVE_IND_V01,
+ .ei = qmi_wlanfw_qdss_trace_save_ind_msg_v01_ei,
+ .decoded_size =
+ sizeof(struct qmi_wlanfw_qdss_trace_save_ind_msg_v01),
+ .fn = ath11k_wlfw_qdss_trace_save_ind_cb,
+ },
+
};
static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl,
@@ -3472,6 +3906,12 @@ static void ath11k_qmi_driver_event_work
case ATH11K_QMI_EVENT_M3_DUMP_UPLOAD_REQ:
ath11k_qmi_event_m3_dump_upload_req(qmi, event->data);
break;
+ case ATH11K_QMI_EVENT_QDSS_TRACE_REQ_MEM:
+ ath11k_qmi_event_qdss_trace_req_mem_hdlr(qmi);
+ break;
+ case ATH11K_QMI_EVENT_QDSS_TRACE_SAVE:
+ ath11k_qmi_event_qdss_trace_save_hdlr(qmi, event->data);
+ break;
default:
ath11k_warn(ab, "invalid event type: %d", event->type);
break;
--- a/drivers/net/wireless/ath/ath11k/qmi.h
+++ b/drivers/net/wireless/ath/ath11k/qmi.h
@@ -42,6 +42,9 @@
#define QMI_WLFW_FW_READY_IND_V01 0x0038
#define QMI_WLFW_M3_DUMP_UPLOAD_DONE_REQ_V01 0x004E
#define QMI_WLFW_M3_DUMP_UPLOAD_REQ_IND_V01 0x004D
+#define QMI_WLFW_QDSS_TRACE_REQ_MEM_IND_V01 0x003F
+#define QMI_Q6_QDSS_ETR_SIZE_QCN9074 0x100000
+#define QMI_WLFW_QDSS_TRACE_SAVE_IND_V01 0x0041
#define QMI_WLANFW_MAX_DATA_SIZE_V01 6144
#define ATH11K_FIRMWARE_MODE_OFF 4
@@ -77,6 +80,8 @@ enum ath11k_qmi_event_type {
ATH11K_QMI_EVENT_POWER_UP,
ATH11K_QMI_EVENT_POWER_DOWN,
ATH11K_QMI_EVENT_M3_DUMP_UPLOAD_REQ,
+ ATH11K_QMI_EVENT_QDSS_TRACE_REQ_MEM,
+ ATH11K_QMI_EVENT_QDSS_TRACE_SAVE,
ATH11K_QMI_EVENT_MAX,
};
@@ -113,7 +118,7 @@ struct target_mem_chunk {
u32 size;
u32 type;
dma_addr_t paddr;
- u32 *vaddr;
+ void *vaddr;
};
struct target_info {
@@ -146,6 +151,8 @@ struct ath11k_qmi {
struct ath11k_qmi_ce_cfg ce_cfg;
struct target_mem_chunk target_mem[ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01];
u32 mem_seg_count;
+ struct target_mem_chunk qdss_mem[ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01];
+ u32 qdss_mem_seg_len;
u32 target_mem_mode;
bool target_mem_delayed;
u8 cal_done;
@@ -195,6 +202,7 @@ struct qmi_wlanfw_m3_dump_upload_done_re
#define QMI_WLANFW_QDSS_TRACE_MODE_REQ_MSG_V01_MAX_LEN 18
#define QMI_WLANFW_QDSS_TRACE_MODE_RESP_MSG_V01_MAX_LEN 7
#define QMI_WLANFW_QDSS_TRACE_MODE_RESP_V01 0x0045
+#define QMI_WLANFW_QDSS_STOP_ALL_TRACE 0x3f
enum wlfw_qdss_trace_mode_enum_v01 {
WLFW_QDSS_TRACE_MODE_ENUM_MIN_VAL_V01 = INT_MIN,
@@ -224,6 +232,7 @@ struct qmi_wlanfw_qdss_trace_mode_resp_m
#define BDF_MEM_REGION_TYPE 0x2
#define M3_DUMP_REGION_TYPE 0x3
#define CALDB_MEM_REGION_TYPE 0x4
+#define QDSS_ETR_MEM_REGION_TYPE 0x6
struct qmi_wlanfw_host_cap_req_msg_v01 {
u8 num_clients_valid;
@@ -316,7 +325,9 @@ struct qmi_wlanfw_ind_register_resp_msg_
#define QMI_WLANFW_REQUEST_MEM_IND_V01 0x0035
#define QMI_WLANFW_RESPOND_MEM_REQ_V01 0x0036
#define QMI_WLANFW_RESPOND_MEM_RESP_V01 0x0036
+#define QMI_WLFW_QDSS_TRACE_MEM_INFO_REQ_V01 0x0040
#define QMI_WLANFW_MAX_NUM_MEM_CFG_V01 2
+#define QMI_WLANFW_MAX_STR_LEN_V01 16
struct qmi_wlanfw_mem_cfg_s_v01 {
u64 offset;
@@ -381,6 +392,29 @@ struct qmi_wlanfw_m3_dump_upload_req_ind
u64 size;
};
+struct qmi_wlanfw_qdss_trace_save_ind_msg_v01 {
+ u32 source;
+ u32 total_size;
+ u8 mem_seg_valid;
+ u32 mem_seg_len;
+ struct qmi_wlanfw_mem_seg_resp_s_v01 mem_seg[ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01];
+ u8 file_name_valid;
+ char file_name[QMI_WLANFW_MAX_STR_LEN_V01 + 1];
+};
+
+#define QDSS_TRACE_SEG_LEN_MAX 32
+
+struct qdss_trace_mem_seg {
+ u64 addr;
+ u32 size;
+};
+
+struct ath11k_qmi_event_qdss_trace_save_data {
+ u32 total_size;
+ u32 mem_seg_len;
+ struct qdss_trace_mem_seg mem_seg[QDSS_TRACE_SEG_LEN_MAX];
+};
+
#define QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN 0
#define QMI_WLANFW_CAP_RESP_MSG_V01_MAX_LEN 235
#define QMI_WLANFW_CAP_REQ_V01 0x0024
@@ -530,7 +564,6 @@ struct qmi_wlanfw_m3_info_resp_msg_v01 {
#define QMI_WLANFW_WLAN_MODE_RESP_V01 0x0022
#define QMI_WLANFW_WLAN_CFG_REQ_V01 0x0023
#define QMI_WLANFW_WLAN_CFG_RESP_V01 0x0023
-#define QMI_WLANFW_MAX_STR_LEN_V01 16
#define QMI_WLANFW_MAX_NUM_CE_V01 12
#define QMI_WLANFW_MAX_NUM_SVC_V01 24
#define QMI_WLANFW_MAX_NUM_SHADOW_REG_V01 24
@@ -582,7 +615,7 @@ int wlfw_send_qdss_trace_config_download
const u8 *buffer, unsigned int len);
int ath11k_send_qdss_trace_mode_req(struct ath11k_base *ab,
- enum wlfw_qdss_trace_mode_enum_v01 mode);
+ enum wlfw_qdss_trace_mode_enum_v01 mode);
int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab);