Commit 6e797a078824b30afbfae6cc4b1c2b21c51761ef

Authored by Rafael J. Wysocki
1 parent dc7fd275ae

PM / cpuidle: Add driver reference counter

Add a reference counter for the cpuidle driver, so that it can't
be unregistered when it is in use.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>

Showing 2 changed files with 33 additions and 2 deletions Side-by-side Diff

drivers/cpuidle/driver.c
... ... @@ -16,6 +16,7 @@
16 16  
17 17 static struct cpuidle_driver *cpuidle_curr_driver;
18 18 DEFINE_SPINLOCK(cpuidle_driver_lock);
  19 +int cpuidle_driver_refcount;
19 20  
20 21 static void __cpuidle_register_driver(struct cpuidle_driver *drv)
21 22 {
22 23  
... ... @@ -89,9 +90,35 @@
89 90 }
90 91  
91 92 spin_lock(&cpuidle_driver_lock);
92   - cpuidle_curr_driver = NULL;
  93 +
  94 + if (!WARN_ON(cpuidle_driver_refcount > 0))
  95 + cpuidle_curr_driver = NULL;
  96 +
93 97 spin_unlock(&cpuidle_driver_lock);
94 98 }
95 99  
96 100 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
  101 +
  102 +struct cpuidle_driver *cpuidle_driver_ref(void)
  103 +{
  104 + struct cpuidle_driver *drv;
  105 +
  106 + spin_lock(&cpuidle_driver_lock);
  107 +
  108 + drv = cpuidle_curr_driver;
  109 + cpuidle_driver_refcount++;
  110 +
  111 + spin_unlock(&cpuidle_driver_lock);
  112 + return drv;
  113 +}
  114 +
  115 +void cpuidle_driver_unref(void)
  116 +{
  117 + spin_lock(&cpuidle_driver_lock);
  118 +
  119 + if (!WARN_ON(cpuidle_driver_refcount <= 0))
  120 + cpuidle_driver_refcount--;
  121 +
  122 + spin_unlock(&cpuidle_driver_lock);
  123 +}
include/linux/cpuidle.h
... ... @@ -136,7 +136,9 @@
136 136 extern void disable_cpuidle(void);
137 137 extern int cpuidle_idle_call(void);
138 138 extern int cpuidle_register_driver(struct cpuidle_driver *drv);
139   -struct cpuidle_driver *cpuidle_get_driver(void);
  139 +extern struct cpuidle_driver *cpuidle_get_driver(void);
  140 +extern struct cpuidle_driver *cpuidle_driver_ref(void);
  141 +extern void cpuidle_driver_unref(void);
140 142 extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
141 143 extern int cpuidle_register_device(struct cpuidle_device *dev);
142 144 extern void cpuidle_unregister_device(struct cpuidle_device *dev);
... ... @@ -157,6 +159,8 @@
157 159 static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
158 160 {return -ENODEV; }
159 161 static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
  162 +static inline struct cpuidle_driver *cpuidle_driver_ref(void) {return NULL; }
  163 +static inline void cpuidle_driver_unref(void) {}
160 164 static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
161 165 static inline int cpuidle_register_device(struct cpuidle_device *dev)
162 166 {return -ENODEV; }