brintos

brintos / linux-shallow public Read only

0
0
Text · 3.9 KiB · 663b7f1 Raw
158 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * haltpoll.c - haltpoll idle governor4 *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.  See8 * 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 24static unsigned int guest_halt_poll_ns __read_mostly = 200000;25module_param(guest_halt_poll_ns, uint, 0644);26 27/* division factor to shrink halt_poll_ns */28static unsigned int guest_halt_poll_shrink __read_mostly = 2;29module_param(guest_halt_poll_shrink, uint, 0644);30 31/* multiplication factor to grow per-cpu poll_limit_ns */32static unsigned int guest_halt_poll_grow __read_mostly = 2;33module_param(guest_halt_poll_grow, uint, 0644);34 35/* value in us to start growing per-cpu halt_poll_ns */36static unsigned int guest_halt_poll_grow_start __read_mostly = 50000;37module_param(guest_halt_poll_grow_start, uint, 0644);38 39/* allow shrinking guest halt poll */40static bool guest_halt_poll_allow_shrink __read_mostly = true;41module_param(guest_halt_poll_allow_shrink, bool, 0644);42 43/**44 * haltpoll_select - selects the next idle state to enter45 * @drv: cpuidle driver containing state data46 * @dev: the CPU47 * @stop_tick: indication on whether or not to stop the tick48 */49static 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 79static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns)80{81	unsigned int val;82 83	/* Grow cpu_halt_poll_us if84	 * cpu_halt_poll_us < block_ns < guest_halt_poll_us85	 */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 time117 * @dev: the CPU118 * @index: the index of actual entered state119 */120static 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 setup130 * @drv: cpuidle driver131 * @dev: the CPU132 */133static 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 141static 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 149static int __init init_haltpoll(void)150{151	if (kvm_para_available())152		return cpuidle_register_governor(&haltpoll_governor);153 154	return 0;155}156 157postcore_initcall(init_haltpoll);158