Browse Source

Drillbit: Keep reading work for as long as the device returns results.

The firmware protocol has the concept of returning up to "N" result
packets in a single query/response. However in testing this turned out
to be problematic (at least with cgminer) so it actually now only
returns 0 or 1 as the result count. This is the case for all released
Drillbit firmwares.

This means the preferred method for reading results is to immediately
keep checking for results until a zero response is seen. On a 64 ASIC
miniplane (8x Eight boards) this turned out to be important, as the
internal queue is only 32 results deep and it was losing results when
running at a 10ms poll interval.

As it happens the firmware will wait up to 100ms for any results
before returning a zero result count to the caller, so the protocol
itself builds in a certain amount of poll rate limiting (this is a bit
of a weird design decision, I know.)
Angus Gratton 12 years ago
parent
commit
4acf6058f0
1 changed files with 62 additions and 60 deletions
  1. 62 60
      driver-drillbit.c

+ 62 - 60
driver-drillbit.c

@@ -419,75 +419,77 @@ bool drillbit_get_work_results(struct cgpu_info * const dev)
 	uint32_t total;
 	int i, j;
 	
-	if (1 != write(fd, "E", 1))
-		problem(false, LOG_ERR, "%s: Error sending request for work results", dev->dev_repr);
+	do {
+		if (1 != write(fd, "E", 1))
+			problem(false, LOG_ERR, "%s: Error sending request for work results", dev->dev_repr);
 	
-	if (sizeof(total) != serial_read(fd, &total, sizeof(total)))
-		problem(false, LOG_ERR, "%s: Short read in response to 'E'", dev->dev_repr);
-	total = le32toh(total);
+		if (sizeof(total) != serial_read(fd, &total, sizeof(total)))
+			problem(false, LOG_ERR, "%s: Short read in response to 'E'", dev->dev_repr);
+		total = le32toh(total);
 	
-	if (total > DRILLBIT_MAX_WORK_RESULTS)
-		problem(false, LOG_ERR, "%s: Impossible number of total work: %lu",
-		        dev->dev_repr, (unsigned long)total);
+		if (total > DRILLBIT_MAX_WORK_RESULTS)
+			problem(false, LOG_ERR, "%s: Impossible number of total work: %lu",
+				dev->dev_repr, (unsigned long)total);
 	
-	for (i = 0; i < total; ++i)
-	{
-		if (sizeof(buf) != serial_read(fd, buf, sizeof(buf)))
-			problem(false, LOG_ERR, "%s: Short read on %dth total work",
-			        dev->dev_repr, i);
-		const int chipid = buf[0];
-		struct cgpu_info * const proc = drillbit_find_proc(dev, chipid);
-		struct thr_info * const thr = proc->thr[0];
-		if (unlikely(!proc))
-		{
-			applog(LOG_ERR, "%s: Unknown chip id %d", dev->dev_repr, chipid);
-			continue;
-		}
-		const bool is_idle = buf[3];
-		int nonces = buf[2];
-		if (nonces > DRILLBIT_MAX_RESULT_NONCES)
-		{
-			applog(LOG_ERR, "%"PRIpreprv": More than %d nonces claimed, impossible",
-			       proc->proc_repr, (int)DRILLBIT_MAX_RESULT_NONCES);
-			nonces = DRILLBIT_MAX_RESULT_NONCES;
-		}
-		applog(LOG_DEBUG, "%"PRIpreprv": Handling completion of %d nonces. is_idle=%d work=%p next_work=%p",
-		       proc->proc_repr, nonces, is_idle, thr->work, thr->next_work);
-		const uint32_t *nonce_p = (void*)&buf[4];
-		for (j = 0; j < nonces; ++j, ++nonce_p)
+		for (i = 0; i < total; ++i)
 		{
-			uint32_t nonce = bitfury_decnonce(*nonce_p);
-			if (bitfury_fudge_nonce2(thr->work, &nonce))
-				submit_nonce(thr, thr->work, nonce);
-			else
-			if (bitfury_fudge_nonce2(thr->next_work, &nonce))
+			if (sizeof(buf) != serial_read(fd, buf, sizeof(buf)))
+				problem(false, LOG_ERR, "%s: Short read on %dth total work",
+					dev->dev_repr, i);
+			const int chipid = buf[0];
+			struct cgpu_info * const proc = drillbit_find_proc(dev, chipid);
+			struct thr_info * const thr = proc->thr[0];
+			if (unlikely(!proc))
 			{
-				applog(LOG_DEBUG, "%"PRIpreprv": Result for next work, transitioning",
-				       proc->proc_repr);
-				submit_nonce(thr, thr->next_work, nonce);
-				mt_job_transition(thr);
-				job_start_complete(thr);
+				applog(LOG_ERR, "%s: Unknown chip id %d", dev->dev_repr, chipid);
+				continue;
 			}
-			else
-			if (bitfury_fudge_nonce2(thr->prev_work, &nonce))
+			const bool is_idle = buf[3];
+			int nonces = buf[2];
+			if (nonces > DRILLBIT_MAX_RESULT_NONCES)
 			{
-				applog(LOG_DEBUG, "%"PRIpreprv": Result for PREVIOUS work",
-				       proc->proc_repr);
-				submit_nonce(thr, thr->prev_work, nonce);
+				applog(LOG_ERR, "%"PRIpreprv": More than %d nonces claimed, impossible",
+					proc->proc_repr, (int)DRILLBIT_MAX_RESULT_NONCES);
+				nonces = DRILLBIT_MAX_RESULT_NONCES;
 			}
-			else
-				inc_hw_errors(thr, thr->work, nonce);
-		}
-		if (is_idle && thr->next_work)
-		{
-			applog(LOG_DEBUG, "%"PRIpreprv": Chip went idle without any results for next work",
-			       proc->proc_repr);
-			mt_job_transition(thr);
-			job_start_complete(thr);
+			applog(LOG_DEBUG, "%"PRIpreprv": Handling completion of %d nonces from chip %d. is_idle=%d work=%p next_work=%p",
+				proc->proc_repr, nonces, chipid, is_idle, thr->work, thr->next_work);
+			const uint32_t *nonce_p = (void*)&buf[4];
+			for (j = 0; j < nonces; ++j, ++nonce_p)
+			{
+				uint32_t nonce = bitfury_decnonce(*nonce_p);
+				if (bitfury_fudge_nonce2(thr->work, &nonce))
+					submit_nonce(thr, thr->work, nonce);
+				else
+					if (bitfury_fudge_nonce2(thr->next_work, &nonce))
+					{
+						applog(LOG_DEBUG, "%"PRIpreprv": Result for next work, transitioning",
+							proc->proc_repr);
+						submit_nonce(thr, thr->next_work, nonce);
+						mt_job_transition(thr);
+						job_start_complete(thr);
+					}
+					else
+						if (bitfury_fudge_nonce2(thr->prev_work, &nonce))
+						{
+							applog(LOG_DEBUG, "%"PRIpreprv": Result for PREVIOUS work",
+								proc->proc_repr);
+							submit_nonce(thr, thr->prev_work, nonce);
+						}
+						else
+							inc_hw_errors(thr, thr->work, nonce);
+			}
+			if (is_idle && thr->next_work)
+			{
+				applog(LOG_DEBUG, "%"PRIpreprv": Chip went idle without any results for next work",
+					proc->proc_repr);
+				mt_job_transition(thr);
+				job_start_complete(thr);
+			}
+			if (!thr->next_work)
+				timer_set_now(&thr->tv_morework);
 		}
-		if (!thr->next_work)
-			timer_set_now(&thr->tv_morework);
-	}
+	} while(total > 0);
 	
 	return true;
 }