Print this page
8680 Time of Day clock error

@@ -17,10 +17,11 @@
  * information: Portions Copyright [yyyy] [name of copyright owner]
  *
  * CDDL HEADER END
  */
 /*
+ * Copyright 2018 Gary Mills
  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.

@@ -44,10 +45,11 @@
 #include <sys/archsystm.h>
 #include <sys/sysmacros.h>
 #include <sys/lockstat.h>
 #include <sys/stat.h>
 #include <sys/sunddi.h>
+#include <sys/ddi.h>
 
 #include <sys/acpi/acpi.h>
 #include <sys/acpica.h>
 
 static int todpc_rtcget(unsigned char *buf);

@@ -328,11 +330,13 @@
 
 /*
  * Routine to read contents of real time clock to the specified buffer.
  * Returns ENXIO if clock not valid, or EAGAIN if clock data cannot be read
  * else 0.
- * The routine will busy wait for the Update-In-Progress flag to clear.
+ * Some RTC hardware is very slow at asserting the validity flag on
+ * startup.  The routine will busy wait for the RTC to become valid.
+ * The routine will also busy wait for the Update-In-Progress flag to clear.
  * On completion of the reads the Seconds register is re-read and the
  * UIP flag is rechecked to confirm that an clock update did not occur
  * during the accesses.  Routine will error exit after 256 attempts.
  * (See bugid 1158298.)
  * Routine returns RTC_NREG (which is 15) bytes of data, as given in the

@@ -342,11 +346,12 @@
 static int
 todpc_rtcget(unsigned char *buf)
 {
         unsigned char   reg;
         int             i;
-        int             retries = 256;
+        int             uip_try = 256;
+        int             vrt_try = 512;
         unsigned char   *rawp;
         unsigned char   century = RTC_CENTURY;
         unsigned char   day_alrm;
         unsigned char   mon_alrm;
 

@@ -356,17 +361,23 @@
         mon_alrm = pc_rtc_offset.mon_alrm;
         if (pc_rtc_offset.century != 0) {
                 century = pc_rtc_offset.century;
         }
 
+        for (;;) {
+                if (vrt_try-- < 0)
+                        return (ENXIO);
         outb(RTC_ADDR, RTC_D);          /* check if clock valid */
         reg = inb(RTC_DATA);
-        if ((reg & RTC_VRT) == 0)
-                return (ENXIO);
+                if ((reg & RTC_VRT) != 0)
+                        break;
+                drv_usecwait(5000);             /* Delay for 5000 us */
+        }
 
+
 checkuip:
-        if (retries-- < 0)
+        if (uip_try-- < 0)
                 return (EAGAIN);
         outb(RTC_ADDR, RTC_A);          /* check if update in progress */
         reg = inb(RTC_DATA);
         if (reg & RTC_UIP) {
                 tenmicrosec();