import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / m68k / kernel / time.c
1 /*
2  *  linux/arch/m68k/kernel/time.c
3  *
4  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
5  *
6  * This file contains the m68k-specific time handling details.
7  * Most of the stuff is located in the machine specific files.
8  *
9  * 1997-09-10   Updated NTP code according to technical memorandum Jan '96
10  *              "A Kernel Model for Precision Timekeeping" by Dave Mills
11  */
12
13 #include <linux/config.h> /* CONFIG_HEARTBEAT */
14 #include <linux/errno.h>
15 #include <linux/sched.h>
16 #include <linux/kernel.h>
17 #include <linux/param.h>
18 #include <linux/string.h>
19 #include <linux/mm.h>
20
21 #include <asm/machdep.h>
22 #include <asm/io.h>
23
24 #include <linux/timex.h>
25
26
27 static inline int set_rtc_mmss(unsigned long nowtime)
28 {
29   if (mach_set_clock_mmss)
30     return mach_set_clock_mmss (nowtime);
31   return -1;
32 }
33
34 static inline void do_profile (unsigned long pc)
35 {
36         if (prof_buffer && current->pid) {
37                 extern int _stext;
38                 pc -= (unsigned long) &_stext;
39                 pc >>= prof_shift;
40                 if (pc < prof_len)
41                         ++prof_buffer[pc];
42                 else
43                 /*
44                  * Don't ignore out-of-bounds PC values silently,
45                  * put them into the last histogram slot, so if
46                  * present, they will show up as a sharp peak.
47                  */
48                         ++prof_buffer[prof_len-1];
49         }
50 }
51
52 /*
53  * timer_interrupt() needs to keep up the real-time clock,
54  * as well as call the "do_timer()" routine every clocktick
55  */
56 static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
57 {
58         do_timer(regs);
59
60         if (!user_mode(regs))
61                 do_profile(regs->pc);
62
63 #ifdef CONFIG_HEARTBEAT
64         /* use power LED as a heartbeat instead -- much more useful
65            for debugging -- based on the version for PReP by Cort */
66         /* acts like an actual heart beat -- ie thump-thump-pause... */
67         if (mach_heartbeat) {
68             static unsigned cnt = 0, period = 0, dist = 0;
69
70             if (cnt == 0 || cnt == dist)
71                 mach_heartbeat( 1 );
72             else if (cnt == 7 || cnt == dist+7)
73                 mach_heartbeat( 0 );
74
75             if (++cnt > period) {
76                 cnt = 0;
77                 /* The hyperbolic function below modifies the heartbeat period
78                  * length in dependency of the current (5min) load. It goes
79                  * through the points f(0)=126, f(1)=86, f(5)=51,
80                  * f(inf)->30. */
81                 period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
82                 dist = period / 4;
83             }
84         }
85 #endif /* CONFIG_HEARTBEAT */
86 }
87
88 void time_init(void)
89 {
90         unsigned int year, mon, day, hour, min, sec;
91
92         extern void arch_gettod(int *year, int *mon, int *day, int *hour,
93                                 int *min, int *sec);
94
95         arch_gettod (&year, &mon, &day, &hour, &min, &sec);
96
97         if ((year += 1900) < 1970)
98                 year += 100;
99         xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
100         xtime.tv_usec = 0;
101
102         mach_sched_init(timer_interrupt);
103 }
104
105 extern rwlock_t xtime_lock;
106
107 /*
108  * This version of gettimeofday has near microsecond resolution.
109  */
110 void do_gettimeofday(struct timeval *tv)
111 {
112         extern unsigned long wall_jiffies;
113         unsigned long flags;
114         unsigned long usec, sec, lost;
115
116         read_lock_irqsave(&xtime_lock, flags);
117         usec = mach_gettimeoffset();
118         lost = jiffies - wall_jiffies;
119         if (lost)
120                 usec += lost * (1000000/HZ);
121         sec = xtime.tv_sec;
122         usec += xtime.tv_usec;
123         read_unlock_irqrestore(&xtime_lock, flags);
124
125         while (usec >= 1000000) {
126                 usec -= 1000000;
127                 sec++;
128         }
129
130         tv->tv_sec = sec;
131         tv->tv_usec = usec;
132 }
133
134 void do_settimeofday(struct timeval *tv)
135 {
136         write_lock_irq(&xtime_lock);
137         /* This is revolting. We need to set the xtime.tv_usec
138          * correctly. However, the value in this location is
139          * is value at the last tick.
140          * Discover what correction gettimeofday
141          * would have done, and then undo it!
142          */
143         tv->tv_usec -= mach_gettimeoffset();
144
145         while (tv->tv_usec < 0) {
146                 tv->tv_usec += 1000000;
147                 tv->tv_sec--;
148         }
149
150         xtime = *tv;
151         time_adjust = 0;                /* stop active adjtime() */
152         time_status |= STA_UNSYNC;
153         time_maxerror = NTP_PHASE_LIMIT;
154         time_esterror = NTP_PHASE_LIMIT;
155         write_unlock_irq(&xtime_lock);
156 }