From patchwork Sun Feb 7 11:35:06 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frediano Ziglio X-Patchwork-Id: 44736 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 69758B7C98 for ; Sun, 7 Feb 2010 22:40:12 +1100 (EST) Received: from localhost ([127.0.0.1]:35629 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Ne5RV-0003Di-CO for incoming@patchwork.ozlabs.org; Sun, 07 Feb 2010 06:36:45 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Ne5Q9-0003DR-OI for qemu-devel@nongnu.org; Sun, 07 Feb 2010 06:35:21 -0500 Received: from [199.232.76.173] (port=53521 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Ne5Q8-0003DH-Cn for qemu-devel@nongnu.org; Sun, 07 Feb 2010 06:35:20 -0500 Received: from Debian-exim by monty-python.gnu.org with spam-scanned (Exim 4.60) (envelope-from ) id 1Ne5Q0-0008OZ-Of for qemu-devel@nongnu.org; Sun, 07 Feb 2010 06:35:19 -0500 Received: from mail-fx0-f209.google.com ([209.85.220.209]:56424) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Ne5Pz-0008Nc-4g for qemu-devel@nongnu.org; Sun, 07 Feb 2010 06:35:12 -0500 Received: by fxm1 with SMTP id 1so5824739fxm.4 for ; Sun, 07 Feb 2010 03:35:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:subject:from:to:content-type :date:message-id:mime-version:x-mailer; bh=naNWy9C+GzEWcQ5+xhuqouAs1QFqL5B+7LXVewbYm9w=; b=Nj+fjfp/FRTF/v3VfckokgAu8lWCeozoYhxfzojKm+/utwsoA0tys2L/BC1Fg3QLij WHRR2KmYfzbnGBSZ1/+GEfNYuB4mu37npkoI/8R7sBPueQS/YzK2OsQpaPysYev/yhcQ /nT2FDtu73pWnMWjlt18Ts5E7KA4/kNU4R+Dc= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=subject:from:to:content-type:date:message-id:mime-version:x-mailer; b=SeHTElH5wroLO5nuKei5G8LyKKLimkgkNA2MoYzuaLIZ4plqcHIvyCFIvV52V/H7Vy GszNgzTzT0JWofP6m5VlCBhvr7AzLaPLAbjrwyQhhS75Q+YtjZgU2FHIjz+QZ8VvTv/C OT/0m+4gjDwbTLIovCMtmf7otoQnfqnuTy4Rk= Received: by 10.223.29.199 with SMTP id r7mr3110509fac.73.1265542508793; Sun, 07 Feb 2010 03:35:08 -0800 (PST) Received: from ?192.168.1.2? (net-93-65-72-162.cust.dsl.vodafone.it [93.65.72.162]) by mx.google.com with ESMTPS id 14sm1421827fxm.15.2010.02.07.03.35.07 (version=SSLv3 cipher=RC4-MD5); Sun, 07 Feb 2010 03:35:08 -0800 (PST) From: Frediano Ziglio To: qemu-devel@nongnu.org Date: Sun, 07 Feb 2010 12:35:06 +0100 Message-Id: <1265542506.5027.2.camel@freddy> Mime-Version: 1.0 X-Mailer: Evolution 2.26.1 X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) Subject: [Qemu-devel] Updated rtl8139 timer interrupt rewrote X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Hi, I rewrote timer implementation for this card. I wrote even a small Linux guest test program (attached as main.c). This patch add a QEMU timer only when needed (timeout status not set, timeout irq wanted and timer set). I tested this patch with a Darwin system and with my test program (I bought a compatible physical card and it works too). This patch replace previous (I updated just style). Regards Frediano Ziglio diff --git a/hw/rtl8139.c b/hw/rtl8139.c index f04dd54..0d877b7 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -41,6 +41,10 @@ * segmentation offloading * Removed slirp.h dependency * Added rx/tx buffer reset when enabling rx/tx operation + * + * 2009-Feb-04 Frediano Ziglio: Rewrote timer support using QEMU timer only + * when strictly needed (required for for + * Darwin) */ #include "hw.h" @@ -61,7 +65,7 @@ #define RTL8139_CALCULATE_RXCRC 1 /* Uncomment to enable on-board timer interrupts */ -//#define RTL8139_ONBOARD_TIMER 1 +#define RTL8139_ONBOARD_TIMER 1 #if defined(RTL8139_CALCULATE_RXCRC) /* For crc32 */ @@ -489,11 +493,20 @@ typedef struct RTL8139State { int cplus_txbuffer_len; int cplus_txbuffer_offset; +#ifdef RTL8139_ONBOARD_TIMER /* PCI interrupt timer */ QEMUTimer *timer; + int64_t TimerExpire; +#endif } RTL8139State; +#ifdef RTL8139_ONBOARD_TIMER +static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time); +#else +#define rtl8139_set_next_tctr_time(s,t) do { ; } while(0) +#endif + static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) { DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command)); @@ -2522,7 +2535,9 @@ static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val) s->IntrMask = val; + rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock)); rtl8139_update_irq(s); + } static uint32_t rtl8139_IntrMask_read(RTL8139State *s) @@ -2555,12 +2570,22 @@ static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val) rtl8139_update_irq(s); s->IntrStatus = newStatus; + /* + * Computing if we miss an interrupt here is not that correct but + * considered that we should have had already an interrupt + * and probably emulated is slower is better to assume this resetting was + * done before testing on previous rtl8139_update_irq lead to IRQ loosing + */ + rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock)); rtl8139_update_irq(s); + #endif } static uint32_t rtl8139_IntrStatus_read(RTL8139State *s) { + rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock)); + uint32_t ret = s->IntrStatus; DEBUG_PRINT(("RTL8139: IntrStatus read(w) val=0x%04x\n", ret)); @@ -2739,6 +2764,45 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val) } } +#ifdef RTL8139_ONBOARD_TIMER +static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time) +{ + DEBUG_PRINT(("RTL8139: entered rtl8139_set_next_tctr_time\n")); + + if (s->TimerExpire && current_time >= s->TimerExpire) { + s->IntrStatus |= PCSTimeout; + rtl8139_update_irq(s); + } + + /* Set QEMU timer only if needed that is + * - TimerInt <> 0 (we have a timer) + * - mask = 1 (we want an interrupt timer) + * - irq = 0 (irq is not already active) + * If any of above change we need to compute timer again + * Also we must check if timer is passed without QEMU timer + */ + s->TimerExpire = 0; + if (!s->TimerInt) { + return; + } + + int64_t pci_time = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY, + get_ticks_per_sec()); + uint32_t low_pci = pci_time & 0xffffffff; + pci_time = pci_time - low_pci + s->TimerInt; + if (low_pci >= s->TimerInt) { + pci_time += 0x100000000LL; + } + int64_t next_time = s->TCTR_base + muldiv64(pci_time, get_ticks_per_sec(), + PCI_FREQUENCY); + s->TimerExpire = next_time; + + if ((s->IntrMask & PCSTimeout) != 0 && (s->IntrStatus & PCSTimeout) == 0) { + qemu_mod_timer(s->timer, next_time); + } +} +#endif + static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) { RTL8139State *s = opaque; @@ -2784,13 +2848,16 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) case Timer: DEBUG_PRINT(("RTL8139: TCTR Timer reset on write\n")); - s->TCTR = 0; s->TCTR_base = qemu_get_clock(vm_clock); + rtl8139_set_next_tctr_time(s, s->TCTR_base); break; case FlashReg: DEBUG_PRINT(("RTL8139: FlashReg TimerInt write val=0x%08x\n", val)); - s->TimerInt = val; + if (s->TimerInt != val) { + s->TimerInt = val; + rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock)); + } break; default: @@ -3000,7 +3067,8 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) break; case Timer: - ret = s->TCTR; + ret = muldiv64(qemu_get_clock(vm_clock) - s->TCTR_base, + PCI_FREQUENCY, get_ticks_per_sec()); DEBUG_PRINT(("RTL8139: TCTR Timer read val=0x%08x\n", ret)); break; @@ -3105,6 +3173,7 @@ static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr) static int rtl8139_post_load(void *opaque, int version_id) { RTL8139State* s = opaque; + rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock)); if (version_id < 4) { s->cplus_enabled = s->CpCmd != 0; } @@ -3112,12 +3181,24 @@ static int rtl8139_post_load(void *opaque, int version_id) return 0; } +static void rtl8139_pre_save(void *opaque) +{ + RTL8139State* s = opaque; + + // set IntrStatus correctly + int64_t current_time = qemu_get_clock(vm_clock); + rtl8139_set_next_tctr_time(s, current_time); + s->TCTR = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY, + get_ticks_per_sec()); +} + static const VMStateDescription vmstate_rtl8139 = { .name = "rtl8139", .version_id = 4, .minimum_version_id = 3, .minimum_version_id_old = 3, .post_load = rtl8139_post_load, + .pre_save = rtl8139_pre_save, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, RTL8139State), VMSTATE_PARTIAL_BUFFER(phys, RTL8139State, 6), @@ -3231,57 +3312,20 @@ static CPUWriteMemoryFunc * const rtl8139_mmio_write[3] = { 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, get_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) { DEBUG_PRINT(("RTL8139: >>> timer: clock is not running\n")); return; } - curr_time = qemu_get_clock(vm_clock); - - curr_tick = muldiv64(curr_time - s->TCTR_base, PCI_FREQUENCY, - get_ticks_per_sec()); - - 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)); + s->IntrStatus |= PCSTimeout; + rtl8139_update_irq(s); + rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock)); } #endif /* RTL8139_ONBOARD_TIMER */ @@ -3357,10 +3401,9 @@ static int pci_rtl8139_init(PCIDevice *dev) s->cplus_txbuffer_offset = 0; #ifdef RTL8139_ONBOARD_TIMER + s->TimerExpire = 0; 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))); + rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock)); #endif /* RTL8139_ONBOARD_TIMER */ return 0; }