OSDN Git Service

Merge tag 'kvm-arm-for-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm...
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / virt / kvm / kvm_main.c
index a25a731..484079e 100644 (file)
@@ -66,8 +66,8 @@
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
-/* halt polling only reduces halt latency by 5-7 us, 500us is enough */
-static unsigned int halt_poll_ns = 500000;
+/* Architectures should define their poll value according to the halt latency */
+static unsigned int halt_poll_ns = KVM_HALT_POLL_NS_DEFAULT;
 module_param(halt_poll_ns, uint, S_IRUGO | S_IWUSR);
 
 /* Default doubles per-vcpu halt_poll_ns. */
@@ -230,6 +230,9 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
        init_waitqueue_head(&vcpu->wq);
        kvm_async_pf_vcpu_init(vcpu);
 
+       vcpu->pre_pcpu = -1;
+       INIT_LIST_HEAD(&vcpu->blocked_vcpu_list);
+
        page = alloc_page(GFP_KERNEL | __GFP_ZERO);
        if (!page) {
                r = -ENOMEM;
@@ -2004,6 +2007,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
        if (vcpu->halt_poll_ns) {
                ktime_t stop = ktime_add_ns(ktime_get(), vcpu->halt_poll_ns);
 
+               ++vcpu->stat.halt_attempted_poll;
                do {
                        /*
                         * This sets KVM_REQ_UNHALT if an interrupt
@@ -2017,6 +2021,8 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
                } while (single_task_running() && ktime_before(cur, stop));
        }
 
+       kvm_arch_vcpu_blocking(vcpu);
+
        for (;;) {
                prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE);
 
@@ -2030,6 +2036,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
        finish_wait(&vcpu->wq, &wait);
        cur = ktime_get();
 
+       kvm_arch_vcpu_unblocking(vcpu);
 out:
        block_ns = ktime_to_ns(cur) - ktime_to_ns(start);
 
@@ -2043,7 +2050,8 @@ out:
                else if (vcpu->halt_poll_ns < halt_poll_ns &&
                        block_ns < halt_poll_ns)
                        grow_halt_poll_ns(vcpu);
-       }
+       } else
+               vcpu->halt_poll_ns = 0;
 
        trace_kvm_vcpu_wakeup(block_ns, waited);
 }
@@ -2716,6 +2724,7 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
        case KVM_CAP_IRQFD:
        case KVM_CAP_IRQFD_RESAMPLE:
 #endif
+       case KVM_CAP_IOEVENTFD_ANY_LENGTH:
        case KVM_CAP_CHECK_EXTENSION_VM:
                return 1;
 #ifdef CONFIG_HAVE_KVM_IRQ_ROUTING
@@ -3156,10 +3165,25 @@ static void kvm_io_bus_destroy(struct kvm_io_bus *bus)
 static inline int kvm_io_bus_cmp(const struct kvm_io_range *r1,
                                 const struct kvm_io_range *r2)
 {
-       if (r1->addr < r2->addr)
+       gpa_t addr1 = r1->addr;
+       gpa_t addr2 = r2->addr;
+
+       if (addr1 < addr2)
                return -1;
-       if (r1->addr + r1->len > r2->addr + r2->len)
+
+       /* If r2->len == 0, match the exact address.  If r2->len != 0,
+        * accept any overlapping write.  Any order is acceptable for
+        * overlapping ranges, because kvm_io_bus_get_first_dev ensures
+        * we process all of them.
+        */
+       if (r2->len) {
+               addr1 += r1->len;
+               addr2 += r2->len;
+       }
+
+       if (addr1 > addr2)
                return 1;
+
        return 0;
 }
 
@@ -3324,7 +3348,7 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
        if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
                return -ENOSPC;
 
-       new_bus = kzalloc(sizeof(*bus) + ((bus->dev_count + 1) *
+       new_bus = kmalloc(sizeof(*bus) + ((bus->dev_count + 1) *
                          sizeof(struct kvm_io_range)), GFP_KERNEL);
        if (!new_bus)
                return -ENOMEM;
@@ -3356,7 +3380,7 @@ int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
        if (r)
                return r;
 
-       new_bus = kzalloc(sizeof(*bus) + ((bus->dev_count - 1) *
+       new_bus = kmalloc(sizeof(*bus) + ((bus->dev_count - 1) *
                          sizeof(struct kvm_io_range)), GFP_KERNEL);
        if (!new_bus)
                return -ENOMEM;