From d294fdf2ffc18563bdd3a14b7574b46526763be8 Mon Sep 17 00:00:00 2001 From: Joshua Primero Date: Thu, 9 Feb 2012 12:03:00 -0800 Subject: ARM: tegra: Object based balanced throttling Implemented an object based balanced throttling in preparation for multiple balanced throttling objects. bug 1007726 Change-Id: Ib58fafaf696af0ae58e78bd9fd417d3a822d0571 Signed-off-by: Joshua Primero Reviewed-on: http://git-master/r/105238 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Sachin Nikam --- arch/arm/mach-tegra/cpu-tegra.c | 3 - arch/arm/mach-tegra/include/mach/thermal.h | 29 +++- arch/arm/mach-tegra/tegra3_thermal.c | 147 +++++++++++------- arch/arm/mach-tegra/tegra3_throttle.c | 229 ++++++++++++++++++----------- 4 files changed, 267 insertions(+), 141 deletions(-) diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c index 5c680b849435..9bed9270b412 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/arch/arm/mach-tegra/cpu-tegra.c @@ -435,9 +435,6 @@ static int __init tegra_cpu_debug_init(void) if (!cpu_tegra_debugfs_root) return -ENOMEM; - if (tegra_throttle_debug_init(cpu_tegra_debugfs_root)) - goto err_out; - if (tegra_edp_debug_init(cpu_tegra_debugfs_root)) goto err_out; diff --git a/arch/arm/mach-tegra/include/mach/thermal.h b/arch/arm/mach-tegra/include/mach/thermal.h index 67586224cead..78599971cd9f 100644 --- a/arch/arm/mach-tegra/include/mach/thermal.h +++ b/arch/arm/mach-tegra/include/mach/thermal.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/thermal.h * - * Copyright (C) 2010-2011 NVIDIA Corporation. + * Copyright (C) 2010-2012 NVIDIA Corporation. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -42,8 +42,35 @@ struct tegra_thermal_device { int (*set_limits) (void *, long, long); int (*set_alert)(void *, void (*)(void *), void *); int (*set_shutdown_temp)(void *, long); +#ifdef CONFIG_TEGRA_THERMAL_THROTTLE + struct thermal_zone_device *thz; +#endif +}; + +#ifdef CONFIG_TEGRA_THERMAL_THROTTLE +struct throttle_table { + unsigned int cpu_freq; + int core_cap_level; }; +struct balanced_throttle { + int id; + struct throttle_table *throt_tab; + int throt_tab_size; + + int is_throttling; + int throttle_index; + struct thermal_cooling_device *cdev; + + struct list_head node; +}; + +struct balanced_throttle *balanced_throttle_register( + int id, + struct throttle_table *table, + int tab_size); +#endif + #ifndef CONFIG_ARCH_TEGRA_2x_SOC int tegra_thermal_init(struct tegra_thermal_data *data); int tegra_thermal_set_device(struct tegra_thermal_device *device); diff --git a/arch/arm/mach-tegra/tegra3_thermal.c b/arch/arm/mach-tegra/tegra3_thermal.c index 6322eb35ab79..d94158aff7d2 100644 --- a/arch/arm/mach-tegra/tegra3_thermal.c +++ b/arch/arm/mach-tegra/tegra3_thermal.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/tegra3_thermal.c * - * Copyright (C) 2010-2011 NVIDIA Corporation. + * Copyright (C) 2010-2012 NVIDIA Corporation. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -40,7 +40,6 @@ struct tegra_thermal { long temp_shutdown_tj; #ifdef CONFIG_TEGRA_THERMAL_THROTTLE long temp_throttle_tj; - struct thermal_zone_device *thz; int tc1; int tc2; long passive_delay; @@ -59,6 +58,24 @@ static struct tegra_thermal thermal_state = { .edp_thermal_zone_val = -1, #endif }; +#ifdef CONFIG_TEGRA_THERMAL_THROTTLE +static struct throttle_table tj_bthrot_table[] = { + { 0, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 760000, 1000 }, + { 760000, 1050 }, + {1000000, 1050 }, + {1000000, 1100 }, +}; + +static struct balanced_throttle *tj_bthrot; + +#define TJ_BALANCED_THROTTLE_ID (0) +#endif #ifdef CONFIG_TEGRA_EDP_LIMITS static inline long edp2tj(struct tegra_thermal *thermal, @@ -86,25 +103,54 @@ static inline long tj2dev(struct tegra_thermal_device *dev, return tj_temp - dev->offset; } +static int tegra_thermal_get_tj_temp(long *tj_temp) +{ + long temp_dev; + struct tegra_thermal *thermal = &thermal_state; + + if (!thermal->device) + return -1; + + thermal->device->get_temp(thermal->device->data, + &temp_dev); + *tj_temp = dev2tj(thermal->device, temp_dev); + + return 0; +} + #ifdef CONFIG_TEGRA_THERMAL_THROTTLE -static int tegra_thermal_zone_bind(struct thermal_zone_device *thermal, +static int tegra_thermal_zone_bind(struct thermal_zone_device *thz, struct thermal_cooling_device *cdevice) { - /* Support only Thermal Throttling (1 trip) for now */ - return thermal_zone_bind_cooling_device(thermal, 0, cdevice); + + struct balanced_throttle *bthrot = cdevice->devdata; + struct tegra_thermal_device *device = thz->devdata; + + if ((bthrot->id == TJ_BALANCED_THROTTLE_ID) && + (device == thermal_state.device)) + return thermal_zone_bind_cooling_device(thz, 0, cdevice); + + return 0; } -static int tegra_thermal_zone_unbind(struct thermal_zone_device *thermal, +static int tegra_thermal_zone_unbind(struct thermal_zone_device *thz, struct thermal_cooling_device *cdevice) { - /* Support only Thermal Throttling (1 trip) for now */ - return thermal_zone_unbind_cooling_device(thermal, 0, cdevice); + struct balanced_throttle *bthrot = cdevice->devdata; + struct tegra_thermal_device *device = thz->devdata; + + if ((bthrot->id == TJ_BALANCED_THROTTLE_ID) && + (device == thermal_state.device)) + return thermal_zone_unbind_cooling_device(thz, 0, cdevice); + + return 0; } static int tegra_thermal_zone_get_temp(struct thermal_zone_device *thz, unsigned long *temp) { - struct tegra_thermal *thermal = thz->devdata; - thermal->device->get_temp(thermal->device->data, temp); + struct tegra_thermal_device *device = thz->devdata; + + device->get_temp(device->data, temp); return 0; } @@ -113,8 +159,6 @@ static int tegra_thermal_zone_get_trip_type( struct thermal_zone_device *thermal, int trip, enum thermal_trip_type *type) { - - /* Support only Thermal Throttling (1 trip) for now */ if (trip != 0) return -EINVAL; @@ -126,13 +170,12 @@ static int tegra_thermal_zone_get_trip_type( static int tegra_thermal_zone_get_trip_temp(struct thermal_zone_device *thz, int trip, unsigned long *temp) { - struct tegra_thermal *thermal = thz->devdata; + struct tegra_thermal_device *device = thz->devdata; - /* Support only Thermal Throttling (1 trip) for now */ if (trip != 0) return -EINVAL; - *temp = tj2dev(thermal->device, thermal->temp_throttle_tj); + *temp = tj2dev(device, thermal_state.temp_throttle_tj); return 0; } @@ -150,8 +193,7 @@ static struct thermal_zone_device_ops tegra_thermal_zone_ops = { void tegra_thermal_alert(void *data) { struct tegra_thermal *thermal = data; - int err; - long temp_dev, temp_tj; + long temp_tj; long lo_limit_throttle_tj, hi_limit_throttle_tj; long lo_limit_edp_tj = 0, hi_limit_edp_tj = 0; long temp_low_dev, temp_low_tj; @@ -168,21 +210,16 @@ void tegra_thermal_alert(void *data) mutex_lock(&thermal_state.mutex); #ifdef CONFIG_TEGRA_THERMAL_THROTTLE - if (thermal->thz) { - if (!thermal->thz->passive) - thermal_zone_device_update(thermal->thz); + if (thermal->device->thz) { + if (!thermal->device->thz->passive) + thermal_zone_device_update(thermal->device->thz); } #endif - err = thermal->device->get_temp(thermal->device->data, &temp_dev); - if (err) { - pr_err("%s: get temp fail(%d)", __func__, err); - goto done; - } - /* Convert all temps to tj and then do all work/logic in terms of tj in order to avoid confusion */ - temp_tj = dev2tj(thermal->device, temp_dev); + if (tegra_thermal_get_tj_temp(&temp_tj)) + goto done; thermal->device->get_temp_low(thermal->device, &temp_low_dev); temp_low_tj = dev2tj(thermal->device, temp_low_dev); @@ -248,6 +285,8 @@ done: mutex_unlock(&thermal_state.mutex); } + + int tegra_thermal_set_device(struct tegra_thermal_device *device) { #ifdef CONFIG_TEGRA_THERMAL_THROTTLE @@ -261,29 +300,35 @@ int tegra_thermal_set_device(struct tegra_thermal_device *device) thermal_state.device = device; #ifdef CONFIG_TEGRA_THERMAL_THROTTLE - thz = thermal_zone_device_register(thermal_state.device->name, + thz = thermal_zone_device_register(device->name, 1, /* trips */ - &thermal_state, + device, &tegra_thermal_zone_ops, thermal_state.tc1, /* dT/dt */ thermal_state.tc2, /* throttle */ thermal_state.passive_delay, 0); /* polling delay */ + if (IS_ERR_OR_NULL(thz)) + return -ENODEV; - if (IS_ERR(thz)) { - thz = NULL; + device->thz = thz; + + tj_bthrot = balanced_throttle_register( + TJ_BALANCED_THROTTLE_ID, + tj_bthrot_table, + ARRAY_SIZE(tj_bthrot_table)); + if (IS_ERR_OR_NULL(tj_bthrot)) return -ENODEV; - } - thermal_state.thz = thz; #endif - thermal_state.device->set_alert(thermal_state.device->data, - tegra_thermal_alert, - &thermal_state); + device->set_alert(device->data, + tegra_thermal_alert, + &thermal_state); - thermal_state.device->set_shutdown_temp(thermal_state.device->data, + device->set_shutdown_temp(device->data, tj2dev(device, thermal_state.temp_shutdown_tj)); + /* initialize limits */ tegra_thermal_alert(&thermal_state); @@ -313,8 +358,8 @@ int __init tegra_thermal_init(struct tegra_thermal_data *data) int tegra_thermal_exit(void) { #ifdef CONFIG_TEGRA_THERMAL_THROTTLE - if (thermal_state.thz) - thermal_zone_device_unregister(thermal_state.thz); + if (thermal_state.device->thz) + thermal_zone_device_unregister(thermal_state.device->thz); #endif return 0; @@ -375,18 +420,10 @@ DEFINE_SIMPLE_ATTRIBUTE(shutdown_temp_tj_fops, static int tegra_thermal_temp_tj_get(void *data, u64 *val) { - long temp_tj, temp_dev; - - if (thermal_state.device) { - thermal_state.device->get_temp(thermal_state.device->data, - &temp_dev); + long temp_tj; - /* Convert all temps to tj and then do all work/logic in - terms of tj in order to avoid confusion */ - temp_tj = dev2tj(thermal_state.device, temp_dev); - } else { + if (tegra_thermal_get_tj_temp(&temp_tj)) temp_tj = -1; - } *val = (u64)temp_tj; @@ -401,13 +438,13 @@ DEFINE_SIMPLE_ATTRIBUTE(temp_tj_fops, #ifdef CONFIG_TEGRA_THERMAL_THROTTLE static int tegra_thermal_tc1_set(void *data, u64 val) { - thermal_state.thz->tc1 = val; + thermal_state.device->thz->tc1 = val; return 0; } static int tegra_thermal_tc1_get(void *data, u64 *val) { - *val = (u64)thermal_state.thz->tc1; + *val = (u64)thermal_state.device->thz->tc1; return 0; } @@ -418,13 +455,13 @@ DEFINE_SIMPLE_ATTRIBUTE(tc1_fops, static int tegra_thermal_tc2_set(void *data, u64 val) { - thermal_state.thz->tc2 = val; + thermal_state.device->thz->tc2 = val; return 0; } static int tegra_thermal_tc2_get(void *data, u64 *val) { - *val = (u64)thermal_state.thz->tc2; + *val = (u64)thermal_state.device->thz->tc2; return 0; } @@ -435,13 +472,13 @@ DEFINE_SIMPLE_ATTRIBUTE(tc2_fops, static int tegra_thermal_passive_delay_set(void *data, u64 val) { - thermal_state.thz->passive_delay = val; + thermal_state.device->thz->passive_delay = val; return 0; } static int tegra_thermal_passive_delay_get(void *data, u64 *val) { - *val = (u64)thermal_state.thz->passive_delay; + *val = (u64)thermal_state.device->thz->passive_delay; return 0; } diff --git a/arch/arm/mach-tegra/tegra3_throttle.c b/arch/arm/mach-tegra/tegra3_throttle.c index 9e8d32fb79fa..61dc5cdb6a7d 100644 --- a/arch/arm/mach-tegra/tegra3_throttle.c +++ b/arch/arm/mach-tegra/tegra3_throttle.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/tegra3_throttle.c * - * Copyright (c) 2011, NVIDIA Corporation. + * Copyright (c) 2011-2012, NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,37 +27,28 @@ #include #include #include +#include #include "clock.h" #include "cpu-tegra.h" #include "dvfs.h" -/* tegra throttling require frequencies in the table to be in ascending order */ -static struct cpufreq_frequency_table *cpu_freq_table; -static struct { - unsigned int cpu_freq; - int core_cap_level; -} throttle_table[] = { - { 0, 1000 }, /* placeholder for cpu floor rate */ - { 640000, 1000 }, - { 640000, 1000 }, - { 640000, 1000 }, - { 640000, 1000 }, - { 640000, 1000 }, - { 760000, 1000 }, - { 760000, 1050 }, - {1000000, 1050 }, - {1000000, 1100 }, -}; - -static int is_throttling; -static int throttle_index; -static struct thermal_cooling_device *cdev; +static struct mutex *cpu_throttle_lock; +static DEFINE_MUTEX(bthrot_list_lock); +static LIST_HEAD(bthrot_list); static unsigned int clip_to_table(unsigned int cpu_freq) { int i; + struct cpufreq_frequency_table *cpu_freq_table; + struct tegra_cpufreq_table_data *table_data = + tegra_cpufreq_table_get(); + + if (IS_ERR_OR_NULL(table_data)) + return -EINVAL; + + cpu_freq_table = table_data->freq_table; for (i = 0; cpu_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { if (cpu_freq_table[i].frequency > cpu_freq) @@ -69,13 +60,37 @@ static unsigned int clip_to_table(unsigned int cpu_freq) unsigned int tegra_throttle_governor_speed(unsigned int requested_speed) { - return is_throttling ? - min(requested_speed, throttle_table[throttle_index].cpu_freq) : - requested_speed; + struct balanced_throttle *bthrot; + unsigned int throttle_speed = requested_speed; + int index; + + mutex_lock(&bthrot_list_lock); + list_for_each_entry(bthrot, &bthrot_list, node) { + if (bthrot->is_throttling) { + index = bthrot->throttle_index; + throttle_speed = min(throttle_speed, + bthrot->throt_tab[index].cpu_freq); + } + } + mutex_unlock(&bthrot_list_lock); + + return throttle_speed; } bool tegra_is_throttling(void) { + struct balanced_throttle *bthrot; + bool is_throttling = false; + + mutex_lock(&bthrot_list_lock); + list_for_each_entry(bthrot, &bthrot_list, node) { + if (bthrot->is_throttling) { + is_throttling = true; + break; + } + } + mutex_unlock(&bthrot_list_lock); + return is_throttling; } @@ -83,7 +98,10 @@ static int tegra_throttle_get_max_state(struct thermal_cooling_device *cdev, unsigned long *max_state) { - *max_state = ARRAY_SIZE(throttle_table); + struct balanced_throttle *bthrot = cdev->devdata; + + *max_state = bthrot->throt_tab_size; + return 0; } @@ -91,9 +109,13 @@ static int tegra_throttle_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *cur_state) { - *cur_state = is_throttling ? - (ARRAY_SIZE(throttle_table) - throttle_index) : + struct balanced_throttle *bthrot = cdev->devdata; + + mutex_lock(cpu_throttle_lock); + *cur_state = bthrot->is_throttling ? + (bthrot->throt_tab_size - bthrot->throttle_index) : 0; + mutex_unlock(cpu_throttle_lock); return 0; } @@ -102,84 +124,55 @@ static int tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev, unsigned long cur_state) { + struct balanced_throttle *bthrot = cdev->devdata; int core_level; + int index; + mutex_lock(cpu_throttle_lock); if (cur_state == 0) { /* restore speed requested by governor */ - if (is_throttling) { + if (bthrot->is_throttling) { tegra_dvfs_core_cap_enable(false); - is_throttling = false; + bthrot->is_throttling = false; } tegra_cpu_set_speed_cap(NULL); } else { - if (!is_throttling) { + if (!bthrot->is_throttling) { tegra_dvfs_core_cap_enable(true); - is_throttling = true; + bthrot->is_throttling = true; } - throttle_index = ARRAY_SIZE(throttle_table) - cur_state; - core_level = throttle_table[throttle_index].core_cap_level; + bthrot->throttle_index = bthrot->throt_tab_size - cur_state; + index = bthrot->throttle_index; + core_level = bthrot->throt_tab[index].core_cap_level; tegra_dvfs_core_cap_level_set(core_level); tegra_cpu_set_speed_cap(NULL); } + mutex_unlock(cpu_throttle_lock); return 0; } -struct thermal_cooling_device_ops tegra_throttle_cooling_ops = { +static struct thermal_cooling_device_ops tegra_throttle_cooling_ops = { .get_max_state = tegra_throttle_get_max_state, .get_cur_state = tegra_throttle_get_cur_state, .set_cur_state = tegra_throttle_set_cur_state, }; -int __init tegra_throttle_init(struct mutex *cpu_lock) -{ - int i; - struct tegra_cpufreq_table_data *table_data = - tegra_cpufreq_table_get(); - if (IS_ERR_OR_NULL(table_data)) - return -EINVAL; - - cpu_freq_table = table_data->freq_table; - throttle_table[0].cpu_freq = - cpu_freq_table[table_data->throttle_lowest_index].frequency; - - for (i = 0; i < ARRAY_SIZE(throttle_table); i++) { - unsigned int cpu_freq = throttle_table[i].cpu_freq; - throttle_table[i].cpu_freq = clip_to_table(cpu_freq); - } - - cdev = thermal_cooling_device_register("Throttle", NULL, - &tegra_throttle_cooling_ops); - - if (IS_ERR(cdev)) { - cdev = NULL; - return -ENODEV; - } - - return 0; -} - -void tegra_throttle_exit(void) -{ - if (cdev) { - thermal_cooling_device_unregister(cdev); - cdev = NULL; - } -} - #ifdef CONFIG_DEBUG_FS static int table_show(struct seq_file *s, void *data) { + struct balanced_throttle *bthrot = s->private; int i; - for (i = 0; i < ARRAY_SIZE(throttle_table); i++) + for (i = 0; i < bthrot->throt_tab_size; i++) seq_printf(s, "[%d] = %7u %4d\n", - i, throttle_table[i].cpu_freq, - throttle_table[i].core_cap_level); + i, bthrot->throt_tab[i].cpu_freq, + bthrot->throt_tab[i].core_cap_level); + return 0; } @@ -191,6 +184,7 @@ static int table_open(struct inode *inode, struct file *file) static ssize_t table_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { + struct balanced_throttle *bthrot = file->private_data; char buf[80]; int table_idx; unsigned int cpu_freq; @@ -211,12 +205,12 @@ static ssize_t table_write(struct file *file, &table_idx, &cpu_freq, &core_cap_level) != 3) return -1; - if ((table_idx < 0) || (table_idx >= ARRAY_SIZE(throttle_table))) + if ((table_idx < 0) || (table_idx >= bthrot->throt_tab_size)) return -EINVAL; /* round new settings before updating table */ - throttle_table[table_idx].cpu_freq = clip_to_table(cpu_freq); - throttle_table[table_idx].core_cap_level = (core_cap_level / 50) * 50; + bthrot->throt_tab[table_idx].cpu_freq = clip_to_table(cpu_freq); + bthrot->throt_tab[table_idx].core_cap_level = (core_cap_level / 50) * 50; return count; } @@ -229,14 +223,85 @@ static const struct file_operations table_fops = { .release = single_release, }; +static struct dentry *throttle_debugfs_root; +#endif /* CONFIG_DEBUG_FS */ -int __init tegra_throttle_debug_init(struct dentry *cpu_tegra_debugfs_root) + +struct balanced_throttle *balanced_throttle_register( + int id, + struct throttle_table *table, + int tab_size) { - if (!debugfs_create_file("throttle_table", 0644, cpu_tegra_debugfs_root, - NULL, &table_fops)) - return -ENOMEM; + struct balanced_throttle *bthrot; + char name[32]; + int i, index; + struct cpufreq_frequency_table *cpu_freq_table; + struct tegra_cpufreq_table_data *table_data = + tegra_cpufreq_table_get(); + if (IS_ERR_OR_NULL(table_data)) + return ERR_PTR(-EINVAL); + + cpu_freq_table = table_data->freq_table; + + bthrot = kzalloc(sizeof(struct balanced_throttle), GFP_KERNEL); + + if (!bthrot) + return ERR_PTR(-ENOMEM); + + bthrot->id = id; + bthrot->throt_tab = table; + bthrot->throt_tab_size = tab_size; + + + for (i = 0; i < bthrot->throt_tab_size; i++) { + unsigned int cpu_freq = bthrot->throt_tab[i].cpu_freq; + if (cpu_freq == 0) { + index = table_data->throttle_lowest_index; + cpu_freq = cpu_freq_table[index].frequency; + } else { + cpu_freq = clip_to_table(cpu_freq); + } + bthrot->throt_tab[i].cpu_freq = cpu_freq; + } + + bthrot->cdev = thermal_cooling_device_register( + "balanced", + bthrot, + &tegra_throttle_cooling_ops); + + if (IS_ERR(bthrot->cdev)) { + bthrot->cdev = NULL; + kfree(bthrot); + return ERR_PTR(-ENODEV); + } + + mutex_lock(&bthrot_list_lock); + list_add(&bthrot->node, &bthrot_list); + mutex_unlock(&bthrot_list_lock); + +#ifdef CONFIG_DEBUG_FS + sprintf(name, "throttle_table%d", id); + debugfs_create_file(name,0644, throttle_debugfs_root, + bthrot, &table_fops); +#endif + + return bthrot; +} + +int __init tegra_throttle_init(struct mutex *cpu_lock) +{ + cpu_throttle_lock = cpu_lock; +#ifdef CONFIG_DEBUG_FS + throttle_debugfs_root = debugfs_create_dir("tegra_throttle", 0); +#endif return 0; } -#endif /* CONFIG_DEBUG_FS */ + +void tegra_throttle_exit(void) +{ +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(throttle_debugfs_root); +#endif +} -- cgit v1.2.3