xref: /openbmc/qemu/hw/ppc/ppc.c (revision 6b829602e2f10f301ff8508f3a6850a0e913142c)
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"
359db680f8SNicholas Piggin #include "sysemu/replay.h"
3654d31236SMarkus Armbruster #include "sysemu/runstate.h"
3753018216SPaolo Bonzini #include "kvm_ppc.h"
38d6454270SMarkus Armbruster #include "migration/vmstate.h"
3998a8b524SAlexey Kardashevskiy #include "trace.h"
4053018216SPaolo Bonzini 
4153018216SPaolo Bonzini static void cpu_ppc_tb_stop (CPUPPCState *env);
4253018216SPaolo Bonzini static void cpu_ppc_tb_start (CPUPPCState *env);
4353018216SPaolo Bonzini 
ppc_set_irq(PowerPCCPU * cpu,int irq,int level)44f003109fSMatheus Ferst void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
4553018216SPaolo Bonzini {
4653018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
478d04fb55SJan Kiszka     unsigned int old_pending;
488d04fb55SJan Kiszka 
498d04fb55SJan Kiszka     /* We may already have the BQL if coming from the reset path */
5032ead8e6SStefan Hajnoczi     BQL_LOCK_GUARD();
518d04fb55SJan Kiszka 
528d04fb55SJan Kiszka     old_pending = env->pending_interrupts;
5353018216SPaolo Bonzini 
5453018216SPaolo Bonzini     if (level) {
55f003109fSMatheus Ferst         env->pending_interrupts |= irq;
5653018216SPaolo Bonzini     } else {
57f003109fSMatheus Ferst         env->pending_interrupts &= ~irq;
5853018216SPaolo Bonzini     }
5953018216SPaolo Bonzini 
6053018216SPaolo Bonzini     if (old_pending != env->pending_interrupts) {
612fdedcbcSMatheus Ferst         ppc_maybe_interrupt(env);
6276d93e14Sjianchunfu         if (kvm_enabled()) {
63f003109fSMatheus Ferst             kvmppc_set_interrupt(cpu, irq, level);
6453018216SPaolo Bonzini         }
6576d93e14Sjianchunfu     }
6653018216SPaolo Bonzini 
67f003109fSMatheus Ferst     trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
68af96d2e6SCédric Le Goater                            CPU(cpu)->interrupt_request);
6953018216SPaolo Bonzini }
7053018216SPaolo Bonzini 
7153018216SPaolo Bonzini /* PowerPC 6xx / 7xx internal IRQ controller */
ppc6xx_set_irq(void * opaque,int pin,int level)7253018216SPaolo Bonzini static void ppc6xx_set_irq(void *opaque, int pin, int level)
7353018216SPaolo Bonzini {
7453018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
7553018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
7653018216SPaolo Bonzini     int cur_level;
7753018216SPaolo Bonzini 
78af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
79af96d2e6SCédric Le Goater 
8053018216SPaolo Bonzini     cur_level = (env->irq_input_state >> pin) & 1;
8153018216SPaolo Bonzini     /* Don't generate spurious events */
8253018216SPaolo Bonzini     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
83259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
84259186a7SAndreas Färber 
8553018216SPaolo Bonzini         switch (pin) {
8653018216SPaolo Bonzini         case PPC6xx_INPUT_TBEN:
8753018216SPaolo Bonzini             /* Level sensitive - active high */
88af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("time base", level);
8953018216SPaolo Bonzini             if (level) {
9053018216SPaolo Bonzini                 cpu_ppc_tb_start(env);
9153018216SPaolo Bonzini             } else {
9253018216SPaolo Bonzini                 cpu_ppc_tb_stop(env);
9353018216SPaolo Bonzini             }
94b2bd5b20SChen Qun             break;
9553018216SPaolo Bonzini         case PPC6xx_INPUT_INT:
9653018216SPaolo Bonzini             /* Level sensitive - active high */
97af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("external IRQ", level);
9853018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
9953018216SPaolo Bonzini             break;
10053018216SPaolo Bonzini         case PPC6xx_INPUT_SMI:
10153018216SPaolo Bonzini             /* Level sensitive - active high */
102af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("SMI IRQ", level);
10353018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level);
10453018216SPaolo Bonzini             break;
10553018216SPaolo Bonzini         case PPC6xx_INPUT_MCP:
10653018216SPaolo Bonzini             /* Negative edge sensitive */
10753018216SPaolo Bonzini             /* XXX: TODO: actual reaction may depends on HID0 status
10853018216SPaolo Bonzini              *            603/604/740/750: check HID0[EMCP]
10953018216SPaolo Bonzini              */
11053018216SPaolo Bonzini             if (cur_level == 1 && level == 0) {
111af96d2e6SCédric Le Goater                 trace_ppc_irq_set_state("machine check", 1);
11253018216SPaolo Bonzini                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
11353018216SPaolo Bonzini             }
11453018216SPaolo Bonzini             break;
11553018216SPaolo Bonzini         case PPC6xx_INPUT_CKSTP_IN:
11653018216SPaolo Bonzini             /* Level sensitive - active low */
11753018216SPaolo Bonzini             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
11853018216SPaolo Bonzini             /* XXX: Note that the only way to restart the CPU is to reset it */
11953018216SPaolo Bonzini             if (level) {
120af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("stop");
121259186a7SAndreas Färber                 cs->halted = 1;
12253018216SPaolo Bonzini             }
12353018216SPaolo Bonzini             break;
12453018216SPaolo Bonzini         case PPC6xx_INPUT_HRESET:
12553018216SPaolo Bonzini             /* Level sensitive - active low */
12653018216SPaolo Bonzini             if (level) {
127af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("CPU");
128c3affe56SAndreas Färber                 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
12953018216SPaolo Bonzini             }
13053018216SPaolo Bonzini             break;
13153018216SPaolo Bonzini         case PPC6xx_INPUT_SRESET:
132af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("RESET IRQ", level);
13353018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
13453018216SPaolo Bonzini             break;
13553018216SPaolo Bonzini         default:
1367279810bSCédric Le Goater             g_assert_not_reached();
13753018216SPaolo Bonzini         }
13853018216SPaolo Bonzini         if (level)
13953018216SPaolo Bonzini             env->irq_input_state |= 1 << pin;
14053018216SPaolo Bonzini         else
14153018216SPaolo Bonzini             env->irq_input_state &= ~(1 << pin);
14253018216SPaolo Bonzini     }
14353018216SPaolo Bonzini }
14453018216SPaolo Bonzini 
ppc6xx_irq_init(PowerPCCPU * cpu)145aa5a9e24SPaolo Bonzini void ppc6xx_irq_init(PowerPCCPU *cpu)
14653018216SPaolo Bonzini {
1470f3e0c6fSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppc6xx_set_irq, PPC6xx_INPUT_NB);
14853018216SPaolo Bonzini }
14953018216SPaolo Bonzini 
15053018216SPaolo Bonzini #if defined(TARGET_PPC64)
15153018216SPaolo Bonzini /* PowerPC 970 internal IRQ controller */
ppc970_set_irq(void * opaque,int pin,int level)15253018216SPaolo Bonzini static void ppc970_set_irq(void *opaque, int pin, int level)
15353018216SPaolo Bonzini {
15453018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
15553018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
15653018216SPaolo Bonzini     int cur_level;
15753018216SPaolo Bonzini 
158af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
159af96d2e6SCédric Le Goater 
16053018216SPaolo Bonzini     cur_level = (env->irq_input_state >> pin) & 1;
16153018216SPaolo Bonzini     /* Don't generate spurious events */
16253018216SPaolo Bonzini     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
163259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
164259186a7SAndreas Färber 
16553018216SPaolo Bonzini         switch (pin) {
16653018216SPaolo Bonzini         case PPC970_INPUT_INT:
16753018216SPaolo Bonzini             /* Level sensitive - active high */
168af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("external IRQ", level);
16953018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
17053018216SPaolo Bonzini             break;
17153018216SPaolo Bonzini         case PPC970_INPUT_THINT:
17253018216SPaolo Bonzini             /* Level sensitive - active high */
173af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("SMI IRQ", level);
17453018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level);
17553018216SPaolo Bonzini             break;
17653018216SPaolo Bonzini         case PPC970_INPUT_MCP:
17753018216SPaolo Bonzini             /* Negative edge sensitive */
17853018216SPaolo Bonzini             /* XXX: TODO: actual reaction may depends on HID0 status
17953018216SPaolo Bonzini              *            603/604/740/750: check HID0[EMCP]
18053018216SPaolo Bonzini              */
18153018216SPaolo Bonzini             if (cur_level == 1 && level == 0) {
182af96d2e6SCédric Le Goater                 trace_ppc_irq_set_state("machine check", 1);
18353018216SPaolo Bonzini                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
18453018216SPaolo Bonzini             }
18553018216SPaolo Bonzini             break;
18653018216SPaolo Bonzini         case PPC970_INPUT_CKSTP:
18753018216SPaolo Bonzini             /* Level sensitive - active low */
18853018216SPaolo Bonzini             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
18953018216SPaolo Bonzini             if (level) {
190af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("stop");
191259186a7SAndreas Färber                 cs->halted = 1;
19253018216SPaolo Bonzini             } else {
193af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("restart");
194259186a7SAndreas Färber                 cs->halted = 0;
195259186a7SAndreas Färber                 qemu_cpu_kick(cs);
19653018216SPaolo Bonzini             }
19753018216SPaolo Bonzini             break;
19853018216SPaolo Bonzini         case PPC970_INPUT_HRESET:
19953018216SPaolo Bonzini             /* Level sensitive - active low */
20053018216SPaolo Bonzini             if (level) {
201c3affe56SAndreas Färber                 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
20253018216SPaolo Bonzini             }
20353018216SPaolo Bonzini             break;
20453018216SPaolo Bonzini         case PPC970_INPUT_SRESET:
205af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("RESET IRQ", level);
20653018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
20753018216SPaolo Bonzini             break;
20853018216SPaolo Bonzini         case PPC970_INPUT_TBEN:
209af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("TBEN IRQ", level);
21053018216SPaolo Bonzini             /* XXX: TODO */
21153018216SPaolo Bonzini             break;
21253018216SPaolo Bonzini         default:
2137279810bSCédric Le Goater             g_assert_not_reached();
21453018216SPaolo Bonzini         }
21553018216SPaolo Bonzini         if (level)
21653018216SPaolo Bonzini             env->irq_input_state |= 1 << pin;
21753018216SPaolo Bonzini         else
21853018216SPaolo Bonzini             env->irq_input_state &= ~(1 << pin);
21953018216SPaolo Bonzini     }
22053018216SPaolo Bonzini }
22153018216SPaolo Bonzini 
ppc970_irq_init(PowerPCCPU * cpu)222aa5a9e24SPaolo Bonzini void ppc970_irq_init(PowerPCCPU *cpu)
22353018216SPaolo Bonzini {
2249fd0122eSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppc970_set_irq, PPC970_INPUT_NB);
22553018216SPaolo Bonzini }
22653018216SPaolo Bonzini 
22753018216SPaolo Bonzini /* POWER7 internal IRQ controller */
power7_set_irq(void * opaque,int pin,int level)22853018216SPaolo Bonzini static void power7_set_irq(void *opaque, int pin, int level)
22953018216SPaolo Bonzini {
23053018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
23153018216SPaolo Bonzini 
232af96d2e6SCédric Le Goater     trace_ppc_irq_set(&cpu->env, pin, level);
23353018216SPaolo Bonzini 
23453018216SPaolo Bonzini     switch (pin) {
23553018216SPaolo Bonzini     case POWER7_INPUT_INT:
23653018216SPaolo Bonzini         /* Level sensitive - active high */
237af96d2e6SCédric Le Goater         trace_ppc_irq_set_state("external IRQ", level);
23853018216SPaolo Bonzini         ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
23953018216SPaolo Bonzini         break;
24053018216SPaolo Bonzini     default:
2417279810bSCédric Le Goater         g_assert_not_reached();
24253018216SPaolo Bonzini     }
24353018216SPaolo Bonzini }
24453018216SPaolo Bonzini 
ppcPOWER7_irq_init(PowerPCCPU * cpu)245aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu)
24653018216SPaolo Bonzini {
2479fd0122eSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), power7_set_irq, POWER7_INPUT_NB);
24853018216SPaolo Bonzini }
24967afe775SBenjamin Herrenschmidt 
25067afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */
power9_set_irq(void * opaque,int pin,int level)25167afe775SBenjamin Herrenschmidt static void power9_set_irq(void *opaque, int pin, int level)
25267afe775SBenjamin Herrenschmidt {
25367afe775SBenjamin Herrenschmidt     PowerPCCPU *cpu = opaque;
25467afe775SBenjamin Herrenschmidt 
255af96d2e6SCédric Le Goater     trace_ppc_irq_set(&cpu->env, pin, level);
25667afe775SBenjamin Herrenschmidt 
25767afe775SBenjamin Herrenschmidt     switch (pin) {
25867afe775SBenjamin Herrenschmidt     case POWER9_INPUT_INT:
25967afe775SBenjamin Herrenschmidt         /* Level sensitive - active high */
260af96d2e6SCédric Le Goater         trace_ppc_irq_set_state("external IRQ", level);
26167afe775SBenjamin Herrenschmidt         ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
26267afe775SBenjamin Herrenschmidt         break;
26367afe775SBenjamin Herrenschmidt     case POWER9_INPUT_HINT:
26467afe775SBenjamin Herrenschmidt         /* Level sensitive - active high */
265af96d2e6SCédric Le Goater         trace_ppc_irq_set_state("HV external IRQ", level);
26667afe775SBenjamin Herrenschmidt         ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level);
26767afe775SBenjamin Herrenschmidt         break;
26867afe775SBenjamin Herrenschmidt     default:
2697279810bSCédric Le Goater         g_assert_not_reached();
27067afe775SBenjamin Herrenschmidt     }
27167afe775SBenjamin Herrenschmidt }
27267afe775SBenjamin Herrenschmidt 
ppcPOWER9_irq_init(PowerPCCPU * cpu)27367afe775SBenjamin Herrenschmidt void ppcPOWER9_irq_init(PowerPCCPU *cpu)
27467afe775SBenjamin Herrenschmidt {
2759fd0122eSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), power9_set_irq, POWER9_INPUT_NB);
27667afe775SBenjamin Herrenschmidt }
27753018216SPaolo Bonzini #endif /* defined(TARGET_PPC64) */
27853018216SPaolo Bonzini 
ppc40x_core_reset(PowerPCCPU * cpu)27952144b69SThomas Huth void ppc40x_core_reset(PowerPCCPU *cpu)
28052144b69SThomas Huth {
28152144b69SThomas Huth     CPUPPCState *env = &cpu->env;
28252144b69SThomas Huth     target_ulong dbsr;
28352144b69SThomas Huth 
28452144b69SThomas Huth     qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n");
28552144b69SThomas Huth     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
28652144b69SThomas Huth     dbsr = env->spr[SPR_40x_DBSR];
28752144b69SThomas Huth     dbsr &= ~0x00000300;
28852144b69SThomas Huth     dbsr |= 0x00000100;
28952144b69SThomas Huth     env->spr[SPR_40x_DBSR] = dbsr;
29052144b69SThomas Huth }
29152144b69SThomas Huth 
ppc40x_chip_reset(PowerPCCPU * cpu)29252144b69SThomas Huth void ppc40x_chip_reset(PowerPCCPU *cpu)
29352144b69SThomas Huth {
29452144b69SThomas Huth     CPUPPCState *env = &cpu->env;
29552144b69SThomas Huth     target_ulong dbsr;
29652144b69SThomas Huth 
29752144b69SThomas Huth     qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n");
29852144b69SThomas Huth     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
29952144b69SThomas Huth     /* XXX: TODO reset all internal peripherals */
30052144b69SThomas Huth     dbsr = env->spr[SPR_40x_DBSR];
30152144b69SThomas Huth     dbsr &= ~0x00000300;
30252144b69SThomas Huth     dbsr |= 0x00000200;
30352144b69SThomas Huth     env->spr[SPR_40x_DBSR] = dbsr;
30452144b69SThomas Huth }
30552144b69SThomas Huth 
ppc40x_system_reset(PowerPCCPU * cpu)30652144b69SThomas Huth void ppc40x_system_reset(PowerPCCPU *cpu)
30752144b69SThomas Huth {
30852144b69SThomas Huth     qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n");
30952144b69SThomas Huth     qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
31052144b69SThomas Huth }
31152144b69SThomas Huth 
store_40x_dbcr0(CPUPPCState * env,uint32_t val)31252144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val)
31352144b69SThomas Huth {
314db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
31552144b69SThomas Huth 
316195801d7SStefan Hajnoczi     bql_lock();
3175ae3d2e8SThomas Huth 
31852144b69SThomas Huth     switch ((val >> 28) & 0x3) {
31952144b69SThomas Huth     case 0x0:
32052144b69SThomas Huth         /* No action */
32152144b69SThomas Huth         break;
32252144b69SThomas Huth     case 0x1:
32352144b69SThomas Huth         /* Core reset */
32452144b69SThomas Huth         ppc40x_core_reset(cpu);
32552144b69SThomas Huth         break;
32652144b69SThomas Huth     case 0x2:
32752144b69SThomas Huth         /* Chip reset */
32852144b69SThomas Huth         ppc40x_chip_reset(cpu);
32952144b69SThomas Huth         break;
33052144b69SThomas Huth     case 0x3:
33152144b69SThomas Huth         /* System reset */
33252144b69SThomas Huth         ppc40x_system_reset(cpu);
33352144b69SThomas Huth         break;
33452144b69SThomas Huth     }
3355ae3d2e8SThomas Huth 
336195801d7SStefan Hajnoczi     bql_unlock();
33752144b69SThomas Huth }
33852144b69SThomas Huth 
33953018216SPaolo Bonzini /* PowerPC 40x internal IRQ controller */
ppc40x_set_irq(void * opaque,int pin,int level)34053018216SPaolo Bonzini static void ppc40x_set_irq(void *opaque, int pin, int level)
34153018216SPaolo Bonzini {
34253018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
34353018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
34453018216SPaolo Bonzini     int cur_level;
34553018216SPaolo Bonzini 
346af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
347af96d2e6SCédric Le Goater 
34853018216SPaolo Bonzini     cur_level = (env->irq_input_state >> pin) & 1;
34953018216SPaolo Bonzini     /* Don't generate spurious events */
35053018216SPaolo Bonzini     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
351259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
352259186a7SAndreas Färber 
35353018216SPaolo Bonzini         switch (pin) {
35453018216SPaolo Bonzini         case PPC40x_INPUT_RESET_SYS:
35553018216SPaolo Bonzini             if (level) {
356af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("system");
35753018216SPaolo Bonzini                 ppc40x_system_reset(cpu);
35853018216SPaolo Bonzini             }
35953018216SPaolo Bonzini             break;
36053018216SPaolo Bonzini         case PPC40x_INPUT_RESET_CHIP:
36153018216SPaolo Bonzini             if (level) {
362af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("chip");
36353018216SPaolo Bonzini                 ppc40x_chip_reset(cpu);
36453018216SPaolo Bonzini             }
36553018216SPaolo Bonzini             break;
36653018216SPaolo Bonzini         case PPC40x_INPUT_RESET_CORE:
36753018216SPaolo Bonzini             /* XXX: TODO: update DBSR[MRR] */
36853018216SPaolo Bonzini             if (level) {
369af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("core");
37053018216SPaolo Bonzini                 ppc40x_core_reset(cpu);
37153018216SPaolo Bonzini             }
37253018216SPaolo Bonzini             break;
37353018216SPaolo Bonzini         case PPC40x_INPUT_CINT:
37453018216SPaolo Bonzini             /* Level sensitive - active high */
375af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("critical IRQ", level);
37653018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
37753018216SPaolo Bonzini             break;
37853018216SPaolo Bonzini         case PPC40x_INPUT_INT:
37953018216SPaolo Bonzini             /* Level sensitive - active high */
380af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("external IRQ", level);
38153018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
38253018216SPaolo Bonzini             break;
38353018216SPaolo Bonzini         case PPC40x_INPUT_HALT:
38453018216SPaolo Bonzini             /* Level sensitive - active low */
38553018216SPaolo Bonzini             if (level) {
386af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("stop");
387259186a7SAndreas Färber                 cs->halted = 1;
38853018216SPaolo Bonzini             } else {
389af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("restart");
390259186a7SAndreas Färber                 cs->halted = 0;
391259186a7SAndreas Färber                 qemu_cpu_kick(cs);
39253018216SPaolo Bonzini             }
39353018216SPaolo Bonzini             break;
39453018216SPaolo Bonzini         case PPC40x_INPUT_DEBUG:
39553018216SPaolo Bonzini             /* Level sensitive - active high */
396af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("debug pin", level);
39753018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
39853018216SPaolo Bonzini             break;
39953018216SPaolo Bonzini         default:
4007279810bSCédric Le Goater             g_assert_not_reached();
40153018216SPaolo Bonzini         }
40253018216SPaolo Bonzini         if (level)
40353018216SPaolo Bonzini             env->irq_input_state |= 1 << pin;
40453018216SPaolo Bonzini         else
40553018216SPaolo Bonzini             env->irq_input_state &= ~(1 << pin);
40653018216SPaolo Bonzini     }
40753018216SPaolo Bonzini }
40853018216SPaolo Bonzini 
ppc40x_irq_init(PowerPCCPU * cpu)409aa5a9e24SPaolo Bonzini void ppc40x_irq_init(PowerPCCPU *cpu)
41053018216SPaolo Bonzini {
41147b60fc6SCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppc40x_set_irq, PPC40x_INPUT_NB);
41253018216SPaolo Bonzini }
41353018216SPaolo Bonzini 
41453018216SPaolo Bonzini /* PowerPC E500 internal IRQ controller */
ppce500_set_irq(void * opaque,int pin,int level)41553018216SPaolo Bonzini static void ppce500_set_irq(void *opaque, int pin, int level)
41653018216SPaolo Bonzini {
41753018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
41853018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
41953018216SPaolo Bonzini     int cur_level;
42053018216SPaolo Bonzini 
421af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
422af96d2e6SCédric Le Goater 
42353018216SPaolo Bonzini     cur_level = (env->irq_input_state >> pin) & 1;
42453018216SPaolo Bonzini     /* Don't generate spurious events */
42553018216SPaolo Bonzini     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
42653018216SPaolo Bonzini         switch (pin) {
42753018216SPaolo Bonzini         case PPCE500_INPUT_MCK:
42853018216SPaolo Bonzini             if (level) {
429af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("system");
430cf83f140SEric Blake                 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
43153018216SPaolo Bonzini             }
43253018216SPaolo Bonzini             break;
43353018216SPaolo Bonzini         case PPCE500_INPUT_RESET_CORE:
43453018216SPaolo Bonzini             if (level) {
435af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("core");
43653018216SPaolo Bonzini                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level);
43753018216SPaolo Bonzini             }
43853018216SPaolo Bonzini             break;
43953018216SPaolo Bonzini         case PPCE500_INPUT_CINT:
44053018216SPaolo Bonzini             /* Level sensitive - active high */
441af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("critical IRQ", level);
44253018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
44353018216SPaolo Bonzini             break;
44453018216SPaolo Bonzini         case PPCE500_INPUT_INT:
44553018216SPaolo Bonzini             /* Level sensitive - active high */
446af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("core IRQ", level);
44753018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
44853018216SPaolo Bonzini             break;
44953018216SPaolo Bonzini         case PPCE500_INPUT_DEBUG:
45053018216SPaolo Bonzini             /* Level sensitive - active high */
451af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("debug pin", level);
45253018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
45353018216SPaolo Bonzini             break;
45453018216SPaolo Bonzini         default:
4557279810bSCédric Le Goater             g_assert_not_reached();
45653018216SPaolo Bonzini         }
45753018216SPaolo Bonzini         if (level)
45853018216SPaolo Bonzini             env->irq_input_state |= 1 << pin;
45953018216SPaolo Bonzini         else
46053018216SPaolo Bonzini             env->irq_input_state &= ~(1 << pin);
46153018216SPaolo Bonzini     }
46253018216SPaolo Bonzini }
46353018216SPaolo Bonzini 
ppce500_irq_init(PowerPCCPU * cpu)464aa5a9e24SPaolo Bonzini void ppce500_irq_init(PowerPCCPU *cpu)
46553018216SPaolo Bonzini {
4665e66cd0cSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppce500_set_irq, PPCE500_INPUT_NB);
46753018216SPaolo Bonzini }
46853018216SPaolo Bonzini 
46953018216SPaolo Bonzini /* Enable or Disable the E500 EPR capability */
ppce500_set_mpic_proxy(bool enabled)47053018216SPaolo Bonzini void ppce500_set_mpic_proxy(bool enabled)
47153018216SPaolo Bonzini {
472182735efSAndreas Färber     CPUState *cs;
47353018216SPaolo Bonzini 
474bdc44640SAndreas Färber     CPU_FOREACH(cs) {
475182735efSAndreas Färber         PowerPCCPU *cpu = POWERPC_CPU(cs);
47653018216SPaolo Bonzini 
477182735efSAndreas Färber         cpu->env.mpic_proxy = enabled;
47853018216SPaolo Bonzini         if (kvm_enabled()) {
479182735efSAndreas Färber             kvmppc_set_mpic_proxy(cpu, enabled);
48053018216SPaolo Bonzini         }
48153018216SPaolo Bonzini     }
48253018216SPaolo Bonzini }
48353018216SPaolo Bonzini 
48453018216SPaolo Bonzini /*****************************************************************************/
48553018216SPaolo Bonzini /* PowerPC time base and decrementer emulation */
48653018216SPaolo Bonzini 
487eab08884SNicholas Piggin /*
488eab08884SNicholas Piggin  * Conversion between QEMU_CLOCK_VIRTUAL ns and timebase (TB) ticks:
489eab08884SNicholas Piggin  * TB ticks are arrived at by multiplying tb_freq then dividing by
490eab08884SNicholas Piggin  * ns per second, and rounding down. TB ticks drive all clocks and
491eab08884SNicholas Piggin  * timers in the target machine.
492eab08884SNicholas Piggin  *
493eab08884SNicholas Piggin  * Converting TB intervals to ns for the purpose of setting a
494eab08884SNicholas Piggin  * QEMU_CLOCK_VIRTUAL timer should go the other way, but rounding
495eab08884SNicholas Piggin  * up. Rounding down could cause the timer to fire before the TB
496eab08884SNicholas Piggin  * value has been reached.
497eab08884SNicholas Piggin  */
ns_to_tb(uint32_t freq,int64_t clock)4987798f5c5SNicholas Piggin static uint64_t ns_to_tb(uint32_t freq, int64_t clock)
4997798f5c5SNicholas Piggin {
5007798f5c5SNicholas Piggin     return muldiv64(clock, freq, NANOSECONDS_PER_SECOND);
5017798f5c5SNicholas Piggin }
5027798f5c5SNicholas Piggin 
503eab08884SNicholas Piggin /* virtual clock in TB ticks, not adjusted by TB offset */
tb_to_ns_round_up(uint32_t freq,uint64_t tb)504eab08884SNicholas Piggin static int64_t tb_to_ns_round_up(uint32_t freq, uint64_t tb)
5057798f5c5SNicholas Piggin {
506eab08884SNicholas Piggin     return muldiv64_round_up(tb, NANOSECONDS_PER_SECOND, freq);
5077798f5c5SNicholas Piggin }
5087798f5c5SNicholas Piggin 
cpu_ppc_get_tb(ppc_tb_t * tb_env,uint64_t vmclk,int64_t tb_offset)50953018216SPaolo Bonzini uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
51053018216SPaolo Bonzini {
51153018216SPaolo Bonzini     /* TB time in tb periods */
5127798f5c5SNicholas Piggin     return ns_to_tb(tb_env->tb_freq, vmclk) + tb_offset;
51353018216SPaolo Bonzini }
51453018216SPaolo Bonzini 
cpu_ppc_load_tbl(CPUPPCState * env)51553018216SPaolo Bonzini uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
51653018216SPaolo Bonzini {
51753018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
51853018216SPaolo Bonzini     uint64_t tb;
51953018216SPaolo Bonzini 
52053018216SPaolo Bonzini     if (kvm_enabled()) {
52153018216SPaolo Bonzini         return env->spr[SPR_TBL];
52253018216SPaolo Bonzini     }
52353018216SPaolo Bonzini 
524eaf832fcSNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
525eaf832fcSNicholas Piggin                         tb_env->tb_offset);
526af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
52753018216SPaolo Bonzini 
52853018216SPaolo Bonzini     return tb;
52953018216SPaolo Bonzini }
53053018216SPaolo Bonzini 
_cpu_ppc_load_tbu(CPUPPCState * env)53153018216SPaolo Bonzini static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env)
53253018216SPaolo Bonzini {
53353018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
53453018216SPaolo Bonzini     uint64_t tb;
53553018216SPaolo Bonzini 
536eaf832fcSNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
537eaf832fcSNicholas Piggin                         tb_env->tb_offset);
538af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
53953018216SPaolo Bonzini 
54053018216SPaolo Bonzini     return tb >> 32;
54153018216SPaolo Bonzini }
54253018216SPaolo Bonzini 
cpu_ppc_load_tbu(CPUPPCState * env)54353018216SPaolo Bonzini uint32_t cpu_ppc_load_tbu (CPUPPCState *env)
54453018216SPaolo Bonzini {
54553018216SPaolo Bonzini     if (kvm_enabled()) {
54653018216SPaolo Bonzini         return env->spr[SPR_TBU];
54753018216SPaolo Bonzini     }
54853018216SPaolo Bonzini 
54953018216SPaolo Bonzini     return _cpu_ppc_load_tbu(env);
55053018216SPaolo Bonzini }
55153018216SPaolo Bonzini 
cpu_ppc_store_tb(ppc_tb_t * tb_env,uint64_t vmclk,int64_t * tb_offsetp,uint64_t value)55253018216SPaolo Bonzini static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
55353018216SPaolo Bonzini                                     int64_t *tb_offsetp, uint64_t value)
55453018216SPaolo Bonzini {
5557798f5c5SNicholas Piggin     *tb_offsetp = value - ns_to_tb(tb_env->tb_freq, vmclk);
55673bcb24dSRutuja Shah 
557af96d2e6SCédric Le Goater     trace_ppc_tb_store(value, *tb_offsetp);
55853018216SPaolo Bonzini }
55953018216SPaolo Bonzini 
cpu_ppc_store_tbl(CPUPPCState * env,uint32_t value)56053018216SPaolo Bonzini void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value)
56153018216SPaolo Bonzini {
56253018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
5632ad2e113SNicholas Piggin     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
56453018216SPaolo Bonzini     uint64_t tb;
56553018216SPaolo Bonzini 
5662ad2e113SNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset);
56753018216SPaolo Bonzini     tb &= 0xFFFFFFFF00000000ULL;
5682ad2e113SNicholas Piggin     cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb | (uint64_t)value);
56953018216SPaolo Bonzini }
57053018216SPaolo Bonzini 
_cpu_ppc_store_tbu(CPUPPCState * env,uint32_t value)57153018216SPaolo Bonzini static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value)
57253018216SPaolo Bonzini {
57353018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
5742ad2e113SNicholas Piggin     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
57553018216SPaolo Bonzini     uint64_t tb;
57653018216SPaolo Bonzini 
5772ad2e113SNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset);
57853018216SPaolo Bonzini     tb &= 0x00000000FFFFFFFFULL;
5792ad2e113SNicholas Piggin     cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset,
5802ad2e113SNicholas Piggin                      ((uint64_t)value << 32) | tb);
58153018216SPaolo Bonzini }
58253018216SPaolo Bonzini 
cpu_ppc_store_tbu(CPUPPCState * env,uint32_t value)58353018216SPaolo Bonzini void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value)
58453018216SPaolo Bonzini {
58553018216SPaolo Bonzini     _cpu_ppc_store_tbu(env, value);
58653018216SPaolo Bonzini }
58753018216SPaolo Bonzini 
cpu_ppc_load_atbl(CPUPPCState * env)58853018216SPaolo Bonzini uint64_t cpu_ppc_load_atbl (CPUPPCState *env)
58953018216SPaolo Bonzini {
59053018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
59153018216SPaolo Bonzini     uint64_t tb;
59253018216SPaolo Bonzini 
593eaf832fcSNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
594eaf832fcSNicholas Piggin                         tb_env->atb_offset);
595af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
59653018216SPaolo Bonzini 
59753018216SPaolo Bonzini     return tb;
59853018216SPaolo Bonzini }
59953018216SPaolo Bonzini 
cpu_ppc_load_atbu(CPUPPCState * env)60053018216SPaolo Bonzini uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
60153018216SPaolo Bonzini {
60253018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
60353018216SPaolo Bonzini     uint64_t tb;
60453018216SPaolo Bonzini 
605eaf832fcSNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
606eaf832fcSNicholas Piggin                         tb_env->atb_offset);
607af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
60853018216SPaolo Bonzini 
60953018216SPaolo Bonzini     return tb >> 32;
61053018216SPaolo Bonzini }
61153018216SPaolo Bonzini 
cpu_ppc_store_atbl(CPUPPCState * env,uint32_t value)61253018216SPaolo Bonzini void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value)
61353018216SPaolo Bonzini {
61453018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
6152ad2e113SNicholas Piggin     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
61653018216SPaolo Bonzini     uint64_t tb;
61753018216SPaolo Bonzini 
6182ad2e113SNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset);
61953018216SPaolo Bonzini     tb &= 0xFFFFFFFF00000000ULL;
6202ad2e113SNicholas Piggin     cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset, tb | (uint64_t)value);
62153018216SPaolo Bonzini }
62253018216SPaolo Bonzini 
cpu_ppc_store_atbu(CPUPPCState * env,uint32_t value)62353018216SPaolo Bonzini void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
62453018216SPaolo Bonzini {
62553018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
6262ad2e113SNicholas Piggin     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
62753018216SPaolo Bonzini     uint64_t tb;
62853018216SPaolo Bonzini 
6292ad2e113SNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset);
63053018216SPaolo Bonzini     tb &= 0x00000000FFFFFFFFULL;
6312ad2e113SNicholas Piggin     cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset,
6322ad2e113SNicholas Piggin                      ((uint64_t)value << 32) | tb);
63353018216SPaolo Bonzini }
63453018216SPaolo Bonzini 
cpu_ppc_increase_tb_by_offset(CPUPPCState * env,int64_t offset)63549771107SHarsh Prateek Bora void cpu_ppc_increase_tb_by_offset(CPUPPCState *env, int64_t offset)
63649771107SHarsh Prateek Bora {
63749771107SHarsh Prateek Bora     env->tb_env->tb_offset += offset;
63849771107SHarsh Prateek Bora }
63949771107SHarsh Prateek Bora 
cpu_ppc_decrease_tb_by_offset(CPUPPCState * env,int64_t offset)64049771107SHarsh Prateek Bora void cpu_ppc_decrease_tb_by_offset(CPUPPCState *env, int64_t offset)
64149771107SHarsh Prateek Bora {
64249771107SHarsh Prateek Bora     env->tb_env->tb_offset -= offset;
64349771107SHarsh Prateek Bora }
64449771107SHarsh Prateek Bora 
cpu_ppc_load_vtb(CPUPPCState * env)6455d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env)
6465d62725bSSuraj Jitindar Singh {
6475d62725bSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
6485d62725bSSuraj Jitindar Singh 
6495d62725bSSuraj Jitindar Singh     return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
6505d62725bSSuraj Jitindar Singh                           tb_env->vtb_offset);
6515d62725bSSuraj Jitindar Singh }
6525d62725bSSuraj Jitindar Singh 
cpu_ppc_store_vtb(CPUPPCState * env,uint64_t value)6535d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value)
6545d62725bSSuraj Jitindar Singh {
6555d62725bSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
6565d62725bSSuraj Jitindar Singh 
6575d62725bSSuraj Jitindar Singh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
6585d62725bSSuraj Jitindar Singh                      &tb_env->vtb_offset, value);
6595d62725bSSuraj Jitindar Singh }
6605d62725bSSuraj Jitindar Singh 
cpu_ppc_store_tbu40(CPUPPCState * env,uint64_t value)661f0ec31b1SSuraj Jitindar Singh void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value)
662f0ec31b1SSuraj Jitindar Singh {
663f0ec31b1SSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
6642ad2e113SNicholas Piggin     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
665f0ec31b1SSuraj Jitindar Singh     uint64_t tb;
666f0ec31b1SSuraj Jitindar Singh 
6672ad2e113SNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset);
668f0ec31b1SSuraj Jitindar Singh     tb &= 0xFFFFFFUL;
669f0ec31b1SSuraj Jitindar Singh     tb |= (value & ~0xFFFFFFUL);
6702ad2e113SNicholas Piggin     cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb);
671f0ec31b1SSuraj Jitindar Singh }
672f0ec31b1SSuraj Jitindar Singh 
cpu_ppc_tb_stop(CPUPPCState * env)67353018216SPaolo Bonzini static void cpu_ppc_tb_stop (CPUPPCState *env)
67453018216SPaolo Bonzini {
67553018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
67653018216SPaolo Bonzini     uint64_t tb, atb, vmclk;
67753018216SPaolo Bonzini 
67853018216SPaolo Bonzini     /* If the time base is already frozen, do nothing */
67953018216SPaolo Bonzini     if (tb_env->tb_freq != 0) {
680bc72ad67SAlex Bligh         vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
68153018216SPaolo Bonzini         /* Get the time base */
68253018216SPaolo Bonzini         tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
68353018216SPaolo Bonzini         /* Get the alternate time base */
68453018216SPaolo Bonzini         atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
68553018216SPaolo Bonzini         /* Store the time base value (ie compute the current offset) */
68653018216SPaolo Bonzini         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
68753018216SPaolo Bonzini         /* Store the alternate time base value (compute the current offset) */
68853018216SPaolo Bonzini         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
68953018216SPaolo Bonzini         /* Set the time base frequency to zero */
69053018216SPaolo Bonzini         tb_env->tb_freq = 0;
69153018216SPaolo Bonzini         /* Now, the time bases are frozen to tb_offset / atb_offset value */
69253018216SPaolo Bonzini     }
69353018216SPaolo Bonzini }
69453018216SPaolo Bonzini 
cpu_ppc_tb_start(CPUPPCState * env)69553018216SPaolo Bonzini static void cpu_ppc_tb_start (CPUPPCState *env)
69653018216SPaolo Bonzini {
69753018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
69853018216SPaolo Bonzini     uint64_t tb, atb, vmclk;
69953018216SPaolo Bonzini 
70053018216SPaolo Bonzini     /* If the time base is not frozen, do nothing */
70153018216SPaolo Bonzini     if (tb_env->tb_freq == 0) {
702bc72ad67SAlex Bligh         vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
70353018216SPaolo Bonzini         /* Get the time base from tb_offset */
70453018216SPaolo Bonzini         tb = tb_env->tb_offset;
70553018216SPaolo Bonzini         /* Get the alternate time base from atb_offset */
70653018216SPaolo Bonzini         atb = tb_env->atb_offset;
70753018216SPaolo Bonzini         /* Restore the tb frequency from the decrementer frequency */
70853018216SPaolo Bonzini         tb_env->tb_freq = tb_env->decr_freq;
70953018216SPaolo Bonzini         /* Store the time base value */
71053018216SPaolo Bonzini         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
71153018216SPaolo Bonzini         /* Store the alternate time base value */
71253018216SPaolo Bonzini         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
71353018216SPaolo Bonzini     }
71453018216SPaolo Bonzini }
71553018216SPaolo Bonzini 
ppc_decr_clear_on_delivery(CPUPPCState * env)716e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env)
717e81a982aSAlexander Graf {
718e81a982aSAlexander Graf     ppc_tb_t *tb_env = env->tb_env;
719e81a982aSAlexander Graf     int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL;
720e81a982aSAlexander Graf     return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
721e81a982aSAlexander Graf }
722e81a982aSAlexander Graf 
__cpu_ppc_load_decr(CPUPPCState * env,int64_t now,uint64_t next)723ea62f8a5SNicholas Piggin static inline int64_t __cpu_ppc_load_decr(CPUPPCState *env, int64_t now,
724ea62f8a5SNicholas Piggin                                           uint64_t next)
72553018216SPaolo Bonzini {
72653018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
727ea62f8a5SNicholas Piggin     uint64_t n;
7288e0a5ac8SNicholas Piggin     int64_t decr;
72953018216SPaolo Bonzini 
7308e0a5ac8SNicholas Piggin     n = ns_to_tb(tb_env->decr_freq, now);
731*f10827a8SClément Chigot 
732*f10827a8SClément Chigot     /* BookE timers stop when reaching 0.  */
733*f10827a8SClément Chigot     if (next < n && tb_env->flags & PPC_TIMER_BOOKE) {
73453018216SPaolo Bonzini         decr = 0;
73553018216SPaolo Bonzini     } else {
7368e0a5ac8SNicholas Piggin         decr = next - n;
73753018216SPaolo Bonzini     }
7388e0a5ac8SNicholas Piggin 
739af96d2e6SCédric Le Goater     trace_ppc_decr_load(decr);
74053018216SPaolo Bonzini 
74153018216SPaolo Bonzini     return decr;
74253018216SPaolo Bonzini }
74353018216SPaolo Bonzini 
_cpu_ppc_load_decr(CPUPPCState * env,int64_t now)744ea62f8a5SNicholas Piggin static target_ulong _cpu_ppc_load_decr(CPUPPCState *env, int64_t now)
74553018216SPaolo Bonzini {
74653018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
747a8dafa52SSuraj Jitindar Singh     uint64_t decr;
74853018216SPaolo Bonzini 
749ea62f8a5SNicholas Piggin     decr = __cpu_ppc_load_decr(env, now, tb_env->decr_next);
750a8dafa52SSuraj Jitindar Singh 
751a8dafa52SSuraj Jitindar Singh     /*
752e6a19a64SMichael Tokarev      * If large decrementer is enabled then the decrementer is signed extended
753a8dafa52SSuraj Jitindar Singh      * to 64 bits, otherwise it is a 32 bit value.
754a8dafa52SSuraj Jitindar Singh      */
755a8dafa52SSuraj Jitindar Singh     if (env->spr[SPR_LPCR] & LPCR_LD) {
756c8fbc6b9SNicholas Piggin         PowerPCCPU *cpu = env_archcpu(env);
757c8fbc6b9SNicholas Piggin         PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
758c8fbc6b9SNicholas Piggin         return sextract64(decr, 0, pcc->lrg_decr_bits);
759a8dafa52SSuraj Jitindar Singh     }
760a8dafa52SSuraj Jitindar Singh     return (uint32_t) decr;
76153018216SPaolo Bonzini }
76253018216SPaolo Bonzini 
cpu_ppc_load_decr(CPUPPCState * env)763ea62f8a5SNicholas Piggin target_ulong cpu_ppc_load_decr(CPUPPCState *env)
764ea62f8a5SNicholas Piggin {
765ea62f8a5SNicholas Piggin     if (kvm_enabled()) {
766ea62f8a5SNicholas Piggin         return env->spr[SPR_DECR];
767ea62f8a5SNicholas Piggin     } else {
768ea62f8a5SNicholas Piggin         return _cpu_ppc_load_decr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
769ea62f8a5SNicholas Piggin     }
770ea62f8a5SNicholas Piggin }
771ea62f8a5SNicholas Piggin 
_cpu_ppc_load_hdecr(CPUPPCState * env,int64_t now)772ea62f8a5SNicholas Piggin static target_ulong _cpu_ppc_load_hdecr(CPUPPCState *env, int64_t now)
77353018216SPaolo Bonzini {
774db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
775a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
77653018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
777a8dafa52SSuraj Jitindar Singh     uint64_t hdecr;
77853018216SPaolo Bonzini 
779ea62f8a5SNicholas Piggin     hdecr =  __cpu_ppc_load_decr(env, now, tb_env->hdecr_next);
780a8dafa52SSuraj Jitindar Singh 
781a8dafa52SSuraj Jitindar Singh     /*
782a8dafa52SSuraj Jitindar Singh      * If we have a large decrementer (POWER9 or later) then hdecr is sign
783a8dafa52SSuraj Jitindar Singh      * extended to 64 bits, otherwise it is 32 bits.
784a8dafa52SSuraj Jitindar Singh      */
785a8dafa52SSuraj Jitindar Singh     if (pcc->lrg_decr_bits > 32) {
786c8fbc6b9SNicholas Piggin         return sextract64(hdecr, 0, pcc->lrg_decr_bits);
787a8dafa52SSuraj Jitindar Singh     }
788a8dafa52SSuraj Jitindar Singh     return (uint32_t) hdecr;
78953018216SPaolo Bonzini }
79053018216SPaolo Bonzini 
cpu_ppc_load_hdecr(CPUPPCState * env)791ea62f8a5SNicholas Piggin target_ulong cpu_ppc_load_hdecr(CPUPPCState *env)
792ea62f8a5SNicholas Piggin {
793ea62f8a5SNicholas Piggin     return _cpu_ppc_load_hdecr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
794ea62f8a5SNicholas Piggin }
795ea62f8a5SNicholas Piggin 
cpu_ppc_load_purr(CPUPPCState * env)79653018216SPaolo Bonzini uint64_t cpu_ppc_load_purr (CPUPPCState *env)
79753018216SPaolo Bonzini {
79853018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
79953018216SPaolo Bonzini 
8005cc7e69fSSuraj Jitindar Singh     return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
8015cc7e69fSSuraj Jitindar Singh                           tb_env->purr_offset);
80253018216SPaolo Bonzini }
80353018216SPaolo Bonzini 
80453018216SPaolo Bonzini /* When decrementer expires,
80553018216SPaolo Bonzini  * all we need to do is generate or queue a CPU exception
80653018216SPaolo Bonzini  */
cpu_ppc_decr_excp(PowerPCCPU * cpu)80753018216SPaolo Bonzini static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
80853018216SPaolo Bonzini {
80953018216SPaolo Bonzini     /* Raise it */
810af96d2e6SCédric Le Goater     trace_ppc_decr_excp("raise");
81153018216SPaolo Bonzini     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
81253018216SPaolo Bonzini }
81353018216SPaolo Bonzini 
cpu_ppc_decr_lower(PowerPCCPU * cpu)814e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu)
815e81a982aSAlexander Graf {
816e81a982aSAlexander Graf     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
817e81a982aSAlexander Graf }
818e81a982aSAlexander Graf 
cpu_ppc_hdecr_excp(PowerPCCPU * cpu)81953018216SPaolo Bonzini static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
82053018216SPaolo Bonzini {
8214b236b62SBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
8224b236b62SBenjamin Herrenschmidt 
82353018216SPaolo Bonzini     /* Raise it */
824af96d2e6SCédric Le Goater     trace_ppc_decr_excp("raise HV");
8254b236b62SBenjamin Herrenschmidt 
8264b236b62SBenjamin Herrenschmidt     /* The architecture specifies that we don't deliver HDEC
8274b236b62SBenjamin Herrenschmidt      * interrupts in a PM state. Not only they don't cause a
8284b236b62SBenjamin Herrenschmidt      * wakeup but they also get effectively discarded.
8294b236b62SBenjamin Herrenschmidt      */
8301e7fd61dSBenjamin Herrenschmidt     if (!env->resume_as_sreset) {
83153018216SPaolo Bonzini         ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
83253018216SPaolo Bonzini     }
8334b236b62SBenjamin Herrenschmidt }
83453018216SPaolo Bonzini 
cpu_ppc_hdecr_lower(PowerPCCPU * cpu)835e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
836e81a982aSAlexander Graf {
837e81a982aSAlexander Graf     ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
838e81a982aSAlexander Graf }
839e81a982aSAlexander Graf 
__cpu_ppc_store_decr(PowerPCCPU * cpu,int64_t now,uint64_t * nextp,QEMUTimer * timer,void (* raise_excp)(void *),void (* lower_excp)(PowerPCCPU *),uint32_t flags,target_ulong decr,target_ulong value,int nr_bits)840ea62f8a5SNicholas Piggin static void __cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now, uint64_t *nextp,
8411246b259SStefan Weil                                  QEMUTimer *timer,
842e81a982aSAlexander Graf                                  void (*raise_excp)(void *),
843e81a982aSAlexander Graf                                  void (*lower_excp)(PowerPCCPU *),
844a5ff7875SNicholas Piggin                                  uint32_t flags, target_ulong decr,
845a5ff7875SNicholas Piggin                                  target_ulong value, int nr_bits)
84653018216SPaolo Bonzini {
84753018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
84853018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
849ea62f8a5SNicholas Piggin     uint64_t next;
8504d9b8ef9SCédric Le Goater     int64_t signed_value;
8514d9b8ef9SCédric Le Goater     int64_t signed_decr;
85253018216SPaolo Bonzini 
853a8dafa52SSuraj Jitindar Singh     /* Truncate value to decr_width and sign extend for simplicity */
85409d2db9fSNicholas Piggin     value = extract64(value, 0, nr_bits);
85509d2db9fSNicholas Piggin     decr = extract64(decr, 0, nr_bits);
8564d9b8ef9SCédric Le Goater     signed_value = sextract64(value, 0, nr_bits);
8574d9b8ef9SCédric Le Goater     signed_decr = sextract64(decr, 0, nr_bits);
858a8dafa52SSuraj Jitindar Singh 
859af96d2e6SCédric Le Goater     trace_ppc_decr_store(nr_bits, decr, value);
86053018216SPaolo Bonzini 
861e81a982aSAlexander Graf     /*
862febb71d5SNicholas Piggin      * Calculate the next decrementer event and set a timer.
863febb71d5SNicholas Piggin      * decr_next is in timebase units to keep rounding simple. Note it is
864febb71d5SNicholas Piggin      * not adjusted by tb_offset because if TB changes via tb_offset changing,
865febb71d5SNicholas Piggin      * decrementer does not change, so not directly comparable with TB.
866febb71d5SNicholas Piggin      */
867febb71d5SNicholas Piggin     next = ns_to_tb(tb_env->decr_freq, now) + value;
868febb71d5SNicholas Piggin     *nextp = next; /* nextp is in timebase units */
869febb71d5SNicholas Piggin 
870febb71d5SNicholas Piggin     /*
87117dd1354SNicholas Piggin      * Going from 1 -> 0 or 0 -> -1 is the event to generate a DEC interrupt.
872e81a982aSAlexander Graf      *
873e81a982aSAlexander Graf      * On MSB level based DEC implementations the MSB always means the interrupt
874e81a982aSAlexander Graf      * is pending, so raise it on those.
875e81a982aSAlexander Graf      *
876e81a982aSAlexander Graf      * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
877e81a982aSAlexander Graf      * an edge interrupt, so raise it here too.
878e81a982aSAlexander Graf      */
879a5ff7875SNicholas Piggin     if (((flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) ||
880a5ff7875SNicholas Piggin         ((flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0
8814d9b8ef9SCédric Le Goater           && signed_decr >= 0)) {
882e81a982aSAlexander Graf         (*raise_excp)(cpu);
883e81a982aSAlexander Graf         return;
884e81a982aSAlexander Graf     }
885e81a982aSAlexander Graf 
886e81a982aSAlexander Graf     /* On MSB level based systems a 0 for the MSB stops interrupt delivery */
887a5ff7875SNicholas Piggin     if (signed_value >= 0 && (flags & PPC_DECR_UNDERFLOW_LEVEL)) {
888e81a982aSAlexander Graf         (*lower_excp)(cpu);
889e81a982aSAlexander Graf     }
890e81a982aSAlexander Graf 
89153018216SPaolo Bonzini     /* Adjust timer */
8928e0a5ac8SNicholas Piggin     timer_mod(timer, tb_to_ns_round_up(tb_env->decr_freq, next));
89353018216SPaolo Bonzini }
89453018216SPaolo Bonzini 
_cpu_ppc_store_decr(PowerPCCPU * cpu,int64_t now,target_ulong decr,target_ulong value,int nr_bits)895ea62f8a5SNicholas Piggin static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now,
896ea62f8a5SNicholas Piggin                                        target_ulong decr, target_ulong value,
897ea62f8a5SNicholas Piggin                                        int nr_bits)
89853018216SPaolo Bonzini {
89953018216SPaolo Bonzini     ppc_tb_t *tb_env = cpu->env.tb_env;
90053018216SPaolo Bonzini 
901ea62f8a5SNicholas Piggin     __cpu_ppc_store_decr(cpu, now, &tb_env->decr_next, tb_env->decr_timer,
902a5ff7875SNicholas Piggin                          tb_env->decr_timer->cb, &cpu_ppc_decr_lower,
903a5ff7875SNicholas Piggin                          tb_env->flags, decr, value, nr_bits);
90453018216SPaolo Bonzini }
90553018216SPaolo Bonzini 
cpu_ppc_store_decr(CPUPPCState * env,target_ulong value)906a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value)
90753018216SPaolo Bonzini {
908db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
909a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
910ea62f8a5SNicholas Piggin     int64_t now;
911ea62f8a5SNicholas Piggin     target_ulong decr;
912a8dafa52SSuraj Jitindar Singh     int nr_bits = 32;
91353018216SPaolo Bonzini 
914ea62f8a5SNicholas Piggin     if (kvm_enabled()) {
915ea62f8a5SNicholas Piggin         /* KVM handles decrementer exceptions, we don't need our own timer */
916ea62f8a5SNicholas Piggin         return;
917ea62f8a5SNicholas Piggin     }
918ea62f8a5SNicholas Piggin 
919a8dafa52SSuraj Jitindar Singh     if (env->spr[SPR_LPCR] & LPCR_LD) {
920a8dafa52SSuraj Jitindar Singh         nr_bits = pcc->lrg_decr_bits;
921a8dafa52SSuraj Jitindar Singh     }
922a8dafa52SSuraj Jitindar Singh 
923ea62f8a5SNicholas Piggin     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
924ea62f8a5SNicholas Piggin     decr = _cpu_ppc_load_decr(env, now);
925ea62f8a5SNicholas Piggin     _cpu_ppc_store_decr(cpu, now, decr, value, nr_bits);
92653018216SPaolo Bonzini }
92753018216SPaolo Bonzini 
cpu_ppc_decr_cb(void * opaque)92853018216SPaolo Bonzini static void cpu_ppc_decr_cb(void *opaque)
92953018216SPaolo Bonzini {
93053018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
93153018216SPaolo Bonzini 
932e81a982aSAlexander Graf     cpu_ppc_decr_excp(cpu);
93353018216SPaolo Bonzini }
93453018216SPaolo Bonzini 
_cpu_ppc_store_hdecr(PowerPCCPU * cpu,int64_t now,target_ulong hdecr,target_ulong value,int nr_bits)935ea62f8a5SNicholas Piggin static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, int64_t now,
936ea62f8a5SNicholas Piggin                                         target_ulong hdecr, target_ulong value,
937ea62f8a5SNicholas Piggin                                         int nr_bits)
93853018216SPaolo Bonzini {
93953018216SPaolo Bonzini     ppc_tb_t *tb_env = cpu->env.tb_env;
94053018216SPaolo Bonzini 
94153018216SPaolo Bonzini     if (tb_env->hdecr_timer != NULL) {
942a5ff7875SNicholas Piggin         /* HDECR (Book3S 64bit) is edge-based, not level like DECR */
943ea62f8a5SNicholas Piggin         __cpu_ppc_store_decr(cpu, now, &tb_env->hdecr_next, tb_env->hdecr_timer,
944e81a982aSAlexander Graf                              tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
945a5ff7875SNicholas Piggin                              PPC_DECR_UNDERFLOW_TRIGGERED,
946a8dafa52SSuraj Jitindar Singh                              hdecr, value, nr_bits);
94753018216SPaolo Bonzini     }
94853018216SPaolo Bonzini }
94953018216SPaolo Bonzini 
cpu_ppc_store_hdecr(CPUPPCState * env,target_ulong value)950a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value)
95153018216SPaolo Bonzini {
952db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
953a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
954ea62f8a5SNicholas Piggin     int64_t now;
955ea62f8a5SNicholas Piggin     target_ulong hdecr;
95653018216SPaolo Bonzini 
957ea62f8a5SNicholas Piggin     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
958ea62f8a5SNicholas Piggin     hdecr = _cpu_ppc_load_hdecr(env, now);
959ea62f8a5SNicholas Piggin     _cpu_ppc_store_hdecr(cpu, now, hdecr, value, pcc->lrg_decr_bits);
96053018216SPaolo Bonzini }
96153018216SPaolo Bonzini 
cpu_ppc_hdecr_cb(void * opaque)96253018216SPaolo Bonzini static void cpu_ppc_hdecr_cb(void *opaque)
96353018216SPaolo Bonzini {
96453018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
96553018216SPaolo Bonzini 
966e81a982aSAlexander Graf     cpu_ppc_hdecr_excp(cpu);
96753018216SPaolo Bonzini }
96853018216SPaolo Bonzini 
_cpu_ppc_store_purr(CPUPPCState * env,int64_t now,uint64_t value)969ea62f8a5SNicholas Piggin static void _cpu_ppc_store_purr(CPUPPCState *env, int64_t now, uint64_t value)
97053018216SPaolo Bonzini {
9715cc7e69fSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
97253018216SPaolo Bonzini 
973ea62f8a5SNicholas Piggin     cpu_ppc_store_tb(tb_env, now, &tb_env->purr_offset, value);
974ea62f8a5SNicholas Piggin }
975ea62f8a5SNicholas Piggin 
cpu_ppc_store_purr(CPUPPCState * env,uint64_t value)976ea62f8a5SNicholas Piggin void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value)
977ea62f8a5SNicholas Piggin {
978ea62f8a5SNicholas Piggin     _cpu_ppc_store_purr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), value);
97953018216SPaolo Bonzini }
98053018216SPaolo Bonzini 
timebase_save(PPCTimebase * tb)98142043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb)
98298a8b524SAlexey Kardashevskiy {
9834a7428c5SChristopher Covington     uint64_t ticks = cpu_get_host_ticks();
98498a8b524SAlexey Kardashevskiy     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
98598a8b524SAlexey Kardashevskiy 
98698a8b524SAlexey Kardashevskiy     if (!first_ppc_cpu->env.tb_env) {
98798a8b524SAlexey Kardashevskiy         error_report("No timebase object");
98898a8b524SAlexey Kardashevskiy         return;
98998a8b524SAlexey Kardashevskiy     }
99098a8b524SAlexey Kardashevskiy 
9919db680f8SNicholas Piggin     if (replay_mode == REPLAY_MODE_NONE) {
99242043e4fSLaurent Vivier         /* not used anymore, we keep it for compatibility */
99377bad151SPaolo Bonzini         tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
9949db680f8SNicholas Piggin     } else {
9959db680f8SNicholas Piggin         /* simpler for record-replay to avoid this event, compat not needed */
9969db680f8SNicholas Piggin         tb->time_of_the_day_ns = 0;
9979db680f8SNicholas Piggin     }
9989db680f8SNicholas Piggin 
99998a8b524SAlexey Kardashevskiy     /*
100042043e4fSLaurent Vivier      * tb_offset is only expected to be changed by QEMU so
100198a8b524SAlexey Kardashevskiy      * there is no need to update it from KVM here
100298a8b524SAlexey Kardashevskiy      */
100398a8b524SAlexey Kardashevskiy     tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
1004d14f3397SMaxiwell S. Garcia 
1005711dfb24SGreg Kurz     tb->runstate_paused =
1006711dfb24SGreg Kurz         runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM);
100798a8b524SAlexey Kardashevskiy }
100898a8b524SAlexey Kardashevskiy 
timebase_load(PPCTimebase * tb)100942043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb)
101098a8b524SAlexey Kardashevskiy {
101198a8b524SAlexey Kardashevskiy     CPUState *cpu;
101298a8b524SAlexey Kardashevskiy     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
101342043e4fSLaurent Vivier     int64_t tb_off_adj, tb_off;
101498a8b524SAlexey Kardashevskiy     unsigned long freq;
101598a8b524SAlexey Kardashevskiy 
101698a8b524SAlexey Kardashevskiy     if (!first_ppc_cpu->env.tb_env) {
101798a8b524SAlexey Kardashevskiy         error_report("No timebase object");
101842043e4fSLaurent Vivier         return;
101998a8b524SAlexey Kardashevskiy     }
102098a8b524SAlexey Kardashevskiy 
102198a8b524SAlexey Kardashevskiy     freq = first_ppc_cpu->env.tb_env->tb_freq;
102298a8b524SAlexey Kardashevskiy 
102342043e4fSLaurent Vivier     tb_off_adj = tb->guest_timebase - cpu_get_host_ticks();
102498a8b524SAlexey Kardashevskiy 
102598a8b524SAlexey Kardashevskiy     tb_off = first_ppc_cpu->env.tb_env->tb_offset;
102698a8b524SAlexey Kardashevskiy     trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off,
102798a8b524SAlexey Kardashevskiy                         (tb_off_adj - tb_off) / freq);
102898a8b524SAlexey Kardashevskiy 
102998a8b524SAlexey Kardashevskiy     /* Set new offset to all CPUs */
103098a8b524SAlexey Kardashevskiy     CPU_FOREACH(cpu) {
103198a8b524SAlexey Kardashevskiy         PowerPCCPU *pcpu = POWERPC_CPU(cpu);
103298a8b524SAlexey Kardashevskiy         pcpu->env.tb_env->tb_offset = tb_off_adj;
10339723295aSGreg Kurz         kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset);
103442043e4fSLaurent Vivier     }
103598a8b524SAlexey Kardashevskiy }
103698a8b524SAlexey Kardashevskiy 
cpu_ppc_clock_vm_state_change(void * opaque,bool running,RunState state)1037538f0497SPhilippe Mathieu-Daudé void cpu_ppc_clock_vm_state_change(void *opaque, bool running,
103842043e4fSLaurent Vivier                                    RunState state)
103942043e4fSLaurent Vivier {
104042043e4fSLaurent Vivier     PPCTimebase *tb = opaque;
104142043e4fSLaurent Vivier 
104242043e4fSLaurent Vivier     if (running) {
104342043e4fSLaurent Vivier         timebase_load(tb);
104442043e4fSLaurent Vivier     } else {
104542043e4fSLaurent Vivier         timebase_save(tb);
104642043e4fSLaurent Vivier     }
104742043e4fSLaurent Vivier }
104842043e4fSLaurent Vivier 
104942043e4fSLaurent Vivier /*
1050d14f3397SMaxiwell S. Garcia  * When migrating a running guest, read the clock just
1051d14f3397SMaxiwell S. Garcia  * before migration, so that the guest clock counts
1052d14f3397SMaxiwell S. Garcia  * during the events between:
105342043e4fSLaurent Vivier  *
105442043e4fSLaurent Vivier  *  * vm_stop()
105542043e4fSLaurent Vivier  *  *
105642043e4fSLaurent Vivier  *  * pre_save()
105742043e4fSLaurent Vivier  *
105842043e4fSLaurent Vivier  *  This reduces clock difference on migration from 5s
105942043e4fSLaurent Vivier  *  to 0.1s (when max_downtime == 5s), because sending the
106042043e4fSLaurent Vivier  *  final pages of memory (which happens between vm_stop()
106142043e4fSLaurent Vivier  *  and pre_save()) takes max_downtime.
106242043e4fSLaurent Vivier  */
timebase_pre_save(void * opaque)106344b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque)
106442043e4fSLaurent Vivier {
106542043e4fSLaurent Vivier     PPCTimebase *tb = opaque;
106642043e4fSLaurent Vivier 
1067711dfb24SGreg Kurz     /* guest_timebase won't be overridden in case of paused guest or savevm */
1068d14f3397SMaxiwell S. Garcia     if (!tb->runstate_paused) {
106942043e4fSLaurent Vivier         timebase_save(tb);
1070d14f3397SMaxiwell S. Garcia     }
107144b1ff31SDr. David Alan Gilbert 
107244b1ff31SDr. David Alan Gilbert     return 0;
107398a8b524SAlexey Kardashevskiy }
107498a8b524SAlexey Kardashevskiy 
107598a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = {
107698a8b524SAlexey Kardashevskiy     .name = "timebase",
107798a8b524SAlexey Kardashevskiy     .version_id = 1,
107898a8b524SAlexey Kardashevskiy     .minimum_version_id = 1,
107998a8b524SAlexey Kardashevskiy     .pre_save = timebase_pre_save,
1080078ddbc9SRichard Henderson     .fields = (const VMStateField []) {
108198a8b524SAlexey Kardashevskiy         VMSTATE_UINT64(guest_timebase, PPCTimebase),
108298a8b524SAlexey Kardashevskiy         VMSTATE_INT64(time_of_the_day_ns, PPCTimebase),
108398a8b524SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
108498a8b524SAlexey Kardashevskiy     },
108598a8b524SAlexey Kardashevskiy };
108698a8b524SAlexey Kardashevskiy 
108753018216SPaolo Bonzini /* Set up (once) timebase frequency (in Hz) */
cpu_ppc_tb_init(CPUPPCState * env,uint32_t freq)108830d0647bSNicholas Piggin void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq)
108953018216SPaolo Bonzini {
1090db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
109153018216SPaolo Bonzini     ppc_tb_t *tb_env;
109253018216SPaolo Bonzini 
1093b21e2380SMarkus Armbruster     tb_env = g_new0(ppc_tb_t, 1);
109453018216SPaolo Bonzini     env->tb_env = tb_env;
109553018216SPaolo Bonzini     tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
1096d0db7cadSGreg Kurz     if (is_book3s_arch2x(env)) {
1097e81a982aSAlexander Graf         /* All Book3S 64bit CPUs implement level based DEC logic */
1098e81a982aSAlexander Graf         tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
1099e81a982aSAlexander Graf     }
110053018216SPaolo Bonzini     /* Create new timer */
1101eaf832fcSNicholas Piggin     tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
1102eaf832fcSNicholas Piggin                                       &cpu_ppc_decr_cb, cpu);
11035ff40b01SNicholas Piggin     if (env->has_hv_mode && !cpu->vhyp) {
1104eaf832fcSNicholas Piggin         tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
1105eaf832fcSNicholas Piggin                                            &cpu_ppc_hdecr_cb, cpu);
110653018216SPaolo Bonzini     } else {
110753018216SPaolo Bonzini         tb_env->hdecr_timer = NULL;
110853018216SPaolo Bonzini     }
110953018216SPaolo Bonzini 
111030d0647bSNicholas Piggin     tb_env->tb_freq = freq;
111130d0647bSNicholas Piggin     tb_env->decr_freq = freq;
111230d0647bSNicholas Piggin }
111330d0647bSNicholas Piggin 
cpu_ppc_tb_reset(CPUPPCState * env)111430d0647bSNicholas Piggin void cpu_ppc_tb_reset(CPUPPCState *env)
111530d0647bSNicholas Piggin {
111630d0647bSNicholas Piggin     PowerPCCPU *cpu = env_archcpu(env);
111730d0647bSNicholas Piggin     ppc_tb_t *tb_env = env->tb_env;
111830d0647bSNicholas Piggin 
111930d0647bSNicholas Piggin     timer_del(tb_env->decr_timer);
112030d0647bSNicholas Piggin     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
112130d0647bSNicholas Piggin     tb_env->decr_next = 0;
112230d0647bSNicholas Piggin     if (tb_env->hdecr_timer != NULL) {
112330d0647bSNicholas Piggin         timer_del(tb_env->hdecr_timer);
112430d0647bSNicholas Piggin         ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
112530d0647bSNicholas Piggin         tb_env->hdecr_next = 0;
112630d0647bSNicholas Piggin     }
112730d0647bSNicholas Piggin 
112830d0647bSNicholas Piggin     /*
112930d0647bSNicholas Piggin      * There is a bug in Linux 2.4 kernels:
113030d0647bSNicholas Piggin      * if a decrementer exception is pending when it enables msr_ee at startup,
113130d0647bSNicholas Piggin      * it's not ready to handle it...
113230d0647bSNicholas Piggin      */
113330d0647bSNicholas Piggin     cpu_ppc_store_decr(env, -1);
113430d0647bSNicholas Piggin     cpu_ppc_store_hdecr(env, -1);
113530d0647bSNicholas Piggin     cpu_ppc_store_purr(env, 0x0000000000000000ULL);
113653018216SPaolo Bonzini }
113753018216SPaolo Bonzini 
cpu_ppc_tb_free(CPUPPCState * env)1138ef95a244SDaniel Henrique Barboza void cpu_ppc_tb_free(CPUPPCState *env)
1139ef95a244SDaniel Henrique Barboza {
1140ef95a244SDaniel Henrique Barboza     timer_free(env->tb_env->decr_timer);
1141ef95a244SDaniel Henrique Barboza     timer_free(env->tb_env->hdecr_timer);
1142ef95a244SDaniel Henrique Barboza     g_free(env->tb_env);
1143ef95a244SDaniel Henrique Barboza }
1144ef95a244SDaniel Henrique Barboza 
114593aeb702SNicholas Piggin /* cpu_ppc_hdecr_init may be used if the timer is not used by HDEC emulation */
cpu_ppc_hdecr_init(CPUPPCState * env)114693aeb702SNicholas Piggin void cpu_ppc_hdecr_init(CPUPPCState *env)
114793aeb702SNicholas Piggin {
114893aeb702SNicholas Piggin     PowerPCCPU *cpu = env_archcpu(env);
114993aeb702SNicholas Piggin 
115093aeb702SNicholas Piggin     assert(env->tb_env->hdecr_timer == NULL);
115193aeb702SNicholas Piggin 
115293aeb702SNicholas Piggin     env->tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
115393aeb702SNicholas Piggin                                             &cpu_ppc_hdecr_cb, cpu);
115493aeb702SNicholas Piggin }
115593aeb702SNicholas Piggin 
cpu_ppc_hdecr_exit(CPUPPCState * env)115693aeb702SNicholas Piggin void cpu_ppc_hdecr_exit(CPUPPCState *env)
115793aeb702SNicholas Piggin {
115893aeb702SNicholas Piggin     PowerPCCPU *cpu = env_archcpu(env);
115993aeb702SNicholas Piggin 
116093aeb702SNicholas Piggin     timer_free(env->tb_env->hdecr_timer);
116193aeb702SNicholas Piggin     env->tb_env->hdecr_timer = NULL;
116293aeb702SNicholas Piggin 
116393aeb702SNicholas Piggin     cpu_ppc_hdecr_lower(cpu);
116493aeb702SNicholas Piggin }
116593aeb702SNicholas Piggin 
116653018216SPaolo Bonzini /*****************************************************************************/
116753018216SPaolo Bonzini /* PowerPC 40x timers */
116853018216SPaolo Bonzini 
116953018216SPaolo Bonzini /* PIT, FIT & WDT */
117053018216SPaolo Bonzini typedef struct ppc40x_timer_t ppc40x_timer_t;
117153018216SPaolo Bonzini struct ppc40x_timer_t {
117253018216SPaolo Bonzini     uint64_t pit_reload;  /* PIT auto-reload value        */
117353018216SPaolo Bonzini     uint64_t fit_next;    /* Tick for next FIT interrupt  */
11741246b259SStefan Weil     QEMUTimer *fit_timer;
117553018216SPaolo Bonzini     uint64_t wdt_next;    /* Tick for next WDT interrupt  */
11761246b259SStefan Weil     QEMUTimer *wdt_timer;
117753018216SPaolo Bonzini 
117853018216SPaolo Bonzini     /* 405 have the PIT, 440 have a DECR.  */
117953018216SPaolo Bonzini     unsigned int decr_excp;
118053018216SPaolo Bonzini };
118153018216SPaolo Bonzini 
118253018216SPaolo Bonzini /* Fixed interval timer */
cpu_4xx_fit_cb(void * opaque)118353018216SPaolo Bonzini static void cpu_4xx_fit_cb (void *opaque)
118453018216SPaolo Bonzini {
1185b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1186b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
118753018216SPaolo Bonzini     ppc_tb_t *tb_env;
118853018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
118953018216SPaolo Bonzini     uint64_t now, next;
119053018216SPaolo Bonzini 
119153018216SPaolo Bonzini     tb_env = env->tb_env;
119253018216SPaolo Bonzini     ppc40x_timer = tb_env->opaque;
1193bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
119453018216SPaolo Bonzini     switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
119553018216SPaolo Bonzini     case 0:
119653018216SPaolo Bonzini         next = 1 << 9;
119753018216SPaolo Bonzini         break;
119853018216SPaolo Bonzini     case 1:
119953018216SPaolo Bonzini         next = 1 << 13;
120053018216SPaolo Bonzini         break;
120153018216SPaolo Bonzini     case 2:
120253018216SPaolo Bonzini         next = 1 << 17;
120353018216SPaolo Bonzini         break;
120453018216SPaolo Bonzini     case 3:
120553018216SPaolo Bonzini         next = 1 << 21;
120653018216SPaolo Bonzini         break;
120753018216SPaolo Bonzini     default:
120853018216SPaolo Bonzini         /* Cannot occur, but makes gcc happy */
120953018216SPaolo Bonzini         return;
121053018216SPaolo Bonzini     }
1211eab08884SNicholas Piggin     next = now + tb_to_ns_round_up(tb_env->tb_freq, next);
1212bc72ad67SAlex Bligh     timer_mod(ppc40x_timer->fit_timer, next);
121353018216SPaolo Bonzini     env->spr[SPR_40x_TSR] |= 1 << 26;
121453018216SPaolo Bonzini     if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) {
121553018216SPaolo Bonzini         ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1);
121653018216SPaolo Bonzini     }
1217af96d2e6SCédric Le Goater     trace_ppc4xx_fit((int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
121853018216SPaolo Bonzini                          env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
121953018216SPaolo Bonzini }
122053018216SPaolo Bonzini 
122153018216SPaolo Bonzini /* Programmable interval timer */
start_stop_pit(CPUPPCState * env,ppc_tb_t * tb_env,int is_excp)122253018216SPaolo Bonzini static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
122353018216SPaolo Bonzini {
122453018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
122553018216SPaolo Bonzini     uint64_t now, next;
122653018216SPaolo Bonzini 
122753018216SPaolo Bonzini     ppc40x_timer = tb_env->opaque;
122853018216SPaolo Bonzini     if (ppc40x_timer->pit_reload <= 1 ||
122953018216SPaolo Bonzini         !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
123053018216SPaolo Bonzini         (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
123153018216SPaolo Bonzini         /* Stop PIT */
1232af96d2e6SCédric Le Goater         trace_ppc4xx_pit_stop();
1233bc72ad67SAlex Bligh         timer_del(tb_env->decr_timer);
123453018216SPaolo Bonzini     } else {
1235af96d2e6SCédric Le Goater         trace_ppc4xx_pit_start(ppc40x_timer->pit_reload);
1236bc72ad67SAlex Bligh         now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
12378e0a5ac8SNicholas Piggin 
12388e0a5ac8SNicholas Piggin         if (is_excp) {
12398e0a5ac8SNicholas Piggin             tb_env->decr_next += ppc40x_timer->pit_reload;
12408e0a5ac8SNicholas Piggin         } else {
12418e0a5ac8SNicholas Piggin             tb_env->decr_next = ns_to_tb(tb_env->decr_freq, now)
12428e0a5ac8SNicholas Piggin                                 + ppc40x_timer->pit_reload;
12438e0a5ac8SNicholas Piggin         }
12448e0a5ac8SNicholas Piggin         next = tb_to_ns_round_up(tb_env->decr_freq, tb_env->decr_next);
1245bc72ad67SAlex Bligh         timer_mod(tb_env->decr_timer, next);
124653018216SPaolo Bonzini     }
124753018216SPaolo Bonzini }
124853018216SPaolo Bonzini 
cpu_4xx_pit_cb(void * opaque)124953018216SPaolo Bonzini static void cpu_4xx_pit_cb (void *opaque)
125053018216SPaolo Bonzini {
1251b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1252b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
125353018216SPaolo Bonzini     ppc_tb_t *tb_env;
125453018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
125553018216SPaolo Bonzini 
125653018216SPaolo Bonzini     tb_env = env->tb_env;
125753018216SPaolo Bonzini     ppc40x_timer = tb_env->opaque;
125853018216SPaolo Bonzini     env->spr[SPR_40x_TSR] |= 1 << 27;
125953018216SPaolo Bonzini     if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) {
126053018216SPaolo Bonzini         ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1);
126153018216SPaolo Bonzini     }
126253018216SPaolo Bonzini     start_stop_pit(env, tb_env, 1);
1263af96d2e6SCédric Le Goater     trace_ppc4xx_pit((int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
126453018216SPaolo Bonzini            (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
126553018216SPaolo Bonzini            env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
126653018216SPaolo Bonzini            ppc40x_timer->pit_reload);
126753018216SPaolo Bonzini }
126853018216SPaolo Bonzini 
126953018216SPaolo Bonzini /* Watchdog timer */
cpu_4xx_wdt_cb(void * opaque)127053018216SPaolo Bonzini static void cpu_4xx_wdt_cb (void *opaque)
127153018216SPaolo Bonzini {
1272b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1273b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
127453018216SPaolo Bonzini     ppc_tb_t *tb_env;
127553018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
127653018216SPaolo Bonzini     uint64_t now, next;
127753018216SPaolo Bonzini 
127853018216SPaolo Bonzini     tb_env = env->tb_env;
127953018216SPaolo Bonzini     ppc40x_timer = tb_env->opaque;
1280bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
128153018216SPaolo Bonzini     switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
128253018216SPaolo Bonzini     case 0:
128353018216SPaolo Bonzini         next = 1 << 17;
128453018216SPaolo Bonzini         break;
128553018216SPaolo Bonzini     case 1:
128653018216SPaolo Bonzini         next = 1 << 21;
128753018216SPaolo Bonzini         break;
128853018216SPaolo Bonzini     case 2:
128953018216SPaolo Bonzini         next = 1 << 25;
129053018216SPaolo Bonzini         break;
129153018216SPaolo Bonzini     case 3:
129253018216SPaolo Bonzini         next = 1 << 29;
129353018216SPaolo Bonzini         break;
129453018216SPaolo Bonzini     default:
129553018216SPaolo Bonzini         /* Cannot occur, but makes gcc happy */
129653018216SPaolo Bonzini         return;
129753018216SPaolo Bonzini     }
1298eab08884SNicholas Piggin     next = now + tb_to_ns_round_up(tb_env->decr_freq, next);
1299af96d2e6SCédric Le Goater     trace_ppc4xx_wdt(env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
130053018216SPaolo Bonzini     switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
130153018216SPaolo Bonzini     case 0x0:
130253018216SPaolo Bonzini     case 0x1:
1303bc72ad67SAlex Bligh         timer_mod(ppc40x_timer->wdt_timer, next);
130453018216SPaolo Bonzini         ppc40x_timer->wdt_next = next;
1305a1f7f97bSPeter Maydell         env->spr[SPR_40x_TSR] |= 1U << 31;
130653018216SPaolo Bonzini         break;
130753018216SPaolo Bonzini     case 0x2:
1308bc72ad67SAlex Bligh         timer_mod(ppc40x_timer->wdt_timer, next);
130953018216SPaolo Bonzini         ppc40x_timer->wdt_next = next;
131053018216SPaolo Bonzini         env->spr[SPR_40x_TSR] |= 1 << 30;
131153018216SPaolo Bonzini         if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) {
131253018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1);
131353018216SPaolo Bonzini         }
131453018216SPaolo Bonzini         break;
131553018216SPaolo Bonzini     case 0x3:
131653018216SPaolo Bonzini         env->spr[SPR_40x_TSR] &= ~0x30000000;
131753018216SPaolo Bonzini         env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
131853018216SPaolo Bonzini         switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
131953018216SPaolo Bonzini         case 0x0:
132053018216SPaolo Bonzini             /* No reset */
132153018216SPaolo Bonzini             break;
132253018216SPaolo Bonzini         case 0x1: /* Core reset */
132353018216SPaolo Bonzini             ppc40x_core_reset(cpu);
132453018216SPaolo Bonzini             break;
132553018216SPaolo Bonzini         case 0x2: /* Chip reset */
132653018216SPaolo Bonzini             ppc40x_chip_reset(cpu);
132753018216SPaolo Bonzini             break;
132853018216SPaolo Bonzini         case 0x3: /* System reset */
132953018216SPaolo Bonzini             ppc40x_system_reset(cpu);
133053018216SPaolo Bonzini             break;
133153018216SPaolo Bonzini         }
133253018216SPaolo Bonzini     }
133353018216SPaolo Bonzini }
133453018216SPaolo Bonzini 
store_40x_pit(CPUPPCState * env,target_ulong val)133553018216SPaolo Bonzini void store_40x_pit (CPUPPCState *env, target_ulong val)
133653018216SPaolo Bonzini {
133753018216SPaolo Bonzini     ppc_tb_t *tb_env;
133853018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
133953018216SPaolo Bonzini 
134053018216SPaolo Bonzini     tb_env = env->tb_env;
134153018216SPaolo Bonzini     ppc40x_timer = tb_env->opaque;
1342af96d2e6SCédric Le Goater     trace_ppc40x_store_pit(val);
134353018216SPaolo Bonzini     ppc40x_timer->pit_reload = val;
134453018216SPaolo Bonzini     start_stop_pit(env, tb_env, 0);
134553018216SPaolo Bonzini }
134653018216SPaolo Bonzini 
load_40x_pit(CPUPPCState * env)134753018216SPaolo Bonzini target_ulong load_40x_pit (CPUPPCState *env)
134853018216SPaolo Bonzini {
134953018216SPaolo Bonzini     return cpu_ppc_load_decr(env);
135053018216SPaolo Bonzini }
135153018216SPaolo Bonzini 
store_40x_tsr(CPUPPCState * env,target_ulong val)1352cbd8f17dSCédric Le Goater void store_40x_tsr(CPUPPCState *env, target_ulong val)
1353cbd8f17dSCédric Le Goater {
1354cbd8f17dSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1355cbd8f17dSCédric Le Goater 
1356cbd8f17dSCédric Le Goater     trace_ppc40x_store_tcr(val);
1357cbd8f17dSCédric Le Goater 
1358cbd8f17dSCédric Le Goater     env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
1359cbd8f17dSCédric Le Goater     if (val & 0x80000000) {
1360cbd8f17dSCédric Le Goater         ppc_set_irq(cpu, PPC_INTERRUPT_PIT, 0);
1361cbd8f17dSCédric Le Goater     }
1362cbd8f17dSCédric Le Goater }
1363cbd8f17dSCédric Le Goater 
store_40x_tcr(CPUPPCState * env,target_ulong val)1364cbd8f17dSCédric Le Goater void store_40x_tcr(CPUPPCState *env, target_ulong val)
1365cbd8f17dSCédric Le Goater {
1366cbd8f17dSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1367cbd8f17dSCédric Le Goater     ppc_tb_t *tb_env;
1368cbd8f17dSCédric Le Goater 
1369cbd8f17dSCédric Le Goater     trace_ppc40x_store_tsr(val);
1370cbd8f17dSCédric Le Goater 
1371cbd8f17dSCédric Le Goater     tb_env = env->tb_env;
1372cbd8f17dSCédric Le Goater     env->spr[SPR_40x_TCR] = val & 0xFFC00000;
1373cbd8f17dSCédric Le Goater     start_stop_pit(env, tb_env, 1);
1374cbd8f17dSCédric Le Goater     cpu_4xx_wdt_cb(cpu);
1375cbd8f17dSCédric Le Goater }
1376cbd8f17dSCédric Le Goater 
ppc_40x_set_tb_clk(void * opaque,uint32_t freq)137753018216SPaolo Bonzini static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
137853018216SPaolo Bonzini {
137953018216SPaolo Bonzini     CPUPPCState *env = opaque;
138053018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
138153018216SPaolo Bonzini 
1382af96d2e6SCédric Le Goater     trace_ppc40x_set_tb_clk(freq);
138353018216SPaolo Bonzini     tb_env->tb_freq = freq;
138453018216SPaolo Bonzini     tb_env->decr_freq = freq;
138553018216SPaolo Bonzini     /* XXX: we should also update all timers */
138653018216SPaolo Bonzini }
138753018216SPaolo Bonzini 
ppc_40x_timers_init(CPUPPCState * env,uint32_t freq,unsigned int decr_excp)138853018216SPaolo Bonzini clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
138953018216SPaolo Bonzini                                   unsigned int decr_excp)
139053018216SPaolo Bonzini {
139153018216SPaolo Bonzini     ppc_tb_t *tb_env;
139253018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
1393b1273a5eSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1394b1273a5eSCédric Le Goater 
1395b1273a5eSCédric Le Goater     trace_ppc40x_timers_init(freq);
139653018216SPaolo Bonzini 
1397b21e2380SMarkus Armbruster     tb_env = g_new0(ppc_tb_t, 1);
1398b21e2380SMarkus Armbruster     ppc40x_timer = g_new0(ppc40x_timer_t, 1);
1399b1273a5eSCédric Le Goater 
140053018216SPaolo Bonzini     env->tb_env = tb_env;
140153018216SPaolo Bonzini     tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
140253018216SPaolo Bonzini     tb_env->tb_freq = freq;
140353018216SPaolo Bonzini     tb_env->decr_freq = freq;
140453018216SPaolo Bonzini     tb_env->opaque = ppc40x_timer;
1405b1273a5eSCédric Le Goater 
140653018216SPaolo Bonzini     /* We use decr timer for PIT */
1407b1273a5eSCédric Le Goater     tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, cpu);
140853018216SPaolo Bonzini     ppc40x_timer->fit_timer =
1409b1273a5eSCédric Le Goater         timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, cpu);
141053018216SPaolo Bonzini     ppc40x_timer->wdt_timer =
1411b1273a5eSCédric Le Goater         timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, cpu);
141253018216SPaolo Bonzini     ppc40x_timer->decr_excp = decr_excp;
141353018216SPaolo Bonzini 
141453018216SPaolo Bonzini     return &ppc_40x_set_tb_clk;
141553018216SPaolo Bonzini }
141653018216SPaolo Bonzini 
141753018216SPaolo Bonzini /*****************************************************************************/
141853018216SPaolo Bonzini /* Embedded PowerPC Device Control Registers */
141953018216SPaolo Bonzini typedef struct ppc_dcrn_t ppc_dcrn_t;
142053018216SPaolo Bonzini struct ppc_dcrn_t {
142153018216SPaolo Bonzini     dcr_read_cb dcr_read;
142253018216SPaolo Bonzini     dcr_write_cb dcr_write;
142353018216SPaolo Bonzini     void *opaque;
142453018216SPaolo Bonzini };
142553018216SPaolo Bonzini 
142653018216SPaolo Bonzini /* XXX: on 460, DCR addresses are 32 bits wide,
142753018216SPaolo Bonzini  *      using DCRIPR to get the 22 upper bits of the DCR address
142853018216SPaolo Bonzini  */
142953018216SPaolo Bonzini #define DCRN_NB 1024
143053018216SPaolo Bonzini struct ppc_dcr_t {
143153018216SPaolo Bonzini     ppc_dcrn_t dcrn[DCRN_NB];
143253018216SPaolo Bonzini     int (*read_error)(int dcrn);
143353018216SPaolo Bonzini     int (*write_error)(int dcrn);
143453018216SPaolo Bonzini };
143553018216SPaolo Bonzini 
ppc_dcr_read(ppc_dcr_t * dcr_env,int dcrn,uint32_t * valp)143653018216SPaolo Bonzini int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
143753018216SPaolo Bonzini {
143853018216SPaolo Bonzini     ppc_dcrn_t *dcr;
143953018216SPaolo Bonzini 
144053018216SPaolo Bonzini     if (dcrn < 0 || dcrn >= DCRN_NB)
144153018216SPaolo Bonzini         goto error;
144253018216SPaolo Bonzini     dcr = &dcr_env->dcrn[dcrn];
144353018216SPaolo Bonzini     if (dcr->dcr_read == NULL)
144453018216SPaolo Bonzini         goto error;
144553018216SPaolo Bonzini     *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
1446de82dabeSCédric Le Goater     trace_ppc_dcr_read(dcrn, *valp);
144753018216SPaolo Bonzini 
144853018216SPaolo Bonzini     return 0;
144953018216SPaolo Bonzini 
145053018216SPaolo Bonzini  error:
145153018216SPaolo Bonzini     if (dcr_env->read_error != NULL)
145253018216SPaolo Bonzini         return (*dcr_env->read_error)(dcrn);
145353018216SPaolo Bonzini 
145453018216SPaolo Bonzini     return -1;
145553018216SPaolo Bonzini }
145653018216SPaolo Bonzini 
ppc_dcr_write(ppc_dcr_t * dcr_env,int dcrn,uint32_t val)145753018216SPaolo Bonzini int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
145853018216SPaolo Bonzini {
145953018216SPaolo Bonzini     ppc_dcrn_t *dcr;
146053018216SPaolo Bonzini 
146153018216SPaolo Bonzini     if (dcrn < 0 || dcrn >= DCRN_NB)
146253018216SPaolo Bonzini         goto error;
146353018216SPaolo Bonzini     dcr = &dcr_env->dcrn[dcrn];
146453018216SPaolo Bonzini     if (dcr->dcr_write == NULL)
146553018216SPaolo Bonzini         goto error;
1466de82dabeSCédric Le Goater     trace_ppc_dcr_write(dcrn, val);
146753018216SPaolo Bonzini     (*dcr->dcr_write)(dcr->opaque, dcrn, val);
146853018216SPaolo Bonzini 
146953018216SPaolo Bonzini     return 0;
147053018216SPaolo Bonzini 
147153018216SPaolo Bonzini  error:
147253018216SPaolo Bonzini     if (dcr_env->write_error != NULL)
147353018216SPaolo Bonzini         return (*dcr_env->write_error)(dcrn);
147453018216SPaolo Bonzini 
147553018216SPaolo Bonzini     return -1;
147653018216SPaolo Bonzini }
147753018216SPaolo Bonzini 
ppc_dcr_register(CPUPPCState * env,int dcrn,void * opaque,dcr_read_cb dcr_read,dcr_write_cb dcr_write)147853018216SPaolo Bonzini int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
147953018216SPaolo Bonzini                       dcr_read_cb dcr_read, dcr_write_cb dcr_write)
148053018216SPaolo Bonzini {
148153018216SPaolo Bonzini     ppc_dcr_t *dcr_env;
148253018216SPaolo Bonzini     ppc_dcrn_t *dcr;
148353018216SPaolo Bonzini 
148453018216SPaolo Bonzini     dcr_env = env->dcr_env;
148553018216SPaolo Bonzini     if (dcr_env == NULL)
148653018216SPaolo Bonzini         return -1;
148753018216SPaolo Bonzini     if (dcrn < 0 || dcrn >= DCRN_NB)
148853018216SPaolo Bonzini         return -1;
148953018216SPaolo Bonzini     dcr = &dcr_env->dcrn[dcrn];
149053018216SPaolo Bonzini     if (dcr->opaque != NULL ||
149153018216SPaolo Bonzini         dcr->dcr_read != NULL ||
149253018216SPaolo Bonzini         dcr->dcr_write != NULL)
149353018216SPaolo Bonzini         return -1;
149453018216SPaolo Bonzini     dcr->opaque = opaque;
149553018216SPaolo Bonzini     dcr->dcr_read = dcr_read;
149653018216SPaolo Bonzini     dcr->dcr_write = dcr_write;
149753018216SPaolo Bonzini 
149853018216SPaolo Bonzini     return 0;
149953018216SPaolo Bonzini }
150053018216SPaolo Bonzini 
ppc_dcr_init(CPUPPCState * env,int (* read_error)(int dcrn),int (* write_error)(int dcrn))150153018216SPaolo Bonzini int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn),
150253018216SPaolo Bonzini                   int (*write_error)(int dcrn))
150353018216SPaolo Bonzini {
150453018216SPaolo Bonzini     ppc_dcr_t *dcr_env;
150553018216SPaolo Bonzini 
1506b21e2380SMarkus Armbruster     dcr_env = g_new0(ppc_dcr_t, 1);
150753018216SPaolo Bonzini     dcr_env->read_error = read_error;
150853018216SPaolo Bonzini     dcr_env->write_error = write_error;
150953018216SPaolo Bonzini     env->dcr_env = dcr_env;
151053018216SPaolo Bonzini 
151153018216SPaolo Bonzini     return 0;
151253018216SPaolo Bonzini }
151353018216SPaolo Bonzini 
151453018216SPaolo Bonzini /*****************************************************************************/
1515051e2973SCédric Le Goater 
ppc_cpu_pir(PowerPCCPU * cpu)15164a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu)
15174a89e204SCédric Le Goater {
15184a89e204SCédric Le Goater     CPUPPCState *env = &cpu->env;
15194a89e204SCédric Le Goater     return env->spr_cb[SPR_PIR].default_value;
15204a89e204SCédric Le Goater }
15214a89e204SCédric Le Goater 
ppc_cpu_tir(PowerPCCPU * cpu)1522d24e80b2SNicholas Piggin int ppc_cpu_tir(PowerPCCPU *cpu)
1523d24e80b2SNicholas Piggin {
1524d24e80b2SNicholas Piggin     CPUPPCState *env = &cpu->env;
1525d24e80b2SNicholas Piggin     return env->spr_cb[SPR_TIR].default_value;
1526d24e80b2SNicholas Piggin }
1527d24e80b2SNicholas Piggin 
ppc_get_vcpu_by_pir(int pir)1528051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
1529051e2973SCédric Le Goater {
1530051e2973SCédric Le Goater     CPUState *cs;
1531051e2973SCédric Le Goater 
1532051e2973SCédric Le Goater     CPU_FOREACH(cs) {
1533051e2973SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
1534051e2973SCédric Le Goater 
15354a89e204SCédric Le Goater         if (ppc_cpu_pir(cpu) == pir) {
1536051e2973SCédric Le Goater             return cpu;
1537051e2973SCédric Le Goater         }
1538051e2973SCédric Le Goater     }
1539051e2973SCédric Le Goater 
1540051e2973SCédric Le Goater     return NULL;
1541051e2973SCédric Le Goater }
154240177438SGreg Kurz 
ppc_irq_reset(PowerPCCPU * cpu)154340177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu)
154440177438SGreg Kurz {
154540177438SGreg Kurz     CPUPPCState *env = &cpu->env;
154640177438SGreg Kurz 
154740177438SGreg Kurz     env->irq_input_state = 0;
154876d93e14Sjianchunfu     if (kvm_enabled()) {
154940177438SGreg Kurz         kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0);
155040177438SGreg Kurz     }
155176d93e14Sjianchunfu }
1552