[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH] sparc64: reimplement tick timers v4
From: |
Blue Swirl |
Subject: |
Re: [Qemu-devel] [PATCH] sparc64: reimplement tick timers v4 |
Date: |
Wed, 27 Jan 2010 21:40:13 +0000 |
Thanks, applied.
On Wed, Jan 27, 2010 at 9:00 PM, Igor V. Kovalenko
<address@hidden> wrote:
> From: Igor V. Kovalenko <address@hidden>
>
> 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 <address@hidden>
> ---
> 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;
>
>
>
>