|
@@ -21,6 +21,7 @@
|
|
|
#include <linux/time.h>
|
|
|
#include <linux/tick.h>
|
|
|
#include <linux/stop_machine.h>
|
|
|
+#include <linux/pvclock_gtod.h>
|
|
|
|
|
|
|
|
|
static struct timekeeper timekeeper;
|
|
@@ -180,6 +181,54 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
|
|
|
return nsec + arch_gettimeoffset();
|
|
|
}
|
|
|
|
|
|
+static RAW_NOTIFIER_HEAD(pvclock_gtod_chain);
|
|
|
+
|
|
|
+static void update_pvclock_gtod(struct timekeeper *tk)
|
|
|
+{
|
|
|
+ raw_notifier_call_chain(&pvclock_gtod_chain, 0, tk);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pvclock_gtod_register_notifier - register a pvclock timedata update listener
|
|
|
+ *
|
|
|
+ * Must hold write on timekeeper.lock
|
|
|
+ */
|
|
|
+int pvclock_gtod_register_notifier(struct notifier_block *nb)
|
|
|
+{
|
|
|
+ struct timekeeper *tk = &timekeeper;
|
|
|
+ unsigned long flags;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ write_seqlock_irqsave(&tk->lock, flags);
|
|
|
+ ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb);
|
|
|
+ /* update timekeeping data */
|
|
|
+ update_pvclock_gtod(tk);
|
|
|
+ write_sequnlock_irqrestore(&tk->lock, flags);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(pvclock_gtod_register_notifier);
|
|
|
+
|
|
|
+/**
|
|
|
+ * pvclock_gtod_unregister_notifier - unregister a pvclock
|
|
|
+ * timedata update listener
|
|
|
+ *
|
|
|
+ * Must hold write on timekeeper.lock
|
|
|
+ */
|
|
|
+int pvclock_gtod_unregister_notifier(struct notifier_block *nb)
|
|
|
+{
|
|
|
+ struct timekeeper *tk = &timekeeper;
|
|
|
+ unsigned long flags;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ write_seqlock_irqsave(&tk->lock, flags);
|
|
|
+ ret = raw_notifier_chain_unregister(&pvclock_gtod_chain, nb);
|
|
|
+ write_sequnlock_irqrestore(&tk->lock, flags);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier);
|
|
|
+
|
|
|
/* must hold write on timekeeper.lock */
|
|
|
static void timekeeping_update(struct timekeeper *tk, bool clearntp)
|
|
|
{
|
|
@@ -188,6 +237,7 @@ static void timekeeping_update(struct timekeeper *tk, bool clearntp)
|
|
|
ntp_clear();
|
|
|
}
|
|
|
update_vsyscall(tk);
|
|
|
+ update_pvclock_gtod(tk);
|
|
|
}
|
|
|
|
|
|
/**
|