]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/misc/mei/client.c
mei: revamp writing slot counting
[karo-tx-linux.git] / drivers / misc / mei / client.c
index fdc25595534162e1efec93f5c26880e83f87b8b3..2b0f99955ba6a71babc3d6e2c27df09be661d729 100644 (file)
@@ -371,6 +371,23 @@ void mei_host_client_init(struct work_struct *work)
        mutex_unlock(&dev->device_lock);
 }
 
+/**
+ * mei_hbuf_acquire: try to acquire host buffer
+ *
+ * @dev: the device structure
+ * returns true if host buffer was acquired
+ */
+bool mei_hbuf_acquire(struct mei_device *dev)
+{
+       if (!dev->hbuf_is_ready) {
+               dev_dbg(&dev->pdev->dev, "hbuf is not ready\n");
+               return false;
+       }
+
+       dev->hbuf_is_ready = false;
+
+       return true;
+}
 
 /**
  * mei_cl_disconnect - disconnect host client from the me one
@@ -402,8 +419,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
                return -ENOMEM;
 
        cb->fop_type = MEI_FOP_CLOSE;
-       if (dev->hbuf_is_ready) {
-               dev->hbuf_is_ready = false;
+       if (mei_hbuf_acquire(dev)) {
                if (mei_hbm_cl_disconnect_req(dev, cl)) {
                        rets = -ENODEV;
                        cl_err(dev, cl, "failed to disconnect.\n");
@@ -503,9 +519,8 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
 
        cb->fop_type = MEI_FOP_CONNECT;
 
-       if (dev->hbuf_is_ready && !mei_cl_is_other_connecting(cl)) {
-               dev->hbuf_is_ready = false;
-
+       /* run hbuf acquire last so we don't have to undo */
+       if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
                if (mei_hbm_cl_connect_req(dev, cl)) {
                        rets = -ENODEV;
                        goto out;
@@ -663,9 +678,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
                goto err;
 
        cb->fop_type = MEI_FOP_READ;
-       cl->read_cb = cb;
-       if (dev->hbuf_is_ready) {
-               dev->hbuf_is_ready = false;
+       if (mei_hbuf_acquire(dev)) {
                if (mei_hbm_cl_flow_control_req(dev, cl)) {
                        cl_err(dev, cl, "flow control send failed\n");
                        rets = -ENODEV;
@@ -675,6 +688,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
        } else {
                list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
        }
+
+       cl->read_cb = cb;
+
        return rets;
 err:
        mei_io_cb_free(cb);
@@ -682,27 +698,26 @@ err:
 }
 
 /**
- * mei_cl_irq_write_complete - write a message to device
+ * mei_cl_irq_write - write a message to device
  *     from the interrupt thread context
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise error.
  */
-int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
-                                    s32 *slots, struct mei_cl_cb *cmpl_list)
+int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+                    struct mei_cl_cb *cmpl_list)
 {
        struct mei_device *dev;
        struct mei_msg_data *buf;
        struct mei_msg_hdr mei_hdr;
        size_t len;
        u32 msg_slots;
+       int slots;
        int rets;
 
-
        if (WARN_ON(!cl || !cl->dev))
                return -ENODEV;
 
@@ -719,6 +734,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
                return 0;
        }
 
+       slots = mei_hbuf_empty_slots(dev);
        len = buf->size - cb->buf_idx;
        msg_slots = mei_data2slots(len);
 
@@ -727,13 +743,13 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
        mei_hdr.reserved = 0;
        mei_hdr.internal = cb->internal;
 
-       if (*slots >= msg_slots) {
+       if (slots >= msg_slots) {
                mei_hdr.length = len;
                mei_hdr.msg_complete = 1;
        /* Split the message only if we can write the whole host buffer */
-       } else if (*slots == dev->hbuf_depth) {
-               msg_slots = *slots;
-               len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
+       } else if (slots == dev->hbuf_depth) {
+               msg_slots = slots;
+               len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
                mei_hdr.length = len;
                mei_hdr.msg_complete = 0;
        } else {
@@ -744,7 +760,6 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
        cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
                        cb->request_buffer.size, cb->buf_idx);
 
-       *slots -=  msg_slots;
        rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
        if (rets) {
                cl->status = rets;
@@ -797,21 +812,29 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
 
 
        cb->fop_type = MEI_FOP_WRITE;
+       cb->buf_idx = 0;
+       cl->writing_state = MEI_IDLE;
+
+       mei_hdr.host_addr = cl->host_client_id;
+       mei_hdr.me_addr = cl->me_client_id;
+       mei_hdr.reserved = 0;
+       mei_hdr.msg_complete = 0;
+       mei_hdr.internal = cb->internal;
 
        rets = mei_cl_flow_ctrl_creds(cl);
        if (rets < 0)
                goto err;
 
-       /* Host buffer is not ready, we queue the request */
-       if (rets == 0 || !dev->hbuf_is_ready) {
-               cb->buf_idx = 0;
-               /* unseting complete will enqueue the cb for write */
-               mei_hdr.msg_complete = 0;
+       if (rets == 0) {
+               cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
+               rets = buf->size;
+               goto out;
+       }
+       if (!mei_hbuf_acquire(dev)) {
+               cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
                rets = buf->size;
                goto out;
        }
-
-       dev->hbuf_is_ready = false;
 
        /* Check for a maximum length */
        if (buf->size > mei_hbuf_max_len(dev)) {
@@ -822,12 +845,6 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
                mei_hdr.msg_complete = 1;
        }
 
-       mei_hdr.host_addr = cl->host_client_id;
-       mei_hdr.me_addr = cl->me_client_id;
-       mei_hdr.reserved = 0;
-       mei_hdr.internal = cb->internal;
-
-
        rets = mei_write_message(dev, &mei_hdr, buf->data);
        if (rets)
                goto err;