From c54bf3ab7536e062b507b625bfd2befb9b2cb841 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:39 +0200 Subject: [PATCH] mei: iamthif: send flow control as a regular client Reuse common client mechanism for sending flow control hbm message. Add new function mei_amthif_read_start similar to mei_cl_read_start that puts control flow request onto the control write queue and drop mei_amthif_irq_read function Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 134 +++++++++++++++++++---------------- drivers/misc/mei/interrupt.c | 25 ++----- drivers/misc/mei/mei_dev.h | 2 - 3 files changed, 77 insertions(+), 84 deletions(-) diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 788b00e23353..e6f7180fd8f2 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -254,6 +254,47 @@ int mei_amthif_read(struct mei_device *dev, struct file *file, return rets; } +/** + * mei_amthif_read_start - queue message for sending read credential + * + * @cl: host client + * @file: file pointer of message recipient + * + * Return: 0 on success, <0 on failure. + */ +static int mei_amthif_read_start(struct mei_cl *cl, struct file *file) +{ + struct mei_device *dev = cl->dev; + struct mei_cl_cb *cb; + size_t length = dev->iamthif_mtu; + int rets; + + cb = mei_io_cb_init(cl, file); + if (!cb) { + rets = -ENOMEM; + goto err; + } + + rets = mei_io_cb_alloc_resp_buf(cb, length); + if (rets) + goto err; + + cb->fop_type = MEI_FOP_READ; + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); + + dev->iamthif_msg_buf_index = 0; + dev->iamthif_msg_buf_size = 0; + + dev->iamthif_state = MEI_IAMTHIF_READING; + dev->iamthif_file_object = cb->file_object; + dev->iamthif_current_cb = cb; + + return 0; +err: + mei_io_cb_free(cb); + return rets; +} + /** * mei_amthif_send_cmd - send amthif command to the ME * @@ -287,6 +328,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) if (ret < 0) return ret; + cb->fop_type = MEI_FOP_WRITE; if (ret && mei_hbuf_acquire(dev)) { ret = 0; if (cb->request_buffer.size > mei_hbuf_max_len(dev)) { @@ -309,19 +351,17 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) if (mei_hdr.msg_complete) { if (mei_cl_flow_ctrl_reduce(cl)) return -EIO; - dev->iamthif_flow_control_pending = true; - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev_dbg(dev->dev, "add amthif cb to write waiting list\n"); - dev->iamthif_current_cb = cb; - dev->iamthif_file_object = cb->file_object; + cb->status = mei_amthif_read_start(cl, cb->file_object); list_add_tail(&cb->list, &dev->write_waiting_list.list); } else { dev_dbg(dev->dev, "message does not complete, so add amthif cb to write list.\n"); list_add_tail(&cb->list, &dev->write_list.list); } } else { + list_add_tail(&cb->list, &dev->write_list.list); } + return 0; } @@ -336,17 +376,10 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) */ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) { - int ret; - if (!dev || !cb) return -ENODEV; - ret = mei_io_cb_alloc_resp_buf(cb, dev->iamthif_mtu); - if (ret) - return ret; - cb->fop_type = MEI_FOP_WRITE; - if (!list_empty(&dev->amthif_cmd_list.list) || dev->iamthif_state != MEI_IAMTHIF_IDLE) { dev_dbg(dev->dev, @@ -383,7 +416,7 @@ void mei_amthif_run_next_cmd(struct mei_device *dev) typeof(*cb), list); if (!cb) return; - list_del(&cb->list); + list_del_init(&cb->list); ret = mei_amthif_send_cmd(dev, cb); if (ret) dev_warn(dev->dev, "amthif write failed status = %d\n", ret); @@ -483,13 +516,7 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, cl->status = 0; if (mei_hdr.msg_complete) { - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev->iamthif_flow_control_pending = true; - - /* save iamthif cb sent to amthif client */ - cb->buf_idx = dev->iamthif_msg_buf_index; - dev->iamthif_current_cb = cb; - + cb->status = mei_amthif_read_start(cl, cb->file_object); list_move_tail(&cb->list, &dev->write_waiting_list.list); } @@ -505,7 +532,7 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, * @mei_hdr: header of amthif message * @complete_list: completed callbacks list * - * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status + * Return: Always 0; error message is in cb->status */ int mei_amthif_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr, @@ -514,7 +541,6 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl, struct mei_device *dev; struct mei_cl_cb *cb; unsigned char *buffer; - int ret = 0; dev = cl->dev; @@ -524,10 +550,13 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl, if (dev->iamthif_state != MEI_IAMTHIF_READING) goto err; - cb = dev->iamthif_current_cb; + list_for_each_entry(cb, &dev->read_list.list, list) { + if (cl == cb->cl) + break; + } - if (!cb) { - ret = -ENODEV; + if (&cb->list == &dev->read_list.list) { + dev_err(dev->dev, "no reader found\n"); goto err; } @@ -553,7 +582,7 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl, cb->read_time = jiffies; dev_dbg(dev->dev, "complete the amthif read cb.\n "); - list_add_tail(&cb->list, &complete_list->list); + list_move_tail(&cb->list, &complete_list->list); return 0; @@ -561,38 +590,6 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl, mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length); dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n", MEI_HDR_PRM(mei_hdr)); - return ret; -} - -/** - * mei_amthif_irq_read - prepares to read amthif data. - * - * @dev: the device structure. - * @slots: free slots. - * - * Return: 0, OK; otherwise, error. - */ -int mei_amthif_irq_read(struct mei_device *dev, s32 *slots) -{ - u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control)); - - if (*slots < msg_slots) - return -EMSGSIZE; - - *slots -= msg_slots; - - if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) { - dev_dbg(dev->dev, "iamthif flow control failed\n"); - return -EIO; - } - - dev_dbg(dev->dev, "iamthif flow control success\n"); - dev->iamthif_state = MEI_IAMTHIF_READING; - dev->iamthif_flow_control_pending = false; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; - dev->hbuf_is_ready = mei_hbuf_is_ready(dev); return 0; } @@ -604,17 +601,32 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots) */ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb) { + + if (cb->fop_type == MEI_FOP_WRITE) { + if (!cb->status) { + dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; + mei_io_cb_free(cb); + return; + } + /* + * in case of error enqueue the write cb to complete read list + * so it can be propagated to the reader + */ + list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list); + wake_up_interruptible(&dev->iamthif_cl.wait); + return; + } + if (dev->iamthif_canceled != 1) { dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; dev->iamthif_stall_timer = 0; memcpy(cb->response_buffer.data, - dev->iamthif_msg_buf, - dev->iamthif_msg_buf_index); + dev->iamthif_msg_buf, dev->iamthif_msg_buf_index); list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list); dev_dbg(dev->dev, "amthif read completed\n"); dev->iamthif_timer = jiffies; dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n", - dev->iamthif_timer); + dev->iamthif_timer); } else { mei_amthif_run_next_cmd(dev); } diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 4cb602fba593..89f2fbce160f 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -43,7 +43,7 @@ void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list) list_for_each_entry_safe(cb, next, &compl_list->list, list) { cl = cb->cl; - list_del(&cb->list); + list_del_init(&cb->list); dev_dbg(dev->dev, "completing call back.\n"); if (cl == &dev->iamthif_cl) @@ -386,11 +386,6 @@ int mei_irq_read_handler(struct mei_device *dev, if (cl == &dev->iamthif_cl) { ret = mei_amthif_irq_read_msg(cl, mei_hdr, cmpl_list); - if (ret) { - dev_err(dev->dev, "mei_amthif_irq_read_msg failed = %d\n", - ret); - goto end; - } } else { ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list); } @@ -448,21 +443,9 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) cl = cb->cl; cl->status = 0; - list_del(&cb->list); - if (cb->fop_type == MEI_FOP_WRITE && - cl != &dev->iamthif_cl) { - cl_dbg(dev, cl, "MEI WRITE COMPLETE\n"); - cl->writing_state = MEI_WRITE_COMPLETE; - list_add_tail(&cb->list, &cmpl_list->list); - } - if (cl == &dev->iamthif_cl) { - cl_dbg(dev, cl, "check iamthif flow control.\n"); - if (dev->iamthif_flow_control_pending) { - ret = mei_amthif_irq_read(dev, &slots); - if (ret) - return ret; - } - } + cl_dbg(dev, cl, "MEI WRITE COMPLETE\n"); + cl->writing_state = MEI_WRITE_COMPLETE; + list_move_tail(&cb->list, &cmpl_list->list); } if (dev->wd_state == MEI_WD_STOPPING) { diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 6cc68de580ba..fc460af131d4 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -487,7 +487,6 @@ const char *mei_pg_state_str(enum mei_pg_state state); * @iamthif_msg_buf_size : size of current amthif message request buffer * @iamthif_msg_buf_index : current index in amthif message request buffer * @iamthif_state : amthif processor state - * @iamthif_flow_control_pending: amthif waits for flow control * @iamthif_canceled : current amthif command is canceled * * @init_work : work item for the device init @@ -586,7 +585,6 @@ struct mei_device { u32 iamthif_msg_buf_size; u32 iamthif_msg_buf_index; enum iamthif_states iamthif_state; - bool iamthif_flow_control_pending; bool iamthif_canceled; struct work_struct init_work; -- GitLab