mei: add a handler that waits for notification on event
authorTomas Winkler <tomas.winkler@intel.com>
Sun, 26 Jul 2015 06:54:19 +0000 (09:54 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 4 Aug 2015 00:30:00 +0000 (17:30 -0700)
mei_cl_notify_get is to be called by a host client
to wait, receive, and ack the event notification.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/mei/client.c
drivers/misc/mei/client.h
drivers/misc/mei/hbm.c
drivers/misc/mei/mei_dev.h

index fae4050413a25b56baedcd0273dd2c67614bbc2c..d9396838774c50db2afdf11610b209520d573589 100644 (file)
@@ -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);
@@ -1349,6 +1350,51 @@ out:
        return rets;
 }
 
+/**
+ * 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.
  *
@@ -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);
+               }
        }
 }
 
index 506b7d40d42792a918ea96fa36769ff5056095f0..58a4b49701fe0b720033be3cbdc092419e4aabb4 100644 (file)
@@ -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);
index 12229ff4bc7e4da817fe3cf513e774133d769f73..70c94a9cd9052b2134c414a2e9a1839772b07107 100644 (file)
@@ -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);
+       }
 }
 
 /**
index e22bd21bb754600ec99dbf366d492eb9e7b29c6f..6f8f5e1e909ecd31059b31c0007f97218ae8eddc 100644 (file)
@@ -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;