From 6a1aa24e805fabf26efa11b2af0f0183ab1aeda4 Mon Sep 17 00:00:00 2001 From: Alex Frid Date: Thu, 21 Apr 2011 21:33:12 -0700 Subject: ARM: tegra: power: Check Tegra3 auto-hotplug speed balance When current CPU complex frequency is above target range: - bring new core on-line only if cpufreq governor requests for all already on-lined CPUs are above 50% of current CPU frequency - off-line one core (despite high pick request) if cpufreq governor requests for at least 2 on-lined CPUs are below 25% of current CPU frequency - do nothing if neither of the above conditions is true Original-Change-Id: I77e1bd543a8fadd51974f7d574f256a6e7e2979a Reviewed-on: http://git-master/r/29702 Reviewed-by: Aleksandr Frid Tested-by: Aleksandr Frid Reviewed-by: Diwakar Tundlam Tested-by: Diwakar Tundlam Reviewed-by: Scott Williams Rebase-Id: Rc5c717454d1e09ca97ccc79fff60cb33fcf854e9 --- arch/arm/mach-tegra/cpu-tegra3.c | 51 +++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 8 deletions(-) (limited to 'arch/arm/mach-tegra/cpu-tegra3.c') diff --git a/arch/arm/mach-tegra/cpu-tegra3.c b/arch/arm/mach-tegra/cpu-tegra3.c index 88adea4fd792..acd6889e54f7 100644 --- a/arch/arm/mach-tegra/cpu-tegra3.c +++ b/arch/arm/mach-tegra/cpu-tegra3.c @@ -178,6 +178,26 @@ static struct kernel_param_ops tegra_hp_state_ops = { module_param_cb(auto_hotplug, &tegra_hp_state_ops, &hp_state, 0644); +enum { + TEGRA_CPU_SPEED_BALANCED, + TEGRA_CPU_SPEED_BIASED, + TEGRA_CPU_SPEED_SKEWED, +}; + +static int tegra_cpu_speed_balance(void) +{ + unsigned long highest_speed = tegra_cpu_highest_speed(); + + /* balanced: freq targets for all CPUs are above 50% of highest speed + biased: freq target for at least one CPU is below 50% threshold + skewed: freq targets for at least 2 CPUs are below 25% threshold */ + if (tegra_count_slow_cpus(highest_speed / 4) >= 2) + return TEGRA_CPU_SPEED_SKEWED; + else if (tegra_count_slow_cpus(highest_speed / 2) >= 1) + return TEGRA_CPU_SPEED_BIASED; + return TEGRA_CPU_SPEED_BALANCED; +} + static void tegra_auto_hotplug_work_func(struct work_struct *work) { bool up = false; @@ -213,17 +233,32 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work) /* catch-up with governor target speed */ tegra_cpu_cap_highest_speed(NULL); } - queue_delayed_work( - hotplug_wq, &hotplug_work, up2gn_delay); } else { - cpu = cpumask_next_zero(0, cpu_online_mask); - if (cpu < nr_cpu_ids) { - up = true; - queue_delayed_work( - hotplug_wq, &hotplug_work, up2gn_delay); - hp_stats_update(cpu, true); + switch (tegra_cpu_speed_balance()) { + /* cpu speed is up and balanced - one more on-line */ + case TEGRA_CPU_SPEED_BALANCED: + cpu = cpumask_next_zero(0, cpu_online_mask); + if (cpu < nr_cpu_ids) { + up = true; + hp_stats_update(cpu, true); + } + break; + /* cpu speed is up, but skewed - remove one core */ + case TEGRA_CPU_SPEED_SKEWED: + cpu = tegra_get_slowest_cpu_n(); + if (cpu < nr_cpu_ids) { + up = false; + hp_stats_update(cpu, false); + } + break; + /* cpu speed is up, but under-utilized - do nothing */ + case TEGRA_CPU_SPEED_BIASED: + default: + break; } } + queue_delayed_work( + hotplug_wq, &hotplug_work, up2gn_delay); break; default: pr_err("%s: invalid tegra hotplug state %d\n", -- cgit v1.2.3