root/drivers/cpuidle/governors/haltpoll.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. haltpoll_select
  2. adjust_poll_limit
  3. haltpoll_reflect
  4. haltpoll_enable_device
  5. init_haltpoll

   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 
  23 static unsigned int guest_halt_poll_ns __read_mostly = 200000;
  24 module_param(guest_halt_poll_ns, uint, 0644);
  25 
  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);
  29 
  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);
  33 
  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);
  37 
  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);
  41 
  42 /**
  43  * haltpoll_select - selects the next idle state to enter
  44  * @drv: cpuidle driver containing state data
  45  * @dev: the CPU
  46  * @stop_tick: indication on whether or not to stop the tick
  47  */
  48 static int haltpoll_select(struct cpuidle_driver *drv,
  49                            struct cpuidle_device *dev,
  50                            bool *stop_tick)
  51 {
  52         int latency_req = cpuidle_governor_latency_req(dev->cpu);
  53 
  54         if (!drv->state_count || latency_req == 0) {
  55                 *stop_tick = false;
  56                 return 0;
  57         }
  58 
  59         if (dev->poll_limit_ns == 0)
  60                 return 1;
  61 
  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)
  66                         return 1;
  67 
  68                 *stop_tick = false;
  69                 /* Otherwise, poll again */
  70                 return 0;
  71         }
  72 
  73         *stop_tick = false;
  74         /* Last state was halt: poll */
  75         return 0;
  76 }
  77 
  78 static void adjust_poll_limit(struct cpuidle_device *dev, unsigned int block_us)
  79 {
  80         unsigned int val;
  81         u64 block_ns = block_us*NSEC_PER_USEC;
  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                 dev->poll_limit_ns = val;
  95         } else if (block_ns > guest_halt_poll_ns &&
  96                    guest_halt_poll_allow_shrink) {
  97                 unsigned int shrink = guest_halt_poll_shrink;
  98 
  99                 val = dev->poll_limit_ns;
 100                 if (shrink == 0)
 101                         val = 0;
 102                 else
 103                         val /= shrink;
 104                 dev->poll_limit_ns = val;
 105         }
 106 }
 107 
 108 /**
 109  * haltpoll_reflect - update variables and update poll time
 110  * @dev: the CPU
 111  * @index: the index of actual entered state
 112  */
 113 static void haltpoll_reflect(struct cpuidle_device *dev, int index)
 114 {
 115         dev->last_state_idx = index;
 116 
 117         if (index != 0)
 118                 adjust_poll_limit(dev, dev->last_residency);
 119 }
 120 
 121 /**
 122  * haltpoll_enable_device - scans a CPU's states and does setup
 123  * @drv: cpuidle driver
 124  * @dev: the CPU
 125  */
 126 static int haltpoll_enable_device(struct cpuidle_driver *drv,
 127                                   struct cpuidle_device *dev)
 128 {
 129         dev->poll_limit_ns = 0;
 130 
 131         return 0;
 132 }
 133 
 134 static struct cpuidle_governor haltpoll_governor = {
 135         .name =                 "haltpoll",
 136         .rating =               9,
 137         .enable =               haltpoll_enable_device,
 138         .select =               haltpoll_select,
 139         .reflect =              haltpoll_reflect,
 140 };
 141 
 142 static int __init init_haltpoll(void)
 143 {
 144         if (kvm_para_available())
 145                 return cpuidle_register_governor(&haltpoll_governor);
 146 
 147         return 0;
 148 }
 149 
 150 postcore_initcall(init_haltpoll);

/* [<][>][^][v][top][bottom][index][help] */