All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/3] mips: Handle late r4k timers
@ 2011-01-17 23:29 edgar.iglesias
  2011-01-17 23:29 ` [Qemu-devel] [PATCH 1/3] mips: Break TBs after mfc0_count edgar.iglesias
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: edgar.iglesias @ 2011-01-17 23:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, aurelien

From: Edgar E. Iglesias <edgar.iglesias@gmail.com>

Linux runs a test to check if the internal r4k timer is usable prior
to enabling it. The test basically starts a timer, repeatedly
compares cp0_count with cp0_compare and finally when the
timer should have hit it verifies that the irq line is asserted.
Depending on host timing, qemu may fail this test. On my x86_64 host,
we basically always fail it.

The following set of patches makes qemu pass the test reliably.

Edgar E. Iglesias (3):
  mips: Break TBs after mfc0_count
  mips: Break out cpu_mips_timer_expire
  mips: Expire late timers when reading cp0_count

 hw/mips_timer.c         |   43 +++++++++++++++++++++++++++++--------------
 target-mips/translate.c |    4 +++-
 2 files changed, 32 insertions(+), 15 deletions(-)

-- 
1.7.2.2

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 1/3] mips: Break TBs after mfc0_count
  2011-01-17 23:29 [Qemu-devel] [PATCH 0/3] mips: Handle late r4k timers edgar.iglesias
@ 2011-01-17 23:29 ` edgar.iglesias
  2011-01-18 10:34   ` Aurelien Jarno
  2011-01-17 23:29 ` [Qemu-devel] [PATCH 2/3] mips: Break out cpu_mips_timer_expire edgar.iglesias
  2011-01-17 23:29 ` [Qemu-devel] [PATCH 3/3] mips: Expire late timers when reading cp0_count edgar.iglesias
  2 siblings, 1 reply; 12+ messages in thread
From: edgar.iglesias @ 2011-01-17 23:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, aurelien

From: Edgar E. Iglesias <edgar.iglesias@gmail.com>

Break the TB after reading the count register. This makes it
possible to take timer interrupts immediately after a read of
a possibly expired timer.

Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
---
 target-mips/translate.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/target-mips/translate.c b/target-mips/translate.c
index cce77be..313cc29 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -3410,8 +3410,10 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
             gen_helper_mfc0_count(arg);
             if (use_icount) {
                 gen_io_end();
-                ctx->bstate = BS_STOP;
             }
+            /* Break the TB to be able to take timer interrupts immediately
+               after reading count.  */
+            ctx->bstate = BS_STOP;
             rn = "Count";
             break;
         /* 6,7 are implementation dependent */
-- 
1.7.2.2

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 2/3] mips: Break out cpu_mips_timer_expire
  2011-01-17 23:29 [Qemu-devel] [PATCH 0/3] mips: Handle late r4k timers edgar.iglesias
  2011-01-17 23:29 ` [Qemu-devel] [PATCH 1/3] mips: Break TBs after mfc0_count edgar.iglesias
@ 2011-01-17 23:29 ` edgar.iglesias
  2011-01-18 10:35   ` [Qemu-devel] " Aurelien Jarno
  2011-01-17 23:29 ` [Qemu-devel] [PATCH 3/3] mips: Expire late timers when reading cp0_count edgar.iglesias
  2 siblings, 1 reply; 12+ messages in thread
From: edgar.iglesias @ 2011-01-17 23:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, aurelien

From: Edgar E. Iglesias <edgar.iglesias@gmail.com>

Reorganize for future patches, no functional change.

Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
---
 hw/mips_timer.c |   36 ++++++++++++++++++++++--------------
 1 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/hw/mips_timer.c b/hw/mips_timer.c
index e3beee8..8c32087 100644
--- a/hw/mips_timer.c
+++ b/hw/mips_timer.c
@@ -42,16 +42,6 @@ uint32_t cpu_mips_get_random (CPUState *env)
 }
 
 /* MIPS R4K timer */
-uint32_t cpu_mips_get_count (CPUState *env)
-{
-    if (env->CP0_Cause & (1 << CP0Ca_DC))
-        return env->CP0_Count;
-    else
-        return env->CP0_Count +
-            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
-                               TIMER_FREQ, get_ticks_per_sec());
-}
-
 static void cpu_mips_timer_update(CPUState *env)
 {
     uint64_t now, next;
@@ -64,6 +54,27 @@ static void cpu_mips_timer_update(CPUState *env)
     qemu_mod_timer(env->timer, next);
 }
 
+/* Expire the timer.  */
+static void cpu_mips_timer_expire(CPUState *env)
+{
+    cpu_mips_timer_update(env);
+    if (env->insn_flags & ISA_MIPS32R2) {
+        env->CP0_Cause |= 1 << CP0Ca_TI;
+    }
+    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
+}
+
+uint32_t cpu_mips_get_count (CPUState *env)
+{
+    if (env->CP0_Cause & (1 << CP0Ca_DC)) {
+        return env->CP0_Count;
+    } else {
+        return env->CP0_Count +
+            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
+                               TIMER_FREQ, get_ticks_per_sec());
+    }
+}
+
 void cpu_mips_store_count (CPUState *env, uint32_t count)
 {
     if (env->CP0_Cause & (1 << CP0Ca_DC))
@@ -116,11 +127,8 @@ static void mips_timer_cb (void *opaque)
        the comparator value.  Offset the count by one to avoid immediately
        retriggering the callback before any virtual time has passed.  */
     env->CP0_Count++;
-    cpu_mips_timer_update(env);
+    cpu_mips_timer_expire(env);
     env->CP0_Count--;
-    if (env->insn_flags & ISA_MIPS32R2)
-        env->CP0_Cause |= 1 << CP0Ca_TI;
-    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
 }
 
 void cpu_mips_clock_init (CPUState *env)
-- 
1.7.2.2

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH 3/3] mips: Expire late timers when reading cp0_count
  2011-01-17 23:29 [Qemu-devel] [PATCH 0/3] mips: Handle late r4k timers edgar.iglesias
  2011-01-17 23:29 ` [Qemu-devel] [PATCH 1/3] mips: Break TBs after mfc0_count edgar.iglesias
  2011-01-17 23:29 ` [Qemu-devel] [PATCH 2/3] mips: Break out cpu_mips_timer_expire edgar.iglesias
@ 2011-01-17 23:29 ` edgar.iglesias
  2011-01-18  0:33   ` [Qemu-devel] " Edgar E. Iglesias
  2 siblings, 1 reply; 12+ messages in thread
From: edgar.iglesias @ 2011-01-17 23:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, aurelien

From: Edgar E. Iglesias <edgar.iglesias@gmail.com>

When reading cp0_count from a timer with a late trigger that should
already have expired, expire it and raise the timer irq.

This makes it possible for guest code (e.g, Linux) that first read
cp0_count, then compare it with cp0_compare and check for raised
timer interrupt lines to run reliably.

Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
---
 hw/mips_timer.c |   11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/hw/mips_timer.c b/hw/mips_timer.c
index 8c32087..4e5c0b5 100644
--- a/hw/mips_timer.c
+++ b/hw/mips_timer.c
@@ -69,9 +69,16 @@ uint32_t cpu_mips_get_count (CPUState *env)
     if (env->CP0_Cause & (1 << CP0Ca_DC)) {
         return env->CP0_Count;
     } else {
+        uint64_t now;
+
+        now = qemu_get_clock(vm_clock);
+        if (qemu_timer_expired(env->timer, now)) {
+            /* The timer has already expired.  */
+            cpu_mips_timer_expire(env);
+        }
+
         return env->CP0_Count +
-            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
-                               TIMER_FREQ, get_ticks_per_sec());
+            (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
     }
 }
 
-- 
1.7.2.2

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] Re: [PATCH 3/3] mips: Expire late timers when reading cp0_count
  2011-01-17 23:29 ` [Qemu-devel] [PATCH 3/3] mips: Expire late timers when reading cp0_count edgar.iglesias
@ 2011-01-18  0:33   ` Edgar E. Iglesias
  2011-01-18 10:36     ` Aurelien Jarno
  0 siblings, 1 reply; 12+ messages in thread
From: Edgar E. Iglesias @ 2011-01-18  0:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: aurelien

On Tue, Jan 18, 2011 at 12:29:42AM +0100, edgar.iglesias@gmail.com wrote:
> From: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> 
> When reading cp0_count from a timer with a late trigger that should
> already have expired, expire it and raise the timer irq.
> 
> This makes it possible for guest code (e.g, Linux) that first read
> cp0_count, then compare it with cp0_compare and check for raised
> timer interrupt lines to run reliably.
> 
> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>

Sorry sent the wrong version of this one. It's supposed to be the
following:

commit 139330de404209528712fd703952c0b5ad4459a1
Author: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Date:   Tue Jan 18 00:12:22 2011 +0100

    mips: Expire late timers when reading cp0_count
    
    When reading cp0_count from a timer with a late trigger that should
    already have expired, expire it and raise the timer irq.
    
    This makes it possible for guest code (e.g, Linux) that first read
    cp0_count, then compare it with cp0_compare and check for raised
    timer interrupt lines to run reliably.
    
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>

diff --git a/hw/mips_timer.c b/hw/mips_timer.c
index 8c32087..9c95f28 100644
--- a/hw/mips_timer.c
+++ b/hw/mips_timer.c
@@ -69,9 +69,17 @@ uint32_t cpu_mips_get_count (CPUState *env)
     if (env->CP0_Cause & (1 << CP0Ca_DC)) {
         return env->CP0_Count;
     } else {
+        uint64_t now;
+
+        now = qemu_get_clock(vm_clock);
+        if (qemu_timer_pending(env->timer)
+            && qemu_timer_expired(env->timer, now)) {
+            /* The timer has already expired.  */
+            cpu_mips_timer_expire(env);
+        }
+
         return env->CP0_Count +
-            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
-                               TIMER_FREQ, get_ticks_per_sec());
+            (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
     }
 }
 
 

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH 1/3] mips: Break TBs after mfc0_count
  2011-01-17 23:29 ` [Qemu-devel] [PATCH 1/3] mips: Break TBs after mfc0_count edgar.iglesias
@ 2011-01-18 10:34   ` Aurelien Jarno
  2011-01-18 10:43     ` Edgar E. Iglesias
  2011-01-18 11:50     ` Edgar E. Iglesias
  0 siblings, 2 replies; 12+ messages in thread
From: Aurelien Jarno @ 2011-01-18 10:34 UTC (permalink / raw)
  To: edgar.iglesias; +Cc: qemu-devel

On Tue, Jan 18, 2011 at 12:29:40AM +0100, edgar.iglesias@gmail.com wrote:
> From: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> 
> Break the TB after reading the count register. This makes it
> possible to take timer interrupts immediately after a read of
> a possibly expired timer.
> 
> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> ---
>  target-mips/translate.c |    4 +++-
>  1 files changed, 3 insertions(+), 1 deletions(-)
> 
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index cce77be..313cc29 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -3410,8 +3410,10 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
>              gen_helper_mfc0_count(arg);
>              if (use_icount) {
>                  gen_io_end();
> -                ctx->bstate = BS_STOP;
>              }
> +            /* Break the TB to be able to take timer interrupts immediately
> +               after reading count.  */
> +            ctx->bstate = BS_STOP;
>              rn = "Count";
>              break;
>          /* 6,7 are implementation dependent */

This looks fine, however it should probably be done the same way for
dmfc0 on 64-bit MIPS.

-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Qemu-devel] Re: [PATCH 2/3] mips: Break out cpu_mips_timer_expire
  2011-01-17 23:29 ` [Qemu-devel] [PATCH 2/3] mips: Break out cpu_mips_timer_expire edgar.iglesias
@ 2011-01-18 10:35   ` Aurelien Jarno
  0 siblings, 0 replies; 12+ messages in thread
From: Aurelien Jarno @ 2011-01-18 10:35 UTC (permalink / raw)
  To: edgar.iglesias; +Cc: qemu-devel

On Tue, Jan 18, 2011 at 12:29:41AM +0100, edgar.iglesias@gmail.com wrote:
> From: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> 
> Reorganize for future patches, no functional change.
> 
> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> ---
>  hw/mips_timer.c |   36 ++++++++++++++++++++++--------------
>  1 files changed, 22 insertions(+), 14 deletions(-)
> 
> diff --git a/hw/mips_timer.c b/hw/mips_timer.c
> index e3beee8..8c32087 100644
> --- a/hw/mips_timer.c
> +++ b/hw/mips_timer.c
> @@ -42,16 +42,6 @@ uint32_t cpu_mips_get_random (CPUState *env)
>  }
>  
>  /* MIPS R4K timer */
> -uint32_t cpu_mips_get_count (CPUState *env)
> -{
> -    if (env->CP0_Cause & (1 << CP0Ca_DC))
> -        return env->CP0_Count;
> -    else
> -        return env->CP0_Count +
> -            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
> -                               TIMER_FREQ, get_ticks_per_sec());
> -}
> -
>  static void cpu_mips_timer_update(CPUState *env)
>  {
>      uint64_t now, next;
> @@ -64,6 +54,27 @@ static void cpu_mips_timer_update(CPUState *env)
>      qemu_mod_timer(env->timer, next);
>  }
>  
> +/* Expire the timer.  */
> +static void cpu_mips_timer_expire(CPUState *env)
> +{
> +    cpu_mips_timer_update(env);
> +    if (env->insn_flags & ISA_MIPS32R2) {
> +        env->CP0_Cause |= 1 << CP0Ca_TI;
> +    }
> +    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
> +}
> +
> +uint32_t cpu_mips_get_count (CPUState *env)
> +{
> +    if (env->CP0_Cause & (1 << CP0Ca_DC)) {
> +        return env->CP0_Count;
> +    } else {
> +        return env->CP0_Count +
> +            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
> +                               TIMER_FREQ, get_ticks_per_sec());
> +    }
> +}
> +
>  void cpu_mips_store_count (CPUState *env, uint32_t count)
>  {
>      if (env->CP0_Cause & (1 << CP0Ca_DC))
> @@ -116,11 +127,8 @@ static void mips_timer_cb (void *opaque)
>         the comparator value.  Offset the count by one to avoid immediately
>         retriggering the callback before any virtual time has passed.  */
>      env->CP0_Count++;
> -    cpu_mips_timer_update(env);
> +    cpu_mips_timer_expire(env);
>      env->CP0_Count--;
> -    if (env->insn_flags & ISA_MIPS32R2)
> -        env->CP0_Cause |= 1 << CP0Ca_TI;
> -    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
>  }
>  
>  void cpu_mips_clock_init (CPUState *env)
> -- 
> 1.7.2.2
> 
> 

Acked-by: Aurelien Jarno <aurelien@aurel32.net>

-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] Re: [PATCH 3/3] mips: Expire late timers when reading cp0_count
  2011-01-18  0:33   ` [Qemu-devel] " Edgar E. Iglesias
@ 2011-01-18 10:36     ` Aurelien Jarno
  2011-01-18 10:41       ` Edgar E. Iglesias
  0 siblings, 1 reply; 12+ messages in thread
From: Aurelien Jarno @ 2011-01-18 10:36 UTC (permalink / raw)
  To: Edgar E. Iglesias; +Cc: qemu-devel

On Tue, Jan 18, 2011 at 01:33:00AM +0100, Edgar E. Iglesias wrote:
> On Tue, Jan 18, 2011 at 12:29:42AM +0100, edgar.iglesias@gmail.com wrote:
> > From: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > 
> > When reading cp0_count from a timer with a late trigger that should
> > already have expired, expire it and raise the timer irq.
> > 
> > This makes it possible for guest code (e.g, Linux) that first read
> > cp0_count, then compare it with cp0_compare and check for raised
> > timer interrupt lines to run reliably.
> > 
> > Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> 
> Sorry sent the wrong version of this one. It's supposed to be the
> following:
> 
> commit 139330de404209528712fd703952c0b5ad4459a1
> Author: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> Date:   Tue Jan 18 00:12:22 2011 +0100
> 
>     mips: Expire late timers when reading cp0_count
>     
>     When reading cp0_count from a timer with a late trigger that should
>     already have expired, expire it and raise the timer irq.
>     
>     This makes it possible for guest code (e.g, Linux) that first read
>     cp0_count, then compare it with cp0_compare and check for raised
>     timer interrupt lines to run reliably.
>     
>     Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> 
> diff --git a/hw/mips_timer.c b/hw/mips_timer.c
> index 8c32087..9c95f28 100644
> --- a/hw/mips_timer.c
> +++ b/hw/mips_timer.c
> @@ -69,9 +69,17 @@ uint32_t cpu_mips_get_count (CPUState *env)
>      if (env->CP0_Cause & (1 << CP0Ca_DC)) {
>          return env->CP0_Count;
>      } else {
> +        uint64_t now;
> +
> +        now = qemu_get_clock(vm_clock);
> +        if (qemu_timer_pending(env->timer)
> +            && qemu_timer_expired(env->timer, now)) {
> +            /* The timer has already expired.  */
> +            cpu_mips_timer_expire(env);
> +        }
> +
>          return env->CP0_Count +
> -            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
> -                               TIMER_FREQ, get_ticks_per_sec());
> +            (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
>      }
>  }
>  

Given the TB is now ended after this instruction (due to patch 1), isn't
the interrupt handled before starting the next TB, where the interrupt
line (I guess CP0_Cause) read?

-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] Re: [PATCH 3/3] mips: Expire late timers when reading cp0_count
  2011-01-18 10:36     ` Aurelien Jarno
@ 2011-01-18 10:41       ` Edgar E. Iglesias
  2011-01-18 10:52         ` Aurelien Jarno
  0 siblings, 1 reply; 12+ messages in thread
From: Edgar E. Iglesias @ 2011-01-18 10:41 UTC (permalink / raw)
  To: Aurelien Jarno; +Cc: qemu-devel

On Tue, Jan 18, 2011 at 11:36:25AM +0100, Aurelien Jarno wrote:
> On Tue, Jan 18, 2011 at 01:33:00AM +0100, Edgar E. Iglesias wrote:
> > On Tue, Jan 18, 2011 at 12:29:42AM +0100, edgar.iglesias@gmail.com wrote:
> > > From: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > > 
> > > When reading cp0_count from a timer with a late trigger that should
> > > already have expired, expire it and raise the timer irq.
> > > 
> > > This makes it possible for guest code (e.g, Linux) that first read
> > > cp0_count, then compare it with cp0_compare and check for raised
> > > timer interrupt lines to run reliably.
> > > 
> > > Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > 
> > Sorry sent the wrong version of this one. It's supposed to be the
> > following:
> > 
> > commit 139330de404209528712fd703952c0b5ad4459a1
> > Author: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > Date:   Tue Jan 18 00:12:22 2011 +0100
> > 
> >     mips: Expire late timers when reading cp0_count
> >     
> >     When reading cp0_count from a timer with a late trigger that should
> >     already have expired, expire it and raise the timer irq.
> >     
> >     This makes it possible for guest code (e.g, Linux) that first read
> >     cp0_count, then compare it with cp0_compare and check for raised
> >     timer interrupt lines to run reliably.
> >     
> >     Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > 
> > diff --git a/hw/mips_timer.c b/hw/mips_timer.c
> > index 8c32087..9c95f28 100644
> > --- a/hw/mips_timer.c
> > +++ b/hw/mips_timer.c
> > @@ -69,9 +69,17 @@ uint32_t cpu_mips_get_count (CPUState *env)
> >      if (env->CP0_Cause & (1 << CP0Ca_DC)) {
> >          return env->CP0_Count;
> >      } else {
> > +        uint64_t now;
> > +
> > +        now = qemu_get_clock(vm_clock);
> > +        if (qemu_timer_pending(env->timer)
> > +            && qemu_timer_expired(env->timer, now)) {
> > +            /* The timer has already expired.  */
> > +            cpu_mips_timer_expire(env);
> > +        }
> > +
> >          return env->CP0_Count +
> > -            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
> > -                               TIMER_FREQ, get_ticks_per_sec());
> > +            (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
> >      }
> >  }
> >  
> 
> Given the TB is now ended after this instruction (due to patch 1), isn't
> the interrupt handled before starting the next TB, where the interrupt
> line (I guess CP0_Cause) read?

Hi,

The problem here is different. Due to host timing granularity, the
timer might expire later than it's precise scheduled time. If that
happens, get_count will return a count value that goes beyond the
trigger time but the interrupt may come later (when the host timer
expires).

This patch catches that case and expires the timer in-band, raising
the timer interrupt if needed.

Cheers

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH 1/3] mips: Break TBs after mfc0_count
  2011-01-18 10:34   ` Aurelien Jarno
@ 2011-01-18 10:43     ` Edgar E. Iglesias
  2011-01-18 11:50     ` Edgar E. Iglesias
  1 sibling, 0 replies; 12+ messages in thread
From: Edgar E. Iglesias @ 2011-01-18 10:43 UTC (permalink / raw)
  To: Aurelien Jarno; +Cc: qemu-devel

On Tue, Jan 18, 2011 at 11:34:28AM +0100, Aurelien Jarno wrote:
> On Tue, Jan 18, 2011 at 12:29:40AM +0100, edgar.iglesias@gmail.com wrote:
> > From: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > 
> > Break the TB after reading the count register. This makes it
> > possible to take timer interrupts immediately after a read of
> > a possibly expired timer.
> > 
> > Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > ---
> >  target-mips/translate.c |    4 +++-
> >  1 files changed, 3 insertions(+), 1 deletions(-)
> > 
> > diff --git a/target-mips/translate.c b/target-mips/translate.c
> > index cce77be..313cc29 100644
> > --- a/target-mips/translate.c
> > +++ b/target-mips/translate.c
> > @@ -3410,8 +3410,10 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
> >              gen_helper_mfc0_count(arg);
> >              if (use_icount) {
> >                  gen_io_end();
> > -                ctx->bstate = BS_STOP;
> >              }
> > +            /* Break the TB to be able to take timer interrupts immediately
> > +               after reading count.  */
> > +            ctx->bstate = BS_STOP;
> >              rn = "Count";
> >              break;
> >          /* 6,7 are implementation dependent */
> 
> This looks fine, however it should probably be done the same way for
> dmfc0 on 64-bit MIPS.

You're right, I'll fix that. Thanks.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] Re: [PATCH 3/3] mips: Expire late timers when reading cp0_count
  2011-01-18 10:41       ` Edgar E. Iglesias
@ 2011-01-18 10:52         ` Aurelien Jarno
  0 siblings, 0 replies; 12+ messages in thread
From: Aurelien Jarno @ 2011-01-18 10:52 UTC (permalink / raw)
  To: Edgar E. Iglesias; +Cc: qemu-devel

On Tue, Jan 18, 2011 at 11:41:54AM +0100, Edgar E. Iglesias wrote:
> On Tue, Jan 18, 2011 at 11:36:25AM +0100, Aurelien Jarno wrote:
> > On Tue, Jan 18, 2011 at 01:33:00AM +0100, Edgar E. Iglesias wrote:
> > > On Tue, Jan 18, 2011 at 12:29:42AM +0100, edgar.iglesias@gmail.com wrote:
> > > > From: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > > > 
> > > > When reading cp0_count from a timer with a late trigger that should
> > > > already have expired, expire it and raise the timer irq.
> > > > 
> > > > This makes it possible for guest code (e.g, Linux) that first read
> > > > cp0_count, then compare it with cp0_compare and check for raised
> > > > timer interrupt lines to run reliably.
> > > > 
> > > > Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > > 
> > > Sorry sent the wrong version of this one. It's supposed to be the
> > > following:
> > > 
> > > commit 139330de404209528712fd703952c0b5ad4459a1
> > > Author: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > > Date:   Tue Jan 18 00:12:22 2011 +0100
> > > 
> > >     mips: Expire late timers when reading cp0_count
> > >     
> > >     When reading cp0_count from a timer with a late trigger that should
> > >     already have expired, expire it and raise the timer irq.
> > >     
> > >     This makes it possible for guest code (e.g, Linux) that first read
> > >     cp0_count, then compare it with cp0_compare and check for raised
> > >     timer interrupt lines to run reliably.
> > >     
> > >     Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > > 
> > > diff --git a/hw/mips_timer.c b/hw/mips_timer.c
> > > index 8c32087..9c95f28 100644
> > > --- a/hw/mips_timer.c
> > > +++ b/hw/mips_timer.c
> > > @@ -69,9 +69,17 @@ uint32_t cpu_mips_get_count (CPUState *env)
> > >      if (env->CP0_Cause & (1 << CP0Ca_DC)) {
> > >          return env->CP0_Count;
> > >      } else {
> > > +        uint64_t now;
> > > +
> > > +        now = qemu_get_clock(vm_clock);
> > > +        if (qemu_timer_pending(env->timer)
> > > +            && qemu_timer_expired(env->timer, now)) {
> > > +            /* The timer has already expired.  */
> > > +            cpu_mips_timer_expire(env);
> > > +        }
> > > +
> > >          return env->CP0_Count +
> > > -            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
> > > -                               TIMER_FREQ, get_ticks_per_sec());
> > > +            (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
> > >      }
> > >  }
> > >  
> > 
> > Given the TB is now ended after this instruction (due to patch 1), isn't
> > the interrupt handled before starting the next TB, where the interrupt
> > line (I guess CP0_Cause) read?
> 
> Hi,
> 
> The problem here is different. Due to host timing granularity, the
> timer might expire later than it's precise scheduled time. If that
> happens, get_count will return a count value that goes beyond the
> trigger time but the interrupt may come later (when the host timer
> expires).
> 
> This patch catches that case and expires the timer in-band, raising
> the timer interrupt if needed.
> 

Ok, thanks for the explanation.

Acked-by: Aurelien Jarno <aurelien@aurel32.net>


-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH 1/3] mips: Break TBs after mfc0_count
  2011-01-18 10:34   ` Aurelien Jarno
  2011-01-18 10:43     ` Edgar E. Iglesias
@ 2011-01-18 11:50     ` Edgar E. Iglesias
  1 sibling, 0 replies; 12+ messages in thread
From: Edgar E. Iglesias @ 2011-01-18 11:50 UTC (permalink / raw)
  To: Aurelien Jarno; +Cc: qemu-devel

On Tue, Jan 18, 2011 at 11:34:28AM +0100, Aurelien Jarno wrote:
> On Tue, Jan 18, 2011 at 12:29:40AM +0100, edgar.iglesias@gmail.com wrote:
> > From: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > 
> > Break the TB after reading the count register. This makes it
> > possible to take timer interrupts immediately after a read of
> > a possibly expired timer.
> > 
> > Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> > ---
> >  target-mips/translate.c |    4 +++-
> >  1 files changed, 3 insertions(+), 1 deletions(-)
> > 
> > diff --git a/target-mips/translate.c b/target-mips/translate.c
> > index cce77be..313cc29 100644
> > --- a/target-mips/translate.c
> > +++ b/target-mips/translate.c
> > @@ -3410,8 +3410,10 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
> >              gen_helper_mfc0_count(arg);
> >              if (use_icount) {
> >                  gen_io_end();
> > -                ctx->bstate = BS_STOP;
> >              }
> > +            /* Break the TB to be able to take timer interrupts immediately
> > +               after reading count.  */
> > +            ctx->bstate = BS_STOP;
> >              rn = "Count";
> >              break;
> >          /* 6,7 are implementation dependent */
> 
> This looks fine, however it should probably be done the same way for
> dmfc0 on 64-bit MIPS.

Thanks for the quick review, I've pushed the series with this
suggested change.

Cheers

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-01-18 11:50 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-17 23:29 [Qemu-devel] [PATCH 0/3] mips: Handle late r4k timers edgar.iglesias
2011-01-17 23:29 ` [Qemu-devel] [PATCH 1/3] mips: Break TBs after mfc0_count edgar.iglesias
2011-01-18 10:34   ` Aurelien Jarno
2011-01-18 10:43     ` Edgar E. Iglesias
2011-01-18 11:50     ` Edgar E. Iglesias
2011-01-17 23:29 ` [Qemu-devel] [PATCH 2/3] mips: Break out cpu_mips_timer_expire edgar.iglesias
2011-01-18 10:35   ` [Qemu-devel] " Aurelien Jarno
2011-01-17 23:29 ` [Qemu-devel] [PATCH 3/3] mips: Expire late timers when reading cp0_count edgar.iglesias
2011-01-18  0:33   ` [Qemu-devel] " Edgar E. Iglesias
2011-01-18 10:36     ` Aurelien Jarno
2011-01-18 10:41       ` Edgar E. Iglesias
2011-01-18 10:52         ` Aurelien Jarno

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.