Browse Source

bitforce: Minimally refactor to adapt to new minerloop_async

Luke Dashjr 13 years ago
parent
commit
bdf34c72ed
4 changed files with 186 additions and 116 deletions
  1. 12 10
      HACKING
  2. 10 6
      deviceapi.c
  3. 1 0
      deviceapi.h
  4. 163 100
      driver-bitforce.c

+ 12 - 10
HACKING

@@ -88,11 +88,12 @@ and should start the job most recently prepared with `job_prepare`. Note that
 it is possible for `job_prepare` to be called for a job that never starts
 it is possible for `job_prepare` to be called for a job that never starts
 (another `job_prepare` may be executed to override the previous one instead).
 (another `job_prepare` may be executed to override the previous one instead).
 `job_start` must call `mt_job_transition` as soon as the actual switchover to
 `job_start` must call `mt_job_transition` as soon as the actual switchover to
-the new job takes place, and must call `job_start_complete` when finished.
-`job_start` must set `thr->tv_morework` to the time the device expects to need
-its next work item. It is generally advisable to set this a bit early to ensure
-any delays do not make it late. `job_start` is expected to always succeed and
-does not have a return value.
+the new job takes place, and must call `job_start_complete` when successful;
+in case of a failure, it should call `job_start_abort` instead. `job_start`
+must set `thr->tv_morework` to the time the device expects to need its next
+work item. It is generally advisable to set this a bit early to ensure any
+delays do not make it late. `job_start` is expected to always succeed and does
+not have a return value.
 
 
 Immediately before `job_start` is called to change from one job to the next,
 Immediately before `job_start` is called to change from one job to the next,
 `job_get_results` will be called to fetch any volatile results from the
 `job_get_results` will be called to fetch any volatile results from the
@@ -100,11 +101,12 @@ previous job. It is provided the Processor's `struct thr_info *` and the
 currently executing job's `struct work *`. It should ONLY fetch the raw data
 currently executing job's `struct work *`. It should ONLY fetch the raw data
 for the results, and not spend any time processing or submitting it. If
 for the results, and not spend any time processing or submitting it. If
 `job_get_results` is defined for your driver, it must (directly or indirectly)
 `job_get_results` is defined for your driver, it must (directly or indirectly)
-ensure `job_results_fetched` is called when complete. After the new job has
-been started, your driver's `job_process_results` function will be called to
-complete the submission of these results with the same arguments, plus a bool
-to tell you whether the processor is being stopped. If it is, your driver must
-call `mt_disable_start` when it has successfully stopped hashing.
+ensure `job_results_fetched` is called when complete (including the case of
+failure). After the new job has been started, your driver's
+`job_process_results` function will be called to complete the submission of
+these results with the same arguments, plus a bool to tell you whether the
+processor is being stopped. If it is, your driver must call `mt_disable_start`
+when it has successfully stopped hashing.
 
 
 Drivers may define a `poll` function. If this is defined, `thr->tv_poll` must
 Drivers may define a `poll` function. If this is defined, `thr->tv_poll` must
 always be set to a valid time to next execute it, for each Processor.
 always be set to a valid time to next execute it, for each Processor.

+ 10 - 6
deviceapi.c

@@ -248,13 +248,17 @@ void job_start_complete(struct thr_info *mythr)
 	
 	
 	gettimeofday(&tv_now, NULL);
 	gettimeofday(&tv_now, NULL);
 	
 	
-	if (!do_process_results(mythr, &tv_now, mythr->prev_work, false))
-	{
-		struct cgpu_info *proc = mythr->cgpu;
-		
+	do_process_results(mythr, &tv_now, mythr->prev_work, false);
+}
+
+void job_start_abort(struct thr_info *mythr, bool failure)
+{
+	struct cgpu_info *proc = mythr->cgpu;
+	
+	if (failure)
 		proc->deven = DEV_RECOVER_ERR;
 		proc->deven = DEV_RECOVER_ERR;
-		mythr->_job_transition_in_progress = false;
-	}
+	mythr->work = NULL;
+	mythr->_job_transition_in_progress = false;
 }
 }
 
 
 bool do_process_results(struct thr_info *mythr, struct timeval *tvp_now, struct work *work, bool stopping)
 bool do_process_results(struct thr_info *mythr, struct timeval *tvp_now, struct work *work, bool stopping)

+ 1 - 0
deviceapi.h

@@ -23,6 +23,7 @@ extern void job_results_fetched(struct thr_info *);
 extern void do_job_start(struct thr_info *);
 extern void do_job_start(struct thr_info *);
 extern void mt_job_transition(struct thr_info *);
 extern void mt_job_transition(struct thr_info *);
 extern void job_start_complete(struct thr_info *);
 extern void job_start_complete(struct thr_info *);
+extern void job_start_abort(struct thr_info *, bool failure);
 extern bool do_process_results(struct thr_info *, struct timeval *tvp_now, struct work *, bool stopping);
 extern bool do_process_results(struct thr_info *, struct timeval *tvp_now, struct work *, bool stopping);
 extern void minerloop_async(struct thr_info *);
 extern void minerloop_async(struct thr_info *);
 
 

+ 163 - 100
driver-bitforce.c

@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <unistd.h>
 
 
 #include "compat.h"
 #include "compat.h"
+#include "deviceapi.h"
 #include "miner.h"
 #include "miner.h"
 #include "fpgautils.h"
 #include "fpgautils.h"
 
 
@@ -95,16 +96,6 @@ static bool bitforce_detect_one(const char *devpath)
 	bitforce->device_path = strdup(devpath);
 	bitforce->device_path = strdup(devpath);
 	bitforce->deven = DEV_ENABLED;
 	bitforce->deven = DEV_ENABLED;
 	bitforce->threads = 1;
 	bitforce->threads = 1;
-	/* Initially enable support for nonce range and disable it later if it
-	 * fails */
-	if (opt_bfl_noncerange) {
-		bitforce->nonce_range = true;
-		bitforce->sleep_ms = BITFORCE_SLEEP_MS;
-		bitforce->kname = KNAME_RANGE;
-	} else {
-		bitforce->sleep_ms = BITFORCE_SLEEP_MS * 5;
-		bitforce->kname = KNAME_WORK;
-	}
 
 
 	if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
 	if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
 		s[0] = '\0';
 		s[0] = '\0';
@@ -126,6 +117,35 @@ static void bitforce_detect(void)
 	serial_detect_auto(&bitforce_api, bitforce_detect_one, bitforce_detect_auto);
 	serial_detect_auto(&bitforce_api, bitforce_detect_one, bitforce_detect_auto);
 }
 }
 
 
+struct bitforce_data {
+	unsigned char next_work_ob[70];
+	char noncebuf[0x100];
+};
+
+static void bitforce_clear_buffer(struct cgpu_info *);
+
+static
+void bitforce_comm_error(struct thr_info *thr)
+{
+	struct cgpu_info *bitforce = thr->cgpu;
+	struct bitforce_data *data = bitforce->cgpu_data;
+	
+	data->noncebuf[0] = '\0';
+	applog(LOG_ERR, "%"PRIpreprv": Comms error", bitforce->proc_repr);
+	dev_error(bitforce, REASON_DEV_COMMS_ERROR);
+	++bitforce->hw_errors;
+	++hw_errors;
+	BFclose(bitforce->device_fd);
+	int fd = bitforce->device_fd = BFopen(bitforce->device_path);
+	if (fd == -1)
+	{
+		applog(LOG_ERR, "%"PRIpreprv": Error reopening", bitforce->proc_repr);
+		return;
+	}
+	/* empty read buffer */
+	bitforce_clear_buffer(bitforce);
+}
+
 static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
 static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
 {
 {
 	float gt = bitforce->temp;
 	float gt = bitforce->temp;
@@ -328,16 +348,67 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
 	return true;
 	return true;
 }
 }
 
 
-static bool bitforce_send_work(struct thr_info *thr, struct work *work)
+static
+bool bitforce_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused uint64_t max_nonce)
 {
 {
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct cgpu_info *bitforce = thr->cgpu;
+	struct bitforce_data *data = bitforce->cgpu_data;
+	unsigned char *ob_ms = &data->next_work_ob[8];
+	unsigned char *ob_dt = &ob_ms[32];
+	
+	memcpy(ob_ms, work->midstate, 32);
+	memcpy(ob_dt, work->data + 64, 12);
+	if (bitforce->nonce_range)
+	{
+		uint32_t *ob_nonce = (uint32_t*)&(ob_dt[32]);
+		ob_nonce[0] = htobe32(work->blk.nonce);
+		ob_nonce[1] = htobe32(work->blk.nonce + bitforce->nonces);
+		// FIXME: if nonce range fails... we didn't increment enough
+		work->blk.nonce += bitforce->nonces + 1;
+	}
+	else
+		work->blk.nonce = 0xffffffff;
+	
+	return true;
+}
+
+static
+void bitforce_change_mode(struct cgpu_info *bitforce, bool noncerange)
+{
+	struct bitforce_data *data = bitforce->cgpu_data;
+	
+	if (bitforce->nonce_range == noncerange)
+		return;
+	bitforce->nonce_range = noncerange;
+	if (noncerange)
+	{
+		/* Split work up into 1/5th nonce ranges */
+		bitforce->nonces = 0x33333332;
+		bitforce->sleep_ms /= 5;
+		bitforce->kname = KNAME_RANGE;
+	}
+	else
+	{
+		bitforce->nonces = 0xffffffff;
+		bitforce->sleep_ms *= 5;
+		bitforce->kname = KNAME_WORK;
+		memset(&data->next_work_ob[8+32+12], '>', 8);
+	}
+}
+
+static
+void bitforce_job_start(struct thr_info *thr)
+{
+	struct cgpu_info *bitforce = thr->cgpu;
+	struct bitforce_data *data = bitforce->cgpu_data;
 	int fdDev = bitforce->device_fd;
 	int fdDev = bitforce->device_fd;
-	unsigned char ob[70];
+	unsigned char *ob = data->next_work_ob;
 	char pdevbuf[0x100];
 	char pdevbuf[0x100];
 	char *s;
 	char *s;
+	struct timeval tv_now;
 
 
 	if (!fdDev)
 	if (!fdDev)
-		return false;
+		goto commerr;
 re_send:
 re_send:
 	mutex_lock(&bitforce->device_mutex);
 	mutex_lock(&bitforce->device_mutex);
 	if (bitforce->nonce_range)
 	if (bitforce->nonce_range)
@@ -349,44 +420,31 @@ re_send:
 	if (!pdevbuf[0] || !strncasecmp(pdevbuf, "B", 1)) {
 	if (!pdevbuf[0] || !strncasecmp(pdevbuf, "B", 1)) {
 		mutex_unlock(&bitforce->device_mutex);
 		mutex_unlock(&bitforce->device_mutex);
 		if (!restart_wait(WORK_CHECK_INTERVAL_MS))
 		if (!restart_wait(WORK_CHECK_INTERVAL_MS))
-			return false;
+		{
+			job_start_abort(thr, false);
+			return;
+		}
 		goto re_send;
 		goto re_send;
 	} else if (unlikely(strncasecmp(pdevbuf, "OK", 2))) {
 	} else if (unlikely(strncasecmp(pdevbuf, "OK", 2))) {
 		mutex_unlock(&bitforce->device_mutex);
 		mutex_unlock(&bitforce->device_mutex);
 		if (bitforce->nonce_range) {
 		if (bitforce->nonce_range) {
 			applog(LOG_WARNING, "%"PRIpreprv": Does not support nonce range, disabling", bitforce->proc_repr);
 			applog(LOG_WARNING, "%"PRIpreprv": Does not support nonce range, disabling", bitforce->proc_repr);
-			bitforce->nonce_range = false;
-			bitforce->sleep_ms *= 5;
-			bitforce->kname = KNAME_WORK;
+			bitforce_change_mode(bitforce, false);
 			goto re_send;
 			goto re_send;
 		}
 		}
 		applog(LOG_ERR, "%"PRIpreprv": Error: Send work reports: %s", bitforce->proc_repr, pdevbuf);
 		applog(LOG_ERR, "%"PRIpreprv": Error: Send work reports: %s", bitforce->proc_repr, pdevbuf);
-		return false;
+		goto commerr;
 	}
 	}
 
 
-	sprintf((char *)ob, ">>>>>>>>");
-	memcpy(ob + 8, work->midstate, 32);
-	memcpy(ob + 8 + 32, work->data + 64, 12);
 	if (!bitforce->nonce_range) {
 	if (!bitforce->nonce_range) {
-		sprintf((char *)ob + 8 + 32 + 12, ">>>>>>>>");
-		work->blk.nonce = bitforce->nonces = 0xffffffff;
 		BFwrite(fdDev, ob, 60);
 		BFwrite(fdDev, ob, 60);
 	} else {
 	} else {
-		uint32_t *nonce;
-
-		nonce = (uint32_t *)(ob + 8 + 32 + 12);
-		*nonce = htobe32(work->blk.nonce);
-		nonce = (uint32_t *)(ob + 8 + 32 + 12 + 4);
-		/* Split work up into 1/5th nonce ranges */
-		bitforce->nonces = 0x33333332;
-		*nonce = htobe32(work->blk.nonce + bitforce->nonces);
-		work->blk.nonce += bitforce->nonces + 1;
-		sprintf((char *)ob + 8 + 32 + 12 + 8, ">>>>>>>>");
 		BFwrite(fdDev, ob, 68);
 		BFwrite(fdDev, ob, 68);
 	}
 	}
 
 
 	pdevbuf[0] = '\0';
 	pdevbuf[0] = '\0';
 	BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
 	BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
+	mt_job_transition(thr);
 	mutex_unlock(&bitforce->device_mutex);
 	mutex_unlock(&bitforce->device_mutex);
 
 
 	if (opt_debug) {
 	if (opt_debug) {
@@ -397,16 +455,25 @@ re_send:
 
 
 	if (unlikely(!pdevbuf[0])) {
 	if (unlikely(!pdevbuf[0])) {
 		applog(LOG_ERR, "%"PRIpreprv": Error: Send block data returned empty string/timed out", bitforce->proc_repr);
 		applog(LOG_ERR, "%"PRIpreprv": Error: Send block data returned empty string/timed out", bitforce->proc_repr);
-		return false;
+		goto commerr;
 	}
 	}
 
 
 	if (unlikely(strncasecmp(pdevbuf, "OK", 2))) {
 	if (unlikely(strncasecmp(pdevbuf, "OK", 2))) {
 		applog(LOG_ERR, "%"PRIpreprv": Error: Send block data reports: %s", bitforce->proc_repr, pdevbuf);
 		applog(LOG_ERR, "%"PRIpreprv": Error: Send block data reports: %s", bitforce->proc_repr, pdevbuf);
-		return false;
+		goto commerr;
 	}
 	}
 
 
-	gettimeofday(&bitforce->work_start_tv, NULL);
-	return true;
+	gettimeofday(&tv_now, NULL);
+	bitforce->work_start_tv = tv_now;
+	
+	timer_set_delay(&thr->tv_morework, &tv_now, bitforce->sleep_ms * 1000);
+	
+	job_start_complete(thr);
+	return;
+
+commerr:
+	bitforce_comm_error(thr);
+	job_start_abort(thr, true);
 }
 }
 
 
 static inline int noisy_stale_wait(unsigned int mstime, struct work*work, bool checkend, struct cgpu_info*bitforce)
 static inline int noisy_stale_wait(unsigned int mstime, struct work*work, bool checkend, struct cgpu_info*bitforce)
@@ -419,25 +486,30 @@ static inline int noisy_stale_wait(unsigned int mstime, struct work*work, bool c
 }
 }
 #define noisy_stale_wait(mstime, work, checkend)  noisy_stale_wait(mstime, work, checkend, bitforce)
 #define noisy_stale_wait(mstime, work, checkend)  noisy_stale_wait(mstime, work, checkend, bitforce)
 
 
-static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
+static
+void bitforce_job_get_results(struct thr_info *thr, struct work *work)
 {
 {
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct cgpu_info *bitforce = thr->cgpu;
+	struct bitforce_data *data = bitforce->cgpu_data;
 	int fdDev = bitforce->device_fd;
 	int fdDev = bitforce->device_fd;
 	unsigned int delay_time_ms;
 	unsigned int delay_time_ms;
 	struct timeval elapsed;
 	struct timeval elapsed;
 	struct timeval now;
 	struct timeval now;
-	char pdevbuf[0x100];
-	char *pnoncebuf;
-	uint32_t nonce;
+	char *pdevbuf = &data->noncebuf[0];
 
 
+	gettimeofday(&now, NULL);
+	timersub(&now, &bitforce->work_start_tv, &elapsed);
+	bitforce->wait_ms = tv_to_ms(elapsed);
+	bitforce->polling = true;
+	
 	if (!fdDev)
 	if (!fdDev)
-		return -1;
+		goto commerr;
 
 
 	while (1) {
 	while (1) {
 		mutex_lock(&bitforce->device_mutex);
 		mutex_lock(&bitforce->device_mutex);
 		BFwrite(fdDev, "ZFX", 3);
 		BFwrite(fdDev, "ZFX", 3);
 		pdevbuf[0] = '\0';
 		pdevbuf[0] = '\0';
-		BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
+		BFgets(pdevbuf, sizeof(data->noncebuf), fdDev);
 		mutex_unlock(&bitforce->device_mutex);
 		mutex_unlock(&bitforce->device_mutex);
 
 
 		gettimeofday(&now, NULL);
 		gettimeofday(&now, NULL);
@@ -446,7 +518,7 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
 		if (elapsed.tv_sec >= BITFORCE_LONG_TIMEOUT_S) {
 		if (elapsed.tv_sec >= BITFORCE_LONG_TIMEOUT_S) {
 			applog(LOG_ERR, "%"PRIpreprv": took %lums - longer than %lums", bitforce->proc_repr,
 			applog(LOG_ERR, "%"PRIpreprv": took %lums - longer than %lums", bitforce->proc_repr,
 				tv_to_ms(elapsed), (unsigned long)BITFORCE_LONG_TIMEOUT_MS);
 				tv_to_ms(elapsed), (unsigned long)BITFORCE_LONG_TIMEOUT_MS);
-			return 0;
+			goto out;
 		}
 		}
 
 
 		if (pdevbuf[0] && strncasecmp(pdevbuf, "B", 1)) /* BFL does not respond during throttling */
 		if (pdevbuf[0] && strncasecmp(pdevbuf, "B", 1)) /* BFL does not respond during throttling */
@@ -455,7 +527,7 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
 		/* if BFL is throttling, no point checking so quickly */
 		/* if BFL is throttling, no point checking so quickly */
 		delay_time_ms = (pdevbuf[0] ? BITFORCE_CHECK_INTERVAL_MS : 2 * WORK_CHECK_INTERVAL_MS);
 		delay_time_ms = (pdevbuf[0] ? BITFORCE_CHECK_INTERVAL_MS : 2 * WORK_CHECK_INTERVAL_MS);
 		if (noisy_stale_wait(delay_time_ms, work, true))
 		if (noisy_stale_wait(delay_time_ms, work, true))
-			return 0;
+			goto out;
 		bitforce->wait_ms += delay_time_ms;
 		bitforce->wait_ms += delay_time_ms;
 	}
 	}
 
 
@@ -471,7 +543,7 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
 		 * throttling.
 		 * throttling.
 		 */
 		 */
 		if (strncasecmp(pdevbuf, "NONCE-FOUND", 11))
 		if (strncasecmp(pdevbuf, "NONCE-FOUND", 11))
-			return 0;
+			goto out;
 	} else if (!strncasecmp(pdevbuf, "N", 1)) {/* Hashing complete (NONCE-FOUND or NO-NONCE) */
 	} else if (!strncasecmp(pdevbuf, "N", 1)) {/* Hashing complete (NONCE-FOUND or NO-NONCE) */
 		/* Simple timing adjustment. Allow a few polls to cope with
 		/* Simple timing adjustment. Allow a few polls to cope with
 		 * OS timer delays being variably reliable. wait_ms will
 		 * OS timer delays being variably reliable. wait_ms will
@@ -497,30 +569,45 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
 	}
 	}
 
 
 	applog(LOG_DEBUG, "%"PRIpreprv": waited %dms until %s", bitforce->proc_repr, bitforce->wait_ms, pdevbuf);
 	applog(LOG_DEBUG, "%"PRIpreprv": waited %dms until %s", bitforce->proc_repr, bitforce->wait_ms, pdevbuf);
-	if (!strncasecmp(&pdevbuf[2], "-", 1))
-		return bitforce->nonces;   /* No valid nonce found */
-	else if (!strncasecmp(pdevbuf, "I", 1))
-		return 0;	/* Device idle */
-	else if (strncasecmp(pdevbuf, "NONCE-FOUND", 11)) {
+	if (strncasecmp(pdevbuf, "NONCE-FOUND", 11) && (pdevbuf[2] != '-') && strncasecmp(pdevbuf, "I", 1)) {
 		bitforce->hw_errors++;
 		bitforce->hw_errors++;
 		++hw_errors;
 		++hw_errors;
 		applog(LOG_WARNING, "%"PRIpreprv": Error: Get result reports: %s", bitforce->proc_repr, pdevbuf);
 		applog(LOG_WARNING, "%"PRIpreprv": Error: Get result reports: %s", bitforce->proc_repr, pdevbuf);
 		bitforce_clear_buffer(bitforce);
 		bitforce_clear_buffer(bitforce);
-		return 0;
 	}
 	}
+out:
+	bitforce->polling = false;
+	job_results_fetched(thr);
+	return;
 
 
-	pnoncebuf = &pdevbuf[12];
+commerr:
+	bitforce_comm_error(thr);
+	goto out;
+}
 
 
+static
+int64_t bitforce_job_process_results(struct thr_info *thr, struct work *work, __maybe_unused bool stopping)
+{
+	struct cgpu_info *bitforce = thr->cgpu;
+	struct bitforce_data *data = bitforce->cgpu_data;
+	char *pnoncebuf = &data->noncebuf[0];
+	uint32_t nonce;
+	
+	if (!strncasecmp(pnoncebuf, "NO-", 3))
+		return bitforce->nonces;   /* No valid nonce found */
+	if (strncasecmp(pnoncebuf, "NONCE-FOUND", 11))
+		return 0;
+
+	pnoncebuf += 12;
+	
 	while (1) {
 	while (1) {
 		hex2bin((void*)&nonce, pnoncebuf, 4);
 		hex2bin((void*)&nonce, pnoncebuf, 4);
 		nonce = be32toh(nonce);
 		nonce = be32toh(nonce);
 		if (unlikely(bitforce->nonce_range && (nonce >= work->blk.nonce ||
 		if (unlikely(bitforce->nonce_range && (nonce >= work->blk.nonce ||
+			/* FIXME: blk.nonce is probably moved on quite a bit now! */
 			(work->blk.nonce > 0 && nonce < work->blk.nonce - bitforce->nonces - 1)))) {
 			(work->blk.nonce > 0 && nonce < work->blk.nonce - bitforce->nonces - 1)))) {
 				applog(LOG_WARNING, "%"PRIpreprv": Disabling broken nonce range support", bitforce->proc_repr);
 				applog(LOG_WARNING, "%"PRIpreprv": Disabling broken nonce range support", bitforce->proc_repr);
-				bitforce->nonce_range = false;
-				work->blk.nonce = 0xffffffff;
-				bitforce->sleep_ms *= 5;
-				bitforce->kname = KNAME_WORK;
+				bitforce_change_mode(bitforce, false);
 		}
 		}
 			
 			
 		submit_nonce(thr, work, nonce);
 		submit_nonce(thr, work, nonce);
@@ -529,6 +616,7 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
 		pnoncebuf += 9;
 		pnoncebuf += 9;
 	}
 	}
 
 
+	// FIXME: This might have changed in the meantime (new job start, or broken)
 	return bitforce->nonces;
 	return bitforce->nonces;
 }
 }
 
 
@@ -547,48 +635,6 @@ static void biforce_thread_enable(struct thr_info *thr)
 	bitforce_init(bitforce);
 	bitforce_init(bitforce);
 }
 }
 
 
-static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
-{
-	struct cgpu_info *bitforce = thr->cgpu;
-	int64_t ret;
-
-	if (!bitforce_send_work(thr, work)) {
-		if (thr->work_restart)
-			return 0;
-		sleep(opt_fail_pause);
-		goto commerr;
-	}
-
-	if (noisy_stale_wait(bitforce->sleep_ms, work, true))
-		return 0;
-
-	bitforce->wait_ms = bitforce->sleep_ms;
-
-	{
-		bitforce->polling = true;
-		ret = bitforce_get_result(thr, work);
-		bitforce->polling = false;
-	}
-
-	if (ret == -1) {
-commerr:
-		ret = 0;
-		applog(LOG_ERR, "%"PRIpreprv": Comms error", bitforce->proc_repr);
-		dev_error(bitforce, REASON_DEV_COMMS_ERROR);
-		bitforce->hw_errors++;
-		++hw_errors;
-		BFclose(bitforce->device_fd);
-		int fd = bitforce->device_fd = BFopen(bitforce->device_path);
-		if (fd == -1) {
-			applog(LOG_ERR, "%"PRIpreprv": Error reopening", bitforce->proc_repr);
-			return -1;
-		}
-		/* empty read buffer */
-		bitforce_clear_buffer(bitforce);
-	}
-	return ret;
-}
-
 static bool bitforce_get_stats(struct cgpu_info *bitforce)
 static bool bitforce_get_stats(struct cgpu_info *bitforce)
 {
 {
 	return bitforce_get_temp(bitforce);
 	return bitforce_get_temp(bitforce);
@@ -604,6 +650,19 @@ static bool bitforce_thread_init(struct thr_info *thr)
 {
 {
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct cgpu_info *bitforce = thr->cgpu;
 	unsigned int wait;
 	unsigned int wait;
+	struct bitforce_data *data;
+	
+	bitforce->cgpu_data = data = malloc(sizeof(*data));
+	*data = (struct bitforce_data){
+		.next_work_ob = ">>>>>>>>|---------- MidState ----------||-DataTail-|>>>>>>>>>>>>>>>>",
+	};
+	bitforce->nonce_range = true;
+	bitforce->sleep_ms = BITFORCE_SLEEP_MS;
+	bitforce_change_mode(bitforce, false);
+	/* Initially enable support for nonce range and disable it later if it
+	 * fails */
+	if (opt_bfl_noncerange)
+		bitforce_change_mode(bitforce, true);
 
 
 	/* Pause each new thread at least 100ms between initialising
 	/* Pause each new thread at least 100ms between initialising
 	 * so the devices aren't making calls all at the same time. */
 	 * so the devices aren't making calls all at the same time. */
@@ -633,13 +692,17 @@ struct device_api bitforce_api = {
 	.name = "BFL",
 	.name = "BFL",
 	.api_detect = bitforce_detect,
 	.api_detect = bitforce_detect,
 	.get_api_stats = bitforce_api_stats,
 	.get_api_stats = bitforce_api_stats,
+	.minerloop = minerloop_async,
 	.reinit_device = bitforce_init,
 	.reinit_device = bitforce_init,
 	.get_statline_before = get_bitforce_statline_before,
 	.get_statline_before = get_bitforce_statline_before,
 	.get_stats = bitforce_get_stats,
 	.get_stats = bitforce_get_stats,
 	.identify_device = bitforce_identify,
 	.identify_device = bitforce_identify,
 	.thread_prepare = bitforce_thread_prepare,
 	.thread_prepare = bitforce_thread_prepare,
 	.thread_init = bitforce_thread_init,
 	.thread_init = bitforce_thread_init,
-	.scanhash = bitforce_scanhash,
+	.job_prepare = bitforce_job_prepare,
+	.job_start = bitforce_job_start,
+	.job_get_results = bitforce_job_get_results,
+	.job_process_results = bitforce_job_process_results,
 	.thread_shutdown = bitforce_shutdown,
 	.thread_shutdown = bitforce_shutdown,
 	.thread_enable = biforce_thread_enable
 	.thread_enable = biforce_thread_enable
 };
 };