ia64/xen-unstable

view extras/mini-os/arch/ia64/time.c @ 19693:28c6c955998c

minios: Remove Linux attribution for mktime() as it's not true since c/s 19638.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jun 01 14:39:25 2009 +0100 (2009-06-01)
parents 9535ef2be909
children
line source
1 /*
2 * Done by Dietmar Hahn <dietmar.hahn@fujitsu-siemens.com>
3 * Description: simple ia64 specific time handling
4 * Parts are taken from FreeBSD.
5 *
6 ****************************************************************************
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
30 #include "os.h"
31 #include "console.h"
32 #include "time.h"
33 #include "efi.h"
34 #include "events.h"
36 struct timespec os_time;
37 static uint64_t itc_alt; /* itc on last update. */
38 static uint64_t itc_at_boot; /* itc on boot */
39 static uint64_t itc_frequency;
40 static uint64_t processor_frequency;
41 static uint64_t itm_val;
43 static int is_leap_year(int year)
44 {
45 if( year % 4 == 0 )
46 {
47 if( year % 100 == 0 )
48 {
49 if( year % 400 == 0 ) return 1;
50 else return 0;
51 }
52 return 1;
53 }
54 return 0;
55 }
57 static int count_leap_years(int epoch, int year)
58 {
59 int i, result = 0;
60 for( i = epoch ; i < year ; i++ ) if( is_leap_year(i) ) result++;
61 return result;
62 }
64 static int get_day(int year, int mon, int day) {
65 int result;
66 switch(mon)
67 {
68 case 0: result = 0; break;
69 case 1: result = 31; break; /* 1: 31 */
70 case 2: result = 59; break; /* 2: 31+28 */
71 case 3: result = 90; break; /* 3: 59+31 */
72 case 4: result = 120;break; /* 4: 90+30 */
73 case 5: result = 151;break; /* 5: 120+31 */
74 case 6: result = 181;break; /* 6: 151+30 */
75 case 7: result = 212;break; /* 7: 181+31 */
76 case 8: result = 243;break; /* 8: 212+31 */
77 case 9: result = 273;break; /* 9: 243+30 */
78 case 10:result = 304;break; /* 10:273+31 */
79 case 11:result = 334;break; /* 11:304+30 */
80 default: break;
81 }
82 if( is_leap_year(year) && mon > 2 ) result++;
83 result += day - 1;
84 return result;
85 }
87 /*
88 * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
89 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
90 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
91 *
92 * WARNING: this function will overflow on 2106-02-07 06:28:16 on
93 * machines were long is 32-bit! (However, as time_t is signed, we
94 * will already get problems at other places on 2038-01-19 03:14:08)
95 */
96 static unsigned long _mktime(const unsigned int year, const unsigned int mon,
97 const unsigned int day, const unsigned int hour,
98 const unsigned int min, const unsigned int sec)
99 {
100 unsigned long result = 0;
102 result = sec;
103 result += min * 60;
104 result += hour * 3600;
105 result += get_day(year, mon - 1, day) * 86400;
106 result += (year - 1970) * 31536000;
107 result += count_leap_years(1970, year) * 86400;
109 return result;
110 }
112 static inline uint64_t
113 ns_from_cycles(uint64_t cycles)
114 {
115 return (cycles * (1000000000 / itc_frequency));
116 }
118 static inline uint64_t
119 ns_to_cycles(uint64_t ns)
120 {
121 return (ns * (itc_frequency / 1000000000));
122 }
124 /*
125 * Block the domain until until(nanoseconds) is over.
126 * If block is called no timerinterrupts are delivered from xen!
127 */
128 void
129 block_domain(s_time_t until)
130 {
131 struct ia64_pal_result pal_res;
132 uint64_t c, new;
134 c = ns_to_cycles(until);
135 new = ia64_get_itc() + c - NOW();
136 ia64_set_itm(new); /* Reload cr.itm */
137 /*
138 * PAL_HALT_LIGHT returns on every external interrupt,
139 * including timer interrupts.
140 */
141 pal_res = ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0);
142 if (pal_res.pal_status != 0)
143 printk("%s: PAL_HALT_LIGHT returns an error\n");
144 /* Reload the normal timer interrupt match. */
145 new = ia64_get_itc() + itm_val;
146 ia64_set_itm(new);
147 }
149 static void
150 calculate_time(void)
151 {
152 uint64_t itc_new, new;
154 itc_new = ia64_get_itc();
155 if (itc_new < itc_alt)
156 new = ~0 - itc_alt + itc_new;
157 else
158 new = itc_new - itc_alt;
159 itc_alt = itc_new;
160 new = ns_from_cycles(new);
161 os_time.tv_nsec += new;
162 if (os_time.tv_nsec > 1000000000) { /* On overflow. */
163 os_time.tv_sec++;
164 os_time.tv_nsec -= 1000000000;
165 }
166 }
168 void
169 timer_interrupt(evtchn_port_t port, struct pt_regs* regsP, void *data)
170 {
171 uint64_t new;
173 calculate_time();
174 new = ia64_get_itc() + itm_val;
175 ia64_set_itm(new);
176 }
178 /*
179 * monotonic_clock(): returns # of nanoseconds passed since time_init()
180 */
181 u64
182 monotonic_clock(void)
183 {
184 uint64_t delta;
186 delta = ia64_get_itc() - itc_at_boot;
187 delta = ns_from_cycles(delta);
188 return delta;
189 }
191 int
192 gettimeofday(struct timeval *tv, void *tz)
193 {
194 calculate_time();
195 tv->tv_sec = os_time.tv_sec; /* seconds */
196 tv->tv_usec = NSEC_TO_USEC(os_time.tv_nsec); /* microseconds */
197 return 0;
198 };
200 /*
201 * Read the clock frequencies from pal and sal for calculating
202 * the clock interrupt.
203 */
204 static void
205 calculate_frequencies(void)
206 {
207 struct ia64_sal_result sal_res;
208 struct ia64_pal_result pal_res;
210 pal_res = ia64_call_pal_static(PAL_FREQ_RATIOS, 0, 0, 0);
211 sal_res = ia64_sal_entry(SAL_FREQ_BASE, 0, 0, 0, 0, 0, 0, 0);
213 if (sal_res.sal_status == 0 && pal_res.pal_status == 0) {
214 processor_frequency =
215 sal_res.sal_result[0] * (pal_res.pal_result[0] >> 32)
216 / (pal_res.pal_result[0] & ((1L << 32) - 1));
217 itc_frequency =
218 sal_res.sal_result[0] * (pal_res.pal_result[2] >> 32)
219 / (pal_res.pal_result[2] & ((1L << 32) - 1));
220 PRINT_BV("Reading clock frequencies:\n");
221 PRINT_BV(" Platform clock frequency %ld Hz\n",
222 sal_res.sal_result[0]);
223 PRINT_BV(" Processor ratio %ld/%ld, Bus ratio %ld/%ld, "
224 " ITC ratio %ld/%ld\n",
225 pal_res.pal_result[0] >> 32,
226 pal_res.pal_result[0] & ((1L << 32) - 1),
227 pal_res.pal_result[1] >> 32,
228 pal_res.pal_result[1] & ((1L << 32) - 1),
229 pal_res.pal_result[2] >> 32,
230 pal_res.pal_result[2] & ((1L << 32) - 1));
232 printk(" ITC frequency %ld\n", itc_frequency);
233 } else {
234 itc_frequency = 1000000000;
235 processor_frequency = 0;
236 printk("Reading clock frequencies failed!!! Using: %ld\n",
237 itc_frequency);
238 }
239 }
242 //#define HZ 1
243 #define HZ 1000 // 1000 clock ticks per sec
244 #define IA64_TIMER_VECTOR 0xef
246 void
247 init_time(void)
248 {
249 uint64_t new;
250 efi_time_t tm;
251 evtchn_port_t port = 0;
253 printk("Initialising time\n");
254 calculate_frequencies();
256 itm_val = (itc_frequency + HZ/2) / HZ;
257 printk(" itm_val: %ld\n", itm_val);
259 os_time.tv_sec = 0;
260 os_time.tv_nsec = 0;
262 if (efi_get_time(&tm)) {
263 printk(" EFI-Time: %d.%d.%d %d:%d:%d\n", tm.Day,
264 tm.Month, tm.Year, tm.Hour, tm.Minute, tm.Second);
265 os_time.tv_sec = _mktime(tm.Year, tm.Month,
266 tm.Day, tm.Hour, tm.Minute, tm.Second);
267 os_time.tv_nsec = tm.Nanosecond;
268 } else
269 printk("efi_get_time() failed\n");
271 port = bind_virq(VIRQ_ITC, timer_interrupt, NULL);
272 if (port == -1) {
273 printk("XEN timer request chn bind failed %i\n", port);
274 return;
275 }
276 unmask_evtchn(port);
277 itc_alt = ia64_get_itc();
278 itc_at_boot = itc_alt;
279 new = ia64_get_itc() + itm_val;
280 ia64_set_itv(IA64_TIMER_VECTOR);
281 ia64_set_itm(new);
282 ia64_srlz_d();
283 }
285 void
286 fini_time(void)
287 {
288 /* TODO */
289 }