diff options
-rw-r--r-- | drivers/misc/mei/client.c | 52 | ||||
-rw-r--r-- | drivers/misc/mei/client.h | 1 | ||||
-rw-r--r-- | drivers/misc/mei/hbm.c | 4 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 2 |
4 files changed, 58 insertions, 1 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index fae4050413a2..d9396838774c 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -555,6 +555,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) init_waitqueue_head(&cl->wait); init_waitqueue_head(&cl->rx_wait); init_waitqueue_head(&cl->tx_wait); + init_waitqueue_head(&cl->ev_wait); INIT_LIST_HEAD(&cl->rd_completed); INIT_LIST_HEAD(&cl->rd_pending); INIT_LIST_HEAD(&cl->link); @@ -1350,6 +1351,51 @@ out: } /** + * mei_cl_notify_get - get or wait for notification event + * + * @cl: host client + * @block: this request is blocking + * @notify_ev: true if notification event was received + * + * Locking: called under "dev->device_lock" lock + * + * Return: 0 on such and error otherwise. + */ +int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev) +{ + struct mei_device *dev; + int rets; + + *notify_ev = false; + + if (WARN_ON(!cl || !cl->dev)) + return -ENODEV; + + dev = cl->dev; + + if (!mei_cl_is_connected(cl)) + return -ENODEV; + + if (cl->notify_ev) + goto out; + + if (!block) + return -EAGAIN; + + mutex_unlock(&dev->device_lock); + rets = wait_event_interruptible(cl->ev_wait, cl->notify_ev); + mutex_lock(&dev->device_lock); + + if (rets < 0) + return rets; + +out: + *notify_ev = cl->notify_ev; + cl->notify_ev = false; + return 0; +} + +/** * mei_cl_read_start - the start read client message function. * * @cl: host client @@ -1701,6 +1747,12 @@ void mei_cl_all_wakeup(struct mei_device *dev) cl_dbg(dev, cl, "Waking up writing client!\n"); wake_up_interruptible(&cl->tx_wait); } + + /* synchronized under device mutex */ + if (waitqueue_active(&cl->ev_wait)) { + cl_dbg(dev, cl, "Waking up waiting for event clients!\n"); + wake_up_interruptible(&cl->ev_wait); + } } } diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 506b7d40d427..58a4b49701fe 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -224,6 +224,7 @@ enum mei_cb_file_ops mei_cl_notify_req2fop(u8 request); int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request); int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); +int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev); void mei_cl_all_disconnect(struct mei_device *dev); void mei_cl_all_wakeup(struct mei_device *dev); diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 12229ff4bc7e..70c94a9cd905 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -514,8 +514,10 @@ static void mei_hbm_cl_notify(struct mei_device *dev, struct mei_cl *cl; cl = mei_hbm_cl_find_by_cmd(dev, cmd); - if (cl && cl->notify_en) + if (cl && cl->notify_en) { cl->notify_ev = true; + wake_up_interruptible(&cl->ev_wait); + } } /** diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index e22bd21bb754..6f8f5e1e909e 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -235,6 +235,7 @@ struct mei_cl_cb { * @tx_wait: wait queue for tx completion * @rx_wait: wait queue for rx completion * @wait: wait queue for management operation + * @ev_wait: notification wait queue * @status: connection status * @me_cl: fw client connected * @host_client_id: host id @@ -256,6 +257,7 @@ struct mei_cl { wait_queue_head_t tx_wait; wait_queue_head_t rx_wait; wait_queue_head_t wait; + wait_queue_head_t ev_wait; int status; struct mei_me_client *me_cl; u8 host_client_id; |