diff options
author | Alex Frid <afrid@nvidia.com> | 2011-04-21 21:33:12 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 00:53:07 -0700 |
commit | 686201879f274e07a01d1c5184adda335eaccd66 (patch) | |
tree | 13fadebc95f2cd8249993ba68569aa364f8da994 /arch/arm/mach-tegra/cpu-tegra3.c | |
parent | 18f481749360fa079507e1c4a7b6c78d2fa68042 (diff) |
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 <afrid@nvidia.com>
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com>
Tested-by: Diwakar Tundlam <dtundlam@nvidia.com>
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Rebase-Id: Rc5c717454d1e09ca97ccc79fff60cb33fcf854e9
Diffstat (limited to 'arch/arm/mach-tegra/cpu-tegra3.c')
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra3.c | 51 |
1 files changed, 43 insertions, 8 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra3.c b/arch/arm/mach-tegra/cpu-tegra3.c index 9d42f77c2513..d629dc704594 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", |