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