aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/mei/client.c2
-rw-r--r--drivers/misc/mei/hw-me.c59
-rw-r--r--drivers/misc/mei/hw-txe.c13
-rw-r--r--drivers/misc/mei/mei_dev.h11
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)
714bool mei_hbuf_acquire(struct mei_device *dev) 714bool 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
665reply: 665reply:
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
686out:
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 */
700static 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 */
741static 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 */
311static 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 */
353enum mei_pg_event { 357enum 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
679static inline bool mei_pg_in_transition(struct mei_device *dev)
680{
681 return dev->ops->pg_in_transition(dev);
682}
683
673static inline bool mei_pg_is_enabled(struct mei_device *dev) 684static 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);