Print this page
8680 Time of Day clock error


   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;


 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) {




   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;


 315 
 316         todpc_rtcput((unsigned char *)&rtc);
 317 }
 318 
 319 /*
 320  * Clear an alarm.  This is effectively setting an alarm of 0.
 321  */
 322 void
 323 /*ARGSUSED*/
 324 todpc_clralarm(tod_ops_t *top)
 325 {
 326         mutex_enter(&tod_lock);
 327         todpc_setalarm(top, 0);
 328         mutex_exit(&tod_lock);
 329 }
 330 
 331 /*
 332  * Routine to read contents of real time clock to the specified buffer.
 333  * Returns ENXIO if clock not valid, or EAGAIN if clock data cannot be read
 334  * else 0.
 335  * Some RTC hardware is very slow at asserting the validity flag on
 336  * startup.  The routine will busy wait for the RTC to become valid.
 337  * The routine will also busy wait for the Update-In-Progress flag to clear.
 338  * On completion of the reads the Seconds register is re-read and the
 339  * UIP flag is rechecked to confirm that an clock update did not occur
 340  * during the accesses.  Routine will error exit after 256 attempts.
 341  * (See bugid 1158298.)
 342  * Routine returns RTC_NREG (which is 15) bytes of data, as given in the
 343  * technical reference.  This data includes both time and status registers.
 344  */
 345 
 346 static int
 347 todpc_rtcget(unsigned char *buf)
 348 {
 349         unsigned char   reg;
 350         int             i;
 351         int             uip_try = 256;
 352         int             vrt_try = 512;
 353         unsigned char   *rawp;
 354         unsigned char   century = RTC_CENTURY;
 355         unsigned char   day_alrm;
 356         unsigned char   mon_alrm;
 357 
 358         ASSERT(MUTEX_HELD(&tod_lock));
 359 
 360         day_alrm = pc_rtc_offset.day_alrm;
 361         mon_alrm = pc_rtc_offset.mon_alrm;
 362         if (pc_rtc_offset.century != 0) {
 363                 century = pc_rtc_offset.century;
 364         }
 365 
 366         for (;;) {
 367                 if (vrt_try-- < 0)
 368                         return (ENXIO);
 369                 outb(RTC_ADDR, RTC_D);          /* check if clock valid */
 370                 reg = inb(RTC_DATA);
 371                 if ((reg & RTC_VRT) != 0)
 372                         break;
 373                 drv_usecwait(5000);             /* Delay for 5000 us */
 374         }
 375 
 376 
 377 checkuip:
 378         if (uip_try-- < 0)
 379                 return (EAGAIN);
 380         outb(RTC_ADDR, RTC_A);          /* check if update in progress */
 381         reg = inb(RTC_DATA);
 382         if (reg & RTC_UIP) {
 383                 tenmicrosec();
 384                 goto checkuip;
 385         }
 386 
 387         for (i = 0, rawp = buf; i < RTC_NREG; i++) {
 388                 outb(RTC_ADDR, i);
 389                 *rawp++ = inb(RTC_DATA);
 390         }
 391         outb(RTC_ADDR, century); /* do century */
 392         ((struct rtc_t *)buf)->rtc_century = inb(RTC_DATA);
 393 
 394         if (day_alrm > 0) {
 395                 outb(RTC_ADDR, day_alrm);
 396                 ((struct rtc_t *)buf)->rtc_adom = inb(RTC_DATA) & 0x3f;
 397         }
 398         if (mon_alrm > 0) {