diff options
author | Ilan Aelion <iaelion@nvidia.com> | 2012-10-23 12:43:53 -0600 |
---|---|---|
committer | Riham Haidar <rhaidar@nvidia.com> | 2013-03-13 16:22:35 -0700 |
commit | 84d79a515e3074d390a91755f931def47ff383c7 (patch) | |
tree | a63b97138fa9f1d55ec113f9974929360bdc7905 | |
parent | 0ad2213531f3270c2e0a2ffcf824c46623c9b687 (diff) |
video: tegra: host: add 3dfs user space control
Additional sysfs nodes user and freq_request may be used to control
gpu frequency. If user is set to non-zero, the value of freq_request
is used for setting the gpu frequency. freq_request is initialized to
the max gpu frequency.
Bug 1161410
Change-Id: I4065397450fd8774fbe7715145ab481698d41929
Signed-off-by: Ilan Aelion <iaelion@nvidia.com>
Reviewed-on: http://git-master/r/#change,165100
(cherry picked from commit 3668de9c7b71634a8f2afdada1b8c381c07a9bc4)
Reviewed-on: http://git-master/r/199922
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r-- | drivers/video/tegra/host/gr3d/pod_scaling.c | 219 | ||||
-rw-r--r-- | include/trace/events/nvhost_podgov.h | 34 |
2 files changed, 247 insertions, 6 deletions
diff --git a/drivers/video/tegra/host/gr3d/pod_scaling.c b/drivers/video/tegra/host/gr3d/pod_scaling.c index ddde17d6dbf9..06683aafb577 100644 --- a/drivers/video/tegra/host/gr3d/pod_scaling.c +++ b/drivers/video/tegra/host/gr3d/pod_scaling.c @@ -3,7 +3,7 @@ * * Tegra Graphics Host 3D clock scaling * - * Copyright (c) 2012, NVIDIA Corporation. + * Copyright (c) 2013, NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -65,6 +65,8 @@ static int podgov_is_enabled(struct device *dev); static void podgov_enable(struct device *dev, int enable); +static int podgov_user_ctl(struct device *dev); +static void podgov_set_user_ctl(struct device *dev, int enable); /******************************************************************************* * podgov_info_rec - gr3d scaling governor specific parameters @@ -104,6 +106,8 @@ struct podgov_info_rec { unsigned int p_idle_max; unsigned int idle_max; unsigned int p_adjust; + unsigned int p_user; + unsigned int p_freq_request; long last_total_idle; long total_idle; @@ -291,6 +295,127 @@ static void podgov_enable(struct device *dev, int enable) } /******************************************************************************* + * podgov_user_ctl(dev) + * + * Check whether the gpu scaling is set to user space control. + ******************************************************************************/ + +static int podgov_user_ctl(struct device *dev) +{ + struct platform_device *d = to_platform_device(dev); + struct nvhost_device_data *pdata = platform_get_drvdata(d); + struct devfreq *df = pdata->power_manager; + struct podgov_info_rec *podgov; + int user; + + if (!df) + return 0; + + mutex_lock(&df->lock); + podgov = df->data; + user = podgov->p_user; + mutex_unlock(&df->lock); + + return user; +} + +/***************************************************************************** + * podgov_set_user_ctl(dev, user) + * + * This function enables or disables user control of the gpu. If user control + * is enabled, setting the freq_request controls the gpu frequency, and other + * gpu scaling mechanisms are disabled. + ******************************************************************************/ + +static void podgov_set_user_ctl(struct device *dev, int user) +{ + struct platform_device *d = to_platform_device(dev); + struct nvhost_device_data *pdata = platform_get_drvdata(d); + struct devfreq *df = pdata->power_manager; + struct podgov_info_rec *podgov; + + if (!df) + return; + + mutex_lock(&df->lock); + podgov = df->data; + + trace_podgov_set_user_ctl(user); + + if (podgov->enable && user && !podgov->p_user) { + cancel_work_sync(&podgov->work); + cancel_delayed_work(&podgov->idle_timer); + + podgov->adjustment_frequency = podgov->p_freq_request; + podgov->adjustment_type = ADJUSTMENT_LOCAL; + update_devfreq(df); + } + + podgov->p_user = user; + + mutex_unlock(&df->lock); +} + +/******************************************************************************* + * podgov_get_freq_request(dev) + * + * return the latest freq request if anybody asks + ******************************************************************************/ + +static int podgov_get_freq_request(struct device *dev) +{ + struct platform_device *d = to_platform_device(dev); + struct nvhost_device_data *pdata = platform_get_drvdata(d); + struct devfreq *df = pdata->power_manager; + struct podgov_info_rec *podgov; + int freq_request; + + if (!df) + return 0; + + mutex_lock(&df->lock); + podgov = df->data; + freq_request = podgov->p_freq_request; + mutex_unlock(&df->lock); + + return freq_request; +} + +/***************************************************************************** + * podgov_set_freq_request(dev, user) + * + * Set the current freq request. If scaling is enabled, and podgov user space + * control is enabled, this will set the gpu frequency. + ******************************************************************************/ + +static void podgov_set_freq_request(struct device *dev, int freq_request) +{ + struct platform_device *d = to_platform_device(dev); + struct nvhost_device_data *pdata = platform_get_drvdata(d); + struct devfreq *df = pdata->power_manager; + struct podgov_info_rec *podgov; + + if (!df) + return; + + mutex_lock(&df->lock); + podgov = df->data; + + trace_podgov_set_freq_request(freq_request); + + podgov->p_freq_request = freq_request; + + if (podgov->enable && podgov->p_user) { + + podgov->adjustment_frequency = freq_request; + podgov->adjustment_type = ADJUSTMENT_LOCAL; + update_devfreq(df); + } + + mutex_unlock(&df->lock); +} + +/******************************************************************************* * scaling_adjust(podgov, time) * * use scale up / scale down hint counts to adjust scaling parameters. @@ -732,6 +857,64 @@ static DEVICE_ATTR(enable_3d_scaling, S_IRUGO | S_IWUSR, enable_3d_scaling_show, enable_3d_scaling_store); /******************************************************************************* + * sysfs interface for user space control + * user = [0,1] disables / enabled user space control + * freq_request is the sysfs node user space writes frequency requests to + ******************************************************************************/ + +static ssize_t user_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t res; + + res = snprintf(buf, PAGE_SIZE, "%d\n", podgov_user_ctl(dev)); + + return res; +} + +static ssize_t user_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val = 0; + + if (kstrtoul(buf, 10, &val) < 0) + return -EINVAL; + + podgov_set_user_ctl(dev, val); + + return count; +} + +static DEVICE_ATTR(user, S_IRUGO | S_IWUSR, + user_show, user_store); + +static ssize_t freq_request_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t res; + + res = snprintf(buf, PAGE_SIZE, "%d\n", podgov_get_freq_request(dev)); + + return res; +} + +static ssize_t freq_request_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val = 0; + + if (kstrtoul(buf, 10, &val) < 0) + return -EINVAL; + + podgov_set_freq_request(dev, val); + + return count; +} + +static DEVICE_ATTR(freq_request, S_IRUGO | S_IWUSR, + freq_request_show, freq_request_store); + +/******************************************************************************* * nvhost_pod_estimate_freq(df, freq) * * This function is called for re-estimating the frequency. The function is @@ -752,9 +935,9 @@ static int nvhost_pod_estimate_freq(struct devfreq *df, struct devfreq_dev_status dev_stat; struct nvhost_devfreq_ext_stat *ext_stat; long delay; - int current_event = DEVICE_IDLE; - int stat = 0; - ktime_t now = ktime_get(); + int current_event; + int stat; + ktime_t now; /* Ensure maximal clock when scaling is disabled */ if (!podgov->enable) { @@ -762,6 +945,15 @@ static int nvhost_pod_estimate_freq(struct devfreq *df, return 0; } + if (podgov->p_user) { + *freq = podgov->p_freq_request; + return 0; + } + + current_event = DEVICE_IDLE; + stat = 0; + now = ktime_get(); + /* Local adjustments (i.e. requests from kernel threads) are * handled here */ @@ -898,6 +1090,7 @@ static int nvhost_pod_init(struct devfreq *df) } podgov->p_estimation_window = 10000; podgov->adjustment_type = ADJUSTMENT_DEVICE_REQ; + podgov->p_user = 0; /* Reset clock counters */ podgov->last_throughput_hint = now; @@ -920,12 +1113,24 @@ static int nvhost_pod_init(struct devfreq *df) df->min_freq = ext_stat->min_freq; df->max_freq = ext_stat->max_freq; - /* Create a sysfs entry for controlling this governor */ + podgov->p_freq_request = ext_stat->max_freq; + + /* Create sysfs entries for controlling this governor */ error = device_create_file(&d->dev, &dev_attr_enable_3d_scaling); if (error) goto err_create_sysfs_entry; + error = device_create_file(&d->dev, + &dev_attr_user); + if (error) + goto err_create_sysfs_entry; + + error = device_create_file(&d->dev, + &dev_attr_freq_request); + if (error) + goto err_create_sysfs_entry; + rate = 0; podgov->freq_count = 0; while (rate <= df->max_freq) { @@ -957,6 +1162,8 @@ static int nvhost_pod_init(struct devfreq *df) err_allocate_freq_list: device_remove_file(&d->dev, &dev_attr_enable_3d_scaling); + device_remove_file(&d->dev, &dev_attr_user); + device_remove_file(&d->dev, &dev_attr_freq_request); err_create_sysfs_entry: dev_err(&d->dev, "failed to create sysfs attributes"); err_get_current_status: @@ -982,6 +1189,8 @@ static void nvhost_pod_exit(struct devfreq *df) kfree(podgov->freqlist); device_remove_file(&d->dev, &dev_attr_enable_3d_scaling); + device_remove_file(&d->dev, &dev_attr_user); + device_remove_file(&d->dev, &dev_attr_freq_request); nvhost_scale3d_debug_deinit(df); diff --git a/include/trace/events/nvhost_podgov.h b/include/trace/events/nvhost_podgov.h index 5eb12a84dbfd..e0b999154447 100644 --- a/include/trace/events/nvhost_podgov.h +++ b/include/trace/events/nvhost_podgov.h @@ -3,7 +3,7 @@ * * Nvhost event logging to ftrace. * - * Copyright (c) 2012, NVIDIA Corporation. + * Copyright (c) 2013, 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 @@ -84,6 +84,38 @@ TRACE_EVENT(podgov_enabled, TP_printk("scaling_enabled=%d", __entry->enable) ); +TRACE_EVENT(podgov_set_user_ctl, + TP_PROTO(int user_ctl), + + TP_ARGS(user_ctl), + + TP_STRUCT__entry( + __field(int, user_ctl) + ), + + TP_fast_assign( + __entry->user_ctl = user_ctl; + ), + + TP_printk("userspace control=%d", __entry->user_ctl) +); + +TRACE_EVENT(podgov_set_freq_request, + TP_PROTO(int freq_request), + + TP_ARGS(freq_request), + + TP_STRUCT__entry( + __field(int, freq_request) + ), + + TP_fast_assign( + __entry->freq_request = freq_request; + ), + + TP_printk("freq_request=%d", __entry->freq_request) +); + TRACE_EVENT(podgov_busy, TP_PROTO(unsigned long busyness), |