Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e5a15f51 authored by Manikandan Mohan's avatar Manikandan Mohan
Browse files

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: default avatarManikandan Mohan <manikand@codeaurora.org>
parent 5b478488
Loading
Loading
Loading
Loading
+58 −58
Original line number Diff line number Diff line
@@ -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,
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;

	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);
		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;
	}
		}
	} 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);
		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 for pa %pa\n",
					    &pa);
			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;
		}
		ret = cnss_genl_send_msg(va, CNSS_GENL_MSG_TYPE_QDSS,
						 event_data->file_name, size);
					 event_data->file_name,
					 event_data->mem_seg[i].size);
		if (ret < 0) {
				cnss_pr_err("Fail to save QDSS data: %d\n",
			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,8 +1689,8 @@ 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,
		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:
+1 −1
Original line number Diff line number Diff line
@@ -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,
};
+47 −37
Original line number Diff line number Diff line
@@ -1919,7 +1919,16 @@ 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,
/**
 * 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)
@@ -1927,55 +1936,56 @@ static void cnss_wlfw_qdss_trace_save_ind_cb(struct qmi_handle *qmi_wlfw,
	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_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;

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

	event_data->total_size = ind_msg->total_size;

	if (ind_msg->file_name_valid)
	if (ind_msg->file_name_valid) {
		strlcpy(event_data->file_name, ind_msg->file_name,
			QDSS_TRACE_FILE_NAME_MAX + 1);
	else
			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",
			QDSS_TRACE_FILE_NAME_MAX + 1);
				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_QDSS_TRACE_SAVE,
	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,
+4 −6
Original line number Diff line number Diff line
@@ -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