File: /usr/src/linux/arch/arm/kernel/time.c

1     /*
2      *  linux/arch/arm/kernel/time.c
3      *
4      *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
5      *  Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King
6      *
7      * This program is free software; you can redistribute it and/or modify
8      * it under the terms of the GNU General Public License version 2 as
9      * published by the Free Software Foundation.
10      *
11      *  This file contains the ARM-specific time handling details:
12      *  reading the RTC at bootup, etc...
13      *
14      *  1994-07-02  Alan Modra
15      *              fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
16      *  1998-12-20  Updated NTP code according to technical memorandum Jan '96
17      *              "A Kernel Model for Precision Timekeeping" by Dave Mills
18      */
19     #include <linux/config.h>
20     #include <linux/module.h>
21     #include <linux/sched.h>
22     #include <linux/kernel.h>
23     #include <linux/interrupt.h>
24     #include <linux/time.h>
25     #include <linux/init.h>
26     #include <linux/smp.h>
27     
28     #include <asm/uaccess.h>
29     #include <asm/io.h>
30     #include <asm/irq.h>
31     
32     #include <linux/timex.h>
33     #include <asm/hardware.h>
34     
35     extern int setup_arm_irq(int, struct irqaction *);
36     extern void setup_timer(void);
37     extern rwlock_t xtime_lock;
38     extern unsigned long wall_jiffies;
39     
40     /* change this if you have some constant time drift */
41     #define USECS_PER_JIFFY	(1000000/HZ)
42     
43     #ifndef BCD_TO_BIN
44     #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
45     #endif
46     
47     #ifndef BIN_TO_BCD
48     #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
49     #endif
50     
51     static int dummy_set_rtc(void)
52     {
53     	return 0;
54     }
55     
56     /*
57      * hook for setting the RTC's idea of the current time.
58      */
59     int (*set_rtc)(void) = dummy_set_rtc;
60     
61     static unsigned long dummy_gettimeoffset(void)
62     {
63     	return 0;
64     }
65     
66     /*
67      * hook for getting the time offset.  Note that it is
68      * always called with interrupts disabled.
69      */
70     unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset;
71     
72     /*
73      * Handle kernel profile stuff...
74      */
75     static inline void do_profile(struct pt_regs *regs)
76     {
77     	if (!user_mode(regs) &&
78     	    prof_buffer &&
79     	    current->pid) {
80     		unsigned long pc = instruction_pointer(regs);
81     		extern int _stext;
82     
83     		pc -= (unsigned long)&_stext;
84     
85     		pc >>= prof_shift;
86     
87     		if (pc >= prof_len)
88     			pc = prof_len - 1;
89     
90     		prof_buffer[pc] += 1;
91     	}
92     }
93     
94     static long next_rtc_update;
95     
96     /*
97      * If we have an externally synchronized linux clock, then update
98      * CMOS clock accordingly every ~11 minutes.  set_rtc() has to be
99      * called as close as possible to 500 ms before the new second
100      * starts.
101      */
102     static inline void do_set_rtc(void)
103     {
104     	if (time_status & STA_UNSYNC || set_rtc == NULL)
105     		return;
106     
107     	if (next_rtc_update &&
108     	    time_before(xtime.tv_sec, next_rtc_update))
109     		return;
110     
111     	if (xtime.tv_usec < 50000 - (tick >> 1) &&
112     	    xtime.tv_usec >= 50000 + (tick >> 1))
113     		return;
114     
115     	if (set_rtc())
116     		/*
117     		 * rtc update failed.  Try again in 60s
118     		 */
119     		next_rtc_update = xtime.tv_sec + 60;
120     	else
121     		next_rtc_update = xtime.tv_sec + 660;
122     }
123     
124     #ifdef CONFIG_LEDS
125     
126     #include <asm/leds.h>
127     
128     static void dummy_leds_event(led_event_t evt)
129     {
130     }
131     
132     void (*leds_event)(led_event_t) = dummy_leds_event;
133     
134     #ifdef CONFIG_MODULES
135     EXPORT_SYMBOL(leds_event);
136     #endif
137     #endif
138     
139     #ifdef CONFIG_LEDS_TIMER
140     static void do_leds(void)
141     {
142     	static unsigned int count = 50;
143     
144     	if (--count == 0) {
145     		count = 50;
146     		leds_event(led_timer);
147     	}
148     }
149     #else
150     #define do_leds()
151     #endif
152     
153     void do_gettimeofday(struct timeval *tv)
154     {
155     	unsigned long flags;
156     	unsigned long usec, sec;
157     
158     	read_lock_irqsave(&xtime_lock, flags);
159     	usec = gettimeoffset();
160     	{
161     		unsigned long lost = jiffies - wall_jiffies;
162     
163     		if (lost)
164     			usec += lost * USECS_PER_JIFFY;
165     	}
166     	sec = xtime.tv_sec;
167     	usec += xtime.tv_usec;
168     	read_unlock_irqrestore(&xtime_lock, flags);
169     
170     	/* usec may have gone up a lot: be safe */
171     	while (usec >= 1000000) {
172     		usec -= 1000000;
173     		sec++;
174     	}
175     
176     	tv->tv_sec = sec;
177     	tv->tv_usec = usec;
178     }
179     
180     void do_settimeofday(struct timeval *tv)
181     {
182     	write_lock_irq(&xtime_lock);
183     	/* This is revolting. We need to set the xtime.tv_usec
184     	 * correctly. However, the value in this location is
185     	 * is value at the last tick.
186     	 * Discover what correction gettimeofday
187     	 * would have done, and then undo it!
188     	 */
189     	tv->tv_usec -= gettimeoffset();
190     	tv->tv_usec -= (jiffies - wall_jiffies) * USECS_PER_JIFFY;
191     
192     	while (tv->tv_usec < 0) {
193     		tv->tv_usec += 1000000;
194     		tv->tv_sec--;
195     	}
196     
197     	xtime = *tv;
198     	time_adjust = 0;		/* stop active adjtime() */
199     	time_status |= STA_UNSYNC;
200     	time_maxerror = NTP_PHASE_LIMIT;
201     	time_esterror = NTP_PHASE_LIMIT;
202     	write_unlock_irq(&xtime_lock);
203     }
204     
205     static struct irqaction timer_irq = {
206     	name: "timer",
207     };
208     
209     /*
210      * Include architecture specific code
211      */
212     #include <asm/arch/time.h>
213     
214     /*
215      * This must cause the timer to start ticking.
216      * It doesn't have to set the current time though
217      * from an RTC - it can be done later once we have
218      * some buses initialised.
219      */
220     void __init time_init(void)
221     {
222     	xtime.tv_usec = 0;
223     	xtime.tv_sec  = 0;
224     
225     	setup_timer();
226     }
227