diff options
Diffstat (limited to 'drivers/misc/mei/client.c')
-rw-r--r-- | drivers/misc/mei/client.c | 129 |
1 files changed, 77 insertions, 52 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index e0684b4d9a0..87c96e4669e 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -187,10 +187,14 @@ int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) */ int mei_cl_flush_queues(struct mei_cl *cl) { + struct mei_device *dev; + if (WARN_ON(!cl || !cl->dev)) return -EINVAL; - dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n"); + dev = cl->dev; + + cl_dbg(dev, cl, "remove list entry belonging to cl\n"); mei_io_list_flush(&cl->dev->read_list, cl); mei_io_list_flush(&cl->dev->write_list, cl); mei_io_list_flush(&cl->dev->write_waiting_list, cl); @@ -271,6 +275,7 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl) int mei_cl_link(struct mei_cl *cl, int id) { struct mei_device *dev; + long open_handle_count; if (WARN_ON(!cl || !cl->dev)) return -EINVAL; @@ -284,7 +289,14 @@ int mei_cl_link(struct mei_cl *cl, int id) if (id >= MEI_CLIENTS_MAX) { dev_err(&dev->pdev->dev, "id exceded %d", MEI_CLIENTS_MAX) ; - return -ENOENT; + return -EMFILE; + } + + open_handle_count = dev->open_handle_count + dev->iamthif_open_count; + if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { + dev_err(&dev->pdev->dev, "open_handle_count exceded %d", + MEI_MAX_OPEN_HANDLE_COUNT); + return -EMFILE; } dev->open_handle_count++; @@ -296,7 +308,7 @@ int mei_cl_link(struct mei_cl *cl, int id) cl->state = MEI_FILE_INITIALIZING; - dev_dbg(&dev->pdev->dev, "link cl host id = %d\n", cl->host_client_id); + cl_dbg(dev, cl, "link cl\n"); return 0; } @@ -308,7 +320,6 @@ int mei_cl_link(struct mei_cl *cl, int id) int mei_cl_unlink(struct mei_cl *cl) { struct mei_device *dev; - struct mei_cl *pos, *next; /* don't shout on error exit path */ if (!cl) @@ -320,14 +331,21 @@ int mei_cl_unlink(struct mei_cl *cl) dev = cl->dev; - list_for_each_entry_safe(pos, next, &dev->file_list, link) { - if (cl->host_client_id == pos->host_client_id) { - dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", - pos->host_client_id, pos->me_client_id); - list_del_init(&pos->link); - break; - } - } + cl_dbg(dev, cl, "unlink client"); + + if (dev->open_handle_count > 0) + dev->open_handle_count--; + + /* never clear the 0 bit */ + if (cl->host_client_id) + clear_bit(cl->host_client_id, dev->host_clients_map); + + list_del_init(&cl->link); + + cl->state = MEI_FILE_INITIALIZING; + + list_del_init(&cl->link); + return 0; } @@ -341,17 +359,6 @@ void mei_host_client_init(struct work_struct *work) mutex_lock(&dev->device_lock); - bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); - dev->open_handle_count = 0; - - /* - * Reserving the first three client IDs - * 0: Reserved for MEI Bus Message communications - * 1: Reserved for Watchdog - * 2: Reserved for AMTHI - */ - bitmap_set(dev->host_clients_map, 0, 3); - for (i = 0; i < dev->me_clients_num; i++) { client_props = &dev->me_clients[i].props; @@ -390,6 +397,8 @@ int mei_cl_disconnect(struct mei_cl *cl) dev = cl->dev; + cl_dbg(dev, cl, "disconnecting"); + if (cl->state != MEI_FILE_DISCONNECTING) return 0; @@ -402,13 +411,13 @@ int mei_cl_disconnect(struct mei_cl *cl) dev->hbuf_is_ready = false; if (mei_hbm_cl_disconnect_req(dev, cl)) { rets = -ENODEV; - dev_err(&dev->pdev->dev, "failed to disconnect.\n"); + cl_err(dev, cl, "failed to disconnect.\n"); goto free; } mdelay(10); /* Wait for hardware disconnection ready */ list_add_tail(&cb->list, &dev->ctrl_rd_list.list); } else { - dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); + cl_dbg(dev, cl, "add disconnect cb to control write list\n"); list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } @@ -421,18 +430,17 @@ int mei_cl_disconnect(struct mei_cl *cl) mutex_lock(&dev->device_lock); if (MEI_FILE_DISCONNECTED == cl->state) { rets = 0; - dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); + cl_dbg(dev, cl, "successfully disconnected from FW client.\n"); } else { rets = -ENODEV; if (MEI_FILE_DISCONNECTED != cl->state) - dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); + cl_err(dev, cl, "wrong status client disconnect.\n"); if (err) - dev_dbg(&dev->pdev->dev, - "wait failed disconnect err=%08x\n", + cl_dbg(dev, cl, "wait failed disconnect err=%08x\n", err); - dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); + cl_err(dev, cl, "failed to disconnect from FW client.\n"); } mei_io_list_flush(&dev->ctrl_rd_list, cl); @@ -639,13 +647,12 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) return -ENODEV; if (cl->read_cb) { - dev_dbg(&dev->pdev->dev, "read is pending.\n"); + cl_dbg(dev, cl, "read is pending.\n"); return -EBUSY; } i = mei_me_cl_by_id(dev, cl->me_client_id); if (i < 0) { - dev_err(&dev->pdev->dev, "no such me client %d\n", - cl->me_client_id); + cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); return -ENODEV; } @@ -664,6 +671,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) if (dev->hbuf_is_ready) { dev->hbuf_is_ready = false; if (mei_hbm_cl_flow_control_req(dev, cl)) { + cl_err(dev, cl, "flow control send failed\n"); rets = -ENODEV; goto err; } @@ -691,10 +699,32 @@ err: int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, s32 *slots, struct mei_cl_cb *cmpl_list) { - struct mei_device *dev = cl->dev; + struct mei_device *dev; + struct mei_msg_data *buf; struct mei_msg_hdr mei_hdr; - size_t len = cb->request_buffer.size - cb->buf_idx; - u32 msg_slots = mei_data2slots(len); + size_t len; + u32 msg_slots; + int rets; + + + if (WARN_ON(!cl || !cl->dev)) + return -ENODEV; + + dev = cl->dev; + + buf = &cb->request_buffer; + + rets = mei_cl_flow_ctrl_creds(cl); + if (rets < 0) + return rets; + + if (rets == 0) { + cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); + return 0; + } + + len = buf->size - cb->buf_idx; + msg_slots = mei_data2slots(len); mei_hdr.host_addr = cl->host_client_id; mei_hdr.me_addr = cl->me_client_id; @@ -714,16 +744,15 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, return 0; } - dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n", + cl_dbg(dev, cl, "buf: size = %d idx = %lu\n", cb->request_buffer.size, cb->buf_idx); - dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr)); *slots -= msg_slots; - if (mei_write_message(dev, &mei_hdr, - cb->request_buffer.data + cb->buf_idx)) { - cl->status = -ENODEV; + rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx); + if (rets) { + cl->status = rets; list_move_tail(&cb->list, &cmpl_list->list); - return -ENODEV; + return rets; } cl->status = 0; @@ -732,7 +761,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, if (mei_hdr.msg_complete) { if (mei_cl_flow_ctrl_reduce(cl)) - return -ENODEV; + return -EIO; list_move_tail(&cb->list, &dev->write_waiting_list.list); } @@ -767,7 +796,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) buf = &cb->request_buffer; - dev_dbg(&dev->pdev->dev, "mei_cl_write %d\n", buf->size); + cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size); cb->fop_type = MEI_FOP_WRITE; @@ -800,14 +829,10 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) mei_hdr.me_addr = cl->me_client_id; mei_hdr.reserved = 0; - dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n", - MEI_HDR_PRM(&mei_hdr)); - - if (mei_write_message(dev, &mei_hdr, buf->data)) { - rets = -EIO; + rets = mei_write_message(dev, &mei_hdr, buf->data); + if (rets) goto err; - } cl->writing_state = MEI_WRITING; cb->buf_idx = mei_hdr.length; @@ -898,11 +923,11 @@ void mei_cl_all_wakeup(struct mei_device *dev) struct mei_cl *cl, *next; list_for_each_entry_safe(cl, next, &dev->file_list, link) { if (waitqueue_active(&cl->rx_wait)) { - dev_dbg(&dev->pdev->dev, "Waking up reading client!\n"); + cl_dbg(dev, cl, "Waking up reading client!\n"); wake_up_interruptible(&cl->rx_wait); } if (waitqueue_active(&cl->tx_wait)) { - dev_dbg(&dev->pdev->dev, "Waking up writing client!\n"); + cl_dbg(dev, cl, "Waking up writing client!\n"); wake_up_interruptible(&cl->tx_wait); } } |