153018216SPaolo Bonzini /* 253018216SPaolo Bonzini * QEMU generic PowerPC hardware System Emulator 353018216SPaolo Bonzini * 453018216SPaolo Bonzini * Copyright (c) 2003-2007 Jocelyn Mayer 553018216SPaolo Bonzini * 653018216SPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 753018216SPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 853018216SPaolo Bonzini * in the Software without restriction, including without limitation the rights 953018216SPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1053018216SPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 1153018216SPaolo Bonzini * furnished to do so, subject to the following conditions: 1253018216SPaolo Bonzini * 1353018216SPaolo Bonzini * The above copyright notice and this permission notice shall be included in 1453018216SPaolo Bonzini * all copies or substantial portions of the Software. 1553018216SPaolo Bonzini * 1653018216SPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1753018216SPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1853018216SPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1953018216SPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2053018216SPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2153018216SPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2253018216SPaolo Bonzini * THE SOFTWARE. 2353018216SPaolo Bonzini */ 2464552b6bSMarkus Armbruster 250d75590dSPeter Maydell #include "qemu/osdep.h" 2664552b6bSMarkus Armbruster #include "hw/irq.h" 270d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h" 282b927571SAndreas Färber #include "hw/ppc/ppc_e500.h" 2953018216SPaolo Bonzini #include "qemu/timer.h" 300ce470cdSAlexey Kardashevskiy #include "sysemu/cpus.h" 3153018216SPaolo Bonzini #include "qemu/log.h" 32db725815SMarkus Armbruster #include "qemu/main-loop.h" 3398a8b524SAlexey Kardashevskiy #include "qemu/error-report.h" 3453018216SPaolo Bonzini #include "sysemu/kvm.h" 3554d31236SMarkus Armbruster #include "sysemu/runstate.h" 3653018216SPaolo Bonzini #include "kvm_ppc.h" 37d6454270SMarkus Armbruster #include "migration/vmstate.h" 3898a8b524SAlexey Kardashevskiy #include "trace.h" 3953018216SPaolo Bonzini 4053018216SPaolo Bonzini static void cpu_ppc_tb_stop (CPUPPCState *env); 4153018216SPaolo Bonzini static void cpu_ppc_tb_start (CPUPPCState *env); 4253018216SPaolo Bonzini 43f003109fSMatheus Ferst void ppc_set_irq(PowerPCCPU *cpu, int irq, int level) 4453018216SPaolo Bonzini { 4553018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 468d04fb55SJan Kiszka unsigned int old_pending; 478d04fb55SJan Kiszka 488d04fb55SJan Kiszka /* We may already have the BQL if coming from the reset path */ 4950c9c512SRichard Henderson QEMU_IOTHREAD_LOCK_GUARD(); 508d04fb55SJan Kiszka 518d04fb55SJan Kiszka old_pending = env->pending_interrupts; 5253018216SPaolo Bonzini 5353018216SPaolo Bonzini if (level) { 54f003109fSMatheus Ferst env->pending_interrupts |= irq; 5553018216SPaolo Bonzini } else { 56f003109fSMatheus Ferst env->pending_interrupts &= ~irq; 5753018216SPaolo Bonzini } 5853018216SPaolo Bonzini 5953018216SPaolo Bonzini if (old_pending != env->pending_interrupts) { 602fdedcbcSMatheus Ferst ppc_maybe_interrupt(env); 61f003109fSMatheus Ferst kvmppc_set_interrupt(cpu, irq, level); 6253018216SPaolo Bonzini } 6353018216SPaolo Bonzini 64f003109fSMatheus Ferst trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts, 65af96d2e6SCédric Le Goater CPU(cpu)->interrupt_request); 6653018216SPaolo Bonzini } 6753018216SPaolo Bonzini 6853018216SPaolo Bonzini /* PowerPC 6xx / 7xx internal IRQ controller */ 6953018216SPaolo Bonzini static void ppc6xx_set_irq(void *opaque, int pin, int level) 7053018216SPaolo Bonzini { 7153018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 7253018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 7353018216SPaolo Bonzini int cur_level; 7453018216SPaolo Bonzini 75af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 76af96d2e6SCédric Le Goater 7753018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 7853018216SPaolo Bonzini /* Don't generate spurious events */ 7953018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 80259186a7SAndreas Färber CPUState *cs = CPU(cpu); 81259186a7SAndreas Färber 8253018216SPaolo Bonzini switch (pin) { 8353018216SPaolo Bonzini case PPC6xx_INPUT_TBEN: 8453018216SPaolo Bonzini /* Level sensitive - active high */ 85af96d2e6SCédric Le Goater trace_ppc_irq_set_state("time base", level); 8653018216SPaolo Bonzini if (level) { 8753018216SPaolo Bonzini cpu_ppc_tb_start(env); 8853018216SPaolo Bonzini } else { 8953018216SPaolo Bonzini cpu_ppc_tb_stop(env); 9053018216SPaolo Bonzini } 91b2bd5b20SChen Qun break; 9253018216SPaolo Bonzini case PPC6xx_INPUT_INT: 9353018216SPaolo Bonzini /* Level sensitive - active high */ 94af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 9553018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 9653018216SPaolo Bonzini break; 9753018216SPaolo Bonzini case PPC6xx_INPUT_SMI: 9853018216SPaolo Bonzini /* Level sensitive - active high */ 99af96d2e6SCédric Le Goater trace_ppc_irq_set_state("SMI IRQ", level); 10053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); 10153018216SPaolo Bonzini break; 10253018216SPaolo Bonzini case PPC6xx_INPUT_MCP: 10353018216SPaolo Bonzini /* Negative edge sensitive */ 10453018216SPaolo Bonzini /* XXX: TODO: actual reaction may depends on HID0 status 10553018216SPaolo Bonzini * 603/604/740/750: check HID0[EMCP] 10653018216SPaolo Bonzini */ 10753018216SPaolo Bonzini if (cur_level == 1 && level == 0) { 108af96d2e6SCédric Le Goater trace_ppc_irq_set_state("machine check", 1); 10953018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 11053018216SPaolo Bonzini } 11153018216SPaolo Bonzini break; 11253018216SPaolo Bonzini case PPC6xx_INPUT_CKSTP_IN: 11353018216SPaolo Bonzini /* Level sensitive - active low */ 11453018216SPaolo Bonzini /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 11553018216SPaolo Bonzini /* XXX: Note that the only way to restart the CPU is to reset it */ 11653018216SPaolo Bonzini if (level) { 117af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 118259186a7SAndreas Färber cs->halted = 1; 11953018216SPaolo Bonzini } 12053018216SPaolo Bonzini break; 12153018216SPaolo Bonzini case PPC6xx_INPUT_HRESET: 12253018216SPaolo Bonzini /* Level sensitive - active low */ 12353018216SPaolo Bonzini if (level) { 124af96d2e6SCédric Le Goater trace_ppc_irq_reset("CPU"); 125c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 12653018216SPaolo Bonzini } 12753018216SPaolo Bonzini break; 12853018216SPaolo Bonzini case PPC6xx_INPUT_SRESET: 129af96d2e6SCédric Le Goater trace_ppc_irq_set_state("RESET IRQ", level); 13053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 13153018216SPaolo Bonzini break; 13253018216SPaolo Bonzini default: 1337279810bSCédric Le Goater g_assert_not_reached(); 13453018216SPaolo Bonzini } 13553018216SPaolo Bonzini if (level) 13653018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 13753018216SPaolo Bonzini else 13853018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 13953018216SPaolo Bonzini } 14053018216SPaolo Bonzini } 14153018216SPaolo Bonzini 142aa5a9e24SPaolo Bonzini void ppc6xx_irq_init(PowerPCCPU *cpu) 14353018216SPaolo Bonzini { 1440f3e0c6fSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc6xx_set_irq, PPC6xx_INPUT_NB); 14553018216SPaolo Bonzini } 14653018216SPaolo Bonzini 14753018216SPaolo Bonzini #if defined(TARGET_PPC64) 14853018216SPaolo Bonzini /* PowerPC 970 internal IRQ controller */ 14953018216SPaolo Bonzini static void ppc970_set_irq(void *opaque, int pin, int level) 15053018216SPaolo Bonzini { 15153018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 15253018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 15353018216SPaolo Bonzini int cur_level; 15453018216SPaolo Bonzini 155af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 156af96d2e6SCédric Le Goater 15753018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 15853018216SPaolo Bonzini /* Don't generate spurious events */ 15953018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 160259186a7SAndreas Färber CPUState *cs = CPU(cpu); 161259186a7SAndreas Färber 16253018216SPaolo Bonzini switch (pin) { 16353018216SPaolo Bonzini case PPC970_INPUT_INT: 16453018216SPaolo Bonzini /* Level sensitive - active high */ 165af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 16653018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 16753018216SPaolo Bonzini break; 16853018216SPaolo Bonzini case PPC970_INPUT_THINT: 16953018216SPaolo Bonzini /* Level sensitive - active high */ 170af96d2e6SCédric Le Goater trace_ppc_irq_set_state("SMI IRQ", level); 17153018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); 17253018216SPaolo Bonzini break; 17353018216SPaolo Bonzini case PPC970_INPUT_MCP: 17453018216SPaolo Bonzini /* Negative edge sensitive */ 17553018216SPaolo Bonzini /* XXX: TODO: actual reaction may depends on HID0 status 17653018216SPaolo Bonzini * 603/604/740/750: check HID0[EMCP] 17753018216SPaolo Bonzini */ 17853018216SPaolo Bonzini if (cur_level == 1 && level == 0) { 179af96d2e6SCédric Le Goater trace_ppc_irq_set_state("machine check", 1); 18053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 18153018216SPaolo Bonzini } 18253018216SPaolo Bonzini break; 18353018216SPaolo Bonzini case PPC970_INPUT_CKSTP: 18453018216SPaolo Bonzini /* Level sensitive - active low */ 18553018216SPaolo Bonzini /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 18653018216SPaolo Bonzini if (level) { 187af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 188259186a7SAndreas Färber cs->halted = 1; 18953018216SPaolo Bonzini } else { 190af96d2e6SCédric Le Goater trace_ppc_irq_cpu("restart"); 191259186a7SAndreas Färber cs->halted = 0; 192259186a7SAndreas Färber qemu_cpu_kick(cs); 19353018216SPaolo Bonzini } 19453018216SPaolo Bonzini break; 19553018216SPaolo Bonzini case PPC970_INPUT_HRESET: 19653018216SPaolo Bonzini /* Level sensitive - active low */ 19753018216SPaolo Bonzini if (level) { 198c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 19953018216SPaolo Bonzini } 20053018216SPaolo Bonzini break; 20153018216SPaolo Bonzini case PPC970_INPUT_SRESET: 202af96d2e6SCédric Le Goater trace_ppc_irq_set_state("RESET IRQ", level); 20353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 20453018216SPaolo Bonzini break; 20553018216SPaolo Bonzini case PPC970_INPUT_TBEN: 206af96d2e6SCédric Le Goater trace_ppc_irq_set_state("TBEN IRQ", level); 20753018216SPaolo Bonzini /* XXX: TODO */ 20853018216SPaolo Bonzini break; 20953018216SPaolo Bonzini default: 2107279810bSCédric Le Goater g_assert_not_reached(); 21153018216SPaolo Bonzini } 21253018216SPaolo Bonzini if (level) 21353018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 21453018216SPaolo Bonzini else 21553018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 21653018216SPaolo Bonzini } 21753018216SPaolo Bonzini } 21853018216SPaolo Bonzini 219aa5a9e24SPaolo Bonzini void ppc970_irq_init(PowerPCCPU *cpu) 22053018216SPaolo Bonzini { 2219fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc970_set_irq, PPC970_INPUT_NB); 22253018216SPaolo Bonzini } 22353018216SPaolo Bonzini 22453018216SPaolo Bonzini /* POWER7 internal IRQ controller */ 22553018216SPaolo Bonzini static void power7_set_irq(void *opaque, int pin, int level) 22653018216SPaolo Bonzini { 22753018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 22853018216SPaolo Bonzini 229af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 23053018216SPaolo Bonzini 23153018216SPaolo Bonzini switch (pin) { 23253018216SPaolo Bonzini case POWER7_INPUT_INT: 23353018216SPaolo Bonzini /* Level sensitive - active high */ 234af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 23553018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 23653018216SPaolo Bonzini break; 23753018216SPaolo Bonzini default: 2387279810bSCédric Le Goater g_assert_not_reached(); 23953018216SPaolo Bonzini } 24053018216SPaolo Bonzini } 24153018216SPaolo Bonzini 242aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu) 24353018216SPaolo Bonzini { 2449fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), power7_set_irq, POWER7_INPUT_NB); 24553018216SPaolo Bonzini } 24667afe775SBenjamin Herrenschmidt 24767afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */ 24867afe775SBenjamin Herrenschmidt static void power9_set_irq(void *opaque, int pin, int level) 24967afe775SBenjamin Herrenschmidt { 25067afe775SBenjamin Herrenschmidt PowerPCCPU *cpu = opaque; 25167afe775SBenjamin Herrenschmidt 252af96d2e6SCédric Le Goater trace_ppc_irq_set(&cpu->env, pin, level); 25367afe775SBenjamin Herrenschmidt 25467afe775SBenjamin Herrenschmidt switch (pin) { 25567afe775SBenjamin Herrenschmidt case POWER9_INPUT_INT: 25667afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 257af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 25867afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 25967afe775SBenjamin Herrenschmidt break; 26067afe775SBenjamin Herrenschmidt case POWER9_INPUT_HINT: 26167afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 262af96d2e6SCédric Le Goater trace_ppc_irq_set_state("HV external IRQ", level); 26367afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level); 26467afe775SBenjamin Herrenschmidt break; 26567afe775SBenjamin Herrenschmidt default: 2667279810bSCédric Le Goater g_assert_not_reached(); 267af96d2e6SCédric Le Goater return; 26867afe775SBenjamin Herrenschmidt } 26967afe775SBenjamin Herrenschmidt } 27067afe775SBenjamin Herrenschmidt 27167afe775SBenjamin Herrenschmidt void ppcPOWER9_irq_init(PowerPCCPU *cpu) 27267afe775SBenjamin Herrenschmidt { 2739fd0122eSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), power9_set_irq, POWER9_INPUT_NB); 27467afe775SBenjamin Herrenschmidt } 27553018216SPaolo Bonzini #endif /* defined(TARGET_PPC64) */ 27653018216SPaolo Bonzini 27752144b69SThomas Huth void ppc40x_core_reset(PowerPCCPU *cpu) 27852144b69SThomas Huth { 27952144b69SThomas Huth CPUPPCState *env = &cpu->env; 28052144b69SThomas Huth target_ulong dbsr; 28152144b69SThomas Huth 28252144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n"); 28352144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 28452144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 28552144b69SThomas Huth dbsr &= ~0x00000300; 28652144b69SThomas Huth dbsr |= 0x00000100; 28752144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 28852144b69SThomas Huth } 28952144b69SThomas Huth 29052144b69SThomas Huth void ppc40x_chip_reset(PowerPCCPU *cpu) 29152144b69SThomas Huth { 29252144b69SThomas Huth CPUPPCState *env = &cpu->env; 29352144b69SThomas Huth target_ulong dbsr; 29452144b69SThomas Huth 29552144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n"); 29652144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 29752144b69SThomas Huth /* XXX: TODO reset all internal peripherals */ 29852144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 29952144b69SThomas Huth dbsr &= ~0x00000300; 30052144b69SThomas Huth dbsr |= 0x00000200; 30152144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 30252144b69SThomas Huth } 30352144b69SThomas Huth 30452144b69SThomas Huth void ppc40x_system_reset(PowerPCCPU *cpu) 30552144b69SThomas Huth { 30652144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n"); 30752144b69SThomas Huth qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 30852144b69SThomas Huth } 30952144b69SThomas Huth 31052144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val) 31152144b69SThomas Huth { 312db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 31352144b69SThomas Huth 3145ae3d2e8SThomas Huth qemu_mutex_lock_iothread(); 3155ae3d2e8SThomas Huth 31652144b69SThomas Huth switch ((val >> 28) & 0x3) { 31752144b69SThomas Huth case 0x0: 31852144b69SThomas Huth /* No action */ 31952144b69SThomas Huth break; 32052144b69SThomas Huth case 0x1: 32152144b69SThomas Huth /* Core reset */ 32252144b69SThomas Huth ppc40x_core_reset(cpu); 32352144b69SThomas Huth break; 32452144b69SThomas Huth case 0x2: 32552144b69SThomas Huth /* Chip reset */ 32652144b69SThomas Huth ppc40x_chip_reset(cpu); 32752144b69SThomas Huth break; 32852144b69SThomas Huth case 0x3: 32952144b69SThomas Huth /* System reset */ 33052144b69SThomas Huth ppc40x_system_reset(cpu); 33152144b69SThomas Huth break; 33252144b69SThomas Huth } 3335ae3d2e8SThomas Huth 3345ae3d2e8SThomas Huth qemu_mutex_unlock_iothread(); 33552144b69SThomas Huth } 33652144b69SThomas Huth 33753018216SPaolo Bonzini /* PowerPC 40x internal IRQ controller */ 33853018216SPaolo Bonzini static void ppc40x_set_irq(void *opaque, int pin, int level) 33953018216SPaolo Bonzini { 34053018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 34153018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 34253018216SPaolo Bonzini int cur_level; 34353018216SPaolo Bonzini 344af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 345af96d2e6SCédric Le Goater 34653018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 34753018216SPaolo Bonzini /* Don't generate spurious events */ 34853018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 349259186a7SAndreas Färber CPUState *cs = CPU(cpu); 350259186a7SAndreas Färber 35153018216SPaolo Bonzini switch (pin) { 35253018216SPaolo Bonzini case PPC40x_INPUT_RESET_SYS: 35353018216SPaolo Bonzini if (level) { 354af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 35553018216SPaolo Bonzini ppc40x_system_reset(cpu); 35653018216SPaolo Bonzini } 35753018216SPaolo Bonzini break; 35853018216SPaolo Bonzini case PPC40x_INPUT_RESET_CHIP: 35953018216SPaolo Bonzini if (level) { 360af96d2e6SCédric Le Goater trace_ppc_irq_reset("chip"); 36153018216SPaolo Bonzini ppc40x_chip_reset(cpu); 36253018216SPaolo Bonzini } 36353018216SPaolo Bonzini break; 36453018216SPaolo Bonzini case PPC40x_INPUT_RESET_CORE: 36553018216SPaolo Bonzini /* XXX: TODO: update DBSR[MRR] */ 36653018216SPaolo Bonzini if (level) { 367af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 36853018216SPaolo Bonzini ppc40x_core_reset(cpu); 36953018216SPaolo Bonzini } 37053018216SPaolo Bonzini break; 37153018216SPaolo Bonzini case PPC40x_INPUT_CINT: 37253018216SPaolo Bonzini /* Level sensitive - active high */ 373af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 37453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 37553018216SPaolo Bonzini break; 37653018216SPaolo Bonzini case PPC40x_INPUT_INT: 37753018216SPaolo Bonzini /* Level sensitive - active high */ 378af96d2e6SCédric Le Goater trace_ppc_irq_set_state("external IRQ", level); 37953018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 38053018216SPaolo Bonzini break; 38153018216SPaolo Bonzini case PPC40x_INPUT_HALT: 38253018216SPaolo Bonzini /* Level sensitive - active low */ 38353018216SPaolo Bonzini if (level) { 384af96d2e6SCédric Le Goater trace_ppc_irq_cpu("stop"); 385259186a7SAndreas Färber cs->halted = 1; 38653018216SPaolo Bonzini } else { 387af96d2e6SCédric Le Goater trace_ppc_irq_cpu("restart"); 388259186a7SAndreas Färber cs->halted = 0; 389259186a7SAndreas Färber qemu_cpu_kick(cs); 39053018216SPaolo Bonzini } 39153018216SPaolo Bonzini break; 39253018216SPaolo Bonzini case PPC40x_INPUT_DEBUG: 39353018216SPaolo Bonzini /* Level sensitive - active high */ 394af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 39553018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 39653018216SPaolo Bonzini break; 39753018216SPaolo Bonzini default: 3987279810bSCédric Le Goater g_assert_not_reached(); 39953018216SPaolo Bonzini } 40053018216SPaolo Bonzini if (level) 40153018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 40253018216SPaolo Bonzini else 40353018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 40453018216SPaolo Bonzini } 40553018216SPaolo Bonzini } 40653018216SPaolo Bonzini 407aa5a9e24SPaolo Bonzini void ppc40x_irq_init(PowerPCCPU *cpu) 40853018216SPaolo Bonzini { 40947b60fc6SCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppc40x_set_irq, PPC40x_INPUT_NB); 41053018216SPaolo Bonzini } 41153018216SPaolo Bonzini 41253018216SPaolo Bonzini /* PowerPC E500 internal IRQ controller */ 41353018216SPaolo Bonzini static void ppce500_set_irq(void *opaque, int pin, int level) 41453018216SPaolo Bonzini { 41553018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 41653018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 41753018216SPaolo Bonzini int cur_level; 41853018216SPaolo Bonzini 419af96d2e6SCédric Le Goater trace_ppc_irq_set(env, pin, level); 420af96d2e6SCédric Le Goater 42153018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 42253018216SPaolo Bonzini /* Don't generate spurious events */ 42353018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 42453018216SPaolo Bonzini switch (pin) { 42553018216SPaolo Bonzini case PPCE500_INPUT_MCK: 42653018216SPaolo Bonzini if (level) { 427af96d2e6SCédric Le Goater trace_ppc_irq_reset("system"); 428cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 42953018216SPaolo Bonzini } 43053018216SPaolo Bonzini break; 43153018216SPaolo Bonzini case PPCE500_INPUT_RESET_CORE: 43253018216SPaolo Bonzini if (level) { 433af96d2e6SCédric Le Goater trace_ppc_irq_reset("core"); 43453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); 43553018216SPaolo Bonzini } 43653018216SPaolo Bonzini break; 43753018216SPaolo Bonzini case PPCE500_INPUT_CINT: 43853018216SPaolo Bonzini /* Level sensitive - active high */ 439af96d2e6SCédric Le Goater trace_ppc_irq_set_state("critical IRQ", level); 44053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 44153018216SPaolo Bonzini break; 44253018216SPaolo Bonzini case PPCE500_INPUT_INT: 44353018216SPaolo Bonzini /* Level sensitive - active high */ 444af96d2e6SCédric Le Goater trace_ppc_irq_set_state("core IRQ", level); 44553018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 44653018216SPaolo Bonzini break; 44753018216SPaolo Bonzini case PPCE500_INPUT_DEBUG: 44853018216SPaolo Bonzini /* Level sensitive - active high */ 449af96d2e6SCédric Le Goater trace_ppc_irq_set_state("debug pin", level); 45053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 45153018216SPaolo Bonzini break; 45253018216SPaolo Bonzini default: 4537279810bSCédric Le Goater g_assert_not_reached(); 45453018216SPaolo Bonzini } 45553018216SPaolo Bonzini if (level) 45653018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 45753018216SPaolo Bonzini else 45853018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 45953018216SPaolo Bonzini } 46053018216SPaolo Bonzini } 46153018216SPaolo Bonzini 462aa5a9e24SPaolo Bonzini void ppce500_irq_init(PowerPCCPU *cpu) 46353018216SPaolo Bonzini { 4645e66cd0cSCédric Le Goater qdev_init_gpio_in(DEVICE(cpu), ppce500_set_irq, PPCE500_INPUT_NB); 46553018216SPaolo Bonzini } 46653018216SPaolo Bonzini 46753018216SPaolo Bonzini /* Enable or Disable the E500 EPR capability */ 46853018216SPaolo Bonzini void ppce500_set_mpic_proxy(bool enabled) 46953018216SPaolo Bonzini { 470182735efSAndreas Färber CPUState *cs; 47153018216SPaolo Bonzini 472bdc44640SAndreas Färber CPU_FOREACH(cs) { 473182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 47453018216SPaolo Bonzini 475182735efSAndreas Färber cpu->env.mpic_proxy = enabled; 47653018216SPaolo Bonzini if (kvm_enabled()) { 477182735efSAndreas Färber kvmppc_set_mpic_proxy(cpu, enabled); 47853018216SPaolo Bonzini } 47953018216SPaolo Bonzini } 48053018216SPaolo Bonzini } 48153018216SPaolo Bonzini 48253018216SPaolo Bonzini /*****************************************************************************/ 48353018216SPaolo Bonzini /* PowerPC time base and decrementer emulation */ 48453018216SPaolo Bonzini 485eab08884SNicholas Piggin /* 486eab08884SNicholas Piggin * Conversion between QEMU_CLOCK_VIRTUAL ns and timebase (TB) ticks: 487eab08884SNicholas Piggin * TB ticks are arrived at by multiplying tb_freq then dividing by 488eab08884SNicholas Piggin * ns per second, and rounding down. TB ticks drive all clocks and 489eab08884SNicholas Piggin * timers in the target machine. 490eab08884SNicholas Piggin * 491eab08884SNicholas Piggin * Converting TB intervals to ns for the purpose of setting a 492eab08884SNicholas Piggin * QEMU_CLOCK_VIRTUAL timer should go the other way, but rounding 493eab08884SNicholas Piggin * up. Rounding down could cause the timer to fire before the TB 494eab08884SNicholas Piggin * value has been reached. 495eab08884SNicholas Piggin */ 4967798f5c5SNicholas Piggin static uint64_t ns_to_tb(uint32_t freq, int64_t clock) 4977798f5c5SNicholas Piggin { 4987798f5c5SNicholas Piggin return muldiv64(clock, freq, NANOSECONDS_PER_SECOND); 4997798f5c5SNicholas Piggin } 5007798f5c5SNicholas Piggin 501eab08884SNicholas Piggin /* virtual clock in TB ticks, not adjusted by TB offset */ 502eab08884SNicholas Piggin static int64_t tb_to_ns_round_up(uint32_t freq, uint64_t tb) 5037798f5c5SNicholas Piggin { 504eab08884SNicholas Piggin return muldiv64_round_up(tb, NANOSECONDS_PER_SECOND, freq); 5057798f5c5SNicholas Piggin } 5067798f5c5SNicholas Piggin 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 */ 5107798f5c5SNicholas Piggin return ns_to_tb(tb_env->tb_freq, vmclk) + 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 522eaf832fcSNicholas Piggin tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 523eaf832fcSNicholas Piggin tb_env->tb_offset); 524af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 52553018216SPaolo Bonzini 52653018216SPaolo Bonzini return tb; 52753018216SPaolo Bonzini } 52853018216SPaolo Bonzini 52953018216SPaolo Bonzini static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) 53053018216SPaolo Bonzini { 53153018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 53253018216SPaolo Bonzini uint64_t tb; 53353018216SPaolo Bonzini 534eaf832fcSNicholas Piggin tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 535eaf832fcSNicholas Piggin tb_env->tb_offset); 536af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 53753018216SPaolo Bonzini 53853018216SPaolo Bonzini return tb >> 32; 53953018216SPaolo Bonzini } 54053018216SPaolo Bonzini 54153018216SPaolo Bonzini uint32_t cpu_ppc_load_tbu (CPUPPCState *env) 54253018216SPaolo Bonzini { 54353018216SPaolo Bonzini if (kvm_enabled()) { 54453018216SPaolo Bonzini return env->spr[SPR_TBU]; 54553018216SPaolo Bonzini } 54653018216SPaolo Bonzini 54753018216SPaolo Bonzini return _cpu_ppc_load_tbu(env); 54853018216SPaolo Bonzini } 54953018216SPaolo Bonzini 55053018216SPaolo Bonzini static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, 55153018216SPaolo Bonzini int64_t *tb_offsetp, uint64_t value) 55253018216SPaolo Bonzini { 5537798f5c5SNicholas Piggin *tb_offsetp = value - ns_to_tb(tb_env->tb_freq, vmclk); 55473bcb24dSRutuja Shah 555af96d2e6SCédric Le Goater trace_ppc_tb_store(value, *tb_offsetp); 55653018216SPaolo Bonzini } 55753018216SPaolo Bonzini 55853018216SPaolo Bonzini void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) 55953018216SPaolo Bonzini { 56053018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 5612ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 56253018216SPaolo Bonzini uint64_t tb; 56353018216SPaolo Bonzini 5642ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset); 56553018216SPaolo Bonzini tb &= 0xFFFFFFFF00000000ULL; 5662ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb | (uint64_t)value); 56753018216SPaolo Bonzini } 56853018216SPaolo Bonzini 56953018216SPaolo Bonzini static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) 57053018216SPaolo Bonzini { 57153018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 5722ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 57353018216SPaolo Bonzini uint64_t tb; 57453018216SPaolo Bonzini 5752ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset); 57653018216SPaolo Bonzini tb &= 0x00000000FFFFFFFFULL; 5772ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, 5782ad2e113SNicholas Piggin ((uint64_t)value << 32) | tb); 57953018216SPaolo Bonzini } 58053018216SPaolo Bonzini 58153018216SPaolo Bonzini void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value) 58253018216SPaolo Bonzini { 58353018216SPaolo Bonzini _cpu_ppc_store_tbu(env, value); 58453018216SPaolo Bonzini } 58553018216SPaolo Bonzini 58653018216SPaolo Bonzini uint64_t cpu_ppc_load_atbl (CPUPPCState *env) 58753018216SPaolo Bonzini { 58853018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 58953018216SPaolo Bonzini uint64_t tb; 59053018216SPaolo Bonzini 591eaf832fcSNicholas Piggin tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 592eaf832fcSNicholas Piggin tb_env->atb_offset); 593af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 59453018216SPaolo Bonzini 59553018216SPaolo Bonzini return tb; 59653018216SPaolo Bonzini } 59753018216SPaolo Bonzini 59853018216SPaolo Bonzini uint32_t cpu_ppc_load_atbu (CPUPPCState *env) 59953018216SPaolo Bonzini { 60053018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 60153018216SPaolo Bonzini uint64_t tb; 60253018216SPaolo Bonzini 603eaf832fcSNicholas Piggin tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 604eaf832fcSNicholas Piggin tb_env->atb_offset); 605af96d2e6SCédric Le Goater trace_ppc_tb_load(tb); 60653018216SPaolo Bonzini 60753018216SPaolo Bonzini return tb >> 32; 60853018216SPaolo Bonzini } 60953018216SPaolo Bonzini 61053018216SPaolo Bonzini void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) 61153018216SPaolo Bonzini { 61253018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 6132ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 61453018216SPaolo Bonzini uint64_t tb; 61553018216SPaolo Bonzini 6162ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset); 61753018216SPaolo Bonzini tb &= 0xFFFFFFFF00000000ULL; 6182ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset, tb | (uint64_t)value); 61953018216SPaolo Bonzini } 62053018216SPaolo Bonzini 62153018216SPaolo Bonzini void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) 62253018216SPaolo Bonzini { 62353018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 6242ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 62553018216SPaolo Bonzini uint64_t tb; 62653018216SPaolo Bonzini 6272ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset); 62853018216SPaolo Bonzini tb &= 0x00000000FFFFFFFFULL; 6292ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset, 6302ad2e113SNicholas Piggin ((uint64_t)value << 32) | tb); 63153018216SPaolo Bonzini } 63253018216SPaolo Bonzini 6335d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env) 6345d62725bSSuraj Jitindar Singh { 6355d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6365d62725bSSuraj Jitindar Singh 6375d62725bSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6385d62725bSSuraj Jitindar Singh tb_env->vtb_offset); 6395d62725bSSuraj Jitindar Singh } 6405d62725bSSuraj Jitindar Singh 6415d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value) 6425d62725bSSuraj Jitindar Singh { 6435d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6445d62725bSSuraj Jitindar Singh 6455d62725bSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6465d62725bSSuraj Jitindar Singh &tb_env->vtb_offset, value); 6475d62725bSSuraj Jitindar Singh } 6485d62725bSSuraj Jitindar Singh 649f0ec31b1SSuraj Jitindar Singh void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value) 650f0ec31b1SSuraj Jitindar Singh { 651f0ec31b1SSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6522ad2e113SNicholas Piggin int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 653f0ec31b1SSuraj Jitindar Singh uint64_t tb; 654f0ec31b1SSuraj Jitindar Singh 6552ad2e113SNicholas Piggin tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset); 656f0ec31b1SSuraj Jitindar Singh tb &= 0xFFFFFFUL; 657f0ec31b1SSuraj Jitindar Singh tb |= (value & ~0xFFFFFFUL); 6582ad2e113SNicholas Piggin cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb); 659f0ec31b1SSuraj Jitindar Singh } 660f0ec31b1SSuraj Jitindar Singh 66153018216SPaolo Bonzini static void cpu_ppc_tb_stop (CPUPPCState *env) 66253018216SPaolo Bonzini { 66353018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 66453018216SPaolo Bonzini uint64_t tb, atb, vmclk; 66553018216SPaolo Bonzini 66653018216SPaolo Bonzini /* If the time base is already frozen, do nothing */ 66753018216SPaolo Bonzini if (tb_env->tb_freq != 0) { 668bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 66953018216SPaolo Bonzini /* Get the time base */ 67053018216SPaolo Bonzini tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); 67153018216SPaolo Bonzini /* Get the alternate time base */ 67253018216SPaolo Bonzini atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); 67353018216SPaolo Bonzini /* Store the time base value (ie compute the current offset) */ 67453018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 67553018216SPaolo Bonzini /* Store the alternate time base value (compute the current offset) */ 67653018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 67753018216SPaolo Bonzini /* Set the time base frequency to zero */ 67853018216SPaolo Bonzini tb_env->tb_freq = 0; 67953018216SPaolo Bonzini /* Now, the time bases are frozen to tb_offset / atb_offset value */ 68053018216SPaolo Bonzini } 68153018216SPaolo Bonzini } 68253018216SPaolo Bonzini 68353018216SPaolo Bonzini static void cpu_ppc_tb_start (CPUPPCState *env) 68453018216SPaolo Bonzini { 68553018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 68653018216SPaolo Bonzini uint64_t tb, atb, vmclk; 68753018216SPaolo Bonzini 68853018216SPaolo Bonzini /* If the time base is not frozen, do nothing */ 68953018216SPaolo Bonzini if (tb_env->tb_freq == 0) { 690bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 69153018216SPaolo Bonzini /* Get the time base from tb_offset */ 69253018216SPaolo Bonzini tb = tb_env->tb_offset; 69353018216SPaolo Bonzini /* Get the alternate time base from atb_offset */ 69453018216SPaolo Bonzini atb = tb_env->atb_offset; 69553018216SPaolo Bonzini /* Restore the tb frequency from the decrementer frequency */ 69653018216SPaolo Bonzini tb_env->tb_freq = tb_env->decr_freq; 69753018216SPaolo Bonzini /* Store the time base value */ 69853018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 69953018216SPaolo Bonzini /* Store the alternate time base value */ 70053018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 70153018216SPaolo Bonzini } 70253018216SPaolo Bonzini } 70353018216SPaolo Bonzini 704e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env) 705e81a982aSAlexander Graf { 706e81a982aSAlexander Graf ppc_tb_t *tb_env = env->tb_env; 707e81a982aSAlexander Graf int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL; 708e81a982aSAlexander Graf return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED); 709e81a982aSAlexander Graf } 710e81a982aSAlexander Graf 711a8dafa52SSuraj Jitindar Singh static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) 71253018216SPaolo Bonzini { 71353018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 7148e0a5ac8SNicholas Piggin uint64_t now, n; 7158e0a5ac8SNicholas Piggin int64_t decr; 71653018216SPaolo Bonzini 7178e0a5ac8SNicholas Piggin now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 7188e0a5ac8SNicholas Piggin n = ns_to_tb(tb_env->decr_freq, now); 7198e0a5ac8SNicholas Piggin if (next > n && tb_env->flags & PPC_TIMER_BOOKE) { 72053018216SPaolo Bonzini decr = 0; 72153018216SPaolo Bonzini } else { 7228e0a5ac8SNicholas Piggin decr = next - n; 72353018216SPaolo Bonzini } 7248e0a5ac8SNicholas Piggin 725af96d2e6SCédric Le Goater trace_ppc_decr_load(decr); 72653018216SPaolo Bonzini 72753018216SPaolo Bonzini return decr; 72853018216SPaolo Bonzini } 72953018216SPaolo Bonzini 730a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_decr(CPUPPCState *env) 73153018216SPaolo Bonzini { 73253018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 733a8dafa52SSuraj Jitindar Singh uint64_t decr; 73453018216SPaolo Bonzini 73553018216SPaolo Bonzini if (kvm_enabled()) { 73653018216SPaolo Bonzini return env->spr[SPR_DECR]; 73753018216SPaolo Bonzini } 73853018216SPaolo Bonzini 739a8dafa52SSuraj Jitindar Singh decr = _cpu_ppc_load_decr(env, tb_env->decr_next); 740a8dafa52SSuraj Jitindar Singh 741a8dafa52SSuraj Jitindar Singh /* 742a8dafa52SSuraj Jitindar Singh * If large decrementer is enabled then the decrementer is signed extened 743a8dafa52SSuraj Jitindar Singh * to 64 bits, otherwise it is a 32 bit value. 744a8dafa52SSuraj Jitindar Singh */ 745a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 746c8fbc6b9SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 747c8fbc6b9SNicholas Piggin PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 748c8fbc6b9SNicholas Piggin return sextract64(decr, 0, pcc->lrg_decr_bits); 749a8dafa52SSuraj Jitindar Singh } 750a8dafa52SSuraj Jitindar Singh return (uint32_t) decr; 75153018216SPaolo Bonzini } 75253018216SPaolo Bonzini 753a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_hdecr(CPUPPCState *env) 75453018216SPaolo Bonzini { 755db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 756a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 75753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 758a8dafa52SSuraj Jitindar Singh uint64_t hdecr; 75953018216SPaolo Bonzini 760a8dafa52SSuraj Jitindar Singh hdecr = _cpu_ppc_load_decr(env, tb_env->hdecr_next); 761a8dafa52SSuraj Jitindar Singh 762a8dafa52SSuraj Jitindar Singh /* 763a8dafa52SSuraj Jitindar Singh * If we have a large decrementer (POWER9 or later) then hdecr is sign 764a8dafa52SSuraj Jitindar Singh * extended to 64 bits, otherwise it is 32 bits. 765a8dafa52SSuraj Jitindar Singh */ 766a8dafa52SSuraj Jitindar Singh if (pcc->lrg_decr_bits > 32) { 767c8fbc6b9SNicholas Piggin return sextract64(hdecr, 0, pcc->lrg_decr_bits); 768a8dafa52SSuraj Jitindar Singh } 769a8dafa52SSuraj Jitindar Singh return (uint32_t) hdecr; 77053018216SPaolo Bonzini } 77153018216SPaolo Bonzini 77253018216SPaolo Bonzini uint64_t cpu_ppc_load_purr (CPUPPCState *env) 77353018216SPaolo Bonzini { 77453018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 77553018216SPaolo Bonzini 7765cc7e69fSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 7775cc7e69fSSuraj Jitindar Singh tb_env->purr_offset); 77853018216SPaolo Bonzini } 77953018216SPaolo Bonzini 78053018216SPaolo Bonzini /* When decrementer expires, 78153018216SPaolo Bonzini * all we need to do is generate or queue a CPU exception 78253018216SPaolo Bonzini */ 78353018216SPaolo Bonzini static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) 78453018216SPaolo Bonzini { 78553018216SPaolo Bonzini /* Raise it */ 786af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise"); 78753018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); 78853018216SPaolo Bonzini } 78953018216SPaolo Bonzini 790e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu) 791e81a982aSAlexander Graf { 792e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0); 793e81a982aSAlexander Graf } 794e81a982aSAlexander Graf 79553018216SPaolo Bonzini static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) 79653018216SPaolo Bonzini { 7974b236b62SBenjamin Herrenschmidt CPUPPCState *env = &cpu->env; 7984b236b62SBenjamin Herrenschmidt 79953018216SPaolo Bonzini /* Raise it */ 800af96d2e6SCédric Le Goater trace_ppc_decr_excp("raise HV"); 8014b236b62SBenjamin Herrenschmidt 8024b236b62SBenjamin Herrenschmidt /* The architecture specifies that we don't deliver HDEC 8034b236b62SBenjamin Herrenschmidt * interrupts in a PM state. Not only they don't cause a 8044b236b62SBenjamin Herrenschmidt * wakeup but they also get effectively discarded. 8054b236b62SBenjamin Herrenschmidt */ 8061e7fd61dSBenjamin Herrenschmidt if (!env->resume_as_sreset) { 80753018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); 80853018216SPaolo Bonzini } 8094b236b62SBenjamin Herrenschmidt } 81053018216SPaolo Bonzini 811e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) 812e81a982aSAlexander Graf { 813e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); 814e81a982aSAlexander Graf } 815e81a982aSAlexander Graf 81653018216SPaolo Bonzini static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, 8171246b259SStefan Weil QEMUTimer *timer, 818e81a982aSAlexander Graf void (*raise_excp)(void *), 819e81a982aSAlexander Graf void (*lower_excp)(PowerPCCPU *), 820a5ff7875SNicholas Piggin uint32_t flags, target_ulong decr, 821a5ff7875SNicholas Piggin target_ulong value, int nr_bits) 82253018216SPaolo Bonzini { 82353018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 82453018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 82553018216SPaolo Bonzini uint64_t now, next; 8264d9b8ef9SCédric Le Goater int64_t signed_value; 8274d9b8ef9SCédric Le Goater int64_t signed_decr; 82853018216SPaolo Bonzini 829a8dafa52SSuraj Jitindar Singh /* Truncate value to decr_width and sign extend for simplicity */ 83009d2db9fSNicholas Piggin value = extract64(value, 0, nr_bits); 83109d2db9fSNicholas Piggin decr = extract64(decr, 0, nr_bits); 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 /* 84317dd1354SNicholas Piggin * Going from 1 -> 0 or 0 -> -1 is the event to generate a DEC interrupt. 844e81a982aSAlexander Graf * 845e81a982aSAlexander Graf * On MSB level based DEC implementations the MSB always means the interrupt 846e81a982aSAlexander Graf * is pending, so raise it on those. 847e81a982aSAlexander Graf * 848e81a982aSAlexander Graf * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers 849e81a982aSAlexander Graf * an edge interrupt, so raise it here too. 850e81a982aSAlexander Graf */ 851a5ff7875SNicholas Piggin if (((flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) || 852a5ff7875SNicholas Piggin ((flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0 8534d9b8ef9SCédric Le Goater && signed_decr >= 0)) { 854e81a982aSAlexander Graf (*raise_excp)(cpu); 855e81a982aSAlexander Graf return; 856e81a982aSAlexander Graf } 857e81a982aSAlexander Graf 858e81a982aSAlexander Graf /* On MSB level based systems a 0 for the MSB stops interrupt delivery */ 859a5ff7875SNicholas Piggin if (signed_value >= 0 && (flags & PPC_DECR_UNDERFLOW_LEVEL)) { 860e81a982aSAlexander Graf (*lower_excp)(cpu); 861e81a982aSAlexander Graf } 862e81a982aSAlexander Graf 8638e0a5ac8SNicholas Piggin /* 8648e0a5ac8SNicholas Piggin * Calculate the next decrementer event and set a timer. 8658e0a5ac8SNicholas Piggin * decr_next is in timebase units to keep rounding simple. Note it is 8668e0a5ac8SNicholas Piggin * not adjusted by tb_offset because if TB changes via tb_offset changing, 8678e0a5ac8SNicholas Piggin * decrementer does not change, so not directly comparable with TB. 8688e0a5ac8SNicholas Piggin */ 869bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 8708e0a5ac8SNicholas Piggin next = ns_to_tb(tb_env->decr_freq, now) + value; 87153018216SPaolo Bonzini *nextp = next; 872e81a982aSAlexander Graf 87353018216SPaolo Bonzini /* Adjust timer */ 8748e0a5ac8SNicholas Piggin timer_mod(timer, tb_to_ns_round_up(tb_env->decr_freq, 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, 883a5ff7875SNicholas Piggin tb_env->decr_timer->cb, &cpu_ppc_decr_lower, 884a5ff7875SNicholas Piggin tb_env->flags, decr, 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) { 913a5ff7875SNicholas Piggin /* HDECR (Book3S 64bit) is edge-based, not level like DECR */ 91453018216SPaolo Bonzini __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, 915e81a982aSAlexander Graf tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower, 916a5ff7875SNicholas Piggin PPC_DECR_UNDERFLOW_TRIGGERED, 917a8dafa52SSuraj Jitindar Singh hdecr, value, nr_bits); 91853018216SPaolo Bonzini } 91953018216SPaolo Bonzini } 92053018216SPaolo Bonzini 921a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value) 92253018216SPaolo Bonzini { 923db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 924a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 92553018216SPaolo Bonzini 926a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 927a8dafa52SSuraj Jitindar Singh pcc->lrg_decr_bits); 92853018216SPaolo Bonzini } 92953018216SPaolo Bonzini 93053018216SPaolo Bonzini static void cpu_ppc_hdecr_cb(void *opaque) 93153018216SPaolo Bonzini { 93253018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 93353018216SPaolo Bonzini 934e81a982aSAlexander Graf cpu_ppc_hdecr_excp(cpu); 93553018216SPaolo Bonzini } 93653018216SPaolo Bonzini 9375cc7e69fSSuraj Jitindar Singh void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) 93853018216SPaolo Bonzini { 9395cc7e69fSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 94053018216SPaolo Bonzini 9415cc7e69fSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 9425cc7e69fSSuraj Jitindar Singh &tb_env->purr_offset, value); 94353018216SPaolo Bonzini } 94453018216SPaolo Bonzini 94553018216SPaolo Bonzini static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) 94653018216SPaolo Bonzini { 94753018216SPaolo Bonzini CPUPPCState *env = opaque; 948db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 94953018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 95053018216SPaolo Bonzini 95153018216SPaolo Bonzini tb_env->tb_freq = freq; 95253018216SPaolo Bonzini tb_env->decr_freq = freq; 95353018216SPaolo Bonzini /* There is a bug in Linux 2.4 kernels: 95453018216SPaolo Bonzini * if a decrementer exception is pending when it enables msr_ee at startup, 95553018216SPaolo Bonzini * it's not ready to handle it... 95653018216SPaolo Bonzini */ 957a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 958a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 9595cc7e69fSSuraj Jitindar Singh cpu_ppc_store_purr(env, 0x0000000000000000ULL); 96053018216SPaolo Bonzini } 96153018216SPaolo Bonzini 96242043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb) 96398a8b524SAlexey Kardashevskiy { 9644a7428c5SChristopher Covington uint64_t ticks = cpu_get_host_ticks(); 96598a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 96698a8b524SAlexey Kardashevskiy 96798a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 96898a8b524SAlexey Kardashevskiy error_report("No timebase object"); 96998a8b524SAlexey Kardashevskiy return; 97098a8b524SAlexey Kardashevskiy } 97198a8b524SAlexey Kardashevskiy 97242043e4fSLaurent Vivier /* not used anymore, we keep it for compatibility */ 97377bad151SPaolo Bonzini tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); 97498a8b524SAlexey Kardashevskiy /* 97542043e4fSLaurent Vivier * tb_offset is only expected to be changed by QEMU so 97698a8b524SAlexey Kardashevskiy * there is no need to update it from KVM here 97798a8b524SAlexey Kardashevskiy */ 97898a8b524SAlexey Kardashevskiy tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; 979d14f3397SMaxiwell S. Garcia 980711dfb24SGreg Kurz tb->runstate_paused = 981711dfb24SGreg Kurz runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM); 98298a8b524SAlexey Kardashevskiy } 98398a8b524SAlexey Kardashevskiy 98442043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb) 98598a8b524SAlexey Kardashevskiy { 98698a8b524SAlexey Kardashevskiy CPUState *cpu; 98798a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 98842043e4fSLaurent Vivier int64_t tb_off_adj, tb_off; 98998a8b524SAlexey Kardashevskiy unsigned long freq; 99098a8b524SAlexey Kardashevskiy 99198a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 99298a8b524SAlexey Kardashevskiy error_report("No timebase object"); 99342043e4fSLaurent Vivier return; 99498a8b524SAlexey Kardashevskiy } 99598a8b524SAlexey Kardashevskiy 99698a8b524SAlexey Kardashevskiy freq = first_ppc_cpu->env.tb_env->tb_freq; 99798a8b524SAlexey Kardashevskiy 99842043e4fSLaurent Vivier tb_off_adj = tb->guest_timebase - cpu_get_host_ticks(); 99998a8b524SAlexey Kardashevskiy 100098a8b524SAlexey Kardashevskiy tb_off = first_ppc_cpu->env.tb_env->tb_offset; 100198a8b524SAlexey Kardashevskiy trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off, 100298a8b524SAlexey Kardashevskiy (tb_off_adj - tb_off) / freq); 100398a8b524SAlexey Kardashevskiy 100498a8b524SAlexey Kardashevskiy /* Set new offset to all CPUs */ 100598a8b524SAlexey Kardashevskiy CPU_FOREACH(cpu) { 100698a8b524SAlexey Kardashevskiy PowerPCCPU *pcpu = POWERPC_CPU(cpu); 100798a8b524SAlexey Kardashevskiy pcpu->env.tb_env->tb_offset = tb_off_adj; 10089723295aSGreg Kurz kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset); 100942043e4fSLaurent Vivier } 101098a8b524SAlexey Kardashevskiy } 101198a8b524SAlexey Kardashevskiy 1012538f0497SPhilippe Mathieu-Daudé void cpu_ppc_clock_vm_state_change(void *opaque, bool running, 101342043e4fSLaurent Vivier RunState state) 101442043e4fSLaurent Vivier { 101542043e4fSLaurent Vivier PPCTimebase *tb = opaque; 101642043e4fSLaurent Vivier 101742043e4fSLaurent Vivier if (running) { 101842043e4fSLaurent Vivier timebase_load(tb); 101942043e4fSLaurent Vivier } else { 102042043e4fSLaurent Vivier timebase_save(tb); 102142043e4fSLaurent Vivier } 102242043e4fSLaurent Vivier } 102342043e4fSLaurent Vivier 102442043e4fSLaurent Vivier /* 1025d14f3397SMaxiwell S. Garcia * When migrating a running guest, read the clock just 1026d14f3397SMaxiwell S. Garcia * before migration, so that the guest clock counts 1027d14f3397SMaxiwell S. Garcia * during the events between: 102842043e4fSLaurent Vivier * 102942043e4fSLaurent Vivier * * vm_stop() 103042043e4fSLaurent Vivier * * 103142043e4fSLaurent Vivier * * pre_save() 103242043e4fSLaurent Vivier * 103342043e4fSLaurent Vivier * This reduces clock difference on migration from 5s 103442043e4fSLaurent Vivier * to 0.1s (when max_downtime == 5s), because sending the 103542043e4fSLaurent Vivier * final pages of memory (which happens between vm_stop() 103642043e4fSLaurent Vivier * and pre_save()) takes max_downtime. 103742043e4fSLaurent Vivier */ 103844b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque) 103942043e4fSLaurent Vivier { 104042043e4fSLaurent Vivier PPCTimebase *tb = opaque; 104142043e4fSLaurent Vivier 1042711dfb24SGreg Kurz /* guest_timebase won't be overridden in case of paused guest or savevm */ 1043d14f3397SMaxiwell S. Garcia if (!tb->runstate_paused) { 104442043e4fSLaurent Vivier timebase_save(tb); 1045d14f3397SMaxiwell S. Garcia } 104644b1ff31SDr. David Alan Gilbert 104744b1ff31SDr. David Alan Gilbert return 0; 104898a8b524SAlexey Kardashevskiy } 104998a8b524SAlexey Kardashevskiy 105098a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = { 105198a8b524SAlexey Kardashevskiy .name = "timebase", 105298a8b524SAlexey Kardashevskiy .version_id = 1, 105398a8b524SAlexey Kardashevskiy .minimum_version_id = 1, 105498a8b524SAlexey Kardashevskiy .pre_save = timebase_pre_save, 105598a8b524SAlexey Kardashevskiy .fields = (VMStateField []) { 105698a8b524SAlexey Kardashevskiy VMSTATE_UINT64(guest_timebase, PPCTimebase), 105798a8b524SAlexey Kardashevskiy VMSTATE_INT64(time_of_the_day_ns, PPCTimebase), 105898a8b524SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 105998a8b524SAlexey Kardashevskiy }, 106098a8b524SAlexey Kardashevskiy }; 106198a8b524SAlexey Kardashevskiy 106253018216SPaolo Bonzini /* Set up (once) timebase frequency (in Hz) */ 106353018216SPaolo Bonzini clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) 106453018216SPaolo Bonzini { 1065db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 106653018216SPaolo Bonzini ppc_tb_t *tb_env; 106753018216SPaolo Bonzini 1068b21e2380SMarkus Armbruster tb_env = g_new0(ppc_tb_t, 1); 106953018216SPaolo Bonzini env->tb_env = tb_env; 107053018216SPaolo Bonzini tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 1071d0db7cadSGreg Kurz if (is_book3s_arch2x(env)) { 1072e81a982aSAlexander Graf /* All Book3S 64bit CPUs implement level based DEC logic */ 1073e81a982aSAlexander Graf tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL; 1074e81a982aSAlexander Graf } 107553018216SPaolo Bonzini /* Create new timer */ 1076eaf832fcSNicholas Piggin tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 1077eaf832fcSNicholas Piggin &cpu_ppc_decr_cb, cpu); 10785ff40b01SNicholas Piggin if (env->has_hv_mode && !cpu->vhyp) { 1079eaf832fcSNicholas Piggin tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 1080eaf832fcSNicholas Piggin &cpu_ppc_hdecr_cb, cpu); 108153018216SPaolo Bonzini } else { 108253018216SPaolo Bonzini tb_env->hdecr_timer = NULL; 108353018216SPaolo Bonzini } 108453018216SPaolo Bonzini cpu_ppc_set_tb_clk(env, freq); 108553018216SPaolo Bonzini 108653018216SPaolo Bonzini return &cpu_ppc_set_tb_clk; 108753018216SPaolo Bonzini } 108853018216SPaolo Bonzini 1089ef95a244SDaniel Henrique Barboza void cpu_ppc_tb_free(CPUPPCState *env) 1090ef95a244SDaniel Henrique Barboza { 1091ef95a244SDaniel Henrique Barboza timer_free(env->tb_env->decr_timer); 1092ef95a244SDaniel Henrique Barboza timer_free(env->tb_env->hdecr_timer); 1093ef95a244SDaniel Henrique Barboza g_free(env->tb_env); 1094ef95a244SDaniel Henrique Barboza } 1095ef95a244SDaniel Henrique Barboza 109693aeb702SNicholas Piggin /* cpu_ppc_hdecr_init may be used if the timer is not used by HDEC emulation */ 109793aeb702SNicholas Piggin void cpu_ppc_hdecr_init(CPUPPCState *env) 109893aeb702SNicholas Piggin { 109993aeb702SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 110093aeb702SNicholas Piggin 110193aeb702SNicholas Piggin assert(env->tb_env->hdecr_timer == NULL); 110293aeb702SNicholas Piggin 110393aeb702SNicholas Piggin env->tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 110493aeb702SNicholas Piggin &cpu_ppc_hdecr_cb, cpu); 110593aeb702SNicholas Piggin } 110693aeb702SNicholas Piggin 110793aeb702SNicholas Piggin void cpu_ppc_hdecr_exit(CPUPPCState *env) 110893aeb702SNicholas Piggin { 110993aeb702SNicholas Piggin PowerPCCPU *cpu = env_archcpu(env); 111093aeb702SNicholas Piggin 111193aeb702SNicholas Piggin timer_free(env->tb_env->hdecr_timer); 111293aeb702SNicholas Piggin env->tb_env->hdecr_timer = NULL; 111393aeb702SNicholas Piggin 111493aeb702SNicholas Piggin cpu_ppc_hdecr_lower(cpu); 111593aeb702SNicholas Piggin } 111693aeb702SNicholas Piggin 111753018216SPaolo Bonzini /*****************************************************************************/ 111853018216SPaolo Bonzini /* PowerPC 40x timers */ 111953018216SPaolo Bonzini 112053018216SPaolo Bonzini /* PIT, FIT & WDT */ 112153018216SPaolo Bonzini typedef struct ppc40x_timer_t ppc40x_timer_t; 112253018216SPaolo Bonzini struct ppc40x_timer_t { 112353018216SPaolo Bonzini uint64_t pit_reload; /* PIT auto-reload value */ 112453018216SPaolo Bonzini uint64_t fit_next; /* Tick for next FIT interrupt */ 11251246b259SStefan Weil QEMUTimer *fit_timer; 112653018216SPaolo Bonzini uint64_t wdt_next; /* Tick for next WDT interrupt */ 11271246b259SStefan Weil QEMUTimer *wdt_timer; 112853018216SPaolo Bonzini 112953018216SPaolo Bonzini /* 405 have the PIT, 440 have a DECR. */ 113053018216SPaolo Bonzini unsigned int decr_excp; 113153018216SPaolo Bonzini }; 113253018216SPaolo Bonzini 113353018216SPaolo Bonzini /* Fixed interval timer */ 113453018216SPaolo Bonzini static void cpu_4xx_fit_cb (void *opaque) 113553018216SPaolo Bonzini { 1136b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1137b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 113853018216SPaolo Bonzini ppc_tb_t *tb_env; 113953018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 114053018216SPaolo Bonzini uint64_t now, next; 114153018216SPaolo Bonzini 114253018216SPaolo Bonzini tb_env = env->tb_env; 114353018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1144bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 114553018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { 114653018216SPaolo Bonzini case 0: 114753018216SPaolo Bonzini next = 1 << 9; 114853018216SPaolo Bonzini break; 114953018216SPaolo Bonzini case 1: 115053018216SPaolo Bonzini next = 1 << 13; 115153018216SPaolo Bonzini break; 115253018216SPaolo Bonzini case 2: 115353018216SPaolo Bonzini next = 1 << 17; 115453018216SPaolo Bonzini break; 115553018216SPaolo Bonzini case 3: 115653018216SPaolo Bonzini next = 1 << 21; 115753018216SPaolo Bonzini break; 115853018216SPaolo Bonzini default: 115953018216SPaolo Bonzini /* Cannot occur, but makes gcc happy */ 116053018216SPaolo Bonzini return; 116153018216SPaolo Bonzini } 1162eab08884SNicholas Piggin next = now + tb_to_ns_round_up(tb_env->tb_freq, next); 1163bc72ad67SAlex Bligh timer_mod(ppc40x_timer->fit_timer, next); 116453018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 26; 116553018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { 116653018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); 116753018216SPaolo Bonzini } 1168af96d2e6SCédric Le Goater trace_ppc4xx_fit((int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), 116953018216SPaolo Bonzini env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 117053018216SPaolo Bonzini } 117153018216SPaolo Bonzini 117253018216SPaolo Bonzini /* Programmable interval timer */ 117353018216SPaolo Bonzini static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) 117453018216SPaolo Bonzini { 117553018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 117653018216SPaolo Bonzini uint64_t now, next; 117753018216SPaolo Bonzini 117853018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 117953018216SPaolo Bonzini if (ppc40x_timer->pit_reload <= 1 || 118053018216SPaolo Bonzini !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || 118153018216SPaolo Bonzini (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { 118253018216SPaolo Bonzini /* Stop PIT */ 1183af96d2e6SCédric Le Goater trace_ppc4xx_pit_stop(); 1184bc72ad67SAlex Bligh timer_del(tb_env->decr_timer); 118553018216SPaolo Bonzini } else { 1186af96d2e6SCédric Le Goater trace_ppc4xx_pit_start(ppc40x_timer->pit_reload); 1187bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 11888e0a5ac8SNicholas Piggin 11898e0a5ac8SNicholas Piggin if (is_excp) { 11908e0a5ac8SNicholas Piggin tb_env->decr_next += ppc40x_timer->pit_reload; 11918e0a5ac8SNicholas Piggin } else { 11928e0a5ac8SNicholas Piggin tb_env->decr_next = ns_to_tb(tb_env->decr_freq, now) 11938e0a5ac8SNicholas Piggin + ppc40x_timer->pit_reload; 11948e0a5ac8SNicholas Piggin } 11958e0a5ac8SNicholas Piggin next = tb_to_ns_round_up(tb_env->decr_freq, tb_env->decr_next); 1196bc72ad67SAlex Bligh timer_mod(tb_env->decr_timer, next); 119753018216SPaolo Bonzini } 119853018216SPaolo Bonzini } 119953018216SPaolo Bonzini 120053018216SPaolo Bonzini static void cpu_4xx_pit_cb (void *opaque) 120153018216SPaolo Bonzini { 1202b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1203b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 120453018216SPaolo Bonzini ppc_tb_t *tb_env; 120553018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 120653018216SPaolo Bonzini 120753018216SPaolo Bonzini tb_env = env->tb_env; 120853018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 120953018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 27; 121053018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { 121153018216SPaolo Bonzini ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); 121253018216SPaolo Bonzini } 121353018216SPaolo Bonzini start_stop_pit(env, tb_env, 1); 1214af96d2e6SCédric Le Goater trace_ppc4xx_pit((int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), 121553018216SPaolo Bonzini (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), 121653018216SPaolo Bonzini env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], 121753018216SPaolo Bonzini ppc40x_timer->pit_reload); 121853018216SPaolo Bonzini } 121953018216SPaolo Bonzini 122053018216SPaolo Bonzini /* Watchdog timer */ 122153018216SPaolo Bonzini static void cpu_4xx_wdt_cb (void *opaque) 122253018216SPaolo Bonzini { 1223b1273a5eSCédric Le Goater PowerPCCPU *cpu = opaque; 1224b1273a5eSCédric Le Goater CPUPPCState *env = &cpu->env; 122553018216SPaolo Bonzini ppc_tb_t *tb_env; 122653018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 122753018216SPaolo Bonzini uint64_t now, next; 122853018216SPaolo Bonzini 122953018216SPaolo Bonzini tb_env = env->tb_env; 123053018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1231bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 123253018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { 123353018216SPaolo Bonzini case 0: 123453018216SPaolo Bonzini next = 1 << 17; 123553018216SPaolo Bonzini break; 123653018216SPaolo Bonzini case 1: 123753018216SPaolo Bonzini next = 1 << 21; 123853018216SPaolo Bonzini break; 123953018216SPaolo Bonzini case 2: 124053018216SPaolo Bonzini next = 1 << 25; 124153018216SPaolo Bonzini break; 124253018216SPaolo Bonzini case 3: 124353018216SPaolo Bonzini next = 1 << 29; 124453018216SPaolo Bonzini break; 124553018216SPaolo Bonzini default: 124653018216SPaolo Bonzini /* Cannot occur, but makes gcc happy */ 124753018216SPaolo Bonzini return; 124853018216SPaolo Bonzini } 1249eab08884SNicholas Piggin next = now + tb_to_ns_round_up(tb_env->decr_freq, 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 1303cbd8f17dSCédric Le Goater void store_40x_tsr(CPUPPCState *env, target_ulong val) 1304cbd8f17dSCédric Le Goater { 1305cbd8f17dSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1306cbd8f17dSCédric Le Goater 1307cbd8f17dSCédric Le Goater trace_ppc40x_store_tcr(val); 1308cbd8f17dSCédric Le Goater 1309cbd8f17dSCédric Le Goater env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000); 1310cbd8f17dSCédric Le Goater if (val & 0x80000000) { 1311cbd8f17dSCédric Le Goater ppc_set_irq(cpu, PPC_INTERRUPT_PIT, 0); 1312cbd8f17dSCédric Le Goater } 1313cbd8f17dSCédric Le Goater } 1314cbd8f17dSCédric Le Goater 1315cbd8f17dSCédric Le Goater void store_40x_tcr(CPUPPCState *env, target_ulong val) 1316cbd8f17dSCédric Le Goater { 1317cbd8f17dSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1318cbd8f17dSCédric Le Goater ppc_tb_t *tb_env; 1319cbd8f17dSCédric Le Goater 1320cbd8f17dSCédric Le Goater trace_ppc40x_store_tsr(val); 1321cbd8f17dSCédric Le Goater 1322cbd8f17dSCédric Le Goater tb_env = env->tb_env; 1323cbd8f17dSCédric Le Goater env->spr[SPR_40x_TCR] = val & 0xFFC00000; 1324cbd8f17dSCédric Le Goater start_stop_pit(env, tb_env, 1); 1325cbd8f17dSCédric Le Goater cpu_4xx_wdt_cb(cpu); 1326cbd8f17dSCédric Le Goater } 1327cbd8f17dSCédric Le Goater 132853018216SPaolo Bonzini static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq) 132953018216SPaolo Bonzini { 133053018216SPaolo Bonzini CPUPPCState *env = opaque; 133153018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 133253018216SPaolo Bonzini 1333af96d2e6SCédric Le Goater trace_ppc40x_set_tb_clk(freq); 133453018216SPaolo Bonzini tb_env->tb_freq = freq; 133553018216SPaolo Bonzini tb_env->decr_freq = freq; 133653018216SPaolo Bonzini /* XXX: we should also update all timers */ 133753018216SPaolo Bonzini } 133853018216SPaolo Bonzini 133953018216SPaolo Bonzini clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, 134053018216SPaolo Bonzini unsigned int decr_excp) 134153018216SPaolo Bonzini { 134253018216SPaolo Bonzini ppc_tb_t *tb_env; 134353018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 1344b1273a5eSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env); 1345b1273a5eSCédric Le Goater 1346b1273a5eSCédric Le Goater trace_ppc40x_timers_init(freq); 134753018216SPaolo Bonzini 1348b21e2380SMarkus Armbruster tb_env = g_new0(ppc_tb_t, 1); 1349b21e2380SMarkus Armbruster ppc40x_timer = g_new0(ppc40x_timer_t, 1); 1350b1273a5eSCédric Le Goater 135153018216SPaolo Bonzini env->tb_env = tb_env; 135253018216SPaolo Bonzini tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 135353018216SPaolo Bonzini tb_env->tb_freq = freq; 135453018216SPaolo Bonzini tb_env->decr_freq = freq; 135553018216SPaolo Bonzini tb_env->opaque = ppc40x_timer; 1356b1273a5eSCédric Le Goater 135753018216SPaolo Bonzini /* We use decr timer for PIT */ 1358b1273a5eSCédric Le Goater tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, cpu); 135953018216SPaolo Bonzini ppc40x_timer->fit_timer = 1360b1273a5eSCédric Le Goater timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, cpu); 136153018216SPaolo Bonzini ppc40x_timer->wdt_timer = 1362b1273a5eSCédric Le Goater timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, cpu); 136353018216SPaolo Bonzini ppc40x_timer->decr_excp = decr_excp; 136453018216SPaolo Bonzini 136553018216SPaolo Bonzini return &ppc_40x_set_tb_clk; 136653018216SPaolo Bonzini } 136753018216SPaolo Bonzini 136853018216SPaolo Bonzini /*****************************************************************************/ 136953018216SPaolo Bonzini /* Embedded PowerPC Device Control Registers */ 137053018216SPaolo Bonzini typedef struct ppc_dcrn_t ppc_dcrn_t; 137153018216SPaolo Bonzini struct ppc_dcrn_t { 137253018216SPaolo Bonzini dcr_read_cb dcr_read; 137353018216SPaolo Bonzini dcr_write_cb dcr_write; 137453018216SPaolo Bonzini void *opaque; 137553018216SPaolo Bonzini }; 137653018216SPaolo Bonzini 137753018216SPaolo Bonzini /* XXX: on 460, DCR addresses are 32 bits wide, 137853018216SPaolo Bonzini * using DCRIPR to get the 22 upper bits of the DCR address 137953018216SPaolo Bonzini */ 138053018216SPaolo Bonzini #define DCRN_NB 1024 138153018216SPaolo Bonzini struct ppc_dcr_t { 138253018216SPaolo Bonzini ppc_dcrn_t dcrn[DCRN_NB]; 138353018216SPaolo Bonzini int (*read_error)(int dcrn); 138453018216SPaolo Bonzini int (*write_error)(int dcrn); 138553018216SPaolo Bonzini }; 138653018216SPaolo Bonzini 138753018216SPaolo Bonzini int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) 138853018216SPaolo Bonzini { 138953018216SPaolo Bonzini ppc_dcrn_t *dcr; 139053018216SPaolo Bonzini 139153018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 139253018216SPaolo Bonzini goto error; 139353018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 139453018216SPaolo Bonzini if (dcr->dcr_read == NULL) 139553018216SPaolo Bonzini goto error; 139653018216SPaolo Bonzini *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); 1397de82dabeSCédric Le Goater trace_ppc_dcr_read(dcrn, *valp); 139853018216SPaolo Bonzini 139953018216SPaolo Bonzini return 0; 140053018216SPaolo Bonzini 140153018216SPaolo Bonzini error: 140253018216SPaolo Bonzini if (dcr_env->read_error != NULL) 140353018216SPaolo Bonzini return (*dcr_env->read_error)(dcrn); 140453018216SPaolo Bonzini 140553018216SPaolo Bonzini return -1; 140653018216SPaolo Bonzini } 140753018216SPaolo Bonzini 140853018216SPaolo Bonzini int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) 140953018216SPaolo Bonzini { 141053018216SPaolo Bonzini ppc_dcrn_t *dcr; 141153018216SPaolo Bonzini 141253018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 141353018216SPaolo Bonzini goto error; 141453018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 141553018216SPaolo Bonzini if (dcr->dcr_write == NULL) 141653018216SPaolo Bonzini goto error; 1417de82dabeSCédric Le Goater trace_ppc_dcr_write(dcrn, val); 141853018216SPaolo Bonzini (*dcr->dcr_write)(dcr->opaque, dcrn, val); 141953018216SPaolo Bonzini 142053018216SPaolo Bonzini return 0; 142153018216SPaolo Bonzini 142253018216SPaolo Bonzini error: 142353018216SPaolo Bonzini if (dcr_env->write_error != NULL) 142453018216SPaolo Bonzini return (*dcr_env->write_error)(dcrn); 142553018216SPaolo Bonzini 142653018216SPaolo Bonzini return -1; 142753018216SPaolo Bonzini } 142853018216SPaolo Bonzini 142953018216SPaolo Bonzini int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, 143053018216SPaolo Bonzini dcr_read_cb dcr_read, dcr_write_cb dcr_write) 143153018216SPaolo Bonzini { 143253018216SPaolo Bonzini ppc_dcr_t *dcr_env; 143353018216SPaolo Bonzini ppc_dcrn_t *dcr; 143453018216SPaolo Bonzini 143553018216SPaolo Bonzini dcr_env = env->dcr_env; 143653018216SPaolo Bonzini if (dcr_env == NULL) 143753018216SPaolo Bonzini return -1; 143853018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 143953018216SPaolo Bonzini return -1; 144053018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 144153018216SPaolo Bonzini if (dcr->opaque != NULL || 144253018216SPaolo Bonzini dcr->dcr_read != NULL || 144353018216SPaolo Bonzini dcr->dcr_write != NULL) 144453018216SPaolo Bonzini return -1; 144553018216SPaolo Bonzini dcr->opaque = opaque; 144653018216SPaolo Bonzini dcr->dcr_read = dcr_read; 144753018216SPaolo Bonzini dcr->dcr_write = dcr_write; 144853018216SPaolo Bonzini 144953018216SPaolo Bonzini return 0; 145053018216SPaolo Bonzini } 145153018216SPaolo Bonzini 145253018216SPaolo Bonzini int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn), 145353018216SPaolo Bonzini int (*write_error)(int dcrn)) 145453018216SPaolo Bonzini { 145553018216SPaolo Bonzini ppc_dcr_t *dcr_env; 145653018216SPaolo Bonzini 1457b21e2380SMarkus Armbruster dcr_env = g_new0(ppc_dcr_t, 1); 145853018216SPaolo Bonzini dcr_env->read_error = read_error; 145953018216SPaolo Bonzini dcr_env->write_error = write_error; 146053018216SPaolo Bonzini env->dcr_env = dcr_env; 146153018216SPaolo Bonzini 146253018216SPaolo Bonzini return 0; 146353018216SPaolo Bonzini } 146453018216SPaolo Bonzini 146553018216SPaolo Bonzini /*****************************************************************************/ 1466051e2973SCédric Le Goater 14674a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu) 14684a89e204SCédric Le Goater { 14694a89e204SCédric Le Goater CPUPPCState *env = &cpu->env; 14704a89e204SCédric Le Goater return env->spr_cb[SPR_PIR].default_value; 14714a89e204SCédric Le Goater } 14724a89e204SCédric Le Goater 1473d24e80b2SNicholas Piggin int ppc_cpu_tir(PowerPCCPU *cpu) 1474d24e80b2SNicholas Piggin { 1475d24e80b2SNicholas Piggin CPUPPCState *env = &cpu->env; 1476d24e80b2SNicholas Piggin return env->spr_cb[SPR_TIR].default_value; 1477d24e80b2SNicholas Piggin } 1478d24e80b2SNicholas Piggin 1479051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir) 1480051e2973SCédric Le Goater { 1481051e2973SCédric Le Goater CPUState *cs; 1482051e2973SCédric Le Goater 1483051e2973SCédric Le Goater CPU_FOREACH(cs) { 1484051e2973SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 1485051e2973SCédric Le Goater 14864a89e204SCédric Le Goater if (ppc_cpu_pir(cpu) == pir) { 1487051e2973SCédric Le Goater return cpu; 1488051e2973SCédric Le Goater } 1489051e2973SCédric Le Goater } 1490051e2973SCédric Le Goater 1491051e2973SCédric Le Goater return NULL; 1492051e2973SCédric Le Goater } 149340177438SGreg Kurz 149440177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu) 149540177438SGreg Kurz { 149640177438SGreg Kurz CPUPPCState *env = &cpu->env; 149740177438SGreg Kurz 149840177438SGreg Kurz env->irq_input_state = 0; 149940177438SGreg Kurz kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); 150040177438SGreg Kurz } 1501