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 <acpica/include/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(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 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 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*/ 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*/ 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 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 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;