xref: /qemu/hw/ppc/ppc.c (revision c8fbc6b9)
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