Browse Source

cairnsmore: Detect availability of frequency scaling, and only enable it when supported

Luke Dashjr 13 years ago
parent
commit
63e0713bc9
3 changed files with 66 additions and 27 deletions
  1. 56 18
      driver-cairnsmore.c
  2. 1 9
      driver-icarus.c
  3. 9 0
      icarus-common.h

+ 56 - 18
driver-cairnsmore.c

@@ -34,7 +34,7 @@ static bool cairnsmore_detect_one(const char *devpath)
 	info->fpga_count = 2;
 	info->fpga_count = 2;
 	info->quirk_reopen = false;
 	info->quirk_reopen = false;
 	info->Hs = CAIRNSMORE1_HASH_TIME;
 	info->Hs = CAIRNSMORE1_HASH_TIME;
-	info->timing_mode = MODE_SHORT;
+	info->timing_mode = MODE_LONG;
 	info->do_icarus_timing = true;
 	info->do_icarus_timing = true;
 
 
 	if (!icarus_detect_custom(devpath, &cairnsmore_api, info)) {
 	if (!icarus_detect_custom(devpath, &cairnsmore_api, info)) {
@@ -59,9 +59,8 @@ static void cairnsmore_detect()
 	serial_detect_auto_byname(cairnsmore_api.dname, cairnsmore_detect_one, cairnsmore_detect_auto);
 	serial_detect_auto_byname(cairnsmore_api.dname, cairnsmore_detect_one, cairnsmore_detect_auto);
 }
 }
 
 
-static bool cairnsmore_send_cmd(struct cgpu_info *cm1, uint8_t cmd, uint8_t data)
+static bool cairnsmore_send_cmd(int fd, uint8_t cmd, uint8_t data)
 {
 {
-	int fd = cm1->device_fd;
 	unsigned char pkt[64] =
 	unsigned char pkt[64] =
 		"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 		"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 		"vdi\xb7"
 		"vdi\xb7"
@@ -73,12 +72,43 @@ static bool cairnsmore_send_cmd(struct cgpu_info *cm1, uint8_t cmd, uint8_t data
 	return write(fd, pkt, sizeof(pkt)) == sizeof(pkt);
 	return write(fd, pkt, sizeof(pkt)) == sizeof(pkt);
 }
 }
 
 
+bool cairnsmore_supports_dynclock(int fd)
+{
+	unsigned char pkts[64] =
+		"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+		"\xe6\x3c\0\xb7"  // Set frequency multiplier to 60 (150 Mhz)
+		"\0\0\0\0\0\0\0\0\0\0\0\0" "BFG0"
+		"\x8b\xdb\x05\x1a" "\xff\xff\xff\xff" "\x00\x00\x1e\xfd";
+	if (write(fd, pkts, sizeof(pkts) != sizeof(pkts)))
+		return false;
+
+	uint32_t nonce = 0;
+	{
+		struct timeval tv_finish;
+		struct thr_info dummy = {
+			.work_restart = false,
+			.work_restart_fd = -1,
+		};
+		icarus_gets((unsigned char*)&nonce, fd, &tv_finish, &dummy, 1);
+	}
+	switch (nonce) {
+		case 0x000b1b5e:
+			// Hashed the command, so it's not supported
+			return false;
+		case 0:
+			return true;
+		default:
+			applog(LOG_DEBUG, "cairnsmore_supports_dynclock got unexpected nonce %08x", nonce);
+			return false;
+	}
+}
+
 static bool cairnsmore_change_clock_func(struct thr_info *thr, int bestM)
 static bool cairnsmore_change_clock_func(struct thr_info *thr, int bestM)
 {
 {
 	struct cgpu_info *cm1 = thr->cgpu;
 	struct cgpu_info *cm1 = thr->cgpu;
 	struct ICARUS_INFO *info = cm1->cgpu_data;
 	struct ICARUS_INFO *info = cm1->cgpu_data;
 
 
-	if (unlikely(!cairnsmore_send_cmd(cm1, 0, bestM)))
+	if (unlikely(!cairnsmore_send_cmd(cm1->device_fd, 0, bestM)))
 		return false;
 		return false;
 	char repr[0x10];
 	char repr[0x10];
 	sprintf(repr, "%s %u", cm1->api->name, cm1->device_id);
 	sprintf(repr, "%s %u", cm1->api->name, cm1->device_id);
@@ -93,17 +123,23 @@ static bool cairnsmore_init(struct thr_info *thr)
 	struct cgpu_info *cm1 = thr->cgpu;
 	struct cgpu_info *cm1 = thr->cgpu;
 	struct ICARUS_INFO *info = cm1->cgpu_data;
 	struct ICARUS_INFO *info = cm1->cgpu_data;
 
 
-	info->dclk_change_clock_func = cairnsmore_change_clock_func;
-
-	dclk_prepare(&info->dclk);
-	info->dclk.freqMaxM = CAIRNSMORE1_MAXIMUM_CLOCK / 2.5;
-	info->dclk.freqM =
-	info->dclk.freqMDefault = CAIRNSMORE1_DEFAULT_CLOCK / 2.5;
-	cairnsmore_send_cmd(cm1, 0, info->dclk.freqM);
-	applog(LOG_WARNING, "%s %u: Frequency set to %u Mhz (range: %u-%u)",
-	       cm1->api->name, cm1->device_id,
-	       CAIRNSMORE1_DEFAULT_CLOCK, CAIRNSMORE1_MINIMUM_CLOCK, CAIRNSMORE1_MAXIMUM_CLOCK
-	);
+	if (cairnsmore_supports_dynclock(cm1->device_fd)) {
+		info->dclk_change_clock_func = cairnsmore_change_clock_func;
+
+		dclk_prepare(&info->dclk);
+		info->dclk.freqMaxM = CAIRNSMORE1_MAXIMUM_CLOCK / 2.5;
+		info->dclk.freqM =
+		info->dclk.freqMDefault = CAIRNSMORE1_DEFAULT_CLOCK / 2.5;
+		cairnsmore_send_cmd(cm1->device_fd, 0, info->dclk.freqM);
+		applog(LOG_WARNING, "%s %u: Frequency set to %u Mhz (range: %u-%u)",
+		       cm1->api->name, cm1->device_id,
+		       CAIRNSMORE1_DEFAULT_CLOCK, CAIRNSMORE1_MINIMUM_CLOCK, CAIRNSMORE1_MAXIMUM_CLOCK
+		);
+	} else {
+		// Test failures corrupt the hash state, so next scanhash is a firstrun
+		struct icarus_state *state = thr->cgpu_data;
+		state->firstrun = true;
+	}
 
 
 	return true;
 	return true;
 }
 }
@@ -113,7 +149,7 @@ void convert_icarus_to_cairnsmore(struct cgpu_info *cm1)
 	struct ICARUS_INFO *info = cm1->cgpu_data;
 	struct ICARUS_INFO *info = cm1->cgpu_data;
 	info->Hs = CAIRNSMORE1_HASH_TIME;
 	info->Hs = CAIRNSMORE1_HASH_TIME;
 	info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
 	info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
-	info->timing_mode = MODE_SHORT;
+	info->timing_mode = MODE_LONG;
 	info->do_icarus_timing = true;
 	info->do_icarus_timing = true;
 	cm1->api = &cairnsmore_api;
 	cm1->api = &cairnsmore_api;
 	renumber_cgpu(cm1);
 	renumber_cgpu(cm1);
@@ -125,8 +161,10 @@ static struct api_data *cairnsmore_api_extra_device_status(struct cgpu_info *cm1
 	struct ICARUS_INFO *info = cm1->cgpu_data;
 	struct ICARUS_INFO *info = cm1->cgpu_data;
 	struct api_data*root = NULL;
 	struct api_data*root = NULL;
 
 
-	double frequency = 2.5 * info->dclk.freqM;
-	root = api_add_freq(root, "Frequency", &frequency, true);
+	if (info->dclk.freqM) {
+		double frequency = 2.5 * info->dclk.freqM;
+		root = api_add_freq(root, "Frequency", &frequency, true);
+	}
 
 
 	return root;
 	return root;
 }
 }

+ 1 - 9
driver-icarus.c

@@ -173,7 +173,7 @@ static void rev(unsigned char *s, size_t l)
 #define icarus_open2(devpath, baud, purge)  serial_open(devpath, baud, ICARUS_READ_FAULT_DECISECONDS, purge)
 #define icarus_open2(devpath, baud, purge)  serial_open(devpath, baud, ICARUS_READ_FAULT_DECISECONDS, purge)
 #define icarus_open(devpath, baud)  icarus_open2(devpath, baud, false)
 #define icarus_open(devpath, baud)  icarus_open2(devpath, baud, false)
 
 
-static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count)
+int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count)
 {
 {
 	ssize_t ret = 0;
 	ssize_t ret = 0;
 	int rc = 0;
 	int rc = 0;
@@ -637,14 +637,6 @@ static void icarus_detect()
 	serial_detect(icarus_api.dname, icarus_detect_one);
 	serial_detect(icarus_api.dname, icarus_detect_one);
 }
 }
 
 
-struct icarus_state {
-	bool firstrun;
-	struct timeval tv_workstart;
-	struct timeval tv_workfinish;
-	struct work last_work;
-	bool changework;
-};
-
 static bool icarus_prepare(struct thr_info *thr)
 static bool icarus_prepare(struct thr_info *thr)
 {
 {
 	struct cgpu_info *icarus = thr->cgpu;
 	struct cgpu_info *icarus = thr->cgpu;

+ 9 - 0
icarus-common.h

@@ -75,6 +75,15 @@ struct ICARUS_INFO {
 	struct dclk_data dclk;
 	struct dclk_data dclk;
 };
 };
 
 
+struct icarus_state {
+	bool firstrun;
+	struct timeval tv_workstart;
+	struct timeval tv_workfinish;
+	struct work last_work;
+	bool changework;
+};
+
 bool icarus_detect_custom(const char *devpath, struct device_api *, struct ICARUS_INFO *);
 bool icarus_detect_custom(const char *devpath, struct device_api *, struct ICARUS_INFO *);
+extern int icarus_gets(unsigned char *, int fd, struct timeval *tv_finish, struct thr_info *, int read_count);
 
 
 #endif
 #endif