|
|
@@ -19,6 +19,8 @@
|
|
|
#include "miner.h"
|
|
|
|
|
|
#define ROCKMINER_MIN_FREQ_MHZ 200
|
|
|
+#define ROCKMINER_POLL_US 0
|
|
|
+#define ROCKMINER_RETRY_US 5000000
|
|
|
|
|
|
#define ROCKMINER_MAX_CHIPS 64
|
|
|
#define ROCKMINER_WORK_REQ_SIZE 0x40
|
|
|
@@ -26,12 +28,16 @@
|
|
|
|
|
|
enum rockminer_replies {
|
|
|
ROCKMINER_REPLY_NONCE_FOUND = 0,
|
|
|
+ ROCKMINER_REPLY_TASK_COMPLETE = 1,
|
|
|
+ ROCKMINER_REPLY_GET_TASK = 2,
|
|
|
};
|
|
|
|
|
|
BFG_REGISTER_DRIVER(rockminer_drv)
|
|
|
|
|
|
struct rockminer_chip_data {
|
|
|
uint8_t next_work_req[ROCKMINER_WORK_REQ_SIZE];
|
|
|
+ struct work *works[2];
|
|
|
+ uint8_t last_taskid;
|
|
|
};
|
|
|
|
|
|
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);
|
|
|
}
|
|
|
|
|
|
+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 = {
|
|
|
.dname = "rockminer",
|
|
|
.name = "RKM",
|
|
|
+
|
|
|
.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,
|
|
|
};
|