Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PM: Introduce generic "noirq" callback routines for subsystems (v2)

Introduce generic "noirq" power management callback routines for
subsystems in addition to the "regular" generic PM callback routines.

The new routines will be used, among other things, for implementing
system-wide PM transitions support for generic PM domains.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>

+119 -17
+30 -2
Documentation/power/runtime_pm.txt
··· 606 606 callback provided by its driver and return its result, or return 0 if not 607 607 defined 608 608 609 + int pm_generic_suspend_noirq(struct device *dev); 610 + - if pm_runtime_suspended(dev) returns "false", invoke the ->suspend_noirq() 611 + callback provided by the device's driver and return its result, or return 612 + 0 if not defined 613 + 609 614 int pm_generic_resume(struct device *dev); 610 615 - invoke the ->resume() callback provided by the driver of this device and, 611 616 if successful, change the device's runtime PM status to 'active' 617 + 618 + int pm_generic_resume_noirq(struct device *dev); 619 + - invoke the ->resume_noirq() callback provided by the driver of this device 612 620 613 621 int pm_generic_freeze(struct device *dev); 614 622 - if the device has not been suspended at run time, invoke the ->freeze() 615 623 callback provided by its driver and return its result, or return 0 if not 616 624 defined 617 625 626 + int pm_generic_freeze_noirq(struct device *dev); 627 + - if pm_runtime_suspended(dev) returns "false", invoke the ->freeze_noirq() 628 + callback provided by the device's driver and return its result, or return 629 + 0 if not defined 630 + 618 631 int pm_generic_thaw(struct device *dev); 619 632 - if the device has not been suspended at run time, invoke the ->thaw() 620 633 callback provided by its driver and return its result, or return 0 if not 621 634 defined 635 + 636 + int pm_generic_thaw_noirq(struct device *dev); 637 + - if pm_runtime_suspended(dev) returns "false", invoke the ->thaw_noirq() 638 + callback provided by the device's driver and return its result, or return 639 + 0 if not defined 622 640 623 641 int pm_generic_poweroff(struct device *dev); 624 642 - if the device has not been suspended at run time, invoke the ->poweroff() 625 643 callback provided by its driver and return its result, or return 0 if not 626 644 defined 627 645 646 + int pm_generic_poweroff_noirq(struct device *dev); 647 + - if pm_runtime_suspended(dev) returns "false", run the ->poweroff_noirq() 648 + callback provided by the device's driver and return its result, or return 649 + 0 if not defined 650 + 628 651 int pm_generic_restore(struct device *dev); 629 652 - invoke the ->restore() callback provided by the driver of this device and, 630 653 if successful, change the device's runtime PM status to 'active' 631 654 655 + int pm_generic_restore_noirq(struct device *dev); 656 + - invoke the ->restore_noirq() callback provided by the device's driver 657 + 632 658 These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(), 633 - ->runtime_resume(), ->suspend(), ->resume(), ->freeze(), ->thaw(), ->poweroff(), 634 - or ->restore() callback pointers in the subsystem-level dev_pm_ops structures. 659 + ->runtime_resume(), ->suspend(), ->suspend_noirq(), ->resume(), 660 + ->resume_noirq(), ->freeze(), ->freeze_noirq(), ->thaw(), ->thaw_noirq(), 661 + ->poweroff(), ->poweroff_noirq(), ->restore(), ->restore_noirq() callback 662 + pointers in the subsystem-level dev_pm_ops structures. 635 663 636 664 If a subsystem wishes to use all of them at the same time, it can simply assign 637 665 the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its
+83 -15
drivers/base/power/generic_ops.c
··· 94 94 * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. 95 95 * @dev: Device to handle. 96 96 * @event: PM transition of the system under way. 97 + * @bool: Whether or not this is the "noirq" stage. 97 98 * 98 99 * If the device has not been suspended at run time, execute the 99 100 * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and 100 101 * return its error code. Otherwise, return zero. 101 102 */ 102 - static int __pm_generic_call(struct device *dev, int event) 103 + static int __pm_generic_call(struct device *dev, int event, bool noirq) 103 104 { 104 105 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 105 106 int (*callback)(struct device *); ··· 110 109 111 110 switch (event) { 112 111 case PM_EVENT_SUSPEND: 113 - callback = pm->suspend; 112 + callback = noirq ? pm->suspend_noirq : pm->suspend; 114 113 break; 115 114 case PM_EVENT_FREEZE: 116 - callback = pm->freeze; 115 + callback = noirq ? pm->freeze_noirq : pm->freeze; 117 116 break; 118 117 case PM_EVENT_HIBERNATE: 119 - callback = pm->poweroff; 118 + callback = noirq ? pm->poweroff_noirq : pm->poweroff; 120 119 break; 121 120 case PM_EVENT_THAW: 122 - callback = pm->thaw; 121 + callback = noirq ? pm->thaw_noirq : pm->thaw; 123 122 break; 124 123 default: 125 124 callback = NULL; ··· 130 129 } 131 130 132 131 /** 132 + * pm_generic_suspend_noirq - Generic suspend_noirq callback for subsystems. 133 + * @dev: Device to suspend. 134 + */ 135 + int pm_generic_suspend_noirq(struct device *dev) 136 + { 137 + return __pm_generic_call(dev, PM_EVENT_SUSPEND, true); 138 + } 139 + EXPORT_SYMBOL_GPL(pm_generic_suspend_noirq); 140 + 141 + /** 133 142 * pm_generic_suspend - Generic suspend callback for subsystems. 134 143 * @dev: Device to suspend. 135 144 */ 136 145 int pm_generic_suspend(struct device *dev) 137 146 { 138 - return __pm_generic_call(dev, PM_EVENT_SUSPEND); 147 + return __pm_generic_call(dev, PM_EVENT_SUSPEND, false); 139 148 } 140 149 EXPORT_SYMBOL_GPL(pm_generic_suspend); 150 + 151 + /** 152 + * pm_generic_freeze_noirq - Generic freeze_noirq callback for subsystems. 153 + * @dev: Device to freeze. 154 + */ 155 + int pm_generic_freeze_noirq(struct device *dev) 156 + { 157 + return __pm_generic_call(dev, PM_EVENT_FREEZE, true); 158 + } 159 + EXPORT_SYMBOL_GPL(pm_generic_freeze_noirq); 141 160 142 161 /** 143 162 * pm_generic_freeze - Generic freeze callback for subsystems. ··· 165 144 */ 166 145 int pm_generic_freeze(struct device *dev) 167 146 { 168 - return __pm_generic_call(dev, PM_EVENT_FREEZE); 147 + return __pm_generic_call(dev, PM_EVENT_FREEZE, false); 169 148 } 170 149 EXPORT_SYMBOL_GPL(pm_generic_freeze); 150 + 151 + /** 152 + * pm_generic_poweroff_noirq - Generic poweroff_noirq callback for subsystems. 153 + * @dev: Device to handle. 154 + */ 155 + int pm_generic_poweroff_noirq(struct device *dev) 156 + { 157 + return __pm_generic_call(dev, PM_EVENT_HIBERNATE, true); 158 + } 159 + EXPORT_SYMBOL_GPL(pm_generic_poweroff_noirq); 171 160 172 161 /** 173 162 * pm_generic_poweroff - Generic poweroff callback for subsystems. ··· 185 154 */ 186 155 int pm_generic_poweroff(struct device *dev) 187 156 { 188 - return __pm_generic_call(dev, PM_EVENT_HIBERNATE); 157 + return __pm_generic_call(dev, PM_EVENT_HIBERNATE, false); 189 158 } 190 159 EXPORT_SYMBOL_GPL(pm_generic_poweroff); 160 + 161 + /** 162 + * pm_generic_thaw_noirq - Generic thaw_noirq callback for subsystems. 163 + * @dev: Device to thaw. 164 + */ 165 + int pm_generic_thaw_noirq(struct device *dev) 166 + { 167 + return __pm_generic_call(dev, PM_EVENT_THAW, true); 168 + } 169 + EXPORT_SYMBOL_GPL(pm_generic_thaw_noirq); 191 170 192 171 /** 193 172 * pm_generic_thaw - Generic thaw callback for subsystems. ··· 205 164 */ 206 165 int pm_generic_thaw(struct device *dev) 207 166 { 208 - return __pm_generic_call(dev, PM_EVENT_THAW); 167 + return __pm_generic_call(dev, PM_EVENT_THAW, false); 209 168 } 210 169 EXPORT_SYMBOL_GPL(pm_generic_thaw); 211 170 ··· 213 172 * __pm_generic_resume - Generic resume/restore callback for subsystems. 214 173 * @dev: Device to handle. 215 174 * @event: PM transition of the system under way. 175 + * @bool: Whether or not this is the "noirq" stage. 216 176 * 217 177 * Execute the resume/resotre callback provided by the @dev's driver, if 218 178 * defined. If it returns 0, change the device's runtime PM status to 'active'. 219 179 * Return the callback's error code. 220 180 */ 221 - static int __pm_generic_resume(struct device *dev, int event) 181 + static int __pm_generic_resume(struct device *dev, int event, bool noirq) 222 182 { 223 183 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 224 184 int (*callback)(struct device *); ··· 230 188 231 189 switch (event) { 232 190 case PM_EVENT_RESUME: 233 - callback = pm->resume; 191 + callback = noirq ? pm->resume_noirq : pm->resume; 234 192 break; 235 193 case PM_EVENT_RESTORE: 236 - callback = pm->restore; 194 + callback = noirq ? pm->restore_noirq : pm->restore; 237 195 break; 238 196 default: 239 197 callback = NULL; ··· 244 202 return 0; 245 203 246 204 ret = callback(dev); 247 - if (!ret && pm_runtime_enabled(dev)) { 205 + if (!ret && !noirq && pm_runtime_enabled(dev)) { 248 206 pm_runtime_disable(dev); 249 207 pm_runtime_set_active(dev); 250 208 pm_runtime_enable(dev); ··· 254 212 } 255 213 256 214 /** 215 + * pm_generic_resume_noirq - Generic resume_noirq callback for subsystems. 216 + * @dev: Device to resume. 217 + */ 218 + int pm_generic_resume_noirq(struct device *dev) 219 + { 220 + return __pm_generic_resume(dev, PM_EVENT_RESUME, true); 221 + } 222 + EXPORT_SYMBOL_GPL(pm_generic_resume_noirq); 223 + 224 + /** 257 225 * pm_generic_resume - Generic resume callback for subsystems. 258 226 * @dev: Device to resume. 259 227 */ 260 228 int pm_generic_resume(struct device *dev) 261 229 { 262 - return __pm_generic_resume(dev, PM_EVENT_RESUME); 230 + return __pm_generic_resume(dev, PM_EVENT_RESUME, false); 263 231 } 264 232 EXPORT_SYMBOL_GPL(pm_generic_resume); 233 + 234 + /** 235 + * pm_generic_restore_noirq - Generic restore_noirq callback for subsystems. 236 + * @dev: Device to restore. 237 + */ 238 + int pm_generic_restore_noirq(struct device *dev) 239 + { 240 + return __pm_generic_resume(dev, PM_EVENT_RESTORE, true); 241 + } 242 + EXPORT_SYMBOL_GPL(pm_generic_restore_noirq); 265 243 266 244 /** 267 245 * pm_generic_restore - Generic restore callback for subsystems. ··· 289 227 */ 290 228 int pm_generic_restore(struct device *dev) 291 229 { 292 - return __pm_generic_resume(dev, PM_EVENT_RESTORE); 230 + return __pm_generic_resume(dev, PM_EVENT_RESTORE, false); 293 231 } 294 232 EXPORT_SYMBOL_GPL(pm_generic_restore); 295 233 ··· 318 256 #ifdef CONFIG_PM_SLEEP 319 257 .prepare = pm_generic_prepare, 320 258 .suspend = pm_generic_suspend, 259 + .suspend_noirq = pm_generic_suspend_noirq, 321 260 .resume = pm_generic_resume, 261 + .resume_noirq = pm_generic_resume_noirq, 322 262 .freeze = pm_generic_freeze, 263 + .freeze_noirq = pm_generic_freeze_noirq, 323 264 .thaw = pm_generic_thaw, 265 + .thaw_noirq = pm_generic_thaw_noirq, 324 266 .poweroff = pm_generic_poweroff, 267 + .poweroff_noirq = pm_generic_poweroff_noirq, 325 268 .restore = pm_generic_restore, 269 + .restore_noirq = pm_generic_restore_noirq, 326 270 .complete = pm_generic_complete, 327 271 #endif 328 272 #ifdef CONFIG_PM_RUNTIME
+6
include/linux/pm.h
··· 553 553 extern int device_pm_wait_for_dev(struct device *sub, struct device *dev); 554 554 555 555 extern int pm_generic_prepare(struct device *dev); 556 + extern int pm_generic_suspend_noirq(struct device *dev); 556 557 extern int pm_generic_suspend(struct device *dev); 558 + extern int pm_generic_resume_noirq(struct device *dev); 557 559 extern int pm_generic_resume(struct device *dev); 560 + extern int pm_generic_freeze_noirq(struct device *dev); 558 561 extern int pm_generic_freeze(struct device *dev); 562 + extern int pm_generic_thaw_noirq(struct device *dev); 559 563 extern int pm_generic_thaw(struct device *dev); 564 + extern int pm_generic_restore_noirq(struct device *dev); 560 565 extern int pm_generic_restore(struct device *dev); 566 + extern int pm_generic_poweroff_noirq(struct device *dev); 561 567 extern int pm_generic_poweroff(struct device *dev); 562 568 extern void pm_generic_complete(struct device *dev); 563 569