diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/power/clock_ops.c | 123 | ||||
-rw-r--r-- | drivers/base/power/common.c | 86 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 346 |
4 files changed, 341 insertions, 216 deletions
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 2639ae79a37..6488ce12f58 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-$(CONFIG_PM) += sysfs.o generic_ops.o | 1 | obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o |
2 | obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o | 2 | obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o |
3 | obj-$(CONFIG_PM_RUNTIME) += runtime.o | 3 | obj-$(CONFIG_PM_RUNTIME) += runtime.o |
4 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o | 4 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o |
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index b97294e2d95..b876e60a53e 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c | |||
@@ -10,18 +10,13 @@ | |||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/io.h> | 11 | #include <linux/io.h> |
12 | #include <linux/pm.h> | 12 | #include <linux/pm.h> |
13 | #include <linux/pm_runtime.h> | 13 | #include <linux/pm_clock.h> |
14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | 17 | ||
18 | #ifdef CONFIG_PM | 18 | #ifdef CONFIG_PM |
19 | 19 | ||
20 | struct pm_clk_data { | ||
21 | struct list_head clock_list; | ||
22 | spinlock_t lock; | ||
23 | }; | ||
24 | |||
25 | enum pce_status { | 20 | enum pce_status { |
26 | PCE_STATUS_NONE = 0, | 21 | PCE_STATUS_NONE = 0, |
27 | PCE_STATUS_ACQUIRED, | 22 | PCE_STATUS_ACQUIRED, |
@@ -36,11 +31,6 @@ struct pm_clock_entry { | |||
36 | enum pce_status status; | 31 | enum pce_status status; |
37 | }; | 32 | }; |
38 | 33 | ||
39 | static struct pm_clk_data *__to_pcd(struct device *dev) | ||
40 | { | ||
41 | return dev ? dev->power.subsys_data : NULL; | ||
42 | } | ||
43 | |||
44 | /** | 34 | /** |
45 | * pm_clk_acquire - Acquire a device clock. | 35 | * pm_clk_acquire - Acquire a device clock. |
46 | * @dev: Device whose clock is to be acquired. | 36 | * @dev: Device whose clock is to be acquired. |
@@ -67,10 +57,10 @@ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) | |||
67 | */ | 57 | */ |
68 | int pm_clk_add(struct device *dev, const char *con_id) | 58 | int pm_clk_add(struct device *dev, const char *con_id) |
69 | { | 59 | { |
70 | struct pm_clk_data *pcd = __to_pcd(dev); | 60 | struct pm_subsys_data *psd = dev_to_psd(dev); |
71 | struct pm_clock_entry *ce; | 61 | struct pm_clock_entry *ce; |
72 | 62 | ||
73 | if (!pcd) | 63 | if (!psd) |
74 | return -EINVAL; | 64 | return -EINVAL; |
75 | 65 | ||
76 | ce = kzalloc(sizeof(*ce), GFP_KERNEL); | 66 | ce = kzalloc(sizeof(*ce), GFP_KERNEL); |
@@ -91,9 +81,9 @@ int pm_clk_add(struct device *dev, const char *con_id) | |||
91 | 81 | ||
92 | pm_clk_acquire(dev, ce); | 82 | pm_clk_acquire(dev, ce); |
93 | 83 | ||
94 | spin_lock_irq(&pcd->lock); | 84 | spin_lock_irq(&psd->lock); |
95 | list_add_tail(&ce->node, &pcd->clock_list); | 85 | list_add_tail(&ce->node, &psd->clock_list); |
96 | spin_unlock_irq(&pcd->lock); | 86 | spin_unlock_irq(&psd->lock); |
97 | return 0; | 87 | return 0; |
98 | } | 88 | } |
99 | 89 | ||
@@ -130,15 +120,15 @@ static void __pm_clk_remove(struct pm_clock_entry *ce) | |||
130 | */ | 120 | */ |
131 | void pm_clk_remove(struct device *dev, const char *con_id) | 121 | void pm_clk_remove(struct device *dev, const char *con_id) |
132 | { | 122 | { |
133 | struct pm_clk_data *pcd = __to_pcd(dev); | 123 | struct pm_subsys_data *psd = dev_to_psd(dev); |
134 | struct pm_clock_entry *ce; | 124 | struct pm_clock_entry *ce; |
135 | 125 | ||
136 | if (!pcd) | 126 | if (!psd) |
137 | return; | 127 | return; |
138 | 128 | ||
139 | spin_lock_irq(&pcd->lock); | 129 | spin_lock_irq(&psd->lock); |
140 | 130 | ||
141 | list_for_each_entry(ce, &pcd->clock_list, node) { | 131 | list_for_each_entry(ce, &psd->clock_list, node) { |
142 | if (!con_id && !ce->con_id) | 132 | if (!con_id && !ce->con_id) |
143 | goto remove; | 133 | goto remove; |
144 | else if (!con_id || !ce->con_id) | 134 | else if (!con_id || !ce->con_id) |
@@ -147,12 +137,12 @@ void pm_clk_remove(struct device *dev, const char *con_id) | |||
147 | goto remove; | 137 | goto remove; |
148 | } | 138 | } |
149 | 139 | ||
150 | spin_unlock_irq(&pcd->lock); | 140 | spin_unlock_irq(&psd->lock); |
151 | return; | 141 | return; |
152 | 142 | ||
153 | remove: | 143 | remove: |
154 | list_del(&ce->node); | 144 | list_del(&ce->node); |
155 | spin_unlock_irq(&pcd->lock); | 145 | spin_unlock_irq(&psd->lock); |
156 | 146 | ||
157 | __pm_clk_remove(ce); | 147 | __pm_clk_remove(ce); |
158 | } | 148 | } |
@@ -161,23 +151,27 @@ void pm_clk_remove(struct device *dev, const char *con_id) | |||
161 | * pm_clk_init - Initialize a device's list of power management clocks. | 151 | * pm_clk_init - Initialize a device's list of power management clocks. |
162 | * @dev: Device to initialize the list of PM clocks for. | 152 | * @dev: Device to initialize the list of PM clocks for. |
163 | * | 153 | * |
164 | * Allocate a struct pm_clk_data object, initialize its lock member and | 154 | * Initialize the lock and clock_list members of the device's pm_subsys_data |
165 | * make the @dev's power.subsys_data field point to it. | 155 | * object. |
166 | */ | 156 | */ |
167 | int pm_clk_init(struct device *dev) | 157 | void pm_clk_init(struct device *dev) |
168 | { | 158 | { |
169 | struct pm_clk_data *pcd; | 159 | struct pm_subsys_data *psd = dev_to_psd(dev); |
170 | 160 | if (psd) | |
171 | pcd = kzalloc(sizeof(*pcd), GFP_KERNEL); | 161 | INIT_LIST_HEAD(&psd->clock_list); |
172 | if (!pcd) { | 162 | } |
173 | dev_err(dev, "Not enough memory for PM clock data.\n"); | ||
174 | return -ENOMEM; | ||
175 | } | ||
176 | 163 | ||
177 | INIT_LIST_HEAD(&pcd->clock_list); | 164 | /** |
178 | spin_lock_init(&pcd->lock); | 165 | * pm_clk_create - Create and initialize a device's list of PM clocks. |
179 | dev->power.subsys_data = pcd; | 166 | * @dev: Device to create and initialize the list of PM clocks for. |
180 | return 0; | 167 | * |
168 | * Allocate a struct pm_subsys_data object, initialize its lock and clock_list | ||
169 | * members and make the @dev's power.subsys_data field point to it. | ||
170 | */ | ||
171 | int pm_clk_create(struct device *dev) | ||
172 | { | ||
173 | int ret = dev_pm_get_subsys_data(dev); | ||
174 | return ret < 0 ? ret : 0; | ||
181 | } | 175 | } |
182 | 176 | ||
183 | /** | 177 | /** |
@@ -185,29 +179,28 @@ int pm_clk_init(struct device *dev) | |||
185 | * @dev: Device to destroy the list of PM clocks for. | 179 | * @dev: Device to destroy the list of PM clocks for. |
186 | * | 180 | * |
187 | * Clear the @dev's power.subsys_data field, remove the list of clock entries | 181 | * Clear the @dev's power.subsys_data field, remove the list of clock entries |
188 | * from the struct pm_clk_data object pointed to by it before and free | 182 | * from the struct pm_subsys_data object pointed to by it before and free |
189 | * that object. | 183 | * that object. |
190 | */ | 184 | */ |
191 | void pm_clk_destroy(struct device *dev) | 185 | void pm_clk_destroy(struct device *dev) |
192 | { | 186 | { |
193 | struct pm_clk_data *pcd = __to_pcd(dev); | 187 | struct pm_subsys_data *psd = dev_to_psd(dev); |
194 | struct pm_clock_entry *ce, *c; | 188 | struct pm_clock_entry *ce, *c; |
195 | struct list_head list; | 189 | struct list_head list; |
196 | 190 | ||
197 | if (!pcd) | 191 | if (!psd) |
198 | return; | 192 | return; |
199 | 193 | ||
200 | dev->power.subsys_data = NULL; | ||
201 | INIT_LIST_HEAD(&list); | 194 | INIT_LIST_HEAD(&list); |
202 | 195 | ||
203 | spin_lock_irq(&pcd->lock); | 196 | spin_lock_irq(&psd->lock); |
204 | 197 | ||
205 | list_for_each_entry_safe_reverse(ce, c, &pcd->clock_list, node) | 198 | list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node) |
206 | list_move(&ce->node, &list); | 199 | list_move(&ce->node, &list); |
207 | 200 | ||
208 | spin_unlock_irq(&pcd->lock); | 201 | spin_unlock_irq(&psd->lock); |
209 | 202 | ||
210 | kfree(pcd); | 203 | dev_pm_put_subsys_data(dev); |
211 | 204 | ||
212 | list_for_each_entry_safe_reverse(ce, c, &list, node) { | 205 | list_for_each_entry_safe_reverse(ce, c, &list, node) { |
213 | list_del(&ce->node); | 206 | list_del(&ce->node); |
@@ -225,25 +218,25 @@ void pm_clk_destroy(struct device *dev) | |||
225 | */ | 218 | */ |
226 | int pm_clk_suspend(struct device *dev) | 219 | int pm_clk_suspend(struct device *dev) |
227 | { | 220 | { |
228 | struct pm_clk_data *pcd = __to_pcd(dev); | 221 | struct pm_subsys_data *psd = dev_to_psd(dev); |
229 | struct pm_clock_entry *ce; | 222 | struct pm_clock_entry *ce; |
230 | unsigned long flags; | 223 | unsigned long flags; |
231 | 224 | ||
232 | dev_dbg(dev, "%s()\n", __func__); | 225 | dev_dbg(dev, "%s()\n", __func__); |
233 | 226 | ||
234 | if (!pcd) | 227 | if (!psd) |
235 | return 0; | 228 | return 0; |
236 | 229 | ||
237 | spin_lock_irqsave(&pcd->lock, flags); | 230 | spin_lock_irqsave(&psd->lock, flags); |
238 | 231 | ||
239 | list_for_each_entry_reverse(ce, &pcd->clock_list, node) { | 232 | list_for_each_entry_reverse(ce, &psd->clock_list, node) { |
240 | if (ce->status < PCE_STATUS_ERROR) { | 233 | if (ce->status < PCE_STATUS_ERROR) { |
241 | clk_disable(ce->clk); | 234 | clk_disable(ce->clk); |
242 | ce->status = PCE_STATUS_ACQUIRED; | 235 | ce->status = PCE_STATUS_ACQUIRED; |
243 | } | 236 | } |
244 | } | 237 | } |
245 | 238 | ||
246 | spin_unlock_irqrestore(&pcd->lock, flags); | 239 | spin_unlock_irqrestore(&psd->lock, flags); |
247 | 240 | ||
248 | return 0; | 241 | return 0; |
249 | } | 242 | } |
@@ -254,25 +247,25 @@ int pm_clk_suspend(struct device *dev) | |||
254 | */ | 247 | */ |
255 | int pm_clk_resume(struct device *dev) | 248 | int pm_clk_resume(struct device *dev) |
256 | { | 249 | { |
257 | struct pm_clk_data *pcd = __to_pcd(dev); | 250 | struct pm_subsys_data *psd = dev_to_psd(dev); |
258 | struct pm_clock_entry *ce; | 251 | struct pm_clock_entry *ce; |
259 | unsigned long flags; | 252 | unsigned long flags; |
260 | 253 | ||
261 | dev_dbg(dev, "%s()\n", __func__); | 254 | dev_dbg(dev, "%s()\n", __func__); |
262 | 255 | ||
263 | if (!pcd) | 256 | if (!psd) |
264 | return 0; | 257 | return 0; |
265 | 258 | ||
266 | spin_lock_irqsave(&pcd->lock, flags); | 259 | spin_lock_irqsave(&psd->lock, flags); |
267 | 260 | ||
268 | list_for_each_entry(ce, &pcd->clock_list, node) { | 261 | list_for_each_entry(ce, &psd->clock_list, node) { |
269 | if (ce->status < PCE_STATUS_ERROR) { | 262 | if (ce->status < PCE_STATUS_ERROR) { |
270 | clk_enable(ce->clk); | 263 | clk_enable(ce->clk); |
271 | ce->status = PCE_STATUS_ENABLED; | 264 | ce->status = PCE_STATUS_ENABLED; |
272 | } | 265 | } |
273 | } | 266 | } |
274 | 267 | ||
275 | spin_unlock_irqrestore(&pcd->lock, flags); | 268 | spin_unlock_irqrestore(&psd->lock, flags); |
276 | 269 | ||
277 | return 0; | 270 | return 0; |
278 | } | 271 | } |
@@ -310,7 +303,7 @@ static int pm_clk_notify(struct notifier_block *nb, | |||
310 | if (dev->pm_domain) | 303 | if (dev->pm_domain) |
311 | break; | 304 | break; |
312 | 305 | ||
313 | error = pm_clk_init(dev); | 306 | error = pm_clk_create(dev); |
314 | if (error) | 307 | if (error) |
315 | break; | 308 | break; |
316 | 309 | ||
@@ -345,22 +338,22 @@ static int pm_clk_notify(struct notifier_block *nb, | |||
345 | */ | 338 | */ |
346 | int pm_clk_suspend(struct device *dev) | 339 | int pm_clk_suspend(struct device *dev) |
347 | { | 340 | { |
348 | struct pm_clk_data *pcd = __to_pcd(dev); | 341 | struct pm_subsys_data *psd = dev_to_psd(dev); |
349 | struct pm_clock_entry *ce; | 342 | struct pm_clock_entry *ce; |
350 | unsigned long flags; | 343 | unsigned long flags; |
351 | 344 | ||
352 | dev_dbg(dev, "%s()\n", __func__); | 345 | dev_dbg(dev, "%s()\n", __func__); |
353 | 346 | ||
354 | /* If there is no driver, the clocks are already disabled. */ | 347 | /* If there is no driver, the clocks are already disabled. */ |
355 | if (!pcd || !dev->driver) | 348 | if (!psd || !dev->driver) |
356 | return 0; | 349 | return 0; |
357 | 350 | ||
358 | spin_lock_irqsave(&pcd->lock, flags); | 351 | spin_lock_irqsave(&psd->lock, flags); |
359 | 352 | ||
360 | list_for_each_entry_reverse(ce, &pcd->clock_list, node) | 353 | list_for_each_entry_reverse(ce, &psd->clock_list, node) |
361 | clk_disable(ce->clk); | 354 | clk_disable(ce->clk); |
362 | 355 | ||
363 | spin_unlock_irqrestore(&pcd->lock, flags); | 356 | spin_unlock_irqrestore(&psd->lock, flags); |
364 | 357 | ||
365 | return 0; | 358 | return 0; |
366 | } | 359 | } |
@@ -371,22 +364,22 @@ int pm_clk_suspend(struct device *dev) | |||
371 | */ | 364 | */ |
372 | int pm_clk_resume(struct device *dev) | 365 | int pm_clk_resume(struct device *dev) |
373 | { | 366 | { |
374 | struct pm_clk_data *pcd = __to_pcd(dev); | 367 | struct pm_subsys_data *psd = dev_to_psd(dev); |
375 | struct pm_clock_entry *ce; | 368 | struct pm_clock_entry *ce; |
376 | unsigned long flags; | 369 | unsigned long flags; |
377 | 370 | ||
378 | dev_dbg(dev, "%s()\n", __func__); | 371 | dev_dbg(dev, "%s()\n", __func__); |
379 | 372 | ||
380 | /* If there is no driver, the clocks should remain disabled. */ | 373 | /* If there is no driver, the clocks should remain disabled. */ |
381 | if (!pcd || !dev->driver) | 374 | if (!psd || !dev->driver) |
382 | return 0; | 375 | return 0; |
383 | 376 | ||
384 | spin_lock_irqsave(&pcd->lock, flags); | 377 | spin_lock_irqsave(&psd->lock, flags); |
385 | 378 | ||
386 | list_for_each_entry(ce, &pcd->clock_list, node) | 379 | list_for_each_entry(ce, &psd->clock_list, node) |
387 | clk_enable(ce->clk); | 380 | clk_enable(ce->clk); |
388 | 381 | ||
389 | spin_unlock_irqrestore(&pcd->lock, flags); | 382 | spin_unlock_irqrestore(&psd->lock, flags); |
390 | 383 | ||
391 | return 0; | 384 | return 0; |
392 | } | 385 | } |
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c new file mode 100644 index 00000000000..29820c39618 --- /dev/null +++ b/drivers/base/power/common.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * drivers/base/power/common.c - Common device power management code. | ||
3 | * | ||
4 | * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp. | ||
5 | * | ||
6 | * This file is released under the GPLv2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/pm_clock.h> | ||
14 | |||
15 | /** | ||
16 | * dev_pm_get_subsys_data - Create or refcount power.subsys_data for device. | ||
17 | * @dev: Device to handle. | ||
18 | * | ||
19 | * If power.subsys_data is NULL, point it to a new object, otherwise increment | ||
20 | * its reference counter. Return 1 if a new object has been created, otherwise | ||
21 | * return 0 or error code. | ||
22 | */ | ||
23 | int dev_pm_get_subsys_data(struct device *dev) | ||
24 | { | ||
25 | struct pm_subsys_data *psd; | ||
26 | int ret = 0; | ||
27 | |||
28 | psd = kzalloc(sizeof(*psd), GFP_KERNEL); | ||
29 | if (!psd) | ||
30 | return -ENOMEM; | ||
31 | |||
32 | spin_lock_irq(&dev->power.lock); | ||
33 | |||
34 | if (dev->power.subsys_data) { | ||
35 | dev->power.subsys_data->refcount++; | ||
36 | } else { | ||
37 | spin_lock_init(&psd->lock); | ||
38 | psd->refcount = 1; | ||
39 | dev->power.subsys_data = psd; | ||
40 | pm_clk_init(dev); | ||
41 | psd = NULL; | ||
42 | ret = 1; | ||
43 | } | ||
44 | |||
45 | spin_unlock_irq(&dev->power.lock); | ||
46 | |||
47 | /* kfree() verifies that its argument is nonzero. */ | ||
48 | kfree(psd); | ||
49 | |||
50 | return ret; | ||
51 | } | ||
52 | EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data); | ||
53 | |||
54 | /** | ||
55 | * dev_pm_put_subsys_data - Drop reference to power.subsys_data. | ||
56 | * @dev: Device to handle. | ||
57 | * | ||
58 | * If the reference counter of power.subsys_data is zero after dropping the | ||
59 | * reference, power.subsys_data is removed. Return 1 if that happens or 0 | ||
60 | * otherwise. | ||
61 | */ | ||
62 | int dev_pm_put_subsys_data(struct device *dev) | ||
63 | { | ||
64 | struct pm_subsys_data *psd; | ||
65 | int ret = 0; | ||
66 | |||
67 | spin_lock_irq(&dev->power.lock); | ||
68 | |||
69 | psd = dev_to_psd(dev); | ||
70 | if (!psd) { | ||
71 | ret = -EINVAL; | ||
72 | goto out; | ||
73 | } | ||
74 | |||
75 | if (--psd->refcount == 0) { | ||
76 | dev->power.subsys_data = NULL; | ||
77 | kfree(psd); | ||
78 | ret = 1; | ||
79 | } | ||
80 | |||
81 | out: | ||
82 | spin_unlock_irq(&dev->power.lock); | ||
83 | |||
84 | return ret; | ||
85 | } | ||
86 | EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); | ||
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 1c374579407..c2468a7e5b2 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -29,10 +29,20 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev) | |||
29 | return pd_to_genpd(dev->pm_domain); | 29 | return pd_to_genpd(dev->pm_domain); |
30 | } | 30 | } |
31 | 31 | ||
32 | static void genpd_sd_counter_dec(struct generic_pm_domain *genpd) | 32 | static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) |
33 | { | 33 | { |
34 | if (!WARN_ON(genpd->sd_count == 0)) | 34 | bool ret = false; |
35 | genpd->sd_count--; | 35 | |
36 | if (!WARN_ON(atomic_read(&genpd->sd_count) == 0)) | ||
37 | ret = !!atomic_dec_and_test(&genpd->sd_count); | ||
38 | |||
39 | return ret; | ||
40 | } | ||
41 | |||
42 | static void genpd_sd_counter_inc(struct generic_pm_domain *genpd) | ||
43 | { | ||
44 | atomic_inc(&genpd->sd_count); | ||
45 | smp_mb__after_atomic_inc(); | ||
36 | } | 46 | } |
37 | 47 | ||
38 | static void genpd_acquire_lock(struct generic_pm_domain *genpd) | 48 | static void genpd_acquire_lock(struct generic_pm_domain *genpd) |
@@ -71,81 +81,118 @@ static void genpd_set_active(struct generic_pm_domain *genpd) | |||
71 | } | 81 | } |
72 | 82 | ||
73 | /** | 83 | /** |
74 | * pm_genpd_poweron - Restore power to a given PM domain and its parents. | 84 | * __pm_genpd_poweron - Restore power to a given PM domain and its masters. |
75 | * @genpd: PM domain to power up. | 85 | * @genpd: PM domain to power up. |
76 | * | 86 | * |
77 | * Restore power to @genpd and all of its parents so that it is possible to | 87 | * Restore power to @genpd and all of its masters so that it is possible to |
78 | * resume a device belonging to it. | 88 | * resume a device belonging to it. |
79 | */ | 89 | */ |
80 | int pm_genpd_poweron(struct generic_pm_domain *genpd) | 90 | int __pm_genpd_poweron(struct generic_pm_domain *genpd) |
91 | __releases(&genpd->lock) __acquires(&genpd->lock) | ||
81 | { | 92 | { |
82 | struct generic_pm_domain *parent = genpd->parent; | 93 | struct gpd_link *link; |
94 | DEFINE_WAIT(wait); | ||
83 | int ret = 0; | 95 | int ret = 0; |
84 | 96 | ||
85 | start: | 97 | /* If the domain's master is being waited for, we have to wait too. */ |
86 | if (parent) { | 98 | for (;;) { |
87 | genpd_acquire_lock(parent); | 99 | prepare_to_wait(&genpd->status_wait_queue, &wait, |
88 | mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING); | 100 | TASK_UNINTERRUPTIBLE); |
89 | } else { | 101 | if (genpd->status != GPD_STATE_WAIT_MASTER) |
102 | break; | ||
103 | mutex_unlock(&genpd->lock); | ||
104 | |||
105 | schedule(); | ||
106 | |||
90 | mutex_lock(&genpd->lock); | 107 | mutex_lock(&genpd->lock); |
91 | } | 108 | } |
109 | finish_wait(&genpd->status_wait_queue, &wait); | ||
92 | 110 | ||
93 | if (genpd->status == GPD_STATE_ACTIVE | 111 | if (genpd->status == GPD_STATE_ACTIVE |
94 | || (genpd->prepared_count > 0 && genpd->suspend_power_off)) | 112 | || (genpd->prepared_count > 0 && genpd->suspend_power_off)) |
95 | goto out; | 113 | return 0; |
96 | 114 | ||
97 | if (genpd->status != GPD_STATE_POWER_OFF) { | 115 | if (genpd->status != GPD_STATE_POWER_OFF) { |
98 | genpd_set_active(genpd); | 116 | genpd_set_active(genpd); |
99 | goto out; | 117 | return 0; |
100 | } | 118 | } |
101 | 119 | ||
102 | if (parent && parent->status != GPD_STATE_ACTIVE) { | 120 | /* |
121 | * The list is guaranteed not to change while the loop below is being | ||
122 | * executed, unless one of the masters' .power_on() callbacks fiddles | ||
123 | * with it. | ||
124 | */ | ||
125 | list_for_each_entry(link, &genpd->slave_links, slave_node) { | ||
126 | genpd_sd_counter_inc(link->master); | ||
127 | genpd->status = GPD_STATE_WAIT_MASTER; | ||
128 | |||
103 | mutex_unlock(&genpd->lock); | 129 | mutex_unlock(&genpd->lock); |
104 | genpd_release_lock(parent); | ||
105 | 130 | ||
106 | ret = pm_genpd_poweron(parent); | 131 | ret = pm_genpd_poweron(link->master); |
107 | if (ret) | ||
108 | return ret; | ||
109 | 132 | ||
110 | goto start; | 133 | mutex_lock(&genpd->lock); |
134 | |||
135 | /* | ||
136 | * The "wait for parent" status is guaranteed not to change | ||
137 | * while the master is powering on. | ||
138 | */ | ||
139 | genpd->status = GPD_STATE_POWER_OFF; | ||
140 | wake_up_all(&genpd->status_wait_queue); | ||
141 | if (ret) { | ||
142 | genpd_sd_counter_dec(link->master); | ||
143 | goto err; | ||
144 | } | ||
111 | } | 145 | } |
112 | 146 | ||
113 | if (genpd->power_on) { | 147 | if (genpd->power_on) { |
114 | ret = genpd->power_on(genpd); | 148 | ret = genpd->power_on(genpd); |
115 | if (ret) | 149 | if (ret) |
116 | goto out; | 150 | goto err; |
117 | } | 151 | } |
118 | 152 | ||
119 | genpd_set_active(genpd); | 153 | genpd_set_active(genpd); |
120 | if (parent) | ||
121 | parent->sd_count++; | ||
122 | 154 | ||
123 | out: | 155 | return 0; |
124 | mutex_unlock(&genpd->lock); | 156 | |
125 | if (parent) | 157 | err: |
126 | genpd_release_lock(parent); | 158 | list_for_each_entry_continue_reverse(link, &genpd->slave_links, slave_node) |
159 | genpd_sd_counter_dec(link->master); | ||
127 | 160 | ||
128 | return ret; | 161 | return ret; |
129 | } | 162 | } |
130 | 163 | ||
164 | /** | ||
165 | * pm_genpd_poweron - Restore power to a given PM domain and its masters. | ||
166 | * @genpd: PM domain to power up. | ||
167 | */ | ||
168 | int pm_genpd_poweron(struct generic_pm_domain *genpd) | ||
169 | { | ||
170 | int ret; | ||
171 | |||
172 | mutex_lock(&genpd->lock); | ||
173 | ret = __pm_genpd_poweron(genpd); | ||
174 | mutex_unlock(&genpd->lock); | ||
175 | return ret; | ||
176 | } | ||
177 | |||
131 | #endif /* CONFIG_PM */ | 178 | #endif /* CONFIG_PM */ |
132 | 179 | ||
133 | #ifdef CONFIG_PM_RUNTIME | 180 | #ifdef CONFIG_PM_RUNTIME |
134 | 181 | ||
135 | /** | 182 | /** |
136 | * __pm_genpd_save_device - Save the pre-suspend state of a device. | 183 | * __pm_genpd_save_device - Save the pre-suspend state of a device. |
137 | * @dle: Device list entry of the device to save the state of. | 184 | * @pdd: Domain data of the device to save the state of. |
138 | * @genpd: PM domain the device belongs to. | 185 | * @genpd: PM domain the device belongs to. |
139 | */ | 186 | */ |
140 | static int __pm_genpd_save_device(struct dev_list_entry *dle, | 187 | static int __pm_genpd_save_device(struct pm_domain_data *pdd, |
141 | struct generic_pm_domain *genpd) | 188 | struct generic_pm_domain *genpd) |
142 | __releases(&genpd->lock) __acquires(&genpd->lock) | 189 | __releases(&genpd->lock) __acquires(&genpd->lock) |
143 | { | 190 | { |
144 | struct device *dev = dle->dev; | 191 | struct device *dev = pdd->dev; |
145 | struct device_driver *drv = dev->driver; | 192 | struct device_driver *drv = dev->driver; |
146 | int ret = 0; | 193 | int ret = 0; |
147 | 194 | ||
148 | if (dle->need_restore) | 195 | if (pdd->need_restore) |
149 | return 0; | 196 | return 0; |
150 | 197 | ||
151 | mutex_unlock(&genpd->lock); | 198 | mutex_unlock(&genpd->lock); |
@@ -163,24 +210,24 @@ static int __pm_genpd_save_device(struct dev_list_entry *dle, | |||
163 | mutex_lock(&genpd->lock); | 210 | mutex_lock(&genpd->lock); |
164 | 211 | ||
165 | if (!ret) | 212 | if (!ret) |
166 | dle->need_restore = true; | 213 | pdd->need_restore = true; |
167 | 214 | ||
168 | return ret; | 215 | return ret; |
169 | } | 216 | } |
170 | 217 | ||
171 | /** | 218 | /** |
172 | * __pm_genpd_restore_device - Restore the pre-suspend state of a device. | 219 | * __pm_genpd_restore_device - Restore the pre-suspend state of a device. |
173 | * @dle: Device list entry of the device to restore the state of. | 220 | * @pdd: Domain data of the device to restore the state of. |
174 | * @genpd: PM domain the device belongs to. | 221 | * @genpd: PM domain the device belongs to. |
175 | */ | 222 | */ |
176 | static void __pm_genpd_restore_device(struct dev_list_entry *dle, | 223 | static void __pm_genpd_restore_device(struct pm_domain_data *pdd, |
177 | struct generic_pm_domain *genpd) | 224 | struct generic_pm_domain *genpd) |
178 | __releases(&genpd->lock) __acquires(&genpd->lock) | 225 | __releases(&genpd->lock) __acquires(&genpd->lock) |
179 | { | 226 | { |
180 | struct device *dev = dle->dev; | 227 | struct device *dev = pdd->dev; |
181 | struct device_driver *drv = dev->driver; | 228 | struct device_driver *drv = dev->driver; |
182 | 229 | ||
183 | if (!dle->need_restore) | 230 | if (!pdd->need_restore) |
184 | return; | 231 | return; |
185 | 232 | ||
186 | mutex_unlock(&genpd->lock); | 233 | mutex_unlock(&genpd->lock); |
@@ -197,7 +244,7 @@ static void __pm_genpd_restore_device(struct dev_list_entry *dle, | |||
197 | 244 | ||
198 | mutex_lock(&genpd->lock); | 245 | mutex_lock(&genpd->lock); |
199 | 246 | ||
200 | dle->need_restore = false; | 247 | pdd->need_restore = false; |
201 | } | 248 | } |
202 | 249 | ||
203 | /** | 250 | /** |
@@ -211,7 +258,8 @@ static void __pm_genpd_restore_device(struct dev_list_entry *dle, | |||
211 | */ | 258 | */ |
212 | static bool genpd_abort_poweroff(struct generic_pm_domain *genpd) | 259 | static bool genpd_abort_poweroff(struct generic_pm_domain *genpd) |
213 | { | 260 | { |
214 | return genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0; | 261 | return genpd->status == GPD_STATE_WAIT_MASTER |
262 | || genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0; | ||
215 | } | 263 | } |
216 | 264 | ||
217 | /** | 265 | /** |
@@ -238,8 +286,8 @@ void genpd_queue_power_off_work(struct generic_pm_domain *genpd) | |||
238 | static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | 286 | static int pm_genpd_poweroff(struct generic_pm_domain *genpd) |
239 | __releases(&genpd->lock) __acquires(&genpd->lock) | 287 | __releases(&genpd->lock) __acquires(&genpd->lock) |
240 | { | 288 | { |
241 | struct generic_pm_domain *parent; | 289 | struct pm_domain_data *pdd; |
242 | struct dev_list_entry *dle; | 290 | struct gpd_link *link; |
243 | unsigned int not_suspended; | 291 | unsigned int not_suspended; |
244 | int ret = 0; | 292 | int ret = 0; |
245 | 293 | ||
@@ -247,19 +295,22 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
247 | /* | 295 | /* |
248 | * Do not try to power off the domain in the following situations: | 296 | * Do not try to power off the domain in the following situations: |
249 | * (1) The domain is already in the "power off" state. | 297 | * (1) The domain is already in the "power off" state. |
250 | * (2) System suspend is in progress. | 298 | * (2) The domain is waiting for its master to power up. |
251 | * (3) One of the domain's devices is being resumed right now. | 299 | * (3) One of the domain's devices is being resumed right now. |
300 | * (4) System suspend is in progress. | ||
252 | */ | 301 | */ |
253 | if (genpd->status == GPD_STATE_POWER_OFF || genpd->prepared_count > 0 | 302 | if (genpd->status == GPD_STATE_POWER_OFF |
254 | || genpd->resume_count > 0) | 303 | || genpd->status == GPD_STATE_WAIT_MASTER |
304 | || genpd->resume_count > 0 || genpd->prepared_count > 0) | ||
255 | return 0; | 305 | return 0; |
256 | 306 | ||
257 | if (genpd->sd_count > 0) | 307 | if (atomic_read(&genpd->sd_count) > 0) |
258 | return -EBUSY; | 308 | return -EBUSY; |
259 | 309 | ||
260 | not_suspended = 0; | 310 | not_suspended = 0; |
261 | list_for_each_entry(dle, &genpd->dev_list, node) | 311 | list_for_each_entry(pdd, &genpd->dev_list, list_node) |
262 | if (dle->dev->driver && !pm_runtime_suspended(dle->dev)) | 312 | if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) |
313 | || pdd->dev->power.irq_safe)) | ||
263 | not_suspended++; | 314 | not_suspended++; |
264 | 315 | ||
265 | if (not_suspended > genpd->in_progress) | 316 | if (not_suspended > genpd->in_progress) |
@@ -282,54 +333,50 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
282 | genpd->status = GPD_STATE_BUSY; | 333 | genpd->status = GPD_STATE_BUSY; |
283 | genpd->poweroff_task = current; | 334 | genpd->poweroff_task = current; |
284 | 335 | ||
285 | list_for_each_entry_reverse(dle, &genpd->dev_list, node) { | 336 | list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) { |
286 | ret = __pm_genpd_save_device(dle, genpd); | 337 | ret = atomic_read(&genpd->sd_count) == 0 ? |
338 | __pm_genpd_save_device(pdd, genpd) : -EBUSY; | ||
339 | |||
340 | if (genpd_abort_poweroff(genpd)) | ||
341 | goto out; | ||
342 | |||
287 | if (ret) { | 343 | if (ret) { |
288 | genpd_set_active(genpd); | 344 | genpd_set_active(genpd); |
289 | goto out; | 345 | goto out; |
290 | } | 346 | } |
291 | 347 | ||
292 | if (genpd_abort_poweroff(genpd)) | ||
293 | goto out; | ||
294 | |||
295 | if (genpd->status == GPD_STATE_REPEAT) { | 348 | if (genpd->status == GPD_STATE_REPEAT) { |
296 | genpd->poweroff_task = NULL; | 349 | genpd->poweroff_task = NULL; |
297 | goto start; | 350 | goto start; |
298 | } | 351 | } |
299 | } | 352 | } |
300 | 353 | ||
301 | parent = genpd->parent; | 354 | if (genpd->power_off) { |
302 | if (parent) { | 355 | if (atomic_read(&genpd->sd_count) > 0) { |
303 | mutex_unlock(&genpd->lock); | 356 | ret = -EBUSY; |
304 | |||
305 | genpd_acquire_lock(parent); | ||
306 | mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING); | ||
307 | |||
308 | if (genpd_abort_poweroff(genpd)) { | ||
309 | genpd_release_lock(parent); | ||
310 | goto out; | 357 | goto out; |
311 | } | 358 | } |
312 | } | ||
313 | 359 | ||
314 | if (genpd->power_off) { | 360 | /* |
361 | * If sd_count > 0 at this point, one of the subdomains hasn't | ||
362 | * managed to call pm_genpd_poweron() for the master yet after | ||
363 | * incrementing it. In that case pm_genpd_poweron() will wait | ||
364 | * for us to drop the lock, so we can call .power_off() and let | ||
365 | * the pm_genpd_poweron() restore power for us (this shouldn't | ||
366 | * happen very often). | ||
367 | */ | ||
315 | ret = genpd->power_off(genpd); | 368 | ret = genpd->power_off(genpd); |
316 | if (ret == -EBUSY) { | 369 | if (ret == -EBUSY) { |
317 | genpd_set_active(genpd); | 370 | genpd_set_active(genpd); |
318 | if (parent) | ||
319 | genpd_release_lock(parent); | ||
320 | |||
321 | goto out; | 371 | goto out; |
322 | } | 372 | } |
323 | } | 373 | } |
324 | 374 | ||
325 | genpd->status = GPD_STATE_POWER_OFF; | 375 | genpd->status = GPD_STATE_POWER_OFF; |
326 | 376 | ||
327 | if (parent) { | 377 | list_for_each_entry(link, &genpd->slave_links, slave_node) { |
328 | genpd_sd_counter_dec(parent); | 378 | genpd_sd_counter_dec(link->master); |
329 | if (parent->sd_count == 0) | 379 | genpd_queue_power_off_work(link->master); |
330 | genpd_queue_power_off_work(parent); | ||
331 | |||
332 | genpd_release_lock(parent); | ||
333 | } | 380 | } |
334 | 381 | ||
335 | out: | 382 | out: |
@@ -371,12 +418,21 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
371 | if (IS_ERR(genpd)) | 418 | if (IS_ERR(genpd)) |
372 | return -EINVAL; | 419 | return -EINVAL; |
373 | 420 | ||
421 | might_sleep_if(!genpd->dev_irq_safe); | ||
422 | |||
374 | if (genpd->stop_device) { | 423 | if (genpd->stop_device) { |
375 | int ret = genpd->stop_device(dev); | 424 | int ret = genpd->stop_device(dev); |
376 | if (ret) | 425 | if (ret) |
377 | return ret; | 426 | return ret; |
378 | } | 427 | } |
379 | 428 | ||
429 | /* | ||
430 | * If power.irq_safe is set, this routine will be run with interrupts | ||
431 | * off, so it can't use mutexes. | ||
432 | */ | ||
433 | if (dev->power.irq_safe) | ||
434 | return 0; | ||
435 | |||
380 | mutex_lock(&genpd->lock); | 436 | mutex_lock(&genpd->lock); |
381 | genpd->in_progress++; | 437 | genpd->in_progress++; |
382 | pm_genpd_poweroff(genpd); | 438 | pm_genpd_poweroff(genpd); |
@@ -387,24 +443,6 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
387 | } | 443 | } |
388 | 444 | ||
389 | /** | 445 | /** |
390 | * __pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain. | ||
391 | * @dev: Device to resume. | ||
392 | * @genpd: PM domain the device belongs to. | ||
393 | */ | ||
394 | static void __pm_genpd_runtime_resume(struct device *dev, | ||
395 | struct generic_pm_domain *genpd) | ||
396 | { | ||
397 | struct dev_list_entry *dle; | ||
398 | |||
399 | list_for_each_entry(dle, &genpd->dev_list, node) { | ||
400 | if (dle->dev == dev) { | ||
401 | __pm_genpd_restore_device(dle, genpd); | ||
402 | break; | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain. | 446 | * pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain. |
409 | * @dev: Device to resume. | 447 | * @dev: Device to resume. |
410 | * | 448 | * |
@@ -424,11 +462,18 @@ static int pm_genpd_runtime_resume(struct device *dev) | |||
424 | if (IS_ERR(genpd)) | 462 | if (IS_ERR(genpd)) |
425 | return -EINVAL; | 463 | return -EINVAL; |
426 | 464 | ||
427 | ret = pm_genpd_poweron(genpd); | 465 | might_sleep_if(!genpd->dev_irq_safe); |
428 | if (ret) | 466 | |
429 | return ret; | 467 | /* If power.irq_safe, the PM domain is never powered off. */ |
468 | if (dev->power.irq_safe) | ||
469 | goto out; | ||
430 | 470 | ||
431 | mutex_lock(&genpd->lock); | 471 | mutex_lock(&genpd->lock); |
472 | ret = __pm_genpd_poweron(genpd); | ||
473 | if (ret) { | ||
474 | mutex_unlock(&genpd->lock); | ||
475 | return ret; | ||
476 | } | ||
432 | genpd->status = GPD_STATE_BUSY; | 477 | genpd->status = GPD_STATE_BUSY; |
433 | genpd->resume_count++; | 478 | genpd->resume_count++; |
434 | for (;;) { | 479 | for (;;) { |
@@ -448,12 +493,13 @@ static int pm_genpd_runtime_resume(struct device *dev) | |||
448 | mutex_lock(&genpd->lock); | 493 | mutex_lock(&genpd->lock); |
449 | } | 494 | } |
450 | finish_wait(&genpd->status_wait_queue, &wait); | 495 | finish_wait(&genpd->status_wait_queue, &wait); |
451 | __pm_genpd_runtime_resume(dev, genpd); | 496 | __pm_genpd_restore_device(&dev->power.subsys_data->domain_data, genpd); |
452 | genpd->resume_count--; | 497 | genpd->resume_count--; |
453 | genpd_set_active(genpd); | 498 | genpd_set_active(genpd); |
454 | wake_up_all(&genpd->status_wait_queue); | 499 | wake_up_all(&genpd->status_wait_queue); |
455 | mutex_unlock(&genpd->lock); | 500 | mutex_unlock(&genpd->lock); |
456 | 501 | ||
502 | out: | ||
457 | if (genpd->start_device) | 503 | if (genpd->start_device) |
458 | genpd->start_device(dev); | 504 | genpd->start_device(dev); |
459 | 505 | ||
@@ -478,8 +524,6 @@ void pm_genpd_poweroff_unused(void) | |||
478 | #else | 524 | #else |
479 | 525 | ||
480 | static inline void genpd_power_off_work_fn(struct work_struct *work) {} | 526 | static inline void genpd_power_off_work_fn(struct work_struct *work) {} |
481 | static inline void __pm_genpd_runtime_resume(struct device *dev, | ||
482 | struct generic_pm_domain *genpd) {} | ||
483 | 527 | ||
484 | #define pm_genpd_runtime_suspend NULL | 528 | #define pm_genpd_runtime_suspend NULL |
485 | #define pm_genpd_runtime_resume NULL | 529 | #define pm_genpd_runtime_resume NULL |
@@ -489,11 +533,11 @@ static inline void __pm_genpd_runtime_resume(struct device *dev, | |||
489 | #ifdef CONFIG_PM_SLEEP | 533 | #ifdef CONFIG_PM_SLEEP |
490 | 534 | ||
491 | /** | 535 | /** |
492 | * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its parents. | 536 | * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters. |
493 | * @genpd: PM domain to power off, if possible. | 537 | * @genpd: PM domain to power off, if possible. |
494 | * | 538 | * |
495 | * Check if the given PM domain can be powered off (during system suspend or | 539 | * Check if the given PM domain can be powered off (during system suspend or |
496 | * hibernation) and do that if so. Also, in that case propagate to its parent. | 540 | * hibernation) and do that if so. Also, in that case propagate to its masters. |
497 | * | 541 | * |
498 | * This function is only called in "noirq" stages of system power transitions, | 542 | * This function is only called in "noirq" stages of system power transitions, |
499 | * so it need not acquire locks (all of the "noirq" callbacks are executed | 543 | * so it need not acquire locks (all of the "noirq" callbacks are executed |
@@ -501,21 +545,23 @@ static inline void __pm_genpd_runtime_resume(struct device *dev, | |||
501 | */ | 545 | */ |
502 | static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd) | 546 | static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd) |
503 | { | 547 | { |
504 | struct generic_pm_domain *parent = genpd->parent; | 548 | struct gpd_link *link; |
505 | 549 | ||
506 | if (genpd->status == GPD_STATE_POWER_OFF) | 550 | if (genpd->status == GPD_STATE_POWER_OFF) |
507 | return; | 551 | return; |
508 | 552 | ||
509 | if (genpd->suspended_count != genpd->device_count || genpd->sd_count > 0) | 553 | if (genpd->suspended_count != genpd->device_count |
554 | || atomic_read(&genpd->sd_count) > 0) | ||
510 | return; | 555 | return; |
511 | 556 | ||
512 | if (genpd->power_off) | 557 | if (genpd->power_off) |
513 | genpd->power_off(genpd); | 558 | genpd->power_off(genpd); |
514 | 559 | ||
515 | genpd->status = GPD_STATE_POWER_OFF; | 560 | genpd->status = GPD_STATE_POWER_OFF; |
516 | if (parent) { | 561 | |
517 | genpd_sd_counter_dec(parent); | 562 | list_for_each_entry(link, &genpd->slave_links, slave_node) { |
518 | pm_genpd_sync_poweroff(parent); | 563 | genpd_sd_counter_dec(link->master); |
564 | pm_genpd_sync_poweroff(link->master); | ||
519 | } | 565 | } |
520 | } | 566 | } |
521 | 567 | ||
@@ -1034,7 +1080,7 @@ static void pm_genpd_complete(struct device *dev) | |||
1034 | */ | 1080 | */ |
1035 | int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) | 1081 | int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) |
1036 | { | 1082 | { |
1037 | struct dev_list_entry *dle; | 1083 | struct pm_domain_data *pdd; |
1038 | int ret = 0; | 1084 | int ret = 0; |
1039 | 1085 | ||
1040 | dev_dbg(dev, "%s()\n", __func__); | 1086 | dev_dbg(dev, "%s()\n", __func__); |
@@ -1054,26 +1100,20 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) | |||
1054 | goto out; | 1100 | goto out; |
1055 | } | 1101 | } |
1056 | 1102 | ||
1057 | list_for_each_entry(dle, &genpd->dev_list, node) | 1103 | list_for_each_entry(pdd, &genpd->dev_list, list_node) |
1058 | if (dle->dev == dev) { | 1104 | if (pdd->dev == dev) { |
1059 | ret = -EINVAL; | 1105 | ret = -EINVAL; |
1060 | goto out; | 1106 | goto out; |
1061 | } | 1107 | } |
1062 | 1108 | ||
1063 | dle = kzalloc(sizeof(*dle), GFP_KERNEL); | ||
1064 | if (!dle) { | ||
1065 | ret = -ENOMEM; | ||
1066 | goto out; | ||
1067 | } | ||
1068 | |||
1069 | dle->dev = dev; | ||
1070 | dle->need_restore = false; | ||
1071 | list_add_tail(&dle->node, &genpd->dev_list); | ||
1072 | genpd->device_count++; | 1109 | genpd->device_count++; |
1073 | 1110 | ||
1074 | spin_lock_irq(&dev->power.lock); | ||
1075 | dev->pm_domain = &genpd->domain; | 1111 | dev->pm_domain = &genpd->domain; |
1076 | spin_unlock_irq(&dev->power.lock); | 1112 | dev_pm_get_subsys_data(dev); |
1113 | pdd = &dev->power.subsys_data->domain_data; | ||
1114 | pdd->dev = dev; | ||
1115 | pdd->need_restore = false; | ||
1116 | list_add_tail(&pdd->list_node, &genpd->dev_list); | ||
1077 | 1117 | ||
1078 | out: | 1118 | out: |
1079 | genpd_release_lock(genpd); | 1119 | genpd_release_lock(genpd); |
@@ -1089,7 +1129,7 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) | |||
1089 | int pm_genpd_remove_device(struct generic_pm_domain *genpd, | 1129 | int pm_genpd_remove_device(struct generic_pm_domain *genpd, |
1090 | struct device *dev) | 1130 | struct device *dev) |
1091 | { | 1131 | { |
1092 | struct dev_list_entry *dle; | 1132 | struct pm_domain_data *pdd; |
1093 | int ret = -EINVAL; | 1133 | int ret = -EINVAL; |
1094 | 1134 | ||
1095 | dev_dbg(dev, "%s()\n", __func__); | 1135 | dev_dbg(dev, "%s()\n", __func__); |
@@ -1104,17 +1144,16 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1104 | goto out; | 1144 | goto out; |
1105 | } | 1145 | } |
1106 | 1146 | ||
1107 | list_for_each_entry(dle, &genpd->dev_list, node) { | 1147 | list_for_each_entry(pdd, &genpd->dev_list, list_node) { |
1108 | if (dle->dev != dev) | 1148 | if (pdd->dev != dev) |
1109 | continue; | 1149 | continue; |
1110 | 1150 | ||
1111 | spin_lock_irq(&dev->power.lock); | 1151 | list_del_init(&pdd->list_node); |
1152 | pdd->dev = NULL; | ||
1153 | dev_pm_put_subsys_data(dev); | ||
1112 | dev->pm_domain = NULL; | 1154 | dev->pm_domain = NULL; |
1113 | spin_unlock_irq(&dev->power.lock); | ||
1114 | 1155 | ||
1115 | genpd->device_count--; | 1156 | genpd->device_count--; |
1116 | list_del(&dle->node); | ||
1117 | kfree(dle); | ||
1118 | 1157 | ||
1119 | ret = 0; | 1158 | ret = 0; |
1120 | break; | 1159 | break; |
@@ -1129,48 +1168,55 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1129 | /** | 1168 | /** |
1130 | * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. | 1169 | * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. |
1131 | * @genpd: Master PM domain to add the subdomain to. | 1170 | * @genpd: Master PM domain to add the subdomain to. |
1132 | * @new_subdomain: Subdomain to be added. | 1171 | * @subdomain: Subdomain to be added. |
1133 | */ | 1172 | */ |
1134 | int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | 1173 | int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, |
1135 | struct generic_pm_domain *new_subdomain) | 1174 | struct generic_pm_domain *subdomain) |
1136 | { | 1175 | { |
1137 | struct generic_pm_domain *subdomain; | 1176 | struct gpd_link *link; |
1138 | int ret = 0; | 1177 | int ret = 0; |
1139 | 1178 | ||
1140 | if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(new_subdomain)) | 1179 | if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain)) |
1141 | return -EINVAL; | 1180 | return -EINVAL; |
1142 | 1181 | ||
1143 | start: | 1182 | start: |
1144 | genpd_acquire_lock(genpd); | 1183 | genpd_acquire_lock(genpd); |
1145 | mutex_lock_nested(&new_subdomain->lock, SINGLE_DEPTH_NESTING); | 1184 | mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING); |
1146 | 1185 | ||
1147 | if (new_subdomain->status != GPD_STATE_POWER_OFF | 1186 | if (subdomain->status != GPD_STATE_POWER_OFF |
1148 | && new_subdomain->status != GPD_STATE_ACTIVE) { | 1187 | && subdomain->status != GPD_STATE_ACTIVE) { |
1149 | mutex_unlock(&new_subdomain->lock); | 1188 | mutex_unlock(&subdomain->lock); |
1150 | genpd_release_lock(genpd); | 1189 | genpd_release_lock(genpd); |
1151 | goto start; | 1190 | goto start; |
1152 | } | 1191 | } |
1153 | 1192 | ||
1154 | if (genpd->status == GPD_STATE_POWER_OFF | 1193 | if (genpd->status == GPD_STATE_POWER_OFF |
1155 | && new_subdomain->status != GPD_STATE_POWER_OFF) { | 1194 | && subdomain->status != GPD_STATE_POWER_OFF) { |
1156 | ret = -EINVAL; | 1195 | ret = -EINVAL; |
1157 | goto out; | 1196 | goto out; |
1158 | } | 1197 | } |
1159 | 1198 | ||
1160 | list_for_each_entry(subdomain, &genpd->sd_list, sd_node) { | 1199 | list_for_each_entry(link, &genpd->slave_links, slave_node) { |
1161 | if (subdomain == new_subdomain) { | 1200 | if (link->slave == subdomain && link->master == genpd) { |
1162 | ret = -EINVAL; | 1201 | ret = -EINVAL; |
1163 | goto out; | 1202 | goto out; |
1164 | } | 1203 | } |
1165 | } | 1204 | } |
1166 | 1205 | ||
1167 | list_add_tail(&new_subdomain->sd_node, &genpd->sd_list); | 1206 | link = kzalloc(sizeof(*link), GFP_KERNEL); |
1168 | new_subdomain->parent = genpd; | 1207 | if (!link) { |
1208 | ret = -ENOMEM; | ||
1209 | goto out; | ||
1210 | } | ||
1211 | link->master = genpd; | ||
1212 | list_add_tail(&link->master_node, &genpd->master_links); | ||
1213 | link->slave = subdomain; | ||
1214 | list_add_tail(&link->slave_node, &subdomain->slave_links); | ||
1169 | if (subdomain->status != GPD_STATE_POWER_OFF) | 1215 | if (subdomain->status != GPD_STATE_POWER_OFF) |
1170 | genpd->sd_count++; | 1216 | genpd_sd_counter_inc(genpd); |
1171 | 1217 | ||
1172 | out: | 1218 | out: |
1173 | mutex_unlock(&new_subdomain->lock); | 1219 | mutex_unlock(&subdomain->lock); |
1174 | genpd_release_lock(genpd); | 1220 | genpd_release_lock(genpd); |
1175 | 1221 | ||
1176 | return ret; | 1222 | return ret; |
@@ -1179,22 +1225,22 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | |||
1179 | /** | 1225 | /** |
1180 | * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain. | 1226 | * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain. |
1181 | * @genpd: Master PM domain to remove the subdomain from. | 1227 | * @genpd: Master PM domain to remove the subdomain from. |
1182 | * @target: Subdomain to be removed. | 1228 | * @subdomain: Subdomain to be removed. |
1183 | */ | 1229 | */ |
1184 | int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, | 1230 | int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, |
1185 | struct generic_pm_domain *target) | 1231 | struct generic_pm_domain *subdomain) |
1186 | { | 1232 | { |
1187 | struct generic_pm_domain *subdomain; | 1233 | struct gpd_link *link; |
1188 | int ret = -EINVAL; | 1234 | int ret = -EINVAL; |
1189 | 1235 | ||
1190 | if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(target)) | 1236 | if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain)) |
1191 | return -EINVAL; | 1237 | return -EINVAL; |
1192 | 1238 | ||
1193 | start: | 1239 | start: |
1194 | genpd_acquire_lock(genpd); | 1240 | genpd_acquire_lock(genpd); |
1195 | 1241 | ||
1196 | list_for_each_entry(subdomain, &genpd->sd_list, sd_node) { | 1242 | list_for_each_entry(link, &genpd->master_links, master_node) { |
1197 | if (subdomain != target) | 1243 | if (link->slave != subdomain) |
1198 | continue; | 1244 | continue; |
1199 | 1245 | ||
1200 | mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING); | 1246 | mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING); |
@@ -1206,8 +1252,9 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, | |||
1206 | goto start; | 1252 | goto start; |
1207 | } | 1253 | } |
1208 | 1254 | ||
1209 | list_del(&subdomain->sd_node); | 1255 | list_del(&link->master_node); |
1210 | subdomain->parent = NULL; | 1256 | list_del(&link->slave_node); |
1257 | kfree(link); | ||
1211 | if (subdomain->status != GPD_STATE_POWER_OFF) | 1258 | if (subdomain->status != GPD_STATE_POWER_OFF) |
1212 | genpd_sd_counter_dec(genpd); | 1259 | genpd_sd_counter_dec(genpd); |
1213 | 1260 | ||
@@ -1234,15 +1281,14 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
1234 | if (IS_ERR_OR_NULL(genpd)) | 1281 | if (IS_ERR_OR_NULL(genpd)) |
1235 | return; | 1282 | return; |
1236 | 1283 | ||
1237 | INIT_LIST_HEAD(&genpd->sd_node); | 1284 | INIT_LIST_HEAD(&genpd->master_links); |
1238 | genpd->parent = NULL; | 1285 | INIT_LIST_HEAD(&genpd->slave_links); |
1239 | INIT_LIST_HEAD(&genpd->dev_list); | 1286 | INIT_LIST_HEAD(&genpd->dev_list); |
1240 | INIT_LIST_HEAD(&genpd->sd_list); | ||
1241 | mutex_init(&genpd->lock); | 1287 | mutex_init(&genpd->lock); |
1242 | genpd->gov = gov; | 1288 | genpd->gov = gov; |
1243 | INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn); | 1289 | INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn); |
1244 | genpd->in_progress = 0; | 1290 | genpd->in_progress = 0; |
1245 | genpd->sd_count = 0; | 1291 | atomic_set(&genpd->sd_count, 0); |
1246 | genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE; | 1292 | genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE; |
1247 | init_waitqueue_head(&genpd->status_wait_queue); | 1293 | init_waitqueue_head(&genpd->status_wait_queue); |
1248 | genpd->poweroff_task = NULL; | 1294 | genpd->poweroff_task = NULL; |