All of lore.kernel.org
 help / color / mirror / Atom feed
From: Martin Peres <martin.peres-GANU6spQydw@public.gmane.org>
To: nouveau <Nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org>
Subject: [Patch] Add a custom power management perflvl
Date: Sun, 21 Nov 2010 03:47:43 +0100	[thread overview]
Message-ID: <4CE8884F.10008@free.fr> (raw)

[-- Attachment #1: Type: text/plain, Size: 557 bytes --]

Hi everyone,

Please comment on this patch allowing you to set all the PM-related 
clocks on the card. The patch is described in length in the commit log.

There is something some of you will like and some won't. The custom_* 
files will always contain the values of the current perflvl unless the 
user changed them after the latest reclock.
I may also add all the available voltage in sysfs in the same way Ben 
added all the available performance levels (performance_level_X).

If you no-one has anything against it, please push it to master.

Martin




[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-a-custom-power-management-perflvl.patch --]
[-- Type: text/x-patch; name="0001-Add-a-custom-power-management-perflvl.patch", Size: 12238 bytes --]

From 1df2984f21ba0bf034684b1b1287fb86a255a15c Mon Sep 17 00:00:00 2001
From: Martin Peres <mupuf-IIUFz0z94vfYtjvyW6yDsg@public.gmane.org>
Date: Sat, 20 Nov 2010 18:29:45 +0100
Subject: [PATCH] Add a custom power management perflvl
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This is to allow people to tweak their clocks at will.
Marcin asked for something like this to help him REing.
I was personnaly interested to see if openarena fps rate would scale with the GPU clocks (it doesn't ... yet).
This patch will also allow overclockers to test their cards (On my NVS 140M: Memory +66%, core: +66%, shader: +25%).

This patch introduces a few sysfs files:
- custom_*: Get/set the current clock/voltage value (kHz or *10mV)

Once you've set all the values you wanted to change, just echo "custom" into performance_level.

WARNINGS:
1) Pay attention to your current temperature, my card's temperature rose by 9°C.
We'll need to use the thermal zones to be able to monitor that and downclock the card automatically (if someone wants to help here, he would be welcome).

2) Changing clocks isn't safe at the moment, I'm working on this but the reclocking process is really different accross the boards.
So far, nv84 and nv86 work perfectly (as in no flicker and being able to reclock while playing games).

By the time I get this patch ready, please stop 3D applications, switch to a tty, do the reclock and come back to X.

Signed-off-by: Martin Peres <martin.peres-Iz16wY1oaNPLSKGbIzaifA@public.gmane.org>
---
 drivers/gpu/drm/nouveau/nouveau_drv.h |    1 +
 drivers/gpu/drm/nouveau/nouveau_pm.c  |  265 ++++++++++++++++++++++++++++++++-
 2 files changed, 263 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index a52b1da..5928301 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -463,6 +463,7 @@ struct nouveau_pm_engine {
 	struct nouveau_pm_threshold_temp threshold_temp;
 
 	struct nouveau_pm_level boot;
+	struct nouveau_pm_level custom;
 	struct nouveau_pm_level *cur;
 
 	struct device *hwmon;
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index d938141..7bcb27f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -35,6 +35,10 @@
 #include <linux/hwmon-sysfs.h>
 
 static int
+nouveau_pm_perflvl_get(struct drm_device *dev,
+					struct nouveau_pm_level *perflvl);
+
+static int
 nouveau_pm_clock_set(struct drm_device *dev, struct nouveau_pm_level *perflvl,
 		     u8 id, u32 khz)
 {
@@ -61,7 +65,7 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
 	int ret;
 
-	if (perflvl == pm->cur)
+	if (perflvl != &pm->custom && perflvl == pm->cur)
 		return 0;
 
 	if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) {
@@ -78,6 +82,10 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
 	nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05);
 
 	pm->cur = perflvl;
+
+	/* Copy the new profile to the custom profile */
+	nouveau_pm_perflvl_get(dev, &pm->custom);
+
 	return 0;
 }
 
@@ -97,6 +105,8 @@ nouveau_pm_profile_set(struct drm_device *dev, const char *profile)
 
 	if (!strncmp(profile, "boot", 4))
 		perflvl = &pm->boot;
+	else if (!strncmp(profile, "custom", 6))
+		perflvl = &pm->custom;
 	else {
 		int pl = simple_strtol(profile, NULL, 10);
 		int i;
@@ -208,6 +218,8 @@ nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf)
 		snprintf(ptr, len, "setting: boot\n");
 	else if (pm->cur == &pm->boot)
 		snprintf(ptr, len, "setting: boot\nc: ");
+	else if (pm->cur == &pm->custom)
+		snprintf(ptr, len, "setting: custom\nclocks: ");
 	else
 		snprintf(ptr, len, "setting: static %d\nc: ", pm->cur->id);
 	ptr += strlen(buf);
@@ -221,7 +233,7 @@ nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf)
 
 static ssize_t
 nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a,
-		       const char *buf, size_t count)
+					const char *buf, size_t count)
 {
 	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
 	int ret;
@@ -233,7 +245,226 @@ nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a,
 }
 
 static DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR,
-		   nouveau_pm_get_perflvl, nouveau_pm_set_perflvl);
+			nouveau_pm_get_perflvl, nouveau_pm_set_perflvl);
+
+static ssize_t
+nouveau_pm_get_custom_core(struct device *d,
+					struct device_attribute *a, char *buf)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	int len = PAGE_SIZE;
+	char *ptr = buf;
+
+	snprintf(ptr, len, "%d\n", pm->custom.core);
+	return strlen(buf);
+}
+
+static ssize_t
+nouveau_pm_set_custom_core(struct device *d, struct device_attribute *a,
+					const char *buf, size_t count)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	void *pre_state;
+	long sysfs_value;
+
+	if (strict_strtol(buf, 10, &sysfs_value) == -EINVAL)
+		return -EINVAL;
+
+	if (sysfs_value < 2000)
+		return -EINVAL;
+
+	pre_state = pm->clock_pre(dev, &pm->custom, PLL_CORE,
+					(u32) sysfs_value);
+	if (IS_ERR(pre_state))
+		return -ENOENT;
+	else
+		kfree(pre_state);
+
+	pm->custom.core = (u32) sysfs_value;
+
+	return strlen(buf);
+}
+
+static DEVICE_ATTR(custom_core, S_IRUGO | S_IWUSR,
+			nouveau_pm_get_custom_core, nouveau_pm_set_custom_core);
+
+static ssize_t
+nouveau_pm_get_custom_memory(struct device *d,
+					struct device_attribute *a, char *buf)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	int len = PAGE_SIZE;
+	char *ptr = buf;
+
+	snprintf(ptr, len, "%d\n", pm->custom.memory);
+	return strlen(buf);
+}
+
+static ssize_t
+nouveau_pm_set_custom_memory(struct device *d, struct device_attribute *a,
+					const char *buf, size_t count)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	void *pre_state;
+	long sysfs_value;
+
+	if (strict_strtol(buf, 10, &sysfs_value) == -EINVAL)
+		return -EINVAL;
+
+	if (sysfs_value < 2000)
+		return -EINVAL;
+
+	pre_state = pm->clock_pre(dev, &pm->custom, PLL_MEMORY,
+					(u32) sysfs_value);
+	if (IS_ERR(pre_state))
+		return -ENOENT;
+	else
+		kfree(pre_state);
+
+	pm->custom.memory = (u32) sysfs_value;
+
+	return strlen(buf);
+}
+
+static DEVICE_ATTR(custom_memory, S_IRUGO | S_IWUSR,
+		   nouveau_pm_get_custom_memory, nouveau_pm_set_custom_memory);
+
+static ssize_t
+nouveau_pm_get_custom_shader(struct device *d,
+					struct device_attribute *a, char *buf)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	int len = PAGE_SIZE;
+	char *ptr = buf;
+
+	snprintf(ptr, len, "%d\n", pm->custom.shader);
+	return strlen(buf);
+}
+
+static ssize_t
+nouveau_pm_set_custom_shader(struct device *d, struct device_attribute *a,
+					const char *buf, size_t count)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	void *pre_state;
+	long sysfs_value;
+
+	if (strict_strtol(buf, 10, &sysfs_value) == -EINVAL)
+		return -EINVAL;
+
+	if (sysfs_value < 2000)
+		return -EINVAL;
+
+	pre_state = pm->clock_pre(dev, &pm->custom, PLL_SHADER,
+					  (u32) sysfs_value);
+	if (IS_ERR(pre_state))
+		return -ENOENT;
+	else
+		kfree(pre_state);
+
+	pm->custom.shader = (u32) sysfs_value;
+
+	return strlen(buf);
+}
+
+static DEVICE_ATTR(custom_shader, S_IRUGO | S_IWUSR,
+					nouveau_pm_get_custom_shader,
+					nouveau_pm_set_custom_shader);
+
+static ssize_t
+nouveau_pm_get_custom_unk05(struct device *d,
+					struct device_attribute *a, char *buf)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	int len = PAGE_SIZE;
+	char *ptr = buf;
+
+	snprintf(ptr, len, "%d\n", pm->custom.unk05);
+	return strlen(buf);
+}
+
+static ssize_t
+nouveau_pm_set_custom_unk05(struct device *d, struct device_attribute *a,
+					const char *buf, size_t count)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	void *pre_state;
+	long sysfs_value;
+
+	if (strict_strtol(buf, 10, &sysfs_value) == -EINVAL)
+		return -EINVAL;
+
+	if (sysfs_value < 2000)
+		return -EINVAL;
+
+	pre_state = pm->clock_pre(dev, &pm->custom, PLL_UNK05,
+					(u32) sysfs_value);
+	if (IS_ERR(pre_state))
+		return -ENOENT;
+	else
+		kfree(pre_state);
+
+	pm->custom.unk05 = (u32) sysfs_value;
+
+	return strlen(buf);
+}
+
+static DEVICE_ATTR(custom_unk05, S_IRUGO | S_IWUSR,
+		   nouveau_pm_get_custom_unk05, nouveau_pm_set_custom_unk05);
+
+static ssize_t
+nouveau_pm_get_custom_voltage(struct device *d,
+				struct device_attribute *a, char *buf)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	int len = PAGE_SIZE;
+	char *ptr = buf;
+
+	snprintf(ptr, len, "%d\n", pm->custom.voltage);
+
+	return strlen(buf);
+}
+
+static ssize_t
+nouveau_pm_set_custom_voltage(struct device *d, struct device_attribute *a,
+		       const char *buf, size_t count)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	long voltage_sysfs;
+
+	if (strict_strtol(buf, 10, &voltage_sysfs) == -EINVAL)
+		return -EINVAL;
+
+	if (nouveau_volt_vid_lookup(dev, voltage_sysfs) < 0)
+		return -ENOENT;
+
+	pm->custom.voltage = (u32) voltage_sysfs;
+	return strlen(buf);
+}
+
+static DEVICE_ATTR(custom_voltage, S_IRUGO | S_IWUSR,
+				nouveau_pm_get_custom_voltage,
+				nouveau_pm_set_custom_voltage);
 
 static int
 nouveau_sysfs_init(struct drm_device *dev)
@@ -266,6 +497,26 @@ nouveau_sysfs_init(struct drm_device *dev)
 		}
 	}
 
+	ret = device_create_file(d, &dev_attr_custom_core);
+	if (ret)
+		return ret;
+
+	ret = device_create_file(d, &dev_attr_custom_memory);
+	if (ret)
+		return ret;
+
+	ret = device_create_file(d, &dev_attr_custom_shader);
+	if (ret)
+		return ret;
+
+	ret = device_create_file(d, &dev_attr_custom_unk05);
+	if (ret)
+		return ret;
+
+	ret = device_create_file(d, &dev_attr_custom_voltage);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
@@ -286,6 +537,11 @@ nouveau_sysfs_fini(struct drm_device *dev)
 
 		device_remove_file(d, &pl->dev_attr);
 	}
+	device_remove_file(d, &dev_attr_custom_core);
+	device_remove_file(d, &dev_attr_custom_memory);
+	device_remove_file(d, &dev_attr_custom_shader);
+	device_remove_file(d, &dev_attr_custom_unk05);
+	device_remove_file(d, &dev_attr_custom_voltage);
 }
 
 #ifdef CONFIG_HWMON
@@ -497,6 +753,9 @@ nouveau_pm_init(struct drm_device *dev)
 		NV_INFO(dev, "c: %s", info);
 	}
 
+	/* set custom clocks to the boot performance level */
+	nouveau_pm_perflvl_get(dev, &pm->custom);
+
 	/* switch performance levels now if requested */
 	if (nouveau_perflvl != NULL) {
 		ret = nouveau_pm_profile_set(dev, nouveau_perflvl);
-- 
1.7.3.2


[-- Attachment #3: Type: text/plain, Size: 181 bytes --]

_______________________________________________
Nouveau mailing list
Nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

             reply	other threads:[~2010-11-21  2:47 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-11-21  2:47 Martin Peres [this message]
     [not found] ` <4CE8884F.10008-GANU6spQydw@public.gmane.org>
2010-11-21 23:50   ` [Patch] Add a custom power management perflvl Martin Peres

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4CE8884F.10008@free.fr \
    --to=martin.peres-ganu6spqydw@public.gmane.org \
    --cc=Nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.