xref: /qemu/hw/ppc/ppc.c (revision 76d93e146768dde7e38b6e5e43c27e478ccb580e)
1a541f297Sbellard /*
2e9df014cSj_mayer  * QEMU generic PowerPC hardware System Emulator
3a541f297Sbellard  *
476a66253Sj_mayer  * Copyright (c) 2003-2007 Jocelyn Mayer
5a541f297Sbellard  *
6a541f297Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7a541f297Sbellard  * of this software and associated documentation files (the "Software"), to deal
8a541f297Sbellard  * in the Software without restriction, including without limitation the rights
9a541f297Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10a541f297Sbellard  * copies of the Software, and to permit persons to whom the Software is
11a541f297Sbellard  * furnished to do so, subject to the following conditions:
12a541f297Sbellard  *
13a541f297Sbellard  * The above copyright notice and this permission notice shall be included in
14a541f297Sbellard  * all copies or substantial portions of the Software.
15a541f297Sbellard  *
16a541f297Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17a541f297Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18a541f297Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19a541f297Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20a541f297Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21a541f297Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22a541f297Sbellard  * THE SOFTWARE.
23a541f297Sbellard  */
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"
291de7afc9SPaolo Bonzini #include "qemu/timer.h"
300ce470cdSAlexey Kardashevskiy #include "sysemu/cpus.h"
311de7afc9SPaolo Bonzini #include "qemu/log.h"
32db725815SMarkus Armbruster #include "qemu/main-loop.h"
3398a8b524SAlexey Kardashevskiy #include "qemu/error-report.h"
349c17d615SPaolo Bonzini #include "sysemu/kvm.h"
359db680f8SNicholas Piggin #include "sysemu/replay.h"
3654d31236SMarkus Armbruster #include "sysemu/runstate.h"
37fc87e185SAlexander Graf #include "kvm_ppc.h"
38d6454270SMarkus Armbruster #include "migration/vmstate.h"
3998a8b524SAlexey Kardashevskiy #include "trace.h"
40a541f297Sbellard 
41e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env);
42e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env);
43dbdd2506Sj_mayer 
44f003109fSMatheus Ferst void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
4547103572Sj_mayer {
467058581aSAndreas Färber     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 */
5050c9c512SRichard Henderson     QEMU_IOTHREAD_LOCK_GUARD();
518d04fb55SJan Kiszka 
528d04fb55SJan Kiszka     old_pending = env->pending_interrupts;
53fc87e185SAlexander Graf 
5447103572Sj_mayer     if (level) {
55f003109fSMatheus Ferst         env->pending_interrupts |= irq;
5647103572Sj_mayer     } else {
57f003109fSMatheus Ferst         env->pending_interrupts &= ~irq;
5847103572Sj_mayer     }
59fc87e185SAlexander Graf 
60fc87e185SAlexander Graf     if (old_pending != env->pending_interrupts) {
612fdedcbcSMatheus Ferst         ppc_maybe_interrupt(env);
62*76d93e14Sjianchunfu         if (kvm_enabled()) {
63f003109fSMatheus Ferst             kvmppc_set_interrupt(cpu, irq, level);
64fc87e185SAlexander Graf         }
65*76d93e14Sjianchunfu     }
66fc87e185SAlexander Graf 
67f003109fSMatheus Ferst     trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
68af96d2e6SCédric Le Goater                            CPU(cpu)->interrupt_request);
69a496775fSj_mayer }
7047103572Sj_mayer 
71e9df014cSj_mayer /* PowerPC 6xx / 7xx internal IRQ controller */
72e9df014cSj_mayer static void ppc6xx_set_irq(void *opaque, int pin, int level)
73d537cf6cSpbrook {
74a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
75a0961245SAndreas Färber     CPUPPCState *env = &cpu->env;
76e9df014cSj_mayer     int cur_level;
77d537cf6cSpbrook 
78af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
79af96d2e6SCédric Le Goater 
80e9df014cSj_mayer     cur_level = (env->irq_input_state >> pin) & 1;
81e9df014cSj_mayer     /* Don't generate spurious events */
8224be5ae3Sj_mayer     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
83259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
84259186a7SAndreas Färber 
85e9df014cSj_mayer         switch (pin) {
86dbdd2506Sj_mayer         case PPC6xx_INPUT_TBEN:
87dbdd2506Sj_mayer             /* Level sensitive - active high */
88af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("time base", level);
89dbdd2506Sj_mayer             if (level) {
90dbdd2506Sj_mayer                 cpu_ppc_tb_start(env);
91dbdd2506Sj_mayer             } else {
92dbdd2506Sj_mayer                 cpu_ppc_tb_stop(env);
93dbdd2506Sj_mayer             }
94b2bd5b20SChen Qun             break;
9524be5ae3Sj_mayer         case PPC6xx_INPUT_INT:
9624be5ae3Sj_mayer             /* Level sensitive - active high */
97af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("external IRQ", level);
987058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
99e9df014cSj_mayer             break;
10024be5ae3Sj_mayer         case PPC6xx_INPUT_SMI:
101e9df014cSj_mayer             /* Level sensitive - active high */
102af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("SMI IRQ", level);
1037058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level);
104e9df014cSj_mayer             break;
10524be5ae3Sj_mayer         case PPC6xx_INPUT_MCP:
106e9df014cSj_mayer             /* Negative edge sensitive */
107e9df014cSj_mayer             /* XXX: TODO: actual reaction may depends on HID0 status
108e9df014cSj_mayer              *            603/604/740/750: check HID0[EMCP]
109e9df014cSj_mayer              */
110e9df014cSj_mayer             if (cur_level == 1 && level == 0) {
111af96d2e6SCédric Le Goater                 trace_ppc_irq_set_state("machine check", 1);
1127058581aSAndreas Färber                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
113d537cf6cSpbrook             }
114e9df014cSj_mayer             break;
11524be5ae3Sj_mayer         case PPC6xx_INPUT_CKSTP_IN:
116e9df014cSj_mayer             /* Level sensitive - active low */
117e9df014cSj_mayer             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
118e63ecc6fSj_mayer             /* XXX: Note that the only way to restart the CPU is to reset it */
119e9df014cSj_mayer             if (level) {
120af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("stop");
121259186a7SAndreas Färber                 cs->halted = 1;
122d537cf6cSpbrook             }
12347103572Sj_mayer             break;
12424be5ae3Sj_mayer         case PPC6xx_INPUT_HRESET:
125e9df014cSj_mayer             /* Level sensitive - active low */
126e9df014cSj_mayer             if (level) {
127af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("CPU");
128c3affe56SAndreas Färber                 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
129e9df014cSj_mayer             }
13047103572Sj_mayer             break;
13124be5ae3Sj_mayer         case PPC6xx_INPUT_SRESET:
132af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("RESET IRQ", level);
1337058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
13447103572Sj_mayer             break;
135e9df014cSj_mayer         default:
1367279810bSCédric Le Goater             g_assert_not_reached();
13747103572Sj_mayer         }
138e9df014cSj_mayer         if (level)
139e9df014cSj_mayer             env->irq_input_state |= 1 << pin;
140e9df014cSj_mayer         else
141e9df014cSj_mayer             env->irq_input_state &= ~(1 << pin);
142e9df014cSj_mayer     }
143e9df014cSj_mayer }
144e9df014cSj_mayer 
145aa5a9e24SPaolo Bonzini void ppc6xx_irq_init(PowerPCCPU *cpu)
146e9df014cSj_mayer {
1470f3e0c6fSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppc6xx_set_irq, PPC6xx_INPUT_NB);
14847103572Sj_mayer }
14947103572Sj_mayer 
15000af685fSj_mayer #if defined(TARGET_PPC64)
151d0dfae6eSj_mayer /* PowerPC 970 internal IRQ controller */
152d0dfae6eSj_mayer static void ppc970_set_irq(void *opaque, int pin, int level)
153d0dfae6eSj_mayer {
154a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
155a0961245SAndreas Färber     CPUPPCState *env = &cpu->env;
156d0dfae6eSj_mayer     int cur_level;
157d0dfae6eSj_mayer 
158af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
159af96d2e6SCédric Le Goater 
160d0dfae6eSj_mayer     cur_level = (env->irq_input_state >> pin) & 1;
161d0dfae6eSj_mayer     /* Don't generate spurious events */
162d0dfae6eSj_mayer     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
163259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
164259186a7SAndreas Färber 
165d0dfae6eSj_mayer         switch (pin) {
166d0dfae6eSj_mayer         case PPC970_INPUT_INT:
167d0dfae6eSj_mayer             /* Level sensitive - active high */
168af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("external IRQ", level);
1697058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
170d0dfae6eSj_mayer             break;
171d0dfae6eSj_mayer         case PPC970_INPUT_THINT:
172d0dfae6eSj_mayer             /* Level sensitive - active high */
173af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("SMI IRQ", level);
1747058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level);
175d0dfae6eSj_mayer             break;
176d0dfae6eSj_mayer         case PPC970_INPUT_MCP:
177d0dfae6eSj_mayer             /* Negative edge sensitive */
178d0dfae6eSj_mayer             /* XXX: TODO: actual reaction may depends on HID0 status
179d0dfae6eSj_mayer              *            603/604/740/750: check HID0[EMCP]
180d0dfae6eSj_mayer              */
181d0dfae6eSj_mayer             if (cur_level == 1 && level == 0) {
182af96d2e6SCédric Le Goater                 trace_ppc_irq_set_state("machine check", 1);
1837058581aSAndreas Färber                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
184d0dfae6eSj_mayer             }
185d0dfae6eSj_mayer             break;
186d0dfae6eSj_mayer         case PPC970_INPUT_CKSTP:
187d0dfae6eSj_mayer             /* Level sensitive - active low */
188d0dfae6eSj_mayer             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
189d0dfae6eSj_mayer             if (level) {
190af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("stop");
191259186a7SAndreas Färber                 cs->halted = 1;
192d0dfae6eSj_mayer             } else {
193af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("restart");
194259186a7SAndreas Färber                 cs->halted = 0;
195259186a7SAndreas Färber                 qemu_cpu_kick(cs);
196d0dfae6eSj_mayer             }
197d0dfae6eSj_mayer             break;
198d0dfae6eSj_mayer         case PPC970_INPUT_HRESET:
199d0dfae6eSj_mayer             /* Level sensitive - active low */
200d0dfae6eSj_mayer             if (level) {
201c3affe56SAndreas Färber                 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
202d0dfae6eSj_mayer             }
203d0dfae6eSj_mayer             break;
204d0dfae6eSj_mayer         case PPC970_INPUT_SRESET:
205af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("RESET IRQ", level);
2067058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
207d0dfae6eSj_mayer             break;
208d0dfae6eSj_mayer         case PPC970_INPUT_TBEN:
209af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("TBEN IRQ", level);
210d0dfae6eSj_mayer             /* XXX: TODO */
211d0dfae6eSj_mayer             break;
212d0dfae6eSj_mayer         default:
2137279810bSCédric Le Goater             g_assert_not_reached();
214d0dfae6eSj_mayer         }
215d0dfae6eSj_mayer         if (level)
216d0dfae6eSj_mayer             env->irq_input_state |= 1 << pin;
217d0dfae6eSj_mayer         else
218d0dfae6eSj_mayer             env->irq_input_state &= ~(1 << pin);
219d0dfae6eSj_mayer     }
220d0dfae6eSj_mayer }
221d0dfae6eSj_mayer 
222aa5a9e24SPaolo Bonzini void ppc970_irq_init(PowerPCCPU *cpu)
223d0dfae6eSj_mayer {
2249fd0122eSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppc970_set_irq, PPC970_INPUT_NB);
225d0dfae6eSj_mayer }
2269d52e907SDavid Gibson 
2279d52e907SDavid Gibson /* POWER7 internal IRQ controller */
2289d52e907SDavid Gibson static void power7_set_irq(void *opaque, int pin, int level)
2299d52e907SDavid Gibson {
230a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
2319d52e907SDavid Gibson 
232af96d2e6SCédric Le Goater     trace_ppc_irq_set(&cpu->env, pin, level);
2339d52e907SDavid Gibson 
2349d52e907SDavid Gibson     switch (pin) {
2359d52e907SDavid Gibson     case POWER7_INPUT_INT:
2369d52e907SDavid Gibson         /* Level sensitive - active high */
237af96d2e6SCédric Le Goater         trace_ppc_irq_set_state("external IRQ", level);
2387058581aSAndreas Färber         ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
2399d52e907SDavid Gibson         break;
2409d52e907SDavid Gibson     default:
2417279810bSCédric Le Goater         g_assert_not_reached();
2429d52e907SDavid Gibson     }
2439d52e907SDavid Gibson }
2449d52e907SDavid Gibson 
245aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu)
2469d52e907SDavid Gibson {
2479fd0122eSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), power7_set_irq, POWER7_INPUT_NB);
2489d52e907SDavid Gibson }
24967afe775SBenjamin Herrenschmidt 
25067afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */
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();
270af96d2e6SCédric Le Goater         return;
27167afe775SBenjamin Herrenschmidt     }
27267afe775SBenjamin Herrenschmidt }
27367afe775SBenjamin Herrenschmidt 
27467afe775SBenjamin Herrenschmidt void ppcPOWER9_irq_init(PowerPCCPU *cpu)
27567afe775SBenjamin Herrenschmidt {
2769fd0122eSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), power9_set_irq, POWER9_INPUT_NB);
27767afe775SBenjamin Herrenschmidt }
27800af685fSj_mayer #endif /* defined(TARGET_PPC64) */
279d0dfae6eSj_mayer 
28052144b69SThomas Huth void ppc40x_core_reset(PowerPCCPU *cpu)
28152144b69SThomas Huth {
28252144b69SThomas Huth     CPUPPCState *env = &cpu->env;
28352144b69SThomas Huth     target_ulong dbsr;
28452144b69SThomas Huth 
28552144b69SThomas Huth     qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n");
28652144b69SThomas Huth     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
28752144b69SThomas Huth     dbsr = env->spr[SPR_40x_DBSR];
28852144b69SThomas Huth     dbsr &= ~0x00000300;
28952144b69SThomas Huth     dbsr |= 0x00000100;
29052144b69SThomas Huth     env->spr[SPR_40x_DBSR] = dbsr;
29152144b69SThomas Huth }
29252144b69SThomas Huth 
29352144b69SThomas Huth void ppc40x_chip_reset(PowerPCCPU *cpu)
29452144b69SThomas Huth {
29552144b69SThomas Huth     CPUPPCState *env = &cpu->env;
29652144b69SThomas Huth     target_ulong dbsr;
29752144b69SThomas Huth 
29852144b69SThomas Huth     qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n");
29952144b69SThomas Huth     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
30052144b69SThomas Huth     /* XXX: TODO reset all internal peripherals */
30152144b69SThomas Huth     dbsr = env->spr[SPR_40x_DBSR];
30252144b69SThomas Huth     dbsr &= ~0x00000300;
30352144b69SThomas Huth     dbsr |= 0x00000200;
30452144b69SThomas Huth     env->spr[SPR_40x_DBSR] = dbsr;
30552144b69SThomas Huth }
30652144b69SThomas Huth 
30752144b69SThomas Huth void ppc40x_system_reset(PowerPCCPU *cpu)
30852144b69SThomas Huth {
30952144b69SThomas Huth     qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n");
31052144b69SThomas Huth     qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
31152144b69SThomas Huth }
31252144b69SThomas Huth 
31352144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val)
31452144b69SThomas Huth {
315db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
31652144b69SThomas Huth 
3175ae3d2e8SThomas Huth     qemu_mutex_lock_iothread();
3185ae3d2e8SThomas Huth 
31952144b69SThomas Huth     switch ((val >> 28) & 0x3) {
32052144b69SThomas Huth     case 0x0:
32152144b69SThomas Huth         /* No action */
32252144b69SThomas Huth         break;
32352144b69SThomas Huth     case 0x1:
32452144b69SThomas Huth         /* Core reset */
32552144b69SThomas Huth         ppc40x_core_reset(cpu);
32652144b69SThomas Huth         break;
32752144b69SThomas Huth     case 0x2:
32852144b69SThomas Huth         /* Chip reset */
32952144b69SThomas Huth         ppc40x_chip_reset(cpu);
33052144b69SThomas Huth         break;
33152144b69SThomas Huth     case 0x3:
33252144b69SThomas Huth         /* System reset */
33352144b69SThomas Huth         ppc40x_system_reset(cpu);
33452144b69SThomas Huth         break;
33552144b69SThomas Huth     }
3365ae3d2e8SThomas Huth 
3375ae3d2e8SThomas Huth     qemu_mutex_unlock_iothread();
33852144b69SThomas Huth }
33952144b69SThomas Huth 
3404e290a0bSj_mayer /* PowerPC 40x internal IRQ controller */
3414e290a0bSj_mayer static void ppc40x_set_irq(void *opaque, int pin, int level)
34224be5ae3Sj_mayer {
343a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
344a0961245SAndreas Färber     CPUPPCState *env = &cpu->env;
34524be5ae3Sj_mayer     int cur_level;
34624be5ae3Sj_mayer 
347af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
348af96d2e6SCédric Le Goater 
34924be5ae3Sj_mayer     cur_level = (env->irq_input_state >> pin) & 1;
35024be5ae3Sj_mayer     /* Don't generate spurious events */
35124be5ae3Sj_mayer     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
352259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
353259186a7SAndreas Färber 
35424be5ae3Sj_mayer         switch (pin) {
3554e290a0bSj_mayer         case PPC40x_INPUT_RESET_SYS:
3568ecc7913Sj_mayer             if (level) {
357af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("system");
358f3273ba6SAndreas Färber                 ppc40x_system_reset(cpu);
3598ecc7913Sj_mayer             }
3608ecc7913Sj_mayer             break;
3614e290a0bSj_mayer         case PPC40x_INPUT_RESET_CHIP:
3628ecc7913Sj_mayer             if (level) {
363af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("chip");
364f3273ba6SAndreas Färber                 ppc40x_chip_reset(cpu);
3658ecc7913Sj_mayer             }
3668ecc7913Sj_mayer             break;
3674e290a0bSj_mayer         case PPC40x_INPUT_RESET_CORE:
36824be5ae3Sj_mayer             /* XXX: TODO: update DBSR[MRR] */
36924be5ae3Sj_mayer             if (level) {
370af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("core");
371f3273ba6SAndreas Färber                 ppc40x_core_reset(cpu);
37224be5ae3Sj_mayer             }
37324be5ae3Sj_mayer             break;
3744e290a0bSj_mayer         case PPC40x_INPUT_CINT:
37524be5ae3Sj_mayer             /* Level sensitive - active high */
376af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("critical IRQ", level);
3777058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
37824be5ae3Sj_mayer             break;
3794e290a0bSj_mayer         case PPC40x_INPUT_INT:
38024be5ae3Sj_mayer             /* Level sensitive - active high */
381af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("external IRQ", level);
3827058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
38324be5ae3Sj_mayer             break;
3844e290a0bSj_mayer         case PPC40x_INPUT_HALT:
38524be5ae3Sj_mayer             /* Level sensitive - active low */
38624be5ae3Sj_mayer             if (level) {
387af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("stop");
388259186a7SAndreas Färber                 cs->halted = 1;
38924be5ae3Sj_mayer             } else {
390af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("restart");
391259186a7SAndreas Färber                 cs->halted = 0;
392259186a7SAndreas Färber                 qemu_cpu_kick(cs);
39324be5ae3Sj_mayer             }
39424be5ae3Sj_mayer             break;
3954e290a0bSj_mayer         case PPC40x_INPUT_DEBUG:
39624be5ae3Sj_mayer             /* Level sensitive - active high */
397af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("debug pin", level);
3987058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
39924be5ae3Sj_mayer             break;
40024be5ae3Sj_mayer         default:
4017279810bSCédric Le Goater             g_assert_not_reached();
40224be5ae3Sj_mayer         }
40324be5ae3Sj_mayer         if (level)
40424be5ae3Sj_mayer             env->irq_input_state |= 1 << pin;
40524be5ae3Sj_mayer         else
40624be5ae3Sj_mayer             env->irq_input_state &= ~(1 << pin);
40724be5ae3Sj_mayer     }
40824be5ae3Sj_mayer }
40924be5ae3Sj_mayer 
410aa5a9e24SPaolo Bonzini void ppc40x_irq_init(PowerPCCPU *cpu)
41124be5ae3Sj_mayer {
41247b60fc6SCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppc40x_set_irq, PPC40x_INPUT_NB);
41324be5ae3Sj_mayer }
41424be5ae3Sj_mayer 
4159fdc60bfSaurel32 /* PowerPC E500 internal IRQ controller */
4169fdc60bfSaurel32 static void ppce500_set_irq(void *opaque, int pin, int level)
4179fdc60bfSaurel32 {
418a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
419a0961245SAndreas Färber     CPUPPCState *env = &cpu->env;
4209fdc60bfSaurel32     int cur_level;
4219fdc60bfSaurel32 
422af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
423af96d2e6SCédric Le Goater 
4249fdc60bfSaurel32     cur_level = (env->irq_input_state >> pin) & 1;
4259fdc60bfSaurel32     /* Don't generate spurious events */
4269fdc60bfSaurel32     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
4279fdc60bfSaurel32         switch (pin) {
4289fdc60bfSaurel32         case PPCE500_INPUT_MCK:
4299fdc60bfSaurel32             if (level) {
430af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("system");
431cf83f140SEric Blake                 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
4329fdc60bfSaurel32             }
4339fdc60bfSaurel32             break;
4349fdc60bfSaurel32         case PPCE500_INPUT_RESET_CORE:
4359fdc60bfSaurel32             if (level) {
436af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("core");
4377058581aSAndreas Färber                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level);
4389fdc60bfSaurel32             }
4399fdc60bfSaurel32             break;
4409fdc60bfSaurel32         case PPCE500_INPUT_CINT:
4419fdc60bfSaurel32             /* Level sensitive - active high */
442af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("critical IRQ", level);
4437058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
4449fdc60bfSaurel32             break;
4459fdc60bfSaurel32         case PPCE500_INPUT_INT:
4469fdc60bfSaurel32             /* Level sensitive - active high */
447af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("core IRQ", level);
4487058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
4499fdc60bfSaurel32             break;
4509fdc60bfSaurel32         case PPCE500_INPUT_DEBUG:
4519fdc60bfSaurel32             /* Level sensitive - active high */
452af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("debug pin", level);
4537058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
4549fdc60bfSaurel32             break;
4559fdc60bfSaurel32         default:
4567279810bSCédric Le Goater             g_assert_not_reached();
4579fdc60bfSaurel32         }
4589fdc60bfSaurel32         if (level)
4599fdc60bfSaurel32             env->irq_input_state |= 1 << pin;
4609fdc60bfSaurel32         else
4619fdc60bfSaurel32             env->irq_input_state &= ~(1 << pin);
4629fdc60bfSaurel32     }
4639fdc60bfSaurel32 }
4649fdc60bfSaurel32 
465aa5a9e24SPaolo Bonzini void ppce500_irq_init(PowerPCCPU *cpu)
4669fdc60bfSaurel32 {
4675e66cd0cSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppce500_set_irq, PPCE500_INPUT_NB);
4689fdc60bfSaurel32 }
469e49798b1SAlexander Graf 
470e49798b1SAlexander Graf /* Enable or Disable the E500 EPR capability */
471e49798b1SAlexander Graf void ppce500_set_mpic_proxy(bool enabled)
472e49798b1SAlexander Graf {
473182735efSAndreas Färber     CPUState *cs;
474e49798b1SAlexander Graf 
475bdc44640SAndreas Färber     CPU_FOREACH(cs) {
476182735efSAndreas Färber         PowerPCCPU *cpu = POWERPC_CPU(cs);
4775b95b8b9SAlexander Graf 
478182735efSAndreas Färber         cpu->env.mpic_proxy = enabled;
4795b95b8b9SAlexander Graf         if (kvm_enabled()) {
480182735efSAndreas Färber             kvmppc_set_mpic_proxy(cpu, enabled);
4815b95b8b9SAlexander Graf         }
482e49798b1SAlexander Graf     }
483e49798b1SAlexander Graf }
484e49798b1SAlexander Graf 
4859fddaa0cSbellard /*****************************************************************************/
486e9df014cSj_mayer /* PowerPC time base and decrementer emulation */
4879fddaa0cSbellard 
488eab08884SNicholas Piggin /*
489eab08884SNicholas Piggin  * Conversion between QEMU_CLOCK_VIRTUAL ns and timebase (TB) ticks:
490eab08884SNicholas Piggin  * TB ticks are arrived at by multiplying tb_freq then dividing by
491eab08884SNicholas Piggin  * ns per second, and rounding down. TB ticks drive all clocks and
492eab08884SNicholas Piggin  * timers in the target machine.
493eab08884SNicholas Piggin  *
494eab08884SNicholas Piggin  * Converting TB intervals to ns for the purpose of setting a
495eab08884SNicholas Piggin  * QEMU_CLOCK_VIRTUAL timer should go the other way, but rounding
496eab08884SNicholas Piggin  * up. Rounding down could cause the timer to fire before the TB
497eab08884SNicholas Piggin  * value has been reached.
498eab08884SNicholas Piggin  */
4997798f5c5SNicholas Piggin static uint64_t ns_to_tb(uint32_t freq, int64_t clock)
5007798f5c5SNicholas Piggin {
5017798f5c5SNicholas Piggin     return muldiv64(clock, freq, NANOSECONDS_PER_SECOND);
5027798f5c5SNicholas Piggin }
5037798f5c5SNicholas Piggin 
504eab08884SNicholas Piggin /* virtual clock in TB ticks, not adjusted by TB offset */
505eab08884SNicholas Piggin static int64_t tb_to_ns_round_up(uint32_t freq, uint64_t tb)
5067798f5c5SNicholas Piggin {
507eab08884SNicholas Piggin     return muldiv64_round_up(tb, NANOSECONDS_PER_SECOND, freq);
5087798f5c5SNicholas Piggin }
5097798f5c5SNicholas Piggin 
510ddd1055bSFabien Chouteau uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
5119fddaa0cSbellard {
5129fddaa0cSbellard     /* TB time in tb periods */
5137798f5c5SNicholas Piggin     return ns_to_tb(tb_env->tb_freq, vmclk) + tb_offset;
5149fddaa0cSbellard }
5159fddaa0cSbellard 
516e2684c0bSAndreas Färber uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
5179fddaa0cSbellard {
518c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
5199fddaa0cSbellard     uint64_t tb;
5209fddaa0cSbellard 
52190dc8812SScott Wood     if (kvm_enabled()) {
52290dc8812SScott Wood         return env->spr[SPR_TBL];
52390dc8812SScott Wood     }
52490dc8812SScott Wood 
525eaf832fcSNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
526eaf832fcSNicholas Piggin                         tb_env->tb_offset);
527af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
5289fddaa0cSbellard 
529e3ea6529SAlexander Graf     return tb;
5309fddaa0cSbellard }
5319fddaa0cSbellard 
532e2684c0bSAndreas Färber static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env)
5339fddaa0cSbellard {
534c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
5359fddaa0cSbellard     uint64_t tb;
5369fddaa0cSbellard 
537eaf832fcSNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
538eaf832fcSNicholas Piggin                         tb_env->tb_offset);
539af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
54076a66253Sj_mayer 
5419fddaa0cSbellard     return tb >> 32;
5429fddaa0cSbellard }
5439fddaa0cSbellard 
544e2684c0bSAndreas Färber uint32_t cpu_ppc_load_tbu (CPUPPCState *env)
5458a84de23Sj_mayer {
54690dc8812SScott Wood     if (kvm_enabled()) {
54790dc8812SScott Wood         return env->spr[SPR_TBU];
54890dc8812SScott Wood     }
54990dc8812SScott Wood 
5508a84de23Sj_mayer     return _cpu_ppc_load_tbu(env);
5518a84de23Sj_mayer }
5528a84de23Sj_mayer 
553c227f099SAnthony Liguori static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
554636aa200SBlue Swirl                                     int64_t *tb_offsetp, uint64_t value)
5559fddaa0cSbellard {
5567798f5c5SNicholas Piggin     *tb_offsetp = value - ns_to_tb(tb_env->tb_freq, vmclk);
55773bcb24dSRutuja Shah 
558af96d2e6SCédric Le Goater     trace_ppc_tb_store(value, *tb_offsetp);
559a496775fSj_mayer }
5609fddaa0cSbellard 
561e2684c0bSAndreas Färber void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value)
5629fddaa0cSbellard {
563c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
5642ad2e113SNicholas Piggin     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
565a062e36cSj_mayer     uint64_t tb;
5669fddaa0cSbellard 
5672ad2e113SNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset);
568a062e36cSj_mayer     tb &= 0xFFFFFFFF00000000ULL;
5692ad2e113SNicholas Piggin     cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb | (uint64_t)value);
570a062e36cSj_mayer }
571a062e36cSj_mayer 
572e2684c0bSAndreas Färber static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value)
573a062e36cSj_mayer {
574c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
5752ad2e113SNicholas Piggin     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
576a062e36cSj_mayer     uint64_t tb;
577a062e36cSj_mayer 
5782ad2e113SNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset);
579a062e36cSj_mayer     tb &= 0x00000000FFFFFFFFULL;
5802ad2e113SNicholas Piggin     cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset,
5812ad2e113SNicholas Piggin                      ((uint64_t)value << 32) | tb);
582a062e36cSj_mayer }
583a062e36cSj_mayer 
584e2684c0bSAndreas Färber void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value)
5858a84de23Sj_mayer {
5868a84de23Sj_mayer     _cpu_ppc_store_tbu(env, value);
5878a84de23Sj_mayer }
5888a84de23Sj_mayer 
589e2684c0bSAndreas Färber uint64_t cpu_ppc_load_atbl (CPUPPCState *env)
590a062e36cSj_mayer {
591c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
592a062e36cSj_mayer     uint64_t tb;
593a062e36cSj_mayer 
594eaf832fcSNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
595eaf832fcSNicholas Piggin                         tb_env->atb_offset);
596af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
597a062e36cSj_mayer 
598b711de95SAurelien Jarno     return tb;
599a062e36cSj_mayer }
600a062e36cSj_mayer 
601e2684c0bSAndreas Färber uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
602a062e36cSj_mayer {
603c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
604a062e36cSj_mayer     uint64_t tb;
605a062e36cSj_mayer 
606eaf832fcSNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
607eaf832fcSNicholas Piggin                         tb_env->atb_offset);
608af96d2e6SCédric Le Goater     trace_ppc_tb_load(tb);
609a062e36cSj_mayer 
610a062e36cSj_mayer     return tb >> 32;
611a062e36cSj_mayer }
612a062e36cSj_mayer 
613e2684c0bSAndreas Färber void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value)
614a062e36cSj_mayer {
615c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
6162ad2e113SNicholas Piggin     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
617a062e36cSj_mayer     uint64_t tb;
618a062e36cSj_mayer 
6192ad2e113SNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset);
620a062e36cSj_mayer     tb &= 0xFFFFFFFF00000000ULL;
6212ad2e113SNicholas Piggin     cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset, tb | (uint64_t)value);
622a062e36cSj_mayer }
623a062e36cSj_mayer 
624e2684c0bSAndreas Färber void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
625a062e36cSj_mayer {
626c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
6272ad2e113SNicholas Piggin     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
628a062e36cSj_mayer     uint64_t tb;
629a062e36cSj_mayer 
6302ad2e113SNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, clock, tb_env->atb_offset);
631a062e36cSj_mayer     tb &= 0x00000000FFFFFFFFULL;
6322ad2e113SNicholas Piggin     cpu_ppc_store_tb(tb_env, clock, &tb_env->atb_offset,
6332ad2e113SNicholas Piggin                      ((uint64_t)value << 32) | tb);
634dbdd2506Sj_mayer }
635dbdd2506Sj_mayer 
6365d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env)
6375d62725bSSuraj Jitindar Singh {
6385d62725bSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
6395d62725bSSuraj Jitindar Singh 
6405d62725bSSuraj Jitindar Singh     return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
6415d62725bSSuraj Jitindar Singh                           tb_env->vtb_offset);
6425d62725bSSuraj Jitindar Singh }
6435d62725bSSuraj Jitindar Singh 
6445d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value)
6455d62725bSSuraj Jitindar Singh {
6465d62725bSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
6475d62725bSSuraj Jitindar Singh 
6485d62725bSSuraj Jitindar Singh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
6495d62725bSSuraj Jitindar Singh                      &tb_env->vtb_offset, value);
6505d62725bSSuraj Jitindar Singh }
6515d62725bSSuraj Jitindar Singh 
652f0ec31b1SSuraj Jitindar Singh void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value)
653f0ec31b1SSuraj Jitindar Singh {
654f0ec31b1SSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
6552ad2e113SNicholas Piggin     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
656f0ec31b1SSuraj Jitindar Singh     uint64_t tb;
657f0ec31b1SSuraj Jitindar Singh 
6582ad2e113SNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset);
659f0ec31b1SSuraj Jitindar Singh     tb &= 0xFFFFFFUL;
660f0ec31b1SSuraj Jitindar Singh     tb |= (value & ~0xFFFFFFUL);
6612ad2e113SNicholas Piggin     cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb);
662f0ec31b1SSuraj Jitindar Singh }
663f0ec31b1SSuraj Jitindar Singh 
664e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env)
665dbdd2506Sj_mayer {
666c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
667dbdd2506Sj_mayer     uint64_t tb, atb, vmclk;
668dbdd2506Sj_mayer 
669dbdd2506Sj_mayer     /* If the time base is already frozen, do nothing */
670dbdd2506Sj_mayer     if (tb_env->tb_freq != 0) {
671bc72ad67SAlex Bligh         vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
672dbdd2506Sj_mayer         /* Get the time base */
673dbdd2506Sj_mayer         tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
674dbdd2506Sj_mayer         /* Get the alternate time base */
675dbdd2506Sj_mayer         atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
676dbdd2506Sj_mayer         /* Store the time base value (ie compute the current offset) */
677dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
678dbdd2506Sj_mayer         /* Store the alternate time base value (compute the current offset) */
679dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
680dbdd2506Sj_mayer         /* Set the time base frequency to zero */
681dbdd2506Sj_mayer         tb_env->tb_freq = 0;
682dbdd2506Sj_mayer         /* Now, the time bases are frozen to tb_offset / atb_offset value */
683dbdd2506Sj_mayer     }
684dbdd2506Sj_mayer }
685dbdd2506Sj_mayer 
686e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env)
687dbdd2506Sj_mayer {
688c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
689dbdd2506Sj_mayer     uint64_t tb, atb, vmclk;
690dbdd2506Sj_mayer 
691dbdd2506Sj_mayer     /* If the time base is not frozen, do nothing */
692dbdd2506Sj_mayer     if (tb_env->tb_freq == 0) {
693bc72ad67SAlex Bligh         vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
694dbdd2506Sj_mayer         /* Get the time base from tb_offset */
695dbdd2506Sj_mayer         tb = tb_env->tb_offset;
696dbdd2506Sj_mayer         /* Get the alternate time base from atb_offset */
697dbdd2506Sj_mayer         atb = tb_env->atb_offset;
698dbdd2506Sj_mayer         /* Restore the tb frequency from the decrementer frequency */
699dbdd2506Sj_mayer         tb_env->tb_freq = tb_env->decr_freq;
700dbdd2506Sj_mayer         /* Store the time base value */
701dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
702dbdd2506Sj_mayer         /* Store the alternate time base value */
703dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
704dbdd2506Sj_mayer     }
7059fddaa0cSbellard }
7069fddaa0cSbellard 
707e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env)
708e81a982aSAlexander Graf {
709e81a982aSAlexander Graf     ppc_tb_t *tb_env = env->tb_env;
710e81a982aSAlexander Graf     int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL;
711e81a982aSAlexander Graf     return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
712e81a982aSAlexander Graf }
713e81a982aSAlexander Graf 
714ea62f8a5SNicholas Piggin static inline int64_t __cpu_ppc_load_decr(CPUPPCState *env, int64_t now,
715ea62f8a5SNicholas Piggin                                           uint64_t next)
7169fddaa0cSbellard {
717c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
718ea62f8a5SNicholas Piggin     uint64_t n;
7198e0a5ac8SNicholas Piggin     int64_t decr;
7209fddaa0cSbellard 
7218e0a5ac8SNicholas Piggin     n = ns_to_tb(tb_env->decr_freq, now);
7228e0a5ac8SNicholas Piggin     if (next > n && tb_env->flags & PPC_TIMER_BOOKE) {
723ddd1055bSFabien Chouteau         decr = 0;
724ddd1055bSFabien Chouteau     } else {
7258e0a5ac8SNicholas Piggin         decr = next - n;
726ddd1055bSFabien Chouteau     }
7278e0a5ac8SNicholas Piggin 
728af96d2e6SCédric Le Goater     trace_ppc_decr_load(decr);
72976a66253Sj_mayer 
7309fddaa0cSbellard     return decr;
7319fddaa0cSbellard }
7329fddaa0cSbellard 
733ea62f8a5SNicholas Piggin static target_ulong _cpu_ppc_load_decr(CPUPPCState *env, int64_t now)
73458a7d328Sj_mayer {
735c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
736a8dafa52SSuraj Jitindar Singh     uint64_t decr;
73758a7d328Sj_mayer 
738ea62f8a5SNicholas Piggin     decr = __cpu_ppc_load_decr(env, now, tb_env->decr_next);
739a8dafa52SSuraj Jitindar Singh 
740a8dafa52SSuraj Jitindar Singh     /*
741a8dafa52SSuraj Jitindar Singh      * If large decrementer is enabled then the decrementer is signed extened
742a8dafa52SSuraj Jitindar Singh      * to 64 bits, otherwise it is a 32 bit value.
743a8dafa52SSuraj Jitindar Singh      */
744a8dafa52SSuraj Jitindar Singh     if (env->spr[SPR_LPCR] & LPCR_LD) {
745c8fbc6b9SNicholas Piggin         PowerPCCPU *cpu = env_archcpu(env);
746c8fbc6b9SNicholas Piggin         PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
747c8fbc6b9SNicholas Piggin         return sextract64(decr, 0, pcc->lrg_decr_bits);
748a8dafa52SSuraj Jitindar Singh     }
749a8dafa52SSuraj Jitindar Singh     return (uint32_t) decr;
75058a7d328Sj_mayer }
75158a7d328Sj_mayer 
752ea62f8a5SNicholas Piggin target_ulong cpu_ppc_load_decr(CPUPPCState *env)
753ea62f8a5SNicholas Piggin {
754ea62f8a5SNicholas Piggin     if (kvm_enabled()) {
755ea62f8a5SNicholas Piggin         return env->spr[SPR_DECR];
756ea62f8a5SNicholas Piggin     } else {
757ea62f8a5SNicholas Piggin         return _cpu_ppc_load_decr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
758ea62f8a5SNicholas Piggin     }
759ea62f8a5SNicholas Piggin }
760ea62f8a5SNicholas Piggin 
761ea62f8a5SNicholas Piggin static target_ulong _cpu_ppc_load_hdecr(CPUPPCState *env, int64_t now)
76258a7d328Sj_mayer {
763db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
764a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
765c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
766a8dafa52SSuraj Jitindar Singh     uint64_t hdecr;
76758a7d328Sj_mayer 
768ea62f8a5SNicholas Piggin     hdecr =  __cpu_ppc_load_decr(env, now, tb_env->hdecr_next);
769a8dafa52SSuraj Jitindar Singh 
770a8dafa52SSuraj Jitindar Singh     /*
771a8dafa52SSuraj Jitindar Singh      * If we have a large decrementer (POWER9 or later) then hdecr is sign
772a8dafa52SSuraj Jitindar Singh      * extended to 64 bits, otherwise it is 32 bits.
773a8dafa52SSuraj Jitindar Singh      */
774a8dafa52SSuraj Jitindar Singh     if (pcc->lrg_decr_bits > 32) {
775c8fbc6b9SNicholas Piggin         return sextract64(hdecr, 0, pcc->lrg_decr_bits);
776a8dafa52SSuraj Jitindar Singh     }
777a8dafa52SSuraj Jitindar Singh     return (uint32_t) hdecr;
77858a7d328Sj_mayer }
77958a7d328Sj_mayer 
780ea62f8a5SNicholas Piggin target_ulong cpu_ppc_load_hdecr(CPUPPCState *env)
781ea62f8a5SNicholas Piggin {
782ea62f8a5SNicholas Piggin     return _cpu_ppc_load_hdecr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
783ea62f8a5SNicholas Piggin }
784ea62f8a5SNicholas Piggin 
785e2684c0bSAndreas Färber uint64_t cpu_ppc_load_purr (CPUPPCState *env)
78658a7d328Sj_mayer {
787c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
78858a7d328Sj_mayer 
7895cc7e69fSSuraj Jitindar Singh     return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
7905cc7e69fSSuraj Jitindar Singh                           tb_env->purr_offset);
79158a7d328Sj_mayer }
79258a7d328Sj_mayer 
7939fddaa0cSbellard /* When decrementer expires,
7949fddaa0cSbellard  * all we need to do is generate or queue a CPU exception
7959fddaa0cSbellard  */
7967e0a9247SAndreas Färber static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
7979fddaa0cSbellard {
7989fddaa0cSbellard     /* Raise it */
799af96d2e6SCédric Le Goater     trace_ppc_decr_excp("raise");
8007058581aSAndreas Färber     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
8019fddaa0cSbellard }
8029fddaa0cSbellard 
803e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu)
804e81a982aSAlexander Graf {
805e81a982aSAlexander Graf     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
806e81a982aSAlexander Graf }
807e81a982aSAlexander Graf 
8087e0a9247SAndreas Färber static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
80958a7d328Sj_mayer {
8104b236b62SBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
8114b236b62SBenjamin Herrenschmidt 
81258a7d328Sj_mayer     /* Raise it */
813af96d2e6SCédric Le Goater     trace_ppc_decr_excp("raise HV");
8144b236b62SBenjamin Herrenschmidt 
8154b236b62SBenjamin Herrenschmidt     /* The architecture specifies that we don't deliver HDEC
8164b236b62SBenjamin Herrenschmidt      * interrupts in a PM state. Not only they don't cause a
8174b236b62SBenjamin Herrenschmidt      * wakeup but they also get effectively discarded.
8184b236b62SBenjamin Herrenschmidt      */
8191e7fd61dSBenjamin Herrenschmidt     if (!env->resume_as_sreset) {
8207058581aSAndreas Färber         ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
82158a7d328Sj_mayer     }
8224b236b62SBenjamin Herrenschmidt }
82358a7d328Sj_mayer 
824e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
825e81a982aSAlexander Graf {
826e81a982aSAlexander Graf     ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
827e81a982aSAlexander Graf }
828e81a982aSAlexander Graf 
829ea62f8a5SNicholas Piggin static void __cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now, uint64_t *nextp,
8301246b259SStefan Weil                                  QEMUTimer *timer,
831e81a982aSAlexander Graf                                  void (*raise_excp)(void *),
832e81a982aSAlexander Graf                                  void (*lower_excp)(PowerPCCPU *),
833a5ff7875SNicholas Piggin                                  uint32_t flags, target_ulong decr,
834a5ff7875SNicholas Piggin                                  target_ulong value, int nr_bits)
8359fddaa0cSbellard {
8367e0a9247SAndreas Färber     CPUPPCState *env = &cpu->env;
837c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
838ea62f8a5SNicholas Piggin     uint64_t next;
8394d9b8ef9SCédric Le Goater     int64_t signed_value;
8404d9b8ef9SCédric Le Goater     int64_t signed_decr;
8419fddaa0cSbellard 
842a8dafa52SSuraj Jitindar Singh     /* Truncate value to decr_width and sign extend for simplicity */
84309d2db9fSNicholas Piggin     value = extract64(value, 0, nr_bits);
84409d2db9fSNicholas Piggin     decr = extract64(decr, 0, nr_bits);
8454d9b8ef9SCédric Le Goater     signed_value = sextract64(value, 0, nr_bits);
8464d9b8ef9SCédric Le Goater     signed_decr = sextract64(decr, 0, nr_bits);
847a8dafa52SSuraj Jitindar Singh 
848af96d2e6SCédric Le Goater     trace_ppc_decr_store(nr_bits, decr, value);
84955f7d4b0SDavid Gibson 
850e81a982aSAlexander Graf     /*
851febb71d5SNicholas Piggin      * Calculate the next decrementer event and set a timer.
852febb71d5SNicholas Piggin      * decr_next is in timebase units to keep rounding simple. Note it is
853febb71d5SNicholas Piggin      * not adjusted by tb_offset because if TB changes via tb_offset changing,
854febb71d5SNicholas Piggin      * decrementer does not change, so not directly comparable with TB.
855febb71d5SNicholas Piggin      */
856febb71d5SNicholas Piggin     next = ns_to_tb(tb_env->decr_freq, now) + value;
857febb71d5SNicholas Piggin     *nextp = next; /* nextp is in timebase units */
858febb71d5SNicholas Piggin 
859febb71d5SNicholas Piggin     /*
86017dd1354SNicholas Piggin      * Going from 1 -> 0 or 0 -> -1 is the event to generate a DEC interrupt.
861e81a982aSAlexander Graf      *
862e81a982aSAlexander Graf      * On MSB level based DEC implementations the MSB always means the interrupt
863e81a982aSAlexander Graf      * is pending, so raise it on those.
864e81a982aSAlexander Graf      *
865e81a982aSAlexander Graf      * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
866e81a982aSAlexander Graf      * an edge interrupt, so raise it here too.
867e81a982aSAlexander Graf      */
868a5ff7875SNicholas Piggin     if (((flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) ||
869a5ff7875SNicholas Piggin         ((flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0
8704d9b8ef9SCédric Le Goater           && signed_decr >= 0)) {
871e81a982aSAlexander Graf         (*raise_excp)(cpu);
872e81a982aSAlexander Graf         return;
873e81a982aSAlexander Graf     }
874e81a982aSAlexander Graf 
875e81a982aSAlexander Graf     /* On MSB level based systems a 0 for the MSB stops interrupt delivery */
876a5ff7875SNicholas Piggin     if (signed_value >= 0 && (flags & PPC_DECR_UNDERFLOW_LEVEL)) {
877e81a982aSAlexander Graf         (*lower_excp)(cpu);
878e81a982aSAlexander Graf     }
879e81a982aSAlexander Graf 
8809fddaa0cSbellard     /* Adjust timer */
8818e0a5ac8SNicholas Piggin     timer_mod(timer, tb_to_ns_round_up(tb_env->decr_freq, next));
882ddd1055bSFabien Chouteau }
88358a7d328Sj_mayer 
884ea62f8a5SNicholas Piggin static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now,
885ea62f8a5SNicholas Piggin                                        target_ulong decr, target_ulong value,
886ea62f8a5SNicholas Piggin                                        int nr_bits)
88758a7d328Sj_mayer {
8887e0a9247SAndreas Färber     ppc_tb_t *tb_env = cpu->env.tb_env;
88958a7d328Sj_mayer 
890ea62f8a5SNicholas Piggin     __cpu_ppc_store_decr(cpu, now, &tb_env->decr_next, tb_env->decr_timer,
891a5ff7875SNicholas Piggin                          tb_env->decr_timer->cb, &cpu_ppc_decr_lower,
892a5ff7875SNicholas Piggin                          tb_env->flags, decr, value, nr_bits);
8939fddaa0cSbellard }
8949fddaa0cSbellard 
895a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value)
8969fddaa0cSbellard {
897db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
898a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
899ea62f8a5SNicholas Piggin     int64_t now;
900ea62f8a5SNicholas Piggin     target_ulong decr;
901a8dafa52SSuraj Jitindar Singh     int nr_bits = 32;
9027e0a9247SAndreas Färber 
903ea62f8a5SNicholas Piggin     if (kvm_enabled()) {
904ea62f8a5SNicholas Piggin         /* KVM handles decrementer exceptions, we don't need our own timer */
905ea62f8a5SNicholas Piggin         return;
906ea62f8a5SNicholas Piggin     }
907ea62f8a5SNicholas Piggin 
908a8dafa52SSuraj Jitindar Singh     if (env->spr[SPR_LPCR] & LPCR_LD) {
909a8dafa52SSuraj Jitindar Singh         nr_bits = pcc->lrg_decr_bits;
910a8dafa52SSuraj Jitindar Singh     }
911a8dafa52SSuraj Jitindar Singh 
912ea62f8a5SNicholas Piggin     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
913ea62f8a5SNicholas Piggin     decr = _cpu_ppc_load_decr(env, now);
914ea62f8a5SNicholas Piggin     _cpu_ppc_store_decr(cpu, now, decr, value, nr_bits);
9159fddaa0cSbellard }
9169fddaa0cSbellard 
9179fddaa0cSbellard static void cpu_ppc_decr_cb(void *opaque)
9189fddaa0cSbellard {
91950c680f0SAndreas Färber     PowerPCCPU *cpu = opaque;
9207e0a9247SAndreas Färber 
921e81a982aSAlexander Graf     cpu_ppc_decr_excp(cpu);
9229fddaa0cSbellard }
9239fddaa0cSbellard 
924ea62f8a5SNicholas Piggin static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, int64_t now,
925ea62f8a5SNicholas Piggin                                         target_ulong hdecr, target_ulong value,
926ea62f8a5SNicholas Piggin                                         int nr_bits)
92758a7d328Sj_mayer {
9287e0a9247SAndreas Färber     ppc_tb_t *tb_env = cpu->env.tb_env;
92958a7d328Sj_mayer 
930b172c56aSj_mayer     if (tb_env->hdecr_timer != NULL) {
931a5ff7875SNicholas Piggin         /* HDECR (Book3S 64bit) is edge-based, not level like DECR */
932ea62f8a5SNicholas Piggin         __cpu_ppc_store_decr(cpu, now, &tb_env->hdecr_next, tb_env->hdecr_timer,
933e81a982aSAlexander Graf                              tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
934a5ff7875SNicholas Piggin                              PPC_DECR_UNDERFLOW_TRIGGERED,
935a8dafa52SSuraj Jitindar Singh                              hdecr, value, nr_bits);
93658a7d328Sj_mayer     }
937b172c56aSj_mayer }
93858a7d328Sj_mayer 
939a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value)
94058a7d328Sj_mayer {
941db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
942a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
943ea62f8a5SNicholas Piggin     int64_t now;
944ea62f8a5SNicholas Piggin     target_ulong hdecr;
9457e0a9247SAndreas Färber 
946ea62f8a5SNicholas Piggin     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
947ea62f8a5SNicholas Piggin     hdecr = _cpu_ppc_load_hdecr(env, now);
948ea62f8a5SNicholas Piggin     _cpu_ppc_store_hdecr(cpu, now, hdecr, value, pcc->lrg_decr_bits);
94958a7d328Sj_mayer }
95058a7d328Sj_mayer 
95158a7d328Sj_mayer static void cpu_ppc_hdecr_cb(void *opaque)
95258a7d328Sj_mayer {
95350c680f0SAndreas Färber     PowerPCCPU *cpu = opaque;
9547e0a9247SAndreas Färber 
955e81a982aSAlexander Graf     cpu_ppc_hdecr_excp(cpu);
95658a7d328Sj_mayer }
95758a7d328Sj_mayer 
958ea62f8a5SNicholas Piggin static void _cpu_ppc_store_purr(CPUPPCState *env, int64_t now, uint64_t value)
95958a7d328Sj_mayer {
9605cc7e69fSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
96158a7d328Sj_mayer 
962ea62f8a5SNicholas Piggin     cpu_ppc_store_tb(tb_env, now, &tb_env->purr_offset, value);
963ea62f8a5SNicholas Piggin }
964ea62f8a5SNicholas Piggin 
965ea62f8a5SNicholas Piggin void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value)
966ea62f8a5SNicholas Piggin {
967ea62f8a5SNicholas Piggin     _cpu_ppc_store_purr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), value);
96858a7d328Sj_mayer }
96958a7d328Sj_mayer 
97042043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb)
97198a8b524SAlexey Kardashevskiy {
9724a7428c5SChristopher Covington     uint64_t ticks = cpu_get_host_ticks();
97398a8b524SAlexey Kardashevskiy     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
97498a8b524SAlexey Kardashevskiy 
97598a8b524SAlexey Kardashevskiy     if (!first_ppc_cpu->env.tb_env) {
97698a8b524SAlexey Kardashevskiy         error_report("No timebase object");
97798a8b524SAlexey Kardashevskiy         return;
97898a8b524SAlexey Kardashevskiy     }
97998a8b524SAlexey Kardashevskiy 
9809db680f8SNicholas Piggin     if (replay_mode == REPLAY_MODE_NONE) {
98142043e4fSLaurent Vivier         /* not used anymore, we keep it for compatibility */
98277bad151SPaolo Bonzini         tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
9839db680f8SNicholas Piggin     } else {
9849db680f8SNicholas Piggin         /* simpler for record-replay to avoid this event, compat not needed */
9859db680f8SNicholas Piggin         tb->time_of_the_day_ns = 0;
9869db680f8SNicholas Piggin     }
9879db680f8SNicholas Piggin 
98898a8b524SAlexey Kardashevskiy     /*
98942043e4fSLaurent Vivier      * tb_offset is only expected to be changed by QEMU so
99098a8b524SAlexey Kardashevskiy      * there is no need to update it from KVM here
99198a8b524SAlexey Kardashevskiy      */
99298a8b524SAlexey Kardashevskiy     tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
993d14f3397SMaxiwell S. Garcia 
994711dfb24SGreg Kurz     tb->runstate_paused =
995711dfb24SGreg Kurz         runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM);
99698a8b524SAlexey Kardashevskiy }
99798a8b524SAlexey Kardashevskiy 
99842043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb)
99998a8b524SAlexey Kardashevskiy {
100098a8b524SAlexey Kardashevskiy     CPUState *cpu;
100198a8b524SAlexey Kardashevskiy     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
100242043e4fSLaurent Vivier     int64_t tb_off_adj, tb_off;
100398a8b524SAlexey Kardashevskiy     unsigned long freq;
100498a8b524SAlexey Kardashevskiy 
100598a8b524SAlexey Kardashevskiy     if (!first_ppc_cpu->env.tb_env) {
100698a8b524SAlexey Kardashevskiy         error_report("No timebase object");
100742043e4fSLaurent Vivier         return;
100898a8b524SAlexey Kardashevskiy     }
100998a8b524SAlexey Kardashevskiy 
101098a8b524SAlexey Kardashevskiy     freq = first_ppc_cpu->env.tb_env->tb_freq;
101198a8b524SAlexey Kardashevskiy 
101242043e4fSLaurent Vivier     tb_off_adj = tb->guest_timebase - cpu_get_host_ticks();
101398a8b524SAlexey Kardashevskiy 
101498a8b524SAlexey Kardashevskiy     tb_off = first_ppc_cpu->env.tb_env->tb_offset;
101598a8b524SAlexey Kardashevskiy     trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off,
101698a8b524SAlexey Kardashevskiy                         (tb_off_adj - tb_off) / freq);
101798a8b524SAlexey Kardashevskiy 
101898a8b524SAlexey Kardashevskiy     /* Set new offset to all CPUs */
101998a8b524SAlexey Kardashevskiy     CPU_FOREACH(cpu) {
102098a8b524SAlexey Kardashevskiy         PowerPCCPU *pcpu = POWERPC_CPU(cpu);
102198a8b524SAlexey Kardashevskiy         pcpu->env.tb_env->tb_offset = tb_off_adj;
10229723295aSGreg Kurz         kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset);
102342043e4fSLaurent Vivier     }
102498a8b524SAlexey Kardashevskiy }
102598a8b524SAlexey Kardashevskiy 
1026538f0497SPhilippe Mathieu-Daudé void cpu_ppc_clock_vm_state_change(void *opaque, bool running,
102742043e4fSLaurent Vivier                                    RunState state)
102842043e4fSLaurent Vivier {
102942043e4fSLaurent Vivier     PPCTimebase *tb = opaque;
103042043e4fSLaurent Vivier 
103142043e4fSLaurent Vivier     if (running) {
103242043e4fSLaurent Vivier         timebase_load(tb);
103342043e4fSLaurent Vivier     } else {
103442043e4fSLaurent Vivier         timebase_save(tb);
103542043e4fSLaurent Vivier     }
103642043e4fSLaurent Vivier }
103742043e4fSLaurent Vivier 
103842043e4fSLaurent Vivier /*
1039d14f3397SMaxiwell S. Garcia  * When migrating a running guest, read the clock just
1040d14f3397SMaxiwell S. Garcia  * before migration, so that the guest clock counts
1041d14f3397SMaxiwell S. Garcia  * during the events between:
104242043e4fSLaurent Vivier  *
104342043e4fSLaurent Vivier  *  * vm_stop()
104442043e4fSLaurent Vivier  *  *
104542043e4fSLaurent Vivier  *  * pre_save()
104642043e4fSLaurent Vivier  *
104742043e4fSLaurent Vivier  *  This reduces clock difference on migration from 5s
104842043e4fSLaurent Vivier  *  to 0.1s (when max_downtime == 5s), because sending the
104942043e4fSLaurent Vivier  *  final pages of memory (which happens between vm_stop()
105042043e4fSLaurent Vivier  *  and pre_save()) takes max_downtime.
105142043e4fSLaurent Vivier  */
105244b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque)
105342043e4fSLaurent Vivier {
105442043e4fSLaurent Vivier     PPCTimebase *tb = opaque;
105542043e4fSLaurent Vivier 
1056711dfb24SGreg Kurz     /* guest_timebase won't be overridden in case of paused guest or savevm */
1057d14f3397SMaxiwell S. Garcia     if (!tb->runstate_paused) {
105842043e4fSLaurent Vivier         timebase_save(tb);
1059d14f3397SMaxiwell S. Garcia     }
106044b1ff31SDr. David Alan Gilbert 
106144b1ff31SDr. David Alan Gilbert     return 0;
106298a8b524SAlexey Kardashevskiy }
106398a8b524SAlexey Kardashevskiy 
106498a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = {
106598a8b524SAlexey Kardashevskiy     .name = "timebase",
106698a8b524SAlexey Kardashevskiy     .version_id = 1,
106798a8b524SAlexey Kardashevskiy     .minimum_version_id = 1,
106898a8b524SAlexey Kardashevskiy     .pre_save = timebase_pre_save,
106998a8b524SAlexey Kardashevskiy     .fields      = (VMStateField []) {
107098a8b524SAlexey Kardashevskiy         VMSTATE_UINT64(guest_timebase, PPCTimebase),
107198a8b524SAlexey Kardashevskiy         VMSTATE_INT64(time_of_the_day_ns, PPCTimebase),
107298a8b524SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
107398a8b524SAlexey Kardashevskiy     },
107498a8b524SAlexey Kardashevskiy };
107598a8b524SAlexey Kardashevskiy 
10769fddaa0cSbellard /* Set up (once) timebase frequency (in Hz) */
107730d0647bSNicholas Piggin void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq)
10789fddaa0cSbellard {
1079db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
1080c227f099SAnthony Liguori     ppc_tb_t *tb_env;
10819fddaa0cSbellard 
1082b21e2380SMarkus Armbruster     tb_env = g_new0(ppc_tb_t, 1);
10839fddaa0cSbellard     env->tb_env = tb_env;
1084ddd1055bSFabien Chouteau     tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
1085d0db7cadSGreg Kurz     if (is_book3s_arch2x(env)) {
1086e81a982aSAlexander Graf         /* All Book3S 64bit CPUs implement level based DEC logic */
1087e81a982aSAlexander Graf         tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
1088e81a982aSAlexander Graf     }
10899fddaa0cSbellard     /* Create new timer */
1090eaf832fcSNicholas Piggin     tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
1091eaf832fcSNicholas Piggin                                       &cpu_ppc_decr_cb, cpu);
10925ff40b01SNicholas Piggin     if (env->has_hv_mode && !cpu->vhyp) {
1093eaf832fcSNicholas Piggin         tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
1094eaf832fcSNicholas Piggin                                            &cpu_ppc_hdecr_cb, cpu);
1095b172c56aSj_mayer     } else {
1096b172c56aSj_mayer         tb_env->hdecr_timer = NULL;
1097b172c56aSj_mayer     }
10989fddaa0cSbellard 
109930d0647bSNicholas Piggin     tb_env->tb_freq = freq;
110030d0647bSNicholas Piggin     tb_env->decr_freq = freq;
110130d0647bSNicholas Piggin }
110230d0647bSNicholas Piggin 
110330d0647bSNicholas Piggin void cpu_ppc_tb_reset(CPUPPCState *env)
110430d0647bSNicholas Piggin {
110530d0647bSNicholas Piggin     PowerPCCPU *cpu = env_archcpu(env);
110630d0647bSNicholas Piggin     ppc_tb_t *tb_env = env->tb_env;
110730d0647bSNicholas Piggin 
110830d0647bSNicholas Piggin     timer_del(tb_env->decr_timer);
110930d0647bSNicholas Piggin     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
111030d0647bSNicholas Piggin     tb_env->decr_next = 0;
111130d0647bSNicholas Piggin     if (tb_env->hdecr_timer != NULL) {
111230d0647bSNicholas Piggin         timer_del(tb_env->hdecr_timer);
111330d0647bSNicholas Piggin         ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
111430d0647bSNicholas Piggin         tb_env->hdecr_next = 0;
111530d0647bSNicholas Piggin     }
111630d0647bSNicholas Piggin 
111730d0647bSNicholas Piggin     /*
111830d0647bSNicholas Piggin      * There is a bug in Linux 2.4 kernels:
111930d0647bSNicholas Piggin      * if a decrementer exception is pending when it enables msr_ee at startup,
112030d0647bSNicholas Piggin      * it's not ready to handle it...
112130d0647bSNicholas Piggin      */
112230d0647bSNicholas Piggin     cpu_ppc_store_decr(env, -1);
112330d0647bSNicholas Piggin     cpu_ppc_store_hdecr(env, -1);
112430d0647bSNicholas Piggin     cpu_ppc_store_purr(env, 0x0000000000000000ULL);
11259fddaa0cSbellard }
11269fddaa0cSbellard 
1127ef95a244SDaniel Henrique Barboza void cpu_ppc_tb_free(CPUPPCState *env)
1128ef95a244SDaniel Henrique Barboza {
1129ef95a244SDaniel Henrique Barboza     timer_free(env->tb_env->decr_timer);
1130ef95a244SDaniel Henrique Barboza     timer_free(env->tb_env->hdecr_timer);
1131ef95a244SDaniel Henrique Barboza     g_free(env->tb_env);
1132ef95a244SDaniel Henrique Barboza }
1133ef95a244SDaniel Henrique Barboza 
113493aeb702SNicholas Piggin /* cpu_ppc_hdecr_init may be used if the timer is not used by HDEC emulation */
113593aeb702SNicholas Piggin void cpu_ppc_hdecr_init(CPUPPCState *env)
113693aeb702SNicholas Piggin {
113793aeb702SNicholas Piggin     PowerPCCPU *cpu = env_archcpu(env);
113893aeb702SNicholas Piggin 
113993aeb702SNicholas Piggin     assert(env->tb_env->hdecr_timer == NULL);
114093aeb702SNicholas Piggin 
114193aeb702SNicholas Piggin     env->tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
114293aeb702SNicholas Piggin                                             &cpu_ppc_hdecr_cb, cpu);
114393aeb702SNicholas Piggin }
114493aeb702SNicholas Piggin 
114593aeb702SNicholas Piggin void cpu_ppc_hdecr_exit(CPUPPCState *env)
114693aeb702SNicholas Piggin {
114793aeb702SNicholas Piggin     PowerPCCPU *cpu = env_archcpu(env);
114893aeb702SNicholas Piggin 
114993aeb702SNicholas Piggin     timer_free(env->tb_env->hdecr_timer);
115093aeb702SNicholas Piggin     env->tb_env->hdecr_timer = NULL;
115193aeb702SNicholas Piggin 
115293aeb702SNicholas Piggin     cpu_ppc_hdecr_lower(cpu);
115393aeb702SNicholas Piggin }
115493aeb702SNicholas Piggin 
1155636aaad7Sj_mayer /*****************************************************************************/
1156ddd1055bSFabien Chouteau /* PowerPC 40x timers */
1157636aaad7Sj_mayer 
1158636aaad7Sj_mayer /* PIT, FIT & WDT */
1159ddd1055bSFabien Chouteau typedef struct ppc40x_timer_t ppc40x_timer_t;
1160ddd1055bSFabien Chouteau struct ppc40x_timer_t {
1161636aaad7Sj_mayer     uint64_t pit_reload;  /* PIT auto-reload value        */
1162636aaad7Sj_mayer     uint64_t fit_next;    /* Tick for next FIT interrupt  */
11631246b259SStefan Weil     QEMUTimer *fit_timer;
1164636aaad7Sj_mayer     uint64_t wdt_next;    /* Tick for next WDT interrupt  */
11651246b259SStefan Weil     QEMUTimer *wdt_timer;
1166d63cb48dSEdgar E. Iglesias 
1167d63cb48dSEdgar E. Iglesias     /* 405 have the PIT, 440 have a DECR.  */
1168d63cb48dSEdgar E. Iglesias     unsigned int decr_excp;
1169636aaad7Sj_mayer };
1170636aaad7Sj_mayer 
1171636aaad7Sj_mayer /* Fixed interval timer */
1172636aaad7Sj_mayer static void cpu_4xx_fit_cb (void *opaque)
117376a66253Sj_mayer {
1174b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1175b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
1176c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1177ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1178636aaad7Sj_mayer     uint64_t now, next;
1179636aaad7Sj_mayer 
1180636aaad7Sj_mayer     tb_env = env->tb_env;
1181ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1182bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1183636aaad7Sj_mayer     switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
1184636aaad7Sj_mayer     case 0:
1185636aaad7Sj_mayer         next = 1 << 9;
1186636aaad7Sj_mayer         break;
1187636aaad7Sj_mayer     case 1:
1188636aaad7Sj_mayer         next = 1 << 13;
1189636aaad7Sj_mayer         break;
1190636aaad7Sj_mayer     case 2:
1191636aaad7Sj_mayer         next = 1 << 17;
1192636aaad7Sj_mayer         break;
1193636aaad7Sj_mayer     case 3:
1194636aaad7Sj_mayer         next = 1 << 21;
1195636aaad7Sj_mayer         break;
1196636aaad7Sj_mayer     default:
1197636aaad7Sj_mayer         /* Cannot occur, but makes gcc happy */
1198636aaad7Sj_mayer         return;
1199636aaad7Sj_mayer     }
1200eab08884SNicholas Piggin     next = now + tb_to_ns_round_up(tb_env->tb_freq, next);
1201bc72ad67SAlex Bligh     timer_mod(ppc40x_timer->fit_timer, next);
1202636aaad7Sj_mayer     env->spr[SPR_40x_TSR] |= 1 << 26;
12037058581aSAndreas Färber     if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) {
12047058581aSAndreas Färber         ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1);
12057058581aSAndreas Färber     }
1206af96d2e6SCédric Le Goater     trace_ppc4xx_fit((int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
1207636aaad7Sj_mayer                          env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
1208636aaad7Sj_mayer }
1209636aaad7Sj_mayer 
1210636aaad7Sj_mayer /* Programmable interval timer */
1211e2684c0bSAndreas Färber static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
1212636aaad7Sj_mayer {
1213ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1214636aaad7Sj_mayer     uint64_t now, next;
1215636aaad7Sj_mayer 
1216ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1217ddd1055bSFabien Chouteau     if (ppc40x_timer->pit_reload <= 1 ||
12184b6d0a4cSj_mayer         !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
12194b6d0a4cSj_mayer         (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
12204b6d0a4cSj_mayer         /* Stop PIT */
1221af96d2e6SCédric Le Goater         trace_ppc4xx_pit_stop();
1222bc72ad67SAlex Bligh         timer_del(tb_env->decr_timer);
12234b6d0a4cSj_mayer     } else {
1224af96d2e6SCédric Le Goater         trace_ppc4xx_pit_start(ppc40x_timer->pit_reload);
1225bc72ad67SAlex Bligh         now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
12268e0a5ac8SNicholas Piggin 
12278e0a5ac8SNicholas Piggin         if (is_excp) {
12288e0a5ac8SNicholas Piggin             tb_env->decr_next += ppc40x_timer->pit_reload;
12298e0a5ac8SNicholas Piggin         } else {
12308e0a5ac8SNicholas Piggin             tb_env->decr_next = ns_to_tb(tb_env->decr_freq, now)
12318e0a5ac8SNicholas Piggin                                 + ppc40x_timer->pit_reload;
12328e0a5ac8SNicholas Piggin         }
12338e0a5ac8SNicholas Piggin         next = tb_to_ns_round_up(tb_env->decr_freq, tb_env->decr_next);
1234bc72ad67SAlex Bligh         timer_mod(tb_env->decr_timer, next);
1235636aaad7Sj_mayer     }
12364b6d0a4cSj_mayer }
12374b6d0a4cSj_mayer 
12384b6d0a4cSj_mayer static void cpu_4xx_pit_cb (void *opaque)
12394b6d0a4cSj_mayer {
1240b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1241b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
1242c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1243ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
12444b6d0a4cSj_mayer 
12454b6d0a4cSj_mayer     tb_env = env->tb_env;
1246ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1247636aaad7Sj_mayer     env->spr[SPR_40x_TSR] |= 1 << 27;
12487058581aSAndreas Färber     if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) {
12497058581aSAndreas Färber         ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1);
12507058581aSAndreas Färber     }
12514b6d0a4cSj_mayer     start_stop_pit(env, tb_env, 1);
1252af96d2e6SCédric Le Goater     trace_ppc4xx_pit((int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
1253e96efcfcSj_mayer            (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
1254636aaad7Sj_mayer            env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
1255ddd1055bSFabien Chouteau            ppc40x_timer->pit_reload);
1256636aaad7Sj_mayer }
1257636aaad7Sj_mayer 
1258636aaad7Sj_mayer /* Watchdog timer */
1259636aaad7Sj_mayer static void cpu_4xx_wdt_cb (void *opaque)
1260636aaad7Sj_mayer {
1261b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1262b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
1263c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1264ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1265636aaad7Sj_mayer     uint64_t now, next;
1266636aaad7Sj_mayer 
1267636aaad7Sj_mayer     tb_env = env->tb_env;
1268ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1269bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1270636aaad7Sj_mayer     switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
1271636aaad7Sj_mayer     case 0:
1272636aaad7Sj_mayer         next = 1 << 17;
1273636aaad7Sj_mayer         break;
1274636aaad7Sj_mayer     case 1:
1275636aaad7Sj_mayer         next = 1 << 21;
1276636aaad7Sj_mayer         break;
1277636aaad7Sj_mayer     case 2:
1278636aaad7Sj_mayer         next = 1 << 25;
1279636aaad7Sj_mayer         break;
1280636aaad7Sj_mayer     case 3:
1281636aaad7Sj_mayer         next = 1 << 29;
1282636aaad7Sj_mayer         break;
1283636aaad7Sj_mayer     default:
1284636aaad7Sj_mayer         /* Cannot occur, but makes gcc happy */
1285636aaad7Sj_mayer         return;
1286636aaad7Sj_mayer     }
1287eab08884SNicholas Piggin     next = now + tb_to_ns_round_up(tb_env->decr_freq, next);
1288af96d2e6SCédric Le Goater     trace_ppc4xx_wdt(env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
1289636aaad7Sj_mayer     switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
1290636aaad7Sj_mayer     case 0x0:
1291636aaad7Sj_mayer     case 0x1:
1292bc72ad67SAlex Bligh         timer_mod(ppc40x_timer->wdt_timer, next);
1293ddd1055bSFabien Chouteau         ppc40x_timer->wdt_next = next;
1294a1f7f97bSPeter Maydell         env->spr[SPR_40x_TSR] |= 1U << 31;
1295636aaad7Sj_mayer         break;
1296636aaad7Sj_mayer     case 0x2:
1297bc72ad67SAlex Bligh         timer_mod(ppc40x_timer->wdt_timer, next);
1298ddd1055bSFabien Chouteau         ppc40x_timer->wdt_next = next;
1299636aaad7Sj_mayer         env->spr[SPR_40x_TSR] |= 1 << 30;
13007058581aSAndreas Färber         if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) {
13017058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1);
13027058581aSAndreas Färber         }
1303636aaad7Sj_mayer         break;
1304636aaad7Sj_mayer     case 0x3:
1305636aaad7Sj_mayer         env->spr[SPR_40x_TSR] &= ~0x30000000;
1306636aaad7Sj_mayer         env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
1307636aaad7Sj_mayer         switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
1308636aaad7Sj_mayer         case 0x0:
1309636aaad7Sj_mayer             /* No reset */
1310636aaad7Sj_mayer             break;
1311636aaad7Sj_mayer         case 0x1: /* Core reset */
1312f3273ba6SAndreas Färber             ppc40x_core_reset(cpu);
13138ecc7913Sj_mayer             break;
1314636aaad7Sj_mayer         case 0x2: /* Chip reset */
1315f3273ba6SAndreas Färber             ppc40x_chip_reset(cpu);
13168ecc7913Sj_mayer             break;
1317636aaad7Sj_mayer         case 0x3: /* System reset */
1318f3273ba6SAndreas Färber             ppc40x_system_reset(cpu);
13198ecc7913Sj_mayer             break;
1320636aaad7Sj_mayer         }
1321636aaad7Sj_mayer     }
132276a66253Sj_mayer }
132376a66253Sj_mayer 
1324e2684c0bSAndreas Färber void store_40x_pit (CPUPPCState *env, target_ulong val)
132576a66253Sj_mayer {
1326c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1327ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1328636aaad7Sj_mayer 
1329636aaad7Sj_mayer     tb_env = env->tb_env;
1330ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1331af96d2e6SCédric Le Goater     trace_ppc40x_store_pit(val);
1332ddd1055bSFabien Chouteau     ppc40x_timer->pit_reload = val;
13334b6d0a4cSj_mayer     start_stop_pit(env, tb_env, 0);
133476a66253Sj_mayer }
133576a66253Sj_mayer 
1336e2684c0bSAndreas Färber target_ulong load_40x_pit (CPUPPCState *env)
133776a66253Sj_mayer {
1338636aaad7Sj_mayer     return cpu_ppc_load_decr(env);
133976a66253Sj_mayer }
134076a66253Sj_mayer 
1341cbd8f17dSCédric Le Goater void store_40x_tsr(CPUPPCState *env, target_ulong val)
1342cbd8f17dSCédric Le Goater {
1343cbd8f17dSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1344cbd8f17dSCédric Le Goater 
1345cbd8f17dSCédric Le Goater     trace_ppc40x_store_tcr(val);
1346cbd8f17dSCédric Le Goater 
1347cbd8f17dSCédric Le Goater     env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
1348cbd8f17dSCédric Le Goater     if (val & 0x80000000) {
1349cbd8f17dSCédric Le Goater         ppc_set_irq(cpu, PPC_INTERRUPT_PIT, 0);
1350cbd8f17dSCédric Le Goater     }
1351cbd8f17dSCédric Le Goater }
1352cbd8f17dSCédric Le Goater 
1353cbd8f17dSCédric Le Goater void store_40x_tcr(CPUPPCState *env, target_ulong val)
1354cbd8f17dSCédric Le Goater {
1355cbd8f17dSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1356cbd8f17dSCédric Le Goater     ppc_tb_t *tb_env;
1357cbd8f17dSCédric Le Goater 
1358cbd8f17dSCédric Le Goater     trace_ppc40x_store_tsr(val);
1359cbd8f17dSCédric Le Goater 
1360cbd8f17dSCédric Le Goater     tb_env = env->tb_env;
1361cbd8f17dSCédric Le Goater     env->spr[SPR_40x_TCR] = val & 0xFFC00000;
1362cbd8f17dSCédric Le Goater     start_stop_pit(env, tb_env, 1);
1363cbd8f17dSCédric Le Goater     cpu_4xx_wdt_cb(cpu);
1364cbd8f17dSCédric Le Goater }
1365cbd8f17dSCédric Le Goater 
1366ddd1055bSFabien Chouteau static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
13674b6d0a4cSj_mayer {
1368e2684c0bSAndreas Färber     CPUPPCState *env = opaque;
1369c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
13704b6d0a4cSj_mayer 
1371af96d2e6SCédric Le Goater     trace_ppc40x_set_tb_clk(freq);
13724b6d0a4cSj_mayer     tb_env->tb_freq = freq;
1373dbdd2506Sj_mayer     tb_env->decr_freq = freq;
13744b6d0a4cSj_mayer     /* XXX: we should also update all timers */
13754b6d0a4cSj_mayer }
13764b6d0a4cSj_mayer 
1377e2684c0bSAndreas Färber clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
1378d63cb48dSEdgar E. Iglesias                                   unsigned int decr_excp)
1379636aaad7Sj_mayer {
1380c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1381ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1382b1273a5eSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1383b1273a5eSCédric Le Goater 
1384b1273a5eSCédric Le Goater     trace_ppc40x_timers_init(freq);
1385636aaad7Sj_mayer 
1386b21e2380SMarkus Armbruster     tb_env = g_new0(ppc_tb_t, 1);
1387b21e2380SMarkus Armbruster     ppc40x_timer = g_new0(ppc40x_timer_t, 1);
1388b1273a5eSCédric Le Goater 
13898ecc7913Sj_mayer     env->tb_env = tb_env;
1390ddd1055bSFabien Chouteau     tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
13918ecc7913Sj_mayer     tb_env->tb_freq = freq;
1392dbdd2506Sj_mayer     tb_env->decr_freq = freq;
1393ddd1055bSFabien Chouteau     tb_env->opaque = ppc40x_timer;
1394b1273a5eSCédric Le Goater 
1395636aaad7Sj_mayer     /* We use decr timer for PIT */
1396b1273a5eSCédric Le Goater     tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, cpu);
1397ddd1055bSFabien Chouteau     ppc40x_timer->fit_timer =
1398b1273a5eSCédric Le Goater         timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, cpu);
1399ddd1055bSFabien Chouteau     ppc40x_timer->wdt_timer =
1400b1273a5eSCédric Le Goater         timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, cpu);
1401ddd1055bSFabien Chouteau     ppc40x_timer->decr_excp = decr_excp;
14028ecc7913Sj_mayer 
1403ddd1055bSFabien Chouteau     return &ppc_40x_set_tb_clk;
140476a66253Sj_mayer }
140576a66253Sj_mayer 
14062e719ba3Sj_mayer /*****************************************************************************/
14072e719ba3Sj_mayer /* Embedded PowerPC Device Control Registers */
1408c227f099SAnthony Liguori typedef struct ppc_dcrn_t ppc_dcrn_t;
1409c227f099SAnthony Liguori struct ppc_dcrn_t {
14102e719ba3Sj_mayer     dcr_read_cb dcr_read;
14112e719ba3Sj_mayer     dcr_write_cb dcr_write;
14122e719ba3Sj_mayer     void *opaque;
14132e719ba3Sj_mayer };
14142e719ba3Sj_mayer 
1415a750fc0bSj_mayer /* XXX: on 460, DCR addresses are 32 bits wide,
1416a750fc0bSj_mayer  *      using DCRIPR to get the 22 upper bits of the DCR address
1417a750fc0bSj_mayer  */
14182e719ba3Sj_mayer #define DCRN_NB 1024
1419c227f099SAnthony Liguori struct ppc_dcr_t {
1420c227f099SAnthony Liguori     ppc_dcrn_t dcrn[DCRN_NB];
14212e719ba3Sj_mayer     int (*read_error)(int dcrn);
14222e719ba3Sj_mayer     int (*write_error)(int dcrn);
14232e719ba3Sj_mayer };
14242e719ba3Sj_mayer 
142573b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
14262e719ba3Sj_mayer {
1427c227f099SAnthony Liguori     ppc_dcrn_t *dcr;
14282e719ba3Sj_mayer 
14292e719ba3Sj_mayer     if (dcrn < 0 || dcrn >= DCRN_NB)
14302e719ba3Sj_mayer         goto error;
14312e719ba3Sj_mayer     dcr = &dcr_env->dcrn[dcrn];
14322e719ba3Sj_mayer     if (dcr->dcr_read == NULL)
14332e719ba3Sj_mayer         goto error;
14342e719ba3Sj_mayer     *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
1435de82dabeSCédric Le Goater     trace_ppc_dcr_read(dcrn, *valp);
14362e719ba3Sj_mayer 
14372e719ba3Sj_mayer     return 0;
14382e719ba3Sj_mayer 
14392e719ba3Sj_mayer  error:
14402e719ba3Sj_mayer     if (dcr_env->read_error != NULL)
14412e719ba3Sj_mayer         return (*dcr_env->read_error)(dcrn);
14422e719ba3Sj_mayer 
14432e719ba3Sj_mayer     return -1;
14442e719ba3Sj_mayer }
14452e719ba3Sj_mayer 
144673b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
14472e719ba3Sj_mayer {
1448c227f099SAnthony Liguori     ppc_dcrn_t *dcr;
14492e719ba3Sj_mayer 
14502e719ba3Sj_mayer     if (dcrn < 0 || dcrn >= DCRN_NB)
14512e719ba3Sj_mayer         goto error;
14522e719ba3Sj_mayer     dcr = &dcr_env->dcrn[dcrn];
14532e719ba3Sj_mayer     if (dcr->dcr_write == NULL)
14542e719ba3Sj_mayer         goto error;
1455de82dabeSCédric Le Goater     trace_ppc_dcr_write(dcrn, val);
14562e719ba3Sj_mayer     (*dcr->dcr_write)(dcr->opaque, dcrn, val);
14572e719ba3Sj_mayer 
14582e719ba3Sj_mayer     return 0;
14592e719ba3Sj_mayer 
14602e719ba3Sj_mayer  error:
14612e719ba3Sj_mayer     if (dcr_env->write_error != NULL)
14622e719ba3Sj_mayer         return (*dcr_env->write_error)(dcrn);
14632e719ba3Sj_mayer 
14642e719ba3Sj_mayer     return -1;
14652e719ba3Sj_mayer }
14662e719ba3Sj_mayer 
1467e2684c0bSAndreas Färber int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
14682e719ba3Sj_mayer                       dcr_read_cb dcr_read, dcr_write_cb dcr_write)
14692e719ba3Sj_mayer {
1470c227f099SAnthony Liguori     ppc_dcr_t *dcr_env;
1471c227f099SAnthony Liguori     ppc_dcrn_t *dcr;
14722e719ba3Sj_mayer 
14732e719ba3Sj_mayer     dcr_env = env->dcr_env;
14742e719ba3Sj_mayer     if (dcr_env == NULL)
14752e719ba3Sj_mayer         return -1;
14762e719ba3Sj_mayer     if (dcrn < 0 || dcrn >= DCRN_NB)
14772e719ba3Sj_mayer         return -1;
14782e719ba3Sj_mayer     dcr = &dcr_env->dcrn[dcrn];
14792e719ba3Sj_mayer     if (dcr->opaque != NULL ||
14802e719ba3Sj_mayer         dcr->dcr_read != NULL ||
14812e719ba3Sj_mayer         dcr->dcr_write != NULL)
14822e719ba3Sj_mayer         return -1;
14832e719ba3Sj_mayer     dcr->opaque = opaque;
14842e719ba3Sj_mayer     dcr->dcr_read = dcr_read;
14852e719ba3Sj_mayer     dcr->dcr_write = dcr_write;
14862e719ba3Sj_mayer 
14872e719ba3Sj_mayer     return 0;
14882e719ba3Sj_mayer }
14892e719ba3Sj_mayer 
1490e2684c0bSAndreas Färber int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn),
14912e719ba3Sj_mayer                   int (*write_error)(int dcrn))
14922e719ba3Sj_mayer {
1493c227f099SAnthony Liguori     ppc_dcr_t *dcr_env;
14942e719ba3Sj_mayer 
1495b21e2380SMarkus Armbruster     dcr_env = g_new0(ppc_dcr_t, 1);
14962e719ba3Sj_mayer     dcr_env->read_error = read_error;
14972e719ba3Sj_mayer     dcr_env->write_error = write_error;
14982e719ba3Sj_mayer     env->dcr_env = dcr_env;
14992e719ba3Sj_mayer 
15002e719ba3Sj_mayer     return 0;
15012e719ba3Sj_mayer }
15022e719ba3Sj_mayer 
150364201201Sbellard /*****************************************************************************/
1504051e2973SCédric Le Goater 
15054a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu)
15064a89e204SCédric Le Goater {
15074a89e204SCédric Le Goater     CPUPPCState *env = &cpu->env;
15084a89e204SCédric Le Goater     return env->spr_cb[SPR_PIR].default_value;
15094a89e204SCédric Le Goater }
15104a89e204SCédric Le Goater 
1511d24e80b2SNicholas Piggin int ppc_cpu_tir(PowerPCCPU *cpu)
1512d24e80b2SNicholas Piggin {
1513d24e80b2SNicholas Piggin     CPUPPCState *env = &cpu->env;
1514d24e80b2SNicholas Piggin     return env->spr_cb[SPR_TIR].default_value;
1515d24e80b2SNicholas Piggin }
1516d24e80b2SNicholas Piggin 
1517051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
1518051e2973SCédric Le Goater {
1519051e2973SCédric Le Goater     CPUState *cs;
1520051e2973SCédric Le Goater 
1521051e2973SCédric Le Goater     CPU_FOREACH(cs) {
1522051e2973SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
1523051e2973SCédric Le Goater 
15244a89e204SCédric Le Goater         if (ppc_cpu_pir(cpu) == pir) {
1525051e2973SCédric Le Goater             return cpu;
1526051e2973SCédric Le Goater         }
1527051e2973SCédric Le Goater     }
1528051e2973SCédric Le Goater 
1529051e2973SCédric Le Goater     return NULL;
1530051e2973SCédric Le Goater }
153140177438SGreg Kurz 
153240177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu)
153340177438SGreg Kurz {
153440177438SGreg Kurz     CPUPPCState *env = &cpu->env;
153540177438SGreg Kurz 
153640177438SGreg Kurz     env->irq_input_state = 0;
1537*76d93e14Sjianchunfu     if (kvm_enabled()) {
153840177438SGreg Kurz         kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0);
153940177438SGreg Kurz     }
1540*76d93e14Sjianchunfu }
1541