2. pm runtime introduction
2.1 pm_runtimedocumentation
Documentation/power/runtime_pm.txt
2.2 RuntimePM Device Fields
Common for runtime PM status:
.runtime_status = RPM_SUSPENDED;
.disable_depth = 1;
.runtime_error = 0;
.usage_count, 0);
.runtime_auto = true;
rpm_idle:
.idle_notification = false;
[wangshm5]For rpm_idle since no suspending/resuming statues to markthis feature in progress
For children:
power.child_count
.ingnor_children
For ASYNC mode:
.request_pending = false;
.request = RPM_REQ_NONE;
.deferred_resume = false;
For auto suspending feature:
.accounting_timestamp = jiffies;
.timer_expires = 0;
.last_busy -called after suspend immediately
.autosuspend_delay;
. use_autosuspend;
2.3 somepm_runtime helper function
2.3.1 rpm_resume
pm_runtime_resume(structdevice *dev) ó rpm_resume(dev,0)
pm_request_resume(structdevice *dev) ó rpm_resume(dev,RPM_ASYNC)
pm_runtime_get_sync(structdevice *dev) ó usage_count++;rpm_resume(dev,0)
pm_runtime_get(structdevice *dev) ó usage_count++;pm_resume(dev,RPM_ASYNC)
* If the resume callback returns an error code, the PMcore regards this as a fatal error and will refuse to run the helper functions until its status is directly set to either'active', or 'suspended' (by means ofspecial helper functions provided by the PM core for this purpose).
[wangshm5] NO -EBUSY or -EAGIAN, directlyother error code
* If->runtime_resume() is about to be executed or there's a pending request to execute it, the other callbacks will notbe executed for the same device.
* A request to execute->runtime_resume() will cancel any pending or scheduled requests to execute the othercallbacks for the same device, exceptfor scheduled autosuspends.
[wangshm5]Nearly future, IO operationneeded, so cancel other
2.3.2 Rpm_idle
pm_runtime_idle(struct device *dev) ó rpm_idle(dev,0)
pm_request_idle(struct device *dev) ó rpm_idle(dev,RPM_ASYNC)
pm_runtime_put_sync(structdevice *dev) ó usage_count--; ifusage_count != 0,return 0;rpm_idle(dev,0)
pm_runtime_put(structdevice *dev) ó usage_count--; ifusage_count != 0,return 0;rpm_idle(dev,RPM_ASYNC)
If there is no idle callback, or if the callback returns 0,then the PM core will attempt to carry out a runtime suspend of the device, alsorespecting devices configured for autosuspend.
Any pending request other than an idle notification takesprecedence over us, except that the timer may be running.
2.3.3 rpm_Suspend
pm_runtime_suspend(struct device *dev) ó rpm_suspend(dev,0)
pm_runtime_autosuspend(struct device *dev) ó rpm_suspend(dev,RPM_AUTO)
pm_request_autosuspend(struct device *dev) ó rpm_suspend(dev,RPM_ASYNC | RPM_AUTO)
pm_runtime_put_sync_suspend(struct device *dev) ó usage_count--; if usage_count != 0,return0;rpm_suspend(dev,0)
pm_runtime_put_sync_autosuspend(structdevice *dev) ó usage_count--; ifusage_count != 0,return 0;rpm_suspend(dev,RPM_AUTO)
pm_runtime_put_autosuspend(structdevice *dev) ó usage_count--; ifusage_count != 0,return 0;rpm_suspend(dev,RPM_ASYNC | RPM_AUTO)
[wangshm5] 默认的put是对应到idle的,加suspend才是对应到suspend的
[wangshm5]Nopm_runtime_put_suspend
2.3.4 irq_safe
By default, the callbacks are always invoked in processcontext with interrupts enabled (can sleep). However, the pm_runtime_irq_safe() helper function can be used to tellthe PM core that it is safe to run the ->runtime_suspend(),->runtime_resume() and ->runtime_idle() callbacks for the given device inatomic context with interrupts disabled.
2.3.5 Runtime rules
2.3.6 Tips
2.4 State Transaction
---------------------------------------------------20150720
SUSPEND without AUTO flag
| current status | SYNC | ASYNC | NOWAIT |
rpm_ resume | ACTIVE | 1(same) | ||
SUSPENDED | Callback (ACTIVE/SUSPENDED) | rpm_resume (dev,NOWAIT) | Callback (ACTIVE/SUSPENDED) | |
SUSPENDING | SLEEP_WAIT_ RESTART1 | Mark Deferred resume 2(same) | ||
RESUMING | EINPORGRESS(same) | |||
rpm_ suspend | ACTIVE | Callback (ACTIVE/SUSPENDED) | (dev,NOWAIT) | Callback (ACTIVE/SUSPENDED) |
SUSPENDED | 1(same) | |||
SUSPENDING | SLEEP_WAIT_ RESTART | EINPROGRESS(same) | ||
RESUMING | EAGAIN(same)4 Not allowed this operation | rpm_suspend (dev,NOWAIT) | EAGIN(same)5 Not allowed this operation | |
rpm_ idle | ACTIVE && not idle notification | Callback rpm_suspend(SYNC)3 | rpm_idle(dev, NOWAIT) | Callback rpm_suspend(SYNC)3 |
ACTIVE && idle notification | EINPROGRESS(same) | |||
SUSPENDED | 1(same) | |||
SUSPENDING | EAGAIN(same) | |||
RESUMING | EAGAIN(same) |
Notice: Inthe bracket is device status
Same: devicestatus stay unchanged
EAGAIN: a kind oferror, we can refer it as this operation is not allowed
Red: when callback failed, the device status
Blue: queue_work to workqueue, and call rpm_xxx in columnASYNC in the near future.
Brown: If callback executed failed, ACTIVE; else it noidle callback or success then invoke rpm_suspend
1、SLEEP_WAIT _RESTART: sleep until theother thread which is do suspending or resuming operation change the statusand wakeup it to go to the beginning ofthe rpm_xxx to redo the code.
2、Whichimplicate rpm_resume(SYNC) will be called immediately after SUSPENDED inrpm_suspend
3、Assumecallback should execute successfully.
4、Whenyou use SYNC mode, the resume function return the device should be ACTIVE. And evenASYNC mode, resume operation will try its best to execute ->runtime_resumecallback function to wakeup the device;
5、rpm_suspendtry tosuspend the device, but it cannot guarantee after call the device status isSUSPENDED
6、rpm_idletry to call rpm_suspend function with SYNC flag, so it cannot guarantee aftercall the device status is SUSPENDED
7、resumeoperation is always take precedence over suspend operation.
8、Synchronoussuspends are not allowed when device is in RESUMING mode4
9、Asyncwork queue always only pending the last RMP_RQQUEST_XXX
10、 other scheduled or pending requests need to be canceled atthe beginning of rpm_suspend
SUSPEND with AUTO flag
| current status | AUTO | ASYNC | AUTO | NOWAIT | AUTO | |||
rpm_ suspend | ACTIVE | Autosuspend delay time not expired | Autosuspend delay time expired | Autosuspend delay time not expired | Autosuspend delay timer expired | Autosuspend delay time not expired | Autosuspend delay timer expired |
Mod_timer (same) ,
timer_func: rpm_suspend (dev,ASYNC| AUTO); | Callback (ACTIVE /SUSPENDED) | Mod_timer to reschedule (same),
timer_func: rpm_suspend (dev,ASYNC| AUTO); | rpm_suspend (dev,NOWAIT| AUTO) | Mod_timer to reschedule (same)
timer_func: rpm_suspend(dev, ASYNC|AUTO) | Callback (ACTIVE /SUSPENDED) | ||
SUSPENDED | 1(same) | ||||||
SUSPENDING | SLEEP_WAIT_ RESTART | EINPROGRESS(same) | |||||
RESUMING | EAGAIN(same) | rpm_suspend (dev,NOWAIT) | EAGIN(same) |
Blue: queue_work toworkqueue, and call rpm_xxx in column ASYNC in the near future.