Browse Source

rockminer: Detection code for new driver

Luke Dashjr 11 years ago
parent
commit
9f0adf6fc0
3 changed files with 218 additions and 0 deletions
  1. 4 0
      Makefile.am
  2. 14 0
      configure.ac
  3. 200 0
      driver-rockminer.c

+ 4 - 0
Makefile.am

@@ -320,6 +320,10 @@ if USE_HASHFAST
 bfgminer_SOURCES += driver-hashfast.c
 endif
 
+if USE_ROCKMINER
+bfgminer_SOURCES += driver-rockminer.c
+endif
+
 if NEED_BFG_LOWL_FTDI
 bfgminer_SOURCES += lowl-ftdi.c lowl-ftdi.h
 endif

+ 14 - 0
configure.ac

@@ -1036,6 +1036,20 @@ fi
 AM_CONDITIONAL([HAS_METABANK], [test x$metabank = xyes])
 
 
+driverlist="$driverlist rockminer"
+AC_ARG_ENABLE([rockminer],
+	[AC_HELP_STRING([--disable-rockminer],[Compile support for RockMiner (default enabled)])],
+	[rockminer=$enableval],
+	[rockminer=$ddyes]
+)
+if test "x$rockminer" = xyes; then
+	AC_DEFINE([USE_ROCKMINER], [1], [Defined to 1 if RockMiner support is wanted])
+	need_lowl_vcom=yes
+	has_asic=yes
+fi
+AM_CONDITIONAL([USE_ROCKMINER], [test x$rockminer = xyes])
+
+
 if test "x$need_lowl_vcom" != "xno"; then
 	# Lowlevel VCOM doesn't need libusb, but it can take advantage of it to reattach drivers
 	if test "x$libusb" != xno; then

+ 200 - 0
driver-rockminer.c

@@ -0,0 +1,200 @@
+/*
+ * Copyright 2014 Luke Dashjr
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "deviceapi.h"
+#include "lowl-vcom.h"
+#include "miner.h"
+
+#define ROCKMINER_MIN_FREQ_MHZ  200
+
+#define ROCKMINER_MAX_CHIPS  64
+#define ROCKMINER_WORK_REQ_SIZE  0x40
+#define ROCKMINER_REPLY_SIZE        8
+
+enum rockminer_replies {
+	ROCKMINER_REPLY_NONCE_FOUND = 0,
+};
+
+BFG_REGISTER_DRIVER(rockminer_drv)
+
+struct rockminer_chip_data {
+	uint8_t next_work_req[ROCKMINER_WORK_REQ_SIZE];
+};
+
+static
+void rockminer_job_buf_init(uint8_t * const buf, const uint8_t chipid)
+{
+	memset(&buf[0x20], 0, 0x10);
+	buf[0x30] = 0xaa;
+	// 0x31 is frequency, filled in elsewhere
+	buf[0x32] = chipid;
+	buf[0x33] = 0x55;
+}
+
+static
+void rockminer_job_buf_set_freq(uint8_t * const buf, const unsigned short freq)
+{
+	buf[0x31] = (freq / 10) - 1;
+}
+
+static const uint8_t golden_midstate[] = {
+	0x4a, 0x54, 0x8f, 0xe4, 0x71, 0xfa, 0x3a, 0x9a,
+	0x13, 0x71, 0x14, 0x45, 0x56, 0xc3, 0xf6, 0x4d,
+	0x25, 0x00, 0xb4, 0x82, 0x60, 0x08, 0xfe, 0x4b,
+	0xbf, 0x76, 0x98, 0xc9, 0x4e, 0xba, 0x79, 0x46,
+};
+
+static const uint8_t golden_datatail[] = {
+	                        0xce, 0x22, 0xa7, 0x2f,
+	0x4f, 0x67, 0x26, 0x14, 0x1a, 0x0b, 0x32, 0x87,
+};
+
+static const uint8_t golden_result[] = {
+	0x00, 0x01, 0x87, 0xa2,
+};
+
+int8_t rockminer_bisect_chips(const int fd, uint8_t * const buf)
+{
+	static const int max_concurrent_tests = 4;
+	int concurrent_tests = max_concurrent_tests;
+	uint8_t tests[max_concurrent_tests];
+	uint8_t reply[ROCKMINER_REPLY_SIZE];
+	uint8_t minvalid = 0, maxvalid = ROCKMINER_MAX_CHIPS - 1;
+	uint8_t pertest;
+	char msg[0x10];
+	ssize_t rsz;
+	
+	do {
+		pertest = (maxvalid + 1 - minvalid) / concurrent_tests;
+		if (!pertest)
+			pertest = 1;
+		msg[0] = '\0';
+		for (int i = 0; i < concurrent_tests; ++i)
+		{
+			uint8_t chipid = (minvalid + pertest * (i + 1)) - 1;
+			if (chipid > maxvalid)
+			{
+				concurrent_tests = i;
+				break;
+			}
+			tests[i] = chipid;
+			
+			buf[0x32] = chipid;
+			if (write(fd, buf, ROCKMINER_WORK_REQ_SIZE) != ROCKMINER_WORK_REQ_SIZE)
+				applogr(-1, LOG_DEBUG, "%s(%d): Error sending request for chip %d", __func__, fd, chipid);
+			
+			tailsprintf(msg, sizeof(msg), "%d ", chipid);
+		}
+		
+		msg[strlen(msg)-1] = '\0';
+		applog(LOG_DEBUG, "%s(%d): Testing chips %s (within range %d-%d)", __func__, fd, msg, minvalid, maxvalid);
+		
+		while ( (rsz = read(fd, reply, sizeof(reply))) == sizeof(reply))
+		{
+			const uint8_t chipid = reply[5] & 0x3f;
+			if (chipid > minvalid)
+			{
+				applog(LOG_DEBUG, "%s(%d): Saw chip %d", __func__, fd, chipid);
+				minvalid = chipid;
+				if (minvalid >= tests[concurrent_tests-1])
+					break;
+			}
+		}
+		
+		for (int i = concurrent_tests; i--; )
+		{
+			if (tests[i] > minvalid)
+			{
+				applog(LOG_DEBUG, "%s(%d): Didn't see chip %d", __func__, fd, tests[i]);
+				maxvalid = tests[i] - 1;
+			}
+			else
+				break;
+		}
+	} while (minvalid != maxvalid);
+	
+	return maxvalid + 1;
+}
+
+static
+bool rockminer_detect_one(const char * const devpath)
+{
+	int fd, chips;
+	uint8_t buf[ROCKMINER_WORK_REQ_SIZE], reply[ROCKMINER_REPLY_SIZE];
+	ssize_t rsz;
+	
+	fd = serial_open(devpath, 0, 1, true);
+	if (fd < 0)
+		return_via_applog(err, , LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Failed to open", devpath);
+	
+	applog(LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Successfully opened", devpath);
+	
+	rockminer_job_buf_init(buf, 0);
+	rockminer_job_buf_set_freq(buf, ROCKMINER_MIN_FREQ_MHZ);
+	memcpy(&buf[   0], golden_midstate, 0x20);
+	memcpy(&buf[0x34], golden_datatail,  0xc);
+	
+	if (write(fd, buf, sizeof(buf)) != sizeof(buf))
+		return_via_applog(err, , LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Error sending request to ", devpath);
+	
+	while (true)
+	{
+		rsz = read(fd, reply, sizeof(reply));
+		if (rsz != sizeof(reply))
+			return_via_applog(err, , LOG_DEBUG, "%s: Short read from %s (%d)", rockminer_drv.dname, devpath, rsz);
+		if ((!memcmp(reply, golden_result, sizeof(golden_result))) && (reply[4] & 0xf) == ROCKMINER_REPLY_NONCE_FOUND)
+			break;
+	}
+	
+	applog(LOG_DEBUG, "%s: Found chip 0 on %s, probing for total chip count", rockminer_drv.dname, devpath);
+	chips = rockminer_bisect_chips(fd, buf);
+	applog(LOG_DEBUG, "%s: Identified %d chips on %s", rockminer_drv.dname, chips, devpath);
+	
+	if (serial_claim_v(devpath, &rockminer_drv))
+		goto err;
+	
+	serial_close(fd);
+	
+	struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
+	*cgpu = (struct cgpu_info){
+		.drv = &rockminer_drv,
+		.device_path = strdup(devpath),
+		.deven = DEV_ENABLED,
+		.procs = chips,
+		.threads = 1,
+	};
+	// NOTE: Xcode's clang has a bug where it cannot find fields inside anonymous unions (more details in fpgautils)
+	cgpu->device_fd = -1;
+	
+	return add_cgpu(cgpu);
+
+err:
+	if (fd >= 0)
+		serial_close(fd);
+	return false;
+}
+
+static
+bool rockminer_lowl_probe(const struct lowlevel_device_info * const info)
+{
+	return vcom_lowl_probe_wrapper(info, rockminer_detect_one);
+}
+
+struct device_drv rockminer_drv = {
+	.dname = "rockminer",
+	.name = "RKM",
+	.lowl_probe = rockminer_lowl_probe,
+};