#include "sysemu/device_tree.h"
#include "sysemu/block-backend.h"
#include "sysemu/cpus.h"
-#include "sysemu/kvm.h"
-#include "sysemu/device_tree.h"
+#include "sysemu/hw_accel.h"
#include "kvm_ppc.h"
#include "migration/migration.h"
#include "mmu-hash64.h"
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;
}
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;
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;
}
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;
_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)
int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
target_ulong addr, target_ulong size,
- bool cpu_update,
sPAPROptionVector *ov5_updates)
{
void *fdt, *fdt_skel;
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;
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;
return version_id < 3;
}
+static bool spapr_ov5_cas_needed(void *opaque)
+{
+ sPAPRMachineState *spapr = opaque;
+ sPAPROptionVector *ov5_mask = spapr_ovec_new();
+ sPAPROptionVector *ov5_legacy = spapr_ovec_new();
+ sPAPROptionVector *ov5_removed = spapr_ovec_new();
+ bool cas_needed;
+
+ /* Prior to the introduction of sPAPROptionVector, we had two option
+ * vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
+ * Both of these options encode machine topology into the device-tree
+ * in such a way that the now-booted OS should still be able to interact
+ * appropriately with QEMU regardless of what options were actually
+ * negotiatied on the source side.
+ *
+ * As such, we can avoid migrating the CAS-negotiated options if these
+ * are the only options available on the current machine/platform.
+ * Since these are the only options available for pseries-2.7 and
+ * earlier, this allows us to maintain old->new/new->old migration
+ * compatibility.
+ *
+ * For QEMU 2.8+, there are additional CAS-negotiatable options available
+ * via default pseries-2.8 machines and explicit command-line parameters.
+ * Some of these options, like OV5_HP_EVT, *do* require QEMU to be aware
+ * of the actual CAS-negotiated values to continue working properly. For
+ * example, availability of memory unplug depends on knowing whether
+ * OV5_HP_EVT was negotiated via CAS.
+ *
+ * Thus, for any cases where the set of available CAS-negotiatable
+ * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
+ * include the CAS-negotiated options in the migration stream.
+ */
+ spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
+ spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
+
+ /* spapr_ovec_diff returns true if bits were removed. we avoid using
+ * the mask itself since in the future it's possible "legacy" bits may be
+ * removed via machine options, which could generate a false positive
+ * that breaks migration.
+ */
+ spapr_ovec_intersect(ov5_legacy, spapr->ov5, ov5_mask);
+ cas_needed = spapr_ovec_diff(ov5_removed, spapr->ov5, ov5_legacy);
+
+ spapr_ovec_cleanup(ov5_mask);
+ spapr_ovec_cleanup(ov5_legacy);
+ spapr_ovec_cleanup(ov5_removed);
+
+ return cas_needed;
+}
+
+static const VMStateDescription vmstate_spapr_ov5_cas = {
+ .name = "spapr_option_vector_ov5_cas",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = spapr_ov5_cas_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_POINTER_V(ov5_cas, sPAPRMachineState, 1,
+ vmstate_spapr_ovec, sPAPROptionVector),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static const VMStateDescription vmstate_spapr = {
.name = "spapr",
.version_id = 3,
VMSTATE_PPC_TIMEBASE_V(tb, sPAPRMachineState, 2),
VMSTATE_END_OF_LIST()
},
+ .subsections = (const VMStateDescription*[]) {
+ &vmstate_spapr_ov5_cas,
+ NULL
+ }
};
static int htab_save_setup(QEMUFile *f, void *opaque)
}
}
+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;
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);
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 */
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)
}
}
+ /*
+ * 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);
spapr->kvm_type = g_strdup(value);
}
+static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+
+ return spapr->use_hotplug_event_source;
+}
+
+static void spapr_set_modern_hotplug_events(Object *obj, bool value,
+ Error **errp)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+
+ spapr->use_hotplug_event_source = value;
+}
+
static void spapr_machine_initfn(Object *obj)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
spapr->htab_fd = -1;
+ spapr->use_hotplug_event_source = true;
object_property_add_str(obj, "kvm-type",
spapr_get_kvm_type, spapr_set_kvm_type, NULL);
object_property_set_description(obj, "kvm-type",
"Specifies the KVM virtualization mode (HV, PR)",
NULL);
+ object_property_add_bool(obj, "modern-hotplug-events",
+ spapr_get_modern_hotplug_events,
+ spapr_set_modern_hotplug_events,
+ NULL);
+ object_property_set_description(obj, "modern-hotplug-events",
+ "Use dedicated hotplug event mechanism in"
+ " place of standard EPOW events when possible"
+ " (required for memory hot-unplug support)",
+ NULL);
}
static void spapr_machine_finalizefn(Object *obj)
g_free(spapr->kvm_type);
}
-static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, void *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);
CPUState *cs;
CPU_FOREACH(cs) {
- async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, NULL);
+ async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
}
}
-static void spapr_add_lmbs(DeviceState *dev, uint64_t addr, uint64_t size,
- uint32_t node, Error **errp)
+static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
+ uint32_t node, bool dedicated_hp_event_source,
+ Error **errp)
{
sPAPRDRConnector *drc;
sPAPRDRConnectorClass *drck;
uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
int i, fdt_offset, fdt_size;
void *fdt;
+ uint64_t addr = addr_start;
for (i = 0; i < nr_lmbs; i++) {
drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB,
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, errp);
addr += SPAPR_MEMORY_BLOCK_SIZE;
+ if (!dev->hotplugged) {
+ /* guests expect coldplugged LMBs to be pre-allocated */
+ drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
+ drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
+ }
}
/* send hotplug notification to the
* guest only in case of hotplugged memory
*/
if (dev->hotplugged) {
- spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs);
+ if (dedicated_hp_event_source) {
+ drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB,
+ addr_start / SPAPR_MEMORY_BLOCK_SIZE);
+ drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ spapr_hotplug_req_add_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
+ nr_lmbs,
+ drck->get_index(drc));
+ } else {
+ spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB,
+ nr_lmbs);
+ }
}
}
goto out;
}
- spapr_add_lmbs(dev, addr, size, node, &error_abort);
+ spapr_add_lmbs(dev, addr, size, node,
+ spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT),
+ &error_abort);
out:
error_propagate(errp, local_err);
}
+typedef struct sPAPRDIMMState {
+ uint32_t nr_lmbs;
+} sPAPRDIMMState;
+
+static void spapr_lmb_release(DeviceState *dev, void *opaque)
+{
+ sPAPRDIMMState *ds = (sPAPRDIMMState *)opaque;
+ HotplugHandler *hotplug_ctrl;
+
+ if (--ds->nr_lmbs) {
+ return;
+ }
+
+ g_free(ds);
+
+ /*
+ * 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_ctrl = qdev_get_hotplug_handler(dev);
+ hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
+}
+
+static void spapr_del_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
+ Error **errp)
+{
+ sPAPRDRConnector *drc;
+ sPAPRDRConnectorClass *drck;
+ uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
+ int i;
+ sPAPRDIMMState *ds = g_malloc0(sizeof(sPAPRDIMMState));
+ uint64_t addr = addr_start;
+
+ ds->nr_lmbs = nr_lmbs;
+ for (i = 0; i < nr_lmbs; i++) {
+ drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB,
+ addr / SPAPR_MEMORY_BLOCK_SIZE);
+ g_assert(drc);
+
+ drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ drck->detach(drc, dev, spapr_lmb_release, ds, errp);
+ addr += SPAPR_MEMORY_BLOCK_SIZE;
+ }
+
+ drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB,
+ addr_start / SPAPR_MEMORY_BLOCK_SIZE);
+ drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
+ nr_lmbs,
+ drck->get_index(drc));
+}
+
+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);
+ object_unparent(OBJECT(dev));
+}
+
+static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ Error *local_err = NULL;
+ PCDIMMDevice *dimm = PC_DIMM(dev);
+ PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
+ MemoryRegion *mr = ddc->get_memory_region(dimm);
+ uint64_t size = memory_region_size(mr);
+ uint64_t addr;
+
+ addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ spapr_del_lmbs(dev, addr, size, &error_abort);
+out:
+ error_propagate(errp, local_err);
+}
+
void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
sPAPRMachineState *spapr)
{
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->query_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)
+{
+ sPAPRMachineState *sms = SPAPR_MACHINE(qdev_get_machine());
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
- error_setg(errp, "Memory hot unplug not supported by sPAPR");
+ if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) {
+ spapr_memory_unplug_request(hotplug_dev, dev, errp);
+ } else {
+ /* NOTE: this means there is a window after guest reset, prior to
+ * CAS negotiation, where unplug requests will fail due to the
+ * capability not being detected yet. This is a bit different than
+ * the case with PCI unplug, where the events will be queued and
+ * eventually handled by the guest after boot
+ */
+ error_setg(errp, "Memory hot unplug not supported for this guest");
+ }
} else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
if (!mc->query_hotpluggable_cpus) {
error_setg(errp, "CPU hot unplug not supported on this machine");
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)";
hc->plug = spapr_machine_device_plug;
hc->unplug = spapr_machine_device_unplug;
mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id;
+ hc->unplug_request = spapr_machine_device_unplug_request;
smc->dr_lmb_enabled = true;
smc->tcg_default_cpu = "POWER8";
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 = {
{ TYPE_FW_PATH_PROVIDER },
{ TYPE_NMI },
{ TYPE_HOTPLUG_HANDLER },
+ { TYPE_PPC_VIRTUAL_HYPERVISOR },
{ }
},
};
} \
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
.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,
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)