root/kernel/cpu_pm.c

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

DEFINITIONS

This source file includes following definitions.
  1. cpu_pm_notify
  2. cpu_pm_register_notifier
  3. cpu_pm_unregister_notifier
  4. cpu_pm_enter
  5. cpu_pm_exit
  6. cpu_cluster_pm_enter
  7. cpu_cluster_pm_exit
  8. cpu_pm_suspend
  9. cpu_pm_resume
  10. cpu_pm_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2011 Google, Inc.
   4  *
   5  * Author:
   6  *      Colin Cross <ccross@android.com>
   7  */
   8 
   9 #include <linux/kernel.h>
  10 #include <linux/cpu_pm.h>
  11 #include <linux/module.h>
  12 #include <linux/notifier.h>
  13 #include <linux/spinlock.h>
  14 #include <linux/syscore_ops.h>
  15 
  16 static ATOMIC_NOTIFIER_HEAD(cpu_pm_notifier_chain);
  17 
  18 static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls)
  19 {
  20         int ret;
  21 
  22         /*
  23          * __atomic_notifier_call_chain has a RCU read critical section, which
  24          * could be disfunctional in cpu idle. Copy RCU_NONIDLE code to let
  25          * RCU know this.
  26          */
  27         rcu_irq_enter_irqson();
  28         ret = __atomic_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL,
  29                 nr_to_call, nr_calls);
  30         rcu_irq_exit_irqson();
  31 
  32         return notifier_to_errno(ret);
  33 }
  34 
  35 /**
  36  * cpu_pm_register_notifier - register a driver with cpu_pm
  37  * @nb: notifier block to register
  38  *
  39  * Add a driver to a list of drivers that are notified about
  40  * CPU and CPU cluster low power entry and exit.
  41  *
  42  * This function may sleep, and has the same return conditions as
  43  * raw_notifier_chain_register.
  44  */
  45 int cpu_pm_register_notifier(struct notifier_block *nb)
  46 {
  47         return atomic_notifier_chain_register(&cpu_pm_notifier_chain, nb);
  48 }
  49 EXPORT_SYMBOL_GPL(cpu_pm_register_notifier);
  50 
  51 /**
  52  * cpu_pm_unregister_notifier - unregister a driver with cpu_pm
  53  * @nb: notifier block to be unregistered
  54  *
  55  * Remove a driver from the CPU PM notifier list.
  56  *
  57  * This function may sleep, and has the same return conditions as
  58  * raw_notifier_chain_unregister.
  59  */
  60 int cpu_pm_unregister_notifier(struct notifier_block *nb)
  61 {
  62         return atomic_notifier_chain_unregister(&cpu_pm_notifier_chain, nb);
  63 }
  64 EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
  65 
  66 /**
  67  * cpu_pm_enter - CPU low power entry notifier
  68  *
  69  * Notifies listeners that a single CPU is entering a low power state that may
  70  * cause some blocks in the same power domain as the cpu to reset.
  71  *
  72  * Must be called on the affected CPU with interrupts disabled.  Platform is
  73  * responsible for ensuring that cpu_pm_enter is not called twice on the same
  74  * CPU before cpu_pm_exit is called. Notified drivers can include VFP
  75  * co-processor, interrupt controller and its PM extensions, local CPU
  76  * timers context save/restore which shouldn't be interrupted. Hence it
  77  * must be called with interrupts disabled.
  78  *
  79  * Return conditions are same as __raw_notifier_call_chain.
  80  */
  81 int cpu_pm_enter(void)
  82 {
  83         int nr_calls;
  84         int ret = 0;
  85 
  86         ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
  87         if (ret)
  88                 /*
  89                  * Inform listeners (nr_calls - 1) about failure of CPU PM
  90                  * PM entry who are notified earlier to prepare for it.
  91                  */
  92                 cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL);
  93 
  94         return ret;
  95 }
  96 EXPORT_SYMBOL_GPL(cpu_pm_enter);
  97 
  98 /**
  99  * cpu_pm_exit - CPU low power exit notifier
 100  *
 101  * Notifies listeners that a single CPU is exiting a low power state that may
 102  * have caused some blocks in the same power domain as the cpu to reset.
 103  *
 104  * Notified drivers can include VFP co-processor, interrupt controller
 105  * and its PM extensions, local CPU timers context save/restore which
 106  * shouldn't be interrupted. Hence it must be called with interrupts disabled.
 107  *
 108  * Return conditions are same as __raw_notifier_call_chain.
 109  */
 110 int cpu_pm_exit(void)
 111 {
 112         return cpu_pm_notify(CPU_PM_EXIT, -1, NULL);
 113 }
 114 EXPORT_SYMBOL_GPL(cpu_pm_exit);
 115 
 116 /**
 117  * cpu_cluster_pm_enter - CPU cluster low power entry notifier
 118  *
 119  * Notifies listeners that all cpus in a power domain are entering a low power
 120  * state that may cause some blocks in the same power domain to reset.
 121  *
 122  * Must be called after cpu_pm_enter has been called on all cpus in the power
 123  * domain, and before cpu_pm_exit has been called on any cpu in the power
 124  * domain. Notified drivers can include VFP co-processor, interrupt controller
 125  * and its PM extensions, local CPU timers context save/restore which
 126  * shouldn't be interrupted. Hence it must be called with interrupts disabled.
 127  *
 128  * Must be called with interrupts disabled.
 129  *
 130  * Return conditions are same as __raw_notifier_call_chain.
 131  */
 132 int cpu_cluster_pm_enter(void)
 133 {
 134         int nr_calls;
 135         int ret = 0;
 136 
 137         ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls);
 138         if (ret)
 139                 /*
 140                  * Inform listeners (nr_calls - 1) about failure of CPU cluster
 141                  * PM entry who are notified earlier to prepare for it.
 142                  */
 143                 cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL);
 144 
 145         return ret;
 146 }
 147 EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
 148 
 149 /**
 150  * cpu_cluster_pm_exit - CPU cluster low power exit notifier
 151  *
 152  * Notifies listeners that all cpus in a power domain are exiting form a
 153  * low power state that may have caused some blocks in the same power domain
 154  * to reset.
 155  *
 156  * Must be called after cpu_cluster_pm_enter has been called for the power
 157  * domain, and before cpu_pm_exit has been called on any cpu in the power
 158  * domain. Notified drivers can include VFP co-processor, interrupt controller
 159  * and its PM extensions, local CPU timers context save/restore which
 160  * shouldn't be interrupted. Hence it must be called with interrupts disabled.
 161  *
 162  * Return conditions are same as __raw_notifier_call_chain.
 163  */
 164 int cpu_cluster_pm_exit(void)
 165 {
 166         return cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL);
 167 }
 168 EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit);
 169 
 170 #ifdef CONFIG_PM
 171 static int cpu_pm_suspend(void)
 172 {
 173         int ret;
 174 
 175         ret = cpu_pm_enter();
 176         if (ret)
 177                 return ret;
 178 
 179         ret = cpu_cluster_pm_enter();
 180         return ret;
 181 }
 182 
 183 static void cpu_pm_resume(void)
 184 {
 185         cpu_cluster_pm_exit();
 186         cpu_pm_exit();
 187 }
 188 
 189 static struct syscore_ops cpu_pm_syscore_ops = {
 190         .suspend = cpu_pm_suspend,
 191         .resume = cpu_pm_resume,
 192 };
 193 
 194 static int cpu_pm_init(void)
 195 {
 196         register_syscore_ops(&cpu_pm_syscore_ops);
 197         return 0;
 198 }
 199 core_initcall(cpu_pm_init);
 200 #endif

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