diff options
Diffstat (limited to 'drivers/misc/mei/hw-me.c')
| -rw-r--r-- | drivers/misc/mei/hw-me.c | 59 |
1 files changed, 55 insertions, 4 deletions
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 6fb75e62a764..43d7101ff993 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c | |||
| @@ -663,11 +663,27 @@ int mei_me_pg_exit_sync(struct mei_device *dev) | |||
| 663 | mutex_lock(&dev->device_lock); | 663 | mutex_lock(&dev->device_lock); |
| 664 | 664 | ||
| 665 | reply: | 665 | reply: |
| 666 | if (dev->pg_event == MEI_PG_EVENT_RECEIVED) | 666 | if (dev->pg_event != MEI_PG_EVENT_RECEIVED) { |
| 667 | ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_EXIT_RES_CMD); | 667 | ret = -ETIME; |
| 668 | goto out; | ||
| 669 | } | ||
| 670 | |||
| 671 | dev->pg_event = MEI_PG_EVENT_INTR_WAIT; | ||
| 672 | ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_EXIT_RES_CMD); | ||
| 673 | if (ret) | ||
| 674 | return ret; | ||
| 675 | |||
| 676 | mutex_unlock(&dev->device_lock); | ||
| 677 | wait_event_timeout(dev->wait_pg, | ||
| 678 | dev->pg_event == MEI_PG_EVENT_INTR_RECEIVED, timeout); | ||
| 679 | mutex_lock(&dev->device_lock); | ||
| 680 | |||
| 681 | if (dev->pg_event == MEI_PG_EVENT_INTR_RECEIVED) | ||
| 682 | ret = 0; | ||
| 668 | else | 683 | else |
| 669 | ret = -ETIME; | 684 | ret = -ETIME; |
| 670 | 685 | ||
| 686 | out: | ||
| 671 | dev->pg_event = MEI_PG_EVENT_IDLE; | 687 | dev->pg_event = MEI_PG_EVENT_IDLE; |
| 672 | hw->pg_state = MEI_PG_OFF; | 688 | hw->pg_state = MEI_PG_OFF; |
| 673 | 689 | ||
| @@ -675,6 +691,19 @@ reply: | |||
| 675 | } | 691 | } |
| 676 | 692 | ||
| 677 | /** | 693 | /** |
| 694 | * mei_me_pg_in_transition - is device now in pg transition | ||
| 695 | * | ||
| 696 | * @dev: the device structure | ||
| 697 | * | ||
| 698 | * Return: true if in pg transition, false otherwise | ||
| 699 | */ | ||
| 700 | static bool mei_me_pg_in_transition(struct mei_device *dev) | ||
| 701 | { | ||
| 702 | return dev->pg_event >= MEI_PG_EVENT_WAIT && | ||
| 703 | dev->pg_event <= MEI_PG_EVENT_INTR_WAIT; | ||
| 704 | } | ||
| 705 | |||
| 706 | /** | ||
| 678 | * mei_me_pg_is_enabled - detect if PG is supported by HW | 707 | * mei_me_pg_is_enabled - detect if PG is supported by HW |
| 679 | * | 708 | * |
| 680 | * @dev: the device structure | 709 | * @dev: the device structure |
| @@ -705,6 +734,24 @@ notsupported: | |||
| 705 | } | 734 | } |
| 706 | 735 | ||
| 707 | /** | 736 | /** |
| 737 | * mei_me_pg_intr - perform pg processing in interrupt thread handler | ||
| 738 | * | ||
| 739 | * @dev: the device structure | ||
| 740 | */ | ||
| 741 | static void mei_me_pg_intr(struct mei_device *dev) | ||
| 742 | { | ||
| 743 | struct mei_me_hw *hw = to_me_hw(dev); | ||
| 744 | |||
| 745 | if (dev->pg_event != MEI_PG_EVENT_INTR_WAIT) | ||
| 746 | return; | ||
| 747 | |||
| 748 | dev->pg_event = MEI_PG_EVENT_INTR_RECEIVED; | ||
| 749 | hw->pg_state = MEI_PG_OFF; | ||
| 750 | if (waitqueue_active(&dev->wait_pg)) | ||
| 751 | wake_up(&dev->wait_pg); | ||
| 752 | } | ||
| 753 | |||
| 754 | /** | ||
| 708 | * mei_me_irq_quick_handler - The ISR of the MEI device | 755 | * mei_me_irq_quick_handler - The ISR of the MEI device |
| 709 | * | 756 | * |
| 710 | * @irq: The irq number | 757 | * @irq: The irq number |
| @@ -761,6 +808,8 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |||
| 761 | goto end; | 808 | goto end; |
| 762 | } | 809 | } |
| 763 | 810 | ||
| 811 | mei_me_pg_intr(dev); | ||
| 812 | |||
| 764 | /* check if we need to start the dev */ | 813 | /* check if we need to start the dev */ |
| 765 | if (!mei_host_is_ready(dev)) { | 814 | if (!mei_host_is_ready(dev)) { |
| 766 | if (mei_hw_is_ready(dev)) { | 815 | if (mei_hw_is_ready(dev)) { |
| @@ -797,9 +846,10 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |||
| 797 | /* | 846 | /* |
| 798 | * During PG handshake only allowed write is the replay to the | 847 | * During PG handshake only allowed write is the replay to the |
| 799 | * PG exit message, so block calling write function | 848 | * PG exit message, so block calling write function |
| 800 | * if the pg state is not idle | 849 | * if the pg event is in PG handshake |
| 801 | */ | 850 | */ |
| 802 | if (dev->pg_event == MEI_PG_EVENT_IDLE) { | 851 | if (dev->pg_event != MEI_PG_EVENT_WAIT && |
| 852 | dev->pg_event != MEI_PG_EVENT_RECEIVED) { | ||
| 803 | rets = mei_irq_write_handler(dev, &complete_list); | 853 | rets = mei_irq_write_handler(dev, &complete_list); |
| 804 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); | 854 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); |
| 805 | } | 855 | } |
| @@ -824,6 +874,7 @@ static const struct mei_hw_ops mei_me_hw_ops = { | |||
| 824 | .hw_config = mei_me_hw_config, | 874 | .hw_config = mei_me_hw_config, |
| 825 | .hw_start = mei_me_hw_start, | 875 | .hw_start = mei_me_hw_start, |
| 826 | 876 | ||
| 877 | .pg_in_transition = mei_me_pg_in_transition, | ||
| 827 | .pg_is_enabled = mei_me_pg_is_enabled, | 878 | .pg_is_enabled = mei_me_pg_is_enabled, |
| 828 | 879 | ||
| 829 | .intr_clear = mei_me_intr_clear, | 880 | .intr_clear = mei_me_intr_clear, |
