Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f9f7c4d authored by Skylar Chang's avatar Skylar Chang Committed by Mohammed Javid
Browse files

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: default avatarAdy Abraham <adya@qti.qualcomm.com>
Acked-by: default avatarAshok Vuyyuru <avuyyuru@qti.qualcomm.com>
Signed-off-by: default avatarSkylar Chang <chiaweic@codeaurora.org>
parent 87874f76
Loading
Loading
Loading
Loading
+27 −0
Original line number Original line Diff line number Diff line
@@ -3267,6 +3267,33 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode)
			mode == GSI_CHAN_MODE_CALLBACK) {
			mode == GSI_CHAN_MODE_CALLBACK) {
		atomic_set(&ctx->poll_mode, mode);
		atomic_set(&ctx->poll_mode, mode);
		__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0);
		__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++;
		ctx->stats.poll_to_callback++;
	}
	}
	spin_unlock_irqrestore(&gsi_ctx->slock, flags);
	spin_unlock_irqrestore(&gsi_ctx->slock, flags);
+1 −0
Original line number Original line Diff line number Diff line
@@ -120,6 +120,7 @@ struct gsi_chan_stats {
	unsigned long completed;
	unsigned long completed;
	unsigned long callback_to_poll;
	unsigned long callback_to_poll;
	unsigned long poll_to_callback;
	unsigned long poll_to_callback;
	unsigned long poll_pending_irq;
	unsigned long invalid_tre_error;
	unsigned long invalid_tre_error;
	unsigned long poll_ok;
	unsigned long poll_ok;
	unsigned long poll_empty;
	unsigned long poll_empty;
+3 −2
Original line number Original line Diff line number Diff line
@@ -273,9 +273,10 @@ static void gsi_dump_ch_stats(struct gsi_chan_ctx *ctx)
	PRT_STAT("queued=%lu compl=%lu\n",
	PRT_STAT("queued=%lu compl=%lu\n",
		ctx->stats.queued,
		ctx->stats.queued,
		ctx->stats.completed);
		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.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",
	PRT_STAT("invalid_tre_error=%lu\n",
		ctx->stats.invalid_tre_error);
		ctx->stats.invalid_tre_error);
	PRT_STAT("poll_ok=%lu poll_empty=%lu\n",
	PRT_STAT("poll_ok=%lu poll_empty=%lu\n",
+22 −14
Original line number Original line Diff line number Diff line
@@ -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
 * 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;
	int ret;


	if (!atomic_read(&sys->curr_polling_state)) {
		IPAERR("already in intr mode\n");
		goto fail;
	}
	atomic_set(&sys->curr_polling_state, 0);
	atomic_set(&sys->curr_polling_state, 0);
	ipa3_dec_release_wakelock();
	ipa3_dec_release_wakelock();
	ret = gsi_config_channel_mode(sys->ep->gsi_chan_hdl,
	ret = gsi_config_channel_mode(sys->ep->gsi_chan_hdl,
		GSI_CHAN_MODE_CALLBACK);
		GSI_CHAN_MODE_CALLBACK);
	if (ret != GSI_STATUS_SUCCESS) {
	if (ret != GSI_STATUS_SUCCESS) {
		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");
			IPAERR("Failed to switch to intr mode.\n");
		goto fail;
		}
		}
	return;
	}


fail:
	return ret;
	queue_delayed_work(sys->wq, &sys->switch_to_intr_work,
			msecs_to_jiffies(1));
}
}


/**
/**
@@ -785,13 +782,16 @@ static void ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys)
 */
 */
static void ipa3_handle_rx(struct ipa3_sys_context *sys)
static void ipa3_handle_rx(struct ipa3_sys_context *sys)
{
{
	int inactive_cycles = 0;
	int inactive_cycles;
	int cnt;
	int cnt;
	int ret;


	if (ipa3_ctx->use_ipa_pm)
	if (ipa3_ctx->use_ipa_pm)
		ipa_pm_activate_sync(sys->pm_hdl);
		ipa_pm_activate_sync(sys->pm_hdl);
	else
	else
		IPA_ACTIVE_CLIENTS_INC_SIMPLE();
		IPA_ACTIVE_CLIENTS_INC_SIMPLE();
start_poll:
	inactive_cycles = 0;
	do {
	do {
		cnt = ipa3_handle_rx_core(sys, true, true);
		cnt = ipa3_handle_rx_core(sys, true, true);
		if (cnt == 0)
		if (cnt == 0)
@@ -814,7 +814,10 @@ static void ipa3_handle_rx(struct ipa3_sys_context *sys)
	} while (inactive_cycles <= POLLING_INACTIVITY_RX);
	} while (inactive_cycles <= POLLING_INACTIVITY_RX);


	trace_poll_to_intr3(sys->ep->client);
	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)
	if (ipa3_ctx->use_ipa_pm)
		ipa_pm_deferred_deactivate(sys->pm_hdl);
		ipa_pm_deferred_deactivate(sys->pm_hdl);
	else
	else
@@ -4059,6 +4062,7 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight)
	}
	}


	ep = &ipa3_ctx->ep[clnt_hdl];
	ep = &ipa3_ctx->ep[clnt_hdl];
start_poll:
	while (remain_aggr_weight > 0 &&
	while (remain_aggr_weight > 0 &&
			atomic_read(&ep->sys->curr_polling_state)) {
			atomic_read(&ep->sys->curr_polling_state)) {
		atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
		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;
	cnt += weight - remain_aggr_weight * IPA_WAN_AGGR_PKT_CNT;
	if (cnt < weight) {
	if (cnt < weight) {
		napi_complete(ep->sys->napi_obj);
		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)
		if (ipa3_ctx->use_ipa_pm)
			ipa_pm_deferred_deactivate(ep->sys->pm_hdl);
			ipa_pm_deferred_deactivate(ep->sys->pm_hdl);
		else
		else
+17 −6
Original line number Original line Diff line number Diff line
@@ -6694,6 +6694,15 @@ void ipa3_suspend_apps_pipes(bool suspend)
	if (ep->valid) {
	if (ep->valid) {
		IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
		IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
			ipa_ep_idx);
			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 (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
			if (suspend) {
			if (suspend) {
				res = __ipa3_stop_gsi_channel(ipa_ep_idx);
				res = __ipa3_stop_gsi_channel(ipa_ep_idx);
@@ -6713,9 +6722,6 @@ void ipa3_suspend_apps_pipes(bool suspend)
		}
		}
		if (suspend)
		if (suspend)
			ipa3_gsi_poll_after_suspend(ep);
			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);
	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) {
	if (ep->valid) {
		IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
		IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
			ipa_ep_idx);
			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 (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
			if (suspend) {
			if (suspend) {
				res = __ipa3_stop_gsi_channel(ipa_ep_idx);
				res = __ipa3_stop_gsi_channel(ipa_ep_idx);
@@ -6747,9 +6761,6 @@ void ipa3_suspend_apps_pipes(bool suspend)
		}
		}
		if (suspend)
		if (suspend)
			ipa3_gsi_poll_after_suspend(ep);
			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);
	}
	}
}
}


Loading