2012-12-06 12:15:58 +01:00
|
|
|
#ifndef HW_PPC_H
|
2016-06-29 15:29:06 +02:00
|
|
|
#define HW_PPC_H
|
2012-12-06 12:15:58 +01:00
|
|
|
|
2016-10-11 08:56:52 +02:00
|
|
|
#include "target/ppc/cpu-qom.h"
|
2016-03-15 14:32:19 +01:00
|
|
|
|
2012-12-01 03:55:58 +01:00
|
|
|
void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level);
|
2019-03-06 09:50:07 +01:00
|
|
|
PowerPCCPU *ppc_get_vcpu_by_pir(int pir);
|
2019-11-25 07:58:05 +01:00
|
|
|
int ppc_cpu_pir(PowerPCCPU *cpu);
|
2023-06-22 11:33:53 +02:00
|
|
|
int ppc_cpu_tir(PowerPCCPU *cpu);
|
2011-09-13 06:00:32 +02:00
|
|
|
|
2007-11-17 18:14:51 +01:00
|
|
|
/* PowerPC hardware exceptions management helpers */
|
|
|
|
typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
|
2009-10-01 23:12:16 +02:00
|
|
|
typedef struct clk_setup_t clk_setup_t;
|
|
|
|
struct clk_setup_t {
|
2007-11-17 18:14:51 +01:00
|
|
|
clk_setup_cb cb;
|
|
|
|
void *opaque;
|
|
|
|
};
|
2009-10-01 23:12:16 +02:00
|
|
|
static inline void clk_setup (clk_setup_t *clk, uint32_t freq)
|
2007-11-17 18:14:51 +01:00
|
|
|
{
|
|
|
|
if (clk->cb != NULL)
|
|
|
|
(*clk->cb)(clk->opaque, freq);
|
|
|
|
}
|
|
|
|
|
2011-09-13 06:00:32 +02:00
|
|
|
struct ppc_tb_t {
|
|
|
|
/* Time base management */
|
|
|
|
int64_t tb_offset; /* Compensation */
|
|
|
|
int64_t atb_offset; /* Compensation */
|
2019-11-28 14:46:54 +01:00
|
|
|
int64_t vtb_offset;
|
2011-09-13 06:00:32 +02:00
|
|
|
uint32_t tb_freq; /* TB frequency */
|
|
|
|
/* Decrementer management */
|
|
|
|
uint64_t decr_next; /* Tick for next decr interrupt */
|
|
|
|
uint32_t decr_freq; /* decrementer frequency */
|
2013-12-01 08:49:47 +01:00
|
|
|
QEMUTimer *decr_timer;
|
2011-09-13 06:00:32 +02:00
|
|
|
/* Hypervisor decrementer management */
|
|
|
|
uint64_t hdecr_next; /* Tick for next hdecr interrupt */
|
2013-12-01 08:49:47 +01:00
|
|
|
QEMUTimer *hdecr_timer;
|
2019-11-28 14:46:55 +01:00
|
|
|
int64_t purr_offset;
|
2011-09-13 06:00:32 +02:00
|
|
|
void *opaque;
|
|
|
|
uint32_t flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* PPC Timers flags */
|
|
|
|
#define PPC_TIMER_BOOKE (1 << 0) /* Enable Booke support */
|
|
|
|
#define PPC_TIMER_E500 (1 << 1) /* Enable e500 support */
|
|
|
|
#define PPC_DECR_UNDERFLOW_TRIGGERED (1 << 2) /* Decr interrupt triggered when
|
|
|
|
* the most significant bit
|
|
|
|
* changes from 0 to 1.
|
|
|
|
*/
|
|
|
|
#define PPC_DECR_ZERO_TRIGGERED (1 << 3) /* Decr interrupt triggered when
|
|
|
|
* the decrementer reaches zero.
|
|
|
|
*/
|
2014-04-06 01:32:06 +02:00
|
|
|
#define PPC_DECR_UNDERFLOW_LEVEL (1 << 4) /* Decr interrupt active when
|
|
|
|
* the most significant bit is 1.
|
|
|
|
*/
|
2011-09-13 06:00:32 +02:00
|
|
|
|
|
|
|
uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
|
2023-08-08 06:19:53 +02:00
|
|
|
void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq);
|
|
|
|
void cpu_ppc_tb_reset(CPUPPCState *env);
|
2022-04-04 08:49:06 +02:00
|
|
|
void cpu_ppc_tb_free(CPUPPCState *env);
|
2022-02-18 08:34:14 +01:00
|
|
|
void cpu_ppc_hdecr_init(CPUPPCState *env);
|
|
|
|
void cpu_ppc_hdecr_exit(CPUPPCState *env);
|
|
|
|
|
2007-11-17 18:14:51 +01:00
|
|
|
/* Embedded PowerPC DCR management */
|
2009-12-21 14:02:39 +01:00
|
|
|
typedef uint32_t (*dcr_read_cb)(void *opaque, int dcrn);
|
|
|
|
typedef void (*dcr_write_cb)(void *opaque, int dcrn, uint32_t val);
|
2012-03-14 01:38:23 +01:00
|
|
|
int ppc_dcr_init (CPUPPCState *env, int (*dcr_read_error)(int dcrn),
|
2007-11-17 18:14:51 +01:00
|
|
|
int (*dcr_write_error)(int dcrn));
|
2012-03-14 01:38:23 +01:00
|
|
|
int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
|
2007-11-17 18:14:51 +01:00
|
|
|
dcr_read_cb drc_read, dcr_write_cb dcr_write);
|
2012-03-14 01:38:23 +01:00
|
|
|
clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
|
2010-09-20 19:08:42 +02:00
|
|
|
unsigned int decr_excp);
|
|
|
|
|
2007-11-17 18:14:51 +01:00
|
|
|
/* Embedded PowerPC reset */
|
2013-01-18 15:57:51 +01:00
|
|
|
void ppc40x_core_reset(PowerPCCPU *cpu);
|
|
|
|
void ppc40x_chip_reset(PowerPCCPU *cpu);
|
|
|
|
void ppc40x_system_reset(PowerPCCPU *cpu);
|
2008-10-26 14:43:07 +01:00
|
|
|
|
2016-03-15 14:32:19 +01:00
|
|
|
#if defined(CONFIG_USER_ONLY)
|
|
|
|
static inline void ppc40x_irq_init(PowerPCCPU *cpu) {}
|
|
|
|
static inline void ppc6xx_irq_init(PowerPCCPU *cpu) {}
|
|
|
|
static inline void ppc970_irq_init(PowerPCCPU *cpu) {}
|
|
|
|
static inline void ppcPOWER7_irq_init(PowerPCCPU *cpu) {}
|
2019-02-15 17:16:47 +01:00
|
|
|
static inline void ppcPOWER9_irq_init(PowerPCCPU *cpu) {}
|
2016-03-15 14:32:19 +01:00
|
|
|
static inline void ppce500_irq_init(PowerPCCPU *cpu) {}
|
ppc: Deassert the external interrupt pin in KVM on reset
When a CPU is reset, QEMU makes sure no interrupt is pending by clearing
CPUPPCstate::pending_interrupts in ppc_cpu_reset(). In the case of a
complete machine emulation, eg. a sPAPR machine, an external interrupt
request could still be pending in KVM though, eg. an IPI. It will be
eventually presented to the guest, which is supposed to acknowledge it at
the interrupt controller. If the interrupt controller is emulated in QEMU,
either XICS or XIVE, ppc_set_irq() won't deassert the external interrupt
pin in KVM since it isn't pending anymore for QEMU. When the vCPU re-enters
the guest, the interrupt request is still pending and the vCPU will try
again to acknowledge it. This causes an infinite loop and eventually hangs
the guest.
The code has been broken since the beginning. The issue wasn't hit before
because accel=kvm,kernel-irqchip=off is an awkward setup that never got
used until recently with the LC92x IBM systems (aka, Boston).
Add a ppc_irq_reset() function to do the necessary cleanup, ie. deassert
the IRQ pins of the CPU in QEMU and most importantly the external interrupt
pin for this vCPU in KVM.
Reported-by: Satheesh Rajendran <sathnaga@linux.vnet.ibm.com>
Signed-off-by: Greg Kurz <groug@kaod.org>
Message-Id: <157548861740.3650476.16879693165328764758.stgit@bahia.lan>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2019-12-04 20:43:37 +01:00
|
|
|
static inline void ppc_irq_reset(PowerPCCPU *cpu) {}
|
2016-03-15 14:32:19 +01:00
|
|
|
#else
|
|
|
|
void ppc40x_irq_init(PowerPCCPU *cpu);
|
|
|
|
void ppce500_irq_init(PowerPCCPU *cpu);
|
|
|
|
void ppc6xx_irq_init(PowerPCCPU *cpu);
|
|
|
|
void ppc970_irq_init(PowerPCCPU *cpu);
|
|
|
|
void ppcPOWER7_irq_init(PowerPCCPU *cpu);
|
2019-02-15 17:16:47 +01:00
|
|
|
void ppcPOWER9_irq_init(PowerPCCPU *cpu);
|
ppc: Deassert the external interrupt pin in KVM on reset
When a CPU is reset, QEMU makes sure no interrupt is pending by clearing
CPUPPCstate::pending_interrupts in ppc_cpu_reset(). In the case of a
complete machine emulation, eg. a sPAPR machine, an external interrupt
request could still be pending in KVM though, eg. an IPI. It will be
eventually presented to the guest, which is supposed to acknowledge it at
the interrupt controller. If the interrupt controller is emulated in QEMU,
either XICS or XIVE, ppc_set_irq() won't deassert the external interrupt
pin in KVM since it isn't pending anymore for QEMU. When the vCPU re-enters
the guest, the interrupt request is still pending and the vCPU will try
again to acknowledge it. This causes an infinite loop and eventually hangs
the guest.
The code has been broken since the beginning. The issue wasn't hit before
because accel=kvm,kernel-irqchip=off is an awkward setup that never got
used until recently with the LC92x IBM systems (aka, Boston).
Add a ppc_irq_reset() function to do the necessary cleanup, ie. deassert
the IRQ pins of the CPU in QEMU and most importantly the external interrupt
pin for this vCPU in KVM.
Reported-by: Satheesh Rajendran <sathnaga@linux.vnet.ibm.com>
Signed-off-by: Greg Kurz <groug@kaod.org>
Message-Id: <157548861740.3650476.16879693165328764758.stgit@bahia.lan>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2019-12-04 20:43:37 +01:00
|
|
|
void ppc_irq_reset(PowerPCCPU *cpu);
|
2016-03-15 14:32:19 +01:00
|
|
|
#endif
|
2009-01-08 17:01:23 +01:00
|
|
|
|
|
|
|
/* PPC machines for OpenBIOS */
|
|
|
|
enum {
|
|
|
|
ARCH_PREP = 0,
|
|
|
|
ARCH_MAC99,
|
|
|
|
ARCH_HEATHROW,
|
2010-02-09 17:37:02 +01:00
|
|
|
ARCH_MAC99_U3,
|
2009-01-08 17:01:23 +01:00
|
|
|
};
|
|
|
|
|
2022-04-12 04:12:41 +02:00
|
|
|
#define FW_CFG_PPC_WIDTH (FW_CFG_ARCH_LOCAL + 0x00)
|
|
|
|
#define FW_CFG_PPC_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
|
|
|
|
#define FW_CFG_PPC_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
|
|
|
|
#define FW_CFG_PPC_TBFREQ (FW_CFG_ARCH_LOCAL + 0x03)
|
|
|
|
#define FW_CFG_PPC_CLOCKFREQ (FW_CFG_ARCH_LOCAL + 0x04)
|
2010-08-03 15:22:42 +02:00
|
|
|
#define FW_CFG_PPC_IS_KVM (FW_CFG_ARCH_LOCAL + 0x05)
|
|
|
|
#define FW_CFG_PPC_KVM_HC (FW_CFG_ARCH_LOCAL + 0x06)
|
|
|
|
#define FW_CFG_PPC_KVM_PID (FW_CFG_ARCH_LOCAL + 0x07)
|
2014-07-11 03:24:39 +02:00
|
|
|
#define FW_CFG_PPC_NVRAM_ADDR (FW_CFG_ARCH_LOCAL + 0x08)
|
2014-04-17 19:04:44 +02:00
|
|
|
#define FW_CFG_PPC_BUSFREQ (FW_CFG_ARCH_LOCAL + 0x09)
|
2018-06-07 18:59:55 +02:00
|
|
|
#define FW_CFG_PPC_NVRAM_FLAT (FW_CFG_ARCH_LOCAL + 0x0a)
|
2018-06-12 18:43:57 +02:00
|
|
|
#define FW_CFG_PPC_VIACONFIG (FW_CFG_ARCH_LOCAL + 0x0b)
|
2009-08-15 16:27:05 +02:00
|
|
|
|
|
|
|
#define PPC_SERIAL_MM_BAUDBASE 399193
|
2011-09-13 06:00:32 +02:00
|
|
|
|
|
|
|
/* ppc_booke.c */
|
2012-12-01 04:43:18 +01:00
|
|
|
void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags);
|
2012-12-06 12:15:58 +01:00
|
|
|
#endif
|