1e80cfcfcSbellard /* 2e80cfcfcSbellard * QEMU Sparc SLAVIO timer controller emulation 3e80cfcfcSbellard * 466321a11Sbellard * Copyright (c) 2003-2005 Fabrice Bellard 5e80cfcfcSbellard * 6e80cfcfcSbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7e80cfcfcSbellard * of this software and associated documentation files (the "Software"), to deal 8e80cfcfcSbellard * in the Software without restriction, including without limitation the rights 9e80cfcfcSbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10e80cfcfcSbellard * copies of the Software, and to permit persons to whom the Software is 11e80cfcfcSbellard * furnished to do so, subject to the following conditions: 12e80cfcfcSbellard * 13e80cfcfcSbellard * The above copyright notice and this permission notice shall be included in 14e80cfcfcSbellard * all copies or substantial portions of the Software. 15e80cfcfcSbellard * 16e80cfcfcSbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17e80cfcfcSbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18e80cfcfcSbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19e80cfcfcSbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20e80cfcfcSbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21e80cfcfcSbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22e80cfcfcSbellard * THE SOFTWARE. 23e80cfcfcSbellard */ 24c70c59eeSBlue Swirl 25282bc81eSPeter Maydell #include "qemu/osdep.h" 261de7afc9SPaolo Bonzini #include "qemu/timer.h" 2764552b6bSMarkus Armbruster #include "hw/irq.h" 2883c9f4caSPaolo Bonzini #include "hw/ptimer.h" 29a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 3083c9f4caSPaolo Bonzini #include "hw/sysbus.h" 31d6454270SMarkus Armbruster #include "migration/vmstate.h" 3297bf4851SBlue Swirl #include "trace.h" 330b8fa32fSMarkus Armbruster #include "qemu/module.h" 3466321a11Sbellard 35e80cfcfcSbellard /* 36e80cfcfcSbellard * Registers of hardware timer in sun4m. 37e80cfcfcSbellard * 38e80cfcfcSbellard * This is the timer/counter part of chip STP2001 (Slave I/O), also 39e80cfcfcSbellard * produced as NCR89C105. See 40e80cfcfcSbellard * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt 41e80cfcfcSbellard * 42e80cfcfcSbellard * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 43e80cfcfcSbellard * are zero. Bit 31 is 1 when count has been reached. 44e80cfcfcSbellard * 45ba3c64fbSbellard * Per-CPU timers interrupt local CPU, system timer uses normal 46ba3c64fbSbellard * interrupt routing. 47ba3c64fbSbellard * 48e80cfcfcSbellard */ 49e80cfcfcSbellard 5081732d19Sblueswir1 #define MAX_CPUS 16 5181732d19Sblueswir1 527204ff9cSBlue Swirl typedef struct CPUTimerState { 53d7edfd27Sblueswir1 qemu_irq irq; 548d05ea8aSblueswir1 ptimer_state *timer; 558d05ea8aSblueswir1 uint32_t count, counthigh, reached; 56f90074f4SBlue Swirl /* processor only */ 57ead4cf04SMark Cave-Ayland uint32_t run; 58f90074f4SBlue Swirl uint64_t limit; 597204ff9cSBlue Swirl } CPUTimerState; 607204ff9cSBlue Swirl 61c275471eSAndreas Färber #define TYPE_SLAVIO_TIMER "slavio_timer" 62c275471eSAndreas Färber #define SLAVIO_TIMER(obj) \ 63c275471eSAndreas Färber OBJECT_CHECK(SLAVIO_TIMERState, (obj), TYPE_SLAVIO_TIMER) 64c275471eSAndreas Färber 657204ff9cSBlue Swirl typedef struct SLAVIO_TIMERState { 66c275471eSAndreas Färber SysBusDevice parent_obj; 67c275471eSAndreas Färber 687204ff9cSBlue Swirl uint32_t num_cpus; 697204ff9cSBlue Swirl uint32_t cputimer_mode; 70f90074f4SBlue Swirl CPUTimerState cputimer[MAX_CPUS + 1]; 71e80cfcfcSbellard } SLAVIO_TIMERState; 72e80cfcfcSbellard 737204ff9cSBlue Swirl typedef struct TimerContext { 74a3d12d07SBenoît Canet MemoryRegion iomem; 757204ff9cSBlue Swirl SLAVIO_TIMERState *s; 767204ff9cSBlue Swirl unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */ 777204ff9cSBlue Swirl } TimerContext; 787204ff9cSBlue Swirl 79115646b6Sblueswir1 #define SYS_TIMER_SIZE 0x14 8081732d19Sblueswir1 #define CPU_TIMER_SIZE 0x10 81e80cfcfcSbellard 82d2c38b24Sblueswir1 #define TIMER_LIMIT 0 83d2c38b24Sblueswir1 #define TIMER_COUNTER 1 84d2c38b24Sblueswir1 #define TIMER_COUNTER_NORST 2 85d2c38b24Sblueswir1 #define TIMER_STATUS 3 86d2c38b24Sblueswir1 #define TIMER_MODE 4 87d2c38b24Sblueswir1 88d2c38b24Sblueswir1 #define TIMER_COUNT_MASK32 0xfffffe00 89d2c38b24Sblueswir1 #define TIMER_LIMIT_MASK32 0x7fffffff 90d2c38b24Sblueswir1 #define TIMER_MAX_COUNT64 0x7ffffffffffffe00ULL 91d2c38b24Sblueswir1 #define TIMER_MAX_COUNT32 0x7ffffe00ULL 92d2c38b24Sblueswir1 #define TIMER_REACHED 0x80000000 93d2c38b24Sblueswir1 #define TIMER_PERIOD 500ULL // 500ns 9468fb89a2SBlue Swirl #define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1) 9568fb89a2SBlue Swirl #define PERIODS_TO_LIMIT(l) (((l) + 1) << 9) 96d2c38b24Sblueswir1 977204ff9cSBlue Swirl static int slavio_timer_is_user(TimerContext *tc) 98115646b6Sblueswir1 { 997204ff9cSBlue Swirl SLAVIO_TIMERState *s = tc->s; 1007204ff9cSBlue Swirl unsigned int timer_index = tc->timer_index; 1017204ff9cSBlue Swirl 1027204ff9cSBlue Swirl return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1))); 103115646b6Sblueswir1 } 104115646b6Sblueswir1 105e80cfcfcSbellard // Update count, set irq, update expire_time 1068d05ea8aSblueswir1 // Convert from ptimer countdown units 1077204ff9cSBlue Swirl static void slavio_timer_get_out(CPUTimerState *t) 108e80cfcfcSbellard { 109bd7e2875Sblueswir1 uint64_t count, limit; 110e80cfcfcSbellard 1117204ff9cSBlue Swirl if (t->limit == 0) { /* free-run system or processor counter */ 112bd7e2875Sblueswir1 limit = TIMER_MAX_COUNT32; 1137204ff9cSBlue Swirl } else { 1147204ff9cSBlue Swirl limit = t->limit; 1157204ff9cSBlue Swirl } 1167204ff9cSBlue Swirl count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer)); 1179ebec28bSBlue Swirl 11897bf4851SBlue Swirl trace_slavio_timer_get_out(t->limit, t->counthigh, t->count); 1197204ff9cSBlue Swirl t->count = count & TIMER_COUNT_MASK32; 1207204ff9cSBlue Swirl t->counthigh = count >> 32; 121e80cfcfcSbellard } 122e80cfcfcSbellard 123e80cfcfcSbellard // timer callback 124e80cfcfcSbellard static void slavio_timer_irq(void *opaque) 125e80cfcfcSbellard { 1267204ff9cSBlue Swirl TimerContext *tc = opaque; 1277204ff9cSBlue Swirl SLAVIO_TIMERState *s = tc->s; 1287204ff9cSBlue Swirl CPUTimerState *t = &s->cputimer[tc->timer_index]; 129e80cfcfcSbellard 1307204ff9cSBlue Swirl slavio_timer_get_out(t); 13197bf4851SBlue Swirl trace_slavio_timer_irq(t->counthigh, t->count); 13268fb89a2SBlue Swirl /* if limit is 0 (free-run), there will be no match */ 13368fb89a2SBlue Swirl if (t->limit != 0) { 1347204ff9cSBlue Swirl t->reached = TIMER_REACHED; 13568fb89a2SBlue Swirl } 136452efba6SBlue Swirl /* there is no interrupt if user timer or free-run */ 137452efba6SBlue Swirl if (!slavio_timer_is_user(tc) && t->limit != 0) { 1387204ff9cSBlue Swirl qemu_irq_raise(t->irq); 1397204ff9cSBlue Swirl } 140e80cfcfcSbellard } 141e80cfcfcSbellard 142a8170e5eSAvi Kivity static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr, 143a3d12d07SBenoît Canet unsigned size) 144e80cfcfcSbellard { 1457204ff9cSBlue Swirl TimerContext *tc = opaque; 1467204ff9cSBlue Swirl SLAVIO_TIMERState *s = tc->s; 1478d05ea8aSblueswir1 uint32_t saddr, ret; 1487204ff9cSBlue Swirl unsigned int timer_index = tc->timer_index; 1497204ff9cSBlue Swirl CPUTimerState *t = &s->cputimer[timer_index]; 150e80cfcfcSbellard 151e64d7d59Sblueswir1 saddr = addr >> 2; 152e80cfcfcSbellard switch (saddr) { 153d2c38b24Sblueswir1 case TIMER_LIMIT: 154e80cfcfcSbellard // read limit (system counter mode) or read most signifying 155e80cfcfcSbellard // part of counter (user mode) 1567204ff9cSBlue Swirl if (slavio_timer_is_user(tc)) { 157115646b6Sblueswir1 // read user timer MSW 1587204ff9cSBlue Swirl slavio_timer_get_out(t); 1597204ff9cSBlue Swirl ret = t->counthigh | t->reached; 160115646b6Sblueswir1 } else { 161115646b6Sblueswir1 // read limit 162e80cfcfcSbellard // clear irq 1637204ff9cSBlue Swirl qemu_irq_lower(t->irq); 1647204ff9cSBlue Swirl t->reached = 0; 1657204ff9cSBlue Swirl ret = t->limit & TIMER_LIMIT_MASK32; 166e80cfcfcSbellard } 1678d05ea8aSblueswir1 break; 168d2c38b24Sblueswir1 case TIMER_COUNTER: 169e80cfcfcSbellard // read counter and reached bit (system mode) or read lsbits 170e80cfcfcSbellard // of counter (user mode) 1717204ff9cSBlue Swirl slavio_timer_get_out(t); 1727204ff9cSBlue Swirl if (slavio_timer_is_user(tc)) { // read user timer LSW 1737204ff9cSBlue Swirl ret = t->count & TIMER_MAX_COUNT64; 1747204ff9cSBlue Swirl } else { // read limit 1757204ff9cSBlue Swirl ret = (t->count & TIMER_MAX_COUNT32) | 1767204ff9cSBlue Swirl t->reached; 1777204ff9cSBlue Swirl } 1788d05ea8aSblueswir1 break; 179d2c38b24Sblueswir1 case TIMER_STATUS: 180115646b6Sblueswir1 // only available in processor counter/timer 181e80cfcfcSbellard // read start/stop status 1827204ff9cSBlue Swirl if (timer_index > 0) { 183ead4cf04SMark Cave-Ayland ret = t->run; 1847204ff9cSBlue Swirl } else { 1857204ff9cSBlue Swirl ret = 0; 1867204ff9cSBlue Swirl } 1878d05ea8aSblueswir1 break; 188d2c38b24Sblueswir1 case TIMER_MODE: 189115646b6Sblueswir1 // only available in system counter 190e80cfcfcSbellard // read user/system mode 1917204ff9cSBlue Swirl ret = s->cputimer_mode; 1928d05ea8aSblueswir1 break; 193e80cfcfcSbellard default: 19497bf4851SBlue Swirl trace_slavio_timer_mem_readl_invalid(addr); 1958d05ea8aSblueswir1 ret = 0; 1968d05ea8aSblueswir1 break; 197e80cfcfcSbellard } 19897bf4851SBlue Swirl trace_slavio_timer_mem_readl(addr, ret); 1998d05ea8aSblueswir1 return ret; 200e80cfcfcSbellard } 201e80cfcfcSbellard 202a8170e5eSAvi Kivity static void slavio_timer_mem_writel(void *opaque, hwaddr addr, 203a3d12d07SBenoît Canet uint64_t val, unsigned size) 204e80cfcfcSbellard { 2057204ff9cSBlue Swirl TimerContext *tc = opaque; 2067204ff9cSBlue Swirl SLAVIO_TIMERState *s = tc->s; 207e80cfcfcSbellard uint32_t saddr; 2087204ff9cSBlue Swirl unsigned int timer_index = tc->timer_index; 2097204ff9cSBlue Swirl CPUTimerState *t = &s->cputimer[timer_index]; 210e80cfcfcSbellard 21197bf4851SBlue Swirl trace_slavio_timer_mem_writel(addr, val); 212e64d7d59Sblueswir1 saddr = addr >> 2; 213e80cfcfcSbellard switch (saddr) { 214d2c38b24Sblueswir1 case TIMER_LIMIT: 215*2ee62f32SPeter Maydell ptimer_transaction_begin(t->timer); 2167204ff9cSBlue Swirl if (slavio_timer_is_user(tc)) { 217e1cb9502Sblueswir1 uint64_t count; 218e1cb9502Sblueswir1 219115646b6Sblueswir1 // set user counter MSW, reset counter 2207204ff9cSBlue Swirl t->limit = TIMER_MAX_COUNT64; 2217204ff9cSBlue Swirl t->counthigh = val & (TIMER_MAX_COUNT64 >> 32); 2227204ff9cSBlue Swirl t->reached = 0; 2237204ff9cSBlue Swirl count = ((uint64_t)t->counthigh << 32) | t->count; 22497bf4851SBlue Swirl trace_slavio_timer_mem_writel_limit(timer_index, count); 2257204ff9cSBlue Swirl ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); 226115646b6Sblueswir1 } else { 227e80cfcfcSbellard // set limit, reset counter 2287204ff9cSBlue Swirl qemu_irq_lower(t->irq); 2297204ff9cSBlue Swirl t->limit = val & TIMER_MAX_COUNT32; 2307204ff9cSBlue Swirl if (t->limit == 0) { /* free-run */ 2317204ff9cSBlue Swirl ptimer_set_limit(t->timer, 23277f193daSblueswir1 LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); 2337204ff9cSBlue Swirl } else { 2347204ff9cSBlue Swirl ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1); 2357204ff9cSBlue Swirl } 236115646b6Sblueswir1 } 237*2ee62f32SPeter Maydell ptimer_transaction_commit(t->timer); 238115646b6Sblueswir1 break; 239d2c38b24Sblueswir1 case TIMER_COUNTER: 2407204ff9cSBlue Swirl if (slavio_timer_is_user(tc)) { 241e1cb9502Sblueswir1 uint64_t count; 242e1cb9502Sblueswir1 243115646b6Sblueswir1 // set user counter LSW, reset counter 2447204ff9cSBlue Swirl t->limit = TIMER_MAX_COUNT64; 2457204ff9cSBlue Swirl t->count = val & TIMER_MAX_COUNT64; 2467204ff9cSBlue Swirl t->reached = 0; 2477204ff9cSBlue Swirl count = ((uint64_t)t->counthigh) << 32 | t->count; 24897bf4851SBlue Swirl trace_slavio_timer_mem_writel_limit(timer_index, count); 249*2ee62f32SPeter Maydell ptimer_transaction_begin(t->timer); 2507204ff9cSBlue Swirl ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); 251*2ee62f32SPeter Maydell ptimer_transaction_commit(t->timer); 25297bf4851SBlue Swirl } else { 25397bf4851SBlue Swirl trace_slavio_timer_mem_writel_counter_invalid(); 25497bf4851SBlue Swirl } 255115646b6Sblueswir1 break; 256d2c38b24Sblueswir1 case TIMER_COUNTER_NORST: 257e80cfcfcSbellard // set limit without resetting counter 2587204ff9cSBlue Swirl t->limit = val & TIMER_MAX_COUNT32; 259*2ee62f32SPeter Maydell ptimer_transaction_begin(t->timer); 2607204ff9cSBlue Swirl if (t->limit == 0) { /* free-run */ 2619ebec28bSBlue Swirl ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); 2627204ff9cSBlue Swirl } else { 2637204ff9cSBlue Swirl ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0); 2647204ff9cSBlue Swirl } 265*2ee62f32SPeter Maydell ptimer_transaction_commit(t->timer); 266e80cfcfcSbellard break; 267d2c38b24Sblueswir1 case TIMER_STATUS: 268*2ee62f32SPeter Maydell ptimer_transaction_begin(t->timer); 2697204ff9cSBlue Swirl if (slavio_timer_is_user(tc)) { 270e80cfcfcSbellard // start/stop user counter 271ead4cf04SMark Cave-Ayland if (val & 1) { 27297bf4851SBlue Swirl trace_slavio_timer_mem_writel_status_start(timer_index); 2737204ff9cSBlue Swirl ptimer_run(t->timer, 0); 274ead4cf04SMark Cave-Ayland } else { 27597bf4851SBlue Swirl trace_slavio_timer_mem_writel_status_stop(timer_index); 2767204ff9cSBlue Swirl ptimer_stop(t->timer); 277e80cfcfcSbellard } 278e80cfcfcSbellard } 279ead4cf04SMark Cave-Ayland t->run = val & 1; 280*2ee62f32SPeter Maydell ptimer_transaction_commit(t->timer); 281e80cfcfcSbellard break; 282d2c38b24Sblueswir1 case TIMER_MODE: 2837204ff9cSBlue Swirl if (timer_index == 0) { 28481732d19Sblueswir1 unsigned int i; 28581732d19Sblueswir1 2867204ff9cSBlue Swirl for (i = 0; i < s->num_cpus; i++) { 28767e42751Sblueswir1 unsigned int processor = 1 << i; 2887204ff9cSBlue Swirl CPUTimerState *curr_timer = &s->cputimer[i + 1]; 28967e42751Sblueswir1 290*2ee62f32SPeter Maydell ptimer_transaction_begin(curr_timer->timer); 29167e42751Sblueswir1 // check for a change in timer mode for this processor 2927204ff9cSBlue Swirl if ((val & processor) != (s->cputimer_mode & processor)) { 29367e42751Sblueswir1 if (val & processor) { // counter -> user timer 2947204ff9cSBlue Swirl qemu_irq_lower(curr_timer->irq); 29567e42751Sblueswir1 // counters are always running 296ead4cf04SMark Cave-Ayland if (!curr_timer->run) { 2977204ff9cSBlue Swirl ptimer_stop(curr_timer->timer); 298ead4cf04SMark Cave-Ayland } 29967e42751Sblueswir1 // user timer limit is always the same 3007204ff9cSBlue Swirl curr_timer->limit = TIMER_MAX_COUNT64; 3017204ff9cSBlue Swirl ptimer_set_limit(curr_timer->timer, 3027204ff9cSBlue Swirl LIMIT_TO_PERIODS(curr_timer->limit), 30377f193daSblueswir1 1); 30467e42751Sblueswir1 // set this processors user timer bit in config 30567e42751Sblueswir1 // register 3067204ff9cSBlue Swirl s->cputimer_mode |= processor; 30797bf4851SBlue Swirl trace_slavio_timer_mem_writel_mode_user(timer_index); 30867e42751Sblueswir1 } else { // user timer -> counter 30967e42751Sblueswir1 // start the counter 3107204ff9cSBlue Swirl ptimer_run(curr_timer->timer, 0); 31167e42751Sblueswir1 // clear this processors user timer bit in config 31267e42751Sblueswir1 // register 3137204ff9cSBlue Swirl s->cputimer_mode &= ~processor; 31497bf4851SBlue Swirl trace_slavio_timer_mem_writel_mode_counter(timer_index); 31581732d19Sblueswir1 } 31681732d19Sblueswir1 } 317*2ee62f32SPeter Maydell ptimer_transaction_commit(curr_timer->timer); 31867e42751Sblueswir1 } 3197204ff9cSBlue Swirl } else { 32097bf4851SBlue Swirl trace_slavio_timer_mem_writel_mode_invalid(); 3217204ff9cSBlue Swirl } 322e80cfcfcSbellard break; 323e80cfcfcSbellard default: 32497bf4851SBlue Swirl trace_slavio_timer_mem_writel_invalid(addr); 325e80cfcfcSbellard break; 326e80cfcfcSbellard } 327e80cfcfcSbellard } 328e80cfcfcSbellard 329a3d12d07SBenoît Canet static const MemoryRegionOps slavio_timer_mem_ops = { 330a3d12d07SBenoît Canet .read = slavio_timer_mem_readl, 331a3d12d07SBenoît Canet .write = slavio_timer_mem_writel, 332a3d12d07SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 333a3d12d07SBenoît Canet .valid = { 334a3d12d07SBenoît Canet .min_access_size = 4, 335a3d12d07SBenoît Canet .max_access_size = 4, 336a3d12d07SBenoît Canet }, 337e80cfcfcSbellard }; 338e80cfcfcSbellard 339f4b19cd0SBlue Swirl static const VMStateDescription vmstate_timer = { 340f4b19cd0SBlue Swirl .name ="timer", 341f4b19cd0SBlue Swirl .version_id = 3, 342f4b19cd0SBlue Swirl .minimum_version_id = 3, 343f4b19cd0SBlue Swirl .fields = (VMStateField[]) { 344f4b19cd0SBlue Swirl VMSTATE_UINT64(limit, CPUTimerState), 345f4b19cd0SBlue Swirl VMSTATE_UINT32(count, CPUTimerState), 346f4b19cd0SBlue Swirl VMSTATE_UINT32(counthigh, CPUTimerState), 347f4b19cd0SBlue Swirl VMSTATE_UINT32(reached, CPUTimerState), 348ead4cf04SMark Cave-Ayland VMSTATE_UINT32(run , CPUTimerState), 349f4b19cd0SBlue Swirl VMSTATE_PTIMER(timer, CPUTimerState), 350f4b19cd0SBlue Swirl VMSTATE_END_OF_LIST() 3517204ff9cSBlue Swirl } 352f4b19cd0SBlue Swirl }; 353f4b19cd0SBlue Swirl 354f4b19cd0SBlue Swirl static const VMStateDescription vmstate_slavio_timer = { 355f4b19cd0SBlue Swirl .name ="slavio_timer", 356f4b19cd0SBlue Swirl .version_id = 3, 357f4b19cd0SBlue Swirl .minimum_version_id = 3, 358f4b19cd0SBlue Swirl .fields = (VMStateField[]) { 359f4b19cd0SBlue Swirl VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3, 360f4b19cd0SBlue Swirl vmstate_timer, CPUTimerState), 361f4b19cd0SBlue Swirl VMSTATE_END_OF_LIST() 3627204ff9cSBlue Swirl } 363f4b19cd0SBlue Swirl }; 364e80cfcfcSbellard 3650e0bfeeaSBlue Swirl static void slavio_timer_reset(DeviceState *d) 366e80cfcfcSbellard { 367c275471eSAndreas Färber SLAVIO_TIMERState *s = SLAVIO_TIMER(d); 3687204ff9cSBlue Swirl unsigned int i; 3697204ff9cSBlue Swirl CPUTimerState *curr_timer; 370e80cfcfcSbellard 3717204ff9cSBlue Swirl for (i = 0; i <= MAX_CPUS; i++) { 3727204ff9cSBlue Swirl curr_timer = &s->cputimer[i]; 3737204ff9cSBlue Swirl curr_timer->limit = 0; 3747204ff9cSBlue Swirl curr_timer->count = 0; 3757204ff9cSBlue Swirl curr_timer->reached = 0; 3765933e8a9SArtyom Tarasenko if (i <= s->num_cpus) { 377*2ee62f32SPeter Maydell ptimer_transaction_begin(curr_timer->timer); 3787204ff9cSBlue Swirl ptimer_set_limit(curr_timer->timer, 3797204ff9cSBlue Swirl LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); 3807204ff9cSBlue Swirl ptimer_run(curr_timer->timer, 0); 381ead4cf04SMark Cave-Ayland curr_timer->run = 1; 382*2ee62f32SPeter Maydell ptimer_transaction_commit(curr_timer->timer); 3837204ff9cSBlue Swirl } 3845933e8a9SArtyom Tarasenko } 3857204ff9cSBlue Swirl s->cputimer_mode = 0; 386e80cfcfcSbellard } 387e80cfcfcSbellard 3884410b94cSxiaoqiang zhao static void slavio_timer_init(Object *obj) 389c70c59eeSBlue Swirl { 3904410b94cSxiaoqiang zhao SLAVIO_TIMERState *s = SLAVIO_TIMER(obj); 3914410b94cSxiaoqiang zhao SysBusDevice *dev = SYS_BUS_DEVICE(obj); 3927204ff9cSBlue Swirl unsigned int i; 3937204ff9cSBlue Swirl TimerContext *tc; 394e80cfcfcSbellard 3957204ff9cSBlue Swirl for (i = 0; i <= MAX_CPUS; i++) { 396a3d12d07SBenoît Canet uint64_t size; 397a3d12d07SBenoît Canet char timer_name[20]; 398a3d12d07SBenoît Canet 3997267c094SAnthony Liguori tc = g_malloc0(sizeof(TimerContext)); 4007204ff9cSBlue Swirl tc->s = s; 4017204ff9cSBlue Swirl tc->timer_index = i; 402c70c59eeSBlue Swirl 403*2ee62f32SPeter Maydell s->cputimer[i].timer = ptimer_init(slavio_timer_irq, tc, 404*2ee62f32SPeter Maydell PTIMER_POLICY_DEFAULT); 405*2ee62f32SPeter Maydell ptimer_transaction_begin(s->cputimer[i].timer); 4067204ff9cSBlue Swirl ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD); 407*2ee62f32SPeter Maydell ptimer_transaction_commit(s->cputimer[i].timer); 4087204ff9cSBlue Swirl 409a3d12d07SBenoît Canet size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE; 410a3d12d07SBenoît Canet snprintf(timer_name, sizeof(timer_name), "timer-%i", i); 4114410b94cSxiaoqiang zhao memory_region_init_io(&tc->iomem, obj, &slavio_timer_mem_ops, tc, 412a3d12d07SBenoît Canet timer_name, size); 413750ecd44SAvi Kivity sysbus_init_mmio(dev, &tc->iomem); 414e80cfcfcSbellard 4157204ff9cSBlue Swirl sysbus_init_irq(dev, &s->cputimer[i].irq); 416c70c59eeSBlue Swirl } 41781732d19Sblueswir1 } 41881732d19Sblueswir1 419999e12bbSAnthony Liguori static Property slavio_timer_properties[] = { 42018c637dcSGerd Hoffmann DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0), 42118c637dcSGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 422999e12bbSAnthony Liguori }; 423999e12bbSAnthony Liguori 424999e12bbSAnthony Liguori static void slavio_timer_class_init(ObjectClass *klass, void *data) 425999e12bbSAnthony Liguori { 42639bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 427999e12bbSAnthony Liguori 42839bffca2SAnthony Liguori dc->reset = slavio_timer_reset; 42939bffca2SAnthony Liguori dc->vmsd = &vmstate_slavio_timer; 43039bffca2SAnthony Liguori dc->props = slavio_timer_properties; 431c70c59eeSBlue Swirl } 432999e12bbSAnthony Liguori 4338c43a6f0SAndreas Färber static const TypeInfo slavio_timer_info = { 434c275471eSAndreas Färber .name = TYPE_SLAVIO_TIMER, 43539bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 43639bffca2SAnthony Liguori .instance_size = sizeof(SLAVIO_TIMERState), 4374410b94cSxiaoqiang zhao .instance_init = slavio_timer_init, 438999e12bbSAnthony Liguori .class_init = slavio_timer_class_init, 439c70c59eeSBlue Swirl }; 440c70c59eeSBlue Swirl 44183f7d43aSAndreas Färber static void slavio_timer_register_types(void) 442c70c59eeSBlue Swirl { 44339bffca2SAnthony Liguori type_register_static(&slavio_timer_info); 444c70c59eeSBlue Swirl } 445c70c59eeSBlue Swirl 44683f7d43aSAndreas Färber type_init(slavio_timer_register_types) 447