diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-09-03 17:20:39 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-09-03 17:20:40 +0100 |
commit | 3b3f0646a40b0a6e30817f931cafefe743fb0c33 (patch) | |
tree | 3c5a045b2defdd5e52d95d4f37233942cc0488a5 | |
parent | 3483534ec314f6057e66966bfceaa9df02c28fbf (diff) | |
parent | b1e815674343a171e51ce447495957e289091e9f (diff) |
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-4.2-20190829' into staging
ppc patch queue 2018-08-29
Another pull request for ppc-for-4.2. Includes
* Several powernv patches which were pulled last minute from the
last PULL, now that some problems with them have been sorted out
* A fix for -no-reboot which has been broken since the
pseries-rhel4.1.0 machine type
* Add some host threads information which AIX guests will need to
properly scale the PURR and SPURR
* Change behaviour to match x86 when unplugging function 0 of a
multifunction PCI device
* A number of TCG fixes in FPU emulation
And a handful of other assorted fixes and cleanups.
# gpg: Signature made Thu 29 Aug 2019 06:36:23 BST
# gpg: using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full]
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full]
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full]
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown]
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-4.2-20190829:
spapr: Set compat mode in spapr_core_plug()
spapr/pci: Convert types to QEMU coding style
spapr_pci: Advertise BAR reallocation capability
spapr: Use SHUTDOWN_CAUSE_SUBSYSTEM_RESET for CAS reboots
powerpc/spapr: Add host threads parameter to ibm,get_system_parameter
pseries: Update SLOF firmware image
target/ppc: Refactor emulation of vmrgew and vmrgow instructions
target/ppc: Fix do_float_check_status vs inexact
target/ppc: Set float_tininess_before_rounding at cpu reset
pseries: Fix compat_pvr on reset
spapr_pci: remove all child functions in function zero unplug
ppc: Fix xscvdpspn for SNAN
ppc: Fix xsmaddmdp and friends
tests/boot-serial-test: add support for all the PowerNV machines
ppc/pnv: Introduce PowerNV machines with fixed CPU models
ppc/pnv: Generate phandle for the "interrupt-parent" property
ppc/pnv: add more dummy XSCOM addresses for the P9 CAPP
ppc/pnv: update skiboot to v6.4
ppc/pnv: Set default ram size to 1.75GB
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/ppc/pnv.c | 81 | ||||
-rw-r--r-- | hw/ppc/pnv_xscom.c | 20 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 29 | ||||
-rw-r--r-- | hw/ppc/spapr_cpu_core.c | 5 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 2 | ||||
-rw-r--r-- | hw/ppc/spapr_pci.c | 40 | ||||
-rw-r--r-- | hw/ppc/spapr_pci_nvlink2.c | 40 | ||||
-rw-r--r-- | hw/ppc/spapr_rtas.c | 15 | ||||
-rw-r--r-- | include/hw/pci-host/spapr.h | 24 | ||||
-rw-r--r-- | include/hw/ppc/spapr.h | 1 | ||||
-rw-r--r-- | pc-bios/README | 2 | ||||
-rw-r--r-- | pc-bios/skiboot.lid | bin | 1591384 -> 1667280 bytes | |||
-rw-r--r-- | pc-bios/slof.bin | bin | 926784 -> 930656 bytes | |||
m--------- | roms/SLOF | 0 | ||||
m--------- | roms/skiboot | 0 | ||||
-rw-r--r-- | target/ppc/cpu-qom.h | 1 | ||||
-rw-r--r-- | target/ppc/fpu_helper.c | 42 | ||||
-rw-r--r-- | target/ppc/translate/vmx-impl.inc.c | 66 | ||||
-rw-r--r-- | target/ppc/translate/vsx-impl.inc.c | 2 | ||||
-rw-r--r-- | target/ppc/translate_init.inc.c | 6 | ||||
-rw-r--r-- | tests/boot-serial-test.c | 3 | ||||
-rw-r--r-- | tests/pnv-xscom-test.c | 16 |
22 files changed, 287 insertions, 108 deletions
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index d95086fbbd..3f08db7b9e 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -434,9 +434,14 @@ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt) .fdt = fdt, .offset = isa_offset, }; + uint32_t phandle; _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0))); + phandle = qemu_fdt_alloc_phandle(fdt); + assert(phandle > 0); + _FDT((fdt_setprop_cell(fdt, isa_offset, "phandle", phandle))); + /* ISA devices are not necessarily parented to the ISA bus so we * can not use object_child_foreach() */ qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL, @@ -600,9 +605,20 @@ static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon) pnv_psi_pic_print_info(&chip9->psi, mon); } +static bool pnv_match_cpu(const char *default_type, const char *cpu_type) +{ + PowerPCCPUClass *ppc_default = + POWERPC_CPU_CLASS(object_class_by_name(default_type)); + PowerPCCPUClass *ppc = + POWERPC_CPU_CLASS(object_class_by_name(cpu_type)); + + return ppc_default->pvr_match(ppc_default, ppc->pvr); +} + static void pnv_init(MachineState *machine) { PnvMachineState *pnv = PNV_MACHINE(machine); + MachineClass *mc = MACHINE_GET_CLASS(machine); MemoryRegion *ram; char *fw_filename; long fw_size; @@ -662,13 +678,23 @@ static void pnv_init(MachineState *machine) } } + /* + * Check compatibility of the specified CPU with the machine + * default. + */ + if (!pnv_match_cpu(mc->default_cpu_type, machine->cpu_type)) { + error_report("invalid CPU model '%s' for %s machine", + machine->cpu_type, mc->name); + exit(1); + } + /* Create the processor chips */ i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX); chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"), i, machine->cpu_type); if (!object_class_by_name(chip_typename)) { - error_report("invalid CPU model '%.*s' for %s machine", - i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name); + error_report("invalid chip model '%.*s' for %s machine", + i, machine->cpu_type, mc->name); exit(1); } @@ -1346,25 +1372,47 @@ static void pnv_machine_class_props_init(ObjectClass *oc) NULL); } -static void pnv_machine_class_init(ObjectClass *oc, void *data) +static void pnv_machine_power8_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); XICSFabricClass *xic = XICS_FABRIC_CLASS(oc); + + mc->desc = "IBM PowerNV (Non-Virtualized) POWER8"; + mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0"); + + xic->icp_get = pnv_icp_get; + xic->ics_get = pnv_ics_get; + xic->ics_resend = pnv_ics_resend; +} + +static void pnv_machine_power9_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "IBM PowerNV (Non-Virtualized) POWER9"; + mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0"); + + mc->alias = "powernv"; +} + +static void pnv_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); mc->desc = "IBM PowerNV (Non-Virtualized)"; mc->init = pnv_init; mc->reset = pnv_reset; mc->max_cpus = MAX_CPUS; - mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0"); mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for * storage */ mc->no_parallel = 1; mc->default_boot_order = NULL; - mc->default_ram_size = 1 * GiB; - xic->icp_get = pnv_icp_get; - xic->ics_get = pnv_ics_get; - xic->ics_resend = pnv_ics_resend; + /* + * RAM defaults to less than 2048 for 32-bit hosts, and large + * enough to fit the maximum initrd size at it's load address + */ + mc->default_ram_size = INITRD_LOAD_ADDR + INITRD_MAX_SIZE; ispc->print_info = pnv_pic_print_info; pnv_machine_class_props_init(oc); @@ -1384,10 +1432,27 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data) .parent = TYPE_PNV9_CHIP, \ } +#define DEFINE_PNV_MACHINE_TYPE(cpu, class_initfn) \ + { \ + .name = MACHINE_TYPE_NAME(cpu), \ + .parent = TYPE_PNV_MACHINE, \ + .instance_size = sizeof(PnvMachineState), \ + .instance_init = pnv_machine_instance_init, \ + .class_init = class_initfn, \ + .interfaces = (InterfaceInfo[]) { \ + { TYPE_XICS_FABRIC }, \ + { TYPE_INTERRUPT_STATS_PROVIDER }, \ + { }, \ + }, \ + } + static const TypeInfo types[] = { + DEFINE_PNV_MACHINE_TYPE("powernv8", pnv_machine_power8_class_init), + DEFINE_PNV_MACHINE_TYPE("powernv9", pnv_machine_power9_class_init), { .name = TYPE_PNV_MACHINE, .parent = TYPE_MACHINE, + .abstract = true, .instance_size = sizeof(PnvMachineState), .instance_init = pnv_machine_instance_init, .class_init = pnv_machine_class_init, diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index 0e31c5786b..67aab98fef 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -106,6 +106,16 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba) case 0x201302a: /* CAPP stuff */ case 0x2013801: /* CAPP stuff */ case 0x2013802: /* CAPP stuff */ + + /* P9 CAPP regs */ + case 0x2010841: + case 0x2010842: + case 0x201082a: + case 0x2010828: + case 0x4010841: + case 0x4010842: + case 0x401082a: + case 0x4010828: return 0; default: return -1; @@ -138,6 +148,16 @@ static bool xscom_write_default(PnvChip *chip, uint32_t pcba, uint64_t val) case 0x2013801: /* CAPP stuff */ case 0x2013802: /* CAPP stuff */ + /* P9 CAPP regs */ + case 0x2010841: + case 0x2010842: + case 0x201082a: + case 0x2010828: + case 0x4010841: + case 0x4010842: + case 0x401082a: + case 0x4010828: + /* P8 PRD registers */ case PRD_P8_IPOLL_REG_MASK: case PRD_P8_IPOLL_REG_STATUS: diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index baedadf20b..ea56499b4b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1168,6 +1168,7 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt, static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt) { MachineState *machine = MACHINE(spapr); + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); int chosen; const char *boot_device = machine->boot_order; char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus); @@ -1225,6 +1226,11 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt) _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path)); } + /* We can deal with BAR reallocation just fine, advertise it to the guest */ + if (smc->linux_pci_probe) { + _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0)); + } + spapr_dt_ov5_platform_support(spapr, fdt, chosen); g_free(stdout_path); @@ -1752,7 +1758,7 @@ static void spapr_machine_reset(MachineState *machine) spapr_ovec_cleanup(spapr->ov5_cas); spapr->ov5_cas = spapr_ovec_new(); - ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal); + ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal); } /* @@ -3829,6 +3835,7 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, CPUArchId *core_slot; int index; bool hotplugged = spapr_drc_hotplugged(dev); + int i; core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index); if (!core_slot) { @@ -3862,13 +3869,26 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, core_slot->cpu = OBJECT(dev); if (smc->pre_2_10_has_unused_icps) { - int i; - for (i = 0; i < cc->nr_threads; i++) { cs = CPU(core->threads[i]); pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index); } } + + /* + * Set compatibility mode to match the boot CPU, which was either set + * by the machine reset code or by CAS. + */ + if (hotplugged) { + for (i = 0; i < cc->nr_threads; i++) { + ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } + } } static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, @@ -4470,6 +4490,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) spapr_caps_add_properties(smc, &error_abort); smc->irq = &spapr_irq_dual; smc->dr_phb_enabled = true; + smc->linux_pci_probe = true; } static const TypeInfo spapr_machine_info = { @@ -4529,12 +4550,14 @@ DEFINE_SPAPR_MACHINE(4_2, "4.2", true); */ static void spapr_machine_4_1_class_options(MachineClass *mc) { + SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc); static GlobalProperty compat[] = { /* Only allow 4kiB and 64kiB IOMMU pagesizes */ { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" }, }; spapr_machine_4_2_class_options(mc); + smc->linux_pci_probe = false; compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len); compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index bf47fbdf6f..1d93de8161 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -41,11 +41,6 @@ static void spapr_cpu_reset(void *opaque) * using an RTAS call */ cs->halted = 1; - /* Set compatibility mode to match the boot CPU, which was either set - * by the machine reset code or by CAS. This should never fail. - */ - ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &error_abort); - env->spr[SPR_HIOR] = 0; lpcr = env->spr[SPR_LPCR]; diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index e20a946b99..23e4bdb829 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1811,7 +1811,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, spapr_ovec_cleanup(ov5_updates); if (spapr->cas_reboot) { - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + qemu_system_reset_request(SHUTDOWN_CAUSE_SUBSYSTEM_RESET); } return H_SUCCESS; diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index deb0b0c80c..a777fb3e7f 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -280,7 +280,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr, unsigned int irq, max_irqs = 0; SpaprPhbState *phb = NULL; PCIDevice *pdev = NULL; - spapr_pci_msi *msi; + SpaprPciMsi *msi; int *config_addr_key; Error *err = NULL; int i; @@ -328,7 +328,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr, return; } - msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr); + msi = (SpaprPciMsi *) g_hash_table_lookup(phb->msi, &config_addr); /* Releasing MSIs */ if (!req_num) { @@ -415,7 +415,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr, irq, req_num); /* Add MSI device to cache */ - msi = g_new(spapr_pci_msi, 1); + msi = g_new(SpaprPciMsi, 1); msi->first_irq = irq; msi->num = req_num; config_addr_key = g_new(int, 1); @@ -446,7 +446,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu, unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3); SpaprPhbState *phb = NULL; PCIDevice *pdev = NULL; - spapr_pci_msi *msi; + SpaprPciMsi *msi; /* Find SpaprPhbState */ phb = spapr_pci_find_phb(spapr, buid); @@ -459,7 +459,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu, } /* Find device descriptor and start IRQ */ - msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr); + msi = (SpaprPciMsi *) g_hash_table_lookup(phb->msi, &config_addr); if (!msi || !msi->first_irq || !msi->num || (ioa_intr_num >= msi->num)) { trace_spapr_pci_msi("Failed to return vector", config_addr); rtas_st(rets, 0, RTAS_OUT_HW_ERROR); @@ -1700,11 +1700,13 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, state = func_drck->dr_entity_sense(func_drc); if (state == SPAPR_DR_ENTITY_SENSE_PRESENT && !spapr_drc_unplug_requested(func_drc)) { - error_setg(errp, - "PCI: slot %d, function %d still present. " - "Must unplug all non-0 functions first.", - slotnr, i); - return; + /* + * Attempting to remove function 0 of a multifunction + * device will will cascade into removing all child + * functions, even if their unplug weren't requested + * beforehand. + */ + spapr_drc_detach(func_drc); } } } @@ -1804,7 +1806,7 @@ static void spapr_phb_destroy_msi(gpointer opaque) { SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); - spapr_pci_msi *msi = opaque; + SpaprPciMsi *msi = opaque; if (!smc->legacy_irq_allocation) { spapr_irq_msi_free(spapr, msi->first_irq, msi->num); @@ -2118,7 +2120,7 @@ static const VMStateDescription vmstate_spapr_pci_lsi = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32_EQUAL(irq, struct spapr_pci_lsi, NULL), + VMSTATE_UINT32_EQUAL(irq, SpaprPciLsi, NULL), VMSTATE_END_OF_LIST() }, @@ -2129,9 +2131,9 @@ static const VMStateDescription vmstate_spapr_pci_msi = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField []) { - VMSTATE_UINT32(key, spapr_pci_msi_mig), - VMSTATE_UINT32(value.first_irq, spapr_pci_msi_mig), - VMSTATE_UINT32(value.num, spapr_pci_msi_mig), + VMSTATE_UINT32(key, SpaprPciMsiMig), + VMSTATE_UINT32(value.first_irq, SpaprPciMsiMig), + VMSTATE_UINT32(value.num, SpaprPciMsiMig), VMSTATE_END_OF_LIST() }, }; @@ -2163,12 +2165,12 @@ static int spapr_pci_pre_save(void *opaque) if (!sphb->msi_devs_num) { return 0; } - sphb->msi_devs = g_new(spapr_pci_msi_mig, sphb->msi_devs_num); + sphb->msi_devs = g_new(SpaprPciMsiMig, sphb->msi_devs_num); g_hash_table_iter_init(&iter, sphb->msi); for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) { sphb->msi_devs[i].key = *(uint32_t *) key; - sphb->msi_devs[i].value = *(spapr_pci_msi *) value; + sphb->msi_devs[i].value = *(SpaprPciMsi *) value; } return 0; @@ -2215,10 +2217,10 @@ static const VMStateDescription vmstate_spapr_pci = { VMSTATE_UINT64_TEST(mig_io_win_addr, SpaprPhbState, pre_2_8_migration), VMSTATE_UINT64_TEST(mig_io_win_size, SpaprPhbState, pre_2_8_migration), VMSTATE_STRUCT_ARRAY(lsi_table, SpaprPhbState, PCI_NUM_PINS, 0, - vmstate_spapr_pci_lsi, struct spapr_pci_lsi), + vmstate_spapr_pci_lsi, SpaprPciLsi), VMSTATE_INT32(msi_devs_num, SpaprPhbState), VMSTATE_STRUCT_VARRAY_ALLOC(msi_devs, SpaprPhbState, msi_devs_num, 0, - vmstate_spapr_pci_msi, spapr_pci_msi_mig), + vmstate_spapr_pci_msi, SpaprPciMsiMig), VMSTATE_END_OF_LIST() }, }; diff --git a/hw/ppc/spapr_pci_nvlink2.c b/hw/ppc/spapr_pci_nvlink2.c index eda8c752aa..4aa89ede23 100644 --- a/hw/ppc/spapr_pci_nvlink2.c +++ b/hw/ppc/spapr_pci_nvlink2.c @@ -39,11 +39,7 @@ #define SPAPR_GPU_NUMA_ID (cpu_to_be32(1)) -struct spapr_phb_pci_nvgpu_config { - uint64_t nv2_ram_current; - uint64_t nv2_atsd_current; - int num; /* number of non empty (i.e. tgt!=0) entries in slots[] */ - struct spapr_phb_pci_nvgpu_slot { +typedef struct SpaprPhbPciNvGpuSlot { uint64_t tgt; uint64_t gpa; unsigned numa_id; @@ -54,12 +50,18 @@ struct spapr_phb_pci_nvgpu_config { PCIDevice *npdev; uint32_t link_speed; } links[NVGPU_MAX_LINKS]; - } slots[NVGPU_MAX_NUM]; +} SpaprPhbPciNvGpuSlot; + +struct SpaprPhbPciNvGpuConfig { + uint64_t nv2_ram_current; + uint64_t nv2_atsd_current; + int num; /* number of non empty (i.e. tgt!=0) entries in slots[] */ + SpaprPhbPciNvGpuSlot slots[NVGPU_MAX_NUM]; Error *errp; }; -static struct spapr_phb_pci_nvgpu_slot * -spapr_nvgpu_get_slot(struct spapr_phb_pci_nvgpu_config *nvgpus, uint64_t tgt) +static SpaprPhbPciNvGpuSlot * +spapr_nvgpu_get_slot(SpaprPhbPciNvGpuConfig *nvgpus, uint64_t tgt) { int i; @@ -81,13 +83,13 @@ spapr_nvgpu_get_slot(struct spapr_phb_pci_nvgpu_config *nvgpus, uint64_t tgt) return &nvgpus->slots[i]; } -static void spapr_pci_collect_nvgpu(struct spapr_phb_pci_nvgpu_config *nvgpus, +static void spapr_pci_collect_nvgpu(SpaprPhbPciNvGpuConfig *nvgpus, PCIDevice *pdev, uint64_t tgt, MemoryRegion *mr, Error **errp) { MachineState *machine = MACHINE(qdev_get_machine()); SpaprMachineState *spapr = SPAPR_MACHINE(machine); - struct spapr_phb_pci_nvgpu_slot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt); + SpaprPhbPciNvGpuSlot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt); if (!nvslot) { error_setg(errp, "Found too many GPUs per vPHB"); @@ -102,11 +104,11 @@ static void spapr_pci_collect_nvgpu(struct spapr_phb_pci_nvgpu_config *nvgpus, ++spapr->gpu_numa_id; } -static void spapr_pci_collect_nvnpu(struct spapr_phb_pci_nvgpu_config *nvgpus, +static void spapr_pci_collect_nvnpu(SpaprPhbPciNvGpuConfig *nvgpus, PCIDevice *pdev, uint64_t tgt, MemoryRegion *mr, Error **errp) { - struct spapr_phb_pci_nvgpu_slot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt); + SpaprPhbPciNvGpuSlot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt); int j; if (!nvslot) { @@ -138,7 +140,7 @@ static void spapr_phb_pci_collect_nvgpu(PCIBus *bus, PCIDevice *pdev, if (tgt) { Error *local_err = NULL; - struct spapr_phb_pci_nvgpu_config *nvgpus = opaque; + SpaprPhbPciNvGpuConfig *nvgpus = opaque; Object *mr_gpu = object_property_get_link(po, "nvlink2-mr[0]", NULL); Object *mr_npu = object_property_get_link(po, "nvlink2-atsd-mr[0]", NULL); @@ -177,7 +179,7 @@ void spapr_phb_nvgpu_setup(SpaprPhbState *sphb, Error **errp) return; } - sphb->nvgpus = g_new0(struct spapr_phb_pci_nvgpu_config, 1); + sphb->nvgpus = g_new0(SpaprPhbPciNvGpuConfig, 1); sphb->nvgpus->nv2_ram_current = sphb->nv2_gpa_win_addr; sphb->nvgpus->nv2_atsd_current = sphb->nv2_atsd_win_addr; @@ -194,7 +196,7 @@ void spapr_phb_nvgpu_setup(SpaprPhbState *sphb, Error **errp) /* Add found GPU RAM and ATSD MRs if found */ for (i = 0, valid_gpu_num = 0; i < sphb->nvgpus->num; ++i) { Object *nvmrobj; - struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; + SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i]; if (!nvslot->gpdev) { continue; @@ -242,7 +244,7 @@ void spapr_phb_nvgpu_free(SpaprPhbState *sphb) } for (i = 0; i < sphb->nvgpus->num; ++i) { - struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; + SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i]; Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev), "nvlink2-mr[0]", NULL); @@ -276,7 +278,7 @@ void spapr_phb_nvgpu_populate_dt(SpaprPhbState *sphb, void *fdt, int bus_off, } for (i = 0; (i < sphb->nvgpus->num) && (atsdnum < ARRAY_SIZE(atsd)); ++i) { - struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; + SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i]; if (!nvslot->gpdev) { continue; @@ -354,7 +356,7 @@ void spapr_phb_nvgpu_ram_populate_dt(SpaprPhbState *sphb, void *fdt) /* Add memory nodes for GPU RAM and mark them unusable */ for (i = 0; i < sphb->nvgpus->num; ++i) { - struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; + SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i]; Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev), "nvlink2-mr[0]", NULL); uint32_t associativity[] = { @@ -398,7 +400,7 @@ void spapr_phb_nvgpu_populate_pcidev_dt(PCIDevice *dev, void *fdt, int offset, } for (i = 0; i < sphb->nvgpus->num; ++i) { - struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; + SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i]; /* Skip "slot" without attached GPU */ if (!nvslot->gpdev) { diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 526b489297..bee3835214 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -266,6 +266,7 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, target_ulong args, uint32_t nret, target_ulong rets) { + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); MachineState *ms = MACHINE(qdev_get_machine()); unsigned int max_cpus = ms->smp.max_cpus; target_ulong parameter = rtas_ld(args, 0); @@ -283,6 +284,20 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, current_machine->ram_size / MiB, ms->smp.cpus, max_cpus); + if (pcc->n_host_threads > 0) { + char *hostthr_val, *old = param_val; + + /* + * Add HostThrs property. This property is not present in PAPR but + * is expected by some guests to communicate the number of physical + * host threads per core on the system so that they can scale + * information which varies based on the thread configuration. + */ + hostthr_val = g_strdup_printf(",HostThrs=%d", pcc->n_host_threads); + param_val = g_strconcat(param_val, hostthr_val, NULL); + g_free(hostthr_val); + g_free(old); + } ret = sysparm_st(buffer, length, param_val, strlen(param_val) + 1); g_free(param_val); break; diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 1b61162f91..abd87605b2 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -34,15 +34,21 @@ typedef struct SpaprPhbState SpaprPhbState; -typedef struct spapr_pci_msi { +typedef struct SpaprPciMsi { uint32_t first_irq; uint32_t num; -} spapr_pci_msi; +} SpaprPciMsi; -typedef struct spapr_pci_msi_mig { +typedef struct SpaprPciMsiMig { uint32_t key; - spapr_pci_msi value; -} spapr_pci_msi_mig; + SpaprPciMsi value; +} SpaprPciMsiMig; + +typedef struct SpaprPciLsi { + uint32_t irq; +} SpaprPciLsi; + +typedef struct SpaprPhbPciNvGpuConfig SpaprPhbPciNvGpuConfig; struct SpaprPhbState { PCIHostState parent_obj; @@ -63,14 +69,12 @@ struct SpaprPhbState { AddressSpace iommu_as; MemoryRegion iommu_root; - struct spapr_pci_lsi { - uint32_t irq; - } lsi_table[PCI_NUM_PINS]; + SpaprPciLsi lsi_table[PCI_NUM_PINS]; GHashTable *msi; /* Temporary cache for migration purposes */ int32_t msi_devs_num; - spapr_pci_msi_mig *msi_devs; + SpaprPciMsiMig *msi_devs; QLIST_ENTRY(SpaprPhbState) list; @@ -89,7 +93,7 @@ struct SpaprPhbState { hwaddr mig_io_win_addr, mig_io_win_size; hwaddr nv2_gpa_win_addr; hwaddr nv2_atsd_win_addr; - struct spapr_phb_pci_nvgpu_config *nvgpus; + SpaprPhbPciNvGpuConfig *nvgpus; }; #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index fa7c380edb..03111fd55b 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -121,6 +121,7 @@ struct SpaprMachineClass { bool legacy_irq_allocation; bool broken_host_serial_model; /* present real host info to the guest */ bool pre_4_1_migration; /* don't migrate hpt-max-page-size */ + bool linux_pci_probe; void (*phb_placement)(SpaprMachineState *spapr, uint32_t index, uint64_t *buid, hwaddr *pio, diff --git a/pc-bios/README b/pc-bios/README index d59cd25461..ad78f6dc49 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20190719. + built from git tag qemu-slof-20190827. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/skiboot.lid b/pc-bios/skiboot.lid Binary files differindex 6d5966c3ae..504b95e8b6 100644 --- a/pc-bios/skiboot.lid +++ b/pc-bios/skiboot.lid diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin Binary files differindex fb0837508b..a3a3e49332 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin diff --git a/roms/SLOF b/roms/SLOF -Subproject 7bfe584e321946771692711ff83ad2b5850daca +Subproject ea221600a116883137ef90b2b7ab7d2472bc4f1 diff --git a/roms/skiboot b/roms/skiboot -Subproject 261ca8e779e5138869a45f174caa49be6a27450 +Subproject 3a6fdede6ce117facec0108afe716cf5d0472c3 diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h index 7ffdb0a706..e499575dc8 100644 --- a/target/ppc/cpu-qom.h +++ b/target/ppc/cpu-qom.h @@ -191,6 +191,7 @@ typedef struct PowerPCCPUClass { const PPCHash64Options *hash64_opts; struct ppc_radix_page_info *radix_page_info; uint32_t lrg_decr_bits; + int n_host_threads; void (*init_proc)(CPUPPCState *env); int (*check_pow)(CPUPPCState *env); int (*handle_mmu_fault)(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx); diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 07bc9051b0..4b1a2e6178 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -630,19 +630,15 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) { CPUState *cs = env_cpu(env); int status = get_float_exception_flags(&env->fp_status); - bool inexact_happened = false; if (status & float_flag_overflow) { float_overflow_excp(env); } else if (status & float_flag_underflow) { float_underflow_excp(env); - } else if (status & float_flag_inexact) { - float_inexact_excp(env); - inexact_happened = true; } - - /* if the inexact flag was not set */ - if (inexact_happened == false) { + if (status & float_flag_inexact) { + float_inexact_excp(env); + } else { env->fpscr &= ~(1 << FPSCR_FI); /* clear the FPSCR[FI] bit */ } @@ -2887,12 +2883,40 @@ void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode, uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) { - uint64_t result; + uint64_t result, sign, exp, frac; float_status tstat = env->fp_status; set_float_exception_flags(0, &tstat); - result = (uint64_t)float64_to_float32(xb, &tstat); + sign = extract64(xb, 63, 1); + exp = extract64(xb, 52, 11); + frac = extract64(xb, 0, 52) | 0x10000000000000ULL; + + if (unlikely(exp == 0 && extract64(frac, 0, 52) != 0)) { + /* DP denormal operand. */ + /* Exponent override to DP min exp. */ + exp = 1; + /* Implicit bit override to 0. */ + frac = deposit64(frac, 53, 1, 0); + } + + if (unlikely(exp < 897 && frac != 0)) { + /* SP tiny operand. */ + if (897 - exp > 63) { + frac = 0; + } else { + /* Denormalize until exp = SP min exp. */ + frac >>= (897 - exp); + } + /* Exponent override to SP min exp - 1. */ + exp = 896; + } + + result = sign << 31; + result |= extract64(exp, 10, 1) << 30; + result |= extract64(exp, 0, 7) << 23; + result |= extract64(frac, 29, 23); + /* hardware replicates result to both words of the doubleword result. */ return (result << 32) | result; } diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c index 0d71c10428..2472a5217a 100644 --- a/target/ppc/translate/vmx-impl.inc.c +++ b/target/ppc/translate/vmx-impl.inc.c @@ -350,6 +350,28 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ } \ } +/* + * We use this macro if one instruction is realized with direct + * translation, and second one with helper. + */ +#define GEN_VXFORM_TRANS_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1)\ +static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ +{ \ + if ((Rc(ctx->opcode) == 0) && \ + ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + trans_##name0(ctx); \ + } else if ((Rc(ctx->opcode) == 1) && \ + ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \ + gen_##name1(ctx); \ + } else { \ + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ + } \ +} + /* Adds support to provide invalid mask */ #define GEN_VXFORM_DUAL_EXT(name0, flg0, flg2_0, inval0, \ name1, flg1, flg2_1, inval1) \ @@ -431,20 +453,13 @@ GEN_VXFORM(vmrglb, 6, 4); GEN_VXFORM(vmrglh, 6, 5); GEN_VXFORM(vmrglw, 6, 6); -static void gen_vmrgew(DisasContext *ctx) +static void trans_vmrgew(DisasContext *ctx) { - TCGv_i64 tmp; - TCGv_i64 avr; - int VT, VA, VB; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - VT = rD(ctx->opcode); - VA = rA(ctx->opcode); - VB = rB(ctx->opcode); - tmp = tcg_temp_new_i64(); - avr = tcg_temp_new_i64(); + int VT = rD(ctx->opcode); + int VA = rA(ctx->opcode); + int VB = rB(ctx->opcode); + TCGv_i64 tmp = tcg_temp_new_i64(); + TCGv_i64 avr = tcg_temp_new_i64(); get_avr64(avr, VB, true); tcg_gen_shri_i64(tmp, avr, 32); @@ -462,21 +477,14 @@ static void gen_vmrgew(DisasContext *ctx) tcg_temp_free_i64(avr); } -static void gen_vmrgow(DisasContext *ctx) +static void trans_vmrgow(DisasContext *ctx) { - TCGv_i64 t0, t1; - TCGv_i64 avr; - int VT, VA, VB; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - VT = rD(ctx->opcode); - VA = rA(ctx->opcode); - VB = rB(ctx->opcode); - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - avr = tcg_temp_new_i64(); + int VT = rD(ctx->opcode); + int VA = rA(ctx->opcode); + int VB = rB(ctx->opcode); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 avr = tcg_temp_new_i64(); get_avr64(t0, VB, true); get_avr64(t1, VA, true); @@ -936,14 +944,14 @@ GEN_VXFORM_ENV(vminfp, 5, 17); GEN_VXFORM_HETRO(vextublx, 6, 24) GEN_VXFORM_HETRO(vextuhlx, 6, 25) GEN_VXFORM_HETRO(vextuwlx, 6, 26) -GEN_VXFORM_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207, +GEN_VXFORM_TRANS_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207, vextuwlx, PPC_NONE, PPC2_ISA300) GEN_VXFORM_HETRO(vextubrx, 6, 28) GEN_VXFORM_HETRO(vextuhrx, 6, 29) GEN_VXFORM_HETRO(vextuwrx, 6, 30) GEN_VXFORM_TRANS(lvsl, 6, 31) GEN_VXFORM_TRANS(lvsr, 6, 32) -GEN_VXFORM_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207, \ +GEN_VXFORM_TRANS_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207, vextuwrx, PPC_NONE, PPC2_ISA300) #define GEN_VXRFORM1(opname, name, str, opc2, opc3) \ diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c index 3922686ad6..8287e272f5 100644 --- a/target/ppc/translate/vsx-impl.inc.c +++ b/target/ppc/translate/vsx-impl.inc.c @@ -1308,7 +1308,7 @@ static void gen_##name(DisasContext *ctx) \ } \ xt = gen_vsr_ptr(xT(ctx->opcode)); \ xa = gen_vsr_ptr(xA(ctx->opcode)); \ - if (ctx->opcode & PPC_BIT(25)) { \ + if (ctx->opcode & PPC_BIT32(25)) { \ /* \ * AxT + B \ */ \ diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index 4a21ed7289..0fb11c7ac6 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -8770,6 +8770,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; pcc->hash64_opts = &ppc_hash64_opts_POWER7; pcc->lrg_decr_bits = 32; + pcc->n_host_threads = 8; #endif pcc->excp_model = POWERPC_EXCP_POWER8; pcc->bus_model = PPC_FLAGS_INPUT_POWER7; @@ -8981,6 +8982,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) pcc->hash64_opts = &ppc_hash64_opts_POWER7; pcc->radix_page_info = &POWER9_radix_page_info; pcc->lrg_decr_bits = 56; + pcc->n_host_threads = 4; #endif pcc->excp_model = POWERPC_EXCP_POWER9; pcc->bus_model = PPC_FLAGS_INPUT_POWER9; @@ -10461,6 +10463,10 @@ static void ppc_cpu_reset(CPUState *s) s->exception_index = POWERPC_EXCP_NONE; env->error_code = 0; + /* tininess for underflow is detected before rounding */ + set_float_detect_tininess(float_tininess_before_rounding, + &env->fp_status); + for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { ppc_spr_t *spr = &env->spr_cb[i]; diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c index 24852d4c7d..a54d007298 100644 --- a/tests/boot-serial-test.c +++ b/tests/boot-serial-test.c @@ -103,7 +103,8 @@ static testdef_t tests[] = { { "ppc64", "pseries", "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken", "Open Firmware" }, - { "ppc64", "powernv", "-cpu POWER8", "OPAL" }, + { "ppc64", "powernv8", "", "OPAL" }, + { "ppc64", "powernv9", "", "OPAL" }, { "ppc64", "sam460ex", "-device e1000", "8086 100e" }, { "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" }, { "i386", "pc", "-device sga", "SGABIOS" }, diff --git a/tests/pnv-xscom-test.c b/tests/pnv-xscom-test.c index 63d464048d..9fddc7d5f9 100644 --- a/tests/pnv-xscom-test.c +++ b/tests/pnv-xscom-test.c @@ -77,9 +77,15 @@ static void test_xscom_cfam_id(QTestState *qts, const PnvChip *chip) static void test_cfam_id(const void *data) { const PnvChip *chip = data; + const char *machine = "powernv8"; QTestState *qts; - qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model); + if (chip->chip_type == PNV_CHIP_POWER9) { + machine = "powernv9"; + } + + qts = qtest_initf("-M %s,accel=tcg -cpu %s", + machine, chip->cpu_model); test_xscom_cfam_id(qts, chip); qtest_quit(qts); } @@ -113,8 +119,14 @@ static void test_core(const void *data) { const PnvChip *chip = data; QTestState *qts; + const char *machine = "powernv8"; + + if (chip->chip_type == PNV_CHIP_POWER9) { + machine = "powernv9"; + } - qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model); + qts = qtest_initf("-M %s,accel=tcg -cpu %s", + machine, chip->cpu_model); test_xscom_core(qts, chip); qtest_quit(qts); } |