This adds a new ioctl, KVM_SET_IRQ_ARCHITECTURE, which is intended to
be called by userspace to specify that it wishes the kernel to emulate
a specific interrupt controller architecture.  This doesn't imply the
creation of any specific device, but does indicate that when vcpus are
created, space for per-vcpu interrupt controller state should be
allocated.  Having this ioctl enables userspace to defer creation of
the actual interrupt controller device(s) until after the vcpus are
created.

The KVM_SET_IRQ_ARCHITECTURE ioctl takes a single 32-bit unsigned int
as its parameter.  Values for this parameter will be defined in
subsequent patches.  The value of 0 means no in-kernel interrupt
controller emulation.

In order to ensure that this ioctl will fail once any vcpu has been
created, we use an arch.vcpus_created field to indicate that vcpu
creation has commenced.  We don't use the online_vcpus field because
that is only incremented after vcpu creation; if we used that there
would be a window during the first KVM_CREATE_VCPU ioctl where the
first vcpu had been created but the interrupt architecture could still
be changed.

Signed-off-by: Paul Mackerras <pau...@samba.org>
---
So, should this all be done in generic code?

 Documentation/virtual/kvm/api.txt   |   22 ++++++++++++
 arch/powerpc/include/asm/kvm_host.h |    2 ++
 arch/powerpc/kvm/powerpc.c          |   66 +++++++++++++++++++++++++++++++++--
 include/uapi/linux/kvm.h            |    3 ++
 4 files changed, 90 insertions(+), 3 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt 
b/Documentation/virtual/kvm/api.txt
index cce500a..d550313 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2126,6 +2126,28 @@ header; first `n_valid' valid entries with contents from 
the data
 written, then `n_invalid' invalid entries, invalidating any previously
 valid entries found.
 
+4.79 KVM_SET_IRQ_ARCHITECTURE
+
+Capability: KVM_CAP_IRQ_ARCH
+Architecture: powerpc
+Type: vm ioctl
+Parameters: Pointer to u32 (in)
+Returns: 0 on success, -1 on error
+
+This is called before any vcpus are created, if in-kernel interrupt
+controller emulation is desired, to specify what overall interrupt
+controller architecture should be emulated.  Having this called before
+any vcpus are created allows per-vcpu interrupt controller state to be
+allocated at vcpu creation time, and allows the creation of the actual
+interrupt controller device to be deferred until after the vcpus are
+created.
+
+The parameter is a 32-bit unsigned integer specifying the
+architecture, or the value 0 to specify that no emulation should be
+done.  If the requested architecture is not supported by the kernel,
+this ioctl returns an EINVAL error.  Otherwise, if this ioctl is
+called after any vcpus have been created, it returns an EBUSY error.
+
 
 5. The kvm_run structure
 ------------------------
diff --git a/arch/powerpc/include/asm/kvm_host.h 
b/arch/powerpc/include/asm/kvm_host.h
index 8a72d59..e21ea1f 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -227,6 +227,8 @@ struct kvm_arch_memory_slot {
 };
 
 struct kvm_arch {
+       unsigned int irq_arch;
+       int vcpus_created;
        unsigned int lpid;
 #ifdef CONFIG_KVM_BOOK3S_64_HV
        unsigned long hpt_virt;
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 934413c..b681746 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -441,10 +441,21 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, 
unsigned int id)
 {
        struct kvm_vcpu *vcpu;
        vcpu = kvmppc_core_vcpu_create(kvm, id);
-       if (!IS_ERR(vcpu)) {
-               vcpu->arch.wqp = &vcpu->wq;
-               kvmppc_create_vcpu_debugfs(vcpu, id);
+       if (IS_ERR(vcpu))
+               goto out;
+
+       /* Create per-vcpu irq controller state if needed */
+       mutex_lock(&kvm->lock);
+       kvm->arch.vcpus_created = 1;
+       switch (kvm->arch.irq_arch) {
+       default:
+               break;
        }
+       mutex_unlock(&kvm->lock);
+
+       vcpu->arch.wqp = &vcpu->wq;
+       kvmppc_create_vcpu_debugfs(vcpu, id);
+ out:
        return vcpu;
 }
 
@@ -459,6 +470,12 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
        hrtimer_cancel(&vcpu->arch.dec_timer);
        tasklet_kill(&vcpu->arch.tasklet);
 
+       /* Destroy per-vcpu irq controller state */
+       switch (vcpu->kvm->arch.irq_arch) {
+       default:
+               break;
+       }
+
        kvmppc_remove_vcpu_debugfs(vcpu);
        kvmppc_core_vcpu_free(vcpu);
 }
@@ -996,6 +1013,49 @@ long kvm_arch_vm_ioctl(struct file *filp,
                break;
        }
 #endif /* CONFIG_PPC_BOOK3S_64 */
+
+       case KVM_IRQ_LINE: {
+               struct kvm *kvm = filp->private_data;
+               struct kvm_irq_level args;
+
+               r = -EFAULT;
+               if (copy_from_user(&args, argp, sizeof(args)))
+                       break;
+               switch (kvm->arch.irq_arch) {
+               default:
+                       r = -EINVAL;
+               }
+               break;
+       }
+
+       case KVM_SET_IRQ_ARCHITECTURE: {
+               struct kvm *kvm = filp->private_data;
+               u32 arch_id;
+
+               r = -EFAULT;
+               if (get_user(arch_id, (u32 __user *)argp))
+                       break;
+               r = 0;
+               switch (arch_id) {
+               case 0:         /* no emulation */
+                       break;
+               default:
+                       r = -EINVAL;
+                       break;
+               }
+               if (r)
+                       break;
+
+               /* mutex ensures we don't race with vcpu creation */
+               mutex_lock(&kvm->lock);
+               if (!kvm->arch.vcpus_created)
+                       kvm->arch.irq_arch = arch_id;
+               else
+                       r = -EBUSY;
+               mutex_unlock(&kvm->lock);
+               break;
+       }
+
        default:
                r = -ENOTTY;
        }
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 9a2db57..2c0ea1c 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -662,6 +662,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_PPC_HTAB_FD 84
 #define KVM_CAP_S390_CSS_SUPPORT 85
 #define KVM_CAP_PPC_EPR 86
+#define KVM_CAP_IRQ_ARCH 87
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -889,6 +890,8 @@ struct kvm_s390_ucas_mapping {
 #define KVM_ALLOCATE_RMA         _IOR(KVMIO,  0xa9, struct kvm_allocate_rma)
 /* Available with KVM_CAP_PPC_HTAB_FD */
 #define KVM_PPC_GET_HTAB_FD      _IOW(KVMIO,  0xaa, struct kvm_get_htab_fd)
+/* Available with KVM_CAP_IRQ_ARCH */
+#define KVM_SET_IRQ_ARCHITECTURE  _IOW(KVMIO,  0xab, __u32)
 
 /*
  * ioctls for vcpu fds
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to