diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/m32r/kernel/time.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/m32r/kernel/time.c')
-rw-r--r-- | arch/m32r/kernel/time.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c new file mode 100644 index 000000000000..3c4707280a52 --- /dev/null +++ b/arch/m32r/kernel/time.c | |||
@@ -0,0 +1,318 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/kernel/time.c | ||
3 | * | ||
4 | * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, | ||
5 | * Hitoshi Yamamoto | ||
6 | * Taken from i386 version. | ||
7 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | ||
8 | * Copyright (C) 1996, 1997, 1998 Ralf Baechle | ||
9 | * | ||
10 | * This file contains the time handling details for PC-style clocks as | ||
11 | * found in some MIPS systems. | ||
12 | * | ||
13 | * Some code taken from sh version. | ||
14 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | ||
15 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
16 | */ | ||
17 | |||
18 | #undef DEBUG_TIMER | ||
19 | |||
20 | #include <linux/config.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/param.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/profile.h> | ||
31 | |||
32 | #include <asm/io.h> | ||
33 | #include <asm/m32r.h> | ||
34 | |||
35 | #include <asm/hw_irq.h> | ||
36 | |||
37 | #ifdef CONFIG_SMP | ||
38 | extern void send_IPI_allbutself(int, int); | ||
39 | extern void smp_local_timer_interrupt(struct pt_regs *); | ||
40 | #endif | ||
41 | |||
42 | u64 jiffies_64 = INITIAL_JIFFIES; | ||
43 | |||
44 | EXPORT_SYMBOL(jiffies_64); | ||
45 | |||
46 | extern unsigned long wall_jiffies; | ||
47 | #define TICK_SIZE (tick_nsec / 1000) | ||
48 | |||
49 | /* | ||
50 | * Change this if you have some constant time drift | ||
51 | */ | ||
52 | |||
53 | /* This is for machines which generate the exact clock. */ | ||
54 | #define USECS_PER_JIFFY (1000000/HZ) | ||
55 | |||
56 | static unsigned long latch; | ||
57 | |||
58 | static unsigned long do_gettimeoffset(void) | ||
59 | { | ||
60 | unsigned long elapsed_time = 0; /* [us] */ | ||
61 | |||
62 | #if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \ | ||
63 | || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \ | ||
64 | || defined(CONFIG_CHIP_OPSP) | ||
65 | #ifndef CONFIG_SMP | ||
66 | |||
67 | unsigned long count; | ||
68 | |||
69 | /* timer count may underflow right here */ | ||
70 | count = inl(M32R_MFT2CUT_PORTL); | ||
71 | |||
72 | if (inl(M32R_ICU_CR18_PORTL) & 0x00000100) /* underflow check */ | ||
73 | count = 0; | ||
74 | |||
75 | count = (latch - count) * TICK_SIZE; | ||
76 | elapsed_time = (count + latch / 2) / latch; | ||
77 | /* NOTE: LATCH is equal to the "interval" value (= reload count). */ | ||
78 | |||
79 | #else /* CONFIG_SMP */ | ||
80 | unsigned long count; | ||
81 | static unsigned long p_jiffies = -1; | ||
82 | static unsigned long p_count = 0; | ||
83 | |||
84 | /* timer count may underflow right here */ | ||
85 | count = inl(M32R_MFT2CUT_PORTL); | ||
86 | |||
87 | if (jiffies == p_jiffies && count > p_count) | ||
88 | count = 0; | ||
89 | |||
90 | p_jiffies = jiffies; | ||
91 | p_count = count; | ||
92 | |||
93 | count = (latch - count) * TICK_SIZE; | ||
94 | elapsed_time = (count + latch / 2) / latch; | ||
95 | /* NOTE: LATCH is equal to the "interval" value (= reload count). */ | ||
96 | #endif /* CONFIG_SMP */ | ||
97 | #elif defined(CONFIG_CHIP_M32310) | ||
98 | #warning do_gettimeoffse not implemented | ||
99 | #else | ||
100 | #error no chip configuration | ||
101 | #endif | ||
102 | |||
103 | return elapsed_time; | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * This version of gettimeofday has near microsecond resolution. | ||
108 | */ | ||
109 | void do_gettimeofday(struct timeval *tv) | ||
110 | { | ||
111 | unsigned long seq; | ||
112 | unsigned long usec, sec; | ||
113 | unsigned long max_ntp_tick = tick_usec - tickadj; | ||
114 | |||
115 | do { | ||
116 | unsigned long lost; | ||
117 | |||
118 | seq = read_seqbegin(&xtime_lock); | ||
119 | |||
120 | usec = do_gettimeoffset(); | ||
121 | lost = jiffies - wall_jiffies; | ||
122 | |||
123 | /* | ||
124 | * If time_adjust is negative then NTP is slowing the clock | ||
125 | * so make sure not to go into next possible interval. | ||
126 | * Better to lose some accuracy than have time go backwards.. | ||
127 | */ | ||
128 | if (unlikely(time_adjust < 0)) { | ||
129 | usec = min(usec, max_ntp_tick); | ||
130 | if (lost) | ||
131 | usec += lost * max_ntp_tick; | ||
132 | } else if (unlikely(lost)) | ||
133 | usec += lost * tick_usec; | ||
134 | |||
135 | sec = xtime.tv_sec; | ||
136 | usec += (xtime.tv_nsec / 1000); | ||
137 | } while (read_seqretry(&xtime_lock, seq)); | ||
138 | |||
139 | while (usec >= 1000000) { | ||
140 | usec -= 1000000; | ||
141 | sec++; | ||
142 | } | ||
143 | |||
144 | tv->tv_sec = sec; | ||
145 | tv->tv_usec = usec; | ||
146 | } | ||
147 | |||
148 | EXPORT_SYMBOL(do_gettimeofday); | ||
149 | |||
150 | int do_settimeofday(struct timespec *tv) | ||
151 | { | ||
152 | time_t wtm_sec, sec = tv->tv_sec; | ||
153 | long wtm_nsec, nsec = tv->tv_nsec; | ||
154 | |||
155 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | ||
156 | return -EINVAL; | ||
157 | |||
158 | write_seqlock_irq(&xtime_lock); | ||
159 | /* | ||
160 | * This is revolting. We need to set "xtime" correctly. However, the | ||
161 | * value in this location is the value at the most recent update of | ||
162 | * wall time. Discover what correction gettimeofday() would have | ||
163 | * made, and then undo it! | ||
164 | */ | ||
165 | nsec -= do_gettimeoffset() * NSEC_PER_USEC; | ||
166 | nsec -= (jiffies - wall_jiffies) * TICK_NSEC; | ||
167 | |||
168 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | ||
169 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | ||
170 | |||
171 | set_normalized_timespec(&xtime, sec, nsec); | ||
172 | set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); | ||
173 | |||
174 | time_adjust = 0; /* stop active adjtime() */ | ||
175 | time_status |= STA_UNSYNC; | ||
176 | time_maxerror = NTP_PHASE_LIMIT; | ||
177 | time_esterror = NTP_PHASE_LIMIT; | ||
178 | write_sequnlock_irq(&xtime_lock); | ||
179 | clock_was_set(); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | EXPORT_SYMBOL(do_settimeofday); | ||
185 | |||
186 | /* | ||
187 | * In order to set the CMOS clock precisely, set_rtc_mmss has to be | ||
188 | * called 500 ms after the second nowtime has started, because when | ||
189 | * nowtime is written into the registers of the CMOS clock, it will | ||
190 | * jump to the next second precisely 500 ms later. Check the Motorola | ||
191 | * MC146818A or Dallas DS12887 data sheet for details. | ||
192 | * | ||
193 | * BUG: This routine does not handle hour overflow properly; it just | ||
194 | * sets the minutes. Usually you won't notice until after reboot! | ||
195 | */ | ||
196 | static inline int set_rtc_mmss(unsigned long nowtime) | ||
197 | { | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | /* last time the cmos clock got updated */ | ||
202 | static long last_rtc_update = 0; | ||
203 | |||
204 | /* | ||
205 | * timer_interrupt() needs to keep up the real-time clock, | ||
206 | * as well as call the "do_timer()" routine every clocktick | ||
207 | */ | ||
208 | static inline void | ||
209 | do_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) | ||
210 | { | ||
211 | #ifndef CONFIG_SMP | ||
212 | profile_tick(CPU_PROFILING, regs); | ||
213 | #endif | ||
214 | do_timer(regs); | ||
215 | |||
216 | #ifndef CONFIG_SMP | ||
217 | update_process_times(user_mode(regs)); | ||
218 | #endif | ||
219 | /* | ||
220 | * If we have an externally synchronized Linux clock, then update | ||
221 | * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be | ||
222 | * called as close as possible to 500 ms before the new second starts. | ||
223 | */ | ||
224 | if ((time_status & STA_UNSYNC) == 0 | ||
225 | && xtime.tv_sec > last_rtc_update + 660 | ||
226 | && (xtime.tv_nsec / 1000) >= 500000 - ((unsigned)TICK_SIZE) / 2 | ||
227 | && (xtime.tv_nsec / 1000) <= 500000 + ((unsigned)TICK_SIZE) / 2) | ||
228 | { | ||
229 | if (set_rtc_mmss(xtime.tv_sec) == 0) | ||
230 | last_rtc_update = xtime.tv_sec; | ||
231 | else /* do it again in 60 s */ | ||
232 | last_rtc_update = xtime.tv_sec - 600; | ||
233 | } | ||
234 | /* As we return to user mode fire off the other CPU schedulers.. | ||
235 | this is basically because we don't yet share IRQ's around. | ||
236 | This message is rigged to be safe on the 386 - basically it's | ||
237 | a hack, so don't look closely for now.. */ | ||
238 | |||
239 | #ifdef CONFIG_SMP | ||
240 | smp_local_timer_interrupt(regs); | ||
241 | #endif | ||
242 | } | ||
243 | |||
244 | irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
245 | { | ||
246 | write_seqlock(&xtime_lock); | ||
247 | do_timer_interrupt(irq, NULL, regs); | ||
248 | write_sequnlock(&xtime_lock); | ||
249 | |||
250 | return IRQ_HANDLED; | ||
251 | } | ||
252 | |||
253 | struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, | ||
254 | "MFT2", NULL, NULL }; | ||
255 | |||
256 | void __init time_init(void) | ||
257 | { | ||
258 | unsigned int epoch, year, mon, day, hour, min, sec; | ||
259 | |||
260 | sec = min = hour = day = mon = year = 0; | ||
261 | epoch = 0; | ||
262 | |||
263 | year = 23; | ||
264 | mon = 4; | ||
265 | day = 17; | ||
266 | |||
267 | /* Attempt to guess the epoch. This is the same heuristic as in rtc.c | ||
268 | so no stupid things will happen to timekeeping. Who knows, maybe | ||
269 | Ultrix also uses 1952 as epoch ... */ | ||
270 | if (year > 10 && year < 44) | ||
271 | epoch = 1980; | ||
272 | else if (year < 96) | ||
273 | epoch = 1952; | ||
274 | year += epoch; | ||
275 | |||
276 | xtime.tv_sec = mktime(year, mon, day, hour, min, sec); | ||
277 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
278 | set_normalized_timespec(&wall_to_monotonic, | ||
279 | -xtime.tv_sec, -xtime.tv_nsec); | ||
280 | |||
281 | #if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \ | ||
282 | || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \ | ||
283 | || defined(CONFIG_CHIP_OPSP) | ||
284 | |||
285 | /* M32102 MFT setup */ | ||
286 | setup_irq(M32R_IRQ_MFT2, &irq0); | ||
287 | { | ||
288 | unsigned long bus_clock; | ||
289 | unsigned short divide; | ||
290 | |||
291 | bus_clock = boot_cpu_data.bus_clock; | ||
292 | divide = boot_cpu_data.timer_divide; | ||
293 | latch = (bus_clock/divide + HZ / 2) / HZ; | ||
294 | |||
295 | printk("Timer start : latch = %ld\n", latch); | ||
296 | |||
297 | outl((M32R_MFTMOD_CC_MASK | M32R_MFTMOD_TCCR \ | ||
298 | |M32R_MFTMOD_CSSEL011), M32R_MFT2MOD_PORTL); | ||
299 | outl(latch, M32R_MFT2RLD_PORTL); | ||
300 | outl(latch, M32R_MFT2CUT_PORTL); | ||
301 | outl(0, M32R_MFT2CMPRLD_PORTL); | ||
302 | outl((M32R_MFTCR_MFT2MSK|M32R_MFTCR_MFT2EN), M32R_MFTCR_PORTL); | ||
303 | } | ||
304 | |||
305 | #elif defined(CONFIG_CHIP_M32310) | ||
306 | #warning time_init not implemented | ||
307 | #else | ||
308 | #error no chip configuration | ||
309 | #endif | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Scheduler clock - returns current time in nanosec units. | ||
314 | */ | ||
315 | unsigned long long sched_clock(void) | ||
316 | { | ||
317 | return (unsigned long long)jiffies * (1000000000 / HZ); | ||
318 | } | ||