1 // SPDX-License-Identifier: GPL-2.0
3 * haltpoll.c - haltpoll idle governor
5 * Copyright 2019 Red Hat, Inc. and/or its affiliates.
7 * This work is licensed under the terms of the GNU GPL, version 2. See
8 * the COPYING file in the top-level directory.
10 * Authors: Marcelo Tosatti <mtosatti@redhat.com>
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>
24 static unsigned int guest_halt_poll_ns __read_mostly
= 200000;
25 module_param(guest_halt_poll_ns
, uint
, 0644);
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);
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);
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);
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);
44 * haltpoll_select - selects the next idle state to enter
45 * @drv: cpuidle driver containing state data
47 * @stop_tick: indication on whether or not to stop the tick
49 static int haltpoll_select(struct cpuidle_driver
*drv
,
50 struct cpuidle_device
*dev
,
53 s64 latency_req
= cpuidle_governor_latency_req(dev
->cpu
);
55 if (!drv
->state_count
|| latency_req
== 0) {
60 if (dev
->poll_limit_ns
== 0)
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)
70 /* Otherwise, poll again */
75 /* Last state was halt: poll */
79 static void adjust_poll_limit(struct cpuidle_device
*dev
, u64 block_ns
)
83 /* Grow cpu_halt_poll_us if
84 * cpu_halt_poll_us < block_ns < guest_halt_poll_us
86 if (block_ns
> dev
->poll_limit_ns
&& block_ns
<= guest_halt_poll_ns
) {
87 val
= dev
->poll_limit_ns
* guest_halt_poll_grow
;
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
;
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
;
100 val
= dev
->poll_limit_ns
;
105 /* Reset value to 0 if shrunk below grow_start */
106 if (val
< guest_halt_poll_grow_start
)
110 trace_guest_halt_poll_ns_shrink(val
, dev
->poll_limit_ns
);
111 dev
->poll_limit_ns
= val
;
116 * haltpoll_reflect - update variables and update poll time
118 * @index: the index of actual entered state
120 static void haltpoll_reflect(struct cpuidle_device
*dev
, int index
)
122 dev
->last_state_idx
= index
;
125 adjust_poll_limit(dev
, dev
->last_residency_ns
);
129 * haltpoll_enable_device - scans a CPU's states and does setup
130 * @drv: cpuidle driver
133 static int haltpoll_enable_device(struct cpuidle_driver
*drv
,
134 struct cpuidle_device
*dev
)
136 dev
->poll_limit_ns
= 0;
141 static struct cpuidle_governor haltpoll_governor
= {
144 .enable
= haltpoll_enable_device
,
145 .select
= haltpoll_select
,
146 .reflect
= haltpoll_reflect
,
149 static int __init
init_haltpoll(void)
151 if (kvm_para_available())
152 return cpuidle_register_governor(&haltpoll_governor
);
157 postcore_initcall(init_haltpoll
);