domain.c revision f721889ff65afa6243c463832c74dee3bed418d5
1/* 2 * drivers/base/power/domain.c - Common code related to device power domains. 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/io.h> 12#include <linux/pm_runtime.h> 13#include <linux/pm_domain.h> 14#include <linux/slab.h> 15#include <linux/err.h> 16 17#ifdef CONFIG_PM_RUNTIME 18 19static void genpd_sd_counter_dec(struct generic_pm_domain *genpd) 20{ 21 if (!WARN_ON(genpd->sd_count == 0)) 22 genpd->sd_count--; 23} 24 25/** 26 * __pm_genpd_save_device - Save the pre-suspend state of a device. 27 * @dle: Device list entry of the device to save the state of. 28 * @genpd: PM domain the device belongs to. 29 */ 30static int __pm_genpd_save_device(struct dev_list_entry *dle, 31 struct generic_pm_domain *genpd) 32{ 33 struct device *dev = dle->dev; 34 struct device_driver *drv = dev->driver; 35 int ret = 0; 36 37 if (dle->need_restore) 38 return 0; 39 40 if (drv && drv->pm && drv->pm->runtime_suspend) { 41 if (genpd->start_device) 42 genpd->start_device(dev); 43 44 ret = drv->pm->runtime_suspend(dev); 45 46 if (genpd->stop_device) 47 genpd->stop_device(dev); 48 } 49 50 if (!ret) 51 dle->need_restore = true; 52 53 return ret; 54} 55 56/** 57 * __pm_genpd_restore_device - Restore the pre-suspend state of a device. 58 * @dle: Device list entry of the device to restore the state of. 59 * @genpd: PM domain the device belongs to. 60 */ 61static void __pm_genpd_restore_device(struct dev_list_entry *dle, 62 struct generic_pm_domain *genpd) 63{ 64 struct device *dev = dle->dev; 65 struct device_driver *drv = dev->driver; 66 67 if (!dle->need_restore) 68 return; 69 70 if (drv && drv->pm && drv->pm->runtime_resume) { 71 if (genpd->start_device) 72 genpd->start_device(dev); 73 74 drv->pm->runtime_resume(dev); 75 76 if (genpd->stop_device) 77 genpd->stop_device(dev); 78 } 79 80 dle->need_restore = false; 81} 82 83/** 84 * pm_genpd_poweroff - Remove power from a given PM domain. 85 * @genpd: PM domain to power down. 86 * 87 * If all of the @genpd's devices have been suspended and all of its subdomains 88 * have been powered down, run the runtime suspend callbacks provided by all of 89 * the @genpd's devices' drivers and remove power from @genpd. 90 */ 91static int pm_genpd_poweroff(struct generic_pm_domain *genpd) 92{ 93 struct generic_pm_domain *parent; 94 struct dev_list_entry *dle; 95 unsigned int not_suspended; 96 int ret; 97 98 if (genpd->power_is_off) 99 return 0; 100 101 if (genpd->sd_count > 0) 102 return -EBUSY; 103 104 not_suspended = 0; 105 list_for_each_entry(dle, &genpd->dev_list, node) 106 if (dle->dev->driver && !pm_runtime_suspended(dle->dev)) 107 not_suspended++; 108 109 if (not_suspended > genpd->in_progress) 110 return -EBUSY; 111 112 if (genpd->gov && genpd->gov->power_down_ok) { 113 if (!genpd->gov->power_down_ok(&genpd->domain)) 114 return -EAGAIN; 115 } 116 117 list_for_each_entry_reverse(dle, &genpd->dev_list, node) { 118 ret = __pm_genpd_save_device(dle, genpd); 119 if (ret) 120 goto err_dev; 121 } 122 123 if (genpd->power_off) 124 genpd->power_off(genpd); 125 126 genpd->power_is_off = true; 127 128 parent = genpd->parent; 129 if (parent) { 130 genpd_sd_counter_dec(parent); 131 if (parent->sd_count == 0) 132 queue_work(pm_wq, &parent->power_off_work); 133 } 134 135 return 0; 136 137 err_dev: 138 list_for_each_entry_continue(dle, &genpd->dev_list, node) 139 __pm_genpd_restore_device(dle, genpd); 140 141 return ret; 142} 143 144/** 145 * genpd_power_off_work_fn - Power off PM domain whose subdomain count is 0. 146 * @work: Work structure used for scheduling the execution of this function. 147 */ 148static void genpd_power_off_work_fn(struct work_struct *work) 149{ 150 struct generic_pm_domain *genpd; 151 152 genpd = container_of(work, struct generic_pm_domain, power_off_work); 153 154 if (genpd->parent) 155 mutex_lock(&genpd->parent->lock); 156 mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING); 157 pm_genpd_poweroff(genpd); 158 mutex_unlock(&genpd->lock); 159 if (genpd->parent) 160 mutex_unlock(&genpd->parent->lock); 161} 162 163/** 164 * pm_genpd_runtime_suspend - Suspend a device belonging to I/O PM domain. 165 * @dev: Device to suspend. 166 * 167 * Carry out a runtime suspend of a device under the assumption that its 168 * pm_domain field points to the domain member of an object of type 169 * struct generic_pm_domain representing a PM domain consisting of I/O devices. 170 */ 171static int pm_genpd_runtime_suspend(struct device *dev) 172{ 173 struct generic_pm_domain *genpd; 174 175 dev_dbg(dev, "%s()\n", __func__); 176 177 if (IS_ERR_OR_NULL(dev->pm_domain)) 178 return -EINVAL; 179 180 genpd = container_of(dev->pm_domain, struct generic_pm_domain, domain); 181 182 if (genpd->parent) 183 mutex_lock(&genpd->parent->lock); 184 mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING); 185 186 if (genpd->stop_device) { 187 int ret = genpd->stop_device(dev); 188 if (ret) 189 goto out; 190 } 191 genpd->in_progress++; 192 pm_genpd_poweroff(genpd); 193 genpd->in_progress--; 194 195 out: 196 mutex_unlock(&genpd->lock); 197 if (genpd->parent) 198 mutex_unlock(&genpd->parent->lock); 199 200 return 0; 201} 202 203/** 204 * pm_genpd_poweron - Restore power to a given PM domain and its parents. 205 * @genpd: PM domain to power up. 206 * 207 * Restore power to @genpd and all of its parents so that it is possible to 208 * resume a device belonging to it. 209 */ 210static int pm_genpd_poweron(struct generic_pm_domain *genpd) 211{ 212 int ret = 0; 213 214 start: 215 if (genpd->parent) 216 mutex_lock(&genpd->parent->lock); 217 mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING); 218 219 if (!genpd->power_is_off) 220 goto out; 221 222 if (genpd->parent && genpd->parent->power_is_off) { 223 mutex_unlock(&genpd->lock); 224 mutex_unlock(&genpd->parent->lock); 225 226 ret = pm_genpd_poweron(genpd->parent); 227 if (ret) 228 return ret; 229 230 goto start; 231 } 232 233 if (genpd->power_on) { 234 int ret = genpd->power_on(genpd); 235 if (ret) 236 goto out; 237 } 238 239 genpd->power_is_off = false; 240 if (genpd->parent) 241 genpd->parent->sd_count++; 242 243 out: 244 mutex_unlock(&genpd->lock); 245 if (genpd->parent) 246 mutex_unlock(&genpd->parent->lock); 247 248 return ret; 249} 250 251/** 252 * pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain. 253 * @dev: Device to resume. 254 * 255 * Carry out a runtime resume of a device under the assumption that its 256 * pm_domain field points to the domain member of an object of type 257 * struct generic_pm_domain representing a PM domain consisting of I/O devices. 258 */ 259static int pm_genpd_runtime_resume(struct device *dev) 260{ 261 struct generic_pm_domain *genpd; 262 struct dev_list_entry *dle; 263 int ret; 264 265 dev_dbg(dev, "%s()\n", __func__); 266 267 if (IS_ERR_OR_NULL(dev->pm_domain)) 268 return -EINVAL; 269 270 genpd = container_of(dev->pm_domain, struct generic_pm_domain, domain); 271 272 ret = pm_genpd_poweron(genpd); 273 if (ret) 274 return ret; 275 276 mutex_lock(&genpd->lock); 277 278 list_for_each_entry(dle, &genpd->dev_list, node) { 279 if (dle->dev == dev) { 280 __pm_genpd_restore_device(dle, genpd); 281 break; 282 } 283 } 284 285 if (genpd->start_device) 286 genpd->start_device(dev); 287 288 mutex_unlock(&genpd->lock); 289 290 return 0; 291} 292 293#else 294 295static inline void genpd_power_off_work_fn(struct work_struct *work) {} 296 297#define pm_genpd_runtime_suspend NULL 298#define pm_genpd_runtime_resume NULL 299 300#endif /* CONFIG_PM_RUNTIME */ 301 302/** 303 * pm_genpd_add_device - Add a device to an I/O PM domain. 304 * @genpd: PM domain to add the device to. 305 * @dev: Device to be added. 306 */ 307int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) 308{ 309 struct dev_list_entry *dle; 310 int ret = 0; 311 312 dev_dbg(dev, "%s()\n", __func__); 313 314 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) 315 return -EINVAL; 316 317 mutex_lock(&genpd->lock); 318 319 if (genpd->power_is_off) { 320 ret = -EINVAL; 321 goto out; 322 } 323 324 list_for_each_entry(dle, &genpd->dev_list, node) 325 if (dle->dev == dev) { 326 ret = -EINVAL; 327 goto out; 328 } 329 330 dle = kzalloc(sizeof(*dle), GFP_KERNEL); 331 if (!dle) { 332 ret = -ENOMEM; 333 goto out; 334 } 335 336 dle->dev = dev; 337 dle->need_restore = false; 338 list_add_tail(&dle->node, &genpd->dev_list); 339 340 spin_lock_irq(&dev->power.lock); 341 dev->pm_domain = &genpd->domain; 342 spin_unlock_irq(&dev->power.lock); 343 344 out: 345 mutex_unlock(&genpd->lock); 346 347 return ret; 348} 349 350/** 351 * pm_genpd_remove_device - Remove a device from an I/O PM domain. 352 * @genpd: PM domain to remove the device from. 353 * @dev: Device to be removed. 354 */ 355int pm_genpd_remove_device(struct generic_pm_domain *genpd, 356 struct device *dev) 357{ 358 struct dev_list_entry *dle; 359 int ret = -EINVAL; 360 361 dev_dbg(dev, "%s()\n", __func__); 362 363 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) 364 return -EINVAL; 365 366 mutex_lock(&genpd->lock); 367 368 list_for_each_entry(dle, &genpd->dev_list, node) { 369 if (dle->dev != dev) 370 continue; 371 372 spin_lock_irq(&dev->power.lock); 373 dev->pm_domain = NULL; 374 spin_unlock_irq(&dev->power.lock); 375 376 list_del(&dle->node); 377 kfree(dle); 378 379 ret = 0; 380 break; 381 } 382 383 mutex_unlock(&genpd->lock); 384 385 return ret; 386} 387 388/** 389 * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. 390 * @genpd: Master PM domain to add the subdomain to. 391 * @new_subdomain: Subdomain to be added. 392 */ 393int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, 394 struct generic_pm_domain *new_subdomain) 395{ 396 struct generic_pm_domain *subdomain; 397 int ret = 0; 398 399 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(new_subdomain)) 400 return -EINVAL; 401 402 mutex_lock(&genpd->lock); 403 404 if (genpd->power_is_off && !new_subdomain->power_is_off) { 405 ret = -EINVAL; 406 goto out; 407 } 408 409 list_for_each_entry(subdomain, &genpd->sd_list, sd_node) { 410 if (subdomain == new_subdomain) { 411 ret = -EINVAL; 412 goto out; 413 } 414 } 415 416 mutex_lock_nested(&new_subdomain->lock, SINGLE_DEPTH_NESTING); 417 418 list_add_tail(&new_subdomain->sd_node, &genpd->sd_list); 419 new_subdomain->parent = genpd; 420 if (!subdomain->power_is_off) 421 genpd->sd_count++; 422 423 mutex_unlock(&new_subdomain->lock); 424 425 out: 426 mutex_unlock(&genpd->lock); 427 428 return ret; 429} 430 431/** 432 * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain. 433 * @genpd: Master PM domain to remove the subdomain from. 434 * @target: Subdomain to be removed. 435 */ 436int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, 437 struct generic_pm_domain *target) 438{ 439 struct generic_pm_domain *subdomain; 440 int ret = -EINVAL; 441 442 if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(target)) 443 return -EINVAL; 444 445 mutex_lock(&genpd->lock); 446 447 list_for_each_entry(subdomain, &genpd->sd_list, sd_node) { 448 if (subdomain != target) 449 continue; 450 451 mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING); 452 453 list_del(&subdomain->sd_node); 454 subdomain->parent = NULL; 455 if (!subdomain->power_is_off) 456 genpd_sd_counter_dec(genpd); 457 458 mutex_unlock(&subdomain->lock); 459 460 ret = 0; 461 break; 462 } 463 464 mutex_unlock(&genpd->lock); 465 466 return ret; 467} 468 469/** 470 * pm_genpd_init - Initialize a generic I/O PM domain object. 471 * @genpd: PM domain object to initialize. 472 * @gov: PM domain governor to associate with the domain (may be NULL). 473 * @is_off: Initial value of the domain's power_is_off field. 474 */ 475void pm_genpd_init(struct generic_pm_domain *genpd, 476 struct dev_power_governor *gov, bool is_off) 477{ 478 if (IS_ERR_OR_NULL(genpd)) 479 return; 480 481 INIT_LIST_HEAD(&genpd->sd_node); 482 genpd->parent = NULL; 483 INIT_LIST_HEAD(&genpd->dev_list); 484 INIT_LIST_HEAD(&genpd->sd_list); 485 mutex_init(&genpd->lock); 486 genpd->gov = gov; 487 INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn); 488 genpd->in_progress = 0; 489 genpd->sd_count = 0; 490 genpd->power_is_off = is_off; 491 genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; 492 genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; 493 genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; 494} 495