From ee78356eba8df05043bac392c263450db5e7eed6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 Jun 2017 14:56:56 +0100 Subject: hw/intc/exynos4210_gic: Use more meaningful name for local variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are to SysBusDevice variables in exynos4210_gic_realize() function: one for the device itself and second for arm_gic device. Add a prefix "gic" to the second one so it will be easier to understand the code. While at it, put local uninitialized 'i' variable at the end, next to other uninitialized ones. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- hw/intc/exynos4210_gic.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index 2a55817..62acede 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -286,21 +286,21 @@ static void exynos4210_gic_init(Object *obj) DeviceState *dev = DEVICE(obj); Exynos4210GicState *s = EXYNOS4210_GIC(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - uint32_t i; const char cpu_prefix[] = "exynos4210-gic-alias_cpu"; const char dist_prefix[] = "exynos4210-gic-alias_dist"; char cpu_alias_name[sizeof(cpu_prefix) + 3]; char dist_alias_name[sizeof(cpu_prefix) + 3]; - SysBusDevice *busdev; + SysBusDevice *gicbusdev; + uint32_t i; s->gic = qdev_create(NULL, "arm_gic"); qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ); qdev_init_nofail(s->gic); - busdev = SYS_BUS_DEVICE(s->gic); + gicbusdev = SYS_BUS_DEVICE(s->gic); /* Pass through outbound IRQ lines from the GIC */ - sysbus_pass_irq(sbd, busdev); + sysbus_pass_irq(sbd, gicbusdev); /* Pass through inbound GPIO lines to the GIC */ qdev_init_gpio_in(dev, exynos4210_gic_set_irq, @@ -316,7 +316,7 @@ static void exynos4210_gic_init(Object *obj) sprintf(cpu_alias_name, "%s%x", cpu_prefix, i); memory_region_init_alias(&s->cpu_alias[i], obj, cpu_alias_name, - sysbus_mmio_get_region(busdev, 1), + sysbus_mmio_get_region(gicbusdev, 1), 0, EXYNOS4210_GIC_CPU_REGION_SIZE); memory_region_add_subregion(&s->cpu_container, @@ -326,7 +326,7 @@ static void exynos4210_gic_init(Object *obj) sprintf(dist_alias_name, "%s%x", dist_prefix, i); memory_region_init_alias(&s->dist_alias[i], obj, dist_alias_name, - sysbus_mmio_get_region(busdev, 0), + sysbus_mmio_get_region(gicbusdev, 0), 0, EXYNOS4210_GIC_DIST_REGION_SIZE); memory_region_add_subregion(&s->dist_container, -- cgit v1.1 From 5f7f22ffe1861d19a4693db2dd75e85206015560 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 Jun 2017 14:56:58 +0100 Subject: hw/intc/exynos4210_gic: Constify array of combiner interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The static array of interrupt combiner mappings is not modified so it can be made const for code safeness. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- hw/intc/exynos4210_gic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/intc') diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index 62acede..b6b00a4 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -116,7 +116,7 @@ enum ExtInt { * which is INTG16 in Internal Interrupt Combiner. */ -static uint32_t +static const uint32_t combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { /* int combiner groups 16-19 */ { }, { }, { }, { }, -- cgit v1.1 From 556969e938a97e98eec9df039944741ed74ce049 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 13 Jun 2017 14:57:00 +0100 Subject: kvm-all: Pass an error object to kvm_device_access In some circumstances, we don't want to abort if the kvm_device_access fails. This will be the case during ITS migration, in case the ITS table save/restore fails because the guest did not program the vITS correctly. So let's pass an error object to the function and return the ioctl value. New callers will be able to make a decision upon this returned value. Existing callers pass &error_abort which will cause the function to abort on failure. Signed-off-by: Eric Auger Reviewed-by: Juan Quintela Reviewed-by: Peter Xu Message-id: 1497023553-18411-2-git-send-email-eric.auger@redhat.com [PMM: wrapped long line] Signed-off-by: Peter Maydell --- hw/intc/arm_gic_kvm.c | 9 +++++---- hw/intc/arm_gicv3_its_kvm.c | 2 +- hw/intc/arm_gicv3_kvm.c | 14 +++++++------- 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index af5cd36..ae095d0 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -100,14 +100,14 @@ static void kvm_gicd_access(GICState *s, int offset, int cpu, uint32_t *val, bool write) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, - KVM_VGIC_ATTR(offset, cpu), val, write); + KVM_VGIC_ATTR(offset, cpu), val, write, &error_abort); } static void kvm_gicc_access(GICState *s, int offset, int cpu, uint32_t *val, bool write) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, - KVM_VGIC_ATTR(offset, cpu), val, write); + KVM_VGIC_ATTR(offset, cpu), val, write, &error_abort); } #define for_each_irq_reg(_ctr, _max_irq, _field_width) \ @@ -538,13 +538,14 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) { uint32_t numirqs = s->num_irq; kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, - &numirqs, true); + &numirqs, true, &error_abort); } /* Tell the kernel to complete VGIC initialization now */ if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT)) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, + &error_abort); } } else if (ret != -ENODEV && ret != -ENOTSUP) { error_setg_errno(errp, -ret, "error creating in-kernel VGIC"); diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index a0441d6..340c2b0 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -78,7 +78,7 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) /* explicit init of the ITS */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort); /* register the base address */ kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 4ee2baa..b70ee27 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -93,7 +93,7 @@ static inline void kvm_gicd_access(GICv3State *s, int offset, { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, KVM_VGIC_ATTR(offset, 0), - val, write); + val, write, &error_abort); } static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu, @@ -101,7 +101,7 @@ static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu, { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, KVM_VGIC_ATTR(offset, s->cpu[cpu].gicr_typer), - val, write); + val, write, &error_abort); } static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu, @@ -109,7 +109,7 @@ static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu, { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, KVM_VGIC_ATTR(reg, s->cpu[cpu].gicr_typer), - val, write); + val, write, &error_abort); } static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, @@ -119,7 +119,7 @@ static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, KVM_VGIC_ATTR(irq, s->cpu[cpu].gicr_typer) | (VGIC_LEVEL_INFO_LINE_LEVEL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT), - val, write); + val, write, &error_abort); } /* Loop through each distributor IRQ related register; since bits @@ -630,7 +630,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) /* Initialize to actual HW supported configuration */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity), - &c->icc_ctlr_el1[GICV3_NS], false); + &c->icc_ctlr_el1[GICV3_NS], false, &error_abort); c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; } @@ -717,11 +717,11 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) } kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, - 0, &s->num_irq, true); + 0, &s->num_irq, true, &error_abort); /* Tell the kernel to complete VGIC initialization now */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort); kvm_arm_register_device(&s->iomem_dist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd); -- cgit v1.1 From cddafd8f353d2d251b1a5c6c948a577a85838582 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 13 Jun 2017 14:57:00 +0100 Subject: hw/intc/arm_gicv3_its: Implement state save/restore We need to handle both registers and ITS tables. While register handling is standard, ITS table handling is more challenging since the kernel API is devised so that the tables are flushed into guest RAM and not in vmstate buffers. Flushing the ITS tables on device pre_save() is too late since the guest RAM is already saved at this point. Table flushing needs to happen when we are sure the vcpus are stopped and before the last dirty page saving. The right point is RUN_STATE_FINISH_MIGRATE but sometimes the VM gets stopped before migration launch so let's simply flush the tables each time the VM gets stopped. For regular ITS registers we just can use vmstate pre_save() and post_load() callbacks. Signed-off-by: Eric Auger Message-id: 1497023553-18411-3-git-send-email-eric.auger@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/arm_gicv3_its_common.c | 10 ++++ hw/intc/arm_gicv3_its_kvm.c | 105 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) (limited to 'hw/intc') diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c index 9d67c5c..696c11c 100644 --- a/hw/intc/arm_gicv3_its_common.c +++ b/hw/intc/arm_gicv3_its_common.c @@ -49,6 +49,15 @@ static const VMStateDescription vmstate_its = { .pre_save = gicv3_its_pre_save, .post_load = gicv3_its_post_load, .unmigratable = true, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ctlr, GICv3ITSState), + VMSTATE_UINT32(iidr, GICv3ITSState), + VMSTATE_UINT64(cbaser, GICv3ITSState), + VMSTATE_UINT64(cwriter, GICv3ITSState), + VMSTATE_UINT64(creadr, GICv3ITSState), + VMSTATE_UINT64_ARRAY(baser, GICv3ITSState, 8), + VMSTATE_END_OF_LIST() + }, }; static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset, @@ -118,6 +127,7 @@ static void gicv3_its_common_reset(DeviceState *dev) s->cbaser = 0; s->cwriter = 0; s->creadr = 0; + s->iidr = 0; memset(&s->baser, 0, sizeof(s->baser)); gicv3_its_post_load(s, 0); diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index 340c2b0..4cd8f5f 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -53,6 +53,33 @@ static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid) return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi); } +/** + * vm_change_state_handler - VM change state callback aiming at flushing + * ITS tables into guest RAM + * + * The tables get flushed to guest RAM whenever the VM gets stopped. + */ +static void vm_change_state_handler(void *opaque, int running, + RunState state) +{ + GICv3ITSState *s = (GICv3ITSState *)opaque; + Error *err = NULL; + int ret; + + if (running) { + return; + } + + ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_ITS_SAVE_TABLES, NULL, true, &err); + if (err) { + error_report_err(err); + } + if (ret < 0 && ret != -EFAULT) { + abort(); + } +} + static void kvm_arm_its_realize(DeviceState *dev, Error **errp) { GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); @@ -89,6 +116,8 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) kvm_msi_use_devid = true; kvm_gsi_direct_mapping = false; kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); + + qemu_add_vm_change_state_handler(vm_change_state_handler, s); } static void kvm_arm_its_init(Object *obj) @@ -102,6 +131,80 @@ static void kvm_arm_its_init(Object *obj) &error_abort); } +/** + * kvm_arm_its_pre_save - handles the saving of ITS registers. + * ITS tables are flushed into guest RAM separately and earlier, + * through the VM change state handler, since at the moment pre_save() + * is called, the guest RAM has already been saved. + */ +static void kvm_arm_its_pre_save(GICv3ITSState *s) +{ + int i; + + for (i = 0; i < 8; i++) { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_BASER + i * 8, &s->baser[i], false, + &error_abort); + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CTLR, &s->ctlr, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CBASER, &s->cbaser, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CREADR, &s->creadr, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CWRITER, &s->cwriter, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_IIDR, &s->iidr, false, &error_abort); +} + +/** + * kvm_arm_its_post_load - Restore both the ITS registers and tables + */ +static void kvm_arm_its_post_load(GICv3ITSState *s) +{ + int i; + + if (!s->iidr) { + return; + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_IIDR, &s->iidr, true, &error_abort); + + /* + * must be written before GITS_CREADR since GITS_CBASER write + * access resets GITS_CREADR. + */ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CBASER, &s->cbaser, true, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CREADR, &s->creadr, true, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CWRITER, &s->cwriter, true, &error_abort); + + + for (i = 0; i < 8; i++) { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_BASER + i * 8, &s->baser[i], true, + &error_abort); + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_ITS_RESTORE_TABLES, NULL, true, + &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CTLR, &s->ctlr, true, &error_abort); +} + static void kvm_arm_its_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -109,6 +212,8 @@ static void kvm_arm_its_class_init(ObjectClass *klass, void *data) dc->realize = kvm_arm_its_realize; icc->send_msi = kvm_its_send_msi; + icc->pre_save = kvm_arm_its_pre_save; + icc->post_load = kvm_arm_its_post_load; } static const TypeInfo kvm_arm_its_info = { -- cgit v1.1 From d5aa0c229ab5d46c1a4ff497553671cd46486749 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 13 Jun 2017 14:57:00 +0100 Subject: hw/intc/arm_gicv3_kvm: Implement pending table save This patch adds the flush of the LPI pending bits into the redistributor pending tables. This happens on VM stop. There is no explicit restore as the tables are implicitly sync'ed on ITS table restore and on LPI enable at redistributor level. Signed-off-by: Eric Auger Message-id: 1497023553-18411-4-git-send-email-eric.auger@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/arm_gicv3_kvm.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'hw/intc') diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index b70ee27..6051c77 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -25,6 +25,7 @@ #include "hw/sysbus.h" #include "qemu/error-report.h" #include "sysemu/kvm.h" +#include "sysemu/sysemu.h" #include "kvm_arm.h" #include "gicv3_internal.h" #include "vgic_common.h" @@ -680,6 +681,35 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { REGINFO_SENTINEL }; +/** + * vm_change_state_handler - VM change state callback aiming at flushing + * RDIST pending tables into guest RAM + * + * The tables get flushed to guest RAM whenever the VM gets stopped. + */ +static void vm_change_state_handler(void *opaque, int running, + RunState state) +{ + GICv3State *s = (GICv3State *)opaque; + Error *err = NULL; + int ret; + + if (running) { + return; + } + + ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES, + NULL, true, &err); + if (err) { + error_report_err(err); + } + if (ret < 0 && ret != -EFAULT) { + abort(); + } +} + + static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) { GICv3State *s = KVM_ARM_GICV3(dev); @@ -751,6 +781,10 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) return; } } + if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES)) { + qemu_add_vm_change_state_handler(vm_change_state_handler, s); + } } static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) -- cgit v1.1 From 252a7a6a968c279a4636a86b0559ba3a930a90b5 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 13 Jun 2017 14:57:01 +0100 Subject: hw/intc/arm_gicv3_its: Allow save/restore We change the restoration priority of both the GICv3 and ITS. The GICv3 must be restored before the ITS and the ITS needs to be restored before PCIe devices since it translates their MSI transactions. Signed-off-by: Eric Auger Reviewed-by: Juan Quintela Message-id: 1497023553-18411-5-git-send-email-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/intc/arm_gicv3_common.c | 1 + hw/intc/arm_gicv3_its_common.c | 2 +- hw/intc/arm_gicv3_its_kvm.c | 24 ++++++++++++------------ 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index c6493d6..4228b7c 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -145,6 +145,7 @@ static const VMStateDescription vmstate_gicv3 = { .minimum_version_id = 1, .pre_save = gicv3_pre_save, .post_load = gicv3_post_load, + .priority = MIG_PRI_GICV3, .fields = (VMStateField[]) { VMSTATE_UINT32(gicd_ctlr, GICv3State), VMSTATE_UINT32_ARRAY(gicd_statusr, GICv3State, 2), diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c index 696c11c..68b20fc 100644 --- a/hw/intc/arm_gicv3_its_common.c +++ b/hw/intc/arm_gicv3_its_common.c @@ -48,7 +48,7 @@ static const VMStateDescription vmstate_its = { .name = "arm_gicv3_its", .pre_save = gicv3_its_pre_save, .post_load = gicv3_its_post_load, - .unmigratable = true, + .priority = MIG_PRI_GICV3_ITS, .fields = (VMStateField[]) { VMSTATE_UINT32(ctlr, GICv3ITSState), VMSTATE_UINT32(iidr, GICv3ITSState), diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index 4cd8f5f..1f8991b 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -85,18 +85,6 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); Error *local_err = NULL; - /* - * Block migration of a KVM GICv3 ITS device: the API for saving and - * restoring the state in the kernel is not yet available - */ - error_setg(&s->migration_blocker, "vITS migration is not implemented"); - migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); - error_free(s->migration_blocker); - return; - } - s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false); if (s->dev_fd < 0) { error_setg_errno(errp, -s->dev_fd, "error creating in-kernel ITS"); @@ -113,6 +101,18 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) gicv3_its_init_mmio(s, NULL); + if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CTLR)) { + error_setg(&s->migration_blocker, "This operating system kernel " + "does not support vITS migration"); + migrate_add_blocker(s->migration_blocker, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_free(s->migration_blocker); + return; + } + } + kvm_msi_use_devid = true; kvm_gsi_direct_mapping = false; kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); -- cgit v1.1