diff options
-rw-r--r-- | Documentation/virtual/kvm/api.txt | 17 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/x86/kvm/i8254.c | 4 | ||||
-rw-r--r-- | arch/x86/kvm/ioapic.h | 8 | ||||
-rw-r--r-- | arch/x86/kvm/irq.h | 11 | ||||
-rw-r--r-- | arch/x86/kvm/irq_comm.c | 9 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 6 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 23 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/kvm.h | 1 |
10 files changed, 75 insertions, 7 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index d9ecceea5a02..43e0816d0de1 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt | |||
@@ -3627,6 +3627,23 @@ struct { | |||
3627 | 3627 | ||
3628 | KVM handlers should exit to userspace with rc = -EREMOTE. | 3628 | KVM handlers should exit to userspace with rc = -EREMOTE. |
3629 | 3629 | ||
3630 | 7.5 KVM_CAP_SPLIT_IRQCHIP | ||
3631 | |||
3632 | Architectures: x86 | ||
3633 | Parameters: None | ||
3634 | Returns: 0 on success, -1 on error | ||
3635 | |||
3636 | Create a local apic for each processor in the kernel. This can be used | ||
3637 | instead of KVM_CREATE_IRQCHIP if the userspace VMM wishes to emulate the | ||
3638 | IOAPIC and PIC (and also the PIT, even though this has to be enabled | ||
3639 | separately). | ||
3640 | |||
3641 | This supersedes KVM_CREATE_IRQCHIP, creating only local APICs, but no in kernel | ||
3642 | IOAPIC or PIC. This also enables in kernel routing of interrupt requests. | ||
3643 | |||
3644 | Fails if VCPU has already been created, or if the irqchip is already in the | ||
3645 | kernel (i.e. KVM_CREATE_IRQCHIP has already been called). | ||
3646 | |||
3630 | 3647 | ||
3631 | 8. Other capabilities. | 3648 | 8. Other capabilities. |
3632 | ---------------------- | 3649 | ---------------------- |
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index a0ef289d5a86..befcf555bddc 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -684,6 +684,8 @@ struct kvm_arch { | |||
684 | u32 bsp_vcpu_id; | 684 | u32 bsp_vcpu_id; |
685 | 685 | ||
686 | u64 disabled_quirks; | 686 | u64 disabled_quirks; |
687 | |||
688 | bool irqchip_split; | ||
687 | }; | 689 | }; |
688 | 690 | ||
689 | struct kvm_vm_stat { | 691 | struct kvm_vm_stat { |
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index f90952f64e79..08116ff227cc 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/kvm_host.h> | 35 | #include <linux/kvm_host.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | 37 | ||
38 | #include "ioapic.h" | ||
38 | #include "irq.h" | 39 | #include "irq.h" |
39 | #include "i8254.h" | 40 | #include "i8254.h" |
40 | #include "x86.h" | 41 | #include "x86.h" |
@@ -333,7 +334,8 @@ static void create_pit_timer(struct kvm *kvm, u32 val, int is_period) | |||
333 | struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; | 334 | struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; |
334 | s64 interval; | 335 | s64 interval; |
335 | 336 | ||
336 | if (!irqchip_in_kernel(kvm) || ps->flags & KVM_PIT_FLAGS_HPET_LEGACY) | 337 | if (!ioapic_in_kernel(kvm) || |
338 | ps->flags & KVM_PIT_FLAGS_HPET_LEGACY) | ||
337 | return; | 339 | return; |
338 | 340 | ||
339 | interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ); | 341 | interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ); |
diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h index bf36d66a1951..a8842c0dee73 100644 --- a/arch/x86/kvm/ioapic.h +++ b/arch/x86/kvm/ioapic.h | |||
@@ -97,6 +97,14 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm) | |||
97 | return kvm->arch.vioapic; | 97 | return kvm->arch.vioapic; |
98 | } | 98 | } |
99 | 99 | ||
100 | static inline int ioapic_in_kernel(struct kvm *kvm) | ||
101 | { | ||
102 | int ret; | ||
103 | |||
104 | ret = (ioapic_irqchip(kvm) != NULL); | ||
105 | return ret; | ||
106 | } | ||
107 | |||
100 | void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu); | 108 | void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu); |
101 | bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, | 109 | bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, |
102 | int short_hand, unsigned int dest, int dest_mode); | 110 | int short_hand, unsigned int dest, int dest_mode); |
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 9e6e7e04de98..2f9703dcd913 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h | |||
@@ -83,13 +83,22 @@ static inline struct kvm_pic *pic_irqchip(struct kvm *kvm) | |||
83 | return kvm->arch.vpic; | 83 | return kvm->arch.vpic; |
84 | } | 84 | } |
85 | 85 | ||
86 | static inline int irqchip_split(struct kvm *kvm) | ||
87 | { | ||
88 | return kvm->arch.irqchip_split; | ||
89 | } | ||
90 | |||
86 | static inline int irqchip_in_kernel(struct kvm *kvm) | 91 | static inline int irqchip_in_kernel(struct kvm *kvm) |
87 | { | 92 | { |
88 | struct kvm_pic *vpic = pic_irqchip(kvm); | 93 | struct kvm_pic *vpic = pic_irqchip(kvm); |
94 | bool ret; | ||
95 | |||
96 | ret = (vpic != NULL); | ||
97 | ret |= irqchip_split(kvm); | ||
89 | 98 | ||
90 | /* Read vpic before kvm->irq_routing. */ | 99 | /* Read vpic before kvm->irq_routing. */ |
91 | smp_rmb(); | 100 | smp_rmb(); |
92 | return vpic != NULL; | 101 | return ret; |
93 | } | 102 | } |
94 | 103 | ||
95 | static inline int lapic_in_kernel(struct kvm_vcpu *vcpu) | 104 | static inline int lapic_in_kernel(struct kvm_vcpu *vcpu) |
diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c index 9efff9e5b58c..67f6b62a6814 100644 --- a/arch/x86/kvm/irq_comm.c +++ b/arch/x86/kvm/irq_comm.c | |||
@@ -208,7 +208,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) | |||
208 | goto unlock; | 208 | goto unlock; |
209 | } | 209 | } |
210 | clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap); | 210 | clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap); |
211 | if (!irqchip_in_kernel(kvm)) | 211 | if (!ioapic_in_kernel(kvm)) |
212 | goto unlock; | 212 | goto unlock; |
213 | 213 | ||
214 | kvm_ioapic_clear_all(kvm->arch.vioapic, irq_source_id); | 214 | kvm_ioapic_clear_all(kvm->arch.vioapic, irq_source_id); |
@@ -328,3 +328,10 @@ int kvm_setup_default_irq_routing(struct kvm *kvm) | |||
328 | return kvm_set_irq_routing(kvm, default_routing, | 328 | return kvm_set_irq_routing(kvm, default_routing, |
329 | ARRAY_SIZE(default_routing), 0); | 329 | ARRAY_SIZE(default_routing), 0); |
330 | } | 330 | } |
331 | |||
332 | static const struct kvm_irq_routing_entry empty_routing[] = {}; | ||
333 | |||
334 | int kvm_setup_empty_irq_routing(struct kvm *kvm) | ||
335 | { | ||
336 | return kvm_set_irq_routing(kvm, empty_routing, 0, 0); | ||
337 | } | ||
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index c4bcc86d6dc4..e05946c36b87 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -209,7 +209,8 @@ out: | |||
209 | if (old) | 209 | if (old) |
210 | kfree_rcu(old, rcu); | 210 | kfree_rcu(old, rcu); |
211 | 211 | ||
212 | kvm_vcpu_request_scan_ioapic(kvm); | 212 | if (ioapic_in_kernel(kvm)) |
213 | kvm_vcpu_request_scan_ioapic(kvm); | ||
213 | } | 214 | } |
214 | 215 | ||
215 | static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) | 216 | static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) |
@@ -1845,7 +1846,8 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu, | |||
1845 | kvm_x86_ops->hwapic_isr_update(vcpu->kvm, | 1846 | kvm_x86_ops->hwapic_isr_update(vcpu->kvm, |
1846 | apic_find_highest_isr(apic)); | 1847 | apic_find_highest_isr(apic)); |
1847 | kvm_make_request(KVM_REQ_EVENT, vcpu); | 1848 | kvm_make_request(KVM_REQ_EVENT, vcpu); |
1848 | kvm_rtc_eoi_tracking_restore_one(vcpu); | 1849 | if (ioapic_in_kernel(vcpu->kvm)) |
1850 | kvm_rtc_eoi_tracking_restore_one(vcpu); | ||
1849 | } | 1851 | } |
1850 | 1852 | ||
1851 | void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) | 1853 | void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 28c98c8f9d1c..f720774a4797 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -2448,6 +2448,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) | |||
2448 | case KVM_CAP_ENABLE_CAP_VM: | 2448 | case KVM_CAP_ENABLE_CAP_VM: |
2449 | case KVM_CAP_DISABLE_QUIRKS: | 2449 | case KVM_CAP_DISABLE_QUIRKS: |
2450 | case KVM_CAP_SET_BOOT_CPU_ID: | 2450 | case KVM_CAP_SET_BOOT_CPU_ID: |
2451 | case KVM_CAP_SPLIT_IRQCHIP: | ||
2451 | #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT | 2452 | #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT |
2452 | case KVM_CAP_ASSIGN_DEV_IRQ: | 2453 | case KVM_CAP_ASSIGN_DEV_IRQ: |
2453 | case KVM_CAP_PCI_2_3: | 2454 | case KVM_CAP_PCI_2_3: |
@@ -3555,6 +3556,24 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, | |||
3555 | kvm->arch.disabled_quirks = cap->args[0]; | 3556 | kvm->arch.disabled_quirks = cap->args[0]; |
3556 | r = 0; | 3557 | r = 0; |
3557 | break; | 3558 | break; |
3559 | case KVM_CAP_SPLIT_IRQCHIP: { | ||
3560 | mutex_lock(&kvm->lock); | ||
3561 | r = -EEXIST; | ||
3562 | if (irqchip_in_kernel(kvm)) | ||
3563 | goto split_irqchip_unlock; | ||
3564 | if (atomic_read(&kvm->online_vcpus)) | ||
3565 | goto split_irqchip_unlock; | ||
3566 | r = kvm_setup_empty_irq_routing(kvm); | ||
3567 | if (r) | ||
3568 | goto split_irqchip_unlock; | ||
3569 | /* Pairs with irqchip_in_kernel. */ | ||
3570 | smp_wmb(); | ||
3571 | kvm->arch.irqchip_split = true; | ||
3572 | r = 0; | ||
3573 | split_irqchip_unlock: | ||
3574 | mutex_unlock(&kvm->lock); | ||
3575 | break; | ||
3576 | } | ||
3558 | default: | 3577 | default: |
3559 | r = -EINVAL; | 3578 | r = -EINVAL; |
3560 | break; | 3579 | break; |
@@ -3668,7 +3687,7 @@ long kvm_arch_vm_ioctl(struct file *filp, | |||
3668 | } | 3687 | } |
3669 | 3688 | ||
3670 | r = -ENXIO; | 3689 | r = -ENXIO; |
3671 | if (!irqchip_in_kernel(kvm)) | 3690 | if (!irqchip_in_kernel(kvm) || irqchip_split(kvm)) |
3672 | goto get_irqchip_out; | 3691 | goto get_irqchip_out; |
3673 | r = kvm_vm_ioctl_get_irqchip(kvm, chip); | 3692 | r = kvm_vm_ioctl_get_irqchip(kvm, chip); |
3674 | if (r) | 3693 | if (r) |
@@ -3692,7 +3711,7 @@ long kvm_arch_vm_ioctl(struct file *filp, | |||
3692 | } | 3711 | } |
3693 | 3712 | ||
3694 | r = -ENXIO; | 3713 | r = -ENXIO; |
3695 | if (!irqchip_in_kernel(kvm)) | 3714 | if (!irqchip_in_kernel(kvm) || irqchip_split(kvm)) |
3696 | goto set_irqchip_out; | 3715 | goto set_irqchip_out; |
3697 | r = kvm_vm_ioctl_set_irqchip(kvm, chip); | 3716 | r = kvm_vm_ioctl_set_irqchip(kvm, chip); |
3698 | if (r) | 3717 | if (r) |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 1bef9e21e725..354f147647ab 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -1002,6 +1002,7 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq) | |||
1002 | #endif | 1002 | #endif |
1003 | 1003 | ||
1004 | int kvm_setup_default_irq_routing(struct kvm *kvm); | 1004 | int kvm_setup_default_irq_routing(struct kvm *kvm); |
1005 | int kvm_setup_empty_irq_routing(struct kvm *kvm); | ||
1005 | int kvm_set_irq_routing(struct kvm *kvm, | 1006 | int kvm_set_irq_routing(struct kvm *kvm, |
1006 | const struct kvm_irq_routing_entry *entries, | 1007 | const struct kvm_irq_routing_entry *entries, |
1007 | unsigned nr, | 1008 | unsigned nr, |
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index a9256f0331ae..ed00f8fc9ea2 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h | |||
@@ -824,6 +824,7 @@ struct kvm_ppc_smmu_info { | |||
824 | #define KVM_CAP_MULTI_ADDRESS_SPACE 118 | 824 | #define KVM_CAP_MULTI_ADDRESS_SPACE 118 |
825 | #define KVM_CAP_GUEST_DEBUG_HW_BPS 119 | 825 | #define KVM_CAP_GUEST_DEBUG_HW_BPS 119 |
826 | #define KVM_CAP_GUEST_DEBUG_HW_WPS 120 | 826 | #define KVM_CAP_GUEST_DEBUG_HW_WPS 120 |
827 | #define KVM_CAP_SPLIT_IRQCHIP 121 | ||
827 | 828 | ||
828 | #ifdef KVM_CAP_IRQ_ROUTING | 829 | #ifdef KVM_CAP_IRQ_ROUTING |
829 | 830 | ||