|
|
76daa3 |
From 3d589a2d3dbe2a376122713cb67be0e3b64d8f3f Mon Sep 17 00:00:00 2001
|
|
|
76daa3 |
From: Auger Eric <eric.auger@redhat.com>
|
|
|
76daa3 |
Date: Fri, 16 Jun 2017 15:17:54 +0200
|
|
|
76daa3 |
Subject: [PATCH 3/5] hw/intc/arm_gicv3_its: Implement state save/restore
|
|
|
76daa3 |
|
|
|
76daa3 |
RH-Author: Auger Eric <eric.auger@redhat.com>
|
|
|
76daa3 |
Message-id: <1497626276-18221-4-git-send-email-eric.auger@redhat.com>
|
|
|
76daa3 |
Patchwork-id: 75634
|
|
|
76daa3 |
O-Subject: [Pegas-1.0 qemu-kvm PATCH v2 3/5] hw/intc/arm_gicv3_its: Implement state save/restore
|
|
|
76daa3 |
Bugzilla: 1462061
|
|
|
76daa3 |
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
|
|
|
76daa3 |
RH-Acked-by: Peter Xu <peterx@redhat.com>
|
|
|
76daa3 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
76daa3 |
|
|
|
76daa3 |
We need to handle both registers and ITS tables. While
|
|
|
76daa3 |
register handling is standard, ITS table handling is more
|
|
|
76daa3 |
challenging since the kernel API is devised so that the
|
|
|
76daa3 |
tables are flushed into guest RAM and not in vmstate buffers.
|
|
|
76daa3 |
|
|
|
76daa3 |
Flushing the ITS tables on device pre_save() is too late
|
|
|
76daa3 |
since the guest RAM is already saved at this point.
|
|
|
76daa3 |
|
|
|
76daa3 |
Table flushing needs to happen when we are sure the vcpus
|
|
|
76daa3 |
are stopped and before the last dirty page saving. The
|
|
|
76daa3 |
right point is RUN_STATE_FINISH_MIGRATE but sometimes the
|
|
|
76daa3 |
VM gets stopped before migration launch so let's simply
|
|
|
76daa3 |
flush the tables each time the VM gets stopped.
|
|
|
76daa3 |
|
|
|
76daa3 |
For regular ITS registers we just can use vmstate pre_save()
|
|
|
76daa3 |
and post_load() callbacks.
|
|
|
76daa3 |
|
|
|
76daa3 |
Signed-off-by: Eric Auger <eric.auger@redhat.com>
|
|
|
76daa3 |
Message-id: 1497023553-18411-3-git-send-email-eric.auger@redhat.com
|
|
|
76daa3 |
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
|
|
76daa3 |
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
|
|
76daa3 |
(cherry picked from commit cddafd8f353d2d251b1a5c6c948a577a85838582)
|
|
|
76daa3 |
Signed-off-by: Eric Auger <eric.auger@redhat.com>
|
|
|
76daa3 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
76daa3 |
---
|
|
|
76daa3 |
hw/intc/arm_gicv3_its_common.c | 10 ++++
|
|
|
76daa3 |
hw/intc/arm_gicv3_its_kvm.c | 105 +++++++++++++++++++++++++++++++++
|
|
|
76daa3 |
include/hw/intc/arm_gicv3_its_common.h | 8 +++
|
|
|
76daa3 |
3 files changed, 123 insertions(+)
|
|
|
76daa3 |
|
|
|
76daa3 |
diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c
|
|
|
76daa3 |
index 9d67c5c..696c11c 100644
|
|
|
76daa3 |
--- a/hw/intc/arm_gicv3_its_common.c
|
|
|
76daa3 |
+++ b/hw/intc/arm_gicv3_its_common.c
|
|
|
76daa3 |
@@ -49,6 +49,15 @@ static const VMStateDescription vmstate_its = {
|
|
|
76daa3 |
.pre_save = gicv3_its_pre_save,
|
|
|
76daa3 |
.post_load = gicv3_its_post_load,
|
|
|
76daa3 |
.unmigratable = true,
|
|
|
76daa3 |
+ .fields = (VMStateField[]) {
|
|
|
76daa3 |
+ VMSTATE_UINT32(ctlr, GICv3ITSState),
|
|
|
76daa3 |
+ VMSTATE_UINT32(iidr, GICv3ITSState),
|
|
|
76daa3 |
+ VMSTATE_UINT64(cbaser, GICv3ITSState),
|
|
|
76daa3 |
+ VMSTATE_UINT64(cwriter, GICv3ITSState),
|
|
|
76daa3 |
+ VMSTATE_UINT64(creadr, GICv3ITSState),
|
|
|
76daa3 |
+ VMSTATE_UINT64_ARRAY(baser, GICv3ITSState, 8),
|
|
|
76daa3 |
+ VMSTATE_END_OF_LIST()
|
|
|
76daa3 |
+ },
|
|
|
76daa3 |
};
|
|
|
76daa3 |
|
|
|
76daa3 |
static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset,
|
|
|
76daa3 |
@@ -118,6 +127,7 @@ static void gicv3_its_common_reset(DeviceState *dev)
|
|
|
76daa3 |
s->cbaser = 0;
|
|
|
76daa3 |
s->cwriter = 0;
|
|
|
76daa3 |
s->creadr = 0;
|
|
|
76daa3 |
+ s->iidr = 0;
|
|
|
76daa3 |
memset(&s->baser, 0, sizeof(s->baser));
|
|
|
76daa3 |
|
|
|
76daa3 |
gicv3_its_post_load(s, 0);
|
|
|
76daa3 |
diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c
|
|
|
76daa3 |
index ad2a1db..3c7c28c 100644
|
|
|
76daa3 |
--- a/hw/intc/arm_gicv3_its_kvm.c
|
|
|
76daa3 |
+++ b/hw/intc/arm_gicv3_its_kvm.c
|
|
|
76daa3 |
@@ -53,6 +53,33 @@ static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid)
|
|
|
76daa3 |
return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi;;
|
|
|
76daa3 |
}
|
|
|
76daa3 |
|
|
|
76daa3 |
+/**
|
|
|
76daa3 |
+ * vm_change_state_handler - VM change state callback aiming at flushing
|
|
|
76daa3 |
+ * ITS tables into guest RAM
|
|
|
76daa3 |
+ *
|
|
|
76daa3 |
+ * The tables get flushed to guest RAM whenever the VM gets stopped.
|
|
|
76daa3 |
+ */
|
|
|
76daa3 |
+static void vm_change_state_handler(void *opaque, int running,
|
|
|
76daa3 |
+ RunState state)
|
|
|
76daa3 |
+{
|
|
|
76daa3 |
+ GICv3ITSState *s = (GICv3ITSState *)opaque;
|
|
|
76daa3 |
+ Error *err = NULL;
|
|
|
76daa3 |
+ int ret;
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ if (running) {
|
|
|
76daa3 |
+ return;
|
|
|
76daa3 |
+ }
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
|
|
|
76daa3 |
+ KVM_DEV_ARM_ITS_SAVE_TABLES, NULL, true, &err;;
|
|
|
76daa3 |
+ if (err) {
|
|
|
76daa3 |
+ error_report_err(err);
|
|
|
76daa3 |
+ }
|
|
|
76daa3 |
+ if (ret < 0 && ret != -EFAULT) {
|
|
|
76daa3 |
+ abort();
|
|
|
76daa3 |
+ }
|
|
|
76daa3 |
+}
|
|
|
76daa3 |
+
|
|
|
76daa3 |
static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
|
|
|
76daa3 |
{
|
|
|
76daa3 |
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
|
|
|
76daa3 |
@@ -89,6 +116,8 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
|
|
|
76daa3 |
kvm_msi_use_devid = true;
|
|
|
76daa3 |
kvm_gsi_direct_mapping = false;
|
|
|
76daa3 |
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ qemu_add_vm_change_state_handler(vm_change_state_handler, s);
|
|
|
76daa3 |
}
|
|
|
76daa3 |
|
|
|
76daa3 |
static void kvm_arm_its_init(Object *obj)
|
|
|
76daa3 |
@@ -102,6 +131,80 @@ static void kvm_arm_its_init(Object *obj)
|
|
|
76daa3 |
&error_abort);
|
|
|
76daa3 |
}
|
|
|
76daa3 |
|
|
|
76daa3 |
+/**
|
|
|
76daa3 |
+ * kvm_arm_its_pre_save - handles the saving of ITS registers.
|
|
|
76daa3 |
+ * ITS tables are flushed into guest RAM separately and earlier,
|
|
|
76daa3 |
+ * through the VM change state handler, since at the moment pre_save()
|
|
|
76daa3 |
+ * is called, the guest RAM has already been saved.
|
|
|
76daa3 |
+ */
|
|
|
76daa3 |
+static void kvm_arm_its_pre_save(GICv3ITSState *s)
|
|
|
76daa3 |
+{
|
|
|
76daa3 |
+ int i;
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ for (i = 0; i < 8; i++) {
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_BASER + i * 8, &s->baser[i], false,
|
|
|
76daa3 |
+ &error_abort);
|
|
|
76daa3 |
+ }
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_CTLR, &s->ctlr, false, &error_abort);
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_CBASER, &s->cbaser, false, &error_abort);
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_CREADR, &s->creadr, false, &error_abort);
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_CWRITER, &s->cwriter, false, &error_abort);
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_IIDR, &s->iidr, false, &error_abort);
|
|
|
76daa3 |
+}
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+/**
|
|
|
76daa3 |
+ * kvm_arm_its_post_load - Restore both the ITS registers and tables
|
|
|
76daa3 |
+ */
|
|
|
76daa3 |
+static void kvm_arm_its_post_load(GICv3ITSState *s)
|
|
|
76daa3 |
+{
|
|
|
76daa3 |
+ int i;
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ if (!s->iidr) {
|
|
|
76daa3 |
+ return;
|
|
|
76daa3 |
+ }
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_IIDR, &s->iidr, true, &error_abort);
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ /*
|
|
|
76daa3 |
+ * must be written before GITS_CREADR since GITS_CBASER write
|
|
|
76daa3 |
+ * access resets GITS_CREADR.
|
|
|
76daa3 |
+ */
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_CBASER, &s->cbaser, true, &error_abort);
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_CREADR, &s->creadr, true, &error_abort);
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_CWRITER, &s->cwriter, true, &error_abort);
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ for (i = 0; i < 8; i++) {
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_BASER + i * 8, &s->baser[i], true,
|
|
|
76daa3 |
+ &error_abort);
|
|
|
76daa3 |
+ }
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
|
|
|
76daa3 |
+ KVM_DEV_ARM_ITS_RESTORE_TABLES, NULL, true,
|
|
|
76daa3 |
+ &error_abort);
|
|
|
76daa3 |
+
|
|
|
76daa3 |
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
|
76daa3 |
+ GITS_CTLR, &s->ctlr, true, &error_abort);
|
|
|
76daa3 |
+}
|
|
|
76daa3 |
+
|
|
|
76daa3 |
static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
|
|
|
76daa3 |
{
|
|
|
76daa3 |
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
76daa3 |
@@ -109,6 +212,8 @@ static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
|
|
|
76daa3 |
|
|
|
76daa3 |
dc->realize = kvm_arm_its_realize;
|
|
|
76daa3 |
icc->send_msi = kvm_its_send_msi;
|
|
|
76daa3 |
+ icc->pre_save = kvm_arm_its_pre_save;
|
|
|
76daa3 |
+ icc->post_load = kvm_arm_its_post_load;
|
|
|
76daa3 |
}
|
|
|
76daa3 |
|
|
|
76daa3 |
static const TypeInfo kvm_arm_its_info = {
|
|
|
76daa3 |
diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h
|
|
|
76daa3 |
index 1ba1894..fd1fe64 100644
|
|
|
76daa3 |
--- a/include/hw/intc/arm_gicv3_its_common.h
|
|
|
76daa3 |
+++ b/include/hw/intc/arm_gicv3_its_common.h
|
|
|
76daa3 |
@@ -28,6 +28,13 @@
|
|
|
76daa3 |
#define ITS_TRANS_SIZE 0x10000
|
|
|
76daa3 |
#define ITS_SIZE (ITS_CONTROL_SIZE + ITS_TRANS_SIZE)
|
|
|
76daa3 |
|
|
|
76daa3 |
+#define GITS_CTLR 0x0
|
|
|
76daa3 |
+#define GITS_IIDR 0x4
|
|
|
76daa3 |
+#define GITS_CBASER 0x80
|
|
|
76daa3 |
+#define GITS_CWRITER 0x88
|
|
|
76daa3 |
+#define GITS_CREADR 0x90
|
|
|
76daa3 |
+#define GITS_BASER 0x100
|
|
|
76daa3 |
+
|
|
|
76daa3 |
struct GICv3ITSState {
|
|
|
76daa3 |
SysBusDevice parent_obj;
|
|
|
76daa3 |
|
|
|
76daa3 |
@@ -43,6 +50,7 @@ struct GICv3ITSState {
|
|
|
76daa3 |
|
|
|
76daa3 |
/* Registers */
|
|
|
76daa3 |
uint32_t ctlr;
|
|
|
76daa3 |
+ uint32_t iidr;
|
|
|
76daa3 |
uint64_t cbaser;
|
|
|
76daa3 |
uint64_t cwriter;
|
|
|
76daa3 |
uint64_t creadr;
|
|
|
76daa3 |
--
|
|
|
76daa3 |
1.8.3.1
|
|
|
76daa3 |
|