diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-01-04 04:59:36 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-01-04 04:59:36 -0500 |
commit | 4010b0192ddf6ec7ec1b9feb9b0953692aeb7329 (patch) | |
tree | 188a36186f6ce580b479a9f90404fa7bfd8b22d7 /virt | |
parent | 79ff56ebd3edfb16f8badc558cb439b203a3298f (diff) | |
parent | 7d3b56ba37a95f1f370f50258ed3954c304c524b (diff) |
Merge branch 'linus' into core/urgent
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/iommu.c (renamed from virt/kvm/vtd.c) | 135 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 50 |
2 files changed, 128 insertions, 57 deletions
diff --git a/virt/kvm/vtd.c b/virt/kvm/iommu.c index a770874f3a3a..e9693a29d00e 100644 --- a/virt/kvm/vtd.c +++ b/virt/kvm/iommu.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/kvm_host.h> | 25 | #include <linux/kvm_host.h> |
26 | #include <linux/pci.h> | 26 | #include <linux/pci.h> |
27 | #include <linux/dmar.h> | 27 | #include <linux/dmar.h> |
28 | #include <linux/iommu.h> | ||
28 | #include <linux/intel-iommu.h> | 29 | #include <linux/intel-iommu.h> |
29 | 30 | ||
30 | static int kvm_iommu_unmap_memslots(struct kvm *kvm); | 31 | static int kvm_iommu_unmap_memslots(struct kvm *kvm); |
@@ -37,7 +38,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, | |||
37 | gfn_t gfn = base_gfn; | 38 | gfn_t gfn = base_gfn; |
38 | pfn_t pfn; | 39 | pfn_t pfn; |
39 | int i, r = 0; | 40 | int i, r = 0; |
40 | struct dmar_domain *domain = kvm->arch.intel_iommu_domain; | 41 | struct iommu_domain *domain = kvm->arch.iommu_domain; |
41 | 42 | ||
42 | /* check if iommu exists and in use */ | 43 | /* check if iommu exists and in use */ |
43 | if (!domain) | 44 | if (!domain) |
@@ -45,20 +46,17 @@ int kvm_iommu_map_pages(struct kvm *kvm, | |||
45 | 46 | ||
46 | for (i = 0; i < npages; i++) { | 47 | for (i = 0; i < npages; i++) { |
47 | /* check if already mapped */ | 48 | /* check if already mapped */ |
48 | pfn = (pfn_t)intel_iommu_iova_to_pfn(domain, | 49 | if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn))) |
49 | gfn_to_gpa(gfn)); | ||
50 | if (pfn) | ||
51 | continue; | 50 | continue; |
52 | 51 | ||
53 | pfn = gfn_to_pfn(kvm, gfn); | 52 | pfn = gfn_to_pfn(kvm, gfn); |
54 | r = intel_iommu_page_mapping(domain, | 53 | r = iommu_map_range(domain, |
55 | gfn_to_gpa(gfn), | 54 | gfn_to_gpa(gfn), |
56 | pfn_to_hpa(pfn), | 55 | pfn_to_hpa(pfn), |
57 | PAGE_SIZE, | 56 | PAGE_SIZE, |
58 | DMA_PTE_READ | | 57 | IOMMU_READ | IOMMU_WRITE); |
59 | DMA_PTE_WRITE); | ||
60 | if (r) { | 58 | if (r) { |
61 | printk(KERN_ERR "kvm_iommu_map_pages:" | 59 | printk(KERN_ERR "kvm_iommu_map_address:" |
62 | "iommu failed to map pfn=%lx\n", pfn); | 60 | "iommu failed to map pfn=%lx\n", pfn); |
63 | goto unmap_pages; | 61 | goto unmap_pages; |
64 | } | 62 | } |
@@ -73,7 +71,7 @@ unmap_pages: | |||
73 | 71 | ||
74 | static int kvm_iommu_map_memslots(struct kvm *kvm) | 72 | static int kvm_iommu_map_memslots(struct kvm *kvm) |
75 | { | 73 | { |
76 | int i, r; | 74 | int i, r = 0; |
77 | 75 | ||
78 | down_read(&kvm->slots_lock); | 76 | down_read(&kvm->slots_lock); |
79 | for (i = 0; i < kvm->nmemslots; i++) { | 77 | for (i = 0; i < kvm->nmemslots; i++) { |
@@ -86,50 +84,79 @@ static int kvm_iommu_map_memslots(struct kvm *kvm) | |||
86 | return r; | 84 | return r; |
87 | } | 85 | } |
88 | 86 | ||
89 | int kvm_iommu_map_guest(struct kvm *kvm, | 87 | int kvm_assign_device(struct kvm *kvm, |
90 | struct kvm_assigned_dev_kernel *assigned_dev) | 88 | struct kvm_assigned_dev_kernel *assigned_dev) |
91 | { | 89 | { |
92 | struct pci_dev *pdev = NULL; | 90 | struct pci_dev *pdev = NULL; |
91 | struct iommu_domain *domain = kvm->arch.iommu_domain; | ||
93 | int r; | 92 | int r; |
94 | 93 | ||
95 | if (!intel_iommu_found()) { | 94 | /* check if iommu exists and in use */ |
96 | printk(KERN_ERR "%s: intel iommu not found\n", __func__); | 95 | if (!domain) |
96 | return 0; | ||
97 | |||
98 | pdev = assigned_dev->dev; | ||
99 | if (pdev == NULL) | ||
97 | return -ENODEV; | 100 | return -ENODEV; |
101 | |||
102 | r = iommu_attach_device(domain, &pdev->dev); | ||
103 | if (r) { | ||
104 | printk(KERN_ERR "assign device %x:%x.%x failed", | ||
105 | pdev->bus->number, | ||
106 | PCI_SLOT(pdev->devfn), | ||
107 | PCI_FUNC(pdev->devfn)); | ||
108 | return r; | ||
98 | } | 109 | } |
99 | 110 | ||
100 | printk(KERN_DEBUG "VT-d direct map: host bdf = %x:%x:%x\n", | 111 | printk(KERN_DEBUG "assign device: host bdf = %x:%x:%x\n", |
101 | assigned_dev->host_busnr, | 112 | assigned_dev->host_busnr, |
102 | PCI_SLOT(assigned_dev->host_devfn), | 113 | PCI_SLOT(assigned_dev->host_devfn), |
103 | PCI_FUNC(assigned_dev->host_devfn)); | 114 | PCI_FUNC(assigned_dev->host_devfn)); |
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | int kvm_deassign_device(struct kvm *kvm, | ||
120 | struct kvm_assigned_dev_kernel *assigned_dev) | ||
121 | { | ||
122 | struct iommu_domain *domain = kvm->arch.iommu_domain; | ||
123 | struct pci_dev *pdev = NULL; | ||
124 | |||
125 | /* check if iommu exists and in use */ | ||
126 | if (!domain) | ||
127 | return 0; | ||
104 | 128 | ||
105 | pdev = assigned_dev->dev; | 129 | pdev = assigned_dev->dev; |
130 | if (pdev == NULL) | ||
131 | return -ENODEV; | ||
106 | 132 | ||
107 | if (pdev == NULL) { | 133 | iommu_detach_device(domain, &pdev->dev); |
108 | if (kvm->arch.intel_iommu_domain) { | 134 | |
109 | intel_iommu_domain_exit(kvm->arch.intel_iommu_domain); | 135 | printk(KERN_DEBUG "deassign device: host bdf = %x:%x:%x\n", |
110 | kvm->arch.intel_iommu_domain = NULL; | 136 | assigned_dev->host_busnr, |
111 | } | 137 | PCI_SLOT(assigned_dev->host_devfn), |
138 | PCI_FUNC(assigned_dev->host_devfn)); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | int kvm_iommu_map_guest(struct kvm *kvm) | ||
144 | { | ||
145 | int r; | ||
146 | |||
147 | if (!iommu_found()) { | ||
148 | printk(KERN_ERR "%s: iommu not found\n", __func__); | ||
112 | return -ENODEV; | 149 | return -ENODEV; |
113 | } | 150 | } |
114 | 151 | ||
115 | kvm->arch.intel_iommu_domain = intel_iommu_domain_alloc(pdev); | 152 | kvm->arch.iommu_domain = iommu_domain_alloc(); |
116 | if (!kvm->arch.intel_iommu_domain) | 153 | if (!kvm->arch.iommu_domain) |
117 | return -ENODEV; | 154 | return -ENOMEM; |
118 | 155 | ||
119 | r = kvm_iommu_map_memslots(kvm); | 156 | r = kvm_iommu_map_memslots(kvm); |
120 | if (r) | 157 | if (r) |
121 | goto out_unmap; | 158 | goto out_unmap; |
122 | 159 | ||
123 | intel_iommu_detach_dev(kvm->arch.intel_iommu_domain, | ||
124 | pdev->bus->number, pdev->devfn); | ||
125 | |||
126 | r = intel_iommu_context_mapping(kvm->arch.intel_iommu_domain, | ||
127 | pdev); | ||
128 | if (r) { | ||
129 | printk(KERN_ERR "Domain context map for %s failed", | ||
130 | pci_name(pdev)); | ||
131 | goto out_unmap; | ||
132 | } | ||
133 | return 0; | 160 | return 0; |
134 | 161 | ||
135 | out_unmap: | 162 | out_unmap: |
@@ -138,19 +165,26 @@ out_unmap: | |||
138 | } | 165 | } |
139 | 166 | ||
140 | static void kvm_iommu_put_pages(struct kvm *kvm, | 167 | static void kvm_iommu_put_pages(struct kvm *kvm, |
141 | gfn_t base_gfn, unsigned long npages) | 168 | gfn_t base_gfn, unsigned long npages) |
142 | { | 169 | { |
143 | gfn_t gfn = base_gfn; | 170 | gfn_t gfn = base_gfn; |
144 | pfn_t pfn; | 171 | pfn_t pfn; |
145 | struct dmar_domain *domain = kvm->arch.intel_iommu_domain; | 172 | struct iommu_domain *domain = kvm->arch.iommu_domain; |
146 | int i; | 173 | unsigned long i; |
174 | u64 phys; | ||
175 | |||
176 | /* check if iommu exists and in use */ | ||
177 | if (!domain) | ||
178 | return; | ||
147 | 179 | ||
148 | for (i = 0; i < npages; i++) { | 180 | for (i = 0; i < npages; i++) { |
149 | pfn = (pfn_t)intel_iommu_iova_to_pfn(domain, | 181 | phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn)); |
150 | gfn_to_gpa(gfn)); | 182 | pfn = phys >> PAGE_SHIFT; |
151 | kvm_release_pfn_clean(pfn); | 183 | kvm_release_pfn_clean(pfn); |
152 | gfn++; | 184 | gfn++; |
153 | } | 185 | } |
186 | |||
187 | iommu_unmap_range(domain, gfn_to_gpa(base_gfn), PAGE_SIZE * npages); | ||
154 | } | 188 | } |
155 | 189 | ||
156 | static int kvm_iommu_unmap_memslots(struct kvm *kvm) | 190 | static int kvm_iommu_unmap_memslots(struct kvm *kvm) |
@@ -168,24 +202,13 @@ static int kvm_iommu_unmap_memslots(struct kvm *kvm) | |||
168 | 202 | ||
169 | int kvm_iommu_unmap_guest(struct kvm *kvm) | 203 | int kvm_iommu_unmap_guest(struct kvm *kvm) |
170 | { | 204 | { |
171 | struct kvm_assigned_dev_kernel *entry; | 205 | struct iommu_domain *domain = kvm->arch.iommu_domain; |
172 | struct dmar_domain *domain = kvm->arch.intel_iommu_domain; | ||
173 | 206 | ||
174 | /* check if iommu exists and in use */ | 207 | /* check if iommu exists and in use */ |
175 | if (!domain) | 208 | if (!domain) |
176 | return 0; | 209 | return 0; |
177 | 210 | ||
178 | list_for_each_entry(entry, &kvm->arch.assigned_dev_head, list) { | ||
179 | printk(KERN_DEBUG "VT-d unmap: host bdf = %x:%x:%x\n", | ||
180 | entry->host_busnr, | ||
181 | PCI_SLOT(entry->host_devfn), | ||
182 | PCI_FUNC(entry->host_devfn)); | ||
183 | |||
184 | /* detach kvm dmar domain */ | ||
185 | intel_iommu_detach_dev(domain, entry->host_busnr, | ||
186 | entry->host_devfn); | ||
187 | } | ||
188 | kvm_iommu_unmap_memslots(kvm); | 211 | kvm_iommu_unmap_memslots(kvm); |
189 | intel_iommu_domain_exit(domain); | 212 | iommu_domain_free(domain); |
190 | return 0; | 213 | return 0; |
191 | } | 214 | } |
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 | } |