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 */ 240d75590dSPeter Maydell #include "qemu/osdep.h" 254771d756SPaolo Bonzini #include "qemu-common.h" 264771d756SPaolo Bonzini #include "cpu.h" 2783c9f4caSPaolo Bonzini #include "hw/hw.h" 280d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h" 292b927571SAndreas Färber #include "hw/ppc/ppc_e500.h" 301de7afc9SPaolo Bonzini #include "qemu/timer.h" 319c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 320ce470cdSAlexey Kardashevskiy #include "sysemu/cpus.h" 330d09e41aSPaolo Bonzini #include "hw/timer/m48t59.h" 341de7afc9SPaolo Bonzini #include "qemu/log.h" 3598a8b524SAlexey Kardashevskiy #include "qemu/error-report.h" 3683c9f4caSPaolo Bonzini #include "hw/loader.h" 379c17d615SPaolo Bonzini #include "sysemu/kvm.h" 38fc87e185SAlexander Graf #include "kvm_ppc.h" 3998a8b524SAlexey Kardashevskiy #include "trace.h" 40a541f297Sbellard 41e9df014cSj_mayer //#define PPC_DEBUG_IRQ 424b6d0a4cSj_mayer //#define PPC_DEBUG_TB 43e9df014cSj_mayer 44d12d51d5Saliguori #ifdef PPC_DEBUG_IRQ 4593fcfe39Saliguori # define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) 46d12d51d5Saliguori #else 47d12d51d5Saliguori # define LOG_IRQ(...) do { } while (0) 48d12d51d5Saliguori #endif 49d12d51d5Saliguori 50d12d51d5Saliguori 51d12d51d5Saliguori #ifdef PPC_DEBUG_TB 5293fcfe39Saliguori # define LOG_TB(...) qemu_log(__VA_ARGS__) 53d12d51d5Saliguori #else 54d12d51d5Saliguori # define LOG_TB(...) do { } while (0) 55d12d51d5Saliguori #endif 56d12d51d5Saliguori 57e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env); 58e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env); 59dbdd2506Sj_mayer 607058581aSAndreas Färber void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) 6147103572Sj_mayer { 62d8ed887bSAndreas Färber CPUState *cs = CPU(cpu); 637058581aSAndreas Färber CPUPPCState *env = &cpu->env; 64fc87e185SAlexander Graf unsigned int old_pending = env->pending_interrupts; 65fc87e185SAlexander Graf 6647103572Sj_mayer if (level) { 6747103572Sj_mayer env->pending_interrupts |= 1 << n_IRQ; 68c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 6947103572Sj_mayer } else { 7047103572Sj_mayer env->pending_interrupts &= ~(1 << n_IRQ); 71d8ed887bSAndreas Färber if (env->pending_interrupts == 0) { 72d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 73d8ed887bSAndreas Färber } 7447103572Sj_mayer } 75fc87e185SAlexander Graf 76fc87e185SAlexander Graf if (old_pending != env->pending_interrupts) { 77fc87e185SAlexander Graf #ifdef CONFIG_KVM 787058581aSAndreas Färber kvmppc_set_interrupt(cpu, n_IRQ, level); 79fc87e185SAlexander Graf #endif 80fc87e185SAlexander Graf } 81fc87e185SAlexander Graf 82d12d51d5Saliguori LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32 83aae9366aSj_mayer "req %08x\n", __func__, env, n_IRQ, level, 84259186a7SAndreas Färber env->pending_interrupts, CPU(cpu)->interrupt_request); 85a496775fSj_mayer } 8647103572Sj_mayer 87e9df014cSj_mayer /* PowerPC 6xx / 7xx internal IRQ controller */ 88e9df014cSj_mayer static void ppc6xx_set_irq(void *opaque, int pin, int level) 89d537cf6cSpbrook { 90a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 91a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 92e9df014cSj_mayer int cur_level; 93d537cf6cSpbrook 94d12d51d5Saliguori LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 95a496775fSj_mayer env, pin, level); 96e9df014cSj_mayer cur_level = (env->irq_input_state >> pin) & 1; 97e9df014cSj_mayer /* Don't generate spurious events */ 9824be5ae3Sj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 99259186a7SAndreas Färber CPUState *cs = CPU(cpu); 100259186a7SAndreas Färber 101e9df014cSj_mayer switch (pin) { 102dbdd2506Sj_mayer case PPC6xx_INPUT_TBEN: 103dbdd2506Sj_mayer /* Level sensitive - active high */ 104d12d51d5Saliguori LOG_IRQ("%s: %s the time base\n", 105dbdd2506Sj_mayer __func__, level ? "start" : "stop"); 106dbdd2506Sj_mayer if (level) { 107dbdd2506Sj_mayer cpu_ppc_tb_start(env); 108dbdd2506Sj_mayer } else { 109dbdd2506Sj_mayer cpu_ppc_tb_stop(env); 110dbdd2506Sj_mayer } 11124be5ae3Sj_mayer case PPC6xx_INPUT_INT: 11224be5ae3Sj_mayer /* Level sensitive - active high */ 113d12d51d5Saliguori LOG_IRQ("%s: set the external IRQ state to %d\n", 114a496775fSj_mayer __func__, level); 1157058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 116e9df014cSj_mayer break; 11724be5ae3Sj_mayer case PPC6xx_INPUT_SMI: 118e9df014cSj_mayer /* Level sensitive - active high */ 119d12d51d5Saliguori LOG_IRQ("%s: set the SMI IRQ state to %d\n", 120a496775fSj_mayer __func__, level); 1217058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); 122e9df014cSj_mayer break; 12324be5ae3Sj_mayer case PPC6xx_INPUT_MCP: 124e9df014cSj_mayer /* Negative edge sensitive */ 125e9df014cSj_mayer /* XXX: TODO: actual reaction may depends on HID0 status 126e9df014cSj_mayer * 603/604/740/750: check HID0[EMCP] 127e9df014cSj_mayer */ 128e9df014cSj_mayer if (cur_level == 1 && level == 0) { 129d12d51d5Saliguori LOG_IRQ("%s: raise machine check state\n", 130a496775fSj_mayer __func__); 1317058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 132d537cf6cSpbrook } 133e9df014cSj_mayer break; 13424be5ae3Sj_mayer case PPC6xx_INPUT_CKSTP_IN: 135e9df014cSj_mayer /* Level sensitive - active low */ 136e9df014cSj_mayer /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 137e63ecc6fSj_mayer /* XXX: Note that the only way to restart the CPU is to reset it */ 138e9df014cSj_mayer if (level) { 139d12d51d5Saliguori LOG_IRQ("%s: stop the CPU\n", __func__); 140259186a7SAndreas Färber cs->halted = 1; 141d537cf6cSpbrook } 14247103572Sj_mayer break; 14324be5ae3Sj_mayer case PPC6xx_INPUT_HRESET: 144e9df014cSj_mayer /* Level sensitive - active low */ 145e9df014cSj_mayer if (level) { 146d12d51d5Saliguori LOG_IRQ("%s: reset the CPU\n", __func__); 147c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 148e9df014cSj_mayer } 14947103572Sj_mayer break; 15024be5ae3Sj_mayer case PPC6xx_INPUT_SRESET: 151d12d51d5Saliguori LOG_IRQ("%s: set the RESET IRQ state to %d\n", 152a496775fSj_mayer __func__, level); 1537058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 15447103572Sj_mayer break; 155e9df014cSj_mayer default: 156e9df014cSj_mayer /* Unknown pin - do nothing */ 157d12d51d5Saliguori LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 15847103572Sj_mayer return; 15947103572Sj_mayer } 160e9df014cSj_mayer if (level) 161e9df014cSj_mayer env->irq_input_state |= 1 << pin; 162e9df014cSj_mayer else 163e9df014cSj_mayer env->irq_input_state &= ~(1 << pin); 164e9df014cSj_mayer } 165e9df014cSj_mayer } 166e9df014cSj_mayer 167e2684c0bSAndreas Färber void ppc6xx_irq_init(CPUPPCState *env) 168e9df014cSj_mayer { 169a0961245SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 170a0961245SAndreas Färber 171a0961245SAndreas Färber env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu, 1727b62a955Sj_mayer PPC6xx_INPUT_NB); 17347103572Sj_mayer } 17447103572Sj_mayer 17500af685fSj_mayer #if defined(TARGET_PPC64) 176d0dfae6eSj_mayer /* PowerPC 970 internal IRQ controller */ 177d0dfae6eSj_mayer static void ppc970_set_irq(void *opaque, int pin, int level) 178d0dfae6eSj_mayer { 179a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 180a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 181d0dfae6eSj_mayer int cur_level; 182d0dfae6eSj_mayer 183d12d51d5Saliguori LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 184d0dfae6eSj_mayer env, pin, level); 185d0dfae6eSj_mayer cur_level = (env->irq_input_state >> pin) & 1; 186d0dfae6eSj_mayer /* Don't generate spurious events */ 187d0dfae6eSj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 188259186a7SAndreas Färber CPUState *cs = CPU(cpu); 189259186a7SAndreas Färber 190d0dfae6eSj_mayer switch (pin) { 191d0dfae6eSj_mayer case PPC970_INPUT_INT: 192d0dfae6eSj_mayer /* Level sensitive - active high */ 193d12d51d5Saliguori LOG_IRQ("%s: set the external IRQ state to %d\n", 194d0dfae6eSj_mayer __func__, level); 1957058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 196d0dfae6eSj_mayer break; 197d0dfae6eSj_mayer case PPC970_INPUT_THINT: 198d0dfae6eSj_mayer /* Level sensitive - active high */ 199d12d51d5Saliguori LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__, 200d0dfae6eSj_mayer level); 2017058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); 202d0dfae6eSj_mayer break; 203d0dfae6eSj_mayer case PPC970_INPUT_MCP: 204d0dfae6eSj_mayer /* Negative edge sensitive */ 205d0dfae6eSj_mayer /* XXX: TODO: actual reaction may depends on HID0 status 206d0dfae6eSj_mayer * 603/604/740/750: check HID0[EMCP] 207d0dfae6eSj_mayer */ 208d0dfae6eSj_mayer if (cur_level == 1 && level == 0) { 209d12d51d5Saliguori LOG_IRQ("%s: raise machine check state\n", 210d0dfae6eSj_mayer __func__); 2117058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 212d0dfae6eSj_mayer } 213d0dfae6eSj_mayer break; 214d0dfae6eSj_mayer case PPC970_INPUT_CKSTP: 215d0dfae6eSj_mayer /* Level sensitive - active low */ 216d0dfae6eSj_mayer /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 217d0dfae6eSj_mayer if (level) { 218d12d51d5Saliguori LOG_IRQ("%s: stop the CPU\n", __func__); 219259186a7SAndreas Färber cs->halted = 1; 220d0dfae6eSj_mayer } else { 221d12d51d5Saliguori LOG_IRQ("%s: restart the CPU\n", __func__); 222259186a7SAndreas Färber cs->halted = 0; 223259186a7SAndreas Färber qemu_cpu_kick(cs); 224d0dfae6eSj_mayer } 225d0dfae6eSj_mayer break; 226d0dfae6eSj_mayer case PPC970_INPUT_HRESET: 227d0dfae6eSj_mayer /* Level sensitive - active low */ 228d0dfae6eSj_mayer if (level) { 229c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 230d0dfae6eSj_mayer } 231d0dfae6eSj_mayer break; 232d0dfae6eSj_mayer case PPC970_INPUT_SRESET: 233d12d51d5Saliguori LOG_IRQ("%s: set the RESET IRQ state to %d\n", 234d0dfae6eSj_mayer __func__, level); 2357058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 236d0dfae6eSj_mayer break; 237d0dfae6eSj_mayer case PPC970_INPUT_TBEN: 238d12d51d5Saliguori LOG_IRQ("%s: set the TBEN state to %d\n", __func__, 239d0dfae6eSj_mayer level); 240d0dfae6eSj_mayer /* XXX: TODO */ 241d0dfae6eSj_mayer break; 242d0dfae6eSj_mayer default: 243d0dfae6eSj_mayer /* Unknown pin - do nothing */ 244d12d51d5Saliguori LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 245d0dfae6eSj_mayer return; 246d0dfae6eSj_mayer } 247d0dfae6eSj_mayer if (level) 248d0dfae6eSj_mayer env->irq_input_state |= 1 << pin; 249d0dfae6eSj_mayer else 250d0dfae6eSj_mayer env->irq_input_state &= ~(1 << pin); 251d0dfae6eSj_mayer } 252d0dfae6eSj_mayer } 253d0dfae6eSj_mayer 254e2684c0bSAndreas Färber void ppc970_irq_init(CPUPPCState *env) 255d0dfae6eSj_mayer { 256a0961245SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 257a0961245SAndreas Färber 258a0961245SAndreas Färber env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu, 2597b62a955Sj_mayer PPC970_INPUT_NB); 260d0dfae6eSj_mayer } 2619d52e907SDavid Gibson 2629d52e907SDavid Gibson /* POWER7 internal IRQ controller */ 2639d52e907SDavid Gibson static void power7_set_irq(void *opaque, int pin, int level) 2649d52e907SDavid Gibson { 265a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 266a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 2679d52e907SDavid Gibson 2689d52e907SDavid Gibson LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 2699d52e907SDavid Gibson env, pin, level); 2709d52e907SDavid Gibson 2719d52e907SDavid Gibson switch (pin) { 2729d52e907SDavid Gibson case POWER7_INPUT_INT: 2739d52e907SDavid Gibson /* Level sensitive - active high */ 2749d52e907SDavid Gibson LOG_IRQ("%s: set the external IRQ state to %d\n", 2759d52e907SDavid Gibson __func__, level); 2767058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 2779d52e907SDavid Gibson break; 2789d52e907SDavid Gibson default: 2799d52e907SDavid Gibson /* Unknown pin - do nothing */ 2809d52e907SDavid Gibson LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 2819d52e907SDavid Gibson return; 2829d52e907SDavid Gibson } 2839d52e907SDavid Gibson if (level) { 2849d52e907SDavid Gibson env->irq_input_state |= 1 << pin; 2859d52e907SDavid Gibson } else { 2869d52e907SDavid Gibson env->irq_input_state &= ~(1 << pin); 2879d52e907SDavid Gibson } 2889d52e907SDavid Gibson } 2899d52e907SDavid Gibson 290e2684c0bSAndreas Färber void ppcPOWER7_irq_init(CPUPPCState *env) 2919d52e907SDavid Gibson { 292a0961245SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 293a0961245SAndreas Färber 294a0961245SAndreas Färber env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu, 2959d52e907SDavid Gibson POWER7_INPUT_NB); 2969d52e907SDavid Gibson } 29700af685fSj_mayer #endif /* defined(TARGET_PPC64) */ 298d0dfae6eSj_mayer 2994e290a0bSj_mayer /* PowerPC 40x internal IRQ controller */ 3004e290a0bSj_mayer static void ppc40x_set_irq(void *opaque, int pin, int level) 30124be5ae3Sj_mayer { 302a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 303a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 30424be5ae3Sj_mayer int cur_level; 30524be5ae3Sj_mayer 306d12d51d5Saliguori LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 3078ecc7913Sj_mayer env, pin, level); 30824be5ae3Sj_mayer cur_level = (env->irq_input_state >> pin) & 1; 30924be5ae3Sj_mayer /* Don't generate spurious events */ 31024be5ae3Sj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 311259186a7SAndreas Färber CPUState *cs = CPU(cpu); 312259186a7SAndreas Färber 31324be5ae3Sj_mayer switch (pin) { 3144e290a0bSj_mayer case PPC40x_INPUT_RESET_SYS: 3158ecc7913Sj_mayer if (level) { 316d12d51d5Saliguori LOG_IRQ("%s: reset the PowerPC system\n", 3178ecc7913Sj_mayer __func__); 318f3273ba6SAndreas Färber ppc40x_system_reset(cpu); 3198ecc7913Sj_mayer } 3208ecc7913Sj_mayer break; 3214e290a0bSj_mayer case PPC40x_INPUT_RESET_CHIP: 3228ecc7913Sj_mayer if (level) { 323d12d51d5Saliguori LOG_IRQ("%s: reset the PowerPC chip\n", __func__); 324f3273ba6SAndreas Färber ppc40x_chip_reset(cpu); 3258ecc7913Sj_mayer } 3268ecc7913Sj_mayer break; 3274e290a0bSj_mayer case PPC40x_INPUT_RESET_CORE: 32824be5ae3Sj_mayer /* XXX: TODO: update DBSR[MRR] */ 32924be5ae3Sj_mayer if (level) { 330d12d51d5Saliguori LOG_IRQ("%s: reset the PowerPC core\n", __func__); 331f3273ba6SAndreas Färber ppc40x_core_reset(cpu); 33224be5ae3Sj_mayer } 33324be5ae3Sj_mayer break; 3344e290a0bSj_mayer case PPC40x_INPUT_CINT: 33524be5ae3Sj_mayer /* Level sensitive - active high */ 336d12d51d5Saliguori LOG_IRQ("%s: set the critical IRQ state to %d\n", 3378ecc7913Sj_mayer __func__, level); 3387058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 33924be5ae3Sj_mayer break; 3404e290a0bSj_mayer case PPC40x_INPUT_INT: 34124be5ae3Sj_mayer /* Level sensitive - active high */ 342d12d51d5Saliguori LOG_IRQ("%s: set the external IRQ state to %d\n", 343a496775fSj_mayer __func__, level); 3447058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 34524be5ae3Sj_mayer break; 3464e290a0bSj_mayer case PPC40x_INPUT_HALT: 34724be5ae3Sj_mayer /* Level sensitive - active low */ 34824be5ae3Sj_mayer if (level) { 349d12d51d5Saliguori LOG_IRQ("%s: stop the CPU\n", __func__); 350259186a7SAndreas Färber cs->halted = 1; 35124be5ae3Sj_mayer } else { 352d12d51d5Saliguori LOG_IRQ("%s: restart the CPU\n", __func__); 353259186a7SAndreas Färber cs->halted = 0; 354259186a7SAndreas Färber qemu_cpu_kick(cs); 35524be5ae3Sj_mayer } 35624be5ae3Sj_mayer break; 3574e290a0bSj_mayer case PPC40x_INPUT_DEBUG: 35824be5ae3Sj_mayer /* Level sensitive - active high */ 359d12d51d5Saliguori LOG_IRQ("%s: set the debug pin state to %d\n", 360a496775fSj_mayer __func__, level); 3617058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 36224be5ae3Sj_mayer break; 36324be5ae3Sj_mayer default: 36424be5ae3Sj_mayer /* Unknown pin - do nothing */ 365d12d51d5Saliguori LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 36624be5ae3Sj_mayer return; 36724be5ae3Sj_mayer } 36824be5ae3Sj_mayer if (level) 36924be5ae3Sj_mayer env->irq_input_state |= 1 << pin; 37024be5ae3Sj_mayer else 37124be5ae3Sj_mayer env->irq_input_state &= ~(1 << pin); 37224be5ae3Sj_mayer } 37324be5ae3Sj_mayer } 37424be5ae3Sj_mayer 375e2684c0bSAndreas Färber void ppc40x_irq_init(CPUPPCState *env) 37624be5ae3Sj_mayer { 377a0961245SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 378a0961245SAndreas Färber 3794e290a0bSj_mayer env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, 380a0961245SAndreas Färber cpu, PPC40x_INPUT_NB); 38124be5ae3Sj_mayer } 38224be5ae3Sj_mayer 3839fdc60bfSaurel32 /* PowerPC E500 internal IRQ controller */ 3849fdc60bfSaurel32 static void ppce500_set_irq(void *opaque, int pin, int level) 3859fdc60bfSaurel32 { 386a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 387a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 3889fdc60bfSaurel32 int cur_level; 3899fdc60bfSaurel32 3909fdc60bfSaurel32 LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 3919fdc60bfSaurel32 env, pin, level); 3929fdc60bfSaurel32 cur_level = (env->irq_input_state >> pin) & 1; 3939fdc60bfSaurel32 /* Don't generate spurious events */ 3949fdc60bfSaurel32 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 3959fdc60bfSaurel32 switch (pin) { 3969fdc60bfSaurel32 case PPCE500_INPUT_MCK: 3979fdc60bfSaurel32 if (level) { 3989fdc60bfSaurel32 LOG_IRQ("%s: reset the PowerPC system\n", 3999fdc60bfSaurel32 __func__); 4009fdc60bfSaurel32 qemu_system_reset_request(); 4019fdc60bfSaurel32 } 4029fdc60bfSaurel32 break; 4039fdc60bfSaurel32 case PPCE500_INPUT_RESET_CORE: 4049fdc60bfSaurel32 if (level) { 4059fdc60bfSaurel32 LOG_IRQ("%s: reset the PowerPC core\n", __func__); 4067058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); 4079fdc60bfSaurel32 } 4089fdc60bfSaurel32 break; 4099fdc60bfSaurel32 case PPCE500_INPUT_CINT: 4109fdc60bfSaurel32 /* Level sensitive - active high */ 4119fdc60bfSaurel32 LOG_IRQ("%s: set the critical IRQ state to %d\n", 4129fdc60bfSaurel32 __func__, level); 4137058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 4149fdc60bfSaurel32 break; 4159fdc60bfSaurel32 case PPCE500_INPUT_INT: 4169fdc60bfSaurel32 /* Level sensitive - active high */ 4179fdc60bfSaurel32 LOG_IRQ("%s: set the core IRQ state to %d\n", 4189fdc60bfSaurel32 __func__, level); 4197058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 4209fdc60bfSaurel32 break; 4219fdc60bfSaurel32 case PPCE500_INPUT_DEBUG: 4229fdc60bfSaurel32 /* Level sensitive - active high */ 4239fdc60bfSaurel32 LOG_IRQ("%s: set the debug pin state to %d\n", 4249fdc60bfSaurel32 __func__, level); 4257058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 4269fdc60bfSaurel32 break; 4279fdc60bfSaurel32 default: 4289fdc60bfSaurel32 /* Unknown pin - do nothing */ 4299fdc60bfSaurel32 LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 4309fdc60bfSaurel32 return; 4319fdc60bfSaurel32 } 4329fdc60bfSaurel32 if (level) 4339fdc60bfSaurel32 env->irq_input_state |= 1 << pin; 4349fdc60bfSaurel32 else 4359fdc60bfSaurel32 env->irq_input_state &= ~(1 << pin); 4369fdc60bfSaurel32 } 4379fdc60bfSaurel32 } 4389fdc60bfSaurel32 439e2684c0bSAndreas Färber void ppce500_irq_init(CPUPPCState *env) 4409fdc60bfSaurel32 { 441a0961245SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 442a0961245SAndreas Färber 4439fdc60bfSaurel32 env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, 444a0961245SAndreas Färber cpu, PPCE500_INPUT_NB); 4459fdc60bfSaurel32 } 446e49798b1SAlexander Graf 447e49798b1SAlexander Graf /* Enable or Disable the E500 EPR capability */ 448e49798b1SAlexander Graf void ppce500_set_mpic_proxy(bool enabled) 449e49798b1SAlexander Graf { 450182735efSAndreas Färber CPUState *cs; 451e49798b1SAlexander Graf 452bdc44640SAndreas Färber CPU_FOREACH(cs) { 453182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 4545b95b8b9SAlexander Graf 455182735efSAndreas Färber cpu->env.mpic_proxy = enabled; 4565b95b8b9SAlexander Graf if (kvm_enabled()) { 457182735efSAndreas Färber kvmppc_set_mpic_proxy(cpu, enabled); 4585b95b8b9SAlexander Graf } 459e49798b1SAlexander Graf } 460e49798b1SAlexander Graf } 461e49798b1SAlexander Graf 4629fddaa0cSbellard /*****************************************************************************/ 463e9df014cSj_mayer /* PowerPC time base and decrementer emulation */ 4649fddaa0cSbellard 465ddd1055bSFabien Chouteau uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) 4669fddaa0cSbellard { 4679fddaa0cSbellard /* TB time in tb periods */ 468*73bcb24dSRutuja Shah return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset; 4699fddaa0cSbellard } 4709fddaa0cSbellard 471e2684c0bSAndreas Färber uint64_t cpu_ppc_load_tbl (CPUPPCState *env) 4729fddaa0cSbellard { 473c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 4749fddaa0cSbellard uint64_t tb; 4759fddaa0cSbellard 47690dc8812SScott Wood if (kvm_enabled()) { 47790dc8812SScott Wood return env->spr[SPR_TBL]; 47890dc8812SScott Wood } 47990dc8812SScott Wood 480bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 481d12d51d5Saliguori LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 4829fddaa0cSbellard 483e3ea6529SAlexander Graf return tb; 4849fddaa0cSbellard } 4859fddaa0cSbellard 486e2684c0bSAndreas Färber static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) 4879fddaa0cSbellard { 488c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 4899fddaa0cSbellard uint64_t tb; 4909fddaa0cSbellard 491bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 492d12d51d5Saliguori LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 49376a66253Sj_mayer 4949fddaa0cSbellard return tb >> 32; 4959fddaa0cSbellard } 4969fddaa0cSbellard 497e2684c0bSAndreas Färber uint32_t cpu_ppc_load_tbu (CPUPPCState *env) 4988a84de23Sj_mayer { 49990dc8812SScott Wood if (kvm_enabled()) { 50090dc8812SScott Wood return env->spr[SPR_TBU]; 50190dc8812SScott Wood } 50290dc8812SScott Wood 5038a84de23Sj_mayer return _cpu_ppc_load_tbu(env); 5048a84de23Sj_mayer } 5058a84de23Sj_mayer 506c227f099SAnthony Liguori static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, 507636aa200SBlue Swirl int64_t *tb_offsetp, uint64_t value) 5089fddaa0cSbellard { 509*73bcb24dSRutuja Shah *tb_offsetp = value - 510*73bcb24dSRutuja Shah muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND); 511*73bcb24dSRutuja Shah 512d12d51d5Saliguori LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n", 513aae9366aSj_mayer __func__, value, *tb_offsetp); 514a496775fSj_mayer } 5159fddaa0cSbellard 516e2684c0bSAndreas Färber void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) 5179fddaa0cSbellard { 518c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 519a062e36cSj_mayer uint64_t tb; 5209fddaa0cSbellard 521bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 522a062e36cSj_mayer tb &= 0xFFFFFFFF00000000ULL; 523bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 524dbdd2506Sj_mayer &tb_env->tb_offset, tb | (uint64_t)value); 525a062e36cSj_mayer } 526a062e36cSj_mayer 527e2684c0bSAndreas Färber static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) 528a062e36cSj_mayer { 529c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 530a062e36cSj_mayer uint64_t tb; 531a062e36cSj_mayer 532bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 533a062e36cSj_mayer tb &= 0x00000000FFFFFFFFULL; 534bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 535dbdd2506Sj_mayer &tb_env->tb_offset, ((uint64_t)value << 32) | tb); 536a062e36cSj_mayer } 537a062e36cSj_mayer 538e2684c0bSAndreas Färber void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value) 5398a84de23Sj_mayer { 5408a84de23Sj_mayer _cpu_ppc_store_tbu(env, value); 5418a84de23Sj_mayer } 5428a84de23Sj_mayer 543e2684c0bSAndreas Färber uint64_t cpu_ppc_load_atbl (CPUPPCState *env) 544a062e36cSj_mayer { 545c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 546a062e36cSj_mayer uint64_t tb; 547a062e36cSj_mayer 548bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 549d12d51d5Saliguori LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 550a062e36cSj_mayer 551b711de95SAurelien Jarno return tb; 552a062e36cSj_mayer } 553a062e36cSj_mayer 554e2684c0bSAndreas Färber uint32_t cpu_ppc_load_atbu (CPUPPCState *env) 555a062e36cSj_mayer { 556c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 557a062e36cSj_mayer uint64_t tb; 558a062e36cSj_mayer 559bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 560d12d51d5Saliguori LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 561a062e36cSj_mayer 562a062e36cSj_mayer return tb >> 32; 563a062e36cSj_mayer } 564a062e36cSj_mayer 565e2684c0bSAndreas Färber void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) 566a062e36cSj_mayer { 567c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 568a062e36cSj_mayer uint64_t tb; 569a062e36cSj_mayer 570bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 571a062e36cSj_mayer tb &= 0xFFFFFFFF00000000ULL; 572bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 573dbdd2506Sj_mayer &tb_env->atb_offset, tb | (uint64_t)value); 574a062e36cSj_mayer } 575a062e36cSj_mayer 576e2684c0bSAndreas Färber void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) 577a062e36cSj_mayer { 578c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 579a062e36cSj_mayer uint64_t tb; 580a062e36cSj_mayer 581bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 582a062e36cSj_mayer tb &= 0x00000000FFFFFFFFULL; 583bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 584dbdd2506Sj_mayer &tb_env->atb_offset, ((uint64_t)value << 32) | tb); 585dbdd2506Sj_mayer } 586dbdd2506Sj_mayer 587e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env) 588dbdd2506Sj_mayer { 589c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 590dbdd2506Sj_mayer uint64_t tb, atb, vmclk; 591dbdd2506Sj_mayer 592dbdd2506Sj_mayer /* If the time base is already frozen, do nothing */ 593dbdd2506Sj_mayer if (tb_env->tb_freq != 0) { 594bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 595dbdd2506Sj_mayer /* Get the time base */ 596dbdd2506Sj_mayer tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); 597dbdd2506Sj_mayer /* Get the alternate time base */ 598dbdd2506Sj_mayer atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); 599dbdd2506Sj_mayer /* Store the time base value (ie compute the current offset) */ 600dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 601dbdd2506Sj_mayer /* Store the alternate time base value (compute the current offset) */ 602dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 603dbdd2506Sj_mayer /* Set the time base frequency to zero */ 604dbdd2506Sj_mayer tb_env->tb_freq = 0; 605dbdd2506Sj_mayer /* Now, the time bases are frozen to tb_offset / atb_offset value */ 606dbdd2506Sj_mayer } 607dbdd2506Sj_mayer } 608dbdd2506Sj_mayer 609e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env) 610dbdd2506Sj_mayer { 611c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 612dbdd2506Sj_mayer uint64_t tb, atb, vmclk; 613dbdd2506Sj_mayer 614dbdd2506Sj_mayer /* If the time base is not frozen, do nothing */ 615dbdd2506Sj_mayer if (tb_env->tb_freq == 0) { 616bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 617dbdd2506Sj_mayer /* Get the time base from tb_offset */ 618dbdd2506Sj_mayer tb = tb_env->tb_offset; 619dbdd2506Sj_mayer /* Get the alternate time base from atb_offset */ 620dbdd2506Sj_mayer atb = tb_env->atb_offset; 621dbdd2506Sj_mayer /* Restore the tb frequency from the decrementer frequency */ 622dbdd2506Sj_mayer tb_env->tb_freq = tb_env->decr_freq; 623dbdd2506Sj_mayer /* Store the time base value */ 624dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 625dbdd2506Sj_mayer /* Store the alternate time base value */ 626dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 627dbdd2506Sj_mayer } 6289fddaa0cSbellard } 6299fddaa0cSbellard 630e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env) 631e81a982aSAlexander Graf { 632e81a982aSAlexander Graf ppc_tb_t *tb_env = env->tb_env; 633e81a982aSAlexander Graf int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL; 634e81a982aSAlexander Graf return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED); 635e81a982aSAlexander Graf } 636e81a982aSAlexander Graf 637e2684c0bSAndreas Färber static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) 6389fddaa0cSbellard { 639c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 6409fddaa0cSbellard uint32_t decr; 6414e588a4dSbellard int64_t diff; 6429fddaa0cSbellard 643bc72ad67SAlex Bligh diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 644ddd1055bSFabien Chouteau if (diff >= 0) { 645*73bcb24dSRutuja Shah decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 646ddd1055bSFabien Chouteau } else if (tb_env->flags & PPC_TIMER_BOOKE) { 647ddd1055bSFabien Chouteau decr = 0; 648ddd1055bSFabien Chouteau } else { 649*73bcb24dSRutuja Shah decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 650ddd1055bSFabien Chouteau } 651d12d51d5Saliguori LOG_TB("%s: %08" PRIx32 "\n", __func__, decr); 65276a66253Sj_mayer 6539fddaa0cSbellard return decr; 6549fddaa0cSbellard } 6559fddaa0cSbellard 656e2684c0bSAndreas Färber uint32_t cpu_ppc_load_decr (CPUPPCState *env) 65758a7d328Sj_mayer { 658c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 65958a7d328Sj_mayer 66090dc8812SScott Wood if (kvm_enabled()) { 66190dc8812SScott Wood return env->spr[SPR_DECR]; 66290dc8812SScott Wood } 66390dc8812SScott Wood 664f55e9d9aSTristan Gingold return _cpu_ppc_load_decr(env, tb_env->decr_next); 66558a7d328Sj_mayer } 66658a7d328Sj_mayer 667e2684c0bSAndreas Färber uint32_t cpu_ppc_load_hdecr (CPUPPCState *env) 66858a7d328Sj_mayer { 669c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 67058a7d328Sj_mayer 671f55e9d9aSTristan Gingold return _cpu_ppc_load_decr(env, tb_env->hdecr_next); 67258a7d328Sj_mayer } 67358a7d328Sj_mayer 674e2684c0bSAndreas Färber uint64_t cpu_ppc_load_purr (CPUPPCState *env) 67558a7d328Sj_mayer { 676c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 67758a7d328Sj_mayer uint64_t diff; 67858a7d328Sj_mayer 679bc72ad67SAlex Bligh diff = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - tb_env->purr_start; 68058a7d328Sj_mayer 681*73bcb24dSRutuja Shah return tb_env->purr_load + 682*73bcb24dSRutuja Shah muldiv64(diff, tb_env->tb_freq, NANOSECONDS_PER_SECOND); 68358a7d328Sj_mayer } 68458a7d328Sj_mayer 6859fddaa0cSbellard /* When decrementer expires, 6869fddaa0cSbellard * all we need to do is generate or queue a CPU exception 6879fddaa0cSbellard */ 6887e0a9247SAndreas Färber static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) 6899fddaa0cSbellard { 6909fddaa0cSbellard /* Raise it */ 691d12d51d5Saliguori LOG_TB("raise decrementer exception\n"); 6927058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); 6939fddaa0cSbellard } 6949fddaa0cSbellard 695e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu) 696e81a982aSAlexander Graf { 697e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0); 698e81a982aSAlexander Graf } 699e81a982aSAlexander Graf 7007e0a9247SAndreas Färber static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) 70158a7d328Sj_mayer { 70258a7d328Sj_mayer /* Raise it */ 703d12d51d5Saliguori LOG_TB("raise decrementer exception\n"); 7047058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); 70558a7d328Sj_mayer } 70658a7d328Sj_mayer 707e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) 708e81a982aSAlexander Graf { 709e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); 710e81a982aSAlexander Graf } 711e81a982aSAlexander Graf 7127e0a9247SAndreas Färber static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, 7131246b259SStefan Weil QEMUTimer *timer, 714e81a982aSAlexander Graf void (*raise_excp)(void *), 715e81a982aSAlexander Graf void (*lower_excp)(PowerPCCPU *), 716e81a982aSAlexander Graf uint32_t decr, uint32_t value) 7179fddaa0cSbellard { 7187e0a9247SAndreas Färber CPUPPCState *env = &cpu->env; 719c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 7209fddaa0cSbellard uint64_t now, next; 7219fddaa0cSbellard 722d12d51d5Saliguori LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__, 723aae9366aSj_mayer decr, value); 72455f7d4b0SDavid Gibson 72555f7d4b0SDavid Gibson if (kvm_enabled()) { 72655f7d4b0SDavid Gibson /* KVM handles decrementer exceptions, we don't need our own timer */ 72755f7d4b0SDavid Gibson return; 72855f7d4b0SDavid Gibson } 72955f7d4b0SDavid Gibson 730e81a982aSAlexander Graf /* 731e81a982aSAlexander Graf * Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC 732e81a982aSAlexander Graf * interrupt. 733e81a982aSAlexander Graf * 734e81a982aSAlexander Graf * If we get a really small DEC value, we can assume that by the time we 735e81a982aSAlexander Graf * handled it we should inject an interrupt already. 736e81a982aSAlexander Graf * 737e81a982aSAlexander Graf * On MSB level based DEC implementations the MSB always means the interrupt 738e81a982aSAlexander Graf * is pending, so raise it on those. 739e81a982aSAlexander Graf * 740e81a982aSAlexander Graf * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers 741e81a982aSAlexander Graf * an edge interrupt, so raise it here too. 742e81a982aSAlexander Graf */ 743e81a982aSAlexander Graf if ((value < 3) || 744e81a982aSAlexander Graf ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && (value & 0x80000000)) || 745e81a982aSAlexander Graf ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000) 746e81a982aSAlexander Graf && !(decr & 0x80000000))) { 747e81a982aSAlexander Graf (*raise_excp)(cpu); 748e81a982aSAlexander Graf return; 749e81a982aSAlexander Graf } 750e81a982aSAlexander Graf 751e81a982aSAlexander Graf /* On MSB level based systems a 0 for the MSB stops interrupt delivery */ 752e81a982aSAlexander Graf if (!(value & 0x80000000) && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) { 753e81a982aSAlexander Graf (*lower_excp)(cpu); 754e81a982aSAlexander Graf } 755e81a982aSAlexander Graf 756e81a982aSAlexander Graf /* Calculate the next timer event */ 757bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 758*73bcb24dSRutuja Shah next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 75958a7d328Sj_mayer *nextp = next; 760e81a982aSAlexander Graf 7619fddaa0cSbellard /* Adjust timer */ 762bc72ad67SAlex Bligh timer_mod(timer, next); 763ddd1055bSFabien Chouteau } 76458a7d328Sj_mayer 7657e0a9247SAndreas Färber static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr, 766e81a982aSAlexander Graf uint32_t value) 76758a7d328Sj_mayer { 7687e0a9247SAndreas Färber ppc_tb_t *tb_env = cpu->env.tb_env; 76958a7d328Sj_mayer 7707e0a9247SAndreas Färber __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, 771e81a982aSAlexander Graf tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr, 772e81a982aSAlexander Graf value); 7739fddaa0cSbellard } 7749fddaa0cSbellard 775e2684c0bSAndreas Färber void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value) 7769fddaa0cSbellard { 7777e0a9247SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 7787e0a9247SAndreas Färber 779e81a982aSAlexander Graf _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value); 7809fddaa0cSbellard } 7819fddaa0cSbellard 7829fddaa0cSbellard static void cpu_ppc_decr_cb(void *opaque) 7839fddaa0cSbellard { 78450c680f0SAndreas Färber PowerPCCPU *cpu = opaque; 7857e0a9247SAndreas Färber 786e81a982aSAlexander Graf cpu_ppc_decr_excp(cpu); 7879fddaa0cSbellard } 7889fddaa0cSbellard 7897e0a9247SAndreas Färber static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr, 790e81a982aSAlexander Graf uint32_t value) 79158a7d328Sj_mayer { 7927e0a9247SAndreas Färber ppc_tb_t *tb_env = cpu->env.tb_env; 79358a7d328Sj_mayer 794b172c56aSj_mayer if (tb_env->hdecr_timer != NULL) { 7957e0a9247SAndreas Färber __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, 796e81a982aSAlexander Graf tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower, 797e81a982aSAlexander Graf hdecr, value); 79858a7d328Sj_mayer } 799b172c56aSj_mayer } 80058a7d328Sj_mayer 801e2684c0bSAndreas Färber void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value) 80258a7d328Sj_mayer { 8037e0a9247SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 8047e0a9247SAndreas Färber 805e81a982aSAlexander Graf _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value); 80658a7d328Sj_mayer } 80758a7d328Sj_mayer 80858a7d328Sj_mayer static void cpu_ppc_hdecr_cb(void *opaque) 80958a7d328Sj_mayer { 81050c680f0SAndreas Färber PowerPCCPU *cpu = opaque; 8117e0a9247SAndreas Färber 812e81a982aSAlexander Graf cpu_ppc_hdecr_excp(cpu); 81358a7d328Sj_mayer } 81458a7d328Sj_mayer 8157e0a9247SAndreas Färber static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value) 81658a7d328Sj_mayer { 8177e0a9247SAndreas Färber ppc_tb_t *tb_env = cpu->env.tb_env; 81858a7d328Sj_mayer 81958a7d328Sj_mayer tb_env->purr_load = value; 820bc72ad67SAlex Bligh tb_env->purr_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 82158a7d328Sj_mayer } 82258a7d328Sj_mayer 8238ecc7913Sj_mayer static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) 8248ecc7913Sj_mayer { 825e2684c0bSAndreas Färber CPUPPCState *env = opaque; 8267e0a9247SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 827c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 8288ecc7913Sj_mayer 8298ecc7913Sj_mayer tb_env->tb_freq = freq; 830dbdd2506Sj_mayer tb_env->decr_freq = freq; 8318ecc7913Sj_mayer /* There is a bug in Linux 2.4 kernels: 8328ecc7913Sj_mayer * if a decrementer exception is pending when it enables msr_ee at startup, 8338ecc7913Sj_mayer * it's not ready to handle it... 8348ecc7913Sj_mayer */ 835e81a982aSAlexander Graf _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF); 836e81a982aSAlexander Graf _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF); 8377e0a9247SAndreas Färber cpu_ppc_store_purr(cpu, 0x0000000000000000ULL); 8388ecc7913Sj_mayer } 8398ecc7913Sj_mayer 84098a8b524SAlexey Kardashevskiy static void timebase_pre_save(void *opaque) 84198a8b524SAlexey Kardashevskiy { 84298a8b524SAlexey Kardashevskiy PPCTimebase *tb = opaque; 8434a7428c5SChristopher Covington uint64_t ticks = cpu_get_host_ticks(); 84498a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 84598a8b524SAlexey Kardashevskiy 84698a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 84798a8b524SAlexey Kardashevskiy error_report("No timebase object"); 84898a8b524SAlexey Kardashevskiy return; 84998a8b524SAlexey Kardashevskiy } 85098a8b524SAlexey Kardashevskiy 85177bad151SPaolo Bonzini tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); 85298a8b524SAlexey Kardashevskiy /* 85398a8b524SAlexey Kardashevskiy * tb_offset is only expected to be changed by migration so 85498a8b524SAlexey Kardashevskiy * there is no need to update it from KVM here 85598a8b524SAlexey Kardashevskiy */ 85698a8b524SAlexey Kardashevskiy tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; 85798a8b524SAlexey Kardashevskiy } 85898a8b524SAlexey Kardashevskiy 85998a8b524SAlexey Kardashevskiy static int timebase_post_load(void *opaque, int version_id) 86098a8b524SAlexey Kardashevskiy { 86198a8b524SAlexey Kardashevskiy PPCTimebase *tb_remote = opaque; 86298a8b524SAlexey Kardashevskiy CPUState *cpu; 86398a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 86498a8b524SAlexey Kardashevskiy int64_t tb_off_adj, tb_off, ns_diff; 86598a8b524SAlexey Kardashevskiy int64_t migration_duration_ns, migration_duration_tb, guest_tb, host_ns; 86698a8b524SAlexey Kardashevskiy unsigned long freq; 86798a8b524SAlexey Kardashevskiy 86898a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 86998a8b524SAlexey Kardashevskiy error_report("No timebase object"); 87098a8b524SAlexey Kardashevskiy return -1; 87198a8b524SAlexey Kardashevskiy } 87298a8b524SAlexey Kardashevskiy 87398a8b524SAlexey Kardashevskiy freq = first_ppc_cpu->env.tb_env->tb_freq; 87498a8b524SAlexey Kardashevskiy /* 87598a8b524SAlexey Kardashevskiy * Calculate timebase on the destination side of migration. 87698a8b524SAlexey Kardashevskiy * The destination timebase must be not less than the source timebase. 87798a8b524SAlexey Kardashevskiy * We try to adjust timebase by downtime if host clocks are not 87898a8b524SAlexey Kardashevskiy * too much out of sync (1 second for now). 87998a8b524SAlexey Kardashevskiy */ 88077bad151SPaolo Bonzini host_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); 88198a8b524SAlexey Kardashevskiy ns_diff = MAX(0, host_ns - tb_remote->time_of_the_day_ns); 88213566fe3SStefan Hajnoczi migration_duration_ns = MIN(NANOSECONDS_PER_SECOND, ns_diff); 88313566fe3SStefan Hajnoczi migration_duration_tb = muldiv64(migration_duration_ns, freq, 88413566fe3SStefan Hajnoczi NANOSECONDS_PER_SECOND); 88598a8b524SAlexey Kardashevskiy guest_tb = tb_remote->guest_timebase + MIN(0, migration_duration_tb); 88698a8b524SAlexey Kardashevskiy 8874a7428c5SChristopher Covington tb_off_adj = guest_tb - cpu_get_host_ticks(); 88898a8b524SAlexey Kardashevskiy 88998a8b524SAlexey Kardashevskiy tb_off = first_ppc_cpu->env.tb_env->tb_offset; 89098a8b524SAlexey Kardashevskiy trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off, 89198a8b524SAlexey Kardashevskiy (tb_off_adj - tb_off) / freq); 89298a8b524SAlexey Kardashevskiy 89398a8b524SAlexey Kardashevskiy /* Set new offset to all CPUs */ 89498a8b524SAlexey Kardashevskiy CPU_FOREACH(cpu) { 89598a8b524SAlexey Kardashevskiy PowerPCCPU *pcpu = POWERPC_CPU(cpu); 89698a8b524SAlexey Kardashevskiy pcpu->env.tb_env->tb_offset = tb_off_adj; 89798a8b524SAlexey Kardashevskiy } 89898a8b524SAlexey Kardashevskiy 89998a8b524SAlexey Kardashevskiy return 0; 90098a8b524SAlexey Kardashevskiy } 90198a8b524SAlexey Kardashevskiy 90298a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = { 90398a8b524SAlexey Kardashevskiy .name = "timebase", 90498a8b524SAlexey Kardashevskiy .version_id = 1, 90598a8b524SAlexey Kardashevskiy .minimum_version_id = 1, 90698a8b524SAlexey Kardashevskiy .minimum_version_id_old = 1, 90798a8b524SAlexey Kardashevskiy .pre_save = timebase_pre_save, 90898a8b524SAlexey Kardashevskiy .post_load = timebase_post_load, 90998a8b524SAlexey Kardashevskiy .fields = (VMStateField []) { 91098a8b524SAlexey Kardashevskiy VMSTATE_UINT64(guest_timebase, PPCTimebase), 91198a8b524SAlexey Kardashevskiy VMSTATE_INT64(time_of_the_day_ns, PPCTimebase), 91298a8b524SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 91398a8b524SAlexey Kardashevskiy }, 91498a8b524SAlexey Kardashevskiy }; 91598a8b524SAlexey Kardashevskiy 9169fddaa0cSbellard /* Set up (once) timebase frequency (in Hz) */ 917e2684c0bSAndreas Färber clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) 9189fddaa0cSbellard { 91950c680f0SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 920c227f099SAnthony Liguori ppc_tb_t *tb_env; 9219fddaa0cSbellard 9227267c094SAnthony Liguori tb_env = g_malloc0(sizeof(ppc_tb_t)); 9239fddaa0cSbellard env->tb_env = tb_env; 924ddd1055bSFabien Chouteau tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 925e81a982aSAlexander Graf if (env->insns_flags & PPC_SEGMENT_64B) { 926e81a982aSAlexander Graf /* All Book3S 64bit CPUs implement level based DEC logic */ 927e81a982aSAlexander Graf tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL; 928e81a982aSAlexander Graf } 9299fddaa0cSbellard /* Create new timer */ 930bc72ad67SAlex Bligh tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); 931b172c56aSj_mayer if (0) { 932b172c56aSj_mayer /* XXX: find a suitable condition to enable the hypervisor decrementer 933b172c56aSj_mayer */ 934bc72ad67SAlex Bligh tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, 93550c680f0SAndreas Färber cpu); 936b172c56aSj_mayer } else { 937b172c56aSj_mayer tb_env->hdecr_timer = NULL; 938b172c56aSj_mayer } 9398ecc7913Sj_mayer cpu_ppc_set_tb_clk(env, freq); 9409fddaa0cSbellard 9418ecc7913Sj_mayer return &cpu_ppc_set_tb_clk; 9429fddaa0cSbellard } 9439fddaa0cSbellard 94476a66253Sj_mayer /* Specific helpers for POWER & PowerPC 601 RTC */ 945b1d8e52eSblueswir1 #if 0 946e2684c0bSAndreas Färber static clk_setup_cb cpu_ppc601_rtc_init (CPUPPCState *env) 94776a66253Sj_mayer { 94876a66253Sj_mayer return cpu_ppc_tb_init(env, 7812500); 94976a66253Sj_mayer } 950b1d8e52eSblueswir1 #endif 95176a66253Sj_mayer 952e2684c0bSAndreas Färber void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value) 9538a84de23Sj_mayer { 9548a84de23Sj_mayer _cpu_ppc_store_tbu(env, value); 9558a84de23Sj_mayer } 95676a66253Sj_mayer 957e2684c0bSAndreas Färber uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env) 9588a84de23Sj_mayer { 9598a84de23Sj_mayer return _cpu_ppc_load_tbu(env); 9608a84de23Sj_mayer } 96176a66253Sj_mayer 962e2684c0bSAndreas Färber void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value) 96376a66253Sj_mayer { 96476a66253Sj_mayer cpu_ppc_store_tbl(env, value & 0x3FFFFF80); 96576a66253Sj_mayer } 96676a66253Sj_mayer 967e2684c0bSAndreas Färber uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env) 96876a66253Sj_mayer { 96976a66253Sj_mayer return cpu_ppc_load_tbl(env) & 0x3FFFFF80; 97076a66253Sj_mayer } 97176a66253Sj_mayer 972636aaad7Sj_mayer /*****************************************************************************/ 973ddd1055bSFabien Chouteau /* PowerPC 40x timers */ 974636aaad7Sj_mayer 975636aaad7Sj_mayer /* PIT, FIT & WDT */ 976ddd1055bSFabien Chouteau typedef struct ppc40x_timer_t ppc40x_timer_t; 977ddd1055bSFabien Chouteau struct ppc40x_timer_t { 978636aaad7Sj_mayer uint64_t pit_reload; /* PIT auto-reload value */ 979636aaad7Sj_mayer uint64_t fit_next; /* Tick for next FIT interrupt */ 9801246b259SStefan Weil QEMUTimer *fit_timer; 981636aaad7Sj_mayer uint64_t wdt_next; /* Tick for next WDT interrupt */ 9821246b259SStefan Weil QEMUTimer *wdt_timer; 983d63cb48dSEdgar E. Iglesias 984d63cb48dSEdgar E. Iglesias /* 405 have the PIT, 440 have a DECR. */ 985d63cb48dSEdgar E. Iglesias unsigned int decr_excp; 986636aaad7Sj_mayer }; 987636aaad7Sj_mayer 988636aaad7Sj_mayer /* Fixed interval timer */ 989636aaad7Sj_mayer static void cpu_4xx_fit_cb (void *opaque) 99076a66253Sj_mayer { 9917058581aSAndreas Färber PowerPCCPU *cpu; 992e2684c0bSAndreas Färber CPUPPCState *env; 993c227f099SAnthony Liguori ppc_tb_t *tb_env; 994ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 995636aaad7Sj_mayer uint64_t now, next; 996636aaad7Sj_mayer 997636aaad7Sj_mayer env = opaque; 9987058581aSAndreas Färber cpu = ppc_env_get_cpu(env); 999636aaad7Sj_mayer tb_env = env->tb_env; 1000ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1001bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1002636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { 1003636aaad7Sj_mayer case 0: 1004636aaad7Sj_mayer next = 1 << 9; 1005636aaad7Sj_mayer break; 1006636aaad7Sj_mayer case 1: 1007636aaad7Sj_mayer next = 1 << 13; 1008636aaad7Sj_mayer break; 1009636aaad7Sj_mayer case 2: 1010636aaad7Sj_mayer next = 1 << 17; 1011636aaad7Sj_mayer break; 1012636aaad7Sj_mayer case 3: 1013636aaad7Sj_mayer next = 1 << 21; 1014636aaad7Sj_mayer break; 1015636aaad7Sj_mayer default: 1016636aaad7Sj_mayer /* Cannot occur, but makes gcc happy */ 1017636aaad7Sj_mayer return; 1018636aaad7Sj_mayer } 1019*73bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq); 1020636aaad7Sj_mayer if (next == now) 1021636aaad7Sj_mayer next++; 1022bc72ad67SAlex Bligh timer_mod(ppc40x_timer->fit_timer, next); 1023636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 26; 10247058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { 10257058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); 10267058581aSAndreas Färber } 102790e189ecSBlue Swirl LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, 1028e96efcfcSj_mayer (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), 1029636aaad7Sj_mayer env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 1030636aaad7Sj_mayer } 1031636aaad7Sj_mayer 1032636aaad7Sj_mayer /* Programmable interval timer */ 1033e2684c0bSAndreas Färber static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) 1034636aaad7Sj_mayer { 1035ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1036636aaad7Sj_mayer uint64_t now, next; 1037636aaad7Sj_mayer 1038ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1039ddd1055bSFabien Chouteau if (ppc40x_timer->pit_reload <= 1 || 10404b6d0a4cSj_mayer !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || 10414b6d0a4cSj_mayer (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { 10424b6d0a4cSj_mayer /* Stop PIT */ 1043d12d51d5Saliguori LOG_TB("%s: stop PIT\n", __func__); 1044bc72ad67SAlex Bligh timer_del(tb_env->decr_timer); 10454b6d0a4cSj_mayer } else { 1046d12d51d5Saliguori LOG_TB("%s: start PIT %016" PRIx64 "\n", 1047ddd1055bSFabien Chouteau __func__, ppc40x_timer->pit_reload); 1048bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1049ddd1055bSFabien Chouteau next = now + muldiv64(ppc40x_timer->pit_reload, 1050*73bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, tb_env->decr_freq); 10514b6d0a4cSj_mayer if (is_excp) 10524b6d0a4cSj_mayer next += tb_env->decr_next - now; 1053636aaad7Sj_mayer if (next == now) 1054636aaad7Sj_mayer next++; 1055bc72ad67SAlex Bligh timer_mod(tb_env->decr_timer, next); 1056636aaad7Sj_mayer tb_env->decr_next = next; 1057636aaad7Sj_mayer } 10584b6d0a4cSj_mayer } 10594b6d0a4cSj_mayer 10604b6d0a4cSj_mayer static void cpu_4xx_pit_cb (void *opaque) 10614b6d0a4cSj_mayer { 10627058581aSAndreas Färber PowerPCCPU *cpu; 1063e2684c0bSAndreas Färber CPUPPCState *env; 1064c227f099SAnthony Liguori ppc_tb_t *tb_env; 1065ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 10664b6d0a4cSj_mayer 10674b6d0a4cSj_mayer env = opaque; 10687058581aSAndreas Färber cpu = ppc_env_get_cpu(env); 10694b6d0a4cSj_mayer tb_env = env->tb_env; 1070ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1071636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 27; 10727058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { 10737058581aSAndreas Färber ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); 10747058581aSAndreas Färber } 10754b6d0a4cSj_mayer start_stop_pit(env, tb_env, 1); 107690e189ecSBlue Swirl LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " " 1077e96efcfcSj_mayer "%016" PRIx64 "\n", __func__, 1078e96efcfcSj_mayer (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), 1079e96efcfcSj_mayer (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), 1080636aaad7Sj_mayer env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], 1081ddd1055bSFabien Chouteau ppc40x_timer->pit_reload); 1082636aaad7Sj_mayer } 1083636aaad7Sj_mayer 1084636aaad7Sj_mayer /* Watchdog timer */ 1085636aaad7Sj_mayer static void cpu_4xx_wdt_cb (void *opaque) 1086636aaad7Sj_mayer { 10877058581aSAndreas Färber PowerPCCPU *cpu; 1088e2684c0bSAndreas Färber CPUPPCState *env; 1089c227f099SAnthony Liguori ppc_tb_t *tb_env; 1090ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1091636aaad7Sj_mayer uint64_t now, next; 1092636aaad7Sj_mayer 1093636aaad7Sj_mayer env = opaque; 10947058581aSAndreas Färber cpu = ppc_env_get_cpu(env); 1095636aaad7Sj_mayer tb_env = env->tb_env; 1096ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1097bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1098636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { 1099636aaad7Sj_mayer case 0: 1100636aaad7Sj_mayer next = 1 << 17; 1101636aaad7Sj_mayer break; 1102636aaad7Sj_mayer case 1: 1103636aaad7Sj_mayer next = 1 << 21; 1104636aaad7Sj_mayer break; 1105636aaad7Sj_mayer case 2: 1106636aaad7Sj_mayer next = 1 << 25; 1107636aaad7Sj_mayer break; 1108636aaad7Sj_mayer case 3: 1109636aaad7Sj_mayer next = 1 << 29; 1110636aaad7Sj_mayer break; 1111636aaad7Sj_mayer default: 1112636aaad7Sj_mayer /* Cannot occur, but makes gcc happy */ 1113636aaad7Sj_mayer return; 1114636aaad7Sj_mayer } 1115*73bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 1116636aaad7Sj_mayer if (next == now) 1117636aaad7Sj_mayer next++; 111890e189ecSBlue Swirl LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, 1119636aaad7Sj_mayer env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 1120636aaad7Sj_mayer switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { 1121636aaad7Sj_mayer case 0x0: 1122636aaad7Sj_mayer case 0x1: 1123bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 1124ddd1055bSFabien Chouteau ppc40x_timer->wdt_next = next; 1125a1f7f97bSPeter Maydell env->spr[SPR_40x_TSR] |= 1U << 31; 1126636aaad7Sj_mayer break; 1127636aaad7Sj_mayer case 0x2: 1128bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 1129ddd1055bSFabien Chouteau ppc40x_timer->wdt_next = next; 1130636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 30; 11317058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { 11327058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); 11337058581aSAndreas Färber } 1134636aaad7Sj_mayer break; 1135636aaad7Sj_mayer case 0x3: 1136636aaad7Sj_mayer env->spr[SPR_40x_TSR] &= ~0x30000000; 1137636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000; 1138636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) { 1139636aaad7Sj_mayer case 0x0: 1140636aaad7Sj_mayer /* No reset */ 1141636aaad7Sj_mayer break; 1142636aaad7Sj_mayer case 0x1: /* Core reset */ 1143f3273ba6SAndreas Färber ppc40x_core_reset(cpu); 11448ecc7913Sj_mayer break; 1145636aaad7Sj_mayer case 0x2: /* Chip reset */ 1146f3273ba6SAndreas Färber ppc40x_chip_reset(cpu); 11478ecc7913Sj_mayer break; 1148636aaad7Sj_mayer case 0x3: /* System reset */ 1149f3273ba6SAndreas Färber ppc40x_system_reset(cpu); 11508ecc7913Sj_mayer break; 1151636aaad7Sj_mayer } 1152636aaad7Sj_mayer } 115376a66253Sj_mayer } 115476a66253Sj_mayer 1155e2684c0bSAndreas Färber void store_40x_pit (CPUPPCState *env, target_ulong val) 115676a66253Sj_mayer { 1157c227f099SAnthony Liguori ppc_tb_t *tb_env; 1158ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1159636aaad7Sj_mayer 1160636aaad7Sj_mayer tb_env = env->tb_env; 1161ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 116290e189ecSBlue Swirl LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val); 1163ddd1055bSFabien Chouteau ppc40x_timer->pit_reload = val; 11644b6d0a4cSj_mayer start_stop_pit(env, tb_env, 0); 116576a66253Sj_mayer } 116676a66253Sj_mayer 1167e2684c0bSAndreas Färber target_ulong load_40x_pit (CPUPPCState *env) 116876a66253Sj_mayer { 1169636aaad7Sj_mayer return cpu_ppc_load_decr(env); 117076a66253Sj_mayer } 117176a66253Sj_mayer 1172ddd1055bSFabien Chouteau static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq) 11734b6d0a4cSj_mayer { 1174e2684c0bSAndreas Färber CPUPPCState *env = opaque; 1175c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 11764b6d0a4cSj_mayer 1177d12d51d5Saliguori LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__, 1178aae9366aSj_mayer freq); 11794b6d0a4cSj_mayer tb_env->tb_freq = freq; 1180dbdd2506Sj_mayer tb_env->decr_freq = freq; 11814b6d0a4cSj_mayer /* XXX: we should also update all timers */ 11824b6d0a4cSj_mayer } 11834b6d0a4cSj_mayer 1184e2684c0bSAndreas Färber clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, 1185d63cb48dSEdgar E. Iglesias unsigned int decr_excp) 1186636aaad7Sj_mayer { 1187c227f099SAnthony Liguori ppc_tb_t *tb_env; 1188ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1189636aaad7Sj_mayer 11907267c094SAnthony Liguori tb_env = g_malloc0(sizeof(ppc_tb_t)); 11918ecc7913Sj_mayer env->tb_env = tb_env; 1192ddd1055bSFabien Chouteau tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 1193ddd1055bSFabien Chouteau ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t)); 11948ecc7913Sj_mayer tb_env->tb_freq = freq; 1195dbdd2506Sj_mayer tb_env->decr_freq = freq; 1196ddd1055bSFabien Chouteau tb_env->opaque = ppc40x_timer; 1197d12d51d5Saliguori LOG_TB("%s freq %" PRIu32 "\n", __func__, freq); 1198ddd1055bSFabien Chouteau if (ppc40x_timer != NULL) { 1199636aaad7Sj_mayer /* We use decr timer for PIT */ 1200bc72ad67SAlex Bligh tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, env); 1201ddd1055bSFabien Chouteau ppc40x_timer->fit_timer = 1202bc72ad67SAlex Bligh timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, env); 1203ddd1055bSFabien Chouteau ppc40x_timer->wdt_timer = 1204bc72ad67SAlex Bligh timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, env); 1205ddd1055bSFabien Chouteau ppc40x_timer->decr_excp = decr_excp; 1206636aaad7Sj_mayer } 12078ecc7913Sj_mayer 1208ddd1055bSFabien Chouteau return &ppc_40x_set_tb_clk; 120976a66253Sj_mayer } 121076a66253Sj_mayer 12112e719ba3Sj_mayer /*****************************************************************************/ 12122e719ba3Sj_mayer /* Embedded PowerPC Device Control Registers */ 1213c227f099SAnthony Liguori typedef struct ppc_dcrn_t ppc_dcrn_t; 1214c227f099SAnthony Liguori struct ppc_dcrn_t { 12152e719ba3Sj_mayer dcr_read_cb dcr_read; 12162e719ba3Sj_mayer dcr_write_cb dcr_write; 12172e719ba3Sj_mayer void *opaque; 12182e719ba3Sj_mayer }; 12192e719ba3Sj_mayer 1220a750fc0bSj_mayer /* XXX: on 460, DCR addresses are 32 bits wide, 1221a750fc0bSj_mayer * using DCRIPR to get the 22 upper bits of the DCR address 1222a750fc0bSj_mayer */ 12232e719ba3Sj_mayer #define DCRN_NB 1024 1224c227f099SAnthony Liguori struct ppc_dcr_t { 1225c227f099SAnthony Liguori ppc_dcrn_t dcrn[DCRN_NB]; 12262e719ba3Sj_mayer int (*read_error)(int dcrn); 12272e719ba3Sj_mayer int (*write_error)(int dcrn); 12282e719ba3Sj_mayer }; 12292e719ba3Sj_mayer 123073b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) 12312e719ba3Sj_mayer { 1232c227f099SAnthony Liguori ppc_dcrn_t *dcr; 12332e719ba3Sj_mayer 12342e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 12352e719ba3Sj_mayer goto error; 12362e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 12372e719ba3Sj_mayer if (dcr->dcr_read == NULL) 12382e719ba3Sj_mayer goto error; 12392e719ba3Sj_mayer *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); 12402e719ba3Sj_mayer 12412e719ba3Sj_mayer return 0; 12422e719ba3Sj_mayer 12432e719ba3Sj_mayer error: 12442e719ba3Sj_mayer if (dcr_env->read_error != NULL) 12452e719ba3Sj_mayer return (*dcr_env->read_error)(dcrn); 12462e719ba3Sj_mayer 12472e719ba3Sj_mayer return -1; 12482e719ba3Sj_mayer } 12492e719ba3Sj_mayer 125073b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) 12512e719ba3Sj_mayer { 1252c227f099SAnthony Liguori ppc_dcrn_t *dcr; 12532e719ba3Sj_mayer 12542e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 12552e719ba3Sj_mayer goto error; 12562e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 12572e719ba3Sj_mayer if (dcr->dcr_write == NULL) 12582e719ba3Sj_mayer goto error; 12592e719ba3Sj_mayer (*dcr->dcr_write)(dcr->opaque, dcrn, val); 12602e719ba3Sj_mayer 12612e719ba3Sj_mayer return 0; 12622e719ba3Sj_mayer 12632e719ba3Sj_mayer error: 12642e719ba3Sj_mayer if (dcr_env->write_error != NULL) 12652e719ba3Sj_mayer return (*dcr_env->write_error)(dcrn); 12662e719ba3Sj_mayer 12672e719ba3Sj_mayer return -1; 12682e719ba3Sj_mayer } 12692e719ba3Sj_mayer 1270e2684c0bSAndreas Färber int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, 12712e719ba3Sj_mayer dcr_read_cb dcr_read, dcr_write_cb dcr_write) 12722e719ba3Sj_mayer { 1273c227f099SAnthony Liguori ppc_dcr_t *dcr_env; 1274c227f099SAnthony Liguori ppc_dcrn_t *dcr; 12752e719ba3Sj_mayer 12762e719ba3Sj_mayer dcr_env = env->dcr_env; 12772e719ba3Sj_mayer if (dcr_env == NULL) 12782e719ba3Sj_mayer return -1; 12792e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 12802e719ba3Sj_mayer return -1; 12812e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 12822e719ba3Sj_mayer if (dcr->opaque != NULL || 12832e719ba3Sj_mayer dcr->dcr_read != NULL || 12842e719ba3Sj_mayer dcr->dcr_write != NULL) 12852e719ba3Sj_mayer return -1; 12862e719ba3Sj_mayer dcr->opaque = opaque; 12872e719ba3Sj_mayer dcr->dcr_read = dcr_read; 12882e719ba3Sj_mayer dcr->dcr_write = dcr_write; 12892e719ba3Sj_mayer 12902e719ba3Sj_mayer return 0; 12912e719ba3Sj_mayer } 12922e719ba3Sj_mayer 1293e2684c0bSAndreas Färber int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn), 12942e719ba3Sj_mayer int (*write_error)(int dcrn)) 12952e719ba3Sj_mayer { 1296c227f099SAnthony Liguori ppc_dcr_t *dcr_env; 12972e719ba3Sj_mayer 12987267c094SAnthony Liguori dcr_env = g_malloc0(sizeof(ppc_dcr_t)); 12992e719ba3Sj_mayer dcr_env->read_error = read_error; 13002e719ba3Sj_mayer dcr_env->write_error = write_error; 13012e719ba3Sj_mayer env->dcr_env = dcr_env; 13022e719ba3Sj_mayer 13032e719ba3Sj_mayer return 0; 13042e719ba3Sj_mayer } 13052e719ba3Sj_mayer 130664201201Sbellard /*****************************************************************************/ 130764201201Sbellard /* Debug port */ 1308fd0bbb12Sbellard void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) 130964201201Sbellard { 131064201201Sbellard addr &= 0xF; 131164201201Sbellard switch (addr) { 131264201201Sbellard case 0: 131364201201Sbellard printf("%c", val); 131464201201Sbellard break; 131564201201Sbellard case 1: 131664201201Sbellard printf("\n"); 131764201201Sbellard fflush(stdout); 131864201201Sbellard break; 131964201201Sbellard case 2: 1320aae9366aSj_mayer printf("Set loglevel to %04" PRIx32 "\n", val); 132124537a01SPeter Maydell qemu_set_log(val | 0x100); 132264201201Sbellard break; 132364201201Sbellard } 132464201201Sbellard } 132564201201Sbellard 13260ce470cdSAlexey Kardashevskiy /* CPU device-tree ID helpers */ 13270ce470cdSAlexey Kardashevskiy int ppc_get_vcpu_dt_id(PowerPCCPU *cpu) 13280ce470cdSAlexey Kardashevskiy { 13290ce470cdSAlexey Kardashevskiy return cpu->cpu_dt_id; 13300ce470cdSAlexey Kardashevskiy } 13310ce470cdSAlexey Kardashevskiy 13320ce470cdSAlexey Kardashevskiy PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id) 13330ce470cdSAlexey Kardashevskiy { 13340ce470cdSAlexey Kardashevskiy CPUState *cs; 13350ce470cdSAlexey Kardashevskiy 13360ce470cdSAlexey Kardashevskiy CPU_FOREACH(cs) { 13370ce470cdSAlexey Kardashevskiy PowerPCCPU *cpu = POWERPC_CPU(cs); 13380ce470cdSAlexey Kardashevskiy 13390ce470cdSAlexey Kardashevskiy if (cpu->cpu_dt_id == cpu_dt_id) { 13400ce470cdSAlexey Kardashevskiy return cpu; 13410ce470cdSAlexey Kardashevskiy } 13420ce470cdSAlexey Kardashevskiy } 13430ce470cdSAlexey Kardashevskiy 13440ce470cdSAlexey Kardashevskiy return NULL; 13450ce470cdSAlexey Kardashevskiy } 1346