From 1ceeb3b76cf4b5fd31162fb7592d5ca50206c9e4 Mon Sep 17 00:00:00 2001 From: Henrik Nordstrom Date: Mon, 27 May 2013 16:27:25 +0200 Subject: [PATCH 01/18] Remove prebuild ccan/opt dependencies these must be rebuilt from source to match target headers --- ccan/opt/helpers.d | 24 ------------------------ ccan/opt/opt.d | 26 -------------------------- ccan/opt/parse.d | 18 ------------------ ccan/opt/usage.d | 22 ---------------------- 4 files changed, 90 deletions(-) delete mode 100644 ccan/opt/helpers.d delete mode 100644 ccan/opt/opt.d delete mode 100644 ccan/opt/parse.d delete mode 100644 ccan/opt/usage.d diff --git a/ccan/opt/helpers.d b/ccan/opt/helpers.d deleted file mode 100644 index 669baaff..00000000 --- a/ccan/opt/helpers.d +++ /dev/null @@ -1,24 +0,0 @@ -ccan/opt/helpers.o: ccan/opt/helpers.c ccan/opt/opt.h \ - ccan/compiler/compiler.h config.h ccan/typesafe_cb/typesafe_cb.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdbool.h \ - /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stddef.h \ - /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/xlocale.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/errno.h \ - /usr/include/bits/errno.h /usr/include/linux/errno.h \ - /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ - /usr/include/asm-generic/errno-base.h /usr/include/stdio.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - ccan/opt/private.h diff --git a/ccan/opt/opt.d b/ccan/opt/opt.d deleted file mode 100644 index 73205643..00000000 --- a/ccan/opt/opt.d +++ /dev/null @@ -1,26 +0,0 @@ -ccan/opt/opt.o: ccan/opt/opt.c ccan/opt/opt.h ccan/compiler/compiler.h \ - config.h ccan/typesafe_cb/typesafe_cb.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdbool.h \ - /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stddef.h \ - /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/xlocale.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/errno.h \ - /usr/include/bits/errno.h /usr/include/linux/errno.h \ - /usr/include/i386-linux-gnu/asm/errno.h /usr/include/asm-generic/errno.h \ - /usr/include/asm-generic/errno-base.h /usr/include/stdio.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/err.h /usr/include/assert.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdint.h \ - /usr/include/stdint.h /usr/include/bits/wchar.h ccan/opt/private.h diff --git a/ccan/opt/parse.d b/ccan/opt/parse.d deleted file mode 100644 index 016ba9e0..00000000 --- a/ccan/opt/parse.d +++ /dev/null @@ -1,18 +0,0 @@ -ccan/opt/parse.o: ccan/opt/parse.c ccan/opt/opt.h \ - ccan/compiler/compiler.h config.h ccan/typesafe_cb/typesafe_cb.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdbool.h \ - /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stddef.h \ - /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/xlocale.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/assert.h \ - ccan/opt/private.h diff --git a/ccan/opt/usage.d b/ccan/opt/usage.d deleted file mode 100644 index 0cacbfd1..00000000 --- a/ccan/opt/usage.d +++ /dev/null @@ -1,22 +0,0 @@ -ccan/opt/usage.o: ccan/opt/usage.c ccan/opt/opt.h \ - ccan/compiler/compiler.h config.h ccan/typesafe_cb/typesafe_cb.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdbool.h \ - /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stddef.h \ - /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/xlocale.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/stdio.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/include/stdint.h \ - /usr/include/stdint.h /usr/include/bits/wchar.h ccan/opt/private.h From 1e51336f9599dde8952c9d38211d5584e4870b1d Mon Sep 17 00:00:00 2001 From: Henrik Nordstrom Date: Sun, 9 Jun 2013 16:35:02 +0200 Subject: [PATCH 02/18] Silence warning if MAX/MIN is already defined --- miner.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/miner.h b/miner.h index bd80883a..73da6b6c 100644 --- a/miner.h +++ b/miner.h @@ -223,8 +223,12 @@ static inline int fsync (int fd) #define semtimedop(SEM, SOPS, VAL, TIMEOUT) semop(SEM, SOPS, VAL) #endif +#ifndef MIN #define MIN(x, y) ((x) > (y) ? (y) : (x)) +#endif +#ifndef MAX #define MAX(x, y) ((x) > (y) ? (x) : (y)) +#endif /* Put avalon last to make it the last device it tries to detect to prevent it * trying to claim same chip but different devices. Adding a device here will From 14d20837b3f2da4fe76f7a933098fd0b6f8e2f28 Mon Sep 17 00:00:00 2001 From: Vitalii Demianets Date: Fri, 9 Aug 2013 10:28:17 +0200 Subject: [PATCH 03/18] 'llround' is more suitable here than 'roundl' --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index f4cb7d6d..e65c0f70 100644 --- a/cgminer.c +++ b/cgminer.c @@ -5110,7 +5110,7 @@ static void hashmeter(int thr_id, struct timeval *diff, local_secs = (double)total_diff.tv_sec + ((double)total_diff.tv_usec / 1000000.0); decay_time(&total_rolling, local_mhashes_done / local_secs, local_secs); - global_hashrate = roundl(total_rolling) * 1000000; + global_hashrate = llround(total_rolling) * 1000000; timersub(&total_tv_end, &total_tv_start, &total_diff); total_secs = (double)total_diff.tv_sec + From 4bc955c004086873e7e5f23b7a209d2250cbe11a Mon Sep 17 00:00:00 2001 From: Henrik Nordstrom Date: Sat, 26 Oct 2013 16:41:28 +0200 Subject: [PATCH 04/18] Fixup jansson & libusb include paths when using separate build directory --- Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0e03d2d1..ef64fb69 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,10 +1,10 @@ ACLOCAL_AMFLAGS = -I m4 -JANSSON_INCLUDES= -I$(top_srcdir)/compat/jansson-2.5/src +JANSSON_INCLUDES= -I$(top_builddir)/compat/jansson-2.5/src -I$(top_srcdir)/compat/jansson-2.5/src if WANT_USBUTILS -USBUTILS_INCLUDES = -I$(top_srcdir)/compat/libusb-1.0/libusb +USBUTILS_INCLUDES = -I$(top_builddir)/compat/libusb-1.0/libusb -I$(top_srcdir)/compat/libusb-1.0/libusb else USBUTILS_INCLUDES = endif From dee0192b8a93af1842b607505ed698583d3bc299 Mon Sep 17 00:00:00 2001 From: Vitalii Demianets Date: Thu, 22 Aug 2013 16:02:02 +0200 Subject: [PATCH 05/18] Improve performance of work generation by optimizing hex2bin and bin2hex sprintf is a very expensive function, do direct translation instead. --- util.c | 50 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/util.c b/util.c index 363c73c4..29661988 100644 --- a/util.c +++ b/util.c @@ -588,10 +588,13 @@ char *get_proxy(char *url, struct pool *pool) void __bin2hex(char *s, const unsigned char *p, size_t len) { int i; + static const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - for (i = 0; i < (int)len; i++) - sprintf(s + (i * 2), "%02x", (unsigned int)p[i]); - + for (i = 0; i < (int)len; i++) { + *s++ = hex[p[i] >> 4]; + *s++ = hex[p[i] & 0xF]; + } + *s++ = '\0'; } /* Returns a malloced array string of a binary value of arbitrary length. The @@ -615,33 +618,48 @@ char *bin2hex(const unsigned char *p, size_t len) } /* Does the reverse of bin2hex but does not allocate any ram */ +static const int hex2bin_tbl[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; bool hex2bin(unsigned char *p, const char *hexstr, size_t len) { + int nibble1, nibble2; + unsigned char idx; bool ret = false; while (*hexstr && len) { - char hex_byte[4]; - unsigned int v; - if (unlikely(!hexstr[1])) { applog(LOG_ERR, "hex2bin str truncated"); return ret; } - memset(hex_byte, 0, 4); - hex_byte[0] = hexstr[0]; - hex_byte[1] = hexstr[1]; + idx = *hexstr++; + nibble1 = hex2bin_tbl[idx]; + idx = *hexstr++; + nibble2 = hex2bin_tbl[idx]; - if (unlikely(sscanf(hex_byte, "%x", &v) != 1)) { - applog(LOG_INFO, "hex2bin sscanf '%s' failed", hex_byte); + if (unlikely((nibble1 < 0) || (nibble2 < 0))) { + applog(LOG_ERR, "hex2bin scan failed"); return ret; } - *p = (unsigned char) v; - - p++; - hexstr += 2; - len--; + *p++ = (((unsigned char)nibble1) << 4) | ((unsigned char)nibble2); + --len; } if (likely(len == 0 && *hexstr == 0)) From 53570ae8a06f63dce2096d48829a5cc2829ea759 Mon Sep 17 00:00:00 2001 From: Vitalii Demianets Date: Wed, 2 Oct 2013 03:49:47 +0200 Subject: [PATCH 06/18] KnC driver: knc-spi-fpga ASIC driver This driver talks to KnCMiner controller via SPI Protocol specification is available at https://github.com/KnCMiner/jupiter-hw-docs/blob/master/fpga_spi.md --- Makefile.am | 4 + cgminer.c | 3 + configure.ac | 21 +- driver-knc-spi-fpga.c | 698 ++++++++++++++++++++++++++++++++++++++++++ miner.h | 4 + 5 files changed, 728 insertions(+), 2 deletions(-) create mode 100644 driver-knc-spi-fpga.c diff --git a/Makefile.am b/Makefile.am index ef64fb69..3dc0d4f7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,6 +68,10 @@ if WANT_USBUTILS cgminer_SOURCES += usbutils.c usbutils.h endif +if HAS_KNC +cgminer_SOURCES += driver-knc-spi-fpga.c +endif + if HAS_BFLSC cgminer_SOURCES += driver-bflsc.c driver-bflsc.h endif diff --git a/cgminer.c b/cgminer.c index e65c0f70..62d37187 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1594,6 +1594,9 @@ extern const char *opt_argv0; static char *opt_verusage_and_exit(const char *extra) { printf("%s\nBuilt with " +#ifdef USE_KNC + "KnC " +#endif #ifdef USE_AVALON "avalon " #endif diff --git a/configure.ac b/configure.ac index bc4fbaf7..844e5225 100644 --- a/configure.ac +++ b/configure.ac @@ -221,6 +221,17 @@ fi AM_CONDITIONAL([HAS_SCRYPT], [test x$scrypt = xyes]) +knc="no" + +AC_ARG_ENABLE([knc], + [AC_HELP_STRING([--enable-knc],[Compile support for KnC miners (default disabled)])], + [knc=$enableval] + ) +if test "x$knc" = xyes; then + AC_DEFINE([USE_KNC], [1], [Defined to 1 if KnC miner support is wanted]) +fi +AM_CONDITIONAL([HAS_KNC], [test x$knc = xyes]) + bflsc="no" AC_ARG_ENABLE([bflsc], @@ -515,14 +526,14 @@ if test "x$opencl" != xno; then else echo " OpenCL...............: NOT FOUND. GPU mining support DISABLED" - if test "x$avalon$bitforce$bitfury$icarus$modminer$bflsc$klondike" = xnonononononono; then + if test "x$avalon$bitforce$bitfury$icarus$modminer$bflsc$klondike$knc" = xnononononononono; then AC_MSG_ERROR([No mining configured in]) fi echo " scrypt...............: Disabled (needs OpenCL)" fi else echo " OpenCL...............: Detection overrided. GPU mining support DISABLED" - if test "x$avalon$bitforce$bitfury$icarus$modminer$bflsc$klondike" = xnonononononono; then + if test "x$avalon$bitforce$bitfury$icarus$modminer$bflsc$klondike$knc" = xnononononononono; then AC_MSG_ERROR([No mining configured in]) fi echo " scrypt...............: Disabled (needs OpenCL)" @@ -551,6 +562,12 @@ else echo " BFL.ASICs............: Disabled" fi +if test "x$knc" = xyes; then + echo " KnC.miners...........: Enabled" +else + echo " KnC.miners...........: Disabled" +fi + if test "x$bitforce" = xyes; then echo " BitForce.FPGAs.......: Enabled" else diff --git a/driver-knc-spi-fpga.c b/driver-knc-spi-fpga.c new file mode 100644 index 00000000..00a711f4 --- /dev/null +++ b/driver-knc-spi-fpga.c @@ -0,0 +1,698 @@ +/* cgminer driver for KnCminer Jupiter */ + +#include +#include +#include +#include +#include +#include +#include + +#include "logging.h" +#include "miner.h" + +#define MAX_SPIS 1 +#define MAX_BYTES_IN_SPI_XSFER 4096 +/* /dev/spidevB.C, where B = bus, C = chipselect */ +#define SPI_DEVICE_TEMPLATE "/dev/spidev%d.%d" +#define SPI_MODE (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH) +#define SPI_BITS_PER_WORD 32 +#define SPI_MAX_SPEED 3000000 +#define SPI_DELAY_USECS 0 +/* Max number of ASICs permitted on one SPI device */ +#define MAX_ASICS 6 + +/* How many hardware errors in a row before disabling the core */ +#define HW_ERR_LIMIT 10 + +#define MAX_ACTIVE_WORKS (192 * 2 * 6 * 2) + +#define WORK_MIDSTATE_WORDS 8 +#define WORK_DATA_WORDS 3 + +#define WORK_STALE_US 60000000 + +/* Keep core disabled for no longer than 15 minutes */ +#define CORE_DISA_PERIOD_US (15 * 60 * 1000000) + +struct spidev_context { + int fd; + uint32_t speed; + uint16_t delay; + uint8_t mode; + uint8_t bits; +}; + +struct spi_request { +#define CMD_NOP 0 +#define CMD_GET_VERSION 1 +#define CMD_SUBMIT_WORK 2 +#define CMD_FLUSH_QUEUE 3 + +#define WORK_ID_MASK 0x7FFF + +#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + uint32_t cmd :4; + uint32_t rsvd :1; /* set to zero */ + uint32_t queue_id :12; + uint32_t work_id :15; +#else + uint32_t work_id :15; + uint32_t queue_id :12; + uint32_t rsvd :1; /* set to zero */ + uint32_t cmd :4; +#endif + uint32_t midstate[WORK_MIDSTATE_WORDS]; + uint32_t data[WORK_DATA_WORDS]; +}; + +struct spi_response { +#define RESPONSE_TYPE_NOP 0 +#define RESPONSE_TYPE_NONCE_FOUND 1 +#define RESPONSE_TYPE_WORK_DONE 2 +#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + uint32_t type :2; + uint32_t asic :3; + uint32_t queue_id :12; + uint32_t work_id :15; +#else + uint32_t work_id :15; + uint32_t queue_id :12; + uint32_t asic :3; + uint32_t type :2; +#endif + uint32_t nonce; + uint32_t core; +}; + +#define MAX_REQUESTS_IN_BATCH ( MAX_BYTES_IN_SPI_XSFER / \ + sizeof(struct spi_request) \ + ) + +static struct spi_request spi_txbuf[MAX_REQUESTS_IN_BATCH]; + +#define MAX_RESPONSES_IN_BATCH ( (sizeof(spi_txbuf) - 12) / \ + sizeof(struct spi_response) \ + ) + +struct spi_rx_t { +#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + uint32_t rsvd_1 :31; + uint32_t response_queue_full :1; +#else + uint32_t response_queue_full :1; + uint32_t rsvd_1 :31; +#endif +#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + uint32_t rsvd_2 :16; + uint32_t works_accepted :16; +#else + uint32_t works_accepted :16; + uint32_t rsvd_2 :16; +#endif + uint32_t rsvd_3; + struct spi_response responses[MAX_RESPONSES_IN_BATCH]; +}; +static struct spi_rx_t spi_rxbuf; + +struct device_drv knc_drv; +struct active_work { + struct work *work; + uint32_t work_id; + struct timeval begin; +}; + +struct core_disa_data { + struct timeval disa_begin; + uint8_t asic; + uint8_t core; +}; + +struct knc_state { + struct spidev_context *ctx; + int devices; + uint32_t salt; + uint32_t next_work_id; + + /* read - last read item, next is at (read + 1) mod BUFSIZE + * write - next write item, last written at (write - 1) mod BUFSIZE + * When buffer is empty, read + 1 == write + * Buffer full condition: read == write + */ + int read_q, write_q; +#define KNC_QUEUED_BUFFER_SIZE (MAX_REQUESTS_IN_BATCH + 1) + struct active_work queued_fifo[KNC_QUEUED_BUFFER_SIZE]; + + int read_a, write_a; +#define KNC_ACTIVE_BUFFER_SIZE (MAX_ACTIVE_WORKS + 1) + struct active_work active_fifo[KNC_ACTIVE_BUFFER_SIZE]; + + uint8_t hwerrs[MAX_ASICS * 256]; + int read_d, write_d; +#define KNC_DISA_CORES_SIZE (MAX_ASICS * 256) + struct core_disa_data disa_cores_fifo[KNC_DISA_CORES_SIZE]; +}; + +static inline bool knc_queued_fifo_full(struct knc_state *knc) +{ + return (knc->read_q == knc->write_q); +} + +static inline bool knc_active_fifo_full(struct knc_state *knc) +{ + return (knc->read_a == knc->write_a); +} + +static inline void knc_queued_fifo_inc_idx(int *idx) +{ + if (unlikely(*idx >= (KNC_QUEUED_BUFFER_SIZE - 1))) + *idx = 0; + else + ++(*idx); +} + +static inline void knc_active_fifo_inc_idx(int *idx) +{ + if (unlikely(*idx >= (KNC_ACTIVE_BUFFER_SIZE - 1))) + *idx = 0; + else + ++(*idx); +} + +static inline void knc_disa_cores_fifo_inc_idx(int *idx) +{ + if (unlikely(*idx >= (KNC_DISA_CORES_SIZE - 1))) + *idx = 0; + else + ++(*idx); +} + +/* Find SPI device with index idx, init it */ +static struct spidev_context * spi_new(int idx) +{ + struct spidev_context *ctx; + char dev_fname[PATH_MAX]; + + if(NULL == (ctx = malloc(sizeof(struct spidev_context)))) { + applog(LOG_ERR, "KnC spi: Out of memory"); + goto l_exit_error; + } + ctx->mode = SPI_MODE; + ctx->bits = SPI_BITS_PER_WORD; + ctx->speed = SPI_MAX_SPEED; + ctx->delay = SPI_DELAY_USECS; + + ctx->fd = -1; + + sprintf(dev_fname, SPI_DEVICE_TEMPLATE, + idx, /* bus */ + 0 /* chipselect */ + ); + if (0 > (ctx->fd = open(dev_fname, O_RDWR))) { + applog(LOG_ERR, "KnC spi: Can not open SPI device %s: %m", + dev_fname); + goto l_free_exit_error; + } + + /* + * spi mode + */ + if (0 > ioctl(ctx->fd, SPI_IOC_WR_MODE, &ctx->mode)) + goto l_ioctl_error; + if (0 > ioctl(ctx->fd, SPI_IOC_RD_MODE, &ctx->mode)) + goto l_ioctl_error; + + /* + * bits per word + */ + if (0 > ioctl(ctx->fd, SPI_IOC_WR_BITS_PER_WORD, &ctx->bits)) + goto l_ioctl_error; + if (0 > ioctl(ctx->fd, SPI_IOC_RD_BITS_PER_WORD, &ctx->bits)) + goto l_ioctl_error; + + /* + * max speed hz + */ + if (0 > ioctl(ctx->fd, SPI_IOC_WR_MAX_SPEED_HZ, &ctx->speed)) + goto l_ioctl_error; + if (0 > ioctl(ctx->fd, SPI_IOC_RD_MAX_SPEED_HZ, &ctx->speed)) + goto l_ioctl_error; + + applog(LOG_INFO, "KnC spi: device %s uses mode %hhu, bits %hhu, speed %u", + dev_fname, ctx->mode, ctx->bits, ctx->speed); + + return ctx; + +l_ioctl_error: + applog(LOG_ERR, "KnC spi: ioctl error on SPI device %s: %m", dev_fname); +l_close_free_exit_error: + close(ctx->fd); +l_free_exit_error: + free(ctx); +l_exit_error: + return NULL; +} + +static void spi_free(struct spidev_context *ctx) +{ + if (NULL == ctx) + return; + close(ctx->fd); + free(ctx); +} + +static int spi_transfer(struct spidev_context *ctx, uint8_t *txbuf, + uint8_t *rxbuf, int len) +{ + int ret; + struct spi_ioc_transfer xfr; + + memset(rxbuf, 0xff, len); + + ret = len; + + xfr.tx_buf = (unsigned long)txbuf; + xfr.rx_buf = (unsigned long)rxbuf; + xfr.len = len; + xfr.speed_hz = ctx->speed; + xfr.delay_usecs = ctx->delay; + xfr.bits_per_word = ctx->bits; + xfr.cs_change = 0; + xfr.pad = 0; + + if (1 > (ret = ioctl(ctx->fd, SPI_IOC_MESSAGE(1), &xfr))) { + applog(LOG_ERR, "KnC spi xfer: ioctl error on SPI device: %m"); + } + + return ret; +} + +static void disable_core(uint8_t asic, uint8_t core) +{ + char str[256]; + snprintf(str, sizeof(str), "i2cset -y 2 0x2%hhu %hhu 0", asic, core); + if (0 != WEXITSTATUS(system(str))) + applog(LOG_ERR, "KnC: system call failed"); +} + +static void enable_core(uint8_t asic, uint8_t core) +{ + char str[256]; + snprintf(str, sizeof(str), "i2cset -y 2 0x2%hhu %hhu 1", asic, core); + if (0 != WEXITSTATUS(system(str))) + applog(LOG_ERR, "KnC: system call failed"); +} + +static int64_t timediff(const struct timeval *a, const struct timeval *b) +{ + struct timeval diff; + timersub(a, b, &diff); + return diff.tv_sec * 1000000 + diff.tv_usec; +} + +static void knc_check_disabled_cores(struct knc_state *knc) +{ + int next_read_d; + struct timeval now; + int64_t us; + struct core_disa_data *core; + int cidx; + + next_read_d = knc->read_d; + knc_disa_cores_fifo_inc_idx(&next_read_d); + if (next_read_d == knc->write_d) + return; /* queue empty */ + core = &knc->disa_cores_fifo[next_read_d]; + gettimeofday(&now, NULL); + us = timediff(&now, &core->disa_begin); + if ((us >= 0) && (us < CORE_DISA_PERIOD_US)) + return; /* latest disabled core still not expired */ + cidx = core->asic * 256 + core->core; + enable_core(core->asic, core->core); + knc->hwerrs[cidx] = 0; + applog(LOG_NOTICE, + "KnC: core %u-%u was enabled back from disabled state", + core->asic, core->core); + knc->read_d = next_read_d; +} + +static void knc_work_from_queue_to_spi(struct knc_state *knc, + struct active_work *q_work, + struct spi_request *spi_req) +{ + uint32_t *buf_from, *buf_to; + int i; + + spi_req->cmd = CMD_SUBMIT_WORK; + spi_req->queue_id = 0; /* at the moment we have one and only queue #0 */ + spi_req->work_id = (knc->next_work_id ^ knc->salt) & WORK_ID_MASK; + q_work->work_id = spi_req->work_id; + ++(knc->next_work_id); + buf_to = spi_req->midstate; + buf_from = (uint32_t *)q_work->work->midstate; + for (i = 0; i < WORK_MIDSTATE_WORDS; ++i) + buf_to[i] = le32toh(buf_from[8 - i - 1]); + buf_to = spi_req->data; + buf_from = (uint32_t *)&(q_work->work->data[16 * 4]); + for (i = 0; i < WORK_DATA_WORDS; ++i) + buf_to[i] = le32toh(buf_from[3 - i - 1]); +} + +static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu, + struct spi_rx_t *rxbuf, int num) +{ + struct knc_state *knc = cgpu->knc_state; + struct work *work; + int64_t us; + int works, submitted, completed, i, num_sent; + int next_read_q, next_read_a; + struct timeval now; + + if (knc->write_q > knc->read_q) + num_sent = knc->write_q - knc->read_q - 1; + else + num_sent = + knc->write_q + KNC_QUEUED_BUFFER_SIZE - knc->read_q - 1; + + /* Actually process SPI response */ + if (rxbuf->works_accepted) { + applog(LOG_DEBUG, "KnC spi: raw response %08X %08X", + ((uint32_t *)rxbuf)[0], ((uint32_t *)rxbuf)[1]); + applog(LOG_DEBUG, + "KnC spi: response, accepted %u (from %u), full %u", + rxbuf->works_accepted, num_sent, + rxbuf->response_queue_full); + } + /* move works_accepted number of items from queued_fifo to active_fifo */ + gettimeofday(&now, NULL); + submitted = 0; + for (i = 0; i < rxbuf->works_accepted; ++i) { + next_read_q = knc->read_q; + knc_queued_fifo_inc_idx(&next_read_q); + if ((next_read_q == knc->write_q) || knc_active_fifo_full(knc)) + break; + memcpy(&knc->active_fifo[knc->write_a], + &knc->queued_fifo[next_read_q], + sizeof(struct active_work)); + knc->active_fifo[knc->write_a].begin = now; + knc->queued_fifo[next_read_q].work = NULL; + knc->read_q = next_read_q; + knc_active_fifo_inc_idx(&knc->write_a); + ++submitted; + } + if (submitted != rxbuf->works_accepted) + applog(LOG_ERR, + "KnC: accepted by FPGA %u works, but only %d submitted", + rxbuf->works_accepted, submitted); + + /* check for completed works and calculated nonces */ + gettimeofday(&now, NULL); + completed = 0; + for (i = 0; i < MAX_RESPONSES_IN_BATCH; ++i) + { + if ( (rxbuf->responses[i].type != RESPONSE_TYPE_NONCE_FOUND) && + (rxbuf->responses[i].type != RESPONSE_TYPE_WORK_DONE) + ) + continue; + applog(LOG_DEBUG, "KnC spi: raw response %08X %08X", + ((uint32_t *)&rxbuf->responses[i])[0], + ((uint32_t *)&rxbuf->responses[i])[1]); + applog(LOG_DEBUG, "KnC spi: response, T:%u C:%u-%u Q:%u W:%u", + rxbuf->responses[i].type, + rxbuf->responses[i].asic, rxbuf->responses[i].core, + rxbuf->responses[i].queue_id, + rxbuf->responses[i].work_id); + /* Find active work with matching ID */ + next_read_a = knc->read_a; + knc_active_fifo_inc_idx(&next_read_a); + while (next_read_a != knc->write_a) { + if (knc->active_fifo[next_read_a].work_id == + rxbuf->responses[i].work_id) + break; + + /* check for stale works */ + us = timediff(&now, + &knc->active_fifo[next_read_a].begin); + if ((us < 0) || (us >= WORK_STALE_US)) { + applog(LOG_DEBUG, + "KnC spi: remove stale work %u", + knc->active_fifo[next_read_a].work_id); + work = knc->active_fifo[next_read_a].work; + knc_active_fifo_inc_idx(&knc->read_a); + work_completed(cgpu, work); + if (next_read_a != knc->read_a) + memcpy(&(knc->active_fifo[next_read_a]), + &(knc->active_fifo[knc->read_a]), + sizeof(struct active_work)); + knc->active_fifo[knc->read_a].work = NULL; + } + + knc_active_fifo_inc_idx(&next_read_a); + } + if (next_read_a == knc->write_a) + continue; + applog(LOG_DEBUG, "KnC spi: response work %u found", + rxbuf->responses[i].work_id); + work = knc->active_fifo[next_read_a].work; + + if (rxbuf->responses[i].type == RESPONSE_TYPE_NONCE_FOUND) { + if (NULL != thr) { + int cidx = rxbuf->responses[i].asic * 256 + + rxbuf->responses[i].core; + if (submit_nonce(thr, work, + rxbuf->responses[i].nonce)) { + if (cidx < sizeof(knc->hwerrs)) + knc->hwerrs[cidx] = 0; + } else { + if (cidx < sizeof(knc->hwerrs)) { + if (++(knc->hwerrs[cidx]) >= HW_ERR_LIMIT) { + struct core_disa_data *core; + core = &knc->disa_cores_fifo[knc->write_d]; + core->disa_begin = now; + core->asic = rxbuf->responses[i].asic; + core->core = rxbuf->responses[i].core; + disable_core(core->asic, core->core); + applog(LOG_WARNING, + "KnC: core %u-%u was disabled due to %u HW errors in a row", + core->asic, core->core, HW_ERR_LIMIT); + knc_disa_cores_fifo_inc_idx(&knc->write_d); + } + } + }; + } + continue; + } + + /* Work completed */ + knc_active_fifo_inc_idx(&knc->read_a); + work_completed(cgpu, work); + if (next_read_a != knc->read_a) + memcpy(&(knc->active_fifo[next_read_a]), + &(knc->active_fifo[knc->read_a]), + sizeof(struct active_work)); + knc->active_fifo[knc->read_a].work = NULL; + ++completed; + } + + return ((uint64_t)completed) * 0x100000000UL; +} + +/* Send flush command via SPI */ +static int _internal_knc_flush_fpga(struct knc_state *knc) +{ + int len; + + spi_txbuf[0].cmd = CMD_FLUSH_QUEUE; + spi_txbuf[0].queue_id = 0; /* at the moment we have one and only queue #0 */ + len = spi_transfer(knc->ctx, (uint8_t *)spi_txbuf, + (uint8_t *)&spi_rxbuf, sizeof(struct spi_request)); + if (len != sizeof(struct spi_request)) + return -1; + len /= sizeof(struct spi_response); + + return len; +} + +static bool knc_detect_one(struct spidev_context *ctx) +{ + /* Scan device for ASICs */ + int chip_id; + int devices = 0; + + for (chip_id = 0; chip_id < MAX_ASICS; ++chip_id) { + /* TODO: perform the ASIC test/detection */ + ++devices; + } + + if (!devices) { + applog(LOG_INFO, "SPI detected, but not KnCminer ASICs"); + return false; + } + applog(LOG_INFO, "Found a KnC miner with %d ASICs", devices); + + struct cgpu_info *cgpu = calloc(1, sizeof(*cgpu)); + struct knc_state *knc = calloc(1, sizeof(*knc)); + if (!cgpu || !knc) { + applog(LOG_ERR, "KnC miner detected, but failed to allocate memory"); + return false; + } + + knc->ctx = ctx; + knc->devices = devices; + knc->read_q = 0; + knc->write_q = 1; + knc->read_a = 0; + knc->write_a = 1; + knc->read_d = 0; + knc->write_d = 1; + knc->salt = rand(); + + _internal_knc_flush_fpga(knc); + + cgpu->drv = &knc_drv; + cgpu->name = "KnCminer"; + cgpu->threads = 1; // .. perhaps our number of devices? + + cgpu->knc_state = knc; + add_cgpu(cgpu); + + return true; +} + +// http://www.concentric.net/~Ttwang/tech/inthash.htm +static unsigned long mix(unsigned long a, unsigned long b, unsigned long c) +{ + a=a-b; a=a-c; a=a^(c >> 13); + b=b-c; b=b-a; b=b^(a << 8); + c=c-a; c=c-b; c=c^(b >> 13); + a=a-b; a=a-c; a=a^(c >> 12); + b=b-c; b=b-a; b=b^(a << 16); + c=c-a; c=c-b; c=c^(b >> 5); + a=a-b; a=a-c; a=a^(c >> 3); + b=b-c; b=b-a; b=b^(a << 10); + c=c-a; c=c-b; c=c^(b >> 15); + return c; +} + +/* Probe devices and register with add_cgpu */ +void knc_detect(bool __maybe_unused hotplug) +{ + int idx; + + srand(mix(clock(), time(NULL), getpid())); + + /* Loop through all possible SPI interfaces */ + for (idx = 0; idx < MAX_SPIS; ++idx) { + struct spidev_context *ctx = spi_new(idx + 1); + if (ctx != NULL) { + if (!knc_detect_one(ctx)) + spi_free(ctx); + } + } +} + +/* return value is number of nonces that have been checked since + * previous call + */ +static int64_t knc_scanwork(struct thr_info *thr) +{ + struct cgpu_info *cgpu = thr->cgpu; + struct knc_state *knc = cgpu->knc_state; + int len, num; + int next_read_q; + + applog(LOG_DEBUG, "KnC running scanwork"); + + knc_check_disabled_cores(knc); + + /* Prepare tx buffer */ + memset(spi_txbuf, 0, sizeof(spi_txbuf)); + num = 0; + next_read_q = knc->read_q; + knc_queued_fifo_inc_idx(&next_read_q); + while (next_read_q != knc->write_q) { + knc_work_from_queue_to_spi(knc, &knc->queued_fifo[next_read_q], + &spi_txbuf[num]); + knc_queued_fifo_inc_idx(&next_read_q); + ++num; + } + /* knc->read_q is advanced in knc_process_response, not here */ + + len = spi_transfer(knc->ctx, (uint8_t *)spi_txbuf, + (uint8_t *)&spi_rxbuf, sizeof(spi_txbuf)); + if (len != sizeof(spi_rxbuf)) + return -1; + len /= sizeof(struct spi_response); + + applog(LOG_DEBUG, "KnC spi: %d works in request", num); + + return knc_process_response(thr, cgpu, &spi_rxbuf, len); +} + +static bool knc_queue_full(struct cgpu_info *cgpu) +{ + struct knc_state *knc = cgpu->knc_state; + struct work *work; + int queue_full = true; + + applog(LOG_DEBUG, "KnC running queue full"); + while (!knc_queued_fifo_full(knc)) { + work = get_queued(cgpu); + if (!work) { + queue_full = false; + break; + } + knc->queued_fifo[knc->write_q].work = work; + knc_queued_fifo_inc_idx(&(knc->write_q)); + } + + return queue_full; +} + +static void knc_flush_work(struct cgpu_info *cgpu) +{ + struct knc_state *knc = cgpu->knc_state; + struct work *work; + int len; + int next_read_q, next_read_a; + + applog(LOG_ERR, "KnC running flushwork"); + + /* Drain queued works */ + next_read_q = knc->read_q; + knc_queued_fifo_inc_idx(&next_read_q); + while (next_read_q != knc->write_q) { + work = knc->queued_fifo[next_read_q].work; + work_completed(cgpu, work); + knc->queued_fifo[next_read_q].work = NULL; + knc->read_q = next_read_q; + knc_queued_fifo_inc_idx(&next_read_q); + } + + /* Drain active works */ + next_read_a = knc->read_a; + knc_active_fifo_inc_idx(&next_read_a); + while (next_read_a != knc->write_a) { + work = knc->active_fifo[next_read_a].work; + work_completed(cgpu, work); + knc->active_fifo[next_read_a].work = NULL; + knc->read_a = next_read_a; + knc_active_fifo_inc_idx(&next_read_a); + } + + len = _internal_knc_flush_fpga(knc); + if (len > 0) + knc_process_response(NULL, cgpu, &spi_rxbuf, len); +} + +struct device_drv knc_drv = { + .drv_id = DRIVER_knc, + .dname = "KnCminer", + .name = "KnC", + .drv_detect = knc_detect, // Probe for devices, add with add_cgpu + + .hash_work = hash_queued_work, + .scanwork = knc_scanwork, + .queue_full = knc_queue_full, + .flush_work = knc_flush_work, +}; diff --git a/miner.h b/miner.h index 73da6b6c..1e6f4efd 100644 --- a/miner.h +++ b/miner.h @@ -242,6 +242,7 @@ static inline int fsync (int fd) #define ASIC_PARSE_COMMANDS(DRIVER_ADD_COMMAND) \ DRIVER_ADD_COMMAND(bflsc) \ DRIVER_ADD_COMMAND(bitfury) \ + DRIVER_ADD_COMMAND(knc) \ DRIVER_ADD_COMMAND(avalon) \ DRIVER_ADD_COMMAND(klondike) @@ -496,6 +497,9 @@ struct cgpu_info { bool polling; bool flash_led; #endif /* USE_BITFORCE */ +#if defined(USE_KNC) + struct knc_state *knc_state; +#endif #if defined(USE_BITFORCE) || defined(USE_BFLSC) pthread_mutex_t device_mutex; #endif /* USE_BITFORCE || USE_BFLSC */ From 6d4a03ad8128cf815776f6d9bed65577a0a9354b Mon Sep 17 00:00:00 2001 From: Vitalii Demianets Date: Fri, 18 Oct 2013 15:16:11 +0200 Subject: [PATCH 07/18] Better HW error count; disable permanently those cores which fail often --- driver-knc-spi-fpga.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/driver-knc-spi-fpga.c b/driver-knc-spi-fpga.c index 00a711f4..4eb78a52 100644 --- a/driver-knc-spi-fpga.c +++ b/driver-knc-spi-fpga.c @@ -24,6 +24,7 @@ /* How many hardware errors in a row before disabling the core */ #define HW_ERR_LIMIT 10 +#define DISA_ERR_LIMIT 3 #define MAX_ACTIVE_WORKS (192 * 2 * 6 * 2) @@ -148,6 +149,8 @@ struct knc_state { struct active_work active_fifo[KNC_ACTIVE_BUFFER_SIZE]; uint8_t hwerrs[MAX_ASICS * 256]; + uint8_t disa_cnt[MAX_ASICS * 256]; + uint32_t hwerr_work_id[MAX_ASICS * 256]; int read_d, write_d; #define KNC_DISA_CORES_SIZE (MAX_ASICS * 256) struct core_disa_data disa_cores_fifo[KNC_DISA_CORES_SIZE]; @@ -461,10 +464,15 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu rxbuf->responses[i].core; if (submit_nonce(thr, work, rxbuf->responses[i].nonce)) { - if (cidx < sizeof(knc->hwerrs)) + if (cidx < sizeof(knc->hwerrs)) { knc->hwerrs[cidx] = 0; + knc->disa_cnt[cidx] = 0; + knc->hwerr_work_id[cidx] = 0xFFFFFFFF; + } } else { - if (cidx < sizeof(knc->hwerrs)) { + if ((cidx < sizeof(knc->hwerrs)) && + (knc->hwerr_work_id[cidx] != rxbuf->responses[i].work_id)) { + knc->hwerr_work_id[cidx] = rxbuf->responses[i].work_id; if (++(knc->hwerrs[cidx]) >= HW_ERR_LIMIT) { struct core_disa_data *core; core = &knc->disa_cores_fifo[knc->write_d]; @@ -472,10 +480,15 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu core->asic = rxbuf->responses[i].asic; core->core = rxbuf->responses[i].core; disable_core(core->asic, core->core); - applog(LOG_WARNING, + if (++(knc->disa_cnt[cidx]) >= DISA_ERR_LIMIT) { + applog(LOG_WARNING, + "KnC: core %u-%u was disabled permanently", core->asic, core->core); + } else { + applog(LOG_WARNING, "KnC: core %u-%u was disabled due to %u HW errors in a row", - core->asic, core->core, HW_ERR_LIMIT); - knc_disa_cores_fifo_inc_idx(&knc->write_d); + core->asic, core->core, HW_ERR_LIMIT); + knc_disa_cores_fifo_inc_idx(&knc->write_d); + } } } }; @@ -546,6 +559,7 @@ static bool knc_detect_one(struct spidev_context *ctx) knc->read_d = 0; knc->write_d = 1; knc->salt = rand(); + memset(knc->hwerr_work_id, 0xFF, sizeof(knc->hwerr_work_id)); _internal_knc_flush_fpga(knc); From 6bcd60a931950a38cf06ede701507c6d482856dc Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 28 Oct 2013 11:50:42 +1100 Subject: [PATCH 08/18] Add KNC to api --- api.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/api.c b/api.c index 3494f9ee..797777d2 100644 --- a/api.c +++ b/api.c @@ -29,7 +29,7 @@ #include "miner.h" #include "util.h" -#if defined(USE_BFLSC) || defined(USE_AVALON) || defined(USE_BITFURY) || defined(USE_KLONDIKE) +#if defined(USE_BFLSC) || defined(USE_AVALON) || defined(USE_BITFURY) || defined(USE_KLONDIKE) || defined(USE_KNC) #define HAVE_AN_ASIC 1 #endif @@ -185,6 +185,9 @@ static const char *DEVICECODE = "" #ifdef USE_AVALON "AVA " #endif +#ifdef USE_KNC + "KnC " +#endif #ifdef USE_MODMINER "MMQ " #endif From 5467dfe7a9bfaeae0f19505301c4bfbdf89349a9 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 28 Oct 2013 11:55:12 +1100 Subject: [PATCH 09/18] Fix trivial warnings in knc driver. --- driver-knc-spi-fpga.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/driver-knc-spi-fpga.c b/driver-knc-spi-fpga.c index 4eb78a52..0f52af29 100644 --- a/driver-knc-spi-fpga.c +++ b/driver-knc-spi-fpga.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -168,7 +169,7 @@ static inline bool knc_active_fifo_full(struct knc_state *knc) static inline void knc_queued_fifo_inc_idx(int *idx) { - if (unlikely(*idx >= (KNC_QUEUED_BUFFER_SIZE - 1))) + if (unlikely(*idx >= ((int)KNC_QUEUED_BUFFER_SIZE - 1))) *idx = 0; else ++(*idx); @@ -248,7 +249,7 @@ static struct spidev_context * spi_new(int idx) l_ioctl_error: applog(LOG_ERR, "KnC spi: ioctl error on SPI device %s: %m", dev_fname); -l_close_free_exit_error: +// l_close_free_exit_error: close(ctx->fd); l_free_exit_error: free(ctx); @@ -362,12 +363,12 @@ static void knc_work_from_queue_to_spi(struct knc_state *knc, } static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu, - struct spi_rx_t *rxbuf, int num) + struct spi_rx_t *rxbuf, int __maybe_unused num) { struct knc_state *knc = cgpu->knc_state; struct work *work; int64_t us; - int works, submitted, completed, i, num_sent; + int submitted, completed, i, num_sent; int next_read_q, next_read_a; struct timeval now; @@ -411,7 +412,7 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu /* check for completed works and calculated nonces */ gettimeofday(&now, NULL); completed = 0; - for (i = 0; i < MAX_RESPONSES_IN_BATCH; ++i) + for (i = 0; i < (int)MAX_RESPONSES_IN_BATCH; ++i) { if ( (rxbuf->responses[i].type != RESPONSE_TYPE_NONCE_FOUND) && (rxbuf->responses[i].type != RESPONSE_TYPE_WORK_DONE) @@ -464,13 +465,13 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu rxbuf->responses[i].core; if (submit_nonce(thr, work, rxbuf->responses[i].nonce)) { - if (cidx < sizeof(knc->hwerrs)) { + if (cidx < (int)sizeof(knc->hwerrs)) { knc->hwerrs[cidx] = 0; knc->disa_cnt[cidx] = 0; knc->hwerr_work_id[cidx] = 0xFFFFFFFF; } } else { - if ((cidx < sizeof(knc->hwerrs)) && + if ((cidx < (int)sizeof(knc->hwerrs)) && (knc->hwerr_work_id[cidx] != rxbuf->responses[i].work_id)) { knc->hwerr_work_id[cidx] = rxbuf->responses[i].work_id; if (++(knc->hwerrs[cidx]) >= HW_ERR_LIMIT) { From 76af3bf9a3ee2a3f0be5280ebe5f42ab4de100c9 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 28 Oct 2013 12:01:54 +1100 Subject: [PATCH 10/18] Process multiple responses in the knc driver. --- driver-knc-spi-fpga.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/driver-knc-spi-fpga.c b/driver-knc-spi-fpga.c index 0f52af29..d28930a6 100644 --- a/driver-knc-spi-fpga.c +++ b/driver-knc-spi-fpga.c @@ -363,7 +363,7 @@ static void knc_work_from_queue_to_spi(struct knc_state *knc, } static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu, - struct spi_rx_t *rxbuf, int __maybe_unused num) + struct spi_rx_t *rxbuf) { struct knc_state *knc = cgpu->knc_state; struct work *work; @@ -606,6 +606,17 @@ void knc_detect(bool __maybe_unused hotplug) } } +static int64_t knc_process_responses(struct thr_info *thr, struct cgpu_info *cgpu, + struct spi_rx_t *rxbuf, int num) +{ + int64_t ret = 0; + int i; + + for (i = 0; i < num; i++) + ret += knc_process_response(thr, cgpu, &rxbuf[i]); + return ret; +} + /* return value is number of nonces that have been checked since * previous call */ @@ -641,7 +652,7 @@ static int64_t knc_scanwork(struct thr_info *thr) applog(LOG_DEBUG, "KnC spi: %d works in request", num); - return knc_process_response(thr, cgpu, &spi_rxbuf, len); + return knc_process_responses(thr, cgpu, &spi_rxbuf, len); } static bool knc_queue_full(struct cgpu_info *cgpu) @@ -697,7 +708,7 @@ static void knc_flush_work(struct cgpu_info *cgpu) len = _internal_knc_flush_fpga(knc); if (len > 0) - knc_process_response(NULL, cgpu, &spi_rxbuf, len); + knc_process_responses(NULL, cgpu, &spi_rxbuf, len); } struct device_drv knc_drv = { From 32ec3628219bfcbf1d964019302a9f420a7a9cab Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 28 Oct 2013 12:04:15 +1100 Subject: [PATCH 11/18] Only count successful nonces as hashrate in the knc driver. --- driver-knc-spi-fpga.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/driver-knc-spi-fpga.c b/driver-knc-spi-fpga.c index d28930a6..05d30168 100644 --- a/driver-knc-spi-fpga.c +++ b/driver-knc-spi-fpga.c @@ -368,7 +368,7 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu struct knc_state *knc = cgpu->knc_state; struct work *work; int64_t us; - int submitted, completed, i, num_sent; + int submitted, successful, i, num_sent; int next_read_q, next_read_a; struct timeval now; @@ -411,7 +411,7 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu /* check for completed works and calculated nonces */ gettimeofday(&now, NULL); - completed = 0; + successful = 0; for (i = 0; i < (int)MAX_RESPONSES_IN_BATCH; ++i) { if ( (rxbuf->responses[i].type != RESPONSE_TYPE_NONCE_FOUND) && @@ -470,6 +470,7 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu knc->disa_cnt[cidx] = 0; knc->hwerr_work_id[cidx] = 0xFFFFFFFF; } + successful++; } else { if ((cidx < (int)sizeof(knc->hwerrs)) && (knc->hwerr_work_id[cidx] != rxbuf->responses[i].work_id)) { @@ -505,10 +506,9 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu &(knc->active_fifo[knc->read_a]), sizeof(struct active_work)); knc->active_fifo[knc->read_a].work = NULL; - ++completed; } - return ((uint64_t)completed) * 0x100000000UL; + return ((uint64_t)successful) * 0x100000000UL; } /* Send flush command via SPI */ From 1388b8417861c04ff94b13c6efcf14e100272c1c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 28 Oct 2013 12:06:48 +1100 Subject: [PATCH 12/18] Revert "Process multiple responses in the knc driver." This reverts commit 76af3bf9a3ee2a3f0be5280ebe5f42ab4de100c9. --- driver-knc-spi-fpga.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/driver-knc-spi-fpga.c b/driver-knc-spi-fpga.c index 05d30168..c6f542b7 100644 --- a/driver-knc-spi-fpga.c +++ b/driver-knc-spi-fpga.c @@ -363,7 +363,7 @@ static void knc_work_from_queue_to_spi(struct knc_state *knc, } static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu, - struct spi_rx_t *rxbuf) + struct spi_rx_t *rxbuf, int __maybe_unused num) { struct knc_state *knc = cgpu->knc_state; struct work *work; @@ -606,17 +606,6 @@ void knc_detect(bool __maybe_unused hotplug) } } -static int64_t knc_process_responses(struct thr_info *thr, struct cgpu_info *cgpu, - struct spi_rx_t *rxbuf, int num) -{ - int64_t ret = 0; - int i; - - for (i = 0; i < num; i++) - ret += knc_process_response(thr, cgpu, &rxbuf[i]); - return ret; -} - /* return value is number of nonces that have been checked since * previous call */ @@ -652,7 +641,7 @@ static int64_t knc_scanwork(struct thr_info *thr) applog(LOG_DEBUG, "KnC spi: %d works in request", num); - return knc_process_responses(thr, cgpu, &spi_rxbuf, len); + return knc_process_response(thr, cgpu, &spi_rxbuf, len); } static bool knc_queue_full(struct cgpu_info *cgpu) @@ -708,7 +697,7 @@ static void knc_flush_work(struct cgpu_info *cgpu) len = _internal_knc_flush_fpga(knc); if (len > 0) - knc_process_responses(NULL, cgpu, &spi_rxbuf, len); + knc_process_response(NULL, cgpu, &spi_rxbuf, len); } struct device_drv knc_drv = { From ac7dc468e2d744adff38338c5b81d63dae7962cc Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 28 Oct 2013 14:27:57 +1100 Subject: [PATCH 13/18] Use the existing device_data for knc state data. --- driver-knc-spi-fpga.c | 10 +++++----- miner.h | 3 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/driver-knc-spi-fpga.c b/driver-knc-spi-fpga.c index c6f542b7..b7548708 100644 --- a/driver-knc-spi-fpga.c +++ b/driver-knc-spi-fpga.c @@ -365,7 +365,7 @@ static void knc_work_from_queue_to_spi(struct knc_state *knc, static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu, struct spi_rx_t *rxbuf, int __maybe_unused num) { - struct knc_state *knc = cgpu->knc_state; + struct knc_state *knc = cgpu->device_data; struct work *work; int64_t us; int submitted, successful, i, num_sent; @@ -568,7 +568,7 @@ static bool knc_detect_one(struct spidev_context *ctx) cgpu->name = "KnCminer"; cgpu->threads = 1; // .. perhaps our number of devices? - cgpu->knc_state = knc; + cgpu->device_data = knc; add_cgpu(cgpu); return true; @@ -612,7 +612,7 @@ void knc_detect(bool __maybe_unused hotplug) static int64_t knc_scanwork(struct thr_info *thr) { struct cgpu_info *cgpu = thr->cgpu; - struct knc_state *knc = cgpu->knc_state; + struct knc_state *knc = cgpu->device_data; int len, num; int next_read_q; @@ -646,7 +646,7 @@ static int64_t knc_scanwork(struct thr_info *thr) static bool knc_queue_full(struct cgpu_info *cgpu) { - struct knc_state *knc = cgpu->knc_state; + struct knc_state *knc = cgpu->device_data; struct work *work; int queue_full = true; @@ -666,7 +666,7 @@ static bool knc_queue_full(struct cgpu_info *cgpu) static void knc_flush_work(struct cgpu_info *cgpu) { - struct knc_state *knc = cgpu->knc_state; + struct knc_state *knc = cgpu->device_data; struct work *work; int len; int next_read_q, next_read_a; diff --git a/miner.h b/miner.h index 1e6f4efd..601e3d11 100644 --- a/miner.h +++ b/miner.h @@ -497,9 +497,6 @@ struct cgpu_info { bool polling; bool flash_led; #endif /* USE_BITFORCE */ -#if defined(USE_KNC) - struct knc_state *knc_state; -#endif #if defined(USE_BITFORCE) || defined(USE_BFLSC) pthread_mutex_t device_mutex; #endif /* USE_BITFORCE || USE_BFLSC */ From e684358828f893159e4c102a73f7b69afed57b8f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 28 Oct 2013 14:40:23 +1100 Subject: [PATCH 14/18] Use a mutex to protect data in the knc structure, to prevent loading more work during a flush, and unlock and return to main between calls to get_queued_work. --- driver-knc-spi-fpga.c | 48 ++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/driver-knc-spi-fpga.c b/driver-knc-spi-fpga.c index b7548708..a3779b29 100644 --- a/driver-knc-spi-fpga.c +++ b/driver-knc-spi-fpga.c @@ -155,6 +155,8 @@ struct knc_state { int read_d, write_d; #define KNC_DISA_CORES_SIZE (MAX_ASICS * 256) struct core_disa_data disa_cores_fifo[KNC_DISA_CORES_SIZE]; + + pthread_mutex_t lock; }; static inline bool knc_queued_fifo_full(struct knc_state *knc) @@ -560,6 +562,8 @@ static bool knc_detect_one(struct spidev_context *ctx) knc->read_d = 0; knc->write_d = 1; knc->salt = rand(); + mutex_init(&knc->lock); + memset(knc->hwerr_work_id, 0xFF, sizeof(knc->hwerr_work_id)); _internal_knc_flush_fpga(knc); @@ -613,8 +617,8 @@ static int64_t knc_scanwork(struct thr_info *thr) { struct cgpu_info *cgpu = thr->cgpu; struct knc_state *knc = cgpu->device_data; - int len, num; - int next_read_q; + int len, num, next_read_q; + int64_t ret; applog(LOG_DEBUG, "KnC running scanwork"); @@ -623,6 +627,8 @@ static int64_t knc_scanwork(struct thr_info *thr) /* Prepare tx buffer */ memset(spi_txbuf, 0, sizeof(spi_txbuf)); num = 0; + + mutex_lock(&knc->lock); next_read_q = knc->read_q; knc_queued_fifo_inc_idx(&next_read_q); while (next_read_q != knc->write_q) { @@ -635,31 +641,43 @@ static int64_t knc_scanwork(struct thr_info *thr) len = spi_transfer(knc->ctx, (uint8_t *)spi_txbuf, (uint8_t *)&spi_rxbuf, sizeof(spi_txbuf)); - if (len != sizeof(spi_rxbuf)) - return -1; + if (len != sizeof(spi_rxbuf)) { + ret = -1; + goto out_unlock; + } len /= sizeof(struct spi_response); applog(LOG_DEBUG, "KnC spi: %d works in request", num); - return knc_process_response(thr, cgpu, &spi_rxbuf, len); + ret = knc_process_response(thr, cgpu, &spi_rxbuf, len); +out_unlock: + mutex_unlock(&knc->lock); + + return ret; } static bool knc_queue_full(struct cgpu_info *cgpu) { struct knc_state *knc = cgpu->device_data; struct work *work; - int queue_full = true; + int queue_full = false; applog(LOG_DEBUG, "KnC running queue full"); - while (!knc_queued_fifo_full(knc)) { - work = get_queued(cgpu); - if (!work) { - queue_full = false; - break; - } - knc->queued_fifo[knc->write_q].work = work; - knc_queued_fifo_inc_idx(&(knc->write_q)); + + mutex_lock(&knc->lock); + if (knc_queued_fifo_full(knc)) { + queue_full = true; + goto out_unlock; } + work = get_queued(cgpu); + if (!work) + goto out_unlock; + knc->queued_fifo[knc->write_q].work = work; + knc_queued_fifo_inc_idx(&(knc->write_q)); + if (knc_queued_fifo_full(knc)) + queue_full = true; +out_unlock: + mutex_unlock(&knc->lock); return queue_full; } @@ -673,6 +691,7 @@ static void knc_flush_work(struct cgpu_info *cgpu) applog(LOG_ERR, "KnC running flushwork"); + mutex_lock(&knc->lock); /* Drain queued works */ next_read_q = knc->read_q; knc_queued_fifo_inc_idx(&next_read_q); @@ -698,6 +717,7 @@ static void knc_flush_work(struct cgpu_info *cgpu) len = _internal_knc_flush_fpga(knc); if (len > 0) knc_process_response(NULL, cgpu, &spi_rxbuf, len); + mutex_unlock(&knc->lock); } struct device_drv knc_drv = { From 6e3bee0d5bd7519f4005e66cefe6ce6da81561eb Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 29 Oct 2013 21:31:44 +1100 Subject: [PATCH 15/18] Trivial style changes to knc driver. --- driver-knc-spi-fpga.c | 111 +++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/driver-knc-spi-fpga.c b/driver-knc-spi-fpga.c index a3779b29..ddee1711 100644 --- a/driver-knc-spi-fpga.c +++ b/driver-knc-spi-fpga.c @@ -115,9 +115,9 @@ struct spi_rx_t { uint32_t rsvd_3; struct spi_response responses[MAX_RESPONSES_IN_BATCH]; }; + static struct spi_rx_t spi_rxbuf; -struct device_drv knc_drv; struct active_work { struct work *work; uint32_t work_id; @@ -194,12 +194,12 @@ static inline void knc_disa_cores_fifo_inc_idx(int *idx) } /* Find SPI device with index idx, init it */ -static struct spidev_context * spi_new(int idx) +static struct spidev_context *spi_new(int idx) { struct spidev_context *ctx; char dev_fname[PATH_MAX]; - if(NULL == (ctx = malloc(sizeof(struct spidev_context)))) { + if (NULL == (ctx = malloc(sizeof(struct spidev_context)))) { applog(LOG_ERR, "KnC spi: Out of memory"); goto l_exit_error; } @@ -251,7 +251,6 @@ static struct spidev_context * spi_new(int idx) l_ioctl_error: applog(LOG_ERR, "KnC spi: ioctl error on SPI device %s: %m", dev_fname); -// l_close_free_exit_error: close(ctx->fd); l_free_exit_error: free(ctx); @@ -263,6 +262,7 @@ static void spi_free(struct spidev_context *ctx) { if (NULL == ctx) return; + close(ctx->fd); free(ctx); } @@ -270,8 +270,8 @@ static void spi_free(struct spidev_context *ctx) static int spi_transfer(struct spidev_context *ctx, uint8_t *txbuf, uint8_t *rxbuf, int len) { - int ret; struct spi_ioc_transfer xfr; + int ret; memset(rxbuf, 0xff, len); @@ -286,9 +286,8 @@ static int spi_transfer(struct spidev_context *ctx, uint8_t *txbuf, xfr.cs_change = 0; xfr.pad = 0; - if (1 > (ret = ioctl(ctx->fd, SPI_IOC_MESSAGE(1), &xfr))) { + if (1 > (ret = ioctl(ctx->fd, SPI_IOC_MESSAGE(1), &xfr))) applog(LOG_ERR, "KnC spi xfer: ioctl error on SPI device: %m"); - } return ret; } @@ -296,6 +295,7 @@ static int spi_transfer(struct spidev_context *ctx, uint8_t *txbuf, static void disable_core(uint8_t asic, uint8_t core) { char str[256]; + snprintf(str, sizeof(str), "i2cset -y 2 0x2%hhu %hhu 0", asic, core); if (0 != WEXITSTATUS(system(str))) applog(LOG_ERR, "KnC: system call failed"); @@ -304,6 +304,7 @@ static void disable_core(uint8_t asic, uint8_t core) static void enable_core(uint8_t asic, uint8_t core) { char str[256]; + snprintf(str, sizeof(str), "i2cset -y 2 0x2%hhu %hhu 1", asic, core); if (0 != WEXITSTATUS(system(str))) applog(LOG_ERR, "KnC: system call failed"); @@ -312,27 +313,30 @@ static void enable_core(uint8_t asic, uint8_t core) static int64_t timediff(const struct timeval *a, const struct timeval *b) { struct timeval diff; + timersub(a, b, &diff); + return diff.tv_sec * 1000000 + diff.tv_usec; } static void knc_check_disabled_cores(struct knc_state *knc) { - int next_read_d; + struct core_disa_data *core; + int next_read_d, cidx; struct timeval now; int64_t us; - struct core_disa_data *core; - int cidx; next_read_d = knc->read_d; knc_disa_cores_fifo_inc_idx(&next_read_d); if (next_read_d == knc->write_d) return; /* queue empty */ + core = &knc->disa_cores_fifo[next_read_d]; gettimeofday(&now, NULL); us = timediff(&now, &core->disa_begin); if ((us >= 0) && (us < CORE_DISA_PERIOD_US)) return; /* latest disabled core still not expired */ + cidx = core->asic * 256 + core->core; enable_core(core->asic, core->core); knc->hwerrs[cidx] = 0; @@ -356,29 +360,29 @@ static void knc_work_from_queue_to_spi(struct knc_state *knc, ++(knc->next_work_id); buf_to = spi_req->midstate; buf_from = (uint32_t *)q_work->work->midstate; + for (i = 0; i < WORK_MIDSTATE_WORDS; ++i) buf_to[i] = le32toh(buf_from[8 - i - 1]); buf_to = spi_req->data; buf_from = (uint32_t *)&(q_work->work->data[16 * 4]); + for (i = 0; i < WORK_DATA_WORDS; ++i) buf_to[i] = le32toh(buf_from[3 - i - 1]); } static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu, - struct spi_rx_t *rxbuf, int __maybe_unused num) + struct spi_rx_t *rxbuf) { struct knc_state *knc = cgpu->device_data; - struct work *work; - int64_t us; int submitted, successful, i, num_sent; int next_read_q, next_read_a; struct timeval now; + struct work *work; + int64_t us; - if (knc->write_q > knc->read_q) - num_sent = knc->write_q - knc->read_q - 1; - else - num_sent = - knc->write_q + KNC_QUEUED_BUFFER_SIZE - knc->read_q - 1; + num_sent = knc->write_q - knc->read_q - 1; + if (knc->write_q <= knc->read_q) + num_sent += KNC_QUEUED_BUFFER_SIZE; /* Actually process SPI response */ if (rxbuf->works_accepted) { @@ -392,11 +396,13 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu /* move works_accepted number of items from queued_fifo to active_fifo */ gettimeofday(&now, NULL); submitted = 0; + for (i = 0; i < rxbuf->works_accepted; ++i) { next_read_q = knc->read_q; knc_queued_fifo_inc_idx(&next_read_q); if ((next_read_q == knc->write_q) || knc_active_fifo_full(knc)) break; + memcpy(&knc->active_fifo[knc->write_a], &knc->queued_fifo[next_read_q], sizeof(struct active_work)); @@ -406,20 +412,21 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu knc_active_fifo_inc_idx(&knc->write_a); ++submitted; } - if (submitted != rxbuf->works_accepted) + if (submitted != rxbuf->works_accepted) { applog(LOG_ERR, "KnC: accepted by FPGA %u works, but only %d submitted", rxbuf->works_accepted, submitted); + } /* check for completed works and calculated nonces */ gettimeofday(&now, NULL); successful = 0; - for (i = 0; i < (int)MAX_RESPONSES_IN_BATCH; ++i) - { - if ( (rxbuf->responses[i].type != RESPONSE_TYPE_NONCE_FOUND) && - (rxbuf->responses[i].type != RESPONSE_TYPE_WORK_DONE) - ) + + for (i = 0; i < (int)MAX_RESPONSES_IN_BATCH; ++i) { + if ((rxbuf->responses[i].type != RESPONSE_TYPE_NONCE_FOUND) && + (rxbuf->responses[i].type != RESPONSE_TYPE_WORK_DONE)) continue; + applog(LOG_DEBUG, "KnC spi: raw response %08X %08X", ((uint32_t *)&rxbuf->responses[i])[0], ((uint32_t *)&rxbuf->responses[i])[1]); @@ -431,6 +438,7 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu /* Find active work with matching ID */ next_read_a = knc->read_a; knc_active_fifo_inc_idx(&next_read_a); + while (next_read_a != knc->write_a) { if (knc->active_fifo[next_read_a].work_id == rxbuf->responses[i].work_id) @@ -446,10 +454,11 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu work = knc->active_fifo[next_read_a].work; knc_active_fifo_inc_idx(&knc->read_a); work_completed(cgpu, work); - if (next_read_a != knc->read_a) + if (next_read_a != knc->read_a) { memcpy(&(knc->active_fifo[next_read_a]), &(knc->active_fifo[knc->read_a]), sizeof(struct active_work)); + } knc->active_fifo[knc->read_a].work = NULL; } @@ -457,6 +466,7 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu } if (next_read_a == knc->write_a) continue; + applog(LOG_DEBUG, "KnC spi: response work %u found", rxbuf->responses[i].work_id); work = knc->active_fifo[next_read_a].work; @@ -465,6 +475,7 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu if (NULL != thr) { int cidx = rxbuf->responses[i].asic * 256 + rxbuf->responses[i].core; + if (submit_nonce(thr, work, rxbuf->responses[i].nonce)) { if (cidx < (int)sizeof(knc->hwerrs)) { @@ -479,6 +490,7 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu knc->hwerr_work_id[cidx] = rxbuf->responses[i].work_id; if (++(knc->hwerrs[cidx]) >= HW_ERR_LIMIT) { struct core_disa_data *core; + core = &knc->disa_cores_fifo[knc->write_d]; core->disa_begin = now; core->asic = rxbuf->responses[i].asic; @@ -503,10 +515,11 @@ static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu /* Work completed */ knc_active_fifo_inc_idx(&knc->read_a); work_completed(cgpu, work); - if (next_read_a != knc->read_a) + if (next_read_a != knc->read_a) { memcpy(&(knc->active_fifo[next_read_a]), &(knc->active_fifo[knc->read_a]), sizeof(struct active_work)); + } knc->active_fifo[knc->read_a].work = NULL; } @@ -524,6 +537,7 @@ static int _internal_knc_flush_fpga(struct knc_state *knc) (uint8_t *)&spi_rxbuf, sizeof(struct spi_request)); if (len != sizeof(struct spi_request)) return -1; + len /= sizeof(struct spi_response); return len; @@ -532,8 +546,9 @@ static int _internal_knc_flush_fpga(struct knc_state *knc) static bool knc_detect_one(struct spidev_context *ctx) { /* Scan device for ASICs */ - int chip_id; - int devices = 0; + int chip_id, devices = 0; + struct cgpu_info *cgpu; + struct knc_state *knc; for (chip_id = 0; chip_id < MAX_ASICS; ++chip_id) { /* TODO: perform the ASIC test/detection */ @@ -544,10 +559,11 @@ static bool knc_detect_one(struct spidev_context *ctx) applog(LOG_INFO, "SPI detected, but not KnCminer ASICs"); return false; } + applog(LOG_INFO, "Found a KnC miner with %d ASICs", devices); - struct cgpu_info *cgpu = calloc(1, sizeof(*cgpu)); - struct knc_state *knc = calloc(1, sizeof(*knc)); + cgpu = calloc(1, sizeof(*cgpu)); + knc = calloc(1, sizeof(*knc)); if (!cgpu || !knc) { applog(LOG_ERR, "KnC miner detected, but failed to allocate memory"); return false; @@ -581,16 +597,17 @@ static bool knc_detect_one(struct spidev_context *ctx) // http://www.concentric.net/~Ttwang/tech/inthash.htm static unsigned long mix(unsigned long a, unsigned long b, unsigned long c) { - a=a-b; a=a-c; a=a^(c >> 13); - b=b-c; b=b-a; b=b^(a << 8); - c=c-a; c=c-b; c=c^(b >> 13); - a=a-b; a=a-c; a=a^(c >> 12); - b=b-c; b=b-a; b=b^(a << 16); - c=c-a; c=c-b; c=c^(b >> 5); - a=a-b; a=a-c; a=a^(c >> 3); - b=b-c; b=b-a; b=b^(a << 10); - c=c-a; c=c-b; c=c^(b >> 15); - return c; + a = a - b; a = a - c; a = a ^ (c >> 13); + b = b - c; b = b - a; b = b ^ (a << 8); + c = c - a; c = c - b; c = c ^ (b >> 13); + a = a - b; a = a - c; a = a ^ (c >> 12); + b = b - c; b = b - a; b = b ^ (a << 16); + c = c - a; c = c - b; c = c ^ (b >> 5); + a = a - b; a = a - c; a = a ^ (c >> 3); + b = b - c; b = b - a; b = b ^ (a << 10); + c = c - a; c = c - b; c = c ^ (b >> 15); + + return c; } /* Probe devices and register with add_cgpu */ @@ -603,6 +620,7 @@ void knc_detect(bool __maybe_unused hotplug) /* Loop through all possible SPI interfaces */ for (idx = 0; idx < MAX_SPIS; ++idx) { struct spidev_context *ctx = spi_new(idx + 1); + if (ctx != NULL) { if (!knc_detect_one(ctx)) spi_free(ctx); @@ -631,6 +649,7 @@ static int64_t knc_scanwork(struct thr_info *thr) mutex_lock(&knc->lock); next_read_q = knc->read_q; knc_queued_fifo_inc_idx(&next_read_q); + while (next_read_q != knc->write_q) { knc_work_from_queue_to_spi(knc, &knc->queued_fifo[next_read_q], &spi_txbuf[num]); @@ -645,11 +664,10 @@ static int64_t knc_scanwork(struct thr_info *thr) ret = -1; goto out_unlock; } - len /= sizeof(struct spi_response); applog(LOG_DEBUG, "KnC spi: %d works in request", num); - ret = knc_process_response(thr, cgpu, &spi_rxbuf, len); + ret = knc_process_response(thr, cgpu, &spi_rxbuf); out_unlock: mutex_unlock(&knc->lock); @@ -659,8 +677,8 @@ out_unlock: static bool knc_queue_full(struct cgpu_info *cgpu) { struct knc_state *knc = cgpu->device_data; - struct work *work; int queue_full = false; + struct work *work; applog(LOG_DEBUG, "KnC running queue full"); @@ -685,9 +703,8 @@ out_unlock: static void knc_flush_work(struct cgpu_info *cgpu) { struct knc_state *knc = cgpu->device_data; + int len, next_read_q, next_read_a; struct work *work; - int len; - int next_read_q, next_read_a; applog(LOG_ERR, "KnC running flushwork"); @@ -695,6 +712,7 @@ static void knc_flush_work(struct cgpu_info *cgpu) /* Drain queued works */ next_read_q = knc->read_q; knc_queued_fifo_inc_idx(&next_read_q); + while (next_read_q != knc->write_q) { work = knc->queued_fifo[next_read_q].work; work_completed(cgpu, work); @@ -706,6 +724,7 @@ static void knc_flush_work(struct cgpu_info *cgpu) /* Drain active works */ next_read_a = knc->read_a; knc_active_fifo_inc_idx(&next_read_a); + while (next_read_a != knc->write_a) { work = knc->active_fifo[next_read_a].work; work_completed(cgpu, work); @@ -716,7 +735,7 @@ static void knc_flush_work(struct cgpu_info *cgpu) len = _internal_knc_flush_fpga(knc); if (len > 0) - knc_process_response(NULL, cgpu, &spi_rxbuf, len); + knc_process_response(NULL, cgpu, &spi_rxbuf); mutex_unlock(&knc->lock); } From b542f5235b71c4ee149cc2ca2f7b2c10ea2d2dbd Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 29 Oct 2013 22:08:00 +1100 Subject: [PATCH 16/18] Add copyright notice to knc driver. --- driver-knc-spi-fpga.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/driver-knc-spi-fpga.c b/driver-knc-spi-fpga.c index ddee1711..f8488569 100644 --- a/driver-knc-spi-fpga.c +++ b/driver-knc-spi-fpga.c @@ -1,4 +1,14 @@ -/* cgminer driver for KnCminer Jupiter */ +/* + * cgminer driver for KnCminer devices + * + * Copyright 2013 Con Kolivas + * Copyright 2013 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 #include From 75230ed80814f2a7f11ef7d78040c19203ab0759 Mon Sep 17 00:00:00 2001 From: Kano Date: Tue, 29 Oct 2013 22:30:34 +1100 Subject: [PATCH 17/18] klondike - better to unlock locks than to lock them twice :) --- driver-klondike.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver-klondike.c b/driver-klondike.c index 54743d64..807e7042 100644 --- a/driver-klondike.c +++ b/driver-klondike.c @@ -1017,7 +1017,7 @@ static void *klondike_get_replies(void *userdata) if (klninfo->jobque[dev].flushed == false) idle = true; slaves = klninfo->status[0].kline.ws.slavecount; - rd_lock(&(klninfo->stat_lock)); + rd_unlock(&(klninfo->stat_lock)); if (idle) applog(LOG_WARNING, "%s%i:%d went idle before work was sent", klncgpu->drv->name, @@ -1026,7 +1026,7 @@ static void *klondike_get_replies(void *userdata) } wr_lock(&(klninfo->stat_lock)); klninfo->jobque[dev].flushed = false; - wr_lock(&(klninfo->stat_lock)); + wr_unlock(&(klninfo->stat_lock)); } case KLN_CMD_STATUS: case KLN_CMD_ABORT: From f562174a39738a5906de0d11a690bbc12a5b1461 Mon Sep 17 00:00:00 2001 From: Kano Date: Wed, 30 Oct 2013 11:44:52 +1100 Subject: [PATCH 18/18] klondike - initialise stat_lock --- driver-klondike.c | 1 + 1 file changed, 1 insertion(+) diff --git a/driver-klondike.c b/driver-klondike.c index 807e7042..a445bf4e 100644 --- a/driver-klondike.c +++ b/driver-klondike.c @@ -821,6 +821,7 @@ static bool klondike_detect_one(struct libusb_device *dev, struct usb_find_devic break; update_usb_stats(klncgpu); applog(LOG_DEBUG, "Klondike cgpu added"); + rwlock_init(&klninfo->stat_lock); cglock_init(&klninfo->klist_lock); return true; }