blob: 6516fc52afe01f23ecfbe0365cb251e9d3c8635d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "linux/module.h"
8#include "linux/unistd.h"
9#include "linux/stddef.h"
10#include "linux/spinlock.h"
11#include "linux/time.h"
12#include "linux/sched.h"
13#include "linux/interrupt.h"
14#include "linux/init.h"
15#include "linux/delay.h"
16#include "asm/irq.h"
17#include "asm/param.h"
18#include "asm/current.h"
19#include "kern_util.h"
20#include "user_util.h"
21#include "time_user.h"
22#include "mode.h"
23#include "os.h"
24
25u64 jiffies_64 = INITIAL_JIFFIES;
26
27EXPORT_SYMBOL(jiffies_64);
28
29int hz(void)
30{
31 return(HZ);
32}
33
34/*
35 * Scheduler clock - returns current time in nanosec units.
36 */
37unsigned long long sched_clock(void)
38{
39 return (unsigned long long)jiffies_64 * (1000000000 / HZ);
40}
41
42/* Changed at early boot */
43int timer_irq_inited = 0;
44
45static int first_tick;
46static unsigned long long prev_usecs;
47#ifdef CONFIG_UML_REAL_TIME_CLOCK
48static long long delta; /* Deviation per interval */
49#endif
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051void timer_irq(union uml_pt_regs *regs)
52{
53 unsigned long long ticks = 0;
54
55 if(!timer_irq_inited){
56 /* This is to ensure that ticks don't pile up when
57 * the timer handler is suspended */
58 first_tick = 0;
59 return;
60 }
61
62 if(first_tick){
63#ifdef CONFIG_UML_REAL_TIME_CLOCK
64 /* We've had 1 tick */
65 unsigned long long usecs = os_usecs();
66
67 delta += usecs - prev_usecs;
68 prev_usecs = usecs;
69
70 /* Protect against the host clock being set backwards */
71 if(delta < 0)
72 delta = 0;
73
74 ticks += (delta * HZ) / MILLION;
75 delta -= (ticks * MILLION) / HZ;
76#else
77 ticks = 1;
78#endif
79 }
80 else {
81 prev_usecs = os_usecs();
82 first_tick = 1;
83 }
84
85 while(ticks > 0){
86 do_IRQ(TIMER_IRQ, regs);
87 ticks--;
88 }
89}
90
91void boot_timer_handler(int sig)
92{
93 struct pt_regs regs;
94
95 CHOOSE_MODE((void)
96 (UPT_SC(&regs.regs) = (struct sigcontext *) (&sig + 1)),
97 (void) (regs.regs.skas.is_user = 0));
98 do_timer(&regs);
99}
100
101irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
102{
103 unsigned long flags;
104
105 do_timer(regs);
106 write_seqlock_irqsave(&xtime_lock, flags);
107 timer();
108 write_sequnlock_irqrestore(&xtime_lock, flags);
109 return(IRQ_HANDLED);
110}
111
112long um_time(int __user *tloc)
113{
114 struct timeval now;
115
116 do_gettimeofday(&now);
117 if (tloc) {
118 if (put_user(now.tv_sec, tloc))
119 now.tv_sec = -EFAULT;
120 }
121 return now.tv_sec;
122}
123
124long um_stime(int __user *tptr)
125{
126 int value;
127 struct timespec new;
128
129 if (get_user(value, tptr))
130 return -EFAULT;
131 new.tv_sec = value;
132 new.tv_nsec = 0;
133 do_settimeofday(&new);
134 return 0;
135}
136
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137void timer_handler(int sig, union uml_pt_regs *regs)
138{
139 local_irq_disable();
140 update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)), (regs)->skas.is_user));
141 local_irq_enable();
142 if(current_thread->cpu == 0)
143 timer_irq(regs);
144}
145
146static DEFINE_SPINLOCK(timer_spinlock);
147
148unsigned long time_lock(void)
149{
150 unsigned long flags;
151
152 spin_lock_irqsave(&timer_spinlock, flags);
153 return(flags);
154}
155
156void time_unlock(unsigned long flags)
157{
158 spin_unlock_irqrestore(&timer_spinlock, flags);
159}
160
161int __init timer_init(void)
162{
163 int err;
164
165 CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
166 err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL);
167 if(err != 0)
168 printk(KERN_ERR "timer_init : request_irq failed - "
169 "errno = %d\n", -err);
170 timer_irq_inited = 1;
171 return(0);
172}
173
174__initcall(timer_init);
175
176/*
177 * Overrides for Emacs so that we follow Linus's tabbing style.
178 * Emacs will notice this stuff at the end of the file and automatically
179 * adjust the settings for this buffer only. This must remain at the end
180 * of the file.
181 * ---------------------------------------------------------------------------
182 * Local variables:
183 * c-file-style: "linux"
184 * End:
185 */