diff --git a/drivers/gpu/drm/hisilicon/kirin960/kirin_drm_dss.c b/drivers/gpu/drm/hisilicon/kirin960/kirin_drm_dss.c index 123bf782a886..27b16307ef89 100755 --- a/drivers/gpu/drm/hisilicon/kirin960/kirin_drm_dss.c +++ b/drivers/gpu/drm/hisilicon/kirin960/kirin_drm_dss.c @@ -678,14 +678,12 @@ static int dss_enable_iommu(struct platform_device *pdev, struct dss_hw_ctx *ctx dev = &pdev->dev; /* create iommu domain */ - ctx->mmu_domain = iommu_domain_alloc(dev->bus); + ctx->mmu_domain = hisi_ion_enable_iommu(NULL); if (!ctx->mmu_domain) { pr_err("iommu_domain_alloc failed!\n"); return -EINVAL; } - iommu_attach_device(ctx->mmu_domain, dev); - return 0; } diff --git a/drivers/iommu/hisi_smmu.h b/drivers/iommu/hisi_smmu.h index 4637244dba6b..f4bbf5c54553 100644 --- a/drivers/iommu/hisi_smmu.h +++ b/drivers/iommu/hisi_smmu.h @@ -1,5 +1,6 @@ #ifndef HISI_SMMU_H #define HISI_SMMU_H +#include /*#define IOMMU_DEBUG*/ #ifdef IOMMU_DEBUG @@ -80,15 +81,19 @@ typedef u64 smmu_pgd_t; typedef u64 smmu_pmd_t; typedef u64 smmu_pte_t; +struct hisi_domain { + spinlock_t lock; + struct list_head list; + smmu_pgd_t *va_pgtable_addr; + smmu_pgd_t *va_pgtable_addr_orig; + phys_addr_t pa_pgtable_addr; + struct iommu_domain domain; +}; + /*smmu device object*/ struct hisi_smmu_device_lpae { struct device *dev ; struct list_head domain_list; - unsigned int ref_count; - spinlock_t lock; - unsigned long va_pgtable_addr; - phys_addr_t smmu_phy_pgtable_addr; - smmu_pgd_t *smmu_pgd; }; struct hisi_map_tile_position_lpae { diff --git a/drivers/iommu/hisi_smmu_lpae.c b/drivers/iommu/hisi_smmu_lpae.c index 0ccd5c9ffeb1..fb3150276980 100644 --- a/drivers/iommu/hisi_smmu_lpae.c +++ b/drivers/iommu/hisi_smmu_lpae.c @@ -31,6 +31,11 @@ struct hisi_smmu_device_lpae *hisi_smmu_dev; +static struct hisi_domain *to_hisi_domain(struct iommu_domain *dom) +{ + return container_of(dom, struct hisi_domain, domain); +} + /*transfer 64bit pte table pointer to struct page*/ static pgtable_t smmu_pgd_to_pte_lpae(unsigned int ppte_table) { @@ -57,41 +62,40 @@ static pgtable_t smmu_pmd_to_pte_lpae(unsigned long ppte_table) return table; } -static int get_domain_data_lpae(struct device_node *np, - struct iommu_domain_data *data) +int of_get_iova_info(struct device_node *np, unsigned long *iova_start, + unsigned long *iova_size, unsigned long *iova_align) { - unsigned long long align; - struct device_node *node = NULL; + struct device_node *node; int ret = 0; - data->phy_pgd_base = hisi_smmu_dev->smmu_phy_pgtable_addr; - if (np) { - node = of_find_node_by_name(np, "iommu_info"); - if (!node) { - dbg("find iommu_info node error\n"); - return -ENODEV; - } - ret = of_property_read_u32(node, "start-addr", - &data->iova_start); - if (ret) { - dbg("read iova start address error\n"); - goto read_error; - } - ret = of_property_read_u32(node, "size", &data->iova_size); - if (ret) { - dbg("read iova size error\n"); - goto read_error; - } - ret = of_property_read_u64(node, "iova-align", &align); - if (!ret) - data->iova_align = (unsigned long)align; - else - data->iova_align = SZ_256K; + if (!np) + return -ENODEV; - pr_err("%s:start_addr 0x%x, size 0x%x align 0x%lx\n", - __func__, data->iova_start, - data->iova_size, data->iova_align); + node = of_find_node_by_name(np, "iommu_info"); + if (!node) { + pr_err("find iommu_info node error\n"); + return -ENODEV; } + ret = of_property_read_u32(node, "start-addr", + (u32 *)iova_start); + if (ret) { + pr_err("read iova start address error\n"); + ret = -EINVAL; + goto read_error; + } + ret = of_property_read_u32(node, "size", (u32 *)iova_size); + if (ret) { + pr_err("read iova size error\n"); + ret = -EINVAL; + goto read_error; + } + ret = of_property_read_u64(node, "iova-align", (u64 *)iova_align); + if (ret) + *iova_align = SZ_256K; + + pr_err("%s:start_addr 0x%lx, size 0x%lx align 0x%lx\n", + __func__, *iova_start, *iova_size, + *iova_align); return 0; @@ -102,18 +106,32 @@ read_error: static struct iommu_domain *hisi_smmu_domain_alloc_lpae(unsigned iommu_domain_type) { - struct iommu_domain *domain; + struct hisi_domain *hisi_domain; if (iommu_domain_type != IOMMU_DOMAIN_UNMANAGED) return NULL; - domain = kzalloc(sizeof(*domain), GFP_KERNEL); - if (!domain) { - pr_err("%s: fail to kzalloc %lu bytes\n", - __func__, sizeof(*domain)); - } + hisi_domain = kzalloc(sizeof(*hisi_domain), GFP_KERNEL); + if (!hisi_domain) + return NULL; - return domain; + hisi_domain->va_pgtable_addr_orig = (smmu_pgd_t *)kzalloc(SZ_64, GFP_KERNEL | __GFP_DMA); + if (!hisi_domain->va_pgtable_addr_orig) + goto err_smmu_pgd; + + hisi_domain->va_pgtable_addr = (smmu_pgd_t *)(ALIGN((unsigned long) + (hisi_domain->va_pgtable_addr_orig), SZ_32)); + + hisi_domain->pa_pgtable_addr = virt_to_phys(hisi_domain->va_pgtable_addr); + spin_lock_init(&hisi_domain->lock); + + list_add(&hisi_domain->list, &hisi_smmu_dev->domain_list); + + return &hisi_domain->domain; + +err_smmu_pgd: + kfree(hisi_domain); + return NULL; } @@ -147,17 +165,19 @@ static void hisi_smmu_free_pmds_lpae(smmu_pgd_t pgd) smmu_set_pgd_lpae(&pgd, 0); } -static void hisi_smmu_free_pgtables_lpae(unsigned long *page_table_addr) +static void hisi_smmu_free_pgtables_lpae(struct iommu_domain *domain, + unsigned long *page_table_addr) { int i, j; smmu_pgd_t *pgd; smmu_pmd_t *pmd; unsigned long flags; + struct hisi_domain *hisi_domain = to_hisi_domain(domain); pgd = (smmu_pgd_t *)page_table_addr; pmd = (smmu_pmd_t *)page_table_addr; - spin_lock_irqsave(&hisi_smmu_dev->lock, flags); + spin_lock_irqsave(&hisi_domain->lock, flags); for (i = 0; i < SMMU_PTRS_PER_PGD; ++i) { if ((smmu_pgd_none_lpae(*pgd)) & (smmu_pmd_none_lpae(*pmd))) continue; @@ -169,38 +189,39 @@ static void hisi_smmu_free_pgtables_lpae(unsigned long *page_table_addr) pgd++; } memset((void *)page_table_addr, 0, PAGE_SIZE); - spin_unlock_irqrestore(&hisi_smmu_dev->lock, flags); + spin_unlock_irqrestore(&hisi_domain->lock, flags); } static void hisi_smmu_domain_free_lpae(struct iommu_domain *domain) { - if (list_empty(&hisi_smmu_dev->domain_list)) - hisi_smmu_free_pgtables_lpae((unsigned long *) - hisi_smmu_dev->va_pgtable_addr); - - kfree(domain); + struct hisi_domain *hisi_domain = to_hisi_domain(domain); + hisi_smmu_free_pgtables_lpae(domain, (unsigned long *) + hisi_domain->va_pgtable_addr); + list_del(&hisi_domain->list); + kfree(hisi_domain->va_pgtable_addr_orig); + kfree(hisi_domain); } -static int hisi_smmu_alloc_init_pte_lpae(smmu_pmd_t *ppmd, - unsigned long addr, unsigned long end, +static int hisi_smmu_alloc_init_pte_lpae(struct iommu_domain *domain, + smmu_pmd_t *ppmd, unsigned long addr, unsigned long end, unsigned long pfn, u64 prot, unsigned long *flags) { smmu_pte_t *pte, *start; pgtable_t table; u64 pteval = SMMU_PTE_TYPE; + struct hisi_domain *hisi_domain = to_hisi_domain(domain); if (!smmu_pmd_none_lpae(*ppmd)) goto pte_ready; /* Allocate a new set of tables */ - spin_unlock_irqrestore(&hisi_smmu_dev->lock, *flags); table = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_DMA); - spin_lock_irqsave(&hisi_smmu_dev->lock, *flags); if (!table) { dbg("%s: alloc page fail\n", __func__); return -ENOMEM; } + spin_lock_irqsave(&hisi_domain->lock, *flags); if (smmu_pmd_none_lpae(*ppmd)) { hisi_smmu_flush_pgtable_lpae(page_address(table), @@ -209,6 +230,7 @@ static int hisi_smmu_alloc_init_pte_lpae(smmu_pmd_t *ppmd, hisi_smmu_flush_pgtable_lpae(ppmd, sizeof(*ppmd)); } else __free_page(table); + spin_unlock_irqrestore(&hisi_domain->lock, *flags); pte_ready: if (prot & IOMMU_SEC) @@ -261,27 +283,26 @@ pte_ready: return 0; } -static int hisi_smmu_alloc_init_pmd_lpae(smmu_pgd_t *ppgd, - unsigned long addr, unsigned long end, +static int hisi_smmu_alloc_init_pmd_lpae(struct iommu_domain *domain, + smmu_pgd_t *ppgd, unsigned long addr, unsigned long end, unsigned long paddr, int prot, unsigned long *flags) { int ret = 0; smmu_pmd_t *ppmd, *start; u64 next; pgtable_t table; + struct hisi_domain *hisi_domain = to_hisi_domain(domain); if (!smmu_pgd_none_lpae(*ppgd)) goto pmd_ready; /* Allocate a new set of tables */ - spin_unlock_irqrestore(&hisi_smmu_dev->lock, *flags); table = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_DMA); - spin_lock_irqsave(&hisi_smmu_dev->lock, *flags); if (!table) { dbg("%s: alloc page fail\n", __func__); return -ENOMEM; } - + spin_lock_irqsave(&hisi_domain->lock, *flags); if (smmu_pgd_none_lpae(*ppgd)) { hisi_smmu_flush_pgtable_lpae(page_address(table), SMMU_PAGE_SIZE); @@ -289,6 +310,7 @@ static int hisi_smmu_alloc_init_pmd_lpae(smmu_pgd_t *ppgd, hisi_smmu_flush_pgtable_lpae(ppgd, sizeof(*ppgd)); } else __free_page(table); + spin_unlock_irqrestore(&hisi_domain->lock, *flags); pmd_ready: if (prot & IOMMU_SEC) @@ -299,7 +321,7 @@ pmd_ready: do { next = smmu_pmd_addr_end_lpae(addr, end); - ret = hisi_smmu_alloc_init_pte_lpae(ppmd, + ret = hisi_smmu_alloc_init_pte_lpae(domain, ppmd, addr, next, __phys_to_pfn(paddr), prot, flags); if (ret) goto error; @@ -318,7 +340,9 @@ int hisi_smmu_handle_mapping_lpae(struct iommu_domain *domain, unsigned long end; unsigned long next; unsigned long flags; - smmu_pgd_t *pgd = (smmu_pgd_t *)hisi_smmu_dev->va_pgtable_addr; + + struct hisi_domain *hisi_domain = to_hisi_domain(domain); + smmu_pgd_t *pgd = (smmu_pgd_t *)hisi_domain->va_pgtable_addr; if (!pgd) { dbg("pgd is null\n"); @@ -326,12 +350,11 @@ int hisi_smmu_handle_mapping_lpae(struct iommu_domain *domain, } iova = ALIGN(iova, SMMU_PAGE_SIZE); size = ALIGN(size, SMMU_PAGE_SIZE); - spin_lock_irqsave(&hisi_smmu_dev->lock, flags); pgd += smmu_pgd_index(iova); end = iova + size; do { next = smmu_pgd_addr_end_lpae(iova, end); - ret = hisi_smmu_alloc_init_pmd_lpae(pgd, + ret = hisi_smmu_alloc_init_pmd_lpae(domain, pgd, iova, next, paddr, prot, &flags); if (ret) goto out_unlock; @@ -339,7 +362,6 @@ int hisi_smmu_handle_mapping_lpae(struct iommu_domain *domain, iova = next; } while (pgd++, iova < end); out_unlock: - spin_unlock_irqrestore(&hisi_smmu_dev->lock, flags); return ret; } @@ -348,29 +370,15 @@ static int hisi_smmu_map_lpae(struct iommu_domain *domain, phys_addr_t paddr, size_t size, int prot) { - unsigned long max_iova; struct iommu_domain_data *data; if (!domain) { dbg("domain is null\n"); + data = NULL; return -ENODEV; } data = domain->priv; - max_iova = data->iova_start + data->iova_size; - if (iova < data->iova_start) { - dbg("iova failed: iova = 0x%lx, start = 0x%8x\n", - iova, data->iova_start); - goto error; - } - if ((iova+size) > max_iova) { - dbg("iova out of domain range, iova+size=0x%lx, end=0x%lx\n", - iova+size, max_iova); - goto error; - } return hisi_smmu_handle_mapping_lpae(domain, iova, paddr, size, prot); -error: - dbg("iova is not in this range\n"); - return -EINVAL; } static unsigned int hisi_smmu_clear_pte_lpae(smmu_pgd_t *pmdp, @@ -416,59 +424,42 @@ unsigned int hisi_smmu_handle_unmapping_lpae(struct iommu_domain *domain, unsigned int end = 0; unsigned int next = 0; unsigned int unmap_size = 0; - unsigned long flags; + struct hisi_domain *hisi_domain = to_hisi_domain(domain); iova = SMMU_PAGE_ALIGN(iova); size = SMMU_PAGE_ALIGN(size); - pgdp = (smmu_pgd_t *)hisi_smmu_dev->va_pgtable_addr; + pgdp = (smmu_pgd_t *)hisi_domain->va_pgtable_addr; end = iova + size; - dbg("%s:end=0x%x\n", __func__, end); pgdp += smmu_pgd_index(iova); - spin_lock_irqsave(&hisi_smmu_dev->lock, flags); do { next = smmu_pgd_addr_end_lpae(iova, end); unmap_size += hisi_smmu_clear_pmd_lpae(pgdp, iova, next); iova = next; - dbg("%s: pgdp=%p, iova=0x%lx\n", __func__, pgdp, iova); + dbg("%s: pgdp=%pK, iova=0x%lx\n", __func__, pgdp, iova); } while (pgdp++, iova < end); - spin_unlock_irqrestore(&hisi_smmu_dev->lock, flags); return unmap_size; } static size_t hisi_smmu_unmap_lpae(struct iommu_domain *domain, unsigned long iova, size_t size) { - unsigned long max_iova; unsigned int ret; struct iommu_domain_data *data; if (!domain) { dbg("domain is null\n"); - return -ENODEV; + return 0; } data = domain->priv; /*caculate the max io virtual address */ - max_iova = data->iova_start + data->iova_size; - /*check the iova */ - if (iova < data->iova_start) - goto error; - if ((iova+size) > max_iova) { - dbg("iova out of domain range, iova+size=0x%lx, end=0x%lx\n", - iova+size, max_iova); - goto error; - } /*unmapping the range of iova*/ ret = hisi_smmu_handle_unmapping_lpae(domain, iova, size); if (ret == size) { dbg("%s:unmap size:0x%x\n", __func__, (unsigned int)size); return size; - } else { + } else return 0; - } -error: - dbg("%s:the range of io address is wrong\n", __func__); - return -EINVAL; } static phys_addr_t hisi_smmu_iova_to_phys_lpae( @@ -478,7 +469,8 @@ static phys_addr_t hisi_smmu_iova_to_phys_lpae( smmu_pmd_t pmd; smmu_pte_t pte; - pgdp = (smmu_pgd_t *)hisi_smmu_dev->va_pgtable_addr; + struct hisi_domain *hisi_domain = to_hisi_domain(domain); + pgdp = (smmu_pgd_t *)hisi_domain->va_pgtable_addr; if (!pgdp) return 0; @@ -502,16 +494,17 @@ static int hisi_attach_dev_lpae(struct iommu_domain *domain, struct device *dev) { struct device_node *np = dev->of_node; int ret = 0; - struct iommu_domain_data *iommu_info = NULL; + struct hisi_domain *hisi_domain = to_hisi_domain(domain); + struct iommu_domain_data *domain_data = kzalloc(sizeof + (struct iommu_domain_data), GFP_KERNEL); + if (!domain_data) + return -ENOMEM; + + ret = of_get_iova_info(np, &domain_data->iova_start, &domain_data->iova_size, + &domain_data->iova_align); + domain_data->phy_pgd_base = hisi_domain->pa_pgtable_addr; + domain->priv = domain_data; - iommu_info = kzalloc(sizeof(struct iommu_domain_data), GFP_KERNEL); - if (!iommu_info) { - dbg("alloc iommu_domain_data fail\n"); - return -EINVAL; - } - list_add(&iommu_info->list, &hisi_smmu_dev->domain_list); - domain->priv = iommu_info; - ret = get_domain_data_lpae(np, domain->priv); return ret; } @@ -522,7 +515,6 @@ static void hisi_detach_dev_lpae(struct iommu_domain *domain, data = (struct iommu_domain_data *)domain->priv; if (data) { - list_del(&data->list); domain->priv = NULL; kfree(data); } else { @@ -783,28 +775,15 @@ static int hisi_smmu_probe_lpae(struct platform_device *pdev) struct device *dev = &pdev->dev; dbg("enter %s\n", __func__); + hisi_smmu_dev = devm_kzalloc(dev, sizeof(struct hisi_smmu_device_lpae), GFP_KERNEL); + if(!hisi_smmu_dev) + return -ENOMEM; - hisi_smmu_dev->smmu_pgd = devm_kzalloc(dev, SZ_64, GFP_KERNEL | __GFP_DMA); - if (!hisi_smmu_dev) - goto smmu_device_error; - hisi_smmu_dev->dev = dev; INIT_LIST_HEAD(&hisi_smmu_dev->domain_list); - spin_lock_init(&hisi_smmu_dev->lock); - - hisi_smmu_dev->smmu_pgd = (smmu_pgd_t *)(ALIGN((unsigned long)(hisi_smmu_dev->smmu_pgd), SZ_32)); - - hisi_smmu_dev->smmu_phy_pgtable_addr = - virt_to_phys(hisi_smmu_dev->smmu_pgd); - printk(KERN_ERR "%s, smmu_phy_pgtable_addr is = %llx\n", __func__, hisi_smmu_dev->smmu_phy_pgtable_addr); - - hisi_smmu_dev->va_pgtable_addr = (unsigned long)(hisi_smmu_dev->smmu_pgd); bus_set_iommu(&platform_bus_type, &hisi_smmu_ops); return 0; - -smmu_device_error: - return -ENOMEM; } static int hisi_smmu_remove_lpae(struct platform_device *pdev) @@ -838,7 +817,7 @@ static int __init hisi_smmu_init_lpae(void) static void __exit hisi_smmu_exit_lpae(void) { - return platform_driver_unregister(&hisi_smmu_driver_lpae); + platform_driver_unregister(&hisi_smmu_driver_lpae); } subsys_initcall(hisi_smmu_init_lpae); diff --git a/drivers/iommu/ion-iommu-map.c b/drivers/iommu/ion-iommu-map.c index 52aa9a7bf699..b25d1524c181 100644 --- a/drivers/iommu/ion-iommu-map.c +++ b/drivers/iommu/ion-iommu-map.c @@ -32,12 +32,8 @@ #include #include -#ifdef IOMMU_DEBUG -#define dbg(format, arg...) \ - pr_info("[hisi_iommu_domain]"format, ##arg) -#else -#define dbg(format, arg...) -#endif +#define MAX_IOVA_SIZE_2G 0x80000000UL +#define MAX_IOVA_START_ADDR_4G 0x100000000UL struct map_result { unsigned long iova_start; @@ -47,8 +43,8 @@ struct map_result { unsigned long is_tile; }; -struct iommu_domain_data *domain_info; -static struct hisi_iommu_domain *m_hisi_domain; +static struct iommu_domain_data *ion_domain_info; +static struct ion_iommu_domain *ion_iommu_domain; DEFINE_MUTEX(iova_pool_mutex); static unsigned long hisi_alloc_iova(struct gen_pool *pool, @@ -83,23 +79,23 @@ static void hisi_free_iova(struct gen_pool *pool, unsigned long hisi_iommu_alloc_iova(size_t size, unsigned long align) { - struct hisi_iommu_domain *hisi_domain = m_hisi_domain; + struct ion_iommu_domain *ion_domain = ion_iommu_domain; - return hisi_alloc_iova(hisi_domain->iova_pool, size, align); + return hisi_alloc_iova(ion_domain->iova_pool, size, align); } EXPORT_SYMBOL_GPL(hisi_iommu_alloc_iova); void hisi_iommu_free_iova(unsigned long iova, size_t size) { int ret; - struct hisi_iommu_domain *hisi_domain = m_hisi_domain; + struct ion_iommu_domain *ion_domain = ion_iommu_domain; - ret = addr_in_gen_pool(hisi_domain->iova_pool, iova, size); + ret = addr_in_gen_pool(ion_domain->iova_pool, iova, size); if(!ret) { pr_err("%s:illegal para!!iova = %lx, size = %lx\n", __func__, iova, size); } - hisi_free_iova(hisi_domain->iova_pool, iova, size); + hisi_free_iova(ion_domain->iova_pool, iova, size); } EXPORT_SYMBOL_GPL(hisi_iommu_free_iova); @@ -135,7 +131,41 @@ static void iova_pool_destroy(struct gen_pool *pool) gen_pool_destroy(pool); } -static int do_iommu_domain_map(struct hisi_iommu_domain *hisi_domain, +static int iommu_check_tile_format(struct iommu_map_format *format, + unsigned long phys_len) +{ + unsigned long header_size = format->header_size; + unsigned long phys_page_line = format->phys_page_line; + unsigned long virt_page_line = format->virt_page_line; + + /* check invalid args */ + if ((phys_len <= header_size) || !phys_page_line || !virt_page_line) { + pr_err("[%s]wrong arg:phys_len 0x%lx, header_size 0x%lx\n", + __func__, phys_len, header_size); + pr_err("[%s]wrong arg:phys line 0x%lx, virt line 0x%lx\n", + __func__, phys_page_line, virt_page_line); + return -EINVAL; + } + + /* virt_page_line <= 128 and + * virt_page_line / phys_page_line = 1 in normal process */ + if ((virt_page_line * PAGE_SIZE > SZ_512K) || + (virt_page_line / phys_page_line != 1)) { + pr_err("%s:virt line/phys line out of standard\n", __func__); + return -EINVAL; + } + + /* check overflow */ + if ((virt_page_line * PAGE_SIZE <= virt_page_line) || + (phys_page_line * PAGE_SIZE <= phys_page_line)) { + pr_err("%s:virt_line/phys_line too large!!!\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int do_iommu_domain_map(struct ion_iommu_domain *ion_domain, struct scatterlist *sgl, struct iommu_map_format *format, struct map_result *result) { @@ -147,6 +177,12 @@ static int do_iommu_domain_map(struct hisi_iommu_domain *hisi_domain, struct iommu_domain *domain; struct scatterlist *sg; struct tile_format fmt; + + if (format->prot & IOMMU_SEC) { + pr_err("prot 0x%lx\n", format->prot); + return -EINVAL; + } + /* calculate whole phys mem length */ for (phys_len = 0, sg = sgl; sg; sg = sg_next(sg)) phys_len += (unsigned long)ALIGN(sg->length, PAGE_SIZE); @@ -156,6 +192,10 @@ static int do_iommu_domain_map(struct hisi_iommu_domain *hisi_domain, unsigned long lines; unsigned long body_size; + if (iommu_check_tile_format(format, phys_len)) { + pr_err("%s:check foramt fail\n", __func__); + return -EINVAL; + } body_size = phys_len - format->header_size; lines = body_size / (format->phys_page_line * PAGE_SIZE); @@ -169,15 +209,21 @@ static int do_iommu_domain_map(struct hisi_iommu_domain *hisi_domain, / (format->virt_page_line * PAGE_SIZE); } - iova_size = lines * format->virt_page_line * PAGE_SIZE; + iova_size = lines * format->virt_page_line * PAGE_SIZE - (format->virt_page_line - format->phys_page_line) * PAGE_SIZE; } else { iova_size = phys_len; } + /* Limit not exceeding 2G */ + if (MAX_IOVA_SIZE_2G < iova_size) { + pr_err("[%s]hisi_alloc_iova alloc size more than 2G(0x%lx).\n",__func__, iova_size); + return -EINVAL; + } + /* alloc iova */ - pool = hisi_domain->iova_pool; - domain = hisi_domain->domain; - iova_start = hisi_alloc_iova(pool, iova_size, hisi_domain->range.align); + pool = ion_domain->iova_pool; + domain = ion_domain->domain; + iova_start = hisi_alloc_iova(pool, iova_size, ion_domain->range.align); if (!iova_start) { pr_err("[%s]hisi_alloc_iova alloc size 0x%lx failed!" "hisi ion pool avail 0x%lx\n", @@ -185,7 +231,7 @@ static int do_iommu_domain_map(struct hisi_iommu_domain *hisi_domain, return -EINVAL; } - if (0x100000000 < (iova_start + iova_size)) { + if (MAX_IOVA_START_ADDR_4G < (iova_start + iova_size)) { pr_err("hisi iommu can not deal with iova 0x%lx size 0x%lx\n", iova_start, iova_size); } @@ -222,15 +268,15 @@ int hisi_iommu_map_domain(struct scatterlist *sgl, { int ret = 0; struct map_result result; - struct hisi_iommu_domain *hisi_domain; + struct ion_iommu_domain *ion_domain; - hisi_domain = m_hisi_domain; + ion_domain = ion_iommu_domain; memset(&result, 0, sizeof(result)); - ret = do_iommu_domain_map(hisi_domain, sgl, format, &result); + ret = do_iommu_domain_map(ion_domain, sgl, format, &result); if (ret) { - dbg("alloc iova fail\n"); + pr_err("alloc iova fail\n"); return ret; } format->iova_start = result.iova_start; @@ -245,8 +291,8 @@ static int do_iommu_domain_unmap(struct map_result *result) { int ret; unsigned long unmaped_size; - struct hisi_iommu_domain *hisi_domain = m_hisi_domain; - struct gen_pool *pool = hisi_domain->iova_pool; + struct ion_iommu_domain *ion_domain = ion_iommu_domain; + struct gen_pool *pool = ion_domain->iova_pool; /* never unmap a zero length address space */ if (!result->iova_size) { @@ -257,15 +303,15 @@ static int do_iommu_domain_unmap(struct map_result *result) /* unmap tile equals to unmpa range */ if (result->is_tile) { - unmaped_size = iommu_unmap_tile(hisi_domain->domain, + unmaped_size = iommu_unmap_tile(ion_domain->domain, result->iova_start, result->iova_size); } else { - unmaped_size = iommu_unmap(hisi_domain->domain, + unmaped_size = iommu_unmap(ion_domain->domain, result->iova_start, result->iova_size); } if (unmaped_size != result->iova_size) { - dbg("[%s]unmap failed!\n", __func__); + pr_err("[%s]unmap failed!\n", __func__); return -EINVAL; } /* free iova */ @@ -301,65 +347,70 @@ int hisi_iommu_unmap_domain(struct iommu_map_format *format) EXPORT_SYMBOL_GPL(hisi_iommu_unmap_domain); /*only used to test*/ -phys_addr_t hisi_iommu_domain_iova_to_phys(unsigned long iova) +phys_addr_t ion_iommu_domain_iova_to_phys(unsigned long iova) { struct iommu_domain *domain; - domain = m_hisi_domain->domain; + domain = ion_iommu_domain->domain; return iommu_iova_to_phys(domain, iova); } -EXPORT_SYMBOL_GPL(hisi_iommu_domain_iova_to_phys); +EXPORT_SYMBOL_GPL(ion_iommu_domain_iova_to_phys); -int hisi_ion_enable_iommu(struct platform_device *pdev) +struct iommu_domain *hisi_ion_enable_iommu(struct platform_device *pdev) { - int ret; struct device *dev = &pdev->dev; - struct hisi_iommu_domain *hisi_domain; + struct ion_iommu_domain *ion_domain; pr_info("in %s start\n", __func__); - hisi_domain = kzalloc(sizeof(*hisi_domain), GFP_KERNEL); - if (!hisi_domain) { - dbg("alloc hisi_domain object fail\n"); - return -ENOMEM; + if (ion_iommu_domain) { + pr_err("ion domain already init return domain\n"); + return ion_iommu_domain->domain; + } + + ion_domain = kzalloc(sizeof(*ion_domain), GFP_KERNEL); + if (!ion_domain) { + pr_err("alloc ion_domain object fail\n"); + return NULL; } if (!iommu_present(dev->bus)) { - dbg("iommu not found\n"); - kfree(hisi_domain); - return 0; + pr_err("iommu not found\n"); + kfree(ion_domain); + return NULL; } /* create iommu domain */ - hisi_domain->domain = iommu_domain_alloc(dev->bus); - if (!hisi_domain->domain) { - ret = -EINVAL; + ion_domain->domain = iommu_domain_alloc(dev->bus); + if (!ion_domain->domain) goto error; - } - iommu_attach_device(hisi_domain->domain, dev); - domain_info = (struct iommu_domain_data *)hisi_domain->domain->priv; + + iommu_attach_device(ion_domain->domain, dev); + ion_domain_info = (struct iommu_domain_data *)ion_domain->domain->priv; /** * Current align is 256K */ - hisi_domain->iova_pool = iova_pool_setup(domain_info->iova_start, - domain_info->iova_size, domain_info->iova_align); - if (!hisi_domain->iova_pool) { - ret = -EINVAL; + ion_domain->iova_pool = iova_pool_setup(ion_domain_info->iova_start, + ion_domain_info->iova_size, ion_domain_info->iova_align); + if (!ion_domain->iova_pool) goto error; - } - /* this is a global pointer */ - m_hisi_domain = hisi_domain; - dbg("in %s end\n", __func__); - return 0; + /* this is a global pointer */ + ion_iommu_domain = ion_domain; + + pr_info("in %s end\n", __func__); + return ion_iommu_domain->domain; error: - WARN(1, "hisi_iommu_domain_init failed!\n"); - if (hisi_domain->iova_pool) - iova_pool_destroy(hisi_domain->iova_pool); - if (hisi_domain->domain) - iommu_domain_free(hisi_domain->domain); - kfree(hisi_domain); + WARN(1, "ion_iommu_domain_init failed!\n"); + if (ion_domain->iova_pool) + iova_pool_destroy(ion_domain->iova_pool); - return ret; + if (ion_domain->domain) + iommu_domain_free(ion_domain->domain); + + kfree(ion_domain); + + ion_iommu_domain = NULL; + return NULL; } EXPORT_SYMBOL(hisi_ion_enable_iommu); diff --git a/drivers/staging/android/ion/hisi/of_hisi_ion.c b/drivers/staging/android/ion/hisi/of_hisi_ion.c index b9d2c886d677..f8a262b96e35 100644 --- a/drivers/staging/android/ion/hisi/of_hisi_ion.c +++ b/drivers/staging/android/ion/hisi/of_hisi_ion.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -165,7 +166,6 @@ static long hisi_ion_custom_ioctl(struct ion_client *client, return ret; } -extern int hisi_ion_enable_iommu(struct platform_device *pdev); static int get_type_by_name(const char *name, enum ion_heap_type *type) { @@ -233,7 +233,7 @@ static int hisi_set_platform_data(struct platform_device *pdev) } if (!prop->value || !prop->length) { - pr_err("%s %s %d, node %s, invalid phandle, value=%p,length=%d\n", + pr_err("%s %s %d, node %s, invalid phandle, value=%pK,length=%d\n", __FILE__,__FUNCTION__,__LINE__, np->name, prop->value, prop->length ); continue; @@ -337,7 +337,7 @@ static int hisi_ion_probe(struct platform_device *pdev) } /* FIXME will move to iommu driver*/ - if (hisi_ion_enable_iommu(pdev)) { + if (!hisi_ion_enable_iommu(pdev)) { dev_info(&pdev->dev, "enable iommu fail \n"); err = -EINVAL; goto err_free_idev; diff --git a/include/linux/hisi/hisi-iommu.h b/include/linux/hisi/hisi-iommu.h index 00dd5e97db59..ad6aab46b90d 100644 --- a/include/linux/hisi/hisi-iommu.h +++ b/include/linux/hisi/hisi-iommu.h @@ -2,9 +2,16 @@ #define _HI36XX_SMMU_H #include +#include +#include + +extern struct iommu_domain *hisi_ion_enable_iommu(struct platform_device *pdev); +extern int of_get_iova_info(struct device_node *np, unsigned long *iova_start, + unsigned long *iova_size, unsigned long *iova_align); + struct iommu_domain_data { - unsigned int iova_start; - unsigned int iova_size; + unsigned long iova_start; + unsigned long iova_size; phys_addr_t phy_pgd_base; unsigned long iova_align; struct list_head list; diff --git a/include/linux/hisi/ion-iommu.h b/include/linux/hisi/ion-iommu.h index 6e73ae3ff494..0c7fb360f1e8 100644 --- a/include/linux/hisi/ion-iommu.h +++ b/include/linux/hisi/ion-iommu.h @@ -13,7 +13,7 @@ struct section_info { unsigned int page_size; unsigned int align; }; -struct hisi_iommu_domain { +struct ion_iommu_domain { struct iommu_domain *domain; struct gen_pool *iova_pool; struct section_info range; @@ -26,7 +26,6 @@ struct hisi_iommu_domain * hisi_get_domain(void); size_t hisi_iommu_iova_size(void); size_t hisi_iommu_iova_available(void); void hisi_iommu_free_iova(unsigned long iova, size_t size); -unsigned long hisi_iommu_alloc_iova(size_t size, unsigned long align); int hisi_iommu_map_range(struct iommu_domain *domain,unsigned long iova_start, struct scatterlist *sgl, unsigned long iova_size,unsigned int prot); int hisi_iommu_unmap_range(struct iommu_domain *domain,unsigned long iova_start,unsigned long iova_size);