diff options
-rw-r--r-- | drivers/misc/mei/client.c | 2 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me.c | 59 | ||||
-rw-r--r-- | drivers/misc/mei/hw-txe.c | 13 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 11 |
4 files changed, 80 insertions, 5 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 1e99ef6a54a2..b2b9f4382d77 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
@@ -699,7 +699,7 @@ void mei_host_client_init(struct work_struct *work) | |||
699 | bool mei_hbuf_acquire(struct mei_device *dev) | 699 | bool mei_hbuf_acquire(struct mei_device *dev) |
700 | { | 700 | { |
701 | if (mei_pg_state(dev) == MEI_PG_ON || | 701 | if (mei_pg_state(dev) == MEI_PG_ON || |
702 | dev->pg_event == MEI_PG_EVENT_WAIT) { | 702 | mei_pg_in_transition(dev)) { |
703 | dev_dbg(dev->dev, "device is in pg\n"); | 703 | dev_dbg(dev->dev, "device is in pg\n"); |
704 | return false; | 704 | return false; |
705 | } | 705 | } |
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, |
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c index 7abafe7d120d..964136b35733 100644 --- a/drivers/misc/mei/hw-txe.c +++ b/drivers/misc/mei/hw-txe.c | |||
@@ -302,6 +302,18 @@ int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req) | |||
302 | } | 302 | } |
303 | 303 | ||
304 | /** | 304 | /** |
305 | * mei_txe_pg_in_transition - is device now in pg transition | ||
306 | * | ||
307 | * @dev: the device structure | ||
308 | * | ||
309 | * Return: true if in pg transition, false otherwise | ||
310 | */ | ||
311 | static bool mei_txe_pg_in_transition(struct mei_device *dev) | ||
312 | { | ||
313 | return dev->pg_event == MEI_PG_EVENT_WAIT; | ||
314 | } | ||
315 | |||
316 | /** | ||
305 | * mei_txe_pg_is_enabled - detect if PG is supported by HW | 317 | * mei_txe_pg_is_enabled - detect if PG is supported by HW |
306 | * | 318 | * |
307 | * @dev: the device structure | 319 | * @dev: the device structure |
@@ -1138,6 +1150,7 @@ static const struct mei_hw_ops mei_txe_hw_ops = { | |||
1138 | .hw_config = mei_txe_hw_config, | 1150 | .hw_config = mei_txe_hw_config, |
1139 | .hw_start = mei_txe_hw_start, | 1151 | .hw_start = mei_txe_hw_start, |
1140 | 1152 | ||
1153 | .pg_in_transition = mei_txe_pg_in_transition, | ||
1141 | .pg_is_enabled = mei_txe_pg_is_enabled, | 1154 | .pg_is_enabled = mei_txe_pg_is_enabled, |
1142 | 1155 | ||
1143 | .intr_clear = mei_txe_intr_clear, | 1156 | .intr_clear = mei_txe_intr_clear, |
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index f066ecd71939..f84c39ee28a8 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
@@ -271,6 +271,7 @@ struct mei_cl { | |||
271 | 271 | ||
272 | * @fw_status : get fw status registers | 272 | * @fw_status : get fw status registers |
273 | * @pg_state : power gating state of the device | 273 | * @pg_state : power gating state of the device |
274 | * @pg_in_transition : is device now in pg transition | ||
274 | * @pg_is_enabled : is power gating enabled | 275 | * @pg_is_enabled : is power gating enabled |
275 | 276 | ||
276 | * @intr_clear : clear pending interrupts | 277 | * @intr_clear : clear pending interrupts |
@@ -300,6 +301,7 @@ struct mei_hw_ops { | |||
300 | 301 | ||
301 | int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts); | 302 | int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts); |
302 | enum mei_pg_state (*pg_state)(struct mei_device *dev); | 303 | enum mei_pg_state (*pg_state)(struct mei_device *dev); |
304 | bool (*pg_in_transition)(struct mei_device *dev); | ||
303 | bool (*pg_is_enabled)(struct mei_device *dev); | 305 | bool (*pg_is_enabled)(struct mei_device *dev); |
304 | 306 | ||
305 | void (*intr_clear)(struct mei_device *dev); | 307 | void (*intr_clear)(struct mei_device *dev); |
@@ -398,11 +400,15 @@ struct mei_cl_device { | |||
398 | * @MEI_PG_EVENT_IDLE: the driver is not in power gating transition | 400 | * @MEI_PG_EVENT_IDLE: the driver is not in power gating transition |
399 | * @MEI_PG_EVENT_WAIT: the driver is waiting for a pg event to complete | 401 | * @MEI_PG_EVENT_WAIT: the driver is waiting for a pg event to complete |
400 | * @MEI_PG_EVENT_RECEIVED: the driver received pg event | 402 | * @MEI_PG_EVENT_RECEIVED: the driver received pg event |
403 | * @MEI_PG_EVENT_INTR_WAIT: the driver is waiting for a pg event interrupt | ||
404 | * @MEI_PG_EVENT_INTR_RECEIVED: the driver received pg event interrupt | ||
401 | */ | 405 | */ |
402 | enum mei_pg_event { | 406 | enum mei_pg_event { |
403 | MEI_PG_EVENT_IDLE, | 407 | MEI_PG_EVENT_IDLE, |
404 | MEI_PG_EVENT_WAIT, | 408 | MEI_PG_EVENT_WAIT, |
405 | MEI_PG_EVENT_RECEIVED, | 409 | MEI_PG_EVENT_RECEIVED, |
410 | MEI_PG_EVENT_INTR_WAIT, | ||
411 | MEI_PG_EVENT_INTR_RECEIVED, | ||
406 | }; | 412 | }; |
407 | 413 | ||
408 | /** | 414 | /** |
@@ -717,6 +723,11 @@ static inline enum mei_pg_state mei_pg_state(struct mei_device *dev) | |||
717 | return dev->ops->pg_state(dev); | 723 | return dev->ops->pg_state(dev); |
718 | } | 724 | } |
719 | 725 | ||
726 | static inline bool mei_pg_in_transition(struct mei_device *dev) | ||
727 | { | ||
728 | return dev->ops->pg_in_transition(dev); | ||
729 | } | ||
730 | |||
720 | static inline bool mei_pg_is_enabled(struct mei_device *dev) | 731 | static inline bool mei_pg_is_enabled(struct mei_device *dev) |
721 | { | 732 | { |
722 | return dev->ops->pg_is_enabled(dev); | 733 | return dev->ops->pg_is_enabled(dev); |