From: Cho KyongHo <pullip.cho@xxxxxxxxxxx> This commit introduces sysmmu_pte_t for page table entries and sysmmu_iova_t vor I/O virtual address that is manipulated by exynos-iommu driver. The purpose of the typedef is to remove dependencies to the driver code from the change of CPU architecture from 32 bit to 64 bit. Signed-off-by: Cho KyongHo <pullip.cho@xxxxxxxxxxx> --- drivers/iommu/exynos-iommu.c | 117 ++++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 50 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 08a7ce0..00915f2 100755 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -33,6 +33,9 @@ #include <asm/cacheflush.h> #include <asm/pgtable.h> +typedef u32 sysmmu_iova_t; +typedef u32 sysmmu_pte_t; + /* We does not consider super section mapping (16MB) */ #define SECT_ORDER 20 #define LPAGE_ORDER 16 @@ -54,20 +57,32 @@ #define lv2ent_small(pent) ((*(pent) & 2) == 2) #define lv2ent_large(pent) ((*(pent) & 3) == 1) +static u32 sysmmu_page_offset(sysmmu_iova_t iova, u32 size) +{ + return iova & (size - 1); +} + #define section_phys(sent) (*(sent) & SECT_MASK) -#define section_offs(iova) ((iova) & 0xFFFFF) +#define section_offs(iova) sysmmu_page_offset((iova), SECT_SIZE) #define lpage_phys(pent) (*(pent) & LPAGE_MASK) -#define lpage_offs(iova) ((iova) & 0xFFFF) +#define lpage_offs(iova) sysmmu_page_offset((iova), LPAGE_SIZE) #define spage_phys(pent) (*(pent) & SPAGE_MASK) -#define spage_offs(iova) ((iova) & 0xFFF) - -#define lv1ent_offset(iova) ((iova) >> SECT_ORDER) -#define lv2ent_offset(iova) (((iova) & 0xFF000) >> SPAGE_ORDER) +#define spage_offs(iova) sysmmu_page_offset((iova), SPAGE_SIZE) #define NUM_LV1ENTRIES 4096 -#define NUM_LV2ENTRIES 256 +#define NUM_LV2ENTRIES (SECT_SIZE / SPAGE_SIZE) -#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(long)) +static u32 lv1ent_offset(sysmmu_iova_t iova) +{ + return iova >> SECT_ORDER; +} + +static u32 lv2ent_offset(sysmmu_iova_t iova) +{ + return (iova >> SPAGE_ORDER) & (NUM_LV2ENTRIES - 1); +} + +#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(sysmmu_pte_t)) #define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE) @@ -124,14 +139,14 @@ static struct kmem_cache *lv2table_kmem_cache; -static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova) +static sysmmu_pte_t *section_entry(sysmmu_pte_t *pgtable, sysmmu_iova_t iova) { return pgtable + lv1ent_offset(iova); } -static unsigned long *page_entry(unsigned long *sent, unsigned long iova) +static sysmmu_pte_t *page_entry(sysmmu_pte_t *sent, sysmmu_iova_t iova) { - return (unsigned long *)phys_to_virt( + return (sysmmu_pte_t *)phys_to_virt( lv2table_base(sent)) + lv2ent_offset(iova); } @@ -183,7 +198,7 @@ struct exynos_iommu_owner { struct exynos_iommu_domain { struct list_head clients; /* list of sysmmu_drvdata.node */ - unsigned long *pgtable; /* lv1 page table, 16KB */ + sysmmu_pte_t *pgtable; /* lv1 page table, 16KB */ short *lv2entcnt; /* free lv2 entry counter for each section */ spinlock_t lock; /* lock for this structure */ spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */ @@ -277,7 +292,7 @@ static void __sysmmu_tlb_invalidate(void __iomem *sfrbase) } static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase, - unsigned long iova, unsigned int num_inv) + sysmmu_iova_t iova, unsigned int num_inv) { unsigned int i; for (i = 0; i < num_inv; i++) { @@ -288,7 +303,7 @@ static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase, } static void __sysmmu_set_ptbase(void __iomem *sfrbase, - unsigned long pgd) + phys_addr_t pgd) { __raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR); @@ -297,22 +312,22 @@ static void __sysmmu_set_ptbase(void __iomem *sfrbase, static void show_fault_information(const char *name, enum exynos_sysmmu_inttype itype, - phys_addr_t pgtable_base, unsigned long fault_addr) + phys_addr_t pgtable_base, sysmmu_iova_t fault_addr) { - unsigned long *ent; + sysmmu_pte_t *ent; if ((itype >= SYSMMU_FAULTS_NUM) || (itype < SYSMMU_PAGEFAULT)) itype = SYSMMU_FAULT_UNKNOWN; - pr_err("%s occurred at %#lx by %s(Page table base: %pa)\n", + pr_err("%s occurred at %#x by %s(Page table base: %pa)\n", sysmmu_fault_name[itype], fault_addr, name, &pgtable_base); ent = section_entry(phys_to_virt(pgtable_base), fault_addr); - pr_err("\tLv1 entry: 0x%lx\n", *ent); + pr_err("\tLv1 entry: %#x\n", *ent); if (lv1ent_page(ent)) { ent = page_entry(ent, fault_addr); - pr_err("\t Lv2 entry: 0x%lx\n", *ent); + pr_err("\t Lv2 entry: %#x\n", *ent); } } @@ -321,7 +336,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) /* SYSMMU is in blocked when interrupt occurred. */ struct sysmmu_drvdata *data = dev_id; enum exynos_sysmmu_inttype itype; - unsigned long addr = -1; + sysmmu_iova_t addr = -1; int ret = -ENOSYS; WARN_ON(!is_sysmmu_active(data)); @@ -345,7 +360,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) __func__); BUG(); } else { - unsigned long base = + unsigned int base = __raw_readl(data->sfrbase + REG_PT_BASE_ADDR); show_fault_information(dev_name(data->sysmmu), itype, base, addr); @@ -411,7 +426,7 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data) static void __sysmmu_init_config(struct sysmmu_drvdata *data) { - unsigned long cfg = CFG_LRU | CFG_QOS(15); + unsigned int cfg = CFG_LRU | CFG_QOS(15); int maj, min = 0; maj = __sysmmu_version(data, &min); @@ -449,7 +464,7 @@ static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) } static int __sysmmu_enable(struct sysmmu_drvdata *data, - unsigned long pgtable, struct iommu_domain *domain) + phys_addr_t pgtable, struct iommu_domain *domain) { int ret = 0; unsigned long flags; @@ -478,12 +493,12 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data, } /* __exynos_sysmmu_enable: Enables System MMU -* -* returns -error if an error occurred and System MMU is not enabled, -* 0 if the System MMU has been just enabled and 1 if System MMU was already -* enabled before. -*/ -static int __exynos_sysmmu_enable(struct device *dev, unsigned long pgtable, + * + * returns -error if an error occurred and System MMU is not enabled, + * 0 if the System MMU has been just enabled and 1 if System MMU was already + * enabled before. + */ +static int __exynos_sysmmu_enable(struct device *dev, phys_addr_t pgtable, struct iommu_domain *domain) { int ret = 0; @@ -517,7 +532,7 @@ static int __exynos_sysmmu_enable(struct device *dev, unsigned long pgtable, return ret; } -int exynos_sysmmu_enable(struct device *dev, unsigned long pgtable) +int exynos_sysmmu_enable(struct device *dev, phys_addr_t pgtable) { BUG_ON(!memblock_is_memory(pgtable)); @@ -548,7 +563,7 @@ static bool exynos_sysmmu_disable(struct device *dev) return disabled; } -static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova, +static void sysmmu_tlb_invalidate_entry(struct device *dev, sysmmu_iova_t iova, size_t size) { struct exynos_iommu_owner *owner = dev->archdata.iommu; @@ -590,7 +605,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova, clk_disable(data->clk_master); } else { dev_dbg(dev, - "disabled. Skipping TLB invalidation @ %#lx\n", + "disabled. Skipping TLB invalidation @ %#x\n", iova); } @@ -856,7 +871,7 @@ static int exynos_iommu_domain_init(struct iommu_domain *domain) if (!priv) return -ENOMEM; - priv->pgtable = (unsigned long *)__get_free_pages( + priv->pgtable = (sysmmu_pte_t *)__get_free_pages( GFP_KERNEL | __GFP_ZERO, 2); if (!priv->pgtable) goto err_pgtable; @@ -978,19 +993,19 @@ static void exynos_iommu_detach_device(struct iommu_domain *domain, dev_dbg(dev, "%s: No IOMMU is attached\n", __func__); } -static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova, +static sysmmu_pte_t *alloc_lv2entry(sysmmu_pte_t *sent, sysmmu_iova_t iova, short *pgcounter) { if (lv1ent_section(sent)) { - WARN(1, "Trying mapping on %#08lx mapped with 1MiB page", iova); + WARN(1, "Trying mapping on %#08x mapped with 1MiB page", iova); return ERR_PTR(-EADDRINUSE); } if (lv1ent_fault(sent)) { - unsigned long *pent; + sysmmu_pte_t *pent; pent = kmem_cache_zalloc(lv2table_kmem_cache, GFP_ATOMIC); - BUG_ON((unsigned long)pent & (LV2TABLE_SIZE - 1)); + BUG_ON((unsigned int)pent & (LV2TABLE_SIZE - 1)); if (!pent) return ERR_PTR(-ENOMEM); @@ -1003,18 +1018,18 @@ static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova, return page_entry(sent, iova); } -static int lv1set_section(unsigned long *sent, unsigned long iova, +static int lv1set_section(sysmmu_pte_t *sent, sysmmu_iova_t iova, phys_addr_t paddr, short *pgcnt) { if (lv1ent_section(sent)) { - WARN(1, "Trying mapping on 1MiB@%#08lx that is mapped", + WARN(1, "Trying mapping on 1MiB@%#08x that is mapped", iova); return -EADDRINUSE; } if (lv1ent_page(sent)) { if (*pgcnt != NUM_LV2ENTRIES) { - WARN(1, "Trying mapping on 1MiB@%#08lx that is mapped", + WARN(1, "Trying mapping on 1MiB@%#08x that is mapped", iova); return -EADDRINUSE; } @@ -1030,7 +1045,7 @@ static int lv1set_section(unsigned long *sent, unsigned long iova, return 0; } -static int lv2set_page(unsigned long *pent, phys_addr_t paddr, size_t size, +static int lv2set_page(sysmmu_pte_t *pent, phys_addr_t paddr, size_t size, short *pgcnt) { if (size == SPAGE_SIZE) { @@ -1062,11 +1077,12 @@ static int lv2set_page(unsigned long *pent, phys_addr_t paddr, size_t size, return 0; } -static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova, +static int exynos_iommu_map(struct iommu_domain *domain, unsigned long l_iova, phys_addr_t paddr, size_t size, int prot) { struct exynos_iommu_domain *priv = domain->priv; - unsigned long *entry; + sysmmu_pte_t *entry; + sysmmu_iova_t iova = (sysmmu_iova_t)l_iova; unsigned long flags; int ret = -ENOMEM; @@ -1080,7 +1096,7 @@ static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova, ret = lv1set_section(entry, iova, paddr, &priv->lv2entcnt[lv1ent_offset(iova)]); } else { - unsigned long *pent; + sysmmu_pte_t *pent; pent = alloc_lv2entry(entry, iova, &priv->lv2entcnt[lv1ent_offset(iova)]); @@ -1093,7 +1109,7 @@ static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova, } if (ret) - pr_debug("%s: Failed to map iova 0x%lx/0x%x bytes\n", + pr_debug("%s: Failed to map iova %#x/%#zx bytes\n", __func__, iova, size); spin_unlock_irqrestore(&priv->pgtablelock, flags); @@ -1102,13 +1118,14 @@ static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova, } static size_t exynos_iommu_unmap(struct iommu_domain *domain, - unsigned long iova, size_t size) + unsigned long l_iova, size_t size) { struct exynos_iommu_domain *priv = domain->priv; struct exynos_iommu_owner *owner; - unsigned long flags; - unsigned long *ent; + sysmmu_iova_t iova = (sysmmu_iova_t)l_iova; + sysmmu_pte_t *ent; size_t err_pgsize; + unsigned long flags; BUG_ON(priv->pgtable == NULL); @@ -1175,7 +1192,7 @@ err: spin_unlock_irqrestore(&priv->pgtablelock, flags); WARN(1, - "%s: Failed due to size(%#x) @ %#08lx is smaller than page size %#x\n", + "%s: Failed due to size(%#zx) @ %#x is smaller than page size %#zx\n", __func__, size, iova, err_pgsize); return 0; @@ -1185,7 +1202,7 @@ static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) { struct exynos_iommu_domain *priv = domain->priv; - unsigned long *entry; + sysmmu_pte_t *entry; unsigned long flags; phys_addr_t phys = 0; -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html