From: Anthony Liguori <anthony@codemonkey.ws>
To: Frediano Ziglio <freddy77@gmail.com>
Cc: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH] rewrote timer implementation for rtl8139.
Date: Sat, 20 Feb 2010 11:13:15 -0600 [thread overview]
Message-ID: <4B80182B.6040200@codemonkey.ws> (raw)
In-Reply-To: <1266681995-12315-1-git-send-email-freddy77@gmail.com>
On 02/20/2010 10:06 AM, Frediano Ziglio wrote:
> Add a QEMU timer only when needed (timeout status not set, timeout
> irq wanted and timer set).
>
> This patch is required for Darwin. Patch has been tested under
> FreeBSD, Darwin and Linux.
>
This is missing a Signed-off-by.
Regards,
Anthony Liguori
> ---
> hw/rtl8139.c | 139 +++++++++++++++++++++++++++++++++++-----------------------
> 1 files changed, 84 insertions(+), 55 deletions(-)
>
> diff --git a/hw/rtl8139.c b/hw/rtl8139.c
> index f04dd54..72e2242 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
> + *
> + * 2010-Feb-04 Frediano Ziglio: Rewrote timer support using QEMU timer only
> + * when strictly needed (required for for
> + * Darwin)
> */
>
> #include "hw.h"
> @@ -60,9 +64,6 @@
> /* Calculate CRCs properly on Rx packets */
> #define RTL8139_CALCULATE_RXCRC 1
>
> -/* Uncomment to enable on-board timer interrupts */
> -//#define RTL8139_ONBOARD_TIMER 1
> -
> #if defined(RTL8139_CALCULATE_RXCRC)
> /* For crc32 */
> #include<zlib.h>
> @@ -491,9 +492,12 @@ typedef struct RTL8139State {
>
> /* PCI interrupt timer */
> QEMUTimer *timer;
> + int64_t TimerExpire;
>
> } RTL8139State;
>
> +static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time);
> +
> static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
> {
> DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command));
> @@ -2522,7 +2526,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 +2561,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 +2755,46 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
> }
> }
>
> +static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time)
> +{
> + int64_t pci_time, next_time;
> + uint32_t low_pci;
> +
> + 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;
> + }
> +
> + pci_time = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
> + get_ticks_per_sec());
> + low_pci = pci_time& 0xffffffff;
> + pci_time = pci_time - low_pci + s->TimerInt;
> + if (low_pci>= s->TimerInt) {
> + pci_time += 0x100000000LL;
> + }
> + 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);
> + }
> +}
> +
> static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
> {
> RTL8139State *s = opaque;
> @@ -2784,13 +2840,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 +3059,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 +3165,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 +3173,24 @@ static int rtl8139_post_load(void *opaque, int version_id)
> return 0;
> }
>
> +static void rtl8139_pre_save(void *opaque)
> +{
> + RTL8139State* s = opaque;
> + int64_t current_time = qemu_get_clock(vm_clock);
> +
> + /* set IntrStatus correctly */
> + 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,59 +3304,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 */
>
> static void rtl8139_cleanup(VLANClientState *nc)
> {
> @@ -3301,10 +3335,8 @@ static int pci_rtl8139_uninit(PCIDevice *dev)
> qemu_free(s->cplus_txbuffer);
> s->cplus_txbuffer = NULL;
> }
> -#ifdef RTL8139_ONBOARD_TIMER
> qemu_del_timer(s->timer);
> qemu_free_timer(s->timer);
> -#endif
> qemu_del_vlan_client(&s->nic->nc);
> return 0;
> }
> @@ -3356,12 +3388,9 @@ static int pci_rtl8139_init(PCIDevice *dev)
> s->cplus_txbuffer_len = 0;
> 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)));
> -#endif /* RTL8139_ONBOARD_TIMER */
> + rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock));
> return 0;
> }
>
>
next prev parent reply other threads:[~2010-02-20 17:13 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-02-16 8:35 [Qemu-devel] [PATCH] rewrote timer implementation for rtl8139 Frediano Ziglio
2010-02-19 21:50 ` Anthony Liguori
2010-02-19 22:22 ` Alexander Graf
2010-02-19 23:26 ` Anthony Liguori
2010-02-20 5:52 ` Igor Kovalenko
2010-02-20 16:14 ` Frediano Ziglio
2010-02-20 16:06 ` Frediano Ziglio
2010-02-20 17:13 ` Anthony Liguori [this message]
2010-02-20 17:27 ` Frediano Ziglio
2010-02-25 14:24 ` Paul Brook
2010-02-20 17:50 ` Frediano Ziglio
2010-02-19 23:24 ` Anthony Liguori
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4B80182B.6040200@codemonkey.ws \
--to=anthony@codemonkey.ws \
--cc=freddy77@gmail.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).