diff options
-rw-r--r-- | include/linux/kvm_host.h | 8 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 42 | ||||
-rw-r--r-- | virt/kvm/vtd.c | 24 |
3 files changed, 74 insertions, 0 deletions
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index c96739b4b7a3..ce5d1c17ce26 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -334,6 +334,8 @@ int kvm_iommu_map_guest(struct kvm *kvm); | |||
334 | int kvm_iommu_unmap_guest(struct kvm *kvm); | 334 | int kvm_iommu_unmap_guest(struct kvm *kvm); |
335 | int kvm_assign_device(struct kvm *kvm, | 335 | int kvm_assign_device(struct kvm *kvm, |
336 | struct kvm_assigned_dev_kernel *assigned_dev); | 336 | struct kvm_assigned_dev_kernel *assigned_dev); |
337 | int kvm_deassign_device(struct kvm *kvm, | ||
338 | struct kvm_assigned_dev_kernel *assigned_dev); | ||
337 | #else /* CONFIG_DMAR */ | 339 | #else /* CONFIG_DMAR */ |
338 | static inline int kvm_iommu_map_pages(struct kvm *kvm, | 340 | static inline int kvm_iommu_map_pages(struct kvm *kvm, |
339 | gfn_t base_gfn, | 341 | gfn_t base_gfn, |
@@ -357,6 +359,12 @@ static inline int kvm_assign_device(struct kvm *kvm, | |||
357 | { | 359 | { |
358 | return 0; | 360 | return 0; |
359 | } | 361 | } |
362 | |||
363 | static inline int kvm_deassign_device(struct kvm *kvm, | ||
364 | struct kvm_assigned_dev_kernel *assigned_dev) | ||
365 | { | ||
366 | return 0; | ||
367 | } | ||
360 | #endif /* CONFIG_DMAR */ | 368 | #endif /* CONFIG_DMAR */ |
361 | 369 | ||
362 | static inline void kvm_guest_enter(void) | 370 | static inline void kvm_guest_enter(void) |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index c92b63462b79..3238e08e4651 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -530,6 +530,35 @@ out_free: | |||
530 | } | 530 | } |
531 | #endif | 531 | #endif |
532 | 532 | ||
533 | #ifdef KVM_CAP_DEVICE_DEASSIGNMENT | ||
534 | static int kvm_vm_ioctl_deassign_device(struct kvm *kvm, | ||
535 | struct kvm_assigned_pci_dev *assigned_dev) | ||
536 | { | ||
537 | int r = 0; | ||
538 | struct kvm_assigned_dev_kernel *match; | ||
539 | |||
540 | mutex_lock(&kvm->lock); | ||
541 | |||
542 | match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head, | ||
543 | assigned_dev->assigned_dev_id); | ||
544 | if (!match) { | ||
545 | printk(KERN_INFO "%s: device hasn't been assigned before, " | ||
546 | "so cannot be deassigned\n", __func__); | ||
547 | r = -EINVAL; | ||
548 | goto out; | ||
549 | } | ||
550 | |||
551 | if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) | ||
552 | kvm_deassign_device(kvm, match); | ||
553 | |||
554 | kvm_free_assigned_device(kvm, match); | ||
555 | |||
556 | out: | ||
557 | mutex_unlock(&kvm->lock); | ||
558 | return r; | ||
559 | } | ||
560 | #endif | ||
561 | |||
533 | static inline int valid_vcpu(int n) | 562 | static inline int valid_vcpu(int n) |
534 | { | 563 | { |
535 | return likely(n >= 0 && n < KVM_MAX_VCPUS); | 564 | return likely(n >= 0 && n < KVM_MAX_VCPUS); |
@@ -1863,6 +1892,19 @@ static long kvm_vm_ioctl(struct file *filp, | |||
1863 | break; | 1892 | break; |
1864 | } | 1893 | } |
1865 | #endif | 1894 | #endif |
1895 | #ifdef KVM_CAP_DEVICE_DEASSIGNMENT | ||
1896 | case KVM_DEASSIGN_PCI_DEVICE: { | ||
1897 | struct kvm_assigned_pci_dev assigned_dev; | ||
1898 | |||
1899 | r = -EFAULT; | ||
1900 | if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev)) | ||
1901 | goto out; | ||
1902 | r = kvm_vm_ioctl_deassign_device(kvm, &assigned_dev); | ||
1903 | if (r) | ||
1904 | goto out; | ||
1905 | break; | ||
1906 | } | ||
1907 | #endif | ||
1866 | default: | 1908 | default: |
1867 | r = kvm_arch_vm_ioctl(filp, ioctl, arg); | 1909 | r = kvm_arch_vm_ioctl(filp, ioctl, arg); |
1868 | } | 1910 | } |
diff --git a/virt/kvm/vtd.c b/virt/kvm/vtd.c index 44bb58a395a5..174ea1f8cee5 100644 --- a/virt/kvm/vtd.c +++ b/virt/kvm/vtd.c | |||
@@ -116,6 +116,30 @@ int kvm_assign_device(struct kvm *kvm, | |||
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
118 | 118 | ||
119 | int kvm_deassign_device(struct kvm *kvm, | ||
120 | struct kvm_assigned_dev_kernel *assigned_dev) | ||
121 | { | ||
122 | struct dmar_domain *domain = kvm->arch.intel_iommu_domain; | ||
123 | struct pci_dev *pdev = NULL; | ||
124 | |||
125 | /* check if iommu exists and in use */ | ||
126 | if (!domain) | ||
127 | return 0; | ||
128 | |||
129 | pdev = assigned_dev->dev; | ||
130 | if (pdev == NULL) | ||
131 | return -ENODEV; | ||
132 | |||
133 | intel_iommu_detach_device(domain, pdev); | ||
134 | |||
135 | printk(KERN_DEBUG "deassign device: host bdf = %x:%x:%x\n", | ||
136 | assigned_dev->host_busnr, | ||
137 | PCI_SLOT(assigned_dev->host_devfn), | ||
138 | PCI_FUNC(assigned_dev->host_devfn)); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
119 | int kvm_iommu_map_guest(struct kvm *kvm) | 143 | int kvm_iommu_map_guest(struct kvm *kvm) |
120 | { | 144 | { |
121 | int r; | 145 | int r; |