153018216SPaolo Bonzini /* 253018216SPaolo Bonzini * QEMU generic PowerPC hardware System Emulator 353018216SPaolo Bonzini * 453018216SPaolo Bonzini * Copyright (c) 2003-2007 Jocelyn Mayer 553018216SPaolo Bonzini * 653018216SPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 753018216SPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 853018216SPaolo Bonzini * in the Software without restriction, including without limitation the rights 953018216SPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1053018216SPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 1153018216SPaolo Bonzini * furnished to do so, subject to the following conditions: 1253018216SPaolo Bonzini * 1353018216SPaolo Bonzini * The above copyright notice and this permission notice shall be included in 1453018216SPaolo Bonzini * all copies or substantial portions of the Software. 1553018216SPaolo Bonzini * 1653018216SPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1753018216SPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1853018216SPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1953018216SPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2053018216SPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2153018216SPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2253018216SPaolo Bonzini * THE SOFTWARE. 2353018216SPaolo Bonzini */ 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" 2953018216SPaolo Bonzini #include "qemu/timer.h" 300ce470cdSAlexey Kardashevskiy #include "sysemu/cpus.h" 3153018216SPaolo Bonzini #include "qemu/log.h" 32db725815SMarkus Armbruster #include "qemu/main-loop.h" 3398a8b524SAlexey Kardashevskiy #include "qemu/error-report.h" 3453018216SPaolo Bonzini #include "sysemu/kvm.h" 3554d31236SMarkus Armbruster #include "sysemu/runstate.h" 3653018216SPaolo Bonzini #include "kvm_ppc.h" 37d6454270SMarkus Armbruster #include "migration/vmstate.h" 3898a8b524SAlexey Kardashevskiy #include "trace.h" 3953018216SPaolo Bonzini 4053018216SPaolo Bonzini static void cpu_ppc_tb_stop (CPUPPCState *env); 4153018216SPaolo Bonzini static void cpu_ppc_tb_start (CPUPPCState *env); 4253018216SPaolo Bonzini 43f003109fSMatheus Ferst void ppc_set_irq(PowerPCCPU *cpu, int irq, int level) 4453018216SPaolo Bonzini { 4553018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 468d04fb55SJan Kiszka unsigned int old_pending; 478d04fb55SJan Kiszka bool locked = false; 488d04fb55SJan Kiszka 498d04fb55SJan Kiszka /* We may already have the BQL if coming from the reset path */ 508d04fb55SJan Kiszka if (!qemu_mutex_iothread_locked()) { 518d04fb55SJan Kiszka locked = true; 528d04fb55SJan Kiszka qemu_mutex_lock_iothread(); 538d04fb55SJan Kiszka } 548d04fb55SJan Kiszka 558d04fb55SJan Kiszka old_pending = env->pending_interrupts; 5653018216SPaolo Bonzini 5753018216SPaolo Bonzini if (level) { 58f003109fSMatheus Ferst env->pending_interrupts |= irq; 5953018216SPaolo Bonzini } else { 60f003109fSMatheus Ferst env->pending_interrupts &= ~irq; 6153018216SPaolo Bonzini } 6253018216SPaolo Bonzini 6353018216SPaolo Bonzini if (old_pending != env->pending_interrupts) { 64*2fdedcbcSMatheus Ferst ppc_maybe_interrupt(env); 65f003109fSMatheus Ferst kvmppc_set_interrupt(cpu, irq, level); 6653018216SPaolo Bonzini } 6753018216SPaolo Bonzini 68f003109fSMatheus Ferst trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts, 69af96d2e6SCédric Le Goater CPU(cpu)->interrupt_request); 708d04fb55SJan Kiszka 718d04fb55SJan Kiszka if (locked) { 728d04fb55SJan Kiszka qemu_mutex_unlock_iothread(); 738d04fb55SJan Kiszka } 7453018216SPaolo Bonzini } 7553018216SPaolo Bonzini 7653018216SPaolo Bonzini /* PowerPC 6xx / 7xx internal IRQ controller */ 7753018216SPaolo Bonzini static void ppc6xx_set_irq(void *opaque, int pin, int level) 7853018216SPaolo Bonzini { 7953018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 8053018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 8153018216SPaolo Bonzini int cur_level; 8253018216SPaolo Bonzini 83af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 84af96d2e6SCédric Le Goater 8553018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 8653018216SPaolo Bonzini /* Don't generate spurious events */ 8753018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 88259186a7SAndreas Färber CPUState *cs = CPU(cpu); 89259186a7SAndreas Färber 9053018216SPaolo Bonzini switch (pin) { 9153018216SPaolo Bonzini case PPC6xx_INPUT_TBEN: 9253018216SPaolo Bonzini /* Level sensitive - active high */ 93af96d2e6SCédric Le Goater trace_ppc_irq_set_state("time base", level); 9453018216SPaolo Bonzini if (level) { 9553018216SPaolo Bonzini cpu_ppc_tb_start(env); 9653018216SPaolo Bonzini } else { 9753018216SPaolo Bonzini cpu_ppc_tb_stop(env); 9853018216SPaolo Bonzini } 99b2bd5b20SChen Qun break; 10053018216SPaolo Bonzini case PPC6xx_INPUT_INT: 10153018216SPaolo Bonzini /* Level sensitive - active high */ 102af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 10353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 10453018216SPaolo Bonzini break; 10553018216SPaolo Bonzini case PPC6xx_INPUT_SMI: 10653018216SPaolo Bonzini /* Level sensitive - active high */ 107af96d2e6SCédric Le Goater trace_ppc_irq_set_state("SMI IRQ", level); 10853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); 10953018216SPaolo Bonzini break; 11053018216SPaolo Bonzini case PPC6xx_INPUT_MCP: 11153018216SPaolo Bonzini /* Negative edge sensitive */ 11253018216SPaolo Bonzini /* XXX: TODO: actual reaction may depends on HID0 status 11353018216SPaolo Bonzini * 603/604/740/750: check HID0[EMCP] 11453018216SPaolo Bonzini */ 11553018216SPaolo Bonzini if (cur_level == 1 && level == 0) { 116af96d2e6SCédric Le Goater trace_ppc_irq_set_state("machine check", 1); 11753018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 11853018216SPaolo Bonzini } 11953018216SPaolo Bonzini break; 12053018216SPaolo Bonzini case PPC6xx_INPUT_CKSTP_IN: 12153018216SPaolo Bonzini /* Level sensitive - active low */ 12253018216SPaolo Bonzini /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 12353018216SPaolo Bonzini /* XXX: Note that the only way to restart the CPU is to reset it */ 12453018216SPaolo Bonzini if (level) { 125af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 126259186a7SAndreas Färber cs->halted = 1; 12753018216SPaolo Bonzini } 12853018216SPaolo Bonzini break; 12953018216SPaolo Bonzini case PPC6xx_INPUT_HRESET: 13053018216SPaolo Bonzini /* Level sensitive - active low */ 13153018216SPaolo Bonzini if (level) { 132af96d2e6SCédric Le Goater trace_ppc_irq_reset("CPU"); 133c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 13453018216SPaolo Bonzini } 13553018216SPaolo Bonzini break; 13653018216SPaolo Bonzini case PPC6xx_INPUT_SRESET: 137af96d2e6SCédric Le Goater trace_ppc_irq_set_state("RESET IRQ", level); 13853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 13953018216SPaolo Bonzini break; 14053018216SPaolo Bonzini default: 1417279810bSCédric Le Goater g_assert_not_reached(); 14253018216SPaolo Bonzini } 14353018216SPaolo Bonzini if (level) 14453018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 14553018216SPaolo Bonzini else 14653018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 14753018216SPaolo Bonzini } 14853018216SPaolo Bonzini } 14953018216SPaolo Bonzini 150aa5a9e24SPaolo Bonzini void ppc6xx_irq_init(PowerPCCPU *cpu) 15153018216SPaolo Bonzini { 1520f3e0c6fSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc6xx_set_irq, PPC6xx_INPUT_NB); 15353018216SPaolo Bonzini } 15453018216SPaolo Bonzini 15553018216SPaolo Bonzini #if defined(TARGET_PPC64) 15653018216SPaolo Bonzini /* PowerPC 970 internal IRQ controller */ 15753018216SPaolo Bonzini static void ppc970_set_irq(void *opaque, int pin, int level) 15853018216SPaolo Bonzini { 15953018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 16053018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 16153018216SPaolo Bonzini int cur_level; 16253018216SPaolo Bonzini 163af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 164af96d2e6SCédric Le Goater 16553018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 16653018216SPaolo Bonzini /* Don't generate spurious events */ 16753018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 168259186a7SAndreas Färber CPUState *cs = CPU(cpu); 169259186a7SAndreas Färber 17053018216SPaolo Bonzini switch (pin) { 17153018216SPaolo Bonzini case PPC970_INPUT_INT: 17253018216SPaolo Bonzini /* Level sensitive - active high */ 173af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 17453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 17553018216SPaolo Bonzini break; 17653018216SPaolo Bonzini case PPC970_INPUT_THINT: 17753018216SPaolo Bonzini /* Level sensitive - active high */ 178af96d2e6SCédric Le Goater trace_ppc_irq_set_state("SMI IRQ", level); 17953018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); 18053018216SPaolo Bonzini break; 18153018216SPaolo Bonzini case PPC970_INPUT_MCP: 18253018216SPaolo Bonzini /* Negative edge sensitive */ 18353018216SPaolo Bonzini /* XXX: TODO: actual reaction may depends on HID0 status 18453018216SPaolo Bonzini * 603/604/740/750: check HID0[EMCP] 18553018216SPaolo Bonzini */ 18653018216SPaolo Bonzini if (cur_level == 1 && level == 0) { 187af96d2e6SCédric Le Goater trace_ppc_irq_set_state("machine check", 1); 18853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 18953018216SPaolo Bonzini } 19053018216SPaolo Bonzini break; 19153018216SPaolo Bonzini case PPC970_INPUT_CKSTP: 19253018216SPaolo Bonzini /* Level sensitive - active low */ 19353018216SPaolo Bonzini /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 19453018216SPaolo Bonzini if (level) { 195af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 196259186a7SAndreas Färber cs->halted = 1; 19753018216SPaolo Bonzini } else { 198af96d2e6SCédric Le Goater trace_ppc_irq_cpu("restart"); 199259186a7SAndreas Färber cs->halted = 0; 200259186a7SAndreas Färber qemu_cpu_kick(cs); 20153018216SPaolo Bonzini } 20253018216SPaolo Bonzini break; 20353018216SPaolo Bonzini case PPC970_INPUT_HRESET: 20453018216SPaolo Bonzini /* Level sensitive - active low */ 20553018216SPaolo Bonzini if (level) { 206c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 20753018216SPaolo Bonzini } 20853018216SPaolo Bonzini break; 20953018216SPaolo Bonzini case PPC970_INPUT_SRESET: 210af96d2e6SCédric Le Goater trace_ppc_irq_set_state("RESET IRQ", level); 21153018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 21253018216SPaolo Bonzini break; 21353018216SPaolo Bonzini case PPC970_INPUT_TBEN: 214af96d2e6SCédric Le Goater trace_ppc_irq_set_state("TBEN IRQ", level); 21553018216SPaolo Bonzini /* XXX: TODO */ 21653018216SPaolo Bonzini break; 21753018216SPaolo Bonzini default: 2187279810bSCédric Le Goater g_assert_not_reached(); 21953018216SPaolo Bonzini } 22053018216SPaolo Bonzini if (level) 22153018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 22253018216SPaolo Bonzini else 22353018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 22453018216SPaolo Bonzini } 22553018216SPaolo Bonzini } 22653018216SPaolo Bonzini 227aa5a9e24SPaolo Bonzini void ppc970_irq_init(PowerPCCPU *cpu) 22853018216SPaolo Bonzini { 2299fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc970_set_irq, PPC970_INPUT_NB); 23053018216SPaolo Bonzini } 23153018216SPaolo Bonzini 23253018216SPaolo Bonzini /* POWER7 internal IRQ controller */ 23353018216SPaolo Bonzini static void power7_set_irq(void *opaque, int pin, int level) 23453018216SPaolo Bonzini { 23553018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 23653018216SPaolo Bonzini 237af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 23853018216SPaolo Bonzini 23953018216SPaolo Bonzini switch (pin) { 24053018216SPaolo Bonzini case POWER7_INPUT_INT: 24153018216SPaolo Bonzini /* Level sensitive - active high */ 242af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 24353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 24453018216SPaolo Bonzini break; 24553018216SPaolo Bonzini default: 2467279810bSCédric Le Goater g_assert_not_reached(); 24753018216SPaolo Bonzini } 24853018216SPaolo Bonzini } 24953018216SPaolo Bonzini 250aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu) 25153018216SPaolo Bonzini { 2529fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), power7_set_irq, POWER7_INPUT_NB); 25353018216SPaolo Bonzini } 25467afe775SBenjamin Herrenschmidt 25567afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */ 25667afe775SBenjamin Herrenschmidt static void power9_set_irq(void *opaque, int pin, int level) 25767afe775SBenjamin Herrenschmidt { 25867afe775SBenjamin Herrenschmidt PowerPCCPU *cpu = opaque; 25967afe775SBenjamin Herrenschmidt 260af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 26167afe775SBenjamin Herrenschmidt 26267afe775SBenjamin Herrenschmidt switch (pin) { 26367afe775SBenjamin Herrenschmidt case POWER9_INPUT_INT: 26467afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 265af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 26667afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 26767afe775SBenjamin Herrenschmidt break; 26867afe775SBenjamin Herrenschmidt case POWER9_INPUT_HINT: 26967afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 270af96d2e6SCédric Le Goater trace_ppc_irq_set_state("HV external IRQ", level); 27167afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level); 27267afe775SBenjamin Herrenschmidt break; 27367afe775SBenjamin Herrenschmidt default: 2747279810bSCédric Le Goater g_assert_not_reached(); 275af96d2e6SCédric Le Goater return; 27667afe775SBenjamin Herrenschmidt } 27767afe775SBenjamin Herrenschmidt } 27867afe775SBenjamin Herrenschmidt 27967afe775SBenjamin Herrenschmidt void ppcPOWER9_irq_init(PowerPCCPU *cpu) 28067afe775SBenjamin Herrenschmidt { 2819fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), power9_set_irq, POWER9_INPUT_NB); 28267afe775SBenjamin Herrenschmidt } 28353018216SPaolo Bonzini #endif /* defined(TARGET_PPC64) */ 28453018216SPaolo Bonzini 28552144b69SThomas Huth void ppc40x_core_reset(PowerPCCPU *cpu) 28652144b69SThomas Huth { 28752144b69SThomas Huth CPUPPCState *env = &cpu->env; 28852144b69SThomas Huth target_ulong dbsr; 28952144b69SThomas Huth 29052144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n"); 29152144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 29252144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 29352144b69SThomas Huth dbsr &= ~0x00000300; 29452144b69SThomas Huth dbsr |= 0x00000100; 29552144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 29652144b69SThomas Huth } 29752144b69SThomas Huth 29852144b69SThomas Huth void ppc40x_chip_reset(PowerPCCPU *cpu) 29952144b69SThomas Huth { 30052144b69SThomas Huth CPUPPCState *env = &cpu->env; 30152144b69SThomas Huth target_ulong dbsr; 30252144b69SThomas Huth 30352144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n"); 30452144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 30552144b69SThomas Huth /* XXX: TODO reset all internal peripherals */ 30652144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 30752144b69SThomas Huth dbsr &= ~0x00000300; 30852144b69SThomas Huth dbsr |= 0x00000200; 30952144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 31052144b69SThomas Huth } 31152144b69SThomas Huth 31252144b69SThomas Huth void ppc40x_system_reset(PowerPCCPU *cpu) 31352144b69SThomas Huth { 31452144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n"); 31552144b69SThomas Huth qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 31652144b69SThomas Huth } 31752144b69SThomas Huth 31852144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val) 31952144b69SThomas Huth { 320db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 32152144b69SThomas Huth 3225ae3d2e8SThomas Huth qemu_mutex_lock_iothread(); 3235ae3d2e8SThomas Huth 32452144b69SThomas Huth switch ((val >> 28) & 0x3) { 32552144b69SThomas Huth case 0x0: 32652144b69SThomas Huth /* No action */ 32752144b69SThomas Huth break; 32852144b69SThomas Huth case 0x1: 32952144b69SThomas Huth /* Core reset */ 33052144b69SThomas Huth ppc40x_core_reset(cpu); 33152144b69SThomas Huth break; 33252144b69SThomas Huth case 0x2: 33352144b69SThomas Huth /* Chip reset */ 33452144b69SThomas Huth ppc40x_chip_reset(cpu); 33552144b69SThomas Huth break; 33652144b69SThomas Huth case 0x3: 33752144b69SThomas Huth /* System reset */ 33852144b69SThomas Huth ppc40x_system_reset(cpu); 33952144b69SThomas Huth break; 34052144b69SThomas Huth } 3415ae3d2e8SThomas Huth 3425ae3d2e8SThomas Huth qemu_mutex_unlock_iothread(); 34352144b69SThomas Huth } 34452144b69SThomas Huth 34553018216SPaolo Bonzini /* PowerPC 40x internal IRQ controller */ 34653018216SPaolo Bonzini static void ppc40x_set_irq(void *opaque, int pin, int level) 34753018216SPaolo Bonzini { 34853018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 34953018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 35053018216SPaolo Bonzini int cur_level; 35153018216SPaolo Bonzini 352af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 353af96d2e6SCédric Le Goater 35453018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 35553018216SPaolo Bonzini /* Don't generate spurious events */ 35653018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 357259186a7SAndreas Färber CPUState *cs = CPU(cpu); 358259186a7SAndreas Färber 35953018216SPaolo Bonzini switch (pin) { 36053018216SPaolo Bonzini case PPC40x_INPUT_RESET_SYS: 36153018216SPaolo Bonzini if (level) { 362af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 36353018216SPaolo Bonzini ppc40x_system_reset(cpu); 36453018216SPaolo Bonzini } 36553018216SPaolo Bonzini break; 36653018216SPaolo Bonzini case PPC40x_INPUT_RESET_CHIP: 36753018216SPaolo Bonzini if (level) { 368af96d2e6SCédric Le Goater trace_ppc_irq_reset("chip"); 36953018216SPaolo Bonzini ppc40x_chip_reset(cpu); 37053018216SPaolo Bonzini } 37153018216SPaolo Bonzini break; 37253018216SPaolo Bonzini case PPC40x_INPUT_RESET_CORE: 37353018216SPaolo Bonzini /* XXX: TODO: update DBSR[MRR] */ 37453018216SPaolo Bonzini if (level) { 375af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 37653018216SPaolo Bonzini ppc40x_core_reset(cpu); 37753018216SPaolo Bonzini } 37853018216SPaolo Bonzini break; 37953018216SPaolo Bonzini case PPC40x_INPUT_CINT: 38053018216SPaolo Bonzini /* Level sensitive - active high */ 381af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 38253018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 38353018216SPaolo Bonzini break; 38453018216SPaolo Bonzini case PPC40x_INPUT_INT: 38553018216SPaolo Bonzini /* Level sensitive - active high */ 386af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 38753018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 38853018216SPaolo Bonzini break; 38953018216SPaolo Bonzini case PPC40x_INPUT_HALT: 39053018216SPaolo Bonzini /* Level sensitive - active low */ 39153018216SPaolo Bonzini if (level) { 392af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 393259186a7SAndreas Färber cs->halted = 1; 39453018216SPaolo Bonzini } else { 395af96d2e6SCédric Le Goater trace_ppc_irq_cpu("restart"); 396259186a7SAndreas Färber cs->halted = 0; 397259186a7SAndreas Färber qemu_cpu_kick(cs); 39853018216SPaolo Bonzini } 39953018216SPaolo Bonzini break; 40053018216SPaolo Bonzini case PPC40x_INPUT_DEBUG: 40153018216SPaolo Bonzini /* Level sensitive - active high */ 402af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 40353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 40453018216SPaolo Bonzini break; 40553018216SPaolo Bonzini default: 4067279810bSCédric Le Goater g_assert_not_reached(); 40753018216SPaolo Bonzini } 40853018216SPaolo Bonzini if (level) 40953018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 41053018216SPaolo Bonzini else 41153018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 41253018216SPaolo Bonzini } 41353018216SPaolo Bonzini } 41453018216SPaolo Bonzini 415aa5a9e24SPaolo Bonzini void ppc40x_irq_init(PowerPCCPU *cpu) 41653018216SPaolo Bonzini { 41747b60fc6SCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc40x_set_irq, PPC40x_INPUT_NB); 41853018216SPaolo Bonzini } 41953018216SPaolo Bonzini 42053018216SPaolo Bonzini /* PowerPC E500 internal IRQ controller */ 42153018216SPaolo Bonzini static void ppce500_set_irq(void *opaque, int pin, int level) 42253018216SPaolo Bonzini { 42353018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 42453018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 42553018216SPaolo Bonzini int cur_level; 42653018216SPaolo Bonzini 427af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 428af96d2e6SCédric Le Goater 42953018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 43053018216SPaolo Bonzini /* Don't generate spurious events */ 43153018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 43253018216SPaolo Bonzini switch (pin) { 43353018216SPaolo Bonzini case PPCE500_INPUT_MCK: 43453018216SPaolo Bonzini if (level) { 435af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 436cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 43753018216SPaolo Bonzini } 43853018216SPaolo Bonzini break; 43953018216SPaolo Bonzini case PPCE500_INPUT_RESET_CORE: 44053018216SPaolo Bonzini if (level) { 441af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 44253018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); 44353018216SPaolo Bonzini } 44453018216SPaolo Bonzini break; 44553018216SPaolo Bonzini case PPCE500_INPUT_CINT: 44653018216SPaolo Bonzini /* Level sensitive - active high */ 447af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 44853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 44953018216SPaolo Bonzini break; 45053018216SPaolo Bonzini case PPCE500_INPUT_INT: 45153018216SPaolo Bonzini /* Level sensitive - active high */ 452af96d2e6SCédric Le Goater trace_ppc_irq_set_state("core IRQ", level); 45353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 45453018216SPaolo Bonzini break; 45553018216SPaolo Bonzini case PPCE500_INPUT_DEBUG: 45653018216SPaolo Bonzini /* Level sensitive - active high */ 457af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 45853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 45953018216SPaolo Bonzini break; 46053018216SPaolo Bonzini default: 4617279810bSCédric Le Goater g_assert_not_reached(); 46253018216SPaolo Bonzini } 46353018216SPaolo Bonzini if (level) 46453018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 46553018216SPaolo Bonzini else 46653018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 46753018216SPaolo Bonzini } 46853018216SPaolo Bonzini } 46953018216SPaolo Bonzini 470aa5a9e24SPaolo Bonzini void ppce500_irq_init(PowerPCCPU *cpu) 47153018216SPaolo Bonzini { 4725e66cd0cSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppce500_set_irq, PPCE500_INPUT_NB); 47353018216SPaolo Bonzini } 47453018216SPaolo Bonzini 47553018216SPaolo Bonzini /* Enable or Disable the E500 EPR capability */ 47653018216SPaolo Bonzini void ppce500_set_mpic_proxy(bool enabled) 47753018216SPaolo Bonzini { 478182735efSAndreas Färber CPUState *cs; 47953018216SPaolo Bonzini 480bdc44640SAndreas Färber CPU_FOREACH(cs) { 481182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 48253018216SPaolo Bonzini 483182735efSAndreas Färber cpu->env.mpic_proxy = enabled; 48453018216SPaolo Bonzini if (kvm_enabled()) { 485182735efSAndreas Färber kvmppc_set_mpic_proxy(cpu, enabled); 48653018216SPaolo Bonzini } 48753018216SPaolo Bonzini } 48853018216SPaolo Bonzini } 48953018216SPaolo Bonzini 49053018216SPaolo Bonzini /*****************************************************************************/ 49153018216SPaolo Bonzini /* PowerPC time base and decrementer emulation */ 49253018216SPaolo Bonzini 49353018216SPaolo Bonzini uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) 49453018216SPaolo Bonzini { 49553018216SPaolo Bonzini /* TB time in tb periods */ 49673bcb24dSRutuja Shah return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset; 49753018216SPaolo Bonzini } 49853018216SPaolo Bonzini 49953018216SPaolo Bonzini uint64_t cpu_ppc_load_tbl (CPUPPCState *env) 50053018216SPaolo Bonzini { 50153018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 50253018216SPaolo Bonzini uint64_t tb; 50353018216SPaolo Bonzini 50453018216SPaolo Bonzini if (kvm_enabled()) { 50553018216SPaolo Bonzini return env->spr[SPR_TBL]; 50653018216SPaolo Bonzini } 50753018216SPaolo Bonzini 508bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 509af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 51053018216SPaolo Bonzini 51153018216SPaolo Bonzini return tb; 51253018216SPaolo Bonzini } 51353018216SPaolo Bonzini 51453018216SPaolo Bonzini static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) 51553018216SPaolo Bonzini { 51653018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 51753018216SPaolo Bonzini uint64_t tb; 51853018216SPaolo Bonzini 519bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 520af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 52153018216SPaolo Bonzini 52253018216SPaolo Bonzini return tb >> 32; 52353018216SPaolo Bonzini } 52453018216SPaolo Bonzini 52553018216SPaolo Bonzini uint32_t cpu_ppc_load_tbu (CPUPPCState *env) 52653018216SPaolo Bonzini { 52753018216SPaolo Bonzini if (kvm_enabled()) { 52853018216SPaolo Bonzini return env->spr[SPR_TBU]; 52953018216SPaolo Bonzini } 53053018216SPaolo Bonzini 53153018216SPaolo Bonzini return _cpu_ppc_load_tbu(env); 53253018216SPaolo Bonzini } 53353018216SPaolo Bonzini 53453018216SPaolo Bonzini static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, 53553018216SPaolo Bonzini int64_t *tb_offsetp, uint64_t value) 53653018216SPaolo Bonzini { 53773bcb24dSRutuja Shah *tb_offsetp = value - 53873bcb24dSRutuja Shah muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND); 53973bcb24dSRutuja Shah 540af96d2e6SCédric Le Goater trace_ppc_tb_store(value, *tb_offsetp); 54153018216SPaolo Bonzini } 54253018216SPaolo Bonzini 54353018216SPaolo Bonzini void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) 54453018216SPaolo Bonzini { 54553018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 54653018216SPaolo Bonzini uint64_t tb; 54753018216SPaolo Bonzini 548bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 54953018216SPaolo Bonzini tb &= 0xFFFFFFFF00000000ULL; 550bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 55153018216SPaolo Bonzini &tb_env->tb_offset, tb | (uint64_t)value); 55253018216SPaolo Bonzini } 55353018216SPaolo Bonzini 55453018216SPaolo Bonzini static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) 55553018216SPaolo Bonzini { 55653018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 55753018216SPaolo Bonzini uint64_t tb; 55853018216SPaolo Bonzini 559bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 56053018216SPaolo Bonzini tb &= 0x00000000FFFFFFFFULL; 561bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 56253018216SPaolo Bonzini &tb_env->tb_offset, ((uint64_t)value << 32) | tb); 56353018216SPaolo Bonzini } 56453018216SPaolo Bonzini 56553018216SPaolo Bonzini void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value) 56653018216SPaolo Bonzini { 56753018216SPaolo Bonzini _cpu_ppc_store_tbu(env, value); 56853018216SPaolo Bonzini } 56953018216SPaolo Bonzini 57053018216SPaolo Bonzini uint64_t cpu_ppc_load_atbl (CPUPPCState *env) 57153018216SPaolo Bonzini { 57253018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 57353018216SPaolo Bonzini uint64_t tb; 57453018216SPaolo Bonzini 575bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 576af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 57753018216SPaolo Bonzini 57853018216SPaolo Bonzini return tb; 57953018216SPaolo Bonzini } 58053018216SPaolo Bonzini 58153018216SPaolo Bonzini uint32_t cpu_ppc_load_atbu (CPUPPCState *env) 58253018216SPaolo Bonzini { 58353018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 58453018216SPaolo Bonzini uint64_t tb; 58553018216SPaolo Bonzini 586bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 587af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 58853018216SPaolo Bonzini 58953018216SPaolo Bonzini return tb >> 32; 59053018216SPaolo Bonzini } 59153018216SPaolo Bonzini 59253018216SPaolo Bonzini void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) 59353018216SPaolo Bonzini { 59453018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 59553018216SPaolo Bonzini uint64_t tb; 59653018216SPaolo Bonzini 597bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 59853018216SPaolo Bonzini tb &= 0xFFFFFFFF00000000ULL; 599bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 60053018216SPaolo Bonzini &tb_env->atb_offset, tb | (uint64_t)value); 60153018216SPaolo Bonzini } 60253018216SPaolo Bonzini 60353018216SPaolo Bonzini void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) 60453018216SPaolo Bonzini { 60553018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 60653018216SPaolo Bonzini uint64_t tb; 60753018216SPaolo Bonzini 608bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 60953018216SPaolo Bonzini tb &= 0x00000000FFFFFFFFULL; 610bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 61153018216SPaolo Bonzini &tb_env->atb_offset, ((uint64_t)value << 32) | tb); 61253018216SPaolo Bonzini } 61353018216SPaolo Bonzini 6145d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env) 6155d62725bSSuraj Jitindar Singh { 6165d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6175d62725bSSuraj Jitindar Singh 6185d62725bSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6195d62725bSSuraj Jitindar Singh tb_env->vtb_offset); 6205d62725bSSuraj Jitindar Singh } 6215d62725bSSuraj Jitindar Singh 6225d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value) 6235d62725bSSuraj Jitindar Singh { 6245d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6255d62725bSSuraj Jitindar Singh 6265d62725bSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6275d62725bSSuraj Jitindar Singh &tb_env->vtb_offset, value); 6285d62725bSSuraj Jitindar Singh } 6295d62725bSSuraj Jitindar Singh 630f0ec31b1SSuraj Jitindar Singh void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value) 631f0ec31b1SSuraj Jitindar Singh { 632f0ec31b1SSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 633f0ec31b1SSuraj Jitindar Singh uint64_t tb; 634f0ec31b1SSuraj Jitindar Singh 635f0ec31b1SSuraj Jitindar Singh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 636f0ec31b1SSuraj Jitindar Singh tb_env->tb_offset); 637f0ec31b1SSuraj Jitindar Singh tb &= 0xFFFFFFUL; 638f0ec31b1SSuraj Jitindar Singh tb |= (value & ~0xFFFFFFUL); 639f0ec31b1SSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 640f0ec31b1SSuraj Jitindar Singh &tb_env->tb_offset, tb); 641f0ec31b1SSuraj Jitindar Singh } 642f0ec31b1SSuraj Jitindar Singh 64353018216SPaolo Bonzini static void cpu_ppc_tb_stop (CPUPPCState *env) 64453018216SPaolo Bonzini { 64553018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 64653018216SPaolo Bonzini uint64_t tb, atb, vmclk; 64753018216SPaolo Bonzini 64853018216SPaolo Bonzini /* If the time base is already frozen, do nothing */ 64953018216SPaolo Bonzini if (tb_env->tb_freq != 0) { 650bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 65153018216SPaolo Bonzini /* Get the time base */ 65253018216SPaolo Bonzini tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); 65353018216SPaolo Bonzini /* Get the alternate time base */ 65453018216SPaolo Bonzini atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); 65553018216SPaolo Bonzini /* Store the time base value (ie compute the current offset) */ 65653018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 65753018216SPaolo Bonzini /* Store the alternate time base value (compute the current offset) */ 65853018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 65953018216SPaolo Bonzini /* Set the time base frequency to zero */ 66053018216SPaolo Bonzini tb_env->tb_freq = 0; 66153018216SPaolo Bonzini /* Now, the time bases are frozen to tb_offset / atb_offset value */ 66253018216SPaolo Bonzini } 66353018216SPaolo Bonzini } 66453018216SPaolo Bonzini 66553018216SPaolo Bonzini static void cpu_ppc_tb_start (CPUPPCState *env) 66653018216SPaolo Bonzini { 66753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 66853018216SPaolo Bonzini uint64_t tb, atb, vmclk; 66953018216SPaolo Bonzini 67053018216SPaolo Bonzini /* If the time base is not frozen, do nothing */ 67153018216SPaolo Bonzini if (tb_env->tb_freq == 0) { 672bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 67353018216SPaolo Bonzini /* Get the time base from tb_offset */ 67453018216SPaolo Bonzini tb = tb_env->tb_offset; 67553018216SPaolo Bonzini /* Get the alternate time base from atb_offset */ 67653018216SPaolo Bonzini atb = tb_env->atb_offset; 67753018216SPaolo Bonzini /* Restore the tb frequency from the decrementer frequency */ 67853018216SPaolo Bonzini tb_env->tb_freq = tb_env->decr_freq; 67953018216SPaolo Bonzini /* Store the time base value */ 68053018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 68153018216SPaolo Bonzini /* Store the alternate time base value */ 68253018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 68353018216SPaolo Bonzini } 68453018216SPaolo Bonzini } 68553018216SPaolo Bonzini 686e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env) 687e81a982aSAlexander Graf { 688e81a982aSAlexander Graf ppc_tb_t *tb_env = env->tb_env; 689e81a982aSAlexander Graf int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL; 690e81a982aSAlexander Graf return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED); 691e81a982aSAlexander Graf } 692e81a982aSAlexander Graf 693a8dafa52SSuraj Jitindar Singh static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) 69453018216SPaolo Bonzini { 69553018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 696a8dafa52SSuraj Jitindar Singh int64_t decr, diff; 69753018216SPaolo Bonzini 698bc72ad67SAlex Bligh diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 69953018216SPaolo Bonzini if (diff >= 0) { 70073bcb24dSRutuja Shah decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 70153018216SPaolo Bonzini } else if (tb_env->flags & PPC_TIMER_BOOKE) { 70253018216SPaolo Bonzini decr = 0; 70353018216SPaolo Bonzini } else { 70473bcb24dSRutuja Shah decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 70553018216SPaolo Bonzini } 706af96d2e6SCédric Le Goater trace_ppc_decr_load(decr); 70753018216SPaolo Bonzini 70853018216SPaolo Bonzini return decr; 70953018216SPaolo Bonzini } 71053018216SPaolo Bonzini 711a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_decr(CPUPPCState *env) 71253018216SPaolo Bonzini { 71353018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 714a8dafa52SSuraj Jitindar Singh uint64_t decr; 71553018216SPaolo Bonzini 71653018216SPaolo Bonzini if (kvm_enabled()) { 71753018216SPaolo Bonzini return env->spr[SPR_DECR]; 71853018216SPaolo Bonzini } 71953018216SPaolo Bonzini 720a8dafa52SSuraj Jitindar Singh decr = _cpu_ppc_load_decr(env, tb_env->decr_next); 721a8dafa52SSuraj Jitindar Singh 722a8dafa52SSuraj Jitindar Singh /* 723a8dafa52SSuraj Jitindar Singh * If large decrementer is enabled then the decrementer is signed extened 724a8dafa52SSuraj Jitindar Singh * to 64 bits, otherwise it is a 32 bit value. 725a8dafa52SSuraj Jitindar Singh */ 726a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 727a8dafa52SSuraj Jitindar Singh return decr; 728a8dafa52SSuraj Jitindar Singh } 729a8dafa52SSuraj Jitindar Singh return (uint32_t) decr; 73053018216SPaolo Bonzini } 73153018216SPaolo Bonzini 732a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_hdecr(CPUPPCState *env) 73353018216SPaolo Bonzini { 734db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 735a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 73653018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 737a8dafa52SSuraj Jitindar Singh uint64_t hdecr; 73853018216SPaolo Bonzini 739a8dafa52SSuraj Jitindar Singh hdecr = _cpu_ppc_load_decr(env, tb_env->hdecr_next); 740a8dafa52SSuraj Jitindar Singh 741a8dafa52SSuraj Jitindar Singh /* 742a8dafa52SSuraj Jitindar Singh * If we have a large decrementer (POWER9 or later) then hdecr is sign 743a8dafa52SSuraj Jitindar Singh * extended to 64 bits, otherwise it is 32 bits. 744a8dafa52SSuraj Jitindar Singh */ 745a8dafa52SSuraj Jitindar Singh if (pcc->lrg_decr_bits > 32) { 746a8dafa52SSuraj Jitindar Singh return hdecr; 747a8dafa52SSuraj Jitindar Singh } 748a8dafa52SSuraj Jitindar Singh return (uint32_t) hdecr; 74953018216SPaolo Bonzini } 75053018216SPaolo Bonzini 75153018216SPaolo Bonzini uint64_t cpu_ppc_load_purr (CPUPPCState *env) 75253018216SPaolo Bonzini { 75353018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 75453018216SPaolo Bonzini 7555cc7e69fSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 7565cc7e69fSSuraj Jitindar Singh tb_env->purr_offset); 75753018216SPaolo Bonzini } 75853018216SPaolo Bonzini 75953018216SPaolo Bonzini /* When decrementer expires, 76053018216SPaolo Bonzini * all we need to do is generate or queue a CPU exception 76153018216SPaolo Bonzini */ 76253018216SPaolo Bonzini static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) 76353018216SPaolo Bonzini { 76453018216SPaolo Bonzini /* Raise it */ 765af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise"); 76653018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); 76753018216SPaolo Bonzini } 76853018216SPaolo Bonzini 769e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu) 770e81a982aSAlexander Graf { 771e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0); 772e81a982aSAlexander Graf } 773e81a982aSAlexander Graf 77453018216SPaolo Bonzini static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) 77553018216SPaolo Bonzini { 7764b236b62SBenjamin Herrenschmidt CPUPPCState *env = &cpu->env; 7774b236b62SBenjamin Herrenschmidt 77853018216SPaolo Bonzini /* Raise it */ 779af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise HV"); 7804b236b62SBenjamin Herrenschmidt 7814b236b62SBenjamin Herrenschmidt /* The architecture specifies that we don't deliver HDEC 7824b236b62SBenjamin Herrenschmidt * interrupts in a PM state. Not only they don't cause a 7834b236b62SBenjamin Herrenschmidt * wakeup but they also get effectively discarded. 7844b236b62SBenjamin Herrenschmidt */ 7851e7fd61dSBenjamin Herrenschmidt if (!env->resume_as_sreset) { 78653018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); 78753018216SPaolo Bonzini } 7884b236b62SBenjamin Herrenschmidt } 78953018216SPaolo Bonzini 790e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) 791e81a982aSAlexander Graf { 792e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); 793e81a982aSAlexander Graf } 794e81a982aSAlexander Graf 79553018216SPaolo Bonzini static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, 7961246b259SStefan Weil QEMUTimer *timer, 797e81a982aSAlexander Graf void (*raise_excp)(void *), 798e81a982aSAlexander Graf void (*lower_excp)(PowerPCCPU *), 799a8dafa52SSuraj Jitindar Singh target_ulong decr, target_ulong value, 800a8dafa52SSuraj Jitindar Singh int nr_bits) 80153018216SPaolo Bonzini { 80253018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 80353018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 80453018216SPaolo Bonzini uint64_t now, next; 8054d9b8ef9SCédric Le Goater int64_t signed_value; 8064d9b8ef9SCédric Le Goater int64_t signed_decr; 80753018216SPaolo Bonzini 808a8dafa52SSuraj Jitindar Singh /* Truncate value to decr_width and sign extend for simplicity */ 8094d9b8ef9SCédric Le Goater signed_value = sextract64(value, 0, nr_bits); 8104d9b8ef9SCédric Le Goater signed_decr = sextract64(decr, 0, nr_bits); 811a8dafa52SSuraj Jitindar Singh 812af96d2e6SCédric Le Goater trace_ppc_decr_store(nr_bits, decr, value); 81353018216SPaolo Bonzini 81453018216SPaolo Bonzini if (kvm_enabled()) { 81553018216SPaolo Bonzini /* KVM handles decrementer exceptions, we don't need our own timer */ 81653018216SPaolo Bonzini return; 81753018216SPaolo Bonzini } 81853018216SPaolo Bonzini 819e81a982aSAlexander Graf /* 820e81a982aSAlexander Graf * Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC 821e81a982aSAlexander Graf * interrupt. 822e81a982aSAlexander Graf * 823e81a982aSAlexander Graf * If we get a really small DEC value, we can assume that by the time we 824e81a982aSAlexander Graf * handled it we should inject an interrupt already. 825e81a982aSAlexander Graf * 826e81a982aSAlexander Graf * On MSB level based DEC implementations the MSB always means the interrupt 827e81a982aSAlexander Graf * is pending, so raise it on those. 828e81a982aSAlexander Graf * 829e81a982aSAlexander Graf * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers 830e81a982aSAlexander Graf * an edge interrupt, so raise it here too. 831e81a982aSAlexander Graf */ 832a8dcb8daSCédric Le Goater if ((value < 3) || 8334d9b8ef9SCédric Le Goater ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) || 8344d9b8ef9SCédric Le Goater ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0 8354d9b8ef9SCédric Le Goater && signed_decr >= 0)) { 836e81a982aSAlexander Graf (*raise_excp)(cpu); 837e81a982aSAlexander Graf return; 838e81a982aSAlexander Graf } 839e81a982aSAlexander Graf 840e81a982aSAlexander Graf /* On MSB level based systems a 0 for the MSB stops interrupt delivery */ 8414d9b8ef9SCédric Le Goater if (signed_value >= 0 && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) { 842e81a982aSAlexander Graf (*lower_excp)(cpu); 843e81a982aSAlexander Graf } 844e81a982aSAlexander Graf 845e81a982aSAlexander Graf /* Calculate the next timer event */ 846bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 84773bcb24dSRutuja Shah next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 84853018216SPaolo Bonzini *nextp = next; 849e81a982aSAlexander Graf 85053018216SPaolo Bonzini /* Adjust timer */ 851bc72ad67SAlex Bligh timer_mod(timer, next); 85253018216SPaolo Bonzini } 85353018216SPaolo Bonzini 854a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr, 855a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 85653018216SPaolo Bonzini { 85753018216SPaolo Bonzini ppc_tb_t *tb_env = cpu->env.tb_env; 85853018216SPaolo Bonzini 85953018216SPaolo Bonzini __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, 860e81a982aSAlexander Graf tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr, 861a8dafa52SSuraj Jitindar Singh value, nr_bits); 86253018216SPaolo Bonzini } 86353018216SPaolo Bonzini 864a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value) 86553018216SPaolo Bonzini { 866db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 867a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 868a8dafa52SSuraj Jitindar Singh int nr_bits = 32; 86953018216SPaolo Bonzini 870a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 871a8dafa52SSuraj Jitindar Singh nr_bits = pcc->lrg_decr_bits; 872a8dafa52SSuraj Jitindar Singh } 873a8dafa52SSuraj Jitindar Singh 874a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, nr_bits); 87553018216SPaolo Bonzini } 87653018216SPaolo Bonzini 87753018216SPaolo Bonzini static void cpu_ppc_decr_cb(void *opaque) 87853018216SPaolo Bonzini { 87953018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 88053018216SPaolo Bonzini 881e81a982aSAlexander Graf cpu_ppc_decr_excp(cpu); 88253018216SPaolo Bonzini } 88353018216SPaolo Bonzini 884a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr, 885a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 88653018216SPaolo Bonzini { 88753018216SPaolo Bonzini ppc_tb_t *tb_env = cpu->env.tb_env; 88853018216SPaolo Bonzini 88953018216SPaolo Bonzini if (tb_env->hdecr_timer != NULL) { 89053018216SPaolo Bonzini __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, 891e81a982aSAlexander Graf tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower, 892a8dafa52SSuraj Jitindar Singh hdecr, value, nr_bits); 89353018216SPaolo Bonzini } 89453018216SPaolo Bonzini } 89553018216SPaolo Bonzini 896a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value) 89753018216SPaolo Bonzini { 898db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 899a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 90053018216SPaolo Bonzini 901a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 902a8dafa52SSuraj Jitindar Singh pcc->lrg_decr_bits); 90353018216SPaolo Bonzini } 90453018216SPaolo Bonzini 90553018216SPaolo Bonzini static void cpu_ppc_hdecr_cb(void *opaque) 90653018216SPaolo Bonzini { 90753018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 90853018216SPaolo Bonzini 909e81a982aSAlexander Graf cpu_ppc_hdecr_excp(cpu); 91053018216SPaolo Bonzini } 91153018216SPaolo Bonzini 9125cc7e69fSSuraj Jitindar Singh void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) 91353018216SPaolo Bonzini { 9145cc7e69fSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 91553018216SPaolo Bonzini 9165cc7e69fSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 9175cc7e69fSSuraj Jitindar Singh &tb_env->purr_offset, value); 91853018216SPaolo Bonzini } 91953018216SPaolo Bonzini 92053018216SPaolo Bonzini static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) 92153018216SPaolo Bonzini { 92253018216SPaolo Bonzini CPUPPCState *env = opaque; 923db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 92453018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 92553018216SPaolo Bonzini 92653018216SPaolo Bonzini tb_env->tb_freq = freq; 92753018216SPaolo Bonzini tb_env->decr_freq = freq; 92853018216SPaolo Bonzini /* There is a bug in Linux 2.4 kernels: 92953018216SPaolo Bonzini * if a decrementer exception is pending when it enables msr_ee at startup, 93053018216SPaolo Bonzini * it's not ready to handle it... 93153018216SPaolo Bonzini */ 932a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 933a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 9345cc7e69fSSuraj Jitindar Singh cpu_ppc_store_purr(env, 0x0000000000000000ULL); 93553018216SPaolo Bonzini } 93653018216SPaolo Bonzini 93742043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb) 93898a8b524SAlexey Kardashevskiy { 9394a7428c5SChristopher Covington uint64_t ticks = cpu_get_host_ticks(); 94098a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 94198a8b524SAlexey Kardashevskiy 94298a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 94398a8b524SAlexey Kardashevskiy error_report("No timebase object"); 94498a8b524SAlexey Kardashevskiy return; 94598a8b524SAlexey Kardashevskiy } 94698a8b524SAlexey Kardashevskiy 94742043e4fSLaurent Vivier /* not used anymore, we keep it for compatibility */ 94877bad151SPaolo Bonzini tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); 94998a8b524SAlexey Kardashevskiy /* 95042043e4fSLaurent Vivier * tb_offset is only expected to be changed by QEMU so 95198a8b524SAlexey Kardashevskiy * there is no need to update it from KVM here 95298a8b524SAlexey Kardashevskiy */ 95398a8b524SAlexey Kardashevskiy tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; 954d14f3397SMaxiwell S. Garcia 955711dfb24SGreg Kurz tb->runstate_paused = 956711dfb24SGreg Kurz runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM); 95798a8b524SAlexey Kardashevskiy } 95898a8b524SAlexey Kardashevskiy 95942043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb) 96098a8b524SAlexey Kardashevskiy { 96198a8b524SAlexey Kardashevskiy CPUState *cpu; 96298a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 96342043e4fSLaurent Vivier int64_t tb_off_adj, tb_off; 96498a8b524SAlexey Kardashevskiy unsigned long freq; 96598a8b524SAlexey Kardashevskiy 96698a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 96798a8b524SAlexey Kardashevskiy error_report("No timebase object"); 96842043e4fSLaurent Vivier return; 96998a8b524SAlexey Kardashevskiy } 97098a8b524SAlexey Kardashevskiy 97198a8b524SAlexey Kardashevskiy freq = first_ppc_cpu->env.tb_env->tb_freq; 97298a8b524SAlexey Kardashevskiy 97342043e4fSLaurent Vivier tb_off_adj = tb->guest_timebase - cpu_get_host_ticks(); 97498a8b524SAlexey Kardashevskiy 97598a8b524SAlexey Kardashevskiy tb_off = first_ppc_cpu->env.tb_env->tb_offset; 97698a8b524SAlexey Kardashevskiy trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off, 97798a8b524SAlexey Kardashevskiy (tb_off_adj - tb_off) / freq); 97898a8b524SAlexey Kardashevskiy 97998a8b524SAlexey Kardashevskiy /* Set new offset to all CPUs */ 98098a8b524SAlexey Kardashevskiy CPU_FOREACH(cpu) { 98198a8b524SAlexey Kardashevskiy PowerPCCPU *pcpu = POWERPC_CPU(cpu); 98298a8b524SAlexey Kardashevskiy pcpu->env.tb_env->tb_offset = tb_off_adj; 9839723295aSGreg Kurz kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset); 98442043e4fSLaurent Vivier } 98598a8b524SAlexey Kardashevskiy } 98698a8b524SAlexey Kardashevskiy 987538f0497SPhilippe Mathieu-Daudé void cpu_ppc_clock_vm_state_change(void *opaque, bool running, 98842043e4fSLaurent Vivier RunState state) 98942043e4fSLaurent Vivier { 99042043e4fSLaurent Vivier PPCTimebase *tb = opaque; 99142043e4fSLaurent Vivier 99242043e4fSLaurent Vivier if (running) { 99342043e4fSLaurent Vivier timebase_load(tb); 99442043e4fSLaurent Vivier } else { 99542043e4fSLaurent Vivier timebase_save(tb); 99642043e4fSLaurent Vivier } 99742043e4fSLaurent Vivier } 99842043e4fSLaurent Vivier 99942043e4fSLaurent Vivier /* 1000d14f3397SMaxiwell S. Garcia * When migrating a running guest, read the clock just 1001d14f3397SMaxiwell S. Garcia * before migration, so that the guest clock counts 1002d14f3397SMaxiwell S. Garcia * during the events between: 100342043e4fSLaurent Vivier * 100442043e4fSLaurent Vivier * * vm_stop() 100542043e4fSLaurent Vivier * * 100642043e4fSLaurent Vivier * * pre_save() 100742043e4fSLaurent Vivier * 100842043e4fSLaurent Vivier * This reduces clock difference on migration from 5s 100942043e4fSLaurent Vivier * to 0.1s (when max_downtime == 5s), because sending the 101042043e4fSLaurent Vivier * final pages of memory (which happens between vm_stop() 101142043e4fSLaurent Vivier * and pre_save()) takes max_downtime. 101242043e4fSLaurent Vivier */ 101344b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque) 101442043e4fSLaurent Vivier { 101542043e4fSLaurent Vivier PPCTimebase *tb = opaque; 101642043e4fSLaurent Vivier 1017711dfb24SGreg Kurz /* guest_timebase won't be overridden in case of paused guest or savevm */ 1018d14f3397SMaxiwell S. Garcia if (!tb->runstate_paused) { 101942043e4fSLaurent Vivier timebase_save(tb); 1020d14f3397SMaxiwell S. Garcia } 102144b1ff31SDr. David Alan Gilbert 102244b1ff31SDr. David Alan Gilbert return 0; 102398a8b524SAlexey Kardashevskiy } 102498a8b524SAlexey Kardashevskiy 102598a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = { 102698a8b524SAlexey Kardashevskiy .name = "timebase", 102798a8b524SAlexey Kardashevskiy .version_id = 1, 102898a8b524SAlexey Kardashevskiy .minimum_version_id = 1, 102998a8b524SAlexey Kardashevskiy .pre_save = timebase_pre_save, 103098a8b524SAlexey Kardashevskiy .fields = (VMStateField []) { 103198a8b524SAlexey Kardashevskiy VMSTATE_UINT64(guest_timebase, PPCTimebase), 103298a8b524SAlexey Kardashevskiy VMSTATE_INT64(time_of_the_day_ns, PPCTimebase), 103398a8b524SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 103498a8b524SAlexey Kardashevskiy }, 103598a8b524SAlexey Kardashevskiy }; 103698a8b524SAlexey Kardashevskiy 103753018216SPaolo Bonzini /* Set up (once) timebase frequency (in Hz) */ 103853018216SPaolo Bonzini clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) 103953018216SPaolo Bonzini { 1040db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 104153018216SPaolo Bonzini ppc_tb_t *tb_env; 104253018216SPaolo Bonzini 1043b21e2380SMarkus Armbruster tb_env = g_new0(ppc_tb_t, 1); 104453018216SPaolo Bonzini env->tb_env = tb_env; 104553018216SPaolo Bonzini tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 1046d0db7cadSGreg Kurz if (is_book3s_arch2x(env)) { 1047e81a982aSAlexander Graf /* All Book3S 64bit CPUs implement level based DEC logic */ 1048e81a982aSAlexander Graf tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL; 1049e81a982aSAlexander Graf } 105053018216SPaolo Bonzini /* Create new timer */ 1051bc72ad67SAlex Bligh tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); 10525ff40b01SNicholas Piggin if (env->has_hv_mode && !cpu->vhyp) { 1053bc72ad67SAlex Bligh tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, 105453018216SPaolo Bonzini cpu); 105553018216SPaolo Bonzini } else { 105653018216SPaolo Bonzini tb_env->hdecr_timer = NULL; 105753018216SPaolo Bonzini } 105853018216SPaolo Bonzini cpu_ppc_set_tb_clk(env, freq); 105953018216SPaolo Bonzini 106053018216SPaolo Bonzini return &cpu_ppc_set_tb_clk; 106153018216SPaolo Bonzini } 106253018216SPaolo Bonzini 1063ef95a244SDaniel Henrique Barboza void cpu_ppc_tb_free(CPUPPCState *env) 1064ef95a244SDaniel Henrique Barboza { 1065ef95a244SDaniel Henrique Barboza timer_free(env->tb_env->decr_timer); 1066ef95a244SDaniel Henrique Barboza timer_free(env->tb_env->hdecr_timer); 1067ef95a244SDaniel Henrique Barboza g_free(env->tb_env); 1068ef95a244SDaniel Henrique Barboza } 1069ef95a244SDaniel Henrique Barboza 107093aeb702SNicholas Piggin /* cpu_ppc_hdecr_init may be used if the timer is not used by HDEC emulation */ 107193aeb702SNicholas Piggin void cpu_ppc_hdecr_init(CPUPPCState *env) 107293aeb702SNicholas Piggin { 107393aeb702SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 107493aeb702SNicholas Piggin 107593aeb702SNicholas Piggin assert(env->tb_env->hdecr_timer == NULL); 107693aeb702SNicholas Piggin 107793aeb702SNicholas Piggin env->tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 107893aeb702SNicholas Piggin &cpu_ppc_hdecr_cb, cpu); 107993aeb702SNicholas Piggin } 108093aeb702SNicholas Piggin 108193aeb702SNicholas Piggin void cpu_ppc_hdecr_exit(CPUPPCState *env) 108293aeb702SNicholas Piggin { 108393aeb702SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 108493aeb702SNicholas Piggin 108593aeb702SNicholas Piggin timer_free(env->tb_env->hdecr_timer); 108693aeb702SNicholas Piggin env->tb_env->hdecr_timer = NULL; 108793aeb702SNicholas Piggin 108893aeb702SNicholas Piggin cpu_ppc_hdecr_lower(cpu); 108993aeb702SNicholas Piggin } 109093aeb702SNicholas Piggin 109153018216SPaolo Bonzini /*****************************************************************************/ 109253018216SPaolo Bonzini /* PowerPC 40x timers */ 109353018216SPaolo Bonzini 109453018216SPaolo Bonzini /* PIT, FIT & WDT */ 109553018216SPaolo Bonzini typedef struct ppc40x_timer_t ppc40x_timer_t; 109653018216SPaolo Bonzini struct ppc40x_timer_t { 109753018216SPaolo Bonzini uint64_t pit_reload; /* PIT auto-reload value */ 109853018216SPaolo Bonzini uint64_t fit_next; /* Tick for next FIT interrupt */ 10991246b259SStefan Weil QEMUTimer *fit_timer; 110053018216SPaolo Bonzini uint64_t wdt_next; /* Tick for next WDT interrupt */ 11011246b259SStefan Weil QEMUTimer *wdt_timer; 110253018216SPaolo Bonzini 110353018216SPaolo Bonzini /* 405 have the PIT, 440 have a DECR. */ 110453018216SPaolo Bonzini unsigned int decr_excp; 110553018216SPaolo Bonzini }; 110653018216SPaolo Bonzini 110753018216SPaolo Bonzini /* Fixed interval timer */ 110853018216SPaolo Bonzini static void cpu_4xx_fit_cb (void *opaque) 110953018216SPaolo Bonzini { 1110b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1111b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 111253018216SPaolo Bonzini ppc_tb_t *tb_env; 111353018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 111453018216SPaolo Bonzini uint64_t now, next; 111553018216SPaolo Bonzini 111653018216SPaolo Bonzini tb_env = env->tb_env; 111753018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1118bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 111953018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { 112053018216SPaolo Bonzini case 0: 112153018216SPaolo Bonzini next = 1 << 9; 112253018216SPaolo Bonzini break; 112353018216SPaolo Bonzini case 1: 112453018216SPaolo Bonzini next = 1 << 13; 112553018216SPaolo Bonzini break; 112653018216SPaolo Bonzini case 2: 112753018216SPaolo Bonzini next = 1 << 17; 112853018216SPaolo Bonzini break; 112953018216SPaolo Bonzini case 3: 113053018216SPaolo Bonzini next = 1 << 21; 113153018216SPaolo Bonzini break; 113253018216SPaolo Bonzini default: 113353018216SPaolo Bonzini /* Cannot occur, but makes gcc happy */ 113453018216SPaolo Bonzini return; 113553018216SPaolo Bonzini } 113673bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq); 113753018216SPaolo Bonzini if (next == now) 113853018216SPaolo Bonzini next++; 1139bc72ad67SAlex Bligh timer_mod(ppc40x_timer->fit_timer, next); 114053018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 26; 114153018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { 114253018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); 114353018216SPaolo Bonzini } 1144af96d2e6SCédric Le Goater trace_ppc4xx_fit((int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), 114553018216SPaolo Bonzini env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 114653018216SPaolo Bonzini } 114753018216SPaolo Bonzini 114853018216SPaolo Bonzini /* Programmable interval timer */ 114953018216SPaolo Bonzini static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) 115053018216SPaolo Bonzini { 115153018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 115253018216SPaolo Bonzini uint64_t now, next; 115353018216SPaolo Bonzini 115453018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 115553018216SPaolo Bonzini if (ppc40x_timer->pit_reload <= 1 || 115653018216SPaolo Bonzini !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || 115753018216SPaolo Bonzini (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { 115853018216SPaolo Bonzini /* Stop PIT */ 1159af96d2e6SCédric Le Goater trace_ppc4xx_pit_stop(); 1160bc72ad67SAlex Bligh timer_del(tb_env->decr_timer); 116153018216SPaolo Bonzini } else { 1162af96d2e6SCédric Le Goater trace_ppc4xx_pit_start(ppc40x_timer->pit_reload); 1163bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 116453018216SPaolo Bonzini next = now + muldiv64(ppc40x_timer->pit_reload, 116573bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, tb_env->decr_freq); 116653018216SPaolo Bonzini if (is_excp) 116753018216SPaolo Bonzini next += tb_env->decr_next - now; 116853018216SPaolo Bonzini if (next == now) 116953018216SPaolo Bonzini next++; 1170bc72ad67SAlex Bligh timer_mod(tb_env->decr_timer, next); 117153018216SPaolo Bonzini tb_env->decr_next = next; 117253018216SPaolo Bonzini } 117353018216SPaolo Bonzini } 117453018216SPaolo Bonzini 117553018216SPaolo Bonzini static void cpu_4xx_pit_cb (void *opaque) 117653018216SPaolo Bonzini { 1177b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1178b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 117953018216SPaolo Bonzini ppc_tb_t *tb_env; 118053018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 118153018216SPaolo Bonzini 118253018216SPaolo Bonzini tb_env = env->tb_env; 118353018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 118453018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 27; 118553018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { 118653018216SPaolo Bonzini ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); 118753018216SPaolo Bonzini } 118853018216SPaolo Bonzini start_stop_pit(env, tb_env, 1); 1189af96d2e6SCédric Le Goater trace_ppc4xx_pit((int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), 119053018216SPaolo Bonzini (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), 119153018216SPaolo Bonzini env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], 119253018216SPaolo Bonzini ppc40x_timer->pit_reload); 119353018216SPaolo Bonzini } 119453018216SPaolo Bonzini 119553018216SPaolo Bonzini /* Watchdog timer */ 119653018216SPaolo Bonzini static void cpu_4xx_wdt_cb (void *opaque) 119753018216SPaolo Bonzini { 1198b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1199b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 120053018216SPaolo Bonzini ppc_tb_t *tb_env; 120153018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 120253018216SPaolo Bonzini uint64_t now, next; 120353018216SPaolo Bonzini 120453018216SPaolo Bonzini tb_env = env->tb_env; 120553018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1206bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 120753018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { 120853018216SPaolo Bonzini case 0: 120953018216SPaolo Bonzini next = 1 << 17; 121053018216SPaolo Bonzini break; 121153018216SPaolo Bonzini case 1: 121253018216SPaolo Bonzini next = 1 << 21; 121353018216SPaolo Bonzini break; 121453018216SPaolo Bonzini case 2: 121553018216SPaolo Bonzini next = 1 << 25; 121653018216SPaolo Bonzini break; 121753018216SPaolo Bonzini case 3: 121853018216SPaolo Bonzini next = 1 << 29; 121953018216SPaolo Bonzini break; 122053018216SPaolo Bonzini default: 122153018216SPaolo Bonzini /* Cannot occur, but makes gcc happy */ 122253018216SPaolo Bonzini return; 122353018216SPaolo Bonzini } 122473bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 122553018216SPaolo Bonzini if (next == now) 122653018216SPaolo Bonzini next++; 1227af96d2e6SCédric Le Goater trace_ppc4xx_wdt(env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 122853018216SPaolo Bonzini switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { 122953018216SPaolo Bonzini case 0x0: 123053018216SPaolo Bonzini case 0x1: 1231bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 123253018216SPaolo Bonzini ppc40x_timer->wdt_next = next; 1233a1f7f97bSPeter Maydell env->spr[SPR_40x_TSR] |= 1U << 31; 123453018216SPaolo Bonzini break; 123553018216SPaolo Bonzini case 0x2: 1236bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 123753018216SPaolo Bonzini ppc40x_timer->wdt_next = next; 123853018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 30; 123953018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { 124053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); 124153018216SPaolo Bonzini } 124253018216SPaolo Bonzini break; 124353018216SPaolo Bonzini case 0x3: 124453018216SPaolo Bonzini env->spr[SPR_40x_TSR] &= ~0x30000000; 124553018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000; 124653018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) { 124753018216SPaolo Bonzini case 0x0: 124853018216SPaolo Bonzini /* No reset */ 124953018216SPaolo Bonzini break; 125053018216SPaolo Bonzini case 0x1: /* Core reset */ 125153018216SPaolo Bonzini ppc40x_core_reset(cpu); 125253018216SPaolo Bonzini break; 125353018216SPaolo Bonzini case 0x2: /* Chip reset */ 125453018216SPaolo Bonzini ppc40x_chip_reset(cpu); 125553018216SPaolo Bonzini break; 125653018216SPaolo Bonzini case 0x3: /* System reset */ 125753018216SPaolo Bonzini ppc40x_system_reset(cpu); 125853018216SPaolo Bonzini break; 125953018216SPaolo Bonzini } 126053018216SPaolo Bonzini } 126153018216SPaolo Bonzini } 126253018216SPaolo Bonzini 126353018216SPaolo Bonzini void store_40x_pit (CPUPPCState *env, target_ulong val) 126453018216SPaolo Bonzini { 126553018216SPaolo Bonzini ppc_tb_t *tb_env; 126653018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 126753018216SPaolo Bonzini 126853018216SPaolo Bonzini tb_env = env->tb_env; 126953018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1270af96d2e6SCédric Le Goater trace_ppc40x_store_pit(val); 127153018216SPaolo Bonzini ppc40x_timer->pit_reload = val; 127253018216SPaolo Bonzini start_stop_pit(env, tb_env, 0); 127353018216SPaolo Bonzini } 127453018216SPaolo Bonzini 127553018216SPaolo Bonzini target_ulong load_40x_pit (CPUPPCState *env) 127653018216SPaolo Bonzini { 127753018216SPaolo Bonzini return cpu_ppc_load_decr(env); 127853018216SPaolo Bonzini } 127953018216SPaolo Bonzini 1280cbd8f17dSCédric Le Goater void store_40x_tsr(CPUPPCState *env, target_ulong val) 1281cbd8f17dSCédric Le Goater { 1282cbd8f17dSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1283cbd8f17dSCédric Le Goater 1284cbd8f17dSCédric Le Goater trace_ppc40x_store_tcr(val); 1285cbd8f17dSCédric Le Goater 1286cbd8f17dSCédric Le Goater env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000); 1287cbd8f17dSCédric Le Goater if (val & 0x80000000) { 1288cbd8f17dSCédric Le Goater ppc_set_irq(cpu, PPC_INTERRUPT_PIT, 0); 1289cbd8f17dSCédric Le Goater } 1290cbd8f17dSCédric Le Goater } 1291cbd8f17dSCédric Le Goater 1292cbd8f17dSCédric Le Goater void store_40x_tcr(CPUPPCState *env, target_ulong val) 1293cbd8f17dSCédric Le Goater { 1294cbd8f17dSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1295cbd8f17dSCédric Le Goater ppc_tb_t *tb_env; 1296cbd8f17dSCédric Le Goater 1297cbd8f17dSCédric Le Goater trace_ppc40x_store_tsr(val); 1298cbd8f17dSCédric Le Goater 1299cbd8f17dSCédric Le Goater tb_env = env->tb_env; 1300cbd8f17dSCédric Le Goater env->spr[SPR_40x_TCR] = val & 0xFFC00000; 1301cbd8f17dSCédric Le Goater start_stop_pit(env, tb_env, 1); 1302cbd8f17dSCédric Le Goater cpu_4xx_wdt_cb(cpu); 1303cbd8f17dSCédric Le Goater } 1304cbd8f17dSCédric Le Goater 130553018216SPaolo Bonzini static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq) 130653018216SPaolo Bonzini { 130753018216SPaolo Bonzini CPUPPCState *env = opaque; 130853018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 130953018216SPaolo Bonzini 1310af96d2e6SCédric Le Goater trace_ppc40x_set_tb_clk(freq); 131153018216SPaolo Bonzini tb_env->tb_freq = freq; 131253018216SPaolo Bonzini tb_env->decr_freq = freq; 131353018216SPaolo Bonzini /* XXX: we should also update all timers */ 131453018216SPaolo Bonzini } 131553018216SPaolo Bonzini 131653018216SPaolo Bonzini clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, 131753018216SPaolo Bonzini unsigned int decr_excp) 131853018216SPaolo Bonzini { 131953018216SPaolo Bonzini ppc_tb_t *tb_env; 132053018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 1321b1273a5eSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1322b1273a5eSCédric Le Goater 1323b1273a5eSCédric Le Goater trace_ppc40x_timers_init(freq); 132453018216SPaolo Bonzini 1325b21e2380SMarkus Armbruster tb_env = g_new0(ppc_tb_t, 1); 1326b21e2380SMarkus Armbruster ppc40x_timer = g_new0(ppc40x_timer_t, 1); 1327b1273a5eSCédric Le Goater 132853018216SPaolo Bonzini env->tb_env = tb_env; 132953018216SPaolo Bonzini tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 133053018216SPaolo Bonzini tb_env->tb_freq = freq; 133153018216SPaolo Bonzini tb_env->decr_freq = freq; 133253018216SPaolo Bonzini tb_env->opaque = ppc40x_timer; 1333b1273a5eSCédric Le Goater 133453018216SPaolo Bonzini /* We use decr timer for PIT */ 1335b1273a5eSCédric Le Goater tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, cpu); 133653018216SPaolo Bonzini ppc40x_timer->fit_timer = 1337b1273a5eSCédric Le Goater timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, cpu); 133853018216SPaolo Bonzini ppc40x_timer->wdt_timer = 1339b1273a5eSCédric Le Goater timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, cpu); 134053018216SPaolo Bonzini ppc40x_timer->decr_excp = decr_excp; 134153018216SPaolo Bonzini 134253018216SPaolo Bonzini return &ppc_40x_set_tb_clk; 134353018216SPaolo Bonzini } 134453018216SPaolo Bonzini 134553018216SPaolo Bonzini /*****************************************************************************/ 134653018216SPaolo Bonzini /* Embedded PowerPC Device Control Registers */ 134753018216SPaolo Bonzini typedef struct ppc_dcrn_t ppc_dcrn_t; 134853018216SPaolo Bonzini struct ppc_dcrn_t { 134953018216SPaolo Bonzini dcr_read_cb dcr_read; 135053018216SPaolo Bonzini dcr_write_cb dcr_write; 135153018216SPaolo Bonzini void *opaque; 135253018216SPaolo Bonzini }; 135353018216SPaolo Bonzini 135453018216SPaolo Bonzini /* XXX: on 460, DCR addresses are 32 bits wide, 135553018216SPaolo Bonzini * using DCRIPR to get the 22 upper bits of the DCR address 135653018216SPaolo Bonzini */ 135753018216SPaolo Bonzini #define DCRN_NB 1024 135853018216SPaolo Bonzini struct ppc_dcr_t { 135953018216SPaolo Bonzini ppc_dcrn_t dcrn[DCRN_NB]; 136053018216SPaolo Bonzini int (*read_error)(int dcrn); 136153018216SPaolo Bonzini int (*write_error)(int dcrn); 136253018216SPaolo Bonzini }; 136353018216SPaolo Bonzini 136453018216SPaolo Bonzini int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) 136553018216SPaolo Bonzini { 136653018216SPaolo Bonzini ppc_dcrn_t *dcr; 136753018216SPaolo Bonzini 136853018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 136953018216SPaolo Bonzini goto error; 137053018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 137153018216SPaolo Bonzini if (dcr->dcr_read == NULL) 137253018216SPaolo Bonzini goto error; 137353018216SPaolo Bonzini *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); 1374de82dabeSCédric Le Goater trace_ppc_dcr_read(dcrn, *valp); 137553018216SPaolo Bonzini 137653018216SPaolo Bonzini return 0; 137753018216SPaolo Bonzini 137853018216SPaolo Bonzini error: 137953018216SPaolo Bonzini if (dcr_env->read_error != NULL) 138053018216SPaolo Bonzini return (*dcr_env->read_error)(dcrn); 138153018216SPaolo Bonzini 138253018216SPaolo Bonzini return -1; 138353018216SPaolo Bonzini } 138453018216SPaolo Bonzini 138553018216SPaolo Bonzini int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) 138653018216SPaolo Bonzini { 138753018216SPaolo Bonzini ppc_dcrn_t *dcr; 138853018216SPaolo Bonzini 138953018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 139053018216SPaolo Bonzini goto error; 139153018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 139253018216SPaolo Bonzini if (dcr->dcr_write == NULL) 139353018216SPaolo Bonzini goto error; 1394de82dabeSCédric Le Goater trace_ppc_dcr_write(dcrn, val); 139553018216SPaolo Bonzini (*dcr->dcr_write)(dcr->opaque, dcrn, val); 139653018216SPaolo Bonzini 139753018216SPaolo Bonzini return 0; 139853018216SPaolo Bonzini 139953018216SPaolo Bonzini error: 140053018216SPaolo Bonzini if (dcr_env->write_error != NULL) 140153018216SPaolo Bonzini return (*dcr_env->write_error)(dcrn); 140253018216SPaolo Bonzini 140353018216SPaolo Bonzini return -1; 140453018216SPaolo Bonzini } 140553018216SPaolo Bonzini 140653018216SPaolo Bonzini int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, 140753018216SPaolo Bonzini dcr_read_cb dcr_read, dcr_write_cb dcr_write) 140853018216SPaolo Bonzini { 140953018216SPaolo Bonzini ppc_dcr_t *dcr_env; 141053018216SPaolo Bonzini ppc_dcrn_t *dcr; 141153018216SPaolo Bonzini 141253018216SPaolo Bonzini dcr_env = env->dcr_env; 141353018216SPaolo Bonzini if (dcr_env == NULL) 141453018216SPaolo Bonzini return -1; 141553018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 141653018216SPaolo Bonzini return -1; 141753018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 141853018216SPaolo Bonzini if (dcr->opaque != NULL || 141953018216SPaolo Bonzini dcr->dcr_read != NULL || 142053018216SPaolo Bonzini dcr->dcr_write != NULL) 142153018216SPaolo Bonzini return -1; 142253018216SPaolo Bonzini dcr->opaque = opaque; 142353018216SPaolo Bonzini dcr->dcr_read = dcr_read; 142453018216SPaolo Bonzini dcr->dcr_write = dcr_write; 142553018216SPaolo Bonzini 142653018216SPaolo Bonzini return 0; 142753018216SPaolo Bonzini } 142853018216SPaolo Bonzini 142953018216SPaolo Bonzini int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn), 143053018216SPaolo Bonzini int (*write_error)(int dcrn)) 143153018216SPaolo Bonzini { 143253018216SPaolo Bonzini ppc_dcr_t *dcr_env; 143353018216SPaolo Bonzini 1434b21e2380SMarkus Armbruster dcr_env = g_new0(ppc_dcr_t, 1); 143553018216SPaolo Bonzini dcr_env->read_error = read_error; 143653018216SPaolo Bonzini dcr_env->write_error = write_error; 143753018216SPaolo Bonzini env->dcr_env = dcr_env; 143853018216SPaolo Bonzini 143953018216SPaolo Bonzini return 0; 144053018216SPaolo Bonzini } 144153018216SPaolo Bonzini 144253018216SPaolo Bonzini /*****************************************************************************/ 1443051e2973SCédric Le Goater 14444a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu) 14454a89e204SCédric Le Goater { 14464a89e204SCédric Le Goater CPUPPCState *env = &cpu->env; 14474a89e204SCédric Le Goater return env->spr_cb[SPR_PIR].default_value; 14484a89e204SCédric Le Goater } 14494a89e204SCédric Le Goater 1450051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir) 1451051e2973SCédric Le Goater { 1452051e2973SCédric Le Goater CPUState *cs; 1453051e2973SCédric Le Goater 1454051e2973SCédric Le Goater CPU_FOREACH(cs) { 1455051e2973SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 1456051e2973SCédric Le Goater 14574a89e204SCédric Le Goater if (ppc_cpu_pir(cpu) == pir) { 1458051e2973SCédric Le Goater return cpu; 1459051e2973SCédric Le Goater } 1460051e2973SCédric Le Goater } 1461051e2973SCédric Le Goater 1462051e2973SCédric Le Goater return NULL; 1463051e2973SCédric Le Goater } 146440177438SGreg Kurz 146540177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu) 146640177438SGreg Kurz { 146740177438SGreg Kurz CPUPPCState *env = &cpu->env; 146840177438SGreg Kurz 146940177438SGreg Kurz env->irq_input_state = 0; 147040177438SGreg Kurz kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); 147140177438SGreg Kurz } 1472