Commit 0a920356 authored by Weidong Han's avatar Weidong Han Committed by Joerg Roedel

KVM: support device deassignment

Support device deassignment, it can be used in device hotplug.
Signed-off-by: default avatarWeidong Han <weidong.han@intel.com>
Signed-off-by: default avatarJoerg Roedel <joerg.roedel@amd.com>
parent 260782bc
...@@ -334,6 +334,8 @@ int kvm_iommu_map_guest(struct kvm *kvm); ...@@ -334,6 +334,8 @@ int kvm_iommu_map_guest(struct kvm *kvm);
int kvm_iommu_unmap_guest(struct kvm *kvm); int kvm_iommu_unmap_guest(struct kvm *kvm);
int kvm_assign_device(struct kvm *kvm, int kvm_assign_device(struct kvm *kvm,
struct kvm_assigned_dev_kernel *assigned_dev); struct kvm_assigned_dev_kernel *assigned_dev);
int kvm_deassign_device(struct kvm *kvm,
struct kvm_assigned_dev_kernel *assigned_dev);
#else /* CONFIG_DMAR */ #else /* CONFIG_DMAR */
static inline int kvm_iommu_map_pages(struct kvm *kvm, static inline int kvm_iommu_map_pages(struct kvm *kvm,
gfn_t base_gfn, gfn_t base_gfn,
...@@ -357,6 +359,12 @@ static inline int kvm_assign_device(struct kvm *kvm, ...@@ -357,6 +359,12 @@ static inline int kvm_assign_device(struct kvm *kvm,
{ {
return 0; return 0;
} }
static inline int kvm_deassign_device(struct kvm *kvm,
struct kvm_assigned_dev_kernel *assigned_dev)
{
return 0;
}
#endif /* CONFIG_DMAR */ #endif /* CONFIG_DMAR */
static inline void kvm_guest_enter(void) static inline void kvm_guest_enter(void)
......
...@@ -530,6 +530,35 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm, ...@@ -530,6 +530,35 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
} }
#endif #endif
#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
static int kvm_vm_ioctl_deassign_device(struct kvm *kvm,
struct kvm_assigned_pci_dev *assigned_dev)
{
int r = 0;
struct kvm_assigned_dev_kernel *match;
mutex_lock(&kvm->lock);
match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
assigned_dev->assigned_dev_id);
if (!match) {
printk(KERN_INFO "%s: device hasn't been assigned before, "
"so cannot be deassigned\n", __func__);
r = -EINVAL;
goto out;
}
if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU)
kvm_deassign_device(kvm, match);
kvm_free_assigned_device(kvm, match);
out:
mutex_unlock(&kvm->lock);
return r;
}
#endif
static inline int valid_vcpu(int n) static inline int valid_vcpu(int n)
{ {
return likely(n >= 0 && n < KVM_MAX_VCPUS); return likely(n >= 0 && n < KVM_MAX_VCPUS);
...@@ -1862,6 +1891,19 @@ static long kvm_vm_ioctl(struct file *filp, ...@@ -1862,6 +1891,19 @@ static long kvm_vm_ioctl(struct file *filp,
goto out; goto out;
break; break;
} }
#endif
#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
case KVM_DEASSIGN_PCI_DEVICE: {
struct kvm_assigned_pci_dev assigned_dev;
r = -EFAULT;
if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
goto out;
r = kvm_vm_ioctl_deassign_device(kvm, &assigned_dev);
if (r)
goto out;
break;
}
#endif #endif
default: default:
r = kvm_arch_vm_ioctl(filp, ioctl, arg); r = kvm_arch_vm_ioctl(filp, ioctl, arg);
......
...@@ -116,6 +116,30 @@ int kvm_assign_device(struct kvm *kvm, ...@@ -116,6 +116,30 @@ int kvm_assign_device(struct kvm *kvm,
return 0; return 0;
} }
int kvm_deassign_device(struct kvm *kvm,
struct kvm_assigned_dev_kernel *assigned_dev)
{
struct dmar_domain *domain = kvm->arch.intel_iommu_domain;
struct pci_dev *pdev = NULL;
/* check if iommu exists and in use */
if (!domain)
return 0;
pdev = assigned_dev->dev;
if (pdev == NULL)
return -ENODEV;
intel_iommu_detach_device(domain, pdev);
printk(KERN_DEBUG "deassign device: host bdf = %x:%x:%x\n",
assigned_dev->host_busnr,
PCI_SLOT(assigned_dev->host_devfn),
PCI_FUNC(assigned_dev->host_devfn));
return 0;
}
int kvm_iommu_map_guest(struct kvm *kvm) int kvm_iommu_map_guest(struct kvm *kvm)
{ {
int r; int r;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment