From db4756fd2f16efae8469dd1e37710919a0af9370 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:37 +0200 Subject: [PATCH] mei: iamthif: fix device reset on mei_amthif_irq_read_msg On failure mei_amthif_irq_read_msg returns an error that will cause device reset but the issue is software one so instead we should propagate error to caller and just clean the read queues. As a side effect also removes useless BUG_ONs Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 76 +++++++++++++++++++++++------------- drivers/misc/mei/interrupt.c | 7 +--- drivers/misc/mei/mei_dev.h | 2 +- 3 files changed, 51 insertions(+), 34 deletions(-) diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index c4cb9a984a5f..2ad2f94678c8 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -195,23 +195,26 @@ int mei_amthif_read(struct mei_device *dev, struct file *file, dev_dbg(dev->dev, "woke up from sleep\n"); } + if (cb->status) { + rets = cb->status; + dev_dbg(dev->dev, "read operation failed %d\n", rets); + goto free; + } dev_dbg(dev->dev, "Got amthif data\n"); dev->iamthif_timer = 0; - if (cb) { - timeout = cb->read_time + - mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); - dev_dbg(dev->dev, "amthif timeout = %lud\n", - timeout); - - if (time_after(jiffies, timeout)) { - dev_dbg(dev->dev, "amthif Time out\n"); - /* 15 sec for the message has expired */ - list_del(&cb->list); - rets = -ETIME; - goto free; - } + timeout = cb->read_time + + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); + dev_dbg(dev->dev, "amthif timeout = %lud\n", + timeout); + + if (time_after(jiffies, timeout)) { + dev_dbg(dev->dev, "amthif Time out\n"); + /* 15 sec for the message has expired */ + list_del(&cb->list); + rets = -ETIME; + goto free; } /* if the whole message will fit remove it from the list */ if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) @@ -501,25 +504,42 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, * mei_amthif_irq_read_msg - read routine after ISR to * handle the read amthif message * - * @dev: the device structure + * @cl: mei client * @mei_hdr: header of amthif message - * @complete_list: An instance of our list structure + * @complete_list: completed callbacks list * - * Return: 0 on success, <0 on failure. + * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status */ -int mei_amthif_irq_read_msg(struct mei_device *dev, +int mei_amthif_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr, struct mei_cl_cb *complete_list) { + struct mei_device *dev; struct mei_cl_cb *cb; unsigned char *buffer; + int ret = 0; - BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id); - BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); + dev = cl->dev; - buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; - BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); + if (cl->state != MEI_FILE_CONNECTED) + goto err; + + if (dev->iamthif_state != MEI_IAMTHIF_READING) + goto err; + + cb = dev->iamthif_current_cb; + if (!cb) { + ret = -ENODEV; + goto err; + } + + if (dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length) { + cb->status = -ERANGE; + goto err; + } + + buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; mei_read_slots(dev, buffer, mei_hdr->length); dev->iamthif_msg_buf_index += mei_hdr->length; @@ -527,14 +547,8 @@ int mei_amthif_irq_read_msg(struct mei_device *dev, if (!mei_hdr->msg_complete) return 0; - dev_dbg(dev->dev, "amthif_message_buffer_index =%d\n", - mei_hdr->length); - dev_dbg(dev->dev, "completed amthif read.\n "); - if (!dev->iamthif_current_cb) - return -ENODEV; - cb = dev->iamthif_current_cb; dev->iamthif_current_cb = NULL; dev->iamthif_stall_timer = 0; @@ -543,10 +557,16 @@ int mei_amthif_irq_read_msg(struct mei_device *dev, if (dev->iamthif_ioctl) { /* found the iamthif cb */ dev_dbg(dev->dev, "complete the amthif read cb.\n "); - dev_dbg(dev->dev, "add the amthif read cb to complete.\n "); list_add_tail(&cb->list, &complete_list->list); } + return 0; + +err: + 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; } /** diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 587cb04a3cf5..151f0c84a65e 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -384,11 +384,8 @@ int mei_irq_read_handler(struct mei_device *dev, goto end; } - if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && - MEI_FILE_CONNECTED == dev->iamthif_cl.state && - dev->iamthif_state == MEI_IAMTHIF_READING) { - - ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list); + 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); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 195e426b08f0..b74d156ed600 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -685,7 +685,7 @@ 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, +int mei_amthif_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr, struct mei_cl_cb *complete_list); int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); -- 2.34.1