History

cpuidle-haltpoll: vcpu hotplug support

When cpus != maxcpus cpuidle-haltpoll will fail to register all vcpus past the online ones and thus fail to register the idle driver. This is because cpuidle_add_sysfs() will return with -ENODEV as a consequence from get_cpu_device() return no device for a non-existing CPU. Instead switch to cpuidle_register_driver() and manually register each of the present cpus through cpuhp_setup_state() callbacks and future ones that get onlined or offlined. This mimmics similar logic that intel_idle does.

Joao Martins committed 7 years ago

Commit 97d3eb91 parent b7e7fff4 files · +73 −21Browse files

Unified · Split

4 files
  1. arch/x86/include/asm/cpuidle_haltpoll.h +2 −2
  2. arch/x86/kernel/kvm.c +6 −12
  3. drivers/cpuidle/cpuidle-haltpoll.c +63 −5
  4. include/linux/cpuidle_haltpoll.h +2 −2
arch/x86/include/asm/cpuidle_haltpoll.h+2−2
@@ -2,7 +2,7 @@ · 1 unmodified line
2#ifndef _ARCH_HALTPOLL_H2#ifndef _ARCH_HALTPOLL_H
3#define _ARCH_HALTPOLL_H3#define _ARCH_HALTPOLL_H
4 4
5void arch_haltpoll_enable(void);5void arch_haltpoll_enable(unsigned int cpu);
6void arch_haltpoll_disable(void);6void arch_haltpoll_disable(unsigned int cpu);
7 7
8#endif8#endif
arch/x86/kernel/kvm.c+6−12
@@ -888,32 +888,26 @@ static void kvm_enable_host_haltpoll(void *i) · 887 unmodified lines
888 wrmsrl(MSR_KVM_POLL_CONTROL, 1);888 wrmsrl(MSR_KVM_POLL_CONTROL, 1);
889}889}
890 890
891void arch_haltpoll_enable(void)891void arch_haltpoll_enable(unsigned int cpu)
892{892{
893 if (!kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL)) {893 if (!kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL)) {
894 printk(KERN_ERR "kvm: host does not support poll control\n");894 pr_err_once("kvm: host does not support poll control\n");
895 printk(KERN_ERR "kvm: host upgrade recommended\n");895 pr_err_once("kvm: host upgrade recommended\n");
896 return;896 return;
897 }897 }
898 898
899 preempt_disable();
900 /* Enable guest halt poll disables host halt poll */899 /* Enable guest halt poll disables host halt poll */
901 kvm_disable_host_haltpoll(NULL);900 smp_call_function_single(cpu, kvm_disable_host_haltpoll, NULL, 1);
902 smp_call_function(kvm_disable_host_haltpoll, NULL, 1);
903 preempt_enable();
904}901}
905EXPORT_SYMBOL_GPL(arch_haltpoll_enable);902EXPORT_SYMBOL_GPL(arch_haltpoll_enable);
906 903
907void arch_haltpoll_disable(void)904void arch_haltpoll_disable(unsigned int cpu)
908{905{
909 if (!kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL))906 if (!kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL))
910 return;907 return;
911 908
912 preempt_disable();
913 /* Enable guest halt poll disables host halt poll */909 /* Enable guest halt poll disables host halt poll */
914 kvm_enable_host_haltpoll(NULL);910 smp_call_function_single(cpu, kvm_enable_host_haltpoll, NULL, 1);
915 smp_call_function(kvm_enable_host_haltpoll, NULL, 1);
916 preempt_enable();
917}911}
918EXPORT_SYMBOL_GPL(arch_haltpoll_disable);912EXPORT_SYMBOL_GPL(arch_haltpoll_disable);
919#endif913#endif
drivers/cpuidle/cpuidle-haltpoll.c+63−5
@@ -11,12 +11,16 @@ · 10 unmodified lines
11 */11 */
12 12
13#include <linux/init.h>13#include <linux/init.h>
14#include <linux/cpu.h>
14#include <linux/cpuidle.h>15#include <linux/cpuidle.h>
15#include <linux/module.h>16#include <linux/module.h>
16#include <linux/sched/idle.h>17#include <linux/sched/idle.h>
17#include <linux/kvm_para.h>18#include <linux/kvm_para.h>
18#include <linux/cpuidle_haltpoll.h>19#include <linux/cpuidle_haltpoll.h>
19 20
21static struct cpuidle_device __percpu *haltpoll_cpuidle_devices;
22static enum cpuhp_state haltpoll_hp_state;
23
20static int default_enter_idle(struct cpuidle_device *dev,24static int default_enter_idle(struct cpuidle_device *dev,
21 struct cpuidle_driver *drv, int index)25 struct cpuidle_driver *drv, int index)
22{26{
@@ -46,6 +50,46 @@ static struct cpuidle_driver haltpoll_driver = { · 23 unmodified lines
46 .state_count = 2,50 .state_count = 2,
47};51};
48 52
53static int haltpoll_cpu_online(unsigned int cpu)
54{
55 struct cpuidle_device *dev;
56
57 dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu);
58 if (!dev->registered) {
59 dev->cpu = cpu;
60 if (cpuidle_register_device(dev)) {
61 pr_notice("cpuidle_register_device %d failed!\n", cpu);
62 return -EIO;
63 }
64 arch_haltpoll_enable(cpu);
65 }
66
67 return 0;
68}
69
70static int haltpoll_cpu_offline(unsigned int cpu)
71{
72 struct cpuidle_device *dev;
73
74 dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu);
75 if (dev->registered) {
76 arch_haltpoll_disable(cpu);
77 cpuidle_unregister_device(dev);
78 }
79
80 return 0;
81}
82
83static void haltpoll_uninit(void)
84{
85 if (haltpoll_hp_state)
86 cpuhp_remove_state(haltpoll_hp_state);
87 cpuidle_unregister_driver(&haltpoll_driver);
88
89 free_percpu(haltpoll_cpuidle_devices);
90 haltpoll_cpuidle_devices = NULL;
91}
92
49static int __init haltpoll_init(void)93static int __init haltpoll_init(void)
50{94{
51 int ret;95 int ret;
@@ -56,17 +100,31 @@ static int __init haltpoll_init(void) · 4 unmodified lines
56 if (!kvm_para_available())100 if (!kvm_para_available())
57 return 0;101 return 0;
58 102
59 ret = cpuidle_register(&haltpoll_driver, NULL);103 ret = cpuidle_register_driver(drv);
60 if (ret == 0)104 if (ret < 0)
61 arch_haltpoll_enable();105 return ret;
106
107 haltpoll_cpuidle_devices = alloc_percpu(struct cpuidle_device);
108 if (haltpoll_cpuidle_devices == NULL) {
109 cpuidle_unregister_driver(drv);
110 return -ENOMEM;
111 }
112
113 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "cpuidle/haltpoll:online",
114 haltpoll_cpu_online, haltpoll_cpu_offline);
115 if (ret < 0) {
116 haltpoll_uninit();
117 } else {
118 haltpoll_hp_state = ret;
119 ret = 0;
120 }
62 121
63 return ret;122 return ret;
64}123}
65 124
66static void __exit haltpoll_exit(void)125static void __exit haltpoll_exit(void)
67{126{
68 arch_haltpoll_disable();127 haltpoll_uninit();
69 cpuidle_unregister(&haltpoll_driver);
70}128}
71 129
72module_init(haltpoll_init);130module_init(haltpoll_init);
include/linux/cpuidle_haltpoll.h+2−2
@@ -5,11 +5,11 @@ · 4 unmodified lines
5#ifdef CONFIG_ARCH_CPUIDLE_HALTPOLL5#ifdef CONFIG_ARCH_CPUIDLE_HALTPOLL
6#include <asm/cpuidle_haltpoll.h>6#include <asm/cpuidle_haltpoll.h>
7#else7#else
8static inline void arch_haltpoll_enable(void)8static inline void arch_haltpoll_enable(unsigned int cpu)
9{9{
10}10}
11 11
12static inline void arch_haltpoll_disable(void)12static inline void arch_haltpoll_disable(unsigned int cpu)
13{13{
14}14}
15#endif15#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t