aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2010-12-07 00:04:20 -0800
committerH. Peter Anvin <hpa@linux.intel.com>2010-12-14 10:48:41 -0800
commit20211a44505789bd027a85b08253866c8c3fdbbb (patch)
tree9a29ef682693438c91fc96481e77e1ae93710563
parentcc76afb3c3a2bf99f7e5f5744d1111a6db7f333d (diff)
downloadmrst-s0i3-test-20211a44505789bd027a85b08253866c8c3fdbbb.tar.gz
mrst-s0i3-test-20211a44505789bd027a85b08253866c8c3fdbbb.tar.xz
mrst-s0i3-test-20211a44505789bd027a85b08253866c8c3fdbbb.zip
s0i3: delay the PM_CMD write until immediately before MWAIT
PM_CMD has a timeout, make sure it doesn't get triggered by WBINVD.
-rw-r--r--drivers/idle/mrst_s0i3.c29
-rw-r--r--drivers/idle/mrst_s0i3.h2
-rw-r--r--drivers/idle/mrst_s0i3_asm.S7
3 files changed, 21 insertions, 17 deletions
diff --git a/drivers/idle/mrst_s0i3.c b/drivers/idle/mrst_s0i3.c
index 6bd9f37659f..a5a350e4c11 100644
--- a/drivers/idle/mrst_s0i3.c
+++ b/drivers/idle/mrst_s0i3.c
@@ -217,6 +217,16 @@ static void s0i3_poke_other_cpu(void)
#define SUB_SYS_D0I2_VALUE 0x00aaaaaa
#define WAKE_ENABLE_VALUE 0x0786 /* 0x4786? */
#define SUSPEND_GFX 0xc
+#define PM_S0I3_COMMAND \
+ ((0 << 31) | /* Reserved */ \
+ (0 << 30) | /* Core must be idle */ \
+ (0xc2 << 22) | /* ACK C6 trigger */ \
+ (3 << 19) | /* Trigger on DMI message */ \
+ (3 << 16) | /* Enter S0i3 */ \
+ (0 << 13) | /* Numeric mode ID (sw) */ \
+ (3 << 9) | /* Trigger mode */ \
+ (0 << 8) | /* Do not interrupt */ \
+ (1 << 0)) /* Set configuration */
static void s0i3_wait_for_pmu(void)
{
@@ -224,28 +234,19 @@ static void s0i3_wait_for_pmu(void)
cpu_relax();
}
-static void s0i3_prep_pmu(void)
+noinline static void s0i3_prep_pmu(void)
{
s0i3_wait_for_pmu();
+ /* Clear any possible error conditions */
+ writel(0x300, &pmu_reg->pm_ics);
+
/* Program the wakeup */
writel(WAKE_ENABLE_VALUE, &pmu_reg->pm_wkc[0]);
writel(AUTO_CLK_GATE_VALUE, &pmu_reg->pm_wssc[0]);
/* Clock gate Langwell */
writel(SUB_SYS_D0I2_VALUE, &pmu_reg->pm_ssc[0]);
-
- /* Do this when S0i3 is entered */
- writel((0 << 31) | /* Reserved */
- (0 << 30) | /* Core must be idle */
- (0xc2 << 22) | /* ACK C6 trigger */
- (3 << 19) | /* Trigger on DMI message */
- (3 << 16) | /* Enter S0i3 */
- (0 << 13) | /* Numeric mode ID (sw) */
- (3 << 9) | /* Trigger mode */
- (0 << 8) | /* Do not interrupt */
- (1 << 0), /* Set configuration */
- &pmu_reg->pm_cmd);
}
static inline void s0i3_update_wake_pointer(void)
@@ -260,7 +261,7 @@ static noinline void do_s0i3(void)
s0i3_save_msrs();
save_processor_state();
s0i3_prep_pmu();
- if (mrst_s0i3_entry()) {
+ if (mrst_s0i3_entry(PM_S0I3_COMMAND, &pmu_reg->pm_cmd)) {
s0i3_restore_msrs();
restore_processor_state();
s0i3_restore_lapic();
diff --git a/drivers/idle/mrst_s0i3.h b/drivers/idle/mrst_s0i3.h
index ee6b1b2ba74..574626ffb15 100644
--- a/drivers/idle/mrst_s0i3.h
+++ b/drivers/idle/mrst_s0i3.h
@@ -30,7 +30,7 @@
int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
int mrst_s0i3_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
-int mrst_s0i3_entry(void);
+int mrst_s0i3_entry(u32 regval, volatile u32 *regaddr);
void mrst_s0i3_resume(void);
#endif /* __ASSEMBLY__ */
diff --git a/drivers/idle/mrst_s0i3_asm.S b/drivers/idle/mrst_s0i3_asm.S
index 10872fa4a3c..4561a53c347 100644
--- a/drivers/idle/mrst_s0i3_asm.S
+++ b/drivers/idle/mrst_s0i3_asm.S
@@ -37,7 +37,9 @@ ENTRY(mrst_s0i3_entry)
pushl %ebp
pushl %ebx
- movl %esp, %esi
+ movl %esp, %ebp
+ movl %eax, %esi /* Command code to write to PM_CMD */
+ movl %edx, %edi /* Linear address of the PM_CMD register */
sldt %eax
pushl %eax
@@ -89,13 +91,14 @@ ENTRY(mrst_s0i3_entry)
movl $MRST_C6_HINTS_EAX, %eax
movl $MRST_C6_HINTS_ECX, %ecx
+ movl %esi, (%edi)
sti
mwait
/* If MWAIT wakes us up, assume something happened... */
cli
/* jmp simulate_resume */
- movl %esi, %esp
+ movl %ebp, %esp
xorl %eax, %eax /* Not really S0i3 */
popl %ebx