aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-05-05 15:57:28 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-05-11 15:11:16 -0400
commit4e585d25e120f1eae0a3a8bf8f6ebc7692afec18 (patch)
tree9385b0ca4d8de60c08896193a0187f5074b55496 /kernel
parentc73893e2ca731b4a81ae59246ab57979aa188777 (diff)
PM / Sleep: User space wakeup sources garbage collector Kconfig option
Make it possible to configure out the user space wakeup sources garbage collector for debugging and default Android builds. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Arve Hjønnevåg <arve@android.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/Kconfig5
-rw-r--r--kernel/power/wakelock.c101
2 files changed, 67 insertions, 39 deletions
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 08783eda9ce..8f9b4eb974e 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -125,6 +125,11 @@ config PM_WAKELOCKS_LIMIT
125 default 100 125 default 100
126 depends on PM_WAKELOCKS 126 depends on PM_WAKELOCKS
127 127
128config PM_WAKELOCKS_GC
129 bool "Garbage collector for user space wakeup sources"
130 depends on PM_WAKELOCKS
131 default y
132
128config PM_RUNTIME 133config PM_RUNTIME
129 bool "Run-time PM core functionality" 134 bool "Run-time PM core functionality"
130 depends on !IA64_HP_SIM 135 depends on !IA64_HP_SIM
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index dc34b9d3b7d..c8fba338007 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -17,21 +17,18 @@
17#include <linux/rbtree.h> 17#include <linux/rbtree.h>
18#include <linux/slab.h> 18#include <linux/slab.h>
19 19
20#define WL_GC_COUNT_MAX 100
21#define WL_GC_TIME_SEC 300
22
23static DEFINE_MUTEX(wakelocks_lock); 20static DEFINE_MUTEX(wakelocks_lock);
24 21
25struct wakelock { 22struct wakelock {
26 char *name; 23 char *name;
27 struct rb_node node; 24 struct rb_node node;
28 struct wakeup_source ws; 25 struct wakeup_source ws;
26#ifdef CONFIG_PM_WAKELOCKS_GC
29 struct list_head lru; 27 struct list_head lru;
28#endif
30}; 29};
31 30
32static struct rb_root wakelocks_tree = RB_ROOT; 31static struct rb_root wakelocks_tree = RB_ROOT;
33static LIST_HEAD(wakelocks_lru_list);
34static unsigned int wakelocks_gc_count;
35 32
36ssize_t pm_show_wakelocks(char *buf, bool show_active) 33ssize_t pm_show_wakelocks(char *buf, bool show_active)
37{ 34{
@@ -79,6 +76,61 @@ static inline void increment_wakelocks_number(void) {}
79static inline void decrement_wakelocks_number(void) {} 76static inline void decrement_wakelocks_number(void) {}
80#endif /* CONFIG_PM_WAKELOCKS_LIMIT */ 77#endif /* CONFIG_PM_WAKELOCKS_LIMIT */
81 78
79#ifdef CONFIG_PM_WAKELOCKS_GC
80#define WL_GC_COUNT_MAX 100
81#define WL_GC_TIME_SEC 300
82
83static LIST_HEAD(wakelocks_lru_list);
84static unsigned int wakelocks_gc_count;
85
86static inline void wakelocks_lru_add(struct wakelock *wl)
87{
88 list_add(&wl->lru, &wakelocks_lru_list);
89}
90
91static inline void wakelocks_lru_most_recent(struct wakelock *wl)
92{
93 list_move(&wl->lru, &wakelocks_lru_list);
94}
95
96static void wakelocks_gc(void)
97{
98 struct wakelock *wl, *aux;
99 ktime_t now;
100
101 if (++wakelocks_gc_count <= WL_GC_COUNT_MAX)
102 return;
103
104 now = ktime_get();
105 list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
106 u64 idle_time_ns;
107 bool active;
108
109 spin_lock_irq(&wl->ws.lock);
110 idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time));
111 active = wl->ws.active;
112 spin_unlock_irq(&wl->ws.lock);
113
114 if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC))
115 break;
116
117 if (!active) {
118 wakeup_source_remove(&wl->ws);
119 rb_erase(&wl->node, &wakelocks_tree);
120 list_del(&wl->lru);
121 kfree(wl->name);
122 kfree(wl);
123 decrement_wakelocks_number();
124 }
125 }
126 wakelocks_gc_count = 0;
127}
128#else /* !CONFIG_PM_WAKELOCKS_GC */
129static inline void wakelocks_lru_add(struct wakelock *wl) {}
130static inline void wakelocks_lru_most_recent(struct wakelock *wl) {}
131static inline void wakelocks_gc(void) {}
132#endif /* !CONFIG_PM_WAKELOCKS_GC */
133
82static struct wakelock *wakelock_lookup_add(const char *name, size_t len, 134static struct wakelock *wakelock_lookup_add(const char *name, size_t len,
83 bool add_if_not_found) 135 bool add_if_not_found)
84{ 136{
@@ -123,7 +175,7 @@ static struct wakelock *wakelock_lookup_add(const char *name, size_t len,
123 wakeup_source_add(&wl->ws); 175 wakeup_source_add(&wl->ws);
124 rb_link_node(&wl->node, parent, node); 176 rb_link_node(&wl->node, parent, node);
125 rb_insert_color(&wl->node, &wakelocks_tree); 177 rb_insert_color(&wl->node, &wakelocks_tree);
126 list_add(&wl->lru, &wakelocks_lru_list); 178 wakelocks_lru_add(wl);
127 increment_wakelocks_number(); 179 increment_wakelocks_number();
128 return wl; 180 return wl;
129} 181}
@@ -166,42 +218,13 @@ int pm_wake_lock(const char *buf)
166 __pm_stay_awake(&wl->ws); 218 __pm_stay_awake(&wl->ws);
167 } 219 }
168 220
169 list_move(&wl->lru, &wakelocks_lru_list); 221 wakelocks_lru_most_recent(wl);
170 222
171 out: 223 out:
172 mutex_unlock(&wakelocks_lock); 224 mutex_unlock(&wakelocks_lock);
173 return ret; 225 return ret;
174} 226}
175 227
176static void wakelocks_gc(void)
177{
178 struct wakelock *wl, *aux;
179 ktime_t now = ktime_get();
180
181 list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
182 u64 idle_time_ns;
183 bool active;
184
185 spin_lock_irq(&wl->ws.lock);
186 idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time));
187 active = wl->ws.active;
188 spin_unlock_irq(&wl->ws.lock);
189
190 if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC))
191 break;
192
193 if (!active) {
194 wakeup_source_remove(&wl->ws);
195 rb_erase(&wl->node, &wakelocks_tree);
196 list_del(&wl->lru);
197 kfree(wl->name);
198 kfree(wl);
199 decrement_wakelocks_number();
200 }
201 }
202 wakelocks_gc_count = 0;
203}
204
205int pm_wake_unlock(const char *buf) 228int pm_wake_unlock(const char *buf)
206{ 229{
207 struct wakelock *wl; 230 struct wakelock *wl;
@@ -226,9 +249,9 @@ int pm_wake_unlock(const char *buf)
226 goto out; 249 goto out;
227 } 250 }
228 __pm_relax(&wl->ws); 251 __pm_relax(&wl->ws);
229 list_move(&wl->lru, &wakelocks_lru_list); 252
230 if (++wakelocks_gc_count > WL_GC_COUNT_MAX) 253 wakelocks_lru_most_recent(wl);
231 wakelocks_gc(); 254 wakelocks_gc();
232 255
233 out: 256 out:
234 mutex_unlock(&wakelocks_lock); 257 mutex_unlock(&wakelocks_lock);