[SeaBIOS] [PATCH 10/10] Unify pmtimer_read() and pittimer_read() code.

Kevin O'Connor kevin at koconnor.net
Sun Jul 21 01:50:28 CEST 2013


These two functions both need to add in extra high bits to their
timers, and this code is the bulk of these functions.  Factor out the
duplicate code.

Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
 src/timer.c | 75 +++++++++++++++++++++++--------------------------------------
 1 file changed, 28 insertions(+), 47 deletions(-)

diff --git a/src/timer.c b/src/timer.c
index cc9e9f1..c0cda79 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -17,15 +17,9 @@
 
 #define PMTIMER_HZ 3579545      // Underlying Hz of the PM Timer
 #define PMTIMER_TO_PIT 3        // Ratio of pmtimer rate to pit rate
-#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
 
 u32 TimerKHz VARFSEG;
-u8 no_tsc VARFSEG;
-
-u16 pmtimer_ioport VARFSEG;
-u32 pmtimer_wraps VARLOW;
-u32 pmtimer_last VARLOW;
-
+u16 TimerPort VARFSEG;
 u8 ShiftTSC VARFSEG;
 
 
@@ -75,7 +69,7 @@ tsctimer_setup(void)
 void
 timer_setup(void)
 {
-    if (CONFIG_PMTIMER && GET_GLOBAL(pmtimer_ioport)) {
+    if (CONFIG_PMTIMER && TimerPort) {
         dprintf(3, "pmtimer already configured; will not calibrate TSC\n");
         return;
     }
@@ -86,7 +80,7 @@ timer_setup(void)
         cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
 
     if (!(cpuid_features & CPUID_TSC)) {
-        no_tsc = 1;
+        TimerPort = PORT_PIT_COUNTER0;
         TimerKHz = DIV_ROUND_UP(PMTIMER_HZ, 1000 * PMTIMER_TO_PIT);
         dprintf(3, "386/486 class CPU. Using TSC emulation\n");
         return;
@@ -101,7 +95,7 @@ pmtimer_setup(u16 ioport)
     if (!CONFIG_PMTIMER)
         return;
     dprintf(1, "Using pmtimer, ioport 0x%x\n", ioport);
-    pmtimer_ioport = ioport;
+    TimerPort = ioport;
     TimerKHz = DIV_ROUND_UP(PMTIMER_HZ, 1000);
 }
 
@@ -110,54 +104,39 @@ pmtimer_setup(u16 ioport)
  * Internal timer reading
  ****************************************************************/
 
-/* TSC emulation timekeepers */
-u32 TSC_8254 VARLOW;
-int Last_TSC_8254 VARLOW;
+u32 TimerLast VARLOW;
 
+// Add extra high bits to timers that have less than 32bits of precision.
 static u32
-pittimer_read(void)
+timer_adjust_bits(u32 value, u32 validbits)
 {
-    /* read timer 0 current count */
-    u32 ret = GET_LOW(TSC_8254);
-    /* readback mode has slightly shifted registers, works on all
-     * 8254, readback PIT0 latch */
-    outb(PM_SEL_READBACK | PM_READ_VALUE | PM_READ_COUNTER0, PORT_PIT_MODE);
-    int cnt = (inb(PORT_PIT_COUNTER0) | (inb(PORT_PIT_COUNTER0) << 8));
-    int d = GET_LOW(Last_TSC_8254) - cnt;
-    /* Determine the ticks count from last invocation of this function */
-    ret += (d > 0) ? d : (PIT_TICK_INTERVAL + d);
-    SET_LOW(Last_TSC_8254, cnt);
-    SET_LOW(TSC_8254, ret);
-    return ret;
-}
-
-static u32
-pmtimer_read(void)
-{
-    u16 ioport = GET_GLOBAL(pmtimer_ioport);
-    u32 wraps = GET_LOW(pmtimer_wraps);
-    u32 pmtimer = inl(ioport) & 0xffffff;
-
-    if (pmtimer < GET_LOW(pmtimer_last)) {
-        wraps++;
-        SET_LOW(pmtimer_wraps, wraps);
-    }
-    SET_LOW(pmtimer_last, pmtimer);
-
-    dprintf(9, "pmtimer: %u:%u\n", wraps, pmtimer);
-    return wraps << 24 | pmtimer;
+    u32 last = GET_LOW(TimerLast);
+    value = (last & ~validbits) | (value & validbits);
+    if (value < last)
+        value += validbits + 1;
+    SET_LOW(TimerLast, value);
+    return value;
 }
 
+// Sample the current timer value.
 static u32
 timer_read(void)
 {
-    if (unlikely(GET_GLOBAL(no_tsc)))
-        return pittimer_read();
-    if (CONFIG_PMTIMER && GET_GLOBAL(pmtimer_ioport))
-        return pmtimer_read();
+    u16 port = GET_GLOBAL(TimerPort);
+    if (port) {
+        if (CONFIG_PMTIMER && port != PORT_PIT_COUNTER0)
+            // Read from PMTIMER
+            return timer_adjust_bits(inl(port), 0xffffff);
+        // Read from PIT.
+        outb(PM_SEL_READBACK | PM_READ_VALUE | PM_READ_COUNTER0, PORT_PIT_MODE);
+        u16 v = inb(PORT_PIT_COUNTER0) | (inb(PORT_PIT_COUNTER0) << 8);
+        return timer_adjust_bits(v, 0xffff);
+    }
+    // Read from CPU TSC
     return rdtscll() >> GET_GLOBAL(ShiftTSC);
 }
 
+// Check if the current time is past a previously calculated end time.
 int
 timer_check(u32 end)
 {
@@ -221,6 +200,8 @@ timer_calc_usec(u32 usecs)
  * IRQ based timer
  ****************************************************************/
 
+#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
+
 // Return the number of milliseconds in 'ticks' number of timer irqs.
 u32
 ticks_to_ms(u32 ticks)
-- 
1.7.11.7




More information about the SeaBIOS mailing list