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@xxxxxxxx> --- 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(-) diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 748518c7bf70..5c0af1cabe34 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -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, diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index b8356cdc0c04..b0c85525944d 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c @@ -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, diff --git a/arch/powerpc/kvm/book3s_xive.c b/arch/powerpc/kvm/book3s_xive.c index abb4ae5c5b91..3c66480d3304 100644 --- a/arch/powerpc/kvm/book3s_xive.c +++ b/arch/powerpc/kvm/book3s_xive.c @@ -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, diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 42eb75e43d6e..e0ff5e9610ee 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -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; -- 2.13.6