]> rtime.felk.cvut.cz Git - zynq/linux.git/blobdiff - kernel/time/ntp.c
rt,ntp: Move call to schedule_delayed_work() to helper thread
[zynq/linux.git] / kernel / time / ntp.c
index 0f60b08a4f073e9246ced1dc3b5de5f50efd7cf4..34bccda5fb56a1349e932f9c7f1f00d9365da69b 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/workqueue.h>
 #include <linux/hrtimer.h>
 #include <linux/jiffies.h>
+#include <linux/kthread.h>
 #include <linux/math64.h>
 #include <linux/timex.h>
 #include <linux/time.h>
@@ -519,10 +520,52 @@ static void sync_cmos_clock(struct work_struct *work)
                           &sync_cmos_work, timespec_to_jiffies(&next));
 }
 
+#ifdef CONFIG_PREEMPT_RT_FULL
+/*
+ * RT can not call schedule_delayed_work from real interrupt context.
+ * Need to make a thread to do the real work.
+ */
+static struct task_struct *cmos_delay_thread;
+static bool do_cmos_delay;
+
+static int run_cmos_delay(void *ignore)
+{
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (do_cmos_delay) {
+                       do_cmos_delay = false;
+                       queue_delayed_work(system_power_efficient_wq,
+                                          &sync_cmos_work, 0);
+               }
+               schedule();
+       }
+       __set_current_state(TASK_RUNNING);
+       return 0;
+}
+
+void ntp_notify_cmos_timer(void)
+{
+       do_cmos_delay = true;
+       /* Make visible before waking up process */
+       smp_wmb();
+       wake_up_process(cmos_delay_thread);
+}
+
+static __init int create_cmos_delay_thread(void)
+{
+       cmos_delay_thread = kthread_run(run_cmos_delay, NULL, "kcmosdelayd");
+       BUG_ON(!cmos_delay_thread);
+       return 0;
+}
+early_initcall(create_cmos_delay_thread);
+
+#else
+
 void ntp_notify_cmos_timer(void)
 {
        queue_delayed_work(system_power_efficient_wq, &sync_cmos_work, 0);
 }
+#endif /* CONFIG_PREEMPT_RT_FULL */
 
 #else
 void ntp_notify_cmos_timer(void) { }