Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/cpuidle/cpuidle-haltpoll.c
26278 views
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 <[email protected]>
11
*/
12
13
#include <linux/init.h>
14
#include <linux/cpu.h>
15
#include <linux/cpuidle.h>
16
#include <linux/module.h>
17
#include <linux/sched/idle.h>
18
#include <linux/kvm_para.h>
19
#include <linux/cpuidle_haltpoll.h>
20
21
static bool force __read_mostly;
22
module_param(force, bool, 0444);
23
MODULE_PARM_DESC(force, "Load unconditionally");
24
25
static struct cpuidle_device __percpu *haltpoll_cpuidle_devices;
26
static enum cpuhp_state haltpoll_hp_state;
27
28
static __cpuidle int default_enter_idle(struct cpuidle_device *dev,
29
struct cpuidle_driver *drv, int index)
30
{
31
if (current_clr_polling_and_test())
32
return index;
33
34
arch_cpu_idle();
35
return index;
36
}
37
38
static struct cpuidle_driver haltpoll_driver = {
39
.name = "haltpoll",
40
.governor = "haltpoll",
41
.states = {
42
{ /* entry 0 is for polling */ },
43
{
44
.enter = default_enter_idle,
45
.exit_latency = 1,
46
.target_residency = 1,
47
.power_usage = -1,
48
.name = "haltpoll idle",
49
.desc = "default architecture idle",
50
},
51
},
52
.safe_state_index = 0,
53
.state_count = 2,
54
};
55
56
static int haltpoll_cpu_online(unsigned int cpu)
57
{
58
struct cpuidle_device *dev;
59
60
dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu);
61
if (!dev->registered) {
62
dev->cpu = cpu;
63
if (cpuidle_register_device(dev)) {
64
pr_notice("cpuidle_register_device %d failed!\n", cpu);
65
return -EIO;
66
}
67
arch_haltpoll_enable(cpu);
68
}
69
70
return 0;
71
}
72
73
static int haltpoll_cpu_offline(unsigned int cpu)
74
{
75
struct cpuidle_device *dev;
76
77
dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu);
78
if (dev->registered) {
79
arch_haltpoll_disable(cpu);
80
cpuidle_unregister_device(dev);
81
}
82
83
return 0;
84
}
85
86
static void haltpoll_uninit(void)
87
{
88
if (haltpoll_hp_state)
89
cpuhp_remove_state(haltpoll_hp_state);
90
cpuidle_unregister_driver(&haltpoll_driver);
91
92
free_percpu(haltpoll_cpuidle_devices);
93
haltpoll_cpuidle_devices = NULL;
94
}
95
96
static bool haltpoll_want(void)
97
{
98
return kvm_para_has_hint(KVM_HINTS_REALTIME) || force;
99
}
100
101
static int __init haltpoll_init(void)
102
{
103
int ret;
104
struct cpuidle_driver *drv = &haltpoll_driver;
105
106
/* Do not load haltpoll if idle= is passed */
107
if (boot_option_idle_override != IDLE_NO_OVERRIDE)
108
return -ENODEV;
109
110
if (!kvm_para_available() || !haltpoll_want())
111
return -ENODEV;
112
113
cpuidle_poll_state_init(drv);
114
115
ret = cpuidle_register_driver(drv);
116
if (ret < 0)
117
return ret;
118
119
haltpoll_cpuidle_devices = alloc_percpu(struct cpuidle_device);
120
if (haltpoll_cpuidle_devices == NULL) {
121
cpuidle_unregister_driver(drv);
122
return -ENOMEM;
123
}
124
125
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "cpuidle/haltpoll:online",
126
haltpoll_cpu_online, haltpoll_cpu_offline);
127
if (ret < 0) {
128
haltpoll_uninit();
129
} else {
130
haltpoll_hp_state = ret;
131
ret = 0;
132
}
133
134
return ret;
135
}
136
137
static void __exit haltpoll_exit(void)
138
{
139
haltpoll_uninit();
140
}
141
142
module_init(haltpoll_init);
143
module_exit(haltpoll_exit);
144
MODULE_DESCRIPTION("cpuidle driver for haltpoll governor");
145
MODULE_LICENSE("GPL");
146
MODULE_AUTHOR("Marcelo Tosatti <[email protected]>");
147
148