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" 3554d31236SMarkus Armbruster #include "sysemu/runstate.h" 36fc87e185SAlexander Graf #include "kvm_ppc.h" 37d6454270SMarkus Armbruster #include "migration/vmstate.h" 3898a8b524SAlexey Kardashevskiy #include "trace.h" 39a541f297Sbellard 40e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env); 41e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env); 42dbdd2506Sj_mayer 43f003109fSMatheus Ferst void ppc_set_irq(PowerPCCPU *cpu, int irq, int level) 4447103572Sj_mayer { 457058581aSAndreas Färber CPUPPCState *env = &cpu->env; 468d04fb55SJan Kiszka unsigned int old_pending; 478d04fb55SJan Kiszka 488d04fb55SJan Kiszka /* We may already have the BQL if coming from the reset path */ 4950c9c512SRichard Henderson QEMU_IOTHREAD_LOCK_GUARD(); 508d04fb55SJan Kiszka 518d04fb55SJan Kiszka old_pending = env->pending_interrupts; 52fc87e185SAlexander Graf 5347103572Sj_mayer if (level) { 54f003109fSMatheus Ferst env->pending_interrupts |= irq; 5547103572Sj_mayer } else { 56f003109fSMatheus Ferst env->pending_interrupts &= ~irq; 5747103572Sj_mayer } 58fc87e185SAlexander Graf 59fc87e185SAlexander Graf if (old_pending != env->pending_interrupts) { 602fdedcbcSMatheus Ferst ppc_maybe_interrupt(env); 61f003109fSMatheus Ferst kvmppc_set_interrupt(cpu, irq, level); 62fc87e185SAlexander Graf } 63fc87e185SAlexander Graf 64f003109fSMatheus Ferst trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts, 65af96d2e6SCédric Le Goater CPU(cpu)->interrupt_request); 66a496775fSj_mayer } 6747103572Sj_mayer 68e9df014cSj_mayer /* PowerPC 6xx / 7xx internal IRQ controller */ 69e9df014cSj_mayer static void ppc6xx_set_irq(void *opaque, int pin, int level) 70d537cf6cSpbrook { 71a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 72a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 73e9df014cSj_mayer int cur_level; 74d537cf6cSpbrook 75af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 76af96d2e6SCédric Le Goater 77e9df014cSj_mayer cur_level = (env->irq_input_state >> pin) & 1; 78e9df014cSj_mayer /* Don't generate spurious events */ 7924be5ae3Sj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 80259186a7SAndreas Färber CPUState *cs = CPU(cpu); 81259186a7SAndreas Färber 82e9df014cSj_mayer switch (pin) { 83dbdd2506Sj_mayer case PPC6xx_INPUT_TBEN: 84dbdd2506Sj_mayer /* Level sensitive - active high */ 85af96d2e6SCédric Le Goater trace_ppc_irq_set_state("time base", level); 86dbdd2506Sj_mayer if (level) { 87dbdd2506Sj_mayer cpu_ppc_tb_start(env); 88dbdd2506Sj_mayer } else { 89dbdd2506Sj_mayer cpu_ppc_tb_stop(env); 90dbdd2506Sj_mayer } 91b2bd5b20SChen Qun break; 9224be5ae3Sj_mayer case PPC6xx_INPUT_INT: 9324be5ae3Sj_mayer /* Level sensitive - active high */ 94af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 957058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 96e9df014cSj_mayer break; 9724be5ae3Sj_mayer case PPC6xx_INPUT_SMI: 98e9df014cSj_mayer /* Level sensitive - active high */ 99af96d2e6SCédric Le Goater trace_ppc_irq_set_state("SMI IRQ", level); 1007058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); 101e9df014cSj_mayer break; 10224be5ae3Sj_mayer case PPC6xx_INPUT_MCP: 103e9df014cSj_mayer /* Negative edge sensitive */ 104e9df014cSj_mayer /* XXX: TODO: actual reaction may depends on HID0 status 105e9df014cSj_mayer * 603/604/740/750: check HID0[EMCP] 106e9df014cSj_mayer */ 107e9df014cSj_mayer if (cur_level == 1 && level == 0) { 108af96d2e6SCédric Le Goater trace_ppc_irq_set_state("machine check", 1); 1097058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 110d537cf6cSpbrook } 111e9df014cSj_mayer break; 11224be5ae3Sj_mayer case PPC6xx_INPUT_CKSTP_IN: 113e9df014cSj_mayer /* Level sensitive - active low */ 114e9df014cSj_mayer /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 115e63ecc6fSj_mayer /* XXX: Note that the only way to restart the CPU is to reset it */ 116e9df014cSj_mayer if (level) { 117af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 118259186a7SAndreas Färber cs->halted = 1; 119d537cf6cSpbrook } 12047103572Sj_mayer break; 12124be5ae3Sj_mayer case PPC6xx_INPUT_HRESET: 122e9df014cSj_mayer /* Level sensitive - active low */ 123e9df014cSj_mayer if (level) { 124af96d2e6SCédric Le Goater trace_ppc_irq_reset("CPU"); 125c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 126e9df014cSj_mayer } 12747103572Sj_mayer break; 12824be5ae3Sj_mayer case PPC6xx_INPUT_SRESET: 129af96d2e6SCédric Le Goater trace_ppc_irq_set_state("RESET IRQ", level); 1307058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 13147103572Sj_mayer break; 132e9df014cSj_mayer default: 1337279810bSCédric Le Goater g_assert_not_reached(); 13447103572Sj_mayer } 135e9df014cSj_mayer if (level) 136e9df014cSj_mayer env->irq_input_state |= 1 << pin; 137e9df014cSj_mayer else 138e9df014cSj_mayer env->irq_input_state &= ~(1 << pin); 139e9df014cSj_mayer } 140e9df014cSj_mayer } 141e9df014cSj_mayer 142aa5a9e24SPaolo Bonzini void ppc6xx_irq_init(PowerPCCPU *cpu) 143e9df014cSj_mayer { 1440f3e0c6fSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc6xx_set_irq, PPC6xx_INPUT_NB); 14547103572Sj_mayer } 14647103572Sj_mayer 14700af685fSj_mayer #if defined(TARGET_PPC64) 148d0dfae6eSj_mayer /* PowerPC 970 internal IRQ controller */ 149d0dfae6eSj_mayer static void ppc970_set_irq(void *opaque, int pin, int level) 150d0dfae6eSj_mayer { 151a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 152a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 153d0dfae6eSj_mayer int cur_level; 154d0dfae6eSj_mayer 155af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 156af96d2e6SCédric Le Goater 157d0dfae6eSj_mayer cur_level = (env->irq_input_state >> pin) & 1; 158d0dfae6eSj_mayer /* Don't generate spurious events */ 159d0dfae6eSj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 160259186a7SAndreas Färber CPUState *cs = CPU(cpu); 161259186a7SAndreas Färber 162d0dfae6eSj_mayer switch (pin) { 163d0dfae6eSj_mayer case PPC970_INPUT_INT: 164d0dfae6eSj_mayer /* Level sensitive - active high */ 165af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 1667058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 167d0dfae6eSj_mayer break; 168d0dfae6eSj_mayer case PPC970_INPUT_THINT: 169d0dfae6eSj_mayer /* Level sensitive - active high */ 170af96d2e6SCédric Le Goater trace_ppc_irq_set_state("SMI IRQ", level); 1717058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); 172d0dfae6eSj_mayer break; 173d0dfae6eSj_mayer case PPC970_INPUT_MCP: 174d0dfae6eSj_mayer /* Negative edge sensitive */ 175d0dfae6eSj_mayer /* XXX: TODO: actual reaction may depends on HID0 status 176d0dfae6eSj_mayer * 603/604/740/750: check HID0[EMCP] 177d0dfae6eSj_mayer */ 178d0dfae6eSj_mayer if (cur_level == 1 && level == 0) { 179af96d2e6SCédric Le Goater trace_ppc_irq_set_state("machine check", 1); 1807058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 181d0dfae6eSj_mayer } 182d0dfae6eSj_mayer break; 183d0dfae6eSj_mayer case PPC970_INPUT_CKSTP: 184d0dfae6eSj_mayer /* Level sensitive - active low */ 185d0dfae6eSj_mayer /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 186d0dfae6eSj_mayer if (level) { 187af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 188259186a7SAndreas Färber cs->halted = 1; 189d0dfae6eSj_mayer } else { 190af96d2e6SCédric Le Goater trace_ppc_irq_cpu("restart"); 191259186a7SAndreas Färber cs->halted = 0; 192259186a7SAndreas Färber qemu_cpu_kick(cs); 193d0dfae6eSj_mayer } 194d0dfae6eSj_mayer break; 195d0dfae6eSj_mayer case PPC970_INPUT_HRESET: 196d0dfae6eSj_mayer /* Level sensitive - active low */ 197d0dfae6eSj_mayer if (level) { 198c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 199d0dfae6eSj_mayer } 200d0dfae6eSj_mayer break; 201d0dfae6eSj_mayer case PPC970_INPUT_SRESET: 202af96d2e6SCédric Le Goater trace_ppc_irq_set_state("RESET IRQ", level); 2037058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 204d0dfae6eSj_mayer break; 205d0dfae6eSj_mayer case PPC970_INPUT_TBEN: 206af96d2e6SCédric Le Goater trace_ppc_irq_set_state("TBEN IRQ", level); 207d0dfae6eSj_mayer /* XXX: TODO */ 208d0dfae6eSj_mayer break; 209d0dfae6eSj_mayer default: 2107279810bSCédric Le Goater g_assert_not_reached(); 211d0dfae6eSj_mayer } 212d0dfae6eSj_mayer if (level) 213d0dfae6eSj_mayer env->irq_input_state |= 1 << pin; 214d0dfae6eSj_mayer else 215d0dfae6eSj_mayer env->irq_input_state &= ~(1 << pin); 216d0dfae6eSj_mayer } 217d0dfae6eSj_mayer } 218d0dfae6eSj_mayer 219aa5a9e24SPaolo Bonzini void ppc970_irq_init(PowerPCCPU *cpu) 220d0dfae6eSj_mayer { 2219fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc970_set_irq, PPC970_INPUT_NB); 222d0dfae6eSj_mayer } 2239d52e907SDavid Gibson 2249d52e907SDavid Gibson /* POWER7 internal IRQ controller */ 2259d52e907SDavid Gibson static void power7_set_irq(void *opaque, int pin, int level) 2269d52e907SDavid Gibson { 227a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 2289d52e907SDavid Gibson 229af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 2309d52e907SDavid Gibson 2319d52e907SDavid Gibson switch (pin) { 2329d52e907SDavid Gibson case POWER7_INPUT_INT: 2339d52e907SDavid Gibson /* Level sensitive - active high */ 234af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 2357058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 2369d52e907SDavid Gibson break; 2379d52e907SDavid Gibson default: 2387279810bSCédric Le Goater g_assert_not_reached(); 2399d52e907SDavid Gibson } 2409d52e907SDavid Gibson } 2419d52e907SDavid Gibson 242aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu) 2439d52e907SDavid Gibson { 2449fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), power7_set_irq, POWER7_INPUT_NB); 2459d52e907SDavid Gibson } 24667afe775SBenjamin Herrenschmidt 24767afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */ 24867afe775SBenjamin Herrenschmidt static void power9_set_irq(void *opaque, int pin, int level) 24967afe775SBenjamin Herrenschmidt { 25067afe775SBenjamin Herrenschmidt PowerPCCPU *cpu = opaque; 25167afe775SBenjamin Herrenschmidt 252af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 25367afe775SBenjamin Herrenschmidt 25467afe775SBenjamin Herrenschmidt switch (pin) { 25567afe775SBenjamin Herrenschmidt case POWER9_INPUT_INT: 25667afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 257af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 25867afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 25967afe775SBenjamin Herrenschmidt break; 26067afe775SBenjamin Herrenschmidt case POWER9_INPUT_HINT: 26167afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 262af96d2e6SCédric Le Goater trace_ppc_irq_set_state("HV external IRQ", level); 26367afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level); 26467afe775SBenjamin Herrenschmidt break; 26567afe775SBenjamin Herrenschmidt default: 2667279810bSCédric Le Goater g_assert_not_reached(); 267af96d2e6SCédric Le Goater return; 26867afe775SBenjamin Herrenschmidt } 26967afe775SBenjamin Herrenschmidt } 27067afe775SBenjamin Herrenschmidt 27167afe775SBenjamin Herrenschmidt void ppcPOWER9_irq_init(PowerPCCPU *cpu) 27267afe775SBenjamin Herrenschmidt { 2739fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), power9_set_irq, POWER9_INPUT_NB); 27467afe775SBenjamin Herrenschmidt } 27500af685fSj_mayer #endif /* defined(TARGET_PPC64) */ 276d0dfae6eSj_mayer 27752144b69SThomas Huth void ppc40x_core_reset(PowerPCCPU *cpu) 27852144b69SThomas Huth { 27952144b69SThomas Huth CPUPPCState *env = &cpu->env; 28052144b69SThomas Huth target_ulong dbsr; 28152144b69SThomas Huth 28252144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n"); 28352144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 28452144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 28552144b69SThomas Huth dbsr &= ~0x00000300; 28652144b69SThomas Huth dbsr |= 0x00000100; 28752144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 28852144b69SThomas Huth } 28952144b69SThomas Huth 29052144b69SThomas Huth void ppc40x_chip_reset(PowerPCCPU *cpu) 29152144b69SThomas Huth { 29252144b69SThomas Huth CPUPPCState *env = &cpu->env; 29352144b69SThomas Huth target_ulong dbsr; 29452144b69SThomas Huth 29552144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n"); 29652144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 29752144b69SThomas Huth /* XXX: TODO reset all internal peripherals */ 29852144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 29952144b69SThomas Huth dbsr &= ~0x00000300; 30052144b69SThomas Huth dbsr |= 0x00000200; 30152144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 30252144b69SThomas Huth } 30352144b69SThomas Huth 30452144b69SThomas Huth void ppc40x_system_reset(PowerPCCPU *cpu) 30552144b69SThomas Huth { 30652144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n"); 30752144b69SThomas Huth qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 30852144b69SThomas Huth } 30952144b69SThomas Huth 31052144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val) 31152144b69SThomas Huth { 312db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 31352144b69SThomas Huth 3145ae3d2e8SThomas Huth qemu_mutex_lock_iothread(); 3155ae3d2e8SThomas Huth 31652144b69SThomas Huth switch ((val >> 28) & 0x3) { 31752144b69SThomas Huth case 0x0: 31852144b69SThomas Huth /* No action */ 31952144b69SThomas Huth break; 32052144b69SThomas Huth case 0x1: 32152144b69SThomas Huth /* Core reset */ 32252144b69SThomas Huth ppc40x_core_reset(cpu); 32352144b69SThomas Huth break; 32452144b69SThomas Huth case 0x2: 32552144b69SThomas Huth /* Chip reset */ 32652144b69SThomas Huth ppc40x_chip_reset(cpu); 32752144b69SThomas Huth break; 32852144b69SThomas Huth case 0x3: 32952144b69SThomas Huth /* System reset */ 33052144b69SThomas Huth ppc40x_system_reset(cpu); 33152144b69SThomas Huth break; 33252144b69SThomas Huth } 3335ae3d2e8SThomas Huth 3345ae3d2e8SThomas Huth qemu_mutex_unlock_iothread(); 33552144b69SThomas Huth } 33652144b69SThomas Huth 3374e290a0bSj_mayer /* PowerPC 40x internal IRQ controller */ 3384e290a0bSj_mayer static void ppc40x_set_irq(void *opaque, int pin, int level) 33924be5ae3Sj_mayer { 340a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 341a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 34224be5ae3Sj_mayer int cur_level; 34324be5ae3Sj_mayer 344af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 345af96d2e6SCédric Le Goater 34624be5ae3Sj_mayer cur_level = (env->irq_input_state >> pin) & 1; 34724be5ae3Sj_mayer /* Don't generate spurious events */ 34824be5ae3Sj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 349259186a7SAndreas Färber CPUState *cs = CPU(cpu); 350259186a7SAndreas Färber 35124be5ae3Sj_mayer switch (pin) { 3524e290a0bSj_mayer case PPC40x_INPUT_RESET_SYS: 3538ecc7913Sj_mayer if (level) { 354af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 355f3273ba6SAndreas Färber ppc40x_system_reset(cpu); 3568ecc7913Sj_mayer } 3578ecc7913Sj_mayer break; 3584e290a0bSj_mayer case PPC40x_INPUT_RESET_CHIP: 3598ecc7913Sj_mayer if (level) { 360af96d2e6SCédric Le Goater trace_ppc_irq_reset("chip"); 361f3273ba6SAndreas Färber ppc40x_chip_reset(cpu); 3628ecc7913Sj_mayer } 3638ecc7913Sj_mayer break; 3644e290a0bSj_mayer case PPC40x_INPUT_RESET_CORE: 36524be5ae3Sj_mayer /* XXX: TODO: update DBSR[MRR] */ 36624be5ae3Sj_mayer if (level) { 367af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 368f3273ba6SAndreas Färber ppc40x_core_reset(cpu); 36924be5ae3Sj_mayer } 37024be5ae3Sj_mayer break; 3714e290a0bSj_mayer case PPC40x_INPUT_CINT: 37224be5ae3Sj_mayer /* Level sensitive - active high */ 373af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 3747058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 37524be5ae3Sj_mayer break; 3764e290a0bSj_mayer case PPC40x_INPUT_INT: 37724be5ae3Sj_mayer /* Level sensitive - active high */ 378af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 3797058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 38024be5ae3Sj_mayer break; 3814e290a0bSj_mayer case PPC40x_INPUT_HALT: 38224be5ae3Sj_mayer /* Level sensitive - active low */ 38324be5ae3Sj_mayer if (level) { 384af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 385259186a7SAndreas Färber cs->halted = 1; 38624be5ae3Sj_mayer } else { 387af96d2e6SCédric Le Goater trace_ppc_irq_cpu("restart"); 388259186a7SAndreas Färber cs->halted = 0; 389259186a7SAndreas Färber qemu_cpu_kick(cs); 39024be5ae3Sj_mayer } 39124be5ae3Sj_mayer break; 3924e290a0bSj_mayer case PPC40x_INPUT_DEBUG: 39324be5ae3Sj_mayer /* Level sensitive - active high */ 394af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 3957058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 39624be5ae3Sj_mayer break; 39724be5ae3Sj_mayer default: 3987279810bSCédric Le Goater g_assert_not_reached(); 39924be5ae3Sj_mayer } 40024be5ae3Sj_mayer if (level) 40124be5ae3Sj_mayer env->irq_input_state |= 1 << pin; 40224be5ae3Sj_mayer else 40324be5ae3Sj_mayer env->irq_input_state &= ~(1 << pin); 40424be5ae3Sj_mayer } 40524be5ae3Sj_mayer } 40624be5ae3Sj_mayer 407aa5a9e24SPaolo Bonzini void ppc40x_irq_init(PowerPCCPU *cpu) 40824be5ae3Sj_mayer { 40947b60fc6SCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc40x_set_irq, PPC40x_INPUT_NB); 41024be5ae3Sj_mayer } 41124be5ae3Sj_mayer 4129fdc60bfSaurel32 /* PowerPC E500 internal IRQ controller */ 4139fdc60bfSaurel32 static void ppce500_set_irq(void *opaque, int pin, int level) 4149fdc60bfSaurel32 { 415a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 416a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 4179fdc60bfSaurel32 int cur_level; 4189fdc60bfSaurel32 419af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 420af96d2e6SCédric Le Goater 4219fdc60bfSaurel32 cur_level = (env->irq_input_state >> pin) & 1; 4229fdc60bfSaurel32 /* Don't generate spurious events */ 4239fdc60bfSaurel32 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 4249fdc60bfSaurel32 switch (pin) { 4259fdc60bfSaurel32 case PPCE500_INPUT_MCK: 4269fdc60bfSaurel32 if (level) { 427af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 428cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 4299fdc60bfSaurel32 } 4309fdc60bfSaurel32 break; 4319fdc60bfSaurel32 case PPCE500_INPUT_RESET_CORE: 4329fdc60bfSaurel32 if (level) { 433af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 4347058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); 4359fdc60bfSaurel32 } 4369fdc60bfSaurel32 break; 4379fdc60bfSaurel32 case PPCE500_INPUT_CINT: 4389fdc60bfSaurel32 /* Level sensitive - active high */ 439af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 4407058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 4419fdc60bfSaurel32 break; 4429fdc60bfSaurel32 case PPCE500_INPUT_INT: 4439fdc60bfSaurel32 /* Level sensitive - active high */ 444af96d2e6SCédric Le Goater trace_ppc_irq_set_state("core IRQ", level); 4457058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 4469fdc60bfSaurel32 break; 4479fdc60bfSaurel32 case PPCE500_INPUT_DEBUG: 4489fdc60bfSaurel32 /* Level sensitive - active high */ 449af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 4507058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 4519fdc60bfSaurel32 break; 4529fdc60bfSaurel32 default: 4537279810bSCédric Le Goater g_assert_not_reached(); 4549fdc60bfSaurel32 } 4559fdc60bfSaurel32 if (level) 4569fdc60bfSaurel32 env->irq_input_state |= 1 << pin; 4579fdc60bfSaurel32 else 4589fdc60bfSaurel32 env->irq_input_state &= ~(1 << pin); 4599fdc60bfSaurel32 } 4609fdc60bfSaurel32 } 4619fdc60bfSaurel32 462aa5a9e24SPaolo Bonzini void ppce500_irq_init(PowerPCCPU *cpu) 4639fdc60bfSaurel32 { 4645e66cd0cSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppce500_set_irq, PPCE500_INPUT_NB); 4659fdc60bfSaurel32 } 466e49798b1SAlexander Graf 467e49798b1SAlexander Graf /* Enable or Disable the E500 EPR capability */ 468e49798b1SAlexander Graf void ppce500_set_mpic_proxy(bool enabled) 469e49798b1SAlexander Graf { 470182735efSAndreas Färber CPUState *cs; 471e49798b1SAlexander Graf 472bdc44640SAndreas Färber CPU_FOREACH(cs) { 473182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 4745b95b8b9SAlexander Graf 475182735efSAndreas Färber cpu->env.mpic_proxy = enabled; 4765b95b8b9SAlexander Graf if (kvm_enabled()) { 477182735efSAndreas Färber kvmppc_set_mpic_proxy(cpu, enabled); 4785b95b8b9SAlexander Graf } 479e49798b1SAlexander Graf } 480e49798b1SAlexander Graf } 481e49798b1SAlexander Graf 4829fddaa0cSbellard /*****************************************************************************/ 483e9df014cSj_mayer /* PowerPC time base and decrementer emulation */ 4849fddaa0cSbellard 485ddd1055bSFabien Chouteau uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) 4869fddaa0cSbellard { 4879fddaa0cSbellard /* TB time in tb periods */ 48873bcb24dSRutuja Shah return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset; 4899fddaa0cSbellard } 4909fddaa0cSbellard 491e2684c0bSAndreas Färber uint64_t cpu_ppc_load_tbl (CPUPPCState *env) 4929fddaa0cSbellard { 493c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 4949fddaa0cSbellard uint64_t tb; 4959fddaa0cSbellard 49690dc8812SScott Wood if (kvm_enabled()) { 49790dc8812SScott Wood return env->spr[SPR_TBL]; 49890dc8812SScott Wood } 49990dc8812SScott Wood 500bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 501af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 5029fddaa0cSbellard 503e3ea6529SAlexander Graf return tb; 5049fddaa0cSbellard } 5059fddaa0cSbellard 506e2684c0bSAndreas Färber static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) 5079fddaa0cSbellard { 508c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 5099fddaa0cSbellard uint64_t tb; 5109fddaa0cSbellard 511bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 512af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 51376a66253Sj_mayer 5149fddaa0cSbellard return tb >> 32; 5159fddaa0cSbellard } 5169fddaa0cSbellard 517e2684c0bSAndreas Färber uint32_t cpu_ppc_load_tbu (CPUPPCState *env) 5188a84de23Sj_mayer { 51990dc8812SScott Wood if (kvm_enabled()) { 52090dc8812SScott Wood return env->spr[SPR_TBU]; 52190dc8812SScott Wood } 52290dc8812SScott Wood 5238a84de23Sj_mayer return _cpu_ppc_load_tbu(env); 5248a84de23Sj_mayer } 5258a84de23Sj_mayer 526c227f099SAnthony Liguori static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, 527636aa200SBlue Swirl int64_t *tb_offsetp, uint64_t value) 5289fddaa0cSbellard { 52973bcb24dSRutuja Shah *tb_offsetp = value - 53073bcb24dSRutuja Shah muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND); 53173bcb24dSRutuja Shah 532af96d2e6SCédric Le Goater trace_ppc_tb_store(value, *tb_offsetp); 533a496775fSj_mayer } 5349fddaa0cSbellard 535e2684c0bSAndreas Färber void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) 5369fddaa0cSbellard { 537c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 538*2ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 539a062e36cSj_mayer uint64_t tb; 5409fddaa0cSbellard 541*2ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset); 542a062e36cSj_mayer tb &= 0xFFFFFFFF00000000ULL; 543*2ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb | (uint64_t)value); 544a062e36cSj_mayer } 545a062e36cSj_mayer 546e2684c0bSAndreas Färber static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) 547a062e36cSj_mayer { 548c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 549*2ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 550a062e36cSj_mayer uint64_t tb; 551a062e36cSj_mayer 552*2ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset); 553a062e36cSj_mayer tb &= 0x00000000FFFFFFFFULL; 554*2ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, 555*2ad2e113SNicholas Piggin ((uint64_t)value << 32) | tb); 556a062e36cSj_mayer } 557a062e36cSj_mayer 558e2684c0bSAndreas Färber void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value) 5598a84de23Sj_mayer { 5608a84de23Sj_mayer _cpu_ppc_store_tbu(env, value); 5618a84de23Sj_mayer } 5628a84de23Sj_mayer 563e2684c0bSAndreas Färber uint64_t cpu_ppc_load_atbl (CPUPPCState *env) 564a062e36cSj_mayer { 565c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 566a062e36cSj_mayer uint64_t tb; 567a062e36cSj_mayer 568bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 569af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 570a062e36cSj_mayer 571b711de95SAurelien Jarno return tb; 572a062e36cSj_mayer } 573a062e36cSj_mayer 574e2684c0bSAndreas Färber uint32_t cpu_ppc_load_atbu (CPUPPCState *env) 575a062e36cSj_mayer { 576c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 577a062e36cSj_mayer uint64_t tb; 578a062e36cSj_mayer 579bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 580af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 581a062e36cSj_mayer 582a062e36cSj_mayer return tb >> 32; 583a062e36cSj_mayer } 584a062e36cSj_mayer 585e2684c0bSAndreas Färber void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) 586a062e36cSj_mayer { 587c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 588*2ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 589a062e36cSj_mayer uint64_t tb; 590a062e36cSj_mayer 591*2ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset); 592a062e36cSj_mayer tb &= 0xFFFFFFFF00000000ULL; 593*2ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset, tb | (uint64_t)value); 594a062e36cSj_mayer } 595a062e36cSj_mayer 596e2684c0bSAndreas Färber void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) 597a062e36cSj_mayer { 598c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 599*2ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 600a062e36cSj_mayer uint64_t tb; 601a062e36cSj_mayer 602*2ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset); 603a062e36cSj_mayer tb &= 0x00000000FFFFFFFFULL; 604*2ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset, 605*2ad2e113SNicholas Piggin ((uint64_t)value << 32) | tb); 606dbdd2506Sj_mayer } 607dbdd2506Sj_mayer 6085d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env) 6095d62725bSSuraj Jitindar Singh { 6105d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6115d62725bSSuraj Jitindar Singh 6125d62725bSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6135d62725bSSuraj Jitindar Singh tb_env->vtb_offset); 6145d62725bSSuraj Jitindar Singh } 6155d62725bSSuraj Jitindar Singh 6165d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value) 6175d62725bSSuraj Jitindar Singh { 6185d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6195d62725bSSuraj Jitindar Singh 6205d62725bSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6215d62725bSSuraj Jitindar Singh &tb_env->vtb_offset, value); 6225d62725bSSuraj Jitindar Singh } 6235d62725bSSuraj Jitindar Singh 624f0ec31b1SSuraj Jitindar Singh void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value) 625f0ec31b1SSuraj Jitindar Singh { 626f0ec31b1SSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 627*2ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 628f0ec31b1SSuraj Jitindar Singh uint64_t tb; 629f0ec31b1SSuraj Jitindar Singh 630*2ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset); 631f0ec31b1SSuraj Jitindar Singh tb &= 0xFFFFFFUL; 632f0ec31b1SSuraj Jitindar Singh tb |= (value & ~0xFFFFFFUL); 633*2ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb); 634f0ec31b1SSuraj Jitindar Singh } 635f0ec31b1SSuraj Jitindar Singh 636e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env) 637dbdd2506Sj_mayer { 638c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 639dbdd2506Sj_mayer uint64_t tb, atb, vmclk; 640dbdd2506Sj_mayer 641dbdd2506Sj_mayer /* If the time base is already frozen, do nothing */ 642dbdd2506Sj_mayer if (tb_env->tb_freq != 0) { 643bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 644dbdd2506Sj_mayer /* Get the time base */ 645dbdd2506Sj_mayer tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); 646dbdd2506Sj_mayer /* Get the alternate time base */ 647dbdd2506Sj_mayer atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); 648dbdd2506Sj_mayer /* Store the time base value (ie compute the current offset) */ 649dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 650dbdd2506Sj_mayer /* Store the alternate time base value (compute the current offset) */ 651dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 652dbdd2506Sj_mayer /* Set the time base frequency to zero */ 653dbdd2506Sj_mayer tb_env->tb_freq = 0; 654dbdd2506Sj_mayer /* Now, the time bases are frozen to tb_offset / atb_offset value */ 655dbdd2506Sj_mayer } 656dbdd2506Sj_mayer } 657dbdd2506Sj_mayer 658e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env) 659dbdd2506Sj_mayer { 660c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 661dbdd2506Sj_mayer uint64_t tb, atb, vmclk; 662dbdd2506Sj_mayer 663dbdd2506Sj_mayer /* If the time base is not frozen, do nothing */ 664dbdd2506Sj_mayer if (tb_env->tb_freq == 0) { 665bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 666dbdd2506Sj_mayer /* Get the time base from tb_offset */ 667dbdd2506Sj_mayer tb = tb_env->tb_offset; 668dbdd2506Sj_mayer /* Get the alternate time base from atb_offset */ 669dbdd2506Sj_mayer atb = tb_env->atb_offset; 670dbdd2506Sj_mayer /* Restore the tb frequency from the decrementer frequency */ 671dbdd2506Sj_mayer tb_env->tb_freq = tb_env->decr_freq; 672dbdd2506Sj_mayer /* Store the time base value */ 673dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 674dbdd2506Sj_mayer /* Store the alternate time base value */ 675dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 676dbdd2506Sj_mayer } 6779fddaa0cSbellard } 6789fddaa0cSbellard 679e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env) 680e81a982aSAlexander Graf { 681e81a982aSAlexander Graf ppc_tb_t *tb_env = env->tb_env; 682e81a982aSAlexander Graf int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL; 683e81a982aSAlexander Graf return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED); 684e81a982aSAlexander Graf } 685e81a982aSAlexander Graf 686a8dafa52SSuraj Jitindar Singh static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) 6879fddaa0cSbellard { 688c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 689a8dafa52SSuraj Jitindar Singh int64_t decr, diff; 6909fddaa0cSbellard 691bc72ad67SAlex Bligh diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 692ddd1055bSFabien Chouteau if (diff >= 0) { 69373bcb24dSRutuja Shah decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 694ddd1055bSFabien Chouteau } else if (tb_env->flags & PPC_TIMER_BOOKE) { 695ddd1055bSFabien Chouteau decr = 0; 696ddd1055bSFabien Chouteau } else { 69773bcb24dSRutuja Shah decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 698ddd1055bSFabien Chouteau } 699af96d2e6SCédric Le Goater trace_ppc_decr_load(decr); 70076a66253Sj_mayer 7019fddaa0cSbellard return decr; 7029fddaa0cSbellard } 7039fddaa0cSbellard 704a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_decr(CPUPPCState *env) 70558a7d328Sj_mayer { 706c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 707a8dafa52SSuraj Jitindar Singh uint64_t decr; 70858a7d328Sj_mayer 70990dc8812SScott Wood if (kvm_enabled()) { 71090dc8812SScott Wood return env->spr[SPR_DECR]; 71190dc8812SScott Wood } 71290dc8812SScott Wood 713a8dafa52SSuraj Jitindar Singh decr = _cpu_ppc_load_decr(env, tb_env->decr_next); 714a8dafa52SSuraj Jitindar Singh 715a8dafa52SSuraj Jitindar Singh /* 716a8dafa52SSuraj Jitindar Singh * If large decrementer is enabled then the decrementer is signed extened 717a8dafa52SSuraj Jitindar Singh * to 64 bits, otherwise it is a 32 bit value. 718a8dafa52SSuraj Jitindar Singh */ 719a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 720a8dafa52SSuraj Jitindar Singh return decr; 721a8dafa52SSuraj Jitindar Singh } 722a8dafa52SSuraj Jitindar Singh return (uint32_t) decr; 72358a7d328Sj_mayer } 72458a7d328Sj_mayer 725a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_hdecr(CPUPPCState *env) 72658a7d328Sj_mayer { 727db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 728a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 729c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 730a8dafa52SSuraj Jitindar Singh uint64_t hdecr; 73158a7d328Sj_mayer 732a8dafa52SSuraj Jitindar Singh hdecr = _cpu_ppc_load_decr(env, tb_env->hdecr_next); 733a8dafa52SSuraj Jitindar Singh 734a8dafa52SSuraj Jitindar Singh /* 735a8dafa52SSuraj Jitindar Singh * If we have a large decrementer (POWER9 or later) then hdecr is sign 736a8dafa52SSuraj Jitindar Singh * extended to 64 bits, otherwise it is 32 bits. 737a8dafa52SSuraj Jitindar Singh */ 738a8dafa52SSuraj Jitindar Singh if (pcc->lrg_decr_bits > 32) { 739a8dafa52SSuraj Jitindar Singh return hdecr; 740a8dafa52SSuraj Jitindar Singh } 741a8dafa52SSuraj Jitindar Singh return (uint32_t) hdecr; 74258a7d328Sj_mayer } 74358a7d328Sj_mayer 744e2684c0bSAndreas Färber uint64_t cpu_ppc_load_purr (CPUPPCState *env) 74558a7d328Sj_mayer { 746c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 74758a7d328Sj_mayer 7485cc7e69fSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 7495cc7e69fSSuraj Jitindar Singh tb_env->purr_offset); 75058a7d328Sj_mayer } 75158a7d328Sj_mayer 7529fddaa0cSbellard /* When decrementer expires, 7539fddaa0cSbellard * all we need to do is generate or queue a CPU exception 7549fddaa0cSbellard */ 7557e0a9247SAndreas Färber static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) 7569fddaa0cSbellard { 7579fddaa0cSbellard /* Raise it */ 758af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise"); 7597058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); 7609fddaa0cSbellard } 7619fddaa0cSbellard 762e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu) 763e81a982aSAlexander Graf { 764e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0); 765e81a982aSAlexander Graf } 766e81a982aSAlexander Graf 7677e0a9247SAndreas Färber static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) 76858a7d328Sj_mayer { 7694b236b62SBenjamin Herrenschmidt CPUPPCState *env = &cpu->env; 7704b236b62SBenjamin Herrenschmidt 77158a7d328Sj_mayer /* Raise it */ 772af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise HV"); 7734b236b62SBenjamin Herrenschmidt 7744b236b62SBenjamin Herrenschmidt /* The architecture specifies that we don't deliver HDEC 7754b236b62SBenjamin Herrenschmidt * interrupts in a PM state. Not only they don't cause a 7764b236b62SBenjamin Herrenschmidt * wakeup but they also get effectively discarded. 7774b236b62SBenjamin Herrenschmidt */ 7781e7fd61dSBenjamin Herrenschmidt if (!env->resume_as_sreset) { 7797058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); 78058a7d328Sj_mayer } 7814b236b62SBenjamin Herrenschmidt } 78258a7d328Sj_mayer 783e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) 784e81a982aSAlexander Graf { 785e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); 786e81a982aSAlexander Graf } 787e81a982aSAlexander Graf 7887e0a9247SAndreas Färber static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, 7891246b259SStefan Weil QEMUTimer *timer, 790e81a982aSAlexander Graf void (*raise_excp)(void *), 791e81a982aSAlexander Graf void (*lower_excp)(PowerPCCPU *), 792a5ff7875SNicholas Piggin uint32_t flags, target_ulong decr, 793a5ff7875SNicholas Piggin target_ulong value, int nr_bits) 7949fddaa0cSbellard { 7957e0a9247SAndreas Färber CPUPPCState *env = &cpu->env; 796c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 7979fddaa0cSbellard uint64_t now, next; 7984d9b8ef9SCédric Le Goater int64_t signed_value; 7994d9b8ef9SCédric Le Goater int64_t signed_decr; 8009fddaa0cSbellard 801a8dafa52SSuraj Jitindar Singh /* Truncate value to decr_width and sign extend for simplicity */ 80209d2db9fSNicholas Piggin value = extract64(value, 0, nr_bits); 80309d2db9fSNicholas Piggin decr = extract64(decr, 0, nr_bits); 8044d9b8ef9SCédric Le Goater signed_value = sextract64(value, 0, nr_bits); 8054d9b8ef9SCédric Le Goater signed_decr = sextract64(decr, 0, nr_bits); 806a8dafa52SSuraj Jitindar Singh 807af96d2e6SCédric Le Goater trace_ppc_decr_store(nr_bits, decr, value); 80855f7d4b0SDavid Gibson 80955f7d4b0SDavid Gibson if (kvm_enabled()) { 81055f7d4b0SDavid Gibson /* KVM handles decrementer exceptions, we don't need our own timer */ 81155f7d4b0SDavid Gibson return; 81255f7d4b0SDavid Gibson } 81355f7d4b0SDavid Gibson 814e81a982aSAlexander Graf /* 81517dd1354SNicholas Piggin * Going from 1 -> 0 or 0 -> -1 is the event to generate a DEC interrupt. 816e81a982aSAlexander Graf * 817e81a982aSAlexander Graf * On MSB level based DEC implementations the MSB always means the interrupt 818e81a982aSAlexander Graf * is pending, so raise it on those. 819e81a982aSAlexander Graf * 820e81a982aSAlexander Graf * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers 821e81a982aSAlexander Graf * an edge interrupt, so raise it here too. 822e81a982aSAlexander Graf */ 823a5ff7875SNicholas Piggin if (((flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) || 824a5ff7875SNicholas Piggin ((flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0 8254d9b8ef9SCédric Le Goater && signed_decr >= 0)) { 826e81a982aSAlexander Graf (*raise_excp)(cpu); 827e81a982aSAlexander Graf return; 828e81a982aSAlexander Graf } 829e81a982aSAlexander Graf 830e81a982aSAlexander Graf /* On MSB level based systems a 0 for the MSB stops interrupt delivery */ 831a5ff7875SNicholas Piggin if (signed_value >= 0 && (flags & PPC_DECR_UNDERFLOW_LEVEL)) { 832e81a982aSAlexander Graf (*lower_excp)(cpu); 833e81a982aSAlexander Graf } 834e81a982aSAlexander Graf 835e81a982aSAlexander Graf /* Calculate the next timer event */ 836bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 83773bcb24dSRutuja Shah next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 83858a7d328Sj_mayer *nextp = next; 839e81a982aSAlexander Graf 8409fddaa0cSbellard /* Adjust timer */ 841bc72ad67SAlex Bligh timer_mod(timer, next); 842ddd1055bSFabien Chouteau } 84358a7d328Sj_mayer 844a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr, 845a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 84658a7d328Sj_mayer { 8477e0a9247SAndreas Färber ppc_tb_t *tb_env = cpu->env.tb_env; 84858a7d328Sj_mayer 8497e0a9247SAndreas Färber __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, 850a5ff7875SNicholas Piggin tb_env->decr_timer->cb, &cpu_ppc_decr_lower, 851a5ff7875SNicholas Piggin tb_env->flags, decr, value, nr_bits); 8529fddaa0cSbellard } 8539fddaa0cSbellard 854a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value) 8559fddaa0cSbellard { 856db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 857a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 858a8dafa52SSuraj Jitindar Singh int nr_bits = 32; 8597e0a9247SAndreas Färber 860a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 861a8dafa52SSuraj Jitindar Singh nr_bits = pcc->lrg_decr_bits; 862a8dafa52SSuraj Jitindar Singh } 863a8dafa52SSuraj Jitindar Singh 864a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, nr_bits); 8659fddaa0cSbellard } 8669fddaa0cSbellard 8679fddaa0cSbellard static void cpu_ppc_decr_cb(void *opaque) 8689fddaa0cSbellard { 86950c680f0SAndreas Färber PowerPCCPU *cpu = opaque; 8707e0a9247SAndreas Färber 871e81a982aSAlexander Graf cpu_ppc_decr_excp(cpu); 8729fddaa0cSbellard } 8739fddaa0cSbellard 874a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr, 875a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 87658a7d328Sj_mayer { 8777e0a9247SAndreas Färber ppc_tb_t *tb_env = cpu->env.tb_env; 87858a7d328Sj_mayer 879b172c56aSj_mayer if (tb_env->hdecr_timer != NULL) { 880a5ff7875SNicholas Piggin /* HDECR (Book3S 64bit) is edge-based, not level like DECR */ 8817e0a9247SAndreas Färber __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, 882e81a982aSAlexander Graf tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower, 883a5ff7875SNicholas Piggin PPC_DECR_UNDERFLOW_TRIGGERED, 884a8dafa52SSuraj Jitindar Singh hdecr, value, nr_bits); 88558a7d328Sj_mayer } 886b172c56aSj_mayer } 88758a7d328Sj_mayer 888a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value) 88958a7d328Sj_mayer { 890db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 891a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 8927e0a9247SAndreas Färber 893a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 894a8dafa52SSuraj Jitindar Singh pcc->lrg_decr_bits); 89558a7d328Sj_mayer } 89658a7d328Sj_mayer 89758a7d328Sj_mayer static void cpu_ppc_hdecr_cb(void *opaque) 89858a7d328Sj_mayer { 89950c680f0SAndreas Färber PowerPCCPU *cpu = opaque; 9007e0a9247SAndreas Färber 901e81a982aSAlexander Graf cpu_ppc_hdecr_excp(cpu); 90258a7d328Sj_mayer } 90358a7d328Sj_mayer 9045cc7e69fSSuraj Jitindar Singh void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) 90558a7d328Sj_mayer { 9065cc7e69fSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 90758a7d328Sj_mayer 9085cc7e69fSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 9095cc7e69fSSuraj Jitindar Singh &tb_env->purr_offset, value); 91058a7d328Sj_mayer } 91158a7d328Sj_mayer 9128ecc7913Sj_mayer static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) 9138ecc7913Sj_mayer { 914e2684c0bSAndreas Färber CPUPPCState *env = opaque; 915db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 916c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 9178ecc7913Sj_mayer 9188ecc7913Sj_mayer tb_env->tb_freq = freq; 919dbdd2506Sj_mayer tb_env->decr_freq = freq; 9208ecc7913Sj_mayer /* There is a bug in Linux 2.4 kernels: 9218ecc7913Sj_mayer * if a decrementer exception is pending when it enables msr_ee at startup, 9228ecc7913Sj_mayer * it's not ready to handle it... 9238ecc7913Sj_mayer */ 924a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 925a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 9265cc7e69fSSuraj Jitindar Singh cpu_ppc_store_purr(env, 0x0000000000000000ULL); 9278ecc7913Sj_mayer } 9288ecc7913Sj_mayer 92942043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb) 93098a8b524SAlexey Kardashevskiy { 9314a7428c5SChristopher Covington uint64_t ticks = cpu_get_host_ticks(); 93298a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 93398a8b524SAlexey Kardashevskiy 93498a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 93598a8b524SAlexey Kardashevskiy error_report("No timebase object"); 93698a8b524SAlexey Kardashevskiy return; 93798a8b524SAlexey Kardashevskiy } 93898a8b524SAlexey Kardashevskiy 93942043e4fSLaurent Vivier /* not used anymore, we keep it for compatibility */ 94077bad151SPaolo Bonzini tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); 94198a8b524SAlexey Kardashevskiy /* 94242043e4fSLaurent Vivier * tb_offset is only expected to be changed by QEMU so 94398a8b524SAlexey Kardashevskiy * there is no need to update it from KVM here 94498a8b524SAlexey Kardashevskiy */ 94598a8b524SAlexey Kardashevskiy tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; 946d14f3397SMaxiwell S. Garcia 947711dfb24SGreg Kurz tb->runstate_paused = 948711dfb24SGreg Kurz runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM); 94998a8b524SAlexey Kardashevskiy } 95098a8b524SAlexey Kardashevskiy 95142043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb) 95298a8b524SAlexey Kardashevskiy { 95398a8b524SAlexey Kardashevskiy CPUState *cpu; 95498a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 95542043e4fSLaurent Vivier int64_t tb_off_adj, tb_off; 95698a8b524SAlexey Kardashevskiy unsigned long freq; 95798a8b524SAlexey Kardashevskiy 95898a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 95998a8b524SAlexey Kardashevskiy error_report("No timebase object"); 96042043e4fSLaurent Vivier return; 96198a8b524SAlexey Kardashevskiy } 96298a8b524SAlexey Kardashevskiy 96398a8b524SAlexey Kardashevskiy freq = first_ppc_cpu->env.tb_env->tb_freq; 96498a8b524SAlexey Kardashevskiy 96542043e4fSLaurent Vivier tb_off_adj = tb->guest_timebase - cpu_get_host_ticks(); 96698a8b524SAlexey Kardashevskiy 96798a8b524SAlexey Kardashevskiy tb_off = first_ppc_cpu->env.tb_env->tb_offset; 96898a8b524SAlexey Kardashevskiy trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off, 96998a8b524SAlexey Kardashevskiy (tb_off_adj - tb_off) / freq); 97098a8b524SAlexey Kardashevskiy 97198a8b524SAlexey Kardashevskiy /* Set new offset to all CPUs */ 97298a8b524SAlexey Kardashevskiy CPU_FOREACH(cpu) { 97398a8b524SAlexey Kardashevskiy PowerPCCPU *pcpu = POWERPC_CPU(cpu); 97498a8b524SAlexey Kardashevskiy pcpu->env.tb_env->tb_offset = tb_off_adj; 9759723295aSGreg Kurz kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset); 97642043e4fSLaurent Vivier } 97798a8b524SAlexey Kardashevskiy } 97898a8b524SAlexey Kardashevskiy 979538f0497SPhilippe Mathieu-Daudé void cpu_ppc_clock_vm_state_change(void *opaque, bool running, 98042043e4fSLaurent Vivier RunState state) 98142043e4fSLaurent Vivier { 98242043e4fSLaurent Vivier PPCTimebase *tb = opaque; 98342043e4fSLaurent Vivier 98442043e4fSLaurent Vivier if (running) { 98542043e4fSLaurent Vivier timebase_load(tb); 98642043e4fSLaurent Vivier } else { 98742043e4fSLaurent Vivier timebase_save(tb); 98842043e4fSLaurent Vivier } 98942043e4fSLaurent Vivier } 99042043e4fSLaurent Vivier 99142043e4fSLaurent Vivier /* 992d14f3397SMaxiwell S. Garcia * When migrating a running guest, read the clock just 993d14f3397SMaxiwell S. Garcia * before migration, so that the guest clock counts 994d14f3397SMaxiwell S. Garcia * during the events between: 99542043e4fSLaurent Vivier * 99642043e4fSLaurent Vivier * * vm_stop() 99742043e4fSLaurent Vivier * * 99842043e4fSLaurent Vivier * * pre_save() 99942043e4fSLaurent Vivier * 100042043e4fSLaurent Vivier * This reduces clock difference on migration from 5s 100142043e4fSLaurent Vivier * to 0.1s (when max_downtime == 5s), because sending the 100242043e4fSLaurent Vivier * final pages of memory (which happens between vm_stop() 100342043e4fSLaurent Vivier * and pre_save()) takes max_downtime. 100442043e4fSLaurent Vivier */ 100544b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque) 100642043e4fSLaurent Vivier { 100742043e4fSLaurent Vivier PPCTimebase *tb = opaque; 100842043e4fSLaurent Vivier 1009711dfb24SGreg Kurz /* guest_timebase won't be overridden in case of paused guest or savevm */ 1010d14f3397SMaxiwell S. Garcia if (!tb->runstate_paused) { 101142043e4fSLaurent Vivier timebase_save(tb); 1012d14f3397SMaxiwell S. Garcia } 101344b1ff31SDr. David Alan Gilbert 101444b1ff31SDr. David Alan Gilbert return 0; 101598a8b524SAlexey Kardashevskiy } 101698a8b524SAlexey Kardashevskiy 101798a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = { 101898a8b524SAlexey Kardashevskiy .name = "timebase", 101998a8b524SAlexey Kardashevskiy .version_id = 1, 102098a8b524SAlexey Kardashevskiy .minimum_version_id = 1, 102198a8b524SAlexey Kardashevskiy .pre_save = timebase_pre_save, 102298a8b524SAlexey Kardashevskiy .fields = (VMStateField []) { 102398a8b524SAlexey Kardashevskiy VMSTATE_UINT64(guest_timebase, PPCTimebase), 102498a8b524SAlexey Kardashevskiy VMSTATE_INT64(time_of_the_day_ns, PPCTimebase), 102598a8b524SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 102698a8b524SAlexey Kardashevskiy }, 102798a8b524SAlexey Kardashevskiy }; 102898a8b524SAlexey Kardashevskiy 10299fddaa0cSbellard /* Set up (once) timebase frequency (in Hz) */ 1030e2684c0bSAndreas Färber clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) 10319fddaa0cSbellard { 1032db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 1033c227f099SAnthony Liguori ppc_tb_t *tb_env; 10349fddaa0cSbellard 1035b21e2380SMarkus Armbruster tb_env = g_new0(ppc_tb_t, 1); 10369fddaa0cSbellard env->tb_env = tb_env; 1037ddd1055bSFabien Chouteau tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 1038d0db7cadSGreg Kurz if (is_book3s_arch2x(env)) { 1039e81a982aSAlexander Graf /* All Book3S 64bit CPUs implement level based DEC logic */ 1040e81a982aSAlexander Graf tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL; 1041e81a982aSAlexander Graf } 10429fddaa0cSbellard /* Create new timer */ 1043bc72ad67SAlex Bligh tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); 10445ff40b01SNicholas Piggin if (env->has_hv_mode && !cpu->vhyp) { 1045bc72ad67SAlex Bligh tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, 104650c680f0SAndreas Färber cpu); 1047b172c56aSj_mayer } else { 1048b172c56aSj_mayer tb_env->hdecr_timer = NULL; 1049b172c56aSj_mayer } 10508ecc7913Sj_mayer cpu_ppc_set_tb_clk(env, freq); 10519fddaa0cSbellard 10528ecc7913Sj_mayer return &cpu_ppc_set_tb_clk; 10539fddaa0cSbellard } 10549fddaa0cSbellard 1055ef95a244SDaniel Henrique Barboza void cpu_ppc_tb_free(CPUPPCState *env) 1056ef95a244SDaniel Henrique Barboza { 1057ef95a244SDaniel Henrique Barboza timer_free(env->tb_env->decr_timer); 1058ef95a244SDaniel Henrique Barboza timer_free(env->tb_env->hdecr_timer); 1059ef95a244SDaniel Henrique Barboza g_free(env->tb_env); 1060ef95a244SDaniel Henrique Barboza } 1061ef95a244SDaniel Henrique Barboza 106293aeb702SNicholas Piggin /* cpu_ppc_hdecr_init may be used if the timer is not used by HDEC emulation */ 106393aeb702SNicholas Piggin void cpu_ppc_hdecr_init(CPUPPCState *env) 106493aeb702SNicholas Piggin { 106593aeb702SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 106693aeb702SNicholas Piggin 106793aeb702SNicholas Piggin assert(env->tb_env->hdecr_timer == NULL); 106893aeb702SNicholas Piggin 106993aeb702SNicholas Piggin env->tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 107093aeb702SNicholas Piggin &cpu_ppc_hdecr_cb, cpu); 107193aeb702SNicholas Piggin } 107293aeb702SNicholas Piggin 107393aeb702SNicholas Piggin void cpu_ppc_hdecr_exit(CPUPPCState *env) 107493aeb702SNicholas Piggin { 107593aeb702SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 107693aeb702SNicholas Piggin 107793aeb702SNicholas Piggin timer_free(env->tb_env->hdecr_timer); 107893aeb702SNicholas Piggin env->tb_env->hdecr_timer = NULL; 107993aeb702SNicholas Piggin 108093aeb702SNicholas Piggin cpu_ppc_hdecr_lower(cpu); 108193aeb702SNicholas Piggin } 108293aeb702SNicholas Piggin 1083636aaad7Sj_mayer /*****************************************************************************/ 1084ddd1055bSFabien Chouteau /* PowerPC 40x timers */ 1085636aaad7Sj_mayer 1086636aaad7Sj_mayer /* PIT, FIT & WDT */ 1087ddd1055bSFabien Chouteau typedef struct ppc40x_timer_t ppc40x_timer_t; 1088ddd1055bSFabien Chouteau struct ppc40x_timer_t { 1089636aaad7Sj_mayer uint64_t pit_reload; /* PIT auto-reload value */ 1090636aaad7Sj_mayer uint64_t fit_next; /* Tick for next FIT interrupt */ 10911246b259SStefan Weil QEMUTimer *fit_timer; 1092636aaad7Sj_mayer uint64_t wdt_next; /* Tick for next WDT interrupt */ 10931246b259SStefan Weil QEMUTimer *wdt_timer; 1094d63cb48dSEdgar E. Iglesias 1095d63cb48dSEdgar E. Iglesias /* 405 have the PIT, 440 have a DECR. */ 1096d63cb48dSEdgar E. Iglesias unsigned int decr_excp; 1097636aaad7Sj_mayer }; 1098636aaad7Sj_mayer 1099636aaad7Sj_mayer /* Fixed interval timer */ 1100636aaad7Sj_mayer static void cpu_4xx_fit_cb (void *opaque) 110176a66253Sj_mayer { 1102b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1103b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 1104c227f099SAnthony Liguori ppc_tb_t *tb_env; 1105ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1106636aaad7Sj_mayer uint64_t now, next; 1107636aaad7Sj_mayer 1108636aaad7Sj_mayer tb_env = env->tb_env; 1109ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1110bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1111636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { 1112636aaad7Sj_mayer case 0: 1113636aaad7Sj_mayer next = 1 << 9; 1114636aaad7Sj_mayer break; 1115636aaad7Sj_mayer case 1: 1116636aaad7Sj_mayer next = 1 << 13; 1117636aaad7Sj_mayer break; 1118636aaad7Sj_mayer case 2: 1119636aaad7Sj_mayer next = 1 << 17; 1120636aaad7Sj_mayer break; 1121636aaad7Sj_mayer case 3: 1122636aaad7Sj_mayer next = 1 << 21; 1123636aaad7Sj_mayer break; 1124636aaad7Sj_mayer default: 1125636aaad7Sj_mayer /* Cannot occur, but makes gcc happy */ 1126636aaad7Sj_mayer return; 1127636aaad7Sj_mayer } 112873bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq); 1129636aaad7Sj_mayer if (next == now) 1130636aaad7Sj_mayer next++; 1131bc72ad67SAlex Bligh timer_mod(ppc40x_timer->fit_timer, next); 1132636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 26; 11337058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { 11347058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); 11357058581aSAndreas Färber } 1136af96d2e6SCédric Le Goater trace_ppc4xx_fit((int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), 1137636aaad7Sj_mayer env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 1138636aaad7Sj_mayer } 1139636aaad7Sj_mayer 1140636aaad7Sj_mayer /* Programmable interval timer */ 1141e2684c0bSAndreas Färber static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) 1142636aaad7Sj_mayer { 1143ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1144636aaad7Sj_mayer uint64_t now, next; 1145636aaad7Sj_mayer 1146ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1147ddd1055bSFabien Chouteau if (ppc40x_timer->pit_reload <= 1 || 11484b6d0a4cSj_mayer !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || 11494b6d0a4cSj_mayer (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { 11504b6d0a4cSj_mayer /* Stop PIT */ 1151af96d2e6SCédric Le Goater trace_ppc4xx_pit_stop(); 1152bc72ad67SAlex Bligh timer_del(tb_env->decr_timer); 11534b6d0a4cSj_mayer } else { 1154af96d2e6SCédric Le Goater trace_ppc4xx_pit_start(ppc40x_timer->pit_reload); 1155bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1156ddd1055bSFabien Chouteau next = now + muldiv64(ppc40x_timer->pit_reload, 115773bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, tb_env->decr_freq); 11584b6d0a4cSj_mayer if (is_excp) 11594b6d0a4cSj_mayer next += tb_env->decr_next - now; 1160636aaad7Sj_mayer if (next == now) 1161636aaad7Sj_mayer next++; 1162bc72ad67SAlex Bligh timer_mod(tb_env->decr_timer, next); 1163636aaad7Sj_mayer tb_env->decr_next = next; 1164636aaad7Sj_mayer } 11654b6d0a4cSj_mayer } 11664b6d0a4cSj_mayer 11674b6d0a4cSj_mayer static void cpu_4xx_pit_cb (void *opaque) 11684b6d0a4cSj_mayer { 1169b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1170b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 1171c227f099SAnthony Liguori ppc_tb_t *tb_env; 1172ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 11734b6d0a4cSj_mayer 11744b6d0a4cSj_mayer tb_env = env->tb_env; 1175ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1176636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 27; 11777058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { 11787058581aSAndreas Färber ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); 11797058581aSAndreas Färber } 11804b6d0a4cSj_mayer start_stop_pit(env, tb_env, 1); 1181af96d2e6SCédric Le Goater trace_ppc4xx_pit((int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), 1182e96efcfcSj_mayer (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), 1183636aaad7Sj_mayer env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], 1184ddd1055bSFabien Chouteau ppc40x_timer->pit_reload); 1185636aaad7Sj_mayer } 1186636aaad7Sj_mayer 1187636aaad7Sj_mayer /* Watchdog timer */ 1188636aaad7Sj_mayer static void cpu_4xx_wdt_cb (void *opaque) 1189636aaad7Sj_mayer { 1190b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1191b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 1192c227f099SAnthony Liguori ppc_tb_t *tb_env; 1193ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1194636aaad7Sj_mayer uint64_t now, next; 1195636aaad7Sj_mayer 1196636aaad7Sj_mayer tb_env = env->tb_env; 1197ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1198bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1199636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { 1200636aaad7Sj_mayer case 0: 1201636aaad7Sj_mayer next = 1 << 17; 1202636aaad7Sj_mayer break; 1203636aaad7Sj_mayer case 1: 1204636aaad7Sj_mayer next = 1 << 21; 1205636aaad7Sj_mayer break; 1206636aaad7Sj_mayer case 2: 1207636aaad7Sj_mayer next = 1 << 25; 1208636aaad7Sj_mayer break; 1209636aaad7Sj_mayer case 3: 1210636aaad7Sj_mayer next = 1 << 29; 1211636aaad7Sj_mayer break; 1212636aaad7Sj_mayer default: 1213636aaad7Sj_mayer /* Cannot occur, but makes gcc happy */ 1214636aaad7Sj_mayer return; 1215636aaad7Sj_mayer } 121673bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 1217636aaad7Sj_mayer if (next == now) 1218636aaad7Sj_mayer next++; 1219af96d2e6SCédric Le Goater trace_ppc4xx_wdt(env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 1220636aaad7Sj_mayer switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { 1221636aaad7Sj_mayer case 0x0: 1222636aaad7Sj_mayer case 0x1: 1223bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 1224ddd1055bSFabien Chouteau ppc40x_timer->wdt_next = next; 1225a1f7f97bSPeter Maydell env->spr[SPR_40x_TSR] |= 1U << 31; 1226636aaad7Sj_mayer break; 1227636aaad7Sj_mayer case 0x2: 1228bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 1229ddd1055bSFabien Chouteau ppc40x_timer->wdt_next = next; 1230636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 30; 12317058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { 12327058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); 12337058581aSAndreas Färber } 1234636aaad7Sj_mayer break; 1235636aaad7Sj_mayer case 0x3: 1236636aaad7Sj_mayer env->spr[SPR_40x_TSR] &= ~0x30000000; 1237636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000; 1238636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) { 1239636aaad7Sj_mayer case 0x0: 1240636aaad7Sj_mayer /* No reset */ 1241636aaad7Sj_mayer break; 1242636aaad7Sj_mayer case 0x1: /* Core reset */ 1243f3273ba6SAndreas Färber ppc40x_core_reset(cpu); 12448ecc7913Sj_mayer break; 1245636aaad7Sj_mayer case 0x2: /* Chip reset */ 1246f3273ba6SAndreas Färber ppc40x_chip_reset(cpu); 12478ecc7913Sj_mayer break; 1248636aaad7Sj_mayer case 0x3: /* System reset */ 1249f3273ba6SAndreas Färber ppc40x_system_reset(cpu); 12508ecc7913Sj_mayer break; 1251636aaad7Sj_mayer } 1252636aaad7Sj_mayer } 125376a66253Sj_mayer } 125476a66253Sj_mayer 1255e2684c0bSAndreas Färber void store_40x_pit (CPUPPCState *env, target_ulong val) 125676a66253Sj_mayer { 1257c227f099SAnthony Liguori ppc_tb_t *tb_env; 1258ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1259636aaad7Sj_mayer 1260636aaad7Sj_mayer tb_env = env->tb_env; 1261ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1262af96d2e6SCédric Le Goater trace_ppc40x_store_pit(val); 1263ddd1055bSFabien Chouteau ppc40x_timer->pit_reload = val; 12644b6d0a4cSj_mayer start_stop_pit(env, tb_env, 0); 126576a66253Sj_mayer } 126676a66253Sj_mayer 1267e2684c0bSAndreas Färber target_ulong load_40x_pit (CPUPPCState *env) 126876a66253Sj_mayer { 1269636aaad7Sj_mayer return cpu_ppc_load_decr(env); 127076a66253Sj_mayer } 127176a66253Sj_mayer 1272cbd8f17dSCédric Le Goater void store_40x_tsr(CPUPPCState *env, target_ulong val) 1273cbd8f17dSCédric Le Goater { 1274cbd8f17dSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1275cbd8f17dSCédric Le Goater 1276cbd8f17dSCédric Le Goater trace_ppc40x_store_tcr(val); 1277cbd8f17dSCédric Le Goater 1278cbd8f17dSCédric Le Goater env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000); 1279cbd8f17dSCédric Le Goater if (val & 0x80000000) { 1280cbd8f17dSCédric Le Goater ppc_set_irq(cpu, PPC_INTERRUPT_PIT, 0); 1281cbd8f17dSCédric Le Goater } 1282cbd8f17dSCédric Le Goater } 1283cbd8f17dSCédric Le Goater 1284cbd8f17dSCédric Le Goater void store_40x_tcr(CPUPPCState *env, target_ulong val) 1285cbd8f17dSCédric Le Goater { 1286cbd8f17dSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1287cbd8f17dSCédric Le Goater ppc_tb_t *tb_env; 1288cbd8f17dSCédric Le Goater 1289cbd8f17dSCédric Le Goater trace_ppc40x_store_tsr(val); 1290cbd8f17dSCédric Le Goater 1291cbd8f17dSCédric Le Goater tb_env = env->tb_env; 1292cbd8f17dSCédric Le Goater env->spr[SPR_40x_TCR] = val & 0xFFC00000; 1293cbd8f17dSCédric Le Goater start_stop_pit(env, tb_env, 1); 1294cbd8f17dSCédric Le Goater cpu_4xx_wdt_cb(cpu); 1295cbd8f17dSCédric Le Goater } 1296cbd8f17dSCédric Le Goater 1297ddd1055bSFabien Chouteau static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq) 12984b6d0a4cSj_mayer { 1299e2684c0bSAndreas Färber CPUPPCState *env = opaque; 1300c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 13014b6d0a4cSj_mayer 1302af96d2e6SCédric Le Goater trace_ppc40x_set_tb_clk(freq); 13034b6d0a4cSj_mayer tb_env->tb_freq = freq; 1304dbdd2506Sj_mayer tb_env->decr_freq = freq; 13054b6d0a4cSj_mayer /* XXX: we should also update all timers */ 13064b6d0a4cSj_mayer } 13074b6d0a4cSj_mayer 1308e2684c0bSAndreas Färber clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, 1309d63cb48dSEdgar E. Iglesias unsigned int decr_excp) 1310636aaad7Sj_mayer { 1311c227f099SAnthony Liguori ppc_tb_t *tb_env; 1312ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1313b1273a5eSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1314b1273a5eSCédric Le Goater 1315b1273a5eSCédric Le Goater trace_ppc40x_timers_init(freq); 1316636aaad7Sj_mayer 1317b21e2380SMarkus Armbruster tb_env = g_new0(ppc_tb_t, 1); 1318b21e2380SMarkus Armbruster ppc40x_timer = g_new0(ppc40x_timer_t, 1); 1319b1273a5eSCédric Le Goater 13208ecc7913Sj_mayer env->tb_env = tb_env; 1321ddd1055bSFabien Chouteau tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 13228ecc7913Sj_mayer tb_env->tb_freq = freq; 1323dbdd2506Sj_mayer tb_env->decr_freq = freq; 1324ddd1055bSFabien Chouteau tb_env->opaque = ppc40x_timer; 1325b1273a5eSCédric Le Goater 1326636aaad7Sj_mayer /* We use decr timer for PIT */ 1327b1273a5eSCédric Le Goater tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, cpu); 1328ddd1055bSFabien Chouteau ppc40x_timer->fit_timer = 1329b1273a5eSCédric Le Goater timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, cpu); 1330ddd1055bSFabien Chouteau ppc40x_timer->wdt_timer = 1331b1273a5eSCédric Le Goater timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, cpu); 1332ddd1055bSFabien Chouteau ppc40x_timer->decr_excp = decr_excp; 13338ecc7913Sj_mayer 1334ddd1055bSFabien Chouteau return &ppc_40x_set_tb_clk; 133576a66253Sj_mayer } 133676a66253Sj_mayer 13372e719ba3Sj_mayer /*****************************************************************************/ 13382e719ba3Sj_mayer /* Embedded PowerPC Device Control Registers */ 1339c227f099SAnthony Liguori typedef struct ppc_dcrn_t ppc_dcrn_t; 1340c227f099SAnthony Liguori struct ppc_dcrn_t { 13412e719ba3Sj_mayer dcr_read_cb dcr_read; 13422e719ba3Sj_mayer dcr_write_cb dcr_write; 13432e719ba3Sj_mayer void *opaque; 13442e719ba3Sj_mayer }; 13452e719ba3Sj_mayer 1346a750fc0bSj_mayer /* XXX: on 460, DCR addresses are 32 bits wide, 1347a750fc0bSj_mayer * using DCRIPR to get the 22 upper bits of the DCR address 1348a750fc0bSj_mayer */ 13492e719ba3Sj_mayer #define DCRN_NB 1024 1350c227f099SAnthony Liguori struct ppc_dcr_t { 1351c227f099SAnthony Liguori ppc_dcrn_t dcrn[DCRN_NB]; 13522e719ba3Sj_mayer int (*read_error)(int dcrn); 13532e719ba3Sj_mayer int (*write_error)(int dcrn); 13542e719ba3Sj_mayer }; 13552e719ba3Sj_mayer 135673b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) 13572e719ba3Sj_mayer { 1358c227f099SAnthony Liguori ppc_dcrn_t *dcr; 13592e719ba3Sj_mayer 13602e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 13612e719ba3Sj_mayer goto error; 13622e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 13632e719ba3Sj_mayer if (dcr->dcr_read == NULL) 13642e719ba3Sj_mayer goto error; 13652e719ba3Sj_mayer *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); 1366de82dabeSCédric Le Goater trace_ppc_dcr_read(dcrn, *valp); 13672e719ba3Sj_mayer 13682e719ba3Sj_mayer return 0; 13692e719ba3Sj_mayer 13702e719ba3Sj_mayer error: 13712e719ba3Sj_mayer if (dcr_env->read_error != NULL) 13722e719ba3Sj_mayer return (*dcr_env->read_error)(dcrn); 13732e719ba3Sj_mayer 13742e719ba3Sj_mayer return -1; 13752e719ba3Sj_mayer } 13762e719ba3Sj_mayer 137773b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) 13782e719ba3Sj_mayer { 1379c227f099SAnthony Liguori ppc_dcrn_t *dcr; 13802e719ba3Sj_mayer 13812e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 13822e719ba3Sj_mayer goto error; 13832e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 13842e719ba3Sj_mayer if (dcr->dcr_write == NULL) 13852e719ba3Sj_mayer goto error; 1386de82dabeSCédric Le Goater trace_ppc_dcr_write(dcrn, val); 13872e719ba3Sj_mayer (*dcr->dcr_write)(dcr->opaque, dcrn, val); 13882e719ba3Sj_mayer 13892e719ba3Sj_mayer return 0; 13902e719ba3Sj_mayer 13912e719ba3Sj_mayer error: 13922e719ba3Sj_mayer if (dcr_env->write_error != NULL) 13932e719ba3Sj_mayer return (*dcr_env->write_error)(dcrn); 13942e719ba3Sj_mayer 13952e719ba3Sj_mayer return -1; 13962e719ba3Sj_mayer } 13972e719ba3Sj_mayer 1398e2684c0bSAndreas Färber int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, 13992e719ba3Sj_mayer dcr_read_cb dcr_read, dcr_write_cb dcr_write) 14002e719ba3Sj_mayer { 1401c227f099SAnthony Liguori ppc_dcr_t *dcr_env; 1402c227f099SAnthony Liguori ppc_dcrn_t *dcr; 14032e719ba3Sj_mayer 14042e719ba3Sj_mayer dcr_env = env->dcr_env; 14052e719ba3Sj_mayer if (dcr_env == NULL) 14062e719ba3Sj_mayer return -1; 14072e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 14082e719ba3Sj_mayer return -1; 14092e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 14102e719ba3Sj_mayer if (dcr->opaque != NULL || 14112e719ba3Sj_mayer dcr->dcr_read != NULL || 14122e719ba3Sj_mayer dcr->dcr_write != NULL) 14132e719ba3Sj_mayer return -1; 14142e719ba3Sj_mayer dcr->opaque = opaque; 14152e719ba3Sj_mayer dcr->dcr_read = dcr_read; 14162e719ba3Sj_mayer dcr->dcr_write = dcr_write; 14172e719ba3Sj_mayer 14182e719ba3Sj_mayer return 0; 14192e719ba3Sj_mayer } 14202e719ba3Sj_mayer 1421e2684c0bSAndreas Färber int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn), 14222e719ba3Sj_mayer int (*write_error)(int dcrn)) 14232e719ba3Sj_mayer { 1424c227f099SAnthony Liguori ppc_dcr_t *dcr_env; 14252e719ba3Sj_mayer 1426b21e2380SMarkus Armbruster dcr_env = g_new0(ppc_dcr_t, 1); 14272e719ba3Sj_mayer dcr_env->read_error = read_error; 14282e719ba3Sj_mayer dcr_env->write_error = write_error; 14292e719ba3Sj_mayer env->dcr_env = dcr_env; 14302e719ba3Sj_mayer 14312e719ba3Sj_mayer return 0; 14322e719ba3Sj_mayer } 14332e719ba3Sj_mayer 143464201201Sbellard /*****************************************************************************/ 1435051e2973SCédric Le Goater 14364a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu) 14374a89e204SCédric Le Goater { 14384a89e204SCédric Le Goater CPUPPCState *env = &cpu->env; 14394a89e204SCédric Le Goater return env->spr_cb[SPR_PIR].default_value; 14404a89e204SCédric Le Goater } 14414a89e204SCédric Le Goater 1442d24e80b2SNicholas Piggin int ppc_cpu_tir(PowerPCCPU *cpu) 1443d24e80b2SNicholas Piggin { 1444d24e80b2SNicholas Piggin CPUPPCState *env = &cpu->env; 1445d24e80b2SNicholas Piggin return env->spr_cb[SPR_TIR].default_value; 1446d24e80b2SNicholas Piggin } 1447d24e80b2SNicholas Piggin 1448051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir) 1449051e2973SCédric Le Goater { 1450051e2973SCédric Le Goater CPUState *cs; 1451051e2973SCédric Le Goater 1452051e2973SCédric Le Goater CPU_FOREACH(cs) { 1453051e2973SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 1454051e2973SCédric Le Goater 14554a89e204SCédric Le Goater if (ppc_cpu_pir(cpu) == pir) { 1456051e2973SCédric Le Goater return cpu; 1457051e2973SCédric Le Goater } 1458051e2973SCédric Le Goater } 1459051e2973SCédric Le Goater 1460051e2973SCédric Le Goater return NULL; 1461051e2973SCédric Le Goater } 146240177438SGreg Kurz 146340177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu) 146440177438SGreg Kurz { 146540177438SGreg Kurz CPUPPCState *env = &cpu->env; 146640177438SGreg Kurz 146740177438SGreg Kurz env->irq_input_state = 0; 146840177438SGreg Kurz kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); 146940177438SGreg Kurz } 1470