[RFC,qemu,legoater/aspeed-3.1,1/4] timer: aspeed: Fire interrupt on failure to meet deadline

Message ID 20190111035638.19725-2-andrew@aj.id.au
State Not Applicable, archived
Headers show
Series
  • Handle short timer periods
Related show

Commit Message

Andrew Jeffery Jan. 11, 2019, 3:56 a.m.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
---
 hw/timer/aspeed_timer.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

Comments

Cédric Le Goater Jan. 11, 2019, 8:44 a.m. | #1
On 1/11/19 4:56 AM, Andrew Jeffery wrote:
> Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> ---
>  hw/timer/aspeed_timer.c | 14 ++++++++++----
>  1 file changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
> index 1a54d85e9d49..54c75bf4f322 100644
> --- a/hw/timer/aspeed_timer.c
> +++ b/hw/timer/aspeed_timer.c
> @@ -128,10 +128,16 @@ static uint64_t calculate_next(struct AspeedTimer *t)
>      if (now < next)
>          return next;
>  
> -    /* We've missed all of the deadlines. Set a timer in the future to let
> -     * execution catch up */
> -    t->start = now;
> -    return next + 10000;
> +    /* We've missed all deadlines, fire interrupt and try again */
> +    timer_del(&t->timer);
> +
> +    if (timer_overflow_interrupt(t)) {
> +        t->level = !t->level;
> +        qemu_set_irq(t->irq, t->level);
> +    }
> +
> +    t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    return calculate_time(t, MAX(MAX(t->match[0], t->match[1]), 0));

MAX(MAX()) ? 

Is that necessary ?

C.
Andrew Jeffery Jan. 11, 2019, 8:52 a.m. | #2
On Fri, 11 Jan 2019, at 19:14, Cédric Le Goater wrote:
> On 1/11/19 4:56 AM, Andrew Jeffery wrote:
> > Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> > ---
> >  hw/timer/aspeed_timer.c | 14 ++++++++++----
> >  1 file changed, 10 insertions(+), 4 deletions(-)
> > 
> > diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
> > index 1a54d85e9d49..54c75bf4f322 100644
> > --- a/hw/timer/aspeed_timer.c
> > +++ b/hw/timer/aspeed_timer.c
> > @@ -128,10 +128,16 @@ static uint64_t calculate_next(struct AspeedTimer *t)
> >      if (now < next)
> >          return next;
> >  
> > -    /* We've missed all of the deadlines. Set a timer in the future to let
> > -     * execution catch up */
> > -    t->start = now;
> > -    return next + 10000;
> > +    /* We've missed all deadlines, fire interrupt and try again */
> > +    timer_del(&t->timer);
> > +
> > +    if (timer_overflow_interrupt(t)) {
> > +        t->level = !t->level;
> > +        qemu_set_irq(t->irq, t->level);
> > +    }
> > +
> > +    t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> > +    return calculate_time(t, MAX(MAX(t->match[0], t->match[1]), 0));
> 
> MAX(MAX()) ? 
> 
> Is that necessary ?

No, just my wip internal reasoning getting exposed externally :)

> 
> C.

Patch

diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index 1a54d85e9d49..54c75bf4f322 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -128,10 +128,16 @@  static uint64_t calculate_next(struct AspeedTimer *t)
     if (now < next)
         return next;
 
-    /* We've missed all of the deadlines. Set a timer in the future to let
-     * execution catch up */
-    t->start = now;
-    return next + 10000;
+    /* We've missed all deadlines, fire interrupt and try again */
+    timer_del(&t->timer);
+
+    if (timer_overflow_interrupt(t)) {
+        t->level = !t->level;
+        qemu_set_irq(t->irq, t->level);
+    }
+
+    t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    return calculate_time(t, MAX(MAX(t->match[0], t->match[1]), 0));
 }
 
 static void aspeed_timer_mod(AspeedTimer *t)