ia64/xen-unstable

view extras/mini-os/arch/ia64/time.c @ 13907:ac18d251df63

[IA64][MINIOS] Port of mini-os to ia64

ia64 specific parts of mini-os.

Minimal config:

# Kernel image file.
kernel = "mini-os.gz"
# Initial memory allocation (in megabytes) for the new domain.
memory = 64
# A name for your domain.
name = "Mini-OS"

Signed-off-by: Dietmar Hahn <dietmar.hahn@fujitsu-siemens.com>
author awilliam@xenbuild2.aw
date Thu Feb 15 13:13:36 2007 -0700 (2007-02-15)
parents
children e40015e20548
line source
1 /*
2 * Done by Dietmar Hahn <dietmar.hahn@fujitsu-siemens.com>
3 * Description: simple ia64 specific time handling
4 * mktime() is taken from Linux (see copyright below)
5 * Parts are taken from FreeBSD.
6 *
7 ****************************************************************************
8 * For the copy of the mktime() from linux.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 ****************************************************************************
24 *
25 * Redistribution and use in source and binary forms, with or without
26 * modification, are permitted provided that the following conditions
27 * are met:
28 * 1. Redistributions of source code must retain the above copyright
29 * notice, this list of conditions and the following disclaimer.
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the distribution.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 */
47 #include "os.h"
48 #include "console.h"
49 #include "time.h"
50 #include "efi.h"
51 #include "events.h"
53 struct timespec os_time;
54 static uint64_t itc_alt; /* itc on last update. */
55 static uint64_t itc_at_boot; /* itc on boot */
56 static uint64_t itc_frequency;
57 static uint64_t processor_frequency;
58 static uint64_t itm_val;
61 /*
62 * mktime() is take from Linux. See copyright above.
63 * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
64 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
65 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
66 *
67 * [For the Julian calendar (which was used in Russia before 1917,
68 * Britain & colonies before 1752, anywhere else before 1582,
69 * and is still in use by some communities) leave out the
70 * -year/100+year/400 terms, and add 10.]
71 *
72 * This algorithm was first published by Gauss (I think).
73 *
74 * WARNING: this function will overflow on 2106-02-07 06:28:16 on
75 * machines were long is 32-bit! (However, as time_t is signed, we
76 * will already get problems at other places on 2038-01-19 03:14:08)
77 */
78 static unsigned long
79 mktime(const unsigned int year0, const unsigned int mon0,
80 const unsigned int day, const unsigned int hour,
81 const unsigned int min, const unsigned int sec)
82 {
83 unsigned int mon = mon0, year = year0;
85 /* 1..12 -> 11,12,1..10 */
86 if (0 >= (int) (mon -= 2)) {
87 mon += 12; /* Puts Feb last since it has leap day */
88 year -= 1;
89 }
91 return (
92 (
93 ((unsigned long)
94 (year/4 - year/100 + year/400 + 367*mon/12 + day) +
95 year*365 - 719499
96 ) * 24 + hour /* now have hours */
97 ) * 60 + min /* now have minutes */
98 ) * 60 + sec; /* finally seconds */
99 }
101 static inline uint64_t
102 ns_from_cycles(uint64_t cycles)
103 {
104 return (cycles * (1000000000 / itc_frequency));
105 }
107 static inline uint64_t
108 ns_to_cycles(uint64_t ns)
109 {
110 return (ns * (itc_frequency / 1000000000));
111 }
113 /*
114 * Block the domain until until(nanoseconds) is over.
115 * If block is called no timerinterrupts are delivered from xen!
116 */
117 void
118 block_domain(s_time_t until)
119 {
120 struct ia64_pal_result pal_res;
121 uint64_t c, new;
123 c = ns_to_cycles(until);
124 new = ia64_get_itc() + c - NOW();
125 ia64_set_itm(new); /* Reload cr.itm */
126 /*
127 * PAL_HALT_LIGHT returns on every external interrupt,
128 * including timer interrupts.
129 */
130 pal_res = ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0);
131 if (pal_res.pal_status != 0)
132 printk("%s: PAL_HALT_LIGHT returns an error\n");
133 /* Reload the normal timer interrupt match. */
134 new = ia64_get_itc() + itm_val;
135 ia64_set_itm(new);
136 }
138 static void
139 calculate_time(void)
140 {
141 uint64_t itc_new, new;
143 itc_new = ia64_get_itc();
144 if (itc_new < itc_alt)
145 new = ~0 - itc_alt + itc_new;
146 else
147 new = itc_new - itc_alt;
148 itc_alt = itc_new;
149 new = ns_from_cycles(new);
150 os_time.ts_nsec += new;
151 if (os_time.ts_nsec > 1000000000) { /* On overflow. */
152 os_time.ts_sec++;
153 os_time.ts_nsec -= 1000000000;
154 }
155 }
157 void
158 timer_interrupt(evtchn_port_t port, struct pt_regs* regsP, void *data)
159 {
160 uint64_t new;
162 calculate_time();
163 new = ia64_get_itc() + itm_val;
164 ia64_set_itm(new);
165 }
167 /*
168 * monotonic_clock(): returns # of nanoseconds passed since time_init()
169 */
170 u64
171 monotonic_clock(void)
172 {
173 uint64_t delta;
175 delta = ia64_get_itc() - itc_at_boot;
176 delta = ns_from_cycles(delta);
177 return delta;
178 }
180 void
181 gettimeofday(struct timeval *tv)
182 {
183 calculate_time();
184 tv->tv_sec = os_time.ts_sec; /* seconds */
185 tv->tv_usec = NSEC_TO_USEC(os_time.ts_nsec); /* microseconds */
186 };
188 /*
189 * Read the clock frequencies from pal and sal for calculating
190 * the clock interrupt.
191 */
192 static void
193 calculate_frequencies(void)
194 {
195 struct ia64_sal_result sal_res;
196 struct ia64_pal_result pal_res;
198 pal_res = ia64_call_pal_static(PAL_FREQ_RATIOS, 0, 0, 0);
199 //sal_res = ia64_sal_call(SAL_FREQ_BASE, 0, 0, 0, 0, 0, 0, 0);
200 #if defined(BIG_ENDIAN)
201 //#warning calculate_frequencies TODO
202 /*
203 * I have to do an own function with switching psr.be!
204 * Currently it's running because it's a break into the hypervisor
205 * behind the call.!
206 */
207 #endif
208 sal_res = ia64_sal_entry(SAL_FREQ_BASE, 0, 0, 0, 0, 0, 0, 0);
210 if (sal_res.sal_status == 0 && pal_res.pal_status == 0) {
211 processor_frequency =
212 sal_res.sal_result[0] * (pal_res.pal_result[0] >> 32)
213 / (pal_res.pal_result[0] & ((1L << 32) - 1));
214 itc_frequency =
215 sal_res.sal_result[0] * (pal_res.pal_result[2] >> 32)
216 / (pal_res.pal_result[2] & ((1L << 32) - 1));
217 PRINT_BV("Reading clock frequencies:\n");
218 PRINT_BV(" Platform clock frequency %ld Hz\n",
219 sal_res.sal_result[0]);
220 PRINT_BV(" Processor ratio %ld/%ld, Bus ratio %ld/%ld, "
221 " ITC ratio %ld/%ld\n",
222 pal_res.pal_result[0] >> 32,
223 pal_res.pal_result[0] & ((1L << 32) - 1),
224 pal_res.pal_result[1] >> 32,
225 pal_res.pal_result[1] & ((1L << 32) - 1),
226 pal_res.pal_result[2] >> 32,
227 pal_res.pal_result[2] & ((1L << 32) - 1));
229 printk(" ITC frequency %ld\n", itc_frequency);
230 } else {
231 itc_frequency = 1000000000;
232 processor_frequency = 0;
233 printk("Reading clock frequencies failed!!! Using: %ld\n",
234 itc_frequency);
235 }
236 }
239 //#define HZ 1
240 #define HZ 1000 // 1000 clock ticks per sec
241 #define IA64_TIMER_VECTOR 0xef
243 void
244 init_time(void)
245 {
246 uint64_t new;
247 efi_time_t tm;
248 int err = 0;
250 printk("Initialising time\n");
251 calculate_frequencies();
253 itm_val = (itc_frequency + HZ/2) / HZ;
254 printk(" itm_val: %ld\n", itm_val);
256 os_time.ts_sec = 0;
257 os_time.ts_nsec = 0;
259 if (efi_get_time(&tm)) {
260 printk(" EFI-Time: %d.%d.%d %d:%d:%d\n", tm.Day,
261 tm.Month, tm.Year, tm.Hour, tm.Minute, tm.Second);
262 os_time.ts_sec = mktime(SWAP(tm.Year), SWAP(tm.Month),
263 SWAP(tm.Day), SWAP(tm.Hour),
264 SWAP(tm.Minute), SWAP(tm.Second));
265 os_time.ts_nsec = tm.Nanosecond;
266 } else
267 printk("efi_get_time() failed\n");
269 err = bind_virq(VIRQ_ITC, timer_interrupt, NULL);
270 if (err != 0) {
271 printk("XEN timer request chn bind failed %i\n", err);
272 return;
273 }
274 itc_alt = ia64_get_itc();
275 itc_at_boot = itc_alt;
276 new = ia64_get_itc() + itm_val;
277 ia64_set_itv(IA64_TIMER_VECTOR);
278 ia64_set_itm(new);
279 ia64_srlz_d();
280 }