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

Commit dc7eade7 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

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

parents ab8067aa f11fe070
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -770,6 +770,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
 */
@@ -778,6 +798,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);
@@ -786,8 +808,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);
		}
	}

@@ -4301,6 +4325,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
@@ -7704,7 +7704,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;

@@ -7723,16 +7723,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);
@@ -7749,7 +7749,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) {
@@ -7805,18 +7815,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;
@@ -7832,7 +7853,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);
@@ -7841,28 +7862,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;
}