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 250d09e41aSPaolo Bonzini #include "hw/sparc/sun4m.h" 261de7afc9SPaolo Bonzini #include "qemu/timer.h" 2783c9f4caSPaolo Bonzini #include "hw/ptimer.h" 2883c9f4caSPaolo Bonzini #include "hw/sysbus.h" 2997bf4851SBlue Swirl #include "trace.h" 3066321a11Sbellard 31e80cfcfcSbellard /* 32e80cfcfcSbellard * Registers of hardware timer in sun4m. 33e80cfcfcSbellard * 34e80cfcfcSbellard * This is the timer/counter part of chip STP2001 (Slave I/O), also 35e80cfcfcSbellard * produced as NCR89C105. See 36e80cfcfcSbellard * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt 37e80cfcfcSbellard * 38e80cfcfcSbellard * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 39e80cfcfcSbellard * are zero. Bit 31 is 1 when count has been reached. 40e80cfcfcSbellard * 41ba3c64fbSbellard * Per-CPU timers interrupt local CPU, system timer uses normal 42ba3c64fbSbellard * interrupt routing. 43ba3c64fbSbellard * 44e80cfcfcSbellard */ 45e80cfcfcSbellard 4681732d19Sblueswir1 #define MAX_CPUS 16 4781732d19Sblueswir1 487204ff9cSBlue Swirl typedef struct CPUTimerState { 49d7edfd27Sblueswir1 qemu_irq irq; 508d05ea8aSblueswir1 ptimer_state *timer; 518d05ea8aSblueswir1 uint32_t count, counthigh, reached; 52f90074f4SBlue Swirl /* processor only */ 5322548760Sblueswir1 uint32_t running; 54f90074f4SBlue Swirl uint64_t limit; 557204ff9cSBlue Swirl } CPUTimerState; 567204ff9cSBlue Swirl 57*c275471eSAndreas Färber #define TYPE_SLAVIO_TIMER "slavio_timer" 58*c275471eSAndreas Färber #define SLAVIO_TIMER(obj) \ 59*c275471eSAndreas Färber OBJECT_CHECK(SLAVIO_TIMERState, (obj), TYPE_SLAVIO_TIMER) 60*c275471eSAndreas Färber 617204ff9cSBlue Swirl typedef struct SLAVIO_TIMERState { 62*c275471eSAndreas Färber SysBusDevice parent_obj; 63*c275471eSAndreas Färber 647204ff9cSBlue Swirl uint32_t num_cpus; 657204ff9cSBlue Swirl uint32_t cputimer_mode; 66f90074f4SBlue Swirl CPUTimerState cputimer[MAX_CPUS + 1]; 67e80cfcfcSbellard } SLAVIO_TIMERState; 68e80cfcfcSbellard 697204ff9cSBlue Swirl typedef struct TimerContext { 70a3d12d07SBenoît Canet MemoryRegion iomem; 717204ff9cSBlue Swirl SLAVIO_TIMERState *s; 727204ff9cSBlue Swirl unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */ 737204ff9cSBlue Swirl } TimerContext; 747204ff9cSBlue Swirl 75115646b6Sblueswir1 #define SYS_TIMER_SIZE 0x14 7681732d19Sblueswir1 #define CPU_TIMER_SIZE 0x10 77e80cfcfcSbellard 78d2c38b24Sblueswir1 #define TIMER_LIMIT 0 79d2c38b24Sblueswir1 #define TIMER_COUNTER 1 80d2c38b24Sblueswir1 #define TIMER_COUNTER_NORST 2 81d2c38b24Sblueswir1 #define TIMER_STATUS 3 82d2c38b24Sblueswir1 #define TIMER_MODE 4 83d2c38b24Sblueswir1 84d2c38b24Sblueswir1 #define TIMER_COUNT_MASK32 0xfffffe00 85d2c38b24Sblueswir1 #define TIMER_LIMIT_MASK32 0x7fffffff 86d2c38b24Sblueswir1 #define TIMER_MAX_COUNT64 0x7ffffffffffffe00ULL 87d2c38b24Sblueswir1 #define TIMER_MAX_COUNT32 0x7ffffe00ULL 88d2c38b24Sblueswir1 #define TIMER_REACHED 0x80000000 89d2c38b24Sblueswir1 #define TIMER_PERIOD 500ULL // 500ns 9068fb89a2SBlue Swirl #define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1) 9168fb89a2SBlue Swirl #define PERIODS_TO_LIMIT(l) (((l) + 1) << 9) 92d2c38b24Sblueswir1 937204ff9cSBlue Swirl static int slavio_timer_is_user(TimerContext *tc) 94115646b6Sblueswir1 { 957204ff9cSBlue Swirl SLAVIO_TIMERState *s = tc->s; 967204ff9cSBlue Swirl unsigned int timer_index = tc->timer_index; 977204ff9cSBlue Swirl 987204ff9cSBlue Swirl return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1))); 99115646b6Sblueswir1 } 100115646b6Sblueswir1 101e80cfcfcSbellard // Update count, set irq, update expire_time 1028d05ea8aSblueswir1 // Convert from ptimer countdown units 1037204ff9cSBlue Swirl static void slavio_timer_get_out(CPUTimerState *t) 104e80cfcfcSbellard { 105bd7e2875Sblueswir1 uint64_t count, limit; 106e80cfcfcSbellard 1077204ff9cSBlue Swirl if (t->limit == 0) { /* free-run system or processor counter */ 108bd7e2875Sblueswir1 limit = TIMER_MAX_COUNT32; 1097204ff9cSBlue Swirl } else { 1107204ff9cSBlue Swirl limit = t->limit; 1117204ff9cSBlue Swirl } 1127204ff9cSBlue Swirl count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer)); 1139ebec28bSBlue Swirl 11497bf4851SBlue Swirl trace_slavio_timer_get_out(t->limit, t->counthigh, t->count); 1157204ff9cSBlue Swirl t->count = count & TIMER_COUNT_MASK32; 1167204ff9cSBlue Swirl t->counthigh = count >> 32; 117e80cfcfcSbellard } 118e80cfcfcSbellard 119e80cfcfcSbellard // timer callback 120e80cfcfcSbellard static void slavio_timer_irq(void *opaque) 121e80cfcfcSbellard { 1227204ff9cSBlue Swirl TimerContext *tc = opaque; 1237204ff9cSBlue Swirl SLAVIO_TIMERState *s = tc->s; 1247204ff9cSBlue Swirl CPUTimerState *t = &s->cputimer[tc->timer_index]; 125e80cfcfcSbellard 1267204ff9cSBlue Swirl slavio_timer_get_out(t); 12797bf4851SBlue Swirl trace_slavio_timer_irq(t->counthigh, t->count); 12868fb89a2SBlue Swirl /* if limit is 0 (free-run), there will be no match */ 12968fb89a2SBlue Swirl if (t->limit != 0) { 1307204ff9cSBlue Swirl t->reached = TIMER_REACHED; 13168fb89a2SBlue Swirl } 132452efba6SBlue Swirl /* there is no interrupt if user timer or free-run */ 133452efba6SBlue Swirl if (!slavio_timer_is_user(tc) && t->limit != 0) { 1347204ff9cSBlue Swirl qemu_irq_raise(t->irq); 1357204ff9cSBlue Swirl } 136e80cfcfcSbellard } 137e80cfcfcSbellard 138a8170e5eSAvi Kivity static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr, 139a3d12d07SBenoît Canet unsigned size) 140e80cfcfcSbellard { 1417204ff9cSBlue Swirl TimerContext *tc = opaque; 1427204ff9cSBlue Swirl SLAVIO_TIMERState *s = tc->s; 1438d05ea8aSblueswir1 uint32_t saddr, ret; 1447204ff9cSBlue Swirl unsigned int timer_index = tc->timer_index; 1457204ff9cSBlue Swirl CPUTimerState *t = &s->cputimer[timer_index]; 146e80cfcfcSbellard 147e64d7d59Sblueswir1 saddr = addr >> 2; 148e80cfcfcSbellard switch (saddr) { 149d2c38b24Sblueswir1 case TIMER_LIMIT: 150e80cfcfcSbellard // read limit (system counter mode) or read most signifying 151e80cfcfcSbellard // part of counter (user mode) 1527204ff9cSBlue Swirl if (slavio_timer_is_user(tc)) { 153115646b6Sblueswir1 // read user timer MSW 1547204ff9cSBlue Swirl slavio_timer_get_out(t); 1557204ff9cSBlue Swirl ret = t->counthigh | t->reached; 156115646b6Sblueswir1 } else { 157115646b6Sblueswir1 // read limit 158e80cfcfcSbellard // clear irq 1597204ff9cSBlue Swirl qemu_irq_lower(t->irq); 1607204ff9cSBlue Swirl t->reached = 0; 1617204ff9cSBlue Swirl ret = t->limit & TIMER_LIMIT_MASK32; 162e80cfcfcSbellard } 1638d05ea8aSblueswir1 break; 164d2c38b24Sblueswir1 case TIMER_COUNTER: 165e80cfcfcSbellard // read counter and reached bit (system mode) or read lsbits 166e80cfcfcSbellard // of counter (user mode) 1677204ff9cSBlue Swirl slavio_timer_get_out(t); 1687204ff9cSBlue Swirl if (slavio_timer_is_user(tc)) { // read user timer LSW 1697204ff9cSBlue Swirl ret = t->count & TIMER_MAX_COUNT64; 1707204ff9cSBlue Swirl } else { // read limit 1717204ff9cSBlue Swirl ret = (t->count & TIMER_MAX_COUNT32) | 1727204ff9cSBlue Swirl t->reached; 1737204ff9cSBlue Swirl } 1748d05ea8aSblueswir1 break; 175d2c38b24Sblueswir1 case TIMER_STATUS: 176115646b6Sblueswir1 // only available in processor counter/timer 177e80cfcfcSbellard // read start/stop status 1787204ff9cSBlue Swirl if (timer_index > 0) { 1797204ff9cSBlue Swirl ret = t->running; 1807204ff9cSBlue Swirl } else { 1817204ff9cSBlue Swirl ret = 0; 1827204ff9cSBlue Swirl } 1838d05ea8aSblueswir1 break; 184d2c38b24Sblueswir1 case TIMER_MODE: 185115646b6Sblueswir1 // only available in system counter 186e80cfcfcSbellard // read user/system mode 1877204ff9cSBlue Swirl ret = s->cputimer_mode; 1888d05ea8aSblueswir1 break; 189e80cfcfcSbellard default: 19097bf4851SBlue Swirl trace_slavio_timer_mem_readl_invalid(addr); 1918d05ea8aSblueswir1 ret = 0; 1928d05ea8aSblueswir1 break; 193e80cfcfcSbellard } 19497bf4851SBlue Swirl trace_slavio_timer_mem_readl(addr, ret); 1958d05ea8aSblueswir1 return ret; 196e80cfcfcSbellard } 197e80cfcfcSbellard 198a8170e5eSAvi Kivity static void slavio_timer_mem_writel(void *opaque, hwaddr addr, 199a3d12d07SBenoît Canet uint64_t val, unsigned size) 200e80cfcfcSbellard { 2017204ff9cSBlue Swirl TimerContext *tc = opaque; 2027204ff9cSBlue Swirl SLAVIO_TIMERState *s = tc->s; 203e80cfcfcSbellard uint32_t saddr; 2047204ff9cSBlue Swirl unsigned int timer_index = tc->timer_index; 2057204ff9cSBlue Swirl CPUTimerState *t = &s->cputimer[timer_index]; 206e80cfcfcSbellard 20797bf4851SBlue Swirl trace_slavio_timer_mem_writel(addr, val); 208e64d7d59Sblueswir1 saddr = addr >> 2; 209e80cfcfcSbellard switch (saddr) { 210d2c38b24Sblueswir1 case TIMER_LIMIT: 2117204ff9cSBlue Swirl if (slavio_timer_is_user(tc)) { 212e1cb9502Sblueswir1 uint64_t count; 213e1cb9502Sblueswir1 214115646b6Sblueswir1 // set user counter MSW, reset counter 2157204ff9cSBlue Swirl t->limit = TIMER_MAX_COUNT64; 2167204ff9cSBlue Swirl t->counthigh = val & (TIMER_MAX_COUNT64 >> 32); 2177204ff9cSBlue Swirl t->reached = 0; 2187204ff9cSBlue Swirl count = ((uint64_t)t->counthigh << 32) | t->count; 21997bf4851SBlue Swirl trace_slavio_timer_mem_writel_limit(timer_index, count); 2207204ff9cSBlue Swirl ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); 221115646b6Sblueswir1 } else { 222e80cfcfcSbellard // set limit, reset counter 2237204ff9cSBlue Swirl qemu_irq_lower(t->irq); 2247204ff9cSBlue Swirl t->limit = val & TIMER_MAX_COUNT32; 2257204ff9cSBlue Swirl if (t->timer) { 2267204ff9cSBlue Swirl if (t->limit == 0) { /* free-run */ 2277204ff9cSBlue Swirl ptimer_set_limit(t->timer, 22877f193daSblueswir1 LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); 2297204ff9cSBlue Swirl } else { 2307204ff9cSBlue Swirl ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1); 2317204ff9cSBlue Swirl } 232115646b6Sblueswir1 } 23385e3023eSblueswir1 } 234115646b6Sblueswir1 break; 235d2c38b24Sblueswir1 case TIMER_COUNTER: 2367204ff9cSBlue Swirl if (slavio_timer_is_user(tc)) { 237e1cb9502Sblueswir1 uint64_t count; 238e1cb9502Sblueswir1 239115646b6Sblueswir1 // set user counter LSW, reset counter 2407204ff9cSBlue Swirl t->limit = TIMER_MAX_COUNT64; 2417204ff9cSBlue Swirl t->count = val & TIMER_MAX_COUNT64; 2427204ff9cSBlue Swirl t->reached = 0; 2437204ff9cSBlue Swirl count = ((uint64_t)t->counthigh) << 32 | t->count; 24497bf4851SBlue Swirl trace_slavio_timer_mem_writel_limit(timer_index, count); 2457204ff9cSBlue Swirl ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); 24697bf4851SBlue Swirl } else { 24797bf4851SBlue Swirl trace_slavio_timer_mem_writel_counter_invalid(); 24897bf4851SBlue Swirl } 249115646b6Sblueswir1 break; 250d2c38b24Sblueswir1 case TIMER_COUNTER_NORST: 251e80cfcfcSbellard // set limit without resetting counter 2527204ff9cSBlue Swirl t->limit = val & TIMER_MAX_COUNT32; 2537204ff9cSBlue Swirl if (t->limit == 0) { /* free-run */ 2549ebec28bSBlue Swirl ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); 2557204ff9cSBlue Swirl } else { 2567204ff9cSBlue Swirl ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0); 2577204ff9cSBlue Swirl } 258e80cfcfcSbellard break; 259d2c38b24Sblueswir1 case TIMER_STATUS: 2607204ff9cSBlue Swirl if (slavio_timer_is_user(tc)) { 261e80cfcfcSbellard // start/stop user counter 2627204ff9cSBlue Swirl if ((val & 1) && !t->running) { 26397bf4851SBlue Swirl trace_slavio_timer_mem_writel_status_start(timer_index); 2647204ff9cSBlue Swirl ptimer_run(t->timer, 0); 2657204ff9cSBlue Swirl t->running = 1; 2667204ff9cSBlue Swirl } else if (!(val & 1) && t->running) { 26797bf4851SBlue Swirl trace_slavio_timer_mem_writel_status_stop(timer_index); 2687204ff9cSBlue Swirl ptimer_stop(t->timer); 2697204ff9cSBlue Swirl t->running = 0; 270e80cfcfcSbellard } 271e80cfcfcSbellard } 272e80cfcfcSbellard break; 273d2c38b24Sblueswir1 case TIMER_MODE: 2747204ff9cSBlue Swirl if (timer_index == 0) { 27581732d19Sblueswir1 unsigned int i; 27681732d19Sblueswir1 2777204ff9cSBlue Swirl for (i = 0; i < s->num_cpus; i++) { 27867e42751Sblueswir1 unsigned int processor = 1 << i; 2797204ff9cSBlue Swirl CPUTimerState *curr_timer = &s->cputimer[i + 1]; 28067e42751Sblueswir1 28167e42751Sblueswir1 // check for a change in timer mode for this processor 2827204ff9cSBlue Swirl if ((val & processor) != (s->cputimer_mode & processor)) { 28367e42751Sblueswir1 if (val & processor) { // counter -> user timer 2847204ff9cSBlue Swirl qemu_irq_lower(curr_timer->irq); 28567e42751Sblueswir1 // counters are always running 2867204ff9cSBlue Swirl ptimer_stop(curr_timer->timer); 2877204ff9cSBlue Swirl curr_timer->running = 0; 28867e42751Sblueswir1 // user timer limit is always the same 2897204ff9cSBlue Swirl curr_timer->limit = TIMER_MAX_COUNT64; 2907204ff9cSBlue Swirl ptimer_set_limit(curr_timer->timer, 2917204ff9cSBlue Swirl LIMIT_TO_PERIODS(curr_timer->limit), 29277f193daSblueswir1 1); 29367e42751Sblueswir1 // set this processors user timer bit in config 29467e42751Sblueswir1 // register 2957204ff9cSBlue Swirl s->cputimer_mode |= processor; 29697bf4851SBlue Swirl trace_slavio_timer_mem_writel_mode_user(timer_index); 29767e42751Sblueswir1 } else { // user timer -> counter 29867e42751Sblueswir1 // stop the user timer if it is running 2997204ff9cSBlue Swirl if (curr_timer->running) { 3007204ff9cSBlue Swirl ptimer_stop(curr_timer->timer); 3017204ff9cSBlue Swirl } 30267e42751Sblueswir1 // start the counter 3037204ff9cSBlue Swirl ptimer_run(curr_timer->timer, 0); 3047204ff9cSBlue Swirl curr_timer->running = 1; 30567e42751Sblueswir1 // clear this processors user timer bit in config 30667e42751Sblueswir1 // register 3077204ff9cSBlue Swirl s->cputimer_mode &= ~processor; 30897bf4851SBlue Swirl trace_slavio_timer_mem_writel_mode_counter(timer_index); 30981732d19Sblueswir1 } 31081732d19Sblueswir1 } 31167e42751Sblueswir1 } 3127204ff9cSBlue Swirl } else { 31397bf4851SBlue Swirl trace_slavio_timer_mem_writel_mode_invalid(); 3147204ff9cSBlue Swirl } 315e80cfcfcSbellard break; 316e80cfcfcSbellard default: 31797bf4851SBlue Swirl trace_slavio_timer_mem_writel_invalid(addr); 318e80cfcfcSbellard break; 319e80cfcfcSbellard } 320e80cfcfcSbellard } 321e80cfcfcSbellard 322a3d12d07SBenoît Canet static const MemoryRegionOps slavio_timer_mem_ops = { 323a3d12d07SBenoît Canet .read = slavio_timer_mem_readl, 324a3d12d07SBenoît Canet .write = slavio_timer_mem_writel, 325a3d12d07SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 326a3d12d07SBenoît Canet .valid = { 327a3d12d07SBenoît Canet .min_access_size = 4, 328a3d12d07SBenoît Canet .max_access_size = 4, 329a3d12d07SBenoît Canet }, 330e80cfcfcSbellard }; 331e80cfcfcSbellard 332f4b19cd0SBlue Swirl static const VMStateDescription vmstate_timer = { 333f4b19cd0SBlue Swirl .name ="timer", 334f4b19cd0SBlue Swirl .version_id = 3, 335f4b19cd0SBlue Swirl .minimum_version_id = 3, 336f4b19cd0SBlue Swirl .minimum_version_id_old = 3, 337f4b19cd0SBlue Swirl .fields = (VMStateField []) { 338f4b19cd0SBlue Swirl VMSTATE_UINT64(limit, CPUTimerState), 339f4b19cd0SBlue Swirl VMSTATE_UINT32(count, CPUTimerState), 340f4b19cd0SBlue Swirl VMSTATE_UINT32(counthigh, CPUTimerState), 341f4b19cd0SBlue Swirl VMSTATE_UINT32(reached, CPUTimerState), 342f4b19cd0SBlue Swirl VMSTATE_UINT32(running, CPUTimerState), 343f4b19cd0SBlue Swirl VMSTATE_PTIMER(timer, CPUTimerState), 344f4b19cd0SBlue Swirl VMSTATE_END_OF_LIST() 3457204ff9cSBlue Swirl } 346f4b19cd0SBlue Swirl }; 347f4b19cd0SBlue Swirl 348f4b19cd0SBlue Swirl static const VMStateDescription vmstate_slavio_timer = { 349f4b19cd0SBlue Swirl .name ="slavio_timer", 350f4b19cd0SBlue Swirl .version_id = 3, 351f4b19cd0SBlue Swirl .minimum_version_id = 3, 352f4b19cd0SBlue Swirl .minimum_version_id_old = 3, 353f4b19cd0SBlue Swirl .fields = (VMStateField []) { 354f4b19cd0SBlue Swirl VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3, 355f4b19cd0SBlue Swirl vmstate_timer, CPUTimerState), 356f4b19cd0SBlue Swirl VMSTATE_END_OF_LIST() 3577204ff9cSBlue Swirl } 358f4b19cd0SBlue Swirl }; 359e80cfcfcSbellard 3600e0bfeeaSBlue Swirl static void slavio_timer_reset(DeviceState *d) 361e80cfcfcSbellard { 362*c275471eSAndreas Färber SLAVIO_TIMERState *s = SLAVIO_TIMER(d); 3637204ff9cSBlue Swirl unsigned int i; 3647204ff9cSBlue Swirl CPUTimerState *curr_timer; 365e80cfcfcSbellard 3667204ff9cSBlue Swirl for (i = 0; i <= MAX_CPUS; i++) { 3677204ff9cSBlue Swirl curr_timer = &s->cputimer[i]; 3687204ff9cSBlue Swirl curr_timer->limit = 0; 3697204ff9cSBlue Swirl curr_timer->count = 0; 3707204ff9cSBlue Swirl curr_timer->reached = 0; 3715933e8a9SArtyom Tarasenko if (i <= s->num_cpus) { 3727204ff9cSBlue Swirl ptimer_set_limit(curr_timer->timer, 3737204ff9cSBlue Swirl LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); 3747204ff9cSBlue Swirl ptimer_run(curr_timer->timer, 0); 3757204ff9cSBlue Swirl curr_timer->running = 1; 3767204ff9cSBlue Swirl } 3775933e8a9SArtyom Tarasenko } 3787204ff9cSBlue Swirl s->cputimer_mode = 0; 379e80cfcfcSbellard } 380e80cfcfcSbellard 38181a322d4SGerd Hoffmann static int slavio_timer_init1(SysBusDevice *dev) 382c70c59eeSBlue Swirl { 383*c275471eSAndreas Färber SLAVIO_TIMERState *s = SLAVIO_TIMER(dev); 3848d05ea8aSblueswir1 QEMUBH *bh; 3857204ff9cSBlue Swirl unsigned int i; 3867204ff9cSBlue Swirl TimerContext *tc; 387e80cfcfcSbellard 3887204ff9cSBlue Swirl for (i = 0; i <= MAX_CPUS; i++) { 389a3d12d07SBenoît Canet uint64_t size; 390a3d12d07SBenoît Canet char timer_name[20]; 391a3d12d07SBenoît Canet 3927267c094SAnthony Liguori tc = g_malloc0(sizeof(TimerContext)); 3937204ff9cSBlue Swirl tc->s = s; 3947204ff9cSBlue Swirl tc->timer_index = i; 395c70c59eeSBlue Swirl 3967204ff9cSBlue Swirl bh = qemu_bh_new(slavio_timer_irq, tc); 3977204ff9cSBlue Swirl s->cputimer[i].timer = ptimer_init(bh); 3987204ff9cSBlue Swirl ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD); 3997204ff9cSBlue Swirl 400a3d12d07SBenoît Canet size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE; 401a3d12d07SBenoît Canet snprintf(timer_name, sizeof(timer_name), "timer-%i", i); 402853dca12SPaolo Bonzini memory_region_init_io(&tc->iomem, OBJECT(s), &slavio_timer_mem_ops, tc, 403a3d12d07SBenoît Canet timer_name, size); 404750ecd44SAvi Kivity sysbus_init_mmio(dev, &tc->iomem); 405e80cfcfcSbellard 4067204ff9cSBlue Swirl sysbus_init_irq(dev, &s->cputimer[i].irq); 407c70c59eeSBlue Swirl } 408c70c59eeSBlue Swirl 40981a322d4SGerd Hoffmann return 0; 41081732d19Sblueswir1 } 41181732d19Sblueswir1 412999e12bbSAnthony Liguori static Property slavio_timer_properties[] = { 41318c637dcSGerd Hoffmann DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0), 41418c637dcSGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 415999e12bbSAnthony Liguori }; 416999e12bbSAnthony Liguori 417999e12bbSAnthony Liguori static void slavio_timer_class_init(ObjectClass *klass, void *data) 418999e12bbSAnthony Liguori { 41939bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 420999e12bbSAnthony Liguori SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 421999e12bbSAnthony Liguori 422999e12bbSAnthony Liguori k->init = slavio_timer_init1; 42339bffca2SAnthony Liguori dc->reset = slavio_timer_reset; 42439bffca2SAnthony Liguori dc->vmsd = &vmstate_slavio_timer; 42539bffca2SAnthony Liguori dc->props = slavio_timer_properties; 426c70c59eeSBlue Swirl } 427999e12bbSAnthony Liguori 4288c43a6f0SAndreas Färber static const TypeInfo slavio_timer_info = { 429*c275471eSAndreas Färber .name = TYPE_SLAVIO_TIMER, 43039bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 43139bffca2SAnthony Liguori .instance_size = sizeof(SLAVIO_TIMERState), 432999e12bbSAnthony Liguori .class_init = slavio_timer_class_init, 433c70c59eeSBlue Swirl }; 434c70c59eeSBlue Swirl 43583f7d43aSAndreas Färber static void slavio_timer_register_types(void) 436c70c59eeSBlue Swirl { 43739bffca2SAnthony Liguori type_register_static(&slavio_timer_info); 438c70c59eeSBlue Swirl } 439c70c59eeSBlue Swirl 44083f7d43aSAndreas Färber type_init(slavio_timer_register_types) 441