Since kmalloc() does not guarantee the alignment of 1KB when it
allocates 1KB, it is required to allocate lv2 page table from
own slab that guarantees alignment of 1KB.

Signed-off-by: KyongHo Cho <pullip....@samsung.com>
---
 drivers/iommu/exynos-iommu.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 4061b17..0bb194e 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -104,6 +104,8 @@
 #define REG_PB1_SADDR          0x054
 #define REG_PB1_EADDR          0x058
 
+static struct kmem_cache *lv2table_kmem_cache;
+
 static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova)
 {
        return pgtable + lv1ent_offset(iova);
@@ -865,7 +867,8 @@ static void exynos_iommu_domain_destroy(struct iommu_domain 
*domain)
 
        for (i = 0; i < NUM_LV1ENTRIES; i++)
                if (lv1ent_page(priv->pgtable + i))
-                       kfree(__va(lv2table_base(priv->pgtable + i)));
+                       kmem_cache_free(lv2table_kmem_cache,
+                                       __va(lv2table_base(priv->pgtable + i)));
 
        free_pages((unsigned long)priv->pgtable, 2);
        free_pages((unsigned long)priv->lv2entcnt, 1);
@@ -959,7 +962,7 @@ static unsigned long *alloc_lv2entry(unsigned long *sent, 
unsigned long iova,
        if (lv1ent_fault(sent)) {
                unsigned long *pent;
 
-               pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC);
+               pent = kmem_cache_zalloc(lv2table_kmem_cache, GFP_ATOMIC);
                BUG_ON((unsigned long)pent & (LV2TABLE_SIZE - 1));
                if (!pent)
                        return NULL;
@@ -982,7 +985,7 @@ static int lv1set_section(unsigned long *sent, phys_addr_t 
paddr, short *pgcnt)
                if (*pgcnt != NUM_LV2ENTRIES)
                        return -EADDRINUSE;
 
-               kfree(page_entry(sent, 0));
+               kmem_cache_free(lv2table_kmem_cache, page_entry(sent, 0));
 
                *pgcnt = 0;
        }
@@ -1168,10 +1171,23 @@ static int __init exynos_iommu_init(void)
 {
        int ret;
 
+       lv2table_kmem_cache = kmem_cache_create("exynos-iommu-lv2table",
+               LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL);
+       if (!lv2table_kmem_cache) {
+               pr_err("%s: failed to create kmem cache\n", __func__);
+               return -ENOMEM;
+       }
+
        ret = platform_driver_register(&exynos_sysmmu_driver);
 
        if (ret == 0)
-               bus_set_iommu(&platform_bus_type, &exynos_iommu_ops);
+               ret = bus_set_iommu(&platform_bus_type, &exynos_iommu_ops);
+
+       if (ret) {
+               pr_err("%s: Failed to register exynos-iommu driver.\n",
+                                                               __func__);
+               kmem_cache_destroy(lv2table_kmem_cache);
+       }
 
        return ret;
 }
-- 
1.8.0


--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to