]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/iommu/exynos-iommu.c
Merge branch 'misc' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild
[karo-tx-linux.git] / drivers / iommu / exynos-iommu.c
index 9c8ce951158de92ace43d6c359607d72c4c7d151..5ecc86cb74c81f3194732ea6469b4e813a206bf5 100644 (file)
@@ -201,6 +201,7 @@ static const struct sysmmu_fault_info sysmmu_v5_faults[] = {
 */
 struct exynos_iommu_owner {
        struct list_head controllers;   /* list of sysmmu_drvdata.owner_node */
+       struct iommu_domain *domain;    /* domain this device is attached */
 };
 
 /*
@@ -267,18 +268,18 @@ static bool is_sysmmu_active(struct sysmmu_drvdata *data)
 
 static void sysmmu_unblock(struct sysmmu_drvdata *data)
 {
-       __raw_writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL);
+       writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL);
 }
 
 static bool sysmmu_block(struct sysmmu_drvdata *data)
 {
        int i = 120;
 
-       __raw_writel(CTRL_BLOCK, data->sfrbase + REG_MMU_CTRL);
-       while ((i > 0) && !(__raw_readl(data->sfrbase + REG_MMU_STATUS) & 1))
+       writel(CTRL_BLOCK, data->sfrbase + REG_MMU_CTRL);
+       while ((i > 0) && !(readl(data->sfrbase + REG_MMU_STATUS) & 1))
                --i;
 
-       if (!(__raw_readl(data->sfrbase + REG_MMU_STATUS) & 1)) {
+       if (!(readl(data->sfrbase + REG_MMU_STATUS) & 1)) {
                sysmmu_unblock(data);
                return false;
        }
@@ -289,9 +290,9 @@ static bool sysmmu_block(struct sysmmu_drvdata *data)
 static void __sysmmu_tlb_invalidate(struct sysmmu_drvdata *data)
 {
        if (MMU_MAJ_VER(data->version) < 5)
-               __raw_writel(0x1, data->sfrbase + REG_MMU_FLUSH);
+               writel(0x1, data->sfrbase + REG_MMU_FLUSH);
        else
-               __raw_writel(0x1, data->sfrbase + REG_V5_MMU_FLUSH_ALL);
+               writel(0x1, data->sfrbase + REG_V5_MMU_FLUSH_ALL);
 }
 
 static void __sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data,
@@ -301,10 +302,10 @@ static void __sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data,
 
        for (i = 0; i < num_inv; i++) {
                if (MMU_MAJ_VER(data->version) < 5)
-                       __raw_writel((iova & SPAGE_MASK) | 1,
+                       writel((iova & SPAGE_MASK) | 1,
                                     data->sfrbase + REG_MMU_FLUSH_ENTRY);
                else
-                       __raw_writel((iova & SPAGE_MASK) | 1,
+                       writel((iova & SPAGE_MASK) | 1,
                                     data->sfrbase + REG_V5_MMU_FLUSH_ENTRY);
                iova += SPAGE_SIZE;
        }
@@ -313,9 +314,9 @@ static void __sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data,
 static void __sysmmu_set_ptbase(struct sysmmu_drvdata *data, phys_addr_t pgd)
 {
        if (MMU_MAJ_VER(data->version) < 5)
-               __raw_writel(pgd, data->sfrbase + REG_PT_BASE_ADDR);
+               writel(pgd, data->sfrbase + REG_PT_BASE_ADDR);
        else
-               __raw_writel(pgd >> PAGE_SHIFT,
+               writel(pgd >> PAGE_SHIFT,
                             data->sfrbase + REG_V5_PT_BASE_PFN);
 
        __sysmmu_tlb_invalidate(data);
@@ -330,7 +331,7 @@ static void __sysmmu_get_version(struct sysmmu_drvdata *data)
        clk_enable(data->pclk);
        clk_enable(data->aclk);
 
-       ver = __raw_readl(data->sfrbase + REG_MMU_VERSION);
+       ver = readl(data->sfrbase + REG_MMU_VERSION);
 
        /* controllers on some SoCs don't report proper version */
        if (ver == 0x80000001u)
@@ -391,7 +392,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
 
        clk_enable(data->clk_master);
 
-       itype = __ffs(__raw_readl(data->sfrbase + reg_status));
+       itype = __ffs(readl(data->sfrbase + reg_status));
        for (i = 0; i < n; i++, finfo++)
                if (finfo->bit == itype)
                        break;
@@ -399,7 +400,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
        BUG_ON(i == n);
 
        /* print debug message */
-       fault_addr = __raw_readl(data->sfrbase + finfo->addr_reg);
+       fault_addr = readl(data->sfrbase + finfo->addr_reg);
        show_fault_information(data, finfo, fault_addr);
 
        if (data->domain)
@@ -408,7 +409,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
        /* fault is not recovered by fault handler */
        BUG_ON(ret != 0);
 
-       __raw_writel(1 << itype, data->sfrbase + reg_clear);
+       writel(1 << itype, data->sfrbase + reg_clear);
 
        sysmmu_unblock(data);
 
@@ -423,8 +424,8 @@ static void __sysmmu_disable_nocount(struct sysmmu_drvdata *data)
 {
        clk_enable(data->clk_master);
 
-       __raw_writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL);
-       __raw_writel(0, data->sfrbase + REG_MMU_CFG);
+       writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL);
+       writel(0, data->sfrbase + REG_MMU_CFG);
 
        clk_disable(data->aclk);
        clk_disable(data->pclk);
@@ -469,7 +470,7 @@ static void __sysmmu_init_config(struct sysmmu_drvdata *data)
        else
                cfg = CFG_QOS(15) | CFG_FLPDCACHE | CFG_ACGEN;
 
-       __raw_writel(cfg, data->sfrbase + REG_MMU_CFG);
+       writel(cfg, data->sfrbase + REG_MMU_CFG);
 }
 
 static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data)
@@ -479,13 +480,13 @@ static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data)
        clk_enable(data->pclk);
        clk_enable(data->aclk);
 
-       __raw_writel(CTRL_BLOCK, data->sfrbase + REG_MMU_CTRL);
+       writel(CTRL_BLOCK, data->sfrbase + REG_MMU_CTRL);
 
        __sysmmu_init_config(data);
 
        __sysmmu_set_ptbase(data, data->pgtable);
 
-       __raw_writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL);
+       writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL);
 
        clk_disable(data->clk_master);
 }
@@ -825,6 +826,41 @@ static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain)
        kfree(domain);
 }
 
+static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain,
+                                   struct device *dev)
+{
+       struct exynos_iommu_owner *owner = dev->archdata.iommu;
+       struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain);
+       phys_addr_t pagetable = virt_to_phys(domain->pgtable);
+       struct sysmmu_drvdata *data, *next;
+       unsigned long flags;
+       bool found = false;
+
+       if (!has_sysmmu(dev) || owner->domain != iommu_domain)
+               return;
+
+       spin_lock_irqsave(&domain->lock, flags);
+       list_for_each_entry_safe(data, next, &domain->clients, domain_node) {
+               if (data->master == dev) {
+                       if (__sysmmu_disable(data)) {
+                               data->master = NULL;
+                               list_del_init(&data->domain_node);
+                       }
+                       pm_runtime_put(data->sysmmu);
+                       found = true;
+               }
+       }
+       spin_unlock_irqrestore(&domain->lock, flags);
+
+       owner->domain = NULL;
+
+       if (found)
+               dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n",
+                                       __func__, &pagetable);
+       else
+               dev_err(dev, "%s: No IOMMU is attached\n", __func__);
+}
+
 static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain,
                                   struct device *dev)
 {
@@ -838,6 +874,9 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain,
        if (!has_sysmmu(dev))
                return -ENODEV;
 
+       if (owner->domain)
+               exynos_iommu_detach_device(owner->domain, dev);
+
        list_for_each_entry(data, &owner->controllers, owner_node) {
                pm_runtime_get_sync(data->sysmmu);
                ret = __sysmmu_enable(data, pagetable, domain);
@@ -856,44 +895,13 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain,
                return ret;
        }
 
+       owner->domain = iommu_domain;
        dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa %s\n",
                __func__, &pagetable, (ret == 0) ? "" : ", again");
 
        return ret;
 }
 
-static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain,
-                                   struct device *dev)
-{
-       struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain);
-       phys_addr_t pagetable = virt_to_phys(domain->pgtable);
-       struct sysmmu_drvdata *data, *next;
-       unsigned long flags;
-       bool found = false;
-
-       if (!has_sysmmu(dev))
-               return;
-
-       spin_lock_irqsave(&domain->lock, flags);
-       list_for_each_entry_safe(data, next, &domain->clients, domain_node) {
-               if (data->master == dev) {
-                       if (__sysmmu_disable(data)) {
-                               data->master = NULL;
-                               list_del_init(&data->domain_node);
-                       }
-                       pm_runtime_put(data->sysmmu);
-                       found = true;
-               }
-       }
-       spin_unlock_irqrestore(&domain->lock, flags);
-
-       if (found)
-               dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n",
-                                       __func__, &pagetable);
-       else
-               dev_err(dev, "%s: No IOMMU is attached\n", __func__);
-}
-
 static sysmmu_pte_t *alloc_lv2entry(struct exynos_iommu_domain *domain,
                sysmmu_pte_t *sent, sysmmu_iova_t iova, short *pgcounter)
 {
@@ -907,7 +915,7 @@ static sysmmu_pte_t *alloc_lv2entry(struct exynos_iommu_domain *domain,
                bool need_flush_flpd_cache = lv1ent_zero(sent);
 
                pent = kmem_cache_zalloc(lv2table_kmem_cache, GFP_ATOMIC);
-               BUG_ON((phys_addr_t)pent & (LV2TABLE_SIZE - 1));
+               BUG_ON((uintptr_t)pent & (LV2TABLE_SIZE - 1));
                if (!pent)
                        return ERR_PTR(-ENOMEM);