iommu/exynos: Use device dependency links to control runtime pm
authorMarek Szyprowski <m.szyprowski@samsung.com>
Mon, 14 Nov 2016 10:08:12 +0000 (11:08 +0100)
committerJoerg Roedel <jroedel@suse.de>
Mon, 14 Nov 2016 16:11:59 +0000 (17:11 +0100)
This patch uses recently introduced device dependency links to track the
runtime pm state of the master's device. The goal is to let SYSMMU
controller device's runtime PM to follow the runtime PM state of the
respective master's device. This way each SYSMMU controller is active
only when its master's device is active and can properly restore or save
its state instead on runtime PM transition of master's device.
This approach replaces old behavior, when SYSMMU controller was set to
runtime active once after attaching to the master device. In the new
approach SYSMMU controllers no longer prevents respective power domains
to be turned off when master's device is not being used.

This patch reduces total power consumption of idle system, because most
power domains can be finally turned off. For example, on Exynos 4412
based Odroid U3 this patch reduces power consuption from 136mA to 130mA
at 5V (by 4.4%).

The dependency links also enforce proper order of suspending/restoring
devices during system sleep transition, so there is no more need to use
LATE_SYSTEM_SLEEP_PM_OPS-based workaround for ensuring that SYSMMUs are
suspended after their master devices.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/exynos-iommu.c

index 22bc7e5c4dcc0e31e4353ce537cac46e7eecdb45..57ba0d3091ea257a221de36f3143311db3989d63 100644 (file)
@@ -671,8 +671,8 @@ static int __maybe_unused exynos_sysmmu_resume(struct device *dev)
 
 static const struct dev_pm_ops sysmmu_pm_ops = {
        SET_RUNTIME_PM_OPS(exynos_sysmmu_suspend, exynos_sysmmu_resume, NULL)
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                                    pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static const struct of_device_id sysmmu_of_match[] __initconst = {
@@ -819,10 +819,6 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain,
        if (!has_sysmmu(dev) || owner->domain != iommu_domain)
                return;
 
-       list_for_each_entry(data, &owner->controllers, owner_node) {
-               pm_runtime_put_sync(data->sysmmu);
-       }
-
        mutex_lock(&owner->rpm_lock);
 
        list_for_each_entry(data, &owner->controllers, owner_node) {
@@ -886,10 +882,6 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain,
 
        mutex_unlock(&owner->rpm_lock);
 
-       list_for_each_entry(data, &owner->controllers, owner_node) {
-               pm_runtime_get_sync(data->sysmmu);
-       }
-
        dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa\n", __func__,
                &pagetable);
 
@@ -1271,6 +1263,14 @@ static int exynos_iommu_of_xlate(struct device *dev,
 
        list_add_tail(&data->owner_node, &owner->controllers);
        data->master = dev;
+
+       /*
+        * SYSMMU will be runtime activated via device link (dependency) to its
+        * master device, so there are no direct calls to pm_runtime_get/put
+        * in this driver.
+        */
+       device_link_add(dev, data->sysmmu, DL_FLAG_PM_RUNTIME);
+
        return 0;
 }