diff options
Diffstat (limited to 'hw/ppc')
-rw-r--r-- | hw/ppc/e500.c | 19 | ||||
-rw-r--r-- | hw/ppc/mac_newworld.c | 40 | ||||
-rw-r--r-- | hw/ppc/mac_oldworld.c | 10 | ||||
-rw-r--r-- | hw/ppc/pnv.c | 27 | ||||
-rw-r--r-- | hw/ppc/pnv_core.c | 4 | ||||
-rw-r--r-- | hw/ppc/pnv_psi.c | 7 | ||||
-rw-r--r-- | hw/ppc/ppc405_boards.c | 16 | ||||
-rw-r--r-- | hw/ppc/ppc405_uc.c | 6 | ||||
-rw-r--r-- | hw/ppc/ppc440_bamboo.c | 7 | ||||
-rw-r--r-- | hw/ppc/ppc4xx_devs.c | 3 | ||||
-rw-r--r-- | hw/ppc/prep.c | 4 | ||||
-rw-r--r-- | hw/ppc/sam460ex.c | 4 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 448 | ||||
-rw-r--r-- | hw/ppc/spapr_cpu_core.c | 11 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 93 | ||||
-rw-r--r-- | hw/ppc/spapr_iommu.c | 4 | ||||
-rw-r--r-- | hw/ppc/spapr_irq.c | 439 | ||||
-rw-r--r-- | hw/ppc/spapr_pci.c | 44 | ||||
-rw-r--r-- | hw/ppc/spapr_rtas_ddw.c | 19 | ||||
-rw-r--r-- | hw/ppc/spapr_vio.c | 2 | ||||
-rw-r--r-- | hw/ppc/trace-events | 3 | ||||
-rw-r--r-- | hw/ppc/virtex_ml507.c | 2 |
22 files changed, 851 insertions, 361 deletions
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index e6747fce28..0581e9e3d4 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -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; @@ -997,6 +995,7 @@ void ppce500_init(MachineState *machine) * Hrm. No ELF image? Try a uImage, maybe someone is giving us an * ePAPR compliant kernel */ + loadaddr = LOAD_UIMAGE_LOADADDR_INVALID; payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL, NULL, NULL); if (payload_size < 0) { diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 14273a123e..bb19eaba36 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -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; @@ -127,8 +127,7 @@ static void ppc_core99_init(MachineState *machine) MACIOIDEState *macio_ide; BusState *adb_bus; MacIONVRAMState *nvr; - int bios_size, ndrv_size; - uint8_t *ndrv_file; + int bios_size; int ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; @@ -249,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) */ @@ -300,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); @@ -510,11 +505,10 @@ static void ppc_core99_init(MachineState *machine) /* MacOS NDRV VGA driver */ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, NDRV_VGA_FILENAME); if (filename) { - ndrv_size = get_image_size(filename); - if (ndrv_size != -1) { - ndrv_file = g_malloc(ndrv_size); - ndrv_size = load_image(filename, ndrv_file); + gchar *ndrv_file; + gsize ndrv_size; + if (g_file_get_contents(filename, &ndrv_file, &ndrv_size, NULL)) { fw_cfg_add_file(fw_cfg, "ndrv/qemu_vga.ndrv", ndrv_file, ndrv_size); } g_free(filename); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 9891c325a9..817f70e52c 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -99,8 +99,7 @@ static void ppc_heathrow_init(MachineState *machine) SysBusDevice *s; DeviceState *dev, *pic_dev; BusState *adb_bus; - int bios_size, ndrv_size; - uint8_t *ndrv_file; + int bios_size; uint16_t ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; @@ -361,11 +360,10 @@ static void ppc_heathrow_init(MachineState *machine) /* MacOS NDRV VGA driver */ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, NDRV_VGA_FILENAME); if (filename) { - ndrv_size = get_image_size(filename); - if (ndrv_size != -1) { - ndrv_file = g_malloc(ndrv_size); - ndrv_size = load_image(filename, ndrv_file); + gchar *ndrv_file; + gsize ndrv_size; + if (g_file_get_contents(filename, &ndrv_file, &ndrv_size, NULL)) { fw_cfg_add_file(fw_cfg, "ndrv/qemu_vga.ndrv", ndrv_file, ndrv_size); } g_free(filename); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 346f5e7aed..d84acef55b 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -668,11 +668,20 @@ static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id) return (chip->chip_id << 7) | (core_id << 3); } -static Object *pnv_chip_power8_intc_create(PnvChip *chip, Object *child, - Error **errp) +static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu, + Error **errp) { - return icp_create(child, TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()), - errp); + Error *local_err = NULL; + Object *obj; + + obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()), + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + cpu->icp = ICP(obj); } /* @@ -690,10 +699,10 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id) return (chip->chip_id << 8) | (core_id << 2); } -static Object *pnv_chip_power9_intc_create(PnvChip *chip, Object *child, - Error **errp) +static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu, + Error **errp) { - return NULL; + return; } /* Allowed core identifiers on a POWER8 Processor Chip : @@ -1090,7 +1099,7 @@ static ICPState *pnv_icp_get(XICSFabric *xi, int pir) { PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir); - return cpu ? ICP(cpu->intc) : NULL; + return cpu ? cpu->icp : NULL; } static void pnv_pic_print_info(InterruptStatsProvider *obj, @@ -1103,7 +1112,7 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj, CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); - icp_pic_print_info(ICP(cpu->intc), mon); + icp_pic_print_info(cpu->icp, mon); } for (i = 0; i < pnv->num_chips; i++) { diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index ad1bcc7990..b98f277f1e 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -114,7 +114,7 @@ static void pnv_realize_vcpu(PowerPCCPU *cpu, PnvChip *chip, Error **errp) return; } - cpu->intc = pcc->intc_create(chip, OBJECT(cpu), &local_err); + pcc->intc_create(chip, cpu, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -190,7 +190,7 @@ err: static void pnv_unrealize_vcpu(PowerPCCPU *cpu) { qemu_unregister_reset(pnv_cpu_reset, cpu); - object_unparent(cpu->intc); + object_unparent(OBJECT(cpu->icp)); cpu_remove_sync(CPU(cpu)); object_unparent(OBJECT(cpu)); } diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 5b969127c3..8ced095063 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -207,7 +207,6 @@ static const uint64_t stat_bits[] = { void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state) { - ICSState *ics = &psi->ics; uint32_t xivr_reg; uint32_t stat_reg; uint32_t src; @@ -227,14 +226,14 @@ void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state) /* TODO: optimization, check mask here. That means * re-evaluating when unmasking */ - qemu_irq_raise(ics->qirqs[src]); + qemu_irq_raise(psi->qirqs[src]); } else { psi->regs[stat_reg] &= ~stat_bits[irq]; /* FSP and PSI are muxed so don't lower if either is still set */ if (stat_reg != PSIHB_XSCOM_CR || !(psi->regs[stat_reg] & (PSIHB_CR_PSI_IRQ | PSIHB_CR_FSP_IRQ))) { - qemu_irq_lower(ics->qirqs[src]); + qemu_irq_lower(psi->qirqs[src]); } else { state = true; } @@ -491,6 +490,8 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp) ics_set_irq_type(ics, i, true); } + psi->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs); + /* XSCOM region for PSI registers */ pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_xscom_ops, psi, "xscom-psi", PNV_XSCOM_PSIHB_SIZE); diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index 3be3fe4432..f47b15f10e 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -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; @@ -219,9 +219,11 @@ static void ref405ep_init(MachineState *machine) bios_name = BIOS_FILENAME; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); if (filename) { - bios_size = load_image(filename, memory_region_get_ram_ptr(bios)); + bios_size = load_image_size(filename, + memory_region_get_ram_ptr(bios), + BIOS_SIZE); g_free(filename); - if (bios_size < 0 || bios_size > BIOS_SIZE) { + if (bios_size < 0) { error_report("Could not load PowerPC BIOS '%s'", bios_name); exit(1); } @@ -446,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; @@ -515,9 +517,11 @@ static void taihu_405ep_init(MachineState *machine) &error_fatal); filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); if (filename) { - bios_size = load_image(filename, memory_region_get_ram_ptr(bios)); + bios_size = load_image_size(filename, + memory_region_get_ram_ptr(bios), + BIOS_SIZE); g_free(filename); - if (bios_size < 0 || bios_size > BIOS_SIZE) { + if (bios_size < 0) { error_report("Could not load PowerPC BIOS '%s'", bios_name); exit(1); } diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index 5c58415cf1..8d3a797cb8 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -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] = @@ -1885,7 +1885,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); *picp = pic; /* SDRAM controller */ - /* XXX 405EP has no ECC interrupt */ + /* XXX 405EP has no ECC interrupt */ ppc4xx_sdram_init(env, pic[17], 2, ram_memories, ram_bases, ram_sizes, do_init); /* External bus controller */ diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index f5720f979e..fc06191588 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -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; @@ -180,7 +179,7 @@ static void bamboo_init(MachineState *machine) CPUPPCState *env; uint64_t elf_entry; uint64_t elf_lowaddr; - hwaddr loadaddr = 0; + hwaddr loadaddr = LOAD_UIMAGE_LOADADDR_INVALID; target_long initrd_size = 0; DeviceState *dev; int success; @@ -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); diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index 8c6f3c9577..9b6e4c60fa 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -32,8 +32,7 @@ #include "exec/address-spaces.h" #include "qemu/error-report.h" -#define DEBUG_UIC - +/*#define DEBUG_UIC*/ #ifdef DEBUG_UIC # define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 2afb7f437e..7bda86a7d0 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -538,7 +538,7 @@ static void ppc_prep_init(MachineState *machine) nb_nics1 = NE2000_NB_MAX; for(i = 0; i < nb_nics1; i++) { if (nd_table[i].model == NULL) { - nd_table[i].model = g_strdup("ne2k_isa"); + nd_table[i].model = g_strdup("ne2k_isa"); } if (strcmp(nd_table[i].model, "ne2k_isa") == 0) { isa_ne2000_init(isa_bus, ne2000_io[i], ne2000_irq[i], @@ -552,7 +552,7 @@ static void ppc_prep_init(MachineState *machine) for(i = 0; i < MAX_IDE_BUS; i++) { isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i], hd[2 * i], - hd[2 * i + 1]); + hd[2 * i + 1]); } cpu = POWERPC_CPU(first_cpu); diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 5aac58f36e..84ea592749 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -402,7 +402,7 @@ static void sam460ex_init(MachineState *machine) CPUPPCState *env; PPC4xxI2CState *i2c[2]; hwaddr entry = UBOOT_ENTRY; - hwaddr loadaddr = 0; + hwaddr loadaddr = LOAD_UIMAGE_LOADADDR_INVALID; target_long initrd_size = 0; DeviceState *dev; SysBusDevice *sbdev; @@ -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); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 7afd1a175b..0942f35bf8 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -70,7 +70,6 @@ #include "hw/nmi.h" #include "hw/intc/intc.h" -#include "hw/compat.h" #include "qemu/cutils.h" #include "hw/ppc/spapr_cpu_core.h" #include "hw/mem/memory-device.h" @@ -150,7 +149,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 +888,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 +1030,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")); @@ -1051,6 +1048,7 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt) add_str(hypertas, "hcall-sprg0"); add_str(hypertas, "hcall-copy"); add_str(hypertas, "hcall-debug"); + add_str(hypertas, "hcall-vphn"); add_str(qemu_hypertas, "hcall-memop1"); if (!kvm_enabled() || kvmppc_spapr_use_multitce()) { @@ -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 @@ -1656,7 +1669,10 @@ static void spapr_machine_reset(void) /* Load the fdt */ qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt)); cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); - g_free(fdt); + g_free(spapr->fdt_blob); + spapr->fdt_size = fdt_totalsize(fdt); + spapr->fdt_initial_size = spapr->fdt_size; + spapr->fdt_blob = fdt; /* Set up the entry state */ spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr); @@ -1731,20 +1747,17 @@ 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 + /* + * 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 - * value into the RTC device */ + * value into the RTC device + */ if (version_id < 3) { err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset); + if (err) { + return err; + } } if (kvm_enabled() && spapr->patb_entry) { @@ -1759,6 +1772,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; } @@ -1910,6 +1928,39 @@ static const VMStateDescription vmstate_spapr_irq_map = { }, }; +static bool spapr_dtb_needed(void *opaque) +{ + sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque); + + return smc->update_dt_enabled; +} + +static int spapr_dtb_pre_load(void *opaque) +{ + sPAPRMachineState *spapr = (sPAPRMachineState *)opaque; + + g_free(spapr->fdt_blob); + spapr->fdt_blob = NULL; + spapr->fdt_size = 0; + + return 0; +} + +static const VMStateDescription vmstate_spapr_dtb = { + .name = "spapr_dtb", + .version_id = 1, + .minimum_version_id = 1, + .needed = spapr_dtb_needed, + .pre_load = spapr_dtb_pre_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(fdt_initial_size, sPAPRMachineState), + VMSTATE_UINT32(fdt_size, sPAPRMachineState), + VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, sPAPRMachineState, 0, NULL, + fdt_size), + VMSTATE_END_OF_LIST() + }, +}; + static const VMStateDescription vmstate_spapr = { .name = "spapr", .version_id = 3, @@ -1939,6 +1990,7 @@ static const VMStateDescription vmstate_spapr = { &vmstate_spapr_cap_ibs, &vmstate_spapr_irq_map, &vmstate_spapr_cap_nested_kvm_hv, + &vmstate_spapr_dtb, NULL } }; @@ -2466,15 +2518,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. */ @@ -2510,6 +2557,17 @@ static void spapr_init_cpus(sPAPRMachineState *spapr) } } +static PCIHostState *spapr_create_default_phb(void) +{ + DeviceState *dev; + + dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE); + qdev_prop_set_uint32(dev, "index", 0); + qdev_init_nofail(dev); + + return PCI_HOST_BRIDGE(dev); +} + /* pSeries LPAR / sPAPR hardware init */ static void spapr_machine_init(MachineState *machine) { @@ -2593,8 +2651,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 +2685,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 | SPAPR_OV5_XIVE_BOTH)) { + 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 if (spapr->irq->ov5 & SPAPR_OV5_XIVE_EXPLOIT) { + error_report("XIVE-only machines require a POWER9 CPU"); + exit(1); + } + } + /* init CPUs */ spapr_init_cpus(spapr); @@ -2725,7 +2800,7 @@ static void spapr_machine_init(MachineState *machine) /* Set up PCI */ spapr_pci_rtas_init(); - phb = spapr_create_phb(spapr, 0); + phb = spapr_create_default_phb(); for (i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; @@ -3031,9 +3106,42 @@ 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"); + } else if (spapr->irq == &spapr_irq_dual) { + return g_strdup("dual"); + } + 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 if (strcmp(value, "dual") == 0) { + spapr->irq = &spapr_irq_dual; + } 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 +3175,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, dual)", + NULL); } static void spapr_machine_finalizefn(Object *obj) @@ -3733,8 +3849,6 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, * 1TiB 64-bit MMIO windows for each PHB. */ const uint64_t base_buid = 0x800000020000000ULL; -#define SPAPR_MAX_PHBS ((SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / \ - SPAPR_PCI_MEM64_WIN_SIZE - 1) int i; /* Sanity check natural alignments */ @@ -3782,16 +3896,15 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id) { PowerPCCPU *cpu = spapr_find_cpu(vcpu_id); - return cpu ? ICP(cpu->intc) : NULL; + return cpu ? cpu->icp : NULL; } 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 +3986,8 @@ 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"); + smc->update_dt_enabled = true; + 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; @@ -3939,16 +4053,10 @@ static const TypeInfo spapr_machine_info = { mc->is_default = 1; \ } \ } \ - static void spapr_machine_##suffix##_instance_init(Object *obj) \ - { \ - MachineState *machine = MACHINE(obj); \ - spapr_machine_##suffix##_instance_options(machine); \ - } \ static const TypeInfo spapr_machine_##suffix##_info = { \ .name = MACHINE_TYPE_NAME("pseries-" verstr), \ .parent = TYPE_SPAPR_MACHINE, \ .class_init = spapr_machine_##suffix##_class_init, \ - .instance_init = spapr_machine_##suffix##_instance_init, \ }; \ static void spapr_machine_register_##suffix(void) \ { \ @@ -3956,37 +4064,41 @@ static const TypeInfo spapr_machine_info = { } \ type_init(spapr_machine_register_##suffix) - /* - * pseries-3.1 +/* + * pseries-4.0 */ -static void spapr_machine_3_1_instance_options(MachineState *machine) +static void spapr_machine_4_0_class_options(MachineClass *mc) { + /* Defaults for the latest behaviour inherited from the base class */ } +DEFINE_SPAPR_MACHINE(4_0, "4.0", true); + +/* + * pseries-3.1 + */ static void spapr_machine_3_1_class_options(MachineClass *mc) { - /* Defaults for the latest behaviour inherited from the base class */ + sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + + spapr_machine_4_0_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len); + mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0"); + smc->update_dt_enabled = false; } -DEFINE_SPAPR_MACHINE(3_1, "3.1", true); +DEFINE_SPAPR_MACHINE(3_1, "3.1", false); /* * pseries-3.0 */ -#define SPAPR_COMPAT_3_0 \ - HW_COMPAT_3_0 - -static void spapr_machine_3_0_instance_options(MachineState *machine) -{ - spapr_machine_3_1_instance_options(machine); -} static void spapr_machine_3_0_class_options(MachineClass *mc) { sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); spapr_machine_3_1_class_options(mc); - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_3_0); + compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len); smc->legacy_irq_allocation = true; smc->irq = &spapr_irq_xics_legacy; @@ -3997,30 +4109,17 @@ DEFINE_SPAPR_MACHINE(3_0, "3.0", false); /* * pseries-2.12 */ -#define SPAPR_COMPAT_2_12 \ - HW_COMPAT_2_12 \ - { \ - .driver = TYPE_POWERPC_CPU, \ - .property = "pre-3.0-migration", \ - .value = "on", \ - }, \ - { \ - .driver = TYPE_SPAPR_CPU_CORE, \ - .property = "pre-3.0-migration", \ - .value = "on", \ - }, - -static void spapr_machine_2_12_instance_options(MachineState *machine) -{ - spapr_machine_3_0_instance_options(machine); -} - static void spapr_machine_2_12_class_options(MachineClass *mc) { sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + static GlobalProperty compat[] = { + { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" }, + { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" }, + }; spapr_machine_3_0_class_options(mc); - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_12); + compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); /* We depend on kvm_enabled() to choose a default value for the * hpt-max-page-size capability. Of course we can't do it here @@ -4032,11 +4131,6 @@ static void spapr_machine_2_12_class_options(MachineClass *mc) DEFINE_SPAPR_MACHINE(2_12, "2.12", false); -static void spapr_machine_2_12_sxxm_instance_options(MachineState *machine) -{ - spapr_machine_2_12_instance_options(machine); -} - static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc) { sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); @@ -4052,13 +4146,6 @@ DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false); /* * pseries-2.11 */ -#define SPAPR_COMPAT_2_11 \ - HW_COMPAT_2_11 - -static void spapr_machine_2_11_instance_options(MachineState *machine) -{ - spapr_machine_2_12_instance_options(machine); -} static void spapr_machine_2_11_class_options(MachineClass *mc) { @@ -4066,7 +4153,7 @@ static void spapr_machine_2_11_class_options(MachineClass *mc) spapr_machine_2_12_class_options(mc); smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON; - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_11); + compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len); } DEFINE_SPAPR_MACHINE(2_11, "2.11", false); @@ -4074,18 +4161,11 @@ DEFINE_SPAPR_MACHINE(2_11, "2.11", false); /* * pseries-2.10 */ -#define SPAPR_COMPAT_2_10 \ - HW_COMPAT_2_10 - -static void spapr_machine_2_10_instance_options(MachineState *machine) -{ - spapr_machine_2_11_instance_options(machine); -} static void spapr_machine_2_10_class_options(MachineClass *mc) { spapr_machine_2_11_class_options(mc); - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_10); + compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len); } DEFINE_SPAPR_MACHINE(2_10, "2.10", false); @@ -4093,25 +4173,17 @@ DEFINE_SPAPR_MACHINE(2_10, "2.10", false); /* * pseries-2.9 */ -#define SPAPR_COMPAT_2_9 \ - HW_COMPAT_2_9 \ - { \ - .driver = TYPE_POWERPC_CPU, \ - .property = "pre-2.10-migration", \ - .value = "on", \ - }, \ - -static void spapr_machine_2_9_instance_options(MachineState *machine) -{ - spapr_machine_2_10_instance_options(machine); -} static void spapr_machine_2_9_class_options(MachineClass *mc) { sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + static GlobalProperty compat[] = { + { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" }, + }; spapr_machine_2_10_class_options(mc); - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_9); + compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram; smc->pre_2_10_has_unused_icps = true; smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED; @@ -4122,23 +4194,16 @@ DEFINE_SPAPR_MACHINE(2_9, "2.9", false); /* * pseries-2.8 */ -#define SPAPR_COMPAT_2_8 \ - HW_COMPAT_2_8 \ - { \ - .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ - .property = "pcie-extended-configuration-space", \ - .value = "off", \ - }, - -static void spapr_machine_2_8_instance_options(MachineState *machine) -{ - spapr_machine_2_9_instance_options(machine); -} static void spapr_machine_2_8_class_options(MachineClass *mc) { + static GlobalProperty compat[] = { + { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" }, + }; + spapr_machine_2_9_class_options(mc); - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_8); + compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); mc->numa_mem_align_shift = 23; } @@ -4147,28 +4212,6 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", false); /* * pseries-2.7 */ -#define SPAPR_COMPAT_2_7 \ - HW_COMPAT_2_7 \ - { \ - .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ - .property = "mem_win_size", \ - .value = stringify(SPAPR_PCI_2_7_MMIO_WIN_SIZE),\ - }, \ - { \ - .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ - .property = "mem64_win_size", \ - .value = "0", \ - }, \ - { \ - .driver = TYPE_POWERPC_CPU, \ - .property = "pre-2.8-migration", \ - .value = "on", \ - }, \ - { \ - .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ - .property = "pre-2.8-migration", \ - .value = "on", \ - }, static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index, uint64_t *buid, hwaddr *pio, @@ -4219,21 +4262,21 @@ static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index, */ } -static void spapr_machine_2_7_instance_options(MachineState *machine) -{ - sPAPRMachineState *spapr = SPAPR_MACHINE(machine); - - spapr_machine_2_8_instance_options(machine); - spapr->use_hotplug_event_source = false; -} - static void spapr_machine_2_7_class_options(MachineClass *mc) { sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + static GlobalProperty compat[] = { + { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", }, + { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", }, + { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", }, + { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", }, + }; spapr_machine_2_8_class_options(mc); mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3"); - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_7); + mc->default_machine_opts = "modern-hotplug-events=off"; + compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); smc->phb_placement = phb_placement_2_7; } @@ -4242,24 +4285,17 @@ DEFINE_SPAPR_MACHINE(2_7, "2.7", false); /* * pseries-2.6 */ -#define SPAPR_COMPAT_2_6 \ - HW_COMPAT_2_6 \ - { \ - .driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\ - .property = "ddw",\ - .value = stringify(off),\ - }, - -static void spapr_machine_2_6_instance_options(MachineState *machine) -{ - spapr_machine_2_7_instance_options(machine); -} static void spapr_machine_2_6_class_options(MachineClass *mc) { + static GlobalProperty compat[] = { + { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" }, + }; + spapr_machine_2_7_class_options(mc); mc->has_hotpluggable_cpus = false; - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_6); + compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); } DEFINE_SPAPR_MACHINE(2_6, "2.6", false); @@ -4267,26 +4303,18 @@ DEFINE_SPAPR_MACHINE(2_6, "2.6", false); /* * pseries-2.5 */ -#define SPAPR_COMPAT_2_5 \ - HW_COMPAT_2_5 \ - { \ - .driver = "spapr-vlan", \ - .property = "use-rx-buffer-pools", \ - .value = "off", \ - }, - -static void spapr_machine_2_5_instance_options(MachineState *machine) -{ - spapr_machine_2_6_instance_options(machine); -} static void spapr_machine_2_5_class_options(MachineClass *mc) { sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + static GlobalProperty compat[] = { + { "spapr-vlan", "use-rx-buffer-pools", "off" }, + }; spapr_machine_2_6_class_options(mc); smc->use_ohci_by_default = true; - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_5); + compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); } DEFINE_SPAPR_MACHINE(2_5, "2.5", false); @@ -4294,13 +4322,6 @@ DEFINE_SPAPR_MACHINE(2_5, "2.5", false); /* * pseries-2.4 */ -#define SPAPR_COMPAT_2_4 \ - HW_COMPAT_2_4 - -static void spapr_machine_2_4_instance_options(MachineState *machine) -{ - spapr_machine_2_5_instance_options(machine); -} static void spapr_machine_2_4_class_options(MachineClass *mc) { @@ -4308,7 +4329,7 @@ static void spapr_machine_2_4_class_options(MachineClass *mc) spapr_machine_2_5_class_options(mc); smc->dr_lmb_enabled = false; - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_4); + compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len); } DEFINE_SPAPR_MACHINE(2_4, "2.4", false); @@ -4316,23 +4337,15 @@ DEFINE_SPAPR_MACHINE(2_4, "2.4", false); /* * pseries-2.3 */ -#define SPAPR_COMPAT_2_3 \ - HW_COMPAT_2_3 \ - {\ - .driver = "spapr-pci-host-bridge",\ - .property = "dynamic-reconfiguration",\ - .value = "off",\ - }, - -static void spapr_machine_2_3_instance_options(MachineState *machine) -{ - spapr_machine_2_4_instance_options(machine); -} static void spapr_machine_2_3_class_options(MachineClass *mc) { + static GlobalProperty compat[] = { + { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" }, + }; spapr_machine_2_4_class_options(mc); - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_3); + compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); } DEFINE_SPAPR_MACHINE(2_3, "2.3", false); @@ -4340,42 +4353,27 @@ DEFINE_SPAPR_MACHINE(2_3, "2.3", false); * pseries-2.2 */ -#define SPAPR_COMPAT_2_2 \ - HW_COMPAT_2_2 \ - {\ - .driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\ - .property = "mem_win_size",\ - .value = "0x20000000",\ - }, - -static void spapr_machine_2_2_instance_options(MachineState *machine) -{ - spapr_machine_2_3_instance_options(machine); - machine->suppress_vmdesc = true; -} - static void spapr_machine_2_2_class_options(MachineClass *mc) { + static GlobalProperty compat[] = { + { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" }, + }; + spapr_machine_2_3_class_options(mc); - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_2); + compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); + mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on"; } DEFINE_SPAPR_MACHINE(2_2, "2.2", false); /* * pseries-2.1 */ -#define SPAPR_COMPAT_2_1 \ - HW_COMPAT_2_1 - -static void spapr_machine_2_1_instance_options(MachineState *machine) -{ - spapr_machine_2_2_instance_options(machine); -} static void spapr_machine_2_1_class_options(MachineClass *mc) { spapr_machine_2_2_class_options(mc); - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_1); + compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len); } DEFINE_SPAPR_MACHINE(2_1, "2.1", false); diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 2398ce62c0..0405306d1e 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -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" @@ -195,7 +194,12 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc) vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data); } qemu_unregister_reset(spapr_cpu_reset, cpu); - object_unparent(cpu->intc); + if (cpu->icp) { + object_unparent(OBJECT(cpu->icp)); + } + if (cpu->tctx) { + object_unparent(OBJECT(cpu->tctx)); + } cpu_remove_sync(CPU(cpu)); object_unparent(OBJECT(cpu)); } @@ -233,8 +237,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); + spapr->irq->cpu_intc_create(spapr, cpu, &local_err); if (local_err) { goto error_unregister; } diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index ae913d070f..17bcaa3822 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1654,6 +1654,17 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, (spapr_h_cas_compose_response(spapr, args[1], args[2], ov5_updates) != 0); } + + /* + * Generate a machine reset when we have an update of the + * interrupt mode. Only required when the machine supports both + * modes. + */ + if (!spapr->cas_reboot) { + spapr->cas_reboot = spapr_ovec_test(ov5_updates, OV5_XIVE_EXPLOIT) + && spapr->irq->ov5 & SPAPR_OV5_XIVE_BOTH; + } + spapr_ovec_cleanup(ov5_updates); if (spapr->cas_reboot) { @@ -1663,6 +1674,42 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, return H_SUCCESS; } +static target_ulong h_home_node_associativity(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong procno = args[1]; + PowerPCCPU *tcpu; + int idx; + + /* only support procno from H_REGISTER_VPA */ + if (flags != 0x1) { + return H_FUNCTION; + } + + tcpu = spapr_find_cpu(procno); + if (tcpu == NULL) { + return H_P2; + } + + /* sequence is the same as in the "ibm,associativity" property */ + + idx = 0; +#define ASSOCIATIVITY(a, b) (((uint64_t)(a) << 32) | \ + ((uint64_t)(b) & 0xffffffff)) + args[idx++] = ASSOCIATIVITY(0, 0); + args[idx++] = ASSOCIATIVITY(0, tcpu->node_id); + args[idx++] = ASSOCIATIVITY(procno, -1); + for ( ; idx < 6; idx++) { + args[idx] = -1; + } +#undef ASSOCIATIVITY + + return H_SUCCESS; +} + static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, @@ -1717,6 +1764,46 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu, args[0] = characteristics; args[1] = behaviour; + return H_SUCCESS; +} + +static target_ulong h_update_dt(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong dt = ppc64_phys_to_real(args[0]); + struct fdt_header hdr = { 0 }; + unsigned cb; + sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + void *fdt; + + cpu_physical_memory_read(dt, &hdr, sizeof(hdr)); + cb = fdt32_to_cpu(hdr.totalsize); + + if (!smc->update_dt_enabled) { + return H_SUCCESS; + } + + /* Check that the fdt did not grow out of proportion */ + if (cb > spapr->fdt_initial_size * 2) { + trace_spapr_update_dt_failed_size(spapr->fdt_initial_size, cb, + fdt32_to_cpu(hdr.magic)); + return H_PARAMETER; + } + + fdt = g_malloc0(cb); + cpu_physical_memory_read(dt, fdt, cb); + + /* Check the fdt consistency */ + if (fdt_check_full(fdt, cb)) { + trace_spapr_update_dt_failed_check(spapr->fdt_initial_size, cb, + fdt32_to_cpu(hdr.magic)); + return H_PARAMETER; + } + + g_free(spapr->fdt_blob); + spapr->fdt_size = cb; + spapr->fdt_blob = fdt; + trace_spapr_update_dt(cb); return H_SUCCESS; } @@ -1822,6 +1909,12 @@ static void hypercall_register_types(void) /* ibm,client-architecture-support support */ spapr_register_hypercall(KVMPPC_H_CAS, h_client_architecture_support); + + spapr_register_hypercall(KVMPPC_H_UPDATE_DT, h_update_dt); + + /* Virtual Processor Home Node */ + spapr_register_hypercall(H_HOME_NODE_ASSOCIATIVITY, + h_home_node_associativity); } type_init(hypercall_register_types) diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 1b0880ac9e..37e98f9321 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -42,7 +42,7 @@ enum sPAPRTCEAccess { #define IOMMU_PAGE_SIZE(shift) (1ULL << (shift)) #define IOMMU_PAGE_MASK(shift) (~(IOMMU_PAGE_SIZE(shift) - 1)) -static QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables; +static QLIST_HEAD(, sPAPRTCETable) spapr_tce_tables; sPAPRTCETable *spapr_tce_find_by_liobn(target_ulong liobn) { @@ -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); diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index e77b94cc68..1da7a32348 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -12,7 +12,9 @@ #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 "hw/ppc/xics_spapr.h" #include "sysemu/kvm.h" #include "trace.h" @@ -93,15 +95,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)) { @@ -176,7 +172,7 @@ static qemu_irq spapr_qirq_xics(sPAPRMachineState *spapr, int irq) uint32_t srcno = irq - ics->offset; if (ics_valid_irq(ics, irq)) { - return ics->qirqs[srcno]; + return spapr->qirqs[srcno]; } return NULL; @@ -189,12 +185,57 @@ static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon) CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); - icp_pic_print_info(ICP(cpu->intc), mon); + icp_pic_print_info(cpu->icp, mon); } ics_pic_print_info(spapr->ics, mon); } +static void spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr, + PowerPCCPU *cpu, Error **errp) +{ + Error *local_err = NULL; + Object *obj; + + obj = icp_create(OBJECT(cpu), spapr->icp_type, XICS_FABRIC(spapr), + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + cpu->icp = ICP(obj); +} + +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(cpu->icp); + } + } + return 0; +} + +static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val) +{ + sPAPRMachineState *spapr = opaque; + MachineState *machine = MACHINE(opaque); + + if (kvm_enabled() && machine_kernel_irqchip_allowed(machine)) { + ics_kvm_set_irq(spapr->ics, srcno, val); + } else { + ics_simple_set_irq(spapr->ics, srcno, val); + } +} + +static void spapr_irq_reset_xics(sPAPRMachineState *spapr, Error **errp) +{ + /* TODO: create the KVM XICS device */ +} + #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 +243,396 @@ 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, + .reset = spapr_irq_reset_xics, + .set_irq = spapr_irq_set_irq_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) +{ + sPAPRXive *xive = spapr->xive; + + if (irq >= xive->nr_irqs) { + return NULL; + } + + /* The sPAPR machine/device should have claimed the IRQ before */ + assert(xive_eas_is_valid(&xive->eat[irq])); + + return spapr->qirqs[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(cpu->tctx, mon); + } + + spapr_xive_pic_print_info(spapr->xive, mon); +} + +static void spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr, + PowerPCCPU *cpu, Error **errp) +{ + Error *local_err = NULL; + Object *obj; + + obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(spapr->xive), &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + cpu->tctx = XIVE_TCTX(obj); + + /* + * (TCG) Early setting the OS CAM line for hotplugged CPUs as they + * don't beneficiate from the reset of the XIVE IRQ backend + */ + spapr_xive_set_tctx_os_cam(cpu->tctx); +} + +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(cpu->tctx); + } + + /* Activate the XIVE MMIOs */ + spapr_xive_mmio_set_enabled(spapr->xive, true); +} + +static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val) +{ + sPAPRMachineState *spapr = opaque; + + xive_source_set_irq(&spapr->xive->source, srcno, val); +} + +/* + * 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, + .set_irq = spapr_irq_set_irq_xive, +}; + +/* + * Dual XIVE and XICS IRQ backend. + * + * Both interrupt mode, XIVE and XICS, objects are created but the + * machine starts in legacy interrupt mode (XICS). It can be changed + * by the CAS negotiation process and, in that case, the new mode is + * activated after an extra machine reset. + */ + +/* + * Returns the sPAPR IRQ backend negotiated by CAS. XICS is the + * default. + */ +static sPAPRIrq *spapr_irq_current(sPAPRMachineState *spapr) +{ + return spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT) ? + &spapr_irq_xive : &spapr_irq_xics; +} + +static void spapr_irq_init_dual(sPAPRMachineState *spapr, Error **errp) +{ + MachineState *machine = MACHINE(spapr); + Error *local_err = NULL; + + if (kvm_enabled() && machine_kernel_irqchip_allowed(machine)) { + error_setg(errp, "No KVM support for the 'dual' machine"); + return; + } + + spapr_irq_xics.init(spapr, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + /* + * Align the XICS and the XIVE IRQ number space under QEMU. + * + * However, the XICS KVM device still considers that the IRQ + * numbers should start at XICS_IRQ_BASE (0x1000). Either we + * should introduce a KVM device ioctl to set the offset or ignore + * the lower 4K numbers when using the get/set ioctl of the XICS + * KVM device. The second option seems the least intrusive. + */ + spapr->ics->offset = 0; + + spapr_irq_xive.init(spapr, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } +} + +static int spapr_irq_claim_dual(sPAPRMachineState *spapr, int irq, bool lsi, + Error **errp) +{ + Error *local_err = NULL; + int ret; + + ret = spapr_irq_xics.claim(spapr, irq, lsi, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return ret; + } + + ret = spapr_irq_xive.claim(spapr, irq, lsi, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return ret; + } + + return ret; +} + +static void spapr_irq_free_dual(sPAPRMachineState *spapr, int irq, int num) +{ + spapr_irq_xics.free(spapr, irq, num); + spapr_irq_xive.free(spapr, irq, num); +} + +static qemu_irq spapr_qirq_dual(sPAPRMachineState *spapr, int irq) +{ + sPAPRXive *xive = spapr->xive; + ICSState *ics = spapr->ics; + + if (irq >= spapr->irq->nr_irqs) { + return NULL; + } + + /* + * The IRQ number should have been claimed under both interrupt + * controllers. + */ + assert(!ICS_IRQ_FREE(ics, irq - ics->offset)); + assert(xive_eas_is_valid(&xive->eat[irq])); + + return spapr->qirqs[irq]; +} + +static void spapr_irq_print_info_dual(sPAPRMachineState *spapr, Monitor *mon) +{ + spapr_irq_current(spapr)->print_info(spapr, mon); +} + +static void spapr_irq_dt_populate_dual(sPAPRMachineState *spapr, + uint32_t nr_servers, void *fdt, + uint32_t phandle) +{ + spapr_irq_current(spapr)->dt_populate(spapr, nr_servers, fdt, phandle); +} + +static void spapr_irq_cpu_intc_create_dual(sPAPRMachineState *spapr, + PowerPCCPU *cpu, Error **errp) +{ + Error *local_err = NULL; + + spapr_irq_xive.cpu_intc_create(spapr, cpu, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + spapr_irq_xics.cpu_intc_create(spapr, cpu, errp); +} + +static int spapr_irq_post_load_dual(sPAPRMachineState *spapr, int version_id) +{ + /* + * Force a reset of the XIVE backend after migration. The machine + * defaults to XICS at startup. + */ + if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + spapr_irq_xive.reset(spapr, &error_fatal); + } + + return spapr_irq_current(spapr)->post_load(spapr, version_id); +} + +static void spapr_irq_reset_dual(sPAPRMachineState *spapr, Error **errp) +{ + /* + * Deactivate the XIVE MMIOs. The XIVE backend will reenable them + * if selected. + */ + spapr_xive_mmio_set_enabled(spapr->xive, false); + + spapr_irq_current(spapr)->reset(spapr, errp); +} + +static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val) +{ + sPAPRMachineState *spapr = opaque; + + spapr_irq_current(spapr)->set_irq(spapr, srcno, val); +} + +/* + * Define values in sync with the XIVE and XICS backend + */ +#define SPAPR_IRQ_DUAL_NR_IRQS 0x2000 +#define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI) + +sPAPRIrq spapr_irq_dual = { + .nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS, + .nr_msis = SPAPR_IRQ_DUAL_NR_MSIS, + .ov5 = SPAPR_OV5_XIVE_BOTH, + + .init = spapr_irq_init_dual, + .claim = spapr_irq_claim_dual, + .free = spapr_irq_free_dual, + .qirq = spapr_qirq_dual, + .print_info = spapr_irq_print_info_dual, + .dt_populate = spapr_irq_dt_populate_dual, + .cpu_intc_create = spapr_irq_cpu_intc_create_dual, + .post_load = spapr_irq_post_load_dual, + .reset = spapr_irq_reset_dual, + .set_irq = spapr_irq_set_irq_dual }; /* * 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); + + spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, + spapr->irq->nr_irqs); +} 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); +} + +int spapr_irq_post_load(sPAPRMachineState *spapr, int version_id) +{ + return spapr->irq->post_load(spapr, version_id); +} - return smc->irq->qirq(spapr, irq); +void spapr_irq_reset(sPAPRMachineState *spapr, Error **errp) +{ + if (spapr->irq->reset) { + spapr->irq->reset(spapr, errp); + } } /* @@ -295,10 +695,15 @@ 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, + .set_irq = spapr_irq_set_irq_xics, }; diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 2374d55fc1..b74f2632ec 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1370,18 +1370,9 @@ static int spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev, /* Callback to be called during DRC release. */ void spapr_phb_remove_pci_device_cb(DeviceState *dev) { - /* some version guests do not wait for completion of a device - * cleanup (generally done asynchronously by the kernel) before - * signaling to QEMU that the device is safe, but instead sleep - * for some 'safe' period of time. unfortunately on a busy host - * this sleep isn't guaranteed to be long enough, resulting in - * bad things like IRQ lines being left asserted during final - * device removal. to deal with this we call reset just prior - * to finalizing the device, which will put the device back into - * an 'idle' state, as the device cleanup code expects. - */ - pci_device_reset(PCI_DEVICE(dev)); - object_unparent(OBJECT(dev)); + HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev); + + hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort); } static sPAPRDRConnector *spapr_phb_get_pci_func_drc(sPAPRPHBState *phb, @@ -1490,6 +1481,23 @@ out: } } +static void spapr_pci_unplug(HotplugHandler *plug_handler, + DeviceState *plugged_dev, Error **errp) +{ + /* some version guests do not wait for completion of a device + * cleanup (generally done asynchronously by the kernel) before + * signaling to QEMU that the device is safe, but instead sleep + * for some 'safe' period of time. unfortunately on a busy host + * this sleep isn't guaranteed to be long enough, resulting in + * bad things like IRQ lines being left asserted during final + * device removal. to deal with this we call reset just prior + * to finalizing the device, which will put the device back into + * an 'idle' state, as the device cleanup code expects. + */ + pci_device_reset(PCI_DEVICE(plugged_dev)); + object_unparent(OBJECT(plugged_dev)); +} + static void spapr_pci_unplug_request(HotplugHandler *plug_handler, DeviceState *plugged_dev, Error **errp) { @@ -1965,6 +1973,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data) dc->user_creatable = true; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); hp->plug = spapr_pci_plug; + hp->unplug = spapr_pci_unplug; hp->unplug_request = spapr_pci_unplug_request; } @@ -1979,17 +1988,6 @@ static const TypeInfo spapr_phb_info = { } }; -PCIHostState *spapr_create_phb(sPAPRMachineState *spapr, int index) -{ - DeviceState *dev; - - dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE); - qdev_prop_set_uint32(dev, "index", index); - qdev_init_nofail(dev); - - return PCI_HOST_BRIDGE(dev); -} - typedef struct sPAPRFDT { void *fdt; int node_off; diff --git a/hw/ppc/spapr_rtas_ddw.c b/hw/ppc/spapr_rtas_ddw.c index 329feb148f..cb8a410359 100644 --- a/hw/ppc/spapr_rtas_ddw.c +++ b/hw/ppc/spapr_rtas_ddw.c @@ -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: diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 840d4a3c45..7e8a9ad093 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -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; diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index dc5e65aee9..0af155ed32 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -22,6 +22,9 @@ spapr_cas_pvr_try(uint32_t pvr) "0x%x" spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=0x%x, explicit_match=%u, new=0x%x" spapr_h_resize_hpt_prepare(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64 spapr_h_resize_hpt_commit(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64 +spapr_update_dt(unsigned cb) "New blob %u bytes" +spapr_update_dt_failed_size(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x" +spapr_update_dt_failed_check(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x" # hw/ppc/spapr_iommu.c spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=0x%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64 diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index ee9b4b4490..5177120574 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -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); |