aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/Kconfig3
-rw-r--r--drivers/acpi/processor_idle.c4
-rw-r--r--drivers/cpuidle/cpuidle.c41
-rw-r--r--include/linux/cpuidle.h13
4 files changed, 57 insertions, 4 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index e6728bd61cc1..fd4265007053 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -105,6 +105,9 @@ config GENERIC_TIME_VSYSCALL
105 bool 105 bool
106 default X86_64 106 default X86_64
107 107
108config ARCH_HAS_CPU_RELAX
109 def_bool y
110
108config HAVE_SETUP_PER_CPU_AREA 111config HAVE_SETUP_PER_CPU_AREA
109 def_bool X86_64 112 def_bool X86_64
110 113
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index fea71597b40a..32488e6f76ab 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -1628,7 +1628,7 @@ struct cpuidle_driver acpi_idle_driver = {
1628 */ 1628 */
1629static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) 1629static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
1630{ 1630{
1631 int i, count = 0; 1631 int i, count = CPUIDLE_DRIVER_STATE_START;
1632 struct acpi_processor_cx *cx; 1632 struct acpi_processor_cx *cx;
1633 struct cpuidle_state *state; 1633 struct cpuidle_state *state;
1634 struct cpuidle_device *dev = &pr->power.dev; 1634 struct cpuidle_device *dev = &pr->power.dev;
@@ -1687,6 +1687,8 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
1687 } 1687 }
1688 1688
1689 count++; 1689 count++;
1690 if (count == CPUIDLE_STATE_MAX)
1691 break;
1690 } 1692 }
1691 1693
1692 dev->state_count = count; 1694 dev->state_count = count;
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 2a98d99cbd46..2c4b2d47973e 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -15,6 +15,7 @@
15#include <linux/pm_qos_params.h> 15#include <linux/pm_qos_params.h>
16#include <linux/cpu.h> 16#include <linux/cpu.h>
17#include <linux/cpuidle.h> 17#include <linux/cpuidle.h>
18#include <linux/ktime.h>
18 19
19#include "cpuidle.h" 20#include "cpuidle.h"
20 21
@@ -180,6 +181,44 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
180 181
181EXPORT_SYMBOL_GPL(cpuidle_disable_device); 182EXPORT_SYMBOL_GPL(cpuidle_disable_device);
182 183
184#ifdef CONFIG_ARCH_HAS_CPU_RELAX
185static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
186{
187 ktime_t t1, t2;
188 s64 diff;
189 int ret;
190
191 t1 = ktime_get();
192 local_irq_enable();
193 while (!need_resched())
194 cpu_relax();
195
196 t2 = ktime_get();
197 diff = ktime_to_us(ktime_sub(t2, t1));
198 if (diff > INT_MAX)
199 diff = INT_MAX;
200
201 ret = (int) diff;
202 return ret;
203}
204
205static void poll_idle_init(struct cpuidle_device *dev)
206{
207 struct cpuidle_state *state = &dev->states[0];
208
209 cpuidle_set_statedata(state, NULL);
210
211 snprintf(state->name, CPUIDLE_NAME_LEN, "C0 (poll idle)");
212 state->exit_latency = 0;
213 state->target_residency = 0;
214 state->power_usage = -1;
215 state->flags = CPUIDLE_FLAG_POLL | CPUIDLE_FLAG_TIME_VALID;
216 state->enter = poll_idle;
217}
218#else
219static void poll_idle_init(struct cpuidle_device *dev) {}
220#endif /* CONFIG_ARCH_HAS_CPU_RELAX */
221
183/** 222/**
184 * cpuidle_register_device - registers a CPU's idle PM feature 223 * cpuidle_register_device - registers a CPU's idle PM feature
185 * @dev: the cpu 224 * @dev: the cpu
@@ -198,6 +237,8 @@ int cpuidle_register_device(struct cpuidle_device *dev)
198 237
199 mutex_lock(&cpuidle_lock); 238 mutex_lock(&cpuidle_lock);
200 239
240 poll_idle_init(dev);
241
201 per_cpu(cpuidle_devices, dev->cpu) = dev; 242 per_cpu(cpuidle_devices, dev->cpu) = dev;
202 list_add(&dev->device_list, &cpuidle_detected_devices); 243 list_add(&dev->device_list, &cpuidle_detected_devices);
203 if ((ret = cpuidle_add_sysfs(sys_dev))) { 244 if ((ret = cpuidle_add_sysfs(sys_dev))) {
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index b0fd85ab9efb..385d45b616db 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -46,9 +46,10 @@ struct cpuidle_state {
46/* Idle State Flags */ 46/* Idle State Flags */
47#define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ 47#define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */
48#define CPUIDLE_FLAG_CHECK_BM (0x02) /* BM activity will exit state */ 48#define CPUIDLE_FLAG_CHECK_BM (0x02) /* BM activity will exit state */
49#define CPUIDLE_FLAG_SHALLOW (0x10) /* low latency, minimal savings */ 49#define CPUIDLE_FLAG_POLL (0x10) /* no latency, no savings */
50#define CPUIDLE_FLAG_BALANCED (0x20) /* medium latency, moderate savings */ 50#define CPUIDLE_FLAG_SHALLOW (0x20) /* low latency, minimal savings */
51#define CPUIDLE_FLAG_DEEP (0x40) /* high latency, large savings */ 51#define CPUIDLE_FLAG_BALANCED (0x40) /* medium latency, moderate savings */
52#define CPUIDLE_FLAG_DEEP (0x80) /* high latency, large savings */
52 53
53#define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) 54#define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
54 55
@@ -178,4 +179,10 @@ static inline void cpuidle_unregister_governor(struct cpuidle_governor *gov) { }
178 179
179#endif 180#endif
180 181
182#ifdef CONFIG_ARCH_HAS_CPU_RELAX
183#define CPUIDLE_DRIVER_STATE_START 1
184#else
185#define CPUIDLE_DRIVER_STATE_START 0
186#endif
187
181#endif /* _LINUX_CPUIDLE_H */ 188#endif /* _LINUX_CPUIDLE_H */