]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/ia64/ia64/clock.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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         ia64_srlz_d();
76 }
77
78 /*
79  * Start the real-time and statistics clocks. We use cr.itc and cr.itm
80  * to implement a 1000hz clock.
81  */
82 void
83 cpu_initclocks()
84 {
85
86         if (itc_frequency == 0)
87                 panic("Unknown clock frequency");
88
89         stathz = hz;
90         ia64_clock_reload = (itc_frequency + hz/2) / hz;
91
92 #ifndef SMP
93         ia64_timecounter.tc_frequency = itc_frequency;
94         tc_init(&ia64_timecounter);
95 #endif
96
97         pcpu_initclock();
98 }
99
100 void
101 cpu_startprofclock(void)
102 {
103
104         /* nothing to do */
105 }
106
107 void
108 cpu_stopprofclock(void)
109 {
110
111         /* nothing to do */
112 }
113
114 void
115 inittodr(time_t base)
116 {
117         long days;
118         struct efi_tm tm;
119         struct timespec ts;
120         struct clocktime ct;
121
122         efi_get_time(&tm);
123
124         /*
125          * This code was written in 2005, so logically EFI cannot return
126          * a year smaller than that. Assume the EFI clock is out of whack
127          * in that case and reset the EFI clock.
128          */
129         if (tm.tm_year < 2005) {
130                 printf("WARNING: CHECK AND RESET THE DATE!\n");
131                 memset(&tm, 0, sizeof(tm));
132                 tm.tm_year = 2005;
133                 tm.tm_mon = tm.tm_mday = 1;
134                 if (efi_set_time(&tm))
135                         printf("ERROR: COULD NOT RESET EFI CLOCK!\n");
136         }
137
138         ct.nsec = tm.tm_nsec;
139         ct.sec = tm.tm_sec;
140         ct.min = tm.tm_min;
141         ct.hour = tm.tm_hour;
142         ct.day = tm.tm_mday;
143         ct.mon = tm.tm_mon;
144         ct.year = tm.tm_year;
145         ct.dow = -1;
146         if (clock_ct_to_ts(&ct, &ts))
147                 printf("Invalid time in clock: check and reset the date!\n");
148         ts.tv_sec += utc_offset();
149
150         /*
151          * The EFI clock is supposed to be a real-time clock, whereas the
152          * base argument is coming from a saved (as on disk) time. It's
153          * impossible for a saved time to represent a time in the future,
154          * so we expect the EFI clock to be larger. If not, the EFI clock
155          * may not be reliable and we trust the base.
156          * Warn if the EFI clock was off by 2 or more days.
157          */
158         if (ts.tv_sec < base) {
159                 days = (base - ts.tv_sec) / (60L * 60L * 24L);
160                 if (days >= 2)
161                         printf("WARNING: EFI clock lost %ld days!\n", days);
162                 ts.tv_sec = base;
163                 ts.tv_nsec = 0;
164         }
165
166         tc_setclock(&ts);
167         clock_initialized = 1;
168 }
169
170 /*
171  * Reset the TODR based on the time value; used when the TODR has a
172  * preposterous value and also when the time is reset by the stime
173  * system call.  Also called when the TODR goes past
174  * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
175  * to wrap the TODR around.
176  */
177 void
178 resettodr()
179 {
180         struct timespec ts;
181         struct clocktime ct;
182         struct efi_tm tm;
183
184         if (!clock_initialized || disable_rtc_set)
185                 return;
186
187         efi_get_time(&tm);
188         getnanotime(&ts);
189         ts.tv_sec -= utc_offset();
190         clock_ts_to_ct(&ts, &ct);
191
192         tm.tm_nsec = ts.tv_nsec;
193         tm.tm_sec = ct.sec;
194         tm.tm_min = ct.min;
195         tm.tm_hour = ct.hour;
196
197         tm.tm_year = ct.year;
198         tm.tm_mon = ct.mon;
199         tm.tm_mday = ct.day;
200         if (efi_set_time(&tm))
201                 printf("ERROR: COULD NOT RESET EFI CLOCK!\n");
202 }