Browse Source

Merge remote-tracking branch 'upstream/bfgminer' into knc

Vitalii Demianets 11 years ago
parent
commit
29ceca2801
6 changed files with 268 additions and 53 deletions
  1. 39 0
      NEWS
  2. 1 1
      configure.ac
  3. 7 0
      debian/changelog
  4. 1 1
      debian/control
  5. 219 50
      driver-minergate.c
  6. 1 1
      openwrt/bfgminer/Makefile

+ 39 - 0
NEWS

@@ -1,3 +1,41 @@
+BFGMiner Version 4.10.0 - October 21, 2014
+
+- Upgraded Windows libjansson from 2.6 to 2.7
+- i2c-tools are not required by Titan
+- minergate: Fix hashmeter
+- minergate: Support minergate-side ntime rolling for SP30 only
+- minergate: Autodetect SP30 on /tmp/connection_pipe_sp30
+- minergate: Make stats file configurable
+- minergate: SP30 only wants max 10 queue requests at a time
+- minergate: Use work_completed flag for SP30
+- minergate: Only SP10 has a second winner_nonce
+- minergate: Simplify multi-winner_nonce handling
+- Bugfix: minergate: Correct endian for 2nd winner_nonce
+- minergate: Vary max jobs queued
+- minergate: Vary number of requests/responses per packet
+- minergate: Support --set MGT:protover=N
+- Titan: fix compiler warning "maybe-uninitialized"
+- Titan: Increase die inactivity timeout to 20 secs
+- Titan: Slightly improve some debug messages
+- Titan: Use multi-part batched SPI transfers for flushes (saves 2 secs on each
+flush)
+- Titan: Fix buffer overflow
+- Titan: Increase queue prefill value up to 20
+- Titan: Flag for fast broadcast flushes. Not enabled: DC/DCs trip off easily!
+- Titan: Monitor die health, reconfigure it if no shares in 10 seconds
+- Titan: Make log level of some messages lower, to not clobber the screen
+- Titan: Work assignment and flushing is per-die, not per-ASIC
+- Titan: Set flush flag after re-configuring the die
+- Titan: Refactoring: intermediate variables for first_proc and repr
+- Titan: Flush cores one-by-one right before reconfiguring them
+- Titan: Define for the broadcast core address
+- Titan: Re-configuring dies through API command "procset"
+- Titan: Use correct version of knc_titan_setup_core
+- Titan: configure_one_die func for configuring single die
+- Titan: fill all non-found ASIC structs with the same (invalid) data
+- Titan: Core init parameters (nonce range) independent of number of found dies
+
+
 BFGMiner Version 4.9.0 - October 5, 2014
 BFGMiner Version 4.9.0 - October 5, 2014
 
 
 - Upgraded Windows libraries:
 - Upgraded Windows libraries:
@@ -89,6 +127,7 @@ trouble
 - Bugfix: async minerloop fix for devices disabled at start
 - Bugfix: async minerloop fix for devices disabled at start
 - twinfury: Implement device protocol dump more low-level
 - twinfury: Implement device protocol dump more low-level
 
 
+
 BFGMiner Version 4.8.0 - September 10, 2014
 BFGMiner Version 4.8.0 - September 10, 2014
 
 
 - Improve precision of total_secs used in (at least) RPC summary Elapsed
 - Improve precision of total_secs used in (at least) RPC summary Elapsed

+ 1 - 1
configure.ac

@@ -14,7 +14,7 @@ dnl * any later version.  See COPYING for more details.
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [4])
 m4_define([v_maj], [4])
-m4_define([v_min], [9])
+m4_define([v_min], [10])
 m4_define([v_mic], [0])
 m4_define([v_mic], [0])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([v_ver], [v_maj.v_min.v_mic])

+ 7 - 0
debian/changelog

@@ -1,3 +1,10 @@
+bfgminer (4.10.0-0precise1) precise; urgency=low
+
+  * minergate: Support for Spondoolies SP30.
+  * titan: Numerous fixes and improvements from the KnCMiner team.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Tue, 21 Oct 2014 04:01:46 -0000
+
 bfgminer (4.9.0-0precise1) precise; urgency=low
 bfgminer (4.9.0-0precise1) precise; urgency=low
 
 
   * titan: Driver for KnCMiner's scrypt ASIC machine.
   * titan: Driver for KnCMiner's scrypt ASIC machine.

+ 1 - 1
debian/control

@@ -2,7 +2,7 @@ Source: bfgminer
 Priority: optional
 Priority: optional
 Section: misc
 Section: misc
 Maintainer: Luke Dashjr <luke_bfgminer@dashjr.org>
 Maintainer: Luke Dashjr <luke_bfgminer@dashjr.org>
-Standards-Version: 4.9.0
+Standards-Version: 4.10.0
 Build-Depends: build-essential, debhelper, autoconf, automake, libtool, libssl-dev, yasm, pkg-config, libudev-dev, libcurl4-openssl-dev, wget, unzip, libjansson-dev, libncurses5-dev, libudev-dev, libusb-1.0-0-dev, git, quilt, uthash-dev, libsensors4-dev
 Build-Depends: build-essential, debhelper, autoconf, automake, libtool, libssl-dev, yasm, pkg-config, libudev-dev, libcurl4-openssl-dev, wget, unzip, libjansson-dev, libncurses5-dev, libudev-dev, libusb-1.0-0-dev, git, quilt, uthash-dev, libsensors4-dev
 
 
 Package: bfgminer
 Package: bfgminer

+ 219 - 50
driver-minergate.c

@@ -33,27 +33,40 @@
 
 
 static const char * const minergate_stats_file = "/var/run/mg_rate_temp";
 static const char * const minergate_stats_file = "/var/run/mg_rate_temp";
 
 
-#define MINERGATE_PROTOCOL_VER  6
 #define MINERGATE_MAGIC  0xcaf4
 #define MINERGATE_MAGIC  0xcaf4
-static const int minergate_max_responses = 300;
 #define MINERGATE_PKT_HEADER_SZ       8
 #define MINERGATE_PKT_HEADER_SZ       8
 #define MINERGATE_PKT_REQ_ITEM_SZ  0x34
 #define MINERGATE_PKT_REQ_ITEM_SZ  0x34
-#define MINERGATE_PKT_REQ_MAX     100
-#define MINERGATE_PKT_RSP_ITEM_SZ  0x14
-#define MINERGATE_PKT_RSP_MAX     300
 #define MINERGATE_POLL_US      100000
 #define MINERGATE_POLL_US      100000
 #define MINERGATE_RETRY_US    5000000
 #define MINERGATE_RETRY_US    5000000
 
 
-#define MINERGATE_PKT_REQ_SZ  (MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_REQ_ITEM_SZ * MINERGATE_PKT_REQ_MAX))
-#define MINERGATE_PKT_RSP_SZ  (MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_RSP_ITEM_SZ * MINERGATE_PKT_RSP_MAX))
-
 BFG_REGISTER_DRIVER(minergate_drv)
 BFG_REGISTER_DRIVER(minergate_drv)
 
 
+enum minergate_protocol_ver {
+	MPV_SP10 =  6,
+	MPV_SP30 = 30,
+};
+
 enum minergate_reqpkt_flags {
 enum minergate_reqpkt_flags {
 	MRPF_FIRST = 1,
 	MRPF_FIRST = 1,
 	MRPF_FLUSH = 2,
 	MRPF_FLUSH = 2,
 };
 };
 
 
+struct minergate_config {
+	uint8_t protover;
+	int n_req;
+	int n_req_queue;
+	int n_rsp;
+	int queue;
+	char *stats_file;
+	int minimum_roll;
+	int desired_roll;
+	int work_duration;
+	
+	int pkt_req_sz;
+	int pkt_rsp_sz;
+	int pkt_rsp_item_sz;
+};
+
 struct minergate_state {
 struct minergate_state {
 	work_device_id_t next_jobid;
 	work_device_id_t next_jobid;
 	unsigned ready_to_queue;
 	unsigned ready_to_queue;
@@ -107,18 +120,118 @@ ssize_t minergate_read(const int fd, void * const buf_p, size_t bufLen)
 	return ret;
 	return ret;
 }
 }
 
 
+
+#define DEF_POSITIVE_VAR(VARNAME)  \
+static  \
+const char *minergate_init_ ## VARNAME(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)  \
+{  \
+	struct minergate_config * const mgcfg = proc->device_data;  \
+	int nv = atoi(newvalue);  \
+	if (nv < 0)  \
+		return #VARNAME " must be positive";  \
+	mgcfg->VARNAME = nv;  \
+	return NULL;  \
+}  \
+// END OF DEF_POSITIVE_VAR
+
 static
 static
-bool minergate_detect_one(const char * const devpath)
+const char *minergate_init_protover(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct minergate_config * const mgcfg = proc->device_data;
+	
+	int i = atoi(newvalue);
+	
+	if (i != MPV_SP10 || i != MPV_SP30)
+		return "Invalid protocol version";
+	
+	mgcfg->protover = i;
+	
+	return NULL;
+}
+
+DEF_POSITIVE_VAR(n_req)
+DEF_POSITIVE_VAR(n_req_queue)
+DEF_POSITIVE_VAR(n_rsp)
+DEF_POSITIVE_VAR(queue)
+
+static
+const char *minergate_init_stats_file(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct minergate_config * const mgcfg = proc->device_data;
+	free(mgcfg->stats_file);
+	mgcfg->stats_file = trimmed_strdup(newvalue);
+	return NULL;
+}
+
+DEF_POSITIVE_VAR(work_duration)
+DEF_POSITIVE_VAR(minimum_roll)
+DEF_POSITIVE_VAR(desired_roll)
+
+static const struct bfg_set_device_definition minergate_set_device_funcs_probe[] = {
+	{"protover", minergate_init_protover, NULL},
+	{"n_req", minergate_init_n_req, NULL},
+	{"n_req_queue", minergate_init_n_req_queue, NULL},
+	{"n_rsp", minergate_init_n_rsp, NULL},
+	{"queue", minergate_init_queue, NULL},
+	{"stats_file", minergate_init_stats_file, NULL},
+	{"work_duration", minergate_init_work_duration, NULL},
+	{"minimum_roll", minergate_init_minimum_roll, NULL},
+	{"desired_roll", minergate_init_desired_roll, NULL},
+	{NULL},
+};
+
+static
+bool minergate_detect_one_extra(const char * const devpath, const enum minergate_protocol_ver def_protover)
 {
 {
 	bool rv = false;
 	bool rv = false;
 	const int fd = minergate_open(devpath);
 	const int fd = minergate_open(devpath);
 	if (unlikely(fd < 0))
 	if (unlikely(fd < 0))
 		applogr(false, LOG_DEBUG, "%s: %s: Cannot connect", minergate_drv.dname, devpath);
 		applogr(false, LOG_DEBUG, "%s: %s: Cannot connect", minergate_drv.dname, devpath);
 	
 	
+	struct minergate_config * const mgcfg = malloc(sizeof(*mgcfg));
+	*mgcfg = (struct minergate_config){
+		.protover = def_protover,
+		.work_duration = -1,
+		.minimum_roll = -1,
+		.desired_roll = -1,
+	};
+	drv_set_defaults(&minergate_drv, minergate_set_device_funcs_probe, mgcfg, devpath, NULL, 1);
+	switch (mgcfg->protover)
+	{
+		case MPV_SP10:
+			BFGINIT(mgcfg->n_req, 100);
+			BFGINIT(mgcfg->n_req_queue, mgcfg->n_req);
+			BFGINIT(mgcfg->n_rsp, 300);
+			BFGINIT(mgcfg->queue, 300);
+			mgcfg->pkt_rsp_item_sz = 0x14;
+			mgcfg->minimum_roll = mgcfg->desired_roll = 0;  // not supported
+			break;
+		case MPV_SP30:
+			BFGINIT(mgcfg->n_req, 30);
+			BFGINIT(mgcfg->n_req_queue, min(10, mgcfg->n_req));
+			BFGINIT(mgcfg->n_rsp, 60);
+			BFGINIT(mgcfg->queue, 40);
+			mgcfg->pkt_rsp_item_sz = 0x10;
+			if (mgcfg->minimum_roll == -1)
+				mgcfg->minimum_roll = 60;
+			break;
+	}
+	BFGINIT(mgcfg->stats_file, strdup(minergate_stats_file));
+	mgcfg->desired_roll = max(mgcfg->desired_roll, mgcfg->minimum_roll);
+	if (mgcfg->work_duration == -1)
+		mgcfg->work_duration = 0x10;  // reasonable guess?
+	mgcfg->pkt_req_sz = MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_REQ_ITEM_SZ * mgcfg->n_req);
+	mgcfg->pkt_rsp_sz = MINERGATE_PKT_HEADER_SZ + (mgcfg->pkt_rsp_item_sz * mgcfg->n_rsp);
+	
 	int epfd = -1;
 	int epfd = -1;
-	uint8_t buf[MINERGATE_PKT_REQ_SZ] = {0xbf, 0x90, MINERGATE_PROTOCOL_VER, MRPF_FIRST, 0,0, 0 /* req count */,};
+	uint8_t buf[mgcfg->pkt_req_sz];
+	buf[0] = 0xbf;
+	buf[1] = 0x90;
+	buf[2] = mgcfg->protover;
+	buf[3] = MRPF_FIRST;
 	pk_u16le(buf, 4, MINERGATE_MAGIC);
 	pk_u16le(buf, 4, MINERGATE_MAGIC);
-	if (MINERGATE_PKT_REQ_SZ != write(fd, buf, MINERGATE_PKT_REQ_SZ))
+	memset(&buf[6], '\0', mgcfg->pkt_req_sz - 6);
+	if (mgcfg->pkt_req_sz != write(fd, buf, mgcfg->pkt_req_sz))
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: write incomplete or failed", minergate_drv.dname, devpath);
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: write incomplete or failed", minergate_drv.dname, devpath);
 	
 	
 	epfd = epoll_create(1);
 	epfd = epoll_create(1);
@@ -145,13 +258,13 @@ bool minergate_detect_one(const char * const devpath)
 	
 	
 	if (buf[1] != 0x90)
 	if (buf[1] != 0x90)
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "request_id");
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "request_id");
-	if (buf[2] != MINERGATE_PROTOCOL_VER)
+	if (buf[2] != mgcfg->protover)
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "Protocol version");
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "Protocol version");
 	if (upk_u16le(buf, 4) != MINERGATE_MAGIC)
 	if (upk_u16le(buf, 4) != MINERGATE_MAGIC)
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "magic");
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "magic");
 	
 	
 	uint16_t responses = upk_u16le(buf, 6);
 	uint16_t responses = upk_u16le(buf, 6);
-	if (responses > minergate_max_responses)
+	if (responses > mgcfg->n_rsp)
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: More than maximum responses", minergate_drv.dname, devpath);
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: More than maximum responses", minergate_drv.dname, devpath);
 	
 	
 	if (bfg_claim_any2(&minergate_drv, devpath, "unix", devpath))
 	if (bfg_claim_any2(&minergate_drv, devpath, "unix", devpath))
@@ -161,22 +274,36 @@ bool minergate_detect_one(const char * const devpath)
 	*cgpu = (struct cgpu_info){
 	*cgpu = (struct cgpu_info){
 		.drv = &minergate_drv,
 		.drv = &minergate_drv,
 		.device_path = strdup(devpath),
 		.device_path = strdup(devpath),
+		.device_data = mgcfg,
 		.deven = DEV_ENABLED,
 		.deven = DEV_ENABLED,
 		.threads = 1,
 		.threads = 1,
 	};
 	};
 	rv = add_cgpu(cgpu);
 	rv = add_cgpu(cgpu);
 	
 	
 out:
 out:
+	if (!rv)
+		free(mgcfg);
 	close(fd);
 	close(fd);
 	if (epfd >= 0)
 	if (epfd >= 0)
 		close(epfd);
 		close(epfd);
 	return rv;
 	return rv;
 }
 }
 
 
+static
+bool minergate_detect_one(const char * const devpath)
+{
+	return minergate_detect_one_extra(devpath, MPV_SP10);
+}
+
 static
 static
 int minergate_detect_auto(void)
 int minergate_detect_auto(void)
 {
 {
-	return minergate_detect_one("/tmp/connection_pipe") ? 1 : 0;
+	int total = 0;
+	if (minergate_detect_one_extra("/tmp/connection_pipe", MPV_SP10))
+		++total;
+	if (minergate_detect_one_extra("/tmp/connection_pipe_sp30", MPV_SP30))
+		++total;
+	return total;
 }
 }
 
 
 static
 static
@@ -189,13 +316,14 @@ static
 bool minergate_init(struct thr_info * const thr)
 bool minergate_init(struct thr_info * const thr)
 {
 {
 	struct cgpu_info * const dev = thr->cgpu;
 	struct cgpu_info * const dev = thr->cgpu;
+	struct minergate_config * const mgcfg = dev->device_data;
 	
 	
 	const int fd = minergate_open(dev->device_path);
 	const int fd = minergate_open(dev->device_path);
 	dev->device_fd = fd;
 	dev->device_fd = fd;
 	if (fd < 0)
 	if (fd < 0)
 		applogr(false, LOG_ERR, "%s: Cannot connect", dev->dev_repr);
 		applogr(false, LOG_ERR, "%s: Cannot connect", dev->dev_repr);
 	
 	
-	struct minergate_state * const state = malloc(sizeof(*state) + MINERGATE_PKT_REQ_SZ);
+	struct minergate_state * const state = malloc(sizeof(*state) + mgcfg->pkt_req_sz);
 	if (!state)
 	if (!state)
 		applogr(false, LOG_ERR, "%s: %s failed", dev->dev_repr, "malloc");
 		applogr(false, LOG_ERR, "%s: %s failed", dev->dev_repr, "malloc");
 	*state = (struct minergate_state){
 	*state = (struct minergate_state){
@@ -205,8 +333,8 @@ bool minergate_init(struct thr_info * const thr)
 	thr->work = thr->work_list = NULL;
 	thr->work = thr->work_list = NULL;
 	
 	
 	mutex_init(&dev->device_mutex);
 	mutex_init(&dev->device_mutex);
-	memset(state->req_buffer, 0, MINERGATE_PKT_REQ_SZ);
-	pk_u8(state->req_buffer, 2, MINERGATE_PROTOCOL_VER);
+	memset(state->req_buffer, 0, mgcfg->pkt_req_sz);
+	pk_u8(state->req_buffer, 2, mgcfg->protover);
 	state->req_buffer[3] = MRPF_FIRST | MRPF_FLUSH;
 	state->req_buffer[3] = MRPF_FIRST | MRPF_FLUSH;
 	pk_u16le(state->req_buffer, 4, MINERGATE_MAGIC);
 	pk_u16le(state->req_buffer, 4, MINERGATE_MAGIC);
 	timer_set_delay_from_now(&thr->tv_poll, 0);
 	timer_set_delay_from_now(&thr->tv_poll, 0);
@@ -217,14 +345,15 @@ bool minergate_init(struct thr_info * const thr)
 static
 static
 bool minergate_queue_full(struct thr_info * const thr)
 bool minergate_queue_full(struct thr_info * const thr)
 {
 {
-	static const unsigned max_minergate_jobs = 300, max_requests = 100;
+	struct cgpu_info * const dev = thr->cgpu;
+	struct minergate_config * const mgcfg = dev->device_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	bool qf;
 	bool qf;
 	
 	
-	if (HASH_COUNT(thr->work) + state->ready_to_queue >= max_minergate_jobs)
+	if (HASH_COUNT(thr->work) + state->ready_to_queue >= mgcfg->queue)
 		qf = true;
 		qf = true;
 	else
 	else
-	if (state->ready_to_queue >= max_requests)
+	if (state->ready_to_queue >= mgcfg->n_req_queue)
 		qf = true;
 		qf = true;
 	else
 	else
 	if (state->req_buffer[3] & MRPF_FLUSH)
 	if (state->req_buffer[3] & MRPF_FLUSH)
@@ -241,6 +370,7 @@ static
 bool minergate_queue_append(struct thr_info * const thr, struct work * const work)
 bool minergate_queue_append(struct thr_info * const thr, struct work * const work)
 {
 {
 	struct cgpu_info * const dev = thr->cgpu;
 	struct cgpu_info * const dev = thr->cgpu;
+	struct minergate_config * const mgcfg = dev->device_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	
 	
 	if (minergate_queue_full(thr))
 	if (minergate_queue_full(thr))
@@ -250,6 +380,20 @@ bool minergate_queue_append(struct thr_info * const thr, struct work * const wor
 	work->tv_stamp.tv_sec = 0;
 	work->tv_stamp.tv_sec = 0;
 	
 	
 	uint8_t * const my_buf = &state->req_buffer[MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_REQ_ITEM_SZ * state->ready_to_queue++)];
 	uint8_t * const my_buf = &state->req_buffer[MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_REQ_ITEM_SZ * state->ready_to_queue++)];
+	
+	if (mgcfg->desired_roll)
+	{
+		struct timeval tv_now, tv_latest;
+		timer_set_now(&tv_now);
+		timer_set_delay(&tv_latest, &tv_now, mgcfg->work_duration * 1000000LL);
+		int ntimeroll = work_ntime_range(work, &tv_now, &tv_latest, mgcfg->desired_roll);
+		// NOTE: If minimum_roll bumps ntimeroll up, we may get rejects :(
+		ntimeroll = min(0xff, max(mgcfg->minimum_roll, ntimeroll));
+		pk_u8(my_buf, 0x31, ntimeroll);  // ntime limit
+	}
+	else
+		pk_u8(my_buf, 0x31, 0);  // ntime limit
+	
 	pk_u32be(my_buf,  0, work->device_id);
 	pk_u32be(my_buf,  0, work->device_id);
 	memcpy(&my_buf[   4], &work->data[0x48], 4);  // nbits
 	memcpy(&my_buf[   4], &work->data[0x48], 4);  // nbits
 	memcpy(&my_buf[   8], &work->data[0x44], 4);  // ntime
 	memcpy(&my_buf[   8], &work->data[0x44], 4);  // ntime
@@ -263,9 +407,8 @@ bool minergate_queue_append(struct thr_info * const thr, struct work * const wor
 	const uint16_t zerobits = log2(floor(work->nonce_diff * 4294967296));
 	const uint16_t zerobits = log2(floor(work->nonce_diff * 4294967296));
 	work->nonce_diff = pow(2, zerobits) / 4294967296;
 	work->nonce_diff = pow(2, zerobits) / 4294967296;
 	pk_u8(my_buf, 0x30, zerobits);
 	pk_u8(my_buf, 0x30, zerobits);
-	
-	pk_u8(my_buf, 0x31,    0);  // ntime limit
-	pk_u8(my_buf, 0x32,    0);  // ntime offset
+	// 0x31 is ntimeroll, which must be set before data ntime (in case it's changed)
+	pk_u8(my_buf, 0x32,    0);  // pv6: ntime offset ; pv30: reserved
 	pk_u8(my_buf, 0x33,    0);  // reserved
 	pk_u8(my_buf, 0x33,    0);  // reserved
 	
 	
 	struct work *oldwork;
 	struct work *oldwork;
@@ -305,17 +448,40 @@ void minergate_queue_flush(struct thr_info * const thr)
 	timer_set_delay_from_now(&thr->tv_poll, 0);
 	timer_set_delay_from_now(&thr->tv_poll, 0);
 }
 }
 
 
+static
+bool minergate_submit(struct thr_info * const thr, struct work * const work, const uint32_t nonce, const uint8_t ntime_offset, int64_t * const hashes)
+{
+	if (!nonce)
+		return false;
+	
+	if (likely(work))
+	{
+		submit_noffset_nonce(thr, work, nonce, ntime_offset);
+		
+		struct cgpu_info * const dev = thr->cgpu;
+		struct minergate_config * const mgcfg = dev->device_data;
+		if (mgcfg->desired_roll)
+			*hashes += 0x100000000 * work->nonce_diff;
+	}
+	else
+		inc_hw_errors3(thr, NULL, &nonce, 1.);
+	
+	return true;
+}
+
 static
 static
 void minergate_poll(struct thr_info * const thr)
 void minergate_poll(struct thr_info * const thr)
 {
 {
 	struct cgpu_info * const dev = thr->cgpu;
 	struct cgpu_info * const dev = thr->cgpu;
+	struct minergate_config * const mgcfg = dev->device_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	const int fd = dev->device_fd;
 	const int fd = dev->device_fd;
+	uint8_t buf[mgcfg->pkt_rsp_sz];
 	
 	
 	if (opt_dev_protocol || state->ready_to_queue)
 	if (opt_dev_protocol || state->ready_to_queue)
 		applog(LOG_DEBUG, "%s: Polling with %u new jobs", dev->dev_repr, state->ready_to_queue);
 		applog(LOG_DEBUG, "%s: Polling with %u new jobs", dev->dev_repr, state->ready_to_queue);
 	pk_u16le(state->req_buffer, 6, state->ready_to_queue);
 	pk_u16le(state->req_buffer, 6, state->ready_to_queue);
-	if (MINERGATE_PKT_REQ_SZ != write(fd, state->req_buffer, MINERGATE_PKT_REQ_SZ))
+	if (mgcfg->pkt_req_sz != write(fd, state->req_buffer, mgcfg->pkt_req_sz))
 		return_via_applog(err, , LOG_ERR, "%s: write incomplete or failed", dev->dev_repr);
 		return_via_applog(err, , LOG_ERR, "%s: write incomplete or failed", dev->dev_repr);
 	
 	
 	uint8_t flags = state->req_buffer[3];
 	uint8_t flags = state->req_buffer[3];
@@ -323,11 +489,10 @@ void minergate_poll(struct thr_info * const thr)
 	state->ready_to_queue = 0;
 	state->ready_to_queue = 0;
 	thr->work_list = NULL;
 	thr->work_list = NULL;
 	
 	
-	uint8_t buf[MINERGATE_PKT_RSP_SZ];
-	if (minergate_read(fd, buf, MINERGATE_PKT_RSP_SZ) != MINERGATE_PKT_RSP_SZ)
+	if (minergate_read(fd, buf, mgcfg->pkt_rsp_sz) != mgcfg->pkt_rsp_sz)
 		return_via_applog(err, , LOG_ERR, "%s: %s failed", dev->dev_repr, "read");
 		return_via_applog(err, , LOG_ERR, "%s: %s failed", dev->dev_repr, "read");
 	
 	
-	if (upk_u8(buf, 2) != MINERGATE_PROTOCOL_VER || upk_u16le(buf, 4) != MINERGATE_MAGIC)
+	if (upk_u8(buf, 2) != mgcfg->protover || upk_u16le(buf, 4) != MINERGATE_MAGIC)
 		return_via_applog(err, , LOG_ERR, "%s: Protocol mismatch", dev->dev_repr);
 		return_via_applog(err, , LOG_ERR, "%s: Protocol mismatch", dev->dev_repr);
 	
 	
 	uint8_t *jobrsp = &buf[MINERGATE_PKT_HEADER_SZ];
 	uint8_t *jobrsp = &buf[MINERGATE_PKT_HEADER_SZ];
@@ -336,40 +501,40 @@ void minergate_poll(struct thr_info * const thr)
 	if (rsp_count || opt_dev_protocol)
 	if (rsp_count || opt_dev_protocol)
 		applog(LOG_DEBUG, "%s: Received %u job completions", dev->dev_repr, rsp_count);
 		applog(LOG_DEBUG, "%s: Received %u job completions", dev->dev_repr, rsp_count);
 	uint32_t nonce;
 	uint32_t nonce;
+	uint8_t ntime_offset;
 	int64_t hashes = 0;
 	int64_t hashes = 0;
-	for (unsigned i = 0; i < rsp_count; ++i, (jobrsp += MINERGATE_PKT_RSP_ITEM_SZ))
+	for (unsigned i = 0; i < rsp_count; ++i, (jobrsp += mgcfg->pkt_rsp_item_sz))
 	{
 	{
 		work_device_id_t jobid = upk_u32be(jobrsp, 0);
 		work_device_id_t jobid = upk_u32be(jobrsp, 0);
 		nonce = upk_u32le(jobrsp, 8);
 		nonce = upk_u32le(jobrsp, 8);
+		ntime_offset = upk_u8(jobrsp, (mgcfg->protover == MPV_SP10) ? 0x10 : 0xc);
+		
 		HASH_FIND(hh, thr->work, &jobid, sizeof(jobid), work);
 		HASH_FIND(hh, thr->work, &jobid, sizeof(jobid), work);
-		if (!work)
-		{
+		if (unlikely(!work))
 			applog(LOG_ERR, "%s: Unknown job %"PRIwdi, dev->dev_repr, jobid);
 			applog(LOG_ERR, "%s: Unknown job %"PRIwdi, dev->dev_repr, jobid);
-			if (nonce)
+		
+		if (minergate_submit(thr, work, nonce, ntime_offset, &hashes))
+		{
+			if (mgcfg->protover == MPV_SP10)
 			{
 			{
-				inc_hw_errors3(thr, NULL, &nonce, 1.);
 				nonce = upk_u32le(jobrsp, 0xc);
 				nonce = upk_u32le(jobrsp, 0xc);
-				if (nonce)
-					inc_hw_errors3(thr, NULL, &nonce, 1.);
+				minergate_submit(thr, work, nonce, ntime_offset, &hashes);
 			}
 			}
-			else
-				inc_hw_errors_only(thr);
-			continue;
 		}
 		}
-		if (nonce)
+		else
+		if (unlikely(!work))
+			// Increment HW errors even if no nonce to submit
+			inc_hw_errors_only(thr);
+		
+		const bool work_completed = (mgcfg->protover == MPV_SP10) ? (bool)work : (bool)jobrsp[0xe];
+		if (work_completed)
 		{
 		{
-			submit_nonce(thr, work, nonce);
-			
-			nonce = upk_u32be(jobrsp, 0xc);
-			if (nonce)
-				submit_nonce(thr, work, nonce);
+			HASH_DEL(thr->work, work);
+			applog(LOG_DEBUG, "%s: %s job %"PRIwdi" completed", dev->dev_repr, work->tv_stamp.tv_sec ? "Flushed" : "Active", work->device_id);
+			if ((!mgcfg->desired_roll) && !work->tv_stamp.tv_sec)
+				hashes += 0x100000000 * work->nonce_diff;
+			free_work(work);
 		}
 		}
-		
-		HASH_DEL(thr->work, work);
-		applog(LOG_DEBUG, "%s: %s job %"PRIwdi" completed", dev->dev_repr, work->tv_stamp.tv_sec ? "Flushed" : "Active", work->device_id);
-		if (!work->tv_stamp.tv_sec)
-			hashes += 100000000 * work->nonce_diff;
-		free_work(work);
 	}
 	}
 	hashes_done2(thr, hashes, NULL);
 	hashes_done2(thr, hashes, NULL);
 	
 	
@@ -396,10 +561,14 @@ static
 bool minergate_get_stats(struct cgpu_info * const dev)
 bool minergate_get_stats(struct cgpu_info * const dev)
 {
 {
 	static const int skip_stats = 1;
 	static const int skip_stats = 1;
+	struct minergate_config * const mgcfg = dev->device_data;
 	struct thr_info * const thr = dev->thr[0];
 	struct thr_info * const thr = dev->thr[0];
 	struct minergate_state * const state = thr->cgpu_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	
 	
-	FILE *F = fopen(minergate_stats_file, "r");
+	if (!(mgcfg->stats_file && mgcfg->stats_file[0]))
+		return true;
+	
+	FILE *F = fopen(mgcfg->stats_file, "r");
 	char buf[0x100];
 	char buf[0x100];
 	if (F)
 	if (F)
 	{
 	{

+ 1 - 1
openwrt/bfgminer/Makefile

@@ -11,7 +11,7 @@ include $(TOPDIR)/rules.mk
 
 
 PKG_NAME:=bfgminer
 PKG_NAME:=bfgminer
 PKG_TITLE:=BFGMiner
 PKG_TITLE:=BFGMiner
-PKG_VERSION:=4.9.0
+PKG_VERSION:=4.10.0
 PKG_RELEASE:=1
 PKG_RELEASE:=1
 
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).txz
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).txz