From 017e7cbd49f1b8ba31495ddc7d16d441fe9af816 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Apr 2013 13:30:52 +1100 Subject: [PATCH 01/79] Add configure support for avalon. --- configure.ac | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 441dfb13..9a6013cb 100644 --- a/configure.ac +++ b/configure.ac @@ -241,6 +241,17 @@ if test "x$icarus" = xyes; then fi AM_CONDITIONAL([HAS_ICARUS], [test x$icarus = xyes]) +avalon="no" + +AC_ARG_ENABLE([avalon], + [AC_HELP_STRING([--enable-avalon],[Compile support for Avalon (default disabled)])], + [avalon=$enableval] + ) +if test "x$avalon" = xyes; then + AC_DEFINE([USE_AVALON], [1], [Defined to 1 if Avalon support is wanted]) +fi +AM_CONDITIONAL([HAS_AVALON], [test x$avalon = xyes]) + modminer="no" AC_ARG_ENABLE([modminer], @@ -287,7 +298,7 @@ else ]) fi -AM_CONDITIONAL([NEED_FPGAUTILS], [test x$icarus$bitforce$modminer$ztex != xnononono]) +AM_CONDITIONAL([NEED_FPGAUTILS], [test x$avalon$icarus$bitforce$modminer$ztex != xnonononono]) AM_CONDITIONAL([NEED_USBUTILS_C], [test x$bitforce$modminer$bflsc != xnonono]) AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes]) AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue]) @@ -501,14 +512,14 @@ if test "x$opencl" != xno; then else echo " OpenCL...............: NOT FOUND. GPU mining support DISABLED" - if test "x$cpumining$bitforce$icarus$ztex$modminer$bflsc" = xnononononono; then + if test "x$cpumining$bitforce$avalon$icarus$ztex$modminer$bflsc" = xnonononononono; 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$cpumining$bitforce$icarus$ztex$modminer$bflsc" = xnononononono; then + if test "x$cpumining$bitforce$icarus$avalon$ztex$modminer$bflsc" = xnonononononono; then AC_MSG_ERROR([No mining configured in]) fi echo " scrypt...............: Disabled (needs OpenCL)" @@ -525,6 +536,12 @@ else fi echo +if test "x$avalon" = xyes; then + echo " Avalon.ASICs.........: Enabled" +else + echo " Avalon.ASICs.........: Disabled" +fi + if test "x$bflsc" = xyes; then echo " BFL.ASICs............: Enabled" else From dea35d3349a83da39ff3625a132661655abe0b38 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Apr 2013 13:32:09 +1100 Subject: [PATCH 02/79] Add Makefile entry for driver-avalon. --- Makefile.am | 4 ++++ driver-avalon.c | 0 2 files changed, 4 insertions(+) create mode 100644 driver-avalon.c diff --git a/Makefile.am b/Makefile.am index 48847c06..c9070b2a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -98,6 +98,10 @@ if HAS_ICARUS cgminer_SOURCES += driver-icarus.c endif +if HAS_AVALON +cgminer_SOURCES += driver-avalon.c +endif + if HAS_MODMINER cgminer_SOURCES += driver-modminer.c bitstreamsdir = $(bindir)/bitstreams diff --git a/driver-avalon.c b/driver-avalon.c new file mode 100644 index 00000000..e69de29b From 71bae003bc009edf19d96c3d77d0a1633f8686c3 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Apr 2013 14:52:07 +1100 Subject: [PATCH 03/79] First draft of port of avalon driver to new cgminer queued infrastructure. --- cgminer.c | 34 +- driver-avalon.c | 1060 +++++++++++++++++++++++++++++++++++++++++++++++ driver-avalon.h | 136 ++++++ fpgautils.c | 22 + fpgautils.h | 2 + hexdump.c | 77 ++++ miner.h | 17 +- 7 files changed, 1342 insertions(+), 6 deletions(-) create mode 100644 driver-avalon.h create mode 100644 hexdump.c diff --git a/cgminer.c b/cgminer.c index 8d5eaf7a..edcf9eb4 100644 --- a/cgminer.c +++ b/cgminer.c @@ -48,6 +48,7 @@ #include "driver-opencl.h" #include "bench_block.h" #include "scrypt.h" +#include "driver-avalon.h" #if defined(unix) #include @@ -55,9 +56,9 @@ #include #endif -#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_MODMINER) +#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_AVALON) || defined(USE_MODMINER) # define USE_FPGA -#if defined(USE_ICARUS) +#if defined(USE_ICARUS) || defined(USE_AVALON) # define USE_FPGA_SERIAL #endif #elif defined(USE_ZTEX) @@ -138,6 +139,9 @@ bool opt_disable_pool; char *opt_icarus_options = NULL; char *opt_icarus_timing = NULL; bool opt_worktime; +#ifdef USE_AVALON +char *opt_avalon_options = NULL; +#endif #ifdef USE_USBUTILS char *opt_usb_select = NULL; int opt_usbdump = -1; @@ -833,6 +837,15 @@ static char *set_icarus_timing(const char *arg) } #endif +#ifdef USE_AVALON +static char *set_avalon_options(const char *arg) +{ + opt_set_charp(arg, &opt_avalon_options); + + return NULL; +} +#endif + #ifdef USE_USBUTILS static char *set_usb_select(const char *arg) { @@ -1032,6 +1045,11 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--icarus-timing", set_icarus_timing, NULL, NULL, opt_hidden), +#endif +#ifdef USE_AVALON + OPT_WITH_ARG("--avalon-options", + set_avalon_options, NULL, NULL, + opt_hidden), #endif OPT_WITHOUT_ARG("--load-balance", set_loadbalance, &pool_strategy, @@ -1359,6 +1377,9 @@ static char *opt_verusage_and_exit(const char *extra) #ifdef USE_ICARUS "icarus " #endif +#ifdef USE_AVALON + "avalon " +#endif #ifdef USE_MODMINER "modminer " #endif @@ -6792,6 +6813,10 @@ extern struct device_drv bitforce_drv; extern struct device_drv icarus_drv; #endif +#ifdef USE_AVALON +extern struct device_drv avalon_api; +#endif + #ifdef USE_MODMINER extern struct device_drv modminer_drv; #endif @@ -7311,6 +7336,11 @@ int main(int argc, char *argv[]) icarus_drv.drv_detect(); #endif +#ifdef USE_AVALON + if (!opt_scrypt) + avalon_api.drv_detect(); +#endif + #ifdef USE_BFLSC if (!opt_scrypt) bflsc_drv.drv_detect(); diff --git a/driver-avalon.c b/driver-avalon.c index e69de29b..33eae736 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -0,0 +1,1060 @@ +/* + * Copyright 2013 Con Kolivas + * Copyright 2012-2013 Xiangfu + * Copyright 2012 Luke Dashjr + * Copyright 2012 Andrew Smith + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. See COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef WIN32 + #include + #include + #include + #ifndef O_CLOEXEC + #define O_CLOEXEC 0 + #endif +#else + #include + #include +#endif + +#include "elist.h" +#include "miner.h" +#include "fpgautils.h" +#include "driver-avalon.h" +#include "hexdump.c" + +static int option_offset = -1; +struct avalon_info **avalon_info; +struct device_drv avalon_api; + +static int avalon_init_task(struct avalon_task *at, + uint8_t reset, uint8_t ff, uint8_t fan, + uint8_t timeout, uint8_t asic_num, + uint8_t miner_num, uint8_t nonce_elf, + uint8_t gate_miner, int frequency) +{ + uint8_t *buf; + static bool first = true; + + if (unlikely(!at)) + return -1; + + if (unlikely(timeout <= 0 || asic_num <= 0 || miner_num <= 0)) + return -1; + + memset(at, 0, sizeof(struct avalon_task)); + + if (unlikely(reset)) { + at->reset = 1; + at->fan_eft = 1; + at->timer_eft = 1; + first = true; + } + + at->flush_fifo = (ff ? 1 : 0); + at->fan_eft = (fan ? 1 : 0); + + if (unlikely(first && !at->reset)) { + at->fan_eft = 1; + at->timer_eft = 1; + first = false; + } + + at->fan_pwm_data = (fan ? fan : AVALON_DEFAULT_FAN_MAX_PWM); + at->timeout_data = timeout; + at->asic_num = asic_num; + at->miner_num = miner_num; + at->nonce_elf = nonce_elf; + + at->gate_miner_elf = 1; + at->asic_pll = 1; + + if (unlikely(gate_miner)) { + at-> gate_miner = 1; + at->asic_pll = 0; + } + + buf = (uint8_t *)at; + buf[5] = 0x00; + buf[8] = 0x74; + buf[9] = 0x01; + buf[10] = 0x00; + buf[11] = 0x00; + if (frequency == 256) { + buf[6] = 0x03; + buf[7] = 0x08; + } else if (frequency == 270) { + buf[6] = 0x73; + buf[7] = 0x08; + } else if (frequency == 282) { + buf[6] = 0xd3; + buf[7] = 0x08; + } else if (frequency == 300) { + buf[6] = 0x63; + buf[7] = 0x09; + } + + return 0; +} + +static inline void avalon_create_task(struct avalon_task *at, + struct work *work) +{ + memcpy(at->midstate, work->midstate, 32); + memcpy(at->data, work->data + 64, 12); +} + +static int avalon_send_task(int fd, const struct avalon_task *at, + struct cgpu_info *avalon) + +{ + size_t ret; + int full; + struct timespec p; + uint8_t buf[AVALON_WRITE_SIZE + 4 * AVALON_DEFAULT_ASIC_NUM]; + size_t nr_len; + struct avalon_info *info; + uint64_t delay = 32000000; /* Default 32ms for B19200 */ + uint32_t nonce_range; + int i; + + if (at->nonce_elf) + nr_len = AVALON_WRITE_SIZE + 4 * at->asic_num; + else + nr_len = AVALON_WRITE_SIZE; + + memcpy(buf, at, AVALON_WRITE_SIZE); + + if (at->nonce_elf) { + nonce_range = (uint32_t)0xffffffff / at->asic_num; + for (i = 0; i < at->asic_num; i++) { + buf[AVALON_WRITE_SIZE + (i * 4) + 3] = + (i * nonce_range & 0xff000000) >> 24; + buf[AVALON_WRITE_SIZE + (i * 4) + 2] = + (i * nonce_range & 0x00ff0000) >> 16; + buf[AVALON_WRITE_SIZE + (i * 4) + 1] = + (i * nonce_range & 0x0000ff00) >> 8; + buf[AVALON_WRITE_SIZE + (i * 4) + 0] = + (i * nonce_range & 0x000000ff) >> 0; + } + } +#if defined(__BIG_ENDIAN__) || defined(MIPSEB) + uint8_t tt = 0; + + tt = (buf[0] & 0x0f) << 4; + tt |= ((buf[0] & 0x10) ? (1 << 3) : 0); + tt |= ((buf[0] & 0x20) ? (1 << 2) : 0); + tt |= ((buf[0] & 0x40) ? (1 << 1) : 0); + tt |= ((buf[0] & 0x80) ? (1 << 0) : 0); + buf[0] = tt; + + tt = (buf[4] & 0x0f) << 4; + tt |= ((buf[4] & 0x10) ? (1 << 3) : 0); + tt |= ((buf[4] & 0x20) ? (1 << 2) : 0); + tt |= ((buf[4] & 0x40) ? (1 << 1) : 0); + tt |= ((buf[4] & 0x80) ? (1 << 0) : 0); + buf[4] = tt; +#endif + if (likely(avalon)) { + info = avalon_info[avalon->device_id]; + delay = nr_len * 10 * 1000000000ULL; + delay = delay / info->baud; + } + + if (at->reset) + nr_len = 1; + if (opt_debug) { + applog(LOG_DEBUG, "Avalon: Sent(%d):", nr_len); + hexdump((uint8_t *)buf, nr_len); + } + ret = write(fd, buf, nr_len); + if (unlikely(ret != nr_len)) + return AVA_SEND_ERROR; + + p.tv_sec = 0; + p.tv_nsec = (long)delay + 4000000; + nanosleep(&p, NULL); + applog(LOG_DEBUG, "Avalon: Sent: Buffer delay: %ld", p.tv_nsec); + + full = avalon_buffer_full(fd); + applog(LOG_DEBUG, "Avalon: Sent: Buffer full: %s", + ((full == AVA_BUFFER_FULL) ? "Yes" : "No")); + + if (unlikely(full == AVA_BUFFER_FULL)) + return AVA_SEND_BUFFER_FULL; + + return AVA_SEND_BUFFER_EMPTY; +} + +static int avalon_gets(int fd, uint8_t *buf, int read_count, + struct thr_info *thr, struct timeval *tv_finish) +{ + ssize_t ret = 0; + int rc = 0; + int read_amount = AVALON_READ_SIZE; + bool first = true; + + while (true) { + struct timeval timeout = {0, 100000}; + fd_set rd; + + FD_ZERO(&rd); + FD_SET(fd, &rd); + ret = select(fd + 1, &rd, NULL, NULL, &timeout); + if (unlikely(ret < 0)) + return AVA_GETS_ERROR; + if (ret) { + ret = read(fd, buf, read_amount); + if (unlikely(ret < 0)) + return AVA_GETS_ERROR; + if (likely(first)) { + if (likely(tv_finish)) + gettimeofday(tv_finish, NULL); + first = false; + } + if (likely(ret >= read_amount)) + return AVA_GETS_OK; + buf += ret; + read_amount -= ret; + continue; + } + + rc++; + if (rc >= read_count) { + if (opt_debug) { + applog(LOG_WARNING, + "Avalon: No data in %.2f seconds", + (float)rc/(float)AVALON_TIME_FACTOR); + } + return AVA_GETS_TIMEOUT; + } + + if (thr && thr->work_restart) { + if (opt_debug) { + applog(LOG_WARNING, + "Avalon: Work restart at %.2f seconds", + (float)(rc)/(float)AVALON_TIME_FACTOR); + } + return AVA_GETS_RESTART; + } + } +} + +static int avalon_get_result(int fd, struct avalon_result *ar, + struct thr_info *thr, struct timeval *tv_finish) +{ + struct cgpu_info *avalon; + struct avalon_info *info; + uint8_t result[AVALON_READ_SIZE]; + int ret, read_count = AVALON_RESET_FAULT_DECISECONDS * AVALON_TIME_FACTOR; + + if (likely(thr)) { + avalon = thr->cgpu; + info = avalon_info[avalon->device_id]; + read_count = info->read_count; + } + + memset(result, 0, AVALON_READ_SIZE); + ret = avalon_gets(fd, result, read_count, thr, tv_finish); + + if (ret == AVA_GETS_OK) { + if (opt_debug) { + applog(LOG_DEBUG, "Avalon: get:"); + hexdump((uint8_t *)result, AVALON_READ_SIZE); + } + memcpy((uint8_t *)ar, result, AVALON_READ_SIZE); + } + + return ret; +} + +static int avalon_decode_nonce(struct thr_info *thr, struct work **work, + struct avalon_result *ar, uint32_t *nonce) +{ + struct cgpu_info *avalon; + struct avalon_info *info; + int avalon_get_work_count, i; + + if (unlikely(!work)) + return -1; + + avalon = thr->cgpu; + info = avalon_info[avalon->device_id]; + avalon_get_work_count = info->miner_count; + + for (i = 0; i < avalon_get_work_count; i++) { + if (work[i] && + !memcmp(ar->data, work[i]->data + 64, 12) && + !memcmp(ar->midstate, work[i]->midstate, 32)) + break; + } + if (i == avalon_get_work_count) + return -1; + + info->matching_work[i]++; + *nonce = htole32(ar->nonce); + + applog(LOG_DEBUG, "Avalon: match to work[%d](%p): %d",i, work[i], + info->matching_work[i]); + return i; +} + +static int avalon_reset(int fd, struct avalon_result *ar) +{ + struct avalon_task at; + uint8_t *buf; + int ret, i = 0; + struct timespec p; + + avalon_init_task(&at, 1, 0, + AVALON_DEFAULT_FAN_MAX_PWM, + AVALON_DEFAULT_TIMEOUT, + AVALON_DEFAULT_ASIC_NUM, + AVALON_DEFAULT_MINER_NUM, + 0, 0, + AVALON_DEFAULT_FREQUENCY); + ret = avalon_send_task(fd, &at, NULL); + if (ret == AVA_SEND_ERROR) + return 1; + + avalon_get_result(fd, ar, NULL, NULL); + + buf = (uint8_t *)ar; + /* Sometimes there is one extra 0 byte for some reason in the buffer, + * so work around it. */ + if (buf[0] == 0) + buf = (uint8_t *)(ar + 1); + if (buf[0] == 0xAA && buf[1] == 0x55 && + buf[2] == 0xAA && buf[3] == 0x55) { + for (i = 4; i < 11; i++) + if (buf[i] != 0) + break; + } + + p.tv_sec = 0; + p.tv_nsec = AVALON_RESET_PITCH; + nanosleep(&p, NULL); + + if (i != 11) { + applog(LOG_ERR, "Avalon: Reset failed! not an Avalon?" + " (%d: %02x %02x %02x %02x)", + i, buf[0], buf[1], buf[2], buf[3]); + /* FIXME: return 1; */ + } else + applog(LOG_WARNING, "Avalon: Reset succeeded"); + return 0; +} + +static void avalon_idle(struct cgpu_info *avalon) +{ + int i, ret; + struct avalon_task at; + + int fd = avalon->device_fd; + struct avalon_info *info = avalon_info[avalon->device_id]; + int avalon_get_work_count = info->miner_count; + + i = 0; + while (true) { + avalon_init_task(&at, 0, 0, info->fan_pwm, + info->timeout, info->asic_count, + info->miner_count, 1, 1, info->frequency); + ret = avalon_send_task(fd, &at, avalon); + if (unlikely(ret == AVA_SEND_ERROR || + (ret == AVA_SEND_BUFFER_EMPTY && + (i + 1 == avalon_get_work_count * 2)))) { + applog(LOG_ERR, "AVA%i: Comms error", avalon->device_id); + return; + } + if (i + 1 == avalon_get_work_count * 2) + break; + + if (ret == AVA_SEND_BUFFER_FULL) + break; + + i++; + } + applog(LOG_ERR, "Avalon: Goto idle mode"); +} + +static void get_options(int this_option_offset, int *baud, int *miner_count, + int *asic_count, int *timeout, int *frequency) +{ + char err_buf[BUFSIZ+1]; + char buf[BUFSIZ+1]; + char *ptr, *comma, *colon, *colon2, *colon3, *colon4; + size_t max; + int i, tmp; + + if (opt_avalon_options == NULL) + buf[0] = '\0'; + else { + ptr = opt_avalon_options; + for (i = 0; i < this_option_offset; i++) { + comma = strchr(ptr, ','); + if (comma == NULL) + break; + ptr = comma + 1; + } + + comma = strchr(ptr, ','); + if (comma == NULL) + max = strlen(ptr); + else + max = comma - ptr; + + if (max > BUFSIZ) + max = BUFSIZ; + strncpy(buf, ptr, max); + buf[max] = '\0'; + } + + *baud = AVALON_IO_SPEED; + *miner_count = AVALON_DEFAULT_MINER_NUM - 8; + *asic_count = AVALON_DEFAULT_ASIC_NUM; + *timeout = AVALON_DEFAULT_TIMEOUT; + *frequency = AVALON_DEFAULT_FREQUENCY; + + if (!(*buf)) + return; + + colon = strchr(buf, ':'); + if (colon) + *(colon++) = '\0'; + + tmp = atoi(buf); + switch (tmp) { + case 115200: + *baud = 115200; + break; + case 57600: + *baud = 57600; + break; + case 38400: + *baud = 38400; + break; + case 19200: + *baud = 19200; + break; + default: + sprintf(err_buf, + "Invalid avalon-options for baud (%s) " + "must be 115200, 57600, 38400 or 19200", buf); + quit(1, err_buf); + } + + if (colon && *colon) { + colon2 = strchr(colon, ':'); + if (colon2) + *(colon2++) = '\0'; + + if (*colon) { + tmp = atoi(colon); + if (tmp > 0 && tmp <= AVALON_DEFAULT_MINER_NUM) { + *miner_count = tmp; + } else { + sprintf(err_buf, + "Invalid avalon-options for " + "miner_count (%s) must be 1 ~ %d", + colon, AVALON_DEFAULT_MINER_NUM); + quit(1, err_buf); + } + } + + if (colon2 && *colon2) { + colon3 = strchr(colon2, ':'); + if (colon3) + *(colon3++) = '\0'; + + tmp = atoi(colon2); + if (tmp > 0 && tmp <= AVALON_DEFAULT_ASIC_NUM) + *asic_count = tmp; + else { + sprintf(err_buf, + "Invalid avalon-options for " + "asic_count (%s) must be 1 ~ %d", + colon2, AVALON_DEFAULT_ASIC_NUM); + quit(1, err_buf); + } + + if (colon3 && *colon3) { + colon4 = strchr(colon3, ':'); + if (colon4) + *(colon4++) = '\0'; + + tmp = atoi(colon3); + if (tmp > 0 && tmp <= 0xff) + *timeout = tmp; + else { + sprintf(err_buf, + "Invalid avalon-options for " + "timeout (%s) must be 1 ~ %d", + colon3, 0xff); + quit(1, err_buf); + } + if (colon4 && *colon4) { + tmp = atoi(colon4); + switch (tmp) { + case 256: + case 270: + case 282: + case 300: + *frequency = tmp; + break; + default: + sprintf(err_buf, + "Invalid avalon-options for " + "frequency must be 256/270/282/300"); + quit(1, err_buf); + } + } + } + } + } +} + +static bool avalon_detect_one(const char *devpath) +{ + struct avalon_info *info; + struct avalon_result ar; + int fd, ret; + int baud, miner_count, asic_count, timeout, frequency = 0; + struct cgpu_info *avalon; + + int this_option_offset = ++option_offset; + get_options(this_option_offset, &baud, &miner_count, &asic_count, + &timeout, &frequency); + + applog(LOG_DEBUG, "Avalon Detect: Attempting to open %s " + "(baud=%d miner_count=%d asic_count=%d timeout=%d frequency=%d)", + devpath, baud, miner_count, asic_count, timeout, frequency); + + fd = avalon_open2(devpath, baud, true); + if (unlikely(fd == -1)) { + applog(LOG_ERR, "Avalon Detect: Failed to open %s", devpath); + return false; + } + + /* We have a real Avalon! */ + avalon = calloc(1, sizeof(struct cgpu_info)); + avalon->drv = &avalon_api; + avalon->device_path = strdup(devpath); + avalon->device_fd = fd; + avalon->threads = AVALON_MINER_THREADS; + add_cgpu(avalon); + + ret = avalon_reset(fd, &ar); + if (ret) { + ; /* FIXME: I think IT IS avalon and wait on reset; + * avalon_close(fd); + * return false; */ + } + + avalon_info = realloc(avalon_info, + sizeof(struct avalon_info *) * + (total_devices + 1)); + + applog(LOG_INFO, "Avalon Detect: Found at %s, mark as %d", + devpath, avalon->device_id); + + avalon_info[avalon->device_id] = (struct avalon_info *) + malloc(sizeof(struct avalon_info)); + if (unlikely(!(avalon_info[avalon->device_id]))) + quit(1, "Failed to malloc avalon_info"); + + info = avalon_info[avalon->device_id]; + + memset(info, 0, sizeof(struct avalon_info)); + + info->baud = baud; + info->miner_count = miner_count; + info->asic_count = asic_count; + info->timeout = timeout; + info->read_count = ((float)info->timeout * AVALON_HASH_TIME_FACTOR * + AVALON_TIME_FACTOR) / (float)info->miner_count; + + info->fan_pwm = AVALON_DEFAULT_FAN_MIN_PWM; + info->temp_max = 0; + /* This is for check the temp/fan every 3~4s */ + info->temp_history_count = (4 / (float)((float)info->timeout * ((float)1.67/0x32))) + 1; + if (info->temp_history_count <= 0) + info->temp_history_count = 1; + + info->temp_history_index = 0; + info->temp_sum = 0; + info->temp_old = 0; + info->frequency = frequency; + + /* Do something for failed reset ? */ + if (0) { + /* Set asic to idle mode after detect */ + avalon_idle(avalon); + avalon->device_fd = -1; + + avalon_close(fd); + } + return true; +} + +static inline void avalon_detect() +{ + serial_detect(&avalon_api, avalon_detect_one); +} + +static void __avalon_init(struct cgpu_info *avalon) +{ + applog(LOG_INFO, "Avalon: Opened on %s", avalon->device_path); +} + +static void avalon_init(struct cgpu_info *avalon) +{ + struct avalon_result ar; + int fd, ret; + + avalon->device_fd = -1; + fd = avalon_open(avalon->device_path, + avalon_info[avalon->device_id]->baud); + if (unlikely(fd == -1)) { + applog(LOG_ERR, "Avalon: Failed to open on %s", + avalon->device_path); + return; + } + + ret = avalon_reset(fd, &ar); + if (ret) { + avalon_close(fd); + return; + } + + avalon->device_fd = fd; + __avalon_init(avalon); +} + +static bool avalon_prepare(struct thr_info *thr) +{ + struct cgpu_info *avalon = thr->cgpu; + struct avalon_info *info = avalon_info[avalon->device_id]; + struct timeval now; + + avalon->works = calloc(info->miner_count * sizeof(struct work *), 1); + if (!avalon->works) + quit(1, "Failed to calloc avalon works in avalon_prepare"); + __avalon_init(avalon); + + gettimeofday(&now, NULL); + get_datestamp(avalon->init, &now); + return true; +} + +static void avalon_free_work(struct thr_info *thr, struct work **works) +{ + struct cgpu_info *avalon; + struct avalon_info *info; + int i; + + if (unlikely(!works)) + return; + + avalon = thr->cgpu; + info = avalon_info[avalon->device_id]; + + for (i = 0; i < info->miner_count; i++) { + if (likely(works[i])) { + work_completed(avalon, works[i]); + works[i] = NULL; + } + } +} + +static void do_avalon_close(struct thr_info *thr) +{ + struct avalon_result ar; + struct cgpu_info *avalon = thr->cgpu; + struct avalon_info *info = avalon_info[avalon->device_id]; + + sleep(1); + avalon_reset(avalon->device_fd, &ar); + avalon_idle(avalon); + avalon_close(avalon->device_fd); + avalon->device_fd = -1; + + info->no_matching_work = 0; + avalon_free_work(thr, info->bulk0); + avalon_free_work(thr, info->bulk1); + avalon_free_work(thr, info->bulk2); + avalon_free_work(thr, info->bulk3); +} + +static inline void record_temp_fan(struct avalon_info *info, struct avalon_result *ar, float *temp_avg) +{ + int max; + + info->fan0 = ar->fan0 * AVALON_FAN_FACTOR; + info->fan1 = ar->fan1 * AVALON_FAN_FACTOR; + info->fan2 = ar->fan2 * AVALON_FAN_FACTOR; + + info->temp0 = ar->temp0; + info->temp1 = ar->temp1; + info->temp2 = ar->temp2; + if (ar->temp0 & 0x80) { + ar->temp0 &= 0x7f; + info->temp0 = 0 - ((~ar->temp0 & 0x7f) + 1); + } + if (ar->temp1 & 0x80) { + ar->temp1 &= 0x7f; + info->temp1 = 0 - ((~ar->temp1 & 0x7f) + 1); + } + if (ar->temp2 & 0x80) { + ar->temp2 &= 0x7f; + info->temp2 = 0 - ((~ar->temp2 & 0x7f) + 1); + } + + *temp_avg = info->temp2; + + max = info->temp_max; + if (info->temp0 > max) + max = info->temp0; + if (info->temp1 > max) + max = info->temp1; + if (info->temp2 > max) + max = info->temp2; + if (max >= 100) { /* FIXME: fix the root cause on fpga controller firmware */ + if (opt_debug) { + applog(LOG_DEBUG, "Avalon: temp_max: %d", max); + hexdump((uint8_t *)ar, AVALON_READ_SIZE); + } + return; + } + + info->temp_max = max; +} + +static inline void adjust_fan(struct avalon_info *info) +{ + int temp_new; + + temp_new = info->temp_sum / info->temp_history_count; + + if (temp_new < 35) { + info->fan_pwm = AVALON_DEFAULT_FAN_MIN_PWM; + info->temp_old = temp_new; + } else if (temp_new > 55) { + info->fan_pwm = AVALON_DEFAULT_FAN_MAX_PWM; + info->temp_old = temp_new; + } else if (abs(temp_new - info->temp_old) >= 2) { + info->fan_pwm = AVALON_DEFAULT_FAN_MIN_PWM + (temp_new - 35) * 6.4; + info->temp_old = temp_new; + } +} + +static bool avalon_fill(struct cgpu_info *avalon) +{ + struct work *work = get_queued(avalon); + + if (unlikely(!work)) + return false; + avalon->queued++; + if (avalon->queued == avalon_info[avalon->device_id]->miner_count) + return true; + return false; +} + +static int64_t avalon_scanhash(struct thr_info *thr) +{ + struct cgpu_info *avalon; + struct work **works; + int fd, ret, full; + int64_t scanret = 0; + + struct avalon_info *info; + struct avalon_task at; + struct avalon_result ar; + int i, work_i0, work_i1, work_i2, work_i3; + int avalon_get_work_count; + + struct timeval tv_start, tv_finish, elapsed; + uint32_t nonce; + int64_t hash_count; + static int first_try = 0; + int result_count, result_wrong; + + avalon = thr->cgpu; + works = avalon->works; + info = avalon_info[avalon->device_id]; + avalon_get_work_count = info->miner_count; + + if (unlikely(avalon->device_fd == -1)) { + if (!avalon_prepare(thr)) { + applog(LOG_ERR, "AVA%i: Comms error(open)", + avalon->device_id); + dev_error(avalon, REASON_DEV_COMMS_ERROR); + /* fail the device if the reopen attempt fails */ + scanret = -1; + goto out; + } + } + fd = avalon->device_fd; +#ifndef WIN32 + tcflush(fd, TCOFLUSH); +#endif + + for (i = 0; i < avalon_get_work_count; i++) { + info->bulk0[i] = info->bulk1[i]; + info->bulk1[i] = info->bulk2[i]; + info->bulk2[i] = info->bulk3[i]; + info->bulk3[i] = works[i]; + applog(LOG_DEBUG, "Avalon: bulk0/1/2 buffer [%d]: %p, %p, %p, %p", + i, info->bulk0[i], info->bulk1[i], info->bulk2[i], info->bulk3[i]); + } + + i = 0; + while (true) { + avalon_init_task(&at, 0, 0, info->fan_pwm, + info->timeout, info->asic_count, + info->miner_count, 1, 0, info->frequency); + avalon_create_task(&at, works[i]); + ret = avalon_send_task(fd, &at, avalon); + if (unlikely(ret == AVA_SEND_ERROR || + (ret == AVA_SEND_BUFFER_EMPTY && + (i + 1 == avalon_get_work_count) && + first_try))) { + avalon_free_work(thr, info->bulk0); + avalon_free_work(thr, info->bulk1); + avalon_free_work(thr, info->bulk2); + avalon_free_work(thr, info->bulk3); + do_avalon_close(thr); + applog(LOG_ERR, "AVA%i: Comms error(buffer)", + avalon->device_id); + dev_error(avalon, REASON_DEV_COMMS_ERROR); + first_try = 0; + sleep(1); + avalon_init(avalon); + goto out; /* This should never happen */ + } + if (ret == AVA_SEND_BUFFER_EMPTY && (i + 1 == avalon_get_work_count)) { + first_try = 1; + ret = 0xffffffff; + goto out; + } + + works[i]->blk.nonce = 0xffffffff; + + if (ret == AVA_SEND_BUFFER_FULL) + break; + + i++; + } + if (unlikely(first_try)) + first_try = 0; + + elapsed.tv_sec = elapsed.tv_usec = 0; + gettimeofday(&tv_start, NULL); + + result_count = 0; + result_wrong = 0; + hash_count = 0; + while (true) { + work_i0 = work_i1 = work_i2 = work_i3 = -1; + + full = avalon_buffer_full(fd); + applog(LOG_DEBUG, "Avalon: Buffer full: %s", + ((full == AVA_BUFFER_FULL) ? "Yes" : "No")); + if (unlikely(full == AVA_BUFFER_EMPTY)) + break; + + ret = avalon_get_result(fd, &ar, thr, &tv_finish); + if (unlikely(ret == AVA_GETS_ERROR)) { + avalon_free_work(thr, info->bulk0); + avalon_free_work(thr, info->bulk1); + avalon_free_work(thr, info->bulk2); + avalon_free_work(thr, info->bulk3); + do_avalon_close(thr); + applog(LOG_ERR, + "AVA%i: Comms error(read)", avalon->device_id); + dev_error(avalon, REASON_DEV_COMMS_ERROR); + goto out; + } + if (unlikely(ret == AVA_GETS_TIMEOUT)) { + timersub(&tv_finish, &tv_start, &elapsed); + applog(LOG_DEBUG, "Avalon: no nonce in (%ld.%06lds)", + elapsed.tv_sec, elapsed.tv_usec); + continue; + } + if (unlikely(ret == AVA_GETS_RESTART)) { + avalon_free_work(thr, info->bulk0); + avalon_free_work(thr, info->bulk1); + avalon_free_work(thr, info->bulk2); + avalon_free_work(thr, info->bulk3); + break; + } + result_count++; + + work_i0 = avalon_decode_nonce(thr, info->bulk0, &ar, &nonce); + if (work_i0 < 0) { + work_i1 = avalon_decode_nonce(thr, info->bulk1, &ar, &nonce); + if (work_i1 < 0) { + work_i2 = avalon_decode_nonce(thr, info->bulk2, &ar, &nonce); + if (work_i2 < 0) { + work_i3 = avalon_decode_nonce(thr, info->bulk3, &ar, &nonce); + if (work_i3 < 0) { + info->no_matching_work++; + result_wrong++; + + if (opt_debug) { + timersub(&tv_finish, &tv_start, &elapsed); + applog(LOG_DEBUG,"Avalon: no matching work: %d" + " (%ld.%06lds)", info->no_matching_work, + elapsed.tv_sec, elapsed.tv_usec); + } + continue; + } else + submit_nonce(thr, info->bulk3[work_i3], nonce); + } else + submit_nonce(thr, info->bulk2[work_i2], nonce); + } else + submit_nonce(thr, info->bulk1[work_i1], nonce); + } else + submit_nonce(thr, info->bulk0[work_i0], nonce); + + hash_count += nonce; + if (opt_debug) { + timersub(&tv_finish, &tv_start, &elapsed); + applog(LOG_DEBUG, + "Avalon: nonce = 0x%08x = 0x%08llx hashes " + "(%ld.%06lds)", nonce, hash_count, + elapsed.tv_sec, elapsed.tv_usec); + } + } + if (result_wrong && result_count == result_wrong) { + /* This mean FPGA controller give all wrong result + * try to reset the Avalon */ + avalon_free_work(thr, info->bulk0); + avalon_free_work(thr, info->bulk1); + avalon_free_work(thr, info->bulk2); + avalon_free_work(thr, info->bulk3); + do_avalon_close(thr); + applog(LOG_ERR, + "AVA%i: FPGA controller mess up", avalon->device_id); + dev_error(avalon, REASON_DEV_COMMS_ERROR); + do_avalon_close(thr); + sleep(1); + avalon_init(avalon); + goto out; + } + + avalon_free_work(thr, info->bulk0); + + record_temp_fan(info, &ar, &(avalon->temp)); + applog(LOG_INFO, + "Avalon: Fan1: %d/m, Fan2: %d/m, Fan3: %d/m\t" + "Temp1: %dC, Temp2: %dC, Temp3: %dC, TempMAX: %dC", + info->fan0, info->fan1, info->fan2, + info->temp0, info->temp1, info->temp2, info->temp_max); + info->temp_history_index++; + info->temp_sum += info->temp2; + applog(LOG_DEBUG, "Avalon: temp_index: %d, temp_count: %d, temp_old: %d", + info->temp_history_index, info->temp_history_count, info->temp_old); + if (info->temp_history_index == info->temp_history_count) { + adjust_fan(info); + info->temp_history_index = 0; + info->temp_sum = 0; + } + + /* + * FIXME: Each work split to 10 pieces, each piece send to a + * asic(256MHs). one work can be mulit-nonce back. it is not + * easy calculate correct hash on such situation. so I simplely + * add each nonce to hash_count. base on Utility/m hash_count*2 + * give a very good result. + * + * Any patch will be great. + */ + scanret = hash_count * 2; +out: + avalon_free_work(thr, avalon->works); + avalon->queued = 0; + return scanret; +} + +static struct api_data *avalon_api_stats(struct cgpu_info *cgpu) +{ + struct api_data *root = NULL; + struct avalon_info *info = avalon_info[cgpu->device_id]; + + root = api_add_int(root, "baud", &(info->baud), false); + root = api_add_int(root, "miner_count", &(info->miner_count),false); + root = api_add_int(root, "asic_count", &(info->asic_count), false); + root = api_add_int(root, "read_count", &(info->read_count), false); + root = api_add_int(root, "timeout", &(info->timeout), false); + root = api_add_int(root, "frequency", &(info->frequency), false); + + root = api_add_int(root, "fan1", &(info->fan0), false); + root = api_add_int(root, "fan2", &(info->fan1), false); + root = api_add_int(root, "fan3", &(info->fan2), false); + + root = api_add_int(root, "temp1", &(info->temp0), false); + root = api_add_int(root, "temp2", &(info->temp1), false); + root = api_add_int(root, "temp3", &(info->temp2), false); + root = api_add_int(root, "temp_max", &(info->temp_max), false); + + root = api_add_int(root, "no_matching_work", &(info->no_matching_work), false); + root = api_add_int(root, "matching_work_count1", &(info->matching_work[0]), false); + root = api_add_int(root, "matching_work_count2", &(info->matching_work[1]), false); + root = api_add_int(root, "matching_work_count3", &(info->matching_work[2]), false); + root = api_add_int(root, "matching_work_count4", &(info->matching_work[3]), false); + root = api_add_int(root, "matching_work_count5", &(info->matching_work[4]), false); + root = api_add_int(root, "matching_work_count6", &(info->matching_work[5]), false); + root = api_add_int(root, "matching_work_count7", &(info->matching_work[6]), false); + root = api_add_int(root, "matching_work_count8", &(info->matching_work[7]), false); + root = api_add_int(root, "matching_work_count9", &(info->matching_work[8]), false); + root = api_add_int(root, "matching_work_count10", &(info->matching_work[9]), false); + root = api_add_int(root, "matching_work_count11", &(info->matching_work[10]), false); + root = api_add_int(root, "matching_work_count12", &(info->matching_work[11]), false); + root = api_add_int(root, "matching_work_count13", &(info->matching_work[12]), false); + root = api_add_int(root, "matching_work_count14", &(info->matching_work[13]), false); + root = api_add_int(root, "matching_work_count15", &(info->matching_work[14]), false); + root = api_add_int(root, "matching_work_count16", &(info->matching_work[15]), false); + root = api_add_int(root, "matching_work_count17", &(info->matching_work[16]), false); + root = api_add_int(root, "matching_work_count18", &(info->matching_work[17]), false); + root = api_add_int(root, "matching_work_count19", &(info->matching_work[18]), false); + root = api_add_int(root, "matching_work_count20", &(info->matching_work[19]), false); + root = api_add_int(root, "matching_work_count21", &(info->matching_work[20]), false); + root = api_add_int(root, "matching_work_count22", &(info->matching_work[21]), false); + root = api_add_int(root, "matching_work_count23", &(info->matching_work[22]), false); + root = api_add_int(root, "matching_work_count24", &(info->matching_work[23]), false); + + return root; +} + +static void avalon_shutdown(struct thr_info *thr) +{ + do_avalon_close(thr); +} + +struct device_drv avalon_api = { + .dname = "avalon", + .name = "AVA", + .drv_detect = avalon_detect, + .thread_prepare = avalon_prepare, + .hash_work = hash_queued_work, + .queue_full = avalon_fill, + .scanwork = avalon_scanhash, + .get_api_stats = avalon_api_stats, + .reinit_device = avalon_init, + .thread_shutdown = avalon_shutdown, +}; diff --git a/driver-avalon.h b/driver-avalon.h new file mode 100644 index 00000000..d4fb9d9c --- /dev/null +++ b/driver-avalon.h @@ -0,0 +1,136 @@ +/* + * Copyright 2013 Avalon project + * + * 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. + */ + +#ifndef AVALON_H +#define AVALON_H + +#ifdef USE_AVALON + +#define AVALON_TIME_FACTOR 10 +#define AVALON_RESET_FAULT_DECISECONDS 1 +#define AVALON_MINER_THREADS 1 + +#define AVALON_IO_SPEED 115200 +#define AVALON_HASH_TIME_FACTOR ((float)1.67/0x32) +#define AVALON_RESET_PITCH (300*1000*1000) + +#define AVALON_FAN_FACTOR 120 +#define AVALON_DEFAULT_FAN_MAX_PWM 0xA0 /* 100% */ +#define AVALON_DEFAULT_FAN_MIN_PWM 0x20 /* 20% */ + +#define AVALON_DEFAULT_TIMEOUT 0x32 +#define AVALON_DEFAULT_FREQUENCY 256 +#define AVALON_DEFAULT_MINER_NUM 0x20 +#define AVALON_DEFAULT_ASIC_NUM 0xA + +struct avalon_task { + uint8_t reset :1; + uint8_t flush_fifo :1; + uint8_t fan_eft :1; + uint8_t timer_eft :1; + uint8_t asic_num :4; + uint8_t fan_pwm_data; + uint8_t timeout_data; + uint8_t miner_num; + + uint8_t nonce_elf :1; + uint8_t gate_miner_elf :1; + uint8_t asic_pll :1; + uint8_t gate_miner :1; + uint8_t _pad0 :4; + uint8_t _pad1[3]; + uint32_t _pad2; + + uint8_t midstate[32]; + uint8_t data[12]; +} __attribute__((packed, aligned(4))); + +struct avalon_result { + uint32_t nonce; + uint8_t data[12]; + uint8_t midstate[32]; + + uint8_t fan0; + uint8_t fan1; + uint8_t fan2; + uint8_t temp0; + uint8_t temp1; + uint8_t temp2; + uint8_t _pad0[2]; + + uint16_t fifo_wp; + uint16_t fifo_rp; + uint8_t chip_num; + uint8_t pwm_data; + uint8_t timeout; + uint8_t miner_num; +} __attribute__((packed, aligned(4))); + +struct avalon_info { + int read_count; + + int baud; + int miner_count; + int asic_count; + int timeout; + + int fan0; + int fan1; + int fan2; + + int temp0; + int temp1; + int temp2; + int temp_max; + int temp_history_count; + int temp_history_index; + int temp_sum; + int temp_old; + int fan_pwm; + + int no_matching_work; + int matching_work[AVALON_DEFAULT_MINER_NUM]; + struct work *bulk0[AVALON_DEFAULT_MINER_NUM]; + struct work *bulk1[AVALON_DEFAULT_MINER_NUM]; + struct work *bulk2[AVALON_DEFAULT_MINER_NUM]; + struct work *bulk3[AVALON_DEFAULT_MINER_NUM]; + + int frequency; +}; + +#define AVALON_WRITE_SIZE (sizeof(struct avalon_task)) +#define AVALON_READ_SIZE (sizeof(struct avalon_result)) + +#define AVA_GETS_ERROR -1 +#define AVA_GETS_OK 0 +#define AVA_GETS_RESTART 1 +#define AVA_GETS_TIMEOUT 2 + +#define AVA_SEND_ERROR -1 +#define AVA_SEND_OK 0 +#define AVA_SEND_BUFFER_EMPTY 1 +#define AVA_SEND_BUFFER_FULL 2 + +#define AVA_BUFFER_FULL 0 +#define AVA_BUFFER_EMPTY 1 + +#define avalon_open2(devpath, baud, purge) serial_open(devpath, baud, AVALON_RESET_FAULT_DECISECONDS, purge) +#define avalon_open(devpath, baud) avalon_open2(devpath, baud, true) +#define avalon_close(fd) close(fd) + +#define avalon_buffer_full(fd) get_serial_cts(fd) + +#define AVALON_READ_TIME(baud) ((double)AVALON_READ_SIZE * (double)8.0 / (double)(baud)) +#define ASSERT1(condition) __maybe_unused static char sizeof_uint32_t_must_be_4[(condition)?1:-1] +ASSERT1(sizeof(uint32_t) == 4); + +extern struct avalon_info **avalon_info; + +#endif /* USE_AVALON */ +#endif /* AVALON_H */ diff --git a/fpgautils.c b/fpgautils.c index 489c89cf..61706a57 100644 --- a/fpgautils.c +++ b/fpgautils.c @@ -1,4 +1,5 @@ /* + * Copyright 2013 Con Kolivas * Copyright 2012 Luke Dashjr * Copyright 2012 Andrew Smith * @@ -19,6 +20,7 @@ #ifndef WIN32 #include #include +#include #include #include #include @@ -32,10 +34,12 @@ #ifdef HAVE_LIBUDEV #include +#include #endif #include "elist.h" #include "logging.h" +#include "miner.h" #include "fpgautils.h" #ifdef HAVE_LIBUDEV @@ -382,6 +386,14 @@ int serial_open(const char *devpath, unsigned long baud, signed short timeout, b switch (baud) { case 0: break; + case 19200: + cfsetispeed(&my_termios, B19200); + cfsetospeed(&my_termios, B19200); + break; + case 38400: + cfsetispeed(&my_termios, B38400); + cfsetospeed(&my_termios, B38400); + break; case 57600: cfsetispeed(&my_termios, B57600); cfsetospeed(&my_termios, B57600); @@ -570,4 +582,14 @@ size_t _select_write(int fd, char *buf, size_t siz, struct timeval *timeout) return wrote; } +int get_serial_cts(int fd) +{ + int flags; + + if (!fd) + return -1; + + ioctl(fd, TIOCMGET, &flags); + return (flags & TIOCM_CTS) ? 1 : 0; +} #endif // ! WIN32 diff --git a/fpgautils.h b/fpgautils.h index b979b6c6..8a7dd834 100644 --- a/fpgautils.h +++ b/fpgautils.h @@ -36,6 +36,8 @@ extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char *eol); extern FILE *open_bitstream(const char *dname, const char *filename); +extern int get_serial_cts(int fd); + #ifndef WIN32 extern const struct timeval tv_timeout_default; extern const struct timeval tv_inter_char_default; diff --git a/hexdump.c b/hexdump.c new file mode 100644 index 00000000..8951dde8 --- /dev/null +++ b/hexdump.c @@ -0,0 +1,77 @@ +/* + * hexdump implementation without depenecies to *printf() + * output is equal to 'hexdump -C' + * should be compatible to 64bit architectures + * + * Copyright (c) 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 . + */ + +#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 uint8_t *p, unsigned int len) +{ + 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); + } +} diff --git a/miner.h b/miner.h index 68f17c7b..58095e85 100644 --- a/miner.h +++ b/miner.h @@ -120,9 +120,11 @@ static inline int fsync (int fd) #if (!defined(WIN32) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \ || (defined(WIN32) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) -#define bswap_16 __builtin_bswap16 -#define bswap_32 __builtin_bswap32 -#define bswap_64 __builtin_bswap64 +#ifndef bswap_16 + #define bswap_16 __builtin_bswap16 + #define bswap_32 __builtin_bswap32 + #define bswap_64 __builtin_bswap64 +#endif #else #if HAVE_BYTESWAP_H #include @@ -421,8 +423,12 @@ struct cgpu_info { #ifdef USE_USBUTILS struct cg_usb_device *usbdev; #endif -#ifdef USE_ICARUS +#if defined(USE_ICARUS) || defined(USE_AVALON) int device_fd; +#endif +#ifdef USE_AVALON + struct work **works; + int queued; #endif }; #ifdef USE_USBUTILS @@ -786,6 +792,9 @@ extern bool opt_restart; extern char *opt_icarus_options; extern char *opt_icarus_timing; extern bool opt_worktime; +#ifdef USE_AVALON +extern char *opt_avalon_options; +#endif #ifdef USE_USBUTILS extern char *opt_usb_select; extern int opt_usbdump; From 180230220f4af587f175d06cd0bc2fd7e7804c6c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Apr 2013 18:31:20 +1100 Subject: [PATCH 04/79] Rneame avalon_api to avalon_drv. --- cgminer.c | 4 ++-- driver-avalon.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index edcf9eb4..b68bc10f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -6814,7 +6814,7 @@ extern struct device_drv icarus_drv; #endif #ifdef USE_AVALON -extern struct device_drv avalon_api; +extern struct device_drv avalon_drv; #endif #ifdef USE_MODMINER @@ -7338,7 +7338,7 @@ int main(int argc, char *argv[]) #ifdef USE_AVALON if (!opt_scrypt) - avalon_api.drv_detect(); + avalon_drv.drv_detect(); #endif #ifdef USE_BFLSC diff --git a/driver-avalon.c b/driver-avalon.c index 33eae736..5ce47650 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -1046,7 +1046,7 @@ static void avalon_shutdown(struct thr_info *thr) do_avalon_close(thr); } -struct device_drv avalon_api = { +struct device_drv avalon_drv = { .dname = "avalon", .name = "AVA", .drv_detect = avalon_detect, From f0806c682849a2d310081a41772022b41d8d52da Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Apr 2013 18:34:05 +1100 Subject: [PATCH 05/79] Actually put the work in the avalon queue. --- driver-avalon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon.c b/driver-avalon.c index 5ce47650..48bb870f 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -768,7 +768,7 @@ static bool avalon_fill(struct cgpu_info *avalon) if (unlikely(!work)) return false; - avalon->queued++; + avalon->works[avalon->queued++] = work; if (avalon->queued == avalon_info[avalon->device_id]->miner_count) return true; return false; From 23fa953bfcdb533d3d239dbd583a8e96d78370ee Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Apr 2013 18:51:20 +1100 Subject: [PATCH 06/79] Check enough work is queued before queueing more in avalon_fill. --- driver-avalon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/driver-avalon.c b/driver-avalon.c index 48bb870f..cfa2b7a2 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -768,6 +768,8 @@ static bool avalon_fill(struct cgpu_info *avalon) if (unlikely(!work)) return false; + if (avalon->queued == avalon_info[avalon->device_id]->miner_count) + return true; avalon->works[avalon->queued++] = work; if (avalon->queued == avalon_info[avalon->device_id]->miner_count) return true; From 8959f8d0ae8f35d35cc193b7c1468c10fbec7b6e Mon Sep 17 00:00:00 2001 From: Kano Date: Fri, 5 Apr 2013 20:06:03 +1100 Subject: [PATCH 07/79] cgminer.c -S help to only say Icarus --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index f2a9e43a..7779c9c7 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1102,7 +1102,7 @@ static struct opt_table opt_config_table[] = { #ifdef USE_FPGA_SERIAL OPT_WITH_ARG("--scan-serial|-S", add_serial, NULL, NULL, - "Serial port to probe for FPGA Mining device"), + "Serial port to probe for Icarus FPGA Mining device"), #endif OPT_WITH_ARG("--scan-time|-s", set_int_0_to_9999, opt_show_intval, &opt_scantime, From 2f371f13f5dd3cd20edca346927e12137d671f94 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Apr 2013 20:26:29 +1100 Subject: [PATCH 08/79] Use correct struct device_drv for avalon_drv. --- driver-avalon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index cfa2b7a2..8af3c4cc 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -40,7 +40,7 @@ static int option_offset = -1; struct avalon_info **avalon_info; -struct device_drv avalon_api; +struct device_drv avalon_drv; static int avalon_init_task(struct avalon_task *at, uint8_t reset, uint8_t ff, uint8_t fan, @@ -552,7 +552,7 @@ static bool avalon_detect_one(const char *devpath) /* We have a real Avalon! */ avalon = calloc(1, sizeof(struct cgpu_info)); - avalon->drv = &avalon_api; + avalon->drv = &avalon_drv; avalon->device_path = strdup(devpath); avalon->device_fd = fd; avalon->threads = AVALON_MINER_THREADS; @@ -613,7 +613,7 @@ static bool avalon_detect_one(const char *devpath) static inline void avalon_detect() { - serial_detect(&avalon_api, avalon_detect_one); + serial_detect(&avalon_drv, avalon_detect_one); } static void __avalon_init(struct cgpu_info *avalon) From 67c5da49b66557631ab9d1db980b7505b33485f9 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Apr 2013 21:01:42 +1100 Subject: [PATCH 09/79] Members of cgpu_info for avalon are not meant to be in the union. --- miner.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner.h b/miner.h index 58095e85..819d2422 100644 --- a/miner.h +++ b/miner.h @@ -426,11 +426,11 @@ struct cgpu_info { #if defined(USE_ICARUS) || defined(USE_AVALON) int device_fd; #endif + }; #ifdef USE_AVALON struct work **works; int queued; #endif - }; #ifdef USE_USBUTILS struct cg_usb_info usbinfo; #endif From 2f75a5d89e9d9ef1a8dba409b1a69582a7107c95 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 01:03:21 +1100 Subject: [PATCH 10/79] Simplify avalon scanhash code using the new find_queued_work_bymidstate function. Partially works only. --- driver-avalon.c | 133 ++++++++++++++---------------------------------- driver-avalon.h | 4 -- 2 files changed, 39 insertions(+), 98 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 8af3c4cc..01970626 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -272,6 +272,7 @@ static int avalon_get_result(int fd, struct avalon_result *ar, memset(result, 0, AVALON_READ_SIZE); ret = avalon_gets(fd, result, read_count, thr, tv_finish); + memset(ar, 0, sizeof(struct avalon_result)); if (ret == AVA_GETS_OK) { if (opt_debug) { applog(LOG_DEBUG, "Avalon: get:"); @@ -283,35 +284,28 @@ static int avalon_get_result(int fd, struct avalon_result *ar, return ret; } -static int avalon_decode_nonce(struct thr_info *thr, struct work **work, - struct avalon_result *ar, uint32_t *nonce) +static bool avalon_decode_nonce(struct thr_info *thr, struct avalon_result *ar, + uint32_t *nonce) { struct cgpu_info *avalon; struct avalon_info *info; int avalon_get_work_count, i; - - if (unlikely(!work)) - return -1; + struct work *work; avalon = thr->cgpu; - info = avalon_info[avalon->device_id]; - avalon_get_work_count = info->miner_count; + if (unlikely(!avalon->works)) + return false; - for (i = 0; i < avalon_get_work_count; i++) { - if (work[i] && - !memcmp(ar->data, work[i]->data + 64, 12) && - !memcmp(ar->midstate, work[i]->midstate, 32)) - break; - } - if (i == avalon_get_work_count) - return -1; + work = find_queued_work_bymidstate(avalon, ar->midstate, 32, ar->data, 64, 12); + if (!work) + return false; + info = avalon_info[avalon->device_id]; info->matching_work[i]++; *nonce = htole32(ar->nonce); + submit_nonce(thr, work, *nonce); - applog(LOG_DEBUG, "Avalon: match to work[%d](%p): %d",i, work[i], - info->matching_work[i]); - return i; + return true; } static int avalon_reset(int fd, struct avalon_result *ar) @@ -661,16 +655,18 @@ static bool avalon_prepare(struct thr_info *thr) return true; } -static void avalon_free_work(struct thr_info *thr, struct work **works) +static void avalon_free_work(struct thr_info *thr) { struct cgpu_info *avalon; struct avalon_info *info; + struct work **works; int i; - if (unlikely(!works)) - return; - avalon = thr->cgpu; + avalon->queued = 0; + if (unlikely(!avalon->works)) + return; + works = avalon->works; info = avalon_info[avalon->device_id]; for (i = 0; i < info->miner_count; i++) { @@ -687,6 +683,7 @@ static void do_avalon_close(struct thr_info *thr) struct cgpu_info *avalon = thr->cgpu; struct avalon_info *info = avalon_info[avalon->device_id]; + avalon_free_work(thr); sleep(1); avalon_reset(avalon->device_fd, &ar); avalon_idle(avalon); @@ -694,10 +691,6 @@ static void do_avalon_close(struct thr_info *thr) avalon->device_fd = -1; info->no_matching_work = 0; - avalon_free_work(thr, info->bulk0); - avalon_free_work(thr, info->bulk1); - avalon_free_work(thr, info->bulk2); - avalon_free_work(thr, info->bulk3); } static inline void record_temp_fan(struct avalon_info *info, struct avalon_result *ar, float *temp_avg) @@ -781,12 +774,11 @@ static int64_t avalon_scanhash(struct thr_info *thr) struct cgpu_info *avalon; struct work **works; int fd, ret, full; - int64_t scanret = 0; struct avalon_info *info; struct avalon_task at; struct avalon_result ar; - int i, work_i0, work_i1, work_i2, work_i3; + int i; int avalon_get_work_count; struct timeval tv_start, tv_finish, elapsed; @@ -806,8 +798,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) avalon->device_id); dev_error(avalon, REASON_DEV_COMMS_ERROR); /* fail the device if the reopen attempt fails */ - scanret = -1; - goto out; + return -1; } } fd = avalon->device_fd; @@ -815,15 +806,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) tcflush(fd, TCOFLUSH); #endif - for (i = 0; i < avalon_get_work_count; i++) { - info->bulk0[i] = info->bulk1[i]; - info->bulk1[i] = info->bulk2[i]; - info->bulk2[i] = info->bulk3[i]; - info->bulk3[i] = works[i]; - applog(LOG_DEBUG, "Avalon: bulk0/1/2 buffer [%d]: %p, %p, %p, %p", - i, info->bulk0[i], info->bulk1[i], info->bulk2[i], info->bulk3[i]); - } - i = 0; while (true) { avalon_init_task(&at, 0, 0, info->fan_pwm, @@ -835,10 +817,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) (ret == AVA_SEND_BUFFER_EMPTY && (i + 1 == avalon_get_work_count) && first_try))) { - avalon_free_work(thr, info->bulk0); - avalon_free_work(thr, info->bulk1); - avalon_free_work(thr, info->bulk2); - avalon_free_work(thr, info->bulk3); do_avalon_close(thr); applog(LOG_ERR, "AVA%i: Comms error(buffer)", avalon->device_id); @@ -846,12 +824,11 @@ static int64_t avalon_scanhash(struct thr_info *thr) first_try = 0; sleep(1); avalon_init(avalon); - goto out; /* This should never happen */ + return 0; /* This should never happen */ } if (ret == AVA_SEND_BUFFER_EMPTY && (i + 1 == avalon_get_work_count)) { first_try = 1; - ret = 0xffffffff; - goto out; + return 0xffffffff; } works[i]->blk.nonce = 0xffffffff; @@ -871,8 +848,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) result_wrong = 0; hash_count = 0; while (true) { - work_i0 = work_i1 = work_i2 = work_i3 = -1; - full = avalon_buffer_full(fd); applog(LOG_DEBUG, "Avalon: Buffer full: %s", ((full == AVA_BUFFER_FULL) ? "Yes" : "No")); @@ -881,15 +856,11 @@ static int64_t avalon_scanhash(struct thr_info *thr) ret = avalon_get_result(fd, &ar, thr, &tv_finish); if (unlikely(ret == AVA_GETS_ERROR)) { - avalon_free_work(thr, info->bulk0); - avalon_free_work(thr, info->bulk1); - avalon_free_work(thr, info->bulk2); - avalon_free_work(thr, info->bulk3); do_avalon_close(thr); applog(LOG_ERR, "AVA%i: Comms error(read)", avalon->device_id); dev_error(avalon, REASON_DEV_COMMS_ERROR); - goto out; + return 0; } if (unlikely(ret == AVA_GETS_TIMEOUT)) { timersub(&tv_finish, &tv_start, &elapsed); @@ -898,40 +869,22 @@ static int64_t avalon_scanhash(struct thr_info *thr) continue; } if (unlikely(ret == AVA_GETS_RESTART)) { - avalon_free_work(thr, info->bulk0); - avalon_free_work(thr, info->bulk1); - avalon_free_work(thr, info->bulk2); - avalon_free_work(thr, info->bulk3); break; } result_count++; - work_i0 = avalon_decode_nonce(thr, info->bulk0, &ar, &nonce); - if (work_i0 < 0) { - work_i1 = avalon_decode_nonce(thr, info->bulk1, &ar, &nonce); - if (work_i1 < 0) { - work_i2 = avalon_decode_nonce(thr, info->bulk2, &ar, &nonce); - if (work_i2 < 0) { - work_i3 = avalon_decode_nonce(thr, info->bulk3, &ar, &nonce); - if (work_i3 < 0) { - info->no_matching_work++; - result_wrong++; - - if (opt_debug) { - timersub(&tv_finish, &tv_start, &elapsed); - applog(LOG_DEBUG,"Avalon: no matching work: %d" - " (%ld.%06lds)", info->no_matching_work, - elapsed.tv_sec, elapsed.tv_usec); - } - continue; - } else - submit_nonce(thr, info->bulk3[work_i3], nonce); - } else - submit_nonce(thr, info->bulk2[work_i2], nonce); - } else - submit_nonce(thr, info->bulk1[work_i1], nonce); - } else - submit_nonce(thr, info->bulk0[work_i0], nonce); + if (!avalon_decode_nonce(thr, &ar, &nonce)) { + info->no_matching_work++; + result_wrong++; + + if (opt_debug) { + timersub(&tv_finish, &tv_start, &elapsed); + applog(LOG_DEBUG,"Avalon: no matching work: %d" + " (%ld.%06lds)", info->no_matching_work, + elapsed.tv_sec, elapsed.tv_usec); + } + continue; + } hash_count += nonce; if (opt_debug) { @@ -945,10 +898,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) if (result_wrong && result_count == result_wrong) { /* This mean FPGA controller give all wrong result * try to reset the Avalon */ - avalon_free_work(thr, info->bulk0); - avalon_free_work(thr, info->bulk1); - avalon_free_work(thr, info->bulk2); - avalon_free_work(thr, info->bulk3); do_avalon_close(thr); applog(LOG_ERR, "AVA%i: FPGA controller mess up", avalon->device_id); @@ -956,10 +905,10 @@ static int64_t avalon_scanhash(struct thr_info *thr) do_avalon_close(thr); sleep(1); avalon_init(avalon); - goto out; + return 0; } - avalon_free_work(thr, info->bulk0); + avalon_free_work(thr); record_temp_fan(info, &ar, &(avalon->temp)); applog(LOG_INFO, @@ -986,11 +935,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) * * Any patch will be great. */ - scanret = hash_count * 2; -out: - avalon_free_work(thr, avalon->works); - avalon->queued = 0; - return scanret; + return hash_count * 2; } static struct api_data *avalon_api_stats(struct cgpu_info *cgpu) diff --git a/driver-avalon.h b/driver-avalon.h index d4fb9d9c..f8607409 100644 --- a/driver-avalon.h +++ b/driver-avalon.h @@ -96,10 +96,6 @@ struct avalon_info { int no_matching_work; int matching_work[AVALON_DEFAULT_MINER_NUM]; - struct work *bulk0[AVALON_DEFAULT_MINER_NUM]; - struct work *bulk1[AVALON_DEFAULT_MINER_NUM]; - struct work *bulk2[AVALON_DEFAULT_MINER_NUM]; - struct work *bulk3[AVALON_DEFAULT_MINER_NUM]; int frequency; }; From 7dda3e44024480033b74b240751bd731bbc386f6 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 01:34:40 +1100 Subject: [PATCH 11/79] Rename the confusing avalon_info pointer. --- driver-avalon.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 01970626..7ecf7d87 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -39,7 +39,7 @@ #include "hexdump.c" static int option_offset = -1; -struct avalon_info **avalon_info; +struct avalon_info **avalon_infos; struct device_drv avalon_drv; static int avalon_init_task(struct avalon_task *at, @@ -171,7 +171,7 @@ static int avalon_send_task(int fd, const struct avalon_task *at, buf[4] = tt; #endif if (likely(avalon)) { - info = avalon_info[avalon->device_id]; + info = avalon_infos[avalon->device_id]; delay = nr_len * 10 * 1000000000ULL; delay = delay / info->baud; } @@ -265,7 +265,7 @@ static int avalon_get_result(int fd, struct avalon_result *ar, if (likely(thr)) { avalon = thr->cgpu; - info = avalon_info[avalon->device_id]; + info = avalon_infos[avalon->device_id]; read_count = info->read_count; } @@ -300,7 +300,7 @@ static bool avalon_decode_nonce(struct thr_info *thr, struct avalon_result *ar, if (!work) return false; - info = avalon_info[avalon->device_id]; + info = avalon_infos[avalon->device_id]; info->matching_work[i]++; *nonce = htole32(ar->nonce); submit_nonce(thr, work, *nonce); @@ -360,7 +360,7 @@ static void avalon_idle(struct cgpu_info *avalon) struct avalon_task at; int fd = avalon->device_fd; - struct avalon_info *info = avalon_info[avalon->device_id]; + struct avalon_info *info = avalon_infos[avalon->device_id]; int avalon_get_work_count = info->miner_count; i = 0; @@ -559,19 +559,19 @@ static bool avalon_detect_one(const char *devpath) * return false; */ } - avalon_info = realloc(avalon_info, + avalon_infos = realloc(avalon_infos, sizeof(struct avalon_info *) * (total_devices + 1)); applog(LOG_INFO, "Avalon Detect: Found at %s, mark as %d", devpath, avalon->device_id); - avalon_info[avalon->device_id] = (struct avalon_info *) + avalon_infos[avalon->device_id] = (struct avalon_info *) malloc(sizeof(struct avalon_info)); - if (unlikely(!(avalon_info[avalon->device_id]))) - quit(1, "Failed to malloc avalon_info"); + if (unlikely(!(avalon_infos[avalon->device_id]))) + quit(1, "Failed to malloc avalon_infos"); - info = avalon_info[avalon->device_id]; + info = avalon_infos[avalon->device_id]; memset(info, 0, sizeof(struct avalon_info)); @@ -622,7 +622,7 @@ static void avalon_init(struct cgpu_info *avalon) avalon->device_fd = -1; fd = avalon_open(avalon->device_path, - avalon_info[avalon->device_id]->baud); + avalon_infos[avalon->device_id]->baud); if (unlikely(fd == -1)) { applog(LOG_ERR, "Avalon: Failed to open on %s", avalon->device_path); @@ -642,7 +642,7 @@ static void avalon_init(struct cgpu_info *avalon) static bool avalon_prepare(struct thr_info *thr) { struct cgpu_info *avalon = thr->cgpu; - struct avalon_info *info = avalon_info[avalon->device_id]; + struct avalon_info *info = avalon_infos[avalon->device_id]; struct timeval now; avalon->works = calloc(info->miner_count * sizeof(struct work *), 1); @@ -667,7 +667,7 @@ static void avalon_free_work(struct thr_info *thr) if (unlikely(!avalon->works)) return; works = avalon->works; - info = avalon_info[avalon->device_id]; + info = avalon_infos[avalon->device_id]; for (i = 0; i < info->miner_count; i++) { if (likely(works[i])) { @@ -681,7 +681,7 @@ static void do_avalon_close(struct thr_info *thr) { struct avalon_result ar; struct cgpu_info *avalon = thr->cgpu; - struct avalon_info *info = avalon_info[avalon->device_id]; + struct avalon_info *info = avalon_infos[avalon->device_id]; avalon_free_work(thr); sleep(1); @@ -761,10 +761,10 @@ static bool avalon_fill(struct cgpu_info *avalon) if (unlikely(!work)) return false; - if (avalon->queued == avalon_info[avalon->device_id]->miner_count) + if (avalon->queued == avalon_infos[avalon->device_id]->miner_count) return true; avalon->works[avalon->queued++] = work; - if (avalon->queued == avalon_info[avalon->device_id]->miner_count) + if (avalon->queued == avalon_infos[avalon->device_id]->miner_count) return true; return false; } @@ -789,7 +789,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) avalon = thr->cgpu; works = avalon->works; - info = avalon_info[avalon->device_id]; + info = avalon_infos[avalon->device_id]; avalon_get_work_count = info->miner_count; if (unlikely(avalon->device_fd == -1)) { @@ -941,7 +941,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) static struct api_data *avalon_api_stats(struct cgpu_info *cgpu) { struct api_data *root = NULL; - struct avalon_info *info = avalon_info[cgpu->device_id]; + struct avalon_info *info = avalon_infos[cgpu->device_id]; root = api_add_int(root, "baud", &(info->baud), false); root = api_add_int(root, "miner_count", &(info->miner_count),false); From 6752c24750d4bf6a84f9ffd38e9b1f92caaa8185 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 01:42:45 +1100 Subject: [PATCH 12/79] Remove unused per unit matching work count for avalon. --- driver-avalon.c | 29 +++-------------------------- driver-avalon.h | 2 +- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 7ecf7d87..69e78ef8 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -289,7 +289,7 @@ static bool avalon_decode_nonce(struct thr_info *thr, struct avalon_result *ar, { struct cgpu_info *avalon; struct avalon_info *info; - int avalon_get_work_count, i; + int avalon_get_work_count; struct work *work; avalon = thr->cgpu; @@ -301,7 +301,7 @@ static bool avalon_decode_nonce(struct thr_info *thr, struct avalon_result *ar, return false; info = avalon_infos[avalon->device_id]; - info->matching_work[i]++; + info->matching_work++; *nonce = htole32(ar->nonce); submit_nonce(thr, work, *nonce); @@ -960,30 +960,7 @@ static struct api_data *avalon_api_stats(struct cgpu_info *cgpu) root = api_add_int(root, "temp_max", &(info->temp_max), false); root = api_add_int(root, "no_matching_work", &(info->no_matching_work), false); - root = api_add_int(root, "matching_work_count1", &(info->matching_work[0]), false); - root = api_add_int(root, "matching_work_count2", &(info->matching_work[1]), false); - root = api_add_int(root, "matching_work_count3", &(info->matching_work[2]), false); - root = api_add_int(root, "matching_work_count4", &(info->matching_work[3]), false); - root = api_add_int(root, "matching_work_count5", &(info->matching_work[4]), false); - root = api_add_int(root, "matching_work_count6", &(info->matching_work[5]), false); - root = api_add_int(root, "matching_work_count7", &(info->matching_work[6]), false); - root = api_add_int(root, "matching_work_count8", &(info->matching_work[7]), false); - root = api_add_int(root, "matching_work_count9", &(info->matching_work[8]), false); - root = api_add_int(root, "matching_work_count10", &(info->matching_work[9]), false); - root = api_add_int(root, "matching_work_count11", &(info->matching_work[10]), false); - root = api_add_int(root, "matching_work_count12", &(info->matching_work[11]), false); - root = api_add_int(root, "matching_work_count13", &(info->matching_work[12]), false); - root = api_add_int(root, "matching_work_count14", &(info->matching_work[13]), false); - root = api_add_int(root, "matching_work_count15", &(info->matching_work[14]), false); - root = api_add_int(root, "matching_work_count16", &(info->matching_work[15]), false); - root = api_add_int(root, "matching_work_count17", &(info->matching_work[16]), false); - root = api_add_int(root, "matching_work_count18", &(info->matching_work[17]), false); - root = api_add_int(root, "matching_work_count19", &(info->matching_work[18]), false); - root = api_add_int(root, "matching_work_count20", &(info->matching_work[19]), false); - root = api_add_int(root, "matching_work_count21", &(info->matching_work[20]), false); - root = api_add_int(root, "matching_work_count22", &(info->matching_work[21]), false); - root = api_add_int(root, "matching_work_count23", &(info->matching_work[22]), false); - root = api_add_int(root, "matching_work_count24", &(info->matching_work[23]), false); + root = api_add_int(root, "matching_work_count", &(info->matching_work), false); return root; } diff --git a/driver-avalon.h b/driver-avalon.h index f8607409..c040d03d 100644 --- a/driver-avalon.h +++ b/driver-avalon.h @@ -95,7 +95,7 @@ struct avalon_info { int fan_pwm; int no_matching_work; - int matching_work[AVALON_DEFAULT_MINER_NUM]; + int matching_work; int frequency; }; From 67be00e41e491bbe3e1582daf1e59ef006ef6411 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 02:25:48 +1100 Subject: [PATCH 13/79] Create an array of 4 lots of work for avalon and cycle through them. --- driver-avalon.c | 48 +++++++++++++++++++++++++++++++++++++++--------- miner.h | 1 + 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 69e78ef8..5d4656dd 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -645,7 +645,7 @@ static bool avalon_prepare(struct thr_info *thr) struct avalon_info *info = avalon_infos[avalon->device_id]; struct timeval now; - avalon->works = calloc(info->miner_count * sizeof(struct work *), 1); + avalon->works = calloc(info->miner_count * sizeof(struct work *), 4); if (!avalon->works) quit(1, "Failed to calloc avalon works in avalon_prepare"); __avalon_init(avalon); @@ -669,7 +669,31 @@ static void avalon_free_work(struct thr_info *thr) works = avalon->works; info = avalon_infos[avalon->device_id]; - for (i = 0; i < info->miner_count; i++) { + for (i = 0; i < info->miner_count * 4; i++) { + if (works[i]) { + work_completed(avalon, works[i]); + works[i] = NULL; + } + } +} + +static void avalon_free_work_array(struct thr_info *thr) +{ + struct cgpu_info *avalon; + struct work **works; + int i, j, mc, wa; + + avalon = thr->cgpu; + avalon->queued = 0; + if (unlikely(!avalon->works)) + return; + works = avalon->works; + mc = avalon_infos[avalon->device_id]->miner_count; + wa = avalon->work_array + 1; + if (wa > 3) + wa = 0; + + for (i = wa * mc, j = 0; j < mc; i++, j++) { if (likely(works[i])) { work_completed(avalon, works[i]); works[i] = NULL; @@ -758,13 +782,14 @@ static inline void adjust_fan(struct avalon_info *info) static bool avalon_fill(struct cgpu_info *avalon) { struct work *work = get_queued(avalon); + int mc = avalon_infos[avalon->device_id]->miner_count; if (unlikely(!work)) return false; - if (avalon->queued == avalon_infos[avalon->device_id]->miner_count) + if (avalon->queued >= mc) return true; - avalon->works[avalon->queued++] = work; - if (avalon->queued == avalon_infos[avalon->device_id]->miner_count) + avalon->works[avalon->work_array * mc + avalon->queued++] = work; + if (avalon->queued >= mc) return true; return false; } @@ -780,6 +805,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) struct avalon_result ar; int i; int avalon_get_work_count; + int start_count, end_count; struct timeval tv_start, tv_finish, elapsed; uint32_t nonce; @@ -806,7 +832,9 @@ static int64_t avalon_scanhash(struct thr_info *thr) tcflush(fd, TCOFLUSH); #endif - i = 0; + start_count = avalon->work_array * avalon_get_work_count; + end_count = start_count + avalon_get_work_count; + i = start_count; while (true) { avalon_init_task(&at, 0, 0, info->fan_pwm, info->timeout, info->asic_count, @@ -815,7 +843,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) ret = avalon_send_task(fd, &at, avalon); if (unlikely(ret == AVA_SEND_ERROR || (ret == AVA_SEND_BUFFER_EMPTY && - (i + 1 == avalon_get_work_count) && + (i + 1 == end_count) && first_try))) { do_avalon_close(thr); applog(LOG_ERR, "AVA%i: Comms error(buffer)", @@ -826,7 +854,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) avalon_init(avalon); return 0; /* This should never happen */ } - if (ret == AVA_SEND_BUFFER_EMPTY && (i + 1 == avalon_get_work_count)) { + if (ret == AVA_SEND_BUFFER_EMPTY && (i + 1 == end_count)) { first_try = 1; return 0xffffffff; } @@ -908,7 +936,9 @@ static int64_t avalon_scanhash(struct thr_info *thr) return 0; } - avalon_free_work(thr); + avalon_free_work_array(thr); + if (++avalon->work_array > 3) + avalon->work_array = 0; record_temp_fan(info, &ar, &(avalon->temp)); applog(LOG_INFO, diff --git a/miner.h b/miner.h index 819d2422..754d5f81 100644 --- a/miner.h +++ b/miner.h @@ -429,6 +429,7 @@ struct cgpu_info { }; #ifdef USE_AVALON struct work **works; + int work_array; int queued; #endif #ifdef USE_USBUTILS From be5a20c8d6bf9bfb39afc2bdfbdf506ba289bcf8 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 02:29:21 +1100 Subject: [PATCH 14/79] Fix warnings. --- driver-avalon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 5d4656dd..973b1759 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -289,14 +289,14 @@ static bool avalon_decode_nonce(struct thr_info *thr, struct avalon_result *ar, { struct cgpu_info *avalon; struct avalon_info *info; - int avalon_get_work_count; struct work *work; avalon = thr->cgpu; if (unlikely(!avalon->works)) return false; - work = find_queued_work_bymidstate(avalon, ar->midstate, 32, ar->data, 64, 12); + work = find_queued_work_bymidstate(avalon, (char *)ar->midstate, 32, + (char *)ar->data, 64, 12); if (!work) return false; From b2106b3aed398e92aeab63c931b30d608aafb1a8 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 11:18:21 +1100 Subject: [PATCH 15/79] Free avalon->works in the event we call avalon_prepare on failure to initialise. --- driver-avalon.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/driver-avalon.c b/driver-avalon.c index 973b1759..d0087b76 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -645,10 +645,14 @@ static bool avalon_prepare(struct thr_info *thr) struct avalon_info *info = avalon_infos[avalon->device_id]; struct timeval now; + free(avalon->works); avalon->works = calloc(info->miner_count * sizeof(struct work *), 4); if (!avalon->works) quit(1, "Failed to calloc avalon works in avalon_prepare"); - __avalon_init(avalon); + if (avalon->device_fd == -1) + avalon_init(avalon); + else + __avalon_init(avalon); gettimeofday(&now, NULL); get_datestamp(avalon->init, &now); From 2f89eef4b1eb23e6ac5b11ecd1e128eb6429d609 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 11:21:55 +1100 Subject: [PATCH 16/79] Differentiate socket closed from socket error in recv_line. --- util.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/util.c b/util.c index 4428199f..5665f809 100644 --- a/util.c +++ b/util.c @@ -1038,11 +1038,16 @@ char *recv_line(struct pool *pool) mutex_lock(&pool->stratum_lock); do { char s[RBUFSIZE]; - size_t slen, n; + size_t slen; + ssize_t n; memset(s, 0, RBUFSIZE); n = recv(pool->sock, s, RECVSIZE, 0); - if (n < 1 && errno != EAGAIN && errno != EWOULDBLOCK) { + if (!n) { + applog(LOG_DEBUG, "Socket closed waiting in recv_line"); + break; + } + if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { applog(LOG_DEBUG, "Failed to recv sock in recv_line"); break; } From 5f041e1a72629bf92eaf81ab077d473a34d9877c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 12:51:59 +1100 Subject: [PATCH 17/79] Don't get any work if our queue is already full in avalon_fill. --- driver-avalon.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index d0087b76..afeb56f1 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -785,13 +785,14 @@ static inline void adjust_fan(struct avalon_info *info) static bool avalon_fill(struct cgpu_info *avalon) { - struct work *work = get_queued(avalon); + struct work *work; int mc = avalon_infos[avalon->device_id]->miner_count; - if (unlikely(!work)) - return false; if (avalon->queued >= mc) return true; + work = get_queued(avalon); + if (unlikely(!work)) + return false; avalon->works[avalon->work_array * mc + avalon->queued++] = work; if (avalon->queued >= mc) return true; From 97bad1eef69822dc54fee3e60d55e85addfca4b9 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 13:01:42 +1100 Subject: [PATCH 18/79] Only get extra work in fill_queue if we don't have any unqueued work in the list. --- cgminer.c | 12 +++++++++--- miner.h | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index b68bc10f..09570037 100644 --- a/cgminer.c +++ b/cgminer.c @@ -5775,11 +5775,14 @@ static void fill_queue(struct thr_info *mythr, struct cgpu_info *cgpu, struct de { thread_reportout(mythr); do { - struct work *work = get_work(mythr, thr_id); + struct work *work; - work->device_diff = MIN(drv->max_diff, work->work_difficulty); wr_lock(&cgpu->qlock); - HASH_ADD_INT(cgpu->queued_work, id, work); + if (HASH_COUNT(cgpu->queued_work) == cgpu->queued_count) { + work = get_work(mythr, thr_id); + work->device_diff = MIN(drv->max_diff, work->work_difficulty); + HASH_ADD_INT(cgpu->queued_work, id, work); + } wr_unlock(&cgpu->qlock); /* The queue_full function should be used by the driver to * actually place work items on the physical device if it @@ -5799,6 +5802,7 @@ struct work *get_queued(struct cgpu_info *cgpu) HASH_ITER(hh, cgpu->queued_work, work, tmp) { if (!work->queued) { work->queued = true; + cgpu->queued_count++; ret = work; break; } @@ -5849,6 +5853,8 @@ struct work *find_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, void work_completed(struct cgpu_info *cgpu, struct work *work) { wr_lock(&cgpu->qlock); + if (work->queued) + cgpu->queued_count--; HASH_DEL(cgpu->queued_work, work); wr_unlock(&cgpu->qlock); free_work(work); diff --git a/miner.h b/miner.h index 754d5f81..7f565827 100644 --- a/miner.h +++ b/miner.h @@ -534,6 +534,7 @@ struct cgpu_info { pthread_rwlock_t qlock; struct work *queued_work; + unsigned int queued_count; }; extern bool add_cgpu(struct cgpu_info*); From dd1a0d636ac13e01946e21a67931f2389bef839f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 15:09:07 +1100 Subject: [PATCH 19/79] Rotate the avalon work array and free work on AVA_SEND_BUFFER_EMPTY as well. --- driver-avalon.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index afeb56f1..3e19996f 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -685,7 +685,7 @@ static void avalon_free_work_array(struct thr_info *thr) { struct cgpu_info *avalon; struct work **works; - int i, j, mc, wa; + int i, j, mc; avalon = thr->cgpu; avalon->queued = 0; @@ -693,11 +693,10 @@ static void avalon_free_work_array(struct thr_info *thr) return; works = avalon->works; mc = avalon_infos[avalon->device_id]->miner_count; - wa = avalon->work_array + 1; - if (wa > 3) - wa = 0; + if (++avalon->work_array > 3) + avalon->work_array = 0; - for (i = wa * mc, j = 0; j < mc; i++, j++) { + for (i = avalon->work_array * mc, j = 0; j < mc; i++, j++) { if (likely(works[i])) { work_completed(avalon, works[i]); works[i] = NULL; @@ -861,6 +860,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) } if (ret == AVA_SEND_BUFFER_EMPTY && (i + 1 == end_count)) { first_try = 1; + avalon_free_work_array(thr); return 0xffffffff; } @@ -942,8 +942,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) } avalon_free_work_array(thr); - if (++avalon->work_array > 3) - avalon->work_array = 0; record_temp_fan(info, &ar, &(avalon->temp)); applog(LOG_INFO, From ae4ee34ad42abb97d658c1ac26117d0ffe364f9a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 15:49:55 +1100 Subject: [PATCH 20/79] Small timeouts on select() instead of instant timeout increase reliability of socket reads and writes. --- util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util.c b/util.c index 5665f809..5497e7a8 100644 --- a/util.c +++ b/util.c @@ -912,7 +912,7 @@ static bool __stratum_send(struct pool *pool, char *s, ssize_t len) len++; while (len > 0 ) { - struct timeval timeout = {0, 0}; + struct timeval timeout = {1, 0}; ssize_t sent; fd_set wd; @@ -966,7 +966,7 @@ static bool socket_full(struct pool *pool, bool wait) if (wait) timeout.tv_sec = 60; else - timeout.tv_sec = 0; + timeout.tv_sec = 1; if (select(sock + 1, &rd, NULL, NULL, &timeout) > 0) return true; return false; From 689f744b620d8f4a064dcdfe5b9256a165ef50d0 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 18:12:45 +1100 Subject: [PATCH 21/79] Reset the result_wrong count on block change in avalon scanhash to prevent false positives for all nonces failed. --- driver-avalon.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/driver-avalon.c b/driver-avalon.c index 3e19996f..14966b1b 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -902,6 +902,10 @@ static int64_t avalon_scanhash(struct thr_info *thr) continue; } if (unlikely(ret == AVA_GETS_RESTART)) { + /* Reset the wrong count in case there has only been + * a small number of nonces tested before the restart. + */ + result_wrong = 0; break; } result_count++; From 809fec91a62583276b52eaf8265dbc5be4aabe95 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Apr 2013 18:27:38 +1100 Subject: [PATCH 22/79] Only do_avalon_close once on multiple errors. --- driver-avalon.c | 1 - 1 file changed, 1 deletion(-) diff --git a/driver-avalon.c b/driver-avalon.c index 14966b1b..8e2953b9 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -939,7 +939,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) applog(LOG_ERR, "AVA%i: FPGA controller mess up", avalon->device_id); dev_error(avalon, REASON_DEV_COMMS_ERROR); - do_avalon_close(thr); sleep(1); avalon_init(avalon); return 0; From 293b94c7ed2aeb3352e454146ff2d3e400c72da2 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Apr 2013 01:39:20 +1100 Subject: [PATCH 23/79] Add API support for Avalon. --- api.c | 16 ++++++++++++---- miner.h | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/api.c b/api.c index a2c70582..24dcb589 100644 --- a/api.c +++ b/api.c @@ -29,7 +29,7 @@ #include "util.h" #include "driver-cpu.h" /* for algo_names[], TODO: re-factor dependency */ -#if defined(USE_BFLSC) +#if defined(USE_BFLSC) || defined(USE_AVALON) #define HAVE_AN_ASIC 1 #endif @@ -179,6 +179,9 @@ static const char *DEVICECODE = "" #ifdef USE_ICARUS "ICA " #endif +#ifdef USE_AVALON + "AVA " +#endif #ifdef USE_ZTEX "ZTX " #endif @@ -605,9 +608,6 @@ struct CODES { static int my_thr_id = 0; static bool bye; -#if defined(HAVE_OPENCL) || defined (HAVE_AN_ASIC) || defined(HAVE_AN_FPGA) -static bool ping = true; -#endif // Used to control quit restart access to shutdown variables static pthread_mutex_t quit_restart_lock; @@ -1178,6 +1178,10 @@ static int numascs() rd_lock(&devices_lock); for (i = 0; i < total_devices; i++) { +#ifdef USE_AVALON + if (devices[i]->drv->drv_id == DRIVER_AVALON) + count++; +#endif #ifdef USE_BFLSC if (devices[i]->drv->drv_id == DRIVER_BFLSC) count++; @@ -1194,6 +1198,10 @@ static int ascdevice(int ascid) rd_lock(&devices_lock); for (i = 0; i < total_devices; i++) { +#ifdef USE_AVALON + if (devices[i]->drv->drv_id == DRIVER_AVALON) + count++; +#endif #ifdef USE_BFLSC if (devices[i]->drv->drv_id == DRIVER_BFLSC) count++; diff --git a/miner.h b/miner.h index 7f565827..9aa87419 100644 --- a/miner.h +++ b/miner.h @@ -805,6 +805,7 @@ extern bool opt_usb_list_all; #ifdef USE_BITFORCE extern bool opt_bfl_noncerange; #endif +extern bool ping; extern int swork_id; extern pthread_rwlock_t netacc_lock; From 85a4dfd9a7e3238af443a79d5f6d779ffc923683 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Apr 2013 11:53:18 +1100 Subject: [PATCH 24/79] Bump version to 2.11.4 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 9a6013cb..c7bd8735 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_maj], [2]) m4_define([v_min], [11]) -m4_define([v_mic], [3]) +m4_define([v_mic], [4]) ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_ver], [v_maj.v_min.v_mic]) m4_define([lt_rev], m4_eval(v_maj + v_min)) From e9b6ff8f6a4d57931d1309609d87d50f551760a7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Apr 2013 01:46:16 +1100 Subject: [PATCH 25/79] Fix warning with no curses built in. --- cgminer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cgminer.c b/cgminer.c index 09570037..cd8e6c1b 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2320,12 +2320,14 @@ static void enable_pool(struct pool *pool) } } +#ifdef HAVE_CURSES static void disable_pool(struct pool *pool) { if (pool->enabled == POOL_ENABLED) enabled_pools--; pool->enabled = POOL_DISABLED; } +#endif static void reject_pool(struct pool *pool) { From 8b2b9b3d3ed127833b7670e50ffa81ab6f167faf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Apr 2013 02:06:21 +1000 Subject: [PATCH 26/79] Remove inappropriate memset of struct avalon result which was corrupting fan values. --- driver-avalon.c | 1 - 1 file changed, 1 deletion(-) diff --git a/driver-avalon.c b/driver-avalon.c index 8e2953b9..4de52d5d 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -272,7 +272,6 @@ static int avalon_get_result(int fd, struct avalon_result *ar, memset(result, 0, AVALON_READ_SIZE); ret = avalon_gets(fd, result, read_count, thr, tv_finish); - memset(ar, 0, sizeof(struct avalon_result)); if (ret == AVA_GETS_OK) { if (opt_debug) { applog(LOG_DEBUG, "Avalon: get:"); From d9ba82c607f1f7b8adb6886871899bab85c459a9 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Apr 2013 02:21:29 +1000 Subject: [PATCH 27/79] Fix record_temp_fan function in avalon driver. Patch by Xiangfu --- driver-avalon.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 4de52d5d..b263d0ad 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -721,8 +721,6 @@ static void do_avalon_close(struct thr_info *thr) static inline void record_temp_fan(struct avalon_info *info, struct avalon_result *ar, float *temp_avg) { - int max; - info->fan0 = ar->fan0 * AVALON_FAN_FACTOR; info->fan1 = ar->fan1 * AVALON_FAN_FACTOR; info->fan2 = ar->fan2 * AVALON_FAN_FACTOR; @@ -745,22 +743,12 @@ static inline void record_temp_fan(struct avalon_info *info, struct avalon_resul *temp_avg = info->temp2; - max = info->temp_max; - if (info->temp0 > max) - max = info->temp0; - if (info->temp1 > max) - max = info->temp1; - if (info->temp2 > max) - max = info->temp2; - if (max >= 100) { /* FIXME: fix the root cause on fpga controller firmware */ - if (opt_debug) { - applog(LOG_DEBUG, "Avalon: temp_max: %d", max); - hexdump((uint8_t *)ar, AVALON_READ_SIZE); - } - return; - } - - info->temp_max = max; + if (info->temp0 > info->temp_max) + info->temp_max = info->temp0; + if (info->temp1 > info->temp_max) + info->temp_max = info->temp1; + if (info->temp2 > info->temp_max) + info->temp_max = info->temp2; } static inline void adjust_fan(struct avalon_info *info) From b7b5b9ded2d9884c2fd680f5cddc3e9970c4c53d Mon Sep 17 00:00:00 2001 From: Kano Date: Sun, 7 Apr 2013 07:46:45 +1000 Subject: [PATCH 28/79] usbutils more stats for bflsc --- usbutils.c | 4 ++++ usbutils.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/usbutils.c b/usbutils.c index 69bd72ec..6b214c82 100644 --- a/usbutils.c +++ b/usbutils.c @@ -294,6 +294,8 @@ static const char *C_REQUESTQUEJOB_S = "RequestQueJob"; static const char *C_REQUESTQUEJOBSTATUS_S = "RequestQueJobStatus"; static const char *C_QUEJOB_S = "QueJob"; static const char *C_QUEJOBSTATUS_S = "QueJobStatus"; +static const char *C_QUEFLUSH_S = "QueFlush"; +static const char *C_QUEFLUSHREPLY_S = "QueFlushReply"; #ifdef EOL #undef EOL @@ -759,6 +761,8 @@ static void cgusb_check_init() usb_commands[C_REQUESTQUEJOBSTATUS] = C_REQUESTQUEJOBSTATUS_S; usb_commands[C_QUEJOB] = C_QUEJOB_S; usb_commands[C_QUEJOBSTATUS] = C_QUEJOBSTATUS_S; + usb_commands[C_QUEFLUSH] = C_QUEFLUSH_S; + usb_commands[C_QUEFLUSHREPLY] = C_QUEFLUSHREPLY_S; stats_initialised = true; } diff --git a/usbutils.h b/usbutils.h index 8e34d817..db279ce0 100644 --- a/usbutils.h +++ b/usbutils.h @@ -131,6 +131,8 @@ enum usb_cmds { C_REQUESTQUEJOBSTATUS, C_QUEJOB, C_QUEJOBSTATUS, + C_QUEFLUSH, + C_QUEFLUSHREPLY, C_MAX }; From 8e69d75f36f58adefa32a5b3250c9ec4ddb0202d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Apr 2013 11:59:14 +1000 Subject: [PATCH 29/79] Store the subid for the work item in avalon. --- driver-avalon.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index b263d0ad..959b43ee 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -771,15 +771,17 @@ static inline void adjust_fan(struct avalon_info *info) static bool avalon_fill(struct cgpu_info *avalon) { + int subid, mc = avalon_infos[avalon->device_id]->miner_count; struct work *work; - int mc = avalon_infos[avalon->device_id]->miner_count; if (avalon->queued >= mc) return true; work = get_queued(avalon); if (unlikely(!work)) return false; - avalon->works[avalon->work_array * mc + avalon->queued++] = work; + subid = avalon->queued++; + work->subid = subid; + avalon->works[avalon->work_array * mc + subid] = work; if (avalon->queued >= mc) return true; return false; From 0da8868799584cfd3143f1d329d57eb0c6d61c6b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Apr 2013 14:45:54 +1000 Subject: [PATCH 30/79] We should check for a restart message before checking for a timeout in avalon scanhash. --- driver-avalon.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 959b43ee..5a23cbf7 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -884,12 +884,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) dev_error(avalon, REASON_DEV_COMMS_ERROR); return 0; } - if (unlikely(ret == AVA_GETS_TIMEOUT)) { - timersub(&tv_finish, &tv_start, &elapsed); - applog(LOG_DEBUG, "Avalon: no nonce in (%ld.%06lds)", - elapsed.tv_sec, elapsed.tv_usec); - continue; - } if (unlikely(ret == AVA_GETS_RESTART)) { /* Reset the wrong count in case there has only been * a small number of nonces tested before the restart. @@ -897,6 +891,12 @@ static int64_t avalon_scanhash(struct thr_info *thr) result_wrong = 0; break; } + if (unlikely(ret == AVA_GETS_TIMEOUT)) { + timersub(&tv_finish, &tv_start, &elapsed); + applog(LOG_DEBUG, "Avalon: no nonce in (%ld.%06lds)", + elapsed.tv_sec, elapsed.tv_usec); + continue; + } result_count++; if (!avalon_decode_nonce(thr, &ar, &nonce)) { From 53a047d0070933354efbd839026896cd83c1caa5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Apr 2013 14:53:36 +1000 Subject: [PATCH 31/79] Check for a restart before a timeout in message parsing code in avalon. --- driver-avalon.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 5a23cbf7..98c7fc9a 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -234,23 +234,23 @@ static int avalon_gets(int fd, uint8_t *buf, int read_count, continue; } - rc++; - if (rc >= read_count) { + if (thr && thr->work_restart) { if (opt_debug) { applog(LOG_WARNING, - "Avalon: No data in %.2f seconds", - (float)rc/(float)AVALON_TIME_FACTOR); + "Avalon: Work restart at %.2f seconds", + (float)(rc)/(float)AVALON_TIME_FACTOR); } - return AVA_GETS_TIMEOUT; + return AVA_GETS_RESTART; } - if (thr && thr->work_restart) { + rc++; + if (rc >= read_count) { if (opt_debug) { applog(LOG_WARNING, - "Avalon: Work restart at %.2f seconds", - (float)(rc)/(float)AVALON_TIME_FACTOR); + "Avalon: No data in %.2f seconds", + (float)rc/(float)AVALON_TIME_FACTOR); } - return AVA_GETS_RESTART; + return AVA_GETS_TIMEOUT; } } } From ea70300a59d3b40fac4c8095e305f4bdcceb9d9c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Apr 2013 15:03:08 +1000 Subject: [PATCH 32/79] The current hash count returned by avalon scanhash is just an obfuscated utility counter so make it explicit. --- driver-avalon.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 98c7fc9a..36fcee6f 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -912,7 +912,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) continue; } - hash_count += nonce; + hash_count += 0xffffffff; if (opt_debug) { timersub(&tv_finish, &tv_start, &elapsed); applog(LOG_DEBUG, @@ -951,16 +951,8 @@ static int64_t avalon_scanhash(struct thr_info *thr) info->temp_sum = 0; } - /* - * FIXME: Each work split to 10 pieces, each piece send to a - * asic(256MHs). one work can be mulit-nonce back. it is not - * easy calculate correct hash on such situation. so I simplely - * add each nonce to hash_count. base on Utility/m hash_count*2 - * give a very good result. - * - * Any patch will be great. - */ - return hash_count * 2; + /* This hashmeter is just a utility counter based on returned shares */ + return hash_count; } static struct api_data *avalon_api_stats(struct cgpu_info *cgpu) From dec90b96ad067067fec0da02f0278978f8b765c5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Apr 2013 15:35:36 +1000 Subject: [PATCH 33/79] Use a separate avalon_get_reset function for resetting avalon instead of using avalon_get_result. --- driver-avalon.c | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 36fcee6f..7d02c50c 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -261,13 +261,11 @@ static int avalon_get_result(int fd, struct avalon_result *ar, struct cgpu_info *avalon; struct avalon_info *info; uint8_t result[AVALON_READ_SIZE]; - int ret, read_count = AVALON_RESET_FAULT_DECISECONDS * AVALON_TIME_FACTOR; + int ret, read_count; - if (likely(thr)) { - avalon = thr->cgpu; - info = avalon_infos[avalon->device_id]; - read_count = info->read_count; - } + avalon = thr->cgpu; + info = avalon_infos[avalon->device_id]; + read_count = info->read_count; memset(result, 0, AVALON_READ_SIZE); ret = avalon_gets(fd, result, read_count, thr, tv_finish); @@ -307,6 +305,39 @@ static bool avalon_decode_nonce(struct thr_info *thr, struct avalon_result *ar, return true; } +static void avalon_get_reset(int fd, struct avalon_result *ar) +{ + int read_amount = AVALON_READ_SIZE; + uint8_t result[AVALON_READ_SIZE]; + struct timeval timeout = {1, 0}; + ssize_t ret = 0; + fd_set rd; + + memset(result, 0, AVALON_READ_SIZE); + memset(ar, 0, AVALON_READ_SIZE); + FD_ZERO(&rd); + FD_SET(fd, &rd); + ret = select(fd + 1, &rd, NULL, NULL, &timeout); + if (unlikely(ret < 0)) { + applog(LOG_WARNING, "Avalon: Error on select in avalon_get_reset"); + return; + } + if (!ret) { + applog(LOG_WARNING, "Avalon: Timeout on select in avalon_get_reset"); + return; + } + ret = read(fd, result, read_amount); + if (unlikely(ret != read_amount)) { + applog(LOG_WARNING, "Avalon: Error on read in avalon_get_reset"); + return; + } + if (opt_debug) { + applog(LOG_DEBUG, "Avalon: get:"); + hexdump((uint8_t *)result, AVALON_READ_SIZE); + } + memcpy((uint8_t *)ar, result, AVALON_READ_SIZE); +} + static int avalon_reset(int fd, struct avalon_result *ar) { struct avalon_task at; @@ -325,7 +356,7 @@ static int avalon_reset(int fd, struct avalon_result *ar) if (ret == AVA_SEND_ERROR) return 1; - avalon_get_result(fd, ar, NULL, NULL); + avalon_get_reset(fd, ar); buf = (uint8_t *)ar; /* Sometimes there is one extra 0 byte for some reason in the buffer, From 3671b2c310d875ad160dd9918fcc8d48c0ab7be6 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Apr 2013 15:48:35 +1000 Subject: [PATCH 34/79] The read_count is unused by the avalon get result code and no longer required for avalon reset so simplify code removing it. --- driver-avalon.c | 41 +++++++++-------------------------------- driver-avalon.h | 3 --- 2 files changed, 9 insertions(+), 35 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 7d02c50c..1ef19aa9 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -201,13 +201,12 @@ static int avalon_send_task(int fd, const struct avalon_task *at, return AVA_SEND_BUFFER_EMPTY; } -static int avalon_gets(int fd, uint8_t *buf, int read_count, - struct thr_info *thr, struct timeval *tv_finish) +static int avalon_gets(int fd, uint8_t *buf, struct thr_info *thr, + struct timeval *tv_finish) { - ssize_t ret = 0; - int rc = 0; int read_amount = AVALON_READ_SIZE; bool first = true; + ssize_t ret = 0; while (true) { struct timeval timeout = {0, 100000}; @@ -223,8 +222,7 @@ static int avalon_gets(int fd, uint8_t *buf, int read_count, if (unlikely(ret < 0)) return AVA_GETS_ERROR; if (likely(first)) { - if (likely(tv_finish)) - gettimeofday(tv_finish, NULL); + gettimeofday(tv_finish, NULL); first = false; } if (likely(ret >= read_amount)) @@ -234,41 +232,23 @@ static int avalon_gets(int fd, uint8_t *buf, int read_count, continue; } - if (thr && thr->work_restart) { - if (opt_debug) { - applog(LOG_WARNING, - "Avalon: Work restart at %.2f seconds", - (float)(rc)/(float)AVALON_TIME_FACTOR); - } + if (thr->work_restart) { + applog(LOG_DEBUG, "Avalon: Work restart"); return AVA_GETS_RESTART; } - rc++; - if (rc >= read_count) { - if (opt_debug) { - applog(LOG_WARNING, - "Avalon: No data in %.2f seconds", - (float)rc/(float)AVALON_TIME_FACTOR); - } - return AVA_GETS_TIMEOUT; - } + return AVA_GETS_TIMEOUT; } } static int avalon_get_result(int fd, struct avalon_result *ar, struct thr_info *thr, struct timeval *tv_finish) { - struct cgpu_info *avalon; - struct avalon_info *info; uint8_t result[AVALON_READ_SIZE]; - int ret, read_count; - - avalon = thr->cgpu; - info = avalon_infos[avalon->device_id]; - read_count = info->read_count; + int ret; memset(result, 0, AVALON_READ_SIZE); - ret = avalon_gets(fd, result, read_count, thr, tv_finish); + ret = avalon_gets(fd, result, thr, tv_finish); if (ret == AVA_GETS_OK) { if (opt_debug) { @@ -609,8 +589,6 @@ static bool avalon_detect_one(const char *devpath) info->miner_count = miner_count; info->asic_count = asic_count; info->timeout = timeout; - info->read_count = ((float)info->timeout * AVALON_HASH_TIME_FACTOR * - AVALON_TIME_FACTOR) / (float)info->miner_count; info->fan_pwm = AVALON_DEFAULT_FAN_MIN_PWM; info->temp_max = 0; @@ -994,7 +972,6 @@ static struct api_data *avalon_api_stats(struct cgpu_info *cgpu) root = api_add_int(root, "baud", &(info->baud), false); root = api_add_int(root, "miner_count", &(info->miner_count),false); root = api_add_int(root, "asic_count", &(info->asic_count), false); - root = api_add_int(root, "read_count", &(info->read_count), false); root = api_add_int(root, "timeout", &(info->timeout), false); root = api_add_int(root, "frequency", &(info->frequency), false); diff --git a/driver-avalon.h b/driver-avalon.h index c040d03d..93c2e60c 100644 --- a/driver-avalon.h +++ b/driver-avalon.h @@ -12,7 +12,6 @@ #ifdef USE_AVALON -#define AVALON_TIME_FACTOR 10 #define AVALON_RESET_FAULT_DECISECONDS 1 #define AVALON_MINER_THREADS 1 @@ -73,8 +72,6 @@ struct avalon_result { } __attribute__((packed, aligned(4))); struct avalon_info { - int read_count; - int baud; int miner_count; int asic_count; From afd6f4270307f8154dad9e2f74732d722739dac3 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Apr 2013 16:09:26 +1000 Subject: [PATCH 35/79] avalon_gets is always called from the one call site so inline it. --- driver-avalon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon.c b/driver-avalon.c index 1ef19aa9..6e6d143d 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -201,7 +201,7 @@ static int avalon_send_task(int fd, const struct avalon_task *at, return AVA_SEND_BUFFER_EMPTY; } -static int avalon_gets(int fd, uint8_t *buf, struct thr_info *thr, +static inline int avalon_gets(int fd, uint8_t *buf, struct thr_info *thr, struct timeval *tv_finish) { int read_amount = AVALON_READ_SIZE; From 0ea9d68d6786473b641bc377651b908aeeab06a2 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 08:28:53 +1000 Subject: [PATCH 36/79] Use only 2 queued work arrays in avalon. --- driver-avalon.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 6e6d143d..3c8c7ebc 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -654,7 +654,7 @@ static bool avalon_prepare(struct thr_info *thr) struct timeval now; free(avalon->works); - avalon->works = calloc(info->miner_count * sizeof(struct work *), 4); + avalon->works = calloc(info->miner_count * sizeof(struct work *), 2); if (!avalon->works) quit(1, "Failed to calloc avalon works in avalon_prepare"); if (avalon->device_fd == -1) @@ -681,7 +681,7 @@ static void avalon_free_work(struct thr_info *thr) works = avalon->works; info = avalon_infos[avalon->device_id]; - for (i = 0; i < info->miner_count * 4; i++) { + for (i = 0; i < info->miner_count * 2; i++) { if (works[i]) { work_completed(avalon, works[i]); works[i] = NULL; @@ -701,8 +701,7 @@ static void avalon_free_work_array(struct thr_info *thr) return; works = avalon->works; mc = avalon_infos[avalon->device_id]->miner_count; - if (++avalon->work_array > 3) - avalon->work_array = 0; + avalon->work_array ^= 1; for (i = avalon->work_array * mc, j = 0; j < mc; i++, j++) { if (likely(works[i])) { From 5e3474b0c8ef95c3b08ae587c138ea136fcc8362 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 09:04:10 +1000 Subject: [PATCH 37/79] If we get a restart message in avalon_gets still check if there's a receive message to parse first without a timeout before returning AVA_GETS_RESTART. --- driver-avalon.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 3c8c7ebc..5b4d106b 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -209,9 +209,17 @@ static inline int avalon_gets(int fd, uint8_t *buf, struct thr_info *thr, ssize_t ret = 0; while (true) { - struct timeval timeout = {0, 100000}; + struct timeval timeout; fd_set rd; + timeout.tv_sec = 0; + /* If we get a restart message, still check if there's + * anything in the buffer waiting to be parsed */ + if (unlikely(thr->work_restart)) + timeout.tv_usec = 0; + else + timeout.tv_usec = 100000; + FD_ZERO(&rd); FD_SET(fd, &rd); ret = select(fd + 1, &rd, NULL, NULL, &timeout); @@ -232,7 +240,7 @@ static inline int avalon_gets(int fd, uint8_t *buf, struct thr_info *thr, continue; } - if (thr->work_restart) { + if (unlikely(thr->work_restart)) { applog(LOG_DEBUG, "Avalon: Work restart"); return AVA_GETS_RESTART; } From c6b9a3eeeabcdd3f2a6881affa1ec8593bac382b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 09:48:23 +1000 Subject: [PATCH 38/79] Show error codes on select and read fail in avalon. --- driver-avalon.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 5b4d106b..a3e96b4c 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -223,12 +223,16 @@ static inline int avalon_gets(int fd, uint8_t *buf, struct thr_info *thr, FD_ZERO(&rd); FD_SET(fd, &rd); ret = select(fd + 1, &rd, NULL, NULL, &timeout); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + applog(LOG_ERR, "Avalon: Error %d on select in avalon_gets", errno); return AVA_GETS_ERROR; + } if (ret) { ret = read(fd, buf, read_amount); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + applog(LOG_ERR, "Avalon: Error %d on read in avalon_gets", errno); return AVA_GETS_ERROR; + } if (likely(first)) { gettimeofday(tv_finish, NULL); first = false; @@ -307,7 +311,7 @@ static void avalon_get_reset(int fd, struct avalon_result *ar) FD_SET(fd, &rd); ret = select(fd + 1, &rd, NULL, NULL, &timeout); if (unlikely(ret < 0)) { - applog(LOG_WARNING, "Avalon: Error on select in avalon_get_reset"); + applog(LOG_WARNING, "Avalon: Error %d on select in avalon_get_reset", errno); return; } if (!ret) { @@ -316,7 +320,7 @@ static void avalon_get_reset(int fd, struct avalon_result *ar) } ret = read(fd, result, read_amount); if (unlikely(ret != read_amount)) { - applog(LOG_WARNING, "Avalon: Error on read in avalon_get_reset"); + applog(LOG_WARNING, "Avalon: Error %d on read in avalon_get_reset", errno); return; } if (opt_debug) { From 8b0531fb2b399a6a606906014209e1e7814bbcca Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 10:13:15 +1000 Subject: [PATCH 39/79] Make the detection of all wrong results on avalon much more conservative to avoid false positives on work restarts. --- driver-avalon.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index a3e96b4c..9435c366 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -824,7 +824,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) uint32_t nonce; int64_t hash_count; static int first_try = 0; - int result_count, result_wrong; + int result_wrong; avalon = thr->cgpu; works = avalon->works; @@ -886,7 +886,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec = elapsed.tv_usec = 0; gettimeofday(&tv_start, NULL); - result_count = 0; result_wrong = 0; hash_count = 0; while (true) { @@ -904,20 +903,14 @@ static int64_t avalon_scanhash(struct thr_info *thr) dev_error(avalon, REASON_DEV_COMMS_ERROR); return 0; } - if (unlikely(ret == AVA_GETS_RESTART)) { - /* Reset the wrong count in case there has only been - * a small number of nonces tested before the restart. - */ - result_wrong = 0; + if (unlikely(ret == AVA_GETS_RESTART)) break; - } if (unlikely(ret == AVA_GETS_TIMEOUT)) { timersub(&tv_finish, &tv_start, &elapsed); applog(LOG_DEBUG, "Avalon: no nonce in (%ld.%06lds)", elapsed.tv_sec, elapsed.tv_usec); continue; } - result_count++; if (!avalon_decode_nonce(thr, &ar, &nonce)) { info->no_matching_work++; @@ -941,8 +934,8 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec, elapsed.tv_usec); } } - if (result_wrong && result_count == result_wrong) { - /* This mean FPGA controller give all wrong result + if (result_wrong >= info->miner_count) { + /* This mean FPGA controller gave all wrong results, so * try to reset the Avalon */ do_avalon_close(thr); applog(LOG_ERR, From fb34cb1784771ad734fa0724b258bcd4e6e5cad9 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 10:34:47 +1000 Subject: [PATCH 40/79] Check for AVA_GETS_RESTART when deciding if avalon has messed up. --- driver-avalon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 9435c366..9724dca8 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -811,7 +811,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) { struct cgpu_info *avalon; struct work **works; - int fd, ret, full; + int fd, ret = AVA_GETS_OK, full; struct avalon_info *info; struct avalon_task at; @@ -934,7 +934,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec, elapsed.tv_usec); } } - if (result_wrong >= info->miner_count) { + if (result_wrong >= info->miner_count && ret != AVA_GETS_RESTART) { /* This mean FPGA controller gave all wrong results, so * try to reset the Avalon */ do_avalon_close(thr); From 4e2b107642bd5bf02cfb5274783651807561e7bf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 10:37:48 +1000 Subject: [PATCH 41/79] Reuse avalon_get_work_count variable. --- driver-avalon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon.c b/driver-avalon.c index 9724dca8..66455a02 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -934,7 +934,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec, elapsed.tv_usec); } } - if (result_wrong >= info->miner_count && ret != AVA_GETS_RESTART) { + if (result_wrong >= avalon_get_work_count && ret != AVA_GETS_RESTART) { /* This mean FPGA controller gave all wrong results, so * try to reset the Avalon */ do_avalon_close(thr); From 385f1cd8d49bd97a9fe37bec0ac6d29a44404f78 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 10:39:16 +1000 Subject: [PATCH 42/79] Show read discrepancy in avalon_get_reset. --- driver-avalon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/driver-avalon.c b/driver-avalon.c index 66455a02..f93b8394 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -320,7 +320,8 @@ static void avalon_get_reset(int fd, struct avalon_result *ar) } ret = read(fd, result, read_amount); if (unlikely(ret != read_amount)) { - applog(LOG_WARNING, "Avalon: Error %d on read in avalon_get_reset", errno); + applog(LOG_WARNING, "Avalon: Error %d on read, asked for %d got %d in avalon_get_reset", + errno, read_amount, ret); return; } if (opt_debug) { From ad55fbf906eec4b11a9cc9a994e0d77d5729cbec Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 11:20:10 +1000 Subject: [PATCH 43/79] Do sequential reads in avalon_get_reset to cope with partial reads. --- driver-avalon.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index f93b8394..4af8f9c5 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -302,7 +302,7 @@ static void avalon_get_reset(int fd, struct avalon_result *ar) int read_amount = AVALON_READ_SIZE; uint8_t result[AVALON_READ_SIZE]; struct timeval timeout = {1, 0}; - ssize_t ret = 0; + ssize_t ret = 0, offset = 0; fd_set rd; memset(result, 0, AVALON_READ_SIZE); @@ -318,12 +318,15 @@ static void avalon_get_reset(int fd, struct avalon_result *ar) applog(LOG_WARNING, "Avalon: Timeout on select in avalon_get_reset"); return; } - ret = read(fd, result, read_amount); - if (unlikely(ret != read_amount)) { - applog(LOG_WARNING, "Avalon: Error %d on read, asked for %d got %d in avalon_get_reset", - errno, read_amount, ret); - return; - } + do { + ret = read(fd, result + offset, read_amount); + if (unlikely(ret < 0)) { + applog(LOG_WARNING, "Avalon: Error %d on read in avalon_get_reset", errno); + return; + } + read_amount -= ret; + offset += ret; + } while (read_amount > 0); if (opt_debug) { applog(LOG_DEBUG, "Avalon: get:"); hexdump((uint8_t *)result, AVALON_READ_SIZE); From af6111fb555f195574120ec19439662d1eb3d740 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 11:22:25 +1000 Subject: [PATCH 44/79] Use no timeout on further reads in avalon_gets --- driver-avalon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon.c b/driver-avalon.c index 4af8f9c5..4596cde3 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -215,7 +215,7 @@ static inline int avalon_gets(int fd, uint8_t *buf, struct thr_info *thr, timeout.tv_sec = 0; /* If we get a restart message, still check if there's * anything in the buffer waiting to be parsed */ - if (unlikely(thr->work_restart)) + if (unlikely(thr->work_restart || !first)) timeout.tv_usec = 0; else timeout.tv_usec = 100000; From 64ecfa53a9fa3109a137d52cc7251c30b2576ebe Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 11:32:24 +1000 Subject: [PATCH 45/79] Revert "Use only 2 queued work arrays in avalon." This reverts commit 0ea9d68d6786473b641bc377651b908aeeab06a2. This was leading to failure to find work items on block changes. --- driver-avalon.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 4596cde3..7bb8dc81 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -670,7 +670,7 @@ static bool avalon_prepare(struct thr_info *thr) struct timeval now; free(avalon->works); - avalon->works = calloc(info->miner_count * sizeof(struct work *), 2); + avalon->works = calloc(info->miner_count * sizeof(struct work *), 4); if (!avalon->works) quit(1, "Failed to calloc avalon works in avalon_prepare"); if (avalon->device_fd == -1) @@ -697,7 +697,7 @@ static void avalon_free_work(struct thr_info *thr) works = avalon->works; info = avalon_infos[avalon->device_id]; - for (i = 0; i < info->miner_count * 2; i++) { + for (i = 0; i < info->miner_count * 4; i++) { if (works[i]) { work_completed(avalon, works[i]); works[i] = NULL; @@ -717,7 +717,8 @@ static void avalon_free_work_array(struct thr_info *thr) return; works = avalon->works; mc = avalon_infos[avalon->device_id]->miner_count; - avalon->work_array ^= 1; + if (++avalon->work_array > 3) + avalon->work_array = 0; for (i = avalon->work_array * mc, j = 0; j < mc; i++, j++) { if (likely(works[i])) { From 08c0ac290c1196b77388e747ced15d92fce57f18 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 11:59:32 +1000 Subject: [PATCH 46/79] The result_wrong measurement for avalon is continually leading to false positives so remove it. --- driver-avalon.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 7bb8dc81..2d1ea9c0 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -829,7 +829,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) uint32_t nonce; int64_t hash_count; static int first_try = 0; - int result_wrong; avalon = thr->cgpu; works = avalon->works; @@ -891,7 +890,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec = elapsed.tv_usec = 0; gettimeofday(&tv_start, NULL); - result_wrong = 0; hash_count = 0; while (true) { full = avalon_buffer_full(fd); @@ -919,7 +917,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) if (!avalon_decode_nonce(thr, &ar, &nonce)) { info->no_matching_work++; - result_wrong++; if (opt_debug) { timersub(&tv_finish, &tv_start, &elapsed); @@ -939,17 +936,6 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec, elapsed.tv_usec); } } - if (result_wrong >= avalon_get_work_count && ret != AVA_GETS_RESTART) { - /* This mean FPGA controller gave all wrong results, so - * try to reset the Avalon */ - do_avalon_close(thr); - applog(LOG_ERR, - "AVA%i: FPGA controller mess up", avalon->device_id); - dev_error(avalon, REASON_DEV_COMMS_ERROR); - sleep(1); - avalon_init(avalon); - return 0; - } avalon_free_work_array(thr); From af65870244aa80230cdd8c014b39e0304d20b479 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 12:01:16 +1000 Subject: [PATCH 47/79] select() on serial usb in avalon does not work properly with zero timeout. --- driver-avalon.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 2d1ea9c0..9e54e76b 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -212,13 +212,13 @@ static inline int avalon_gets(int fd, uint8_t *buf, struct thr_info *thr, struct timeval timeout; fd_set rd; + if (unlikely(thr->work_restart)) { + applog(LOG_DEBUG, "Avalon: Work restart"); + return AVA_GETS_RESTART; + } + timeout.tv_sec = 0; - /* If we get a restart message, still check if there's - * anything in the buffer waiting to be parsed */ - if (unlikely(thr->work_restart || !first)) - timeout.tv_usec = 0; - else - timeout.tv_usec = 100000; + timeout.tv_usec = 100000; FD_ZERO(&rd); FD_SET(fd, &rd); From 47309e1a184e1f9bb718eb12277d7ac884cba8cb Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 14:04:38 +1000 Subject: [PATCH 48/79] Revert "The result_wrong measurement for avalon is continually leading to false positives so remove it." This reverts commit 08c0ac290c1196b77388e747ced15d92fce57f18. --- driver-avalon.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/driver-avalon.c b/driver-avalon.c index 9e54e76b..6b7da561 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -829,6 +829,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) uint32_t nonce; int64_t hash_count; static int first_try = 0; + int result_wrong; avalon = thr->cgpu; works = avalon->works; @@ -890,6 +891,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec = elapsed.tv_usec = 0; gettimeofday(&tv_start, NULL); + result_wrong = 0; hash_count = 0; while (true) { full = avalon_buffer_full(fd); @@ -917,6 +919,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) if (!avalon_decode_nonce(thr, &ar, &nonce)) { info->no_matching_work++; + result_wrong++; if (opt_debug) { timersub(&tv_finish, &tv_start, &elapsed); @@ -936,6 +939,17 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec, elapsed.tv_usec); } } + if (result_wrong >= avalon_get_work_count && ret != AVA_GETS_RESTART) { + /* This mean FPGA controller gave all wrong results, so + * try to reset the Avalon */ + do_avalon_close(thr); + applog(LOG_ERR, + "AVA%i: FPGA controller mess up", avalon->device_id); + dev_error(avalon, REASON_DEV_COMMS_ERROR); + sleep(1); + avalon_init(avalon); + return 0; + } avalon_free_work_array(thr); From 1c4d1ac863dee6da3c0ca2c0a06dad3dbdf6191f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 14:08:54 +1000 Subject: [PATCH 49/79] Reinstate wrong work count to reset avalon regardless and display number of wrong results. --- driver-avalon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 6b7da561..e179a8de 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -939,12 +939,12 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec, elapsed.tv_usec); } } - if (result_wrong >= avalon_get_work_count && ret != AVA_GETS_RESTART) { - /* This mean FPGA controller gave all wrong results, so + if (result_wrong >= avalon_get_work_count) { + /* This means FPGA controller gave all wrong results, so * try to reset the Avalon */ do_avalon_close(thr); applog(LOG_ERR, - "AVA%i: FPGA controller mess up", avalon->device_id); + "AVA%i: FPGA controller mess up, %d wrong results", avalon->device_id, result_wrong); dev_error(avalon, REASON_DEV_COMMS_ERROR); sleep(1); avalon_init(avalon); From 8a90b5dd10e8b11cfacfa5a722ba56fdd99a3c6f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 15:05:30 +1000 Subject: [PATCH 50/79] Use replacement of work items in the avalon buffer as needed instead of flushing them. --- driver-avalon.c | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index e179a8de..3d670765 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -705,29 +705,6 @@ static void avalon_free_work(struct thr_info *thr) } } -static void avalon_free_work_array(struct thr_info *thr) -{ - struct cgpu_info *avalon; - struct work **works; - int i, j, mc; - - avalon = thr->cgpu; - avalon->queued = 0; - if (unlikely(!avalon->works)) - return; - works = avalon->works; - mc = avalon_infos[avalon->device_id]->miner_count; - if (++avalon->work_array > 3) - avalon->work_array = 0; - - for (i = avalon->work_array * mc, j = 0; j < mc; i++, j++) { - if (likely(works[i])) { - work_completed(avalon, works[i]); - works[i] = NULL; - } - } -} - static void do_avalon_close(struct thr_info *thr) { struct avalon_result ar; @@ -794,9 +771,11 @@ static inline void adjust_fan(struct avalon_info *info) } } +/* We use a replacement algorithm to only remove references to work done from + * the buffer when we need the extra space for new work. */ static bool avalon_fill(struct cgpu_info *avalon) { - int subid, mc = avalon_infos[avalon->device_id]->miner_count; + int subid, slot, mc = avalon_infos[avalon->device_id]->miner_count; struct work *work; if (avalon->queued >= mc) @@ -806,12 +785,22 @@ static bool avalon_fill(struct cgpu_info *avalon) return false; subid = avalon->queued++; work->subid = subid; - avalon->works[avalon->work_array * mc + subid] = work; + slot = avalon->work_array * mc + subid; + if (likely(avalon->works[slot])) + work_completed(avalon, avalon->works[slot]); + avalon->works[slot] = work; if (avalon->queued >= mc) return true; return false; } +static void avalon_rotate_array(struct cgpu_info *avalon) +{ + avalon->queued = 0; + if (++avalon->work_array > 3) + avalon->work_array = 0; +} + static int64_t avalon_scanhash(struct thr_info *thr) { struct cgpu_info *avalon; @@ -874,7 +863,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) } if (ret == AVA_SEND_BUFFER_EMPTY && (i + 1 == end_count)) { first_try = 1; - avalon_free_work_array(thr); + avalon_rotate_array(avalon); return 0xffffffff; } @@ -951,7 +940,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) return 0; } - avalon_free_work_array(thr); + avalon_rotate_array(avalon); record_temp_fan(info, &ar, &(avalon->temp)); applog(LOG_INFO, From 0c35f67aa9540c6544dead314b5c4a6c56051f7b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 15:36:18 +1000 Subject: [PATCH 51/79] Make the avalon array size a macro. --- driver-avalon.c | 5 +++-- driver-avalon.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 3d670765..dd762b86 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -670,7 +670,8 @@ static bool avalon_prepare(struct thr_info *thr) struct timeval now; free(avalon->works); - avalon->works = calloc(info->miner_count * sizeof(struct work *), 4); + avalon->works = calloc(info->miner_count * sizeof(struct work *), + AVALON_ARRAY_SIZE); if (!avalon->works) quit(1, "Failed to calloc avalon works in avalon_prepare"); if (avalon->device_fd == -1) @@ -797,7 +798,7 @@ static bool avalon_fill(struct cgpu_info *avalon) static void avalon_rotate_array(struct cgpu_info *avalon) { avalon->queued = 0; - if (++avalon->work_array > 3) + if (++avalon->work_array >= AVALON_ARRAY_SIZE) avalon->work_array = 0; } diff --git a/driver-avalon.h b/driver-avalon.h index 93c2e60c..cdbd0d28 100644 --- a/driver-avalon.h +++ b/driver-avalon.h @@ -99,6 +99,7 @@ struct avalon_info { #define AVALON_WRITE_SIZE (sizeof(struct avalon_task)) #define AVALON_READ_SIZE (sizeof(struct avalon_result)) +#define AVALON_ARRAY_SIZE 4 #define AVA_GETS_ERROR -1 #define AVA_GETS_OK 0 From 5c7a32fde83d6d2afe9dcf0a600503a26a8761af Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 21:26:10 +1000 Subject: [PATCH 52/79] Rationalise and simplify the share diff and block solve detection to a common site. --- cgminer.c | 119 ++++++++++++++++-------------------------------------- miner.h | 3 +- 2 files changed, 37 insertions(+), 85 deletions(-) diff --git a/cgminer.c b/cgminer.c index cd8e6c1b..559e22a5 100644 --- a/cgminer.c +++ b/cgminer.c @@ -242,7 +242,7 @@ static char datestamp[40]; static char blocktime[32]; struct timeval block_timeval; static char best_share[8] = "0"; -double current_diff; +double current_diff = 0xFFFFFFFFFFFFFFFF; static char block_diff[8]; uint64_t best_diff = 0; @@ -2266,52 +2266,6 @@ void clear_logwin(void) } #endif -/* Returns true if the regenerated work->hash solves a block */ -static bool solves_block(const struct work *work) -{ - uint32_t *hash32 = (uint32_t *)(work->hash); - uint32_t difficulty = 0; - uint32_t diffbytes = 0; - uint32_t diffvalue = 0; - uint32_t diffcmp[8]; - int diffshift = 0; - int i; - - difficulty = swab32(*((uint32_t *)(work->data + 72))); - - diffbytes = ((difficulty >> 24) & 0xff) - 3; - diffvalue = difficulty & 0x00ffffff; - - diffshift = (diffbytes % 4) * 8; - if (diffshift == 0) { - diffshift = 32; - diffbytes--; - } - - memset(diffcmp, 0, 32); - diffbytes >>= 2; - /* Sanity check looking for overflow */ - if (unlikely(diffbytes > 6)) - return false; - diffcmp[diffbytes + 1] = diffvalue >> (32 - diffshift); - diffcmp[diffbytes] = diffvalue << diffshift; - - for (i = 7; i >= 0; i--) { - if (hash32[i] > diffcmp[i]) - return false; - if (hash32[i] < diffcmp[i]) - return true; - } - - // https://en.bitcoin.it/wiki/Block says: "numerically below" - // https://en.bitcoin.it/wiki/Target says: "lower than or equal to" - // code in bitcoind 0.3.24 main.cpp CheckWork() says: if (hash > hashTarget) return false; - if (hash32[0] == diffcmp[0]) - return true; - else - return false; -} - static void enable_pool(struct pool *pool) { if (pool->enabled != POOL_ENABLED) { @@ -2461,34 +2415,6 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work, } } -static const uint64_t diffone = 0xFFFF000000000000ull; - -static uint64_t share_diff(const struct work *work) -{ - uint64_t *data64, d64; - char rhash[32]; - uint64_t ret; - - swab256(rhash, work->hash); - if (opt_scrypt) - data64 = (uint64_t *)(rhash + 2); - else - data64 = (uint64_t *)(rhash + 4); - d64 = be64toh(*data64); - if (unlikely(!d64)) - d64 = 1; - ret = diffone / d64; - cg_wlock(&control_lock); - if (ret > best_diff) { - best_diff = ret; - suffix_string(best_diff, best_share, 0); - } - if (ret > work->pool->best_diff) - work->pool->best_diff = ret; - cg_wunlock(&control_lock); - return ret; -} - static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) { char *hexstr = NULL; @@ -2583,15 +2509,13 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) int intdiff = floor(work->work_difficulty); char diffdisp[16], *outhash; unsigned char rhash[32]; - uint64_t sharediff; swab256(rhash, work->hash); if (opt_scrypt) outhash = bin2hex(rhash + 2, 4); else outhash = bin2hex(rhash + 4, 4); - sharediff = share_diff(work); - suffix_string(sharediff, diffdisp, 0); + suffix_string(work->share_diff, diffdisp, 0); sprintf(hashshow, "%s Diff %s/%d%s", outhash, diffdisp, intdiff, work->block? " BLOCK!" : ""); free(outhash); @@ -2733,6 +2657,7 @@ static inline struct pool *select_pool(bool lagging) } static double DIFFEXACTONE = 26959946667150639794667015087019630673637144422540572481103610249215.0; +static const uint64_t diffone = 0xFFFF000000000000ull; /* * Calculate the work share difficulty @@ -3261,6 +3186,32 @@ static bool stale_work(struct work *work, bool share) return false; } +static uint64_t share_diff(const struct work *work) +{ + uint64_t *data64, d64; + char rhash[32]; + uint64_t ret; + + swab256(rhash, work->hash); + if (opt_scrypt) + data64 = (uint64_t *)(rhash + 2); + else + data64 = (uint64_t *)(rhash + 4); + d64 = be64toh(*data64); + if (unlikely(!d64)) + d64 = 1; + ret = diffone / d64; + cg_wlock(&control_lock); + if (ret > best_diff) { + best_diff = ret; + suffix_string(best_diff, best_share, 0); + } + if (ret > work->pool->best_diff) + work->pool->best_diff = ret; + cg_wunlock(&control_lock); + return ret; +} + static void regen_hash(struct work *work) { uint32_t *data32 = (uint32_t *)(work->data); @@ -3273,15 +3224,16 @@ static void regen_hash(struct work *work) sha2(hash1, 32, (unsigned char *)(work->hash)); } -static void check_solve(struct work *work) +static void rebuild_hash(struct work *work) { if (opt_scrypt) scrypt_outputhash(work); else regen_hash(work); - work->block = solves_block(work); - if (unlikely(work->block)) { + work->share_diff = share_diff(work); + if (unlikely(work->share_diff >= current_diff)) { + work->block = true; work->pool->solved++; found_blocks++; work->mandatory = true; @@ -3304,7 +3256,7 @@ static void *submit_work_thread(void *userdata) applog(LOG_DEBUG, "Creating extra submit work thread"); - check_solve(work); + rebuild_hash(work); if (stale_work(work, true)) { if (opt_submit_stale) @@ -4757,7 +4709,6 @@ static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val, struct stratum_share *sshare) { struct work *work = sshare->work; - uint64_t sharediff = share_diff(work); char hashshow[65]; uint32_t *hash32; char diffdisp[16]; @@ -4765,7 +4716,7 @@ static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val, hash32 = (uint32_t *)(work->hash); intdiff = floor(work->work_difficulty); - suffix_string(sharediff, diffdisp, 0); + suffix_string(work->share_diff, diffdisp, 0); sprintf(hashshow, "%08lx Diff %s/%d%s", (unsigned long)htole32(hash32[6]), diffdisp, intdiff, work->block? " BLOCK!" : ""); share_result(val, res_val, err_val, work, hashshow, false, ""); diff --git a/miner.h b/miner.h index 9aa87419..b4b71ceb 100644 --- a/miner.h +++ b/miner.h @@ -1119,7 +1119,8 @@ struct work { unsigned char target[32]; unsigned char hash[32]; - double device_diff; + double device_diff; + uint64_t share_diff; int rolls; From c2a6392a9d56faf34618651b21c210eb9be21c03 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 22:29:32 +1000 Subject: [PATCH 53/79] Avalon driver is missing the drv_id. --- driver-avalon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/driver-avalon.c b/driver-avalon.c index dd762b86..f1d81016 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -995,6 +995,7 @@ static void avalon_shutdown(struct thr_info *thr) } struct device_drv avalon_drv = { + .drv_id = DRIVER_AVALON, .dname = "avalon", .name = "AVA", .drv_detect = avalon_detect, From 6c5c6e99a32315af9ee345830a10fd770fa615b8 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Apr 2013 22:42:31 +1000 Subject: [PATCH 54/79] Reinstate the matching_work_count per subdevice on avalon based on the work subid. --- driver-avalon.c | 27 +++++++++++++++++++++++++-- driver-avalon.h | 2 +- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index f1d81016..1ae03588 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -290,7 +290,7 @@ static bool avalon_decode_nonce(struct thr_info *thr, struct avalon_result *ar, return false; info = avalon_infos[avalon->device_id]; - info->matching_work++; + info->matching_work[work->subid]++; *nonce = htole32(ar->nonce); submit_nonce(thr, work, *nonce); @@ -984,7 +984,30 @@ static struct api_data *avalon_api_stats(struct cgpu_info *cgpu) root = api_add_int(root, "temp_max", &(info->temp_max), false); root = api_add_int(root, "no_matching_work", &(info->no_matching_work), false); - root = api_add_int(root, "matching_work_count", &(info->matching_work), false); + root = api_add_int(root, "matching_work_count1", &(info->matching_work[0]), false); + root = api_add_int(root, "matching_work_count2", &(info->matching_work[1]), false); + root = api_add_int(root, "matching_work_count3", &(info->matching_work[2]), false); + root = api_add_int(root, "matching_work_count4", &(info->matching_work[3]), false); + root = api_add_int(root, "matching_work_count5", &(info->matching_work[4]), false); + root = api_add_int(root, "matching_work_count6", &(info->matching_work[5]), false); + root = api_add_int(root, "matching_work_count7", &(info->matching_work[6]), false); + root = api_add_int(root, "matching_work_count8", &(info->matching_work[7]), false); + root = api_add_int(root, "matching_work_count9", &(info->matching_work[8]), false); + root = api_add_int(root, "matching_work_count10", &(info->matching_work[9]), false); + root = api_add_int(root, "matching_work_count11", &(info->matching_work[10]), false); + root = api_add_int(root, "matching_work_count12", &(info->matching_work[11]), false); + root = api_add_int(root, "matching_work_count13", &(info->matching_work[12]), false); + root = api_add_int(root, "matching_work_count14", &(info->matching_work[13]), false); + root = api_add_int(root, "matching_work_count15", &(info->matching_work[14]), false); + root = api_add_int(root, "matching_work_count16", &(info->matching_work[15]), false); + root = api_add_int(root, "matching_work_count17", &(info->matching_work[16]), false); + root = api_add_int(root, "matching_work_count18", &(info->matching_work[17]), false); + root = api_add_int(root, "matching_work_count19", &(info->matching_work[18]), false); + root = api_add_int(root, "matching_work_count20", &(info->matching_work[19]), false); + root = api_add_int(root, "matching_work_count21", &(info->matching_work[20]), false); + root = api_add_int(root, "matching_work_count22", &(info->matching_work[21]), false); + root = api_add_int(root, "matching_work_count23", &(info->matching_work[22]), false); + root = api_add_int(root, "matching_work_count24", &(info->matching_work[23]), false); return root; } diff --git a/driver-avalon.h b/driver-avalon.h index cdbd0d28..ed745e77 100644 --- a/driver-avalon.h +++ b/driver-avalon.h @@ -92,7 +92,7 @@ struct avalon_info { int fan_pwm; int no_matching_work; - int matching_work; + int matching_work[AVALON_DEFAULT_MINER_NUM]; int frequency; }; From d57a4e0c2769da1612b61cae91e44391bdefbaba Mon Sep 17 00:00:00 2001 From: Xiangfu Date: Mon, 8 Apr 2013 23:37:04 +0800 Subject: [PATCH 55/79] if hash_count == 0; reinit avalon, fix the 0MHS bug use the max value of temp1 and temp2 for fan control --- driver-avalon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 1ae03588..b4932e60 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -744,7 +744,7 @@ static inline void record_temp_fan(struct avalon_info *info, struct avalon_resul info->temp2 = 0 - ((~ar->temp2 & 0x7f) + 1); } - *temp_avg = info->temp2; + *temp_avg = info->temp2 > info->temp1 ? info->temp2 : info->temp1; if (info->temp0 > info->temp_max) info->temp_max = info->temp0; @@ -929,7 +929,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec, elapsed.tv_usec); } } - if (result_wrong >= avalon_get_work_count) { + if (result_wrong >= avalon_get_work_count || hash_count == 0) { /* This means FPGA controller gave all wrong results, so * try to reset the Avalon */ do_avalon_close(thr); From f68930138d360fc3cd78ec71f332d72ae6bf015a Mon Sep 17 00:00:00 2001 From: Xiangfu Date: Mon, 8 Apr 2013 23:39:08 +0800 Subject: [PATCH 56/79] for some reason network down. one simple cgminer command: "cgminer -o 127.0.0.1:8888 -O fa:ke --avalon-options 115200:32:10:50:256" can idle the avalon for safe power and protect chip --- driver-avalon.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index b4932e60..29662e4c 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -586,8 +586,8 @@ static bool avalon_detect_one(const char *devpath) } avalon_infos = realloc(avalon_infos, - sizeof(struct avalon_info *) * - (total_devices + 1)); + sizeof(struct avalon_info *) * + (total_devices + 1)); applog(LOG_INFO, "Avalon Detect: Found at %s, mark as %d", devpath, avalon->device_id); @@ -618,14 +618,11 @@ static bool avalon_detect_one(const char *devpath) info->temp_old = 0; info->frequency = frequency; - /* Do something for failed reset ? */ - if (0) { - /* Set asic to idle mode after detect */ - avalon_idle(avalon); - avalon->device_fd = -1; + /* Set asic to idle mode after detect */ + avalon_idle(avalon); + avalon->device_fd = -1; - avalon_close(fd); - } + avalon_close(fd); return true; } From dd1c8bd19890dd000177f9b3b7af592fbc3fe2c5 Mon Sep 17 00:00:00 2001 From: Xiangfu Date: Mon, 8 Apr 2013 23:55:09 +0800 Subject: [PATCH 57/79] fix the fan control on max temp2/3 --- driver-avalon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon.c b/driver-avalon.c index 29662e4c..b1d3fb3b 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -947,7 +947,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) info->fan0, info->fan1, info->fan2, info->temp0, info->temp1, info->temp2, info->temp_max); info->temp_history_index++; - info->temp_sum += info->temp2; + info->temp_sum += avalon->temp; applog(LOG_DEBUG, "Avalon: temp_index: %d, temp_count: %d, temp_old: %d", info->temp_history_index, info->temp_history_count, info->temp_old); if (info->temp_history_index == info->temp_history_count) { From 6400088f7a157718629f85b0fb2aecff2b63a9e5 Mon Sep 17 00:00:00 2001 From: ckolivas Date: Wed, 10 Apr 2013 10:59:38 +1000 Subject: [PATCH 58/79] Fix warning on 32bit. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 559e22a5..cf5b7002 100644 --- a/cgminer.c +++ b/cgminer.c @@ -242,7 +242,7 @@ static char datestamp[40]; static char blocktime[32]; struct timeval block_timeval; static char best_share[8] = "0"; -double current_diff = 0xFFFFFFFFFFFFFFFF; +double current_diff = 0xFFFFFFFFFFFFFFFFULL; static char block_diff[8]; uint64_t best_diff = 0; From 874b25f979ed2d217010c5f1c0eb8865f7893d00 Mon Sep 17 00:00:00 2001 From: Xiangfu Date: Wed, 10 Apr 2013 14:10:40 +0800 Subject: [PATCH 59/79] avalon: if result_wrong >= get_work_count jump out the read loop --- driver-avalon.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/driver-avalon.c b/driver-avalon.c index b1d3fb3b..7584c9a9 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -908,6 +908,9 @@ static int64_t avalon_scanhash(struct thr_info *thr) info->no_matching_work++; result_wrong++; + if (result_wrong >= avalon_get_work_count) + break; + if (opt_debug) { timersub(&tv_finish, &tv_start, &elapsed); applog(LOG_DEBUG,"Avalon: no matching work: %d" From c62b985c049bacf2b42fe18cffd41fa6cb33401a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 10 Apr 2013 18:42:50 +1000 Subject: [PATCH 60/79] Wrap result wrong tests in avalon scanhash in unlikely() and only consider a hash count of zero wrong if a restart wasn't issued. --- driver-avalon.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 7584c9a9..377a7fa0 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -908,7 +908,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) info->no_matching_work++; result_wrong++; - if (result_wrong >= avalon_get_work_count) + if (unlikely(result_wrong >= avalon_get_work_count)) break; if (opt_debug) { @@ -929,7 +929,8 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec, elapsed.tv_usec); } } - if (result_wrong >= avalon_get_work_count || hash_count == 0) { + if (unlikely(result_wrong >= avalon_get_work_count || + (hash_count == 0 && ret != AVA_GETS_RESTART))) { /* This means FPGA controller gave all wrong results, so * try to reset the Avalon */ do_avalon_close(thr); From b1dfc12b3ff66d8cf65da403238d2646fe291315 Mon Sep 17 00:00:00 2001 From: ckolivas Date: Thu, 11 Apr 2013 11:43:20 +1000 Subject: [PATCH 61/79] Add more faqs to README. --- README | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README b/README index ab7971d5..88bd1e48 100644 --- a/README +++ b/README @@ -984,6 +984,10 @@ Q: Can I mine with Nvidia or Intel GPUs? A: Yes but their hashrate is very poor and likely you'll be using much more energy than you'll be earning in coins. +Q: Can I mine on both Nvidia and AMD GPUs at the same time? +A: No, you must run one instance of cgminer with the --gpu-platform option for +each. + Q: Can I mine on Linux without running Xorg? A: With Nvidia you can, but with AMD you cannot. @@ -1001,13 +1005,29 @@ A: You are generating garbage hashes due to your choice of settings. Your Work Utility (WU) value will confirm you are not generating garbage. You should be getting about .9WU per kHash. If not, then try decreasing your intensity, do not increase the number of gpu-threads, and consider adding -system RAM to match your GPU ram. +system RAM to match your GPU ram. You may also be using a bad combination +of driver and/or SDK. Q: Scrypt fails to initialise the kernel every time? A: Your parameters are too high. Don't add GPU threads, don't set intensity too high, decrease thread concurrency. See the SCRYPT-README for a lot more help. +Q: Cgminer stops mining (or my GPUs go DEAD) and I can't close it? +A: Once the driver has crashed, there is no way for cgminer to close cleanly. +You will have to kill it, and depending on how corrupted your driver state +has gotten, you may even need to reboot. Windows is known to reset drivers +when they fail and cgminer will be stuck trying to use the old driver instance. + +Q: I can't get any monitoring of temperatures or fanspeed with cgminer when +I start it remotely? +A: With linux, make sure to export the DISPLAY variable. On windows, you +cannot access these monitoring values via a remote session. + +Q: I switch users on windows and my mining stops working? +A: That's correct, it does. It's a permissions issue that there is no known +fix for. + Q: My network gets slower and slower and then dies for a minute? A; Try the --net-delay option. From 4c1960419901206a1d5bbd2a7104a5956dd31df9 Mon Sep 17 00:00:00 2001 From: ckolivas Date: Thu, 11 Apr 2013 13:31:17 +1000 Subject: [PATCH 62/79] Yet more README faqs. --- README | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README b/README index 88bd1e48..1ea135b9 100644 --- a/README +++ b/README @@ -1024,6 +1024,11 @@ I start it remotely? A: With linux, make sure to export the DISPLAY variable. On windows, you cannot access these monitoring values via a remote session. +Q: I change my GPU engine/memory/voltage and cgminer reports back no change? +A: Cgminer asks the GPU using the ATI Display Library to change settings, but +the driver and hardware are free to do what it wants with that query, including +ignoring it. Some GPUs are locked with one or more of those properties as well. + Q: I switch users on windows and my mining stops working? A: That's correct, it does. It's a permissions issue that there is no known fix for. From 2a73254cab418ab4ea094c90a14fd8f14834517a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 09:45:29 +1000 Subject: [PATCH 63/79] More README faqs. --- README | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README b/README index 1ea135b9..9abb460e 100644 --- a/README +++ b/README @@ -1022,13 +1022,19 @@ when they fail and cgminer will be stuck trying to use the old driver instance. Q: I can't get any monitoring of temperatures or fanspeed with cgminer when I start it remotely? A: With linux, make sure to export the DISPLAY variable. On windows, you -cannot access these monitoring values via a remote session. +cannot access these monitoring values via RDP. This should work with tightVNC +or teamviewer though. Q: I change my GPU engine/memory/voltage and cgminer reports back no change? A: Cgminer asks the GPU using the ATI Display Library to change settings, but the driver and hardware are free to do what it wants with that query, including ignoring it. Some GPUs are locked with one or more of those properties as well. +Q: I have some random GPU performance related problem not addressed above. +A: Seriously, it's the driver and/or SDK. Uninstall them and start again, +noting there is no clean way to uninstall them so you have to use extra tools +or do it manually. + Q: I switch users on windows and my mining stops working? A: That's correct, it does. It's a permissions issue that there is no known fix for. From 0488a850cd24acbe25e4818f11879b8bb37625a7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 10:18:03 +1000 Subject: [PATCH 64/79] More GPU faqs. --- README | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README b/README index 9abb460e..af261124 100644 --- a/README +++ b/README @@ -1030,6 +1030,12 @@ A: Cgminer asks the GPU using the ATI Display Library to change settings, but the driver and hardware are free to do what it wants with that query, including ignoring it. Some GPUs are locked with one or more of those properties as well. +Q: I have multiple GPUs and although many devices show up, it appears to be +working only on one GPU splitting it up. +A: Your driver setup is failing to properly use the accessory GPUs. Your +driver may be configured wrong or you have a driver version that needs a dummy +plug on all the GPUs that aren't connected to a monitor. + Q: I have some random GPU performance related problem not addressed above. A: Seriously, it's the driver and/or SDK. Uninstall them and start again, noting there is no clean way to uninstall them so you have to use extra tools From ec9390dc4e03afe21ae56457624c04213ffcb45d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 10:19:37 +1000 Subject: [PATCH 65/79] Variable is already initialised in global scope. --- api-example.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api-example.c b/api-example.c index 9bd44791..71b5b002 100644 --- a/api-example.c +++ b/api-example.c @@ -145,7 +145,7 @@ static const char SEPARATOR = '|'; static const char COMMA = ','; static const char EQ = '='; -static int ONLY = 0; +static int ONLY; void display(char *buf) { From 29f0ac77da7bb93526d28898cc15e30cc99165a7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 10:30:12 +1000 Subject: [PATCH 66/79] Avoid recursive locks in fill_queue. --- cgminer.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/cgminer.c b/cgminer.c index 98d735fd..bbba3a18 100644 --- a/cgminer.c +++ b/cgminer.c @@ -5728,15 +5728,19 @@ static void fill_queue(struct thr_info *mythr, struct cgpu_info *cgpu, struct de { thread_reportout(mythr); do { - struct work *work; + bool need_work; + + rd_lock(&cgpu->qlock); + need_work = (HASH_COUNT(cgpu->queued_work) == cgpu->queued_count); + rd_unlock(&cgpu->qlock); + + if (need_work) { + struct work *work = get_work(mythr, thr_id); - wr_lock(&cgpu->qlock); - if (HASH_COUNT(cgpu->queued_work) == cgpu->queued_count) { - work = get_work(mythr, thr_id); - work->device_diff = MIN(drv->max_diff, work->work_difficulty); + wr_lock(&cgpu->qlock); HASH_ADD_INT(cgpu->queued_work, id, work); + wr_unlock(&cgpu->qlock); } - wr_unlock(&cgpu->qlock); /* The queue_full function should be used by the driver to * actually place work items on the physical device if it * does have a queue. */ From b948669a4f9af15073c0ae359229a55b6b51a553 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 11:13:48 +1000 Subject: [PATCH 67/79] Avoid applog while ch_lock is held. --- cgminer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index bbba3a18..c1a44dbc 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3588,8 +3588,9 @@ static void set_curblock(char *hexstr, unsigned char *hash) free(current_fullhash); current_fullhash = bin2hex(block_hash_swap, 32); get_timestamp(blocktime, &block_timeval); - applog(LOG_INFO, "New block: %s... diff %s", current_hash, block_diff); cg_wunlock(&ch_lock); + + applog(LOG_INFO, "New block: %s... diff %s", current_hash, block_diff); } /* Search to see if this string is from a block that has been seen before */ From 51fbcfed6d9c120cb7d2d37a4ad77353aceff5f4 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 11:25:48 +1000 Subject: [PATCH 68/79] Avoid more recursive locks. --- cgminer.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index c1a44dbc..23e5bd95 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2061,10 +2061,8 @@ static void curses_print_status(void) pool->has_gbt ? "GBT" : "LP", pool->rpc_user); } wclrtoeol(statuswin); - cg_rlock(&ch_lock); mvwprintw(statuswin, 5, 0, " Block: %s... Diff:%s Started: %s Best share: %s ", current_hash, block_diff, blocktime, best_share); - cg_runlock(&ch_lock); mvwhline(statuswin, 6, 0, '-', 80); mvwhline(statuswin, statusy - 1, 0, '-', 80); mvwprintw(statuswin, devcursor - 1, 1, "[P]ool management %s[S]ettings [D]isplay options [Q]uit", @@ -3094,7 +3092,6 @@ static bool clone_available(void) roll_work(work); work_clone = make_clone(work); roll_work(work); - applog(LOG_DEBUG, "Pushing cloned available work to stage thread"); cloned = true; break; } @@ -3103,8 +3100,10 @@ static bool clone_available(void) out_unlock: mutex_unlock(stgd_lock); - if (cloned) + if (cloned) { + applog(LOG_DEBUG, "Pushing cloned available work to stage thread"); stage_work(work_clone); + } return cloned; } From 3209c113d1cca200a393c8dbfaee81d4c404362c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 11:34:21 +1000 Subject: [PATCH 69/79] Avoid applog under pool_lock. --- cgminer.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index 23e5bd95..3eeaa40d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2935,7 +2935,6 @@ static void recruit_curl(struct pool *pool) list_add(&ce->node, &pool->curlring); pool->curls++; - applog(LOG_DEBUG, "Recruited curl %d for pool %d", pool->curls, pool->pool_no); } /* Grab an available curl if there is one. If not, then recruit extra curls @@ -2946,23 +2945,29 @@ static void recruit_curl(struct pool *pool) static struct curl_ent *pop_curl_entry(struct pool *pool) { int curl_limit = opt_delaynet ? 5 : (mining_threads + opt_queue) * 2; + bool recruited = false; struct curl_ent *ce; mutex_lock(&pool->pool_lock); retry: - if (!pool->curls) + if (!pool->curls) { recruit_curl(pool); - else if (list_empty(&pool->curlring)) { + recruited = true; + } else if (list_empty(&pool->curlring)) { if (pool->curls >= curl_limit) { pthread_cond_wait(&pool->cr_cond, &pool->pool_lock); goto retry; - } else + } else { recruit_curl(pool); + recruited = true; + } } ce = list_entry(pool->curlring.next, struct curl_ent, node); list_del(&ce->node); mutex_unlock(&pool->pool_lock); + if (recruited) + applog(LOG_DEBUG, "Recruited curl for pool %d", pool->pool_no); return ce; } From 8d22ca1ac1087963846b5c5c5a436edac84f1fec Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 11:42:16 +1000 Subject: [PATCH 70/79] Put spacing around locking code for clarity. --- cgminer.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/cgminer.c b/cgminer.c index 3eeaa40d..8470cf98 100644 --- a/cgminer.c +++ b/cgminer.c @@ -398,6 +398,7 @@ struct thr_info *get_thread(int thr_id) rd_lock(&mining_thr_lock); thr = mining_thr[thr_id]; rd_unlock(&mining_thr_lock); + return thr; } @@ -415,6 +416,7 @@ struct cgpu_info *get_devices(int id) rd_lock(&devices_lock); cgpu = devices[id]; rd_unlock(&devices_lock); + return cgpu; } @@ -455,6 +457,7 @@ static void sharelog(const char*disposition, const struct work*work) ret = fwrite(s, rv, 1, sharelog_file); fflush(sharelog_file); mutex_unlock(&sharelog_lock); + if (ret != 1) applog(LOG_ERR, "sharelog fwrite error"); } @@ -500,6 +503,7 @@ static bool pool_tset(struct pool *pool, bool *var) ret = *var; *var = true; mutex_unlock(&pool->pool_lock); + return ret; } @@ -511,6 +515,7 @@ bool pool_tclear(struct pool *pool, bool *var) ret = *var; *var = false; mutex_unlock(&pool->pool_lock); + return ret; } @@ -521,6 +526,7 @@ struct pool *current_pool(void) cg_rlock(&control_lock); pool = currentpool; cg_runlock(&control_lock); + return pool; } @@ -790,6 +796,7 @@ static void load_temp_cutoffs() devices[i]->cutofftemp = opt_cutofftemp; } rd_unlock(&devices_lock); + return; } if (device <= 1) { @@ -1491,9 +1498,11 @@ static struct work *make_work(void) if (unlikely(!work)) quit(1, "Failed to calloc work in make_work"); + cg_wlock(&control_lock); work->id = total_work++; cg_wunlock(&control_lock); + return work; } @@ -1886,6 +1895,7 @@ static int total_staged(void) mutex_lock(stgd_lock); ret = __total_staged(); mutex_unlock(stgd_lock); + return ret; } @@ -3158,10 +3168,12 @@ static bool stale_work(struct work *work, bool share) } same_job = true; + cg_rlock(&pool->data_lock); if (strcmp(work->job_id, pool->swork.job_id)) same_job = false; cg_runlock(&pool->data_lock); + if (!same_job) { applog(LOG_DEBUG, "Work stale due to stratum job_id mismatch"); return true; @@ -3205,6 +3217,7 @@ static uint64_t share_diff(const struct work *work) if (unlikely(!d64)) d64 = 1; ret = diffone / d64; + cg_wlock(&control_lock); if (ret > best_diff) { best_diff = ret; @@ -3213,6 +3226,7 @@ static uint64_t share_diff(const struct work *work) if (ret > work->pool->best_diff) work->pool->best_diff = ret; cg_wunlock(&control_lock); + return ret; } @@ -3277,6 +3291,7 @@ static void *submit_work_thread(void *userdata) total_diff_stale += work->work_difficulty; pool->diff_stale += work->work_difficulty; mutex_unlock(&stats_lock); + goto out; } work->stale = true; @@ -3316,10 +3331,12 @@ static void *submit_work_thread(void *userdata) if (likely(stratum_send(pool, s, strlen(s)))) { if (pool_tclear(pool, &pool->submit_fail)) applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no); + mutex_lock(&sshare_lock); HASH_ADD_INT(stratum_shares, id, sshare); pool->sshares++; mutex_unlock(&sshare_lock); + applog(LOG_DEBUG, "Successfully submitted, adding to stratum_shares db"); submitted = true; break; @@ -3365,6 +3382,7 @@ static void *submit_work_thread(void *userdata) total_diff_stale += work->work_difficulty; pool->diff_stale += work->work_difficulty; mutex_unlock(&stats_lock); + break; } @@ -3605,6 +3623,7 @@ static bool block_exists(char *hexstr) rd_lock(&blk_lock); HASH_FIND_STR(blocks, hexstr, s); rd_unlock(&blk_lock); + if (s) return true; return false; @@ -3693,6 +3712,7 @@ static bool test_work_current(struct work *work) quit (1, "test_work_current OOM"); strcpy(s->hash, hexstr); s->block_no = new_blocks++; + wr_lock(&blk_lock); /* Only keep the last hour's worth of blocks in memory since * work from blocks before this is virtually impossible and we @@ -3709,6 +3729,7 @@ static bool test_work_current(struct work *work) HASH_ADD_STR(blocks, hash, s); set_blockdiff(work); wr_unlock(&blk_lock); + if (deleted_block) applog(LOG_DEBUG, "Deleted block %d from database", deleted_block); set_curblock(hexstr, work->data); @@ -4701,6 +4722,7 @@ static void hashmeter(int thr_id, struct timeval *diff, local_mhashes_done = 0; out_unlock: mutex_unlock(&hash_lock); + if (showlog) { if (!curses_active) { printf("%s \r", statusline); @@ -4763,6 +4785,7 @@ static bool parse_stratum_response(struct pool *pool, char *s) } id = json_integer_value(id_val); + mutex_lock(&sshare_lock); HASH_FIND_INT(stratum_shares, &id, sshare); if (sshare) { @@ -4770,6 +4793,7 @@ static bool parse_stratum_response(struct pool *pool, char *s) pool->sshares--; } mutex_unlock(&sshare_lock); + if (!sshare) { if (json_is_true(res_val)) applog(LOG_NOTICE, "Accepted untracked stratum share from pool %d", pool->pool_no); @@ -4840,6 +4864,7 @@ static int cp_prio(void) cg_rlock(&control_lock); prio = currentpool->prio; cg_runlock(&control_lock); + return prio; } @@ -4901,6 +4926,7 @@ static bool supports_resume(struct pool *pool) cg_rlock(&pool->data_lock); ret = (pool->sessionid != NULL); cg_runlock(&pool->data_lock); + return ret; } @@ -5819,6 +5845,7 @@ void work_completed(struct cgpu_info *cgpu, struct work *work) cgpu->queued_count--; HASH_DEL(cgpu->queued_work, work); wr_unlock(&cgpu->qlock); + free_work(work); } @@ -6159,6 +6186,7 @@ static void reap_curl(struct pool *pool) int reaped = 0; gettimeofday(&now, NULL); + mutex_lock(&pool->pool_lock); list_for_each_entry_safe(ent, iter, &pool->curlring, node) { if (pool->curls < 2) @@ -6172,6 +6200,7 @@ static void reap_curl(struct pool *pool) } } mutex_unlock(&pool->pool_lock); + if (reaped) applog(LOG_DEBUG, "Reaped %d curl%s from pool %d", reaped, reaped > 1 ? "s" : "", pool->pool_no); } @@ -6294,6 +6323,7 @@ static void *watchdog_thread(void __maybe_unused *userdata) applog(LOG_WARNING, "Will restart execution as scheduled at %02d:%02d", schedstart.tm.tm_hour, schedstart.tm.tm_min); sched_paused = true; + rd_lock(&mining_thr_lock); for (i = 0; i < mining_threads; i++) mining_thr[i]->pause = true; @@ -6577,6 +6607,7 @@ static void *test_pool_thread(void *arg) pools_active = true; } cg_wunlock(&control_lock); + pool_resus(pool); } else pool_died(pool); @@ -6890,9 +6921,11 @@ void fill_device_drv(struct cgpu_info *cgpu) void enable_device(struct cgpu_info *cgpu) { cgpu->deven = DEV_ENABLED; + wr_lock(&devices_lock); devices[cgpu->cgminer_id = cgminer_id_count++] = cgpu; wr_unlock(&devices_lock); + if (hotplug_mode) { new_threads += cgpu->threads; #ifdef HAVE_CURSES @@ -6935,9 +6968,11 @@ bool add_cgpu(struct cgpu_info*cgpu) cgpu->device_id = d->lastid = 0; HASH_ADD_STR(devids, name, d); } + wr_lock(&devices_lock); devices = realloc(devices, sizeof(struct cgpu_info *) * (total_devices + new_devices + 2)); wr_unlock(&devices_lock); + if (hotplug_mode) devices[total_devices + new_devices++] = cgpu; else @@ -6976,6 +7011,7 @@ static void hotplug_process() wr_lock(&mining_thr_lock); mining_thr = realloc(mining_thr, sizeof(thr) * (mining_threads + new_threads + 1)); wr_unlock(&mining_thr_lock); + if (!mining_thr) quit(1, "Failed to hotplug realloc mining_thr"); for (i = 0; i < new_threads; i++) { From 67ebf45c1908749d27e2ae60189167a3e1111f0c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 11:44:19 +1000 Subject: [PATCH 71/79] Avoid applog under cg_wlock. --- cgminer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 8470cf98..b0e3c69b 100644 --- a/cgminer.c +++ b/cgminer.c @@ -6598,16 +6598,20 @@ static void *test_pool_thread(void *arg) if (pool_active(pool, false)) { pool_tset(pool, &pool->lagging); pool_tclear(pool, &pool->idle); + bool first_pool = false; cg_wlock(&control_lock); if (!pools_active) { currentpool = pool; if (pool->pool_no != 0) - applog(LOG_NOTICE, "Switching to pool %d %s - first alive pool", pool->pool_no, pool->rpc_url); + first_pool = true; pools_active = true; } cg_wunlock(&control_lock); + if (unlikely(first_pool)) + applog(LOG_NOTICE, "Switching to pool %d %s - first alive pool", pool->pool_no, pool->rpc_url); + pool_resus(pool); } else pool_died(pool); From d248e7aafac159460bc3b204f5893837d858b68b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 11:50:59 +1000 Subject: [PATCH 72/79] Put spacing around locking in util.c for clarity. --- util.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/util.c b/util.c index b3cb9c03..61233a8d 100644 --- a/util.c +++ b/util.c @@ -710,9 +710,7 @@ void tq_free(struct thread_q *tq) static void tq_freezethaw(struct thread_q *tq, bool frozen) { mutex_lock(&tq->mutex); - tq->frozen = frozen; - pthread_cond_signal(&tq->cond); mutex_unlock(&tq->mutex); } @@ -740,14 +738,12 @@ bool tq_push(struct thread_q *tq, void *data) INIT_LIST_HEAD(&ent->q_node); mutex_lock(&tq->mutex); - if (!tq->frozen) { list_add_tail(&ent->q_node, &tq->q); } else { free(ent); rc = false; } - pthread_cond_signal(&tq->cond); mutex_unlock(&tq->mutex); @@ -761,7 +757,6 @@ void *tq_pop(struct thread_q *tq, const struct timespec *abstime) int rc; mutex_lock(&tq->mutex); - if (!list_empty(&tq->q)) goto pop; @@ -773,16 +768,15 @@ void *tq_pop(struct thread_q *tq, const struct timespec *abstime) goto out; if (list_empty(&tq->q)) goto out; - pop: ent = list_entry(tq->q.next, struct tq_ent, q_node); rval = ent->data; list_del(&ent->q_node); free(ent); - out: mutex_unlock(&tq->mutex); + return rval; } @@ -1441,6 +1435,7 @@ static bool setup_stratum_curl(struct pool *pool) if (unlikely(!pool->stratum_curl)) quit(1, "Failed to curl_easy_init in initiate_stratum"); mutex_unlock(&pool->stratum_lock); + curl = pool->stratum_curl; if (!pool->sockbuf) { @@ -1517,6 +1512,7 @@ void suspend_stratum(struct pool *pool) { clear_sockbuf(pool); applog(LOG_INFO, "Closing socket for stratum pool %d", pool->pool_no); + mutex_lock(&pool->stratum_lock); pool->stratum_active = pool->stratum_notify = false; if (pool->stratum_curl) { @@ -1654,6 +1650,7 @@ out: free(pool->nonce1); pool->sessionid = pool->nonce1 = NULL; cg_wunlock(&pool->data_lock); + applog(LOG_DEBUG, "Failed to resume stratum, trying afresh"); noresume = true; goto resend; From e4effc372ca20170b12d6b555120ea266ba1f383 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 12:01:24 +1000 Subject: [PATCH 73/79] Avoid applog under stratum_lock in __stratum_send. --- util.c | 52 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/util.c b/util.c index 61233a8d..5e221049 100644 --- a/util.c +++ b/util.c @@ -892,16 +892,20 @@ bool extract_sockaddr(struct pool *pool, char *url) return true; } +enum send_ret { + SEND_OK, + SEND_SELECTFAIL, + SEND_SENDFAIL, + SEND_INACTIVE +}; + /* Send a single command across a socket, appending \n to it. This should all * be done under stratum lock except when first establishing the socket */ -static bool __stratum_send(struct pool *pool, char *s, ssize_t len) +static enum send_ret __stratum_send(struct pool *pool, char *s, ssize_t len) { SOCKETTYPE sock = pool->sock; ssize_t ssent = 0; - if (opt_protocol) - applog(LOG_DEBUG, "SEND: %s", s); - strcat(s, "\n"); len++; @@ -912,16 +916,12 @@ static bool __stratum_send(struct pool *pool, char *s, ssize_t len) FD_ZERO(&wd); FD_SET(sock, &wd); - if (select(sock + 1, NULL, &wd, NULL, &timeout) < 1) { - applog(LOG_DEBUG, "Write select failed on pool %d sock", pool->pool_no); - return false; - } + if (select(sock + 1, NULL, &wd, NULL, &timeout) < 1) + return SEND_SELECTFAIL; sent = send(pool->sock, s + ssent, len, 0); if (sent < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - applog(LOG_DEBUG, "Failed to curl_easy_send in stratum_send"); - return false; - } + if (errno != EAGAIN && errno != EWOULDBLOCK) + return SEND_SENDFAIL; sent = 0; } ssent += sent; @@ -931,21 +931,37 @@ static bool __stratum_send(struct pool *pool, char *s, ssize_t len) pool->cgminer_pool_stats.times_sent++; pool->cgminer_pool_stats.bytes_sent += ssent; pool->cgminer_pool_stats.net_bytes_sent += ssent; - return true; + return SEND_OK; } bool stratum_send(struct pool *pool, char *s, ssize_t len) { - bool ret = false; + enum send_ret ret = SEND_INACTIVE; + + if (opt_protocol) + applog(LOG_DEBUG, "SEND: %s", s); mutex_lock(&pool->stratum_lock); if (pool->stratum_active) ret = __stratum_send(pool, s, len); - else - applog(LOG_DEBUG, "Stratum send failed due to no pool stratum_active"); mutex_unlock(&pool->stratum_lock); - return ret; + /* This is to avoid doing applog under stratum_lock */ + switch (ret) { + default: + case SEND_OK: + break; + case SEND_SELECTFAIL: + applog(LOG_DEBUG, "Write select failed on pool %d sock", pool->pool_no); + break; + case SEND_SENDFAIL: + applog(LOG_DEBUG, "Failed to curl_easy_send in stratum_send"); + break; + case SEND_INACTIVE: + applog(LOG_DEBUG, "Stratum send failed due to no pool stratum_active"); + break; + } + return (ret == SEND_OK); } static bool socket_full(struct pool *pool, bool wait) @@ -1557,7 +1573,7 @@ resend: sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": [\""PACKAGE"/"VERSION"\"]}", swork_id++); } - if (!__stratum_send(pool, s, strlen(s))) { + if (__stratum_send(pool, s, strlen(s)) != SEND_OK) { applog(LOG_DEBUG, "Failed to send s in initiate_stratum"); goto out; } From 69c203d88a8f81a5bd17d4f1a1052a0093e11a57 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 12:07:52 +1000 Subject: [PATCH 74/79] Avoid applog under stratum_lock in recv_line. --- util.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/util.c b/util.c index 5e221049..ff423b7a 100644 --- a/util.c +++ b/util.c @@ -1029,6 +1029,12 @@ static void recalloc_sock(struct pool *pool, size_t len) pool->sockbuf_size = new; } +enum recv_ret { + RECV_OK, + RECV_CLOSED, + RECV_RECVFAIL +}; + /* Peeks at a socket to find the first end of line and then reads just that * from the socket and returns that as a malloced char */ char *recv_line(struct pool *pool) @@ -1037,6 +1043,7 @@ char *recv_line(struct pool *pool) char *tok, *sret = NULL; if (!strstr(pool->sockbuf, "\n")) { + enum recv_ret ret = RECV_OK; struct timeval rstart, now; gettimeofday(&rstart, NULL); @@ -1054,11 +1061,11 @@ char *recv_line(struct pool *pool) memset(s, 0, RBUFSIZE); n = recv(pool->sock, s, RECVSIZE, 0); if (!n) { - applog(LOG_DEBUG, "Socket closed waiting in recv_line"); + ret = RECV_CLOSED; break; } if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { - applog(LOG_DEBUG, "Failed to recv sock in recv_line"); + ret = RECV_RECVFAIL; break; } slen = strlen(s); @@ -1067,6 +1074,18 @@ char *recv_line(struct pool *pool) gettimeofday(&now, NULL); } while (tdiff(&now, &rstart) < 60 && !strstr(pool->sockbuf, "\n")); mutex_unlock(&pool->stratum_lock); + + switch (ret) { + default: + case RECV_OK: + break; + case RECV_CLOSED: + applog(LOG_DEBUG, "Socket closed waiting in recv_line"); + break; + case RECV_RECVFAIL: + applog(LOG_DEBUG, "Failed to recv sock in recv_line"); + break; + } } buflen = strlen(pool->sockbuf); From 81549c5bff9de009cc66d5dafd2af13a769ef550 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 12:16:05 +1000 Subject: [PATCH 75/79] Avoid applog in recalloc_sock. --- util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util.c b/util.c index ff423b7a..2e02c226 100644 --- a/util.c +++ b/util.c @@ -1021,7 +1021,8 @@ static void recalloc_sock(struct pool *pool, size_t len) if (new < pool->sockbuf_size) return; new = new + (RBUFSIZE - (new % RBUFSIZE)); - applog(LOG_DEBUG, "Recallocing pool sockbuf to %d", new); + // Avoid potentially recursive locking + // applog(LOG_DEBUG, "Recallocing pool sockbuf to %d", new); pool->sockbuf = realloc(pool->sockbuf, new); if (!pool->sockbuf) quit(1, "Failed to realloc pool sockbuf in recalloc_sock"); From 36bb133e61822e47f79fe2eaca056ba6248b1c53 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 12:34:34 +1000 Subject: [PATCH 76/79] Cleanup when stratum curl fails to initialise. --- util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util.c b/util.c index 2e02c226..ffe4b941 100644 --- a/util.c +++ b/util.c @@ -1501,6 +1501,8 @@ static bool setup_stratum_curl(struct pool *pool) curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1); if (curl_easy_perform(curl)) { applog(LOG_INFO, "Stratum connect failed to pool %d: %s", pool->pool_no, curl_err_str); + curl_easy_cleanup(curl); + pool->stratum_curl = NULL; return false; } curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, (long *)&pool->sock); From 245fbe1c73fa1c2cc78a41be06e58615a662ce71 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 12:42:11 +1000 Subject: [PATCH 77/79] More FAQs. --- README | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README b/README index af261124..deb88d78 100644 --- a/README +++ b/README @@ -1041,6 +1041,11 @@ A: Seriously, it's the driver and/or SDK. Uninstall them and start again, noting there is no clean way to uninstall them so you have to use extra tools or do it manually. +Q: Do I need to recompile after updating my driver/SDK? +A: No. The software is unchanged regardless of which driver/SDK/ADL_SDK version +you are running. However if you change SDKs you should delete any generated +.bin files for them to be recreated with the new SDK. + Q: I switch users on windows and my mining stops working? A: That's correct, it does. It's a permissions issue that there is no known fix for. From dbab07a12dbf5b9b4a5c50a072bd1e96e32c552c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 20:30:02 +1000 Subject: [PATCH 78/79] Only reset an avalon device with no results when there are no results consecutively. --- driver-avalon.c | 27 ++++++++++++++++----------- miner.h | 1 + 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/driver-avalon.c b/driver-avalon.c index 377a7fa0..4ca39528 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -929,17 +929,22 @@ static int64_t avalon_scanhash(struct thr_info *thr) elapsed.tv_sec, elapsed.tv_usec); } } - if (unlikely(result_wrong >= avalon_get_work_count || - (hash_count == 0 && ret != AVA_GETS_RESTART))) { - /* This means FPGA controller gave all wrong results, so - * try to reset the Avalon */ - do_avalon_close(thr); - applog(LOG_ERR, - "AVA%i: FPGA controller mess up, %d wrong results", avalon->device_id, result_wrong); - dev_error(avalon, REASON_DEV_COMMS_ERROR); - sleep(1); - avalon_init(avalon); - return 0; + if (hash_count) { + if (avalon->results < AVALON_ARRAY_SIZE) + avalon->results++; + } else if (unlikely((result_wrong >= avalon_get_work_count ) || + (ret != AVA_GETS_RESTART && --avalon->results < 0))) { + /* Look for all invalid results, or consecutive failure + * to generate any results suggesting the FPGA + * controller has screwed up. */ + do_avalon_close(thr); + applog(LOG_ERR, + "AVA%i: FPGA controller messed up, %d wrong results", + avalon->device_id, result_wrong); + dev_error(avalon, REASON_DEV_COMMS_ERROR); + sleep(1); + avalon_init(avalon); + return 0; } avalon_rotate_array(avalon); diff --git a/miner.h b/miner.h index b4b71ceb..3d275daf 100644 --- a/miner.h +++ b/miner.h @@ -431,6 +431,7 @@ struct cgpu_info { struct work **works; int work_array; int queued; + int results; #endif #ifdef USE_USBUTILS struct cg_usb_info usbinfo; From d41d210b03ee16c9ad4cfb439916b30a341dc9b6 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 15 Apr 2013 23:01:08 +1000 Subject: [PATCH 79/79] Set device_diff for queued work or there will be no diff1 share count. --- cgminer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cgminer.c b/cgminer.c index b0e3c69b..f2840f0d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -5768,6 +5768,7 @@ static void fill_queue(struct thr_info *mythr, struct cgpu_info *cgpu, struct de if (need_work) { struct work *work = get_work(mythr, thr_id); + work->device_diff = MIN(drv->max_diff, work->work_difficulty); wr_lock(&cgpu->qlock); HASH_ADD_INT(cgpu->queued_work, id, work); wr_unlock(&cgpu->qlock);