diff options
-rw-r--r-- | arch/x86/kernel/process.c | 2 | ||||
-rw-r--r-- | drivers/cpuidle/Kconfig | 9 | ||||
-rw-r--r-- | drivers/cpuidle/Makefile | 1 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-haltpoll.c | 68 |
4 files changed, 79 insertions, 1 deletions
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 75fea0d48c0e..5e94c4354d4e 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -580,7 +580,7 @@ void __cpuidle default_idle(void) | |||
580 | safe_halt(); | 580 | safe_halt(); |
581 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id()); | 581 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id()); |
582 | } | 582 | } |
583 | #ifdef CONFIG_APM_MODULE | 583 | #if defined(CONFIG_APM_MODULE) || defined(CONFIG_HALTPOLL_CPUIDLE_MODULE) |
584 | EXPORT_SYMBOL(default_idle); | 584 | EXPORT_SYMBOL(default_idle); |
585 | #endif | 585 | #endif |
586 | 586 | ||
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index a4ac31e4a58c..cc8efc56be7d 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig | |||
@@ -51,6 +51,15 @@ depends on PPC | |||
51 | source "drivers/cpuidle/Kconfig.powerpc" | 51 | source "drivers/cpuidle/Kconfig.powerpc" |
52 | endmenu | 52 | endmenu |
53 | 53 | ||
54 | config HALTPOLL_CPUIDLE | ||
55 | tristate "Halt poll cpuidle driver" | ||
56 | depends on X86 && KVM_GUEST | ||
57 | default y | ||
58 | help | ||
59 | This option enables halt poll cpuidle driver, which allows to poll | ||
60 | before halting in the guest (more efficient than polling in the | ||
61 | host via halt_poll_ns for some scenarios). | ||
62 | |||
54 | endif | 63 | endif |
55 | 64 | ||
56 | config ARCH_NEEDS_CPU_IDLE_COUPLED | 65 | config ARCH_NEEDS_CPU_IDLE_COUPLED |
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 9d7176cee3d3..240227474cd9 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile | |||
@@ -7,6 +7,7 @@ obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ | |||
7 | obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o | 7 | obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o |
8 | obj-$(CONFIG_DT_IDLE_STATES) += dt_idle_states.o | 8 | obj-$(CONFIG_DT_IDLE_STATES) += dt_idle_states.o |
9 | obj-$(CONFIG_ARCH_HAS_CPU_RELAX) += poll_state.o | 9 | obj-$(CONFIG_ARCH_HAS_CPU_RELAX) += poll_state.o |
10 | obj-$(CONFIG_HALTPOLL_CPUIDLE) += cpuidle-haltpoll.o | ||
10 | 11 | ||
11 | ################################################################################## | 12 | ################################################################################## |
12 | # ARM SoC drivers | 13 | # ARM SoC drivers |
diff --git a/drivers/cpuidle/cpuidle-haltpoll.c b/drivers/cpuidle/cpuidle-haltpoll.c new file mode 100644 index 000000000000..35cfb53e9287 --- /dev/null +++ b/drivers/cpuidle/cpuidle-haltpoll.c | |||
@@ -0,0 +1,68 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * cpuidle driver for haltpoll governor. | ||
4 | * | ||
5 | * Copyright 2019 Red Hat, Inc. and/or its affiliates. | ||
6 | * | ||
7 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
8 | * the COPYING file in the top-level directory. | ||
9 | * | ||
10 | * Authors: Marcelo Tosatti <mtosatti@redhat.com> | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/cpuidle.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/sched/idle.h> | ||
17 | #include <linux/kvm_para.h> | ||
18 | |||
19 | static int default_enter_idle(struct cpuidle_device *dev, | ||
20 | struct cpuidle_driver *drv, int index) | ||
21 | { | ||
22 | if (current_clr_polling_and_test()) { | ||
23 | local_irq_enable(); | ||
24 | return index; | ||
25 | } | ||
26 | default_idle(); | ||
27 | return index; | ||
28 | } | ||
29 | |||
30 | static struct cpuidle_driver haltpoll_driver = { | ||
31 | .name = "haltpoll", | ||
32 | .owner = THIS_MODULE, | ||
33 | .states = { | ||
34 | { /* entry 0 is for polling */ }, | ||
35 | { | ||
36 | .enter = default_enter_idle, | ||
37 | .exit_latency = 1, | ||
38 | .target_residency = 1, | ||
39 | .power_usage = -1, | ||
40 | .name = "haltpoll idle", | ||
41 | .desc = "default architecture idle", | ||
42 | }, | ||
43 | }, | ||
44 | .safe_state_index = 0, | ||
45 | .state_count = 2, | ||
46 | }; | ||
47 | |||
48 | static int __init haltpoll_init(void) | ||
49 | { | ||
50 | struct cpuidle_driver *drv = &haltpoll_driver; | ||
51 | |||
52 | cpuidle_poll_state_init(drv); | ||
53 | |||
54 | if (!kvm_para_available()) | ||
55 | return 0; | ||
56 | |||
57 | return cpuidle_register(&haltpoll_driver, NULL); | ||
58 | } | ||
59 | |||
60 | static void __exit haltpoll_exit(void) | ||
61 | { | ||
62 | cpuidle_unregister(&haltpoll_driver); | ||
63 | } | ||
64 | |||
65 | module_init(haltpoll_init); | ||
66 | module_exit(haltpoll_exit); | ||
67 | MODULE_LICENSE("GPL"); | ||
68 | MODULE_AUTHOR("Marcelo Tosatti <mtosatti@redhat.com>"); | ||