Commit 88d78de83daad8cb4c8d3e9fa85198ceb234ca73

Kano 2013-12-22T18:47:57

Merge remote-tracking branch 'conman/master'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
diff --git a/ASIC-README b/ASIC-README
index a535c2b..67b16ff 100644
--- a/ASIC-README
+++ b/ASIC-README
@@ -49,8 +49,7 @@ Bitfury devices need the --enable-bitfury option when compiling cgminer.
 
 Currently the BPMC/BGMC BF1 devices AKA redfury/bluefury are supported and
 come up as BF1, along with the Bi*fury USB devices which come up as BXF.
-There are no options available for them. Bitfury USB devices are also set up
-as per the USB ASICs below.
+Bitfury USB devices are also set up as per the USB ASICs below.
 
 
 ---
@@ -132,6 +131,7 @@ ASIC SPECIFIC COMMANDS
 --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-voltage <arg> Set BitBurner (Avalon) core voltage, in millivolts
+--bxf-temp-target <arg> Set target temperature for BXF devices (default: 82)
 --klondike-options <arg> Set klondike options clock:temptarget
 
 
@@ -313,6 +313,15 @@ This will allow you to change or disable the default temperature where cgminer
 throttles BFLSC devices by allowing them to temporarily go idle.
 
 
+BITFURY Devices
+
+--bxf-temp-target <arg> Set target temperature for BXF devices (default: 82)
+
+Cgminer uses dynamic clocking on Bi*fury devices to try and maintain the
+temperature just below an optimal target. This option allows you to change the
+target temperature. When actively cooled below this, the devices will run at
+maximum speed.
+
 ---
 
 This code is provided entirely free of charge by the programmer in his spare
diff --git a/cgminer.c b/cgminer.c
index 089f585..6c4ea1a 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -72,6 +72,10 @@ char *curly = ":D";
 #include "driver-bflsc.h"
 #endif
 
+#ifdef USE_BITFURY
+#include "driver-bitfury.h"
+#endif
+
 #ifdef USE_HASHFAST
 #include "driver-hashfast.h"
 int opt_hfa_ntime_roll;
@@ -641,7 +645,7 @@ static char *set_int_0_to_100(const char *arg, int *i)
 }
 #endif
 
-#ifdef USE_BFLSC
+#if defined(USE_BFLSC) || defined(USE_BITFURY)
 static char *set_int_0_to_200(const char *arg, int *i)
 {
 	return set_int_range(arg, i, 0, 200);
@@ -1112,6 +1116,11 @@ static struct opt_table opt_config_table[] = {
 		     set_int_0_to_200, opt_show_intval, &opt_bflsc_overheat,
 		     "Set overheat temperature where BFLSC devices throttle, 0 to disable"),
 #endif
+#ifdef USE_BITFURY
+	OPT_WITH_ARG("--bxf-temp-target",
+		     set_int_0_to_200, opt_show_intval, &opt_bxf_temp_target,
+		     "Set target temperature for BXF devices"),
+#endif
 #ifdef HAVE_CURSES
 	OPT_WITHOUT_ARG("--compact",
 			opt_set_bool, &opt_compact,
@@ -1746,13 +1755,15 @@ static void gen_gbt_work(struct pool *pool, struct work *work)
 {
 	unsigned char *merkleroot;
 	struct timeval now;
+	uint64_t nonce2le;
 
 	cgtime(&now);
 	if (now.tv_sec - pool->tv_lastwork.tv_sec > 60)
 		update_gbt(pool);
 
 	cg_wlock(&pool->gbt_lock);
-	memcpy(pool->coinbase + pool->nonce2_offset, &pool->nonce2, 4);
+	nonce2le = htole64(pool->nonce2);
+	memcpy(pool->coinbase + pool->nonce2_offset, &nonce2le, pool->n2size);
 	pool->nonce2++;
 	cg_dwlock(&pool->gbt_lock);
 	merkleroot = __gbt_merkleroot(pool);
@@ -1851,8 +1862,9 @@ static bool gbt_decode(struct pool *pool, json_t *res_val)
 	free(pool->coinbasetxn);
 	pool->coinbasetxn = strdup(coinbasetxn);
 	cbt_len = strlen(pool->coinbasetxn) / 2;
-	pool->coinbase_len = cbt_len + 4;
-	/* We add 4 bytes of extra data corresponding to nonce2 of stratum */
+	/* We add 8 bytes of extra data corresponding to nonce2 */
+	pool->n2size = 8;
+	pool->coinbase_len = cbt_len + pool->n2size;
 	cal_len = pool->coinbase_len + 1;
 	align_len(&cal_len);
 	free(pool->coinbase);
@@ -1863,7 +1875,7 @@ static bool gbt_decode(struct pool *pool, json_t *res_val)
 	extra_len = (uint8_t *)(pool->coinbase + 41);
 	orig_len = *extra_len;
 	hex2bin(pool->coinbase + 42, pool->coinbasetxn + 84, orig_len);
-	*extra_len += 4;
+	*extra_len += pool->n2size;
 	hex2bin(pool->coinbase + 42 + *extra_len, pool->coinbasetxn + 84 + (orig_len * 2),
 		cbt_len - orig_len - 42);
 	pool->nonce2_offset = orig_len + 42;
@@ -5363,10 +5375,11 @@ static void *stratum_sthread(void *userdata)
 		quit(1, "Failed to create stratum_q in stratum_sthread");
 
 	while (42) {
-		char noncehex[12], nonce2hex[20];
+		char noncehex[12], nonce2hex[20], s[1024];
 		struct stratum_share *sshare;
 		uint32_t *hash32, nonce;
-		char s[1024], nonce2[8];
+		unsigned char nonce2[8];
+		uint64_t *nonce2_64;
 		struct work *work;
 		bool submitted;
 
@@ -5401,10 +5414,9 @@ static void *stratum_sthread(void *userdata)
 		sshare->id = swork_id++;
 		mutex_unlock(&sshare_lock);
 
-		memset(nonce2, 0, 8);
-		/* We only use uint32_t sized nonce2 increments internally */
-		memcpy(nonce2, &work->nonce2, sizeof(uint32_t));
-		__bin2hex(nonce2hex, (const unsigned char *)nonce2, work->nonce2_len);
+		nonce2_64 = (uint64_t *)nonce2;
+		*nonce2_64 = htole64(work->nonce2);
+		__bin2hex(nonce2hex, nonce2, work->nonce2_len);
 
 		snprintf(s, sizeof(s),
 			"{\"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\": %d, \"method\": \"mining.submit\"}",
@@ -5808,12 +5820,15 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 {
 	unsigned char merkle_root[32], merkle_sha[64];
 	uint32_t *data32, *swap32;
+	uint64_t nonce2le;
 	int i;
 
 	cg_wlock(&pool->data_lock);
 
-	/* Update coinbase */
-	memcpy(pool->coinbase + pool->nonce2_offset, &pool->nonce2, sizeof(uint32_t));
+	/* Update coinbase. Always use an LE encoded nonce2 to fill in values
+	 * from left to right and prevent overflow errors with small n2sizes */
+	nonce2le = htole64(pool->nonce2);
+	memcpy(pool->coinbase + pool->nonce2_offset, &nonce2le, pool->n2size);
 	work->nonce2 = pool->nonce2++;
 	work->nonce2_len = pool->n2size;
 
@@ -5853,7 +5868,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 		merkle_hash = bin2hex((const unsigned char *)merkle_root, 32);
 		applog(LOG_DEBUG, "Generated stratum merkle %s", merkle_hash);
 		applog(LOG_DEBUG, "Generated stratum header %s", header);
-		applog(LOG_DEBUG, "Work job_id %s nonce2 %d ntime %s", work->job_id, work->nonce2, work->ntime);
+		applog(LOG_DEBUG, "Work job_id %s nonce2 %"PRIu64" ntime %s", work->job_id,
+		       work->nonce2, work->ntime);
 		free(header);
 		free(merkle_hash);
 	}
diff --git a/driver-bitfury.c b/driver-bitfury.c
index 8de63ce..8d18694 100644
--- a/driver-bitfury.c
+++ b/driver-bitfury.c
@@ -13,6 +13,8 @@
 #include "driver-bitfury.h"
 #include "sha2.h"
 
+int opt_bxf_temp_target = BXF_TEMP_TARGET / 10;
+
 /* Wait longer 1/3 longer than it would take for a full nonce range */
 #define BF1WAIT 1600
 #define BF1MSGSIZE 7
@@ -231,6 +233,7 @@ static bool bxf_detect_one(struct cgpu_info *bitfury, struct bitfury_info *info)
 	       bitfury->drv->name, bitfury->device_id, bitfury->device_path);
 
 	info->total_nonces = 1;
+	info->temp_target = opt_bxf_temp_target * 10;
 	/* This unsets it to make sure it gets set on the first pass */
 	info->maxroll = -1;
 
@@ -369,18 +372,80 @@ static void parse_bxf_submit(struct cgpu_info *bitfury, struct bitfury_info *inf
 	free_work(work);
 }
 
+static bool bxf_send_clock(struct cgpu_info *bitfury, struct bitfury_info *info,
+			   uint8_t clockspeed)
+{
+	char buf[64];
+
+	info->clocks = clockspeed;
+	sprintf(buf, "clock %d %d\n", clockspeed, clockspeed);
+	return bxf_send_msg(bitfury, buf, C_BXF_CLOCK);
+}
+
 static void parse_bxf_temp(struct cgpu_info *bitfury, struct bitfury_info *info, char *buf)
 {
-	unsigned int temp;
+	int decitemp;
 
-	if (!sscanf(&buf[5], "%u", &temp)) {
+	if (!sscanf(&buf[5], "%d", &decitemp)) {
 		applog(LOG_INFO, "%s %d: Failed to parse temperature",
 		       bitfury->drv->name, bitfury->device_id);
 		return;
 	}
+
 	mutex_lock(&info->lock);
-	info->temperature = (double)temp / 10;
+	info->temperature = (double)decitemp / 10;
+	if (decitemp > info->max_decitemp) {
+		info->max_decitemp = decitemp;
+		applog(LOG_DEBUG, "%s %d: New max decitemp %d", bitfury->drv->name,
+		       bitfury->device_id, decitemp);
+	}
 	mutex_unlock(&info->lock);
+
+	if (decitemp > info->temp_target + BXF_TEMP_HYSTERESIS) {
+		if (info->clocks <= BXF_CLOCK_MIN)
+			goto out;
+		applog(LOG_WARNING, "%s %d: Hit overheat temperature of %d, throttling!",
+		       bitfury->drv->name, bitfury->device_id, decitemp);
+		bxf_send_clock(bitfury, info, BXF_CLOCK_MIN);
+		goto out;
+	}
+	if (decitemp > info->temp_target) {
+		if (info->clocks <= BXF_CLOCK_MIN)
+			goto out;
+		if (decitemp < info->last_decitemp)
+			goto out;
+		applog(LOG_INFO, "%s %d: Temp %d over target and not falling, decreasing clock",
+		       bitfury->drv->name, bitfury->device_id, decitemp);
+		bxf_send_clock(bitfury, info, info->clocks - 1);
+		goto out;
+	}
+	if (decitemp <= info->temp_target && decitemp >= info->temp_target - BXF_TEMP_HYSTERESIS) {
+		if (decitemp == info->last_decitemp)
+			goto out;
+		if (decitemp > info->last_decitemp) {
+			if (info->clocks <= BXF_CLOCK_MIN)
+				goto out;
+			applog(LOG_DEBUG, "%s %d: Temp %d in target and rising, decreasing clock",
+			       bitfury->drv->name, bitfury->device_id, decitemp);
+			bxf_send_clock(bitfury, info, info->clocks - 1);
+			goto out;
+		}
+		/* implies: decitemp < info->last_decitemp */
+		if (info->clocks >= BXF_CLOCK_DEFAULT)
+			goto out;
+		applog(LOG_DEBUG, "%s %d: Temp %d in target and falling, increasing clock",
+		       bitfury->drv->name, bitfury->device_id, decitemp);
+		bxf_send_clock(bitfury, info, info->clocks + 1);
+		goto out;
+	}
+	/* implies: decitemp < info->temp_target - BXF_TEMP_HYSTERESIS */
+	if (info->clocks >= BXF_CLOCK_DEFAULT)
+		goto out;
+	applog(LOG_DEBUG, "%s %d: Temp %d below target, increasing clock",
+		bitfury->drv->name, bitfury->device_id, decitemp);
+	bxf_send_clock(bitfury, info, info->clocks + 1);
+out:
+	info->last_decitemp = decitemp;
 }
 
 static void bxf_update_work(struct cgpu_info *bitfury, struct bitfury_info *info);
@@ -399,6 +464,47 @@ static void parse_bxf_needwork(struct cgpu_info *bitfury, struct bitfury_info *i
 		bxf_update_work(bitfury, info);
 }
 
+static void parse_bxf_job(struct cgpu_info *bitfury, struct bitfury_info *info, char *buf)
+{
+	int job_id, timestamp, chip;
+
+	if (sscanf(&buf[4], "%x %x %x", &job_id, &timestamp, &chip) != 3) {
+		applog(LOG_INFO, "%s %d: Failed to parse job",
+		       bitfury->drv->name, bitfury->device_id);
+		return;
+	}
+	if (chip > 1) {
+		applog(LOG_INFO, "%s %d: Invalid job chip number %d",
+		       bitfury->drv->name, bitfury->device_id, chip);
+		return;
+	}
+	++info->job[chip];
+}
+
+static void parse_bxf_hwerror(struct cgpu_info *bitfury, struct bitfury_info *info, char *buf)
+{
+	int chip;
+
+	if (!sscanf(&buf[8], "%d", &chip)) {
+		applog(LOG_INFO, "%s %d: Failed to parse hwerror",
+		       bitfury->drv->name, bitfury->device_id);
+		return;
+	}
+	if (chip > 1) {
+		applog(LOG_INFO, "%s %d: Invalid hwerror chip number %d",
+		       bitfury->drv->name, bitfury->device_id, chip);
+		return;
+	}
+	++info->filtered_hw[chip];
+}
+
+#define PARSE_BXF_MSG(MSG) \
+	msg = strstr(buf, #MSG); \
+	if (msg) { \
+		parse_bxf_##MSG(bitfury, info, msg); \
+		continue; \
+	}
+
 static void *bxf_get_results(void *userdata)
 {
 	struct cgpu_info *bitfury = userdata;
@@ -435,21 +541,12 @@ static void *bxf_get_results(void *userdata)
 		if (!err)
 			continue;
 
-		msg = strstr(buf, "submit");
-		if (msg) {
-			parse_bxf_submit(bitfury, info, msg);
-			continue;
-		}
-		msg = strstr(buf, "temp");
-		if (msg) {
-			parse_bxf_temp(bitfury, info, msg);
-			continue;
-		}
-		msg = strstr(buf, "needwork");
-		if (msg) {
-			parse_bxf_needwork(bitfury, info, msg);
-			continue;
-		}
+		PARSE_BXF_MSG(submit);
+		PARSE_BXF_MSG(temp);
+		PARSE_BXF_MSG(needwork);
+		PARSE_BXF_MSG(job);
+		PARSE_BXF_MSG(hwerror);
+
 		applog(LOG_DEBUG, "%s %d: Unrecognised string %s",
 		       bitfury->drv->name, bitfury->device_id, buf);
 	}
@@ -462,7 +559,7 @@ static bool bxf_prepare(struct cgpu_info *bitfury, struct bitfury_info *info)
 	mutex_init(&info->lock);
 	if (pthread_create(&info->read_thr, NULL, bxf_get_results, (void *)bitfury))
 		quit(1, "Failed to create bxf read_thr");
-	return true;
+	return bxf_send_clock(bitfury, info, BXF_CLOCK_DEFAULT);
 }
 
 static bool bitfury_prepare(struct thr_info *thr)
@@ -787,6 +884,13 @@ static struct api_data *bxf_api_stats(struct bitfury_info *info)
 	nonce_rate = (double)info->total_nonces / (double)info->cycles;
 	root = api_add_double(root, "NonceRate", &nonce_rate, true);
 	root = api_add_int(root, "NoMatchingWork", &info->no_matching_work, false);
+	root = api_add_double(root, "Temperature", &info->temperature, false);
+	root = api_add_int(root, "Max DeciTemp", &info->max_decitemp, false);
+	root = api_add_uint8(root, "Clock", &info->clocks, false);
+	root = api_add_int(root, "Core0 hwerror", &info->filtered_hw[0], false);
+	root = api_add_int(root, "Core1 hwerror", &info->filtered_hw[1], false);
+	root = api_add_int(root, "Core0 jobs", &info->job[0], false);
+	root = api_add_int(root, "Core1 jobs", &info->job[1], false);
 
 	return root;
 }
diff --git a/driver-bitfury.h b/driver-bitfury.h
index 851d3cc..42a805e 100644
--- a/driver-bitfury.h
+++ b/driver-bitfury.h
@@ -13,6 +13,17 @@
 #include "miner.h"
 #include "usbutils.h"
 
+#define BXF_CLOCK_DEFAULT 54
+#define BXF_CLOCK_OFF 0
+#define BXF_CLOCK_MIN 32
+#define BXF_CLOCK_MAX 63 // Not really used since we only get hw errors above default
+
+/* In tenths of a degree */
+#define BXF_TEMP_TARGET 820
+#define BXF_TEMP_HYSTERESIS 30
+
+extern int opt_bxf_temp_target;
+
 struct bitfury_info {
 	struct cgpu_info *base_cgpu;
 	struct thr_info *thr;
@@ -33,6 +44,9 @@ struct bitfury_info {
 	pthread_mutex_t lock;
 	pthread_t read_thr;
 	double temperature;
+	int last_decitemp;
+	int max_decitemp;
+	int temp_target;
 	int work_id; // Current work->subid
 	int no_matching_work;
 	int maxroll; // Last maxroll sent to device
@@ -40,6 +54,9 @@ struct bitfury_info {
 	int ver_minor;
 	int hw_rev;
 	int chips;
+	uint8_t clocks; // There are two but we set them equal
+	int filtered_hw[2]; // Hardware errors we're told about but are filtered
+	int job[2]; // Completed jobs we're told about
 };
 
 #endif /* BITFURY_H */
diff --git a/driver-hashfast.c b/driver-hashfast.c
index fefe57d..605ea95 100644
--- a/driver-hashfast.c
+++ b/driver-hashfast.c
@@ -515,6 +515,22 @@ static void hfa_parse_gwq_status(struct cgpu_info *hashfast, struct hashfast_inf
 		hashfast->device_id, g->sequence_head, g->sequence_tail, info->hash_sequence_tail,
 		g->shed_count, HF_SEQUENCE_DISTANCE(info->hash_sequence_head,g->sequence_tail));
 
+	/* This is a special flag that the thermal overload has been tripped */
+	if (unlikely(h->core_address & 0x80)) {
+		applog(LOG_WARNING, "HFA %d Thermal overload tripped! Resetting device",
+		       hashfast->device_id);
+		hfa_send_shutdown(hashfast);
+		if (hfa_reset(hashfast, info)) {
+			applog(LOG_NOTICE, "HFA %d: Succesfully reset, continuing operation",
+			       hashfast->device_id);
+			return;
+		}
+		applog(LOG_WARNING, "HFA %d Failed to reset device, killing off thread to allow re-hotplug",
+		       hashfast->device_id);
+		usb_nodev(hashfast);
+		return;
+	}
+
 	mutex_lock(&info->lock);
 	info->hash_count += g->hash_count;
 	info->device_sequence_head = g->sequence_head;
@@ -596,15 +612,20 @@ static void hfa_parse_nonce(struct thr_info *thr, struct cgpu_info *hashfast,
 	applog(LOG_DEBUG, "HFA %d: OP_NONCE: %2d:, num_nonces %d hdata 0x%04x",
 	       hashfast->device_id, h->chip_address, num_nonces, h->hdata);
 	for (i = 0; i < num_nonces; i++, n++) {
-		struct work *work;
+		struct work *work = NULL;
 
 		applog(LOG_DEBUG, "HFA %d: OP_NONCE: %2d: %2d: ntime %2d sequence %4d nonce 0x%08x",
 		       hashfast->device_id, h->chip_address, i, n->ntime & HF_NTIME_MASK, n->sequence, n->nonce);
 
-		// Find the job from the sequence number
-		mutex_lock(&info->lock);
-		work = info->works[n->sequence];
-		mutex_unlock(&info->lock);
+		if (n->sequence < info->usb_init_base.sequence_modulus) {
+			// Find the job from the sequence number
+			mutex_lock(&info->lock);
+			work = info->works[n->sequence];
+			mutex_unlock(&info->lock);
+		} else {
+			applog(LOG_INFO, "HFA %d: OP_NONCE: Sequence out of range %4d max %4d",
+			       hashfast->device_id, n->sequence, info->usb_init_base.sequence_modulus);
+		}
 
 		if (unlikely(!work)) {
 			info->no_matching_work++;
diff --git a/miner.h b/miner.h
index b8aed7d..042f8cb 100644
--- a/miner.h
+++ b/miner.h
@@ -1183,7 +1183,7 @@ struct pool {
 	char *nonce1;
 	unsigned char *nonce1bin;
 	size_t n1_len;
-	uint32_t nonce2;
+	uint64_t nonce2;
 	int n2size;
 	char *sessionid;
 	bool has_stratum;
@@ -1259,7 +1259,7 @@ struct work {
 
 	bool		stratum;
 	char 		*job_id;
-	uint32_t	nonce2;
+	uint64_t	nonce2;
 	size_t		nonce2_len;
 	char		*ntime;
 	double		sdiff;
diff --git a/usbutils.c b/usbutils.c
index 83468d2..28dc6a2 100644
--- a/usbutils.c
+++ b/usbutils.c
@@ -77,7 +77,7 @@ static cgtimer_t usb11_cgt;
 #define MODMINER_TIMEOUT_MS 100
 #define AVALON_TIMEOUT_MS 200
 #define KLONDIKE_TIMEOUT_MS 200
-#define HASHFAST_TIMEOUT_MS 200
+#define HASHFAST_TIMEOUT_MS 500
 #endif
 
 #define USB_EPS(_intx, _epinfosx) { \
diff --git a/usbutils.h b/usbutils.h
index 0b883bd..7ab77ac 100644
--- a/usbutils.h
+++ b/usbutils.h
@@ -347,6 +347,7 @@ struct cg_usb_info {
 	USB_ADD_COMMAND(C_BXF_VERSION, "BXFVersion") \
 	USB_ADD_COMMAND(C_BXF_MAXROLL, "BXFMaxRoll") \
 	USB_ADD_COMMAND(C_BXF_FLUSH, "BXFFlush") \
+	USB_ADD_COMMAND(C_BXF_CLOCK, "BXFClock") \
 	USB_ADD_COMMAND(C_HF_RESET, "HFReset") \
 	USB_ADD_COMMAND(C_HF_PLL_CONFIG, "HFPLLConfig") \
 	USB_ADD_COMMAND(C_HF_ADDRESS, "HFAddress") \