Loading drivers/platform/msm/gsi/gsi.c +73 −18 Original line number Diff line number Diff line Loading @@ -21,6 +21,9 @@ #define GSI_STOP_CMD_TIMEOUT_MS 200 #define GSI_MAX_CH_LOW_WEIGHT 15 #define GSI_STOP_CMD_POLL_CNT 4 #define GSI_STOP_IN_PROC_CMD_POLL_CNT 2 #define GSI_RESET_WA_MIN_SLEEP 1000 #define GSI_RESET_WA_MAX_SLEEP 2000 #define GSI_CHNL_STATE_MAX_RETRYCNT 10 Loading Loading @@ -111,17 +114,21 @@ static void __gsi_config_gen_irq(int ee, uint32_t mask, uint32_t val) static void gsi_channel_state_change_wait(unsigned long chan_hdl, struct gsi_chan_ctx *ctx, uint32_t tm) uint32_t tm, enum gsi_ch_cmd_opcode op) { int poll_cnt; int gsi_pending_intr; int res; uint32_t ch; uint32_t type; uint32_t val; int ee = gsi_ctx->per.ee; enum gsi_chan_state curr_state = GSI_CHAN_STATE_NOT_ALLOCATED; int stop_in_proc_retry = 0; int stop_retry = 0; /* * Start polling the GSI channel for * duration = tm * poll_cnt. * duration = tm * GSI_CMD_POLL_CNT. * We need to do polling of gsi state for improving debugability * of gsi hw state. */ Loading @@ -136,32 +143,77 @@ static void gsi_channel_state_change_wait(unsigned long chan_hdl, if (res != 0) return; /* * for the case of pending interrupt we will continue in the * loop. So state update is not needed. */ ch = gsi_readl(gsi_ctx->base + type = gsi_readl(gsi_ctx->base + GSI_EE_n_CNTXT_TYPE_IRQ_OFFS(gsi_ctx->per.ee)); gsi_pending_intr = gsi_readl(gsi_ctx->base + GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_OFFS(ee)); /* Update the channel state only if interrupt was raised * on praticular channel and also checking global interrupt * is raised for channel control. */ if ((type & GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_BMSK) && ((gsi_pending_intr >> chan_hdl) & 1)) { /* * Continue in the loop if a pending interrupt of * corresponding channel is present till an interrupt * is received. * Check channel state here in case the channel is * already started but interrupt is not yet received. */ val = gsi_readl(gsi_ctx->base + GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(chan_hdl, gsi_ctx->per.ee)); curr_state = (val & GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK) >> GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT; } if (op == GSI_CH_START) { if (curr_state == GSI_CHAN_STATE_STARTED) { ctx->state = curr_state; return; } } if (op == GSI_CH_STOP) { if (curr_state == GSI_CHAN_STATE_STOPPED) stop_retry++; else if (curr_state == GSI_CHAN_STATE_STOP_IN_PROC) stop_in_proc_retry++; } /* if interrupt marked reg after poll count reaching to max * keep loop to continue reach max stop proc and max stop count. */ if ((gsi_pending_intr >> chan_hdl) & 1) if (stop_retry == 1 || stop_in_proc_retry == 1) poll_cnt = 0; GSIDBG("GSI wait on chan_hld=%lu chan=%lu state=%u intr=%u\n", /* If stop channel retry reached to max count * clear the pending interrupt, if channel already stopped. */ if (stop_retry == GSI_STOP_CMD_POLL_CNT) { gsi_writel(gsi_pending_intr, gsi_ctx->base + GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(ee)); ctx->state = curr_state; return; } /* If channel state stop in progress case no need * to wait for long time. */ if (stop_in_proc_retry == GSI_STOP_IN_PROC_CMD_POLL_CNT) { ctx->state = curr_state; return; } GSIDBG("GSI wait on chan_hld=%lu irqtyp=%lu state=%u intr=%u\n", chan_hdl, ch, type, ctx->state, gsi_pending_intr); } GSIDBG("invalidating the channel state when timeout happens\n"); ctx->state = curr_state; } static void gsi_handle_ch_ctrl(int ee) Loading Loading @@ -746,6 +798,8 @@ static irqreturn_t gsi_isr(int irq, void *ctxt) gsi_handle_irq(); gsi_ctx->per.rel_clk_cb(gsi_ctx->per.user_data); } } else if (!gsi_ctx->per.clk_status_cb()) { return IRQ_HANDLED; } else { gsi_handle_irq(); } Loading Loading @@ -2702,7 +2756,7 @@ int gsi_start_channel(unsigned long chan_hdl) GSIDBG("GSI Channel Start, waiting for completion\n"); gsi_channel_state_change_wait(chan_hdl, ctx, GSI_START_CMD_TIMEOUT_MS); GSI_START_CMD_TIMEOUT_MS, op); if (ctx->state != GSI_CHAN_STATE_STARTED) { /* Loading Loading @@ -2784,12 +2838,13 @@ int gsi_stop_channel(unsigned long chan_hdl) GSIDBG("GSI Channel Stop, waiting for completion\n"); gsi_channel_state_change_wait(chan_hdl, ctx, GSI_STOP_CMD_TIMEOUT_MS); GSI_STOP_CMD_TIMEOUT_MS, op); if (ctx->state != GSI_CHAN_STATE_STOPPED && ctx->state != GSI_CHAN_STATE_STOP_IN_PROC) { GSIERR("chan=%lu unexpected state=%u\n", chan_hdl, ctx->state); res = -GSI_STATUS_BAD_STATE; BUG(); goto free_lock; } Loading drivers/platform/msm/ipa/ipa_v3/ipa.c +12 −1 Original line number Diff line number Diff line Loading @@ -3600,7 +3600,7 @@ void ipa3_enable_clks(void) if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl, ipa3_get_bus_vote())) WARN(1, "bus scaling failed"); atomic_set(&ipa3_ctx->ipa_clk_vote, 1); ipa3_ctx->ctrl->ipa3_enable_clks(); } Loading Loading @@ -3636,6 +3636,7 @@ void ipa3_disable_clks(void) if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl, 0)) WARN(1, "bus scaling failed"); atomic_set(&ipa3_ctx->ipa_clk_vote, 0); } /** Loading Loading @@ -3799,6 +3800,15 @@ void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id) mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex); } /** * ipa3_active_clks_status() - update the current msm bus clock vote * status */ int ipa3_active_clks_status(void) { return atomic_read(&ipa3_ctx->ipa_clk_vote); } /** * ipa3_inc_client_enable_clks_no_block() - Only increment the number of active * clients if no asynchronous actions should be done. Asynchronous actions are Loading Loading @@ -4709,6 +4719,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, gsi_props.notify_cb = ipa_gsi_notify_cb; gsi_props.req_clk_cb = NULL; gsi_props.rel_clk_cb = NULL; gsi_props.clk_status_cb = ipa3_active_clks_status; if (ipa3_ctx->ipa_config_is_mhi) { gsi_props.mhi_er_id_limits_valid = true; Loading drivers/platform/msm/ipa/ipa_v3/ipa_i.h +1 −0 Original line number Diff line number Diff line Loading @@ -1666,6 +1666,7 @@ struct ipa3_context { struct ipa3_wdi2_ctx wdi2_ctx; struct mbox_client mbox_client; struct mbox_chan *mbox; atomic_t ipa_clk_vote; }; struct ipa3_plat_drv_res { Loading include/linux/msm_gsi.h +2 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ enum gsi_intr_type { * peripheral is clocked at all times * @rel_clk_cb: callback to release peripheral clock * @user_data: cookie used for notifications * @clk_status_cb: callback to update the current msm bus clock vote * * All the callbacks are in interrupt context * Loading @@ -117,6 +118,7 @@ struct gsi_per_props { void (*req_clk_cb)(void *user_data, bool *granted); int (*rel_clk_cb)(void *user_data); void *user_data; int (*clk_status_cb)(void); }; enum gsi_evt_err { Loading Loading
drivers/platform/msm/gsi/gsi.c +73 −18 Original line number Diff line number Diff line Loading @@ -21,6 +21,9 @@ #define GSI_STOP_CMD_TIMEOUT_MS 200 #define GSI_MAX_CH_LOW_WEIGHT 15 #define GSI_STOP_CMD_POLL_CNT 4 #define GSI_STOP_IN_PROC_CMD_POLL_CNT 2 #define GSI_RESET_WA_MIN_SLEEP 1000 #define GSI_RESET_WA_MAX_SLEEP 2000 #define GSI_CHNL_STATE_MAX_RETRYCNT 10 Loading Loading @@ -111,17 +114,21 @@ static void __gsi_config_gen_irq(int ee, uint32_t mask, uint32_t val) static void gsi_channel_state_change_wait(unsigned long chan_hdl, struct gsi_chan_ctx *ctx, uint32_t tm) uint32_t tm, enum gsi_ch_cmd_opcode op) { int poll_cnt; int gsi_pending_intr; int res; uint32_t ch; uint32_t type; uint32_t val; int ee = gsi_ctx->per.ee; enum gsi_chan_state curr_state = GSI_CHAN_STATE_NOT_ALLOCATED; int stop_in_proc_retry = 0; int stop_retry = 0; /* * Start polling the GSI channel for * duration = tm * poll_cnt. * duration = tm * GSI_CMD_POLL_CNT. * We need to do polling of gsi state for improving debugability * of gsi hw state. */ Loading @@ -136,32 +143,77 @@ static void gsi_channel_state_change_wait(unsigned long chan_hdl, if (res != 0) return; /* * for the case of pending interrupt we will continue in the * loop. So state update is not needed. */ ch = gsi_readl(gsi_ctx->base + type = gsi_readl(gsi_ctx->base + GSI_EE_n_CNTXT_TYPE_IRQ_OFFS(gsi_ctx->per.ee)); gsi_pending_intr = gsi_readl(gsi_ctx->base + GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_OFFS(ee)); /* Update the channel state only if interrupt was raised * on praticular channel and also checking global interrupt * is raised for channel control. */ if ((type & GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_BMSK) && ((gsi_pending_intr >> chan_hdl) & 1)) { /* * Continue in the loop if a pending interrupt of * corresponding channel is present till an interrupt * is received. * Check channel state here in case the channel is * already started but interrupt is not yet received. */ val = gsi_readl(gsi_ctx->base + GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(chan_hdl, gsi_ctx->per.ee)); curr_state = (val & GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK) >> GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT; } if (op == GSI_CH_START) { if (curr_state == GSI_CHAN_STATE_STARTED) { ctx->state = curr_state; return; } } if (op == GSI_CH_STOP) { if (curr_state == GSI_CHAN_STATE_STOPPED) stop_retry++; else if (curr_state == GSI_CHAN_STATE_STOP_IN_PROC) stop_in_proc_retry++; } /* if interrupt marked reg after poll count reaching to max * keep loop to continue reach max stop proc and max stop count. */ if ((gsi_pending_intr >> chan_hdl) & 1) if (stop_retry == 1 || stop_in_proc_retry == 1) poll_cnt = 0; GSIDBG("GSI wait on chan_hld=%lu chan=%lu state=%u intr=%u\n", /* If stop channel retry reached to max count * clear the pending interrupt, if channel already stopped. */ if (stop_retry == GSI_STOP_CMD_POLL_CNT) { gsi_writel(gsi_pending_intr, gsi_ctx->base + GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(ee)); ctx->state = curr_state; return; } /* If channel state stop in progress case no need * to wait for long time. */ if (stop_in_proc_retry == GSI_STOP_IN_PROC_CMD_POLL_CNT) { ctx->state = curr_state; return; } GSIDBG("GSI wait on chan_hld=%lu irqtyp=%lu state=%u intr=%u\n", chan_hdl, ch, type, ctx->state, gsi_pending_intr); } GSIDBG("invalidating the channel state when timeout happens\n"); ctx->state = curr_state; } static void gsi_handle_ch_ctrl(int ee) Loading Loading @@ -746,6 +798,8 @@ static irqreturn_t gsi_isr(int irq, void *ctxt) gsi_handle_irq(); gsi_ctx->per.rel_clk_cb(gsi_ctx->per.user_data); } } else if (!gsi_ctx->per.clk_status_cb()) { return IRQ_HANDLED; } else { gsi_handle_irq(); } Loading Loading @@ -2702,7 +2756,7 @@ int gsi_start_channel(unsigned long chan_hdl) GSIDBG("GSI Channel Start, waiting for completion\n"); gsi_channel_state_change_wait(chan_hdl, ctx, GSI_START_CMD_TIMEOUT_MS); GSI_START_CMD_TIMEOUT_MS, op); if (ctx->state != GSI_CHAN_STATE_STARTED) { /* Loading Loading @@ -2784,12 +2838,13 @@ int gsi_stop_channel(unsigned long chan_hdl) GSIDBG("GSI Channel Stop, waiting for completion\n"); gsi_channel_state_change_wait(chan_hdl, ctx, GSI_STOP_CMD_TIMEOUT_MS); GSI_STOP_CMD_TIMEOUT_MS, op); if (ctx->state != GSI_CHAN_STATE_STOPPED && ctx->state != GSI_CHAN_STATE_STOP_IN_PROC) { GSIERR("chan=%lu unexpected state=%u\n", chan_hdl, ctx->state); res = -GSI_STATUS_BAD_STATE; BUG(); goto free_lock; } Loading
drivers/platform/msm/ipa/ipa_v3/ipa.c +12 −1 Original line number Diff line number Diff line Loading @@ -3600,7 +3600,7 @@ void ipa3_enable_clks(void) if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl, ipa3_get_bus_vote())) WARN(1, "bus scaling failed"); atomic_set(&ipa3_ctx->ipa_clk_vote, 1); ipa3_ctx->ctrl->ipa3_enable_clks(); } Loading Loading @@ -3636,6 +3636,7 @@ void ipa3_disable_clks(void) if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl, 0)) WARN(1, "bus scaling failed"); atomic_set(&ipa3_ctx->ipa_clk_vote, 0); } /** Loading Loading @@ -3799,6 +3800,15 @@ void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id) mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex); } /** * ipa3_active_clks_status() - update the current msm bus clock vote * status */ int ipa3_active_clks_status(void) { return atomic_read(&ipa3_ctx->ipa_clk_vote); } /** * ipa3_inc_client_enable_clks_no_block() - Only increment the number of active * clients if no asynchronous actions should be done. Asynchronous actions are Loading Loading @@ -4709,6 +4719,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, gsi_props.notify_cb = ipa_gsi_notify_cb; gsi_props.req_clk_cb = NULL; gsi_props.rel_clk_cb = NULL; gsi_props.clk_status_cb = ipa3_active_clks_status; if (ipa3_ctx->ipa_config_is_mhi) { gsi_props.mhi_er_id_limits_valid = true; Loading
drivers/platform/msm/ipa/ipa_v3/ipa_i.h +1 −0 Original line number Diff line number Diff line Loading @@ -1666,6 +1666,7 @@ struct ipa3_context { struct ipa3_wdi2_ctx wdi2_ctx; struct mbox_client mbox_client; struct mbox_chan *mbox; atomic_t ipa_clk_vote; }; struct ipa3_plat_drv_res { Loading
include/linux/msm_gsi.h +2 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ enum gsi_intr_type { * peripheral is clocked at all times * @rel_clk_cb: callback to release peripheral clock * @user_data: cookie used for notifications * @clk_status_cb: callback to update the current msm bus clock vote * * All the callbacks are in interrupt context * Loading @@ -117,6 +118,7 @@ struct gsi_per_props { void (*req_clk_cb)(void *user_data, bool *granted); int (*rel_clk_cb)(void *user_data); void *user_data; int (*clk_status_cb)(void); }; enum gsi_evt_err { Loading