[COMMON] exynos/iommu: add suspended state
authorJanghyuck Kim <janghyuck.kim@samsung.com>
Fri, 27 May 2016 01:23:56 +0000 (10:23 +0900)
committerSangwook Ju <sw.ju@samsung.com>
Mon, 14 May 2018 10:45:19 +0000 (19:45 +0900)
This patch added suspended state that becomes true when sysmmu goes to
suspend state. No SFR access is allowed if sysmmu is in suspended.

Without suspended state, some operation involving SFR access like tlb
invalidation would make external abort because it only checks internal
reference count before SFR access, and internal reference count is
remained after sysmmu becomes suspend state.

Change-Id: I7460e8b0b96de5f46584cc299dc2e659fc34da44
Signed-off-by: Janghyuck Kim <janghyuck.kim@samsung.com>
drivers/iommu/exynos-iommu.c
drivers/iommu/exynos-iommu.h

index 62ec5882d83913497b91d763232dac6518cfc880..1eb9ba95d72b0ab96e1319afabe9b7514c566aa9 100644 (file)
@@ -559,8 +559,10 @@ static int exynos_sysmmu_suspend(struct device *dev)
 
        spin_lock_irqsave(&drvdata->lock, flags);
        if (is_sysmmu_active(drvdata) &&
-                       is_sysmmu_runtime_active(drvdata))
+                       is_sysmmu_runtime_active(drvdata)) {
                __sysmmu_disable_nocount(drvdata);
+               drvdata->is_suspended = true;
+       }
        spin_unlock_irqrestore(&drvdata->lock, flags);
 
        return 0;
@@ -572,9 +574,10 @@ static int exynos_sysmmu_resume(struct device *dev)
        struct sysmmu_drvdata *drvdata = dev_get_drvdata(dev);
 
        spin_lock_irqsave(&drvdata->lock, flags);
-       if (is_sysmmu_active(drvdata) &&
-                        is_sysmmu_runtime_active(drvdata))
+       if (drvdata->is_suspended) {
                __sysmmu_enable_nocount(drvdata);
+               drvdata->is_suspended = false;
+       }
        spin_unlock_irqrestore(&drvdata->lock, flags);
 
        return 0;
index 8350c962bb075399a54affa8b89806a542ff29fe..671d0559fd9c36520a190a4ef7644643b769d7ee 100644 (file)
@@ -207,6 +207,7 @@ struct sysmmu_drvdata {
        phys_addr_t pgtable;            /* assigned page table structure */
        int version;                    /* our version */
        struct atomic_notifier_head fault_notifiers;
+       bool is_suspended;
 };
 
 struct exynos_vm_region {
@@ -275,7 +276,7 @@ static inline bool set_sysmmu_inactive(struct sysmmu_drvdata *data)
 
 static inline bool is_sysmmu_active(struct sysmmu_drvdata *data)
 {
-       return data->activations > 0;
+       return !data->is_suspended && data->activations > 0;
 }
 
 static inline void __raw_sysmmu_enable(void __iomem *sfrbase)