Commit b0573a07918b30eddf28a453b57e466e818eca5f

Con Kolivas 2013-11-09T23:23:01

Merge branch 'master' into nogpu

diff --git a/README b/README
index 025e8e5..78c32cc 100644
--- a/README
+++ b/README
@@ -119,6 +119,7 @@ Basic *nix build instructions:
 
 	./autogen.sh	# only needed if building from git repo
 	CFLAGS="-O2 -Wall -march=native" ./configure <options>
+	make
 
 	No installation is necessary. You may run cgminer from the build
 	directory directly, but you may do make install if you wish to install
diff --git a/cgminer.c b/cgminer.c
index b7a8361..4249fa2 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -6233,6 +6233,13 @@ static void fill_queue(struct thr_info *mythr, struct cgpu_info *cgpu, struct de
 	} while (!drv->queue_full(cgpu));
 }
 
+/* Add a work item to a cgpu's queued hashlist */
+void __add_queued(struct cgpu_info *cgpu, struct work *work)
+{
+	cgpu->queued_count++;
+	HASH_ADD_INT(cgpu->queued_work, id, work);
+}
+
 /* This function is for retrieving one work item from the unqueued pointer and
  * adding it to the hashtable of queued work. Code using this function must be
  * able to handle NULL as a return which implies there is no work available. */
@@ -6243,7 +6250,7 @@ struct work *get_queued(struct cgpu_info *cgpu)
 	wr_lock(&cgpu->qlock);
 	if (cgpu->unqueued_work) {
 		work = cgpu->unqueued_work;
-		HASH_ADD_INT(cgpu->queued_work, id, work);
+		__add_queued(cgpu, work);
 		cgpu->unqueued_work = NULL;
 	}
 	wr_unlock(&cgpu->qlock);
@@ -6251,6 +6258,22 @@ struct work *get_queued(struct cgpu_info *cgpu)
 	return work;
 }
 
+void add_queued(struct cgpu_info *cgpu, struct work *work)
+{
+	wr_lock(&cgpu->qlock);
+	__add_queued(cgpu, work);
+	wr_unlock(&cgpu->qlock);
+}
+
+/* Get fresh work and add it to cgpu's queued hashlist */
+struct work *get_queue_work(struct thr_info *thr, struct cgpu_info *cgpu, int thr_id)
+{
+	struct work *work = get_work(thr, thr_id);
+
+	add_queued(cgpu, work);
+	return work;
+}
+
 /* This function is for finding an already queued work item in the
  * given que hashtable. Code using this function must be able
  * to handle NULL as a return which implies there is no matching work.
diff --git a/driver-bitfury.c b/driver-bitfury.c
index 69f3aca..b177626 100644
--- a/driver-bitfury.c
+++ b/driver-bitfury.c
@@ -210,7 +210,9 @@ static bool bitfury_checkresults(struct thr_info *thr, struct work *work, uint32
 	int i;
 
 	for (i = 0; i < BT_OFFSETS; i++) {
-		if (test_nonce(work, nonce + bf_offsets[i])) {
+		uint32_t noffset = nonce + bf_offsets[i];
+
+		if (test_nonce(work, noffset)) {
 			submit_tested_work(thr, work);
 			return true;
 		}
@@ -222,18 +224,18 @@ static int64_t bitfury_scanwork(struct thr_info *thr)
 {
 	struct cgpu_info *bitfury = thr->cgpu;
 	struct bitfury_info *info = bitfury->device_data;
+	struct work *work, *tmp;
+	int amount, i, aged = 0;
 	struct timeval tv_now;
-	struct work *work;
 	double nonce_rate;
 	int64_t ret = 0;
-	int amount, i;
 	char buf[45];
 	int ms_diff;
 
-	work = get_work(thr, thr->id);
+	work = get_queue_work(thr, bitfury, thr->id);
 	if (unlikely(thr->work_restart)) {
-		free_work(work);
-		return 0;
+		work_completed(bitfury, work);
+		goto out;
 	}
 
 	buf[0] = 'W';
@@ -251,7 +253,7 @@ static int64_t bitfury_scanwork(struct thr_info *thr)
 	}
 
 	if (unlikely(thr->work_restart))
-		goto cascade;
+		goto out;
 
 	/* Now look for the bulk of the previous work results, they will come
 	 * in a batch following the first data. */
@@ -268,41 +270,60 @@ static int64_t bitfury_scanwork(struct thr_info *thr)
 	};
 
 	if (unlikely(thr->work_restart))
-		goto cascade;
+		goto out;
 
 	/* Send work */
+	cgtime(&work->tv_work_start);
 	usb_write(bitfury, buf, 45, &amount, C_BF1_REQWORK);
 	cgtime(&info->tv_start);
+
 	/* Get response acknowledging work */
 	usb_read(bitfury, buf, BF1MSGSIZE, &amount, C_BF1_GETWORK);
 
-	/* Only happens on startup */
-	if (unlikely(!info->prevwork[BF1ARRAY_SIZE]))
-		goto cascade;
-
 	/* Search for what work the nonce matches in order of likelihood. Last
 	 * entry is end of result marker. */
 	for (i = 0; i < info->tot - BF1MSGSIZE; i += BF1MSGSIZE) {
+		bool found = false;
 		uint32_t nonce;
-		int j;
 
 		/* Ignore state & switched data in results for now. */
 		memcpy(&nonce, info->buf + i + 3, 4);
 		nonce = decnonce(nonce);
-		for (j = 0; j < BF1ARRAY_SIZE; j++) {
-			if (bitfury_checkresults(thr, info->prevwork[j], nonce)) {
+
+		rd_lock(&bitfury->qlock);
+		HASH_ITER(hh, bitfury->queued_work, work, tmp) {
+			if (bitfury_checkresults(thr, work, nonce)) {
 				info->nonces++;
+				found = true;
 				break;
 			}
 		}
+		rd_unlock(&bitfury->qlock);
+
+		if (!found)
+			inc_hw_errors(thr);
 	}
 
 	info->tot = 0;
-	free_work(info->prevwork[BF1ARRAY_SIZE]);
-cascade:
-	for (i = BF1ARRAY_SIZE; i > 0; i--)
-		info->prevwork[i] = info->prevwork[i - 1];
-	info->prevwork[0] = work;
+out:
+	cgtime(&tv_now);
+
+	/* This iterates over the hashlist finding work started more than 6
+	 * seconds ago which equates to leaving 5 past work items in the array
+	 * to look for results. */
+	wr_lock(&bitfury->qlock);
+	HASH_ITER(hh, bitfury->queued_work, work, tmp) {
+		if (tdiff(&tv_now, &work->tv_work_start) > 6.0) {
+			__work_completed(bitfury, work);
+			aged++;
+		}
+	}
+	wr_unlock(&bitfury->qlock);
+
+	if (aged) {
+		applog(LOG_DEBUG, "%s %d: Aged %d work items", bitfury->drv->name,
+		       bitfury->device_id, aged);
+	}
 
 	info->cycles++;
 	info->total_nonces += info->nonces;
diff --git a/driver-bitfury.h b/driver-bitfury.h
index 07e795f..2f09de1 100644
--- a/driver-bitfury.h
+++ b/driver-bitfury.h
@@ -13,14 +13,11 @@
 #include "miner.h"
 #include "usbutils.h"
 
-#define BF1ARRAY_SIZE 2
-
 struct bitfury_info {
 	struct cgpu_info *base_cgpu;
 	uint8_t version;
 	char product[8];
 	uint32_t serial;
-	struct work *prevwork[BF1ARRAY_SIZE + 1];
 	char buf[512];
 	int tot;
 	int nonces;
diff --git a/miner.h b/miner.h
index f5a012b..bbcff0c 100644
--- a/miner.h
+++ b/miner.h
@@ -1435,7 +1435,10 @@ extern bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce
 extern bool submit_noffset_nonce(struct thr_info *thr, struct work *work, uint32_t nonce,
 			  int noffset);
 extern struct work *get_work(struct thr_info *thr, const int thr_id);
+extern void __add_queued(struct cgpu_info *cgpu, struct work *work);
 extern struct work *get_queued(struct cgpu_info *cgpu);
+extern void add_queued(struct cgpu_info *cgpu, struct work *work);
+extern struct work *get_queue_work(struct thr_info *thr, struct cgpu_info *cgpu, int thr_id);
 extern struct work *__find_work_bymidstate(struct work *que, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen);
 extern struct work *find_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen);
 extern struct work *clone_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen);