aboutsummaryrefslogtreecommitdiff
path: root/hw/acpi
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-05-11 16:21:50 +0100
committerPeter Maydell <peter.maydell@linaro.org>2015-05-11 16:25:33 +0100
commit0403b0f539f40a21da60409b825b4653b273ab39 (patch)
treeef1edb203dc4595528c0f86c502df3a8d2931a2b /hw/acpi
parent266745cacb848d7cd0ae8889ae262e8718ace4d4 (diff)
parentbc1f7c4c915a7c727741c4d27a2795e1039eacd3 (diff)
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc, virtio enhancements Memory hot-unplug support for pc, MSI-X mapping update speedup for virtio-pci, misc refactorings and bugfixes. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Mon May 11 08:23:43 2015 BST using RSA key ID D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" * remotes/mst/tags/for_upstream: (28 commits) acpi: update expected files for memory unplug virtio-scsi: Move DEFINE_VIRTIO_SCSI_FEATURES to virtio-scsi virtio-net: Move DEFINE_VIRTIO_NET_FEATURES to virtio-net pci: Merge pci_nic_init() into pci_nic_init_nofail() acpi: add a missing backslash to the \_SB scope. qmp-event: add event notification for memory hot unplug error acpi: add hardware implementation for memory hot unplug acpi: fix "Memory device control fields" register acpi: extend aml_field() to support UpdateRule acpi, mem-hotplug: add unplug cb for memory device acpi, mem-hotplug: add unplug request cb for memory device acpi, mem-hotplug: add acpi_memory_slot_status() to get MemStatus docs: update documentation for memory hot unplug virtio: coding style tweak pci: remove hard-coded bar size in msix_init_exclusive_bar() virtio-pci: speedup MSI-X masking and unmasking virtio: introduce vector to virtqueues mapping virtio-ccw: using VIRTIO_NO_VECTOR instead of 0 for invalid virtqueue monitor: check return value of qemu_find_net_clients_except() monitor: replace the magic number 255 with MAX_QUEUE_NUM ... Conflicts: hw/s390x/s390-virtio-bus.c [PMM: fixed conflict in s390_virtio_scsi_properties and s390_virtio_net_properties arrays; since the result of the two conflicting patches is to empty the property arrays completely, the conflict resolution is to remove them entirely.] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/acpi')
-rw-r--r--hw/acpi/aml-build.c62
-rw-r--r--hw/acpi/ich9.c19
-rw-r--r--hw/acpi/memory_hotplug.c96
-rw-r--r--hw/acpi/piix4.c17
4 files changed, 179 insertions, 15 deletions
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index d7945f6e2d..77ce00b908 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -26,6 +26,7 @@
#include <string.h>
#include "hw/acpi/aml-build.h"
#include "qemu/bswap.h"
+#include "hw/acpi/bios-linker-loader.h"
static GArray *build_alloc_array(void)
{
@@ -635,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;
@@ -891,3 +894,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);
+}
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index 5352e197cb..84e5bb8d39 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -400,15 +400,26 @@ 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,
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 c6580dabb7..34cef1e5c3 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"
@@ -75,6 +76,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:
@@ -90,6 +92,9 @@ 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;
+ Error *local_err = NULL;
if (!mem_st->dev_count) {
return;
@@ -127,13 +132,36 @@ 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, &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;
+ default:
+ break;
}
}
@@ -163,29 +191,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;
@@ -196,6 +246,38 @@ 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);
+}
+
+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 d1f11793a0..1b28481bbd 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 {
@@ -373,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)