Merge "cnss2: Overload QDSS trace save indication for generic mem dump"

This commit is contained in:
qctecmdr 2020-11-04 06:07:46 -08:00 • committed by Gerrit - the friendly Code Review server
commit 92bbd73111
4 changed files with 110 additions and 102 deletions

View file

@ -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);

View file

@ -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,
};

View file

@ -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,

View file

@ -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