xref: /qemu/hw/ppc/ppc.c (revision 2fdedcbc)
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     bool locked = false;
488d04fb55SJan Kiszka 
498d04fb55SJan Kiszka     /* We may already have the BQL if coming from the reset path */
508d04fb55SJan Kiszka     if (!qemu_mutex_iothread_locked()) {
518d04fb55SJan Kiszka         locked = true;
528d04fb55SJan Kiszka         qemu_mutex_lock_iothread();
538d04fb55SJan Kiszka     }
548d04fb55SJan Kiszka 
558d04fb55SJan Kiszka     old_pending = env->pending_interrupts;
5653018216SPaolo Bonzini 
5753018216SPaolo Bonzini     if (level) {
58f003109fSMatheus Ferst         env->pending_interrupts |= irq;
5953018216SPaolo Bonzini     } else {
60f003109fSMatheus Ferst         env->pending_interrupts &= ~irq;
6153018216SPaolo Bonzini     }
6253018216SPaolo Bonzini 
6353018216SPaolo Bonzini     if (old_pending != env->pending_interrupts) {
64*2fdedcbcSMatheus Ferst         ppc_maybe_interrupt(env);
65f003109fSMatheus Ferst         kvmppc_set_interrupt(cpu, irq, level);
6653018216SPaolo Bonzini     }
6753018216SPaolo Bonzini 
68f003109fSMatheus Ferst     trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
69af96d2e6SCédric Le Goater                            CPU(cpu)->interrupt_request);
708d04fb55SJan Kiszka 
718d04fb55SJan Kiszka     if (locked) {
728d04fb55SJan Kiszka         qemu_mutex_unlock_iothread();
738d04fb55SJan Kiszka     }
7453018216SPaolo Bonzini }
7553018216SPaolo Bonzini 
7653018216SPaolo Bonzini /* PowerPC 6xx / 7xx internal IRQ controller */
7753018216SPaolo Bonzini static void ppc6xx_set_irq(void *opaque, int pin, int level)
7853018216SPaolo Bonzini {
7953018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
8053018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
8153018216SPaolo Bonzini     int cur_level;
8253018216SPaolo Bonzini 
83af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
84af96d2e6SCédric Le Goater 
8553018216SPaolo Bonzini     cur_level = (env->irq_input_state >> pin) & 1;
8653018216SPaolo Bonzini     /* Don't generate spurious events */
8753018216SPaolo Bonzini     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
88259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
89259186a7SAndreas Färber 
9053018216SPaolo Bonzini         switch (pin) {
9153018216SPaolo Bonzini         case PPC6xx_INPUT_TBEN:
9253018216SPaolo Bonzini             /* Level sensitive - active high */
93af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("time base", level);
9453018216SPaolo Bonzini             if (level) {
9553018216SPaolo Bonzini                 cpu_ppc_tb_start(env);
9653018216SPaolo Bonzini             } else {
9753018216SPaolo Bonzini                 cpu_ppc_tb_stop(env);
9853018216SPaolo Bonzini             }
99b2bd5b20SChen Qun             break;
10053018216SPaolo Bonzini         case PPC6xx_INPUT_INT:
10153018216SPaolo Bonzini             /* Level sensitive - active high */
102af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("external IRQ", level);
10353018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
10453018216SPaolo Bonzini             break;
10553018216SPaolo Bonzini         case PPC6xx_INPUT_SMI:
10653018216SPaolo Bonzini             /* Level sensitive - active high */
107af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("SMI IRQ", level);
10853018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level);
10953018216SPaolo Bonzini             break;
11053018216SPaolo Bonzini         case PPC6xx_INPUT_MCP:
11153018216SPaolo Bonzini             /* Negative edge sensitive */
11253018216SPaolo Bonzini             /* XXX: TODO: actual reaction may depends on HID0 status
11353018216SPaolo Bonzini              *            603/604/740/750: check HID0[EMCP]
11453018216SPaolo Bonzini              */
11553018216SPaolo Bonzini             if (cur_level == 1 && level == 0) {
116af96d2e6SCédric Le Goater                 trace_ppc_irq_set_state("machine check", 1);
11753018216SPaolo Bonzini                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
11853018216SPaolo Bonzini             }
11953018216SPaolo Bonzini             break;
12053018216SPaolo Bonzini         case PPC6xx_INPUT_CKSTP_IN:
12153018216SPaolo Bonzini             /* Level sensitive - active low */
12253018216SPaolo Bonzini             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
12353018216SPaolo Bonzini             /* XXX: Note that the only way to restart the CPU is to reset it */
12453018216SPaolo Bonzini             if (level) {
125af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("stop");
126259186a7SAndreas Färber                 cs->halted = 1;
12753018216SPaolo Bonzini             }
12853018216SPaolo Bonzini             break;
12953018216SPaolo Bonzini         case PPC6xx_INPUT_HRESET:
13053018216SPaolo Bonzini             /* Level sensitive - active low */
13153018216SPaolo Bonzini             if (level) {
132af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("CPU");
133c3affe56SAndreas Färber                 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
13453018216SPaolo Bonzini             }
13553018216SPaolo Bonzini             break;
13653018216SPaolo Bonzini         case PPC6xx_INPUT_SRESET:
137af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("RESET IRQ", level);
13853018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
13953018216SPaolo Bonzini             break;
14053018216SPaolo Bonzini         default:
1417279810bSCédric Le Goater             g_assert_not_reached();
14253018216SPaolo Bonzini         }
14353018216SPaolo Bonzini         if (level)
14453018216SPaolo Bonzini             env->irq_input_state |= 1 << pin;
14553018216SPaolo Bonzini         else
14653018216SPaolo Bonzini             env->irq_input_state &= ~(1 << pin);
14753018216SPaolo Bonzini     }
14853018216SPaolo Bonzini }
14953018216SPaolo Bonzini 
150aa5a9e24SPaolo Bonzini void ppc6xx_irq_init(PowerPCCPU *cpu)
15153018216SPaolo Bonzini {
1520f3e0c6fSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppc6xx_set_irq, PPC6xx_INPUT_NB);
15353018216SPaolo Bonzini }
15453018216SPaolo Bonzini 
15553018216SPaolo Bonzini #if defined(TARGET_PPC64)
15653018216SPaolo Bonzini /* PowerPC 970 internal IRQ controller */
15753018216SPaolo Bonzini static void ppc970_set_irq(void *opaque, int pin, int level)
15853018216SPaolo Bonzini {
15953018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
16053018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
16153018216SPaolo Bonzini     int cur_level;
16253018216SPaolo Bonzini 
163af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
164af96d2e6SCédric Le Goater 
16553018216SPaolo Bonzini     cur_level = (env->irq_input_state >> pin) & 1;
16653018216SPaolo Bonzini     /* Don't generate spurious events */
16753018216SPaolo Bonzini     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
168259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
169259186a7SAndreas Färber 
17053018216SPaolo Bonzini         switch (pin) {
17153018216SPaolo Bonzini         case PPC970_INPUT_INT:
17253018216SPaolo Bonzini             /* Level sensitive - active high */
173af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("external IRQ", level);
17453018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
17553018216SPaolo Bonzini             break;
17653018216SPaolo Bonzini         case PPC970_INPUT_THINT:
17753018216SPaolo Bonzini             /* Level sensitive - active high */
178af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("SMI IRQ", level);
17953018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level);
18053018216SPaolo Bonzini             break;
18153018216SPaolo Bonzini         case PPC970_INPUT_MCP:
18253018216SPaolo Bonzini             /* Negative edge sensitive */
18353018216SPaolo Bonzini             /* XXX: TODO: actual reaction may depends on HID0 status
18453018216SPaolo Bonzini              *            603/604/740/750: check HID0[EMCP]
18553018216SPaolo Bonzini              */
18653018216SPaolo Bonzini             if (cur_level == 1 && level == 0) {
187af96d2e6SCédric Le Goater                 trace_ppc_irq_set_state("machine check", 1);
18853018216SPaolo Bonzini                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
18953018216SPaolo Bonzini             }
19053018216SPaolo Bonzini             break;
19153018216SPaolo Bonzini         case PPC970_INPUT_CKSTP:
19253018216SPaolo Bonzini             /* Level sensitive - active low */
19353018216SPaolo Bonzini             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
19453018216SPaolo Bonzini             if (level) {
195af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("stop");
196259186a7SAndreas Färber                 cs->halted = 1;
19753018216SPaolo Bonzini             } else {
198af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("restart");
199259186a7SAndreas Färber                 cs->halted = 0;
200259186a7SAndreas Färber                 qemu_cpu_kick(cs);
20153018216SPaolo Bonzini             }
20253018216SPaolo Bonzini             break;
20353018216SPaolo Bonzini         case PPC970_INPUT_HRESET:
20453018216SPaolo Bonzini             /* Level sensitive - active low */
20553018216SPaolo Bonzini             if (level) {
206c3affe56SAndreas Färber                 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
20753018216SPaolo Bonzini             }
20853018216SPaolo Bonzini             break;
20953018216SPaolo Bonzini         case PPC970_INPUT_SRESET:
210af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("RESET IRQ", level);
21153018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
21253018216SPaolo Bonzini             break;
21353018216SPaolo Bonzini         case PPC970_INPUT_TBEN:
214af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("TBEN IRQ", level);
21553018216SPaolo Bonzini             /* XXX: TODO */
21653018216SPaolo Bonzini             break;
21753018216SPaolo Bonzini         default:
2187279810bSCédric Le Goater             g_assert_not_reached();
21953018216SPaolo Bonzini         }
22053018216SPaolo Bonzini         if (level)
22153018216SPaolo Bonzini             env->irq_input_state |= 1 << pin;
22253018216SPaolo Bonzini         else
22353018216SPaolo Bonzini             env->irq_input_state &= ~(1 << pin);
22453018216SPaolo Bonzini     }
22553018216SPaolo Bonzini }
22653018216SPaolo Bonzini 
227aa5a9e24SPaolo Bonzini void ppc970_irq_init(PowerPCCPU *cpu)
22853018216SPaolo Bonzini {
2299fd0122eSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppc970_set_irq, PPC970_INPUT_NB);
23053018216SPaolo Bonzini }
23153018216SPaolo Bonzini 
23253018216SPaolo Bonzini /* POWER7 internal IRQ controller */
23353018216SPaolo Bonzini static void power7_set_irq(void *opaque, int pin, int level)
23453018216SPaolo Bonzini {
23553018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
23653018216SPaolo Bonzini 
237af96d2e6SCédric Le Goater     trace_ppc_irq_set(&cpu->env, pin, level);
23853018216SPaolo Bonzini 
23953018216SPaolo Bonzini     switch (pin) {
24053018216SPaolo Bonzini     case POWER7_INPUT_INT:
24153018216SPaolo Bonzini         /* Level sensitive - active high */
242af96d2e6SCédric Le Goater         trace_ppc_irq_set_state("external IRQ", level);
24353018216SPaolo Bonzini         ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
24453018216SPaolo Bonzini         break;
24553018216SPaolo Bonzini     default:
2467279810bSCédric Le Goater         g_assert_not_reached();
24753018216SPaolo Bonzini     }
24853018216SPaolo Bonzini }
24953018216SPaolo Bonzini 
250aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu)
25153018216SPaolo Bonzini {
2529fd0122eSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), power7_set_irq, POWER7_INPUT_NB);
25353018216SPaolo Bonzini }
25467afe775SBenjamin Herrenschmidt 
25567afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */
25667afe775SBenjamin Herrenschmidt static void power9_set_irq(void *opaque, int pin, int level)
25767afe775SBenjamin Herrenschmidt {
25867afe775SBenjamin Herrenschmidt     PowerPCCPU *cpu = opaque;
25967afe775SBenjamin Herrenschmidt 
260af96d2e6SCédric Le Goater     trace_ppc_irq_set(&cpu->env, pin, level);
26167afe775SBenjamin Herrenschmidt 
26267afe775SBenjamin Herrenschmidt     switch (pin) {
26367afe775SBenjamin Herrenschmidt     case POWER9_INPUT_INT:
26467afe775SBenjamin Herrenschmidt         /* Level sensitive - active high */
265af96d2e6SCédric Le Goater         trace_ppc_irq_set_state("external IRQ", level);
26667afe775SBenjamin Herrenschmidt         ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
26767afe775SBenjamin Herrenschmidt         break;
26867afe775SBenjamin Herrenschmidt     case POWER9_INPUT_HINT:
26967afe775SBenjamin Herrenschmidt         /* Level sensitive - active high */
270af96d2e6SCédric Le Goater         trace_ppc_irq_set_state("HV external IRQ", level);
27167afe775SBenjamin Herrenschmidt         ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level);
27267afe775SBenjamin Herrenschmidt         break;
27367afe775SBenjamin Herrenschmidt     default:
2747279810bSCédric Le Goater         g_assert_not_reached();
275af96d2e6SCédric Le Goater         return;
27667afe775SBenjamin Herrenschmidt     }
27767afe775SBenjamin Herrenschmidt }
27867afe775SBenjamin Herrenschmidt 
27967afe775SBenjamin Herrenschmidt void ppcPOWER9_irq_init(PowerPCCPU *cpu)
28067afe775SBenjamin Herrenschmidt {
2819fd0122eSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), power9_set_irq, POWER9_INPUT_NB);
28267afe775SBenjamin Herrenschmidt }
28353018216SPaolo Bonzini #endif /* defined(TARGET_PPC64) */
28453018216SPaolo Bonzini 
28552144b69SThomas Huth void ppc40x_core_reset(PowerPCCPU *cpu)
28652144b69SThomas Huth {
28752144b69SThomas Huth     CPUPPCState *env = &cpu->env;
28852144b69SThomas Huth     target_ulong dbsr;
28952144b69SThomas Huth 
29052144b69SThomas Huth     qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n");
29152144b69SThomas Huth     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
29252144b69SThomas Huth     dbsr = env->spr[SPR_40x_DBSR];
29352144b69SThomas Huth     dbsr &= ~0x00000300;
29452144b69SThomas Huth     dbsr |= 0x00000100;
29552144b69SThomas Huth     env->spr[SPR_40x_DBSR] = dbsr;
29652144b69SThomas Huth }
29752144b69SThomas Huth 
29852144b69SThomas Huth void ppc40x_chip_reset(PowerPCCPU *cpu)
29952144b69SThomas Huth {
30052144b69SThomas Huth     CPUPPCState *env = &cpu->env;
30152144b69SThomas Huth     target_ulong dbsr;
30252144b69SThomas Huth 
30352144b69SThomas Huth     qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n");
30452144b69SThomas Huth     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
30552144b69SThomas Huth     /* XXX: TODO reset all internal peripherals */
30652144b69SThomas Huth     dbsr = env->spr[SPR_40x_DBSR];
30752144b69SThomas Huth     dbsr &= ~0x00000300;
30852144b69SThomas Huth     dbsr |= 0x00000200;
30952144b69SThomas Huth     env->spr[SPR_40x_DBSR] = dbsr;
31052144b69SThomas Huth }
31152144b69SThomas Huth 
31252144b69SThomas Huth void ppc40x_system_reset(PowerPCCPU *cpu)
31352144b69SThomas Huth {
31452144b69SThomas Huth     qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n");
31552144b69SThomas Huth     qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
31652144b69SThomas Huth }
31752144b69SThomas Huth 
31852144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val)
31952144b69SThomas Huth {
320db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
32152144b69SThomas Huth 
3225ae3d2e8SThomas Huth     qemu_mutex_lock_iothread();
3235ae3d2e8SThomas Huth 
32452144b69SThomas Huth     switch ((val >> 28) & 0x3) {
32552144b69SThomas Huth     case 0x0:
32652144b69SThomas Huth         /* No action */
32752144b69SThomas Huth         break;
32852144b69SThomas Huth     case 0x1:
32952144b69SThomas Huth         /* Core reset */
33052144b69SThomas Huth         ppc40x_core_reset(cpu);
33152144b69SThomas Huth         break;
33252144b69SThomas Huth     case 0x2:
33352144b69SThomas Huth         /* Chip reset */
33452144b69SThomas Huth         ppc40x_chip_reset(cpu);
33552144b69SThomas Huth         break;
33652144b69SThomas Huth     case 0x3:
33752144b69SThomas Huth         /* System reset */
33852144b69SThomas Huth         ppc40x_system_reset(cpu);
33952144b69SThomas Huth         break;
34052144b69SThomas Huth     }
3415ae3d2e8SThomas Huth 
3425ae3d2e8SThomas Huth     qemu_mutex_unlock_iothread();
34352144b69SThomas Huth }
34452144b69SThomas Huth 
34553018216SPaolo Bonzini /* PowerPC 40x internal IRQ controller */
34653018216SPaolo Bonzini static void ppc40x_set_irq(void *opaque, int pin, int level)
34753018216SPaolo Bonzini {
34853018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
34953018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
35053018216SPaolo Bonzini     int cur_level;
35153018216SPaolo Bonzini 
352af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
353af96d2e6SCédric Le Goater 
35453018216SPaolo Bonzini     cur_level = (env->irq_input_state >> pin) & 1;
35553018216SPaolo Bonzini     /* Don't generate spurious events */
35653018216SPaolo Bonzini     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
357259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
358259186a7SAndreas Färber 
35953018216SPaolo Bonzini         switch (pin) {
36053018216SPaolo Bonzini         case PPC40x_INPUT_RESET_SYS:
36153018216SPaolo Bonzini             if (level) {
362af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("system");
36353018216SPaolo Bonzini                 ppc40x_system_reset(cpu);
36453018216SPaolo Bonzini             }
36553018216SPaolo Bonzini             break;
36653018216SPaolo Bonzini         case PPC40x_INPUT_RESET_CHIP:
36753018216SPaolo Bonzini             if (level) {
368af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("chip");
36953018216SPaolo Bonzini                 ppc40x_chip_reset(cpu);
37053018216SPaolo Bonzini             }
37153018216SPaolo Bonzini             break;
37253018216SPaolo Bonzini         case PPC40x_INPUT_RESET_CORE:
37353018216SPaolo Bonzini             /* XXX: TODO: update DBSR[MRR] */
37453018216SPaolo Bonzini             if (level) {
375af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("core");
37653018216SPaolo Bonzini                 ppc40x_core_reset(cpu);
37753018216SPaolo Bonzini             }
37853018216SPaolo Bonzini             break;
37953018216SPaolo Bonzini         case PPC40x_INPUT_CINT:
38053018216SPaolo Bonzini             /* Level sensitive - active high */
381af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("critical IRQ", level);
38253018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
38353018216SPaolo Bonzini             break;
38453018216SPaolo Bonzini         case PPC40x_INPUT_INT:
38553018216SPaolo Bonzini             /* Level sensitive - active high */
386af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("external IRQ", level);
38753018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
38853018216SPaolo Bonzini             break;
38953018216SPaolo Bonzini         case PPC40x_INPUT_HALT:
39053018216SPaolo Bonzini             /* Level sensitive - active low */
39153018216SPaolo Bonzini             if (level) {
392af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("stop");
393259186a7SAndreas Färber                 cs->halted = 1;
39453018216SPaolo Bonzini             } else {
395af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("restart");
396259186a7SAndreas Färber                 cs->halted = 0;
397259186a7SAndreas Färber                 qemu_cpu_kick(cs);
39853018216SPaolo Bonzini             }
39953018216SPaolo Bonzini             break;
40053018216SPaolo Bonzini         case PPC40x_INPUT_DEBUG:
40153018216SPaolo Bonzini             /* Level sensitive - active high */
402af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("debug pin", level);
40353018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
40453018216SPaolo Bonzini             break;
40553018216SPaolo Bonzini         default:
4067279810bSCédric Le Goater             g_assert_not_reached();
40753018216SPaolo Bonzini         }
40853018216SPaolo Bonzini         if (level)
40953018216SPaolo Bonzini             env->irq_input_state |= 1 << pin;
41053018216SPaolo Bonzini         else
41153018216SPaolo Bonzini             env->irq_input_state &= ~(1 << pin);
41253018216SPaolo Bonzini     }
41353018216SPaolo Bonzini }
41453018216SPaolo Bonzini 
415aa5a9e24SPaolo Bonzini void ppc40x_irq_init(PowerPCCPU *cpu)
41653018216SPaolo Bonzini {
41747b60fc6SCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppc40x_set_irq, PPC40x_INPUT_NB);
41853018216SPaolo Bonzini }
41953018216SPaolo Bonzini 
42053018216SPaolo Bonzini /* PowerPC E500 internal IRQ controller */
42153018216SPaolo Bonzini static void ppce500_set_irq(void *opaque, int pin, int level)
42253018216SPaolo Bonzini {
42353018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
42453018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
42553018216SPaolo Bonzini     int cur_level;
42653018216SPaolo Bonzini 
427af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
428af96d2e6SCédric Le Goater 
42953018216SPaolo Bonzini     cur_level = (env->irq_input_state >> pin) & 1;
43053018216SPaolo Bonzini     /* Don't generate spurious events */
43153018216SPaolo Bonzini     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
43253018216SPaolo Bonzini         switch (pin) {
43353018216SPaolo Bonzini         case PPCE500_INPUT_MCK:
43453018216SPaolo Bonzini             if (level) {
435af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("system");
436cf83f140SEric Blake                 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
43753018216SPaolo Bonzini             }
43853018216SPaolo Bonzini             break;
43953018216SPaolo Bonzini         case PPCE500_INPUT_RESET_CORE:
44053018216SPaolo Bonzini             if (level) {
441af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("core");
44253018216SPaolo Bonzini                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level);
44353018216SPaolo Bonzini             }
44453018216SPaolo Bonzini             break;
44553018216SPaolo Bonzini         case PPCE500_INPUT_CINT:
44653018216SPaolo Bonzini             /* Level sensitive - active high */
447af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("critical IRQ", level);
44853018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
44953018216SPaolo Bonzini             break;
45053018216SPaolo Bonzini         case PPCE500_INPUT_INT:
45153018216SPaolo Bonzini             /* Level sensitive - active high */
452af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("core IRQ", level);
45353018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
45453018216SPaolo Bonzini             break;
45553018216SPaolo Bonzini         case PPCE500_INPUT_DEBUG:
45653018216SPaolo Bonzini             /* Level sensitive - active high */
457af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("debug pin", level);
45853018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
45953018216SPaolo Bonzini             break;
46053018216SPaolo Bonzini         default:
4617279810bSCédric Le Goater             g_assert_not_reached();
46253018216SPaolo Bonzini         }
46353018216SPaolo Bonzini         if (level)
46453018216SPaolo Bonzini             env->irq_input_state |= 1 << pin;
46553018216SPaolo Bonzini         else
46653018216SPaolo Bonzini             env->irq_input_state &= ~(1 << pin);
46753018216SPaolo Bonzini     }
46853018216SPaolo Bonzini }
46953018216SPaolo Bonzini 
470aa5a9e24SPaolo Bonzini void ppce500_irq_init(PowerPCCPU *cpu)
47153018216SPaolo Bonzini {
4725e66cd0cSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppce500_set_irq, PPCE500_INPUT_NB);
47353018216SPaolo Bonzini }
47453018216SPaolo Bonzini 
47553018216SPaolo Bonzini /* Enable or Disable the E500 EPR capability */
47653018216SPaolo Bonzini void ppce500_set_mpic_proxy(bool enabled)
47753018216SPaolo Bonzini {
478182735efSAndreas Färber     CPUState *cs;
47953018216SPaolo Bonzini 
480bdc44640SAndreas Färber     CPU_FOREACH(cs) {
481182735efSAndreas Färber         PowerPCCPU *cpu = POWERPC_CPU(cs);
48253018216SPaolo Bonzini 
483182735efSAndreas Färber         cpu->env.mpic_proxy = enabled;
48453018216SPaolo Bonzini         if (kvm_enabled()) {
485182735efSAndreas Färber             kvmppc_set_mpic_proxy(cpu, enabled);
48653018216SPaolo Bonzini         }
48753018216SPaolo Bonzini     }
48853018216SPaolo Bonzini }
48953018216SPaolo Bonzini 
49053018216SPaolo Bonzini /*****************************************************************************/
49153018216SPaolo Bonzini /* PowerPC time base and decrementer emulation */
49253018216SPaolo Bonzini 
49353018216SPaolo Bonzini uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
49453018216SPaolo Bonzini {
49553018216SPaolo Bonzini     /* TB time in tb periods */
49673bcb24dSRutuja Shah     return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset;
49753018216SPaolo Bonzini }
49853018216SPaolo Bonzini 
49953018216SPaolo Bonzini uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
50053018216SPaolo Bonzini {
50153018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
50253018216SPaolo Bonzini     uint64_t tb;
50353018216SPaolo Bonzini 
50453018216SPaolo Bonzini     if (kvm_enabled()) {
50553018216SPaolo Bonzini         return env->spr[SPR_TBL];
50653018216SPaolo Bonzini     }
50753018216SPaolo Bonzini 
508bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
509af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
51053018216SPaolo Bonzini 
51153018216SPaolo Bonzini     return tb;
51253018216SPaolo Bonzini }
51353018216SPaolo Bonzini 
51453018216SPaolo Bonzini static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env)
51553018216SPaolo Bonzini {
51653018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
51753018216SPaolo Bonzini     uint64_t tb;
51853018216SPaolo Bonzini 
519bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
520af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
52153018216SPaolo Bonzini 
52253018216SPaolo Bonzini     return tb >> 32;
52353018216SPaolo Bonzini }
52453018216SPaolo Bonzini 
52553018216SPaolo Bonzini uint32_t cpu_ppc_load_tbu (CPUPPCState *env)
52653018216SPaolo Bonzini {
52753018216SPaolo Bonzini     if (kvm_enabled()) {
52853018216SPaolo Bonzini         return env->spr[SPR_TBU];
52953018216SPaolo Bonzini     }
53053018216SPaolo Bonzini 
53153018216SPaolo Bonzini     return _cpu_ppc_load_tbu(env);
53253018216SPaolo Bonzini }
53353018216SPaolo Bonzini 
53453018216SPaolo Bonzini static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
53553018216SPaolo Bonzini                                     int64_t *tb_offsetp, uint64_t value)
53653018216SPaolo Bonzini {
53773bcb24dSRutuja Shah     *tb_offsetp = value -
53873bcb24dSRutuja Shah         muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND);
53973bcb24dSRutuja Shah 
540af96d2e6SCédric Le Goater     trace_ppc_tb_store(value, *tb_offsetp);
54153018216SPaolo Bonzini }
54253018216SPaolo Bonzini 
54353018216SPaolo Bonzini void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value)
54453018216SPaolo Bonzini {
54553018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
54653018216SPaolo Bonzini     uint64_t tb;
54753018216SPaolo Bonzini 
548bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
54953018216SPaolo Bonzini     tb &= 0xFFFFFFFF00000000ULL;
550bc72ad67SAlex Bligh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
55153018216SPaolo Bonzini                      &tb_env->tb_offset, tb | (uint64_t)value);
55253018216SPaolo Bonzini }
55353018216SPaolo Bonzini 
55453018216SPaolo Bonzini static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value)
55553018216SPaolo Bonzini {
55653018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
55753018216SPaolo Bonzini     uint64_t tb;
55853018216SPaolo Bonzini 
559bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
56053018216SPaolo Bonzini     tb &= 0x00000000FFFFFFFFULL;
561bc72ad67SAlex Bligh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
56253018216SPaolo Bonzini                      &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
56353018216SPaolo Bonzini }
56453018216SPaolo Bonzini 
56553018216SPaolo Bonzini void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value)
56653018216SPaolo Bonzini {
56753018216SPaolo Bonzini     _cpu_ppc_store_tbu(env, value);
56853018216SPaolo Bonzini }
56953018216SPaolo Bonzini 
57053018216SPaolo Bonzini uint64_t cpu_ppc_load_atbl (CPUPPCState *env)
57153018216SPaolo Bonzini {
57253018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
57353018216SPaolo Bonzini     uint64_t tb;
57453018216SPaolo Bonzini 
575bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
576af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
57753018216SPaolo Bonzini 
57853018216SPaolo Bonzini     return tb;
57953018216SPaolo Bonzini }
58053018216SPaolo Bonzini 
58153018216SPaolo Bonzini uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
58253018216SPaolo Bonzini {
58353018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
58453018216SPaolo Bonzini     uint64_t tb;
58553018216SPaolo Bonzini 
586bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
587af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
58853018216SPaolo Bonzini 
58953018216SPaolo Bonzini     return tb >> 32;
59053018216SPaolo Bonzini }
59153018216SPaolo Bonzini 
59253018216SPaolo Bonzini void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value)
59353018216SPaolo Bonzini {
59453018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
59553018216SPaolo Bonzini     uint64_t tb;
59653018216SPaolo Bonzini 
597bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
59853018216SPaolo Bonzini     tb &= 0xFFFFFFFF00000000ULL;
599bc72ad67SAlex Bligh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
60053018216SPaolo Bonzini                      &tb_env->atb_offset, tb | (uint64_t)value);
60153018216SPaolo Bonzini }
60253018216SPaolo Bonzini 
60353018216SPaolo Bonzini void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
60453018216SPaolo Bonzini {
60553018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
60653018216SPaolo Bonzini     uint64_t tb;
60753018216SPaolo Bonzini 
608bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
60953018216SPaolo Bonzini     tb &= 0x00000000FFFFFFFFULL;
610bc72ad67SAlex Bligh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
61153018216SPaolo Bonzini                      &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
61253018216SPaolo Bonzini }
61353018216SPaolo Bonzini 
6145d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env)
6155d62725bSSuraj Jitindar Singh {
6165d62725bSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
6175d62725bSSuraj Jitindar Singh 
6185d62725bSSuraj Jitindar Singh     return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
6195d62725bSSuraj Jitindar Singh                           tb_env->vtb_offset);
6205d62725bSSuraj Jitindar Singh }
6215d62725bSSuraj Jitindar Singh 
6225d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value)
6235d62725bSSuraj Jitindar Singh {
6245d62725bSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
6255d62725bSSuraj Jitindar Singh 
6265d62725bSSuraj Jitindar Singh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
6275d62725bSSuraj Jitindar Singh                      &tb_env->vtb_offset, value);
6285d62725bSSuraj Jitindar Singh }
6295d62725bSSuraj Jitindar Singh 
630f0ec31b1SSuraj Jitindar Singh void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value)
631f0ec31b1SSuraj Jitindar Singh {
632f0ec31b1SSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
633f0ec31b1SSuraj Jitindar Singh     uint64_t tb;
634f0ec31b1SSuraj Jitindar Singh 
635f0ec31b1SSuraj Jitindar Singh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
636f0ec31b1SSuraj Jitindar Singh                         tb_env->tb_offset);
637f0ec31b1SSuraj Jitindar Singh     tb &= 0xFFFFFFUL;
638f0ec31b1SSuraj Jitindar Singh     tb |= (value & ~0xFFFFFFUL);
639f0ec31b1SSuraj Jitindar Singh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
640f0ec31b1SSuraj Jitindar Singh                      &tb_env->tb_offset, tb);
641f0ec31b1SSuraj Jitindar Singh }
642f0ec31b1SSuraj Jitindar Singh 
64353018216SPaolo Bonzini static void cpu_ppc_tb_stop (CPUPPCState *env)
64453018216SPaolo Bonzini {
64553018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
64653018216SPaolo Bonzini     uint64_t tb, atb, vmclk;
64753018216SPaolo Bonzini 
64853018216SPaolo Bonzini     /* If the time base is already frozen, do nothing */
64953018216SPaolo Bonzini     if (tb_env->tb_freq != 0) {
650bc72ad67SAlex Bligh         vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
65153018216SPaolo Bonzini         /* Get the time base */
65253018216SPaolo Bonzini         tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
65353018216SPaolo Bonzini         /* Get the alternate time base */
65453018216SPaolo Bonzini         atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
65553018216SPaolo Bonzini         /* Store the time base value (ie compute the current offset) */
65653018216SPaolo Bonzini         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
65753018216SPaolo Bonzini         /* Store the alternate time base value (compute the current offset) */
65853018216SPaolo Bonzini         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
65953018216SPaolo Bonzini         /* Set the time base frequency to zero */
66053018216SPaolo Bonzini         tb_env->tb_freq = 0;
66153018216SPaolo Bonzini         /* Now, the time bases are frozen to tb_offset / atb_offset value */
66253018216SPaolo Bonzini     }
66353018216SPaolo Bonzini }
66453018216SPaolo Bonzini 
66553018216SPaolo Bonzini static void cpu_ppc_tb_start (CPUPPCState *env)
66653018216SPaolo Bonzini {
66753018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
66853018216SPaolo Bonzini     uint64_t tb, atb, vmclk;
66953018216SPaolo Bonzini 
67053018216SPaolo Bonzini     /* If the time base is not frozen, do nothing */
67153018216SPaolo Bonzini     if (tb_env->tb_freq == 0) {
672bc72ad67SAlex Bligh         vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
67353018216SPaolo Bonzini         /* Get the time base from tb_offset */
67453018216SPaolo Bonzini         tb = tb_env->tb_offset;
67553018216SPaolo Bonzini         /* Get the alternate time base from atb_offset */
67653018216SPaolo Bonzini         atb = tb_env->atb_offset;
67753018216SPaolo Bonzini         /* Restore the tb frequency from the decrementer frequency */
67853018216SPaolo Bonzini         tb_env->tb_freq = tb_env->decr_freq;
67953018216SPaolo Bonzini         /* Store the time base value */
68053018216SPaolo Bonzini         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
68153018216SPaolo Bonzini         /* Store the alternate time base value */
68253018216SPaolo Bonzini         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
68353018216SPaolo Bonzini     }
68453018216SPaolo Bonzini }
68553018216SPaolo Bonzini 
686e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env)
687e81a982aSAlexander Graf {
688e81a982aSAlexander Graf     ppc_tb_t *tb_env = env->tb_env;
689e81a982aSAlexander Graf     int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL;
690e81a982aSAlexander Graf     return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
691e81a982aSAlexander Graf }
692e81a982aSAlexander Graf 
693a8dafa52SSuraj Jitindar Singh static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
69453018216SPaolo Bonzini {
69553018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
696a8dafa52SSuraj Jitindar Singh     int64_t decr, diff;
69753018216SPaolo Bonzini 
698bc72ad67SAlex Bligh     diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
69953018216SPaolo Bonzini     if (diff >= 0) {
70073bcb24dSRutuja Shah         decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND);
70153018216SPaolo Bonzini     } else if (tb_env->flags & PPC_TIMER_BOOKE) {
70253018216SPaolo Bonzini         decr = 0;
70353018216SPaolo Bonzini     }  else {
70473bcb24dSRutuja Shah         decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND);
70553018216SPaolo Bonzini     }
706af96d2e6SCédric Le Goater     trace_ppc_decr_load(decr);
70753018216SPaolo Bonzini 
70853018216SPaolo Bonzini     return decr;
70953018216SPaolo Bonzini }
71053018216SPaolo Bonzini 
711a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_decr(CPUPPCState *env)
71253018216SPaolo Bonzini {
71353018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
714a8dafa52SSuraj Jitindar Singh     uint64_t decr;
71553018216SPaolo Bonzini 
71653018216SPaolo Bonzini     if (kvm_enabled()) {
71753018216SPaolo Bonzini         return env->spr[SPR_DECR];
71853018216SPaolo Bonzini     }
71953018216SPaolo Bonzini 
720a8dafa52SSuraj Jitindar Singh     decr = _cpu_ppc_load_decr(env, tb_env->decr_next);
721a8dafa52SSuraj Jitindar Singh 
722a8dafa52SSuraj Jitindar Singh     /*
723a8dafa52SSuraj Jitindar Singh      * If large decrementer is enabled then the decrementer is signed extened
724a8dafa52SSuraj Jitindar Singh      * to 64 bits, otherwise it is a 32 bit value.
725a8dafa52SSuraj Jitindar Singh      */
726a8dafa52SSuraj Jitindar Singh     if (env->spr[SPR_LPCR] & LPCR_LD) {
727a8dafa52SSuraj Jitindar Singh         return decr;
728a8dafa52SSuraj Jitindar Singh     }
729a8dafa52SSuraj Jitindar Singh     return (uint32_t) decr;
73053018216SPaolo Bonzini }
73153018216SPaolo Bonzini 
732a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_hdecr(CPUPPCState *env)
73353018216SPaolo Bonzini {
734db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
735a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
73653018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
737a8dafa52SSuraj Jitindar Singh     uint64_t hdecr;
73853018216SPaolo Bonzini 
739a8dafa52SSuraj Jitindar Singh     hdecr =  _cpu_ppc_load_decr(env, tb_env->hdecr_next);
740a8dafa52SSuraj Jitindar Singh 
741a8dafa52SSuraj Jitindar Singh     /*
742a8dafa52SSuraj Jitindar Singh      * If we have a large decrementer (POWER9 or later) then hdecr is sign
743a8dafa52SSuraj Jitindar Singh      * extended to 64 bits, otherwise it is 32 bits.
744a8dafa52SSuraj Jitindar Singh      */
745a8dafa52SSuraj Jitindar Singh     if (pcc->lrg_decr_bits > 32) {
746a8dafa52SSuraj Jitindar Singh         return hdecr;
747a8dafa52SSuraj Jitindar Singh     }
748a8dafa52SSuraj Jitindar Singh     return (uint32_t) hdecr;
74953018216SPaolo Bonzini }
75053018216SPaolo Bonzini 
75153018216SPaolo Bonzini uint64_t cpu_ppc_load_purr (CPUPPCState *env)
75253018216SPaolo Bonzini {
75353018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
75453018216SPaolo Bonzini 
7555cc7e69fSSuraj Jitindar Singh     return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
7565cc7e69fSSuraj Jitindar Singh                           tb_env->purr_offset);
75753018216SPaolo Bonzini }
75853018216SPaolo Bonzini 
75953018216SPaolo Bonzini /* When decrementer expires,
76053018216SPaolo Bonzini  * all we need to do is generate or queue a CPU exception
76153018216SPaolo Bonzini  */
76253018216SPaolo Bonzini static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
76353018216SPaolo Bonzini {
76453018216SPaolo Bonzini     /* Raise it */
765af96d2e6SCédric Le Goater     trace_ppc_decr_excp("raise");
76653018216SPaolo Bonzini     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
76753018216SPaolo Bonzini }
76853018216SPaolo Bonzini 
769e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu)
770e81a982aSAlexander Graf {
771e81a982aSAlexander Graf     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
772e81a982aSAlexander Graf }
773e81a982aSAlexander Graf 
77453018216SPaolo Bonzini static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
77553018216SPaolo Bonzini {
7764b236b62SBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
7774b236b62SBenjamin Herrenschmidt 
77853018216SPaolo Bonzini     /* Raise it */
779af96d2e6SCédric Le Goater     trace_ppc_decr_excp("raise HV");
7804b236b62SBenjamin Herrenschmidt 
7814b236b62SBenjamin Herrenschmidt     /* The architecture specifies that we don't deliver HDEC
7824b236b62SBenjamin Herrenschmidt      * interrupts in a PM state. Not only they don't cause a
7834b236b62SBenjamin Herrenschmidt      * wakeup but they also get effectively discarded.
7844b236b62SBenjamin Herrenschmidt      */
7851e7fd61dSBenjamin Herrenschmidt     if (!env->resume_as_sreset) {
78653018216SPaolo Bonzini         ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
78753018216SPaolo Bonzini     }
7884b236b62SBenjamin Herrenschmidt }
78953018216SPaolo Bonzini 
790e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
791e81a982aSAlexander Graf {
792e81a982aSAlexander Graf     ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
793e81a982aSAlexander Graf }
794e81a982aSAlexander Graf 
79553018216SPaolo Bonzini static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
7961246b259SStefan Weil                                  QEMUTimer *timer,
797e81a982aSAlexander Graf                                  void (*raise_excp)(void *),
798e81a982aSAlexander Graf                                  void (*lower_excp)(PowerPCCPU *),
799a8dafa52SSuraj Jitindar Singh                                  target_ulong decr, target_ulong value,
800a8dafa52SSuraj Jitindar Singh                                  int nr_bits)
80153018216SPaolo Bonzini {
80253018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
80353018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
80453018216SPaolo Bonzini     uint64_t now, next;
8054d9b8ef9SCédric Le Goater     int64_t signed_value;
8064d9b8ef9SCédric Le Goater     int64_t signed_decr;
80753018216SPaolo Bonzini 
808a8dafa52SSuraj Jitindar Singh     /* Truncate value to decr_width and sign extend for simplicity */
8094d9b8ef9SCédric Le Goater     signed_value = sextract64(value, 0, nr_bits);
8104d9b8ef9SCédric Le Goater     signed_decr = sextract64(decr, 0, nr_bits);
811a8dafa52SSuraj Jitindar Singh 
812af96d2e6SCédric Le Goater     trace_ppc_decr_store(nr_bits, decr, value);
81353018216SPaolo Bonzini 
81453018216SPaolo Bonzini     if (kvm_enabled()) {
81553018216SPaolo Bonzini         /* KVM handles decrementer exceptions, we don't need our own timer */
81653018216SPaolo Bonzini         return;
81753018216SPaolo Bonzini     }
81853018216SPaolo Bonzini 
819e81a982aSAlexander Graf     /*
820e81a982aSAlexander Graf      * Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC
821e81a982aSAlexander Graf      * interrupt.
822e81a982aSAlexander Graf      *
823e81a982aSAlexander Graf      * If we get a really small DEC value, we can assume that by the time we
824e81a982aSAlexander Graf      * handled it we should inject an interrupt already.
825e81a982aSAlexander Graf      *
826e81a982aSAlexander Graf      * On MSB level based DEC implementations the MSB always means the interrupt
827e81a982aSAlexander Graf      * is pending, so raise it on those.
828e81a982aSAlexander Graf      *
829e81a982aSAlexander Graf      * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
830e81a982aSAlexander Graf      * an edge interrupt, so raise it here too.
831e81a982aSAlexander Graf      */
832a8dcb8daSCédric Le Goater     if ((value < 3) ||
8334d9b8ef9SCédric Le Goater         ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) ||
8344d9b8ef9SCédric Le Goater         ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0
8354d9b8ef9SCédric Le Goater           && signed_decr >= 0)) {
836e81a982aSAlexander Graf         (*raise_excp)(cpu);
837e81a982aSAlexander Graf         return;
838e81a982aSAlexander Graf     }
839e81a982aSAlexander Graf 
840e81a982aSAlexander Graf     /* On MSB level based systems a 0 for the MSB stops interrupt delivery */
8414d9b8ef9SCédric Le Goater     if (signed_value >= 0 && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
842e81a982aSAlexander Graf         (*lower_excp)(cpu);
843e81a982aSAlexander Graf     }
844e81a982aSAlexander Graf 
845e81a982aSAlexander Graf     /* Calculate the next timer event */
846bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
84773bcb24dSRutuja Shah     next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq);
84853018216SPaolo Bonzini     *nextp = next;
849e81a982aSAlexander Graf 
85053018216SPaolo Bonzini     /* Adjust timer */
851bc72ad67SAlex Bligh     timer_mod(timer, next);
85253018216SPaolo Bonzini }
85353018216SPaolo Bonzini 
854a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr,
855a8dafa52SSuraj Jitindar Singh                                        target_ulong value, int nr_bits)
85653018216SPaolo Bonzini {
85753018216SPaolo Bonzini     ppc_tb_t *tb_env = cpu->env.tb_env;
85853018216SPaolo Bonzini 
85953018216SPaolo Bonzini     __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
860e81a982aSAlexander Graf                          tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr,
861a8dafa52SSuraj Jitindar Singh                          value, nr_bits);
86253018216SPaolo Bonzini }
86353018216SPaolo Bonzini 
864a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value)
86553018216SPaolo Bonzini {
866db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
867a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
868a8dafa52SSuraj Jitindar Singh     int nr_bits = 32;
86953018216SPaolo Bonzini 
870a8dafa52SSuraj Jitindar Singh     if (env->spr[SPR_LPCR] & LPCR_LD) {
871a8dafa52SSuraj Jitindar Singh         nr_bits = pcc->lrg_decr_bits;
872a8dafa52SSuraj Jitindar Singh     }
873a8dafa52SSuraj Jitindar Singh 
874a8dafa52SSuraj Jitindar Singh     _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, nr_bits);
87553018216SPaolo Bonzini }
87653018216SPaolo Bonzini 
87753018216SPaolo Bonzini static void cpu_ppc_decr_cb(void *opaque)
87853018216SPaolo Bonzini {
87953018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
88053018216SPaolo Bonzini 
881e81a982aSAlexander Graf     cpu_ppc_decr_excp(cpu);
88253018216SPaolo Bonzini }
88353018216SPaolo Bonzini 
884a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr,
885a8dafa52SSuraj Jitindar Singh                                         target_ulong value, int nr_bits)
88653018216SPaolo Bonzini {
88753018216SPaolo Bonzini     ppc_tb_t *tb_env = cpu->env.tb_env;
88853018216SPaolo Bonzini 
88953018216SPaolo Bonzini     if (tb_env->hdecr_timer != NULL) {
89053018216SPaolo Bonzini         __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
891e81a982aSAlexander Graf                              tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
892a8dafa52SSuraj Jitindar Singh                              hdecr, value, nr_bits);
89353018216SPaolo Bonzini     }
89453018216SPaolo Bonzini }
89553018216SPaolo Bonzini 
896a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value)
89753018216SPaolo Bonzini {
898db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
899a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
90053018216SPaolo Bonzini 
901a8dafa52SSuraj Jitindar Singh     _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value,
902a8dafa52SSuraj Jitindar Singh                          pcc->lrg_decr_bits);
90353018216SPaolo Bonzini }
90453018216SPaolo Bonzini 
90553018216SPaolo Bonzini static void cpu_ppc_hdecr_cb(void *opaque)
90653018216SPaolo Bonzini {
90753018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
90853018216SPaolo Bonzini 
909e81a982aSAlexander Graf     cpu_ppc_hdecr_excp(cpu);
91053018216SPaolo Bonzini }
91153018216SPaolo Bonzini 
9125cc7e69fSSuraj Jitindar Singh void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value)
91353018216SPaolo Bonzini {
9145cc7e69fSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
91553018216SPaolo Bonzini 
9165cc7e69fSSuraj Jitindar Singh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
9175cc7e69fSSuraj Jitindar Singh                      &tb_env->purr_offset, value);
91853018216SPaolo Bonzini }
91953018216SPaolo Bonzini 
92053018216SPaolo Bonzini static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
92153018216SPaolo Bonzini {
92253018216SPaolo Bonzini     CPUPPCState *env = opaque;
923db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
92453018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
92553018216SPaolo Bonzini 
92653018216SPaolo Bonzini     tb_env->tb_freq = freq;
92753018216SPaolo Bonzini     tb_env->decr_freq = freq;
92853018216SPaolo Bonzini     /* There is a bug in Linux 2.4 kernels:
92953018216SPaolo Bonzini      * if a decrementer exception is pending when it enables msr_ee at startup,
93053018216SPaolo Bonzini      * it's not ready to handle it...
93153018216SPaolo Bonzini      */
932a8dafa52SSuraj Jitindar Singh     _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
933a8dafa52SSuraj Jitindar Singh     _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
9345cc7e69fSSuraj Jitindar Singh     cpu_ppc_store_purr(env, 0x0000000000000000ULL);
93553018216SPaolo Bonzini }
93653018216SPaolo Bonzini 
93742043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb)
93898a8b524SAlexey Kardashevskiy {
9394a7428c5SChristopher Covington     uint64_t ticks = cpu_get_host_ticks();
94098a8b524SAlexey Kardashevskiy     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
94198a8b524SAlexey Kardashevskiy 
94298a8b524SAlexey Kardashevskiy     if (!first_ppc_cpu->env.tb_env) {
94398a8b524SAlexey Kardashevskiy         error_report("No timebase object");
94498a8b524SAlexey Kardashevskiy         return;
94598a8b524SAlexey Kardashevskiy     }
94698a8b524SAlexey Kardashevskiy 
94742043e4fSLaurent Vivier     /* not used anymore, we keep it for compatibility */
94877bad151SPaolo Bonzini     tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
94998a8b524SAlexey Kardashevskiy     /*
95042043e4fSLaurent Vivier      * tb_offset is only expected to be changed by QEMU so
95198a8b524SAlexey Kardashevskiy      * there is no need to update it from KVM here
95298a8b524SAlexey Kardashevskiy      */
95398a8b524SAlexey Kardashevskiy     tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
954d14f3397SMaxiwell S. Garcia 
955711dfb24SGreg Kurz     tb->runstate_paused =
956711dfb24SGreg Kurz         runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM);
95798a8b524SAlexey Kardashevskiy }
95898a8b524SAlexey Kardashevskiy 
95942043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb)
96098a8b524SAlexey Kardashevskiy {
96198a8b524SAlexey Kardashevskiy     CPUState *cpu;
96298a8b524SAlexey Kardashevskiy     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
96342043e4fSLaurent Vivier     int64_t tb_off_adj, tb_off;
96498a8b524SAlexey Kardashevskiy     unsigned long freq;
96598a8b524SAlexey Kardashevskiy 
96698a8b524SAlexey Kardashevskiy     if (!first_ppc_cpu->env.tb_env) {
96798a8b524SAlexey Kardashevskiy         error_report("No timebase object");
96842043e4fSLaurent Vivier         return;
96998a8b524SAlexey Kardashevskiy     }
97098a8b524SAlexey Kardashevskiy 
97198a8b524SAlexey Kardashevskiy     freq = first_ppc_cpu->env.tb_env->tb_freq;
97298a8b524SAlexey Kardashevskiy 
97342043e4fSLaurent Vivier     tb_off_adj = tb->guest_timebase - cpu_get_host_ticks();
97498a8b524SAlexey Kardashevskiy 
97598a8b524SAlexey Kardashevskiy     tb_off = first_ppc_cpu->env.tb_env->tb_offset;
97698a8b524SAlexey Kardashevskiy     trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off,
97798a8b524SAlexey Kardashevskiy                         (tb_off_adj - tb_off) / freq);
97898a8b524SAlexey Kardashevskiy 
97998a8b524SAlexey Kardashevskiy     /* Set new offset to all CPUs */
98098a8b524SAlexey Kardashevskiy     CPU_FOREACH(cpu) {
98198a8b524SAlexey Kardashevskiy         PowerPCCPU *pcpu = POWERPC_CPU(cpu);
98298a8b524SAlexey Kardashevskiy         pcpu->env.tb_env->tb_offset = tb_off_adj;
9839723295aSGreg Kurz         kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset);
98442043e4fSLaurent Vivier     }
98598a8b524SAlexey Kardashevskiy }
98698a8b524SAlexey Kardashevskiy 
987538f0497SPhilippe Mathieu-Daudé void cpu_ppc_clock_vm_state_change(void *opaque, bool running,
98842043e4fSLaurent Vivier                                    RunState state)
98942043e4fSLaurent Vivier {
99042043e4fSLaurent Vivier     PPCTimebase *tb = opaque;
99142043e4fSLaurent Vivier 
99242043e4fSLaurent Vivier     if (running) {
99342043e4fSLaurent Vivier         timebase_load(tb);
99442043e4fSLaurent Vivier     } else {
99542043e4fSLaurent Vivier         timebase_save(tb);
99642043e4fSLaurent Vivier     }
99742043e4fSLaurent Vivier }
99842043e4fSLaurent Vivier 
99942043e4fSLaurent Vivier /*
1000d14f3397SMaxiwell S. Garcia  * When migrating a running guest, read the clock just
1001d14f3397SMaxiwell S. Garcia  * before migration, so that the guest clock counts
1002d14f3397SMaxiwell S. Garcia  * during the events between:
100342043e4fSLaurent Vivier  *
100442043e4fSLaurent Vivier  *  * vm_stop()
100542043e4fSLaurent Vivier  *  *
100642043e4fSLaurent Vivier  *  * pre_save()
100742043e4fSLaurent Vivier  *
100842043e4fSLaurent Vivier  *  This reduces clock difference on migration from 5s
100942043e4fSLaurent Vivier  *  to 0.1s (when max_downtime == 5s), because sending the
101042043e4fSLaurent Vivier  *  final pages of memory (which happens between vm_stop()
101142043e4fSLaurent Vivier  *  and pre_save()) takes max_downtime.
101242043e4fSLaurent Vivier  */
101344b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque)
101442043e4fSLaurent Vivier {
101542043e4fSLaurent Vivier     PPCTimebase *tb = opaque;
101642043e4fSLaurent Vivier 
1017711dfb24SGreg Kurz     /* guest_timebase won't be overridden in case of paused guest or savevm */
1018d14f3397SMaxiwell S. Garcia     if (!tb->runstate_paused) {
101942043e4fSLaurent Vivier         timebase_save(tb);
1020d14f3397SMaxiwell S. Garcia     }
102144b1ff31SDr. David Alan Gilbert 
102244b1ff31SDr. David Alan Gilbert     return 0;
102398a8b524SAlexey Kardashevskiy }
102498a8b524SAlexey Kardashevskiy 
102598a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = {
102698a8b524SAlexey Kardashevskiy     .name = "timebase",
102798a8b524SAlexey Kardashevskiy     .version_id = 1,
102898a8b524SAlexey Kardashevskiy     .minimum_version_id = 1,
102998a8b524SAlexey Kardashevskiy     .pre_save = timebase_pre_save,
103098a8b524SAlexey Kardashevskiy     .fields      = (VMStateField []) {
103198a8b524SAlexey Kardashevskiy         VMSTATE_UINT64(guest_timebase, PPCTimebase),
103298a8b524SAlexey Kardashevskiy         VMSTATE_INT64(time_of_the_day_ns, PPCTimebase),
103398a8b524SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
103498a8b524SAlexey Kardashevskiy     },
103598a8b524SAlexey Kardashevskiy };
103698a8b524SAlexey Kardashevskiy 
103753018216SPaolo Bonzini /* Set up (once) timebase frequency (in Hz) */
103853018216SPaolo Bonzini clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
103953018216SPaolo Bonzini {
1040db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
104153018216SPaolo Bonzini     ppc_tb_t *tb_env;
104253018216SPaolo Bonzini 
1043b21e2380SMarkus Armbruster     tb_env = g_new0(ppc_tb_t, 1);
104453018216SPaolo Bonzini     env->tb_env = tb_env;
104553018216SPaolo Bonzini     tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
1046d0db7cadSGreg Kurz     if (is_book3s_arch2x(env)) {
1047e81a982aSAlexander Graf         /* All Book3S 64bit CPUs implement level based DEC logic */
1048e81a982aSAlexander Graf         tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
1049e81a982aSAlexander Graf     }
105053018216SPaolo Bonzini     /* Create new timer */
1051bc72ad67SAlex Bligh     tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu);
10525ff40b01SNicholas Piggin     if (env->has_hv_mode && !cpu->vhyp) {
1053bc72ad67SAlex Bligh         tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb,
105453018216SPaolo Bonzini                                                 cpu);
105553018216SPaolo Bonzini     } else {
105653018216SPaolo Bonzini         tb_env->hdecr_timer = NULL;
105753018216SPaolo Bonzini     }
105853018216SPaolo Bonzini     cpu_ppc_set_tb_clk(env, freq);
105953018216SPaolo Bonzini 
106053018216SPaolo Bonzini     return &cpu_ppc_set_tb_clk;
106153018216SPaolo Bonzini }
106253018216SPaolo Bonzini 
1063ef95a244SDaniel Henrique Barboza void cpu_ppc_tb_free(CPUPPCState *env)
1064ef95a244SDaniel Henrique Barboza {
1065ef95a244SDaniel Henrique Barboza     timer_free(env->tb_env->decr_timer);
1066ef95a244SDaniel Henrique Barboza     timer_free(env->tb_env->hdecr_timer);
1067ef95a244SDaniel Henrique Barboza     g_free(env->tb_env);
1068ef95a244SDaniel Henrique Barboza }
1069ef95a244SDaniel Henrique Barboza 
107093aeb702SNicholas Piggin /* cpu_ppc_hdecr_init may be used if the timer is not used by HDEC emulation */
107193aeb702SNicholas Piggin void cpu_ppc_hdecr_init(CPUPPCState *env)
107293aeb702SNicholas Piggin {
107393aeb702SNicholas Piggin     PowerPCCPU *cpu = env_archcpu(env);
107493aeb702SNicholas Piggin 
107593aeb702SNicholas Piggin     assert(env->tb_env->hdecr_timer == NULL);
107693aeb702SNicholas Piggin 
107793aeb702SNicholas Piggin     env->tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
107893aeb702SNicholas Piggin                                             &cpu_ppc_hdecr_cb, cpu);
107993aeb702SNicholas Piggin }
108093aeb702SNicholas Piggin 
108193aeb702SNicholas Piggin void cpu_ppc_hdecr_exit(CPUPPCState *env)
108293aeb702SNicholas Piggin {
108393aeb702SNicholas Piggin     PowerPCCPU *cpu = env_archcpu(env);
108493aeb702SNicholas Piggin 
108593aeb702SNicholas Piggin     timer_free(env->tb_env->hdecr_timer);
108693aeb702SNicholas Piggin     env->tb_env->hdecr_timer = NULL;
108793aeb702SNicholas Piggin 
108893aeb702SNicholas Piggin     cpu_ppc_hdecr_lower(cpu);
108993aeb702SNicholas Piggin }
109093aeb702SNicholas Piggin 
109153018216SPaolo Bonzini /*****************************************************************************/
109253018216SPaolo Bonzini /* PowerPC 40x timers */
109353018216SPaolo Bonzini 
109453018216SPaolo Bonzini /* PIT, FIT & WDT */
109553018216SPaolo Bonzini typedef struct ppc40x_timer_t ppc40x_timer_t;
109653018216SPaolo Bonzini struct ppc40x_timer_t {
109753018216SPaolo Bonzini     uint64_t pit_reload;  /* PIT auto-reload value        */
109853018216SPaolo Bonzini     uint64_t fit_next;    /* Tick for next FIT interrupt  */
10991246b259SStefan Weil     QEMUTimer *fit_timer;
110053018216SPaolo Bonzini     uint64_t wdt_next;    /* Tick for next WDT interrupt  */
11011246b259SStefan Weil     QEMUTimer *wdt_timer;
110253018216SPaolo Bonzini 
110353018216SPaolo Bonzini     /* 405 have the PIT, 440 have a DECR.  */
110453018216SPaolo Bonzini     unsigned int decr_excp;
110553018216SPaolo Bonzini };
110653018216SPaolo Bonzini 
110753018216SPaolo Bonzini /* Fixed interval timer */
110853018216SPaolo Bonzini static void cpu_4xx_fit_cb (void *opaque)
110953018216SPaolo Bonzini {
1110b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1111b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
111253018216SPaolo Bonzini     ppc_tb_t *tb_env;
111353018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
111453018216SPaolo Bonzini     uint64_t now, next;
111553018216SPaolo Bonzini 
111653018216SPaolo Bonzini     tb_env = env->tb_env;
111753018216SPaolo Bonzini     ppc40x_timer = tb_env->opaque;
1118bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
111953018216SPaolo Bonzini     switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
112053018216SPaolo Bonzini     case 0:
112153018216SPaolo Bonzini         next = 1 << 9;
112253018216SPaolo Bonzini         break;
112353018216SPaolo Bonzini     case 1:
112453018216SPaolo Bonzini         next = 1 << 13;
112553018216SPaolo Bonzini         break;
112653018216SPaolo Bonzini     case 2:
112753018216SPaolo Bonzini         next = 1 << 17;
112853018216SPaolo Bonzini         break;
112953018216SPaolo Bonzini     case 3:
113053018216SPaolo Bonzini         next = 1 << 21;
113153018216SPaolo Bonzini         break;
113253018216SPaolo Bonzini     default:
113353018216SPaolo Bonzini         /* Cannot occur, but makes gcc happy */
113453018216SPaolo Bonzini         return;
113553018216SPaolo Bonzini     }
113673bcb24dSRutuja Shah     next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq);
113753018216SPaolo Bonzini     if (next == now)
113853018216SPaolo Bonzini         next++;
1139bc72ad67SAlex Bligh     timer_mod(ppc40x_timer->fit_timer, next);
114053018216SPaolo Bonzini     env->spr[SPR_40x_TSR] |= 1 << 26;
114153018216SPaolo Bonzini     if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) {
114253018216SPaolo Bonzini         ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1);
114353018216SPaolo Bonzini     }
1144af96d2e6SCédric Le Goater     trace_ppc4xx_fit((int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
114553018216SPaolo Bonzini                          env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
114653018216SPaolo Bonzini }
114753018216SPaolo Bonzini 
114853018216SPaolo Bonzini /* Programmable interval timer */
114953018216SPaolo Bonzini static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
115053018216SPaolo Bonzini {
115153018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
115253018216SPaolo Bonzini     uint64_t now, next;
115353018216SPaolo Bonzini 
115453018216SPaolo Bonzini     ppc40x_timer = tb_env->opaque;
115553018216SPaolo Bonzini     if (ppc40x_timer->pit_reload <= 1 ||
115653018216SPaolo Bonzini         !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
115753018216SPaolo Bonzini         (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
115853018216SPaolo Bonzini         /* Stop PIT */
1159af96d2e6SCédric Le Goater         trace_ppc4xx_pit_stop();
1160bc72ad67SAlex Bligh         timer_del(tb_env->decr_timer);
116153018216SPaolo Bonzini     } else {
1162af96d2e6SCédric Le Goater         trace_ppc4xx_pit_start(ppc40x_timer->pit_reload);
1163bc72ad67SAlex Bligh         now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
116453018216SPaolo Bonzini         next = now + muldiv64(ppc40x_timer->pit_reload,
116573bcb24dSRutuja Shah                               NANOSECONDS_PER_SECOND, tb_env->decr_freq);
116653018216SPaolo Bonzini         if (is_excp)
116753018216SPaolo Bonzini             next += tb_env->decr_next - now;
116853018216SPaolo Bonzini         if (next == now)
116953018216SPaolo Bonzini             next++;
1170bc72ad67SAlex Bligh         timer_mod(tb_env->decr_timer, next);
117153018216SPaolo Bonzini         tb_env->decr_next = next;
117253018216SPaolo Bonzini     }
117353018216SPaolo Bonzini }
117453018216SPaolo Bonzini 
117553018216SPaolo Bonzini static void cpu_4xx_pit_cb (void *opaque)
117653018216SPaolo Bonzini {
1177b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1178b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
117953018216SPaolo Bonzini     ppc_tb_t *tb_env;
118053018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
118153018216SPaolo Bonzini 
118253018216SPaolo Bonzini     tb_env = env->tb_env;
118353018216SPaolo Bonzini     ppc40x_timer = tb_env->opaque;
118453018216SPaolo Bonzini     env->spr[SPR_40x_TSR] |= 1 << 27;
118553018216SPaolo Bonzini     if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) {
118653018216SPaolo Bonzini         ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1);
118753018216SPaolo Bonzini     }
118853018216SPaolo Bonzini     start_stop_pit(env, tb_env, 1);
1189af96d2e6SCédric Le Goater     trace_ppc4xx_pit((int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
119053018216SPaolo Bonzini            (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
119153018216SPaolo Bonzini            env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
119253018216SPaolo Bonzini            ppc40x_timer->pit_reload);
119353018216SPaolo Bonzini }
119453018216SPaolo Bonzini 
119553018216SPaolo Bonzini /* Watchdog timer */
119653018216SPaolo Bonzini static void cpu_4xx_wdt_cb (void *opaque)
119753018216SPaolo Bonzini {
1198b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1199b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
120053018216SPaolo Bonzini     ppc_tb_t *tb_env;
120153018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
120253018216SPaolo Bonzini     uint64_t now, next;
120353018216SPaolo Bonzini 
120453018216SPaolo Bonzini     tb_env = env->tb_env;
120553018216SPaolo Bonzini     ppc40x_timer = tb_env->opaque;
1206bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
120753018216SPaolo Bonzini     switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
120853018216SPaolo Bonzini     case 0:
120953018216SPaolo Bonzini         next = 1 << 17;
121053018216SPaolo Bonzini         break;
121153018216SPaolo Bonzini     case 1:
121253018216SPaolo Bonzini         next = 1 << 21;
121353018216SPaolo Bonzini         break;
121453018216SPaolo Bonzini     case 2:
121553018216SPaolo Bonzini         next = 1 << 25;
121653018216SPaolo Bonzini         break;
121753018216SPaolo Bonzini     case 3:
121853018216SPaolo Bonzini         next = 1 << 29;
121953018216SPaolo Bonzini         break;
122053018216SPaolo Bonzini     default:
122153018216SPaolo Bonzini         /* Cannot occur, but makes gcc happy */
122253018216SPaolo Bonzini         return;
122353018216SPaolo Bonzini     }
122473bcb24dSRutuja Shah     next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq);
122553018216SPaolo Bonzini     if (next == now)
122653018216SPaolo Bonzini         next++;
1227af96d2e6SCédric Le Goater     trace_ppc4xx_wdt(env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
122853018216SPaolo Bonzini     switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
122953018216SPaolo Bonzini     case 0x0:
123053018216SPaolo Bonzini     case 0x1:
1231bc72ad67SAlex Bligh         timer_mod(ppc40x_timer->wdt_timer, next);
123253018216SPaolo Bonzini         ppc40x_timer->wdt_next = next;
1233a1f7f97bSPeter Maydell         env->spr[SPR_40x_TSR] |= 1U << 31;
123453018216SPaolo Bonzini         break;
123553018216SPaolo Bonzini     case 0x2:
1236bc72ad67SAlex Bligh         timer_mod(ppc40x_timer->wdt_timer, next);
123753018216SPaolo Bonzini         ppc40x_timer->wdt_next = next;
123853018216SPaolo Bonzini         env->spr[SPR_40x_TSR] |= 1 << 30;
123953018216SPaolo Bonzini         if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) {
124053018216SPaolo Bonzini             ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1);
124153018216SPaolo Bonzini         }
124253018216SPaolo Bonzini         break;
124353018216SPaolo Bonzini     case 0x3:
124453018216SPaolo Bonzini         env->spr[SPR_40x_TSR] &= ~0x30000000;
124553018216SPaolo Bonzini         env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
124653018216SPaolo Bonzini         switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
124753018216SPaolo Bonzini         case 0x0:
124853018216SPaolo Bonzini             /* No reset */
124953018216SPaolo Bonzini             break;
125053018216SPaolo Bonzini         case 0x1: /* Core reset */
125153018216SPaolo Bonzini             ppc40x_core_reset(cpu);
125253018216SPaolo Bonzini             break;
125353018216SPaolo Bonzini         case 0x2: /* Chip reset */
125453018216SPaolo Bonzini             ppc40x_chip_reset(cpu);
125553018216SPaolo Bonzini             break;
125653018216SPaolo Bonzini         case 0x3: /* System reset */
125753018216SPaolo Bonzini             ppc40x_system_reset(cpu);
125853018216SPaolo Bonzini             break;
125953018216SPaolo Bonzini         }
126053018216SPaolo Bonzini     }
126153018216SPaolo Bonzini }
126253018216SPaolo Bonzini 
126353018216SPaolo Bonzini void store_40x_pit (CPUPPCState *env, target_ulong val)
126453018216SPaolo Bonzini {
126553018216SPaolo Bonzini     ppc_tb_t *tb_env;
126653018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
126753018216SPaolo Bonzini 
126853018216SPaolo Bonzini     tb_env = env->tb_env;
126953018216SPaolo Bonzini     ppc40x_timer = tb_env->opaque;
1270af96d2e6SCédric Le Goater     trace_ppc40x_store_pit(val);
127153018216SPaolo Bonzini     ppc40x_timer->pit_reload = val;
127253018216SPaolo Bonzini     start_stop_pit(env, tb_env, 0);
127353018216SPaolo Bonzini }
127453018216SPaolo Bonzini 
127553018216SPaolo Bonzini target_ulong load_40x_pit (CPUPPCState *env)
127653018216SPaolo Bonzini {
127753018216SPaolo Bonzini     return cpu_ppc_load_decr(env);
127853018216SPaolo Bonzini }
127953018216SPaolo Bonzini 
1280cbd8f17dSCédric Le Goater void store_40x_tsr(CPUPPCState *env, target_ulong val)
1281cbd8f17dSCédric Le Goater {
1282cbd8f17dSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1283cbd8f17dSCédric Le Goater 
1284cbd8f17dSCédric Le Goater     trace_ppc40x_store_tcr(val);
1285cbd8f17dSCédric Le Goater 
1286cbd8f17dSCédric Le Goater     env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
1287cbd8f17dSCédric Le Goater     if (val & 0x80000000) {
1288cbd8f17dSCédric Le Goater         ppc_set_irq(cpu, PPC_INTERRUPT_PIT, 0);
1289cbd8f17dSCédric Le Goater     }
1290cbd8f17dSCédric Le Goater }
1291cbd8f17dSCédric Le Goater 
1292cbd8f17dSCédric Le Goater void store_40x_tcr(CPUPPCState *env, target_ulong val)
1293cbd8f17dSCédric Le Goater {
1294cbd8f17dSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1295cbd8f17dSCédric Le Goater     ppc_tb_t *tb_env;
1296cbd8f17dSCédric Le Goater 
1297cbd8f17dSCédric Le Goater     trace_ppc40x_store_tsr(val);
1298cbd8f17dSCédric Le Goater 
1299cbd8f17dSCédric Le Goater     tb_env = env->tb_env;
1300cbd8f17dSCédric Le Goater     env->spr[SPR_40x_TCR] = val & 0xFFC00000;
1301cbd8f17dSCédric Le Goater     start_stop_pit(env, tb_env, 1);
1302cbd8f17dSCédric Le Goater     cpu_4xx_wdt_cb(cpu);
1303cbd8f17dSCédric Le Goater }
1304cbd8f17dSCédric Le Goater 
130553018216SPaolo Bonzini static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
130653018216SPaolo Bonzini {
130753018216SPaolo Bonzini     CPUPPCState *env = opaque;
130853018216SPaolo Bonzini     ppc_tb_t *tb_env = env->tb_env;
130953018216SPaolo Bonzini 
1310af96d2e6SCédric Le Goater     trace_ppc40x_set_tb_clk(freq);
131153018216SPaolo Bonzini     tb_env->tb_freq = freq;
131253018216SPaolo Bonzini     tb_env->decr_freq = freq;
131353018216SPaolo Bonzini     /* XXX: we should also update all timers */
131453018216SPaolo Bonzini }
131553018216SPaolo Bonzini 
131653018216SPaolo Bonzini clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
131753018216SPaolo Bonzini                                   unsigned int decr_excp)
131853018216SPaolo Bonzini {
131953018216SPaolo Bonzini     ppc_tb_t *tb_env;
132053018216SPaolo Bonzini     ppc40x_timer_t *ppc40x_timer;
1321b1273a5eSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1322b1273a5eSCédric Le Goater 
1323b1273a5eSCédric Le Goater     trace_ppc40x_timers_init(freq);
132453018216SPaolo Bonzini 
1325b21e2380SMarkus Armbruster     tb_env = g_new0(ppc_tb_t, 1);
1326b21e2380SMarkus Armbruster     ppc40x_timer = g_new0(ppc40x_timer_t, 1);
1327b1273a5eSCédric Le Goater 
132853018216SPaolo Bonzini     env->tb_env = tb_env;
132953018216SPaolo Bonzini     tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
133053018216SPaolo Bonzini     tb_env->tb_freq = freq;
133153018216SPaolo Bonzini     tb_env->decr_freq = freq;
133253018216SPaolo Bonzini     tb_env->opaque = ppc40x_timer;
1333b1273a5eSCédric Le Goater 
133453018216SPaolo Bonzini     /* We use decr timer for PIT */
1335b1273a5eSCédric Le Goater     tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, cpu);
133653018216SPaolo Bonzini     ppc40x_timer->fit_timer =
1337b1273a5eSCédric Le Goater         timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, cpu);
133853018216SPaolo Bonzini     ppc40x_timer->wdt_timer =
1339b1273a5eSCédric Le Goater         timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, cpu);
134053018216SPaolo Bonzini     ppc40x_timer->decr_excp = decr_excp;
134153018216SPaolo Bonzini 
134253018216SPaolo Bonzini     return &ppc_40x_set_tb_clk;
134353018216SPaolo Bonzini }
134453018216SPaolo Bonzini 
134553018216SPaolo Bonzini /*****************************************************************************/
134653018216SPaolo Bonzini /* Embedded PowerPC Device Control Registers */
134753018216SPaolo Bonzini typedef struct ppc_dcrn_t ppc_dcrn_t;
134853018216SPaolo Bonzini struct ppc_dcrn_t {
134953018216SPaolo Bonzini     dcr_read_cb dcr_read;
135053018216SPaolo Bonzini     dcr_write_cb dcr_write;
135153018216SPaolo Bonzini     void *opaque;
135253018216SPaolo Bonzini };
135353018216SPaolo Bonzini 
135453018216SPaolo Bonzini /* XXX: on 460, DCR addresses are 32 bits wide,
135553018216SPaolo Bonzini  *      using DCRIPR to get the 22 upper bits of the DCR address
135653018216SPaolo Bonzini  */
135753018216SPaolo Bonzini #define DCRN_NB 1024
135853018216SPaolo Bonzini struct ppc_dcr_t {
135953018216SPaolo Bonzini     ppc_dcrn_t dcrn[DCRN_NB];
136053018216SPaolo Bonzini     int (*read_error)(int dcrn);
136153018216SPaolo Bonzini     int (*write_error)(int dcrn);
136253018216SPaolo Bonzini };
136353018216SPaolo Bonzini 
136453018216SPaolo Bonzini int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
136553018216SPaolo Bonzini {
136653018216SPaolo Bonzini     ppc_dcrn_t *dcr;
136753018216SPaolo Bonzini 
136853018216SPaolo Bonzini     if (dcrn < 0 || dcrn >= DCRN_NB)
136953018216SPaolo Bonzini         goto error;
137053018216SPaolo Bonzini     dcr = &dcr_env->dcrn[dcrn];
137153018216SPaolo Bonzini     if (dcr->dcr_read == NULL)
137253018216SPaolo Bonzini         goto error;
137353018216SPaolo Bonzini     *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
1374de82dabeSCédric Le Goater     trace_ppc_dcr_read(dcrn, *valp);
137553018216SPaolo Bonzini 
137653018216SPaolo Bonzini     return 0;
137753018216SPaolo Bonzini 
137853018216SPaolo Bonzini  error:
137953018216SPaolo Bonzini     if (dcr_env->read_error != NULL)
138053018216SPaolo Bonzini         return (*dcr_env->read_error)(dcrn);
138153018216SPaolo Bonzini 
138253018216SPaolo Bonzini     return -1;
138353018216SPaolo Bonzini }
138453018216SPaolo Bonzini 
138553018216SPaolo Bonzini int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
138653018216SPaolo Bonzini {
138753018216SPaolo Bonzini     ppc_dcrn_t *dcr;
138853018216SPaolo Bonzini 
138953018216SPaolo Bonzini     if (dcrn < 0 || dcrn >= DCRN_NB)
139053018216SPaolo Bonzini         goto error;
139153018216SPaolo Bonzini     dcr = &dcr_env->dcrn[dcrn];
139253018216SPaolo Bonzini     if (dcr->dcr_write == NULL)
139353018216SPaolo Bonzini         goto error;
1394de82dabeSCédric Le Goater     trace_ppc_dcr_write(dcrn, val);
139553018216SPaolo Bonzini     (*dcr->dcr_write)(dcr->opaque, dcrn, val);
139653018216SPaolo Bonzini 
139753018216SPaolo Bonzini     return 0;
139853018216SPaolo Bonzini 
139953018216SPaolo Bonzini  error:
140053018216SPaolo Bonzini     if (dcr_env->write_error != NULL)
140153018216SPaolo Bonzini         return (*dcr_env->write_error)(dcrn);
140253018216SPaolo Bonzini 
140353018216SPaolo Bonzini     return -1;
140453018216SPaolo Bonzini }
140553018216SPaolo Bonzini 
140653018216SPaolo Bonzini int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
140753018216SPaolo Bonzini                       dcr_read_cb dcr_read, dcr_write_cb dcr_write)
140853018216SPaolo Bonzini {
140953018216SPaolo Bonzini     ppc_dcr_t *dcr_env;
141053018216SPaolo Bonzini     ppc_dcrn_t *dcr;
141153018216SPaolo Bonzini 
141253018216SPaolo Bonzini     dcr_env = env->dcr_env;
141353018216SPaolo Bonzini     if (dcr_env == NULL)
141453018216SPaolo Bonzini         return -1;
141553018216SPaolo Bonzini     if (dcrn < 0 || dcrn >= DCRN_NB)
141653018216SPaolo Bonzini         return -1;
141753018216SPaolo Bonzini     dcr = &dcr_env->dcrn[dcrn];
141853018216SPaolo Bonzini     if (dcr->opaque != NULL ||
141953018216SPaolo Bonzini         dcr->dcr_read != NULL ||
142053018216SPaolo Bonzini         dcr->dcr_write != NULL)
142153018216SPaolo Bonzini         return -1;
142253018216SPaolo Bonzini     dcr->opaque = opaque;
142353018216SPaolo Bonzini     dcr->dcr_read = dcr_read;
142453018216SPaolo Bonzini     dcr->dcr_write = dcr_write;
142553018216SPaolo Bonzini 
142653018216SPaolo Bonzini     return 0;
142753018216SPaolo Bonzini }
142853018216SPaolo Bonzini 
142953018216SPaolo Bonzini int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn),
143053018216SPaolo Bonzini                   int (*write_error)(int dcrn))
143153018216SPaolo Bonzini {
143253018216SPaolo Bonzini     ppc_dcr_t *dcr_env;
143353018216SPaolo Bonzini 
1434b21e2380SMarkus Armbruster     dcr_env = g_new0(ppc_dcr_t, 1);
143553018216SPaolo Bonzini     dcr_env->read_error = read_error;
143653018216SPaolo Bonzini     dcr_env->write_error = write_error;
143753018216SPaolo Bonzini     env->dcr_env = dcr_env;
143853018216SPaolo Bonzini 
143953018216SPaolo Bonzini     return 0;
144053018216SPaolo Bonzini }
144153018216SPaolo Bonzini 
144253018216SPaolo Bonzini /*****************************************************************************/
1443051e2973SCédric Le Goater 
14444a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu)
14454a89e204SCédric Le Goater {
14464a89e204SCédric Le Goater     CPUPPCState *env = &cpu->env;
14474a89e204SCédric Le Goater     return env->spr_cb[SPR_PIR].default_value;
14484a89e204SCédric Le Goater }
14494a89e204SCédric Le Goater 
1450051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
1451051e2973SCédric Le Goater {
1452051e2973SCédric Le Goater     CPUState *cs;
1453051e2973SCédric Le Goater 
1454051e2973SCédric Le Goater     CPU_FOREACH(cs) {
1455051e2973SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
1456051e2973SCédric Le Goater 
14574a89e204SCédric Le Goater         if (ppc_cpu_pir(cpu) == pir) {
1458051e2973SCédric Le Goater             return cpu;
1459051e2973SCédric Le Goater         }
1460051e2973SCédric Le Goater     }
1461051e2973SCédric Le Goater 
1462051e2973SCédric Le Goater     return NULL;
1463051e2973SCédric Le Goater }
146440177438SGreg Kurz 
146540177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu)
146640177438SGreg Kurz {
146740177438SGreg Kurz     CPUPPCState *env = &cpu->env;
146840177438SGreg Kurz 
146940177438SGreg Kurz     env->irq_input_state = 0;
147040177438SGreg Kurz     kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0);
147140177438SGreg Kurz }
1472