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

Commit 3e55e8fb authored by Naman Padhiar's avatar Naman Padhiar
Browse files

icnss2: Send enter power save after driver suspend



In PM suspend of WCN6750, host send WOW Enable to FW
and FW allows target to go to low power mode along
with PCIe link. In Host DP, even after sending WOW
enable it tries to access target for flushing pending
transactions. This will cause NOC error as link is
down.
Send enter power save mode to FW after driver suspend
returns successfully to platform driver and all pending
transactions are flushed. FW will go to low power mode
only after receiveing enter power save mode QMI.

Change-Id: I5dfb257fe3db4dc453bae456c40d19f841e3c5c8
Signed-off-by: default avatarNaman Padhiar <npadhiar@codeaurora.org>
parent 3b62fcac
Loading
Loading
Loading
Loading
+17 −10
Original line number Diff line number Diff line
@@ -2760,7 +2760,6 @@ EXPORT_SYMBOL(icnss_idle_restart);
int icnss_exit_power_save(struct device *dev)
{
	struct icnss_priv *priv = dev_get_drvdata(dev);
	int ret = 0;

	icnss_pr_dbg("Calling Exit Power Save\n");

@@ -2768,12 +2767,8 @@ int icnss_exit_power_save(struct device *dev)
	    !test_bit(ICNSS_MODE_ON, &priv->state))
		return 0;

	ret = wlfw_exit_power_save_send_msg(priv);
	if (ret) {
		priv->stats.pm_resume_err++;
		return ret;
	}
	return 0;
	return wlfw_power_save_send_msg(priv,
			(enum wlfw_power_save_mode_v01)ICNSS_POWER_SAVE_EXIT);
}
EXPORT_SYMBOL(icnss_exit_power_save);

@@ -3358,12 +3353,18 @@ static int icnss_pm_suspend(struct device *dev)

	if (!priv->ops || !priv->ops->pm_suspend ||
	    !test_bit(ICNSS_DRIVER_PROBED, &priv->state))
		goto out;
		return 0;

	ret = priv->ops->pm_suspend(dev);

out:
	if (ret == 0) {
		if (priv->device_id == WCN6750_DEVICE_ID) {
			ret = wlfw_power_save_send_msg(priv,
				(enum wlfw_power_save_mode_v01)
				ICNSS_POWER_SAVE_ENTER);
			if (ret)
				return priv->ops->pm_resume(dev);
		}
		priv->stats.pm_suspend++;
		set_bit(ICNSS_PM_SUSPEND, &priv->state);
	} else {
@@ -3476,7 +3477,13 @@ static int icnss_pm_runtime_suspend(struct device *dev)

	icnss_pr_vdbg("Runtime suspend\n");
	ret = priv->ops->runtime_suspend(dev);

	if (!ret) {
		ret = wlfw_power_save_send_msg(priv,
				(enum wlfw_power_save_mode_v01)
				ICNSS_POWER_SAVE_ENTER);
		if (ret)
			return priv->ops->runtime_resume(dev);
	}
out:
	return ret;
}
+7 −0
Original line number Diff line number Diff line
@@ -158,6 +158,10 @@ struct icnss_fw_mem {
	unsigned long attrs;
};

enum icnss_power_save_mode {
	ICNSS_POWER_SAVE_ENTER,
	ICNSS_POWER_SAVE_EXIT,
};
struct icnss_stats {
	struct {
		uint32_t posted;
@@ -230,6 +234,9 @@ struct icnss_stats {
	u32 exit_power_save_req;
	u32 exit_power_save_resp;
	u32 exit_power_save_err;
	u32 enter_power_save_req;
	u32 enter_power_save_resp;
	u32 enter_power_save_err;
	u32 soc_wake_req;
	u32 soc_wake_resp;
	u32 soc_wake_err;
+29 −31
Original line number Diff line number Diff line
@@ -341,11 +341,11 @@ int wlfw_device_info_send_msg(struct icnss_priv *priv)
	return ret;
}

int wlfw_exit_power_save_send_msg(struct icnss_priv *priv)
int wlfw_power_save_send_msg(struct icnss_priv *priv,
			     enum wlfw_power_save_mode_v01 mode)
{
	int ret;
	struct wlfw_exit_power_save_req_msg_v01 *req;
	struct wlfw_exit_power_save_resp_msg_v01 *resp;
	struct wlfw_power_save_req_msg_v01 *req;
	struct qmi_txn txn;

	if (!priv)
@@ -354,23 +354,27 @@ int wlfw_exit_power_save_send_msg(struct icnss_priv *priv)
	if (test_bit(ICNSS_FW_DOWN, &priv->state))
		return -EINVAL;

	icnss_pr_dbg("Sending exit power save, state: 0x%lx\n",
		     priv->state);
	if (test_bit(ICNSS_PD_RESTART, &priv->state) ||
	    !test_bit(ICNSS_MODE_ON, &priv->state))
		return 0;

	icnss_pr_dbg("Sending power save mode: %d, state: 0x%lx\n",
		     mode, priv->state);

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

	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
	if (!resp) {
		kfree(req);
		return -ENOMEM;
	}
	req->power_save_mode_valid = 1;
	req->power_save_mode = mode;

	if (mode == WLFW_POWER_SAVE_EXIT_V01)
		priv->stats.exit_power_save_req++;
	else
		priv->stats.enter_power_save_req++;

	ret = qmi_txn_init(&priv->qmi, &txn,
			   wlfw_exit_power_save_resp_msg_v01_ei, resp);
			   NULL, NULL);
	if (ret < 0) {
		icnss_qmi_fatal_err("Fail to init txn for exit power save%d\n",
				    ret);
@@ -378,9 +382,9 @@ int wlfw_exit_power_save_send_msg(struct icnss_priv *priv)
	}

	ret = qmi_send_request(&priv->qmi, NULL, &txn,
			       QMI_WLFW_EXIT_POWER_SAVE_REQ_V01,
			       WLFW_EXIT_POWER_SAVE_REQ_MSG_V01_MAX_MSG_LEN,
			       wlfw_exit_power_save_req_msg_v01_ei, req);
			       QMI_WLFW_POWER_SAVE_REQ_V01,
			       WLFW_POWER_SAVE_REQ_MSG_V01_MAX_MSG_LEN,
			       wlfw_power_save_req_msg_v01_ei, req);
	if (ret < 0) {
		qmi_txn_cancel(&txn);
		icnss_qmi_fatal_err("Fail to send exit power save req %d\n",
@@ -388,29 +392,23 @@ int wlfw_exit_power_save_send_msg(struct icnss_priv *priv)
		goto out;
	}

	ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
	if (ret < 0) {
		icnss_qmi_fatal_err("Exit power save wait failed with ret %d\n",
				    ret);
		goto out;
	} else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
		icnss_qmi_fatal_err(
		    "QMI exit power save request rejected,result:%d error:%d\n",
				    resp->resp.result, resp->resp.error);
		ret = -resp->resp.result;
		goto out;
	}
	qmi_txn_cancel(&txn);

	if (mode == WLFW_POWER_SAVE_EXIT_V01)
		priv->stats.exit_power_save_resp++;
	else
		priv->stats.enter_power_save_resp++;

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

out:
	kfree(resp);
	kfree(req);

	if (mode == WLFW_POWER_SAVE_EXIT_V01)
		priv->stats.exit_power_save_err++;
	else
		priv->stats.enter_power_save_err++;
	return ret;
}

+4 −2
Original line number Diff line number Diff line
@@ -129,7 +129,8 @@ int wlfw_qdss_trace_mem_info_send_sync(struct icnss_priv *priv)
	return 0;
}

int wlfw_exit_power_save_send_msg(struct icnss_priv *priv)
int wlfw_power_save_send_msg(struct icnss_priv *priv,
			     enum wlfw_power_save_mode_v01 mode)
{
	return 0;
}
@@ -180,7 +181,8 @@ int wlfw_wlan_mode_send_sync_msg(struct icnss_priv *priv,
				 enum wlfw_driver_mode_enum_v01 mode);
int icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv *priv, u32 bdf_type);
int wlfw_qdss_trace_mem_info_send_sync(struct icnss_priv *priv);
int wlfw_exit_power_save_send_msg(struct icnss_priv *priv);
int wlfw_power_save_send_msg(struct icnss_priv *priv,
			     enum wlfw_power_save_mode_v01 mode);
int icnss_wlfw_get_info_send_sync(struct icnss_priv *priv, int type,
				  void *cmd, int cmd_len);
int wlfw_send_soc_wake_msg(struct icnss_priv *priv,
+142 −5
Original line number Diff line number Diff line
@@ -782,6 +782,24 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = {
		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
					   wfc_call_twt_config_enable),
	},
	{
		.data_type      = QMI_OPT_FLAG,
		.elem_len       = 1,
		.elem_size      = sizeof(u8),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x22,
		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
					   qdss_mem_ready_enable_valid),
	},
	{
		.data_type      = QMI_UNSIGNED_1_BYTE,
		.elem_len       = 1,
		.elem_size      = sizeof(u8),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x22,
		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
					   qdss_mem_ready_enable),
	},
	{
		.data_type      = QMI_EOTI,
		.array_type       = NO_ARRAY,
@@ -1407,6 +1425,42 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = {
		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
					   eeprom_caldata_read_timeout),
	},
	{
		.data_type      = QMI_OPT_FLAG,
		.elem_len       = 1,
		.elem_size      = sizeof(u8),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x1A,
		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
					   fw_caps_valid),
	},
	{
		.data_type      = QMI_UNSIGNED_8_BYTE,
		.elem_len       = 1,
		.elem_size      = sizeof(u64),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x1A,
		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
					   fw_caps),
	},
	{
		.data_type      = QMI_OPT_FLAG,
		.elem_len       = 1,
		.elem_size      = sizeof(u8),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x1B,
		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
					   rd_card_chain_cap_valid),
	},
	{
		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
		.elem_len       = 1,
		.elem_size      = sizeof(enum wlfw_rd_card_chain_cap_v01),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x1B,
		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
					   rd_card_chain_cap),
	},
	{
		.data_type      = QMI_EOTI,
		.array_type       = NO_ARRAY,
@@ -1560,6 +1614,26 @@ struct qmi_elem_info wlfw_bdf_download_resp_msg_v01_ei[] = {
					   resp),
		.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       = 0x10,
		.offset         = offsetof(struct
					   wlfw_bdf_download_resp_msg_v01,
					   host_bdf_data_valid),
	},
	{
		.data_type      = QMI_UNSIGNED_8_BYTE,
		.elem_len       = 1,
		.elem_size      = sizeof(u64),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x10,
		.offset         = offsetof(struct
					   wlfw_bdf_download_resp_msg_v01,
					   host_bdf_data),
	},
	{
		.data_type      = QMI_EOTI,
		.array_type       = NO_ARRAY,
@@ -4287,7 +4361,25 @@ struct qmi_elem_info wlfw_soc_wake_resp_msg_v01_ei[] = {
	},
};

struct qmi_elem_info wlfw_exit_power_save_req_msg_v01_ei[] = {
struct qmi_elem_info wlfw_power_save_req_msg_v01_ei[] = {
	{
		.data_type      = QMI_OPT_FLAG,
		.elem_len       = 1,
		.elem_size      = sizeof(u8),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x10,
		.offset         = offsetof(struct wlfw_power_save_req_msg_v01,
					   power_save_mode_valid),
	},
	{
		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
		.elem_len       = 1,
		.elem_size      = sizeof(enum wlfw_power_save_mode_v01),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x10,
		.offset         = offsetof(struct wlfw_power_save_req_msg_v01,
					   power_save_mode),
	},
	{
		.data_type      = QMI_EOTI,
		.array_type       = NO_ARRAY,
@@ -4295,15 +4387,14 @@ struct qmi_elem_info wlfw_exit_power_save_req_msg_v01_ei[] = {
	},
};

struct qmi_elem_info wlfw_exit_power_save_resp_msg_v01_ei[] = {
struct qmi_elem_info wlfw_power_save_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
					   wlfw_exit_power_save_resp_msg_v01,
		.offset         = offsetof(struct wlfw_power_save_resp_msg_v01,
					   resp),
		.ei_array      = qmi_response_type_v01_ei,
	},
@@ -4441,3 +4532,49 @@ struct qmi_elem_info wlfw_wfc_call_twt_config_ind_msg_v01_ei[] = {
		.tlv_type       = QMI_COMMON_TLV_TYPE,
	},
};

struct qmi_elem_info wlfw_qdss_mem_ready_ind_msg_v01_ei[] = {
	{
		.data_type      = QMI_EOTI,
		.array_type       = NO_ARRAY,
		.tlv_type       = QMI_COMMON_TLV_TYPE,
	},
};

struct qmi_elem_info wlfw_pcie_gen_switch_req_msg_v01_ei[] = {
	{
		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
		.elem_len       = 1,
		.elem_size      = sizeof(enum wlfw_pcie_gen_speed_v01),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x01,
		.offset         = offsetof(struct
					   wlfw_pcie_gen_switch_req_msg_v01,
					   pcie_speed),
	},
	{
		.data_type      = QMI_EOTI,
		.array_type       = NO_ARRAY,
		.tlv_type       = QMI_COMMON_TLV_TYPE,
	},
};

struct qmi_elem_info wlfw_pcie_gen_switch_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
					   wlfw_pcie_gen_switch_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,
	},
};
Loading