iommu/vt-d: Make use of domain_alloc and domain_free
[firefly-linux-kernel-4.4.55.git] / drivers / iommu / intel-iommu.c
index 40dfbc0444c0eaccdeca8cebfcd5f567e3d84ae4..a312e4966686f55b6e8f7a3c3ff9baa829d7b86e 100644 (file)
@@ -71,6 +71,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))
@@ -336,7 +339,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 */
@@ -355,6 +358,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 */
@@ -446,6 +452,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)
@@ -485,7 +497,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)
 {
@@ -523,16 +534,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;
@@ -1643,7 +1644,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);
@@ -1701,7 +1703,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 */
@@ -3427,23 +3430,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;
@@ -3461,7 +3447,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;
 }
@@ -3470,8 +3456,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)
@@ -4342,7 +4327,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 */
@@ -4363,44 +4349,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;
@@ -4465,16 +4452,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;
@@ -4511,7 +4496,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;
@@ -4559,7 +4544,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;
@@ -4618,8 +4603,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,