Browse Source

Merge branch 'titan' into bfgminer

Conflicts:
	.gitmodules
Luke Dashjr 11 years ago
parent
commit
fae30b88dc
17 changed files with 825 additions and 99 deletions
  1. 3 0
      .gitmodules
  2. 6 4
      .travis.yml
  3. 5 1
      Makefile.am
  4. 1 0
      README
  5. 18 1
      README.ASIC
  6. 38 0
      configure.ac
  7. 9 6
      driver-avalon.c
  8. 625 0
      driver-titan.c
  9. 0 82
      hexdump.c
  10. 1 0
      knc-asic
  11. 0 2
      logging.h
  12. 1 0
      make-release
  13. 5 2
      miner.c
  14. 4 0
      miner.h
  15. 80 0
      titan-asic.c
  16. 29 0
      titan-asic.h
  17. 0 1
      tm_i2c.c

+ 3 - 0
.gitmodules

@@ -7,3 +7,6 @@
 [submodule "libbase58"]
 [submodule "libbase58"]
 	path = libbase58
 	path = libbase58
 	url = git://github.com/luke-jr/libbase58.git
 	url = git://github.com/luke-jr/libbase58.git
+[submodule "knc-asic"]
+	path = knc-asic
+	url = git://github.com/KnCMiner/knc-asic

+ 6 - 4
.travis.yml

@@ -16,7 +16,7 @@ matrix:
     - compiler: ": pkgconf"
     - compiler: ": pkgconf"
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev pkgconf' EXTRA_DEPS='libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm libsensors4-dev' BUILD_CFLAGS='-Werror' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-system-libbase58 --enable-tool'
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev pkgconf' EXTRA_DEPS='libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm libsensors4-dev' BUILD_CFLAGS='-Werror' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-system-libbase58 --enable-tool'
     - compiler: ": MinGW64"
     - compiler: ": MinGW64"
-      env: UBUNTU_DEPS='gcc-mingw-w64-x86-64' EXTRA_DEPS='pkg-config yasm' CROSS_BINPKGS='x86_64-w64-mingw32' BUILD_CFLAGS='-Werror' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-system-libbase58 --host=x86_64-w64-mingw32 --disable-knc --disable-bfsb --disable-jingtian --disable-metabank --disable-minergate'
+      env: UBUNTU_DEPS='gcc-mingw-w64-x86-64' EXTRA_DEPS='pkg-config yasm' CROSS_BINPKGS='x86_64-w64-mingw32' BUILD_CFLAGS='-Werror' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-system-libbase58 --host=x86_64-w64-mingw32 --disable-knc --disable-bfsb --disable-jingtian --disable-metabank --disable-minergate --disable-titan'
     - compiler: ": Std SHA2"
     - compiler: ": Std SHA2"
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm libsensors4-dev' CONFIGURE_ARGS=''
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm libsensors4-dev' CONFIGURE_ARGS=''
     - compiler: ": Std scrypt"
     - compiler: ": Std scrypt"
@@ -42,15 +42,15 @@ matrix:
     - compiler: ": No libmicrohttpd"
     - compiler: ": No libmicrohttpd"
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libi2c-dev yasm libsensors4-dev' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-libmicrohttpd'
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libi2c-dev yasm libsensors4-dev' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-libmicrohttpd'
     - compiler: ": No libi2c-dev"
     - compiler: ": No libi2c-dev"
-      env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev yasm libsensors4-dev' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --disable-knc'
+      env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev yasm libsensors4-dev' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --disable-knc --disable-titan'
     - compiler: ": No yasm"
     - compiler: ": No yasm"
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev libsensors4-dev' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt'
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev libsensors4-dev' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt'
     - compiler: ": No libsensors"
     - compiler: ": No libsensors"
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-sensors'
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-sensors'
     - compiler: ": No opt deps"
     - compiler: ": No opt deps"
-      env: myCC='clang' EXTRA_DEPS='pkg-config' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-uio --without-vfio --without-sensors --without-libmicrohttpd --without-libevent --without-libusb --without-curses --without-libudev --disable-knc'
+      env: myCC='clang' EXTRA_DEPS='pkg-config' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-uio --without-vfio --without-sensors --without-libmicrohttpd --without-libevent --without-libusb --without-curses --without-libudev --disable-knc --disable-titan'
     - compiler: ": Only ncurses"
     - compiler: ": Only ncurses"
-      env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-uio --without-vfio --without-sensors --without-libmicrohttpd --without-libevent --without-libusb --without-libudev --disable-knc'
+      env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-uio --without-vfio --without-sensors --without-libmicrohttpd --without-libevent --without-libusb --without-libudev --disable-knc --disable-titan'
     - compiler: ": Only CPU"
     - compiler: ": Only CPU"
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev yasm' CONFIGURE_ARGS='--disable-other-drivers --enable-cpumining --enable-scrypt'
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev yasm' CONFIGURE_ARGS='--disable-other-drivers --enable-cpumining --enable-scrypt'
     - compiler: ": Only OpenCL"
     - compiler: ": Only OpenCL"
@@ -83,6 +83,8 @@ matrix:
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev libusb-1.0-0-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-cointerra'
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev libusb-1.0-0-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-cointerra'
     - compiler: ": Only klondike"
     - compiler: ": Only klondike"
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev libusb-1.0-0-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-klondike'
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev libusb-1.0-0-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-klondike'
+    - compiler: ": Only titan"
+      env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev libi2c-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-scrypt --enable-titan'
     - compiler: ": Only x6500"
     - compiler: ": Only x6500"
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev libusb-1.0-0-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-x6500'
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev libusb-1.0-0-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-x6500'
     - compiler: ": Only ztex"
     - compiler: ": Only ztex"

+ 5 - 1
Makefile.am

@@ -270,7 +270,7 @@ bfgminer_SOURCES += driver-zeusminer.c
 endif
 endif
 
 
 if HAS_AVALON
 if HAS_AVALON
-bfgminer_SOURCES += driver-avalon.c driver-avalon.h hexdump.c
+bfgminer_SOURCES += driver-avalon.c driver-avalon.h
 endif
 endif
 
 
 if USE_AVALONMM
 if USE_AVALONMM
@@ -289,6 +289,10 @@ if HAS_MODMINER
 bfgminer_SOURCES += driver-modminer.c
 bfgminer_SOURCES += driver-modminer.c
 endif
 endif
 
 
+if USE_TITAN
+bfgminer_SOURCES += driver-titan.c titan-asic.c knc-asic/knc-asic.c knc-asic/knc-spimux.c knc-asic/knc-transport-spimux.c titan-asic.h knc-asic/include/knc-asic.h knc-asic/include/knc-transport.h
+endif
+
 if HAS_X6500
 if HAS_X6500
 bfgminer_SOURCES += driver-x6500.c jtag.c jtag.h
 bfgminer_SOURCES += driver-x6500.c jtag.c jtag.h
 endif
 endif

+ 1 - 0
README

@@ -168,6 +168,7 @@ BFGMiner driver configuration options:
 	--enable-opencl         Compile support for OpenCL (default disabled)
 	--enable-opencl         Compile support for OpenCL (default disabled)
 	--disable-adl           Build without ADL monitoring (default enabled)
 	--disable-adl           Build without ADL monitoring (default enabled)
 	--disable-rockminer     Compile support for RockMiner (default enabled)
 	--disable-rockminer     Compile support for RockMiner (default enabled)
+	--enable-titan          Compile support for KnC Titan (default disabled)
 	--disable-twinfury      Compile support for Twinfury USB miner (default
 	--disable-twinfury      Compile support for Twinfury USB miner (default
 	                        enabled)
 	                        enabled)
 	--disable-x6500         Compile support for X6500 (default if libusb)
 	--disable-x6500         Compile support for X6500 (default if libusb)

+ 18 - 1
README.ASIC

@@ -162,7 +162,7 @@ KLONDIKE
 --klondike-options <arg> Set klondike options clock:temptarget
 --klondike-options <arg> Set klondike options clock:temptarget
 
 
 
 
-KNCMINER
+KNCMINER (Jupiter)
 --------
 --------
 
 
 KnCMiner rigs use a BeagleBone Black (BBB) as the host; this is pluged into a
 KnCMiner rigs use a BeagleBone Black (BBB) as the host; this is pluged into a
@@ -206,6 +206,23 @@ make AR=arm-angstrom-linux-gnueabi-ar
 
 
 ---------------END-------------
 ---------------END-------------
 
 
+KNCMINER (Titan)
+--------
+
+Titan uses RaspberryPi as a controller.
+
+Build instructions:
+-----------------Start------------
+
+git clone git@github.com:KnCMiner/bfgminer.git
+cd bfgminer
+./autogen.sh
+./configure --enable-scrypt --enable-titan --disable-other-drivers CFLAGS="-Iuthash/src"
+make
+sudo /etc/init.d/bfgminer.sh restart
+screen -r
+
+---------------END-------------
 
 
 MONARCH
 MONARCH
 -------
 -------

+ 38 - 0
configure.ac

@@ -784,6 +784,44 @@ fi
 AM_CONDITIONAL([HAS_KLONDIKE], [test x$klondike = xyes])
 AM_CONDITIONAL([HAS_KLONDIKE], [test x$klondike = xyes])
 
 
 
 
+driverlist="$driverlist titan"
+AC_ARG_ENABLE([titan],
+	[AC_HELP_STRING([--enable-titan],[Compile support for KnC Titan (default disabled)])],
+	[titan=$enableval],
+	[titan=$ddno]
+	)
+if test "x$titan" != xno && test "x$titan" != xauto; then
+	titan_controller=$titan
+	if test "x$titan" = xyes; then
+		titan_controller=RPI
+	fi
+	titan=yes
+	if test "x$scrypt" = "xno"; then
+		AC_MSG_ERROR([You explicitly enabled KnC Titan, but did not enable scrypt])
+	fi
+	AC_CHECK_HEADERS([linux/i2c-dev-user.h])
+	AC_CHECK_DECL([i2c_smbus_read_word_data],[true],[
+		AC_MSG_ERROR([linux/i2c-dev.h header from i2c-tools/libi2c-dev (NOT linux headers) is required for titan driver])
+	],[
+		#include <stddef.h>
+		#ifdef HAVE_LINUX_I2C_DEV_USER_H
+		#include <linux/i2c-dev-user.h>
+		#else
+		#ifdef NEED_LINUX_I2C_H
+		#include <linux/i2c.h>
+		#endif
+		#include <linux/i2c-dev.h>
+		#endif
+	])
+	AC_DEFINE([USE_TITAN], [1], [Defined to 1 if KnC Titan support is wanted])
+	AC_DEFINE_UNQUOTED([CONTROLLER_BOARD_$titan_controller],[1])
+	AH_TEMPLATE([CONTROLLER_BOARD_BACKPLANE])
+	AH_TEMPLATE([CONTROLLER_BOARD_BBB])
+	AH_TEMPLATE([CONTROLLER_BOARD_RPI])
+fi
+AM_CONDITIONAL([USE_TITAN], [test x$titan = xyes])
+
+
 driverlist="$driverlist x6500"
 driverlist="$driverlist x6500"
 AC_ARG_ENABLE([x6500],
 AC_ARG_ENABLE([x6500],
 	[AC_HELP_STRING([--disable-x6500],[Compile support for X6500 (default if libusb)])],
 	[AC_HELP_STRING([--disable-x6500],[Compile support for X6500 (default if libusb)])],

+ 9 - 6
driver-avalon.c

@@ -200,8 +200,9 @@ static int avalon_send_task(int fd, const struct avalon_task *at,
 	if (at->reset)
 	if (at->reset)
 		nr_len = 1;
 		nr_len = 1;
 	if (opt_debug) {
 	if (opt_debug) {
-		applog(LOG_DEBUG, "Avalon: Sent(%u):", (unsigned int)nr_len);
-		hexdump((uint8_t *)buf, nr_len);
+		char x[(nr_len * 2) + 1];
+		bin2hex(x, buf, nr_len);
+		applog(LOG_DEBUG, "Avalon: Sent(%u): %s", (unsigned int)nr_len, x);
 	}
 	}
 	ret = write(fd, buf, nr_len);
 	ret = write(fd, buf, nr_len);
 	if (unlikely(ret != nr_len))
 	if (unlikely(ret != nr_len))
@@ -290,8 +291,9 @@ static int avalon_get_result(int fd, struct avalon_result *ar,
 
 
 	if (ret == AVA_GETS_OK) {
 	if (ret == AVA_GETS_OK) {
 		if (opt_debug) {
 		if (opt_debug) {
-			applog(LOG_DEBUG, "Avalon: get:");
-			hexdump((uint8_t *)result, AVALON_READ_SIZE);
+			char x[(AVALON_READ_SIZE * 2) + 1];
+			bin2hex(x, result, AVALON_READ_SIZE);
+			applog(LOG_DEBUG, "Avalon: get: %s", x);
 		}
 		}
 		memcpy((uint8_t *)ar, result, AVALON_READ_SIZE);
 		memcpy((uint8_t *)ar, result, AVALON_READ_SIZE);
 	}
 	}
@@ -334,8 +336,9 @@ static void avalon_get_reset(int fd, struct avalon_result *ar)
 	ret = avalon_gets(fd, (uint8_t*)ar, read_count, NULL, NULL);
 	ret = avalon_gets(fd, (uint8_t*)ar, read_count, NULL, NULL);
 	
 	
 	if (ret == AVA_GETS_OK && opt_debug) {
 	if (ret == AVA_GETS_OK && opt_debug) {
-		applog(LOG_DEBUG, "Avalon: get:");
-		hexdump((uint8_t *)ar, AVALON_READ_SIZE);
+		char x[(AVALON_READ_SIZE * 2) + 1];
+		bin2hex(x, ar, AVALON_READ_SIZE);
+		applog(LOG_DEBUG, "Avalon: get: %s", x);
 	}
 	}
 }
 }
 
 

+ 625 - 0
driver-titan.c

@@ -0,0 +1,625 @@
+/*
+ * Copyright 2014 Vitalii Demianets
+ * Copyright 2014 KnCMiner
+ *
+ * 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 <fcntl.h>
+#include <sys/ioctl.h>
+
+#include "deviceapi.h"
+#include "logging.h"
+#include "miner.h"
+#include "util.h"
+
+#include "titan-asic.h"
+
+#define	KNC_TITAN_DEFAULT_FREQUENCY	275
+
+#define KNC_TITAN_HWERR_DISABLE_SECS	10
+
+#define	KNC_POLL_INTERVAL_US		10000
+
+/* Work queue pre-fill level.
+ * Must be high enough to supply all ASICs with works after a flush */
+#define WORK_QUEUE_PREFILL		10
+
+/* Specify here minimum number of leading zeroes in hash */
+#define	DEFAULT_DIFF_FILTERING_ZEROES	24
+#define	DEFAULT_DIFF_FILTERING_FLOAT	(1. / ((double)(0x00000000FFFFFFFF >> DEFAULT_DIFF_FILTERING_ZEROES)))
+#define	DEFAULT_DIFF_HASHES_PER_NONCE	(1 << DEFAULT_DIFF_FILTERING_ZEROES)
+
+BFG_REGISTER_DRIVER(knc_titan_drv)
+
+/* 3 - default number of threads per core */
+static int opt_knc_threads_per_core = 3;
+
+static const struct bfg_set_device_definition knc_titan_set_device_funcs[];
+
+struct knc_titan_core {
+	int asicno;
+	int dieno; /* inside asic */
+	int coreno; /* inside die */
+	struct knc_titan_die *die;
+	struct cgpu_info *proc;
+
+	int hwerr_in_row;
+	int hwerr_disable_time;
+	struct timeval enable_at;
+	struct timeval first_hwerr;
+
+	struct nonce_report last_nonce;
+};
+
+struct knc_titan_die {
+	int asicno;
+	int dieno; /* inside asic */
+	int cores;
+	struct cgpu_info *first_proc;
+
+	int freq;
+};
+
+struct knc_titan_info {
+	void *ctx;
+	struct cgpu_info *cgpu;
+	int cores;
+	struct knc_titan_die dies[KNC_TITAN_MAX_ASICS][KNC_TITAN_DIES_PER_ASIC];
+
+	/* Per-ASIC data */
+	bool need_flush[KNC_TITAN_MAX_ASICS];
+	int next_slot[KNC_TITAN_MAX_ASICS];
+	/* First slot after flush. If next_slot reaches this, then
+	 * we need to re-flush all the cores to avoid duplicating slot numbers
+	 * for different works */
+	int first_slot[KNC_TITAN_MAX_ASICS];
+
+	struct work *workqueue;
+	int workqueue_size;
+	int workqueue_max;
+	int next_id;
+
+	struct work *devicework;
+};
+
+static bool knc_titan_detect_one(const char *devpath)
+{
+	static struct cgpu_info *prev_cgpu = NULL;
+	struct cgpu_info *cgpu;
+	void *ctx;
+	struct knc_titan_info *knc;
+	int cores = 0, asic, die;
+	struct knc_die_info die_info;
+	char repr[6];
+
+	cgpu = malloc(sizeof(*cgpu));
+	if (unlikely(!cgpu))
+		quit(1, "Failed to alloc cgpu_info");
+
+	if (!prev_cgpu) {
+		if (NULL == (ctx = knc_trnsp_new(NULL))) {
+			free(cgpu);
+			return false;
+		}
+
+		knc = calloc(1, sizeof(*knc));
+		if (unlikely(!knc))
+			quit(1, "Failed to alloc knc_titan_info");
+
+		knc->ctx = ctx;
+		knc->cgpu = cgpu;
+		knc->workqueue_max = WORK_QUEUE_PREFILL;
+	} else {
+		knc = prev_cgpu->device_data;
+		ctx = knc->ctx;
+	}
+
+	snprintf(repr, sizeof(repr), "%s %s", knc_titan_drv.name, devpath);
+	asic = atoi(devpath);
+	for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
+		die_info.cores = KNC_TITAN_CORES_PER_DIE; /* core hint */
+		die_info.version = KNC_VERSION_TITAN;
+		if (!knc_titan_get_info(repr, ctx, asic, die, &die_info))
+			continue;
+		if (0 < die_info.cores) {
+			knc->dies[asic][die] = (struct knc_titan_die) {
+				.asicno = asic,
+				.dieno = die,
+				.cores = die_info.cores,
+				.first_proc = cgpu,
+				.freq = KNC_TITAN_DEFAULT_FREQUENCY,
+			};
+			cores += die_info.cores;
+		} else {
+			knc->dies[asic][die] = (struct knc_titan_die) {
+				.asicno = -INT_MAX,
+				.dieno = -INT_MAX,
+				.cores = 0,
+				.first_proc = NULL,
+			};
+		}
+	}
+	if (0 == cores) {
+		free(cgpu);
+		if (!prev_cgpu) {
+			free(knc);
+			knc_trnsp_free(ctx);
+		}
+		return false;
+	}
+
+	applog(LOG_NOTICE, "%s: Found ASIC with %d cores", repr, cores);
+
+	*cgpu = (struct cgpu_info) {
+		.drv = &knc_titan_drv,
+		.device_path = strdup(devpath),
+		.set_device_funcs = knc_titan_set_device_funcs,
+		.deven = DEV_ENABLED,
+		.procs = cores,
+		.threads = prev_cgpu ? 0 : 1,
+		.extra_work_queue = -1,
+		.device_data = knc,
+	};
+	const bool rv = add_cgpu_slave(cgpu, prev_cgpu);
+	if (!prev_cgpu)
+		cgpu->extra_work_queue += WORK_QUEUE_PREFILL;
+	prev_cgpu = cgpu;
+	return rv;
+}
+
+static int knc_titan_detect_auto(void)
+{
+	const int first = 0, last = KNC_TITAN_MAX_ASICS - 1;
+	char devpath[256];
+	int found = 0, i;
+
+	for (i = first; i <= last; ++i) {
+		sprintf(devpath, "%d", i);
+		if (knc_titan_detect_one(devpath))
+			++found;
+	}
+
+	return found;
+}
+
+static void knc_titan_detect(void)
+{
+	generic_detect(&knc_titan_drv, knc_titan_detect_one, knc_titan_detect_auto, GDF_REQUIRE_DNAME | GDF_DEFAULT_NOAUTO);
+}
+
+static void knc_titan_clean_flush(const char *repr, void * const ctx, int asic, int die)
+{
+	struct knc_report report;
+	bool unused;
+	knc_titan_set_work(repr, ctx, asic, die, 0xFFFF, 0, NULL, true, &unused, &report);
+}
+
+static bool knc_titan_init(struct thr_info * const thr)
+{
+	const int max_cores = KNC_TITAN_CORES_PER_ASIC;
+	struct thr_info *mythr;
+	struct cgpu_info * const cgpu = thr->cgpu, *proc;
+	struct knc_titan_core *knccore;
+	struct knc_titan_info *knc;
+	int i, asic, die, core_base;
+	int total_cores = 0;
+	int asic_cores[KNC_TITAN_MAX_ASICS] = {0};
+
+	for (proc = cgpu; proc; ) {
+		proc->min_nonce_diff = DEFAULT_DIFF_FILTERING_FLOAT;
+		if (proc->device != proc) {
+			applog(LOG_WARNING, "%"PRIpreprv": Extra processor?", proc->proc_repr);
+			proc = proc->next_proc;
+			continue;
+		}
+
+		asic = atoi(proc->device_path);
+		knc = proc->device_data;
+
+		die = 0;
+		core_base = 0;
+		for (i = 0; i < max_cores; ++i) {
+			while (i >= (core_base + knc->dies[asic][die].cores)) {
+				core_base += knc->dies[asic][die].cores;
+				if (++die >= KNC_TITAN_DIES_PER_ASIC)
+					break;
+			}
+			if (die >= KNC_TITAN_DIES_PER_ASIC)
+				break;
+
+			mythr = proc->thr[0];
+			mythr->cgpu_data = knccore = malloc(sizeof(*knccore));
+			if (unlikely(!knccore))
+				quit(1, "Failed to alloc knc_titan_core");
+			*knccore = (struct knc_titan_core) {
+				.asicno = asic,
+				.dieno = die,
+				.coreno = i - core_base,
+				.die = &(knc->dies[asic][die]),
+				.proc = proc,
+				.hwerr_in_row = 0,
+				.hwerr_disable_time = KNC_TITAN_HWERR_DISABLE_SECS,
+			};
+			timer_set_now(&knccore->enable_at);
+			proc->device_data = knc;
+			++total_cores;
+			++(asic_cores[asic]);
+			applog(LOG_DEBUG, "%s Allocated core %d:%d:%d", proc->device->dev_repr, asic, die, (i - core_base));
+
+			if (0 == knccore->coreno) {
+				knc->dies[asic][die].first_proc = proc;
+				knc_titan_clean_flush(proc->device->dev_repr, knc->ctx, knccore->asicno, knccore->dieno);
+			}
+
+			proc = proc->next_proc;
+			if ((!proc) || proc->device == proc)
+				break;
+		}
+
+		knc->cores = total_cores;
+	}
+
+	cgpu_set_defaults(cgpu);
+	if (0 >= total_cores)
+		return false;
+
+	/* Init nonce ranges for cores */
+	double nonce_step = 4294967296.0 / total_cores;
+	double nonce_f = 0.0;
+	struct titan_setup_core_params setup_params = {
+		.bad_address_mask = {0, 0},
+		.bad_address_match = {0x3FF, 0x3FF},
+		.difficulty = DEFAULT_DIFF_FILTERING_ZEROES - 1,
+		.thread_enable = 0xFF,
+		.thread_base_address = {0, 1, 2, 3, 4, 5, 6, 7},
+		.lookup_gap_mask = {0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7},
+		.N_mask = {0, 0, 0, 0, 0, 0, 0, 0},
+		.N_shift = {0, 0, 0, 0, 0, 0, 0, 0},
+		.nonce_bottom = 0,
+		.nonce_top = 0xFFFFFFFF,
+	};
+	fill_in_thread_params(opt_knc_threads_per_core, &setup_params);
+
+	int prev_asic = -1;
+	for (proc = cgpu; proc; proc = proc->next_proc) {
+		knc = proc->device_data;
+		mythr = proc->thr[0];
+		knccore = mythr->cgpu_data;
+		if (knccore->asicno != prev_asic) {
+			int numcores = asic_cores[knccore->asicno];
+			if (numcores < 1)
+				numcores = 1;
+			prev_asic = knccore->asicno;
+			nonce_f = 0.0;
+			nonce_step = 4294967296.0 / numcores;
+			setup_params.nonce_top = 0xFFFFFFFF;
+		}
+		nonce_f += nonce_step;
+		setup_params.nonce_bottom = setup_params.nonce_top + 1;
+		if (NULL != proc->next_proc)
+			setup_params.nonce_top = nonce_f;
+		else
+			setup_params.nonce_top = 0xFFFFFFFF;
+		applog(LOG_DEBUG, "%s Setup core %d:%d:%d, nonces 0x%08X - 0x%08X", proc->device->dev_repr, knccore->asicno, knccore->dieno, knccore->coreno, setup_params.nonce_bottom, setup_params.nonce_top);
+		knc_titan_setup_core_local(proc->device->dev_repr, knc->ctx, knccore->asicno, knccore->dieno, knccore->coreno, &setup_params);
+	}
+
+	for (asic = 0; asic < KNC_TITAN_MAX_ASICS; ++asic) {
+		knc->next_slot[asic] = KNC_TITAN_MIN_WORK_SLOT_NUM;
+		knc->first_slot[asic] = KNC_TITAN_MIN_WORK_SLOT_NUM;
+		knc->need_flush[asic] = true;
+	}
+	timer_set_now(&thr->tv_poll);
+
+	return true;
+}
+
+static bool knc_titan_prepare_work(struct thr_info *thr, struct work *work)
+{
+	struct cgpu_info * const cgpu = thr->cgpu;
+
+	work->nonce_diff = cgpu->min_nonce_diff;
+	return true;
+}
+
+static void knc_titan_set_queue_full(struct knc_titan_info * const knc)
+{
+	const bool full = (knc->workqueue_size >= knc->workqueue_max);
+	struct cgpu_info *proc;
+
+	for (proc = knc->cgpu; proc; proc = proc->next_proc) {
+		struct thr_info * const thr = proc->thr[0];
+		thr->queue_full = full;
+	}
+}
+
+static void knc_titan_remove_local_queue(struct knc_titan_info * const knc, struct work * const work)
+{
+	DL_DELETE(knc->workqueue, work);
+	free_work(work);
+	--knc->workqueue_size;
+}
+
+static void knc_titan_prune_local_queue(struct thr_info *thr)
+{
+	struct cgpu_info * const cgpu = thr->cgpu;
+	struct knc_titan_info * const knc = cgpu->device_data;
+	struct work *work, *tmp;
+
+	DL_FOREACH_SAFE(knc->workqueue, work, tmp) {
+		if (stale_work(work, false))
+			knc_titan_remove_local_queue(knc, work);
+	}
+	knc_titan_set_queue_full(knc);
+}
+
+static bool knc_titan_queue_append(struct thr_info * const thr, struct work * const work)
+{
+	struct cgpu_info * const cgpu = thr->cgpu;
+	struct knc_titan_info * const knc = cgpu->device_data;
+
+	if (knc->workqueue_size >= knc->workqueue_max) {
+		knc_titan_prune_local_queue(thr);
+		if (thr->queue_full)
+			return false;
+	}
+
+	DL_APPEND(knc->workqueue, work);
+	++knc->workqueue_size;
+
+	knc_titan_set_queue_full(knc);
+	if (thr->queue_full)
+		knc_titan_prune_local_queue(thr);
+
+	return true;
+}
+
+#define HASH_LAST_ADDED(head, out)  \
+	(out = (head) ? (ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail)) : NULL)
+
+static void knc_titan_queue_flush(struct thr_info * const thr)
+{
+	struct cgpu_info * const cgpu = thr->cgpu;
+	struct knc_titan_info * const knc = cgpu->device_data;
+	struct work *work, *tmp;
+
+	if (knc->cgpu != cgpu)
+		return;
+
+	DL_FOREACH_SAFE(knc->workqueue, work, tmp){
+		knc_titan_remove_local_queue(knc, work);
+	}
+	knc_titan_set_queue_full(knc);
+
+	HASH_LAST_ADDED(knc->devicework, work);
+	if (work && stale_work(work, true)) {
+		int asic;
+		for (asic = 0; asic < KNC_TITAN_MAX_ASICS; ++asic)
+			knc->need_flush[asic] = true;
+		timer_set_now(&thr->tv_poll);
+	}
+}
+
+static void knc_titan_poll(struct thr_info * const thr)
+{
+	struct thr_info *mythr;
+	struct cgpu_info * const cgpu = thr->cgpu, *proc;
+	struct knc_titan_info * const knc = cgpu->device_data;
+	struct knc_titan_core *knccore, *core1;
+	struct work *work, *tmp;
+	int workaccept = 0;
+	unsigned long delay_usecs = KNC_POLL_INTERVAL_US;
+	struct knc_report report;
+	struct knc_die_info die_info;
+	int asic;
+	int die;
+	int i, tmp_int;
+
+	knc_titan_prune_local_queue(thr);
+
+	for (asic = 0; asic < KNC_TITAN_MAX_ASICS; ++asic) {
+		DL_FOREACH_SAFE(knc->workqueue, work, tmp) {
+			bool work_accepted = false;
+			bool need_replace;
+			if (knc->first_slot[asic] > KNC_TITAN_MIN_WORK_SLOT_NUM)
+				need_replace = ((knc->next_slot[asic] + 1) == knc->first_slot[asic]);
+			else
+				need_replace = (knc->next_slot[asic] == KNC_TITAN_MAX_WORK_SLOT_NUM);
+			knccore = NULL;
+			for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
+				if (0 >= knc->dies[asic][die].cores)
+					continue;
+				struct cgpu_info *first_proc = knc->dies[asic][die].first_proc;
+				/* knccore is the core data of the first core in this asic */
+				if (NULL == knccore)
+					knccore = first_proc->thr[0]->cgpu_data;
+				bool die_work_accepted = false;
+				if (knc->need_flush[asic] || need_replace) {
+					for (proc = first_proc; proc; proc = proc->next_proc) {
+						mythr = proc->thr[0];
+						core1 = mythr->cgpu_data;
+						bool unused;
+						if ((core1->dieno != die) || (core1->asicno != asic))
+							break;
+						if (knc_titan_set_work(proc->proc_repr, knc->ctx, asic, die, core1->coreno, knc->next_slot[asic], work, true, &unused, &report)) {
+							core1->last_nonce.slot = report.nonce[0].slot;
+							core1->last_nonce.nonce = report.nonce[0].nonce;
+							die_work_accepted = true;
+						}
+					}
+				} else {
+					if (!knc_titan_set_work(first_proc->dev_repr, knc->ctx, asic, die, 0xFFFF, knc->next_slot[asic], work, false, &die_work_accepted, &report))
+						die_work_accepted = false;
+				}
+				if (die_work_accepted)
+					work_accepted = true;
+			}
+			if ((!work_accepted) || (NULL == knccore))
+				break;
+			bool was_flushed = false;
+			if (knc->need_flush[asic] || need_replace) {
+				struct work *work1, *tmp1;
+				applog(LOG_NOTICE, "%s: Flushing stale works (%s)", knccore->proc->dev_repr,
+				       knc->need_flush[asic] ? "New work" : "Slot collision");
+				knc->need_flush[asic] = false;
+				knc->first_slot[asic] = knc->next_slot[asic];
+				HASH_ITER(hh, knc->devicework, work1, tmp1) {
+					if (asic == ((work1->device_id >> 8) & 0xFF)) {
+						HASH_DEL(knc->devicework, work1);
+						free_work(work1);
+					}
+				}
+				delay_usecs = 0;
+				was_flushed = true;
+			}
+			--knc->workqueue_size;
+			DL_DELETE(knc->workqueue, work);
+			work->device_id = (asic << 8) | knc->next_slot[asic];
+			HASH_ADD(hh, knc->devicework, device_id, sizeof(work->device_id), work);
+			if (++(knc->next_slot[asic]) > KNC_TITAN_MAX_WORK_SLOT_NUM)
+				knc->next_slot[asic] = KNC_TITAN_MIN_WORK_SLOT_NUM;
+			++workaccept;
+			/* If we know for sure that this work was urgent, then we don't need to hurry up
+			 * with filling next slot, we have plenty of time until current work completes.
+			 * So, better to proceed with other ASICs. */
+			if (was_flushed)
+				break;
+		}
+	}
+
+	applog(LOG_DEBUG, "%s: %d jobs accepted to queue (max=%d)", knc_titan_drv.dname, workaccept, knc->workqueue_max);
+
+	for (asic = 0; asic < KNC_TITAN_MAX_ASICS; ++asic) {
+		for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
+			if (0 >= knc->dies[asic][die].cores)
+				continue;
+			die_info.cores = knc->dies[asic][die].cores; /* core hint */
+			die_info.version = KNC_VERSION_TITAN;
+			if (!knc_titan_get_info(cgpu->dev_repr, knc->ctx, asic, die, &die_info))
+				continue;
+			for (proc = knc->dies[asic][die].first_proc; proc; proc = proc->next_proc) {
+				mythr = proc->thr[0];
+				knccore = mythr->cgpu_data;
+				if ((knccore->dieno != die) || (knccore->asicno != asic))
+					break;
+				if (!die_info.has_report[knccore->coreno])
+					continue;
+				if (!knc_titan_get_report(proc->proc_repr, knc->ctx, asic, die, knccore->coreno, &report))
+					continue;
+				for (i = 0; i < KNC_TITAN_NONCES_PER_REPORT; ++i) {
+					if ((report.nonce[i].slot == knccore->last_nonce.slot) &&
+					    (report.nonce[i].nonce == knccore->last_nonce.nonce))
+						break;
+					tmp_int = (asic << 8) | report.nonce[i].slot;
+					HASH_FIND_INT(knc->devicework, &tmp_int, work);
+					if (!work) {
+						applog(LOG_WARNING, "%"PRIpreprv": Got nonce for unknown work in slot %u (asic %d)", proc->proc_repr, (unsigned)report.nonce[i].slot, asic);
+						continue;
+					}
+					if (submit_nonce(mythr, work, report.nonce[i].nonce)) {
+						hashes_done2(mythr, DEFAULT_DIFF_HASHES_PER_NONCE, NULL);
+						knccore->hwerr_in_row = 0;
+					}
+				}
+				knccore->last_nonce.slot = report.nonce[0].slot;
+				knccore->last_nonce.nonce = report.nonce[0].nonce;
+			}
+		}
+	}
+
+	if (workaccept) {
+		if (workaccept >= knc->workqueue_max) {
+			knc->workqueue_max = workaccept;
+			delay_usecs = 0;
+		}
+		knc_titan_set_queue_full(knc);
+	}
+
+	timer_set_delay_from_now(&thr->tv_poll, delay_usecs);
+}
+
+/*
+ * specify settings / options via RPC or command line
+ */
+
+/* support for --set-device
+ * must be set before probing the device
+ */
+static void knc_titan_set_clock_freq(struct cgpu_info * const device, int const val)
+{
+}
+
+static const char *knc_titan_set_clock(struct cgpu_info * const device, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	knc_titan_set_clock_freq(device, atoi(setting));
+	return NULL;
+}
+
+static const struct bfg_set_device_definition knc_titan_set_device_funcs[] = {
+	{ "clock", knc_titan_set_clock, NULL },
+	{ NULL },
+};
+
+/*
+ * specify settings / options via TUI
+ */
+
+#ifdef HAVE_CURSES
+static void knc_titan_tui_wlogprint_choices(struct cgpu_info * const proc)
+{
+	wlogprint("[C]lock speed ");
+}
+
+static const char *knc_titan_tui_handle_choice(struct cgpu_info * const proc, const int input)
+{
+	static char buf[0x100];  /* Static for replies */
+
+	switch (input)
+	{
+		case 'c': case 'C':
+		{
+			sprintf(buf, "Set clock speed");
+			char * const setting = curses_input(buf);
+
+			knc_titan_set_clock_freq(proc->device, atoi(setting));
+
+			return "Clock speed changed\n";
+		}
+	}
+	return NULL;
+}
+
+static void knc_titan_wlogprint_status(struct cgpu_info * const proc)
+{
+	wlogprint("Clock speed: N/A\n");
+}
+#endif
+
+struct device_drv knc_titan_drv =
+{
+	/* metadata */
+	.dname = "titan",
+	.name = "KNC",
+	.supported_algos = POW_SCRYPT,
+	.drv_detect = knc_titan_detect,
+
+	.thread_init = knc_titan_init,
+
+	/* specify mining type - queue */
+	.minerloop = minerloop_queue,
+	.queue_append = knc_titan_queue_append,
+	.queue_flush = knc_titan_queue_flush,
+	.poll = knc_titan_poll,
+	.prepare_work = knc_titan_prepare_work,
+
+	/* TUI support - e.g. setting clock via UI */
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = knc_titan_wlogprint_status,
+	.proc_tui_wlogprint_choices = knc_titan_tui_wlogprint_choices,
+	.proc_tui_handle_choice = knc_titan_tui_handle_choice,
+#endif
+};

+ 0 - 82
hexdump.c

@@ -1,82 +0,0 @@
-/*
- * hexdump implementation without depenecies to *printf()
- * output is equal to 'hexdump -C'
- * should be compatible to 64bit architectures
- *
- * Copyright 2009 Daniel Mack
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include "logging.h"
-
-#define hex_print(p) applog(LOG_DEBUG, "%s", p)
-
-static char nibble[] = {
-	'0', '1', '2', '3', '4', '5', '6', '7',
-	'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
-#define BYTES_PER_LINE 0x10
-
-void hexdump(const void *vp, unsigned int len)
-{
-	const unsigned char *p = vp;
-	unsigned int i, addr;
-	unsigned int wordlen = sizeof(void*);
-	unsigned char v, line[BYTES_PER_LINE * 5];
-
-	for (addr = 0; addr < len; addr += BYTES_PER_LINE) {
-		/* clear line */
-		for (i = 0; i < sizeof(line); i++) {
-			if (i == wordlen * 2 + 52 ||
-			    i == wordlen * 2 + 69) {
-			    	line[i] = '|';
-				continue;
-			}
-
-			if (i == wordlen * 2 + 70) {
-				line[i] = '\0';
-				continue;
-			}
-
-			line[i] = ' ';
-		}
-
-		/* print address */
-		for (i = 0; i < wordlen * 2; i++) {
-			v = addr >> ((wordlen * 2 - i - 1) * 4);
-			line[i] = nibble[v & 0xf];
-		}
-
-		/* dump content */
-		for (i = 0; i < BYTES_PER_LINE; i++) {
-			int pos = (wordlen * 2) + 3 + (i / 8);
-
-			if (addr + i >= len)
-				break;
-
-			v = p[addr + i];
-			line[pos + (i * 3) + 0] = nibble[v >> 4];
-			line[pos + (i * 3) + 1] = nibble[v & 0xf];
-
-			/* character printable? */
-			line[(wordlen * 2) + 53 + i] =
-				(v >= ' ' && v <= '~') ? v : '.';
-		}
-
-		hex_print(line);
-	}
-}

+ 1 - 0
knc-asic

@@ -0,0 +1 @@
+Subproject commit e5c986d3c44fde8c5b069508ef6979f2f2be92d6

+ 0 - 2
logging.h

@@ -173,6 +173,4 @@ extern void _bfg_clean_up(bool);
 
 
 #endif
 #endif
 
 
-extern void hexdump(const void *, unsigned int len);
-
 #endif /* __LOGGING_H__ */
 #endif /* __LOGGING_H__ */

+ 1 - 0
make-release

@@ -48,6 +48,7 @@ git submodule update --init
 		git archive --prefix "$sw/ccan-upstream/" --format tar HEAD ccan/{build_assert,cast,compiler,opt,typesafe_cb} licenses/{CC0,GPL-3,LGPL-2.1}
 		git archive --prefix "$sw/ccan-upstream/" --format tar HEAD ccan/{build_assert,cast,compiler,opt,typesafe_cb} licenses/{CC0,GPL-3,LGPL-2.1}
 	)
 	)
 } | tar -xivp
 } | tar -xivp
+rm -r "$sw"/knc-asic/{*.rbf,*system,waas}
 ./gen-version.sh >"$sw"/version.h
 ./gen-version.sh >"$sw"/version.h
 cd "$sw"
 cd "$sw"
 NOSUBMODULES=1 \
 NOSUBMODULES=1 \

+ 5 - 2
miner.c

@@ -214,6 +214,7 @@ struct cgpu_info **devices_new;
 bool have_opencl;
 bool have_opencl;
 int opt_n_threads = -1;
 int opt_n_threads = -1;
 int mining_threads;
 int mining_threads;
+int base_queue;
 int num_processors;
 int num_processors;
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 bool use_curses = true;
 bool use_curses = true;
@@ -11620,7 +11621,9 @@ void register_device(struct cgpu_info *cgpu)
 
 
 	if (!cgpu->proc_id)
 	if (!cgpu->proc_id)
 		cgpu->device_line_id = device_line_id_count++;
 		cgpu->device_line_id = device_line_id_count++;
-	mining_threads += cgpu->threads ?: 1;
+	int thr_objs = cgpu->threads ?: 1;
+	mining_threads += thr_objs;
+	base_queue += thr_objs + cgpu->extra_work_queue;
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 	adj_width(mining_threads, &dev_width);
 	adj_width(mining_threads, &dev_width);
 #endif
 #endif
@@ -13078,7 +13081,7 @@ begin_bench:
 		cp = current_pool();
 		cp = current_pool();
 
 
 		// Generally, each processor needs a new work, and all at once during work restarts
 		// Generally, each processor needs a new work, and all at once during work restarts
-		max_staged += mining_threads;
+		max_staged += base_queue;
 
 
 		mutex_lock(stgd_lock);
 		mutex_lock(stgd_lock);
 		ts = __total_staged();
 		ts = __total_staged();

+ 4 - 0
miner.h

@@ -28,6 +28,9 @@
 #include <jansson.h>
 #include <jansson.h>
 #include <curl/curl.h>
 #include <curl/curl.h>
 #include <sched.h>
 #include <sched.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
 
 
 #include <blkmaker.h>
 #include <blkmaker.h>
 #include <blktemplate.h>
 #include <blktemplate.h>
@@ -468,6 +471,7 @@ struct cgpu_info {
 	char proc_repr_ns[9];
 	char proc_repr_ns[9];
 	struct cgpu_info *device;
 	struct cgpu_info *device;
 	struct cgpu_info *next_proc;
 	struct cgpu_info *next_proc;
+	int extra_work_queue;
 	
 	
 	const char *device_path;
 	const char *device_path;
 	void *device_data;
 	void *device_data;

+ 80 - 0
titan-asic.c

@@ -0,0 +1,80 @@
+/*
+ * Copyright 2014 Vitalii Demianets
+ * Copyright 2014 KnCMiner
+ *
+ * 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 "miner.h"
+#include "logging.h"
+
+#include "titan-asic.h"
+
+bool knc_titan_get_info(const char *repr, void * const ctx, int channel, int die, struct knc_die_info *die_info)
+{
+	int rc;
+	rc = knc_detect_die(ctx, channel, die, die_info);
+	return (0 == rc);
+}
+
+bool knc_titan_set_work(const char *repr, void * const ctx, int channel, int die, int core, int slot, struct work *work, bool urgent, bool *work_accepted, struct knc_report *report)
+{
+	int request_length = 4 + 1 + 6*4 + 3*4 + 8*4;
+	uint8_t request[request_length];
+	int response_length = 1 + 1 + (1 + 4) * 5;
+	uint8_t response[response_length];
+	int status;
+
+	request_length = knc_prepare_titan_setwork(request, die, core, slot, work, urgent);
+	status = knc_syncronous_transfer(ctx, channel, request_length, request, response_length, response);
+	if (status == KNC_ACCEPTED) {
+		*work_accepted = true;
+	} else {
+		*work_accepted = false;
+		if (response[0] == 0x7f) {
+			applog(LOG_DEBUG, "%s[%d:%d]: Core disabled", repr, channel, die);
+			return false;
+		}
+		if (status & KNC_ERR_MASK) {
+			applog(LOG_ERR, "%s[%d:%d]: Failed to set work state (%x)", repr, channel, die, status);
+			return false;
+		}
+		if (!(status & KNC_ERR_MASK)) {
+			/* !KNC_ERRMASK */
+			applog(LOG_DEBUG, "%s[%d:%d]: Core busy (%x)", repr, channel, die, status);
+		}
+	}
+
+	knc_decode_report(response, report, KNC_VERSION_TITAN);
+	return true;
+}
+
+bool knc_titan_get_report(const char *repr, void * const ctx, int channel, int die, int core, struct knc_report *report)
+{
+	uint8_t request[4];
+	int request_length;
+	int response_length = 1 + 1 + (1 + 4) * 5;
+	uint8_t response[response_length];
+	int status;
+
+	request_length = knc_prepare_report(request, die, core);
+	status = knc_syncronous_transfer(ctx, channel, request_length, request, response_length, response);
+	if (status) {
+		applog(LOG_ERR, "%s[%d:%d]: get_report failed (%x)", repr, channel, die, status);
+		return false;
+	}
+
+	knc_decode_report(response, report, KNC_VERSION_TITAN);
+	return true;
+}
+
+/* This fails if core is hashing!
+ * Stop it before setting up.
+ */
+bool knc_titan_setup_core_local(const char *repr, void * const ctx, int channel, int die, int core, struct titan_setup_core_params *params)
+{
+	return knc_titan_setup_core(ctx, channel, die, core, params);
+}

+ 29 - 0
titan-asic.h

@@ -0,0 +1,29 @@
+#ifndef __TITAN_ASIC_H
+#define __TITAN_ASIC_H
+
+#include "knc-asic/knc-asic.h"
+#include "knc-asic/knc-transport.h"
+
+#define	KNC_TITAN_MAX_ASICS		6
+#define	KNC_TITAN_DIES_PER_ASIC		4
+#define	KNC_TITAN_CORES_PER_DIE		571
+#define	KNC_TITAN_CORES_PER_ASIC	(KNC_TITAN_CORES_PER_DIE * KNC_TITAN_DIES_PER_ASIC)
+#define	KNC_TITAN_WORKSLOTS_PER_CORE	2
+#define	KNC_TITAN_THREADS_PER_CORE	8
+#define	KNC_TITAN_NONCES_PER_REPORT	5
+
+/* Valid slot numbers: 1..15 */
+#define	KNC_TITAN_MIN_WORK_SLOT_NUM	1
+#define	KNC_TITAN_MAX_WORK_SLOT_NUM	15
+
+struct nonce_report {
+	uint32_t nonce;
+	uint8_t slot;
+};
+
+bool knc_titan_get_info(const char *repr, void * const ctx, int channel, int die, struct knc_die_info *die_info);
+bool knc_titan_set_work(const char *repr, void * const ctx, int channel, int die, int core, int slot, struct work *work, bool urgent, bool *work_accepted, struct knc_report *report);
+bool knc_titan_get_report(const char *repr, void * const ctx, int channel, int die, int core, struct knc_report *report);
+bool knc_titan_setup_core_local(const char *repr, void * const ctx, int channel, int die, int core, struct titan_setup_core_params *params);
+
+#endif /* __TITAN_ASIC_H */

+ 0 - 1
tm_i2c.c

@@ -96,7 +96,6 @@ unsigned int tm_i2c_req(int fd, unsigned char addr, unsigned char cmd, unsigned
 		return -1;
 		return -1;
 	}
 	}
 
 
-	//hexdump(buf, 10);
 	ret = (tm->data_msb << 8) + tm->data_lsb;
 	ret = (tm->data_msb << 8) + tm->data_lsb;
 	if (tm->cmd == cmd) return ret;
 	if (tm->cmd == cmd) return ret;
 	return 0;
 	return 0;