The vCPUs are disconnected from the KVM device using a 'disable=1' as last argument of the KVM_ENABLE_CAP ioctl. This is a bit hacky, we should probably introduce a KVM_DISABLE_CAP ioctl.
Signed-off-by: Cédric Le Goater <c...@kaod.org> --- hw/intc/spapr_xive_kvm.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++-- hw/intc/xics.c | 4 ++++ hw/intc/xics_kvm.c | 48 ++++++++++++++++++++++++++++++++++++++++-- hw/intc/xive.c | 5 +++++ hw/ppc/spapr_cpu_core.c | 8 +++++++ 5 files changed, 116 insertions(+), 4 deletions(-) diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index ec5613fc2804..e3851991653e 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -15,6 +15,7 @@ #include "sysemu/cpus.h" #include "sysemu/kvm.h" #include "monitor/monitor.h" +#include "hw/intc/intc.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_xive.h" #include "hw/ppc/xive.h" @@ -47,6 +48,25 @@ static bool xive_nvt_kvm_cpu_is_enabled(CPUState *cs) return false; } +static void xive_nvt_kvm_cpu_disable(CPUState *cs, Error **errp) +{ + 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) { + break; + } + } + + if (enabled_cpu->vcpu_id == vcpu_id) { + QLIST_REMOVE(enabled_cpu, node); + g_free(enabled_cpu); + } else { + error_setg(errp, "Can not find enabled CPU%ld", vcpu_id); + } +} + static void xive_nvt_kvm_cpu_enable(CPUState *cs) { KVMEnabledCPU *enabled_cpu; @@ -183,8 +203,36 @@ static void xive_nvt_kvm_reset(XiveNVT *nvt) xive_nvt_kvm_set_state(nvt, 1); } -static void xive_nvt_kvm_realize(XiveNVT *nvt, Error **errp) +static void xive_nvt_kvm_disconnect(CPUIntc *intc, Error **errp) { + XiveNVT *nvt = XIVE_NVT_KVM(intc); + CPUState *cs = nvt->cs; + unsigned long vcpu_id = kvm_arch_vcpu_id(cs); + int ret; + + if (kernel_xive_fd == -1) { + return; + } + + /* Disable IRQ capability with a 'disable=1' as last argument. + * + * This is a bit hacky, we should introduce a KVM_DISABLE_CAP + * iotcl + */ + ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_IRQ_XIVE, 0, kernel_xive_fd, + vcpu_id, 1); + if (ret < 0) { + error_setg(errp, "Unable to disconnect CPU%ld from KVM XIVE device: %s", + vcpu_id, strerror(errno)); + return; + } + + xive_nvt_kvm_cpu_disable(cs, errp); +} + +static void xive_nvt_kvm_connect(CPUIntc *intc, Error **errp) +{ + XiveNVT *nvt = XIVE_NVT_KVM(intc); CPUState *cs = nvt->cs; unsigned long vcpu_id = kvm_arch_vcpu_id(cs); int ret; @@ -209,14 +257,17 @@ static void xive_nvt_kvm_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); XiveNVTClass *xnc = XIVE_NVT_CLASS(klass); + CPUIntcClass *cic = CPU_INTC_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; + + cic->connect = xive_nvt_kvm_connect; + cic->disconnect = xive_nvt_kvm_disconnect; } static const TypeInfo xive_nvt_kvm_info = { diff --git a/hw/intc/xics.c b/hw/intc/xics.c index e73e623e3b53..48fed2731fd2 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -381,6 +381,10 @@ static const TypeInfo icp_info = { .instance_size = sizeof(ICPState), .class_init = icp_class_init, .class_size = sizeof(ICPStateClass), + .interfaces = (InterfaceInfo[]) { + { TYPE_CPU_INTC }, + { } + } }; Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp) diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index e727397c4a4d..62ea4ea150f2 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -32,6 +32,7 @@ #include "hw/hw.h" #include "trace.h" #include "sysemu/kvm.h" +#include "hw/intc/intc.h" #include "hw/ppc/spapr.h" #include "hw/ppc/xics.h" #include "kvm_ppc.h" @@ -137,8 +138,48 @@ static void icp_kvm_reset(ICPState *icp) icp_set_kvm_state(icp, 1); } -static void icp_kvm_realize(ICPState *icp, Error **errp) +static void icp_kvm_disconnect(CPUIntc *intc, Error **errp) { + ICPState *icp = ICP(intc); + CPUState *cs = icp->cs; + KVMEnabledICP *enabled_icp; + unsigned long vcpu_id = kvm_arch_vcpu_id(cs); + int ret; + + if (kernel_xics_fd == -1) { + return; + } + + /* Disable IRQ capability with a 'disable=1' as last argument. + * + * This is a bit hacky, we should introduce a KVM_DISABLE_CAP + * iotcl + */ + ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd, + vcpu_id, 1); + if (ret < 0) { + error_setg(errp, "Unable to disconnect CPU%ld to kernel XICS: %s", + vcpu_id, strerror(errno)); + return; + } + + QLIST_FOREACH(enabled_icp, &kvm_enabled_icps, node) { + if (enabled_icp->vcpu_id == vcpu_id) { + break; + } + } + + if (enabled_icp->vcpu_id == vcpu_id) { + QLIST_REMOVE(enabled_icp, node); + g_free(enabled_icp); + } else { + error_setg(errp, "Can not find enabled CPU%ld", vcpu_id); + } + } + +static void icp_kvm_connect(CPUIntc *intc, Error **errp) +{ + ICPState *icp = ICP(intc); CPUState *cs = icp->cs; KVMEnabledICP *enabled_icp; unsigned long vcpu_id = kvm_arch_vcpu_id(cs); @@ -173,12 +214,15 @@ static void icp_kvm_realize(ICPState *icp, Error **errp) static void icp_kvm_class_init(ObjectClass *klass, void *data) { ICPStateClass *icpc = ICP_CLASS(klass); + CPUIntcClass *cic = CPU_INTC_CLASS(klass); icpc->pre_save = icp_get_kvm_state; icpc->post_load = icp_set_kvm_state; - icpc->realize = icp_kvm_realize; icpc->reset = icp_kvm_reset; icpc->synchronize_state = icp_synchronize_state; + + cic->connect = icp_kvm_connect; + cic->disconnect = icp_kvm_disconnect; } static const TypeInfo icp_kvm_info = { diff --git a/hw/intc/xive.c b/hw/intc/xive.c index d96732cfe6be..4a9b09e3d819 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -14,6 +14,7 @@ #include "sysemu/cpus.h" #include "sysemu/dma.h" #include "monitor/monitor.h" +#include "hw/intc/intc.h" #include "hw/ppc/xics.h" /* for ICP_PROP_CPU */ #include "hw/ppc/xive.h" #include "hw/ppc/xive_regs.h" @@ -513,6 +514,10 @@ static const TypeInfo xive_nvt_info = { .instance_init = xive_nvt_init, .class_init = xive_nvt_class_init, .class_size = sizeof(XiveNVTClass), + .interfaces = (InterfaceInfo[]) { + { TYPE_CPU_INTC }, + { } + } }; /* diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 3df2bda53f50..aa612cb1c9f6 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -16,6 +16,7 @@ #include "sysemu/cpus.h" #include "sysemu/kvm.h" #include "target/ppc/kvm_ppc.h" +#include "hw/intc/intc.h" #include "hw/ppc/ppc.h" #include "target/ppc/mmu-hash64.h" #include "sysemu/numa.h" @@ -105,6 +106,7 @@ static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp) PowerPCCPU *cpu = POWERPC_CPU(cs); spapr_cpu_destroy(cpu); + cpu_intc_disconnect(CPU_INTC(cpu->intc), NULL); object_unparent(cpu->intc); cpu_remove_sync(cs); object_unparent(obj); @@ -134,6 +136,10 @@ static void spapr_cpu_core_realize_child(Object *child, goto error; } + cpu_intc_connect(CPU_INTC(cpu->intc), &local_err); + if (local_err) { + goto error; + } return; error: @@ -263,6 +269,7 @@ void spapr_cpu_core_reset_icp(Error **errp) CPU_FOREACH(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); + cpu_intc_disconnect(CPU_INTC(cpu->intc), errp); cpu->intc = NULL; } } @@ -298,5 +305,6 @@ void spapr_cpu_core_set_icp(const char *icp_type, Error **errp) } cpu->intc = args.icp; + cpu_intc_connect(CPU_INTC(cpu->intc), errp); } } -- 2.13.6