Message ID | 20100127210053.18945.35057.stgit@skyserv |
---|---|
State | New |
Headers | show |
Thanks, applied. On Wed, Jan 27, 2010 at 9:00 PM, Igor V. Kovalenko <igor.v.kovalenko@gmail.com> wrote: > 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. > > v3 -> v4: > - coding style > > v2 -> v3: > - added missing timer debug output macro > - CPUTimer struct and typedef moved to cpu.h > - change CPU_SAVE_VERSION to 6, older save formats not supported > > v1 -> v2: > - new conversion helpers cpu_to_timer_ticks and timer_to_cpu_ticks > - save offset from clock source to implement cpu_tick_set_count > - renamed struct sun4u_timer to CPUTimer > - load and save cpu timers > > v0 -> v1: > - coding style > > Signed-off-by: Igor V. Kovalenko <igor.v.kovalenko@gmail.com> > --- > hw/sun4u.c | 206 ++++++++++++++++++++++++++++++++++++++++-------- > target-sparc/cpu.h | 28 +++++-- > target-sparc/machine.c | 14 ++- > 3 files changed, 202 insertions(+), 46 deletions(-) > > diff --git a/hw/sun4u.c b/hw/sun4u.c > index c1530a6..1e01123 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 > @@ -282,6 +290,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; > @@ -303,6 +317,52 @@ typedef struct ResetData { > uint64_t prom_addr; > } ResetData; > > +void cpu_put_timer(QEMUFile *f, CPUTimer *s) > +{ > + qemu_put_be32s(f, &s->frequency); > + qemu_put_be32s(f, &s->disabled); > + qemu_put_be64s(f, &s->disabled_mask); > + qemu_put_sbe64s(f, &s->clock_offset); > + > + qemu_put_timer(f, s->qtimer); > +} > + > +void cpu_get_timer(QEMUFile *f, CPUTimer *s) > +{ > + qemu_get_be32s(f, &s->frequency); > + qemu_get_be32s(f, &s->disabled); > + qemu_get_be64s(f, &s->disabled_mask); > + qemu_get_sbe64s(f, &s->clock_offset); > + > + qemu_get_timer(f, s->qtimer); > +} > + > +static CPUTimer* cpu_timer_create(const char* name, CPUState *env, > + QEMUBHFunc *cb, uint32_t frequency, > + uint64_t disabled_mask) > +{ > + CPUTimer *timer = qemu_mallocz(sizeof (CPUTimer)); > + > + timer->name = name; > + timer->frequency = frequency; > + timer->disabled_mask = disabled_mask; > + > + timer->disabled = 1; > + timer->clock_offset = qemu_get_clock(vm_clock); > + > + timer->qtimer = qemu_new_timer(vm_clock, cb, env); > + > + return timer; > +} > + > +static void cpu_timer_reset(CPUTimer *timer) > +{ > + timer->disabled = 1; > + timer->clock_offset = qemu_get_clock(vm_clock); > + > + qemu_del_timer(timer->qtimer); > +} > + > static void main_cpu_reset(void *opaque) > { > ResetData *s = (ResetData *)opaque; > @@ -310,15 +370,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); > + > + cpu_timer_reset(env->tick); > + cpu_timer_reset(env->stick); > + cpu_timer_reset(env->hstick); > + > env->gregs[1] = 0; // Memory start > env->gregs[2] = ram_size; // Memory size > env->gregs[3] = 0; // Machine description XXX > @@ -335,44 +391,127 @@ 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); > + CPUTimer* 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); > + CPUTimer* 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); > + CPUTimer* 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); > +} > + > +static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency) > +{ > + return muldiv64(cpu_ticks, get_ticks_per_sec(), frequency); > +} > + > +static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency) > +{ > + return muldiv64(timer_ticks, frequency, get_ticks_per_sec()); > } > > -void cpu_tick_set_count(void *opaque, uint64_t count) > +void cpu_tick_set_count(CPUTimer *timer, uint64_t count) > { > - ptimer_set_count(opaque, -count); > + uint64_t real_count = count & ~timer->disabled_mask; > + uint64_t disabled_bit = count & timer->disabled_mask; > + > + int64_t vm_clock_offset = qemu_get_clock(vm_clock) - > + cpu_to_timer_ticks(real_count, timer->frequency); > + > + TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n", > + timer->name, real_count, > + timer->disabled?"disabled":"enabled", timer); > + > + timer->disabled = disabled_bit ? 1 : 0; > + timer->clock_offset = vm_clock_offset; > } > > -uint64_t cpu_tick_get_count(void *opaque) > +uint64_t cpu_tick_get_count(CPUTimer *timer) > { > - return -ptimer_get_count(opaque); > + uint64_t real_count = timer_to_cpu_ticks( > + qemu_get_clock(vm_clock) - timer->clock_offset, > + timer->frequency); > + > + TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n", > + timer->name, real_count, > + timer->disabled?"disabled":"enabled", timer); > + > + if (timer->disabled) > + real_count |= timer->disabled_mask; > + > + return real_count; > } > > -void cpu_tick_set_limit(void *opaque, uint64_t limit) > +void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit) > { > - ptimer_set_limit(opaque, -limit, 0); > + int64_t now = qemu_get_clock(vm_clock); > + > + uint64_t real_limit = limit & ~timer->disabled_mask; > + timer->disabled = (limit & timer->disabled_mask) ? 1 : 0; > + > + int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) + > + timer->clock_offset; > + > + if (expires < now) { > + expires = now + 1; > + } > + > + 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", > + timer, limit, > + timer_to_cpu_ticks(now - timer->clock_offset, > + timer->frequency), > + timer_to_cpu_ticks(expires - now, timer->frequency)); > + > + 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, expires); > + } > } > > static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num, > @@ -559,9 +698,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 = 100*1000000; > + uint32_t stick_frequency = 100*1000000; > + uint32_t hstick_frequency = 100*1000000; > + > if (!cpu_model) > cpu_model = hwdef->default_cpu_model; > env = cpu_init(cpu_model); > @@ -569,17 +711,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 = cpu_timer_create("tick", env, tick_irq, > + tick_frequency, TICK_NPT_MASK); > + > + env->stick = cpu_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 = cpu_timer_create("hstick", env, hstick_irq, > + hstick_frequency, TICK_INT_DIS); > > reset_info = qemu_mallocz(sizeof(ResetData)); > reset_info->env = env; > diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h > index 842a2f4..5980deb 100644 > --- a/target-sparc/cpu.h > +++ b/target-sparc/cpu.h > @@ -292,6 +292,22 @@ typedef struct SparcTLBEntry { > uint64_t tte; > } SparcTLBEntry; > > +struct CPUTimer > +{ > + const char *name; > + uint32_t frequency; > + uint32_t disabled; > + uint64_t disabled_mask; > + int64_t clock_offset; > + struct QEMUTimer *qtimer; > +}; > + > +typedef struct CPUTimer CPUTimer; > + > +struct QEMUFile; > +void cpu_put_timer(struct QEMUFile *f, CPUTimer *s); > +void cpu_get_timer(struct QEMUFile *f, CPUTimer *s); > + > typedef struct CPUSPARCState { > target_ulong gregs[8]; /* general registers */ > target_ulong *regwptr; /* pointer to current register window */ > @@ -393,14 +409,14 @@ typedef struct CPUSPARCState { > uint64_t mgregs[8]; /* mmu general registers */ > uint64_t fprs; > uint64_t tick_cmpr, stick_cmpr; > - void *tick, *stick; > + CPUTimer *tick, *stick; > #define TICK_NPT_MASK 0x8000000000000000ULL > #define TICK_INT_DIS 0x8000000000000000ULL > uint64_t gsr; > uint32_t gl; // UA2005 > /* UA 2005 hyperprivileged registers */ > uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr; > - void *hstick; // UA 2005 > + CPUTimer *hstick; // UA 2005 > uint32_t softint; > #define SOFTINT_TIMER 1 > #define SOFTINT_STIMER (1 << 16) > @@ -536,7 +552,7 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); > #define cpu_signal_handler cpu_sparc_signal_handler > #define cpu_list sparc_cpu_list > > -#define CPU_SAVE_VERSION 5 > +#define CPU_SAVE_VERSION 6 > > /* MMU modes definitions */ > #define MMU_MODE0_SUFFIX _user > @@ -615,9 +631,9 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) > > #ifdef TARGET_SPARC64 > /* sun4u.c */ > -void cpu_tick_set_count(void *opaque, uint64_t count); > -uint64_t cpu_tick_get_count(void *opaque); > -void cpu_tick_set_limit(void *opaque, uint64_t limit); > +void cpu_tick_set_count(CPUTimer *timer, uint64_t count); > +uint64_t cpu_tick_get_count(CPUTimer *timer); > +void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit); > trap_state* cpu_tsptr(CPUState* env); > #endif > > diff --git a/target-sparc/machine.c b/target-sparc/machine.c > index c7c03b6..4b87ec6 100644 > --- a/target-sparc/machine.c > +++ b/target-sparc/machine.c > @@ -84,8 +84,8 @@ void cpu_save(QEMUFile *f, void *opaque) > qemu_put_be64s(f, &env->fprs); > qemu_put_be64s(f, &env->tick_cmpr); > qemu_put_be64s(f, &env->stick_cmpr); > - qemu_put_ptimer(f, env->tick); > - qemu_put_ptimer(f, env->stick); > + cpu_put_timer(f, env->tick); > + cpu_put_timer(f, env->stick); > qemu_put_be64s(f, &env->gsr); > qemu_put_be32s(f, &env->gl); > qemu_put_be64s(f, &env->hpstate); > @@ -96,7 +96,7 @@ void cpu_save(QEMUFile *f, void *opaque) > qemu_put_be64s(f, &env->hver); > qemu_put_be64s(f, &env->hstick_cmpr); > qemu_put_be64s(f, &env->ssr); > - qemu_put_ptimer(f, env->hstick); > + cpu_put_timer(f, env->hstick); > #endif > } > > @@ -106,7 +106,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) > int i; > uint32_t tmp; > > - if (version_id != 5) > + if (version_id < 6) > return -EINVAL; > for(i = 0; i < 8; i++) > qemu_get_betls(f, &env->gregs[i]); > @@ -180,8 +180,8 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) > qemu_get_be64s(f, &env->fprs); > qemu_get_be64s(f, &env->tick_cmpr); > qemu_get_be64s(f, &env->stick_cmpr); > - qemu_get_ptimer(f, env->tick); > - qemu_get_ptimer(f, env->stick); > + cpu_get_timer(f, env->tick); > + cpu_get_timer(f, env->stick); > qemu_get_be64s(f, &env->gsr); > qemu_get_be32s(f, &env->gl); > qemu_get_be64s(f, &env->hpstate); > @@ -192,7 +192,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) > qemu_get_be64s(f, &env->hver); > qemu_get_be64s(f, &env->hstick_cmpr); > qemu_get_be64s(f, &env->ssr); > - qemu_get_ptimer(f, env->hstick); > + cpu_get_timer(f, env->hstick); > #endif > tlb_flush(env, 1); > return 0; > > > >
On Wed, Jan 27, 2010 at 9:00 PM, Igor V. Kovalenko <igor.v.kovalenko@gmail.com> wrote: > 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. Now also IDE probe succeeds, almost: cmd64x 0000:00:05.0: IDE controller (0x1095:0x0646 rev 0x07) cmd64x 0000:00:05.0: 100% native mode on irq 1 ide0: BM-DMA at 0x1fe02000700-0x1fe02000707 ide1: BM-DMA at 0x1fe02000708-0x1fe0200070f hdc: EQUMD DVR-MO, ATAPI cdrom or floppy?, assuming FLOPPY drive ide0 at 0x1fe02000500-0x1fe02000507,0x1fe02000582 on irq 1 (serialized) ide1 at 0x1fe02000600-0x1fe02000607,0x1fe02000682 on irq 1 (serialized) ide-gd driver 1.18
diff --git a/hw/sun4u.c b/hw/sun4u.c index c1530a6..1e01123 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 @@ -282,6 +290,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; @@ -303,6 +317,52 @@ typedef struct ResetData { uint64_t prom_addr; } ResetData; +void cpu_put_timer(QEMUFile *f, CPUTimer *s) +{ + qemu_put_be32s(f, &s->frequency); + qemu_put_be32s(f, &s->disabled); + qemu_put_be64s(f, &s->disabled_mask); + qemu_put_sbe64s(f, &s->clock_offset); + + qemu_put_timer(f, s->qtimer); +} + +void cpu_get_timer(QEMUFile *f, CPUTimer *s) +{ + qemu_get_be32s(f, &s->frequency); + qemu_get_be32s(f, &s->disabled); + qemu_get_be64s(f, &s->disabled_mask); + qemu_get_sbe64s(f, &s->clock_offset); + + qemu_get_timer(f, s->qtimer); +} + +static CPUTimer* cpu_timer_create(const char* name, CPUState *env, + QEMUBHFunc *cb, uint32_t frequency, + uint64_t disabled_mask) +{ + CPUTimer *timer = qemu_mallocz(sizeof (CPUTimer)); + + timer->name = name; + timer->frequency = frequency; + timer->disabled_mask = disabled_mask; + + timer->disabled = 1; + timer->clock_offset = qemu_get_clock(vm_clock); + + timer->qtimer = qemu_new_timer(vm_clock, cb, env); + + return timer; +} + +static void cpu_timer_reset(CPUTimer *timer) +{ + timer->disabled = 1; + timer->clock_offset = qemu_get_clock(vm_clock); + + qemu_del_timer(timer->qtimer); +} + static void main_cpu_reset(void *opaque) { ResetData *s = (ResetData *)opaque; @@ -310,15 +370,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); + + cpu_timer_reset(env->tick); + cpu_timer_reset(env->stick); + cpu_timer_reset(env->hstick); + env->gregs[1] = 0; // Memory start env->gregs[2] = ram_size; // Memory size env->gregs[3] = 0; // Machine description XXX @@ -335,44 +391,127 @@ 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); + CPUTimer* 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); + CPUTimer* 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); + CPUTimer* 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); +} + +static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency) +{ + return muldiv64(cpu_ticks, get_ticks_per_sec(), frequency); +} + +static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency) +{ + return muldiv64(timer_ticks, frequency, get_ticks_per_sec()); } -void cpu_tick_set_count(void *opaque, uint64_t count) +void cpu_tick_set_count(CPUTimer *timer, uint64_t count) { - ptimer_set_count(opaque, -count); + uint64_t real_count = count & ~timer->disabled_mask; + uint64_t disabled_bit = count & timer->disabled_mask; + + int64_t vm_clock_offset = qemu_get_clock(vm_clock) - + cpu_to_timer_ticks(real_count, timer->frequency); + + TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n", + timer->name, real_count, + timer->disabled?"disabled":"enabled", timer); + + timer->disabled = disabled_bit ? 1 : 0; + timer->clock_offset = vm_clock_offset; } -uint64_t cpu_tick_get_count(void *opaque) +uint64_t cpu_tick_get_count(CPUTimer *timer) { - return -ptimer_get_count(opaque); + uint64_t real_count = timer_to_cpu_ticks( + qemu_get_clock(vm_clock) - timer->clock_offset, + timer->frequency); + + TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n", + timer->name, real_count, + timer->disabled?"disabled":"enabled", timer); + + if (timer->disabled) + real_count |= timer->disabled_mask; + + return real_count; } -void cpu_tick_set_limit(void *opaque, uint64_t limit) +void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit) { - ptimer_set_limit(opaque, -limit, 0); + int64_t now = qemu_get_clock(vm_clock); + + uint64_t real_limit = limit & ~timer->disabled_mask; + timer->disabled = (limit & timer->disabled_mask) ? 1 : 0; + + int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) + + timer->clock_offset; + + if (expires < now) { + expires = now + 1; + } + + 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", + timer, limit, + timer_to_cpu_ticks(now - timer->clock_offset, + timer->frequency), + timer_to_cpu_ticks(expires - now, timer->frequency)); + + 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, expires); + } } static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num, @@ -559,9 +698,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 = 100*1000000; + uint32_t stick_frequency = 100*1000000; + uint32_t hstick_frequency = 100*1000000; + if (!cpu_model) cpu_model = hwdef->default_cpu_model; env = cpu_init(cpu_model); @@ -569,17 +711,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 = cpu_timer_create("tick", env, tick_irq, + tick_frequency, TICK_NPT_MASK); + + env->stick = cpu_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 = cpu_timer_create("hstick", env, hstick_irq, + hstick_frequency, TICK_INT_DIS); reset_info = qemu_mallocz(sizeof(ResetData)); reset_info->env = env; diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 842a2f4..5980deb 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -292,6 +292,22 @@ typedef struct SparcTLBEntry { uint64_t tte; } SparcTLBEntry; +struct CPUTimer +{ + const char *name; + uint32_t frequency; + uint32_t disabled; + uint64_t disabled_mask; + int64_t clock_offset; + struct QEMUTimer *qtimer; +}; + +typedef struct CPUTimer CPUTimer; + +struct QEMUFile; +void cpu_put_timer(struct QEMUFile *f, CPUTimer *s); +void cpu_get_timer(struct QEMUFile *f, CPUTimer *s); + typedef struct CPUSPARCState { target_ulong gregs[8]; /* general registers */ target_ulong *regwptr; /* pointer to current register window */ @@ -393,14 +409,14 @@ typedef struct CPUSPARCState { uint64_t mgregs[8]; /* mmu general registers */ uint64_t fprs; uint64_t tick_cmpr, stick_cmpr; - void *tick, *stick; + CPUTimer *tick, *stick; #define TICK_NPT_MASK 0x8000000000000000ULL #define TICK_INT_DIS 0x8000000000000000ULL uint64_t gsr; uint32_t gl; // UA2005 /* UA 2005 hyperprivileged registers */ uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr; - void *hstick; // UA 2005 + CPUTimer *hstick; // UA 2005 uint32_t softint; #define SOFTINT_TIMER 1 #define SOFTINT_STIMER (1 << 16) @@ -536,7 +552,7 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); #define cpu_signal_handler cpu_sparc_signal_handler #define cpu_list sparc_cpu_list -#define CPU_SAVE_VERSION 5 +#define CPU_SAVE_VERSION 6 /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _user @@ -615,9 +631,9 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) #ifdef TARGET_SPARC64 /* sun4u.c */ -void cpu_tick_set_count(void *opaque, uint64_t count); -uint64_t cpu_tick_get_count(void *opaque); -void cpu_tick_set_limit(void *opaque, uint64_t limit); +void cpu_tick_set_count(CPUTimer *timer, uint64_t count); +uint64_t cpu_tick_get_count(CPUTimer *timer); +void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit); trap_state* cpu_tsptr(CPUState* env); #endif diff --git a/target-sparc/machine.c b/target-sparc/machine.c index c7c03b6..4b87ec6 100644 --- a/target-sparc/machine.c +++ b/target-sparc/machine.c @@ -84,8 +84,8 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be64s(f, &env->fprs); qemu_put_be64s(f, &env->tick_cmpr); qemu_put_be64s(f, &env->stick_cmpr); - qemu_put_ptimer(f, env->tick); - qemu_put_ptimer(f, env->stick); + cpu_put_timer(f, env->tick); + cpu_put_timer(f, env->stick); qemu_put_be64s(f, &env->gsr); qemu_put_be32s(f, &env->gl); qemu_put_be64s(f, &env->hpstate); @@ -96,7 +96,7 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be64s(f, &env->hver); qemu_put_be64s(f, &env->hstick_cmpr); qemu_put_be64s(f, &env->ssr); - qemu_put_ptimer(f, env->hstick); + cpu_put_timer(f, env->hstick); #endif } @@ -106,7 +106,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) int i; uint32_t tmp; - if (version_id != 5) + if (version_id < 6) return -EINVAL; for(i = 0; i < 8; i++) qemu_get_betls(f, &env->gregs[i]); @@ -180,8 +180,8 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be64s(f, &env->fprs); qemu_get_be64s(f, &env->tick_cmpr); qemu_get_be64s(f, &env->stick_cmpr); - qemu_get_ptimer(f, env->tick); - qemu_get_ptimer(f, env->stick); + cpu_get_timer(f, env->tick); + cpu_get_timer(f, env->stick); qemu_get_be64s(f, &env->gsr); qemu_get_be32s(f, &env->gl); qemu_get_be64s(f, &env->hpstate); @@ -192,7 +192,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be64s(f, &env->hver); qemu_get_be64s(f, &env->hstick_cmpr); qemu_get_be64s(f, &env->ssr); - qemu_get_ptimer(f, env->hstick); + cpu_get_timer(f, env->hstick); #endif tlb_flush(env, 1); return 0;