diff options
Diffstat (limited to 'drivers/misc/mei/interrupt.c')
-rw-r--r-- | drivers/misc/mei/interrupt.c | 94 |
1 files changed, 38 insertions, 56 deletions
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 64b568a..1e5cb1f 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -48,7 +48,7 @@ void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list) dev_dbg(dev->dev, "completing call back.\n"); if (cl == &dev->iamthif_cl) - mei_amthif_complete(dev, cb); + mei_amthif_complete(cl, cb); else mei_cl_complete(cl, cb); } @@ -104,6 +104,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_device *dev = cl->dev; struct mei_cl_cb *cb; unsigned char *buffer = NULL; + size_t buf_sz; cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list); if (!cb) { @@ -124,11 +125,21 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, goto out; } - if (cb->buf.size < mei_hdr->length + cb->buf_idx) { - cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n", + buf_sz = mei_hdr->length + cb->buf_idx; + /* catch for integer overflow */ + if (buf_sz < cb->buf_idx) { + cl_err(dev, cl, "message is too big len %d idx %zu\n", + mei_hdr->length, cb->buf_idx); + + list_move_tail(&cb->list, &complete_list->list); + cb->status = -EMSGSIZE; + goto out; + } + + if (cb->buf.size < buf_sz) { + cl_dbg(dev, cl, "message overflow. size %zu len %d idx %zu\n", cb->buf.size, mei_hdr->length, cb->buf_idx); - buffer = krealloc(cb->buf.data, mei_hdr->length + cb->buf_idx, - GFP_KERNEL); + buffer = krealloc(cb->buf.data, buf_sz, GFP_KERNEL); if (!buffer) { cb->status = -ENOMEM; @@ -136,7 +147,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, goto out; } cb->buf.data = buffer; - cb->buf.size = mei_hdr->length + cb->buf_idx; + cb->buf.size = buf_sz; } buffer = cb->buf.data + cb->buf_idx; @@ -145,8 +156,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, 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); + cl_dbg(dev, cl, "completed read length = %zu\n", cb->buf_idx); list_move_tail(&cb->list, &complete_list->list); } else { pm_runtime_mark_last_busy(dev->dev); @@ -229,6 +239,16 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb, return 0; } +static inline bool hdr_is_hbm(struct mei_msg_hdr *mei_hdr) +{ + return mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0; +} + +static inline bool hdr_is_fixed(struct mei_msg_hdr *mei_hdr) +{ + return mei_hdr->host_addr == 0 && mei_hdr->me_addr != 0; +} + /** * mei_irq_read_handler - bottom half read routine after ISR to * handle the read processing. @@ -270,7 +290,7 @@ int mei_irq_read_handler(struct mei_device *dev, } /* HBM message */ - if (mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0) { + if (hdr_is_hbm(mei_hdr)) { ret = mei_hbm_dispatch(dev, mei_hdr); if (ret) { dev_dbg(dev->dev, "mei_hbm_dispatch failed ret = %d\n", @@ -290,6 +310,14 @@ int mei_irq_read_handler(struct mei_device *dev, /* if no recipient cl was found we assume corrupted header */ if (&cl->link == &dev->file_list) { + /* A message for not connected fixed address clients + * should be silently discarded + */ + if (hdr_is_fixed(mei_hdr)) { + mei_irq_discard_msg(dev, mei_hdr); + ret = 0; + goto reset_slots; + } dev_err(dev->dev, "no destination client found 0x%08X\n", dev->rd_msg_hdr); ret = -EBADMSG; @@ -360,21 +388,6 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) list_move_tail(&cb->list, &cmpl_list->list); } - if (dev->wd_state == MEI_WD_STOPPING) { - dev->wd_state = MEI_WD_IDLE; - wake_up(&dev->wait_stop_wd); - } - - if (mei_cl_is_connected(&dev->wd_cl)) { - if (dev->wd_pending && - mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) { - ret = mei_wd_send(dev); - if (ret) - return ret; - dev->wd_pending = false; - } - } - /* complete control write list CB */ dev_dbg(dev->dev, "complete control write list cb.\n"); list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list.list, list) { @@ -462,7 +475,6 @@ static void mei_connect_timeout(struct mei_cl *cl) */ void mei_timer(struct work_struct *work) { - unsigned long timeout; struct mei_cl *cl; struct mei_device *dev = container_of(work, @@ -508,45 +520,15 @@ void mei_timer(struct work_struct *work) mei_reset(dev); dev->iamthif_canceled = false; dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->iamthif_timer = 0; mei_io_cb_free(dev->iamthif_current_cb); dev->iamthif_current_cb = NULL; - dev->iamthif_file_object = NULL; + dev->iamthif_fp = NULL; mei_amthif_run_next_cmd(dev); } } - if (dev->iamthif_timer) { - - timeout = dev->iamthif_timer + - mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); - - dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n", - dev->iamthif_timer); - dev_dbg(dev->dev, "timeout = %ld\n", timeout); - dev_dbg(dev->dev, "jiffies = %ld\n", jiffies); - if (time_after(jiffies, timeout)) { - /* - * User didn't read the AMTHI data on time (15sec) - * freeing AMTHI for other requests - */ - - dev_dbg(dev->dev, "freeing AMTHI for other requests\n"); - - mei_io_list_flush(&dev->amthif_rd_complete_list, - &dev->iamthif_cl); - mei_io_cb_free(dev->iamthif_current_cb); - dev->iamthif_current_cb = NULL; - - dev->iamthif_file_object->private_data = NULL; - dev->iamthif_file_object = NULL; - dev->iamthif_timer = 0; - mei_amthif_run_next_cmd(dev); - - } - } out: if (dev->dev_state != MEI_DEV_DISABLED) schedule_delayed_work(&dev->timer_work, 2 * HZ); |