Skip to contentSkip to conversation

sparc64: interrupts and tick timers v1

PATCH Applied Igor V. Kovalenko 2 participants 11 messages Jan 7, 2010 – Jan 8, 2010

lore
Share & tools
lore
#0 lore raw

cover sparc64: interrupts and tick timers v1

The following series is a cleanup over previous one.

v0 -> v1: post-review changes
- dropped patch "clear exception_index with -1 val" (applied)
- new patch "change_pstate should have 32bit argument"
- cleanups for coding style and hexadecimal output convention
- wrpil is no-op for CONFIG_USER_ONLY
- restored PIL 15 as non-maskable interrupt level on sparcv8
- check for PSTATE.IE is replaced with call to cpu_interrupts_enabled()
- in patch "sparc64: interrupt trap handling"
cleaned up change in cpu_exec; since sparc64 does not use CPU_INTERRUPT_TIMER now, corresponding code branch is unchanged

---

Igor V. Kovalenko (9):
sparc64: change_pstate should have 32bit argument
sparc64: trace pstate and global register set changes
sparc64: add PIL to cpu state dump
sparc64: use helper_wrpil to check pending irq on write
sparc64: check for pending irq when pil, pstate or softint is changed
sparc64: add macros to deal with softint and timer interrupt
sparc64: move cpu_interrupts_enabled to cpu.h
sparc64: interrupt trap handling
sparc64: reimplement tick timers

 cpu-exec.c               |   28 +++---
 hw/sun4u.c               |  225 +++++++++++++++++++++++++++++++++++++---------
 target-sparc/cpu.h       |   27 ++++++
 target-sparc/exec.h      |   13 ---
 target-sparc/helper.c    |    1 
 target-sparc/helper.h    |    1 
 target-sparc/op_helper.c |   81 +++++++++++++++--
 target-sparc/translate.c |    5 -
 8 files changed, 300 insertions(+), 81 deletions(-)
Signature · 2 lines
Kind regards,
Igor V. Kovalenko
#1 lore raw

PATCH 1/9 sparc64: change_pstate should have 32bit argument

From: Igor V. Kovalenko <[email protected]>

- pstate is 32bit variable, no need to pass 64bit value around

---
 target-sparc/op_helper.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
target-sparc/op_helper.c +3 -3
index c63de07..fd3286d 100644
@@ -3240,7 +3240,7 @@ target_ulong helper_popc(target_ulong val)
     return ctpop64(val);
 }
 
-static inline uint64_t *get_gregset(uint64_t pstate)
+static inline uint64_t *get_gregset(uint32_t pstate)
 {
     switch (pstate) {
     default:
@@ -3255,9 +3255,9 @@ static inline uint64_t *get_gregset(uint64_t pstate)
     }
 }
 
-static inline void change_pstate(uint64_t new_pstate)
+static inline void change_pstate(uint32_t new_pstate)
 {
-    uint64_t pstate_regs, new_pstate_regs;
+    uint32_t pstate_regs, new_pstate_regs;
     uint64_t *src, *dst;
 
     if (env->def->features & CPU_FEATURE_GL) {
#2 lore raw

PATCH 2/9 sparc64: trace pstate and global register set changes

In reply to Igor V. Kovalenko

From: Igor V. Kovalenko <[email protected]>

---
 target-sparc/op_helper.c |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)
target-sparc/op_helper.c +20 -0
index fd3286d..1d3adef 100644
@@ -11,6 +11,7 @@
 //#define DEBUG_UNASSIGNED
 //#define DEBUG_ASI
 //#define DEBUG_PCALL
+//#define DEBUG_PSTATE
 
 #ifdef DEBUG_MMU
 #define DPRINTF_MMU(fmt, ...)                                   \
@@ -31,6 +32,13 @@
     do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
 #endif
 
+#ifdef DEBUG_PSTATE
+#define DPRINTF_PSTATE(fmt, ...)                                   \
+    do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
+#endif
+
 #ifdef TARGET_SPARC64
 #ifndef TARGET_ABI32
 #define AM_CHECK(env1) ((env1)->pstate & PS_AM)
@@ -3244,6 +3252,12 @@ static inline uint64_t *get_gregset(uint32_t pstate)
 {
     switch (pstate) {
     default:
+        DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n",
+                pstate,
+                (pstate & PS_IG) ? " IG" : "",
+                (pstate & PS_MG) ? " MG" : "",
+                (pstate & PS_AG) ? " AG" : "");
+        /* pass through to normal set of global registers */
     case 0:
         return env->bgregs;
     case PS_AG:
@@ -3269,12 +3283,18 @@ static inline void change_pstate(uint32_t new_pstate)
     new_pstate_regs = new_pstate & 0xc01;
 
     if (new_pstate_regs != pstate_regs) {
+        DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n",
+                       pstate_regs, new_pstate_regs);
         // Switch global register bank
         src = get_gregset(new_pstate_regs);
         dst = get_gregset(pstate_regs);
         memcpy32(dst, env->gregs);
         memcpy32(env->gregs, src);
     }
+    else {
+        DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n",
+                       new_pstate_regs);
+    }
     env->pstate = new_pstate;
 }
 
#3 lore raw

PATCH 3/9 sparc64: add PIL to cpu state dump

In reply to Igor V. Kovalenko

From: Igor V. Kovalenko <[email protected]>

---
 target-sparc/helper.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
target-sparc/helper.c +1 -0
index a06923a..e801474 100644
@@ -1452,6 +1452,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
 #ifdef TARGET_SPARC64
     cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d fprs: %d\n",
                 env->pstate, GET_CCR(env), env->asi, env->tl, env->fprs);
+    cpu_fprintf(f, "pil=%x\n", env->psrpil);
     cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate %d "
                 "cleanwin %d cwp %d\n",
                 env->cansave, env->canrestore, env->otherwin, env->wstate,
#4 lore raw

PATCH 4/9 sparc64: use helper_wrpil to check pending irq on write

In reply to Igor V. Kovalenko

From: Igor V. Kovalenko <[email protected]>

---
 target-sparc/helper.h    |    1 +
 target-sparc/op_helper.c |   14 ++++++++++++++
 target-sparc/translate.c |    5 +----
 3 files changed, 16 insertions(+), 4 deletions(-)
target-sparc/helper.h +1 -0
index 4002b9e..6f103e7 100644
@@ -5,6 +5,7 @@ DEF_HELPER_0(rett, void)
 DEF_HELPER_1(wrpsr, void, tl)
 DEF_HELPER_0(rdpsr, tl)
 #else
+DEF_HELPER_1(wrpil, void, tl)
 DEF_HELPER_1(wrpstate, void, tl)
 DEF_HELPER_0(done, void)
 DEF_HELPER_0(retry, void)
target-sparc/op_helper.c +14 -0
index 1d3adef..3d7f64c 100644
@@ -3303,6 +3303,20 @@ void helper_wrpstate(target_ulong new_state)
     change_pstate(new_state & 0xf3f);
 }
 
+void helper_wrpil(target_ulong new_pil)
+{
+#if !defined(CONFIG_USER_ONLY)
+    DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n",
+                   env->psrpil, (uint32_t)new_pil);
+
+    env->psrpil = new_pil;
+
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
 void helper_done(void)
 {
     trap_state* tsptr = cpu_tsptr(env);
target-sparc/translate.c +1 -4
index bf6df50..7e9f0cf 100644
@@ -3371,10 +3371,7 @@ static void disas_sparc_insn(DisasContext * dc)
                                                offsetof(CPUSPARCState, tl));
                                 break;
                             case 8: // pil
-                                tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
-                                tcg_gen_st_i32(cpu_tmp32, cpu_env,
-                                               offsetof(CPUSPARCState,
-                                                        psrpil));
+                                gen_helper_wrpil(cpu_tmp0);
                                 break;
                             case 9: // cwp
                                 gen_helper_wrcwp(cpu_tmp0);
#5 lore raw

PATCH 5/9 sparc64: check for pending irq when pil, pstate or softint is changed

In reply to Igor V. Kovalenko

From: Igor V. Kovalenko <[email protected]>

---
 target-sparc/op_helper.c |   41 ++++++++++++++++++++++++++++++++++++++---
 1 files changed, 38 insertions(+), 3 deletions(-)
target-sparc/op_helper.c +38 -3
index 3d7f64c..381e6c4 100644
@@ -3301,6 +3301,12 @@ static inline void change_pstate(uint32_t new_pstate)
 void helper_wrpstate(target_ulong new_state)
 {
     change_pstate(new_state & 0xf3f);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
 }
 
 void helper_wrpil(target_ulong new_pil)
@@ -3328,6 +3334,14 @@ void helper_done(void)
     change_pstate((tsptr->tstate >> 8) & 0xf3f);
     PUT_CWP64(env, tsptr->tstate & 0xff);
     env->tl--;
+
+    DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
 }
 
 void helper_retry(void)
@@ -3341,21 +3355,42 @@ void helper_retry(void)
     change_pstate((tsptr->tstate >> 8) & 0xf3f);
     PUT_CWP64(env, tsptr->tstate & 0xff);
     env->tl--;
+
+    DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+    if (cpu_interrupts_enabled(env)) {
+        cpu_check_irqs(env);
+    }
+#endif
+}
+
+static void do_modify_softint(const char* operation, uint32_t value)
+{
+    if (env->softint != value) {
+        env->softint = value;
+        DPRINTF_PSTATE(": %s new %08x\n", operation, env->softint);
+#if !defined(CONFIG_USER_ONLY)
+        if (cpu_interrupts_enabled(env)) {
+            cpu_check_irqs(env);
+        }
+#endif
+    }
 }
 
 void helper_set_softint(uint64_t value)
 {
-    env->softint |= (uint32_t)value;
+    do_modify_softint("helper_set_softint", env->softint | (uint32_t)value);
 }
 
 void helper_clear_softint(uint64_t value)
 {
-    env->softint &= (uint32_t)~value;
+    do_modify_softint("helper_clear_softint", env->softint & (uint32_t)~value);
 }
 
 void helper_write_softint(uint64_t value)
 {
-    env->softint = (uint32_t)value;
+    do_modify_softint("helper_write_softint", (uint32_t)value);
 }
 #endif
 
#6 lore raw

PATCH 6/9 sparc64: add macros to deal with softint and timer interrupt

In reply to Igor V. Kovalenko

From: Igor V. Kovalenko <[email protected]>

---
 hw/sun4u.c         |    1 -
 target-sparc/cpu.h |    4 ++++
 2 files changed, 4 insertions(+), 1 deletions(-)
hw/sun4u.c +0 -1
index 9d46f08..029e3ed 100644
@@ -73,7 +73,6 @@
 
 #define MAX_PILS 16
 
-#define TICK_INT_DIS         0x8000000000000000ULL
 #define TICK_MAX             0x7fffffffffffffffULL
 
 struct hwdef {
target-sparc/cpu.h +4 -0
index 1fe4d0f..0f0e38c 100644
@@ -394,6 +394,8 @@ typedef struct CPUSPARCState {
     uint64_t fprs;
     uint64_t tick_cmpr, stick_cmpr;
     void *tick, *stick;
+#define TICK_NPT_MASK        0x8000000000000000ULL
+#define TICK_INT_DIS         0x8000000000000000ULL
     uint64_t gsr;
     uint32_t gl; // UA2005
     /* UA 2005 hyperprivileged registers */
@@ -402,6 +404,8 @@ typedef struct CPUSPARCState {
     uint32_t softint;
 #define SOFTINT_TIMER   1
 #define SOFTINT_STIMER  (1 << 16)
+#define SOFTINT_INTRMASK (0xFFFE)
+#define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
 #endif
     sparc_def_t *def;
 } CPUSPARCState;
#7 lore raw

PATCH 7/9 sparc64: move cpu_interrupts_enabled to cpu.h

In reply to Igor V. Kovalenko

From: Igor V. Kovalenko <[email protected]>

- to be used by cpu_check_irqs

---
 target-sparc/cpu.h  |   13 +++++++++++++
 target-sparc/exec.h |   13 -------------
 2 files changed, 13 insertions(+), 13 deletions(-)
target-sparc/cpu.h +13 -0
index 0f0e38c..e5b282d 100644
@@ -564,6 +564,19 @@ static inline int cpu_mmu_index(CPUState *env1)
 #endif
 }
 
+static inline int cpu_interrupts_enabled(CPUState *env1)
+{
+#if !defined (TARGET_SPARC64)
+    if (env1->psret != 0)
+        return 1;
+#else
+    if (env1->pstate & PS_IE)
+        return 1;
+#endif
+
+    return 0;
+}
+
 static inline int cpu_fpu_enabled(CPUState *env1)
 {
 #if defined(CONFIG_USER_ONLY)
target-sparc/exec.h +0 -13
index e120d6f..3e021e9 100644
@@ -24,19 +24,6 @@ static inline void regs_to_env(void)
 /* op_helper.c */
 void do_interrupt(CPUState *env);
 
-static inline int cpu_interrupts_enabled(CPUState *env1)
-{
-#if !defined (TARGET_SPARC64)
-    if (env1->psret != 0)
-        return 1;
-#else
-    if (env1->pstate & PS_IE)
-        return 1;
-#endif
-
-    return 0;
-}
-
 static inline int cpu_has_work(CPUState *env1)
 {
     return (env1->interrupt_request & CPU_INTERRUPT_HARD) &&
#8 lore raw

PATCH 8/9 sparc64: interrupt trap handling

In reply to Igor V. Kovalenko

From: Igor V. Kovalenko <[email protected]>

cpu_check_irqs
- handle SOFTINT register TICK and STICK timer bits
- only check interrupt levels greater than PIL value
- handle preemption by higher level traps

cpu_exec
- handle CPU_INTERRUPT_HARD only if interrupts are enabled
- PIL 15 is not special level on sparcv9

---
 cpu-exec.c         |   28 ++++++++++++++--------------
 hw/sun4u.c         |   48 +++++++++++++++++++++++++++++++++++-------------
 target-sparc/cpu.h |   10 ++++++++++
 3 files changed, 59 insertions(+), 27 deletions(-)
cpu-exec.c +14 -14
index af4595b..4635be3 100644
@@ -449,20 +449,20 @@ int cpu_exec(CPUState *env1)
                         next_tb = 0;
                     }
 #elif defined(TARGET_SPARC)
-                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
-			cpu_interrupts_enabled(env)) {
-			int pil = env->interrupt_index & 15;
-			int type = env->interrupt_index & 0xf0;
-
-			if (((type == TT_EXTINT) &&
-			     (pil == 15 || pil > env->psrpil)) ||
-			    type != TT_EXTINT) {
-			    env->interrupt_request &= ~CPU_INTERRUPT_HARD;
-                            env->exception_index = env->interrupt_index;
-                            do_interrupt(env);
-			    env->interrupt_index = 0;
-                        next_tb = 0;
-			}
+                    if (interrupt_request & CPU_INTERRUPT_HARD) {
+                        if (cpu_interrupts_enabled(env) &&
+                            env->interrupt_index > 0) {
+                            int pil = env->interrupt_index & 0xf;
+                            int type = env->interrupt_index & 0xf0;
+
+                            if (((type == TT_EXTINT) &&
+                                  cpu_pil_allowed(env, pil)) ||
+                                  type != TT_EXTINT) {
+                                env->exception_index = env->interrupt_index;
+                                do_interrupt(env);
+                                next_tb = 0;
+                            }
+                        }
 		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
 			//do_interrupt(0, 0, 0, 0, 0);
 			env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
hw/sun4u.c +35 -13

64 lines not on this page · raw message

target-sparc/cpu.h +10 -0
index e5b282d..50859c7 100644
@@ -577,6 +577,16 @@ static inline int cpu_interrupts_enabled(CPUState *env1)
     return 0;
 }
 
+static inline int cpu_pil_allowed(CPUState *env1, int pil)
+{
+#if !defined(TARGET_SPARC64)
+    /* level 15 is non-maskable on sparc v8 */
+    return pil == 15 || pil > env1->psrpil;
+#else
+    return pil > env1->psrpil;
+#endif
+}
+
 static inline int cpu_fpu_enabled(CPUState *env1)
 {
 #if defined(CONFIG_USER_ONLY)
#9 lore raw

PATCH 9/9 sparc64: reimplement tick timers

In reply to Igor V. Kovalenko

From: Igor V. Kovalenko <[email protected]>

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.

---
 hw/sun4u.c |  176 ++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 146 insertions(+), 30 deletions(-)
hw/sun4u.c +146 -30
index ae32878..565b25d 100644
@@ -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;
Applied
#10 lore raw
In reply to Igor V. Kovalenko

Thanks, applied all except 9/9.

Quoted 43 lines · Igor V. Kovalenko

The following series is a cleanup over previous one.

v0 -> v1: post-review changes
- dropped patch "clear exception_index with -1 val" (applied)
- new patch "change_pstate should have 32bit argument"
- cleanups for coding style and hexadecimal output convention
- wrpil is no-op for CONFIG_USER_ONLY
- restored PIL 15 as non-maskable interrupt level on sparcv8
- check for PSTATE.IE is replaced with call to cpu_interrupts_enabled()
- in patch "sparc64: interrupt trap handling"
 cleaned up change in cpu_exec; since sparc64 does not use CPU_INTERRUPT_TIMER now, corresponding code branch is unchanged

---

Igor V. Kovalenko (9):
     sparc64: change_pstate should have 32bit argument
     sparc64: trace pstate and global register set changes
     sparc64: add PIL to cpu state dump
     sparc64: use helper_wrpil to check pending irq on write
     sparc64: check for pending irq when pil, pstate or softint is changed
     sparc64: add macros to deal with softint and timer interrupt
     sparc64: move cpu_interrupts_enabled to cpu.h
     sparc64: interrupt trap handling
     sparc64: reimplement tick timers

 cpu-exec.c               |   28 +++---
 hw/sun4u.c               |  225 +++++++++++++++++++++++++++++++++++++--------- target-sparc/cpu.h       |   27 ++++++
 target-sparc/exec.h      |   13 ---
 target-sparc/helper.c    |    1
 target-sparc/helper.h    |    1
 target-sparc/op_helper.c |   81 +++++++++++++++-- target-sparc/translate.c |    5 -

 8 files changed, 300 insertions(+), 81 deletions(-)

--
Kind regards,
Igor V. Kovalenko