diff options
| author | Yuanyuan Liu <yuanliu@codeaurora.org> | 2016-12-14 10:45:34 -0800 |
|---|---|---|
| committer | Yuanyuan Liu <yuanliu@codeaurora.org> | 2017-01-12 12:33:07 -0800 |
| commit | 28520e0a3827e8588913672ca348ec381ebef3da (patch) | |
| tree | d51031e593b6f82b035f8626b28b00ed8d61122f /drivers/soc/qcom | |
| parent | d19122a52dcd88dd93da334ce13f26f4099417d0 (diff) | |
icnss: Add support of FW rejuvenation
Add support of WLAN FW rejuvenation. After receiving FW
rejuvenate indication, ICNSS will start WLAN FW rejuvenation
and ack back to FW.
CRs-Fixed: 1107443
Change-Id: I127e86d8467f64534f096d58424e687d4231d7a5
Signed-off-by: Yuanyuan Liu <yuanliu@codeaurora.org>
Diffstat (limited to 'drivers/soc/qcom')
| -rw-r--r-- | drivers/soc/qcom/icnss.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 561a0d38e502..0e534625ef1e 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -175,6 +175,7 @@ enum icnss_driver_event_type { struct icnss_event_pd_service_down_data { bool crashed; + bool fw_rejuvenate; }; struct icnss_driver_event { @@ -256,6 +257,9 @@ struct icnss_stats { uint32_t vbatt_req; uint32_t vbatt_resp; uint32_t vbatt_req_err; + uint32_t rejuvenate_ack_req; + uint32_t rejuvenate_ack_resp; + uint32_t rejuvenate_ack_err; }; #define MAX_NO_OF_MAC_ADDR 4 @@ -1001,6 +1005,8 @@ static int wlfw_ind_register_send_sync_msg(void) req.msa_ready_enable = 1; req.pin_connect_result_enable_valid = 1; req.pin_connect_result_enable = 1; + req.rejuvenate_enable_valid = 1; + req.rejuvenate_enable = 1; req_desc.max_msg_len = WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN; req_desc.msg_id = QMI_WLFW_IND_REGISTER_REQ_V01; @@ -1390,6 +1396,51 @@ out: return ret; } +static int wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv *priv) +{ + int ret; + struct wlfw_rejuvenate_ack_req_msg_v01 req; + struct wlfw_rejuvenate_ack_resp_msg_v01 resp; + struct msg_desc req_desc, resp_desc; + + icnss_pr_dbg("Sending rejuvenate ack request, state: 0x%lx\n", + priv->state); + + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); + + req_desc.max_msg_len = WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN; + req_desc.msg_id = QMI_WLFW_REJUVENATE_ACK_REQ_V01; + req_desc.ei_array = wlfw_rejuvenate_ack_req_msg_v01_ei; + + resp_desc.max_msg_len = WLFW_REJUVENATE_ACK_RESP_MSG_V01_MAX_MSG_LEN; + resp_desc.msg_id = QMI_WLFW_REJUVENATE_ACK_RESP_V01; + resp_desc.ei_array = wlfw_rejuvenate_ack_resp_msg_v01_ei; + + priv->stats.rejuvenate_ack_req++; + ret = qmi_send_req_wait(priv->wlfw_clnt, &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), + WLFW_TIMEOUT_MS); + if (ret < 0) { + icnss_pr_err("Send rejuvenate ack req failed %d\n", ret); + goto out; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + icnss_pr_err("QMI rejuvenate ack request rejected, result:%d error %d\n", + resp.resp.result, resp.resp.error); + ret = resp.resp.result; + goto out; + } + priv->stats.rejuvenate_ack_resp++; + return 0; + +out: + priv->stats.rejuvenate_ack_err++; + ICNSS_ASSERT(false); + return ret; +} + static void icnss_qmi_wlfw_clnt_notify_work(struct work_struct *work) { int ret; @@ -1430,6 +1481,8 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle, unsigned int msg_id, void *msg, unsigned int msg_len, void *ind_cb_priv) { + struct icnss_event_pd_service_down_data *event_data; + if (!penv) return; @@ -1450,6 +1503,17 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle, msg_id); icnss_qmi_pin_connect_result_ind(msg, msg_len); break; + case QMI_WLFW_REJUVENATE_IND_V01: + icnss_pr_dbg("Received Rejuvenate Indication msg_id 0x%x, state: 0x%lx\n", + msg_id, penv->state); + event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); + if (event_data == NULL) + return; + event_data->crashed = true; + event_data->fw_rejuvenate = true; + icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, + 0, event_data); + break; default: icnss_pr_err("Invalid msg_id 0x%x\n", msg_id); break; @@ -1773,6 +1837,9 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, else icnss_call_driver_remove(priv); + if (event_data->fw_rejuvenate) + wlfw_rejuvenate_ack_send_sync_msg(priv); + out: ret = icnss_hw_power_off(priv); @@ -3103,6 +3170,9 @@ static int icnss_stats_show(struct seq_file *s, void *data) ICNSS_STATS_DUMP(s, priv, vbatt_req); ICNSS_STATS_DUMP(s, priv, vbatt_resp); ICNSS_STATS_DUMP(s, priv, vbatt_req_err); + ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req); + ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp); + ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err); seq_puts(s, "\n<------------------ PM stats ------------------->\n"); ICNSS_STATS_DUMP(s, priv, pm_suspend); |
