1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
23 */
24 /*
25 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28
29 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
30 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
31 /* All Rights Reserved */
32
33 /* Copyright (c) 1987, 1988 Microsoft Corporation */
34 /* All Rights Reserved */
35
36 #include <sys/param.h>
37 #include <sys/time.h>
38 #include <sys/systm.h>
39
40 #include <sys/cpuvar.h>
41 #include <sys/clock.h>
42 #include <sys/debug.h>
43 #include <sys/rtc.h>
44 #include <sys/archsystm.h>
45 #include <sys/sysmacros.h>
46 #include <sys/lockstat.h>
47 #include <sys/stat.h>
48 #include <sys/sunddi.h>
49
50 #include <sys/acpi/acpi.h>
51 #include <sys/acpica.h>
52
53 static int todpc_rtcget(unsigned char *buf);
54 static void todpc_rtcput(unsigned char *buf);
55
56 #define CLOCK_RES 1000 /* 1 microsec in nanosecs */
57
58 int clock_res = CLOCK_RES;
59
60 /*
61 * The minimum sleep time till an alarm can be fired.
62 * This can be tuned in /etc/system, but if the value is too small,
63 * there is a danger that it will be missed if it takes too long to
64 * get from the set point to sleep. Or that it can fire quickly, and
65 * generate a power spike on the hardware. And small values are
66 * probably only usefull for test setups.
67 */
68 int clock_min_alarm = 4;
69
70 /*
71 * Machine-dependent clock routines.
72 */
73
74 extern long gmt_lag;
75
76 struct rtc_offset {
77 int8_t loaded;
78 uint8_t day_alrm;
79 uint8_t mon_alrm;
80 uint8_t century;
81 };
82
83 static struct rtc_offset pc_rtc_offset = {0, 0, 0, 0};
84
85
86 /*
87 * Entry point for ACPI to pass RTC or other clock values that
88 * are useful to TOD.
89 */
90 void
pc_tod_set_rtc_offsets(ACPI_TABLE_FADT * fadt)91 pc_tod_set_rtc_offsets(ACPI_TABLE_FADT *fadt) {
92 int ok = 0;
93
94 /*
95 * ASSERT is for debugging, but we don't want the machine
96 * falling over because for some reason we didn't get a valid
97 * pointer.
98 */
99 ASSERT(fadt);
100 if (fadt == NULL) {
101 return;
102 }
103
104 if (fadt->DayAlarm) {
105 pc_rtc_offset.day_alrm = fadt->DayAlarm;
106 ok = 1;
107 }
108
109 if (fadt->MonthAlarm) {
110 pc_rtc_offset.mon_alrm = fadt->MonthAlarm;
111 ok = 1;
112 }
113
114 if (fadt->Century) {
115 pc_rtc_offset.century = fadt->Century;
116 ok = 1;
117 }
118
119 pc_rtc_offset.loaded = ok;
120 }
121
122
123 /*
124 * Write the specified time into the clock chip.
125 * Must be called with tod_lock held.
126 */
127 /*ARGSUSED*/
128 static void
todpc_set(tod_ops_t * top,timestruc_t ts)129 todpc_set(tod_ops_t *top, timestruc_t ts)
130 {
131 todinfo_t tod = utc_to_tod(ts.tv_sec - ggmtl());
132 struct rtc_t rtc;
133
134 ASSERT(MUTEX_HELD(&tod_lock));
135
136 if (todpc_rtcget((unsigned char *)&rtc))
137 return;
138
139 /*
140 * rtc bytes are in binary-coded decimal, so we have to convert.
141 * We assume that we wrap the rtc year back to zero at 2000.
142 */
143 /* LINTED: YRBASE = 0 for x86 */
144 tod.tod_year -= YRBASE;
145 if (tod.tod_year >= 100) {
146 tod.tod_year -= 100;
147 rtc.rtc_century = BYTE_TO_BCD(20); /* 20xx year */
148 } else
149 rtc.rtc_century = BYTE_TO_BCD(19); /* 19xx year */
150 rtc.rtc_yr = BYTE_TO_BCD(tod.tod_year);
151 rtc.rtc_mon = BYTE_TO_BCD(tod.tod_month);
152 rtc.rtc_dom = BYTE_TO_BCD(tod.tod_day);
153 /* dow < 10, so no conversion */
154 rtc.rtc_dow = (unsigned char)tod.tod_dow;
155 rtc.rtc_hr = BYTE_TO_BCD(tod.tod_hour);
156 rtc.rtc_min = BYTE_TO_BCD(tod.tod_min);
157 rtc.rtc_sec = BYTE_TO_BCD(tod.tod_sec);
158
159 todpc_rtcput((unsigned char *)&rtc);
160 }
161
162 /*
163 * Read the current time from the clock chip and convert to UNIX form.
164 * Assumes that the year in the clock chip is valid.
165 * Must be called with tod_lock held.
166 */
167 /*ARGSUSED*/
168 static timestruc_t
todpc_get(tod_ops_t * top)169 todpc_get(tod_ops_t *top)
170 {
171 timestruc_t ts;
172 todinfo_t tod;
173 struct rtc_t rtc;
174 int compute_century;
175 static int century_warn = 1; /* only warn once, not each time called */
176 static int range_warn = 1;
177
178 ASSERT(MUTEX_HELD(&tod_lock));
179
180 if (todpc_rtcget((unsigned char *)&rtc)) {
181 tod_status_set(TOD_GET_FAILED);
182 return (hrestime);
183 }
184
185 /* assume that we wrap the rtc year back to zero at 2000 */
186 tod.tod_year = BCD_TO_BYTE(rtc.rtc_yr);
187 if (tod.tod_year < 69) {
188 if (range_warn && tod.tod_year > 38) {
189 cmn_err(CE_WARN, "hardware real-time clock is out "
190 "of range -- time needs to be reset");
191 range_warn = 0;
192 }
193 tod.tod_year += 100 + YRBASE; /* 20xx year */
194 compute_century = 20;
195 } else {
196 /* LINTED: YRBASE = 0 for x86 */
197 tod.tod_year += YRBASE; /* 19xx year */
198 compute_century = 19;
199 }
200 if (century_warn && BCD_TO_BYTE(rtc.rtc_century) != compute_century) {
201 cmn_err(CE_NOTE,
202 "The hardware real-time clock appears to have the "
203 "wrong century: %d.\nSolaris will still operate "
204 "correctly, but other OS's/firmware agents may "
205 "not.\nUse date(1) to set the date to the current "
206 "time to correct the RTC.",
207 BCD_TO_BYTE(rtc.rtc_century));
208 century_warn = 0;
209 }
210 tod.tod_month = BCD_TO_BYTE(rtc.rtc_mon);
211 tod.tod_day = BCD_TO_BYTE(rtc.rtc_dom);
212 tod.tod_dow = rtc.rtc_dow; /* dow < 10, so no conversion needed */
213 tod.tod_hour = BCD_TO_BYTE(rtc.rtc_hr);
214 tod.tod_min = BCD_TO_BYTE(rtc.rtc_min);
215 tod.tod_sec = BCD_TO_BYTE(rtc.rtc_sec);
216
217 /* read was successful so ensure failure flag is clear */
218 tod_status_clear(TOD_GET_FAILED);
219
220 ts.tv_sec = tod_to_utc(tod) + ggmtl();
221 ts.tv_nsec = 0;
222
223 return (ts);
224 }
225
226 #include <sys/promif.h>
227 /*
228 * Write the specified wakeup alarm into the clock chip.
229 * Must be called with tod_lock held.
230 */
231 void
232 /*ARGSUSED*/
todpc_setalarm(tod_ops_t * top,int nsecs)233 todpc_setalarm(tod_ops_t *top, int nsecs)
234 {
235 struct rtc_t rtc;
236 int delta, asec, amin, ahr, adom, amon;
237 int day_alrm = pc_rtc_offset.day_alrm;
238 int mon_alrm = pc_rtc_offset.mon_alrm;
239
240 ASSERT(MUTEX_HELD(&tod_lock));
241
242 /* A delay of zero is not allowed */
243 if (nsecs == 0)
244 return;
245
246 /* Make sure that we delay no less than the minimum time */
247 if (nsecs < clock_min_alarm)
248 nsecs = clock_min_alarm;
249
250 if (todpc_rtcget((unsigned char *)&rtc))
251 return;
252
253 /*
254 * Compute alarm secs, mins and hrs, and where appropriate, dom
255 * and mon. rtc bytes are in binary-coded decimal, so we have
256 * to convert.
257 */
258 delta = nsecs + BCD_TO_BYTE(rtc.rtc_sec);
259 asec = delta % 60;
260
261 delta = (delta / 60) + BCD_TO_BYTE(rtc.rtc_min);
262 amin = delta % 60;
263
264 delta = (delta / 60) + BCD_TO_BYTE(rtc.rtc_hr);
265 ahr = delta % 24;
266
267 if (day_alrm == 0 && delta >= 24) {
268 prom_printf("No day alarm - set to end of today!\n");
269 asec = 59;
270 amin = 59;
271 ahr = 23;
272 } else {
273 int mon = BCD_TO_BYTE(rtc.rtc_mon);
274 static int dpm[] =
275 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
276
277 adom = (delta / 24) + BCD_TO_BYTE(rtc.rtc_dom);
278
279 if (mon_alrm == 0) {
280 if (adom > dpm[mon]) {
281 prom_printf("No mon alarm - "
282 "set to end of current month!\n");
283 asec = 59;
284 amin = 59;
285 ahr = 23;
286 adom = dpm[mon];
287 }
288 } else {
289 for (amon = mon;
290 amon <= 12 && adom > dpm[amon]; amon++) {
291 adom -= dpm[amon];
292 }
293 if (amon > 12) {
294 prom_printf("Alarm too far in future - "
295 "set to end of current year!\n");
296 asec = 59;
297 amin = 59;
298 ahr = 23;
299 adom = dpm[12];
300 amon = 12;
301 }
302 rtc.rtc_amon = BYTE_TO_BCD(amon);
303 }
304
305 rtc.rtc_adom = BYTE_TO_BCD(adom);
306 }
307
308 rtc.rtc_asec = BYTE_TO_BCD(asec);
309 rtc.rtc_amin = BYTE_TO_BCD(amin);
310 rtc.rtc_ahr = BYTE_TO_BCD(ahr);
311
312 rtc.rtc_statusb |= RTC_AIE; /* Enable alarm interrupt */
313
314 todpc_rtcput((unsigned char *)&rtc);
315 }
316
317 /*
318 * Clear an alarm. This is effectively setting an alarm of 0.
319 */
320 void
321 /*ARGSUSED*/
todpc_clralarm(tod_ops_t * top)322 todpc_clralarm(tod_ops_t *top)
323 {
324 mutex_enter(&tod_lock);
325 todpc_setalarm(top, 0);
326 mutex_exit(&tod_lock);
327 }
328
329 /*
330 * Routine to read contents of real time clock to the specified buffer.
331 * Returns ENXIO if clock not valid, or EAGAIN if clock data cannot be read
332 * else 0.
333 * The routine will busy wait for the Update-In-Progress flag to clear.
334 * On completion of the reads the Seconds register is re-read and the
335 * UIP flag is rechecked to confirm that an clock update did not occur
336 * during the accesses. Routine will error exit after 256 attempts.
337 * (See bugid 1158298.)
338 * Routine returns RTC_NREG (which is 15) bytes of data, as given in the
339 * technical reference. This data includes both time and status registers.
340 */
341
342 static int
todpc_rtcget(unsigned char * buf)343 todpc_rtcget(unsigned char *buf)
344 {
345 unsigned char reg;
346 int i;
347 int retries = 256;
348 unsigned char *rawp;
349 unsigned char century = RTC_CENTURY;
350 unsigned char day_alrm;
351 unsigned char mon_alrm;
352
353 ASSERT(MUTEX_HELD(&tod_lock));
354
355 day_alrm = pc_rtc_offset.day_alrm;
356 mon_alrm = pc_rtc_offset.mon_alrm;
357 if (pc_rtc_offset.century != 0) {
358 century = pc_rtc_offset.century;
359 }
360
361 outb(RTC_ADDR, RTC_D); /* check if clock valid */
362 reg = inb(RTC_DATA);
363 if ((reg & RTC_VRT) == 0)
364 return (ENXIO);
365
366 checkuip:
367 if (retries-- < 0)
368 return (EAGAIN);
369 outb(RTC_ADDR, RTC_A); /* check if update in progress */
370 reg = inb(RTC_DATA);
371 if (reg & RTC_UIP) {
372 tenmicrosec();
373 goto checkuip;
374 }
375
376 for (i = 0, rawp = buf; i < RTC_NREG; i++) {
377 outb(RTC_ADDR, i);
378 *rawp++ = inb(RTC_DATA);
379 }
380 outb(RTC_ADDR, century); /* do century */
381 ((struct rtc_t *)buf)->rtc_century = inb(RTC_DATA);
382
383 if (day_alrm > 0) {
384 outb(RTC_ADDR, day_alrm);
385 ((struct rtc_t *)buf)->rtc_adom = inb(RTC_DATA) & 0x3f;
386 }
387 if (mon_alrm > 0) {
388 outb(RTC_ADDR, mon_alrm);
389 ((struct rtc_t *)buf)->rtc_amon = inb(RTC_DATA);
390 }
391
392 outb(RTC_ADDR, 0); /* re-read Seconds register */
393 reg = inb(RTC_DATA);
394 if (reg != ((struct rtc_t *)buf)->rtc_sec ||
395 (((struct rtc_t *)buf)->rtc_statusa & RTC_UIP))
396 /* update occured during reads */
397 goto checkuip;
398
399 return (0);
400 }
401
402 /*
403 * This routine writes the contents of the given buffer to the real time
404 * clock. It is given RTC_NREGP bytes of data, which are the 10 bytes used
405 * to write the time and set the alarm. It should be called with the priority
406 * raised to 5.
407 */
408 static void
todpc_rtcput(unsigned char * buf)409 todpc_rtcput(unsigned char *buf)
410 {
411 unsigned char reg;
412 int i;
413 unsigned char century = RTC_CENTURY;
414 unsigned char day_alrm = pc_rtc_offset.day_alrm;
415 unsigned char mon_alrm = pc_rtc_offset.mon_alrm;
416 unsigned char tmp;
417
418 if (pc_rtc_offset.century != 0) {
419 century = pc_rtc_offset.century;
420 }
421
422 outb(RTC_ADDR, RTC_B);
423 reg = inb(RTC_DATA);
424 outb(RTC_ADDR, RTC_B);
425 outb(RTC_DATA, reg | RTC_SET); /* allow time set now */
426 for (i = 0; i < RTC_NREGP; i++) { /* set the time */
427 outb(RTC_ADDR, i);
428 outb(RTC_DATA, buf[i]);
429 }
430 outb(RTC_ADDR, century); /* do century */
431 outb(RTC_DATA, ((struct rtc_t *)buf)->rtc_century);
432
433 if (day_alrm > 0) {
434 outb(RTC_ADDR, day_alrm);
435 /* preserve RTC_VRT bit; some virt envs accept writes there */
436 tmp = inb(RTC_DATA) & RTC_VRT;
437 tmp |= ((struct rtc_t *)buf)->rtc_adom & ~RTC_VRT;
438 outb(RTC_DATA, tmp);
439 }
440 if (mon_alrm > 0) {
441 outb(RTC_ADDR, mon_alrm);
442 outb(RTC_DATA, ((struct rtc_t *)buf)->rtc_amon);
443 }
444
445 outb(RTC_ADDR, RTC_B);
446 reg = inb(RTC_DATA);
447 outb(RTC_ADDR, RTC_B);
448 outb(RTC_DATA, reg & ~RTC_SET); /* allow time update */
449 }
450
451 static tod_ops_t todpc_ops = {
452 TOD_OPS_VERSION,
453 todpc_get,
454 todpc_set,
455 NULL,
456 NULL,
457 todpc_setalarm,
458 todpc_clralarm,
459 NULL
460 };
461
462 /*
463 * Initialize for the default TOD ops vector for use on hardware.
464 */
465
466 tod_ops_t *tod_ops = &todpc_ops;
467