KVM: support device deassignment
Support device deassignment, it can be used in device hotplug. Signed-off-by: Weidong Han <weidong.han@intel.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
This commit is contained in:
parent
260782bcfd
commit
0a92035674
|
@ -334,6 +334,8 @@ int kvm_iommu_map_guest(struct kvm *kvm);
|
|||
int kvm_iommu_unmap_guest(struct kvm *kvm);
|
||||
int kvm_assign_device(struct kvm *kvm,
|
||||
struct kvm_assigned_dev_kernel *assigned_dev);
|
||||
int kvm_deassign_device(struct kvm *kvm,
|
||||
struct kvm_assigned_dev_kernel *assigned_dev);
|
||||
#else /* CONFIG_DMAR */
|
||||
static inline int kvm_iommu_map_pages(struct kvm *kvm,
|
||||
gfn_t base_gfn,
|
||||
|
@ -357,6 +359,12 @@ static inline int kvm_assign_device(struct kvm *kvm,
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kvm_deassign_device(struct kvm *kvm,
|
||||
struct kvm_assigned_dev_kernel *assigned_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DMAR */
|
||||
|
||||
static inline void kvm_guest_enter(void)
|
||||
|
|
|
@ -530,6 +530,35 @@ out_free:
|
|||
}
|
||||
#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)
|
||||
{
|
||||
return likely(n >= 0 && n < KVM_MAX_VCPUS);
|
||||
|
@ -1862,6 +1891,19 @@ static long kvm_vm_ioctl(struct file *filp,
|
|||
goto out;
|
||||
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
|
||||
default:
|
||||
r = kvm_arch_vm_ioctl(filp, ioctl, arg);
|
||||
|
|
|
@ -116,6 +116,30 @@ int kvm_assign_device(struct kvm *kvm,
|
|||
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 r;
|
||||
|
|
Loading…
Reference in New Issue