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