From e5a15f51f2171764420a80f4289869d0bb6dc868 Mon Sep 17 00:00:00 2001 From: Manikandan Mohan Date: Thu, 29 Oct 2020 18:17:08 -0700 Subject: [PATCH] cnss2: Overload QDSS trace save indication for generic mem dump QDSS trace save QMI indication will be used by FW to dump any type of host allocated DDR remote memory. Update QDSS trace save indication handler for saving different memory types. Change-Id: I0e78e2f6de367a500e78622e841e0cdf0f4170e5 Signed-off-by: Manikandan Mohan --- drivers/net/wireless/cnss2/main.c | 116 +++++++++++++++--------------- drivers/net/wireless/cnss2/main.h | 2 +- drivers/net/wireless/cnss2/qmi.c | 90 ++++++++++++----------- drivers/net/wireless/cnss2/qmi.h | 10 ++- 4 files changed, 113 insertions(+), 105 deletions(-) diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 023f3de71db8..ceb98ece043c 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -533,8 +533,8 @@ static char *cnss_driver_event_to_str(enum cnss_driver_event_type type) return "WLFW_TWC_CFG_IND"; case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM: return "QDSS_TRACE_REQ_MEM"; - case CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE: - return "QDSS_TRACE_SAVE"; + case CNSS_DRIVER_EVENT_FW_MEM_FILE_SAVE: + return "FW_MEM_FILE_SAVE"; case CNSS_DRIVER_EVENT_QDSS_TRACE_FREE: return "QDSS_TRACE_FREE"; case CNSS_DRIVER_EVENT_MAX: @@ -1504,89 +1504,89 @@ static int cnss_qdss_trace_req_mem_hdlr(struct cnss_plat_data *plat_priv) return cnss_wlfw_qdss_trace_mem_info_send_sync(plat_priv); } -static void *cnss_qdss_trace_pa_to_va(struct cnss_plat_data *plat_priv, - u64 pa, u32 size, int *seg_id) +static void *cnss_get_fw_mem_pa_to_va(struct cnss_fw_mem *fw_mem, + u32 mem_seg_len, u64 pa, u32 size) { int i = 0; - struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem; u64 offset = 0; void *va = NULL; u64 local_pa; u32 local_size; - for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) { - local_pa = (u64)qdss_mem[i].pa; - local_size = (u32)qdss_mem[i].size; + for (i = 0; i < mem_seg_len; i++) { + local_pa = (u64)fw_mem[i].pa; + local_size = (u32)fw_mem[i].size; if (pa == local_pa && size <= local_size) { - va = qdss_mem[i].va; + va = fw_mem[i].va; break; } if (pa > local_pa && pa < local_pa + local_size && pa + size <= local_pa + local_size) { offset = pa - local_pa; - va = qdss_mem[i].va + offset; + va = fw_mem[i].va + offset; break; } } - - *seg_id = i; return va; } -static int cnss_qdss_trace_save_hdlr(struct cnss_plat_data *plat_priv, - void *data) +static int cnss_fw_mem_file_save_hdlr(struct cnss_plat_data *plat_priv, + void *data) { - struct cnss_qmi_event_qdss_trace_save_data *event_data = data; - struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem; - int ret = 0; - int i; + struct cnss_qmi_event_fw_mem_file_save_data *event_data = data; + struct cnss_fw_mem *fw_mem_seg; + int ret = 0L; void *va = NULL; - u64 pa; - u32 size; - int seg_id = 0; + u32 i, fw_mem_seg_len; - if (!plat_priv->qdss_mem_seg_len) { - cnss_pr_err("Memory for QDSS trace is not available\n"); - return -ENOMEM; + switch (event_data->mem_type) { + case QMI_WLFW_MEM_TYPE_DDR_V01: + if (!plat_priv->fw_mem_seg_len) + goto invalid_mem_save; + + fw_mem_seg = plat_priv->fw_mem; + fw_mem_seg_len = plat_priv->fw_mem_seg_len; + break; + case QMI_WLFW_MEM_QDSS_V01: + if (!plat_priv->qdss_mem_seg_len) + goto invalid_mem_save; + + fw_mem_seg = plat_priv->qdss_mem; + fw_mem_seg_len = plat_priv->qdss_mem_seg_len; + break; + default: + goto invalid_mem_save; } - if (event_data->mem_seg_len == 0) { - for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) { - ret = cnss_genl_send_msg(qdss_mem[i].va, - CNSS_GENL_MSG_TYPE_QDSS, - event_data->file_name, - qdss_mem[i].size); - if (ret < 0) { - cnss_pr_err("Fail to save QDSS data: %d\n", - ret); - break; - } + for (i = 0; i < event_data->mem_seg_len; i++) { + va = cnss_get_fw_mem_pa_to_va(fw_mem_seg, fw_mem_seg_len, + event_data->mem_seg[i].addr, + event_data->mem_seg[i].size); + if (!va) { + cnss_pr_err("Fail to find matching va of pa %pa for mem type: %d\n", + &event_data->mem_seg[i].addr, + event_data->mem_type); + ret = -EINVAL; + break; } - } else { - for (i = 0; i < event_data->mem_seg_len; i++) { - pa = event_data->mem_seg[i].addr; - size = event_data->mem_seg[i].size; - va = cnss_qdss_trace_pa_to_va(plat_priv, pa, - size, &seg_id); - if (!va) { - cnss_pr_err("Fail to find matching va for pa %pa\n", - &pa); - ret = -EINVAL; - break; - } - ret = cnss_genl_send_msg(va, CNSS_GENL_MSG_TYPE_QDSS, - event_data->file_name, size); - if (ret < 0) { - cnss_pr_err("Fail to save QDSS data: %d\n", - ret); - break; - } + ret = cnss_genl_send_msg(va, CNSS_GENL_MSG_TYPE_QDSS, + event_data->file_name, + event_data->mem_seg[i].size); + if (ret < 0) { + cnss_pr_err("Fail to save fw mem data: %d\n", + ret); + break; } } - kfree(data); return ret; + +invalid_mem_save: + cnss_pr_err("FW Mem type %d not allocated. Invalid save request\n", + event_data->mem_type); + kfree(data); + return -EINVAL; } static int cnss_qdss_trace_free_hdlr(struct cnss_plat_data *plat_priv) @@ -1689,9 +1689,9 @@ static void cnss_driver_event_work(struct work_struct *work) case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM: ret = cnss_qdss_trace_req_mem_hdlr(plat_priv); break; - case CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE: - ret = cnss_qdss_trace_save_hdlr(plat_priv, - event->data); + case CNSS_DRIVER_EVENT_FW_MEM_FILE_SAVE: + ret = cnss_fw_mem_file_save_hdlr(plat_priv, + event->data); break; case CNSS_DRIVER_EVENT_QDSS_TRACE_FREE: ret = cnss_qdss_trace_free_hdlr(plat_priv); diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index 09c2d2bff74f..8f677f03b7d6 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -259,7 +259,7 @@ enum cnss_driver_event_type { CNSS_DRIVER_EVENT_IMS_WFC_CALL_IND, CNSS_DRIVER_EVENT_WLFW_TWT_CFG_IND, CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM, - CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE, + CNSS_DRIVER_EVENT_FW_MEM_FILE_SAVE, CNSS_DRIVER_EVENT_QDSS_TRACE_FREE, CNSS_DRIVER_EVENT_MAX, }; diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index a8f717503aaa..82e7f897e973 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -1919,63 +1919,73 @@ static void cnss_wlfw_qdss_trace_req_mem_ind_cb(struct qmi_handle *qmi_wlfw, 0, NULL); } -static void cnss_wlfw_qdss_trace_save_ind_cb(struct qmi_handle *qmi_wlfw, - struct sockaddr_qrtr *sq, - struct qmi_txn *txn, - const void *data) +/** + * cnss_wlfw_fw_mem_file_save_ind_cb: Save given FW mem to filesystem + * + * QDSS_TRACE_SAVE_IND feature is overloaded to provide any host allocated + * fw memory segment for dumping to file system. Only one type of mem can be + * saved per indication and is provided in mem seg index 0. + * + * Return: None + */ +static void cnss_wlfw_fw_mem_file_save_ind_cb(struct qmi_handle *qmi_wlfw, + struct sockaddr_qrtr *sq, + struct qmi_txn *txn, + const void *data) { struct cnss_plat_data *plat_priv = container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); const struct wlfw_qdss_trace_save_ind_msg_v01 *ind_msg = data; - struct cnss_qmi_event_qdss_trace_save_data *event_data; + struct cnss_qmi_event_fw_mem_file_save_data *event_data; int i = 0; - cnss_pr_dbg("Received QMI WLFW QDSS trace save indication\n"); - - if (!txn) { + if (!txn || !data) { cnss_pr_err("Spurious indication\n"); return; } - - cnss_pr_dbg("QDSS_trace_save info: source %u, total_size %u, file_name_valid %u, file_name %s\n", - ind_msg->source, ind_msg->total_size, - ind_msg->file_name_valid, ind_msg->file_name); - - if (ind_msg->source == 1) + cnss_pr_dbg("QMI fw_mem_file_save: source: %d mem_seg: %d type: %u len: %u\n", + ind_msg->source, ind_msg->mem_seg_valid, + ind_msg->mem_seg[0].type, ind_msg->mem_seg_len); + if (ind_msg->source == 1 || !ind_msg->mem_seg_valid || + !ind_msg->mem_seg_len || + ind_msg->mem_seg_len > QMI_WLFW_MAX_STR_LEN_V01) { + cnss_pr_err("Invalid FW mem file save indication\n"); return; + } 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) { - cnss_pr_err("Invalid seg len %u\n", - ind_msg->mem_seg_len); - goto free_event_data; - } - cnss_pr_dbg("QDSS_trace_save seg len %u\n", - ind_msg->mem_seg_len); - 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; - cnss_pr_dbg("seg-%d: addr 0x%llx size 0x%x\n", - i, ind_msg->mem_seg[i].addr, - ind_msg->mem_seg[i].size); - } - } - + event_data->mem_type = ind_msg->mem_seg[0].type; + event_data->mem_seg_len = ind_msg->mem_seg_len; event_data->total_size = ind_msg->total_size; - if (ind_msg->file_name_valid) - strlcpy(event_data->file_name, ind_msg->file_name, - QDSS_TRACE_FILE_NAME_MAX + 1); - else - strlcpy(event_data->file_name, "qdss_trace", - QDSS_TRACE_FILE_NAME_MAX + 1); + 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; + if (event_data->mem_type != ind_msg->mem_seg[i].type) { + cnss_pr_err("FW Mem file save ind cannot have multiple mem types\n"); + goto free_event_data; + } + cnss_pr_dbg("seg-%d: addr 0x%llx size 0x%x\n", + i, ind_msg->mem_seg[i].addr, + ind_msg->mem_seg[i].size); + } - cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE, + if (ind_msg->file_name_valid) { + strlcpy(event_data->file_name, ind_msg->file_name, + QMI_WLFW_MAX_STR_LEN_V01 + 1); + } else { + if (event_data->mem_type == QMI_WLFW_MEM_QDSS_V01) + strlcpy(event_data->file_name, "qdss_trace", + QMI_WLFW_MAX_STR_LEN_V01 + 1); + else + strlcpy(event_data->file_name, "fw_mem_dump", + QMI_WLFW_MAX_STR_LEN_V01 + 1); + } + + cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_FW_MEM_FILE_SAVE, 0, event_data); return; @@ -2207,7 +2217,7 @@ static struct qmi_msg_handler qmi_wlfw_msg_handlers[] = { .ei = wlfw_qdss_trace_save_ind_msg_v01_ei, .decoded_size = sizeof(struct wlfw_qdss_trace_save_ind_msg_v01), - .fn = cnss_wlfw_qdss_trace_save_ind_cb + .fn = cnss_wlfw_fw_mem_file_save_ind_cb }, { .type = QMI_INDICATION, diff --git a/drivers/net/wireless/cnss2/qmi.h b/drivers/net/wireless/cnss2/qmi.h index 4d74ad11dc33..0583f2c76f99 100644 --- a/drivers/net/wireless/cnss2/qmi.h +++ b/drivers/net/wireless/cnss2/qmi.h @@ -13,19 +13,17 @@ struct cnss_qmi_event_server_arrive_data { unsigned int port; }; -#define QDSS_TRACE_SEG_LEN_MAX 32 -#define QDSS_TRACE_FILE_NAME_MAX 16 - struct cnss_mem_seg { u64 addr; u32 size; }; -struct cnss_qmi_event_qdss_trace_save_data { +struct cnss_qmi_event_fw_mem_file_save_data { u32 total_size; u32 mem_seg_len; - struct cnss_mem_seg mem_seg[QDSS_TRACE_SEG_LEN_MAX]; - char file_name[QDSS_TRACE_FILE_NAME_MAX + 1]; + enum wlfw_mem_type_enum_v01 mem_type; + struct cnss_mem_seg mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01]; + char file_name[QMI_WLFW_MAX_STR_LEN_V01 + 1]; }; #ifdef CONFIG_CNSS2_QMI