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 d089b136f12c..6decbe136ea7 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
@@ -714,7 +714,7 @@ void mei_host_client_init(struct work_struct *work) | |||
714 | bool mei_hbuf_acquire(struct mei_device *dev) | 714 | bool mei_hbuf_acquire(struct mei_device *dev) |
715 | { | 715 | { |
716 | if (mei_pg_state(dev) == MEI_PG_ON || | 716 | if (mei_pg_state(dev) == MEI_PG_ON || |
717 | dev->pg_event == MEI_PG_EVENT_WAIT) { | 717 | mei_pg_in_transition(dev)) { |
718 | dev_dbg(dev->dev, "device is in pg\n"); | 718 | dev_dbg(dev->dev, "device is in pg\n"); |
719 | return false; | 719 | return false; |
720 | } | 720 | } |
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 1cd223c96864..bae680c648ff 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 70a644f688b0..453f6a333b42 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
@@ -276,6 +276,7 @@ struct mei_cl { | |||
276 | 276 | ||
277 | * @fw_status : get fw status registers | 277 | * @fw_status : get fw status registers |
278 | * @pg_state : power gating state of the device | 278 | * @pg_state : power gating state of the device |
279 | * @pg_in_transition : is device now in pg transition | ||
279 | * @pg_is_enabled : is power gating enabled | 280 | * @pg_is_enabled : is power gating enabled |
280 | 281 | ||
281 | * @intr_clear : clear pending interrupts | 282 | * @intr_clear : clear pending interrupts |
@@ -305,6 +306,7 @@ struct mei_hw_ops { | |||
305 | 306 | ||
306 | int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts); | 307 | int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts); |
307 | enum mei_pg_state (*pg_state)(struct mei_device *dev); | 308 | enum mei_pg_state (*pg_state)(struct mei_device *dev); |
309 | bool (*pg_in_transition)(struct mei_device *dev); | ||
308 | bool (*pg_is_enabled)(struct mei_device *dev); | 310 | bool (*pg_is_enabled)(struct mei_device *dev); |
309 | 311 | ||
310 | void (*intr_clear)(struct mei_device *dev); | 312 | void (*intr_clear)(struct mei_device *dev); |
@@ -349,11 +351,15 @@ struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *dev, uuid_le uuid); | |||
349 | * @MEI_PG_EVENT_IDLE: the driver is not in power gating transition | 351 | * @MEI_PG_EVENT_IDLE: the driver is not in power gating transition |
350 | * @MEI_PG_EVENT_WAIT: the driver is waiting for a pg event to complete | 352 | * @MEI_PG_EVENT_WAIT: the driver is waiting for a pg event to complete |
351 | * @MEI_PG_EVENT_RECEIVED: the driver received pg event | 353 | * @MEI_PG_EVENT_RECEIVED: the driver received pg event |
354 | * @MEI_PG_EVENT_INTR_WAIT: the driver is waiting for a pg event interrupt | ||
355 | * @MEI_PG_EVENT_INTR_RECEIVED: the driver received pg event interrupt | ||
352 | */ | 356 | */ |
353 | enum mei_pg_event { | 357 | enum mei_pg_event { |
354 | MEI_PG_EVENT_IDLE, | 358 | MEI_PG_EVENT_IDLE, |
355 | MEI_PG_EVENT_WAIT, | 359 | MEI_PG_EVENT_WAIT, |
356 | MEI_PG_EVENT_RECEIVED, | 360 | MEI_PG_EVENT_RECEIVED, |
361 | MEI_PG_EVENT_INTR_WAIT, | ||
362 | MEI_PG_EVENT_INTR_RECEIVED, | ||
357 | }; | 363 | }; |
358 | 364 | ||
359 | /** | 365 | /** |
@@ -670,6 +676,11 @@ static inline enum mei_pg_state mei_pg_state(struct mei_device *dev) | |||
670 | return dev->ops->pg_state(dev); | 676 | return dev->ops->pg_state(dev); |
671 | } | 677 | } |
672 | 678 | ||
679 | static inline bool mei_pg_in_transition(struct mei_device *dev) | ||
680 | { | ||
681 | return dev->ops->pg_in_transition(dev); | ||
682 | } | ||
683 | |||
673 | static inline bool mei_pg_is_enabled(struct mei_device *dev) | 684 | static inline bool mei_pg_is_enabled(struct mei_device *dev) |
674 | { | 685 | { |
675 | return dev->ops->pg_is_enabled(dev); | 686 | return dev->ops->pg_is_enabled(dev); |