Browse Source

Bugfix: gridseed: Implement a proper scanhash routine for GridSeeds

Previous behavior worked, but not intentionally
Nate Woolls 11 years ago
parent
commit
c73353f9da
3 changed files with 45 additions and 38 deletions
  1. 25 7
      driver-gridseed.c
  2. 20 30
      gc3355.c
  3. 0 1
      gc3355.h

+ 25 - 7
driver-gridseed.c

@@ -90,13 +90,19 @@ int64_t gridseed_calculate_chip_hashes(struct thr_info *thr)
 }
 
 static
-void gridseed_hashes_done(struct thr_info *thr)
+int64_t gridseed_hashes_done(struct thr_info *thr)
 {
 	struct cgpu_info *device = thr->cgpu;
 	int64_t chip_hashes = gridseed_calculate_chip_hashes(thr);
+	int64_t total_hashes = 0;
 
-	for (struct cgpu_info *proc = device; proc; proc = proc->next_proc)
+	for_each_managed_proc(proc, device)
+	{
+		total_hashes += chip_hashes;
 		hashes_done2(proc->thr[0], chip_hashes, NULL);
+	}
+
+	return total_hashes;
 }
 
 /*
@@ -221,6 +227,10 @@ bool gridseed_prepare_work(struct thr_info __maybe_unused *thr, struct work *wor
 		return false;
 	}
 
+	// after sending work to the device, minerloop_scanhash-based
+	// drivers must set work->blk.nonce to the last nonce to hash
+	work->blk.nonce = 0xffffffff;
+
 	return true;
 }
 
@@ -231,7 +241,7 @@ void gridseed_submit_nonce(struct thr_info * const thr, const unsigned char buf[
 	
 	uint32_t nonce = *(uint32_t *)(buf + 4);
 	nonce = le32toh(nonce);
-	uint32_t chip = nonce / ((uint32_t)0xffffffff / device->procs);
+	uint32_t chip = nonce / (work->blk.nonce / device->procs);
 	
 	struct thr_info *proc_thr = gridseed_thread_by_chip(device, chip);
 	
@@ -239,6 +249,9 @@ void gridseed_submit_nonce(struct thr_info * const thr, const unsigned char buf[
 }
 
 // read from device for nonce or command
+// unless the device can target specific nonce ranges, the scanhash routine should loop
+// until the device has processed the work item, scanning the full nonce range
+// return the total number of hashes done
 static
 int64_t gridseed_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
 {
@@ -246,16 +259,21 @@ int64_t gridseed_scanhash(struct thr_info *thr, struct work *work, int64_t __may
 	unsigned char buf[GC3355_READ_SIZE];
 	int read = 0;
 	int fd = device->device_fd;
+	int64_t total_hashes = 0;
 
-	while (!thr->work_restart && (read = gc3355_read(fd, (char *)buf, GC3355_READ_SIZE)) > 0)
+	while (!thr->work_restart                                                   // true when new work is available (miner.c)
+	    && ((read = gc3355_read(fd, (char *)buf, GC3355_READ_SIZE)) >= 0)       // only check for failure - allow 0 bytes
+	    && (total_hashes < max_nonce))                                          // false when we've had time to scan a range
 	{
+		total_hashes += gridseed_hashes_done(thr);
+
+		if (read == 0)
+			continue;
+
 		if ((buf[0] == 0x55) && (buf[1] == 0x20))
 			gridseed_submit_nonce(thr, buf, work);
 		else
-		{
 			applog(LOG_ERR, "%"PRIpreprv": Unrecognized response", device->proc_repr);
-			break;
-		}
 	}
 
 	if (read == -1)

+ 20 - 30
gc3355.c

@@ -33,7 +33,9 @@
 int opt_sha2_units = -1;
 int opt_pll_freq = 0; // default is set in gc3355_set_pll_freq
 
-#define GC3355_CHIP_NAME  "gc3355"
+#define GC3355_CHIP_NAME         "gc3355"
+#define GC3355_COMMAND_DELAY_MS  20
+#define GC3355_WRITE_DELAY_MS    10
 
 // General GC3355 commands
 
@@ -390,20 +392,7 @@ void gc3355_log_protocol(int fd, const char *buf, size_t size, const char *prefi
 
 ssize_t gc3355_read(int fd, char *buf, size_t size)
 {
-	size_t read;
-	int tries = 20;
-	
-	while (tries > 0)
-	{
-		read = serial_read(fd, buf, size);
-		if (read > 0)
-			break;
-		
-		tries--;
-	}
-	
-	if (unlikely(tries == 0))
-		return read;
+	size_t read = serial_read(fd, buf, size);
 	
 	if ((read > 0) && opt_dev_protocol)
 		gc3355_log_protocol(fd, buf, read, "RECV");
@@ -415,12 +404,21 @@ ssize_t gc3355_write(int fd, const void * const buf, const size_t size)
 {
 	if (opt_dev_protocol)
 		gc3355_log_protocol(fd, buf, size, "SEND");
-	
-	return write(fd, buf, size);
+
+	ssize_t result = write(fd, buf, size);
+
+	// gc3355 can suffer register corruption if multiple writes are
+	// made in a short period of time.
+	// This is not possible to reproduce on Mac OS X where the serial
+	// drivers seem to carry an additional overhead / latency.
+	// This is reproducable on Linux though by removing the following:
+	cgsleep_ms(GC3355_WRITE_DELAY_MS);
+
+	return result;
 }
 
 static
-void _gc3355_send_cmds_bin(int fd, const char *cmds[], bool is_bin, int size)
+void gc3355_send_cmds(int fd, const char *cmds[])
 {
 	int i = 0;
 	unsigned char ob_bin[512];
@@ -430,22 +428,14 @@ void _gc3355_send_cmds_bin(int fd, const char *cmds[], bool is_bin, int size)
 		if (cmd == NULL)
 			break;
 
-		if (is_bin)
-			gc3355_write(fd, cmd, size);
-		else
-		{
-			int bin_size = strlen(cmd) / 2;
-			hex2bin(ob_bin, cmd, bin_size);
-			gc3355_write(fd, ob_bin, bin_size);
-		}
-		
+		int bin_size = strlen(cmd) / 2;
+		hex2bin(ob_bin, cmd, bin_size);
+		gc3355_write(fd, ob_bin, bin_size);
+
 		cgsleep_ms(GC3355_COMMAND_DELAY_MS);
 	}
 }
 
-#define gc3355_send_cmds_bin(fd, cmds, size)  _gc3355_send_cmds_bin(fd, cmds, true, size)
-#define gc3355_send_cmds(fd, cmds)  _gc3355_send_cmds_bin(fd, cmds, false, -1)
-
 void gc3355_scrypt_only_reset(int fd)
 {
 	gc3355_send_cmds(fd, scrypt_only_reset_cmd);

+ 0 - 1
gc3355.h

@@ -27,7 +27,6 @@ int opt_pll_freq;
 
 // GridSeed common code begins here
 
-#define GC3355_COMMAND_DELAY_MS 20
 #define GC3355_ORB_DEFAULT_CHIPS   5
 #define GC3355_BLADE_DEFAULT_CHIPS	40
 #define GC3355_READ_SIZE          12