diff options
author | Peter Maydell | 2017-07-17 13:52:59 +0200 |
---|---|---|
committer | Peter Maydell | 2017-07-17 13:52:59 +0200 |
commit | 77031ee1ce4c7e5f4b4941535c4912eb2eb3503c (patch) | |
tree | c70b354b3cdb137d9b4bb0d4d395b3a49022b067 /hw/ppc/spapr.c | |
parent | Merge remote-tracking branch 'remotes/famz/tags/block-and-testing-pull-reques... (diff) | |
parent | target/ppc: fix CPU hotplug when radix is enabled (TCG) (diff) | |
download | qemu-77031ee1ce4c7e5f4b4941535c4912eb2eb3503c.tar.gz qemu-77031ee1ce4c7e5f4b4941535c4912eb2eb3503c.tar.xz qemu-77031ee1ce4c7e5f4b4941535c4912eb2eb3503c.zip |
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.10-20170717' into staging
ppc patch queue 2017-07-17
This pull requests supersedes the one from 2017-07-14. That one had a
couple of subtle regressions: there was a build error for mingw32, and
an instance_size which was theoretically wrong everywhere, but only
actually bit on the Travis OSX build.
There are two major batches in this set, rather than the usual
collection of assorted fixes.
* More DRC cleanup. This gets the state management into a state
which should fix many of the hotplug+migration problems we've
had. Plus it gets the migration stream format into something
well defined and pretty minimal which we can reasonably support
into the future.
* Hashed Page Table resizing. It's been a while since this was
posted, but it's been through several previous rounds of review.
The kernel parts (both guest and host) are merged in 4.11, so
this is the only remaining piece left to allow resizing of the
HPT in a running guest.
There are also a handful of unrelated fixes.
# gpg: Signature made Mon 17 Jul 2017 07:36:52 BST
# 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.10-20170717: (21 commits)
target/ppc: fix CPU hotplug when radix is enabled (TCG)
spapr: fix memory leak in spapr_core_pre_plug()
pseries: Allow HPT resizing with KVM
pseries: Use smaller default hash page tables when guest can resize
pseries: Enable HPT resizing for 2.10
pseries: Implement HPT resizing
pseries: Stubs for HPT resizing
ppc/pnv: Remove unused XICSState reference
spapr: fix potential memory leak in spapr_core_plug()
spapr: Implement DR-indicator for physical DRCs only
spapr: Remove sPAPRConfigureConnectorState sub-structure
spapr: Consolidate DRC state variables
spapr: Cleanups relating to DRC awaiting_release field
spapr: Refactor spapr_drc_detach()
spapr: Abort on delete failure in spapr_drc_release()
spapr: Simplify unplug path
spapr: Remove 'awaiting_allocation' DRC flag
spapr: Treat devices added before inbound migration as coldplugged
spapr: Minor cleanups to events handling
spapr: migrate pending_events of spapr state
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/ppc/spapr.c')
-rw-r--r-- | hw/ppc/spapr.c | 239 |
1 files changed, 161 insertions, 78 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 16638ce80c..970093e6b5 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -98,8 +98,6 @@ #define PHANDLE_XICP 0x00001111 -#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) - static ICSState *spapr_ics_create(sPAPRMachineState *spapr, const char *type_ics, int nr_irqs, Error **errp) @@ -874,6 +872,11 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt) if (!kvm_enabled() || kvmppc_spapr_use_multitce()) { add_str(hypertas, "hcall-multi-tce"); } + + if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) { + add_str(hypertas, "hcall-hpt-resize"); + } + _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions", hypertas->str, hypertas->len)); g_string_free(hypertas, TRUE); @@ -1264,7 +1267,7 @@ static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex, } } -static int spapr_hpt_shift_for_ramsize(uint64_t ramsize) +int spapr_hpt_shift_for_ramsize(uint64_t ramsize) { int shift; @@ -1285,8 +1288,8 @@ void spapr_free_hpt(sPAPRMachineState *spapr) close_htab_fd(spapr); } -static void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, - Error **errp) +void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, + Error **errp) { long rc; @@ -1334,9 +1337,17 @@ static void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr) { - spapr_reallocate_hpt(spapr, - spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size), - &error_fatal); + int hpt_shift; + + if ((spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) + || (spapr->cas_reboot + && !spapr_ovec_test(spapr->ov5_cas, OV5_HPT_RESIZE))) { + hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size); + } else { + hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->ram_size); + } + spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal); + if (spapr->vrma_adjust) { spapr->rma_size = kvmppc_rma_size(spapr_node0_size(), spapr->htab_shift); @@ -1517,6 +1528,37 @@ static bool version_before_3(void *opaque, int version_id) return version_id < 3; } +static bool spapr_pending_events_needed(void *opaque) +{ + sPAPRMachineState *spapr = (sPAPRMachineState *)opaque; + return !QTAILQ_EMPTY(&spapr->pending_events); +} + +static const VMStateDescription vmstate_spapr_event_entry = { + .name = "spapr_event_log_entry", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(summary, sPAPREventLogEntry), + VMSTATE_UINT32(extended_length, sPAPREventLogEntry), + VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, sPAPREventLogEntry, 0, + NULL, extended_length), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_spapr_pending_events = { + .name = "spapr_pending_events", + .version_id = 1, + .minimum_version_id = 1, + .needed = spapr_pending_events_needed, + .fields = (VMStateField[]) { + VMSTATE_QTAILQ_V(pending_events, sPAPRMachineState, 1, + vmstate_spapr_event_entry, sPAPREventLogEntry, next), + VMSTATE_END_OF_LIST() + }, +}; + static bool spapr_ov5_cas_needed(void *opaque) { sPAPRMachineState *spapr = opaque; @@ -1615,6 +1657,7 @@ static const VMStateDescription vmstate_spapr = { .subsections = (const VMStateDescription*[]) { &vmstate_spapr_ov5_cas, &vmstate_spapr_patb_entry, + &vmstate_spapr_pending_events, NULL } }; @@ -2116,12 +2159,41 @@ static void ppc_spapr_init(MachineState *machine) hwaddr node0_size = spapr_node0_size(); long load_limit, fw_size; char *filename; + Error *resize_hpt_err = NULL; msi_nonbroken = true; QLIST_INIT(&spapr->phbs); QTAILQ_INIT(&spapr->pending_dimm_unplugs); + /* Check HPT resizing availability */ + kvmppc_check_papr_resize_hpt(&resize_hpt_err); + if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) { + /* + * If the user explicitly requested a mode we should either + * supply it, or fail completely (which we do below). But if + * it's not set explicitly, we reset our mode to something + * that works + */ + if (resize_hpt_err) { + spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED; + error_free(resize_hpt_err); + resize_hpt_err = NULL; + } else { + spapr->resize_hpt = smc->resize_hpt_default; + } + } + + assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT); + + if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) { + /* + * User requested HPT resize, but this host can't supply it. Bail out + */ + error_report_err(resize_hpt_err); + exit(1); + } + /* Allocate RMA if necessary */ rma_alloc_size = kvmppc_alloc_rma(&rma); @@ -2190,6 +2262,11 @@ static void ppc_spapr_init(MachineState *machine) spapr_ovec_set(spapr->ov5, OV5_HP_EVT); } + /* advertise support for HPT resizing */ + if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) { + spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE); + } + /* init CPUs */ if (machine->cpu_model == NULL) { machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu; @@ -2547,6 +2624,40 @@ static void spapr_set_modern_hotplug_events(Object *obj, bool value, spapr->use_hotplug_event_source = value; } +static char *spapr_get_resize_hpt(Object *obj, Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + + switch (spapr->resize_hpt) { + case SPAPR_RESIZE_HPT_DEFAULT: + return g_strdup("default"); + case SPAPR_RESIZE_HPT_DISABLED: + return g_strdup("disabled"); + case SPAPR_RESIZE_HPT_ENABLED: + return g_strdup("enabled"); + case SPAPR_RESIZE_HPT_REQUIRED: + return g_strdup("required"); + } + g_assert_not_reached(); +} + +static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + + if (strcmp(value, "default") == 0) { + spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT; + } else if (strcmp(value, "disabled") == 0) { + spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED; + } else if (strcmp(value, "enabled") == 0) { + spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED; + } else if (strcmp(value, "required") == 0) { + spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED; + } else { + error_setg(errp, "Bad value for \"resize-hpt\" property"); + } +} + static void spapr_machine_initfn(Object *obj) { sPAPRMachineState *spapr = SPAPR_MACHINE(obj); @@ -2571,6 +2682,12 @@ static void spapr_machine_initfn(Object *obj) ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr, "Maximum permitted CPU compatibility mode", &error_fatal); + + object_property_add_str(obj, "resize-hpt", + spapr_get_resize_hpt, spapr_set_resize_hpt, NULL); + object_property_set_description(obj, "resize-hpt", + "Resizing of the Hash Page Table (enabled, disabled, required)", + NULL); } static void spapr_machine_finalizefn(Object *obj) @@ -2604,6 +2721,7 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size, int i, fdt_offset, fdt_size; void *fdt; uint64_t addr = addr_start; + bool hotplugged = spapr_drc_hotplugged(dev); Error *local_err = NULL; for (i = 0; i < nr_lmbs; i++) { @@ -2621,18 +2739,21 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size, addr -= SPAPR_MEMORY_BLOCK_SIZE; drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr / SPAPR_MEMORY_BLOCK_SIZE); - spapr_drc_detach(drc, dev, NULL); + spapr_drc_detach(drc); } g_free(fdt); error_propagate(errp, local_err); return; } + if (!hotplugged) { + spapr_drc_reset(drc); + } addr += SPAPR_MEMORY_BLOCK_SIZE; } /* send hotplug notification to the * guest only in case of hotplugged memory */ - if (dev->hotplugged) { + if (hotplugged) { if (dedicated_hp_event_source) { drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, addr_start / SPAPR_MEMORY_BLOCK_SIZE); @@ -2780,8 +2901,10 @@ static sPAPRDIMMState *spapr_recover_pending_dimm_state(sPAPRMachineState *ms, /* Callback to be called during DRC release. */ void spapr_lmb_release(DeviceState *dev) { - HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev); - sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl); + sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_hotplug_handler(dev)); + PCDIMMDevice *dimm = PC_DIMM(dev); + PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); + MemoryRegion *mr = ddc->get_memory_region(dimm); sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev)); /* This information will get lost if a migration occurs @@ -2802,18 +2925,7 @@ void spapr_lmb_release(DeviceState *dev) * Now that all the LMBs have been removed by the guest, call the * pc-dimm unplug handler to cleanup up the pc-dimm device. */ - hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort); -} - -static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) -{ - sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev); - PCDIMMDevice *dimm = PC_DIMM(dev); - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); - MemoryRegion *mr = ddc->get_memory_region(dimm); - - pc_dimm_memory_unplug(dev, &ms->hotplug_memory, mr); + pc_dimm_memory_unplug(dev, &spapr->hotplug_memory, mr); object_unparent(OBJECT(dev)); } @@ -2849,7 +2961,7 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, addr / SPAPR_MEMORY_BLOCK_SIZE); g_assert(drc); - spapr_drc_detach(drc, dev, errp); + spapr_drc_detach(drc); addr += SPAPR_MEMORY_BLOCK_SIZE; } @@ -2882,10 +2994,10 @@ static void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset, return fdt; } -static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) +/* Callback to be called during DRC release. */ +void spapr_core_release(DeviceState *dev) { - MachineState *ms = MACHINE(qdev_get_machine()); + MachineState *ms = MACHINE(qdev_get_hotplug_handler(dev)); sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms); CPUCore *cc = CPU_CORE(dev); CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL); @@ -2909,22 +3021,12 @@ static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, object_unparent(OBJECT(dev)); } -/* Callback to be called during DRC release. */ -void spapr_core_release(DeviceState *dev) -{ - HotplugHandler *hotplug_ctrl; - - hotplug_ctrl = qdev_get_hotplug_handler(dev); - hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort); -} - static void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { int index; sPAPRDRConnector *drc; - Error *local_err = NULL; CPUCore *cc = CPU_CORE(dev); int smt = kvmppc_smt_threads(); @@ -2941,11 +3043,7 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index * smt); g_assert(drc); - spapr_drc_detach(drc, dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } + spapr_drc_detach(drc); spapr_hotplug_req_remove_by_index(drc); } @@ -2961,11 +3059,10 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, CPUState *cs = CPU(core->threads); sPAPRDRConnector *drc; Error *local_err = NULL; - void *fdt = NULL; - int fdt_offset = 0; int smt = kvmppc_smt_threads(); CPUArchId *core_slot; int index; + bool hotplugged = spapr_drc_hotplugged(dev); core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index); if (!core_slot) { @@ -2977,24 +3074,30 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, g_assert(drc || !mc->has_hotpluggable_cpus); - fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr); - if (drc) { + void *fdt; + int fdt_offset; + + fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr); + spapr_drc_attach(drc, dev, fdt, fdt_offset, &local_err); if (local_err) { g_free(fdt); error_propagate(errp, local_err); return; } - } - if (dev->hotplugged) { - /* - * Send hotplug notification interrupt to the guest only in case - * of hotplugged CPUs. - */ - spapr_hotplug_req_add_by_index(drc); + if (hotplugged) { + /* + * Send hotplug notification interrupt to the guest only + * in case of hotplugged CPUs. + */ + spapr_hotplug_req_add_by_index(drc); + } else { + spapr_drc_reset(drc); + } } + core_slot->cpu = OBJECT(dev); if (smc->pre_2_10_has_unused_icps) { @@ -3047,9 +3150,9 @@ static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, * total vcpus not a multiple of threads-per-core. */ if (mc->has_hotpluggable_cpus && (cc->nr_threads != smp_threads)) { - error_setg(errp, "invalid nr-threads %d, must be %d", + error_setg(&local_err, "invalid nr-threads %d, must be %d", cc->nr_threads, smp_threads); - return; + goto out; } core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index); @@ -3119,27 +3222,6 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, } } -static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - sPAPRMachineState *sms = SPAPR_MACHINE(qdev_get_machine()); - MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); - - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) { - spapr_memory_unplug(hotplug_dev, dev, errp); - } else { - error_setg(errp, "Memory hot unplug not supported for this guest"); - } - } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { - if (!mc->has_hotpluggable_cpus) { - error_setg(errp, "CPU hot unplug not supported on this machine"); - return; - } - spapr_core_unplug(hotplug_dev, dev, errp); - } -} - static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -3357,7 +3439,6 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->get_hotplug_handler = spapr_get_hotplug_handler; hc->pre_plug = spapr_machine_device_pre_plug; hc->plug = spapr_machine_device_plug; - hc->unplug = spapr_machine_device_unplug; mc->cpu_index_to_instance_props = spapr_cpu_index_to_props; mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids; hc->unplug_request = spapr_machine_device_unplug_request; @@ -3365,6 +3446,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) smc->dr_lmb_enabled = true; smc->tcg_default_cpu = "POWER8"; mc->has_hotpluggable_cpus = true; + smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; smc->phb_placement = spapr_phb_placement; @@ -3471,6 +3553,7 @@ static void spapr_machine_2_9_class_options(MachineClass *mc) SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_9); 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; } DEFINE_SPAPR_MACHINE(2_9, "2.9", false); |