From 13f45df6a66c97e7c1885474e67d8d543dc6e1d2 Mon Sep 17 00:00:00 2001 From: Illyas Mansoor Date: Fri, 11 Nov 2011 18:43:45 +0530 Subject: [PATCH] [PORT FROM R2] intel_idle: re-introduce c6 to c4 demotion BZ: 14243 In patch #19777 BZ 7240 we reasoned that using set_s0ix_complete implementation will effectively remove the need for C6 to C4 demotion. But based on BZ 12588 analysis and conclusion that C6 to C4 offload is still required in some cases even thou set_s0ix_complete() is called suggests that we need to get back C6 to C4 demotion logic and also get back the fix for LPMP3 BZ 5212 power regression. Also in case we demote we dont have to increment/decrement C6 counter. This patch fixes this scenario: 1. s0i3 command issued in MID_PMU 2. c6 offload bit not set 3. c4 demoted but need_reschdule was set so no mwait executed. 4. idle: c6 latency found so soc_s0ix_idle get called with eax==C6_HINT 5. in this case mfld_s0ix_enter not called 6. need_reschudle now not true so mwait(c6) issued. Hence will have to get back the c6 to c4 demotion logic. Change-Id: Ib35e2756a3d99e30418869b84f8befb7b8faa98e Orig-Change-Id: Ic7740686c45679438154b456a06f99f947577eed Signed-off-by: Illyas Mansoor Reviewed-on: http://android.intel.com:8080/29304 Reviewed-by: Martin, LoicX Tested-by: Martin, LoicX Reviewed-by: buildbot Tested-by: buildbot --- arch/x86/platform/mfld/pmu.c | 17 +++++++++++++++++ drivers/idle/intel_idle.c | 18 ++++++++++++++++-- include/linux/intel_mid_pm.h | 6 ++++-- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/arch/x86/platform/mfld/pmu.c b/arch/x86/platform/mfld/pmu.c index 8fb8ef4..6d88d68 100755 --- a/arch/x86/platform/mfld/pmu.c +++ b/arch/x86/platform/mfld/pmu.c @@ -34,6 +34,8 @@ #include #include #include +#include + #include #include "pmu.h" @@ -1057,6 +1059,10 @@ static irqreturn_t pmu_sc_irq(int irq, void *ignored) } else { s0ix_sram_restore(mid_pmu_cxt->s0ix_entered); + /* Wakeup allother CPU's */ + if (mid_pmu_cxt->s0ix_entered == MID_S0I3_STATE) + apic->send_IPI_allbutself(RESCHEDULE_VECTOR); + mid_pmu_cxt->s0ix_entered = 0; /* S0ix case release it */ @@ -1075,6 +1081,17 @@ void pmu_set_s0ix_complete(void) } EXPORT_SYMBOL(pmu_set_s0ix_complete); +bool pmu_is_s0i3_in_progress(void) +{ + bool state = false; + + if (pmu_initialized && mid_pmu_cxt->s0ix_entered == MID_S0I3_STATE) + state = true; + + return state; +} +EXPORT_SYMBOL(pmu_is_s0i3_in_progress); + static inline u32 find_index_in_hash(struct pci_dev *pdev, int *found) { u32 h_index; diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index e4f2bc6..a4574b6 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -381,6 +381,15 @@ static int soc_s0ix_idle(struct cpuidle_device *dev, eax = C6_HINT; } + /* Check if s0i3 is already in progress, + * This is required to demote C6 while S0ix + * is in progress + */ + if (unlikely(pmu_is_s0i3_in_progress())) { + dev->last_state = &dev->states[C4_STATE_IDX]; + return intel_idle(dev, &dev->states[C4_STATE_IDX]); + } + local_irq_disable(); /* @@ -401,7 +410,10 @@ static int soc_s0ix_idle(struct cpuidle_device *dev, num_online_cpus() && s0ix_state) { s0ix_entered = mfld_s0ix_enter(s0ix_state); if (!s0ix_entered) { - eax = C4_HINT; + if (pmu_is_s0i3_in_progress()) { + atomic_dec(&nr_cpus_in_c6); + eax = C4_HINT; + } pmu_set_s0ix_complete(); } } @@ -411,7 +423,9 @@ static int soc_s0ix_idle(struct cpuidle_device *dev, if (!need_resched()) __mwait(eax, ecx); - atomic_dec(&nr_cpus_in_c6); + if (likely(eax == C6_HINT)) + atomic_dec(&nr_cpus_in_c6); + /* During s0ix exit inform scu that OS * has exited. In case scu is still waiting * for ack c6 trigger, it would exit out diff --git a/include/linux/intel_mid_pm.h b/include/linux/intel_mid_pm.h index 9a25e45..8dc87f6 100644 --- a/include/linux/intel_mid_pm.h +++ b/include/linux/intel_mid_pm.h @@ -102,7 +102,7 @@ extern int mfld_s0ix_enter(int); extern int get_target_platform_state(void); extern void pmu_set_s0ix_complete(void); -extern unsigned long pmu_get_cstate(unsigned long eax); +extern bool pmu_is_s0i3_in_progress(void); extern int pmu_nc_set_power_state (int islands, int state_type, int reg_type); extern void mfld_shutdown(void); @@ -131,6 +131,8 @@ static inline int pmu_nc_set_power_state static inline void pmu_set_s0ix_complete(void) { return; } static inline void mfld_shutdown(void) { return; } -#endif /* #ifdef CONFIG_X86_MDFLD */ +static inline bool pmu_is_s0ix_in_progress(void) { return false; }; +#endif /* #ifdef CONFIG_INTEL_MID_POWER */ + #endif /* #ifndef INTEL_MID_PM_H */ -- 2.7.4