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>
This commit is contained in:
parent
1cd5db2e88
commit
c3da26f314
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user