forked from Minki/linux
8ef386092d
With 2.6.18-rc4-mm2, now wall_jiffies will always be the same as jiffies. So we can kill wall_jiffies completely. This is just a cleanup and logically should not change any real behavior except for one thing: RTC updating code in (old) ppc and xtensa use a condition "jiffies - wall_jiffies == 1". This condition is never met so I suppose it is just a bug. I just remove that condition only instead of kill the whole "if" block. [heiko.carstens@de.ibm.com: s390 build fix and cleanup] Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Cc: Andi Kleen <ak@muc.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Richard Henderson <rth@twiddle.net> Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru> Cc: Russell King <rmk@arm.linux.org.uk> Cc: Ian Molton <spyro@f2s.com> Cc: Mikael Starvik <starvik@axis.com> Cc: David Howells <dhowells@redhat.com> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Cc: Hirokazu Takata <takata.hirokazu@renesas.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Kyle McMartin <kyle@mcmartin.ca> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Paul Mundt <lethal@linux-sh.org> Cc: Kazumoto Kojima <kkojima@rr.iij4u.or.jp> Cc: Richard Curnow <rc@rc0.org.uk> Cc: William Lee Irwin III <wli@holomorphy.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Jeff Dike <jdike@addtoit.com> Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Cc: Miles Bader <uclinux-v850@lsi.nec.co.jp> Cc: Chris Zankel <chris@zankel.net> Cc: "Luck, Tony" <tony.luck@intel.com> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
236 lines
5.6 KiB
C
236 lines
5.6 KiB
C
/* $Id: time.c,v 1.18 2005/03/04 08:16:17 starvik Exp $
|
|
*
|
|
* linux/arch/cris/kernel/time.c
|
|
*
|
|
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
|
|
* Copyright (C) 1999, 2000, 2001 Axis Communications AB
|
|
*
|
|
* 1994-07-02 Alan Modra
|
|
* fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
|
|
* 1995-03-26 Markus Kuhn
|
|
* fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
|
|
* precision CMOS clock update
|
|
* 1996-05-03 Ingo Molnar
|
|
* fixed time warps in do_[slow|fast]_gettimeoffset()
|
|
* 1997-09-10 Updated NTP code according to technical memorandum Jan '96
|
|
* "A Kernel Model for Precision Timekeeping" by Dave Mills
|
|
*
|
|
* Linux/CRIS specific code:
|
|
*
|
|
* Authors: Bjorn Wesen
|
|
* Johan Adolfsson
|
|
*
|
|
*/
|
|
|
|
#include <asm/rtc.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/module.h>
|
|
#include <linux/param.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/bcd.h>
|
|
#include <linux/timex.h>
|
|
#include <linux/init.h>
|
|
#include <linux/profile.h>
|
|
#include <linux/sched.h> /* just for sched_clock() - funny that */
|
|
|
|
int have_rtc; /* used to remember if we have an RTC or not */;
|
|
|
|
#define TICK_SIZE tick
|
|
|
|
extern unsigned long loops_per_jiffy; /* init/main.c */
|
|
unsigned long loops_per_usec;
|
|
|
|
extern unsigned long do_slow_gettimeoffset(void);
|
|
static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
|
|
|
|
/*
|
|
* This version of gettimeofday has near microsecond resolution.
|
|
*
|
|
* Note: Division is quite slow on CRIS and do_gettimeofday is called
|
|
* rather often. Maybe we should do some kind of approximation here
|
|
* (a naive approximation would be to divide by 1024).
|
|
*/
|
|
void do_gettimeofday(struct timeval *tv)
|
|
{
|
|
unsigned long flags;
|
|
signed long usec, sec;
|
|
local_irq_save(flags);
|
|
local_irq_disable();
|
|
usec = do_gettimeoffset();
|
|
|
|
/*
|
|
* If time_adjust is negative then NTP is slowing the clock
|
|
* so make sure not to go into next possible interval.
|
|
* Better to lose some accuracy than have time go backwards..
|
|
*/
|
|
if (unlikely(time_adjust < 0) && usec > tickadj)
|
|
usec = tickadj;
|
|
|
|
sec = xtime.tv_sec;
|
|
usec += xtime.tv_nsec / 1000;
|
|
local_irq_restore(flags);
|
|
|
|
while (usec >= 1000000) {
|
|
usec -= 1000000;
|
|
sec++;
|
|
}
|
|
|
|
tv->tv_sec = sec;
|
|
tv->tv_usec = usec;
|
|
}
|
|
|
|
EXPORT_SYMBOL(do_gettimeofday);
|
|
|
|
int do_settimeofday(struct timespec *tv)
|
|
{
|
|
time_t wtm_sec, sec = tv->tv_sec;
|
|
long wtm_nsec, nsec = tv->tv_nsec;
|
|
|
|
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
|
|
return -EINVAL;
|
|
|
|
write_seqlock_irq(&xtime_lock);
|
|
/*
|
|
* This is revolting. We need to set "xtime" correctly. However, the
|
|
* value in this location is the value at the most recent update of
|
|
* wall time. Discover what correction gettimeofday() would have
|
|
* made, and then undo it!
|
|
*/
|
|
nsec -= do_gettimeoffset() * NSEC_PER_USEC;
|
|
|
|
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
|
|
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
|
|
|
|
set_normalized_timespec(&xtime, sec, nsec);
|
|
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
|
|
|
|
ntp_clear();
|
|
write_sequnlock_irq(&xtime_lock);
|
|
clock_was_set();
|
|
return 0;
|
|
}
|
|
|
|
EXPORT_SYMBOL(do_settimeofday);
|
|
|
|
|
|
/*
|
|
* BUG: This routine does not handle hour overflow properly; it just
|
|
* sets the minutes. Usually you'll only notice that after reboot!
|
|
*/
|
|
|
|
int set_rtc_mmss(unsigned long nowtime)
|
|
{
|
|
int retval = 0;
|
|
int real_seconds, real_minutes, cmos_minutes;
|
|
|
|
printk(KERN_DEBUG "set_rtc_mmss(%lu)\n", nowtime);
|
|
|
|
if(!have_rtc)
|
|
return 0;
|
|
|
|
cmos_minutes = CMOS_READ(RTC_MINUTES);
|
|
BCD_TO_BIN(cmos_minutes);
|
|
|
|
/*
|
|
* since we're only adjusting minutes and seconds,
|
|
* don't interfere with hour overflow. This avoids
|
|
* messing with unknown time zones but requires your
|
|
* RTC not to be off by more than 15 minutes
|
|
*/
|
|
real_seconds = nowtime % 60;
|
|
real_minutes = nowtime / 60;
|
|
if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
|
|
real_minutes += 30; /* correct for half hour time zone */
|
|
real_minutes %= 60;
|
|
|
|
if (abs(real_minutes - cmos_minutes) < 30) {
|
|
BIN_TO_BCD(real_seconds);
|
|
BIN_TO_BCD(real_minutes);
|
|
CMOS_WRITE(real_seconds,RTC_SECONDS);
|
|
CMOS_WRITE(real_minutes,RTC_MINUTES);
|
|
} else {
|
|
printk(KERN_WARNING
|
|
"set_rtc_mmss: can't update from %d to %d\n",
|
|
cmos_minutes, real_minutes);
|
|
retval = -1;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/* grab the time from the RTC chip */
|
|
|
|
unsigned long
|
|
get_cmos_time(void)
|
|
{
|
|
unsigned int year, mon, day, hour, min, sec;
|
|
|
|
sec = CMOS_READ(RTC_SECONDS);
|
|
min = CMOS_READ(RTC_MINUTES);
|
|
hour = CMOS_READ(RTC_HOURS);
|
|
day = CMOS_READ(RTC_DAY_OF_MONTH);
|
|
mon = CMOS_READ(RTC_MONTH);
|
|
year = CMOS_READ(RTC_YEAR);
|
|
|
|
printk(KERN_DEBUG
|
|
"rtc: sec 0x%x min 0x%x hour 0x%x day 0x%x mon 0x%x year 0x%x\n",
|
|
sec, min, hour, day, mon, year);
|
|
|
|
BCD_TO_BIN(sec);
|
|
BCD_TO_BIN(min);
|
|
BCD_TO_BIN(hour);
|
|
BCD_TO_BIN(day);
|
|
BCD_TO_BIN(mon);
|
|
BCD_TO_BIN(year);
|
|
|
|
if ((year += 1900) < 1970)
|
|
year += 100;
|
|
|
|
return mktime(year, mon, day, hour, min, sec);
|
|
}
|
|
|
|
/* update xtime from the CMOS settings. used when /dev/rtc gets a SET_TIME.
|
|
* TODO: this doesn't reset the fancy NTP phase stuff as do_settimeofday does.
|
|
*/
|
|
|
|
void
|
|
update_xtime_from_cmos(void)
|
|
{
|
|
if(have_rtc) {
|
|
xtime.tv_sec = get_cmos_time();
|
|
xtime.tv_nsec = 0;
|
|
}
|
|
}
|
|
|
|
extern void cris_profile_sample(struct pt_regs* regs);
|
|
|
|
void
|
|
cris_do_profile(struct pt_regs* regs)
|
|
{
|
|
|
|
#if CONFIG_SYSTEM_PROFILER
|
|
cris_profile_sample(regs);
|
|
#endif
|
|
|
|
#if CONFIG_PROFILING
|
|
profile_tick(CPU_PROFILING, regs);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Scheduler clock - returns current time in nanosec units.
|
|
*/
|
|
unsigned long long sched_clock(void)
|
|
{
|
|
return (unsigned long long)jiffies * (1000000000 / HZ);
|
|
}
|
|
|
|
static int
|
|
__init init_udelay(void)
|
|
{
|
|
loops_per_usec = (loops_per_jiffy * HZ) / 1000000;
|
|
return 0;
|
|
}
|
|
|
|
__initcall(init_udelay);
|