summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/mei/hw.h2
-rw-r--r--drivers/misc/mei/init.c2
-rw-r--r--drivers/misc/mei/main.c25
-rw-r--r--drivers/misc/mei/mei_dev.h3
4 files changed, 32 insertions, 0 deletions
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index 2e9cf6f4efb6..3771aa09c592 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -27,6 +27,8 @@
#define MKHI_RCV_TIMEOUT 500 /* receive timeout in msec */
#define MKHI_RCV_TIMEOUT_SLOW 10000 /* receive timeout in msec, slow FW */
+#define MEI_LINK_RESET_WAIT_TIMEOUT_MSEC 500 /* Max wait timeout for link reset, in msec */
+
/*
* FW page size for DMA allocations
*/
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index b9fb54328a7b..32ce6a879207 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -400,6 +400,7 @@ void mei_device_init(struct mei_device *dev,
init_waitqueue_head(&dev->wait_pg);
init_waitqueue_head(&dev->wait_hbm_start);
dev->dev_state = MEI_DEV_UNINITIALIZED;
+ init_waitqueue_head(&dev->wait_dev_state);
dev->reset_count = 0;
INIT_LIST_HEAD(&dev->write_list);
@@ -442,5 +443,6 @@ void mei_device_init(struct mei_device *dev,
dev->timeouts.hbm = mei_secs_to_jiffies(MEI_HBM_TIMEOUT);
dev->timeouts.mkhi_recv = msecs_to_jiffies(MKHI_RCV_TIMEOUT);
}
+ dev->timeouts.link_reset_wait = msecs_to_jiffies(MEI_LINK_RESET_WAIT_TIMEOUT_MSEC);
}
EXPORT_SYMBOL_GPL(mei_device_init);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 2d41a05b8694..e69140fc5aa4 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -423,6 +423,7 @@ static int mei_ioctl_connect_client(struct file *file,
cl->state != MEI_FILE_DISCONNECTED)
return -EBUSY;
+retry:
/* find ME client we're trying to connect to */
me_cl = mei_me_cl_by_uuid(dev, in_client_uuid);
if (!me_cl) {
@@ -454,6 +455,28 @@ static int mei_ioctl_connect_client(struct file *file,
rets = mei_cl_connect(cl, me_cl, file);
+ if (rets && cl->status == -EFAULT &&
+ (dev->dev_state == MEI_DEV_RESETTING ||
+ dev->dev_state == MEI_DEV_INIT_CLIENTS)) {
+ /* in link reset, wait for it completion */
+ mutex_unlock(&dev->device_lock);
+ rets = wait_event_interruptible_timeout(dev->wait_dev_state,
+ dev->dev_state == MEI_DEV_ENABLED,
+ dev->timeouts.link_reset_wait);
+ mutex_lock(&dev->device_lock);
+ if (rets < 0) {
+ if (signal_pending(current))
+ rets = -EINTR;
+ goto end;
+ }
+ if (dev->dev_state != MEI_DEV_ENABLED) {
+ rets = -ETIME;
+ goto end;
+ }
+ mei_me_cl_put(me_cl);
+ goto retry;
+ }
+
end:
mei_me_cl_put(me_cl);
return rets;
@@ -1120,6 +1143,8 @@ void mei_set_devstate(struct mei_device *dev, enum mei_dev_state state)
dev->dev_state = state;
+ wake_up_interruptible_all(&dev->wait_dev_state);
+
if (!dev->cdev)
return;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 9f2044ae6cc4..23afa381a0a0 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -466,6 +466,7 @@ struct mei_dev_timeouts {
unsigned int d0i3; /* D0i3 set/unset max response time, in jiffies */
unsigned long hbm; /* HBM operation timeout, in jiffies */
unsigned long mkhi_recv; /* receive timeout, in jiffies */
+ unsigned long link_reset_wait; /* link reset wait timeout, in jiffies */
};
/**
@@ -496,6 +497,7 @@ struct mei_dev_timeouts {
*
* @reset_count : number of consecutive resets
* @dev_state : device state
+ * @wait_dev_state: wait queue for device state change
* @hbm_state : state of host bus message protocol
* @pxp_mode : PXP device mode
* @init_clients_timer : HBM init handshake timeout
@@ -588,6 +590,7 @@ struct mei_device {
*/
unsigned long reset_count;
enum mei_dev_state dev_state;
+ wait_queue_head_t wait_dev_state;
enum mei_hbm_state hbm_state;
enum mei_dev_pxp_mode pxp_mode;
u16 init_clients_timer;