Browse Source

Merge branch 'master' into hashfast

Con Kolivas 12 years ago
parent
commit
5c9f30369a
7 changed files with 204 additions and 146 deletions
  1. 1 1
      ASIC-README
  2. 1 0
      README
  3. 28 66
      cgminer.c
  4. 109 51
      driver-klondike.c
  5. 24 10
      usbutils.c
  6. 2 1
      usbutils.h
  7. 39 17
      util.c

+ 1 - 1
ASIC-README

@@ -105,7 +105,7 @@ ASIC SPECIFIC COMMANDS
 --bitburner-fury-options <arg> Override avalon-options for BitBurner Fury boards baud:miners:asic:timeout:freq
 --bitburner-fury-options <arg> Override avalon-options for BitBurner Fury boards baud:miners:asic:timeout:freq
 --bitburner-fury-voltage <arg> Set BitBurner Fury core voltage, in millivolts
 --bitburner-fury-voltage <arg> Set BitBurner Fury core voltage, in millivolts
 --bitburner-voltage <arg> Set BitBurner (Avalon) core voltage, in millivolts
 --bitburner-voltage <arg> Set BitBurner (Avalon) core voltage, in millivolts
---klondike-options <arg> Set klondike options clock:temp1:temp2:fan
+--klondike-options <arg> Set klondike options clock:temptarget
 
 
 
 
 AVALON AND BITBURNER DEVICES
 AVALON AND BITBURNER DEVICES

+ 1 - 0
README

@@ -227,6 +227,7 @@ ASIC only options:
 --bitburner-fury-options <arg> Override avalon-options for BitBurner Fury boards baud:miners:asic:timeout:freq
 --bitburner-fury-options <arg> Override avalon-options for BitBurner Fury boards baud:miners:asic:timeout:freq
 --bitburner-fury-voltage <arg> Set BitBurner Fury core voltage, in millivolts
 --bitburner-fury-voltage <arg> Set BitBurner Fury core voltage, in millivolts
 --bitburner-voltage <arg> Set BitBurner (Avalon) core voltage, in millivolts
 --bitburner-voltage <arg> Set BitBurner (Avalon) core voltage, in millivolts
+--klondike-options <arg> Set klondike options clock:temptarget
 
 
 See ASIC-README for more information regarding these.
 See ASIC-README for more information regarding these.
 
 

+ 28 - 66
cgminer.c

@@ -1274,7 +1274,7 @@ static struct opt_table opt_config_table[] = {
 #ifdef USE_KLONDIKE
 #ifdef USE_KLONDIKE
 	OPT_WITH_ARG("--klondike-options",
 	OPT_WITH_ARG("--klondike-options",
 		     set_klondike_options, NULL, NULL,
 		     set_klondike_options, NULL, NULL,
-		     "Set klondike options clock:temp1:temp2:fan"),
+		     "Set klondike options clock:temptarget"),
 #endif
 #endif
 	OPT_WITHOUT_ARG("--load-balance",
 	OPT_WITHOUT_ARG("--load-balance",
 		     set_loadbalance, &pool_strategy,
 		     set_loadbalance, &pool_strategy,
@@ -4030,51 +4030,20 @@ static int block_sort(struct block *blocka, struct block *blockb)
 	return blocka->block_no - blockb->block_no;
 	return blocka->block_no - blockb->block_no;
 }
 }
 
 
+/* Decode the current block difficulty which is in packed form */
 static void set_blockdiff(const struct work *work)
 static void set_blockdiff(const struct work *work)
 {
 {
-	uint64_t *data64, d64, diff64;
-	double previous_diff;
-	uint32_t diffhash[8];
-	uint32_t difficulty;
-	uint32_t diffbytes;
-	uint32_t diffvalue;
-	char rhash[32];
-	int diffshift;
-
-	difficulty = swab32(*((uint32_t *)(work->data + 72)));
-
-	diffbytes = ((difficulty >> 24) & 0xff) - 3;
-	diffvalue = difficulty & 0x00ffffff;
-
-	diffshift = (diffbytes % 4) * 8;
-	if (diffshift == 0) {
-		diffshift = 32;
-		diffbytes--;
-	}
-
-	memset(diffhash, 0, 32);
-	diffbytes >>= 2;
-	if (unlikely(diffbytes > 6))
-		return;
-	diffhash[diffbytes + 1] = diffvalue >> (32 - diffshift);
-	diffhash[diffbytes] = diffvalue << diffshift;
-
-	swab256(rhash, diffhash);
-
-	if (opt_scrypt)
-		data64 = (uint64_t *)(rhash + 2);
-	else
-		data64 = (uint64_t *)(rhash + 4);
-	d64 = bswap_64(*data64);
-	if (unlikely(!d64))
-		d64 = 1;
+	uint8_t pow = work->data[72];
+	int powdiff = (8 * (0x1d - 3)) - (8 * (pow - 3));
+	uint32_t diff32 = swab32(*((uint32_t *)(work->data + 72))) & 0x00FFFFFF;
+	double numerator = 0xFFFFULL << powdiff;
+	double ddiff = numerator / (double)diff32;
 
 
-	previous_diff = current_diff;
-	diff64 = diffone / d64;
-	suffix_string(diff64, block_diff, sizeof(block_diff), 0);
-	current_diff = (double)diffone / (double)d64;
-	if (unlikely(current_diff != previous_diff))
+	if (unlikely(current_diff != ddiff)) {
+		suffix_string(ddiff, block_diff, sizeof(block_diff), 0);
+		current_diff = ddiff;
 		applog(LOG_NOTICE, "Network diff set to %s", block_diff);
 		applog(LOG_NOTICE, "Network diff set to %s", block_diff);
+	}
 }
 }
 
 
 static bool test_work_current(struct work *work)
 static bool test_work_current(struct work *work)
@@ -5929,38 +5898,23 @@ static void gen_hash(unsigned char *data, unsigned char *hash, int len)
 	sha256(hash1, 32, hash);
 	sha256(hash1, 32, hash);
 }
 }
 
 
-/* Diff 1 is a 256 bit unsigned integer of
- * 0x00000000ffff0000000000000000000000000000000000000000000000000000
- * so we use a big endian 64 bit unsigned integer centred on the 5th byte to
- * cover a huge range of difficulty targets, though not all 256 bits' worth */
 void set_target(unsigned char *dest_target, double diff)
 void set_target(unsigned char *dest_target, double diff)
 {
 {
-	unsigned char target[32];
+	unsigned char target[32], rtarget[32];
 	uint64_t *data64, h64;
 	uint64_t *data64, h64;
 	double d64;
 	double d64;
 
 
-	d64 = diffone;
+	if (opt_scrypt)
+		d64 = 0xFFFF00000000ull;
+	else
+		d64 = 0xFFFF0000ull;
 	d64 /= diff;
 	d64 /= diff;
 	h64 = d64;
 	h64 = d64;
 
 
-	memset(target, 0, 32);
-	if (h64) {
-		unsigned char rtarget[32];
-
-		memset(rtarget, 0, 32);
-		if (opt_scrypt)
-			data64 = (uint64_t *)(rtarget + 2);
-		else
-			data64 = (uint64_t *)(rtarget + 4);
-		*data64 = htobe64(h64);
-		swab256(target, rtarget);
-	} else {
-		/* Support for the classic all FFs just-below-1 diff */
-		if (opt_scrypt)
-			memset(target, 0xff, 30);
-		else
-			memset(target, 0xff, 28);
-	}
+	memset(rtarget, 0xFF, 32);
+	data64 = (uint64_t *)rtarget;
+	*data64 = htobe64(h64);
+	swab256(target, rtarget);
 
 
 	if (opt_debug) {
 	if (opt_debug) {
 		char *htarget = bin2hex(target, 32);
 		char *htarget = bin2hex(target, 32);
@@ -6145,6 +6099,14 @@ static void update_work_stats(struct thr_info *thr, struct work *work)
 {
 {
 	work->share_diff = share_diff(work);
 	work->share_diff = share_diff(work);
 
 
+	if (unlikely(work->share_diff >= current_diff)) {
+		work->block = true;
+		work->pool->solved++;
+		found_blocks++;
+		work->mandatory = true;
+		applog(LOG_NOTICE, "Found block for pool %d!", work->pool->pool_no);
+	}
+
 	mutex_lock(&stats_lock);
 	mutex_lock(&stats_lock);
 	total_diff1 += work->device_diff;
 	total_diff1 += work->device_diff;
 	thr->cgpu->diff1 += work->device_diff;
 	thr->cgpu->diff1 += work->device_diff;

+ 109 - 51
driver-klondike.c

@@ -63,9 +63,6 @@ static const char *msg_reply = "Reply";
 #define KLN_KILLWORK_TEMP	53.5
 #define KLN_KILLWORK_TEMP	53.5
 #define KLN_COOLED_DOWN		45.5
 #define KLN_COOLED_DOWN		45.5
 
 
-// If 5 late updates in a row, try to reset the device
-#define KLN_LATE_UPDATE_LIMIT	5
-
 /*
 /*
  *  Work older than 5s will already be completed
  *  Work older than 5s will already be completed
  *  FYI it must not be possible to complete 256 work
  *  FYI it must not be possible to complete 256 work
@@ -74,12 +71,29 @@ static const char *msg_reply = "Reply";
  */
  */
 #define OLD_WORK_MS ((int)(5 * 1000))
 #define OLD_WORK_MS ((int)(5 * 1000))
 
 
+/*
+ * How many incorrect slave counts to ignore in a row
+ * 2 means it allows random grabage returned twice
+ * Until slaves are implemented, this should never occur
+ * so allowing 2 in a row should ignore random errros
+ */
+#define KLN_ISS_IGNORE 2
+
 /*
 /*
  * If the queue status hasn't been updated for this long then do it now
  * If the queue status hasn't been updated for this long then do it now
  * 5GH/s = 859ms per full nonce range
  * 5GH/s = 859ms per full nonce range
  */
  */
 #define LATE_UPDATE_MS ((int)(2.5 * 1000))
 #define LATE_UPDATE_MS ((int)(2.5 * 1000))
 
 
+// If 5 late updates in a row, try to reset the device
+#define LATE_UPDATE_LIMIT	5
+
+// If the reset fails sleep for 1s
+#define LATE_UPDATE_SLEEP_MS 1000
+
+// However give up after 8s
+#define LATE_UPDATE_NODEV_MS ((int)(8.0 * 1000))
+
 struct device_drv klondike_drv;
 struct device_drv klondike_drv;
 
 
 typedef struct klondike_header {
 typedef struct klondike_header {
@@ -194,12 +208,12 @@ typedef struct jobque {
 	int workqc;
 	int workqc;
 	struct timeval last_update;
 	struct timeval last_update;
 	bool overheat;
 	bool overheat;
+	bool flushed;
 	int late_update_count;
 	int late_update_count;
 	int late_update_sequential;
 	int late_update_sequential;
 } JOBQUE;
 } JOBQUE;
 
 
 struct klondike_info {
 struct klondike_info {
-	bool shutdown;
 	pthread_rwlock_t stat_lock;
 	pthread_rwlock_t stat_lock;
 	struct thr_info replies_thr;
 	struct thr_info replies_thr;
 	cglock_t klist_lock;
 	cglock_t klist_lock;
@@ -216,6 +230,7 @@ struct klondike_info {
 	uint64_t hashcount;
 	uint64_t hashcount;
 	uint64_t errorcount;
 	uint64_t errorcount;
 	uint64_t noisecount;
 	uint64_t noisecount;
+	int incorrect_slave_sequential;
 
 
 	// us Delay from USB reply to being processed
 	// us Delay from USB reply to being processed
 	double delay_count;
 	double delay_count;
@@ -301,7 +316,7 @@ static KLIST *allocate_kitem(struct cgpu_info *klncgpu)
 	cg_wunlock(&klninfo->klist_lock);
 	cg_wunlock(&klninfo->klist_lock);
 
 
 	if (ran_out > 0)
 	if (ran_out > 0)
-		applog(LOG_ERR, "%s", errbuf);
+		applog(LOG_WARNING, "%s", errbuf);
 
 
 	return kitem;
 	return kitem;
 }
 }
@@ -540,7 +555,7 @@ static KLIST *GetReply(struct cgpu_info *klncgpu, uint8_t cmd, uint8_t dev)
 	KLIST *kitem;
 	KLIST *kitem;
 	int retries = CMD_REPLY_RETRIES;
 	int retries = CMD_REPLY_RETRIES;
 
 
-	while (retries-- > 0 && klninfo->shutdown == false) {
+	while (retries-- > 0 && klncgpu->shutdown == false) {
 		cgsleep_ms(REPLY_WAIT_TIME);
 		cgsleep_ms(REPLY_WAIT_TIME);
 		cg_rlock(&klninfo->klist_lock);
 		cg_rlock(&klninfo->klist_lock);
 		kitem = klninfo->used;
 		kitem = klninfo->used;
@@ -696,16 +711,13 @@ static bool klondike_init(struct cgpu_info *klncgpu)
 	// boundaries are checked by device, with valid values returned
 	// boundaries are checked by device, with valid values returned
 	if (opt_klondike_options != NULL) {
 	if (opt_klondike_options != NULL) {
 		int hashclock;
 		int hashclock;
-		double temp1, temp2;
+		double temptarget;
 
 
-		sscanf(opt_klondike_options, "%d:%lf:%lf:%"SCNu8,
-						&hashclock,
-						&temp1, &temp2,
-						&kline.cfg.fantarget);
+		sscanf(opt_klondike_options, "%d:%lf", &hashclock, &temptarget);
 		SET_HASHCLOCK(kline.cfg.hashclock, hashclock);
 		SET_HASHCLOCK(kline.cfg.hashclock, hashclock);
-		kline.cfg.temptarget = cvtCToKln(temp1);
-		kline.cfg.tempcritical = cvtCToKln(temp2);
-		kline.cfg.fantarget = (int)255*kline.cfg.fantarget/100;
+		kline.cfg.temptarget = cvtCToKln(temptarget);
+		kline.cfg.tempcritical = 0; // hard code for old firmware
+		kline.cfg.fantarget = 0xff; // hard code for old firmware
 		size = sizeof(kline.cfg) - 2;
 		size = sizeof(kline.cfg) - 2;
 	}
 	}
 
 
@@ -932,13 +944,13 @@ static void *klondike_get_replies(void *userdata)
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
 	KLIST *kitem = NULL;
 	KLIST *kitem = NULL;
 	char *hexdata;
 	char *hexdata;
-	int err, recd, slaves, dev;
-	bool overheat;
+	int err, recd, slaves, dev, isc;
+	bool overheat, sent;
 
 
 	applog(LOG_DEBUG, "%s%i: listening for replies",
 	applog(LOG_DEBUG, "%s%i: listening for replies",
 			  klncgpu->drv->name, klncgpu->device_id);
 			  klncgpu->drv->name, klncgpu->device_id);
 
 
-	while (klninfo->shutdown == false) {
+	while (klncgpu->shutdown == false) {
 		if (klncgpu->usbinfo.nodev)
 		if (klncgpu->usbinfo.nodev)
 			return NULL;
 			return NULL;
 
 
@@ -956,7 +968,9 @@ static void *klondike_get_replies(void *userdata)
 		}
 		}
 		if (!err && recd == REPLY_SIZE) {
 		if (!err && recd == REPLY_SIZE) {
 			cgtime(&(kitem->tv_when));
 			cgtime(&(kitem->tv_when));
+			rd_lock(&(klninfo->stat_lock));
 			kitem->block_seq = klninfo->block_seq;
 			kitem->block_seq = klninfo->block_seq;
+			rd_unlock(&(klninfo->stat_lock));
 			if (opt_log_level <= READ_DEBUG) {
 			if (opt_log_level <= READ_DEBUG) {
 				hexdata = bin2hex((unsigned char *)&(kitem->kline.hd.dev), recd-1);
 				hexdata = bin2hex((unsigned char *)&(kitem->kline.hd.dev), recd-1);
 				applog(READ_DEBUG, "%s%i:%d reply [%c:%s]",
 				applog(READ_DEBUG, "%s%i:%d reply [%c:%s]",
@@ -993,27 +1007,59 @@ static void *klondike_get_replies(void *userdata)
 					klondike_check_nonce(klncgpu, kitem);
 					klondike_check_nonce(klncgpu, kitem);
 					display_kline(klncgpu, &kitem->kline, msg_reply);
 					display_kline(klncgpu, &kitem->kline, msg_reply);
 					break;
 					break;
-				case KLN_CMD_STATUS:
 				case KLN_CMD_WORK:
 				case KLN_CMD_WORK:
+					// We can't do/check this until it's initialised
+					if (klninfo->initialised) {
+						dev = kitem->kline.ws.dev;
+						if (kitem->kline.ws.workqc == 0) {
+							bool idle = false;
+							rd_lock(&(klninfo->stat_lock));
+							if (klninfo->jobque[dev].flushed == false)
+								idle = true;
+							slaves = klninfo->status[0].kline.ws.slavecount;
+							rd_lock(&(klninfo->stat_lock));
+							if (idle)
+								applog(LOG_WARNING, "%s%i:%d went idle before work was sent",
+										    klncgpu->drv->name,
+										    klncgpu->device_id,
+										    dev);
+						}
+						wr_lock(&(klninfo->stat_lock));
+						klninfo->jobque[dev].flushed = false;
+						wr_lock(&(klninfo->stat_lock));
+					}
+				case KLN_CMD_STATUS:
 				case KLN_CMD_ABORT:
 				case KLN_CMD_ABORT:
 					// We can't do/check this until it's initialised
 					// We can't do/check this until it's initialised
 					if (klninfo->initialised) {
 					if (klninfo->initialised) {
+						isc = 0;
 						dev = kitem->kline.ws.dev;
 						dev = kitem->kline.ws.dev;
 						wr_lock(&(klninfo->stat_lock));
 						wr_lock(&(klninfo->stat_lock));
 						klninfo->jobque[dev].workqc = (int)(kitem->kline.ws.workqc);
 						klninfo->jobque[dev].workqc = (int)(kitem->kline.ws.workqc);
 						cgtime(&(klninfo->jobque[dev].last_update));
 						cgtime(&(klninfo->jobque[dev].last_update));
 						slaves = klninfo->status[0].kline.ws.slavecount;
 						slaves = klninfo->status[0].kline.ws.slavecount;
 						overheat = klninfo->jobque[dev].overheat;
 						overheat = klninfo->jobque[dev].overheat;
+						if (dev == 0) {
+							if (kitem->kline.ws.slavecount != slaves)
+								isc = ++klninfo->incorrect_slave_sequential;
+							else
+								isc = klninfo->incorrect_slave_sequential = 0;
+						}
 						wr_unlock(&(klninfo->stat_lock));
 						wr_unlock(&(klninfo->stat_lock));
 
 
-						if (kitem->kline.ws.slavecount != slaves) {
-							applog(LOG_ERR, "%s%i:%d reply [%c] has a diff # of slaves=%d"
-									" (curr=%d) dropping device to hotplug",
-									klncgpu->drv->name, klncgpu->device_id,
-									dev, (char)(kitem->kline.ws.cmd),
+						if (isc) {
+							applog(LOG_ERR, "%s%i:%d reply [%c] has a diff"
+									" # of slaves=%d (curr=%d)%s",
+									klncgpu->drv->name,
+									klncgpu->device_id,
+									dev,
+									(char)(kitem->kline.ws.cmd),
 									(int)(kitem->kline.ws.slavecount),
 									(int)(kitem->kline.ws.slavecount),
-									slaves);
-							klninfo->shutdown = true;
+									slaves,
+									isc <= KLN_ISS_IGNORE ? "" :
+									 " disabling device");
+							if (isc > KLN_ISS_IGNORE)
+								usb_nodev(klncgpu);
 							break;
 							break;
 						}
 						}
 
 
@@ -1026,22 +1072,24 @@ static void *klondike_get_replies(void *userdata)
 								klninfo->jobque[dev].overheat = true;
 								klninfo->jobque[dev].overheat = true;
 								wr_unlock(&(klninfo->stat_lock));
 								wr_unlock(&(klninfo->stat_lock));
 
 
-								applog(LOG_ERR, "%s%i:%d Critical overheat (%.0fC)",
-										klncgpu->drv->name, klncgpu->device_id,
-										dev, temp);
+								applog(LOG_WARNING, "%s%i:%d Critical overheat (%.0fC)",
+										    klncgpu->drv->name,
+										    klncgpu->device_id,
+										    dev, temp);
 
 
 								zero_kline(&kline);
 								zero_kline(&kline);
 								kline.hd.cmd = KLN_CMD_ABORT;
 								kline.hd.cmd = KLN_CMD_ABORT;
 								kline.hd.dev = dev;
 								kline.hd.dev = dev;
-								if (!SendCmd(klncgpu, &kline, KSENDHD(0))) {
-									applog(LOG_ERR, "%s%i:%d failed to abort work"
-											" - dropping device to hotplug",
+								sent = SendCmd(klncgpu, &kline, KSENDHD(0));
+								kln_disable(klncgpu, dev, false);
+								if (!sent) {
+									applog(LOG_ERR, "%s%i:%d overheat failed to"
+											" abort work - disabling device",
 											klncgpu->drv->name,
 											klncgpu->drv->name,
 											klncgpu->device_id,
 											klncgpu->device_id,
 											dev);
 											dev);
-									klninfo->shutdown = true;
+									usb_nodev(klncgpu);
 								}
 								}
-								kln_disable(klncgpu, dev, false);
 							}
 							}
 						}
 						}
 					}
 					}
@@ -1080,13 +1128,13 @@ static void klondike_flush_work(struct cgpu_info *klncgpu)
 	KLINE kline;
 	KLINE kline;
 	int slaves, dev;
 	int slaves, dev;
 
 
+	wr_lock(&(klninfo->stat_lock));
 	klninfo->block_seq++;
 	klninfo->block_seq++;
+	slaves = klninfo->status[0].kline.ws.slavecount;
+	wr_unlock(&(klninfo->stat_lock));
 
 
 	applog(LOG_DEBUG, "%s%i: flushing work",
 	applog(LOG_DEBUG, "%s%i: flushing work",
 			  klncgpu->drv->name, klncgpu->device_id);
 			  klncgpu->drv->name, klncgpu->device_id);
-	rd_lock(&(klninfo->stat_lock));
-	slaves = klninfo->status[0].kline.ws.slavecount;
-	rd_unlock(&(klninfo->stat_lock));
 	zero_kline(&kline);
 	zero_kline(&kline);
 	kline.hd.cmd = KLN_CMD_ABORT;
 	kline.hd.cmd = KLN_CMD_ABORT;
 	for (dev = 0; dev <= slaves; dev++) {
 	for (dev = 0; dev <= slaves; dev++) {
@@ -1097,6 +1145,7 @@ static void klondike_flush_work(struct cgpu_info *klncgpu)
 			memcpy((void *)&(klninfo->status[dev]),
 			memcpy((void *)&(klninfo->status[dev]),
 				kitem,
 				kitem,
 				sizeof(klninfo->status[dev]));
 				sizeof(klninfo->status[dev]));
+			klninfo->jobque[dev].flushed = true;
 			wr_unlock(&(klninfo->stat_lock));
 			wr_unlock(&(klninfo->stat_lock));
 			kitem = release_kitem(klncgpu, kitem);
 			kitem = release_kitem(klncgpu, kitem);
 		}
 		}
@@ -1142,7 +1191,7 @@ static void klondike_shutdown(struct thr_info *thr)
 
 
 	kln_disable(klncgpu, klninfo->status[0].kline.ws.slavecount, true);
 	kln_disable(klncgpu, klninfo->status[0].kline.ws.slavecount, true);
 
 
-	klncgpu->shutdown = klninfo->shutdown = true;
+	klncgpu->shutdown = true;
 }
 }
 
 
 static void klondike_thread_enable(struct thr_info *thr)
 static void klondike_thread_enable(struct thr_info *thr)
@@ -1228,10 +1277,13 @@ static bool klondike_queue_full(struct cgpu_info *klncgpu)
 {
 {
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
 	struct work *work = NULL;
 	struct work *work = NULL;
-	int dev, queued, slaves, seq;
+	int dev, queued, slaves, seq, howlong;
 	struct timeval now;
 	struct timeval now;
 	bool nowork;
 	bool nowork;
 
 
+	if (klncgpu->shutdown == true)
+		return true;
+
 	cgtime(&now);
 	cgtime(&now);
 	rd_lock(&(klninfo->stat_lock));
 	rd_lock(&(klninfo->stat_lock));
 	slaves = klninfo->status[0].kline.ws.slavecount;
 	slaves = klninfo->status[0].kline.ws.slavecount;
@@ -1240,25 +1292,30 @@ static bool klondike_queue_full(struct cgpu_info *klncgpu)
 			klninfo->jobque[dev].late_update_count++;
 			klninfo->jobque[dev].late_update_count++;
 			seq = ++klninfo->jobque[dev].late_update_sequential;
 			seq = ++klninfo->jobque[dev].late_update_sequential;
 			rd_unlock(&(klninfo->stat_lock));
 			rd_unlock(&(klninfo->stat_lock));
-			if (seq < KLN_LATE_UPDATE_LIMIT) {
-				applog(LOG_ERR, "%s%i:%d late update",
+			if (seq < LATE_UPDATE_LIMIT) {
+				applog(LOG_DEBUG, "%s%i:%d late update",
 						klncgpu->drv->name, klncgpu->device_id, dev);
 						klncgpu->drv->name, klncgpu->device_id, dev);
 				klondike_get_stats(klncgpu);
 				klondike_get_stats(klncgpu);
 				goto que;
 				goto que;
 			} else {
 			} else {
-				applog(LOG_ERR, "%s%i:%d late update (%d) reached - attempting reset",
-						klncgpu->drv->name, klncgpu->device_id,
-						dev, KLN_LATE_UPDATE_LIMIT);
+				applog(LOG_WARNING, "%s%i:%d late update (%d) reached - attempting reset",
+						    klncgpu->drv->name, klncgpu->device_id,
+						    dev, LATE_UPDATE_LIMIT);
 				control_init(klncgpu);
 				control_init(klncgpu);
 				kln_enable(klncgpu);
 				kln_enable(klncgpu);
 				klondike_get_stats(klncgpu);
 				klondike_get_stats(klncgpu);
 				rd_lock(&(klninfo->stat_lock));
 				rd_lock(&(klninfo->stat_lock));
-				if (ms_tdiff(&now, &(klninfo->jobque[dev].last_update)) > LATE_UPDATE_MS) {
+				howlong = ms_tdiff(&now, &(klninfo->jobque[dev].last_update));
+				if (howlong > LATE_UPDATE_MS) {
 					rd_unlock(&(klninfo->stat_lock));
 					rd_unlock(&(klninfo->stat_lock));
-					applog(LOG_ERR, "%s%i:%d reset failed - dropping device",
-							klncgpu->drv->name, klncgpu->device_id, dev);
-					klninfo->shutdown = true;
-					return false;
+					if (howlong > LATE_UPDATE_NODEV_MS) {
+						applog(LOG_ERR, "%s%i:%d reset failed - dropping device",
+								klncgpu->drv->name, klncgpu->device_id, dev);
+						usb_nodev(klncgpu);
+					} else
+						cgsleep_ms(LATE_UPDATE_SLEEP_MS);
+
+					return true;
 				}
 				}
 				break;
 				break;
 			}
 			}
@@ -1283,9 +1340,9 @@ tryagain:
 				if (temp <= KLN_COOLED_DOWN) {
 				if (temp <= KLN_COOLED_DOWN) {
 					klninfo->jobque[dev].overheat = false;
 					klninfo->jobque[dev].overheat = false;
 					rd_unlock(&(klninfo->stat_lock));
 					rd_unlock(&(klninfo->stat_lock));
-					applog(LOG_ERR, "%s%i:%d Overheat recovered (%.0fC)",
-							klncgpu->drv->name, klncgpu->device_id,
-							dev, temp);
+					applog(LOG_WARNING, "%s%i:%d Overheat recovered (%.0fC)",
+							    klncgpu->drv->name, klncgpu->device_id,
+							    dev, temp);
 					kln_enable(klncgpu);
 					kln_enable(klncgpu);
 					goto tryagain;
 					goto tryagain;
 				} else {
 				} else {
@@ -1345,6 +1402,7 @@ static int64_t klondike_scanwork(struct thr_info *thr)
 		klninfo->noncecount = 0;
 		klninfo->noncecount = 0;
 		rd_unlock(&(klninfo->stat_lock));
 		rd_unlock(&(klninfo->stat_lock));
 	}
 	}
+
 	return newhashcount;
 	return newhashcount;
 }
 }
 
 

+ 24 - 10
usbutils.c

@@ -1390,6 +1390,20 @@ static void release_cgpu(struct cgpu_info *cgpu)
 	cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address);
 	cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address);
 }
 }
 
 
+/*
+ * Force a NODEV on a device so it goes back to hotplug
+ */
+void usb_nodev(struct cgpu_info *cgpu)
+{
+	int pstate;
+
+	DEVWLOCK(cgpu, pstate);
+
+	release_cgpu(cgpu);
+
+	DEVWUNLOCK(cgpu, pstate);
+}
+
 /*
 /*
  * Use the same usbdev thus locking is across all related devices
  * Use the same usbdev thus locking is across all related devices
  */
  */
@@ -2530,14 +2544,14 @@ int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t
 				cgtimer_t now, already_done;
 				cgtimer_t now, already_done;
 				double sleep_estimate;
 				double sleep_estimate;
 				double write_time = (double)(usbdev->last_write_siz) /
 				double write_time = (double)(usbdev->last_write_siz) /
-						    (double)(usbdev->cps);
+						    (double)(usbdev->cps) * 1000;
 
 
 				cgtimer_time(&now);
 				cgtimer_time(&now);
 				cgtimer_sub(&now, &usbdev->cgt_last_write, &already_done);
 				cgtimer_sub(&now, &usbdev->cgt_last_write, &already_done);
 				sleep_estimate = write_time - cgtimer_to_ms(&already_done);
 				sleep_estimate = write_time - cgtimer_to_ms(&already_done);
 
 
 				if (sleep_estimate > 0.0) {
 				if (sleep_estimate > 0.0) {
-					cgsleep_ms_r(&usbdev->cgt_last_write, write_time * 1000.0);
+					cgsleep_ms_r(&usbdev->cgt_last_write, write_time);
 					cgpu->usbinfo.read_delay_count++;
 					cgpu->usbinfo.read_delay_count++;
 					cgpu->usbinfo.total_read_delay += sleep_estimate;
 					cgpu->usbinfo.total_read_delay += sleep_estimate;
 				}
 				}
@@ -2631,14 +2645,14 @@ int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t
 			cgtimer_t now, already_done;
 			cgtimer_t now, already_done;
 			double sleep_estimate;
 			double sleep_estimate;
 			double write_time = (double)(usbdev->last_write_siz) /
 			double write_time = (double)(usbdev->last_write_siz) /
-					    (double)(usbdev->cps);
+					    (double)(usbdev->cps) * 1000;
 
 
 			cgtimer_time(&now);
 			cgtimer_time(&now);
 			cgtimer_sub(&now, &usbdev->cgt_last_write, &already_done);
 			cgtimer_sub(&now, &usbdev->cgt_last_write, &already_done);
 			sleep_estimate = write_time - cgtimer_to_ms(&already_done);
 			sleep_estimate = write_time - cgtimer_to_ms(&already_done);
 
 
 			if (sleep_estimate > 0.0) {
 			if (sleep_estimate > 0.0) {
-				cgsleep_ms_r(&usbdev->cgt_last_write, write_time * 1000.0);
+				cgsleep_ms_r(&usbdev->cgt_last_write, write_time);
 				cgpu->usbinfo.read_delay_count++;
 				cgpu->usbinfo.read_delay_count++;
 				cgpu->usbinfo.total_read_delay += sleep_estimate;
 				cgpu->usbinfo.total_read_delay += sleep_estimate;
 			}
 			}
@@ -2778,14 +2792,14 @@ int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_
 				cgtimer_t now, already_done;
 				cgtimer_t now, already_done;
 				double sleep_estimate;
 				double sleep_estimate;
 				double write_time = (double)(usbdev->last_write_siz) /
 				double write_time = (double)(usbdev->last_write_siz) /
-						    (double)(usbdev->cps);
+						    (double)(usbdev->cps) * 1000;
 
 
 				cgtimer_time(&now);
 				cgtimer_time(&now);
 				cgtimer_sub(&now, &usbdev->cgt_last_write, &already_done);
 				cgtimer_sub(&now, &usbdev->cgt_last_write, &already_done);
 				sleep_estimate = write_time - cgtimer_to_ms(&already_done);
 				sleep_estimate = write_time - cgtimer_to_ms(&already_done);
 
 
 				if (sleep_estimate > 0.0) {
 				if (sleep_estimate > 0.0) {
-					cgsleep_ms_r(&usbdev->cgt_last_write, write_time * 1000.0);
+					cgsleep_ms_r(&usbdev->cgt_last_write, write_time);
 					cgpu->usbinfo.write_delay_count++;
 					cgpu->usbinfo.write_delay_count++;
 					cgpu->usbinfo.total_write_delay += sleep_estimate;
 					cgpu->usbinfo.total_write_delay += sleep_estimate;
 				}
 				}
@@ -2917,14 +2931,14 @@ int __usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bReques
 			cgtimer_t now, already_done;
 			cgtimer_t now, already_done;
 			double sleep_estimate;
 			double sleep_estimate;
 			double write_time = (double)(usbdev->last_write_siz) /
 			double write_time = (double)(usbdev->last_write_siz) /
-					    (double)(usbdev->cps);
+					    (double)(usbdev->cps) * 1000;
 
 
 			cgtimer_time(&now);
 			cgtimer_time(&now);
 			cgtimer_sub(&now, &usbdev->cgt_last_write, &already_done);
 			cgtimer_sub(&now, &usbdev->cgt_last_write, &already_done);
 			sleep_estimate = write_time - cgtimer_to_ms(&already_done);
 			sleep_estimate = write_time - cgtimer_to_ms(&already_done);
 
 
 			if (sleep_estimate > 0.0) {
 			if (sleep_estimate > 0.0) {
-				cgsleep_ms_r(&usbdev->cgt_last_write, write_time * 1000.0);
+				cgsleep_ms_r(&usbdev->cgt_last_write, write_time);
 				cgpu->usbinfo.write_delay_count++;
 				cgpu->usbinfo.write_delay_count++;
 				cgpu->usbinfo.total_write_delay += sleep_estimate;
 				cgpu->usbinfo.total_write_delay += sleep_estimate;
 			}
 			}
@@ -2999,14 +3013,14 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe
 		cgtimer_t now, already_done;
 		cgtimer_t now, already_done;
 		double sleep_estimate;
 		double sleep_estimate;
 		double write_time = (double)(usbdev->last_write_siz) /
 		double write_time = (double)(usbdev->last_write_siz) /
-				    (double)(usbdev->cps);
+				    (double)(usbdev->cps) * 1000;
 
 
 		cgtimer_time(&now);
 		cgtimer_time(&now);
 		cgtimer_sub(&now, &usbdev->cgt_last_write, &already_done);
 		cgtimer_sub(&now, &usbdev->cgt_last_write, &already_done);
 		sleep_estimate = write_time - cgtimer_to_ms(&already_done);
 		sleep_estimate = write_time - cgtimer_to_ms(&already_done);
 
 
 		if (sleep_estimate > 0.0) {
 		if (sleep_estimate > 0.0) {
-			cgsleep_ms_r(&usbdev->cgt_last_write, write_time * 1000.0);
+			cgsleep_ms_r(&usbdev->cgt_last_write, write_time);
 			cgpu->usbinfo.read_delay_count++;
 			cgpu->usbinfo.read_delay_count++;
 			cgpu->usbinfo.total_read_delay += sleep_estimate;
 			cgpu->usbinfo.total_read_delay += sleep_estimate;
 		}
 		}

+ 2 - 1
usbutils.h

@@ -378,7 +378,8 @@ bool async_usb_transfers(void);
 void cancel_usb_transfers(void);
 void cancel_usb_transfers(void);
 void usb_all(int level);
 void usb_all(int level);
 const char *usb_cmdname(enum usb_cmds cmd);
 const char *usb_cmdname(enum usb_cmds cmd);
-void usb_applog(struct cgpu_info *bflsc, enum usb_cmds cmd, char *msg, int amount, int err);
+void usb_applog(struct cgpu_info *cgpu, enum usb_cmds cmd, char *msg, int amount, int err);
+void usb_nodev(struct cgpu_info *cgpu);
 struct cgpu_info *usb_copy_cgpu(struct cgpu_info *orig);
 struct cgpu_info *usb_copy_cgpu(struct cgpu_info *orig);
 struct cgpu_info *usb_alloc_cgpu(struct device_drv *drv, int threads);
 struct cgpu_info *usb_alloc_cgpu(struct device_drv *drv, int threads);
 struct cgpu_info *usb_free_cgpu(struct cgpu_info *cgpu);
 struct cgpu_info *usb_free_cgpu(struct cgpu_info *cgpu);

+ 39 - 17
util.c

@@ -588,10 +588,13 @@ char *get_proxy(char *url, struct pool *pool)
 void __bin2hex(char *s, const unsigned char *p, size_t len)
 void __bin2hex(char *s, const unsigned char *p, size_t len)
 {
 {
 	int i;
 	int i;
+	static const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
 
 
-	for (i = 0; i < (int)len; i++)
-		sprintf(s + (i * 2), "%02x", (unsigned int)p[i]);
-
+	for (i = 0; i < (int)len; i++) {
+		*s++ = hex[p[i] >> 4];
+		*s++ = hex[p[i] & 0xF];
+	}
+	*s++ = '\0';
 }
 }
 
 
 /* Returns a malloced array string of a binary value of arbitrary length. The
 /* Returns a malloced array string of a binary value of arbitrary length. The
@@ -615,33 +618,48 @@ char *bin2hex(const unsigned char *p, size_t len)
 }
 }
 
 
 /* Does the reverse of bin2hex but does not allocate any ram */
 /* Does the reverse of bin2hex but does not allocate any ram */
+static const int hex2bin_tbl[256] = {
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
 bool hex2bin(unsigned char *p, const char *hexstr, size_t len)
 bool hex2bin(unsigned char *p, const char *hexstr, size_t len)
 {
 {
+	int nibble1, nibble2;
+	unsigned char idx;
 	bool ret = false;
 	bool ret = false;
 
 
 	while (*hexstr && len) {
 	while (*hexstr && len) {
-		char hex_byte[4];
-		unsigned int v;
-
 		if (unlikely(!hexstr[1])) {
 		if (unlikely(!hexstr[1])) {
 			applog(LOG_ERR, "hex2bin str truncated");
 			applog(LOG_ERR, "hex2bin str truncated");
 			return ret;
 			return ret;
 		}
 		}
 
 
-		memset(hex_byte, 0, 4);
-		hex_byte[0] = hexstr[0];
-		hex_byte[1] = hexstr[1];
+		idx = *hexstr++;
+		nibble1 = hex2bin_tbl[idx];
+		idx = *hexstr++;
+		nibble2 = hex2bin_tbl[idx];
 
 
-		if (unlikely(sscanf(hex_byte, "%x", &v) != 1)) {
-			applog(LOG_INFO, "hex2bin sscanf '%s' failed", hex_byte);
+		if (unlikely((nibble1 < 0) || (nibble2 < 0))) {
+			applog(LOG_ERR, "hex2bin scan failed");
 			return ret;
 			return ret;
 		}
 		}
 
 
-		*p = (unsigned char) v;
-
-		p++;
-		hexstr += 2;
-		len--;
+		*p++ = (((unsigned char)nibble1) << 4) | ((unsigned char)nibble2);
+		--len;
 	}
 	}
 
 
 	if (likely(len == 0 && *hexstr == 0))
 	if (likely(len == 0 && *hexstr == 0))
@@ -1061,9 +1079,13 @@ void cgtimer_time(cgtimer_t *ts_start)
 
 
 static void liSleep(LARGE_INTEGER *li, int timeout)
 static void liSleep(LARGE_INTEGER *li, int timeout)
 {
 {
-	HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
+	HANDLE hTimer;
 	DWORD ret;
 	DWORD ret;
 
 
+	if (unlikely(timeout <= 0))
+		return;
+
+	hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
 	if (unlikely(!hTimer))
 	if (unlikely(!hTimer))
 		quit(1, "Failed to create hTimer in liSleep");
 		quit(1, "Failed to create hTimer in liSleep");
 	ret = SetWaitableTimer(hTimer, li, 0, NULL, NULL, 0);
 	ret = SetWaitableTimer(hTimer, li, 0, NULL, NULL, 0);