* [Qemu-devel] [PATCH 9/9] sparc64: reimplement tick timers
@ 2010-01-05 23:47 Igor Kovalenko
2010-01-06 17:31 ` Blue Swirl
0 siblings, 1 reply; 4+ messages in thread
From: Igor Kovalenko @ 2010-01-05 23:47 UTC (permalink / raw)
To: qemu-devel
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 | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 152 insertions(+), 30 deletions(-)
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 84a8043..35f4c6b 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -281,6 +281,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;
@@ -302,6 +308,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,
+ int64_t period, 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;
@@ -309,15 +350,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
@@ -334,44 +371,125 @@ 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)
+ {
+ fprintf(logfile, "tick_irq: softint disabled\n");
+ return;
}
+ else
+ {
+ fprintf(logfile, "tick: fire\n");
+ }
+
+ env->softint |= SOFTINT_TM;
+ 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_SM;
+ 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_SM;
+ 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;
+
+ fprintf(logfile, "%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());
+
+ fprintf(logfile, "%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;
+
+ fprintf(logfile, "%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)
+ {
+ fprintf(logfile, "%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,
@@ -558,9 +676,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);
@@ -568,17 +689,18 @@ 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, 1ULL,
+ TICK_NPT_MASK);
+
+ env->stick = sun4u_timer_create("stick", env, stick_irq,
+ stick_frequency, 1ULL,
+ TICK_SOFTINT_DISABLE);
- 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, 1ULL,
+ TICK_SOFTINT_DISABLE);
reset_info = qemu_mallocz(sizeof(ResetData));
reset_info->env = env;
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH 9/9] sparc64: reimplement tick timers
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
0 siblings, 1 reply; 4+ messages in thread
From: Blue Swirl @ 2010-01-06 17:31 UTC (permalink / raw)
To: Igor Kovalenko; +Cc: qemu-devel
On Tue, Jan 5, 2010 at 11:47 PM, Igor Kovalenko
<igor.v.kovalenko@gmail.com> wrote:
> 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 | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++----------
> 1 files changed, 152 insertions(+), 30 deletions(-)
>
> diff --git a/hw/sun4u.c b/hw/sun4u.c
> index 84a8043..35f4c6b 100644
> --- a/hw/sun4u.c
> +++ b/hw/sun4u.c
> @@ -281,6 +281,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;
> @@ -302,6 +308,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;
> +};
The formatting seems to be off. Please don't use tabs. The prefix
'sun4u_' does not fit hstick and it's not CamelCase, how about
CPUTimer?
> +
> +typedef struct sun4u_timer sun4u_timer;
> +
> +static sun4u_timer* sun4u_timer_create(const char* name, CPUState *env,
> + QEMUBHFunc *cb, uint32_t frequency,
> + int64_t period, 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;
> +}
The parameter 'period' is not used.
> +
> +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;
> @@ -309,15 +350,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
> @@ -334,44 +371,125 @@ 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)
> + {
Coding style.
> + fprintf(logfile, "tick_irq: softint disabled\n");
> + return;
> }
> + else
> + {
Coding style.
> + fprintf(logfile, "tick: fire\n");
> + }
> +
> + env->softint |= SOFTINT_TM;
> + 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)
> + {
Coding style.
> + CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
> + return;
> }
> + else
> + {
Coding style.
> + CPUIRQ_DPRINTF("stick: fire\n");
> + }
> +
> + env->softint |= SOFTINT_SM;
> + 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
Coding style.
> + {
> + CPUIRQ_DPRINTF("hstick: fire\n");
> }
> +
> + env->softint |= SOFTINT_SM;
> + 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;
> +
> + fprintf(logfile, "%s (ignored) set_count count=0x%016lx (%s) p=%p\n",
> + timer->name, real_count,
> timer->disabled?"disabled":"enabled", opaque);
I think logging this is not necessary, please create TICK_DPRINTF() or
something.
> +
> + // 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());
The line is wrapped, perhaps the line is too long?
> +
> + fprintf(logfile, "%s get_count count=0x%016lx (%s) p=%p\n",
> + timer->name, real_count,
> timer->disabled?"disabled":"enabled", opaque);
DPRINTF()
> +
> + 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;
Line too long.
> + 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;
> +
> + fprintf(logfile, "%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);
DPRINTF()
> +
> + if (!real_limit)
> + {
Coding style.
> + fprintf(logfile, "%s set_limit limit=ZERO - not starting timer\n",
> + timer->name);
> + qemu_del_timer(timer->qtimer);
> + }
> + else if (timer->disabled)
> + {
Coding style.
> + qemu_del_timer(timer->qtimer);
> + }
> + else
> + {
Coding style.
> + qemu_mod_timer(timer->qtimer, now + muldiv64(delta,
> get_ticks_per_sec(),
Line too long.
> + timer->frequency));
> + }
> }
>
> static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
> @@ -558,9 +676,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);
> @@ -568,17 +689,18 @@ 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, 1ULL,
> + TICK_NPT_MASK);
> +
> + env->stick = sun4u_timer_create("stick", env, stick_irq,
> + stick_frequency, 1ULL,
> + TICK_SOFTINT_DISABLE);
>
> - 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, 1ULL,
> + TICK_SOFTINT_DISABLE);
>
> reset_info = qemu_mallocz(sizeof(ResetData));
> reset_info->env = env;
>
>
>
After this, are ptimers not going to be used anymore for Sparc64? Then
Makefile etc. changes should be included.
Anyway, thank you for your efforts.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH 9/9] sparc64: reimplement tick timers
2010-01-06 17:31 ` Blue Swirl
@ 2010-01-06 20:53 ` Igor Kovalenko
0 siblings, 0 replies; 4+ messages in thread
From: Igor Kovalenko @ 2010-01-06 20:53 UTC (permalink / raw)
To: Blue Swirl, qemu-devel
On Wed, Jan 6, 2010 at 8:31 PM, Blue Swirl <blauwirbel@gmail.com> wrote:
> On Tue, Jan 5, 2010 at 11:47 PM, Igor Kovalenko
> <igor.v.kovalenko@gmail.com> wrote:
>> 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 | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++----------
>> 1 files changed, 152 insertions(+), 30 deletions(-)
>>
>> diff --git a/hw/sun4u.c b/hw/sun4u.c
>> index 84a8043..35f4c6b 100644
>> --- a/hw/sun4u.c
>> +++ b/hw/sun4u.c
>> @@ -281,6 +281,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;
>> @@ -302,6 +308,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;
>> +};
>
> The formatting seems to be off. Please don't use tabs. The prefix
> 'sun4u_' does not fit hstick and it's not CamelCase, how about
> CPUTimer?
>
>> +
>> +typedef struct sun4u_timer sun4u_timer;
>> +
>> +static sun4u_timer* sun4u_timer_create(const char* name, CPUState *env,
>> + QEMUBHFunc *cb, uint32_t frequency,
>> + int64_t period, 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;
>> +}
>
> The parameter 'period' is not used.
>
>> +
>> +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;
>> @@ -309,15 +350,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
>> @@ -334,44 +371,125 @@ 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)
>> + {
>
> Coding style.
>
>> + fprintf(logfile, "tick_irq: softint disabled\n");
>> + return;
>> }
>> + else
>> + {
>
> Coding style.
>
>> + fprintf(logfile, "tick: fire\n");
>> + }
>> +
>> + env->softint |= SOFTINT_TM;
>> + 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)
>> + {
>
> Coding style.
>
>> + CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
>> + return;
>> }
>> + else
>> + {
>
> Coding style.
>
>> + CPUIRQ_DPRINTF("stick: fire\n");
>> + }
>> +
>> + env->softint |= SOFTINT_SM;
>> + 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
>
> Coding style.
>
>> + {
>> + CPUIRQ_DPRINTF("hstick: fire\n");
>> }
>> +
>> + env->softint |= SOFTINT_SM;
>> + 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;
>> +
>> + fprintf(logfile, "%s (ignored) set_count count=0x%016lx (%s) p=%p\n",
>> + timer->name, real_count,
>> timer->disabled?"disabled":"enabled", opaque);
>
> I think logging this is not necessary, please create TICK_DPRINTF() or
> something.
>
>> +
>> + // 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());
>
> The line is wrapped, perhaps the line is too long?
>
>> +
>> + fprintf(logfile, "%s get_count count=0x%016lx (%s) p=%p\n",
>> + timer->name, real_count,
>> timer->disabled?"disabled":"enabled", opaque);
>
> DPRINTF()
>
>> +
>> + 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;
>
> Line too long.
>
>> + 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;
>> +
>> + fprintf(logfile, "%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);
>
> DPRINTF()
>
>> +
>> + if (!real_limit)
>> + {
>
> Coding style.
>
>> + fprintf(logfile, "%s set_limit limit=ZERO - not starting timer\n",
>> + timer->name);
>> + qemu_del_timer(timer->qtimer);
>> + }
>> + else if (timer->disabled)
>> + {
>
> Coding style.
>
>> + qemu_del_timer(timer->qtimer);
>> + }
>> + else
>> + {
>
> Coding style.
>
>> + qemu_mod_timer(timer->qtimer, now + muldiv64(delta,
>> get_ticks_per_sec(),
>
> Line too long.
>
>> + timer->frequency));
>> + }
>> }
>>
>> static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
>> @@ -558,9 +676,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);
>> @@ -568,17 +689,18 @@ 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, 1ULL,
>> + TICK_NPT_MASK);
>> +
>> + env->stick = sun4u_timer_create("stick", env, stick_irq,
>> + stick_frequency, 1ULL,
>> + TICK_SOFTINT_DISABLE);
>>
>> - 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, 1ULL,
>> + TICK_SOFTINT_DISABLE);
>>
>> reset_info = qemu_mallocz(sizeof(ResetData));
>> reset_info->env = env;
>>
>>
>>
>
> After this, are ptimers not going to be used anymore for Sparc64? Then
> Makefile etc. changes should be included.
>
> Anyway, thank you for your efforts.
Thanks for the review!
I'm not sure at the moment we need to discard ptimer implementation
for sparc64. I'll work with the rest of this series according to review
comments, assuming those are otherwise not bad to be committed.
We can deal with (the only, at the moment) interrupt source separately.
--
Kind regards,
Igor V. Kovalenko
^ permalink raw reply [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 0/9] sparc64: interrupts and tick timers v1
@ 2010-01-07 20:27 Igor V. Kovalenko
2010-01-07 20:28 ` [Qemu-devel] [PATCH 9/9] sparc64: reimplement tick timers Igor V. Kovalenko
0 siblings, 1 reply; 4+ messages in thread
From: Igor V. Kovalenko @ 2010-01-07 20:27 UTC (permalink / raw)
To: qemu-devel
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
^ permalink raw reply [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 9/9] sparc64: reimplement tick timers
2010-01-07 20:27 [Qemu-devel] [PATCH 0/9] sparc64: interrupts and tick timers v1 Igor V. Kovalenko
@ 2010-01-07 20:28 ` Igor V. Kovalenko
0 siblings, 0 replies; 4+ messages in thread
From: Igor V. Kovalenko @ 2010-01-07 20:28 UTC (permalink / raw)
To: qemu-devel
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;
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2010-01-07 20:28 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
-- strict thread matches above, loose matches on Subject: below --
2010-01-07 20:27 [Qemu-devel] [PATCH 0/9] sparc64: interrupts and tick timers v1 Igor V. Kovalenko
2010-01-07 20:28 ` [Qemu-devel] [PATCH 9/9] sparc64: reimplement tick timers Igor V. Kovalenko
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).