ia64/xen-unstable
changeset 561:faa66eccb6f3
bitkeeper revision 1.259.2.5 (3f0be04e_JN3KEqwAUTHcvXxNP01LQ)
Merge ssh://rn212@shep.cl.cam.ac.uk//usr/groups/xeno/users/rn212/xeno.time
into wyvis.research.intel-research.net:/home/irchomes/rneugeba/src/xeno/xeno.time
Merge ssh://rn212@shep.cl.cam.ac.uk//usr/groups/xeno/users/rn212/xeno.time
into wyvis.research.intel-research.net:/home/irchomes/rneugeba/src/xeno/xeno.time
author | rneugeba@wyvis.research.intel-research.net |
---|---|
date | Wed Jul 09 09:28:46 2003 +0000 (2003-07-09) |
parents | e381bd125a43 e5bf251a865f |
children | 7dd26f39dacb |
files | BitKeeper/etc/logging_ok xen/arch/i386/time.c |
line diff
1.1 --- a/BitKeeper/etc/logging_ok Tue Jul 08 14:40:18 2003 +0000 1.2 +++ b/BitKeeper/etc/logging_ok Wed Jul 09 09:28:46 2003 +0000 1.3 @@ -18,6 +18,7 @@ lynx@idefix.cl.cam.ac.uk 1.4 rgr22@boulderdash.cl.cam.ac.uk 1.5 rn@wyvis.camb.intel-research.net 1.6 rn@wyvis.research.intel-research.net 1.7 +rneugeba@wyvis.research.intel-research.net 1.8 smh22@boulderdash.cl.cam.ac.uk 1.9 smh22@labyrinth.cl.cam.ac.uk 1.10 smh22@uridium.cl.cam.ac.uk
2.1 --- a/xen/arch/i386/time.c Tue Jul 08 14:40:18 2003 +0000 2.2 +++ b/xen/arch/i386/time.c Wed Jul 09 09:28:46 2003 +0000 2.3 @@ -185,11 +185,41 @@ mktime (unsigned int year, unsigned int 2.4 )*60 + sec; /* finally seconds */ 2.5 } 2.6 2.7 -static unsigned long get_cmos_time(void) 2.8 +static unsigned long __get_cmos_time(void) 2.9 { 2.10 unsigned int year, mon, day, hour, min, sec; 2.11 + /* Linux waits here for a the Update-In-Progress (UIP) flag going 2.12 + * from 1 to 0. This can take up to a second. This is not acceptable 2.13 + * for the use in Xen and this code is therfor removed at the cost 2.14 + * of reduced accuracy. */ 2.15 + sec = CMOS_READ(RTC_SECONDS); 2.16 + min = CMOS_READ(RTC_MINUTES); 2.17 + hour = CMOS_READ(RTC_HOURS); 2.18 + day = CMOS_READ(RTC_DAY_OF_MONTH); 2.19 + mon = CMOS_READ(RTC_MONTH); 2.20 + year = CMOS_READ(RTC_YEAR); 2.21 + 2.22 + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) 2.23 + { 2.24 + BCD_TO_BIN(sec); 2.25 + BCD_TO_BIN(min); 2.26 + BCD_TO_BIN(hour); 2.27 + BCD_TO_BIN(day); 2.28 + BCD_TO_BIN(mon); 2.29 + BCD_TO_BIN(year); 2.30 + } 2.31 + 2.32 + if ((year += 1900) < 1970) 2.33 + year += 100; 2.34 + 2.35 + return mktime(year, mon, day, hour, min, sec); 2.36 +} 2.37 + 2.38 +/* the more accurate version waits for a change */ 2.39 +static unsigned long get_cmos_time(void) 2.40 +{ 2.41 + unsigned long res; 2.42 int i; 2.43 - 2.44 spin_lock(&rtc_lock); 2.45 /* The Linux interpretation of the CMOS clock register contents: 2.46 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the 2.47 @@ -203,29 +233,10 @@ static unsigned long get_cmos_time(void) 2.48 for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ 2.49 if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) 2.50 break; 2.51 - do { /* Isn't this overkill ? UIP above should guarantee consistency */ 2.52 - sec = CMOS_READ(RTC_SECONDS); 2.53 - min = CMOS_READ(RTC_MINUTES); 2.54 - hour = CMOS_READ(RTC_HOURS); 2.55 - day = CMOS_READ(RTC_DAY_OF_MONTH); 2.56 - mon = CMOS_READ(RTC_MONTH); 2.57 - year = CMOS_READ(RTC_YEAR); 2.58 - } while (sec != CMOS_READ(RTC_SECONDS)); 2.59 - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) 2.60 - { 2.61 - BCD_TO_BIN(sec); 2.62 - BCD_TO_BIN(min); 2.63 - BCD_TO_BIN(hour); 2.64 - BCD_TO_BIN(day); 2.65 - BCD_TO_BIN(mon); 2.66 - BCD_TO_BIN(year); 2.67 - } 2.68 + res = __get_cmos_time(); 2.69 spin_unlock(&rtc_lock); 2.70 - if ((year += 1900) < 1970) 2.71 - year += 100; 2.72 - printk(".... CMOS Clock: %02d/%02d/%04d %02d:%02d:%02d\n", 2.73 - day, mon, year, hour, min, sec); 2.74 - return mktime(year, mon, day, hour, min, sec); 2.75 + return res; 2.76 + 2.77 } 2.78 2.79 /*************************************************************************** 2.80 @@ -368,6 +379,64 @@ static void update_time(unsigned long fo 2.81 add_ac_timer(&update_timer); 2.82 } 2.83 2.84 + 2.85 +/* 2.86 + * VERY crude way to keep system time from drfiting. 2.87 + * Update the scaling factor using the RTC 2.88 + * This is done periodically of it's own timer 2.89 + * We maintain an array of cpu frequencies. 2.90 + * - index 0 -> go slower 2.91 + * - index 1 -> frequency as determined during calibration 2.92 + * - index 2 -> go faster 2.93 + */ 2.94 +#define UPDATE_PERIOD SECONDS(50) 2.95 +static struct ac_timer scale_timer; 2.96 +static unsigned long init_cmos_time; 2.97 +static u64 cpu_freqs[3]; 2.98 +static void update_scale(unsigned long foo) 2.99 +{ 2.100 + unsigned long flags; 2.101 + unsigned long cmos_time; 2.102 + s_time_t now; 2.103 + s32 st, ct, dt; 2.104 + u64 scale; 2.105 + int freq_index; 2.106 + 2.107 + spin_lock(&rtc_lock); 2.108 + cmos_time = __get_cmos_time(); 2.109 + spin_unlock(&rtc_lock); 2.110 + 2.111 + spin_lock_irqsave(&stime_lock, flags); 2.112 + now = __get_s_time(); 2.113 + 2.114 + ct = (cmos_time - init_cmos_time); 2.115 + st = (s32)(now/SECONDS(1)); 2.116 + dt = ct - st; 2.117 + 2.118 + /* work out adjustment to scaling factor. allow +/- 1s drift */ 2.119 + if (dt < -1) freq_index = 0; /* go slower */ 2.120 + else if (dt > 1) freq_index = 2; /* go faster */ 2.121 + else freq_index = 1; /* correct speed */ 2.122 + 2.123 + if (dt <= -10 || dt >= 10) 2.124 + printk("Large time drift (cmos time - system time = %ds)\n", dt); 2.125 + 2.126 + /* set new frequency */ 2.127 + cpu_freq = cpu_freqs[freq_index]; 2.128 + 2.129 + /* adjust scaling factor */ 2.130 + scale = 1000000000LL << 32; 2.131 + scale /= cpu_freq; 2.132 + st_scale_f = scale & 0xffffffff; 2.133 + st_scale_i = scale >> 32; 2.134 + 2.135 + spin_unlock_irqrestore(&stime_lock, flags); 2.136 + scale_timer.expires = now + UPDATE_PERIOD; 2.137 + add_ac_timer(&scale_timer); 2.138 + TRC(printk(" %ds[%d] ", dt, freq_index)); 2.139 +} 2.140 + 2.141 + 2.142 /*************************************************************************** 2.143 * Init Xeno Time 2.144 * This has to be done after all CPUs have been booted 2.145 @@ -376,7 +445,9 @@ int __init init_xeno_time() 2.146 { 2.147 int cpu = smp_processor_id(); 2.148 u32 cpu_cycle; /* time of one cpu cyle in pico-seconds */ 2.149 - u64 scale; /* scale factor */ 2.150 + u64 scale; /* scale factor */ 2.151 + s64 freq_off; 2.152 + 2.153 2.154 spin_lock_init(&stime_lock); 2.155 spin_lock_init(&wctime_lock); 2.156 @@ -385,15 +456,26 @@ int __init init_xeno_time() 2.157 2.158 /* System Time */ 2.159 cpu_cycle = (u32) (1000000000LL/cpu_khz); /* in pico seconds */ 2.160 + 2.161 scale = 1000000000LL << 32; 2.162 scale /= cpu_freq; 2.163 st_scale_f = scale & 0xffffffff; 2.164 st_scale_i = scale >> 32; 2.165 2.166 + 2.167 + /* calculate adjusted frequencies */ 2.168 + freq_off = cpu_freq/1000; /* .1% */ 2.169 + cpu_freqs[0] = cpu_freq + freq_off; 2.170 + cpu_freqs[1] = cpu_freq; 2.171 + cpu_freqs[2] = cpu_freq - freq_off; 2.172 + 2.173 /* Wall Clock time */ 2.174 wall_clock_time.tv_sec = get_cmos_time(); 2.175 wall_clock_time.tv_usec = 0; 2.176 2.177 + /* init cmos_time for synchronising */ 2.178 + init_cmos_time = wall_clock_time.tv_sec - 3; 2.179 + 2.180 /* set starting times */ 2.181 stime_now = (s_time_t)0; 2.182 rdtscl(stime_pcc); 2.183 @@ -404,12 +486,19 @@ int __init init_xeno_time() 2.184 update_timer.data = 1; 2.185 update_timer.function = &update_time; 2.186 update_time(0); 2.187 + 2.188 + init_ac_timer(&scale_timer, 0); 2.189 + scale_timer.data = 4; 2.190 + scale_timer.function = &update_scale; 2.191 + update_scale(0); 2.192 2.193 - printk(".... System Time: %lldns\n", NOW()); 2.194 - printk(".....cpu_cycle: %u ps\n", cpu_cycle); 2.195 - printk(".... st_scale_f: %X\n", st_scale_f); 2.196 - printk(".... st_scale_i: %X\n", st_scale_i); 2.197 - printk(".... stime_pcc: %u\n", stime_pcc); 2.198 + printk(".... System Time: %lldns\n", NOW()); 2.199 + printk(".....cpu_freq: %08X%08X\n", (u32)(cpu_freq>>32), (u32)cpu_freq); 2.200 + printk(".....cpu_cycle: %u ps\n", cpu_cycle); 2.201 + printk(".....scale: %08X%08X\n", (u32)(scale>>32), (u32)scale); 2.202 + printk(".... st_scale_f: %X\n", st_scale_f); 2.203 + printk(".... st_scale_i: %X\n", st_scale_i); 2.204 + printk(".... stime_pcc: %u\n", stime_pcc); 2.205 2.206 printk(".... Wall Clock: %lds %ldus\n", wall_clock_time.tv_sec, 2.207 wall_clock_time.tv_usec);