From cfad44940c7fecbac1c251b85d13c669554fa3ec Mon Sep 17 00:00:00 2001 From: Bojun Pan Date: Thu, 14 Jan 2021 13:24:04 -0800 Subject: [PATCH] msm: ipa: fix race condition on PM vote on sys pipes There is race condition on PM defer deactive and PM active where the PM active triggered by new NAPI scheduling would be accidently unvoted by PM defer deactive after last NAPI completion. This is causing the NoC error on packet handling due to no clock. The fix here is to using ACTIVE_CLIENT_NO_BLOCK for clock voting and still use PM handle for BW voting so that we would have reference count to make sure this unexpected devote not happens. Change-Id: If1ece48dc16256dae9a810b3efa6eb4f533f06a8 --- drivers/platform/msm/ipa/ipa_common_i.h | 17 +++++++ drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 56 +++++++++++++++++++----- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h index ea75edf28dd8..351065e2412d 100644 --- a/drivers/platform/msm/ipa/ipa_common_i.h +++ b/drivers/platform/msm/ipa/ipa_common_i.h @@ -103,6 +103,23 @@ ipa3_dec_client_disable_clks(&log_info); \ } while (0) +#define IPA_ACTIVE_CLIENTS_INC_EP_NO_BLOCK(client) ({\ + int __ret = 0; \ + do { \ + struct ipa_active_client_logging_info log_info; \ + IPA_ACTIVE_CLIENTS_PREP_EP(log_info, client); \ + __ret = ipa3_inc_client_enable_clks_no_block(&log_info); \ + } while (0); \ + (__ret); \ +}) + +#define IPA_ACTIVE_CLIENTS_DEC_EP_NO_BLOCK(client) \ + do { \ + struct ipa_active_client_logging_info log_info; \ + IPA_ACTIVE_CLIENTS_PREP_EP(log_info, client); \ + ipa3_dec_client_disable_clks_no_block(&log_info); \ + } while (0) + /* * Printing one warning message in 5 seconds if multiple warning messages * are coming back to back. diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index ba494d5ef406..97f410510070 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -894,7 +894,7 @@ static int ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys) atomic_set(&sys->curr_polling_state, 0); __ipa3_update_curr_poll_state(sys->ep->client, 0); - + ipa_pm_deferred_deactivate(sys->pm_hdl); ipa3_dec_release_wakelock(); ret = gsi_config_channel_mode(sys->ep->gsi_chan_hdl, GSI_CHAN_MODE_CALLBACK); @@ -927,8 +927,8 @@ static void ipa3_handle_rx(struct ipa3_sys_context *sys) int cnt; int ret; - ipa_pm_activate_sync(sys->pm_hdl); start_poll: + ipa_pm_activate_sync(sys->pm_hdl); inactive_cycles = 0; do { cnt = ipa3_handle_rx_core(sys, true, true); @@ -956,7 +956,7 @@ start_poll: if (ret == -GSI_STATUS_PENDING_IRQ) goto start_poll; - ipa_pm_deferred_deactivate(sys->pm_hdl); + IPA_ACTIVE_CLIENTS_DEC_EP(sys->ep->client); } static void ipa3_switch_to_intr_rx_work_func(struct work_struct *work) @@ -1936,15 +1936,23 @@ fail_pipe_not_valid: static void ipa3_wq_handle_rx(struct work_struct *work) { struct ipa3_sys_context *sys; + enum ipa_client_type client_type; sys = container_of(work, struct ipa3_sys_context, work); + /* + * Mark client as WAN_COAL_CONS only as + * NAPI only use sys of WAN_COAL_CONS. + */ + if (IPA_CLIENT_IS_WAN_CONS(sys->ep->client)) + client_type = IPA_CLIENT_APPS_WAN_COAL_CONS; + else + client_type = sys->ep->client; + IPA_ACTIVE_CLIENTS_INC_EP(client_type); if (sys->napi_obj) { - ipa_pm_activate_sync(sys->pm_hdl); napi_schedule(sys->napi_obj); IPA_STATS_INC_CNT(sys->napi_sch_cnt); } else if (IPA_CLIENT_IS_LOW_LAT_CONS(sys->ep->client)) { - ipa_pm_activate_sync(sys->pm_hdl); tasklet_schedule(&sys->tasklet); } else ipa3_handle_rx(sys); @@ -4596,17 +4604,26 @@ static void ipa_gsi_irq_tx_notify_cb(struct gsi_chan_xfer_notify *notify) void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys) { bool clk_off; + enum ipa_client_type client_type; atomic_set(&sys->curr_polling_state, 1); __ipa3_update_curr_poll_state(sys->ep->client, 1); ipa3_inc_acquire_wakelock(); - /* - * pm deactivate is done in wq context - * or after NAPI poll + * Mark client as WAN_COAL_CONS only as + * NAPI only use sys of WAN_COAL_CONS. */ - clk_off = ipa_pm_activate(sys->pm_hdl); + if (IPA_CLIENT_IS_WAN_CONS(sys->ep->client)) + client_type = IPA_CLIENT_APPS_WAN_COAL_CONS; + else + client_type = sys->ep->client; + /* + * Have race condition to use PM on poll to isr + * switch. Use the active no block instead + * where we would have ref counts. + */ + clk_off = IPA_ACTIVE_CLIENTS_INC_EP_NO_BLOCK(client_type); if (!clk_off && sys->napi_obj) { trace_ipa3_napi_schedule(sys->ep->client); napi_schedule(sys->napi_obj); @@ -5217,6 +5234,11 @@ int ipa3_lan_rx_poll(u32 clnt_hdl, int weight) ep = &ipa3_ctx->ep[clnt_hdl]; start_poll: + /* + * it is guaranteed we already have clock here. + * This is mainly for clock scaling. + */ + ipa_pm_activate(ep->sys->pm_hdl); while (remain_aggr_weight > 0 && atomic_read(&ep->sys->curr_polling_state)) { atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1); @@ -5246,7 +5268,7 @@ start_poll: napi_reschedule(ep->sys->napi_obj)) goto start_poll; - ipa_pm_deferred_deactivate(ep->sys->pm_hdl); + IPA_ACTIVE_CLIENTS_DEC_EP_NO_BLOCK(ep->client); } return cnt; @@ -5302,6 +5324,11 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight) } start_poll: + /* + * it is guaranteed we already have clock here. + * This is mainly for clock scaling. + */ + ipa_pm_activate(ep->sys->pm_hdl); while (remain_aggr_weight > 0 && atomic_read(&ep->sys->curr_polling_state)) { atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1); @@ -5340,7 +5367,7 @@ start_poll: if (ret == -GSI_STATUS_PENDING_IRQ && napi_reschedule(ep->sys->napi_obj)) goto start_poll; - ipa_pm_deferred_deactivate(ep->sys->pm_hdl); + IPA_ACTIVE_CLIENTS_DEC_EP_NO_BLOCK(ep->client); } else { cnt = weight; IPADBG_LOW("Client = %d not replenished free descripotrs\n", @@ -5483,6 +5510,11 @@ static void ipa3_tasklet_rx_notify(unsigned long data) sys = (struct ipa3_sys_context *)data; atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1); start_poll: + /* + * it is guaranteed we already have clock here. + * This is mainly for clock scaling. + */ + ipa_pm_activate(sys->pm_hdl); while (1) { ret = ipa_poll_gsi_pkt(sys, ¬ify); if (ret) @@ -5497,6 +5529,6 @@ start_poll: ret = ipa3_rx_switch_to_intr_mode(sys); if (ret == -GSI_STATUS_PENDING_IRQ) goto start_poll; - ipa_pm_deferred_deactivate(sys->pm_hdl); + IPA_ACTIVE_CLIENTS_DEC_EP_NO_BLOCK(sys->ep->client); }