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 <mtosatti@redhat.com> 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 if (cpuidle_governor_latency_req(dev->cpu) == 0) { 54 *stop_tick = false; 55 return 0; 56 } 57 58 if (dev->poll_limit_ns == 0) 59 return 1; 60 61 /* Last state was poll? */ 62 if (dev->last_state_idx == 0) { 63 /* Halt if no event occurred on poll window */ 64 if (dev->poll_time_limit == true) 65 return 1; 66 67 *stop_tick = false; 68 /* Otherwise, poll again */ 69 return 0; 70 } 71 72 *stop_tick = false; 73 /* Last state was halt: poll */ 74 return 0; 75 } 76 77 static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns) 78 { 79 unsigned int val; 80 81 /* Grow cpu_halt_poll_us if 82 * cpu_halt_poll_us < block_ns < guest_halt_poll_us 83 */ 84 if (block_ns > dev->poll_limit_ns && block_ns <= guest_halt_poll_ns) { 85 val = dev->poll_limit_ns * guest_halt_poll_grow; 86 87 if (val < guest_halt_poll_grow_start) 88 val = guest_halt_poll_grow_start; 89 if (val > guest_halt_poll_ns) 90 val = guest_halt_poll_ns; 91 92 trace_guest_halt_poll_ns_grow(val, dev->poll_limit_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; 97 98 val = dev->poll_limit_ns; 99 if (shrink == 0) { 100 val = 0; 101 } else { 102 val /= shrink; 103 /* Reset value to 0 if shrunk below grow_start */ 104 if (val < guest_halt_poll_grow_start) 105 val = 0; 106 } 107 108 trace_guest_halt_poll_ns_shrink(val, dev->poll_limit_ns); 109 dev->poll_limit_ns = val; 110 } 111 } 112 113 /** 114 * haltpoll_reflect - update variables and update poll time 115 * @dev: the CPU 116 * @index: the index of actual entered state 117 */ 118 static void haltpoll_reflect(struct cpuidle_device *dev, int index) 119 { 120 dev->last_state_idx = index; 121 122 if (index != 0) 123 adjust_poll_limit(dev, dev->last_residency_ns); 124 } 125 126 /** 127 * haltpoll_enable_device - scans a CPU's states and does setup 128 * @drv: cpuidle driver 129 * @dev: the CPU 130 */ 131 static int haltpoll_enable_device(struct cpuidle_driver *drv, 132 struct cpuidle_device *dev) 133 { 134 dev->poll_limit_ns = 0; 135 136 return 0; 137 } 138 139 static struct cpuidle_governor haltpoll_governor = { 140 .name = "haltpoll", 141 .rating = 9, 142 .enable = haltpoll_enable_device, 143 .select = haltpoll_select, 144 .reflect = haltpoll_reflect, 145 }; 146 147 static int __init init_haltpoll(void) 148 { 149 if (kvm_para_available()) 150 return cpuidle_register_governor(&haltpoll_governor); 151 152 return 0; 153 } 154 155 postcore_initcall(init_haltpoll); 156