]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/ia64/ia64/clock.c
This commit was generated by cvs2svn to compensate for changes in r169689,
[FreeBSD/FreeBSD.git] / sys / ia64 / ia64 / clock.c
1 /*-
2  * Copyright (c) 2005 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/clock.h>
33 #include <sys/queue.h>
34 #include <sys/sysctl.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37 #include <sys/clock.h>
38 #include <sys/timetc.h>
39 #include <sys/pcpu.h>
40
41 #include <machine/clock.h>
42 #include <machine/cpu.h>
43 #include <machine/efi.h>
44
45 uint64_t ia64_clock_reload;
46
47 static int clock_initialized = 0;
48
49 #ifndef SMP
50 static timecounter_get_t ia64_get_timecount;
51
52 static struct timecounter ia64_timecounter = {
53         ia64_get_timecount,     /* get_timecount */
54         0,                      /* no poll_pps */
55         ~0u,                    /* counter_mask */
56         0,                      /* frequency */
57         "ITC"                   /* name */
58 };
59
60 static unsigned
61 ia64_get_timecount(struct timecounter* tc)
62 {
63         return ia64_get_itc();
64 }
65 #endif
66
67 void
68 pcpu_initclock(void)
69 {
70
71         PCPU_SET(clockadj, 0);
72         PCPU_SET(clock, ia64_get_itc());
73         ia64_set_itm(PCPU_GET(clock) + ia64_clock_reload);
74         ia64_set_itv(CLOCK_VECTOR);     /* highest priority class */
75 }
76
77 /*
78  * Start the real-time and statistics clocks. We use cr.itc and cr.itm
79  * to implement a 1000hz clock.
80  */
81 void
82 cpu_initclocks()
83 {
84
85         if (itc_frequency == 0)
86                 panic("Unknown clock frequency");
87
88         stathz = hz;
89         ia64_clock_reload = (itc_frequency + hz/2) / hz;
90
91 #ifndef SMP
92         ia64_timecounter.tc_frequency = itc_frequency;
93         tc_init(&ia64_timecounter);
94 #endif
95
96         pcpu_initclock();
97 }
98
99 void
100 cpu_startprofclock(void)
101 {
102
103         /* nothing to do */
104 }
105
106 void
107 cpu_stopprofclock(void)
108 {
109
110         /* nothing to do */
111 }
112
113 void
114 inittodr(time_t base)
115 {
116         long days;
117         struct efi_tm tm;
118         struct timespec ts;
119         struct clocktime ct;
120
121         efi_get_time(&tm);
122
123         /*
124          * This code was written in 2005, so logically EFI cannot return
125          * a year smaller than that. Assume the EFI clock is out of whack
126          * in that case and reset the EFI clock.
127          */
128         if (tm.tm_year < 2005) {
129                 printf("WARNING: CHECK AND RESET THE DATE!\n");
130                 memset(&tm, 0, sizeof(tm));
131                 tm.tm_year = 2005;
132                 tm.tm_mon = tm.tm_mday = 1;
133                 if (efi_set_time(&tm))
134                         printf("ERROR: COULD NOT RESET EFI CLOCK!\n");
135         }
136
137         ct.nsec = tm.tm_nsec;
138         ct.sec = tm.tm_sec;
139         ct.min = tm.tm_min;
140         ct.hour = tm.tm_hour;
141         ct.day = tm.tm_mday;
142         ct.mon = tm.tm_mon;
143         ct.year = tm.tm_year;
144         ct.dow = -1;
145         clock_ct_to_ts(&ct, &ts);
146         ts.tv_sec += utc_offset();
147
148         /*
149          * The EFI clock is supposed to be a real-time clock, whereas the
150          * base argument is coming from a saved (as on disk) time. It's
151          * impossible for a saved time to represent a time in the future,
152          * so we expect the EFI clock to be larger. If not, the EFI clock
153          * may not be reliable and we trust the base.
154          * Warn if the EFI clock was off by 2 or more days.
155          */
156         if (ts.tv_sec < base) {
157                 days = (base - ts.tv_sec) / (60L * 60L * 24L);
158                 if (days >= 2)
159                         printf("WARNING: EFI clock lost %ld days!\n", days);
160                 ts.tv_sec = base;
161                 ts.tv_nsec = 0;
162         }
163
164         tc_setclock(&ts);
165         clock_initialized = 1;
166 }
167
168 /*
169  * Reset the TODR based on the time value; used when the TODR has a
170  * preposterous value and also when the time is reset by the stime
171  * system call.  Also called when the TODR goes past
172  * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
173  * to wrap the TODR around.
174  */
175 void
176 resettodr()
177 {
178         struct timespec ts;
179         struct clocktime ct;
180         struct efi_tm tm;
181
182         if (!clock_initialized || disable_rtc_set)
183                 return;
184
185         efi_get_time(&tm);
186         getnanotime(&ts);
187         ts.tv_sec -= utc_offset();
188         clock_ts_to_ct(&ts, &ct);
189
190         tm.tm_nsec = ts.tv_nsec;
191         tm.tm_sec = ct.sec;
192         tm.tm_min = ct.min;
193         tm.tm_hour = ct.hour;
194
195         tm.tm_year = ct.year;
196         tm.tm_mon = ct.mon;
197         tm.tm_mday = ct.day;
198         if (efi_set_time(&tm))
199                 printf("ERROR: COULD NOT RESET EFI CLOCK!\n");
200 }