Browse Source

minergate: Implement mining

Luke Dashjr 11 years ago
parent
commit
1270f9d646
1 changed files with 211 additions and 9 deletions
  1. 211 9
      driver-minergate.c

+ 211 - 9
driver-minergate.c

@@ -23,9 +23,22 @@
 #include <sys/un.h>
 
 #include "deviceapi.h"
+#include "logging.h"
 #include "miner.h"
 
+#define MINERGATE_PROTOCOL_VER  6
+#define MINERGATE_MAGIC  0xcaf4
 static const int minergate_max_responses = 300;
+#define MINERGATE_PKT_HEADER_SZ       8
+#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_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)
 
@@ -34,6 +47,12 @@ enum minergate_reqpkt_flags {
 	MRPF_FLUSH = 2,
 };
 
+struct minergate_state {
+	work_device_id_t next_jobid;
+	unsigned ready_to_queue;
+	uint8_t *req_buffer;
+};
+
 static
 int minergate_open(const char * const devpath)
 {
@@ -57,6 +76,27 @@ int minergate_open(const char * const devpath)
 	return fd;
 }
 
+static
+ssize_t minergate_read(const int fd, void * const buf_p, size_t bufLen)
+{
+	uint8_t *buf = buf_p;
+	ssize_t rv, ret = 0;
+	while (bufLen > 0)
+	{
+		rv = read(fd, buf, bufLen);
+		if (rv <= 0)
+		{
+			if (ret > 0)
+				return ret;
+			return rv;
+		}
+		buf += rv;
+		bufLen -= rv;
+		ret += rv;
+	}
+	return ret;
+}
+
 static
 bool minergate_detect_one(const char * const devpath)
 {
@@ -66,11 +106,9 @@ bool minergate_detect_one(const char * const devpath)
 		applogr(false, LOG_DEBUG, "%s: %s: Cannot connect", minergate_drv.dname, devpath);
 	
 	int epfd = -1;
-	static const int minergate_version = 6;
-#define req_sz (8 + (24 * 100))
-	uint8_t buf[req_sz] = {0xbf, 0x90, minergate_version, MRPF_FIRST, 0,0, 0 /* req count */,};
-	pk_u16le(buf, 4, 0xcaf4);
-	if (req_sz != write(fd, buf, req_sz))
+	uint8_t buf[MINERGATE_PKT_REQ_SZ] = {0xbf, 0x90, MINERGATE_PROTOCOL_VER, MRPF_FIRST, 0,0, 0 /* req count */,};
+	pk_u16le(buf, 4, MINERGATE_MAGIC);
+	if (MINERGATE_PKT_REQ_SZ != write(fd, buf, MINERGATE_PKT_REQ_SZ))
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: write incomplete or failed", minergate_drv.dname, devpath);
 	
 	epfd = epoll_create(1);
@@ -83,7 +121,7 @@ bool minergate_detect_one(const char * const devpath)
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s failed", minergate_drv.dname, devpath, "epoll_ctl");
 	
 	size_t read_bytes = 0;
-	static const size_t read_expect = 8;
+	static const size_t read_expect = MINERGATE_PKT_HEADER_SZ;
 	ssize_t r;
 	while (read_bytes < read_expect)
 	{
@@ -97,9 +135,9 @@ bool minergate_detect_one(const char * const devpath)
 	
 	if (buf[1] != 0x90)
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "request_id");
-	if (buf[2] != minergate_version)
-		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "minergate_version");
-	if (upk_u16le(buf, 4) != 0xcaf4)
+	if (buf[2] != MINERGATE_PROTOCOL_VER)
+		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "Protocol version");
+	if (upk_u16le(buf, 4) != MINERGATE_MAGIC)
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "magic");
 	
 	uint16_t responses = upk_u16le(buf, 6);
@@ -111,6 +149,7 @@ bool minergate_detect_one(const char * const devpath)
 		.drv = &minergate_drv,
 		.device_path = strdup(devpath),
 		.deven = DEV_ENABLED,
+		.threads = 1,
 	};
 	rv = add_cgpu(cgpu);
 	
@@ -133,8 +172,171 @@ void minergate_detect(void)
 	generic_detect(&minergate_drv, minergate_detect_one, minergate_detect_auto, 0);
 }
 
+static
+bool minergate_init(struct thr_info * const thr)
+{
+	struct cgpu_info * const dev = thr->cgpu;
+	
+	const int fd = minergate_open(dev->device_path);
+	dev->device_fd = fd;
+	if (fd < 0)
+		applogr(false, LOG_ERR, "%s: Cannot connect", dev->dev_repr);
+	
+	struct minergate_state * const state = malloc(sizeof(*state) + MINERGATE_PKT_REQ_SZ);
+	if (!state)
+		applogr(false, LOG_ERR, "%s: %s failed", dev->dev_repr, "malloc");
+	*state = (struct minergate_state){
+		.req_buffer = (void*)&state[1]
+	};
+	thr->cgpu_data = state;
+	thr->work = thr->work_list = NULL;
+	
+	memset(state->req_buffer, 0, MINERGATE_PKT_REQ_SZ);
+	pk_u8(state->req_buffer, 2, MINERGATE_PROTOCOL_VER);
+	state->req_buffer[3] = MRPF_FIRST;
+	pk_u16le(state->req_buffer, 4, MINERGATE_MAGIC);
+	
+	return true;
+}
+
+static
+bool minergate_queue_full(struct thr_info * const thr)
+{
+	static const unsigned max_minergate_jobs = 300, max_requests = 100;
+	struct minergate_state * const state = thr->cgpu_data;
+	bool qf;
+	
+	if (HASH_COUNT(thr->work) + state->ready_to_queue >= max_minergate_jobs)
+		qf = true;
+	else
+	if (state->ready_to_queue >= max_requests)
+		qf = true;
+	else
+		qf = false;
+	
+	thr->queue_full = qf;
+	return qf;
+}
+
+static
+bool minergate_queue_append(struct thr_info * const thr, struct work * const work)
+{
+	struct minergate_state * const state = thr->cgpu_data;
+	
+	if (minergate_queue_full(thr))
+		return false;
+	
+	work->device_id = (uint32_t)(state->next_jobid++);
+	
+	uint8_t * const my_buf = &state->req_buffer[MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_REQ_ITEM_SZ * state->ready_to_queue++)];
+	pk_u32be(my_buf,  0, work->device_id);
+	memcpy(&my_buf[   4], &work->data[0x48], 4);  // nbits
+	memcpy(&my_buf[   8], &work->data[0x44], 4);  // ntime
+	memcpy(&my_buf[0x0c], &work->data[0x40], 4);  // merkle-tail
+	memcpy(&my_buf[0x10], work->midstate, 0x20);
+	pk_u8(my_buf, 0x30, 0x20);  // search leading zeros
+	pk_u8(my_buf, 0x31,    0);  // ntime limit
+	pk_u8(my_buf, 0x32,    0);  // ntime offset
+	pk_u8(my_buf, 0x33,    0);  // reserved
+	
+	HASH_ADD(hh, thr->work, device_id, sizeof(work->device_id), work);
+	LL_PREPEND(thr->work_list, work);
+	timer_set_delay_from_now(&thr->tv_poll, 0);
+	minergate_queue_full(thr);
+	
+	return true;
+}
+
+static
+void minergate_queue_flush(struct thr_info * const thr)
+{
+	struct minergate_state * const state = thr->cgpu_data;
+	
+	// TODO: prune state->ready_to_queue
+	state->req_buffer[3] |= MRPF_FLUSH;
+	timer_set_delay_from_now(&thr->tv_poll, 0);
+}
+
+static
+void minergate_poll(struct thr_info * const thr)
+{
+	struct cgpu_info * const dev = thr->cgpu;
+	struct minergate_state * const state = thr->cgpu_data;
+	const int fd = dev->device_fd;
+	
+	if (opt_dev_protocol || 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);
+	if (MINERGATE_PKT_REQ_SZ != write(fd, state->req_buffer, MINERGATE_PKT_REQ_SZ))
+		return_via_applog(err, , LOG_ERR, "%s: write incomplete or failed", dev->dev_repr);
+	
+	state->req_buffer[3] = 0;
+	state->ready_to_queue = 0;
+	thr->work_list = NULL;
+	
+	uint8_t buf[MINERGATE_PKT_RSP_SZ];
+	if (minergate_read(fd, buf, MINERGATE_PKT_RSP_SZ) != MINERGATE_PKT_RSP_SZ)
+		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)
+		return_via_applog(err, , LOG_ERR, "%s: Protocol mismatch", dev->dev_repr);
+	
+	uint8_t *jobrsp = &buf[MINERGATE_PKT_HEADER_SZ];
+	struct work *work;
+	uint16_t rsp_count = upk_u16le(buf, 6);
+	if (rsp_count || opt_dev_protocol)
+		applog(LOG_DEBUG, "%s: Received %u job completions", dev->dev_repr, rsp_count);
+	uint32_t nonce;
+	for (unsigned i = 0; i < rsp_count; ++i, (jobrsp += MINERGATE_PKT_RSP_ITEM_SZ))
+	{
+		work_device_id_t jobid = upk_u32be(jobrsp, 0);
+		nonce = upk_u32le(jobrsp, 8);
+		HASH_FIND(hh, thr->work, &jobid, sizeof(jobid), work);
+		if (!work)
+		{
+			applog(LOG_ERR, "%s: Unknown job %"PRIwdi, dev->dev_repr, jobid);
+			if (nonce)
+			{
+				inc_hw_errors3(thr, NULL, &nonce, 1.);
+				nonce = upk_u32le(jobrsp, 0xc);
+				if (nonce)
+					inc_hw_errors3(thr, NULL, &nonce, 1.);
+			}
+			else
+				inc_hw_errors_only(thr);
+			continue;
+		}
+		if (nonce)
+		{
+			submit_nonce(thr, work, nonce);
+			
+			nonce = upk_u32be(jobrsp, 0xc);
+			if (nonce)
+				submit_nonce(thr, work, nonce);
+		}
+		
+		HASH_DEL(thr->work, work);
+		free_work(work);
+	}
+	
+	minergate_queue_full(thr);
+	timer_set_delay_from_now(&thr->tv_poll, MINERGATE_POLL_US);
+	return;
+
+err:
+	// TODO: reconnect
+	timer_set_delay_from_now(&thr->tv_poll, MINERGATE_RETRY_US);
+}
+
 struct device_drv minergate_drv = {
 	.dname = "minergate",
 	.name = "MGT",
 	.drv_detect = minergate_detect,
+	
+	.thread_init = minergate_init,
+	.minerloop = minerloop_queue,
+	
+	.queue_append = minergate_queue_append,
+	.queue_flush = minergate_queue_flush,
+	.poll = minergate_poll,
 };