Commit 35ace4632517631b184d7aa36aae7b107f7e22af

Con Kolivas 2011-09-03T13:02:21

Enable changing of engine clock setting on the fly.

diff --git a/adl.c b/adl.c
index d2ca00a..7a84dad 100644
--- a/adl.c
+++ b/adl.c
@@ -1,5 +1,8 @@
 #include "miner.h"
 #include "adl.h"
+
+bool adl_active;
+
 #ifdef HAVE_ADL
 #if defined (__linux)
  #include "ADL_SDK/adl_sdk.h"
@@ -13,6 +16,7 @@
 #endif
 
 #include <stdio.h>
+#include <curses.h>
 
 #include "adl_functions.h"
 
@@ -57,7 +61,6 @@ static	ADL_OVERDRIVE5_ODPERFORMANCELEVELS_GET	ADL_Overdrive5_ODPerformanceLevels
 static	ADL_OVERDRIVE5_ODPERFORMANCELEVELS_SET	ADL_Overdrive5_ODPerformanceLevels_Set;
 static	ADL_MAIN_CONTROL_REFRESH	ADL_Main_Control_Refresh;
 
-bool adl_active;
 #if defined (LINUX)
 	static void *hDLL;	// Handle to .so library
 #else
@@ -297,6 +300,89 @@ int gpu_fanspeed(int gpu)
 	return ga->lpFanSpeedValue.iFanSpeed;
 }
 
+static void get_enginerange(int gpu, int *imin, int *imax)
+{
+	struct gpu_adl *ga;
+
+	if (!gpus[gpu].has_adl || !adl_active) {
+		wlogprint("Get enginerange not supported\n");
+		return;
+	}
+	ga = &gpus[gpu].adl;
+	*imin = ga->lpOdParameters.sEngineClock.iMin / 100;
+	*imax = ga->lpOdParameters.sEngineClock.iMax / 100;
+}
+
+static int set_engineclock(int gpu, int iEngineClock)
+{
+	ADLODPerformanceLevels *lpOdPerformanceLevels;
+	struct gpu_adl *ga;
+	int lev;
+
+	if (!gpus[gpu].has_adl || !adl_active) {
+		wlogprint("Set engineclock not supported\n");
+		return 1;
+	}
+
+	iEngineClock *= 100;
+	ga = &gpus[gpu].adl;
+	if (iEngineClock > ga->lpOdParameters.sEngineClock.iMax ||
+		iEngineClock < ga->lpOdParameters.sEngineClock.iMin)
+			return 1;
+
+	lev = ga->lpOdParameters.iNumberOfPerformanceLevels - 1;
+	lpOdPerformanceLevels = alloca(sizeof(ADLODPerformanceLevels) + (lev * sizeof(ADLODPerformanceLevel)));
+	lpOdPerformanceLevels->iSize = sizeof(ADLODPerformanceLevels) + sizeof(ADLODPerformanceLevel) * lev;
+	if (ADL_Overdrive5_ODPerformanceLevels_Get(ga->iAdapterIndex, 0, lpOdPerformanceLevels) != ADL_OK)
+		return 1;
+	lpOdPerformanceLevels->aLevels[lev].iEngineClock = iEngineClock;
+	if (ADL_Overdrive5_ODPerformanceLevels_Set(ga->iAdapterIndex, lpOdPerformanceLevels) != ADL_OK)
+		return 1;
+	ADL_Overdrive5_ODPerformanceLevels_Get(ga->iAdapterIndex, 0, lpOdPerformanceLevels);
+	/* Reset to old value if it fails! */
+	if (lpOdPerformanceLevels->aLevels[lev].iEngineClock != iEngineClock) {
+		/* Set all the parameters in case they're linked somehow */
+		lpOdPerformanceLevels->aLevels[lev].iEngineClock = ga->iEngineClock;
+		lpOdPerformanceLevels->aLevels[lev].iMemoryClock = ga->iMemoryClock;
+		lpOdPerformanceLevels->aLevels[lev].iVddc = ga->iVddc;
+		ADL_Overdrive5_ODPerformanceLevels_Set(ga->iAdapterIndex, lpOdPerformanceLevels);
+		ADL_Overdrive5_ODPerformanceLevels_Get(ga->iAdapterIndex, 0, lpOdPerformanceLevels);
+		return 1;
+	}
+	ga->iEngineClock = lpOdPerformanceLevels->aLevels[lev].iEngineClock;
+	ga->iMemoryClock = lpOdPerformanceLevels->aLevels[lev].iMemoryClock;
+	ga->iVddc = lpOdPerformanceLevels->aLevels[lev].iVddc;
+	return 0;
+}
+
+void change_gpusettings(int gpu)
+{
+	int val, imin = 0, imax = 0;
+	char input;
+
+	wlogprint("Change [E]ngine\n");
+	wlogprint("Or press any other key to continue\n");
+	input = getch();
+
+	if (!strncasecmp(&input, "e", 1)) {
+		get_enginerange(gpu, &imin, &imax);
+		wlogprint("Enter GPU engine clock speed (%d - %d Mhz):", imin, imax);
+		val = curses_int("");
+		if (val < imin || val > imax) {
+			wlogprint("Value is outside safe range, are you sure?\n");
+			input = getch();
+			if (strncasecmp(&input, "y", 1))
+				return;
+		}
+		if (!set_engineclock(gpu, val))
+			wlogprint("Successfully modified clock speed\n");
+		else
+			wlogprint("Failed to modify clock speed\n");
+		wlogprint("Press any key to continue\n");
+		input = getch();
+	}
+}
+
 void clear_adl(void)
 {
 	if (!adl_active)
diff --git a/adl.h b/adl.h
index 68dc611..2e3fee7 100644
--- a/adl.h
+++ b/adl.h
@@ -1,5 +1,6 @@
 #ifndef __ADL_H__
 #define __ADL_H__
+bool adl_active;
 #ifdef HAVE_ADL
 void init_adl(int nDevs);
 float gpu_temp(int gpu);
@@ -8,9 +9,11 @@ int gpu_memclock(int gpu);
 float gpu_vddc(int gpu);
 int gpu_activity(int gpu);
 int gpu_fanspeed(int gpu);
+void change_gpusettings(int gpu);
 void clear_adl(void);
 #else /* HAVE_ADL */
 void init_adl(int nDevs) {}
+void change_gpusettings(int gpu) { }
 void clear_adl(void) {}
 #endif
 #endif
diff --git a/main.c b/main.c
index 04a67ae..e0d0164 100644
--- a/main.c
+++ b/main.c
@@ -1610,7 +1610,7 @@ static void wlog(const char *f, ...)
 }
 
 /* Mandatory printing */
-static void wlogprint(const char *f, ...)
+void wlogprint(const char *f, ...)
 {
 	va_list ap;
 
@@ -2372,9 +2372,7 @@ static void *stage_thread(void *userdata)
 	return NULL;
 }
 
-static char *curses_input(const char *query);
-
-static int curses_int(const char *query)
+int curses_int(const char *query)
 {
 	int ret;
 	char *cvar;
@@ -2783,7 +2781,8 @@ retry:
 		wlog("\n");
 	}
 
-	wlogprint("[E]nable [D]isable [R]estart GPU\n");
+	wlogprint("[E]nable [D]isable [R]estart GPU %s\n",adl_active ? "[C]hange settings" : "");
+
 	wlogprint("Or press any other key to continue\n");
 	input = getch();
 
@@ -2826,6 +2825,13 @@ retry:
 		}
 		wlogprint("Attempting to restart threads of GPU %d\n", selected);
 		reinit_device(&gpus[selected]);
+	} else if (adl_active && (!strncasecmp(&input, "c", 1))) {
+		selected = curses_int("Select GPU to change settings on");
+		if (selected < 0 || selected >= nDevs) {
+			wlogprint("Invalid selection\n");
+			goto retry;
+		}
+		change_gpusettings(selected);
 	}
 
 	clear_logwin();
@@ -4331,10 +4337,6 @@ static void *watchdog_thread(void *userdata)
 				break;
 			thr = &thr_info[i];
 			gpu = thr->cgpu->cpu_gpu;
-#if 0
-			applog(LOG_WARNING, "Temp %d engine %d mem %d vddc %d activity %d fanspeed %d", gpu_temp(gpu), gpu_engineclock(gpu),
-				gpu_memclock(gpu), gpu_vddc(gpu), gpu_activity(gpu), gpu_fanspeed(gpu));
-#endif
 			/* Thread is waiting on getwork or disabled */
 			if (thr->getwork || !gpu_devices[gpu])
 				continue;
@@ -4471,7 +4473,7 @@ void quit(int status, const char *format, ...)
 	exit(status);
 }
 
-static char *curses_input(const char *query)
+char *curses_input(const char *query)
 {
 	char *input;
 
diff --git a/miner.h b/miner.h
index b2aa14e..58cf810 100644
--- a/miner.h
+++ b/miner.h
@@ -443,7 +443,9 @@ enum cl_kernel {
 };
 
 bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
-
+extern void wlogprint(const char *f, ...);
+extern int curses_int(const char *query);
+extern char *curses_input(const char *query);
 extern void kill_work(void);
 extern void log_curses(int prio, const char *f, va_list ap);
 extern void vapplog(int prio, const char *fmt, va_list ap);