aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/time_kern.c
diff options
context:
space:
mode:
authorGennady Sharapov <Gennady.V.Sharapov@intel.com>2006-01-18 20:42:42 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-18 22:20:19 -0500
commitcff65c4f0ea6662124bbb7bf3806e5df1c6d735d (patch)
tree5f19b3facdfa6a50ad1668b28d1ff74a92a90271 /arch/um/kernel/time_kern.c
parent4fef0c10fa174b57a10854b8b4b2b90d155706e0 (diff)
[PATCH] uml: move libc-dependent time code
The serial UML OS-abstraction layer patch (um/kernel dir). This moves all systemcalls from time.c file under os-Linux dir and joins time.c and tine_kernel.c files Signed-off-by: Gennady Sharapov <Gennady.V.Sharapov@intel.com> Signed-off-by: Jeff Dike <jdike@addtoit.com> Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/um/kernel/time_kern.c')
-rw-r--r--arch/um/kernel/time_kern.c124
1 files changed, 76 insertions, 48 deletions
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
index 020ca79b8d33..6712ffad0242 100644
--- a/arch/um/kernel/time_kern.c
+++ b/arch/um/kernel/time_kern.c
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) 2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
@@ -13,12 +13,12 @@
13#include "linux/interrupt.h" 13#include "linux/interrupt.h"
14#include "linux/init.h" 14#include "linux/init.h"
15#include "linux/delay.h" 15#include "linux/delay.h"
16#include "linux/hrtimer.h"
16#include "asm/irq.h" 17#include "asm/irq.h"
17#include "asm/param.h" 18#include "asm/param.h"
18#include "asm/current.h" 19#include "asm/current.h"
19#include "kern_util.h" 20#include "kern_util.h"
20#include "user_util.h" 21#include "user_util.h"
21#include "time_user.h"
22#include "mode.h" 22#include "mode.h"
23#include "os.h" 23#include "os.h"
24 24
@@ -39,7 +39,7 @@ unsigned long long sched_clock(void)
39int timer_irq_inited = 0; 39int timer_irq_inited = 0;
40 40
41static int first_tick; 41static int first_tick;
42static unsigned long long prev_usecs; 42static unsigned long long prev_nsecs;
43#ifdef CONFIG_UML_REAL_TIME_CLOCK 43#ifdef CONFIG_UML_REAL_TIME_CLOCK
44static long long delta; /* Deviation per interval */ 44static long long delta; /* Deviation per interval */
45#endif 45#endif
@@ -58,23 +58,23 @@ void timer_irq(union uml_pt_regs *regs)
58 if(first_tick){ 58 if(first_tick){
59#ifdef CONFIG_UML_REAL_TIME_CLOCK 59#ifdef CONFIG_UML_REAL_TIME_CLOCK
60 /* We've had 1 tick */ 60 /* We've had 1 tick */
61 unsigned long long usecs = os_usecs(); 61 unsigned long long nsecs = os_nsecs();
62 62
63 delta += usecs - prev_usecs; 63 delta += nsecs - prev_nsecs;
64 prev_usecs = usecs; 64 prev_nsecs = nsecs;
65 65
66 /* Protect against the host clock being set backwards */ 66 /* Protect against the host clock being set backwards */
67 if(delta < 0) 67 if(delta < 0)
68 delta = 0; 68 delta = 0;
69 69
70 ticks += (delta * HZ) / MILLION; 70 ticks += (delta * HZ) / BILLION;
71 delta -= (ticks * MILLION) / HZ; 71 delta -= (ticks * BILLION) / HZ;
72#else 72#else
73 ticks = 1; 73 ticks = 1;
74#endif 74#endif
75 } 75 }
76 else { 76 else {
77 prev_usecs = os_usecs(); 77 prev_nsecs = os_nsecs();
78 first_tick = 1; 78 first_tick = 1;
79 } 79 }
80 80
@@ -88,45 +88,99 @@ void boot_timer_handler(int sig)
88{ 88{
89 struct pt_regs regs; 89 struct pt_regs regs;
90 90
91 CHOOSE_MODE((void) 91 CHOOSE_MODE((void)
92 (UPT_SC(&regs.regs) = (struct sigcontext *) (&sig + 1)), 92 (UPT_SC(&regs.regs) = (struct sigcontext *) (&sig + 1)),
93 (void) (regs.regs.skas.is_user = 0)); 93 (void) (regs.regs.skas.is_user = 0));
94 do_timer(&regs); 94 do_timer(&regs);
95} 95}
96 96
97static DEFINE_SPINLOCK(timer_spinlock);
98
99static unsigned long long local_offset = 0;
100
101static inline unsigned long long get_time(void)
102{
103 unsigned long long nsecs;
104 unsigned long flags;
105
106 spin_lock_irqsave(&timer_spinlock, flags);
107 nsecs = os_nsecs();
108 nsecs += local_offset;
109 spin_unlock_irqrestore(&timer_spinlock, flags);
110
111 return nsecs;
112}
113
97irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) 114irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
98{ 115{
116 unsigned long long nsecs;
99 unsigned long flags; 117 unsigned long flags;
100 118
101 do_timer(regs); 119 do_timer(regs);
120
102 write_seqlock_irqsave(&xtime_lock, flags); 121 write_seqlock_irqsave(&xtime_lock, flags);
103 timer(); 122 nsecs = get_time() + local_offset;
123 xtime.tv_sec = nsecs / NSEC_PER_SEC;
124 xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC;
104 write_sequnlock_irqrestore(&xtime_lock, flags); 125 write_sequnlock_irqrestore(&xtime_lock, flags);
126
105 return(IRQ_HANDLED); 127 return(IRQ_HANDLED);
106} 128}
107 129
108long um_time(int __user *tloc) 130long um_time(int __user *tloc)
109{ 131{
110 struct timeval now; 132 long ret = get_time() / NSEC_PER_SEC;
111 133
112 do_gettimeofday(&now); 134 if((tloc != NULL) && put_user(ret, tloc))
113 if (tloc) { 135 return -EFAULT;
114 if (put_user(now.tv_sec, tloc)) 136
115 now.tv_sec = -EFAULT; 137 return ret;
116 } 138}
117 return now.tv_sec; 139
140void do_gettimeofday(struct timeval *tv)
141{
142 unsigned long long nsecs = get_time();
143
144 tv->tv_sec = nsecs / NSEC_PER_SEC;
145 /* Careful about calculations here - this was originally done as
146 * (nsecs - tv->tv_sec * NSEC_PER_SEC) / NSEC_PER_USEC
147 * which gave bogus (> 1000000) values. Dunno why, suspect gcc
148 * (4.0.0) miscompiled it, or there's a subtle 64/32-bit conversion
149 * problem that I missed.
150 */
151 nsecs -= tv->tv_sec * NSEC_PER_SEC;
152 tv->tv_usec = (unsigned long) nsecs / NSEC_PER_USEC;
153}
154
155static inline void set_time(unsigned long long nsecs)
156{
157 unsigned long long now;
158 unsigned long flags;
159
160 spin_lock_irqsave(&timer_spinlock, flags);
161 now = os_nsecs();
162 local_offset = nsecs - now;
163 spin_unlock_irqrestore(&timer_spinlock, flags);
164
165 clock_was_set();
118} 166}
119 167
120long um_stime(int __user *tptr) 168long um_stime(int __user *tptr)
121{ 169{
122 int value; 170 int value;
123 struct timespec new;
124 171
125 if (get_user(value, tptr)) 172 if (get_user(value, tptr))
126 return -EFAULT; 173 return -EFAULT;
127 new.tv_sec = value; 174
128 new.tv_nsec = 0; 175 set_time((unsigned long long) value * NSEC_PER_SEC);
129 do_settimeofday(&new); 176
177 return 0;
178}
179
180int do_settimeofday(struct timespec *tv)
181{
182 set_time((unsigned long long) tv->tv_sec * NSEC_PER_SEC + tv->tv_nsec);
183
130 return 0; 184 return 0;
131} 185}
132 186
@@ -142,21 +196,6 @@ void timer_handler(int sig, union uml_pt_regs *regs)
142 timer_irq(regs); 196 timer_irq(regs);
143} 197}
144 198
145static DEFINE_SPINLOCK(timer_spinlock);
146
147unsigned long time_lock(void)
148{
149 unsigned long flags;
150
151 spin_lock_irqsave(&timer_spinlock, flags);
152 return(flags);
153}
154
155void time_unlock(unsigned long flags)
156{
157 spin_unlock_irqrestore(&timer_spinlock, flags);
158}
159
160int __init timer_init(void) 199int __init timer_init(void)
161{ 200{
162 int err; 201 int err;
@@ -171,14 +210,3 @@ int __init timer_init(void)
171} 210}
172 211
173__initcall(timer_init); 212__initcall(timer_init);
174
175/*
176 * Overrides for Emacs so that we follow Linus's tabbing style.
177 * Emacs will notice this stuff at the end of the file and automatically
178 * adjust the settings for this buffer only. This must remain at the end
179 * of the file.
180 * ---------------------------------------------------------------------------
181 * Local variables:
182 * c-file-style: "linux"
183 * End:
184 */