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); }