Browse Source

rockminer: Implement mining (at 200 MHz)

Luke Dashjr 11 years ago
parent
commit
081582273c
1 changed files with 157 additions and 0 deletions
  1. 157 0
      driver-rockminer.c

+ 157 - 0
driver-rockminer.c

@@ -19,6 +19,8 @@
 #include "miner.h"
 #include "miner.h"
 
 
 #define ROCKMINER_MIN_FREQ_MHZ  200
 #define ROCKMINER_MIN_FREQ_MHZ  200
+#define ROCKMINER_POLL_US         0
+#define ROCKMINER_RETRY_US  5000000
 
 
 #define ROCKMINER_MAX_CHIPS  64
 #define ROCKMINER_MAX_CHIPS  64
 #define ROCKMINER_WORK_REQ_SIZE  0x40
 #define ROCKMINER_WORK_REQ_SIZE  0x40
@@ -26,12 +28,16 @@
 
 
 enum rockminer_replies {
 enum rockminer_replies {
 	ROCKMINER_REPLY_NONCE_FOUND = 0,
 	ROCKMINER_REPLY_NONCE_FOUND = 0,
+	ROCKMINER_REPLY_TASK_COMPLETE = 1,
+	ROCKMINER_REPLY_GET_TASK = 2,
 };
 };
 
 
 BFG_REGISTER_DRIVER(rockminer_drv)
 BFG_REGISTER_DRIVER(rockminer_drv)
 
 
 struct rockminer_chip_data {
 struct rockminer_chip_data {
 	uint8_t next_work_req[ROCKMINER_WORK_REQ_SIZE];
 	uint8_t next_work_req[ROCKMINER_WORK_REQ_SIZE];
+	struct work *works[2];
+	uint8_t last_taskid;
 };
 };
 
 
 static
 static
@@ -193,8 +199,159 @@ bool rockminer_lowl_probe(const struct lowlevel_device_info * const info)
 	return vcom_lowl_probe_wrapper(info, rockminer_detect_one);
 	return vcom_lowl_probe_wrapper(info, rockminer_detect_one);
 }
 }
 
 
+static
+bool rockminer_init(struct thr_info * const master_thr)
+{
+	struct cgpu_info * const dev = master_thr->cgpu;
+	
+	for_each_managed_proc(proc, dev)
+	{
+		struct thr_info * const thr = proc->thr[0];
+		struct rockminer_chip_data * const chip = malloc(sizeof(*chip));
+		
+		thr->cgpu_data = chip;
+		
+		rockminer_job_buf_init(chip->next_work_req, proc->proc_id);
+		rockminer_job_buf_set_freq(chip->next_work_req, ROCKMINER_MIN_FREQ_MHZ);
+	}
+	
+	timer_set_now(&master_thr->tv_poll);
+	
+	return true;
+}
+
+static
+void rockminer_dead(struct cgpu_info * const dev)
+{
+	serial_close(dev->device_fd);
+	dev->device_fd = -1;
+	for_each_managed_proc(proc, dev)
+	{
+		struct thr_info * const thr = proc->thr[0];
+		thr->queue_full = true;
+	}
+}
+
+static
+bool rockminer_queue_append(struct thr_info * const thr, struct work * const work)
+{
+	struct cgpu_info * const proc = thr->cgpu;
+	struct cgpu_info * const dev = proc->device;
+	struct rockminer_chip_data * const chip = thr->cgpu_data;
+	const int fd = dev->device_fd;
+	
+	thr->queue_full = true;
+	
+	if (fd < 0)
+		return false;
+	
+	memcpy(&chip->next_work_req[   0], work->midstate, 0x20);
+	memcpy(&chip->next_work_req[0x34], &work->data[0x40], 0xc);
+	if (write(fd, chip->next_work_req, sizeof(chip->next_work_req)) != sizeof(chip->next_work_req))
+	{
+		rockminer_dead(dev);
+		applogr(false, LOG_ERR, "%"PRIpreprv": Failed to send work", proc->proc_repr);
+	}
+	
+	chip->last_taskid = chip->last_taskid ? 0 : 1;
+	if (chip->works[chip->last_taskid])
+		free_work(chip->works[chip->last_taskid]);
+	chip->works[chip->last_taskid] = work;
+	
+	return true;
+}
+
+static
+void rockminer_queue_flush(__maybe_unused struct thr_info * const thr)
+{
+	
+}
+
+static
+void rockminer_poll(struct thr_info * const master_thr)
+{
+	struct cgpu_info * const dev = master_thr->cgpu;
+	int fd = dev->device_fd;
+	uint8_t reply[ROCKMINER_REPLY_SIZE];
+	ssize_t rsz;
+	
+	if (fd < 0)
+	{
+		fd = serial_open(dev->device_path, 0, 1, true);
+		if (fd < 0)
+		{
+			timer_set_delay_from_now(&master_thr->tv_poll, ROCKMINER_RETRY_US);
+			applogr(, LOG_ERR, "%s: Failed to open %s", dev->dev_repr, dev->device_path);
+		}
+		dev->device_fd = fd;
+		for_each_managed_proc(proc, dev)
+		{
+			struct thr_info * const thr = proc->thr[0];
+			thr->queue_full = false;
+		}
+	}
+	
+	while ( (rsz = read(fd, reply, sizeof(reply))) == sizeof(reply))
+	{
+// 		const uint8_t status = reply[4] >> 4;
+		const enum rockminer_replies cmd = reply[4] & 0xf;
+// 		const uint8_t prodid = reply[5] >> 6;
+		const uint8_t chipid = reply[5] & 0x3f;
+		const uint8_t taskid = reply[6] & 1;
+// 		const uint8_t temp = reply[7];
+		struct cgpu_info * const proc = device_proc_by_id(dev, chipid);
+		if (unlikely(!proc))
+		{
+			applog(LOG_ERR, "%s: Chip id %d out of range", dev->dev_repr, chipid);
+			continue;
+		}
+		struct thr_info * const thr = proc->thr[0];
+		struct rockminer_chip_data * const chip = thr->cgpu_data;
+		
+		switch (cmd) {
+			case ROCKMINER_REPLY_NONCE_FOUND:
+			{
+				const uint32_t nonce = upk_u32be(reply, 0);
+				struct work *work;
+				if (test_nonce(chip->works[taskid], nonce, false))
+				{}
+				else
+				if (test_nonce(chip->works[taskid ? 0 : 1], nonce, false))
+				{
+					applog(LOG_DEBUG, "%"PRIpreprv": We have task ids inverted; fixing", proc->proc_repr);
+					work = chip->works[0];
+					chip->works[0] = chip->works[1];
+					chip->works[1] = work;
+					chip->last_taskid = chip->last_taskid ? 0 : 1;
+				}
+				work = chip->works[taskid];
+				submit_nonce(thr, work, nonce);
+				break;
+			}
+			case ROCKMINER_REPLY_TASK_COMPLETE:
+				hashes_done2(thr, 0x100000000, NULL);
+				break;
+			case ROCKMINER_REPLY_GET_TASK:
+				thr->queue_full = false;
+				break;
+		}
+	}
+	if (rsz < 0)
+		rockminer_dead(dev);
+	
+	timer_set_delay_from_now(&master_thr->tv_poll, ROCKMINER_POLL_US);
+}
+
 struct device_drv rockminer_drv = {
 struct device_drv rockminer_drv = {
 	.dname = "rockminer",
 	.dname = "rockminer",
 	.name = "RKM",
 	.name = "RKM",
+	
 	.lowl_probe = rockminer_lowl_probe,
 	.lowl_probe = rockminer_lowl_probe,
+	
+	.thread_init = rockminer_init,
+	
+	.minerloop = minerloop_queue,
+	.queue_append = rockminer_queue_append,
+	.queue_flush = rockminer_queue_flush,
+	.poll = rockminer_poll,
 };
 };