@@ -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 = {
@@ -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)
@@ -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 = {
@@ -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 },
+ { }
+ }
};
/*
@@ -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);
}
}
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 <clg@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(-)