ppc patch queue 2018-12-21
This pull request supersedes the one from 2018-12-13. This is a revised first ppc pull request for qemu-4.0. Highlights are: * Most of the code for the POWER9 "XIVE" interrupt controller (not complete yet, but we're getting there) * A number of g_new vs. g_malloc cleanups * Some IRQ wiring cleanups * A fix for how we advertise NUMA nodes to the guest for pseries -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAlwce1QACgkQbDjKyiDZ s5JqlhAAhES3+UoNHa/eTf/o2OOgIgZ3A2FVP1kGQbb3Q415hxx1blpYkBDk6sUg POEgwbj8QMvJ8npOICb2NnHNsAhKRfgGxx/lqVgxLPTDdwGBq7Jr1lfhyX4D99WD C2oLtJWvQrA7yIsDzurMjJpFvw8SYSogppom4lqE5667pm6U0j7JggFJkwIo+VAj jzl706vvB6/EL3PHZ8eCzsxT2oRpxxMStE3lJ1JPpKc60mFb5gkXMk3hura1L8Ez t4NEN9I4ePivXlh6YYDp7Pv5l9JSzKV7Uu8xrYeMdz33e0jUWyoERrdhM51mI4s1 WGoQm6eL6p0jngAUPYtAdIGC6ZGaCMT5rkoDZ4K+us94kVvdqzWjQyRNp84GpQq0 Z/sxJaTSK2DZMnQL3LE19upk7XkB5uBgnjs5T5FcFia7bIDG3p8MY4VwIM4dRum9 WuirEUJRKg28eTTnuK9NQX2+MEnrRWc/FSNaBLjxrijD4C4jHogXTpssNprYnkV7 HgkQ2MaidcnNLftfOUeBr0aTx+rGqtUB56Xas1UK+WqykKVfRdZ6hnbRg30FJvQ/ X4SIc/QZcLcA78C/SvCuXa1uqWqlrZMhN2e5r+eiEXaFYyriWgMYe9w+mXKbrTsb ZPkbax6xz1esqOZ15ytCTneQONyhMXy5iFDfb0khO4DO0uXq4dA= =IN1s -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-4.0-20181221' into staging ppc patch queue 2018-12-21 This pull request supersedes the one from 2018-12-13. This is a revised first ppc pull request for qemu-4.0. Highlights are: * Most of the code for the POWER9 "XIVE" interrupt controller (not complete yet, but we're getting there) * A number of g_new vs. g_malloc cleanups * Some IRQ wiring cleanups * A fix for how we advertise NUMA nodes to the guest for pseries # gpg: Signature made Fri 21 Dec 2018 05:34:12 GMT # gpg: using RSA key 6C38CACA20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" # gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" # Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392 * remotes/dgibson/tags/ppc-for-4.0-20181221: (40 commits) MAINTAINERS: PPC: add a XIVE section spapr: change default CPU type to POWER9 spapr: introduce an 'ic-mode' machine option spapr: add an extra OV5 field to the sPAPR IRQ backend spapr: add a 'reset' method to the sPAPR IRQ backend spapr: extend the sPAPR IRQ backend for XICS migration spapr: allocate the interrupt thread context under the CPU core spapr: add device tree support for the XIVE exploitation mode spapr: add hcalls support for the XIVE exploitation interrupt mode spapr: introduce a new machine IRQ backend for XIVE spapr-iommu: Always advertise the maximum possible DMA window size spapr/xive: use the VCPU id as a NVT identifier spapr/xive: introduce a XIVE interrupt controller ppc/xive: notify the CPU when the interrupt priority is more privileged ppc/xive: introduce a simplified XIVE presenter ppc/xive: introduce the XIVE interrupt thread context ppc/xive: add support for the END Event State Buffers Changes requirement for "vsubsbs" instruction spapr: export and rename the xics_max_server_number() routine spapr: introduce a spapr_irq_init() routine ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
891ff9f4a3
@ -1011,6 +1011,14 @@ F: tests/libqos/*spapr*
|
||||
F: tests/rtas*
|
||||
F: tests/libqos/rtas*
|
||||
|
||||
XIVE
|
||||
M: David Gibson <david@gibson.dropbear.id.au>
|
||||
M: Cédric Le Goater <clg@kaod.org>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Supported
|
||||
F: hw/*/*xive*
|
||||
F: include/hw/*/*xive*
|
||||
|
||||
virtex_ml507
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
L: qemu-ppc@nongnu.org
|
||||
|
@ -16,6 +16,8 @@ CONFIG_VIRTIO_VGA=y
|
||||
CONFIG_XICS=$(CONFIG_PSERIES)
|
||||
CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
|
||||
CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM))
|
||||
CONFIG_XIVE=$(CONFIG_PSERIES)
|
||||
CONFIG_XIVE_SPAPR=$(CONFIG_PSERIES)
|
||||
CONFIG_MEM_DEVICE=y
|
||||
CONFIG_DIMM=y
|
||||
CONFIG_SPAPR_RNG=y
|
||||
|
@ -3734,6 +3734,8 @@ const struct powerpc_opcode powerpc_opcodes[] = {
|
||||
{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPCCOM, { RT, RA } },
|
||||
{ "ameo.", XO(31,234,1,1), XORB_MASK, PWRCOM, { RT, RA } },
|
||||
|
||||
{ "addex", XO(31,170,0,0), XO_MASK, POWER9, { RT, RA, RB } },
|
||||
|
||||
{ "mullw", XO(31,235,0,0), XO_MASK, PPCCOM, { RT, RA, RB } },
|
||||
{ "muls", XO(31,235,0,0), XO_MASK, PWRCOM, { RT, RA, RB } },
|
||||
{ "mullw.", XO(31,235,0,1), XO_MASK, PPCCOM, { RT, RA, RB } },
|
||||
|
@ -37,6 +37,8 @@ obj-$(CONFIG_SH4) += sh_intc.o
|
||||
obj-$(CONFIG_XICS) += xics.o
|
||||
obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o
|
||||
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
|
||||
obj-$(CONFIG_XIVE) += xive.o
|
||||
obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o
|
||||
obj-$(CONFIG_POWERNV) += xics_pnv.o
|
||||
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
|
||||
obj-$(CONFIG_S390_FLIC) += s390_flic.o
|
||||
|
1486
hw/intc/spapr_xive.c
Normal file
1486
hw/intc/spapr_xive.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -244,7 +244,8 @@ void xics_spapr_init(sPAPRMachineState *spapr)
|
||||
spapr_register_hypercall(H_IPOLL, h_ipoll);
|
||||
}
|
||||
|
||||
void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle)
|
||||
void spapr_dt_xics(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
|
||||
uint32_t phandle)
|
||||
{
|
||||
uint32_t interrupt_server_ranges_prop[] = {
|
||||
0, cpu_to_be32(nr_servers),
|
||||
|
1599
hw/intc/xive.c
Normal file
1599
hw/intc/xive.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -685,7 +685,7 @@ static void ppce500_cpu_reset(void *opaque)
|
||||
}
|
||||
|
||||
static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
|
||||
qemu_irq **irqs)
|
||||
IrqLines *irqs)
|
||||
{
|
||||
DeviceState *dev;
|
||||
SysBusDevice *s;
|
||||
@ -705,7 +705,7 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
|
||||
k = 0;
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
|
||||
sysbus_connect_irq(s, k++, irqs[i][j]);
|
||||
sysbus_connect_irq(s, k++, irqs[i].irq[j]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -713,7 +713,7 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
|
||||
}
|
||||
|
||||
static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc,
|
||||
qemu_irq **irqs, Error **errp)
|
||||
IrqLines *irqs, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
DeviceState *dev;
|
||||
@ -742,7 +742,7 @@ static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc,
|
||||
|
||||
static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms,
|
||||
MemoryRegion *ccsr,
|
||||
qemu_irq **irqs)
|
||||
IrqLines *irqs)
|
||||
{
|
||||
MachineState *machine = MACHINE(pms);
|
||||
const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
|
||||
@ -806,15 +806,14 @@ void ppce500_init(MachineState *machine)
|
||||
/* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
|
||||
* 4 respectively */
|
||||
unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
|
||||
qemu_irq **irqs;
|
||||
IrqLines *irqs;
|
||||
DeviceState *dev, *mpicdev;
|
||||
CPUPPCState *firstenv = NULL;
|
||||
MemoryRegion *ccsr_addr_space;
|
||||
SysBusDevice *s;
|
||||
PPCE500CCSRState *ccsr;
|
||||
|
||||
irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
|
||||
irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
|
||||
irqs = g_new0(IrqLines, smp_cpus);
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
PowerPCCPU *cpu;
|
||||
CPUState *cs;
|
||||
@ -834,10 +833,9 @@ void ppce500_init(MachineState *machine)
|
||||
firstenv = env;
|
||||
}
|
||||
|
||||
irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
|
||||
input = (qemu_irq *)env->irq_inputs;
|
||||
irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
|
||||
irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
|
||||
irqs[i].irq[OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
|
||||
irqs[i].irq[OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
|
||||
env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
|
||||
env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0;
|
||||
|
||||
|
@ -115,7 +115,7 @@ static void ppc_core99_init(MachineState *machine)
|
||||
PowerPCCPU *cpu = NULL;
|
||||
CPUPPCState *env = NULL;
|
||||
char *filename;
|
||||
qemu_irq **openpic_irqs;
|
||||
IrqLines *openpic_irqs;
|
||||
int linux_boot, i, j, k;
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1), *bios = g_new(MemoryRegion, 1);
|
||||
hwaddr kernel_base, initrd_base, cmdline_base = 0;
|
||||
@ -248,41 +248,37 @@ static void ppc_core99_init(MachineState *machine)
|
||||
memory_region_add_subregion(get_system_memory(), 0xf8000000,
|
||||
sysbus_mmio_get_region(s, 0));
|
||||
|
||||
openpic_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
|
||||
openpic_irqs[0] =
|
||||
g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
|
||||
openpic_irqs = g_new0(IrqLines, smp_cpus);
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
/* Mac99 IRQ connection between OpenPIC outputs pins
|
||||
* and PowerPC input pins
|
||||
*/
|
||||
switch (PPC_INPUT(env)) {
|
||||
case PPC_FLAGS_INPUT_6xx:
|
||||
openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
|
||||
openpic_irqs[i][OPENPIC_OUTPUT_INT] =
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_INT] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
|
||||
openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_CINT] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
|
||||
openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_MCK] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP];
|
||||
/* Not connected ? */
|
||||
openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_DEBUG] = NULL;
|
||||
/* Check this */
|
||||
openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_RESET] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET];
|
||||
break;
|
||||
#if defined(TARGET_PPC64)
|
||||
case PPC_FLAGS_INPUT_970:
|
||||
openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
|
||||
openpic_irqs[i][OPENPIC_OUTPUT_INT] =
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_INT] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
|
||||
openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_CINT] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
|
||||
openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_MCK] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP];
|
||||
/* Not connected ? */
|
||||
openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_DEBUG] = NULL;
|
||||
/* Check this */
|
||||
openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_RESET] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET];
|
||||
break;
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
@ -299,7 +295,7 @@ static void ppc_core99_init(MachineState *machine)
|
||||
k = 0;
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
|
||||
sysbus_connect_irq(s, k++, openpic_irqs[i][j]);
|
||||
sysbus_connect_irq(s, k++, openpic_irqs[i].irq[j]);
|
||||
}
|
||||
}
|
||||
g_free(openpic_irqs);
|
||||
|
@ -149,7 +149,7 @@ static void ref405ep_init(MachineState *machine)
|
||||
MemoryRegion *bios;
|
||||
MemoryRegion *sram = g_new(MemoryRegion, 1);
|
||||
ram_addr_t bdloc;
|
||||
MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
|
||||
MemoryRegion *ram_memories = g_new(MemoryRegion, 2);
|
||||
hwaddr ram_bases[2], ram_sizes[2];
|
||||
target_ulong sram_size;
|
||||
long bios_size;
|
||||
@ -448,7 +448,7 @@ static void taihu_405ep_init(MachineState *machine)
|
||||
qemu_irq *pic;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *bios;
|
||||
MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
|
||||
MemoryRegion *ram_memories = g_new(MemoryRegion, 2);
|
||||
MemoryRegion *ram = g_malloc0(sizeof(*ram));
|
||||
hwaddr ram_bases[2], ram_sizes[2];
|
||||
long bios_size;
|
||||
|
@ -1519,7 +1519,7 @@ CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
|
||||
/* OBP arbitrer */
|
||||
ppc4xx_opba_init(0xef600600);
|
||||
/* Universal interrupt controller */
|
||||
irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
|
||||
irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
|
||||
irqs[PPCUIC_OUTPUT_INT] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
|
||||
irqs[PPCUIC_OUTPUT_CINT] =
|
||||
@ -1877,7 +1877,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
|
||||
/* Initialize timers */
|
||||
ppc_booke_timers_init(cpu, sysclk, 0);
|
||||
/* Universal interrupt controller */
|
||||
irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
|
||||
irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
|
||||
irqs[PPCUIC_OUTPUT_INT] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
|
||||
irqs[PPCUIC_OUTPUT_CINT] =
|
||||
|
@ -169,8 +169,7 @@ static void bamboo_init(MachineState *machine)
|
||||
unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *isa = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *ram_memories
|
||||
= g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
|
||||
MemoryRegion *ram_memories = g_new(MemoryRegion, PPC440EP_SDRAM_NR_BANKS);
|
||||
hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS];
|
||||
hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS];
|
||||
qemu_irq *pic;
|
||||
@ -200,7 +199,7 @@ static void bamboo_init(MachineState *machine)
|
||||
ppc_dcr_init(env, NULL, NULL);
|
||||
|
||||
/* interrupt controller */
|
||||
irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
|
||||
irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
|
||||
irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
|
||||
irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
|
||||
pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
|
||||
|
@ -430,7 +430,7 @@ static void sam460ex_init(MachineState *machine)
|
||||
ppc4xx_plb_init(env);
|
||||
|
||||
/* interrupt controllers */
|
||||
irqs = g_malloc0(sizeof(*irqs) * PPCUIC_OUTPUT_NB);
|
||||
irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
|
||||
irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
|
||||
irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
|
||||
uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
|
||||
|
121
hw/ppc/spapr.c
121
hw/ppc/spapr.c
@ -150,7 +150,7 @@ static void pre_2_10_vmstate_unregister_dummy_icp(int i)
|
||||
(void *)(uintptr_t) i);
|
||||
}
|
||||
|
||||
static int xics_max_server_number(sPAPRMachineState *spapr)
|
||||
int spapr_max_server_number(sPAPRMachineState *spapr)
|
||||
{
|
||||
assert(spapr->vsmt);
|
||||
return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads);
|
||||
@ -889,8 +889,6 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
|
||||
/* ibm,associativity-lookup-arrays */
|
||||
buf_len = (nr_nodes * 4 + 2) * sizeof(uint32_t);
|
||||
cur_index = int_buf = g_malloc0(buf_len);
|
||||
|
||||
cur_index = int_buf;
|
||||
int_buf[0] = cpu_to_be32(nr_nodes);
|
||||
int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
|
||||
cur_index += 2;
|
||||
@ -1033,7 +1031,7 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
|
||||
cpu_to_be32(0),
|
||||
cpu_to_be32(0),
|
||||
cpu_to_be32(0),
|
||||
cpu_to_be32(nb_numa_nodes ? nb_numa_nodes - 1 : 0),
|
||||
cpu_to_be32(nb_numa_nodes ? nb_numa_nodes : 1),
|
||||
};
|
||||
|
||||
_FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
|
||||
@ -1097,15 +1095,18 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
|
||||
spapr_dt_rtas_tokens(fdt, rtas);
|
||||
}
|
||||
|
||||
/* Prepare ibm,arch-vec-5-platform-support, which indicates the MMU features
|
||||
* that the guest may request and thus the valid values for bytes 24..26 of
|
||||
* option vector 5: */
|
||||
static void spapr_dt_ov5_platform_support(void *fdt, int chosen)
|
||||
/*
|
||||
* Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
|
||||
* and the XIVE features that the guest may request and thus the valid
|
||||
* values for bytes 23..26 of option vector 5:
|
||||
*/
|
||||
static void spapr_dt_ov5_platform_support(sPAPRMachineState *spapr, void *fdt,
|
||||
int chosen)
|
||||
{
|
||||
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
|
||||
|
||||
char val[2 * 4] = {
|
||||
23, 0x00, /* Xive mode, filled in below. */
|
||||
23, spapr->irq->ov5, /* Xive mode. */
|
||||
24, 0x00, /* Hash/Radix, filled in below. */
|
||||
25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
|
||||
26, 0x40, /* Radix options: GTSE == yes. */
|
||||
@ -1113,7 +1114,11 @@ static void spapr_dt_ov5_platform_support(void *fdt, int chosen)
|
||||
|
||||
if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
|
||||
first_ppc_cpu->compat_pvr)) {
|
||||
/* If we're in a pre POWER9 compat mode then the guest should do hash */
|
||||
/*
|
||||
* If we're in a pre POWER9 compat mode then the guest should
|
||||
* do hash and use the legacy interrupt mode
|
||||
*/
|
||||
val[1] = 0x00; /* XICS */
|
||||
val[3] = 0x00; /* Hash */
|
||||
} else if (kvm_enabled()) {
|
||||
if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
|
||||
@ -1191,7 +1196,7 @@ static void spapr_dt_chosen(sPAPRMachineState *spapr, void *fdt)
|
||||
_FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
|
||||
}
|
||||
|
||||
spapr_dt_ov5_platform_support(fdt, chosen);
|
||||
spapr_dt_ov5_platform_support(spapr, fdt, chosen);
|
||||
|
||||
g_free(stdout_path);
|
||||
g_free(bootlist);
|
||||
@ -1270,7 +1275,8 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,
|
||||
_FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
|
||||
|
||||
/* /interrupt controller */
|
||||
spapr_dt_xics(xics_max_server_number(spapr), fdt, PHANDLE_XICP);
|
||||
spapr->irq->dt_populate(spapr, spapr_max_server_number(spapr), fdt,
|
||||
PHANDLE_XICP);
|
||||
|
||||
ret = spapr_populate_memory(spapr, fdt);
|
||||
if (ret < 0) {
|
||||
@ -1290,7 +1296,8 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,
|
||||
}
|
||||
|
||||
QLIST_FOREACH(phb, &spapr->phbs, list) {
|
||||
ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt, smc->irq->nr_msis);
|
||||
ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt,
|
||||
spapr->irq->nr_msis);
|
||||
if (ret < 0) {
|
||||
error_report("couldn't setup PCI devices in fdt");
|
||||
exit(1);
|
||||
@ -1620,6 +1627,12 @@ static void spapr_machine_reset(void)
|
||||
|
||||
qemu_devices_reset();
|
||||
|
||||
/*
|
||||
* This is fixing some of the default configuration of the XIVE
|
||||
* devices. To be called after the reset of the machine devices.
|
||||
*/
|
||||
spapr_irq_reset(spapr, &error_fatal);
|
||||
|
||||
/* DRC reset may cause a device to be unplugged. This will cause troubles
|
||||
* if this device is used by another device (eg, a running vhost backend
|
||||
* will crash QEMU if the DIMM holding the vring goes away). To avoid such
|
||||
@ -1731,14 +1744,6 @@ static int spapr_post_load(void *opaque, int version_id)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!object_dynamic_cast(OBJECT(spapr->ics), TYPE_ICS_KVM)) {
|
||||
CPUState *cs;
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
icp_resend(ICP(cpu->intc));
|
||||
}
|
||||
}
|
||||
|
||||
/* In earlier versions, there was no separate qdev for the PAPR
|
||||
* RTC, so the RTC offset was stored directly in sPAPREnvironment.
|
||||
* So when migrating from those versions, poke the incoming offset
|
||||
@ -1759,6 +1764,11 @@ static int spapr_post_load(void *opaque, int version_id)
|
||||
}
|
||||
}
|
||||
|
||||
err = spapr_irq_post_load(spapr, version_id);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2466,15 +2476,10 @@ static void spapr_init_cpus(sPAPRMachineState *spapr)
|
||||
boot_cores_nr = possible_cpus->len;
|
||||
}
|
||||
|
||||
/* VSMT must be set in order to be able to compute VCPU ids, ie to
|
||||
* call xics_max_server_number() or spapr_vcpu_id().
|
||||
*/
|
||||
spapr_set_vsmt_mode(spapr, &error_fatal);
|
||||
|
||||
if (smc->pre_2_10_has_unused_icps) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < xics_max_server_number(spapr); i++) {
|
||||
for (i = 0; i < spapr_max_server_number(spapr); i++) {
|
||||
/* Dummy entries get deregistered when real ICPState objects
|
||||
* are registered during CPU core hotplug.
|
||||
*/
|
||||
@ -2593,8 +2598,14 @@ static void spapr_machine_init(MachineState *machine)
|
||||
/* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
|
||||
load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
|
||||
|
||||
/*
|
||||
* VSMT must be set in order to be able to compute VCPU ids, ie to
|
||||
* call spapr_max_server_number() or spapr_vcpu_id().
|
||||
*/
|
||||
spapr_set_vsmt_mode(spapr, &error_fatal);
|
||||
|
||||
/* Set up Interrupt Controller before we create the VCPUs */
|
||||
smc->irq->init(spapr, &error_fatal);
|
||||
spapr_irq_init(spapr, &error_fatal);
|
||||
|
||||
/* Set up containers for ibm,client-architecture-support negotiated options
|
||||
*/
|
||||
@ -2621,6 +2632,17 @@ static void spapr_machine_init(MachineState *machine)
|
||||
/* advertise support for ibm,dyamic-memory-v2 */
|
||||
spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
|
||||
|
||||
/* advertise XIVE on POWER9 machines */
|
||||
if (spapr->irq->ov5 & SPAPR_OV5_XIVE_EXPLOIT) {
|
||||
if (ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00,
|
||||
0, spapr->max_compat_pvr)) {
|
||||
spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
|
||||
} else {
|
||||
error_report("XIVE-only machines require a POWER9 CPU");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* init CPUs */
|
||||
spapr_init_cpus(spapr);
|
||||
|
||||
@ -3031,9 +3053,38 @@ static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name,
|
||||
visit_type_uint32(v, name, (uint32_t *)opaque, errp);
|
||||
}
|
||||
|
||||
static char *spapr_get_ic_mode(Object *obj, Error **errp)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
|
||||
|
||||
if (spapr->irq == &spapr_irq_xics_legacy) {
|
||||
return g_strdup("legacy");
|
||||
} else if (spapr->irq == &spapr_irq_xics) {
|
||||
return g_strdup("xics");
|
||||
} else if (spapr->irq == &spapr_irq_xive) {
|
||||
return g_strdup("xive");
|
||||
}
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
|
||||
|
||||
/* The legacy IRQ backend can not be set */
|
||||
if (strcmp(value, "xics") == 0) {
|
||||
spapr->irq = &spapr_irq_xics;
|
||||
} else if (strcmp(value, "xive") == 0) {
|
||||
spapr->irq = &spapr_irq_xive;
|
||||
} else {
|
||||
error_setg(errp, "Bad value for \"ic-mode\" property");
|
||||
}
|
||||
}
|
||||
|
||||
static void spapr_instance_init(Object *obj)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
|
||||
spapr->htab_fd = -1;
|
||||
spapr->use_hotplug_event_source = true;
|
||||
@ -3067,6 +3118,14 @@ static void spapr_instance_init(Object *obj)
|
||||
" the host's SMT mode", &error_abort);
|
||||
object_property_add_bool(obj, "vfio-no-msix-emulation",
|
||||
spapr_get_msix_emulation, NULL, NULL);
|
||||
|
||||
/* The machine class defines the default interrupt controller mode */
|
||||
spapr->irq = smc->irq;
|
||||
object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
|
||||
spapr_set_ic_mode, NULL);
|
||||
object_property_set_description(obj, "ic-mode",
|
||||
"Specifies the interrupt controller mode (xics, xive)",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void spapr_machine_finalizefn(Object *obj)
|
||||
@ -3789,9 +3848,8 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj,
|
||||
Monitor *mon)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
|
||||
smc->irq->print_info(spapr, mon);
|
||||
spapr->irq->print_info(spapr, mon);
|
||||
}
|
||||
|
||||
int spapr_get_vcpu_id(PowerPCCPU *cpu)
|
||||
@ -3873,7 +3931,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
hc->unplug = spapr_machine_device_unplug;
|
||||
|
||||
smc->dr_lmb_enabled = true;
|
||||
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
|
||||
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
|
||||
mc->has_hotpluggable_cpus = true;
|
||||
smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
|
||||
fwc->get_dev_path = spapr_get_fw_dev_path;
|
||||
@ -3970,6 +4028,7 @@ static void spapr_machine_3_1_class_options(MachineClass *mc)
|
||||
{
|
||||
spapr_machine_4_0_class_options(mc);
|
||||
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_3_1);
|
||||
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "hw/ppc/spapr_cpu_core.h"
|
||||
#include "target/ppc/cpu.h"
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/xics.h" /* for icp_create() - to be removed */
|
||||
#include "hw/boards.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/cpus.h"
|
||||
@ -233,8 +232,7 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
qemu_register_reset(spapr_cpu_reset, cpu);
|
||||
spapr_cpu_reset(cpu);
|
||||
|
||||
cpu->intc = icp_create(OBJECT(cpu), spapr->icp_type, XICS_FABRIC(spapr),
|
||||
&local_err);
|
||||
cpu->intc = spapr->irq->cpu_intc_create(spapr, OBJECT(cpu), &local_err);
|
||||
if (local_err) {
|
||||
goto error_unregister;
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ static uint64_t *spapr_tce_alloc_table(uint32_t liobn,
|
||||
|
||||
if (!table) {
|
||||
*fd = -1;
|
||||
table = g_malloc0(nb_table * sizeof(uint64_t));
|
||||
table = g_new0(uint64_t, nb_table);
|
||||
}
|
||||
|
||||
trace_spapr_iommu_new_table(liobn, table, *fd);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/spapr_xive.h"
|
||||
#include "hw/ppc/xics.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
@ -93,15 +94,9 @@ error:
|
||||
static void spapr_irq_init_xics(sPAPRMachineState *spapr, Error **errp)
|
||||
{
|
||||
MachineState *machine = MACHINE(spapr);
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
int nr_irqs = smc->irq->nr_irqs;
|
||||
int nr_irqs = spapr->irq->nr_irqs;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/* Initialize the MSI IRQ allocator. */
|
||||
if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
|
||||
spapr_irq_msi_init(spapr, smc->irq->nr_msis);
|
||||
}
|
||||
|
||||
if (kvm_enabled()) {
|
||||
if (machine_kernel_irqchip_allowed(machine) &&
|
||||
!xics_kvm_init(spapr, &local_err)) {
|
||||
@ -195,6 +190,24 @@ static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon)
|
||||
ics_pic_print_info(spapr->ics, mon);
|
||||
}
|
||||
|
||||
static Object *spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr,
|
||||
Object *cpu, Error **errp)
|
||||
{
|
||||
return icp_create(cpu, spapr->icp_type, XICS_FABRIC(spapr), errp);
|
||||
}
|
||||
|
||||
static int spapr_irq_post_load_xics(sPAPRMachineState *spapr, int version_id)
|
||||
{
|
||||
if (!object_dynamic_cast(OBJECT(spapr->ics), TYPE_ICS_KVM)) {
|
||||
CPUState *cs;
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
icp_resend(ICP(cpu->intc));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SPAPR_IRQ_XICS_NR_IRQS 0x1000
|
||||
#define SPAPR_IRQ_XICS_NR_MSIS \
|
||||
(XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI)
|
||||
@ -202,37 +215,184 @@ static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon)
|
||||
sPAPRIrq spapr_irq_xics = {
|
||||
.nr_irqs = SPAPR_IRQ_XICS_NR_IRQS,
|
||||
.nr_msis = SPAPR_IRQ_XICS_NR_MSIS,
|
||||
.ov5 = SPAPR_OV5_XIVE_LEGACY,
|
||||
|
||||
.init = spapr_irq_init_xics,
|
||||
.claim = spapr_irq_claim_xics,
|
||||
.free = spapr_irq_free_xics,
|
||||
.qirq = spapr_qirq_xics,
|
||||
.print_info = spapr_irq_print_info_xics,
|
||||
.dt_populate = spapr_dt_xics,
|
||||
.cpu_intc_create = spapr_irq_cpu_intc_create_xics,
|
||||
.post_load = spapr_irq_post_load_xics,
|
||||
};
|
||||
|
||||
/*
|
||||
* XIVE IRQ backend.
|
||||
*/
|
||||
static void spapr_irq_init_xive(sPAPRMachineState *spapr, Error **errp)
|
||||
{
|
||||
MachineState *machine = MACHINE(spapr);
|
||||
uint32_t nr_servers = spapr_max_server_number(spapr);
|
||||
DeviceState *dev;
|
||||
int i;
|
||||
|
||||
/* KVM XIVE device not yet available */
|
||||
if (kvm_enabled()) {
|
||||
if (machine_kernel_irqchip_required(machine)) {
|
||||
error_setg(errp, "kernel_irqchip requested. no KVM XIVE support");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dev = qdev_create(NULL, TYPE_SPAPR_XIVE);
|
||||
qdev_prop_set_uint32(dev, "nr-irqs", spapr->irq->nr_irqs);
|
||||
/*
|
||||
* 8 XIVE END structures per CPU. One for each available priority
|
||||
*/
|
||||
qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
spapr->xive = SPAPR_XIVE(dev);
|
||||
|
||||
/* Enable the CPU IPIs */
|
||||
for (i = 0; i < nr_servers; ++i) {
|
||||
spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, false);
|
||||
}
|
||||
|
||||
spapr_xive_hcall_init(spapr);
|
||||
}
|
||||
|
||||
static int spapr_irq_claim_xive(sPAPRMachineState *spapr, int irq, bool lsi,
|
||||
Error **errp)
|
||||
{
|
||||
if (!spapr_xive_irq_claim(spapr->xive, irq, lsi)) {
|
||||
error_setg(errp, "IRQ %d is invalid", irq);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spapr_irq_free_xive(sPAPRMachineState *spapr, int irq, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = irq; i < irq + num; ++i) {
|
||||
spapr_xive_irq_free(spapr->xive, i);
|
||||
}
|
||||
}
|
||||
|
||||
static qemu_irq spapr_qirq_xive(sPAPRMachineState *spapr, int irq)
|
||||
{
|
||||
return spapr_xive_qirq(spapr->xive, irq);
|
||||
}
|
||||
|
||||
static void spapr_irq_print_info_xive(sPAPRMachineState *spapr,
|
||||
Monitor *mon)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
|
||||
xive_tctx_pic_print_info(XIVE_TCTX(cpu->intc), mon);
|
||||
}
|
||||
|
||||
spapr_xive_pic_print_info(spapr->xive, mon);
|
||||
}
|
||||
|
||||
static Object *spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr,
|
||||
Object *cpu, Error **errp)
|
||||
{
|
||||
Object *obj = xive_tctx_create(cpu, XIVE_ROUTER(spapr->xive), errp);
|
||||
|
||||
/*
|
||||
* (TCG) Early setting the OS CAM line for hotplugged CPUs as they
|
||||
* don't benificiate from the reset of the XIVE IRQ backend
|
||||
*/
|
||||
spapr_xive_set_tctx_os_cam(XIVE_TCTX(obj));
|
||||
return obj;
|
||||
}
|
||||
|
||||
static int spapr_irq_post_load_xive(sPAPRMachineState *spapr, int version_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spapr_irq_reset_xive(sPAPRMachineState *spapr, Error **errp)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
|
||||
/* (TCG) Set the OS CAM line of the thread interrupt context. */
|
||||
spapr_xive_set_tctx_os_cam(XIVE_TCTX(cpu->intc));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* XIVE uses the full IRQ number space. Set it to 8K to be compatible
|
||||
* with XICS.
|
||||
*/
|
||||
|
||||
#define SPAPR_IRQ_XIVE_NR_IRQS 0x2000
|
||||
#define SPAPR_IRQ_XIVE_NR_MSIS (SPAPR_IRQ_XIVE_NR_IRQS - SPAPR_IRQ_MSI)
|
||||
|
||||
sPAPRIrq spapr_irq_xive = {
|
||||
.nr_irqs = SPAPR_IRQ_XIVE_NR_IRQS,
|
||||
.nr_msis = SPAPR_IRQ_XIVE_NR_MSIS,
|
||||
.ov5 = SPAPR_OV5_XIVE_EXPLOIT,
|
||||
|
||||
.init = spapr_irq_init_xive,
|
||||
.claim = spapr_irq_claim_xive,
|
||||
.free = spapr_irq_free_xive,
|
||||
.qirq = spapr_qirq_xive,
|
||||
.print_info = spapr_irq_print_info_xive,
|
||||
.dt_populate = spapr_dt_xive,
|
||||
.cpu_intc_create = spapr_irq_cpu_intc_create_xive,
|
||||
.post_load = spapr_irq_post_load_xive,
|
||||
.reset = spapr_irq_reset_xive,
|
||||
};
|
||||
|
||||
/*
|
||||
* sPAPR IRQ frontend routines for devices
|
||||
*/
|
||||
void spapr_irq_init(sPAPRMachineState *spapr, Error **errp)
|
||||
{
|
||||
/* Initialize the MSI IRQ allocator. */
|
||||
if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
|
||||
spapr_irq_msi_init(spapr, spapr->irq->nr_msis);
|
||||
}
|
||||
|
||||
spapr->irq->init(spapr, errp);
|
||||
}
|
||||
|
||||
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp)
|
||||
{
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
|
||||
return smc->irq->claim(spapr, irq, lsi, errp);
|
||||
return spapr->irq->claim(spapr, irq, lsi, errp);
|
||||
}
|
||||
|
||||
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num)
|
||||
{
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
|
||||
smc->irq->free(spapr, irq, num);
|
||||
spapr->irq->free(spapr, irq, num);
|
||||
}
|
||||
|
||||
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq)
|
||||
{
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
return spapr->irq->qirq(spapr, irq);
|
||||
}
|
||||
|
||||
return smc->irq->qirq(spapr, irq);
|
||||
int spapr_irq_post_load(sPAPRMachineState *spapr, int version_id)
|
||||
{
|
||||
return spapr->irq->post_load(spapr, version_id);
|
||||
}
|
||||
|
||||
void spapr_irq_reset(sPAPRMachineState *spapr, Error **errp)
|
||||
{
|
||||
if (spapr->irq->reset) {
|
||||
spapr->irq->reset(spapr, errp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -295,10 +455,14 @@ int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp)
|
||||
sPAPRIrq spapr_irq_xics_legacy = {
|
||||
.nr_irqs = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
|
||||
.nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
|
||||
.ov5 = SPAPR_OV5_XIVE_LEGACY,
|
||||
|
||||
.init = spapr_irq_init_xics,
|
||||
.claim = spapr_irq_claim_xics,
|
||||
.free = spapr_irq_free_xics,
|
||||
.qirq = spapr_qirq_xics,
|
||||
.print_info = spapr_irq_print_info_xics,
|
||||
.dt_populate = spapr_dt_xics,
|
||||
.cpu_intc_create = spapr_irq_cpu_intc_create_xics,
|
||||
.post_load = spapr_irq_post_load_xics,
|
||||
};
|
||||
|
@ -96,9 +96,8 @@ static void rtas_ibm_query_pe_dma_window(PowerPCCPU *cpu,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
sPAPRPHBState *sphb;
|
||||
uint64_t buid, max_window_size;
|
||||
uint64_t buid;
|
||||
uint32_t avail, addr, pgmask = 0;
|
||||
MachineState *machine = MACHINE(spapr);
|
||||
|
||||
if ((nargs != 3) || (nret != 5)) {
|
||||
goto param_error_exit;
|
||||
@ -114,27 +113,15 @@ static void rtas_ibm_query_pe_dma_window(PowerPCCPU *cpu,
|
||||
/* Translate page mask to LoPAPR format */
|
||||
pgmask = spapr_page_mask_to_query_mask(sphb->page_size_mask);
|
||||
|
||||
/*
|
||||
* This is "Largest contiguous block of TCEs allocated specifically
|
||||
* for (that is, are reserved for) this PE".
|
||||
* Return the maximum number as maximum supported RAM size was in 4K pages.
|
||||
*/
|
||||
if (machine->ram_size == machine->maxram_size) {
|
||||
max_window_size = machine->ram_size;
|
||||
} else {
|
||||
max_window_size = machine->device_memory->base +
|
||||
memory_region_size(&machine->device_memory->mr);
|
||||
}
|
||||
|
||||
avail = SPAPR_PCI_DMA_MAX_WINDOWS - spapr_phb_get_active_win_num(sphb);
|
||||
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
rtas_st(rets, 1, avail);
|
||||
rtas_st(rets, 2, max_window_size >> SPAPR_TCE_PAGE_SHIFT);
|
||||
rtas_st(rets, 2, 0x80000000); /* The largest window we can possibly have */
|
||||
rtas_st(rets, 3, pgmask);
|
||||
rtas_st(rets, 4, 0); /* DMA migration mask, not supported */
|
||||
|
||||
trace_spapr_iommu_ddw_query(buid, addr, avail, max_window_size, pgmask);
|
||||
trace_spapr_iommu_ddw_query(buid, addr, avail, 0x80000000, pgmask);
|
||||
return;
|
||||
|
||||
param_error_exit:
|
||||
|
@ -730,7 +730,7 @@ void spapr_dt_vdevice(VIOsPAPRBus *bus, void *fdt)
|
||||
}
|
||||
|
||||
/* Copy out into an array of pointers */
|
||||
qdevs = g_malloc(sizeof(qdev) * num);
|
||||
qdevs = g_new(DeviceState *, num);
|
||||
num = 0;
|
||||
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
|
||||
qdevs[num++] = kid->child;
|
||||
|
@ -105,7 +105,7 @@ static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size,
|
||||
ppc_dcr_init(env, NULL, NULL);
|
||||
|
||||
/* interrupt controller */
|
||||
irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
|
||||
irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
|
||||
irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
|
||||
irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
|
||||
ppcuic_init(env, irqs, 0x0C0, 0, 1);
|
||||
|
@ -20,6 +20,8 @@ enum {
|
||||
OPENPIC_OUTPUT_NB,
|
||||
};
|
||||
|
||||
typedef struct IrqLines { qemu_irq irq[OPENPIC_OUTPUT_NB]; } IrqLines;
|
||||
|
||||
#define OPENPIC_MODEL_RAVEN 0
|
||||
#define OPENPIC_MODEL_FSL_MPIC_20 1
|
||||
#define OPENPIC_MODEL_FSL_MPIC_42 2
|
||||
|
@ -16,6 +16,7 @@ typedef struct sPAPREventLogEntry sPAPREventLogEntry;
|
||||
typedef struct sPAPREventSource sPAPREventSource;
|
||||
typedef struct sPAPRPendingHPT sPAPRPendingHPT;
|
||||
typedef struct ICSState ICSState;
|
||||
typedef struct sPAPRXive sPAPRXive;
|
||||
|
||||
#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL
|
||||
#define SPAPR_ENTRY_POINT 0x100
|
||||
@ -175,6 +176,8 @@ struct sPAPRMachineState {
|
||||
const char *icp_type;
|
||||
int32_t irq_map_nr;
|
||||
unsigned long *irq_map;
|
||||
sPAPRXive *xive;
|
||||
sPAPRIrq *irq;
|
||||
|
||||
bool cmd_line_caps[SPAPR_CAP_NUM];
|
||||
sPAPRCapabilities def, eff, mig;
|
||||
@ -450,7 +453,20 @@ struct sPAPRMachineState {
|
||||
#define H_INVALIDATE_PID 0x378
|
||||
#define H_REGISTER_PROC_TBL 0x37C
|
||||
#define H_SIGNAL_SYS_RESET 0x380
|
||||
#define MAX_HCALL_OPCODE H_SIGNAL_SYS_RESET
|
||||
|
||||
#define H_INT_GET_SOURCE_INFO 0x3A8
|
||||
#define H_INT_SET_SOURCE_CONFIG 0x3AC
|
||||
#define H_INT_GET_SOURCE_CONFIG 0x3B0
|
||||
#define H_INT_GET_QUEUE_INFO 0x3B4
|
||||
#define H_INT_SET_QUEUE_CONFIG 0x3B8
|
||||
#define H_INT_GET_QUEUE_CONFIG 0x3BC
|
||||
#define H_INT_SET_OS_REPORTING_LINE 0x3C0
|
||||
#define H_INT_GET_OS_REPORTING_LINE 0x3C4
|
||||
#define H_INT_ESB 0x3C8
|
||||
#define H_INT_SYNC 0x3CC
|
||||
#define H_INT_RESET 0x3D0
|
||||
|
||||
#define MAX_HCALL_OPCODE H_INT_RESET
|
||||
|
||||
/* The hcalls above are standardized in PAPR and implemented by pHyp
|
||||
* as well.
|
||||
@ -737,6 +753,7 @@ int spapr_hpt_shift_for_ramsize(uint64_t ramsize);
|
||||
void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
|
||||
Error **errp);
|
||||
void spapr_clear_pending_events(sPAPRMachineState *spapr);
|
||||
int spapr_max_server_number(sPAPRMachineState *spapr);
|
||||
|
||||
/* CPU and LMB DRC release callbacks. */
|
||||
void spapr_core_release(DeviceState *dev);
|
||||
@ -808,5 +825,11 @@ int spapr_caps_post_migration(sPAPRMachineState *spapr);
|
||||
|
||||
void spapr_check_pagesize(sPAPRMachineState *spapr, hwaddr pagesize,
|
||||
Error **errp);
|
||||
/*
|
||||
* XIVE definitions
|
||||
*/
|
||||
#define SPAPR_OV5_XIVE_LEGACY 0x0
|
||||
#define SPAPR_OV5_XIVE_EXPLOIT 0x40
|
||||
#define SPAPR_OV5_XIVE_BOTH 0x80 /* Only to advertise on the platform */
|
||||
|
||||
#endif /* HW_SPAPR_H */
|
||||
|
@ -13,6 +13,7 @@
|
||||
/*
|
||||
* IRQ range offsets per device type
|
||||
*/
|
||||
#define SPAPR_IRQ_IPI 0x0
|
||||
#define SPAPR_IRQ_EPOW 0x1000 /* XICS_IRQ_BASE offset */
|
||||
#define SPAPR_IRQ_HOTPLUG 0x1001
|
||||
#define SPAPR_IRQ_VIO 0x1100 /* 256 VIO devices */
|
||||
@ -32,20 +33,31 @@ void spapr_irq_msi_reset(sPAPRMachineState *spapr);
|
||||
typedef struct sPAPRIrq {
|
||||
uint32_t nr_irqs;
|
||||
uint32_t nr_msis;
|
||||
uint8_t ov5;
|
||||
|
||||
void (*init)(sPAPRMachineState *spapr, Error **errp);
|
||||
int (*claim)(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
|
||||
void (*free)(sPAPRMachineState *spapr, int irq, int num);
|
||||
qemu_irq (*qirq)(sPAPRMachineState *spapr, int irq);
|
||||
void (*print_info)(sPAPRMachineState *spapr, Monitor *mon);
|
||||
void (*dt_populate)(sPAPRMachineState *spapr, uint32_t nr_servers,
|
||||
void *fdt, uint32_t phandle);
|
||||
Object *(*cpu_intc_create)(sPAPRMachineState *spapr, Object *cpu,
|
||||
Error **errp);
|
||||
int (*post_load)(sPAPRMachineState *spapr, int version_id);
|
||||
void (*reset)(sPAPRMachineState *spapr, Error **errp);
|
||||
} sPAPRIrq;
|
||||
|
||||
extern sPAPRIrq spapr_irq_xics;
|
||||
extern sPAPRIrq spapr_irq_xics_legacy;
|
||||
extern sPAPRIrq spapr_irq_xive;
|
||||
|
||||
void spapr_irq_init(sPAPRMachineState *spapr, Error **errp);
|
||||
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
|
||||
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num);
|
||||
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq);
|
||||
int spapr_irq_post_load(sPAPRMachineState *spapr, int version_id);
|
||||
void spapr_irq_reset(sPAPRMachineState *spapr, Error **errp);
|
||||
|
||||
/*
|
||||
* XICS legacy routines
|
||||
|
52
include/hw/ppc/spapr_xive.h
Normal file
52
include/hw/ppc/spapr_xive.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* QEMU PowerPC sPAPR XIVE interrupt controller model
|
||||
*
|
||||
* Copyright (c) 2017-2018, IBM Corporation.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See the
|
||||
* COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef PPC_SPAPR_XIVE_H
|
||||
#define PPC_SPAPR_XIVE_H
|
||||
|
||||
#include "hw/ppc/xive.h"
|
||||
|
||||
#define TYPE_SPAPR_XIVE "spapr-xive"
|
||||
#define SPAPR_XIVE(obj) OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE)
|
||||
|
||||
typedef struct sPAPRXive {
|
||||
XiveRouter parent;
|
||||
|
||||
/* Internal interrupt source for IPIs and virtual devices */
|
||||
XiveSource source;
|
||||
hwaddr vc_base;
|
||||
|
||||
/* END ESB MMIOs */
|
||||
XiveENDSource end_source;
|
||||
hwaddr end_base;
|
||||
|
||||
/* Routing table */
|
||||
XiveEAS *eat;
|
||||
uint32_t nr_irqs;
|
||||
XiveEND *endt;
|
||||
uint32_t nr_ends;
|
||||
|
||||
/* TIMA mapping address */
|
||||
hwaddr tm_base;
|
||||
MemoryRegion tm_mmio;
|
||||
} sPAPRXive;
|
||||
|
||||
bool spapr_xive_irq_claim(sPAPRXive *xive, uint32_t lisn, bool lsi);
|
||||
bool spapr_xive_irq_free(sPAPRXive *xive, uint32_t lisn);
|
||||
void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon);
|
||||
qemu_irq spapr_xive_qirq(sPAPRXive *xive, uint32_t lisn);
|
||||
|
||||
typedef struct sPAPRMachineState sPAPRMachineState;
|
||||
|
||||
void spapr_xive_hcall_init(sPAPRMachineState *spapr);
|
||||
void spapr_dt_xive(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
|
||||
uint32_t phandle);
|
||||
void spapr_xive_set_tctx_os_cam(XiveTCTX *tctx);
|
||||
|
||||
#endif /* PPC_SPAPR_XIVE_H */
|
@ -181,8 +181,6 @@ typedef struct XICSFabricClass {
|
||||
ICPState *(*icp_get)(XICSFabric *xi, int server);
|
||||
} XICSFabricClass;
|
||||
|
||||
void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle);
|
||||
|
||||
ICPState *xics_icp_get(XICSFabric *xi, int server);
|
||||
|
||||
/* Internal XICS interfaces */
|
||||
@ -204,6 +202,8 @@ void icp_resend(ICPState *ss);
|
||||
|
||||
typedef struct sPAPRMachineState sPAPRMachineState;
|
||||
|
||||
void spapr_dt_xics(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
|
||||
uint32_t phandle);
|
||||
int xics_kvm_init(sPAPRMachineState *spapr, Error **errp);
|
||||
void xics_spapr_init(sPAPRMachineState *spapr);
|
||||
|
||||
|
429
include/hw/ppc/xive.h
Normal file
429
include/hw/ppc/xive.h
Normal file
@ -0,0 +1,429 @@
|
||||
/*
|
||||
* QEMU PowerPC XIVE interrupt controller model
|
||||
*
|
||||
*
|
||||
* The POWER9 processor comes with a new interrupt controller, called
|
||||
* XIVE as "eXternal Interrupt Virtualization Engine".
|
||||
*
|
||||
* = Overall architecture
|
||||
*
|
||||
*
|
||||
* XIVE Interrupt Controller
|
||||
* +------------------------------------+ IPIs
|
||||
* | +---------+ +---------+ +--------+ | +-------+
|
||||
* | |VC | |CQ | |PC |----> | CORES |
|
||||
* | | esb | | | | |----> | |
|
||||
* | | eas | | Bridge | | tctx |----> | |
|
||||
* | |SC end | | | | nvt | | | |
|
||||
* +------+ | +---------+ +----+----+ +--------+ | +-+-+-+-+
|
||||
* | RAM | +------------------|-----------------+ | | |
|
||||
* | | | | | |
|
||||
* | | | | | |
|
||||
* | | +--------------------v------------------------v-v-v--+ other
|
||||
* | <--+ Power Bus +--> chips
|
||||
* | esb | +---------+-----------------------+------------------+
|
||||
* | eas | | |
|
||||
* | end | +--|------+ |
|
||||
* | nvt | +----+----+ | +----+----+
|
||||
* +------+ |SC | | |SC |
|
||||
* | | | | |
|
||||
* | PQ-bits | | | PQ-bits |
|
||||
* | local |-+ | in VC |
|
||||
* +---------+ +---------+
|
||||
* PCIe NX,NPU,CAPI
|
||||
*
|
||||
* SC: Source Controller (aka. IVSE)
|
||||
* VC: Virtualization Controller (aka. IVRE)
|
||||
* PC: Presentation Controller (aka. IVPE)
|
||||
* CQ: Common Queue (Bridge)
|
||||
*
|
||||
* PQ-bits: 2 bits source state machine (P:pending Q:queued)
|
||||
* esb: Event State Buffer (Array of PQ bits in an IVSE)
|
||||
* eas: Event Assignment Structure
|
||||
* end: Event Notification Descriptor
|
||||
* nvt: Notification Virtual Target
|
||||
* tctx: Thread interrupt Context
|
||||
*
|
||||
*
|
||||
* The XIVE IC is composed of three sub-engines :
|
||||
*
|
||||
* - Interrupt Virtualization Source Engine (IVSE), or Source
|
||||
* Controller (SC). These are found in PCI PHBs, in the PSI host
|
||||
* bridge controller, but also inside the main controller for the
|
||||
* core IPIs and other sub-chips (NX, CAP, NPU) of the
|
||||
* chip/processor. They are configured to feed the IVRE with events.
|
||||
*
|
||||
* - Interrupt Virtualization Routing Engine (IVRE) or Virtualization
|
||||
* Controller (VC). Its job is to match an event source with an
|
||||
* Event Notification Descriptor (END).
|
||||
*
|
||||
* - Interrupt Virtualization Presentation Engine (IVPE) or
|
||||
* Presentation Controller (PC). It maintains the interrupt context
|
||||
* state of each thread and handles the delivery of the external
|
||||
* exception to the thread.
|
||||
*
|
||||
* In XIVE 1.0, the sub-engines used to be referred as:
|
||||
*
|
||||
* SC Source Controller
|
||||
* VC Virtualization Controller
|
||||
* PC Presentation Controller
|
||||
* CQ Common Queue (PowerBUS Bridge)
|
||||
*
|
||||
*
|
||||
* = XIVE internal tables
|
||||
*
|
||||
* Each of the sub-engines uses a set of tables to redirect exceptions
|
||||
* from event sources to CPU threads.
|
||||
*
|
||||
* +-------+
|
||||
* User or OS | EQ |
|
||||
* or +------>|entries|
|
||||
* Hypervisor | | .. |
|
||||
* Memory | +-------+
|
||||
* | ^
|
||||
* | |
|
||||
* +-------------------------------------------------+
|
||||
* | |
|
||||
* Hypervisor +------+ +---+--+ +---+--+ +------+
|
||||
* Memory | ESB | | EAT | | ENDT | | NVTT |
|
||||
* (skiboot) +----+-+ +----+-+ +----+-+ +------+
|
||||
* ^ | ^ | ^ | ^
|
||||
* | | | | | | |
|
||||
* +-------------------------------------------------+
|
||||
* | | | | | | |
|
||||
* | | | | | | |
|
||||
* +----|--|--------|--|--------|--|-+ +-|-----+ +------+
|
||||
* | | | | | | | | | | tctx| |Thread|
|
||||
* IPI or --> | + v + v + v |---| + .. |-----> |
|
||||
* HW events --> | | | | | |
|
||||
* IVSE | IVRE | | IVPE | +------+
|
||||
* +---------------------------------+ +-------+
|
||||
*
|
||||
*
|
||||
*
|
||||
* The IVSE have a 2-bits state machine, P for pending and Q for queued,
|
||||
* for each source that allows events to be triggered. They are stored in
|
||||
* an Event State Buffer (ESB) array and can be controlled by MMIOs.
|
||||
*
|
||||
* If the event is let through, the IVRE looks up in the Event Assignment
|
||||
* Structure (EAS) table for an Event Notification Descriptor (END)
|
||||
* configured for the source. Each Event Notification Descriptor defines
|
||||
* a notification path to a CPU and an in-memory Event Queue, in which
|
||||
* will be enqueued an EQ data for the OS to pull.
|
||||
*
|
||||
* The IVPE determines if a Notification Virtual Target (NVT) can
|
||||
* handle the event by scanning the thread contexts of the VCPUs
|
||||
* dispatched on the processor HW threads. It maintains the state of
|
||||
* the thread interrupt context (TCTX) of each thread in a NVT table.
|
||||
*
|
||||
* = Acronyms
|
||||
*
|
||||
* Description In XIVE 1.0, used to be referred as
|
||||
*
|
||||
* EAS Event Assignment Structure IVE Interrupt Virt. Entry
|
||||
* EAT Event Assignment Table IVT Interrupt Virt. Table
|
||||
* ENDT Event Notif. Descriptor Table EQDT Event Queue Desc. Table
|
||||
* EQ Event Queue same
|
||||
* ESB Event State Buffer SBE State Bit Entry
|
||||
* NVT Notif. Virtual Target VPD Virtual Processor Desc.
|
||||
* NVTT Notif. Virtual Target Table VPDT Virtual Processor Desc. Table
|
||||
* TCTX Thread interrupt Context
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2018, IBM Corporation.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See the
|
||||
* COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PPC_XIVE_H
|
||||
#define PPC_XIVE_H
|
||||
|
||||
#include "hw/qdev-core.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ppc/xive_regs.h"
|
||||
|
||||
/*
|
||||
* XIVE Fabric (Interface between Source and Router)
|
||||
*/
|
||||
|
||||
typedef struct XiveNotifier {
|
||||
Object parent;
|
||||
} XiveNotifier;
|
||||
|
||||
#define TYPE_XIVE_NOTIFIER "xive-notifier"
|
||||
#define XIVE_NOTIFIER(obj) \
|
||||
OBJECT_CHECK(XiveNotifier, (obj), TYPE_XIVE_NOTIFIER)
|
||||
#define XIVE_NOTIFIER_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(XiveNotifierClass, (klass), TYPE_XIVE_NOTIFIER)
|
||||
#define XIVE_NOTIFIER_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(XiveNotifierClass, (obj), TYPE_XIVE_NOTIFIER)
|
||||
|
||||
typedef struct XiveNotifierClass {
|
||||
InterfaceClass parent;
|
||||
void (*notify)(XiveNotifier *xn, uint32_t lisn);
|
||||
} XiveNotifierClass;
|
||||
|
||||
/*
|
||||
* XIVE Interrupt Source
|
||||
*/
|
||||
|
||||
#define TYPE_XIVE_SOURCE "xive-source"
|
||||
#define XIVE_SOURCE(obj) OBJECT_CHECK(XiveSource, (obj), TYPE_XIVE_SOURCE)
|
||||
|
||||
/*
|
||||
* XIVE Interrupt Source characteristics, which define how the ESB are
|
||||
* controlled.
|
||||
*/
|
||||
#define XIVE_SRC_H_INT_ESB 0x1 /* ESB managed with hcall H_INT_ESB */
|
||||
#define XIVE_SRC_STORE_EOI 0x2 /* Store EOI supported */
|
||||
|
||||
typedef struct XiveSource {
|
||||
DeviceState parent;
|
||||
|
||||
/* IRQs */
|
||||
uint32_t nr_irqs;
|
||||
qemu_irq *qirqs;
|
||||
unsigned long *lsi_map;
|
||||
|
||||
/* PQ bits and LSI assertion bit */
|
||||
uint8_t *status;
|
||||
|
||||
/* ESB memory region */
|
||||
uint64_t esb_flags;
|
||||
uint32_t esb_shift;
|
||||
MemoryRegion esb_mmio;
|
||||
|
||||
XiveNotifier *xive;
|
||||
} XiveSource;
|
||||
|
||||
/*
|
||||
* ESB MMIO setting. Can be one page, for both source triggering and
|
||||
* source management, or two different pages. See below for magic
|
||||
* values.
|
||||
*/
|
||||
#define XIVE_ESB_4K 12 /* PSI HB only */
|
||||
#define XIVE_ESB_4K_2PAGE 13
|
||||
#define XIVE_ESB_64K 16
|
||||
#define XIVE_ESB_64K_2PAGE 17
|
||||
|
||||
static inline bool xive_source_esb_has_2page(XiveSource *xsrc)
|
||||
{
|
||||
return xsrc->esb_shift == XIVE_ESB_64K_2PAGE ||
|
||||
xsrc->esb_shift == XIVE_ESB_4K_2PAGE;
|
||||
}
|
||||
|
||||
/* The trigger page is always the first/even page */
|
||||
static inline hwaddr xive_source_esb_page(XiveSource *xsrc, uint32_t srcno)
|
||||
{
|
||||
assert(srcno < xsrc->nr_irqs);
|
||||
return (1ull << xsrc->esb_shift) * srcno;
|
||||
}
|
||||
|
||||
/* In a two pages ESB MMIO setting, the odd page is for management */
|
||||
static inline hwaddr xive_source_esb_mgmt(XiveSource *xsrc, int srcno)
|
||||
{
|
||||
hwaddr addr = xive_source_esb_page(xsrc, srcno);
|
||||
|
||||
if (xive_source_esb_has_2page(xsrc)) {
|
||||
addr += (1 << (xsrc->esb_shift - 1));
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Each interrupt source has a 2-bit state machine which can be
|
||||
* controlled by MMIO. P indicates that an interrupt is pending (has
|
||||
* been sent to a queue and is waiting for an EOI). Q indicates that
|
||||
* the interrupt has been triggered while pending.
|
||||
*
|
||||
* This acts as a coalescing mechanism in order to guarantee that a
|
||||
* given interrupt only occurs at most once in a queue.
|
||||
*
|
||||
* When doing an EOI, the Q bit will indicate if the interrupt
|
||||
* needs to be re-triggered.
|
||||
*/
|
||||
#define XIVE_STATUS_ASSERTED 0x4 /* Extra bit for LSI */
|
||||
#define XIVE_ESB_VAL_P 0x2
|
||||
#define XIVE_ESB_VAL_Q 0x1
|
||||
|
||||
#define XIVE_ESB_RESET 0x0
|
||||
#define XIVE_ESB_PENDING XIVE_ESB_VAL_P
|
||||
#define XIVE_ESB_QUEUED (XIVE_ESB_VAL_P | XIVE_ESB_VAL_Q)
|
||||
#define XIVE_ESB_OFF XIVE_ESB_VAL_Q
|
||||
|
||||
/*
|
||||
* "magic" Event State Buffer (ESB) MMIO offsets.
|
||||
*
|
||||
* The following offsets into the ESB MMIO allow to read or manipulate
|
||||
* the PQ bits. They must be used with an 8-byte load instruction.
|
||||
* They all return the previous state of the interrupt (atomically).
|
||||
*
|
||||
* Additionally, some ESB pages support doing an EOI via a store and
|
||||
* some ESBs support doing a trigger via a separate trigger page.
|
||||
*/
|
||||
#define XIVE_ESB_STORE_EOI 0x400 /* Store */
|
||||
#define XIVE_ESB_LOAD_EOI 0x000 /* Load */
|
||||
#define XIVE_ESB_GET 0x800 /* Load */
|
||||
#define XIVE_ESB_SET_PQ_00 0xc00 /* Load */
|
||||
#define XIVE_ESB_SET_PQ_01 0xd00 /* Load */
|
||||
#define XIVE_ESB_SET_PQ_10 0xe00 /* Load */
|
||||
#define XIVE_ESB_SET_PQ_11 0xf00 /* Load */
|
||||
|
||||
uint8_t xive_source_esb_get(XiveSource *xsrc, uint32_t srcno);
|
||||
uint8_t xive_source_esb_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq);
|
||||
|
||||
void xive_source_pic_print_info(XiveSource *xsrc, uint32_t offset,
|
||||
Monitor *mon);
|
||||
|
||||
static inline qemu_irq xive_source_qirq(XiveSource *xsrc, uint32_t srcno)
|
||||
{
|
||||
assert(srcno < xsrc->nr_irqs);
|
||||
return xsrc->qirqs[srcno];
|
||||
}
|
||||
|
||||
static inline bool xive_source_irq_is_lsi(XiveSource *xsrc, uint32_t srcno)
|
||||
{
|
||||
assert(srcno < xsrc->nr_irqs);
|
||||
return test_bit(srcno, xsrc->lsi_map);
|
||||
}
|
||||
|
||||
static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno,
|
||||
bool lsi)
|
||||
{
|
||||
assert(srcno < xsrc->nr_irqs);
|
||||
if (lsi) {
|
||||
bitmap_set(xsrc->lsi_map, srcno, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* XIVE Router
|
||||
*/
|
||||
|
||||
typedef struct XiveRouter {
|
||||
SysBusDevice parent;
|
||||
} XiveRouter;
|
||||
|
||||
#define TYPE_XIVE_ROUTER "xive-router"
|
||||
#define XIVE_ROUTER(obj) \
|
||||
OBJECT_CHECK(XiveRouter, (obj), TYPE_XIVE_ROUTER)
|
||||
#define XIVE_ROUTER_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(XiveRouterClass, (klass), TYPE_XIVE_ROUTER)
|
||||
#define XIVE_ROUTER_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(XiveRouterClass, (obj), TYPE_XIVE_ROUTER)
|
||||
|
||||
typedef struct XiveRouterClass {
|
||||
SysBusDeviceClass parent;
|
||||
|
||||
/* XIVE table accessors */
|
||||
int (*get_eas)(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx,
|
||||
XiveEAS *eas);
|
||||
int (*get_end)(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
|
||||
XiveEND *end);
|
||||
int (*write_end)(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
|
||||
XiveEND *end, uint8_t word_number);
|
||||
int (*get_nvt)(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
XiveNVT *nvt);
|
||||
int (*write_nvt)(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
XiveNVT *nvt, uint8_t word_number);
|
||||
} XiveRouterClass;
|
||||
|
||||
void xive_eas_pic_print_info(XiveEAS *eas, uint32_t lisn, Monitor *mon);
|
||||
|
||||
int xive_router_get_eas(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx,
|
||||
XiveEAS *eas);
|
||||
int xive_router_get_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
|
||||
XiveEND *end);
|
||||
int xive_router_write_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
|
||||
XiveEND *end, uint8_t word_number);
|
||||
int xive_router_get_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
XiveNVT *nvt);
|
||||
int xive_router_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
XiveNVT *nvt, uint8_t word_number);
|
||||
|
||||
|
||||
/*
|
||||
* XIVE END ESBs
|
||||
*/
|
||||
|
||||
#define TYPE_XIVE_END_SOURCE "xive-end-source"
|
||||
#define XIVE_END_SOURCE(obj) \
|
||||
OBJECT_CHECK(XiveENDSource, (obj), TYPE_XIVE_END_SOURCE)
|
||||
|
||||
typedef struct XiveENDSource {
|
||||
DeviceState parent;
|
||||
|
||||
uint32_t nr_ends;
|
||||
uint8_t block_id;
|
||||
|
||||
/* ESB memory region */
|
||||
uint32_t esb_shift;
|
||||
MemoryRegion esb_mmio;
|
||||
|
||||
XiveRouter *xrtr;
|
||||
} XiveENDSource;
|
||||
|
||||
/*
|
||||
* For legacy compatibility, the exceptions define up to 256 different
|
||||
* priorities. P9 implements only 9 levels : 8 active levels [0 - 7]
|
||||
* and the least favored level 0xFF.
|
||||
*/
|
||||
#define XIVE_PRIORITY_MAX 7
|
||||
|
||||
void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon);
|
||||
void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon);
|
||||
|
||||
/*
|
||||
* XIVE Thread interrupt Management (TM) context
|
||||
*/
|
||||
|
||||
#define TYPE_XIVE_TCTX "xive-tctx"
|
||||
#define XIVE_TCTX(obj) OBJECT_CHECK(XiveTCTX, (obj), TYPE_XIVE_TCTX)
|
||||
|
||||
/*
|
||||
* XIVE Thread interrupt Management register rings :
|
||||
*
|
||||
* QW-0 User event-based exception state
|
||||
* QW-1 O/S OS context for priority management, interrupt acks
|
||||
* QW-2 Pool hypervisor pool context for virtual processors dispatched
|
||||
* QW-3 Physical physical thread context and security context
|
||||
*/
|
||||
#define XIVE_TM_RING_COUNT 4
|
||||
#define XIVE_TM_RING_SIZE 0x10
|
||||
|
||||
typedef struct XiveTCTX {
|
||||
DeviceState parent_obj;
|
||||
|
||||
CPUState *cs;
|
||||
qemu_irq output;
|
||||
|
||||
uint8_t regs[XIVE_TM_RING_COUNT * XIVE_TM_RING_SIZE];
|
||||
} XiveTCTX;
|
||||
|
||||
/*
|
||||
* XIVE Thread Interrupt Management Aera (TIMA)
|
||||
*
|
||||
* This region gives access to the registers of the thread interrupt
|
||||
* management context. It is four page wide, each page providing a
|
||||
* different view of the registers. The page with the lower offset is
|
||||
* the most privileged and gives access to the entire context.
|
||||
*/
|
||||
#define XIVE_TM_HW_PAGE 0x0
|
||||
#define XIVE_TM_HV_PAGE 0x1
|
||||
#define XIVE_TM_OS_PAGE 0x2
|
||||
#define XIVE_TM_USER_PAGE 0x3
|
||||
|
||||
extern const MemoryRegionOps xive_tm_ops;
|
||||
|
||||
void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon);
|
||||
Object *xive_tctx_create(Object *cpu, XiveRouter *xrtr, Error **errp);
|
||||
|
||||
static inline uint32_t xive_nvt_cam_line(uint8_t nvt_blk, uint32_t nvt_idx)
|
||||
{
|
||||
return (nvt_blk << 19) | nvt_idx;
|
||||
}
|
||||
|
||||
#endif /* PPC_XIVE_H */
|
235
include/hw/ppc/xive_regs.h
Normal file
235
include/hw/ppc/xive_regs.h
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* QEMU PowerPC XIVE internal structure definitions
|
||||
*
|
||||
*
|
||||
* The XIVE structures are accessed by the HW and their format is
|
||||
* architected to be big-endian. Some macros are provided to ease
|
||||
* access to the different fields.
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2016-2018, IBM Corporation.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See the
|
||||
* COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef PPC_XIVE_REGS_H
|
||||
#define PPC_XIVE_REGS_H
|
||||
|
||||
/*
|
||||
* Interrupt source number encoding on PowerBUS
|
||||
*/
|
||||
#define XIVE_SRCNO_BLOCK(srcno) (((srcno) >> 28) & 0xf)
|
||||
#define XIVE_SRCNO_INDEX(srcno) ((srcno) & 0x0fffffff)
|
||||
#define XIVE_SRCNO(blk, idx) ((uint32_t)(blk) << 28 | (idx))
|
||||
|
||||
#define TM_SHIFT 16
|
||||
|
||||
/* TM register offsets */
|
||||
#define TM_QW0_USER 0x000 /* All rings */
|
||||
#define TM_QW1_OS 0x010 /* Ring 0..2 */
|
||||
#define TM_QW2_HV_POOL 0x020 /* Ring 0..1 */
|
||||
#define TM_QW3_HV_PHYS 0x030 /* Ring 0..1 */
|
||||
|
||||
/* Byte offsets inside a QW QW0 QW1 QW2 QW3 */
|
||||
#define TM_NSR 0x0 /* + + - + */
|
||||
#define TM_CPPR 0x1 /* - + - + */
|
||||
#define TM_IPB 0x2 /* - + + + */
|
||||
#define TM_LSMFB 0x3 /* - + + + */
|
||||
#define TM_ACK_CNT 0x4 /* - + - - */
|
||||
#define TM_INC 0x5 /* - + - + */
|
||||
#define TM_AGE 0x6 /* - + - + */
|
||||
#define TM_PIPR 0x7 /* - + - + */
|
||||
|
||||
#define TM_WORD0 0x0
|
||||
#define TM_WORD1 0x4
|
||||
|
||||
/*
|
||||
* QW word 2 contains the valid bit at the top and other fields
|
||||
* depending on the QW.
|
||||
*/
|
||||
#define TM_WORD2 0x8
|
||||
#define TM_QW0W2_VU PPC_BIT32(0)
|
||||
#define TM_QW0W2_LOGIC_SERV PPC_BITMASK32(1, 31) /* XX 2,31 ? */
|
||||
#define TM_QW1W2_VO PPC_BIT32(0)
|
||||
#define TM_QW1W2_OS_CAM PPC_BITMASK32(8, 31)
|
||||
#define TM_QW2W2_VP PPC_BIT32(0)
|
||||
#define TM_QW2W2_POOL_CAM PPC_BITMASK32(8, 31)
|
||||
#define TM_QW3W2_VT PPC_BIT32(0)
|
||||
#define TM_QW3W2_LP PPC_BIT32(6)
|
||||
#define TM_QW3W2_LE PPC_BIT32(7)
|
||||
#define TM_QW3W2_T PPC_BIT32(31)
|
||||
|
||||
/*
|
||||
* In addition to normal loads to "peek" and writes (only when invalid)
|
||||
* using 4 and 8 bytes accesses, the above registers support these
|
||||
* "special" byte operations:
|
||||
*
|
||||
* - Byte load from QW0[NSR] - User level NSR (EBB)
|
||||
* - Byte store to QW0[NSR] - User level NSR (EBB)
|
||||
* - Byte load/store to QW1[CPPR] and QW3[CPPR] - CPPR access
|
||||
* - Byte load from QW3[TM_WORD2] - Read VT||00000||LP||LE on thrd 0
|
||||
* otherwise VT||0000000
|
||||
* - Byte store to QW3[TM_WORD2] - Set VT bit (and LP/LE if present)
|
||||
*
|
||||
* Then we have all these "special" CI ops at these offset that trigger
|
||||
* all sorts of side effects:
|
||||
*/
|
||||
#define TM_SPC_ACK_EBB 0x800 /* Load8 ack EBB to reg*/
|
||||
#define TM_SPC_ACK_OS_REG 0x810 /* Load16 ack OS irq to reg */
|
||||
#define TM_SPC_PUSH_USR_CTX 0x808 /* Store32 Push/Validate user context */
|
||||
#define TM_SPC_PULL_USR_CTX 0x808 /* Load32 Pull/Invalidate user
|
||||
* context */
|
||||
#define TM_SPC_SET_OS_PENDING 0x812 /* Store8 Set OS irq pending bit */
|
||||
#define TM_SPC_PULL_OS_CTX 0x818 /* Load32/Load64 Pull/Invalidate OS
|
||||
* context to reg */
|
||||
#define TM_SPC_PULL_POOL_CTX 0x828 /* Load32/Load64 Pull/Invalidate Pool
|
||||
* context to reg*/
|
||||
#define TM_SPC_ACK_HV_REG 0x830 /* Load16 ack HV irq to reg */
|
||||
#define TM_SPC_PULL_USR_CTX_OL 0xc08 /* Store8 Pull/Inval usr ctx to odd
|
||||
* line */
|
||||
#define TM_SPC_ACK_OS_EL 0xc10 /* Store8 ack OS irq to even line */
|
||||
#define TM_SPC_ACK_HV_POOL_EL 0xc20 /* Store8 ack HV evt pool to even
|
||||
* line */
|
||||
#define TM_SPC_ACK_HV_EL 0xc30 /* Store8 ack HV irq to even line */
|
||||
/* XXX more... */
|
||||
|
||||
/* NSR fields for the various QW ack types */
|
||||
#define TM_QW0_NSR_EB PPC_BIT8(0)
|
||||
#define TM_QW1_NSR_EO PPC_BIT8(0)
|
||||
#define TM_QW3_NSR_HE PPC_BITMASK8(0, 1)
|
||||
#define TM_QW3_NSR_HE_NONE 0
|
||||
#define TM_QW3_NSR_HE_POOL 1
|
||||
#define TM_QW3_NSR_HE_PHYS 2
|
||||
#define TM_QW3_NSR_HE_LSI 3
|
||||
#define TM_QW3_NSR_I PPC_BIT8(2)
|
||||
#define TM_QW3_NSR_GRP_LVL PPC_BIT8(3, 7)
|
||||
|
||||
/*
|
||||
* EAS (Event Assignment Structure)
|
||||
*
|
||||
* One per interrupt source. Targets an interrupt to a given Event
|
||||
* Notification Descriptor (END) and provides the corresponding
|
||||
* logical interrupt number (END data)
|
||||
*/
|
||||
typedef struct XiveEAS {
|
||||
/*
|
||||
* Use a single 64-bit definition to make it easier to perform
|
||||
* atomic updates
|
||||
*/
|
||||
uint64_t w;
|
||||
#define EAS_VALID PPC_BIT(0)
|
||||
#define EAS_END_BLOCK PPC_BITMASK(4, 7) /* Destination END block# */
|
||||
#define EAS_END_INDEX PPC_BITMASK(8, 31) /* Destination END index */
|
||||
#define EAS_MASKED PPC_BIT(32) /* Masked */
|
||||
#define EAS_END_DATA PPC_BITMASK(33, 63) /* Data written to the END */
|
||||
} XiveEAS;
|
||||
|
||||
#define xive_eas_is_valid(eas) (be64_to_cpu((eas)->w) & EAS_VALID)
|
||||
#define xive_eas_is_masked(eas) (be64_to_cpu((eas)->w) & EAS_MASKED)
|
||||
|
||||
static inline uint64_t xive_get_field64(uint64_t mask, uint64_t word)
|
||||
{
|
||||
return (be64_to_cpu(word) & mask) >> ctz64(mask);
|
||||
}
|
||||
|
||||
static inline uint64_t xive_set_field64(uint64_t mask, uint64_t word,
|
||||
uint64_t value)
|
||||
{
|
||||
uint64_t tmp =
|
||||
(be64_to_cpu(word) & ~mask) | ((value << ctz64(mask)) & mask);
|
||||
return cpu_to_be64(tmp);
|
||||
}
|
||||
|
||||
static inline uint32_t xive_get_field32(uint32_t mask, uint32_t word)
|
||||
{
|
||||
return (be32_to_cpu(word) & mask) >> ctz32(mask);
|
||||
}
|
||||
|
||||
static inline uint32_t xive_set_field32(uint32_t mask, uint32_t word,
|
||||
uint32_t value)
|
||||
{
|
||||
uint32_t tmp =
|
||||
(be32_to_cpu(word) & ~mask) | ((value << ctz32(mask)) & mask);
|
||||
return cpu_to_be32(tmp);
|
||||
}
|
||||
|
||||
/* Event Notification Descriptor (END) */
|
||||
typedef struct XiveEND {
|
||||
uint32_t w0;
|
||||
#define END_W0_VALID PPC_BIT32(0) /* "v" bit */
|
||||
#define END_W0_ENQUEUE PPC_BIT32(1) /* "q" bit */
|
||||
#define END_W0_UCOND_NOTIFY PPC_BIT32(2) /* "n" bit */
|
||||
#define END_W0_BACKLOG PPC_BIT32(3) /* "b" bit */
|
||||
#define END_W0_PRECL_ESC_CTL PPC_BIT32(4) /* "p" bit */
|
||||
#define END_W0_ESCALATE_CTL PPC_BIT32(5) /* "e" bit */
|
||||
#define END_W0_UNCOND_ESCALATE PPC_BIT32(6) /* "u" bit - DD2.0 */
|
||||
#define END_W0_SILENT_ESCALATE PPC_BIT32(7) /* "s" bit - DD2.0 */
|
||||
#define END_W0_QSIZE PPC_BITMASK32(12, 15)
|
||||
#define END_W0_SW0 PPC_BIT32(16)
|
||||
#define END_W0_FIRMWARE END_W0_SW0 /* Owned by FW */
|
||||
#define END_QSIZE_4K 0
|
||||
#define END_QSIZE_64K 4
|
||||
#define END_W0_HWDEP PPC_BITMASK32(24, 31)
|
||||
uint32_t w1;
|
||||
#define END_W1_ESn PPC_BITMASK32(0, 1)
|
||||
#define END_W1_ESn_P PPC_BIT32(0)
|
||||
#define END_W1_ESn_Q PPC_BIT32(1)
|
||||
#define END_W1_ESe PPC_BITMASK32(2, 3)
|
||||
#define END_W1_ESe_P PPC_BIT32(2)
|
||||
#define END_W1_ESe_Q PPC_BIT32(3)
|
||||
#define END_W1_GENERATION PPC_BIT32(9)
|
||||
#define END_W1_PAGE_OFF PPC_BITMASK32(10, 31)
|
||||
uint32_t w2;
|
||||
#define END_W2_MIGRATION_REG PPC_BITMASK32(0, 3)
|
||||
#define END_W2_OP_DESC_HI PPC_BITMASK32(4, 31)
|
||||
uint32_t w3;
|
||||
#define END_W3_OP_DESC_LO PPC_BITMASK32(0, 31)
|
||||
uint32_t w4;
|
||||
#define END_W4_ESC_END_BLOCK PPC_BITMASK32(4, 7)
|
||||
#define END_W4_ESC_END_INDEX PPC_BITMASK32(8, 31)
|
||||
uint32_t w5;
|
||||
#define END_W5_ESC_END_DATA PPC_BITMASK32(1, 31)
|
||||
uint32_t w6;
|
||||
#define END_W6_FORMAT_BIT PPC_BIT32(8)
|
||||
#define END_W6_NVT_BLOCK PPC_BITMASK32(9, 12)
|
||||
#define END_W6_NVT_INDEX PPC_BITMASK32(13, 31)
|
||||
uint32_t w7;
|
||||
#define END_W7_F0_IGNORE PPC_BIT32(0)
|
||||
#define END_W7_F0_BLK_GROUPING PPC_BIT32(1)
|
||||
#define END_W7_F0_PRIORITY PPC_BITMASK32(8, 15)
|
||||
#define END_W7_F1_WAKEZ PPC_BIT32(0)
|
||||
#define END_W7_F1_LOG_SERVER_ID PPC_BITMASK32(1, 31)
|
||||
} XiveEND;
|
||||
|
||||
#define xive_end_is_valid(end) (be32_to_cpu((end)->w0) & END_W0_VALID)
|
||||
#define xive_end_is_enqueue(end) (be32_to_cpu((end)->w0) & END_W0_ENQUEUE)
|
||||
#define xive_end_is_notify(end) (be32_to_cpu((end)->w0) & END_W0_UCOND_NOTIFY)
|
||||
#define xive_end_is_backlog(end) (be32_to_cpu((end)->w0) & END_W0_BACKLOG)
|
||||
#define xive_end_is_escalate(end) (be32_to_cpu((end)->w0) & END_W0_ESCALATE_CTL)
|
||||
|
||||
/* Notification Virtual Target (NVT) */
|
||||
typedef struct XiveNVT {
|
||||
uint32_t w0;
|
||||
#define NVT_W0_VALID PPC_BIT32(0)
|
||||
uint32_t w1;
|
||||
uint32_t w2;
|
||||
uint32_t w3;
|
||||
uint32_t w4;
|
||||
uint32_t w5;
|
||||
uint32_t w6;
|
||||
uint32_t w7;
|
||||
uint32_t w8;
|
||||
#define NVT_W8_GRP_VALID PPC_BIT32(0)
|
||||
uint32_t w9;
|
||||
uint32_t wa;
|
||||
uint32_t wb;
|
||||
uint32_t wc;
|
||||
uint32_t wd;
|
||||
uint32_t we;
|
||||
uint32_t wf;
|
||||
} XiveNVT;
|
||||
|
||||
#define xive_nvt_is_valid(nvt) (be32_to_cpu((nvt)->w0) & NVT_W0_VALID)
|
||||
|
||||
#endif /* PPC_XIVE_REGS_H */
|
@ -70,26 +70,14 @@
|
||||
#define PPC_ELF_MACHINE EM_PPC
|
||||
#endif
|
||||
|
||||
#define PPC_BIT(bit) (0x8000000000000000UL >> (bit))
|
||||
#define PPC_BIT32(bit) (0x80000000UL >> (bit))
|
||||
#define PPC_BIT8(bit) (0x80UL >> (bit))
|
||||
#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
|
||||
#define PPC_BIT32(bit) (0x80000000 >> (bit))
|
||||
#define PPC_BIT8(bit) (0x80 >> (bit))
|
||||
#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
|
||||
#define PPC_BITMASK32(bs, be) ((PPC_BIT32(bs) - PPC_BIT32(be)) | \
|
||||
PPC_BIT32(bs))
|
||||
#define PPC_BITMASK8(bs, be) ((PPC_BIT8(bs) - PPC_BIT8(be)) | PPC_BIT8(bs))
|
||||
|
||||
#if HOST_LONG_BITS == 32
|
||||
# define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1)
|
||||
#elif HOST_LONG_BITS == 64
|
||||
# define MASK_TO_LSH(m) (__builtin_ffsl(m) - 1)
|
||||
#else
|
||||
# error Unknown sizeof long
|
||||
#endif
|
||||
|
||||
#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m))
|
||||
#define SETFIELD(m, v, val) \
|
||||
(((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m)))
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Exception vectors definitions */
|
||||
enum {
|
||||
|
@ -849,7 +849,7 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
|
||||
|
||||
static inline void gen_op_arith_compute_ca32(DisasContext *ctx,
|
||||
TCGv res, TCGv arg0, TCGv arg1,
|
||||
int sub)
|
||||
TCGv ca32, int sub)
|
||||
{
|
||||
TCGv t0;
|
||||
|
||||
@ -864,13 +864,14 @@ static inline void gen_op_arith_compute_ca32(DisasContext *ctx,
|
||||
tcg_gen_xor_tl(t0, arg0, arg1);
|
||||
}
|
||||
tcg_gen_xor_tl(t0, t0, res);
|
||||
tcg_gen_extract_tl(cpu_ca32, t0, 32, 1);
|
||||
tcg_gen_extract_tl(ca32, t0, 32, 1);
|
||||
tcg_temp_free(t0);
|
||||
}
|
||||
|
||||
/* Common add function */
|
||||
static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
|
||||
TCGv arg2, bool add_ca, bool compute_ca,
|
||||
TCGv arg2, TCGv ca, TCGv ca32,
|
||||
bool add_ca, bool compute_ca,
|
||||
bool compute_ov, bool compute_rc0)
|
||||
{
|
||||
TCGv t0 = ret;
|
||||
@ -888,29 +889,29 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
|
||||
tcg_gen_xor_tl(t1, arg1, arg2); /* add without carry */
|
||||
tcg_gen_add_tl(t0, arg1, arg2);
|
||||
if (add_ca) {
|
||||
tcg_gen_add_tl(t0, t0, cpu_ca);
|
||||
tcg_gen_add_tl(t0, t0, ca);
|
||||
}
|
||||
tcg_gen_xor_tl(cpu_ca, t0, t1); /* bits changed w/ carry */
|
||||
tcg_gen_xor_tl(ca, t0, t1); /* bits changed w/ carry */
|
||||
tcg_temp_free(t1);
|
||||
tcg_gen_extract_tl(cpu_ca, cpu_ca, 32, 1);
|
||||
tcg_gen_extract_tl(ca, ca, 32, 1);
|
||||
if (is_isa300(ctx)) {
|
||||
tcg_gen_mov_tl(cpu_ca32, cpu_ca);
|
||||
tcg_gen_mov_tl(ca32, ca);
|
||||
}
|
||||
} else {
|
||||
TCGv zero = tcg_const_tl(0);
|
||||
if (add_ca) {
|
||||
tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, cpu_ca, zero);
|
||||
tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, arg2, zero);
|
||||
tcg_gen_add2_tl(t0, ca, arg1, zero, ca, zero);
|
||||
tcg_gen_add2_tl(t0, ca, t0, ca, arg2, zero);
|
||||
} else {
|
||||
tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero);
|
||||
tcg_gen_add2_tl(t0, ca, arg1, zero, arg2, zero);
|
||||
}
|
||||
gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, 0);
|
||||
gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, ca32, 0);
|
||||
tcg_temp_free(zero);
|
||||
}
|
||||
} else {
|
||||
tcg_gen_add_tl(t0, arg1, arg2);
|
||||
if (add_ca) {
|
||||
tcg_gen_add_tl(t0, t0, cpu_ca);
|
||||
tcg_gen_add_tl(t0, t0, ca);
|
||||
}
|
||||
}
|
||||
|
||||
@ -927,40 +928,44 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
|
||||
}
|
||||
}
|
||||
/* Add functions with two operands */
|
||||
#define GEN_INT_ARITH_ADD(name, opc3, add_ca, compute_ca, compute_ov) \
|
||||
#define GEN_INT_ARITH_ADD(name, opc3, ca, add_ca, compute_ca, compute_ov) \
|
||||
static void glue(gen_, name)(DisasContext *ctx) \
|
||||
{ \
|
||||
gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \
|
||||
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \
|
||||
ca, glue(ca, 32), \
|
||||
add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
|
||||
}
|
||||
/* Add functions with one operand and one immediate */
|
||||
#define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val, \
|
||||
#define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val, ca, \
|
||||
add_ca, compute_ca, compute_ov) \
|
||||
static void glue(gen_, name)(DisasContext *ctx) \
|
||||
{ \
|
||||
TCGv t0 = tcg_const_tl(const_val); \
|
||||
gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \
|
||||
cpu_gpr[rA(ctx->opcode)], t0, \
|
||||
ca, glue(ca, 32), \
|
||||
add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
|
||||
tcg_temp_free(t0); \
|
||||
}
|
||||
|
||||
/* add add. addo addo. */
|
||||
GEN_INT_ARITH_ADD(add, 0x08, 0, 0, 0)
|
||||
GEN_INT_ARITH_ADD(addo, 0x18, 0, 0, 1)
|
||||
GEN_INT_ARITH_ADD(add, 0x08, cpu_ca, 0, 0, 0)
|
||||
GEN_INT_ARITH_ADD(addo, 0x18, cpu_ca, 0, 0, 1)
|
||||
/* addc addc. addco addco. */
|
||||
GEN_INT_ARITH_ADD(addc, 0x00, 0, 1, 0)
|
||||
GEN_INT_ARITH_ADD(addco, 0x10, 0, 1, 1)
|
||||
GEN_INT_ARITH_ADD(addc, 0x00, cpu_ca, 0, 1, 0)
|
||||
GEN_INT_ARITH_ADD(addco, 0x10, cpu_ca, 0, 1, 1)
|
||||
/* adde adde. addeo addeo. */
|
||||
GEN_INT_ARITH_ADD(adde, 0x04, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD(addeo, 0x14, 1, 1, 1)
|
||||
GEN_INT_ARITH_ADD(adde, 0x04, cpu_ca, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD(addeo, 0x14, cpu_ca, 1, 1, 1)
|
||||
/* addme addme. addmeo addmeo. */
|
||||
GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, 1, 1, 1)
|
||||
GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, cpu_ca, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, cpu_ca, 1, 1, 1)
|
||||
/* addex */
|
||||
GEN_INT_ARITH_ADD(addex, 0x05, cpu_ov, 1, 1, 0);
|
||||
/* addze addze. addzeo addzeo.*/
|
||||
GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, 1, 1, 1)
|
||||
GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, cpu_ca, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, cpu_ca, 1, 1, 1)
|
||||
/* addi */
|
||||
static void gen_addi(DisasContext *ctx)
|
||||
{
|
||||
@ -979,7 +984,7 @@ static inline void gen_op_addic(DisasContext *ctx, bool compute_rc0)
|
||||
{
|
||||
TCGv c = tcg_const_tl(SIMM(ctx->opcode));
|
||||
gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
|
||||
c, 0, 1, 0, compute_rc0);
|
||||
c, cpu_ca, cpu_ca32, 0, 1, 0, compute_rc0);
|
||||
tcg_temp_free(c);
|
||||
}
|
||||
|
||||
@ -1432,13 +1437,13 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
|
||||
zero = tcg_const_tl(0);
|
||||
tcg_gen_add2_tl(t0, cpu_ca, arg2, zero, cpu_ca, zero);
|
||||
tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, inv1, zero);
|
||||
gen_op_arith_compute_ca32(ctx, t0, inv1, arg2, 0);
|
||||
gen_op_arith_compute_ca32(ctx, t0, inv1, arg2, cpu_ca32, 0);
|
||||
tcg_temp_free(zero);
|
||||
tcg_temp_free(inv1);
|
||||
} else {
|
||||
tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1);
|
||||
tcg_gen_sub_tl(t0, arg2, arg1);
|
||||
gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, 1);
|
||||
gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, cpu_ca32, 1);
|
||||
}
|
||||
} else if (add_ca) {
|
||||
/* Since we're ignoring carry-out, we can simplify the
|
||||
@ -7087,6 +7092,7 @@ GEN_INT_ARITH_ADD(adde, 0x04, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD(addeo, 0x14, 1, 1, 1)
|
||||
GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, 1, 1, 1)
|
||||
GEN_HANDLER_E(addex, 0x1F, 0x0A, 0x05, 0x00000000, PPC_NONE, PPC2_ISA300),
|
||||
GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, 1, 1, 0)
|
||||
GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, 1, 1, 1)
|
||||
|
||||
|
@ -143,7 +143,7 @@ GEN_VXFORM(vaddsws, 0, 14),
|
||||
GEN_VXFORM_DUAL(vsububs, bcdadd, 0, 24, PPC_ALTIVEC, PPC_NONE),
|
||||
GEN_VXFORM_DUAL(vsubuhs, bcdsub, 0, 25, PPC_ALTIVEC, PPC_NONE),
|
||||
GEN_VXFORM(vsubuws, 0, 26),
|
||||
GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_NONE, PPC2_ISA300),
|
||||
GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_ALTIVEC, PPC2_ISA300),
|
||||
GEN_VXFORM(vsubshs, 0, 29),
|
||||
GEN_VXFORM_DUAL(vsubsws, xpnd04_2, 0, 30, PPC_ALTIVEC, PPC_NONE),
|
||||
GEN_VXFORM_207(vadduqm, 0, 4),
|
||||
|
@ -9081,13 +9081,13 @@ static void init_ppc_proc(PowerPCCPU *cpu)
|
||||
nb_tlb *= 2;
|
||||
switch (env->tlb_type) {
|
||||
case TLB_6XX:
|
||||
env->tlb.tlb6 = g_malloc0(nb_tlb * sizeof(ppc6xx_tlb_t));
|
||||
env->tlb.tlb6 = g_new0(ppc6xx_tlb_t, nb_tlb);
|
||||
break;
|
||||
case TLB_EMB:
|
||||
env->tlb.tlbe = g_malloc0(nb_tlb * sizeof(ppcemb_tlb_t));
|
||||
env->tlb.tlbe = g_new0(ppcemb_tlb_t, nb_tlb);
|
||||
break;
|
||||
case TLB_MAS:
|
||||
env->tlb.tlbm = g_malloc0(nb_tlb * sizeof(ppcmas_tlb_t));
|
||||
env->tlb.tlbm = g_new0(ppcmas_tlb_t, nb_tlb);
|
||||
break;
|
||||
}
|
||||
/* Pre-compute some useful values */
|
||||
|
Loading…
Reference in New Issue
Block a user