ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / um / kernel / time_kern.c
1 /* 
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
24 u64 jiffies_64;
25
26 EXPORT_SYMBOL(jiffies_64);
27
28 int hz(void)
29 {
30         return(HZ);
31 }
32
33 /* Changed at early boot */
34 int timer_irq_inited = 0;
35
36 /* missed_ticks will be modified after kernel memory has been 
37  * write-protected, so this puts it in a section which will be left 
38  * write-enabled.
39  */
40 int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS];
41
42 void timer_irq(union uml_pt_regs *regs)
43 {
44         int cpu = current->thread_info->cpu, ticks = missed_ticks[cpu];
45
46         if(!timer_irq_inited) return;
47         missed_ticks[cpu] = 0;
48         while(ticks--) do_IRQ(TIMER_IRQ, regs);
49 }
50
51 void boot_timer_handler(int sig)
52 {
53         struct pt_regs regs;
54
55         CHOOSE_MODE((void) 
56                     (UPT_SC(&regs.regs) = (struct sigcontext *) (&sig + 1)),
57                     (void) (regs.regs.skas.is_user = 0));
58         do_timer(&regs);
59 }
60
61 void um_timer(int irq, void *dev, struct pt_regs *regs)
62 {
63         do_timer(regs);
64         write_seqlock(&xtime_lock);
65         timer();
66         write_sequnlock(&xtime_lock);
67 }
68
69 long um_time(int * tloc)
70 {
71         struct timeval now;
72
73         do_gettimeofday(&now);
74         if (tloc) {
75                 if (put_user(now.tv_sec,tloc))
76                         now.tv_sec = -EFAULT;
77         }
78         return now.tv_sec;
79 }
80
81 long um_stime(int * tptr)
82 {
83         int value;
84         struct timeval new;
85
86         if (get_user(value, tptr))
87                 return -EFAULT;
88         new.tv_sec = value;
89         new.tv_usec = 0;
90         do_settimeofday(&new);
91         return 0;
92 }
93
94 /* XXX Needs to be moved under sys-i386 */
95 void __delay(um_udelay_t time)
96 {
97         /* Stolen from the i386 __loop_delay */
98         int d0;
99         __asm__ __volatile__(
100                 "\tjmp 1f\n"
101                 ".align 16\n"
102                 "1:\tjmp 2f\n"
103                 ".align 16\n"
104                 "2:\tdecl %0\n\tjns 2b"
105                 :"=&a" (d0)
106                 :"0" (time));
107 }
108
109 void __udelay(um_udelay_t usecs)
110 {
111         int i, n;
112
113         n = (loops_per_jiffy * HZ * usecs) / 1000000;
114         for(i=0;i<n;i++) ;
115 }
116
117 void __const_udelay(um_udelay_t usecs)
118 {
119         int i, n;
120
121         n = (loops_per_jiffy * HZ * usecs) / 1000000;
122         for(i=0;i<n;i++) ;
123 }
124
125 void timer_handler(int sig, union uml_pt_regs *regs)
126 {
127 #ifdef CONFIG_SMP
128         update_process_times(user_context(UPT_SP(regs)));
129 #endif
130         if(current->thread_info->cpu == 0)
131                 timer_irq(regs);
132 }
133
134 static spinlock_t timer_spinlock = SPIN_LOCK_UNLOCKED;
135
136 unsigned long time_lock(void)
137 {
138         unsigned long flags;
139         spin_lock_irqsave(&timer_spinlock, flags);
140         return(flags);
141 }
142
143 void time_unlock(unsigned long flags)
144 {
145         spin_unlock_irqrestore(&timer_spinlock, flags);
146 }
147
148 int __init timer_init(void)
149 {
150         int err;
151
152         CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
153         if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", 
154                               NULL)) != 0)
155                 printk(KERN_ERR "timer_init : request_irq failed - "
156                        "errno = %d\n", -err);
157         timer_irq_inited = 1;
158         return(0);
159 }
160
161 __initcall(timer_init);
162
163
164 /*
165  * Overrides for Emacs so that we follow Linus's tabbing style.
166  * Emacs will notice this stuff at the end of the file and automatically
167  * adjust the settings for this buffer only.  This must remain at the end
168  * of the file.
169  * ---------------------------------------------------------------------------
170  * Local variables:
171  * c-file-style: "linux"
172  * End:
173  */