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 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)
699bool mei_hbuf_acquire(struct mei_device *dev) 699bool 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
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 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 */
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 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 */
402enum mei_pg_event { 406enum 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
726static inline bool mei_pg_in_transition(struct mei_device *dev)
727{
728 return dev->ops->pg_in_transition(dev);
729}
730
720static inline bool mei_pg_is_enabled(struct mei_device *dev) 731static 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);