Browse Source

Merge branch 'erupter_identify' into bfgminer

Luke Dashjr 12 years ago
parent
commit
dfe1a23858
3 changed files with 122 additions and 22 deletions
  1. 9 0
      driver-erupter.c
  2. 110 22
      driver-icarus.c
  3. 3 0
      icarus-common.h

+ 9 - 0
driver-erupter.c

@@ -72,12 +72,21 @@ static void erupter_detect()
 	serial_detect_auto_byname(&erupter_drv_emerald, erupter_emerald_detect_one, erupter_emerald_detect_auto);
 }
 
+static bool erupter_identify(struct cgpu_info *erupter)
+{
+	struct thr_info *thr = erupter->thr[0];
+	struct icarus_state *state = thr->cgpu_data;
+	state->identify = true;
+	return true;
+}
+
 static void erupter_drv_init()
 {
 	erupter_drv = icarus_drv;
 	erupter_drv.dname = "erupter";
 	erupter_drv.name = "BES";
 	erupter_drv.drv_detect = erupter_detect;
+	erupter_drv.identify_device = erupter_identify;
 	
 	erupter_drv_emerald = erupter_drv;
 	erupter_drv_emerald.name = "BEE";

+ 110 - 22
driver-icarus.c

@@ -747,13 +747,44 @@ static bool icarus_reopen(struct cgpu_info *icarus, struct icarus_state *state,
 	return true;
 }
 
-static bool icarus_start_work(struct thr_info *thr, const unsigned char *ob_bin)
+static
+bool icarus_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused uint64_t max_nonce)
+{
+	struct cgpu_info * const icarus = thr->cgpu;
+	struct icarus_state * const state = thr->cgpu_data;
+	uint8_t * const ob_bin = state->ob_bin;
+	
+	memcpy(ob_bin, work->midstate, 32);
+	memcpy(ob_bin + 52, work->data + 64, 12);
+	if (!(memcmp(&ob_bin[56], "\xff\xff\xff\xff", 4)
+	   || memcmp(&ob_bin, "\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", 32))) {
+		// This sequence is used on cairnsmore bitstreams for commands, NEVER send it otherwise
+		applog(LOG_WARNING, "%"PRIpreprv": Received job attempting to send a command, corrupting it!",
+		       icarus->proc_repr);
+		ob_bin[56] = 0;
+	}
+	rev(ob_bin, 32);
+	rev(ob_bin + 52, 12);
+	
+	return true;
+}
+
+static bool icarus_job_start(struct thr_info *thr)
 {
 	struct cgpu_info *icarus = thr->cgpu;
+	struct ICARUS_INFO *info = icarus->device_data;
 	struct icarus_state *state = thr->cgpu_data;
+	const uint8_t * const ob_bin = state->ob_bin;
 	int fd = icarus->device_fd;
 	int ret;
 
+	// 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(!state->firstrun)) {
+		dclk_preUpdate(&info->dclk);
+		dclk_updateFreq(&info->dclk, info->dclk_change_clock_func, thr);
+	}
+	
 	cgtime(&state->tv_workstart);
 
 	ret = icarus_write(fd, ob_bin, 64);
@@ -775,6 +806,63 @@ static bool icarus_start_work(struct thr_info *thr, const unsigned char *ob_bin)
 	return true;
 }
 
+static
+void handle_identify(struct thr_info * const thr, int ret, const bool was_first_run)
+{
+	const struct cgpu_info * const icarus = thr->cgpu;
+	const struct ICARUS_INFO * const info = icarus->device_data;
+	struct icarus_state * const state = thr->cgpu_data;
+	int fd = icarus->device_fd;
+	struct timeval tv_now;
+	double delapsed;
+	uint32_t nonce;
+	
+	// If identify is requested (block erupters):
+	// 1. Don't start the next job right away (above)
+	// 2. Wait for the current job to complete 100%
+	
+	if (!was_first_run)
+	{
+		applog(LOG_DEBUG, "%"PRIpreprv": Identify: Waiting for current job to finish", icarus->proc_repr);
+		while (true)
+		{
+			cgtime(&tv_now);
+			delapsed = tdiff(&tv_now, &state->tv_workstart);
+			if (delapsed + 0.1 > info->fullnonce)
+				break;
+			
+			// Try to get more nonces (ignoring work restart)
+			ret = icarus_gets((void *)&nonce, fd, &tv_now, NULL, (info->fullnonce - delapsed) * 10);
+			if (ret == ICA_GETS_OK)
+			{
+				nonce = be32toh(nonce);
+				submit_nonce(thr, &state->last_work, nonce);
+			}
+		}
+	}
+	else
+		applog(LOG_DEBUG, "%"PRIpreprv": Identify: Current job should already be finished", icarus->proc_repr);
+	
+	// 3. Delay 3 more seconds
+	applog(LOG_DEBUG, "%"PRIpreprv": Identify: Leaving idle for 3 seconds", icarus->proc_repr);
+	nmsleep(3000);
+	
+	// Check for work restart in the meantime
+	if (thr->work_restart)
+	{
+		applog(LOG_DEBUG, "%"PRIpreprv": Identify: Work restart requested during delay", icarus->proc_repr);
+		goto no_job_start;
+	}
+	
+	// 4. Start next job
+	applog(LOG_DEBUG, "%"PRIpreprv": Identify: Starting next job", icarus->proc_repr);
+	if (!icarus_job_start(thr))
+no_job_start:
+		state->firstrun = true;
+	
+	state->identify = false;
+}
+
 static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 				__maybe_unused int64_t max_nonce)
 {
@@ -784,7 +872,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	struct ICARUS_INFO *info;
 
-	unsigned char ob_bin[64] = {0}, nonce_bin[ICARUS_READ_SIZE] = {0};
+	unsigned char nonce_bin[ICARUS_READ_SIZE] = {0};
 	uint32_t nonce;
 	int64_t hash_count;
 	struct timeval tv_start, elapsed;
@@ -792,6 +880,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	double Ti, Xi;
 	int curr_hw_errors, i;
 	bool was_hw_error;
+	bool was_first_run;
 
 	struct ICARUS_HISTORY *history0, *history;
 	int count;
@@ -805,19 +894,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	icarus = thr->cgpu;
 	struct icarus_state *state = thr->cgpu_data;
+	was_first_run = state->firstrun;
 
-	// Prepare the next work immediately
-	memcpy(ob_bin, work->midstate, 32);
-	memcpy(ob_bin + 52, work->data + 64, 12);
-	if (!(memcmp(&ob_bin[56], "\xff\xff\xff\xff", 4)
-	   || memcmp(&ob_bin, "\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", 32))) {
-		// This sequence is used on cairnsmore bitstreams for commands, NEVER send it otherwise
-		applog(LOG_WARNING, "%"PRIpreprv": Received job attempting to send a command, corrupting it!",
-		       icarus->proc_repr);
-		ob_bin[56] = 0;
-	}
-	rev(ob_bin, 32);
-	rev(ob_bin + 52, 12);
+	icarus_job_prepare(thr, work, max_nonce);
 
 	// Wait for the previous run's result
 	fd = icarus->device_fd;
@@ -871,17 +950,20 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	// 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(!state->firstrun)) {
+	if (info->dclk.freqM && likely(!was_first_run)) {
 		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))
 			dclk_errorCount(&info->dclk, qsec);
-		dclk_preUpdate(&info->dclk);
-		dclk_updateFreq(&info->dclk, info->dclk_change_clock_func, thr);
 	}
 
-	if (!icarus_start_work(thr, ob_bin))
+	if (unlikely(state->identify))
+	{
+		// Delay job start until later...
+	}
+	else
+	if (!icarus_job_start(thr))
 		/* This should never happen */
 		state->firstrun = true;
 
@@ -890,10 +972,11 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	work->blk.nonce = 0xffffffff;
 
-	if (state->firstrun) {
+	if (was_first_run) {
 		state->firstrun = false;
 		__copy_work(&state->last_work, work);
-		return 0;
+		hash_count = 0;
+		goto out;
 	}
 
 	// OK, done starting Icarus's next job... now process the last run's result!
@@ -918,7 +1001,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 					(int64_t)elapsed.tv_sec, (unsigned long)elapsed.tv_usec);
 		}
 
-		return estimate_hashes;
+		hash_count = estimate_hashes;
+		goto out;
 	}
 
 	curr_hw_errors = icarus->hw_errors;
@@ -932,7 +1016,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 			if (!icarus_reopen(icarus, state, &fd))
 				state->firstrun = true;
 			// Some devices (Cairnsmore1, for example) abort hashing when reopened, so send the job again
-			if (!icarus_start_work(thr, ob_bin))
+			if (!icarus_job_start(thr))
 				state->firstrun = true;
 		}
 
@@ -1079,6 +1163,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		timeradd(&tv_history_finish, &(info->history_time), &(info->history_time));
 	}
 
+out:
+	if (unlikely(state->identify))
+		handle_identify(thr, ret, was_first_run);
+	
 	return hash_count;
 }
 

+ 3 - 0
icarus-common.h

@@ -94,6 +94,9 @@ struct icarus_state {
 	struct timeval tv_workfinish;
 	struct work last_work;
 	bool changework;
+	bool identify;
+	
+	uint8_t ob_bin[64];
 };
 
 bool icarus_detect_custom(const char *devpath, struct device_drv *, struct ICARUS_INFO *);