root/drivers/cpuidle/cpuidle-haltpoll.c

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

DEFINITIONS

This source file includes following definitions.
  1. default_enter_idle
  2. haltpoll_cpu_online
  3. haltpoll_cpu_offline
  4. haltpoll_uninit
  5. haltpoll_init
  6. haltpoll_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * cpuidle driver for haltpoll 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/init.h>
  14 #include <linux/cpu.h>
  15 #include <linux/cpuidle.h>
  16 #include <linux/module.h>
  17 #include <linux/sched/idle.h>
  18 #include <linux/kvm_para.h>
  19 #include <linux/cpuidle_haltpoll.h>
  20 
  21 static struct cpuidle_device __percpu *haltpoll_cpuidle_devices;
  22 static enum cpuhp_state haltpoll_hp_state;
  23 
  24 static int default_enter_idle(struct cpuidle_device *dev,
  25                               struct cpuidle_driver *drv, int index)
  26 {
  27         if (current_clr_polling_and_test()) {
  28                 local_irq_enable();
  29                 return index;
  30         }
  31         default_idle();
  32         return index;
  33 }
  34 
  35 static struct cpuidle_driver haltpoll_driver = {
  36         .name = "haltpoll",
  37         .governor = "haltpoll",
  38         .states = {
  39                 { /* entry 0 is for polling */ },
  40                 {
  41                         .enter                  = default_enter_idle,
  42                         .exit_latency           = 1,
  43                         .target_residency       = 1,
  44                         .power_usage            = -1,
  45                         .name                   = "haltpoll idle",
  46                         .desc                   = "default architecture idle",
  47                 },
  48         },
  49         .safe_state_index = 0,
  50         .state_count = 2,
  51 };
  52 
  53 static int haltpoll_cpu_online(unsigned int cpu)
  54 {
  55         struct cpuidle_device *dev;
  56 
  57         dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu);
  58         if (!dev->registered) {
  59                 dev->cpu = cpu;
  60                 if (cpuidle_register_device(dev)) {
  61                         pr_notice("cpuidle_register_device %d failed!\n", cpu);
  62                         return -EIO;
  63                 }
  64                 arch_haltpoll_enable(cpu);
  65         }
  66 
  67         return 0;
  68 }
  69 
  70 static int haltpoll_cpu_offline(unsigned int cpu)
  71 {
  72         struct cpuidle_device *dev;
  73 
  74         dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu);
  75         if (dev->registered) {
  76                 arch_haltpoll_disable(cpu);
  77                 cpuidle_unregister_device(dev);
  78         }
  79 
  80         return 0;
  81 }
  82 
  83 static void haltpoll_uninit(void)
  84 {
  85         if (haltpoll_hp_state)
  86                 cpuhp_remove_state(haltpoll_hp_state);
  87         cpuidle_unregister_driver(&haltpoll_driver);
  88 
  89         free_percpu(haltpoll_cpuidle_devices);
  90         haltpoll_cpuidle_devices = NULL;
  91 }
  92 
  93 static int __init haltpoll_init(void)
  94 {
  95         int ret;
  96         struct cpuidle_driver *drv = &haltpoll_driver;
  97 
  98         /* Do not load haltpoll if idle= is passed */
  99         if (boot_option_idle_override != IDLE_NO_OVERRIDE)
 100                 return -ENODEV;
 101 
 102         cpuidle_poll_state_init(drv);
 103 
 104         if (!kvm_para_available() ||
 105                 !kvm_para_has_hint(KVM_HINTS_REALTIME))
 106                 return -ENODEV;
 107 
 108         ret = cpuidle_register_driver(drv);
 109         if (ret < 0)
 110                 return ret;
 111 
 112         haltpoll_cpuidle_devices = alloc_percpu(struct cpuidle_device);
 113         if (haltpoll_cpuidle_devices == NULL) {
 114                 cpuidle_unregister_driver(drv);
 115                 return -ENOMEM;
 116         }
 117 
 118         ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "cpuidle/haltpoll:online",
 119                                 haltpoll_cpu_online, haltpoll_cpu_offline);
 120         if (ret < 0) {
 121                 haltpoll_uninit();
 122         } else {
 123                 haltpoll_hp_state = ret;
 124                 ret = 0;
 125         }
 126 
 127         return ret;
 128 }
 129 
 130 static void __exit haltpoll_exit(void)
 131 {
 132         haltpoll_uninit();
 133 }
 134 
 135 module_init(haltpoll_init);
 136 module_exit(haltpoll_exit);
 137 MODULE_LICENSE("GPL");
 138 MODULE_AUTHOR("Marcelo Tosatti <mtosatti@redhat.com>");

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