diff options
Diffstat (limited to 'drivers/iommu/intel-iommu.c')
-rw-r--r-- | drivers/iommu/intel-iommu.c | 115 |
1 files changed, 50 insertions, 65 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 3df27c5d18a6..68d43beccb7e 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -72,6 +72,9 @@ __DOMAIN_MAX_PFN(gaw), (unsigned long)-1)) #define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT) +/* IO virtual address start page frame number */ +#define IOVA_START_PFN (1) + #define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT) #define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32)) #define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64)) @@ -316,7 +319,7 @@ struct dmar_domain { DECLARE_BITMAP(iommu_bmp, DMAR_UNITS_SUPPORTED); /* bitmap of iommus this domain uses*/ - struct list_head devices; /* all devices' list */ + struct list_head devices; /* all devices' list */ struct iova_domain iovad; /* iova's that belong to this domain */ struct dma_pte *pgd; /* virtual address */ @@ -335,6 +338,9 @@ struct dmar_domain { 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */ spinlock_t iommu_lock; /* protect iommu set in domain */ u64 max_addr; /* maximum mapped address */ + + struct iommu_domain domain; /* generic domain data structure for + iommu core */ }; /* PCI domain-device relationship */ @@ -426,6 +432,12 @@ static LIST_HEAD(device_domain_list); static const struct iommu_ops intel_iommu_ops; +/* Convert generic 'struct iommu_domain to private struct dmar_domain */ +static struct dmar_domain *to_dmar_domain(struct iommu_domain *dom) +{ + return container_of(dom, struct dmar_domain, domain); +} + static int __init intel_iommu_setup(char *str) { if (!str) @@ -465,7 +477,6 @@ __setup("intel_iommu=", intel_iommu_setup); static struct kmem_cache *iommu_domain_cache; static struct kmem_cache *iommu_devinfo_cache; -static struct kmem_cache *iommu_iova_cache; static inline void *alloc_pgtable_page(int node) { @@ -503,16 +514,6 @@ static inline void free_devinfo_mem(void *vaddr) kmem_cache_free(iommu_devinfo_cache, vaddr); } -struct iova *alloc_iova_mem(void) -{ - return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC); -} - -void free_iova_mem(struct iova *iova) -{ - kmem_cache_free(iommu_iova_cache, iova); -} - static inline int domain_type_is_vm(struct dmar_domain *domain) { return domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE; @@ -583,12 +584,13 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain) { struct dmar_drhd_unit *drhd; struct intel_iommu *iommu; - int i, found = 0; + bool found = false; + int i; domain->iommu_coherency = 1; for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) { - found = 1; + found = true; if (!ecap_coherent(g_iommus[i]->ecap)) { domain->iommu_coherency = 0; break; @@ -706,7 +708,7 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf if (dev_is_pci(dev)) { pdev = to_pci_dev(dev); segment = pci_domain_nr(pdev->bus); - } else if (ACPI_COMPANION(dev)) + } else if (has_acpi_companion(dev)) dev = &ACPI_COMPANION(dev)->dev; rcu_read_lock(); @@ -1259,7 +1261,7 @@ static struct device_domain_info * iommu_support_dev_iotlb (struct dmar_domain *domain, struct intel_iommu *iommu, u8 bus, u8 devfn) { - int found = 0; + bool found = false; unsigned long flags; struct device_domain_info *info; struct pci_dev *pdev; @@ -1274,7 +1276,7 @@ iommu_support_dev_iotlb (struct dmar_domain *domain, struct intel_iommu *iommu, list_for_each_entry(info, &domain->devices, link) if (info->iommu == iommu && info->bus == bus && info->devfn == devfn) { - found = 1; + found = true; break; } spin_unlock_irqrestore(&device_domain_lock, flags); @@ -1627,7 +1629,8 @@ static int dmar_init_reserved_ranges(void) struct iova *iova; int i; - init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN); + init_iova_domain(&reserved_iova_list, VTD_PAGE_SIZE, IOVA_START_PFN, + DMA_32BIT_PFN); lockdep_set_class(&reserved_iova_list.iova_rbtree_lock, &reserved_rbtree_key); @@ -1685,7 +1688,8 @@ static int domain_init(struct dmar_domain *domain, int guest_width) int adjust_width, agaw; unsigned long sagaw; - init_iova_domain(&domain->iovad, DMA_32BIT_PFN); + init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN, + DMA_32BIT_PFN); domain_reserve_special_ranges(domain); /* calculate AGAW */ @@ -1732,9 +1736,8 @@ static int domain_init(struct dmar_domain *domain, int guest_width) static void domain_exit(struct dmar_domain *domain) { - struct dmar_drhd_unit *drhd; - struct intel_iommu *iommu; struct page *freelist = NULL; + int i; /* Domain 0 is reserved, so dont process it */ if (!domain) @@ -1754,8 +1757,8 @@ static void domain_exit(struct dmar_domain *domain) /* clear attached or cached domains */ rcu_read_lock(); - for_each_active_iommu(iommu, drhd) - iommu_detach_domain(domain, iommu); + for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) + iommu_detach_domain(domain, g_iommus[i]); rcu_read_unlock(); dma_free_pagelist(freelist); @@ -3417,23 +3420,6 @@ static inline int iommu_devinfo_cache_init(void) return ret; } -static inline int iommu_iova_cache_init(void) -{ - int ret = 0; - - iommu_iova_cache = kmem_cache_create("iommu_iova", - sizeof(struct iova), - 0, - SLAB_HWCACHE_ALIGN, - NULL); - if (!iommu_iova_cache) { - printk(KERN_ERR "Couldn't create iova cache\n"); - ret = -ENOMEM; - } - - return ret; -} - static int __init iommu_init_mempool(void) { int ret; @@ -3451,7 +3437,7 @@ static int __init iommu_init_mempool(void) kmem_cache_destroy(iommu_domain_cache); domain_error: - kmem_cache_destroy(iommu_iova_cache); + iommu_iova_cache_destroy(); return -ENOMEM; } @@ -3460,8 +3446,7 @@ static void __init iommu_exit_mempool(void) { kmem_cache_destroy(iommu_devinfo_cache); kmem_cache_destroy(iommu_domain_cache); - kmem_cache_destroy(iommu_iova_cache); - + iommu_iova_cache_destroy(); } static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev) @@ -4284,7 +4269,7 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain, struct device_domain_info *info, *tmp; struct intel_iommu *iommu; unsigned long flags; - int found = 0; + bool found = false; u8 bus, devfn; iommu = device_to_iommu(dev, &bus, &devfn); @@ -4316,7 +4301,7 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain, * update iommu count and coherency */ if (info->iommu == iommu) - found = 1; + found = true; } spin_unlock_irqrestore(&device_domain_lock, flags); @@ -4332,7 +4317,8 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width) { int adjust_width; - init_iova_domain(&domain->iovad, DMA_32BIT_PFN); + init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN, + DMA_32BIT_PFN); domain_reserve_special_ranges(domain); /* calculate AGAW */ @@ -4353,44 +4339,45 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width) return 0; } -static int intel_iommu_domain_init(struct iommu_domain *domain) +static struct iommu_domain *intel_iommu_domain_alloc(unsigned type) { struct dmar_domain *dmar_domain; + struct iommu_domain *domain; + + if (type != IOMMU_DOMAIN_UNMANAGED) + return NULL; dmar_domain = alloc_domain(DOMAIN_FLAG_VIRTUAL_MACHINE); if (!dmar_domain) { printk(KERN_ERR "intel_iommu_domain_init: dmar_domain == NULL\n"); - return -ENOMEM; + return NULL; } if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) { printk(KERN_ERR "intel_iommu_domain_init() failed\n"); domain_exit(dmar_domain); - return -ENOMEM; + return NULL; } domain_update_iommu_cap(dmar_domain); - domain->priv = dmar_domain; + domain = &dmar_domain->domain; domain->geometry.aperture_start = 0; domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw); domain->geometry.force_aperture = true; - return 0; + return domain; } -static void intel_iommu_domain_destroy(struct iommu_domain *domain) +static void intel_iommu_domain_free(struct iommu_domain *domain) { - struct dmar_domain *dmar_domain = domain->priv; - - domain->priv = NULL; - domain_exit(dmar_domain); + domain_exit(to_dmar_domain(domain)); } static int intel_iommu_attach_device(struct iommu_domain *domain, struct device *dev) { - struct dmar_domain *dmar_domain = domain->priv; + struct dmar_domain *dmar_domain = to_dmar_domain(domain); struct intel_iommu *iommu; int addr_width; u8 bus, devfn; @@ -4455,16 +4442,14 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, static void intel_iommu_detach_device(struct iommu_domain *domain, struct device *dev) { - struct dmar_domain *dmar_domain = domain->priv; - - domain_remove_one_dev_info(dmar_domain, dev); + domain_remove_one_dev_info(to_dmar_domain(domain), dev); } static int intel_iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t hpa, size_t size, int iommu_prot) { - struct dmar_domain *dmar_domain = domain->priv; + struct dmar_domain *dmar_domain = to_dmar_domain(domain); u64 max_addr; int prot = 0; int ret; @@ -4501,7 +4486,7 @@ static int intel_iommu_map(struct iommu_domain *domain, static size_t intel_iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) { - struct dmar_domain *dmar_domain = domain->priv; + struct dmar_domain *dmar_domain = to_dmar_domain(domain); struct page *freelist = NULL; struct intel_iommu *iommu; unsigned long start_pfn, last_pfn; @@ -4549,7 +4534,7 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain, static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) { - struct dmar_domain *dmar_domain = domain->priv; + struct dmar_domain *dmar_domain = to_dmar_domain(domain); struct dma_pte *pte; int level = 0; u64 phys = 0; @@ -4608,8 +4593,8 @@ static void intel_iommu_remove_device(struct device *dev) static const struct iommu_ops intel_iommu_ops = { .capable = intel_iommu_capable, - .domain_init = intel_iommu_domain_init, - .domain_destroy = intel_iommu_domain_destroy, + .domain_alloc = intel_iommu_domain_alloc, + .domain_free = intel_iommu_domain_free, .attach_dev = intel_iommu_attach_device, .detach_dev = intel_iommu_detach_device, .map = intel_iommu_map, |