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

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

Merge "msm: ipa4: flow control changes for rmnet pipe"

parents 48993f44 20557e54
Loading
Loading
Loading
Loading
+92 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/of.h>
@@ -4249,6 +4249,97 @@ int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, int *code)
}
EXPORT_SYMBOL(gsi_alloc_channel_ee);

int gsi_enable_flow_control_ee(unsigned int chan_idx, unsigned int ee,
								int *code)
{
	enum gsi_generic_ee_cmd_opcode op = GSI_GEN_EE_CMD_ENABLE_FLOW_CHANNEL;
	uint32_t val;
	enum gsi_chan_state curr_state = GSI_CHAN_STATE_NOT_ALLOCATED;
	int res;

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

	if (chan_idx >= gsi_ctx->max_ch || !code) {
		GSIERR("bad params chan_idx=%d\n", chan_idx);
		return -GSI_STATUS_INVALID_PARAMS;
	}

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

	/* invalidate the response */
	gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base +
			GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));
	gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code = 0;
	gsi_writel(gsi_ctx->scratch.word0.val, gsi_ctx->base +
			GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));

	gsi_ctx->gen_ee_cmd_dbg.flow_ctrl_channel++;
	val = (((op << GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT) &
		GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK) |
		((chan_idx << GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT) &
			GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK) |
		((ee << GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT) &
			GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK));
	gsi_writel(val, gsi_ctx->base +
		GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(gsi_ctx->per.ee));

	res = wait_for_completion_timeout(&gsi_ctx->gen_ee_cmd_compl,
		msecs_to_jiffies(GSI_CMD_TIMEOUT));
	if (res == 0) {
		GSIERR("chan_idx=%u ee=%u timed out\n", chan_idx, ee);
		res = -GSI_STATUS_TIMED_OUT;
		goto free_lock;
	}

	gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base +
		GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee));
	if (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code ==
		GSI_GEN_EE_CMD_RETURN_CODE_CHANNEL_NOT_RUNNING) {
		GSIDBG("chan_idx=%u ee=%u not in correct state\n",
							chan_idx, ee);
		*code = GSI_GEN_EE_CMD_RETURN_CODE_CHANNEL_NOT_RUNNING;
		res = -GSI_STATUS_RES_ALLOC_FAILURE;
		goto free_lock;
	} else if (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code ==
			GSI_GEN_EE_CMD_RETURN_CODE_INCORRECT_CHANNEL_TYPE ||
			gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code ==
			GSI_GEN_EE_CMD_RETURN_CODE_INCORRECT_CHANNEL_INDEX){
		GSIERR("chan_idx=%u ee=%u not in correct state\n",
				chan_idx, ee);
		GSI_ASSERT();
	}
	if (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code == 0) {
		GSIERR("No response received\n");
		res = -GSI_STATUS_ERROR;
		goto free_lock;
	}

	/*Reading current channel state*/
	val = gsi_readl(gsi_ctx->base +
				GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(chan_idx, ee));
	curr_state = (val &
				GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK) >>
				GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT;
	if (curr_state == GSI_CHAN_STATE_FLOW_CONTROL) {
		GSIDBG("ch %u state updated to %u\n", chan_idx, curr_state);
		res = GSI_STATUS_SUCCESS;
	} else {
		GSIERR("ch %u state updated to %u incorrect state\n",
							chan_idx, curr_state);
		res = -GSI_STATUS_ERROR;
	}
	*code = gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code;
free_lock:
	mutex_unlock(&gsi_ctx->mlock);

	return res;
}
EXPORT_SYMBOL(gsi_enable_flow_control_ee);

int gsi_map_virtual_ch_to_per_ep(u32 ee, u32 chan_num, u32 per_ep_index)
{
	if (!gsi_ctx) {
+4 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */

#ifndef GSI_H
@@ -198,6 +198,7 @@ struct ch_debug_stats {

struct gsi_generic_ee_cmd_debug_stats {
	unsigned long halt_channel;
	unsigned long flow_ctrl_channel;
};

struct gsi_coal_chan_info {
@@ -332,6 +333,8 @@ enum gsi_evt_ch_cmd_opcode {
enum gsi_generic_ee_cmd_opcode {
	GSI_GEN_EE_CMD_HALT_CHANNEL = 0x1,
	GSI_GEN_EE_CMD_ALLOC_CHANNEL = 0x2,
	GSI_GEN_EE_CMD_ENABLE_FLOW_CHANNEL = 0x3,
	GSI_GEN_EE_CMD_DISABLE_FLOW_CHANNEL = 0x4,
};

enum gsi_generic_ee_cmd_return_code {
+39 −4
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
 */

#include <asm/barrier.h>
@@ -583,6 +583,15 @@ int ipa3_request_gsi_channel(struct ipa_request_gsi_channel_params *params,
		IPADBG("ep configuration successful\n");
	} else {
		IPADBG("Skipping endpoint configuration.\n");
		if (IPA_CLIENT_IS_PROD(ipa3_ctx->ep[ipa_ep_idx].client) &&
			ipa3_ctx->ep[ipa_ep_idx].client == IPA_CLIENT_USB_PROD
			&& !ipa3_is_mhip_offload_enabled()) {
			if (ipa3_cfg_ep_seq(ipa_ep_idx,
						&params->ipa_ep_cfg.seq)) {
				IPAERR("fail to configure USB pipe seq\n");
				goto ipa_cfg_ep_fail;
			}
		}
	}

	out_params->clnt_hdl = ipa_ep_idx;
@@ -772,6 +781,7 @@ int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid)
	int result = -EFAULT;
	enum gsi_status gsi_res;
	struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
	int code = 0;

	IPADBG("entry\n");
	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes  ||
@@ -814,6 +824,20 @@ int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid)
		IPAERR("Error starting channel: %d\n", gsi_res);
		goto write_chan_scratch_fail;
	}

	if (IPA_CLIENT_IS_PROD(ep->client) && ep->skip_ep_cfg &&
			ipa3_ctx->ipa_endp_delay_wa &&
			!ipa3_is_mhip_offload_enabled()) {
		gsi_res = gsi_enable_flow_control_ee(ep->gsi_chan_hdl, 0,
									&code);
		if (gsi_res == GSI_STATUS_SUCCESS) {
			IPADBG("flow control sussess gsi ch %d with code %d\n",
					ep->gsi_chan_hdl, code);
		} else {
			IPADBG("failed to flow control gsi ch %d code %d\n",
					ep->gsi_chan_hdl, code);
		}
	}
	ipa3_start_gsi_debug_monitor(clnt_hdl);
	if (!ep->keep_ipa_awake)
		IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
@@ -1225,6 +1249,7 @@ int ipa3_start_stop_client_prod_gsi_chnl(enum ipa_client_type client,
	int result = 0;
	int pipe_idx;
	struct ipa3_ep_context *ep;
	int code = 0;

	if (IPA_CLIENT_IS_CONS(client)) {
		IPAERR("client (%d) not PROD\n", client);
@@ -1240,10 +1265,20 @@ int ipa3_start_stop_client_prod_gsi_chnl(enum ipa_client_type client,

	client_lock_unlock_cb(client, true);
	ep = &ipa3_ctx->ep[pipe_idx];
	if (ep->valid && ep->skip_ep_cfg && ipa3_get_teth_port_status(client)) {
		if (start_chnl)
	if (ep->valid && ep->skip_ep_cfg && ipa3_get_teth_port_status(client)
		&& !ipa3_is_mhip_offload_enabled()) {
		if (start_chnl) {
			result = ipa3_start_gsi_channel(pipe_idx);
		else
			result = gsi_enable_flow_control_ee(ep->gsi_chan_hdl,
								0, &code);
			if (result == GSI_STATUS_SUCCESS) {
				IPADBG("flow control sussess ch %d code %d\n",
						ep->gsi_chan_hdl, code);
			} else {
				IPADBG("failed to flow control ch %d code %d\n",
						ep->gsi_chan_hdl, code);
			}
		} else
			result = ipa3_stop_gsi_channel(pipe_idx);
	}
	client_lock_unlock_cb(client, false);
+2 −0
Original line number Diff line number Diff line
@@ -2358,6 +2358,8 @@ int ipa3_clear_endpoint_delay(u32 clnt_hdl);
 */
int ipa3_cfg_ep(u32 clnt_hdl, const struct ipa_ep_cfg *ipa_ep_cfg);

int ipa3_cfg_ep_seq(u32 clnt_hdl, const struct ipa_ep_cfg_seq *seq_cfg);

int ipa3_cfg_ep_nat(u32 clnt_hdl, const struct ipa_ep_cfg_nat *ipa_ep_cfg);

int ipa3_cfg_ep_conn_track(u32 clnt_hdl,
+55 −31
Original line number Diff line number Diff line
@@ -182,7 +182,8 @@ static int ipa3_mhi_get_ch_poll_cfg(enum ipa_client_type client,
}

static int ipa_mhi_start_gsi_channel(enum ipa_client_type client,
	int ipa_ep_idx, struct start_gsi_channel *params)
	int ipa_ep_idx, struct start_gsi_channel *params,
	struct ipa_ep_cfg *ipa_ep_cfg)
{
	int res = 0;
	struct gsi_evt_ring_props ev_props;
@@ -193,6 +194,7 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client,
	const struct ipa_gsi_ep_config *ep_cfg;
	struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
	bool burst_mode_enabled = false;
	int code = 0;

	IPA_MHI_FUNC_ENTRY();

@@ -342,6 +344,37 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client,

	*params->mhi = ch_scratch.mhi;

	res = ipa3_enable_data_path(ipa_ep_idx);
	if (res) {
		IPA_MHI_ERR("enable data path failed res=%d clnt=%d.\n", res,
			ipa_ep_idx);
		goto fail_ep_cfg;
	}

	if (!ep->skip_ep_cfg) {
		if (ipa3_cfg_ep(ipa_ep_idx, ipa_ep_cfg)) {
			IPAERR("fail to configure EP.\n");
			goto fail_ep_cfg;
		}
		if (ipa3_cfg_ep_status(ipa_ep_idx, &ep->status)) {
			IPAERR("fail to configure status of EP.\n");
			goto fail_ep_cfg;
		}
		IPA_MHI_DBG("ep configuration successful\n");
	} else {
		IPA_MHI_DBG("skipping ep configuration\n");
		if (IPA_CLIENT_IS_PROD(ipa3_ctx->ep[ipa_ep_idx].client) &&
			ipa3_ctx->ep[ipa_ep_idx].client == IPA_CLIENT_MHI_PROD
				&& !ipa3_is_mhip_offload_enabled()) {
			if (ipa3_cfg_ep_seq(ipa_ep_idx,
						&ipa_ep_cfg->seq)) {
				IPA_MHI_ERR("fail to configure USB pipe seq\n");
				goto fail_ep_cfg;
			}
		}

	}

	if (IPA_CLIENT_IS_PROD(ep->client) && ep->skip_ep_cfg) {
		memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
		ep_cfg_ctrl.ipa_ep_delay = true;
@@ -356,6 +389,9 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client,
		ep->ep_delay_set = false;
	}

	if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(client))
		ipa3_install_dflt_flt_rules(ipa_ep_idx);

	IPA_MHI_DBG("Starting channel\n");
	res = gsi_start_channel(ep->gsi_chan_hdl);
	if (res) {
@@ -363,9 +399,24 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client,
		goto fail_ch_start;
	}

	if (IPA_CLIENT_IS_PROD(ep->client) && ep->skip_ep_cfg &&
			ipa3_ctx->ipa_endp_delay_wa &&
			!ipa3_is_mhip_offload_enabled()) {
		res = gsi_enable_flow_control_ee(ep->gsi_chan_hdl, 0, &code);
		if (res == GSI_STATUS_SUCCESS) {
			IPA_MHI_DBG("flow ctrl sussess gsi ch %d code %d\n",
					ep->gsi_chan_hdl, code);
		} else {
			IPA_MHI_DBG("failed to flow ctrll gsi ch %d code %d\n",
					ep->gsi_chan_hdl, code);
		}
	}

	IPA_MHI_FUNC_EXIT();
	return 0;

fail_ep_cfg:
	ipa3_disable_data_path(ipa_ep_idx);
fail_ch_start:
fail_ch_scratch:
	gsi_dealloc_channel(ep->gsi_chan_hdl);
@@ -473,49 +524,22 @@ int ipa3_connect_mhi_pipe(struct ipa_mhi_connect_params_internal *in,
	ep->keep_ipa_awake = in->sys->keep_ipa_awake;

	res = ipa_mhi_start_gsi_channel(client,
					ipa_ep_idx, &in->start.gsi);
					ipa_ep_idx, &in->start.gsi,
					&in->sys->ipa_ep_cfg);
	if (res) {
		IPA_MHI_ERR("ipa_mhi_start_gsi_channel failed %d\n",
			res);
		goto fail_start_channel;
	}

	res = ipa3_enable_data_path(ipa_ep_idx);
	if (res) {
		IPA_MHI_ERR("enable data path failed res=%d clnt=%d.\n", res,
			ipa_ep_idx);
		goto fail_ep_cfg;
	}

	if (!ep->skip_ep_cfg) {
		if (ipa3_cfg_ep(ipa_ep_idx, &in->sys->ipa_ep_cfg)) {
			IPAERR("fail to configure EP.\n");
			goto fail_ep_cfg;
		}
		if (ipa3_cfg_ep_status(ipa_ep_idx, &ep->status)) {
			IPAERR("fail to configure status of EP.\n");
			goto fail_ep_cfg;
		}
		IPA_MHI_DBG("ep configuration successful\n");
	} else {
		IPA_MHI_DBG("skipping ep configuration\n");
	}

	*clnt_hdl = ipa_ep_idx;

	if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(client))
		ipa3_install_dflt_flt_rules(ipa_ep_idx);

	ipa3_ctx->skip_ep_cfg_shadow[ipa_ep_idx] = ep->skip_ep_cfg;
	IPA_MHI_DBG("client %d (ep: %d) connected\n", client,
		ipa_ep_idx);
	IPA_MHI_DBG("client %d (ep: %d) connected\n", client, ipa_ep_idx);

	IPA_MHI_FUNC_EXIT();

	return 0;

fail_ep_cfg:
	ipa3_disable_data_path(ipa_ep_idx);
fail_start_channel:
	memset(ep, 0, offsetof(struct ipa3_ep_context, sys));
	return -EPERM;
Loading