qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Anthony Liguori <anthony@codemonkey.ws>
To: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH][RESEND] Time drift again.
Date: Thu, 15 Jan 2009 14:12:35 -0600	[thread overview]
Message-ID: <496F98B3.70900@codemonkey.ws> (raw)
In-Reply-To: <20090114115910.GR3267@redhat.com>

Gleb Natapov wrote:
> Hello,
>
>  After my last patch to fix interrupt coalescing was rejected
> on the basis that it is too intrusive we decided to make the
> fix much more localized and only fix the problem for RTC time
> source. Unfortunately it is impossible to fix the problem entirely
> inside RTC code like Andrzej proposed since Windows reads RTC
> register C more then once on each time interrupt so it is impossible
> to count reliably how many interrupt windows actually handled.
> Proposed solution is localized to I386 target and is disabled by
> default. To enable it "-rtc-td-hack" flag should be used.
>
> Signed-off-by: Gleb Natapov <gleb@redhat.com>
>   

Applied.  Thanks for all your work on this.  I know this has gone 
through a lot of iterations to come up with something that made everyone 
happy and the persistence is appreciated :-)

Regards,

Anthony Liguori

> diff --git a/hw/apic.c b/hw/apic.c
> index bad137f..3052843 100644
> --- a/hw/apic.c
> +++ b/hw/apic.c
> @@ -100,6 +100,8 @@ struct IOAPICState {
>  static int apic_io_memory;
>  static APICState *local_apics[MAX_APICS + 1];
>  static int last_apic_id = 0;
> +static int apic_irq_delivered;
> +
>  
>  static void apic_init_ipi(APICState *s);
>  static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
> @@ -133,6 +135,14 @@ static inline void reset_bit(uint32_t *tab, int index)
>      tab[i] &= ~mask;
>  }
>  
> +static inline int get_bit(uint32_t *tab, int index)
> +{
> +    int i, mask;
> +    i = index >> 5;
> +    mask = 1 << (index & 0x1f);
> +    return !!(tab[i] & mask);
> +}
> +
>  static void apic_local_deliver(CPUState *env, int vector)
>  {
>      APICState *s = env->apic_state;
> @@ -349,8 +359,20 @@ static void apic_update_irq(APICState *s)
>      cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
>  }
>  
> +void apic_reset_irq_delivered(void)
> +{
> +    apic_irq_delivered = 0;
> +}
> +
> +int apic_get_irq_delivered(void)
> +{
> +    return apic_irq_delivered;
> +}
> +
>  static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
>  {
> +    apic_irq_delivered += !get_bit(s->irr, vector_num);
> +
>      set_bit(s->irr, vector_num);
>      if (trigger_mode)
>          set_bit(s->tmr, vector_num);
> diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
> index faf847d..1c71bda 100644
> --- a/hw/mc146818rtc.c
> +++ b/hw/mc146818rtc.c
> @@ -66,6 +66,10 @@ struct RTCState {
>      int64_t next_periodic_time;
>      /* second update */
>      int64_t next_second_time;
> +#ifdef TARGET_I386
> +    uint32_t irq_coalesced;
> +    uint32_t period;
> +#endif
>      QEMUTimer *second_timer;
>      QEMUTimer *second_timer2;
>  };
> @@ -103,12 +107,20 @@ static void rtc_timer_update(RTCState *s, int64_t current_time)
>              period_code += 7;
>          /* period in 32 Khz cycles */
>          period = 1 << (period_code - 1);
> +#ifdef TARGET_I386
> +        if(period != s->period)
> +            s->irq_coalesced = (s->irq_coalesced * s->period) / period;
> +        s->period = period;
> +#endif
>          /* compute 32 khz clock */
>          cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
>          next_irq_clock = (cur_clock & ~(period - 1)) + period;
>          s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
>          qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
>      } else {
> +#ifdef TARGET_I386
> +        s->irq_coalesced = 0;
> +#endif
>          qemu_del_timer(s->periodic_timer);
>      }
>  }
> @@ -118,6 +130,12 @@ static void rtc_periodic_timer(void *opaque)
>      RTCState *s = opaque;
>  
>      rtc_timer_update(s, s->next_periodic_time);
> +#ifdef TARGET_I386
> +    if ((s->cmos_data[RTC_REG_C] & 0xc0) && rtc_td_hack) {
> +        s->irq_coalesced++;
> +        return;
> +    }
> +#endif
>      s->cmos_data[RTC_REG_C] |= 0xc0;
>      rtc_irq_raise(s->irq);
>  }
> @@ -378,6 +396,15 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
>          case RTC_REG_C:
>              ret = s->cmos_data[s->cmos_index];
>              qemu_irq_lower(s->irq);
> +#ifdef TARGET_I386
> +            if(s->irq_coalesced) {
> +                apic_reset_irq_delivered();
> +                qemu_irq_raise(s->irq);
> +                if (apic_get_irq_delivered())
> +                    s->irq_coalesced--;
> +                break;
> +            }
> +#endif
>              s->cmos_data[RTC_REG_C] = 0x00;
>              break;
>          default:
> @@ -472,6 +499,28 @@ static int rtc_load(QEMUFile *f, void *opaque, int version_id)
>      return 0;
>  }
>  
> +#ifdef TARGET_I386
> +static void rtc_save_td(QEMUFile *f, void *opaque)
> +{
> +    RTCState *s = opaque;
> +
> +    qemu_put_be32(f, s->irq_coalesced);
> +    qemu_put_be32(f, s->period);
> +}
> +
> +static int rtc_load_td(QEMUFile *f, void *opaque, int version_id)
> +{
> +    RTCState *s = opaque;
> +
> +    if (version_id != 1)
> +        return -EINVAL;
> +
> +    s->irq_coalesced = qemu_get_be32(f);
> +    s->period = qemu_get_be32(f);
> +    return 0;
> +}
> +#endif
> +
>  RTCState *rtc_init(int base, qemu_irq irq)
>  {
>      RTCState *s;
> @@ -502,6 +551,10 @@ RTCState *rtc_init(int base, qemu_irq irq)
>      register_ioport_read(base, 2, 1, cmos_ioport_read, s);
>  
>      register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
> +#ifdef TARGET_I386
> +    if (rtc_td_hack)
> +        register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
> +#endif
>      return s;
>  }
>  
> @@ -608,5 +661,9 @@ RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq)
>      cpu_register_physical_memory(base, 2 << it_shift, io_memory);
>  
>      register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
> +#ifdef TARGET_I386
> +    if (rtc_td_hack)
> +        register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
> +#endif
>      return s;
>  }
> diff --git a/hw/pc.h b/hw/pc.h
> index a60bddf..5dc7709 100644
> --- a/hw/pc.h
> +++ b/hw/pc.h
> @@ -46,6 +46,8 @@ void apic_deliver_pic_intr(CPUState *env, int level);
>  int apic_get_interrupt(CPUState *env);
>  IOAPICState *ioapic_init(void);
>  void ioapic_set_irq(void *opaque, int vector, int level);
> +void apic_reset_irq_delivered(void);
> +int apic_get_irq_delivered(void);
>  
>  /* i8254.c */
>  
> diff --git a/qemu-doc.texi b/qemu-doc.texi
> index 5a12dc9..f61ae34 100644
> --- a/qemu-doc.texi
> +++ b/qemu-doc.texi
> @@ -420,6 +420,11 @@ Use it when installing Windows 2000 to avoid a disk full bug. After
>  Windows 2000 is installed, you no longer need this option (this option
>  slows down the IDE transfers).
>  
> +@item -rtc-td-hack
> +Use it if you experience time drift problem in Windows with ACPI HAL.
> +This option will try to figure out how many timer interrupts were not
> +processed by the Windows guest and will re-inject them.
> +
>  @item -option-rom @var{file}
>  Load the contents of @var{file} as an option ROM.
>  This option is useful to load things like EtherBoot.
> diff --git a/sysemu.h b/sysemu.h
> index 47c1fea..a9e156c 100644
> --- a/sysemu.h
> +++ b/sysemu.h
> @@ -90,6 +90,7 @@ extern int graphic_depth;
>  extern int nographic;
>  extern const char *keyboard_layout;
>  extern int win2k_install_hack;
> +extern int rtc_td_hack;
>  extern int alt_grab;
>  extern int usb_enabled;
>  extern int smp_cpus;
> diff --git a/vl.c b/vl.c
> index e29072b..244d1c3 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -211,6 +211,7 @@ CharDriverState *serial_hds[MAX_SERIAL_PORTS];
>  CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
>  #ifdef TARGET_I386
>  int win2k_install_hack = 0;
> +int rtc_td_hack = 0;
>  #endif
>  int usb_enabled = 0;
>  int smp_cpus = 1;
> @@ -3877,6 +3878,7 @@ static void help(int exitcode)
>             "-full-screen    start in full screen\n"
>  #ifdef TARGET_I386
>             "-win2k-hack     use it when installing Windows 2000 to avoid a disk full bug\n"
> +           "-rtc-td-hack    use it to fix time drift in Windows ACPI HAL\n"
>  #endif
>             "-usb            enable the USB driver (will be the default soon)\n"
>             "-usbdevice name add the host or guest USB device 'name'\n"
> @@ -4072,6 +4074,7 @@ enum {
>      QEMU_OPTION_kernel_kqemu,
>      QEMU_OPTION_enable_kvm,
>      QEMU_OPTION_win2k_hack,
> +    QEMU_OPTION_rtc_td_hack,
>      QEMU_OPTION_usb,
>      QEMU_OPTION_usbdevice,
>      QEMU_OPTION_smp,
> @@ -4180,6 +4183,7 @@ static const QEMUOption qemu_options[] = {
>  #endif
>      { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
>      { "win2k-hack", 0, QEMU_OPTION_win2k_hack },
> +    { "rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack },
>      { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
>      { "smp", HAS_ARG, QEMU_OPTION_smp },
>      { "vnc", HAS_ARG, QEMU_OPTION_vnc },
> @@ -4993,6 +4997,9 @@ int main(int argc, char **argv, char **envp)
>              case QEMU_OPTION_win2k_hack:
>                  win2k_install_hack = 1;
>                  break;
> +            case QEMU_OPTION_rtc_td_hack:
> +                rtc_td_hack = 1;
> +                break;
>  #endif
>  #ifdef USE_KQEMU
>              case QEMU_OPTION_no_kqemu:
> --
> 			Gleb.
>
>
>   

      parent reply	other threads:[~2009-01-15 20:12 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-14 11:59 [Qemu-devel] [PATCH][RESEND] Time drift again Gleb Natapov
2009-01-14 17:02 ` Jamie Lokier
2009-01-14 17:34   ` Avi Kivity
2009-01-15 13:53   ` Marcelo Tosatti
2009-01-15 20:12 ` Anthony Liguori [this message]

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=496F98B3.70900@codemonkey.ws \
    --to=anthony@codemonkey.ws \
    --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).