ARM: tegra: power: Modify auto-hotplug locking
Alex Frid [Thu, 31 Mar 2011 03:31:30 +0000 (20:31 -0700)]
Use cpufreq (cpu DFS) mutex for auto-hotplug (instead of a separate
one) to serialize cpu frequency scaling, hotplug, and CPU mode switch
operations.

Original-Change-Id: I7ea865894d1676c865294ab31a903248d9437534
Reviewed-on: http://git-master/r/24893
Reviewed-by: Aleksandr Frid <afrid@nvidia.com>
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Original-Change-Id: I906a23561c1567079a41590a30b29b3d52fa5de8

Rebase-Id: R5d16154c91b41fd02f2a50af7ec6868a7958dc13

arch/arm/mach-tegra/cpu-tegra.c
arch/arm/mach-tegra/cpu-tegra3.c
arch/arm/mach-tegra/pm.h

index a71339f..9d3cf15 100644 (file)
@@ -275,11 +275,10 @@ static int tegra_target(struct cpufreq_policy *policy,
        target_cpu_speed[policy->cpu] = freq;
        new_speed = throttle_governor_speed(tegra_cpu_highest_speed());
        ret = tegra_update_cpu_speed(new_speed);
-out:
-       mutex_unlock(&tegra_cpu_lock);
-
        if (ret == 0)
                tegra_auto_hotplug_governor(new_speed);
+out:
+       mutex_unlock(&tegra_cpu_lock);
 
        return ret;
 }
@@ -391,7 +390,7 @@ static int __init tegra_cpufreq_init(void)
        throttle_lowest_index = table_data->throttle_lowest_index;
        throttle_highest_index = table_data->throttle_highest_index;
 #endif
-       ret = tegra_auto_hotplug_init();
+       ret = tegra_auto_hotplug_init(&tegra_cpu_lock);
        if (ret)
                return ret;
 
index fdc5331..8e4fe79 100644 (file)
@@ -42,7 +42,7 @@
 #define UP2Gn_DELAY_MS         1000
 #define DOWN_DELAY_MS          2000
 
-static DEFINE_MUTEX(tegra_hp_lock);
+static struct mutex *tegra3_cpu_lock;
 
 static struct workqueue_struct *hotplug_wq;
 static struct delayed_work hotplug_work;
@@ -132,7 +132,10 @@ static int hp_state_set(const char *arg, const struct kernel_param *kp)
        int ret = 0;
        int old_state;
 
-       mutex_lock(&tegra_hp_lock);
+       if (!tegra3_cpu_lock)
+               return ret;
+
+       mutex_lock(tegra3_cpu_lock);
 
        old_state = hp_state;
        ret = param_set_int(arg, kp);
@@ -159,7 +162,7 @@ static int hp_state_set(const char *arg, const struct kernel_param *kp)
                        hp_state = old_state;
                }
        }
-       mutex_unlock(&tegra_hp_lock);
+       mutex_unlock(tegra3_cpu_lock);
        return ret;
 }
 
@@ -180,7 +183,7 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work)
        bool up = false;
        unsigned int cpu = nr_cpu_ids;
 
-       mutex_lock(&tegra_hp_lock);
+       mutex_lock(tegra3_cpu_lock);
 
        switch (hp_state) {
        case TEGRA_HP_DISABLED:
@@ -224,7 +227,7 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work)
                pr_err("%s: invalid tegra hotplug state %d\n",
                       __func__, hp_state);
        }
-       mutex_unlock(&tegra_hp_lock);
+       mutex_unlock(tegra3_cpu_lock);
 
        if (cpu < nr_cpu_ids) {
                if (up)
@@ -241,7 +244,6 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq)
        if (!is_g_cluster_present())
                return;
 
-       mutex_lock(&tegra_hp_lock);
        up_delay = is_lp_cluster() ? up2g0_delay : up2gn_delay;
 
        switch (hp_state) {
@@ -281,10 +283,9 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq)
                       __func__, hp_state);
                BUG();
        }
-       mutex_unlock(&tegra_hp_lock);
 }
 
-int tegra_auto_hotplug_init(void)
+int tegra_auto_hotplug_init(struct mutex *cpu_lock)
 {
        /*
         * Not bound to the issuer CPU (=> high-priority), has rescue worker
@@ -310,6 +311,7 @@ int tegra_auto_hotplug_init(void)
        up2gn_delay = msecs_to_jiffies(UP2Gn_DELAY_MS);
        down_delay = msecs_to_jiffies(DOWN_DELAY_MS);
 
+       tegra3_cpu_lock = cpu_lock;
        hp_state = INITIAL_STATE;
        hp_init_stats();
        pr_info("Tegra auto-hotplug initialized: %s\n",
@@ -327,14 +329,14 @@ static int hp_stats_show(struct seq_file *s, void *data)
        int i;
        u64 cur_jiffies = get_jiffies_64();
 
-       mutex_lock(&tegra_hp_lock);
+       mutex_lock(tegra3_cpu_lock);
        if (hp_state != TEGRA_HP_DISABLED) {
                for (i = 0; i <= CONFIG_NR_CPUS; i++) {
                        bool was_up = (hp_stats[i].up_down_count & 0x1);
                        hp_stats_update(i, was_up);
                }
        }
-       mutex_unlock(&tegra_hp_lock);
+       mutex_unlock(tegra3_cpu_lock);
 
        seq_printf(s, "%-15s ", "cpu:");
        for (i = 0; i < CONFIG_NR_CPUS; i++) {
@@ -375,6 +377,9 @@ static const struct file_operations hp_stats_fops = {
 
 static int __init tegra_auto_hotplug_debug_init(void)
 {
+       if (!tegra3_cpu_lock)
+               return -ENOENT;
+
        hp_debugfs_root = debugfs_create_dir("tegra_hotplug", NULL);
        if (!hp_debugfs_root)
                return -ENOMEM;
index f7522c2..effa054 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef _MACH_TEGRA_SUSPEND_H_
 #define _MACH_TEGRA_SUSPEND_H_
 
+#include <linux/mutex.h>
+
 enum tegra_suspend_mode {
        TEGRA_SUSPEND_NONE = 0,
        TEGRA_SUSPEND_LP2,      /* CPU voltage off */
@@ -70,11 +72,11 @@ void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat);
 void tegra_idle_lp2(void);
 
 #if defined(CONFIG_TEGRA_AUTO_HOTPLUG) && !defined(CONFIG_ARCH_TEGRA_2x_SOC)
-int tegra_auto_hotplug_init(void);
+int tegra_auto_hotplug_init(struct mutex *cpu_lock);
 void tegra_auto_hotplug_exit(void);
 void tegra_auto_hotplug_governor(unsigned int cpu_freq);
 #else
-static inline int tegra_auto_hotplug_init(void)
+static inline int tegra_auto_hotplug_init(struct mutex *cpu_lock)
 { return 0; }
 static inline void tegra_auto_hotplug_exit(void)
 { }