diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-10-16 16:12:57 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-10-16 16:12:57 -0400 |
commit | 88cfe5356a9b5cbc77e444b55c7e0d8ba4cc5ecb (patch) | |
tree | e9f81bf9f916b982ae24c0c9df22dfb9bccaa441 /drivers/base | |
parent | a98f1b78ecf325bf29c9d3d1eb38cbc9340000af (diff) | |
parent | 7420aa4fed8cc7f3f7d7cc89ea1028fddfdacac8 (diff) |
Merge back earlier 'pm-domains' material for v4.4.
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/domain.c | 280 |
1 files changed, 25 insertions, 255 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 16550c63d611..6e1bcdef7a79 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -53,24 +53,6 @@ | |||
53 | static LIST_HEAD(gpd_list); | 53 | static LIST_HEAD(gpd_list); |
54 | static DEFINE_MUTEX(gpd_list_lock); | 54 | static DEFINE_MUTEX(gpd_list_lock); |
55 | 55 | ||
56 | static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name) | ||
57 | { | ||
58 | struct generic_pm_domain *genpd = NULL, *gpd; | ||
59 | |||
60 | if (IS_ERR_OR_NULL(domain_name)) | ||
61 | return NULL; | ||
62 | |||
63 | mutex_lock(&gpd_list_lock); | ||
64 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) { | ||
65 | if (!strcmp(gpd->name, domain_name)) { | ||
66 | genpd = gpd; | ||
67 | break; | ||
68 | } | ||
69 | } | ||
70 | mutex_unlock(&gpd_list_lock); | ||
71 | return genpd; | ||
72 | } | ||
73 | |||
74 | /* | 56 | /* |
75 | * Get the generic PM domain for a particular struct device. | 57 | * Get the generic PM domain for a particular struct device. |
76 | * This validates the struct device pointer, the PM domain pointer, | 58 | * This validates the struct device pointer, the PM domain pointer, |
@@ -140,19 +122,6 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd) | |||
140 | smp_mb__after_atomic(); | 122 | smp_mb__after_atomic(); |
141 | } | 123 | } |
142 | 124 | ||
143 | static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd) | ||
144 | { | ||
145 | s64 usecs64; | ||
146 | |||
147 | if (!genpd->cpuidle_data) | ||
148 | return; | ||
149 | |||
150 | usecs64 = genpd->power_on_latency_ns; | ||
151 | do_div(usecs64, NSEC_PER_USEC); | ||
152 | usecs64 += genpd->cpuidle_data->saved_exit_latency; | ||
153 | genpd->cpuidle_data->idle_state->exit_latency = usecs64; | ||
154 | } | ||
155 | |||
156 | static int genpd_power_on(struct generic_pm_domain *genpd, bool timed) | 125 | static int genpd_power_on(struct generic_pm_domain *genpd, bool timed) |
157 | { | 126 | { |
158 | ktime_t time_start; | 127 | ktime_t time_start; |
@@ -176,7 +145,6 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed) | |||
176 | 145 | ||
177 | genpd->power_on_latency_ns = elapsed_ns; | 146 | genpd->power_on_latency_ns = elapsed_ns; |
178 | genpd->max_off_time_changed = true; | 147 | genpd->max_off_time_changed = true; |
179 | genpd_recalc_cpu_exit_latency(genpd); | ||
180 | pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", | 148 | pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", |
181 | genpd->name, "on", elapsed_ns); | 149 | genpd->name, "on", elapsed_ns); |
182 | 150 | ||
@@ -213,10 +181,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed) | |||
213 | } | 181 | } |
214 | 182 | ||
215 | /** | 183 | /** |
216 | * genpd_queue_power_off_work - Queue up the execution of pm_genpd_poweroff(). | 184 | * genpd_queue_power_off_work - Queue up the execution of genpd_poweroff(). |
217 | * @genpd: PM domait to power off. | 185 | * @genpd: PM domait to power off. |
218 | * | 186 | * |
219 | * Queue up the execution of pm_genpd_poweroff() unless it's already been done | 187 | * Queue up the execution of genpd_poweroff() unless it's already been done |
220 | * before. | 188 | * before. |
221 | */ | 189 | */ |
222 | static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) | 190 | static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) |
@@ -224,14 +192,16 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) | |||
224 | queue_work(pm_wq, &genpd->power_off_work); | 192 | queue_work(pm_wq, &genpd->power_off_work); |
225 | } | 193 | } |
226 | 194 | ||
195 | static int genpd_poweron(struct generic_pm_domain *genpd); | ||
196 | |||
227 | /** | 197 | /** |
228 | * __pm_genpd_poweron - Restore power to a given PM domain and its masters. | 198 | * __genpd_poweron - Restore power to a given PM domain and its masters. |
229 | * @genpd: PM domain to power up. | 199 | * @genpd: PM domain to power up. |
230 | * | 200 | * |
231 | * Restore power to @genpd and all of its masters so that it is possible to | 201 | * Restore power to @genpd and all of its masters so that it is possible to |
232 | * resume a device belonging to it. | 202 | * resume a device belonging to it. |
233 | */ | 203 | */ |
234 | static int __pm_genpd_poweron(struct generic_pm_domain *genpd) | 204 | static int __genpd_poweron(struct generic_pm_domain *genpd) |
235 | { | 205 | { |
236 | struct gpd_link *link; | 206 | struct gpd_link *link; |
237 | int ret = 0; | 207 | int ret = 0; |
@@ -240,13 +210,6 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd) | |||
240 | || (genpd->prepared_count > 0 && genpd->suspend_power_off)) | 210 | || (genpd->prepared_count > 0 && genpd->suspend_power_off)) |
241 | return 0; | 211 | return 0; |
242 | 212 | ||
243 | if (genpd->cpuidle_data) { | ||
244 | cpuidle_pause_and_lock(); | ||
245 | genpd->cpuidle_data->idle_state->disabled = true; | ||
246 | cpuidle_resume_and_unlock(); | ||
247 | goto out; | ||
248 | } | ||
249 | |||
250 | /* | 213 | /* |
251 | * The list is guaranteed not to change while the loop below is being | 214 | * The list is guaranteed not to change while the loop below is being |
252 | * executed, unless one of the masters' .power_on() callbacks fiddles | 215 | * executed, unless one of the masters' .power_on() callbacks fiddles |
@@ -255,7 +218,7 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd) | |||
255 | list_for_each_entry(link, &genpd->slave_links, slave_node) { | 218 | list_for_each_entry(link, &genpd->slave_links, slave_node) { |
256 | genpd_sd_counter_inc(link->master); | 219 | genpd_sd_counter_inc(link->master); |
257 | 220 | ||
258 | ret = pm_genpd_poweron(link->master); | 221 | ret = genpd_poweron(link->master); |
259 | if (ret) { | 222 | if (ret) { |
260 | genpd_sd_counter_dec(link->master); | 223 | genpd_sd_counter_dec(link->master); |
261 | goto err; | 224 | goto err; |
@@ -266,7 +229,6 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd) | |||
266 | if (ret) | 229 | if (ret) |
267 | goto err; | 230 | goto err; |
268 | 231 | ||
269 | out: | ||
270 | genpd->status = GPD_STATE_ACTIVE; | 232 | genpd->status = GPD_STATE_ACTIVE; |
271 | return 0; | 233 | return 0; |
272 | 234 | ||
@@ -282,31 +244,19 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd) | |||
282 | } | 244 | } |
283 | 245 | ||
284 | /** | 246 | /** |
285 | * pm_genpd_poweron - Restore power to a given PM domain and its masters. | 247 | * genpd_poweron - Restore power to a given PM domain and its masters. |
286 | * @genpd: PM domain to power up. | 248 | * @genpd: PM domain to power up. |
287 | */ | 249 | */ |
288 | int pm_genpd_poweron(struct generic_pm_domain *genpd) | 250 | static int genpd_poweron(struct generic_pm_domain *genpd) |
289 | { | 251 | { |
290 | int ret; | 252 | int ret; |
291 | 253 | ||
292 | mutex_lock(&genpd->lock); | 254 | mutex_lock(&genpd->lock); |
293 | ret = __pm_genpd_poweron(genpd); | 255 | ret = __genpd_poweron(genpd); |
294 | mutex_unlock(&genpd->lock); | 256 | mutex_unlock(&genpd->lock); |
295 | return ret; | 257 | return ret; |
296 | } | 258 | } |
297 | 259 | ||
298 | /** | ||
299 | * pm_genpd_name_poweron - Restore power to a given PM domain and its masters. | ||
300 | * @domain_name: Name of the PM domain to power up. | ||
301 | */ | ||
302 | int pm_genpd_name_poweron(const char *domain_name) | ||
303 | { | ||
304 | struct generic_pm_domain *genpd; | ||
305 | |||
306 | genpd = pm_genpd_lookup_name(domain_name); | ||
307 | return genpd ? pm_genpd_poweron(genpd) : -EINVAL; | ||
308 | } | ||
309 | |||
310 | static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) | 260 | static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) |
311 | { | 261 | { |
312 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev, | 262 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev, |
@@ -365,13 +315,14 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, | |||
365 | } | 315 | } |
366 | 316 | ||
367 | /** | 317 | /** |
368 | * pm_genpd_poweroff - Remove power from a given PM domain. | 318 | * genpd_poweroff - Remove power from a given PM domain. |
369 | * @genpd: PM domain to power down. | 319 | * @genpd: PM domain to power down. |
320 | * @is_async: PM domain is powered down from a scheduled work | ||
370 | * | 321 | * |
371 | * If all of the @genpd's devices have been suspended and all of its subdomains | 322 | * If all of the @genpd's devices have been suspended and all of its subdomains |
372 | * have been powered down, remove power from @genpd. | 323 | * have been powered down, remove power from @genpd. |
373 | */ | 324 | */ |
374 | static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | 325 | static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async) |
375 | { | 326 | { |
376 | struct pm_domain_data *pdd; | 327 | struct pm_domain_data *pdd; |
377 | struct gpd_link *link; | 328 | struct gpd_link *link; |
@@ -403,7 +354,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
403 | not_suspended++; | 354 | not_suspended++; |
404 | } | 355 | } |
405 | 356 | ||
406 | if (not_suspended > genpd->in_progress) | 357 | if (not_suspended > 1 || (not_suspended == 1 && is_async)) |
407 | return -EBUSY; | 358 | return -EBUSY; |
408 | 359 | ||
409 | if (genpd->gov && genpd->gov->power_down_ok) { | 360 | if (genpd->gov && genpd->gov->power_down_ok) { |
@@ -411,21 +362,6 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
411 | return -EAGAIN; | 362 | return -EAGAIN; |
412 | } | 363 | } |
413 | 364 | ||
414 | if (genpd->cpuidle_data) { | ||
415 | /* | ||
416 | * If cpuidle_data is set, cpuidle should turn the domain off | ||
417 | * when the CPU in it is idle. In that case we don't decrement | ||
418 | * the subdomain counts of the master domains, so that power is | ||
419 | * not removed from the current domain prematurely as a result | ||
420 | * of cutting off the masters' power. | ||
421 | */ | ||
422 | genpd->status = GPD_STATE_POWER_OFF; | ||
423 | cpuidle_pause_and_lock(); | ||
424 | genpd->cpuidle_data->idle_state->disabled = false; | ||
425 | cpuidle_resume_and_unlock(); | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | if (genpd->power_off) { | 365 | if (genpd->power_off) { |
430 | int ret; | 366 | int ret; |
431 | 367 | ||
@@ -434,10 +370,10 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
434 | 370 | ||
435 | /* | 371 | /* |
436 | * If sd_count > 0 at this point, one of the subdomains hasn't | 372 | * If sd_count > 0 at this point, one of the subdomains hasn't |
437 | * managed to call pm_genpd_poweron() for the master yet after | 373 | * managed to call genpd_poweron() for the master yet after |
438 | * incrementing it. In that case pm_genpd_poweron() will wait | 374 | * incrementing it. In that case genpd_poweron() will wait |
439 | * for us to drop the lock, so we can call .power_off() and let | 375 | * for us to drop the lock, so we can call .power_off() and let |
440 | * the pm_genpd_poweron() restore power for us (this shouldn't | 376 | * the genpd_poweron() restore power for us (this shouldn't |
441 | * happen very often). | 377 | * happen very often). |
442 | */ | 378 | */ |
443 | ret = genpd_power_off(genpd, true); | 379 | ret = genpd_power_off(genpd, true); |
@@ -466,7 +402,7 @@ static void genpd_power_off_work_fn(struct work_struct *work) | |||
466 | genpd = container_of(work, struct generic_pm_domain, power_off_work); | 402 | genpd = container_of(work, struct generic_pm_domain, power_off_work); |
467 | 403 | ||
468 | mutex_lock(&genpd->lock); | 404 | mutex_lock(&genpd->lock); |
469 | pm_genpd_poweroff(genpd); | 405 | genpd_poweroff(genpd, true); |
470 | mutex_unlock(&genpd->lock); | 406 | mutex_unlock(&genpd->lock); |
471 | } | 407 | } |
472 | 408 | ||
@@ -512,9 +448,7 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
512 | return 0; | 448 | return 0; |
513 | 449 | ||
514 | mutex_lock(&genpd->lock); | 450 | mutex_lock(&genpd->lock); |
515 | genpd->in_progress++; | 451 | genpd_poweroff(genpd, false); |
516 | pm_genpd_poweroff(genpd); | ||
517 | genpd->in_progress--; | ||
518 | mutex_unlock(&genpd->lock); | 452 | mutex_unlock(&genpd->lock); |
519 | 453 | ||
520 | return 0; | 454 | return 0; |
@@ -547,7 +481,7 @@ static int pm_genpd_runtime_resume(struct device *dev) | |||
547 | } | 481 | } |
548 | 482 | ||
549 | mutex_lock(&genpd->lock); | 483 | mutex_lock(&genpd->lock); |
550 | ret = __pm_genpd_poweron(genpd); | 484 | ret = __genpd_poweron(genpd); |
551 | mutex_unlock(&genpd->lock); | 485 | mutex_unlock(&genpd->lock); |
552 | 486 | ||
553 | if (ret) | 487 | if (ret) |
@@ -569,15 +503,15 @@ static int __init pd_ignore_unused_setup(char *__unused) | |||
569 | __setup("pd_ignore_unused", pd_ignore_unused_setup); | 503 | __setup("pd_ignore_unused", pd_ignore_unused_setup); |
570 | 504 | ||
571 | /** | 505 | /** |
572 | * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use. | 506 | * genpd_poweroff_unused - Power off all PM domains with no devices in use. |
573 | */ | 507 | */ |
574 | void pm_genpd_poweroff_unused(void) | 508 | static int __init genpd_poweroff_unused(void) |
575 | { | 509 | { |
576 | struct generic_pm_domain *genpd; | 510 | struct generic_pm_domain *genpd; |
577 | 511 | ||
578 | if (pd_ignore_unused) { | 512 | if (pd_ignore_unused) { |
579 | pr_warn("genpd: Not disabling unused power domains\n"); | 513 | pr_warn("genpd: Not disabling unused power domains\n"); |
580 | return; | 514 | return 0; |
581 | } | 515 | } |
582 | 516 | ||
583 | mutex_lock(&gpd_list_lock); | 517 | mutex_lock(&gpd_list_lock); |
@@ -586,11 +520,7 @@ void pm_genpd_poweroff_unused(void) | |||
586 | genpd_queue_power_off_work(genpd); | 520 | genpd_queue_power_off_work(genpd); |
587 | 521 | ||
588 | mutex_unlock(&gpd_list_lock); | 522 | mutex_unlock(&gpd_list_lock); |
589 | } | ||
590 | 523 | ||
591 | static int __init genpd_poweroff_unused(void) | ||
592 | { | ||
593 | pm_genpd_poweroff_unused(); | ||
594 | return 0; | 524 | return 0; |
595 | } | 525 | } |
596 | late_initcall(genpd_poweroff_unused); | 526 | late_initcall(genpd_poweroff_unused); |
@@ -764,7 +694,7 @@ static int pm_genpd_prepare(struct device *dev) | |||
764 | 694 | ||
765 | /* | 695 | /* |
766 | * The PM domain must be in the GPD_STATE_ACTIVE state at this point, | 696 | * The PM domain must be in the GPD_STATE_ACTIVE state at this point, |
767 | * so pm_genpd_poweron() will return immediately, but if the device | 697 | * so genpd_poweron() will return immediately, but if the device |
768 | * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need | 698 | * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need |
769 | * to make it operational. | 699 | * to make it operational. |
770 | */ | 700 | */ |
@@ -1317,18 +1247,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, | |||
1317 | } | 1247 | } |
1318 | 1248 | ||
1319 | /** | 1249 | /** |
1320 | * __pm_genpd_name_add_device - Find I/O PM domain and add a device to it. | ||
1321 | * @domain_name: Name of the PM domain to add the device to. | ||
1322 | * @dev: Device to be added. | ||
1323 | * @td: Set of PM QoS timing parameters to attach to the device. | ||
1324 | */ | ||
1325 | int __pm_genpd_name_add_device(const char *domain_name, struct device *dev, | ||
1326 | struct gpd_timing_data *td) | ||
1327 | { | ||
1328 | return __pm_genpd_add_device(pm_genpd_lookup_name(domain_name), dev, td); | ||
1329 | } | ||
1330 | |||
1331 | /** | ||
1332 | * pm_genpd_remove_device - Remove a device from an I/O PM domain. | 1250 | * pm_genpd_remove_device - Remove a device from an I/O PM domain. |
1333 | * @genpd: PM domain to remove the device from. | 1251 | * @genpd: PM domain to remove the device from. |
1334 | * @dev: Device to be removed. | 1252 | * @dev: Device to be removed. |
@@ -1429,35 +1347,6 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | |||
1429 | } | 1347 | } |
1430 | 1348 | ||
1431 | /** | 1349 | /** |
1432 | * pm_genpd_add_subdomain_names - Add a subdomain to an I/O PM domain. | ||
1433 | * @master_name: Name of the master PM domain to add the subdomain to. | ||
1434 | * @subdomain_name: Name of the subdomain to be added. | ||
1435 | */ | ||
1436 | int pm_genpd_add_subdomain_names(const char *master_name, | ||
1437 | const char *subdomain_name) | ||
1438 | { | ||
1439 | struct generic_pm_domain *master = NULL, *subdomain = NULL, *gpd; | ||
1440 | |||
1441 | if (IS_ERR_OR_NULL(master_name) || IS_ERR_OR_NULL(subdomain_name)) | ||
1442 | return -EINVAL; | ||
1443 | |||
1444 | mutex_lock(&gpd_list_lock); | ||
1445 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) { | ||
1446 | if (!master && !strcmp(gpd->name, master_name)) | ||
1447 | master = gpd; | ||
1448 | |||
1449 | if (!subdomain && !strcmp(gpd->name, subdomain_name)) | ||
1450 | subdomain = gpd; | ||
1451 | |||
1452 | if (master && subdomain) | ||
1453 | break; | ||
1454 | } | ||
1455 | mutex_unlock(&gpd_list_lock); | ||
1456 | |||
1457 | return pm_genpd_add_subdomain(master, subdomain); | ||
1458 | } | ||
1459 | |||
1460 | /** | ||
1461 | * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain. | 1350 | * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain. |
1462 | * @genpd: Master PM domain to remove the subdomain from. | 1351 | * @genpd: Master PM domain to remove the subdomain from. |
1463 | * @subdomain: Subdomain to be removed. | 1352 | * @subdomain: Subdomain to be removed. |
@@ -1504,124 +1393,6 @@ out: | |||
1504 | return ret; | 1393 | return ret; |
1505 | } | 1394 | } |
1506 | 1395 | ||
1507 | /** | ||
1508 | * pm_genpd_attach_cpuidle - Connect the given PM domain with cpuidle. | ||
1509 | * @genpd: PM domain to be connected with cpuidle. | ||
1510 | * @state: cpuidle state this domain can disable/enable. | ||
1511 | * | ||
1512 | * Make a PM domain behave as though it contained a CPU core, that is, instead | ||
1513 | * of calling its power down routine it will enable the given cpuidle state so | ||
1514 | * that the cpuidle subsystem can power it down (if possible and desirable). | ||
1515 | */ | ||
1516 | int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state) | ||
1517 | { | ||
1518 | struct cpuidle_driver *cpuidle_drv; | ||
1519 | struct gpd_cpuidle_data *cpuidle_data; | ||
1520 | struct cpuidle_state *idle_state; | ||
1521 | int ret = 0; | ||
1522 | |||
1523 | if (IS_ERR_OR_NULL(genpd) || state < 0) | ||
1524 | return -EINVAL; | ||
1525 | |||
1526 | mutex_lock(&genpd->lock); | ||
1527 | |||
1528 | if (genpd->cpuidle_data) { | ||
1529 | ret = -EEXIST; | ||
1530 | goto out; | ||
1531 | } | ||
1532 | cpuidle_data = kzalloc(sizeof(*cpuidle_data), GFP_KERNEL); | ||
1533 | if (!cpuidle_data) { | ||
1534 | ret = -ENOMEM; | ||
1535 | goto out; | ||
1536 | } | ||
1537 | cpuidle_drv = cpuidle_driver_ref(); | ||
1538 | if (!cpuidle_drv) { | ||
1539 | ret = -ENODEV; | ||
1540 | goto err_drv; | ||
1541 | } | ||
1542 | if (cpuidle_drv->state_count <= state) { | ||
1543 | ret = -EINVAL; | ||
1544 | goto err; | ||
1545 | } | ||
1546 | idle_state = &cpuidle_drv->states[state]; | ||
1547 | if (!idle_state->disabled) { | ||
1548 | ret = -EAGAIN; | ||
1549 | goto err; | ||
1550 | } | ||
1551 | cpuidle_data->idle_state = idle_state; | ||
1552 | cpuidle_data->saved_exit_latency = idle_state->exit_latency; | ||
1553 | genpd->cpuidle_data = cpuidle_data; | ||
1554 | genpd_recalc_cpu_exit_latency(genpd); | ||
1555 | |||
1556 | out: | ||
1557 | mutex_unlock(&genpd->lock); | ||
1558 | return ret; | ||
1559 | |||
1560 | err: | ||
1561 | cpuidle_driver_unref(); | ||
1562 | |||
1563 | err_drv: | ||
1564 | kfree(cpuidle_data); | ||
1565 | goto out; | ||
1566 | } | ||
1567 | |||
1568 | /** | ||
1569 | * pm_genpd_name_attach_cpuidle - Find PM domain and connect cpuidle to it. | ||
1570 | * @name: Name of the domain to connect to cpuidle. | ||
1571 | * @state: cpuidle state this domain can manipulate. | ||
1572 | */ | ||
1573 | int pm_genpd_name_attach_cpuidle(const char *name, int state) | ||
1574 | { | ||
1575 | return pm_genpd_attach_cpuidle(pm_genpd_lookup_name(name), state); | ||
1576 | } | ||
1577 | |||
1578 | /** | ||
1579 | * pm_genpd_detach_cpuidle - Remove the cpuidle connection from a PM domain. | ||
1580 | * @genpd: PM domain to remove the cpuidle connection from. | ||
1581 | * | ||
1582 | * Remove the cpuidle connection set up by pm_genpd_attach_cpuidle() from the | ||
1583 | * given PM domain. | ||
1584 | */ | ||
1585 | int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd) | ||
1586 | { | ||
1587 | struct gpd_cpuidle_data *cpuidle_data; | ||
1588 | struct cpuidle_state *idle_state; | ||
1589 | int ret = 0; | ||
1590 | |||
1591 | if (IS_ERR_OR_NULL(genpd)) | ||
1592 | return -EINVAL; | ||
1593 | |||
1594 | mutex_lock(&genpd->lock); | ||
1595 | |||
1596 | cpuidle_data = genpd->cpuidle_data; | ||
1597 | if (!cpuidle_data) { | ||
1598 | ret = -ENODEV; | ||
1599 | goto out; | ||
1600 | } | ||
1601 | idle_state = cpuidle_data->idle_state; | ||
1602 | if (!idle_state->disabled) { | ||
1603 | ret = -EAGAIN; | ||
1604 | goto out; | ||
1605 | } | ||
1606 | idle_state->exit_latency = cpuidle_data->saved_exit_latency; | ||
1607 | cpuidle_driver_unref(); | ||
1608 | genpd->cpuidle_data = NULL; | ||
1609 | kfree(cpuidle_data); | ||
1610 | |||
1611 | out: | ||
1612 | mutex_unlock(&genpd->lock); | ||
1613 | return ret; | ||
1614 | } | ||
1615 | |||
1616 | /** | ||
1617 | * pm_genpd_name_detach_cpuidle - Find PM domain and disconnect cpuidle from it. | ||
1618 | * @name: Name of the domain to disconnect cpuidle from. | ||
1619 | */ | ||
1620 | int pm_genpd_name_detach_cpuidle(const char *name) | ||
1621 | { | ||
1622 | return pm_genpd_detach_cpuidle(pm_genpd_lookup_name(name)); | ||
1623 | } | ||
1624 | |||
1625 | /* Default device callbacks for generic PM domains. */ | 1396 | /* Default device callbacks for generic PM domains. */ |
1626 | 1397 | ||
1627 | /** | 1398 | /** |
@@ -1688,7 +1459,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
1688 | mutex_init(&genpd->lock); | 1459 | mutex_init(&genpd->lock); |
1689 | genpd->gov = gov; | 1460 | genpd->gov = gov; |
1690 | INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn); | 1461 | INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn); |
1691 | genpd->in_progress = 0; | ||
1692 | atomic_set(&genpd->sd_count, 0); | 1462 | atomic_set(&genpd->sd_count, 0); |
1693 | genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE; | 1463 | genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE; |
1694 | genpd->device_count = 0; | 1464 | genpd->device_count = 0; |
@@ -2023,7 +1793,7 @@ int genpd_dev_pm_attach(struct device *dev) | |||
2023 | 1793 | ||
2024 | dev->pm_domain->detach = genpd_dev_pm_detach; | 1794 | dev->pm_domain->detach = genpd_dev_pm_detach; |
2025 | dev->pm_domain->sync = genpd_dev_pm_sync; | 1795 | dev->pm_domain->sync = genpd_dev_pm_sync; |
2026 | ret = pm_genpd_poweron(pd); | 1796 | ret = genpd_poweron(pd); |
2027 | 1797 | ||
2028 | out: | 1798 | out: |
2029 | return ret ? -EPROBE_DEFER : 0; | 1799 | return ret ? -EPROBE_DEFER : 0; |