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