Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/cpuidle/governors/haltpoll.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* haltpoll.c - haltpoll idle 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/kernel.h>
14
#include <linux/cpuidle.h>
15
#include <linux/time.h>
16
#include <linux/ktime.h>
17
#include <linux/hrtimer.h>
18
#include <linux/tick.h>
19
#include <linux/sched.h>
20
#include <linux/module.h>
21
#include <linux/kvm_para.h>
22
#include <trace/events/power.h>
23
24
static unsigned int guest_halt_poll_ns __read_mostly = 200000;
25
module_param(guest_halt_poll_ns, uint, 0644);
26
27
/* division factor to shrink halt_poll_ns */
28
static unsigned int guest_halt_poll_shrink __read_mostly = 2;
29
module_param(guest_halt_poll_shrink, uint, 0644);
30
31
/* multiplication factor to grow per-cpu poll_limit_ns */
32
static unsigned int guest_halt_poll_grow __read_mostly = 2;
33
module_param(guest_halt_poll_grow, uint, 0644);
34
35
/* value in us to start growing per-cpu halt_poll_ns */
36
static unsigned int guest_halt_poll_grow_start __read_mostly = 50000;
37
module_param(guest_halt_poll_grow_start, uint, 0644);
38
39
/* allow shrinking guest halt poll */
40
static bool guest_halt_poll_allow_shrink __read_mostly = true;
41
module_param(guest_halt_poll_allow_shrink, bool, 0644);
42
43
/**
44
* haltpoll_select - selects the next idle state to enter
45
* @drv: cpuidle driver containing state data
46
* @dev: the CPU
47
* @stop_tick: indication on whether or not to stop the tick
48
*/
49
static int haltpoll_select(struct cpuidle_driver *drv,
50
struct cpuidle_device *dev,
51
bool *stop_tick)
52
{
53
s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
54
55
if (!drv->state_count || latency_req == 0) {
56
*stop_tick = false;
57
return 0;
58
}
59
60
if (dev->poll_limit_ns == 0)
61
return 1;
62
63
/* Last state was poll? */
64
if (dev->last_state_idx == 0) {
65
/* Halt if no event occurred on poll window */
66
if (dev->poll_time_limit == true)
67
return 1;
68
69
*stop_tick = false;
70
/* Otherwise, poll again */
71
return 0;
72
}
73
74
*stop_tick = false;
75
/* Last state was halt: poll */
76
return 0;
77
}
78
79
static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns)
80
{
81
unsigned int val;
82
83
/* Grow cpu_halt_poll_us if
84
* cpu_halt_poll_us < block_ns < guest_halt_poll_us
85
*/
86
if (block_ns > dev->poll_limit_ns && block_ns <= guest_halt_poll_ns) {
87
val = dev->poll_limit_ns * guest_halt_poll_grow;
88
89
if (val < guest_halt_poll_grow_start)
90
val = guest_halt_poll_grow_start;
91
if (val > guest_halt_poll_ns)
92
val = guest_halt_poll_ns;
93
94
trace_guest_halt_poll_ns_grow(val, dev->poll_limit_ns);
95
dev->poll_limit_ns = val;
96
} else if (block_ns > guest_halt_poll_ns &&
97
guest_halt_poll_allow_shrink) {
98
unsigned int shrink = guest_halt_poll_shrink;
99
100
val = dev->poll_limit_ns;
101
if (shrink == 0) {
102
val = 0;
103
} else {
104
val /= shrink;
105
/* Reset value to 0 if shrunk below grow_start */
106
if (val < guest_halt_poll_grow_start)
107
val = 0;
108
}
109
110
trace_guest_halt_poll_ns_shrink(val, dev->poll_limit_ns);
111
dev->poll_limit_ns = val;
112
}
113
}
114
115
/**
116
* haltpoll_reflect - update variables and update poll time
117
* @dev: the CPU
118
* @index: the index of actual entered state
119
*/
120
static void haltpoll_reflect(struct cpuidle_device *dev, int index)
121
{
122
dev->last_state_idx = index;
123
124
if (index != 0)
125
adjust_poll_limit(dev, dev->last_residency_ns);
126
}
127
128
/**
129
* haltpoll_enable_device - scans a CPU's states and does setup
130
* @drv: cpuidle driver
131
* @dev: the CPU
132
*/
133
static int haltpoll_enable_device(struct cpuidle_driver *drv,
134
struct cpuidle_device *dev)
135
{
136
dev->poll_limit_ns = 0;
137
138
return 0;
139
}
140
141
static struct cpuidle_governor haltpoll_governor = {
142
.name = "haltpoll",
143
.rating = 9,
144
.enable = haltpoll_enable_device,
145
.select = haltpoll_select,
146
.reflect = haltpoll_reflect,
147
};
148
149
static int __init init_haltpoll(void)
150
{
151
if (kvm_para_available())
152
return cpuidle_register_governor(&haltpoll_governor);
153
154
return 0;
155
}
156
157
postcore_initcall(init_haltpoll);
158
159