static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr, unsigned size) { TimerContext *tc = opaque; SLAVIO_TIMERState *s = tc->s; uint32_t saddr, ret; unsigned int timer_index = tc->timer_index; CPUTimerState *t = &s->cputimer[timer_index]; saddr = addr >> 2; switch (saddr) { case TIMER_LIMIT: // read limit (system counter mode) or read most signifying // part of counter (user mode) if (slavio_timer_is_user(tc)) { // read user timer MSW slavio_timer_get_out(t); ret = t->counthigh | t->reached; } else { // read limit // clear irq qemu_irq_lower(t->irq); t->reached = 0; ret = t->limit & TIMER_LIMIT_MASK32; } break; case TIMER_COUNTER: // read counter and reached bit (system mode) or read lsbits // of counter (user mode) slavio_timer_get_out(t); if (slavio_timer_is_user(tc)) { // read user timer LSW ret = t->count & TIMER_MAX_COUNT64; } else { // read limit ret = (t->count & TIMER_MAX_COUNT32) | t->reached; } break; case TIMER_STATUS: // only available in processor counter/timer // read start/stop status if (timer_index > 0) { ret = t->run; } else { ret = 0; } break; case TIMER_MODE: // only available in system counter // read user/system mode ret = s->cputimer_mode; break; default: trace_slavio_timer_mem_readl_invalid(addr); ret = 0; break; } trace_slavio_timer_mem_readl(addr, ret); return ret; }
static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) { SLAVIO_TIMERState *s = opaque; uint32_t saddr, ret; saddr = addr >> 2; switch (saddr) { case TIMER_LIMIT: // read limit (system counter mode) or read most signifying // part of counter (user mode) if (slavio_timer_is_user(s)) { // read user timer MSW slavio_timer_get_out(s); ret = s->counthigh | s->reached; } else { // read limit // clear irq qemu_irq_lower(s->irq); s->reached = 0; ret = s->limit & TIMER_LIMIT_MASK32; } break; case TIMER_COUNTER: // read counter and reached bit (system mode) or read lsbits // of counter (user mode) slavio_timer_get_out(s); if (slavio_timer_is_user(s)) // read user timer LSW ret = s->count & TIMER_MAX_COUNT64; else // read limit ret = (s->count & TIMER_MAX_COUNT32) | s->reached; break; case TIMER_STATUS: // only available in processor counter/timer // read start/stop status ret = s->running; break; case TIMER_MODE: // only available in system counter // read user/system mode ret = s->slave_mode; break; default: DPRINTF("invalid read address " TARGET_FMT_plx "\n", addr); ret = 0; break; } DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret); return ret; }
// timer callback static void slavio_timer_irq(void *opaque) { SLAVIO_TIMERState *s = opaque; slavio_timer_get_out(s); DPRINTF("callback: count %x%08x\n", s->counthigh, s->count); s->reached = TIMER_REACHED; if (!slavio_timer_is_user(s)) qemu_irq_raise(s->irq); }
// timer callback static void slavio_timer_irq(void *opaque) { TimerContext *tc = opaque; SLAVIO_TIMERState *s = tc->s; CPUTimerState *t = &s->cputimer[tc->timer_index]; slavio_timer_get_out(t); DPRINTF("callback: count %x%08x\n", t->counthigh, t->count); t->reached = TIMER_REACHED; if (!slavio_timer_is_user(tc)) { qemu_irq_raise(t->irq); } }
// timer callback static void slavio_timer_irq(void *opaque) { TimerContext *tc = opaque; SLAVIO_TIMERState *s = tc->s; CPUTimerState *t = &s->cputimer[tc->timer_index]; slavio_timer_get_out(t); trace_slavio_timer_irq(t->counthigh, t->count); /* if limit is 0 (free-run), there will be no match */ if (t->limit != 0) { t->reached = TIMER_REACHED; } /* there is no interrupt if user timer or free-run */ if (!slavio_timer_is_user(tc) && t->limit != 0) { qemu_irq_raise(t->irq); } }
static void slavio_timer_mem_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { TimerContext *tc = opaque; SLAVIO_TIMERState *s = tc->s; uint32_t saddr; unsigned int timer_index = tc->timer_index; CPUTimerState *t = &s->cputimer[timer_index]; trace_slavio_timer_mem_writel(addr, val); saddr = addr >> 2; switch (saddr) { case TIMER_LIMIT: if (slavio_timer_is_user(tc)) { uint64_t count; // set user counter MSW, reset counter t->limit = TIMER_MAX_COUNT64; t->counthigh = val & (TIMER_MAX_COUNT64 >> 32); t->reached = 0; count = ((uint64_t)t->counthigh << 32) | t->count; trace_slavio_timer_mem_writel_limit(timer_index, count); ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); } else { // set limit, reset counter qemu_irq_lower(t->irq); t->limit = val & TIMER_MAX_COUNT32; if (t->timer) { if (t->limit == 0) { /* free-run */ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); } else { ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1); } } } break; case TIMER_COUNTER: if (slavio_timer_is_user(tc)) { uint64_t count; // set user counter LSW, reset counter t->limit = TIMER_MAX_COUNT64; t->count = val & TIMER_MAX_COUNT64; t->reached = 0; count = ((uint64_t)t->counthigh) << 32 | t->count; trace_slavio_timer_mem_writel_limit(timer_index, count); ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); } else { trace_slavio_timer_mem_writel_counter_invalid(); } break; case TIMER_COUNTER_NORST: // set limit without resetting counter t->limit = val & TIMER_MAX_COUNT32; if (t->limit == 0) { /* free-run */ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); } else { ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0); } break; case TIMER_STATUS: if (slavio_timer_is_user(tc)) { // start/stop user counter if (val & 1) { trace_slavio_timer_mem_writel_status_start(timer_index); ptimer_run(t->timer, 0); } else { trace_slavio_timer_mem_writel_status_stop(timer_index); ptimer_stop(t->timer); } } t->run = val & 1; break; case TIMER_MODE: if (timer_index == 0) { unsigned int i; for (i = 0; i < s->num_cpus; i++) { unsigned int processor = 1 << i; CPUTimerState *curr_timer = &s->cputimer[i + 1]; // check for a change in timer mode for this processor if ((val & processor) != (s->cputimer_mode & processor)) { if (val & processor) { // counter -> user timer qemu_irq_lower(curr_timer->irq); // counters are always running if (!curr_timer->run) { ptimer_stop(curr_timer->timer); } // user timer limit is always the same curr_timer->limit = TIMER_MAX_COUNT64; ptimer_set_limit(curr_timer->timer, LIMIT_TO_PERIODS(curr_timer->limit), 1); // set this processors user timer bit in config // register s->cputimer_mode |= processor; trace_slavio_timer_mem_writel_mode_user(timer_index); } else { // user timer -> counter // start the counter ptimer_run(curr_timer->timer, 0); // clear this processors user timer bit in config // register s->cputimer_mode &= ~processor; trace_slavio_timer_mem_writel_mode_counter(timer_index); } } } } else { trace_slavio_timer_mem_writel_mode_invalid(); } break; default: trace_slavio_timer_mem_writel_invalid(addr); break; }
static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { TimerContext *tc = opaque; SLAVIO_TIMERState *s = tc->s; uint32_t saddr; unsigned int timer_index = tc->timer_index; CPUTimerState *t = &s->cputimer[timer_index]; DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val); saddr = addr >> 2; switch (saddr) { case TIMER_LIMIT: if (slavio_timer_is_user(tc)) { uint64_t count; // set user counter MSW, reset counter t->limit = TIMER_MAX_COUNT64; t->counthigh = val & (TIMER_MAX_COUNT64 >> 32); t->reached = 0; count = ((uint64_t)t->counthigh << 32) | t->count; DPRINTF("processor %d user timer set to %016" PRIx64 "\n", timer_index, count); ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); } else { // set limit, reset counter qemu_irq_lower(t->irq); t->limit = val & TIMER_MAX_COUNT32; if (t->timer) { if (t->limit == 0) { /* free-run */ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); } else { ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1); } } } break; case TIMER_COUNTER: if (slavio_timer_is_user(tc)) { uint64_t count; // set user counter LSW, reset counter t->limit = TIMER_MAX_COUNT64; t->count = val & TIMER_MAX_COUNT64; t->reached = 0; count = ((uint64_t)t->counthigh) << 32 | t->count; DPRINTF("processor %d user timer set to %016" PRIx64 "\n", timer_index, count); ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); } else DPRINTF("not user timer\n"); break; case TIMER_COUNTER_NORST: // set limit without resetting counter t->limit = val & TIMER_MAX_COUNT32; if (t->limit == 0) { /* free-run */ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); } else { ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0); } break; case TIMER_STATUS: if (slavio_timer_is_user(tc)) { // start/stop user counter if ((val & 1) && !t->running) { DPRINTF("processor %d user timer started\n", timer_index); ptimer_run(t->timer, 0); t->running = 1; } else if (!(val & 1) && t->running) { DPRINTF("processor %d user timer stopped\n", timer_index); ptimer_stop(t->timer); t->running = 0; } } break; case TIMER_MODE: if (timer_index == 0) { unsigned int i; for (i = 0; i < s->num_cpus; i++) { unsigned int processor = 1 << i; CPUTimerState *curr_timer = &s->cputimer[i + 1]; // check for a change in timer mode for this processor if ((val & processor) != (s->cputimer_mode & processor)) { if (val & processor) { // counter -> user timer qemu_irq_lower(curr_timer->irq); // counters are always running ptimer_stop(curr_timer->timer); curr_timer->running = 0; // user timer limit is always the same curr_timer->limit = TIMER_MAX_COUNT64; ptimer_set_limit(curr_timer->timer, LIMIT_TO_PERIODS(curr_timer->limit), 1); // set this processors user timer bit in config // register s->cputimer_mode |= processor; DPRINTF("processor %d changed from counter to user " "timer\n", timer_index); } else { // user timer -> counter // stop the user timer if it is running if (curr_timer->running) { ptimer_stop(curr_timer->timer); } // start the counter ptimer_run(curr_timer->timer, 0); curr_timer->running = 1; // clear this processors user timer bit in config // register s->cputimer_mode &= ~processor; DPRINTF("processor %d changed from user timer to " "counter\n", timer_index); } } } } else { DPRINTF("not system timer\n"); } break; default: DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr); break; }