Merge "msm: ipa: changes to suspend/disable for WDI 2"

This commit is contained in:
Linux Build Service Account 2017-02-21 05:33:23 -08:00 committed by Gerrit - the friendly Code Review server
commit 7997223a2d
4 changed files with 85 additions and 26 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, 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
@ -95,6 +95,46 @@ int ipa_disable_data_path(u32 clnt_hdl)
return res;
}
int ipa2_enable_force_clear(u32 request_id, bool throttle_source,
u32 source_pipe_bitmask)
{
struct ipa_enable_force_clear_datapath_req_msg_v01 req;
int result;
memset(&req, 0, sizeof(req));
req.request_id = request_id;
req.source_pipe_bitmask = source_pipe_bitmask;
if (throttle_source) {
req.throttle_source_valid = 1;
req.throttle_source = 1;
}
result = qmi_enable_force_clear_datapath_send(&req);
if (result) {
IPAERR("qmi_enable_force_clear_datapath_send failed %d\n",
result);
return result;
}
return 0;
}
int ipa2_disable_force_clear(u32 request_id)
{
struct ipa_disable_force_clear_datapath_req_msg_v01 req;
int result;
memset(&req, 0, sizeof(req));
req.request_id = request_id;
result = qmi_disable_force_clear_datapath_send(&req);
if (result) {
IPAERR("qmi_disable_force_clear_datapath_send failed %d\n",
result);
return result;
}
return 0;
}
static int ipa2_smmu_map_peer_bam(unsigned long dev)
{
phys_addr_t base;

View file

@ -1803,6 +1803,9 @@ void ipa_delete_dflt_flt_rules(u32 ipa_ep_idx);
int ipa_enable_data_path(u32 clnt_hdl);
int ipa_disable_data_path(u32 clnt_hdl);
int ipa2_enable_force_clear(u32 request_id, bool throttle_source,
u32 source_pipe_bitmask);
int ipa2_disable_force_clear(u32 request_id);
int ipa_id_alloc(void *ptr);
void *ipa_id_find(u32 id);
void ipa_id_remove(u32 id);

View file

@ -39,6 +39,8 @@
#define QMI_SEND_STATS_REQ_TIMEOUT_MS 5000
#define QMI_SEND_REQ_TIMEOUT_MS 60000
#define QMI_IPA_FORCE_CLEAR_DATAPATH_TIMEOUT_MS 1000
static struct qmi_handle *ipa_svc_handle;
static void ipa_a5_svc_recv_msg(struct work_struct *work);
static DECLARE_DELAYED_WORK(work_recv_msg, ipa_a5_svc_recv_msg);
@ -583,7 +585,8 @@ int qmi_enable_force_clear_datapath_send(
&req_desc,
req,
sizeof(*req),
&resp_desc, &resp, sizeof(resp), 0);
&resp_desc, &resp, sizeof(resp),
QMI_IPA_FORCE_CLEAR_DATAPATH_TIMEOUT_MS);
if (rc < 0) {
IPAWANERR("send req failed %d\n", rc);
return rc;
@ -628,7 +631,8 @@ int qmi_disable_force_clear_datapath_send(
&req_desc,
req,
sizeof(*req),
&resp_desc, &resp, sizeof(resp), 0);
&resp_desc, &resp, sizeof(resp),
QMI_IPA_FORCE_CLEAR_DATAPATH_TIMEOUT_MS);
if (rc < 0) {
IPAWANERR("send req failed %d\n", rc);
return rc;

View file

@ -1404,7 +1404,6 @@ int ipa2_disable_wdi_pipe(u32 clnt_hdl)
union IpaHwWdiCommonChCmdData_t disable;
struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
u32 prod_hdl;
int i;
if (unlikely(!ipa_ctx)) {
IPAERR("IPA driver was not initialized\n");
@ -1421,28 +1420,6 @@ int ipa2_disable_wdi_pipe(u32 clnt_hdl)
if (result)
return result;
/* checking rdy_ring_rp_pa matches the rdy_comp_ring_wp_pa on WDI2.0 */
if (ipa_ctx->ipa_wdi2) {
for (i = 0; i < IPA_UC_FINISH_MAX; i++) {
IPADBG("(%d) rp_value(%u), comp_wp_value(%u)\n",
i,
*ipa_ctx->uc_ctx.rdy_ring_rp_va,
*ipa_ctx->uc_ctx.rdy_comp_ring_wp_va);
if (*ipa_ctx->uc_ctx.rdy_ring_rp_va !=
*ipa_ctx->uc_ctx.rdy_comp_ring_wp_va) {
usleep_range(IPA_UC_WAIT_MIN_SLEEP,
IPA_UC_WAII_MAX_SLEEP);
} else {
break;
}
}
/* In case ipa_uc still haven't processed all
* pending descriptors, we have to assert
*/
if (i == IPA_UC_FINISH_MAX)
BUG();
}
IPADBG("ep=%d\n", clnt_hdl);
ep = &ipa_ctx->ep[clnt_hdl];
@ -1468,6 +1445,11 @@ int ipa2_disable_wdi_pipe(u32 clnt_hdl)
* holb on IPA Producer pipe
*/
if (IPA_CLIENT_IS_PROD(ep->client)) {
IPADBG("Stopping PROD channel - hdl=%d clnt=%d\n",
clnt_hdl, ep->client);
/* remove delay on wlan-prod pipe*/
memset(&ep_cfg_ctrl, 0 , sizeof(struct ipa_ep_cfg_ctrl));
ipa2_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
@ -1594,6 +1576,8 @@ int ipa2_suspend_wdi_pipe(u32 clnt_hdl)
struct ipa_ep_context *ep;
union IpaHwWdiCommonChCmdData_t suspend;
struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
u32 source_pipe_bitmask = 0;
bool disable_force_clear = false;
if (unlikely(!ipa_ctx)) {
IPAERR("IPA driver was not initialized\n");
@ -1623,6 +1607,31 @@ int ipa2_suspend_wdi_pipe(u32 clnt_hdl)
suspend.params.ipa_pipe_number = clnt_hdl;
if (IPA_CLIENT_IS_PROD(ep->client)) {
/*
* For WDI 2.0 need to ensure pipe will be empty before suspend
* as IPA uC will fail to suspend the pipe otherwise.
*/
if (ipa_ctx->ipa_wdi2) {
source_pipe_bitmask = 1 <<
ipa_get_ep_mapping(ep->client);
result = ipa2_enable_force_clear(clnt_hdl,
false, source_pipe_bitmask);
if (result) {
/*
* assuming here modem SSR, AP can remove
* the delay in this case
*/
IPAERR("failed to force clear %d\n", result);
IPAERR("remove delay from SCND reg\n");
memset(&ep_cfg_ctrl, 0,
sizeof(struct ipa_ep_cfg_ctrl));
ep_cfg_ctrl.ipa_ep_delay = false;
ep_cfg_ctrl.ipa_ep_suspend = false;
ipa2_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
} else {
disable_force_clear = true;
}
}
IPADBG("Post suspend event first for IPA Producer\n");
IPADBG("Client: %d clnt_hdl: %d\n", ep->client, clnt_hdl);
result = ipa_uc_send_cmd(suspend.raw32b,
@ -1667,6 +1676,9 @@ int ipa2_suspend_wdi_pipe(u32 clnt_hdl)
}
}
if (disable_force_clear)
ipa2_disable_force_clear(clnt_hdl);
ipa_ctx->tag_process_before_gating = true;
IPA_ACTIVE_CLIENTS_DEC_EP(ipa2_get_client_mapping(clnt_hdl));
ep->uc_offload_state &= ~IPA_WDI_RESUMED;