diff options
Diffstat (limited to 'hw/ppc/spapr.c')
| -rw-r--r-- | hw/ppc/spapr.c | 124 |
1 files changed, 101 insertions, 23 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c9b2e0a5e0..c03ce6afb9 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -80,6 +80,7 @@ #include "hw/ppc/spapr_cpu_core.h" #include "hw/mem/memory-device.h" #include "hw/ppc/spapr_tpm_proxy.h" +#include "hw/ppc/spapr_nvdimm.h" #include "monitor/monitor.h" @@ -675,6 +676,14 @@ static int spapr_populate_drmem_v2(SpaprMachineState *spapr, void *fdt, size = di->size; node = di->node; + /* + * The NVDIMM area is hotpluggable after the NVDIMM is unplugged. The + * area is marked hotpluggable in the next iteration for the bigger + * chunk including the NVDIMM occupied area. + */ + if (info->value->type == MEMORY_DEVICE_INFO_KIND_NVDIMM) + continue; + /* Entry for hot-pluggable area */ if (cur_addr < addr) { drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, cur_addr / lmb_size); @@ -1055,7 +1064,7 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt) } if (spapr->kernel_size) { - uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR), + uint64_t kprop[2] = { cpu_to_be64(spapr->kernel_addr), cpu_to_be64(spapr->kernel_size) }; _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel", @@ -1243,7 +1252,8 @@ void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space) /* Build memory reserve map */ if (reset) { if (spapr->kernel_size) { - _FDT((fdt_add_mem_rsv(fdt, KERNEL_LOAD_ADDR, spapr->kernel_size))); + _FDT((fdt_add_mem_rsv(fdt, spapr->kernel_addr, + spapr->kernel_size))); } if (spapr->initrd_size) { _FDT((fdt_add_mem_rsv(fdt, spapr->initrd_base, @@ -1266,12 +1276,19 @@ void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space) } } + /* NVDIMM devices */ + if (mc->nvdimm_supported) { + spapr_dt_persistent_memory(fdt); + } + return fdt; } static uint64_t translate_kernel_address(void *opaque, uint64_t addr) { - return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; + SpaprMachineState *spapr = opaque; + + return (addr & 0x0fffffff) + spapr->kernel_addr; } static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp, @@ -2629,12 +2646,12 @@ static void spapr_machine_init(MachineState *machine) { SpaprMachineState *spapr = SPAPR_MACHINE(machine); SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); + MachineClass *mc = MACHINE_GET_CLASS(machine); const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; PCIHostState *phb; int i; MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); hwaddr node0_size = spapr_node0_size(machine); long load_limit, fw_size; char *filename; @@ -2813,10 +2830,8 @@ static void spapr_machine_init(MachineState *machine) kvmppc_enable_h_page_init(); } - /* allocate RAM */ - memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram", - machine->ram_size); - memory_region_add_subregion(sysmem, 0, ram); + /* map RAM */ + memory_region_add_subregion(sysmem, 0, machine->ram); /* always allocate the device memory information */ machine->device_memory = g_malloc0(sizeof(*machine->device_memory)); @@ -2861,6 +2876,10 @@ static void spapr_machine_init(MachineState *machine) "may run and log hardware error on the destination"); } + if (mc->nvdimm_supported) { + spapr_create_nvdimm_dr_connectors(spapr); + } + /* Set up RTAS event infrastructure */ spapr_events_init(spapr); @@ -2948,14 +2967,15 @@ static void spapr_machine_init(MachineState *machine) uint64_t lowaddr = 0; spapr->kernel_size = load_elf(kernel_filename, NULL, - translate_kernel_address, NULL, + translate_kernel_address, spapr, NULL, &lowaddr, NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0); if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) { spapr->kernel_size = load_elf(kernel_filename, NULL, - translate_kernel_address, NULL, NULL, + translate_kernel_address, spapr, NULL, &lowaddr, NULL, NULL, 0, - PPC_ELF_MACHINE, 0, 0); + PPC_ELF_MACHINE, + 0, 0); spapr->kernel_le = spapr->kernel_size > 0; } if (spapr->kernel_size < 0) { @@ -2969,7 +2989,7 @@ static void spapr_machine_init(MachineState *machine) /* Try to locate the initrd in the gap between the kernel * and the firmware. Add a bit of space just in case */ - spapr->initrd_base = (KERNEL_LOAD_ADDR + spapr->kernel_size + spapr->initrd_base = (spapr->kernel_addr + spapr->kernel_size + 0x1ffff) & ~0xffff; spapr->initrd_size = load_image_targphys(initrd_filename, spapr->initrd_base, @@ -3215,6 +3235,18 @@ static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name, visit_type_uint32(v, name, (uint32_t *)opaque, errp); } +static void spapr_get_kernel_addr(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + visit_type_uint64(v, name, (uint64_t *)opaque, errp); +} + +static void spapr_set_kernel_addr(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + visit_type_uint64(v, name, (uint64_t *)opaque, errp); +} + static char *spapr_get_ic_mode(Object *obj, Error **errp) { SpaprMachineState *spapr = SPAPR_MACHINE(obj); @@ -3320,6 +3352,14 @@ static void spapr_instance_init(Object *obj) object_property_add_bool(obj, "vfio-no-msix-emulation", spapr_get_msix_emulation, NULL, NULL); + object_property_add(obj, "kernel-addr", "uint64", spapr_get_kernel_addr, + spapr_set_kernel_addr, NULL, &spapr->kernel_addr, + &error_abort); + object_property_set_description(obj, "kernel-addr", + stringify(KERNEL_LOAD_ADDR) + " for -kernel is the default", + NULL); + spapr->kernel_addr = KERNEL_LOAD_ADDR; /* The machine class defines the default interrupt controller mode */ spapr->irq = smc->irq; object_property_add_str(obj, "ic-mode", spapr_get_ic_mode, @@ -3430,7 +3470,8 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error *local_err = NULL; SpaprMachineState *ms = SPAPR_MACHINE(hotplug_dev); PCDIMMDevice *dimm = PC_DIMM(dev); - uint64_t size, addr; + uint64_t size, addr, slot; + bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM); size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort); @@ -3439,14 +3480,24 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev, goto out; } - addr = object_property_get_uint(OBJECT(dimm), - PC_DIMM_ADDR_PROP, &local_err); - if (local_err) { - goto out_unplug; + if (!is_nvdimm) { + addr = object_property_get_uint(OBJECT(dimm), + PC_DIMM_ADDR_PROP, &local_err); + if (local_err) { + goto out_unplug; + } + spapr_add_lmbs(dev, addr, size, + spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT), + &local_err); + } else { + slot = object_property_get_uint(OBJECT(dimm), + PC_DIMM_SLOT_PROP, &local_err); + if (local_err) { + goto out_unplug; + } + spapr_add_nvdimm(dev, slot, &local_err); } - spapr_add_lmbs(dev, addr, size, spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT), - &local_err); if (local_err) { goto out_unplug; } @@ -3464,6 +3515,8 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, { const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev); SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev); + const MachineClass *mc = MACHINE_CLASS(smc); + bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM); PCDIMMDevice *dimm = PC_DIMM(dev); Error *local_err = NULL; uint64_t size; @@ -3475,16 +3528,27 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } + if (is_nvdimm && !mc->nvdimm_supported) { + error_setg(errp, "NVDIMM hotplug not supported for this machine"); + return; + } + size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err); if (local_err) { error_propagate(errp, local_err); return; } - if (size % SPAPR_MEMORY_BLOCK_SIZE) { + if (!is_nvdimm && size % SPAPR_MEMORY_BLOCK_SIZE) { error_setg(errp, "Hotplugged memory size must be a multiple of " - "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB); + "%" PRIu64 " MB", SPAPR_MEMORY_BLOCK_SIZE / MiB); return; + } else if (is_nvdimm) { + spapr_nvdimm_validate_opts(NVDIMM(dev), size, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } } memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP, @@ -3624,6 +3688,12 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, int i; SpaprDrc *drc; + if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { + error_setg(&local_err, + "nvdimm device hot unplug is not supported yet."); + goto out; + } + size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort); nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE; @@ -4400,6 +4470,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->no_parallel = 1; mc->default_boot_order = ""; mc->default_ram_size = 512 * MiB; + mc->default_ram_id = "ppc_spapr.ram"; mc->default_display = "std"; mc->kvm_type = spapr_kvm_type; machine_class_allow_dynamic_sysbus_dev(mc, TYPE_SPAPR_PCI_HOST_BRIDGE); @@ -4418,6 +4489,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) smc->update_dt_enabled = true; mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0"); mc->has_hotpluggable_cpus = true; + mc->nvdimm_supported = true; smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; @@ -4485,6 +4557,12 @@ static const TypeInfo spapr_machine_info = { }, }; +static void spapr_machine_latest_class_options(MachineClass *mc) +{ + mc->alias = "pseries"; + mc->is_default = 1; +} + #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest) \ static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \ void *data) \ @@ -4492,8 +4570,7 @@ static const TypeInfo spapr_machine_info = { MachineClass *mc = MACHINE_CLASS(oc); \ spapr_machine_##suffix##_class_options(mc); \ if (latest) { \ - mc->alias = "pseries"; \ - mc->is_default = 1; \ + spapr_machine_latest_class_options(mc); \ } \ } \ static const TypeInfo spapr_machine_##suffix##_info = { \ @@ -4528,6 +4605,7 @@ static void spapr_machine_4_2_class_options(MachineClass *mc) compat_props_add(mc->compat_props, hw_compat_4_2, hw_compat_4_2_len); smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF; smc->default_caps.caps[SPAPR_CAP_FWNMI_MCE] = SPAPR_CAP_OFF; + mc->nvdimm_supported = false; } DEFINE_SPAPR_MACHINE(4_2, "4.2", false); |