sun4m: fix slavio timer RUN/STOP bit

The sun4m architecture has one 'system' timer and one timer per CPU.
The CPU timers can be configured in two modes:

  * 22 bits Counter/Timer. Periodic interrupts.
  * 54 bits User timer. For profiling. In this mode, the Run/Stop bit
    controls the timer.

The run/stop bit controls the timer only when it is in "User" mode, but
its state shall be persistent.

Signed-off-by: Olivier Danet <odanet@caramail.com>
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
This commit is contained in:
Mark Cave-Ayland 2014-02-22 22:54:53 +00:00
parent f9681f116c
commit ead4cf04f8
1 changed files with 10 additions and 15 deletions

View File

@ -51,7 +51,7 @@ typedef struct CPUTimerState {
ptimer_state *timer; ptimer_state *timer;
uint32_t count, counthigh, reached; uint32_t count, counthigh, reached;
/* processor only */ /* processor only */
uint32_t running; uint32_t run;
uint64_t limit; uint64_t limit;
} CPUTimerState; } CPUTimerState;
@ -177,7 +177,7 @@ static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
// only available in processor counter/timer // only available in processor counter/timer
// read start/stop status // read start/stop status
if (timer_index > 0) { if (timer_index > 0) {
ret = t->running; ret = t->run;
} else { } else {
ret = 0; ret = 0;
} }
@ -260,16 +260,15 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
case TIMER_STATUS: case TIMER_STATUS:
if (slavio_timer_is_user(tc)) { if (slavio_timer_is_user(tc)) {
// start/stop user counter // start/stop user counter
if ((val & 1) && !t->running) { if (val & 1) {
trace_slavio_timer_mem_writel_status_start(timer_index); trace_slavio_timer_mem_writel_status_start(timer_index);
ptimer_run(t->timer, 0); ptimer_run(t->timer, 0);
t->running = 1; } else {
} else if (!(val & 1) && t->running) {
trace_slavio_timer_mem_writel_status_stop(timer_index); trace_slavio_timer_mem_writel_status_stop(timer_index);
ptimer_stop(t->timer); ptimer_stop(t->timer);
t->running = 0;
} }
} }
t->run = val & 1;
break; break;
case TIMER_MODE: case TIMER_MODE:
if (timer_index == 0) { if (timer_index == 0) {
@ -284,8 +283,9 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
if (val & processor) { // counter -> user timer if (val & processor) { // counter -> user timer
qemu_irq_lower(curr_timer->irq); qemu_irq_lower(curr_timer->irq);
// counters are always running // counters are always running
ptimer_stop(curr_timer->timer); if (!curr_timer->run) {
curr_timer->running = 0; ptimer_stop(curr_timer->timer);
}
// user timer limit is always the same // user timer limit is always the same
curr_timer->limit = TIMER_MAX_COUNT64; curr_timer->limit = TIMER_MAX_COUNT64;
ptimer_set_limit(curr_timer->timer, ptimer_set_limit(curr_timer->timer,
@ -296,13 +296,8 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
s->cputimer_mode |= processor; s->cputimer_mode |= processor;
trace_slavio_timer_mem_writel_mode_user(timer_index); trace_slavio_timer_mem_writel_mode_user(timer_index);
} else { // user timer -> counter } else { // user timer -> counter
// stop the user timer if it is running
if (curr_timer->running) {
ptimer_stop(curr_timer->timer);
}
// start the counter // start the counter
ptimer_run(curr_timer->timer, 0); ptimer_run(curr_timer->timer, 0);
curr_timer->running = 1;
// clear this processors user timer bit in config // clear this processors user timer bit in config
// register // register
s->cputimer_mode &= ~processor; s->cputimer_mode &= ~processor;
@ -340,7 +335,7 @@ static const VMStateDescription vmstate_timer = {
VMSTATE_UINT32(count, CPUTimerState), VMSTATE_UINT32(count, CPUTimerState),
VMSTATE_UINT32(counthigh, CPUTimerState), VMSTATE_UINT32(counthigh, CPUTimerState),
VMSTATE_UINT32(reached, CPUTimerState), VMSTATE_UINT32(reached, CPUTimerState),
VMSTATE_UINT32(running, CPUTimerState), VMSTATE_UINT32(run , CPUTimerState),
VMSTATE_PTIMER(timer, CPUTimerState), VMSTATE_PTIMER(timer, CPUTimerState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
} }
@ -373,7 +368,7 @@ static void slavio_timer_reset(DeviceState *d)
ptimer_set_limit(curr_timer->timer, ptimer_set_limit(curr_timer->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
ptimer_run(curr_timer->timer, 0); ptimer_run(curr_timer->timer, 0);
curr_timer->running = 1; curr_timer->run = 1;
} }
} }
s->cputimer_mode = 0; s->cputimer_mode = 0;