mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 01:10:04 +00:00
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:
parent
70ef835c84
commit
18901357e7
6 changed files with 95 additions and 29 deletions
|
@ -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 @@ int mei_cl_disconnect(struct mei_cl *cl)
|
|||
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;
|
||||
|
|
|
@ -156,6 +156,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
|
|||
dev->hbm_f_pg_supported);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n",
|
||||
dev->hbm_f_dc_supported);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n",
|
||||
dev->hbm_f_dot_supported);
|
||||
}
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n",
|
||||
|
|
|
@ -774,6 +774,10 @@ static void mei_hbm_config_features(struct mei_device *dev)
|
|||
|
||||
if (dev->version.major_version >= HBM_MAJOR_VERSION_DC)
|
||||
dev->hbm_f_dc_supported = 1;
|
||||
|
||||
/* disconnect on connect timeout instead of link reset */
|
||||
if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT)
|
||||
dev->hbm_f_dot_supported = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -52,6 +52,12 @@
|
|||
#define HBM_MINOR_VERSION_DC 0
|
||||
#define HBM_MAJOR_VERSION_DC 2
|
||||
|
||||
/*
|
||||
* MEI version with disconnect on connection timeout support
|
||||
*/
|
||||
#define HBM_MINOR_VERSION_DOT 0
|
||||
#define HBM_MAJOR_VERSION_DOT 2
|
||||
|
||||
/* Host bus message command opcode */
|
||||
#define MEI_HBM_CMD_OP_MSK 0x7f
|
||||
/* Host bus message command RESPONSE */
|
||||
|
|
|
@ -424,6 +424,24 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
|
|||
EXPORT_SYMBOL_GPL(mei_irq_write_handler);
|
||||
|
||||
|
||||
/**
|
||||
* mei_connect_timeout - connect/disconnect timeouts
|
||||
*
|
||||
* @cl: host client
|
||||
*/
|
||||
static void mei_connect_timeout(struct mei_cl *cl)
|
||||
{
|
||||
struct mei_device *dev = cl->dev;
|
||||
|
||||
if (cl->state == MEI_FILE_CONNECTING) {
|
||||
if (dev->hbm_f_dot_supported) {
|
||||
cl->state = MEI_FILE_DISCONNECT_REQUIRED;
|
||||
wake_up(&cl->wait);
|
||||
return;
|
||||
}
|
||||
}
|
||||
mei_reset(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_timer - timer function.
|
||||
|
@ -464,7 +482,7 @@ void mei_timer(struct work_struct *work)
|
|||
if (cl->timer_count) {
|
||||
if (--cl->timer_count == 0) {
|
||||
dev_err(dev->dev, "timer: connect/disconnect timeout.\n");
|
||||
mei_reset(dev);
|
||||
mei_connect_timeout(cl);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ enum file_state {
|
|||
MEI_FILE_CONNECTED,
|
||||
MEI_FILE_DISCONNECTING,
|
||||
MEI_FILE_DISCONNECT_REPLY,
|
||||
MEI_FILE_DISCONNECT_REQUIRED,
|
||||
MEI_FILE_DISCONNECTED,
|
||||
};
|
||||
|
||||
|
@ -407,8 +408,9 @@ const char *mei_pg_state_str(enum mei_pg_state state);
|
|||
* @wr_msg : the buffer for hbm control messages
|
||||
*
|
||||
* @version : HBM protocol version in use
|
||||
* @hbm_f_pg_supported : hbm feature pgi protocol
|
||||
* @hbm_f_dc_supported : hbm feature dynamic clients
|
||||
* @hbm_f_pg_supported : hbm feature pgi protocol
|
||||
* @hbm_f_dc_supported : hbm feature dynamic clients
|
||||
* @hbm_f_dot_supported : hbm feature disconnect on timeout
|
||||
*
|
||||
* @me_clients_rwsem: rw lock over me_clients list
|
||||
* @me_clients : list of FW clients
|
||||
|
@ -503,6 +505,7 @@ struct mei_device {
|
|||
struct hbm_version version;
|
||||
unsigned int hbm_f_pg_supported:1;
|
||||
unsigned int hbm_f_dc_supported:1;
|
||||
unsigned int hbm_f_dot_supported:1;
|
||||
|
||||
struct rw_semaphore me_clients_rwsem;
|
||||
struct list_head me_clients;
|
||||
|
|
Loading…
Reference in a new issue