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

Commit ab667544 authored by Michael Adisumarta's avatar Michael Adisumarta
Browse files

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



Changes to poll the GSI channel state if GSI interrupt indicating
completion of GSI writes is not yet received.

Acked-by: default avatarJyothi Jayanthi <jyothij@qti.qualcomm.com>
Signed-off-by: default avatarMichael Adisumarta <madisuma@codeaurora.org>
Change-Id: I8060a5ae7bd7941bb78073a84bd0bfe63405540c
parent 130b5c4c
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;
@@ -2275,7 +2336,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;

@@ -2308,21 +2368,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) <<
@@ -2378,27 +2442,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) {