mei: disconnect on connection request timeout

For the FW with  HBM version >= 2.0 we don't need to reset the whole
device in case of a particular client failing to connect, it is enough
to send disconnect a request to bring the device to the stable state.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Alexander Usyskin
2015-07-23 21:37:13 +03:00
committed by Greg Kroah-Hartman
parent 70ef835c84
commit 18901357e7
6 changed files with 95 additions and 29 deletions

View File

@@ -836,44 +836,24 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
return ret;
}
/**
* mei_cl_disconnect - disconnect host client from the me one
* __mei_cl_disconnect - disconnect host client from the me one
* internal function runtime pm has to be already acquired
*
* @cl: host client
*
* Locking: called under "dev->device_lock" lock
*
* Return: 0 on success, <0 on failure.
*/
int mei_cl_disconnect(struct mei_cl *cl)
static int __mei_cl_disconnect(struct mei_cl *cl)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
int rets;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
dev = cl->dev;
cl_dbg(dev, cl, "disconnecting");
if (!mei_cl_is_connected(cl))
return 0;
if (mei_cl_is_fixed_address(cl)) {
mei_cl_set_disconnected(cl);
return 0;
}
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
if (WARN_ON(!pm_runtime_active(dev->dev)))
return -EFAULT;
cl->state = MEI_FILE_DISCONNECTING;
@@ -910,11 +890,52 @@ out:
if (!rets)
cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
mei_io_cb_free(cb);
return rets;
}
/**
* mei_cl_disconnect - disconnect host client from the me one
*
* @cl: host client
*
* Locking: called under "dev->device_lock" lock
*
* Return: 0 on success, <0 on failure.
*/
int mei_cl_disconnect(struct mei_cl *cl)
{
struct mei_device *dev;
int rets;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
dev = cl->dev;
cl_dbg(dev, cl, "disconnecting");
if (!mei_cl_is_connected(cl))
return 0;
if (mei_cl_is_fixed_address(cl)) {
mei_cl_set_disconnected(cl);
return 0;
}
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
rets = __mei_cl_disconnect(cl);
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
mei_io_cb_free(cb);
return rets;
}
@@ -1059,11 +1080,23 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
mutex_unlock(&dev->device_lock);
wait_event_timeout(cl->wait,
(cl->state == MEI_FILE_CONNECTED ||
cl->state == MEI_FILE_DISCONNECT_REQUIRED ||
cl->state == MEI_FILE_DISCONNECT_REPLY),
mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
mutex_lock(&dev->device_lock);
if (!mei_cl_is_connected(cl)) {
if (cl->state == MEI_FILE_DISCONNECT_REQUIRED) {
mei_io_list_flush(&dev->ctrl_rd_list, cl);
mei_io_list_flush(&dev->ctrl_wr_list, cl);
/* ignore disconnect return valuue;
* in case of failure reset will be invoked
*/
__mei_cl_disconnect(cl);
rets = -EFAULT;
goto out;
}
/* timeout or something went really wrong */
if (!cl->status)
cl->status = -EFAULT;