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 | /** | ||
