msm: ipa: allow abort for disable_clks

If a GSI channel is not quite clock cannot be devoted.
This change introduces the capability to "abort and retry"
clock devote operation.

Change-Id: I6e591435bbc3de81dce39e3ad5a0ae0f87c9a783
Signed-off-by: Ashok Vuyyuru <avuyyuru@codeaurora.org>
This commit is contained in:
Ashok Vuyyuru 2018-07-03 18:14:19 -07:00
commit eb8c172da8
3 changed files with 74 additions and 128 deletions

View file

@ -54,6 +54,8 @@
#include "ipa_trace.h"
#include "ipa_odl.h"
#define IPA_SUSPEND_BUSY_TIMEOUT (msecs_to_jiffies(10))
/*
* The following for adding code (ie. for EMULATION) not found on x86.
*/
@ -117,7 +119,7 @@ static void ipa3_load_ipa_fw(struct work_struct *work);
static DECLARE_WORK(ipa3_fw_loading_work, ipa3_load_ipa_fw);
static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work);
static DECLARE_WORK(ipa_dec_clients_disable_clks_on_wq_work,
static DECLARE_DELAYED_WORK(ipa_dec_clients_disable_clks_on_wq_work,
ipa_dec_clients_disable_clks_on_wq);
static int ipa3_ioctl_add_rt_rule_v2(unsigned long arg);
@ -4815,8 +4817,16 @@ static void __ipa3_dec_client_disable_clks(void)
ret = atomic_sub_return(1, &ipa3_ctx->ipa3_active_clients.cnt);
if (ret > 0)
goto unlock_mutex;
ipa3_suspend_apps_pipes(true);
ipa3_disable_clks();
ret = ipa3_suspend_apps_pipes(true);
if (ret) {
/* HW is busy, retry after some time */
atomic_inc(&ipa3_ctx->ipa3_active_clients.cnt);
queue_delayed_work(ipa3_ctx->power_mgmt_wq,
&ipa_dec_clients_disable_clks_on_wq_work,
IPA_SUSPEND_BUSY_TIMEOUT);
} else {
ipa3_disable_clks();
}
unlock_mutex:
mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
@ -4869,8 +4879,8 @@ void ipa3_dec_client_disable_clks_no_block(
}
/* seems like this is the only client holding the clocks */
queue_work(ipa3_ctx->power_mgmt_wq,
&ipa_dec_clients_disable_clks_on_wq_work);
queue_delayed_work(ipa3_ctx->power_mgmt_wq,
&ipa_dec_clients_disable_clks_on_wq_work, 0);
}
/**

View file

@ -2915,7 +2915,7 @@ int ipa3_create_wdi_mapping(u32 num_buffers, struct ipa_wdi_buffer_info *info);
int ipa3_set_flt_tuple_mask(int pipe_idx, struct ipahal_reg_hash_tuple *tuple);
int ipa3_set_rt_tuple_mask(int tbl_idx, struct ipahal_reg_hash_tuple *tuple);
void ipa3_set_resorce_groups_min_max_limits(void);
void ipa3_suspend_apps_pipes(bool suspend);
int ipa3_suspend_apps_pipes(bool suspend);
int ipa3_flt_read_tbl_from_hw(u32 pipe_idx,
enum ipa_ip_type ip_type,
bool hashable,

View file

@ -7484,12 +7484,10 @@ void ipa3_set_resorce_groups_min_max_limits(void)
IPADBG("EXIT\n");
}
static void ipa3_gsi_poll_after_suspend(struct ipa3_ep_context *ep)
static bool ipa3_gsi_channel_is_quite(struct ipa3_ep_context *ep)
{
bool empty;
IPADBG("switch ch %ld to poll\n", ep->gsi_chan_hdl);
gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL);
gsi_is_channel_empty(ep->gsi_chan_hdl, &empty);
if (!empty) {
IPADBG("ch %ld not empty\n", ep->gsi_chan_hdl);
@ -7498,6 +7496,7 @@ static void ipa3_gsi_poll_after_suspend(struct ipa3_ep_context *ep)
if (!atomic_read(&ep->sys->curr_polling_state))
__ipa_gsi_irq_rx_scedule_poll(ep->sys);
}
return empty;
}
static int __ipa3_stop_gsi_channel(u32 clnt_hdl)
@ -7623,141 +7622,78 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl)
return res;
}
void ipa3_suspend_apps_pipes(bool suspend)
static int _ipa_suspend_pipe(enum ipa_client_type client, bool suspend)
{
struct ipa_ep_cfg_ctrl cfg;
int ipa_ep_idx;
struct ipa3_ep_context *ep;
int res;
memset(&cfg, 0, sizeof(cfg));
cfg.ipa_ep_suspend = suspend;
if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
IPAERR("not supported\n");
return -EPERM;
}
ipa_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS);
ipa_ep_idx = ipa3_get_ep_mapping(client);
if (ipa_ep_idx < 0) {
IPAERR("IPA client mapping failed\n");
ipa_assert();
return;
IPADBG("client %d not configured\n", client);
return 0;
}
ep = &ipa3_ctx->ep[ipa_ep_idx];
if (ep->valid) {
IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
ipa_ep_idx);
/*
* move the channel to callback mode.
* This needs to happen before starting the channel to make
* sure we don't loose any interrupt
*/
if (!suspend && !atomic_read(&ep->sys->curr_polling_state))
gsi_config_channel_mode(ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
if (suspend) {
res = __ipa3_stop_gsi_channel(ipa_ep_idx);
if (res) {
IPAERR("failed to stop LAN channel\n");
ipa_assert();
}
} else {
res = gsi_start_channel(ep->gsi_chan_hdl);
if (res) {
IPAERR("failed to start LAN channel\n");
ipa_assert();
}
}
} else {
ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
ep = &ipa3_ctx->ep[ipa_ep_idx];
if (!ep->valid)
return 0;
IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend", ipa_ep_idx);
/*
* move the channel to callback mode.
* This needs to happen before starting the channel to make
* sure we don't loose any interrupt
*/
if (!suspend && !atomic_read(&ep->sys->curr_polling_state))
gsi_config_channel_mode(ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
if (suspend) {
res = __ipa3_stop_gsi_channel(ipa_ep_idx);
if (res) {
IPAERR("failed to stop LAN channel\n");
ipa_assert();
}
if (suspend)
ipa3_gsi_poll_after_suspend(ep);
}
ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS);
/* Considering the case for SSR. */
if (ipa_ep_idx == -1) {
IPADBG("Invalid mapping for IPA_CLIENT_APPS_WAN_CONS\n");
return;
}
ep = &ipa3_ctx->ep[ipa_ep_idx];
if (ep->valid) {
IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
ipa_ep_idx);
/*
* move the channel to callback mode.
* This needs to happen before starting the channel to make
* sure we don't loose any interrupt
*/
if (!suspend && !atomic_read(&ep->sys->curr_polling_state))
gsi_config_channel_mode(ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
if (suspend) {
res = __ipa3_stop_gsi_channel(ipa_ep_idx);
if (res) {
IPAERR("failed to stop WAN channel\n");
ipa_assert();
}
} else if (!atomic_read(&ipa3_ctx->is_ssr)) {
/* If SSR was alreday started not required to
* start WAN channel,Because in SSR will stop
* channel and reset the channel.
*/
res = gsi_start_channel(ep->gsi_chan_hdl);
if (res) {
IPAERR("failed to start WAN channel\n");
ipa_assert();
}
}
} else {
ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
} else {
res = gsi_start_channel(ep->gsi_chan_hdl);
if (res) {
IPAERR("failed to start LAN channel\n");
ipa_assert();
}
if (suspend)
ipa3_gsi_poll_after_suspend(ep);
}
ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_ODL_DPL_CONS);
/* Considering the case for SSR. */
if (ipa_ep_idx == -1) {
IPADBG("Invalid mapping for IPA_CLIENT_ODL_DPL_CONS\n");
return;
}
ep = &ipa3_ctx->ep[ipa_ep_idx];
if (ep->valid) {
IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
ipa_ep_idx);
/*
* move the channel to callback mode.
* This needs to happen before starting the channel to make
* sure we don't loose any interrupt
*/
if (!suspend && !atomic_read(&ep->sys->curr_polling_state))
gsi_config_channel_mode(ep->gsi_chan_hdl,
if (suspend) {
IPADBG("switch ch %ld to poll\n", ep->gsi_chan_hdl);
gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL);
if (!ipa3_gsi_channel_is_quite(ep))
return -EAGAIN;
} else if (!atomic_read(&ep->sys->curr_polling_state)) {
IPADBG("switch ch %ld to callback\n", ep->gsi_chan_hdl);
gsi_config_channel_mode(ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
if (suspend) {
res = __ipa3_stop_gsi_channel(ipa_ep_idx);
if (res) {
IPAERR("failed to stop ODL channel\n");
ipa_assert();
}
} else if (!atomic_read(&ipa3_ctx->is_ssr)) {
/* If SSR was alreday started not required to
* start WAN channel,Because in SSR will stop
* channel and reset the channel.
*/
res = gsi_start_channel(ep->gsi_chan_hdl);
if (res) {
IPAERR("failed to start ODL channel\n");
ipa_assert();
}
}
} else {
ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
}
if (suspend)
ipa3_gsi_poll_after_suspend(ep);
}
return 0;
}
int ipa3_suspend_apps_pipes(bool suspend)
{
int res;
res = _ipa_suspend_pipe(IPA_CLIENT_APPS_LAN_CONS, suspend);
if (res)
return res;
res = _ipa_suspend_pipe(IPA_CLIENT_APPS_WAN_CONS, suspend);
if (res)
return res;
return 0;
}
int ipa3_allocate_dma_task_for_gsi(void)