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>
23 static unsigned int guest_halt_poll_ns __read_mostly
= 200000;
24 module_param(guest_halt_poll_ns
, uint
, 0644);
26 /* division factor to shrink halt_poll_ns */
27 static unsigned int guest_halt_poll_shrink __read_mostly
= 2;
28 module_param(guest_halt_poll_shrink
, uint
, 0644);
30 /* multiplication factor to grow per-cpu poll_limit_ns */
31 static unsigned int guest_halt_poll_grow __read_mostly
= 2;
32 module_param(guest_halt_poll_grow
, uint
, 0644);
34 /* value in us to start growing per-cpu halt_poll_ns */
35 static unsigned int guest_halt_poll_grow_start __read_mostly
= 50000;
36 module_param(guest_halt_poll_grow_start
, uint
, 0644);
38 /* allow shrinking guest halt poll */
39 static bool guest_halt_poll_allow_shrink __read_mostly
= true;
40 module_param(guest_halt_poll_allow_shrink
, bool, 0644);
43 * haltpoll_select - selects the next idle state to enter
44 * @drv: cpuidle driver containing state data
46 * @stop_tick: indication on whether or not to stop the tick
48 static int haltpoll_select(struct cpuidle_driver
*drv
,
49 struct cpuidle_device
*dev
,
52 s64 latency_req
= cpuidle_governor_latency_req(dev
->cpu
);
54 if (!drv
->state_count
|| latency_req
== 0) {
59 if (dev
->poll_limit_ns
== 0)
62 /* Last state was poll? */
63 if (dev
->last_state_idx
== 0) {
64 /* Halt if no event occurred on poll window */
65 if (dev
->poll_time_limit
== true)
69 /* Otherwise, poll again */
74 /* Last state was halt: poll */
78 static void adjust_poll_limit(struct cpuidle_device
*dev
, u64 block_ns
)
82 /* Grow cpu_halt_poll_us if
83 * cpu_halt_poll_us < block_ns < guest_halt_poll_us
85 if (block_ns
> dev
->poll_limit_ns
&& block_ns
<= guest_halt_poll_ns
) {
86 val
= dev
->poll_limit_ns
* guest_halt_poll_grow
;
88 if (val
< guest_halt_poll_grow_start
)
89 val
= guest_halt_poll_grow_start
;
90 if (val
> guest_halt_poll_ns
)
91 val
= guest_halt_poll_ns
;
93 dev
->poll_limit_ns
= val
;
94 } else if (block_ns
> guest_halt_poll_ns
&&
95 guest_halt_poll_allow_shrink
) {
96 unsigned int shrink
= guest_halt_poll_shrink
;
98 val
= dev
->poll_limit_ns
;
103 dev
->poll_limit_ns
= val
;
108 * haltpoll_reflect - update variables and update poll time
110 * @index: the index of actual entered state
112 static void haltpoll_reflect(struct cpuidle_device
*dev
, int index
)
114 dev
->last_state_idx
= index
;
117 adjust_poll_limit(dev
, dev
->last_residency_ns
);
121 * haltpoll_enable_device - scans a CPU's states and does setup
122 * @drv: cpuidle driver
125 static int haltpoll_enable_device(struct cpuidle_driver
*drv
,
126 struct cpuidle_device
*dev
)
128 dev
->poll_limit_ns
= 0;
133 static struct cpuidle_governor haltpoll_governor
= {
136 .enable
= haltpoll_enable_device
,
137 .select
= haltpoll_select
,
138 .reflect
= haltpoll_reflect
,
141 static int __init
init_haltpoll(void)
143 if (kvm_para_available())
144 return cpuidle_register_governor(&haltpoll_governor
);
149 postcore_initcall(init_haltpoll
);