diff options
Diffstat (limited to 'drivers/misc/mei/interrupt.c')
-rw-r--r-- | drivers/misc/mei/interrupt.c | 171 |
1 files changed, 71 insertions, 100 deletions
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 711cddfa9c99..3f84d2edcde4 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) @@ -68,91 +68,91 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl, return cl->host_client_id == mei_hdr->host_addr && cl->me_client_id == mei_hdr->me_addr; } + /** - * mei_cl_is_reading - checks if the client - * is the one to read this message - * - * @cl: mei client - * @mei_hdr: header of mei message + * mei_irq_discard_msg - discard received message * - * Return: true on match and false otherwise + * @dev: mei device + * @hdr: message header */ -static bool mei_cl_is_reading(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr) +static inline +void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr) { - return mei_cl_hbm_equal(cl, mei_hdr) && - cl->state == MEI_FILE_CONNECTED && - cl->reading_state != MEI_READ_COMPLETE; + /* + * no need to check for size as it is guarantied + * that length fits into rd_msg_buf + */ + mei_read_slots(dev, dev->rd_msg_buf, hdr->length); + dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n", + MEI_HDR_PRM(hdr)); } /** * mei_cl_irq_read_msg - process client message * - * @dev: the device structure + * @cl: reading client * @mei_hdr: header of mei client message - * @complete_list: An instance of our list structure + * @complete_list: completion list * - * Return: 0 on success, <0 on failure. + * Return: always 0 */ -static int mei_cl_irq_read_msg(struct mei_device *dev, - struct mei_msg_hdr *mei_hdr, - struct mei_cl_cb *complete_list) +int mei_cl_irq_read_msg(struct mei_cl *cl, + struct mei_msg_hdr *mei_hdr, + struct mei_cl_cb *complete_list) { - struct mei_cl *cl; - struct mei_cl_cb *cb, *next; + struct mei_device *dev = cl->dev; + struct mei_cl_cb *cb; unsigned char *buffer = NULL; - list_for_each_entry_safe(cb, next, &dev->read_list.list, list) { - cl = cb->cl; - if (!mei_cl_is_reading(cl, mei_hdr)) - continue; - - cl->reading_state = MEI_READING; + cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list); + if (!cb) { + cl_err(dev, cl, "pending read cb not found\n"); + goto out; + } - if (cb->response_buffer.size == 0 || - cb->response_buffer.data == NULL) { - cl_err(dev, cl, "response buffer is not allocated.\n"); - list_del(&cb->list); - return -ENOMEM; - } + if (!mei_cl_is_connected(cl)) { + cl_dbg(dev, cl, "not connected\n"); + cb->status = -ENODEV; + goto out; + } - if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) { - cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n", - cb->response_buffer.size, - mei_hdr->length, cb->buf_idx); - buffer = krealloc(cb->response_buffer.data, - mei_hdr->length + cb->buf_idx, - GFP_KERNEL); - - if (!buffer) { - list_del(&cb->list); - return -ENOMEM; - } - cb->response_buffer.data = buffer; - cb->response_buffer.size = - mei_hdr->length + cb->buf_idx; - } + if (cb->buf.size == 0 || cb->buf.data == NULL) { + cl_err(dev, cl, "response buffer is not allocated.\n"); + list_move_tail(&cb->list, &complete_list->list); + cb->status = -ENOMEM; + goto out; + } - buffer = cb->response_buffer.data + cb->buf_idx; - mei_read_slots(dev, buffer, mei_hdr->length); + if (cb->buf.size < mei_hdr->length + cb->buf_idx) { + cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n", + cb->buf.size, mei_hdr->length, cb->buf_idx); + buffer = krealloc(cb->buf.data, mei_hdr->length + cb->buf_idx, + GFP_KERNEL); - cb->buf_idx += mei_hdr->length; - if (mei_hdr->msg_complete) { - cl->status = 0; - list_del(&cb->list); - cl_dbg(dev, cl, "completed read length = %lu\n", - cb->buf_idx); - list_add_tail(&cb->list, &complete_list->list); + if (!buffer) { + cb->status = -ENOMEM; + list_move_tail(&cb->list, &complete_list->list); + goto out; } - break; + cb->buf.data = buffer; + cb->buf.size = mei_hdr->length + cb->buf_idx; } - dev_dbg(dev->dev, "message read\n"); - if (!buffer) { - 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)); + buffer = cb->buf.data + cb->buf_idx; + mei_read_slots(dev, buffer, mei_hdr->length); + + cb->buf_idx += mei_hdr->length; + + if (mei_hdr->msg_complete) { + cb->read_time = jiffies; + cl_dbg(dev, cl, "completed read length = %lu\n", cb->buf_idx); + list_move_tail(&cb->list, &complete_list->list); } +out: + if (!buffer) + mei_irq_discard_msg(dev, mei_hdr); + return 0; } @@ -183,7 +183,6 @@ static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb, cl->state = MEI_FILE_DISCONNECTED; cl->status = 0; - list_del(&cb->list); mei_io_cb_free(cb); return ret; @@ -263,7 +262,7 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb, return ret; } - list_move_tail(&cb->list, &dev->read_list.list); + list_move_tail(&cb->list, &cl->rd_pending); return 0; } @@ -301,7 +300,7 @@ static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, if (ret) { cl->status = ret; cb->buf_idx = 0; - list_del(&cb->list); + list_del_init(&cb->list); return ret; } @@ -378,25 +377,13 @@ 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 (ret) { - dev_err(dev->dev, "mei_amthif_irq_read_msg failed = %d\n", - ret); - goto end; - } + if (cl == &dev->iamthif_cl) { + ret = mei_amthif_irq_read_msg(cl, mei_hdr, cmpl_list); } else { - ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list); - if (ret) { - dev_err(dev->dev, "mei_cl_irq_read_msg failed = %d\n", - ret); - goto end; - } + ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list); } + reset_slots: /* reset the number of slots and header */ *slots = mei_count_full_read_slots(dev); @@ -449,21 +436,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) { @@ -587,10 +562,7 @@ void mei_timer(struct work_struct *work) if (--dev->iamthif_stall_timer == 0) { dev_err(dev->dev, "timer: amthif hanged.\n"); mei_reset(dev); - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; dev->iamthif_canceled = false; - dev->iamthif_ioctl = true; dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->iamthif_timer = 0; @@ -636,4 +608,3 @@ out: schedule_delayed_work(&dev->timer_work, 2 * HZ); mutex_unlock(&dev->device_lock); } - |