Browse Source

Merge branch 'icarus_race_nonce' into bfgminer

Conflicts:
	driver-icarus.c
Luke Dashjr 12 years ago
parent
commit
523a99c72e
4 changed files with 90 additions and 36 deletions
  1. 1 0
      driver-erupter.c
  2. 77 35
      driver-icarus.c
  3. 3 1
      icarus-common.h
  4. 9 0
      util.h

+ 1 - 0
driver-erupter.c

@@ -29,6 +29,7 @@ static bool _erupter_detect_one(const char *devpath, struct device_drv *drv)
 		.baud = ERUPTER_IO_SPEED,
 		.Hs = ERUPTER_HASH_TIME,
 		.timing_mode = MODE_DEFAULT,
+		.continue_search = true,
 	};
 
 	if (!icarus_detect_custom(devpath, drv, info)) {

+ 77 - 35
driver-icarus.c

@@ -805,6 +805,17 @@ static bool icarus_job_start(struct thr_info *thr)
 	return true;
 }
 
+static
+struct work *icarus_process_worknonce(struct icarus_state *state, uint32_t *nonce)
+{
+	*nonce = be32toh(*nonce);
+	if (test_nonce(state->last_work, *nonce, false))
+		return state->last_work;
+	if (test_nonce(state->last2_work, *nonce, false))
+		return state->last2_work;
+	return NULL;
+}
+
 static
 void handle_identify(struct thr_info * const thr, int ret, const bool was_first_run)
 {
@@ -835,7 +846,7 @@ void handle_identify(struct thr_info * const thr, int ret, const bool was_first_
 			if (ret == ICA_GETS_OK)
 			{
 				nonce = be32toh(nonce);
-				submit_nonce(thr, &state->last_work, nonce);
+				submit_nonce(thr, state->last_work, nonce);
 			}
 		}
 	}
@@ -865,6 +876,15 @@ no_job_start:
 	state->identify = false;
 }
 
+static
+void icarus_transition_work(struct icarus_state *state, struct work *work)
+{
+	if (state->last2_work)
+		free_work(state->last2_work);
+	state->last2_work = state->last_work;
+	state->last_work = copy_work(work);
+}
+
 static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 				__maybe_unused int64_t max_nonce)
 {
@@ -874,14 +894,14 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	struct ICARUS_INFO *info;
 
-	unsigned char nonce_bin[ICARUS_READ_SIZE] = {0};
 	uint32_t nonce;
+	struct work *nonce_work;
 	int64_t hash_count;
 	struct timeval tv_start, elapsed;
 	struct timeval tv_history_start, tv_history_finish;
 	double Ti, Xi;
-	int curr_hw_errors, i;
-	bool was_hw_error;
+	int i;
+	bool was_hw_error = false;
 	bool was_first_run;
 
 	struct ICARUS_HISTORY *history0, *history;
@@ -912,8 +932,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		}
 		else
 		{
+			read_count = info->read_count;
+keepwaiting:
 			/* Icarus will return 4 bytes (ICARUS_READ_SIZE) nonces or nothing */
-			ret = icarus_gets(nonce_bin, fd, &state->tv_workfinish, thr, info->read_count);
+			ret = icarus_gets((void*)&nonce, fd, &state->tv_workfinish, thr, read_count);
 			switch (ret) {
 				case ICA_GETS_RESTART:
 					// The prepared work is invalid, and the current work is abandoned
@@ -940,25 +962,58 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		timersub(&state->tv_workfinish, &tv_start, &elapsed);
 	}
 	else
-	if (fd == -1 && !icarus_reopen(icarus, state, &fd))
-		return -1;
+	{
+		if (fd == -1 && !icarus_reopen(icarus, state, &fd))
+			return -1;
+		
+		// First run; no nonce, no hashes done
+		ret = ICA_GETS_ERROR;
+	}
 
 #ifndef WIN32
 	tcflush(fd, TCOFLUSH);
 #endif
 
-	memcpy(&nonce, nonce_bin, sizeof(nonce_bin));
-	nonce = be32toh(nonce);
-
+	if (ret == ICA_GETS_OK)
+	{
+		nonce_work = icarus_process_worknonce(state, &nonce);
+		if (likely(nonce_work))
+		{
+			if (nonce_work == state->last2_work)
+			{
+				// nonce was for the last job; submit and keep processing the current one
+				submit_nonce(thr, nonce_work, nonce);
+				goto keepwaiting;
+			}
+			if (info->continue_search)
+			{
+				read_count = info->read_count - ((timer_elapsed_us(&state->tv_workstart, NULL) / (1000000 / TIME_FACTOR)) + 1);
+				if (read_count)
+				{
+					submit_nonce(thr, nonce_work, nonce);
+					goto keepwaiting;
+				}
+			}
+		}
+		else
+			was_hw_error = true;
+	}
+	
 	// Handle dynamic clocking for "subclass" devices
 	// This needs to run before sending next job, since it hashes the command too
-	if (info->dclk.freqM && likely(!was_first_run)) {
+	if (info->dclk.freqM && likely(ret == ICA_GETS_OK || ret == ICA_GETS_TIMEOUT)) {
 		int qsec = ((4 * elapsed.tv_sec) + (elapsed.tv_usec / 250000)) ?: 1;
 		for (int n = qsec; n; --n)
 			dclk_gotNonces(&info->dclk);
-		if (nonce && !test_nonce(&state->last_work, nonce, false))
+		if (was_hw_error)
 			dclk_errorCount(&info->dclk, qsec);
 	}
+	
+	// Force a USB close/reopen on any hw error
+	if (was_hw_error && info->quirk_reopen != 2) {
+		if (!icarus_reopen(icarus, state, &fd))
+			state->firstrun = true;
+	}
 
 	if (unlikely(state->identify))
 	{
@@ -974,9 +1029,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	work->blk.nonce = 0xffffffff;
 
-	if (was_first_run) {
+	if (ret == ICA_GETS_ERROR) {
 		state->firstrun = false;
-		__copy_work(&state->last_work, work);
+		icarus_transition_work(state, work);
 		hash_count = 0;
 		goto out;
 	}
@@ -985,7 +1040,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	// aborted before becoming idle, get new work
 	if (ret == ICA_GETS_TIMEOUT || ret == ICA_GETS_RESTART) {
-		__copy_work(&state->last_work, work);
+		icarus_transition_work(state, work);
 		// ONLY up to just when it aborted
 		// We didn't read a reply so we don't subtract ICARUS_READ_TIME
 		estimate_hashes = ((double)(elapsed.tv_sec)
@@ -1007,26 +1062,13 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		goto out;
 	}
 
-	curr_hw_errors = icarus->hw_errors;
-	submit_nonce(thr, &state->last_work, nonce);
-	was_hw_error = (curr_hw_errors > icarus->hw_errors);
-	__copy_work(&state->last_work, work);
-
-	// Force a USB close/reopen on any hw error
-	if (was_hw_error)
-		if (info->quirk_reopen != 2) {
-			if (!icarus_reopen(icarus, state, &fd))
-				state->firstrun = true;
-			else
-			if (unlikely(state->identify))
-			{
-				// Delay job start until later...
-			}
-			else
-			// Some devices (Cairnsmore1, for example) abort hashing when reopened, so send the job again
-			if (!icarus_job_start(thr))
-				state->firstrun = true;
-		}
+	// Only ICA_GETS_OK gets here
+	
+	if (likely(!was_hw_error))
+		submit_nonce(thr, nonce_work, nonce);
+	else
+		inc_hw_errors(thr, state->last_work, nonce);
+	icarus_transition_work(state, work);
 
 	hash_count = (nonce & info->nonce_mask);
 	hash_count++;

+ 3 - 1
icarus-common.h

@@ -83,6 +83,7 @@ struct ICARUS_INFO {
 	uint32_t nonce_mask;
 	bool quirk_reopen;
 	uint8_t user_set;
+	bool continue_search;
 
 	dclk_change_clock_func_t dclk_change_clock_func;
 	struct dclk_data dclk;
@@ -92,7 +93,8 @@ struct icarus_state {
 	bool firstrun;
 	struct timeval tv_workstart;
 	struct timeval tv_workfinish;
-	struct work last_work;
+	struct work *last_work;
+	struct work *last2_work;
 	bool changework;
 	bool identify;
 	

+ 9 - 0
util.h

@@ -335,6 +335,15 @@ const struct timeval *_bfg_nullisnow(const struct timeval *tvp, struct timeval *
 	return tvp_buf;
 }
 
+static inline
+long timer_elapsed_us(const struct timeval *tvp_timer, const struct timeval *tvp_now)
+{
+	struct timeval tv;
+	const struct timeval *_tvp_now = _bfg_nullisnow(tvp_now, &tv);
+	timersub(_tvp_now, tvp_timer, &tv);
+	return ((long)tv.tv_sec * 1000000) + tv.tv_usec;
+}
+
 static inline
 int timer_elapsed(const struct timeval *tvp_timer, const struct timeval *tvp_now)
 {