From 658c27181bf3b08a9cf2fab00ecce7f76065f6af Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Fri, 3 Apr 2015 18:03:34 +0800 Subject: hw/i386/acpi-build: move generic acpi building helpers into dedictated file Move generic acpi building helpers into dedictated file and this can be shared with other machines. Signed-off-by: Shannon Zhao Signed-off-by: Shannon Zhao Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/aml-build.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'hw/acpi') diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index d7945f6e2d..8d019590df 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -26,6 +26,7 @@ #include #include "hw/acpi/aml-build.h" #include "qemu/bswap.h" +#include "hw/acpi/bios-linker-loader.h" static GArray *build_alloc_array(void) { @@ -891,3 +892,60 @@ Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed, dec, addr_gran, addr_min, addr_max, addr_trans, len, flags); } + +void +build_header(GArray *linker, GArray *table_data, + AcpiTableHeader *h, const char *sig, int len, uint8_t rev) +{ + memcpy(&h->signature, sig, 4); + h->length = cpu_to_le32(len); + h->revision = rev; + memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6); + memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4); + memcpy(h->oem_table_id + 4, sig, 4); + h->oem_revision = cpu_to_le32(1); + memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4); + h->asl_compiler_revision = cpu_to_le32(1); + h->checksum = 0; + /* Checksum to be filled in by Guest linker */ + bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE, + table_data->data, h, len, &h->checksum); +} + +void *acpi_data_push(GArray *table_data, unsigned size) +{ + unsigned off = table_data->len; + g_array_set_size(table_data, off + size); + return table_data->data + off; +} + +unsigned acpi_data_len(GArray *table) +{ +#if GLIB_CHECK_VERSION(2, 22, 0) + assert(g_array_get_element_size(table) == 1); +#endif + return table->len; +} + +void acpi_add_table(GArray *table_offsets, GArray *table_data) +{ + uint32_t offset = cpu_to_le32(table_data->len); + g_array_append_val(table_offsets, offset); +} + +void acpi_build_tables_init(AcpiBuildTables *tables) +{ + tables->rsdp = g_array_new(false, true /* clear */, 1); + tables->table_data = g_array_new(false, true /* clear */, 1); + tables->tcpalog = g_array_new(false, true /* clear */, 1); + tables->linker = bios_linker_loader_init(); +} + +void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre) +{ + void *linker_data = bios_linker_loader_cleanup(tables->linker); + g_free(linker_data); + g_array_free(tables->rsdp, true); + g_array_free(tables->table_data, true); + g_array_free(tables->tcpalog, mfre); +} -- cgit v1.2.3 From 4aae99b63333e71b2097b106bb15a6fde7f9b55b Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Mon, 27 Apr 2015 16:47:16 +0800 Subject: acpi, mem-hotplug: add acpi_memory_slot_status() to get MemStatus Add a new API named acpi_memory_slot_status() to obtain a single memory slot status. Doing this is because this procedure will be used by other functions in the next coming patches. Reviewed-by: Igor Mammedov Signed-off-by: Tang Chen Signed-off-by: Zhu Guihua Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/memory_hotplug.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'hw/acpi') diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index c6580dabb7..6af93032d2 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -163,29 +163,51 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, memory_region_add_subregion(as, ACPI_MEMORY_HOTPLUG_BASE, &state->io); } -void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st, - DeviceState *dev, Error **errp) +/** + * acpi_memory_slot_status: + * @mem_st: memory hotplug state + * @dev: device + * @errp: set in case of an error + * + * Obtain a single memory slot status. + * + * This function will be called by memory unplug request cb and unplug cb. + */ +static MemStatus * +acpi_memory_slot_status(MemHotplugState *mem_st, + DeviceState *dev, Error **errp) { - MemStatus *mdev; Error *local_err = NULL; int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, &local_err); if (local_err) { error_propagate(errp, local_err); - return; + return NULL; } if (slot >= mem_st->dev_count) { char *dev_path = object_get_canonical_path(OBJECT(dev)); - error_setg(errp, "acpi_memory_plug_cb: " + error_setg(errp, "acpi_memory_slot_status: " "device [%s] returned invalid memory slot[%d]", dev_path, slot); g_free(dev_path); + return NULL; + } + + return &mem_st->devs[slot]; +} + +void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st, + DeviceState *dev, Error **errp) +{ + MemStatus *mdev; + + mdev = acpi_memory_slot_status(mem_st, dev, errp); + if (!mdev) { return; } - mdev = &mem_st->devs[slot]; mdev->dimm = dev; mdev->is_enabled = true; mdev->is_inserting = true; -- cgit v1.2.3 From 64fec58e8ab62490edd2638e4214d8c9f84518c9 Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Mon, 27 Apr 2015 16:47:17 +0800 Subject: acpi, mem-hotplug: add unplug request cb for memory device This patch adds unplug request cb for memory device, and adds the is_removing boolean field to MemStatus. This field is used to indicate whether the memory device in slot has been requested to be ejected. This field is set to true in acpi_memory_unplug_request_cb(). Reviewed-by: Igor Mammedov Signed-off-by: Tang Chen Signed-off-by: Zhu Guihua Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/ich9.c | 10 ++++++++-- hw/acpi/memory_hotplug.c | 19 +++++++++++++++++++ hw/acpi/piix4.c | 6 +++++- 3 files changed, 32 insertions(+), 3 deletions(-) (limited to 'hw/acpi') diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 5352e197cb..b85eed4a82 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -400,8 +400,14 @@ void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp) void ich9_pm_device_unplug_request_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp) { - error_setg(errp, "acpi: device unplug request for not supported device" - " type: %s", object_get_typename(OBJECT(dev))); + if (pm->acpi_memory_hotplug.is_enabled && + object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + acpi_memory_unplug_request_cb(&pm->acpi_regs, pm->irq, + &pm->acpi_memory_hotplug, dev, errp); + } else { + error_setg(errp, "acpi: device unplug request for not supported device" + " type: %s", object_get_typename(OBJECT(dev))); + } } void ich9_pm_device_unplug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 6af93032d2..42fe66850c 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -75,6 +75,7 @@ static uint64_t acpi_memory_hotplug_read(void *opaque, hwaddr addr, case 0x14: /* pack and return is_* fields */ val |= mdev->is_enabled ? 1 : 0; val |= mdev->is_inserting ? 2 : 0; + val |= mdev->is_removing ? 4 : 0; trace_mhp_acpi_read_flags(mem_st->selector, val); break; default: @@ -218,6 +219,24 @@ void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st, return; } +void acpi_memory_unplug_request_cb(ACPIREGS *ar, qemu_irq irq, + MemHotplugState *mem_st, + DeviceState *dev, Error **errp) +{ + MemStatus *mdev; + + mdev = acpi_memory_slot_status(mem_st, dev, errp); + if (!mdev) { + return; + } + + mdev->is_removing = true; + + /* Do ACPI magic */ + ar->gpe.sts[0] |= ACPI_MEMORY_HOTPLUG_STATUS; + acpi_update_sci(ar, irq); +} + static const VMStateDescription vmstate_memhp_sts = { .name = "memory hotplug device state", .version_id = 1, diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index d1f11793a0..f716e916c2 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -361,7 +361,11 @@ static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev, { PIIX4PMState *s = PIIX4_PM(hotplug_dev); - if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + if (s->acpi_memory_hotplug.is_enabled && + object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + acpi_memory_unplug_request_cb(&s->ar, s->irq, &s->acpi_memory_hotplug, + dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { acpi_pcihp_device_unplug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev, errp); } else { -- cgit v1.2.3 From f7d3e29db5a5900a1f0ed10f8313f7c3f28e5b59 Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Mon, 27 Apr 2015 16:47:18 +0800 Subject: acpi, mem-hotplug: add unplug cb for memory device This patch adds unplug cb for memory device. It resets memory status "is_enabled" in acpi_memory_unplug_cb(), removes the corresponding memory region, unregisters vmstate, and unparents the object. Reviewed-by: Igor Mammedov Signed-off-by: Tang Chen Signed-off-by: Zhu Guihua Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/ich9.c | 9 +++++++-- hw/acpi/memory_hotplug.c | 14 ++++++++++++++ hw/acpi/piix4.c | 11 +++++++++-- 3 files changed, 30 insertions(+), 4 deletions(-) (limited to 'hw/acpi') diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index b85eed4a82..84e5bb8d39 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -413,8 +413,13 @@ void ich9_pm_device_unplug_request_cb(ICH9LPCPMRegs *pm, DeviceState *dev, void ich9_pm_device_unplug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp) { - error_setg(errp, "acpi: device unplug for not supported device" - " type: %s", object_get_typename(OBJECT(dev))); + if (pm->acpi_memory_hotplug.is_enabled && + object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + acpi_memory_unplug_cb(&pm->acpi_memory_hotplug, dev, errp); + } else { + error_setg(errp, "acpi: device unplug for not supported device" + " type: %s", object_get_typename(OBJECT(dev))); + } } void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 42fe66850c..07e281f4a8 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -237,6 +237,20 @@ void acpi_memory_unplug_request_cb(ACPIREGS *ar, qemu_irq irq, acpi_update_sci(ar, irq); } +void acpi_memory_unplug_cb(MemHotplugState *mem_st, + DeviceState *dev, Error **errp) +{ + MemStatus *mdev; + + mdev = acpi_memory_slot_status(mem_st, dev, errp); + if (!mdev) { + return; + } + + mdev->is_enabled = false; + mdev->dimm = NULL; +} + static const VMStateDescription vmstate_memhp_sts = { .name = "memory hotplug device state", .version_id = 1, diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index f716e916c2..1b28481bbd 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -377,8 +377,15 @@ static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev, static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - error_setg(errp, "acpi: device unplug for not supported device" - " type: %s", object_get_typename(OBJECT(dev))); + PIIX4PMState *s = PIIX4_PM(hotplug_dev); + + if (s->acpi_memory_hotplug.is_enabled && + object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp); + } else { + error_setg(errp, "acpi: device unplug for not supported device" + " type: %s", object_get_typename(OBJECT(dev))); + } } static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque) -- cgit v1.2.3 From af5098973136029211848b4999ad5d38bc90180f Mon Sep 17 00:00:00 2001 From: Zhu Guihua Date: Mon, 27 Apr 2015 16:47:19 +0800 Subject: acpi: extend aml_field() to support UpdateRule The flags field is declared with default update rule 'Preserve', this patch extends aml_field() to support UpdateRule so that we can specify different values per field. Reviewed-by: Igor Mammedov Signed-off-by: Zhu Guihua Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/aml-build.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'hw/acpi') diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 8d019590df..77ce00b908 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -636,9 +636,11 @@ Aml *aml_reserved_field(unsigned length) } /* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefField */ -Aml *aml_field(const char *name, AmlFieldFlags flags) +Aml *aml_field(const char *name, AmlAccessType type, AmlUpdateRule rule) { Aml *var = aml_bundle(0x81 /* FieldOp */, AML_EXT_PACKAGE); + uint8_t flags = rule << 5 | type; + build_append_namestring(var->buf, "%s", name); build_append_byte(var->buf, flags); return var; -- cgit v1.2.3 From c06b2ffb02bfcc642c67300d2c4dffd5aa54932b Mon Sep 17 00:00:00 2001 From: Zhu Guihua Date: Mon, 27 Apr 2015 16:47:21 +0800 Subject: acpi: add hardware implementation for memory hot unplug - implements QEMU hardware part of memory hot unplug protocol described at "docs/spec/acpi_mem_hotplug.txt" - handles memory remove notification event - handles device eject notification Reviewed-by: Igor Mammedov Signed-off-by: Zhu Guihua Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/memory_hotplug.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'hw/acpi') diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 07e281f4a8..35bbfeb1d8 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -2,6 +2,7 @@ #include "hw/acpi/pc-hotplug.h" #include "hw/mem/pc-dimm.h" #include "hw/boards.h" +#include "hw/qdev-core.h" #include "trace.h" #include "qapi-event.h" @@ -91,6 +92,8 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data, MemHotplugState *mem_st = opaque; MemStatus *mdev; ACPIOSTInfo *info; + DeviceState *dev = NULL; + HotplugHandler *hotplug_ctrl = NULL; if (!mem_st->dev_count) { return; @@ -128,13 +131,29 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data, qapi_event_send_acpi_device_ost(info, &error_abort); qapi_free_ACPIOSTInfo(info); break; - case 0x14: + case 0x14: /* set is_* fields */ mdev = &mem_st->devs[mem_st->selector]; if (data & 2) { /* clear insert event */ mdev->is_inserting = false; trace_mhp_acpi_clear_insert_evt(mem_st->selector); + } else if (data & 4) { + mdev->is_removing = false; + trace_mhp_acpi_clear_remove_evt(mem_st->selector); + } else if (data & 8) { + if (!mdev->is_enabled) { + trace_mhp_acpi_ejecting_invalid_slot(mem_st->selector); + break; + } + + dev = DEVICE(mdev->dimm); + hotplug_ctrl = qdev_get_hotplug_handler(dev); + /* call pc-dimm unplug cb */ + hotplug_handler_unplug(hotplug_ctrl, dev, NULL); + trace_mhp_acpi_pc_dimm_deleted(mem_st->selector); } break; + default: + break; } } -- cgit v1.2.3 From bc09e06113e79e5d70cf2b37015a26f2102cc03e Mon Sep 17 00:00:00 2001 From: Zhu Guihua Date: Mon, 27 Apr 2015 16:47:22 +0800 Subject: qmp-event: add event notification for memory hot unplug error When memory hot unplug fails, this patch adds support to send QMP event to notify mgmt about this failure. Reviewed-by: Igor Mammedov Signed-off-by: Zhu Guihua Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/memory_hotplug.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'hw/acpi') diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 35bbfeb1d8..34cef1e5c3 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -94,6 +94,7 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data, ACPIOSTInfo *info; DeviceState *dev = NULL; HotplugHandler *hotplug_ctrl = NULL; + Error *local_err = NULL; if (!mem_st->dev_count) { return; @@ -148,7 +149,14 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data, dev = DEVICE(mdev->dimm); hotplug_ctrl = qdev_get_hotplug_handler(dev); /* call pc-dimm unplug cb */ - hotplug_handler_unplug(hotplug_ctrl, dev, NULL); + hotplug_handler_unplug(hotplug_ctrl, dev, &local_err); + if (local_err) { + trace_mhp_acpi_pc_dimm_delete_failed(mem_st->selector); + qapi_event_send_mem_unplug_error(dev->id, + error_get_pretty(local_err), + &error_abort); + break; + } trace_mhp_acpi_pc_dimm_deleted(mem_st->selector); } break; -- cgit v1.2.3