xref: /qemu/hw/ppc/ppc.c (revision 73bcb24d932912f8e75e1d88da0fc0ac6d4bce78)
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  */
240d75590dSPeter Maydell #include "qemu/osdep.h"
254771d756SPaolo Bonzini #include "qemu-common.h"
264771d756SPaolo Bonzini #include "cpu.h"
2783c9f4caSPaolo Bonzini #include "hw/hw.h"
280d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
292b927571SAndreas Färber #include "hw/ppc/ppc_e500.h"
301de7afc9SPaolo Bonzini #include "qemu/timer.h"
319c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
320ce470cdSAlexey Kardashevskiy #include "sysemu/cpus.h"
330d09e41aSPaolo Bonzini #include "hw/timer/m48t59.h"
341de7afc9SPaolo Bonzini #include "qemu/log.h"
3598a8b524SAlexey Kardashevskiy #include "qemu/error-report.h"
3683c9f4caSPaolo Bonzini #include "hw/loader.h"
379c17d615SPaolo Bonzini #include "sysemu/kvm.h"
38fc87e185SAlexander Graf #include "kvm_ppc.h"
3998a8b524SAlexey Kardashevskiy #include "trace.h"
40a541f297Sbellard 
41e9df014cSj_mayer //#define PPC_DEBUG_IRQ
424b6d0a4cSj_mayer //#define PPC_DEBUG_TB
43e9df014cSj_mayer 
44d12d51d5Saliguori #ifdef PPC_DEBUG_IRQ
4593fcfe39Saliguori #  define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
46d12d51d5Saliguori #else
47d12d51d5Saliguori #  define LOG_IRQ(...) do { } while (0)
48d12d51d5Saliguori #endif
49d12d51d5Saliguori 
50d12d51d5Saliguori 
51d12d51d5Saliguori #ifdef PPC_DEBUG_TB
5293fcfe39Saliguori #  define LOG_TB(...) qemu_log(__VA_ARGS__)
53d12d51d5Saliguori #else
54d12d51d5Saliguori #  define LOG_TB(...) do { } while (0)
55d12d51d5Saliguori #endif
56d12d51d5Saliguori 
57e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env);
58e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env);
59dbdd2506Sj_mayer 
607058581aSAndreas Färber void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
6147103572Sj_mayer {
62d8ed887bSAndreas Färber     CPUState *cs = CPU(cpu);
637058581aSAndreas Färber     CPUPPCState *env = &cpu->env;
64fc87e185SAlexander Graf     unsigned int old_pending = env->pending_interrupts;
65fc87e185SAlexander Graf 
6647103572Sj_mayer     if (level) {
6747103572Sj_mayer         env->pending_interrupts |= 1 << n_IRQ;
68c3affe56SAndreas Färber         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
6947103572Sj_mayer     } else {
7047103572Sj_mayer         env->pending_interrupts &= ~(1 << n_IRQ);
71d8ed887bSAndreas Färber         if (env->pending_interrupts == 0) {
72d8ed887bSAndreas Färber             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
73d8ed887bSAndreas Färber         }
7447103572Sj_mayer     }
75fc87e185SAlexander Graf 
76fc87e185SAlexander Graf     if (old_pending != env->pending_interrupts) {
77fc87e185SAlexander Graf #ifdef CONFIG_KVM
787058581aSAndreas Färber         kvmppc_set_interrupt(cpu, n_IRQ, level);
79fc87e185SAlexander Graf #endif
80fc87e185SAlexander Graf     }
81fc87e185SAlexander Graf 
82d12d51d5Saliguori     LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
83aae9366aSj_mayer                 "req %08x\n", __func__, env, n_IRQ, level,
84259186a7SAndreas Färber                 env->pending_interrupts, CPU(cpu)->interrupt_request);
85a496775fSj_mayer }
8647103572Sj_mayer 
87e9df014cSj_mayer /* PowerPC 6xx / 7xx internal IRQ controller */
88e9df014cSj_mayer static void ppc6xx_set_irq(void *opaque, int pin, int level)
89d537cf6cSpbrook {
90a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
91a0961245SAndreas Färber     CPUPPCState *env = &cpu->env;
92e9df014cSj_mayer     int cur_level;
93d537cf6cSpbrook 
94d12d51d5Saliguori     LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
95a496775fSj_mayer                 env, pin, level);
96e9df014cSj_mayer     cur_level = (env->irq_input_state >> pin) & 1;
97e9df014cSj_mayer     /* Don't generate spurious events */
9824be5ae3Sj_mayer     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
99259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
100259186a7SAndreas Färber 
101e9df014cSj_mayer         switch (pin) {
102dbdd2506Sj_mayer         case PPC6xx_INPUT_TBEN:
103dbdd2506Sj_mayer             /* Level sensitive - active high */
104d12d51d5Saliguori             LOG_IRQ("%s: %s the time base\n",
105dbdd2506Sj_mayer                         __func__, level ? "start" : "stop");
106dbdd2506Sj_mayer             if (level) {
107dbdd2506Sj_mayer                 cpu_ppc_tb_start(env);
108dbdd2506Sj_mayer             } else {
109dbdd2506Sj_mayer                 cpu_ppc_tb_stop(env);
110dbdd2506Sj_mayer             }
11124be5ae3Sj_mayer         case PPC6xx_INPUT_INT:
11224be5ae3Sj_mayer             /* Level sensitive - active high */
113d12d51d5Saliguori             LOG_IRQ("%s: set the external IRQ state to %d\n",
114a496775fSj_mayer                         __func__, level);
1157058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
116e9df014cSj_mayer             break;
11724be5ae3Sj_mayer         case PPC6xx_INPUT_SMI:
118e9df014cSj_mayer             /* Level sensitive - active high */
119d12d51d5Saliguori             LOG_IRQ("%s: set the SMI IRQ state to %d\n",
120a496775fSj_mayer                         __func__, level);
1217058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level);
122e9df014cSj_mayer             break;
12324be5ae3Sj_mayer         case PPC6xx_INPUT_MCP:
124e9df014cSj_mayer             /* Negative edge sensitive */
125e9df014cSj_mayer             /* XXX: TODO: actual reaction may depends on HID0 status
126e9df014cSj_mayer              *            603/604/740/750: check HID0[EMCP]
127e9df014cSj_mayer              */
128e9df014cSj_mayer             if (cur_level == 1 && level == 0) {
129d12d51d5Saliguori                 LOG_IRQ("%s: raise machine check state\n",
130a496775fSj_mayer                             __func__);
1317058581aSAndreas Färber                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
132d537cf6cSpbrook             }
133e9df014cSj_mayer             break;
13424be5ae3Sj_mayer         case PPC6xx_INPUT_CKSTP_IN:
135e9df014cSj_mayer             /* Level sensitive - active low */
136e9df014cSj_mayer             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
137e63ecc6fSj_mayer             /* XXX: Note that the only way to restart the CPU is to reset it */
138e9df014cSj_mayer             if (level) {
139d12d51d5Saliguori                 LOG_IRQ("%s: stop the CPU\n", __func__);
140259186a7SAndreas Färber                 cs->halted = 1;
141d537cf6cSpbrook             }
14247103572Sj_mayer             break;
14324be5ae3Sj_mayer         case PPC6xx_INPUT_HRESET:
144e9df014cSj_mayer             /* Level sensitive - active low */
145e9df014cSj_mayer             if (level) {
146d12d51d5Saliguori                 LOG_IRQ("%s: reset the CPU\n", __func__);
147c3affe56SAndreas Färber                 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
148e9df014cSj_mayer             }
14947103572Sj_mayer             break;
15024be5ae3Sj_mayer         case PPC6xx_INPUT_SRESET:
151d12d51d5Saliguori             LOG_IRQ("%s: set the RESET IRQ state to %d\n",
152a496775fSj_mayer                         __func__, level);
1537058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
15447103572Sj_mayer             break;
155e9df014cSj_mayer         default:
156e9df014cSj_mayer             /* Unknown pin - do nothing */
157d12d51d5Saliguori             LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
15847103572Sj_mayer             return;
15947103572Sj_mayer         }
160e9df014cSj_mayer         if (level)
161e9df014cSj_mayer             env->irq_input_state |= 1 << pin;
162e9df014cSj_mayer         else
163e9df014cSj_mayer             env->irq_input_state &= ~(1 << pin);
164e9df014cSj_mayer     }
165e9df014cSj_mayer }
166e9df014cSj_mayer 
167e2684c0bSAndreas Färber void ppc6xx_irq_init(CPUPPCState *env)
168e9df014cSj_mayer {
169a0961245SAndreas Färber     PowerPCCPU *cpu = ppc_env_get_cpu(env);
170a0961245SAndreas Färber 
171a0961245SAndreas Färber     env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu,
1727b62a955Sj_mayer                                                   PPC6xx_INPUT_NB);
17347103572Sj_mayer }
17447103572Sj_mayer 
17500af685fSj_mayer #if defined(TARGET_PPC64)
176d0dfae6eSj_mayer /* PowerPC 970 internal IRQ controller */
177d0dfae6eSj_mayer static void ppc970_set_irq(void *opaque, int pin, int level)
178d0dfae6eSj_mayer {
179a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
180a0961245SAndreas Färber     CPUPPCState *env = &cpu->env;
181d0dfae6eSj_mayer     int cur_level;
182d0dfae6eSj_mayer 
183d12d51d5Saliguori     LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
184d0dfae6eSj_mayer                 env, pin, level);
185d0dfae6eSj_mayer     cur_level = (env->irq_input_state >> pin) & 1;
186d0dfae6eSj_mayer     /* Don't generate spurious events */
187d0dfae6eSj_mayer     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
188259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
189259186a7SAndreas Färber 
190d0dfae6eSj_mayer         switch (pin) {
191d0dfae6eSj_mayer         case PPC970_INPUT_INT:
192d0dfae6eSj_mayer             /* Level sensitive - active high */
193d12d51d5Saliguori             LOG_IRQ("%s: set the external IRQ state to %d\n",
194d0dfae6eSj_mayer                         __func__, level);
1957058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
196d0dfae6eSj_mayer             break;
197d0dfae6eSj_mayer         case PPC970_INPUT_THINT:
198d0dfae6eSj_mayer             /* Level sensitive - active high */
199d12d51d5Saliguori             LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__,
200d0dfae6eSj_mayer                         level);
2017058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level);
202d0dfae6eSj_mayer             break;
203d0dfae6eSj_mayer         case PPC970_INPUT_MCP:
204d0dfae6eSj_mayer             /* Negative edge sensitive */
205d0dfae6eSj_mayer             /* XXX: TODO: actual reaction may depends on HID0 status
206d0dfae6eSj_mayer              *            603/604/740/750: check HID0[EMCP]
207d0dfae6eSj_mayer              */
208d0dfae6eSj_mayer             if (cur_level == 1 && level == 0) {
209d12d51d5Saliguori                 LOG_IRQ("%s: raise machine check state\n",
210d0dfae6eSj_mayer                             __func__);
2117058581aSAndreas Färber                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
212d0dfae6eSj_mayer             }
213d0dfae6eSj_mayer             break;
214d0dfae6eSj_mayer         case PPC970_INPUT_CKSTP:
215d0dfae6eSj_mayer             /* Level sensitive - active low */
216d0dfae6eSj_mayer             /* XXX: TODO: relay the signal to CKSTP_OUT pin */
217d0dfae6eSj_mayer             if (level) {
218d12d51d5Saliguori                 LOG_IRQ("%s: stop the CPU\n", __func__);
219259186a7SAndreas Färber                 cs->halted = 1;
220d0dfae6eSj_mayer             } else {
221d12d51d5Saliguori                 LOG_IRQ("%s: restart the CPU\n", __func__);
222259186a7SAndreas Färber                 cs->halted = 0;
223259186a7SAndreas Färber                 qemu_cpu_kick(cs);
224d0dfae6eSj_mayer             }
225d0dfae6eSj_mayer             break;
226d0dfae6eSj_mayer         case PPC970_INPUT_HRESET:
227d0dfae6eSj_mayer             /* Level sensitive - active low */
228d0dfae6eSj_mayer             if (level) {
229c3affe56SAndreas Färber                 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
230d0dfae6eSj_mayer             }
231d0dfae6eSj_mayer             break;
232d0dfae6eSj_mayer         case PPC970_INPUT_SRESET:
233d12d51d5Saliguori             LOG_IRQ("%s: set the RESET IRQ state to %d\n",
234d0dfae6eSj_mayer                         __func__, level);
2357058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
236d0dfae6eSj_mayer             break;
237d0dfae6eSj_mayer         case PPC970_INPUT_TBEN:
238d12d51d5Saliguori             LOG_IRQ("%s: set the TBEN state to %d\n", __func__,
239d0dfae6eSj_mayer                         level);
240d0dfae6eSj_mayer             /* XXX: TODO */
241d0dfae6eSj_mayer             break;
242d0dfae6eSj_mayer         default:
243d0dfae6eSj_mayer             /* Unknown pin - do nothing */
244d12d51d5Saliguori             LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
245d0dfae6eSj_mayer             return;
246d0dfae6eSj_mayer         }
247d0dfae6eSj_mayer         if (level)
248d0dfae6eSj_mayer             env->irq_input_state |= 1 << pin;
249d0dfae6eSj_mayer         else
250d0dfae6eSj_mayer             env->irq_input_state &= ~(1 << pin);
251d0dfae6eSj_mayer     }
252d0dfae6eSj_mayer }
253d0dfae6eSj_mayer 
254e2684c0bSAndreas Färber void ppc970_irq_init(CPUPPCState *env)
255d0dfae6eSj_mayer {
256a0961245SAndreas Färber     PowerPCCPU *cpu = ppc_env_get_cpu(env);
257a0961245SAndreas Färber 
258a0961245SAndreas Färber     env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu,
2597b62a955Sj_mayer                                                   PPC970_INPUT_NB);
260d0dfae6eSj_mayer }
2619d52e907SDavid Gibson 
2629d52e907SDavid Gibson /* POWER7 internal IRQ controller */
2639d52e907SDavid Gibson static void power7_set_irq(void *opaque, int pin, int level)
2649d52e907SDavid Gibson {
265a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
266a0961245SAndreas Färber     CPUPPCState *env = &cpu->env;
2679d52e907SDavid Gibson 
2689d52e907SDavid Gibson     LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
2699d52e907SDavid Gibson                 env, pin, level);
2709d52e907SDavid Gibson 
2719d52e907SDavid Gibson     switch (pin) {
2729d52e907SDavid Gibson     case POWER7_INPUT_INT:
2739d52e907SDavid Gibson         /* Level sensitive - active high */
2749d52e907SDavid Gibson         LOG_IRQ("%s: set the external IRQ state to %d\n",
2759d52e907SDavid Gibson                 __func__, level);
2767058581aSAndreas Färber         ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
2779d52e907SDavid Gibson         break;
2789d52e907SDavid Gibson     default:
2799d52e907SDavid Gibson         /* Unknown pin - do nothing */
2809d52e907SDavid Gibson         LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
2819d52e907SDavid Gibson         return;
2829d52e907SDavid Gibson     }
2839d52e907SDavid Gibson     if (level) {
2849d52e907SDavid Gibson         env->irq_input_state |= 1 << pin;
2859d52e907SDavid Gibson     } else {
2869d52e907SDavid Gibson         env->irq_input_state &= ~(1 << pin);
2879d52e907SDavid Gibson     }
2889d52e907SDavid Gibson }
2899d52e907SDavid Gibson 
290e2684c0bSAndreas Färber void ppcPOWER7_irq_init(CPUPPCState *env)
2919d52e907SDavid Gibson {
292a0961245SAndreas Färber     PowerPCCPU *cpu = ppc_env_get_cpu(env);
293a0961245SAndreas Färber 
294a0961245SAndreas Färber     env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu,
2959d52e907SDavid Gibson                                                   POWER7_INPUT_NB);
2969d52e907SDavid Gibson }
29700af685fSj_mayer #endif /* defined(TARGET_PPC64) */
298d0dfae6eSj_mayer 
2994e290a0bSj_mayer /* PowerPC 40x internal IRQ controller */
3004e290a0bSj_mayer static void ppc40x_set_irq(void *opaque, int pin, int level)
30124be5ae3Sj_mayer {
302a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
303a0961245SAndreas Färber     CPUPPCState *env = &cpu->env;
30424be5ae3Sj_mayer     int cur_level;
30524be5ae3Sj_mayer 
306d12d51d5Saliguori     LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
3078ecc7913Sj_mayer                 env, pin, level);
30824be5ae3Sj_mayer     cur_level = (env->irq_input_state >> pin) & 1;
30924be5ae3Sj_mayer     /* Don't generate spurious events */
31024be5ae3Sj_mayer     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
311259186a7SAndreas Färber         CPUState *cs = CPU(cpu);
312259186a7SAndreas Färber 
31324be5ae3Sj_mayer         switch (pin) {
3144e290a0bSj_mayer         case PPC40x_INPUT_RESET_SYS:
3158ecc7913Sj_mayer             if (level) {
316d12d51d5Saliguori                 LOG_IRQ("%s: reset the PowerPC system\n",
3178ecc7913Sj_mayer                             __func__);
318f3273ba6SAndreas Färber                 ppc40x_system_reset(cpu);
3198ecc7913Sj_mayer             }
3208ecc7913Sj_mayer             break;
3214e290a0bSj_mayer         case PPC40x_INPUT_RESET_CHIP:
3228ecc7913Sj_mayer             if (level) {
323d12d51d5Saliguori                 LOG_IRQ("%s: reset the PowerPC chip\n", __func__);
324f3273ba6SAndreas Färber                 ppc40x_chip_reset(cpu);
3258ecc7913Sj_mayer             }
3268ecc7913Sj_mayer             break;
3274e290a0bSj_mayer         case PPC40x_INPUT_RESET_CORE:
32824be5ae3Sj_mayer             /* XXX: TODO: update DBSR[MRR] */
32924be5ae3Sj_mayer             if (level) {
330d12d51d5Saliguori                 LOG_IRQ("%s: reset the PowerPC core\n", __func__);
331f3273ba6SAndreas Färber                 ppc40x_core_reset(cpu);
33224be5ae3Sj_mayer             }
33324be5ae3Sj_mayer             break;
3344e290a0bSj_mayer         case PPC40x_INPUT_CINT:
33524be5ae3Sj_mayer             /* Level sensitive - active high */
336d12d51d5Saliguori             LOG_IRQ("%s: set the critical IRQ state to %d\n",
3378ecc7913Sj_mayer                         __func__, level);
3387058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
33924be5ae3Sj_mayer             break;
3404e290a0bSj_mayer         case PPC40x_INPUT_INT:
34124be5ae3Sj_mayer             /* Level sensitive - active high */
342d12d51d5Saliguori             LOG_IRQ("%s: set the external IRQ state to %d\n",
343a496775fSj_mayer                         __func__, level);
3447058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
34524be5ae3Sj_mayer             break;
3464e290a0bSj_mayer         case PPC40x_INPUT_HALT:
34724be5ae3Sj_mayer             /* Level sensitive - active low */
34824be5ae3Sj_mayer             if (level) {
349d12d51d5Saliguori                 LOG_IRQ("%s: stop the CPU\n", __func__);
350259186a7SAndreas Färber                 cs->halted = 1;
35124be5ae3Sj_mayer             } else {
352d12d51d5Saliguori                 LOG_IRQ("%s: restart the CPU\n", __func__);
353259186a7SAndreas Färber                 cs->halted = 0;
354259186a7SAndreas Färber                 qemu_cpu_kick(cs);
35524be5ae3Sj_mayer             }
35624be5ae3Sj_mayer             break;
3574e290a0bSj_mayer         case PPC40x_INPUT_DEBUG:
35824be5ae3Sj_mayer             /* Level sensitive - active high */
359d12d51d5Saliguori             LOG_IRQ("%s: set the debug pin state to %d\n",
360a496775fSj_mayer                         __func__, level);
3617058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
36224be5ae3Sj_mayer             break;
36324be5ae3Sj_mayer         default:
36424be5ae3Sj_mayer             /* Unknown pin - do nothing */
365d12d51d5Saliguori             LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
36624be5ae3Sj_mayer             return;
36724be5ae3Sj_mayer         }
36824be5ae3Sj_mayer         if (level)
36924be5ae3Sj_mayer             env->irq_input_state |= 1 << pin;
37024be5ae3Sj_mayer         else
37124be5ae3Sj_mayer             env->irq_input_state &= ~(1 << pin);
37224be5ae3Sj_mayer     }
37324be5ae3Sj_mayer }
37424be5ae3Sj_mayer 
375e2684c0bSAndreas Färber void ppc40x_irq_init(CPUPPCState *env)
37624be5ae3Sj_mayer {
377a0961245SAndreas Färber     PowerPCCPU *cpu = ppc_env_get_cpu(env);
378a0961245SAndreas Färber 
3794e290a0bSj_mayer     env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
380a0961245SAndreas Färber                                                   cpu, PPC40x_INPUT_NB);
38124be5ae3Sj_mayer }
38224be5ae3Sj_mayer 
3839fdc60bfSaurel32 /* PowerPC E500 internal IRQ controller */
3849fdc60bfSaurel32 static void ppce500_set_irq(void *opaque, int pin, int level)
3859fdc60bfSaurel32 {
386a0961245SAndreas Färber     PowerPCCPU *cpu = opaque;
387a0961245SAndreas Färber     CPUPPCState *env = &cpu->env;
3889fdc60bfSaurel32     int cur_level;
3899fdc60bfSaurel32 
3909fdc60bfSaurel32     LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
3919fdc60bfSaurel32                 env, pin, level);
3929fdc60bfSaurel32     cur_level = (env->irq_input_state >> pin) & 1;
3939fdc60bfSaurel32     /* Don't generate spurious events */
3949fdc60bfSaurel32     if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
3959fdc60bfSaurel32         switch (pin) {
3969fdc60bfSaurel32         case PPCE500_INPUT_MCK:
3979fdc60bfSaurel32             if (level) {
3989fdc60bfSaurel32                 LOG_IRQ("%s: reset the PowerPC system\n",
3999fdc60bfSaurel32                             __func__);
4009fdc60bfSaurel32                 qemu_system_reset_request();
4019fdc60bfSaurel32             }
4029fdc60bfSaurel32             break;
4039fdc60bfSaurel32         case PPCE500_INPUT_RESET_CORE:
4049fdc60bfSaurel32             if (level) {
4059fdc60bfSaurel32                 LOG_IRQ("%s: reset the PowerPC core\n", __func__);
4067058581aSAndreas Färber                 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level);
4079fdc60bfSaurel32             }
4089fdc60bfSaurel32             break;
4099fdc60bfSaurel32         case PPCE500_INPUT_CINT:
4109fdc60bfSaurel32             /* Level sensitive - active high */
4119fdc60bfSaurel32             LOG_IRQ("%s: set the critical IRQ state to %d\n",
4129fdc60bfSaurel32                         __func__, level);
4137058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
4149fdc60bfSaurel32             break;
4159fdc60bfSaurel32         case PPCE500_INPUT_INT:
4169fdc60bfSaurel32             /* Level sensitive - active high */
4179fdc60bfSaurel32             LOG_IRQ("%s: set the core IRQ state to %d\n",
4189fdc60bfSaurel32                         __func__, level);
4197058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
4209fdc60bfSaurel32             break;
4219fdc60bfSaurel32         case PPCE500_INPUT_DEBUG:
4229fdc60bfSaurel32             /* Level sensitive - active high */
4239fdc60bfSaurel32             LOG_IRQ("%s: set the debug pin state to %d\n",
4249fdc60bfSaurel32                         __func__, level);
4257058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
4269fdc60bfSaurel32             break;
4279fdc60bfSaurel32         default:
4289fdc60bfSaurel32             /* Unknown pin - do nothing */
4299fdc60bfSaurel32             LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
4309fdc60bfSaurel32             return;
4319fdc60bfSaurel32         }
4329fdc60bfSaurel32         if (level)
4339fdc60bfSaurel32             env->irq_input_state |= 1 << pin;
4349fdc60bfSaurel32         else
4359fdc60bfSaurel32             env->irq_input_state &= ~(1 << pin);
4369fdc60bfSaurel32     }
4379fdc60bfSaurel32 }
4389fdc60bfSaurel32 
439e2684c0bSAndreas Färber void ppce500_irq_init(CPUPPCState *env)
4409fdc60bfSaurel32 {
441a0961245SAndreas Färber     PowerPCCPU *cpu = ppc_env_get_cpu(env);
442a0961245SAndreas Färber 
4439fdc60bfSaurel32     env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq,
444a0961245SAndreas Färber                                                   cpu, PPCE500_INPUT_NB);
4459fdc60bfSaurel32 }
446e49798b1SAlexander Graf 
447e49798b1SAlexander Graf /* Enable or Disable the E500 EPR capability */
448e49798b1SAlexander Graf void ppce500_set_mpic_proxy(bool enabled)
449e49798b1SAlexander Graf {
450182735efSAndreas Färber     CPUState *cs;
451e49798b1SAlexander Graf 
452bdc44640SAndreas Färber     CPU_FOREACH(cs) {
453182735efSAndreas Färber         PowerPCCPU *cpu = POWERPC_CPU(cs);
4545b95b8b9SAlexander Graf 
455182735efSAndreas Färber         cpu->env.mpic_proxy = enabled;
4565b95b8b9SAlexander Graf         if (kvm_enabled()) {
457182735efSAndreas Färber             kvmppc_set_mpic_proxy(cpu, enabled);
4585b95b8b9SAlexander Graf         }
459e49798b1SAlexander Graf     }
460e49798b1SAlexander Graf }
461e49798b1SAlexander Graf 
4629fddaa0cSbellard /*****************************************************************************/
463e9df014cSj_mayer /* PowerPC time base and decrementer emulation */
4649fddaa0cSbellard 
465ddd1055bSFabien Chouteau uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
4669fddaa0cSbellard {
4679fddaa0cSbellard     /* TB time in tb periods */
468*73bcb24dSRutuja Shah     return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset;
4699fddaa0cSbellard }
4709fddaa0cSbellard 
471e2684c0bSAndreas Färber uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
4729fddaa0cSbellard {
473c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
4749fddaa0cSbellard     uint64_t tb;
4759fddaa0cSbellard 
47690dc8812SScott Wood     if (kvm_enabled()) {
47790dc8812SScott Wood         return env->spr[SPR_TBL];
47890dc8812SScott Wood     }
47990dc8812SScott Wood 
480bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
481d12d51d5Saliguori     LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
4829fddaa0cSbellard 
483e3ea6529SAlexander Graf     return tb;
4849fddaa0cSbellard }
4859fddaa0cSbellard 
486e2684c0bSAndreas Färber static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env)
4879fddaa0cSbellard {
488c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
4899fddaa0cSbellard     uint64_t tb;
4909fddaa0cSbellard 
491bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
492d12d51d5Saliguori     LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
49376a66253Sj_mayer 
4949fddaa0cSbellard     return tb >> 32;
4959fddaa0cSbellard }
4969fddaa0cSbellard 
497e2684c0bSAndreas Färber uint32_t cpu_ppc_load_tbu (CPUPPCState *env)
4988a84de23Sj_mayer {
49990dc8812SScott Wood     if (kvm_enabled()) {
50090dc8812SScott Wood         return env->spr[SPR_TBU];
50190dc8812SScott Wood     }
50290dc8812SScott Wood 
5038a84de23Sj_mayer     return _cpu_ppc_load_tbu(env);
5048a84de23Sj_mayer }
5058a84de23Sj_mayer 
506c227f099SAnthony Liguori static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
507636aa200SBlue Swirl                                     int64_t *tb_offsetp, uint64_t value)
5089fddaa0cSbellard {
509*73bcb24dSRutuja Shah     *tb_offsetp = value -
510*73bcb24dSRutuja Shah         muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND);
511*73bcb24dSRutuja Shah 
512d12d51d5Saliguori     LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n",
513aae9366aSj_mayer                 __func__, value, *tb_offsetp);
514a496775fSj_mayer }
5159fddaa0cSbellard 
516e2684c0bSAndreas Färber void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value)
5179fddaa0cSbellard {
518c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
519a062e36cSj_mayer     uint64_t tb;
5209fddaa0cSbellard 
521bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
522a062e36cSj_mayer     tb &= 0xFFFFFFFF00000000ULL;
523bc72ad67SAlex Bligh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
524dbdd2506Sj_mayer                      &tb_env->tb_offset, tb | (uint64_t)value);
525a062e36cSj_mayer }
526a062e36cSj_mayer 
527e2684c0bSAndreas Färber static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value)
528a062e36cSj_mayer {
529c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
530a062e36cSj_mayer     uint64_t tb;
531a062e36cSj_mayer 
532bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
533a062e36cSj_mayer     tb &= 0x00000000FFFFFFFFULL;
534bc72ad67SAlex Bligh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
535dbdd2506Sj_mayer                      &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
536a062e36cSj_mayer }
537a062e36cSj_mayer 
538e2684c0bSAndreas Färber void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value)
5398a84de23Sj_mayer {
5408a84de23Sj_mayer     _cpu_ppc_store_tbu(env, value);
5418a84de23Sj_mayer }
5428a84de23Sj_mayer 
543e2684c0bSAndreas Färber uint64_t cpu_ppc_load_atbl (CPUPPCState *env)
544a062e36cSj_mayer {
545c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
546a062e36cSj_mayer     uint64_t tb;
547a062e36cSj_mayer 
548bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
549d12d51d5Saliguori     LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
550a062e36cSj_mayer 
551b711de95SAurelien Jarno     return tb;
552a062e36cSj_mayer }
553a062e36cSj_mayer 
554e2684c0bSAndreas Färber uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
555a062e36cSj_mayer {
556c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
557a062e36cSj_mayer     uint64_t tb;
558a062e36cSj_mayer 
559bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
560d12d51d5Saliguori     LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
561a062e36cSj_mayer 
562a062e36cSj_mayer     return tb >> 32;
563a062e36cSj_mayer }
564a062e36cSj_mayer 
565e2684c0bSAndreas Färber void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value)
566a062e36cSj_mayer {
567c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
568a062e36cSj_mayer     uint64_t tb;
569a062e36cSj_mayer 
570bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
571a062e36cSj_mayer     tb &= 0xFFFFFFFF00000000ULL;
572bc72ad67SAlex Bligh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
573dbdd2506Sj_mayer                      &tb_env->atb_offset, tb | (uint64_t)value);
574a062e36cSj_mayer }
575a062e36cSj_mayer 
576e2684c0bSAndreas Färber void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
577a062e36cSj_mayer {
578c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
579a062e36cSj_mayer     uint64_t tb;
580a062e36cSj_mayer 
581bc72ad67SAlex Bligh     tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
582a062e36cSj_mayer     tb &= 0x00000000FFFFFFFFULL;
583bc72ad67SAlex Bligh     cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
584dbdd2506Sj_mayer                      &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
585dbdd2506Sj_mayer }
586dbdd2506Sj_mayer 
587e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env)
588dbdd2506Sj_mayer {
589c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
590dbdd2506Sj_mayer     uint64_t tb, atb, vmclk;
591dbdd2506Sj_mayer 
592dbdd2506Sj_mayer     /* If the time base is already frozen, do nothing */
593dbdd2506Sj_mayer     if (tb_env->tb_freq != 0) {
594bc72ad67SAlex Bligh         vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
595dbdd2506Sj_mayer         /* Get the time base */
596dbdd2506Sj_mayer         tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
597dbdd2506Sj_mayer         /* Get the alternate time base */
598dbdd2506Sj_mayer         atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
599dbdd2506Sj_mayer         /* Store the time base value (ie compute the current offset) */
600dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
601dbdd2506Sj_mayer         /* Store the alternate time base value (compute the current offset) */
602dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
603dbdd2506Sj_mayer         /* Set the time base frequency to zero */
604dbdd2506Sj_mayer         tb_env->tb_freq = 0;
605dbdd2506Sj_mayer         /* Now, the time bases are frozen to tb_offset / atb_offset value */
606dbdd2506Sj_mayer     }
607dbdd2506Sj_mayer }
608dbdd2506Sj_mayer 
609e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env)
610dbdd2506Sj_mayer {
611c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
612dbdd2506Sj_mayer     uint64_t tb, atb, vmclk;
613dbdd2506Sj_mayer 
614dbdd2506Sj_mayer     /* If the time base is not frozen, do nothing */
615dbdd2506Sj_mayer     if (tb_env->tb_freq == 0) {
616bc72ad67SAlex Bligh         vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
617dbdd2506Sj_mayer         /* Get the time base from tb_offset */
618dbdd2506Sj_mayer         tb = tb_env->tb_offset;
619dbdd2506Sj_mayer         /* Get the alternate time base from atb_offset */
620dbdd2506Sj_mayer         atb = tb_env->atb_offset;
621dbdd2506Sj_mayer         /* Restore the tb frequency from the decrementer frequency */
622dbdd2506Sj_mayer         tb_env->tb_freq = tb_env->decr_freq;
623dbdd2506Sj_mayer         /* Store the time base value */
624dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
625dbdd2506Sj_mayer         /* Store the alternate time base value */
626dbdd2506Sj_mayer         cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
627dbdd2506Sj_mayer     }
6289fddaa0cSbellard }
6299fddaa0cSbellard 
630e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env)
631e81a982aSAlexander Graf {
632e81a982aSAlexander Graf     ppc_tb_t *tb_env = env->tb_env;
633e81a982aSAlexander Graf     int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL;
634e81a982aSAlexander Graf     return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
635e81a982aSAlexander Graf }
636e81a982aSAlexander Graf 
637e2684c0bSAndreas Färber static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
6389fddaa0cSbellard {
639c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
6409fddaa0cSbellard     uint32_t decr;
6414e588a4dSbellard     int64_t diff;
6429fddaa0cSbellard 
643bc72ad67SAlex Bligh     diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
644ddd1055bSFabien Chouteau     if (diff >= 0) {
645*73bcb24dSRutuja Shah         decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND);
646ddd1055bSFabien Chouteau     } else if (tb_env->flags & PPC_TIMER_BOOKE) {
647ddd1055bSFabien Chouteau         decr = 0;
648ddd1055bSFabien Chouteau     }  else {
649*73bcb24dSRutuja Shah         decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND);
650ddd1055bSFabien Chouteau     }
651d12d51d5Saliguori     LOG_TB("%s: %08" PRIx32 "\n", __func__, decr);
65276a66253Sj_mayer 
6539fddaa0cSbellard     return decr;
6549fddaa0cSbellard }
6559fddaa0cSbellard 
656e2684c0bSAndreas Färber uint32_t cpu_ppc_load_decr (CPUPPCState *env)
65758a7d328Sj_mayer {
658c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
65958a7d328Sj_mayer 
66090dc8812SScott Wood     if (kvm_enabled()) {
66190dc8812SScott Wood         return env->spr[SPR_DECR];
66290dc8812SScott Wood     }
66390dc8812SScott Wood 
664f55e9d9aSTristan Gingold     return _cpu_ppc_load_decr(env, tb_env->decr_next);
66558a7d328Sj_mayer }
66658a7d328Sj_mayer 
667e2684c0bSAndreas Färber uint32_t cpu_ppc_load_hdecr (CPUPPCState *env)
66858a7d328Sj_mayer {
669c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
67058a7d328Sj_mayer 
671f55e9d9aSTristan Gingold     return _cpu_ppc_load_decr(env, tb_env->hdecr_next);
67258a7d328Sj_mayer }
67358a7d328Sj_mayer 
674e2684c0bSAndreas Färber uint64_t cpu_ppc_load_purr (CPUPPCState *env)
67558a7d328Sj_mayer {
676c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
67758a7d328Sj_mayer     uint64_t diff;
67858a7d328Sj_mayer 
679bc72ad67SAlex Bligh     diff = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - tb_env->purr_start;
68058a7d328Sj_mayer 
681*73bcb24dSRutuja Shah     return tb_env->purr_load +
682*73bcb24dSRutuja Shah         muldiv64(diff, tb_env->tb_freq, NANOSECONDS_PER_SECOND);
68358a7d328Sj_mayer }
68458a7d328Sj_mayer 
6859fddaa0cSbellard /* When decrementer expires,
6869fddaa0cSbellard  * all we need to do is generate or queue a CPU exception
6879fddaa0cSbellard  */
6887e0a9247SAndreas Färber static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
6899fddaa0cSbellard {
6909fddaa0cSbellard     /* Raise it */
691d12d51d5Saliguori     LOG_TB("raise decrementer exception\n");
6927058581aSAndreas Färber     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
6939fddaa0cSbellard }
6949fddaa0cSbellard 
695e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu)
696e81a982aSAlexander Graf {
697e81a982aSAlexander Graf     ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
698e81a982aSAlexander Graf }
699e81a982aSAlexander Graf 
7007e0a9247SAndreas Färber static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
70158a7d328Sj_mayer {
70258a7d328Sj_mayer     /* Raise it */
703d12d51d5Saliguori     LOG_TB("raise decrementer exception\n");
7047058581aSAndreas Färber     ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
70558a7d328Sj_mayer }
70658a7d328Sj_mayer 
707e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
708e81a982aSAlexander Graf {
709e81a982aSAlexander Graf     ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
710e81a982aSAlexander Graf }
711e81a982aSAlexander Graf 
7127e0a9247SAndreas Färber static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
7131246b259SStefan Weil                                  QEMUTimer *timer,
714e81a982aSAlexander Graf                                  void (*raise_excp)(void *),
715e81a982aSAlexander Graf                                  void (*lower_excp)(PowerPCCPU *),
716e81a982aSAlexander Graf                                  uint32_t decr, uint32_t value)
7179fddaa0cSbellard {
7187e0a9247SAndreas Färber     CPUPPCState *env = &cpu->env;
719c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
7209fddaa0cSbellard     uint64_t now, next;
7219fddaa0cSbellard 
722d12d51d5Saliguori     LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
723aae9366aSj_mayer                 decr, value);
72455f7d4b0SDavid Gibson 
72555f7d4b0SDavid Gibson     if (kvm_enabled()) {
72655f7d4b0SDavid Gibson         /* KVM handles decrementer exceptions, we don't need our own timer */
72755f7d4b0SDavid Gibson         return;
72855f7d4b0SDavid Gibson     }
72955f7d4b0SDavid Gibson 
730e81a982aSAlexander Graf     /*
731e81a982aSAlexander Graf      * Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC
732e81a982aSAlexander Graf      * interrupt.
733e81a982aSAlexander Graf      *
734e81a982aSAlexander Graf      * If we get a really small DEC value, we can assume that by the time we
735e81a982aSAlexander Graf      * handled it we should inject an interrupt already.
736e81a982aSAlexander Graf      *
737e81a982aSAlexander Graf      * On MSB level based DEC implementations the MSB always means the interrupt
738e81a982aSAlexander Graf      * is pending, so raise it on those.
739e81a982aSAlexander Graf      *
740e81a982aSAlexander Graf      * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
741e81a982aSAlexander Graf      * an edge interrupt, so raise it here too.
742e81a982aSAlexander Graf      */
743e81a982aSAlexander Graf     if ((value < 3) ||
744e81a982aSAlexander Graf         ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && (value & 0x80000000)) ||
745e81a982aSAlexander Graf         ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000)
746e81a982aSAlexander Graf           && !(decr & 0x80000000))) {
747e81a982aSAlexander Graf         (*raise_excp)(cpu);
748e81a982aSAlexander Graf         return;
749e81a982aSAlexander Graf     }
750e81a982aSAlexander Graf 
751e81a982aSAlexander Graf     /* On MSB level based systems a 0 for the MSB stops interrupt delivery */
752e81a982aSAlexander Graf     if (!(value & 0x80000000) && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
753e81a982aSAlexander Graf         (*lower_excp)(cpu);
754e81a982aSAlexander Graf     }
755e81a982aSAlexander Graf 
756e81a982aSAlexander Graf     /* Calculate the next timer event */
757bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
758*73bcb24dSRutuja Shah     next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq);
75958a7d328Sj_mayer     *nextp = next;
760e81a982aSAlexander Graf 
7619fddaa0cSbellard     /* Adjust timer */
762bc72ad67SAlex Bligh     timer_mod(timer, next);
763ddd1055bSFabien Chouteau }
76458a7d328Sj_mayer 
7657e0a9247SAndreas Färber static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr,
766e81a982aSAlexander Graf                                        uint32_t value)
76758a7d328Sj_mayer {
7687e0a9247SAndreas Färber     ppc_tb_t *tb_env = cpu->env.tb_env;
76958a7d328Sj_mayer 
7707e0a9247SAndreas Färber     __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
771e81a982aSAlexander Graf                          tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr,
772e81a982aSAlexander Graf                          value);
7739fddaa0cSbellard }
7749fddaa0cSbellard 
775e2684c0bSAndreas Färber void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
7769fddaa0cSbellard {
7777e0a9247SAndreas Färber     PowerPCCPU *cpu = ppc_env_get_cpu(env);
7787e0a9247SAndreas Färber 
779e81a982aSAlexander Graf     _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value);
7809fddaa0cSbellard }
7819fddaa0cSbellard 
7829fddaa0cSbellard static void cpu_ppc_decr_cb(void *opaque)
7839fddaa0cSbellard {
78450c680f0SAndreas Färber     PowerPCCPU *cpu = opaque;
7857e0a9247SAndreas Färber 
786e81a982aSAlexander Graf     cpu_ppc_decr_excp(cpu);
7879fddaa0cSbellard }
7889fddaa0cSbellard 
7897e0a9247SAndreas Färber static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr,
790e81a982aSAlexander Graf                                         uint32_t value)
79158a7d328Sj_mayer {
7927e0a9247SAndreas Färber     ppc_tb_t *tb_env = cpu->env.tb_env;
79358a7d328Sj_mayer 
794b172c56aSj_mayer     if (tb_env->hdecr_timer != NULL) {
7957e0a9247SAndreas Färber         __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
796e81a982aSAlexander Graf                              tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
797e81a982aSAlexander Graf                              hdecr, value);
79858a7d328Sj_mayer     }
799b172c56aSj_mayer }
80058a7d328Sj_mayer 
801e2684c0bSAndreas Färber void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value)
80258a7d328Sj_mayer {
8037e0a9247SAndreas Färber     PowerPCCPU *cpu = ppc_env_get_cpu(env);
8047e0a9247SAndreas Färber 
805e81a982aSAlexander Graf     _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value);
80658a7d328Sj_mayer }
80758a7d328Sj_mayer 
80858a7d328Sj_mayer static void cpu_ppc_hdecr_cb(void *opaque)
80958a7d328Sj_mayer {
81050c680f0SAndreas Färber     PowerPCCPU *cpu = opaque;
8117e0a9247SAndreas Färber 
812e81a982aSAlexander Graf     cpu_ppc_hdecr_excp(cpu);
81358a7d328Sj_mayer }
81458a7d328Sj_mayer 
8157e0a9247SAndreas Färber static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
81658a7d328Sj_mayer {
8177e0a9247SAndreas Färber     ppc_tb_t *tb_env = cpu->env.tb_env;
81858a7d328Sj_mayer 
81958a7d328Sj_mayer     tb_env->purr_load = value;
820bc72ad67SAlex Bligh     tb_env->purr_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
82158a7d328Sj_mayer }
82258a7d328Sj_mayer 
8238ecc7913Sj_mayer static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
8248ecc7913Sj_mayer {
825e2684c0bSAndreas Färber     CPUPPCState *env = opaque;
8267e0a9247SAndreas Färber     PowerPCCPU *cpu = ppc_env_get_cpu(env);
827c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
8288ecc7913Sj_mayer 
8298ecc7913Sj_mayer     tb_env->tb_freq = freq;
830dbdd2506Sj_mayer     tb_env->decr_freq = freq;
8318ecc7913Sj_mayer     /* There is a bug in Linux 2.4 kernels:
8328ecc7913Sj_mayer      * if a decrementer exception is pending when it enables msr_ee at startup,
8338ecc7913Sj_mayer      * it's not ready to handle it...
8348ecc7913Sj_mayer      */
835e81a982aSAlexander Graf     _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
836e81a982aSAlexander Graf     _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
8377e0a9247SAndreas Färber     cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
8388ecc7913Sj_mayer }
8398ecc7913Sj_mayer 
84098a8b524SAlexey Kardashevskiy static void timebase_pre_save(void *opaque)
84198a8b524SAlexey Kardashevskiy {
84298a8b524SAlexey Kardashevskiy     PPCTimebase *tb = opaque;
8434a7428c5SChristopher Covington     uint64_t ticks = cpu_get_host_ticks();
84498a8b524SAlexey Kardashevskiy     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
84598a8b524SAlexey Kardashevskiy 
84698a8b524SAlexey Kardashevskiy     if (!first_ppc_cpu->env.tb_env) {
84798a8b524SAlexey Kardashevskiy         error_report("No timebase object");
84898a8b524SAlexey Kardashevskiy         return;
84998a8b524SAlexey Kardashevskiy     }
85098a8b524SAlexey Kardashevskiy 
85177bad151SPaolo Bonzini     tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
85298a8b524SAlexey Kardashevskiy     /*
85398a8b524SAlexey Kardashevskiy      * tb_offset is only expected to be changed by migration so
85498a8b524SAlexey Kardashevskiy      * there is no need to update it from KVM here
85598a8b524SAlexey Kardashevskiy      */
85698a8b524SAlexey Kardashevskiy     tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
85798a8b524SAlexey Kardashevskiy }
85898a8b524SAlexey Kardashevskiy 
85998a8b524SAlexey Kardashevskiy static int timebase_post_load(void *opaque, int version_id)
86098a8b524SAlexey Kardashevskiy {
86198a8b524SAlexey Kardashevskiy     PPCTimebase *tb_remote = opaque;
86298a8b524SAlexey Kardashevskiy     CPUState *cpu;
86398a8b524SAlexey Kardashevskiy     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
86498a8b524SAlexey Kardashevskiy     int64_t tb_off_adj, tb_off, ns_diff;
86598a8b524SAlexey Kardashevskiy     int64_t migration_duration_ns, migration_duration_tb, guest_tb, host_ns;
86698a8b524SAlexey Kardashevskiy     unsigned long freq;
86798a8b524SAlexey Kardashevskiy 
86898a8b524SAlexey Kardashevskiy     if (!first_ppc_cpu->env.tb_env) {
86998a8b524SAlexey Kardashevskiy         error_report("No timebase object");
87098a8b524SAlexey Kardashevskiy         return -1;
87198a8b524SAlexey Kardashevskiy     }
87298a8b524SAlexey Kardashevskiy 
87398a8b524SAlexey Kardashevskiy     freq = first_ppc_cpu->env.tb_env->tb_freq;
87498a8b524SAlexey Kardashevskiy     /*
87598a8b524SAlexey Kardashevskiy      * Calculate timebase on the destination side of migration.
87698a8b524SAlexey Kardashevskiy      * The destination timebase must be not less than the source timebase.
87798a8b524SAlexey Kardashevskiy      * We try to adjust timebase by downtime if host clocks are not
87898a8b524SAlexey Kardashevskiy      * too much out of sync (1 second for now).
87998a8b524SAlexey Kardashevskiy      */
88077bad151SPaolo Bonzini     host_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
88198a8b524SAlexey Kardashevskiy     ns_diff = MAX(0, host_ns - tb_remote->time_of_the_day_ns);
88213566fe3SStefan Hajnoczi     migration_duration_ns = MIN(NANOSECONDS_PER_SECOND, ns_diff);
88313566fe3SStefan Hajnoczi     migration_duration_tb = muldiv64(migration_duration_ns, freq,
88413566fe3SStefan Hajnoczi                                      NANOSECONDS_PER_SECOND);
88598a8b524SAlexey Kardashevskiy     guest_tb = tb_remote->guest_timebase + MIN(0, migration_duration_tb);
88698a8b524SAlexey Kardashevskiy 
8874a7428c5SChristopher Covington     tb_off_adj = guest_tb - cpu_get_host_ticks();
88898a8b524SAlexey Kardashevskiy 
88998a8b524SAlexey Kardashevskiy     tb_off = first_ppc_cpu->env.tb_env->tb_offset;
89098a8b524SAlexey Kardashevskiy     trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off,
89198a8b524SAlexey Kardashevskiy                         (tb_off_adj - tb_off) / freq);
89298a8b524SAlexey Kardashevskiy 
89398a8b524SAlexey Kardashevskiy     /* Set new offset to all CPUs */
89498a8b524SAlexey Kardashevskiy     CPU_FOREACH(cpu) {
89598a8b524SAlexey Kardashevskiy         PowerPCCPU *pcpu = POWERPC_CPU(cpu);
89698a8b524SAlexey Kardashevskiy         pcpu->env.tb_env->tb_offset = tb_off_adj;
89798a8b524SAlexey Kardashevskiy     }
89898a8b524SAlexey Kardashevskiy 
89998a8b524SAlexey Kardashevskiy     return 0;
90098a8b524SAlexey Kardashevskiy }
90198a8b524SAlexey Kardashevskiy 
90298a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = {
90398a8b524SAlexey Kardashevskiy     .name = "timebase",
90498a8b524SAlexey Kardashevskiy     .version_id = 1,
90598a8b524SAlexey Kardashevskiy     .minimum_version_id = 1,
90698a8b524SAlexey Kardashevskiy     .minimum_version_id_old = 1,
90798a8b524SAlexey Kardashevskiy     .pre_save = timebase_pre_save,
90898a8b524SAlexey Kardashevskiy     .post_load = timebase_post_load,
90998a8b524SAlexey Kardashevskiy     .fields      = (VMStateField []) {
91098a8b524SAlexey Kardashevskiy         VMSTATE_UINT64(guest_timebase, PPCTimebase),
91198a8b524SAlexey Kardashevskiy         VMSTATE_INT64(time_of_the_day_ns, PPCTimebase),
91298a8b524SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
91398a8b524SAlexey Kardashevskiy     },
91498a8b524SAlexey Kardashevskiy };
91598a8b524SAlexey Kardashevskiy 
9169fddaa0cSbellard /* Set up (once) timebase frequency (in Hz) */
917e2684c0bSAndreas Färber clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
9189fddaa0cSbellard {
91950c680f0SAndreas Färber     PowerPCCPU *cpu = ppc_env_get_cpu(env);
920c227f099SAnthony Liguori     ppc_tb_t *tb_env;
9219fddaa0cSbellard 
9227267c094SAnthony Liguori     tb_env = g_malloc0(sizeof(ppc_tb_t));
9239fddaa0cSbellard     env->tb_env = tb_env;
924ddd1055bSFabien Chouteau     tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
925e81a982aSAlexander Graf     if (env->insns_flags & PPC_SEGMENT_64B) {
926e81a982aSAlexander Graf         /* All Book3S 64bit CPUs implement level based DEC logic */
927e81a982aSAlexander Graf         tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
928e81a982aSAlexander Graf     }
9299fddaa0cSbellard     /* Create new timer */
930bc72ad67SAlex Bligh     tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu);
931b172c56aSj_mayer     if (0) {
932b172c56aSj_mayer         /* XXX: find a suitable condition to enable the hypervisor decrementer
933b172c56aSj_mayer          */
934bc72ad67SAlex Bligh         tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb,
93550c680f0SAndreas Färber                                                 cpu);
936b172c56aSj_mayer     } else {
937b172c56aSj_mayer         tb_env->hdecr_timer = NULL;
938b172c56aSj_mayer     }
9398ecc7913Sj_mayer     cpu_ppc_set_tb_clk(env, freq);
9409fddaa0cSbellard 
9418ecc7913Sj_mayer     return &cpu_ppc_set_tb_clk;
9429fddaa0cSbellard }
9439fddaa0cSbellard 
94476a66253Sj_mayer /* Specific helpers for POWER & PowerPC 601 RTC */
945b1d8e52eSblueswir1 #if 0
946e2684c0bSAndreas Färber static clk_setup_cb cpu_ppc601_rtc_init (CPUPPCState *env)
94776a66253Sj_mayer {
94876a66253Sj_mayer     return cpu_ppc_tb_init(env, 7812500);
94976a66253Sj_mayer }
950b1d8e52eSblueswir1 #endif
95176a66253Sj_mayer 
952e2684c0bSAndreas Färber void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value)
9538a84de23Sj_mayer {
9548a84de23Sj_mayer     _cpu_ppc_store_tbu(env, value);
9558a84de23Sj_mayer }
95676a66253Sj_mayer 
957e2684c0bSAndreas Färber uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env)
9588a84de23Sj_mayer {
9598a84de23Sj_mayer     return _cpu_ppc_load_tbu(env);
9608a84de23Sj_mayer }
96176a66253Sj_mayer 
962e2684c0bSAndreas Färber void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value)
96376a66253Sj_mayer {
96476a66253Sj_mayer     cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
96576a66253Sj_mayer }
96676a66253Sj_mayer 
967e2684c0bSAndreas Färber uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env)
96876a66253Sj_mayer {
96976a66253Sj_mayer     return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
97076a66253Sj_mayer }
97176a66253Sj_mayer 
972636aaad7Sj_mayer /*****************************************************************************/
973ddd1055bSFabien Chouteau /* PowerPC 40x timers */
974636aaad7Sj_mayer 
975636aaad7Sj_mayer /* PIT, FIT & WDT */
976ddd1055bSFabien Chouteau typedef struct ppc40x_timer_t ppc40x_timer_t;
977ddd1055bSFabien Chouteau struct ppc40x_timer_t {
978636aaad7Sj_mayer     uint64_t pit_reload;  /* PIT auto-reload value        */
979636aaad7Sj_mayer     uint64_t fit_next;    /* Tick for next FIT interrupt  */
9801246b259SStefan Weil     QEMUTimer *fit_timer;
981636aaad7Sj_mayer     uint64_t wdt_next;    /* Tick for next WDT interrupt  */
9821246b259SStefan Weil     QEMUTimer *wdt_timer;
983d63cb48dSEdgar E. Iglesias 
984d63cb48dSEdgar E. Iglesias     /* 405 have the PIT, 440 have a DECR.  */
985d63cb48dSEdgar E. Iglesias     unsigned int decr_excp;
986636aaad7Sj_mayer };
987636aaad7Sj_mayer 
988636aaad7Sj_mayer /* Fixed interval timer */
989636aaad7Sj_mayer static void cpu_4xx_fit_cb (void *opaque)
99076a66253Sj_mayer {
9917058581aSAndreas Färber     PowerPCCPU *cpu;
992e2684c0bSAndreas Färber     CPUPPCState *env;
993c227f099SAnthony Liguori     ppc_tb_t *tb_env;
994ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
995636aaad7Sj_mayer     uint64_t now, next;
996636aaad7Sj_mayer 
997636aaad7Sj_mayer     env = opaque;
9987058581aSAndreas Färber     cpu = ppc_env_get_cpu(env);
999636aaad7Sj_mayer     tb_env = env->tb_env;
1000ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1001bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1002636aaad7Sj_mayer     switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
1003636aaad7Sj_mayer     case 0:
1004636aaad7Sj_mayer         next = 1 << 9;
1005636aaad7Sj_mayer         break;
1006636aaad7Sj_mayer     case 1:
1007636aaad7Sj_mayer         next = 1 << 13;
1008636aaad7Sj_mayer         break;
1009636aaad7Sj_mayer     case 2:
1010636aaad7Sj_mayer         next = 1 << 17;
1011636aaad7Sj_mayer         break;
1012636aaad7Sj_mayer     case 3:
1013636aaad7Sj_mayer         next = 1 << 21;
1014636aaad7Sj_mayer         break;
1015636aaad7Sj_mayer     default:
1016636aaad7Sj_mayer         /* Cannot occur, but makes gcc happy */
1017636aaad7Sj_mayer         return;
1018636aaad7Sj_mayer     }
1019*73bcb24dSRutuja Shah     next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq);
1020636aaad7Sj_mayer     if (next == now)
1021636aaad7Sj_mayer         next++;
1022bc72ad67SAlex Bligh     timer_mod(ppc40x_timer->fit_timer, next);
1023636aaad7Sj_mayer     env->spr[SPR_40x_TSR] |= 1 << 26;
10247058581aSAndreas Färber     if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) {
10257058581aSAndreas Färber         ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1);
10267058581aSAndreas Färber     }
102790e189ecSBlue Swirl     LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
1028e96efcfcSj_mayer            (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
1029636aaad7Sj_mayer            env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
1030636aaad7Sj_mayer }
1031636aaad7Sj_mayer 
1032636aaad7Sj_mayer /* Programmable interval timer */
1033e2684c0bSAndreas Färber static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
1034636aaad7Sj_mayer {
1035ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1036636aaad7Sj_mayer     uint64_t now, next;
1037636aaad7Sj_mayer 
1038ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1039ddd1055bSFabien Chouteau     if (ppc40x_timer->pit_reload <= 1 ||
10404b6d0a4cSj_mayer         !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
10414b6d0a4cSj_mayer         (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
10424b6d0a4cSj_mayer         /* Stop PIT */
1043d12d51d5Saliguori         LOG_TB("%s: stop PIT\n", __func__);
1044bc72ad67SAlex Bligh         timer_del(tb_env->decr_timer);
10454b6d0a4cSj_mayer     } else {
1046d12d51d5Saliguori         LOG_TB("%s: start PIT %016" PRIx64 "\n",
1047ddd1055bSFabien Chouteau                     __func__, ppc40x_timer->pit_reload);
1048bc72ad67SAlex Bligh         now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1049ddd1055bSFabien Chouteau         next = now + muldiv64(ppc40x_timer->pit_reload,
1050*73bcb24dSRutuja Shah                               NANOSECONDS_PER_SECOND, tb_env->decr_freq);
10514b6d0a4cSj_mayer         if (is_excp)
10524b6d0a4cSj_mayer             next += tb_env->decr_next - now;
1053636aaad7Sj_mayer         if (next == now)
1054636aaad7Sj_mayer             next++;
1055bc72ad67SAlex Bligh         timer_mod(tb_env->decr_timer, next);
1056636aaad7Sj_mayer         tb_env->decr_next = next;
1057636aaad7Sj_mayer     }
10584b6d0a4cSj_mayer }
10594b6d0a4cSj_mayer 
10604b6d0a4cSj_mayer static void cpu_4xx_pit_cb (void *opaque)
10614b6d0a4cSj_mayer {
10627058581aSAndreas Färber     PowerPCCPU *cpu;
1063e2684c0bSAndreas Färber     CPUPPCState *env;
1064c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1065ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
10664b6d0a4cSj_mayer 
10674b6d0a4cSj_mayer     env = opaque;
10687058581aSAndreas Färber     cpu = ppc_env_get_cpu(env);
10694b6d0a4cSj_mayer     tb_env = env->tb_env;
1070ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1071636aaad7Sj_mayer     env->spr[SPR_40x_TSR] |= 1 << 27;
10727058581aSAndreas Färber     if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) {
10737058581aSAndreas Färber         ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1);
10747058581aSAndreas Färber     }
10754b6d0a4cSj_mayer     start_stop_pit(env, tb_env, 1);
107690e189ecSBlue Swirl     LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
1077e96efcfcSj_mayer            "%016" PRIx64 "\n", __func__,
1078e96efcfcSj_mayer            (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
1079e96efcfcSj_mayer            (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
1080636aaad7Sj_mayer            env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
1081ddd1055bSFabien Chouteau            ppc40x_timer->pit_reload);
1082636aaad7Sj_mayer }
1083636aaad7Sj_mayer 
1084636aaad7Sj_mayer /* Watchdog timer */
1085636aaad7Sj_mayer static void cpu_4xx_wdt_cb (void *opaque)
1086636aaad7Sj_mayer {
10877058581aSAndreas Färber     PowerPCCPU *cpu;
1088e2684c0bSAndreas Färber     CPUPPCState *env;
1089c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1090ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1091636aaad7Sj_mayer     uint64_t now, next;
1092636aaad7Sj_mayer 
1093636aaad7Sj_mayer     env = opaque;
10947058581aSAndreas Färber     cpu = ppc_env_get_cpu(env);
1095636aaad7Sj_mayer     tb_env = env->tb_env;
1096ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
1097bc72ad67SAlex Bligh     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1098636aaad7Sj_mayer     switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
1099636aaad7Sj_mayer     case 0:
1100636aaad7Sj_mayer         next = 1 << 17;
1101636aaad7Sj_mayer         break;
1102636aaad7Sj_mayer     case 1:
1103636aaad7Sj_mayer         next = 1 << 21;
1104636aaad7Sj_mayer         break;
1105636aaad7Sj_mayer     case 2:
1106636aaad7Sj_mayer         next = 1 << 25;
1107636aaad7Sj_mayer         break;
1108636aaad7Sj_mayer     case 3:
1109636aaad7Sj_mayer         next = 1 << 29;
1110636aaad7Sj_mayer         break;
1111636aaad7Sj_mayer     default:
1112636aaad7Sj_mayer         /* Cannot occur, but makes gcc happy */
1113636aaad7Sj_mayer         return;
1114636aaad7Sj_mayer     }
1115*73bcb24dSRutuja Shah     next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq);
1116636aaad7Sj_mayer     if (next == now)
1117636aaad7Sj_mayer         next++;
111890e189ecSBlue Swirl     LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
1119636aaad7Sj_mayer            env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
1120636aaad7Sj_mayer     switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
1121636aaad7Sj_mayer     case 0x0:
1122636aaad7Sj_mayer     case 0x1:
1123bc72ad67SAlex Bligh         timer_mod(ppc40x_timer->wdt_timer, next);
1124ddd1055bSFabien Chouteau         ppc40x_timer->wdt_next = next;
1125a1f7f97bSPeter Maydell         env->spr[SPR_40x_TSR] |= 1U << 31;
1126636aaad7Sj_mayer         break;
1127636aaad7Sj_mayer     case 0x2:
1128bc72ad67SAlex Bligh         timer_mod(ppc40x_timer->wdt_timer, next);
1129ddd1055bSFabien Chouteau         ppc40x_timer->wdt_next = next;
1130636aaad7Sj_mayer         env->spr[SPR_40x_TSR] |= 1 << 30;
11317058581aSAndreas Färber         if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) {
11327058581aSAndreas Färber             ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1);
11337058581aSAndreas Färber         }
1134636aaad7Sj_mayer         break;
1135636aaad7Sj_mayer     case 0x3:
1136636aaad7Sj_mayer         env->spr[SPR_40x_TSR] &= ~0x30000000;
1137636aaad7Sj_mayer         env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
1138636aaad7Sj_mayer         switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
1139636aaad7Sj_mayer         case 0x0:
1140636aaad7Sj_mayer             /* No reset */
1141636aaad7Sj_mayer             break;
1142636aaad7Sj_mayer         case 0x1: /* Core reset */
1143f3273ba6SAndreas Färber             ppc40x_core_reset(cpu);
11448ecc7913Sj_mayer             break;
1145636aaad7Sj_mayer         case 0x2: /* Chip reset */
1146f3273ba6SAndreas Färber             ppc40x_chip_reset(cpu);
11478ecc7913Sj_mayer             break;
1148636aaad7Sj_mayer         case 0x3: /* System reset */
1149f3273ba6SAndreas Färber             ppc40x_system_reset(cpu);
11508ecc7913Sj_mayer             break;
1151636aaad7Sj_mayer         }
1152636aaad7Sj_mayer     }
115376a66253Sj_mayer }
115476a66253Sj_mayer 
1155e2684c0bSAndreas Färber void store_40x_pit (CPUPPCState *env, target_ulong val)
115676a66253Sj_mayer {
1157c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1158ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1159636aaad7Sj_mayer 
1160636aaad7Sj_mayer     tb_env = env->tb_env;
1161ddd1055bSFabien Chouteau     ppc40x_timer = tb_env->opaque;
116290e189ecSBlue Swirl     LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val);
1163ddd1055bSFabien Chouteau     ppc40x_timer->pit_reload = val;
11644b6d0a4cSj_mayer     start_stop_pit(env, tb_env, 0);
116576a66253Sj_mayer }
116676a66253Sj_mayer 
1167e2684c0bSAndreas Färber target_ulong load_40x_pit (CPUPPCState *env)
116876a66253Sj_mayer {
1169636aaad7Sj_mayer     return cpu_ppc_load_decr(env);
117076a66253Sj_mayer }
117176a66253Sj_mayer 
1172ddd1055bSFabien Chouteau static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
11734b6d0a4cSj_mayer {
1174e2684c0bSAndreas Färber     CPUPPCState *env = opaque;
1175c227f099SAnthony Liguori     ppc_tb_t *tb_env = env->tb_env;
11764b6d0a4cSj_mayer 
1177d12d51d5Saliguori     LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__,
1178aae9366aSj_mayer                 freq);
11794b6d0a4cSj_mayer     tb_env->tb_freq = freq;
1180dbdd2506Sj_mayer     tb_env->decr_freq = freq;
11814b6d0a4cSj_mayer     /* XXX: we should also update all timers */
11824b6d0a4cSj_mayer }
11834b6d0a4cSj_mayer 
1184e2684c0bSAndreas Färber clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
1185d63cb48dSEdgar E. Iglesias                                   unsigned int decr_excp)
1186636aaad7Sj_mayer {
1187c227f099SAnthony Liguori     ppc_tb_t *tb_env;
1188ddd1055bSFabien Chouteau     ppc40x_timer_t *ppc40x_timer;
1189636aaad7Sj_mayer 
11907267c094SAnthony Liguori     tb_env = g_malloc0(sizeof(ppc_tb_t));
11918ecc7913Sj_mayer     env->tb_env = tb_env;
1192ddd1055bSFabien Chouteau     tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
1193ddd1055bSFabien Chouteau     ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t));
11948ecc7913Sj_mayer     tb_env->tb_freq = freq;
1195dbdd2506Sj_mayer     tb_env->decr_freq = freq;
1196ddd1055bSFabien Chouteau     tb_env->opaque = ppc40x_timer;
1197d12d51d5Saliguori     LOG_TB("%s freq %" PRIu32 "\n", __func__, freq);
1198ddd1055bSFabien Chouteau     if (ppc40x_timer != NULL) {
1199636aaad7Sj_mayer         /* We use decr timer for PIT */
1200bc72ad67SAlex Bligh         tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, env);
1201ddd1055bSFabien Chouteau         ppc40x_timer->fit_timer =
1202bc72ad67SAlex Bligh             timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, env);
1203ddd1055bSFabien Chouteau         ppc40x_timer->wdt_timer =
1204bc72ad67SAlex Bligh             timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, env);
1205ddd1055bSFabien Chouteau         ppc40x_timer->decr_excp = decr_excp;
1206636aaad7Sj_mayer     }
12078ecc7913Sj_mayer 
1208ddd1055bSFabien Chouteau     return &ppc_40x_set_tb_clk;
120976a66253Sj_mayer }
121076a66253Sj_mayer 
12112e719ba3Sj_mayer /*****************************************************************************/
12122e719ba3Sj_mayer /* Embedded PowerPC Device Control Registers */
1213c227f099SAnthony Liguori typedef struct ppc_dcrn_t ppc_dcrn_t;
1214c227f099SAnthony Liguori struct ppc_dcrn_t {
12152e719ba3Sj_mayer     dcr_read_cb dcr_read;
12162e719ba3Sj_mayer     dcr_write_cb dcr_write;
12172e719ba3Sj_mayer     void *opaque;
12182e719ba3Sj_mayer };
12192e719ba3Sj_mayer 
1220a750fc0bSj_mayer /* XXX: on 460, DCR addresses are 32 bits wide,
1221a750fc0bSj_mayer  *      using DCRIPR to get the 22 upper bits of the DCR address
1222a750fc0bSj_mayer  */
12232e719ba3Sj_mayer #define DCRN_NB 1024
1224c227f099SAnthony Liguori struct ppc_dcr_t {
1225c227f099SAnthony Liguori     ppc_dcrn_t dcrn[DCRN_NB];
12262e719ba3Sj_mayer     int (*read_error)(int dcrn);
12272e719ba3Sj_mayer     int (*write_error)(int dcrn);
12282e719ba3Sj_mayer };
12292e719ba3Sj_mayer 
123073b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
12312e719ba3Sj_mayer {
1232c227f099SAnthony Liguori     ppc_dcrn_t *dcr;
12332e719ba3Sj_mayer 
12342e719ba3Sj_mayer     if (dcrn < 0 || dcrn >= DCRN_NB)
12352e719ba3Sj_mayer         goto error;
12362e719ba3Sj_mayer     dcr = &dcr_env->dcrn[dcrn];
12372e719ba3Sj_mayer     if (dcr->dcr_read == NULL)
12382e719ba3Sj_mayer         goto error;
12392e719ba3Sj_mayer     *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
12402e719ba3Sj_mayer 
12412e719ba3Sj_mayer     return 0;
12422e719ba3Sj_mayer 
12432e719ba3Sj_mayer  error:
12442e719ba3Sj_mayer     if (dcr_env->read_error != NULL)
12452e719ba3Sj_mayer         return (*dcr_env->read_error)(dcrn);
12462e719ba3Sj_mayer 
12472e719ba3Sj_mayer     return -1;
12482e719ba3Sj_mayer }
12492e719ba3Sj_mayer 
125073b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
12512e719ba3Sj_mayer {
1252c227f099SAnthony Liguori     ppc_dcrn_t *dcr;
12532e719ba3Sj_mayer 
12542e719ba3Sj_mayer     if (dcrn < 0 || dcrn >= DCRN_NB)
12552e719ba3Sj_mayer         goto error;
12562e719ba3Sj_mayer     dcr = &dcr_env->dcrn[dcrn];
12572e719ba3Sj_mayer     if (dcr->dcr_write == NULL)
12582e719ba3Sj_mayer         goto error;
12592e719ba3Sj_mayer     (*dcr->dcr_write)(dcr->opaque, dcrn, val);
12602e719ba3Sj_mayer 
12612e719ba3Sj_mayer     return 0;
12622e719ba3Sj_mayer 
12632e719ba3Sj_mayer  error:
12642e719ba3Sj_mayer     if (dcr_env->write_error != NULL)
12652e719ba3Sj_mayer         return (*dcr_env->write_error)(dcrn);
12662e719ba3Sj_mayer 
12672e719ba3Sj_mayer     return -1;
12682e719ba3Sj_mayer }
12692e719ba3Sj_mayer 
1270e2684c0bSAndreas Färber int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
12712e719ba3Sj_mayer                       dcr_read_cb dcr_read, dcr_write_cb dcr_write)
12722e719ba3Sj_mayer {
1273c227f099SAnthony Liguori     ppc_dcr_t *dcr_env;
1274c227f099SAnthony Liguori     ppc_dcrn_t *dcr;
12752e719ba3Sj_mayer 
12762e719ba3Sj_mayer     dcr_env = env->dcr_env;
12772e719ba3Sj_mayer     if (dcr_env == NULL)
12782e719ba3Sj_mayer         return -1;
12792e719ba3Sj_mayer     if (dcrn < 0 || dcrn >= DCRN_NB)
12802e719ba3Sj_mayer         return -1;
12812e719ba3Sj_mayer     dcr = &dcr_env->dcrn[dcrn];
12822e719ba3Sj_mayer     if (dcr->opaque != NULL ||
12832e719ba3Sj_mayer         dcr->dcr_read != NULL ||
12842e719ba3Sj_mayer         dcr->dcr_write != NULL)
12852e719ba3Sj_mayer         return -1;
12862e719ba3Sj_mayer     dcr->opaque = opaque;
12872e719ba3Sj_mayer     dcr->dcr_read = dcr_read;
12882e719ba3Sj_mayer     dcr->dcr_write = dcr_write;
12892e719ba3Sj_mayer 
12902e719ba3Sj_mayer     return 0;
12912e719ba3Sj_mayer }
12922e719ba3Sj_mayer 
1293e2684c0bSAndreas Färber int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn),
12942e719ba3Sj_mayer                   int (*write_error)(int dcrn))
12952e719ba3Sj_mayer {
1296c227f099SAnthony Liguori     ppc_dcr_t *dcr_env;
12972e719ba3Sj_mayer 
12987267c094SAnthony Liguori     dcr_env = g_malloc0(sizeof(ppc_dcr_t));
12992e719ba3Sj_mayer     dcr_env->read_error = read_error;
13002e719ba3Sj_mayer     dcr_env->write_error = write_error;
13012e719ba3Sj_mayer     env->dcr_env = dcr_env;
13022e719ba3Sj_mayer 
13032e719ba3Sj_mayer     return 0;
13042e719ba3Sj_mayer }
13052e719ba3Sj_mayer 
130664201201Sbellard /*****************************************************************************/
130764201201Sbellard /* Debug port */
1308fd0bbb12Sbellard void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
130964201201Sbellard {
131064201201Sbellard     addr &= 0xF;
131164201201Sbellard     switch (addr) {
131264201201Sbellard     case 0:
131364201201Sbellard         printf("%c", val);
131464201201Sbellard         break;
131564201201Sbellard     case 1:
131664201201Sbellard         printf("\n");
131764201201Sbellard         fflush(stdout);
131864201201Sbellard         break;
131964201201Sbellard     case 2:
1320aae9366aSj_mayer         printf("Set loglevel to %04" PRIx32 "\n", val);
132124537a01SPeter Maydell         qemu_set_log(val | 0x100);
132264201201Sbellard         break;
132364201201Sbellard     }
132464201201Sbellard }
132564201201Sbellard 
13260ce470cdSAlexey Kardashevskiy /* CPU device-tree ID helpers */
13270ce470cdSAlexey Kardashevskiy int ppc_get_vcpu_dt_id(PowerPCCPU *cpu)
13280ce470cdSAlexey Kardashevskiy {
13290ce470cdSAlexey Kardashevskiy     return cpu->cpu_dt_id;
13300ce470cdSAlexey Kardashevskiy }
13310ce470cdSAlexey Kardashevskiy 
13320ce470cdSAlexey Kardashevskiy PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id)
13330ce470cdSAlexey Kardashevskiy {
13340ce470cdSAlexey Kardashevskiy     CPUState *cs;
13350ce470cdSAlexey Kardashevskiy 
13360ce470cdSAlexey Kardashevskiy     CPU_FOREACH(cs) {
13370ce470cdSAlexey Kardashevskiy         PowerPCCPU *cpu = POWERPC_CPU(cs);
13380ce470cdSAlexey Kardashevskiy 
13390ce470cdSAlexey Kardashevskiy         if (cpu->cpu_dt_id == cpu_dt_id) {
13400ce470cdSAlexey Kardashevskiy             return cpu;
13410ce470cdSAlexey Kardashevskiy         }
13420ce470cdSAlexey Kardashevskiy     }
13430ce470cdSAlexey Kardashevskiy 
13440ce470cdSAlexey Kardashevskiy     return NULL;
13450ce470cdSAlexey Kardashevskiy }
1346