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

Commit 6fa70646 authored by Yue Ma's avatar Yue Ma
Browse files

cnss2: Support unified QMI sequence



Unified QMI sequence creates a common sequence that can be used by
firmware and host driver among various devices. It will help reduce
maintenance effort and enhance scalability. Add the support for it
to CNSS2 driver.

Change-Id: Ia8b20f185bd9ecc4b7866aa2df62318b981e93f5
Signed-off-by: default avatarYue Ma <yuem@codeaurora.org>
parent db005c45
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1690,6 +1690,7 @@ static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)

static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
{
	plat_priv->cal_done = true;
	cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01);
	cnss_shutdown(plat_priv);
	clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
+4 −1
Original line number Diff line number Diff line
@@ -107,6 +107,7 @@ struct cnss_fw_mem {
	void *va;
	phys_addr_t pa;
	bool valid;
	u32 type;
};

enum cnss_driver_event_type {
@@ -192,7 +193,8 @@ struct cnss_plat_data {
	struct wlfw_rf_board_info_s_v01 board_info;
	struct wlfw_soc_info_s_v01 soc_info;
	struct wlfw_fw_version_info_s_v01 fw_version_info;
	struct cnss_fw_mem fw_mem;
	u32 fw_mem_seg_len;
	struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
	struct cnss_fw_mem m3_mem;
	struct cnss_pin_connect_result pin_result;
	struct dentry *root_dentry;
@@ -204,6 +206,7 @@ struct cnss_plat_data {
	u32 diag_reg_read_mem_type;
	u32 diag_reg_read_len;
	u8 *diag_reg_read_buf;
	bool cal_done;
};

void *cnss_bus_dev_to_bus_priv(struct device *dev);
+33 −22
Original line number Diff line number Diff line
@@ -737,20 +737,23 @@ int cnss_pm_request_resume(struct cnss_pci_data *pci_priv)
int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;

	if (!fw_mem->va && fw_mem->size) {
		fw_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
						fw_mem->size, &fw_mem->pa,
						GFP_KERNEL);
		if (!fw_mem->va) {
			cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx\n",
				    fw_mem->size);
			fw_mem->size = 0;
	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
	int i;

	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
		if (!fw_mem[i].va && fw_mem[i].size) {
			fw_mem[i].va =
				dma_alloc_coherent(&pci_priv->pci_dev->dev,
						   fw_mem[i].size,
						   &fw_mem[i].pa, GFP_KERNEL);
			if (!fw_mem[i].va) {
				cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx, type: %u\n",
					    fw_mem[i].size, fw_mem[i].type);

				return -ENOMEM;
			}
		}
	}

	return 0;
}
@@ -758,19 +761,27 @@ int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv)
static void cnss_pci_free_fw_mem(struct cnss_pci_data *pci_priv)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
	int i;

	if (fw_mem->va && fw_mem->size) {
		cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n",
			    fw_mem->va, &fw_mem->pa, fw_mem->size);
		dma_free_coherent(&pci_priv->pci_dev->dev, fw_mem->size,
				  fw_mem->va, fw_mem->pa);
		fw_mem->va = NULL;
		fw_mem->pa = 0;
		fw_mem->size = 0;
	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
		if (fw_mem[i].va && fw_mem[i].size) {
			cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
				    fw_mem[i].va, &fw_mem[i].pa,
				    fw_mem[i].size, fw_mem[i].type);
			dma_free_coherent(&pci_priv->pci_dev->dev,
					  fw_mem[i].size, fw_mem[i].va,
					  fw_mem[i].pa);
			fw_mem[i].va = NULL;
			fw_mem[i].pa = 0;
			fw_mem[i].size = 0;
			fw_mem[i].type = 0;
		}
	}

	plat_priv->fw_mem_seg_len = 0;
}

int cnss_pci_load_m3(struct cnss_pci_data *pci_priv)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+92 −37
Original line number Diff line number Diff line
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -159,10 +159,9 @@ static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv)
	memset(&req, 0, sizeof(req));
	memset(&resp, 0, sizeof(resp));

	req.daemon_support_valid = 1;
	req.daemon_support = daemon_support;

	cnss_pr_dbg("daemon_support is %d\n", req.daemon_support);
	req.num_clients_valid = 1;
	req.num_clients = daemon_support ? 2 : 1;
	cnss_pr_dbg("Number of clients is %d\n", req.num_clients);

	req.wake_msi = cnss_get_wake_msi(plat_priv);
	if (req.wake_msi) {
@@ -170,6 +169,19 @@ static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv)
		req.wake_msi_valid = 1;
	}

	req.bdf_support_valid = 1;
	req.bdf_support = 1;

	req.m3_support_valid = 1;
	req.m3_support = 1;

	req.m3_cache_support_valid = 1;
	req.m3_cache_support = 1;

	req.cal_done_valid = 1;
	req.cal_done = plat_priv->cal_done;
	cnss_pr_dbg("Calibration done is %d\n", plat_priv->cal_done);

	req_desc.max_msg_len = WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN;
	req_desc.msg_id = QMI_WLFW_HOST_CAP_REQ_V01;
	req_desc.ei_array = wlfw_host_cap_req_msg_v01_ei;
@@ -221,8 +233,8 @@ static int cnss_wlfw_ind_register_send_sync(struct cnss_plat_data *plat_priv)
	req.request_mem_enable = 1;
	req.fw_mem_ready_enable_valid = 1;
	req.fw_mem_ready_enable = 1;
	req.cold_boot_cal_done_enable_valid = 1;
	req.cold_boot_cal_done_enable = 1;
	req.fw_init_done_enable_valid = 1;
	req.fw_init_done_enable = 1;
	req.pin_connect_result_enable_valid = 1;
	req.pin_connect_result_enable = 1;

@@ -260,27 +272,48 @@ static int cnss_wlfw_request_mem_ind_hdlr(struct cnss_plat_data *plat_priv,
					  void *msg, unsigned int msg_len)
{
	struct msg_desc ind_desc;
	struct wlfw_request_mem_ind_msg_v01 ind_msg;
	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
	int ret = 0;
	struct wlfw_request_mem_ind_msg_v01 *ind_msg;
	int ret = 0, i;

	ind_msg = kzalloc(sizeof(*ind_msg), GFP_KERNEL);
	if (!ind_msg)
		return -ENOMEM;

	ind_desc.msg_id = QMI_WLFW_REQUEST_MEM_IND_V01;
	ind_desc.max_msg_len = WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN;
	ind_desc.ei_array = wlfw_request_mem_ind_msg_v01_ei;

	ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
	ret = qmi_kernel_decode(&ind_desc, ind_msg, msg, msg_len);
	if (ret < 0) {
		cnss_pr_err("Failed to decode request memory indication, msg_len: %u, err = %d\n",
			    ret, msg_len);
		return ret;
		goto out;
	}

	if (ind_msg->mem_seg_len == 0 ||
	    ind_msg->mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
		cnss_pr_err("Invalid memory segment length: %u\n",
			    ind_msg->mem_seg_len);
		ret = -EINVAL;
		goto out;
	}

	fw_mem->size = ind_msg.size;
	cnss_pr_dbg("FW memory segment count is %u\n", ind_msg->mem_seg_len);
	plat_priv->fw_mem_seg_len = ind_msg->mem_seg_len;
	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
		plat_priv->fw_mem[i].type = ind_msg->mem_seg[i].type;
		plat_priv->fw_mem[i].size = ind_msg->mem_seg[i].size;
	}

	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REQUEST_MEM,
			       0, NULL);

	kfree(ind_msg);
	return 0;

out:
	kfree(ind_msg);
	return ret;
}

static int cnss_qmi_pin_result_ind_hdlr(struct cnss_plat_data *plat_priv,
@@ -317,29 +350,46 @@ static int cnss_qmi_pin_result_ind_hdlr(struct cnss_plat_data *plat_priv,

int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv)
{
	struct wlfw_respond_mem_req_msg_v01 req;
	struct wlfw_respond_mem_resp_msg_v01 resp;
	struct wlfw_respond_mem_req_msg_v01 *req;
	struct wlfw_respond_mem_resp_msg_v01 *resp;
	struct msg_desc req_desc, resp_desc;
	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
	int ret = 0;
	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
	int ret = 0, i;

	cnss_pr_dbg("Sending respond memory message, state: 0x%lx\n",
		    plat_priv->driver_state);

	if (!fw_mem->pa || !fw_mem->size) {
		cnss_pr_err("Memory for FW is not available!\n");
	req = kzalloc(sizeof(*req), GFP_KERNEL);
	if (!req)
		return -ENOMEM;

	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
	if (!resp)
		return -ENOMEM;

	req->mem_seg_len = plat_priv->fw_mem_seg_len;
	for (i = 0; i < req->mem_seg_len; i++) {
		if (!fw_mem[i].pa || !fw_mem[i].size) {
			if (fw_mem[i].type == 0) {
				cnss_pr_err("Invalid memory for FW type, segment = %d\n",
					    i);
				ret = -EINVAL;
				goto out;
			}
			cnss_pr_err("Memory for FW is not available for type: %u\n",
				    fw_mem[i].type);
			ret = -ENOMEM;
			goto out;
		}

	cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n",
		    fw_mem->va, &fw_mem->pa, fw_mem->size);
		cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
			    fw_mem[i].va, &fw_mem[i].pa,
			    fw_mem[i].size, fw_mem[i].type);

	memset(&req, 0, sizeof(req));
	memset(&resp, 0, sizeof(resp));

	req.addr = fw_mem->pa;
	req.size = fw_mem->size;
		req->mem_seg[i].addr = fw_mem[i].pa;
		req->mem_seg[i].size = fw_mem[i].size;
		req->mem_seg[i].type = fw_mem[i].type;
	}

	req_desc.max_msg_len = WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN;
	req_desc.msg_id = QMI_WLFW_RESPOND_MEM_REQ_V01;
@@ -349,8 +399,8 @@ int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv)
	resp_desc.msg_id = QMI_WLFW_RESPOND_MEM_RESP_V01;
	resp_desc.ei_array = wlfw_respond_mem_resp_msg_v01_ei;

	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
				sizeof(req), &resp_desc, &resp, sizeof(resp),
	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, req,
				sizeof(*req), &resp_desc, resp, sizeof(*resp),
				QMI_WLFW_TIMEOUT_MS);
	if (ret < 0) {
		cnss_pr_err("Failed to send respond memory request, err = %d\n",
@@ -358,16 +408,21 @@ int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv)
		goto out;
	}

	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
		cnss_pr_err("Respond memory request failed, result: %d, err: %d\n",
			    resp.resp.result, resp.resp.error);
		ret = resp.resp.result;
			    resp->resp.result, resp->resp.error);
		ret = resp->resp.result;
		goto out;
	}

	kfree(req);
	kfree(resp);
	return 0;

out:
	CNSS_ASSERT(0);
	kfree(req);
	kfree(resp);
	return ret;
}

@@ -908,12 +963,12 @@ static void cnss_wlfw_clnt_ind(struct qmi_handle *handle,
				       CNSS_DRIVER_EVENT_FW_MEM_READY,
				       0, NULL);
		break;
	case QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01:
	case QMI_WLFW_FW_READY_IND_V01:
		cnss_driver_event_post(plat_priv,
				       CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
				       0, NULL);
		break;
	case QMI_WLFW_FW_READY_IND_V01:
	case QMI_WLFW_FW_INIT_DONE_IND_V01:
		cnss_driver_event_post(plat_priv,
				       CNSS_DRIVER_EVENT_FW_READY,
				       0, NULL);
@@ -974,11 +1029,11 @@ int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv)
	cnss_pr_info("QMI WLFW service connected, state: 0x%lx\n",
		     plat_priv->driver_state);

	ret = cnss_wlfw_host_cap_send_sync(plat_priv);
	ret = cnss_wlfw_ind_register_send_sync(plat_priv);
	if (ret < 0)
		goto out;

	ret = cnss_wlfw_ind_register_send_sync(plat_priv);
	ret = cnss_wlfw_host_cap_send_sync(plat_priv);
	if (ret < 0)
		goto out;

+465 −79

File changed.

Preview size limit exceeded, changes collapsed.

Loading