Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.29-rc1 214 lines 4.9 kB view raw
1/* 2 * Copyright (c) 2006, Intel Corporation. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 15 * Place - Suite 330, Boston, MA 02111-1307 USA. 16 * 17 * Copyright (C) 2006-2008 Intel Corporation 18 * Copyright IBM Corporation, 2008 19 * Author: Allen M. Kay <allen.m.kay@intel.com> 20 * Author: Weidong Han <weidong.han@intel.com> 21 * Author: Ben-Ami Yassour <benami@il.ibm.com> 22 */ 23 24#include <linux/list.h> 25#include <linux/kvm_host.h> 26#include <linux/pci.h> 27#include <linux/dmar.h> 28#include <linux/iommu.h> 29#include <linux/intel-iommu.h> 30 31static int kvm_iommu_unmap_memslots(struct kvm *kvm); 32static void kvm_iommu_put_pages(struct kvm *kvm, 33 gfn_t base_gfn, unsigned long npages); 34 35int kvm_iommu_map_pages(struct kvm *kvm, 36 gfn_t base_gfn, unsigned long npages) 37{ 38 gfn_t gfn = base_gfn; 39 pfn_t pfn; 40 int i, r = 0; 41 struct iommu_domain *domain = kvm->arch.iommu_domain; 42 43 /* check if iommu exists and in use */ 44 if (!domain) 45 return 0; 46 47 for (i = 0; i < npages; i++) { 48 /* check if already mapped */ 49 if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn))) 50 continue; 51 52 pfn = gfn_to_pfn(kvm, gfn); 53 r = iommu_map_range(domain, 54 gfn_to_gpa(gfn), 55 pfn_to_hpa(pfn), 56 PAGE_SIZE, 57 IOMMU_READ | IOMMU_WRITE); 58 if (r) { 59 printk(KERN_ERR "kvm_iommu_map_address:" 60 "iommu failed to map pfn=%lx\n", pfn); 61 goto unmap_pages; 62 } 63 gfn++; 64 } 65 return 0; 66 67unmap_pages: 68 kvm_iommu_put_pages(kvm, base_gfn, i); 69 return r; 70} 71 72static int kvm_iommu_map_memslots(struct kvm *kvm) 73{ 74 int i, r = 0; 75 76 down_read(&kvm->slots_lock); 77 for (i = 0; i < kvm->nmemslots; i++) { 78 r = kvm_iommu_map_pages(kvm, kvm->memslots[i].base_gfn, 79 kvm->memslots[i].npages); 80 if (r) 81 break; 82 } 83 up_read(&kvm->slots_lock); 84 return r; 85} 86 87int kvm_assign_device(struct kvm *kvm, 88 struct kvm_assigned_dev_kernel *assigned_dev) 89{ 90 struct pci_dev *pdev = NULL; 91 struct iommu_domain *domain = kvm->arch.iommu_domain; 92 int r; 93 94 /* check if iommu exists and in use */ 95 if (!domain) 96 return 0; 97 98 pdev = assigned_dev->dev; 99 if (pdev == NULL) 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; 109 } 110 111 printk(KERN_DEBUG "assign device: host bdf = %x:%x:%x\n", 112 assigned_dev->host_busnr, 113 PCI_SLOT(assigned_dev->host_devfn), 114 PCI_FUNC(assigned_dev->host_devfn)); 115 116 return 0; 117} 118 119int 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; 128 129 pdev = assigned_dev->dev; 130 if (pdev == NULL) 131 return -ENODEV; 132 133 iommu_detach_device(domain, &pdev->dev); 134 135 printk(KERN_DEBUG "deassign device: host bdf = %x:%x:%x\n", 136 assigned_dev->host_busnr, 137 PCI_SLOT(assigned_dev->host_devfn), 138 PCI_FUNC(assigned_dev->host_devfn)); 139 140 return 0; 141} 142 143int 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__); 149 return -ENODEV; 150 } 151 152 kvm->arch.iommu_domain = iommu_domain_alloc(); 153 if (!kvm->arch.iommu_domain) 154 return -ENOMEM; 155 156 r = kvm_iommu_map_memslots(kvm); 157 if (r) 158 goto out_unmap; 159 160 return 0; 161 162out_unmap: 163 kvm_iommu_unmap_memslots(kvm); 164 return r; 165} 166 167static void kvm_iommu_put_pages(struct kvm *kvm, 168 gfn_t base_gfn, unsigned long npages) 169{ 170 gfn_t gfn = base_gfn; 171 pfn_t pfn; 172 struct iommu_domain *domain = kvm->arch.iommu_domain; 173 unsigned long i; 174 u64 phys; 175 176 /* check if iommu exists and in use */ 177 if (!domain) 178 return; 179 180 for (i = 0; i < npages; i++) { 181 phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn)); 182 pfn = phys >> PAGE_SHIFT; 183 kvm_release_pfn_clean(pfn); 184 gfn++; 185 } 186 187 iommu_unmap_range(domain, gfn_to_gpa(base_gfn), PAGE_SIZE * npages); 188} 189 190static int kvm_iommu_unmap_memslots(struct kvm *kvm) 191{ 192 int i; 193 down_read(&kvm->slots_lock); 194 for (i = 0; i < kvm->nmemslots; i++) { 195 kvm_iommu_put_pages(kvm, kvm->memslots[i].base_gfn, 196 kvm->memslots[i].npages); 197 } 198 up_read(&kvm->slots_lock); 199 200 return 0; 201} 202 203int kvm_iommu_unmap_guest(struct kvm *kvm) 204{ 205 struct iommu_domain *domain = kvm->arch.iommu_domain; 206 207 /* check if iommu exists and in use */ 208 if (!domain) 209 return 0; 210 211 kvm_iommu_unmap_memslots(kvm); 212 iommu_domain_free(domain); 213 return 0; 214}