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 { 237aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 23853018216SPaolo Bonzini 23953018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu, 24053018216SPaolo Bonzini PPC970_INPUT_NB); 24153018216SPaolo Bonzini } 24253018216SPaolo Bonzini 24353018216SPaolo Bonzini /* POWER7 internal IRQ controller */ 24453018216SPaolo Bonzini static void power7_set_irq(void *opaque, int pin, int level) 24553018216SPaolo Bonzini { 24653018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 24753018216SPaolo Bonzini 248af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 24953018216SPaolo Bonzini 25053018216SPaolo Bonzini switch (pin) { 25153018216SPaolo Bonzini case POWER7_INPUT_INT: 25253018216SPaolo Bonzini /* Level sensitive - active high */ 253af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 25453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 25553018216SPaolo Bonzini break; 25653018216SPaolo Bonzini default: 2577279810bSCédric Le Goater g_assert_not_reached(); 25853018216SPaolo Bonzini } 25953018216SPaolo Bonzini } 26053018216SPaolo Bonzini 261aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu) 26253018216SPaolo Bonzini { 263aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 26453018216SPaolo Bonzini 26553018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu, 26653018216SPaolo Bonzini POWER7_INPUT_NB); 26753018216SPaolo Bonzini } 26867afe775SBenjamin Herrenschmidt 26967afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */ 27067afe775SBenjamin Herrenschmidt static void power9_set_irq(void *opaque, int pin, int level) 27167afe775SBenjamin Herrenschmidt { 27267afe775SBenjamin Herrenschmidt PowerPCCPU *cpu = opaque; 27367afe775SBenjamin Herrenschmidt 274af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 27567afe775SBenjamin Herrenschmidt 27667afe775SBenjamin Herrenschmidt switch (pin) { 27767afe775SBenjamin Herrenschmidt case POWER9_INPUT_INT: 27867afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 279af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 28067afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 28167afe775SBenjamin Herrenschmidt break; 28267afe775SBenjamin Herrenschmidt case POWER9_INPUT_HINT: 28367afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 284af96d2e6SCédric Le Goater trace_ppc_irq_set_state("HV external IRQ", level); 28567afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level); 28667afe775SBenjamin Herrenschmidt break; 28767afe775SBenjamin Herrenschmidt default: 2887279810bSCédric Le Goater g_assert_not_reached(); 289af96d2e6SCédric Le Goater return; 29067afe775SBenjamin Herrenschmidt } 29167afe775SBenjamin Herrenschmidt } 29267afe775SBenjamin Herrenschmidt 29367afe775SBenjamin Herrenschmidt void ppcPOWER9_irq_init(PowerPCCPU *cpu) 29467afe775SBenjamin Herrenschmidt { 29567afe775SBenjamin Herrenschmidt CPUPPCState *env = &cpu->env; 29667afe775SBenjamin Herrenschmidt 29767afe775SBenjamin Herrenschmidt env->irq_inputs = (void **)qemu_allocate_irqs(&power9_set_irq, cpu, 29867afe775SBenjamin Herrenschmidt POWER9_INPUT_NB); 29967afe775SBenjamin Herrenschmidt } 30053018216SPaolo Bonzini #endif /* defined(TARGET_PPC64) */ 30153018216SPaolo Bonzini 30252144b69SThomas Huth void ppc40x_core_reset(PowerPCCPU *cpu) 30352144b69SThomas Huth { 30452144b69SThomas Huth CPUPPCState *env = &cpu->env; 30552144b69SThomas Huth target_ulong dbsr; 30652144b69SThomas Huth 30752144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n"); 30852144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 30952144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 31052144b69SThomas Huth dbsr &= ~0x00000300; 31152144b69SThomas Huth dbsr |= 0x00000100; 31252144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 31352144b69SThomas Huth } 31452144b69SThomas Huth 31552144b69SThomas Huth void ppc40x_chip_reset(PowerPCCPU *cpu) 31652144b69SThomas Huth { 31752144b69SThomas Huth CPUPPCState *env = &cpu->env; 31852144b69SThomas Huth target_ulong dbsr; 31952144b69SThomas Huth 32052144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n"); 32152144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 32252144b69SThomas Huth /* XXX: TODO reset all internal peripherals */ 32352144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 32452144b69SThomas Huth dbsr &= ~0x00000300; 32552144b69SThomas Huth dbsr |= 0x00000200; 32652144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 32752144b69SThomas Huth } 32852144b69SThomas Huth 32952144b69SThomas Huth void ppc40x_system_reset(PowerPCCPU *cpu) 33052144b69SThomas Huth { 33152144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n"); 33252144b69SThomas Huth qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 33352144b69SThomas Huth } 33452144b69SThomas Huth 33552144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val) 33652144b69SThomas Huth { 337db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 33852144b69SThomas Huth 3395ae3d2e8SThomas Huth qemu_mutex_lock_iothread(); 3405ae3d2e8SThomas Huth 34152144b69SThomas Huth switch ((val >> 28) & 0x3) { 34252144b69SThomas Huth case 0x0: 34352144b69SThomas Huth /* No action */ 34452144b69SThomas Huth break; 34552144b69SThomas Huth case 0x1: 34652144b69SThomas Huth /* Core reset */ 34752144b69SThomas Huth ppc40x_core_reset(cpu); 34852144b69SThomas Huth break; 34952144b69SThomas Huth case 0x2: 35052144b69SThomas Huth /* Chip reset */ 35152144b69SThomas Huth ppc40x_chip_reset(cpu); 35252144b69SThomas Huth break; 35352144b69SThomas Huth case 0x3: 35452144b69SThomas Huth /* System reset */ 35552144b69SThomas Huth ppc40x_system_reset(cpu); 35652144b69SThomas Huth break; 35752144b69SThomas Huth } 3585ae3d2e8SThomas Huth 3595ae3d2e8SThomas Huth qemu_mutex_unlock_iothread(); 36052144b69SThomas Huth } 36152144b69SThomas Huth 36253018216SPaolo Bonzini /* PowerPC 40x internal IRQ controller */ 36353018216SPaolo Bonzini static void ppc40x_set_irq(void *opaque, int pin, int level) 36453018216SPaolo Bonzini { 36553018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 36653018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 36753018216SPaolo Bonzini int cur_level; 36853018216SPaolo Bonzini 369af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 370af96d2e6SCédric Le Goater 37153018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 37253018216SPaolo Bonzini /* Don't generate spurious events */ 37353018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 374259186a7SAndreas Färber CPUState *cs = CPU(cpu); 375259186a7SAndreas Färber 37653018216SPaolo Bonzini switch (pin) { 37753018216SPaolo Bonzini case PPC40x_INPUT_RESET_SYS: 37853018216SPaolo Bonzini if (level) { 379af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 38053018216SPaolo Bonzini ppc40x_system_reset(cpu); 38153018216SPaolo Bonzini } 38253018216SPaolo Bonzini break; 38353018216SPaolo Bonzini case PPC40x_INPUT_RESET_CHIP: 38453018216SPaolo Bonzini if (level) { 385af96d2e6SCédric Le Goater trace_ppc_irq_reset("chip"); 38653018216SPaolo Bonzini ppc40x_chip_reset(cpu); 38753018216SPaolo Bonzini } 38853018216SPaolo Bonzini break; 38953018216SPaolo Bonzini case PPC40x_INPUT_RESET_CORE: 39053018216SPaolo Bonzini /* XXX: TODO: update DBSR[MRR] */ 39153018216SPaolo Bonzini if (level) { 392af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 39353018216SPaolo Bonzini ppc40x_core_reset(cpu); 39453018216SPaolo Bonzini } 39553018216SPaolo Bonzini break; 39653018216SPaolo Bonzini case PPC40x_INPUT_CINT: 39753018216SPaolo Bonzini /* Level sensitive - active high */ 398af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 39953018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 40053018216SPaolo Bonzini break; 40153018216SPaolo Bonzini case PPC40x_INPUT_INT: 40253018216SPaolo Bonzini /* Level sensitive - active high */ 403af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 40453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 40553018216SPaolo Bonzini break; 40653018216SPaolo Bonzini case PPC40x_INPUT_HALT: 40753018216SPaolo Bonzini /* Level sensitive - active low */ 40853018216SPaolo Bonzini if (level) { 409af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 410259186a7SAndreas Färber cs->halted = 1; 41153018216SPaolo Bonzini } else { 412af96d2e6SCédric Le Goater trace_ppc_irq_cpu("restart"); 413259186a7SAndreas Färber cs->halted = 0; 414259186a7SAndreas Färber qemu_cpu_kick(cs); 41553018216SPaolo Bonzini } 41653018216SPaolo Bonzini break; 41753018216SPaolo Bonzini case PPC40x_INPUT_DEBUG: 41853018216SPaolo Bonzini /* Level sensitive - active high */ 419af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 42053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 42153018216SPaolo Bonzini break; 42253018216SPaolo Bonzini default: 4237279810bSCédric Le Goater g_assert_not_reached(); 42453018216SPaolo Bonzini } 42553018216SPaolo Bonzini if (level) 42653018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 42753018216SPaolo Bonzini else 42853018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 42953018216SPaolo Bonzini } 43053018216SPaolo Bonzini } 43153018216SPaolo Bonzini 432aa5a9e24SPaolo Bonzini void ppc40x_irq_init(PowerPCCPU *cpu) 43353018216SPaolo Bonzini { 434aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 43553018216SPaolo Bonzini 43653018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, 43753018216SPaolo Bonzini cpu, PPC40x_INPUT_NB); 43853018216SPaolo Bonzini } 43953018216SPaolo Bonzini 44053018216SPaolo Bonzini /* PowerPC E500 internal IRQ controller */ 44153018216SPaolo Bonzini static void ppce500_set_irq(void *opaque, int pin, int level) 44253018216SPaolo Bonzini { 44353018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 44453018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 44553018216SPaolo Bonzini int cur_level; 44653018216SPaolo Bonzini 447af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 448af96d2e6SCédric Le Goater 44953018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 45053018216SPaolo Bonzini /* Don't generate spurious events */ 45153018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 45253018216SPaolo Bonzini switch (pin) { 45353018216SPaolo Bonzini case PPCE500_INPUT_MCK: 45453018216SPaolo Bonzini if (level) { 455af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 456cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 45753018216SPaolo Bonzini } 45853018216SPaolo Bonzini break; 45953018216SPaolo Bonzini case PPCE500_INPUT_RESET_CORE: 46053018216SPaolo Bonzini if (level) { 461af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 46253018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); 46353018216SPaolo Bonzini } 46453018216SPaolo Bonzini break; 46553018216SPaolo Bonzini case PPCE500_INPUT_CINT: 46653018216SPaolo Bonzini /* Level sensitive - active high */ 467af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 46853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 46953018216SPaolo Bonzini break; 47053018216SPaolo Bonzini case PPCE500_INPUT_INT: 47153018216SPaolo Bonzini /* Level sensitive - active high */ 472af96d2e6SCédric Le Goater trace_ppc_irq_set_state("core IRQ", level); 47353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 47453018216SPaolo Bonzini break; 47553018216SPaolo Bonzini case PPCE500_INPUT_DEBUG: 47653018216SPaolo Bonzini /* Level sensitive - active high */ 477af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 47853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 47953018216SPaolo Bonzini break; 48053018216SPaolo Bonzini default: 4817279810bSCédric Le Goater g_assert_not_reached(); 48253018216SPaolo Bonzini } 48353018216SPaolo Bonzini if (level) 48453018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 48553018216SPaolo Bonzini else 48653018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 48753018216SPaolo Bonzini } 48853018216SPaolo Bonzini } 48953018216SPaolo Bonzini 490aa5a9e24SPaolo Bonzini void ppce500_irq_init(PowerPCCPU *cpu) 49153018216SPaolo Bonzini { 492aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 49353018216SPaolo Bonzini 49453018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, 49553018216SPaolo Bonzini cpu, PPCE500_INPUT_NB); 49653018216SPaolo Bonzini } 49753018216SPaolo Bonzini 49853018216SPaolo Bonzini /* Enable or Disable the E500 EPR capability */ 49953018216SPaolo Bonzini void ppce500_set_mpic_proxy(bool enabled) 50053018216SPaolo Bonzini { 501182735efSAndreas Färber CPUState *cs; 50253018216SPaolo Bonzini 503bdc44640SAndreas Färber CPU_FOREACH(cs) { 504182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 50553018216SPaolo Bonzini 506182735efSAndreas Färber cpu->env.mpic_proxy = enabled; 50753018216SPaolo Bonzini if (kvm_enabled()) { 508182735efSAndreas Färber kvmppc_set_mpic_proxy(cpu, enabled); 50953018216SPaolo Bonzini } 51053018216SPaolo Bonzini } 51153018216SPaolo Bonzini } 51253018216SPaolo Bonzini 51353018216SPaolo Bonzini /*****************************************************************************/ 51453018216SPaolo Bonzini /* PowerPC time base and decrementer emulation */ 51553018216SPaolo Bonzini 51653018216SPaolo Bonzini uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) 51753018216SPaolo Bonzini { 51853018216SPaolo Bonzini /* TB time in tb periods */ 51973bcb24dSRutuja Shah return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset; 52053018216SPaolo Bonzini } 52153018216SPaolo Bonzini 52253018216SPaolo Bonzini uint64_t cpu_ppc_load_tbl (CPUPPCState *env) 52353018216SPaolo Bonzini { 52453018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 52553018216SPaolo Bonzini uint64_t tb; 52653018216SPaolo Bonzini 52753018216SPaolo Bonzini if (kvm_enabled()) { 52853018216SPaolo Bonzini return env->spr[SPR_TBL]; 52953018216SPaolo Bonzini } 53053018216SPaolo Bonzini 531bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 532af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 53353018216SPaolo Bonzini 53453018216SPaolo Bonzini return tb; 53553018216SPaolo Bonzini } 53653018216SPaolo Bonzini 53753018216SPaolo Bonzini static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) 53853018216SPaolo Bonzini { 53953018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 54053018216SPaolo Bonzini uint64_t tb; 54153018216SPaolo Bonzini 542bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 543af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 54453018216SPaolo Bonzini 54553018216SPaolo Bonzini return tb >> 32; 54653018216SPaolo Bonzini } 54753018216SPaolo Bonzini 54853018216SPaolo Bonzini uint32_t cpu_ppc_load_tbu (CPUPPCState *env) 54953018216SPaolo Bonzini { 55053018216SPaolo Bonzini if (kvm_enabled()) { 55153018216SPaolo Bonzini return env->spr[SPR_TBU]; 55253018216SPaolo Bonzini } 55353018216SPaolo Bonzini 55453018216SPaolo Bonzini return _cpu_ppc_load_tbu(env); 55553018216SPaolo Bonzini } 55653018216SPaolo Bonzini 55753018216SPaolo Bonzini static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, 55853018216SPaolo Bonzini int64_t *tb_offsetp, uint64_t value) 55953018216SPaolo Bonzini { 56073bcb24dSRutuja Shah *tb_offsetp = value - 56173bcb24dSRutuja Shah muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND); 56273bcb24dSRutuja Shah 563af96d2e6SCédric Le Goater trace_ppc_tb_store(value, *tb_offsetp); 56453018216SPaolo Bonzini } 56553018216SPaolo Bonzini 56653018216SPaolo Bonzini void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) 56753018216SPaolo Bonzini { 56853018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 56953018216SPaolo Bonzini uint64_t tb; 57053018216SPaolo Bonzini 571bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 57253018216SPaolo Bonzini tb &= 0xFFFFFFFF00000000ULL; 573bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 57453018216SPaolo Bonzini &tb_env->tb_offset, tb | (uint64_t)value); 57553018216SPaolo Bonzini } 57653018216SPaolo Bonzini 57753018216SPaolo Bonzini static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) 57853018216SPaolo Bonzini { 57953018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 58053018216SPaolo Bonzini uint64_t tb; 58153018216SPaolo Bonzini 582bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 58353018216SPaolo Bonzini tb &= 0x00000000FFFFFFFFULL; 584bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 58553018216SPaolo Bonzini &tb_env->tb_offset, ((uint64_t)value << 32) | tb); 58653018216SPaolo Bonzini } 58753018216SPaolo Bonzini 58853018216SPaolo Bonzini void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value) 58953018216SPaolo Bonzini { 59053018216SPaolo Bonzini _cpu_ppc_store_tbu(env, value); 59153018216SPaolo Bonzini } 59253018216SPaolo Bonzini 59353018216SPaolo Bonzini uint64_t cpu_ppc_load_atbl (CPUPPCState *env) 59453018216SPaolo Bonzini { 59553018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 59653018216SPaolo Bonzini uint64_t tb; 59753018216SPaolo Bonzini 598bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 599af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 60053018216SPaolo Bonzini 60153018216SPaolo Bonzini return tb; 60253018216SPaolo Bonzini } 60353018216SPaolo Bonzini 60453018216SPaolo Bonzini uint32_t cpu_ppc_load_atbu (CPUPPCState *env) 60553018216SPaolo Bonzini { 60653018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 60753018216SPaolo Bonzini uint64_t tb; 60853018216SPaolo Bonzini 609bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 610af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 61153018216SPaolo Bonzini 61253018216SPaolo Bonzini return tb >> 32; 61353018216SPaolo Bonzini } 61453018216SPaolo Bonzini 61553018216SPaolo Bonzini void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) 61653018216SPaolo Bonzini { 61753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 61853018216SPaolo Bonzini uint64_t tb; 61953018216SPaolo Bonzini 620bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 62153018216SPaolo Bonzini tb &= 0xFFFFFFFF00000000ULL; 622bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 62353018216SPaolo Bonzini &tb_env->atb_offset, tb | (uint64_t)value); 62453018216SPaolo Bonzini } 62553018216SPaolo Bonzini 62653018216SPaolo Bonzini void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) 62753018216SPaolo Bonzini { 62853018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 62953018216SPaolo Bonzini uint64_t tb; 63053018216SPaolo Bonzini 631bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 63253018216SPaolo Bonzini tb &= 0x00000000FFFFFFFFULL; 633bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 63453018216SPaolo Bonzini &tb_env->atb_offset, ((uint64_t)value << 32) | tb); 63553018216SPaolo Bonzini } 63653018216SPaolo Bonzini 6375d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env) 6385d62725bSSuraj Jitindar Singh { 6395d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6405d62725bSSuraj Jitindar Singh 6415d62725bSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6425d62725bSSuraj Jitindar Singh tb_env->vtb_offset); 6435d62725bSSuraj Jitindar Singh } 6445d62725bSSuraj Jitindar Singh 6455d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value) 6465d62725bSSuraj Jitindar Singh { 6475d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6485d62725bSSuraj Jitindar Singh 6495d62725bSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6505d62725bSSuraj Jitindar Singh &tb_env->vtb_offset, value); 6515d62725bSSuraj Jitindar Singh } 6525d62725bSSuraj Jitindar Singh 653f0ec31b1SSuraj Jitindar Singh void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value) 654f0ec31b1SSuraj Jitindar Singh { 655f0ec31b1SSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 656f0ec31b1SSuraj Jitindar Singh uint64_t tb; 657f0ec31b1SSuraj Jitindar Singh 658f0ec31b1SSuraj Jitindar Singh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 659f0ec31b1SSuraj Jitindar Singh tb_env->tb_offset); 660f0ec31b1SSuraj Jitindar Singh tb &= 0xFFFFFFUL; 661f0ec31b1SSuraj Jitindar Singh tb |= (value & ~0xFFFFFFUL); 662f0ec31b1SSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 663f0ec31b1SSuraj Jitindar Singh &tb_env->tb_offset, tb); 664f0ec31b1SSuraj Jitindar Singh } 665f0ec31b1SSuraj Jitindar Singh 66653018216SPaolo Bonzini static void cpu_ppc_tb_stop (CPUPPCState *env) 66753018216SPaolo Bonzini { 66853018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 66953018216SPaolo Bonzini uint64_t tb, atb, vmclk; 67053018216SPaolo Bonzini 67153018216SPaolo Bonzini /* If the time base is already frozen, do nothing */ 67253018216SPaolo Bonzini if (tb_env->tb_freq != 0) { 673bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 67453018216SPaolo Bonzini /* Get the time base */ 67553018216SPaolo Bonzini tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); 67653018216SPaolo Bonzini /* Get the alternate time base */ 67753018216SPaolo Bonzini atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); 67853018216SPaolo Bonzini /* Store the time base value (ie compute the current offset) */ 67953018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 68053018216SPaolo Bonzini /* Store the alternate time base value (compute the current offset) */ 68153018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 68253018216SPaolo Bonzini /* Set the time base frequency to zero */ 68353018216SPaolo Bonzini tb_env->tb_freq = 0; 68453018216SPaolo Bonzini /* Now, the time bases are frozen to tb_offset / atb_offset value */ 68553018216SPaolo Bonzini } 68653018216SPaolo Bonzini } 68753018216SPaolo Bonzini 68853018216SPaolo Bonzini static void cpu_ppc_tb_start (CPUPPCState *env) 68953018216SPaolo Bonzini { 69053018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 69153018216SPaolo Bonzini uint64_t tb, atb, vmclk; 69253018216SPaolo Bonzini 69353018216SPaolo Bonzini /* If the time base is not frozen, do nothing */ 69453018216SPaolo Bonzini if (tb_env->tb_freq == 0) { 695bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 69653018216SPaolo Bonzini /* Get the time base from tb_offset */ 69753018216SPaolo Bonzini tb = tb_env->tb_offset; 69853018216SPaolo Bonzini /* Get the alternate time base from atb_offset */ 69953018216SPaolo Bonzini atb = tb_env->atb_offset; 70053018216SPaolo Bonzini /* Restore the tb frequency from the decrementer frequency */ 70153018216SPaolo Bonzini tb_env->tb_freq = tb_env->decr_freq; 70253018216SPaolo Bonzini /* Store the time base value */ 70353018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 70453018216SPaolo Bonzini /* Store the alternate time base value */ 70553018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 70653018216SPaolo Bonzini } 70753018216SPaolo Bonzini } 70853018216SPaolo Bonzini 709e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env) 710e81a982aSAlexander Graf { 711e81a982aSAlexander Graf ppc_tb_t *tb_env = env->tb_env; 712e81a982aSAlexander Graf int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL; 713e81a982aSAlexander Graf return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED); 714e81a982aSAlexander Graf } 715e81a982aSAlexander Graf 716a8dafa52SSuraj Jitindar Singh static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) 71753018216SPaolo Bonzini { 71853018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 719a8dafa52SSuraj Jitindar Singh int64_t decr, diff; 72053018216SPaolo Bonzini 721bc72ad67SAlex Bligh diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 72253018216SPaolo Bonzini if (diff >= 0) { 72373bcb24dSRutuja Shah decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 72453018216SPaolo Bonzini } else if (tb_env->flags & PPC_TIMER_BOOKE) { 72553018216SPaolo Bonzini decr = 0; 72653018216SPaolo Bonzini } else { 72773bcb24dSRutuja Shah decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 72853018216SPaolo Bonzini } 729af96d2e6SCédric Le Goater trace_ppc_decr_load(decr); 73053018216SPaolo Bonzini 73153018216SPaolo Bonzini return decr; 73253018216SPaolo Bonzini } 73353018216SPaolo Bonzini 734a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_decr(CPUPPCState *env) 73553018216SPaolo Bonzini { 73653018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 737a8dafa52SSuraj Jitindar Singh uint64_t decr; 73853018216SPaolo Bonzini 73953018216SPaolo Bonzini if (kvm_enabled()) { 74053018216SPaolo Bonzini return env->spr[SPR_DECR]; 74153018216SPaolo Bonzini } 74253018216SPaolo Bonzini 743a8dafa52SSuraj Jitindar Singh decr = _cpu_ppc_load_decr(env, tb_env->decr_next); 744a8dafa52SSuraj Jitindar Singh 745a8dafa52SSuraj Jitindar Singh /* 746a8dafa52SSuraj Jitindar Singh * If large decrementer is enabled then the decrementer is signed extened 747a8dafa52SSuraj Jitindar Singh * to 64 bits, otherwise it is a 32 bit value. 748a8dafa52SSuraj Jitindar Singh */ 749a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 750a8dafa52SSuraj Jitindar Singh return decr; 751a8dafa52SSuraj Jitindar Singh } 752a8dafa52SSuraj Jitindar Singh return (uint32_t) decr; 75353018216SPaolo Bonzini } 75453018216SPaolo Bonzini 755a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_hdecr(CPUPPCState *env) 75653018216SPaolo Bonzini { 757db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 758a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 75953018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 760a8dafa52SSuraj Jitindar Singh uint64_t hdecr; 76153018216SPaolo Bonzini 762a8dafa52SSuraj Jitindar Singh hdecr = _cpu_ppc_load_decr(env, tb_env->hdecr_next); 763a8dafa52SSuraj Jitindar Singh 764a8dafa52SSuraj Jitindar Singh /* 765a8dafa52SSuraj Jitindar Singh * If we have a large decrementer (POWER9 or later) then hdecr is sign 766a8dafa52SSuraj Jitindar Singh * extended to 64 bits, otherwise it is 32 bits. 767a8dafa52SSuraj Jitindar Singh */ 768a8dafa52SSuraj Jitindar Singh if (pcc->lrg_decr_bits > 32) { 769a8dafa52SSuraj Jitindar Singh return hdecr; 770a8dafa52SSuraj Jitindar Singh } 771a8dafa52SSuraj Jitindar Singh return (uint32_t) hdecr; 77253018216SPaolo Bonzini } 77353018216SPaolo Bonzini 77453018216SPaolo Bonzini uint64_t cpu_ppc_load_purr (CPUPPCState *env) 77553018216SPaolo Bonzini { 77653018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 77753018216SPaolo Bonzini 7785cc7e69fSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 7795cc7e69fSSuraj Jitindar Singh tb_env->purr_offset); 78053018216SPaolo Bonzini } 78153018216SPaolo Bonzini 78253018216SPaolo Bonzini /* When decrementer expires, 78353018216SPaolo Bonzini * all we need to do is generate or queue a CPU exception 78453018216SPaolo Bonzini */ 78553018216SPaolo Bonzini static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) 78653018216SPaolo Bonzini { 78753018216SPaolo Bonzini /* Raise it */ 788af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise"); 78953018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); 79053018216SPaolo Bonzini } 79153018216SPaolo Bonzini 792e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu) 793e81a982aSAlexander Graf { 794e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0); 795e81a982aSAlexander Graf } 796e81a982aSAlexander Graf 79753018216SPaolo Bonzini static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) 79853018216SPaolo Bonzini { 7994b236b62SBenjamin Herrenschmidt CPUPPCState *env = &cpu->env; 8004b236b62SBenjamin Herrenschmidt 80153018216SPaolo Bonzini /* Raise it */ 802af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise HV"); 8034b236b62SBenjamin Herrenschmidt 8044b236b62SBenjamin Herrenschmidt /* The architecture specifies that we don't deliver HDEC 8054b236b62SBenjamin Herrenschmidt * interrupts in a PM state. Not only they don't cause a 8064b236b62SBenjamin Herrenschmidt * wakeup but they also get effectively discarded. 8074b236b62SBenjamin Herrenschmidt */ 8081e7fd61dSBenjamin Herrenschmidt if (!env->resume_as_sreset) { 80953018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); 81053018216SPaolo Bonzini } 8114b236b62SBenjamin Herrenschmidt } 81253018216SPaolo Bonzini 813e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) 814e81a982aSAlexander Graf { 815e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); 816e81a982aSAlexander Graf } 817e81a982aSAlexander Graf 81853018216SPaolo Bonzini static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, 8191246b259SStefan Weil QEMUTimer *timer, 820e81a982aSAlexander Graf void (*raise_excp)(void *), 821e81a982aSAlexander Graf void (*lower_excp)(PowerPCCPU *), 822a8dafa52SSuraj Jitindar Singh target_ulong decr, target_ulong value, 823a8dafa52SSuraj Jitindar Singh int nr_bits) 82453018216SPaolo Bonzini { 82553018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 82653018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 82753018216SPaolo Bonzini uint64_t now, next; 8284d9b8ef9SCédric Le Goater int64_t signed_value; 8294d9b8ef9SCédric Le Goater int64_t signed_decr; 83053018216SPaolo Bonzini 831a8dafa52SSuraj Jitindar Singh /* Truncate value to decr_width and sign extend for simplicity */ 8324d9b8ef9SCédric Le Goater signed_value = sextract64(value, 0, nr_bits); 8334d9b8ef9SCédric Le Goater signed_decr = sextract64(decr, 0, nr_bits); 834a8dafa52SSuraj Jitindar Singh 835af96d2e6SCédric Le Goater trace_ppc_decr_store(nr_bits, decr, value); 83653018216SPaolo Bonzini 83753018216SPaolo Bonzini if (kvm_enabled()) { 83853018216SPaolo Bonzini /* KVM handles decrementer exceptions, we don't need our own timer */ 83953018216SPaolo Bonzini return; 84053018216SPaolo Bonzini } 84153018216SPaolo Bonzini 842e81a982aSAlexander Graf /* 843e81a982aSAlexander Graf * Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC 844e81a982aSAlexander Graf * interrupt. 845e81a982aSAlexander Graf * 846e81a982aSAlexander Graf * If we get a really small DEC value, we can assume that by the time we 847e81a982aSAlexander Graf * handled it we should inject an interrupt already. 848e81a982aSAlexander Graf * 849e81a982aSAlexander Graf * On MSB level based DEC implementations the MSB always means the interrupt 850e81a982aSAlexander Graf * is pending, so raise it on those. 851e81a982aSAlexander Graf * 852e81a982aSAlexander Graf * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers 853e81a982aSAlexander Graf * an edge interrupt, so raise it here too. 854e81a982aSAlexander Graf */ 855a8dcb8daSCédric Le Goater if ((value < 3) || 8564d9b8ef9SCédric Le Goater ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) || 8574d9b8ef9SCédric Le Goater ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0 8584d9b8ef9SCédric Le Goater && signed_decr >= 0)) { 859e81a982aSAlexander Graf (*raise_excp)(cpu); 860e81a982aSAlexander Graf return; 861e81a982aSAlexander Graf } 862e81a982aSAlexander Graf 863e81a982aSAlexander Graf /* On MSB level based systems a 0 for the MSB stops interrupt delivery */ 8644d9b8ef9SCédric Le Goater if (signed_value >= 0 && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) { 865e81a982aSAlexander Graf (*lower_excp)(cpu); 866e81a982aSAlexander Graf } 867e81a982aSAlexander Graf 868e81a982aSAlexander Graf /* Calculate the next timer event */ 869bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 87073bcb24dSRutuja Shah next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 87153018216SPaolo Bonzini *nextp = next; 872e81a982aSAlexander Graf 87353018216SPaolo Bonzini /* Adjust timer */ 874bc72ad67SAlex Bligh timer_mod(timer, next); 87553018216SPaolo Bonzini } 87653018216SPaolo Bonzini 877a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr, 878a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 87953018216SPaolo Bonzini { 88053018216SPaolo Bonzini ppc_tb_t *tb_env = cpu->env.tb_env; 88153018216SPaolo Bonzini 88253018216SPaolo Bonzini __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, 883e81a982aSAlexander Graf tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr, 884a8dafa52SSuraj Jitindar Singh value, nr_bits); 88553018216SPaolo Bonzini } 88653018216SPaolo Bonzini 887a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value) 88853018216SPaolo Bonzini { 889db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 890a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 891a8dafa52SSuraj Jitindar Singh int nr_bits = 32; 89253018216SPaolo Bonzini 893a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 894a8dafa52SSuraj Jitindar Singh nr_bits = pcc->lrg_decr_bits; 895a8dafa52SSuraj Jitindar Singh } 896a8dafa52SSuraj Jitindar Singh 897a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, nr_bits); 89853018216SPaolo Bonzini } 89953018216SPaolo Bonzini 90053018216SPaolo Bonzini static void cpu_ppc_decr_cb(void *opaque) 90153018216SPaolo Bonzini { 90253018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 90353018216SPaolo Bonzini 904e81a982aSAlexander Graf cpu_ppc_decr_excp(cpu); 90553018216SPaolo Bonzini } 90653018216SPaolo Bonzini 907a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr, 908a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 90953018216SPaolo Bonzini { 91053018216SPaolo Bonzini ppc_tb_t *tb_env = cpu->env.tb_env; 91153018216SPaolo Bonzini 91253018216SPaolo Bonzini if (tb_env->hdecr_timer != NULL) { 91353018216SPaolo Bonzini __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, 914e81a982aSAlexander Graf tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower, 915a8dafa52SSuraj Jitindar Singh hdecr, value, nr_bits); 91653018216SPaolo Bonzini } 91753018216SPaolo Bonzini } 91853018216SPaolo Bonzini 919a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value) 92053018216SPaolo Bonzini { 921db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 922a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 92353018216SPaolo Bonzini 924a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 925a8dafa52SSuraj Jitindar Singh pcc->lrg_decr_bits); 92653018216SPaolo Bonzini } 92753018216SPaolo Bonzini 92853018216SPaolo Bonzini static void cpu_ppc_hdecr_cb(void *opaque) 92953018216SPaolo Bonzini { 93053018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 93153018216SPaolo Bonzini 932e81a982aSAlexander Graf cpu_ppc_hdecr_excp(cpu); 93353018216SPaolo Bonzini } 93453018216SPaolo Bonzini 9355cc7e69fSSuraj Jitindar Singh void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) 93653018216SPaolo Bonzini { 9375cc7e69fSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 93853018216SPaolo Bonzini 9395cc7e69fSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 9405cc7e69fSSuraj Jitindar Singh &tb_env->purr_offset, value); 94153018216SPaolo Bonzini } 94253018216SPaolo Bonzini 94353018216SPaolo Bonzini static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) 94453018216SPaolo Bonzini { 94553018216SPaolo Bonzini CPUPPCState *env = opaque; 946db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 94753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 94853018216SPaolo Bonzini 94953018216SPaolo Bonzini tb_env->tb_freq = freq; 95053018216SPaolo Bonzini tb_env->decr_freq = freq; 95153018216SPaolo Bonzini /* There is a bug in Linux 2.4 kernels: 95253018216SPaolo Bonzini * if a decrementer exception is pending when it enables msr_ee at startup, 95353018216SPaolo Bonzini * it's not ready to handle it... 95453018216SPaolo Bonzini */ 955a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 956a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 9575cc7e69fSSuraj Jitindar Singh cpu_ppc_store_purr(env, 0x0000000000000000ULL); 95853018216SPaolo Bonzini } 95953018216SPaolo Bonzini 96042043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb) 96198a8b524SAlexey Kardashevskiy { 9624a7428c5SChristopher Covington uint64_t ticks = cpu_get_host_ticks(); 96398a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 96498a8b524SAlexey Kardashevskiy 96598a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 96698a8b524SAlexey Kardashevskiy error_report("No timebase object"); 96798a8b524SAlexey Kardashevskiy return; 96898a8b524SAlexey Kardashevskiy } 96998a8b524SAlexey Kardashevskiy 97042043e4fSLaurent Vivier /* not used anymore, we keep it for compatibility */ 97177bad151SPaolo Bonzini tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); 97298a8b524SAlexey Kardashevskiy /* 97342043e4fSLaurent Vivier * tb_offset is only expected to be changed by QEMU so 97498a8b524SAlexey Kardashevskiy * there is no need to update it from KVM here 97598a8b524SAlexey Kardashevskiy */ 97698a8b524SAlexey Kardashevskiy tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; 977d14f3397SMaxiwell S. Garcia 978711dfb24SGreg Kurz tb->runstate_paused = 979711dfb24SGreg Kurz runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM); 98098a8b524SAlexey Kardashevskiy } 98198a8b524SAlexey Kardashevskiy 98242043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb) 98398a8b524SAlexey Kardashevskiy { 98498a8b524SAlexey Kardashevskiy CPUState *cpu; 98598a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 98642043e4fSLaurent Vivier int64_t tb_off_adj, tb_off; 98798a8b524SAlexey Kardashevskiy unsigned long freq; 98898a8b524SAlexey Kardashevskiy 98998a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 99098a8b524SAlexey Kardashevskiy error_report("No timebase object"); 99142043e4fSLaurent Vivier return; 99298a8b524SAlexey Kardashevskiy } 99398a8b524SAlexey Kardashevskiy 99498a8b524SAlexey Kardashevskiy freq = first_ppc_cpu->env.tb_env->tb_freq; 99598a8b524SAlexey Kardashevskiy 99642043e4fSLaurent Vivier tb_off_adj = tb->guest_timebase - cpu_get_host_ticks(); 99798a8b524SAlexey Kardashevskiy 99898a8b524SAlexey Kardashevskiy tb_off = first_ppc_cpu->env.tb_env->tb_offset; 99998a8b524SAlexey Kardashevskiy trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off, 100098a8b524SAlexey Kardashevskiy (tb_off_adj - tb_off) / freq); 100198a8b524SAlexey Kardashevskiy 100298a8b524SAlexey Kardashevskiy /* Set new offset to all CPUs */ 100398a8b524SAlexey Kardashevskiy CPU_FOREACH(cpu) { 100498a8b524SAlexey Kardashevskiy PowerPCCPU *pcpu = POWERPC_CPU(cpu); 100598a8b524SAlexey Kardashevskiy pcpu->env.tb_env->tb_offset = tb_off_adj; 10069723295aSGreg Kurz kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset); 100742043e4fSLaurent Vivier } 100898a8b524SAlexey Kardashevskiy } 100998a8b524SAlexey Kardashevskiy 1010538f0497SPhilippe Mathieu-Daudé void cpu_ppc_clock_vm_state_change(void *opaque, bool running, 101142043e4fSLaurent Vivier RunState state) 101242043e4fSLaurent Vivier { 101342043e4fSLaurent Vivier PPCTimebase *tb = opaque; 101442043e4fSLaurent Vivier 101542043e4fSLaurent Vivier if (running) { 101642043e4fSLaurent Vivier timebase_load(tb); 101742043e4fSLaurent Vivier } else { 101842043e4fSLaurent Vivier timebase_save(tb); 101942043e4fSLaurent Vivier } 102042043e4fSLaurent Vivier } 102142043e4fSLaurent Vivier 102242043e4fSLaurent Vivier /* 1023d14f3397SMaxiwell S. Garcia * When migrating a running guest, read the clock just 1024d14f3397SMaxiwell S. Garcia * before migration, so that the guest clock counts 1025d14f3397SMaxiwell S. Garcia * during the events between: 102642043e4fSLaurent Vivier * 102742043e4fSLaurent Vivier * * vm_stop() 102842043e4fSLaurent Vivier * * 102942043e4fSLaurent Vivier * * pre_save() 103042043e4fSLaurent Vivier * 103142043e4fSLaurent Vivier * This reduces clock difference on migration from 5s 103242043e4fSLaurent Vivier * to 0.1s (when max_downtime == 5s), because sending the 103342043e4fSLaurent Vivier * final pages of memory (which happens between vm_stop() 103442043e4fSLaurent Vivier * and pre_save()) takes max_downtime. 103542043e4fSLaurent Vivier */ 103644b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque) 103742043e4fSLaurent Vivier { 103842043e4fSLaurent Vivier PPCTimebase *tb = opaque; 103942043e4fSLaurent Vivier 1040711dfb24SGreg Kurz /* guest_timebase won't be overridden in case of paused guest or savevm */ 1041d14f3397SMaxiwell S. Garcia if (!tb->runstate_paused) { 104242043e4fSLaurent Vivier timebase_save(tb); 1043d14f3397SMaxiwell S. Garcia } 104444b1ff31SDr. David Alan Gilbert 104544b1ff31SDr. David Alan Gilbert return 0; 104698a8b524SAlexey Kardashevskiy } 104798a8b524SAlexey Kardashevskiy 104898a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = { 104998a8b524SAlexey Kardashevskiy .name = "timebase", 105098a8b524SAlexey Kardashevskiy .version_id = 1, 105198a8b524SAlexey Kardashevskiy .minimum_version_id = 1, 105298a8b524SAlexey Kardashevskiy .minimum_version_id_old = 1, 105398a8b524SAlexey Kardashevskiy .pre_save = timebase_pre_save, 105498a8b524SAlexey Kardashevskiy .fields = (VMStateField []) { 105598a8b524SAlexey Kardashevskiy VMSTATE_UINT64(guest_timebase, PPCTimebase), 105698a8b524SAlexey Kardashevskiy VMSTATE_INT64(time_of_the_day_ns, PPCTimebase), 105798a8b524SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 105898a8b524SAlexey Kardashevskiy }, 105998a8b524SAlexey Kardashevskiy }; 106098a8b524SAlexey Kardashevskiy 106153018216SPaolo Bonzini /* Set up (once) timebase frequency (in Hz) */ 106253018216SPaolo Bonzini clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) 106353018216SPaolo Bonzini { 1064db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 106553018216SPaolo Bonzini ppc_tb_t *tb_env; 106653018216SPaolo Bonzini 106753018216SPaolo Bonzini tb_env = g_malloc0(sizeof(ppc_tb_t)); 106853018216SPaolo Bonzini env->tb_env = tb_env; 106953018216SPaolo Bonzini tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 1070d0db7cadSGreg Kurz if (is_book3s_arch2x(env)) { 1071e81a982aSAlexander Graf /* All Book3S 64bit CPUs implement level based DEC logic */ 1072e81a982aSAlexander Graf tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL; 1073e81a982aSAlexander Graf } 107453018216SPaolo Bonzini /* Create new timer */ 1075bc72ad67SAlex Bligh tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); 10764b236b62SBenjamin Herrenschmidt if (env->has_hv_mode) { 1077bc72ad67SAlex Bligh tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, 107853018216SPaolo Bonzini cpu); 107953018216SPaolo Bonzini } else { 108053018216SPaolo Bonzini tb_env->hdecr_timer = NULL; 108153018216SPaolo Bonzini } 108253018216SPaolo Bonzini cpu_ppc_set_tb_clk(env, freq); 108353018216SPaolo Bonzini 108453018216SPaolo Bonzini return &cpu_ppc_set_tb_clk; 108553018216SPaolo Bonzini } 108653018216SPaolo Bonzini 108753018216SPaolo Bonzini /* Specific helpers for POWER & PowerPC 601 RTC */ 108853018216SPaolo Bonzini void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value) 108953018216SPaolo Bonzini { 109053018216SPaolo Bonzini _cpu_ppc_store_tbu(env, value); 109153018216SPaolo Bonzini } 109253018216SPaolo Bonzini 109353018216SPaolo Bonzini uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env) 109453018216SPaolo Bonzini { 109553018216SPaolo Bonzini return _cpu_ppc_load_tbu(env); 109653018216SPaolo Bonzini } 109753018216SPaolo Bonzini 109853018216SPaolo Bonzini void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value) 109953018216SPaolo Bonzini { 110053018216SPaolo Bonzini cpu_ppc_store_tbl(env, value & 0x3FFFFF80); 110153018216SPaolo Bonzini } 110253018216SPaolo Bonzini 110353018216SPaolo Bonzini uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env) 110453018216SPaolo Bonzini { 110553018216SPaolo Bonzini return cpu_ppc_load_tbl(env) & 0x3FFFFF80; 110653018216SPaolo Bonzini } 110753018216SPaolo Bonzini 110853018216SPaolo Bonzini /*****************************************************************************/ 110953018216SPaolo Bonzini /* PowerPC 40x timers */ 111053018216SPaolo Bonzini 111153018216SPaolo Bonzini /* PIT, FIT & WDT */ 111253018216SPaolo Bonzini typedef struct ppc40x_timer_t ppc40x_timer_t; 111353018216SPaolo Bonzini struct ppc40x_timer_t { 111453018216SPaolo Bonzini uint64_t pit_reload; /* PIT auto-reload value */ 111553018216SPaolo Bonzini uint64_t fit_next; /* Tick for next FIT interrupt */ 11161246b259SStefan Weil QEMUTimer *fit_timer; 111753018216SPaolo Bonzini uint64_t wdt_next; /* Tick for next WDT interrupt */ 11181246b259SStefan Weil QEMUTimer *wdt_timer; 111953018216SPaolo Bonzini 112053018216SPaolo Bonzini /* 405 have the PIT, 440 have a DECR. */ 112153018216SPaolo Bonzini unsigned int decr_excp; 112253018216SPaolo Bonzini }; 112353018216SPaolo Bonzini 112453018216SPaolo Bonzini /* Fixed interval timer */ 112553018216SPaolo Bonzini static void cpu_4xx_fit_cb (void *opaque) 112653018216SPaolo Bonzini { 112753018216SPaolo Bonzini PowerPCCPU *cpu; 112853018216SPaolo Bonzini CPUPPCState *env; 112953018216SPaolo Bonzini ppc_tb_t *tb_env; 113053018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 113153018216SPaolo Bonzini uint64_t now, next; 113253018216SPaolo Bonzini 113353018216SPaolo Bonzini env = opaque; 1134db70b311SRichard Henderson cpu = env_archcpu(env); 113553018216SPaolo Bonzini tb_env = env->tb_env; 113653018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1137bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 113853018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { 113953018216SPaolo Bonzini case 0: 114053018216SPaolo Bonzini next = 1 << 9; 114153018216SPaolo Bonzini break; 114253018216SPaolo Bonzini case 1: 114353018216SPaolo Bonzini next = 1 << 13; 114453018216SPaolo Bonzini break; 114553018216SPaolo Bonzini case 2: 114653018216SPaolo Bonzini next = 1 << 17; 114753018216SPaolo Bonzini break; 114853018216SPaolo Bonzini case 3: 114953018216SPaolo Bonzini next = 1 << 21; 115053018216SPaolo Bonzini break; 115153018216SPaolo Bonzini default: 115253018216SPaolo Bonzini /* Cannot occur, but makes gcc happy */ 115353018216SPaolo Bonzini return; 115453018216SPaolo Bonzini } 115573bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq); 115653018216SPaolo Bonzini if (next == now) 115753018216SPaolo Bonzini next++; 1158bc72ad67SAlex Bligh timer_mod(ppc40x_timer->fit_timer, next); 115953018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 26; 116053018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { 116153018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); 116253018216SPaolo Bonzini } 1163af96d2e6SCédric Le Goater trace_ppc4xx_fit((int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), 116453018216SPaolo Bonzini env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 116553018216SPaolo Bonzini } 116653018216SPaolo Bonzini 116753018216SPaolo Bonzini /* Programmable interval timer */ 116853018216SPaolo Bonzini static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) 116953018216SPaolo Bonzini { 117053018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 117153018216SPaolo Bonzini uint64_t now, next; 117253018216SPaolo Bonzini 117353018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 117453018216SPaolo Bonzini if (ppc40x_timer->pit_reload <= 1 || 117553018216SPaolo Bonzini !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || 117653018216SPaolo Bonzini (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { 117753018216SPaolo Bonzini /* Stop PIT */ 1178af96d2e6SCédric Le Goater trace_ppc4xx_pit_stop(); 1179bc72ad67SAlex Bligh timer_del(tb_env->decr_timer); 118053018216SPaolo Bonzini } else { 1181af96d2e6SCédric Le Goater trace_ppc4xx_pit_start(ppc40x_timer->pit_reload); 1182bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 118353018216SPaolo Bonzini next = now + muldiv64(ppc40x_timer->pit_reload, 118473bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, tb_env->decr_freq); 118553018216SPaolo Bonzini if (is_excp) 118653018216SPaolo Bonzini next += tb_env->decr_next - now; 118753018216SPaolo Bonzini if (next == now) 118853018216SPaolo Bonzini next++; 1189bc72ad67SAlex Bligh timer_mod(tb_env->decr_timer, next); 119053018216SPaolo Bonzini tb_env->decr_next = next; 119153018216SPaolo Bonzini } 119253018216SPaolo Bonzini } 119353018216SPaolo Bonzini 119453018216SPaolo Bonzini static void cpu_4xx_pit_cb (void *opaque) 119553018216SPaolo Bonzini { 119653018216SPaolo Bonzini PowerPCCPU *cpu; 119753018216SPaolo Bonzini CPUPPCState *env; 119853018216SPaolo Bonzini ppc_tb_t *tb_env; 119953018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 120053018216SPaolo Bonzini 120153018216SPaolo Bonzini env = opaque; 1202db70b311SRichard Henderson cpu = env_archcpu(env); 120353018216SPaolo Bonzini tb_env = env->tb_env; 120453018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 120553018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 27; 120653018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { 120753018216SPaolo Bonzini ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); 120853018216SPaolo Bonzini } 120953018216SPaolo Bonzini start_stop_pit(env, tb_env, 1); 1210af96d2e6SCédric Le Goater trace_ppc4xx_pit((int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), 121153018216SPaolo Bonzini (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), 121253018216SPaolo Bonzini env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], 121353018216SPaolo Bonzini ppc40x_timer->pit_reload); 121453018216SPaolo Bonzini } 121553018216SPaolo Bonzini 121653018216SPaolo Bonzini /* Watchdog timer */ 121753018216SPaolo Bonzini static void cpu_4xx_wdt_cb (void *opaque) 121853018216SPaolo Bonzini { 121953018216SPaolo Bonzini PowerPCCPU *cpu; 122053018216SPaolo Bonzini CPUPPCState *env; 122153018216SPaolo Bonzini ppc_tb_t *tb_env; 122253018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 122353018216SPaolo Bonzini uint64_t now, next; 122453018216SPaolo Bonzini 122553018216SPaolo Bonzini env = opaque; 1226db70b311SRichard Henderson cpu = env_archcpu(env); 122753018216SPaolo Bonzini tb_env = env->tb_env; 122853018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1229bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 123053018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { 123153018216SPaolo Bonzini case 0: 123253018216SPaolo Bonzini next = 1 << 17; 123353018216SPaolo Bonzini break; 123453018216SPaolo Bonzini case 1: 123553018216SPaolo Bonzini next = 1 << 21; 123653018216SPaolo Bonzini break; 123753018216SPaolo Bonzini case 2: 123853018216SPaolo Bonzini next = 1 << 25; 123953018216SPaolo Bonzini break; 124053018216SPaolo Bonzini case 3: 124153018216SPaolo Bonzini next = 1 << 29; 124253018216SPaolo Bonzini break; 124353018216SPaolo Bonzini default: 124453018216SPaolo Bonzini /* Cannot occur, but makes gcc happy */ 124553018216SPaolo Bonzini return; 124653018216SPaolo Bonzini } 124773bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 124853018216SPaolo Bonzini if (next == now) 124953018216SPaolo Bonzini next++; 1250af96d2e6SCédric Le Goater trace_ppc4xx_wdt(env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 125153018216SPaolo Bonzini switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { 125253018216SPaolo Bonzini case 0x0: 125353018216SPaolo Bonzini case 0x1: 1254bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 125553018216SPaolo Bonzini ppc40x_timer->wdt_next = next; 1256a1f7f97bSPeter Maydell env->spr[SPR_40x_TSR] |= 1U << 31; 125753018216SPaolo Bonzini break; 125853018216SPaolo Bonzini case 0x2: 1259bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 126053018216SPaolo Bonzini ppc40x_timer->wdt_next = next; 126153018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 30; 126253018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { 126353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); 126453018216SPaolo Bonzini } 126553018216SPaolo Bonzini break; 126653018216SPaolo Bonzini case 0x3: 126753018216SPaolo Bonzini env->spr[SPR_40x_TSR] &= ~0x30000000; 126853018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000; 126953018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) { 127053018216SPaolo Bonzini case 0x0: 127153018216SPaolo Bonzini /* No reset */ 127253018216SPaolo Bonzini break; 127353018216SPaolo Bonzini case 0x1: /* Core reset */ 127453018216SPaolo Bonzini ppc40x_core_reset(cpu); 127553018216SPaolo Bonzini break; 127653018216SPaolo Bonzini case 0x2: /* Chip reset */ 127753018216SPaolo Bonzini ppc40x_chip_reset(cpu); 127853018216SPaolo Bonzini break; 127953018216SPaolo Bonzini case 0x3: /* System reset */ 128053018216SPaolo Bonzini ppc40x_system_reset(cpu); 128153018216SPaolo Bonzini break; 128253018216SPaolo Bonzini } 128353018216SPaolo Bonzini } 128453018216SPaolo Bonzini } 128553018216SPaolo Bonzini 128653018216SPaolo Bonzini void store_40x_pit (CPUPPCState *env, target_ulong val) 128753018216SPaolo Bonzini { 128853018216SPaolo Bonzini ppc_tb_t *tb_env; 128953018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 129053018216SPaolo Bonzini 129153018216SPaolo Bonzini tb_env = env->tb_env; 129253018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1293af96d2e6SCédric Le Goater trace_ppc40x_store_pit(val); 129453018216SPaolo Bonzini ppc40x_timer->pit_reload = val; 129553018216SPaolo Bonzini start_stop_pit(env, tb_env, 0); 129653018216SPaolo Bonzini } 129753018216SPaolo Bonzini 129853018216SPaolo Bonzini target_ulong load_40x_pit (CPUPPCState *env) 129953018216SPaolo Bonzini { 130053018216SPaolo Bonzini return cpu_ppc_load_decr(env); 130153018216SPaolo Bonzini } 130253018216SPaolo Bonzini 130353018216SPaolo Bonzini static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq) 130453018216SPaolo Bonzini { 130553018216SPaolo Bonzini CPUPPCState *env = opaque; 130653018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 130753018216SPaolo Bonzini 1308af96d2e6SCédric Le Goater trace_ppc40x_set_tb_clk(freq); 130953018216SPaolo Bonzini tb_env->tb_freq = freq; 131053018216SPaolo Bonzini tb_env->decr_freq = freq; 131153018216SPaolo Bonzini /* XXX: we should also update all timers */ 131253018216SPaolo Bonzini } 131353018216SPaolo Bonzini 131453018216SPaolo Bonzini clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, 131553018216SPaolo Bonzini unsigned int decr_excp) 131653018216SPaolo Bonzini { 131753018216SPaolo Bonzini ppc_tb_t *tb_env; 131853018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 131953018216SPaolo Bonzini 132053018216SPaolo Bonzini tb_env = g_malloc0(sizeof(ppc_tb_t)); 132153018216SPaolo Bonzini env->tb_env = tb_env; 132253018216SPaolo Bonzini tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 132353018216SPaolo Bonzini ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t)); 132453018216SPaolo Bonzini tb_env->tb_freq = freq; 132553018216SPaolo Bonzini tb_env->decr_freq = freq; 132653018216SPaolo Bonzini tb_env->opaque = ppc40x_timer; 1327af96d2e6SCédric Le Goater trace_ppc40x_timers_init(freq); 132853018216SPaolo Bonzini if (ppc40x_timer != NULL) { 132953018216SPaolo Bonzini /* We use decr timer for PIT */ 1330bc72ad67SAlex Bligh tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, env); 133153018216SPaolo Bonzini ppc40x_timer->fit_timer = 1332bc72ad67SAlex Bligh timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, env); 133353018216SPaolo Bonzini ppc40x_timer->wdt_timer = 1334bc72ad67SAlex Bligh timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, env); 133553018216SPaolo Bonzini ppc40x_timer->decr_excp = decr_excp; 133653018216SPaolo Bonzini } 133753018216SPaolo Bonzini 133853018216SPaolo Bonzini return &ppc_40x_set_tb_clk; 133953018216SPaolo Bonzini } 134053018216SPaolo Bonzini 134153018216SPaolo Bonzini /*****************************************************************************/ 134253018216SPaolo Bonzini /* Embedded PowerPC Device Control Registers */ 134353018216SPaolo Bonzini typedef struct ppc_dcrn_t ppc_dcrn_t; 134453018216SPaolo Bonzini struct ppc_dcrn_t { 134553018216SPaolo Bonzini dcr_read_cb dcr_read; 134653018216SPaolo Bonzini dcr_write_cb dcr_write; 134753018216SPaolo Bonzini void *opaque; 134853018216SPaolo Bonzini }; 134953018216SPaolo Bonzini 135053018216SPaolo Bonzini /* XXX: on 460, DCR addresses are 32 bits wide, 135153018216SPaolo Bonzini * using DCRIPR to get the 22 upper bits of the DCR address 135253018216SPaolo Bonzini */ 135353018216SPaolo Bonzini #define DCRN_NB 1024 135453018216SPaolo Bonzini struct ppc_dcr_t { 135553018216SPaolo Bonzini ppc_dcrn_t dcrn[DCRN_NB]; 135653018216SPaolo Bonzini int (*read_error)(int dcrn); 135753018216SPaolo Bonzini int (*write_error)(int dcrn); 135853018216SPaolo Bonzini }; 135953018216SPaolo Bonzini 136053018216SPaolo Bonzini int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) 136153018216SPaolo Bonzini { 136253018216SPaolo Bonzini ppc_dcrn_t *dcr; 136353018216SPaolo Bonzini 136453018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 136553018216SPaolo Bonzini goto error; 136653018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 136753018216SPaolo Bonzini if (dcr->dcr_read == NULL) 136853018216SPaolo Bonzini goto error; 136953018216SPaolo Bonzini *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); 1370*de82dabeSCédric Le Goater trace_ppc_dcr_read(dcrn, *valp); 137153018216SPaolo Bonzini 137253018216SPaolo Bonzini return 0; 137353018216SPaolo Bonzini 137453018216SPaolo Bonzini error: 137553018216SPaolo Bonzini if (dcr_env->read_error != NULL) 137653018216SPaolo Bonzini return (*dcr_env->read_error)(dcrn); 137753018216SPaolo Bonzini 137853018216SPaolo Bonzini return -1; 137953018216SPaolo Bonzini } 138053018216SPaolo Bonzini 138153018216SPaolo Bonzini int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) 138253018216SPaolo Bonzini { 138353018216SPaolo Bonzini ppc_dcrn_t *dcr; 138453018216SPaolo Bonzini 138553018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 138653018216SPaolo Bonzini goto error; 138753018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 138853018216SPaolo Bonzini if (dcr->dcr_write == NULL) 138953018216SPaolo Bonzini goto error; 1390*de82dabeSCédric Le Goater trace_ppc_dcr_write(dcrn, val); 139153018216SPaolo Bonzini (*dcr->dcr_write)(dcr->opaque, dcrn, val); 139253018216SPaolo Bonzini 139353018216SPaolo Bonzini return 0; 139453018216SPaolo Bonzini 139553018216SPaolo Bonzini error: 139653018216SPaolo Bonzini if (dcr_env->write_error != NULL) 139753018216SPaolo Bonzini return (*dcr_env->write_error)(dcrn); 139853018216SPaolo Bonzini 139953018216SPaolo Bonzini return -1; 140053018216SPaolo Bonzini } 140153018216SPaolo Bonzini 140253018216SPaolo Bonzini int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, 140353018216SPaolo Bonzini dcr_read_cb dcr_read, dcr_write_cb dcr_write) 140453018216SPaolo Bonzini { 140553018216SPaolo Bonzini ppc_dcr_t *dcr_env; 140653018216SPaolo Bonzini ppc_dcrn_t *dcr; 140753018216SPaolo Bonzini 140853018216SPaolo Bonzini dcr_env = env->dcr_env; 140953018216SPaolo Bonzini if (dcr_env == NULL) 141053018216SPaolo Bonzini return -1; 141153018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 141253018216SPaolo Bonzini return -1; 141353018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 141453018216SPaolo Bonzini if (dcr->opaque != NULL || 141553018216SPaolo Bonzini dcr->dcr_read != NULL || 141653018216SPaolo Bonzini dcr->dcr_write != NULL) 141753018216SPaolo Bonzini return -1; 141853018216SPaolo Bonzini dcr->opaque = opaque; 141953018216SPaolo Bonzini dcr->dcr_read = dcr_read; 142053018216SPaolo Bonzini dcr->dcr_write = dcr_write; 142153018216SPaolo Bonzini 142253018216SPaolo Bonzini return 0; 142353018216SPaolo Bonzini } 142453018216SPaolo Bonzini 142553018216SPaolo Bonzini int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn), 142653018216SPaolo Bonzini int (*write_error)(int dcrn)) 142753018216SPaolo Bonzini { 142853018216SPaolo Bonzini ppc_dcr_t *dcr_env; 142953018216SPaolo Bonzini 143053018216SPaolo Bonzini dcr_env = g_malloc0(sizeof(ppc_dcr_t)); 143153018216SPaolo Bonzini dcr_env->read_error = read_error; 143253018216SPaolo Bonzini dcr_env->write_error = write_error; 143353018216SPaolo Bonzini env->dcr_env = dcr_env; 143453018216SPaolo Bonzini 143553018216SPaolo Bonzini return 0; 143653018216SPaolo Bonzini } 143753018216SPaolo Bonzini 143853018216SPaolo Bonzini /*****************************************************************************/ 1439051e2973SCédric Le Goater 14404a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu) 14414a89e204SCédric Le Goater { 14424a89e204SCédric Le Goater CPUPPCState *env = &cpu->env; 14434a89e204SCédric Le Goater return env->spr_cb[SPR_PIR].default_value; 14444a89e204SCédric Le Goater } 14454a89e204SCédric Le Goater 1446051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir) 1447051e2973SCédric Le Goater { 1448051e2973SCédric Le Goater CPUState *cs; 1449051e2973SCédric Le Goater 1450051e2973SCédric Le Goater CPU_FOREACH(cs) { 1451051e2973SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 1452051e2973SCédric Le Goater 14534a89e204SCédric Le Goater if (ppc_cpu_pir(cpu) == pir) { 1454051e2973SCédric Le Goater return cpu; 1455051e2973SCédric Le Goater } 1456051e2973SCédric Le Goater } 1457051e2973SCédric Le Goater 1458051e2973SCédric Le Goater return NULL; 1459051e2973SCédric Le Goater } 146040177438SGreg Kurz 146140177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu) 146240177438SGreg Kurz { 146340177438SGreg Kurz CPUPPCState *env = &cpu->env; 146440177438SGreg Kurz 146540177438SGreg Kurz env->irq_input_state = 0; 146640177438SGreg Kurz kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); 146740177438SGreg Kurz } 1468