msm: ipa: handle missing interrupts

In GSI 2.2 and 2.5 there is a limitation that can lead
to losing an interrupt. For these versions an
explicit check is needed after enabling the interrupt

Change-Id: I3907ea1750ceaece42c8b3ca0f63850e2d7d7f3e
Acked-by: Ady Abraham <adya@qti.qualcomm.com>
Acked-by: Ashok Vuyyuru <avuyyuru@qti.qualcomm.com>
Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
tirimbino
Skylar Chang 7 years ago committed by Mohammed Javid
parent 87874f76c6
commit 1f9f7c4db4
  1. 27
      drivers/platform/msm/gsi/gsi.c
  2. 1
      drivers/platform/msm/gsi/gsi.h
  3. 5
      drivers/platform/msm/gsi/gsi_dbg.c
  4. 36
      drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
  5. 23
      drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
  6. 1
      include/linux/msm_gsi.h

@ -3267,6 +3267,33 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode)
mode == GSI_CHAN_MODE_CALLBACK) {
atomic_set(&ctx->poll_mode, mode);
__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0);
/*
* In GSI 2.2 and 2.5 there is a limitation that can lead
* to losing an interrupt. For these versions an
* explicit check is needed after enabling the interrupt
*/
if (gsi_ctx->per.ver == GSI_VER_2_2 ||
gsi_ctx->per.ver == GSI_VER_2_5) {
u32 src = gsi_readl(gsi_ctx->base +
GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(
gsi_ctx->per.ee));
if (src & (1 << ctx->evtr->id)) {
__gsi_config_ieob_irq(
gsi_ctx->per.ee, 1 << ctx->evtr->id, 0);
gsi_writel(1 << ctx->evtr->id, gsi_ctx->base +
GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(
gsi_ctx->per.ee));
spin_unlock_irqrestore(&gsi_ctx->slock, flags);
spin_lock_irqsave(&ctx->ring.slock, flags);
atomic_set(
&ctx->poll_mode, GSI_CHAN_MODE_POLL);
spin_unlock_irqrestore(
&ctx->ring.slock, flags);
ctx->stats.poll_pending_irq++;
return -GSI_STATUS_PENDING_IRQ;
}
}
ctx->stats.poll_to_callback++;
}
spin_unlock_irqrestore(&gsi_ctx->slock, flags);

@ -120,6 +120,7 @@ struct gsi_chan_stats {
unsigned long completed;
unsigned long callback_to_poll;
unsigned long poll_to_callback;
unsigned long poll_pending_irq;
unsigned long invalid_tre_error;
unsigned long poll_ok;
unsigned long poll_empty;

@ -273,9 +273,10 @@ static void gsi_dump_ch_stats(struct gsi_chan_ctx *ctx)
PRT_STAT("queued=%lu compl=%lu\n",
ctx->stats.queued,
ctx->stats.completed);
PRT_STAT("cb->poll=%lu poll->cb=%lu\n",
PRT_STAT("cb->poll=%lu poll->cb=%lu poll_pend_irq=%lu\n",
ctx->stats.callback_to_poll,
ctx->stats.poll_to_callback);
ctx->stats.poll_to_callback,
ctx->stats.poll_pending_irq);
PRT_STAT("invalid_tre_error=%lu\n",
ctx->stats.invalid_tre_error);
PRT_STAT("poll_ok=%lu poll_empty=%lu\n",

@ -752,27 +752,24 @@ static int ipa3_handle_rx_core(struct ipa3_sys_context *sys, bool process_all,
/**
* ipa3_rx_switch_to_intr_mode() - Operate the Rx data path in interrupt mode
*/
static void ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys)
static int ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys)
{
int ret;
if (!atomic_read(&sys->curr_polling_state)) {
IPAERR("already in intr mode\n");
goto fail;
}
atomic_set(&sys->curr_polling_state, 0);
ipa3_dec_release_wakelock();
ret = gsi_config_channel_mode(sys->ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
if (ret != GSI_STATUS_SUCCESS) {
IPAERR("Failed to switch to intr mode.\n");
goto fail;
if (ret == -GSI_STATUS_PENDING_IRQ) {
ipa3_inc_acquire_wakelock();
atomic_set(&sys->curr_polling_state, 1);
} else {
IPAERR("Failed to switch to intr mode.\n");
}
}
return;
fail:
queue_delayed_work(sys->wq, &sys->switch_to_intr_work,
msecs_to_jiffies(1));
return ret;
}
/**
@ -785,13 +782,16 @@ fail:
*/
static void ipa3_handle_rx(struct ipa3_sys_context *sys)
{
int inactive_cycles = 0;
int inactive_cycles;
int cnt;
int ret;
if (ipa3_ctx->use_ipa_pm)
ipa_pm_activate_sync(sys->pm_hdl);
else
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
start_poll:
inactive_cycles = 0;
do {
cnt = ipa3_handle_rx_core(sys, true, true);
if (cnt == 0)
@ -814,7 +814,10 @@ static void ipa3_handle_rx(struct ipa3_sys_context *sys)
} while (inactive_cycles <= POLLING_INACTIVITY_RX);
trace_poll_to_intr3(sys->ep->client);
ipa3_rx_switch_to_intr_mode(sys);
ret = ipa3_rx_switch_to_intr_mode(sys);
if (ret == -GSI_STATUS_PENDING_IRQ)
goto start_poll;
if (ipa3_ctx->use_ipa_pm)
ipa_pm_deferred_deactivate(sys->pm_hdl);
else
@ -4059,6 +4062,7 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight)
}
ep = &ipa3_ctx->ep[clnt_hdl];
start_poll:
while (remain_aggr_weight > 0 &&
atomic_read(&ep->sys->curr_polling_state)) {
atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
@ -4086,7 +4090,11 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight)
cnt += weight - remain_aggr_weight * IPA_WAN_AGGR_PKT_CNT;
if (cnt < weight) {
napi_complete(ep->sys->napi_obj);
ipa3_rx_switch_to_intr_mode(ep->sys);
ret = ipa3_rx_switch_to_intr_mode(ep->sys);
if (ret == -GSI_STATUS_PENDING_IRQ &&
napi_reschedule(ep->sys->napi_obj))
goto start_poll;
if (ipa3_ctx->use_ipa_pm)
ipa_pm_deferred_deactivate(ep->sys->pm_hdl);
else

@ -6694,6 +6694,15 @@ void ipa3_suspend_apps_pipes(bool suspend)
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);
@ -6713,9 +6722,6 @@ void ipa3_suspend_apps_pipes(bool suspend)
}
if (suspend)
ipa3_gsi_poll_after_suspend(ep);
else if (!atomic_read(&ep->sys->curr_polling_state))
gsi_config_channel_mode(ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
}
ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS);
@ -6728,6 +6734,14 @@ void ipa3_suspend_apps_pipes(bool suspend)
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);
@ -6747,9 +6761,6 @@ void ipa3_suspend_apps_pipes(bool suspend)
}
if (suspend)
ipa3_gsi_poll_after_suspend(ep);
else if (!atomic_read(&ep->sys->curr_polling_state))
gsi_config_channel_mode(ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
}
}

@ -39,6 +39,7 @@ enum gsi_status {
GSI_STATUS_EVT_RING_INCOMPATIBLE = 10,
GSI_STATUS_TIMED_OUT = 11,
GSI_STATUS_AGAIN = 12,
GSI_STATUS_PENDING_IRQ = 13,
};
enum gsi_per_evt {

Loading…
Cancel
Save