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 4353018216SPaolo Bonzini void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) 4453018216SPaolo Bonzini { 45d8ed887bSAndreas Färber CPUState *cs = CPU(cpu); 4653018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 478d04fb55SJan Kiszka unsigned int old_pending; 488d04fb55SJan Kiszka bool locked = false; 498d04fb55SJan Kiszka 508d04fb55SJan Kiszka /* We may already have the BQL if coming from the reset path */ 518d04fb55SJan Kiszka if (!qemu_mutex_iothread_locked()) { 528d04fb55SJan Kiszka locked = true; 538d04fb55SJan Kiszka qemu_mutex_lock_iothread(); 548d04fb55SJan Kiszka } 558d04fb55SJan Kiszka 568d04fb55SJan Kiszka old_pending = env->pending_interrupts; 5753018216SPaolo Bonzini 5853018216SPaolo Bonzini if (level) { 5953018216SPaolo Bonzini env->pending_interrupts |= 1 << n_IRQ; 60c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 6153018216SPaolo Bonzini } else { 6253018216SPaolo Bonzini env->pending_interrupts &= ~(1 << n_IRQ); 63d8ed887bSAndreas Färber if (env->pending_interrupts == 0) { 64d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 65d8ed887bSAndreas Färber } 6653018216SPaolo Bonzini } 6753018216SPaolo Bonzini 6853018216SPaolo Bonzini if (old_pending != env->pending_interrupts) { 6953018216SPaolo Bonzini kvmppc_set_interrupt(cpu, n_IRQ, level); 7053018216SPaolo Bonzini } 7153018216SPaolo Bonzini 728d04fb55SJan Kiszka 73af96d2e6SCédric Le Goater trace_ppc_irq_set_exit(env, n_IRQ, level, env->pending_interrupts, 74af96d2e6SCédric Le Goater CPU(cpu)->interrupt_request); 758d04fb55SJan Kiszka 768d04fb55SJan Kiszka if (locked) { 778d04fb55SJan Kiszka qemu_mutex_unlock_iothread(); 788d04fb55SJan Kiszka } 7953018216SPaolo Bonzini } 8053018216SPaolo Bonzini 8153018216SPaolo Bonzini /* PowerPC 6xx / 7xx internal IRQ controller */ 8253018216SPaolo Bonzini static void ppc6xx_set_irq(void *opaque, int pin, int level) 8353018216SPaolo Bonzini { 8453018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 8553018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 8653018216SPaolo Bonzini int cur_level; 8753018216SPaolo Bonzini 88af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 89af96d2e6SCédric Le Goater 9053018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 9153018216SPaolo Bonzini /* Don't generate spurious events */ 9253018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 93259186a7SAndreas Färber CPUState *cs = CPU(cpu); 94259186a7SAndreas Färber 9553018216SPaolo Bonzini switch (pin) { 9653018216SPaolo Bonzini case PPC6xx_INPUT_TBEN: 9753018216SPaolo Bonzini /* Level sensitive - active high */ 98af96d2e6SCédric Le Goater trace_ppc_irq_set_state("time base", level); 9953018216SPaolo Bonzini if (level) { 10053018216SPaolo Bonzini cpu_ppc_tb_start(env); 10153018216SPaolo Bonzini } else { 10253018216SPaolo Bonzini cpu_ppc_tb_stop(env); 10353018216SPaolo Bonzini } 104b2bd5b20SChen Qun break; 10553018216SPaolo Bonzini case PPC6xx_INPUT_INT: 10653018216SPaolo Bonzini /* Level sensitive - active high */ 107af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 10853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 10953018216SPaolo Bonzini break; 11053018216SPaolo Bonzini case PPC6xx_INPUT_SMI: 11153018216SPaolo Bonzini /* Level sensitive - active high */ 112af96d2e6SCédric Le Goater trace_ppc_irq_set_state("SMI IRQ", level); 11353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); 11453018216SPaolo Bonzini break; 11553018216SPaolo Bonzini case PPC6xx_INPUT_MCP: 11653018216SPaolo Bonzini /* Negative edge sensitive */ 11753018216SPaolo Bonzini /* XXX: TODO: actual reaction may depends on HID0 status 11853018216SPaolo Bonzini * 603/604/740/750: check HID0[EMCP] 11953018216SPaolo Bonzini */ 12053018216SPaolo Bonzini if (cur_level == 1 && level == 0) { 121af96d2e6SCédric Le Goater trace_ppc_irq_set_state("machine check", 1); 12253018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 12353018216SPaolo Bonzini } 12453018216SPaolo Bonzini break; 12553018216SPaolo Bonzini case PPC6xx_INPUT_CKSTP_IN: 12653018216SPaolo Bonzini /* Level sensitive - active low */ 12753018216SPaolo Bonzini /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 12853018216SPaolo Bonzini /* XXX: Note that the only way to restart the CPU is to reset it */ 12953018216SPaolo Bonzini if (level) { 130af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 131259186a7SAndreas Färber cs->halted = 1; 13253018216SPaolo Bonzini } 13353018216SPaolo Bonzini break; 13453018216SPaolo Bonzini case PPC6xx_INPUT_HRESET: 13553018216SPaolo Bonzini /* Level sensitive - active low */ 13653018216SPaolo Bonzini if (level) { 137af96d2e6SCédric Le Goater trace_ppc_irq_reset("CPU"); 138c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 13953018216SPaolo Bonzini } 14053018216SPaolo Bonzini break; 14153018216SPaolo Bonzini case PPC6xx_INPUT_SRESET: 142af96d2e6SCédric Le Goater trace_ppc_irq_set_state("RESET IRQ", level); 14353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 14453018216SPaolo Bonzini break; 14553018216SPaolo Bonzini default: 1467279810bSCédric Le Goater g_assert_not_reached(); 14753018216SPaolo Bonzini } 14853018216SPaolo Bonzini if (level) 14953018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 15053018216SPaolo Bonzini else 15153018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 15253018216SPaolo Bonzini } 15353018216SPaolo Bonzini } 15453018216SPaolo Bonzini 155aa5a9e24SPaolo Bonzini void ppc6xx_irq_init(PowerPCCPU *cpu) 15653018216SPaolo Bonzini { 157aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 15853018216SPaolo Bonzini 15953018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu, 16053018216SPaolo Bonzini PPC6xx_INPUT_NB); 16153018216SPaolo Bonzini } 16253018216SPaolo Bonzini 16353018216SPaolo Bonzini #if defined(TARGET_PPC64) 16453018216SPaolo Bonzini /* PowerPC 970 internal IRQ controller */ 16553018216SPaolo Bonzini static void ppc970_set_irq(void *opaque, int pin, int level) 16653018216SPaolo Bonzini { 16753018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 16853018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 16953018216SPaolo Bonzini int cur_level; 17053018216SPaolo Bonzini 171af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 172af96d2e6SCédric Le Goater 17353018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 17453018216SPaolo Bonzini /* Don't generate spurious events */ 17553018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 176259186a7SAndreas Färber CPUState *cs = CPU(cpu); 177259186a7SAndreas Färber 17853018216SPaolo Bonzini switch (pin) { 17953018216SPaolo Bonzini case PPC970_INPUT_INT: 18053018216SPaolo Bonzini /* Level sensitive - active high */ 181af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 18253018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 18353018216SPaolo Bonzini break; 18453018216SPaolo Bonzini case PPC970_INPUT_THINT: 18553018216SPaolo Bonzini /* Level sensitive - active high */ 186af96d2e6SCédric Le Goater trace_ppc_irq_set_state("SMI IRQ", level); 18753018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); 18853018216SPaolo Bonzini break; 18953018216SPaolo Bonzini case PPC970_INPUT_MCP: 19053018216SPaolo Bonzini /* Negative edge sensitive */ 19153018216SPaolo Bonzini /* XXX: TODO: actual reaction may depends on HID0 status 19253018216SPaolo Bonzini * 603/604/740/750: check HID0[EMCP] 19353018216SPaolo Bonzini */ 19453018216SPaolo Bonzini if (cur_level == 1 && level == 0) { 195af96d2e6SCédric Le Goater trace_ppc_irq_set_state("machine check", 1); 19653018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 19753018216SPaolo Bonzini } 19853018216SPaolo Bonzini break; 19953018216SPaolo Bonzini case PPC970_INPUT_CKSTP: 20053018216SPaolo Bonzini /* Level sensitive - active low */ 20153018216SPaolo Bonzini /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 20253018216SPaolo Bonzini if (level) { 203af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 204259186a7SAndreas Färber cs->halted = 1; 20553018216SPaolo Bonzini } else { 206af96d2e6SCédric Le Goater trace_ppc_irq_cpu("restart"); 207259186a7SAndreas Färber cs->halted = 0; 208259186a7SAndreas Färber qemu_cpu_kick(cs); 20953018216SPaolo Bonzini } 21053018216SPaolo Bonzini break; 21153018216SPaolo Bonzini case PPC970_INPUT_HRESET: 21253018216SPaolo Bonzini /* Level sensitive - active low */ 21353018216SPaolo Bonzini if (level) { 214c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 21553018216SPaolo Bonzini } 21653018216SPaolo Bonzini break; 21753018216SPaolo Bonzini case PPC970_INPUT_SRESET: 218af96d2e6SCédric Le Goater trace_ppc_irq_set_state("RESET IRQ", level); 21953018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 22053018216SPaolo Bonzini break; 22153018216SPaolo Bonzini case PPC970_INPUT_TBEN: 222af96d2e6SCédric Le Goater trace_ppc_irq_set_state("TBEN IRQ", level); 22353018216SPaolo Bonzini /* XXX: TODO */ 22453018216SPaolo Bonzini break; 22553018216SPaolo Bonzini default: 2267279810bSCédric Le Goater g_assert_not_reached(); 22753018216SPaolo Bonzini } 22853018216SPaolo Bonzini if (level) 22953018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 23053018216SPaolo Bonzini else 23153018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 23253018216SPaolo Bonzini } 23353018216SPaolo Bonzini } 23453018216SPaolo Bonzini 235aa5a9e24SPaolo Bonzini void ppc970_irq_init(PowerPCCPU *cpu) 23653018216SPaolo Bonzini { 237*9fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc970_set_irq, PPC970_INPUT_NB); 23853018216SPaolo Bonzini } 23953018216SPaolo Bonzini 24053018216SPaolo Bonzini /* POWER7 internal IRQ controller */ 24153018216SPaolo Bonzini static void power7_set_irq(void *opaque, int pin, int level) 24253018216SPaolo Bonzini { 24353018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 24453018216SPaolo Bonzini 245af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 24653018216SPaolo Bonzini 24753018216SPaolo Bonzini switch (pin) { 24853018216SPaolo Bonzini case POWER7_INPUT_INT: 24953018216SPaolo Bonzini /* Level sensitive - active high */ 250af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 25153018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 25253018216SPaolo Bonzini break; 25353018216SPaolo Bonzini default: 2547279810bSCédric Le Goater g_assert_not_reached(); 25553018216SPaolo Bonzini } 25653018216SPaolo Bonzini } 25753018216SPaolo Bonzini 258aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu) 25953018216SPaolo Bonzini { 260*9fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), power7_set_irq, POWER7_INPUT_NB); 26153018216SPaolo Bonzini } 26267afe775SBenjamin Herrenschmidt 26367afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */ 26467afe775SBenjamin Herrenschmidt static void power9_set_irq(void *opaque, int pin, int level) 26567afe775SBenjamin Herrenschmidt { 26667afe775SBenjamin Herrenschmidt PowerPCCPU *cpu = opaque; 26767afe775SBenjamin Herrenschmidt 268af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 26967afe775SBenjamin Herrenschmidt 27067afe775SBenjamin Herrenschmidt switch (pin) { 27167afe775SBenjamin Herrenschmidt case POWER9_INPUT_INT: 27267afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 273af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 27467afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 27567afe775SBenjamin Herrenschmidt break; 27667afe775SBenjamin Herrenschmidt case POWER9_INPUT_HINT: 27767afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 278af96d2e6SCédric Le Goater trace_ppc_irq_set_state("HV external IRQ", level); 27967afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level); 28067afe775SBenjamin Herrenschmidt break; 28167afe775SBenjamin Herrenschmidt default: 2827279810bSCédric Le Goater g_assert_not_reached(); 283af96d2e6SCédric Le Goater return; 28467afe775SBenjamin Herrenschmidt } 28567afe775SBenjamin Herrenschmidt } 28667afe775SBenjamin Herrenschmidt 28767afe775SBenjamin Herrenschmidt void ppcPOWER9_irq_init(PowerPCCPU *cpu) 28867afe775SBenjamin Herrenschmidt { 289*9fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), power9_set_irq, POWER9_INPUT_NB); 29067afe775SBenjamin Herrenschmidt } 29153018216SPaolo Bonzini #endif /* defined(TARGET_PPC64) */ 29253018216SPaolo Bonzini 29352144b69SThomas Huth void ppc40x_core_reset(PowerPCCPU *cpu) 29452144b69SThomas Huth { 29552144b69SThomas Huth CPUPPCState *env = &cpu->env; 29652144b69SThomas Huth target_ulong dbsr; 29752144b69SThomas Huth 29852144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n"); 29952144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 30052144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 30152144b69SThomas Huth dbsr &= ~0x00000300; 30252144b69SThomas Huth dbsr |= 0x00000100; 30352144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 30452144b69SThomas Huth } 30552144b69SThomas Huth 30652144b69SThomas Huth void ppc40x_chip_reset(PowerPCCPU *cpu) 30752144b69SThomas Huth { 30852144b69SThomas Huth CPUPPCState *env = &cpu->env; 30952144b69SThomas Huth target_ulong dbsr; 31052144b69SThomas Huth 31152144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n"); 31252144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 31352144b69SThomas Huth /* XXX: TODO reset all internal peripherals */ 31452144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 31552144b69SThomas Huth dbsr &= ~0x00000300; 31652144b69SThomas Huth dbsr |= 0x00000200; 31752144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 31852144b69SThomas Huth } 31952144b69SThomas Huth 32052144b69SThomas Huth void ppc40x_system_reset(PowerPCCPU *cpu) 32152144b69SThomas Huth { 32252144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n"); 32352144b69SThomas Huth qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 32452144b69SThomas Huth } 32552144b69SThomas Huth 32652144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val) 32752144b69SThomas Huth { 328db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 32952144b69SThomas Huth 3305ae3d2e8SThomas Huth qemu_mutex_lock_iothread(); 3315ae3d2e8SThomas Huth 33252144b69SThomas Huth switch ((val >> 28) & 0x3) { 33352144b69SThomas Huth case 0x0: 33452144b69SThomas Huth /* No action */ 33552144b69SThomas Huth break; 33652144b69SThomas Huth case 0x1: 33752144b69SThomas Huth /* Core reset */ 33852144b69SThomas Huth ppc40x_core_reset(cpu); 33952144b69SThomas Huth break; 34052144b69SThomas Huth case 0x2: 34152144b69SThomas Huth /* Chip reset */ 34252144b69SThomas Huth ppc40x_chip_reset(cpu); 34352144b69SThomas Huth break; 34452144b69SThomas Huth case 0x3: 34552144b69SThomas Huth /* System reset */ 34652144b69SThomas Huth ppc40x_system_reset(cpu); 34752144b69SThomas Huth break; 34852144b69SThomas Huth } 3495ae3d2e8SThomas Huth 3505ae3d2e8SThomas Huth qemu_mutex_unlock_iothread(); 35152144b69SThomas Huth } 35252144b69SThomas Huth 35353018216SPaolo Bonzini /* PowerPC 40x internal IRQ controller */ 35453018216SPaolo Bonzini static void ppc40x_set_irq(void *opaque, int pin, int level) 35553018216SPaolo Bonzini { 35653018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 35753018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 35853018216SPaolo Bonzini int cur_level; 35953018216SPaolo Bonzini 360af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 361af96d2e6SCédric Le Goater 36253018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 36353018216SPaolo Bonzini /* Don't generate spurious events */ 36453018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 365259186a7SAndreas Färber CPUState *cs = CPU(cpu); 366259186a7SAndreas Färber 36753018216SPaolo Bonzini switch (pin) { 36853018216SPaolo Bonzini case PPC40x_INPUT_RESET_SYS: 36953018216SPaolo Bonzini if (level) { 370af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 37153018216SPaolo Bonzini ppc40x_system_reset(cpu); 37253018216SPaolo Bonzini } 37353018216SPaolo Bonzini break; 37453018216SPaolo Bonzini case PPC40x_INPUT_RESET_CHIP: 37553018216SPaolo Bonzini if (level) { 376af96d2e6SCédric Le Goater trace_ppc_irq_reset("chip"); 37753018216SPaolo Bonzini ppc40x_chip_reset(cpu); 37853018216SPaolo Bonzini } 37953018216SPaolo Bonzini break; 38053018216SPaolo Bonzini case PPC40x_INPUT_RESET_CORE: 38153018216SPaolo Bonzini /* XXX: TODO: update DBSR[MRR] */ 38253018216SPaolo Bonzini if (level) { 383af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 38453018216SPaolo Bonzini ppc40x_core_reset(cpu); 38553018216SPaolo Bonzini } 38653018216SPaolo Bonzini break; 38753018216SPaolo Bonzini case PPC40x_INPUT_CINT: 38853018216SPaolo Bonzini /* Level sensitive - active high */ 389af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 39053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 39153018216SPaolo Bonzini break; 39253018216SPaolo Bonzini case PPC40x_INPUT_INT: 39353018216SPaolo Bonzini /* Level sensitive - active high */ 394af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 39553018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 39653018216SPaolo Bonzini break; 39753018216SPaolo Bonzini case PPC40x_INPUT_HALT: 39853018216SPaolo Bonzini /* Level sensitive - active low */ 39953018216SPaolo Bonzini if (level) { 400af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 401259186a7SAndreas Färber cs->halted = 1; 40253018216SPaolo Bonzini } else { 403af96d2e6SCédric Le Goater trace_ppc_irq_cpu("restart"); 404259186a7SAndreas Färber cs->halted = 0; 405259186a7SAndreas Färber qemu_cpu_kick(cs); 40653018216SPaolo Bonzini } 40753018216SPaolo Bonzini break; 40853018216SPaolo Bonzini case PPC40x_INPUT_DEBUG: 40953018216SPaolo Bonzini /* Level sensitive - active high */ 410af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 41153018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 41253018216SPaolo Bonzini break; 41353018216SPaolo Bonzini default: 4147279810bSCédric Le Goater g_assert_not_reached(); 41553018216SPaolo Bonzini } 41653018216SPaolo Bonzini if (level) 41753018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 41853018216SPaolo Bonzini else 41953018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 42053018216SPaolo Bonzini } 42153018216SPaolo Bonzini } 42253018216SPaolo Bonzini 423aa5a9e24SPaolo Bonzini void ppc40x_irq_init(PowerPCCPU *cpu) 42453018216SPaolo Bonzini { 425aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 42653018216SPaolo Bonzini 42753018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, 42853018216SPaolo Bonzini cpu, PPC40x_INPUT_NB); 42953018216SPaolo Bonzini } 43053018216SPaolo Bonzini 43153018216SPaolo Bonzini /* PowerPC E500 internal IRQ controller */ 43253018216SPaolo Bonzini static void ppce500_set_irq(void *opaque, int pin, int level) 43353018216SPaolo Bonzini { 43453018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 43553018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 43653018216SPaolo Bonzini int cur_level; 43753018216SPaolo Bonzini 438af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 439af96d2e6SCédric Le Goater 44053018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 44153018216SPaolo Bonzini /* Don't generate spurious events */ 44253018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 44353018216SPaolo Bonzini switch (pin) { 44453018216SPaolo Bonzini case PPCE500_INPUT_MCK: 44553018216SPaolo Bonzini if (level) { 446af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 447cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 44853018216SPaolo Bonzini } 44953018216SPaolo Bonzini break; 45053018216SPaolo Bonzini case PPCE500_INPUT_RESET_CORE: 45153018216SPaolo Bonzini if (level) { 452af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 45353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); 45453018216SPaolo Bonzini } 45553018216SPaolo Bonzini break; 45653018216SPaolo Bonzini case PPCE500_INPUT_CINT: 45753018216SPaolo Bonzini /* Level sensitive - active high */ 458af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 45953018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 46053018216SPaolo Bonzini break; 46153018216SPaolo Bonzini case PPCE500_INPUT_INT: 46253018216SPaolo Bonzini /* Level sensitive - active high */ 463af96d2e6SCédric Le Goater trace_ppc_irq_set_state("core IRQ", level); 46453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 46553018216SPaolo Bonzini break; 46653018216SPaolo Bonzini case PPCE500_INPUT_DEBUG: 46753018216SPaolo Bonzini /* Level sensitive - active high */ 468af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 46953018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 47053018216SPaolo Bonzini break; 47153018216SPaolo Bonzini default: 4727279810bSCédric Le Goater g_assert_not_reached(); 47353018216SPaolo Bonzini } 47453018216SPaolo Bonzini if (level) 47553018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 47653018216SPaolo Bonzini else 47753018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 47853018216SPaolo Bonzini } 47953018216SPaolo Bonzini } 48053018216SPaolo Bonzini 481aa5a9e24SPaolo Bonzini void ppce500_irq_init(PowerPCCPU *cpu) 48253018216SPaolo Bonzini { 483aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 48453018216SPaolo Bonzini 48553018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, 48653018216SPaolo Bonzini cpu, PPCE500_INPUT_NB); 48753018216SPaolo Bonzini } 48853018216SPaolo Bonzini 48953018216SPaolo Bonzini /* Enable or Disable the E500 EPR capability */ 49053018216SPaolo Bonzini void ppce500_set_mpic_proxy(bool enabled) 49153018216SPaolo Bonzini { 492182735efSAndreas Färber CPUState *cs; 49353018216SPaolo Bonzini 494bdc44640SAndreas Färber CPU_FOREACH(cs) { 495182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 49653018216SPaolo Bonzini 497182735efSAndreas Färber cpu->env.mpic_proxy = enabled; 49853018216SPaolo Bonzini if (kvm_enabled()) { 499182735efSAndreas Färber kvmppc_set_mpic_proxy(cpu, enabled); 50053018216SPaolo Bonzini } 50153018216SPaolo Bonzini } 50253018216SPaolo Bonzini } 50353018216SPaolo Bonzini 50453018216SPaolo Bonzini /*****************************************************************************/ 50553018216SPaolo Bonzini /* PowerPC time base and decrementer emulation */ 50653018216SPaolo Bonzini 50753018216SPaolo Bonzini uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) 50853018216SPaolo Bonzini { 50953018216SPaolo Bonzini /* TB time in tb periods */ 51073bcb24dSRutuja Shah return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset; 51153018216SPaolo Bonzini } 51253018216SPaolo Bonzini 51353018216SPaolo Bonzini uint64_t cpu_ppc_load_tbl (CPUPPCState *env) 51453018216SPaolo Bonzini { 51553018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 51653018216SPaolo Bonzini uint64_t tb; 51753018216SPaolo Bonzini 51853018216SPaolo Bonzini if (kvm_enabled()) { 51953018216SPaolo Bonzini return env->spr[SPR_TBL]; 52053018216SPaolo Bonzini } 52153018216SPaolo Bonzini 522bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 523af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 52453018216SPaolo Bonzini 52553018216SPaolo Bonzini return tb; 52653018216SPaolo Bonzini } 52753018216SPaolo Bonzini 52853018216SPaolo Bonzini static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) 52953018216SPaolo Bonzini { 53053018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 53153018216SPaolo Bonzini uint64_t tb; 53253018216SPaolo Bonzini 533bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 534af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 53553018216SPaolo Bonzini 53653018216SPaolo Bonzini return tb >> 32; 53753018216SPaolo Bonzini } 53853018216SPaolo Bonzini 53953018216SPaolo Bonzini uint32_t cpu_ppc_load_tbu (CPUPPCState *env) 54053018216SPaolo Bonzini { 54153018216SPaolo Bonzini if (kvm_enabled()) { 54253018216SPaolo Bonzini return env->spr[SPR_TBU]; 54353018216SPaolo Bonzini } 54453018216SPaolo Bonzini 54553018216SPaolo Bonzini return _cpu_ppc_load_tbu(env); 54653018216SPaolo Bonzini } 54753018216SPaolo Bonzini 54853018216SPaolo Bonzini static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, 54953018216SPaolo Bonzini int64_t *tb_offsetp, uint64_t value) 55053018216SPaolo Bonzini { 55173bcb24dSRutuja Shah *tb_offsetp = value - 55273bcb24dSRutuja Shah muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND); 55373bcb24dSRutuja Shah 554af96d2e6SCédric Le Goater trace_ppc_tb_store(value, *tb_offsetp); 55553018216SPaolo Bonzini } 55653018216SPaolo Bonzini 55753018216SPaolo Bonzini void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) 55853018216SPaolo Bonzini { 55953018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 56053018216SPaolo Bonzini uint64_t tb; 56153018216SPaolo Bonzini 562bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 56353018216SPaolo Bonzini tb &= 0xFFFFFFFF00000000ULL; 564bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 56553018216SPaolo Bonzini &tb_env->tb_offset, tb | (uint64_t)value); 56653018216SPaolo Bonzini } 56753018216SPaolo Bonzini 56853018216SPaolo Bonzini static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) 56953018216SPaolo Bonzini { 57053018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 57153018216SPaolo Bonzini uint64_t tb; 57253018216SPaolo Bonzini 573bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 57453018216SPaolo Bonzini tb &= 0x00000000FFFFFFFFULL; 575bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 57653018216SPaolo Bonzini &tb_env->tb_offset, ((uint64_t)value << 32) | tb); 57753018216SPaolo Bonzini } 57853018216SPaolo Bonzini 57953018216SPaolo Bonzini void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value) 58053018216SPaolo Bonzini { 58153018216SPaolo Bonzini _cpu_ppc_store_tbu(env, value); 58253018216SPaolo Bonzini } 58353018216SPaolo Bonzini 58453018216SPaolo Bonzini uint64_t cpu_ppc_load_atbl (CPUPPCState *env) 58553018216SPaolo Bonzini { 58653018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 58753018216SPaolo Bonzini uint64_t tb; 58853018216SPaolo Bonzini 589bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 590af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 59153018216SPaolo Bonzini 59253018216SPaolo Bonzini return tb; 59353018216SPaolo Bonzini } 59453018216SPaolo Bonzini 59553018216SPaolo Bonzini uint32_t cpu_ppc_load_atbu (CPUPPCState *env) 59653018216SPaolo Bonzini { 59753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 59853018216SPaolo Bonzini uint64_t tb; 59953018216SPaolo Bonzini 600bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 601af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 60253018216SPaolo Bonzini 60353018216SPaolo Bonzini return tb >> 32; 60453018216SPaolo Bonzini } 60553018216SPaolo Bonzini 60653018216SPaolo Bonzini void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) 60753018216SPaolo Bonzini { 60853018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 60953018216SPaolo Bonzini uint64_t tb; 61053018216SPaolo Bonzini 611bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 61253018216SPaolo Bonzini tb &= 0xFFFFFFFF00000000ULL; 613bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 61453018216SPaolo Bonzini &tb_env->atb_offset, tb | (uint64_t)value); 61553018216SPaolo Bonzini } 61653018216SPaolo Bonzini 61753018216SPaolo Bonzini void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) 61853018216SPaolo Bonzini { 61953018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 62053018216SPaolo Bonzini uint64_t tb; 62153018216SPaolo Bonzini 622bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 62353018216SPaolo Bonzini tb &= 0x00000000FFFFFFFFULL; 624bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 62553018216SPaolo Bonzini &tb_env->atb_offset, ((uint64_t)value << 32) | tb); 62653018216SPaolo Bonzini } 62753018216SPaolo Bonzini 6285d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env) 6295d62725bSSuraj Jitindar Singh { 6305d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6315d62725bSSuraj Jitindar Singh 6325d62725bSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6335d62725bSSuraj Jitindar Singh tb_env->vtb_offset); 6345d62725bSSuraj Jitindar Singh } 6355d62725bSSuraj Jitindar Singh 6365d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value) 6375d62725bSSuraj Jitindar Singh { 6385d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6395d62725bSSuraj Jitindar Singh 6405d62725bSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6415d62725bSSuraj Jitindar Singh &tb_env->vtb_offset, value); 6425d62725bSSuraj Jitindar Singh } 6435d62725bSSuraj Jitindar Singh 644f0ec31b1SSuraj Jitindar Singh void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value) 645f0ec31b1SSuraj Jitindar Singh { 646f0ec31b1SSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 647f0ec31b1SSuraj Jitindar Singh uint64_t tb; 648f0ec31b1SSuraj Jitindar Singh 649f0ec31b1SSuraj Jitindar Singh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 650f0ec31b1SSuraj Jitindar Singh tb_env->tb_offset); 651f0ec31b1SSuraj Jitindar Singh tb &= 0xFFFFFFUL; 652f0ec31b1SSuraj Jitindar Singh tb |= (value & ~0xFFFFFFUL); 653f0ec31b1SSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 654f0ec31b1SSuraj Jitindar Singh &tb_env->tb_offset, tb); 655f0ec31b1SSuraj Jitindar Singh } 656f0ec31b1SSuraj Jitindar Singh 65753018216SPaolo Bonzini static void cpu_ppc_tb_stop (CPUPPCState *env) 65853018216SPaolo Bonzini { 65953018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 66053018216SPaolo Bonzini uint64_t tb, atb, vmclk; 66153018216SPaolo Bonzini 66253018216SPaolo Bonzini /* If the time base is already frozen, do nothing */ 66353018216SPaolo Bonzini if (tb_env->tb_freq != 0) { 664bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 66553018216SPaolo Bonzini /* Get the time base */ 66653018216SPaolo Bonzini tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); 66753018216SPaolo Bonzini /* Get the alternate time base */ 66853018216SPaolo Bonzini atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); 66953018216SPaolo Bonzini /* Store the time base value (ie compute the current offset) */ 67053018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 67153018216SPaolo Bonzini /* Store the alternate time base value (compute the current offset) */ 67253018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 67353018216SPaolo Bonzini /* Set the time base frequency to zero */ 67453018216SPaolo Bonzini tb_env->tb_freq = 0; 67553018216SPaolo Bonzini /* Now, the time bases are frozen to tb_offset / atb_offset value */ 67653018216SPaolo Bonzini } 67753018216SPaolo Bonzini } 67853018216SPaolo Bonzini 67953018216SPaolo Bonzini static void cpu_ppc_tb_start (CPUPPCState *env) 68053018216SPaolo Bonzini { 68153018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 68253018216SPaolo Bonzini uint64_t tb, atb, vmclk; 68353018216SPaolo Bonzini 68453018216SPaolo Bonzini /* If the time base is not frozen, do nothing */ 68553018216SPaolo Bonzini if (tb_env->tb_freq == 0) { 686bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 68753018216SPaolo Bonzini /* Get the time base from tb_offset */ 68853018216SPaolo Bonzini tb = tb_env->tb_offset; 68953018216SPaolo Bonzini /* Get the alternate time base from atb_offset */ 69053018216SPaolo Bonzini atb = tb_env->atb_offset; 69153018216SPaolo Bonzini /* Restore the tb frequency from the decrementer frequency */ 69253018216SPaolo Bonzini tb_env->tb_freq = tb_env->decr_freq; 69353018216SPaolo Bonzini /* Store the time base value */ 69453018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 69553018216SPaolo Bonzini /* Store the alternate time base value */ 69653018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 69753018216SPaolo Bonzini } 69853018216SPaolo Bonzini } 69953018216SPaolo Bonzini 700e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env) 701e81a982aSAlexander Graf { 702e81a982aSAlexander Graf ppc_tb_t *tb_env = env->tb_env; 703e81a982aSAlexander Graf int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL; 704e81a982aSAlexander Graf return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED); 705e81a982aSAlexander Graf } 706e81a982aSAlexander Graf 707a8dafa52SSuraj Jitindar Singh static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) 70853018216SPaolo Bonzini { 70953018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 710a8dafa52SSuraj Jitindar Singh int64_t decr, diff; 71153018216SPaolo Bonzini 712bc72ad67SAlex Bligh diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 71353018216SPaolo Bonzini if (diff >= 0) { 71473bcb24dSRutuja Shah decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 71553018216SPaolo Bonzini } else if (tb_env->flags & PPC_TIMER_BOOKE) { 71653018216SPaolo Bonzini decr = 0; 71753018216SPaolo Bonzini } else { 71873bcb24dSRutuja Shah decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 71953018216SPaolo Bonzini } 720af96d2e6SCédric Le Goater trace_ppc_decr_load(decr); 72153018216SPaolo Bonzini 72253018216SPaolo Bonzini return decr; 72353018216SPaolo Bonzini } 72453018216SPaolo Bonzini 725a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_decr(CPUPPCState *env) 72653018216SPaolo Bonzini { 72753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 728a8dafa52SSuraj Jitindar Singh uint64_t decr; 72953018216SPaolo Bonzini 73053018216SPaolo Bonzini if (kvm_enabled()) { 73153018216SPaolo Bonzini return env->spr[SPR_DECR]; 73253018216SPaolo Bonzini } 73353018216SPaolo Bonzini 734a8dafa52SSuraj Jitindar Singh decr = _cpu_ppc_load_decr(env, tb_env->decr_next); 735a8dafa52SSuraj Jitindar Singh 736a8dafa52SSuraj Jitindar Singh /* 737a8dafa52SSuraj Jitindar Singh * If large decrementer is enabled then the decrementer is signed extened 738a8dafa52SSuraj Jitindar Singh * to 64 bits, otherwise it is a 32 bit value. 739a8dafa52SSuraj Jitindar Singh */ 740a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 741a8dafa52SSuraj Jitindar Singh return decr; 742a8dafa52SSuraj Jitindar Singh } 743a8dafa52SSuraj Jitindar Singh return (uint32_t) decr; 74453018216SPaolo Bonzini } 74553018216SPaolo Bonzini 746a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_hdecr(CPUPPCState *env) 74753018216SPaolo Bonzini { 748db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 749a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 75053018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 751a8dafa52SSuraj Jitindar Singh uint64_t hdecr; 75253018216SPaolo Bonzini 753a8dafa52SSuraj Jitindar Singh hdecr = _cpu_ppc_load_decr(env, tb_env->hdecr_next); 754a8dafa52SSuraj Jitindar Singh 755a8dafa52SSuraj Jitindar Singh /* 756a8dafa52SSuraj Jitindar Singh * If we have a large decrementer (POWER9 or later) then hdecr is sign 757a8dafa52SSuraj Jitindar Singh * extended to 64 bits, otherwise it is 32 bits. 758a8dafa52SSuraj Jitindar Singh */ 759a8dafa52SSuraj Jitindar Singh if (pcc->lrg_decr_bits > 32) { 760a8dafa52SSuraj Jitindar Singh return hdecr; 761a8dafa52SSuraj Jitindar Singh } 762a8dafa52SSuraj Jitindar Singh return (uint32_t) hdecr; 76353018216SPaolo Bonzini } 76453018216SPaolo Bonzini 76553018216SPaolo Bonzini uint64_t cpu_ppc_load_purr (CPUPPCState *env) 76653018216SPaolo Bonzini { 76753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 76853018216SPaolo Bonzini 7695cc7e69fSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 7705cc7e69fSSuraj Jitindar Singh tb_env->purr_offset); 77153018216SPaolo Bonzini } 77253018216SPaolo Bonzini 77353018216SPaolo Bonzini /* When decrementer expires, 77453018216SPaolo Bonzini * all we need to do is generate or queue a CPU exception 77553018216SPaolo Bonzini */ 77653018216SPaolo Bonzini static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) 77753018216SPaolo Bonzini { 77853018216SPaolo Bonzini /* Raise it */ 779af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise"); 78053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); 78153018216SPaolo Bonzini } 78253018216SPaolo Bonzini 783e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu) 784e81a982aSAlexander Graf { 785e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0); 786e81a982aSAlexander Graf } 787e81a982aSAlexander Graf 78853018216SPaolo Bonzini static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) 78953018216SPaolo Bonzini { 7904b236b62SBenjamin Herrenschmidt CPUPPCState *env = &cpu->env; 7914b236b62SBenjamin Herrenschmidt 79253018216SPaolo Bonzini /* Raise it */ 793af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise HV"); 7944b236b62SBenjamin Herrenschmidt 7954b236b62SBenjamin Herrenschmidt /* The architecture specifies that we don't deliver HDEC 7964b236b62SBenjamin Herrenschmidt * interrupts in a PM state. Not only they don't cause a 7974b236b62SBenjamin Herrenschmidt * wakeup but they also get effectively discarded. 7984b236b62SBenjamin Herrenschmidt */ 7991e7fd61dSBenjamin Herrenschmidt if (!env->resume_as_sreset) { 80053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); 80153018216SPaolo Bonzini } 8024b236b62SBenjamin Herrenschmidt } 80353018216SPaolo Bonzini 804e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) 805e81a982aSAlexander Graf { 806e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); 807e81a982aSAlexander Graf } 808e81a982aSAlexander Graf 80953018216SPaolo Bonzini static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, 8101246b259SStefan Weil QEMUTimer *timer, 811e81a982aSAlexander Graf void (*raise_excp)(void *), 812e81a982aSAlexander Graf void (*lower_excp)(PowerPCCPU *), 813a8dafa52SSuraj Jitindar Singh target_ulong decr, target_ulong value, 814a8dafa52SSuraj Jitindar Singh int nr_bits) 81553018216SPaolo Bonzini { 81653018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 81753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 81853018216SPaolo Bonzini uint64_t now, next; 8194d9b8ef9SCédric Le Goater int64_t signed_value; 8204d9b8ef9SCédric Le Goater int64_t signed_decr; 82153018216SPaolo Bonzini 822a8dafa52SSuraj Jitindar Singh /* Truncate value to decr_width and sign extend for simplicity */ 8234d9b8ef9SCédric Le Goater signed_value = sextract64(value, 0, nr_bits); 8244d9b8ef9SCédric Le Goater signed_decr = sextract64(decr, 0, nr_bits); 825a8dafa52SSuraj Jitindar Singh 826af96d2e6SCédric Le Goater trace_ppc_decr_store(nr_bits, decr, value); 82753018216SPaolo Bonzini 82853018216SPaolo Bonzini if (kvm_enabled()) { 82953018216SPaolo Bonzini /* KVM handles decrementer exceptions, we don't need our own timer */ 83053018216SPaolo Bonzini return; 83153018216SPaolo Bonzini } 83253018216SPaolo Bonzini 833e81a982aSAlexander Graf /* 834e81a982aSAlexander Graf * Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC 835e81a982aSAlexander Graf * interrupt. 836e81a982aSAlexander Graf * 837e81a982aSAlexander Graf * If we get a really small DEC value, we can assume that by the time we 838e81a982aSAlexander Graf * handled it we should inject an interrupt already. 839e81a982aSAlexander Graf * 840e81a982aSAlexander Graf * On MSB level based DEC implementations the MSB always means the interrupt 841e81a982aSAlexander Graf * is pending, so raise it on those. 842e81a982aSAlexander Graf * 843e81a982aSAlexander Graf * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers 844e81a982aSAlexander Graf * an edge interrupt, so raise it here too. 845e81a982aSAlexander Graf */ 846a8dcb8daSCédric Le Goater if ((value < 3) || 8474d9b8ef9SCédric Le Goater ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) || 8484d9b8ef9SCédric Le Goater ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0 8494d9b8ef9SCédric Le Goater && signed_decr >= 0)) { 850e81a982aSAlexander Graf (*raise_excp)(cpu); 851e81a982aSAlexander Graf return; 852e81a982aSAlexander Graf } 853e81a982aSAlexander Graf 854e81a982aSAlexander Graf /* On MSB level based systems a 0 for the MSB stops interrupt delivery */ 8554d9b8ef9SCédric Le Goater if (signed_value >= 0 && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) { 856e81a982aSAlexander Graf (*lower_excp)(cpu); 857e81a982aSAlexander Graf } 858e81a982aSAlexander Graf 859e81a982aSAlexander Graf /* Calculate the next timer event */ 860bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 86173bcb24dSRutuja Shah next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 86253018216SPaolo Bonzini *nextp = next; 863e81a982aSAlexander Graf 86453018216SPaolo Bonzini /* Adjust timer */ 865bc72ad67SAlex Bligh timer_mod(timer, next); 86653018216SPaolo Bonzini } 86753018216SPaolo Bonzini 868a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr, 869a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 87053018216SPaolo Bonzini { 87153018216SPaolo Bonzini ppc_tb_t *tb_env = cpu->env.tb_env; 87253018216SPaolo Bonzini 87353018216SPaolo Bonzini __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, 874e81a982aSAlexander Graf tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr, 875a8dafa52SSuraj Jitindar Singh value, nr_bits); 87653018216SPaolo Bonzini } 87753018216SPaolo Bonzini 878a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value) 87953018216SPaolo Bonzini { 880db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 881a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 882a8dafa52SSuraj Jitindar Singh int nr_bits = 32; 88353018216SPaolo Bonzini 884a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 885a8dafa52SSuraj Jitindar Singh nr_bits = pcc->lrg_decr_bits; 886a8dafa52SSuraj Jitindar Singh } 887a8dafa52SSuraj Jitindar Singh 888a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, nr_bits); 88953018216SPaolo Bonzini } 89053018216SPaolo Bonzini 89153018216SPaolo Bonzini static void cpu_ppc_decr_cb(void *opaque) 89253018216SPaolo Bonzini { 89353018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 89453018216SPaolo Bonzini 895e81a982aSAlexander Graf cpu_ppc_decr_excp(cpu); 89653018216SPaolo Bonzini } 89753018216SPaolo Bonzini 898a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr, 899a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 90053018216SPaolo Bonzini { 90153018216SPaolo Bonzini ppc_tb_t *tb_env = cpu->env.tb_env; 90253018216SPaolo Bonzini 90353018216SPaolo Bonzini if (tb_env->hdecr_timer != NULL) { 90453018216SPaolo Bonzini __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, 905e81a982aSAlexander Graf tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower, 906a8dafa52SSuraj Jitindar Singh hdecr, value, nr_bits); 90753018216SPaolo Bonzini } 90853018216SPaolo Bonzini } 90953018216SPaolo Bonzini 910a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value) 91153018216SPaolo Bonzini { 912db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 913a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 91453018216SPaolo Bonzini 915a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 916a8dafa52SSuraj Jitindar Singh pcc->lrg_decr_bits); 91753018216SPaolo Bonzini } 91853018216SPaolo Bonzini 91953018216SPaolo Bonzini static void cpu_ppc_hdecr_cb(void *opaque) 92053018216SPaolo Bonzini { 92153018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 92253018216SPaolo Bonzini 923e81a982aSAlexander Graf cpu_ppc_hdecr_excp(cpu); 92453018216SPaolo Bonzini } 92553018216SPaolo Bonzini 9265cc7e69fSSuraj Jitindar Singh void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) 92753018216SPaolo Bonzini { 9285cc7e69fSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 92953018216SPaolo Bonzini 9305cc7e69fSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 9315cc7e69fSSuraj Jitindar Singh &tb_env->purr_offset, value); 93253018216SPaolo Bonzini } 93353018216SPaolo Bonzini 93453018216SPaolo Bonzini static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) 93553018216SPaolo Bonzini { 93653018216SPaolo Bonzini CPUPPCState *env = opaque; 937db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 93853018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 93953018216SPaolo Bonzini 94053018216SPaolo Bonzini tb_env->tb_freq = freq; 94153018216SPaolo Bonzini tb_env->decr_freq = freq; 94253018216SPaolo Bonzini /* There is a bug in Linux 2.4 kernels: 94353018216SPaolo Bonzini * if a decrementer exception is pending when it enables msr_ee at startup, 94453018216SPaolo Bonzini * it's not ready to handle it... 94553018216SPaolo Bonzini */ 946a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 947a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 9485cc7e69fSSuraj Jitindar Singh cpu_ppc_store_purr(env, 0x0000000000000000ULL); 94953018216SPaolo Bonzini } 95053018216SPaolo Bonzini 95142043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb) 95298a8b524SAlexey Kardashevskiy { 9534a7428c5SChristopher Covington uint64_t ticks = cpu_get_host_ticks(); 95498a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 95598a8b524SAlexey Kardashevskiy 95698a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 95798a8b524SAlexey Kardashevskiy error_report("No timebase object"); 95898a8b524SAlexey Kardashevskiy return; 95998a8b524SAlexey Kardashevskiy } 96098a8b524SAlexey Kardashevskiy 96142043e4fSLaurent Vivier /* not used anymore, we keep it for compatibility */ 96277bad151SPaolo Bonzini tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); 96398a8b524SAlexey Kardashevskiy /* 96442043e4fSLaurent Vivier * tb_offset is only expected to be changed by QEMU so 96598a8b524SAlexey Kardashevskiy * there is no need to update it from KVM here 96698a8b524SAlexey Kardashevskiy */ 96798a8b524SAlexey Kardashevskiy tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; 968d14f3397SMaxiwell S. Garcia 969711dfb24SGreg Kurz tb->runstate_paused = 970711dfb24SGreg Kurz runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM); 97198a8b524SAlexey Kardashevskiy } 97298a8b524SAlexey Kardashevskiy 97342043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb) 97498a8b524SAlexey Kardashevskiy { 97598a8b524SAlexey Kardashevskiy CPUState *cpu; 97698a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 97742043e4fSLaurent Vivier int64_t tb_off_adj, tb_off; 97898a8b524SAlexey Kardashevskiy unsigned long freq; 97998a8b524SAlexey Kardashevskiy 98098a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 98198a8b524SAlexey Kardashevskiy error_report("No timebase object"); 98242043e4fSLaurent Vivier return; 98398a8b524SAlexey Kardashevskiy } 98498a8b524SAlexey Kardashevskiy 98598a8b524SAlexey Kardashevskiy freq = first_ppc_cpu->env.tb_env->tb_freq; 98698a8b524SAlexey Kardashevskiy 98742043e4fSLaurent Vivier tb_off_adj = tb->guest_timebase - cpu_get_host_ticks(); 98898a8b524SAlexey Kardashevskiy 98998a8b524SAlexey Kardashevskiy tb_off = first_ppc_cpu->env.tb_env->tb_offset; 99098a8b524SAlexey Kardashevskiy trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off, 99198a8b524SAlexey Kardashevskiy (tb_off_adj - tb_off) / freq); 99298a8b524SAlexey Kardashevskiy 99398a8b524SAlexey Kardashevskiy /* Set new offset to all CPUs */ 99498a8b524SAlexey Kardashevskiy CPU_FOREACH(cpu) { 99598a8b524SAlexey Kardashevskiy PowerPCCPU *pcpu = POWERPC_CPU(cpu); 99698a8b524SAlexey Kardashevskiy pcpu->env.tb_env->tb_offset = tb_off_adj; 9979723295aSGreg Kurz kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset); 99842043e4fSLaurent Vivier } 99998a8b524SAlexey Kardashevskiy } 100098a8b524SAlexey Kardashevskiy 1001538f0497SPhilippe Mathieu-Daudé void cpu_ppc_clock_vm_state_change(void *opaque, bool running, 100242043e4fSLaurent Vivier RunState state) 100342043e4fSLaurent Vivier { 100442043e4fSLaurent Vivier PPCTimebase *tb = opaque; 100542043e4fSLaurent Vivier 100642043e4fSLaurent Vivier if (running) { 100742043e4fSLaurent Vivier timebase_load(tb); 100842043e4fSLaurent Vivier } else { 100942043e4fSLaurent Vivier timebase_save(tb); 101042043e4fSLaurent Vivier } 101142043e4fSLaurent Vivier } 101242043e4fSLaurent Vivier 101342043e4fSLaurent Vivier /* 1014d14f3397SMaxiwell S. Garcia * When migrating a running guest, read the clock just 1015d14f3397SMaxiwell S. Garcia * before migration, so that the guest clock counts 1016d14f3397SMaxiwell S. Garcia * during the events between: 101742043e4fSLaurent Vivier * 101842043e4fSLaurent Vivier * * vm_stop() 101942043e4fSLaurent Vivier * * 102042043e4fSLaurent Vivier * * pre_save() 102142043e4fSLaurent Vivier * 102242043e4fSLaurent Vivier * This reduces clock difference on migration from 5s 102342043e4fSLaurent Vivier * to 0.1s (when max_downtime == 5s), because sending the 102442043e4fSLaurent Vivier * final pages of memory (which happens between vm_stop() 102542043e4fSLaurent Vivier * and pre_save()) takes max_downtime. 102642043e4fSLaurent Vivier */ 102744b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque) 102842043e4fSLaurent Vivier { 102942043e4fSLaurent Vivier PPCTimebase *tb = opaque; 103042043e4fSLaurent Vivier 1031711dfb24SGreg Kurz /* guest_timebase won't be overridden in case of paused guest or savevm */ 1032d14f3397SMaxiwell S. Garcia if (!tb->runstate_paused) { 103342043e4fSLaurent Vivier timebase_save(tb); 1034d14f3397SMaxiwell S. Garcia } 103544b1ff31SDr. David Alan Gilbert 103644b1ff31SDr. David Alan Gilbert return 0; 103798a8b524SAlexey Kardashevskiy } 103898a8b524SAlexey Kardashevskiy 103998a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = { 104098a8b524SAlexey Kardashevskiy .name = "timebase", 104198a8b524SAlexey Kardashevskiy .version_id = 1, 104298a8b524SAlexey Kardashevskiy .minimum_version_id = 1, 104398a8b524SAlexey Kardashevskiy .pre_save = timebase_pre_save, 104498a8b524SAlexey Kardashevskiy .fields = (VMStateField []) { 104598a8b524SAlexey Kardashevskiy VMSTATE_UINT64(guest_timebase, PPCTimebase), 104698a8b524SAlexey Kardashevskiy VMSTATE_INT64(time_of_the_day_ns, PPCTimebase), 104798a8b524SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 104898a8b524SAlexey Kardashevskiy }, 104998a8b524SAlexey Kardashevskiy }; 105098a8b524SAlexey Kardashevskiy 105153018216SPaolo Bonzini /* Set up (once) timebase frequency (in Hz) */ 105253018216SPaolo Bonzini clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) 105353018216SPaolo Bonzini { 1054db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 105553018216SPaolo Bonzini ppc_tb_t *tb_env; 105653018216SPaolo Bonzini 1057b21e2380SMarkus Armbruster tb_env = g_new0(ppc_tb_t, 1); 105853018216SPaolo Bonzini env->tb_env = tb_env; 105953018216SPaolo Bonzini tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 1060d0db7cadSGreg Kurz if (is_book3s_arch2x(env)) { 1061e81a982aSAlexander Graf /* All Book3S 64bit CPUs implement level based DEC logic */ 1062e81a982aSAlexander Graf tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL; 1063e81a982aSAlexander Graf } 106453018216SPaolo Bonzini /* Create new timer */ 1065bc72ad67SAlex Bligh tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); 10665ff40b01SNicholas Piggin if (env->has_hv_mode && !cpu->vhyp) { 1067bc72ad67SAlex Bligh tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, 106853018216SPaolo Bonzini cpu); 106953018216SPaolo Bonzini } else { 107053018216SPaolo Bonzini tb_env->hdecr_timer = NULL; 107153018216SPaolo Bonzini } 107253018216SPaolo Bonzini cpu_ppc_set_tb_clk(env, freq); 107353018216SPaolo Bonzini 107453018216SPaolo Bonzini return &cpu_ppc_set_tb_clk; 107553018216SPaolo Bonzini } 107653018216SPaolo Bonzini 1077ef95a244SDaniel Henrique Barboza void cpu_ppc_tb_free(CPUPPCState *env) 1078ef95a244SDaniel Henrique Barboza { 1079ef95a244SDaniel Henrique Barboza timer_free(env->tb_env->decr_timer); 1080ef95a244SDaniel Henrique Barboza timer_free(env->tb_env->hdecr_timer); 1081ef95a244SDaniel Henrique Barboza g_free(env->tb_env); 1082ef95a244SDaniel Henrique Barboza } 1083ef95a244SDaniel Henrique Barboza 108493aeb702SNicholas Piggin /* cpu_ppc_hdecr_init may be used if the timer is not used by HDEC emulation */ 108593aeb702SNicholas Piggin void cpu_ppc_hdecr_init(CPUPPCState *env) 108693aeb702SNicholas Piggin { 108793aeb702SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 108893aeb702SNicholas Piggin 108993aeb702SNicholas Piggin assert(env->tb_env->hdecr_timer == NULL); 109093aeb702SNicholas Piggin 109193aeb702SNicholas Piggin env->tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 109293aeb702SNicholas Piggin &cpu_ppc_hdecr_cb, cpu); 109393aeb702SNicholas Piggin } 109493aeb702SNicholas Piggin 109593aeb702SNicholas Piggin void cpu_ppc_hdecr_exit(CPUPPCState *env) 109693aeb702SNicholas Piggin { 109793aeb702SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 109893aeb702SNicholas Piggin 109993aeb702SNicholas Piggin timer_free(env->tb_env->hdecr_timer); 110093aeb702SNicholas Piggin env->tb_env->hdecr_timer = NULL; 110193aeb702SNicholas Piggin 110293aeb702SNicholas Piggin cpu_ppc_hdecr_lower(cpu); 110393aeb702SNicholas Piggin } 110493aeb702SNicholas Piggin 110553018216SPaolo Bonzini /*****************************************************************************/ 110653018216SPaolo Bonzini /* PowerPC 40x timers */ 110753018216SPaolo Bonzini 110853018216SPaolo Bonzini /* PIT, FIT & WDT */ 110953018216SPaolo Bonzini typedef struct ppc40x_timer_t ppc40x_timer_t; 111053018216SPaolo Bonzini struct ppc40x_timer_t { 111153018216SPaolo Bonzini uint64_t pit_reload; /* PIT auto-reload value */ 111253018216SPaolo Bonzini uint64_t fit_next; /* Tick for next FIT interrupt */ 11131246b259SStefan Weil QEMUTimer *fit_timer; 111453018216SPaolo Bonzini uint64_t wdt_next; /* Tick for next WDT interrupt */ 11151246b259SStefan Weil QEMUTimer *wdt_timer; 111653018216SPaolo Bonzini 111753018216SPaolo Bonzini /* 405 have the PIT, 440 have a DECR. */ 111853018216SPaolo Bonzini unsigned int decr_excp; 111953018216SPaolo Bonzini }; 112053018216SPaolo Bonzini 112153018216SPaolo Bonzini /* Fixed interval timer */ 112253018216SPaolo Bonzini static void cpu_4xx_fit_cb (void *opaque) 112353018216SPaolo Bonzini { 1124b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1125b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 112653018216SPaolo Bonzini ppc_tb_t *tb_env; 112753018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 112853018216SPaolo Bonzini uint64_t now, next; 112953018216SPaolo Bonzini 113053018216SPaolo Bonzini tb_env = env->tb_env; 113153018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1132bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 113353018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { 113453018216SPaolo Bonzini case 0: 113553018216SPaolo Bonzini next = 1 << 9; 113653018216SPaolo Bonzini break; 113753018216SPaolo Bonzini case 1: 113853018216SPaolo Bonzini next = 1 << 13; 113953018216SPaolo Bonzini break; 114053018216SPaolo Bonzini case 2: 114153018216SPaolo Bonzini next = 1 << 17; 114253018216SPaolo Bonzini break; 114353018216SPaolo Bonzini case 3: 114453018216SPaolo Bonzini next = 1 << 21; 114553018216SPaolo Bonzini break; 114653018216SPaolo Bonzini default: 114753018216SPaolo Bonzini /* Cannot occur, but makes gcc happy */ 114853018216SPaolo Bonzini return; 114953018216SPaolo Bonzini } 115073bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq); 115153018216SPaolo Bonzini if (next == now) 115253018216SPaolo Bonzini next++; 1153bc72ad67SAlex Bligh timer_mod(ppc40x_timer->fit_timer, next); 115453018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 26; 115553018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { 115653018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); 115753018216SPaolo Bonzini } 1158af96d2e6SCédric Le Goater trace_ppc4xx_fit((int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), 115953018216SPaolo Bonzini env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 116053018216SPaolo Bonzini } 116153018216SPaolo Bonzini 116253018216SPaolo Bonzini /* Programmable interval timer */ 116353018216SPaolo Bonzini static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) 116453018216SPaolo Bonzini { 116553018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 116653018216SPaolo Bonzini uint64_t now, next; 116753018216SPaolo Bonzini 116853018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 116953018216SPaolo Bonzini if (ppc40x_timer->pit_reload <= 1 || 117053018216SPaolo Bonzini !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || 117153018216SPaolo Bonzini (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { 117253018216SPaolo Bonzini /* Stop PIT */ 1173af96d2e6SCédric Le Goater trace_ppc4xx_pit_stop(); 1174bc72ad67SAlex Bligh timer_del(tb_env->decr_timer); 117553018216SPaolo Bonzini } else { 1176af96d2e6SCédric Le Goater trace_ppc4xx_pit_start(ppc40x_timer->pit_reload); 1177bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 117853018216SPaolo Bonzini next = now + muldiv64(ppc40x_timer->pit_reload, 117973bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, tb_env->decr_freq); 118053018216SPaolo Bonzini if (is_excp) 118153018216SPaolo Bonzini next += tb_env->decr_next - now; 118253018216SPaolo Bonzini if (next == now) 118353018216SPaolo Bonzini next++; 1184bc72ad67SAlex Bligh timer_mod(tb_env->decr_timer, next); 118553018216SPaolo Bonzini tb_env->decr_next = next; 118653018216SPaolo Bonzini } 118753018216SPaolo Bonzini } 118853018216SPaolo Bonzini 118953018216SPaolo Bonzini static void cpu_4xx_pit_cb (void *opaque) 119053018216SPaolo Bonzini { 1191b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1192b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 119353018216SPaolo Bonzini ppc_tb_t *tb_env; 119453018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 119553018216SPaolo Bonzini 119653018216SPaolo Bonzini tb_env = env->tb_env; 119753018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 119853018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 27; 119953018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { 120053018216SPaolo Bonzini ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); 120153018216SPaolo Bonzini } 120253018216SPaolo Bonzini start_stop_pit(env, tb_env, 1); 1203af96d2e6SCédric Le Goater trace_ppc4xx_pit((int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), 120453018216SPaolo Bonzini (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), 120553018216SPaolo Bonzini env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], 120653018216SPaolo Bonzini ppc40x_timer->pit_reload); 120753018216SPaolo Bonzini } 120853018216SPaolo Bonzini 120953018216SPaolo Bonzini /* Watchdog timer */ 121053018216SPaolo Bonzini static void cpu_4xx_wdt_cb (void *opaque) 121153018216SPaolo Bonzini { 1212b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1213b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 121453018216SPaolo Bonzini ppc_tb_t *tb_env; 121553018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 121653018216SPaolo Bonzini uint64_t now, next; 121753018216SPaolo Bonzini 121853018216SPaolo Bonzini tb_env = env->tb_env; 121953018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1220bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 122153018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { 122253018216SPaolo Bonzini case 0: 122353018216SPaolo Bonzini next = 1 << 17; 122453018216SPaolo Bonzini break; 122553018216SPaolo Bonzini case 1: 122653018216SPaolo Bonzini next = 1 << 21; 122753018216SPaolo Bonzini break; 122853018216SPaolo Bonzini case 2: 122953018216SPaolo Bonzini next = 1 << 25; 123053018216SPaolo Bonzini break; 123153018216SPaolo Bonzini case 3: 123253018216SPaolo Bonzini next = 1 << 29; 123353018216SPaolo Bonzini break; 123453018216SPaolo Bonzini default: 123553018216SPaolo Bonzini /* Cannot occur, but makes gcc happy */ 123653018216SPaolo Bonzini return; 123753018216SPaolo Bonzini } 123873bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 123953018216SPaolo Bonzini if (next == now) 124053018216SPaolo Bonzini next++; 1241af96d2e6SCédric Le Goater trace_ppc4xx_wdt(env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 124253018216SPaolo Bonzini switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { 124353018216SPaolo Bonzini case 0x0: 124453018216SPaolo Bonzini case 0x1: 1245bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 124653018216SPaolo Bonzini ppc40x_timer->wdt_next = next; 1247a1f7f97bSPeter Maydell env->spr[SPR_40x_TSR] |= 1U << 31; 124853018216SPaolo Bonzini break; 124953018216SPaolo Bonzini case 0x2: 1250bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 125153018216SPaolo Bonzini ppc40x_timer->wdt_next = next; 125253018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 30; 125353018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { 125453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); 125553018216SPaolo Bonzini } 125653018216SPaolo Bonzini break; 125753018216SPaolo Bonzini case 0x3: 125853018216SPaolo Bonzini env->spr[SPR_40x_TSR] &= ~0x30000000; 125953018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000; 126053018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) { 126153018216SPaolo Bonzini case 0x0: 126253018216SPaolo Bonzini /* No reset */ 126353018216SPaolo Bonzini break; 126453018216SPaolo Bonzini case 0x1: /* Core reset */ 126553018216SPaolo Bonzini ppc40x_core_reset(cpu); 126653018216SPaolo Bonzini break; 126753018216SPaolo Bonzini case 0x2: /* Chip reset */ 126853018216SPaolo Bonzini ppc40x_chip_reset(cpu); 126953018216SPaolo Bonzini break; 127053018216SPaolo Bonzini case 0x3: /* System reset */ 127153018216SPaolo Bonzini ppc40x_system_reset(cpu); 127253018216SPaolo Bonzini break; 127353018216SPaolo Bonzini } 127453018216SPaolo Bonzini } 127553018216SPaolo Bonzini } 127653018216SPaolo Bonzini 127753018216SPaolo Bonzini void store_40x_pit (CPUPPCState *env, target_ulong val) 127853018216SPaolo Bonzini { 127953018216SPaolo Bonzini ppc_tb_t *tb_env; 128053018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 128153018216SPaolo Bonzini 128253018216SPaolo Bonzini tb_env = env->tb_env; 128353018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1284af96d2e6SCédric Le Goater trace_ppc40x_store_pit(val); 128553018216SPaolo Bonzini ppc40x_timer->pit_reload = val; 128653018216SPaolo Bonzini start_stop_pit(env, tb_env, 0); 128753018216SPaolo Bonzini } 128853018216SPaolo Bonzini 128953018216SPaolo Bonzini target_ulong load_40x_pit (CPUPPCState *env) 129053018216SPaolo Bonzini { 129153018216SPaolo Bonzini return cpu_ppc_load_decr(env); 129253018216SPaolo Bonzini } 129353018216SPaolo Bonzini 1294cbd8f17dSCédric Le Goater void store_40x_tsr(CPUPPCState *env, target_ulong val) 1295cbd8f17dSCédric Le Goater { 1296cbd8f17dSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1297cbd8f17dSCédric Le Goater 1298cbd8f17dSCédric Le Goater trace_ppc40x_store_tcr(val); 1299cbd8f17dSCédric Le Goater 1300cbd8f17dSCédric Le Goater env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000); 1301cbd8f17dSCédric Le Goater if (val & 0x80000000) { 1302cbd8f17dSCédric Le Goater ppc_set_irq(cpu, PPC_INTERRUPT_PIT, 0); 1303cbd8f17dSCédric Le Goater } 1304cbd8f17dSCédric Le Goater } 1305cbd8f17dSCédric Le Goater 1306cbd8f17dSCédric Le Goater void store_40x_tcr(CPUPPCState *env, target_ulong val) 1307cbd8f17dSCédric Le Goater { 1308cbd8f17dSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1309cbd8f17dSCédric Le Goater ppc_tb_t *tb_env; 1310cbd8f17dSCédric Le Goater 1311cbd8f17dSCédric Le Goater trace_ppc40x_store_tsr(val); 1312cbd8f17dSCédric Le Goater 1313cbd8f17dSCédric Le Goater tb_env = env->tb_env; 1314cbd8f17dSCédric Le Goater env->spr[SPR_40x_TCR] = val & 0xFFC00000; 1315cbd8f17dSCédric Le Goater start_stop_pit(env, tb_env, 1); 1316cbd8f17dSCédric Le Goater cpu_4xx_wdt_cb(cpu); 1317cbd8f17dSCédric Le Goater } 1318cbd8f17dSCédric Le Goater 131953018216SPaolo Bonzini static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq) 132053018216SPaolo Bonzini { 132153018216SPaolo Bonzini CPUPPCState *env = opaque; 132253018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 132353018216SPaolo Bonzini 1324af96d2e6SCédric Le Goater trace_ppc40x_set_tb_clk(freq); 132553018216SPaolo Bonzini tb_env->tb_freq = freq; 132653018216SPaolo Bonzini tb_env->decr_freq = freq; 132753018216SPaolo Bonzini /* XXX: we should also update all timers */ 132853018216SPaolo Bonzini } 132953018216SPaolo Bonzini 133053018216SPaolo Bonzini clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, 133153018216SPaolo Bonzini unsigned int decr_excp) 133253018216SPaolo Bonzini { 133353018216SPaolo Bonzini ppc_tb_t *tb_env; 133453018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 1335b1273a5eSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1336b1273a5eSCédric Le Goater 1337b1273a5eSCédric Le Goater trace_ppc40x_timers_init(freq); 133853018216SPaolo Bonzini 1339b21e2380SMarkus Armbruster tb_env = g_new0(ppc_tb_t, 1); 1340b21e2380SMarkus Armbruster ppc40x_timer = g_new0(ppc40x_timer_t, 1); 1341b1273a5eSCédric Le Goater 134253018216SPaolo Bonzini env->tb_env = tb_env; 134353018216SPaolo Bonzini tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 134453018216SPaolo Bonzini tb_env->tb_freq = freq; 134553018216SPaolo Bonzini tb_env->decr_freq = freq; 134653018216SPaolo Bonzini tb_env->opaque = ppc40x_timer; 1347b1273a5eSCédric Le Goater 134853018216SPaolo Bonzini /* We use decr timer for PIT */ 1349b1273a5eSCédric Le Goater tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, cpu); 135053018216SPaolo Bonzini ppc40x_timer->fit_timer = 1351b1273a5eSCédric Le Goater timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, cpu); 135253018216SPaolo Bonzini ppc40x_timer->wdt_timer = 1353b1273a5eSCédric Le Goater timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, cpu); 135453018216SPaolo Bonzini ppc40x_timer->decr_excp = decr_excp; 135553018216SPaolo Bonzini 135653018216SPaolo Bonzini return &ppc_40x_set_tb_clk; 135753018216SPaolo Bonzini } 135853018216SPaolo Bonzini 135953018216SPaolo Bonzini /*****************************************************************************/ 136053018216SPaolo Bonzini /* Embedded PowerPC Device Control Registers */ 136153018216SPaolo Bonzini typedef struct ppc_dcrn_t ppc_dcrn_t; 136253018216SPaolo Bonzini struct ppc_dcrn_t { 136353018216SPaolo Bonzini dcr_read_cb dcr_read; 136453018216SPaolo Bonzini dcr_write_cb dcr_write; 136553018216SPaolo Bonzini void *opaque; 136653018216SPaolo Bonzini }; 136753018216SPaolo Bonzini 136853018216SPaolo Bonzini /* XXX: on 460, DCR addresses are 32 bits wide, 136953018216SPaolo Bonzini * using DCRIPR to get the 22 upper bits of the DCR address 137053018216SPaolo Bonzini */ 137153018216SPaolo Bonzini #define DCRN_NB 1024 137253018216SPaolo Bonzini struct ppc_dcr_t { 137353018216SPaolo Bonzini ppc_dcrn_t dcrn[DCRN_NB]; 137453018216SPaolo Bonzini int (*read_error)(int dcrn); 137553018216SPaolo Bonzini int (*write_error)(int dcrn); 137653018216SPaolo Bonzini }; 137753018216SPaolo Bonzini 137853018216SPaolo Bonzini int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) 137953018216SPaolo Bonzini { 138053018216SPaolo Bonzini ppc_dcrn_t *dcr; 138153018216SPaolo Bonzini 138253018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 138353018216SPaolo Bonzini goto error; 138453018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 138553018216SPaolo Bonzini if (dcr->dcr_read == NULL) 138653018216SPaolo Bonzini goto error; 138753018216SPaolo Bonzini *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); 1388de82dabeSCédric Le Goater trace_ppc_dcr_read(dcrn, *valp); 138953018216SPaolo Bonzini 139053018216SPaolo Bonzini return 0; 139153018216SPaolo Bonzini 139253018216SPaolo Bonzini error: 139353018216SPaolo Bonzini if (dcr_env->read_error != NULL) 139453018216SPaolo Bonzini return (*dcr_env->read_error)(dcrn); 139553018216SPaolo Bonzini 139653018216SPaolo Bonzini return -1; 139753018216SPaolo Bonzini } 139853018216SPaolo Bonzini 139953018216SPaolo Bonzini int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) 140053018216SPaolo Bonzini { 140153018216SPaolo Bonzini ppc_dcrn_t *dcr; 140253018216SPaolo Bonzini 140353018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 140453018216SPaolo Bonzini goto error; 140553018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 140653018216SPaolo Bonzini if (dcr->dcr_write == NULL) 140753018216SPaolo Bonzini goto error; 1408de82dabeSCédric Le Goater trace_ppc_dcr_write(dcrn, val); 140953018216SPaolo Bonzini (*dcr->dcr_write)(dcr->opaque, dcrn, val); 141053018216SPaolo Bonzini 141153018216SPaolo Bonzini return 0; 141253018216SPaolo Bonzini 141353018216SPaolo Bonzini error: 141453018216SPaolo Bonzini if (dcr_env->write_error != NULL) 141553018216SPaolo Bonzini return (*dcr_env->write_error)(dcrn); 141653018216SPaolo Bonzini 141753018216SPaolo Bonzini return -1; 141853018216SPaolo Bonzini } 141953018216SPaolo Bonzini 142053018216SPaolo Bonzini int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, 142153018216SPaolo Bonzini dcr_read_cb dcr_read, dcr_write_cb dcr_write) 142253018216SPaolo Bonzini { 142353018216SPaolo Bonzini ppc_dcr_t *dcr_env; 142453018216SPaolo Bonzini ppc_dcrn_t *dcr; 142553018216SPaolo Bonzini 142653018216SPaolo Bonzini dcr_env = env->dcr_env; 142753018216SPaolo Bonzini if (dcr_env == NULL) 142853018216SPaolo Bonzini return -1; 142953018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 143053018216SPaolo Bonzini return -1; 143153018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 143253018216SPaolo Bonzini if (dcr->opaque != NULL || 143353018216SPaolo Bonzini dcr->dcr_read != NULL || 143453018216SPaolo Bonzini dcr->dcr_write != NULL) 143553018216SPaolo Bonzini return -1; 143653018216SPaolo Bonzini dcr->opaque = opaque; 143753018216SPaolo Bonzini dcr->dcr_read = dcr_read; 143853018216SPaolo Bonzini dcr->dcr_write = dcr_write; 143953018216SPaolo Bonzini 144053018216SPaolo Bonzini return 0; 144153018216SPaolo Bonzini } 144253018216SPaolo Bonzini 144353018216SPaolo Bonzini int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn), 144453018216SPaolo Bonzini int (*write_error)(int dcrn)) 144553018216SPaolo Bonzini { 144653018216SPaolo Bonzini ppc_dcr_t *dcr_env; 144753018216SPaolo Bonzini 1448b21e2380SMarkus Armbruster dcr_env = g_new0(ppc_dcr_t, 1); 144953018216SPaolo Bonzini dcr_env->read_error = read_error; 145053018216SPaolo Bonzini dcr_env->write_error = write_error; 145153018216SPaolo Bonzini env->dcr_env = dcr_env; 145253018216SPaolo Bonzini 145353018216SPaolo Bonzini return 0; 145453018216SPaolo Bonzini } 145553018216SPaolo Bonzini 145653018216SPaolo Bonzini /*****************************************************************************/ 1457051e2973SCédric Le Goater 14584a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu) 14594a89e204SCédric Le Goater { 14604a89e204SCédric Le Goater CPUPPCState *env = &cpu->env; 14614a89e204SCédric Le Goater return env->spr_cb[SPR_PIR].default_value; 14624a89e204SCédric Le Goater } 14634a89e204SCédric Le Goater 1464051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir) 1465051e2973SCédric Le Goater { 1466051e2973SCédric Le Goater CPUState *cs; 1467051e2973SCédric Le Goater 1468051e2973SCédric Le Goater CPU_FOREACH(cs) { 1469051e2973SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 1470051e2973SCédric Le Goater 14714a89e204SCédric Le Goater if (ppc_cpu_pir(cpu) == pir) { 1472051e2973SCédric Le Goater return cpu; 1473051e2973SCédric Le Goater } 1474051e2973SCédric Le Goater } 1475051e2973SCédric Le Goater 1476051e2973SCédric Le Goater return NULL; 1477051e2973SCédric Le Goater } 147840177438SGreg Kurz 147940177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu) 148040177438SGreg Kurz { 148140177438SGreg Kurz CPUPPCState *env = &cpu->env; 148240177438SGreg Kurz 148340177438SGreg Kurz env->irq_input_state = 0; 148440177438SGreg Kurz kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); 148540177438SGreg Kurz } 1486