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

Commit 00cc4800 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa3: Decouple xDCI DPL channel from data channels"

parents aeb944f7 949f519e
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -1078,7 +1078,7 @@ int ipa3_request_gsi_channel(struct ipa_request_gsi_channel_params *params,
	struct ipa_gsi_ep_config gsi_ep_cfg;
	struct ipa_gsi_ep_config *gsi_ep_cfg_ptr = &gsi_ep_cfg;

	IPADBG("ipa3_request_gsi_channel: entry\n");
	IPADBG("entry\n");
	if (params == NULL || out_params == NULL ||
		!ipa3_is_legal_params(params)) {
		IPAERR("bad parameters\n");
@@ -1202,7 +1202,7 @@ int ipa3_request_gsi_channel(struct ipa_request_gsi_channel_params *params,
	ipa3_dec_client_disable_clks();

	IPADBG("client %d (ep: %d) connected\n", params->client, ipa_ep_idx);
	IPADBG("ipa3_request_gsi_channel: exit\n");
	IPADBG("exit\n");

	return 0;

@@ -1223,7 +1223,7 @@ int ipa3_set_usb_max_packet_size(
	struct gsi_device_scratch dev_scratch;
	enum gsi_status gsi_res;

	IPADBG("ipa3_set_usb_max_packet_size: entry\n");
	IPADBG("entry\n");

	ipa3_inc_client_enable_clks();

@@ -1241,7 +1241,7 @@ int ipa3_set_usb_max_packet_size(

	ipa3_dec_client_disable_clks();

	IPADBG("ipa3_set_usb_max_packet_size: exit\n");
	IPADBG("exit\n");
	return 0;
}

@@ -1251,7 +1251,7 @@ int ipa3_xdci_connect(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid)
	int result = -EFAULT;
	enum gsi_status gsi_res;

	IPADBG("ipa3_xdci_connect: entry\n");
	IPADBG("entry\n");
	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes  ||
		ipa3_ctx->ep[clnt_hdl].valid == 0 ||
		xferrscidx < 0 || xferrscidx > IPA_XFER_RSC_IDX_MAX) {
@@ -1280,7 +1280,7 @@ int ipa3_xdci_connect(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid)
	if (!ep->keep_ipa_awake)
		ipa3_dec_client_disable_clks();

	IPADBG("ipa3_xdci_connect: exit\n");
	IPADBG("exit\n");
	return 0;

write_chan_scratch_fail:
@@ -1577,9 +1577,11 @@ int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
	if (!dl_data_pending) {
		aggr_active_bitmap = ipa_read_reg(ipa3_ctx->mmio,
				IPA_STATE_AGGR_ACTIVE_OFST);
		if (aggr_active_bitmap & (1 << dl_clnt_hdl))
		if (aggr_active_bitmap & (1 << dl_clnt_hdl)) {
			IPADBG("DL data pending due to open aggr. frame\n");
			dl_data_pending = true;
		}
	}
	if (dl_data_pending) {
		IPAERR("DL data pending, can't suspend\n");
		result = -EFAULT;
+183 −151
Original line number Diff line number Diff line
@@ -186,18 +186,34 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state)
			ipa3_usb_ctx->state == IPA_USB_RESUME_IN_PROGRESS ||
			ipa3_usb_ctx->state == IPA_USB_SUSPEND_REQUESTED)
			state_legal = true;
		if (ipa3_usb_ctx->rm_ctx.cons_state == IPA_USB_CONS_GRANTED ||
		if (ipa3_usb_ctx->diag_state == IPA_USB_SUSPEND_REQUESTED ||
			(ipa3_usb_ctx->diag_state ==
			IPA_USB_SUSPEND_IN_PROGRESS) ||
			ipa3_usb_ctx->diag_state == IPA_USB_SUSPENDED ||
			(ipa3_usb_ctx->diag_state ==
			IPA_USB_RESUME_IN_PROGRESS)) {
			state_legal = false;
			IPA_USB_ERR("Cannot connect while DPL in Suspend\n");
		}

		if (state_legal) {
			if ((ipa3_usb_ctx->rm_ctx.cons_state ==
				IPA_USB_CONS_GRANTED) ||
				ipa3_usb_ctx->rm_ctx.cons_requested_released) {
				ipa3_usb_ctx->rm_ctx.cons_requested = false;
			ipa3_usb_ctx->rm_ctx.cons_requested_released = false;
				ipa3_usb_ctx->rm_ctx.cons_requested_released =
					false;
			}
			/* Notify RM that consumer is granted */
			if (ipa3_usb_ctx->rm_ctx.cons_requested) {
			ipa3_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
				ipa3_rm_notify_completion(
					IPA_RM_RESOURCE_GRANTED,
					ipa3_usb_ctx->rm_ctx.cons_params.name);
			ipa3_usb_ctx->rm_ctx.cons_state = IPA_USB_CONS_GRANTED;
				ipa3_usb_ctx->rm_ctx.cons_state =
					IPA_USB_CONS_GRANTED;
				ipa3_usb_ctx->rm_ctx.cons_requested = false;
			}
		}
		break;
	case IPA_USB_STOPPED:
		if (ipa3_usb_ctx->state == IPA_USB_SUSPEND_IN_PROGRESS ||
@@ -249,7 +265,7 @@ static bool ipa3_usb_set_diag_state(enum ipa3_usb_state new_state)
	int state_legal = false;

	spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
	IPA_USB_DBG("ipa3_usb_set_diag_state: current diag state = %s\n",
	IPA_USB_DBG("current diag state = %s\n",
		ipa3_usb_state_to_string(ipa3_usb_ctx->diag_state));
	switch (new_state) {
	case IPA_USB_INVALID:
@@ -258,14 +274,20 @@ static bool ipa3_usb_set_diag_state(enum ipa3_usb_state new_state)
		break;
	case IPA_USB_INITIALIZED:
		if (ipa3_usb_ctx->diag_state == IPA_USB_INVALID ||
			ipa3_usb_ctx->diag_state == IPA_USB_STOPPED ||
			ipa3_usb_ctx->diag_state == IPA_USB_INITIALIZED)
			ipa3_usb_ctx->diag_state == IPA_USB_STOPPED)
			state_legal = true;
		break;
	case IPA_USB_CONNECTED:
		if (ipa3_usb_ctx->diag_state == IPA_USB_INITIALIZED ||
			ipa3_usb_ctx->diag_state == IPA_USB_STOPPED)
			state_legal = true;
		if (ipa3_usb_ctx->state == IPA_USB_SUSPEND_REQUESTED ||
			ipa3_usb_ctx->state == IPA_USB_SUSPEND_IN_PROGRESS ||
			ipa3_usb_ctx->state == IPA_USB_SUSPENDED ||
			ipa3_usb_ctx->state == IPA_USB_RESUME_IN_PROGRESS) {
			state_legal = false;
			IPA_USB_ERR("Cannot connect DPL while in suspend\n");
		}
		break;
	case IPA_USB_STOPPED:
		if (ipa3_usb_ctx->diag_state == IPA_USB_CONNECTED)
@@ -319,11 +341,21 @@ static bool ipa3_usb_check_legal_op(enum ipa3_usb_op op, bool is_diag)
		break;
	case IPA_USB_CONNECT:
		if (!is_diag && (ipa3_usb_ctx->state == IPA_USB_INITIALIZED ||
			ipa3_usb_ctx->state == IPA_USB_STOPPED))
			ipa3_usb_ctx->state == IPA_USB_STOPPED) &&
			(ipa3_usb_ctx->diag_state !=
			IPA_USB_SUSPEND_REQUESTED) &&
			(ipa3_usb_ctx->diag_state !=
			IPA_USB_SUSPEND_IN_PROGRESS) &&
			(ipa3_usb_ctx->diag_state != IPA_USB_SUSPENDED) &&
			(ipa3_usb_ctx->diag_state !=
			IPA_USB_RESUME_IN_PROGRESS))
			is_legal = true;
		if (is_diag && ipa3_usb_ctx->state == IPA_USB_CONNECTED &&
			(ipa3_usb_ctx->diag_state == IPA_USB_INITIALIZED
			|| ipa3_usb_ctx->diag_state == IPA_USB_STOPPED))
		if (is_diag && (ipa3_usb_ctx->diag_state == IPA_USB_INITIALIZED
			|| ipa3_usb_ctx->diag_state == IPA_USB_STOPPED) &&
			ipa3_usb_ctx->state != IPA_USB_SUSPEND_REQUESTED &&
			ipa3_usb_ctx->state != IPA_USB_SUSPEND_IN_PROGRESS &&
			ipa3_usb_ctx->state != IPA_USB_SUSPENDED &&
			ipa3_usb_ctx->state != IPA_USB_RESUME_IN_PROGRESS)
			is_legal = true;
		break;
	case IPA_USB_DISCONNECT:
@@ -639,7 +671,7 @@ int ipa3_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot,
	int result = -EFAULT;

	mutex_lock(&ipa3_usb_ctx->general_mutex);
	IPA_USB_DBG("ipa3_usb_init_teth_prot: entry\n");
	IPA_USB_DBG("entry\n");
	if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE ||
		((teth_prot == IPA_USB_RNDIS || teth_prot == IPA_USB_ECM) &&
		teth_params == NULL) || ipa_usb_notify_cb == NULL ||
@@ -697,7 +729,13 @@ int ipa3_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot,
		ipa3_usb_ctx->rm_ctx.cons_valid = true;
		IPA_USB_DBG("Created USB_CONS RM resource.\n");
	}
	if (!ipa3_usb_ctx->ipa_usb_notify_cb) {
		ipa3_usb_ctx->ipa_usb_notify_cb = ipa_usb_notify_cb;
	} else if (ipa3_usb_ctx->ipa_usb_notify_cb != ipa_usb_notify_cb) {
		IPA_USB_ERR("usb_notify_cb different from the current one\n");
		result = -EINVAL;
		goto init_rndis_ipa_fail;
	}

	/* Initialize tethering protocol */
	switch (teth_prot) {
@@ -763,6 +801,7 @@ int ipa3_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot,
		break;
	case IPA_USB_RMNET:
	case IPA_USB_MBIM:
	case IPA_USB_DIAG:
		if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
			IPA_USB_TETH_PROT_INVALID) {
			IPA_USB_DBG("%s already initialized\n",
@@ -780,22 +819,6 @@ int ipa3_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot,
		IPA_USB_DBG("initialized %s\n",
			ipa3_usb_teth_prot_to_string(teth_prot));
		break;
	case IPA_USB_DIAG:
		if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state !=
			IPA_USB_TETH_PROT_INVALID) {
			IPA_USB_DBG("%s already initialized\n",
				ipa3_usb_teth_prot_to_string(teth_prot));
			result = -EPERM;
			goto bad_params;
		}
		ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data;
		ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
			IPA_USB_TETH_PROT_INITIALIZED;
		ipa3_usb_ctx->diag_user_data = user_data;
		ipa3_usb_ctx->num_init_prot++;
		IPA_USB_DBG("initialized %s\n",
			ipa3_usb_teth_prot_to_string(teth_prot));
		break;
	default:
		IPA_USB_ERR("unexpected tethering protocol\n");
		result = -EINVAL;
@@ -810,16 +833,20 @@ int ipa3_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot,
			IPA_USB_ERR("failed to change diag state to init\n");
	}

	IPA_USB_DBG("ipa3_usb_init_teth_prot: exit\n");
	IPA_USB_DBG("exit\n");
	mutex_unlock(&ipa3_usb_ctx->general_mutex);
	return 0;

init_rndis_ipa_fail:
	if (ipa3_usb_ctx->num_init_prot == 0)
	if (ipa3_usb_ctx->num_init_prot == 0) {
		ipa3_usb_ctx->rm_ctx.cons_valid = false;
		ipa_rm_delete_resource(ipa3_usb_ctx->rm_ctx.cons_params.name);
	}
create_cons_rsc_fail:
	if (ipa3_usb_ctx->num_init_prot == 0)
	if (ipa3_usb_ctx->num_init_prot == 0) {
		ipa3_usb_ctx->rm_ctx.prod_valid = false;
		ipa_rm_delete_resource(ipa3_usb_ctx->rm_ctx.prod_params.name);
	}
bad_params:
	mutex_unlock(&ipa3_usb_ctx->general_mutex);
	return result;
@@ -872,24 +899,8 @@ static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params)
	switch (params->teth_prot) {
	case IPA_USB_RNDIS:
	case IPA_USB_ECM:
		if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
			IPA_USB_TETH_PROT_INVALID) {
			IPA_USB_ERR("%s is not initialized\n",
				ipa3_usb_teth_prot_to_string(
				params->teth_prot));
			return false;
		}
		break;
	case IPA_USB_RMNET:
	case IPA_USB_MBIM:
		if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
			IPA_USB_TETH_PROT_INVALID) {
			IPA_USB_ERR("%s is not initialized\n",
				ipa3_usb_teth_prot_to_string(
				params->teth_prot));
			return false;
		}
		break;
	case IPA_USB_DIAG:
		if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
			IPA_USB_TETH_PROT_INVALID) {
@@ -898,7 +909,8 @@ static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params)
				params->teth_prot));
			return false;
		}
		if (!IPA_CLIENT_IS_CONS(params->client)) {
		if ((params->teth_prot == IPA_USB_DIAG) &&
			!IPA_CLIENT_IS_CONS(params->client)) {
			IPA_USB_ERR("DIAG supports only DL channel\n");
			return false;
		}
@@ -916,7 +928,7 @@ static int ipa3_usb_request_xdci_channel(
	int result = -EFAULT;
	struct ipa_request_gsi_channel_params chan_params;

	IPA_USB_DBG("ipa3_usb_request_xdci_channel: entry\n");
	IPA_USB_DBG("entry\n");
	if (params == NULL || out_params == NULL ||
		!ipa3_usb_check_chan_params(params)) {
		IPA_USB_ERR("bad parameters.\n");
@@ -1038,7 +1050,7 @@ static int ipa3_usb_request_xdci_channel(
		return result;
	}

	IPA_USB_DBG("ipa3_usb_request_xdci_channel: exit\n");
	IPA_USB_DBG("exit\n");
	return 0;
}

@@ -1168,10 +1180,6 @@ static bool ipa3_usb_check_connect_params(
		return false;
	}

	switch (params->teth_prot) {
	case IPA_USB_RNDIS:
	case IPA_USB_ECM:
	case IPA_USB_DIAG:
	if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
		IPA_USB_TETH_PROT_INVALID) {
		IPA_USB_ERR("%s is not initialized\n",
@@ -1179,13 +1187,7 @@ static bool ipa3_usb_check_connect_params(
			params->teth_prot));
		return false;
	}
		break;
	case IPA_USB_RMNET:
	case IPA_USB_MBIM:
		return true;
	default:
		break;
	}

	return true;
}

@@ -1214,7 +1216,7 @@ static int ipa3_usb_connect_teth_prot(
	int result;
	struct teth_bridge_connect_params teth_bridge_params;

	IPA_USB_DBG("ipa3_usb_connect_teth_prot: connecting protocol = %d\n",
	IPA_USB_DBG("connecting protocol = %d\n",
		params->teth_prot);
	switch (params->teth_prot) {
	case IPA_USB_RNDIS:
@@ -1317,6 +1319,21 @@ static int ipa3_usb_connect_teth_prot(
				params->teth_prot));
			return -EPERM;
		}
		result = ipa3_usb_init_teth_bridge();
		if (result)
			return result;

		ipa3_usb_ctx->diag_user_data =
			ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].
			user_data;
		teth_bridge_params.ipa_usb_pipe_hdl =
			params->ipa_to_usb_clnt_hdl;
		teth_bridge_params.usb_ipa_pipe_hdl =
			params->usb_to_ipa_clnt_hdl;
		teth_bridge_params.client_type = IPA_CLIENT_USB_CONS;
		result = ipa3_usb_connect_teth_bridge(&teth_bridge_params);
		if (result)
			return result;
		ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state =
			IPA_USB_TETH_PROT_CONNECTED;
		ipa3_usb_notify_device_ready(ipa3_usb_ctx->diag_user_data);
@@ -1377,6 +1394,7 @@ static int ipa3_usb_disconnect_teth_prot(enum ipa_usb_teth_prot teth_prot)
		}
		ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
			IPA_USB_TETH_PROT_INITIALIZED;
		ipa3_usb_ctx->user_data = NULL;
		IPA_USB_DBG("disconnected %s\n",
			ipa3_usb_teth_prot_to_string(teth_prot));
		break;
@@ -1388,11 +1406,15 @@ static int ipa3_usb_disconnect_teth_prot(enum ipa_usb_teth_prot teth_prot)
				ipa3_usb_teth_prot_to_string(teth_prot));
			return -EPERM;
		}
		if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state !=
			IPA_USB_TETH_PROT_CONNECTED) {
			result = ipa3_usb_disconnect_teth_bridge();
			if (result)
				break;
		}
		ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
			IPA_USB_TETH_PROT_INITIALIZED;
		ipa3_usb_ctx->user_data = NULL;
		IPA_USB_DBG("disconnected %s\n",
			ipa3_usb_teth_prot_to_string(teth_prot));
		break;
@@ -1403,8 +1425,17 @@ static int ipa3_usb_disconnect_teth_prot(enum ipa_usb_teth_prot teth_prot)
				ipa3_usb_teth_prot_to_string(teth_prot));
			return -EPERM;
		}
		if ((ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RMNET].state !=
			IPA_USB_TETH_PROT_CONNECTED) &&
			(ipa3_usb_ctx->teth_prot_ctx[IPA_USB_MBIM].state !=
			IPA_USB_TETH_PROT_CONNECTED)) {
			result = ipa3_usb_disconnect_teth_bridge();
			if (result)
				break;
		}
		ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
			IPA_USB_TETH_PROT_INITIALIZED;
		ipa3_usb_ctx->diag_user_data = NULL;
		IPA_USB_DBG("disconnected %s\n",
			ipa3_usb_teth_prot_to_string(teth_prot));
		break;
@@ -1412,42 +1443,6 @@ static int ipa3_usb_disconnect_teth_prot(enum ipa_usb_teth_prot teth_prot)
		break;
	}

	ipa3_usb_ctx->user_data = NULL;
	return result;
}

static int ipa3_usb_xdci_connect_diag(
	struct ipa_usb_xdci_connect_params_internal *params)
{
	int result = -EFAULT;

	/* Start DIAG channel */
	result = ipa3_xdci_connect(params->ipa_to_usb_clnt_hdl,
		params->ipa_to_usb_xferrscidx,
		params->ipa_to_usb_xferrscidx_valid);
	if (result) {
		IPA_USB_ERR("failed to connect DIAG channel.\n");
		return result;
	}

	result = ipa3_usb_connect_teth_prot(params);
	if (result)
		goto connect_teth_prot_fail;

	/* Change diag state to CONNECTED */
	if (!ipa3_usb_set_diag_state(IPA_USB_CONNECTED)) {
		IPA_USB_ERR("failed to change diag state to connected\n");
		goto state_change_diag_connected_fail;
	}

	return 0;

state_change_diag_connected_fail:
	ipa3_usb_disconnect_teth_prot(params->teth_prot);
connect_teth_prot_fail:
	ipa3_xdci_disconnect(params->ipa_to_usb_clnt_hdl, false, -1);
	ipa3_reset_gsi_channel(params->ipa_to_usb_clnt_hdl);
	ipa3_reset_gsi_event_ring(params->ipa_to_usb_clnt_hdl);
	return result;
}

@@ -1457,7 +1452,7 @@ static int ipa3_usb_xdci_connect_internal(
	int result = -EFAULT;
	struct ipa_rm_perf_profile profile;

	IPA_USB_DBG("ipa3_usb_xdci_connect_internal: entry\n");
	IPA_USB_DBG("entry\n");
	if (params == NULL || !ipa3_usb_check_connect_params(params)) {
		IPA_USB_ERR("bad parameters.\n");
		return -EINVAL;
@@ -1469,12 +1464,6 @@ static int ipa3_usb_xdci_connect_internal(
		return -EPERM;
	}

	if (params->teth_prot == IPA_USB_DIAG) {
		result = ipa3_usb_xdci_connect_diag(params);
		IPA_USB_DBG("ipa3_usb_xdci_connect: exit\n");
		return result;
	}

	/* Set EE xDCI specific scratch */
	result = ipa3_set_usb_max_packet_size(params->max_pkt_size);
	if (result) {
@@ -1503,6 +1492,7 @@ static int ipa3_usb_xdci_connect_internal(
	if (result)
		return result;

	if (params->teth_prot != IPA_USB_DIAG) {
		/* Start UL channel */
		result = ipa3_xdci_connect(params->usb_to_ipa_clnt_hdl,
			params->usb_to_ipa_xferrscidx,
@@ -1511,13 +1501,14 @@ static int ipa3_usb_xdci_connect_internal(
			IPA_USB_ERR("failed to connect UL channel.\n");
			goto connect_ul_fail;
		}
	}

	/* Start DL channel */
	/* Start DL/Diag channel */
	result = ipa3_xdci_connect(params->ipa_to_usb_clnt_hdl,
		params->ipa_to_usb_xferrscidx,
		params->ipa_to_usb_xferrscidx_valid);
	if (result) {
		IPA_USB_ERR("failed to connect DL channel.\n");
		IPA_USB_ERR("failed to connect DL/Diag channel.\n");
		goto connect_dl_fail;
	}

@@ -1526,13 +1517,23 @@ static int ipa3_usb_xdci_connect_internal(
	if (result)
		goto connect_teth_prot_fail;


	if (params->teth_prot == IPA_USB_DIAG) {
		/* Change diag state to CONNECTED */
		if (!ipa3_usb_set_diag_state(IPA_USB_CONNECTED)) {
			IPA_USB_ERR(
				"failed to change diag state to connected\n");
			goto state_change_connected_fail;
		}
	} else {
		/* Change ipa_usb state to CONNECTED */
		if (!ipa3_usb_set_state(IPA_USB_CONNECTED)) {
			IPA_USB_ERR("failed to change state to connected\n");
			goto state_change_connected_fail;
		}
	}

	IPA_USB_DBG("ipa3_usb_xdci_connect: exit\n");
	IPA_USB_DBG("exit\n");
	return 0;

state_change_connected_fail:
@@ -1542,9 +1543,11 @@ connect_teth_prot_fail:
	ipa3_reset_gsi_channel(params->ipa_to_usb_clnt_hdl);
	ipa3_reset_gsi_event_ring(params->ipa_to_usb_clnt_hdl);
connect_dl_fail:
	if (params->teth_prot != IPA_USB_DIAG) {
		ipa3_xdci_disconnect(params->usb_to_ipa_clnt_hdl, false, -1);
		ipa3_reset_gsi_channel(params->usb_to_ipa_clnt_hdl);
		ipa3_reset_gsi_event_ring(params->usb_to_ipa_clnt_hdl);
	}
connect_ul_fail:
	ipa3_usb_release_prod();
	return result;
@@ -1560,7 +1563,7 @@ int ipa3_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params,
	struct ipa_usb_xdci_connect_params_internal conn_params;

	mutex_lock(&ipa3_usb_ctx->general_mutex);
	IPA_USB_DBG("ipa3_usb_xdci_connect: entry\n");
	IPA_USB_DBG("entry\n");
	if (connect_params == NULL || dl_chan_params == NULL ||
		dl_out_params == NULL ||
		(connect_params->teth_prot != IPA_USB_DIAG &&
@@ -1575,7 +1578,7 @@ int ipa3_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params,
			ul_out_params);
		if (result) {
			IPA_USB_ERR("failed to allocate UL channel.\n");
			return result;
			goto bad_params;
		}
	}

@@ -1610,7 +1613,7 @@ int ipa3_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params,
		goto connect_fail;
	}

	IPA_USB_DBG("ipa3_usb_xdci_connect: exit\n");
	IPA_USB_DBG("exit\n");
	mutex_unlock(&ipa3_usb_ctx->general_mutex);
	return 0;

@@ -1629,6 +1632,7 @@ bad_params:
static int ipa3_usb_xdci_disconnect_diag(u32 dl_clnt_hdl)
{
	int result = 0;
	unsigned long flags;

	/* Stop DIAG channel */
	result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
@@ -1668,6 +1672,19 @@ static int ipa3_usb_xdci_disconnect_diag(u32 dl_clnt_hdl)
		return result;
	}

	spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
	if ((ipa3_usb_ctx->state != IPA_USB_CONNECTED) &&
		(ipa3_usb_ctx->state != IPA_USB_STOPPED)) {
		/* These are the only cases where data channels has USB_PROD */
		spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
		result = ipa3_usb_release_prod();
		if (result) {
			IPA_USB_ERR("failed to release USB_PROD.\n");
			return result;
		}
	} else
		spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);

	return 0;
}

@@ -1696,7 +1713,7 @@ int ipa3_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
	unsigned long flags;

	mutex_lock(&ipa3_usb_ctx->general_mutex);
	IPA_USB_DBG("ipa3_usb_xdci_disconnect: entry\n");
	IPA_USB_DBG("entry\n");
	if (ipa3_usb_check_disconnect_prot(teth_prot)) {
		result = -EINVAL;
		goto bad_params;
@@ -1711,7 +1728,8 @@ int ipa3_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,

	if (teth_prot == IPA_USB_DIAG) {
		result = ipa3_usb_xdci_disconnect_diag(dl_clnt_hdl);
		IPA_USB_DBG("ipa3_usb_xdci_disconnect: exit\n");
		if (!result)
			IPA_USB_DBG("exit\n");
		mutex_unlock(&ipa3_usb_ctx->general_mutex);
		return result;
	}
@@ -1808,7 +1826,9 @@ int ipa3_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,

	spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
	if (ipa3_usb_ctx->state != IPA_USB_SUSPEND_IN_PROGRESS &&
		ipa3_usb_ctx->state != IPA_USB_SUSPENDED) {
		ipa3_usb_ctx->state != IPA_USB_SUSPENDED &&
		ipa3_usb_ctx->diag_state != IPA_USB_CONNECTED &&
		ipa3_usb_ctx->diag_state != IPA_USB_STOPPED) {
		spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
		result = ipa3_usb_release_prod();
		if (result) {
@@ -1818,7 +1838,7 @@ int ipa3_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
	} else
		spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);

	IPA_USB_DBG("ipa3_usb_xdci_disconnect: exit\n");
	IPA_USB_DBG("exit\n");
	mutex_unlock(&ipa3_usb_ctx->general_mutex);
	return 0;

@@ -1833,7 +1853,7 @@ int ipa3_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
	int result = -EFAULT;

	mutex_lock(&ipa3_usb_ctx->general_mutex);
	IPA_USB_DBG("ipa3_usb_deinit_teth_prot: entry\n");
	IPA_USB_DBG("entry\n");
	if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
		IPA_USB_ERR("bad parameters.\n");
		result = -EINVAL;
@@ -1882,9 +1902,12 @@ int ipa3_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
			result = -EINVAL;
			goto bad_params;
		}
		if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state !=
			IPA_USB_TETH_PROT_CONNECTED) {
			result = ipa3_usb_disconnect_teth_bridge();
			if (result)
				goto bad_params;
		}
		ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data =
			NULL;
		ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
@@ -1901,6 +1924,14 @@ int ipa3_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
			result = -EINVAL;
			goto bad_params;
		}
		if ((ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RMNET].state !=
			IPA_USB_TETH_PROT_CONNECTED) &&
			(ipa3_usb_ctx->teth_prot_ctx[IPA_USB_MBIM].state !=
			IPA_USB_TETH_PROT_CONNECTED)) {
			result = ipa3_usb_disconnect_teth_bridge();
			if (result)
				goto bad_params;
		}
		ipa3_usb_ctx->diag_user_data = NULL;
		ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
			IPA_USB_TETH_PROT_INVALID;
@@ -1919,7 +1950,8 @@ int ipa3_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
		IPA_USB_ERR("failed to change diag state to invalid\n");
	}
	if (ipa3_usb_ctx->num_init_prot == 0) {
		if (!ipa3_usb_set_state(IPA_USB_INVALID))
		if ((teth_prot != IPA_USB_DIAG) &&
			!ipa3_usb_set_state(IPA_USB_INVALID))
			IPA_USB_ERR("failed to change state to invalid\n");
		ipa_rm_delete_resource(ipa3_usb_ctx->rm_ctx.prod_params.name);
		ipa3_usb_ctx->rm_ctx.prod_valid = false;
@@ -1928,7 +1960,7 @@ int ipa3_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
		ipa3_usb_ctx->ipa_usb_notify_cb = NULL;
	}

	IPA_USB_DBG("ipa3_usb_deinit_teth_prot: exit\n");
	IPA_USB_DBG("exit\n");
	mutex_unlock(&ipa3_usb_ctx->general_mutex);
	return 0;