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:
Peter Maydell 2018-12-21 15:49:59 +00:00
commit 891ff9f4a3
31 changed files with 4201 additions and 153 deletions

View File

@ -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

View File

@ -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

View File

@ -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 } },

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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] =

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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,
};

View File

@ -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:

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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 */

View File

@ -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

View 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 */

View File

@ -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
View 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
View 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 */

View File

@ -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 {

View File

@ -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)

View File

@ -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),

View File

@ -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 */