aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong Wang <yong.y.wang@intel.com>2010-12-16 10:29:13 +0800
committerH. Peter Anvin <hpa@linux.intel.com>2010-12-22 13:50:30 -0800
commit0a9a4daedffbb195aef2e08ad58ca2c232bbe18d (patch)
tree30dd040b995e0b3c1425a9bdc2589e4dd8f35775
parente203358312b4762936de133caf00b126c115952c (diff)
downloadmrst-s0i3-test-0a9a4daedffbb195aef2e08ad58ca2c232bbe18d.tar.gz
mrst-s0i3-test-0a9a4daedffbb195aef2e08ad58ca2c232bbe18d.tar.xz
mrst-s0i3-test-0a9a4daedffbb195aef2e08ad58ca2c232bbe18d.zip
x86, mrst: do state demotions in prepare callback
Check state availability and do state demotions in cpuidle_device's prepare callback function so that state statistics data gets accounted on the right state. Signed-off-by: Yong Wang <yong.y.wang@intel.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--drivers/idle/intel_idle.c3
-rw-r--r--drivers/idle/mrst_s0i3.c61
-rw-r--r--drivers/idle/mrst_s0i3.h1
3 files changed, 46 insertions, 19 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index bf906c88760..4abb67f3554 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -79,6 +79,7 @@ static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only
static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
static struct cpuidle_state *cpuidle_state_table;
+static int (*cpuidle_device_prepare)(struct cpuidle_device *dev);
/*
* Indicates that this is not a proper MWAIT state
@@ -354,6 +355,7 @@ static int intel_idle_probe(void)
case 0x26: /* 38 - Lincroft Atom Processor */
lapic_timer_reliable_states = (1 << 1); /* C1 */
cpuidle_state_table = mrst_cstates;
+ cpuidle_device_prepare = mrst_check_state_availability;
break;
case 0x2A: /* SNB */
@@ -455,6 +457,7 @@ static int intel_idle_cpuidle_devices_init(void)
}
dev->cpu = i;
+ dev->prepare = cpuidle_device_prepare;
if (cpuidle_register_device(dev)) {
pr_debug(PREFIX "cpuidle_register_device %d failed!\n",
i);
diff --git a/drivers/idle/mrst_s0i3.c b/drivers/idle/mrst_s0i3.c
index d44e806662a..59400773ba1 100644
--- a/drivers/idle/mrst_s0i3.c
+++ b/drivers/idle/mrst_s0i3.c
@@ -62,6 +62,40 @@ static void *s0i3_trampoline_base;
static volatile bool s0i3_pmu_command_pending;
/**
+ * mrst_check_state_availability
+ * @dev: cpuidle_device
+ *
+ * Certain states are not appropriate for governor to pick in some cases.
+ * This function will be called as cpuidle_device's prepare callback and
+ * thus tells governor to ignore such states when selecting the next state
+ * to enter.
+ */
+int mrst_check_state_availability(struct cpuidle_device *dev)
+{
+ int cpu = smp_processor_id();
+
+ /*
+ * If there is another CPU running, the GPU is active or the PMU
+ * is uninitialized, we cannot enter S0i3
+ */
+ if (!pmu_reg || !cpumask_equal(cpu_online_mask, cpumask_of(cpu)))
+ dev->states[5].flags |= CPUIDLE_FLAG_IGNORE;
+ else
+ dev->states[5].flags &= ~CPUIDLE_FLAG_IGNORE;
+
+ /*
+ * If there is a pending PMU command, we cannot enter C6,
+ * demote to C4.
+ */
+ if (s0i3_pmu_command_pending)
+ dev->states[4].flags |= CPUIDLE_FLAG_IGNORE;
+ else
+ dev->states[4].flags &= ~CPUIDLE_FLAG_IGNORE;
+
+ return 0;
+}
+
+/**
* mrst_idle
* @dev: cpuidle_device
* @state: cpuidle state
@@ -80,22 +114,6 @@ int mrst_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
local_irq_disable();
/*
- * If there is another CPU running, the GPU is active or the PMU
- * is uninitialized, we cannot enter S0i3
- */
- if (eax == -1UL &&
- (!pmu_reg || !cpumask_equal(cpu_online_mask, cpumask_of(cpu)))) {
- eax = 0x52; /* Demote to C6 */
- }
-
- /*
- * If there is a pending PMU command, we cannot enter C6,
- * demote to C4.
- */
- if (eax == 0x52 && s0i3_pmu_command_pending)
- eax = 0x30; /* Demote to C4 */
-
- /*
* leave_mm() to avoid costly and often unnecessary wakeups
* for flushing the user TLB's associated with the active mm.
*/
@@ -361,7 +379,12 @@ static irqreturn_t s0i3_pmu_irq(int irq, void *dummy)
return IRQ_HANDLED;
}
-/* XXX: Replace this with unified trampoline code */
+/*
+ * Reserve memory for the return-to-C6 trampoline. This is called
+ * extremely early in initialization in order to allocate low memory.
+ *
+ * XXX: Replace this with unified trampoline code.
+ */
extern const char s0i3_trampoline_data[], s0i3_trampoline_data_end[];
void s0i3_reserve_memory(void)
@@ -382,7 +405,7 @@ void s0i3_reserve_memory(void)
memblock_x86_reserve_range(mem, mem + size, "S0I3");
}
-/* Hacky! */
+/* Hacky - should be replaced with a registered PCI ID driver */
static int s0i3_prepare(void)
{
int err;
@@ -428,7 +451,7 @@ static int s0i3_prepare(void)
tmp |= 0x100; /* Enable interrupts */
writel(tmp, &pmu_reg->pm_ics);
- /* Set up the wakeup trampoline */
+ /* Set up the return-to-C6 code trampoline in low memory */
memcpy(s0i3_trampoline_base, s0i3_trampoline_data,
s0i3_trampoline_data_end - s0i3_trampoline_data);
diff --git a/drivers/idle/mrst_s0i3.h b/drivers/idle/mrst_s0i3.h
index 23f7c26d6bf..02a073d7591 100644
--- a/drivers/idle/mrst_s0i3.h
+++ b/drivers/idle/mrst_s0i3.h
@@ -32,6 +32,7 @@ int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
int mrst_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
int mrst_s0i3_entry(u32 regval, volatile u32 *regaddr);
void mrst_s0i3_resume(void);
+int mrst_check_state_availability(struct cpuidle_device *dev);
#endif /* __ASSEMBLY__ */
#endif /* MRST_S0I3_H */