diff options
| author | Sheng Yang <sheng@linux.intel.com> | 2009-04-27 20:35:43 +0800 | 
|---|---|---|
| committer | Avi Kivity <avi@redhat.com> | 2009-06-10 11:48:50 +0300 | 
| commit | 522c68c4416de3cd3e11a9ff10d58e776a69ae1e (patch) | |
| tree | 62940e35988f5e2a52df10276882ec64518ee369 /virt | |
| parent | 4b12f0de33a64dfc624b2480f55b674f7fa23ef2 (diff) | |
| download | linux-522c68c4416de3cd3e11a9ff10d58e776a69ae1e.tar.bz2 | |
KVM: Enable snooping control for supported hardware
Memory aliases with different memory type is a problem for guest. For the guest
without assigned device, the memory type of guest memory would always been the
same as host(WB); but for the assigned device, some part of memory may be used
as DMA and then set to uncacheable memory type(UC/WC), which would be a conflict of
host memory type then be a potential issue.
Snooping control can guarantee the cache correctness of memory go through the
DMA engine of VT-d.
[avi: fix build on ia64]
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'virt')
| -rw-r--r-- | virt/kvm/iommu.c | 27 | 
1 files changed, 24 insertions, 3 deletions
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index 4c4037503600..15147583abd1 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -39,11 +39,16 @@ int kvm_iommu_map_pages(struct kvm *kvm,  	pfn_t pfn;  	int i, r = 0;  	struct iommu_domain *domain = kvm->arch.iommu_domain; +	int flags;  	/* check if iommu exists and in use */  	if (!domain)  		return 0; +	flags = IOMMU_READ | IOMMU_WRITE; +	if (kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY) +		flags |= IOMMU_CACHE; +  	for (i = 0; i < npages; i++) {  		/* check if already mapped */  		if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn))) @@ -53,8 +58,7 @@ int kvm_iommu_map_pages(struct kvm *kvm,  		r = iommu_map_range(domain,  				    gfn_to_gpa(gfn),  				    pfn_to_hpa(pfn), -				    PAGE_SIZE, -				    IOMMU_READ | IOMMU_WRITE); +				    PAGE_SIZE, flags);  		if (r) {  			printk(KERN_ERR "kvm_iommu_map_address:"  			       "iommu failed to map pfn=%lx\n", pfn); @@ -88,7 +92,7 @@ int kvm_assign_device(struct kvm *kvm,  {  	struct pci_dev *pdev = NULL;  	struct iommu_domain *domain = kvm->arch.iommu_domain; -	int r; +	int r, last_flags;  	/* check if iommu exists and in use */  	if (!domain) @@ -107,12 +111,29 @@ int kvm_assign_device(struct kvm *kvm,  		return r;  	} +	last_flags = kvm->arch.iommu_flags; +	if (iommu_domain_has_cap(kvm->arch.iommu_domain, +				 IOMMU_CAP_CACHE_COHERENCY)) +		kvm->arch.iommu_flags |= KVM_IOMMU_CACHE_COHERENCY; + +	/* Check if need to update IOMMU page table for guest memory */ +	if ((last_flags ^ kvm->arch.iommu_flags) == +			KVM_IOMMU_CACHE_COHERENCY) { +		kvm_iommu_unmap_memslots(kvm); +		r = kvm_iommu_map_memslots(kvm); +		if (r) +			goto out_unmap; +	} +  	printk(KERN_DEBUG "assign 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; +out_unmap: +	kvm_iommu_unmap_memslots(kvm); +	return r;  }  int kvm_deassign_device(struct kvm *kvm,  |