qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Igor V. Kovalenko" <igor.v.kovalenko@gmail.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH 9/9] sparc64: reimplement tick timers
Date: Thu, 07 Jan 2010 23:28:36 +0300	[thread overview]
Message-ID: <20100107202836.16653.88450.stgit@skyserv> (raw)
In-Reply-To: <20100107201810.16653.85771.stgit@skyserv>

From: Igor V. Kovalenko <igor.v.kovalenko@gmail.com>

sparc64 timer has tick counter which can be set and read,
and tick compare value used as deadline to fire timer interrupt.
The timer is not used as periodic timer, instead deadline
is set each time new timer interrupt is needed.

This change implements sparc64 timers without
periodic timers. It is not complete yet,
cpu_tick_set_count does not really set counter value.

Signed-off-by: Igor V. Kovalenko <igor.v.kovalenko@gmail.com>
---
 hw/sun4u.c |  176 ++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 146 insertions(+), 30 deletions(-)

diff --git a/hw/sun4u.c b/hw/sun4u.c
index ae32878..565b25d 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -40,6 +40,7 @@
 
 //#define DEBUG_IRQ
 //#define DEBUG_EBUS
+//#define DEBUG_TIMER
 
 #ifdef DEBUG_IRQ
 #define CPUIRQ_DPRINTF(fmt, ...)                                \
@@ -55,6 +56,13 @@
 #define EBUS_DPRINTF(fmt, ...)
 #endif
 
+#ifdef DEBUG_TIMER
+#define TIMER_DPRINTF(fmt, ...)                                  \
+    do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define TIMER_DPRINTF(fmt, ...)
+#endif
+
 #define KERNEL_LOAD_ADDR     0x00404000
 #define CMDLINE_ADDR         0x003ff000
 #define INITRD_LOAD_ADDR     0x00300000
@@ -280,6 +288,12 @@ void cpu_check_irqs(CPUState *env)
     }
 }
 
+static void cpu_kick_irq(CPUState *env)
+{
+    env->halted = 0;
+    cpu_check_irqs(env);
+}
+
 static void cpu_set_irq(void *opaque, int irq, int level)
 {
     CPUState *env = opaque;
@@ -301,6 +315,41 @@ typedef struct ResetData {
     uint64_t prom_addr;
 } ResetData;
 
+struct sun4u_timer
+{
+    const char *name;
+    uint32_t    frequency;
+    int      disabled;
+    uint64_t disabled_mask;
+    QEMUTimer *qtimer;
+};
+
+typedef struct sun4u_timer sun4u_timer;
+
+static sun4u_timer* sun4u_timer_create(const char* name, CPUState *env,
+                                       QEMUBHFunc *cb, uint32_t frequency,
+                                       uint64_t disabled_mask)
+{
+    sun4u_timer *timer;
+
+    timer = qemu_mallocz(sizeof (sun4u_timer));
+
+    timer->name = name;
+    timer->frequency = frequency;
+    timer->disabled = 1;
+    timer->disabled_mask = disabled_mask;
+
+    timer->qtimer = qemu_new_timer(vm_clock, cb, env);
+
+    return timer;
+}
+
+static void sun4u_timer_reset(sun4u_timer *timer)
+{
+    timer->disabled = 1;
+    qemu_del_timer(timer->qtimer);
+}
+
 static void main_cpu_reset(void *opaque)
 {
     ResetData *s = (ResetData *)opaque;
@@ -308,15 +357,11 @@ static void main_cpu_reset(void *opaque)
     static unsigned int nr_resets;
 
     cpu_reset(env);
-    env->tick_cmpr = TICK_INT_DIS | 0;
-    ptimer_set_limit(env->tick, TICK_MAX, 1);
-    ptimer_run(env->tick, 1);
-    env->stick_cmpr = TICK_INT_DIS | 0;
-    ptimer_set_limit(env->stick, TICK_MAX, 1);
-    ptimer_run(env->stick, 1);
-    env->hstick_cmpr = TICK_INT_DIS | 0;
-    ptimer_set_limit(env->hstick, TICK_MAX, 1);
-    ptimer_run(env->hstick, 1);
+
+    sun4u_timer_reset(env->tick);
+    sun4u_timer_reset(env->stick);
+    sun4u_timer_reset(env->hstick);
+
     env->gregs[1] = 0; // Memory start
     env->gregs[2] = ram_size; // Memory size
     env->gregs[3] = 0; // Machine description XXX
@@ -333,44 +378,114 @@ static void tick_irq(void *opaque)
 {
     CPUState *env = opaque;
 
-    if (!(env->tick_cmpr & TICK_INT_DIS)) {
-        env->softint |= SOFTINT_TIMER;
-        cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+    sun4u_timer* timer = (sun4u_timer*) env->tick;
+
+    if (timer->disabled) {
+        CPUIRQ_DPRINTF("tick_irq: softint disabled\n");
+        return;
+    } else {
+        CPUIRQ_DPRINTF("tick: fire\n");
     }
+
+    env->softint |= SOFTINT_TIMER;
+    cpu_kick_irq(env);
 }
 
 static void stick_irq(void *opaque)
 {
     CPUState *env = opaque;
 
-    if (!(env->stick_cmpr & TICK_INT_DIS)) {
-        env->softint |= SOFTINT_STIMER;
-        cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+    sun4u_timer* timer = (sun4u_timer*) env->stick;
+
+    if (timer->disabled) {
+        CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
+        return;
+    } else {
+        CPUIRQ_DPRINTF("stick: fire\n");
     }
+
+    env->softint |= SOFTINT_STIMER;
+    cpu_kick_irq(env);
 }
 
 static void hstick_irq(void *opaque)
 {
     CPUState *env = opaque;
 
-    if (!(env->hstick_cmpr & TICK_INT_DIS)) {
-        cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+    sun4u_timer* timer = (sun4u_timer*) env->hstick;
+
+    if (timer->disabled) {
+        CPUIRQ_DPRINTF("hstick_irq: softint disabled\n");
+        return;
+    } else {
+        CPUIRQ_DPRINTF("hstick: fire\n");
     }
+
+    env->softint |= SOFTINT_STIMER;
+    cpu_kick_irq(env);
 }
 
 void cpu_tick_set_count(void *opaque, uint64_t count)
 {
-    ptimer_set_count(opaque, -count);
+    sun4u_timer *timer = opaque;
+
+    uint64_t real_count = count & ~timer->disabled_mask;
+    timer->disabled = (count & timer->disabled_mask) ? 1 : 0;
+
+    TIMER_DPRINTF("%s (ignored) set_count count=0x%016lx (%s) p=%p\n",
+           timer->name, real_count, timer->disabled?"disabled":"enabled", opaque);
+
+    // TODO: save offset in our timer
 }
 
 uint64_t cpu_tick_get_count(void *opaque)
 {
-    return -ptimer_get_count(opaque);
+    sun4u_timer *timer = opaque;
+
+    uint64_t real_count = muldiv64(qemu_get_clock(vm_clock), timer->frequency,
+                                   get_ticks_per_sec());
+
+    TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n",
+           timer->name, real_count,
+           timer->disabled?"disabled":"enabled", opaque);
+
+    if (timer->disabled)
+        real_count |= timer->disabled_mask;
+
+    return real_count;
 }
 
 void cpu_tick_set_limit(void *opaque, uint64_t limit)
 {
-    ptimer_set_limit(opaque, -limit, 0);
+    sun4u_timer *timer = opaque;
+
+    int64_t now = qemu_get_clock(vm_clock);
+
+    int64_t real_limit = limit & ~timer->disabled_mask;
+    int64_t expires = muldiv64(now, timer->frequency,
+                               get_ticks_per_sec()) & ~timer->disabled_mask;
+    int64_t current_tick = expires;
+    int64_t delta = real_limit - current_tick;
+    if (delta < 0)
+        delta = 1;
+
+    timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
+
+    TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p "
+            "called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n",
+           timer->name, real_limit, timer->disabled?"disabled":"enabled",
+                           opaque, limit, current_tick, delta);
+
+    if (!real_limit) {
+        TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n",
+                timer->name);
+        qemu_del_timer(timer->qtimer);
+    } else if (timer->disabled) {
+        qemu_del_timer(timer->qtimer);
+    } else {
+        qemu_mod_timer(timer->qtimer, now + muldiv64(delta, get_ticks_per_sec(),
+                                                     timer->frequency));
+    }
 }
 
 static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
@@ -557,9 +672,12 @@ device_init(ram_register_devices);
 static CPUState *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
 {
     CPUState *env;
-    QEMUBH *bh;
     ResetData *reset_info;
 
+    uint32_t   tick_frequency = 10*1000000;
+    uint32_t  stick_frequency = 10*1000000;
+    uint32_t hstick_frequency = 10*1000000;
+
     if (!cpu_model)
         cpu_model = hwdef->default_cpu_model;
     env = cpu_init(cpu_model);
@@ -567,17 +685,15 @@ static CPUState *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
         fprintf(stderr, "Unable to find Sparc CPU definition\n");
         exit(1);
     }
-    bh = qemu_bh_new(tick_irq, env);
-    env->tick = ptimer_init(bh);
-    ptimer_set_period(env->tick, 1ULL);
 
-    bh = qemu_bh_new(stick_irq, env);
-    env->stick = ptimer_init(bh);
-    ptimer_set_period(env->stick, 1ULL);
+    env->tick = sun4u_timer_create("tick", env, tick_irq,
+                                   tick_frequency, TICK_NPT_MASK);
+
+    env->stick = sun4u_timer_create("stick", env, stick_irq,
+                                    stick_frequency, TICK_INT_DIS);
 
-    bh = qemu_bh_new(hstick_irq, env);
-    env->hstick = ptimer_init(bh);
-    ptimer_set_period(env->hstick, 1ULL);
+    env->hstick = sun4u_timer_create("hstick", env, hstick_irq,
+                                     hstick_frequency, TICK_INT_DIS);
 
     reset_info = qemu_mallocz(sizeof(ResetData));
     reset_info->env = env;

  parent reply	other threads:[~2010-01-07 20:28 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-01-07 20:27 [Qemu-devel] [PATCH 0/9] sparc64: interrupts and tick timers v1 Igor V. Kovalenko
2010-01-07 20:27 ` [Qemu-devel] [PATCH 1/9] sparc64: change_pstate should have 32bit argument Igor V. Kovalenko
2010-01-07 20:28 ` [Qemu-devel] [PATCH 2/9] sparc64: trace pstate and global register set changes Igor V. Kovalenko
2010-01-07 20:28 ` [Qemu-devel] [PATCH 3/9] sparc64: add PIL to cpu state dump Igor V. Kovalenko
2010-01-07 20:28 ` [Qemu-devel] [PATCH 4/9] sparc64: use helper_wrpil to check pending irq on write Igor V. Kovalenko
2010-01-07 20:28 ` [Qemu-devel] [PATCH 5/9] sparc64: check for pending irq when pil, pstate or softint is changed Igor V. Kovalenko
2010-01-07 20:28 ` [Qemu-devel] [PATCH 6/9] sparc64: add macros to deal with softint and timer interrupt Igor V. Kovalenko
2010-01-07 20:28 ` [Qemu-devel] [PATCH 7/9] sparc64: move cpu_interrupts_enabled to cpu.h Igor V. Kovalenko
2010-01-07 20:28 ` [Qemu-devel] [PATCH 8/9] sparc64: interrupt trap handling Igor V. Kovalenko
2010-01-07 20:28 ` Igor V. Kovalenko [this message]
2010-01-08 18:16 ` [Qemu-devel] [PATCH 0/9] sparc64: interrupts and tick timers v1 Blue Swirl
  -- strict thread matches above, loose matches on Subject: below --
2010-01-05 23:47 [Qemu-devel] [PATCH 9/9] sparc64: reimplement tick timers Igor Kovalenko
2010-01-06 17:31 ` Blue Swirl
2010-01-06 20:53   ` Igor Kovalenko

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=20100107202836.16653.88450.stgit@skyserv \
    --to=igor.v.kovalenko@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).