PageRenderTime 41ms CodeModel.GetById 14ms app.highlight 20ms RepoModel.GetById 2ms app.codeStats 0ms

/arch/cris/kernel/time.c

https://bitbucket.org/evzijst/gittest
C | 232 lines | 133 code | 41 blank | 58 comment | 11 complexity | adc44202478914b9235e0aba065e5efa MD5 | raw file
  1/* $Id: time.c,v 1.14 2004/06/01 05:38:11 starvik Exp $
  2 *
  3 *  linux/arch/cris/kernel/time.c
  4 *
  5 *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
  6 *  Copyright (C) 1999, 2000, 2001 Axis Communications AB
  7 *
  8 * 1994-07-02    Alan Modra
  9 *	fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
 10 * 1995-03-26    Markus Kuhn
 11 *      fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
 12 *      precision CMOS clock update
 13 * 1996-05-03    Ingo Molnar
 14 *      fixed time warps in do_[slow|fast]_gettimeoffset()
 15 * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
 16 *		"A Kernel Model for Precision Timekeeping" by Dave Mills
 17 *
 18 * Linux/CRIS specific code:
 19 *
 20 * Authors:    Bjorn Wesen
 21 *             Johan Adolfsson  
 22 *
 23 */
 24
 25#include <asm/rtc.h>
 26#include <linux/errno.h>
 27#include <linux/module.h>
 28#include <linux/param.h>
 29#include <linux/jiffies.h>
 30#include <linux/bcd.h>
 31#include <linux/timex.h>
 32#include <linux/init.h>
 33
 34u64 jiffies_64 = INITIAL_JIFFIES;
 35
 36EXPORT_SYMBOL(jiffies_64);
 37
 38int have_rtc;  /* used to remember if we have an RTC or not */;
 39
 40#define TICK_SIZE tick
 41
 42extern unsigned long wall_jiffies;
 43extern unsigned long loops_per_jiffy; /* init/main.c */
 44unsigned long loops_per_usec;
 45
 46extern unsigned long do_slow_gettimeoffset(void);
 47static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
 48
 49/*
 50 * This version of gettimeofday has near microsecond resolution.
 51 *
 52 * Note: Division is quite slow on CRIS and do_gettimeofday is called
 53 *       rather often. Maybe we should do some kind of approximation here
 54 *       (a naive approximation would be to divide by 1024).
 55 */
 56void do_gettimeofday(struct timeval *tv)
 57{
 58	unsigned long flags;
 59	signed long usec, sec;
 60	local_irq_save(flags);
 61	local_irq_disable();
 62	usec = do_gettimeoffset();
 63	{
 64		unsigned long lost = jiffies - wall_jiffies;
 65		if (lost)
 66			usec += lost * (1000000 / HZ);
 67	}
 68
 69        /*
 70	 * If time_adjust is negative then NTP is slowing the clock
 71	 * so make sure not to go into next possible interval.
 72	 * Better to lose some accuracy than have time go backwards..
 73	 */
 74	if (unlikely(time_adjust < 0) && usec > tickadj)
 75		usec = tickadj;
 76
 77	sec = xtime.tv_sec;
 78	usec += xtime.tv_nsec / 1000;
 79	local_irq_restore(flags);
 80
 81	while (usec >= 1000000) {
 82		usec -= 1000000;
 83		sec++;
 84	}
 85
 86	tv->tv_sec = sec;
 87	tv->tv_usec = usec;
 88}
 89
 90EXPORT_SYMBOL(do_gettimeofday);
 91
 92int do_settimeofday(struct timespec *tv)
 93{
 94	time_t wtm_sec, sec = tv->tv_sec;
 95	long wtm_nsec, nsec = tv->tv_nsec;
 96
 97	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
 98		return -EINVAL;
 99
100	write_seqlock_irq(&xtime_lock);
101	/*
102	 * This is revolting. We need to set "xtime" correctly. However, the
103	 * value in this location is the value at the most recent update of
104	 * wall time.  Discover what correction gettimeofday() would have
105	 * made, and then undo it!
106	 */
107	nsec -= do_gettimeoffset() * NSEC_PER_USEC;
108	nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
109
110	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
111	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
112
113	set_normalized_timespec(&xtime, sec, nsec);
114	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
115
116	time_adjust = 0;		/* stop active adjtime() */
117	time_status |= STA_UNSYNC;
118	time_maxerror = NTP_PHASE_LIMIT;
119	time_esterror = NTP_PHASE_LIMIT;
120	write_sequnlock_irq(&xtime_lock);
121	clock_was_set();
122	return 0;
123}
124
125EXPORT_SYMBOL(do_settimeofday);
126
127
128/*
129 * BUG: This routine does not handle hour overflow properly; it just
130 *      sets the minutes. Usually you'll only notice that after reboot!
131 */
132
133int set_rtc_mmss(unsigned long nowtime)
134{
135	int retval = 0;
136	int real_seconds, real_minutes, cmos_minutes;
137
138	printk(KERN_DEBUG "set_rtc_mmss(%lu)\n", nowtime);
139
140	if(!have_rtc)
141		return 0;
142
143	cmos_minutes = CMOS_READ(RTC_MINUTES);
144	BCD_TO_BIN(cmos_minutes);
145
146	/*
147	 * since we're only adjusting minutes and seconds,
148	 * don't interfere with hour overflow. This avoids
149	 * messing with unknown time zones but requires your
150	 * RTC not to be off by more than 15 minutes
151	 */
152	real_seconds = nowtime % 60;
153	real_minutes = nowtime / 60;
154	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
155		real_minutes += 30;		/* correct for half hour time zone */
156	real_minutes %= 60;
157
158	if (abs(real_minutes - cmos_minutes) < 30) {
159		BIN_TO_BCD(real_seconds);
160		BIN_TO_BCD(real_minutes);
161		CMOS_WRITE(real_seconds,RTC_SECONDS);
162		CMOS_WRITE(real_minutes,RTC_MINUTES);
163	} else {
164		printk(KERN_WARNING
165		       "set_rtc_mmss: can't update from %d to %d\n",
166		       cmos_minutes, real_minutes);
167		retval = -1;
168	}
169
170	return retval;
171}
172
173/* grab the time from the RTC chip */
174
175unsigned long
176get_cmos_time(void)
177{
178	unsigned int year, mon, day, hour, min, sec;
179
180	sec = CMOS_READ(RTC_SECONDS);
181	min = CMOS_READ(RTC_MINUTES);
182	hour = CMOS_READ(RTC_HOURS);
183	day = CMOS_READ(RTC_DAY_OF_MONTH);
184	mon = CMOS_READ(RTC_MONTH);
185	year = CMOS_READ(RTC_YEAR);
186
187	printk(KERN_DEBUG
188	       "rtc: sec 0x%x min 0x%x hour 0x%x day 0x%x mon 0x%x year 0x%x\n",
189	       sec, min, hour, day, mon, year);
190
191	BCD_TO_BIN(sec);
192	BCD_TO_BIN(min);
193	BCD_TO_BIN(hour);
194	BCD_TO_BIN(day);
195	BCD_TO_BIN(mon);
196	BCD_TO_BIN(year);
197
198	if ((year += 1900) < 1970)
199		year += 100;
200
201	return mktime(year, mon, day, hour, min, sec);
202}
203
204/* update xtime from the CMOS settings. used when /dev/rtc gets a SET_TIME.
205 * TODO: this doesn't reset the fancy NTP phase stuff as do_settimeofday does.
206 */
207
208void
209update_xtime_from_cmos(void)
210{
211	if(have_rtc) {
212		xtime.tv_sec = get_cmos_time();
213		xtime.tv_nsec = 0;
214	}
215}
216
217/*
218 * Scheduler clock - returns current time in nanosec units.
219 */
220unsigned long long sched_clock(void)
221{
222	return (unsigned long long)jiffies * (1000000000 / HZ);
223}
224
225static int
226__init init_udelay(void)
227{
228	loops_per_usec = (loops_per_jiffy * HZ) / 1000000;
229	return 0;
230}
231
232__initcall(init_udelay);