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

Commit a8f47b22 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: fix dependencies not added on composition switch"

parents 1e1f8603 fc26460e
Loading
Loading
Loading
Loading
+174 −52
Original line number Diff line number Diff line
@@ -29,7 +29,8 @@

#define IPA_POLL_FOR_EMPTINESS_NUM 50
#define IPA_POLL_FOR_EMPTINESS_SLEEP_USEC 20
#define IPA_POLL_FOR_CHANNEL_STOP_NUM 10
#define IPA_CHANNEL_STOP_IN_PROC_TO_MSEC 5
#define IPA_CHANNEL_STOP_IN_PROC_SLEEP_USEC 200

/* xfer_rsc_idx should be 7 bits */
#define IPA_XFER_RSC_IDX_MAX 127
@@ -928,6 +929,12 @@ static int ipa3_reset_with_open_aggr_frame_wa(u32 clnt_hdl,
		goto start_chan_fail;
	}

	/*
	 * Need to sleep for 1ms as required by H/W verified
	 * sequence for resetting GSI channel
	 */
	msleep(IPA_POLL_AGGR_STATE_SLEEP_MSEC);

	/* Restore channels properties */
	result = ipa3_restore_channel_properties(ep, &orig_chan_props,
		&orig_chan_scratch);
@@ -957,7 +964,7 @@ int ipa3_reset_gsi_channel(u32 clnt_hdl)
	enum gsi_status gsi_res;
	int aggr_active_bitmap = 0;

	IPADBG("ipa3_reset_gsi_channel: entry\n");
	IPADBG("entry\n");
	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
		ipa3_ctx->ep[clnt_hdl].valid == 0) {
		IPAERR("Bad parameter.\n");
@@ -984,7 +991,11 @@ int ipa3_reset_gsi_channel(u32 clnt_hdl)
		}
	}

	/* Reset channel */
	/*
	 * Reset channel
	 * If the reset called after stop, need to wait 1ms
	 */
	msleep(IPA_POLL_AGGR_STATE_SLEEP_MSEC);
	gsi_res = gsi_reset_channel(ep->gsi_chan_hdl);
	if (gsi_res != GSI_STATUS_SUCCESS) {
		IPAERR("Error resetting channel: %d\n", gsi_res);
@@ -996,7 +1007,7 @@ finish_reset:
	if (!ep->keep_ipa_awake)
		IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));

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

reset_chan_fail:
@@ -1011,7 +1022,7 @@ int ipa3_reset_gsi_event_ring(u32 clnt_hdl)
	int result = -EFAULT;
	enum gsi_status gsi_res;

	IPADBG("ipa3_reset_gsi_event_ring: entry\n");
	IPADBG("entry\n");
	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
		ipa3_ctx->ep[clnt_hdl].valid == 0) {
		IPAERR("Bad parameter.\n");
@@ -1033,7 +1044,7 @@ int ipa3_reset_gsi_event_ring(u32 clnt_hdl)
	if (!ep->keep_ipa_awake)
		IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));

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

reset_evt_fail:
@@ -1380,52 +1391,160 @@ static int ipa3_disable_force_clear(u32 request_id)
	return 0;
}

/* Clocks should be voted before invoking this function */
static int ipa3_xdci_stop_gsi_channel(u32 clnt_hdl, bool *stop_in_proc)
{
	int res;

	IPADBG("entry\n");
	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
		ipa3_ctx->ep[clnt_hdl].valid == 0 ||
		!stop_in_proc) {
		IPAERR("Bad parameter.\n");
		return -EINVAL;
	}

	res = ipa3_stop_gsi_channel(clnt_hdl);
	if (res != 0 && res != -GSI_STATUS_AGAIN &&
		res != -GSI_STATUS_TIMED_OUT) {
		IPAERR("xDCI stop channel failed res=%d\n", res);
		return -EFAULT;
	}

	*stop_in_proc = res;

	IPADBG("xDCI channel is %s (result=%d)\n",
		res ? "STOP_IN_PROC/TimeOut" : "STOP", res);

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

/* Clocks should be voted before invoking this function */
static int ipa3_xdci_stop_gsi_ch_brute_force(u32 clnt_hdl,
	bool *stop_in_proc)
{
	unsigned long jiffies_start;
	unsigned long jiffies_timeout =
		msecs_to_jiffies(IPA_CHANNEL_STOP_IN_PROC_TO_MSEC);
	int res;

	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
		ipa3_ctx->ep[clnt_hdl].valid == 0 ||
		!stop_in_proc) {
		IPAERR("Bad parameter.\n");
		return -EINVAL;
	}

	jiffies_start = jiffies;
	while (1) {
		res = ipa3_xdci_stop_gsi_channel(clnt_hdl,
			stop_in_proc);
		if (res) {
			IPAERR("failed to stop xDCI channel hdl=%d\n",
				clnt_hdl);
			return res;
		}

		if (!*stop_in_proc) {
			IPADBG("xDCI channel STOP hdl=%d\n", clnt_hdl);
			return res;
		}

		/*
		 * Give chance to the previous stop request to be accomplished
		 * before the retry
		 */
		udelay(IPA_CHANNEL_STOP_IN_PROC_SLEEP_USEC);

		if (time_after(jiffies, jiffies_start + jiffies_timeout)) {
			IPADBG("timeout waiting for xDCI channel emptiness\n");
			return res;
		}
	}
}

/* Clocks should be voted for before invoking this function */
static int ipa3_drain_ul_chan_data(struct ipa3_ep_context *ep, u32 qmi_req_id,
	u32 source_pipe_bitmask, bool should_force_clear)
static int ipa3_stop_ul_chan_with_data_drain(u32 qmi_req_id,
		u32 source_pipe_bitmask, bool should_force_clear, u32 clnt_hdl)
{
	int i;
	bool is_empty = false;
	int result;
	bool is_empty = false;
	int i;
	bool stop_in_proc;
	struct ipa3_ep_context *ep;

	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
		ipa3_ctx->ep[clnt_hdl].valid == 0) {
		IPAERR("Bad parameter.\n");
		return -EINVAL;
	}

	ep = &ipa3_ctx->ep[clnt_hdl];

	/* first try to stop the channel */
	result = ipa3_xdci_stop_gsi_ch_brute_force(clnt_hdl,
			&stop_in_proc);
	if (result) {
		IPAERR("fail to stop UL channel - hdl=%d clnt=%d\n",
			clnt_hdl, ep->client);
		goto exit;
	}
	if (!stop_in_proc)
			goto exit;

	/* if stop_in_proc, lets wait for emptiness */
	for (i = 0; i < IPA_POLL_FOR_EMPTINESS_NUM; i++) {
		result = ipa3_is_xdci_channel_empty(ep, &is_empty);
		if (result)
			return -EFAULT;
			goto exit;
		if (is_empty)
			return 0;
			break;
		udelay(IPA_POLL_FOR_EMPTINESS_SLEEP_USEC);
	}
	/* In case of empty, lets try to stop the channel again */
	if (is_empty) {
		result = ipa3_xdci_stop_gsi_ch_brute_force(clnt_hdl,
			&stop_in_proc);
		if (result) {
			IPAERR("fail to stop UL channel - hdl=%d clnt=%d\n",
				clnt_hdl, ep->client);
			goto exit;
		}
		if (!stop_in_proc)
			goto exit;
	}
	/* if still stop_in_proc or not empty, activate force clear */
	if (should_force_clear) {
		result = ipa3_enable_force_clear(qmi_req_id, true,
			source_pipe_bitmask);
		if (result)
			return -EFAULT;
			goto exit;
	}
	/* with force clear, wait for emptiness */
	for (i = 0; i < IPA_POLL_FOR_EMPTINESS_NUM; i++) {
		result = ipa3_is_xdci_channel_empty(ep, &is_empty);
		if (result) {
			result = -EFAULT;
		if (result)
			goto disable_force_clear_and_exit;
		if (is_empty)
			break;

		udelay(IPA_POLL_FOR_EMPTINESS_SLEEP_USEC);
	}
		if (is_empty) {
			result = 0;
	/* try to stop for the last time */
	result = ipa3_xdci_stop_gsi_ch_brute_force(clnt_hdl,
		&stop_in_proc);
	if (result) {
		IPAERR("fail to stop UL channel - hdl=%d clnt=%d\n",
			clnt_hdl, ep->client);
		goto disable_force_clear_and_exit;
	}
		udelay(IPA_POLL_FOR_EMPTINESS_SLEEP_USEC);
	}
	result = stop_in_proc ? -EFAULT : 0;

disable_force_clear_and_exit:
	if (should_force_clear) {
	if (should_force_clear)
		result = ipa3_disable_force_clear(qmi_req_id);
		if (result)
			return -EFAULT;
	}
	if (!result && !is_empty) {
		/* Not error and not not empty */
		IPAERR("UL channel is not empty after draining it!\n");
		BUG();
	}
exit:
	return result;
}

@@ -1449,20 +1568,28 @@ int ipa3_xdci_disconnect(u32 clnt_hdl, bool should_force_clear, u32 qmi_req_id)

	ipa3_disable_data_path(clnt_hdl);

	/* Drain UL channel before stopping it */
	if (!IPA_CLIENT_IS_CONS(ep->client)) {
		source_pipe_bitmask = 1 << ipa3_get_ep_mapping(ep->client);
		result = ipa3_drain_ul_chan_data(ep, qmi_req_id,
			source_pipe_bitmask, should_force_clear);
		if (result)
			IPAERR("Error draining UL channel data: %d\n", result);
		IPADBG("Stopping PROD channel - hdl=%d clnt=%d\n",
			clnt_hdl, ep->client);
		source_pipe_bitmask = 1 <<
			ipa3_get_ep_mapping(ep->client);
		result = ipa3_stop_ul_chan_with_data_drain(qmi_req_id,
			source_pipe_bitmask, should_force_clear, clnt_hdl);
		if (result) {
			IPAERR("Fail to stop UL channel with data drain\n");
			BUG();
			goto stop_chan_fail;
		}

	} else {
		IPADBG("Stopping CONS channel - hdl=%d clnt=%d\n",
			clnt_hdl, ep->client);
		result = ipa3_stop_gsi_channel(clnt_hdl);
		if (result) {
		IPAERR("Error stopping channel: %d\n", result);
			IPAERR("Error stopping channel (CONS client): %d\n",
				result);
			goto stop_chan_fail;
		}
	}
	IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));

	IPADBG("exit\n");
@@ -1600,15 +1727,6 @@ int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
		goto disable_clk_and_exit;
	}

	/* Drain UL channel before stopping it */
	if (!is_dpl && ul_data_pending) {
		source_pipe_bitmask = 1 << ipa3_get_ep_mapping(ul_ep->client);
		result = ipa3_drain_ul_chan_data(ul_ep, qmi_req_id,
			source_pipe_bitmask, should_force_clear);
		if (result)
			IPAERR("Error draining UL channel data: %d\n", result);
	}

	/* Suspend the DL/DPL EP */
	memset(&ep_cfg_ctrl, 0 , sizeof(struct ipa_ep_cfg_ctrl));
	ep_cfg_ctrl.ipa_ep_suspend = true;
@@ -1627,10 +1745,14 @@ int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
		goto unsuspend_dl_and_exit;
	}

	/* STOP UL channel */
	if (!is_dpl) {
		result = ipa3_stop_gsi_channel(ul_clnt_hdl);
		source_pipe_bitmask = 1 << ipa3_get_ep_mapping(ul_ep->client);
		result = ipa3_stop_ul_chan_with_data_drain(qmi_req_id,
			source_pipe_bitmask, should_force_clear, ul_clnt_hdl);
		if (result) {
			IPAERR("Error stopping UL channel: %d\n", result);
			IPAERR("Error stopping UL channel: result = %d\n",
				result);
			goto unsuspend_dl_and_exit;
		}
	}
+48 −55
Original line number Diff line number Diff line
@@ -127,7 +127,6 @@ struct ipa3_usb_context {
	struct ipa3_usb_teth_prot_context
		teth_prot_ctx[IPA_USB_MAX_TETH_PROT_SIZE];
	int num_init_prot; /* without dpl */
	enum ipa3_usb_teth_prot_state teth_bridge_state;
	struct teth_bridge_init_params teth_bridge_params;
	struct completion dev_ready_comp;
	u32 qmi_req_id;
@@ -435,7 +434,6 @@ int ipa3_usb_init(void)
		ipa3_usb_ctx->teth_prot_ctx[i].state =
			IPA_USB_TETH_PROT_INVALID;
	ipa3_usb_ctx->num_init_prot = 0;
	ipa3_usb_ctx->teth_bridge_state = IPA_USB_TETH_PROT_INVALID;
	init_completion(&ipa3_usb_ctx->dev_ready_comp);
	ipa3_usb_ctx->qmi_req_id = 0;
	spin_lock_init(&ipa3_usb_ctx->state_lock);
@@ -776,15 +774,11 @@ static int ipa3_usb_init_teth_bridge(void)
{
	int result;

	if (ipa3_usb_ctx->teth_bridge_state != IPA_USB_TETH_PROT_INVALID)
		return 0;

	result = teth_bridge_init(&ipa3_usb_ctx->teth_bridge_params);
	if (result) {
		IPA_USB_ERR("Failed to initialize teth_bridge.\n");
		return result;
	}
	ipa3_usb_ctx->teth_bridge_state = IPA_USB_TETH_PROT_INITIALIZED;

	return 0;
}
@@ -1375,9 +1369,6 @@ static int ipa3_usb_connect_teth_bridge(
{
	int result;

	if (ipa3_usb_ctx->teth_bridge_state != IPA_USB_TETH_PROT_INITIALIZED)
		return 0;

	result = teth_bridge_connect(params);
	if (result) {
		IPA_USB_ERR("failed to connect teth_bridge (%s)\n",
@@ -1385,7 +1376,6 @@ static int ipa3_usb_connect_teth_bridge(
			"rmnet" : "mbim");
		return result;
	}
	ipa3_usb_ctx->teth_bridge_state = IPA_USB_TETH_PROT_CONNECTED;

	return 0;
}
@@ -1394,19 +1384,29 @@ static int ipa3_usb_connect_dpl(void)
{
	int res = 0;

	/* Add DPL dependency to RM dependency graph */
	/*
	 * Add DPL dependency to RM dependency graph, first add_dependency call
	 * is sync in order to make sure the IPA clocks are up before we
	 * continue and notify the USB driver it may continue.
	 */
	res = ipa3_rm_add_dependency_sync(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
				    IPA_RM_RESOURCE_Q6_CONS);
	if (res < 0) {
		IPA_USB_ERR("ipa3_rm_add_dependency_sync() failed.\n");
		return res;
	}

	/*
	 * this add_dependency call can't be sync since it will block until DPL
	 * status is connected (which can happen only later in the flow),
	 * the clocks are already up so the call doesn't need to block.
	 */
	res = ipa3_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
				    IPA_RM_RESOURCE_USB_DPL_CONS);
	if (res < 0 && res != -EINPROGRESS) {
		IPA_USB_ERR("ipa3_rm_add_dependency() failed.\n");
		return res;
	}
	res = ipa3_rm_add_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
		ipa3_rm_delete_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
				IPA_RM_RESOURCE_Q6_CONS);
	if (res < 0 && res != -EINPROGRESS) {
		IPA_USB_ERR("ipa3_rm_add_dependency() failed.\n");
		ipa3_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
			IPA_RM_RESOURCE_USB_DPL_CONS);
		return res;
	}

@@ -1557,15 +1557,11 @@ static int ipa3_usb_disconnect_teth_bridge(void)
{
	int result;

	if (ipa3_usb_ctx->teth_bridge_state != IPA_USB_TETH_PROT_CONNECTED)
		return 0;

	result = teth_bridge_disconnect(IPA_CLIENT_USB_PROD);
	if (result) {
		IPA_USB_ERR("failed to disconnect teth_bridge.\n");
		return result;
	}
	ipa3_usb_ctx->teth_bridge_state = IPA_USB_TETH_PROT_INVALID;

	return 0;
}
@@ -1890,6 +1886,23 @@ int ipa3_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
		goto bad_params;
	}

	spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
	if (ipa3_usb_ctx->ttype_ctx[ttype].state != IPA_USB_SUSPENDED) {
		spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
		/* Stop DL/DPL channel */
		result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
		if (result) {
			IPA_USB_ERR("failed to disconnect DL/DPL channel.\n");
			goto bad_params;
		}
	} else {
		spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
		memset(&holb_cfg, 0, sizeof(holb_cfg));
		holb_cfg.en = IPA_HOLB_TMR_EN;
		holb_cfg.tmr_val = 0;
		ipa3_cfg_ep_holb(dl_clnt_hdl, &holb_cfg);
	}

	spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
	orig_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
	if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
@@ -1915,21 +1928,18 @@ int ipa3_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
	} else
		spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);

	spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
	if (ipa3_usb_ctx->ttype_ctx[ttype].state != IPA_USB_SUSPENDED) {
		spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
		/* Stop DL/DPL channel */
		result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
	/* Reset DL channel */
	result = ipa3_reset_gsi_channel(dl_clnt_hdl);
	if (result) {
			IPA_USB_ERR("failed to disconnect DL/DPL channel.\n");
		IPA_USB_ERR("failed to reset DL channel.\n");
		goto bad_params;
	}
	} else {
		spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
		memset(&holb_cfg, 0, sizeof(holb_cfg));
		holb_cfg.en = IPA_HOLB_TMR_EN;
		holb_cfg.tmr_val = 0;
		ipa3_cfg_ep_holb(dl_clnt_hdl, &holb_cfg);

	/* Reset DL event ring */
	result = ipa3_reset_gsi_event_ring(dl_clnt_hdl);
	if (result) {
		IPA_USB_ERR("failed to reset DL event ring.\n");
		goto bad_params;
	}

	if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
@@ -1948,20 +1958,6 @@ int ipa3_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
		}
	}

	/* Reset DL channel */
	result = ipa3_reset_gsi_channel(dl_clnt_hdl);
	if (result) {
		IPA_USB_ERR("failed to reset DL channel.\n");
		goto bad_params;
	}

	/* Reset DL event ring */
	result = ipa3_reset_gsi_event_ring(dl_clnt_hdl);
	if (result) {
		IPA_USB_ERR("failed to reset DL event ring.\n");
		goto bad_params;
	}

	/* Change state to STOPPED */
	if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype))
		IPA_USB_ERR("failed to change state to stopped\n");
@@ -2061,9 +2057,6 @@ int ipa3_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
			result = -EINVAL;
			goto bad_params;
		}
		result = ipa3_usb_disconnect_teth_bridge();
		if (result)
			goto bad_params;

		ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data =
			NULL;
+35 −24
Original line number Diff line number Diff line
@@ -98,8 +98,6 @@ static void teth_bridge_ipa_cb(void *priv, enum ipa_dp_evt_type evt,
*/
int ipa3_teth_bridge_init(struct teth_bridge_init_params *params)
{
	int res = 0;

	TETH_DBG_FUNC_ENTRY();

	if (!params) {
@@ -112,28 +110,8 @@ int ipa3_teth_bridge_init(struct teth_bridge_init_params *params)
	params->private_data = NULL;
	params->skip_ep_cfg = true;

	/* Build dependency graph */
	res = ipa3_rm_add_dependency(IPA_RM_RESOURCE_USB_PROD,
				    IPA_RM_RESOURCE_Q6_CONS);
	if (res < 0 && res != -EINPROGRESS) {
		TETH_ERR("ipa3_rm_add_dependency() failed.\n");
		goto bail;
	}
	res = ipa3_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
				    IPA_RM_RESOURCE_USB_CONS);
	if (res < 0 && res != -EINPROGRESS) {
		ipa3_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
					IPA_RM_RESOURCE_Q6_CONS);
		TETH_ERR("ipa3_rm_add_dependency() failed.\n");
		goto bail;
	}

	res = 0;
	goto bail;

bail:
	TETH_DBG_FUNC_EXIT();
	return res;
	return 0;
}

/**
@@ -162,7 +140,40 @@ int ipa3_teth_bridge_disconnect(enum ipa_client_type client)
*/
int ipa3_teth_bridge_connect(struct teth_bridge_connect_params *connect_params)
{
	return 0;
	int res = 0;

	TETH_DBG_FUNC_ENTRY();

	/* Build the dependency graph, first add_dependency call is sync
	 * in order to make sure the IPA clocks are up before we continue
	 * and notify the USB driver it may continue.
	 */
	res = ipa3_rm_add_dependency_sync(IPA_RM_RESOURCE_USB_PROD,
				    IPA_RM_RESOURCE_Q6_CONS);
	if (res < 0) {
		TETH_ERR("ipa3_rm_add_dependency() failed.\n");
		goto bail;
	}

	/* this add_dependency call can't be sync since it will block until USB
	 * status is connected (which can happen only after the tethering
	 * bridge is connected), the clocks are already up so the call doesn't
	 * need to block.
	 */
	res = ipa3_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
				    IPA_RM_RESOURCE_USB_CONS);
	if (res < 0 && res != -EINPROGRESS) {
		ipa3_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
					IPA_RM_RESOURCE_Q6_CONS);
		TETH_ERR("ipa3_rm_add_dependency() failed.\n");
		goto bail;
	}

	res = 0;

bail:
	TETH_DBG_FUNC_EXIT();
	return res;
}

static long ipa3_teth_bridge_ioctl(struct file *filp,