summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlan Aelion <iaelion@nvidia.com>2012-10-23 12:43:53 -0600
committerRiham Haidar <rhaidar@nvidia.com>2013-03-13 16:22:35 -0700
commit84d79a515e3074d390a91755f931def47ff383c7 (patch)
treea63b97138fa9f1d55ec113f9974929360bdc7905
parent0ad2213531f3270c2e0a2ffcf824c46623c9b687 (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.c219
-rw-r--r--include/trace/events/nvhost_podgov.h34
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),