autosleep.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * kernel/power/autosleep.c
  3. *
  4. * Opportunistic sleep support.
  5. *
  6. * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
  7. */
  8. #include <linux/device.h>
  9. #include <linux/mutex.h>
  10. #include <linux/pm_wakeup.h>
  11. #include "power.h"
  12. static suspend_state_t autosleep_state;
  13. static struct workqueue_struct *autosleep_wq;
  14. /*
  15. * Note: it is only safe to mutex_lock(&autosleep_lock) if a wakeup_source
  16. * is active, otherwise a deadlock with try_to_suspend() is possible.
  17. * Alternatively mutex_lock_interruptible() can be used. This will then fail
  18. * if an auto_sleep cycle tries to freeze processes.
  19. */
  20. static DEFINE_MUTEX(autosleep_lock);
  21. static struct wakeup_source *autosleep_ws;
  22. static void try_to_suspend(struct work_struct *work)
  23. {
  24. unsigned int initial_count, final_count;
  25. if (!pm_get_wakeup_count(&initial_count, true))
  26. goto out;
  27. mutex_lock(&autosleep_lock);
  28. if (!pm_save_wakeup_count(initial_count)) {
  29. mutex_unlock(&autosleep_lock);
  30. goto out;
  31. }
  32. if (autosleep_state == PM_SUSPEND_ON) {
  33. mutex_unlock(&autosleep_lock);
  34. return;
  35. }
  36. if (autosleep_state >= PM_SUSPEND_MAX)
  37. hibernate();
  38. else
  39. pm_suspend(autosleep_state);
  40. mutex_unlock(&autosleep_lock);
  41. if (!pm_get_wakeup_count(&final_count, false))
  42. goto out;
  43. /*
  44. * If the wakeup occured for an unknown reason, wait to prevent the
  45. * system from trying to suspend and waking up in a tight loop.
  46. */
  47. if (final_count == initial_count)
  48. schedule_timeout_uninterruptible(HZ / 2);
  49. out:
  50. queue_up_suspend_work();
  51. }
  52. static DECLARE_WORK(suspend_work, try_to_suspend);
  53. void queue_up_suspend_work(void)
  54. {
  55. if (!work_pending(&suspend_work) && autosleep_state > PM_SUSPEND_ON)
  56. queue_work(autosleep_wq, &suspend_work);
  57. }
  58. suspend_state_t pm_autosleep_state(void)
  59. {
  60. return autosleep_state;
  61. }
  62. int pm_autosleep_lock(void)
  63. {
  64. return mutex_lock_interruptible(&autosleep_lock);
  65. }
  66. void pm_autosleep_unlock(void)
  67. {
  68. mutex_unlock(&autosleep_lock);
  69. }
  70. int pm_autosleep_set_state(suspend_state_t state)
  71. {
  72. #ifndef CONFIG_HIBERNATION
  73. if (state >= PM_SUSPEND_MAX)
  74. return -EINVAL;
  75. #endif
  76. __pm_stay_awake(autosleep_ws);
  77. mutex_lock(&autosleep_lock);
  78. autosleep_state = state;
  79. __pm_relax(autosleep_ws);
  80. if (state > PM_SUSPEND_ON) {
  81. pm_wakep_autosleep_enabled(true);
  82. queue_up_suspend_work();
  83. } else {
  84. pm_wakep_autosleep_enabled(false);
  85. }
  86. mutex_unlock(&autosleep_lock);
  87. return 0;
  88. }
  89. int __init pm_autosleep_init(void)
  90. {
  91. autosleep_ws = wakeup_source_register("autosleep");
  92. if (!autosleep_ws)
  93. return -ENOMEM;
  94. autosleep_wq = alloc_ordered_workqueue("autosleep", 0);
  95. if (autosleep_wq)
  96. return 0;
  97. wakeup_source_unregister(autosleep_ws);
  98. return -ENOMEM;
  99. }