aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorXiaojuan Yang <yangxiaojuan@loongson.cn>2022-08-25 11:36:59 +0800
committerSong Gao <gaosong@loongson.cn>2022-09-20 15:44:25 +0800
commitc3da26f314ad918ad36ca1373ea7c7f1aa036a87 (patch)
tree14bae2ddaa6a24adca1f5dc3fe56663e3fcd9bfa /hw
parent1cd5db2e8836dc2e1e8fe83f6a2fc101c539df0c (diff)
downloadqemu-c3da26f314ad918ad36ca1373ea7c7f1aa036a87.zip
qemu-c3da26f314ad918ad36ca1373ea7c7f1aa036a87.tar.gz
qemu-c3da26f314ad918ad36ca1373ea7c7f1aa036a87.tar.bz2
hw/loongarch: Support memory hotplug
Add hotplug/unplug interface for memory device. Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn> Acked-by: Song Gao <gaosong@loongson.cn> Message-Id: <20220908094623.73051-9-yangxiaojuan@loongson.cn> Signed-off-by: Song Gao <gaosong@loongson.cn>
Diffstat (limited to 'hw')
-rw-r--r--hw/loongarch/Kconfig2
-rw-r--r--hw/loongarch/acpi-build.c32
-rw-r--r--hw/loongarch/virt.c105
3 files changed, 132 insertions, 7 deletions
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index fef55c5..17d15b6 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -4,6 +4,7 @@ config LOONGARCH_VIRT
select PCI_EXPRESS_GENERIC_BRIDGE
imply VIRTIO_VGA
imply PCI_DEVICES
+ imply NVDIMM
select ISA_BUS
select SERIAL
select SERIAL_ISA
@@ -18,3 +19,4 @@ config LOONGARCH_VIRT
select ACPI_PCI
select ACPI_HW_REDUCED
select FW_CFG_DMA
+ select DIMM
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index 95e3097..92ee62c 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -186,6 +186,12 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
build_srat_memory(table_data, VIRT_HIGHMEM_BASE, machine->ram_size - VIRT_LOWMEM_SIZE,
0, MEM_AFFINITY_ENABLED);
+ if (ms->device_memory) {
+ build_srat_memory(table_data, ms->device_memory->base,
+ memory_region_size(&ms->device_memory->mr),
+ 0, MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
+ }
+
acpi_table_end(linker, &table);
}
@@ -335,6 +341,25 @@ static void build_uart_device_aml(Aml *table)
aml_append(table, scope);
}
+static void
+build_la_ged_aml(Aml *dsdt, MachineState *machine)
+{
+ uint32_t event;
+ LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+
+ build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
+ HOTPLUG_HANDLER(lams->acpi_ged),
+ VIRT_SCI_IRQ, AML_SYSTEM_MEMORY,
+ VIRT_GED_EVT_ADDR);
+ event = object_property_get_uint(OBJECT(lams->acpi_ged),
+ "ged-event", &error_abort);
+ if (event & ACPI_GED_MEM_HOTPLUG_EVT) {
+ build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL,
+ AML_SYSTEM_MEMORY,
+ VIRT_GED_MEM_ADDR);
+ }
+}
+
/* build DSDT */
static void
build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
@@ -364,12 +389,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
build_gpex_pci0_int(dsdt);
build_uart_device_aml(dsdt);
- if (lams->acpi_ged) {
- build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
- HOTPLUG_HANDLER(lams->acpi_ged),
- VIRT_SCI_IRQ, AML_SYSTEM_MEMORY,
- VIRT_GED_EVT_ADDR);
- }
+ build_la_ged_aml(dsdt, machine);
scope = aml_scope("\\_SB.PCI0");
/* Build PCI0._CRS */
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 0dd5793..fe175e8 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -40,6 +40,7 @@
#include "hw/core/sysbus-fdt.h"
#include "hw/platform-bus.h"
#include "hw/display/ramfb.h"
+#include "hw/mem/pc-dimm.h"
static void create_fdt(LoongArchMachineState *lams)
{
@@ -718,6 +719,35 @@ static void loongarch_init(MachineState *machine)
machine->ram, offset, highram_size);
memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
memmap_add_entry(0x90000000, highram_size, 1);
+
+ /* initialize device memory address space */
+ if (machine->ram_size < machine->maxram_size) {
+ machine->device_memory = g_malloc0(sizeof(*machine->device_memory));
+ ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
+
+ if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) {
+ error_report("unsupported amount of memory slots: %"PRIu64,
+ machine->ram_slots);
+ exit(EXIT_FAILURE);
+ }
+
+ if (QEMU_ALIGN_UP(machine->maxram_size,
+ TARGET_PAGE_SIZE) != machine->maxram_size) {
+ error_report("maximum memory size must by aligned to multiple of "
+ "%d bytes", TARGET_PAGE_SIZE);
+ exit(EXIT_FAILURE);
+ }
+ /* device memory base is the top of high memory address. */
+ machine->device_memory->base = 0x90000000 + highram_size;
+ machine->device_memory->base =
+ ROUND_UP(machine->device_memory->base, 1 * GiB);
+
+ memory_region_init(&machine->device_memory->mr, OBJECT(lams),
+ "device-memory", device_mem_size);
+ memory_region_add_subregion(address_space_mem, machine->device_memory->base,
+ &machine->device_memory->mr);
+ }
+
/* Add isa io region */
memory_region_init_alias(&lams->isa_io, NULL, "isa-io",
get_system_io(), 0, VIRT_ISA_IO_SIZE);
@@ -804,6 +834,73 @@ static void loongarch_machine_initfn(Object *obj)
lams->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
}
+static bool memhp_type_supported(DeviceState *dev)
+{
+ /* we only support pc dimm now */
+ return object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
+ !object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
+}
+
+static void virt_mem_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), NULL, errp);
+}
+
+static void virt_machine_device_pre_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ if (memhp_type_supported(dev)) {
+ virt_mem_pre_plug(hotplug_dev, dev, errp);
+ }
+}
+
+static void virt_mem_unplug_request(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+
+ /* the acpi ged is always exist */
+ hotplug_handler_unplug_request(HOTPLUG_HANDLER(lams->acpi_ged), dev,
+ errp);
+}
+
+static void virt_machine_device_unplug_request(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ if (memhp_type_supported(dev)) {
+ virt_mem_unplug_request(hotplug_dev, dev, errp);
+ }
+}
+
+static void virt_mem_unplug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+
+ hotplug_handler_unplug(HOTPLUG_HANDLER(lams->acpi_ged), dev, errp);
+ pc_dimm_unplug(PC_DIMM(dev), MACHINE(lams));
+ qdev_unrealize(dev);
+}
+
+static void virt_machine_device_unplug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ if (memhp_type_supported(dev)) {
+ virt_mem_unplug(hotplug_dev, dev, errp);
+ }
+}
+
+static void virt_mem_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+
+ pc_dimm_plug(PC_DIMM(dev), MACHINE(lams));
+ hotplug_handler_plug(HOTPLUG_HANDLER(lams->acpi_ged),
+ dev, &error_abort);
+}
+
static void loongarch_machine_device_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
@@ -815,6 +912,8 @@ static void loongarch_machine_device_plug_cb(HotplugHandler *hotplug_dev,
platform_bus_link_device(PLATFORM_BUS_DEVICE(lams->platform_bus_dev),
SYS_BUS_DEVICE(dev));
}
+ } else if (memhp_type_supported(dev)) {
+ virt_mem_plug(hotplug_dev, dev, errp);
}
}
@@ -823,7 +922,8 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
{
MachineClass *mc = MACHINE_GET_CLASS(machine);
- if (device_is_dynamic_sysbus(mc, dev)) {
+ if (device_is_dynamic_sysbus(mc, dev) ||
+ memhp_type_supported(dev)) {
return HOTPLUG_HANDLER(machine);
}
return NULL;
@@ -847,6 +947,9 @@ static void loongarch_class_init(ObjectClass *oc, void *data)
mc->no_cdrom = 1;
mc->get_hotplug_handler = virt_machine_get_hotplug_handler;
hc->plug = loongarch_machine_device_plug_cb;
+ hc->pre_plug = virt_machine_device_pre_plug;
+ hc->unplug_request = virt_machine_device_unplug_request;
+ hc->unplug = virt_machine_device_unplug;
object_class_property_add(oc, "acpi", "OnOffAuto",
loongarch_get_acpi, loongarch_set_acpi,