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; }