static LIST_HEAD(inactive_locks);
static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT];
static int current_event_num;
+#ifdef CONFIG_SUSPEND_SYNC_WORKQUEUE
+static int suspend_sys_sync_count;
+static DEFINE_SPINLOCK(suspend_sys_sync_lock);
+static struct workqueue_struct *suspend_sys_sync_work_queue;
+static DECLARE_COMPLETION(suspend_sys_sync_comp);
+#endif
struct workqueue_struct *suspend_work_queue;
struct wake_lock main_wake_lock;
suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
return ret;
}
+#ifdef CONFIG_SUSPEND_SYNC_WORKQUEUE
+static void suspend_sys_sync(struct work_struct *work)
+{
+ if (debug_mask & DEBUG_SUSPEND)
+ pr_info("PM: Syncing filesystems...\n");
+
+ sys_sync();
+
+ if (debug_mask & DEBUG_SUSPEND)
+ pr_info("sync done.\n");
+
+ spin_lock(&suspend_sys_sync_lock);
+ suspend_sys_sync_count--;
+ spin_unlock(&suspend_sys_sync_lock);
+}
+static DECLARE_WORK(suspend_sys_sync_work, suspend_sys_sync);
+
+void suspend_sys_sync_queue(void)
+{
+ int ret;
+
+ spin_lock(&suspend_sys_sync_lock);
+ ret = queue_work(suspend_sys_sync_work_queue, &suspend_sys_sync_work);
+ if (ret)
+ suspend_sys_sync_count++;
+ spin_unlock(&suspend_sys_sync_lock);
+}
+
+static bool suspend_sys_sync_abort;
+static void suspend_sys_sync_handler(unsigned long);
+static DEFINE_TIMER(suspend_sys_sync_timer, suspend_sys_sync_handler, 0, 0);
+/* value should be less then half of input event wake lock timeout value
+ * which is currently set to 5*HZ (see drivers/input/evdev.c)
+ */
+#define SUSPEND_SYS_SYNC_TIMEOUT (HZ/4)
+static void suspend_sys_sync_handler(unsigned long arg)
+{
+ if (suspend_sys_sync_count == 0) {
+ complete(&suspend_sys_sync_comp);
+ } else if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
+ suspend_sys_sync_abort = true;
+ complete(&suspend_sys_sync_comp);
+ } else {
+ mod_timer(&suspend_sys_sync_timer, jiffies +
+ SUSPEND_SYS_SYNC_TIMEOUT);
+ }
+}
+
+int suspend_sys_sync_wait(void)
+{
+ suspend_sys_sync_abort = false;
+
+ if (suspend_sys_sync_count != 0) {
+ mod_timer(&suspend_sys_sync_timer, jiffies +
+ SUSPEND_SYS_SYNC_TIMEOUT);
+ wait_for_completion(&suspend_sys_sync_comp);
+ }
+ if (suspend_sys_sync_abort) {
+ pr_info("suspend aborted....while waiting for sys_sync\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_SUSPEND_SYNC_WORKQUEUE */
+
static void suspend_backoff(void)
{
pr_info("suspend: too many immediate wakeups, back off\n");
}
entry_event_num = current_event_num;
+#ifdef CONFIG_SUSPEND_SYNC_WORKQUEUE
+ suspend_sys_sync_queue();
+#else
sys_sync();
+#endif
if (debug_mask & DEBUG_SUSPEND)
pr_info("suspend: enter suspend\n");
getnstimeofday(&ts_entry);
goto err_platform_driver_register;
}
+#ifdef CONFIG_SUSPEND_SYNC_WORKQUEUE
+ INIT_COMPLETION(suspend_sys_sync_comp);
+ suspend_sys_sync_work_queue =
+ create_singlethread_workqueue("suspend_sys_sync");
+ if (suspend_sys_sync_work_queue == NULL) {
+ ret = -ENOMEM;
+ goto err_suspend_sys_sync_work_queue;
+ }
+#endif
+
suspend_work_queue = create_singlethread_workqueue("suspend");
if (suspend_work_queue == NULL) {
ret = -ENOMEM;
return 0;
err_suspend_work_queue:
+#ifdef CONFIG_SUSPEND_SYNC_WORKQUEUE
+ destroy_workqueue(suspend_sys_sync_work_queue);
+err_suspend_sys_sync_work_queue:
+#endif
platform_driver_unregister(&power_driver);
err_platform_driver_register:
platform_device_unregister(&power_device);
remove_proc_entry("wakelocks", NULL);
#endif
destroy_workqueue(suspend_work_queue);
+#ifdef CONFIG_SUSPEND_SYNC_WORKQUEUE
+ destroy_workqueue(suspend_sys_sync_work_queue);
+#endif
platform_driver_unregister(&power_driver);
platform_device_unregister(&power_device);
wake_lock_destroy(&suspend_backoff_lock);