diff options
| author | Sheng Yang <sheng@linux.intel.com> | 2009-04-27 08:35:43 -0400 |
|---|---|---|
| committer | Avi Kivity <avi@redhat.com> | 2009-06-10 04:48:50 -0400 |
| commit | 522c68c4416de3cd3e11a9ff10d58e776a69ae1e (patch) | |
| tree | 62940e35988f5e2a52df10276882ec64518ee369 /virt | |
| parent | 4b12f0de33a64dfc624b2480f55b674f7fa23ef2 (diff) | |
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, | |||
| 39 | pfn_t pfn; | 39 | pfn_t pfn; |
| 40 | int i, r = 0; | 40 | int i, r = 0; |
| 41 | struct iommu_domain *domain = kvm->arch.iommu_domain; | 41 | struct iommu_domain *domain = kvm->arch.iommu_domain; |
| 42 | int flags; | ||
| 42 | 43 | ||
| 43 | /* check if iommu exists and in use */ | 44 | /* check if iommu exists and in use */ |
| 44 | if (!domain) | 45 | if (!domain) |
| 45 | return 0; | 46 | return 0; |
| 46 | 47 | ||
| 48 | flags = IOMMU_READ | IOMMU_WRITE; | ||
| 49 | if (kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY) | ||
| 50 | flags |= IOMMU_CACHE; | ||
| 51 | |||
| 47 | for (i = 0; i < npages; i++) { | 52 | for (i = 0; i < npages; i++) { |
| 48 | /* check if already mapped */ | 53 | /* check if already mapped */ |
| 49 | if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn))) | 54 | if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn))) |
| @@ -53,8 +58,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, | |||
| 53 | r = iommu_map_range(domain, | 58 | r = iommu_map_range(domain, |
| 54 | gfn_to_gpa(gfn), | 59 | gfn_to_gpa(gfn), |
| 55 | pfn_to_hpa(pfn), | 60 | pfn_to_hpa(pfn), |
| 56 | PAGE_SIZE, | 61 | PAGE_SIZE, flags); |
| 57 | IOMMU_READ | IOMMU_WRITE); | ||
| 58 | if (r) { | 62 | if (r) { |
| 59 | printk(KERN_ERR "kvm_iommu_map_address:" | 63 | printk(KERN_ERR "kvm_iommu_map_address:" |
| 60 | "iommu failed to map pfn=%lx\n", pfn); | 64 | "iommu failed to map pfn=%lx\n", pfn); |
| @@ -88,7 +92,7 @@ int kvm_assign_device(struct kvm *kvm, | |||
| 88 | { | 92 | { |
| 89 | struct pci_dev *pdev = NULL; | 93 | struct pci_dev *pdev = NULL; |
| 90 | struct iommu_domain *domain = kvm->arch.iommu_domain; | 94 | struct iommu_domain *domain = kvm->arch.iommu_domain; |
| 91 | int r; | 95 | int r, last_flags; |
| 92 | 96 | ||
| 93 | /* check if iommu exists and in use */ | 97 | /* check if iommu exists and in use */ |
| 94 | if (!domain) | 98 | if (!domain) |
| @@ -107,12 +111,29 @@ int kvm_assign_device(struct kvm *kvm, | |||
| 107 | return r; | 111 | return r; |
| 108 | } | 112 | } |
| 109 | 113 | ||
| 114 | last_flags = kvm->arch.iommu_flags; | ||
| 115 | if (iommu_domain_has_cap(kvm->arch.iommu_domain, | ||
| 116 | IOMMU_CAP_CACHE_COHERENCY)) | ||
| 117 | kvm->arch.iommu_flags |= KVM_IOMMU_CACHE_COHERENCY; | ||
| 118 | |||
| 119 | /* Check if need to update IOMMU page table for guest memory */ | ||
| 120 | if ((last_flags ^ kvm->arch.iommu_flags) == | ||
| 121 | KVM_IOMMU_CACHE_COHERENCY) { | ||
| 122 | kvm_iommu_unmap_memslots(kvm); | ||
| 123 | r = kvm_iommu_map_memslots(kvm); | ||
| 124 | if (r) | ||
| 125 | goto out_unmap; | ||
| 126 | } | ||
| 127 | |||
| 110 | printk(KERN_DEBUG "assign device: host bdf = %x:%x:%x\n", | 128 | printk(KERN_DEBUG "assign device: host bdf = %x:%x:%x\n", |
| 111 | assigned_dev->host_busnr, | 129 | assigned_dev->host_busnr, |
| 112 | PCI_SLOT(assigned_dev->host_devfn), | 130 | PCI_SLOT(assigned_dev->host_devfn), |
| 113 | PCI_FUNC(assigned_dev->host_devfn)); | 131 | PCI_FUNC(assigned_dev->host_devfn)); |
| 114 | 132 | ||
| 115 | return 0; | 133 | return 0; |
| 134 | out_unmap: | ||
| 135 | kvm_iommu_unmap_memslots(kvm); | ||
| 136 | return r; | ||
| 116 | } | 137 | } |
| 117 | 138 | ||
| 118 | int kvm_deassign_device(struct kvm *kvm, | 139 | int kvm_deassign_device(struct kvm *kvm, |
