aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2014-03-18 16:52:00 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-03 19:20:24 -0400
commitba9cdd0e1ad88004c68395697fb2ec6b9b4ff020 (patch)
tree203335393930390637b68fb58eb257403b98d94e /drivers
parent964a2331e9a207fc15ef9eef833212347498bea1 (diff)
mei: me: add pg exit and entry flow commands
For power gating entry we write hbm pg entry request command and then we set pg register For power gating exit we clear pg register and wait for exit request hbm command. Exit power gating request might also be initiated by the firmware w/o explicit driver request The power gating state is tracked by pg_state member of me_hw Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/mei/hbm.c2
-rw-r--r--drivers/misc/mei/hw-me.c92
-rw-r--r--drivers/misc/mei/hw-me.h4
-rw-r--r--drivers/misc/mei/hw.h1
4 files changed, 95 insertions, 4 deletions
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index a16b47c855aa..a725365e2150 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -732,12 +732,14 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
732 732
733 case MEI_PG_ISOLATION_ENTRY_RES_CMD: 733 case MEI_PG_ISOLATION_ENTRY_RES_CMD:
734 dev_dbg(&dev->pdev->dev, "power gate isolation entry response received\n"); 734 dev_dbg(&dev->pdev->dev, "power gate isolation entry response received\n");
735 dev->pg_event = MEI_PG_EVENT_RECEIVED;
735 if (waitqueue_active(&dev->wait_pg)) 736 if (waitqueue_active(&dev->wait_pg))
736 wake_up(&dev->wait_pg); 737 wake_up(&dev->wait_pg);
737 break; 738 break;
738 739
739 case MEI_PG_ISOLATION_EXIT_REQ_CMD: 740 case MEI_PG_ISOLATION_EXIT_REQ_CMD:
740 dev_dbg(&dev->pdev->dev, "power gate isolation exit request received\n"); 741 dev_dbg(&dev->pdev->dev, "power gate isolation exit request received\n");
742 dev->pg_event = MEI_PG_EVENT_RECEIVED;
741 if (waitqueue_active(&dev->wait_pg)) 743 if (waitqueue_active(&dev->wait_pg))
742 wake_up(&dev->wait_pg); 744 wake_up(&dev->wait_pg);
743 break; 745 break;
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 02f3b0c3a2a3..4b048b67a248 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -109,9 +109,12 @@ static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
109 */ 109 */
110static void mei_me_hw_config(struct mei_device *dev) 110static void mei_me_hw_config(struct mei_device *dev)
111{ 111{
112 struct mei_me_hw *hw = to_me_hw(dev);
112 u32 hcsr = mei_hcsr_read(to_me_hw(dev)); 113 u32 hcsr = mei_hcsr_read(to_me_hw(dev));
113 /* Doesn't change in runtime */ 114 /* Doesn't change in runtime */
114 dev->hbuf_depth = (hcsr & H_CBD) >> 24; 115 dev->hbuf_depth = (hcsr & H_CBD) >> 24;
116
117 hw->pg_state = MEI_PG_OFF;
115} 118}
116 119
117/** 120/**
@@ -123,7 +126,8 @@ static void mei_me_hw_config(struct mei_device *dev)
123 */ 126 */
124static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev) 127static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev)
125{ 128{
126 return MEI_PG_OFF; 129 struct mei_me_hw *hw = to_me_hw(dev);
130 return hw->pg_state;
127} 131}
128 132
129/** 133/**
@@ -473,6 +477,80 @@ static void mei_me_pg_exit(struct mei_device *dev)
473} 477}
474 478
475/** 479/**
480 * mei_me_pg_set_sync - perform pg entry procedure
481 *
482 * @dev: the device structure
483 *
484 * returns 0 on success an error code otherwise
485 */
486int mei_me_pg_set_sync(struct mei_device *dev)
487{
488 struct mei_me_hw *hw = to_me_hw(dev);
489 unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT);
490 int ret;
491
492 dev->pg_event = MEI_PG_EVENT_WAIT;
493
494 ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_ENTRY_REQ_CMD);
495 if (ret)
496 return ret;
497
498 mutex_unlock(&dev->device_lock);
499 wait_event_timeout(dev->wait_pg,
500 dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout);
501 mutex_lock(&dev->device_lock);
502
503 if (dev->pg_event == MEI_PG_EVENT_RECEIVED) {
504 mei_me_pg_enter(dev);
505 ret = 0;
506 } else {
507 ret = -ETIME;
508 }
509
510 dev->pg_event = MEI_PG_EVENT_IDLE;
511 hw->pg_state = MEI_PG_ON;
512
513 return ret;
514}
515
516/**
517 * mei_me_pg_unset_sync - perform pg exit procedure
518 *
519 * @dev: the device structure
520 *
521 * returns 0 on success an error code otherwise
522 */
523int mei_me_pg_unset_sync(struct mei_device *dev)
524{
525 struct mei_me_hw *hw = to_me_hw(dev);
526 unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT);
527 int ret;
528
529 if (dev->pg_event == MEI_PG_EVENT_RECEIVED)
530 goto reply;
531
532 dev->pg_event = MEI_PG_EVENT_WAIT;
533
534 mei_me_pg_exit(dev);
535
536 mutex_unlock(&dev->device_lock);
537 wait_event_timeout(dev->wait_pg,
538 dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout);
539 mutex_lock(&dev->device_lock);
540
541reply:
542 if (dev->pg_event == MEI_PG_EVENT_RECEIVED)
543 ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_EXIT_RES_CMD);
544 else
545 ret = -ETIME;
546
547 dev->pg_event = MEI_PG_EVENT_IDLE;
548 hw->pg_state = MEI_PG_OFF;
549
550 return ret;
551}
552
553/**
476 * mei_me_pg_is_enabled - detect if PG is supported by HW 554 * mei_me_pg_is_enabled - detect if PG is supported by HW
477 * 555 *
478 * @dev: the device structure 556 * @dev: the device structure
@@ -601,9 +679,15 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
601 679
602 dev->hbuf_is_ready = mei_hbuf_is_ready(dev); 680 dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
603 681
604 rets = mei_irq_write_handler(dev, &complete_list); 682 /*
605 683 * During PG handshake only allowed write is the replay to the
606 dev->hbuf_is_ready = mei_hbuf_is_ready(dev); 684 * PG exit message, so block calling write function
685 * if the pg state is not idle
686 */
687 if (dev->pg_event == MEI_PG_EVENT_IDLE) {
688 rets = mei_irq_write_handler(dev, &complete_list);
689 dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
690 }
607 691
608 mei_irq_compl_handler(dev, &complete_list); 692 mei_irq_compl_handler(dev, &complete_list);
609 693
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
index 893d5119fa9b..8b412820cc66 100644
--- a/drivers/misc/mei/hw-me.h
+++ b/drivers/misc/mei/hw-me.h
@@ -31,12 +31,16 @@ struct mei_me_hw {
31 */ 31 */
32 u32 host_hw_state; 32 u32 host_hw_state;
33 u32 me_hw_state; 33 u32 me_hw_state;
34 enum mei_pg_state pg_state;
34}; 35};
35 36
36#define to_me_hw(dev) (struct mei_me_hw *)((dev)->hw) 37#define to_me_hw(dev) (struct mei_me_hw *)((dev)->hw)
37 38
38struct mei_device *mei_me_dev_init(struct pci_dev *pdev); 39struct mei_device *mei_me_dev_init(struct pci_dev *pdev);
39 40
41int mei_me_pg_set_sync(struct mei_device *dev);
42int mei_me_pg_unset_sync(struct mei_device *dev);
43
40irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id); 44irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id);
41irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id); 45irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id);
42 46
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index ec4a91a534e6..9bad9cf7a8a0 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -31,6 +31,7 @@
31#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */ 31#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */
32#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */ 32#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */
33 33
34#define MEI_PGI_TIMEOUT 1 /* PG Isolation time response 1 sec */
34#define MEI_HBM_TIMEOUT 1 /* 1 second */ 35#define MEI_HBM_TIMEOUT 1 /* 1 second */
35 36
36/* 37/*