1a541f297Sbellard /* 2e9df014cSj_mayer * QEMU generic PowerPC hardware System Emulator 3a541f297Sbellard * 476a66253Sj_mayer * Copyright (c) 2003-2007 Jocelyn Mayer 5a541f297Sbellard * 6a541f297Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7a541f297Sbellard * of this software and associated documentation files (the "Software"), to deal 8a541f297Sbellard * in the Software without restriction, including without limitation the rights 9a541f297Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10a541f297Sbellard * copies of the Software, and to permit persons to whom the Software is 11a541f297Sbellard * furnished to do so, subject to the following conditions: 12a541f297Sbellard * 13a541f297Sbellard * The above copyright notice and this permission notice shall be included in 14a541f297Sbellard * all copies or substantial portions of the Software. 15a541f297Sbellard * 16a541f297Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17a541f297Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18a541f297Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19a541f297Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20a541f297Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21a541f297Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22a541f297Sbellard * THE SOFTWARE. 23a541f297Sbellard */ 2464552b6bSMarkus Armbruster 250d75590dSPeter Maydell #include "qemu/osdep.h" 2664552b6bSMarkus Armbruster #include "hw/irq.h" 270d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h" 282b927571SAndreas Färber #include "hw/ppc/ppc_e500.h" 291de7afc9SPaolo Bonzini #include "qemu/timer.h" 300ce470cdSAlexey Kardashevskiy #include "sysemu/cpus.h" 311de7afc9SPaolo Bonzini #include "qemu/log.h" 32db725815SMarkus Armbruster #include "qemu/main-loop.h" 3398a8b524SAlexey Kardashevskiy #include "qemu/error-report.h" 349c17d615SPaolo Bonzini #include "sysemu/kvm.h" 359db680f8SNicholas Piggin #include "sysemu/replay.h" 3654d31236SMarkus Armbruster #include "sysemu/runstate.h" 37fc87e185SAlexander Graf #include "kvm_ppc.h" 38d6454270SMarkus Armbruster #include "migration/vmstate.h" 3998a8b524SAlexey Kardashevskiy #include "trace.h" 40a541f297Sbellard 41e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env); 42e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env); 43dbdd2506Sj_mayer 44f003109fSMatheus Ferst void ppc_set_irq(PowerPCCPU *cpu, int irq, int level) 4547103572Sj_mayer { 467058581aSAndreas Färber CPUPPCState *env = &cpu->env; 478d04fb55SJan Kiszka unsigned int old_pending; 488d04fb55SJan Kiszka 498d04fb55SJan Kiszka /* We may already have the BQL if coming from the reset path */ 5050c9c512SRichard Henderson QEMU_IOTHREAD_LOCK_GUARD(); 518d04fb55SJan Kiszka 528d04fb55SJan Kiszka old_pending = env->pending_interrupts; 53fc87e185SAlexander Graf 5447103572Sj_mayer if (level) { 55f003109fSMatheus Ferst env->pending_interrupts |= irq; 5647103572Sj_mayer } else { 57f003109fSMatheus Ferst env->pending_interrupts &= ~irq; 5847103572Sj_mayer } 59fc87e185SAlexander Graf 60fc87e185SAlexander Graf if (old_pending != env->pending_interrupts) { 612fdedcbcSMatheus Ferst ppc_maybe_interrupt(env); 62*76d93e14Sjianchunfu if (kvm_enabled()) { 63f003109fSMatheus Ferst kvmppc_set_interrupt(cpu, irq, level); 64fc87e185SAlexander Graf } 65*76d93e14Sjianchunfu } 66fc87e185SAlexander Graf 67f003109fSMatheus Ferst trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts, 68af96d2e6SCédric Le Goater CPU(cpu)->interrupt_request); 69a496775fSj_mayer } 7047103572Sj_mayer 71e9df014cSj_mayer /* PowerPC 6xx / 7xx internal IRQ controller */ 72e9df014cSj_mayer static void ppc6xx_set_irq(void *opaque, int pin, int level) 73d537cf6cSpbrook { 74a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 75a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 76e9df014cSj_mayer int cur_level; 77d537cf6cSpbrook 78af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 79af96d2e6SCédric Le Goater 80e9df014cSj_mayer cur_level = (env->irq_input_state >> pin) & 1; 81e9df014cSj_mayer /* Don't generate spurious events */ 8224be5ae3Sj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 83259186a7SAndreas Färber CPUState *cs = CPU(cpu); 84259186a7SAndreas Färber 85e9df014cSj_mayer switch (pin) { 86dbdd2506Sj_mayer case PPC6xx_INPUT_TBEN: 87dbdd2506Sj_mayer /* Level sensitive - active high */ 88af96d2e6SCédric Le Goater trace_ppc_irq_set_state("time base", level); 89dbdd2506Sj_mayer if (level) { 90dbdd2506Sj_mayer cpu_ppc_tb_start(env); 91dbdd2506Sj_mayer } else { 92dbdd2506Sj_mayer cpu_ppc_tb_stop(env); 93dbdd2506Sj_mayer } 94b2bd5b20SChen Qun break; 9524be5ae3Sj_mayer case PPC6xx_INPUT_INT: 9624be5ae3Sj_mayer /* Level sensitive - active high */ 97af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 987058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 99e9df014cSj_mayer break; 10024be5ae3Sj_mayer case PPC6xx_INPUT_SMI: 101e9df014cSj_mayer /* Level sensitive - active high */ 102af96d2e6SCédric Le Goater trace_ppc_irq_set_state("SMI IRQ", level); 1037058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); 104e9df014cSj_mayer break; 10524be5ae3Sj_mayer case PPC6xx_INPUT_MCP: 106e9df014cSj_mayer /* Negative edge sensitive */ 107e9df014cSj_mayer /* XXX: TODO: actual reaction may depends on HID0 status 108e9df014cSj_mayer * 603/604/740/750: check HID0[EMCP] 109e9df014cSj_mayer */ 110e9df014cSj_mayer if (cur_level == 1 && level == 0) { 111af96d2e6SCédric Le Goater trace_ppc_irq_set_state("machine check", 1); 1127058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 113d537cf6cSpbrook } 114e9df014cSj_mayer break; 11524be5ae3Sj_mayer case PPC6xx_INPUT_CKSTP_IN: 116e9df014cSj_mayer /* Level sensitive - active low */ 117e9df014cSj_mayer /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 118e63ecc6fSj_mayer /* XXX: Note that the only way to restart the CPU is to reset it */ 119e9df014cSj_mayer if (level) { 120af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 121259186a7SAndreas Färber cs->halted = 1; 122d537cf6cSpbrook } 12347103572Sj_mayer break; 12424be5ae3Sj_mayer case PPC6xx_INPUT_HRESET: 125e9df014cSj_mayer /* Level sensitive - active low */ 126e9df014cSj_mayer if (level) { 127af96d2e6SCédric Le Goater trace_ppc_irq_reset("CPU"); 128c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 129e9df014cSj_mayer } 13047103572Sj_mayer break; 13124be5ae3Sj_mayer case PPC6xx_INPUT_SRESET: 132af96d2e6SCédric Le Goater trace_ppc_irq_set_state("RESET IRQ", level); 1337058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 13447103572Sj_mayer break; 135e9df014cSj_mayer default: 1367279810bSCédric Le Goater g_assert_not_reached(); 13747103572Sj_mayer } 138e9df014cSj_mayer if (level) 139e9df014cSj_mayer env->irq_input_state |= 1 << pin; 140e9df014cSj_mayer else 141e9df014cSj_mayer env->irq_input_state &= ~(1 << pin); 142e9df014cSj_mayer } 143e9df014cSj_mayer } 144e9df014cSj_mayer 145aa5a9e24SPaolo Bonzini void ppc6xx_irq_init(PowerPCCPU *cpu) 146e9df014cSj_mayer { 1470f3e0c6fSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc6xx_set_irq, PPC6xx_INPUT_NB); 14847103572Sj_mayer } 14947103572Sj_mayer 15000af685fSj_mayer #if defined(TARGET_PPC64) 151d0dfae6eSj_mayer /* PowerPC 970 internal IRQ controller */ 152d0dfae6eSj_mayer static void ppc970_set_irq(void *opaque, int pin, int level) 153d0dfae6eSj_mayer { 154a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 155a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 156d0dfae6eSj_mayer int cur_level; 157d0dfae6eSj_mayer 158af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 159af96d2e6SCédric Le Goater 160d0dfae6eSj_mayer cur_level = (env->irq_input_state >> pin) & 1; 161d0dfae6eSj_mayer /* Don't generate spurious events */ 162d0dfae6eSj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 163259186a7SAndreas Färber CPUState *cs = CPU(cpu); 164259186a7SAndreas Färber 165d0dfae6eSj_mayer switch (pin) { 166d0dfae6eSj_mayer case PPC970_INPUT_INT: 167d0dfae6eSj_mayer /* Level sensitive - active high */ 168af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 1697058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 170d0dfae6eSj_mayer break; 171d0dfae6eSj_mayer case PPC970_INPUT_THINT: 172d0dfae6eSj_mayer /* Level sensitive - active high */ 173af96d2e6SCédric Le Goater trace_ppc_irq_set_state("SMI IRQ", level); 1747058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); 175d0dfae6eSj_mayer break; 176d0dfae6eSj_mayer case PPC970_INPUT_MCP: 177d0dfae6eSj_mayer /* Negative edge sensitive */ 178d0dfae6eSj_mayer /* XXX: TODO: actual reaction may depends on HID0 status 179d0dfae6eSj_mayer * 603/604/740/750: check HID0[EMCP] 180d0dfae6eSj_mayer */ 181d0dfae6eSj_mayer if (cur_level == 1 && level == 0) { 182af96d2e6SCédric Le Goater trace_ppc_irq_set_state("machine check", 1); 1837058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 184d0dfae6eSj_mayer } 185d0dfae6eSj_mayer break; 186d0dfae6eSj_mayer case PPC970_INPUT_CKSTP: 187d0dfae6eSj_mayer /* Level sensitive - active low */ 188d0dfae6eSj_mayer /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 189d0dfae6eSj_mayer if (level) { 190af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 191259186a7SAndreas Färber cs->halted = 1; 192d0dfae6eSj_mayer } else { 193af96d2e6SCédric Le Goater trace_ppc_irq_cpu("restart"); 194259186a7SAndreas Färber cs->halted = 0; 195259186a7SAndreas Färber qemu_cpu_kick(cs); 196d0dfae6eSj_mayer } 197d0dfae6eSj_mayer break; 198d0dfae6eSj_mayer case PPC970_INPUT_HRESET: 199d0dfae6eSj_mayer /* Level sensitive - active low */ 200d0dfae6eSj_mayer if (level) { 201c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 202d0dfae6eSj_mayer } 203d0dfae6eSj_mayer break; 204d0dfae6eSj_mayer case PPC970_INPUT_SRESET: 205af96d2e6SCédric Le Goater trace_ppc_irq_set_state("RESET IRQ", level); 2067058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 207d0dfae6eSj_mayer break; 208d0dfae6eSj_mayer case PPC970_INPUT_TBEN: 209af96d2e6SCédric Le Goater trace_ppc_irq_set_state("TBEN IRQ", level); 210d0dfae6eSj_mayer /* XXX: TODO */ 211d0dfae6eSj_mayer break; 212d0dfae6eSj_mayer default: 2137279810bSCédric Le Goater g_assert_not_reached(); 214d0dfae6eSj_mayer } 215d0dfae6eSj_mayer if (level) 216d0dfae6eSj_mayer env->irq_input_state |= 1 << pin; 217d0dfae6eSj_mayer else 218d0dfae6eSj_mayer env->irq_input_state &= ~(1 << pin); 219d0dfae6eSj_mayer } 220d0dfae6eSj_mayer } 221d0dfae6eSj_mayer 222aa5a9e24SPaolo Bonzini void ppc970_irq_init(PowerPCCPU *cpu) 223d0dfae6eSj_mayer { 2249fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc970_set_irq, PPC970_INPUT_NB); 225d0dfae6eSj_mayer } 2269d52e907SDavid Gibson 2279d52e907SDavid Gibson /* POWER7 internal IRQ controller */ 2289d52e907SDavid Gibson static void power7_set_irq(void *opaque, int pin, int level) 2299d52e907SDavid Gibson { 230a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 2319d52e907SDavid Gibson 232af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 2339d52e907SDavid Gibson 2349d52e907SDavid Gibson switch (pin) { 2359d52e907SDavid Gibson case POWER7_INPUT_INT: 2369d52e907SDavid Gibson /* Level sensitive - active high */ 237af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 2387058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 2399d52e907SDavid Gibson break; 2409d52e907SDavid Gibson default: 2417279810bSCédric Le Goater g_assert_not_reached(); 2429d52e907SDavid Gibson } 2439d52e907SDavid Gibson } 2449d52e907SDavid Gibson 245aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu) 2469d52e907SDavid Gibson { 2479fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), power7_set_irq, POWER7_INPUT_NB); 2489d52e907SDavid Gibson } 24967afe775SBenjamin Herrenschmidt 25067afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */ 25167afe775SBenjamin Herrenschmidt static void power9_set_irq(void *opaque, int pin, int level) 25267afe775SBenjamin Herrenschmidt { 25367afe775SBenjamin Herrenschmidt PowerPCCPU *cpu = opaque; 25467afe775SBenjamin Herrenschmidt 255af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 25667afe775SBenjamin Herrenschmidt 25767afe775SBenjamin Herrenschmidt switch (pin) { 25867afe775SBenjamin Herrenschmidt case POWER9_INPUT_INT: 25967afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 260af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 26167afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 26267afe775SBenjamin Herrenschmidt break; 26367afe775SBenjamin Herrenschmidt case POWER9_INPUT_HINT: 26467afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 265af96d2e6SCédric Le Goater trace_ppc_irq_set_state("HV external IRQ", level); 26667afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level); 26767afe775SBenjamin Herrenschmidt break; 26867afe775SBenjamin Herrenschmidt default: 2697279810bSCédric Le Goater g_assert_not_reached(); 270af96d2e6SCédric Le Goater return; 27167afe775SBenjamin Herrenschmidt } 27267afe775SBenjamin Herrenschmidt } 27367afe775SBenjamin Herrenschmidt 27467afe775SBenjamin Herrenschmidt void ppcPOWER9_irq_init(PowerPCCPU *cpu) 27567afe775SBenjamin Herrenschmidt { 2769fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), power9_set_irq, POWER9_INPUT_NB); 27767afe775SBenjamin Herrenschmidt } 27800af685fSj_mayer #endif /* defined(TARGET_PPC64) */ 279d0dfae6eSj_mayer 28052144b69SThomas Huth void ppc40x_core_reset(PowerPCCPU *cpu) 28152144b69SThomas Huth { 28252144b69SThomas Huth CPUPPCState *env = &cpu->env; 28352144b69SThomas Huth target_ulong dbsr; 28452144b69SThomas Huth 28552144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n"); 28652144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 28752144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 28852144b69SThomas Huth dbsr &= ~0x00000300; 28952144b69SThomas Huth dbsr |= 0x00000100; 29052144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 29152144b69SThomas Huth } 29252144b69SThomas Huth 29352144b69SThomas Huth void ppc40x_chip_reset(PowerPCCPU *cpu) 29452144b69SThomas Huth { 29552144b69SThomas Huth CPUPPCState *env = &cpu->env; 29652144b69SThomas Huth target_ulong dbsr; 29752144b69SThomas Huth 29852144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n"); 29952144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 30052144b69SThomas Huth /* XXX: TODO reset all internal peripherals */ 30152144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 30252144b69SThomas Huth dbsr &= ~0x00000300; 30352144b69SThomas Huth dbsr |= 0x00000200; 30452144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 30552144b69SThomas Huth } 30652144b69SThomas Huth 30752144b69SThomas Huth void ppc40x_system_reset(PowerPCCPU *cpu) 30852144b69SThomas Huth { 30952144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n"); 31052144b69SThomas Huth qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 31152144b69SThomas Huth } 31252144b69SThomas Huth 31352144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val) 31452144b69SThomas Huth { 315db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 31652144b69SThomas Huth 3175ae3d2e8SThomas Huth qemu_mutex_lock_iothread(); 3185ae3d2e8SThomas Huth 31952144b69SThomas Huth switch ((val >> 28) & 0x3) { 32052144b69SThomas Huth case 0x0: 32152144b69SThomas Huth /* No action */ 32252144b69SThomas Huth break; 32352144b69SThomas Huth case 0x1: 32452144b69SThomas Huth /* Core reset */ 32552144b69SThomas Huth ppc40x_core_reset(cpu); 32652144b69SThomas Huth break; 32752144b69SThomas Huth case 0x2: 32852144b69SThomas Huth /* Chip reset */ 32952144b69SThomas Huth ppc40x_chip_reset(cpu); 33052144b69SThomas Huth break; 33152144b69SThomas Huth case 0x3: 33252144b69SThomas Huth /* System reset */ 33352144b69SThomas Huth ppc40x_system_reset(cpu); 33452144b69SThomas Huth break; 33552144b69SThomas Huth } 3365ae3d2e8SThomas Huth 3375ae3d2e8SThomas Huth qemu_mutex_unlock_iothread(); 33852144b69SThomas Huth } 33952144b69SThomas Huth 3404e290a0bSj_mayer /* PowerPC 40x internal IRQ controller */ 3414e290a0bSj_mayer static void ppc40x_set_irq(void *opaque, int pin, int level) 34224be5ae3Sj_mayer { 343a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 344a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 34524be5ae3Sj_mayer int cur_level; 34624be5ae3Sj_mayer 347af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 348af96d2e6SCédric Le Goater 34924be5ae3Sj_mayer cur_level = (env->irq_input_state >> pin) & 1; 35024be5ae3Sj_mayer /* Don't generate spurious events */ 35124be5ae3Sj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 352259186a7SAndreas Färber CPUState *cs = CPU(cpu); 353259186a7SAndreas Färber 35424be5ae3Sj_mayer switch (pin) { 3554e290a0bSj_mayer case PPC40x_INPUT_RESET_SYS: 3568ecc7913Sj_mayer if (level) { 357af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 358f3273ba6SAndreas Färber ppc40x_system_reset(cpu); 3598ecc7913Sj_mayer } 3608ecc7913Sj_mayer break; 3614e290a0bSj_mayer case PPC40x_INPUT_RESET_CHIP: 3628ecc7913Sj_mayer if (level) { 363af96d2e6SCédric Le Goater trace_ppc_irq_reset("chip"); 364f3273ba6SAndreas Färber ppc40x_chip_reset(cpu); 3658ecc7913Sj_mayer } 3668ecc7913Sj_mayer break; 3674e290a0bSj_mayer case PPC40x_INPUT_RESET_CORE: 36824be5ae3Sj_mayer /* XXX: TODO: update DBSR[MRR] */ 36924be5ae3Sj_mayer if (level) { 370af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 371f3273ba6SAndreas Färber ppc40x_core_reset(cpu); 37224be5ae3Sj_mayer } 37324be5ae3Sj_mayer break; 3744e290a0bSj_mayer case PPC40x_INPUT_CINT: 37524be5ae3Sj_mayer /* Level sensitive - active high */ 376af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 3777058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 37824be5ae3Sj_mayer break; 3794e290a0bSj_mayer case PPC40x_INPUT_INT: 38024be5ae3Sj_mayer /* Level sensitive - active high */ 381af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 3827058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 38324be5ae3Sj_mayer break; 3844e290a0bSj_mayer case PPC40x_INPUT_HALT: 38524be5ae3Sj_mayer /* Level sensitive - active low */ 38624be5ae3Sj_mayer if (level) { 387af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 388259186a7SAndreas Färber cs->halted = 1; 38924be5ae3Sj_mayer } else { 390af96d2e6SCédric Le Goater trace_ppc_irq_cpu("restart"); 391259186a7SAndreas Färber cs->halted = 0; 392259186a7SAndreas Färber qemu_cpu_kick(cs); 39324be5ae3Sj_mayer } 39424be5ae3Sj_mayer break; 3954e290a0bSj_mayer case PPC40x_INPUT_DEBUG: 39624be5ae3Sj_mayer /* Level sensitive - active high */ 397af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 3987058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 39924be5ae3Sj_mayer break; 40024be5ae3Sj_mayer default: 4017279810bSCédric Le Goater g_assert_not_reached(); 40224be5ae3Sj_mayer } 40324be5ae3Sj_mayer if (level) 40424be5ae3Sj_mayer env->irq_input_state |= 1 << pin; 40524be5ae3Sj_mayer else 40624be5ae3Sj_mayer env->irq_input_state &= ~(1 << pin); 40724be5ae3Sj_mayer } 40824be5ae3Sj_mayer } 40924be5ae3Sj_mayer 410aa5a9e24SPaolo Bonzini void ppc40x_irq_init(PowerPCCPU *cpu) 41124be5ae3Sj_mayer { 41247b60fc6SCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc40x_set_irq, PPC40x_INPUT_NB); 41324be5ae3Sj_mayer } 41424be5ae3Sj_mayer 4159fdc60bfSaurel32 /* PowerPC E500 internal IRQ controller */ 4169fdc60bfSaurel32 static void ppce500_set_irq(void *opaque, int pin, int level) 4179fdc60bfSaurel32 { 418a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 419a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 4209fdc60bfSaurel32 int cur_level; 4219fdc60bfSaurel32 422af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 423af96d2e6SCédric Le Goater 4249fdc60bfSaurel32 cur_level = (env->irq_input_state >> pin) & 1; 4259fdc60bfSaurel32 /* Don't generate spurious events */ 4269fdc60bfSaurel32 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 4279fdc60bfSaurel32 switch (pin) { 4289fdc60bfSaurel32 case PPCE500_INPUT_MCK: 4299fdc60bfSaurel32 if (level) { 430af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 431cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 4329fdc60bfSaurel32 } 4339fdc60bfSaurel32 break; 4349fdc60bfSaurel32 case PPCE500_INPUT_RESET_CORE: 4359fdc60bfSaurel32 if (level) { 436af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 4377058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); 4389fdc60bfSaurel32 } 4399fdc60bfSaurel32 break; 4409fdc60bfSaurel32 case PPCE500_INPUT_CINT: 4419fdc60bfSaurel32 /* Level sensitive - active high */ 442af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 4437058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 4449fdc60bfSaurel32 break; 4459fdc60bfSaurel32 case PPCE500_INPUT_INT: 4469fdc60bfSaurel32 /* Level sensitive - active high */ 447af96d2e6SCédric Le Goater trace_ppc_irq_set_state("core IRQ", level); 4487058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 4499fdc60bfSaurel32 break; 4509fdc60bfSaurel32 case PPCE500_INPUT_DEBUG: 4519fdc60bfSaurel32 /* Level sensitive - active high */ 452af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 4537058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 4549fdc60bfSaurel32 break; 4559fdc60bfSaurel32 default: 4567279810bSCédric Le Goater g_assert_not_reached(); 4579fdc60bfSaurel32 } 4589fdc60bfSaurel32 if (level) 4599fdc60bfSaurel32 env->irq_input_state |= 1 << pin; 4609fdc60bfSaurel32 else 4619fdc60bfSaurel32 env->irq_input_state &= ~(1 << pin); 4629fdc60bfSaurel32 } 4639fdc60bfSaurel32 } 4649fdc60bfSaurel32 465aa5a9e24SPaolo Bonzini void ppce500_irq_init(PowerPCCPU *cpu) 4669fdc60bfSaurel32 { 4675e66cd0cSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppce500_set_irq, PPCE500_INPUT_NB); 4689fdc60bfSaurel32 } 469e49798b1SAlexander Graf 470e49798b1SAlexander Graf /* Enable or Disable the E500 EPR capability */ 471e49798b1SAlexander Graf void ppce500_set_mpic_proxy(bool enabled) 472e49798b1SAlexander Graf { 473182735efSAndreas Färber CPUState *cs; 474e49798b1SAlexander Graf 475bdc44640SAndreas Färber CPU_FOREACH(cs) { 476182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 4775b95b8b9SAlexander Graf 478182735efSAndreas Färber cpu->env.mpic_proxy = enabled; 4795b95b8b9SAlexander Graf if (kvm_enabled()) { 480182735efSAndreas Färber kvmppc_set_mpic_proxy(cpu, enabled); 4815b95b8b9SAlexander Graf } 482e49798b1SAlexander Graf } 483e49798b1SAlexander Graf } 484e49798b1SAlexander Graf 4859fddaa0cSbellard /*****************************************************************************/ 486e9df014cSj_mayer /* PowerPC time base and decrementer emulation */ 4879fddaa0cSbellard 488eab08884SNicholas Piggin /* 489eab08884SNicholas Piggin * Conversion between QEMU_CLOCK_VIRTUAL ns and timebase (TB) ticks: 490eab08884SNicholas Piggin * TB ticks are arrived at by multiplying tb_freq then dividing by 491eab08884SNicholas Piggin * ns per second, and rounding down. TB ticks drive all clocks and 492eab08884SNicholas Piggin * timers in the target machine. 493eab08884SNicholas Piggin * 494eab08884SNicholas Piggin * Converting TB intervals to ns for the purpose of setting a 495eab08884SNicholas Piggin * QEMU_CLOCK_VIRTUAL timer should go the other way, but rounding 496eab08884SNicholas Piggin * up. Rounding down could cause the timer to fire before the TB 497eab08884SNicholas Piggin * value has been reached. 498eab08884SNicholas Piggin */ 4997798f5c5SNicholas Piggin static uint64_t ns_to_tb(uint32_t freq, int64_t clock) 5007798f5c5SNicholas Piggin { 5017798f5c5SNicholas Piggin return muldiv64(clock, freq, NANOSECONDS_PER_SECOND); 5027798f5c5SNicholas Piggin } 5037798f5c5SNicholas Piggin 504eab08884SNicholas Piggin /* virtual clock in TB ticks, not adjusted by TB offset */ 505eab08884SNicholas Piggin static int64_t tb_to_ns_round_up(uint32_t freq, uint64_t tb) 5067798f5c5SNicholas Piggin { 507eab08884SNicholas Piggin return muldiv64_round_up(tb, NANOSECONDS_PER_SECOND, freq); 5087798f5c5SNicholas Piggin } 5097798f5c5SNicholas Piggin 510ddd1055bSFabien Chouteau uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) 5119fddaa0cSbellard { 5129fddaa0cSbellard /* TB time in tb periods */ 5137798f5c5SNicholas Piggin return ns_to_tb(tb_env->tb_freq, vmclk) + tb_offset; 5149fddaa0cSbellard } 5159fddaa0cSbellard 516e2684c0bSAndreas Färber uint64_t cpu_ppc_load_tbl (CPUPPCState *env) 5179fddaa0cSbellard { 518c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 5199fddaa0cSbellard uint64_t tb; 5209fddaa0cSbellard 52190dc8812SScott Wood if (kvm_enabled()) { 52290dc8812SScott Wood return env->spr[SPR_TBL]; 52390dc8812SScott Wood } 52490dc8812SScott Wood 525eaf832fcSNicholas Piggin tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 526eaf832fcSNicholas Piggin tb_env->tb_offset); 527af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 5289fddaa0cSbellard 529e3ea6529SAlexander Graf return tb; 5309fddaa0cSbellard } 5319fddaa0cSbellard 532e2684c0bSAndreas Färber static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) 5339fddaa0cSbellard { 534c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 5359fddaa0cSbellard uint64_t tb; 5369fddaa0cSbellard 537eaf832fcSNicholas Piggin tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 538eaf832fcSNicholas Piggin tb_env->tb_offset); 539af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 54076a66253Sj_mayer 5419fddaa0cSbellard return tb >> 32; 5429fddaa0cSbellard } 5439fddaa0cSbellard 544e2684c0bSAndreas Färber uint32_t cpu_ppc_load_tbu (CPUPPCState *env) 5458a84de23Sj_mayer { 54690dc8812SScott Wood if (kvm_enabled()) { 54790dc8812SScott Wood return env->spr[SPR_TBU]; 54890dc8812SScott Wood } 54990dc8812SScott Wood 5508a84de23Sj_mayer return _cpu_ppc_load_tbu(env); 5518a84de23Sj_mayer } 5528a84de23Sj_mayer 553c227f099SAnthony Liguori static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, 554636aa200SBlue Swirl int64_t *tb_offsetp, uint64_t value) 5559fddaa0cSbellard { 5567798f5c5SNicholas Piggin *tb_offsetp = value - ns_to_tb(tb_env->tb_freq, vmclk); 55773bcb24dSRutuja Shah 558af96d2e6SCédric Le Goater trace_ppc_tb_store(value, *tb_offsetp); 559a496775fSj_mayer } 5609fddaa0cSbellard 561e2684c0bSAndreas Färber void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) 5629fddaa0cSbellard { 563c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 5642ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 565a062e36cSj_mayer uint64_t tb; 5669fddaa0cSbellard 5672ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset); 568a062e36cSj_mayer tb &= 0xFFFFFFFF00000000ULL; 5692ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb | (uint64_t)value); 570a062e36cSj_mayer } 571a062e36cSj_mayer 572e2684c0bSAndreas Färber static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) 573a062e36cSj_mayer { 574c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 5752ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 576a062e36cSj_mayer uint64_t tb; 577a062e36cSj_mayer 5782ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset); 579a062e36cSj_mayer tb &= 0x00000000FFFFFFFFULL; 5802ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, 5812ad2e113SNicholas Piggin ((uint64_t)value << 32) | tb); 582a062e36cSj_mayer } 583a062e36cSj_mayer 584e2684c0bSAndreas Färber void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value) 5858a84de23Sj_mayer { 5868a84de23Sj_mayer _cpu_ppc_store_tbu(env, value); 5878a84de23Sj_mayer } 5888a84de23Sj_mayer 589e2684c0bSAndreas Färber uint64_t cpu_ppc_load_atbl (CPUPPCState *env) 590a062e36cSj_mayer { 591c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 592a062e36cSj_mayer uint64_t tb; 593a062e36cSj_mayer 594eaf832fcSNicholas Piggin tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 595eaf832fcSNicholas Piggin tb_env->atb_offset); 596af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 597a062e36cSj_mayer 598b711de95SAurelien Jarno return tb; 599a062e36cSj_mayer } 600a062e36cSj_mayer 601e2684c0bSAndreas Färber uint32_t cpu_ppc_load_atbu (CPUPPCState *env) 602a062e36cSj_mayer { 603c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 604a062e36cSj_mayer uint64_t tb; 605a062e36cSj_mayer 606eaf832fcSNicholas Piggin tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 607eaf832fcSNicholas Piggin tb_env->atb_offset); 608af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 609a062e36cSj_mayer 610a062e36cSj_mayer return tb >> 32; 611a062e36cSj_mayer } 612a062e36cSj_mayer 613e2684c0bSAndreas Färber void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) 614a062e36cSj_mayer { 615c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 6162ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 617a062e36cSj_mayer uint64_t tb; 618a062e36cSj_mayer 6192ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset); 620a062e36cSj_mayer tb &= 0xFFFFFFFF00000000ULL; 6212ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset, tb | (uint64_t)value); 622a062e36cSj_mayer } 623a062e36cSj_mayer 624e2684c0bSAndreas Färber void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) 625a062e36cSj_mayer { 626c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 6272ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 628a062e36cSj_mayer uint64_t tb; 629a062e36cSj_mayer 6302ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset); 631a062e36cSj_mayer tb &= 0x00000000FFFFFFFFULL; 6322ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset, 6332ad2e113SNicholas Piggin ((uint64_t)value << 32) | tb); 634dbdd2506Sj_mayer } 635dbdd2506Sj_mayer 6365d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env) 6375d62725bSSuraj Jitindar Singh { 6385d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6395d62725bSSuraj Jitindar Singh 6405d62725bSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6415d62725bSSuraj Jitindar Singh tb_env->vtb_offset); 6425d62725bSSuraj Jitindar Singh } 6435d62725bSSuraj Jitindar Singh 6445d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value) 6455d62725bSSuraj Jitindar Singh { 6465d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6475d62725bSSuraj Jitindar Singh 6485d62725bSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6495d62725bSSuraj Jitindar Singh &tb_env->vtb_offset, value); 6505d62725bSSuraj Jitindar Singh } 6515d62725bSSuraj Jitindar Singh 652f0ec31b1SSuraj Jitindar Singh void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value) 653f0ec31b1SSuraj Jitindar Singh { 654f0ec31b1SSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6552ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 656f0ec31b1SSuraj Jitindar Singh uint64_t tb; 657f0ec31b1SSuraj Jitindar Singh 6582ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset); 659f0ec31b1SSuraj Jitindar Singh tb &= 0xFFFFFFUL; 660f0ec31b1SSuraj Jitindar Singh tb |= (value & ~0xFFFFFFUL); 6612ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb); 662f0ec31b1SSuraj Jitindar Singh } 663f0ec31b1SSuraj Jitindar Singh 664e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env) 665dbdd2506Sj_mayer { 666c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 667dbdd2506Sj_mayer uint64_t tb, atb, vmclk; 668dbdd2506Sj_mayer 669dbdd2506Sj_mayer /* If the time base is already frozen, do nothing */ 670dbdd2506Sj_mayer if (tb_env->tb_freq != 0) { 671bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 672dbdd2506Sj_mayer /* Get the time base */ 673dbdd2506Sj_mayer tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); 674dbdd2506Sj_mayer /* Get the alternate time base */ 675dbdd2506Sj_mayer atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); 676dbdd2506Sj_mayer /* Store the time base value (ie compute the current offset) */ 677dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 678dbdd2506Sj_mayer /* Store the alternate time base value (compute the current offset) */ 679dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 680dbdd2506Sj_mayer /* Set the time base frequency to zero */ 681dbdd2506Sj_mayer tb_env->tb_freq = 0; 682dbdd2506Sj_mayer /* Now, the time bases are frozen to tb_offset / atb_offset value */ 683dbdd2506Sj_mayer } 684dbdd2506Sj_mayer } 685dbdd2506Sj_mayer 686e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env) 687dbdd2506Sj_mayer { 688c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 689dbdd2506Sj_mayer uint64_t tb, atb, vmclk; 690dbdd2506Sj_mayer 691dbdd2506Sj_mayer /* If the time base is not frozen, do nothing */ 692dbdd2506Sj_mayer if (tb_env->tb_freq == 0) { 693bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 694dbdd2506Sj_mayer /* Get the time base from tb_offset */ 695dbdd2506Sj_mayer tb = tb_env->tb_offset; 696dbdd2506Sj_mayer /* Get the alternate time base from atb_offset */ 697dbdd2506Sj_mayer atb = tb_env->atb_offset; 698dbdd2506Sj_mayer /* Restore the tb frequency from the decrementer frequency */ 699dbdd2506Sj_mayer tb_env->tb_freq = tb_env->decr_freq; 700dbdd2506Sj_mayer /* Store the time base value */ 701dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 702dbdd2506Sj_mayer /* Store the alternate time base value */ 703dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 704dbdd2506Sj_mayer } 7059fddaa0cSbellard } 7069fddaa0cSbellard 707e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env) 708e81a982aSAlexander Graf { 709e81a982aSAlexander Graf ppc_tb_t *tb_env = env->tb_env; 710e81a982aSAlexander Graf int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL; 711e81a982aSAlexander Graf return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED); 712e81a982aSAlexander Graf } 713e81a982aSAlexander Graf 714ea62f8a5SNicholas Piggin static inline int64_t __cpu_ppc_load_decr(CPUPPCState *env, int64_t now, 715ea62f8a5SNicholas Piggin uint64_t next) 7169fddaa0cSbellard { 717c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 718ea62f8a5SNicholas Piggin uint64_t n; 7198e0a5ac8SNicholas Piggin int64_t decr; 7209fddaa0cSbellard 7218e0a5ac8SNicholas Piggin n = ns_to_tb(tb_env->decr_freq, now); 7228e0a5ac8SNicholas Piggin if (next > n && tb_env->flags & PPC_TIMER_BOOKE) { 723ddd1055bSFabien Chouteau decr = 0; 724ddd1055bSFabien Chouteau } else { 7258e0a5ac8SNicholas Piggin decr = next - n; 726ddd1055bSFabien Chouteau } 7278e0a5ac8SNicholas Piggin 728af96d2e6SCédric Le Goater trace_ppc_decr_load(decr); 72976a66253Sj_mayer 7309fddaa0cSbellard return decr; 7319fddaa0cSbellard } 7329fddaa0cSbellard 733ea62f8a5SNicholas Piggin static target_ulong _cpu_ppc_load_decr(CPUPPCState *env, int64_t now) 73458a7d328Sj_mayer { 735c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 736a8dafa52SSuraj Jitindar Singh uint64_t decr; 73758a7d328Sj_mayer 738ea62f8a5SNicholas Piggin decr = __cpu_ppc_load_decr(env, now, tb_env->decr_next); 739a8dafa52SSuraj Jitindar Singh 740a8dafa52SSuraj Jitindar Singh /* 741a8dafa52SSuraj Jitindar Singh * If large decrementer is enabled then the decrementer is signed extened 742a8dafa52SSuraj Jitindar Singh * to 64 bits, otherwise it is a 32 bit value. 743a8dafa52SSuraj Jitindar Singh */ 744a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 745c8fbc6b9SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 746c8fbc6b9SNicholas Piggin PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 747c8fbc6b9SNicholas Piggin return sextract64(decr, 0, pcc->lrg_decr_bits); 748a8dafa52SSuraj Jitindar Singh } 749a8dafa52SSuraj Jitindar Singh return (uint32_t) decr; 75058a7d328Sj_mayer } 75158a7d328Sj_mayer 752ea62f8a5SNicholas Piggin target_ulong cpu_ppc_load_decr(CPUPPCState *env) 753ea62f8a5SNicholas Piggin { 754ea62f8a5SNicholas Piggin if (kvm_enabled()) { 755ea62f8a5SNicholas Piggin return env->spr[SPR_DECR]; 756ea62f8a5SNicholas Piggin } else { 757ea62f8a5SNicholas Piggin return _cpu_ppc_load_decr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 758ea62f8a5SNicholas Piggin } 759ea62f8a5SNicholas Piggin } 760ea62f8a5SNicholas Piggin 761ea62f8a5SNicholas Piggin static target_ulong _cpu_ppc_load_hdecr(CPUPPCState *env, int64_t now) 76258a7d328Sj_mayer { 763db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 764a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 765c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 766a8dafa52SSuraj Jitindar Singh uint64_t hdecr; 76758a7d328Sj_mayer 768ea62f8a5SNicholas Piggin hdecr = __cpu_ppc_load_decr(env, now, tb_env->hdecr_next); 769a8dafa52SSuraj Jitindar Singh 770a8dafa52SSuraj Jitindar Singh /* 771a8dafa52SSuraj Jitindar Singh * If we have a large decrementer (POWER9 or later) then hdecr is sign 772a8dafa52SSuraj Jitindar Singh * extended to 64 bits, otherwise it is 32 bits. 773a8dafa52SSuraj Jitindar Singh */ 774a8dafa52SSuraj Jitindar Singh if (pcc->lrg_decr_bits > 32) { 775c8fbc6b9SNicholas Piggin return sextract64(hdecr, 0, pcc->lrg_decr_bits); 776a8dafa52SSuraj Jitindar Singh } 777a8dafa52SSuraj Jitindar Singh return (uint32_t) hdecr; 77858a7d328Sj_mayer } 77958a7d328Sj_mayer 780ea62f8a5SNicholas Piggin target_ulong cpu_ppc_load_hdecr(CPUPPCState *env) 781ea62f8a5SNicholas Piggin { 782ea62f8a5SNicholas Piggin return _cpu_ppc_load_hdecr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 783ea62f8a5SNicholas Piggin } 784ea62f8a5SNicholas Piggin 785e2684c0bSAndreas Färber uint64_t cpu_ppc_load_purr (CPUPPCState *env) 78658a7d328Sj_mayer { 787c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 78858a7d328Sj_mayer 7895cc7e69fSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 7905cc7e69fSSuraj Jitindar Singh tb_env->purr_offset); 79158a7d328Sj_mayer } 79258a7d328Sj_mayer 7939fddaa0cSbellard /* When decrementer expires, 7949fddaa0cSbellard * all we need to do is generate or queue a CPU exception 7959fddaa0cSbellard */ 7967e0a9247SAndreas Färber static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) 7979fddaa0cSbellard { 7989fddaa0cSbellard /* Raise it */ 799af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise"); 8007058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); 8019fddaa0cSbellard } 8029fddaa0cSbellard 803e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu) 804e81a982aSAlexander Graf { 805e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0); 806e81a982aSAlexander Graf } 807e81a982aSAlexander Graf 8087e0a9247SAndreas Färber static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) 80958a7d328Sj_mayer { 8104b236b62SBenjamin Herrenschmidt CPUPPCState *env = &cpu->env; 8114b236b62SBenjamin Herrenschmidt 81258a7d328Sj_mayer /* Raise it */ 813af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise HV"); 8144b236b62SBenjamin Herrenschmidt 8154b236b62SBenjamin Herrenschmidt /* The architecture specifies that we don't deliver HDEC 8164b236b62SBenjamin Herrenschmidt * interrupts in a PM state. Not only they don't cause a 8174b236b62SBenjamin Herrenschmidt * wakeup but they also get effectively discarded. 8184b236b62SBenjamin Herrenschmidt */ 8191e7fd61dSBenjamin Herrenschmidt if (!env->resume_as_sreset) { 8207058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); 82158a7d328Sj_mayer } 8224b236b62SBenjamin Herrenschmidt } 82358a7d328Sj_mayer 824e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) 825e81a982aSAlexander Graf { 826e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); 827e81a982aSAlexander Graf } 828e81a982aSAlexander Graf 829ea62f8a5SNicholas Piggin static void __cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now, uint64_t *nextp, 8301246b259SStefan Weil QEMUTimer *timer, 831e81a982aSAlexander Graf void (*raise_excp)(void *), 832e81a982aSAlexander Graf void (*lower_excp)(PowerPCCPU *), 833a5ff7875SNicholas Piggin uint32_t flags, target_ulong decr, 834a5ff7875SNicholas Piggin target_ulong value, int nr_bits) 8359fddaa0cSbellard { 8367e0a9247SAndreas Färber CPUPPCState *env = &cpu->env; 837c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 838ea62f8a5SNicholas Piggin uint64_t next; 8394d9b8ef9SCédric Le Goater int64_t signed_value; 8404d9b8ef9SCédric Le Goater int64_t signed_decr; 8419fddaa0cSbellard 842a8dafa52SSuraj Jitindar Singh /* Truncate value to decr_width and sign extend for simplicity */ 84309d2db9fSNicholas Piggin value = extract64(value, 0, nr_bits); 84409d2db9fSNicholas Piggin decr = extract64(decr, 0, nr_bits); 8454d9b8ef9SCédric Le Goater signed_value = sextract64(value, 0, nr_bits); 8464d9b8ef9SCédric Le Goater signed_decr = sextract64(decr, 0, nr_bits); 847a8dafa52SSuraj Jitindar Singh 848af96d2e6SCédric Le Goater trace_ppc_decr_store(nr_bits, decr, value); 84955f7d4b0SDavid Gibson 850e81a982aSAlexander Graf /* 851febb71d5SNicholas Piggin * Calculate the next decrementer event and set a timer. 852febb71d5SNicholas Piggin * decr_next is in timebase units to keep rounding simple. Note it is 853febb71d5SNicholas Piggin * not adjusted by tb_offset because if TB changes via tb_offset changing, 854febb71d5SNicholas Piggin * decrementer does not change, so not directly comparable with TB. 855febb71d5SNicholas Piggin */ 856febb71d5SNicholas Piggin next = ns_to_tb(tb_env->decr_freq, now) + value; 857febb71d5SNicholas Piggin *nextp = next; /* nextp is in timebase units */ 858febb71d5SNicholas Piggin 859febb71d5SNicholas Piggin /* 86017dd1354SNicholas Piggin * Going from 1 -> 0 or 0 -> -1 is the event to generate a DEC interrupt. 861e81a982aSAlexander Graf * 862e81a982aSAlexander Graf * On MSB level based DEC implementations the MSB always means the interrupt 863e81a982aSAlexander Graf * is pending, so raise it on those. 864e81a982aSAlexander Graf * 865e81a982aSAlexander Graf * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers 866e81a982aSAlexander Graf * an edge interrupt, so raise it here too. 867e81a982aSAlexander Graf */ 868a5ff7875SNicholas Piggin if (((flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) || 869a5ff7875SNicholas Piggin ((flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0 8704d9b8ef9SCédric Le Goater && signed_decr >= 0)) { 871e81a982aSAlexander Graf (*raise_excp)(cpu); 872e81a982aSAlexander Graf return; 873e81a982aSAlexander Graf } 874e81a982aSAlexander Graf 875e81a982aSAlexander Graf /* On MSB level based systems a 0 for the MSB stops interrupt delivery */ 876a5ff7875SNicholas Piggin if (signed_value >= 0 && (flags & PPC_DECR_UNDERFLOW_LEVEL)) { 877e81a982aSAlexander Graf (*lower_excp)(cpu); 878e81a982aSAlexander Graf } 879e81a982aSAlexander Graf 8809fddaa0cSbellard /* Adjust timer */ 8818e0a5ac8SNicholas Piggin timer_mod(timer, tb_to_ns_round_up(tb_env->decr_freq, next)); 882ddd1055bSFabien Chouteau } 88358a7d328Sj_mayer 884ea62f8a5SNicholas Piggin static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now, 885ea62f8a5SNicholas Piggin target_ulong decr, target_ulong value, 886ea62f8a5SNicholas Piggin int nr_bits) 88758a7d328Sj_mayer { 8887e0a9247SAndreas Färber ppc_tb_t *tb_env = cpu->env.tb_env; 88958a7d328Sj_mayer 890ea62f8a5SNicholas Piggin __cpu_ppc_store_decr(cpu, now, &tb_env->decr_next, tb_env->decr_timer, 891a5ff7875SNicholas Piggin tb_env->decr_timer->cb, &cpu_ppc_decr_lower, 892a5ff7875SNicholas Piggin tb_env->flags, decr, value, nr_bits); 8939fddaa0cSbellard } 8949fddaa0cSbellard 895a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value) 8969fddaa0cSbellard { 897db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 898a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 899ea62f8a5SNicholas Piggin int64_t now; 900ea62f8a5SNicholas Piggin target_ulong decr; 901a8dafa52SSuraj Jitindar Singh int nr_bits = 32; 9027e0a9247SAndreas Färber 903ea62f8a5SNicholas Piggin if (kvm_enabled()) { 904ea62f8a5SNicholas Piggin /* KVM handles decrementer exceptions, we don't need our own timer */ 905ea62f8a5SNicholas Piggin return; 906ea62f8a5SNicholas Piggin } 907ea62f8a5SNicholas Piggin 908a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 909a8dafa52SSuraj Jitindar Singh nr_bits = pcc->lrg_decr_bits; 910a8dafa52SSuraj Jitindar Singh } 911a8dafa52SSuraj Jitindar Singh 912ea62f8a5SNicholas Piggin now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 913ea62f8a5SNicholas Piggin decr = _cpu_ppc_load_decr(env, now); 914ea62f8a5SNicholas Piggin _cpu_ppc_store_decr(cpu, now, decr, value, nr_bits); 9159fddaa0cSbellard } 9169fddaa0cSbellard 9179fddaa0cSbellard static void cpu_ppc_decr_cb(void *opaque) 9189fddaa0cSbellard { 91950c680f0SAndreas Färber PowerPCCPU *cpu = opaque; 9207e0a9247SAndreas Färber 921e81a982aSAlexander Graf cpu_ppc_decr_excp(cpu); 9229fddaa0cSbellard } 9239fddaa0cSbellard 924ea62f8a5SNicholas Piggin static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, int64_t now, 925ea62f8a5SNicholas Piggin target_ulong hdecr, target_ulong value, 926ea62f8a5SNicholas Piggin int nr_bits) 92758a7d328Sj_mayer { 9287e0a9247SAndreas Färber ppc_tb_t *tb_env = cpu->env.tb_env; 92958a7d328Sj_mayer 930b172c56aSj_mayer if (tb_env->hdecr_timer != NULL) { 931a5ff7875SNicholas Piggin /* HDECR (Book3S 64bit) is edge-based, not level like DECR */ 932ea62f8a5SNicholas Piggin __cpu_ppc_store_decr(cpu, now, &tb_env->hdecr_next, tb_env->hdecr_timer, 933e81a982aSAlexander Graf tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower, 934a5ff7875SNicholas Piggin PPC_DECR_UNDERFLOW_TRIGGERED, 935a8dafa52SSuraj Jitindar Singh hdecr, value, nr_bits); 93658a7d328Sj_mayer } 937b172c56aSj_mayer } 93858a7d328Sj_mayer 939a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value) 94058a7d328Sj_mayer { 941db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 942a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 943ea62f8a5SNicholas Piggin int64_t now; 944ea62f8a5SNicholas Piggin target_ulong hdecr; 9457e0a9247SAndreas Färber 946ea62f8a5SNicholas Piggin now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 947ea62f8a5SNicholas Piggin hdecr = _cpu_ppc_load_hdecr(env, now); 948ea62f8a5SNicholas Piggin _cpu_ppc_store_hdecr(cpu, now, hdecr, value, pcc->lrg_decr_bits); 94958a7d328Sj_mayer } 95058a7d328Sj_mayer 95158a7d328Sj_mayer static void cpu_ppc_hdecr_cb(void *opaque) 95258a7d328Sj_mayer { 95350c680f0SAndreas Färber PowerPCCPU *cpu = opaque; 9547e0a9247SAndreas Färber 955e81a982aSAlexander Graf cpu_ppc_hdecr_excp(cpu); 95658a7d328Sj_mayer } 95758a7d328Sj_mayer 958ea62f8a5SNicholas Piggin static void _cpu_ppc_store_purr(CPUPPCState *env, int64_t now, uint64_t value) 95958a7d328Sj_mayer { 9605cc7e69fSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 96158a7d328Sj_mayer 962ea62f8a5SNicholas Piggin cpu_ppc_store_tb(tb_env, now, &tb_env->purr_offset, value); 963ea62f8a5SNicholas Piggin } 964ea62f8a5SNicholas Piggin 965ea62f8a5SNicholas Piggin void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) 966ea62f8a5SNicholas Piggin { 967ea62f8a5SNicholas Piggin _cpu_ppc_store_purr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), value); 96858a7d328Sj_mayer } 96958a7d328Sj_mayer 97042043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb) 97198a8b524SAlexey Kardashevskiy { 9724a7428c5SChristopher Covington uint64_t ticks = cpu_get_host_ticks(); 97398a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 97498a8b524SAlexey Kardashevskiy 97598a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 97698a8b524SAlexey Kardashevskiy error_report("No timebase object"); 97798a8b524SAlexey Kardashevskiy return; 97898a8b524SAlexey Kardashevskiy } 97998a8b524SAlexey Kardashevskiy 9809db680f8SNicholas Piggin if (replay_mode == REPLAY_MODE_NONE) { 98142043e4fSLaurent Vivier /* not used anymore, we keep it for compatibility */ 98277bad151SPaolo Bonzini tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); 9839db680f8SNicholas Piggin } else { 9849db680f8SNicholas Piggin /* simpler for record-replay to avoid this event, compat not needed */ 9859db680f8SNicholas Piggin tb->time_of_the_day_ns = 0; 9869db680f8SNicholas Piggin } 9879db680f8SNicholas Piggin 98898a8b524SAlexey Kardashevskiy /* 98942043e4fSLaurent Vivier * tb_offset is only expected to be changed by QEMU so 99098a8b524SAlexey Kardashevskiy * there is no need to update it from KVM here 99198a8b524SAlexey Kardashevskiy */ 99298a8b524SAlexey Kardashevskiy tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; 993d14f3397SMaxiwell S. Garcia 994711dfb24SGreg Kurz tb->runstate_paused = 995711dfb24SGreg Kurz runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM); 99698a8b524SAlexey Kardashevskiy } 99798a8b524SAlexey Kardashevskiy 99842043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb) 99998a8b524SAlexey Kardashevskiy { 100098a8b524SAlexey Kardashevskiy CPUState *cpu; 100198a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 100242043e4fSLaurent Vivier int64_t tb_off_adj, tb_off; 100398a8b524SAlexey Kardashevskiy unsigned long freq; 100498a8b524SAlexey Kardashevskiy 100598a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 100698a8b524SAlexey Kardashevskiy error_report("No timebase object"); 100742043e4fSLaurent Vivier return; 100898a8b524SAlexey Kardashevskiy } 100998a8b524SAlexey Kardashevskiy 101098a8b524SAlexey Kardashevskiy freq = first_ppc_cpu->env.tb_env->tb_freq; 101198a8b524SAlexey Kardashevskiy 101242043e4fSLaurent Vivier tb_off_adj = tb->guest_timebase - cpu_get_host_ticks(); 101398a8b524SAlexey Kardashevskiy 101498a8b524SAlexey Kardashevskiy tb_off = first_ppc_cpu->env.tb_env->tb_offset; 101598a8b524SAlexey Kardashevskiy trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off, 101698a8b524SAlexey Kardashevskiy (tb_off_adj - tb_off) / freq); 101798a8b524SAlexey Kardashevskiy 101898a8b524SAlexey Kardashevskiy /* Set new offset to all CPUs */ 101998a8b524SAlexey Kardashevskiy CPU_FOREACH(cpu) { 102098a8b524SAlexey Kardashevskiy PowerPCCPU *pcpu = POWERPC_CPU(cpu); 102198a8b524SAlexey Kardashevskiy pcpu->env.tb_env->tb_offset = tb_off_adj; 10229723295aSGreg Kurz kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset); 102342043e4fSLaurent Vivier } 102498a8b524SAlexey Kardashevskiy } 102598a8b524SAlexey Kardashevskiy 1026538f0497SPhilippe Mathieu-Daudé void cpu_ppc_clock_vm_state_change(void *opaque, bool running, 102742043e4fSLaurent Vivier RunState state) 102842043e4fSLaurent Vivier { 102942043e4fSLaurent Vivier PPCTimebase *tb = opaque; 103042043e4fSLaurent Vivier 103142043e4fSLaurent Vivier if (running) { 103242043e4fSLaurent Vivier timebase_load(tb); 103342043e4fSLaurent Vivier } else { 103442043e4fSLaurent Vivier timebase_save(tb); 103542043e4fSLaurent Vivier } 103642043e4fSLaurent Vivier } 103742043e4fSLaurent Vivier 103842043e4fSLaurent Vivier /* 1039d14f3397SMaxiwell S. Garcia * When migrating a running guest, read the clock just 1040d14f3397SMaxiwell S. Garcia * before migration, so that the guest clock counts 1041d14f3397SMaxiwell S. Garcia * during the events between: 104242043e4fSLaurent Vivier * 104342043e4fSLaurent Vivier * * vm_stop() 104442043e4fSLaurent Vivier * * 104542043e4fSLaurent Vivier * * pre_save() 104642043e4fSLaurent Vivier * 104742043e4fSLaurent Vivier * This reduces clock difference on migration from 5s 104842043e4fSLaurent Vivier * to 0.1s (when max_downtime == 5s), because sending the 104942043e4fSLaurent Vivier * final pages of memory (which happens between vm_stop() 105042043e4fSLaurent Vivier * and pre_save()) takes max_downtime. 105142043e4fSLaurent Vivier */ 105244b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque) 105342043e4fSLaurent Vivier { 105442043e4fSLaurent Vivier PPCTimebase *tb = opaque; 105542043e4fSLaurent Vivier 1056711dfb24SGreg Kurz /* guest_timebase won't be overridden in case of paused guest or savevm */ 1057d14f3397SMaxiwell S. Garcia if (!tb->runstate_paused) { 105842043e4fSLaurent Vivier timebase_save(tb); 1059d14f3397SMaxiwell S. Garcia } 106044b1ff31SDr. David Alan Gilbert 106144b1ff31SDr. David Alan Gilbert return 0; 106298a8b524SAlexey Kardashevskiy } 106398a8b524SAlexey Kardashevskiy 106498a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = { 106598a8b524SAlexey Kardashevskiy .name = "timebase", 106698a8b524SAlexey Kardashevskiy .version_id = 1, 106798a8b524SAlexey Kardashevskiy .minimum_version_id = 1, 106898a8b524SAlexey Kardashevskiy .pre_save = timebase_pre_save, 106998a8b524SAlexey Kardashevskiy .fields = (VMStateField []) { 107098a8b524SAlexey Kardashevskiy VMSTATE_UINT64(guest_timebase, PPCTimebase), 107198a8b524SAlexey Kardashevskiy VMSTATE_INT64(time_of_the_day_ns, PPCTimebase), 107298a8b524SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 107398a8b524SAlexey Kardashevskiy }, 107498a8b524SAlexey Kardashevskiy }; 107598a8b524SAlexey Kardashevskiy 10769fddaa0cSbellard /* Set up (once) timebase frequency (in Hz) */ 107730d0647bSNicholas Piggin void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq) 10789fddaa0cSbellard { 1079db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 1080c227f099SAnthony Liguori ppc_tb_t *tb_env; 10819fddaa0cSbellard 1082b21e2380SMarkus Armbruster tb_env = g_new0(ppc_tb_t, 1); 10839fddaa0cSbellard env->tb_env = tb_env; 1084ddd1055bSFabien Chouteau tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 1085d0db7cadSGreg Kurz if (is_book3s_arch2x(env)) { 1086e81a982aSAlexander Graf /* All Book3S 64bit CPUs implement level based DEC logic */ 1087e81a982aSAlexander Graf tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL; 1088e81a982aSAlexander Graf } 10899fddaa0cSbellard /* Create new timer */ 1090eaf832fcSNicholas Piggin tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 1091eaf832fcSNicholas Piggin &cpu_ppc_decr_cb, cpu); 10925ff40b01SNicholas Piggin if (env->has_hv_mode && !cpu->vhyp) { 1093eaf832fcSNicholas Piggin tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 1094eaf832fcSNicholas Piggin &cpu_ppc_hdecr_cb, cpu); 1095b172c56aSj_mayer } else { 1096b172c56aSj_mayer tb_env->hdecr_timer = NULL; 1097b172c56aSj_mayer } 10989fddaa0cSbellard 109930d0647bSNicholas Piggin tb_env->tb_freq = freq; 110030d0647bSNicholas Piggin tb_env->decr_freq = freq; 110130d0647bSNicholas Piggin } 110230d0647bSNicholas Piggin 110330d0647bSNicholas Piggin void cpu_ppc_tb_reset(CPUPPCState *env) 110430d0647bSNicholas Piggin { 110530d0647bSNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 110630d0647bSNicholas Piggin ppc_tb_t *tb_env = env->tb_env; 110730d0647bSNicholas Piggin 110830d0647bSNicholas Piggin timer_del(tb_env->decr_timer); 110930d0647bSNicholas Piggin ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0); 111030d0647bSNicholas Piggin tb_env->decr_next = 0; 111130d0647bSNicholas Piggin if (tb_env->hdecr_timer != NULL) { 111230d0647bSNicholas Piggin timer_del(tb_env->hdecr_timer); 111330d0647bSNicholas Piggin ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); 111430d0647bSNicholas Piggin tb_env->hdecr_next = 0; 111530d0647bSNicholas Piggin } 111630d0647bSNicholas Piggin 111730d0647bSNicholas Piggin /* 111830d0647bSNicholas Piggin * There is a bug in Linux 2.4 kernels: 111930d0647bSNicholas Piggin * if a decrementer exception is pending when it enables msr_ee at startup, 112030d0647bSNicholas Piggin * it's not ready to handle it... 112130d0647bSNicholas Piggin */ 112230d0647bSNicholas Piggin cpu_ppc_store_decr(env, -1); 112330d0647bSNicholas Piggin cpu_ppc_store_hdecr(env, -1); 112430d0647bSNicholas Piggin cpu_ppc_store_purr(env, 0x0000000000000000ULL); 11259fddaa0cSbellard } 11269fddaa0cSbellard 1127ef95a244SDaniel Henrique Barboza void cpu_ppc_tb_free(CPUPPCState *env) 1128ef95a244SDaniel Henrique Barboza { 1129ef95a244SDaniel Henrique Barboza timer_free(env->tb_env->decr_timer); 1130ef95a244SDaniel Henrique Barboza timer_free(env->tb_env->hdecr_timer); 1131ef95a244SDaniel Henrique Barboza g_free(env->tb_env); 1132ef95a244SDaniel Henrique Barboza } 1133ef95a244SDaniel Henrique Barboza 113493aeb702SNicholas Piggin /* cpu_ppc_hdecr_init may be used if the timer is not used by HDEC emulation */ 113593aeb702SNicholas Piggin void cpu_ppc_hdecr_init(CPUPPCState *env) 113693aeb702SNicholas Piggin { 113793aeb702SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 113893aeb702SNicholas Piggin 113993aeb702SNicholas Piggin assert(env->tb_env->hdecr_timer == NULL); 114093aeb702SNicholas Piggin 114193aeb702SNicholas Piggin env->tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 114293aeb702SNicholas Piggin &cpu_ppc_hdecr_cb, cpu); 114393aeb702SNicholas Piggin } 114493aeb702SNicholas Piggin 114593aeb702SNicholas Piggin void cpu_ppc_hdecr_exit(CPUPPCState *env) 114693aeb702SNicholas Piggin { 114793aeb702SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 114893aeb702SNicholas Piggin 114993aeb702SNicholas Piggin timer_free(env->tb_env->hdecr_timer); 115093aeb702SNicholas Piggin env->tb_env->hdecr_timer = NULL; 115193aeb702SNicholas Piggin 115293aeb702SNicholas Piggin cpu_ppc_hdecr_lower(cpu); 115393aeb702SNicholas Piggin } 115493aeb702SNicholas Piggin 1155636aaad7Sj_mayer /*****************************************************************************/ 1156ddd1055bSFabien Chouteau /* PowerPC 40x timers */ 1157636aaad7Sj_mayer 1158636aaad7Sj_mayer /* PIT, FIT & WDT */ 1159ddd1055bSFabien Chouteau typedef struct ppc40x_timer_t ppc40x_timer_t; 1160ddd1055bSFabien Chouteau struct ppc40x_timer_t { 1161636aaad7Sj_mayer uint64_t pit_reload; /* PIT auto-reload value */ 1162636aaad7Sj_mayer uint64_t fit_next; /* Tick for next FIT interrupt */ 11631246b259SStefan Weil QEMUTimer *fit_timer; 1164636aaad7Sj_mayer uint64_t wdt_next; /* Tick for next WDT interrupt */ 11651246b259SStefan Weil QEMUTimer *wdt_timer; 1166d63cb48dSEdgar E. Iglesias 1167d63cb48dSEdgar E. Iglesias /* 405 have the PIT, 440 have a DECR. */ 1168d63cb48dSEdgar E. Iglesias unsigned int decr_excp; 1169636aaad7Sj_mayer }; 1170636aaad7Sj_mayer 1171636aaad7Sj_mayer /* Fixed interval timer */ 1172636aaad7Sj_mayer static void cpu_4xx_fit_cb (void *opaque) 117376a66253Sj_mayer { 1174b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1175b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 1176c227f099SAnthony Liguori ppc_tb_t *tb_env; 1177ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1178636aaad7Sj_mayer uint64_t now, next; 1179636aaad7Sj_mayer 1180636aaad7Sj_mayer tb_env = env->tb_env; 1181ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1182bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1183636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { 1184636aaad7Sj_mayer case 0: 1185636aaad7Sj_mayer next = 1 << 9; 1186636aaad7Sj_mayer break; 1187636aaad7Sj_mayer case 1: 1188636aaad7Sj_mayer next = 1 << 13; 1189636aaad7Sj_mayer break; 1190636aaad7Sj_mayer case 2: 1191636aaad7Sj_mayer next = 1 << 17; 1192636aaad7Sj_mayer break; 1193636aaad7Sj_mayer case 3: 1194636aaad7Sj_mayer next = 1 << 21; 1195636aaad7Sj_mayer break; 1196636aaad7Sj_mayer default: 1197636aaad7Sj_mayer /* Cannot occur, but makes gcc happy */ 1198636aaad7Sj_mayer return; 1199636aaad7Sj_mayer } 1200eab08884SNicholas Piggin next = now + tb_to_ns_round_up(tb_env->tb_freq, next); 1201bc72ad67SAlex Bligh timer_mod(ppc40x_timer->fit_timer, next); 1202636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 26; 12037058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { 12047058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); 12057058581aSAndreas Färber } 1206af96d2e6SCédric Le Goater trace_ppc4xx_fit((int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), 1207636aaad7Sj_mayer env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 1208636aaad7Sj_mayer } 1209636aaad7Sj_mayer 1210636aaad7Sj_mayer /* Programmable interval timer */ 1211e2684c0bSAndreas Färber static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) 1212636aaad7Sj_mayer { 1213ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1214636aaad7Sj_mayer uint64_t now, next; 1215636aaad7Sj_mayer 1216ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1217ddd1055bSFabien Chouteau if (ppc40x_timer->pit_reload <= 1 || 12184b6d0a4cSj_mayer !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || 12194b6d0a4cSj_mayer (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { 12204b6d0a4cSj_mayer /* Stop PIT */ 1221af96d2e6SCédric Le Goater trace_ppc4xx_pit_stop(); 1222bc72ad67SAlex Bligh timer_del(tb_env->decr_timer); 12234b6d0a4cSj_mayer } else { 1224af96d2e6SCédric Le Goater trace_ppc4xx_pit_start(ppc40x_timer->pit_reload); 1225bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 12268e0a5ac8SNicholas Piggin 12278e0a5ac8SNicholas Piggin if (is_excp) { 12288e0a5ac8SNicholas Piggin tb_env->decr_next += ppc40x_timer->pit_reload; 12298e0a5ac8SNicholas Piggin } else { 12308e0a5ac8SNicholas Piggin tb_env->decr_next = ns_to_tb(tb_env->decr_freq, now) 12318e0a5ac8SNicholas Piggin + ppc40x_timer->pit_reload; 12328e0a5ac8SNicholas Piggin } 12338e0a5ac8SNicholas Piggin next = tb_to_ns_round_up(tb_env->decr_freq, tb_env->decr_next); 1234bc72ad67SAlex Bligh timer_mod(tb_env->decr_timer, next); 1235636aaad7Sj_mayer } 12364b6d0a4cSj_mayer } 12374b6d0a4cSj_mayer 12384b6d0a4cSj_mayer static void cpu_4xx_pit_cb (void *opaque) 12394b6d0a4cSj_mayer { 1240b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1241b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 1242c227f099SAnthony Liguori ppc_tb_t *tb_env; 1243ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 12444b6d0a4cSj_mayer 12454b6d0a4cSj_mayer tb_env = env->tb_env; 1246ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1247636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 27; 12487058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { 12497058581aSAndreas Färber ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); 12507058581aSAndreas Färber } 12514b6d0a4cSj_mayer start_stop_pit(env, tb_env, 1); 1252af96d2e6SCédric Le Goater trace_ppc4xx_pit((int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), 1253e96efcfcSj_mayer (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), 1254636aaad7Sj_mayer env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], 1255ddd1055bSFabien Chouteau ppc40x_timer->pit_reload); 1256636aaad7Sj_mayer } 1257636aaad7Sj_mayer 1258636aaad7Sj_mayer /* Watchdog timer */ 1259636aaad7Sj_mayer static void cpu_4xx_wdt_cb (void *opaque) 1260636aaad7Sj_mayer { 1261b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1262b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 1263c227f099SAnthony Liguori ppc_tb_t *tb_env; 1264ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1265636aaad7Sj_mayer uint64_t now, next; 1266636aaad7Sj_mayer 1267636aaad7Sj_mayer tb_env = env->tb_env; 1268ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1269bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1270636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { 1271636aaad7Sj_mayer case 0: 1272636aaad7Sj_mayer next = 1 << 17; 1273636aaad7Sj_mayer break; 1274636aaad7Sj_mayer case 1: 1275636aaad7Sj_mayer next = 1 << 21; 1276636aaad7Sj_mayer break; 1277636aaad7Sj_mayer case 2: 1278636aaad7Sj_mayer next = 1 << 25; 1279636aaad7Sj_mayer break; 1280636aaad7Sj_mayer case 3: 1281636aaad7Sj_mayer next = 1 << 29; 1282636aaad7Sj_mayer break; 1283636aaad7Sj_mayer default: 1284636aaad7Sj_mayer /* Cannot occur, but makes gcc happy */ 1285636aaad7Sj_mayer return; 1286636aaad7Sj_mayer } 1287eab08884SNicholas Piggin next = now + tb_to_ns_round_up(tb_env->decr_freq, next); 1288af96d2e6SCédric Le Goater trace_ppc4xx_wdt(env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 1289636aaad7Sj_mayer switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { 1290636aaad7Sj_mayer case 0x0: 1291636aaad7Sj_mayer case 0x1: 1292bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 1293ddd1055bSFabien Chouteau ppc40x_timer->wdt_next = next; 1294a1f7f97bSPeter Maydell env->spr[SPR_40x_TSR] |= 1U << 31; 1295636aaad7Sj_mayer break; 1296636aaad7Sj_mayer case 0x2: 1297bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 1298ddd1055bSFabien Chouteau ppc40x_timer->wdt_next = next; 1299636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 30; 13007058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { 13017058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); 13027058581aSAndreas Färber } 1303636aaad7Sj_mayer break; 1304636aaad7Sj_mayer case 0x3: 1305636aaad7Sj_mayer env->spr[SPR_40x_TSR] &= ~0x30000000; 1306636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000; 1307636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) { 1308636aaad7Sj_mayer case 0x0: 1309636aaad7Sj_mayer /* No reset */ 1310636aaad7Sj_mayer break; 1311636aaad7Sj_mayer case 0x1: /* Core reset */ 1312f3273ba6SAndreas Färber ppc40x_core_reset(cpu); 13138ecc7913Sj_mayer break; 1314636aaad7Sj_mayer case 0x2: /* Chip reset */ 1315f3273ba6SAndreas Färber ppc40x_chip_reset(cpu); 13168ecc7913Sj_mayer break; 1317636aaad7Sj_mayer case 0x3: /* System reset */ 1318f3273ba6SAndreas Färber ppc40x_system_reset(cpu); 13198ecc7913Sj_mayer break; 1320636aaad7Sj_mayer } 1321636aaad7Sj_mayer } 132276a66253Sj_mayer } 132376a66253Sj_mayer 1324e2684c0bSAndreas Färber void store_40x_pit (CPUPPCState *env, target_ulong val) 132576a66253Sj_mayer { 1326c227f099SAnthony Liguori ppc_tb_t *tb_env; 1327ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1328636aaad7Sj_mayer 1329636aaad7Sj_mayer tb_env = env->tb_env; 1330ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1331af96d2e6SCédric Le Goater trace_ppc40x_store_pit(val); 1332ddd1055bSFabien Chouteau ppc40x_timer->pit_reload = val; 13334b6d0a4cSj_mayer start_stop_pit(env, tb_env, 0); 133476a66253Sj_mayer } 133576a66253Sj_mayer 1336e2684c0bSAndreas Färber target_ulong load_40x_pit (CPUPPCState *env) 133776a66253Sj_mayer { 1338636aaad7Sj_mayer return cpu_ppc_load_decr(env); 133976a66253Sj_mayer } 134076a66253Sj_mayer 1341cbd8f17dSCédric Le Goater void store_40x_tsr(CPUPPCState *env, target_ulong val) 1342cbd8f17dSCédric Le Goater { 1343cbd8f17dSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1344cbd8f17dSCédric Le Goater 1345cbd8f17dSCédric Le Goater trace_ppc40x_store_tcr(val); 1346cbd8f17dSCédric Le Goater 1347cbd8f17dSCédric Le Goater env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000); 1348cbd8f17dSCédric Le Goater if (val & 0x80000000) { 1349cbd8f17dSCédric Le Goater ppc_set_irq(cpu, PPC_INTERRUPT_PIT, 0); 1350cbd8f17dSCédric Le Goater } 1351cbd8f17dSCédric Le Goater } 1352cbd8f17dSCédric Le Goater 1353cbd8f17dSCédric Le Goater void store_40x_tcr(CPUPPCState *env, target_ulong val) 1354cbd8f17dSCédric Le Goater { 1355cbd8f17dSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1356cbd8f17dSCédric Le Goater ppc_tb_t *tb_env; 1357cbd8f17dSCédric Le Goater 1358cbd8f17dSCédric Le Goater trace_ppc40x_store_tsr(val); 1359cbd8f17dSCédric Le Goater 1360cbd8f17dSCédric Le Goater tb_env = env->tb_env; 1361cbd8f17dSCédric Le Goater env->spr[SPR_40x_TCR] = val & 0xFFC00000; 1362cbd8f17dSCédric Le Goater start_stop_pit(env, tb_env, 1); 1363cbd8f17dSCédric Le Goater cpu_4xx_wdt_cb(cpu); 1364cbd8f17dSCédric Le Goater } 1365cbd8f17dSCédric Le Goater 1366ddd1055bSFabien Chouteau static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq) 13674b6d0a4cSj_mayer { 1368e2684c0bSAndreas Färber CPUPPCState *env = opaque; 1369c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 13704b6d0a4cSj_mayer 1371af96d2e6SCédric Le Goater trace_ppc40x_set_tb_clk(freq); 13724b6d0a4cSj_mayer tb_env->tb_freq = freq; 1373dbdd2506Sj_mayer tb_env->decr_freq = freq; 13744b6d0a4cSj_mayer /* XXX: we should also update all timers */ 13754b6d0a4cSj_mayer } 13764b6d0a4cSj_mayer 1377e2684c0bSAndreas Färber clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, 1378d63cb48dSEdgar E. Iglesias unsigned int decr_excp) 1379636aaad7Sj_mayer { 1380c227f099SAnthony Liguori ppc_tb_t *tb_env; 1381ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1382b1273a5eSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1383b1273a5eSCédric Le Goater 1384b1273a5eSCédric Le Goater trace_ppc40x_timers_init(freq); 1385636aaad7Sj_mayer 1386b21e2380SMarkus Armbruster tb_env = g_new0(ppc_tb_t, 1); 1387b21e2380SMarkus Armbruster ppc40x_timer = g_new0(ppc40x_timer_t, 1); 1388b1273a5eSCédric Le Goater 13898ecc7913Sj_mayer env->tb_env = tb_env; 1390ddd1055bSFabien Chouteau tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 13918ecc7913Sj_mayer tb_env->tb_freq = freq; 1392dbdd2506Sj_mayer tb_env->decr_freq = freq; 1393ddd1055bSFabien Chouteau tb_env->opaque = ppc40x_timer; 1394b1273a5eSCédric Le Goater 1395636aaad7Sj_mayer /* We use decr timer for PIT */ 1396b1273a5eSCédric Le Goater tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, cpu); 1397ddd1055bSFabien Chouteau ppc40x_timer->fit_timer = 1398b1273a5eSCédric Le Goater timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, cpu); 1399ddd1055bSFabien Chouteau ppc40x_timer->wdt_timer = 1400b1273a5eSCédric Le Goater timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, cpu); 1401ddd1055bSFabien Chouteau ppc40x_timer->decr_excp = decr_excp; 14028ecc7913Sj_mayer 1403ddd1055bSFabien Chouteau return &ppc_40x_set_tb_clk; 140476a66253Sj_mayer } 140576a66253Sj_mayer 14062e719ba3Sj_mayer /*****************************************************************************/ 14072e719ba3Sj_mayer /* Embedded PowerPC Device Control Registers */ 1408c227f099SAnthony Liguori typedef struct ppc_dcrn_t ppc_dcrn_t; 1409c227f099SAnthony Liguori struct ppc_dcrn_t { 14102e719ba3Sj_mayer dcr_read_cb dcr_read; 14112e719ba3Sj_mayer dcr_write_cb dcr_write; 14122e719ba3Sj_mayer void *opaque; 14132e719ba3Sj_mayer }; 14142e719ba3Sj_mayer 1415a750fc0bSj_mayer /* XXX: on 460, DCR addresses are 32 bits wide, 1416a750fc0bSj_mayer * using DCRIPR to get the 22 upper bits of the DCR address 1417a750fc0bSj_mayer */ 14182e719ba3Sj_mayer #define DCRN_NB 1024 1419c227f099SAnthony Liguori struct ppc_dcr_t { 1420c227f099SAnthony Liguori ppc_dcrn_t dcrn[DCRN_NB]; 14212e719ba3Sj_mayer int (*read_error)(int dcrn); 14222e719ba3Sj_mayer int (*write_error)(int dcrn); 14232e719ba3Sj_mayer }; 14242e719ba3Sj_mayer 142573b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) 14262e719ba3Sj_mayer { 1427c227f099SAnthony Liguori ppc_dcrn_t *dcr; 14282e719ba3Sj_mayer 14292e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 14302e719ba3Sj_mayer goto error; 14312e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 14322e719ba3Sj_mayer if (dcr->dcr_read == NULL) 14332e719ba3Sj_mayer goto error; 14342e719ba3Sj_mayer *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); 1435de82dabeSCédric Le Goater trace_ppc_dcr_read(dcrn, *valp); 14362e719ba3Sj_mayer 14372e719ba3Sj_mayer return 0; 14382e719ba3Sj_mayer 14392e719ba3Sj_mayer error: 14402e719ba3Sj_mayer if (dcr_env->read_error != NULL) 14412e719ba3Sj_mayer return (*dcr_env->read_error)(dcrn); 14422e719ba3Sj_mayer 14432e719ba3Sj_mayer return -1; 14442e719ba3Sj_mayer } 14452e719ba3Sj_mayer 144673b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) 14472e719ba3Sj_mayer { 1448c227f099SAnthony Liguori ppc_dcrn_t *dcr; 14492e719ba3Sj_mayer 14502e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 14512e719ba3Sj_mayer goto error; 14522e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 14532e719ba3Sj_mayer if (dcr->dcr_write == NULL) 14542e719ba3Sj_mayer goto error; 1455de82dabeSCédric Le Goater trace_ppc_dcr_write(dcrn, val); 14562e719ba3Sj_mayer (*dcr->dcr_write)(dcr->opaque, dcrn, val); 14572e719ba3Sj_mayer 14582e719ba3Sj_mayer return 0; 14592e719ba3Sj_mayer 14602e719ba3Sj_mayer error: 14612e719ba3Sj_mayer if (dcr_env->write_error != NULL) 14622e719ba3Sj_mayer return (*dcr_env->write_error)(dcrn); 14632e719ba3Sj_mayer 14642e719ba3Sj_mayer return -1; 14652e719ba3Sj_mayer } 14662e719ba3Sj_mayer 1467e2684c0bSAndreas Färber int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, 14682e719ba3Sj_mayer dcr_read_cb dcr_read, dcr_write_cb dcr_write) 14692e719ba3Sj_mayer { 1470c227f099SAnthony Liguori ppc_dcr_t *dcr_env; 1471c227f099SAnthony Liguori ppc_dcrn_t *dcr; 14722e719ba3Sj_mayer 14732e719ba3Sj_mayer dcr_env = env->dcr_env; 14742e719ba3Sj_mayer if (dcr_env == NULL) 14752e719ba3Sj_mayer return -1; 14762e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 14772e719ba3Sj_mayer return -1; 14782e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 14792e719ba3Sj_mayer if (dcr->opaque != NULL || 14802e719ba3Sj_mayer dcr->dcr_read != NULL || 14812e719ba3Sj_mayer dcr->dcr_write != NULL) 14822e719ba3Sj_mayer return -1; 14832e719ba3Sj_mayer dcr->opaque = opaque; 14842e719ba3Sj_mayer dcr->dcr_read = dcr_read; 14852e719ba3Sj_mayer dcr->dcr_write = dcr_write; 14862e719ba3Sj_mayer 14872e719ba3Sj_mayer return 0; 14882e719ba3Sj_mayer } 14892e719ba3Sj_mayer 1490e2684c0bSAndreas Färber int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn), 14912e719ba3Sj_mayer int (*write_error)(int dcrn)) 14922e719ba3Sj_mayer { 1493c227f099SAnthony Liguori ppc_dcr_t *dcr_env; 14942e719ba3Sj_mayer 1495b21e2380SMarkus Armbruster dcr_env = g_new0(ppc_dcr_t, 1); 14962e719ba3Sj_mayer dcr_env->read_error = read_error; 14972e719ba3Sj_mayer dcr_env->write_error = write_error; 14982e719ba3Sj_mayer env->dcr_env = dcr_env; 14992e719ba3Sj_mayer 15002e719ba3Sj_mayer return 0; 15012e719ba3Sj_mayer } 15022e719ba3Sj_mayer 150364201201Sbellard /*****************************************************************************/ 1504051e2973SCédric Le Goater 15054a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu) 15064a89e204SCédric Le Goater { 15074a89e204SCédric Le Goater CPUPPCState *env = &cpu->env; 15084a89e204SCédric Le Goater return env->spr_cb[SPR_PIR].default_value; 15094a89e204SCédric Le Goater } 15104a89e204SCédric Le Goater 1511d24e80b2SNicholas Piggin int ppc_cpu_tir(PowerPCCPU *cpu) 1512d24e80b2SNicholas Piggin { 1513d24e80b2SNicholas Piggin CPUPPCState *env = &cpu->env; 1514d24e80b2SNicholas Piggin return env->spr_cb[SPR_TIR].default_value; 1515d24e80b2SNicholas Piggin } 1516d24e80b2SNicholas Piggin 1517051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir) 1518051e2973SCédric Le Goater { 1519051e2973SCédric Le Goater CPUState *cs; 1520051e2973SCédric Le Goater 1521051e2973SCédric Le Goater CPU_FOREACH(cs) { 1522051e2973SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 1523051e2973SCédric Le Goater 15244a89e204SCédric Le Goater if (ppc_cpu_pir(cpu) == pir) { 1525051e2973SCédric Le Goater return cpu; 1526051e2973SCédric Le Goater } 1527051e2973SCédric Le Goater } 1528051e2973SCédric Le Goater 1529051e2973SCédric Le Goater return NULL; 1530051e2973SCédric Le Goater } 153140177438SGreg Kurz 153240177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu) 153340177438SGreg Kurz { 153440177438SGreg Kurz CPUPPCState *env = &cpu->env; 153540177438SGreg Kurz 153640177438SGreg Kurz env->irq_input_state = 0; 1537*76d93e14Sjianchunfu if (kvm_enabled()) { 153840177438SGreg Kurz kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); 153940177438SGreg Kurz } 1540*76d93e14Sjianchunfu } 1541