Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LCFbA-0006bJ-Dj for qemu-devel@nongnu.org; Mon, 15 Dec 2008 10:43:08 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LCFb7-0006aJ-Di for qemu-devel@nongnu.org; Mon, 15 Dec 2008 10:43:08 -0500 Received: from [199.232.76.173] (port=55209 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LCFb7-0006aB-32 for qemu-devel@nongnu.org; Mon, 15 Dec 2008 10:43:05 -0500 Received: from smtp02.citrix.com ([66.165.176.63]:39361) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LCFb6-0004mF-7a for qemu-devel@nongnu.org; Mon, 15 Dec 2008 10:43:04 -0500 Date: Mon, 15 Dec 2008 15:42:58 +0000 From: Tim Deegan Message-ID: <20081215154258.GD23562@york.uk.xensource.com> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Subject: [Qemu-devel] [PATCH] Rework the RTL8139C timer interrupts and enable them by default Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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 --- 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 */ }