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 <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(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;