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

Commit f11fe070 authored by Ashok Vuyyuru's avatar Ashok Vuyyuru
Browse files

msm: ipa3: Fix to race condition in updating current polling state



Configure the callback mode only one time after starting the channel
otherwise observing IEOB interrupt received before configure callback
mode second time. It was leading race condition in updating current
polling state.

Change-Id: I35cdf77ee564ca82d9ff3e0cc6a58a88e8cbb471
Signed-off-by: default avatarAshok Vuyyuru <avuyyuru@codeaurora.org>
parent 757c4610
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -768,6 +768,26 @@ static int ipa3_handle_rx_core(struct ipa3_sys_context *sys, bool process_all,
	return cnt;
}

/**
 * __ipa3_update_curr_poll_state -> update current polling for default wan and
 *                                  coalescing pipe.
 * In RSC/RSB enabled cases using common event ring, so both the pipe
 * polling state should be in sync.
 */
void __ipa3_update_curr_poll_state(enum ipa_client_type client, int state)
{
	int ep_idx = IPA_EP_NOT_ALLOCATED;

	if (client == IPA_CLIENT_APPS_WAN_COAL_CONS)
		ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS);
	if (client == IPA_CLIENT_APPS_WAN_CONS)
		ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS);

	if (ep_idx != IPA_EP_NOT_ALLOCATED && ipa3_ctx->ep[ep_idx].sys)
		atomic_set(&ipa3_ctx->ep[ep_idx].sys->curr_polling_state,
									state);
}

/**
 * ipa3_rx_switch_to_intr_mode() - Operate the Rx data path in interrupt mode
 */
@@ -776,6 +796,8 @@ static int ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys)
	int ret;

	atomic_set(&sys->curr_polling_state, 0);
	__ipa3_update_curr_poll_state(sys->ep->client, 0);

	ipa3_dec_release_wakelock();
	ret = gsi_config_channel_mode(sys->ep->gsi_chan_hdl,
		GSI_CHAN_MODE_CALLBACK);
@@ -784,8 +806,10 @@ static int ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys)
		if (ret == -GSI_STATUS_PENDING_IRQ) {
			ipa3_inc_acquire_wakelock();
			atomic_set(&sys->curr_polling_state, 1);
			__ipa3_update_curr_poll_state(sys->ep->client, 1);
		} else {
			IPAERR("Failed to switch to intr mode.\n");
			IPAERR("Failed to switch to intr mode %d ch_id %d\n",
			 sys->curr_polling_state, sys->ep->gsi_chan_hdl);
		}
	}

@@ -4277,6 +4301,8 @@ void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys)
	bool clk_off;

	atomic_set(&sys->curr_polling_state, 1);
	__ipa3_update_curr_poll_state(sys->ep->client, 1);

	ipa3_inc_acquire_wakelock();

	/*
+65 −35
Original line number Diff line number Diff line
@@ -7703,7 +7703,7 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl)

static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend)
{
	int ipa_ep_idx;
	int ipa_ep_idx, coal_ep_idx;
	struct ipa3_ep_context *ep;
	int res;

@@ -7722,16 +7722,16 @@ static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend)
	if (!ep->valid)
		return 0;

	coal_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS);

	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
	 * Configure the callback mode only one time after starting the channel
	 * otherwise observing IEOB interrupt received before configure callmode
	 * second time. It was leading race condition in updating current
	 * polling state.
	 */
	if (!suspend && !atomic_read(&ep->sys->curr_polling_state) &&
		!IPA_CLIENT_IS_APPS_PROD(client))
		gsi_config_channel_mode(ep->gsi_chan_hdl,
					GSI_CHAN_MODE_CALLBACK);

	if (suspend) {
		res = __ipa3_stop_gsi_channel(ipa_ep_idx);
@@ -7748,7 +7748,17 @@ static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend)
	}

	/* Apps prod pipes use common event ring so cannot configure mode*/
	if (IPA_CLIENT_IS_APPS_PROD(client))

	/*
	 * Skipping to configure mode for default wan pipe,
	 * as both pipes using commong event ring. if both pipes
	 * configure same event ring observing race condition in
	 * updating current polling state.
	 */

	if (IPA_CLIENT_IS_APPS_PROD(client) ||
		(client == IPA_CLIENT_APPS_WAN_CONS &&
			coal_ep_idx != IPA_EP_NOT_ALLOCATED))
		return 0;

	if (suspend) {
@@ -7804,18 +7814,29 @@ void ipa3_force_close_coal(void)
int ipa3_suspend_apps_pipes(bool suspend)
{
	int res;
	enum ipa_client_type client;

	if (suspend)
		ipa3_force_close_coal();

	for (client = 0; client < IPA_CLIENT_MAX; client++) {
		if (IPA_CLIENT_IS_APPS_CONS(client)) {
			res = _ipa_suspend_resume_pipe(client, suspend);
			if (res)
				goto undo_cons;
		}
	}
	/* As per HPG first need start/stop coalescing channel
	 * then default one. Coalescing client number was greater then
	 * default one so starting the last client.
	 */
	res = _ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_COAL_CONS, suspend);
	if (res == -EAGAIN)
		goto undo_coal_cons;

	res = _ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_CONS, suspend);
	if (res == -EAGAIN)
		goto undo_wan_cons;

	res = _ipa_suspend_resume_pipe(IPA_CLIENT_APPS_LAN_CONS, suspend);
	if (res == -EAGAIN)
		goto undo_lan_cons;

	res = _ipa_suspend_resume_pipe(IPA_CLIENT_ODL_DPL_CONS, suspend);
	if (res == -EAGAIN)
		goto undo_odl_cons;

	if (suspend) {
		struct ipahal_reg_tx_wrapper tx;
@@ -7831,7 +7852,7 @@ int ipa3_suspend_apps_pipes(bool suspend)
			IPADBG("COAL frame is open 0x%x\n",
				tx.coal_slave_open_frame);
			res = -EAGAIN;
			goto undo_cons;
			goto undo_odl_cons;
		}

		usleep_range(IPA_TAG_SLEEP_MIN_USEC, IPA_TAG_SLEEP_MAX_USEC);
@@ -7840,28 +7861,37 @@ int ipa3_suspend_apps_pipes(bool suspend)
			ipa3_ctx->ee);
		if (res) {
			IPADBG("suspend irq is pending 0x%x\n", res);
			goto undo_cons;
			goto undo_odl_cons;
		}
	}
do_prod:
	for (client = 0; client < IPA_CLIENT_MAX; client++) {
		if (IPA_CLIENT_IS_APPS_PROD(client)) {
			res = _ipa_suspend_resume_pipe(client, suspend);
			if (res)
				goto undo_prod;
		}
	}
	res = _ipa_suspend_resume_pipe(IPA_CLIENT_APPS_LAN_PROD, suspend);
	if (res == -EAGAIN)
		goto undo_lan_prod;
	res = _ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_PROD, suspend);
	if (res == -EAGAIN)
		goto undo_wan_prod;

	return 0;
undo_prod:
	for (client; client <= IPA_CLIENT_MAX && client >= 0; client--)
		if (IPA_CLIENT_IS_APPS_PROD(client))
			_ipa_suspend_resume_pipe(client, !suspend);
	client = IPA_CLIENT_MAX;
undo_cons:
	for (client; client <= IPA_CLIENT_MAX && client >= 0; client--)
		if (IPA_CLIENT_IS_APPS_CONS(client))
			_ipa_suspend_resume_pipe(client, !suspend);

undo_wan_prod:
	_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_PROD, !suspend);

undo_lan_prod:
	_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_LAN_PROD, !suspend);

undo_odl_cons:
	_ipa_suspend_resume_pipe(IPA_CLIENT_ODL_DPL_CONS, !suspend);
undo_lan_cons:
	_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_LAN_CONS, !suspend);
undo_wan_cons:
	_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_COAL_CONS, !suspend);
	_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_CONS, !suspend);
	return res;

undo_coal_cons:
	_ipa_suspend_resume_pipe(IPA_CLIENT_APPS_WAN_COAL_CONS, !suspend);

	return res;
}