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 | /* * linux/arch/arm/kernel/time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds * Modifications for ARM (C) 1994-2001 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * 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/module.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 <linux/timex.h> #include <linux/errno.h> #include <asm/hardware.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/leds.h> u64 jiffies_64; extern rwlock_t xtime_lock; extern unsigned long wall_jiffies; /* this needs a better home */ spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; #ifdef CONFIG_SA1100_RTC_MODULE EXPORT_SYMBOL(rtc_lock); #endif /* 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. Note that it is * always called with interrupts disabled. */ unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset; /* * 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 static void dummy_leds_event(led_event_t evt) { } void (*leds_event)(led_event_t) = dummy_leds_event; EXPORT_SYMBOL(leds_event); #endif #ifdef CONFIG_LEDS_TIMER static void do_leds(void) { static unsigned int count = 50; if (--count == 0) { count = 50; leds_event(led_timer); } } #else #define do_leds() #endif void do_gettimeofday(struct timeval *tv) { unsigned long flags; unsigned long usec, sec, lost; read_lock_irqsave(&xtime_lock, flags); usec = gettimeoffset(); lost = jiffies - wall_jiffies; if (lost) usec += lost * USECS_PER_JIFFY; sec = xtime.tv_sec; usec += xtime.tv_usec; read_unlock_irqrestore(&xtime_lock, flags); /* usec may have gone up a lot: be safe */ while (usec >= 1000000) { usec -= 1000000; sec++; } tv->tv_sec = sec; tv->tv_usec = usec; } void do_settimeofday(struct timeval *tv) { write_lock_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 * done, and then undo it! */ tv->tv_usec -= gettimeoffset(); tv->tv_usec -= (jiffies - wall_jiffies) * USECS_PER_JIFFY; while (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; write_unlock_irq(&xtime_lock); } static struct irqaction timer_irq = { .name = "timer", }; /* * Include architecture specific code */ #include <asm/arch/time.h> |