All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] Rework the RTL8139C timer interrupts and enable them by default
@ 2008-12-15 15:42 Tim Deegan
  0 siblings, 0 replies; only message in thread
From: Tim Deegan @ 2008-12-15 15:42 UTC (permalink / raw)
  To: qemu-devel

Reorganise the RTL8139 rolling timer so that it calculates the counter
on read instead of updating it in real time, and only sets a timer when
the guest has programmed a timer interrupt.

Enable it by default since it should have no overhead for guests that
don't use it, and OpenBSD's rtl8139 driver relies on it.

Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
---
 rtl8139.c |   87 ++++++++++++++++++++++++++++++--------------------------------
 1 file changed, 43 insertions(+), 44 deletions(-)

Index: hw/rtl8139.c
===================================================================
--- hw/rtl8139.c	(revision 6042)
+++ hw/rtl8139.c	(working copy)
@@ -59,8 +59,8 @@
 /* Calculate CRCs properly on Rx packets */
 #define RTL8139_CALCULATE_RXCRC 1
 
-/* Uncomment to enable on-board timer interrupts */
-//#define RTL8139_ONBOARD_TIMER 1
+/* Enable on-board timer interrupts */
+#define RTL8139_ONBOARD_TIMER 1
 
 #if defined(RTL8139_CALCULATE_RXCRC)
 /* For crc32 */
@@ -497,6 +497,37 @@
 
 } RTL8139State;
 
+/* Fix up the TCTR field to match the current system time */
+static inline void rtl8139_update_tctr(RTL8139State *s, int64_t current_time)
+{
+    if (s->clock_enabled)
+        s->TCTR = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY, ticks_per_sec);
+}
+
+/* Queue a timer interrupt based on the state of the TCTR and TimerInt */
+static inline void rtl8139_set_tctr_timer(RTL8139State *s)
+{
+#if RTL8139_ONBOARD_TIMER
+    int64_t next_time;
+    int64_t curr_time = qemu_get_clock(vm_clock);
+
+    if (!s->clock_enabled || s->TimerInt == 0) 
+    {
+        DEBUG_PRINT(("RTL8139: >>> set timer: clock not running or timeout not set\n"));
+        return;
+    }
+
+    rtl8139_update_tctr(s, curr_time);
+    next_time = curr_time +
+        muldiv64((1 + s->TimerInt - s->TCTR), ticks_per_sec, PCI_FREQUENCY);
+
+    if (next_time <= curr_time)
+        next_time = curr_time + 1;
+
+    qemu_mod_timer(s->timer, next_time);
+#endif
+}
+
 static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
 {
     DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command));
@@ -2788,11 +2819,13 @@
             DEBUG_PRINT(("RTL8139: TCTR Timer reset on write\n"));
             s->TCTR = 0;
             s->TCTR_base = qemu_get_clock(vm_clock);
+            rtl8139_set_tctr_timer(s);
             break;
 
         case FlashReg:
             DEBUG_PRINT(("RTL8139: FlashReg TimerInt write val=0x%08x\n", val));
             s->TimerInt = val;
+            rtl8139_set_tctr_timer(s);
             break;
 
         default:
@@ -3002,6 +3035,7 @@
             break;
 
         case Timer:
+            rtl8139_update_tctr(s, qemu_get_clock(vm_clock));
             ret = s->TCTR;
             DEBUG_PRINT(("RTL8139: TCTR Timer read val=0x%08x\n", ret));
             break;
@@ -3287,6 +3321,7 @@
         qemu_get_be32s(f, &s->TimerInt);
         s->TCTR_base=qemu_get_be64(f);
 
+        rtl8139_set_tctr_timer(s);
         RTL8139TallyCounters_load(f, &s->tally_counters);
     }
     else
@@ -3347,56 +3382,23 @@
     rtl8139_mmio_writel,
 };
 
-static inline int64_t rtl8139_get_next_tctr_time(RTL8139State *s, int64_t current_time)
-{
-    int64_t next_time = current_time +
-        muldiv64(1, ticks_per_sec, PCI_FREQUENCY);
-    if (next_time <= current_time)
-        next_time = current_time + 1;
-    return next_time;
-}
-
 #ifdef RTL8139_ONBOARD_TIMER
 static void rtl8139_timer(void *opaque)
 {
     RTL8139State *s = opaque;
 
-    int is_timeout = 0;
-
-    int64_t  curr_time;
-    uint32_t curr_tick;
-
-    if (!s->clock_enabled)
+    if (!s->clock_enabled || s->TimerInt == 0)
     {
-        DEBUG_PRINT(("RTL8139: >>> timer: clock is not running\n"));
+        DEBUG_PRINT(("RTL8139: >>> timer: clock not running or timeout not set\n"));
         return;
     }
 
-    curr_time = qemu_get_clock(vm_clock);
+    s->IntrStatus |= PCSTimeout;
+    rtl8139_update_irq(s);
 
-    curr_tick = muldiv64(curr_time - s->TCTR_base, PCI_FREQUENCY, ticks_per_sec);
+    rtl8139_set_tctr_timer(s);
 
-    if (s->TimerInt && curr_tick >= s->TimerInt)
-    {
-        if (s->TCTR < s->TimerInt || curr_tick < s->TCTR)
-        {
-            is_timeout = 1;
-        }
-    }
-
-    s->TCTR = curr_tick;
-
-//  DEBUG_PRINT(("RTL8139: >>> timer: tick=%08u\n", s->TCTR));
-
-    if (is_timeout)
-    {
-        DEBUG_PRINT(("RTL8139: >>> timer: timeout tick=%08u\n", s->TCTR));
-        s->IntrStatus |= PCSTimeout;
-        rtl8139_update_irq(s);
-    }
-
-    qemu_mod_timer(s->timer,
-        rtl8139_get_next_tctr_time(s,curr_time));
+    DEBUG_PRINT(("RTL8139: >>> timer: timeout tick=%08u (%08u)\n", s->TCTR, s->TimerInt));
 }
 #endif /* RTL8139_ONBOARD_TIMER */
 
@@ -3458,8 +3460,5 @@
 
 #ifdef RTL8139_ONBOARD_TIMER
     s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s);
-
-    qemu_mod_timer(s->timer,
-        rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock)));
 #endif /* RTL8139_ONBOARD_TIMER */
 }

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-12-15 15:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-12-15 15:42 [Qemu-devel] [PATCH] Rework the RTL8139C timer interrupts and enable them by default Tim Deegan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.