Implement time based checks even when looping on an ioport.
authorKevin O'Connor <kevin@koconnor.net>
Sat, 13 Dec 2008 15:45:50 +0000 (10:45 -0500)
committerKevin O'Connor <kevin@koconnor.net>
Sat, 13 Dec 2008 15:45:50 +0000 (10:45 -0500)
Implement real timeout code in ATA.
Implement real timeout code for RTC updating check.

src/ata.c
src/clock.c
src/util.h

index 77f5e340c9757031a0086ec3679ac15c014f6eab..53f9196378756f94fdeac15fb25659081be6e084 100644 (file)
--- a/src/ata.c
+++ b/src/ata.c
 static int
 await_ide(u8 when_done, u16 base, u16 timeout)
 {
-    u32 time=0, last=0;
+    u64 end = calc_future_tsc(timeout);
     for (;;) {
         u8 status = inb(base+ATA_CB_STAT);
-        time++;
         u8 result = 0;
         if (when_done == BSY)
             result = status & ATA_CB_STAT_BSY;
@@ -55,20 +54,13 @@ await_ide(u8 when_done, u16 base, u16 timeout)
 
         if (result)
             return status;
-        // mod 2048 each 16 ms
-        if (time>>16 != last) {
-            last = time >>16;
-            dprintf(6, "await_ide: (TIMEOUT,BSY,!BSY,!BSY_DRQ"
-                    ",!BSY_!DRQ,!BSY_RDY) %d time= %d timeout= %d\n"
-                    , when_done, time>>11, timeout);
-        }
         if (status & ATA_CB_STAT_ERR) {
             dprintf(1, "await_ide: ERROR (TIMEOUT,BSY,!BSY,!BSY_DRQ"
-                    ",!BSY_!DRQ,!BSY_RDY) %d status=%x time= %d timeout= %d\n"
-                    , when_done, status, time>>11, timeout);
+                    ",!BSY_!DRQ,!BSY_RDY) %d status=%x timeout=%d\n"
+                    , when_done, status, timeout);
             return -1;
         }
-        if (timeout == 0 || (time>>11) > timeout)
+        if (rdtscll() >= end)
             break;
     }
     dprintf(1, "IDE time out\n");
index 7261f2db5e3a16f991794839d9c00e6dbdac38dd..5933ad3e9b82ad5eb1f73effaeb035d938ee3576 100644 (file)
@@ -114,11 +114,42 @@ mdelay(u32 count)
     tscsleep(count * khz);
 }
 
+// Return the TSC value that is 'msecs' time in the future.
+u64
+calc_future_tsc(u32 msecs)
+{
+    u32 khz = GET_VAR(CS, cpu_khz);
+    return rdtscll() + ((u64)khz * msecs);
+}
+
 
 /****************************************************************
  * Init
  ****************************************************************/
 
+static int
+rtc_updating()
+{
+    // This function checks to see if the update-in-progress bit
+    // is set in CMOS Status Register A.  If not, it returns 0.
+    // If it is set, it tries to wait until there is a transition
+    // to 0, and will return 0 if such a transition occurs.  A -1
+    // is returned only after timing out.  The maximum period
+    // that this bit should be set is constrained to 244useconds, so
+    // we wait for 1 msec max.
+
+    if ((inb_cmos(CMOS_STATUS_A) & 0x80) == 0)
+        return 0;
+    u64 end = calc_future_tsc(1);
+    do {
+        if ((inb_cmos(CMOS_STATUS_A) & 0x80) == 0)
+            return 0;
+    } while (rdtscll() <= end);
+
+    // update-in-progress never transitioned to 0
+    return -1;
+}
+
 static void
 pit_setup()
 {
@@ -142,6 +173,7 @@ timer_setup()
     calibrate_tsc();
     pit_setup();
 
+    rtc_updating();
     u32 seconds = bcd2bin(inb_cmos(CMOS_RTC_SECONDS));
     u32 ticks = (seconds * 18206507) / 1000000;
     u32 minutes = bcd2bin(inb_cmos(CMOS_RTC_MINUTES));
@@ -169,26 +201,6 @@ init_rtc()
  * Standard clock functions
  ****************************************************************/
 
-static u8
-rtc_updating()
-{
-    // This function checks to see if the update-in-progress bit
-    // is set in CMOS Status Register A.  If not, it returns 0.
-    // If it is set, it tries to wait until there is a transition
-    // to 0, and will return 0 if such a transition occurs.  A 1
-    // is returned only after timing out.  The maximum period
-    // that this bit should be set is constrained to 244useconds.
-    // The count I use below guarantees coverage or more than
-    // this time, with any reasonable IPS setting.
-
-    u16 count = 25000;
-    while (--count != 0) {
-        if ( (inb_cmos(CMOS_STATUS_A) & 0x80) == 0 )
-            return 0;
-    }
-    return 1; // update-in-progress never transitioned to 0
-}
-
 // get current clock count
 static void
 handle_1a00(struct bregs *regs)
index 5bbe9e81465e64e9df1c40673439ca1f6b6a39a5..0966c4c71fffa79614d7cb479adbd7460b3cf3b0 100644 (file)
@@ -125,6 +125,7 @@ void timer_setup();
 void ndelay(u32 count);
 void udelay(u32 count);
 void mdelay(u32 count);
+u64 calc_future_tsc(u32 msecs);
 void handle_1583(struct bregs *regs);
 void handle_1586(struct bregs *regs);