Commit 6e797a078824b30afbfae6cc4b1c2b21c51761ef
1 parent
dc7fd275ae
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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; } |