Chinaunix首页 | 论坛 | 博客
  • 博客访问: 198028
  • 博文数量: 68
  • 博客积分: 529
  • 博客等级: 中士
  • 技术积分: 721
  • 用 户 组: 普通用户
  • 注册时间: 2007-08-10 16:38
文章分类

全部博文(68)

文章存档

2014年(2)

2013年(4)

2012年(16)

2011年(34)

2010年(4)

2009年(8)

分类: LINUX

2012-05-30 15:19:26

通过pm_runtime , 我们可以很好的控制设备的状态, 设备suspend 的顺序为, 先父设备再子设备,
设备resume的顺序为, 先子设备,在父设备。
设备的回到函数的优先级从从高到低顺序为:
dev->pwr_domain 
dev->type->pm
dev->class->pm
dev->bus->pm

点击(此处)折叠或打开

  1. if (dev->pwr_domain)
  2. callback = dev->pwr_domain->ops.runtime_resume;
  3. else if (dev->type && dev->type->pm)
  4. callback = dev->type->pm->runtime_resume;
  5. else if (dev->class && dev->class->pm)
  6. callback = dev->class->pm->runtime_resume;
  7. else if (dev->bus && dev->bus->pm)
  8. callback = dev->bus->pm->runtime_resume;
  9. else
  10. callback = NULL;


也就是说,这个优先级顺序给我我们接口来安排各个设备的 resume 和 suspend顺序。

对于platform device 设备, 它调用的是通用的pm_runtime 接口。

点击(此处)折叠或打开

  1. static const struct dev_pm_ops platform_dev_pm_ops = {
  2. .runtime_suspend = pm_generic_runtime_suspend,
  3. .runtime_resume = pm_generic_runtime_resume,
  4. .runtime_idle = pm_generic_runtime_idle,
  5. USE_PLATFORM_PM_SLEEP_OPS
  6. };


点击(此处)折叠或打开

  1. /**
  2. * rpm_resume - Carry out run-time resume of given device.
  3. * @dev: Device to resume.
  4. * @rpmflags: Flag bits.
  5. *
  6. * Check if the device's run-time PM status allows it to be resumed. Cancel
  7. * any scheduled or pending requests. If another resume has been started
  8. * earlier, either return immediately or wait for it to finish, depending on the
  9. * RPM_NOWAIT and RPM_ASYNC flags. Similarly, if there's a suspend running in
  10. * parallel with this function, either tell the other process to resume after
  11. * suspending (deferred_resume) or wait for it to finish. If the RPM_ASYNC
  12. * flag is set then queue a resume request; otherwise run the
  13. * ->runtime_resume() callback directly. Queue an idle notification for the
  14. * device if the resume succeeded.
  15. *
  16. * This function must be called under dev->power.lock with interrupts disabled.
  17. */
  18. /× 正常情况下, 有先resume 负设备 , 在resume 子设备 ×/
  19. static int rpm_resume(struct device *dev, int rpmflags)
  20. __releases(&dev->power.lock) __acquires(&dev->power.lock)
  21. {
  22. int (*callback)(struct device *);
  23. struct device *parent = NULL;
  24. int retval = 0;
  25. dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
  26. repeat:
  27. if (dev->power.runtime_error) /× 如果调用设备的callback 函数出错误, 则更新runtime_error */
  28. retval = -EINVAL;
  29. else if (dev->power.disable_depth > 0) /* disable_depth 初始值为1, pm_runtime_enable 将-- __pm_runtime_disable 将++ 这个值 ×/
  30. retval = -EAGAIN; /× 如果值不为零, 则直接返回 ×/
  31. if (retval)
  32. goto out;
  33. /*
  34. * Other scheduled or pending requests need to be canceled. Small
  35. * optimization: If an autosuspend timer is running, leave it running
  36. * rather than cancelling it now only to restart it again in the near
  37. * future.
  38. */
  39. dev->power.request = RPM_REQ_NONE;
  40. /× 如果不是自动suspend, 则 停止suspend timer */
  41. if (!dev->power.timer_autosuspends)
  42. pm_runtime_deactivate_timer(dev);
  43. /* 当设备创建后, runtime_status的初始化值为RPM_SUSPENDED , 此后这个值的调用是通过 __update_runtime_status×/
  44. /× 如果设备是active,则 直接返回 ×/
  45. if (dev->power.runtime_status == RPM_ACTIVE) {
  46. retval = 1;
  47. goto out;
  48. }
  49. /× 此时设备正在resuming or suspending */
  50. if (dev->power.runtime_status == RPM_RESUMING
  51. || dev->power.runtime_status == RPM_SUSPENDING) {
  52. DEFINE_WAIT(wait);
  53. /* 如果是异步的,并且不等待,则 设置deferred_resume, 让suspend 后直接resume */
  54. if (rpmflags & (RPM_ASYNC | RPM_NOWAIT)) {
  55. if (dev->power.runtime_status == RPM_SUSPENDING)
  56. dev->power.deferred_resume = true;
  57. else
  58. retval = -EINPROGRESS;
  59. goto out;
  60. }
  61. /* Wait for the operation carried out in parallel with us. */
  62. for (;;) {
  63. prepare_to_wait(&dev->power.wait_queue, &wait,
  64. TASK_UNINTERRUPTIBLE);
  65. if (dev->power.runtime_status != RPM_RESUMING
  66. && dev->power.runtime_status != RPM_SUSPENDING)
  67. break;
  68. spin_unlock_irq(&dev->power.lock);
  69. schedule();
  70. spin_lock_irq(&dev->power.lock);
  71. }
  72. finish_wait(&dev->power.wait_queue, &wait);
  73. goto repeat;
  74. }
  75. /*
  76. * See if we can skip waking up the parent. This is safe only if
  77. * power.no_callbacks is set, because otherwise we don't know whether
  78. * the resume will actually succeed.
  79. */
  80. if (dev->power.no_callbacks && !parent && dev->parent) {
  81. spin_lock_nested(&dev->parent->power.lock, SINGLE_DEPTH_NESTING);
  82. if (dev->parent->power.disable_depth > 0
  83. || dev->parent->power.ignore_children
  84. || dev->parent->power.runtime_status == RPM_ACTIVE) {
  85. atomic_inc(&dev->parent->power.child_count);
  86. spin_unlock(&dev->parent->power.lock);
  87. goto no_callback; /* Assume success. */
  88. }
  89. spin_unlock(&dev->parent->power.lock);
  90. }
  91. /* 如果是异步的, 有工作队列负责resume */
  92. /* Carry out an asynchronous or a synchronous resume. */
  93. if (rpmflags & RPM_ASYNC) {
  94. dev->power.request = RPM_REQ_RESUME;
  95. if (!dev->power.request_pending) {
  96. dev->power.request_pending = true;
  97. queue_work(pm_wq, &dev->power.work);
  98. }
  99. retval = 0;
  100. goto out;
  101. }
  102. if (!parent && dev->parent) {
  103. /*
  104. * Increment the parent's usage counter and resume it if
  105. * necessary. Not needed if dev is irq-safe; then the
  106. * parent is permanently resumed.
  107. */
  108. parent = dev->parent;
  109. if (dev->power.irq_safe)
  110. goto skip_parent;
  111. spin_unlock(&dev->power.lock);
  112. /* 增加父设备的引用计数 ×/
  113. pm_runtime_get_noresume(parent);
  114. spin_lock(&parent->power.lock);
  115. /*
  116. * We can resume if the parent's run-time PM is disabled or it
  117. * is set to ignore children.
  118. */
  119. if (!parent->power.disable_depth
  120. && !parent->power.ignore_children) {
  121. /× resume 负设备 ×/
  122. rpm_resume(parent, 0);
  123. if (parent->power.runtime_status != RPM_ACTIVE)
  124. retval = -EBUSY;
  125. }
  126. spin_unlock(&parent->power.lock);
  127. spin_lock(&dev->power.lock);
  128. if (retval)
  129. goto out;
  130. goto repeat;
  131. }
  132. skip_parent:
  133. if (dev->power.no_callbacks)
  134. goto no_callback; /* Assume success. */
  135. __update_runtime_status(dev, RPM_RESUMING);
  136. if (dev->pwr_domain)
  137. callback = dev->pwr_domain->ops.runtime_resume;
  138. else if (dev->type && dev->type->pm)
  139. callback = dev->type->pm->runtime_resume;
  140. else if (dev->class && dev->class->pm)
  141. callback = dev->class->pm->runtime_resume;
  142. else if (dev->bus && dev->bus->pm)
  143. callback = dev->bus->pm->runtime_resume;
  144. else
  145. callback = NULL;
  146. /× 执行真正的resume函数 ×/
  147. retval = rpm_callback(callback, dev);
  148. if (retval) {
  149. __update_runtime_status(dev, RPM_SUSPENDED);
  150. pm_runtime_cancel_pending(dev);
  151. } else {
  152. no_callback:
  153. __update_runtime_status(dev, RPM_ACTIVE);
  154. if (parent)
  155. atomic_inc(&parent->power.child_count);
  156. }
  157. wake_up_all(&dev->power.wait_queue);
  158. /× 如果正常, 则idle 设备 ×/
  159. if (!retval)
  160. rpm_idle(dev, RPM_ASYNC);
  161. out:
  162. if (parent && !dev->power.irq_safe) {
  163. spin_unlock_irq(&dev->power.lock);
  164. /* idle 父设别 ×/
  165. pm_runtime_put(parent);
  166. spin_lock_irq(&dev->power.lock);
  167. }
  168. dev_dbg(dev, "%s returns %d\n", __func__, retval);
  169. return retval;
  170. }
  171. /**
  172. * rpm_idle - Notify device bus type if the device can be suspended.
  173. * @dev: Device to notify the bus type about.
  174. * @rpmflags: Flag bits.
  175. *
  176. * Check if the device's run-time PM status allows it to be suspended. If
  177. * another idle notification has been started earlier, return immediately. If
  178. * the RPM_ASYNC flag is set then queue an idle-notification request; otherwise
  179. * run the ->runtime_idle() callback directly.
  180. *
  181. * This function must be called under dev->power.lock with interrupts disabled.
  182. */
  183. static int rpm_idle(struct device *dev, int rpmflags)
  184. {
  185. int (*callback)(struct device *);
  186. int retval;
  187. retval = rpm_check_suspend_allowed(dev);
  188. if (retval < 0)
  189. ; /* Conditions are wrong. */
  190. /* Idle notifications are allowed only in the RPM_ACTIVE state. */
  191. else if (dev->power.runtime_status != RPM_ACTIVE)
  192. retval = -EAGAIN;
  193. /*
  194. * Any pending request other than an idle notification takes
  195. * precedence over us, except that the timer may be running.
  196. */
  197. else if (dev->power.request_pending &&
  198. dev->power.request > RPM_REQ_IDLE)
  199. retval = -EAGAIN;
  200. /* Act as though RPM_NOWAIT is always set. */
  201. else if (dev->power.idle_notification)
  202. retval = -EINPROGRESS;
  203. if (retval)
  204. goto out;
  205. /* Pending requests need to be canceled. */
  206. dev->power.request = RPM_REQ_NONE;
  207. if (dev->power.no_callbacks) {
  208. /* Assume ->runtime_idle() callback would have suspended. */
  209. retval = rpm_suspend(dev, rpmflags);
  210. goto out;
  211. }
  212. /* Carry out an asynchronous or a synchronous idle notification. */
  213. if (rpmflags & RPM_ASYNC) {
  214. dev->power.request = RPM_REQ_IDLE;
  215. if (!dev->power.request_pending) {
  216. dev->power.request_pending = true;
  217. queue_work(pm_wq, &dev->power.work);
  218. }
  219. goto out;
  220. }
  221. dev->power.idle_notification = true;
  222. if (dev->pwr_domain)
  223. callback = dev->pwr_domain->ops.runtime_idle;
  224. else if (dev->type && dev->type->pm)
  225. callback = dev->type->pm->runtime_idle;
  226. else if (dev->class && dev->class->pm)
  227. callback = dev->class->pm->runtime_idle;
  228. else if (dev->bus && dev->bus->pm)
  229. callback = dev->bus->pm->runtime_idle;
  230. else
  231. callback = NULL;
  232. if (callback) {
  233. spin_unlock_irq(&dev->power.lock);
  234. callback(dev);
  235. spin_lock_irq(&dev->power.lock);
  236. }
  237. dev->power.idle_notification = false;
  238. wake_up_all(&dev->power.wait_queue);
  239. out:
  240. return retval;
  241. }
  242. /**
  243. * rpm_suspend - Carry out run-time suspend of given device.
  244. * @dev: Device to suspend.
  245. * @rpmflags: Flag bits.
  246. *
  247. * Check if the device's run-time PM status allows it to be suspended. If
  248. * another suspend has been started earlier, either return immediately or wait
  249. * for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC flags. Cancel a
  250. * pending idle notification. If the RPM_ASYNC flag is set then queue a
  251. * suspend request; otherwise run the ->runtime_suspend() callback directly.
  252. * If a deferred resume was requested while the callback was running then carry
  253. * it out; otherwise send an idle notification for the device (if the suspend
  254. * failed) or for its parent (if the suspend succeeded).
  255. * If ->runtime_suspend failed with -EAGAIN or -EBUSY, and if the RPM_AUTO
  256. * flag is set and the next autosuspend-delay expiration time is in the
  257. * future, schedule another autosuspend attempt.
  258. *
  259. * This function must be called under dev->power.lock with interrupts disabled.
  260. */
  261. static int rpm_suspend(struct device *dev, int rpmflags)
  262. __releases(&dev->power.lock) __acquires(&dev->power.lock)
  263. {
  264. int (*callback)(struct device *);
  265. struct device *parent = NULL;
  266. int retval;
  267. dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
  268. repeat:
  269. retval = rpm_check_suspend_allowed(dev);
  270. if (retval < 0)
  271. ; /* Conditions are wrong. */
  272. /* Synchronous suspends are not allowed in the RPM_RESUMING state. */
  273. else if (dev->power.runtime_status == RPM_RESUMING &&
  274. !(rpmflags & RPM_ASYNC))
  275. retval = -EAGAIN;
  276. if (retval)
  277. goto out;
  278. /* If the autosuspend_delay time hasn't expired yet, reschedule. */
  279. if ((rpmflags & RPM_AUTO)
  280. && dev->power.runtime_status != RPM_SUSPENDING) {
  281. unsigned long expires = pm_runtime_autosuspend_expiration(dev);
  282. if (expires != 0) {
  283. /* Pending requests need to be canceled. */
  284. dev->power.request = RPM_REQ_NONE;
  285. /*
  286. * Optimization: If the timer is already running and is
  287. * set to expire at or before the autosuspend delay,
  288. * avoid the overhead of resetting it. Just let it
  289. * expire; pm_suspend_timer_fn() will take care of the
  290. * rest.
  291. */
  292. if (!(dev->power.timer_expires && time_before_eq(
  293. dev->power.timer_expires, expires))) {
  294. dev->power.timer_expires = expires;
  295. mod_timer(&dev->power.suspend_timer, expires);
  296. }
  297. dev->power.timer_autosuspends = 1;
  298. goto out;
  299. }
  300. }
  301. /* Other scheduled or pending requests need to be canceled. */
  302. pm_runtime_cancel_pending(dev);
  303. if (dev->power.runtime_status == RPM_SUSPENDING) {
  304. DEFINE_WAIT(wait);
  305. if (rpmflags & (RPM_ASYNC | RPM_NOWAIT)) {
  306. retval = -EINPROGRESS;
  307. goto out;
  308. }
  309. /* Wait for the other suspend running in parallel with us. */
  310. for (;;) {
  311. prepare_to_wait(&dev->power.wait_queue, &wait,
  312. TASK_UNINTERRUPTIBLE);
  313. if (dev->power.runtime_status != RPM_SUSPENDING)
  314. break;
  315. spin_unlock_irq(&dev->power.lock);
  316. schedule();
  317. spin_lock_irq(&dev->power.lock);
  318. }
  319. finish_wait(&dev->power.wait_queue, &wait);
  320. goto repeat;
  321. }
  322. dev->power.deferred_resume = false;
  323. if (dev->power.no_callbacks)
  324. goto no_callback; /* Assume success. */
  325. /* Carry out an asynchronous or a synchronous suspend. */
  326. if (rpmflags & RPM_ASYNC) {
  327. dev->power.request = (rpmflags & RPM_AUTO) ?
  328. RPM_REQ_AUTOSUSPEND : RPM_REQ_SUSPEND;
  329. if (!dev->power.request_pending) {
  330. dev->power.request_pending = true;
  331. queue_work(pm_wq, &dev->power.work);
  332. }
  333. goto out;
  334. }
  335. __update_runtime_status(dev, RPM_SUSPENDING);
  336. if (dev->pwr_domain)
  337. callback = dev->pwr_domain->ops.runtime_suspend;
  338. else if (dev->type && dev->type->pm)
  339. callback = dev->type->pm->runtime_suspend;
  340. else if (dev->class && dev->class->pm)
  341. callback = dev->class->pm->runtime_suspend;
  342. else if (dev->bus && dev->bus->pm)
  343. callback = dev->bus->pm->runtime_suspend;
  344. else
  345. callback = NULL;
  346. retval = rpm_callback(callback, dev);
  347. if (retval) {
  348. __update_runtime_status(dev, RPM_ACTIVE);
  349. dev->power.deferred_resume = 0;
  350. if (retval == -EAGAIN || retval == -EBUSY) {
  351. dev->power.runtime_error = 0;
  352. /*
  353. * If the callback routine failed an autosuspend, and
  354. * if the last_busy time has been updated so that there
  355. * is a new autosuspend expiration time, automatically
  356. * reschedule another autosuspend.
  357. */
  358. if ((rpmflags & RPM_AUTO) &&
  359. pm_runtime_autosuspend_expiration(dev) != 0)
  360. goto repeat;
  361. } else {
  362. pm_runtime_cancel_pending(dev);
  363. }
  364. } else {
  365. no_callback:
  366. __update_runtime_status(dev, RPM_SUSPENDED);
  367. pm_runtime_deactivate_timer(dev);
  368. if (dev->parent) {
  369. parent = dev->parent;
  370. atomic_add_unless(&parent->power.child_count, -1, 0);
  371. }
  372. }
  373. wake_up_all(&dev->power.wait_queue);
  374. if (dev->power.deferred_resume) {
  375. rpm_resume(dev, 0);
  376. retval = -EAGAIN;
  377. goto out;
  378. }
  379. /* Maybe the parent is now able to suspend. */
  380. if (parent && !parent->power.ignore_children && !dev->power.irq_safe) {
  381. spin_unlock(&dev->power.lock);
  382. spin_lock(&parent->power.lock);
  383. rpm_idle(parent, RPM_ASYNC);
  384. spin_unlock(&parent->power.lock);
  385. spin_lock(&dev->power.lock);
  386. }
  387. out:
  388. dev_dbg(dev, "%s returns %d\n", __func__, retval);
  389. return retval;
  390. }
  391. /**
  392. * pm_generic_runtime_idle - Generic runtime idle callback for subsystems.
  393. * @dev: Device to handle.
  394. *
  395. * If PM operations are defined for the @dev's driver and they include
  396. * ->runtime_idle(), execute it and return its error code, if nonzero.
  397. * Otherwise, execute pm_runtime_suspend() for the device and return 0.
  398. */
  399. int pm_generic_runtime_idle(struct device *dev)
  400. {
  401. const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
  402. if (pm && pm->runtime_idle) {
  403. int ret = pm->runtime_idle(dev);
  404. if (ret)
  405. return ret;
  406. }
  407. pm_runtime_suspend(dev);
  408. return 0;
  409. }
设备接口的调用:


probe:

pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev,
omap_up_info->auto_sus_timeout);

if (device_may_wakeup(&pdev->dev))
pm_runtime_enable(&pdev->dev);

pm_runtime_irq_safe(&pdev->dev);


点击(此处)折叠或打开

  1. int omap_uart_enable(u8 uart_num)
  2. {
  3. if (uart_num > OMAP_MAX_HSUART_PORTS)
  4. return -ENODEV;
  5. if (!ui[uart_num - 1])
  6. return -ENODEV;
  7. pm_runtime_get_sync(&ui[uart_num - 1]->pdev->dev);
  8. return 0;
  9. }
  10. int omap_uart_disable(u8 uart_num)
  11. {
  12. if (uart_num > OMAP_MAX_HSUART_PORTS)
  13. return -ENODEV;
  14. if (!ui[uart_num - 1])
  15. return -ENODEV;
  16. pm_runtime_put_sync_suspend(&ui[uart_num - 1]->pdev->dev);
  17. return 0;
  18. }





阅读(2415) | 评论(1) | 转发(0) |
0

上一篇:linux启动综述

下一篇:audio alsa driver

给主人留下些什么吧!~~

suyingshipp2012-09-20 07:10:53

前面解释的还挺详细的 但是后面就 如在后面接口调用那块 为什么不举个例子来分析 呵呵 以后会多关注一下你的文章 学习学习