xref: /qemu/hw/ppc/ppc.c (revision fc524567087c2537b5103cdfc1d41e4f442892b6)
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"
30*22a7c2f2SPierrick Bouvier #include "exec/cpu-interrupt.h"
3132cad1ffSPhilippe Mathieu-Daudé #include "system/cpus.h"
321de7afc9SPaolo Bonzini #include "qemu/log.h"
33db725815SMarkus Armbruster #include "qemu/main-loop.h"
3498a8b524SAlexey Kardashevskiy #include "qemu/error-report.h"
3532cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h"
3632cad1ffSPhilippe Mathieu-Daudé #include "system/replay.h"
3732cad1ffSPhilippe Mathieu-Daudé #include "system/runstate.h"
38fc87e185SAlexander Graf #include "kvm_ppc.h"
39d6454270SMarkus Armbruster #include "migration/vmstate.h"
4098a8b524SAlexey Kardashevskiy #include "trace.h"
41a541f297Sbellard 
42e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env);
43e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env);
44dbdd2506Sj_mayer 
ppc_set_irq(PowerPCCPU * cpu,int irq,int level)45f003109fSMatheus Ferst void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
4647103572Sj_mayer {
477058581aSAndreas Färber     CPUPPCState *env = &cpu->env;
488d04fb55SJan Kiszka     unsigned int old_pending;
498d04fb55SJan Kiszka 
508d04fb55SJan Kiszka     /* We may already have the BQL if coming from the reset path */
5132ead8e6SStefan Hajnoczi     BQL_LOCK_GUARD();
528d04fb55SJan Kiszka 
538d04fb55SJan Kiszka     old_pending = env->pending_interrupts;
54fc87e185SAlexander Graf 
5547103572Sj_mayer     if (level) {
56f003109fSMatheus Ferst         env->pending_interrupts |= irq;
5747103572Sj_mayer     } else {
58f003109fSMatheus Ferst         env->pending_interrupts &= ~irq;
5947103572Sj_mayer     }
60fc87e185SAlexander Graf 
61fc87e185SAlexander Graf     if (old_pending != env->pending_interrupts) {
622fdedcbcSMatheus Ferst         ppc_maybe_interrupt(env);
6376d93e14Sjianchunfu         if (kvm_enabled()) {
64f003109fSMatheus Ferst             kvmppc_set_interrupt(cpu, irq, level);
65fc87e185SAlexander Graf         }
6676d93e14Sjianchunfu     }
67fc87e185SAlexander Graf 
68f003109fSMatheus Ferst     trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
69af96d2e6SCédric Le Goater                            CPU(cpu)->interrupt_request);
70a496775fSj_mayer }
7147103572Sj_mayer 
72e9df014cSj_mayer /* PowerPC 6xx / 7xx internal IRQ controller */
ppc6xx_set_irq(void * opaque,int pin,int level)73e9df014cSj_mayer static void ppc6xx_set_irq(void *opaque, int pin, int level)
74d537cf6cSpbrook {
75a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
76a0961245SAndreas Färber     CPUPPCState *env = &cpu->env;
77e9df014cSj_mayer     int cur_level;
78d537cf6cSpbrook 
79af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
80af96d2e6SCédric Le Goater 
81e9df014cSj_mayer     cur_level = (env->irq_input_state >> pin) & 1;
82e9df014cSj_mayer     /* Don't generate spurious events */
8324be5ae3Sj_mayer     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
84259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
85259186a7SAndreas Färber 
86e9df014cSj_mayer         switch (pin) {
87dbdd2506Sj_mayer         case PPC6xx_INPUT_TBEN:
88dbdd2506Sj_mayer             /* Level sensitive - active high */
89af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("time base", level);
90dbdd2506Sj_mayer             if (level) {
91dbdd2506Sj_mayer                 cpu_ppc_tb_start(env);
92dbdd2506Sj_mayer             } else {
93dbdd2506Sj_mayer                 cpu_ppc_tb_stop(env);
94dbdd2506Sj_mayer             }
95b2bd5b20SChen Qun             break;
9624be5ae3Sj_mayer         case PPC6xx_INPUT_INT:
9724be5ae3Sj_mayer             /* Level sensitive - active high */
98af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("external IRQ", level);
997058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
100e9df014cSj_mayer             break;
10124be5ae3Sj_mayer         case PPC6xx_INPUT_SMI:
102e9df014cSj_mayer             /* Level sensitive - active high */
103af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("SMI IRQ", level);
1047058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level);
105e9df014cSj_mayer             break;
10624be5ae3Sj_mayer         case PPC6xx_INPUT_MCP:
107e9df014cSj_mayer             /* Negative edge sensitive */
108e9df014cSj_mayer             /* XXX: TODO: actual reaction may depends on HID0 status
109e9df014cSj_mayer              *            603/604/740/750: check HID0[EMCP]
110e9df014cSj_mayer              */
111e9df014cSj_mayer             if (cur_level == 1 && level == 0) {
112af96d2e6SCédric Le Goater                 trace_ppc_irq_set_state("machine check", 1);
1137058581aSAndreas Färber                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
114d537cf6cSpbrook             }
115e9df014cSj_mayer             break;
11624be5ae3Sj_mayer         case PPC6xx_INPUT_CKSTP_IN:
117e9df014cSj_mayer             /* Level sensitive - active low */
118e9df014cSj_mayer             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
119e63ecc6fSj_mayer             /* XXX: Note that the only way to restart the CPU is to reset it */
120e9df014cSj_mayer             if (level) {
121af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("stop");
122259186a7SAndreas Färber                 cs->halted = 1;
123d537cf6cSpbrook             }
12447103572Sj_mayer             break;
12524be5ae3Sj_mayer         case PPC6xx_INPUT_HRESET:
126e9df014cSj_mayer             /* Level sensitive - active low */
127e9df014cSj_mayer             if (level) {
128af96d2e6SCédric Le Goater                 trace_ppc_irq_reset("CPU");
129c3affe56SAndreas Färber                 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
130e9df014cSj_mayer             }
13147103572Sj_mayer             break;
13224be5ae3Sj_mayer         case PPC6xx_INPUT_SRESET:
133af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("RESET IRQ", level);
1347058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
13547103572Sj_mayer             break;
136e9df014cSj_mayer         default:
1377279810bSCédric Le Goater             g_assert_not_reached();
13847103572Sj_mayer         }
139e9df014cSj_mayer         if (level)
140e9df014cSj_mayer             env->irq_input_state |= 1 << pin;
141e9df014cSj_mayer         else
142e9df014cSj_mayer             env->irq_input_state &= ~(1 << pin);
143e9df014cSj_mayer     }
144e9df014cSj_mayer }
145e9df014cSj_mayer 
ppc6xx_irq_init(PowerPCCPU * cpu)146aa5a9e24SPaolo Bonzini void ppc6xx_irq_init(PowerPCCPU *cpu)
147e9df014cSj_mayer {
1480f3e0c6fSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppc6xx_set_irq, PPC6xx_INPUT_NB);
14947103572Sj_mayer }
15047103572Sj_mayer 
15100af685fSj_mayer #if defined(TARGET_PPC64)
152d0dfae6eSj_mayer /* PowerPC 970 internal IRQ controller */
ppc970_set_irq(void * opaque,int pin,int level)153d0dfae6eSj_mayer static void ppc970_set_irq(void *opaque, int pin, int level)
154d0dfae6eSj_mayer {
155a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
156a0961245SAndreas Färber     CPUPPCState *env = &cpu->env;
157d0dfae6eSj_mayer     int cur_level;
158d0dfae6eSj_mayer 
159af96d2e6SCédric Le Goater     trace_ppc_irq_set(env, pin, level);
160af96d2e6SCédric Le Goater 
161d0dfae6eSj_mayer     cur_level = (env->irq_input_state >> pin) & 1;
162d0dfae6eSj_mayer     /* Don't generate spurious events */
163d0dfae6eSj_mayer     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
164259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
165259186a7SAndreas Färber 
166d0dfae6eSj_mayer         switch (pin) {
167d0dfae6eSj_mayer         case PPC970_INPUT_INT:
168d0dfae6eSj_mayer             /* Level sensitive - active high */
169af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("external IRQ", level);
1707058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
171d0dfae6eSj_mayer             break;
172d0dfae6eSj_mayer         case PPC970_INPUT_THINT:
173d0dfae6eSj_mayer             /* Level sensitive - active high */
174af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("SMI IRQ", level);
1757058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level);
176d0dfae6eSj_mayer             break;
177d0dfae6eSj_mayer         case PPC970_INPUT_MCP:
178d0dfae6eSj_mayer             /* Negative edge sensitive */
179d0dfae6eSj_mayer             /* XXX: TODO: actual reaction may depends on HID0 status
180d0dfae6eSj_mayer              *            603/604/740/750: check HID0[EMCP]
181d0dfae6eSj_mayer              */
182d0dfae6eSj_mayer             if (cur_level == 1 && level == 0) {
183af96d2e6SCédric Le Goater                 trace_ppc_irq_set_state("machine check", 1);
1847058581aSAndreas Färber                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
185d0dfae6eSj_mayer             }
186d0dfae6eSj_mayer             break;
187d0dfae6eSj_mayer         case PPC970_INPUT_CKSTP:
188d0dfae6eSj_mayer             /* Level sensitive - active low */
189d0dfae6eSj_mayer             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
190d0dfae6eSj_mayer             if (level) {
191af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("stop");
192259186a7SAndreas Färber                 cs->halted = 1;
193d0dfae6eSj_mayer             } else {
194af96d2e6SCédric Le Goater                 trace_ppc_irq_cpu("restart");
195259186a7SAndreas Färber                 cs->halted = 0;
196259186a7SAndreas Färber                 qemu_cpu_kick(cs);
197d0dfae6eSj_mayer             }
198d0dfae6eSj_mayer             break;
199d0dfae6eSj_mayer         case PPC970_INPUT_HRESET:
200d0dfae6eSj_mayer             /* Level sensitive - active low */
201d0dfae6eSj_mayer             if (level) {
202c3affe56SAndreas Färber                 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
203d0dfae6eSj_mayer             }
204d0dfae6eSj_mayer             break;
205d0dfae6eSj_mayer         case PPC970_INPUT_SRESET:
206af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("RESET IRQ", level);
2077058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
208d0dfae6eSj_mayer             break;
209d0dfae6eSj_mayer         case PPC970_INPUT_TBEN:
210af96d2e6SCédric Le Goater             trace_ppc_irq_set_state("TBEN IRQ", level);
211d0dfae6eSj_mayer             /* XXX: TODO */
212d0dfae6eSj_mayer             break;
213d0dfae6eSj_mayer         default:
2147279810bSCédric Le Goater             g_assert_not_reached();
215d0dfae6eSj_mayer         }
216d0dfae6eSj_mayer         if (level)
217d0dfae6eSj_mayer             env->irq_input_state |= 1 << pin;
218d0dfae6eSj_mayer         else
219d0dfae6eSj_mayer             env->irq_input_state &= ~(1 << pin);
220d0dfae6eSj_mayer     }
221d0dfae6eSj_mayer }
222d0dfae6eSj_mayer 
ppc970_irq_init(PowerPCCPU * cpu)223aa5a9e24SPaolo Bonzini void ppc970_irq_init(PowerPCCPU *cpu)
224d0dfae6eSj_mayer {
2259fd0122eSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), ppc970_set_irq, PPC970_INPUT_NB);
226d0dfae6eSj_mayer }
2279d52e907SDavid Gibson 
2289d52e907SDavid Gibson /* POWER7 internal IRQ controller */
power7_set_irq(void * opaque,int pin,int level)2299d52e907SDavid Gibson static void power7_set_irq(void *opaque, int pin, int level)
2309d52e907SDavid Gibson {
231a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
2329d52e907SDavid Gibson 
233af96d2e6SCédric Le Goater     trace_ppc_irq_set(&cpu->env, pin, level);
2349d52e907SDavid Gibson 
2359d52e907SDavid Gibson     switch (pin) {
2369d52e907SDavid Gibson     case POWER7_INPUT_INT:
2379d52e907SDavid Gibson         /* Level sensitive - active high */
238af96d2e6SCédric Le Goater         trace_ppc_irq_set_state("external IRQ", level);
2397058581aSAndreas Färber         ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
2409d52e907SDavid Gibson         break;
2419d52e907SDavid Gibson     default:
2427279810bSCédric Le Goater         g_assert_not_reached();
2439d52e907SDavid Gibson     }
2449d52e907SDavid Gibson }
2459d52e907SDavid Gibson 
ppcPOWER7_irq_init(PowerPCCPU * cpu)246aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu)
2479d52e907SDavid Gibson {
2489fd0122eSCédric Le Goater     qdev_init_gpio_in(DEVICE(cpu), power7_set_irq, POWER7_INPUT_NB);
2499d52e907SDavid Gibson }
25067afe775SBenjamin Herrenschmidt 
25167afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */
power9_set_irq(void * opaque,int pin,int level)25267afe775SBenjamin Herrenschmidt static void power9_set_irq(void *opaque, int pin, int level)
25367afe775SBenjamin Herrenschmidt {
25467afe775SBenjamin Herrenschmidt     PowerPCCPU *cpu = opaque;
25567afe775SBenjamin Herrenschmidt 
256af96d2e6SCédric Le Goater     trace_ppc_irq_set(&cpu->env, pin, level);
25767afe775SBenjamin Herrenschmidt 
25867afe775SBenjamin Herrenschmidt     switch (pin) {
25967afe775SBenjamin Herrenschmidt     case POWER9_INPUT_INT:
26067afe775SBenjamin Herrenschmidt         /* Level sensitive - active high */
261af96d2e6SCédric Le Goater         trace_ppc_irq_set_state("external IRQ", level);
26267afe775SBenjamin Herrenschmidt         ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
26367afe775SBenjamin Herrenschmidt         break;
26467afe775SBenjamin Herrenschmidt     case POWER9_INPUT_HINT:
26567afe775SBenjamin Herrenschmidt         /* Level sensitive - active high */
266af96d2e6SCédric Le Goater         trace_ppc_irq_set_state("HV external IRQ", level);
26767afe775SBenjamin Herrenschmidt         ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level);
26867afe775SBenjamin Herrenschmidt         break;
26967afe775SBenjamin Herrenschmidt     default:
2707279810bSCédric Le Goater         g_assert_not_reached();
27167afe775SBenjamin Herrenschmidt     }
27267afe775SBenjamin Herrenschmidt }
27367afe775SBenjamin Herrenschmidt 
ppcPOWER9_irq_init(PowerPCCPU * cpu)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 
ppc40x_core_reset(PowerPCCPU * cpu)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 
ppc40x_chip_reset(PowerPCCPU * cpu)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 
ppc40x_system_reset(PowerPCCPU * cpu)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 
store_40x_dbcr0(CPUPPCState * env,uint32_t val)31352144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val)
31452144b69SThomas Huth {
315db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
31652144b69SThomas Huth 
317195801d7SStefan Hajnoczi     bql_lock();
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 
337195801d7SStefan Hajnoczi     bql_unlock();
33852144b69SThomas Huth }
33952144b69SThomas Huth 
3404e290a0bSj_mayer /* PowerPC 40x internal IRQ controller */
ppc40x_set_irq(void * opaque,int pin,int level)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 
ppc40x_irq_init(PowerPCCPU * cpu)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 */
ppce500_set_irq(void * opaque,int pin,int level)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 
ppce500_irq_init(PowerPCCPU * cpu)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 */
ppce500_set_mpic_proxy(bool enabled)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  */
ns_to_tb(uint32_t freq,int64_t clock)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 */
tb_to_ns_round_up(uint32_t freq,uint64_t tb)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 
cpu_ppc_get_tb(ppc_tb_t * tb_env,uint64_t vmclk,int64_t tb_offset)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 
cpu_ppc_load_tbl(CPUPPCState * env)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 
_cpu_ppc_load_tbu(CPUPPCState * env)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 
cpu_ppc_load_tbu(CPUPPCState * env)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 
cpu_ppc_store_tb(ppc_tb_t * tb_env,uint64_t vmclk,int64_t * tb_offsetp,uint64_t value)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 
cpu_ppc_store_tbl(CPUPPCState * env,uint32_t value)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 
_cpu_ppc_store_tbu(CPUPPCState * env,uint32_t value)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 
cpu_ppc_store_tbu(CPUPPCState * env,uint32_t value)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 
cpu_ppc_load_atbl(CPUPPCState * env)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 
cpu_ppc_load_atbu(CPUPPCState * env)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 
cpu_ppc_store_atbl(CPUPPCState * env,uint32_t value)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 
cpu_ppc_store_atbu(CPUPPCState * env,uint32_t value)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 
cpu_ppc_increase_tb_by_offset(CPUPPCState * env,int64_t offset)63649771107SHarsh Prateek Bora void cpu_ppc_increase_tb_by_offset(CPUPPCState *env, int64_t offset)
63749771107SHarsh Prateek Bora {
63849771107SHarsh Prateek Bora     env->tb_env->tb_offset += offset;
63949771107SHarsh Prateek Bora }
64049771107SHarsh Prateek Bora 
cpu_ppc_decrease_tb_by_offset(CPUPPCState * env,int64_t offset)64149771107SHarsh Prateek Bora void cpu_ppc_decrease_tb_by_offset(CPUPPCState *env, int64_t offset)
64249771107SHarsh Prateek Bora {
64349771107SHarsh Prateek Bora     env->tb_env->tb_offset -= offset;
64449771107SHarsh Prateek Bora }
64549771107SHarsh Prateek Bora 
cpu_ppc_load_vtb(CPUPPCState * env)6465d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env)
6475d62725bSSuraj Jitindar Singh {
6485d62725bSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
6495d62725bSSuraj Jitindar Singh 
6505d62725bSSuraj Jitindar Singh     return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
6515d62725bSSuraj Jitindar Singh                           tb_env->vtb_offset);
6525d62725bSSuraj Jitindar Singh }
6535d62725bSSuraj Jitindar Singh 
cpu_ppc_store_vtb(CPUPPCState * env,uint64_t value)6545d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value)
6555d62725bSSuraj Jitindar Singh {
6565d62725bSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
6575d62725bSSuraj Jitindar Singh 
6585d62725bSSuraj Jitindar Singh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
6595d62725bSSuraj Jitindar Singh                      &tb_env->vtb_offset, value);
6605d62725bSSuraj Jitindar Singh }
6615d62725bSSuraj Jitindar Singh 
cpu_ppc_store_tbu40(CPUPPCState * env,uint64_t value)662f0ec31b1SSuraj Jitindar Singh void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value)
663f0ec31b1SSuraj Jitindar Singh {
664f0ec31b1SSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
6652ad2e113SNicholas Piggin     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
666f0ec31b1SSuraj Jitindar Singh     uint64_t tb;
667f0ec31b1SSuraj Jitindar Singh 
6682ad2e113SNicholas Piggin     tb = cpu_ppc_get_tb(tb_env, clock, tb_env->tb_offset);
669f0ec31b1SSuraj Jitindar Singh     tb &= 0xFFFFFFUL;
670f0ec31b1SSuraj Jitindar Singh     tb |= (value & ~0xFFFFFFUL);
6712ad2e113SNicholas Piggin     cpu_ppc_store_tb(tb_env, clock, &tb_env->tb_offset, tb);
672f0ec31b1SSuraj Jitindar Singh }
673f0ec31b1SSuraj Jitindar Singh 
cpu_ppc_tb_stop(CPUPPCState * env)674e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env)
675dbdd2506Sj_mayer {
676c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
677dbdd2506Sj_mayer     uint64_t tb, atb, vmclk;
678dbdd2506Sj_mayer 
679dbdd2506Sj_mayer     /* If the time base is already frozen, do nothing */
680dbdd2506Sj_mayer     if (tb_env->tb_freq != 0) {
681bc72ad67SAlex Bligh         vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
682dbdd2506Sj_mayer         /* Get the time base */
683dbdd2506Sj_mayer         tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
684dbdd2506Sj_mayer         /* Get the alternate time base */
685dbdd2506Sj_mayer         atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
686dbdd2506Sj_mayer         /* Store the time base value (ie compute the current offset) */
687dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
688dbdd2506Sj_mayer         /* Store the alternate time base value (compute the current offset) */
689dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
690dbdd2506Sj_mayer         /* Set the time base frequency to zero */
691dbdd2506Sj_mayer         tb_env->tb_freq = 0;
692dbdd2506Sj_mayer         /* Now, the time bases are frozen to tb_offset / atb_offset value */
693dbdd2506Sj_mayer     }
694dbdd2506Sj_mayer }
695dbdd2506Sj_mayer 
cpu_ppc_tb_start(CPUPPCState * env)696e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env)
697dbdd2506Sj_mayer {
698c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
699dbdd2506Sj_mayer     uint64_t tb, atb, vmclk;
700dbdd2506Sj_mayer 
701dbdd2506Sj_mayer     /* If the time base is not frozen, do nothing */
702dbdd2506Sj_mayer     if (tb_env->tb_freq == 0) {
703bc72ad67SAlex Bligh         vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
704dbdd2506Sj_mayer         /* Get the time base from tb_offset */
705dbdd2506Sj_mayer         tb = tb_env->tb_offset;
706dbdd2506Sj_mayer         /* Get the alternate time base from atb_offset */
707dbdd2506Sj_mayer         atb = tb_env->atb_offset;
708dbdd2506Sj_mayer         /* Restore the tb frequency from the decrementer frequency */
709dbdd2506Sj_mayer         tb_env->tb_freq = tb_env->decr_freq;
710dbdd2506Sj_mayer         /* Store the time base value */
711dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
712dbdd2506Sj_mayer         /* Store the alternate time base value */
713dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
714dbdd2506Sj_mayer     }
7159fddaa0cSbellard }
7169fddaa0cSbellard 
ppc_decr_clear_on_delivery(CPUPPCState * env)717e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env)
718e81a982aSAlexander Graf {
719e81a982aSAlexander Graf     ppc_tb_t *tb_env = env->tb_env;
720e81a982aSAlexander Graf     int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL;
721e81a982aSAlexander Graf     return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
722e81a982aSAlexander Graf }
723e81a982aSAlexander Graf 
__cpu_ppc_load_decr(CPUPPCState * env,int64_t now,uint64_t next)724ea62f8a5SNicholas Piggin static inline int64_t __cpu_ppc_load_decr(CPUPPCState *env, int64_t now,
725ea62f8a5SNicholas Piggin                                           uint64_t next)
7269fddaa0cSbellard {
727c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
728ea62f8a5SNicholas Piggin     uint64_t n;
7298e0a5ac8SNicholas Piggin     int64_t decr;
7309fddaa0cSbellard 
7318e0a5ac8SNicholas Piggin     n = ns_to_tb(tb_env->decr_freq, now);
732f10827a8SClément Chigot 
733f10827a8SClément Chigot     /* BookE timers stop when reaching 0.  */
734f10827a8SClément Chigot     if (next < n && tb_env->flags & PPC_TIMER_BOOKE) {
735ddd1055bSFabien Chouteau         decr = 0;
736ddd1055bSFabien Chouteau     } else {
7378e0a5ac8SNicholas Piggin         decr = next - n;
738ddd1055bSFabien Chouteau     }
7398e0a5ac8SNicholas Piggin 
740af96d2e6SCédric Le Goater     trace_ppc_decr_load(decr);
74176a66253Sj_mayer 
7429fddaa0cSbellard     return decr;
7439fddaa0cSbellard }
7449fddaa0cSbellard 
_cpu_ppc_load_decr(CPUPPCState * env,int64_t now)745ea62f8a5SNicholas Piggin static target_ulong _cpu_ppc_load_decr(CPUPPCState *env, int64_t now)
74658a7d328Sj_mayer {
747c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
748a8dafa52SSuraj Jitindar Singh     uint64_t decr;
74958a7d328Sj_mayer 
750ea62f8a5SNicholas Piggin     decr = __cpu_ppc_load_decr(env, now, tb_env->decr_next);
751a8dafa52SSuraj Jitindar Singh 
752a8dafa52SSuraj Jitindar Singh     /*
753e6a19a64SMichael Tokarev      * If large decrementer is enabled then the decrementer is signed extended
754a8dafa52SSuraj Jitindar Singh      * to 64 bits, otherwise it is a 32 bit value.
755a8dafa52SSuraj Jitindar Singh      */
756a8dafa52SSuraj Jitindar Singh     if (env->spr[SPR_LPCR] & LPCR_LD) {
757c8fbc6b9SNicholas Piggin         PowerPCCPU *cpu = env_archcpu(env);
758c8fbc6b9SNicholas Piggin         PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
759c8fbc6b9SNicholas Piggin         return sextract64(decr, 0, pcc->lrg_decr_bits);
760a8dafa52SSuraj Jitindar Singh     }
761a8dafa52SSuraj Jitindar Singh     return (uint32_t) decr;
76258a7d328Sj_mayer }
76358a7d328Sj_mayer 
cpu_ppc_load_decr(CPUPPCState * env)764ea62f8a5SNicholas Piggin target_ulong cpu_ppc_load_decr(CPUPPCState *env)
765ea62f8a5SNicholas Piggin {
766ea62f8a5SNicholas Piggin     if (kvm_enabled()) {
767ea62f8a5SNicholas Piggin         return env->spr[SPR_DECR];
768ea62f8a5SNicholas Piggin     } else {
769ea62f8a5SNicholas Piggin         return _cpu_ppc_load_decr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
770ea62f8a5SNicholas Piggin     }
771ea62f8a5SNicholas Piggin }
772ea62f8a5SNicholas Piggin 
_cpu_ppc_load_hdecr(CPUPPCState * env,int64_t now)773ea62f8a5SNicholas Piggin static target_ulong _cpu_ppc_load_hdecr(CPUPPCState *env, int64_t now)
77458a7d328Sj_mayer {
775db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
776a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
777c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
778a8dafa52SSuraj Jitindar Singh     uint64_t hdecr;
77958a7d328Sj_mayer 
780ea62f8a5SNicholas Piggin     hdecr =  __cpu_ppc_load_decr(env, now, tb_env->hdecr_next);
781a8dafa52SSuraj Jitindar Singh 
782a8dafa52SSuraj Jitindar Singh     /*
783a8dafa52SSuraj Jitindar Singh      * If we have a large decrementer (POWER9 or later) then hdecr is sign
784a8dafa52SSuraj Jitindar Singh      * extended to 64 bits, otherwise it is 32 bits.
785a8dafa52SSuraj Jitindar Singh      */
786a8dafa52SSuraj Jitindar Singh     if (pcc->lrg_decr_bits > 32) {
787c8fbc6b9SNicholas Piggin         return sextract64(hdecr, 0, pcc->lrg_decr_bits);
788a8dafa52SSuraj Jitindar Singh     }
789a8dafa52SSuraj Jitindar Singh     return (uint32_t) hdecr;
79058a7d328Sj_mayer }
79158a7d328Sj_mayer 
cpu_ppc_load_hdecr(CPUPPCState * env)792ea62f8a5SNicholas Piggin target_ulong cpu_ppc_load_hdecr(CPUPPCState *env)
793ea62f8a5SNicholas Piggin {
794ea62f8a5SNicholas Piggin     return _cpu_ppc_load_hdecr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
795ea62f8a5SNicholas Piggin }
796ea62f8a5SNicholas Piggin 
cpu_ppc_load_purr(CPUPPCState * env)797e2684c0bSAndreas Färber uint64_t cpu_ppc_load_purr (CPUPPCState *env)
79858a7d328Sj_mayer {
799c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
80058a7d328Sj_mayer 
8015cc7e69fSSuraj Jitindar Singh     return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
8025cc7e69fSSuraj Jitindar Singh                           tb_env->purr_offset);
80358a7d328Sj_mayer }
80458a7d328Sj_mayer 
8059fddaa0cSbellard /* When decrementer expires,
8069fddaa0cSbellard  * all we need to do is generate or queue a CPU exception
8079fddaa0cSbellard  */
cpu_ppc_decr_excp(PowerPCCPU * cpu)8087e0a9247SAndreas Färber static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
8099fddaa0cSbellard {
8109fddaa0cSbellard     /* Raise it */
811af96d2e6SCédric Le Goater     trace_ppc_decr_excp("raise");
8127058581aSAndreas Färber     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
8139fddaa0cSbellard }
8149fddaa0cSbellard 
cpu_ppc_decr_lower(PowerPCCPU * cpu)815e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu)
816e81a982aSAlexander Graf {
817e81a982aSAlexander Graf     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
818e81a982aSAlexander Graf }
819e81a982aSAlexander Graf 
cpu_ppc_hdecr_excp(PowerPCCPU * cpu)8207e0a9247SAndreas Färber static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
82158a7d328Sj_mayer {
8224b236b62SBenjamin Herrenschmidt     CPUPPCState *env = &cpu->env;
8234b236b62SBenjamin Herrenschmidt 
82458a7d328Sj_mayer     /* Raise it */
825af96d2e6SCédric Le Goater     trace_ppc_decr_excp("raise HV");
8264b236b62SBenjamin Herrenschmidt 
8274b236b62SBenjamin Herrenschmidt     /* The architecture specifies that we don't deliver HDEC
8284b236b62SBenjamin Herrenschmidt      * interrupts in a PM state. Not only they don't cause a
8294b236b62SBenjamin Herrenschmidt      * wakeup but they also get effectively discarded.
8304b236b62SBenjamin Herrenschmidt      */
8311e7fd61dSBenjamin Herrenschmidt     if (!env->resume_as_sreset) {
8327058581aSAndreas Färber         ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
83358a7d328Sj_mayer     }
8344b236b62SBenjamin Herrenschmidt }
83558a7d328Sj_mayer 
cpu_ppc_hdecr_lower(PowerPCCPU * cpu)836e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
837e81a982aSAlexander Graf {
838e81a982aSAlexander Graf     ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
839e81a982aSAlexander Graf }
840e81a982aSAlexander Graf 
__cpu_ppc_store_decr(PowerPCCPU * cpu,int64_t now,uint64_t * nextp,QEMUTimer * timer,void (* raise_excp)(void *),void (* lower_excp)(PowerPCCPU *),uint32_t flags,target_ulong decr,target_ulong value,int nr_bits)841ea62f8a5SNicholas Piggin static void __cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now, uint64_t *nextp,
8421246b259SStefan Weil                                  QEMUTimer *timer,
843e81a982aSAlexander Graf                                  void (*raise_excp)(void *),
844e81a982aSAlexander Graf                                  void (*lower_excp)(PowerPCCPU *),
845a5ff7875SNicholas Piggin                                  uint32_t flags, target_ulong decr,
846a5ff7875SNicholas Piggin                                  target_ulong value, int nr_bits)
8479fddaa0cSbellard {
8487e0a9247SAndreas Färber     CPUPPCState *env = &cpu->env;
849c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
850ea62f8a5SNicholas Piggin     uint64_t next;
8514d9b8ef9SCédric Le Goater     int64_t signed_value;
8524d9b8ef9SCédric Le Goater     int64_t signed_decr;
8539fddaa0cSbellard 
854a8dafa52SSuraj Jitindar Singh     /* Truncate value to decr_width and sign extend for simplicity */
85509d2db9fSNicholas Piggin     value = extract64(value, 0, nr_bits);
85609d2db9fSNicholas Piggin     decr = extract64(decr, 0, nr_bits);
8574d9b8ef9SCédric Le Goater     signed_value = sextract64(value, 0, nr_bits);
8584d9b8ef9SCédric Le Goater     signed_decr = sextract64(decr, 0, nr_bits);
859a8dafa52SSuraj Jitindar Singh 
860af96d2e6SCédric Le Goater     trace_ppc_decr_store(nr_bits, decr, value);
86155f7d4b0SDavid Gibson 
862e81a982aSAlexander Graf     /*
863febb71d5SNicholas Piggin      * Calculate the next decrementer event and set a timer.
864febb71d5SNicholas Piggin      * decr_next is in timebase units to keep rounding simple. Note it is
865febb71d5SNicholas Piggin      * not adjusted by tb_offset because if TB changes via tb_offset changing,
866febb71d5SNicholas Piggin      * decrementer does not change, so not directly comparable with TB.
867febb71d5SNicholas Piggin      */
868febb71d5SNicholas Piggin     next = ns_to_tb(tb_env->decr_freq, now) + value;
869febb71d5SNicholas Piggin     *nextp = next; /* nextp is in timebase units */
870febb71d5SNicholas Piggin 
871febb71d5SNicholas Piggin     /*
87217dd1354SNicholas Piggin      * Going from 1 -> 0 or 0 -> -1 is the event to generate a DEC interrupt.
873e81a982aSAlexander Graf      *
874e81a982aSAlexander Graf      * On MSB level based DEC implementations the MSB always means the interrupt
875e81a982aSAlexander Graf      * is pending, so raise it on those.
876e81a982aSAlexander Graf      *
877e81a982aSAlexander Graf      * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
878e81a982aSAlexander Graf      * an edge interrupt, so raise it here too.
879e81a982aSAlexander Graf      */
880a5ff7875SNicholas Piggin     if (((flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) ||
881a5ff7875SNicholas Piggin         ((flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0
8824d9b8ef9SCédric Le Goater           && signed_decr >= 0)) {
883e81a982aSAlexander Graf         (*raise_excp)(cpu);
884e81a982aSAlexander Graf         return;
885e81a982aSAlexander Graf     }
886e81a982aSAlexander Graf 
887e81a982aSAlexander Graf     /* On MSB level based systems a 0 for the MSB stops interrupt delivery */
888a5ff7875SNicholas Piggin     if (signed_value >= 0 && (flags & PPC_DECR_UNDERFLOW_LEVEL)) {
889e81a982aSAlexander Graf         (*lower_excp)(cpu);
890e81a982aSAlexander Graf     }
891e81a982aSAlexander Graf 
8929fddaa0cSbellard     /* Adjust timer */
8938e0a5ac8SNicholas Piggin     timer_mod(timer, tb_to_ns_round_up(tb_env->decr_freq, next));
894ddd1055bSFabien Chouteau }
89558a7d328Sj_mayer 
_cpu_ppc_store_decr(PowerPCCPU * cpu,int64_t now,target_ulong decr,target_ulong value,int nr_bits)896ea62f8a5SNicholas Piggin static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, int64_t now,
897ea62f8a5SNicholas Piggin                                        target_ulong decr, target_ulong value,
898ea62f8a5SNicholas Piggin                                        int nr_bits)
89958a7d328Sj_mayer {
9007e0a9247SAndreas Färber     ppc_tb_t *tb_env = cpu->env.tb_env;
90158a7d328Sj_mayer 
902ea62f8a5SNicholas Piggin     __cpu_ppc_store_decr(cpu, now, &tb_env->decr_next, tb_env->decr_timer,
903a5ff7875SNicholas Piggin                          tb_env->decr_timer->cb, &cpu_ppc_decr_lower,
904a5ff7875SNicholas Piggin                          tb_env->flags, decr, value, nr_bits);
9059fddaa0cSbellard }
9069fddaa0cSbellard 
cpu_ppc_store_decr(CPUPPCState * env,target_ulong value)907a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value)
9089fddaa0cSbellard {
909db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
910a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
911ea62f8a5SNicholas Piggin     int64_t now;
912ea62f8a5SNicholas Piggin     target_ulong decr;
913a8dafa52SSuraj Jitindar Singh     int nr_bits = 32;
9147e0a9247SAndreas Färber 
915ea62f8a5SNicholas Piggin     if (kvm_enabled()) {
916ea62f8a5SNicholas Piggin         /* KVM handles decrementer exceptions, we don't need our own timer */
917ea62f8a5SNicholas Piggin         return;
918ea62f8a5SNicholas Piggin     }
919ea62f8a5SNicholas Piggin 
920a8dafa52SSuraj Jitindar Singh     if (env->spr[SPR_LPCR] & LPCR_LD) {
921a8dafa52SSuraj Jitindar Singh         nr_bits = pcc->lrg_decr_bits;
922a8dafa52SSuraj Jitindar Singh     }
923a8dafa52SSuraj Jitindar Singh 
924ea62f8a5SNicholas Piggin     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
925ea62f8a5SNicholas Piggin     decr = _cpu_ppc_load_decr(env, now);
926ea62f8a5SNicholas Piggin     _cpu_ppc_store_decr(cpu, now, decr, value, nr_bits);
9279fddaa0cSbellard }
9289fddaa0cSbellard 
cpu_ppc_decr_cb(void * opaque)9299fddaa0cSbellard static void cpu_ppc_decr_cb(void *opaque)
9309fddaa0cSbellard {
93150c680f0SAndreas Färber     PowerPCCPU *cpu = opaque;
9327e0a9247SAndreas Färber 
933e81a982aSAlexander Graf     cpu_ppc_decr_excp(cpu);
9349fddaa0cSbellard }
9359fddaa0cSbellard 
_cpu_ppc_store_hdecr(PowerPCCPU * cpu,int64_t now,target_ulong hdecr,target_ulong value,int nr_bits)936ea62f8a5SNicholas Piggin static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, int64_t now,
937ea62f8a5SNicholas Piggin                                         target_ulong hdecr, target_ulong value,
938ea62f8a5SNicholas Piggin                                         int nr_bits)
93958a7d328Sj_mayer {
9407e0a9247SAndreas Färber     ppc_tb_t *tb_env = cpu->env.tb_env;
94158a7d328Sj_mayer 
942b172c56aSj_mayer     if (tb_env->hdecr_timer != NULL) {
943a5ff7875SNicholas Piggin         /* HDECR (Book3S 64bit) is edge-based, not level like DECR */
944ea62f8a5SNicholas Piggin         __cpu_ppc_store_decr(cpu, now, &tb_env->hdecr_next, tb_env->hdecr_timer,
945e81a982aSAlexander Graf                              tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
946a5ff7875SNicholas Piggin                              PPC_DECR_UNDERFLOW_TRIGGERED,
947a8dafa52SSuraj Jitindar Singh                              hdecr, value, nr_bits);
94858a7d328Sj_mayer     }
949b172c56aSj_mayer }
95058a7d328Sj_mayer 
cpu_ppc_store_hdecr(CPUPPCState * env,target_ulong value)951a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value)
95258a7d328Sj_mayer {
953db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
954a8dafa52SSuraj Jitindar Singh     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
955ea62f8a5SNicholas Piggin     int64_t now;
956ea62f8a5SNicholas Piggin     target_ulong hdecr;
9577e0a9247SAndreas Färber 
958ea62f8a5SNicholas Piggin     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
959ea62f8a5SNicholas Piggin     hdecr = _cpu_ppc_load_hdecr(env, now);
960ea62f8a5SNicholas Piggin     _cpu_ppc_store_hdecr(cpu, now, hdecr, value, pcc->lrg_decr_bits);
96158a7d328Sj_mayer }
96258a7d328Sj_mayer 
cpu_ppc_hdecr_cb(void * opaque)96358a7d328Sj_mayer static void cpu_ppc_hdecr_cb(void *opaque)
96458a7d328Sj_mayer {
96550c680f0SAndreas Färber     PowerPCCPU *cpu = opaque;
9667e0a9247SAndreas Färber 
967e81a982aSAlexander Graf     cpu_ppc_hdecr_excp(cpu);
96858a7d328Sj_mayer }
96958a7d328Sj_mayer 
_cpu_ppc_store_purr(CPUPPCState * env,int64_t now,uint64_t value)970ea62f8a5SNicholas Piggin static void _cpu_ppc_store_purr(CPUPPCState *env, int64_t now, uint64_t value)
97158a7d328Sj_mayer {
9725cc7e69fSSuraj Jitindar Singh     ppc_tb_t *tb_env = env->tb_env;
97358a7d328Sj_mayer 
974ea62f8a5SNicholas Piggin     cpu_ppc_store_tb(tb_env, now, &tb_env->purr_offset, value);
975ea62f8a5SNicholas Piggin }
976ea62f8a5SNicholas Piggin 
cpu_ppc_store_purr(CPUPPCState * env,uint64_t value)977ea62f8a5SNicholas Piggin void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value)
978ea62f8a5SNicholas Piggin {
979ea62f8a5SNicholas Piggin     _cpu_ppc_store_purr(env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), value);
98058a7d328Sj_mayer }
98158a7d328Sj_mayer 
timebase_save(PPCTimebase * tb)98242043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb)
98398a8b524SAlexey Kardashevskiy {
9844a7428c5SChristopher Covington     uint64_t ticks = cpu_get_host_ticks();
98598a8b524SAlexey Kardashevskiy     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
98698a8b524SAlexey Kardashevskiy 
98798a8b524SAlexey Kardashevskiy     if (!first_ppc_cpu->env.tb_env) {
98898a8b524SAlexey Kardashevskiy         error_report("No timebase object");
98998a8b524SAlexey Kardashevskiy         return;
99098a8b524SAlexey Kardashevskiy     }
99198a8b524SAlexey Kardashevskiy 
9929db680f8SNicholas Piggin     if (replay_mode == REPLAY_MODE_NONE) {
99342043e4fSLaurent Vivier         /* not used anymore, we keep it for compatibility */
99477bad151SPaolo Bonzini         tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
9959db680f8SNicholas Piggin     } else {
9969db680f8SNicholas Piggin         /* simpler for record-replay to avoid this event, compat not needed */
9979db680f8SNicholas Piggin         tb->time_of_the_day_ns = 0;
9989db680f8SNicholas Piggin     }
9999db680f8SNicholas Piggin 
100098a8b524SAlexey Kardashevskiy     /*
100142043e4fSLaurent Vivier      * tb_offset is only expected to be changed by QEMU so
100298a8b524SAlexey Kardashevskiy      * there is no need to update it from KVM here
100398a8b524SAlexey Kardashevskiy      */
100498a8b524SAlexey Kardashevskiy     tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
1005d14f3397SMaxiwell S. Garcia 
1006711dfb24SGreg Kurz     tb->runstate_paused =
1007711dfb24SGreg Kurz         runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM);
100898a8b524SAlexey Kardashevskiy }
100998a8b524SAlexey Kardashevskiy 
timebase_load(PPCTimebase * tb)101042043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb)
101198a8b524SAlexey Kardashevskiy {
101298a8b524SAlexey Kardashevskiy     CPUState *cpu;
101398a8b524SAlexey Kardashevskiy     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
101442043e4fSLaurent Vivier     int64_t tb_off_adj, tb_off;
101598a8b524SAlexey Kardashevskiy     unsigned long freq;
101698a8b524SAlexey Kardashevskiy 
101798a8b524SAlexey Kardashevskiy     if (!first_ppc_cpu->env.tb_env) {
101898a8b524SAlexey Kardashevskiy         error_report("No timebase object");
101942043e4fSLaurent Vivier         return;
102098a8b524SAlexey Kardashevskiy     }
102198a8b524SAlexey Kardashevskiy 
102298a8b524SAlexey Kardashevskiy     freq = first_ppc_cpu->env.tb_env->tb_freq;
102398a8b524SAlexey Kardashevskiy 
102442043e4fSLaurent Vivier     tb_off_adj = tb->guest_timebase - cpu_get_host_ticks();
102598a8b524SAlexey Kardashevskiy 
102698a8b524SAlexey Kardashevskiy     tb_off = first_ppc_cpu->env.tb_env->tb_offset;
102798a8b524SAlexey Kardashevskiy     trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off,
102898a8b524SAlexey Kardashevskiy                         (tb_off_adj - tb_off) / freq);
102998a8b524SAlexey Kardashevskiy 
103098a8b524SAlexey Kardashevskiy     /* Set new offset to all CPUs */
103198a8b524SAlexey Kardashevskiy     CPU_FOREACH(cpu) {
103298a8b524SAlexey Kardashevskiy         PowerPCCPU *pcpu = POWERPC_CPU(cpu);
103398a8b524SAlexey Kardashevskiy         pcpu->env.tb_env->tb_offset = tb_off_adj;
10349723295aSGreg Kurz         kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset);
103542043e4fSLaurent Vivier     }
103698a8b524SAlexey Kardashevskiy }
103798a8b524SAlexey Kardashevskiy 
cpu_ppc_clock_vm_state_change(void * opaque,bool running,RunState state)1038538f0497SPhilippe Mathieu-Daudé void cpu_ppc_clock_vm_state_change(void *opaque, bool running,
103942043e4fSLaurent Vivier                                    RunState state)
104042043e4fSLaurent Vivier {
104142043e4fSLaurent Vivier     PPCTimebase *tb = opaque;
104242043e4fSLaurent Vivier 
104342043e4fSLaurent Vivier     if (running) {
104442043e4fSLaurent Vivier         timebase_load(tb);
104542043e4fSLaurent Vivier     } else {
104642043e4fSLaurent Vivier         timebase_save(tb);
104742043e4fSLaurent Vivier     }
104842043e4fSLaurent Vivier }
104942043e4fSLaurent Vivier 
105042043e4fSLaurent Vivier /*
1051d14f3397SMaxiwell S. Garcia  * When migrating a running guest, read the clock just
1052d14f3397SMaxiwell S. Garcia  * before migration, so that the guest clock counts
1053d14f3397SMaxiwell S. Garcia  * during the events between:
105442043e4fSLaurent Vivier  *
105542043e4fSLaurent Vivier  *  * vm_stop()
105642043e4fSLaurent Vivier  *  *
105742043e4fSLaurent Vivier  *  * pre_save()
105842043e4fSLaurent Vivier  *
105942043e4fSLaurent Vivier  *  This reduces clock difference on migration from 5s
106042043e4fSLaurent Vivier  *  to 0.1s (when max_downtime == 5s), because sending the
106142043e4fSLaurent Vivier  *  final pages of memory (which happens between vm_stop()
106242043e4fSLaurent Vivier  *  and pre_save()) takes max_downtime.
106342043e4fSLaurent Vivier  */
timebase_pre_save(void * opaque)106444b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque)
106542043e4fSLaurent Vivier {
106642043e4fSLaurent Vivier     PPCTimebase *tb = opaque;
106742043e4fSLaurent Vivier 
1068711dfb24SGreg Kurz     /* guest_timebase won't be overridden in case of paused guest or savevm */
1069d14f3397SMaxiwell S. Garcia     if (!tb->runstate_paused) {
107042043e4fSLaurent Vivier         timebase_save(tb);
1071d14f3397SMaxiwell S. Garcia     }
107244b1ff31SDr. David Alan Gilbert 
107344b1ff31SDr. David Alan Gilbert     return 0;
107498a8b524SAlexey Kardashevskiy }
107598a8b524SAlexey Kardashevskiy 
107698a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = {
107798a8b524SAlexey Kardashevskiy     .name = "timebase",
107898a8b524SAlexey Kardashevskiy     .version_id = 1,
107998a8b524SAlexey Kardashevskiy     .minimum_version_id = 1,
108098a8b524SAlexey Kardashevskiy     .pre_save = timebase_pre_save,
1081078ddbc9SRichard Henderson     .fields = (const VMStateField []) {
108298a8b524SAlexey Kardashevskiy         VMSTATE_UINT64(guest_timebase, PPCTimebase),
108398a8b524SAlexey Kardashevskiy         VMSTATE_INT64(time_of_the_day_ns, PPCTimebase),
108498a8b524SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
108598a8b524SAlexey Kardashevskiy     },
108698a8b524SAlexey Kardashevskiy };
108798a8b524SAlexey Kardashevskiy 
10889fddaa0cSbellard /* Set up (once) timebase frequency (in Hz) */
cpu_ppc_tb_init(CPUPPCState * env,uint32_t freq)108930d0647bSNicholas Piggin void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq)
10909fddaa0cSbellard {
1091db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
1092c227f099SAnthony Liguori     ppc_tb_t *tb_env;
10939fddaa0cSbellard 
1094b21e2380SMarkus Armbruster     tb_env = g_new0(ppc_tb_t, 1);
10959fddaa0cSbellard     env->tb_env = tb_env;
1096ddd1055bSFabien Chouteau     tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
1097d0db7cadSGreg Kurz     if (is_book3s_arch2x(env)) {
1098e81a982aSAlexander Graf         /* All Book3S 64bit CPUs implement level based DEC logic */
1099e81a982aSAlexander Graf         tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
1100e81a982aSAlexander Graf     }
11019fddaa0cSbellard     /* Create new timer */
1102eaf832fcSNicholas Piggin     tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
1103eaf832fcSNicholas Piggin                                       &cpu_ppc_decr_cb, cpu);
11045ff40b01SNicholas Piggin     if (env->has_hv_mode && !cpu->vhyp) {
1105eaf832fcSNicholas Piggin         tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
1106eaf832fcSNicholas Piggin                                            &cpu_ppc_hdecr_cb, cpu);
1107b172c56aSj_mayer     } else {
1108b172c56aSj_mayer         tb_env->hdecr_timer = NULL;
1109b172c56aSj_mayer     }
11109fddaa0cSbellard 
111130d0647bSNicholas Piggin     tb_env->tb_freq = freq;
111230d0647bSNicholas Piggin     tb_env->decr_freq = freq;
111330d0647bSNicholas Piggin }
111430d0647bSNicholas Piggin 
cpu_ppc_tb_reset(CPUPPCState * env)111530d0647bSNicholas Piggin void cpu_ppc_tb_reset(CPUPPCState *env)
111630d0647bSNicholas Piggin {
111730d0647bSNicholas Piggin     PowerPCCPU *cpu = env_archcpu(env);
111830d0647bSNicholas Piggin     ppc_tb_t *tb_env = env->tb_env;
111930d0647bSNicholas Piggin 
112030d0647bSNicholas Piggin     timer_del(tb_env->decr_timer);
112130d0647bSNicholas Piggin     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
112230d0647bSNicholas Piggin     tb_env->decr_next = 0;
112330d0647bSNicholas Piggin     if (tb_env->hdecr_timer != NULL) {
112430d0647bSNicholas Piggin         timer_del(tb_env->hdecr_timer);
112530d0647bSNicholas Piggin         ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
112630d0647bSNicholas Piggin         tb_env->hdecr_next = 0;
1127e8291ec1SNicholas Piggin         _cpu_ppc_store_hdecr(cpu, 0, 0, 0, 64);
112830d0647bSNicholas Piggin     }
112930d0647bSNicholas Piggin 
113030d0647bSNicholas Piggin     /*
113130d0647bSNicholas Piggin      * There is a bug in Linux 2.4 kernels:
113230d0647bSNicholas Piggin      * if a decrementer exception is pending when it enables msr_ee at startup,
113330d0647bSNicholas Piggin      * it's not ready to handle it...
1134e8291ec1SNicholas Piggin      *
1135e8291ec1SNicholas Piggin      * On machine reset, this is called before icount is reset, so for
1136e8291ec1SNicholas Piggin      * icount-mode, setting TB registers using now == qemu_clock_get_ns()
1137e8291ec1SNicholas Piggin      * results in them being garbage after icount is reset. Use an
1138e8291ec1SNicholas Piggin      * explicit now == 0 to get a consistent reset state.
113930d0647bSNicholas Piggin      */
1140e8291ec1SNicholas Piggin     _cpu_ppc_store_decr(cpu, 0, 0, -1, 64);
1141e8291ec1SNicholas Piggin     _cpu_ppc_store_purr(env, 0, 0);
11429fddaa0cSbellard }
11439fddaa0cSbellard 
cpu_ppc_tb_free(CPUPPCState * env)1144ef95a244SDaniel Henrique Barboza void cpu_ppc_tb_free(CPUPPCState *env)
1145ef95a244SDaniel Henrique Barboza {
1146ef95a244SDaniel Henrique Barboza     timer_free(env->tb_env->decr_timer);
1147ef95a244SDaniel Henrique Barboza     timer_free(env->tb_env->hdecr_timer);
1148ef95a244SDaniel Henrique Barboza     g_free(env->tb_env);
1149ef95a244SDaniel Henrique Barboza }
1150ef95a244SDaniel Henrique Barboza 
115193aeb702SNicholas Piggin /* cpu_ppc_hdecr_init may be used if the timer is not used by HDEC emulation */
cpu_ppc_hdecr_init(CPUPPCState * env)115293aeb702SNicholas Piggin void cpu_ppc_hdecr_init(CPUPPCState *env)
115393aeb702SNicholas Piggin {
115493aeb702SNicholas Piggin     PowerPCCPU *cpu = env_archcpu(env);
115593aeb702SNicholas Piggin 
115693aeb702SNicholas Piggin     assert(env->tb_env->hdecr_timer == NULL);
115793aeb702SNicholas Piggin 
115893aeb702SNicholas Piggin     env->tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
115993aeb702SNicholas Piggin                                             &cpu_ppc_hdecr_cb, cpu);
116093aeb702SNicholas Piggin }
116193aeb702SNicholas Piggin 
cpu_ppc_hdecr_exit(CPUPPCState * env)116293aeb702SNicholas Piggin void cpu_ppc_hdecr_exit(CPUPPCState *env)
116393aeb702SNicholas Piggin {
116493aeb702SNicholas Piggin     PowerPCCPU *cpu = env_archcpu(env);
116593aeb702SNicholas Piggin 
116693aeb702SNicholas Piggin     timer_free(env->tb_env->hdecr_timer);
116793aeb702SNicholas Piggin     env->tb_env->hdecr_timer = NULL;
116893aeb702SNicholas Piggin 
116993aeb702SNicholas Piggin     cpu_ppc_hdecr_lower(cpu);
117093aeb702SNicholas Piggin }
117193aeb702SNicholas Piggin 
1172636aaad7Sj_mayer /*****************************************************************************/
1173ddd1055bSFabien Chouteau /* PowerPC 40x timers */
1174636aaad7Sj_mayer 
1175636aaad7Sj_mayer /* PIT, FIT & WDT */
1176ddd1055bSFabien Chouteau typedef struct ppc40x_timer_t ppc40x_timer_t;
1177ddd1055bSFabien Chouteau struct ppc40x_timer_t {
1178636aaad7Sj_mayer     uint64_t pit_reload;  /* PIT auto-reload value        */
1179636aaad7Sj_mayer     uint64_t fit_next;    /* Tick for next FIT interrupt  */
11801246b259SStefan Weil     QEMUTimer *fit_timer;
1181636aaad7Sj_mayer     uint64_t wdt_next;    /* Tick for next WDT interrupt  */
11821246b259SStefan Weil     QEMUTimer *wdt_timer;
1183d63cb48dSEdgar E. Iglesias 
1184d63cb48dSEdgar E. Iglesias     /* 405 have the PIT, 440 have a DECR.  */
1185d63cb48dSEdgar E. Iglesias     unsigned int decr_excp;
1186636aaad7Sj_mayer };
1187636aaad7Sj_mayer 
1188636aaad7Sj_mayer /* Fixed interval timer */
cpu_4xx_fit_cb(void * opaque)1189636aaad7Sj_mayer static void cpu_4xx_fit_cb (void *opaque)
119076a66253Sj_mayer {
1191b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1192b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
1193c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1194ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1195636aaad7Sj_mayer     uint64_t now, next;
1196636aaad7Sj_mayer 
1197636aaad7Sj_mayer     tb_env = env->tb_env;
1198ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1199bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1200636aaad7Sj_mayer     switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
1201636aaad7Sj_mayer     case 0:
1202636aaad7Sj_mayer         next = 1 << 9;
1203636aaad7Sj_mayer         break;
1204636aaad7Sj_mayer     case 1:
1205636aaad7Sj_mayer         next = 1 << 13;
1206636aaad7Sj_mayer         break;
1207636aaad7Sj_mayer     case 2:
1208636aaad7Sj_mayer         next = 1 << 17;
1209636aaad7Sj_mayer         break;
1210636aaad7Sj_mayer     case 3:
1211636aaad7Sj_mayer         next = 1 << 21;
1212636aaad7Sj_mayer         break;
1213636aaad7Sj_mayer     default:
1214636aaad7Sj_mayer         /* Cannot occur, but makes gcc happy */
1215636aaad7Sj_mayer         return;
1216636aaad7Sj_mayer     }
1217eab08884SNicholas Piggin     next = now + tb_to_ns_round_up(tb_env->tb_freq, next);
1218bc72ad67SAlex Bligh     timer_mod(ppc40x_timer->fit_timer, next);
1219636aaad7Sj_mayer     env->spr[SPR_40x_TSR] |= 1 << 26;
12207058581aSAndreas Färber     if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) {
12217058581aSAndreas Färber         ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1);
12227058581aSAndreas Färber     }
1223af96d2e6SCédric Le Goater     trace_ppc4xx_fit((int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
1224636aaad7Sj_mayer                          env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
1225636aaad7Sj_mayer }
1226636aaad7Sj_mayer 
1227636aaad7Sj_mayer /* Programmable interval timer */
start_stop_pit(CPUPPCState * env,ppc_tb_t * tb_env,int is_excp)1228e2684c0bSAndreas Färber static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
1229636aaad7Sj_mayer {
1230ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1231636aaad7Sj_mayer     uint64_t now, next;
1232636aaad7Sj_mayer 
1233ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1234ddd1055bSFabien Chouteau     if (ppc40x_timer->pit_reload <= 1 ||
12354b6d0a4cSj_mayer         !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
12364b6d0a4cSj_mayer         (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
12374b6d0a4cSj_mayer         /* Stop PIT */
1238af96d2e6SCédric Le Goater         trace_ppc4xx_pit_stop();
1239bc72ad67SAlex Bligh         timer_del(tb_env->decr_timer);
12404b6d0a4cSj_mayer     } else {
1241af96d2e6SCédric Le Goater         trace_ppc4xx_pit_start(ppc40x_timer->pit_reload);
1242bc72ad67SAlex Bligh         now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
12438e0a5ac8SNicholas Piggin 
12448e0a5ac8SNicholas Piggin         if (is_excp) {
12458e0a5ac8SNicholas Piggin             tb_env->decr_next += ppc40x_timer->pit_reload;
12468e0a5ac8SNicholas Piggin         } else {
12478e0a5ac8SNicholas Piggin             tb_env->decr_next = ns_to_tb(tb_env->decr_freq, now)
12488e0a5ac8SNicholas Piggin                                 + ppc40x_timer->pit_reload;
12498e0a5ac8SNicholas Piggin         }
12508e0a5ac8SNicholas Piggin         next = tb_to_ns_round_up(tb_env->decr_freq, tb_env->decr_next);
1251bc72ad67SAlex Bligh         timer_mod(tb_env->decr_timer, next);
1252636aaad7Sj_mayer     }
12534b6d0a4cSj_mayer }
12544b6d0a4cSj_mayer 
cpu_4xx_pit_cb(void * opaque)12554b6d0a4cSj_mayer static void cpu_4xx_pit_cb (void *opaque)
12564b6d0a4cSj_mayer {
1257b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1258b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
1259c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1260ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
12614b6d0a4cSj_mayer 
12624b6d0a4cSj_mayer     tb_env = env->tb_env;
1263ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1264636aaad7Sj_mayer     env->spr[SPR_40x_TSR] |= 1 << 27;
12657058581aSAndreas Färber     if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) {
12667058581aSAndreas Färber         ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1);
12677058581aSAndreas Färber     }
12684b6d0a4cSj_mayer     start_stop_pit(env, tb_env, 1);
1269af96d2e6SCédric Le Goater     trace_ppc4xx_pit((int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
1270e96efcfcSj_mayer            (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
1271636aaad7Sj_mayer            env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
1272ddd1055bSFabien Chouteau            ppc40x_timer->pit_reload);
1273636aaad7Sj_mayer }
1274636aaad7Sj_mayer 
1275636aaad7Sj_mayer /* Watchdog timer */
cpu_4xx_wdt_cb(void * opaque)1276636aaad7Sj_mayer static void cpu_4xx_wdt_cb (void *opaque)
1277636aaad7Sj_mayer {
1278b1273a5eSCédric Le Goater     PowerPCCPU *cpu = opaque;
1279b1273a5eSCédric Le Goater     CPUPPCState *env = &cpu->env;
1280c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1281ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1282636aaad7Sj_mayer     uint64_t now, next;
1283636aaad7Sj_mayer 
1284636aaad7Sj_mayer     tb_env = env->tb_env;
1285ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1286bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1287636aaad7Sj_mayer     switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
1288636aaad7Sj_mayer     case 0:
1289636aaad7Sj_mayer         next = 1 << 17;
1290636aaad7Sj_mayer         break;
1291636aaad7Sj_mayer     case 1:
1292636aaad7Sj_mayer         next = 1 << 21;
1293636aaad7Sj_mayer         break;
1294636aaad7Sj_mayer     case 2:
1295636aaad7Sj_mayer         next = 1 << 25;
1296636aaad7Sj_mayer         break;
1297636aaad7Sj_mayer     case 3:
1298636aaad7Sj_mayer         next = 1 << 29;
1299636aaad7Sj_mayer         break;
1300636aaad7Sj_mayer     default:
1301636aaad7Sj_mayer         /* Cannot occur, but makes gcc happy */
1302636aaad7Sj_mayer         return;
1303636aaad7Sj_mayer     }
1304eab08884SNicholas Piggin     next = now + tb_to_ns_round_up(tb_env->decr_freq, next);
1305af96d2e6SCédric Le Goater     trace_ppc4xx_wdt(env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
1306636aaad7Sj_mayer     switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
1307636aaad7Sj_mayer     case 0x0:
1308636aaad7Sj_mayer     case 0x1:
1309bc72ad67SAlex Bligh         timer_mod(ppc40x_timer->wdt_timer, next);
1310ddd1055bSFabien Chouteau         ppc40x_timer->wdt_next = next;
1311a1f7f97bSPeter Maydell         env->spr[SPR_40x_TSR] |= 1U << 31;
1312636aaad7Sj_mayer         break;
1313636aaad7Sj_mayer     case 0x2:
1314bc72ad67SAlex Bligh         timer_mod(ppc40x_timer->wdt_timer, next);
1315ddd1055bSFabien Chouteau         ppc40x_timer->wdt_next = next;
1316636aaad7Sj_mayer         env->spr[SPR_40x_TSR] |= 1 << 30;
13177058581aSAndreas Färber         if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) {
13187058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1);
13197058581aSAndreas Färber         }
1320636aaad7Sj_mayer         break;
1321636aaad7Sj_mayer     case 0x3:
1322636aaad7Sj_mayer         env->spr[SPR_40x_TSR] &= ~0x30000000;
1323636aaad7Sj_mayer         env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
1324636aaad7Sj_mayer         switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
1325636aaad7Sj_mayer         case 0x0:
1326636aaad7Sj_mayer             /* No reset */
1327636aaad7Sj_mayer             break;
1328636aaad7Sj_mayer         case 0x1: /* Core reset */
1329f3273ba6SAndreas Färber             ppc40x_core_reset(cpu);
13308ecc7913Sj_mayer             break;
1331636aaad7Sj_mayer         case 0x2: /* Chip reset */
1332f3273ba6SAndreas Färber             ppc40x_chip_reset(cpu);
13338ecc7913Sj_mayer             break;
1334636aaad7Sj_mayer         case 0x3: /* System reset */
1335f3273ba6SAndreas Färber             ppc40x_system_reset(cpu);
13368ecc7913Sj_mayer             break;
1337636aaad7Sj_mayer         }
1338636aaad7Sj_mayer     }
133976a66253Sj_mayer }
134076a66253Sj_mayer 
store_40x_pit(CPUPPCState * env,target_ulong val)1341e2684c0bSAndreas Färber void store_40x_pit (CPUPPCState *env, target_ulong val)
134276a66253Sj_mayer {
1343c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1344ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1345636aaad7Sj_mayer 
1346636aaad7Sj_mayer     tb_env = env->tb_env;
1347ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1348af96d2e6SCédric Le Goater     trace_ppc40x_store_pit(val);
1349ddd1055bSFabien Chouteau     ppc40x_timer->pit_reload = val;
13504b6d0a4cSj_mayer     start_stop_pit(env, tb_env, 0);
135176a66253Sj_mayer }
135276a66253Sj_mayer 
load_40x_pit(CPUPPCState * env)1353e2684c0bSAndreas Färber target_ulong load_40x_pit (CPUPPCState *env)
135476a66253Sj_mayer {
1355636aaad7Sj_mayer     return cpu_ppc_load_decr(env);
135676a66253Sj_mayer }
135776a66253Sj_mayer 
store_40x_tsr(CPUPPCState * env,target_ulong val)1358cbd8f17dSCédric Le Goater void store_40x_tsr(CPUPPCState *env, target_ulong val)
1359cbd8f17dSCédric Le Goater {
1360cbd8f17dSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1361cbd8f17dSCédric Le Goater 
1362cbd8f17dSCédric Le Goater     trace_ppc40x_store_tcr(val);
1363cbd8f17dSCédric Le Goater 
1364cbd8f17dSCédric Le Goater     env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
1365cbd8f17dSCédric Le Goater     if (val & 0x80000000) {
1366cbd8f17dSCédric Le Goater         ppc_set_irq(cpu, PPC_INTERRUPT_PIT, 0);
1367cbd8f17dSCédric Le Goater     }
1368cbd8f17dSCédric Le Goater }
1369cbd8f17dSCédric Le Goater 
store_40x_tcr(CPUPPCState * env,target_ulong val)1370cbd8f17dSCédric Le Goater void store_40x_tcr(CPUPPCState *env, target_ulong val)
1371cbd8f17dSCédric Le Goater {
1372cbd8f17dSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1373cbd8f17dSCédric Le Goater     ppc_tb_t *tb_env;
1374cbd8f17dSCédric Le Goater 
1375cbd8f17dSCédric Le Goater     trace_ppc40x_store_tsr(val);
1376cbd8f17dSCédric Le Goater 
1377cbd8f17dSCédric Le Goater     tb_env = env->tb_env;
1378cbd8f17dSCédric Le Goater     env->spr[SPR_40x_TCR] = val & 0xFFC00000;
1379cbd8f17dSCédric Le Goater     start_stop_pit(env, tb_env, 1);
1380cbd8f17dSCédric Le Goater     cpu_4xx_wdt_cb(cpu);
1381cbd8f17dSCédric Le Goater }
1382cbd8f17dSCédric Le Goater 
ppc_40x_set_tb_clk(void * opaque,uint32_t freq)1383ddd1055bSFabien Chouteau static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
13844b6d0a4cSj_mayer {
1385e2684c0bSAndreas Färber     CPUPPCState *env = opaque;
1386c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
13874b6d0a4cSj_mayer 
1388af96d2e6SCédric Le Goater     trace_ppc40x_set_tb_clk(freq);
13894b6d0a4cSj_mayer     tb_env->tb_freq = freq;
1390dbdd2506Sj_mayer     tb_env->decr_freq = freq;
13914b6d0a4cSj_mayer     /* XXX: we should also update all timers */
13924b6d0a4cSj_mayer }
13934b6d0a4cSj_mayer 
ppc_40x_timers_init(CPUPPCState * env,uint32_t freq,unsigned int decr_excp)1394e2684c0bSAndreas Färber clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
1395d63cb48dSEdgar E. Iglesias                                   unsigned int decr_excp)
1396636aaad7Sj_mayer {
1397c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1398ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1399b1273a5eSCédric Le Goater     PowerPCCPU *cpu = env_archcpu(env);
1400b1273a5eSCédric Le Goater 
1401b1273a5eSCédric Le Goater     trace_ppc40x_timers_init(freq);
1402636aaad7Sj_mayer 
1403b21e2380SMarkus Armbruster     tb_env = g_new0(ppc_tb_t, 1);
1404b21e2380SMarkus Armbruster     ppc40x_timer = g_new0(ppc40x_timer_t, 1);
1405b1273a5eSCédric Le Goater 
14068ecc7913Sj_mayer     env->tb_env = tb_env;
1407ddd1055bSFabien Chouteau     tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
14088ecc7913Sj_mayer     tb_env->tb_freq = freq;
1409dbdd2506Sj_mayer     tb_env->decr_freq = freq;
1410ddd1055bSFabien Chouteau     tb_env->opaque = ppc40x_timer;
1411b1273a5eSCédric Le Goater 
1412636aaad7Sj_mayer     /* We use decr timer for PIT */
1413b1273a5eSCédric Le Goater     tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, cpu);
1414ddd1055bSFabien Chouteau     ppc40x_timer->fit_timer =
1415b1273a5eSCédric Le Goater         timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, cpu);
1416ddd1055bSFabien Chouteau     ppc40x_timer->wdt_timer =
1417b1273a5eSCédric Le Goater         timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, cpu);
1418ddd1055bSFabien Chouteau     ppc40x_timer->decr_excp = decr_excp;
14198ecc7913Sj_mayer 
1420ddd1055bSFabien Chouteau     return &ppc_40x_set_tb_clk;
142176a66253Sj_mayer }
142276a66253Sj_mayer 
14232e719ba3Sj_mayer /*****************************************************************************/
14242e719ba3Sj_mayer /* Embedded PowerPC Device Control Registers */
1425c227f099SAnthony Liguori typedef struct ppc_dcrn_t ppc_dcrn_t;
1426c227f099SAnthony Liguori struct ppc_dcrn_t {
14272e719ba3Sj_mayer     dcr_read_cb dcr_read;
14282e719ba3Sj_mayer     dcr_write_cb dcr_write;
14292e719ba3Sj_mayer     void *opaque;
14302e719ba3Sj_mayer };
14312e719ba3Sj_mayer 
1432a750fc0bSj_mayer /* XXX: on 460, DCR addresses are 32 bits wide,
1433a750fc0bSj_mayer  *      using DCRIPR to get the 22 upper bits of the DCR address
1434a750fc0bSj_mayer  */
14352e719ba3Sj_mayer #define DCRN_NB 1024
1436c227f099SAnthony Liguori struct ppc_dcr_t {
1437c227f099SAnthony Liguori     ppc_dcrn_t dcrn[DCRN_NB];
14382e719ba3Sj_mayer     int (*read_error)(int dcrn);
14392e719ba3Sj_mayer     int (*write_error)(int dcrn);
14402e719ba3Sj_mayer };
14412e719ba3Sj_mayer 
ppc_dcr_read(ppc_dcr_t * dcr_env,int dcrn,uint32_t * valp)144273b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
14432e719ba3Sj_mayer {
1444c227f099SAnthony Liguori     ppc_dcrn_t *dcr;
14452e719ba3Sj_mayer 
14462e719ba3Sj_mayer     if (dcrn < 0 || dcrn >= DCRN_NB)
14472e719ba3Sj_mayer         goto error;
14482e719ba3Sj_mayer     dcr = &dcr_env->dcrn[dcrn];
14492e719ba3Sj_mayer     if (dcr->dcr_read == NULL)
14502e719ba3Sj_mayer         goto error;
14512e719ba3Sj_mayer     *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
1452de82dabeSCédric Le Goater     trace_ppc_dcr_read(dcrn, *valp);
14532e719ba3Sj_mayer 
14542e719ba3Sj_mayer     return 0;
14552e719ba3Sj_mayer 
14562e719ba3Sj_mayer  error:
14572e719ba3Sj_mayer     if (dcr_env->read_error != NULL)
14582e719ba3Sj_mayer         return (*dcr_env->read_error)(dcrn);
14592e719ba3Sj_mayer 
14602e719ba3Sj_mayer     return -1;
14612e719ba3Sj_mayer }
14622e719ba3Sj_mayer 
ppc_dcr_write(ppc_dcr_t * dcr_env,int dcrn,uint32_t val)146373b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
14642e719ba3Sj_mayer {
1465c227f099SAnthony Liguori     ppc_dcrn_t *dcr;
14662e719ba3Sj_mayer 
14672e719ba3Sj_mayer     if (dcrn < 0 || dcrn >= DCRN_NB)
14682e719ba3Sj_mayer         goto error;
14692e719ba3Sj_mayer     dcr = &dcr_env->dcrn[dcrn];
14702e719ba3Sj_mayer     if (dcr->dcr_write == NULL)
14712e719ba3Sj_mayer         goto error;
1472de82dabeSCédric Le Goater     trace_ppc_dcr_write(dcrn, val);
14732e719ba3Sj_mayer     (*dcr->dcr_write)(dcr->opaque, dcrn, val);
14742e719ba3Sj_mayer 
14752e719ba3Sj_mayer     return 0;
14762e719ba3Sj_mayer 
14772e719ba3Sj_mayer  error:
14782e719ba3Sj_mayer     if (dcr_env->write_error != NULL)
14792e719ba3Sj_mayer         return (*dcr_env->write_error)(dcrn);
14802e719ba3Sj_mayer 
14812e719ba3Sj_mayer     return -1;
14822e719ba3Sj_mayer }
14832e719ba3Sj_mayer 
ppc_dcr_register(CPUPPCState * env,int dcrn,void * opaque,dcr_read_cb dcr_read,dcr_write_cb dcr_write)1484e2684c0bSAndreas Färber int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
14852e719ba3Sj_mayer                       dcr_read_cb dcr_read, dcr_write_cb dcr_write)
14862e719ba3Sj_mayer {
1487c227f099SAnthony Liguori     ppc_dcr_t *dcr_env;
1488c227f099SAnthony Liguori     ppc_dcrn_t *dcr;
14892e719ba3Sj_mayer 
14902e719ba3Sj_mayer     dcr_env = env->dcr_env;
14912e719ba3Sj_mayer     if (dcr_env == NULL)
14922e719ba3Sj_mayer         return -1;
14932e719ba3Sj_mayer     if (dcrn < 0 || dcrn >= DCRN_NB)
14942e719ba3Sj_mayer         return -1;
14952e719ba3Sj_mayer     dcr = &dcr_env->dcrn[dcrn];
14962e719ba3Sj_mayer     if (dcr->opaque != NULL ||
14972e719ba3Sj_mayer         dcr->dcr_read != NULL ||
14982e719ba3Sj_mayer         dcr->dcr_write != NULL)
14992e719ba3Sj_mayer         return -1;
15002e719ba3Sj_mayer     dcr->opaque = opaque;
15012e719ba3Sj_mayer     dcr->dcr_read = dcr_read;
15022e719ba3Sj_mayer     dcr->dcr_write = dcr_write;
15032e719ba3Sj_mayer 
15042e719ba3Sj_mayer     return 0;
15052e719ba3Sj_mayer }
15062e719ba3Sj_mayer 
ppc_dcr_init(CPUPPCState * env,int (* read_error)(int dcrn),int (* write_error)(int dcrn))1507e2684c0bSAndreas Färber int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn),
15082e719ba3Sj_mayer                   int (*write_error)(int dcrn))
15092e719ba3Sj_mayer {
1510c227f099SAnthony Liguori     ppc_dcr_t *dcr_env;
15112e719ba3Sj_mayer 
1512b21e2380SMarkus Armbruster     dcr_env = g_new0(ppc_dcr_t, 1);
15132e719ba3Sj_mayer     dcr_env->read_error = read_error;
15142e719ba3Sj_mayer     dcr_env->write_error = write_error;
15152e719ba3Sj_mayer     env->dcr_env = dcr_env;
15162e719ba3Sj_mayer 
15172e719ba3Sj_mayer     return 0;
15182e719ba3Sj_mayer }
15192e719ba3Sj_mayer 
152064201201Sbellard /*****************************************************************************/
1521051e2973SCédric Le Goater 
ppc_cpu_pir(PowerPCCPU * cpu)15224a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu)
15234a89e204SCédric Le Goater {
15244a89e204SCédric Le Goater     CPUPPCState *env = &cpu->env;
15254a89e204SCédric Le Goater     return env->spr_cb[SPR_PIR].default_value;
15264a89e204SCédric Le Goater }
15274a89e204SCédric Le Goater 
ppc_cpu_tir(PowerPCCPU * cpu)1528d24e80b2SNicholas Piggin int ppc_cpu_tir(PowerPCCPU *cpu)
1529d24e80b2SNicholas Piggin {
1530d24e80b2SNicholas Piggin     CPUPPCState *env = &cpu->env;
1531d24e80b2SNicholas Piggin     return env->spr_cb[SPR_TIR].default_value;
1532d24e80b2SNicholas Piggin }
1533d24e80b2SNicholas Piggin 
ppc_get_vcpu_by_pir(int pir)1534051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
1535051e2973SCédric Le Goater {
1536051e2973SCédric Le Goater     CPUState *cs;
1537051e2973SCédric Le Goater 
1538051e2973SCédric Le Goater     CPU_FOREACH(cs) {
1539051e2973SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
1540051e2973SCédric Le Goater 
15414a89e204SCédric Le Goater         if (ppc_cpu_pir(cpu) == pir) {
1542051e2973SCédric Le Goater             return cpu;
1543051e2973SCédric Le Goater         }
1544051e2973SCédric Le Goater     }
1545051e2973SCédric Le Goater 
1546051e2973SCédric Le Goater     return NULL;
1547051e2973SCédric Le Goater }
154840177438SGreg Kurz 
ppc_irq_reset(PowerPCCPU * cpu)154940177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu)
155040177438SGreg Kurz {
155140177438SGreg Kurz     CPUPPCState *env = &cpu->env;
155240177438SGreg Kurz 
155340177438SGreg Kurz     env->irq_input_state = 0;
155476d93e14Sjianchunfu     if (kvm_enabled()) {
155540177438SGreg Kurz         kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0);
155640177438SGreg Kurz     }
155776d93e14Sjianchunfu }
1558