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

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

Merge "msm: ipa4: Fix to WLAN client disconnect/connect issue"

parents ee7bab95 5b4fbdad
Loading
Loading
Loading
Loading
+84 −0
Original line number Diff line number Diff line
@@ -2203,6 +2203,57 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl,
}
EXPORT_SYMBOL(gsi_alloc_channel);

static int gsi_alloc_ap_channel(unsigned int chan_hdl)
{
	struct gsi_chan_ctx *ctx;
	uint32_t val;
	int res;
	int ee;
	enum gsi_ch_cmd_opcode op = GSI_CH_ALLOCATE;

	if (!gsi_ctx) {
		pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
		return -GSI_STATUS_NODEV;
	}

	ctx = &gsi_ctx->chan[chan_hdl];
	if (ctx->allocated) {
		GSIERR("chan %d already allocated\n", chan_hdl);
		return -GSI_STATUS_NODEV;
	}

	memset(ctx, 0, sizeof(*ctx));

	mutex_init(&ctx->mlock);
	init_completion(&ctx->compl);
	atomic_set(&ctx->poll_mode, GSI_CHAN_MODE_CALLBACK);

	mutex_lock(&gsi_ctx->mlock);
	ee = gsi_ctx->per.ee;
	gsi_ctx->ch_dbg[chan_hdl].ch_allocate++;
	val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) &
				GSI_EE_n_GSI_CH_CMD_CHID_BMSK) |
			((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) &
			 GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK));
	gsi_writel(val, gsi_ctx->base +
			GSI_EE_n_GSI_CH_CMD_OFFS(ee));
	res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT);
	if (res == 0) {
		GSIERR("chan_hdl=%u timed out\n", chan_hdl);
		mutex_unlock(&gsi_ctx->mlock);
		return -GSI_STATUS_TIMED_OUT;
	}
	if (ctx->state != GSI_CHAN_STATE_ALLOCATED) {
		GSIERR("chan_hdl=%u allocation failed state=%d\n",
				chan_hdl, ctx->state);
		mutex_unlock(&gsi_ctx->mlock);
		return -GSI_STATUS_RES_ALLOC_FAILURE;
	}
	mutex_unlock(&gsi_ctx->mlock);

	return GSI_STATUS_SUCCESS;
}

static void __gsi_write_channel_scratch(unsigned long chan_hdl,
		union __packed gsi_channel_scratch val)
{
@@ -2221,6 +2272,36 @@ static void __gsi_write_channel_scratch(unsigned long chan_hdl,
			gsi_ctx->per.ee));
}

int gsi_write_channel_scratch3_reg(unsigned long chan_hdl,
		union __packed gsi_wdi_channel_scratch3_reg val)
{
	struct gsi_chan_ctx *ctx;

	if (!gsi_ctx) {
		pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
		return -GSI_STATUS_NODEV;
	}

	if (chan_hdl >= gsi_ctx->max_ch) {
		GSIERR("bad params chan_hdl=%lu\n", chan_hdl);
		return -GSI_STATUS_INVALID_PARAMS;
	}

	ctx = &gsi_ctx->chan[chan_hdl];

	mutex_lock(&ctx->mlock);

	ctx->scratch.wdi.endp_metadatareg_offset =
				val.wdi.endp_metadatareg_offset;
	ctx->scratch.wdi.qmap_id = val.wdi.qmap_id;

	gsi_writel(val.data.word1, gsi_ctx->base +
		GSI_EE_n_GSI_CH_k_SCRATCH_3_OFFS(chan_hdl,
			gsi_ctx->per.ee));
	mutex_unlock(&ctx->mlock);
	return GSI_STATUS_SUCCESS;
}

static void __gsi_read_channel_scratch(unsigned long chan_hdl,
		union __packed gsi_channel_scratch * val)
{
@@ -3632,6 +3713,9 @@ int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, int *code)
		return -GSI_STATUS_INVALID_PARAMS;
	}

	if (ee == 0)
		return gsi_alloc_ap_channel(chan_idx);

	mutex_lock(&gsi_ctx->mlock);
	reinit_completion(&gsi_ctx->gen_ee_cmd_compl);

+40 −79
Original line number Diff line number Diff line
@@ -1857,12 +1857,8 @@ int ipa3_disconnect_gsi_wdi_pipe(u32 clnt_hdl)
	if (!ep->keep_ipa_awake)
		IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));

	result = gsi_reset_evt_ring(ep->gsi_evt_ring_hdl);
	if (result != GSI_STATUS_SUCCESS) {
		IPAERR("Failed to reset evt ring: %d.\n",
				result);
		goto fail_dealloc_channel;
	}
	ipa3_reset_gsi_channel(clnt_hdl);
	ipa3_reset_gsi_event_ring(clnt_hdl);

	if (!ep->keep_ipa_awake)
		IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
@@ -2223,6 +2219,8 @@ int ipa3_resume_gsi_wdi_pipe(u32 clnt_hdl)
	int result = 0;
	struct ipa3_ep_context *ep;
	struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
	struct gsi_chan_info chan_info;
	union __packed gsi_channel_scratch gsi_scratch;

	IPADBG("ep=%d\n", clnt_hdl);
	ep = &ipa3_ctx->ep[clnt_hdl];
@@ -2246,6 +2244,19 @@ int ipa3_resume_gsi_wdi_pipe(u32 clnt_hdl)
		IPAERR("gsi_start_channel failed %d\n", result);
		ipa_assert();
	}
	gsi_query_channel_info(ep->gsi_chan_hdl, &chan_info);
	gsi_read_channel_scratch(ep->gsi_chan_hdl, &gsi_scratch);
	IPADBG("ch=%lu channel base = 0x%llx , event base 0x%llx\n",
				ep->gsi_chan_hdl,
				ep->gsi_mem_info.chan_ring_base_addr,
				ep->gsi_mem_info.evt_ring_base_addr);
	IPADBG("RP=0x%llx WP=0x%llx ev_valid=%d ERP=0x%llx EWP=0x%llx\n",
			chan_info.rp, chan_info.wp, chan_info.evt_valid,
			chan_info.evt_rp, chan_info.evt_wp);
	IPADBG("Scratch 0 = %x Scratch 1 = %x Scratch 2 = %x Scratch 3 = %x\n",
				gsi_scratch.data.word1, gsi_scratch.data.word2,
				gsi_scratch.data.word3, gsi_scratch.data.word4);

	ep->gsi_offload_state |= IPA_WDI_RESUMED;
	IPADBG("exit\n");
	return result;
@@ -2324,6 +2335,8 @@ int ipa3_suspend_gsi_wdi_pipe(u32 clnt_hdl)
	bool disable_force_clear = false;
	struct ipahal_ep_cfg_ctrl_scnd ep_ctrl_scnd = { 0 };
	int retry_cnt = 0;
	struct gsi_chan_info chan_info;
	union __packed gsi_channel_scratch gsi_scratch;

	ipa_ep_idx = ipa3_get_ep_mapping(ipa3_get_client_mapping(clnt_hdl));
	if (ipa_ep_idx < 0) {
@@ -2373,14 +2386,22 @@ int ipa3_suspend_gsi_wdi_pipe(u32 clnt_hdl)
		} else {
			IPADBG("GSI channel %ld STOP\n", ep->gsi_chan_hdl);
		}

		res = ipa3_reset_gsi_channel(clnt_hdl);
		if (res != GSI_STATUS_SUCCESS) {
			IPAERR("Failed to reset chan: %d.\n", res);
			goto fail_stop_channel;
		gsi_query_channel_info(ep->gsi_chan_hdl, &chan_info);
		gsi_read_channel_scratch(ep->gsi_chan_hdl, &gsi_scratch);
		IPADBG("ch=%lu channel base = 0x%llx , event base 0x%llx\n",
				ep->gsi_chan_hdl,
				ep->gsi_mem_info.chan_ring_base_addr,
				ep->gsi_mem_info.evt_ring_base_addr);
		IPADBG("RP=0x%llx WP=0x%llx ev_valid=%d ERP=0x%llx",
				chan_info.rp, chan_info.wp,
				chan_info.evt_valid, chan_info.evt_rp);
		IPADBG("EWP=0x%llx\n", chan_info.evt_wp);
		IPADBG("Scratch 0 = %x Scratch 1 = %x Scratch 2 = %x",
				gsi_scratch.data.word1, gsi_scratch.data.word2,
				gsi_scratch.data.word3);
		IPADBG("Scratch 3 = %x\n", gsi_scratch.data.word4);
	}

	}
	if (disable_force_clear)
		ipa3_disable_force_clear(clnt_hdl);
	IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
@@ -2539,87 +2560,27 @@ int ipa3_write_qmapid_gsi_wdi_pipe(u32 clnt_hdl, u8 qmap_id)
{
	int result = 0;
	struct ipa3_ep_context *ep;
	union __packed gsi_channel_scratch gsi_scratch;
	int retry_cnt = 0;
	u32 source_pipe_bitmask = 0;
	bool disable_force_clear = false;
	struct ipahal_ep_cfg_ctrl_scnd ep_ctrl_scnd = { 0 };
	union __packed gsi_wdi_channel_scratch3_reg gsi_scratch;

	memset(&gsi_scratch, 0, sizeof(gsi_scratch));
	ep = &ipa3_ctx->ep[clnt_hdl];
	IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));
	result = gsi_read_channel_scratch(ep->gsi_chan_hdl, &gsi_scratch);

	if (result != GSI_STATUS_SUCCESS) {
		IPAERR("gsi_read_write_channel_scratch failed %d\n",
			result);
		goto fail_read_channel_scratch;
	}
	if (ep->gsi_offload_state == (IPA_WDI_CONNECTED | IPA_WDI_ENABLED |
						IPA_WDI_RESUMED)) {
		source_pipe_bitmask = 1 <<
			ipa3_get_ep_mapping(ep->client);
		result = ipa3_enable_force_clear(clnt_hdl,
				false, source_pipe_bitmask);
		if (result) {
			/*
			 * assuming here modem SSR, AP can remove
			 * the delay in this case
			 */
			IPAERR("failed to force clear %d\n", result);
			IPAERR("remove delay from SCND reg\n");
			ep_ctrl_scnd.endp_delay = false;
			ipahal_write_reg_n_fields(
					IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl,
					&ep_ctrl_scnd);
		} else {
			disable_force_clear = true;
		}

retry_gsi_stop:
		result = ipa3_stop_gsi_channel(clnt_hdl);
		if (result != 0 && result != -GSI_STATUS_AGAIN &&
				result != -GSI_STATUS_TIMED_OUT) {
			IPAERR("GSI stop channel failed %d\n",
					result);
			goto fail_stop_channel;
		} else if (result == -GSI_STATUS_AGAIN) {
			IPADBG("GSI stop channel failed retry cnt = %d\n",
						retry_cnt);
			retry_cnt++;
			if (retry_cnt >= GSI_STOP_MAX_RETRY_CNT)
				goto fail_stop_channel;
			goto retry_gsi_stop;
		} else {
			IPADBG("GSI channel %ld STOP\n", ep->gsi_chan_hdl);
		}
	}
	gsi_scratch.wdi.qmap_id = qmap_id;
	result = gsi_write_channel_scratch(ep->gsi_chan_hdl,
			gsi_scratch);
	gsi_scratch.wdi.endp_metadatareg_offset = ipahal_get_reg_mn_ofst(
				IPA_ENDP_INIT_HDR_METADATA_n, 0, clnt_hdl)/4;

	result = gsi_write_channel_scratch3_reg(ep->gsi_chan_hdl, gsi_scratch);
	if (result != GSI_STATUS_SUCCESS) {
		IPAERR("gsi_write_channel_scratch failed %d\n",
			result);
		goto fail_write_channel_scratch;
	}
	if (ep->gsi_offload_state == (IPA_WDI_CONNECTED | IPA_WDI_ENABLED |
						IPA_WDI_RESUMED)) {
		result =  gsi_start_channel(ep->gsi_chan_hdl);
		if (result != GSI_STATUS_SUCCESS) {
			IPAERR("gsi_start_channel failed %d\n", result);
			goto fail_start_channel;
		}
	}

	if (disable_force_clear)
		ipa3_disable_force_clear(clnt_hdl);

	IPADBG("client (ep: %d) qmap_id %d updated\n", clnt_hdl, qmap_id);
	IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
	return 0;
fail_start_channel:
fail_read_channel_scratch:
fail_write_channel_scratch:
fail_stop_channel:
	ipa_assert();
	return result;
}
+40 −0
Original line number Diff line number Diff line
@@ -690,6 +690,28 @@ union __packed gsi_channel_scratch {
	} data;
};

/**
 * gsi_wdi_channel_scratch3 - WDI protocol SW config area of
 * channel scratch3
 */

struct __packed gsi_wdi_channel_scratch3 {
	uint32_t endp_metadatareg_offset:16;
	uint32_t qmap_id:16;
};

/**
 * gsi_wdi_channel_scratch3_reg - channel scratch3 SW config area
 *
 */

union __packed gsi_wdi_channel_scratch3_reg {
	struct __packed gsi_wdi_channel_scratch3 wdi;
	struct __packed {
		uint32_t word1;
	} data;
};

/**
 * gsi_mhi_evt_scratch - MHI protocol SW config area of
 * event scratch
@@ -976,6 +998,19 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl,
int gsi_write_channel_scratch(unsigned long chan_hdl,
		union __packed gsi_channel_scratch val);

/**
 * gsi_write_channel_scratch3_reg - Peripheral should call this function to
 * write to the scratch3 reg area of the channel context
 *
 * @chan_hdl:  Client handle previously obtained from
 *             gsi_alloc_channel
 * @val:       Value to write
 *
 * @Return gsi_status
 */
int gsi_write_channel_scratch3_reg(unsigned long chan_hdl,
		union __packed gsi_wdi_channel_scratch3_reg val);

/**
 * gsi_read_channel_scratch - Peripheral should call this function to
 * read to the scratch area of the channel context
@@ -1408,6 +1443,11 @@ static inline int gsi_write_channel_scratch(unsigned long chan_hdl,
{
	return -GSI_STATUS_UNSUPPORTED_OP;
}
static inline int gsi_write_channel_scratch3_reg(unsigned long chan_hdl,
		union __packed gsi_wdi_channel_scratch3_reg val)
{
	return -GSI_STATUS_UNSUPPORTED_OP;
}

static inline int gsi_read_channel_scratch(unsigned long chan_hdl,
		union __packed gsi_channel_scratch *val)