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) |
