soc: samsung: asv: Wait until OPP gets released before adding new one 52/200752/2
authorSylwester Nawrocki <s.nawrocki@samsung.com>
Fri, 1 Mar 2019 15:30:16 +0000 (16:30 +0100)
committerSylwester Nawrocki <s.nawrocki@samsung.com>
Wed, 27 Mar 2019 11:18:53 +0000 (12:18 +0100)
There is currently no check whether an OPP is actually removed before
attempting to add an replacement OPP. In situations when and OPP is
referenced when we try to remove it and it is not already removed at
the time of return from the dev_pm_opp_remove() call subsequent
dev_pm_opp_add() invocation will fail. To avoid that add a polling loop
with timeout as a barrier before adding new OPP.

This patch should also prevent related cpufreq core issues as indicated
by logs as follows.

exynos_asv_update_cpu_opp cpu4 opp5, freq: 2000 missing
exynos5433_asv_opp_get_voltage: arm,cortex-a57: [6] freq: 1900, voltage: 1262500 -> 1187500
cpu cpu4: _opp_add: duplicate OPPs detected. Existing: freq: 1900000000, volt: 1262500,
enabled: 1. New: freq: 1900000000, volt: 1187500, enabled: 1
exynos_asv_update_cpu_opp: Failed to add OPP 1900000000 Hz/1187500 uV for cpu4 (-17)

cpu cpu4: dev_pm_opp_set_rate: failed to find OPP for freq 1900000000 (-34)
exynos5433_asv_opp_get_voltage: arm,cortex-a57: [9] freq: 1600, voltage: 1137500 -> 1062500
cpufreq: __target_index: Failed to change cpu frequency: -34

Change-Id: Ibf6a568cabbd5380952d97f93d27ac59f1db125b
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
drivers/soc/samsung/exynos-asv.c

index f416e0f..611c374 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/bitrev.h>
 #include <linux/cpu.h>
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -46,6 +47,7 @@ int exynos_asv_update_cpu_opp(struct device *cpu)
        for (i = 0; i < subsys->dvfs_nr; i++) {
                unsigned int new_voltage;
                unsigned int voltage;
+               int timeout = 1000;
                int err;
 
                opp_freq = subsys->asv_table[i][0];
@@ -66,6 +68,14 @@ int exynos_asv_update_cpu_opp(struct device *cpu)
                opp_freq *= MHZ;
                dev_pm_opp_remove(cpu, opp_freq);
 
+               while (--timeout) {
+                       opp = dev_pm_opp_find_freq_exact(cpu, opp_freq, true);
+                       if (IS_ERR(opp))
+                               break;
+                       dev_pm_opp_put(opp);
+                       msleep(1);
+               }
+
                err = dev_pm_opp_add(cpu, opp_freq, new_voltage);
                if (err < 0)
                        pr_err("%s: Failed to add OPP %u Hz/%u uV for cpu%d\n",