diff options
Diffstat (limited to 'virt/kvm/kvm_main.c')
| -rw-r--r-- | virt/kvm/kvm_main.c | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index fc6127cbea1f..3a5a08298aab 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
| @@ -496,6 +496,7 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm, | |||
| 496 | match->assigned_dev_id = assigned_dev->assigned_dev_id; | 496 | match->assigned_dev_id = assigned_dev->assigned_dev_id; |
| 497 | match->host_busnr = assigned_dev->busnr; | 497 | match->host_busnr = assigned_dev->busnr; |
| 498 | match->host_devfn = assigned_dev->devfn; | 498 | match->host_devfn = assigned_dev->devfn; |
| 499 | match->flags = assigned_dev->flags; | ||
| 499 | match->dev = dev; | 500 | match->dev = dev; |
| 500 | match->irq_source_id = -1; | 501 | match->irq_source_id = -1; |
| 501 | match->kvm = kvm; | 502 | match->kvm = kvm; |
| @@ -503,7 +504,12 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm, | |||
| 503 | list_add(&match->list, &kvm->arch.assigned_dev_head); | 504 | list_add(&match->list, &kvm->arch.assigned_dev_head); |
| 504 | 505 | ||
| 505 | if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) { | 506 | if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) { |
| 506 | r = kvm_iommu_map_guest(kvm, match); | 507 | if (!kvm->arch.iommu_domain) { |
| 508 | r = kvm_iommu_map_guest(kvm); | ||
| 509 | if (r) | ||
| 510 | goto out_list_del; | ||
| 511 | } | ||
| 512 | r = kvm_assign_device(kvm, match); | ||
| 507 | if (r) | 513 | if (r) |
| 508 | goto out_list_del; | 514 | goto out_list_del; |
| 509 | } | 515 | } |
| @@ -525,6 +531,35 @@ out_free: | |||
| 525 | } | 531 | } |
| 526 | #endif | 532 | #endif |
| 527 | 533 | ||
| 534 | #ifdef KVM_CAP_DEVICE_DEASSIGNMENT | ||
| 535 | static int kvm_vm_ioctl_deassign_device(struct kvm *kvm, | ||
| 536 | struct kvm_assigned_pci_dev *assigned_dev) | ||
| 537 | { | ||
| 538 | int r = 0; | ||
| 539 | struct kvm_assigned_dev_kernel *match; | ||
| 540 | |||
| 541 | mutex_lock(&kvm->lock); | ||
| 542 | |||
| 543 | match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head, | ||
| 544 | assigned_dev->assigned_dev_id); | ||
| 545 | if (!match) { | ||
| 546 | printk(KERN_INFO "%s: device hasn't been assigned before, " | ||
| 547 | "so cannot be deassigned\n", __func__); | ||
| 548 | r = -EINVAL; | ||
| 549 | goto out; | ||
| 550 | } | ||
| 551 | |||
| 552 | if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) | ||
| 553 | kvm_deassign_device(kvm, match); | ||
| 554 | |||
| 555 | kvm_free_assigned_device(kvm, match); | ||
| 556 | |||
| 557 | out: | ||
| 558 | mutex_unlock(&kvm->lock); | ||
| 559 | return r; | ||
| 560 | } | ||
| 561 | #endif | ||
| 562 | |||
| 528 | static inline int valid_vcpu(int n) | 563 | static inline int valid_vcpu(int n) |
| 529 | { | 564 | { |
| 530 | return likely(n >= 0 && n < KVM_MAX_VCPUS); | 565 | return likely(n >= 0 && n < KVM_MAX_VCPUS); |
| @@ -1858,6 +1893,19 @@ static long kvm_vm_ioctl(struct file *filp, | |||
| 1858 | break; | 1893 | break; |
| 1859 | } | 1894 | } |
| 1860 | #endif | 1895 | #endif |
| 1896 | #ifdef KVM_CAP_DEVICE_DEASSIGNMENT | ||
| 1897 | case KVM_DEASSIGN_PCI_DEVICE: { | ||
| 1898 | struct kvm_assigned_pci_dev assigned_dev; | ||
| 1899 | |||
| 1900 | r = -EFAULT; | ||
| 1901 | if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev)) | ||
| 1902 | goto out; | ||
| 1903 | r = kvm_vm_ioctl_deassign_device(kvm, &assigned_dev); | ||
| 1904 | if (r) | ||
| 1905 | goto out; | ||
| 1906 | break; | ||
| 1907 | } | ||
| 1908 | #endif | ||
| 1861 | default: | 1909 | default: |
| 1862 | r = kvm_arch_vm_ioctl(filp, ioctl, arg); | 1910 | r = kvm_arch_vm_ioctl(filp, ioctl, arg); |
| 1863 | } | 1911 | } |
