X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fcpuidle%2Fcpuidle.c;h=fc555a90bb211b651e20c254751ae08f00fffd1a;hb=f5c90e85dc77669a55fecfb593bb8e7f47374ee2;hp=2a98d99cbd46075707c15572dff6ace4e6c602c3;hpb=21511abd0a248a3f225d3b611cfabb93124605a7;p=linux-2.6 diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 2a98d99cbd..fc555a90bb 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "cpuidle.h" @@ -26,6 +27,17 @@ static void (*pm_idle_old)(void); static int enabled_devices; +#if defined(CONFIG_ARCH_HAS_CPU_IDLE_WAIT) +static void cpuidle_kick_cpus(void) +{ + cpu_idle_wait(); +} +#elif defined(CONFIG_SMP) +# error "Arch needs cpu_idle_wait() equivalent here" +#else /* !CONFIG_ARCH_HAS_CPU_IDLE_WAIT && !CONFIG_SMP */ +static void cpuidle_kick_cpus(void) {} +#endif + /** * cpuidle_idle_call - the main idle loop * @@ -55,7 +67,7 @@ static void cpuidle_idle_call(void) /* enter the state and update stats */ dev->last_residency = target_state->enter(dev, target_state); dev->last_state = target_state; - target_state->time += dev->last_residency; + target_state->time += (unsigned long long)dev->last_residency; target_state->usage++; /* give the governor an opportunity to reflect on the outcome */ @@ -82,7 +94,7 @@ void cpuidle_uninstall_idle_handler(void) { if (enabled_devices && (pm_idle != pm_idle_old)) { pm_idle = pm_idle_old; - cpu_idle_wait(); + cpuidle_kick_cpus(); } } @@ -180,6 +192,45 @@ void cpuidle_disable_device(struct cpuidle_device *dev) EXPORT_SYMBOL_GPL(cpuidle_disable_device); +#ifdef CONFIG_ARCH_HAS_CPU_RELAX +static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) +{ + ktime_t t1, t2; + s64 diff; + int ret; + + t1 = ktime_get(); + local_irq_enable(); + while (!need_resched()) + cpu_relax(); + + t2 = ktime_get(); + diff = ktime_to_us(ktime_sub(t2, t1)); + if (diff > INT_MAX) + diff = INT_MAX; + + ret = (int) diff; + return ret; +} + +static void poll_idle_init(struct cpuidle_device *dev) +{ + struct cpuidle_state *state = &dev->states[0]; + + cpuidle_set_statedata(state, NULL); + + snprintf(state->name, CPUIDLE_NAME_LEN, "C0"); + snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); + state->exit_latency = 0; + state->target_residency = 0; + state->power_usage = -1; + state->flags = CPUIDLE_FLAG_POLL; + state->enter = poll_idle; +} +#else +static void poll_idle_init(struct cpuidle_device *dev) {} +#endif /* CONFIG_ARCH_HAS_CPU_RELAX */ + /** * cpuidle_register_device - registers a CPU's idle PM feature * @dev: the cpu @@ -198,6 +249,8 @@ int cpuidle_register_device(struct cpuidle_device *dev) mutex_lock(&cpuidle_lock); + poll_idle_init(dev); + per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); if ((ret = cpuidle_add_sysfs(sys_dev))) {