diff --git a/cgminer.c b/cgminer.c index 0de93f04..e2976fd8 100644 --- a/cgminer.c +++ b/cgminer.c @@ -142,6 +142,7 @@ bool opt_api_listen; bool opt_api_network; bool opt_delaynet; bool opt_disable_pool = true; +char *opt_icarus_options = NULL; char *opt_icarus_timing = NULL; char *opt_kernel_path; @@ -710,6 +711,13 @@ static char *set_api_description(const char *arg) } #ifdef USE_ICARUS +static char *set_icarus_options(const char *arg) +{ + opt_set_charp(arg, &opt_icarus_options); + + return NULL; +} + static char *set_icarus_timing(const char *arg) { opt_set_charp(arg, &opt_icarus_timing); @@ -873,6 +881,9 @@ static struct opt_table opt_config_table[] = { "Override sha256 kernel to use (diablo, poclbm, phatk or diakgcn) - one value or comma separated"), #endif #ifdef USE_ICARUS + OPT_WITH_ARG("--icarus-options", + set_icarus_options, NULL, NULL, + opt_hidden), OPT_WITH_ARG("--icarus-timing", set_icarus_timing, NULL, NULL, opt_hidden), @@ -3011,6 +3022,8 @@ void write_config(FILE *fcfg) fprintf(fcfg, ",\n\"api-description\" : \"%s\"", opt_api_description); if (opt_api_groups) fprintf(fcfg, ",\n\"api-groups\" : \"%s\"", opt_api_groups); + if (opt_icarus_options) + fprintf(fcfg, ",\n\"icarus-options\" : \"%s\"", opt_icarus_options); if (opt_icarus_timing) fprintf(fcfg, ",\n\"icarus-timing\" : \"%s\"", opt_icarus_timing); fputs("\n}", fcfg); diff --git a/driver-icarus.c b/driver-icarus.c index 5f2c78ad..0b3aea7a 100644 --- a/driver-icarus.c +++ b/driver-icarus.c @@ -65,7 +65,7 @@ #define ASSERT1(condition) __maybe_unused static char sizeof_uint32_t_must_be_4[(condition)?1:-1] ASSERT1(sizeof(uint32_t) == 4); -#define ICARUS_READ_TIME ((double)ICARUS_READ_SIZE * (double)8.0 / (double)ICARUS_IO_SPEED) +#define ICARUS_READ_TIME(baud) ((double)ICARUS_READ_SIZE * (double)8.0 / (double)(baud)) // Fraction of a second, USB timeout is measured in // i.e. 10 means 1/10 of a second @@ -176,11 +176,36 @@ struct ICARUS_INFO { // (which will only affect W) uint64_t history_count; struct timeval history_time; + + // icarus-options + int baud; + int work_division; + int fpga_count; + uint32_t nonce_mask; }; +#define END_CONDITION 0x0000ffff + // One for each possible device static struct ICARUS_INFO **icarus_info; +// Looking for options in --icarus-timing and --icarus-options: +// +// Code increments this each time we start to look at a device +// However, this means that if other devices are checked by +// the Icarus code (e.g. BFL) they will count in the option offset +// +// This, however, is deterministic so that's OK +// +// If we were to increment after successfully finding an Icarus +// that would be random since an Icarus may fail and thus we'd +// not be able to predict the option order +// +// This also assumes that serial_detect() checks them sequentially +// and in the order specified on the command line +// +static int option_offset = -1; + struct device_api icarus_api; static void rev(unsigned char *s, size_t l) @@ -195,8 +220,8 @@ static void rev(unsigned char *s, size_t l) } } -#define icarus_open2(devpath, purge) serial_open(devpath, 115200, ICARUS_READ_FAULT_DECISECONDS, purge) -#define icarus_open(devpath) icarus_open2(devpath, false) +#define icarus_open2(devpath, baud, purge) serial_open(devpath, baud, ICARUS_READ_FAULT_DECISECONDS, purge) +#define icarus_open(devpath, baud) icarus_open2(devpath, baud, false) static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count) { @@ -272,7 +297,7 @@ static const char *timing_mode_str(enum timing_mode timing_mode) } } -static void set_timing_mode(struct cgpu_info *icarus) +static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus) { struct ICARUS_INFO *info = icarus_info[icarus->device_id]; double Hs; @@ -285,7 +310,7 @@ static void set_timing_mode(struct cgpu_info *icarus) buf[0] = '\0'; else { ptr = opt_icarus_timing; - for (i = 0; i < icarus->device_id; i++) { + for (i = 0; i < this_option_offset; i++) { comma = strchr(ptr, ','); if (comma == NULL) break; @@ -354,11 +379,122 @@ static void set_timing_mode(struct cgpu_info *icarus) applog(LOG_DEBUG, "Icarus: Init: %d mode=%s read_count=%d Hs=%e", icarus->device_id, timing_mode_str(info->timing_mode), info->read_count, info->Hs); +} + +static uint32_t mask(int work_division) +{ + char err_buf[BUFSIZ+1]; + uint32_t nonce_mask = 0x7fffffff; + + // yes we can calculate these, but this way it's easy to see what they are + switch (work_division) { + case 1: + nonce_mask = 0xffffffff; + break; + case 2: + nonce_mask = 0x7fffffff; + break; + case 4: + nonce_mask = 0x3fffffff; + break; + case 8: + nonce_mask = 0x1fffffff; + break; + default: + sprintf(err_buf, "Invalid2 icarus-options for work_division (%d) must be 1, 2, 4 or 8", work_division); + quit(1, err_buf); + } + + return nonce_mask; +} + +static void get_options(int this_option_offset, int *baud, int *work_division, int *fpga_count) +{ + char err_buf[BUFSIZ+1]; + char buf[BUFSIZ+1]; + char *ptr, *comma, *colon, *colon2; + size_t max; + int i, tmp; + + if (opt_icarus_options == NULL) + buf[0] = '\0'; + else { + ptr = opt_icarus_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 = ICARUS_IO_SPEED; + *work_division = 2; + *fpga_count = 2; + + if (*buf) { + colon = strchr(buf, ':'); + if (colon) + *(colon++) = '\0'; + + if (*buf) { + tmp = atoi(buf); + switch (tmp) { + case 115200: + *baud = 115200; + break; + case 57600: + *baud = 57600; + break; + default: + sprintf(err_buf, "Invalid icarus-options for baud (%s) must be 115200 or 57600", buf); + quit(1, err_buf); + } + } + + if (colon && *colon) { + colon2 = strchr(colon, ':'); + if (colon2) + *(colon2++) = '\0'; + + if (*colon) { + tmp = atoi(colon); + if (tmp == 1 || tmp == 2 || tmp == 4 || tmp == 8) + *work_division = tmp; + else { + sprintf(err_buf, "Invalid icarus-options for work_division (%s) must be 1, 2, 4 or 8", colon); + quit(1, err_buf); + } + } + + if (colon2 && *colon2) { + tmp = atoi(colon2); + if (tmp > 0 && tmp <= *work_division) + *fpga_count = tmp; + else { + sprintf(err_buf, "Invalid icarus-options for fpga_count (%s) must be >0 and <=work_division (%d)", colon2, *work_division); + quit(1, err_buf); + } + } + } + } } static bool icarus_detect_one(const char *devpath) { + int this_option_offset = ++option_offset; + struct ICARUS_INFO *info; struct timeval tv_start, tv_finish; int fd; @@ -379,9 +515,13 @@ static bool icarus_detect_one(const char *devpath) unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE]; char *nonce_hex; + int baud, work_division, fpga_count; + + get_options(this_option_offset, &baud, &work_division, &fpga_count); + applog(LOG_DEBUG, "Icarus Detect: Attempting to open %s", devpath); - fd = icarus_open2(devpath, true); + fd = icarus_open2(devpath, baud, true); if (unlikely(fd == -1)) { applog(LOG_ERR, "Icarus Detect: Failed to open %s", devpath); return false; @@ -429,6 +569,9 @@ static bool icarus_detect_one(const char *devpath) applog(LOG_INFO, "Found Icarus at %s, mark as %d", devpath, icarus->device_id); + applog(LOG_DEBUG, "Icarus: Init: %d baud=%d work_division=%d fpga_count=%d", + icarus->device_id, baud, work_division, fpga_count); + // Since we are adding a new device on the end it needs to always be allocated icarus_info[icarus->device_id] = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO)); if (unlikely(!(icarus_info[icarus->device_id]))) @@ -439,10 +582,15 @@ static bool icarus_detect_one(const char *devpath) // Initialise everything to zero for a new device memset(info, 0, sizeof(struct ICARUS_INFO)); - info->golden_hashes = (golden_nonce_val & 0x7fffffff) << 1; + info->baud = baud; + info->work_division = work_division; + info->fpga_count = fpga_count; + info->nonce_mask = mask(work_division); + + info->golden_hashes = (golden_nonce_val & info->nonce_mask) * fpga_count; timersub(&tv_finish, &tv_start, &(info->golden_tv)); - set_timing_mode(icarus); + set_timing_mode(this_option_offset, icarus); return true; } @@ -458,7 +606,7 @@ static bool icarus_prepare(struct thr_info *thr) struct timeval now; - int fd = icarus_open(icarus->device_path); + int fd = icarus_open(icarus->device_path, icarus_info[icarus->device_id]->baud); if (unlikely(-1 == fd)) { applog(LOG_ERR, "Failed to open Icarus on %s", icarus->device_path); @@ -565,11 +713,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, submit_nonce(thr, work, nonce); - hash_count = (nonce & 0x7fffffff); - if (hash_count++ == 0x7fffffff) - hash_count = 0xffffffff; - else - hash_count <<= 1; + hash_count = (nonce & info->nonce_mask); + hash_count++; + hash_count *= info->fpga_count; if (opt_debug || info->do_icarus_timing) timersub(&tv_finish, &tv_start, &elapsed); @@ -580,7 +726,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, } // ignore possible end condition values - if (info->do_icarus_timing && (nonce & 0x7fffffff) > 0x000fffff && (nonce & 0x7fffffff) < 0x7ff00000) { + if (info->do_icarus_timing + && ((nonce & info->nonce_mask) > END_CONDITION) + && ((nonce & info->nonce_mask) < (info->nonce_mask & ~END_CONDITION))) { gettimeofday(&tv_history_start, NULL); history0 = &(info->history[0]); @@ -590,7 +738,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, Ti = (double)(elapsed.tv_sec) + ((double)(elapsed.tv_usec))/((double)1000000) - - ICARUS_READ_TIME; + - ((double)ICARUS_READ_TIME(info->baud)); Xi = (double)hash_count; history0->sumXiTi += Xi * Ti; history0->sumXi += Xi; @@ -700,6 +848,9 @@ static struct api_data *icarus_api_stats(struct cgpu_info *cgpu) root = api_add_uint(root, "timing_values", &(info->history[0].values), false); root = api_add_const(root, "timing_mode", timing_mode_str(info->timing_mode), false); root = api_add_bool(root, "is_timing", &(info->do_icarus_timing), false); + root = api_add_int(root, "baud", &(info->baud), false); + root = api_add_int(root, "work_division", &(info->work_division), false); + root = api_add_int(root, "fpga_count", &(info->fpga_count), false); return root; } diff --git a/miner.h b/miner.h index 09cb503c..44d03421 100644 --- a/miner.h +++ b/miner.h @@ -557,6 +557,7 @@ extern bool opt_api_listen; extern bool opt_api_network; extern bool opt_delaynet; extern bool opt_restart; +extern char *opt_icarus_options; extern char *opt_icarus_timing; #ifdef USE_BITFORCE extern bool opt_bfl_noncerange;