source: trunk/packages/xen-3.1/xen-3.1/extras/mini-os/arch/ia64/time.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 8.3 KB
Line 
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 */
46
47#include "os.h"
48#include "console.h"
49#include "time.h"
50#include "efi.h"
51#include "events.h"
52
53struct timespec os_time;
54static uint64_t itc_alt;                /* itc on last update. */
55static uint64_t itc_at_boot;            /* itc on boot */
56static uint64_t itc_frequency;
57static uint64_t processor_frequency;
58static uint64_t itm_val;
59
60
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 */
78static unsigned long
79mktime(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;
84
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        }
90
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}
100
101static inline uint64_t
102ns_from_cycles(uint64_t cycles)
103{
104        return (cycles * (1000000000 / itc_frequency));
105}
106
107static inline uint64_t
108ns_to_cycles(uint64_t ns)
109{
110        return (ns * (itc_frequency / 1000000000));
111}
112
113/*
114 * Block the domain until until(nanoseconds) is over.
115 * If block is called no timerinterrupts are delivered from xen!
116 */
117void
118block_domain(s_time_t until)
119{
120        struct ia64_pal_result pal_res;
121        uint64_t c, new;
122
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}
137
138static void
139calculate_time(void)
140{
141        uint64_t itc_new, new;
142
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}
156
157void
158timer_interrupt(evtchn_port_t port, struct pt_regs* regsP, void *data)
159{
160        uint64_t new;
161
162        calculate_time();
163        new = ia64_get_itc() + itm_val;
164        ia64_set_itm(new);
165}
166
167/*
168 * monotonic_clock(): returns # of nanoseconds passed since time_init()
169 */
170u64
171monotonic_clock(void)
172{
173        uint64_t delta;
174
175        delta = ia64_get_itc() - itc_at_boot;
176        delta = ns_from_cycles(delta);
177        return delta;
178}
179
180void
181gettimeofday(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};
187
188/*
189 * Read the clock frequencies from pal and sal for calculating
190 * the clock interrupt.
191 */
192static void
193calculate_frequencies(void)
194{
195        struct ia64_sal_result sal_res;
196        struct ia64_pal_result pal_res;
197
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);
209
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));
228
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}
237
238
239//#define HZ 1
240#define HZ 1000         // 1000 clock ticks per sec
241#define IA64_TIMER_VECTOR 0xef
242
243void
244init_time(void)
245{
246        uint64_t new;
247        efi_time_t tm;
248        int err = 0;
249
250        printk("Initialising time\n");
251        calculate_frequencies();
252
253        itm_val = (itc_frequency + HZ/2) / HZ;
254        printk("  itm_val: %ld\n", itm_val);
255
256        os_time.ts_sec = 0;
257        os_time.ts_nsec = 0;
258
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");
268
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}
Note: See TracBrowser for help on using the repository browser.