diff options
Diffstat (limited to 'drivers/misc/mei/client.c')
-rw-r--r-- | drivers/misc/mei/client.c | 103 |
1 files changed, 63 insertions, 40 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index e0684b4d9a08..fbd319c506e6 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) | |||
187 | */ | 187 | */ |
188 | int mei_cl_flush_queues(struct mei_cl *cl) | 188 | int mei_cl_flush_queues(struct mei_cl *cl) |
189 | { | 189 | { |
190 | struct mei_device *dev; | ||
191 | |||
190 | if (WARN_ON(!cl || !cl->dev)) | 192 | if (WARN_ON(!cl || !cl->dev)) |
191 | return -EINVAL; | 193 | return -EINVAL; |
192 | 194 | ||
193 | dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n"); | 195 | dev = cl->dev; |
196 | |||
197 | cl_dbg(dev, cl, "remove list entry belonging to cl\n"); | ||
194 | mei_io_list_flush(&cl->dev->read_list, cl); | 198 | mei_io_list_flush(&cl->dev->read_list, cl); |
195 | mei_io_list_flush(&cl->dev->write_list, cl); | 199 | mei_io_list_flush(&cl->dev->write_list, cl); |
196 | mei_io_list_flush(&cl->dev->write_waiting_list, cl); | 200 | mei_io_list_flush(&cl->dev->write_waiting_list, cl); |
@@ -287,6 +291,12 @@ int mei_cl_link(struct mei_cl *cl, int id) | |||
287 | return -ENOENT; | 291 | return -ENOENT; |
288 | } | 292 | } |
289 | 293 | ||
294 | if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { | ||
295 | dev_err(&dev->pdev->dev, "open_handle_count exceded %d", | ||
296 | MEI_MAX_OPEN_HANDLE_COUNT); | ||
297 | return -ENOENT; | ||
298 | } | ||
299 | |||
290 | dev->open_handle_count++; | 300 | dev->open_handle_count++; |
291 | 301 | ||
292 | cl->host_client_id = id; | 302 | cl->host_client_id = id; |
@@ -296,7 +306,7 @@ int mei_cl_link(struct mei_cl *cl, int id) | |||
296 | 306 | ||
297 | cl->state = MEI_FILE_INITIALIZING; | 307 | cl->state = MEI_FILE_INITIALIZING; |
298 | 308 | ||
299 | dev_dbg(&dev->pdev->dev, "link cl host id = %d\n", cl->host_client_id); | 309 | cl_dbg(dev, cl, "link cl\n"); |
300 | return 0; | 310 | return 0; |
301 | } | 311 | } |
302 | 312 | ||
@@ -308,7 +318,6 @@ int mei_cl_link(struct mei_cl *cl, int id) | |||
308 | int mei_cl_unlink(struct mei_cl *cl) | 318 | int mei_cl_unlink(struct mei_cl *cl) |
309 | { | 319 | { |
310 | struct mei_device *dev; | 320 | struct mei_device *dev; |
311 | struct mei_cl *pos, *next; | ||
312 | 321 | ||
313 | /* don't shout on error exit path */ | 322 | /* don't shout on error exit path */ |
314 | if (!cl) | 323 | if (!cl) |
@@ -320,14 +329,10 @@ int mei_cl_unlink(struct mei_cl *cl) | |||
320 | 329 | ||
321 | dev = cl->dev; | 330 | dev = cl->dev; |
322 | 331 | ||
323 | list_for_each_entry_safe(pos, next, &dev->file_list, link) { | 332 | cl_dbg(dev, cl, "unlink client"); |
324 | if (cl->host_client_id == pos->host_client_id) { | 333 | |
325 | dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", | 334 | list_del_init(&cl->link); |
326 | pos->host_client_id, pos->me_client_id); | 335 | |
327 | list_del_init(&pos->link); | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | return 0; | 336 | return 0; |
332 | } | 337 | } |
333 | 338 | ||
@@ -390,6 +395,8 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
390 | 395 | ||
391 | dev = cl->dev; | 396 | dev = cl->dev; |
392 | 397 | ||
398 | cl_dbg(dev, cl, "disconnecting"); | ||
399 | |||
393 | if (cl->state != MEI_FILE_DISCONNECTING) | 400 | if (cl->state != MEI_FILE_DISCONNECTING) |
394 | return 0; | 401 | return 0; |
395 | 402 | ||
@@ -402,13 +409,13 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
402 | dev->hbuf_is_ready = false; | 409 | dev->hbuf_is_ready = false; |
403 | if (mei_hbm_cl_disconnect_req(dev, cl)) { | 410 | if (mei_hbm_cl_disconnect_req(dev, cl)) { |
404 | rets = -ENODEV; | 411 | rets = -ENODEV; |
405 | dev_err(&dev->pdev->dev, "failed to disconnect.\n"); | 412 | cl_err(dev, cl, "failed to disconnect.\n"); |
406 | goto free; | 413 | goto free; |
407 | } | 414 | } |
408 | mdelay(10); /* Wait for hardware disconnection ready */ | 415 | mdelay(10); /* Wait for hardware disconnection ready */ |
409 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); | 416 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); |
410 | } else { | 417 | } else { |
411 | dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); | 418 | cl_dbg(dev, cl, "add disconnect cb to control write list\n"); |
412 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | 419 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); |
413 | 420 | ||
414 | } | 421 | } |
@@ -421,18 +428,17 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
421 | mutex_lock(&dev->device_lock); | 428 | mutex_lock(&dev->device_lock); |
422 | if (MEI_FILE_DISCONNECTED == cl->state) { | 429 | if (MEI_FILE_DISCONNECTED == cl->state) { |
423 | rets = 0; | 430 | rets = 0; |
424 | dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); | 431 | cl_dbg(dev, cl, "successfully disconnected from FW client.\n"); |
425 | } else { | 432 | } else { |
426 | rets = -ENODEV; | 433 | rets = -ENODEV; |
427 | if (MEI_FILE_DISCONNECTED != cl->state) | 434 | if (MEI_FILE_DISCONNECTED != cl->state) |
428 | dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); | 435 | cl_err(dev, cl, "wrong status client disconnect.\n"); |
429 | 436 | ||
430 | if (err) | 437 | if (err) |
431 | dev_dbg(&dev->pdev->dev, | 438 | cl_dbg(dev, cl, "wait failed disconnect err=%08x\n", |
432 | "wait failed disconnect err=%08x\n", | ||
433 | err); | 439 | err); |
434 | 440 | ||
435 | dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); | 441 | cl_err(dev, cl, "failed to disconnect from FW client.\n"); |
436 | } | 442 | } |
437 | 443 | ||
438 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 444 | mei_io_list_flush(&dev->ctrl_rd_list, cl); |
@@ -639,13 +645,12 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) | |||
639 | return -ENODEV; | 645 | return -ENODEV; |
640 | 646 | ||
641 | if (cl->read_cb) { | 647 | if (cl->read_cb) { |
642 | dev_dbg(&dev->pdev->dev, "read is pending.\n"); | 648 | cl_dbg(dev, cl, "read is pending.\n"); |
643 | return -EBUSY; | 649 | return -EBUSY; |
644 | } | 650 | } |
645 | i = mei_me_cl_by_id(dev, cl->me_client_id); | 651 | i = mei_me_cl_by_id(dev, cl->me_client_id); |
646 | if (i < 0) { | 652 | if (i < 0) { |
647 | dev_err(&dev->pdev->dev, "no such me client %d\n", | 653 | cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); |
648 | cl->me_client_id); | ||
649 | return -ENODEV; | 654 | return -ENODEV; |
650 | } | 655 | } |
651 | 656 | ||
@@ -664,6 +669,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) | |||
664 | if (dev->hbuf_is_ready) { | 669 | if (dev->hbuf_is_ready) { |
665 | dev->hbuf_is_ready = false; | 670 | dev->hbuf_is_ready = false; |
666 | if (mei_hbm_cl_flow_control_req(dev, cl)) { | 671 | if (mei_hbm_cl_flow_control_req(dev, cl)) { |
672 | cl_err(dev, cl, "flow control send failed\n"); | ||
667 | rets = -ENODEV; | 673 | rets = -ENODEV; |
668 | goto err; | 674 | goto err; |
669 | } | 675 | } |
@@ -691,10 +697,32 @@ err: | |||
691 | int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | 697 | int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, |
692 | s32 *slots, struct mei_cl_cb *cmpl_list) | 698 | s32 *slots, struct mei_cl_cb *cmpl_list) |
693 | { | 699 | { |
694 | struct mei_device *dev = cl->dev; | 700 | struct mei_device *dev; |
701 | struct mei_msg_data *buf; | ||
695 | struct mei_msg_hdr mei_hdr; | 702 | struct mei_msg_hdr mei_hdr; |
696 | size_t len = cb->request_buffer.size - cb->buf_idx; | 703 | size_t len; |
697 | u32 msg_slots = mei_data2slots(len); | 704 | u32 msg_slots; |
705 | int rets; | ||
706 | |||
707 | |||
708 | if (WARN_ON(!cl || !cl->dev)) | ||
709 | return -ENODEV; | ||
710 | |||
711 | dev = cl->dev; | ||
712 | |||
713 | buf = &cb->request_buffer; | ||
714 | |||
715 | rets = mei_cl_flow_ctrl_creds(cl); | ||
716 | if (rets < 0) | ||
717 | return rets; | ||
718 | |||
719 | if (rets == 0) { | ||
720 | cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); | ||
721 | return 0; | ||
722 | } | ||
723 | |||
724 | len = buf->size - cb->buf_idx; | ||
725 | msg_slots = mei_data2slots(len); | ||
698 | 726 | ||
699 | mei_hdr.host_addr = cl->host_client_id; | 727 | mei_hdr.host_addr = cl->host_client_id; |
700 | mei_hdr.me_addr = cl->me_client_id; | 728 | mei_hdr.me_addr = cl->me_client_id; |
@@ -714,16 +742,15 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
714 | return 0; | 742 | return 0; |
715 | } | 743 | } |
716 | 744 | ||
717 | dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n", | 745 | cl_dbg(dev, cl, "buf: size = %d idx = %lu\n", |
718 | cb->request_buffer.size, cb->buf_idx); | 746 | cb->request_buffer.size, cb->buf_idx); |
719 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr)); | ||
720 | 747 | ||
721 | *slots -= msg_slots; | 748 | *slots -= msg_slots; |
722 | if (mei_write_message(dev, &mei_hdr, | 749 | rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx); |
723 | cb->request_buffer.data + cb->buf_idx)) { | 750 | if (rets) { |
724 | cl->status = -ENODEV; | 751 | cl->status = rets; |
725 | list_move_tail(&cb->list, &cmpl_list->list); | 752 | list_move_tail(&cb->list, &cmpl_list->list); |
726 | return -ENODEV; | 753 | return rets; |
727 | } | 754 | } |
728 | 755 | ||
729 | cl->status = 0; | 756 | cl->status = 0; |
@@ -732,7 +759,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
732 | 759 | ||
733 | if (mei_hdr.msg_complete) { | 760 | if (mei_hdr.msg_complete) { |
734 | if (mei_cl_flow_ctrl_reduce(cl)) | 761 | if (mei_cl_flow_ctrl_reduce(cl)) |
735 | return -ENODEV; | 762 | return -EIO; |
736 | list_move_tail(&cb->list, &dev->write_waiting_list.list); | 763 | list_move_tail(&cb->list, &dev->write_waiting_list.list); |
737 | } | 764 | } |
738 | 765 | ||
@@ -767,7 +794,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) | |||
767 | 794 | ||
768 | buf = &cb->request_buffer; | 795 | buf = &cb->request_buffer; |
769 | 796 | ||
770 | dev_dbg(&dev->pdev->dev, "mei_cl_write %d\n", buf->size); | 797 | cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size); |
771 | 798 | ||
772 | 799 | ||
773 | cb->fop_type = MEI_FOP_WRITE; | 800 | cb->fop_type = MEI_FOP_WRITE; |
@@ -800,14 +827,10 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) | |||
800 | mei_hdr.me_addr = cl->me_client_id; | 827 | mei_hdr.me_addr = cl->me_client_id; |
801 | mei_hdr.reserved = 0; | 828 | mei_hdr.reserved = 0; |
802 | 829 | ||
803 | dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n", | ||
804 | MEI_HDR_PRM(&mei_hdr)); | ||
805 | |||
806 | 830 | ||
807 | if (mei_write_message(dev, &mei_hdr, buf->data)) { | 831 | rets = mei_write_message(dev, &mei_hdr, buf->data); |
808 | rets = -EIO; | 832 | if (rets) |
809 | goto err; | 833 | goto err; |
810 | } | ||
811 | 834 | ||
812 | cl->writing_state = MEI_WRITING; | 835 | cl->writing_state = MEI_WRITING; |
813 | cb->buf_idx = mei_hdr.length; | 836 | cb->buf_idx = mei_hdr.length; |
@@ -898,11 +921,11 @@ void mei_cl_all_wakeup(struct mei_device *dev) | |||
898 | struct mei_cl *cl, *next; | 921 | struct mei_cl *cl, *next; |
899 | list_for_each_entry_safe(cl, next, &dev->file_list, link) { | 922 | list_for_each_entry_safe(cl, next, &dev->file_list, link) { |
900 | if (waitqueue_active(&cl->rx_wait)) { | 923 | if (waitqueue_active(&cl->rx_wait)) { |
901 | dev_dbg(&dev->pdev->dev, "Waking up reading client!\n"); | 924 | cl_dbg(dev, cl, "Waking up reading client!\n"); |
902 | wake_up_interruptible(&cl->rx_wait); | 925 | wake_up_interruptible(&cl->rx_wait); |
903 | } | 926 | } |
904 | if (waitqueue_active(&cl->tx_wait)) { | 927 | if (waitqueue_active(&cl->tx_wait)) { |
905 | dev_dbg(&dev->pdev->dev, "Waking up writing client!\n"); | 928 | cl_dbg(dev, cl, "Waking up writing client!\n"); |
906 | wake_up_interruptible(&cl->tx_wait); | 929 | wake_up_interruptible(&cl->tx_wait); |
907 | } | 930 | } |
908 | } | 931 | } |