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

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

Merge "msm: ipa: fix to poll channel state if GSI interrupt is not yet received"

parents cacb3774 ab667544
Loading
Loading
Loading
Loading
+82 −33
Original line number Diff line number Diff line
@@ -23,7 +23,9 @@
#include "gsi_emulation.h"

#define GSI_CMD_TIMEOUT (5*HZ)
#define GSI_STOP_CMD_TIMEOUT_MS 50
#define GSI_START_CMD_TIMEOUT_MS 1000
#define GSI_CMD_POLL_CNT 5
#define GSI_STOP_CMD_TIMEOUT_MS 10
#define GSI_MAX_CH_LOW_WEIGHT 15

#define GSI_RESET_WA_MIN_SLEEP 1000
@@ -112,6 +114,65 @@ static void __gsi_config_gen_irq(int ee, uint32_t mask, uint32_t val)
			GSI_EE_n_CNTXT_GSI_IRQ_EN_OFFS(ee));
}

static void gsi_channel_state_change_wait(unsigned long chan_hdl,
	struct gsi_chan_ctx *ctx,
	uint32_t tm,
	enum gsi_chan_state next_state)
{
	int poll_cnt;
	int gsi_pending_intr;
	int res;
	uint32_t ch;
	uint32_t val;
	int ee = gsi_ctx->per.ee;

	/*
	 * Start polling the GSI channel for
	 * duration = tm * poll_cnt.
	 * We need to do polling of gsi state for improving debugability
	 * of gsi hw state.
	 */

	for (poll_cnt = 0;
		poll_cnt < GSI_CMD_POLL_CNT;
		poll_cnt++) {
		res = wait_for_completion_timeout(&ctx->compl,
			msecs_to_jiffies(tm));

		/* Interrupt received, return */
		if (res != 0)
			return;

		/*
		 * 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));

		ctx->state = (val &
			GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK) >>
			GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT;

		ch = 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));

		GSIDBG("GSI wait on chan_hld=%lu chan=%lu state=%u intr=%u\n",
			chan_hdl,
			ch,
			ctx->state,
			gsi_pending_intr);

		if (ctx->state == next_state)
			break;
	}

}

static void gsi_handle_ch_ctrl(int ee)
{
	uint32_t ch;
@@ -2317,7 +2378,6 @@ EXPORT_SYMBOL(gsi_query_channel_db_addr);
int gsi_start_channel(unsigned long chan_hdl)
{
	enum gsi_ch_cmd_opcode op = GSI_CH_START;
	int res;
	uint32_t val;
	struct gsi_chan_ctx *ctx;

@@ -2350,21 +2410,25 @@ int gsi_start_channel(unsigned long chan_hdl)
		 GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK));
	gsi_writel(val, gsi_ctx->base +
			GSI_EE_n_GSI_CH_CMD_OFFS(gsi_ctx->per.ee));
	res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT);
	if (res == 0) {
		GSIERR("chan_hdl=%lu timed out\n", chan_hdl);
		mutex_unlock(&gsi_ctx->mlock);
		return -GSI_STATUS_TIMED_OUT;
	}

	GSIDBG("GSI Channel Start, waiting for completion\n");
	gsi_channel_state_change_wait(chan_hdl,
		ctx,
		GSI_START_CMD_TIMEOUT_MS,
		GSI_CHAN_STATE_STARTED);

	if (ctx->state != GSI_CHAN_STATE_STARTED) {
		GSIERR("chan=%lu unexpected state=%u\n", chan_hdl, ctx->state);
		/*
		* Hardware returned unexpected status, unexpected
		* hardware state.
		*/
		GSIERR("chan=%lu timed out, unexpected state=%u\n",
			chan_hdl, ctx->state);
		BUG();
	}

	GSIDBG("GSI Channel=%lu Start success\n", chan_hdl);

	/* write order MUST be MSB followed by LSB */
	val = ((ctx->ring.wp_local >> 32) &
		GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK) <<
@@ -2420,27 +2484,12 @@ int gsi_stop_channel(unsigned long chan_hdl)
		 GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK));
	gsi_writel(val, gsi_ctx->base +
			GSI_EE_n_GSI_CH_CMD_OFFS(gsi_ctx->per.ee));
	res = wait_for_completion_timeout(&ctx->compl,
			msecs_to_jiffies(GSI_STOP_CMD_TIMEOUT_MS));
	if (res == 0) {
		/*
		 * check channel state here in case the channel is stopped but
		 * the interrupt was not handled yet.
		 */
		val = gsi_readl(gsi_ctx->base +
			GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(chan_hdl,
			gsi_ctx->per.ee));
		ctx->state = (val &
			GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK) >>
			GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT;
		if (ctx->state == GSI_CHAN_STATE_STOPPED) {
			res = GSI_STATUS_SUCCESS;
			goto free_lock;
		}
		GSIDBG("chan_hdl=%lu timed out\n", chan_hdl);
		res = -GSI_STATUS_TIMED_OUT;
		goto free_lock;
	}

	GSIDBG("GSI Channel Stop, waiting for completion\n");
	gsi_channel_state_change_wait(chan_hdl,
		ctx,
		GSI_STOP_CMD_TIMEOUT_MS,
		GSI_CHAN_STATE_STOPPED);

	if (ctx->state != GSI_CHAN_STATE_STOPPED &&
		ctx->state != GSI_CHAN_STATE_STOP_IN_PROC) {