[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v3 25/35] spapr/xive: add KVM support
From: |
Cédric Le Goater |
Subject: |
[Qemu-devel] [PATCH v3 25/35] spapr/xive: add KVM support |
Date: |
Thu, 19 Apr 2018 14:43:21 +0200 |
This introduces a set of XIVE models specific to KVM. They handle the
synchronization of the state with KVM, for the monitor usage and for
the migration.
The TIMA and ESB MMIO regions are initialized differently under KVM.
'ram device' memory mappings, similarly to VFIO, are exposed to the
guest and the associated VMAs on the host are populated dynamically
with the appropriate pages using a fault handler.
For migration, the main sPAPRXive interrupt controller model saves and
restores the IVE table needed for routing. Each VCPU presenter model
(XiveNVT) does the same for the interrupt management registers and for
the XIVE EQs. The XIVE EQ pages, which reside in the guest RAM, are
marked dirty when the EQs are captured. These get/set operations rely
on their KVM counterpart in the host kernel which acts as a proxy for
OPAL, the host firmware.
The XiveSource model can save and restore the PQ bits directly in the
ESB MMIO region and does not need KVM support.
The XIVE migration sequence is currently ordered with priorities but
this might not be enough to capture correctly all HW state. Extra
quiescence points are possibly needed. Work in progress.
Signed-off-by: Cédric Le Goater <address@hidden>
---
default-configs/ppc64-softmmu.mak | 1 +
hw/intc/Makefile.objs | 1 +
hw/intc/spapr_xive.c | 1 +
hw/intc/spapr_xive_kvm.c | 565 ++++++++++++++++++++++++++++++++++++++
hw/intc/xive.c | 1 +
include/hw/ppc/spapr_xive.h | 23 ++
include/hw/ppc/xive.h | 3 +
include/migration/vmstate.h | 2 +
8 files changed, 597 insertions(+)
create mode 100644 hw/intc/spapr_xive_kvm.c
diff --git a/default-configs/ppc64-softmmu.mak
b/default-configs/ppc64-softmmu.mak
index f8d34722931d..ac7e3af2473c 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -18,4 +18,5 @@ CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM))
CONFIG_XIVE=$(CONFIG_PSERIES)
CONFIG_XIVE_SPAPR=$(CONFIG_PSERIES)
+CONFIG_XIVE_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM))
CONFIG_MEM_HOTPLUG=y
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index eacd26836ebf..dd4d69db2bdd 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -39,6 +39,7 @@ obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
obj-$(CONFIG_XIVE) += xive.o
obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o spapr_xive_hcall.o
+obj-$(CONFIG_XIVE_KVM) += spapr_xive_kvm.o
obj-$(CONFIG_POWERNV) += xics_pnv.o
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
obj-$(CONFIG_S390_FLIC) += s390_flic.o
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index bd604089ad49..b8496033a8b9 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -208,6 +208,7 @@ static const VMStateDescription vmstate_spapr_xive = {
.minimum_version_id = 1,
.pre_save = vmstate_spapr_xive_pre_save,
.post_load = vmstate_spapr_xive_post_load,
+ .priority = MIG_PRI_XIVE_IVE,
.fields = (VMStateField[]) {
VMSTATE_UINT32_EQUAL(nr_irqs, sPAPRXive, NULL),
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(ivt, sPAPRXive, nr_irqs,
diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c
new file mode 100644
index 000000000000..ec5613fc2804
--- /dev/null
+++ b/hw/intc/spapr_xive_kvm.c
@@ -0,0 +1,565 @@
+/*
+ * QEMU PowerPC sPAPR XIVE interrupt controller model
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "target/ppc/cpu.h"
+#include "sysemu/cpus.h"
+#include "sysemu/kvm.h"
+#include "monitor/monitor.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_xive.h"
+#include "hw/ppc/xive.h"
+#include "hw/ppc/xive_regs.h"
+#include "kvm_ppc.h"
+
+#include <sys/ioctl.h>
+
+/* TODO: kernel_xive_fd is used as a global switch for XIVE */
+static int kernel_xive_fd = -1;
+
+typedef struct KVMEnabledCPU {
+ unsigned long vcpu_id;
+ QLIST_ENTRY(KVMEnabledCPU) node;
+} KVMEnabledCPU;
+
+static QLIST_HEAD(, KVMEnabledCPU)
+ kvm_enabled_cpus = QLIST_HEAD_INITIALIZER(&kvm_enabled_cpus);
+
+static bool xive_nvt_kvm_cpu_is_enabled(CPUState *cs)
+{
+ KVMEnabledCPU *enabled_cpu;
+ unsigned long vcpu_id = kvm_arch_vcpu_id(cs);
+
+ QLIST_FOREACH(enabled_cpu, &kvm_enabled_cpus, node) {
+ if (enabled_cpu->vcpu_id == vcpu_id) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void xive_nvt_kvm_cpu_enable(CPUState *cs)
+{
+ KVMEnabledCPU *enabled_cpu;
+ unsigned long vcpu_id = kvm_arch_vcpu_id(cs);
+
+ enabled_cpu = g_malloc(sizeof(*enabled_cpu));
+ enabled_cpu->vcpu_id = vcpu_id;
+ QLIST_INSERT_HEAD(&kvm_enabled_cpus, enabled_cpu, node);
+}
+
+static inline bool xive_queue_is_valid(int priority)
+{
+ switch (priority) {
+ case 0 ... 6:
+ return true;
+ case 7: /* OPAL escalation queue */
+ default:
+ return false;
+ }
+}
+
+static void xive_nvt_kvm_get_state(XiveNVT *nvt)
+{
+ uint64_t state[2] = { 0 };
+ int ret;
+ int i;
+
+ ret = kvm_get_one_reg(nvt->cs, KVM_REG_PPC_VP_STATE, state);
+ if (ret != 0) {
+ error_report("Unable to retrieve KVM XIVE interrupt controller state"
+ " for CPU %ld: %s", kvm_arch_vcpu_id(nvt->cs),
strerror(errno));
+ return;
+ }
+
+ /* First quad should be a backup of word0 and word1 of the OS
+ * ring. Second quad is the OPAL internal state which holds word4
+ * of the VP structure. We are only interested by the IPB in there
+ * but we should consider it as opaque.
+ *
+ * As we won't use the registers of the HV ring on sPAPR, let's
+ * hijack them to store the 'OPAL' state
+ */
+ *((uint64_t *) nvt->ring_os) = state[0];
+ *((uint64_t *) &nvt->regs[TM_QW2_HV_POOL]) = state[1];
+
+ /* Now dump all the queue internals */
+ for (i = 0; i < ARRAY_SIZE(nvt->eqt); i++) {
+ XiveEQ eq = { 0 };
+
+ if (!xive_queue_is_valid(i)) {
+ continue;
+ }
+
+ ret = kvm_get_one_reg(nvt->cs, KVM_REG_PPC_VP_EQ0 + i, &eq);
+ if (ret != 0) {
+ error_report("Unable to retrieve KVM XIVE interrupt controller"
+ " state for CPU %ld priority %d: %s",
+ kvm_arch_vcpu_id(nvt->cs), i, strerror(errno));
+ return;
+ }
+
+ if (eq.w0 & EQ_W0_VALID) {
+ memcpy(&nvt->eqt[i], &eq, sizeof(nvt->eqt[i]));
+ }
+ }
+}
+
+static void xive_nvt_kvm_do_synchronize_state(CPUState *cpu,
+ run_on_cpu_data arg)
+{
+ xive_nvt_kvm_get_state(arg.host_ptr);
+}
+
+static void xive_nvt_kvm_synchronize_state(XiveNVT *nvt)
+{
+ if (nvt->cs) {
+ run_on_cpu(nvt->cs, xive_nvt_kvm_do_synchronize_state,
+ RUN_ON_CPU_HOST_PTR(nvt));
+ }
+}
+
+static int xive_nvt_kvm_set_state(XiveNVT *nvt, int version_id)
+{
+ uint64_t state[2];
+ int ret;
+ int i;
+
+ /* NVT for this CPU thread is not in use, exiting */
+ if (!nvt->cs) {
+ return 0;
+ }
+
+ state[0] = *((uint64_t *) nvt->ring_os);
+ state[1] = *((uint64_t *) &nvt->regs[TM_QW2_HV_POOL]);
+
+ ret = kvm_set_one_reg(nvt->cs, KVM_REG_PPC_VP_STATE, state);
+ if (ret != 0) {
+ error_report("Unable to restore KVM XIVE interrupt controller state"
+ " for CPU %ld: %s", kvm_arch_vcpu_id(nvt->cs),
+ strerror(errno));
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(nvt->eqt); i++) {
+ XiveEQ *eq = &nvt->eqt[i];
+
+ if (!xive_queue_is_valid(i)) {
+ continue;
+ }
+
+ if (!(eq->w0 & EQ_W0_VALID)) {
+ continue;
+ }
+
+ ret = kvm_set_one_reg(nvt->cs, KVM_REG_PPC_VP_EQ0 + i, eq);
+ if (ret != 0) {
+ error_report("Unable to restore KVM XIVE interrupt controller"
+ " state for CPU %ld priority %d: %s",
+ kvm_arch_vcpu_id(nvt->cs), i, strerror(errno));
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void xive_nvt_kvm_reset(XiveNVT *nvt)
+{
+ /* XIVE is not enabled at first machine reset, only after CAS. */
+ if (kernel_xive_fd == -1) {
+ return;
+ }
+
+ xive_nvt_kvm_set_state(nvt, 1);
+}
+
+static void xive_nvt_kvm_realize(XiveNVT *nvt, Error **errp)
+{
+ CPUState *cs = nvt->cs;
+ unsigned long vcpu_id = kvm_arch_vcpu_id(cs);
+ int ret;
+
+ /* Check if CPU was hot unplugged and replugged. */
+ if (xive_nvt_kvm_cpu_is_enabled(cs)) {
+ return;
+ }
+
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_IRQ_XIVE, 0, kernel_xive_fd,
+ vcpu_id, 0);
+ if (ret < 0) {
+ error_setg(errp, "Unable to connect CPU%ld to KVM XIVE device: %s",
+ vcpu_id, strerror(errno));
+ return;
+ }
+
+ xive_nvt_kvm_cpu_enable(cs);
+}
+
+static void xive_nvt_kvm_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ XiveNVTClass *xnc = XIVE_NVT_CLASS(klass);
+
+ dc->desc = "XIVE KVM Interrupt Presenter";
+
+ xnc->realize = xive_nvt_kvm_realize;
+ xnc->synchronize_state = xive_nvt_kvm_synchronize_state;
+ xnc->reset = xive_nvt_kvm_reset;
+ xnc->pre_save = xive_nvt_kvm_get_state;
+ xnc->post_load = xive_nvt_kvm_set_state;
+}
+
+static const TypeInfo xive_nvt_kvm_info = {
+ .name = TYPE_XIVE_NVT_KVM,
+ .parent = TYPE_XIVE_NVT,
+ .instance_size = sizeof(XiveNVT),
+ .class_init = xive_nvt_kvm_class_init,
+ .class_size = sizeof(XiveNVTClass),
+};
+
+static void xive_source_kvm_set_irq(void *opaque, int srcno, int val)
+{
+ XiveSource *xsrc = opaque;
+ struct kvm_irq_level args;
+ int rc;
+
+ args.irq = srcno + xsrc->offset;
+ if (!xive_source_irq_is_lsi(xsrc, srcno)) {
+ if (!val) {
+ return;
+ }
+ args.level = KVM_INTERRUPT_SET;
+ } else {
+ args.level = val ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET;
+ }
+ rc = kvm_vm_ioctl(kvm_state, KVM_IRQ_LINE, &args);
+ if (rc < 0) {
+ error_report("kvm_irq_line() failed : %s", strerror(errno));
+ }
+}
+
+static void xive_source_kvm_reset(XiveSource *xsrc)
+{
+ sPAPRXive *xive = SPAPR_XIVE_KVM(xsrc->xive);
+ int i;
+
+ /* XIVE is not enabled at first machine reset, only after CAS. */
+ if (xive->fd == -1) {
+ return;
+ }
+
+ /*
+ * At reset, interrupt sources are simply created and MASKED, we
+ * only need to inform KVM about their type: LSI or MSI.
+ */
+ for (i = 0; i < xsrc->nr_irqs; i++) {
+ Error *err = NULL;
+ uint64_t state = 0;
+
+ if (xive_source_irq_is_lsi(xsrc, i)) {
+ state |= KVM_XICS_LEVEL_SENSITIVE;
+ }
+
+ kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCES,
+ i + xsrc->offset, &state, true, &err);
+ if (err) {
+ error_report_err(err);
+ return;
+ }
+ }
+}
+
+/*
+ * This is used to perform the magic loads from an ESB described in
+ * xive.h.
+ */
+static uint8_t xive_esb_read(XiveSource *xsrc, int srcno, uint32_t offset)
+{
+ unsigned long addr = (unsigned long) xsrc->esb_mmap +
+ (1ull << xsrc->esb_shift) * srcno;
+
+ /* In a two pages ESB MMIO setting, the odd page is for management */
+ if (xive_source_esb_2page(xsrc)) {
+ addr += (1 << (xsrc->esb_shift - 1));
+ }
+ addr += offset;
+
+ return *((uint8_t *) addr);
+}
+
+static void xive_source_kvm_get_state(XiveSource *xsrc)
+{
+ int i;
+
+ for (i = 0; i < xsrc->nr_irqs; i++) {
+ /* Perform a load without side effect to retrieve the PQ bits */
+ uint8_t pq = xive_esb_read(xsrc, i, XIVE_ESB_GET);
+
+ /* and save PQ locally */
+ xive_source_pq_set(xsrc, i, pq);
+ }
+}
+
+static int xive_source_kvm_set_state(XiveSource *xsrc, int version_id)
+{
+ int i;
+ int unused = 0;
+
+ for (i = 0; i < xsrc->nr_irqs; i++) {
+ uint8_t pq = xive_source_pq_get(xsrc, i);
+
+ /* TODO: prevent the compiler from optimizing away the load */
+ unused |= xive_esb_read(xsrc, i, XIVE_ESB_SET_PQ_00 + (pq << 8));
+ }
+
+ return unused;
+}
+
+static void xive_source_kvm_synchronize_state(XiveSource *xsrc)
+{
+ xive_source_kvm_get_state(xsrc);
+}
+
+static void xive_source_kvm_realize(DeviceState *dev, Error **errp)
+{
+ XiveSource *xsrc = XIVE_SOURCE_KVM(dev);
+
+ xive_source_common_realize(xsrc, xive_source_kvm_set_irq, errp);
+
+ /* The memory regions for the ESB MMIOs will be initialized after
+ * KVM is, but we need to declare them on SysBus for the first
+ * munmap to work in spapr_reset_interrupt() */
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &xsrc->esb_mmio);
+}
+
+static void xive_source_kvm_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ XiveSourceClass *xsc = XIVE_SOURCE_CLASS(klass);
+
+ dc->realize = xive_source_kvm_realize;
+ dc->desc = "XIVE KVM interrupt source";
+
+ xsc->synchronize_state = xive_source_kvm_synchronize_state;
+ xsc->reset = xive_source_kvm_reset;
+ xsc->pre_save = xive_source_kvm_get_state;
+ xsc->post_load = xive_source_kvm_set_state;
+}
+
+static const TypeInfo xive_source_kvm_info = {
+ .name = TYPE_XIVE_SOURCE_KVM,
+ .parent = TYPE_XIVE_SOURCE,
+ .instance_size = sizeof(XiveSource),
+ .class_init = xive_source_kvm_class_init,
+ .class_size = sizeof(XiveSourceClass),
+};
+
+static void spapr_xive_kvm_get_state(sPAPRXive *xive)
+{
+ XiveSource *xsrc = &xive->source;
+ int i;
+
+ for (i = 0; i < xsrc->nr_irqs; i++) {
+ XiveIVE *ive = &xive->ivt[i];
+
+ if (!(ive->w & IVE_VALID)) {
+ continue;
+ }
+
+ kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_IVE,
+ i + xsrc->offset, ive, false, &error_abort);
+ }
+}
+
+static int spapr_xive_kvm_set_state(sPAPRXive *xive, int version_id)
+{
+ XiveSource *xsrc = &xive->source;
+ int i;
+
+ /* First initialize the KVM device sources, as XIVE is not enabled
+ * at machine reset */
+ xive_source_kvm_reset(xsrc);
+
+ for (i = 0; i < xsrc->nr_irqs; i++) {
+ XiveIVE *ive = &xive->ivt[i];
+ Error *err = NULL;
+
+ if (!(ive->w & IVE_VALID) || ive->w & IVE_MASKED) {
+ continue;
+ }
+
+ kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_IVE,
+ i + xsrc->offset, ive, true, &err);
+ if (err) {
+ error_report_err(err);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void spapr_xive_kvm_synchronize_state(sPAPRXive *xive)
+{
+ spapr_xive_kvm_get_state(xive);
+}
+
+static void spapr_xive_kvm_init(Object *obj)
+{
+ sPAPRXive *xive = SPAPR_XIVE_KVM(obj);
+
+ /* We need a KVM flavored source */
+ object_initialize(&xive->source, sizeof(xive->source),
+ TYPE_XIVE_SOURCE_KVM);
+ object_property_add_child(obj, "source", OBJECT(&xive->source), NULL);
+}
+
+static void spapr_xive_kvm_realize(DeviceState *dev, Error **errp)
+{
+ sPAPRXive *xive = SPAPR_XIVE_KVM(dev);
+ Error *local_err = NULL;
+
+ spapr_xive_common_realize(xive, XIVE_ESB_64K_2PAGE, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ xive->fd = -1;
+
+ /* The memory regions for the TIMA MMIOs will be initialized after
+ * KVM is, but we need to declare them on SysBus for the first
+ * munmap to work in spapr_reset_interrupt() */
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &xive->tm_mmio_user);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &xive->tm_mmio_os);
+}
+
+static void spapr_xive_kvm_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ sPAPRXiveClass *sxc = SPAPR_XIVE_CLASS(klass);
+
+ dc->realize = spapr_xive_kvm_realize;
+ /* spapr_xive_reset() is used for reset. */
+ dc->desc = "sPAPR XIVE KVM interrupt controller";
+
+ sxc->synchronize_state = spapr_xive_kvm_synchronize_state;
+ sxc->pre_save = spapr_xive_kvm_get_state;
+ sxc->post_load = spapr_xive_kvm_set_state;
+}
+
+static const TypeInfo spapr_xive_kvm_info = {
+ .name = TYPE_SPAPR_XIVE_KVM,
+ .parent = TYPE_SPAPR_XIVE,
+ .instance_init = spapr_xive_kvm_init,
+ .instance_size = sizeof(sPAPRXive),
+ .class_init = spapr_xive_kvm_class_init,
+ .class_size = sizeof(sPAPRXiveClass),
+};
+
+static void xive_kvm_register_types(void)
+{
+ type_register_static(&spapr_xive_kvm_info);
+ type_register_static(&xive_source_kvm_info);
+ type_register_static(&xive_nvt_kvm_info);
+}
+
+type_init(xive_kvm_register_types)
+
+static void *spapr_xive_kvm_mmap(sPAPRXive *xive, int ctrl, size_t len,
+ Error **errp)
+{
+ Error *local_err = NULL;
+ void *addr;
+ int fd;
+
+ kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_CTRL, ctrl, &fd, false,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return NULL;
+ }
+
+ addr = mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
+ close(fd);
+ if (addr == MAP_FAILED) {
+ error_setg_errno(errp, errno, "Unable to set XIVE mmaping");
+ return NULL;
+ }
+
+ return addr;
+}
+
+void xive_kvm_init(sPAPRXive *xive, Error **errp)
+{
+ XiveSource *xsrc = &xive->source;
+ Error *local_err = NULL;
+ size_t esb_len, tima_len;
+
+ if (!kvm_enabled() || !kvmppc_has_cap_xive()) {
+ error_setg(errp,
+ "IRQ_XIVE capability must be present for KVM XIVE device");
+ return;
+ }
+
+ xive->fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_XIVE, false);
+ if (xive->fd < 0) {
+ error_setg_errno(errp, -xive->fd, "error creating KVM XIVE device");
+ return;
+ }
+
+ kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_CTRL, KVM_DEV_XIVE_VC_BASE,
+ &xsrc->esb_base, true, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* ESB MMIO region */
+ esb_len = (1ull << xsrc->esb_shift) * xsrc->nr_irqs;
+ xsrc->esb_mmap = spapr_xive_kvm_mmap(xive, KVM_DEV_XIVE_GET_ESB_FD,
+ esb_len, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ memory_region_init_ram_device_ptr(&xsrc->esb_mmio, OBJECT(xsrc),
+ "xive.esb", esb_len, xsrc->esb_mmap);
+
+ /* TIMA USER MMIO region */
+ tima_len = 1ull << TM_SHIFT;
+ xive->tm_mmap_user = spapr_xive_kvm_mmap(xive, KVM_DEV_XIVE_GET_TIMA_FD,
+ tima_len, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ memory_region_init_ram_device_ptr(&xive->tm_mmio_user, OBJECT(xive),
+ "xive.tima.user", tima_len,
+ xive->tm_mmap_user);
+
+ /* TIMA OS MMIO region */
+ xive->tm_mmap_os = spapr_xive_kvm_mmap(xive, KVM_DEV_XIVE_GET_TIMA_FD,
+ tima_len, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ memory_region_init_ram_device_ptr(&xive->tm_mmio_os, OBJECT(xive),
+ "xive.tima.os", tima_len,
+ xive->tm_mmap_os);
+
+ kernel_xive_fd = xive->fd;
+ kvm_kernel_irqchip = true;
+ kvm_msi_via_irqfd_allowed = true;
+ kvm_gsi_direct_mapping = true;
+}
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 520b532dbf09..d96732cfe6be 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -487,6 +487,7 @@ static const VMStateDescription vmstate_xive_nvt = {
.minimum_version_id = 1,
.pre_save = vmstate_xive_nvt_pre_save,
.post_load = vmstate_xive_nvt_post_load,
+ .priority = MIG_PRI_XIVE_NVT,
.fields = (VMStateField[]) {
VMSTATE_BUFFER(regs, XiveNVT),
VMSTATE_STRUCT_ARRAY(eqt, XiveNVT, (XIVE_PRIORITY_MAX + 1), 1,
diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h
index f3ac084a71be..75b790cc9730 100644
--- a/include/hw/ppc/spapr_xive.h
+++ b/include/hw/ppc/spapr_xive.h
@@ -30,6 +30,11 @@ typedef struct sPAPRXive {
hwaddr tm_base;
MemoryRegion tm_mmio_user;
MemoryRegion tm_mmio_os;
+
+ /* KVM support */
+ int fd;
+ void *tm_mmap_user;
+ void *tm_mmap_os;
} sPAPRXive;
#define SPAPR_XIVE_CLASS(klass) \
@@ -66,4 +71,22 @@ void spapr_xive_hcall_init(sPAPRMachineState *spapr);
void spapr_dt_xive(sPAPRMachineState *spapr, int nr_servers, void *fdt,
uint32_t phandle);
+/*
+ * XIVE KVM device
+ */
+
+#define TYPE_SPAPR_XIVE_KVM "spapr-xive-kvm"
+#define SPAPR_XIVE_KVM(obj) \
+ OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE_KVM)
+
+#define TYPE_XIVE_SOURCE_KVM "xive-source-kvm"
+#define XIVE_SOURCE_KVM(obj) \
+ OBJECT_CHECK(XiveSource, (obj), TYPE_XIVE_SOURCE_KVM)
+
+#define TYPE_XIVE_NVT_KVM "xive-nvt-kvm"
+#define XIVE_NVT_KVM(obj) \
+ OBJECT_CHECK(XiveNVT, (obj), TYPE_XIVE_NVT_KVM)
+
+void xive_kvm_init(sPAPRXive *xive, Error **errp);
+
#endif /* PPC_SPAPR_XIVE_H */
diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index b040cf580fc9..e99cd874ef3c 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -58,6 +58,9 @@ typedef struct XiveSource {
MemoryRegion esb_mmio;
XiveFabric *xive;
+
+ /* KVM support */
+ void *esb_mmap;
} XiveSource;
#define XIVE_SOURCE_CLASS(klass) \
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index df463fd33d69..482bdf365297 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -151,6 +151,8 @@ typedef enum {
MIG_PRI_PCI_BUS, /* Must happen before IOMMU */
MIG_PRI_GICV3_ITS, /* Must happen before PCI devices */
MIG_PRI_GICV3, /* Must happen before the ITS */
+ MIG_PRI_XIVE_IVE, /* Must happen before XIVE source */
+ MIG_PRI_XIVE_NVT, /* Must happen before XIVE IVE */
MIG_PRI_MAX,
} MigrationPriority;
--
2.13.6
- [Qemu-devel] [PATCH v3 15/35] sysbus: add a sysbus_mmio_unmap() helper, (continued)
- [Qemu-devel] [PATCH v3 15/35] sysbus: add a sysbus_mmio_unmap() helper, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 16/35] spapr: introduce a helper to map the XIVE memory regions, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 17/35] spapr: add XIVE support to spapr_qirq(), Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 18/35] spapr: introduce a spapr_icp_create() helper, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 19/35] spapr: toggle the ICP depending on the selected interrupt mode, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 20/35] spapr: add support to dump XIVE information, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 21/35] spapr: advertise XIVE exploitation mode in CAS, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 22/35] spapr: add classes for the XIVE models, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 23/35] target/ppc/kvm: add Linux KVM definitions for XIVE, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 24/35] spapr/xive: add common realize routine for KVM, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 25/35] spapr/xive: add KVM support,
Cédric Le Goater <=
- [Qemu-devel] [PATCH v3 26/35] spapr/xive: add a XIVE KVM device to the machine, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 27/35] migration: discard non-migratable RAMBlocks, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 28/35] intc: introduce a CPUIntc interface, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 29/35] spapr/xive, xics: use the CPU_INTC handlers to reset KVM, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 30/35] spapr/xive, xics: reset KVM at machine reset, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 31/35] spapr/xive: raise migration priority of the machine, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 32/35] ppc/pnv: introduce a pnv_icp_create() helper, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 33/35] ppc: externalize ppc_get_vcpu_by_pir(), Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 34/35] ppc/pnv: add XIVE support, Cédric Le Goater, 2018/04/19
- [Qemu-devel] [PATCH v3 35/35] ppc/pnv: add a PSI bridge model for POWER9 processor, Cédric Le Goater, 2018/04/19