diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-08-14 09:47:31 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2009-08-15 04:55:46 -0400 |
commit | d4f587c67fc39e0030ddd718675e252e208da4d7 (patch) | |
tree | 2222681c57966cc6b8404afdff3ab1a09ac7ea69 | |
parent | 75c5158f70c065b9704b924503d96e8297838f79 (diff) |
timekeeping: Increase granularity of read_persistent_clock()
The persistent clock of some architectures (e.g. s390) have a
better granularity than seconds. To reduce the delta between the
host clock and the guest clock in a virtualized system change the
read_persistent_clock function to return a struct timespec.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Ingo Molnar <mingo@elte.hu>
Acked-by: John Stultz <johnstul@us.ibm.com>
Cc: Daniel Walker <dwalker@fifo99.com>
LKML-Reference: <20090814134811.013873340@de.ibm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | arch/m68knommu/kernel/time.c | 5 | ||||
-rw-r--r-- | arch/mips/dec/time.c | 5 | ||||
-rw-r--r-- | arch/mips/lasat/ds1603.c | 5 | ||||
-rw-r--r-- | arch/mips/lasat/sysctl.c | 8 | ||||
-rw-r--r-- | arch/mips/lemote/lm2e/setup.c | 5 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-time.c | 5 | ||||
-rw-r--r-- | arch/mips/pmc-sierra/yosemite/setup.c | 5 | ||||
-rw-r--r-- | arch/mips/sibyte/swarm/setup.c | 15 | ||||
-rw-r--r-- | arch/mips/sni/time.c | 5 | ||||
-rw-r--r-- | arch/powerpc/kernel/time.c | 7 | ||||
-rw-r--r-- | arch/s390/kernel/time.c | 22 | ||||
-rw-r--r-- | arch/sh/kernel/time.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/rtc.c | 5 | ||||
-rw-r--r-- | arch/xtensa/kernel/time.c | 5 | ||||
-rw-r--r-- | include/linux/time.h | 2 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 52 |
16 files changed, 83 insertions, 74 deletions
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c index d182b2f72211..68432248515c 100644 --- a/arch/m68knommu/kernel/time.c +++ b/arch/m68knommu/kernel/time.c | |||
@@ -72,9 +72,10 @@ static unsigned long read_rtc_mmss(void) | |||
72 | return mktime(year, mon, day, hour, min, sec);; | 72 | return mktime(year, mon, day, hour, min, sec);; |
73 | } | 73 | } |
74 | 74 | ||
75 | unsigned long read_persistent_clock(void) | 75 | void read_persistent_clock(struct timespec *ts) |
76 | { | 76 | { |
77 | return read_rtc_mmss(); | 77 | ts->tv_sec = read_rtc_mmss(); |
78 | ts->tv_nsec = 0; | ||
78 | } | 79 | } |
79 | 80 | ||
80 | int update_persistent_clock(struct timespec now) | 81 | int update_persistent_clock(struct timespec now) |
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index 463136e6685a..02f505f23c32 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <asm/dec/ioasic.h> | 18 | #include <asm/dec/ioasic.h> |
19 | #include <asm/dec/machtype.h> | 19 | #include <asm/dec/machtype.h> |
20 | 20 | ||
21 | unsigned long read_persistent_clock(void) | 21 | void read_persistent_clock(struct timespec *ts) |
22 | { | 22 | { |
23 | unsigned int year, mon, day, hour, min, sec, real_year; | 23 | unsigned int year, mon, day, hour, min, sec, real_year; |
24 | unsigned long flags; | 24 | unsigned long flags; |
@@ -53,7 +53,8 @@ unsigned long read_persistent_clock(void) | |||
53 | 53 | ||
54 | year += real_year - 72 + 2000; | 54 | year += real_year - 72 + 2000; |
55 | 55 | ||
56 | return mktime(year, mon, day, hour, min, sec); | 56 | ts->tv_sec = mktime(year, mon, day, hour, min, sec); |
57 | ts->tv_nsec = 0; | ||
57 | } | 58 | } |
58 | 59 | ||
59 | /* | 60 | /* |
diff --git a/arch/mips/lasat/ds1603.c b/arch/mips/lasat/ds1603.c index 52cb1436a12a..c6fd96ff118d 100644 --- a/arch/mips/lasat/ds1603.c +++ b/arch/mips/lasat/ds1603.c | |||
@@ -135,7 +135,7 @@ static void rtc_end_op(void) | |||
135 | lasat_ndelay(1000); | 135 | lasat_ndelay(1000); |
136 | } | 136 | } |
137 | 137 | ||
138 | unsigned long read_persistent_clock(void) | 138 | void read_persistent_clock(struct timespec *ts) |
139 | { | 139 | { |
140 | unsigned long word; | 140 | unsigned long word; |
141 | unsigned long flags; | 141 | unsigned long flags; |
@@ -147,7 +147,8 @@ unsigned long read_persistent_clock(void) | |||
147 | rtc_end_op(); | 147 | rtc_end_op(); |
148 | spin_unlock_irqrestore(&rtc_lock, flags); | 148 | spin_unlock_irqrestore(&rtc_lock, flags); |
149 | 149 | ||
150 | return word; | 150 | ts->tv_sec = word; |
151 | ts->tv_nsec = 0; | ||
151 | } | 152 | } |
152 | 153 | ||
153 | int rtc_mips_set_mmss(unsigned long time) | 154 | int rtc_mips_set_mmss(unsigned long time) |
diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c index 8f88886feb12..3f04d4c406b7 100644 --- a/arch/mips/lasat/sysctl.c +++ b/arch/mips/lasat/sysctl.c | |||
@@ -92,10 +92,12 @@ static int rtctmp; | |||
92 | int proc_dolasatrtc(ctl_table *table, int write, struct file *filp, | 92 | int proc_dolasatrtc(ctl_table *table, int write, struct file *filp, |
93 | void *buffer, size_t *lenp, loff_t *ppos) | 93 | void *buffer, size_t *lenp, loff_t *ppos) |
94 | { | 94 | { |
95 | struct timespec ts; | ||
95 | int r; | 96 | int r; |
96 | 97 | ||
97 | if (!write) { | 98 | if (!write) { |
98 | rtctmp = read_persistent_clock(); | 99 | read_persistent_clock(&ts); |
100 | rtctmp = ts.tv_sec; | ||
99 | /* check for time < 0 and set to 0 */ | 101 | /* check for time < 0 and set to 0 */ |
100 | if (rtctmp < 0) | 102 | if (rtctmp < 0) |
101 | rtctmp = 0; | 103 | rtctmp = 0; |
@@ -134,9 +136,11 @@ int sysctl_lasat_rtc(ctl_table *table, | |||
134 | void *oldval, size_t *oldlenp, | 136 | void *oldval, size_t *oldlenp, |
135 | void *newval, size_t newlen) | 137 | void *newval, size_t newlen) |
136 | { | 138 | { |
139 | struct timespec ts; | ||
137 | int r; | 140 | int r; |
138 | 141 | ||
139 | rtctmp = read_persistent_clock(); | 142 | read_persistent_clock(&ts); |
143 | rtctmp = ts.tv_sec; | ||
140 | if (rtctmp < 0) | 144 | if (rtctmp < 0) |
141 | rtctmp = 0; | 145 | rtctmp = 0; |
142 | r = sysctl_intvec(table, oldval, oldlenp, newval, newlen); | 146 | r = sysctl_intvec(table, oldval, oldlenp, newval, newlen); |
diff --git a/arch/mips/lemote/lm2e/setup.c b/arch/mips/lemote/lm2e/setup.c index ebd6ceaef2fd..24b355df6127 100644 --- a/arch/mips/lemote/lm2e/setup.c +++ b/arch/mips/lemote/lm2e/setup.c | |||
@@ -54,9 +54,10 @@ void __init plat_time_init(void) | |||
54 | mips_hpt_frequency = cpu_clock_freq / 2; | 54 | mips_hpt_frequency = cpu_clock_freq / 2; |
55 | } | 55 | } |
56 | 56 | ||
57 | unsigned long read_persistent_clock(void) | 57 | void read_persistent_clock(struct timespec *ts) |
58 | { | 58 | { |
59 | return mc146818_get_cmos_time(); | 59 | ts->tv_sec = mc146818_get_cmos_time(); |
60 | ts->tv_nsec = 0; | ||
60 | } | 61 | } |
61 | 62 | ||
62 | void (*__wbflush)(void); | 63 | void (*__wbflush)(void); |
diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index 0b97d47691fc..3c6f190aa61c 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c | |||
@@ -100,9 +100,10 @@ static unsigned int __init estimate_cpu_frequency(void) | |||
100 | return count; | 100 | return count; |
101 | } | 101 | } |
102 | 102 | ||
103 | unsigned long read_persistent_clock(void) | 103 | void read_persistent_clock(struct timespec *ts) |
104 | { | 104 | { |
105 | return mc146818_get_cmos_time(); | 105 | ts->tv_sec = mc146818_get_cmos_time(); |
106 | ts->tv_nsec = 0; | ||
106 | } | 107 | } |
107 | 108 | ||
108 | static void __init plat_perf_setup(void) | 109 | static void __init plat_perf_setup(void) |
diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c index 2d3c0dca275d..3498ac9c35af 100644 --- a/arch/mips/pmc-sierra/yosemite/setup.c +++ b/arch/mips/pmc-sierra/yosemite/setup.c | |||
@@ -70,7 +70,7 @@ void __init bus_error_init(void) | |||
70 | } | 70 | } |
71 | 71 | ||
72 | 72 | ||
73 | unsigned long read_persistent_clock(void) | 73 | void read_persistent_clock(struct timespec *ts) |
74 | { | 74 | { |
75 | unsigned int year, month, day, hour, min, sec; | 75 | unsigned int year, month, day, hour, min, sec; |
76 | unsigned long flags; | 76 | unsigned long flags; |
@@ -92,7 +92,8 @@ unsigned long read_persistent_clock(void) | |||
92 | m48t37_base->control = 0x00; | 92 | m48t37_base->control = 0x00; |
93 | spin_unlock_irqrestore(&rtc_lock, flags); | 93 | spin_unlock_irqrestore(&rtc_lock, flags); |
94 | 94 | ||
95 | return mktime(year, month, day, hour, min, sec); | 95 | ts->tv_sec = mktime(year, month, day, hour, min, sec); |
96 | ts->tv_nsec = 0; | ||
96 | } | 97 | } |
97 | 98 | ||
98 | int rtc_mips_set_time(unsigned long tim) | 99 | int rtc_mips_set_time(unsigned long tim) |
diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c index 672e45d495a9..623ffc933c4c 100644 --- a/arch/mips/sibyte/swarm/setup.c +++ b/arch/mips/sibyte/swarm/setup.c | |||
@@ -87,19 +87,26 @@ enum swarm_rtc_type { | |||
87 | 87 | ||
88 | enum swarm_rtc_type swarm_rtc_type; | 88 | enum swarm_rtc_type swarm_rtc_type; |
89 | 89 | ||
90 | unsigned long read_persistent_clock(void) | 90 | void read_persistent_clock(struct timespec *ts) |
91 | { | 91 | { |
92 | unsigned long sec; | ||
93 | |||
92 | switch (swarm_rtc_type) { | 94 | switch (swarm_rtc_type) { |
93 | case RTC_XICOR: | 95 | case RTC_XICOR: |
94 | return xicor_get_time(); | 96 | sec = xicor_get_time(); |
97 | break; | ||
95 | 98 | ||
96 | case RTC_M4LT81: | 99 | case RTC_M4LT81: |
97 | return m41t81_get_time(); | 100 | sec = m41t81_get_time(); |
101 | break; | ||
98 | 102 | ||
99 | case RTC_NONE: | 103 | case RTC_NONE: |
100 | default: | 104 | default: |
101 | return mktime(2000, 1, 1, 0, 0, 0); | 105 | sec = mktime(2000, 1, 1, 0, 0, 0); |
106 | break; | ||
102 | } | 107 | } |
108 | ts->tv_sec = sec; | ||
109 | tv->tv_nsec = 0; | ||
103 | } | 110 | } |
104 | 111 | ||
105 | int rtc_mips_set_time(unsigned long sec) | 112 | int rtc_mips_set_time(unsigned long sec) |
diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c index 0d9ec1a5c24a..62df6a598e0a 100644 --- a/arch/mips/sni/time.c +++ b/arch/mips/sni/time.c | |||
@@ -182,7 +182,8 @@ void __init plat_time_init(void) | |||
182 | setup_pit_timer(); | 182 | setup_pit_timer(); |
183 | } | 183 | } |
184 | 184 | ||
185 | unsigned long read_persistent_clock(void) | 185 | void read_persistent_clock(struct timespec *ts) |
186 | { | 186 | { |
187 | return -1; | 187 | ts->tv_sec = -1; |
188 | ts->tv_nsec = 0; | ||
188 | } | 189 | } |
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index eae4511ceeac..ad63f30fe3da 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -769,7 +769,7 @@ int update_persistent_clock(struct timespec now) | |||
769 | return ppc_md.set_rtc_time(&tm); | 769 | return ppc_md.set_rtc_time(&tm); |
770 | } | 770 | } |
771 | 771 | ||
772 | unsigned long read_persistent_clock(void) | 772 | void read_persistent_clock(struct timespec *ts) |
773 | { | 773 | { |
774 | struct rtc_time tm; | 774 | struct rtc_time tm; |
775 | static int first = 1; | 775 | static int first = 1; |
@@ -787,8 +787,9 @@ unsigned long read_persistent_clock(void) | |||
787 | if (!ppc_md.get_rtc_time) | 787 | if (!ppc_md.get_rtc_time) |
788 | return 0; | 788 | return 0; |
789 | ppc_md.get_rtc_time(&tm); | 789 | ppc_md.get_rtc_time(&tm); |
790 | return mktime(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, | 790 | ts->tv_sec = mktime(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, |
791 | tm.tm_hour, tm.tm_min, tm.tm_sec); | 791 | tm.tm_hour, tm.tm_min, tm.tm_sec); |
792 | ts->tv_nsec = 0; | ||
792 | } | 793 | } |
793 | 794 | ||
794 | /* clocksource code */ | 795 | /* clocksource code */ |
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index e76c2e7a8b9a..a94ec48587b4 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -182,12 +182,9 @@ static void timing_alert_interrupt(__u16 code) | |||
182 | static void etr_reset(void); | 182 | static void etr_reset(void); |
183 | static void stp_reset(void); | 183 | static void stp_reset(void); |
184 | 184 | ||
185 | unsigned long read_persistent_clock(void) | 185 | void read_persistent_clock(struct timespec *ts) |
186 | { | 186 | { |
187 | struct timespec ts; | 187 | tod_to_timeval(get_clock() - TOD_UNIX_EPOCH, ts); |
188 | |||
189 | tod_to_timeval(get_clock() - TOD_UNIX_EPOCH, &ts); | ||
190 | return ts.tv_sec; | ||
191 | } | 188 | } |
192 | 189 | ||
193 | static cycle_t read_tod_clock(struct clocksource *cs) | 190 | static cycle_t read_tod_clock(struct clocksource *cs) |
@@ -248,7 +245,6 @@ void __init time_init(void) | |||
248 | { | 245 | { |
249 | struct timespec ts; | 246 | struct timespec ts; |
250 | unsigned long flags; | 247 | unsigned long flags; |
251 | cycle_t now; | ||
252 | 248 | ||
253 | /* Reset time synchronization interfaces. */ | 249 | /* Reset time synchronization interfaces. */ |
254 | etr_reset(); | 250 | etr_reset(); |
@@ -266,20 +262,10 @@ void __init time_init(void) | |||
266 | panic("Could not register TOD clock source"); | 262 | panic("Could not register TOD clock source"); |
267 | 263 | ||
268 | /* | 264 | /* |
269 | * The TOD clock is an accurate clock. The xtime should be | 265 | * Reset wall_to_monotonic to the initial timestamp created |
270 | * initialized in a way that the difference between TOD and | 266 | * in head.S to get a precise value in /proc/uptime. |
271 | * xtime is reasonably small. Too bad that timekeeping_init | ||
272 | * sets xtime.tv_nsec to zero. In addition the clock source | ||
273 | * change from the jiffies clock source to the TOD clock | ||
274 | * source add another error of up to 1/HZ second. The same | ||
275 | * function sets wall_to_monotonic to a value that is too | ||
276 | * small for /proc/uptime to be accurate. | ||
277 | * Reset xtime and wall_to_monotonic to sane values. | ||
278 | */ | 267 | */ |
279 | write_seqlock_irqsave(&xtime_lock, flags); | 268 | write_seqlock_irqsave(&xtime_lock, flags); |
280 | now = get_clock(); | ||
281 | tod_to_timeval(now - TOD_UNIX_EPOCH, &xtime); | ||
282 | clocksource_tod.cycle_last = now; | ||
283 | tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, &ts); | 269 | tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, &ts); |
284 | set_normalized_timespec(&wall_to_monotonic, -ts.tv_sec, -ts.tv_nsec); | 270 | set_normalized_timespec(&wall_to_monotonic, -ts.tv_sec, -ts.tv_nsec); |
285 | write_sequnlock_irqrestore(&xtime_lock, flags); | 271 | write_sequnlock_irqrestore(&xtime_lock, flags); |
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 9b352a1e3fb4..3f4706aa975e 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c | |||
@@ -39,11 +39,9 @@ void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time; | |||
39 | int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time; | 39 | int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time; |
40 | 40 | ||
41 | #ifdef CONFIG_GENERIC_CMOS_UPDATE | 41 | #ifdef CONFIG_GENERIC_CMOS_UPDATE |
42 | unsigned long read_persistent_clock(void) | 42 | void read_persistent_clock(struct timespec *ts) |
43 | { | 43 | { |
44 | struct timespec tv; | 44 | rtc_sh_get_time(&ts); |
45 | rtc_sh_get_time(&tv); | ||
46 | return tv.tv_sec; | ||
47 | } | 45 | } |
48 | 46 | ||
49 | int update_persistent_clock(struct timespec now) | 47 | int update_persistent_clock(struct timespec now) |
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 5d465b207e72..bf67dcb4a44c 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c | |||
@@ -178,7 +178,7 @@ static int set_rtc_mmss(unsigned long nowtime) | |||
178 | } | 178 | } |
179 | 179 | ||
180 | /* not static: needed by APM */ | 180 | /* not static: needed by APM */ |
181 | unsigned long read_persistent_clock(void) | 181 | void read_persistent_clock(struct timespec *ts) |
182 | { | 182 | { |
183 | unsigned long retval, flags; | 183 | unsigned long retval, flags; |
184 | 184 | ||
@@ -186,7 +186,8 @@ unsigned long read_persistent_clock(void) | |||
186 | retval = get_wallclock(); | 186 | retval = get_wallclock(); |
187 | spin_unlock_irqrestore(&rtc_lock, flags); | 187 | spin_unlock_irqrestore(&rtc_lock, flags); |
188 | 188 | ||
189 | return retval; | 189 | ts->tv_sec = retval; |
190 | ts->tv_nsec = 0; | ||
190 | } | 191 | } |
191 | 192 | ||
192 | int update_persistent_clock(struct timespec now) | 193 | int update_persistent_clock(struct timespec now) |
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c index 8848120d291b..19085ff0484a 100644 --- a/arch/xtensa/kernel/time.c +++ b/arch/xtensa/kernel/time.c | |||
@@ -59,9 +59,8 @@ static struct irqaction timer_irqaction = { | |||
59 | 59 | ||
60 | void __init time_init(void) | 60 | void __init time_init(void) |
61 | { | 61 | { |
62 | xtime.tv_nsec = 0; | 62 | /* FIXME: xtime&wall_to_monotonic are set in timekeeping_init. */ |
63 | xtime.tv_sec = read_persistent_clock(); | 63 | read_persistent_clock(&xtime); |
64 | |||
65 | set_normalized_timespec(&wall_to_monotonic, | 64 | set_normalized_timespec(&wall_to_monotonic, |
66 | -xtime.tv_sec, -xtime.tv_nsec); | 65 | -xtime.tv_sec, -xtime.tv_nsec); |
67 | 66 | ||
diff --git a/include/linux/time.h b/include/linux/time.h index e7c844558884..53a3216f0d1b 100644 --- a/include/linux/time.h +++ b/include/linux/time.h | |||
@@ -101,7 +101,7 @@ extern struct timespec xtime; | |||
101 | extern struct timespec wall_to_monotonic; | 101 | extern struct timespec wall_to_monotonic; |
102 | extern seqlock_t xtime_lock; | 102 | extern seqlock_t xtime_lock; |
103 | 103 | ||
104 | extern unsigned long read_persistent_clock(void); | 104 | extern void read_persistent_clock(struct timespec *ts); |
105 | extern int update_persistent_clock(struct timespec now); | 105 | extern int update_persistent_clock(struct timespec now); |
106 | extern int no_sync_cmos_clock __read_mostly; | 106 | extern int no_sync_cmos_clock __read_mostly; |
107 | void timekeeping_init(void); | 107 | void timekeeping_init(void); |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 41579e7fcf9d..f1a21ce491e6 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -154,7 +154,7 @@ __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock); | |||
154 | */ | 154 | */ |
155 | struct timespec xtime __attribute__ ((aligned (16))); | 155 | struct timespec xtime __attribute__ ((aligned (16))); |
156 | struct timespec wall_to_monotonic __attribute__ ((aligned (16))); | 156 | struct timespec wall_to_monotonic __attribute__ ((aligned (16))); |
157 | static unsigned long total_sleep_time; /* seconds */ | 157 | static struct timespec total_sleep_time; |
158 | 158 | ||
159 | /* | 159 | /* |
160 | * The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. | 160 | * The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. |
@@ -487,17 +487,18 @@ int timekeeping_valid_for_hres(void) | |||
487 | } | 487 | } |
488 | 488 | ||
489 | /** | 489 | /** |
490 | * read_persistent_clock - Return time in seconds from the persistent clock. | 490 | * read_persistent_clock - Return time from the persistent clock. |
491 | * | 491 | * |
492 | * Weak dummy function for arches that do not yet support it. | 492 | * Weak dummy function for arches that do not yet support it. |
493 | * Returns seconds from epoch using the battery backed persistent clock. | 493 | * Reads the time from the battery backed persistent clock. |
494 | * Returns zero if unsupported. | 494 | * Returns a timespec with tv_sec=0 and tv_nsec=0 if unsupported. |
495 | * | 495 | * |
496 | * XXX - Do be sure to remove it once all arches implement it. | 496 | * XXX - Do be sure to remove it once all arches implement it. |
497 | */ | 497 | */ |
498 | unsigned long __attribute__((weak)) read_persistent_clock(void) | 498 | void __attribute__((weak)) read_persistent_clock(struct timespec *ts) |
499 | { | 499 | { |
500 | return 0; | 500 | ts->tv_sec = 0; |
501 | ts->tv_nsec = 0; | ||
501 | } | 502 | } |
502 | 503 | ||
503 | /* | 504 | /* |
@@ -507,7 +508,9 @@ void __init timekeeping_init(void) | |||
507 | { | 508 | { |
508 | struct clocksource *clock; | 509 | struct clocksource *clock; |
509 | unsigned long flags; | 510 | unsigned long flags; |
510 | unsigned long sec = read_persistent_clock(); | 511 | struct timespec now; |
512 | |||
513 | read_persistent_clock(&now); | ||
511 | 514 | ||
512 | write_seqlock_irqsave(&xtime_lock, flags); | 515 | write_seqlock_irqsave(&xtime_lock, flags); |
513 | 516 | ||
@@ -518,19 +521,20 @@ void __init timekeeping_init(void) | |||
518 | clock->enable(clock); | 521 | clock->enable(clock); |
519 | timekeeper_setup_internals(clock); | 522 | timekeeper_setup_internals(clock); |
520 | 523 | ||
521 | xtime.tv_sec = sec; | 524 | xtime.tv_sec = now.tv_sec; |
522 | xtime.tv_nsec = 0; | 525 | xtime.tv_nsec = now.tv_nsec; |
523 | raw_time.tv_sec = 0; | 526 | raw_time.tv_sec = 0; |
524 | raw_time.tv_nsec = 0; | 527 | raw_time.tv_nsec = 0; |
525 | set_normalized_timespec(&wall_to_monotonic, | 528 | set_normalized_timespec(&wall_to_monotonic, |
526 | -xtime.tv_sec, -xtime.tv_nsec); | 529 | -xtime.tv_sec, -xtime.tv_nsec); |
527 | update_xtime_cache(0); | 530 | update_xtime_cache(0); |
528 | total_sleep_time = 0; | 531 | total_sleep_time.tv_sec = 0; |
532 | total_sleep_time.tv_nsec = 0; | ||
529 | write_sequnlock_irqrestore(&xtime_lock, flags); | 533 | write_sequnlock_irqrestore(&xtime_lock, flags); |
530 | } | 534 | } |
531 | 535 | ||
532 | /* time in seconds when suspend began */ | 536 | /* time in seconds when suspend began */ |
533 | static unsigned long timekeeping_suspend_time; | 537 | static struct timespec timekeeping_suspend_time; |
534 | 538 | ||
535 | /** | 539 | /** |
536 | * timekeeping_resume - Resumes the generic timekeeping subsystem. | 540 | * timekeeping_resume - Resumes the generic timekeeping subsystem. |
@@ -543,18 +547,19 @@ static unsigned long timekeeping_suspend_time; | |||
543 | static int timekeeping_resume(struct sys_device *dev) | 547 | static int timekeeping_resume(struct sys_device *dev) |
544 | { | 548 | { |
545 | unsigned long flags; | 549 | unsigned long flags; |
546 | unsigned long now = read_persistent_clock(); | 550 | struct timespec ts; |
551 | |||
552 | read_persistent_clock(&ts); | ||
547 | 553 | ||
548 | clocksource_resume(); | 554 | clocksource_resume(); |
549 | 555 | ||
550 | write_seqlock_irqsave(&xtime_lock, flags); | 556 | write_seqlock_irqsave(&xtime_lock, flags); |
551 | 557 | ||
552 | if (now && (now > timekeeping_suspend_time)) { | 558 | if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) { |
553 | unsigned long sleep_length = now - timekeeping_suspend_time; | 559 | ts = timespec_sub(ts, timekeeping_suspend_time); |
554 | 560 | xtime = timespec_add_safe(xtime, ts); | |
555 | xtime.tv_sec += sleep_length; | 561 | wall_to_monotonic = timespec_sub(wall_to_monotonic, ts); |
556 | wall_to_monotonic.tv_sec -= sleep_length; | 562 | total_sleep_time = timespec_add_safe(total_sleep_time, ts); |
557 | total_sleep_time += sleep_length; | ||
558 | } | 563 | } |
559 | update_xtime_cache(0); | 564 | update_xtime_cache(0); |
560 | /* re-base the last cycle value */ | 565 | /* re-base the last cycle value */ |
@@ -577,7 +582,7 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) | |||
577 | { | 582 | { |
578 | unsigned long flags; | 583 | unsigned long flags; |
579 | 584 | ||
580 | timekeeping_suspend_time = read_persistent_clock(); | 585 | read_persistent_clock(&timekeeping_suspend_time); |
581 | 586 | ||
582 | write_seqlock_irqsave(&xtime_lock, flags); | 587 | write_seqlock_irqsave(&xtime_lock, flags); |
583 | timekeeping_forward_now(); | 588 | timekeeping_forward_now(); |
@@ -801,9 +806,10 @@ void update_wall_time(void) | |||
801 | */ | 806 | */ |
802 | void getboottime(struct timespec *ts) | 807 | void getboottime(struct timespec *ts) |
803 | { | 808 | { |
804 | set_normalized_timespec(ts, | 809 | struct timespec boottime; |
805 | - (wall_to_monotonic.tv_sec + total_sleep_time), | 810 | |
806 | - wall_to_monotonic.tv_nsec); | 811 | boottime = timespec_add_safe(wall_to_monotonic, total_sleep_time); |
812 | set_normalized_timespec(ts, -boottime.tv_sec, -boottime.tv_nsec); | ||
807 | } | 813 | } |
808 | 814 | ||
809 | /** | 815 | /** |
@@ -812,7 +818,7 @@ void getboottime(struct timespec *ts) | |||
812 | */ | 818 | */ |
813 | void monotonic_to_bootbased(struct timespec *ts) | 819 | void monotonic_to_bootbased(struct timespec *ts) |
814 | { | 820 | { |
815 | ts->tv_sec += total_sleep_time; | 821 | *ts = timespec_add_safe(*ts, total_sleep_time); |
816 | } | 822 | } |
817 | 823 | ||
818 | unsigned long get_seconds(void) | 824 | unsigned long get_seconds(void) |