Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | /* * linux/arch/arm/kernel/time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds * Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King * * This file contains the ARM-specific time handling details: * reading the RTC at bootup, etc... * * 1994-07-02 Alan Modra * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime * 1998-12-20 Updated NTP code according to technical memorandum Jan '96 * "A Kernel Model for Precision Timekeeping" by Dave Mills */ #include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/time.h> #include <linux/init.h> #include <linux/smp.h> #include <asm/uaccess.h> #include <asm/io.h> #include <asm/irq.h> #include <linux/timex.h> #include <asm/hardware.h> extern int setup_arm_irq(int, struct irqaction *); extern void setup_timer(void); extern volatile unsigned long lost_ticks; /* change this if you have some constant time drift */ #define USECS_PER_JIFFY (1000000/HZ) #ifndef BCD_TO_BIN #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) #endif #ifndef BIN_TO_BCD #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) #endif static int dummy_set_rtc(void) { return 0; } /* * hook for setting the RTC's idea of the current time. */ int (*set_rtc)(void) = dummy_set_rtc; static unsigned long dummy_gettimeoffset(void) { return 0; } /* * hook for getting the time offset */ unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset; /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. * * [For the Julian calendar (which was used in Russia before 1917, * Britain & colonies before 1752, anywhere else before 1582, * and is still in use by some communities) leave out the * -year/100+year/400 terms, and add 10.] * * This algorithm was first published by Gauss (I think). * * WARNING: this function will overflow on 2106-02-07 06:28:16 on * machines were long is 32-bit! (However, as time_t is signed, we * will already get problems at other places on 2038-01-19 03:14:08) */ unsigned long mktime(unsigned int year, unsigned int mon, unsigned int day, unsigned int hour, unsigned int min, unsigned int sec) { if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ mon += 12; /* Puts Feb last since it has leap day */ year -= 1; } return ((( (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + year*365 - 719499 )*24 + hour /* now have hours */ )*60 + min /* now have minutes */ )*60 + sec; /* finally seconds */ } /* * Handle kernel profile stuff... */ static inline void do_profile(struct pt_regs *regs) { if (!user_mode(regs) && prof_buffer && current->pid) { unsigned long pc = instruction_pointer(regs); extern int _stext; pc -= (unsigned long)&_stext; pc >>= prof_shift; if (pc >= prof_len) pc = prof_len - 1; prof_buffer[pc] += 1; } } static long next_rtc_update; /* * If we have an externally synchronized linux clock, then update * CMOS clock accordingly every ~11 minutes. set_rtc() has to be * called as close as possible to 500 ms before the new second * starts. */ static inline void do_set_rtc(void) { if (time_status & STA_UNSYNC || set_rtc == NULL) return; if (next_rtc_update && time_before(xtime.tv_sec, next_rtc_update)) return; if (xtime.tv_usec < 50000 - (tick >> 1) && xtime.tv_usec >= 50000 + (tick >> 1)) return; if (set_rtc()) /* * rtc update failed. Try again in 60s */ next_rtc_update = xtime.tv_sec + 60; else next_rtc_update = xtime.tv_sec + 660; } #ifdef CONFIG_LEDS #include <asm/leds.h> static void do_leds(void) { static unsigned int count = 50; static int last_pid; if (current->pid != last_pid) { last_pid = current->pid; if (last_pid) leds_event(led_idle_end); else leds_event(led_idle_start); } if (--count == 0) { count = 50; leds_event(led_timer); } } #else #define do_leds() #endif void do_gettimeofday(struct timeval *tv) { unsigned long flags; save_flags_cli (flags); *tv = xtime; tv->tv_usec += gettimeoffset(); /* * xtime is atomically updated in timer_bh. lost_ticks is * nonzero if the timer bottom half hasnt executed yet. */ if (lost_ticks) tv->tv_usec += USECS_PER_JIFFY; restore_flags(flags); if (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; tv->tv_sec++; } } void do_settimeofday(struct timeval *tv) { cli (); /* This is revolting. We need to set the xtime.tv_usec * correctly. However, the value in this location is * is value at the last tick. * Discover what correction gettimeofday * would have done, and then undo it! */ tv->tv_usec -= gettimeoffset(); if (tv->tv_usec < 0) { tv->tv_usec += 1000000; tv->tv_sec--; } xtime = *tv; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; sti(); } static struct irqaction timer_irq = { NULL, 0, 0, "timer", NULL, NULL }; /* * Include architecture specific code */ #include <asm/arch/time.h> /* * This must cause the timer to start ticking. * It doesn't have to set the current time though * from an RTC - it can be done later once we have * some buses initialised. */ void __init time_init(void) { xtime.tv_usec = 0; xtime.tv_sec = 0; setup_timer(); } |