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: Siddartha Mohanadoss <smohanad@codeaurora.org>
tirimbino
Siddartha Mohanadoss 5 years ago
parent 65cce8ef06
commit d34ac24764
  1. 79
      drivers/platform/msm/mhi_dev/mhi_uci.c

@ -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);

Loading…
Cancel
Save