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 2007 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 #pragma ident "%Z%%M% %I% %E% SMI" 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 91 pc_tod_set_rtc_offsets(FADT_DESCRIPTOR *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->DayAlrm) { 105 pc_rtc_offset.day_alrm = fadt->DayAlrm; 106 ok = 1; 107 } 108 109 if (fadt->MonAlrm) { 110 pc_rtc_offset.mon_alrm = fadt->MonAlrm; 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 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 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 ts.tv_sec = 0; 182 ts.tv_nsec = 0; 183 tod_fault_reset(); 184 return (ts); 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 ts.tv_sec = tod_to_utc(tod) + ggmtl(); 220 ts.tv_nsec = 0; 221 222 return (ts); 223 } 224 225 #include <sys/promif.h> 226 /* 227 * Write the specified wakeup alarm into the clock chip. 228 * Must be called with tod_lock held. 229 */ 230 void 231 /*ARGSUSED*/ 232 todpc_setalarm(tod_ops_t *top, int nsecs) 233 { 234 struct rtc_t rtc; 235 int delta, asec, amin, ahr, adom, amon; 236 int day_alrm = pc_rtc_offset.day_alrm; 237 int mon_alrm = pc_rtc_offset.mon_alrm; 238 239 ASSERT(MUTEX_HELD(&tod_lock)); 240 241 /* A delay of zero is not allowed */ 242 if (nsecs == 0) 243 return; 244 245 /* Make sure that we delay no less than the minimum time */ 246 if (nsecs < clock_min_alarm) 247 nsecs = clock_min_alarm; 248 249 if (todpc_rtcget((unsigned char *)&rtc)) 250 return; 251 252 /* 253 * Compute alarm secs, mins and hrs, and where appropriate, dom 254 * and mon. rtc bytes are in binary-coded decimal, so we have 255 * to convert. 256 */ 257 delta = nsecs + BCD_TO_BYTE(rtc.rtc_sec); 258 asec = delta % 60; 259 260 delta = (delta / 60) + BCD_TO_BYTE(rtc.rtc_min); 261 amin = delta % 60; 262 263 delta = (delta / 60) + BCD_TO_BYTE(rtc.rtc_hr); 264 ahr = delta % 24; 265 266 if (day_alrm == 0 && delta >= 24) { 267 prom_printf("No day alarm - set to end of today!\n"); 268 asec = 59; 269 amin = 59; 270 ahr = 23; 271 } else { 272 int mon = BCD_TO_BYTE(rtc.rtc_mon); 273 static int dpm[] = 274 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 275 276 adom = (delta / 24) + BCD_TO_BYTE(rtc.rtc_dom); 277 278 if (mon_alrm == 0) { 279 if (adom > dpm[mon]) { 280 prom_printf("No mon alarm - " 281 "set to end of current month!\n"); 282 asec = 59; 283 amin = 59; 284 ahr = 23; 285 adom = dpm[mon]; 286 } 287 } else { 288 for (amon = mon; 289 amon <= 12 && adom > dpm[amon]; amon++) { 290 adom -= dpm[amon]; 291 } 292 if (amon > 12) { 293 prom_printf("Alarm too far in future - " 294 "set to end of current year!\n"); 295 asec = 59; 296 amin = 59; 297 ahr = 23; 298 adom = dpm[12]; 299 amon = 12; 300 } 301 rtc.rtc_amon = BYTE_TO_BCD(amon); 302 } 303 304 rtc.rtc_adom = BYTE_TO_BCD(adom); 305 } 306 307 rtc.rtc_asec = BYTE_TO_BCD(asec); 308 rtc.rtc_amin = BYTE_TO_BCD(amin); 309 rtc.rtc_ahr = BYTE_TO_BCD(ahr); 310 311 rtc.rtc_statusb |= RTC_AIE; /* Enable alarm interrupt */ 312 313 todpc_rtcput((unsigned char *)&rtc); 314 } 315 316 /* 317 * Clear an alarm. This is effectively setting an alarm of 0. 318 */ 319 void 320 /*ARGSUSED*/ 321 todpc_clralarm(tod_ops_t *top) 322 { 323 mutex_enter(&tod_lock); 324 todpc_setalarm(top, 0); 325 mutex_exit(&tod_lock); 326 } 327 328 /* 329 * Routine to read contents of real time clock to the specified buffer. 330 * Returns ENXIO if clock not valid, or EAGAIN if clock data cannot be read 331 * else 0. 332 * The routine will busy wait for the Update-In-Progress flag to clear. 333 * On completion of the reads the Seconds register is re-read and the 334 * UIP flag is rechecked to confirm that an clock update did not occur 335 * during the accesses. Routine will error exit after 256 attempts. 336 * (See bugid 1158298.) 337 * Routine returns RTC_NREG (which is 15) bytes of data, as given in the 338 * technical reference. This data includes both time and status registers. 339 */ 340 341 static int 342 todpc_rtcget(unsigned char *buf) 343 { 344 unsigned char reg; 345 int i; 346 int retries = 256; 347 unsigned char *rawp; 348 unsigned char century = RTC_CENTURY; 349 unsigned char day_alrm; 350 unsigned char mon_alrm; 351 352 ASSERT(MUTEX_HELD(&tod_lock)); 353 354 day_alrm = pc_rtc_offset.day_alrm; 355 mon_alrm = pc_rtc_offset.mon_alrm; 356 if (pc_rtc_offset.century != 0) { 357 century = pc_rtc_offset.century; 358 } 359 360 outb(RTC_ADDR, RTC_D); /* check if clock valid */ 361 reg = inb(RTC_DATA); 362 if ((reg & RTC_VRT) == 0) 363 return (ENXIO); 364 365 checkuip: 366 if (retries-- < 0) 367 return (EAGAIN); 368 outb(RTC_ADDR, RTC_A); /* check if update in progress */ 369 reg = inb(RTC_DATA); 370 if (reg & RTC_UIP) { 371 tenmicrosec(); 372 goto checkuip; 373 } 374 375 for (i = 0, rawp = buf; i < RTC_NREG; i++) { 376 outb(RTC_ADDR, i); 377 *rawp++ = inb(RTC_DATA); 378 } 379 outb(RTC_ADDR, century); /* do century */ 380 ((struct rtc_t *)buf)->rtc_century = inb(RTC_DATA); 381 382 if (day_alrm > 0) { 383 outb(RTC_ADDR, day_alrm); 384 ((struct rtc_t *)buf)->rtc_adom = inb(RTC_DATA) & 0x3f; 385 } 386 if (mon_alrm > 0) { 387 outb(RTC_ADDR, mon_alrm); 388 ((struct rtc_t *)buf)->rtc_amon = inb(RTC_DATA); 389 } 390 391 outb(RTC_ADDR, 0); /* re-read Seconds register */ 392 reg = inb(RTC_DATA); 393 if (reg != ((struct rtc_t *)buf)->rtc_sec || 394 (((struct rtc_t *)buf)->rtc_statusa & RTC_UIP)) 395 /* update occured during reads */ 396 goto checkuip; 397 398 return (0); 399 } 400 401 /* 402 * This routine writes the contents of the given buffer to the real time 403 * clock. It is given RTC_NREGP bytes of data, which are the 10 bytes used 404 * to write the time and set the alarm. It should be called with the priority 405 * raised to 5. 406 */ 407 static void 408 todpc_rtcput(unsigned char *buf) 409 { 410 unsigned char reg; 411 int i; 412 unsigned char century = RTC_CENTURY; 413 unsigned char day_alrm = pc_rtc_offset.day_alrm; 414 unsigned char mon_alrm = pc_rtc_offset.mon_alrm; 415 416 if (pc_rtc_offset.century != 0) { 417 century = pc_rtc_offset.century; 418 } 419 420 outb(RTC_ADDR, RTC_B); 421 reg = inb(RTC_DATA); 422 outb(RTC_ADDR, RTC_B); 423 outb(RTC_DATA, reg | RTC_SET); /* allow time set now */ 424 for (i = 0; i < RTC_NREGP; i++) { /* set the time */ 425 outb(RTC_ADDR, i); 426 outb(RTC_DATA, buf[i]); 427 } 428 outb(RTC_ADDR, century); /* do century */ 429 outb(RTC_DATA, ((struct rtc_t *)buf)->rtc_century); 430 431 if (day_alrm > 0) { 432 outb(RTC_ADDR, day_alrm); 433 outb(RTC_DATA, ((struct rtc_t *)buf)->rtc_adom); 434 } 435 if (mon_alrm > 0) { 436 outb(RTC_ADDR, mon_alrm); 437 outb(RTC_DATA, ((struct rtc_t *)buf)->rtc_amon); 438 } 439 440 outb(RTC_ADDR, RTC_B); 441 reg = inb(RTC_DATA); 442 outb(RTC_ADDR, RTC_B); 443 outb(RTC_DATA, reg & ~RTC_SET); /* allow time update */ 444 } 445 446 static tod_ops_t todpc_ops = { 447 TOD_OPS_VERSION, 448 todpc_get, 449 todpc_set, 450 NULL, 451 NULL, 452 todpc_setalarm, 453 todpc_clralarm, 454 NULL 455 }; 456 457 /* 458 * Initialize for the default TOD ops vector for use on hardware. 459 */ 460 461 tod_ops_t *tod_ops = &todpc_ops; 462