diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-02-02 18:48:06 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-02-02 18:48:06 +0000 |
commit | 5459ef3bff961bc462ac89460ab6b08a14624c8d (patch) | |
tree | 9308ed3504343e7bc9b4fc1b71a2b8fa7ae68592 /hw/ppc/spapr.c | |
parent | 4e9f5244e1945b2852b9ddcd7f023a7d19c9ecd7 (diff) | |
parent | 7c6e8797337c24520b48d8b50a900a747e50f974 (diff) |
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.9-20170202' into staging
ppc patch queue 2017-02-02
This obsoletes ppc-for-2.9-20170112, which had a MacOS build bug.
This is a long overdue ppc pull request for qemu-2.9. It's been a
long time coming due to some holidays and inconveniently timed
problems with testing. So, there's a lot in here:
* More POWER9 instruction implementations for TCG
* The simpler parts of my CPU compatibility mode cleanup
* This changes behaviour to prefer compatibility modes over
"raW" mode for new machine type versions
* New "40p" machine type which is essentially a modernized and
cleaned up "prep". The intention is that it will replace "prep"
once it has some more testing and polish.
* Add pseries-2.9 machine type
* Implement H_SIGNAL_SYS_RESET hypercall
* Consolidate the two alternate CPU init paths in pseries by
making it always go through CPU core objects to initialize CPU
* A number of bugfixes and cleanups
* Stop the guest timebase when the guest is stopped under KVM.
This makes the guest system clock also stop when paused, which
matches the x86 behaviour.
* Some preliminary cleanups leading towards implementation of the
POWER9 MMU.
There are also some changes not strictly related to ppc code, but for
its benefit:
* Limit the pxi-expander-bridge (PXB) device to x86 guests only
(it's essentially a hack to work around historical x86
limitations)
* Some additions to the 128-bit math in host_utils, necessary for
some of the new instructions.
* Revise a number of qtests and enable them for ppc
# gpg: Signature made Thu 02 Feb 2017 01:40:16 GMT
# gpg: using RSA key 0x6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-2.9-20170202: (107 commits)
hw/ppc/pnv: Use error_report instead of hw_error if a ROM file can't be found
ppc/kvm: Handle the "family" CPU via alias instead of registering new types
target/ppc/mmu_hash64: Fix incorrect shift value in amr calculation
target/ppc/mmu_hash64: Fix printing unsigned as signed int
tcg/POWER9: NOOP the cp_abort instruction
target/ppc/debug: Print LPCR register value if register exists
target-ppc: Add xststdc[sp, dp, qp] instructions
target-ppc: Add xvtstdc[sp,dp] instructions
target-ppc: Add MMU model check for booke machines
ppc: switch to constants within BUILD_BUG_ON
target/ppc/cpu-models: Fix/remove bad CPU aliases
target/ppc: Remove unused POWERPC_FAMILY(POWER)
spapr: clock should count only if vm is running
ppc: Remove unused function cpu_ppc601_rtc_init()
target/ppc: Add pcr_supported to POWER9 cpu class definition
powerpc/cpu-models: rename ISAv3.00 logical PVR definition
target-ppc: Add xvcv[hpsp, sphp] instructions
target-ppc: Add xsmulqp instruction
target-ppc: Add xsdivqp instruction
target-ppc: Add xscvsdqp and xscvudqp instructions
...
# Conflicts:
# hw/pci-bridge/Makefile.objs
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/ppc/spapr.c')
-rw-r--r-- | hw/ppc/spapr.c | 196 |
1 files changed, 125 insertions, 71 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 45b7d99821..e465d7ac98 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -148,8 +148,8 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, uint32_t gservers_prop[smt_threads * 2]; int index = ppc_get_vcpu_dt_id(cpu); - if (cpu->cpu_version) { - ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version); + if (cpu->compat_pvr) { + ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr); if (ret < 0) { return ret; } @@ -206,6 +206,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr) PowerPCCPU *cpu = POWERPC_CPU(cs); DeviceClass *dc = DEVICE_GET_CLASS(cs); int index = ppc_get_vcpu_dt_id(cpu); + int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu)); if ((index % smt) != 0) { continue; @@ -240,8 +241,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr) return ret; } - ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, - ppc_get_compat_smt_threads(cpu)); + ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt); if (ret < 0) { return ret; } @@ -407,6 +407,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, size_t page_sizes_prop_size; uint32_t vcpus_per_socket = smp_threads * smp_cores; uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; + int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu)); sPAPRDRConnector *drc; sPAPRDRConnectorClass *drck; int drc_index; @@ -494,8 +495,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cs)); - _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, - ppc_get_compat_smt_threads(cpu))); + _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt)); } static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr) @@ -685,7 +685,6 @@ out: int spapr_h_cas_compose_response(sPAPRMachineState *spapr, target_ulong addr, target_ulong size, - bool cpu_update, sPAPROptionVector *ov5_updates) { void *fdt, *fdt_skel; @@ -704,9 +703,7 @@ int spapr_h_cas_compose_response(sPAPRMachineState *spapr, g_free(fdt_skel); /* Fixup cpu nodes */ - if (cpu_update) { - _FDT((spapr_fixup_cpu_dt(fdt, spapr))); - } + _FDT((spapr_fixup_cpu_dt(fdt, spapr))); if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) { return -1; @@ -1008,7 +1005,8 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; } -static void emulate_spapr_hypercall(PowerPCCPU *cpu) +static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp, + PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; @@ -1753,11 +1751,80 @@ static void spapr_validate_node_memory(MachineState *machine, Error **errp) } } +static void spapr_init_cpus(sPAPRMachineState *spapr) +{ + MachineState *machine = MACHINE(spapr); + MachineClass *mc = MACHINE_GET_CLASS(machine); + char *type = spapr_get_cpu_core_type(machine->cpu_model); + int smt = kvmppc_smt_threads(); + int spapr_max_cores, spapr_cores; + int i; + + if (!type) { + error_report("Unable to find sPAPR CPU Core definition"); + exit(1); + } + + if (mc->query_hotpluggable_cpus) { + if (smp_cpus % smp_threads) { + error_report("smp_cpus (%u) must be multiple of threads (%u)", + smp_cpus, smp_threads); + exit(1); + } + if (max_cpus % smp_threads) { + error_report("max_cpus (%u) must be multiple of threads (%u)", + max_cpus, smp_threads); + exit(1); + } + + spapr_max_cores = max_cpus / smp_threads; + spapr_cores = smp_cpus / smp_threads; + } else { + if (max_cpus != smp_cpus) { + error_report("This machine version does not support CPU hotplug"); + exit(1); + } + + spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads; + spapr_cores = spapr_max_cores; + } + + spapr->cores = g_new0(Object *, spapr_max_cores); + for (i = 0; i < spapr_max_cores; i++) { + int core_id = i * smp_threads; + + if (mc->query_hotpluggable_cpus) { + sPAPRDRConnector *drc = + spapr_dr_connector_new(OBJECT(spapr), + SPAPR_DR_CONNECTOR_TYPE_CPU, + (core_id / smp_threads) * smt); + + qemu_register_reset(spapr_drc_reset, drc); + } + + if (i < spapr_cores) { + Object *core = object_new(type); + int nr_threads = smp_threads; + + /* Handle the partially filled core for older machine types */ + if ((i + 1) * smp_threads >= smp_cpus) { + nr_threads = smp_cpus - i * smp_threads; + } + + object_property_set_int(core, nr_threads, "nr-threads", + &error_fatal); + object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID, + &error_fatal); + object_property_set_bool(core, true, "realized", &error_fatal); + } + } + g_free(type); +} + /* pSeries LPAR / sPAPR hardware init */ static void ppc_spapr_init(MachineState *machine) { sPAPRMachineState *spapr = SPAPR_MACHINE(machine); - MachineClass *mc = MACHINE_GET_CLASS(machine); sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; @@ -1772,28 +1839,11 @@ static void ppc_spapr_init(MachineState *machine) long load_limit, fw_size; char *filename; int smt = kvmppc_smt_threads(); - int spapr_cores = smp_cpus / smp_threads; - int spapr_max_cores = max_cpus / smp_threads; - - if (mc->query_hotpluggable_cpus) { - if (smp_cpus % smp_threads) { - error_report("smp_cpus (%u) must be multiple of threads (%u)", - smp_cpus, smp_threads); - exit(1); - } - if (max_cpus % smp_threads) { - error_report("max_cpus (%u) must be multiple of threads (%u)", - max_cpus, smp_threads); - exit(1); - } - } msi_nonbroken = true; QLIST_INIT(&spapr->phbs); - cpu_ppc_hypercall = emulate_spapr_hypercall; - /* Allocate RMA if necessary */ rma_alloc_size = kvmppc_alloc_rma(&rma); @@ -1866,44 +1916,7 @@ static void ppc_spapr_init(MachineState *machine) ppc_cpu_parse_features(machine->cpu_model); - if (mc->query_hotpluggable_cpus) { - char *type = spapr_get_cpu_core_type(machine->cpu_model); - - if (type == NULL) { - error_report("Unable to find sPAPR CPU Core definition"); - exit(1); - } - - spapr->cores = g_new0(Object *, spapr_max_cores); - for (i = 0; i < spapr_max_cores; i++) { - int core_id = i * smp_threads; - sPAPRDRConnector *drc = - spapr_dr_connector_new(OBJECT(spapr), - SPAPR_DR_CONNECTOR_TYPE_CPU, - (core_id / smp_threads) * smt); - - qemu_register_reset(spapr_drc_reset, drc); - - if (i < spapr_cores) { - Object *core = object_new(type); - object_property_set_int(core, smp_threads, "nr-threads", - &error_fatal); - object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID, - &error_fatal); - object_property_set_bool(core, true, "realized", &error_fatal); - } - } - g_free(type); - } else { - for (i = 0; i < smp_cpus; i++) { - PowerPCCPU *cpu = cpu_ppc_init(machine->cpu_model); - if (cpu == NULL) { - error_report("Unable to find PowerPC CPU definition"); - exit(1); - } - spapr_cpu_init(spapr, cpu, &error_fatal); - } - } + spapr_init_cpus(spapr); if (kvm_enabled()) { /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */ @@ -2116,6 +2129,12 @@ static void ppc_spapr_init(MachineState *machine) qemu_register_reset(spapr_ccs_reset_hook, spapr); qemu_register_boot_set(spapr_boot_set, spapr); + + /* to stop and start vmclock */ + if (kvm_enabled()) { + qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change, + &spapr->tb); + } } static int spapr_kvm_type(const char *vm_type) @@ -2185,6 +2204,19 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus, } } + /* + * SLOF probes the USB devices, and if it recognizes that the device is a + * storage device, it changes its name to "storage" instead of "usb-host", + * and additionally adds a child node for the SCSI LUN, so the correct + * boot path in SLOF is something like .../storage@1/disk@xxx" instead. + */ + if (strcmp("usb-host", qdev_fw_name(dev)) == 0) { + USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE); + if (usb_host_dev_is_scsi_storage(usbdev)) { + return g_strdup_printf("storage@%s/disk", usbdev->port->path); + } + } + if (phb) { /* Replace "pci" with "pci@800000020000000" */ return g_strdup_printf("pci@%"PRIX64, phb->buid); @@ -2252,7 +2284,7 @@ static void spapr_machine_finalizefn(Object *obj) g_free(spapr->kvm_type); } -static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg) +void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg) { cpu_synchronize_state(cs); ppc_cpu_do_system_reset(cs); @@ -2263,7 +2295,7 @@ static void spapr_nmi(NMIState *n, int cpu_index, Error **errp) CPUState *cs; CPU_FOREACH(cs) { - async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL); + async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL); } } @@ -2668,6 +2700,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc); NMIClass *nc = NMI_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); + PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc); mc->desc = "pSeries Logical Partition (PAPR compliant)"; @@ -2699,6 +2732,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; smc->phb_placement = spapr_phb_placement; + vhc->hypercall = emulate_spapr_hypercall; } static const TypeInfo spapr_machine_info = { @@ -2714,6 +2748,7 @@ static const TypeInfo spapr_machine_info = { { TYPE_FW_PATH_PROVIDER }, { TYPE_NMI }, { TYPE_HOTPLUG_HANDLER }, + { TYPE_PPC_VIRTUAL_HYPERVISOR }, { } }, }; @@ -2747,18 +2782,37 @@ static const TypeInfo spapr_machine_info = { type_init(spapr_machine_register_##suffix) /* + * pseries-2.9 + */ +static void spapr_machine_2_9_instance_options(MachineState *machine) +{ +} + +static void spapr_machine_2_9_class_options(MachineClass *mc) +{ + /* Defaults for the latest behaviour inherited from the base class */ +} + +DEFINE_SPAPR_MACHINE(2_9, "2.9", true); + +/* * pseries-2.8 */ +#define SPAPR_COMPAT_2_8 \ + HW_COMPAT_2_8 + 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) { - /* Defaults for the latest behaviour inherited from the base class */ + spapr_machine_2_9_class_options(mc); + SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_8); } -DEFINE_SPAPR_MACHINE(2_8, "2.8", true); +DEFINE_SPAPR_MACHINE(2_8, "2.8", false); /* * pseries-2.7 |