mei: revamp writing slot counting
authorTomas Winkler <tomas.winkler@intel.com>
Wed, 19 Feb 2014 15:35:48 +0000 (17:35 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 28 Feb 2014 23:15:57 +0000 (15:15 -0800)
Since txe use doorbell and not circular buffer
we have to cheat in write slot counting, txe always consume all the
slots upon write. In order for it to work we need to track
slots using mei_hbuf_empty_slots() instead of tracking it in mei layer

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/mei/amthif.c
drivers/misc/mei/client.c
drivers/misc/mei/client.h
drivers/misc/mei/hw-me.c
drivers/misc/mei/hw-txe.c
drivers/misc/mei/hw-txe.h
drivers/misc/mei/interrupt.c
drivers/misc/mei/mei_dev.h

index e7ba8801d2b4afe01494e1e8982fdf775b7dcfa3..bff9a07f1af57e3b75992e52b06f13185932492f 100644 (file)
@@ -436,23 +436,23 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
 
 
 /**
- * mei_amthif_irq_write_completed - processes completed iamthif operation.
+ * mei_amthif_irq_write - write iamthif command in irq thread context.
  *
  * @dev: the device structure.
- * @slots: free slots.
  * @cb_pos: callback block.
  * @cl: private data of the file object.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
-int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
-                                 s32 *slots, struct mei_cl_cb *cmpl_list)
+int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+                        struct mei_cl_cb *cmpl_list)
 {
        struct mei_device *dev = cl->dev;
        struct mei_msg_hdr mei_hdr;
        size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index;
        u32 msg_slots = mei_data2slots(len);
+       int slots;
        int rets;
 
        rets = mei_cl_flow_ctrl_creds(cl);
@@ -469,13 +469,15 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
        mei_hdr.reserved = 0;
        mei_hdr.internal = 0;
 
-       if (*slots >= msg_slots) {
+       slots = mei_hbuf_empty_slots(dev);
+
+       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 {
@@ -485,7 +487,6 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
 
        dev_dbg(&dev->pdev->dev, MEI_HDR_FMT,  MEI_HDR_PRM(&mei_hdr));
 
-       *slots -=  msg_slots;
        rets = mei_write_message(dev, &mei_hdr,
                        dev->iamthif_msg_buf + dev->iamthif_msg_buf_index);
        if (rets) {
index 083179b752972017513dda41b35ad9d6148c340a..2b0f99955ba6a71babc3d6e2c27df09be661d729 100644 (file)
@@ -698,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;
 
@@ -735,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);
 
@@ -743,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 {
@@ -760,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;
index c8396e582f1c697d296834cb62f19442998b59be..c11b663358a4314dff0208ec2afb6f7417467cd6 100644 (file)
@@ -102,8 +102,8 @@ int mei_cl_disconnect(struct mei_cl *cl);
 int mei_cl_connect(struct mei_cl *cl, struct file *file);
 int mei_cl_read_start(struct mei_cl *cl, size_t length);
 int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
-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);
 
 void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
 
index b0c42d6182a60a0981c50f7daae95cab53a58fb0..84165cce57d2ef6cef31530d7e3a409954b14603 100644 (file)
@@ -354,7 +354,7 @@ static int mei_me_write_message(struct mei_device *dev,
 
        dw_cnt = mei_data2slots(length);
        if (empty_slots < 0 || dw_cnt > empty_slots)
-               return -EIO;
+               return -EMSGSIZE;
 
        mei_me_reg_write(hw, H_CB_WW, *((u32 *) header));
 
index 8f5e4be9ebc2c9316ec7978602aaa106bf28f022..f60182a52f964f438709af433efb0f80a27fcb24 100644 (file)
@@ -566,7 +566,9 @@ static int mei_txe_write(struct mei_device *dev,
        struct mei_txe_hw *hw = to_txe_hw(dev);
        unsigned long rem;
        unsigned long length;
+       int slots = dev->hbuf_depth;
        u32 *reg_buf = (u32 *)buf;
+       u32 dw_cnt;
        int i;
 
        if (WARN_ON(!header || !buf))
@@ -576,11 +578,9 @@ static int mei_txe_write(struct mei_device *dev,
 
        dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
 
-       if ((length + sizeof(struct mei_msg_hdr)) > PAYLOAD_SIZE) {
-               dev_err(&dev->pdev->dev, "write length exceeded = %ld > %d\n",
-                       length + sizeof(struct mei_msg_hdr), PAYLOAD_SIZE);
-               return -ERANGE;
-       }
+       dw_cnt = mei_data2slots(length);
+       if (dw_cnt > slots)
+               return -EMSGSIZE;
 
        if (WARN(!hw->aliveness, "txe write: aliveness not asserted\n"))
                return -EAGAIN;
@@ -605,6 +605,9 @@ static int mei_txe_write(struct mei_device *dev,
                mei_txe_input_payload_write(dev, i + 1, reg);
        }
 
+       /* after each write the whole buffer is consumed */
+       hw->slots = 0;
+
        /* Set Input-Doorbell */
        mei_txe_input_doorbell_set(hw);
 
@@ -632,7 +635,8 @@ static size_t mei_txe_hbuf_max_len(const struct mei_device *dev)
  */
 static int mei_txe_hbuf_empty_slots(struct mei_device *dev)
 {
-       return dev->hbuf_depth;
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       return hw->slots;
 }
 
 /**
@@ -978,11 +982,12 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
                }
        }
        /* Input Ready: Detection if host can write to SeC */
-       if (test_and_clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause))
+       if (test_and_clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause)) {
                dev->hbuf_is_ready = true;
+               hw->slots = dev->hbuf_depth;
+       }
 
        if (hw->aliveness && dev->hbuf_is_ready) {
-
                /* get the real register value */
                dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
                rets = mei_irq_write_handler(dev, &complete_list);
index fdb665f44d5d187f2736df8c82bafd6de7820f65..0812d98633a44974b854b25d697bf496badf974b 100644 (file)
@@ -46,6 +46,7 @@ struct mei_txe_hw {
        void __iomem *mem_addr[NUM_OF_MEM_BARS];
        u32 aliveness;
        u32 readiness;
+       u32 slots;
 
        wait_queue_head_t wait_aliveness;
        bool recvd_aliveness;
index aed03efa72f4b5e3fc285095a6255cca70ee998c..e6151e2dac480a176d633529efd8db8c681a9f6b 100644 (file)
@@ -165,25 +165,24 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
 static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
-                       s32 *slots, struct mei_cl_cb *cmpl_list)
+                                    struct mei_cl_cb *cmpl_list)
 {
        struct mei_device *dev = cl->dev;
+       u32 msg_slots;
+       int slots;
        int ret;
 
-       u32 msg_slots =
-               mei_data2slots(sizeof(struct hbm_client_connect_response));
+       slots = mei_hbuf_empty_slots(dev);
+       msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_response));
 
-       if (*slots < msg_slots)
+       if (slots < msg_slots)
                return -EMSGSIZE;
 
-       *slots -= msg_slots;
-
        ret = mei_hbm_cl_disconnect_rsp(dev, cl);
 
        cl->state = MEI_FILE_DISCONNECTED;
@@ -201,24 +200,23 @@ static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
 static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
-                       s32 *slots, struct mei_cl_cb *cmpl_list)
+                           struct mei_cl_cb *cmpl_list)
 {
        struct mei_device *dev = cl->dev;
+       u32 msg_slots;
+       int slots;
 
-       u32 msg_slots =
-               mei_data2slots(sizeof(struct hbm_client_connect_request));
+       msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+       slots = mei_hbuf_empty_slots(dev);
 
-       if (*slots < msg_slots)
+       if (slots < msg_slots)
                return -EMSGSIZE;
 
-       *slots -= msg_slots;
-
        if (mei_hbm_cl_disconnect_req(dev, cl)) {
                cl->status = 0;
                cb->buf_idx = 0;
@@ -242,27 +240,23 @@ static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
 static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
-                          s32 *slots, struct mei_cl_cb *cmpl_list)
+                          struct mei_cl_cb *cmpl_list)
 {
        struct mei_device *dev = cl->dev;
-       u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
-
+       u32 msg_slots;
+       int slots;
        int ret;
 
+       msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
+       slots = mei_hbuf_empty_slots(dev);
 
-       if (*slots < msg_slots) {
-               /* return the cancel routine */
-               list_del(&cb->list);
+       if (slots < msg_slots)
                return -EMSGSIZE;
-       }
-
-       *slots -= msg_slots;
 
        ret = mei_hbm_cl_flow_control_req(dev, cl);
        if (ret) {
@@ -283,30 +277,26 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
 static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
-                          s32 *slots, struct mei_cl_cb *cmpl_list)
+                             struct mei_cl_cb *cmpl_list)
 {
        struct mei_device *dev = cl->dev;
+       u32 msg_slots;
+       int slots;
        int ret;
 
-       u32 msg_slots =
-               mei_data2slots(sizeof(struct hbm_client_connect_request));
+       msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+       slots = mei_hbuf_empty_slots(dev);
 
        if (mei_cl_is_other_connecting(cl))
                return 0;
 
-       if (*slots < msg_slots) {
-               /* return the cancel routine */
-               list_del(&cb->list);
+       if (slots < msg_slots)
                return -EMSGSIZE;
-       }
-
-       *slots -=  msg_slots;
 
        cl->state = MEI_FILE_CONNECTING;
 
@@ -494,13 +484,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
                                dev_dbg(&dev->pdev->dev, "wd send failed.\n");
                        else if (mei_cl_flow_ctrl_reduce(&dev->wd_cl))
                                return -ENODEV;
-
                        dev->wd_pending = false;
-
-                       if (dev->wd_state == MEI_WD_RUNNING)
-                               slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
-                       else
-                               slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
                }
        }
 
@@ -515,28 +499,28 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
                switch (cb->fop_type) {
                case MEI_FOP_CLOSE:
                        /* send disconnect message */
-                       ret = mei_cl_irq_close(cl, cb, &slots, cmpl_list);
+                       ret = mei_cl_irq_close(cl, cb, cmpl_list);
                        if (ret)
                                return ret;
 
                        break;
                case MEI_FOP_READ:
                        /* send flow control message */
-                       ret = mei_cl_irq_read(cl, cb, &slots, cmpl_list);
+                       ret = mei_cl_irq_read(cl, cb, cmpl_list);
                        if (ret)
                                return ret;
 
                        break;
                case MEI_FOP_CONNECT:
                        /* connect message */
-                       ret = mei_cl_irq_connect(cl, cb, &slots, cmpl_list);
+                       ret = mei_cl_irq_connect(cl, cb, cmpl_list);
                        if (ret)
                                return ret;
 
                        break;
                case MEI_FOP_DISCONNECT_RSP:
                        /* send disconnect resp */
-                       ret = mei_cl_irq_disconnect_rsp(cl, cb, &slots, cmpl_list);
+                       ret = mei_cl_irq_disconnect_rsp(cl, cb, cmpl_list);
                        if (ret)
                                return ret;
                default:
@@ -551,11 +535,9 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
                if (cl == NULL)
                        continue;
                if (cl == &dev->iamthif_cl)
-                       ret = mei_amthif_irq_write_complete(cl, cb,
-                                               &slots, cmpl_list);
+                       ret = mei_amthif_irq_write(cl, cb, cmpl_list);
                else
-                       ret = mei_cl_irq_write_complete(cl, cb,
-                                               &slots, cmpl_list);
+                       ret = mei_cl_irq_write(cl, cb, cmpl_list);
                if (ret)
                        return ret;
        }
index 52499bc5a068b03ab5b580d087a2824e9682cac5..36640b9d54c51a63ede520b52eba5083c72576bd 100644 (file)
@@ -515,8 +515,8 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
 
 void mei_amthif_run_next_cmd(struct mei_device *dev);
 
-int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
-                                 s32 *slots, struct mei_cl_cb *cmpl_list);
+int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+                       struct mei_cl_cb *cmpl_list);
 
 void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb);
 int mei_amthif_irq_read_msg(struct mei_device *dev,