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

Commit d34ac247 authored by Siddartha Mohanadoss's avatar Siddartha Mohanadoss
Browse files

msm: mhi_dev: Wake up the client on channel disconnect



In certain cases clients are blocked on read or poll once
the channel disconnect is received. During poll cases return
client with POLLHUP error. For the read case when client
is blocked on read wake up the thread.

Change-Id: Ideded84420b4995251773110ec083a80f9a3a76e
Signed-off-by: default avatarSiddartha Mohanadoss <smohanad@codeaurora.org>
parent 65cce8ef
Loading
Loading
Loading
Loading
+55 −24
Original line number Diff line number Diff line
@@ -389,6 +389,43 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait);
static unsigned int mhi_uci_ctrl_poll(struct file *file, poll_table *wait);
static struct mhi_uci_ctxt_t uci_ctxt;

static bool mhi_uci_are_channels_connected(struct uci_client *uci_client)
{
	uint32_t info_ch_in, info_ch_out;
	int rc;

	/*
	 * Check channel states and return true only if channel
	 * information is available and in connected state.
	 * For all other failure conditions return false.
	 */
	rc = mhi_ctrl_state_info(uci_client->in_chan, &info_ch_in);
	if (rc) {
		uci_log(UCI_DBG_DBG,
			"Channels %d is not available with %d\n",
			uci_client->out_chan, rc);
		return false;
	}

	rc = mhi_ctrl_state_info(uci_client->out_chan, &info_ch_out);
	if (rc) {
		uci_log(UCI_DBG_DBG,
			"Channels %d is not available with %d\n",
			uci_client->out_chan, rc);
		return false;
	}

	if ((info_ch_in != MHI_STATE_CONNECTED) ||
		(info_ch_out != MHI_STATE_CONNECTED)) {
		uci_log(UCI_DBG_DBG,
			"Channels %d or %d are not connected\n",
			uci_client->in_chan, uci_client->out_chan);
		return false;
	}

	return true;
}

static int mhi_init_read_chan(struct uci_client *client_handle,
		enum mhi_client_channel chan)
{
@@ -640,6 +677,15 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait)

	poll_wait(file, &uci_handle->read_wq, wait);
	poll_wait(file, &uci_handle->write_wq, wait);
	/*
	 * Check if the channels on which the clients are trying
	 * to poll are in connected state and return with the
	 * appropriate mask if channels are disconnected.
	 */
	if (!mhi_uci_are_channels_connected(uci_handle)) {
		mask = POLLHUP;
		return mask;
	}
	mask = uci_handle->at_ctrl_mask;
	if (!atomic_read(&uci_ctxt.mhi_disabled) &&
		!mhi_dev_channel_isempty(uci_handle->in_handle)) {
@@ -782,31 +828,9 @@ static int mhi_uci_read_sync(struct uci_client *uci_handle,
static int open_client_mhi_channels(struct uci_client *uci_client)
{
	int rc = 0;
	uint32_t info_ch_in, info_ch_out;

	rc = mhi_ctrl_state_info(uci_client->in_chan, &info_ch_in);
	if (rc) {
		uci_log(UCI_DBG_DBG,
			"Channels %d is not connected with %d\n",
			uci_client->out_chan, rc);
		return -EINVAL;
	}

	rc = mhi_ctrl_state_info(uci_client->out_chan, &info_ch_out);
	if (rc) {
		uci_log(UCI_DBG_DBG,
			"Channels %d is not connected with %d\n",
			uci_client->out_chan, rc);
		return -EINVAL;
	}

	if ((info_ch_in != MHI_STATE_CONNECTED) ||
		(info_ch_out != MHI_STATE_CONNECTED)) {
		uci_log(UCI_DBG_DBG,
			"Channels %d or %d are not connected\n",
			uci_client->in_chan, uci_client->out_chan);
		return -EINVAL;
	}
	if (!mhi_uci_are_channels_connected(uci_client))
		return -ENODEV;

	uci_log(UCI_DBG_DBG,
			"Starting channels %d %d.\n",
@@ -1335,6 +1359,13 @@ void mhi_uci_chan_state_notify(struct mhi_dev *mhi,
		uci_log(UCI_DBG_ERROR,
				"Sending uevent failed for chan %d\n", ch_id);

	if (ch_state == MHI_STATE_DISCONNECTED &&
			!atomic_read(&uci_handle->ref_count)) {
		/* Issue wake only if there is an active client */
		wake_up(&uci_handle->read_wq);
		wake_up(&uci_handle->write_wq);
	}

	kfree(buf[0]);
}
EXPORT_SYMBOL(mhi_uci_chan_state_notify);