mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-21 03:13:17 +00:00
This series is based on * 2020-07-10 ipq6018-ilq-11-0_qca_oem-034672b0676c37b1f4519e5720e18e95fe6236ef Add support for * qsdk kernel/v4.4 * qsdk ethernet subsystem * v5.7 ath11k backport + QualComm staging patches (wlan_ap_1.0) * ath11k-firmware * hostapd/iw/... Feature support * full boot, system detection * sysupgrade to nand * HE support via latest hostapd * driver support for usb, crypto, hwmon, cpufreq, ... Missing * NSS/HW flow offloading - FW blob is not redistributable Using the qsdk v4.4 is an intermediate solution while the vanilla is being tested. Vanilla kernel is almost on feature par. Work has already started to upstream the ethernet and switch drivers. Once complete the target will be fully upstream. Signed-off-by: John Crispin <john@phrozen.org>
631 lines
17 KiB
Diff
631 lines
17 KiB
Diff
--- a/drivers/net/wireless/ath/ath11k/qmi.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
|
|
@@ -8,6 +8,7 @@
|
|
#include "debug.h"
|
|
#include <linux/of.h>
|
|
#include <linux/firmware.h>
|
|
+#include <linux/devcoredump.h>
|
|
|
|
/* set the default max assoc sta to max supported by driver */
|
|
bool enable_cold_boot_cal = 0;
|
|
@@ -507,6 +508,24 @@ static struct qmi_elem_info qmi_wlanfw_h
|
|
.ei_array = qmi_response_type_v01_ei,
|
|
},
|
|
{
|
|
+ .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,
|
|
@@ -1916,6 +1935,87 @@ static struct qmi_elem_info qmi_wlanfw_c
|
|
},
|
|
};
|
|
|
|
+static struct qmi_elem_info qmi_wlanfw_m3_dump_upload_req_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_m3_dump_upload_req_ind_msg_v01,
|
|
+ pdev_id),
|
|
+ },
|
|
+ {
|
|
+ .data_type = QMI_UNSIGNED_8_BYTE,
|
|
+ .elem_len = 1,
|
|
+ .elem_size = sizeof(u64),
|
|
+ .array_type = NO_ARRAY,
|
|
+ .tlv_type = 0x02,
|
|
+ .offset = offsetof(struct qmi_wlanfw_m3_dump_upload_req_ind_msg_v01,
|
|
+ addr),
|
|
+ },
|
|
+ {
|
|
+ .data_type = QMI_UNSIGNED_8_BYTE,
|
|
+ .elem_len = 1,
|
|
+ .elem_size = sizeof(u64),
|
|
+ .array_type = NO_ARRAY,
|
|
+ .tlv_type = 0x03,
|
|
+ .offset = offsetof(struct qmi_wlanfw_m3_dump_upload_req_ind_msg_v01,
|
|
+ size),
|
|
+ },
|
|
+ {
|
|
+ .data_type = QMI_EOTI,
|
|
+ .array_type = NO_ARRAY,
|
|
+ .tlv_type = QMI_COMMON_TLV_TYPE,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct qmi_elem_info qmi_wlanfw_m3_dump_upload_done_req_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_m3_dump_upload_done_req_msg_v01,
|
|
+ pdev_id),
|
|
+ },
|
|
+ {
|
|
+ .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_m3_dump_upload_done_req_msg_v01,
|
|
+ status),
|
|
+ },
|
|
+ {
|
|
+ .data_type = QMI_EOTI,
|
|
+ .array_type = NO_ARRAY,
|
|
+ .tlv_type = QMI_COMMON_TLV_TYPE,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct qmi_elem_info qmi_wlanfw_m3_dump_upload_done_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_m3_dump_upload_done_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)
|
|
{
|
|
@@ -2171,6 +2271,8 @@ static int ath11k_qmi_fw_ind_register_se
|
|
req->qdss_trace_free_enable = 1;
|
|
req->pin_connect_result_enable_valid = 0;
|
|
req->pin_connect_result_enable = 0;
|
|
+ req->m3_dump_upload_req_enable_valid = 1;
|
|
+ req->m3_dump_upload_req_enable = 1;
|
|
|
|
ret = qmi_txn_init(handle, &txn,
|
|
qmi_wlanfw_ind_register_resp_msg_v01_ei, resp);
|
|
@@ -2327,6 +2429,22 @@ static int ath11k_qmi_assign_target_mem_
|
|
ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
|
|
idx++;
|
|
break;
|
|
+ case M3_DUMP_REGION_TYPE:
|
|
+ if (!ab->qmi.target_mem[i].size) {
|
|
+ ath11k_info(ab, "qmi mem size is zero\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ if (ab->qmi.target_mem[i].size > ATH11K_QMI_M3_DUMP_SIZE) {
|
|
+ ath11k_warn(ab, "qmi mem size is low to dump m3 ssr\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
|
|
+ ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
|
|
+ ab->qmi.target_mem[idx].paddr = ab->hw_params.m3_addr;
|
|
+ ab->qmi.target_mem[idx].vaddr =
|
|
+ (unsigned int)ab->qmi.target_mem[idx].paddr;
|
|
+ idx++;
|
|
+ break;
|
|
default:
|
|
ath11k_warn(ab, "qmi ignore invalid mem req type %d\n",
|
|
ab->qmi.target_mem[i].type);
|
|
@@ -2889,6 +3007,123 @@ int ath11k_qmi_process_coldboot_calibrat
|
|
return 0;
|
|
}
|
|
|
|
+static int ath11k_qmi_m3_dump_upload_done_ind_send(struct ath11k_base *ab,
|
|
+ u32 pdev_id, int status)
|
|
+{
|
|
+ struct qmi_wlanfw_m3_dump_upload_done_req_msg_v01 *req;
|
|
+ struct qmi_wlanfw_m3_dump_upload_done_resp_msg_v01 *resp;
|
|
+ struct qmi_txn txn = {};
|
|
+ int ret = 0;
|
|
+
|
|
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
|
|
+ if (!req)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ resp = kzalloc(sizeof(*resp), GFP_KERNEL);
|
|
+ if (!resp) {
|
|
+ kfree(req);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ req->pdev_id = pdev_id;
|
|
+ req->status = status;
|
|
+
|
|
+ ret = qmi_txn_init(&ab->qmi.handle, &txn,
|
|
+ qmi_wlanfw_m3_dump_upload_done_resp_msg_v01_ei, resp);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ ret =
|
|
+ qmi_send_request(&ab->qmi.handle, NULL, &txn,
|
|
+ QMI_WLFW_M3_DUMP_UPLOAD_DONE_REQ_V01,
|
|
+ QMI_WLANFW_M3_DUMP_UPLOAD_DONE_REQ_MSG_V01_MAX_MSG_LEN,
|
|
+ qmi_wlanfw_m3_dump_upload_done_req_msg_v01_ei, req);
|
|
+ if (ret < 0) {
|
|
+ qmi_txn_cancel(&txn);
|
|
+ ath11k_warn(ab, "Failed to send M3 dump upload done request, err %d\n",
|
|
+ ret);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
|
|
+ ath11k_warn(ab, "qmi M3 upload done req failed, result: %d, err: %d\n",
|
|
+ resp->resp.result, resp->resp.error);
|
|
+ ret = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+ ath11k_info(ab, "qmi m3 dump uploaded\n");
|
|
+
|
|
+out:
|
|
+ kfree(req);
|
|
+ kfree(resp);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void ath11k_qmi_event_m3_dump_upload_req(struct ath11k_qmi *qmi,
|
|
+ void *data)
|
|
+{
|
|
+ struct ath11k_base *ab = qmi->ab;
|
|
+ struct target_mem_chunk *target_mem = ab->qmi.target_mem;
|
|
+ struct ath11k_qmi_m3_dump_upload_req_data *event_data = data;
|
|
+ struct ath11k_qmi_m3_dump_data *m3_dump_data;
|
|
+ void *dump;
|
|
+ int i, ret = 0;
|
|
+
|
|
+ m3_dump_data = kzalloc(sizeof(*m3_dump_data), GFP_KERNEL);
|
|
+ if (!m3_dump_data)
|
|
+ return;
|
|
+
|
|
+ dump = vzalloc(event_data->size);
|
|
+ if (!dump) {
|
|
+ kfree(m3_dump_data);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < ab->qmi.mem_seg_count; i++) {
|
|
+ if (target_mem[i].paddr == event_data->addr &&
|
|
+ event_data->size <= target_mem[i].size)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (i == ab->qmi.mem_seg_count) {
|
|
+ ath11k_warn(ab, "qmi invalid paddr from firmware for M3 dump\n");
|
|
+ ret = -EINVAL;
|
|
+ vfree(dump);
|
|
+ goto send_resp;
|
|
+ }
|
|
+
|
|
+ m3_dump_data->addr = ioremap(target_mem[i].paddr, target_mem[i].size);
|
|
+ if (!m3_dump_data->addr) {
|
|
+ ath11k_warn(ab, "qmi failed to ioremap M3 dump region\n");
|
|
+ ret = -ENOMEM;
|
|
+ vfree(dump);
|
|
+ goto send_resp;
|
|
+ }
|
|
+
|
|
+ m3_dump_data->size = event_data->size;
|
|
+ m3_dump_data->pdev_id = event_data->pdev_id;
|
|
+ m3_dump_data->timestamp = ktime_to_ms(ktime_get());
|
|
+
|
|
+ memcpy(dump, m3_dump_data->addr, m3_dump_data->size);
|
|
+
|
|
+ dev_coredumpv(ab->dev, dump, le32_to_cpu(m3_dump_data->size),
|
|
+ GFP_KERNEL);
|
|
+
|
|
+ iounmap(m3_dump_data->addr);
|
|
+
|
|
+send_resp:
|
|
+ ret = ath11k_qmi_m3_dump_upload_done_ind_send(ab, event_data->pdev_id, ret);
|
|
+ if (ret < 0)
|
|
+ ath11k_warn(ab, "qmi M3 dump upload done failed\n");
|
|
+
|
|
+ kfree(m3_dump_data);
|
|
+ return;
|
|
+}
|
|
+
|
|
static int
|
|
ath11k_qmi_driver_event_post(struct ath11k_qmi *qmi,
|
|
enum ath11k_qmi_event_type type,
|
|
@@ -3042,6 +3277,30 @@ static void ath11k_qmi_msg_cold_boot_cal
|
|
ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi cold boot calibration done\n");
|
|
}
|
|
|
|
+static void ath11k_qmi_m3_dump_upload_req_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_m3_dump_upload_req_ind_msg_v01 *msg = data;
|
|
+ struct ath11k_qmi_m3_dump_upload_req_data *event_data;
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi m3 dump memory request\n");
|
|
+
|
|
+ event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
|
|
+ if (!event_data)
|
|
+ return;
|
|
+
|
|
+ event_data->pdev_id = msg->pdev_id;
|
|
+ event_data->addr = msg->addr;
|
|
+ event_data->size = msg->size;
|
|
+
|
|
+ ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_M3_DUMP_UPLOAD_REQ,
|
|
+ event_data);
|
|
+}
|
|
+
|
|
static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = {
|
|
{
|
|
.type = QMI_INDICATION,
|
|
@@ -3072,6 +3331,14 @@ static const struct qmi_msg_handler ath1
|
|
sizeof(struct qmi_wlanfw_fw_cold_cal_done_ind_msg_v01),
|
|
.fn = ath11k_qmi_msg_cold_boot_cal_done_cb,
|
|
},
|
|
+ {
|
|
+ .type = QMI_INDICATION,
|
|
+ .msg_id = QMI_WLFW_M3_DUMP_UPLOAD_REQ_IND_V01,
|
|
+ .ei = qmi_wlanfw_m3_dump_upload_req_ind_msg_v01_ei,
|
|
+ .decoded_size =
|
|
+ sizeof(struct qmi_wlanfw_m3_dump_upload_req_ind_msg_v01),
|
|
+ .fn = ath11k_qmi_m3_dump_upload_req_ind_cb,
|
|
+ },
|
|
};
|
|
|
|
static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl,
|
|
@@ -3162,6 +3429,9 @@ static void ath11k_qmi_driver_event_work
|
|
break;
|
|
case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE:
|
|
break;
|
|
+ case ATH11K_QMI_EVENT_M3_DUMP_UPLOAD_REQ:
|
|
+ ath11k_qmi_event_m3_dump_upload_req(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
|
|
@@ -36,11 +36,16 @@
|
|
#define ATH11K_QMI_DEFAULT_QDSS_CONFIG_FILE_NAME "qdss_trace_config.bin"
|
|
#define NODE_ID_BASE 0x27
|
|
#define FW_ID_BASE 7
|
|
+#define ATH11K_QMI_IPQ8074_M3_DUMP_ADDRESS 0x51000000
|
|
+#define ATH11K_QMI_IPQ6018_M3_DUMP_ADDRESS 0x50100000
|
|
+#define ATH11K_QMI_M3_DUMP_SIZE 0x100000
|
|
|
|
#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
|
|
#define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037
|
|
#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x0021
|
|
#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_WLANFW_MAX_DATA_SIZE_V01 6144
|
|
#define ATH11K_FIRMWARE_MODE_OFF 4
|
|
@@ -71,6 +76,7 @@ enum ath11k_qmi_event_type {
|
|
ATH11K_QMI_EVENT_FORCE_FW_ASSERT,
|
|
ATH11K_QMI_EVENT_POWER_UP,
|
|
ATH11K_QMI_EVENT_POWER_DOWN,
|
|
+ ATH11K_QMI_EVENT_M3_DUMP_UPLOAD_REQ,
|
|
ATH11K_QMI_EVENT_MAX,
|
|
};
|
|
|
|
@@ -80,6 +86,13 @@ struct ath11k_qmi_driver_event {
|
|
void *data;
|
|
};
|
|
|
|
+struct ath11k_qmi_m3_dump_data {
|
|
+ u32 pdev_id;
|
|
+ u32 size;
|
|
+ u64 timestamp;
|
|
+ char *addr;
|
|
+};
|
|
+
|
|
struct ath11k_qmi_ce_cfg {
|
|
const struct ce_pipe_config *tgt_ce;
|
|
int tgt_ce_len;
|
|
@@ -140,6 +153,12 @@ struct ath11k_qmi {
|
|
unsigned int service_ins_id;
|
|
};
|
|
|
|
+struct ath11k_qmi_m3_dump_upload_req_data {
|
|
+ u32 pdev_id;
|
|
+ u64 addr;
|
|
+ u64 size;
|
|
+};
|
|
+
|
|
#define QMI_WLANFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_MSG_V01_MAX_LEN 6167
|
|
#define QMI_WLANFW_QDSS_TRACE_CONFIG_DOWNLOAD_RESP_MSG_V01_MAX_LEN 7
|
|
#define QMI_WLANFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_V01 0x0044
|
|
@@ -161,6 +180,15 @@ struct qmi_wlanfw_qdss_trace_config_down
|
|
struct qmi_response_type_v01 resp;
|
|
};
|
|
|
|
+struct qmi_wlanfw_m3_dump_upload_done_req_msg_v01 {
|
|
+ u32 pdev_id;
|
|
+ u32 status;
|
|
+};
|
|
+
|
|
+struct qmi_wlanfw_m3_dump_upload_done_resp_msg_v01 {
|
|
+ struct qmi_response_type_v01 resp;
|
|
+};
|
|
+
|
|
#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
|
|
@@ -192,6 +220,7 @@ struct qmi_wlanfw_qdss_trace_mode_resp_m
|
|
#define QMI_IPQ8074_FW_MEM_MODE 0xFF
|
|
#define HOST_DDR_REGION_TYPE 0x1
|
|
#define BDF_MEM_REGION_TYPE 0x2
|
|
+#define M3_DUMP_REGION_TYPE 0x3
|
|
#define CALDB_MEM_REGION_TYPE 0x4
|
|
#define QMI_WLFW_MAX_PLATFORM_NAME_LEN_V01 64
|
|
|
|
@@ -349,6 +378,12 @@ struct qmi_wlanfw_fw_cold_cal_done_ind_m
|
|
char placeholder;
|
|
};
|
|
|
|
+struct qmi_wlanfw_m3_dump_upload_req_ind_msg_v01 {
|
|
+ u32 pdev_id;
|
|
+ u64 addr;
|
|
+ u64 size;
|
|
+};
|
|
+
|
|
#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
|
|
@@ -479,6 +514,8 @@ struct qmi_wlanfw_bdf_download_resp_msg_
|
|
#define QMI_WLANFW_M3_INFO_RESP_V01 0x003C
|
|
#define QMI_WLANFW_M3_INFO_REQ_V01 0x003C
|
|
|
|
+#define QMI_WLANFW_M3_DUMP_UPLOAD_DONE_REQ_MSG_V01_MAX_MSG_LEN 14
|
|
+
|
|
struct qmi_wlanfw_m3_info_req_msg_v01 {
|
|
u64 addr;
|
|
u32 size;
|
|
--- a/drivers/net/wireless/ath/ath11k/core.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.h
|
|
@@ -453,6 +453,7 @@ struct ath11k_debug {
|
|
bool is_pkt_logging;
|
|
#endif
|
|
u32 rx_filter;
|
|
+ bool enable_m3_dump;
|
|
};
|
|
|
|
struct ath11k_per_peer_tx_stats {
|
|
--- a/drivers/net/wireless/ath/ath11k/debug.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/debug.c
|
|
@@ -1715,6 +1715,68 @@ static const struct file_operations fops
|
|
.open = simple_open
|
|
};
|
|
|
|
+static ssize_t ath11k_write_enable_m3_dump(struct file *file,
|
|
+ const char __user *ubuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ bool enable;
|
|
+ int ret;
|
|
+
|
|
+ if (kstrtobool_from_user(ubuf, count, &enable))
|
|
+ return -EINVAL;
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+
|
|
+ if (ar->state != ATH11K_STATE_ON) {
|
|
+ ret = -ENETDOWN;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ if (enable == ar->debug.enable_m3_dump) {
|
|
+ ret = count;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ ret = ath11k_wmi_pdev_m3_dump_enable(ar, enable);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ar->ab,
|
|
+ "failed to enable m3 ssr dump %d\n",
|
|
+ ret);
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ ar->debug.enable_m3_dump = enable;
|
|
+ ret = count;
|
|
+
|
|
+exit:
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static ssize_t ath11k_read_enable_m3_dump(struct file *file,
|
|
+ char __user *ubuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ char buf[32];
|
|
+ size_t len = 0;
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
|
|
+ ar->debug.enable_m3_dump);
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+
|
|
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
|
|
+
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_enable_m3_dump = {
|
|
+ .read = ath11k_read_enable_m3_dump,
|
|
+ .write = ath11k_write_enable_m3_dump,
|
|
+ .open = simple_open
|
|
+};
|
|
+
|
|
int ath11k_debug_register(struct ath11k *ar)
|
|
{
|
|
struct ath11k_base *ab = ar->ab;
|
|
@@ -1771,6 +1833,10 @@ int ath11k_debug_register(struct ath11k
|
|
&ar->dfs_block_radar_events);
|
|
}
|
|
|
|
+ debugfs_create_file("enable_m3_dump", 0644,
|
|
+ ar->debug.debugfs_pdev, ar,
|
|
+ &fops_enable_m3_dump);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
|
@@ -7181,6 +7181,36 @@ int ath11k_wmi_simulate_radar(struct ath
|
|
return ath11k_wmi_send_unit_test_cmd(ar, wmi_ut, dfs_args);
|
|
}
|
|
|
|
+int ath11k_wmi_pdev_m3_dump_enable(struct ath11k *ar, u32 enable) {
|
|
+ struct ath11k_vif *arvif;
|
|
+ u32 m3_args[WMI_M3_MAX_TEST_ARGS];
|
|
+ struct wmi_unit_test_cmd wmi_ut;
|
|
+ bool arvif_found = false;
|
|
+
|
|
+ list_for_each_entry(arvif, &ar->arvifs, list) {
|
|
+ if (arvif->is_started) {
|
|
+ arvif_found = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!arvif_found)
|
|
+ return -EINVAL;
|
|
+
|
|
+ m3_args[WMI_M3_TEST_CMDID] = WMI_DBG_ENABLE_M3_SSR;
|
|
+ m3_args[WMI_M3_TEST_ENABLE] = enable;
|
|
+
|
|
+ wmi_ut.vdev_id = arvif->vdev_id;
|
|
+ wmi_ut.module_id = WMI_M3_UNIT_TEST_MODULE;
|
|
+ wmi_ut.num_args = WMI_M3_MAX_TEST_ARGS;
|
|
+ wmi_ut.diag_token = WMI_M3_UNIT_TEST_TOKEN;
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "%s M3 SSR dump\n",
|
|
+ enable ? "Enabling" : "Disabling");
|
|
+
|
|
+ return ath11k_wmi_send_unit_test_cmd(ar, wmi_ut, m3_args);
|
|
+}
|
|
+
|
|
int ath11k_wmi_connect(struct ath11k_base *ab)
|
|
{
|
|
u32 i;
|
|
--- a/drivers/net/wireless/ath/ath11k/wmi.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
|
|
@@ -2055,6 +2055,11 @@ enum wmi_tlv_service {
|
|
|
|
};
|
|
|
|
+enum wmi_unit_test_cmdid {
|
|
+ /* TODO: Add the remaining cmd ids if needed */
|
|
+ WMI_DBG_ENABLE_M3_SSR = 36,
|
|
+};
|
|
+
|
|
enum {
|
|
WMI_SMPS_FORCED_MODE_NONE = 0,
|
|
WMI_SMPS_FORCED_MODE_DISABLED,
|
|
@@ -3884,6 +3889,15 @@ struct wmi_dfs_unit_test_arg {
|
|
u32 radar_param;
|
|
};
|
|
|
|
+#define WMI_M3_UNIT_TEST_MODULE 0x22
|
|
+#define WMI_M3_UNIT_TEST_TOKEN 0
|
|
+
|
|
+enum wmi_m3_test_args_idx {
|
|
+ WMI_M3_TEST_CMDID,
|
|
+ WMI_M3_TEST_ENABLE,
|
|
+ WMI_M3_MAX_TEST_ARGS,
|
|
+};
|
|
+
|
|
struct wmi_unit_test_cmd {
|
|
u32 tlv_header;
|
|
u32 vdev_id;
|
|
@@ -5375,4 +5389,5 @@ int ath11k_wmi_send_obss_color_collision
|
|
int ath11k_wmi_send_bss_color_change_enable_cmd(struct ath11k *ar, u32 vdev_id,
|
|
bool enable);
|
|
int ath11k_wmi_pdev_lro_cfg(struct ath11k *ar, int pdev_id);
|
|
+int ath11k_wmi_pdev_m3_dump_enable(struct ath11k *ar, u32 enable);
|
|
#endif
|
|
--- a/drivers/net/wireless/ath/ath11k/core.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
|
@@ -47,6 +47,7 @@ static const struct ath11k_hw_params ath
|
|
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
|
|
.hw_ops = &ath11k_qca8074_ops,
|
|
.credit_flow = false,
|
|
+ .m3_addr = ATH11K_QMI_IPQ8074_M3_DUMP_ADDRESS,
|
|
},
|
|
{
|
|
.dev_id = ATH11K_HW_IPQ6018,
|
|
@@ -65,6 +66,7 @@ static const struct ath11k_hw_params ath
|
|
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
|
|
.hw_ops = &ath11k_qca6018_ops,
|
|
.credit_flow = false,
|
|
+ .m3_addr = ATH11K_QMI_IPQ6018_M3_DUMP_ADDRESS,
|
|
},
|
|
{
|
|
.dev_id = ATH11K_HW_QCN90XX,
|
|
--- a/drivers/net/wireless/ath/ath11k/hw.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/hw.h
|
|
@@ -173,6 +173,7 @@ struct ath11k_hw_params {
|
|
u8 spectral_fft_sz;
|
|
bool credit_flow;
|
|
u32 hal_desc_sz;
|
|
+ u32 m3_addr;
|
|
const struct ath11k_hw_ops *hw_ops;
|
|
};
|
|
|