Commit 18901357 authored by Alexander Usyskin's avatar Alexander Usyskin Committed by Greg Kroah-Hartman

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: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 70ef835c
...@@ -836,44 +836,24 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, ...@@ -836,44 +836,24 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
return ret; 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 * @cl: host client
* *
* Locking: called under "dev->device_lock" lock
*
* Return: 0 on success, <0 on failure. * 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_device *dev;
struct mei_cl_cb *cb; struct mei_cl_cb *cb;
int rets; int rets;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
dev = cl->dev; dev = cl->dev;
cl_dbg(dev, cl, "disconnecting"); if (WARN_ON(!pm_runtime_active(dev->dev)))
return -EFAULT;
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;
}
cl->state = MEI_FILE_DISCONNECTING; cl->state = MEI_FILE_DISCONNECTING;
...@@ -910,11 +890,52 @@ int mei_cl_disconnect(struct mei_cl *cl) ...@@ -910,11 +890,52 @@ int mei_cl_disconnect(struct mei_cl *cl)
if (!rets) if (!rets)
cl_dbg(dev, cl, "successfully disconnected from FW client.\n"); 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"); cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(dev->dev); pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev); pm_runtime_put_autosuspend(dev->dev);
mei_io_cb_free(cb);
return rets; return rets;
} }
...@@ -1059,11 +1080,23 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, ...@@ -1059,11 +1080,23 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
wait_event_timeout(cl->wait, wait_event_timeout(cl->wait,
(cl->state == MEI_FILE_CONNECTED || (cl->state == MEI_FILE_CONNECTED ||
cl->state == MEI_FILE_DISCONNECT_REQUIRED ||
cl->state == MEI_FILE_DISCONNECT_REPLY), cl->state == MEI_FILE_DISCONNECT_REPLY),
mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
mutex_lock(&dev->device_lock); mutex_lock(&dev->device_lock);
if (!mei_cl_is_connected(cl)) { 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 */ /* timeout or something went really wrong */
if (!cl->status) if (!cl->status)
cl->status = -EFAULT; cl->status = -EFAULT;
......
...@@ -156,6 +156,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf, ...@@ -156,6 +156,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
dev->hbm_f_pg_supported); dev->hbm_f_pg_supported);
pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n", pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n",
dev->hbm_f_dc_supported); 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", pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n",
......
...@@ -774,6 +774,10 @@ static void mei_hbm_config_features(struct mei_device *dev) ...@@ -774,6 +774,10 @@ static void mei_hbm_config_features(struct mei_device *dev)
if (dev->version.major_version >= HBM_MAJOR_VERSION_DC) if (dev->version.major_version >= HBM_MAJOR_VERSION_DC)
dev->hbm_f_dc_supported = 1; 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 @@ ...@@ -52,6 +52,12 @@
#define HBM_MINOR_VERSION_DC 0 #define HBM_MINOR_VERSION_DC 0
#define HBM_MAJOR_VERSION_DC 2 #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 */ /* Host bus message command opcode */
#define MEI_HBM_CMD_OP_MSK 0x7f #define MEI_HBM_CMD_OP_MSK 0x7f
/* Host bus message command RESPONSE */ /* Host bus message command RESPONSE */
......
...@@ -424,6 +424,24 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) ...@@ -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); 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. * mei_timer - timer function.
...@@ -464,7 +482,7 @@ void mei_timer(struct work_struct *work) ...@@ -464,7 +482,7 @@ void mei_timer(struct work_struct *work)
if (cl->timer_count) { if (cl->timer_count) {
if (--cl->timer_count == 0) { if (--cl->timer_count == 0) {
dev_err(dev->dev, "timer: connect/disconnect timeout.\n"); dev_err(dev->dev, "timer: connect/disconnect timeout.\n");
mei_reset(dev); mei_connect_timeout(cl);
goto out; goto out;
} }
} }
......
...@@ -89,6 +89,7 @@ enum file_state { ...@@ -89,6 +89,7 @@ enum file_state {
MEI_FILE_CONNECTED, MEI_FILE_CONNECTED,
MEI_FILE_DISCONNECTING, MEI_FILE_DISCONNECTING,
MEI_FILE_DISCONNECT_REPLY, MEI_FILE_DISCONNECT_REPLY,
MEI_FILE_DISCONNECT_REQUIRED,
MEI_FILE_DISCONNECTED, MEI_FILE_DISCONNECTED,
}; };
...@@ -407,8 +408,9 @@ const char *mei_pg_state_str(enum mei_pg_state state); ...@@ -407,8 +408,9 @@ const char *mei_pg_state_str(enum mei_pg_state state);
* @wr_msg : the buffer for hbm control messages * @wr_msg : the buffer for hbm control messages
* *
* @version : HBM protocol version in use * @version : HBM protocol version in use
* @hbm_f_pg_supported : hbm feature pgi protocol * @hbm_f_pg_supported : hbm feature pgi protocol
* @hbm_f_dc_supported : hbm feature dynamic clients * @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_rwsem: rw lock over me_clients list
* @me_clients : list of FW clients * @me_clients : list of FW clients
...@@ -503,6 +505,7 @@ struct mei_device { ...@@ -503,6 +505,7 @@ struct mei_device {
struct hbm_version version; struct hbm_version version;
unsigned int hbm_f_pg_supported:1; unsigned int hbm_f_pg_supported:1;
unsigned int hbm_f_dc_supported:1; unsigned int hbm_f_dc_supported:1;
unsigned int hbm_f_dot_supported:1;
struct rw_semaphore me_clients_rwsem; struct rw_semaphore me_clients_rwsem;
struct list_head me_clients; struct list_head me_clients;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment