From eb8c172da818256a3f444a08944f791cc42e2d23 Mon Sep 17 00:00:00 2001 From: Ashok Vuyyuru Date: Tue, 3 Jul 2018 18:14:19 -0700 Subject: [PATCH] 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 --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 20 ++- drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 2 +- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 182 +++++++------------- 3 files changed, 75 insertions(+), 129 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 8ac349495933..fd0cbc6cb6c5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -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); } /** diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 1cc20312e1e1..5072ee47625d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -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, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index aea7a5a5fe89..763385965f3b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -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)