Browse Source

x6500: Dynclock support

Luke Dashjr 13 years ago
parent
commit
c6e5b80ff9
1 changed files with 63 additions and 6 deletions
  1. 63 6
      driver-x6500.c

+ 63 - 6
driver-x6500.c

@@ -7,6 +7,8 @@
  * any later version.  See COPYING for more details.
  * any later version.  See COPYING for more details.
  */
  */
 
 
+#include <sys/time.h>
+
 #include <libusb-1.0/libusb.h>
 #include <libusb-1.0/libusb.h>
 
 
 #include "dynclock.h"
 #include "dynclock.h"
@@ -21,8 +23,8 @@
 // NOTE: X6500_BITSTREAM_USERID is bitflipped
 // NOTE: X6500_BITSTREAM_USERID is bitflipped
 #define X6500_BITSTREAM_USERID "\x40\x20\x24\x42"
 #define X6500_BITSTREAM_USERID "\x40\x20\x24\x42"
 #define X6500_MINIMUM_CLOCK    2
 #define X6500_MINIMUM_CLOCK    2
-#define X6500_DEFAULT_CLOCK  200
-#define X6500_MAXIMUM_CLOCK  210
+#define X6500_DEFAULT_CLOCK  180
+#define X6500_MAXIMUM_CLOCK  180
 
 
 struct device_api x6500_api;
 struct device_api x6500_api;
 
 
@@ -277,6 +279,38 @@ x6500_fpga_upload_bitstream(struct cgpu_info *x6500, struct jtag_port *jp1)
 	return true;
 	return true;
 }
 }
 
 
+static bool x6500_change_clock(struct thr_info *thr, int multiplier)
+{
+	struct x6500_fpga_data *fpga = thr->cgpu_data;
+	struct jtag_port *jp = &fpga->jtag;
+
+	x6500_set_register(jp, 0xD, multiplier * 2);
+	ft232r_flush(jp->a->ftdi);
+	fpga->dclk.freqM = multiplier;
+
+	return true;
+}
+
+static bool x6500_dclk_change_clock(struct thr_info *thr, int multiplier)
+{
+	struct cgpu_info *x6500 = thr->cgpu;
+	char fpgaid = thr->device_thread;
+	struct x6500_fpga_data *fpga = thr->cgpu_data;
+	uint8_t oldFreq = fpga->dclk.freqM;
+
+	mutex_lock(&x6500->device_mutex);
+	if (!x6500_change_clock(thr, multiplier)) {
+		mutex_unlock(&x6500->device_mutex);
+		return false;
+	}
+	mutex_unlock(&x6500->device_mutex);
+
+	char repr[0x10];
+	sprintf(repr, "%s %u.%u", x6500->api->name, x6500->device_id, fpgaid);
+	dclk_msg_freqchange(repr, oldFreq * 2, fpga->dclk.freqM * 2, NULL);
+	return true;
+}
+
 static bool x6500_fpga_init(struct thr_info *thr)
 static bool x6500_fpga_init(struct thr_info *thr)
 {
 {
 	struct cgpu_info *x6500 = thr->cgpu;
 	struct cgpu_info *x6500 = thr->cgpu;
@@ -336,9 +370,15 @@ static bool x6500_fpga_init(struct thr_info *thr)
 	
 	
 	thr->cgpu_data = fpga;
 	thr->cgpu_data = fpga;
 
 
-	x6500_set_register(jp, 0xD, 180);  // Set clock speed
-	fpga->dclk.freqM = 90;
-	ft232r_flush(jp->a->ftdi);
+	dclk_prepare(&fpga->dclk);
+	fpga->dclk.freqMaxM = X6500_MAXIMUM_CLOCK / 2;
+	x6500_change_clock(thr, X6500_DEFAULT_CLOCK / 2);
+	fpga->dclk.freqMDefault = fpga->dclk.freqM;
+	applog(LOG_WARNING, "%s %u.%u: Frequency set to %u Mhz (range: %u-%u)",
+	       x6500->api->name, x6500->device_id, fpgaid,
+	       fpga->dclk.freqM * 2,
+	       X6500_MINIMUM_CLOCK,
+	       fpga->dclk.freqMaxM * 2);
 
 
 	mutex_unlock(&x6500->device_mutex);
 	mutex_unlock(&x6500->device_mutex);
 	return true;
 	return true;
@@ -411,10 +451,13 @@ int64_t x6500_process_results(struct thr_info *thr, struct work *work)
 	struct jtag_port *jtag = &fpga->jtag;
 	struct jtag_port *jtag = &fpga->jtag;
 	char fpgaid = thr->device_thread;
 	char fpgaid = thr->device_thread;
 
 
-	struct timeval tv_now;
+	struct timeval tv_now, tv_dclk, tv_delta;
 	int64_t hashes;
 	int64_t hashes;
 	uint32_t nonce;
 	uint32_t nonce;
 	bool bad;
 	bool bad;
+	int imm_bad_nonces = 0, imm_nonces = 0;
+
+	gettimeofday(&tv_dclk, NULL);
 
 
 	while (1) {
 	while (1) {
 		mutex_lock(&x6500->device_mutex);
 		mutex_lock(&x6500->device_mutex);
@@ -422,6 +465,7 @@ int64_t x6500_process_results(struct thr_info *thr, struct work *work)
 		nonce = x6500_get_register(jtag, 0xE);
 		nonce = x6500_get_register(jtag, 0xE);
 		mutex_unlock(&x6500->device_mutex);
 		mutex_unlock(&x6500->device_mutex);
 		if (nonce != 0xffffffff) {
 		if (nonce != 0xffffffff) {
+			++imm_nonces;
 			bad = !test_nonce(work, nonce, false);
 			bad = !test_nonce(work, nonce, false);
 			if (!bad) {
 			if (!bad) {
 				submit_nonce(thr, work, nonce);
 				submit_nonce(thr, work, nonce);
@@ -439,9 +483,19 @@ int64_t x6500_process_results(struct thr_info *thr, struct work *work)
 				       (unsigned long)nonce);
 				       (unsigned long)nonce);
 				++hw_errors;
 				++hw_errors;
 				++x6500->hw_errors;
 				++x6500->hw_errors;
+				++imm_bad_nonces;
 			}
 			}
 		}
 		}
 
 
+		timersub(&tv_now, &tv_dclk, &tv_delta);
+		if (tv_delta.tv_usec >= 250000) {
+			dclk_gotNonces(&fpga->dclk);
+			if (imm_bad_nonces)
+				dclk_errorCount(&fpga->dclk, ((double)imm_bad_nonces) / (double)imm_nonces);
+			imm_bad_nonces = imm_nonces = 0;
+			tv_dclk = tv_now;
+		}
+
 		hashes = calc_hashes(fpga, &tv_now);
 		hashes = calc_hashes(fpga, &tv_now);
 		if (thr->work_restart || hashes >= 0xf0000000)
 		if (thr->work_restart || hashes >= 0xf0000000)
 			break;
 			break;
@@ -451,6 +505,9 @@ int64_t x6500_process_results(struct thr_info *thr, struct work *work)
 			break;
 			break;
 	}
 	}
 
 
+	dclk_preUpdate(&fpga->dclk);
+	dclk_updateFreq(&fpga->dclk, x6500_dclk_change_clock, thr);
+
 	memcpy(&fpga->prevwork, work, sizeof(fpga->prevwork));
 	memcpy(&fpga->prevwork, work, sizeof(fpga->prevwork));
 
 
 	return hashes;
 	return hashes;