@@ -518,7 +518,7 @@ extern void kvmppc_alloc_host_rm_ops(void);
extern void kvmppc_free_host_rm_ops(void);
extern void kvmppc_free_pimap(struct kvm *kvm);
extern int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall);
-extern void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu);
+extern int kvmppc_xics_free_icp(struct kvm_vcpu *vcpu);
extern int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd);
extern u64 kvmppc_xics_get_icp(struct kvm_vcpu *vcpu);
extern int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval);
@@ -574,7 +574,7 @@ extern void kvmppc_xive_exit_module(void);
extern int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
struct kvm_vcpu *vcpu, u32 cpu);
-extern void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu);
+extern int kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu);
extern int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq,
struct irq_desc *host_desc);
extern int kvmppc_xive_clr_mapped(struct kvm *kvm, unsigned long guest_irq,
@@ -1440,13 +1440,14 @@ int kvmppc_xics_connect_vcpu(struct kvm_device *dev, struct kvm_vcpu *vcpu,
return r;
}
-void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu)
+int kvmppc_xics_free_icp(struct kvm_vcpu *vcpu)
{
if (!vcpu->arch.icp)
- return;
+ return -ENOENT;
kfree(vcpu->arch.icp);
vcpu->arch.icp = NULL;
vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT;
+ return 0;
}
void kvmppc_xics_set_mapped(struct kvm *kvm, unsigned long irq,
@@ -1023,12 +1023,15 @@ void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu)
}
}
-void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu)
+int kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu)
{
struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
struct kvmppc_xive *xive = xc->xive;
int i;
+ if (!vcpu->arch.xive_vcpu)
+ return -ENOENT;
+
pr_devel("cleanup_vcpu(cpu=%d)\n", xc->server_num);
/* Ensure no interrupt is still routed to that VP */
@@ -1067,6 +1070,11 @@ void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu)
}
/* Free the VP */
kfree(xc);
+
+ /* Cleanup the vcpu */
+ vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT;
+ vcpu->arch.xive_vcpu = NULL;
+ return 0;
}
int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
@@ -1710,10 +1710,19 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
r = -EPERM;
dev = kvm_device_from_filp(f.file);
if (dev) {
- if (xive_enabled())
- r = kvmppc_xive_connect_vcpu(dev, vcpu, cap->args[1]);
- else
- r = kvmppc_xics_connect_vcpu(dev, vcpu, cap->args[1]);
+ if (cap->args[2]) {
+ if (xive_enabled())
+ r = kvmppc_xive_cleanup_vcpu(vcpu);
+ else
+ r = kvmppc_xics_free_icp(vcpu);
+ } else {
+ if (xive_enabled())
+ r = kvmppc_xive_connect_vcpu(dev, vcpu,
+ cap->args[1]);
+ else
+ r = kvmppc_xics_connect_vcpu(dev, vcpu,
+ cap->args[1]);
+ }
}
fdput(f);
@@ -1736,9 +1745,14 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
r = -EPERM;
dev = kvm_device_from_filp(f.file);
- if (dev)
- r = kvmppc_xive_native_connect_vcpu(dev, vcpu,
- cap->args[1]);
+ if (dev) {
+ if (cap->args[2]) {
+ r = kvmppc_xive_native_cleanup_vcpu(vcpu);
+ } else {
+ r = kvmppc_xive_native_connect_vcpu(dev, vcpu,
+ cap->args[1]);
+ }
+ }
fdput(f);
break;
Before destroying a KVM device for IRQs, we need to disconnect the VCPUs. Do that using a 'disable=1' as last argument of the KVM_ENABLE_CAP ioctl. This is a bit hacky, we should introduce a KVM_DISABLE_CAP ioctl most certainly. Signed-off-by: Cédric Le Goater <clg@kaod.org> --- arch/powerpc/include/asm/kvm_ppc.h | 4 ++-- arch/powerpc/kvm/book3s_xics.c | 5 +++-- arch/powerpc/kvm/book3s_xive.c | 10 +++++++++- arch/powerpc/kvm/powerpc.c | 28 +++++++++++++++++++++------- 4 files changed, 35 insertions(+), 12 deletions(-)