diff options
Diffstat (limited to 'kernel/time/timekeeping.c')
-rw-r--r-- | kernel/time/timekeeping.c | 64 |
1 files changed, 53 insertions, 11 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index e424970bb562..cbc6acb0db3f 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -21,16 +21,11 @@ | |||
21 | #include <linux/time.h> | 21 | #include <linux/time.h> |
22 | #include <linux/tick.h> | 22 | #include <linux/tick.h> |
23 | #include <linux/stop_machine.h> | 23 | #include <linux/stop_machine.h> |
24 | #include <linux/pvclock_gtod.h> | ||
24 | 25 | ||
25 | 26 | ||
26 | static struct timekeeper timekeeper; | 27 | static struct timekeeper timekeeper; |
27 | 28 | ||
28 | /* | ||
29 | * This read-write spinlock protects us from races in SMP while | ||
30 | * playing with xtime. | ||
31 | */ | ||
32 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock); | ||
33 | |||
34 | /* flag for if timekeeping is suspended */ | 29 | /* flag for if timekeeping is suspended */ |
35 | int __read_mostly timekeeping_suspended; | 30 | int __read_mostly timekeeping_suspended; |
36 | 31 | ||
@@ -180,6 +175,54 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) | |||
180 | return nsec + arch_gettimeoffset(); | 175 | return nsec + arch_gettimeoffset(); |
181 | } | 176 | } |
182 | 177 | ||
178 | static RAW_NOTIFIER_HEAD(pvclock_gtod_chain); | ||
179 | |||
180 | static void update_pvclock_gtod(struct timekeeper *tk) | ||
181 | { | ||
182 | raw_notifier_call_chain(&pvclock_gtod_chain, 0, tk); | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * pvclock_gtod_register_notifier - register a pvclock timedata update listener | ||
187 | * | ||
188 | * Must hold write on timekeeper.lock | ||
189 | */ | ||
190 | int pvclock_gtod_register_notifier(struct notifier_block *nb) | ||
191 | { | ||
192 | struct timekeeper *tk = &timekeeper; | ||
193 | unsigned long flags; | ||
194 | int ret; | ||
195 | |||
196 | write_seqlock_irqsave(&tk->lock, flags); | ||
197 | ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb); | ||
198 | /* update timekeeping data */ | ||
199 | update_pvclock_gtod(tk); | ||
200 | write_sequnlock_irqrestore(&tk->lock, flags); | ||
201 | |||
202 | return ret; | ||
203 | } | ||
204 | EXPORT_SYMBOL_GPL(pvclock_gtod_register_notifier); | ||
205 | |||
206 | /** | ||
207 | * pvclock_gtod_unregister_notifier - unregister a pvclock | ||
208 | * timedata update listener | ||
209 | * | ||
210 | * Must hold write on timekeeper.lock | ||
211 | */ | ||
212 | int pvclock_gtod_unregister_notifier(struct notifier_block *nb) | ||
213 | { | ||
214 | struct timekeeper *tk = &timekeeper; | ||
215 | unsigned long flags; | ||
216 | int ret; | ||
217 | |||
218 | write_seqlock_irqsave(&tk->lock, flags); | ||
219 | ret = raw_notifier_chain_unregister(&pvclock_gtod_chain, nb); | ||
220 | write_sequnlock_irqrestore(&tk->lock, flags); | ||
221 | |||
222 | return ret; | ||
223 | } | ||
224 | EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); | ||
225 | |||
183 | /* must hold write on timekeeper.lock */ | 226 | /* must hold write on timekeeper.lock */ |
184 | static void timekeeping_update(struct timekeeper *tk, bool clearntp) | 227 | static void timekeeping_update(struct timekeeper *tk, bool clearntp) |
185 | { | 228 | { |
@@ -188,6 +231,7 @@ static void timekeeping_update(struct timekeeper *tk, bool clearntp) | |||
188 | ntp_clear(); | 231 | ntp_clear(); |
189 | } | 232 | } |
190 | update_vsyscall(tk); | 233 | update_vsyscall(tk); |
234 | update_pvclock_gtod(tk); | ||
191 | } | 235 | } |
192 | 236 | ||
193 | /** | 237 | /** |
@@ -1299,9 +1343,7 @@ struct timespec get_monotonic_coarse(void) | |||
1299 | } | 1343 | } |
1300 | 1344 | ||
1301 | /* | 1345 | /* |
1302 | * The 64-bit jiffies value is not atomic - you MUST NOT read it | 1346 | * Must hold jiffies_lock |
1303 | * without sampling the sequence number in xtime_lock. | ||
1304 | * jiffies is defined in the linker script... | ||
1305 | */ | 1347 | */ |
1306 | void do_timer(unsigned long ticks) | 1348 | void do_timer(unsigned long ticks) |
1307 | { | 1349 | { |
@@ -1389,7 +1431,7 @@ EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset); | |||
1389 | */ | 1431 | */ |
1390 | void xtime_update(unsigned long ticks) | 1432 | void xtime_update(unsigned long ticks) |
1391 | { | 1433 | { |
1392 | write_seqlock(&xtime_lock); | 1434 | write_seqlock(&jiffies_lock); |
1393 | do_timer(ticks); | 1435 | do_timer(ticks); |
1394 | write_sequnlock(&xtime_lock); | 1436 | write_sequnlock(&jiffies_lock); |
1395 | } | 1437 | } |