diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2013-01-08 16:07:15 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-01-08 19:40:45 -0500 |
commit | 9f81abdac3629629a246fdc9e2a7c01ffd52ce8a (patch) | |
tree | 4593dab5bdf44e200efe1fa72f3badb517cc8a12 | |
parent | 90e0b5f18569bdd03c5ddd1d8c99946f42af77b8 (diff) |
mei: implement mei_cl_connect function
Implement mei_cl_connect that warps host client
parts of the connection and leave the ioctl specifics
in the mei_ioctl_connect_client function.
Move mei_ioctl_connect_client to main.c where it
belongs
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/misc/mei/client.c | 219 | ||||
-rw-r--r-- | drivers/misc/mei/main.c | 98 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 5 |
3 files changed, 163 insertions, 159 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index e300637c89ed..cc3e76c60417 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
@@ -461,6 +461,71 @@ bool mei_cl_is_other_connecting(struct mei_cl *cl) | |||
461 | } | 461 | } |
462 | 462 | ||
463 | /** | 463 | /** |
464 | * mei_cl_connect - connect host clinet to the me one | ||
465 | * | ||
466 | * @cl: host client | ||
467 | * | ||
468 | * Locking: called under "dev->device_lock" lock | ||
469 | * | ||
470 | * returns 0 on success, <0 on failure. | ||
471 | */ | ||
472 | int mei_cl_connect(struct mei_cl *cl, struct file *file) | ||
473 | { | ||
474 | struct mei_device *dev; | ||
475 | struct mei_cl_cb *cb; | ||
476 | long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT); | ||
477 | int rets; | ||
478 | |||
479 | if (WARN_ON(!cl || !cl->dev)) | ||
480 | return -ENODEV; | ||
481 | |||
482 | dev = cl->dev; | ||
483 | |||
484 | cb = mei_io_cb_init(cl, file); | ||
485 | if (!cb) { | ||
486 | rets = -ENOMEM; | ||
487 | goto out; | ||
488 | } | ||
489 | |||
490 | cb->fop_type = MEI_FOP_IOCTL; | ||
491 | |||
492 | if (dev->mei_host_buffer_is_empty && | ||
493 | !mei_cl_is_other_connecting(cl)) { | ||
494 | dev->mei_host_buffer_is_empty = false; | ||
495 | |||
496 | if (mei_hbm_cl_connect_req(dev, cl)) { | ||
497 | rets = -ENODEV; | ||
498 | goto out; | ||
499 | } | ||
500 | cl->timer_count = MEI_CONNECT_TIMEOUT; | ||
501 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); | ||
502 | } else { | ||
503 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | ||
504 | } | ||
505 | |||
506 | mutex_unlock(&dev->device_lock); | ||
507 | rets = wait_event_timeout(dev->wait_recvd_msg, | ||
508 | (cl->state == MEI_FILE_CONNECTED || | ||
509 | cl->state == MEI_FILE_DISCONNECTED), | ||
510 | timeout * HZ); | ||
511 | mutex_lock(&dev->device_lock); | ||
512 | |||
513 | if (cl->state != MEI_FILE_CONNECTED) { | ||
514 | rets = -EFAULT; | ||
515 | |||
516 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | ||
517 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | ||
518 | goto out; | ||
519 | } | ||
520 | |||
521 | rets = cl->status; | ||
522 | |||
523 | out: | ||
524 | mei_io_cb_free(cb); | ||
525 | return rets; | ||
526 | } | ||
527 | |||
528 | /** | ||
464 | * mei_cl_flow_ctrl_creds - checks flow_control credits for cl. | 529 | * mei_cl_flow_ctrl_creds - checks flow_control credits for cl. |
465 | * | 530 | * |
466 | * @dev: the device structure | 531 | * @dev: the device structure |
@@ -542,160 +607,6 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl) | |||
542 | return -ENOENT; | 607 | return -ENOENT; |
543 | } | 608 | } |
544 | 609 | ||
545 | |||
546 | |||
547 | /** | ||
548 | * mei_ioctl_connect_client - the connect to fw client IOCTL function | ||
549 | * | ||
550 | * @dev: the device structure | ||
551 | * @data: IOCTL connect data, input and output parameters | ||
552 | * @file: private data of the file object | ||
553 | * | ||
554 | * Locking: called under "dev->device_lock" lock | ||
555 | * | ||
556 | * returns 0 on success, <0 on failure. | ||
557 | */ | ||
558 | int mei_ioctl_connect_client(struct file *file, | ||
559 | struct mei_connect_client_data *data) | ||
560 | { | ||
561 | struct mei_device *dev; | ||
562 | struct mei_cl_cb *cb; | ||
563 | struct mei_client *client; | ||
564 | struct mei_cl *cl; | ||
565 | long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT); | ||
566 | int i; | ||
567 | int err; | ||
568 | int rets; | ||
569 | |||
570 | cl = file->private_data; | ||
571 | if (WARN_ON(!cl || !cl->dev)) | ||
572 | return -ENODEV; | ||
573 | |||
574 | dev = cl->dev; | ||
575 | |||
576 | dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n"); | ||
577 | |||
578 | /* buffered ioctl cb */ | ||
579 | cb = mei_io_cb_init(cl, file); | ||
580 | if (!cb) { | ||
581 | rets = -ENOMEM; | ||
582 | goto end; | ||
583 | } | ||
584 | |||
585 | cb->fop_type = MEI_FOP_IOCTL; | ||
586 | |||
587 | if (dev->dev_state != MEI_DEV_ENABLED) { | ||
588 | rets = -ENODEV; | ||
589 | goto end; | ||
590 | } | ||
591 | if (cl->state != MEI_FILE_INITIALIZING && | ||
592 | cl->state != MEI_FILE_DISCONNECTED) { | ||
593 | rets = -EBUSY; | ||
594 | goto end; | ||
595 | } | ||
596 | |||
597 | /* find ME client we're trying to connect to */ | ||
598 | i = mei_me_cl_by_uuid(dev, &data->in_client_uuid); | ||
599 | if (i >= 0 && !dev->me_clients[i].props.fixed_address) { | ||
600 | cl->me_client_id = dev->me_clients[i].client_id; | ||
601 | cl->state = MEI_FILE_CONNECTING; | ||
602 | } | ||
603 | |||
604 | dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n", | ||
605 | cl->me_client_id); | ||
606 | dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n", | ||
607 | dev->me_clients[i].props.protocol_version); | ||
608 | dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n", | ||
609 | dev->me_clients[i].props.max_msg_length); | ||
610 | |||
611 | /* if we're connecting to amthi client then we will use the | ||
612 | * existing connection | ||
613 | */ | ||
614 | if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) { | ||
615 | dev_dbg(&dev->pdev->dev, "FW Client is amthi\n"); | ||
616 | if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { | ||
617 | rets = -ENODEV; | ||
618 | goto end; | ||
619 | } | ||
620 | clear_bit(cl->host_client_id, dev->host_clients_map); | ||
621 | mei_cl_unlink(cl); | ||
622 | |||
623 | kfree(cl); | ||
624 | cl = NULL; | ||
625 | file->private_data = &dev->iamthif_cl; | ||
626 | |||
627 | client = &data->out_client_properties; | ||
628 | client->max_msg_length = | ||
629 | dev->me_clients[i].props.max_msg_length; | ||
630 | client->protocol_version = | ||
631 | dev->me_clients[i].props.protocol_version; | ||
632 | rets = dev->iamthif_cl.status; | ||
633 | |||
634 | goto end; | ||
635 | } | ||
636 | |||
637 | if (cl->state != MEI_FILE_CONNECTING) { | ||
638 | rets = -ENODEV; | ||
639 | goto end; | ||
640 | } | ||
641 | |||
642 | |||
643 | /* prepare the output buffer */ | ||
644 | client = &data->out_client_properties; | ||
645 | client->max_msg_length = dev->me_clients[i].props.max_msg_length; | ||
646 | client->protocol_version = dev->me_clients[i].props.protocol_version; | ||
647 | dev_dbg(&dev->pdev->dev, "Can connect?\n"); | ||
648 | if (dev->mei_host_buffer_is_empty && | ||
649 | !mei_cl_is_other_connecting(cl)) { | ||
650 | dev_dbg(&dev->pdev->dev, "Sending Connect Message\n"); | ||
651 | dev->mei_host_buffer_is_empty = false; | ||
652 | if (mei_hbm_cl_connect_req(dev, cl)) { | ||
653 | dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n"); | ||
654 | rets = -ENODEV; | ||
655 | goto end; | ||
656 | } else { | ||
657 | dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n"); | ||
658 | cl->timer_count = MEI_CONNECT_TIMEOUT; | ||
659 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); | ||
660 | } | ||
661 | |||
662 | |||
663 | } else { | ||
664 | dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n"); | ||
665 | dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n"); | ||
666 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | ||
667 | } | ||
668 | mutex_unlock(&dev->device_lock); | ||
669 | err = wait_event_timeout(dev->wait_recvd_msg, | ||
670 | (MEI_FILE_CONNECTED == cl->state || | ||
671 | MEI_FILE_DISCONNECTED == cl->state), timeout); | ||
672 | |||
673 | mutex_lock(&dev->device_lock); | ||
674 | if (MEI_FILE_CONNECTED == cl->state) { | ||
675 | dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n"); | ||
676 | rets = cl->status; | ||
677 | goto end; | ||
678 | } else { | ||
679 | dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n", | ||
680 | cl->state); | ||
681 | if (!err) { | ||
682 | dev_dbg(&dev->pdev->dev, | ||
683 | "wait_event_interruptible_timeout failed on client" | ||
684 | " connect message fw response message.\n"); | ||
685 | } | ||
686 | rets = -EFAULT; | ||
687 | |||
688 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | ||
689 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | ||
690 | goto end; | ||
691 | } | ||
692 | rets = 0; | ||
693 | end: | ||
694 | dev_dbg(&dev->pdev->dev, "free connect cb memory."); | ||
695 | mei_io_cb_free(cb); | ||
696 | return rets; | ||
697 | } | ||
698 | |||
699 | /** | 610 | /** |
700 | * mei_cl_start_read - the start read client message function. | 611 | * mei_cl_start_read - the start read client message function. |
701 | * | 612 | * |
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 95f05d97a115..8d3c134314c6 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -562,6 +562,103 @@ err: | |||
562 | return rets; | 562 | return rets; |
563 | } | 563 | } |
564 | 564 | ||
565 | /** | ||
566 | * mei_ioctl_connect_client - the connect to fw client IOCTL function | ||
567 | * | ||
568 | * @dev: the device structure | ||
569 | * @data: IOCTL connect data, input and output parameters | ||
570 | * @file: private data of the file object | ||
571 | * | ||
572 | * Locking: called under "dev->device_lock" lock | ||
573 | * | ||
574 | * returns 0 on success, <0 on failure. | ||
575 | */ | ||
576 | static int mei_ioctl_connect_client(struct file *file, | ||
577 | struct mei_connect_client_data *data) | ||
578 | { | ||
579 | struct mei_device *dev; | ||
580 | struct mei_client *client; | ||
581 | struct mei_cl *cl; | ||
582 | int i; | ||
583 | int rets; | ||
584 | |||
585 | cl = file->private_data; | ||
586 | if (WARN_ON(!cl || !cl->dev)) | ||
587 | return -ENODEV; | ||
588 | |||
589 | dev = cl->dev; | ||
590 | |||
591 | if (dev->dev_state != MEI_DEV_ENABLED) { | ||
592 | rets = -ENODEV; | ||
593 | goto end; | ||
594 | } | ||
595 | |||
596 | if (cl->state != MEI_FILE_INITIALIZING && | ||
597 | cl->state != MEI_FILE_DISCONNECTED) { | ||
598 | rets = -EBUSY; | ||
599 | goto end; | ||
600 | } | ||
601 | |||
602 | /* find ME client we're trying to connect to */ | ||
603 | i = mei_me_cl_by_uuid(dev, &data->in_client_uuid); | ||
604 | if (i >= 0 && !dev->me_clients[i].props.fixed_address) { | ||
605 | cl->me_client_id = dev->me_clients[i].client_id; | ||
606 | cl->state = MEI_FILE_CONNECTING; | ||
607 | } | ||
608 | |||
609 | dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n", | ||
610 | cl->me_client_id); | ||
611 | dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n", | ||
612 | dev->me_clients[i].props.protocol_version); | ||
613 | dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n", | ||
614 | dev->me_clients[i].props.max_msg_length); | ||
615 | |||
616 | /* if we're connecting to amthi client then we will use the | ||
617 | * existing connection | ||
618 | */ | ||
619 | if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) { | ||
620 | dev_dbg(&dev->pdev->dev, "FW Client is amthi\n"); | ||
621 | if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { | ||
622 | rets = -ENODEV; | ||
623 | goto end; | ||
624 | } | ||
625 | clear_bit(cl->host_client_id, dev->host_clients_map); | ||
626 | mei_cl_unlink(cl); | ||
627 | |||
628 | kfree(cl); | ||
629 | cl = NULL; | ||
630 | file->private_data = &dev->iamthif_cl; | ||
631 | |||
632 | client = &data->out_client_properties; | ||
633 | client->max_msg_length = | ||
634 | dev->me_clients[i].props.max_msg_length; | ||
635 | client->protocol_version = | ||
636 | dev->me_clients[i].props.protocol_version; | ||
637 | rets = dev->iamthif_cl.status; | ||
638 | |||
639 | goto end; | ||
640 | } | ||
641 | |||
642 | if (cl->state != MEI_FILE_CONNECTING) { | ||
643 | rets = -ENODEV; | ||
644 | goto end; | ||
645 | } | ||
646 | |||
647 | |||
648 | /* prepare the output buffer */ | ||
649 | client = &data->out_client_properties; | ||
650 | client->max_msg_length = dev->me_clients[i].props.max_msg_length; | ||
651 | client->protocol_version = dev->me_clients[i].props.protocol_version; | ||
652 | dev_dbg(&dev->pdev->dev, "Can connect?\n"); | ||
653 | |||
654 | |||
655 | rets = mei_cl_connect(cl, file); | ||
656 | |||
657 | end: | ||
658 | dev_dbg(&dev->pdev->dev, "free connect cb memory."); | ||
659 | return rets; | ||
660 | } | ||
661 | |||
565 | 662 | ||
566 | /** | 663 | /** |
567 | * mei_ioctl - the IOCTL function | 664 | * mei_ioctl - the IOCTL function |
@@ -610,6 +707,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) | |||
610 | rets = -EFAULT; | 707 | rets = -EFAULT; |
611 | goto out; | 708 | goto out; |
612 | } | 709 | } |
710 | |||
613 | rets = mei_ioctl_connect_client(file, connect_data); | 711 | rets = mei_ioctl_connect_client(file, connect_data); |
614 | 712 | ||
615 | /* if all is ok, copying the data back to user. */ | 713 | /* if all is ok, copying the data back to user. */ |
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 5a1ac9a37e10..f3da1533c619 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
@@ -341,11 +341,6 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id); | |||
341 | void mei_timer(struct work_struct *work); | 341 | void mei_timer(struct work_struct *work); |
342 | 342 | ||
343 | /* | 343 | /* |
344 | * MEI input output function prototype | ||
345 | */ | ||
346 | int mei_ioctl_connect_client(struct file *file, | ||
347 | struct mei_connect_client_data *data); | ||
348 | /* | ||
349 | * AMTHIF - AMT Host Interface Functions | 344 | * AMTHIF - AMT Host Interface Functions |
350 | */ | 345 | */ |
351 | void mei_amthif_reset_params(struct mei_device *dev); | 346 | void mei_amthif_reset_params(struct mei_device *dev); |