diff options
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/kvm_main.c | 42 | ||||
-rw-r--r-- | virt/kvm/vtd.c | 24 |
2 files changed, 66 insertions, 0 deletions
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; |