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