ARM: tegra: dvfs: Handle Tegra3 alternative dvfs errors
Rohan Somvanshi [Tue, 3 Jul 2012 12:28:01 +0000 (12:28 +0000)]
Propagate error to the caller when switching between alternative
cpu dvfs tables. Change dvfs table during cpu hotplug operation
only after the new edp limit is set, and abort bringing cpu core
on-line in case of failure in applying new (less conservative)
table. When cpu core is removed change dvfs table before setting
new edp limit, and ignore error (it is safe to continue with more
conservative table).

Signed-off-by: Alex Frid <afrid@nvidia.com>
(cherry picked from commit 951710ec179fd620a2251d0815ca7bff15da014b)

Change-Id: Ib1ad8e41093fb9bee75d3d6bd18d0ac406da8271
Reviewed-on: http://git-master/r/114779
Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>

arch/arm/mach-tegra/cpu-tegra.c
arch/arm/mach-tegra/dvfs.h
arch/arm/mach-tegra/tegra3_dvfs.c

index afd91ab..5a07034 100644 (file)
@@ -7,7 +7,7 @@
  *     Colin Cross <ccross@google.com>
  *     Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation
  *
- * Copyright (C) 2010-2012 NVIDIA Corporation
+ * Copyright (C) 2010-2012 NVIDIA CORPORATION. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -241,12 +241,12 @@ int tegra_edp_update_thermal_zone(int temperature)
 
        /* Update cpu rate if cpufreq (at least on cpu0) is already started;
           alter cpu dvfs table for this thermal zone if necessary */
-       tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, true);
+       tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, true, 0);
        if (target_cpu_speed[0]) {
                edp_update_limit();
                tegra_cpu_set_speed_cap(NULL);
        }
-       tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false);
+       tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false, 0);
        mutex_unlock(&tegra_cpu_lock);
 
        return ret;
@@ -320,31 +320,31 @@ static int tegra_cpu_edp_notify(
        case CPU_UP_PREPARE:
                mutex_lock(&tegra_cpu_lock);
                cpu_set(cpu, edp_cpumask);
-               tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, true);
                edp_update_limit();
 
                cpu_speed = tegra_getspeed(0);
                new_speed = edp_governor_speed(cpu_speed);
                if (new_speed < cpu_speed) {
                        ret = tegra_cpu_set_speed_cap(NULL);
-                       if (ret) {
-                               cpu_clear(cpu, edp_cpumask);
-                               edp_update_limit();
-                       }
-
-                       printk(KERN_DEBUG "tegra CPU:%sforce EDP limit %u kHz"
+                       printk(KERN_DEBUG "cpu-tegra:%sforce EDP limit %u kHz"
                                "\n", ret ? " failed to " : " ", new_speed);
                }
-               tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false);
+               if (!ret)
+                       ret = tegra_cpu_dvfs_alter(
+                               edp_thermal_index, &edp_cpumask, false, event);
+               if (ret) {
+                       cpu_clear(cpu, edp_cpumask);
+                       edp_update_limit();
+               }
                mutex_unlock(&tegra_cpu_lock);
                break;
        case CPU_DEAD:
                mutex_lock(&tegra_cpu_lock);
                cpu_clear(cpu, edp_cpumask);
-               tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, true);
+               tegra_cpu_dvfs_alter(
+                       edp_thermal_index, &edp_cpumask, true, event);
                edp_update_limit();
                tegra_cpu_set_speed_cap(NULL);
-               tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false);
                mutex_unlock(&tegra_cpu_lock);
                break;
        }
index 0c93775..712edca 100644 (file)
@@ -5,7 +5,7 @@
  * Author:
  *     Colin Cross <ccross@google.com>
  *
- * Copyright (C) 2010-2011 NVIDIA Corporation.
+ * Copyright (C) 2010-2012 NVIDIA CORPORATION. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -120,8 +120,8 @@ int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate);
 void tegra_dvfs_core_cap_enable(bool enable);
 void tegra_dvfs_core_cap_level_set(int level);
 int tegra_dvfs_alt_freqs_set(struct dvfs *d, unsigned long *alt_freqs);
-void tegra_cpu_dvfs_alter(
-       int edp_thermal_index, const cpumask_t *cpus, bool before_clk_update);
+int tegra_cpu_dvfs_alter(int edp_thermal_index, const cpumask_t *cpus,
+                        bool before_clk_update, int cpu_event);
 
 #ifndef CONFIG_ARCH_TEGRA_2x_SOC
 int tegra_dvfs_rail_disable_prepare(struct dvfs_rail *rail);
index 70df242..12c0281 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-tegra/tegra3_dvfs.c
  *
- * Copyright (C) 2010-2012, NVIDIA Corporation.
+ * Copyright (C) 2010-2012 NVIDIA CORPORATION. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -693,19 +693,23 @@ void __init tegra3_init_dvfs(void)
                tegra_dvfs_core_disabled ? "disabled" : "enabled");
 }
 
-void tegra_cpu_dvfs_alter(int edp_thermal_index, const cpumask_t *cpus,
-                         bool before_clk_update)
+int tegra_cpu_dvfs_alter(int edp_thermal_index, const cpumask_t *cpus,
+                         bool before_clk_update, int cpu_event)
 {
        bool cpu_warm = !!edp_thermal_index;
        unsigned int n = cpumask_weight(cpus);
        unsigned long *alt_freqs = cpu_warm ?
                (n > 1 ? NULL : cpu_0_freqs) : cpu_cold_freqs;
 
-       if (cpu_warm == before_clk_update) {
+       if (cpu_event || (cpu_warm == before_clk_update)) {
                int ret = tegra_dvfs_alt_freqs_set(cpu_dvfs, alt_freqs);
-               WARN_ONCE(ret, "tegra dvfs: failed to update CPU alternative"
-                              " frequency limits\n");
+               if (ret) {
+                       pr_err("tegra dvfs: failed to set alternative dvfs on "
+                              "%u %s CPUs\n", n, cpu_warm ? "warm" : "cold");
+                       return ret;
+               }
        }
+       return 0;
 }
 
 int tegra_dvfs_rail_disable_prepare(struct dvfs_rail *rail)