From 619da85ee28dd0afb58ce86475ee61c0415eeae6 Mon Sep 17 00:00:00 2001 From: Johnson-Fan Date: Wed, 22 Feb 2017 18:48:55 +0800 Subject: [PATCH 001/113] Update the default fan speed percentage --- driver-avalon7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon7.c b/driver-avalon7.c index e65f4a271f..3f27d60e25 100644 --- a/driver-avalon7.c +++ b/driver-avalon7.c @@ -1451,7 +1451,7 @@ static void detect_modules(struct cgpu_info *avalon7) info->total_asics[i] = tmp; info->temp_overheat[i] = AVA7_DEFAULT_TEMP_OVERHEAT; info->temp_target[i] = opt_avalon7_temp_target; - info->fan_pct[i] = opt_avalon7_fan_min + (opt_avalon7_fan_min + opt_avalon7_fan_max) / 3; + info->fan_pct[i] = opt_avalon7_fan_min; for (j = 0; j < info->miner_count[i]; j++) { if (opt_avalon7_voltage == AVA7_INVALID_VOLTAGE) info->set_voltage[i][j] = avalon7_dev_table[dev_index].set_voltage; From 19b6d29400f05b8652dd34f465837e30dbed9aa4 Mon Sep 17 00:00:00 2001 From: Mikeqin Date: Tue, 8 Nov 2016 18:02:04 +0800 Subject: [PATCH 002/113] Add SSP support for Avalon7 --- Makefile.am | 4 + cgminer.c | 48 ++++ configure.ac | 1 + driver-avalon7.c | 126 ++++++++- driver-avalon7.h | 10 + libssplus.c | 646 +++++++++++++++++++++++++++++++++++++++++++++++ libssplus.h | 27 ++ miner.h | 1 + util.c | 12 +- 9 files changed, 867 insertions(+), 8 deletions(-) create mode 100644 libssplus.c create mode 100644 libssplus.h diff --git a/Makefile.am b/Makefile.am index f9d21d4cbc..88b9ef6d40 100644 --- a/Makefile.am +++ b/Makefile.am @@ -169,6 +169,10 @@ if NEED_I2C_CONTEXT cgminer_SOURCES += i2c-context.c endif +if SUPPORT_SSP +cgminer_SOURCES += libssplus.c +endif + if HAS_AVALON_MINER cgminer_SOURCES += driver-avalon-miner.c driver-avalon-miner.h endif diff --git a/cgminer.c b/cgminer.c index 8026a34e26..50c8b571cc 100644 --- a/cgminer.c +++ b/cgminer.c @@ -84,6 +84,7 @@ char *curly = ":D"; #ifdef USE_AVALON7 #include "driver-avalon7.h" +#include "libssplus.h" #endif #ifdef USE_AVALON_MINER @@ -1472,6 +1473,9 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--no-avalon7-asic-debug", opt_set_invbool, &opt_avalon7_asic_debug, "Disable A3212 debug."), + OPT_WITHOUT_ARG("--avalon7-ssplus-enable", + opt_set_bool, &opt_avalon7_ssplus_enable, + "Enable avalon7 smart speed plus."), #endif #ifdef USE_AVALON_MINER OPT_WITH_CBARG("--avalonm-voltage", @@ -7298,6 +7302,43 @@ bool submit_nonce2_nonce(struct thr_info *thr, struct pool *pool, struct pool *r free_work(work); return ret; } + +uint32_t gen_merkle_root(struct pool *pool, uint64_t nonce2) +{ + unsigned char merkle_root[32], merkle_sha[64]; + uint32_t *data32, *swap32, tail; + uint64_t nonce2le; + int i; + + /* Update coinbase. Always use an LE encoded nonce2 to fill in values + * from left to right and prevent overflow errors with small n2sizes */ + nonce2le = htole64(nonce2); + cg_memcpy(pool->coinbase + pool->nonce2_offset, &nonce2le, pool->n2size); + + /* Generate merkle root */ + gen_hash(pool->coinbase, merkle_root, pool->coinbase_len); + cg_memcpy(merkle_sha, merkle_root, 32); + for (i = 0; i < pool->merkles; i++) { + cg_memcpy(merkle_sha + 32, pool->swork.merkle_bin[i], 32); + gen_hash(merkle_sha, merkle_root, 64); + cg_memcpy(merkle_sha, merkle_root, 32); + } + data32 = (uint32_t *)merkle_sha; + swap32 = (uint32_t *)merkle_root; + flip32(swap32, data32); + + { + char *merkle_hash; + + merkle_hash = bin2hex((const unsigned char *)merkle_root, 32); + applog(LOG_DEBUG, "[M-N2]: %s-%08x-%08x", merkle_hash, (uint32_t)nonce2le, (uint32_t)nonce2); + free(merkle_hash); + } + + cg_memcpy(&tail, merkle_root + 28, 4); + + return tail; +} #endif /* Generates stratum based work based on the most recent notify information @@ -9973,6 +10014,12 @@ int main(int argc, char *argv[]) gwsched_thr_id = 0; +#ifdef USE_AVALON7 + if (opt_avalon7_ssplus_enable) { + ssp_sorter_init(HT_SIZE, HT_PRB_LMT, HT_PRB_C1, HT_PRB_C2); + ssp_hasher_init(); + } +#endif #ifdef USE_USBUTILS usb_initialise(); @@ -10222,6 +10269,7 @@ int main(int argc, char *argv[]) if (opt_work_update) signal_work_update(); + opt_work_update = false; mutex_lock(stgd_lock); diff --git a/configure.ac b/configure.ac index 51dc23c110..9010d9d347 100644 --- a/configure.ac +++ b/configure.ac @@ -532,6 +532,7 @@ AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue]) AM_CONDITIONAL([HAVE_x86_64], [test x$have_x86_64 = xtrue]) AM_CONDITIONAL([WANT_CRC16], [test x$want_crc16 != xfalse]) AM_CONDITIONAL([NEED_I2C_CONTEXT], [test x$avalon4$avalon7 != xnono]) +AM_CONDITIONAL([SUPPORT_SSP], [test x$avalon7 != xno]) if test "x$want_usbutils" != xfalse; then AC_DEFINE([USE_USBUTILS], [1], [Defined to 1 if usbutils support required]) diff --git a/driver-avalon7.c b/driver-avalon7.c index 3f27d60e25..1c0cd8f6a0 100644 --- a/driver-avalon7.c +++ b/driver-avalon7.c @@ -14,6 +14,7 @@ #include "driver-avalon7.h" #include "crc.h" #include "sha2.h" +#include "libssplus.h" #include "hexdump.c" #define get_fan_pwm(v) (AVA7_PWM_MAX - (v) * AVA7_PWM_MAX / 100) @@ -55,6 +56,7 @@ uint32_t opt_avalon7_th_ms = AVA7_DEFAULT_TH_MS; uint32_t opt_avalon7_th_timeout = AVA7_DEFAULT_TH_TIMEOUT; uint32_t opt_avalon7_nonce_mask = AVA7_DEFAULT_NONCE_MASK; bool opt_avalon7_asic_debug = true; +bool opt_avalon7_ssplus_enable = false; uint32_t cpm_table[] = { @@ -591,10 +593,10 @@ static int decode_pkg(struct cgpu_info *avalon7, struct avalon7_ret *ar, int mod if (ntime > info->max_ntime) info->max_ntime = ntime; - applog(LOG_DEBUG, "%s-%d-%d: Found! P:%d - N2:%08x N:%08x NR:%d/%d [M:%d - MW: (%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64")]", + applog(LOG_NOTICE, "%s-%d-%d: Found! P:%d - N2:%08x N:%08x NR:%d/%d [M:%d, A:%d, C:%d - MW: (%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64")]", avalon7->drv->name, avalon7->device_id, modular_id, pool_no, nonce2, nonce, ntime, info->max_ntime, - miner, + miner, chip_id, nonce & 0x7f, info->chip_matching_work[modular_id][miner][0], info->chip_matching_work[modular_id][miner][1], info->chip_matching_work[modular_id][miner][2], @@ -667,6 +669,9 @@ static int decode_pkg(struct cgpu_info *avalon7, struct avalon7_ret *ar, int mod memcpy(&tmp, ar->data + 24, 4); info->error_crc[modular_id][ar->idx] += be32toh(tmp); + memcpy(&tmp, ar->data + 28, 4); + info->mm_got_pairs[modular_id] += be32toh(tmp) >> 16; + info->mm_got_invalid_pairs[modular_id] += be32toh(tmp) & 0xffff; break; case AVA7_P_STATUS_PMU: /* TODO: decode ntc led from PMU */ @@ -1334,6 +1339,93 @@ static inline void avalon7_detect(bool __maybe_unused hotplug) avalon7_iic_detect(); } +#ifdef PAIR_CHECK +static void copy_pool_stratum(struct pool *pool_stratum, struct pool *pool); +#endif +static void *avalon7_ssp_fill_pairs(void *userdata) +{ + char threadname[16]; + + struct cgpu_info *avalon7 = userdata; + struct avalon7_info *info = avalon7->device_data; + struct avalon7_pkg send_pkg; + ssp_pair pair; + uint8_t pair_counts; + int i, err, fill_timeout;; + uint32_t tmp; +#ifdef PAIR_CHECK + struct pool pool_mirror, *pool; + uint32_t tail[2]; + uint64_t pass, fail; +#endif + + snprintf(threadname, sizeof(threadname), "%d/Av7ssp", avalon7->device_id); + RenameThread(threadname); + + /* timeout in ms = count of points * 4 * ntime_offset / max_ghs(10T) * 1000 */ + fill_timeout = 80 * 4 * AVA7_DEFAULT_NTIME_OFFSET * 1.0 / 10000 * 1000; + + cgsleep_ms(3000); + while (likely(!avalon7->shutdown)) { +#ifdef PAIR_CHECK + if (ssp_sorter_get_pair(pair)) { + pool = current_pool(); + copy_pool_stratum(&pool_mirror, pool); + tail[0] = gen_merkle_root(&pool_mirror, pair[0]); + tail[1] = gen_merkle_root(&pool_mirror, pair[1]); + if (tail[0] != tail[1]) { + fail++; + applog(LOG_NOTICE, "avalon7_ssp_fill_pairs: tail mismatch (%08x:%08x -> %08x:%08x)", + tail[0], + tail[1], + pair[0], + pair[1]); + applog(LOG_NOTICE, "avalon7_ssp_fill_pairs: tail mismatch detail %08x-%08x, F: %"PRIu64", P: %"PRIu64", Errate: %0.2f", tail[0], tail[1], fail, pass, fail * 1.0 / (pass + fail)); + } else { + applog(LOG_NOTICE, "avalon7_ssp_fill_pairs: tail pass (%08x -> %08x:%08x)", + tail[0], + pair[0], + pair[1]); + pass++; + } + } + cgsleep_ms(opt_avalon7_polling_delay); +#else + for (i = 1; i < AVA7_DEFAULT_MODULARS; i++) { + if (!info->enable[i]) + continue; + + pair_counts = 0; + memset(send_pkg.data, 0, AVA7_P_DATA_LEN); + while (pair_counts < 1) { + if (!ssp_sorter_get_pair(pair)) { + applog(LOG_DEBUG, "%s-%d: Waiting for pairs from ssp_sorter_get_pair", + avalon7->drv->name, avalon7->device_id); + continue; + } + tmp = be32toh(pair[0]); + memcpy(send_pkg.data + pair_counts * 8, &tmp, 4); + tmp = be32toh(pair[1]); + applog(LOG_DEBUG, "send pair %08x-%08x", pair[0], pair[1]); + memcpy(send_pkg.data + pair_counts * 8 + 4, &tmp, 4); + pair_counts++; + info->gen_pairs[i]++; + } + + avalon7_init_pkg(&send_pkg, AVA7_P_PAIRS, 1, 1); + err = avalon7_iic_xfer_pkg(avalon7, i, &send_pkg, NULL); + if (err != AVA7_SEND_OK) { + applog(LOG_NOTICE, "%s-%d: send pair failed %d", + avalon7->drv->name, avalon7->device_id, err); + } + } + cgsleep_ms(fill_timeout); +#endif + } + + return NULL; +} + static bool avalon7_prepare(struct thr_info *thr) { struct cgpu_info *avalon7 = thr->cgpu; @@ -1356,6 +1448,13 @@ static bool avalon7_prepare(struct thr_info *thr) cglock_init(&info->pool1.data_lock); cglock_init(&info->pool2.data_lock); + if (opt_avalon7_ssplus_enable) { + if (pthread_create(&(info->ssp_thr), NULL, avalon7_ssp_fill_pairs, (void *)avalon7)) { + applog(LOG_ERR, "%s-%d: create ssp thread failed", avalon7->drv->name, avalon7->device_id); + return false; + } + } + return true; } @@ -1488,6 +1587,9 @@ static void detect_modules(struct cgpu_info *avalon7) info->power_good[i] = 0; memset(info->pmu_version[i], 0, sizeof(char) * 5 * AVA7_DEFAULT_PMU_CNT); info->diff1[i] = 0; + info->mm_got_pairs[i] = 0; + info->mm_got_invalid_pairs[i] = 0; + info->gen_pairs[i] = 0; applog(LOG_NOTICE, "%s-%d: New module detected! ID[%d-%x]", avalon7->drv->name, avalon7->device_id, i, info->mm_dna[i][AVA7_MM_DNA_LEN - 1]); @@ -1643,17 +1745,22 @@ static void avalon7_init_setting(struct cgpu_info *avalon7, int addr) memset(send_pkg.data, 0, AVA7_P_DATA_LEN); - /* TODO:ss/ssp mode */ - tmp = be32toh(opt_avalon7_freq_sel); memcpy(send_pkg.data + 4, &tmp, 4); - /* adjust flag [0-5]: reserved, 6: nonce check, 7: autof*/ + /* + * set flags: + * 0: ss switch + * 1: nonce check + * 2: asic debug + * 3: ssp switch + */ tmp = 1; if (!opt_avalon7_smart_speed) tmp = 0; tmp |= (1 << 1); /* Enable nonce check */ tmp |= (opt_avalon7_asic_debug << 2); + tmp |= (opt_avalon7_ssplus_enable << 3); send_pkg.data[8] = tmp & 0xff; send_pkg.data[9] = opt_avalon7_nonce_mask & 0xff; @@ -1713,11 +1820,11 @@ static void avalon7_set_freq(struct cgpu_info *avalon7, int addr, int miner_id, for (i = 1; i < AVA7_DEFAULT_PLL_CNT; i++) f = f > freq[i] ? f : freq[i]; - tmp = ((AVA7_ASIC_TIMEOUT_CONST / f) * 40 / 4); + tmp = ((AVA7_ASIC_TIMEOUT_CONST / f) * AVA7_DEFAULT_NTIME_OFFSET / 4) * (opt_avalon7_ssplus_enable ? 2 : 1); tmp = be32toh(tmp); memcpy(send_pkg.data + AVA7_DEFAULT_PLL_CNT * 4, &tmp, 4); - tmp = AVA7_ASIC_TIMEOUT_CONST / f * 98 / 100; + tmp = AVA7_ASIC_TIMEOUT_CONST / f * 98 / 100 * (opt_avalon7_ssplus_enable ? 2 : 1); tmp = be32toh(tmp); memcpy(send_pkg.data + AVA7_DEFAULT_PLL_CNT * 4 + 4, &tmp, 4); applog(LOG_DEBUG, "%s-%d-%d: avalon7 set freq miner %x-%x", @@ -2223,6 +2330,11 @@ static struct api_data *avalon7_api_stats(struct cgpu_info *avalon7) } statbuf[strlen(statbuf) - 1] = ']'; + strcat(statbuf, " PAIRS["); + sprintf(buf, "%"PRIu64" %"PRIu64" %"PRIu64" ", info->mm_got_pairs[i], info->mm_got_invalid_pairs[i], info->gen_pairs[i]); + strcat(statbuf, buf); + statbuf[strlen(statbuf) - 1] = ']'; + strcat(statbuf, " PVT_T["); for (j = 0; j < info->miner_count[i]; j++) { sprintf(buf, "%d-%d/%d-%d/%d ", diff --git a/driver-avalon7.h b/driver-avalon7.h index 49066a6630..83888d16a5 100644 --- a/driver-avalon7.h +++ b/driver-avalon7.h @@ -55,6 +55,7 @@ #define AVA7_DEFAULT_PMU_CNT 2 #define AVA7_DEFAULT_POLLING_DELAY 20 /* ms */ +#define AVA7_DEFAULT_NTIME_OFFSET 40 #define AVA7_DEFAULT_SMARTSPEED_OFF 0 #define AVA7_DEFAULT_SMARTSPEED_MODE1 1 @@ -118,6 +119,7 @@ #define AVA7_P_SET_PMU 0x24 #define AVA7_P_SET_PLL 0x25 #define AVA7_P_SET_SS 0x26 +#define AVA7_P_PAIRS 0x27 /* Have to send with I2C address */ #define AVA7_P_POLLING 0x30 @@ -264,6 +266,13 @@ struct avalon7_info { uint16_t vout_adc_ratio[AVA7_DEFAULT_MODULARS]; bool conn_overloaded; + + uint64_t mm_got_pairs[AVA7_DEFAULT_MODULARS]; + uint64_t mm_got_invalid_pairs[AVA7_DEFAULT_MODULARS]; + uint64_t gen_pairs[AVA7_DEFAULT_MODULARS]; + + /* SSP */ + pthread_t ssp_thr; }; struct avalon7_iic_info { @@ -308,5 +317,6 @@ extern uint32_t opt_avalon7_th_ms; extern uint32_t opt_avalon7_th_timeout; extern uint32_t opt_avalon7_nonce_mask; extern bool opt_avalon7_asic_debug; +extern bool opt_avalon7_ssplus_enable; #endif /* USE_AVALON7 */ #endif /* _AVALON7_H_ */ diff --git a/libssplus.c b/libssplus.c new file mode 100644 index 0000000000..6f054ed1b1 --- /dev/null +++ b/libssplus.c @@ -0,0 +1,646 @@ +/* + * Copyright 2016 Mikeqin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. See COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sha2.h" + +#include "libssplus.h" + +#define INSTRUCTIONS_RAM_START 0x42000000 +#define INSTRUCTIONS_RAM_SIZE (1 << 16) +#define POINTS_RAM_START 0xfffc0000 +#define POINTS_RAM_SIZE (256 << 10) + +/* hasher instructions */ +#define INST_DONE 0x00040000 +#define INST_DATA_IRAM 0x0 +#define INST_DATA_LASTHASH_PAD 0x14000000 +#define INST_DATA_LASTHASH_IRAM 0x10000000 +#define INST_DATA_PAD512 0x26000000 +#define INST_MID_INIT 0x0 +#define INST_MID_LASTHASH 0x100000 + +#define NEXT_ADDR(x) (((x) & 0x1ff) << 8) + +#define UNPACK32(x, str) \ +{ \ + *((str) + 3) = (uint8_t) ((x) ); \ + *((str) + 2) = (uint8_t) ((x) >> 8); \ + *((str) + 1) = (uint8_t) ((x) >> 16); \ + *((str) + 0) = (uint8_t) ((x) >> 24); \ +} + +#define SORTER_DEBUG + +struct ssp_hasher_instruction { + uint32_t opcode; + uint8_t data[64]; +}; + +struct ssp_point { + uint32_t nonce2; + uint32_t tail; +}; + +struct ssp_info { + pthread_t hasher_thr; + pthread_mutex_t hasher_lock; + volatile uint32_t *iram_addr; + volatile uint64_t *pram_addr; + bool stratum_update; + bool run; +}; + +struct ssp_pair_element { + uint32_t nonce2[2]; + struct ssp_pair_element *next; +}; + +struct ssp_hashtable { + struct ssp_point *cells; + uint32_t size; + uint32_t max_size; /* must be powers of 2 */ + uint32_t limit; /* probing limit */ + uint32_t c1; + uint32_t c2; +}; + +static struct ssp_info sspinfo; +static struct ssp_hashtable *ssp_ht = NULL; +static struct ssp_pair_element *ssp_pair_head = NULL; +static struct ssp_pair_element *ssp_pair_tail = NULL; + +#ifdef SORTER_DEBUG +static uint32_t pair_count = 0; +static uint32_t consumed = 0; +static uint32_t discarded = 0; +static uint32_t calls = 0; +static struct timeval ssp_ti, ssp_tf; +static double insert_time = .0; + +static uint32_t maxnonce = 0; +static uint32_t ver = 0; +#endif + +static void ssp_sorter_insert(const struct ssp_point *point) +{ + uint32_t i; + uint32_t key; + +#ifdef SORTER_DEBUG + if (calls == 0xffffffff) + applog(LOG_NOTICE, "calls overflow"); + calls++; +#endif + + for (i = 0; i < ssp_ht->limit; i++) { + key = (point->tail + ssp_ht->c1 * i + ssp_ht->c2 * i * i) % + (ssp_ht->max_size); + if (ssp_ht->cells[key].nonce2 == 0 && ssp_ht->cells[key].tail == 0) { + /* insert */ + ssp_ht->cells[key].tail = point->tail; + ssp_ht->cells[key].nonce2 = point->nonce2; + ssp_ht->size++; + goto out; + } + if (ssp_ht->cells[key].tail == point->tail) { + /* get a collision */ + ssp_pair_tail->nonce2[0] = point->nonce2; + ssp_pair_tail->nonce2[1] = ssp_ht->cells[key].nonce2; + ssp_pair_tail->next = (struct ssp_pair_element *)cgmalloc(sizeof(struct ssp_pair_element)); + ssp_pair_tail = ssp_pair_tail->next; +#ifdef SORTER_DEBUG + pair_count++; +#endif + + /* update nonce2 of the point */ + ssp_ht->cells[key].nonce2 = 0; + ssp_ht->cells[key].tail = 0; + /* or just delete it? */ + /* or leave it be? */ + goto out; + } + } + + /* discard */ +#ifdef SORTER_DEBUG + discarded++; +#endif +out: + return; +} + +void ssp_sorter_init(uint32_t max_size, uint32_t limit, uint32_t c1, uint32_t c2) +{ +#ifdef SORTER_DEBUG + cgtime(&ssp_ti); +#endif + + ssp_ht = (struct ssp_hashtable *)cgmalloc(sizeof(struct ssp_hashtable)); + + ssp_ht->max_size = max_size; + ssp_ht->limit = limit; + ssp_ht->c1 = c1; + ssp_ht->c2 = c2; + ssp_ht->size = 0; + ssp_ht->cells = (struct ssp_point *)cgmalloc(sizeof(struct ssp_point) * max_size); + memset(ssp_ht->cells, 0, sizeof(struct ssp_point) * max_size); + + ssp_pair_head = (struct ssp_pair_element *)cgmalloc(sizeof(struct ssp_pair_element)); + ssp_pair_tail = ssp_pair_head; +} + +void ssp_sorter_flush(void) +{ +#ifdef SORTER_DEBUG + double delta_t; + + cgtime(&ssp_tf); + delta_t = tdiff(&ssp_tf, &ssp_ti); + + applog(LOG_NOTICE, "Stratum %d: %f s", ver, delta_t); + applog(LOG_NOTICE, "Stratum %d: get %d pairs. %f pair/s", ver, pair_count, pair_count / delta_t); + applog(LOG_NOTICE, "Stratum %d: consume %d pairs. %f pair/s", ver, consumed, consumed / delta_t); + applog(LOG_NOTICE, "Stratum %d: discard %d points. %f point/s", ver, discarded, discarded / delta_t); + applog(LOG_NOTICE, "Stratum %d: reading discards %d points. %f point/s. %.2f%%", ver, maxnonce - calls, (maxnonce - calls) / delta_t, (maxnonce - calls) * 1.0 / maxnonce * 100); + applog(LOG_NOTICE, "Stratum %d: record %d points. %f%% of hashtable. %f point/s", ver, ssp_ht->size, ssp_ht->size * 100.0 / ssp_ht->max_size, ssp_ht->size / delta_t); + applog(LOG_NOTICE, "Stratum %d: %d calls of sorter_insert. %f call/s", ver, calls, calls / delta_t); + applog(LOG_NOTICE, "Stratum %d: avg call time - %f us", ver, delta_t * 1000000 / calls); + applog(LOG_NOTICE, "Stratum %d: k^2 / 2N / pair - %f", ver, 0.5 * calls * calls / 4294967296 / pair_count); + applog(LOG_NOTICE, "========================================================"); + + cgtime(&ssp_ti); + pair_count = 0; + consumed = 0; + discarded = 0; + calls = 0; + insert_time = 0; + ver++; +#endif + + ssp_ht->size = 0; + memset(ssp_ht->cells, 0, sizeof(struct ssp_point) * ssp_ht->max_size); + + /* MM only use one stratum, we need drop all pairs */ + while (ssp_pair_head != ssp_pair_tail) { + struct ssp_pair_element *tmp; + + tmp = ssp_pair_head; + ssp_pair_head = tmp->next; + free(tmp); + } +} + +int ssp_sorter_get_pair(ssp_pair pair) +{ + struct ssp_pair_element *tmp; + + mutex_lock(&(sspinfo.hasher_lock)); + + if (ssp_pair_head == ssp_pair_tail) { + mutex_unlock(&(sspinfo.hasher_lock)); + return 0; + } + + tmp = ssp_pair_head; + pair[0] = tmp->nonce2[0]; + pair[1] = tmp->nonce2[1]; + + ssp_pair_head = tmp->next; + free(tmp); +#ifdef SORTER_DEBUG + consumed++; +#endif + mutex_unlock(&(sspinfo.hasher_lock)); + return 1; +} + +static void *ssp_hasher_thread(void *userdata) +{ + uint32_t last_nonce2 = 0, point_index = 0, nonce2; + bool valid_nonce2 = false; + struct ssp_info *p_ssp_info = (struct ssp_info *)userdata; + + while (1) { + mutex_lock(&(sspinfo.hasher_lock)); + + if (!p_ssp_info->run) + valid_nonce2 = false; + + if (p_ssp_info->stratum_update) { + p_ssp_info->stratum_update = false; + point_index = 0; + last_nonce2 = 0; + valid_nonce2 = false; + ssp_sorter_flush(); + applog(LOG_NOTICE, "libssplus: stratum update"); + } + + /* Note: hasher is fast enough, so the new job will start with a lower nonce2 */ + nonce2 = (sspinfo.pram_addr[point_index] & 0xffffffff); + if (last_nonce2 > nonce2) + valid_nonce2 = true; + + point_index = (point_index + 1) % (POINTS_RAM_SIZE / sizeof(struct ssp_point)); + if (valid_nonce2) { +#ifdef SORTER_DEBUG + if (nonce2 > maxnonce) + maxnonce = nonce2; +#endif + ssp_sorter_insert((struct ssp_point *)&sspinfo.pram_addr[point_index]); + } + last_nonce2 = nonce2; + + mutex_unlock(&(sspinfo.hasher_lock)); + } + return NULL; +} + +static inline void ssp_hasher_fill_iram(struct ssp_hasher_instruction *p_inst, uint32_t inst_index) +{ + uint8_t i; + volatile uint32_t *p_iram_addr; + uint32_t tmp; + + p_iram_addr = sspinfo.iram_addr + inst_index * 32; + p_iram_addr[0] = p_inst->opcode; + simplelog(LOG_DEBUG, "iram[%d*32+0] = 0x%08x;", inst_index, p_inst->opcode); + + for (i = 0; i < 16; i++) { + tmp = ((p_inst->data[i * 4 + 0] << 24) | + (p_inst->data[i * 4 + 1] << 16) | + (p_inst->data[i * 4 + 2] << 8) | + (p_inst->data[i * 4 + 3])); + p_iram_addr[i + 1] = tmp; + simplelog(LOG_DEBUG, "iram[%d*32+%d] = 0x%08x;", inst_index, i + 1, tmp); + } + p_iram_addr[i + 1] = 0x1; /* flush */ + simplelog(LOG_DEBUG, "iram[%d*32+%d] = 1;", inst_index, i + 1); +} + +static inline void ssp_hasher_stop(void) +{ + sspinfo.iram_addr[31] = 1; + sspinfo.run = false; +} + +static inline void ssp_hasher_start(void) +{ + sspinfo.iram_addr[31] = 0; + sspinfo.run = true; +} + +int ssp_hasher_init(void) +{ + int memfd; + + memfd = open("/dev/mem", O_RDWR | O_SYNC); + if (memfd < 0) { + applog(LOG_ERR, "libssplus: failed open /dev/mem"); + return 1; + } + + sspinfo.iram_addr = (volatile uint32_t *)mmap(NULL, INSTRUCTIONS_RAM_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, memfd, + INSTRUCTIONS_RAM_START); + if (sspinfo.iram_addr == MAP_FAILED) { + close(memfd); + applog(LOG_ERR, "libssplus: mmap instructions ram failed"); + return 1; + } + + sspinfo.pram_addr = (volatile uint64_t *)mmap(NULL, POINTS_RAM_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, memfd, + POINTS_RAM_START); + if (sspinfo.pram_addr == MAP_FAILED) { + close(memfd); + applog(LOG_ERR, "libssplus: mmap points ram failed"); + return 1; + } + close(memfd); + + if (pthread_create(&(sspinfo.hasher_thr), NULL, ssp_hasher_thread, &sspinfo)) { + applog(LOG_ERR, "libssplus: create thread failed"); + return 1; + } + + sspinfo.stratum_update = false; + ssp_hasher_stop(); + mutex_init(&sspinfo.hasher_lock); + + return 0; +} + +static inline void sha256_prehash(const unsigned char *message, unsigned int len, unsigned char *digest) +{ + int i; + sha256_ctx ctx; + + sha256_init(&ctx); + sha256_update(&ctx, message, len); + + for (i = 0; i < 8; i++) + UNPACK32(ctx.h[i], &digest[i << 2]); +} + +void ssp_hasher_update_stratum(struct pool *pool, bool clean) +{ + struct ssp_hasher_instruction inst; + uint32_t coinbase_len_posthash, coinbase_len_prehash; + uint32_t i, len_rem, block_nb; + int merkle_index; + uint32_t inst_index = 0, nonce2_init = 0; + uint64_t coinbase_len_bits = pool->coinbase_len * 8; + + mutex_lock(&(sspinfo.hasher_lock)); + + ssp_hasher_stop(); + /* instruction init */ + inst.opcode = 0; + memset(inst.data, 0, SHA256_BLOCK_SIZE); + inst.data[28] = (nonce2_init >> 24) & 0xff; + inst.data[29] = (nonce2_init >> 16) & 0xff; + inst.data[30] = (nonce2_init >> 8) & 0xff; + inst.data[31] = (nonce2_init) & 0xff; + + coinbase_len_prehash = pool->nonce2_offset - (pool->nonce2_offset % SHA256_BLOCK_SIZE); + sha256_prehash(pool->coinbase, coinbase_len_prehash, inst.data + 32); + ssp_hasher_fill_iram(&inst, inst_index); + inst_index++; + + /* coinbase */ + coinbase_len_posthash = pool->coinbase_len - coinbase_len_prehash; + block_nb = coinbase_len_posthash / SHA256_BLOCK_SIZE; + len_rem = (coinbase_len_posthash % SHA256_BLOCK_SIZE); + for (i = 0; i < block_nb; i++) { + inst.opcode = INST_DATA_IRAM | NEXT_ADDR(inst_index + 1); + if (!i) { + inst.opcode |= (63 - (pool->nonce2_offset % SHA256_BLOCK_SIZE)); + inst.opcode |= INST_MID_INIT; + } else + inst.opcode |= INST_MID_LASTHASH; + memcpy(inst.data, pool->coinbase + coinbase_len_prehash + i * SHA256_BLOCK_SIZE, SHA256_BLOCK_SIZE); + ssp_hasher_fill_iram(&inst, inst_index); + inst_index++; + } + + memset(inst.data, 0, SHA256_BLOCK_SIZE); + inst.opcode = INST_DATA_IRAM | NEXT_ADDR(inst_index + 1); + if (!block_nb) { + inst.opcode |= (63 - (pool->nonce2_offset % SHA256_BLOCK_SIZE)); + inst.opcode |= INST_MID_INIT; + } else + inst.opcode |= INST_MID_LASTHASH; + memcpy(inst.data, pool->coinbase + coinbase_len_prehash + (block_nb * SHA256_BLOCK_SIZE), len_rem); + inst.data[len_rem] = 0x80; + + if (len_rem <= (SHA256_BLOCK_SIZE - 9)) { + for (i = 0; i < 8; i++) + inst.data[63 - i] = (coinbase_len_bits >> (i * 8)) & 0xff; + ssp_hasher_fill_iram(&inst, inst_index); + inst_index++; + } else { + ssp_hasher_fill_iram(&inst, inst_index); + inst_index++; + + memset(inst.data, 0, SHA256_BLOCK_SIZE); + inst.opcode = INST_DATA_IRAM | NEXT_ADDR(inst_index + 1); + inst.opcode |= INST_MID_LASTHASH; + for (i = 0; i < 8; i++) + inst.data[63 - i] = (coinbase_len_bits >> (i * 8)) & 0xff; + ssp_hasher_fill_iram(&inst, inst_index); + inst_index++; + } + + /* double hash coinbase */ + inst.opcode = INST_DATA_LASTHASH_PAD | INST_MID_INIT | NEXT_ADDR(inst_index + 1); + memset(inst.data, 0, SHA256_BLOCK_SIZE); + ssp_hasher_fill_iram(&inst, inst_index); + inst_index++; + + /* merkle branches */ + for (merkle_index = 0; merkle_index < pool->merkles; merkle_index++) { + inst.opcode = INST_DATA_LASTHASH_IRAM | INST_MID_INIT | NEXT_ADDR(inst_index + 1); + memcpy(inst.data + 32, pool->swork.merkle_bin[merkle_index], 32); + ssp_hasher_fill_iram(&inst, inst_index); + inst_index++; + + inst.opcode = INST_DATA_PAD512 | INST_MID_LASTHASH | NEXT_ADDR(inst_index + 1); + memset(inst.data, 0, SHA256_BLOCK_SIZE); + ssp_hasher_fill_iram(&inst, inst_index); + inst_index++; + + inst.opcode = INST_DATA_LASTHASH_PAD | INST_MID_INIT | NEXT_ADDR(inst_index + 1); + memset(inst.data, 0, SHA256_BLOCK_SIZE); + ssp_hasher_fill_iram(&inst, inst_index); + inst_index++; + } + + /* done */ + inst.opcode = INST_DONE; + ssp_hasher_fill_iram(&inst, inst_index); + + sspinfo.stratum_update = true; + ssp_hasher_start(); + mutex_unlock(&(sspinfo.hasher_lock)); +} + +struct testcase { + unsigned char *coinbase; + unsigned char (*merkle_branches)[32]; + unsigned int coinbase_len; + unsigned int merkles; + unsigned int n2size; + unsigned int nonce2_offset; +}; + +#define TESTCASE_COUNT 3 +void ssp_hasher_test(void) +{ + struct pool test_pool[2]; + struct timeval t_start, t_find_pair; + ssp_pair pair; + uint32_t tail[2]; + uint32_t pair_count = 0; + int i, pool_index; + double pair_diff; + struct testcase tc[TESTCASE_COUNT]; + unsigned int tci = 0; + bool stratum_update = true; + bool hasher_update = true; + + /* nonce2 4 bytes without block_nb */ + unsigned char coinbase[] = { + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x64,0x03,0x85,0xc3,0x06,0x37,0xe4,0xb8,0x83,0xe5,0xbd,0xa9,0xe7,0xa5,0x9e,0xe4,0xbb,0x99,0xe9,0xb1,0xbc,0x17,0x60, + 0xcb,0x03,0x29,0xf4,0xa7,0x98,0x99,0xde,0x10,0x87,0xd1,0x01,0xc6,0x1e,0x7a,0x1f,0x0f,0x25,0xc0,0xec,0xc4,0x74,0x65,0x8c,0x69,0x7c,0x78,0x79,0xa4,0x7a,0x02,0x00, + 0x00,0x00,0xf0,0x9f,0x90,0x9f,0x14,0x4d,0x69,0x6e,0x65,0x64,0x20,0x62,0x79,0x20,0x71,0x69,0x6e,0x66,0x65,0x6e,0x67,0x6c,0x69,0x6e,0x67,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x5d,0xcc,0xe0,0x4b,0x00,0x00,0x00,0x00,0x19,0x76,0xa9,0x14,0xc8, + 0x25,0xa1,0xec,0xf2,0xa6,0x83,0x0c,0x44,0x01,0x62,0x0c,0x3a,0x16,0xf1,0x99,0x50,0x57,0xc2,0xab,0x88,0xac,0xa0,0x60,0x82,0x2f + }; + + unsigned char merkle_branches[][32] = { + {0x0d,0x44,0xd1,0xab,0xc4,0x1e,0x2f,0xed,0x72,0xa7,0x46,0xc9,0x68,0x31,0xbd,0x98,0x60,0xe5,0x32,0x6c,0x96,0xf0,0xe8,0x97,0x72,0xf4,0x59,0x0e,0x0c,0x36,0xd9,0x7c}, + {0x10,0x24,0x76,0x6d,0xde,0x67,0xdf,0x66,0x54,0xa8,0xac,0x19,0x8d,0x9d,0xf2,0x45,0xea,0x74,0x60,0x2d,0x0d,0xb7,0xa6,0x34,0x5e,0x2d,0x51,0xe2,0x8a,0x8e,0xb1,0xf6}, + {0x2c,0x03,0x81,0x54,0xf9,0xfc,0xa7,0x7d,0xc8,0x09,0xcf,0xb4,0xc2,0x12,0x11,0xbe,0xbb,0x57,0x8d,0x4f,0x80,0x1f,0x78,0xce,0x5c,0x58,0x10,0xdb,0x03,0xb8,0x33,0xaa}, + {0x61,0xce,0xe4,0xd0,0xb9,0x85,0xf7,0xea,0xb2,0x57,0x39,0x16,0x24,0xb1,0x3d,0xf0,0xd0,0x09,0x65,0x75,0xb2,0xf5,0x95,0x63,0x4b,0x38,0xd8,0xcf,0x8a,0x36,0xe5,0xe9}, + {0x09,0xb4,0x42,0x7c,0xf6,0x18,0xa4,0xe4,0x18,0xd3,0xd1,0xa1,0xe0,0x47,0x7b,0x39,0x6f,0x7c,0x1d,0x70,0x00,0xed,0x07,0xc2,0xd6,0xc1,0x03,0x5b,0x93,0xe8,0x46,0xc6}, + {0x71,0xb0,0x09,0x2f,0x74,0xe9,0x3a,0x86,0x85,0xc6,0x8a,0x27,0xcd,0x2b,0x80,0x13,0xf9,0x4b,0x20,0xcd,0xdb,0x8f,0xfd,0xb2,0x28,0x2e,0x17,0x4f,0xc7,0xd8,0x83,0xd5}, + {0x27,0xc2,0x80,0x96,0xd7,0x8f,0x41,0xfb,0x18,0x2c,0x7c,0xe8,0xce,0x59,0x5a,0x81,0x3f,0x08,0xdb,0xbb,0x02,0xd2,0x43,0x99,0x18,0x04,0x0b,0x61,0x60,0x2f,0x5f,0xba}, + {0xe7,0xf8,0x8a,0x99,0xf3,0x50,0x3c,0xf7,0x81,0x3b,0x9e,0x7e,0xf9,0x6c,0x98,0x85,0x4a,0x67,0x07,0x08,0x61,0x8f,0xe3,0x8c,0x3d,0x78,0xc8,0xd0,0x0e,0x14,0x86,0xf9}, + {0x48,0x56,0x1c,0x47,0x35,0x49,0x4b,0xdb,0x5a,0x19,0xd5,0x27,0xe5,0x7e,0x52,0x59,0x2e,0xe8,0xab,0xae,0xa1,0xc9,0x3e,0x0b,0x09,0x06,0x70,0x81,0xb8,0x38,0xa9,0x22}, + {0x95,0x9c,0x26,0x49,0xa2,0xcc,0xd6,0x96,0x47,0x11,0x49,0xb8,0x31,0x44,0x17,0x01,0xeb,0x32,0xac,0x95,0x07,0xf6,0xd0,0x5c,0x7c,0x0e,0xf9,0x2a,0xd3,0xc2,0xfc,0x27}, + }; + + tc[0].coinbase = coinbase; + tc[0].merkle_branches = merkle_branches; + tc[0].coinbase_len = sizeof(coinbase); + tc[0].merkles = sizeof(merkle_branches) / 32; + tc[0].n2size = 4; + tc[0].nonce2_offset = 142; + + /* nonce2 4 bytes with block_nb */ + unsigned char coinbase1[] = { + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x45,0x03,0x0e,0x47,0x06,0xfa,0xbe,0x6d,0x6d,0x36,0xef,0x89,0xc9,0x76,0xd4,0xb8,0x75,0x52,0xf3,0x52,0x89,0x4a,0x26, + 0xd3,0x07,0x98,0x4b,0x28,0x1d,0x6e,0x3d,0x3a,0xa2,0xa8,0xc8,0x21,0x67,0x33,0x50,0x79,0x95,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xde,0xad,0xbe,0xef,0xca,0xfe, + 0xbe,0x00,0x00,0x00,0x00,0x10,0xe3,0x03,0x2f,0x73,0x6c,0x75,0x73,0x68,0x2f,0x00,0x00,0x00,0x00,0x01,0xeb,0xb9,0xed,0x97,0x00,0x00,0x00,0x00,0x19,0x76,0xa9,0x14, + 0x7c,0x15,0x4e,0xd1,0xdc,0x59,0x60,0x9e,0x3d,0x26,0xab,0xb2,0xdf,0x2e,0xa3,0xd5,0x87,0xcd,0x8c,0x41,0x88,0xac,0x00,0x00,0x00,0x00 + }; + + unsigned char merkle_branches1[][32] = { + {0xf2,0xe1,0xd3,0x58,0x4d,0x02,0x24,0xfb,0x0b,0x7b,0x43,0xc8,0x87,0x41,0x3b,0xb6,0xab,0x3e,0xaf,0x5a,0x79,0x92,0x90,0xc2,0x56,0x9f,0x20,0xb5,0xfe,0x6b,0x0b,0x36}, + {0x36,0xb3,0xff,0xba,0x99,0xb8,0x9f,0xe4,0x0f,0xf3,0x21,0x64,0xf0,0xa1,0x19,0x86,0x0f,0x09,0x13,0x4c,0xe2,0x54,0x1e,0xff,0x38,0xc6,0xab,0x55,0xcc,0x58,0xd2,0xe4}, + {0x13,0xb1,0x66,0xdc,0x92,0x6f,0x3f,0x37,0xdb,0x30,0xec,0x4d,0x7b,0x37,0x38,0xac,0xf5,0x38,0xb6,0x4d,0x1f,0x11,0x6c,0xd2,0xee,0x84,0x5b,0xd2,0x15,0x62,0x99,0x78}, + {0x72,0x24,0xd0,0x31,0x90,0x4a,0x30,0xe0,0x7f,0x8d,0x41,0x48,0xa7,0x26,0x21,0xed,0xd3,0x47,0x0a,0xb7,0x38,0x52,0x0e,0xaf,0x65,0xab,0x3b,0xcd,0xf0,0x1c,0xeb,0x67}, + {0x81,0x85,0xe7,0x18,0x92,0xe5,0xf6,0xc5,0x05,0xba,0xe0,0xdb,0x45,0x45,0xfe,0x86,0x68,0x9a,0x11,0xb8,0x04,0x32,0x14,0x5c,0x72,0x1f,0xf9,0x6c,0xe5,0x26,0x86,0x0a}, + {0xea,0xff,0xbf,0x99,0x8f,0xfc,0x3c,0xa8,0x35,0x14,0x60,0x79,0xa3,0xdc,0x6c,0x97,0x3a,0xe7,0xb0,0xb9,0x64,0x69,0xc7,0x16,0x7b,0x17,0x12,0x46,0x87,0xdd,0x10,0x3f}, + {0x99,0x5a,0x04,0xf1,0x56,0xdf,0x6b,0x09,0x46,0xd2,0x65,0x23,0x6d,0x59,0xdf,0xeb,0xaa,0x60,0xda,0xd0,0x09,0xc3,0x22,0x56,0x14,0xf8,0xbd,0xd1,0x1c,0x74,0x7e,0x71}, + {0xf8,0x3f,0xe9,0x84,0x7c,0x0b,0x35,0x5e,0xfa,0x59,0x06,0x11,0xd2,0x82,0xd2,0x33,0x0b,0x28,0xd2,0x3d,0x18,0x4a,0x45,0x6d,0x05,0xff,0x5f,0x7b,0xaf,0x6a,0xda,0x81}, + {0x13,0xd7,0x5e,0xf4,0xda,0x4b,0x1a,0x2a,0xc9,0x42,0x19,0x7d,0x18,0x5e,0x93,0x4a,0xec,0x72,0x09,0xbc,0x95,0x2a,0xa2,0xdd,0xc6,0x77,0x4f,0xdb,0x1e,0x65,0x2c,0xd7}, + {0x85,0x6b,0x96,0xe8,0x56,0x3e,0xaa,0x9e,0x59,0x3a,0xa7,0xe0,0x29,0xc2,0xd4,0x01,0xc5,0x66,0xf7,0x8d,0x8e,0xf8,0x22,0xda,0xfe,0x79,0x5f,0x10,0x8a,0x59,0x8a,0x28}, + {0xce,0x79,0x63,0xa5,0x43,0xe1,0x00,0x18,0xf2,0x3e,0x3d,0xfd,0x52,0x01,0x17,0x55,0xe5,0xc8,0x47,0x37,0xa0,0xd0,0x86,0x51,0xb8,0x8c,0x89,0x56,0x71,0xf3,0x96,0x49}, + {0x88,0x73,0x89,0x13,0xa3,0xc7,0x3a,0xee,0x99,0x6c,0xc9,0xf5,0x76,0x0a,0xec,0x41,0xf6,0x97,0x99,0xd4,0x9b,0x09,0x36,0x4c,0x12,0xb3,0x6a,0x37,0x9c,0x18,0x42,0xef}, + }; + + tc[1].coinbase = coinbase1; + tc[1].merkle_branches = merkle_branches1; + tc[1].coinbase_len = sizeof(coinbase1); + tc[1].merkles = sizeof(merkle_branches1) / 32; + tc[1].n2size = 4; + tc[1].nonce2_offset = 97; + + /* nonce2 8 bytes */ + unsigned char coinbase2[] = { + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x31,0x03,0x18,0xc4,0x06,0x00,0x04,0xa6,0xfc,0x50,0x58,0x04,0x20,0xb8,0xb4,0x15,0x0c,0x62,0xa4,0x85,0x58,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x63,0x6b,0x70,0x6f,0x6f,0x6c,0x0d,0x2f,0x4b,0x61,0x6e,0x6f,0x20,0x2f,0x42,0x45,0x42,0x4f,0x50,0x2f,0xff,0xff,0xff,0xff,0x02, + 0xe4,0xf2,0x64,0x4d,0x00,0x00,0x00,0x00,0x19,0x76,0xa9,0x14,0x1e,0xff,0xba,0x01,0xe0,0xc6,0x5d,0x69,0x44,0xe5,0x99,0x2e,0x7b,0xa5,0x3d,0x29,0xfc,0x02,0x05,0xca, + 0x88,0xac,0x9b,0xef,0xb3,0x00,0x00,0x00,0x00,0x00,0x19,0x76,0xa9,0x14,0x5d,0xdd,0xa1,0xc1,0x1c,0xe7,0xdf,0x66,0x81,0xcb,0x06,0x4c,0xf9,0xaa,0xb5,0xd6,0xdf,0x44, + 0xbb,0x1b,0x88,0xac,0x00,0x00,0x00,0x00 + }; + + unsigned char merkle_branches2[][32] = { + {0xdf,0x40,0xcf,0x4d,0x90,0x64,0xb3,0x9e,0xce,0x1a,0x32,0x42,0xb0,0x33,0x97,0xea,0x1b,0x43,0x23,0x13,0x8a,0x0a,0x51,0x52,0x7a,0x20,0x74,0xf2,0x71,0xc3,0x88,0x52}, + {0xed,0xb0,0x7a,0x6c,0x50,0x99,0x0f,0xe8,0x9e,0xe7,0x84,0xd7,0x82,0xa0,0xe6,0xd8,0xdd,0x99,0xd6,0x15,0x35,0x63,0xa9,0x3d,0xd3,0x6c,0xb9,0xdb,0x5a,0x1e,0x34,0x5f}, + {0x64,0x98,0xb5,0x26,0x04,0x8f,0x08,0x15,0xd9,0x39,0x0d,0x0f,0x32,0x08,0x57,0x49,0x83,0xcd,0x72,0x52,0x84,0xe3,0x74,0xe0,0xe5,0xda,0x5a,0xcc,0x8e,0xdb,0xe4,0x4c}, + {0x3c,0x78,0x9f,0x8c,0xf7,0x39,0x93,0x52,0x55,0xf4,0x34,0x42,0x9a,0x77,0xe3,0xcf,0x22,0xf6,0x1c,0x4a,0x38,0x2e,0x32,0xfd,0xb5,0xd0,0x3d,0x36,0x9b,0x31,0x79,0x5a}, + {0xc2,0xce,0xd4,0x9b,0x26,0xdf,0x6d,0x83,0x25,0xf8,0x33,0x94,0x60,0xf8,0x8f,0x69,0xbd,0x98,0x07,0x18,0x94,0xa4,0x5a,0x14,0x2a,0x54,0x6e,0x6d,0x88,0xb4,0xc7,0xd2}, + {0x4f,0x62,0x78,0x05,0xdc,0x7e,0x4d,0xc8,0x52,0x6a,0xc8,0xb2,0x86,0xf6,0x52,0x0d,0x17,0x57,0x74,0x59,0x04,0xc3,0x9d,0x38,0xa6,0xf8,0xc3,0x6b,0x74,0xfd,0x5d,0x10}, + {0xe1,0xd3,0xfb,0x46,0x1c,0xb4,0xbe,0xd1,0x55,0xcf,0x9e,0x21,0x2b,0x65,0xe1,0x0f,0xd1,0x65,0x1a,0x2e,0x25,0x78,0x74,0x0f,0x6c,0xb1,0x11,0xa2,0x26,0x34,0xba,0x9e}, + {0x63,0xd0,0x2e,0x76,0xd7,0x54,0xf7,0x67,0xef,0x9a,0x3c,0xa3,0xae,0xa0,0x5e,0xb2,0xc3,0x94,0x75,0x99,0x73,0xf0,0x40,0xa1,0x80,0x9e,0x02,0xf3,0x0e,0xed,0xcd,0x0d}, + {0x7f,0x51,0x79,0xc7,0x36,0x27,0xe7,0x35,0xf4,0x41,0x52,0x04,0x0a,0xd8,0x61,0xe6,0x95,0x97,0xb6,0x89,0x81,0x09,0x17,0x4e,0x09,0x2d,0x28,0xc0,0x37,0x74,0x73,0x52}, + {0x9c,0x37,0x53,0xe0,0x39,0x6f,0x49,0xe4,0x46,0xb9,0xf8,0x82,0x0a,0xaf,0xd0,0x7b,0x38,0xf7,0xea,0x6f,0xf8,0xc3,0x60,0x05,0x96,0x99,0x9b,0x1c,0xbb,0x51,0xd7,0x49}, + {0x20,0xf8,0x90,0x21,0xa8,0x4c,0xb4,0x93,0x0d,0xf8,0x1d,0xfc,0x66,0x81,0xab,0x0e,0x01,0x97,0x95,0x42,0x03,0x36,0x41,0x0f,0xfc,0x2b,0xe2,0x9a,0x31,0x34,0x8e,0x5f}, + }; + + tc[2].coinbase = coinbase2; + tc[2].merkle_branches = merkle_branches2; + tc[2].coinbase_len = sizeof(coinbase2); + tc[2].merkles = sizeof(merkle_branches2) / 32; + tc[2].n2size = 8; + tc[2].nonce2_offset = 62; + + ssp_sorter_init(HT_SIZE, HT_PRB_LMT, HT_PRB_C1, HT_PRB_C2); + ssp_hasher_init(); + + cgtime(&t_start); + while (1) { + if (stratum_update) { + for (pool_index = 0; pool_index < 2; pool_index++) { + test_pool[pool_index].coinbase_len = tc[tci].coinbase_len; + test_pool[pool_index].coinbase = cgcalloc(test_pool[pool_index].coinbase_len, 1); + test_pool[pool_index].merkles = tc[tci].merkles; + + test_pool[pool_index].swork.merkle_bin = cgmalloc(sizeof(char *) * test_pool[pool_index].merkles + 1); + for (i = 0; i < test_pool[pool_index].merkles; i++) { + test_pool[pool_index].swork.merkle_bin[i] = cgmalloc(32); + memcpy(test_pool[pool_index].swork.merkle_bin[i], tc[tci].merkle_branches[i], 32); + } + memcpy(test_pool[pool_index].coinbase, tc[tci].coinbase, test_pool[pool_index].coinbase_len); + test_pool[pool_index].n2size = tc[tci].n2size; + test_pool[pool_index].nonce2_offset = tc[tci].nonce2_offset; + } + stratum_update = false; + hasher_update = true; + } + + if (ssp_sorter_get_pair(pair)) { + cgtime(&t_find_pair); + pair_diff = tdiff(&t_find_pair, &t_start); + applog(LOG_NOTICE, "%0.8fs\tGot a pair %08x-%08x", pair_diff, pair[0], pair[1]); + tail[0] = gen_merkle_root(&test_pool[1], pair[0]); + tail[1] = gen_merkle_root(&test_pool[1], pair[1]); + if (tail[0] != tail[1]) { + applog(LOG_NOTICE, "tail mismatch (%08x:%08x -> %08x:%08x)", + tail[0], + tail[1], + pair[0], + pair[1]); + } else { + applog(LOG_NOTICE, "tail pass (%08x -> %08x:%08x)", + tail[0], + pair[0], + pair[1]); + } + + memcpy(&t_start, &t_find_pair, sizeof(t_find_pair)); + + pair_count++; + if (pair_count == 20) { + stratum_update = true; + pair_count = 0; + tci = (tci + 1) % TESTCASE_COUNT; + + for (pool_index = 0; pool_index < 2; pool_index++) { + free(test_pool[pool_index].coinbase); + for (i = 0; i < test_pool[pool_index].merkles; i++) + free(test_pool[pool_index].swork.merkle_bin[i]); + } + } + } + + if (hasher_update) { + hasher_update = false; + ssp_hasher_update_stratum(&test_pool[0], true); + } + } + + quit(1, "ssp_hasher_test finished\n"); +} diff --git a/libssplus.h b/libssplus.h new file mode 100644 index 0000000000..86fda3fa10 --- /dev/null +++ b/libssplus.h @@ -0,0 +1,27 @@ +/* + * Copyright 2016 Mikeqin + * + * 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 LIBSSPLUS_H +#define LIBSSPLUS_H + +#define HT_SIZE (1 << 22) +#define HT_PRB_LMT 1 +#define HT_PRB_C1 0 +#define HT_PRB_C2 1 + +typedef uint32_t ssp_pair[2]; + +int ssp_hasher_init(void); +void ssp_hasher_update_stratum(struct pool *pool, bool clean); +void ssp_hasher_test(void); + +void ssp_sorter_init(uint32_t max_size, uint32_t limit, uint32_t c1, uint32_t c2); +void ssp_sorter_flush(void); +int ssp_sorter_get_pair(ssp_pair pair); + +#endif /* LIBSSPLUS_H */ diff --git a/miner.h b/miner.h index bec3bfb48a..370bc5ce6b 100644 --- a/miner.h +++ b/miner.h @@ -1129,6 +1129,7 @@ extern void set_target(unsigned char *dest_target, double diff); #if defined (USE_AVALON2) || defined (USE_AVALON4) || defined (USE_AVALON7) || defined (USE_AVALON_MINER) || defined (USE_HASHRATIO) bool submit_nonce2_nonce(struct thr_info *thr, struct pool *pool, struct pool *real_pool, uint32_t nonce2, uint32_t nonce, uint32_t ntime); +uint32_t gen_merkle_root(struct pool *pool, uint64_t nonce2); #endif extern int restart_wait(struct thr_info *thr, unsigned int mstime); diff --git a/util.c b/util.c index 3e3cee319d..7de2e6212d 100644 --- a/util.c +++ b/util.c @@ -44,6 +44,11 @@ #include "elist.h" #include "compat.h" #include "util.h" +#include "libssplus.h" + +#ifdef USE_AVALON7 +#include "driver-avalon7.h" +#endif #define DEFAULT_SOCKWAIT 60 #ifndef STRATUM_USER_AGENT @@ -2151,8 +2156,13 @@ static bool parse_notify(struct pool *pool, json_t *val) /* A notify message is the closest stratum gets to a getwork */ pool->getwork_requested++; total_getworks++; - if (pool == current_pool()) + if (pool == current_pool()) { opt_work_update = true; +#ifdef USE_AVALON7 + if (opt_avalon7_ssplus_enable & pool->has_stratum) + ssp_hasher_update_stratum(pool, true); +#endif + } out: return ret; } From 4cdf957b1e4019ef470c6793437c38ece88b12a8 Mon Sep 17 00:00:00 2001 From: Mikeqin Date: Fri, 19 May 2017 17:06:51 +0800 Subject: [PATCH 003/113] Add clean_jobs notify --- cgminer.c | 19 +++++++++++++++++++ miner.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/cgminer.c b/cgminer.c index 50c8b571cc..e26f2d52a9 100644 --- a/cgminer.c +++ b/cgminer.c @@ -142,6 +142,7 @@ struct strategies strategies[] = { static char packagename[256]; bool opt_work_update; +bool opt_clean_jobs = false; bool opt_protocol; static struct benchfile_layout { int length; @@ -5046,6 +5047,18 @@ static void signal_work_update(void) rd_unlock(&mining_thr_lock); } +static void signal_clean_jobs(void) +{ + int i; + + applog(LOG_NOTICE, "Job clean message received"); + + rd_lock(&mining_thr_lock); + for (i = 0; i < mining_threads; i++) + mining_thr[i]->clean_jobs = true; + rd_unlock(&mining_thr_lock); +} + static void set_curblock(const char *hexstr, const unsigned char *bedata) { int ofs; @@ -5161,6 +5174,7 @@ static bool test_work_current(struct work *work) if (pool->swork.clean) { pool->swork.clean = false; work->longpoll = true; + opt_clean_jobs = true; } if (pool->current_height != height) { pool->current_height = height; @@ -10272,6 +10286,11 @@ int main(int argc, char *argv[]) opt_work_update = false; + if (opt_clean_jobs) { + signal_clean_jobs(); + opt_clean_jobs = false; + } + mutex_lock(stgd_lock); ts = __total_staged(); /* Wait until hash_pop tells us we need to create more work */ diff --git a/miner.h b/miner.h index 370bc5ce6b..f46f983e25 100644 --- a/miner.h +++ b/miner.h @@ -571,6 +571,7 @@ struct thr_info { bool work_restart; bool work_update; + bool clean_jobs; }; struct string_elist { @@ -981,6 +982,7 @@ struct pool; #define API_MCAST_ADDR "224.0.0.75" extern bool opt_work_update; +extern bool opt_clean_jobs; extern bool opt_protocol; extern bool have_longpoll; extern char *opt_kernel_path; From 90262c2342d1b99a71225340be0062c45bac20da Mon Sep 17 00:00:00 2001 From: Mikeqin Date: Fri, 19 May 2017 17:21:46 +0800 Subject: [PATCH 004/113] Only update stratum work to MM when new block was found * It only used in smart speed plus mode --- driver-avalon7.c | 16 +++++++++++++--- util.c | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/driver-avalon7.c b/driver-avalon7.c index 1c0cd8f6a0..a844085bae 100644 --- a/driver-avalon7.c +++ b/driver-avalon7.c @@ -1914,21 +1914,32 @@ static void avalon7_sswork_update(struct cgpu_info *avalon7) struct pool *pool; int coinbase_len_posthash, coinbase_len_prehash; + cgtime(&info->last_stratum); /* * NOTE: We need mark work_restart to private information, * So that it cann't reset by hash_driver_work */ if (thr->work_restart) info->work_restart = thr->work_restart; - applog(LOG_DEBUG, "%s-%d: New stratum: restart: %d, update: %d", + applog(LOG_NOTICE, "%s-%d: New stratum: restart: %d, update: %d, clean: %d", avalon7->drv->name, avalon7->device_id, - thr->work_restart, thr->work_update); + thr->work_restart, thr->work_update, thr->clean_jobs); /* Step 1: MM protocol check */ pool = current_pool(); if (!pool->has_stratum) quit(1, "%s-%d: MM has to use stratum pools", avalon7->drv->name, avalon7->device_id); + if (opt_avalon7_ssplus_enable) { + if (thr->clean_jobs) { + applog(LOG_DEBUG, "%s-%d: Update the stratum", avalon7->drv->name, avalon7->device_id); + thr->clean_jobs = false; + } else { + applog(LOG_DEBUG, "%s-%d: Ignore the stratum", avalon7->drv->name, avalon7->device_id); + return; + } + } + coinbase_len_prehash = pool->nonce2_offset - (pool->nonce2_offset % SHA256_BLOCK_SIZE); coinbase_len_posthash = pool->coinbase_len - coinbase_len_prehash; @@ -1950,7 +1961,6 @@ static void avalon7_sswork_update(struct cgpu_info *avalon7) /* Step 2: Send out stratum pkgs */ cg_rlock(&pool->data_lock); - cgtime(&info->last_stratum); info->pool_no = pool->pool_no; copy_pool_stratum(&info->pool2, &info->pool1); copy_pool_stratum(&info->pool1, &info->pool0); diff --git a/util.c b/util.c index 7de2e6212d..c5aa41306b 100644 --- a/util.c +++ b/util.c @@ -2159,7 +2159,7 @@ static bool parse_notify(struct pool *pool, json_t *val) if (pool == current_pool()) { opt_work_update = true; #ifdef USE_AVALON7 - if (opt_avalon7_ssplus_enable & pool->has_stratum) + if (opt_avalon7_ssplus_enable & pool->has_stratum & clean) ssp_hasher_update_stratum(pool, true); #endif } From 7de9a9b86fefff65c370c01afc3e90c15109d286 Mon Sep 17 00:00:00 2001 From: Mikeqin Date: Sat, 20 May 2017 08:28:41 +0800 Subject: [PATCH 005/113] Support clean jobs for different stratum pool Add --force-clean-jobs option. -1 means ignore the stratum update when clean_jobs is 0 0 means accept the stratum update when parse_notify was called. n means accept the stratum update after n seconds, n > 0. --- README | 1 + cgminer.c | 4 ++++ miner.h | 1 + util.c | 35 +++++++++++++++++++++++++++++++++-- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/README b/README index a70270cda3..427258e0a9 100644 --- a/README +++ b/README @@ -346,6 +346,7 @@ Options for both config file and command line: --verbose Log verbose output to stderr as well as status output --widescreen Use extra wide display without toggling --worktime Display extra work time debug information +--force-clean-jobs Force clean jobs to miners (default: 20) Options for command line only: --config|-c Load a JSON-format configuration file See example.conf for an example configuration. diff --git a/cgminer.c b/cgminer.c index e26f2d52a9..990705e03d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -465,6 +465,7 @@ static struct stratum_share *stratum_shares = NULL; char *opt_socks_proxy = NULL; int opt_suggest_diff; +int opt_force_clean_jobs = 20; static const char def_conf[] = "cgminer.conf"; static char *default_config; static bool config_loaded; @@ -1981,6 +1982,9 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--worktime", opt_set_bool, &opt_worktime, "Display extra work time debug information"), + OPT_WITH_ARG("--force-clean-jobs", + opt_set_intval, NULL, &opt_force_clean_jobs, + "Force clean jobs to miners (default: 20)"), OPT_ENDTABLE }; diff --git a/miner.h b/miner.h index f46f983e25..96fca536d1 100644 --- a/miner.h +++ b/miner.h @@ -988,6 +988,7 @@ extern bool have_longpoll; extern char *opt_kernel_path; extern char *opt_socks_proxy; extern int opt_suggest_diff; +extern int opt_force_clean_jobs; extern char *cgminer_path; extern bool opt_lowmem; extern bool opt_autofan; diff --git a/util.c b/util.c index c5aa41306b..8952082a3a 100644 --- a/util.c +++ b/util.c @@ -2007,6 +2007,9 @@ static void decode_exit(struct pool __maybe_unused *pool, char __maybe_unused *b static bool parse_notify(struct pool *pool, json_t *val) { + static int32_t th_clean_jobs; + static struct timeval last_notify; + struct timeval current; char *job_id, *prev_hash, *coinbase1, *coinbase2, *bbversion, *nbit, *ntime, header[260]; unsigned char *cb1 = NULL, *cb2 = NULL; @@ -2159,8 +2162,36 @@ static bool parse_notify(struct pool *pool, json_t *val) if (pool == current_pool()) { opt_work_update = true; #ifdef USE_AVALON7 - if (opt_avalon7_ssplus_enable & pool->has_stratum & clean) - ssp_hasher_update_stratum(pool, true); + if (opt_avalon7_ssplus_enable & pool->has_stratum) { + /* -1:Ignore, 0:Accept, n:Accept after n seconds, n > 0 */ + if (opt_force_clean_jobs == -1 && clean) + opt_clean_jobs = true; + + if (!opt_force_clean_jobs) + opt_clean_jobs = true; + + if (opt_force_clean_jobs > 0) { + if (clean) + opt_clean_jobs = true; + else { + if (!last_notify.tv_sec && !last_notify.tv_usec) + cgtime(&last_notify); + else { + cgtime(¤t); + th_clean_jobs += (int32_t)ms_tdiff(¤t, &last_notify); + cgtime(&last_notify); + } + + if (th_clean_jobs >= opt_force_clean_jobs * 1000) + opt_clean_jobs = true; + } + } + + if (opt_clean_jobs) { + ssp_hasher_update_stratum(pool, true); + th_clean_jobs = 0; + } + } #endif } out: From 2354004b70bcbc0068d44a471bc9821f4e653612 Mon Sep 17 00:00:00 2001 From: Johnson-Fan Date: Fri, 2 Jun 2017 20:57:10 +0800 Subject: [PATCH 006/113] Add factory info support --- driver-avalon7.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ driver-avalon7.h | 10 +++++++++ 2 files changed, 68 insertions(+) diff --git a/driver-avalon7.c b/driver-avalon7.c index a844085bae..1d33f999a5 100644 --- a/driver-avalon7.c +++ b/driver-avalon7.c @@ -760,6 +760,10 @@ static int decode_pkg(struct cgpu_info *avalon7, struct avalon7_ret *ar, int mod info->get_asic[modular_id][x_miner_id][x_asic_id][10] = tmp; } break; + case AVA7_P_STATUS_FAC: + applog(LOG_DEBUG, "%s-%d-%d: AVA7_P_STATUS_FAC", avalon7->drv->name, avalon7->device_id, modular_id); + info->factory_info[0] = ar->data[0]; + break; default: applog(LOG_DEBUG, "%s-%d-%d: Unknown response %x", avalon7->drv->name, avalon7->device_id, modular_id, ar->type); break; @@ -1840,6 +1844,24 @@ static void avalon7_set_freq(struct cgpu_info *avalon7, int addr, int miner_id, avalon7_iic_xfer_pkg(avalon7, addr, &send_pkg, NULL); } +static void avalon7_set_factory_info(struct cgpu_info *avalon7, int addr, uint8_t value[]) +{ + struct avalon7_pkg send_pkg; + uint8_t i; + + memset(send_pkg.data, 0, AVA7_P_DATA_LEN); + + for (i = 0; i < AVA7_DEFAULT_FACTORY_INFO_CNT; i++) + send_pkg.data[i] = value[i]; + + /* Package the data */ + avalon7_init_pkg(&send_pkg, AVA7_P_SET_FAC, 1, 1); + if (addr == AVA7_MODULE_BROADCAST) + avalon7_send_bc_pkgs(avalon7, &send_pkg); + else + avalon7_iic_xfer_pkg(avalon7, addr, &send_pkg, NULL); +} + static void avalon7_set_ss_param(struct cgpu_info *avalon7, int addr) { struct avalon7_pkg send_pkg; @@ -2270,6 +2292,9 @@ static struct api_data *avalon7_api_stats(struct cgpu_info *avalon7) strcat(statbuf, buf); if (opt_debug) { + sprintf(buf, " FAC0[%d]", info->factory_info[0]); + strcat(statbuf, buf); + for (j = 0; j < info->miner_count[i]; j++) { sprintf(buf, " SF%d[", j); strcat(statbuf, buf); @@ -2523,6 +2548,30 @@ char *set_avalon7_device_freq(struct cgpu_info *avalon7, char *arg) return NULL; } +char *set_avalon7_factory_info(struct cgpu_info *avalon7, char *arg) +{ + struct avalon7_info *info = avalon7->device_data; + int val; + + if (!(*arg)) + return NULL; + + sscanf(arg, "%d", &val); + if (!val) + val = AVA7_DEFAULT_FACTORY_INFO_0; + + if (val < AVA7_DEFAULT_FACTORY_INFO_0_MIN || val > AVA7_DEFAULT_FACTORY_INFO_0_MAX) + return "Invalid value passed to set_avalon7_factory_info"; + + info->factory_info[0] = val; + avalon7_set_factory_info(avalon7, 0, (uint8_t *)info->factory_info); + + applog(LOG_NOTICE, "%s-%d: Update factory info %d", + avalon7->drv->name, avalon7->device_id, val); + + return NULL; +} + static char *avalon7_set_device(struct cgpu_info *avalon7, char *option, char *setting, char *replybuf) { unsigned int val; @@ -2627,6 +2676,15 @@ static char *avalon7_set_device(struct cgpu_info *avalon7, char *option, char *s return set_avalon7_device_voltage(avalon7, setting); } + if (strcasecmp(option, "factory") == 0) { + if (!setting || !*setting) { + sprintf(replybuf, "missing factory info"); + return replybuf; + } + + return set_avalon7_factory_info(avalon7, setting); + } + if (strcasecmp(option, "reboot") == 0) { if (!setting || !*setting) { sprintf(replybuf, "missing reboot value"); diff --git a/driver-avalon7.h b/driver-avalon7.h index 83888d16a5..e31db32e22 100644 --- a/driver-avalon7.h +++ b/driver-avalon7.h @@ -38,6 +38,10 @@ #define AVA7_DEFAULT_VOLTAGE_OFFSET 0 #define AVA7_DEFAULT_VOLTAGE_OFFSET_MAX 1 +#define AVA7_DEFAULT_FACTORY_INFO_0_MIN -15 +#define AVA7_DEFAULT_FACTORY_INFO_0 0 +#define AVA7_DEFAULT_FACTORY_INFO_0_MAX 15 + #define AVA7_DEFAULT_FREQUENCY_MIN 24 /* NOTE: It cann't support 0 */ #define AVA7_DEFAULT_FREQUENCY_0 600 #define AVA7_DEFAULT_FREQUENCY_1 636 @@ -120,6 +124,7 @@ #define AVA7_P_SET_PLL 0x25 #define AVA7_P_SET_SS 0x26 #define AVA7_P_PAIRS 0x27 +#define AVA7_P_SET_FAC 0x28 /* Have to send with I2C address */ #define AVA7_P_POLLING 0x30 @@ -139,6 +144,7 @@ #define AVA7_P_STATUS_LOG 0x4a #define AVA7_P_STATUS_ASIC 0x4b #define AVA7_P_STATUS_PVT 0x4c +#define AVA7_P_STATUS_FAC 0x4d #define AVA7_MODULE_BROADCAST 0 /* End of avalon7 protocol package type */ @@ -158,6 +164,8 @@ #define AVA7_DEFAULT_DELTA_T 0 #define AVA7_DEFAULT_DELTA_FREQ 100 +#define AVA7_DEFAULT_FACTORY_INFO_CNT 1 + #define AVA7_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 100.0) #define AVA7_MM711_VOUT_ADC_RATIO (3.3 / 1024.0 * 125.0 / 43.0 * 10000.0 * 100.0) @@ -249,6 +257,8 @@ struct avalon7_info { /* spd_pass(4B), spd_fail(4B), sum_failed(4B), sum_num(4B), sum_xor(4B), PLL(6 * 4B) */ uint32_t get_asic[AVA7_DEFAULT_MODULARS][AVA7_DEFAULT_MINER_CNT][AVA7_DEFAULT_ASIC_MAX][11]; + int8_t factory_info[AVA7_DEFAULT_FACTORY_INFO_CNT]; + uint64_t local_works[AVA7_DEFAULT_MODULARS]; uint64_t local_works_i[AVA7_DEFAULT_MODULARS][AVA7_DEFAULT_MINER_CNT]; uint64_t hw_works[AVA7_DEFAULT_MODULARS]; From e0a064459d8764f562831cd79c7900caef985008 Mon Sep 17 00:00:00 2001 From: Johnson-Fan Date: Fri, 31 Mar 2017 15:08:52 +0800 Subject: [PATCH 007/113] Add A761 support --- driver-avalon7.c | 8 ++++++++ driver-avalon7.h | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/driver-avalon7.c b/driver-avalon7.c index 1d33f999a5..42a77fba61 100644 --- a/driver-avalon7.c +++ b/driver-avalon7.c @@ -202,6 +202,14 @@ struct avalon7_dev_description avalon7_dev_table[] = { 22, AVA7_MM741_VOUT_ADC_RATIO, 4825, + }, + { + "761", + 761, + 4, + 26, + AVA7_MM761_VOUT_ADC_RATIO, + 4825, } }; diff --git a/driver-avalon7.h b/driver-avalon7.h index e31db32e22..ac38feffab 100644 --- a/driver-avalon7.h +++ b/driver-avalon7.h @@ -54,7 +54,7 @@ #define AVA7_DEFAULT_MODULARS 7 /* Only support 6 modules maximum with one AUC */ #define AVA7_DEFAULT_MINER_CNT 4 -#define AVA7_DEFAULT_ASIC_MAX 22 +#define AVA7_DEFAULT_ASIC_MAX 26 #define AVA7_DEFAULT_PLL_CNT 6 #define AVA7_DEFAULT_PMU_CNT 2 @@ -171,6 +171,7 @@ #define AVA7_MM711_VOUT_ADC_RATIO (3.3 / 1024.0 * 125.0 / 43.0 * 10000.0 * 100.0) #define AVA7_MM721_VOUT_ADC_RATIO (3.3 / 1024.0 * 125.0 / 43.0 * 10000.0 * 100.0) #define AVA7_MM741_VOUT_ADC_RATIO (3.3 / 1024.0 * 63.0 / 20.0 * 10000.0 * 100.0) +#define AVA7_MM761_VOUT_ADC_RATIO (3.3 / 1024.0 * 26.0 / 6.0 * 10000.0 * 100.0) struct avalon7_pkg { uint8_t head[2]; From fa124428405d39247caf33fdd656b83e0f955480 Mon Sep 17 00:00:00 2001 From: Johnson-Fan Date: Fri, 31 Mar 2017 15:23:33 +0800 Subject: [PATCH 008/113] Update avalon7 device description --- driver-avalon7.c | 11 ++++++++--- driver-avalon7.h | 7 ++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/driver-avalon7.c b/driver-avalon7.c index 42a77fba61..ab11e855f1 100644 --- a/driver-avalon7.c +++ b/driver-avalon7.c @@ -184,6 +184,7 @@ struct avalon7_dev_description avalon7_dev_table[] = { 711, 4, 18, + AVA7_MM711_VIN_ADC_RATIO, AVA7_MM711_VOUT_ADC_RATIO, 4981 }, @@ -192,6 +193,7 @@ struct avalon7_dev_description avalon7_dev_table[] = { 721, 4, 18, + AVA7_MM721_VIN_ADC_RATIO, AVA7_MM721_VOUT_ADC_RATIO, 4981 }, @@ -200,6 +202,7 @@ struct avalon7_dev_description avalon7_dev_table[] = { 741, 4, 22, + AVA7_MM741_VIN_ADC_RATIO, AVA7_MM741_VOUT_ADC_RATIO, 4825, }, @@ -208,6 +211,7 @@ struct avalon7_dev_description avalon7_dev_table[] = { 761, 4, 26, + AVA7_MM761_VIN_ADC_RATIO, AVA7_MM761_VOUT_ADC_RATIO, 4825, } @@ -242,9 +246,9 @@ static uint32_t decode_voltage(struct avalon7_info *info, int modular_id, uint32 return (volt * info->vout_adc_ratio[modular_id] / info->asic_count[modular_id] / 100); } -static uint16_t decode_vin(uint16_t volt) +static uint16_t decode_vin(struct avalon7_info *info, int modular_id, uint16_t volt) { - return (volt * AVA7_VIN_ADC_RATIO); + return (volt * info->vin_adc_ratio[modular_id] / 10); } static double decode_pvt_temp(uint16_t pvt_code) @@ -692,7 +696,7 @@ static int decode_pkg(struct cgpu_info *avalon7, struct avalon7_ret *ar, int mod for (i = 0; i < info->miner_count[modular_id]; i++) { memcpy(&vin, ar->data + 8 + i * 2, 2); - info->get_vin[modular_id][i] = decode_vin(be16toh(vin)); + info->get_vin[modular_id][i] = decode_vin(info, modular_id, be16toh(vin)); } break; case AVA7_P_STATUS_VOLT: @@ -1544,6 +1548,7 @@ static void detect_modules(struct cgpu_info *avalon7) info->mod_type[i] = avalon7_dev_table[dev_index].mod_type; info->miner_count[i] = avalon7_dev_table[dev_index].miner_count; info->asic_count[i] = avalon7_dev_table[dev_index].asic_count; + info->vin_adc_ratio[i] = avalon7_dev_table[dev_index].vin_adc_ratio; info->vout_adc_ratio[i] = avalon7_dev_table[dev_index].vout_adc_ratio; break; } diff --git a/driver-avalon7.h b/driver-avalon7.h index ac38feffab..95071392bf 100644 --- a/driver-avalon7.h +++ b/driver-avalon7.h @@ -166,7 +166,10 @@ #define AVA7_DEFAULT_FACTORY_INFO_CNT 1 -#define AVA7_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 100.0) +#define AVA7_MM711_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 1000.0) +#define AVA7_MM721_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 1000.0) +#define AVA7_MM741_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 1000.0) +#define AVA7_MM761_VIN_ADC_RATIO (3.3 / 1024.0 * 26.0 / 6.0 * 1000.0) #define AVA7_MM711_VOUT_ADC_RATIO (3.3 / 1024.0 * 125.0 / 43.0 * 10000.0 * 100.0) #define AVA7_MM721_VOUT_ADC_RATIO (3.3 / 1024.0 * 125.0 / 43.0 * 10000.0 * 100.0) @@ -274,6 +277,7 @@ struct avalon7_info { char pmu_version[AVA7_DEFAULT_MODULARS][AVA7_DEFAULT_PMU_CNT][5]; uint64_t diff1[AVA7_DEFAULT_MODULARS]; + uint16_t vin_adc_ratio[AVA7_DEFAULT_MODULARS]; uint16_t vout_adc_ratio[AVA7_DEFAULT_MODULARS]; bool conn_overloaded; @@ -299,6 +303,7 @@ struct avalon7_dev_description { int mod_type; uint8_t miner_count; /* it should not greater than AVA7_DEFAULT_MINER_CNT */ uint8_t asic_count; /* asic count each miner, it should not great than AVA7_DEFAULT_ASIC_MAX */ + uint16_t vin_adc_ratio; uint16_t vout_adc_ratio; uint32_t set_voltage; }; From 257f2f6e49788596e51a792afbcb65766aac6196 Mon Sep 17 00:00:00 2001 From: Johnson-Fan Date: Thu, 8 Jun 2017 11:53:18 +0800 Subject: [PATCH 009/113] Update vin_adc_ratio calculation --- driver-avalon7.c | 2 +- driver-avalon7.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/driver-avalon7.c b/driver-avalon7.c index ab11e855f1..dd265c638a 100644 --- a/driver-avalon7.c +++ b/driver-avalon7.c @@ -248,7 +248,7 @@ static uint32_t decode_voltage(struct avalon7_info *info, int modular_id, uint32 static uint16_t decode_vin(struct avalon7_info *info, int modular_id, uint16_t volt) { - return (volt * info->vin_adc_ratio[modular_id] / 10); + return (volt * info->vin_adc_ratio[modular_id] / 1000); } static double decode_pvt_temp(uint16_t pvt_code) diff --git a/driver-avalon7.h b/driver-avalon7.h index 95071392bf..b8160e6ebc 100644 --- a/driver-avalon7.h +++ b/driver-avalon7.h @@ -166,10 +166,10 @@ #define AVA7_DEFAULT_FACTORY_INFO_CNT 1 -#define AVA7_MM711_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 1000.0) -#define AVA7_MM721_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 1000.0) -#define AVA7_MM741_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 1000.0) -#define AVA7_MM761_VIN_ADC_RATIO (3.3 / 1024.0 * 26.0 / 6.0 * 1000.0) +#define AVA7_MM711_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 1000.0 * 100.0) +#define AVA7_MM721_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 1000.0 * 100.0) +#define AVA7_MM741_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 1000.0 * 100.0) +#define AVA7_MM761_VIN_ADC_RATIO (3.3 / 1024.0 * 26.0 / 6.0 * 1000.0 * 100.0) #define AVA7_MM711_VOUT_ADC_RATIO (3.3 / 1024.0 * 125.0 / 43.0 * 10000.0 * 100.0) #define AVA7_MM721_VOUT_ADC_RATIO (3.3 / 1024.0 * 125.0 / 43.0 * 10000.0 * 100.0) From 95ead3364d40bc0dbb1e653b6fe4b6c5e4f55927 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Wed, 21 Jun 2017 21:01:26 -0500 Subject: [PATCH 010/113] Fix BIP34 Serialization --- util.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/util.c b/util.c index 3e3cee319d..7cfc617d86 100644 --- a/util.c +++ b/util.c @@ -1037,11 +1037,15 @@ int ser_number(unsigned char *s, int32_t val) int32_t *i32 = (int32_t *)&s[1]; int len; + if (val < 17) { + s[0] = 0x50 + val; + return 1; + } if (val < 128) len = 1; - else if (val < 16512) + else if (val < 32768) len = 2; - else if (val < 2113664) + else if (val < 8388608) len = 3; else len = 4; From 9de831350aa5d439082163512bcef8b5c4daec98 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Wed, 21 Jun 2017 21:44:24 -0500 Subject: [PATCH 011/113] Fix testnet diff --- cgminer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 8026a34e26..e5d5501d4f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -5073,8 +5073,8 @@ static void set_blockdiff(const struct work *work) { uint8_t pow = work->data[72]; int powdiff = (8 * (0x1d - 3)) - (8 * (pow - 3)); - if (powdiff < 8) - powdiff = 8; + if (powdiff < 0) + powdiff = 0; uint32_t diff32 = be32toh(*((uint32_t *)(work->data + 72))) & 0x00FFFFFF; double numerator = 0xFFFFULL << powdiff; double ddiff = numerator / (double)diff32; From c20ff313ff38a79ea87f3e603f5335f26694b303 Mon Sep 17 00:00:00 2001 From: Mikeqin Date: Wed, 27 Sep 2017 10:17:21 +0800 Subject: [PATCH 012/113] Fix warnings --- cgminer.c | 2 ++ util.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/cgminer.c b/cgminer.c index 990705e03d..54e8e3948d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1202,6 +1202,7 @@ static void load_temp_cutoffs() } } +#ifdef USE_ICARUS static char *set_float_100_to_500(const char *arg, float *i) { char *err = opt_set_floatval(arg, i); @@ -1214,6 +1215,7 @@ static char *set_float_100_to_500(const char *arg, float *i) return NULL; } +#endif static char *set_float_125_to_500(const char *arg, float *i) { diff --git a/util.c b/util.c index 8952082a3a..39a5a98f2b 100644 --- a/util.c +++ b/util.c @@ -2007,9 +2007,11 @@ static void decode_exit(struct pool __maybe_unused *pool, char __maybe_unused *b static bool parse_notify(struct pool *pool, json_t *val) { +#ifdef USE_AVALON7 static int32_t th_clean_jobs; static struct timeval last_notify; struct timeval current; +#endif char *job_id, *prev_hash, *coinbase1, *coinbase2, *bbversion, *nbit, *ntime, header[260]; unsigned char *cb1 = NULL, *cb2 = NULL; From 6146576384db52e4d4f32eed58c6cd5706850d96 Mon Sep 17 00:00:00 2001 From: Mikeqin Date: Wed, 27 Sep 2017 10:27:42 +0800 Subject: [PATCH 013/113] Fix api warning without miner enable --- api.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/api.c b/api.c index 5fe90110e9..d5d3a5afd2 100644 --- a/api.c +++ b/api.c @@ -141,9 +141,11 @@ static const char SEPARATOR = '|'; static const char *APIVERSION = "3.7"; static const char *DEAD = "Dead"; +#if defined(HAVE_AN_ASIC) || defined(HAVE_AN_FPGA) static const char *SICK = "Sick"; static const char *NOSTART = "NoStart"; static const char *INIT = "Initialising"; +#endif static const char *DISABLED = "Disabled"; static const char *ALIVE = "Alive"; static const char *REJECTING = "Rejecting"; @@ -1974,6 +1976,7 @@ static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __ io_close(io_data); } +#if defined(HAVE_AN_ASIC) || defined(HAVE_AN_FPGA) static const char *status2str(enum alive status) { switch (status) { @@ -1991,6 +1994,7 @@ static const char *status2str(enum alive status) return UNKNOWN; } } +#endif #ifdef HAVE_AN_ASIC static void ascstatus(struct io_data *io_data, int asc, bool isjson, bool precom) @@ -2155,10 +2159,12 @@ static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom static void devstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { bool io_open = false; - int devcount = 0; int numasc = 0; int numpga = 0; +#if defined(HAVE_AN_ASIC) || defined(HAVE_AN_FPGA) + int devcount = 0; int i; +#endif #ifdef HAVE_AN_ASIC numasc = numascs(); @@ -2205,10 +2211,12 @@ static void devstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __ma static void edevstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { bool io_open = false; - int devcount = 0; int numasc = 0; int numpga = 0; +#if defined(HAVE_AN_ASIC) || defined(HAVE_AN_FPGA) + int devcount = 0; int i; +#endif #ifdef USE_USBUTILS time_t howoldsec = 0; #endif From 6786bbd271d4ef8e445014acbb8d0be2ba93a368 Mon Sep 17 00:00:00 2001 From: xzx Date: Mon, 11 Sep 2017 18:12:19 +0800 Subject: [PATCH 014/113] Add Avalon8 support --- Makefile.am | 4 + api.c | 2 +- cgminer.c | 79 +- configure.ac | 25 +- driver-avalon8.c | 2527 ++++++++++++++++++++++++++++++++++++++++++++++ driver-avalon8.h | 309 ++++++ miner.h | 3 +- usbutils.c | 27 + usbutils.h | 3 + 9 files changed, 2972 insertions(+), 7 deletions(-) create mode 100644 driver-avalon8.c create mode 100644 driver-avalon8.h diff --git a/Makefile.am b/Makefile.am index 88b9ef6d40..42bf4fde4c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -165,6 +165,10 @@ if HAS_AVALON7 cgminer_SOURCES += driver-avalon7.c driver-avalon7.h endif +if HAS_AVALON8 +cgminer_SOURCES += driver-avalon8.c driver-avalon8.h +endif + if NEED_I2C_CONTEXT cgminer_SOURCES += i2c-context.c endif diff --git a/api.c b/api.c index d5d3a5afd2..c58dfdf7f4 100644 --- a/api.c +++ b/api.c @@ -32,7 +32,7 @@ defined(USE_MINION) || defined(USE_COINTERRA) || defined(USE_BITMINE_A1) || \ defined(USE_ANT_S1) || defined(USE_ANT_S2) || defined(USE_ANT_S3) || defined(USE_SP10) || \ defined(USE_SP30) || defined(USE_ICARUS) || defined(USE_HASHRATIO) || defined(USE_AVALON_MINER) || \ - defined(USE_AVALON7) + defined(USE_AVALON7) || defined(USE_AVALON8) #define HAVE_AN_ASIC 1 #endif diff --git a/cgminer.c b/cgminer.c index 54e8e3948d..1d9fa445ea 100644 --- a/cgminer.c +++ b/cgminer.c @@ -87,6 +87,10 @@ char *curly = ":D"; #include "libssplus.h" #endif +#ifdef USE_AVALON8 +#include "driver-avalon8.h" +#endif + #ifdef USE_AVALON_MINER #include "driver-avalon-miner.h" #endif @@ -269,6 +273,13 @@ static char *opt_set_avalon7_voltage_level; static char *opt_set_avalon7_voltage_offset; static char *opt_set_avalon7_freq; #endif +#ifdef USE_AVALON8 +static char *opt_set_avalon8_fan; +static char *opt_set_avalon8_voltage; +static char *opt_set_avalon8_voltage_level; +static char *opt_set_avalon8_voltage_offset; +static char *opt_set_avalon8_freq; +#endif #ifdef USE_AVALON_MINER static char *opt_set_avalonm_voltage; static char *opt_set_avalonm_freq; @@ -835,6 +846,13 @@ static char *set_int_1_to_65535(const char *arg, int *i) return set_int_range(arg, i, 1, 65535); } +#ifdef USE_AVALON8 +static char *set_int_0_to_3(const char *arg, int *i) +{ + return set_int_range(arg, i, 0, 3); +} +#endif + static char *set_int_0_to_5(const char *arg, int *i) { return set_int_range(arg, i, 0, 5); @@ -1481,6 +1499,62 @@ static struct opt_table opt_config_table[] = { opt_set_bool, &opt_avalon7_ssplus_enable, "Enable avalon7 smart speed plus."), #endif +#ifdef USE_AVALON8 + OPT_WITH_CBARG("--avalon8-voltage", + set_avalon8_voltage, NULL, &opt_set_avalon8_voltage, + "Set Avalon8 default core voltage, in millivolts, step: 78"), + OPT_WITH_CBARG("--avalon8-voltage-level", + set_avalon8_voltage_level, NULL, &opt_set_avalon8_voltage_level, + "Set Avalon8 default level of core voltage, range:[0, 15], step: 1"), + OPT_WITH_CBARG("--avalon8-voltage-offset", + set_avalon8_voltage_offset, NULL, &opt_set_avalon8_voltage_offset, + "Set Avalon8 default offset of core voltage, range:[-2, 1], step: 1"), + OPT_WITH_CBARG("--avalon8-freq", + set_avalon8_freq, NULL, &opt_set_avalon8_freq, + "Set Avalon8 default frequency, range:[24, 1404], step: 12, example: 500"), + OPT_WITH_ARG("--avalon8-freq-sel", + set_int_0_to_3, opt_show_intval, &opt_avalon8_freq_sel, + "Set Avalon8 default frequency select, range:[0, 3], step: 1, example: 3"), + OPT_WITH_CBARG("--avalon8-fan", + set_avalon8_fan, NULL, &opt_set_avalon8_fan, + "Set Avalon8 target fan speed, range:[0, 100], step: 1, example: 0-100"), + OPT_WITH_ARG("--avalon8-temp", + set_int_0_to_100, opt_show_intval, &opt_avalon8_temp_target, + "Set Avalon8 target temperature, range:[0, 100]"), + OPT_WITH_ARG("--avalon8-polling-delay", + set_int_1_to_65535, opt_show_intval, &opt_avalon8_polling_delay, + "Set Avalon8 polling delay value (ms)"), + OPT_WITH_ARG("--avalon8-aucspeed", + opt_set_intval, opt_show_intval, &opt_avalon8_aucspeed, + "Set AUC3 IIC bus speed"), + OPT_WITH_ARG("--avalon8-aucxdelay", + opt_set_intval, opt_show_intval, &opt_avalon8_aucxdelay, + "Set AUC3 IIC xfer read delay, 4800 ~= 1ms"), + OPT_WITH_ARG("--avalon8-smart-speed", + opt_set_intval, opt_show_intval, &opt_avalon8_smart_speed, + "Set Avalon8 smart speed, range 0-1. 0 means Disable"), + OPT_WITH_ARG("--avalon8-th-pass", + set_int_0_to_65535, opt_show_intval, &opt_avalon8_th_pass, + "Set A3210 th pass value"), + OPT_WITH_ARG("--avalon8-th-fail", + set_int_0_to_65535, opt_show_intval, &opt_avalon8_th_fail, + "Set A3210 th fail value"), + OPT_WITH_ARG("--avalon8-th-init", + set_int_0_to_65535, opt_show_intval, &opt_avalon8_th_init, + "Set A3210 th init value"), + OPT_WITH_ARG("--avalon8-th-ms", + set_int_0_to_65535, opt_show_intval, &opt_avalon8_th_ms, + "Set A3210 th ms value"), + OPT_WITH_ARG("--avalon8-th-timeout", + opt_set_uintval, opt_show_uintval, &opt_avalon8_th_timeout, + "Set A3210 th timeout value"), + OPT_WITHOUT_ARG("--avalon8-iic-detect", + opt_set_bool, &opt_avalon8_iic_detect, + "Enable Avalon8 detect through iic controller"), + OPT_WITH_ARG("--avalon8-nonce-mask", + set_int_24_to_32, opt_show_intval, &opt_avalon8_nonce_mask, + "Set A3210 nonce mask, range 24-32."), +#endif #ifdef USE_AVALON_MINER OPT_WITH_CBARG("--avalonm-voltage", set_avalonm_voltage, NULL, &opt_set_avalonm_voltage, @@ -2184,6 +2258,9 @@ static char *opt_verusage_and_exit(const char *extra) #ifdef USE_AVALON7 "avalon7 " #endif +#ifdef USE_AVALON8 + "avalon8 " +#endif #ifdef USE_AVALON_MINER "avalon miner" #endif @@ -7289,7 +7366,7 @@ void set_target(unsigned char *dest_target, double diff) cg_memcpy(dest_target, target, 32); } -#if defined (USE_AVALON2) || defined (USE_AVALON4) || defined (USE_AVALON7) || defined (USE_AVALON_MINER) || defined (USE_HASHRATIO) +#if defined (USE_AVALON2) || defined (USE_AVALON4) || defined (USE_AVALON7) || defined (USE_AVALON8) || defined (USE_AVALON_MINER) || defined (USE_HASHRATIO) bool submit_nonce2_nonce(struct thr_info *thr, struct pool *pool, struct pool *real_pool, uint32_t nonce2, uint32_t nonce, uint32_t ntime) { diff --git a/configure.ac b/configure.ac index 9010d9d347..ae1624022f 100644 --- a/configure.ac +++ b/configure.ac @@ -219,6 +219,17 @@ if test "x$avalon7" = xyes; then fi AM_CONDITIONAL([HAS_AVALON7], [test x$avalon7 = xyes]) +avalon8="no" + +AC_ARG_ENABLE([avalon8], + [AC_HELP_STRING([--enable-avalon8],[Compile support for Avalon8 (default disabled)])], + [avalon8=$enableval] + ) +if test "x$avalon8" = xyes; then + AC_DEFINE([USE_AVALON8], [1], [Defined to 1 if Avalon8 support is wanted]) +fi +AM_CONDITIONAL([HAS_AVALON8], [test x$avalon8 = xyes]) + avalon_miner="no" AC_ARG_ENABLE([avalon_miner], @@ -506,7 +517,7 @@ fi #Add a new device to this list if it needs libusb, along with a no on the end. -if test x$avalon$avalon2$avalon4$avalon7$avalon_miner$bitforce$bitfury$blockerupter$modminer$bflsc$icarus$hashfast$hashratio$klondike$drillbit$cointerra$ants1$ants3 != xnononononononononononononononononono; then +if test x$avalon$avalon2$avalon4$avalon7$avalon8$avalon_miner$bitforce$bitfury$blockerupter$modminer$bflsc$icarus$hashfast$hashratio$klondike$drillbit$cointerra$ants1$ants3 != xnonononononononononononononononononono; then want_usbutils=true else want_usbutils=false @@ -518,7 +529,7 @@ else want_libbitfury=false fi -if test x$avalon2$avalon4$avalon7$avalon_miner$hashratio != xnonononono; then +if test x$avalon2$avalon4$avalon7$avalon8$avalon_miner$hashratio != xnononononono; then want_crc16=true else want_crc16=false @@ -531,7 +542,7 @@ AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes]) AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue]) AM_CONDITIONAL([HAVE_x86_64], [test x$have_x86_64 = xtrue]) AM_CONDITIONAL([WANT_CRC16], [test x$want_crc16 != xfalse]) -AM_CONDITIONAL([NEED_I2C_CONTEXT], [test x$avalon4$avalon7 != xnono]) +AM_CONDITIONAL([NEED_I2C_CONTEXT], [test x$avalon4$avalon7$avalon8 != xnonono]) AM_CONDITIONAL([SUPPORT_SSP], [test x$avalon7 != xno]) if test "x$want_usbutils" != xfalse; then @@ -764,6 +775,12 @@ else echo " Avalon7.ASICs........: Disabled" fi +if test "x$avalon8" = xyes; then + echo " Avalon8.ASICs........: Enabled" +else + echo " Avalon8.ASICs........: Disabled" +fi + if test "x$avalon_miner" = xyes; then echo " Avalon miner.ASICs...: Enabled" else @@ -881,7 +898,7 @@ else fi #Add any new device to this, along with a no on the end of the test -if test "x$avalon$avalon2$avalon4$avalon7$avalon_miner$bab$bflsc$bitforce$bitfury$bitfury16$blockerupter$hashfast$hashratio$icarus$klondike$knc$modminer$drillbit$minion$cointerra$bitmine_A1$ants1$ants2$ants3$sp10$sp30" = xnononononononononononononononononononononononononono; then +if test "x$avalon$avalon2$avalon4$avalon7$avalon8$avalon_miner$bab$bflsc$bitforce$bitfury$bitfury16$blockerupter$hashfast$hashratio$icarus$klondike$knc$modminer$drillbit$minion$cointerra$bitmine_A1$ants1$ants2$ants3$sp10$sp30" = xnonononononononononononononononononononononononononono; then echo AC_MSG_ERROR([No mining devices configured in]) echo diff --git a/driver-avalon8.c b/driver-avalon8.c new file mode 100644 index 0000000000..cbb9442ac8 --- /dev/null +++ b/driver-avalon8.c @@ -0,0 +1,2527 @@ +/* + * Copyright 2017 xuzhenxing + * Copyright 2016-2017 Mikeqin + * Copyright 2016 Con Kolivas + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. See COPYING for more details. + */ +#include +#include "config.h" + +#include "miner.h" +#include "driver-avalon8.h" +#include "crc.h" +#include "sha2.h" +#include "hexdump.c" + +#define get_fan_pwm(v) (AVA8_PWM_MAX - (v) * AVA8_PWM_MAX / 100) + +int opt_avalon8_temp_target = AVA8_DEFAULT_TEMP_TARGET; + +int opt_avalon8_fan_min = AVA8_DEFAULT_FAN_MIN; +int opt_avalon8_fan_max = AVA8_DEFAULT_FAN_MAX; + +int opt_avalon8_voltage = AVA8_INVALID_VOLTAGE; +int opt_avalon8_voltage_offset = AVA8_DEFAULT_VOLTAGE_OFFSET; + +int opt_avalon8_freq[AVA8_DEFAULT_PLL_CNT] = {AVA8_DEFAULT_FREQUENCY_0, + AVA8_DEFAULT_FREQUENCY_1, + AVA8_DEFAULT_FREQUENCY_2, + AVA8_DEFAULT_FREQUENCY_3}; + +int opt_avalon8_freq_sel = AVA8_DEFAULT_FREQUENCY_SEL; + +int opt_avalon8_polling_delay = AVA8_DEFAULT_POLLING_DELAY; + +int opt_avalon8_aucspeed = AVA8_AUC_SPEED; +int opt_avalon8_aucxdelay = AVA8_AUC_XDELAY; + +int opt_avalon8_smart_speed = AVA8_DEFAULT_SMART_SPEED; +/* + * smart speed have 2 modes + * 1. auto speed by A3210 chips + * 2. option 1 + adjust by average frequency + */ +bool opt_avalon8_iic_detect = AVA8_DEFAULT_IIC_DETECT; + +uint32_t opt_avalon8_th_pass = AVA8_DEFAULT_TH_PASS; +uint32_t opt_avalon8_th_fail = AVA8_DEFAULT_TH_FAIL; +uint32_t opt_avalon8_th_init = AVA8_DEFAULT_TH_INIT; +uint32_t opt_avalon8_th_ms = AVA8_DEFAULT_TH_MS; +uint32_t opt_avalon8_th_timeout = AVA8_DEFAULT_TH_TIMEOUT; +uint32_t opt_avalon8_nonce_mask = AVA8_DEFAULT_NONCE_MASK; + +uint32_t cpm_table[] = +{ + 0x0173f813, + 0x0175f813, + 0x0163f813, + 0x0164f813, + 0x0165f813, + 0x0166f813, + 0x0153f813, + 0x01547813, + 0x0154f813, + 0x01557813, + 0x0155f813, + 0x01567813, + 0x0156f813, + 0x01577813, + 0x0143f813, + 0x01443813, + 0x01447813, + 0x0144b813, + 0x0144f813, + 0x01453813, + 0x01457813, + 0x0145b813, + 0x0145f813, + 0x01463813, + 0x01467813, + 0x0146b813, + 0x0146f813, + 0x01473813, + 0x01477813, + 0x0147b813, + 0x0133f813, + 0x01341813, + 0x01343813, + 0x01345813, + 0x01347813, + 0x01349813, + 0x0134b813, + 0x0134d813, + 0x0134f813, + 0x01351813, + 0x01353813, + 0x01355813, + 0x01357813, + 0x01359813, + 0x0135b813, + 0x0135d813, + 0x0135f813, + 0x01361813, + 0x01363813, + 0x01365813, + 0x01367813, + 0x01369813, + 0x0136b813, + 0x0136d813, + 0x0136f813, + 0x01371813, + 0x01373813, + 0x01375813, + 0x01377813, + 0x01379813, + 0x0137b813, + 0x0123e813, + 0x0123f813, + 0x01240813, + 0x01241813, + 0x01242813, + 0x01243813, + 0x01244813, + 0x01245813, + 0x01246813, + 0x01247813, + 0x01248813, + 0x01249813, + 0x0124a813, + 0x0124b813, + 0x0124c813, + 0x0124d813, + 0x0124e813, + 0x0124f813, + 0x01250813, + 0x01251813, + 0x01252813, + 0x01253813, + 0x01254813, + 0x01255813, + 0x01256813, + 0x01257813, + 0x01258813, + 0x01259813, + 0x0125a813, + 0x0125b813, + 0x0125c813, + 0x0125d813, + 0x0125e813, + 0x0125f813, + 0x01260813, + 0x01261813, + 0x01262813, + 0x01263813, + 0x01264813, + 0x01265813, + 0x01266813, + 0x01267813, + 0x01268813, + 0x01269813, + 0x0126a813, + 0x0126b813, + 0x0126c813, + 0x0126d813, + 0x0126e813, + 0x0126f813, + 0x01270813, + 0x01271813, + 0x01272813, + 0x01273813, + 0x01274813, +}; + +struct avalon8_dev_description avalon8_dev_table[] = { + { + "821", + 821, + 4, + 26, + AVA8_MM821_VIN_ADC_RATIO, + AVA8_MM821_VOUT_ADC_RATIO, + 4825, + } +}; + +static uint32_t api_get_cpm(uint32_t freq) +{ + return cpm_table[freq / 12 - 2]; +} + +static uint32_t encode_voltage(uint32_t volt) +{ + if (volt > AVA8_DEFAULT_VOLTAGE_MAX) + volt = AVA8_DEFAULT_VOLTAGE_MAX; + + if (volt < AVA8_DEFAULT_VOLTAGE_MIN) + volt = AVA8_DEFAULT_VOLTAGE_MIN; + + return 0x8000 | ((volt - AVA8_DEFAULT_VOLTAGE_MIN) / AVA8_DEFAULT_VOLTAGE_STEP); +} + +static uint32_t convert_voltage_level(uint32_t level) +{ + if (level > AVA8_DEFAULT_VOLTAGE_LEVEL_MAX) + level = AVA8_DEFAULT_VOLTAGE_LEVEL_MAX; + + return AVA8_DEFAULT_VOLTAGE_MIN + level * AVA8_DEFAULT_VOLTAGE_STEP; +} + +static uint32_t decode_voltage(struct avalon8_info *info, int modular_id, uint32_t volt) +{ + return (volt * info->vout_adc_ratio[modular_id] / info->asic_count[modular_id] / 100); +} + +static uint16_t decode_vin(struct avalon8_info *info, int modular_id, uint16_t volt) +{ + return (volt * info->vin_adc_ratio[modular_id] / 1000); +} + +static double decode_pvt_temp(uint16_t pvt_code) +{ + double a4 = -1.1876E-11; + double a3 = 6.6675E-08; + double a2 = -1.7724E-04; + double a1 = 3.3691E-01; + double a0 = -6.0605E+01; + + return a4 * pow(pvt_code, 4) + a3 * pow(pvt_code, 3) + a2 * pow(pvt_code, 2) + a1 * pow(pvt_code, 1) + a0; +} + +#define SERIESRESISTOR 10000 +#define THERMISTORNOMINAL 10000 +#define BCOEFFICIENT 3500 +#define TEMPERATURENOMINAL 25 +float decode_auc_temp(int value) +{ + float ret, resistance; + + if (!((value > 0) && (value < 33000))) + return -273; + + resistance = (3.3 * 10000 / value) - 1; + resistance = SERIESRESISTOR / resistance; + ret = resistance / THERMISTORNOMINAL; + ret = logf(ret); + ret /= BCOEFFICIENT; + ret += 1.0 / (TEMPERATURENOMINAL + 273.15); + ret = 1.0 / ret; + ret -= 273.15; + + return ret; +} + +#define UNPACK32(x, str) \ +{ \ + *((str) + 3) = (uint8_t) ((x) ); \ + *((str) + 2) = (uint8_t) ((x) >> 8); \ + *((str) + 1) = (uint8_t) ((x) >> 16); \ + *((str) + 0) = (uint8_t) ((x) >> 24); \ +} + +static inline void sha256_prehash(const unsigned char *message, unsigned int len, unsigned char *digest) +{ + int i; + sha256_ctx ctx; + + sha256_init(&ctx); + sha256_update(&ctx, message, len); + + for (i = 0; i < 8; i++) + UNPACK32(ctx.h[i], &digest[i << 2]); +} + +char *set_avalon8_fan(char *arg) +{ + int val1, val2, ret; + + ret = sscanf(arg, "%d-%d", &val1, &val2); + if (ret < 1) + return "No value passed to avalon8-fan"; + if (ret == 1) + val2 = val1; + + if (val1 < 0 || val1 > 100 || val2 < 0 || val2 > 100 || val2 < val1) + return "Invalid value passed to avalon8-fan"; + + opt_avalon8_fan_min = val1; + opt_avalon8_fan_max = val2; + + return NULL; +} + +char *set_avalon8_freq(char *arg) +{ + int val[AVA8_DEFAULT_PLL_CNT]; + char *colon, *data; + int i; + + if (!(*arg)) + return NULL; + + data = arg; + memset(val, 0, sizeof(val)); + + for (i = 0; i < AVA8_DEFAULT_PLL_CNT; i++) { + colon = strchr(data, ':'); + if (colon) + *(colon++) = '\0'; + else { + /* last value */ + if (*data) { + val[i] = atoi(data); + if (val[i] < AVA8_DEFAULT_FREQUENCY_MIN || val[i] > AVA8_DEFAULT_FREQUENCY_MAX) + return "Invalid value passed to avalon8-freq"; + } + break; + } + + if (*data) { + val[i] = atoi(data); + if (val[i] < AVA8_DEFAULT_FREQUENCY_MIN || val[i] > AVA8_DEFAULT_FREQUENCY_MAX) + return "Invalid value passed to avalon8-freq"; + } + data = colon; + } + + for (i = 0; i < AVA8_DEFAULT_PLL_CNT; i++) { + if (!val[i] && i) + val[i] = val[i - 1]; + opt_avalon8_freq[i] = val[i]; + } + + return NULL; +} + +char *set_avalon8_voltage(char *arg) +{ + int val, ret; + + ret = sscanf(arg, "%d", &val); + if (ret < 1) + return "No value passed to avalon8-voltage"; + + if (val < AVA8_DEFAULT_VOLTAGE_MIN || val > AVA8_DEFAULT_VOLTAGE_MAX) + return "Invalid value passed to avalon8-voltage"; + + opt_avalon8_voltage = val; + + return NULL; +} + +char *set_avalon8_voltage_level(char *arg) +{ + int val, ret; + + ret = sscanf(arg, "%d", &val); + if (ret < 1) + return "No value passed to avalon8-voltage-level"; + + if (val < AVA8_DEFAULT_VOLTAGE_LEVEL_MIN || val > AVA8_DEFAULT_VOLTAGE_LEVEL_MAX) + return "Invalid value passed to avalon8-voltage-level"; + + opt_avalon8_voltage = convert_voltage_level(val); + + return NULL; +} + +char *set_avalon8_voltage_offset(char *arg) +{ + int val, ret; + + ret = sscanf(arg, "%d", &val); + if (ret < 1) + return "No value passed to avalon8-voltage-offset"; + + if (val < AVA8_DEFAULT_VOLTAGE_OFFSET_MIN || val > AVA8_DEFAULT_VOLTAGE_OFFSET_MAX) + return "Invalid value passed to avalon8-voltage-offset"; + + opt_avalon8_voltage_offset = val; + + return NULL; +} + +static int avalon8_init_pkg(struct avalon8_pkg *pkg, uint8_t type, uint8_t idx, uint8_t cnt) +{ + unsigned short crc; + + pkg->head[0] = AVA8_H1; + pkg->head[1] = AVA8_H2; + + pkg->type = type; + pkg->opt = 0; + pkg->idx = idx; + pkg->cnt = cnt; + + crc = crc16(pkg->data, AVA8_P_DATA_LEN); + + pkg->crc[0] = (crc & 0xff00) >> 8; + pkg->crc[1] = crc & 0xff; + + return 0; +} + +static int job_idcmp(uint8_t *job_id, char *pool_job_id) +{ + int job_id_len; + unsigned short crc, crc_expect; + + if (!pool_job_id) + return 1; + + job_id_len = strlen(pool_job_id); + crc_expect = crc16((unsigned char *)pool_job_id, job_id_len); + + crc = job_id[0] << 8 | job_id[1]; + + if (crc_expect == crc) + return 0; + + applog(LOG_DEBUG, "avalon8: job_id doesn't match! [%04x:%04x (%s)]", + crc, crc_expect, pool_job_id); + + return 1; +} + +static inline int get_temp_max(struct avalon8_info *info, int addr) +{ + int i; + int max = -273; + + for (i = 0; i < info->miner_count[addr]; i++) { + if (info->temp[addr][i][3] > max) + max = info->temp[addr][i][3]; + } + + if (max < info->temp_mm[addr]) + max = info->temp_mm[addr]; + + return max; +} + +/* Use a PID-like feedback mechanism for optimal temperature and fan speed */ +static inline uint32_t adjust_fan(struct avalon8_info *info, int id) +{ + int t, tdiff, delta; + uint32_t pwm; + time_t now_t; + + now_t = time(NULL); + t = get_temp_max(info, id); + tdiff = t - info->temp_last_max[id]; + if (!tdiff && now_t < info->last_temp_time[id] + AVA8_DEFAULT_FAN_INTERVAL) + goto out; + info->last_temp_time[id] = now_t; + delta = t - info->temp_target[id]; + + /* Check for init value and ignore it */ + if (unlikely(info->temp_last_max[id] == -273)) + tdiff = 0; + info->temp_last_max[id] = t; + + if (t >= info->temp_overheat[id]) { + /* Hit the overheat temperature limit */ + if (info->fan_pct[id] < opt_avalon8_fan_max) { + applog(LOG_WARNING, "Overheat detected on AV8-%d, increasing fan to max", id); + info->fan_pct[id] = opt_avalon8_fan_max; + } + } else if (delta > 0) { + /* Over target temperature. */ + + /* Is the temp already coming down */ + if (tdiff < 0) + goto out; + /* Adjust fanspeed by temperature over and any further rise */ + info->fan_pct[id] += delta + tdiff; + } else { + /* Below target temperature */ + int diff = tdiff; + + if (tdiff > 0) { + int divisor = -delta / AVA8_DEFAULT_TEMP_HYSTERESIS + 1; + + /* Adjust fanspeed by temperature change proportional to + * diff from optimal. */ + diff /= divisor; + } else { + /* Is the temp below optimal and unchanging, gently lower speed */ + if (t < info->temp_target[id] - AVA8_DEFAULT_TEMP_HYSTERESIS && !tdiff) + diff -= 1; + } + info->fan_pct[id] += diff; + } + + if (info->fan_pct[id] > opt_avalon8_fan_max) + info->fan_pct[id] = opt_avalon8_fan_max; + else if (info->fan_pct[id] < opt_avalon8_fan_min) + info->fan_pct[id] = opt_avalon8_fan_min; +out: + pwm = get_fan_pwm(info->fan_pct[id]); + + if (info->cutoff[id]) + pwm = get_fan_pwm(opt_avalon8_fan_max); + + applog(LOG_DEBUG, "[%d], Adjust_fan: %dC-%d%%(%03x)", id, t, info->fan_pct[id], pwm); + + return pwm; +} + +static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int modular_id) +{ + struct avalon8_info *info = avalon8->device_data; + struct pool *pool, *real_pool; + struct pool *pool_stratum0 = &info->pool0; + struct pool *pool_stratum1 = &info->pool1; + struct pool *pool_stratum2 = &info->pool2; + struct thr_info *thr = NULL; + + unsigned short expected_crc; + unsigned short actual_crc; + uint32_t nonce, nonce2, ntime, miner, chip_id, tmp; + uint8_t job_id[2]; + int pool_no; + uint32_t i; + int64_t last_diff1; + uint16_t vin; + + if (likely(avalon8->thr)) + thr = avalon8->thr[0]; + if (ar->head[0] != AVA8_H1 && ar->head[1] != AVA8_H2) { + applog(LOG_DEBUG, "%s-%d-%d: H1 %02x, H2 %02x", + avalon8->drv->name, avalon8->device_id, modular_id, + ar->head[0], ar->head[1]); + hexdump(ar->data, 32); + return 1; + } + + expected_crc = crc16(ar->data, AVA8_P_DATA_LEN); + actual_crc = ((ar->crc[0] & 0xff) << 8) | (ar->crc[1] & 0xff); + if (expected_crc != actual_crc) { + applog(LOG_DEBUG, "%s-%d-%d: %02x: expected crc(%04x), actual_crc(%04x)", + avalon8->drv->name, avalon8->device_id, modular_id, + ar->type, expected_crc, actual_crc); + return 1; + } + + switch(ar->type) { + case AVA8_P_NONCE: + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_NONCE", avalon8->drv->name, avalon8->device_id, modular_id); + memcpy(&miner, ar->data + 0, 4); + memcpy(&nonce2, ar->data + 4, 4); + memcpy(&ntime, ar->data + 8, 4); + memcpy(&nonce, ar->data + 12, 4); + job_id[0] = ar->data[16]; + job_id[1] = ar->data[17]; + pool_no = (ar->data[18] | (ar->data[19] << 8)); + + miner = be32toh(miner); + chip_id = (miner >> 16) & 0xffff; + miner &= 0xffff; + ntime = be32toh(ntime); + if (miner >= info->miner_count[modular_id] || + pool_no >= total_pools || pool_no < 0) { + applog(LOG_DEBUG, "%s-%d-%d: Wrong miner/pool_no %d/%d", + avalon8->drv->name, avalon8->device_id, modular_id, + miner, pool_no); + break; + } + nonce2 = be32toh(nonce2); + nonce = be32toh(nonce); + + if (ntime > info->max_ntime) + info->max_ntime = ntime; + + applog(LOG_NOTICE, "%s-%d-%d: Found! P:%d - N2:%08x N:%08x NR:%d/%d [M:%d, A:%d, C:%d - MW: (%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64")]", + avalon8->drv->name, avalon8->device_id, modular_id, + pool_no, nonce2, nonce, ntime, info->max_ntime, + miner, chip_id, nonce & 0x7f, + info->chip_matching_work[modular_id][miner][0], + info->chip_matching_work[modular_id][miner][1], + info->chip_matching_work[modular_id][miner][2], + info->chip_matching_work[modular_id][miner][3]); + + real_pool = pool = pools[pool_no]; + if (job_idcmp(job_id, pool->swork.job_id)) { + if (!job_idcmp(job_id, pool_stratum0->swork.job_id)) { + applog(LOG_DEBUG, "%s-%d-%d: Match to previous stratum0! (%s)", + avalon8->drv->name, avalon8->device_id, modular_id, + pool_stratum0->swork.job_id); + pool = pool_stratum0; + } else if (!job_idcmp(job_id, pool_stratum1->swork.job_id)) { + applog(LOG_DEBUG, "%s-%d-%d: Match to previous stratum1! (%s)", + avalon8->drv->name, avalon8->device_id, modular_id, + pool_stratum1->swork.job_id); + pool = pool_stratum1; + } else if (!job_idcmp(job_id, pool_stratum2->swork.job_id)) { + applog(LOG_DEBUG, "%s-%d-%d: Match to previous stratum2! (%s)", + avalon8->drv->name, avalon8->device_id, modular_id, + pool_stratum2->swork.job_id); + pool = pool_stratum2; + } else { + applog(LOG_ERR, "%s-%d-%d: Cannot match to any stratum! (%s)", + avalon8->drv->name, avalon8->device_id, modular_id, + pool->swork.job_id); + if (likely(thr)) + inc_hw_errors(thr); + info->hw_works_i[modular_id][miner]++; + break; + } + } + + /* Can happen during init sequence before add_cgpu */ + if (unlikely(!thr)) + break; + + last_diff1 = avalon8->diff1; + if (!submit_nonce2_nonce(thr, pool, real_pool, nonce2, nonce, ntime)) + info->hw_works_i[modular_id][miner]++; + else { + info->diff1[modular_id] += (avalon8->diff1 - last_diff1); + info->chip_matching_work[modular_id][miner][chip_id]++; + } + break; + case AVA8_P_STATUS: + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS", avalon8->drv->name, avalon8->device_id, modular_id); + hexdump(ar->data, 32); + memcpy(&tmp, ar->data, 4); + tmp = be32toh(tmp); + info->temp_mm[modular_id] = tmp; + avalon8->temp = decode_auc_temp(info->auc_sensor); + + memcpy(&tmp, ar->data + 4, 4); + tmp = be32toh(tmp); + info->fan_cpm[modular_id] = tmp; + + memcpy(&tmp, ar->data + 8, 4); + info->local_works_i[modular_id][ar->idx] += be32toh(tmp); + + memcpy(&tmp, ar->data + 12, 4); + info->hw_works_i[modular_id][ar->idx] += be32toh(tmp); + + memcpy(&tmp, ar->data + 16, 4); + info->error_code[modular_id][ar->idx] = be32toh(tmp); + + memcpy(&tmp, ar->data + 20, 4); + info->error_code[modular_id][ar->cnt] = be32toh(tmp); + + memcpy(&tmp, ar->data + 24, 4); + info->error_crc[modular_id][ar->idx] += be32toh(tmp); + break; + case AVA8_P_STATUS_PMU: + /* TODO: decode ntc led from PMU */ + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_PMU", avalon8->drv->name, avalon8->device_id, modular_id); + info->power_good[modular_id] = ar->data[16]; + for (i = 0; i < AVA8_DEFAULT_PMU_CNT; i++) { + memcpy(&info->pmu_version[modular_id][i], ar->data + 24 + (i * 4), 4); + info->pmu_version[modular_id][i][4] = '\0'; + } + + for (i = 0; i < info->miner_count[modular_id]; i++) { + memcpy(&vin, ar->data + 8 + i * 2, 2); + info->get_vin[modular_id][i] = decode_vin(info, modular_id, be16toh(vin)); + } + break; + case AVA8_P_STATUS_VOLT: + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_VOLT", avalon8->drv->name, avalon8->device_id, modular_id); + for (i = 0; i < info->miner_count[modular_id]; i++) { + memcpy(&tmp, ar->data + i * 4, 4); + info->get_voltage[modular_id][i] = decode_voltage(info, modular_id, be32toh(tmp)); + } + break; + case AVA8_P_STATUS_PLL: + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_PLL", avalon8->drv->name, avalon8->device_id, modular_id); + for (i = 0; i < AVA8_DEFAULT_PLL_CNT; i++) { + memcpy(&tmp, ar->data + i * 4, 4); + info->get_pll[modular_id][ar->idx][i] = be32toh(tmp); + } + break; + case AVA8_P_STATUS_PVT: + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_PVT", avalon8->drv->name, avalon8->device_id, modular_id); + for (i = 0; i < info->miner_count[modular_id]; i++) { + memcpy(&tmp, ar->data + i * 8, 4); + tmp = be32toh(tmp); + info->temp[modular_id][i][0] = (tmp >> 24) & 0xff; + info->temp[modular_id][i][1] = (tmp >> 16) & 0xff; + info->temp[modular_id][i][2] = tmp & 0xffff; + + memcpy(&tmp, ar->data + (i + 1) * 8 - 4, 4); + tmp = be32toh(tmp); + info->temp[modular_id][i][3] = (tmp >> 16) & 0xffff; + info->temp[modular_id][i][4] = tmp & 0xffff; + + /* Update the pvt code to real temperature */ + info->temp[modular_id][i][2] = (int)decode_pvt_temp((uint16_t)info->temp[modular_id][i][2]); + info->temp[modular_id][i][3] = (int)decode_pvt_temp((uint16_t)info->temp[modular_id][i][3]); + info->temp[modular_id][i][4] = (int)decode_pvt_temp((uint16_t)info->temp[modular_id][i][4]); + } + break; + case AVA8_P_STATUS_FAC: + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_FAC", avalon8->drv->name, avalon8->device_id, modular_id); + info->factory_info[0] = ar->data[0]; + break; + default: + applog(LOG_DEBUG, "%s-%d-%d: Unknown response %x", avalon8->drv->name, avalon8->device_id, modular_id, ar->type); + break; + } + return 0; +} + +/* + # IIC packet format: length[1]+transId[1]+sesId[1]+req[1]+data[60] + # length: 4+len(data) + # transId: 0 + # sesId: 0 + # req: checkout the header file + # data: + # INIT: clock_rate[4] + reserved[4] + payload[52] + # XFER: txSz[1]+rxSz[1]+options[1]+slaveAddr[1] + payload[56] + */ +static int avalon8_auc_init_pkg(uint8_t *iic_pkg, struct avalon8_iic_info *iic_info, uint8_t *buf, int wlen, int rlen) +{ + memset(iic_pkg, 0, AVA8_AUC_P_SIZE); + + switch (iic_info->iic_op) { + case AVA8_IIC_INIT: + iic_pkg[0] = 12; /* 4 bytes IIC header + 4 bytes speed + 4 bytes xfer delay */ + iic_pkg[3] = AVA8_IIC_INIT; + iic_pkg[4] = iic_info->iic_param.aucParam[0] & 0xff; + iic_pkg[5] = (iic_info->iic_param.aucParam[0] >> 8) & 0xff; + iic_pkg[6] = (iic_info->iic_param.aucParam[0] >> 16) & 0xff; + iic_pkg[7] = iic_info->iic_param.aucParam[0] >> 24; + iic_pkg[8] = iic_info->iic_param.aucParam[1] & 0xff; + iic_pkg[9] = (iic_info->iic_param.aucParam[1] >> 8) & 0xff; + iic_pkg[10] = (iic_info->iic_param.aucParam[1] >> 16) & 0xff; + iic_pkg[11] = iic_info->iic_param.aucParam[1] >> 24; + break; + case AVA8_IIC_XFER: + iic_pkg[0] = 8 + wlen; + iic_pkg[3] = AVA8_IIC_XFER; + iic_pkg[4] = wlen; + iic_pkg[5] = rlen; + iic_pkg[7] = iic_info->iic_param.slave_addr; + if (buf && wlen) + memcpy(iic_pkg + 8, buf, wlen); + break; + case AVA8_IIC_RESET: + case AVA8_IIC_DEINIT: + case AVA8_IIC_INFO: + iic_pkg[0] = 4; + iic_pkg[3] = iic_info->iic_op; + break; + + default: + break; + } + + return 0; +} + +static int avalon8_iic_xfer(struct cgpu_info *avalon8, uint8_t slave_addr, + uint8_t *wbuf, int wlen, + uint8_t *rbuf, int rlen) +{ + struct avalon8_info *info = avalon8->device_data; + struct i2c_ctx *pctx = NULL; + int err = 1; + bool ret = false; + + pctx = info->i2c_slaves[slave_addr]; + if (!pctx) { + applog(LOG_ERR, "%s-%d: IIC xfer i2c slaves null!", avalon8->drv->name, avalon8->device_id); + goto out; + } + + if (wbuf) { + ret = pctx->write_raw(pctx, wbuf, wlen); + if (!ret) { + applog(LOG_DEBUG, "%s-%d: IIC xfer write raw failed!", avalon8->drv->name, avalon8->device_id); + goto out; + } + } + + cgsleep_ms(5); + + if (rbuf) { + ret = pctx->read_raw(pctx, rbuf, rlen); + if (!ret) { + applog(LOG_DEBUG, "%s-%d: IIC xfer read raw failed!", avalon8->drv->name, avalon8->device_id); + hexdump(rbuf, rlen); + goto out; + } + } + + return 0; +out: + return err; +} + +static int avalon8_auc_xfer(struct cgpu_info *avalon8, + uint8_t *wbuf, int wlen, int *write, + uint8_t *rbuf, int rlen, int *read) +{ + int err = -1; + + if (unlikely(avalon8->usbinfo.nodev)) + goto out; + + usb_buffer_clear(avalon8); + err = usb_write(avalon8, (char *)wbuf, wlen, write, C_AVA8_WRITE); + if (err || *write != wlen) { + applog(LOG_DEBUG, "%s-%d: AUC xfer %d, w(%d-%d)!", avalon8->drv->name, avalon8->device_id, err, wlen, *write); + usb_nodev(avalon8); + goto out; + } + + cgsleep_ms(opt_avalon8_aucxdelay / 4800 + 1); + + rlen += 4; /* Add 4 bytes IIC header */ + err = usb_read(avalon8, (char *)rbuf, rlen, read, C_AVA8_READ); + if (err || *read != rlen || *read != rbuf[0]) { + applog(LOG_DEBUG, "%s-%d: AUC xfer %d, r(%d-%d-%d)!", avalon8->drv->name, avalon8->device_id, err, rlen - 4, *read, rbuf[0]); + hexdump(rbuf, rlen); + return -1; + } + *read = rbuf[0] - 4; /* Remove 4 bytes IIC header */ +out: + return err; +} + +static int avalon8_auc_init(struct cgpu_info *avalon8, char *ver) +{ + struct avalon8_iic_info iic_info; + int err, wlen, rlen; + uint8_t wbuf[AVA8_AUC_P_SIZE]; + uint8_t rbuf[AVA8_AUC_P_SIZE]; + + if (unlikely(avalon8->usbinfo.nodev)) + return 1; + + /* Try to clean the AUC buffer */ + usb_buffer_clear(avalon8); + err = usb_read(avalon8, (char *)rbuf, AVA8_AUC_P_SIZE, &rlen, C_AVA8_READ); + applog(LOG_DEBUG, "%s-%d: AUC usb_read %d, %d!", avalon8->drv->name, avalon8->device_id, err, rlen); + hexdump(rbuf, AVA8_AUC_P_SIZE); + + /* Reset */ + iic_info.iic_op = AVA8_IIC_RESET; + rlen = 0; + avalon8_auc_init_pkg(wbuf, &iic_info, NULL, 0, rlen); + + memset(rbuf, 0, AVA8_AUC_P_SIZE); + err = avalon8_auc_xfer(avalon8, wbuf, AVA8_AUC_P_SIZE, &wlen, rbuf, rlen, &rlen); + if (err) { + applog(LOG_ERR, "%s-%d: Failed to reset Avalon USB2IIC Converter", avalon8->drv->name, avalon8->device_id); + return 1; + } + + /* Deinit */ + iic_info.iic_op = AVA8_IIC_DEINIT; + rlen = 0; + avalon8_auc_init_pkg(wbuf, &iic_info, NULL, 0, rlen); + + memset(rbuf, 0, AVA8_AUC_P_SIZE); + err = avalon8_auc_xfer(avalon8, wbuf, AVA8_AUC_P_SIZE, &wlen, rbuf, rlen, &rlen); + if (err) { + applog(LOG_ERR, "%s-%d: Failed to deinit Avalon USB2IIC Converter", avalon8->drv->name, avalon8->device_id); + return 1; + } + + /* Init */ + iic_info.iic_op = AVA8_IIC_INIT; + iic_info.iic_param.aucParam[0] = opt_avalon8_aucspeed; + iic_info.iic_param.aucParam[1] = opt_avalon8_aucxdelay; + rlen = AVA8_AUC_VER_LEN; + avalon8_auc_init_pkg(wbuf, &iic_info, NULL, 0, rlen); + + memset(rbuf, 0, AVA8_AUC_P_SIZE); + err = avalon8_auc_xfer(avalon8, wbuf, AVA8_AUC_P_SIZE, &wlen, rbuf, rlen, &rlen); + if (err) { + applog(LOG_ERR, "%s-%d: Failed to init Avalon USB2IIC Converter", avalon8->drv->name, avalon8->device_id); + return 1; + } + + hexdump(rbuf, AVA8_AUC_P_SIZE); + + memcpy(ver, rbuf + 4, AVA8_AUC_VER_LEN); + ver[AVA8_AUC_VER_LEN] = '\0'; + + applog(LOG_DEBUG, "%s-%d: USB2IIC Converter version: %s!", avalon8->drv->name, avalon8->device_id, ver); + + return 0; +} + +static int avalon8_auc_getinfo(struct cgpu_info *avalon8) +{ + struct avalon8_iic_info iic_info; + int err, wlen, rlen; + uint8_t wbuf[AVA8_AUC_P_SIZE]; + uint8_t rbuf[AVA8_AUC_P_SIZE]; + uint8_t *pdata = rbuf + 4; + uint16_t adc_val; + struct avalon8_info *info = avalon8->device_data; + + iic_info.iic_op = AVA8_IIC_INFO; + /* + * Device info: (9 bytes) + * tempadc(2), reqRdIndex, reqWrIndex, + * respRdIndex, respWrIndex, tx_flags, state + */ + rlen = 7; + avalon8_auc_init_pkg(wbuf, &iic_info, NULL, 0, rlen); + + memset(rbuf, 0, AVA8_AUC_P_SIZE); + err = avalon8_auc_xfer(avalon8, wbuf, AVA8_AUC_P_SIZE, &wlen, rbuf, rlen, &rlen); + if (err) { + applog(LOG_ERR, "%s-%d: AUC Failed to get info ", avalon8->drv->name, avalon8->device_id); + return 1; + } + + applog(LOG_DEBUG, "%s-%d: AUC tempADC(%03d), reqcnt(%d), respcnt(%d), txflag(%d), state(%d)", + avalon8->drv->name, avalon8->device_id, + pdata[1] << 8 | pdata[0], + pdata[2], + pdata[3], + pdata[5] << 8 | pdata[4], + pdata[6]); + + adc_val = pdata[1] << 8 | pdata[0]; + + info->auc_sensor = 3.3 * adc_val * 10000 / 1023; + + return 0; +} + +static int avalon8_iic_xfer_pkg(struct cgpu_info *avalon8, uint8_t slave_addr, + const struct avalon8_pkg *pkg, struct avalon8_ret *ret) +{ + struct avalon8_iic_info iic_info; + int err, wcnt, rcnt, rlen = 0; + uint8_t wbuf[AVA8_AUC_P_SIZE]; + uint8_t rbuf[AVA8_AUC_P_SIZE]; + + struct avalon8_info *info = avalon8->device_data; + + if (ret) + rlen = AVA8_READ_SIZE; + + if (info->connecter == AVA8_CONNECTER_AUC) { + if (unlikely(avalon8->usbinfo.nodev)) + return AVA8_SEND_ERROR; + + iic_info.iic_op = AVA8_IIC_XFER; + iic_info.iic_param.slave_addr = slave_addr; + + avalon8_auc_init_pkg(wbuf, &iic_info, (uint8_t *)pkg, AVA8_WRITE_SIZE, rlen); + err = avalon8_auc_xfer(avalon8, wbuf, wbuf[0], &wcnt, rbuf, rlen, &rcnt); + if ((pkg->type != AVA8_P_DETECT) && err == -7 && !rcnt && rlen) { + avalon8_auc_init_pkg(wbuf, &iic_info, NULL, 0, rlen); + err = avalon8_auc_xfer(avalon8, wbuf, wbuf[0], &wcnt, rbuf, rlen, &rcnt); + applog(LOG_DEBUG, "%s-%d-%d: AUC read again!(type:0x%x, err:%d)", avalon8->drv->name, avalon8->device_id, slave_addr, pkg->type, err); + } + if (err || rcnt != rlen) { + if (info->xfer_err_cnt++ == 100) { + applog(LOG_DEBUG, "%s-%d-%d: AUC xfer_err_cnt reach err = %d, rcnt = %d, rlen = %d", + avalon8->drv->name, avalon8->device_id, slave_addr, + err, rcnt, rlen); + + cgsleep_ms(5 * 1000); /* Wait MM reset */ + if (avalon8_auc_init(avalon8, info->auc_version)) { + applog(LOG_WARNING, "%s-%d: Failed to re-init auc, unplugging for new hotplug", + avalon8->drv->name, avalon8->device_id); + usb_nodev(avalon8); + } + } + return AVA8_SEND_ERROR; + } + + if (ret) + memcpy((char *)ret, rbuf + 4, AVA8_READ_SIZE); + + info->xfer_err_cnt = 0; + } + + if (info->connecter == AVA8_CONNECTER_IIC) { + err = avalon8_iic_xfer(avalon8, slave_addr, (uint8_t *)pkg, AVA8_WRITE_SIZE, (uint8_t *)ret, AVA8_READ_SIZE); + if ((pkg->type != AVA8_P_DETECT) && err) { + err = avalon8_iic_xfer(avalon8, slave_addr, (uint8_t *)pkg, AVA8_WRITE_SIZE, (uint8_t *)ret, AVA8_READ_SIZE); + applog(LOG_DEBUG, "%s-%d-%d: IIC read again!(type:0x%x, err:%d)", avalon8->drv->name, avalon8->device_id, slave_addr, pkg->type, err); + } + if (err) { + /* FIXME: Don't care broadcast message with no reply, or it will block other thread when called by avalon8_send_bc_pkgs */ + if ((pkg->type != AVA8_P_DETECT) && (slave_addr == AVA8_MODULE_BROADCAST)) + return AVA8_SEND_OK; + + if (info->xfer_err_cnt++ == 100) { + info->xfer_err_cnt = 0; + applog(LOG_DEBUG, "%s-%d-%d: IIC xfer_err_cnt reach err = %d, rcnt = %d, rlen = %d", + avalon8->drv->name, avalon8->device_id, slave_addr, + err, rcnt, rlen); + + cgsleep_ms(5 * 1000); /* Wait MM reset */ + } + return AVA8_SEND_ERROR; + } + + info->xfer_err_cnt = 0; + } + + return AVA8_SEND_OK; +} + +static int avalon8_send_bc_pkgs(struct cgpu_info *avalon8, const struct avalon8_pkg *pkg) +{ + int ret; + + do { + ret = avalon8_iic_xfer_pkg(avalon8, AVA8_MODULE_BROADCAST, pkg, NULL); + } while (ret != AVA8_SEND_OK); + + return 0; +} + +static void avalon8_stratum_pkgs(struct cgpu_info *avalon8, struct pool *pool) +{ + struct avalon8_info *info = avalon8->device_data; + const int merkle_offset = 36; + struct avalon8_pkg pkg; + int i, a, b; + uint32_t tmp; + unsigned char target[32]; + int job_id_len, n2size; + unsigned short crc; + int coinbase_len_posthash, coinbase_len_prehash; + uint8_t coinbase_prehash[32]; + uint32_t range, start; + + /* Send out the first stratum message STATIC */ + applog(LOG_DEBUG, "%s-%d: Pool stratum message STATIC: %d, %d, %d, %d, %d", + avalon8->drv->name, avalon8->device_id, + pool->coinbase_len, + pool->nonce2_offset, + pool->n2size, + merkle_offset, + pool->merkles); + memset(pkg.data, 0, AVA8_P_DATA_LEN); + tmp = be32toh(pool->coinbase_len); + memcpy(pkg.data, &tmp, 4); + + tmp = be32toh(pool->nonce2_offset); + memcpy(pkg.data + 4, &tmp, 4); + + n2size = pool->n2size >= 4 ? 4 : pool->n2size; + tmp = be32toh(n2size); + memcpy(pkg.data + 8, &tmp, 4); + + tmp = be32toh(merkle_offset); + memcpy(pkg.data + 12, &tmp, 4); + + tmp = be32toh(pool->merkles); + memcpy(pkg.data + 16, &tmp, 4); + + if (pool->n2size == 3) + range = 0xffffff / (total_devices ? total_devices : 1); + else + range = 0xffffffff / (total_devices ? total_devices : 1); + start = range * avalon8->device_id; + + tmp = be32toh(start); + memcpy(pkg.data + 20, &tmp, 4); + + tmp = be32toh(range); + memcpy(pkg.data + 24, &tmp, 4); + + if (info->work_restart) { + info->work_restart = false; + tmp = be32toh(0x1); + memcpy(pkg.data + 28, &tmp, 4); + } + + avalon8_init_pkg(&pkg, AVA8_P_STATIC, 1, 1); + if (avalon8_send_bc_pkgs(avalon8, &pkg)) + return; + + if (pool->sdiff <= AVA8_DRV_DIFFMAX) + set_target(target, pool->sdiff); + else + set_target(target, AVA8_DRV_DIFFMAX); + + memcpy(pkg.data, target, 32); + if (opt_debug) { + char *target_str; + target_str = bin2hex(target, 32); + applog(LOG_DEBUG, "%s-%d: Pool stratum target: %s", avalon8->drv->name, avalon8->device_id, target_str); + free(target_str); + } + avalon8_init_pkg(&pkg, AVA8_P_TARGET, 1, 1); + if (avalon8_send_bc_pkgs(avalon8, &pkg)) + return; + + memset(pkg.data, 0, AVA8_P_DATA_LEN); + + job_id_len = strlen(pool->swork.job_id); + crc = crc16((unsigned char *)pool->swork.job_id, job_id_len); + applog(LOG_DEBUG, "%s-%d: Pool stratum message JOBS_ID[%04x]: %s", + avalon8->drv->name, avalon8->device_id, + crc, pool->swork.job_id); + tmp = ((crc << 16) | pool->pool_no); + if (info->last_jobid != tmp) { + info->last_jobid = tmp; + pkg.data[0] = (crc & 0xff00) >> 8; + pkg.data[1] = crc & 0xff; + pkg.data[2] = pool->pool_no & 0xff; + pkg.data[3] = (pool->pool_no & 0xff00) >> 8; + avalon8_init_pkg(&pkg, AVA8_P_JOB_ID, 1, 1); + if (avalon8_send_bc_pkgs(avalon8, &pkg)) + return; + } + + coinbase_len_prehash = pool->nonce2_offset - (pool->nonce2_offset % SHA256_BLOCK_SIZE); + coinbase_len_posthash = pool->coinbase_len - coinbase_len_prehash; + sha256_prehash(pool->coinbase, coinbase_len_prehash, coinbase_prehash); + + a = (coinbase_len_posthash / AVA8_P_DATA_LEN) + 1; + b = coinbase_len_posthash % AVA8_P_DATA_LEN; + memcpy(pkg.data, coinbase_prehash, 32); + avalon8_init_pkg(&pkg, AVA8_P_COINBASE, 1, a + (b ? 1 : 0)); + if (avalon8_send_bc_pkgs(avalon8, &pkg)) + return; + + applog(LOG_DEBUG, "%s-%d: Pool stratum message modified COINBASE: %d %d", + avalon8->drv->name, avalon8->device_id, + a, b); + for (i = 1; i < a; i++) { + memcpy(pkg.data, pool->coinbase + coinbase_len_prehash + i * 32 - 32, 32); + avalon8_init_pkg(&pkg, AVA8_P_COINBASE, i + 1, a + (b ? 1 : 0)); + if (avalon8_send_bc_pkgs(avalon8, &pkg)) + return; + } + if (b) { + memset(pkg.data, 0, AVA8_P_DATA_LEN); + memcpy(pkg.data, pool->coinbase + coinbase_len_prehash + i * 32 - 32, b); + avalon8_init_pkg(&pkg, AVA8_P_COINBASE, i + 1, i + 1); + if (avalon8_send_bc_pkgs(avalon8, &pkg)) + return; + } + + b = pool->merkles; + applog(LOG_DEBUG, "%s-%d: Pool stratum message MERKLES: %d", avalon8->drv->name, avalon8->device_id, b); + for (i = 0; i < b; i++) { + memset(pkg.data, 0, AVA8_P_DATA_LEN); + memcpy(pkg.data, pool->swork.merkle_bin[i], 32); + avalon8_init_pkg(&pkg, AVA8_P_MERKLES, i + 1, b); + if (avalon8_send_bc_pkgs(avalon8, &pkg)) + return; + } + + applog(LOG_DEBUG, "%s-%d: Pool stratum message HEADER: 4", avalon8->drv->name, avalon8->device_id); + for (i = 0; i < 4; i++) { + memset(pkg.data, 0, AVA8_P_DATA_LEN); + memcpy(pkg.data, pool->header_bin + i * 32, 32); + avalon8_init_pkg(&pkg, AVA8_P_HEADER, i + 1, 4); + if (avalon8_send_bc_pkgs(avalon8, &pkg)) + return; + } + + if (info->connecter == AVA8_CONNECTER_AUC) + avalon8_auc_getinfo(avalon8); +} + +static struct cgpu_info *avalon8_iic_detect(void) +{ + int i; + struct avalon8_info *info; + struct cgpu_info *avalon8 = NULL; + struct i2c_ctx *i2c_slave = NULL; + + i2c_slave = i2c_slave_open(I2C_BUS, 0); + if (!i2c_slave) { + applog(LOG_ERR, "avalon8 init iic failed\n"); + return NULL; + } + + i2c_slave->exit(i2c_slave); + i2c_slave = NULL; + + avalon8 = cgcalloc(1, sizeof(*avalon8)); + avalon8->drv = &avalon8_drv; + avalon8->deven = DEV_ENABLED; + avalon8->threads = 1; + add_cgpu(avalon8); + + applog(LOG_INFO, "%s-%d: Found at %s", avalon8->drv->name, avalon8->device_id, + I2C_BUS); + + avalon8->device_data = cgcalloc(sizeof(struct avalon8_info), 1); + memset(avalon8->device_data, 0, sizeof(struct avalon8_info)); + info = avalon8->device_data; + + for (i = 0; i < AVA8_DEFAULT_MODULARS; i++) { + info->enable[i] = false; + info->reboot[i] = false; + info->i2c_slaves[i] = i2c_slave_open(I2C_BUS, i); + if (!info->i2c_slaves[i]) { + applog(LOG_ERR, "avalon8 init i2c slaves failed\n"); + free(avalon8->device_data); + avalon8->device_data = NULL; + free(avalon8); + avalon8 = NULL; + return NULL; + } + } + + info->connecter = AVA8_CONNECTER_IIC; + + return avalon8; +} + +static void detect_modules(struct cgpu_info *avalon8); + +static struct cgpu_info *avalon8_auc_detect(struct libusb_device *dev, struct usb_find_devices *found) +{ + int i, modules = 0; + struct avalon8_info *info; + struct cgpu_info *avalon8 = usb_alloc_cgpu(&avalon8_drv, 1); + char auc_ver[AVA8_AUC_VER_LEN]; + + if (!usb_init(avalon8, dev, found)) { + applog(LOG_ERR, "avalon8 failed usb_init"); + avalon8 = usb_free_cgpu(avalon8); + return NULL; + } + + /* avalon8 prefers not to use zero length packets */ + avalon8->nozlp = true; + + /* We try twice on AUC init */ + if (avalon8_auc_init(avalon8, auc_ver) && avalon8_auc_init(avalon8, auc_ver)) + return NULL; + + applog(LOG_INFO, "%s-%d: Found at %s", avalon8->drv->name, avalon8->device_id, + avalon8->device_path); + + avalon8->device_data = cgcalloc(sizeof(struct avalon8_info), 1); + memset(avalon8->device_data, 0, sizeof(struct avalon8_info)); + info = avalon8->device_data; + memcpy(info->auc_version, auc_ver, AVA8_AUC_VER_LEN); + info->auc_version[AVA8_AUC_VER_LEN] = '\0'; + info->auc_speed = opt_avalon8_aucspeed; + info->auc_xdelay = opt_avalon8_aucxdelay; + + for (i = 0; i < AVA8_DEFAULT_MODULARS; i++) + info->enable[i] = 0; + + info->connecter = AVA8_CONNECTER_AUC; + + detect_modules(avalon8); + for (i = 0; i < AVA8_DEFAULT_MODULARS; i++) + modules += info->enable[i]; + + if (!modules) { + applog(LOG_INFO, "avalon8 found but no modules initialised"); + free(info); + avalon8 = usb_free_cgpu(avalon8); + return NULL; + } + + /* We have an avalon8 AUC connected */ + avalon8->threads = 1; + add_cgpu(avalon8); + + update_usb_stats(avalon8); + + return avalon8; +} + +static inline void avalon8_detect(bool __maybe_unused hotplug) +{ + usb_detect(&avalon8_drv, avalon8_auc_detect); + if (!hotplug && opt_avalon8_iic_detect) + avalon8_iic_detect(); +} + +static bool avalon8_prepare(struct thr_info *thr) +{ + struct cgpu_info *avalon8 = thr->cgpu; + struct avalon8_info *info = avalon8->device_data; + + info->last_diff1 = 0; + info->pending_diff1 = 0; + info->last_rej = 0; + info->mm_count = 0; + info->xfer_err_cnt = 0; + info->pool_no = 0; + + memset(&(info->firsthash), 0, sizeof(info->firsthash)); + cgtime(&(info->last_fan_adj)); + cgtime(&info->last_stratum); + cgtime(&info->last_detect); + + cglock_init(&info->update_lock); + cglock_init(&info->pool0.data_lock); + cglock_init(&info->pool1.data_lock); + cglock_init(&info->pool2.data_lock); + + return true; +} + +static int check_module_exist(struct cgpu_info *avalon8, uint8_t mm_dna[AVA8_MM_DNA_LEN]) +{ + struct avalon8_info *info = avalon8->device_data; + int i; + + for (i = 0; i < AVA8_DEFAULT_MODULARS; i++) { + /* last byte is \0 */ + if (info->enable[i] && !memcmp(info->mm_dna[i], mm_dna, AVA8_MM_DNA_LEN)) + return 1; + } + + return 0; +} + +static void detect_modules(struct cgpu_info *avalon8) +{ + struct avalon8_info *info = avalon8->device_data; + struct avalon8_pkg send_pkg; + struct avalon8_ret ret_pkg; + uint32_t tmp; + int i, j, k, err, rlen; + uint8_t dev_index; + uint8_t rbuf[AVA8_AUC_P_SIZE]; + + /* Detect new modules here */ + for (i = 1; i < AVA8_DEFAULT_MODULARS + 1; i++) { + if (info->enable[i]) + continue; + + /* Send out detect pkg */ + applog(LOG_DEBUG, "%s-%d: AVA8_P_DETECT ID[%d]", + avalon8->drv->name, avalon8->device_id, i); + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + tmp = be32toh(i); /* ID */ + memcpy(send_pkg.data + 28, &tmp, 4); + avalon8_init_pkg(&send_pkg, AVA8_P_DETECT, 1, 1); + err = avalon8_iic_xfer_pkg(avalon8, AVA8_MODULE_BROADCAST, &send_pkg, &ret_pkg); + if (err == AVA8_SEND_OK) { + if (decode_pkg(avalon8, &ret_pkg, AVA8_MODULE_BROADCAST)) { + applog(LOG_DEBUG, "%s-%d: Should be AVA8_P_ACKDETECT(%d), but %d", + avalon8->drv->name, avalon8->device_id, AVA8_P_ACKDETECT, ret_pkg.type); + continue; + } + } + + if (err != AVA8_SEND_OK) { + applog(LOG_DEBUG, "%s-%d: AVA8_P_DETECT: Failed AUC xfer data with err %d", + avalon8->drv->name, avalon8->device_id, err); + break; + } + + applog(LOG_DEBUG, "%s-%d: Module detect ID[%d]: %d", + avalon8->drv->name, avalon8->device_id, i, ret_pkg.type); + if (ret_pkg.type != AVA8_P_ACKDETECT) + break; + + if (check_module_exist(avalon8, ret_pkg.data)) + continue; + + /* Check count of modulars */ + if (i == AVA8_DEFAULT_MODULARS) { + applog(LOG_NOTICE, "You have connected more than %d machines. This is discouraged.", (AVA8_DEFAULT_MODULARS - 1)); + info->conn_overloaded = true; + break; + } else + info->conn_overloaded = false; + + memcpy(info->mm_version[i], ret_pkg.data + AVA8_MM_DNA_LEN, AVA8_MM_VER_LEN); + info->mm_version[i][AVA8_MM_VER_LEN] = '\0'; + for (dev_index = 0; dev_index < (sizeof(avalon8_dev_table) / sizeof(avalon8_dev_table[0])); dev_index++) { + if (!strncmp((char *)&(info->mm_version[i]), (char *)(avalon8_dev_table[dev_index].dev_id_str), 3)) { + info->mod_type[i] = avalon8_dev_table[dev_index].mod_type; + info->miner_count[i] = avalon8_dev_table[dev_index].miner_count; + info->asic_count[i] = avalon8_dev_table[dev_index].asic_count; + info->vin_adc_ratio[i] = avalon8_dev_table[dev_index].vin_adc_ratio; + info->vout_adc_ratio[i] = avalon8_dev_table[dev_index].vout_adc_ratio; + break; + } + } + if (dev_index == (sizeof(avalon8_dev_table) / sizeof(avalon8_dev_table[0]))) { + applog(LOG_NOTICE, "%s-%d: The modular version %s cann't be support", + avalon8->drv->name, avalon8->device_id, info->mm_version[i]); + break; + } + + info->enable[i] = 1; + cgtime(&info->elapsed[i]); + memcpy(info->mm_dna[i], ret_pkg.data, AVA8_MM_DNA_LEN); + memcpy(&tmp, ret_pkg.data + AVA8_MM_DNA_LEN + AVA8_MM_VER_LEN, 4); + tmp = be32toh(tmp); + info->total_asics[i] = tmp; + info->temp_overheat[i] = AVA8_DEFAULT_TEMP_OVERHEAT; + info->temp_target[i] = opt_avalon8_temp_target; + info->fan_pct[i] = opt_avalon8_fan_min; + for (j = 0; j < info->miner_count[i]; j++) { + if (opt_avalon8_voltage == AVA8_INVALID_VOLTAGE) + info->set_voltage[i][j] = avalon8_dev_table[dev_index].set_voltage; + else + info->set_voltage[i][j] = opt_avalon8_voltage; + info->get_voltage[i][j] = 0; + info->get_vin[i][j] = 0; + + for (k = 0; k < 5; k++) + info->temp[i][j][k] = -273; + } + + info->freq_mode[i] = AVA8_FREQ_INIT_MODE; + memset(info->set_frequency[i], 0, sizeof(unsigned int) * info->miner_count[i] * AVA8_DEFAULT_PLL_CNT); + memset(info->get_pll[i], 0, sizeof(uint32_t) * info->miner_count[i] * AVA8_DEFAULT_PLL_CNT); + + info->led_indicator[i] = 0; + info->cutoff[i] = 0; + info->fan_cpm[i] = 0; + info->temp_mm[i] = -273; + info->temp_last_max[i] = -273; + info->local_works[i] = 0; + info->hw_works[i] = 0; + for (j = 0; j < info->miner_count[i]; j++) { + memset(info->chip_matching_work[i][j], 0, sizeof(uint64_t) * info->asic_count[i]); + info->local_works_i[i][j] = 0; + info->hw_works_i[i][j] = 0; + info->error_code[i][j] = 0; + info->error_crc[i][j] = 0; + } + info->error_code[i][j] = 0; + info->error_polling_cnt[i] = 0; + info->power_good[i] = 0; + memset(info->pmu_version[i], 0, sizeof(char) * 5 * AVA8_DEFAULT_PMU_CNT); + info->diff1[i] = 0; + + applog(LOG_NOTICE, "%s-%d: New module detected! ID[%d-%x]", + avalon8->drv->name, avalon8->device_id, i, info->mm_dna[i][AVA8_MM_DNA_LEN - 1]); + + /* Tell MM, it has been detected */ + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + memcpy(send_pkg.data, info->mm_dna[i], AVA8_MM_DNA_LEN); + avalon8_init_pkg(&send_pkg, AVA8_P_SYNC, 1, 1); + avalon8_iic_xfer_pkg(avalon8, i, &send_pkg, &ret_pkg); + /* Keep the usb buffer is empty */ + usb_buffer_clear(avalon8); + usb_read(avalon8, (char *)rbuf, AVA8_AUC_P_SIZE, &rlen, C_AVA8_READ); + } +} + +static void detach_module(struct cgpu_info *avalon8, int addr) +{ + struct avalon8_info *info = avalon8->device_data; + + info->enable[addr] = 0; + applog(LOG_NOTICE, "%s-%d: Module detached! ID[%d]", + avalon8->drv->name, avalon8->device_id, addr); +} + +static int polling(struct cgpu_info *avalon8) +{ + struct avalon8_info *info = avalon8->device_data; + struct avalon8_pkg send_pkg; + struct avalon8_ret ar; + int i, tmp, ret, decode_err = 0; + struct timeval current_fan; + int do_adjust_fan = 0; + uint32_t fan_pwm; + double device_tdiff; + + cgtime(¤t_fan); + device_tdiff = tdiff(¤t_fan, &(info->last_fan_adj)); + if (device_tdiff > 2.0 || device_tdiff < 0) { + cgtime(&info->last_fan_adj); + do_adjust_fan = 1; + } + + for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { + if (!info->enable[i]) + continue; + + cgsleep_ms(opt_avalon8_polling_delay); + + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + /* Red LED */ + tmp = be32toh(info->led_indicator[i]); + memcpy(send_pkg.data, &tmp, 4); + + /* Adjust fan every 2 seconds*/ + if (do_adjust_fan) { + fan_pwm = adjust_fan(info, i); + fan_pwm |= 0x80000000; + tmp = be32toh(fan_pwm); + memcpy(send_pkg.data + 4, &tmp, 4); + } + + if (info->reboot[i]) { + info->reboot[i] = false; + send_pkg.data[8] = 0x1; + } + + avalon8_init_pkg(&send_pkg, AVA8_P_POLLING, 1, 1); + ret = avalon8_iic_xfer_pkg(avalon8, i, &send_pkg, &ar); + if (ret == AVA8_SEND_OK) + decode_err = decode_pkg(avalon8, &ar, i); + + if (ret != AVA8_SEND_OK || decode_err) { + info->error_polling_cnt[i]++; + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + avalon8_init_pkg(&send_pkg, AVA8_P_RSTMMTX, 1, 1); + avalon8_iic_xfer_pkg(avalon8, i, &send_pkg, NULL); + if (info->error_polling_cnt[i] >= 10) + detach_module(avalon8, i); + } + + if (ret == AVA8_SEND_OK && !decode_err) { + info->error_polling_cnt[i] = 0; + + if ((ar.opt == AVA8_P_STATUS) && + (info->mm_dna[i][AVA8_MM_DNA_LEN - 1] != ar.opt)) { + applog(LOG_ERR, "%s-%d-%d: Dup address found %d-%d", + avalon8->drv->name, avalon8->device_id, i, + info->mm_dna[i][AVA8_MM_DNA_LEN - 1], ar.opt); + hexdump((uint8_t *)&ar, sizeof(ar)); + detach_module(avalon8, i); + } + } + } + + return 0; +} + +static void copy_pool_stratum(struct pool *pool_stratum, struct pool *pool) +{ + int i; + int merkles = pool->merkles, job_id_len; + size_t coinbase_len = pool->coinbase_len; + unsigned short crc; + + if (!pool->swork.job_id) + return; + + if (pool_stratum->swork.job_id) { + job_id_len = strlen(pool->swork.job_id); + crc = crc16((unsigned char *)pool->swork.job_id, job_id_len); + job_id_len = strlen(pool_stratum->swork.job_id); + + if (crc16((unsigned char *)pool_stratum->swork.job_id, job_id_len) == crc) + return; + } + + cg_wlock(&pool_stratum->data_lock); + free(pool_stratum->swork.job_id); + free(pool_stratum->nonce1); + free(pool_stratum->coinbase); + + pool_stratum->coinbase = cgcalloc(coinbase_len, 1); + memcpy(pool_stratum->coinbase, pool->coinbase, coinbase_len); + + for (i = 0; i < pool_stratum->merkles; i++) + free(pool_stratum->swork.merkle_bin[i]); + if (merkles) { + pool_stratum->swork.merkle_bin = cgrealloc(pool_stratum->swork.merkle_bin, + sizeof(char *) * merkles + 1); + for (i = 0; i < merkles; i++) { + pool_stratum->swork.merkle_bin[i] = cgmalloc(32); + memcpy(pool_stratum->swork.merkle_bin[i], pool->swork.merkle_bin[i], 32); + } + } + + pool_stratum->sdiff = pool->sdiff; + pool_stratum->coinbase_len = pool->coinbase_len; + pool_stratum->nonce2_offset = pool->nonce2_offset; + pool_stratum->n2size = pool->n2size; + pool_stratum->merkles = pool->merkles; + pool_stratum->swork.job_id = strdup(pool->swork.job_id); + pool_stratum->nonce1 = strdup(pool->nonce1); + + memcpy(pool_stratum->ntime, pool->ntime, sizeof(pool_stratum->ntime)); + memcpy(pool_stratum->header_bin, pool->header_bin, sizeof(pool_stratum->header_bin)); + cg_wunlock(&pool_stratum->data_lock); +} + +static void avalon8_init_setting(struct cgpu_info *avalon8, int addr) +{ + struct avalon8_pkg send_pkg; + uint32_t tmp; + + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + + tmp = be32toh(opt_avalon8_freq_sel); + memcpy(send_pkg.data + 4, &tmp, 4); + + /* + * set flags: + * 0: ss switch + * 1: nonce check + */ + tmp = 1; + if (!opt_avalon8_smart_speed) + tmp = 0; + tmp |= (1 << 1); /* Enable nonce check */ + send_pkg.data[8] = tmp & 0xff; + send_pkg.data[9] = opt_avalon8_nonce_mask & 0xff; + + /* Package the data */ + avalon8_init_pkg(&send_pkg, AVA8_P_SET, 1, 1); + if (addr == AVA8_MODULE_BROADCAST) + avalon8_send_bc_pkgs(avalon8, &send_pkg); + else + avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); +} + +static void avalon8_set_voltage(struct cgpu_info *avalon8, int addr, unsigned int voltage[]) +{ + struct avalon8_info *info = avalon8->device_data; + struct avalon8_pkg send_pkg; + uint32_t tmp; + uint8_t i; + + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + + /* NOTE: miner_count should <= 8 */ + for (i = 0; i < info->miner_count[addr]; i++) { + tmp = be32toh(encode_voltage(voltage[i] + + opt_avalon8_voltage_offset * AVA8_DEFAULT_VOLTAGE_STEP)); + memcpy(send_pkg.data + i * 4, &tmp, 4); + } + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set voltage miner %d, (%d-%d)", + avalon8->drv->name, avalon8->device_id, addr, + i, voltage[0], voltage[info->miner_count[addr] - 1]); + + /* Package the data */ + avalon8_init_pkg(&send_pkg, AVA8_P_SET_VOLT, 1, 1); + if (addr == AVA8_MODULE_BROADCAST) + avalon8_send_bc_pkgs(avalon8, &send_pkg); + else + avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); +} + +static void avalon8_set_freq(struct cgpu_info *avalon8, int addr, int miner_id, unsigned int freq[]) +{ + struct avalon8_info *info = avalon8->device_data; + struct avalon8_pkg send_pkg; + uint32_t tmp, f; + uint8_t i; + + send_pkg.idx = 0; + /* + * TODO: This is only for broadcast to all miners + * This should be support 4 miners + */ + send_pkg.cnt = info->miner_count[addr]; + + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + for (i = 0; i < AVA8_DEFAULT_PLL_CNT; i++) { + tmp = be32toh(api_get_cpm(freq[i])); + memcpy(send_pkg.data + i * 4, &tmp, 4); + } + + f = freq[0]; + for (i = 1; i < AVA8_DEFAULT_PLL_CNT; i++) + f = f > freq[i] ? f : freq[i]; + + tmp = ((AVA8_ASIC_TIMEOUT_CONST / f) * AVA8_DEFAULT_NTIME_OFFSET / 4); + tmp = be32toh(tmp); + memcpy(send_pkg.data + AVA8_DEFAULT_PLL_CNT * 4, &tmp, 4); + + tmp = AVA8_ASIC_TIMEOUT_CONST / f * 98 / 100; + tmp = be32toh(tmp); + memcpy(send_pkg.data + AVA8_DEFAULT_PLL_CNT * 4 + 4, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set freq miner %x-%x", + avalon8->drv->name, avalon8->device_id, addr, + miner_id, be32toh(tmp)); + + /* Package the data */ + avalon8_init_pkg(&send_pkg, AVA8_P_SET_PLL, miner_id + 1, info->miner_count[addr]); + + if (addr == AVA8_MODULE_BROADCAST) + avalon8_send_bc_pkgs(avalon8, &send_pkg); + else + avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); +} + +static void avalon8_set_factory_info(struct cgpu_info *avalon8, int addr, uint8_t value[]) +{ + struct avalon8_pkg send_pkg; + uint8_t i; + + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + + for (i = 0; i < AVA8_DEFAULT_FACTORY_INFO_CNT; i++) + send_pkg.data[i] = value[i]; + + /* Package the data */ + avalon8_init_pkg(&send_pkg, AVA8_P_SET_FAC, 1, 1); + if (addr == AVA8_MODULE_BROADCAST) + avalon8_send_bc_pkgs(avalon8, &send_pkg); + else + avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); +} + +static void avalon8_set_ss_param(struct cgpu_info *avalon8, int addr) +{ + struct avalon8_pkg send_pkg; + uint32_t tmp; + + if (!opt_avalon8_smart_speed) + return; + + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + + tmp = be32toh(opt_avalon8_th_pass); + memcpy(send_pkg.data, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set th pass %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_th_pass); + + tmp = be32toh(opt_avalon8_th_fail); + memcpy(send_pkg.data + 4, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set th fail %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_th_fail); + + tmp = be32toh(opt_avalon8_th_init); + memcpy(send_pkg.data + 8, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set th init %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_th_init); + + tmp = be32toh(opt_avalon8_th_ms); + memcpy(send_pkg.data + 12, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set th ms %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_th_ms); + + tmp = be32toh(opt_avalon8_th_timeout); + memcpy(send_pkg.data + 16, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set th timeout %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_th_timeout); + + /* Package the data */ + avalon8_init_pkg(&send_pkg, AVA8_P_SET_SS, 1, 1); + + if (addr == AVA8_MODULE_BROADCAST) + avalon8_send_bc_pkgs(avalon8, &send_pkg); + else + avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); +} + +static void avalon8_stratum_finish(struct cgpu_info *avalon8) +{ + struct avalon8_pkg send_pkg; + + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + avalon8_init_pkg(&send_pkg, AVA8_P_JOB_FIN, 1, 1); + avalon8_send_bc_pkgs(avalon8, &send_pkg); +} + +static void avalon8_set_finish(struct cgpu_info *avalon8, int addr) +{ + struct avalon8_pkg send_pkg; + + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + avalon8_init_pkg(&send_pkg, AVA8_P_SET_FIN, 1, 1); + avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); +} + +static void avalon8_sswork_update(struct cgpu_info *avalon8) +{ + struct avalon8_info *info = avalon8->device_data; + struct thr_info *thr = avalon8->thr[0]; + struct pool *pool; + int coinbase_len_posthash, coinbase_len_prehash; + + cgtime(&info->last_stratum); + /* + * NOTE: We need mark work_restart to private information, + * So that it cann't reset by hash_driver_work + */ + if (thr->work_restart) + info->work_restart = thr->work_restart; + applog(LOG_NOTICE, "%s-%d: New stratum: restart: %d, update: %d, clean: %d", + avalon8->drv->name, avalon8->device_id, + thr->work_restart, thr->work_update, thr->clean_jobs); + + /* Step 1: MM protocol check */ + pool = current_pool(); + if (!pool->has_stratum) + quit(1, "%s-%d: MM has to use stratum pools", avalon8->drv->name, avalon8->device_id); + + coinbase_len_prehash = pool->nonce2_offset - (pool->nonce2_offset % SHA256_BLOCK_SIZE); + coinbase_len_posthash = pool->coinbase_len - coinbase_len_prehash; + + if (coinbase_len_posthash + SHA256_BLOCK_SIZE > AVA8_P_COINBASE_SIZE) { + applog(LOG_ERR, "%s-%d: MM pool modified coinbase length(%d) is more than %d", + avalon8->drv->name, avalon8->device_id, + coinbase_len_posthash + SHA256_BLOCK_SIZE, AVA8_P_COINBASE_SIZE); + return; + } + if (pool->merkles > AVA8_P_MERKLES_COUNT) { + applog(LOG_ERR, "%s-%d: MM merkles has to be less then %d", avalon8->drv->name, avalon8->device_id, AVA8_P_MERKLES_COUNT); + return; + } + if (pool->n2size < 3) { + applog(LOG_ERR, "%s-%d: MM nonce2 size has to be >= 3 (%d)", avalon8->drv->name, avalon8->device_id, pool->n2size); + return; + } + cg_wlock(&info->update_lock); + + /* Step 2: Send out stratum pkgs */ + cg_rlock(&pool->data_lock); + info->pool_no = pool->pool_no; + copy_pool_stratum(&info->pool2, &info->pool1); + copy_pool_stratum(&info->pool1, &info->pool0); + copy_pool_stratum(&info->pool0, pool); + + avalon8_stratum_pkgs(avalon8, pool); + cg_runlock(&pool->data_lock); + + /* Step 3: Send out finish pkg */ + avalon8_stratum_finish(avalon8); + cg_wunlock(&info->update_lock); +} + +static int64_t avalon8_scanhash(struct thr_info *thr) +{ + struct cgpu_info *avalon8 = thr->cgpu; + struct avalon8_info *info = avalon8->device_data; + struct timeval current; + int i, j, k, count = 0; + int temp_max; + int64_t ret; + bool update_settings = false; + + if ((info->connecter == AVA8_CONNECTER_AUC) && + (unlikely(avalon8->usbinfo.nodev))) { + applog(LOG_ERR, "%s-%d: Device disappeared, shutting down thread", + avalon8->drv->name, avalon8->device_id); + return -1; + } + + /* Step 1: Stop polling and detach the device if there is no stratum in 3 minutes, network is down */ + cgtime(¤t); + if (tdiff(¤t, &(info->last_stratum)) > 180.0) { + for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { + if (!info->enable[i]) + continue; + detach_module(avalon8, i); + } + info->mm_count = 0; + return 0; + } + + /* Step 2: Try to detect new modules */ + if ((tdiff(¤t, &(info->last_detect)) > AVA8_MODULE_DETECT_INTERVAL) || + !info->mm_count) { + cgtime(&info->last_detect); + detect_modules(avalon8); + } + + /* Step 3: ASIC configrations (voltage and frequency) */ + for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { + if (!info->enable[i]) + continue; + + update_settings = false; + + /* Check temperautre */ + temp_max = get_temp_max(info, i); + + /* Enter too hot */ + if (temp_max >= info->temp_overheat[i]) + info->cutoff[i] = 1; + + /* Exit too hot */ + if (info->cutoff[i] && (temp_max <= (info->temp_overheat[i] - 10))) + info->cutoff[i] = 0; + + switch (info->freq_mode[i]) { + case AVA8_FREQ_INIT_MODE: + update_settings = true; + for (j = 0; j < info->miner_count[i]; j++) { + for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) + info->set_frequency[i][j][k] = opt_avalon8_freq[k]; + } + + avalon8_init_setting(avalon8, i); + + info->freq_mode[i] = AVA8_FREQ_PLLADJ_MODE; + break; + case AVA8_FREQ_PLLADJ_MODE: + if (opt_avalon8_smart_speed == AVA8_DEFAULT_SMARTSPEED_OFF) + break; + + /* AVA8_DEFAULT_SMARTSPEED_MODE1: auto speed by A3210 chips */ + break; + default: + applog(LOG_ERR, "%s-%d-%d: Invalid frequency mode %d", + avalon8->drv->name, avalon8->device_id, i, info->freq_mode[i]); + break; + } + if (update_settings) { + cg_wlock(&info->update_lock); + avalon8_set_voltage(avalon8, i, info->set_voltage[i]); + for (j = 0; j < info->miner_count[i]; j++) + avalon8_set_freq(avalon8, i, j, info->set_frequency[i][j]); + if (opt_avalon8_smart_speed) + avalon8_set_ss_param(avalon8, i); + + avalon8_set_finish(avalon8, i); + cg_wunlock(&info->update_lock); + } + } + + /* Step 4: Polling */ + cg_rlock(&info->update_lock); + polling(avalon8); + cg_runlock(&info->update_lock); + + /* Step 5: Calculate mm count */ + for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { + if (info->enable[i]) + count++; + } + info->mm_count = count; + + /* Step 6: Calculate hashes. Use the diff1 value which is scaled by + * device diff and is usually lower than pool diff which will give a + * more stable result, but remove diff rejected shares to more closely + * approximate diff accepted values. */ + info->pending_diff1 += avalon8->diff1 - info->last_diff1; + info->last_diff1 = avalon8->diff1; + info->pending_diff1 -= avalon8->diff_rejected - info->last_rej; + info->last_rej = avalon8->diff_rejected; + if (info->pending_diff1 && !info->firsthash.tv_sec) { + cgtime(&info->firsthash); + copy_time(&(avalon8->dev_start_tv), &(info->firsthash)); + } + + if (info->pending_diff1 <= 0) + ret = 0; + else { + ret = info->pending_diff1; + info->pending_diff1 = 0; + } + return ret * 0xffffffffull; +} + +static float avalon8_hash_cal(struct cgpu_info *avalon8, int modular_id) +{ + struct avalon8_info *info = avalon8->device_data; + uint32_t tmp_freq[AVA8_DEFAULT_PLL_CNT]; + unsigned int i, j; + float mhsmm; + + mhsmm = 0; + for (i = 0; i < info->miner_count[modular_id]; i++) { + for (j = 0; j < AVA8_DEFAULT_PLL_CNT; j++) + tmp_freq[j] = info->set_frequency[modular_id][i][j]; + + for (j = 0; j < AVA8_DEFAULT_PLL_CNT; j++) + mhsmm += (info->get_pll[modular_id][i][j] * tmp_freq[j]); + } + + return mhsmm; +} + +#define STATBUFLEN_WITHOUT_DBG (6 * 1024) +#define STATBUFLEN_WITH_DBG (6 * 7 * 1024) +static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) +{ + struct api_data *root = NULL; + struct avalon8_info *info = avalon8->device_data; + int i, j, k; + char buf[256]; + char *statbuf = NULL; + struct timeval current; + float mhsmm, auc_temp = 0.0; + + cgtime(¤t); + if (opt_debug) + statbuf = cgcalloc(STATBUFLEN_WITH_DBG, 1); + else + statbuf = cgcalloc(STATBUFLEN_WITHOUT_DBG, 1); + + for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { + if (!info->enable[i]) + continue; + + sprintf(buf, "Ver[%s]", info->mm_version[i]); + strcpy(statbuf, buf); + + sprintf(buf, " DNA[%02x%02x%02x%02x%02x%02x%02x%02x]", + info->mm_dna[i][0], + info->mm_dna[i][1], + info->mm_dna[i][2], + info->mm_dna[i][3], + info->mm_dna[i][4], + info->mm_dna[i][5], + info->mm_dna[i][6], + info->mm_dna[i][7]); + strcat(statbuf, buf); + + sprintf(buf, " Elapsed[%.0f]", tdiff(¤t, &(info->elapsed[i]))); + strcat(statbuf, buf); + + strcat(statbuf, " MW["); + info->local_works[i] = 0; + for (j = 0; j < info->miner_count[i]; j++) { + info->local_works[i] += info->local_works_i[i][j]; + sprintf(buf, "%"PRIu64" ", info->local_works_i[i][j]); + strcat(statbuf, buf); + } + statbuf[strlen(statbuf) - 1] = ']'; + + sprintf(buf, " LW[%"PRIu64"]", info->local_works[i]); + strcat(statbuf, buf); + + strcat(statbuf, " MH["); + info->hw_works[i] = 0; + for (j = 0; j < info->miner_count[i]; j++) { + info->hw_works[i] += info->hw_works_i[i][j]; + sprintf(buf, "%"PRIu64" ", info->hw_works_i[i][j]); + strcat(statbuf, buf); + } + statbuf[strlen(statbuf) - 1] = ']'; + + sprintf(buf, " HW[%"PRIu64"]", info->hw_works[i]); + strcat(statbuf, buf); + + sprintf(buf, " Temp[%d]", info->temp_mm[i]); + strcat(statbuf, buf); + + sprintf(buf, " TMax[%d]", get_temp_max(info, i)); + strcat(statbuf, buf); + + sprintf(buf, " Fan[%d]", info->fan_cpm[i]); + strcat(statbuf, buf); + + sprintf(buf, " FanR[%d%%]", info->fan_pct[i]); + strcat(statbuf, buf); + + sprintf(buf, " Vi["); + strcat(statbuf, buf); + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, "%d ", info->get_vin[i][j]); + strcat(statbuf, buf); + } + statbuf[strlen(statbuf) - 1] = ']'; + + sprintf(buf, " Vo["); + strcat(statbuf, buf); + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, "%d ", info->get_voltage[i][j]); + strcat(statbuf, buf); + } + statbuf[strlen(statbuf) - 1] = ']'; + + if (opt_debug) { + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, " PLL%d[", j); + strcat(statbuf, buf); + for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) { + sprintf(buf, "%d ", info->get_pll[i][j][k]); + strcat(statbuf, buf); + } + statbuf[strlen(statbuf) - 1] = ']'; + } + } + + mhsmm = avalon8_hash_cal(avalon8, i); + sprintf(buf, " GHSmm[%.2f] WU[%.2f] Freq[%.2f]", (float)mhsmm / 1000, + info->diff1[i] / tdiff(¤t, &(info->elapsed[i])) * 60.0, + (float)mhsmm / (info->asic_count[i] * info->miner_count[i] * 128)); + strcat(statbuf, buf); + + sprintf(buf, " PG[%d]", info->power_good[i]); + strcat(statbuf, buf); + + sprintf(buf, " Led[%d]", info->led_indicator[i]); + strcat(statbuf, buf); + + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, " MW%d[", j); + strcat(statbuf, buf); + for (k = 0; k < info->asic_count[i]; k++) { + sprintf(buf, "%"PRIu64" ", info->chip_matching_work[i][j][k]); + strcat(statbuf, buf); + } + + statbuf[strlen(statbuf) - 1] = ']'; + } + + sprintf(buf, " TA[%d]", info->total_asics[i]); + strcat(statbuf, buf); + + strcat(statbuf, " ECHU["); + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, "%d ", info->error_code[i][j]); + strcat(statbuf, buf); + } + statbuf[strlen(statbuf) - 1] = ']'; + + sprintf(buf, " ECMM[%d]", info->error_code[i][j]); + strcat(statbuf, buf); + + if (opt_debug) { + sprintf(buf, " FAC0[%d]", info->factory_info[0]); + strcat(statbuf, buf); + + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, " SF%d[", j); + strcat(statbuf, buf); + for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) { + sprintf(buf, "%d ", info->set_frequency[i][j][k]); + strcat(statbuf, buf); + } + + statbuf[strlen(statbuf) - 1] = ']'; + } + + strcat(statbuf, " PMUV["); + for (j = 0; j < AVA8_DEFAULT_PMU_CNT; j++) { + sprintf(buf, "%s ", info->pmu_version[i][j]); + strcat(statbuf, buf); + } + statbuf[strlen(statbuf) - 1] = ']'; + } + + sprintf(buf, " FM[%d]", info->freq_mode[i]); + strcat(statbuf, buf); + + strcat(statbuf, " CRC["); + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, "%d ", info->error_crc[i][j]); + strcat(statbuf, buf); + } + statbuf[strlen(statbuf) - 1] = ']'; + + strcat(statbuf, " PVT_T["); + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, "%d-%d/%d-%d/%d ", + info->temp[i][j][0], + info->temp[i][j][2], + info->temp[i][j][1], + info->temp[i][j][3], + info->temp[i][j][4]); + strcat(statbuf, buf); + } + statbuf[strlen(statbuf) - 1] = ']'; + statbuf[strlen(statbuf)] = '\0'; + + sprintf(buf, "MM ID%d", i); + root = api_add_string(root, buf, statbuf, true); + } + free(statbuf); + + root = api_add_int(root, "MM Count", &(info->mm_count), true); + root = api_add_int(root, "Smart Speed", &opt_avalon8_smart_speed, true); + if (info->connecter == AVA8_CONNECTER_IIC) + root = api_add_string(root, "Connecter", "IIC", true); + + if (info->connecter == AVA8_CONNECTER_AUC) { + root = api_add_string(root, "Connecter", "AUC", true); + root = api_add_string(root, "AUC VER", info->auc_version, false); + root = api_add_int(root, "AUC I2C Speed", &(info->auc_speed), true); + root = api_add_int(root, "AUC I2C XDelay", &(info->auc_xdelay), true); + root = api_add_int(root, "AUC Sensor", &(info->auc_sensor), true); + auc_temp = decode_auc_temp(info->auc_sensor); + root = api_add_temp(root, "AUC Temperature", &auc_temp, true); + } + + root = api_add_bool(root, "Connection Overloaded", &info->conn_overloaded, true); + root = api_add_int(root, "Voltage Offset", &opt_avalon8_voltage_offset, true); + root = api_add_uint32(root, "Nonce Mask", &opt_avalon8_nonce_mask, true); + + return root; +} + +/* format: voltage[-addr[-miner]] + * add4[0, AVA8_DEFAULT_MODULARS - 1], 0 means all modulars + * miner[0, miner_count], 0 means all miners + */ +char *set_avalon8_device_voltage(struct cgpu_info *avalon8, char *arg) +{ + struct avalon8_info *info = avalon8->device_data; + unsigned int val, addr = 0, i, j; + uint32_t miner_id = 0; + + if (!(*arg)) + return NULL; + + sscanf(arg, "%d-%d-%d", &val, &addr, &miner_id); + if (!val) + val = AVA8_DEFAULT_VOLTAGE_MIN; + + if (val < AVA8_DEFAULT_VOLTAGE_MIN || val > AVA8_DEFAULT_VOLTAGE_MAX) + return "Invalid value passed to set_avalon8_device_voltage"; + + if (addr >= AVA8_DEFAULT_MODULARS) { + applog(LOG_ERR, "invalid modular index: %d, valid range 0-%d", addr, (AVA8_DEFAULT_MODULARS - 1)); + return "Invalid modular index to set_avalon8_device_voltage"; + } + + if (!info->enable[addr]) { + applog(LOG_ERR, "Disabled modular:%d", addr); + return "Disabled modular to set_avalon8_device_voltage"; + } + if (miner_id > info->miner_count[addr]) { + applog(LOG_ERR, "invalid miner index: %d, valid range 0-%d", miner_id, info->miner_count[addr]); + return "Invalid miner index to set_avalon8_device_voltage"; + } + + if (!addr) { + for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { + if (!info->enable[i]) + continue; + + if (miner_id) + info->set_voltage[i][miner_id - 1] = val; + else { + for (j = 0; j < info->miner_count[i]; j++) + info->set_voltage[i][j] = val; + } + avalon8_set_voltage(avalon8, i, info->set_voltage[i]); + } + } else { + if (miner_id) + info->set_voltage[addr][miner_id - 1] = val; + else { + for (j = 0; j < info->miner_count[addr]; j++) + info->set_voltage[addr][j] = val; + } + avalon8_set_voltage(avalon8, addr, info->set_voltage[addr]); + } + + applog(LOG_NOTICE, "%s-%d: Update voltage to %d", + avalon8->drv->name, avalon8->device_id, val); + + return NULL; +} + +/* + * format: freq[-addr[-miner]] + * add4[0, AVA8_DEFAULT_MODULARS - 1], 0 means all modulars + * miner[0, miner_count], 0 means all miners + */ +char *set_avalon8_device_freq(struct cgpu_info *avalon8, char *arg) +{ + struct avalon8_info *info = avalon8->device_data; + unsigned int val, addr = 0, i, j, k; + uint32_t miner_id = 0; + + if (!(*arg)) + return NULL; + + sscanf(arg, "%d-%d-%d", &val, &addr, &miner_id); + if (!val) + val = AVA8_DEFAULT_FREQUENCY_MIN; + + if (val < AVA8_DEFAULT_FREQUENCY_MIN || val > AVA8_DEFAULT_FREQUENCY_MAX) + return "Invalid value passed to set_avalon8_device_freq"; + + if (addr >= AVA8_DEFAULT_MODULARS) { + applog(LOG_ERR, "invalid modular index: %d, valid range 0-%d", addr, (AVA8_DEFAULT_MODULARS - 1)); + return "Invalid modular index to set_avalon8_device_freq"; + } + if (!info->enable[addr]) { + applog(LOG_ERR, "Disabled modular:%d", addr); + return "Disabled modular to set_avalon8_device_freq"; + } + if (miner_id > info->miner_count[addr]) { + applog(LOG_ERR, "invalid miner index: %d, valid range 0-%d", miner_id, info->miner_count[addr]); + return "Invalid miner index to set_avalon8_device_freq"; + } + + if (!addr) { + for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { + if (!info->enable[i]) + continue; + + if (miner_id) { + for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) + info->set_frequency[i][miner_id - 1][k] = val; + + avalon8_set_freq(avalon8, i, miner_id, info->set_frequency[i][miner_id]); + } else { + for (j = 0; j < info->miner_count[i]; j++) { + for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) + info->set_frequency[i][j][k] = val; + + avalon8_set_freq(avalon8, i, j, info->set_frequency[i][j]); + } + } + } + } else { + if (miner_id) { + for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) + info->set_frequency[addr][miner_id - 1][k] = val; + + avalon8_set_freq(avalon8, addr, miner_id, info->set_frequency[addr][miner_id]); + + } else { + for (j = 0; j < info->miner_count[addr]; j++) { + for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) + info->set_frequency[addr][j][k] = val; + + avalon8_set_freq(avalon8, addr, j, info->set_frequency[addr][j]); + } + } + } + + applog(LOG_NOTICE, "%s-%d: Update frequency to %d", + avalon8->drv->name, avalon8->device_id, val); + + return NULL; +} + +char *set_avalon8_factory_info(struct cgpu_info *avalon8, char *arg) +{ + struct avalon8_info *info = avalon8->device_data; + int val; + + if (!(*arg)) + return NULL; + + sscanf(arg, "%d", &val); + if (!val) + val = AVA8_DEFAULT_FACTORY_INFO_0; + + if (val < AVA8_DEFAULT_FACTORY_INFO_0_MIN || val > AVA8_DEFAULT_FACTORY_INFO_0_MAX) + return "Invalid value passed to set_avalon8_factory_info"; + + info->factory_info[0] = val; + avalon8_set_factory_info(avalon8, 0, (uint8_t *)info->factory_info); + + applog(LOG_NOTICE, "%s-%d: Update factory info %d", + avalon8->drv->name, avalon8->device_id, val); + + return NULL; +} + +static char *avalon8_set_device(struct cgpu_info *avalon8, char *option, char *setting, char *replybuf) +{ + unsigned int val; + struct avalon8_info *info = avalon8->device_data; + + if (strcasecmp(option, "help") == 0) { + sprintf(replybuf, "pdelay|fan|frequency|led|voltage"); + return replybuf; + } + + if (strcasecmp(option, "pdelay") == 0) { + if (!setting || !*setting) { + sprintf(replybuf, "missing polling delay setting"); + return replybuf; + } + + val = (unsigned int)atoi(setting); + if (val < 1 || val > 65535) { + sprintf(replybuf, "invalid polling delay: %d, valid range 1-65535", val); + return replybuf; + } + + opt_avalon8_polling_delay = val; + + applog(LOG_NOTICE, "%s-%d: Update polling delay to: %d", + avalon8->drv->name, avalon8->device_id, val); + + return NULL; + } + + if (strcasecmp(option, "fan") == 0) { + if (!setting || !*setting) { + sprintf(replybuf, "missing fan value"); + return replybuf; + } + + if (set_avalon8_fan(setting)) { + sprintf(replybuf, "invalid fan value, valid range 0-100"); + return replybuf; + } + + applog(LOG_NOTICE, "%s-%d: Update fan to %d-%d", + avalon8->drv->name, avalon8->device_id, + opt_avalon8_fan_min, opt_avalon8_fan_max); + + return NULL; + } + + if (strcasecmp(option, "frequency") == 0) { + if (!setting || !*setting) { + sprintf(replybuf, "missing frequency value"); + return replybuf; + } + + return set_avalon8_device_freq(avalon8, setting); + } + + if (strcasecmp(option, "led") == 0) { + int val_led = -1; + + if (!setting || !*setting) { + sprintf(replybuf, "missing module_id setting"); + return replybuf; + } + + sscanf(setting, "%d-%d", &val, &val_led); + if (val < 1 || val >= AVA8_DEFAULT_MODULARS) { + sprintf(replybuf, "invalid module_id: %d, valid range 1-%d", val, AVA8_DEFAULT_MODULARS); + return replybuf; + } + + if (!info->enable[val]) { + sprintf(replybuf, "the current module was disabled %d", val); + return replybuf; + } + + if (val_led == -1) + info->led_indicator[val] = !info->led_indicator[val]; + else { + if (val_led < 0 || val_led > 1) { + sprintf(replybuf, "invalid LED status: %d, valid value 0|1", val_led); + return replybuf; + } + + if (val_led != info->led_indicator[val]) + info->led_indicator[val] = val_led; + } + + applog(LOG_NOTICE, "%s-%d: Module:%d, LED: %s", + avalon8->drv->name, avalon8->device_id, + val, info->led_indicator[val] ? "on" : "off"); + + return NULL; + } + + if (strcasecmp(option, "voltage") == 0) { + if (!setting || !*setting) { + sprintf(replybuf, "missing voltage value"); + return replybuf; + } + + return set_avalon8_device_voltage(avalon8, setting); + } + + if (strcasecmp(option, "factory") == 0) { + if (!setting || !*setting) { + sprintf(replybuf, "missing factory info"); + return replybuf; + } + + return set_avalon8_factory_info(avalon8, setting); + } + + if (strcasecmp(option, "reboot") == 0) { + if (!setting || !*setting) { + sprintf(replybuf, "missing reboot value"); + return replybuf; + } + + sscanf(setting, "%d", &val); + if (val < 1 || val >= AVA8_DEFAULT_MODULARS) { + sprintf(replybuf, "invalid module_id: %d, valid range 1-%d", val, AVA8_DEFAULT_MODULARS); + return replybuf; + } + + info->reboot[val] = true; + + return NULL; + } + + sprintf(replybuf, "Unknown option: %s", option); + return replybuf; +} + +static void avalon8_statline_before(char *buf, size_t bufsiz, struct cgpu_info *avalon8) +{ + struct avalon8_info *info = avalon8->device_data; + int temp = -273; + int fanmin = AVA8_DEFAULT_FAN_MAX; + int i; + uint32_t frequency = 0; + float ghs_sum = 0, mhsmm = 0; + + for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { + if (!info->enable[i]) + continue; + + if (fanmin >= info->fan_pct[i]) + fanmin = info->fan_pct[i]; + + if (temp < get_temp_max(info, i)) + temp = get_temp_max(info, i); + + mhsmm = avalon8_hash_cal(avalon8, i); + frequency += (mhsmm / (info->asic_count[i] * info->miner_count[i] * 128)); + ghs_sum += (mhsmm / 1000); + } + + if (info->mm_count) + frequency /= info->mm_count; + + tailsprintf(buf, bufsiz, "%4dMhz %.2fGHS %2dC %3d%%", frequency, ghs_sum, temp, fanmin); +} + +struct device_drv avalon8_drv = { + .drv_id = DRIVER_avalon8, + .dname = "avalon8", + .name = "AV8", + .set_device = avalon8_set_device, + .get_api_stats = avalon8_api_stats, + .get_statline_before = avalon8_statline_before, + .drv_detect = avalon8_detect, + .thread_prepare = avalon8_prepare, + .hash_work = hash_driver_work, + .flush_work = avalon8_sswork_update, + .update_work = avalon8_sswork_update, + .scanwork = avalon8_scanhash, + .max_diff = AVA8_DRV_DIFFMAX, + .genwork = true, +}; diff --git a/driver-avalon8.h b/driver-avalon8.h new file mode 100644 index 0000000000..1e7795e483 --- /dev/null +++ b/driver-avalon8.h @@ -0,0 +1,309 @@ +/* + * Copyright 2017 xuzhenxing + * Copyright 2016-2017 Mikeqin + * Copyright 2016 Con Kolivas + * + * 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 _AVALON8_H_ +#define _AVALON8_H_ + +#include "util.h" +#include "i2c-context.h" + +#ifdef USE_AVALON8 + +#define AVA8_FREQUENCY_MAX 1404 + +#define AVA8_DEFAULT_FAN_MIN 5 /* % */ +#define AVA8_DEFAULT_FAN_MAX 100 +#define AVA8_DEFAULT_FAN_INTERVAL 15 /* Seconds */ + +#define AVA8_DEFAULT_TEMP_TARGET 90 +#define AVA8_DEFAULT_TEMP_OVERHEAT 105 +#define AVA8_DEFAULT_TEMP_HYSTERESIS 5 + +#define AVA8_DEFAULT_VOLTAGE_MIN 3889 +#define AVA8_DEFAULT_VOLTAGE_MAX 5059 +#define AVA8_INVALID_VOLTAGE 0 +#define AVA8_DEFAULT_VOLTAGE_STEP 78 + +#define AVA8_DEFAULT_VOLTAGE_LEVEL_MIN 0 +#define AVA8_DEFAULT_VOLTAGE_LEVEL_MAX 15 + +#define AVA8_DEFAULT_VOLTAGE_OFFSET_MIN -2 +#define AVA8_DEFAULT_VOLTAGE_OFFSET 0 +#define AVA8_DEFAULT_VOLTAGE_OFFSET_MAX 1 + +#define AVA8_DEFAULT_FACTORY_INFO_0_MIN -15 +#define AVA8_DEFAULT_FACTORY_INFO_0 0 +#define AVA8_DEFAULT_FACTORY_INFO_0_MAX 15 + +#define AVA8_DEFAULT_FREQUENCY_MIN 24 /* NOTE: It cann't support 0 */ +#define AVA8_DEFAULT_FREQUENCY_0 600 +#define AVA8_DEFAULT_FREQUENCY_1 636 +#define AVA8_DEFAULT_FREQUENCY_2 672 +#define AVA8_DEFAULT_FREQUENCY_3 708 +#define AVA8_DEFAULT_FREQUENCY_MAX 1404 +#define AVA8_DEFAULT_FREQUENCY_SEL 0 + +#define AVA8_DEFAULT_MODULARS 7 /* Only support 6 modules maximum with one AUC */ +#define AVA8_DEFAULT_MINER_CNT 4 +#define AVA8_DEFAULT_ASIC_MAX 26 +#define AVA8_DEFAULT_PLL_CNT 4 +#define AVA8_DEFAULT_PMU_CNT 2 + +#define AVA8_DEFAULT_POLLING_DELAY 20 /* ms */ +#define AVA8_DEFAULT_NTIME_OFFSET 40 + +#define AVA8_DEFAULT_SMARTSPEED_OFF 0 +#define AVA8_DEFAULT_SMARTSPEED_MODE1 1 +#define AVA8_DEFAULT_SMART_SPEED (AVA8_DEFAULT_SMARTSPEED_MODE1) + +#define AVA8_DEFAULT_TH_PASS (162) +#define AVA8_DEFAULT_TH_FAIL (10921) +#define AVA8_DEFAULT_TH_INIT (0xffff / 2) +#define AVA8_DEFAULT_TH_MS 1 +#define AVA8_DEFAULT_TH_TIMEOUT 0 +#define AVA8_DEFAULT_NONCE_MASK 29 + +#define AVA8_DEFAULT_IIC_DETECT false + +#define AVA8_PWM_MAX 0x3FF +#define AVA8_DRV_DIFFMAX 500 +#define AVA8_ASIC_TIMEOUT_CONST 0x2000000 /* 2 ^ 32 / 128 */ + +#define AVA8_MODULE_DETECT_INTERVAL 30 /* 30 s */ + +#define AVA8_AUC_VER_LEN 12 /* Version length: 12 (AUC-YYYYMMDD) */ +#define AVA8_AUC_SPEED 400000 +#define AVA8_AUC_XDELAY 19200 /* 4800 = 1ms in AUC (11U14) */ +#define AVA8_AUC_P_SIZE 64 + +#define AVA8_CONNECTER_AUC 1 +#define AVA8_CONNECTER_IIC 2 + +/* avalon8 protocol package type from MM protocol.h */ +#define AVA8_MM_VER_LEN 15 +#define AVA8_MM_DNA_LEN 8 +#define AVA8_H1 'C' +#define AVA8_H2 'N' + +#define AVA8_P_COINBASE_SIZE (6 * 1024 + 64) +#define AVA8_P_MERKLES_COUNT 30 + +#define AVA8_P_COUNT 40 +#define AVA8_P_DATA_LEN 32 + +/* Broadcase with block iic_write*/ +#define AVA8_P_DETECT 0x10 + +/* Broadcase With non-block iic_write*/ +#define AVA8_P_STATIC 0x11 +#define AVA8_P_JOB_ID 0x12 +#define AVA8_P_COINBASE 0x13 +#define AVA8_P_MERKLES 0x14 +#define AVA8_P_HEADER 0x15 +#define AVA8_P_TARGET 0x16 +#define AVA8_P_JOB_FIN 0x17 + +/* Broadcase or with I2C address */ +#define AVA8_P_SET 0x20 +#define AVA8_P_SET_FIN 0x21 +#define AVA8_P_SET_VOLT 0x22 +#define AVA8_P_SET_PMU 0x24 +#define AVA8_P_SET_PLL 0x25 +#define AVA8_P_SET_SS 0x26 +/* 0x27 reserved */ +#define AVA8_P_SET_FAC 0x28 + +/* Have to send with I2C address */ +#define AVA8_P_POLLING 0x30 +#define AVA8_P_SYNC 0x31 +#define AVA8_P_TEST 0x32 +#define AVA8_P_RSTMMTX 0x33 +#define AVA8_P_GET_VOLT 0x34 + +/* Back to host */ +#define AVA8_P_ACKDETECT 0x40 +#define AVA8_P_STATUS 0x41 +#define AVA8_P_NONCE 0x42 +#define AVA8_P_TEST_RET 0x43 +#define AVA8_P_STATUS_VOLT 0x46 +#define AVA8_P_STATUS_PMU 0x48 +#define AVA8_P_STATUS_PLL 0x49 +#define AVA8_P_STATUS_LOG 0x4a +#define AVA8_P_STATUS_ASIC 0x4b +#define AVA8_P_STATUS_PVT 0x4c +#define AVA8_P_STATUS_FAC 0x4d + +#define AVA8_MODULE_BROADCAST 0 +/* End of avalon8 protocol package type */ + +#define AVA8_IIC_RESET 0xa0 +#define AVA8_IIC_INIT 0xa1 +#define AVA8_IIC_DEINIT 0xa2 +#define AVA8_IIC_XFER 0xa5 +#define AVA8_IIC_INFO 0xa6 + +#define AVA8_FREQ_INIT_MODE 0x0 +#define AVA8_FREQ_PLLADJ_MODE 0x1 + +#define AVA8_DEFAULT_FACTORY_INFO_CNT 1 + +#define AVA8_MM821_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 1000.0 * 100.0) +#define AVA8_MM821_VOUT_ADC_RATIO (3.3 / 1024.0 * 63.0 / 20.0 * 10000.0 * 100.0) + +struct avalon8_pkg { + uint8_t head[2]; + uint8_t type; + uint8_t opt; + uint8_t idx; + uint8_t cnt; + uint8_t data[32]; + uint8_t crc[2]; +}; +#define avalon8_ret avalon8_pkg + +struct avalon8_info { + /* Public data */ + int64_t last_diff1; + int64_t pending_diff1; + double last_rej; + + int mm_count; + int xfer_err_cnt; + int pool_no; + + struct timeval firsthash; + struct timeval last_fan_adj; + struct timeval last_stratum; + struct timeval last_detect; + + cglock_t update_lock; + + struct pool pool0; + struct pool pool1; + struct pool pool2; + + bool work_restart; + + uint32_t last_jobid; + + /* For connecter */ + char auc_version[AVA8_AUC_VER_LEN + 1]; + + int auc_speed; + int auc_xdelay; + int auc_sensor; + + struct i2c_ctx *i2c_slaves[AVA8_DEFAULT_MODULARS]; + + uint8_t connecter; /* AUC or IIC */ + + /* For modulars */ + bool enable[AVA8_DEFAULT_MODULARS]; + bool reboot[AVA8_DEFAULT_MODULARS]; + + struct timeval elapsed[AVA8_DEFAULT_MODULARS]; + + uint8_t mm_dna[AVA8_DEFAULT_MODULARS][AVA8_MM_DNA_LEN]; + char mm_version[AVA8_DEFAULT_MODULARS][AVA8_MM_VER_LEN + 1]; /* It's a string */ + uint32_t total_asics[AVA8_DEFAULT_MODULARS]; + uint32_t max_ntime; /* Maximum: 7200 */ + + int mod_type[AVA8_DEFAULT_MODULARS]; + uint8_t miner_count[AVA8_DEFAULT_MODULARS]; + uint8_t asic_count[AVA8_DEFAULT_MODULARS]; + + uint32_t freq_mode[AVA8_DEFAULT_MODULARS]; + int led_indicator[AVA8_DEFAULT_MODULARS]; + int fan_pct[AVA8_DEFAULT_MODULARS]; + int fan_cpm[AVA8_DEFAULT_MODULARS]; + + int temp[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][5]; + int temp_mm[AVA8_DEFAULT_MODULARS]; + + uint8_t cutoff[AVA8_DEFAULT_MODULARS]; + int temp_target[AVA8_DEFAULT_MODULARS]; + int temp_last_max[AVA8_DEFAULT_MODULARS]; + int temp_overheat[AVA8_DEFAULT_MODULARS]; + time_t last_temp_time[AVA8_DEFAULT_MODULARS]; + + uint32_t set_voltage[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; + uint32_t set_frequency[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_PLL_CNT]; + + uint16_t get_vin[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; + uint32_t get_voltage[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; + uint32_t get_pll[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_PLL_CNT]; + + int8_t factory_info[AVA8_DEFAULT_FACTORY_INFO_CNT]; + + uint64_t local_works[AVA8_DEFAULT_MODULARS]; + uint64_t local_works_i[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; + uint64_t hw_works[AVA8_DEFAULT_MODULARS]; + uint64_t hw_works_i[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; + uint64_t chip_matching_work[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_ASIC_MAX]; + + uint32_t error_code[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT + 1]; + uint32_t error_crc[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; + uint8_t error_polling_cnt[AVA8_DEFAULT_MODULARS]; + + uint8_t power_good[AVA8_DEFAULT_MODULARS]; + char pmu_version[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_PMU_CNT][5]; + uint64_t diff1[AVA8_DEFAULT_MODULARS]; + + uint16_t vin_adc_ratio[AVA8_DEFAULT_MODULARS]; + uint16_t vout_adc_ratio[AVA8_DEFAULT_MODULARS]; + + bool conn_overloaded; +}; + +struct avalon8_iic_info { + uint8_t iic_op; + union { + uint32_t aucParam[2]; + uint8_t slave_addr; + } iic_param; +}; + +struct avalon8_dev_description { + uint8_t dev_id_str[8]; + int mod_type; + uint8_t miner_count; /* it should not greater than AVA8_DEFAULT_MINER_CNT */ + uint8_t asic_count; /* asic count each miner, it should not great than AVA8_DEFAULT_ASIC_MAX */ + uint16_t vin_adc_ratio; + uint16_t vout_adc_ratio; + uint32_t set_voltage; +}; + +#define AVA8_WRITE_SIZE (sizeof(struct avalon8_pkg)) +#define AVA8_READ_SIZE AVA8_WRITE_SIZE + +#define AVA8_SEND_OK 0 +#define AVA8_SEND_ERROR -1 + +extern char *set_avalon8_fan(char *arg); +extern char *set_avalon8_freq(char *arg); +extern char *set_avalon8_voltage(char *arg); +extern char *set_avalon8_voltage_level(char *arg); +extern char *set_avalon8_voltage_offset(char *arg); +extern int opt_avalon8_temp_target; +extern int opt_avalon8_polling_delay; +extern int opt_avalon8_aucspeed; +extern int opt_avalon8_aucxdelay; +extern int opt_avalon8_smart_speed; +extern bool opt_avalon8_iic_detect; +extern int opt_avalon8_freq_sel; +extern uint32_t opt_avalon8_th_pass; +extern uint32_t opt_avalon8_th_fail; +extern uint32_t opt_avalon8_th_init; +extern uint32_t opt_avalon8_th_ms; +extern uint32_t opt_avalon8_th_timeout; +extern uint32_t opt_avalon8_nonce_mask; +#endif /* USE_AVALON8 */ +#endif /* _AVALON8_H_ */ diff --git a/miner.h b/miner.h index 96fca536d1..daad9dd14b 100644 --- a/miner.h +++ b/miner.h @@ -242,6 +242,7 @@ static inline int fsync (int fd) DRIVER_ADD_COMMAND(avalon2) \ DRIVER_ADD_COMMAND(avalon4) \ DRIVER_ADD_COMMAND(avalon7) \ + DRIVER_ADD_COMMAND(avalon8) \ DRIVER_ADD_COMMAND(avalonm) \ DRIVER_ADD_COMMAND(bflsc) \ DRIVER_ADD_COMMAND(bitfury) \ @@ -1129,7 +1130,7 @@ extern pthread_cond_t restart_cond; extern void clear_stratum_shares(struct pool *pool); extern void clear_pool_work(struct pool *pool); extern void set_target(unsigned char *dest_target, double diff); -#if defined (USE_AVALON2) || defined (USE_AVALON4) || defined (USE_AVALON7) || defined (USE_AVALON_MINER) || defined (USE_HASHRATIO) +#if defined (USE_AVALON2) || defined (USE_AVALON4) || defined (USE_AVALON7) || defined (USE_AVALON8) || defined (USE_AVALON_MINER) || defined (USE_HASHRATIO) bool submit_nonce2_nonce(struct thr_info *thr, struct pool *pool, struct pool *real_pool, uint32_t nonce2, uint32_t nonce, uint32_t ntime); uint32_t gen_merkle_root(struct pool *pool, uint64_t nonce2); diff --git a/usbutils.c b/usbutils.c index 7c83a35f66..44f38d0237 100644 --- a/usbutils.c +++ b/usbutils.c @@ -71,6 +71,7 @@ static cgtimer_t usb11_cgt; #define AVALON_TIMEOUT_MS 999 #define AVALON4_TIMEOUT_MS 999 #define AVALON7_TIMEOUT_MS 999 +#define AVALON8_TIMEOUT_MS 999 #define AVALONM_TIMEOUT_MS 999 #define KLONDIKE_TIMEOUT_MS 999 #define COINTERRA_TIMEOUT_MS 999 @@ -89,6 +90,7 @@ static cgtimer_t usb11_cgt; #define AVALON_TIMEOUT_MS 200 #define AVALON4_TIMEOUT_MS 200 #define AVALON7_TIMEOUT_MS 200 +#define AVALON8_TIMEOUT_MS 200 #define AVALONM_TIMEOUT_MS 300 #define KLONDIKE_TIMEOUT_MS 200 #define COINTERRA_TIMEOUT_MS 200 @@ -301,6 +303,16 @@ static struct usb_intinfo ava7_ints[] = { USB_EPS(1, ava7_epinfos) }; #endif +#ifdef USE_AVALON8 +static struct usb_epinfo ava8_epinfos[] = { + { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0, 0 }, + { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(1), 0, 0 } +}; + +static struct usb_intinfo ava8_ints[] = { + USB_EPS(1, ava8_epinfos) +}; +#endif #ifdef USE_AVALON_MINER static struct usb_epinfo avam_epinfos[] = { { LIBUSB_TRANSFER_TYPE_INTERRUPT, 40, EPI(1), 0, 0 }, @@ -707,6 +719,20 @@ static struct usb_find_devices find_dev[] = { .latency = LATENCY_UNUSED, INTINFO(ava7_ints) }, #endif +#ifdef USE_AVALON8 + { + .drv = DRIVER_avalon8, + .name = "AV8", + .ident = IDENT_AV8, + .idVendor = 0x29f1, + .idProduct = 0x33f2, + .iManufacturer = "CANAAN", + .iProduct = "USB2IIC Converter", + .config = 1, + .timeout = AVALON8_TIMEOUT_MS, + .latency = LATENCY_UNUSED, + INTINFO(ava8_ints) }, +#endif #ifdef USE_AVALON_MINER { .drv = DRIVER_avalonm, @@ -3813,6 +3839,7 @@ void usb_cleanup(void) case DRIVER_avalon2: case DRIVER_avalon4: case DRIVER_avalon7: + case DRIVER_avalon8: case DRIVER_avalonm: case DRIVER_klondike: case DRIVER_hashfast: diff --git a/usbutils.h b/usbutils.h index 37a347d021..41282b5538 100644 --- a/usbutils.h +++ b/usbutils.h @@ -149,6 +149,7 @@ enum sub_ident { IDENT_AV2, IDENT_AV4, IDENT_AV7, + IDENT_AV8, IDENT_AVM, IDENT_BAJ, IDENT_BAL, @@ -389,6 +390,8 @@ struct cg_usb_info { USB_ADD_COMMAND(C_AVA4_WRITE, "Ava4Write") \ USB_ADD_COMMAND(C_AVA7_READ, "Ava7Read") \ USB_ADD_COMMAND(C_AVA7_WRITE, "Ava7Write") \ + USB_ADD_COMMAND(C_AVA8_READ, "Ava8Read") \ + USB_ADD_COMMAND(C_AVA8_WRITE, "Ava8Write") \ USB_ADD_COMMAND(C_AVAM_READ, "AvamRead") \ USB_ADD_COMMAND(C_AVAM_WRITE, "AvamWrite") \ USB_ADD_COMMAND(C_BET_WRITE, "BlockErupterWrite") \ From d5b0ac3195cc3cc14f2800bf65164ac8b37201e2 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Wed, 8 Nov 2017 03:33:02 -0500 Subject: [PATCH 015/113] Update cpm --- driver-avalon8.c | 144 +++++++---------------------------------------- 1 file changed, 20 insertions(+), 124 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index cbb9442ac8..c2fc8a0c34 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -56,122 +56,19 @@ uint32_t opt_avalon8_nonce_mask = AVA8_DEFAULT_NONCE_MASK; uint32_t cpm_table[] = { - 0x0173f813, - 0x0175f813, - 0x0163f813, - 0x0164f813, - 0x0165f813, - 0x0166f813, - 0x0153f813, - 0x01547813, - 0x0154f813, - 0x01557813, - 0x0155f813, - 0x01567813, - 0x0156f813, - 0x01577813, - 0x0143f813, - 0x01443813, - 0x01447813, - 0x0144b813, - 0x0144f813, - 0x01453813, - 0x01457813, - 0x0145b813, - 0x0145f813, - 0x01463813, - 0x01467813, - 0x0146b813, - 0x0146f813, - 0x01473813, - 0x01477813, - 0x0147b813, - 0x0133f813, - 0x01341813, - 0x01343813, - 0x01345813, - 0x01347813, - 0x01349813, - 0x0134b813, - 0x0134d813, - 0x0134f813, - 0x01351813, - 0x01353813, - 0x01355813, - 0x01357813, - 0x01359813, - 0x0135b813, - 0x0135d813, - 0x0135f813, - 0x01361813, - 0x01363813, - 0x01365813, - 0x01367813, - 0x01369813, - 0x0136b813, - 0x0136d813, - 0x0136f813, - 0x01371813, - 0x01373813, - 0x01375813, - 0x01377813, - 0x01379813, - 0x0137b813, - 0x0123e813, - 0x0123f813, - 0x01240813, - 0x01241813, - 0x01242813, - 0x01243813, - 0x01244813, - 0x01245813, - 0x01246813, - 0x01247813, - 0x01248813, - 0x01249813, - 0x0124a813, - 0x0124b813, - 0x0124c813, - 0x0124d813, - 0x0124e813, - 0x0124f813, - 0x01250813, - 0x01251813, - 0x01252813, - 0x01253813, - 0x01254813, - 0x01255813, - 0x01256813, - 0x01257813, - 0x01258813, - 0x01259813, - 0x0125a813, - 0x0125b813, - 0x0125c813, - 0x0125d813, - 0x0125e813, - 0x0125f813, - 0x01260813, - 0x01261813, - 0x01262813, - 0x01263813, - 0x01264813, - 0x01265813, - 0x01266813, - 0x01267813, - 0x01268813, - 0x01269813, - 0x0126a813, - 0x0126b813, - 0x0126c813, - 0x0126d813, - 0x0126e813, - 0x0126f813, - 0x01270813, - 0x01271813, - 0x01272813, - 0x01273813, - 0x01274813, + 0x008ffbe1, + 0x009fffe1, + 0x009fbfe1, + 0x009da761, + 0x009f9fe1, + 0x009d9761, + 0x00978de1, + 0x009b8ee1, + 0x009f8fe1, + 0x00918461, + 0x009384e1, + 0x00958561, + 0x009785e1 }; struct avalon8_dev_description avalon8_dev_table[] = { @@ -188,7 +85,13 @@ struct avalon8_dev_description avalon8_dev_table[] = { static uint32_t api_get_cpm(uint32_t freq) { - return cpm_table[freq / 12 - 2]; + uint8_t idx; + + idx = freq / 100; + if (idx >= (sizeof(cpm_table) / sizeof(cpm_table[0])) + idx = sizeof(cpm_table) / sizeof(cpm_table[0] - 1; + + return cpm_table[idx]; } static uint32_t encode_voltage(uint32_t volt) @@ -1648,13 +1551,6 @@ static void avalon8_set_freq(struct cgpu_info *avalon8, int addr, int miner_id, uint32_t tmp, f; uint8_t i; - send_pkg.idx = 0; - /* - * TODO: This is only for broadcast to all miners - * This should be support 4 miners - */ - send_pkg.cnt = info->miner_count[addr]; - memset(send_pkg.data, 0, AVA8_P_DATA_LEN); for (i = 0; i < AVA8_DEFAULT_PLL_CNT; i++) { tmp = be32toh(api_get_cpm(freq[i])); From b6200e2e6c119117b310dc4f0b8edc52eb6011d9 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Wed, 8 Nov 2017 05:36:30 -0500 Subject: [PATCH 016/113] Update P_SET_VOLT --- driver-avalon8.c | 23 +++++++++++------------ driver-avalon8.h | 24 ++++++++++++------------ 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index c2fc8a0c34..04cbf80d11 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -75,11 +75,11 @@ struct avalon8_dev_description avalon8_dev_table[] = { { "821", 821, - 4, - 26, + 1, + 2, AVA8_MM821_VIN_ADC_RATIO, AVA8_MM821_VOUT_ADC_RATIO, - 4825, + 4500, } }; @@ -88,8 +88,8 @@ static uint32_t api_get_cpm(uint32_t freq) uint8_t idx; idx = freq / 100; - if (idx >= (sizeof(cpm_table) / sizeof(cpm_table[0])) - idx = sizeof(cpm_table) / sizeof(cpm_table[0] - 1; + if (idx >= (sizeof(cpm_table) / sizeof(cpm_table[0]))) + idx = sizeof(cpm_table) / sizeof(cpm_table[0]) - 1; return cpm_table[idx]; } @@ -102,7 +102,7 @@ static uint32_t encode_voltage(uint32_t volt) if (volt < AVA8_DEFAULT_VOLTAGE_MIN) volt = AVA8_DEFAULT_VOLTAGE_MIN; - return 0x8000 | ((volt - AVA8_DEFAULT_VOLTAGE_MIN) / AVA8_DEFAULT_VOLTAGE_STEP); + return 0x60 - ((volt - AVA8_DEFAULT_VOLTAGE_MIN) / AVA8_DEFAULT_VOLTAGE_STEP); } static uint32_t convert_voltage_level(uint32_t level) @@ -1505,7 +1505,7 @@ static void avalon8_init_setting(struct cgpu_info *avalon8, int addr) tmp = 1; if (!opt_avalon8_smart_speed) tmp = 0; - tmp |= (1 << 1); /* Enable nonce check */ + tmp |= (0 << 1); /* Enable nonce check */ send_pkg.data[8] = tmp & 0xff; send_pkg.data[9] = opt_avalon8_nonce_mask & 0xff; @@ -1528,8 +1528,7 @@ static void avalon8_set_voltage(struct cgpu_info *avalon8, int addr, unsigned in /* NOTE: miner_count should <= 8 */ for (i = 0; i < info->miner_count[addr]; i++) { - tmp = be32toh(encode_voltage(voltage[i] + - opt_avalon8_voltage_offset * AVA8_DEFAULT_VOLTAGE_STEP)); + tmp = be32toh(encode_voltage(voltage[i])); memcpy(send_pkg.data + i * 4, &tmp, 4); } applog(LOG_DEBUG, "%s-%d-%d: avalon8 set voltage miner %d, (%d-%d)", @@ -1561,7 +1560,7 @@ static void avalon8_set_freq(struct cgpu_info *avalon8, int addr, int miner_id, for (i = 1; i < AVA8_DEFAULT_PLL_CNT; i++) f = f > freq[i] ? f : freq[i]; - tmp = ((AVA8_ASIC_TIMEOUT_CONST / f) * AVA8_DEFAULT_NTIME_OFFSET / 4); + tmp = ((AVA8_ASIC_TIMEOUT_CONST / f) * AVA8_DEFAULT_NTIME_OFFSET * 5 / 100); tmp = be32toh(tmp); memcpy(send_pkg.data + AVA8_DEFAULT_PLL_CNT * 4, &tmp, 4); @@ -1972,7 +1971,7 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) mhsmm = avalon8_hash_cal(avalon8, i); sprintf(buf, " GHSmm[%.2f] WU[%.2f] Freq[%.2f]", (float)mhsmm / 1000, info->diff1[i] / tdiff(¤t, &(info->elapsed[i])) * 60.0, - (float)mhsmm / (info->asic_count[i] * info->miner_count[i] * 128)); + (float)mhsmm / (info->asic_count[i] * info->miner_count[i] * 172)); strcat(statbuf, buf); sprintf(buf, " PG[%d]", info->power_good[i]); @@ -2395,7 +2394,7 @@ static void avalon8_statline_before(char *buf, size_t bufsiz, struct cgpu_info * temp = get_temp_max(info, i); mhsmm = avalon8_hash_cal(avalon8, i); - frequency += (mhsmm / (info->asic_count[i] * info->miner_count[i] * 128)); + frequency += (mhsmm / (info->asic_count[i] * info->miner_count[i] * 172)); ghs_sum += (mhsmm / 1000); } diff --git a/driver-avalon8.h b/driver-avalon8.h index 1e7795e483..85b96a8722 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -27,10 +27,10 @@ #define AVA8_DEFAULT_TEMP_OVERHEAT 105 #define AVA8_DEFAULT_TEMP_HYSTERESIS 5 -#define AVA8_DEFAULT_VOLTAGE_MIN 3889 -#define AVA8_DEFAULT_VOLTAGE_MAX 5059 +#define AVA8_DEFAULT_VOLTAGE_MIN 3000 +#define AVA8_DEFAULT_VOLTAGE_MAX 15000 #define AVA8_INVALID_VOLTAGE 0 -#define AVA8_DEFAULT_VOLTAGE_STEP 78 +#define AVA8_DEFAULT_VOLTAGE_STEP 125 #define AVA8_DEFAULT_VOLTAGE_LEVEL_MIN 0 #define AVA8_DEFAULT_VOLTAGE_LEVEL_MAX 15 @@ -43,12 +43,12 @@ #define AVA8_DEFAULT_FACTORY_INFO_0 0 #define AVA8_DEFAULT_FACTORY_INFO_0_MAX 15 -#define AVA8_DEFAULT_FREQUENCY_MIN 24 /* NOTE: It cann't support 0 */ -#define AVA8_DEFAULT_FREQUENCY_0 600 -#define AVA8_DEFAULT_FREQUENCY_1 636 -#define AVA8_DEFAULT_FREQUENCY_2 672 -#define AVA8_DEFAULT_FREQUENCY_3 708 -#define AVA8_DEFAULT_FREQUENCY_MAX 1404 +#define AVA8_DEFAULT_FREQUENCY_MIN 100 /* NOTE: It cann't support 0 */ +#define AVA8_DEFAULT_FREQUENCY_0 800 +#define AVA8_DEFAULT_FREQUENCY_1 800 +#define AVA8_DEFAULT_FREQUENCY_2 800 +#define AVA8_DEFAULT_FREQUENCY_3 800 +#define AVA8_DEFAULT_FREQUENCY_MAX 1200 #define AVA8_DEFAULT_FREQUENCY_SEL 0 #define AVA8_DEFAULT_MODULARS 7 /* Only support 6 modules maximum with one AUC */ @@ -57,8 +57,8 @@ #define AVA8_DEFAULT_PLL_CNT 4 #define AVA8_DEFAULT_PMU_CNT 2 -#define AVA8_DEFAULT_POLLING_DELAY 20 /* ms */ -#define AVA8_DEFAULT_NTIME_OFFSET 40 +#define AVA8_DEFAULT_POLLING_DELAY 2 /* ms */ +#define AVA8_DEFAULT_NTIME_OFFSET 1 #define AVA8_DEFAULT_SMARTSPEED_OFF 0 #define AVA8_DEFAULT_SMARTSPEED_MODE1 1 @@ -75,7 +75,7 @@ #define AVA8_PWM_MAX 0x3FF #define AVA8_DRV_DIFFMAX 500 -#define AVA8_ASIC_TIMEOUT_CONST 0x2000000 /* 2 ^ 32 / 128 */ +#define AVA8_ASIC_TIMEOUT_CONST 419430400 /* (2^32 * 1000) / (256 * 40) */ #define AVA8_MODULE_DETECT_INTERVAL 30 /* 30 s */ From 9345953d8b16bb2f91f5a4b0f58aff56a4abaf18 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 9 Nov 2017 07:15:52 -0500 Subject: [PATCH 017/113] Update P_SET_SS --- cgminer.c | 9 +++++++++ driver-avalon8.c | 21 +++++++++++++++++++++ driver-avalon8.h | 6 ++++++ 3 files changed, 36 insertions(+) diff --git a/cgminer.c b/cgminer.c index 1d9fa445ea..851199da2d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1554,6 +1554,15 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--avalon8-nonce-mask", set_int_24_to_32, opt_show_intval, &opt_avalon8_nonce_mask, "Set A3210 nonce mask, range 24-32."), + OPT_WITH_ARG("--avalon8-mux-l2h", + opt_set_intval, opt_show_intval, &opt_avalon8_mux_l2h, + "Set Avalon8 mux l2h, range 0-2."), + OPT_WITH_ARG("--avalon8-mux-h2l", + opt_set_intval, opt_show_intval, &opt_avalon8_mux_h2l, + "Set Avalon8 mux h2l, range 0-1."), + OPT_WITH_ARG("--avalon8-h2ltime0-spd", + opt_set_intval, opt_show_intval, &opt_avalon8_h2ltime0_spd, + "Set Avalon8 h2ltime0 spd, range 0-7."), #endif #ifdef USE_AVALON_MINER OPT_WITH_CBARG("--avalonm-voltage", diff --git a/driver-avalon8.c b/driver-avalon8.c index 04cbf80d11..d49120f747 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -53,6 +53,9 @@ uint32_t opt_avalon8_th_init = AVA8_DEFAULT_TH_INIT; uint32_t opt_avalon8_th_ms = AVA8_DEFAULT_TH_MS; uint32_t opt_avalon8_th_timeout = AVA8_DEFAULT_TH_TIMEOUT; uint32_t opt_avalon8_nonce_mask = AVA8_DEFAULT_NONCE_MASK; +uint32_t opt_avalon8_mux_l2h = AVA8_DEFAULT_MUX_L2H; +uint32_t opt_avalon8_mux_h2l = AVA8_DEFAULT_MUX_H2L; +uint32_t opt_avalon8_h2ltime0_spd = AVA8_DEFAULT_H2LTIME0_SPD; uint32_t cpm_table[] = { @@ -1638,6 +1641,24 @@ static void avalon8_set_ss_param(struct cgpu_info *avalon8, int addr) avalon8->drv->name, avalon8->device_id, addr, opt_avalon8_th_timeout); + tmp = be32toh(opt_avalon8_mux_l2h); + memcpy(send_pkg.data + 20, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set mux l2h %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_mux_l2h); + + tmp = be32toh(opt_avalon8_mux_h2l); + memcpy(send_pkg.data + 24, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set mux h2l %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_mux_h2l); + + tmp = be32toh(opt_avalon8_h2ltime0_spd); + memcpy(send_pkg.data + 28, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set h2ltime0 spd %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_h2ltime0_spd); + /* Package the data */ avalon8_init_pkg(&send_pkg, AVA8_P_SET_SS, 1, 1); diff --git a/driver-avalon8.h b/driver-avalon8.h index 85b96a8722..c72f6b997d 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -70,6 +70,9 @@ #define AVA8_DEFAULT_TH_MS 1 #define AVA8_DEFAULT_TH_TIMEOUT 0 #define AVA8_DEFAULT_NONCE_MASK 29 +#define AVA8_DEFAULT_MUX_L2H 0 +#define AVA8_DEFAULT_MUX_H2L 1 +#define AVA8_DEFAULT_H2LTIME0_SPD 3 #define AVA8_DEFAULT_IIC_DETECT false @@ -305,5 +308,8 @@ extern uint32_t opt_avalon8_th_init; extern uint32_t opt_avalon8_th_ms; extern uint32_t opt_avalon8_th_timeout; extern uint32_t opt_avalon8_nonce_mask; +extern uint32_t opt_avalon8_mux_l2h; +extern uint32_t opt_avalon8_mux_h2l; +extern uint32_t opt_avalon8_h2ltime0_spd; #endif /* USE_AVALON8 */ #endif /* _AVALON8_H_ */ From 9d5f0f3d9d59ff89443f64dd4c549aa4384caab7 Mon Sep 17 00:00:00 2001 From: Johnson-Fan Date: Thu, 9 Nov 2017 20:41:37 +0800 Subject: [PATCH 018/113] Update P_SET --- driver-avalon8.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index d49120f747..040c3d2ae2 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -1508,10 +1508,28 @@ static void avalon8_init_setting(struct cgpu_info *avalon8, int addr) tmp = 1; if (!opt_avalon8_smart_speed) tmp = 0; - tmp |= (0 << 1); /* Enable nonce check */ + tmp |= (1 << 1); /* Enable nonce check */ send_pkg.data[8] = tmp & 0xff; send_pkg.data[9] = opt_avalon8_nonce_mask & 0xff; + tmp = be32toh(opt_avalon8_mux_l2h); + memcpy(send_pkg.data + 10, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set mux l2h %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_mux_l2h); + + tmp = be32toh(opt_avalon8_mux_h2l); + memcpy(send_pkg.data + 14, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set mux h2l %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_mux_h2l); + + tmp = be32toh(opt_avalon8_h2ltime0_spd); + memcpy(send_pkg.data + 18, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set h2ltime0 spd %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_h2ltime0_spd); + /* Package the data */ avalon8_init_pkg(&send_pkg, AVA8_P_SET, 1, 1); if (addr == AVA8_MODULE_BROADCAST) @@ -1574,6 +1592,7 @@ static void avalon8_set_freq(struct cgpu_info *avalon8, int addr, int miner_id, avalon8->drv->name, avalon8->device_id, addr, miner_id, be32toh(tmp)); + /* Package the data */ avalon8_init_pkg(&send_pkg, AVA8_P_SET_PLL, miner_id + 1, info->miner_count[addr]); @@ -1641,24 +1660,6 @@ static void avalon8_set_ss_param(struct cgpu_info *avalon8, int addr) avalon8->drv->name, avalon8->device_id, addr, opt_avalon8_th_timeout); - tmp = be32toh(opt_avalon8_mux_l2h); - memcpy(send_pkg.data + 20, &tmp, 4); - applog(LOG_DEBUG, "%s-%d-%d: avalon8 set mux l2h %u", - avalon8->drv->name, avalon8->device_id, addr, - opt_avalon8_mux_l2h); - - tmp = be32toh(opt_avalon8_mux_h2l); - memcpy(send_pkg.data + 24, &tmp, 4); - applog(LOG_DEBUG, "%s-%d-%d: avalon8 set mux h2l %u", - avalon8->drv->name, avalon8->device_id, addr, - opt_avalon8_mux_h2l); - - tmp = be32toh(opt_avalon8_h2ltime0_spd); - memcpy(send_pkg.data + 28, &tmp, 4); - applog(LOG_DEBUG, "%s-%d-%d: avalon8 set h2ltime0 spd %u", - avalon8->drv->name, avalon8->device_id, addr, - opt_avalon8_h2ltime0_spd); - /* Package the data */ avalon8_init_pkg(&send_pkg, AVA8_P_SET_SS, 1, 1); From 7d44925e2ee8db17ddde1bd87c1ef2367bca194f Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 9 Nov 2017 22:05:13 -0500 Subject: [PATCH 019/113] Add some options for avalon8 --- cgminer.c | 25 ++++++++++++++++++------- driver-avalon8.c | 10 +++++++++- driver-avalon8.h | 4 ++++ 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/cgminer.c b/cgminer.c index 851199da2d..c305a88d08 100644 --- a/cgminer.c +++ b/cgminer.c @@ -847,9 +847,14 @@ static char *set_int_1_to_65535(const char *arg, int *i) } #ifdef USE_AVALON8 -static char *set_int_0_to_3(const char *arg, int *i) +static char *set_int_0_to_1(const char *arg, int *i) { - return set_int_range(arg, i, 0, 3); + return set_int_range(arg, i, 0, 1); +} + +static char *set_int_0_to_7(const char *arg, int *i) +{ + return set_int_range(arg, i, 0, 7); } #endif @@ -1513,8 +1518,8 @@ static struct opt_table opt_config_table[] = { set_avalon8_freq, NULL, &opt_set_avalon8_freq, "Set Avalon8 default frequency, range:[24, 1404], step: 12, example: 500"), OPT_WITH_ARG("--avalon8-freq-sel", - set_int_0_to_3, opt_show_intval, &opt_avalon8_freq_sel, - "Set Avalon8 default frequency select, range:[0, 3], step: 1, example: 3"), + set_int_0_to_4, opt_show_intval, &opt_avalon8_freq_sel, + "Set Avalon8 default frequency select, range:[0, 4], step: 1, example: 3"), OPT_WITH_CBARG("--avalon8-fan", set_avalon8_fan, NULL, &opt_set_avalon8_fan, "Set Avalon8 target fan speed, range:[0, 100], step: 1, example: 0-100"), @@ -1548,20 +1553,26 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--avalon8-th-timeout", opt_set_uintval, opt_show_uintval, &opt_avalon8_th_timeout, "Set A3210 th timeout value"), + OPT_WITH_ARG("--avalon8-th-add", + set_int_0_to_1, opt_show_intval, &opt_avalon8_th_add, + "Set A3210 th add value"), OPT_WITHOUT_ARG("--avalon8-iic-detect", opt_set_bool, &opt_avalon8_iic_detect, "Enable Avalon8 detect through iic controller"), OPT_WITH_ARG("--avalon8-nonce-mask", set_int_24_to_32, opt_show_intval, &opt_avalon8_nonce_mask, "Set A3210 nonce mask, range 24-32."), + OPT_WITH_ARG("--avalon8-nonce-check", + set_int_0_to_1, opt_show_intval, &opt_avalon8_nonce_check, + "Set A3210 nonce check, range 0-1."), OPT_WITH_ARG("--avalon8-mux-l2h", - opt_set_intval, opt_show_intval, &opt_avalon8_mux_l2h, + set_int_0_to_2, opt_show_intval, &opt_avalon8_mux_l2h, "Set Avalon8 mux l2h, range 0-2."), OPT_WITH_ARG("--avalon8-mux-h2l", - opt_set_intval, opt_show_intval, &opt_avalon8_mux_h2l, + set_int_0_to_1, opt_show_intval, &opt_avalon8_mux_h2l, "Set Avalon8 mux h2l, range 0-1."), OPT_WITH_ARG("--avalon8-h2ltime0-spd", - opt_set_intval, opt_show_intval, &opt_avalon8_h2ltime0_spd, + set_int_0_to_7, opt_show_intval, &opt_avalon8_h2ltime0_spd, "Set Avalon8 h2ltime0 spd, range 0-7."), #endif #ifdef USE_AVALON_MINER diff --git a/driver-avalon8.c b/driver-avalon8.c index 040c3d2ae2..079604752a 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -52,7 +52,9 @@ uint32_t opt_avalon8_th_fail = AVA8_DEFAULT_TH_FAIL; uint32_t opt_avalon8_th_init = AVA8_DEFAULT_TH_INIT; uint32_t opt_avalon8_th_ms = AVA8_DEFAULT_TH_MS; uint32_t opt_avalon8_th_timeout = AVA8_DEFAULT_TH_TIMEOUT; +uint32_t opt_avalon8_th_add = AVA8_DEFAULT_TH_ADD; uint32_t opt_avalon8_nonce_mask = AVA8_DEFAULT_NONCE_MASK; +uint32_t opt_avalon8_nonce_check = AVA8_DEFAULT_NONCE_CHECK; uint32_t opt_avalon8_mux_l2h = AVA8_DEFAULT_MUX_L2H; uint32_t opt_avalon8_mux_h2l = AVA8_DEFAULT_MUX_H2L; uint32_t opt_avalon8_h2ltime0_spd = AVA8_DEFAULT_H2LTIME0_SPD; @@ -1508,7 +1510,7 @@ static void avalon8_init_setting(struct cgpu_info *avalon8, int addr) tmp = 1; if (!opt_avalon8_smart_speed) tmp = 0; - tmp |= (1 << 1); /* Enable nonce check */ + tmp |= (opt_avalon8_nonce_check << 1); send_pkg.data[8] = tmp & 0xff; send_pkg.data[9] = opt_avalon8_nonce_mask & 0xff; @@ -1660,6 +1662,12 @@ static void avalon8_set_ss_param(struct cgpu_info *avalon8, int addr) avalon8->drv->name, avalon8->device_id, addr, opt_avalon8_th_timeout); + tmp = be32toh(opt_avalon8_th_add); + memcpy(send_pkg.data + 20, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set th add %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_th_add); + /* Package the data */ avalon8_init_pkg(&send_pkg, AVA8_P_SET_SS, 1, 1); diff --git a/driver-avalon8.h b/driver-avalon8.h index c72f6b997d..ea95834658 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -67,9 +67,11 @@ #define AVA8_DEFAULT_TH_PASS (162) #define AVA8_DEFAULT_TH_FAIL (10921) #define AVA8_DEFAULT_TH_INIT (0xffff / 2) +#define AVA8_DEFAULT_TH_ADD 0 #define AVA8_DEFAULT_TH_MS 1 #define AVA8_DEFAULT_TH_TIMEOUT 0 #define AVA8_DEFAULT_NONCE_MASK 29 +#define AVA8_DEFAULT_NONCE_CHECK 1 #define AVA8_DEFAULT_MUX_L2H 0 #define AVA8_DEFAULT_MUX_H2L 1 #define AVA8_DEFAULT_H2LTIME0_SPD 3 @@ -307,7 +309,9 @@ extern uint32_t opt_avalon8_th_fail; extern uint32_t opt_avalon8_th_init; extern uint32_t opt_avalon8_th_ms; extern uint32_t opt_avalon8_th_timeout; +extern uint32_t opt_avalon8_th_add; extern uint32_t opt_avalon8_nonce_mask; +extern uint32_t opt_avalon8_nonce_check; extern uint32_t opt_avalon8_mux_l2h; extern uint32_t opt_avalon8_mux_h2l; extern uint32_t opt_avalon8_h2ltime0_spd; From ba8dac4d27326c660f697df28a8e785e15105cf4 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Fri, 10 Nov 2017 00:39:24 -0500 Subject: [PATCH 020/113] Update cpm --- driver-avalon8.c | 68 ++++++++++++++++++++++++++++++++++-------------- driver-avalon8.h | 2 +- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 079604752a..c9bc5ae906 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -61,19 +61,53 @@ uint32_t opt_avalon8_h2ltime0_spd = AVA8_DEFAULT_H2LTIME0_SPD; uint32_t cpm_table[] = { - 0x008ffbe1, - 0x009fffe1, - 0x009fbfe1, - 0x009da761, - 0x009f9fe1, - 0x009d9761, - 0x00978de1, - 0x009b8ee1, - 0x009f8fe1, - 0x00918461, - 0x009384e1, - 0x00958561, - 0x009785e1 + 0x8ffbe1, + 0x97fde1, + 0x9fffe1, + 0x9ddf61, + 0x9dcf61, + 0x9f47c1, + 0x9fbfe1, + 0x9f37c1, + 0x9daf61, + 0x9b26c1, + 0x9da761, + 0x999e61, + 0x9b9ee1, + 0x9d9f61, + 0x9f9fe1, + 0x991641, + 0x9a96a1, + 0x9c1701, + 0x9d9761, + 0x9f17c1, + 0x958d61, + 0x968da1, + 0x978de1, + 0x988e21, + 0x998e61, + 0x9a8ea1, + 0x9b8ee1, + 0x9c8f21, + 0x9d8f61, + 0x9e8fa1, + 0x9f8fe1, + 0x900401, + 0x908421, + 0x910441, + 0x918461, + 0x920481, + 0x9284a1, + 0x9304c1, + 0x9384e1, + 0x940501, + 0x948521, + 0x950541, + 0x958561, + 0x960581, + 0x9685a1, + 0x9705c1, + 0x9785e1 }; struct avalon8_dev_description avalon8_dev_table[] = { @@ -90,13 +124,7 @@ struct avalon8_dev_description avalon8_dev_table[] = { static uint32_t api_get_cpm(uint32_t freq) { - uint8_t idx; - - idx = freq / 100; - if (idx >= (sizeof(cpm_table) / sizeof(cpm_table[0]))) - idx = sizeof(cpm_table) / sizeof(cpm_table[0]) - 1; - - return cpm_table[idx]; + return cpm_table[freq / 25 - 2]; } static uint32_t encode_voltage(uint32_t volt) diff --git a/driver-avalon8.h b/driver-avalon8.h index ea95834658..f58a72897c 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -43,7 +43,7 @@ #define AVA8_DEFAULT_FACTORY_INFO_0 0 #define AVA8_DEFAULT_FACTORY_INFO_0_MAX 15 -#define AVA8_DEFAULT_FREQUENCY_MIN 100 /* NOTE: It cann't support 0 */ +#define AVA8_DEFAULT_FREQUENCY_MIN 50 /* NOTE: It cann't support 0 */ #define AVA8_DEFAULT_FREQUENCY_0 800 #define AVA8_DEFAULT_FREQUENCY_1 800 #define AVA8_DEFAULT_FREQUENCY_2 800 From 8777d3ac9b7084e6fcc27e8859a574276a573f10 Mon Sep 17 00:00:00 2001 From: Mikeqin Date: Fri, 10 Nov 2017 20:14:13 +0800 Subject: [PATCH 021/113] Add PVT_T --- driver-avalon8.c | 15 ++++++++------- driver-avalon8.h | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index c9bc5ae906..a5c4be56f3 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -158,13 +158,14 @@ static uint16_t decode_vin(struct avalon8_info *info, int modular_id, uint16_t v static double decode_pvt_temp(uint16_t pvt_code) { - double a4 = -1.1876E-11; - double a3 = 6.6675E-08; - double a2 = -1.7724E-04; - double a1 = 3.3691E-01; - double a0 = -6.0605E+01; - - return a4 * pow(pvt_code, 4) + a3 * pow(pvt_code, 3) + a2 * pow(pvt_code, 2) + a1 * pow(pvt_code, 1) + a0; + double g = 60.0; + double h = 200.0; + double cal5 = 4094.0; + double j = -0.1; + double fclkm = 6.25; + + /* Mode2 temperature equation */ + return g + h * (pvt_code / cal5 - 0.5) + j * fclkm; } #define SERIESRESISTOR 10000 diff --git a/driver-avalon8.h b/driver-avalon8.h index f58a72897c..e811129875 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -230,6 +230,7 @@ struct avalon8_info { int fan_pct[AVA8_DEFAULT_MODULARS]; int fan_cpm[AVA8_DEFAULT_MODULARS]; + /* min pos, min temp, max pos, max temp, avg temp */ int temp[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][5]; int temp_mm[AVA8_DEFAULT_MODULARS]; From 87b5aead6979b22754823215007c5086bad098bf Mon Sep 17 00:00:00 2001 From: Mikeqin Date: Sat, 11 Nov 2017 11:48:54 +0800 Subject: [PATCH 022/113] Update PVT_T && Add PVT_V --- driver-avalon8.c | 75 ++++++++++++++++++++++++++++++++---------------- driver-avalon8.h | 7 +++-- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index a5c4be56f3..337024acc1 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -168,6 +168,20 @@ static double decode_pvt_temp(uint16_t pvt_code) return g + h * (pvt_code / cal5 - 0.5) + j * fclkm; } +static uint32_t decode_pvt_volt(uint16_t volt) +{ + double vref = 1.20; + double r = 16384.0; /* 2 ** 14 */ + double c; + + c = vref / 5.0 * (6 * (volt - 0.5) / r - 1.0); + + if (c < 0) + c = 0; + + return c * 1000; +} + #define SERIESRESISTOR 10000 #define THERMISTORNOMINAL 10000 #define BCOEFFICIENT 3500 @@ -617,22 +631,24 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod break; case AVA8_P_STATUS_PVT: applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_PVT", avalon8->drv->name, avalon8->device_id, modular_id); - for (i = 0; i < info->miner_count[modular_id]; i++) { - memcpy(&tmp, ar->data + i * 8, 4); - tmp = be32toh(tmp); - info->temp[modular_id][i][0] = (tmp >> 24) & 0xff; - info->temp[modular_id][i][1] = (tmp >> 16) & 0xff; - info->temp[modular_id][i][2] = tmp & 0xffff; - - memcpy(&tmp, ar->data + (i + 1) * 8 - 4, 4); - tmp = be32toh(tmp); - info->temp[modular_id][i][3] = (tmp >> 16) & 0xffff; - info->temp[modular_id][i][4] = tmp & 0xffff; - - /* Update the pvt code to real temperature */ - info->temp[modular_id][i][2] = (int)decode_pvt_temp((uint16_t)info->temp[modular_id][i][2]); - info->temp[modular_id][i][3] = (int)decode_pvt_temp((uint16_t)info->temp[modular_id][i][3]); - info->temp[modular_id][i][4] = (int)decode_pvt_temp((uint16_t)info->temp[modular_id][i][4]); + { + uint16_t pvt_tmp; + + if (!info->asic_count[modular_id]) + break; + + miner = ar->idx / info->asic_count[modular_id]; + chip_id = ar->idx % info->asic_count[modular_id]; + + memcpy(&pvt_tmp, ar->data, 2); + pvt_tmp = be16toh(pvt_tmp); + info->temp[modular_id][miner][chip_id] = decode_pvt_temp(pvt_tmp); + + for (i = 0; i < AVA8_DEFAULT_CORE_VOLT_CNT; i++) { + memcpy(&pvt_tmp, ar->data + 2 + 2 * i, 2); + pvt_tmp = be16toh(pvt_tmp); + info->core_volt[modular_id][miner][chip_id][i] = decode_pvt_volt(pvt_tmp); + } } break; case AVA8_P_STATUS_FAC: @@ -1930,7 +1946,7 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) { struct api_data *root = NULL; struct avalon8_info *info = avalon8->device_data; - int i, j, k; + int i, j, k, m; char buf[256]; char *statbuf = NULL; struct timeval current; @@ -2098,17 +2114,28 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) strcat(statbuf, " PVT_T["); for (j = 0; j < info->miner_count[i]; j++) { - sprintf(buf, "%d-%d/%d-%d/%d ", - info->temp[i][j][0], - info->temp[i][j][2], - info->temp[i][j][1], - info->temp[i][j][3], - info->temp[i][j][4]); - strcat(statbuf, buf); + for (k = 0; k < info->asic_count[i]; k++) { + sprintf(buf, "%d ", info->temp[i][j][k]); + strcat(statbuf, buf); + } } statbuf[strlen(statbuf) - 1] = ']'; statbuf[strlen(statbuf)] = '\0'; + for (j = 0; j < info->miner_count[i]; j++) { + for (k = 0; k < info->asic_count[i]; k++) { + sprintf(buf, " PVT_V%d_%d[", j, k); + strcat(statbuf, buf); + for (m = 0; m < AVA8_DEFAULT_CORE_VOLT_CNT; m++) { + sprintf(buf, "%d ", info->core_volt[i][j][k][m]); + strcat(statbuf, buf); + } + + statbuf[strlen(statbuf) - 1] = ']'; + statbuf[strlen(statbuf)] = '\0'; + } + } + sprintf(buf, "MM ID%d", i); root = api_add_string(root, buf, statbuf, true); } diff --git a/driver-avalon8.h b/driver-avalon8.h index e811129875..4a99011dec 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -56,6 +56,7 @@ #define AVA8_DEFAULT_ASIC_MAX 26 #define AVA8_DEFAULT_PLL_CNT 4 #define AVA8_DEFAULT_PMU_CNT 2 +#define AVA8_DEFAULT_CORE_VOLT_CNT 8 #define AVA8_DEFAULT_POLLING_DELAY 2 /* ms */ #define AVA8_DEFAULT_NTIME_OFFSET 1 @@ -230,10 +231,12 @@ struct avalon8_info { int fan_pct[AVA8_DEFAULT_MODULARS]; int fan_cpm[AVA8_DEFAULT_MODULARS]; - /* min pos, min temp, max pos, max temp, avg temp */ - int temp[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][5]; + int temp[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_ASIC_MAX]; int temp_mm[AVA8_DEFAULT_MODULARS]; + uint32_t core_volt[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT] \ + [AVA8_DEFAULT_ASIC_MAX][AVA8_DEFAULT_CORE_VOLT_CNT]; + uint8_t cutoff[AVA8_DEFAULT_MODULARS]; int temp_target[AVA8_DEFAULT_MODULARS]; int temp_last_max[AVA8_DEFAULT_MODULARS]; From 3a9468a862d5ae68edaba4703c9a05083d86e497 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Sat, 11 Nov 2017 06:24:52 -0500 Subject: [PATCH 023/113] Update cpm --- cgminer.c | 2 +- driver-avalon8.c | 98 ++++++++++++++++++++++++------------------------ driver-avalon8.h | 2 +- 3 files changed, 52 insertions(+), 50 deletions(-) diff --git a/cgminer.c b/cgminer.c index c305a88d08..ba3143cafe 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1516,7 +1516,7 @@ static struct opt_table opt_config_table[] = { "Set Avalon8 default offset of core voltage, range:[-2, 1], step: 1"), OPT_WITH_CBARG("--avalon8-freq", set_avalon8_freq, NULL, &opt_set_avalon8_freq, - "Set Avalon8 default frequency, range:[24, 1404], step: 12, example: 500"), + "Set Avalon8 default frequency, range:[25, 1200], step: 25, example: 800"), OPT_WITH_ARG("--avalon8-freq-sel", set_int_0_to_4, opt_show_intval, &opt_avalon8_freq_sel, "Set Avalon8 default frequency select, range:[0, 4], step: 1, example: 3"), diff --git a/driver-avalon8.c b/driver-avalon8.c index 337024acc1..17464cdf33 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -61,53 +61,55 @@ uint32_t opt_avalon8_h2ltime0_spd = AVA8_DEFAULT_H2LTIME0_SPD; uint32_t cpm_table[] = { - 0x8ffbe1, - 0x97fde1, - 0x9fffe1, - 0x9ddf61, - 0x9dcf61, - 0x9f47c1, - 0x9fbfe1, - 0x9f37c1, - 0x9daf61, - 0x9b26c1, - 0x9da761, - 0x999e61, - 0x9b9ee1, - 0x9d9f61, - 0x9f9fe1, - 0x991641, - 0x9a96a1, - 0x9c1701, - 0x9d9761, - 0x9f17c1, - 0x958d61, - 0x968da1, - 0x978de1, - 0x988e21, - 0x998e61, - 0x9a8ea1, - 0x9b8ee1, - 0x9c8f21, - 0x9d8f61, - 0x9e8fa1, - 0x9f8fe1, - 0x900401, - 0x908421, - 0x910441, - 0x918461, - 0x920481, - 0x9284a1, - 0x9304c1, - 0x9384e1, - 0x940501, - 0x948521, - 0x950541, - 0x958561, - 0x960581, - 0x9685a1, - 0x9705c1, - 0x9785e1 + 0x04000000, + 0x04000000, + 0x008ffbe1, + 0x0097fde1, + 0x009fffe1, + 0x009ddf61, + 0x009dcf61, + 0x009f47c1, + 0x009fbfe1, + 0x009f37c1, + 0x009daf61, + 0x009b26c1, + 0x009da761, + 0x00999e61, + 0x009b9ee1, + 0x009d9f61, + 0x009f9fe1, + 0x00991641, + 0x009a96a1, + 0x009c1701, + 0x009d9761, + 0x009f17c1, + 0x00958d61, + 0x00968da1, + 0x00978de1, + 0x00988e21, + 0x00998e61, + 0x009a8ea1, + 0x009b8ee1, + 0x009c8f21, + 0x009d8f61, + 0x009e8fa1, + 0x009f8fe1, + 0x00900401, + 0x00908421, + 0x00910441, + 0x00918461, + 0x00920481, + 0x009284a1, + 0x009304c1, + 0x009384e1, + 0x00940501, + 0x00948521, + 0x00950541, + 0x00958561, + 0x00960581, + 0x009685a1, + 0x009705c1, + 0x009785e1 }; struct avalon8_dev_description avalon8_dev_table[] = { @@ -124,7 +126,7 @@ struct avalon8_dev_description avalon8_dev_table[] = { static uint32_t api_get_cpm(uint32_t freq) { - return cpm_table[freq / 25 - 2]; + return cpm_table[freq / 25]; } static uint32_t encode_voltage(uint32_t volt) diff --git a/driver-avalon8.h b/driver-avalon8.h index 4a99011dec..be1814afb2 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -43,7 +43,7 @@ #define AVA8_DEFAULT_FACTORY_INFO_0 0 #define AVA8_DEFAULT_FACTORY_INFO_0_MAX 15 -#define AVA8_DEFAULT_FREQUENCY_MIN 50 /* NOTE: It cann't support 0 */ +#define AVA8_DEFAULT_FREQUENCY_MIN 25 /* NOTE: It cann't support 0 */ #define AVA8_DEFAULT_FREQUENCY_0 800 #define AVA8_DEFAULT_FREQUENCY_1 800 #define AVA8_DEFAULT_FREQUENCY_2 800 From 82166472de5c5707d382981a57633d47c5fb52a2 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Sat, 11 Nov 2017 06:49:41 -0500 Subject: [PATCH 024/113] Update P_SET_VOLT --- driver-avalon8.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 17464cdf33..1136e7a802 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -137,7 +137,7 @@ static uint32_t encode_voltage(uint32_t volt) if (volt < AVA8_DEFAULT_VOLTAGE_MIN) volt = AVA8_DEFAULT_VOLTAGE_MIN; - return 0x60 - ((volt - AVA8_DEFAULT_VOLTAGE_MIN) / AVA8_DEFAULT_VOLTAGE_STEP); + return 0x8000 | ((volt - AVA8_DEFAULT_VOLTAGE_MIN) / AVA8_DEFAULT_VOLTAGE_STEP); } static uint32_t convert_voltage_level(uint32_t level) @@ -1598,7 +1598,8 @@ static void avalon8_set_voltage(struct cgpu_info *avalon8, int addr, unsigned in /* NOTE: miner_count should <= 8 */ for (i = 0; i < info->miner_count[addr]; i++) { - tmp = be32toh(encode_voltage(voltage[i])); + tmp = be32toh(encode_voltage(voltage[i] + + opt_avalon8_voltage_offset * AVA8_DEFAULT_VOLTAGE_STEP)); memcpy(send_pkg.data + i * 4, &tmp, 4); } applog(LOG_DEBUG, "%s-%d-%d: avalon8 set voltage miner %d, (%d-%d)", From 2454a71859fe5ce071997b239382e4650612eb43 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Sat, 11 Nov 2017 07:22:31 -0500 Subject: [PATCH 025/113] Support 4 miners --- driver-avalon8.c | 54 +++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 1136e7a802..35fc7ff6b9 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -116,8 +116,8 @@ struct avalon8_dev_description avalon8_dev_table[] = { { "821", 821, - 1, - 2, + 4, + 24, AVA8_MM821_VIN_ADC_RATIO, AVA8_MM821_VOUT_ADC_RATIO, 4500, @@ -2103,6 +2103,32 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) strcat(statbuf, buf); } statbuf[strlen(statbuf) - 1] = ']'; + + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, " PVT_T%d[", j); + strcat(statbuf, buf); + for (k = 0; k < info->asic_count[i]; k++) { + sprintf(buf, "%d ", info->temp[i][j][k]); + strcat(statbuf, buf); + } + + statbuf[strlen(statbuf) - 1] = ']'; + statbuf[strlen(statbuf)] = '\0'; + } + + for (j = 0; j < info->miner_count[i]; j++) { + for (k = 0; k < info->asic_count[i]; k++) { + sprintf(buf, " PVT_V%d_%d[", j, k); + strcat(statbuf, buf); + for (m = 0; m < AVA8_DEFAULT_CORE_VOLT_CNT; m++) { + sprintf(buf, "%d ", info->core_volt[i][j][k][m]); + strcat(statbuf, buf); + } + + statbuf[strlen(statbuf) - 1] = ']'; + statbuf[strlen(statbuf)] = '\0'; + } + } } sprintf(buf, " FM[%d]", info->freq_mode[i]); @@ -2115,30 +2141,6 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) } statbuf[strlen(statbuf) - 1] = ']'; - strcat(statbuf, " PVT_T["); - for (j = 0; j < info->miner_count[i]; j++) { - for (k = 0; k < info->asic_count[i]; k++) { - sprintf(buf, "%d ", info->temp[i][j][k]); - strcat(statbuf, buf); - } - } - statbuf[strlen(statbuf) - 1] = ']'; - statbuf[strlen(statbuf)] = '\0'; - - for (j = 0; j < info->miner_count[i]; j++) { - for (k = 0; k < info->asic_count[i]; k++) { - sprintf(buf, " PVT_V%d_%d[", j, k); - strcat(statbuf, buf); - for (m = 0; m < AVA8_DEFAULT_CORE_VOLT_CNT; m++) { - sprintf(buf, "%d ", info->core_volt[i][j][k][m]); - strcat(statbuf, buf); - } - - statbuf[strlen(statbuf) - 1] = ']'; - statbuf[strlen(statbuf)] = '\0'; - } - } - sprintf(buf, "MM ID%d", i); root = api_add_string(root, buf, statbuf, true); } From a6006fe6890900d0e54f13738c7939e2905fcd89 Mon Sep 17 00:00:00 2001 From: JianXiongZ Date: Mon, 13 Nov 2017 19:33:29 +0800 Subject: [PATCH 026/113] Add max temperature display --- driver-avalon8.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 35fc7ff6b9..566eaf5c48 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -381,12 +381,14 @@ static int job_idcmp(uint8_t *job_id, char *pool_job_id) static inline int get_temp_max(struct avalon8_info *info, int addr) { - int i; + int i, j; int max = -273; for (i = 0; i < info->miner_count[addr]; i++) { - if (info->temp[addr][i][3] > max) - max = info->temp[addr][i][3]; + for (j = 0; j < info->asic_count[addr]; j++) { + if (info->temp[addr][i][j] > max) + max = info->temp[addr][i][j]; + } } if (max < info->temp_mm[addr]) From 115eb0a4886c125f3c697f0306a8e88ede661362 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Tue, 14 Nov 2017 05:00:21 -0500 Subject: [PATCH 027/113] Update cpm --- driver-avalon8.c | 18 +++++++----------- driver-avalon8.h | 1 - 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 566eaf5c48..24f670b83e 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -61,7 +61,7 @@ uint32_t opt_avalon8_h2ltime0_spd = AVA8_DEFAULT_H2LTIME0_SPD; uint32_t cpm_table[] = { - 0x04000000, + 0x04400000, 0x04000000, 0x008ffbe1, 0x0097fde1, @@ -266,7 +266,7 @@ char *set_avalon8_freq(char *arg) /* last value */ if (*data) { val[i] = atoi(data); - if (val[i] < AVA8_DEFAULT_FREQUENCY_MIN || val[i] > AVA8_DEFAULT_FREQUENCY_MAX) + if (val[i] > AVA8_DEFAULT_FREQUENCY_MAX) return "Invalid value passed to avalon8-freq"; } break; @@ -274,17 +274,14 @@ char *set_avalon8_freq(char *arg) if (*data) { val[i] = atoi(data); - if (val[i] < AVA8_DEFAULT_FREQUENCY_MIN || val[i] > AVA8_DEFAULT_FREQUENCY_MAX) + if (val[i] > AVA8_DEFAULT_FREQUENCY_MAX) return "Invalid value passed to avalon8-freq"; } data = colon; } - for (i = 0; i < AVA8_DEFAULT_PLL_CNT; i++) { - if (!val[i] && i) - val[i] = val[i - 1]; + for (i = 0; i < AVA8_DEFAULT_PLL_CNT; i++) opt_avalon8_freq[i] = val[i]; - } return NULL; } @@ -1633,6 +1630,8 @@ static void avalon8_set_freq(struct cgpu_info *avalon8, int addr, int miner_id, for (i = 1; i < AVA8_DEFAULT_PLL_CNT; i++) f = f > freq[i] ? f : freq[i]; + f = f ? f : 1; + tmp = ((AVA8_ASIC_TIMEOUT_CONST / f) * AVA8_DEFAULT_NTIME_OFFSET * 5 / 100); tmp = be32toh(tmp); memcpy(send_pkg.data + AVA8_DEFAULT_PLL_CNT * 4, &tmp, 4); @@ -1644,7 +1643,6 @@ static void avalon8_set_freq(struct cgpu_info *avalon8, int addr, int miner_id, avalon8->drv->name, avalon8->device_id, addr, miner_id, be32toh(tmp)); - /* Package the data */ avalon8_init_pkg(&send_pkg, AVA8_P_SET_PLL, miner_id + 1, info->miner_count[addr]); @@ -2248,10 +2246,8 @@ char *set_avalon8_device_freq(struct cgpu_info *avalon8, char *arg) return NULL; sscanf(arg, "%d-%d-%d", &val, &addr, &miner_id); - if (!val) - val = AVA8_DEFAULT_FREQUENCY_MIN; - if (val < AVA8_DEFAULT_FREQUENCY_MIN || val > AVA8_DEFAULT_FREQUENCY_MAX) + if (val > AVA8_DEFAULT_FREQUENCY_MAX) return "Invalid value passed to set_avalon8_device_freq"; if (addr >= AVA8_DEFAULT_MODULARS) { diff --git a/driver-avalon8.h b/driver-avalon8.h index be1814afb2..54b56dd35e 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -43,7 +43,6 @@ #define AVA8_DEFAULT_FACTORY_INFO_0 0 #define AVA8_DEFAULT_FACTORY_INFO_0_MAX 15 -#define AVA8_DEFAULT_FREQUENCY_MIN 25 /* NOTE: It cann't support 0 */ #define AVA8_DEFAULT_FREQUENCY_0 800 #define AVA8_DEFAULT_FREQUENCY_1 800 #define AVA8_DEFAULT_FREQUENCY_2 800 From f64284dfffb88c73826bf643d24abb4444122f9e Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Tue, 14 Nov 2017 05:06:00 -0500 Subject: [PATCH 028/113] Add a new option for avalon8 * --avalon8-roll-enable --- cgminer.c | 3 +++ driver-avalon8.c | 3 +++ driver-avalon8.h | 2 ++ 3 files changed, 8 insertions(+) diff --git a/cgminer.c b/cgminer.c index ba3143cafe..c79a26e60f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1565,6 +1565,9 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--avalon8-nonce-check", set_int_0_to_1, opt_show_intval, &opt_avalon8_nonce_check, "Set A3210 nonce check, range 0-1."), + OPT_WITH_ARG("--avalon8-roll-enable", + set_int_0_to_1, opt_show_intval, &opt_avalon8_roll_enable, + "Set A3210 roll enable, range 0-1."), OPT_WITH_ARG("--avalon8-mux-l2h", set_int_0_to_2, opt_show_intval, &opt_avalon8_mux_l2h, "Set Avalon8 mux l2h, range 0-2."), diff --git a/driver-avalon8.c b/driver-avalon8.c index 24f670b83e..f88ad1d037 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -58,6 +58,7 @@ uint32_t opt_avalon8_nonce_check = AVA8_DEFAULT_NONCE_CHECK; uint32_t opt_avalon8_mux_l2h = AVA8_DEFAULT_MUX_L2H; uint32_t opt_avalon8_mux_h2l = AVA8_DEFAULT_MUX_H2L; uint32_t opt_avalon8_h2ltime0_spd = AVA8_DEFAULT_H2LTIME0_SPD; +uint32_t opt_avalon8_roll_enable = AVA8_DEFAULT_ROLL_ENABLE; uint32_t cpm_table[] = { @@ -1552,11 +1553,13 @@ static void avalon8_init_setting(struct cgpu_info *avalon8, int addr) * set flags: * 0: ss switch * 1: nonce check + * 2: roll enable */ tmp = 1; if (!opt_avalon8_smart_speed) tmp = 0; tmp |= (opt_avalon8_nonce_check << 1); + tmp |= (opt_avalon8_roll_enable << 2); send_pkg.data[8] = tmp & 0xff; send_pkg.data[9] = opt_avalon8_nonce_mask & 0xff; diff --git a/driver-avalon8.h b/driver-avalon8.h index 54b56dd35e..0d46d9af3a 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -75,6 +75,7 @@ #define AVA8_DEFAULT_MUX_L2H 0 #define AVA8_DEFAULT_MUX_H2L 1 #define AVA8_DEFAULT_H2LTIME0_SPD 3 +#define AVA8_DEFAULT_ROLL_ENABLE 1 #define AVA8_DEFAULT_IIC_DETECT false @@ -318,5 +319,6 @@ extern uint32_t opt_avalon8_nonce_check; extern uint32_t opt_avalon8_mux_l2h; extern uint32_t opt_avalon8_mux_h2l; extern uint32_t opt_avalon8_h2ltime0_spd; +extern uint32_t opt_avalon8_roll_enable; #endif /* USE_AVALON8 */ #endif /* _AVALON8_H_ */ From 2ebc27aae188c2d71f72fbc2cfe685a859a6c464 Mon Sep 17 00:00:00 2001 From: xzx Date: Tue, 14 Nov 2017 19:35:19 +0800 Subject: [PATCH 029/113] Support Vi and Vo display --- driver-avalon8.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver-avalon8.h b/driver-avalon8.h index 0d46d9af3a..b56b5b26ec 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -161,8 +161,8 @@ #define AVA8_DEFAULT_FACTORY_INFO_CNT 1 -#define AVA8_MM821_VIN_ADC_RATIO (3.3 / 1024.0 * 27.15 / 7.15 * 1000.0 * 100.0) -#define AVA8_MM821_VOUT_ADC_RATIO (3.3 / 1024.0 * 63.0 / 20.0 * 10000.0 * 100.0) +#define AVA8_MM821_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) +#define AVA8_MM821_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) struct avalon8_pkg { uint8_t head[2]; From 6944723e35168e2c14a7d2af7e9f41e3647ffb2c Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Wed, 15 Nov 2017 08:53:25 -0500 Subject: [PATCH 030/113] Update options for avalon8 * Add a new --avalon8-voltage-level-offset option * Update --avalon8-voltage-level option * Remove --avlaon8-voltage-offset option * Remove --avlaon8-voltage option --- cgminer.c | 12 ++-- driver-avalon8.c | 140 ++++++++--------------------------------------- driver-avalon8.h | 21 +++---- 3 files changed, 35 insertions(+), 138 deletions(-) diff --git a/cgminer.c b/cgminer.c index c79a26e60f..33a20ca3b2 100644 --- a/cgminer.c +++ b/cgminer.c @@ -275,9 +275,8 @@ static char *opt_set_avalon7_freq; #endif #ifdef USE_AVALON8 static char *opt_set_avalon8_fan; -static char *opt_set_avalon8_voltage; static char *opt_set_avalon8_voltage_level; -static char *opt_set_avalon8_voltage_offset; +static char *opt_set_avalon8_voltage_level_offset; static char *opt_set_avalon8_freq; #endif #ifdef USE_AVALON_MINER @@ -1505,15 +1504,12 @@ static struct opt_table opt_config_table[] = { "Enable avalon7 smart speed plus."), #endif #ifdef USE_AVALON8 - OPT_WITH_CBARG("--avalon8-voltage", - set_avalon8_voltage, NULL, &opt_set_avalon8_voltage, - "Set Avalon8 default core voltage, in millivolts, step: 78"), OPT_WITH_CBARG("--avalon8-voltage-level", set_avalon8_voltage_level, NULL, &opt_set_avalon8_voltage_level, "Set Avalon8 default level of core voltage, range:[0, 15], step: 1"), - OPT_WITH_CBARG("--avalon8-voltage-offset", - set_avalon8_voltage_offset, NULL, &opt_set_avalon8_voltage_offset, - "Set Avalon8 default offset of core voltage, range:[-2, 1], step: 1"), + OPT_WITH_CBARG("--avalon8-voltage-level-offset", + set_avalon8_voltage_level_offset, NULL, &opt_set_avalon8_voltage_level_offset, + "Set Avalon8 default offset of core voltage level, range:[-2, 1], step: 1"), OPT_WITH_CBARG("--avalon8-freq", set_avalon8_freq, NULL, &opt_set_avalon8_freq, "Set Avalon8 default frequency, range:[25, 1200], step: 25, example: 800"), diff --git a/driver-avalon8.c b/driver-avalon8.c index f88ad1d037..5b9d3da71e 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -24,8 +24,8 @@ int opt_avalon8_temp_target = AVA8_DEFAULT_TEMP_TARGET; int opt_avalon8_fan_min = AVA8_DEFAULT_FAN_MIN; int opt_avalon8_fan_max = AVA8_DEFAULT_FAN_MAX; -int opt_avalon8_voltage = AVA8_INVALID_VOLTAGE; -int opt_avalon8_voltage_offset = AVA8_DEFAULT_VOLTAGE_OFFSET; +int opt_avalon8_voltage_level = AVA8_INVALID_VOLTAGE_LEVEL; +int opt_avalon8_voltage_level_offset = AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET; int opt_avalon8_freq[AVA8_DEFAULT_PLL_CNT] = {AVA8_DEFAULT_FREQUENCY_0, AVA8_DEFAULT_FREQUENCY_1, @@ -130,23 +130,17 @@ static uint32_t api_get_cpm(uint32_t freq) return cpm_table[freq / 25]; } -static uint32_t encode_voltage(uint32_t volt) +static uint32_t encode_voltage(int volt_level) { - if (volt > AVA8_DEFAULT_VOLTAGE_MAX) - volt = AVA8_DEFAULT_VOLTAGE_MAX; + if (volt_level > AVA8_DEFAULT_VOLTAGE_LEVEL_MAX) + volt_level = AVA8_DEFAULT_VOLTAGE_LEVEL_MAX; + else if (volt_level < AVA8_DEFAULT_VOLTAGE_LEVEL_MIN) + volt_level = AVA8_DEFAULT_VOLTAGE_LEVEL_MIN; - if (volt < AVA8_DEFAULT_VOLTAGE_MIN) - volt = AVA8_DEFAULT_VOLTAGE_MIN; + if (volt_level < 0) + return 0x8080 | (-volt_level); - return 0x8000 | ((volt - AVA8_DEFAULT_VOLTAGE_MIN) / AVA8_DEFAULT_VOLTAGE_STEP); -} - -static uint32_t convert_voltage_level(uint32_t level) -{ - if (level > AVA8_DEFAULT_VOLTAGE_LEVEL_MAX) - level = AVA8_DEFAULT_VOLTAGE_LEVEL_MAX; - - return AVA8_DEFAULT_VOLTAGE_MIN + level * AVA8_DEFAULT_VOLTAGE_STEP; + return 0x8000 | volt_level; } static uint32_t decode_voltage(struct avalon8_info *info, int modular_id, uint32_t volt) @@ -287,22 +281,6 @@ char *set_avalon8_freq(char *arg) return NULL; } -char *set_avalon8_voltage(char *arg) -{ - int val, ret; - - ret = sscanf(arg, "%d", &val); - if (ret < 1) - return "No value passed to avalon8-voltage"; - - if (val < AVA8_DEFAULT_VOLTAGE_MIN || val > AVA8_DEFAULT_VOLTAGE_MAX) - return "Invalid value passed to avalon8-voltage"; - - opt_avalon8_voltage = val; - - return NULL; -} - char *set_avalon8_voltage_level(char *arg) { int val, ret; @@ -314,23 +292,23 @@ char *set_avalon8_voltage_level(char *arg) if (val < AVA8_DEFAULT_VOLTAGE_LEVEL_MIN || val > AVA8_DEFAULT_VOLTAGE_LEVEL_MAX) return "Invalid value passed to avalon8-voltage-level"; - opt_avalon8_voltage = convert_voltage_level(val); + opt_avalon8_voltage_level = val; return NULL; } -char *set_avalon8_voltage_offset(char *arg) +char *set_avalon8_voltage_level_offset(char *arg) { int val, ret; ret = sscanf(arg, "%d", &val); if (ret < 1) - return "No value passed to avalon8-voltage-offset"; + return "No value passed to avalon8-voltage-level-offset"; - if (val < AVA8_DEFAULT_VOLTAGE_OFFSET_MIN || val > AVA8_DEFAULT_VOLTAGE_OFFSET_MAX) - return "Invalid value passed to avalon8-voltage-offset"; + if (val < AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET_MIN || val > AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET_MAX) + return "Invalid value passed to avalon8-voltage-level-offset"; - opt_avalon8_voltage_offset = val; + opt_avalon8_voltage_level_offset = val; return NULL; } @@ -1357,10 +1335,10 @@ static void detect_modules(struct cgpu_info *avalon8) info->temp_target[i] = opt_avalon8_temp_target; info->fan_pct[i] = opt_avalon8_fan_min; for (j = 0; j < info->miner_count[i]; j++) { - if (opt_avalon8_voltage == AVA8_INVALID_VOLTAGE) - info->set_voltage[i][j] = avalon8_dev_table[dev_index].set_voltage; + if (opt_avalon8_voltage_level == AVA8_INVALID_VOLTAGE_LEVEL) + info->set_voltage_level[i][j] = avalon8_dev_table[dev_index].set_voltage_level; else - info->set_voltage[i][j] = opt_avalon8_voltage; + info->set_voltage_level[i][j] = opt_avalon8_voltage_level; info->get_voltage[i][j] = 0; info->get_vin[i][j] = 0; @@ -1589,7 +1567,7 @@ static void avalon8_init_setting(struct cgpu_info *avalon8, int addr) avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); } -static void avalon8_set_voltage(struct cgpu_info *avalon8, int addr, unsigned int voltage[]) +static void avalon8_set_voltage_level(struct cgpu_info *avalon8, int addr, unsigned int voltage[]) { struct avalon8_info *info = avalon8->device_data; struct avalon8_pkg send_pkg; @@ -1601,7 +1579,7 @@ static void avalon8_set_voltage(struct cgpu_info *avalon8, int addr, unsigned in /* NOTE: miner_count should <= 8 */ for (i = 0; i < info->miner_count[addr]; i++) { tmp = be32toh(encode_voltage(voltage[i] + - opt_avalon8_voltage_offset * AVA8_DEFAULT_VOLTAGE_STEP)); + opt_avalon8_voltage_level_offset)); memcpy(send_pkg.data + i * 4, &tmp, 4); } applog(LOG_DEBUG, "%s-%d-%d: avalon8 set voltage miner %d, (%d-%d)", @@ -1882,7 +1860,7 @@ static int64_t avalon8_scanhash(struct thr_info *thr) } if (update_settings) { cg_wlock(&info->update_lock); - avalon8_set_voltage(avalon8, i, info->set_voltage[i]); + avalon8_set_voltage_level(avalon8, i, info->set_voltage_level[i]); for (j = 0; j < info->miner_count[i]; j++) avalon8_set_freq(avalon8, i, j, info->set_frequency[i][j]); if (opt_avalon8_smart_speed) @@ -2165,75 +2143,12 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) } root = api_add_bool(root, "Connection Overloaded", &info->conn_overloaded, true); - root = api_add_int(root, "Voltage Offset", &opt_avalon8_voltage_offset, true); + root = api_add_int(root, "Voltage Level Offset", &opt_avalon8_voltage_level_offset, true); root = api_add_uint32(root, "Nonce Mask", &opt_avalon8_nonce_mask, true); return root; } -/* format: voltage[-addr[-miner]] - * add4[0, AVA8_DEFAULT_MODULARS - 1], 0 means all modulars - * miner[0, miner_count], 0 means all miners - */ -char *set_avalon8_device_voltage(struct cgpu_info *avalon8, char *arg) -{ - struct avalon8_info *info = avalon8->device_data; - unsigned int val, addr = 0, i, j; - uint32_t miner_id = 0; - - if (!(*arg)) - return NULL; - - sscanf(arg, "%d-%d-%d", &val, &addr, &miner_id); - if (!val) - val = AVA8_DEFAULT_VOLTAGE_MIN; - - if (val < AVA8_DEFAULT_VOLTAGE_MIN || val > AVA8_DEFAULT_VOLTAGE_MAX) - return "Invalid value passed to set_avalon8_device_voltage"; - - if (addr >= AVA8_DEFAULT_MODULARS) { - applog(LOG_ERR, "invalid modular index: %d, valid range 0-%d", addr, (AVA8_DEFAULT_MODULARS - 1)); - return "Invalid modular index to set_avalon8_device_voltage"; - } - - if (!info->enable[addr]) { - applog(LOG_ERR, "Disabled modular:%d", addr); - return "Disabled modular to set_avalon8_device_voltage"; - } - if (miner_id > info->miner_count[addr]) { - applog(LOG_ERR, "invalid miner index: %d, valid range 0-%d", miner_id, info->miner_count[addr]); - return "Invalid miner index to set_avalon8_device_voltage"; - } - - if (!addr) { - for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { - if (!info->enable[i]) - continue; - - if (miner_id) - info->set_voltage[i][miner_id - 1] = val; - else { - for (j = 0; j < info->miner_count[i]; j++) - info->set_voltage[i][j] = val; - } - avalon8_set_voltage(avalon8, i, info->set_voltage[i]); - } - } else { - if (miner_id) - info->set_voltage[addr][miner_id - 1] = val; - else { - for (j = 0; j < info->miner_count[addr]; j++) - info->set_voltage[addr][j] = val; - } - avalon8_set_voltage(avalon8, addr, info->set_voltage[addr]); - } - - applog(LOG_NOTICE, "%s-%d: Update voltage to %d", - avalon8->drv->name, avalon8->device_id, val); - - return NULL; -} - /* * format: freq[-addr[-miner]] * add4[0, AVA8_DEFAULT_MODULARS - 1], 0 means all modulars @@ -2427,15 +2342,6 @@ static char *avalon8_set_device(struct cgpu_info *avalon8, char *option, char *s return NULL; } - if (strcasecmp(option, "voltage") == 0) { - if (!setting || !*setting) { - sprintf(replybuf, "missing voltage value"); - return replybuf; - } - - return set_avalon8_device_voltage(avalon8, setting); - } - if (strcasecmp(option, "factory") == 0) { if (!setting || !*setting) { sprintf(replybuf, "missing factory info"); diff --git a/driver-avalon8.h b/driver-avalon8.h index b56b5b26ec..669b36f2cd 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -27,17 +27,13 @@ #define AVA8_DEFAULT_TEMP_OVERHEAT 105 #define AVA8_DEFAULT_TEMP_HYSTERESIS 5 -#define AVA8_DEFAULT_VOLTAGE_MIN 3000 -#define AVA8_DEFAULT_VOLTAGE_MAX 15000 -#define AVA8_INVALID_VOLTAGE 0 -#define AVA8_DEFAULT_VOLTAGE_STEP 125 - -#define AVA8_DEFAULT_VOLTAGE_LEVEL_MIN 0 +#define AVA8_DEFAULT_VOLTAGE_LEVEL_MIN -15 #define AVA8_DEFAULT_VOLTAGE_LEVEL_MAX 15 +#define AVA8_INVALID_VOLTAGE_LEVEL -16 -#define AVA8_DEFAULT_VOLTAGE_OFFSET_MIN -2 -#define AVA8_DEFAULT_VOLTAGE_OFFSET 0 -#define AVA8_DEFAULT_VOLTAGE_OFFSET_MAX 1 +#define AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET_MIN -2 +#define AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET 0 +#define AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET_MAX 1 #define AVA8_DEFAULT_FACTORY_INFO_0_MIN -15 #define AVA8_DEFAULT_FACTORY_INFO_0 0 @@ -243,7 +239,7 @@ struct avalon8_info { int temp_overheat[AVA8_DEFAULT_MODULARS]; time_t last_temp_time[AVA8_DEFAULT_MODULARS]; - uint32_t set_voltage[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; + int set_voltage_level[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; uint32_t set_frequency[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_PLL_CNT]; uint16_t get_vin[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; @@ -287,7 +283,7 @@ struct avalon8_dev_description { uint8_t asic_count; /* asic count each miner, it should not great than AVA8_DEFAULT_ASIC_MAX */ uint16_t vin_adc_ratio; uint16_t vout_adc_ratio; - uint32_t set_voltage; + int set_voltage_level; }; #define AVA8_WRITE_SIZE (sizeof(struct avalon8_pkg)) @@ -298,9 +294,8 @@ struct avalon8_dev_description { extern char *set_avalon8_fan(char *arg); extern char *set_avalon8_freq(char *arg); -extern char *set_avalon8_voltage(char *arg); extern char *set_avalon8_voltage_level(char *arg); -extern char *set_avalon8_voltage_offset(char *arg); +extern char *set_avalon8_voltage_level_offset(char *arg); extern int opt_avalon8_temp_target; extern int opt_avalon8_polling_delay; extern int opt_avalon8_aucspeed; From 2f476c620cdeba94d70a4706300ca4e77fa26641 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Fri, 17 Nov 2017 02:37:32 -0500 Subject: [PATCH 031/113] Update avalon8 device description --- driver-avalon8.c | 8 ++++---- driver-avalon8.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 5b9d3da71e..38179a4338 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -118,10 +118,10 @@ struct avalon8_dev_description avalon8_dev_table[] = { "821", 821, 4, - 24, + 26, AVA8_MM821_VIN_ADC_RATIO, AVA8_MM821_VOUT_ADC_RATIO, - 4500, + 14, } }; @@ -1613,11 +1613,11 @@ static void avalon8_set_freq(struct cgpu_info *avalon8, int addr, int miner_id, f = f ? f : 1; - tmp = ((AVA8_ASIC_TIMEOUT_CONST / f) * AVA8_DEFAULT_NTIME_OFFSET * 5 / 100); + tmp = (AVA8_ASIC_TIMEOUT_CONST / f) * AVA8_DEFAULT_NTIME_OFFSET; tmp = be32toh(tmp); memcpy(send_pkg.data + AVA8_DEFAULT_PLL_CNT * 4, &tmp, 4); - tmp = AVA8_ASIC_TIMEOUT_CONST / f * 98 / 100; + tmp = AVA8_ASIC_TIMEOUT_CONST / f * 96 / 100; tmp = be32toh(tmp); memcpy(send_pkg.data + AVA8_DEFAULT_PLL_CNT * 4 + 4, &tmp, 4); applog(LOG_DEBUG, "%s-%d-%d: avalon8 set freq miner %x-%x", diff --git a/driver-avalon8.h b/driver-avalon8.h index 669b36f2cd..7b66aadd41 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -54,7 +54,7 @@ #define AVA8_DEFAULT_CORE_VOLT_CNT 8 #define AVA8_DEFAULT_POLLING_DELAY 2 /* ms */ -#define AVA8_DEFAULT_NTIME_OFFSET 1 +#define AVA8_DEFAULT_NTIME_OFFSET 2 #define AVA8_DEFAULT_SMARTSPEED_OFF 0 #define AVA8_DEFAULT_SMARTSPEED_MODE1 1 From 2197b427a1ef382f8809d8d7af61ea854ff65b0a Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Wed, 22 Nov 2017 08:39:11 -0500 Subject: [PATCH 032/113] Update option for avalon8 * Update --avalon8-h2ltime0-spd --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 33a20ca3b2..7e6a495208 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1571,7 +1571,7 @@ static struct opt_table opt_config_table[] = { set_int_0_to_1, opt_show_intval, &opt_avalon8_mux_h2l, "Set Avalon8 mux h2l, range 0-1."), OPT_WITH_ARG("--avalon8-h2ltime0-spd", - set_int_0_to_7, opt_show_intval, &opt_avalon8_h2ltime0_spd, + set_int_0_to_255, opt_show_intval, &opt_avalon8_h2ltime0_spd, "Set Avalon8 h2ltime0 spd, range 0-7."), #endif #ifdef USE_AVALON_MINER From aceb45d97419d3a315fe7d9584fdc4de9c544d8e Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Fri, 24 Nov 2017 07:34:17 -0500 Subject: [PATCH 033/113] Update P_SET_PLL --- driver-avalon8.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 38179a4338..a62e9c2340 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -1613,11 +1613,12 @@ static void avalon8_set_freq(struct cgpu_info *avalon8, int addr, int miner_id, f = f ? f : 1; - tmp = (AVA8_ASIC_TIMEOUT_CONST / f) * AVA8_DEFAULT_NTIME_OFFSET; + /* TODO: adjust it according to frequency */ + tmp = 1; tmp = be32toh(tmp); memcpy(send_pkg.data + AVA8_DEFAULT_PLL_CNT * 4, &tmp, 4); - tmp = AVA8_ASIC_TIMEOUT_CONST / f * 96 / 100; + tmp = AVA8_ASIC_TIMEOUT_CONST / f * 83 / 100; tmp = be32toh(tmp); memcpy(send_pkg.data + AVA8_DEFAULT_PLL_CNT * 4 + 4, &tmp, 4); applog(LOG_DEBUG, "%s-%d-%d: avalon8 set freq miner %x-%x", From 4069a94c5d853f20d84c0bb3a4334f859e1a289b Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Fri, 24 Nov 2017 07:34:49 -0500 Subject: [PATCH 034/113] Update default parameters for avalon8 --- driver-avalon8.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/driver-avalon8.h b/driver-avalon8.h index 7b66aadd41..58476ab57f 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -39,12 +39,12 @@ #define AVA8_DEFAULT_FACTORY_INFO_0 0 #define AVA8_DEFAULT_FACTORY_INFO_0_MAX 15 -#define AVA8_DEFAULT_FREQUENCY_0 800 -#define AVA8_DEFAULT_FREQUENCY_1 800 -#define AVA8_DEFAULT_FREQUENCY_2 800 -#define AVA8_DEFAULT_FREQUENCY_3 800 +#define AVA8_DEFAULT_FREQUENCY_0 0 +#define AVA8_DEFAULT_FREQUENCY_1 0 +#define AVA8_DEFAULT_FREQUENCY_2 0 +#define AVA8_DEFAULT_FREQUENCY_3 700 #define AVA8_DEFAULT_FREQUENCY_MAX 1200 -#define AVA8_DEFAULT_FREQUENCY_SEL 0 +#define AVA8_DEFAULT_FREQUENCY_SEL 3 #define AVA8_DEFAULT_MODULARS 7 /* Only support 6 modules maximum with one AUC */ #define AVA8_DEFAULT_MINER_CNT 4 @@ -53,12 +53,12 @@ #define AVA8_DEFAULT_PMU_CNT 2 #define AVA8_DEFAULT_CORE_VOLT_CNT 8 -#define AVA8_DEFAULT_POLLING_DELAY 2 /* ms */ +#define AVA8_DEFAULT_POLLING_DELAY 20 /* ms */ #define AVA8_DEFAULT_NTIME_OFFSET 2 #define AVA8_DEFAULT_SMARTSPEED_OFF 0 #define AVA8_DEFAULT_SMARTSPEED_MODE1 1 -#define AVA8_DEFAULT_SMART_SPEED (AVA8_DEFAULT_SMARTSPEED_MODE1) +#define AVA8_DEFAULT_SMART_SPEED (AVA8_DEFAULT_SMARTSPEED_OFF) #define AVA8_DEFAULT_TH_PASS (162) #define AVA8_DEFAULT_TH_FAIL (10921) From b56ab3bbe033bd453496c4482621b336898888bd Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Wed, 29 Nov 2017 10:49:44 -0500 Subject: [PATCH 035/113] Update polling error count for avalon8 --- driver-avalon8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index a62e9c2340..7c0cd6dd20 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -1445,7 +1445,7 @@ static int polling(struct cgpu_info *avalon8) memset(send_pkg.data, 0, AVA8_P_DATA_LEN); avalon8_init_pkg(&send_pkg, AVA8_P_RSTMMTX, 1, 1); avalon8_iic_xfer_pkg(avalon8, i, &send_pkg, NULL); - if (info->error_polling_cnt[i] >= 10) + if (info->error_polling_cnt[i] >= 100) detach_module(avalon8, i); } From 01ab3b94da50575e9a943e474227121d5dee8642 Mon Sep 17 00:00:00 2001 From: Mikeqin Date: Thu, 7 Dec 2017 20:07:52 +0800 Subject: [PATCH 036/113] Support voltage-level tweak --- driver-avalon8.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/driver-avalon8.c b/driver-avalon8.c index 7c0cd6dd20..eacffc5b97 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -2150,6 +2150,73 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) return root; } +/* format: voltage[-addr[-miner]] + * addr[0, AVA8_DEFAULT_MODULARS - 1], 0 means all modulars + * miner[0, miner_count], 0 means all miners + */ +char *set_avalon8_device_voltage_level(struct cgpu_info *avalon8, char *arg) +{ + struct avalon8_info *info = avalon8->device_data; + int val; + unsigned int addr = 0, i, j; + uint32_t miner_id = 0; + + if (!(*arg)) + return NULL; + + sscanf(arg, "%d-%d-%d", &val, &addr, &miner_id); + + if (val < AVA8_DEFAULT_VOLTAGE_LEVEL_MIN || val > AVA8_DEFAULT_VOLTAGE_LEVEL_MAX) + return "Invalid value passed to set_avalon8_device_voltage_level"; + + if (addr >= AVA8_DEFAULT_MODULARS) { + applog(LOG_ERR, "invalid modular index: %d, valid range 0-%d", addr, (AVA8_DEFAULT_MODULARS - 1)); + return "Invalid modular index to set_avalon8_device_voltage_level"; + } + + if (!addr) { + for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { + if (!info->enable[i]) + continue; + + if (miner_id > info->miner_count[i]) { + applog(LOG_ERR, "invalid miner index: %d, valid range 0-%d", miner_id, info->miner_count[i]); + return "Invalid miner index to set_avalon8_device_voltage_level"; + } + + if (miner_id) + info->set_voltage_level[i][miner_id - 1] = val; + else { + for (j = 0; j < info->miner_count[i]; j++) + info->set_voltage_level[i][j] = val; + } + avalon8_set_voltage_level(avalon8, i, info->set_voltage_level[i]); + } + } else { + if (!info->enable[addr]) { + applog(LOG_ERR, "Disabled modular:%d", addr); + return "Disabled modular to set_avalon8_device_voltage_level"; + } + + if (miner_id > info->miner_count[addr]) { + applog(LOG_ERR, "invalid miner index: %d, valid range 0-%d", miner_id, info->miner_count[addr]); + return "Invalid miner index to set_avalon8_device_voltage_level"; + } + + if (miner_id) + info->set_voltage_level[addr][miner_id - 1] = val; + else { + for (j = 0; j < info->miner_count[addr]; j++) + info->set_voltage_level[addr][j] = val; + } + avalon8_set_voltage_level(avalon8, addr, info->set_voltage_level[addr]); + } + + applog(LOG_NOTICE, "%s-%d: Update voltage-level to %d", avalon8->drv->name, avalon8->device_id, val); + + return NULL; +} + /* * format: freq[-addr[-miner]] * add4[0, AVA8_DEFAULT_MODULARS - 1], 0 means all modulars @@ -2343,6 +2410,15 @@ static char *avalon8_set_device(struct cgpu_info *avalon8, char *option, char *s return NULL; } + if (strcasecmp(option, "voltage-level") == 0) { + if (!setting || !*setting) { + sprintf(replybuf, "missing voltage-level value"); + return replybuf; + } + + return set_avalon8_device_voltage_level(avalon8, setting); + } + if (strcasecmp(option, "factory") == 0) { if (!setting || !*setting) { sprintf(replybuf, "missing factory info"); From b652b76a59a65af0233d29775561f7c18bba398c Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Sat, 16 Dec 2017 14:47:19 +0800 Subject: [PATCH 037/113] Revert "Update polling error count for avalon8" --- driver-avalon8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index eacffc5b97..5178a858c3 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -1445,7 +1445,7 @@ static int polling(struct cgpu_info *avalon8) memset(send_pkg.data, 0, AVA8_P_DATA_LEN); avalon8_init_pkg(&send_pkg, AVA8_P_RSTMMTX, 1, 1); avalon8_iic_xfer_pkg(avalon8, i, &send_pkg, NULL); - if (info->error_polling_cnt[i] >= 100) + if (info->error_polling_cnt[i] >= 10) detach_module(avalon8, i); } From 3a28ef057012b6d8081a1cc4493799abaafbe203 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Sat, 16 Dec 2017 15:06:58 +0800 Subject: [PATCH 038/113] Update default parameters for avalon8 --- driver-avalon8.c | 2 +- driver-avalon8.h | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 5178a858c3..cd3deaa577 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -121,7 +121,7 @@ struct avalon8_dev_description avalon8_dev_table[] = { 26, AVA8_MM821_VIN_ADC_RATIO, AVA8_MM821_VOUT_ADC_RATIO, - 14, + 5, } }; diff --git a/driver-avalon8.h b/driver-avalon8.h index 58476ab57f..caad4d027f 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -23,7 +23,7 @@ #define AVA8_DEFAULT_FAN_MAX 100 #define AVA8_DEFAULT_FAN_INTERVAL 15 /* Seconds */ -#define AVA8_DEFAULT_TEMP_TARGET 90 +#define AVA8_DEFAULT_TEMP_TARGET 70 #define AVA8_DEFAULT_TEMP_OVERHEAT 105 #define AVA8_DEFAULT_TEMP_HYSTERESIS 5 @@ -42,7 +42,7 @@ #define AVA8_DEFAULT_FREQUENCY_0 0 #define AVA8_DEFAULT_FREQUENCY_1 0 #define AVA8_DEFAULT_FREQUENCY_2 0 -#define AVA8_DEFAULT_FREQUENCY_3 700 +#define AVA8_DEFAULT_FREQUENCY_3 650 #define AVA8_DEFAULT_FREQUENCY_MAX 1200 #define AVA8_DEFAULT_FREQUENCY_SEL 3 @@ -58,15 +58,15 @@ #define AVA8_DEFAULT_SMARTSPEED_OFF 0 #define AVA8_DEFAULT_SMARTSPEED_MODE1 1 -#define AVA8_DEFAULT_SMART_SPEED (AVA8_DEFAULT_SMARTSPEED_OFF) - -#define AVA8_DEFAULT_TH_PASS (162) -#define AVA8_DEFAULT_TH_FAIL (10921) -#define AVA8_DEFAULT_TH_INIT (0xffff / 2) -#define AVA8_DEFAULT_TH_ADD 0 -#define AVA8_DEFAULT_TH_MS 1 -#define AVA8_DEFAULT_TH_TIMEOUT 0 -#define AVA8_DEFAULT_NONCE_MASK 29 +#define AVA8_DEFAULT_SMART_SPEED (AVA8_DEFAULT_SMARTSPEED_MODE1) + +#define AVA8_DEFAULT_TH_PASS 160 +#define AVA8_DEFAULT_TH_FAIL 8000 +#define AVA8_DEFAULT_TH_INIT 32767 +#define AVA8_DEFAULT_TH_ADD 1 +#define AVA8_DEFAULT_TH_MS 5 +#define AVA8_DEFAULT_TH_TIMEOUT 20000 +#define AVA8_DEFAULT_NONCE_MASK 24 #define AVA8_DEFAULT_NONCE_CHECK 1 #define AVA8_DEFAULT_MUX_L2H 0 #define AVA8_DEFAULT_MUX_H2L 1 From 415afcb53d45a667524bc91de12635bc8eb3fdf0 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Sat, 16 Dec 2017 15:36:59 +0800 Subject: [PATCH 039/113] Fix typo --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 7e6a495208..c7917bf4c2 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1572,7 +1572,7 @@ static struct opt_table opt_config_table[] = { "Set Avalon8 mux h2l, range 0-1."), OPT_WITH_ARG("--avalon8-h2ltime0-spd", set_int_0_to_255, opt_show_intval, &opt_avalon8_h2ltime0_spd, - "Set Avalon8 h2ltime0 spd, range 0-7."), + "Set Avalon8 h2ltime0 spd, range 0-255."), #endif #ifdef USE_AVALON_MINER OPT_WITH_CBARG("--avalonm-voltage", From 6284d37f7d0685ee233271cc2b06fb803a1a1d50 Mon Sep 17 00:00:00 2001 From: Mikeqin Date: Thu, 14 Dec 2017 12:52:27 +0800 Subject: [PATCH 040/113] Update frequency tweak --- driver-avalon8.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index cd3deaa577..4eada95f0d 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -2219,7 +2219,7 @@ char *set_avalon8_device_voltage_level(struct cgpu_info *avalon8, char *arg) /* * format: freq[-addr[-miner]] - * add4[0, AVA8_DEFAULT_MODULARS - 1], 0 means all modulars + * addr[0, AVA8_DEFAULT_MODULARS - 1], 0 means all modulars * miner[0, miner_count], 0 means all miners */ char *set_avalon8_device_freq(struct cgpu_info *avalon8, char *arg) @@ -2240,25 +2240,22 @@ char *set_avalon8_device_freq(struct cgpu_info *avalon8, char *arg) applog(LOG_ERR, "invalid modular index: %d, valid range 0-%d", addr, (AVA8_DEFAULT_MODULARS - 1)); return "Invalid modular index to set_avalon8_device_freq"; } - if (!info->enable[addr]) { - applog(LOG_ERR, "Disabled modular:%d", addr); - return "Disabled modular to set_avalon8_device_freq"; - } - if (miner_id > info->miner_count[addr]) { - applog(LOG_ERR, "invalid miner index: %d, valid range 0-%d", miner_id, info->miner_count[addr]); - return "Invalid miner index to set_avalon8_device_freq"; - } if (!addr) { for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { if (!info->enable[i]) continue; + if (miner_id > info->miner_count[i]) { + applog(LOG_ERR, "invalid miner index: %d, valid range 0-%d", miner_id, info->miner_count[i]); + return "Invalid miner index to set_avalon8_device_freq"; + } + if (miner_id) { for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) info->set_frequency[i][miner_id - 1][k] = val; - avalon8_set_freq(avalon8, i, miner_id, info->set_frequency[i][miner_id]); + avalon8_set_freq(avalon8, i, miner_id - 1, info->set_frequency[i][miner_id - 1]); } else { for (j = 0; j < info->miner_count[i]; j++) { for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) @@ -2269,11 +2266,21 @@ char *set_avalon8_device_freq(struct cgpu_info *avalon8, char *arg) } } } else { + if (!info->enable[addr]) { + applog(LOG_ERR, "Disabled modular:%d", addr); + return "Disabled modular to set_avalon8_device_freq"; + } + + if (miner_id > info->miner_count[addr]) { + applog(LOG_ERR, "invalid miner index: %d, valid range 0-%d", miner_id, info->miner_count[addr]); + return "Invalid miner index to set_avalon8_device_freq"; + } + if (miner_id) { for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) info->set_frequency[addr][miner_id - 1][k] = val; - avalon8_set_freq(avalon8, addr, miner_id, info->set_frequency[addr][miner_id]); + avalon8_set_freq(avalon8, addr, miner_id - 1, info->set_frequency[addr][miner_id - 1]); } else { for (j = 0; j < info->miner_count[addr]; j++) { From bbcc13221365ab7d3b3807a6a68f94fb9c497d8d Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 25 Jan 2018 22:38:21 +0800 Subject: [PATCH 041/113] Update P_SET_PLL --- driver-avalon8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 4eada95f0d..10920b94f5 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -1614,7 +1614,7 @@ static void avalon8_set_freq(struct cgpu_info *avalon8, int addr, int miner_id, f = f ? f : 1; /* TODO: adjust it according to frequency */ - tmp = 1; + tmp = 100; tmp = be32toh(tmp); memcpy(send_pkg.data + AVA8_DEFAULT_PLL_CNT * 4, &tmp, 4); From 44685ac06a2fc3b2e5af125c1c76bd6980ade3aa Mon Sep 17 00:00:00 2001 From: xzx Date: Sun, 28 Jan 2018 21:38:27 +0800 Subject: [PATCH 042/113] Add over hashrate --- cgminer.c | 4 +++ driver-avalon8.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ driver-avalon8.h | 48 +++++++++++++++++++++--------------- 3 files changed, 96 insertions(+), 19 deletions(-) diff --git a/cgminer.c b/cgminer.c index c7917bf4c2..97c9c342ff 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1573,6 +1573,10 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--avalon8-h2ltime0-spd", set_int_0_to_255, opt_show_intval, &opt_avalon8_h2ltime0_spd, "Set Avalon8 h2ltime0 spd, range 0-255."), + OPT_WITH_ARG("--avalon8-over-hashrate", + set_int_0_to_1, opt_show_intval, &opt_avalon8_over_hashrate, + "Set Avalon8 over hashrate, range 0-1."), + #endif #ifdef USE_AVALON_MINER OPT_WITH_CBARG("--avalonm-voltage", diff --git a/driver-avalon8.c b/driver-avalon8.c index 10920b94f5..dc1eb0fa31 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -59,6 +59,7 @@ uint32_t opt_avalon8_mux_l2h = AVA8_DEFAULT_MUX_L2H; uint32_t opt_avalon8_mux_h2l = AVA8_DEFAULT_MUX_H2L; uint32_t opt_avalon8_h2ltime0_spd = AVA8_DEFAULT_H2LTIME0_SPD; uint32_t opt_avalon8_roll_enable = AVA8_DEFAULT_ROLL_ENABLE; +uint32_t opt_avalon8_over_hashrate = AVA8_DEFAULT_OVER_HASHRATE; uint32_t cpm_table[] = { @@ -635,6 +636,10 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_FAC", avalon8->drv->name, avalon8->device_id, modular_id); info->factory_info[0] = ar->data[0]; break; + case AVA8_P_STATUS_OVER_HASHRATE: + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_OVER_HASHRATE", avalon8->drv->name, avalon8->device_id, modular_id); + info->over_hashrate_info[0] = ar->data[0]; + break; default: applog(LOG_DEBUG, "%s-%d-%d: Unknown response %x", avalon8->drv->name, avalon8->device_id, modular_id, ar->type); break; @@ -1559,6 +1564,12 @@ static void avalon8_init_setting(struct cgpu_info *avalon8, int addr) avalon8->drv->name, avalon8->device_id, addr, opt_avalon8_h2ltime0_spd); + tmp = be32toh(opt_avalon8_over_hashrate); + memcpy(send_pkg.data + 22, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set over hashrate %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_over_hashrate); + /* Package the data */ avalon8_init_pkg(&send_pkg, AVA8_P_SET, 1, 1); if (addr == AVA8_MODULE_BROADCAST) @@ -1652,6 +1663,24 @@ static void avalon8_set_factory_info(struct cgpu_info *avalon8, int addr, uint8_ avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); } +static void avalon8_set_over_hashrate_info(struct cgpu_info *avalon8, int addr, uint8_t value[]) +{ + struct avalon8_pkg send_pkg; + uint8_t i; + + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + + for (i = 0; i < AVA8_DEFAULT_OVER_HASHRATE_CNT; i++) + send_pkg.data[i] = value[i]; + + /* Package the data */ + avalon8_init_pkg(&send_pkg, AVA8_P_SET_OVER_HASHRATE, 1, 1); + if (addr == AVA8_MODULE_BROADCAST) + avalon8_send_bc_pkgs(avalon8, &send_pkg); + else + avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); +} + static void avalon8_set_ss_param(struct cgpu_info *avalon8, int addr) { struct avalon8_pkg send_pkg; @@ -2068,6 +2097,9 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) sprintf(buf, " FAC0[%d]", info->factory_info[0]); strcat(statbuf, buf); + sprintf(buf, " OHR[%d]", info->over_hashrate_info[0]); + strcat(statbuf, buf); + for (j = 0; j < info->miner_count[i]; j++) { sprintf(buf, " SF%d[", j); strcat(statbuf, buf); @@ -2322,6 +2354,28 @@ char *set_avalon8_factory_info(struct cgpu_info *avalon8, char *arg) return NULL; } +char *set_avalon8_over_hashrate_info(struct cgpu_info *avalon8, char *arg) +{ + struct avalon8_info *info = avalon8->device_data; + int val; + + if (!(*arg)) + return NULL; + + sscanf(arg, "%d", &val); + + if (val != AVA8_DEFAULT_OVER_HASHRATE_OFF && val != AVA8_DEFAULT_OVER_HASHRATE_ON) + return "Invalid value passed to set_avalon8_over_hashrate_info"; + + info->over_hashrate_info[0] = val; + avalon8_set_over_hashrate_info(avalon8, 0, (uint8_t *)info->over_hashrate_info); + + applog(LOG_NOTICE, "%s-%d: Update Over Hashrate info %d", + avalon8->drv->name, avalon8->device_id, val); + + return NULL; +} + static char *avalon8_set_device(struct cgpu_info *avalon8, char *option, char *setting, char *replybuf) { unsigned int val; @@ -2452,6 +2506,15 @@ static char *avalon8_set_device(struct cgpu_info *avalon8, char *option, char *s return NULL; } + if (strcasecmp(option, "over-hashrate") == 0) { + if (!setting || !*setting) { + sprintf(replybuf, "missing over hashrate info"); + return replybuf; + } + + return set_avalon8_over_hashrate_info(avalon8, setting); + } + sprintf(replybuf, "Unknown option: %s", option); return replybuf; } diff --git a/driver-avalon8.h b/driver-avalon8.h index caad4d027f..7a9c9de87d 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -39,6 +39,10 @@ #define AVA8_DEFAULT_FACTORY_INFO_0 0 #define AVA8_DEFAULT_FACTORY_INFO_0_MAX 15 +#define AVA8_DEFAULT_OVER_HASHRATE_OFF 0 +#define AVA8_DEFAULT_OVER_HASHRATE_ON 1 +#define AVA8_DEFAULT_OVER_HASHRATE (AVA8_DEFAULT_OVER_HASHRATE_OFF) + #define AVA8_DEFAULT_FREQUENCY_0 0 #define AVA8_DEFAULT_FREQUENCY_1 0 #define AVA8_DEFAULT_FREQUENCY_2 0 @@ -114,14 +118,15 @@ #define AVA8_P_JOB_FIN 0x17 /* Broadcase or with I2C address */ -#define AVA8_P_SET 0x20 -#define AVA8_P_SET_FIN 0x21 -#define AVA8_P_SET_VOLT 0x22 -#define AVA8_P_SET_PMU 0x24 -#define AVA8_P_SET_PLL 0x25 -#define AVA8_P_SET_SS 0x26 +#define AVA8_P_SET 0x20 +#define AVA8_P_SET_FIN 0x21 +#define AVA8_P_SET_VOLT 0x22 +#define AVA8_P_SET_PMU 0x24 +#define AVA8_P_SET_PLL 0x25 +#define AVA8_P_SET_SS 0x26 /* 0x27 reserved */ -#define AVA8_P_SET_FAC 0x28 +#define AVA8_P_SET_FAC 0x28 +#define AVA8_P_SET_OVER_HASHRATE 0x29 /* Have to send with I2C address */ #define AVA8_P_POLLING 0x30 @@ -131,17 +136,18 @@ #define AVA8_P_GET_VOLT 0x34 /* Back to host */ -#define AVA8_P_ACKDETECT 0x40 -#define AVA8_P_STATUS 0x41 -#define AVA8_P_NONCE 0x42 -#define AVA8_P_TEST_RET 0x43 -#define AVA8_P_STATUS_VOLT 0x46 -#define AVA8_P_STATUS_PMU 0x48 -#define AVA8_P_STATUS_PLL 0x49 -#define AVA8_P_STATUS_LOG 0x4a -#define AVA8_P_STATUS_ASIC 0x4b -#define AVA8_P_STATUS_PVT 0x4c -#define AVA8_P_STATUS_FAC 0x4d +#define AVA8_P_ACKDETECT 0x40 +#define AVA8_P_STATUS 0x41 +#define AVA8_P_NONCE 0x42 +#define AVA8_P_TEST_RET 0x43 +#define AVA8_P_STATUS_VOLT 0x46 +#define AVA8_P_STATUS_PMU 0x48 +#define AVA8_P_STATUS_PLL 0x49 +#define AVA8_P_STATUS_LOG 0x4a +#define AVA8_P_STATUS_ASIC 0x4b +#define AVA8_P_STATUS_PVT 0x4c +#define AVA8_P_STATUS_FAC 0x4d +#define AVA8_P_STATUS_OVER_HASHRATE 0x4e #define AVA8_MODULE_BROADCAST 0 /* End of avalon8 protocol package type */ @@ -157,6 +163,8 @@ #define AVA8_DEFAULT_FACTORY_INFO_CNT 1 +#define AVA8_DEFAULT_OVER_HASHRATE_CNT 1 + #define AVA8_MM821_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) #define AVA8_MM821_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) @@ -247,6 +255,7 @@ struct avalon8_info { uint32_t get_pll[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_PLL_CNT]; int8_t factory_info[AVA8_DEFAULT_FACTORY_INFO_CNT]; + int8_t over_hashrate_info[AVA8_DEFAULT_OVER_HASHRATE_CNT]; uint64_t local_works[AVA8_DEFAULT_MODULARS]; uint64_t local_works_i[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; @@ -315,5 +324,6 @@ extern uint32_t opt_avalon8_mux_l2h; extern uint32_t opt_avalon8_mux_h2l; extern uint32_t opt_avalon8_h2ltime0_spd; extern uint32_t opt_avalon8_roll_enable; +extern uint32_t opt_avalon8_over_hashrate; #endif /* USE_AVALON8 */ -#endif /* _AVALON8_H_ */ +#endif /* _AVALON8_H_ */ From 16b1c7bb0886080515297e1b25a55f6089266dd6 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Mon, 12 Feb 2018 20:43:24 +0800 Subject: [PATCH 043/113] Update P_STATUS_PLL --- driver-avalon8.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/driver-avalon8.c b/driver-avalon8.c index dc1eb0fa31..d3ebb539c6 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -608,6 +608,11 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod for (i = 0; i < AVA8_DEFAULT_PLL_CNT; i++) { memcpy(&tmp, ar->data + i * 4, 4); info->get_pll[modular_id][ar->idx][i] = be32toh(tmp); + + memcpy(&tmp, ar->data + AVA8_DEFAULT_PLL_CNT * 4 + i * 4, 4); + tmp = be32toh(tmp); + if (tmp) + info->set_frequency[modular_id][ar->idx][i] = tmp; } break; case AVA8_P_STATUS_PVT: From d86efcc27b7220676631ddc697496b901d24486d Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Mon, 12 Feb 2018 21:25:38 +0800 Subject: [PATCH 044/113] Change over hashrate to overclocking --- cgminer.c | 4 ---- driver-avalon8.c | 39 ++++++++++++++++----------------------- driver-avalon8.h | 14 ++++++-------- 3 files changed, 22 insertions(+), 35 deletions(-) diff --git a/cgminer.c b/cgminer.c index 97c9c342ff..c7917bf4c2 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1573,10 +1573,6 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--avalon8-h2ltime0-spd", set_int_0_to_255, opt_show_intval, &opt_avalon8_h2ltime0_spd, "Set Avalon8 h2ltime0 spd, range 0-255."), - OPT_WITH_ARG("--avalon8-over-hashrate", - set_int_0_to_1, opt_show_intval, &opt_avalon8_over_hashrate, - "Set Avalon8 over hashrate, range 0-1."), - #endif #ifdef USE_AVALON_MINER OPT_WITH_CBARG("--avalonm-voltage", diff --git a/driver-avalon8.c b/driver-avalon8.c index d3ebb539c6..54886ca10d 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -59,7 +59,6 @@ uint32_t opt_avalon8_mux_l2h = AVA8_DEFAULT_MUX_L2H; uint32_t opt_avalon8_mux_h2l = AVA8_DEFAULT_MUX_H2L; uint32_t opt_avalon8_h2ltime0_spd = AVA8_DEFAULT_H2LTIME0_SPD; uint32_t opt_avalon8_roll_enable = AVA8_DEFAULT_ROLL_ENABLE; -uint32_t opt_avalon8_over_hashrate = AVA8_DEFAULT_OVER_HASHRATE; uint32_t cpm_table[] = { @@ -641,9 +640,9 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_FAC", avalon8->drv->name, avalon8->device_id, modular_id); info->factory_info[0] = ar->data[0]; break; - case AVA8_P_STATUS_OVER_HASHRATE: - applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_OVER_HASHRATE", avalon8->drv->name, avalon8->device_id, modular_id); - info->over_hashrate_info[0] = ar->data[0]; + case AVA8_P_STATUS_OC: + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_OC", avalon8->drv->name, avalon8->device_id, modular_id); + info->overclocking_info[0] = ar->data[0]; break; default: applog(LOG_DEBUG, "%s-%d-%d: Unknown response %x", avalon8->drv->name, avalon8->device_id, modular_id, ar->type); @@ -1569,12 +1568,6 @@ static void avalon8_init_setting(struct cgpu_info *avalon8, int addr) avalon8->drv->name, avalon8->device_id, addr, opt_avalon8_h2ltime0_spd); - tmp = be32toh(opt_avalon8_over_hashrate); - memcpy(send_pkg.data + 22, &tmp, 4); - applog(LOG_DEBUG, "%s-%d-%d: avalon8 set over hashrate %u", - avalon8->drv->name, avalon8->device_id, addr, - opt_avalon8_over_hashrate); - /* Package the data */ avalon8_init_pkg(&send_pkg, AVA8_P_SET, 1, 1); if (addr == AVA8_MODULE_BROADCAST) @@ -1668,18 +1661,18 @@ static void avalon8_set_factory_info(struct cgpu_info *avalon8, int addr, uint8_ avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); } -static void avalon8_set_over_hashrate_info(struct cgpu_info *avalon8, int addr, uint8_t value[]) +static void avalon8_set_overclocking_info(struct cgpu_info *avalon8, int addr, uint8_t value[]) { struct avalon8_pkg send_pkg; uint8_t i; memset(send_pkg.data, 0, AVA8_P_DATA_LEN); - for (i = 0; i < AVA8_DEFAULT_OVER_HASHRATE_CNT; i++) + for (i = 0; i < AVA8_DEFAULT_OVERCLOCKING_CNT; i++) send_pkg.data[i] = value[i]; /* Package the data */ - avalon8_init_pkg(&send_pkg, AVA8_P_SET_OVER_HASHRATE, 1, 1); + avalon8_init_pkg(&send_pkg, AVA8_P_SET_OC, 1, 1); if (addr == AVA8_MODULE_BROADCAST) avalon8_send_bc_pkgs(avalon8, &send_pkg); else @@ -2102,7 +2095,7 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) sprintf(buf, " FAC0[%d]", info->factory_info[0]); strcat(statbuf, buf); - sprintf(buf, " OHR[%d]", info->over_hashrate_info[0]); + sprintf(buf, " OC[%d]", info->overclocking_info[0]); strcat(statbuf, buf); for (j = 0; j < info->miner_count[i]; j++) { @@ -2359,7 +2352,7 @@ char *set_avalon8_factory_info(struct cgpu_info *avalon8, char *arg) return NULL; } -char *set_avalon8_over_hashrate_info(struct cgpu_info *avalon8, char *arg) +char *set_avalon8_overclocking_info(struct cgpu_info *avalon8, char *arg) { struct avalon8_info *info = avalon8->device_data; int val; @@ -2369,13 +2362,13 @@ char *set_avalon8_over_hashrate_info(struct cgpu_info *avalon8, char *arg) sscanf(arg, "%d", &val); - if (val != AVA8_DEFAULT_OVER_HASHRATE_OFF && val != AVA8_DEFAULT_OVER_HASHRATE_ON) - return "Invalid value passed to set_avalon8_over_hashrate_info"; + if (val != AVA8_DEFAULT_OVERCLOCKING_OFF && val != AVA8_DEFAULT_OVERCLOCKING_ON) + return "Invalid value passed to set_avalon8_overclocking_info"; - info->over_hashrate_info[0] = val; - avalon8_set_over_hashrate_info(avalon8, 0, (uint8_t *)info->over_hashrate_info); + info->overclocking_info[0] = val; + avalon8_set_overclocking_info(avalon8, 0, (uint8_t *)info->overclocking_info); - applog(LOG_NOTICE, "%s-%d: Update Over Hashrate info %d", + applog(LOG_NOTICE, "%s-%d: Update Overclocking info %d", avalon8->drv->name, avalon8->device_id, val); return NULL; @@ -2511,13 +2504,13 @@ static char *avalon8_set_device(struct cgpu_info *avalon8, char *option, char *s return NULL; } - if (strcasecmp(option, "over-hashrate") == 0) { + if (strcasecmp(option, "overclocking") == 0) { if (!setting || !*setting) { - sprintf(replybuf, "missing over hashrate info"); + sprintf(replybuf, "missing overclocking info"); return replybuf; } - return set_avalon8_over_hashrate_info(avalon8, setting); + return set_avalon8_overclocking_info(avalon8, setting); } sprintf(replybuf, "Unknown option: %s", option); diff --git a/driver-avalon8.h b/driver-avalon8.h index 7a9c9de87d..3ce9d83b23 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -39,9 +39,8 @@ #define AVA8_DEFAULT_FACTORY_INFO_0 0 #define AVA8_DEFAULT_FACTORY_INFO_0_MAX 15 -#define AVA8_DEFAULT_OVER_HASHRATE_OFF 0 -#define AVA8_DEFAULT_OVER_HASHRATE_ON 1 -#define AVA8_DEFAULT_OVER_HASHRATE (AVA8_DEFAULT_OVER_HASHRATE_OFF) +#define AVA8_DEFAULT_OVERCLOCKING_OFF 0 +#define AVA8_DEFAULT_OVERCLOCKING_ON 1 #define AVA8_DEFAULT_FREQUENCY_0 0 #define AVA8_DEFAULT_FREQUENCY_1 0 @@ -126,7 +125,7 @@ #define AVA8_P_SET_SS 0x26 /* 0x27 reserved */ #define AVA8_P_SET_FAC 0x28 -#define AVA8_P_SET_OVER_HASHRATE 0x29 +#define AVA8_P_SET_OC 0x29 /* Have to send with I2C address */ #define AVA8_P_POLLING 0x30 @@ -147,7 +146,7 @@ #define AVA8_P_STATUS_ASIC 0x4b #define AVA8_P_STATUS_PVT 0x4c #define AVA8_P_STATUS_FAC 0x4d -#define AVA8_P_STATUS_OVER_HASHRATE 0x4e +#define AVA8_P_STATUS_OC 0x4e #define AVA8_MODULE_BROADCAST 0 /* End of avalon8 protocol package type */ @@ -163,7 +162,7 @@ #define AVA8_DEFAULT_FACTORY_INFO_CNT 1 -#define AVA8_DEFAULT_OVER_HASHRATE_CNT 1 +#define AVA8_DEFAULT_OVERCLOCKING_CNT 1 #define AVA8_MM821_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) #define AVA8_MM821_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) @@ -255,7 +254,7 @@ struct avalon8_info { uint32_t get_pll[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_PLL_CNT]; int8_t factory_info[AVA8_DEFAULT_FACTORY_INFO_CNT]; - int8_t over_hashrate_info[AVA8_DEFAULT_OVER_HASHRATE_CNT]; + int8_t overclocking_info[AVA8_DEFAULT_OVERCLOCKING_CNT]; uint64_t local_works[AVA8_DEFAULT_MODULARS]; uint64_t local_works_i[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; @@ -324,6 +323,5 @@ extern uint32_t opt_avalon8_mux_l2h; extern uint32_t opt_avalon8_mux_h2l; extern uint32_t opt_avalon8_h2ltime0_spd; extern uint32_t opt_avalon8_roll_enable; -extern uint32_t opt_avalon8_over_hashrate; #endif /* USE_AVALON8 */ #endif /* _AVALON8_H_ */ From fdddf6ef9541273184bd66d05d843da4a02a66cf Mon Sep 17 00:00:00 2001 From: xzx Date: Fri, 23 Feb 2018 10:22:25 +0800 Subject: [PATCH 045/113] Add A841 support --- driver-avalon8.c | 9 +++++++++ driver-avalon8.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/driver-avalon8.c b/driver-avalon8.c index 54886ca10d..2853bcc07b 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -122,6 +122,15 @@ struct avalon8_dev_description avalon8_dev_table[] = { AVA8_MM821_VIN_ADC_RATIO, AVA8_MM821_VOUT_ADC_RATIO, 5, + }, + { + "841", + 841, + 4, + 26, + AVA8_MM841_VIN_ADC_RATIO, + AVA8_MM841_VOUT_ADC_RATIO, + 5, } }; diff --git a/driver-avalon8.h b/driver-avalon8.h index 3ce9d83b23..a14987433a 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -165,7 +165,10 @@ #define AVA8_DEFAULT_OVERCLOCKING_CNT 1 #define AVA8_MM821_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) +#define AVA8_MM841_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) + #define AVA8_MM821_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) +#define AVA8_MM841_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) struct avalon8_pkg { uint8_t head[2]; From c9d437b6c45799cf5d0496c2baee5870d7b5c094 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Sat, 3 Mar 2018 23:32:45 +0800 Subject: [PATCH 046/113] Update avalon8_dev_description --- driver-avalon8.c | 28 ++++++++++++++++++++++++---- driver-avalon8.h | 9 +++++---- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 2853bcc07b..e1af4a8125 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -27,10 +27,13 @@ int opt_avalon8_fan_max = AVA8_DEFAULT_FAN_MAX; int opt_avalon8_voltage_level = AVA8_INVALID_VOLTAGE_LEVEL; int opt_avalon8_voltage_level_offset = AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET; -int opt_avalon8_freq[AVA8_DEFAULT_PLL_CNT] = {AVA8_DEFAULT_FREQUENCY_0, - AVA8_DEFAULT_FREQUENCY_1, - AVA8_DEFAULT_FREQUENCY_2, - AVA8_DEFAULT_FREQUENCY_3}; +int opt_avalon8_freq[AVA8_DEFAULT_PLL_CNT] = +{ + AVA8_DEFAULT_FREQUENCY, + AVA8_DEFAULT_FREQUENCY, + AVA8_DEFAULT_FREQUENCY, + AVA8_DEFAULT_FREQUENCY +}; int opt_avalon8_freq_sel = AVA8_DEFAULT_FREQUENCY_SEL; @@ -122,6 +125,12 @@ struct avalon8_dev_description avalon8_dev_table[] = { AVA8_MM821_VIN_ADC_RATIO, AVA8_MM821_VOUT_ADC_RATIO, 5, + { + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_650M + } }, { "841", @@ -131,6 +140,12 @@ struct avalon8_dev_description avalon8_dev_table[] = { AVA8_MM841_VIN_ADC_RATIO, AVA8_MM841_VOUT_ADC_RATIO, 5, + { + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_775M + } } }; @@ -1334,6 +1349,11 @@ static void detect_modules(struct cgpu_info *avalon8) info->asic_count[i] = avalon8_dev_table[dev_index].asic_count; info->vin_adc_ratio[i] = avalon8_dev_table[dev_index].vin_adc_ratio; info->vout_adc_ratio[i] = avalon8_dev_table[dev_index].vout_adc_ratio; + + for (j = 0; j < AVA8_DEFAULT_PLL_CNT; j++) { + if (opt_avalon8_freq[j] == AVA8_DEFAULT_FREQUENCY) + opt_avalon8_freq[j] = avalon8_dev_table[dev_index].set_freq[j]; + } break; } } diff --git a/driver-avalon8.h b/driver-avalon8.h index a14987433a..29fe319a61 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -42,11 +42,11 @@ #define AVA8_DEFAULT_OVERCLOCKING_OFF 0 #define AVA8_DEFAULT_OVERCLOCKING_ON 1 -#define AVA8_DEFAULT_FREQUENCY_0 0 -#define AVA8_DEFAULT_FREQUENCY_1 0 -#define AVA8_DEFAULT_FREQUENCY_2 0 -#define AVA8_DEFAULT_FREQUENCY_3 650 +#define AVA8_DEFAULT_FREQUENCY_0M 0 +#define AVA8_DEFAULT_FREQUENCY_650M 650 +#define AVA8_DEFAULT_FREQUENCY_775M 775 #define AVA8_DEFAULT_FREQUENCY_MAX 1200 +#define AVA8_DEFAULT_FREQUENCY (AVA8_DEFAULT_FREQUENCY_MAX) #define AVA8_DEFAULT_FREQUENCY_SEL 3 #define AVA8_DEFAULT_MODULARS 7 /* Only support 6 modules maximum with one AUC */ @@ -295,6 +295,7 @@ struct avalon8_dev_description { uint16_t vin_adc_ratio; uint16_t vout_adc_ratio; int set_voltage_level; + uint16_t set_freq[AVA8_DEFAULT_PLL_CNT]; }; #define AVA8_WRITE_SIZE (sizeof(struct avalon8_pkg)) From b5b497ec3b9fafb59683278ea0bee8ba69ee5208 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Mon, 5 Mar 2018 18:31:03 +0800 Subject: [PATCH 047/113] Update set frequency for avalon8 --- driver-avalon8.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index e1af4a8125..5cd16cd382 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -1349,11 +1349,6 @@ static void detect_modules(struct cgpu_info *avalon8) info->asic_count[i] = avalon8_dev_table[dev_index].asic_count; info->vin_adc_ratio[i] = avalon8_dev_table[dev_index].vin_adc_ratio; info->vout_adc_ratio[i] = avalon8_dev_table[dev_index].vout_adc_ratio; - - for (j = 0; j < AVA8_DEFAULT_PLL_CNT; j++) { - if (opt_avalon8_freq[j] == AVA8_DEFAULT_FREQUENCY) - opt_avalon8_freq[j] = avalon8_dev_table[dev_index].set_freq[j]; - } break; } } @@ -1382,10 +1377,12 @@ static void detect_modules(struct cgpu_info *avalon8) for (k = 0; k < 5; k++) info->temp[i][j][k] = -273; + + for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) + info->set_frequency[i][j][k] = avalon8_dev_table[dev_index].set_freq[k]; } info->freq_mode[i] = AVA8_FREQ_INIT_MODE; - memset(info->set_frequency[i], 0, sizeof(unsigned int) * info->miner_count[i] * AVA8_DEFAULT_PLL_CNT); memset(info->get_pll[i], 0, sizeof(uint32_t) * info->miner_count[i] * AVA8_DEFAULT_PLL_CNT); info->led_indicator[i] = 0; @@ -1896,8 +1893,10 @@ static int64_t avalon8_scanhash(struct thr_info *thr) case AVA8_FREQ_INIT_MODE: update_settings = true; for (j = 0; j < info->miner_count[i]; j++) { - for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) - info->set_frequency[i][j][k] = opt_avalon8_freq[k]; + for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) { + if (opt_avalon8_freq[k] != AVA8_DEFAULT_FREQUENCY) + info->set_frequency[i][j][k] = opt_avalon8_freq[k]; + } } avalon8_init_setting(avalon8, i); From 40104c12a34275dedf21524a0c96671a884566d9 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 15 Mar 2018 22:04:01 +0800 Subject: [PATCH 048/113] Update set_avalon8_factory_info() --- driver-avalon8.c | 13 +++++++++---- driver-avalon8.h | 12 ++++++++---- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 5cd16cd382..e34cd20539 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -2359,19 +2359,24 @@ char *set_avalon8_device_freq(struct cgpu_info *avalon8, char *arg) char *set_avalon8_factory_info(struct cgpu_info *avalon8, char *arg) { struct avalon8_info *info = avalon8->device_data; + char type[AVA8_DEFAULT_FACTORY_INFO_1_CNT]; int val; if (!(*arg)) return NULL; - sscanf(arg, "%d", &val); - if (!val) - val = AVA8_DEFAULT_FACTORY_INFO_0; + memset(type, 0, AVA8_DEFAULT_FACTORY_INFO_1_CNT); + + sscanf(arg, "%d-%s", &val, type); - if (val < AVA8_DEFAULT_FACTORY_INFO_0_MIN || val > AVA8_DEFAULT_FACTORY_INFO_0_MAX) + if ((val != AVA8_DEFAULT_FACTORY_INFO_0_IGNORE) && + (val < AVA8_DEFAULT_FACTORY_INFO_0_MIN || val > AVA8_DEFAULT_FACTORY_INFO_0_MAX)) return "Invalid value passed to set_avalon8_factory_info"; info->factory_info[0] = val; + + memcpy(&info->factory_info[1], type, AVA8_DEFAULT_FACTORY_INFO_1_CNT); + avalon8_set_factory_info(avalon8, 0, (uint8_t *)info->factory_info); applog(LOG_NOTICE, "%s-%d: Update factory info %d", diff --git a/driver-avalon8.h b/driver-avalon8.h index 29fe319a61..deecbdce4f 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -35,9 +35,13 @@ #define AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET 0 #define AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET_MAX 1 -#define AVA8_DEFAULT_FACTORY_INFO_0_MIN -15 -#define AVA8_DEFAULT_FACTORY_INFO_0 0 -#define AVA8_DEFAULT_FACTORY_INFO_0_MAX 15 +#define AVA8_DEFAULT_FACTORY_INFO_0_MIN -15 +#define AVA8_DEFAULT_FACTORY_INFO_0 0 +#define AVA8_DEFAULT_FACTORY_INFO_0_MAX 15 +#define AVA8_DEFAULT_FACTORY_INFO_0_CNT 1 +#define AVA8_DEFAULT_FACTORY_INFO_0_IGNORE 16 + +#define AVA8_DEFAULT_FACTORY_INFO_1_CNT 3 #define AVA8_DEFAULT_OVERCLOCKING_OFF 0 #define AVA8_DEFAULT_OVERCLOCKING_ON 1 @@ -160,7 +164,7 @@ #define AVA8_FREQ_INIT_MODE 0x0 #define AVA8_FREQ_PLLADJ_MODE 0x1 -#define AVA8_DEFAULT_FACTORY_INFO_CNT 1 +#define AVA8_DEFAULT_FACTORY_INFO_CNT (AVA8_DEFAULT_FACTORY_INFO_0_CNT + AVA8_DEFAULT_FACTORY_INFO_1_CNT) #define AVA8_DEFAULT_OVERCLOCKING_CNT 1 From 13cdfddc2865b4c760044b657e6bbdacbbdea1bb Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 29 Mar 2018 15:18:32 +0800 Subject: [PATCH 049/113] Minor fix --- driver-avalon8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index e34cd20539..c481416cc7 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -1375,7 +1375,7 @@ static void detect_modules(struct cgpu_info *avalon8) info->get_voltage[i][j] = 0; info->get_vin[i][j] = 0; - for (k = 0; k < 5; k++) + for (k = 0; k < info->asic_count[i]; k++) info->temp[i][j][k] = -273; for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) From e857578f0807f60eaf0272d494939cd530fea1ba Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Sat, 21 Apr 2018 00:25:56 +0800 Subject: [PATCH 050/113] Add A822 support --- driver-avalon8.c | 15 +++++++++++++++ driver-avalon8.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/driver-avalon8.c b/driver-avalon8.c index c481416cc7..cbd520c6c0 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -132,6 +132,21 @@ struct avalon8_dev_description avalon8_dev_table[] = { AVA8_DEFAULT_FREQUENCY_650M } }, + { + "822", + 822, + 4, + 26, + AVA8_MM822_VIN_ADC_RATIO, + AVA8_MM822_VOUT_ADC_RATIO, + 5, + { + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_725M + } + }, { "841", 841, diff --git a/driver-avalon8.h b/driver-avalon8.h index deecbdce4f..bf862fbdb1 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -48,6 +48,7 @@ #define AVA8_DEFAULT_FREQUENCY_0M 0 #define AVA8_DEFAULT_FREQUENCY_650M 650 +#define AVA8_DEFAULT_FREQUENCY_725M 725 #define AVA8_DEFAULT_FREQUENCY_775M 775 #define AVA8_DEFAULT_FREQUENCY_MAX 1200 #define AVA8_DEFAULT_FREQUENCY (AVA8_DEFAULT_FREQUENCY_MAX) @@ -169,9 +170,11 @@ #define AVA8_DEFAULT_OVERCLOCKING_CNT 1 #define AVA8_MM821_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) +#define AVA8_MM822_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) #define AVA8_MM841_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) #define AVA8_MM821_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) +#define AVA8_MM822_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) #define AVA8_MM841_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) struct avalon8_pkg { From 4fafa6f4aaf593b463edf1cfdb28d61a847d9078 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Wed, 2 May 2018 12:12:30 +0800 Subject: [PATCH 051/113] Rename A822 to A831 --- driver-avalon8.c | 8 ++++---- driver-avalon8.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index cbd520c6c0..2813ed2b92 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -133,12 +133,12 @@ struct avalon8_dev_description avalon8_dev_table[] = { } }, { - "822", - 822, + "831", + 831, 4, 26, - AVA8_MM822_VIN_ADC_RATIO, - AVA8_MM822_VOUT_ADC_RATIO, + AVA8_MM831_VIN_ADC_RATIO, + AVA8_MM831_VOUT_ADC_RATIO, 5, { AVA8_DEFAULT_FREQUENCY_0M, diff --git a/driver-avalon8.h b/driver-avalon8.h index bf862fbdb1..199fc94e53 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -170,11 +170,11 @@ #define AVA8_DEFAULT_OVERCLOCKING_CNT 1 #define AVA8_MM821_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) -#define AVA8_MM822_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) +#define AVA8_MM831_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) #define AVA8_MM841_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) #define AVA8_MM821_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) -#define AVA8_MM822_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) +#define AVA8_MM831_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) #define AVA8_MM841_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) struct avalon8_pkg { From a45b74b4f73eea2dcd4ec9a6c088786e86a9596e Mon Sep 17 00:00:00 2001 From: xzx Date: Wed, 30 May 2018 11:17:36 +0800 Subject: [PATCH 052/113] Add P_STATUS_ASIC --- driver-avalon8.c | 27 +++++++++++++++++++++++++++ driver-avalon8.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/driver-avalon8.c b/driver-avalon8.c index 2813ed2b92..f45fd604b0 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -675,6 +675,33 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod } } break; + case AVA8_P_STATUS_ASIC: + { + int miner_id; + int asic_id; + + if (!info->asic_count[modular_id]) + break; + + miner_id = ar->idx / info->asic_count[modular_id]; + asic_id = ar->idx % info->asic_count[modular_id]; + + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_ASIC %d-%d", + avalon8->drv->name, avalon8->device_id, modular_id, + miner_id, asic_id); + + memcpy(&tmp, ar->data + 0, 4); + if (tmp) + info->get_asic[modular_id][miner_id][asic_id][0] = be32toh(tmp); + + memcpy(&tmp, ar->data + 4, 4); + if (tmp) + info->get_asic[modular_id][miner_id][asic_id][1] = be32toh(tmp); + + for (i = 0; i < AVA8_DEFAULT_PLL_CNT; i++) + info->get_asic[modular_id][miner_id][asic_id][2 + i] = ar->data[8 + i]; + } + break; case AVA8_P_STATUS_FAC: applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_FAC", avalon8->drv->name, avalon8->device_id, modular_id); info->factory_info[0] = ar->data[0]; diff --git a/driver-avalon8.h b/driver-avalon8.h index 199fc94e53..80b21e8cd2 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -263,6 +263,8 @@ struct avalon8_info { uint32_t get_voltage[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; uint32_t get_pll[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_PLL_CNT]; + uint32_t get_asic[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_ASIC_MAX][6]; + int8_t factory_info[AVA8_DEFAULT_FACTORY_INFO_CNT]; int8_t overclocking_info[AVA8_DEFAULT_OVERCLOCKING_CNT]; From 25112482bfca95af3cd530e16b5b45a9ac3250bf Mon Sep 17 00:00:00 2001 From: xzx Date: Wed, 30 May 2018 11:40:20 +0800 Subject: [PATCH 053/113] Add options for avalon8 * --avalon8-spdlow * --avalon8-spdhigh --- cgminer.c | 11 +++++++++++ driver-avalon8.c | 14 ++++++++++++++ driver-avalon8.h | 4 ++++ 3 files changed, 29 insertions(+) diff --git a/cgminer.c b/cgminer.c index c7917bf4c2..26307a1492 100644 --- a/cgminer.c +++ b/cgminer.c @@ -929,6 +929,11 @@ static char __maybe_unused *set_int_0_to_2(const char *arg, int *i) return set_int_range(arg, i, 0, 2); } +static char __maybe_unused *set_int_0_to_3(const char *arg, int *i) +{ + return set_int_range(arg, i, 0, 3); +} + static char __maybe_unused *set_int_0_to_4(const char *arg, int *i) { return set_int_range(arg, i, 0, 4); @@ -1573,6 +1578,12 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--avalon8-h2ltime0-spd", set_int_0_to_255, opt_show_intval, &opt_avalon8_h2ltime0_spd, "Set Avalon8 h2ltime0 spd, range 0-255."), + OPT_WITH_ARG("--avalon8-spdlow", + set_int_0_to_3, opt_show_intval, &opt_avalon8_spdlow, + "Set Avalon8 spdlow, range 0-3."), + OPT_WITH_ARG("--avalon8-spdhigh", + set_int_0_to_3, opt_show_intval, &opt_avalon8_spdhigh, + "Set Avalon8 spdhigh, range 0-3."), #endif #ifdef USE_AVALON_MINER OPT_WITH_CBARG("--avalonm-voltage", diff --git a/driver-avalon8.c b/driver-avalon8.c index f45fd604b0..b4f1fcec18 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -62,6 +62,8 @@ uint32_t opt_avalon8_mux_l2h = AVA8_DEFAULT_MUX_L2H; uint32_t opt_avalon8_mux_h2l = AVA8_DEFAULT_MUX_H2L; uint32_t opt_avalon8_h2ltime0_spd = AVA8_DEFAULT_H2LTIME0_SPD; uint32_t opt_avalon8_roll_enable = AVA8_DEFAULT_ROLL_ENABLE; +uint32_t opt_avalon8_spdlow = AVA8_DEFAULT_SPDLOW; +uint32_t opt_avalon8_spdhigh = AVA8_DEFAULT_SPDHIGH; uint32_t cpm_table[] = { @@ -1636,6 +1638,18 @@ static void avalon8_init_setting(struct cgpu_info *avalon8, int addr) avalon8->drv->name, avalon8->device_id, addr, opt_avalon8_h2ltime0_spd); + tmp = be32toh(opt_avalon8_spdlow); + memcpy(send_pkg.data + 22, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set spdlow %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_spdlow); + + tmp = be32toh(opt_avalon8_spdhigh); + memcpy(send_pkg.data + 26, &tmp, 4); + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set spdhigh %u", + avalon8->drv->name, avalon8->device_id, addr, + opt_avalon8_spdhigh); + /* Package the data */ avalon8_init_pkg(&send_pkg, AVA8_P_SET, 1, 1); if (addr == AVA8_MODULE_BROADCAST) diff --git a/driver-avalon8.h b/driver-avalon8.h index 80b21e8cd2..583c03ba0e 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -80,6 +80,8 @@ #define AVA8_DEFAULT_MUX_H2L 1 #define AVA8_DEFAULT_H2LTIME0_SPD 3 #define AVA8_DEFAULT_ROLL_ENABLE 1 +#define AVA8_DEFAULT_SPDLOW 0 +#define AVA8_DEFAULT_SPDHIGH 3 #define AVA8_DEFAULT_IIC_DETECT false @@ -336,5 +338,7 @@ extern uint32_t opt_avalon8_mux_l2h; extern uint32_t opt_avalon8_mux_h2l; extern uint32_t opt_avalon8_h2ltime0_spd; extern uint32_t opt_avalon8_roll_enable; +extern uint32_t opt_avalon8_spdlow; +extern uint32_t opt_avalon8_spdhigh; #endif /* USE_AVALON8 */ #endif /* _AVALON8_H_ */ From e5385e67ff4eeded2e2b2b831db0f4e42a9a5f25 Mon Sep 17 00:00:00 2001 From: xzx Date: Wed, 30 May 2018 11:52:34 +0800 Subject: [PATCH 054/113] Add A851 support --- driver-avalon8.c | 15 +++++++++++++++ driver-avalon8.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/driver-avalon8.c b/driver-avalon8.c index b4f1fcec18..a5dfde9a00 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -163,6 +163,21 @@ struct avalon8_dev_description avalon8_dev_table[] = { AVA8_DEFAULT_FREQUENCY_0M, AVA8_DEFAULT_FREQUENCY_775M } + }, + { + "851", + 851, + 4, + 26, + AVA8_MM851_VIN_ADC_RATIO, + AVA8_MM851_VOUT_ADC_RATIO, + 5, + { + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_0M, + AVA8_DEFAULT_FREQUENCY_850M + } } }; diff --git a/driver-avalon8.h b/driver-avalon8.h index 583c03ba0e..0528aecc5a 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -50,6 +50,7 @@ #define AVA8_DEFAULT_FREQUENCY_650M 650 #define AVA8_DEFAULT_FREQUENCY_725M 725 #define AVA8_DEFAULT_FREQUENCY_775M 775 +#define AVA8_DEFAULT_FREQUENCY_850M 850 #define AVA8_DEFAULT_FREQUENCY_MAX 1200 #define AVA8_DEFAULT_FREQUENCY (AVA8_DEFAULT_FREQUENCY_MAX) #define AVA8_DEFAULT_FREQUENCY_SEL 3 @@ -174,10 +175,12 @@ #define AVA8_MM821_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) #define AVA8_MM831_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) #define AVA8_MM841_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) +#define AVA8_MM851_VIN_ADC_RATIO (3.3 / 4095.0 * 25.62 / 5.62 * 1000.0 * 100.0) #define AVA8_MM821_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) #define AVA8_MM831_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) #define AVA8_MM841_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) +#define AVA8_MM851_VOUT_ADC_RATIO (3.3 / 4095.0 * 72.3 / 20.0 * 10000.0 * 100.0) struct avalon8_pkg { uint8_t head[2]; From 37a06b087ba88ee71d09ba59a75fcd7e1020ee24 Mon Sep 17 00:00:00 2001 From: xzx Date: Wed, 30 May 2018 13:29:17 +0800 Subject: [PATCH 055/113] Add DH display for A851 --- driver-avalon8.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index a5dfde9a00..afe924b621 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -2114,6 +2114,22 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) sprintf(buf, " HW[%"PRIu64"]", info->hw_works[i]); strcat(statbuf, buf); + if (!strncmp((char *)&(info->mm_version[i]), "851", 3)) { + double a, b, dh; + + a = 0; + b = 0; + for (j = 0; j < info->miner_count[i]; j++) { + for (k = 0; k < info->asic_count[i]; k++) { + a += info->get_asic[i][j][k][0]; + b += info->get_asic[i][j][k][1]; + } + } + dh = b ? (b / (a + b)) * 100 : 0; + sprintf(buf, " DH[%.3f%%]", dh); + strcat(statbuf, buf); + } + sprintf(buf, " Temp[%d]", info->temp_mm[i]); strcat(statbuf, buf); @@ -2626,9 +2642,11 @@ static void avalon8_statline_before(char *buf, size_t bufsiz, struct cgpu_info * struct avalon8_info *info = avalon8->device_data; int temp = -273; int fanmin = AVA8_DEFAULT_FAN_MAX; - int i; + int i, j, k; uint32_t frequency = 0; float ghs_sum = 0, mhsmm = 0; + double pass_num = 0.0, fail_num = 0.0; + uint8_t flag = 0; for (i = 1; i < AVA8_DEFAULT_MODULARS; i++) { if (!info->enable[i]) @@ -2643,12 +2661,26 @@ static void avalon8_statline_before(char *buf, size_t bufsiz, struct cgpu_info * mhsmm = avalon8_hash_cal(avalon8, i); frequency += (mhsmm / (info->asic_count[i] * info->miner_count[i] * 172)); ghs_sum += (mhsmm / 1000); + + if (!strncmp((char *)&(info->mm_version[i]), "851", 3)) { + for (j = 0; j < info->miner_count[i]; j++) { + for (k = 0; k < info->asic_count[i]; k++) { + pass_num += info->get_asic[i][j][k][0]; + fail_num += info->get_asic[i][j][k][1]; + } + } + flag = 1; + } } if (info->mm_count) frequency /= info->mm_count; - tailsprintf(buf, bufsiz, "%4dMhz %.2fGHS %2dC %3d%%", frequency, ghs_sum, temp, fanmin); + if (flag) + tailsprintf(buf, bufsiz, "%4dMhz %.2fGHS %2dC %.2f%% %3d%%", frequency, ghs_sum, temp, + (fail_num + pass_num) ? fail_num * 100.0 / (fail_num + pass_num) : 0, fanmin); + else + tailsprintf(buf, bufsiz, "%4dMhz %.2fGHS %2dC %3d%%", frequency, ghs_sum, temp, fanmin); } struct device_drv avalon8_drv = { From a1d8a34a320dfcc114ed7169690692bfb9f60f12 Mon Sep 17 00:00:00 2001 From: xzx Date: Wed, 30 May 2018 13:54:22 +0800 Subject: [PATCH 056/113] Update P_STATUS_PVT for A851 --- driver-avalon8.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index afe924b621..263fb3a49b 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -672,7 +672,22 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod break; case AVA8_P_STATUS_PVT: applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_PVT", avalon8->drv->name, avalon8->device_id, modular_id); - { + if (!strncmp((char *)&(info->mm_version[modular_id]), "851", 3)) { + if (!info->asic_count[modular_id]) + break; + + if (ar->idx < info->asic_count[modular_id]) { + for (i = 0; i < info->miner_count[modular_id]; i++) { + memcpy(&tmp, ar->data + i * 4, 2); + tmp = be16toh(tmp); + info->temp[modular_id][i][ar->idx] = decode_pvt_temp(tmp); + + memcpy(&tmp, ar->data + i * 4 + 2, 2); + tmp = be16toh(tmp); + info->core_volt[modular_id][i][ar->idx][0] = decode_pvt_volt(tmp); + } + } + } else { uint16_t pvt_tmp; if (!info->asic_count[modular_id]) From 0ffd9242d8ee20537efe3d9b08ad7d7d527f0f2e Mon Sep 17 00:00:00 2001 From: xzx Date: Wed, 30 May 2018 14:17:12 +0800 Subject: [PATCH 057/113] Update api debug message for A851 --- driver-avalon8.c | 94 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 13 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 263fb3a49b..0919f805d9 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -2246,30 +2246,98 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) } statbuf[strlen(statbuf) - 1] = ']'; - for (j = 0; j < info->miner_count[i]; j++) { - sprintf(buf, " PVT_T%d[", j); - strcat(statbuf, buf); - for (k = 0; k < info->asic_count[i]; k++) { - sprintf(buf, "%d ", info->temp[i][j][k]); + if (!strncmp((char *)&(info->mm_version[i]), "851", 3)) { + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, " PVT_T%d[", j); strcat(statbuf, buf); + for (k = 0; k < info->asic_count[i]; k++) { + sprintf(buf, "%3d ", info->temp[i][j][k]); + strcat(statbuf, buf); + } + + statbuf[strlen(statbuf) - 1] = ']'; + statbuf[strlen(statbuf)] = '\0'; } - statbuf[strlen(statbuf) - 1] = ']'; - statbuf[strlen(statbuf)] = '\0'; - } + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, " PVT_V%d[", j); + strcat(statbuf, buf); + for (k = 0; k < info->asic_count[i]; k++) { + sprintf(buf, "%d ", info->core_volt[i][j][k][0]); + strcat(statbuf, buf); + } - for (j = 0; j < info->miner_count[i]; j++) { - for (k = 0; k < info->asic_count[i]; k++) { - sprintf(buf, " PVT_V%d_%d[", j, k); + statbuf[strlen(statbuf) - 1] = ']'; + statbuf[strlen(statbuf)] = '\0'; + } + + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, " ERATIO%d[", j); + strcat(statbuf, buf); + for (k = 0; k < info->asic_count[i]; k++) { + if (info->get_asic[i][j][k][0]) + sprintf(buf, "%6.2f%% ", (double)(info->get_asic[i][j][k][1] * 100.0 / (info->get_asic[i][j][k][0] + info->get_asic[i][j][k][1]))); + else + sprintf(buf, "%6.2f%% ", 0.0); + strcat(statbuf, buf); + } + + statbuf[strlen(statbuf) - 1] = ']'; + } + + int l; + /* i: modular, j: miner, k:asic, l:value */ + for (l = 0; l < 2; l++) { + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, " C_%02d_%02d[", j, l); + strcat(statbuf, buf); + for (k = 0; k < info->asic_count[i]; k++) { + sprintf(buf, "%7d ", info->get_asic[i][j][k][l]); + strcat(statbuf, buf); + } + + statbuf[strlen(statbuf) - 1] = ']'; + } + } + + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, " GHSmm%02d[", j); + strcat(statbuf, buf); + for (k = 0; k < info->asic_count[i]; k++) { + mhsmm = 0; + for (l = 2; l < 6; l++) + mhsmm += (info->get_asic[i][j][k][l] * info->set_frequency[i][j][l - 2]); + sprintf(buf, "%7.2f ", mhsmm / 1000); + strcat(statbuf, buf); + } + statbuf[strlen(statbuf) - 1] = ']'; + } + } else { + for (j = 0; j < info->miner_count[i]; j++) { + sprintf(buf, " PVT_T%d[", j); strcat(statbuf, buf); - for (m = 0; m < AVA8_DEFAULT_CORE_VOLT_CNT; m++) { - sprintf(buf, "%d ", info->core_volt[i][j][k][m]); + for (k = 0; k < info->asic_count[i]; k++) { + sprintf(buf, "%d ", info->temp[i][j][k]); strcat(statbuf, buf); } statbuf[strlen(statbuf) - 1] = ']'; statbuf[strlen(statbuf)] = '\0'; } + + for (j = 0; j < info->miner_count[i]; j++) { + for (k = 0; k < info->asic_count[i]; k++) { + sprintf(buf, " PVT_V%d_%d[", j, k); + strcat(statbuf, buf); + for (m = 0; m < AVA8_DEFAULT_CORE_VOLT_CNT; m++) { + sprintf(buf, "%d ", info->core_volt[i][j][k][m]); + strcat(statbuf, buf); + } + + statbuf[strlen(statbuf) - 1] = ']'; + statbuf[strlen(statbuf)] = '\0'; + } + } } } From 0f3a9d41c46df403aaa4db594c0ceab7aae47a86 Mon Sep 17 00:00:00 2001 From: xzx Date: Thu, 31 May 2018 17:05:39 +0800 Subject: [PATCH 058/113] Update target temperature --- driver-avalon8.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon8.h b/driver-avalon8.h index 0528aecc5a..5d0ddbb419 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -23,7 +23,7 @@ #define AVA8_DEFAULT_FAN_MAX 100 #define AVA8_DEFAULT_FAN_INTERVAL 15 /* Seconds */ -#define AVA8_DEFAULT_TEMP_TARGET 70 +#define AVA8_DEFAULT_TEMP_TARGET 90 #define AVA8_DEFAULT_TEMP_OVERHEAT 105 #define AVA8_DEFAULT_TEMP_HYSTERESIS 5 From 077d2f8259408773177c330747395a8f3b113cc3 Mon Sep 17 00:00:00 2001 From: xzx Date: Tue, 5 Jun 2018 11:58:59 +0800 Subject: [PATCH 059/113] Update Smart speed parameters --- driver-avalon8.c | 13 +++++++++++-- driver-avalon8.h | 6 ++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 0919f805d9..c63b3818e5 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -1985,6 +1985,10 @@ static int64_t avalon8_scanhash(struct thr_info *thr) } } + if (!strncmp((char *)&(info->mm_version[i]), "851", 3)) { + opt_avalon8_nonce_mask = AVA851_DEFAULT_NONCE_MASK; + opt_avalon8_spdlow = AVA851_DEFAULT_SPDLOW; + } avalon8_init_setting(avalon8, i); info->freq_mode[i] = AVA8_FREQ_PLLADJ_MODE; @@ -2005,9 +2009,14 @@ static int64_t avalon8_scanhash(struct thr_info *thr) avalon8_set_voltage_level(avalon8, i, info->set_voltage_level[i]); for (j = 0; j < info->miner_count[i]; j++) avalon8_set_freq(avalon8, i, j, info->set_frequency[i][j]); - if (opt_avalon8_smart_speed) + if (opt_avalon8_smart_speed) { + if (!strncmp((char *)&(info->mm_version[i]), "851", 3)) { + opt_avalon8_th_pass = AVA851_DEFAULT_TH_PASS; + opt_avalon8_th_fail = AVA851_DEFAULT_TH_FAIL; + opt_avalon8_th_timeout = AVA851_DEFAULT_TH_TIMEOUT; + } avalon8_set_ss_param(avalon8, i); - + } avalon8_set_finish(avalon8, i); cg_wunlock(&info->update_lock); } diff --git a/driver-avalon8.h b/driver-avalon8.h index 5d0ddbb419..2135bf64a1 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -84,6 +84,12 @@ #define AVA8_DEFAULT_SPDLOW 0 #define AVA8_DEFAULT_SPDHIGH 3 +#define AVA851_DEFAULT_TH_PASS 200 +#define AVA851_DEFAULT_TH_FAIL 7000 +#define AVA851_DEFAULT_TH_TIMEOUT 16000 +#define AVA851_DEFAULT_SPDLOW 2 +#define AVA851_DEFAULT_NONCE_MASK 27 + #define AVA8_DEFAULT_IIC_DETECT false #define AVA8_PWM_MAX 0x3FF From c4e7ee6e5472661969595aaefd304a423ac79107 Mon Sep 17 00:00:00 2001 From: xzx Date: Tue, 5 Jun 2018 12:06:18 +0800 Subject: [PATCH 060/113] Update AVA8_DRV_DIFFMAX --- driver-avalon8.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon8.h b/driver-avalon8.h index 2135bf64a1..89d844a7ad 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -93,7 +93,7 @@ #define AVA8_DEFAULT_IIC_DETECT false #define AVA8_PWM_MAX 0x3FF -#define AVA8_DRV_DIFFMAX 500 +#define AVA8_DRV_DIFFMAX 1024 #define AVA8_ASIC_TIMEOUT_CONST 419430400 /* (2^32 * 1000) / (256 * 40) */ #define AVA8_MODULE_DETECT_INTERVAL 30 /* 30 s */ From ad49bfb047abf732db4761df6fe22cc761168cd9 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Wed, 27 Jun 2018 23:03:52 +0800 Subject: [PATCH 061/113] Update mhsmm calculation for A851 --- driver-avalon8.c | 37 +++++++++++++++++++++++++++++-------- driver-avalon8.h | 1 + 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index c63b3818e5..5e686c729c 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -711,6 +711,7 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod { int miner_id; int asic_id; + uint16_t freq; if (!info->asic_count[modular_id]) break; @@ -732,6 +733,13 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod for (i = 0; i < AVA8_DEFAULT_PLL_CNT; i++) info->get_asic[modular_id][miner_id][asic_id][2 + i] = ar->data[8 + i]; + + if (!strncmp((char *)&(info->mm_version[modular_id]), "851", 3)) { + for (i = 0; i < AVA8_DEFAULT_PLL_CNT; i++) { + memcpy(&freq, ar->data + 8 + AVA8_DEFAULT_PLL_CNT + i * 2, 2); + info->get_frequency[modular_id][miner_id][asic_id][i] = be16toh(freq); + } + } } break; case AVA8_P_STATUS_FAC: @@ -2060,16 +2068,25 @@ static float avalon8_hash_cal(struct cgpu_info *avalon8, int modular_id) { struct avalon8_info *info = avalon8->device_data; uint32_t tmp_freq[AVA8_DEFAULT_PLL_CNT]; - unsigned int i, j; + unsigned int i, j, k; float mhsmm; mhsmm = 0; - for (i = 0; i < info->miner_count[modular_id]; i++) { - for (j = 0; j < AVA8_DEFAULT_PLL_CNT; j++) - tmp_freq[j] = info->set_frequency[modular_id][i][j]; + if (!strncmp((char *)&(info->mm_version[modular_id]), "851", 3)) { + for (i = 0; i < info->miner_count[modular_id]; i++) { + for (j = 0; j < info->asic_count[modular_id]; j++) { + for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) + mhsmm += (info->get_asic[modular_id][i][j][2 + k] * info->get_frequency[modular_id][i][j][k]); + } + } + } else { + for (i = 0; i < info->miner_count[modular_id]; i++) { + for (j = 0; j < AVA8_DEFAULT_PLL_CNT; j++) + tmp_freq[j] = info->set_frequency[modular_id][i][j]; - for (j = 0; j < AVA8_DEFAULT_PLL_CNT; j++) - mhsmm += (info->get_pll[modular_id][i][j] * tmp_freq[j]); + for (j = 0; j < AVA8_DEFAULT_PLL_CNT; j++) + mhsmm += (info->get_pll[modular_id][i][j] * tmp_freq[j]); + } } return mhsmm; @@ -2314,8 +2331,12 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) strcat(statbuf, buf); for (k = 0; k < info->asic_count[i]; k++) { mhsmm = 0; - for (l = 2; l < 6; l++) - mhsmm += (info->get_asic[i][j][k][l] * info->set_frequency[i][j][l - 2]); + for (l = 2; l < 6; l++) { + if (!strncmp((char *)&(info->mm_version[i]), "851", 3)) + mhsmm += (info->get_asic[i][j][k][l] * info->get_frequency[i][j][k][l - 2]); + else + mhsmm += (info->get_asic[i][j][k][l] * info->set_frequency[i][j][l - 2]); + } sprintf(buf, "%7.2f ", mhsmm / 1000); strcat(statbuf, buf); } diff --git a/driver-avalon8.h b/driver-avalon8.h index 89d844a7ad..b6ade9f42b 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -269,6 +269,7 @@ struct avalon8_info { int set_voltage_level[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; uint32_t set_frequency[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_PLL_CNT]; + uint32_t get_frequency[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_ASIC_MAX][AVA8_DEFAULT_PLL_CNT]; uint16_t get_vin[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; uint32_t get_voltage[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; From 8f2fdfc285f30e47d219fec00331499786153d59 Mon Sep 17 00:00:00 2001 From: xzx Date: Thu, 21 Jun 2018 11:43:45 +0800 Subject: [PATCH 062/113] Update options for avalon8 --- driver-avalon8.c | 37 +++++++++++++++++++++++++++---------- driver-avalon8.h | 5 +++++ 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 5e686c729c..120babed9a 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -50,19 +50,19 @@ int opt_avalon8_smart_speed = AVA8_DEFAULT_SMART_SPEED; */ bool opt_avalon8_iic_detect = AVA8_DEFAULT_IIC_DETECT; -uint32_t opt_avalon8_th_pass = AVA8_DEFAULT_TH_PASS; -uint32_t opt_avalon8_th_fail = AVA8_DEFAULT_TH_FAIL; +uint32_t opt_avalon8_th_pass = AVA8_INVALID_TH_PASS; +uint32_t opt_avalon8_th_fail = AVA8_INVALID_TH_FAIL; uint32_t opt_avalon8_th_init = AVA8_DEFAULT_TH_INIT; uint32_t opt_avalon8_th_ms = AVA8_DEFAULT_TH_MS; -uint32_t opt_avalon8_th_timeout = AVA8_DEFAULT_TH_TIMEOUT; +uint32_t opt_avalon8_th_timeout = AVA8_INVALID_TH_TIMEOUT; uint32_t opt_avalon8_th_add = AVA8_DEFAULT_TH_ADD; -uint32_t opt_avalon8_nonce_mask = AVA8_DEFAULT_NONCE_MASK; +uint32_t opt_avalon8_nonce_mask = AVA8_INVALID_NONCE_MASK; uint32_t opt_avalon8_nonce_check = AVA8_DEFAULT_NONCE_CHECK; uint32_t opt_avalon8_mux_l2h = AVA8_DEFAULT_MUX_L2H; uint32_t opt_avalon8_mux_h2l = AVA8_DEFAULT_MUX_H2L; uint32_t opt_avalon8_h2ltime0_spd = AVA8_DEFAULT_H2LTIME0_SPD; uint32_t opt_avalon8_roll_enable = AVA8_DEFAULT_ROLL_ENABLE; -uint32_t opt_avalon8_spdlow = AVA8_DEFAULT_SPDLOW; +uint32_t opt_avalon8_spdlow = AVA8_INVALID_SPDLOW; uint32_t opt_avalon8_spdhigh = AVA8_DEFAULT_SPDHIGH; uint32_t cpm_table[] = @@ -1994,8 +1994,15 @@ static int64_t avalon8_scanhash(struct thr_info *thr) } if (!strncmp((char *)&(info->mm_version[i]), "851", 3)) { - opt_avalon8_nonce_mask = AVA851_DEFAULT_NONCE_MASK; - opt_avalon8_spdlow = AVA851_DEFAULT_SPDLOW; + if (opt_avalon8_spdlow == AVA8_INVALID_SPDLOW) + opt_avalon8_spdlow = AVA851_DEFAULT_SPDLOW; + if (opt_avalon8_nonce_mask == AVA8_INVALID_NONCE_MASK) + opt_avalon8_nonce_mask = AVA851_DEFAULT_NONCE_MASK; + } else { + if (opt_avalon8_spdlow == AVA8_INVALID_SPDLOW) + opt_avalon8_spdlow = AVA8_DEFAULT_SPDLOW; + if (opt_avalon8_nonce_mask == AVA8_INVALID_NONCE_MASK) + opt_avalon8_nonce_mask = AVA8_DEFAULT_NONCE_MASK; } avalon8_init_setting(avalon8, i); @@ -2019,9 +2026,19 @@ static int64_t avalon8_scanhash(struct thr_info *thr) avalon8_set_freq(avalon8, i, j, info->set_frequency[i][j]); if (opt_avalon8_smart_speed) { if (!strncmp((char *)&(info->mm_version[i]), "851", 3)) { - opt_avalon8_th_pass = AVA851_DEFAULT_TH_PASS; - opt_avalon8_th_fail = AVA851_DEFAULT_TH_FAIL; - opt_avalon8_th_timeout = AVA851_DEFAULT_TH_TIMEOUT; + if (opt_avalon8_th_pass == AVA8_INVALID_TH_PASS) + opt_avalon8_th_pass = AVA851_DEFAULT_TH_PASS; + if (opt_avalon8_th_fail == AVA8_INVALID_TH_FAIL) + opt_avalon8_th_fail = AVA851_DEFAULT_TH_FAIL; + if (opt_avalon8_th_timeout == AVA8_INVALID_TH_TIMEOUT) + opt_avalon8_th_timeout = AVA851_DEFAULT_TH_TIMEOUT; + } else { + if (opt_avalon8_th_pass == AVA8_INVALID_TH_PASS) + opt_avalon8_th_pass = AVA8_DEFAULT_TH_PASS; + if (opt_avalon8_th_fail == AVA8_INVALID_TH_FAIL) + opt_avalon8_th_fail = AVA8_DEFAULT_TH_FAIL; + if (opt_avalon8_th_timeout == AVA8_INVALID_TH_TIMEOUT) + opt_avalon8_th_timeout = AVA8_DEFAULT_TH_TIMEOUT; } avalon8_set_ss_param(avalon8, i); } diff --git a/driver-avalon8.h b/driver-avalon8.h index b6ade9f42b..ac631ceff3 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -83,6 +83,11 @@ #define AVA8_DEFAULT_ROLL_ENABLE 1 #define AVA8_DEFAULT_SPDLOW 0 #define AVA8_DEFAULT_SPDHIGH 3 +#define AVA8_INVALID_TH_PASS -1 +#define AVA8_INVALID_TH_FAIL -1 +#define AVA8_INVALID_TH_TIMEOUT -1 +#define AVA8_INVALID_NONCE_MASK -1 +#define AVA8_INVALID_SPDLOW -1 #define AVA851_DEFAULT_TH_PASS 200 #define AVA851_DEFAULT_TH_FAIL 7000 From faa50dfd1c50bf15bc038a4e5342ccfbac8a68b1 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Sat, 28 Jul 2018 11:18:41 +0800 Subject: [PATCH 063/113] Update smart speed parameters for A831 --- driver-avalon8.c | 12 ++++++++++++ driver-avalon8.h | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/driver-avalon8.c b/driver-avalon8.c index 120babed9a..70a1e2da37 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -1998,6 +1998,11 @@ static int64_t avalon8_scanhash(struct thr_info *thr) opt_avalon8_spdlow = AVA851_DEFAULT_SPDLOW; if (opt_avalon8_nonce_mask == AVA8_INVALID_NONCE_MASK) opt_avalon8_nonce_mask = AVA851_DEFAULT_NONCE_MASK; + } else if (!strncmp((char *)&(info->mm_version[i]), "831", 3)) { + if (opt_avalon8_spdlow == AVA8_INVALID_SPDLOW) + opt_avalon8_spdlow = AVA831_DEFAULT_SPDLOW; + if (opt_avalon8_nonce_mask == AVA8_INVALID_NONCE_MASK) + opt_avalon8_nonce_mask = AVA831_DEFAULT_NONCE_MASK; } else { if (opt_avalon8_spdlow == AVA8_INVALID_SPDLOW) opt_avalon8_spdlow = AVA8_DEFAULT_SPDLOW; @@ -2032,6 +2037,13 @@ static int64_t avalon8_scanhash(struct thr_info *thr) opt_avalon8_th_fail = AVA851_DEFAULT_TH_FAIL; if (opt_avalon8_th_timeout == AVA8_INVALID_TH_TIMEOUT) opt_avalon8_th_timeout = AVA851_DEFAULT_TH_TIMEOUT; + } else if (!strncmp((char *)&(info->mm_version[i]), "831", 3)) { + if (opt_avalon8_th_pass == AVA8_INVALID_TH_PASS) + opt_avalon8_th_pass = AVA831_DEFAULT_TH_PASS; + if (opt_avalon8_th_fail == AVA8_INVALID_TH_FAIL) + opt_avalon8_th_fail = AVA831_DEFAULT_TH_FAIL; + if (opt_avalon8_th_timeout == AVA8_INVALID_TH_TIMEOUT) + opt_avalon8_th_timeout = AVA831_DEFAULT_TH_TIMEOUT; } else { if (opt_avalon8_th_pass == AVA8_INVALID_TH_PASS) opt_avalon8_th_pass = AVA8_DEFAULT_TH_PASS; diff --git a/driver-avalon8.h b/driver-avalon8.h index ac631ceff3..172a85ab0d 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -95,6 +95,12 @@ #define AVA851_DEFAULT_SPDLOW 2 #define AVA851_DEFAULT_NONCE_MASK 27 +#define AVA831_DEFAULT_TH_PASS 200 +#define AVA831_DEFAULT_TH_FAIL 7000 +#define AVA831_DEFAULT_TH_TIMEOUT 16000 +#define AVA831_DEFAULT_SPDLOW 2 +#define AVA831_DEFAULT_NONCE_MASK 27 + #define AVA8_DEFAULT_IIC_DETECT false #define AVA8_PWM_MAX 0x3FF From e45e7f19d77521fc62a9f5970d3e95f8a6bf6ce2 Mon Sep 17 00:00:00 2001 From: Wangxc Date: Thu, 26 Jul 2018 21:58:08 +0800 Subject: [PATCH 064/113] Support to read LotID and WaferID --- driver-avalon8.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ driver-avalon8.h | 7 ++++++ 2 files changed, 70 insertions(+) diff --git a/driver-avalon8.c b/driver-avalon8.c index 70a1e2da37..47bec2800b 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -27,6 +27,8 @@ int opt_avalon8_fan_max = AVA8_DEFAULT_FAN_MAX; int opt_avalon8_voltage_level = AVA8_INVALID_VOLTAGE_LEVEL; int opt_avalon8_voltage_level_offset = AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET; +static uint8_t opt_avalon8_cycle_hit_flag; + int opt_avalon8_freq[AVA8_DEFAULT_PLL_CNT] = { AVA8_DEFAULT_FREQUENCY, @@ -514,6 +516,8 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod int64_t last_diff1; uint16_t vin; + uint32_t asic_id,miner_id; + if (likely(avalon8->thr)) thr = avalon8->thr[0]; if (ar->head[0] != AVA8_H1 && ar->head[1] != AVA8_H2) { @@ -650,6 +654,40 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod memcpy(&vin, ar->data + 8 + i * 2, 2); info->get_vin[modular_id][i] = decode_vin(info, modular_id, be16toh(vin)); } + break; + case AVA8_P_STATUS_OTP: + if (opt_avalon8_cycle_hit_flag) + break; + + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_OTP", avalon8->drv->name, avalon8->device_id, modular_id); + + /* ASIC reading cycle limit hit */ + if (ar->data[17]) { + applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_OTP, OTP read cycle hit!", avalon8->drv->name, avalon8->device_id, modular_id); + opt_avalon8_cycle_hit_flag = 1; + break; + } + + miner_id = ar->idx; + if (miner_id > AVA8_DEFAULT_MINER_CNT) + break; + + /* the reading step on MM side, 0:byte 3-0, 1:byte 7-4, 2:byte 11-8 */ + switch (ar->data[15]) { + case 0: + memcpy(info->otp_info[miner_id], ar->data, 4); + break; + case 1: + memcpy(info->otp_info[miner_id] + 4, ar->data + 4, 4); + break; + case 2: + memcpy(info->otp_info[miner_id] + 8, ar->data + 8, 4); + break; + default: + break; + } + memcpy(info->otp_info[miner_id] + 15, ar->data + 15, 4); + break; case AVA8_P_STATUS_VOLT: applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_VOLT", avalon8->drv->name, avalon8->device_id, modular_id); @@ -2157,6 +2195,31 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) info->mm_dna[i][7]); strcat(statbuf, buf); + if (opt_debug) { + for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { + sprintf(buf, " LotID%d_ASIC%d[%c%c%c%c%c%c%c%c%c]", k, + info->otp_info[k][16], + info->otp_info[k][0], + info->otp_info[k][1], + info->otp_info[k][2], + info->otp_info[k][3], + info->otp_info[k][4], + info->otp_info[k][5], + info->otp_info[k][6], + info->otp_info[k][7], + info->otp_info[k][8]); + strcat(statbuf, buf); + } + + for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { + sprintf(buf, " WaferID%d_ASIC%d[%c%c]", k, + info->otp_info[k][16], + info->otp_info[k][9], + info->otp_info[k][10]); + strcat(statbuf, buf); + } + } + sprintf(buf, " Elapsed[%.0f]", tdiff(¤t, &(info->elapsed[i]))); strcat(statbuf, buf); diff --git a/driver-avalon8.h b/driver-avalon8.h index 172a85ab0d..bfa222c1a3 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -35,6 +35,8 @@ #define AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET 0 #define AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET_MAX 1 +#define AVA8_INVALID_ASIC_OTP -1 + #define AVA8_DEFAULT_FACTORY_INFO_0_MIN -15 #define AVA8_DEFAULT_FACTORY_INFO_0 0 #define AVA8_DEFAULT_FACTORY_INFO_0_MAX 15 @@ -129,6 +131,8 @@ #define AVA8_P_COUNT 40 #define AVA8_P_DATA_LEN 32 +#define AVA8_OTP_LEN 32 + /* Broadcase with block iic_write*/ #define AVA8_P_DETECT 0x10 @@ -172,6 +176,7 @@ #define AVA8_P_STATUS_PVT 0x4c #define AVA8_P_STATUS_FAC 0x4d #define AVA8_P_STATUS_OC 0x4e +#define AVA8_P_STATUS_OTP 0x4f #define AVA8_MODULE_BROADCAST 0 /* End of avalon8 protocol package type */ @@ -257,6 +262,8 @@ struct avalon8_info { uint32_t total_asics[AVA8_DEFAULT_MODULARS]; uint32_t max_ntime; /* Maximum: 7200 */ + uint8_t otp_info[AVA8_DEFAULT_MINER_CNT][AVA8_OTP_LEN + 1]; + int mod_type[AVA8_DEFAULT_MODULARS]; uint8_t miner_count[AVA8_DEFAULT_MODULARS]; uint8_t asic_count[AVA8_DEFAULT_MODULARS]; From 45c7ee1a1ed55d49370e639d82a98473af55b286 Mon Sep 17 00:00:00 2001 From: Wangxc Date: Thu, 26 Jul 2018 22:14:13 +0800 Subject: [PATCH 065/113] Add a new option for avalon8 * --avalon8-asic-otp --- cgminer.c | 4 +++ driver-avalon8.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ driver-avalon8.h | 6 +++++ 3 files changed, 75 insertions(+) diff --git a/cgminer.c b/cgminer.c index 26307a1492..36c1fe0ab3 100644 --- a/cgminer.c +++ b/cgminer.c @@ -278,6 +278,7 @@ static char *opt_set_avalon8_fan; static char *opt_set_avalon8_voltage_level; static char *opt_set_avalon8_voltage_level_offset; static char *opt_set_avalon8_freq; +static char *opt_set_avalon8_asic_otp; #endif #ifdef USE_AVALON_MINER static char *opt_set_avalonm_voltage; @@ -1584,6 +1585,9 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--avalon8-spdhigh", set_int_0_to_3, opt_show_intval, &opt_avalon8_spdhigh, "Set Avalon8 spdhigh, range 0-3."), + OPT_WITH_CBARG("--avalon8-asic-otp", + set_avalon8_asic_otp, NULL, &opt_set_avalon8_asic_otp, + "Set Avalon8 asic index for reading otp info, range:[0, 25], step: 1"), #endif #ifdef USE_AVALON_MINER OPT_WITH_CBARG("--avalonm-voltage", diff --git a/driver-avalon8.c b/driver-avalon8.c index 47bec2800b..b224734aa8 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -27,6 +27,7 @@ int opt_avalon8_fan_max = AVA8_DEFAULT_FAN_MAX; int opt_avalon8_voltage_level = AVA8_INVALID_VOLTAGE_LEVEL; int opt_avalon8_voltage_level_offset = AVA8_DEFAULT_VOLTAGE_LEVEL_OFFSET; +int opt_avalon8_asic_otp = AVA8_INVALID_ASIC_OTP; static uint8_t opt_avalon8_cycle_hit_flag; int opt_avalon8_freq[AVA8_DEFAULT_PLL_CNT] = @@ -371,6 +372,29 @@ char *set_avalon8_voltage_level_offset(char *arg) return NULL; } +char *set_avalon8_asic_otp(char *arg) +{ + int val, ret; + char buf[70], *buf_ptr; + + buf_ptr = buf; + + ret = sscanf(arg, "%d", &val); + if (ret < 1) + return "No value passed to avalon8-asic-otp"; + + if (val < 0 || val > (AVA8_DEFAULT_ASIC_MAX-1)) { + sprintf(buf, "Invalid value %d passed to avalon8-asic-otp! Valid range: 0-%d", val,(AVA8_DEFAULT_ASIC_MAX-1)); + return buf_ptr; + } + + opt_avalon8_asic_otp = val; + + opt_avalon8_cycle_hit_flag = 0; + + return NULL; +} + static int avalon8_init_pkg(struct avalon8_pkg *pkg, uint8_t type, uint8_t idx, uint8_t cnt) { unsigned short crc; @@ -688,6 +712,11 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod } memcpy(info->otp_info[miner_id] + 15, ar->data + 15, 4); + /* check for invisible charactor */ + for(i = 0; i < 11; i++) { + if ((info->otp_info[miner_id][i] < 32) || (info->otp_info[miner_id][i] > 126)) + info->otp_info[miner_id][i] = '0'; + } break; case AVA8_P_STATUS_VOLT: applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_VOLT", avalon8->drv->name, avalon8->device_id, modular_id); @@ -1500,6 +1529,11 @@ static void detect_modules(struct cgpu_info *avalon8) for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) info->set_frequency[i][j][k] = avalon8_dev_table[dev_index].set_freq[k]; + + if (AVA8_INVALID_ASIC_OTP == opt_avalon8_asic_otp) + info->set_asic_otp[i][j] = 0; /* default asic: 0 */ + else + info->set_asic_otp[i][j] = opt_avalon8_asic_otp; } info->freq_mode[i] = AVA8_FREQ_INIT_MODE; @@ -1761,6 +1795,36 @@ static void avalon8_set_voltage_level(struct cgpu_info *avalon8, int addr, unsig avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); } +static void avalon8_set_asic_otp(struct cgpu_info *avalon8, int addr, unsigned int asic[]) +{ + struct avalon8_info *info = avalon8->device_data; + struct avalon8_pkg send_pkg; + uint32_t tmp, core_sel; + uint8_t i; + + memset(send_pkg.data, 0, AVA8_P_DATA_LEN); + + /* NOTE: miner_count should <= 8 */ + for (i = 0; i < info->miner_count[addr]; i++) { + if (asic[i] < 0) + asic[i] = 0; + else if (asic[i] > (AVA8_DEFAULT_ASIC_MAX -1)) + asic[i] = AVA8_DEFAULT_ASIC_MAX - 1; + tmp = be32toh(asic[i]); + memcpy(send_pkg.data + i * 4, &tmp, 4); + } + applog(LOG_DEBUG, "%s-%d-%d: avalon8 set asic for otp reading %d, (%d-%d)", + avalon8->drv->name, avalon8->device_id, addr, + i, asic[0], asic[info->miner_count[addr] - 1]); + + /* Package the data */ + avalon8_init_pkg(&send_pkg, AVA8_P_SET_ASIC_OTP, 1, 1); + if (addr == AVA8_MODULE_BROADCAST) + avalon8_send_bc_pkgs(avalon8, &send_pkg); + else + avalon8_iic_xfer_pkg(avalon8, addr, &send_pkg, NULL); +} + static void avalon8_set_freq(struct cgpu_info *avalon8, int addr, int miner_id, unsigned int freq[]) { struct avalon8_info *info = avalon8->device_data; @@ -2065,6 +2129,7 @@ static int64_t avalon8_scanhash(struct thr_info *thr) if (update_settings) { cg_wlock(&info->update_lock); avalon8_set_voltage_level(avalon8, i, info->set_voltage_level[i]); + avalon8_set_asic_otp(avalon8, i, info->set_asic_otp[i]); for (j = 0; j < info->miner_count[i]; j++) avalon8_set_freq(avalon8, i, j, info->set_frequency[i][j]); if (opt_avalon8_smart_speed) { diff --git a/driver-avalon8.h b/driver-avalon8.h index bfa222c1a3..3e534d1cb4 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -177,6 +177,7 @@ #define AVA8_P_STATUS_FAC 0x4d #define AVA8_P_STATUS_OC 0x4e #define AVA8_P_STATUS_OTP 0x4f +#define AVA8_P_SET_ASIC_OTP 0x50 #define AVA8_MODULE_BROADCAST 0 /* End of avalon8 protocol package type */ @@ -289,6 +290,8 @@ struct avalon8_info { uint32_t set_frequency[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_PLL_CNT]; uint32_t get_frequency[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_ASIC_MAX][AVA8_DEFAULT_PLL_CNT]; + int set_asic_otp[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; + uint16_t get_vin[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; uint32_t get_voltage[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; uint32_t get_pll[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_PLL_CNT]; @@ -335,6 +338,7 @@ struct avalon8_dev_description { uint16_t vout_adc_ratio; int set_voltage_level; uint16_t set_freq[AVA8_DEFAULT_PLL_CNT]; + int set_asic_otp; }; #define AVA8_WRITE_SIZE (sizeof(struct avalon8_pkg)) @@ -368,5 +372,7 @@ extern uint32_t opt_avalon8_h2ltime0_spd; extern uint32_t opt_avalon8_roll_enable; extern uint32_t opt_avalon8_spdlow; extern uint32_t opt_avalon8_spdhigh; +extern char *set_avalon8_asic_otp(char *arg); + #endif /* USE_AVALON8 */ #endif /* _AVALON8_H_ */ From 8f54bba3daf5c625b66988c6bb5a99e8ca569a4e Mon Sep 17 00:00:00 2001 From: Wangxc Date: Tue, 31 Jul 2018 21:19:46 +0800 Subject: [PATCH 066/113] add modular_id support for otp info --- driver-avalon8.c | 42 +++++++++++++++++++++--------------------- driver-avalon8.h | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index b224734aa8..df5792d424 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -699,23 +699,23 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod /* the reading step on MM side, 0:byte 3-0, 1:byte 7-4, 2:byte 11-8 */ switch (ar->data[15]) { case 0: - memcpy(info->otp_info[miner_id], ar->data, 4); + memcpy(info->otp_info[modular_id][miner_id], ar->data, 4); break; case 1: - memcpy(info->otp_info[miner_id] + 4, ar->data + 4, 4); + memcpy(info->otp_info[modular_id][miner_id] + 4, ar->data + 4, 4); break; case 2: - memcpy(info->otp_info[miner_id] + 8, ar->data + 8, 4); + memcpy(info->otp_info[modular_id][miner_id] + 8, ar->data + 8, 4); break; default: break; } - memcpy(info->otp_info[miner_id] + 15, ar->data + 15, 4); + memcpy(info->otp_info[modular_id][miner_id] + 15, ar->data + 15, 4); /* check for invisible charactor */ for(i = 0; i < 11; i++) { - if ((info->otp_info[miner_id][i] < 32) || (info->otp_info[miner_id][i] > 126)) - info->otp_info[miner_id][i] = '0'; + if ((info->otp_info[modular_id][miner_id][i] < 32) || (info->otp_info[modular_id][miner_id][i] > 126)) + info->otp_info[modular_id][miner_id][i] = '0'; } break; case AVA8_P_STATUS_VOLT: @@ -1533,8 +1533,8 @@ static void detect_modules(struct cgpu_info *avalon8) if (AVA8_INVALID_ASIC_OTP == opt_avalon8_asic_otp) info->set_asic_otp[i][j] = 0; /* default asic: 0 */ else - info->set_asic_otp[i][j] = opt_avalon8_asic_otp; - } + info->set_asic_otp[i][j] = opt_avalon8_asic_otp; + } info->freq_mode[i] = AVA8_FREQ_INIT_MODE; memset(info->get_pll[i], 0, sizeof(uint32_t) * info->miner_count[i] * AVA8_DEFAULT_PLL_CNT); @@ -2263,24 +2263,24 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) if (opt_debug) { for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { sprintf(buf, " LotID%d_ASIC%d[%c%c%c%c%c%c%c%c%c]", k, - info->otp_info[k][16], - info->otp_info[k][0], - info->otp_info[k][1], - info->otp_info[k][2], - info->otp_info[k][3], - info->otp_info[k][4], - info->otp_info[k][5], - info->otp_info[k][6], - info->otp_info[k][7], - info->otp_info[k][8]); + info->otp_info[i][k][16], + info->otp_info[i][k][0], + info->otp_info[i][k][1], + info->otp_info[i][k][2], + info->otp_info[i][k][3], + info->otp_info[i][k][4], + info->otp_info[i][k][5], + info->otp_info[i][k][6], + info->otp_info[i][k][7], + info->otp_info[i][k][8]); strcat(statbuf, buf); } for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { sprintf(buf, " WaferID%d_ASIC%d[%c%c]", k, - info->otp_info[k][16], - info->otp_info[k][9], - info->otp_info[k][10]); + info->otp_info[i][k][16], + info->otp_info[i][k][9], + info->otp_info[i][k][10]); strcat(statbuf, buf); } } diff --git a/driver-avalon8.h b/driver-avalon8.h index 3e534d1cb4..d6b160c6a6 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -263,7 +263,7 @@ struct avalon8_info { uint32_t total_asics[AVA8_DEFAULT_MODULARS]; uint32_t max_ntime; /* Maximum: 7200 */ - uint8_t otp_info[AVA8_DEFAULT_MINER_CNT][AVA8_OTP_LEN + 1]; + uint8_t otp_info[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_OTP_LEN + 1]; int mod_type[AVA8_DEFAULT_MODULARS]; uint8_t miner_count[AVA8_DEFAULT_MODULARS]; From 5a74ee4fc2733a53058526e52f50ebcb69fcbcb6 Mon Sep 17 00:00:00 2001 From: Wangxc Date: Tue, 31 Jul 2018 21:23:46 +0800 Subject: [PATCH 067/113] add otp_info initializing --- driver-avalon8.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/driver-avalon8.c b/driver-avalon8.c index df5792d424..994c90adf4 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -1534,6 +1534,11 @@ static void detect_modules(struct cgpu_info *avalon8) info->set_asic_otp[i][j] = 0; /* default asic: 0 */ else info->set_asic_otp[i][j] = opt_avalon8_asic_otp; + + for(k = 0; k < 11; k++) { + if ((info->otp_info[i][j][k] < 32) || (info->otp_info[i][j][k] > 126)) + info->otp_info[i][j][k] = '0'; + } } info->freq_mode[i] = AVA8_FREQ_INIT_MODE; From 7c5ea77be237e65db5583ed9bfa0900c6fa9e1b3 Mon Sep 17 00:00:00 2001 From: Wangxc Date: Fri, 10 Aug 2018 15:38:39 +0800 Subject: [PATCH 068/113] add reading OTP lot id CRC info --- driver-avalon8.c | 62 ++++++++++++++++++++++++++++++------------------ driver-avalon8.h | 6 +++++ 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 994c90adf4..b0fbc2b44b 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -686,7 +686,7 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_OTP", avalon8->drv->name, avalon8->device_id, modular_id); /* ASIC reading cycle limit hit */ - if (ar->data[17]) { + if (ar->data[AVA8_OTP_INDEX_CYCLE_HIT]) { applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_OTP, OTP read cycle hit!", avalon8->drv->name, avalon8->device_id, modular_id); opt_avalon8_cycle_hit_flag = 1; break; @@ -696,24 +696,29 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod if (miner_id > AVA8_DEFAULT_MINER_CNT) break; - /* the reading step on MM side, 0:byte 3-0, 1:byte 7-4, 2:byte 11-8 */ - switch (ar->data[15]) { + /* the reading step on MM side, 0:byte 3-0, 1:byte 7-4, 2:byte 11-8, 3:byte 15-12 */ + switch (ar->data[AVA8_OTP_INDEX_READ_STEP]) { case 0: - memcpy(info->otp_info[modular_id][miner_id], ar->data, 4); + memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTIDCRC_OFFSET, ar->data + AVA8_OTP_INFO_LOTIDCRC_OFFSET, 4); break; case 1: - memcpy(info->otp_info[modular_id][miner_id] + 4, ar->data + 4, 4); + memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTID_OFFSET, ar->data + AVA8_OTP_INFO_LOTID_OFFSET, 4); break; case 2: - memcpy(info->otp_info[modular_id][miner_id] + 8, ar->data + 8, 4); + memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTID_OFFSET + 4, ar->data + AVA8_OTP_INFO_LOTID_OFFSET + 4, 4); + break; + case 3: + memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTID_OFFSET + 8, ar->data + AVA8_OTP_INFO_LOTID_OFFSET + 8, 4); break; default: break; } - memcpy(info->otp_info[modular_id][miner_id] + 15, ar->data + 15, 4); + + /* get the data behind AVA8_OTP_INDEX_READ_STEP for later displaying use*/ + memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INDEX_READ_STEP, ar->data + AVA8_OTP_INDEX_READ_STEP, 4); - /* check for invisible charactor */ - for(i = 0; i < 11; i++) { + /* check for invisible charactors, just for lot id and wafer id, 9+2 bytes*/ + for(i = AVA8_OTP_INFO_LOTID_OFFSET; i < (AVA8_OTP_INFO_LOTID_OFFSET + 11); i++) { if ((info->otp_info[modular_id][miner_id][i] < 32) || (info->otp_info[modular_id][miner_id][i] > 126)) info->otp_info[modular_id][miner_id][i] = '0'; } @@ -1535,7 +1540,7 @@ static void detect_modules(struct cgpu_info *avalon8) else info->set_asic_otp[i][j] = opt_avalon8_asic_otp; - for(k = 0; k < 11; k++) { + for(k = AVA8_OTP_INFO_LOTID_OFFSET; k < (AVA8_OTP_INFO_LOTID_OFFSET + 11); k++) { if ((info->otp_info[i][j][k] < 32) || (info->otp_info[i][j][k] > 126)) info->otp_info[i][j][k] = '0'; } @@ -2268,26 +2273,37 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) if (opt_debug) { for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { sprintf(buf, " LotID%d_ASIC%d[%c%c%c%c%c%c%c%c%c]", k, - info->otp_info[i][k][16], - info->otp_info[i][k][0], - info->otp_info[i][k][1], - info->otp_info[i][k][2], - info->otp_info[i][k][3], - info->otp_info[i][k][4], - info->otp_info[i][k][5], - info->otp_info[i][k][6], - info->otp_info[i][k][7], - info->otp_info[i][k][8]); + info->otp_info[i][k][AVA8_OTP_INDEX_ASIC_NUM], + info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET], + info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 1], + info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 2], + info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 3], + info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 4], + info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 5], + info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 6], + info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 7], + info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 8]); strcat(statbuf, buf); } for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { sprintf(buf, " WaferID%d_ASIC%d[%c%c]", k, - info->otp_info[i][k][16], - info->otp_info[i][k][9], - info->otp_info[i][k][10]); + info->otp_info[i][k][AVA8_OTP_INDEX_ASIC_NUM], + info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 9], + info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 10]); strcat(statbuf, buf); } + + for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { + sprintf(buf, " LotIDCRC%d_ASIC%d[%02x%02x%02x%02x]", k, + info->otp_info[i][k][AVA8_OTP_INDEX_ASIC_NUM], + info->otp_info[i][k][AVA8_OTP_INFO_LOTIDCRC_OFFSET], + info->otp_info[i][k][AVA8_OTP_INFO_LOTIDCRC_OFFSET + 1], + info->otp_info[i][k][AVA8_OTP_INFO_LOTIDCRC_OFFSET + 2], + info->otp_info[i][k][AVA8_OTP_INFO_LOTIDCRC_OFFSET + 3]); + strcat(statbuf, buf); + } + } sprintf(buf, " Elapsed[%.0f]", tdiff(¤t, &(info->elapsed[i]))); diff --git a/driver-avalon8.h b/driver-avalon8.h index d6b160c6a6..94a2ae39b3 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -205,6 +205,12 @@ #define AVA8_MM841_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) #define AVA8_MM851_VOUT_ADC_RATIO (3.3 / 4095.0 * 72.3 / 20.0 * 10000.0 * 100.0) +#define AVA8_OTP_INDEX_READ_STEP 27 +#define AVA8_OTP_INDEX_ASIC_NUM 28 +#define AVA8_OTP_INDEX_CYCLE_HIT 29 +#define AVA8_OTP_INFO_LOTIDCRC_OFFSET 0 +#define AVA8_OTP_INFO_LOTID_OFFSET 4 + struct avalon8_pkg { uint8_t head[2]; uint8_t type; From c56e44583c638730094aa7941893ac1da1cc7044 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 16 Aug 2018 10:38:02 +0800 Subject: [PATCH 069/113] Fix compile warning --- driver-avalon8.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index b0fbc2b44b..520dc44351 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -375,18 +375,13 @@ char *set_avalon8_voltage_level_offset(char *arg) char *set_avalon8_asic_otp(char *arg) { int val, ret; - char buf[70], *buf_ptr; - - buf_ptr = buf; ret = sscanf(arg, "%d", &val); if (ret < 1) return "No value passed to avalon8-asic-otp"; - if (val < 0 || val > (AVA8_DEFAULT_ASIC_MAX-1)) { - sprintf(buf, "Invalid value %d passed to avalon8-asic-otp! Valid range: 0-%d", val,(AVA8_DEFAULT_ASIC_MAX-1)); - return buf_ptr; - } + if (val < 0 || val > (AVA8_DEFAULT_ASIC_MAX - 1)) + return "Invalid value passed to avalon8-asic-otp"; opt_avalon8_asic_otp = val; @@ -713,7 +708,7 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod default: break; } - + /* get the data behind AVA8_OTP_INDEX_READ_STEP for later displaying use*/ memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INDEX_READ_STEP, ar->data + AVA8_OTP_INDEX_READ_STEP, 4); @@ -1538,8 +1533,8 @@ static void detect_modules(struct cgpu_info *avalon8) if (AVA8_INVALID_ASIC_OTP == opt_avalon8_asic_otp) info->set_asic_otp[i][j] = 0; /* default asic: 0 */ else - info->set_asic_otp[i][j] = opt_avalon8_asic_otp; - + info->set_asic_otp[i][j] = opt_avalon8_asic_otp; + for(k = AVA8_OTP_INFO_LOTID_OFFSET; k < (AVA8_OTP_INFO_LOTID_OFFSET + 11); k++) { if ((info->otp_info[i][j][k] < 32) || (info->otp_info[i][j][k] > 126)) info->otp_info[i][j][k] = '0'; @@ -2293,7 +2288,7 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 10]); strcat(statbuf, buf); } - + for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { sprintf(buf, " LotIDCRC%d_ASIC%d[%02x%02x%02x%02x]", k, info->otp_info[i][k][AVA8_OTP_INDEX_ASIC_NUM], From 90eeddf83873f79f629202349b0ccdd25cfc337e Mon Sep 17 00:00:00 2001 From: Wangxc Date: Thu, 16 Aug 2018 15:31:08 +0800 Subject: [PATCH 070/113] Update AVA8_OTP_INFO_LOTID_OFFSET --- driver-avalon8.c | 14 +++++++------- driver-avalon8.h | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 520dc44351..2264dcbb53 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -374,20 +374,20 @@ char *set_avalon8_voltage_level_offset(char *arg) char *set_avalon8_asic_otp(char *arg) { - int val, ret; + int val, ret; - ret = sscanf(arg, "%d", &val); - if (ret < 1) + ret = sscanf(arg, "%d", &val); + if (ret < 1) return "No value passed to avalon8-asic-otp"; - if (val < 0 || val > (AVA8_DEFAULT_ASIC_MAX - 1)) + if (val < 0 || val > (AVA8_DEFAULT_ASIC_MAX - 1)) return "Invalid value passed to avalon8-asic-otp"; - opt_avalon8_asic_otp = val; + opt_avalon8_asic_otp = val; - opt_avalon8_cycle_hit_flag = 0; + opt_avalon8_cycle_hit_flag = 0; - return NULL; + return NULL; } static int avalon8_init_pkg(struct avalon8_pkg *pkg, uint8_t type, uint8_t idx, uint8_t cnt) diff --git a/driver-avalon8.h b/driver-avalon8.h index 94a2ae39b3..4708661995 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -205,11 +205,11 @@ #define AVA8_MM841_VOUT_ADC_RATIO (3.3 / 4095.0 * 63.0 / 20.0 * 10000.0 * 100.0) #define AVA8_MM851_VOUT_ADC_RATIO (3.3 / 4095.0 * 72.3 / 20.0 * 10000.0 * 100.0) -#define AVA8_OTP_INDEX_READ_STEP 27 -#define AVA8_OTP_INDEX_ASIC_NUM 28 -#define AVA8_OTP_INDEX_CYCLE_HIT 29 -#define AVA8_OTP_INFO_LOTIDCRC_OFFSET 0 -#define AVA8_OTP_INFO_LOTID_OFFSET 4 +#define AVA8_OTP_INDEX_READ_STEP 27 +#define AVA8_OTP_INDEX_ASIC_NUM 28 +#define AVA8_OTP_INDEX_CYCLE_HIT 29 +#define AVA8_OTP_INFO_LOTIDCRC_OFFSET 0 +#define AVA8_OTP_INFO_LOTID_OFFSET 6 struct avalon8_pkg { uint8_t head[2]; From 4c38c03a94a6801df641fa2241213459d41dd6ae Mon Sep 17 00:00:00 2001 From: Wangxc Date: Thu, 16 Aug 2018 15:59:05 +0800 Subject: [PATCH 071/113] Update the lotid and waferid display mode --- driver-avalon8.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 2264dcbb53..87c0babb9d 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -712,11 +712,6 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod /* get the data behind AVA8_OTP_INDEX_READ_STEP for later displaying use*/ memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INDEX_READ_STEP, ar->data + AVA8_OTP_INDEX_READ_STEP, 4); - /* check for invisible charactors, just for lot id and wafer id, 9+2 bytes*/ - for(i = AVA8_OTP_INFO_LOTID_OFFSET; i < (AVA8_OTP_INFO_LOTID_OFFSET + 11); i++) { - if ((info->otp_info[modular_id][miner_id][i] < 32) || (info->otp_info[modular_id][miner_id][i] > 126)) - info->otp_info[modular_id][miner_id][i] = '0'; - } break; case AVA8_P_STATUS_VOLT: applog(LOG_DEBUG, "%s-%d-%d: AVA8_P_STATUS_VOLT", avalon8->drv->name, avalon8->device_id, modular_id); @@ -1534,12 +1529,7 @@ static void detect_modules(struct cgpu_info *avalon8) info->set_asic_otp[i][j] = 0; /* default asic: 0 */ else info->set_asic_otp[i][j] = opt_avalon8_asic_otp; - - for(k = AVA8_OTP_INFO_LOTID_OFFSET; k < (AVA8_OTP_INFO_LOTID_OFFSET + 11); k++) { - if ((info->otp_info[i][j][k] < 32) || (info->otp_info[i][j][k] > 126)) - info->otp_info[i][j][k] = '0'; - } - } + } info->freq_mode[i] = AVA8_FREQ_INIT_MODE; memset(info->get_pll[i], 0, sizeof(uint32_t) * info->miner_count[i] * AVA8_DEFAULT_PLL_CNT); @@ -2267,7 +2257,7 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) if (opt_debug) { for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { - sprintf(buf, " LotID%d_ASIC%d[%c%c%c%c%c%c%c%c%c]", k, + sprintf(buf, " LotID%d_ASIC%d[%02x%02x%02x%02x%02x%02x%02x%02x%02x]", k, info->otp_info[i][k][AVA8_OTP_INDEX_ASIC_NUM], info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET], info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 1], @@ -2282,7 +2272,7 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) } for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { - sprintf(buf, " WaferID%d_ASIC%d[%c%c]", k, + sprintf(buf, " WaferID%d_ASIC%d[%02x%02x]", k, info->otp_info[i][k][AVA8_OTP_INDEX_ASIC_NUM], info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 9], info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 10]); From 22e35c90dc202868dda9e6522e1c064d6ac74dbe Mon Sep 17 00:00:00 2001 From: Wangxc Date: Thu, 16 Aug 2018 17:31:51 +0800 Subject: [PATCH 072/113] Update otp display --- driver-avalon8.c | 48 ++++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 87c0babb9d..034c408ec3 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -697,14 +697,23 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTIDCRC_OFFSET, ar->data + AVA8_OTP_INFO_LOTIDCRC_OFFSET, 4); break; case 1: - memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTID_OFFSET, ar->data + AVA8_OTP_INFO_LOTID_OFFSET, 4); + memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTIDCRC_OFFSET + 4, ar->data + AVA8_OTP_INFO_LOTIDCRC_OFFSET + 4, 2); break; case 2: - memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTID_OFFSET + 4, ar->data + AVA8_OTP_INFO_LOTID_OFFSET + 4, 4); + memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTID_OFFSET, ar->data + AVA8_OTP_INFO_LOTID_OFFSET, 4); break; case 3: + memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTID_OFFSET + 4, ar->data + AVA8_OTP_INFO_LOTID_OFFSET + 4, 4); + break; + case 4: memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTID_OFFSET + 8, ar->data + AVA8_OTP_INFO_LOTID_OFFSET + 8, 4); break; + case 5: + memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTID_OFFSET + 12, ar->data + AVA8_OTP_INFO_LOTID_OFFSET + 12, 4); + break; + case 6: + memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INFO_LOTID_OFFSET + 16, ar->data + AVA8_OTP_INFO_LOTID_OFFSET + 16, 4); + break; default: break; } @@ -2257,40 +2266,19 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) if (opt_debug) { for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { - sprintf(buf, " LotID%d_ASIC%d[%02x%02x%02x%02x%02x%02x%02x%02x%02x]", k, - info->otp_info[i][k][AVA8_OTP_INDEX_ASIC_NUM], - info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET], - info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 1], - info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 2], - info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 3], - info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 4], - info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 5], - info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 6], - info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 7], - info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 8]); + sprintf(buf, " CINFO%d%d[", k, + info->otp_info[i][k][AVA8_OTP_INDEX_ASIC_NUM]); strcat(statbuf, buf); - } - for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { - sprintf(buf, " WaferID%d_ASIC%d[%02x%02x]", k, - info->otp_info[i][k][AVA8_OTP_INDEX_ASIC_NUM], - info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 9], - info->otp_info[i][k][AVA8_OTP_INFO_LOTID_OFFSET + 10]); - strcat(statbuf, buf); - } + for (m = 0; m < 23; m++) { + sprintf(buf, "%02x", info->otp_info[i][k][m]); + strcat(statbuf, buf); + } - for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { - sprintf(buf, " LotIDCRC%d_ASIC%d[%02x%02x%02x%02x]", k, - info->otp_info[i][k][AVA8_OTP_INDEX_ASIC_NUM], - info->otp_info[i][k][AVA8_OTP_INFO_LOTIDCRC_OFFSET], - info->otp_info[i][k][AVA8_OTP_INFO_LOTIDCRC_OFFSET + 1], - info->otp_info[i][k][AVA8_OTP_INFO_LOTIDCRC_OFFSET + 2], - info->otp_info[i][k][AVA8_OTP_INFO_LOTIDCRC_OFFSET + 3]); + sprintf(buf, "]"); strcat(statbuf, buf); } - } - sprintf(buf, " Elapsed[%.0f]", tdiff(¤t, &(info->elapsed[i]))); strcat(statbuf, buf); From f298b9951a54f5fcf6c48c1fc73004dfcce06cca Mon Sep 17 00:00:00 2001 From: Wangxc Date: Thu, 16 Aug 2018 18:10:40 +0800 Subject: [PATCH 073/113] Rename avalon8-otp-asic to avalon8-cinfo-asic --- cgminer.c | 4 ++-- driver-avalon8.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index 36c1fe0ab3..804fe0cf36 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1585,9 +1585,9 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--avalon8-spdhigh", set_int_0_to_3, opt_show_intval, &opt_avalon8_spdhigh, "Set Avalon8 spdhigh, range 0-3."), - OPT_WITH_CBARG("--avalon8-asic-otp", + OPT_WITH_CBARG("--avalon8-cinfo-asic", set_avalon8_asic_otp, NULL, &opt_set_avalon8_asic_otp, - "Set Avalon8 asic index for reading otp info, range:[0, 25], step: 1"), + "Set Avalon8 cinfo asic index, range:[0, 25], step: 1"), #endif #ifdef USE_AVALON_MINER OPT_WITH_CBARG("--avalonm-voltage", diff --git a/driver-avalon8.c b/driver-avalon8.c index 034c408ec3..546bc2d784 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -378,10 +378,10 @@ char *set_avalon8_asic_otp(char *arg) ret = sscanf(arg, "%d", &val); if (ret < 1) - return "No value passed to avalon8-asic-otp"; + return "No value passed to avalon8-cinfo-asic"; if (val < 0 || val > (AVA8_DEFAULT_ASIC_MAX - 1)) - return "Invalid value passed to avalon8-asic-otp"; + return "Invalid value passed to avalon8-cinfo-asic"; opt_avalon8_asic_otp = val; From 57256f7cd4b98357c085c23b3140fd66457f940f Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Fri, 17 Aug 2018 13:29:07 +0800 Subject: [PATCH 074/113] Update CINFO display --- driver-avalon8.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 546bc2d784..59825f403e 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -2264,21 +2264,6 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) info->mm_dna[i][7]); strcat(statbuf, buf); - if (opt_debug) { - for (k = 0; k < AVA8_DEFAULT_MINER_CNT; k++) { - sprintf(buf, " CINFO%d%d[", k, - info->otp_info[i][k][AVA8_OTP_INDEX_ASIC_NUM]); - strcat(statbuf, buf); - - for (m = 0; m < 23; m++) { - sprintf(buf, "%02x", info->otp_info[i][k][m]); - strcat(statbuf, buf); - } - - sprintf(buf, "]"); - strcat(statbuf, buf); - } - } sprintf(buf, " Elapsed[%.0f]", tdiff(¤t, &(info->elapsed[i]))); strcat(statbuf, buf); @@ -2493,6 +2478,19 @@ static struct api_data *avalon8_api_stats(struct cgpu_info *avalon8) } statbuf[strlen(statbuf) - 1] = ']'; } + + for (k = 0; k < info->miner_count[i]; k++) { + sprintf(buf, " CINFO%02d[", k); + strcat(statbuf, buf); + + for (m = 0; m < 23; m++) { + sprintf(buf, "%02x", info->otp_info[i][k][m]); + strcat(statbuf, buf); + } + + sprintf(buf, "]"); + strcat(statbuf, buf); + } } else { for (j = 0; j < info->miner_count[i]; j++) { sprintf(buf, " PVT_T%d[", j); From d8b2206aa2ac12735d63f0e52504f6dfc5dc56ec Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Fri, 17 Aug 2018 13:47:42 +0800 Subject: [PATCH 075/113] Minor fix comment indentation --- driver-avalon8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index 59825f403e..3a8218313e 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -718,7 +718,7 @@ static int decode_pkg(struct cgpu_info *avalon8, struct avalon8_ret *ar, int mod break; } - /* get the data behind AVA8_OTP_INDEX_READ_STEP for later displaying use*/ + /* get the data behind AVA8_OTP_INDEX_READ_STEP for later displaying use */ memcpy(info->otp_info[modular_id][miner_id] + AVA8_OTP_INDEX_READ_STEP, ar->data + AVA8_OTP_INDEX_READ_STEP, 4); break; From db147ca9152f220a130cfd6b0bc7b7db9c9e1b8b Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Thu, 16 Aug 2018 21:18:56 -0600 Subject: [PATCH 076/113] Merge s9 soc support --- Makefile.am | 12 +- api-btm.c | 5614 ++++++++++++++++++++ bitmain-board-test.c | 2310 ++++++++ bitmain-board-test.h | 242 + ccan/opt/helpers.c | 6 + ccan/opt/opt.h | 2 + cgminer.c | 253 + configure.ac | 63 +- driver-btm-soc.c | 11793 +++++++++++++++++++++++++++++++++++++++++ driver-btm-soc.h | 918 ++++ miner.h | 27 +- sha2-soc.c | 310 ++ sha2-soc.h | 95 + util.c | 35 + util.h | 5 + 15 files changed, 21678 insertions(+), 7 deletions(-) create mode 100644 api-btm.c create mode 100644 bitmain-board-test.c create mode 100644 bitmain-board-test.h create mode 100644 driver-btm-soc.c create mode 100644 driver-btm-soc.h create mode 100644 sha2-soc.c create mode 100644 sha2-soc.h diff --git a/Makefile.am b/Makefile.am index 25d35263c9..a114b2c040 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,7 +29,7 @@ cgminer_CPPFLAGS = $(PTHREAD_FLAGS) -fno-strict-aliasing $(JANSSON_CPPFLAGS) $(U bin_PROGRAMS = cgminer cgminer_LDFLAGS = $(PTHREAD_FLAGS) -cgminer_LDADD = $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \ +cgminer_LDADD = $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @LIBZ_LIBS@ @PTHREAD_LIBS@ \ @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \ @LIBUSB_LIBS@ @MM_LIBS@ @RT_LIBS@ @LIBSYSTEMD_LIBS@ \ @MATH_LIBS@ lib/libgnu.a ccan/libccan.a @@ -45,7 +45,7 @@ cgminer_SOURCES := cgminer.c cgminer_SOURCES += elist.h miner.h compat.h bench_block.h \ util.c util.h uthash.h logging.h \ - sha2.c sha2.h api.c + sha2.c sha2.h cgminer_SOURCES += logging.c @@ -112,6 +112,14 @@ cgminer_SOURCES += bf16-uartdevice.c bf16-uartdevice.h cgminer_SOURCES += driver-bitfury16.c driver-bitfury16.h endif +if HAS_BITMAIN_SOC +cgminer_SOURCES += driver-btm-soc.c driver-btm-soc.h +cgminer_SOURCES += bitmain-board-test.c bitmain-board-test.h +cgminer_SOURCES += sha2-soc.c sha2-soc.h +cgminer_SOURCES += api-btm.c +else +cgminer_SOURCES += api.c +endif if HAS_BITMINE_A1 cgminer_SOURCES += driver-SPI-bitmine-A1.c diff --git a/api-btm.c b/api-btm.c new file mode 100644 index 0000000000..ca191aa3a5 --- /dev/null +++ b/api-btm.c @@ -0,0 +1,5614 @@ +/* + * Copyright 2011-2014 Andrew Smith + * Copyright 2011-2014 Con Kolivas + * + * 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. + */ +#define _MEMORY_DEBUG_MASTER 1 + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compat.h" +#include "miner.h" +#include "util.h" +#include "klist.h" + +#if defined(USE_BFLSC) || defined(USE_AVALON) || defined(USE_AVALON2) || defined(USE_AVALON4) || \ + defined(USE_HASHFAST) || defined(USE_BITFURY) || defined(USE_BITFURY16) || defined(USE_BLOCKERUPTER) || defined(USE_KLONDIKE) || \ + defined(USE_KNC) || defined(USE_BAB) || defined(USE_DRILLBIT) || \ + defined(USE_MINION) || defined(USE_COINTERRA) || defined(USE_BITMINE_A1) || \ + defined(USE_ANT_S1) || defined(USE_ANT_S2) || defined(USE_ANT_S3) || defined(USE_SP10) || \ + defined(USE_SP30) || defined(USE_ICARUS) || defined(USE_HASHRATIO) || defined(USE_AVALON_MINER) || \ + defined(USE_AVALON7) || defined(USE_BITMAIN_SOC) +#define HAVE_AN_ASIC 1 +#endif + +#if defined(USE_BITFORCE) || defined(USE_MODMINER) +#define HAVE_AN_FPGA 1 +#endif + +// BUFSIZ varies on Windows and Linux +#define TMPBUFSIZ 8192 + +// Number of requests to queue - normally would be small +// However lots of PGA's may mean more +#define QUEUE 100 + +#if defined WIN32 +static char WSAbuf[1024]; + +struct WSAERRORS +{ + int id; + char *code; +} WSAErrors[] = +{ + { 0, "No error" }, + { WSAEINTR, "Interrupted system call" }, + { WSAEBADF, "Bad file number" }, + { WSAEACCES, "Permission denied" }, + { WSAEFAULT, "Bad address" }, + { WSAEINVAL, "Invalid argument" }, + { WSAEMFILE, "Too many open sockets" }, + { WSAEWOULDBLOCK, "Operation would block" }, + { WSAEINPROGRESS, "Operation now in progress" }, + { WSAEALREADY, "Operation already in progress" }, + { WSAENOTSOCK, "Socket operation on non-socket" }, + { WSAEDESTADDRREQ, "Destination address required" }, + { WSAEMSGSIZE, "Message too long" }, + { WSAEPROTOTYPE, "Protocol wrong type for socket" }, + { WSAENOPROTOOPT, "Bad protocol option" }, + { WSAEPROTONOSUPPORT, "Protocol not supported" }, + { WSAESOCKTNOSUPPORT, "Socket type not supported" }, + { WSAEOPNOTSUPP, "Operation not supported on socket" }, + { WSAEPFNOSUPPORT, "Protocol family not supported" }, + { WSAEAFNOSUPPORT, "Address family not supported" }, + { WSAEADDRINUSE, "Address already in use" }, + { WSAEADDRNOTAVAIL, "Can't assign requested address" }, + { WSAENETDOWN, "Network is down" }, + { WSAENETUNREACH, "Network is unreachable" }, + { WSAENETRESET, "Net connection reset" }, + { WSAECONNABORTED, "Software caused connection abort" }, + { WSAECONNRESET, "Connection reset by peer" }, + { WSAENOBUFS, "No buffer space available" }, + { WSAEISCONN, "Socket is already connected" }, + { WSAENOTCONN, "Socket is not connected" }, + { WSAESHUTDOWN, "Can't send after socket shutdown" }, + { WSAETOOMANYREFS, "Too many references, can't splice" }, + { WSAETIMEDOUT, "Connection timed out" }, + { WSAECONNREFUSED, "Connection refused" }, + { WSAELOOP, "Too many levels of symbolic links" }, + { WSAENAMETOOLONG, "File name too long" }, + { WSAEHOSTDOWN, "Host is down" }, + { WSAEHOSTUNREACH, "No route to host" }, + { WSAENOTEMPTY, "Directory not empty" }, + { WSAEPROCLIM, "Too many processes" }, + { WSAEUSERS, "Too many users" }, + { WSAEDQUOT, "Disc quota exceeded" }, + { WSAESTALE, "Stale NFS file handle" }, + { WSAEREMOTE, "Too many levels of remote in path" }, + { WSASYSNOTREADY, "Network system is unavailable" }, + { WSAVERNOTSUPPORTED, "Winsock version out of range" }, + { WSANOTINITIALISED, "WSAStartup not yet called" }, + { WSAEDISCON, "Graceful shutdown in progress" }, + { WSAHOST_NOT_FOUND, "Host not found" }, + { WSANO_DATA, "No host data of that type was found" }, + { -1, "Unknown error code" } +}; + +char *WSAErrorMsg(void) +{ + int i; + int id = WSAGetLastError(); + + /* Assume none of them are actually -1 */ + for (i = 0; WSAErrors[i].id != -1; i++) + if (WSAErrors[i].id == id) + break; + + sprintf(WSAbuf, "Socket Error: (%d) %s", id, WSAErrors[i].code); + + return &(WSAbuf[0]); +} +#endif + +#if defined(__APPLE__) || defined(__FreeBSD__) +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif + +static const char *UNAVAILABLE = " - API will not be available"; +static const char *MUNAVAILABLE = " - API multicast listener will not be available"; + +static const char *BLANK = ""; +static const char *COMMA = ","; +#define COMSTR "," +static const char SEPARATOR = '|'; +#define SEPSTR "|" +#define CMDJOIN '+' +#define JOIN_CMD "CMD=" +#define BETWEEN_JOIN SEPSTR + +static const char *APIVERSION = "3.1"; +static const char *DEAD = "Dead"; +static const char *SICK = "Sick"; +static const char *NOSTART = "NoStart"; +static const char *INIT = "Initialising"; +static const char *DISABLED = "Disabled"; +static const char *ALIVE = "Alive"; +static const char *REJECTING = "Rejecting"; +static const char *UNKNOWN = "Unknown"; + +static __maybe_unused const char *NONE = "None"; + +static const char *YES = "Y"; +static const char *NO = "N"; +static const char *NULLSTR = "(null)"; + +static const char *TRUESTR = "true"; +static const char *FALSESTR = "false"; + +static const char *SHA256STR = "sha256"; + +static const char *DEVICECODE = "" +#ifdef USE_ANT_S1 + "ANT " +#endif +#ifdef USE_ANT_S2 + "AS2 " +#endif +#ifdef USE_ANT_S3 + "AS3 " +#endif +#ifdef USE_AVALON + "AVA " +#endif +#ifdef USE_BAB + "BaB " +#endif +#ifdef USE_BFLSC + "BAS " +#endif +#ifdef USE_BITFORCE + "BFL " +#endif +#ifdef USE_BITFURY + "BFU " +#endif +#ifdef USE_BLOCKERUPTER + "BET " +#endif +#ifdef USE_DRILLBIT + "DRB " +#endif +#ifdef USE_HASHFAST + "HFA " +#endif +#ifdef USE_HASHRATIO + "HRO " +#endif +#ifdef USE_BITMINE_A1 + "BA1 " +#endif +#ifdef USE_ICARUS + "ICA " +#endif +#ifdef USE_KNC + "KnC " +#endif +#ifdef USE_MINION + "MBA " +#endif +#ifdef USE_MODMINER + "MMQ " +#endif +#ifdef USE_COINTERRA + "CTA " +#endif +#ifdef USE_SP10 + "SPN " +#endif +#ifdef USE_SP30 + "S30 " +#endif + + + ""; + +static const char *OSINFO = +#if defined(__linux) + "Linux"; +#else +#if defined(__APPLE__) + "Apple"; +#else +#if defined (WIN32) + "Windows"; +#else +#if defined(unix) + "Unix"; +#else + "Unknown"; +#endif +#endif +#endif +#endif + +#define _DEVS "DEVS" +#define _POOLS "POOLS" +#define _SUMMARY "SUMMARY" +#define _NONCENUM "NONCENUM" +#define _STATUS "STATUS" +#define _VERSION "VERSION" +#define _MINECONFIG "CONFIG" + +#ifdef HAVE_AN_FPGA +#define _PGA "PGA" +#endif + +#ifdef HAVE_AN_ASIC +#define _ASC "ASC" +#endif + +#define _PGAS "PGAS" +#define _ASCS "ASCS" +#define _NOTIFY "NOTIFY" +#define _DEVDETAILS "DEVDETAILS" +#define _BYE "BYE" +#define _RESTART "RESTART" +#define _MINESTATS "STATS" +#define _CHECK "CHECK" +#define _MINECOIN "COIN" +#define _DEBUGSET "DEBUG" +#define _SETCONFIG "SETCONFIG" +#define _USBSTATS "USBSTATS" +#define _LCD "LCD" + +static const char ISJSON = '{'; +#define JSON0 "{" +#define JSON1 "\"" +#define JSON2 "\":[" +#define JSON3 "]" +#define JSON4 ",\"id\":1" +// If anyone cares, id=0 for truncated output +#define JSON4_TRUNCATED ",\"id\":0" +#define JSON5 "}" +#define JSON6 "\":" + +#define JSON_START JSON0 +#define JSON_DEVS JSON1 _DEVS JSON2 +#define JSON_POOLS JSON1 _POOLS JSON2 +#define JSON_SUMMARY JSON1 _SUMMARY JSON2 +#define JSON_NONCENUM JSON1 _NONCENUM JSON2 + +#define JSON_STATUS JSON1 _STATUS JSON2 +#define JSON_VERSION JSON1 _VERSION JSON2 +#define JSON_MINECONFIG JSON1 _MINECONFIG JSON2 +#define JSON_ACTION JSON0 JSON1 _STATUS JSON6 + +#ifdef HAVE_AN_FPGA +#define JSON_PGA JSON1 _PGA JSON2 +#endif + +#ifdef HAVE_AN_ASIC +#define JSON_ASC JSON1 _ASC JSON2 +#endif + +#define JSON_PGAS JSON1 _PGAS JSON2 +#define JSON_ASCS JSON1 _ASCS JSON2 +#define JSON_NOTIFY JSON1 _NOTIFY JSON2 +#define JSON_DEVDETAILS JSON1 _DEVDETAILS JSON2 +#define JSON_BYE JSON1 _BYE JSON1 +#define JSON_RESTART JSON1 _RESTART JSON1 +#define JSON_CLOSE JSON3 +#define JSON_MINESTATS JSON1 _MINESTATS JSON2 +#define JSON_CHECK JSON1 _CHECK JSON2 +#define JSON_MINECOIN JSON1 _MINECOIN JSON2 +#define JSON_DEBUGSET JSON1 _DEBUGSET JSON2 +#define JSON_SETCONFIG JSON1 _SETCONFIG JSON2 +#define JSON_USBSTATS JSON1 _USBSTATS JSON2 +#define JSON_LCD JSON1 _LCD JSON2 +#define JSON_END JSON4 JSON5 +#define JSON_END_TRUNCATED JSON4_TRUNCATED JSON5 +#define JSON_BETWEEN_JOIN "," + +static const char *JSON_COMMAND = "command"; +static const char *JSON_PARAMETER = "parameter"; + +#define MSG_POOL 7 +#define MSG_NOPOOL 8 +#define MSG_DEVS 9 +#define MSG_NODEVS 10 +#define MSG_SUMM 11 +#define MSG_INVCMD 14 +#define MSG_MISID 15 +#define MSG_NONCE_NUM 16 + +#define MSG_VERSION 22 +#define MSG_INVJSON 23 +#define MSG_MISCMD 24 +#define MSG_MISPID 25 +#define MSG_INVPID 26 +#define MSG_SWITCHP 27 +#define MSG_MISVAL 28 +#define MSG_NOADL 29 +#define MSG_INVINT 31 +#define MSG_MINECONFIG 33 +#define MSG_MISFN 42 +#define MSG_BADFN 43 +#define MSG_SAVED 44 +#define MSG_ACCDENY 45 +#define MSG_ACCOK 46 +#define MSG_ENAPOOL 47 +#define MSG_DISPOOL 48 +#define MSG_ALRENAP 49 +#define MSG_ALRDISP 50 +#define MSG_DISLASTP 51 +#define MSG_MISPDP 52 +#define MSG_INVPDP 53 +#define MSG_TOOMANYP 54 +#define MSG_ADDPOOL 55 + +#ifdef HAVE_AN_FPGA +#define MSG_PGANON 56 +#define MSG_PGADEV 57 +#define MSG_INVPGA 58 +#endif + +#define MSG_NUMPGA 59 +#define MSG_NOTIFY 60 + +#ifdef HAVE_AN_FPGA +#define MSG_PGALRENA 61 +#define MSG_PGALRDIS 62 +#define MSG_PGAENA 63 +#define MSG_PGADIS 64 +#define MSG_PGAUNW 65 +#endif + +#define MSG_REMLASTP 66 +#define MSG_ACTPOOL 67 +#define MSG_REMPOOL 68 +#define MSG_DEVDETAILS 69 +#define MSG_MINESTATS 70 +#define MSG_MISCHK 71 +#define MSG_CHECK 72 +#define MSG_POOLPRIO 73 +#define MSG_DUPPID 74 +#define MSG_MISBOOL 75 +#define MSG_INVBOOL 76 +#define MSG_FOO 77 +#define MSG_MINECOIN 78 +#define MSG_DEBUGSET 79 +#define MSG_PGAIDENT 80 +#define MSG_PGANOID 81 +#define MSG_SETCONFIG 82 +#define MSG_UNKCON 83 +#define MSG_INVNUM 84 +#define MSG_CONPAR 85 +#define MSG_CONVAL 86 +#define MSG_USBSTA 87 +#define MSG_NOUSTA 88 + +#ifdef HAVE_AN_FPGA +#define MSG_MISPGAOPT 89 +#define MSG_PGANOSET 90 +#define MSG_PGAHELP 91 +#define MSG_PGASETOK 92 +#define MSG_PGASETERR 93 +#endif + +#define MSG_ZERMIS 94 +#define MSG_ZERINV 95 +#define MSG_ZERSUM 96 +#define MSG_ZERNOSUM 97 +#define MSG_PGAUSBNODEV 98 +#define MSG_INVHPLG 99 +#define MSG_HOTPLUG 100 +#define MSG_DISHPLG 101 +#define MSG_NOHPLG 102 +#define MSG_MISHPLG 103 + +#define MSG_NUMASC 104 +#ifdef HAVE_AN_ASIC +#define MSG_ASCNON 105 +#define MSG_ASCDEV 106 +#define MSG_INVASC 107 +#define MSG_ASCLRENA 108 +#define MSG_ASCLRDIS 109 +#define MSG_ASCENA 110 +#define MSG_ASCDIS 111 +#define MSG_ASCUNW 112 +#define MSG_ASCIDENT 113 +#define MSG_ASCNOID 114 +#endif +#define MSG_ASCUSBNODEV 115 + +#ifdef HAVE_AN_ASIC +#define MSG_MISASCOPT 116 +#define MSG_ASCNOSET 117 +#define MSG_ASCHELP 118 +#define MSG_ASCSETOK 119 +#define MSG_ASCSETERR 120 +#endif + +#define MSG_INVNEG 121 +#define MSG_SETQUOTA 122 +#define MSG_LOCKOK 123 +#define MSG_LOCKDIS 124 +#define MSG_LCD 125 + +#define MSG_DEPRECATED 126 +enum code_severity +{ + SEVERITY_ERR, + SEVERITY_WARN, + SEVERITY_INFO, + SEVERITY_SUCC, + SEVERITY_FAIL +}; + +enum code_parameters +{ + PARAM_PGA, + PARAM_ASC, + PARAM_PID, + PARAM_PGAMAX, + PARAM_ASCMAX, + PARAM_PMAX, + PARAM_POOLMAX, + +// Single generic case: have the code resolve it - see below + PARAM_DMAX, + + PARAM_CMD, + PARAM_POOL, + PARAM_STR, + PARAM_BOTH, + PARAM_BOOL, + PARAM_SET, + PARAM_INT, + PARAM_NONE +}; + +struct CODES +{ + const enum code_severity severity; + const int code; + const enum code_parameters params; + const char *description; +} codes[] = +{ + { SEVERITY_SUCC, MSG_POOL, PARAM_PMAX, "%d Pool(s)" }, + { SEVERITY_ERR, MSG_NOPOOL, PARAM_NONE, "No pools" }, + + { + SEVERITY_SUCC, MSG_DEVS, PARAM_DMAX, +#ifdef HAVE_AN_ASIC + "%d ASC(s)" +#endif +#if defined(HAVE_AN_ASIC) && defined(HAVE_AN_FPGA) + " - " +#endif +#ifdef HAVE_AN_FPGA + "%d PGA(s)" +#endif + }, + + { + SEVERITY_ERR, MSG_NODEVS, PARAM_NONE, "No " +#ifdef HAVE_AN_ASIC + "ASCs" +#endif +#if defined(HAVE_AN_ASIC) && defined(HAVE_AN_FPGA) + "/" +#endif +#ifdef HAVE_AN_FPGA + "PGAs" +#endif + }, + + { SEVERITY_SUCC, MSG_SUMM, PARAM_NONE, "Summary" }, + { SEVERITY_SUCC, MSG_NONCE_NUM,PARAM_NONE,"Nonce num" }, + { SEVERITY_ERR, MSG_INVCMD, PARAM_NONE, "Invalid command" }, + { SEVERITY_ERR, MSG_MISID, PARAM_NONE, "Missing device id parameter" }, +#ifdef HAVE_AN_FPGA + { SEVERITY_ERR, MSG_PGANON, PARAM_NONE, "No PGAs" }, + { SEVERITY_SUCC, MSG_PGADEV, PARAM_PGA, "PGA%d" }, + { SEVERITY_ERR, MSG_INVPGA, PARAM_PGAMAX, "Invalid PGA id %d - range is 0 - %d" }, + { SEVERITY_INFO, MSG_PGALRENA,PARAM_PGA, "PGA %d already enabled" }, + { SEVERITY_INFO, MSG_PGALRDIS,PARAM_PGA, "PGA %d already disabled" }, + { SEVERITY_INFO, MSG_PGAENA, PARAM_PGA, "PGA %d sent enable message" }, + { SEVERITY_INFO, MSG_PGADIS, PARAM_PGA, "PGA %d set disable flag" }, + { SEVERITY_ERR, MSG_PGAUNW, PARAM_PGA, "PGA %d is not flagged WELL, cannot enable" }, +#endif + { SEVERITY_SUCC, MSG_NUMPGA, PARAM_NONE, "PGA count" }, + { SEVERITY_SUCC, MSG_NUMASC, PARAM_NONE, "ASC count" }, + { SEVERITY_SUCC, MSG_VERSION, PARAM_NONE, "CGMiner versions" }, + { SEVERITY_ERR, MSG_INVJSON, PARAM_NONE, "Invalid JSON" }, + { SEVERITY_ERR, MSG_MISCMD, PARAM_CMD, "Missing JSON '%s'" }, + { SEVERITY_ERR, MSG_MISPID, PARAM_NONE, "Missing pool id parameter" }, + { SEVERITY_ERR, MSG_INVPID, PARAM_POOLMAX, "Invalid pool id %d - range is 0 - %d" }, + { SEVERITY_SUCC, MSG_SWITCHP, PARAM_POOL, "Switching to pool %d:'%s'" }, + { SEVERITY_SUCC, MSG_MINECONFIG,PARAM_NONE, "CGMiner config" }, + { SEVERITY_ERR, MSG_MISFN, PARAM_NONE, "Missing save filename parameter" }, + { SEVERITY_ERR, MSG_BADFN, PARAM_STR, "Can't open or create save file '%s'" }, + { SEVERITY_SUCC, MSG_SAVED, PARAM_STR, "Configuration saved to file '%s'" }, + { SEVERITY_ERR, MSG_ACCDENY, PARAM_STR, "Access denied to '%s' command" }, + { SEVERITY_SUCC, MSG_ACCOK, PARAM_NONE, "Privileged access OK" }, + { SEVERITY_SUCC, MSG_ENAPOOL, PARAM_POOL, "Enabling pool %d:'%s'" }, + { SEVERITY_SUCC, MSG_POOLPRIO,PARAM_NONE, "Changed pool priorities" }, + { SEVERITY_ERR, MSG_DUPPID, PARAM_PID, "Duplicate pool specified %d" }, + { SEVERITY_SUCC, MSG_DISPOOL, PARAM_POOL, "Disabling pool %d:'%s'" }, + { SEVERITY_INFO, MSG_ALRENAP, PARAM_POOL, "Pool %d:'%s' already enabled" }, + { SEVERITY_INFO, MSG_ALRDISP, PARAM_POOL, "Pool %d:'%s' already disabled" }, + { SEVERITY_ERR, MSG_DISLASTP,PARAM_POOL, "Cannot disable last active pool %d:'%s'" }, + { SEVERITY_ERR, MSG_MISPDP, PARAM_NONE, "Missing addpool details" }, + { SEVERITY_ERR, MSG_INVPDP, PARAM_STR, "Invalid addpool details '%s'" }, + { SEVERITY_ERR, MSG_TOOMANYP,PARAM_NONE, "Reached maximum number of pools (%d)" }, + { SEVERITY_SUCC, MSG_ADDPOOL, PARAM_POOL, "Added pool %d: '%s'" }, + { SEVERITY_ERR, MSG_REMLASTP,PARAM_POOL, "Cannot remove last pool %d:'%s'" }, + { SEVERITY_ERR, MSG_ACTPOOL, PARAM_POOL, "Cannot remove active pool %d:'%s'" }, + { SEVERITY_SUCC, MSG_REMPOOL, PARAM_BOTH, "Removed pool %d:'%s'" }, + { SEVERITY_SUCC, MSG_NOTIFY, PARAM_NONE, "Notify" }, + { SEVERITY_SUCC, MSG_DEVDETAILS,PARAM_NONE, "Device Details" }, + { SEVERITY_SUCC, MSG_MINESTATS,PARAM_NONE, "CGMiner stats" }, + { SEVERITY_ERR, MSG_MISCHK, PARAM_NONE, "Missing check cmd" }, + { SEVERITY_SUCC, MSG_CHECK, PARAM_NONE, "Check command" }, + { SEVERITY_ERR, MSG_MISBOOL, PARAM_NONE, "Missing parameter: true/false" }, + { SEVERITY_ERR, MSG_INVBOOL, PARAM_NONE, "Invalid parameter should be true or false" }, + { SEVERITY_SUCC, MSG_FOO, PARAM_BOOL, "Failover-Only set to %s" }, + { SEVERITY_SUCC, MSG_MINECOIN,PARAM_NONE, "CGMiner coin" }, + { SEVERITY_SUCC, MSG_DEBUGSET,PARAM_NONE, "Debug settings" }, +#ifdef HAVE_AN_FPGA + { SEVERITY_SUCC, MSG_PGAIDENT,PARAM_PGA, "Identify command sent to PGA%d" }, + { SEVERITY_WARN, MSG_PGANOID, PARAM_PGA, "PGA%d does not support identify" }, +#endif + { SEVERITY_SUCC, MSG_SETCONFIG,PARAM_SET, "Set config '%s' to %d" }, + { SEVERITY_ERR, MSG_UNKCON, PARAM_STR, "Unknown config '%s'" }, + { SEVERITY_ERR, MSG_DEPRECATED, PARAM_STR, "Deprecated config option '%s'" }, + { SEVERITY_ERR, MSG_INVNUM, PARAM_BOTH, "Invalid number (%d) for '%s' range is 0-9999" }, + { SEVERITY_ERR, MSG_INVNEG, PARAM_BOTH, "Invalid negative number (%d) for '%s'" }, + { SEVERITY_SUCC, MSG_SETQUOTA,PARAM_SET, "Set pool '%s' to quota %d'" }, + { SEVERITY_ERR, MSG_CONPAR, PARAM_NONE, "Missing config parameters 'name,N'" }, + { SEVERITY_ERR, MSG_CONVAL, PARAM_STR, "Missing config value N for '%s,N'" }, + { SEVERITY_SUCC, MSG_USBSTA, PARAM_NONE, "USB Statistics" }, + { SEVERITY_INFO, MSG_NOUSTA, PARAM_NONE, "No USB Statistics" }, +#ifdef HAVE_AN_FPGA + { SEVERITY_ERR, MSG_MISPGAOPT, PARAM_NONE, "Missing option after PGA number" }, + { SEVERITY_WARN, MSG_PGANOSET, PARAM_PGA, "PGA %d does not support pgaset" }, + { SEVERITY_INFO, MSG_PGAHELP, PARAM_BOTH, "PGA %d set help: %s" }, + { SEVERITY_SUCC, MSG_PGASETOK, PARAM_BOTH, "PGA %d set OK" }, + { SEVERITY_ERR, MSG_PGASETERR, PARAM_BOTH, "PGA %d set failed: %s" }, +#endif + { SEVERITY_ERR, MSG_ZERMIS, PARAM_NONE, "Missing zero parameters" }, + { SEVERITY_ERR, MSG_ZERINV, PARAM_STR, "Invalid zero parameter '%s'" }, + { SEVERITY_SUCC, MSG_ZERSUM, PARAM_STR, "Zeroed %s stats with summary" }, + { SEVERITY_SUCC, MSG_ZERNOSUM, PARAM_STR, "Zeroed %s stats without summary" }, +#ifdef USE_USBUTILS + { SEVERITY_ERR, MSG_PGAUSBNODEV, PARAM_PGA, "PGA%d has no device" }, + { SEVERITY_ERR, MSG_ASCUSBNODEV, PARAM_PGA, "ASC%d has no device" }, +#endif + { SEVERITY_ERR, MSG_INVHPLG, PARAM_STR, "Invalid value for hotplug (%s) must be 0..9999" }, + { SEVERITY_SUCC, MSG_HOTPLUG, PARAM_INT, "Hotplug check set to %ds" }, + { SEVERITY_SUCC, MSG_DISHPLG, PARAM_NONE, "Hotplug disabled" }, + { SEVERITY_WARN, MSG_NOHPLG, PARAM_NONE, "Hotplug is not available" }, + { SEVERITY_ERR, MSG_MISHPLG, PARAM_NONE, "Missing hotplug parameter" }, +#ifdef HAVE_AN_ASIC + { SEVERITY_ERR, MSG_ASCNON, PARAM_NONE, "No ASCs" }, + { SEVERITY_SUCC, MSG_ASCDEV, PARAM_ASC, "ASC%d" }, + { SEVERITY_ERR, MSG_INVASC, PARAM_ASCMAX, "Invalid ASC id %d - range is 0 - %d" }, + { SEVERITY_INFO, MSG_ASCLRENA,PARAM_ASC, "ASC %d already enabled" }, + { SEVERITY_INFO, MSG_ASCLRDIS,PARAM_ASC, "ASC %d already disabled" }, + { SEVERITY_INFO, MSG_ASCENA, PARAM_ASC, "ASC %d sent enable message" }, + { SEVERITY_INFO, MSG_ASCDIS, PARAM_ASC, "ASC %d set disable flag" }, + { SEVERITY_ERR, MSG_ASCUNW, PARAM_ASC, "ASC %d is not flagged WELL, cannot enable" }, + { SEVERITY_SUCC, MSG_ASCIDENT,PARAM_ASC, "Identify command sent to ASC%d" }, + { SEVERITY_WARN, MSG_ASCNOID, PARAM_ASC, "ASC%d does not support identify" }, + { SEVERITY_ERR, MSG_MISASCOPT, PARAM_NONE, "Missing option after ASC number" }, + { SEVERITY_WARN, MSG_ASCNOSET, PARAM_ASC, "ASC %d does not support ascset" }, + { SEVERITY_INFO, MSG_ASCHELP, PARAM_BOTH, "ASC %d set help: %s" }, + { SEVERITY_SUCC, MSG_ASCSETOK, PARAM_BOTH, "ASC %d set OK" }, + { SEVERITY_ERR, MSG_ASCSETERR, PARAM_BOTH, "ASC %d set failed: %s" }, +#endif + { SEVERITY_SUCC, MSG_LCD, PARAM_NONE, "LCD" }, + { SEVERITY_SUCC, MSG_LOCKOK, PARAM_NONE, "Lock stats created" }, + { SEVERITY_WARN, MSG_LOCKDIS, PARAM_NONE, "Lock stats not enabled" }, + { SEVERITY_FAIL, 0, 0, NULL } +}; + +static const char *localaddr = "127.0.0.1"; + +static int my_thr_id = 0; +static bool bye; + +// Used to control quit restart access to shutdown variables +static pthread_mutex_t quit_restart_lock; + +static bool do_a_quit; +static bool do_a_restart; + +static time_t when = 0; // when the request occurred + +struct IPACCESS +{ + struct in6_addr ip; + struct in6_addr mask; + char group; +}; + +#define GROUP(g) (toupper(g)) +#define PRIVGROUP GROUP('W') +#define NOPRIVGROUP GROUP('R') +#define ISPRIVGROUP(g) (GROUP(g) == PRIVGROUP) +#define GROUPOFFSET(g) (GROUP(g) - GROUP('A')) +#define VALIDGROUP(g) (GROUP(g) >= GROUP('A') && GROUP(g) <= GROUP('Z')) +#define COMMANDS(g) (apigroups[GROUPOFFSET(g)].commands) +#define DEFINEDGROUP(g) (ISPRIVGROUP(g) || COMMANDS(g) != NULL) + +struct APIGROUPS +{ + // This becomes a string like: "|cmd1|cmd2|cmd3|" so it's quick to search + char *commands; +} apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs) + +static struct IPACCESS *ipaccess = NULL; +static int ips = 0; + +struct io_data +{ + size_t siz; + char *ptr; + char *cur; + bool sock; + bool close; +}; + +struct io_list +{ + struct io_data *io_data; + struct io_list *prev; + struct io_list *next; +}; + +static struct io_list *io_head = NULL; + +#define SOCKBUFALLOCSIZ 65536 + +#define io_new(init) _io_new(init, false) +#define sock_io_new() _io_new(SOCKBUFALLOCSIZ, true) + +#define ALLOC_SBITEMS 2 +#define LIMIT_SBITEMS 0 + +typedef struct sbitem +{ + char *buf; + size_t siz; + size_t tot; +} SBITEM; + +// Size to grow tot if exceeded +#define SBEXTEND 4096 + +#define DATASB(_item) ((SBITEM *)(_item->data)) + +static K_LIST *strbufs; + +static void io_reinit(struct io_data *io_data) +{ + io_data->cur = io_data->ptr; + *(io_data->ptr) = '\0'; + io_data->close = false; +} + +static struct io_data *_io_new(size_t initial, bool socket_buf) +{ + struct io_data *io_data; + struct io_list *io_list; + + io_data = cgmalloc(sizeof(*io_data)); + io_data->ptr = cgmalloc(initial); + io_data->siz = initial; + io_data->sock = socket_buf; + io_reinit(io_data); + + io_list = cgmalloc(sizeof(*io_list)); + + io_list->io_data = io_data; + + if (io_head) + { + io_list->next = io_head; + io_list->prev = io_head->prev; + io_list->next->prev = io_list; + io_list->prev->next = io_list; + } + else + { + io_list->prev = io_list; + io_list->next = io_list; + io_head = io_list; + } + + return io_data; +} + +static bool io_add(struct io_data *io_data, char *buf) +{ + size_t len, dif, tot; + + len = strlen(buf); + dif = io_data->cur - io_data->ptr; + // send will always have enough space to add the JSON + tot = len + 1 + dif + sizeof(JSON_CLOSE) + sizeof(JSON_END); + + if (tot > io_data->siz) + { + size_t new = io_data->siz + (2 * SOCKBUFALLOCSIZ); + + if (new < tot) + new = (2 + (size_t)((float)tot / (float)SOCKBUFALLOCSIZ)) * SOCKBUFALLOCSIZ; + + io_data->ptr = cgrealloc(io_data->ptr, new); + io_data->cur = io_data->ptr + dif; + io_data->siz = new; + } + + memcpy(io_data->cur, buf, len + 1); + io_data->cur += len; + + return true; +} + +static bool io_put(struct io_data *io_data, char *buf) +{ + io_reinit(io_data); + return io_add(io_data, buf); +} + +static void io_close(struct io_data *io_data) +{ + io_data->close = true; +} + +static void io_free() +{ + struct io_list *io_list, *io_next; + + if (io_head) + { + io_list = io_head; + do + { + io_next = io_list->next; + + free(io_list->io_data->ptr); + free(io_list->io_data); + free(io_list); + + io_list = io_next; + } + while (io_list != io_head); + + io_head = NULL; + } +} + +// This is only called when expected to be needed (rarely) +// i.e. strings outside of the codes control (input from the user) +static char *escape_string(char *str, bool isjson) +{ + char *buf, *ptr; + int count; + + count = 0; + for (ptr = str; *ptr; ptr++) + { + switch (*ptr) + { + case ',': + case '|': + case '=': + if (!isjson) + count++; + break; + case '"': + if (isjson) + count++; + break; + case '\\': + count++; + break; + } + } + + if (count == 0) + return str; + + buf = cgmalloc(strlen(str) + count + 1); + + ptr = buf; + while (*str) + switch (*str) + { + case ',': + case '|': + case '=': + if (!isjson) + *(ptr++) = '\\'; + *(ptr++) = *(str++); + break; + case '"': + if (isjson) + *(ptr++) = '\\'; + *(ptr++) = *(str++); + break; + case '\\': + *(ptr++) = '\\'; + *(ptr++) = *(str++); + break; + default: + *(ptr++) = *(str++); + break; + } + + *ptr = '\0'; + + return buf; +} + +static struct api_data *api_add_extra(struct api_data *root, struct api_data *extra) +{ + struct api_data *tmp; + + if (root) + { + if (extra) + { + // extra tail + tmp = extra->prev; + + // extra prev = root tail + extra->prev = root->prev; + + // root tail next = extra + root->prev->next = extra; + + // extra tail next = root + tmp->next = root; + + // root prev = extra tail + root->prev = tmp; + } + } + else + root = extra; + + return root; +} + +static struct api_data *api_add_data_full(struct api_data *root, char *name, enum api_data_type type, void *data, bool copy_data) +{ + struct api_data *api_data; + + api_data = cgmalloc(sizeof(struct api_data)); + + api_data->name = strdup(name); + api_data->type = type; + + if (root == NULL) + { + root = api_data; + root->prev = root; + root->next = root; + } + else + { + api_data->prev = root->prev; + root->prev = api_data; + api_data->next = root; + api_data->prev->next = api_data; + } + + api_data->data_was_malloc = copy_data; + + // Avoid crashing on bad data + if (data == NULL) + { + api_data->type = type = API_CONST; + data = (void *)NULLSTR; + api_data->data_was_malloc = copy_data = false; + } + + if (!copy_data) + api_data->data = data; + else + switch(type) + { + case API_ESCAPE: + case API_STRING: + case API_CONST: + api_data->data = cgmalloc(strlen((char *)data) + 1); + strcpy((char*)(api_data->data), (char *)data); + break; + case API_UINT8: + /* Most OSs won't really alloc less than 4 */ + api_data->data = cgmalloc(4); + *(uint8_t *)api_data->data = *(uint8_t *)data; + break; + case API_INT16: + /* Most OSs won't really alloc less than 4 */ + api_data->data = cgmalloc(4); + *(int16_t *)api_data->data = *(int16_t *)data; + break; + case API_UINT16: + /* Most OSs won't really alloc less than 4 */ + api_data->data = cgmalloc(4); + *(uint16_t *)api_data->data = *(uint16_t *)data; + break; + case API_INT: + api_data->data = cgmalloc(sizeof(int)); + *((int *)(api_data->data)) = *((int *)data); + break; + case API_UINT: + api_data->data = cgmalloc(sizeof(unsigned int)); + *((unsigned int *)(api_data->data)) = *((unsigned int *)data); + break; + case API_UINT32: + api_data->data = cgmalloc(sizeof(uint32_t)); + *((uint32_t *)(api_data->data)) = *((uint32_t *)data); + break; + case API_HEX32: + api_data->data = cgmalloc(sizeof(uint32_t)); + *((uint32_t *)(api_data->data)) = *((uint32_t *)data); + break; + case API_UINT64: + api_data->data = cgmalloc(sizeof(uint64_t)); + *((uint64_t *)(api_data->data)) = *((uint64_t *)data); + break; + case API_INT64: + api_data->data = cgmalloc(sizeof(int64_t)); + *((int64_t *)(api_data->data)) = *((int64_t *)data); + break; + case API_DOUBLE: + case API_ELAPSED: + case API_MHS: + case API_MHTOTAL: + case API_UTILITY: + case API_FREQ: + case API_HS: + case API_DIFF: + case API_PERCENT: + api_data->data = cgmalloc(sizeof(double)); + *((double *)(api_data->data)) = *((double *)data); + break; + case API_BOOL: + api_data->data = cgmalloc(sizeof(bool)); + *((bool *)(api_data->data)) = *((bool *)data); + break; + case API_TIMEVAL: + api_data->data = cgmalloc(sizeof(struct timeval)); + memcpy(api_data->data, data, sizeof(struct timeval)); + break; + case API_TIME: + api_data->data = cgmalloc(sizeof(time_t)); + *(time_t *)(api_data->data) = *((time_t *)data); + break; + case API_VOLTS: + case API_TEMP: + case API_AVG: + api_data->data = cgmalloc(sizeof(float)); + *((float *)(api_data->data)) = *((float *)data); + break; + default: + applog(LOG_ERR, "API: unknown1 data type %d ignored", type); + api_data->type = API_STRING; + api_data->data_was_malloc = false; + api_data->data = (void *)UNKNOWN; + break; + } + + return root; +} + +struct api_data *api_add_escape(struct api_data *root, char *name, char *data, bool copy_data) +{ + return api_add_data_full(root, name, API_ESCAPE, (void *)data, copy_data); +} + +struct api_data *api_add_string(struct api_data *root, char *name, char *data, bool copy_data) +{ + return api_add_data_full(root, name, API_STRING, (void *)data, copy_data); +} + +struct api_data *api_add_const(struct api_data *root, char *name, const char *data, bool copy_data) +{ + return api_add_data_full(root, name, API_CONST, (void *)data, copy_data); +} + +struct api_data *api_add_uint8(struct api_data *root, char *name, uint8_t *data, bool copy_data) +{ + return api_add_data_full(root, name, API_UINT8, (void *)data, copy_data); +} + +struct api_data *api_add_int16(struct api_data *root, char *name, uint16_t *data, bool copy_data) +{ + return api_add_data_full(root, name, API_INT16, (void *)data, copy_data); +} + +struct api_data *api_add_uint16(struct api_data *root, char *name, uint16_t *data, bool copy_data) +{ + return api_add_data_full(root, name, API_UINT16, (void *)data, copy_data); +} + +struct api_data *api_add_int(struct api_data *root, char *name, int *data, bool copy_data) +{ + return api_add_data_full(root, name, API_INT, (void *)data, copy_data); +} + +struct api_data *api_add_uint(struct api_data *root, char *name, unsigned int *data, bool copy_data) +{ + return api_add_data_full(root, name, API_UINT, (void *)data, copy_data); +} + +struct api_data *api_add_uint32(struct api_data *root, char *name, uint32_t *data, bool copy_data) +{ + return api_add_data_full(root, name, API_UINT32, (void *)data, copy_data); +} + +struct api_data *api_add_hex32(struct api_data *root, char *name, uint32_t *data, bool copy_data) +{ + return api_add_data_full(root, name, API_HEX32, (void *)data, copy_data); +} + +struct api_data *api_add_uint64(struct api_data *root, char *name, uint64_t *data, bool copy_data) +{ + return api_add_data_full(root, name, API_UINT64, (void *)data, copy_data); +} + +struct api_data *api_add_int64(struct api_data *root, char *name, int64_t *data, bool copy_data) +{ + return api_add_data_full(root, name, API_INT64, (void *)data, copy_data); +} + +struct api_data *api_add_double(struct api_data *root, char *name, double *data, bool copy_data) +{ + return api_add_data_full(root, name, API_DOUBLE, (void *)data, copy_data); +} + +struct api_data *api_add_elapsed(struct api_data *root, char *name, double *data, bool copy_data) +{ + return api_add_data_full(root, name, API_ELAPSED, (void *)data, copy_data); +} + +struct api_data *api_add_bool(struct api_data *root, char *name, bool *data, bool copy_data) +{ + return api_add_data_full(root, name, API_BOOL, (void *)data, copy_data); +} + +struct api_data *api_add_timeval(struct api_data *root, char *name, struct timeval *data, bool copy_data) +{ + return api_add_data_full(root, name, API_TIMEVAL, (void *)data, copy_data); +} + +struct api_data *api_add_time(struct api_data *root, char *name, time_t *data, bool copy_data) +{ + return api_add_data_full(root, name, API_TIME, (void *)data, copy_data); +} + +struct api_data *api_add_mhs(struct api_data *root, char *name, double *data, bool copy_data) +{ + return api_add_data_full(root, name, API_MHS, (void *)data, copy_data); +} + +struct api_data *api_add_mhtotal(struct api_data *root, char *name, double *data, bool copy_data) +{ + return api_add_data_full(root, name, API_MHTOTAL, (void *)data, copy_data); +} + +struct api_data *api_add_temp(struct api_data *root, char *name, float *data, bool copy_data) +{ + return api_add_data_full(root, name, API_TEMP, (void *)data, copy_data); +} + +struct api_data *api_add_utility(struct api_data *root, char *name, double *data, bool copy_data) +{ + return api_add_data_full(root, name, API_UTILITY, (void *)data, copy_data); +} + +struct api_data *api_add_freq(struct api_data *root, char *name, double *data, bool copy_data) +{ + return api_add_data_full(root, name, API_FREQ, (void *)data, copy_data); +} + +struct api_data *api_add_volts(struct api_data *root, char *name, float *data, bool copy_data) +{ + return api_add_data_full(root, name, API_VOLTS, (void *)data, copy_data); +} + +struct api_data *api_add_hs(struct api_data *root, char *name, double *data, bool copy_data) +{ + return api_add_data_full(root, name, API_HS, (void *)data, copy_data); +} + +struct api_data *api_add_diff(struct api_data *root, char *name, double *data, bool copy_data) +{ + return api_add_data_full(root, name, API_DIFF, (void *)data, copy_data); +} + +struct api_data *api_add_percent(struct api_data *root, char *name, double *data, bool copy_data) +{ + return api_add_data_full(root, name, API_PERCENT, (void *)data, copy_data); +} + +struct api_data *api_add_avg(struct api_data *root, char *name, float *data, bool copy_data) +{ + return api_add_data_full(root, name, API_AVG, (void *)data, copy_data); +} + +static void add_item_buf(K_ITEM *item, const char *str) +{ + size_t old_siz, new_siz, siz, ext; + char *buf; + + buf = DATASB(item)->buf; + siz = (size_t)strlen(str); + + old_siz = DATASB(item)->siz; + new_siz = old_siz + siz + 1; // include '\0' + if (DATASB(item)->tot < new_siz) + { + ext = (siz + 1) + SBEXTEND - ((siz + 1) % SBEXTEND); + DATASB(item)->buf = buf = cgrealloc(DATASB(item)->buf, DATASB(item)->tot + ext); + DATASB(item)->tot += ext; + } + memcpy(buf + old_siz, str, siz + 1); + DATASB(item)->siz += siz; +} + +static struct api_data *print_data(struct io_data *io_data, struct api_data *root, bool isjson, bool precom) +{ + // N.B. strings don't use this buffer so 64 is enough (for now) + char buf[64]; + struct api_data *tmp; + bool done, first = true; + char *original, *escape; + K_ITEM *item; + + K_WLOCK(strbufs); + item = k_unlink_head(strbufs); + K_WUNLOCK(strbufs); + + DATASB(item)->siz = 0; + + if (precom) + add_item_buf(item, COMMA); + + if (isjson) + add_item_buf(item, JSON0); + + while (root) + { + if (!first) + add_item_buf(item, COMMA); + else + first = false; + + if (isjson) + add_item_buf(item, JSON1); + + add_item_buf(item, root->name); + + if (isjson) + add_item_buf(item, JSON1); + + if (isjson) + add_item_buf(item, ":"); + else + add_item_buf(item, "="); + + first = false; + + done = false; + switch(root->type) + { + case API_STRING: + case API_CONST: + if (isjson) + add_item_buf(item, JSON1); + add_item_buf(item, (char *)(root->data)); + if (isjson) + add_item_buf(item, JSON1); + done = true; + break; + case API_ESCAPE: + original = (char *)(root->data); + escape = escape_string((char *)(root->data), isjson); + if (isjson) + add_item_buf(item, JSON1); + add_item_buf(item, escape); + if (isjson) + add_item_buf(item, JSON1); + if (escape != original) + free(escape); + done = true; + break; + case API_UINT8: + snprintf(buf, sizeof(buf), "%u", *(uint8_t *)root->data); + break; + case API_INT16: + snprintf(buf, sizeof(buf), "%d", *(int16_t *)root->data); + break; + case API_UINT16: + snprintf(buf, sizeof(buf), "%u", *(uint16_t *)root->data); + break; + case API_INT: + snprintf(buf, sizeof(buf), "%d", *((int *)(root->data))); + break; + case API_UINT: + snprintf(buf, sizeof(buf), "%u", *((unsigned int *)(root->data))); + break; + case API_UINT32: + snprintf(buf, sizeof(buf), "%"PRIu32, *((uint32_t *)(root->data))); + break; + case API_HEX32: + if (isjson) + add_item_buf(item, JSON1); + snprintf(buf, sizeof(buf), "0x%08x", *((uint32_t *)(root->data))); + add_item_buf(item, buf); + if (isjson) + add_item_buf(item, JSON1); + done = true; + break; + case API_UINT64: + snprintf(buf, sizeof(buf), "%"PRIu64, *((uint64_t *)(root->data))); + break; + case API_INT64: + snprintf(buf, sizeof(buf), "%"PRId64, *((int64_t *)(root->data))); + break; + case API_TIME: + snprintf(buf, sizeof(buf), "%lu", *((unsigned long *)(root->data))); + break; + case API_DOUBLE: + snprintf(buf, sizeof(buf), "%f", *((double *)(root->data))); + break; + case API_ELAPSED: + snprintf(buf, sizeof(buf), "%.0f", *((double *)(root->data))); + break; + case API_UTILITY: + case API_FREQ: + case API_MHS: + snprintf(buf, sizeof(buf), "%.2f", *((double *)(root->data))); + break; + case API_VOLTS: + case API_AVG: + snprintf(buf, sizeof(buf), "%.3f", *((float *)(root->data))); + break; + case API_MHTOTAL: + snprintf(buf, sizeof(buf), "%.4f", *((double *)(root->data))); + break; + case API_HS: + snprintf(buf, sizeof(buf), "%.15f", *((double *)(root->data))); + break; + case API_DIFF: + snprintf(buf, sizeof(buf), "%.8f", *((double *)(root->data))); + break; + case API_BOOL: + snprintf(buf, sizeof(buf), "%s", *((bool *)(root->data)) ? TRUESTR : FALSESTR); + break; + case API_TIMEVAL: + snprintf(buf, sizeof(buf), "%ld.%06ld", + (long)((struct timeval *)(root->data))->tv_sec, + (long)((struct timeval *)(root->data))->tv_usec); + break; + case API_TEMP: + snprintf(buf, sizeof(buf), "%.2f", *((float *)(root->data))); + break; + case API_PERCENT: + snprintf(buf, sizeof(buf), "%.4f", *((double *)(root->data)) * 100.0); + break; + default: + applog(LOG_ERR, "API: unknown2 data type %d ignored", root->type); + if (isjson) + add_item_buf(item, JSON1); + add_item_buf(item, UNKNOWN); + if (isjson) + add_item_buf(item, JSON1); + done = true; + break; + } + + if (!done) + add_item_buf(item, buf); + + free(root->name); + if (root->data_was_malloc) + free(root->data); + + if (root->next == root) + { + free(root); + root = NULL; + } + else + { + tmp = root; + root = tmp->next; + root->prev = tmp->prev; + root->prev->next = root; + free(tmp); + } + } + + if (isjson) + add_item_buf(item, JSON5); + else + add_item_buf(item, SEPSTR); + + io_add(io_data, DATASB(item)->buf); + + K_WLOCK(strbufs); + k_add_head(strbufs, item); + K_WUNLOCK(strbufs); + + return root; +} + +#define DRIVER_COUNT_DRV(X) if (devices[i]->drv->drv_id == DRIVER_##X) \ + count++; + +#ifdef HAVE_AN_ASIC +static int numascs(void) +{ + int count = 0; + int i; + + rd_lock(&devices_lock); + for (i = 0; i < total_devices; i++) + { + ASIC_PARSE_COMMANDS(DRIVER_COUNT_DRV) + } + rd_unlock(&devices_lock); + return count; +} + +static int ascdevice(int ascid) +{ + int count = 0; + int i; + + rd_lock(&devices_lock); + for (i = 0; i < total_devices; i++) + { + ASIC_PARSE_COMMANDS(DRIVER_COUNT_DRV) + if (count == (ascid + 1)) + goto foundit; + } + + rd_unlock(&devices_lock); + return -1; + +foundit: + + rd_unlock(&devices_lock); + return i; +} +#endif + +#ifdef HAVE_AN_FPGA +static int numpgas(void) +{ + int count = 0; + int i; + + rd_lock(&devices_lock); + for (i = 0; i < total_devices; i++) + { + FPGA_PARSE_COMMANDS(DRIVER_COUNT_DRV) + } + rd_unlock(&devices_lock); + return count; +} + +static int pgadevice(int pgaid) +{ + int count = 0; + int i; + + rd_lock(&devices_lock); + for (i = 0; i < total_devices; i++) + { + FPGA_PARSE_COMMANDS(DRIVER_COUNT_DRV) + if (count == (pgaid + 1)) + goto foundit; + } + + rd_unlock(&devices_lock); + return -1; + +foundit: + + rd_unlock(&devices_lock); + return i; +} +#endif + +// All replies (except BYE and RESTART) start with a message +// thus for JSON, message() inserts JSON_START at the front +// and send_result() adds JSON_END at the end +static void message(struct io_data *io_data, int messageid, int paramid, char *param2, bool isjson) +{ + struct api_data *root = NULL; + char buf[TMPBUFSIZ]; + char severity[2]; +#ifdef HAVE_AN_ASIC + int asc; +#endif +#ifdef HAVE_AN_FPGA + int pga; +#endif + int i; + + if (isjson) + io_add(io_data, JSON_START JSON_STATUS); + + for (i = 0; codes[i].severity != SEVERITY_FAIL; i++) + { + if (codes[i].code == messageid) + { + switch (codes[i].severity) + { + case SEVERITY_WARN: + severity[0] = 'W'; + break; + case SEVERITY_INFO: + severity[0] = 'I'; + break; + case SEVERITY_SUCC: + severity[0] = 'S'; + break; + case SEVERITY_ERR: + default: + severity[0] = 'E'; + break; + } + severity[1] = '\0'; + + switch(codes[i].params) + { + case PARAM_PGA: + case PARAM_ASC: + case PARAM_PID: + case PARAM_INT: + sprintf(buf, codes[i].description, paramid); + break; + case PARAM_POOL: + sprintf(buf, codes[i].description, paramid, pools[paramid]->rpc_url); + break; +#ifdef HAVE_AN_FPGA + case PARAM_PGAMAX: + pga = numpgas(); + sprintf(buf, codes[i].description, paramid, pga - 1); + break; +#endif +#ifdef HAVE_AN_ASIC + case PARAM_ASCMAX: + asc = numascs(); + sprintf(buf, codes[i].description, paramid, asc - 1); + break; +#endif + case PARAM_PMAX: + sprintf(buf, codes[i].description, total_pools); + break; + case PARAM_POOLMAX: + sprintf(buf, codes[i].description, paramid, total_pools - 1); + break; + case PARAM_DMAX: +#ifdef HAVE_AN_ASIC + asc = numascs(); +#endif +#ifdef HAVE_AN_FPGA + pga = numpgas(); +#endif + + sprintf(buf, codes[i].description +#ifdef HAVE_AN_ASIC + , asc +#endif +#ifdef HAVE_AN_FPGA + , pga +#endif + ); + break; + case PARAM_CMD: + sprintf(buf, codes[i].description, JSON_COMMAND); + break; + case PARAM_STR: + sprintf(buf, codes[i].description, param2); + break; + case PARAM_BOTH: + sprintf(buf, codes[i].description, paramid, param2); + break; + case PARAM_BOOL: + sprintf(buf, codes[i].description, paramid ? TRUESTR : FALSESTR); + break; + case PARAM_SET: + sprintf(buf, codes[i].description, param2, paramid); + break; + case PARAM_NONE: + default: + strcpy(buf, codes[i].description); + } + + root = api_add_string(root, _STATUS, severity, false); + root = api_add_time(root, "When", &when, false); + root = api_add_int(root, "Code", &messageid, false); + root = api_add_escape(root, "Msg", buf, false); + root = api_add_escape(root, "Description", opt_api_description, false); + + root = print_data(io_data, root, isjson, false); + if (isjson) + io_add(io_data, JSON_CLOSE); + return; + } + } + + root = api_add_string(root, _STATUS, "F", false); + root = api_add_time(root, "When", &when, false); + int id = -1; + root = api_add_int(root, "Code", &id, false); + sprintf(buf, "%d", messageid); + root = api_add_escape(root, "Msg", buf, false); + root = api_add_escape(root, "Description", opt_api_description, false); + + root = print_data(io_data, root, isjson, false); + if (isjson) + io_add(io_data, JSON_CLOSE); +} + +#if LOCK_TRACKING + +#define LOCK_FMT_FFL " - called from %s %s():%d" + +#define LOCKMSG(fmt, ...) fprintf(stderr, "APILOCK: " fmt "\n", ##__VA_ARGS__) +#define LOCKMSGMORE(fmt, ...) fprintf(stderr, " " fmt "\n", ##__VA_ARGS__) +#define LOCKMSGFFL(fmt, ...) fprintf(stderr, "APILOCK: " fmt LOCK_FMT_FFL "\n", ##__VA_ARGS__, file, func, linenum) +#define LOCKMSGFLUSH() fflush(stderr) + +typedef struct lockstat +{ + uint64_t lock_id; + const char *file; + const char *func; + int linenum; + struct timeval tv; +} LOCKSTAT; + +typedef struct lockline +{ + struct lockline *prev; + struct lockstat *stat; + struct lockline *next; +} LOCKLINE; + +typedef struct lockinfo +{ + void *lock; + enum cglock_typ typ; + const char *file; + const char *func; + int linenum; + uint64_t gets; + uint64_t gots; + uint64_t tries; + uint64_t dids; + uint64_t didnts; // should be tries - dids + uint64_t unlocks; + LOCKSTAT lastgot; + LOCKLINE *lockgets; + LOCKLINE *locktries; +} LOCKINFO; + +typedef struct locklist +{ + LOCKINFO *info; + struct locklist *next; +} LOCKLIST; + +static uint64_t lock_id = 1; + +static LOCKLIST *lockhead; + +static void lockmsgnow() +{ + struct timeval now; + struct tm *tm; + time_t dt; + + cgtime(&now); + + dt = now.tv_sec; + tm = localtime(&dt); + + LOCKMSG("%d-%02d-%02d %02d:%02d:%02d", + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); +} + +static LOCKLIST *newlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum) +{ + LOCKLIST *list; + + list = cgcalloc(1, sizeof(*list)); + list->info = cgcalloc(1, sizeof(*(list->info))); + list->next = lockhead; + lockhead = list; + + list->info->lock = lock; + list->info->typ = typ; + list->info->file = file; + list->info->func = func; + list->info->linenum = linenum; + + return list; +} + +static LOCKINFO *findlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum) +{ + LOCKLIST *look; + + look = lockhead; + while (look) + { + if (look->info->lock == lock) + break; + look = look->next; + } + + if (!look) + look = newlock(lock, typ, file, func, linenum); + + return look->info; +} + +static void addgettry(LOCKINFO *info, uint64_t id, const char *file, const char *func, const int linenum, bool get) +{ + LOCKSTAT *stat; + LOCKLINE *line; + + stat = cgcalloc(1, sizeof(*stat)); + line = cgcalloc(1, sizeof(*line)); + + if (get) + info->gets++; + else + info->tries++; + + stat->lock_id = id; + stat->file = file; + stat->func = func; + stat->linenum = linenum; + cgtime(&stat->tv); + + line->stat = stat; + + if (get) + { + line->next = info->lockgets; + if (info->lockgets) + info->lockgets->prev = line; + info->lockgets = line; + } + else + { + line->next = info->locktries; + if (info->locktries) + info->locktries->prev = line; + info->locktries = line; + } +} + +static void markgotdid(LOCKINFO *info, uint64_t id, const char *file, const char *func, const int linenum, bool got, int ret) +{ + LOCKLINE *line; + + if (got) + info->gots++; + else + { + if (ret == 0) + info->dids++; + else + info->didnts++; + } + + if (got || ret == 0) + { + info->lastgot.lock_id = id; + info->lastgot.file = file; + info->lastgot.func = func; + info->lastgot.linenum = linenum; + cgtime(&info->lastgot.tv); + } + + if (got) + line = info->lockgets; + else + line = info->locktries; + while (line) + { + if (line->stat->lock_id == id) + break; + line = line->next; + } + + if (!line) + { + lockmsgnow(); + LOCKMSGFFL("ERROR attempt to mark a lock as '%s' that wasn't '%s' id=%"PRIu64, + got ? "got" : "did/didnt", got ? "get" : "try", id); + } + + // Unlink it + if (line->prev) + line->prev->next = line->next; + if (line->next) + line->next->prev = line->prev; + + if (got) + { + if (info->lockgets == line) + info->lockgets = line->next; + } + else + { + if (info->locktries == line) + info->locktries = line->next; + } + + free(line->stat); + free(line); +} + +// Yes this uses locks also ... ;/ +static void locklock() +{ + if (unlikely(pthread_mutex_lock(&lockstat_lock))) + quithere(1, "WTF MUTEX ERROR ON LOCK! errno=%d", errno); +} + +static void lockunlock() +{ + if (unlikely(pthread_mutex_unlock(&lockstat_lock))) + quithere(1, "WTF MUTEX ERROR ON UNLOCK! errno=%d", errno); +} + +uint64_t api_getlock(void *lock, const char *file, const char *func, const int linenum) +{ + LOCKINFO *info; + uint64_t id; + + locklock(); + + info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum); + id = lock_id++; + addgettry(info, id, file, func, linenum, true); + + lockunlock(); + + return id; +} + +void api_gotlock(uint64_t id, void *lock, const char *file, const char *func, const int linenum) +{ + LOCKINFO *info; + + locklock(); + + info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum); + markgotdid(info, id, file, func, linenum, true, 0); + + lockunlock(); +} + +uint64_t api_trylock(void *lock, const char *file, const char *func, const int linenum) +{ + LOCKINFO *info; + uint64_t id; + + locklock(); + + info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum); + id = lock_id++; + addgettry(info, id, file, func, linenum, false); + + lockunlock(); + + return id; +} + +void api_didlock(uint64_t id, int ret, void *lock, const char *file, const char *func, const int linenum) +{ + LOCKINFO *info; + + locklock(); + + info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum); + markgotdid(info, id, file, func, linenum, false, ret); + + lockunlock(); +} + +void api_gunlock(void *lock, const char *file, const char *func, const int linenum) +{ + LOCKINFO *info; + + locklock(); + + info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum); + info->unlocks++; + + lockunlock(); +} + +void api_initlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum) +{ + locklock(); + + findlock(lock, typ, file, func, linenum); + + lockunlock(); +} + +void dsp_det(char *msg, LOCKSTAT *stat) +{ + struct tm *tm; + time_t dt; + + dt = stat->tv.tv_sec; + tm = localtime(&dt); + + LOCKMSGMORE("%s id=%"PRIu64" by %s %s():%d at %d-%02d-%02d %02d:%02d:%02d", + msg, + stat->lock_id, + stat->file, + stat->func, + stat->linenum, + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); +} + +void dsp_lock(LOCKINFO *info) +{ + LOCKLINE *line; + char *status; + + LOCKMSG("Lock %p created by %s %s():%d", + info->lock, + info->file, + info->func, + info->linenum); + LOCKMSGMORE("gets:%"PRIu64" gots:%"PRIu64" tries:%"PRIu64 + " dids:%"PRIu64" didnts:%"PRIu64" unlocks:%"PRIu64, + info->gets, + info->gots, + info->tries, + info->dids, + info->didnts, + info->unlocks); + + if (info->gots > 0 || info->dids > 0) + { + if (info->unlocks < info->gots + info->dids) + status = "Last got/did still HELD"; + else + status = "Last got/did (idle)"; + + dsp_det(status, &(info->lastgot)); + } + else + LOCKMSGMORE("... unused ..."); + + if (info->lockgets) + { + LOCKMSGMORE("BLOCKED gets (%"PRIu64")", info->gets - info->gots); + line = info->lockgets; + while (line) + { + dsp_det("", line->stat); + line = line->next; + } + } + else + LOCKMSGMORE("no blocked gets"); + + if (info->locktries) + { + LOCKMSGMORE("BLOCKED tries (%"PRIu64")", info->tries - info->dids - info->didnts); + line = info->lockgets; + while (line) + { + dsp_det("", line->stat); + line = line->next; + } + } + else + LOCKMSGMORE("no blocked tries"); +} + +void show_locks() +{ + LOCKLIST *list; + + locklock(); + + lockmsgnow(); + + list = lockhead; + if (!list) + LOCKMSG("no locks?!?\n"); + else + { + while (list) + { + dsp_lock(list->info); + list = list->next; + } + } + + LOCKMSGFLUSH(); + + lockunlock(); +} +#endif + +static void lockstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ +#if LOCK_TRACKING + show_locks(); + message(io_data, MSG_LOCKOK, 0, NULL, isjson); +#else + message(io_data, MSG_LOCKDIS, 0, NULL, isjson); +#endif +} + +static void apiversion(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + bool io_open; + + message(io_data, MSG_VERSION, 0, NULL, isjson); + io_open = io_add(io_data, isjson ? COMSTR JSON_VERSION : _VERSION COMSTR); + + root = api_add_string(root, "CGMiner", VERSION, false); + root = api_add_const(root, "API", APIVERSION, false); + root = api_add_string(root, "Miner", g_miner_version, false); + root = api_add_string(root, "CompileTime", g_miner_compiletime, false); + root = api_add_string(root, "Type", g_miner_type, false); + + root = print_data(io_data, root, isjson, false); + if (isjson && io_open) + io_close(io_data); +} + +static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + bool io_open; + int asccount = 0; + int pgacount = 0; + +#ifdef HAVE_AN_ASIC + asccount = numascs(); +#endif + +#ifdef HAVE_AN_FPGA + pgacount = numpgas(); +#endif + + message(io_data, MSG_MINECONFIG, 0, NULL, isjson); + io_open = io_add(io_data, isjson ? COMSTR JSON_MINECONFIG : _MINECONFIG COMSTR); + + root = api_add_int(root, "ASC Count", &asccount, false); + root = api_add_int(root, "PGA Count", &pgacount, false); + root = api_add_int(root, "Pool Count", &total_pools, false); + root = api_add_const(root, "Strategy", strategies[pool_strategy].s, false); + root = api_add_int(root, "Log Interval", &opt_log_interval, false); + root = api_add_const(root, "Device Code", DEVICECODE, false); + root = api_add_const(root, "OS", OSINFO, false); +#ifdef USE_USBUTILS + if (hotplug_time == 0) + root = api_add_const(root, "Hotplug", DISABLED, false); + else + root = api_add_int(root, "Hotplug", &hotplug_time, false); +#else + root = api_add_const(root, "Hotplug", NONE, false); +#endif + + root = print_data(io_data, root, isjson, false); + if (isjson && io_open) + io_close(io_data); +} + +static const char *status2str(enum alive status) +{ + switch (status) + { + case LIFE_WELL: + return ALIVE; + case LIFE_SICK: + return SICK; + case LIFE_DEAD: + return DEAD; + case LIFE_NOSTART: + return NOSTART; + case LIFE_INIT: + return INIT; + default: + return UNKNOWN; + } +} + +#ifdef HAVE_AN_ASIC +static void ascstatus(struct io_data *io_data, int asc, bool isjson, bool precom) +{ + struct api_data *root = NULL; + char *enabled; + char *status; + int numasc = numascs(); + + if (numasc > 0 && asc >= 0 && asc < numasc) + { + int dev = ascdevice(asc); + if (dev < 0) // Should never happen + return; + + struct cgpu_info *cgpu = get_devices(dev); + float temp = cgpu->temp; + double dev_runtime; + + dev_runtime = cgpu_runtime(cgpu); + + cgpu->utility = cgpu->accepted / dev_runtime * 60; + + if (cgpu->deven != DEV_DISABLED) + enabled = (char *)YES; + else + enabled = (char *)NO; + + status = (char *)status2str(cgpu->status); + + root = api_add_int(root, "ASC", &asc, false); + root = api_add_string(root, "Name", cgpu->drv->name, false); + root = api_add_int(root, "ID", &(cgpu->device_id), false); + root = api_add_string(root, "Enabled", enabled, false); + root = api_add_string(root, "Status", status, false); + root = api_add_temp(root, "Temperature", &temp, false); + double mhs = cgpu->total_mhashes / dev_runtime; + root = api_add_mhs(root, "MHS av", &mhs, false); + char mhsname[27]; + sprintf(mhsname, "MHS %ds", opt_log_interval); + root = api_add_mhs(root, mhsname, &(cgpu->rolling), false); + root = api_add_int(root, "Accepted", &(cgpu->accepted), false); + root = api_add_int(root, "Rejected", &(cgpu->rejected), false); + root = api_add_int(root, "Hardware Errors", &(cgpu->hw_errors), false); + root = api_add_utility(root, "Utility", &(cgpu->utility), false); + int last_share_pool = cgpu->last_share_pool_time > 0 ? + cgpu->last_share_pool : -1; + root = api_add_int(root, "Last Share Pool", &last_share_pool, false); + root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false); + root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false); + root = api_add_int64(root, "Diff1 Work", &(cgpu->diff1), false); + root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false); + root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false); + root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false); +#ifdef USE_USBUTILS + root = api_add_bool(root, "No Device", &(cgpu->usbinfo.nodev), false); +#endif + root = api_add_time(root, "Last Valid Work", &(cgpu->last_device_valid_work), false); + double hwp = (cgpu->hw_errors + cgpu->diff1) ? + (double)(cgpu->hw_errors) / (double)(cgpu->hw_errors + cgpu->diff1) : 0; + root = api_add_percent(root, "Device Hardware%", &hwp, false); + double rejp = cgpu->diff1 ? + (double)(cgpu->diff_rejected) / (double)(cgpu->diff1) : 0; + root = api_add_percent(root, "Device Rejected%", &rejp, false); + root = api_add_elapsed(root, "Device Elapsed", &(dev_runtime), false); + + root = print_data(io_data, root, isjson, precom); + } +} +#endif + +#ifdef HAVE_AN_FPGA +static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom) +{ + struct api_data *root = NULL; + char *enabled; + char *status; + int numpga = numpgas(); + + if (numpga > 0 && pga >= 0 && pga < numpga) + { + int dev = pgadevice(pga); + if (dev < 0) // Should never happen + return; + + struct cgpu_info *cgpu = get_devices(dev); + double frequency = 0; + float temp = cgpu->temp; + struct timeval now; + double dev_runtime; + + if (cgpu->dev_start_tv.tv_sec == 0) + dev_runtime = total_secs; + else + { + cgtime(&now); + dev_runtime = tdiff(&now, &(cgpu->dev_start_tv)); + } + + if (dev_runtime < 1.0) + dev_runtime = 1.0; + +#ifdef USE_MODMINER + if (cgpu->drv->drv_id == DRIVER_modminer) + frequency = cgpu->clock; +#endif + + cgpu->utility = cgpu->accepted / dev_runtime * 60; + + if (cgpu->deven != DEV_DISABLED) + enabled = (char *)YES; + else + enabled = (char *)NO; + + status = (char *)status2str(cgpu->status); + + root = api_add_int(root, "PGA", &pga, false); + root = api_add_string(root, "Name", cgpu->drv->name, false); + root = api_add_int(root, "ID", &(cgpu->device_id), false); + root = api_add_string(root, "Enabled", enabled, false); + root = api_add_string(root, "Status", status, false); + root = api_add_temp(root, "Temperature", &temp, false); + double mhs = cgpu->total_mhashes / dev_runtime; + root = api_add_mhs(root, "MHS av", &mhs, false); + char mhsname[27]; + sprintf(mhsname, "MHS %ds", opt_log_interval); + root = api_add_mhs(root, mhsname, &(cgpu->rolling), false); + root = api_add_int(root, "Accepted", &(cgpu->accepted), false); + root = api_add_int(root, "Rejected", &(cgpu->rejected), false); + root = api_add_int(root, "Hardware Errors", &(cgpu->hw_errors), false); + root = api_add_utility(root, "Utility", &(cgpu->utility), false); + int last_share_pool = cgpu->last_share_pool_time > 0 ? + cgpu->last_share_pool : -1; + root = api_add_int(root, "Last Share Pool", &last_share_pool, false); + root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false); + root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false); + root = api_add_freq(root, "Frequency", &frequency, false); + root = api_add_int64(root, "Diff1 Work", &(cgpu->diff1), false); + root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false); + root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false); + root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false); +#ifdef USE_USBUTILS + root = api_add_bool(root, "No Device", &(cgpu->usbinfo.nodev), false); +#endif + root = api_add_time(root, "Last Valid Work", &(cgpu->last_device_valid_work), false); + double hwp = (cgpu->hw_errors + cgpu->diff1) ? + (double)(cgpu->hw_errors) / (double)(cgpu->hw_errors + cgpu->diff1) : 0; + root = api_add_percent(root, "Device Hardware%", &hwp, false); + double rejp = cgpu->diff1 ? + (double)(cgpu->diff_rejected) / (double)(cgpu->diff1) : 0; + root = api_add_percent(root, "Device Rejected%", &rejp, false); + root = api_add_elapsed(root, "Device Elapsed", &(dev_runtime), false); + + root = print_data(io_data, root, isjson, precom); + } +} +#endif + +static void devstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + bool io_open = false; + int devcount = 0; + int numasc = 0; + int numpga = 0; + int i; + +#ifdef HAVE_AN_ASIC + numasc = numascs(); +#endif + +#ifdef HAVE_AN_FPGA + numpga = numpgas(); +#endif + + if (numpga == 0 && numasc == 0) + { + message(io_data, MSG_NODEVS, 0, NULL, isjson); + return; + } + + + message(io_data, MSG_DEVS, 0, NULL, isjson); + if (isjson) + io_open = io_add(io_data, COMSTR JSON_DEVS); + +#ifdef HAVE_AN_ASIC + if (numasc > 0) + { + for (i = 0; i < numasc; i++) + { + ascstatus(io_data, i, isjson, isjson && devcount > 0); + + devcount++; + } + } +#endif + +#ifdef HAVE_AN_FPGA + if (numpga > 0) + { + for (i = 0; i < numpga; i++) + { + pgastatus(io_data, i, isjson, isjson && devcount > 0); + + devcount++; + } + } +#endif + + if (isjson && io_open) + io_close(io_data); +} + +static void edevstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + bool io_open = false; + int devcount = 0; + int numasc = 0; + int numpga = 0; + int i; +#ifdef USE_USBUTILS + time_t howoldsec = 0; +#endif + +#ifdef HAVE_AN_ASIC + numasc = numascs(); +#endif + +#ifdef HAVE_AN_FPGA + numpga = numpgas(); +#endif + + if (numpga == 0 && numasc == 0) + { + message(io_data, MSG_NODEVS, 0, NULL, isjson); + return; + } + +#ifdef USE_USBUTILS + if (param && *param) + howoldsec = (time_t)atoi(param); +#endif + + message(io_data, MSG_DEVS, 0, NULL, isjson); + if (isjson) + io_open = io_add(io_data, COMSTR JSON_DEVS); + +#ifdef HAVE_AN_ASIC + if (numasc > 0) + { + for (i = 0; i < numasc; i++) + { +#ifdef USE_USBUTILS + int dev = ascdevice(i); + if (dev < 0) // Should never happen + continue; + + struct cgpu_info *cgpu = get_devices(dev); + if (!cgpu) + continue; + if (cgpu->blacklisted) + continue; + if (cgpu->usbinfo.nodev) + { + if (howoldsec <= 0) + continue; + if ((when - cgpu->usbinfo.last_nodev.tv_sec) >= howoldsec) + continue; + } +#endif + + ascstatus(io_data, i, isjson, isjson && devcount > 0); + + devcount++; + } + } +#endif + +#ifdef HAVE_AN_FPGA + if (numpga > 0) + { + for (i = 0; i < numpga; i++) + { +#ifdef USE_USBUTILS + int dev = pgadevice(i); + if (dev < 0) // Should never happen + continue; + + struct cgpu_info *cgpu = get_devices(dev); + if (!cgpu) + continue; + if (cgpu->blacklisted) + continue; + if (cgpu->usbinfo.nodev) + { + if (howoldsec <= 0) + continue; + if ((when - cgpu->usbinfo.last_nodev.tv_sec) >= howoldsec) + continue; + } +#endif + + pgastatus(io_data, i, isjson, isjson && devcount > 0); + + devcount++; + } + } +#endif + + if (isjson && io_open) + io_close(io_data); +} + +#ifdef HAVE_AN_FPGA +static void pgadev(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + bool io_open = false; + int numpga = numpgas(); + int id; + + if (numpga == 0) + { + message(io_data, MSG_PGANON, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISID, 0, NULL, isjson); + return; + } + + id = atoi(param); + if (id < 0 || id >= numpga) + { + message(io_data, MSG_INVPGA, id, NULL, isjson); + return; + } + + message(io_data, MSG_PGADEV, id, NULL, isjson); + + if (isjson) + io_open = io_add(io_data, COMSTR JSON_PGA); + + pgastatus(io_data, id, isjson, false); + + if (isjson && io_open) + io_close(io_data); +} + +static void pgaenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct cgpu_info *cgpu; + int numpga = numpgas(); + struct thr_info *thr; + int pga; + int id; + int i; + + if (numpga == 0) + { + message(io_data, MSG_PGANON, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISID, 0, NULL, isjson); + return; + } + + id = atoi(param); + if (id < 0 || id >= numpga) + { + message(io_data, MSG_INVPGA, id, NULL, isjson); + return; + } + + int dev = pgadevice(id); + if (dev < 0) // Should never happen + { + message(io_data, MSG_INVPGA, id, NULL, isjson); + return; + } + + cgpu = get_devices(dev); + + applog(LOG_DEBUG, "API: request to pgaenable pgaid %d device %d %s%u", + id, dev, cgpu->drv->name, cgpu->device_id); + + if (cgpu->deven != DEV_DISABLED) + { + message(io_data, MSG_PGALRENA, id, NULL, isjson); + return; + } + +#if 0 /* A DISABLED device wont change status FIXME: should disabling make it WELL? */ + if (cgpu->status != LIFE_WELL) + { + message(io_data, MSG_PGAUNW, id, NULL, isjson); + return; + } +#endif + +#ifdef USE_USBUTILS + if (cgpu->usbinfo.nodev) + { + message(io_data, MSG_PGAUSBNODEV, id, NULL, isjson); + return; + } +#endif + + for (i = 0; i < mining_threads; i++) + { + thr = get_thread(i); + pga = thr->cgpu->cgminer_id; + if (pga == dev) + { + cgpu->deven = DEV_ENABLED; + applog(LOG_DEBUG, "API: Pushing sem post to thread %d", thr->id); + cgsem_post(&thr->sem); + } + } + + message(io_data, MSG_PGAENA, id, NULL, isjson); +} + +static void pgadisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct cgpu_info *cgpu; + int numpga = numpgas(); + int id; + + if (numpga == 0) + { + message(io_data, MSG_PGANON, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISID, 0, NULL, isjson); + return; + } + + id = atoi(param); + if (id < 0 || id >= numpga) + { + message(io_data, MSG_INVPGA, id, NULL, isjson); + return; + } + + int dev = pgadevice(id); + if (dev < 0) // Should never happen + { + message(io_data, MSG_INVPGA, id, NULL, isjson); + return; + } + + cgpu = get_devices(dev); + + applog(LOG_DEBUG, "API: request to pgadisable pgaid %d device %d %s%u", + id, dev, cgpu->drv->name, cgpu->device_id); + + if (cgpu->deven == DEV_DISABLED) + { + message(io_data, MSG_PGALRDIS, id, NULL, isjson); + return; + } + + cgpu->deven = DEV_DISABLED; + + message(io_data, MSG_PGADIS, id, NULL, isjson); +} + +static void pgaidentify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct cgpu_info *cgpu; + struct device_drv *drv; + int numpga = numpgas(); + int id; + + if (numpga == 0) + { + message(io_data, MSG_PGANON, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISID, 0, NULL, isjson); + return; + } + + id = atoi(param); + if (id < 0 || id >= numpga) + { + message(io_data, MSG_INVPGA, id, NULL, isjson); + return; + } + + int dev = pgadevice(id); + if (dev < 0) // Should never happen + { + message(io_data, MSG_INVPGA, id, NULL, isjson); + return; + } + + cgpu = get_devices(dev); + drv = cgpu->drv; + + if (!drv->identify_device) + message(io_data, MSG_PGANOID, id, NULL, isjson); + else + { + drv->identify_device(cgpu); + message(io_data, MSG_PGAIDENT, id, NULL, isjson); + } +} +#endif +static void poolstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + bool io_open = false; + char *status, *lp; + int i; + int hour = 0; + int minute = 0; + int second = 0; + + char lasttime[256] = {0}; + long timediff = 0; + + if (total_pools == 0) + { + message(io_data, MSG_NOPOOL, 0, NULL, isjson); + return; + } + + message(io_data, MSG_POOL, 0, NULL, isjson); + + if (isjson) + io_open = io_add(io_data, COMSTR JSON_POOLS); + + for (i = 0; i < total_pools; i++) + { + struct pool *pool = pools[i]; + + if (pool->removed) + continue; + + switch (pool->enabled) + { + case POOL_DISABLED: + status = (char *)DISABLED; + break; + case POOL_REJECTING: + status = (char *)REJECTING; + break; + case POOL_ENABLED: + if (pool->idle) + status = (char *)DEAD; + else + status = (char *)ALIVE; + break; + default: + status = (char *)UNKNOWN; + break; + } + + if (pool->hdr_path) + lp = (char *)YES; + else + lp = (char *)NO; + + if(pool->last_share_time <= 0) + { + strcpy(lasttime, "0"); + } + else + { + timediff = time(NULL) - pool->last_share_time; + if(timediff < 0) + timediff = 0; + + hour = timediff / 3600; + minute = (timediff % 3600) / 60; + second = (timediff % 3600) % 60; + sprintf(lasttime, "%d:%02d:%02d", hour, minute, second); + } + + root = api_add_int(root, "POOL", &i, false); + root = api_add_escape(root, "URL", pool->rpc_url, false); + root = api_add_string(root, "Status", status, false); + root = api_add_int(root, "Priority", &(pool->prio), false); + root = api_add_int(root, "Quota", &pool->quota, false); + root = api_add_string(root, "Long Poll", lp, false); + root = api_add_uint(root, "Getworks", &(pool->getwork_requested), false); + root = api_add_int64(root, "Accepted", &(pool->accepted), false); + root = api_add_int64(root, "Rejected", &(pool->rejected), false); + //root = api_add_int(root, "Works", &pool->works, false); + root = api_add_uint(root, "Discarded", &(pool->discarded_work), false); + root = api_add_uint(root, "Stale", &(pool->stale_shares), false); + root = api_add_uint(root, "Get Failures", &(pool->getfail_occasions), false); + root = api_add_uint(root, "Remote Failures", &(pool->remotefail_occasions), false); + root = api_add_escape(root, "User", pool->rpc_user, false); + //root = api_add_time(root, "Last Share Time", &(pool->last_share_time), false); + root = api_add_string(root, "Last Share Time", lasttime, false); + root = api_add_string(root, "Diff", pool->diff, false); + root = api_add_int64(root, "Diff1 Shares", &(pool->diff1), false); + if (pool->rpc_proxy) + { + root = api_add_const(root, "Proxy Type", proxytype(pool->rpc_proxytype), false); + root = api_add_escape(root, "Proxy", pool->rpc_proxy, false); + } + else + { + root = api_add_const(root, "Proxy Type", BLANK, false); + root = api_add_const(root, "Proxy", BLANK, false); + } + root = api_add_diff(root, "Difficulty Accepted", &(pool->diff_accepted), false); + root = api_add_diff(root, "Difficulty Rejected", &(pool->diff_rejected), false); + root = api_add_diff(root, "Difficulty Stale", &(pool->diff_stale), false); + root = api_add_diff(root, "Last Share Difficulty", &(pool->last_share_diff), false); + root = api_add_bool(root, "Has Stratum", &(pool->has_stratum), false); + root = api_add_bool(root, "Stratum Active", &(pool->stratum_active), false); + if (pool->stratum_active) + root = api_add_escape(root, "Stratum URL", pool->stratum_url, false); + else + root = api_add_const(root, "Stratum URL", BLANK, false); + root = api_add_bool(root, "Has GBT", &(pool->has_gbt), false); + root = api_add_uint64(root, "Best Share", &(pool->best_diff), true); + double rejp = (pool->diff_accepted + pool->diff_rejected + pool->diff_stale) ? + (double)(pool->diff_rejected) / (double)(pool->diff_accepted + pool->diff_rejected + pool->diff_stale) : 0; + root = api_add_percent(root, "Pool Rejected%", &rejp, false); + double stalep = (pool->diff_accepted + pool->diff_rejected + pool->diff_stale) ? + (double)(pool->diff_stale) / (double)(pool->diff_accepted + pool->diff_rejected + pool->diff_stale) : 0; + root = api_add_percent(root, "Pool Stale%", &stalep, false); + + root = print_data(io_data, root, isjson, isjson && (i > 0)); + } + + if (isjson && io_open) + io_close(io_data); +} + +static double getAVGhashrate() +{ + return (total_mhashes_done - new_total_mhashes_done)/ 1000 / (total_secs - new_total_secs); +} + +static void lcddisplay(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + bool io_open = false; + char *status, *lp; + double ghs; + + char szindex[32] = {0}; + char szpool[32] = {0}; + char szuser[32] = {0}; + + struct pool *pool = current_pool(); + + message(io_data, MSG_POOL, 0, NULL, isjson); + + if (isjson) + io_open = io_add(io_data, COMSTR JSON_POOLS); + + ghs = getAVGhashrate(); + + strcpy(szindex, "0"); + root = api_add_string(root, "LCD", szindex, false); + + root = api_add_string(root, "GHS 5s", displayed_hash_rate, false); + root = api_add_mhs(root, "GHSavg", &(ghs), false); + + if(pool == NULL) + { + strcpy(szpool, "no"); + strcpy(szuser, "no"); + root = api_add_string(root, "pool", szpool, false); + root = api_add_string(root, "user", szuser, false); + } + else + { + root = api_add_string(root, "pool", pool->rpc_url, false); + root = api_add_string(root, "user", pool->rpc_user, false); + } + + root = print_data(io_data, root, isjson, isjson); + + if (isjson && io_open) + io_close(io_data); +} + +static void summary(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + bool io_open; + double utility, ghs, work_utility; + + message(io_data, MSG_SUMM, 0, NULL, isjson); + io_open = io_add(io_data, isjson ? COMSTR JSON_SUMMARY : _SUMMARY COMSTR); + + // stop hashmeter() changing some while copying + mutex_lock(&hash_lock); + total_diff1 = total_diff_accepted + total_diff_rejected + total_diff_stale; + + utility = total_accepted / ( total_secs ? total_secs : 1 ) * 60; + + ghs = getAVGhashrate(); + + work_utility = total_diff1 / ( total_secs ? total_secs : 1 ) * 60; + + root = api_add_elapsed(root, "Elapsed", &(total_secs), true); + + root = api_add_string(root, "GHS 5s", displayed_hash_rate, false); + root = api_add_mhs(root, "GHS av", &(ghs), false); + root = api_add_uint(root, "Found Blocks", &(found_blocks), true); + root = api_add_int64(root, "Getworks", &(total_getworks), true); + root = api_add_int64(root, "Accepted", &(total_accepted), true); + root = api_add_int64(root, "Rejected", &(total_rejected), true); + root = api_add_int(root, "Hardware Errors", &(hw_errors), true); + root = api_add_utility(root, "Utility", &(utility), false); + root = api_add_int64(root, "Discarded", &(total_discarded), true); + root = api_add_int64(root, "Stale", &(total_stale), true); + root = api_add_uint(root, "Get Failures", &(total_go), true); + root = api_add_uint(root, "Local Work", &(local_work), true); + root = api_add_uint(root, "Remote Failures", &(total_ro), true); + root = api_add_uint(root, "Network Blocks", &(new_blocks), true); + root = api_add_mhtotal(root, "Total MH", &(total_mhashes_done), true); + root = api_add_utility(root, "Work Utility", &(work_utility), false); + root = api_add_diff(root, "Difficulty Accepted", &(total_diff_accepted), true); + root = api_add_diff(root, "Difficulty Rejected", &(total_diff_rejected), true); + root = api_add_diff(root, "Difficulty Stale", &(total_diff_stale), true); + root = api_add_uint64(root, "Best Share", &(best_diff), true); + double hwp = (hw_errors + total_diff1) ? + (double)(hw_errors) / (double)(hw_errors + total_diff1) : 0; + root = api_add_percent(root, "Device Hardware%", &hwp, false); + double rejp = total_diff1 ? + (double)(total_diff_rejected) / (double)(total_diff1) : 0; + root = api_add_percent(root, "Device Rejected%", &rejp, false); + double prejp = (total_diff_accepted + total_diff_rejected + total_diff_stale) ? + (double)(total_diff_rejected) / (double)(total_diff_accepted + total_diff_rejected + total_diff_stale) : 0; + root = api_add_percent(root, "Pool Rejected%", &prejp, false); + double stalep = (total_diff_accepted + total_diff_rejected + total_diff_stale) ? + (double)(total_diff_stale) / (double)(total_diff_accepted + total_diff_rejected + total_diff_stale) : 0; + root = api_add_percent(root, "Pool Stale%", &stalep, false); + root = api_add_time(root, "Last getwork", &last_getwork, false); + + mutex_unlock(&hash_lock); + + root = print_data(io_data, root, isjson, false); + if (isjson && io_open) + io_close(io_data); +} + +static void noncenum(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + bool io_open; + + message(io_data, MSG_NONCE_NUM, 0, NULL, isjson); + io_open = io_add(io_data, isjson ? COMSTR JSON_NONCENUM : _NONCENUM COMSTR); + + root = api_add_string(root, "10min nonce",nonce_num10_string, false); + root = api_add_string(root, "30min nonce",nonce_num30_string , false); + root = api_add_string(root, "60min nonce",nonce_num60_string , false); + + root = print_data(io_data, root, isjson, false); + if (isjson && io_open) + io_close(io_data); +} + + +static void pgacount(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + bool io_open; + int count = 0; + +#ifdef HAVE_AN_FPGA + count = numpgas(); +#endif + + message(io_data, MSG_NUMPGA, 0, NULL, isjson); + io_open = io_add(io_data, isjson ? COMSTR JSON_PGAS : _PGAS COMSTR); + + root = api_add_int(root, "Count", &count, false); + + root = print_data(io_data, root, isjson, false); + if (isjson && io_open) + io_close(io_data); +} + +static void switchpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct pool *pool; + int id; + + if (total_pools == 0) + { + message(io_data, MSG_NOPOOL, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISPID, 0, NULL, isjson); + return; + } + + id = atoi(param); + cg_rlock(&control_lock); + if (id < 0 || id >= total_pools) + { + cg_runlock(&control_lock); + message(io_data, MSG_INVPID, id, NULL, isjson); + return; + } + + pool = pools[id]; + pool->enabled = POOL_ENABLED; + cg_runlock(&control_lock); + switch_pools(pool); + + message(io_data, MSG_SWITCHP, id, NULL, isjson); +} + +static void copyadvanceafter(char ch, char **param, char **buf) +{ +#define src_p (*param) +#define dst_b (*buf) + + while (*src_p && *src_p != ch) + { + if (*src_p == '\\' && *(src_p+1) != '\0') + src_p++; + + *(dst_b++) = *(src_p++); + } + if (*src_p) + src_p++; + + *(dst_b++) = '\0'; +} + +static bool pooldetails(char *param, char **url, char **user, char **pass) +{ + char *ptr, *buf; + + ptr = buf = cgmalloc(strlen(param)+1); + + *url = buf; + + // copy url + copyadvanceafter(',', ¶m, &buf); + + if (!(*param)) // missing user + goto exitsama; + + *user = buf; + + // copy user + copyadvanceafter(',', ¶m, &buf); + + if (!*param) // missing pass + goto exitsama; + + *pass = buf; + + // copy pass + copyadvanceafter(',', ¶m, &buf); + + return true; + +exitsama: + free(ptr); + return false; +} + +static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + char *url, *user, *pass; + struct pool *pool; + char *ptr; + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISPDP, 0, NULL, isjson); + return; + } + + if (!pooldetails(param, &url, &user, &pass)) + { + ptr = escape_string(param, isjson); + message(io_data, MSG_INVPDP, 0, ptr, isjson); + if (ptr != param) + free(ptr); + ptr = NULL; + return; + } + + pool = add_pool(); + detect_stratum(pool, url); + add_pool_details(pool, true, url, user, pass); + + ptr = escape_string(url, isjson); + message(io_data, MSG_ADDPOOL, pool->pool_no, ptr, isjson); + if (ptr != url) + free(ptr); + ptr = NULL; +} + +static void enablepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct pool *pool; + int id; + + if (total_pools == 0) + { + message(io_data, MSG_NOPOOL, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISPID, 0, NULL, isjson); + return; + } + + id = atoi(param); + if (id < 0 || id >= total_pools) + { + message(io_data, MSG_INVPID, id, NULL, isjson); + return; + } + + pool = pools[id]; + if (pool->enabled == POOL_ENABLED) + { + message(io_data, MSG_ALRENAP, id, NULL, isjson); + return; + } + + pool->enabled = POOL_ENABLED; + if (pool->prio < current_pool()->prio) + switch_pools(pool); + + message(io_data, MSG_ENAPOOL, id, NULL, isjson); +} + +static void poolpriority(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + char *ptr, *next; + int i, pr, prio = 0; + + // TODO: all cgminer code needs a mutex added everywhere for change + // access to total_pools and also parts of the pools[] array, + // just copying total_pools here wont solve that + + if (total_pools == 0) + { + message(io_data, MSG_NOPOOL, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISPID, 0, NULL, isjson); + return; + } + + bool pools_changed[total_pools]; + int new_prio[total_pools]; + for (i = 0; i < total_pools; ++i) + pools_changed[i] = false; + + next = param; + while (next && *next) + { + ptr = next; + next = strchr(ptr, ','); + if (next) + *(next++) = '\0'; + + i = atoi(ptr); + if (i < 0 || i >= total_pools) + { + message(io_data, MSG_INVPID, i, NULL, isjson); + return; + } + + if (pools_changed[i]) + { + message(io_data, MSG_DUPPID, i, NULL, isjson); + return; + } + + pools_changed[i] = true; + new_prio[i] = prio++; + } + + // Only change them if no errors + for (i = 0; i < total_pools; i++) + { + if (pools_changed[i]) + pools[i]->prio = new_prio[i]; + } + + // In priority order, cycle through the unchanged pools and append them + for (pr = 0; pr < total_pools; pr++) + for (i = 0; i < total_pools; i++) + { + if (!pools_changed[i] && pools[i]->prio == pr) + { + pools[i]->prio = prio++; + pools_changed[i] = true; + break; + } + } + + if (current_pool()->prio) + switch_pools(NULL); + + message(io_data, MSG_POOLPRIO, 0, NULL, isjson); +} + +static void poolquota(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct pool *pool; + int quota, id; + char *comma; + + if (total_pools == 0) + { + message(io_data, MSG_NOPOOL, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISPID, 0, NULL, isjson); + return; + } + + comma = strchr(param, ','); + if (!comma) + { + message(io_data, MSG_CONVAL, 0, param, isjson); + return; + } + + *(comma++) = '\0'; + + id = atoi(param); + if (id < 0 || id >= total_pools) + { + message(io_data, MSG_INVPID, id, NULL, isjson); + return; + } + pool = pools[id]; + + quota = atoi(comma); + if (quota < 0) + { + message(io_data, MSG_INVNEG, quota, pool->rpc_url, isjson); + return; + } + + pool->quota = quota; + adjust_quota_gcd(); + message(io_data, MSG_SETQUOTA, quota, pool->rpc_url, isjson); +} + +static void disablepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct pool *pool; + int id; + + if (total_pools == 0) + { + message(io_data, MSG_NOPOOL, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISPID, 0, NULL, isjson); + return; + } + + id = atoi(param); + if (id < 0 || id >= total_pools) + { + message(io_data, MSG_INVPID, id, NULL, isjson); + return; + } + + pool = pools[id]; + if (pool->enabled == POOL_DISABLED) + { + message(io_data, MSG_ALRDISP, id, NULL, isjson); + return; + } + + if (enabled_pools <= 1) + { + message(io_data, MSG_DISLASTP, id, NULL, isjson); + return; + } + + pool->enabled = POOL_DISABLED; + if (pool == current_pool()) + switch_pools(NULL); + + message(io_data, MSG_DISPOOL, id, NULL, isjson); +} + +static void removepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct pool *pool; + char *rpc_url; + bool dofree = false; + int id; + + if (total_pools == 0) + { + message(io_data, MSG_NOPOOL, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISPID, 0, NULL, isjson); + return; + } + + id = atoi(param); + if (id < 0 || id >= total_pools) + { + message(io_data, MSG_INVPID, id, NULL, isjson); + return; + } + + if (total_pools <= 1) + { + message(io_data, MSG_REMLASTP, id, NULL, isjson); + return; + } + + pool = pools[id]; + if (pool == current_pool()) + switch_pools(NULL); + + if (pool == current_pool()) + { + message(io_data, MSG_ACTPOOL, id, NULL, isjson); + return; + } + + pool->enabled = POOL_DISABLED; + rpc_url = escape_string(pool->rpc_url, isjson); + if (rpc_url != pool->rpc_url) + dofree = true; + + remove_pool(pool); + + message(io_data, MSG_REMPOOL, id, rpc_url, isjson); + + if (dofree) + free(rpc_url); + rpc_url = NULL; +} + +void doquit(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + if (isjson) + io_put(io_data, JSON_ACTION JSON_BYE); + else + io_put(io_data, _BYE); + + bye = true; + do_a_quit = true; +} + +void dorestart(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + if (isjson) + io_put(io_data, JSON_ACTION JSON_RESTART); + else + io_put(io_data, _RESTART); + + bye = true; + do_a_restart = true; +} + +void privileged(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + message(io_data, MSG_ACCOK, 0, NULL, isjson); +} + +void notifystatus(struct io_data *io_data, int device, struct cgpu_info *cgpu, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + char *reason; + + if (cgpu->device_last_not_well == 0) + reason = REASON_NONE; + else + switch(cgpu->device_not_well_reason) + { + case REASON_THREAD_FAIL_INIT: + reason = REASON_THREAD_FAIL_INIT_STR; + break; + case REASON_THREAD_ZERO_HASH: + reason = REASON_THREAD_ZERO_HASH_STR; + break; + case REASON_THREAD_FAIL_QUEUE: + reason = REASON_THREAD_FAIL_QUEUE_STR; + break; + case REASON_DEV_SICK_IDLE_60: + reason = REASON_DEV_SICK_IDLE_60_STR; + break; + case REASON_DEV_DEAD_IDLE_600: + reason = REASON_DEV_DEAD_IDLE_600_STR; + break; + case REASON_DEV_NOSTART: + reason = REASON_DEV_NOSTART_STR; + break; + case REASON_DEV_OVER_HEAT: + reason = REASON_DEV_OVER_HEAT_STR; + break; + case REASON_DEV_THERMAL_CUTOFF: + reason = REASON_DEV_THERMAL_CUTOFF_STR; + break; + case REASON_DEV_COMMS_ERROR: + reason = REASON_DEV_COMMS_ERROR_STR; + break; + default: + reason = REASON_UNKNOWN_STR; + break; + } + + // ALL counters (and only counters) must start the name with a '*' + // Simplifies future external support for identifying new counters + root = api_add_int(root, "NOTIFY", &device, false); + root = api_add_string(root, "Name", cgpu->drv->name, false); + root = api_add_int(root, "ID", &(cgpu->device_id), false); + root = api_add_time(root, "Last Well", &(cgpu->device_last_well), false); + root = api_add_time(root, "Last Not Well", &(cgpu->device_last_not_well), false); + root = api_add_string(root, "Reason Not Well", reason, false); + root = api_add_int(root, "*Thread Fail Init", &(cgpu->thread_fail_init_count), false); + root = api_add_int(root, "*Thread Zero Hash", &(cgpu->thread_zero_hash_count), false); + root = api_add_int(root, "*Thread Fail Queue", &(cgpu->thread_fail_queue_count), false); + root = api_add_int(root, "*Dev Sick Idle 60s", &(cgpu->dev_sick_idle_60_count), false); + root = api_add_int(root, "*Dev Dead Idle 600s", &(cgpu->dev_dead_idle_600_count), false); + root = api_add_int(root, "*Dev Nostart", &(cgpu->dev_nostart_count), false); + root = api_add_int(root, "*Dev Over Heat", &(cgpu->dev_over_heat_count), false); + root = api_add_int(root, "*Dev Thermal Cutoff", &(cgpu->dev_thermal_cutoff_count), false); + root = api_add_int(root, "*Dev Comms Error", &(cgpu->dev_comms_error_count), false); + root = api_add_int(root, "*Dev Throttle", &(cgpu->dev_throttle_count), false); + + root = print_data(io_data, root, isjson, isjson && (device > 0)); +} + +static void notify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, char group) +{ + struct cgpu_info *cgpu; + bool io_open = false; + int i; + + if (total_devices == 0) + { + message(io_data, MSG_NODEVS, 0, NULL, isjson); + return; + } + + message(io_data, MSG_NOTIFY, 0, NULL, isjson); + + if (isjson) + io_open = io_add(io_data, COMSTR JSON_NOTIFY); + + for (i = 0; i < total_devices; i++) + { + cgpu = get_devices(i); + notifystatus(io_data, i, cgpu, isjson, group); + } + + if (isjson && io_open) + io_close(io_data); +} + +static void devdetails(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + bool io_open = false; + struct cgpu_info *cgpu; + int i; + + if (total_devices == 0) + { + message(io_data, MSG_NODEVS, 0, NULL, isjson); + return; + } + + message(io_data, MSG_DEVDETAILS, 0, NULL, isjson); + + if (isjson) + io_open = io_add(io_data, COMSTR JSON_DEVDETAILS); + + for (i = 0; i < total_devices; i++) + { + cgpu = get_devices(i); + + root = api_add_int(root, "DEVDETAILS", &i, false); + root = api_add_string(root, "Name", cgpu->drv->name, false); + root = api_add_int(root, "ID", &(cgpu->device_id), false); + root = api_add_string(root, "Driver", cgpu->drv->dname, false); + root = api_add_const(root, "Kernel", cgpu->kname ? : BLANK, false); + root = api_add_const(root, "Model", cgpu->name ? : BLANK, false); + root = api_add_const(root, "Device Path", cgpu->device_path ? : BLANK, false); + + root = print_data(io_data, root, isjson, isjson && (i > 0)); + } + + if (isjson && io_open) + io_close(io_data); +} + +void dosave(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + char filename[PATH_MAX]; + FILE *fcfg; + char *ptr; + + if (param == NULL || *param == '\0') + { + default_save_file(filename); + param = filename; + } + + fcfg = fopen(param, "w"); + if (!fcfg) + { + ptr = escape_string(param, isjson); + message(io_data, MSG_BADFN, 0, ptr, isjson); + if (ptr != param) + free(ptr); + ptr = NULL; + return; + } + + write_config(fcfg); + fclose(fcfg); + + ptr = escape_string(param, isjson); + message(io_data, MSG_SAVED, 0, ptr, isjson); + if (ptr != param) + free(ptr); + ptr = NULL; +} + +static int itemstats(struct io_data *io_data, int i, char *id, struct cgminer_stats *stats, struct cgminer_pool_stats *pool_stats, struct api_data *extra, struct cgpu_info *cgpu, bool isjson) +{ + struct api_data *root = NULL; + double ghs; + + + ghs = getAVGhashrate(); + + root = api_add_int(root, "STATS", &i, false); + root = api_add_string(root, "ID", id, false); + root = api_add_elapsed(root, "Elapsed", &(total_secs), false); + root = api_add_uint32(root, "Calls", &(stats->getwork_calls), false); + root = api_add_timeval(root, "Wait", &(stats->getwork_wait), false); + root = api_add_timeval(root, "Max", &(stats->getwork_wait_max), false); + root = api_add_timeval(root, "Min", &(stats->getwork_wait_min), false); + root = api_add_string(root, "GHS 5s", displayed_hash_rate, false); + + root = api_add_mhs(root, "GHS av", &(ghs), false); + + /* + if (pool_stats) { + root = api_add_uint32(root, "Pool Calls", &(pool_stats->getwork_calls), false); + root = api_add_uint32(root, "Pool Attempts", &(pool_stats->getwork_attempts), false); + root = api_add_timeval(root, "Pool Wait", &(pool_stats->getwork_wait), false); + root = api_add_timeval(root, "Pool Max", &(pool_stats->getwork_wait_max), false); + root = api_add_timeval(root, "Pool Min", &(pool_stats->getwork_wait_min), false); + root = api_add_double(root, "Pool Av", &(pool_stats->getwork_wait_rolling), false); + root = api_add_bool(root, "Work Had Roll Time", &(pool_stats->hadrolltime), false); + root = api_add_bool(root, "Work Can Roll", &(pool_stats->canroll), false); + root = api_add_bool(root, "Work Had Expire", &(pool_stats->hadexpire), false); + root = api_add_uint32(root, "Work Roll Time", &(pool_stats->rolltime), false); + root = api_add_diff(root, "Work Diff", &(pool_stats->last_diff), false); + root = api_add_diff(root, "Min Diff", &(pool_stats->min_diff), false); + root = api_add_diff(root, "Max Diff", &(pool_stats->max_diff), false); + root = api_add_uint32(root, "Min Diff Count", &(pool_stats->min_diff_count), false); + root = api_add_uint32(root, "Max Diff Count", &(pool_stats->max_diff_count), false); + root = api_add_uint64(root, "Times Sent", &(pool_stats->times_sent), false); + root = api_add_uint64(root, "Bytes Sent", &(pool_stats->bytes_sent), false); + root = api_add_uint64(root, "Times Recv", &(pool_stats->times_received), false); + root = api_add_uint64(root, "Bytes Recv", &(pool_stats->bytes_received), false); + root = api_add_uint64(root, "Net Bytes Sent", &(pool_stats->net_bytes_sent), false); + root = api_add_uint64(root, "Net Bytes Recv", &(pool_stats->net_bytes_received), false); + }*/ + + if (extra) + root = api_add_extra(root, extra); + + if (cgpu) + { +#ifdef USE_USBUTILS + char details[256]; + + if (cgpu->usbinfo.pipe_count) + snprintf(details, sizeof(details), + "%"PRIu64" %"PRIu64"/%"PRIu64"/%"PRIu64" %lu", + cgpu->usbinfo.pipe_count, + cgpu->usbinfo.clear_err_count, + cgpu->usbinfo.retry_err_count, + cgpu->usbinfo.clear_fail_count, + (unsigned long)(cgpu->usbinfo.last_pipe)); + else + strcpy(details, "0"); + + root = api_add_string(root, "USB Pipe", details, true); + + /* + snprintf(details, sizeof(details), + "r%"PRIu64" %.6f w%"PRIu64" %.6f", + cgpu->usbinfo.read_delay_count, + cgpu->usbinfo.total_read_delay, + cgpu->usbinfo.write_delay_count, + cgpu->usbinfo.total_write_delay); + + root = api_add_string(root, "USB Delay", details, true); + + if (cgpu->usbinfo.usb_tmo[0].count == 0 && + cgpu->usbinfo.usb_tmo[1].count == 0 && + cgpu->usbinfo.usb_tmo[2].count == 0) { + snprintf(details, sizeof(details), + "%"PRIu64" 0", cgpu->usbinfo.tmo_count); + } else { + snprintf(details, sizeof(details), + "%"PRIu64" %d=%d/%d/%d/%"PRIu64"/%"PRIu64 + " %d=%d/%d/%d/%"PRIu64"/%"PRIu64 + " %d=%d/%d/%d/%"PRIu64"/%"PRIu64" ", + cgpu->usbinfo.tmo_count, + USB_TMO_0, cgpu->usbinfo.usb_tmo[0].count, + cgpu->usbinfo.usb_tmo[0].min_tmo, + cgpu->usbinfo.usb_tmo[0].max_tmo, + cgpu->usbinfo.usb_tmo[0].total_over, + cgpu->usbinfo.usb_tmo[0].total_tmo, + USB_TMO_1, cgpu->usbinfo.usb_tmo[1].count, + cgpu->usbinfo.usb_tmo[1].min_tmo, + cgpu->usbinfo.usb_tmo[1].max_tmo, + cgpu->usbinfo.usb_tmo[1].total_over, + cgpu->usbinfo.usb_tmo[1].total_tmo, + USB_TMO_2, cgpu->usbinfo.usb_tmo[2].count, + cgpu->usbinfo.usb_tmo[2].min_tmo, + cgpu->usbinfo.usb_tmo[2].max_tmo, + cgpu->usbinfo.usb_tmo[2].total_over, + cgpu->usbinfo.usb_tmo[2].total_tmo); + } + + root = api_add_string(root, "USB tmo", details, true);*/ +#endif + } + + root = print_data(io_data, root, isjson, isjson && (i > 0)); + + return ++i; +} + +static void minerstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct cgpu_info *cgpu; + bool io_open = false; + struct api_data *extra; + char id[20]; + int i, j; + + message(io_data, MSG_MINESTATS, 0, NULL, isjson); + + if (isjson) + io_open = io_add(io_data, COMSTR JSON_MINESTATS); + + i = 0; + for (j = 0; j < total_devices; j++) + { + cgpu = get_devices(j); + + if (cgpu && cgpu->drv) + { + if (cgpu->drv->get_api_stats) + extra = cgpu->drv->get_api_stats(cgpu); + else + extra = NULL; + + sprintf(id, "%s%d", cgpu->drv->name, cgpu->device_id); + i = itemstats(io_data, i, id, &(cgpu->cgminer_stats), NULL, extra, cgpu, isjson); + } + } + + if (isjson && io_open) + io_close(io_data); +} + +static void minerestats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct cgpu_info *cgpu; + bool io_open = false; + struct api_data *extra; + char id[20]; + int i, j; +#ifdef USE_USBUTILS + time_t howoldsec = 0; + + if (param && *param) + howoldsec = (time_t)atoi(param); +#endif + + message(io_data, MSG_MINESTATS, 0, NULL, isjson); + if (isjson) + io_open = io_add(io_data, COMSTR JSON_MINESTATS); + + i = 0; + for (j = 0; j < total_devices; j++) + { + cgpu = get_devices(j); + if (!cgpu) + continue; +#ifdef USE_USBUTILS + if (cgpu->blacklisted) + continue; + if (cgpu->usbinfo.nodev) + { + if (howoldsec <= 0) + continue; + if ((when - cgpu->usbinfo.last_nodev.tv_sec) >= howoldsec) + continue; + } +#endif + if (cgpu->drv) + { + if (cgpu->drv->get_api_stats) + extra = cgpu->drv->get_api_stats(cgpu); + else + extra = NULL; + + sprintf(id, "%s%d", cgpu->drv->name, cgpu->device_id); + i = itemstats(io_data, i, id, &(cgpu->cgminer_stats), NULL, extra, cgpu, isjson); + } + } + + if (isjson && io_open) + io_close(io_data); +} + +static void failoveronly(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + message(io_data, MSG_DEPRECATED, 0, param, isjson); + + + + + +} + +static void minecoin(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + bool io_open; + + message(io_data, MSG_MINECOIN, 0, NULL, isjson); + io_open = io_add(io_data, isjson ? COMSTR JSON_MINECOIN : _MINECOIN COMSTR); + + root = api_add_const(root, "Hash Method", SHA256STR, false); + + cg_rlock(&ch_lock); + root = api_add_timeval(root, "Current Block Time", &block_timeval, true); + root = api_add_string(root, "Current Block Hash", current_hash, true); + cg_runlock(&ch_lock); + + root = api_add_bool(root, "LP", &have_longpoll, false); + root = api_add_diff(root, "Network Difficulty", ¤t_diff, true); + + root = print_data(io_data, root, isjson, false); + if (isjson && io_open) + io_close(io_data); +} + +static void debugstate(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + bool io_open; + + if (param == NULL) + param = (char *)BLANK; + else + *param = tolower(*param); + + switch(*param) + { + case 's': + opt_realquiet = true; + break; + case 'q': + opt_quiet ^= true; + break; + case 'v': + opt_log_output ^= true; + if (opt_log_output) + opt_quiet = false; + break; + case 'd': + opt_debug ^= true; + opt_log_output = opt_debug; + if (opt_debug) + opt_quiet = false; + break; + case 'r': + opt_protocol ^= true; + if (opt_protocol) + opt_quiet = false; + break; + case 'p': + want_per_device_stats ^= true; + opt_log_output = want_per_device_stats; + break; + case 'n': + opt_log_output = false; + opt_debug = false; + opt_quiet = false; + opt_protocol = false; + want_per_device_stats = false; + opt_worktime = false; + break; + case 'w': + opt_worktime ^= true; + break; +#ifdef _MEMORY_DEBUG + case 'y': + cgmemspeedup(); + break; + case 'z': + cgmemrpt(); + break; +#endif + default: + // anything else just reports the settings + break; + } + + message(io_data, MSG_DEBUGSET, 0, NULL, isjson); + io_open = io_add(io_data, isjson ? COMSTR JSON_DEBUGSET : _DEBUGSET COMSTR); + + root = api_add_bool(root, "Silent", &opt_realquiet, false); + root = api_add_bool(root, "Quiet", &opt_quiet, false); + root = api_add_bool(root, "Verbose", &opt_log_output, false); + root = api_add_bool(root, "Debug", &opt_debug, false); + root = api_add_bool(root, "RPCProto", &opt_protocol, false); + root = api_add_bool(root, "PerDevice", &want_per_device_stats, false); + root = api_add_bool(root, "WorkTime", &opt_worktime, false); + + root = print_data(io_data, root, isjson, false); + if (isjson && io_open) + io_close(io_data); +} + +static void setconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + if (!strcasecmp(param, "queue") || ! strcasecmp(param, "scantime") || !strcasecmp(param, "expiry")) + + message(io_data, MSG_DEPRECATED, 0, param, isjson); + + + message(io_data, MSG_UNKCON, 0, param, isjson); + +} + +static void usbstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + +#ifdef USE_USBUTILS + bool io_open = false; + int count = 0; + + root = api_usb_stats(&count); +#endif + + if (!root) + { + message(io_data, MSG_NOUSTA, 0, NULL, isjson); + return; + } + +#ifdef USE_USBUTILS + message(io_data, MSG_USBSTA, 0, NULL, isjson); + + if (isjson) + io_open = io_add(io_data, COMSTR JSON_USBSTATS); + + root = print_data(io_data, root, isjson, false); + + while (42) + { + root = api_usb_stats(&count); + if (!root) + break; + + root = print_data(io_data, root, isjson, isjson); + } + + if (isjson && io_open) + io_close(io_data); +#endif +} + +#ifdef HAVE_AN_FPGA +static void pgaset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct cgpu_info *cgpu; + struct device_drv *drv; + char buf[TMPBUFSIZ]; + int numpga = numpgas(); + + if (numpga == 0) + { + message(io_data, MSG_PGANON, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISID, 0, NULL, isjson); + return; + } + + char *opt = strchr(param, ','); + if (opt) + *(opt++) = '\0'; + if (!opt || !*opt) + { + message(io_data, MSG_MISPGAOPT, 0, NULL, isjson); + return; + } + + int id = atoi(param); + if (id < 0 || id >= numpga) + { + message(io_data, MSG_INVPGA, id, NULL, isjson); + return; + } + + int dev = pgadevice(id); + if (dev < 0) // Should never happen + { + message(io_data, MSG_INVPGA, id, NULL, isjson); + return; + } + + cgpu = get_devices(dev); + drv = cgpu->drv; + + char *set = strchr(opt, ','); + if (set) + *(set++) = '\0'; + + if (!drv->set_device) + message(io_data, MSG_PGANOSET, id, NULL, isjson); + else + { + char *ret = drv->set_device(cgpu, opt, set, buf); + if (ret) + { + if (strcasecmp(opt, "help") == 0) + message(io_data, MSG_PGAHELP, id, ret, isjson); + else + message(io_data, MSG_PGASETERR, id, ret, isjson); + } + else + message(io_data, MSG_PGASETOK, id, NULL, isjson); + } +} +#endif + +static void dozero(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + if (param == NULL || *param == '\0') + { + message(io_data, MSG_ZERMIS, 0, NULL, isjson); + return; + } + + char *sum = strchr(param, ','); + if (sum) + *(sum++) = '\0'; + if (!sum || !*sum) + { + message(io_data, MSG_MISBOOL, 0, NULL, isjson); + return; + } + + bool all = false; + bool bs = false; + if (strcasecmp(param, "all") == 0) + all = true; + else if (strcasecmp(param, "bestshare") == 0) + bs = true; + + if (all == false && bs == false) + { + message(io_data, MSG_ZERINV, 0, param, isjson); + return; + } + + *sum = tolower(*sum); + if (*sum != 't' && *sum != 'f') + { + message(io_data, MSG_INVBOOL, 0, NULL, isjson); + return; + } + + bool dosum = (*sum == 't'); + if (dosum) + print_summary(); + + if (all) + zero_stats(); + if (bs) + zero_bestshare(); + + if (dosum) + message(io_data, MSG_ZERSUM, 0, all ? "All" : "BestShare", isjson); + else + message(io_data, MSG_ZERNOSUM, 0, all ? "All" : "BestShare", isjson); +} + +static void dohotplug(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ +#ifdef USE_USBUTILS + int value; + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISHPLG, 0, NULL, isjson); + return; + } + + value = atoi(param); + if (value < 0 || value > 9999) + { + message(io_data, MSG_INVHPLG, 0, param, isjson); + return; + } + + hotplug_time = value; + + if (value) + message(io_data, MSG_HOTPLUG, value, NULL, isjson); + else + message(io_data, MSG_DISHPLG, 0, NULL, isjson); +#else + message(io_data, MSG_NOHPLG, 0, NULL, isjson); + return; +#endif +} + +#ifdef HAVE_AN_ASIC +static void ascdev(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + bool io_open = false; + int numasc = numascs(); + int id; + + if (numasc == 0) + { + message(io_data, MSG_ASCNON, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISID, 0, NULL, isjson); + return; + } + + id = atoi(param); + if (id < 0 || id >= numasc) + { + message(io_data, MSG_INVASC, id, NULL, isjson); + return; + } + + message(io_data, MSG_ASCDEV, id, NULL, isjson); + + if (isjson) + io_open = io_add(io_data, COMSTR JSON_ASC); + + ascstatus(io_data, id, isjson, false); + + if (isjson && io_open) + io_close(io_data); +} + +static void ascenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct cgpu_info *cgpu; + int numasc = numascs(); + struct thr_info *thr; + int asc; + int id; + int i; + + if (numasc == 0) + { + message(io_data, MSG_ASCNON, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISID, 0, NULL, isjson); + return; + } + + id = atoi(param); + if (id < 0 || id >= numasc) + { + message(io_data, MSG_INVASC, id, NULL, isjson); + return; + } + + int dev = ascdevice(id); + if (dev < 0) // Should never happen + { + message(io_data, MSG_INVASC, id, NULL, isjson); + return; + } + + cgpu = get_devices(dev); + + applog(LOG_DEBUG, "API: request to ascenable ascid %d device %d %s%u", + id, dev, cgpu->drv->name, cgpu->device_id); + + if (cgpu->deven != DEV_DISABLED) + { + message(io_data, MSG_ASCLRENA, id, NULL, isjson); + return; + } + +#if 0 /* A DISABLED device wont change status FIXME: should disabling make it WELL? */ + if (cgpu->status != LIFE_WELL) + { + message(io_data, MSG_ASCUNW, id, NULL, isjson); + return; + } +#endif + +#ifdef USE_USBUTILS + if (cgpu->usbinfo.nodev) + { + message(io_data, MSG_ASCUSBNODEV, id, NULL, isjson); + return; + } +#endif + + for (i = 0; i < mining_threads; i++) + { + thr = get_thread(i); + asc = thr->cgpu->cgminer_id; + if (asc == dev) + { + cgpu->deven = DEV_ENABLED; + applog(LOG_DEBUG, "API: Pushing sem post to thread %d", thr->id); + cgsem_post(&thr->sem); + } + } + + message(io_data, MSG_ASCENA, id, NULL, isjson); +} + +static void ascdisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct cgpu_info *cgpu; + int numasc = numascs(); + int id; + + if (numasc == 0) + { + message(io_data, MSG_ASCNON, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISID, 0, NULL, isjson); + return; + } + + id = atoi(param); + if (id < 0 || id >= numasc) + { + message(io_data, MSG_INVASC, id, NULL, isjson); + return; + } + + int dev = ascdevice(id); + if (dev < 0) // Should never happen + { + message(io_data, MSG_INVASC, id, NULL, isjson); + return; + } + + cgpu = get_devices(dev); + + applog(LOG_DEBUG, "API: request to ascdisable ascid %d device %d %s%u", + id, dev, cgpu->drv->name, cgpu->device_id); + + if (cgpu->deven == DEV_DISABLED) + { + message(io_data, MSG_ASCLRDIS, id, NULL, isjson); + return; + } + + cgpu->deven = DEV_DISABLED; + + message(io_data, MSG_ASCDIS, id, NULL, isjson); +} + +static void ascidentify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct cgpu_info *cgpu; + struct device_drv *drv; + int numasc = numascs(); + int id; + + if (numasc == 0) + { + message(io_data, MSG_ASCNON, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISID, 0, NULL, isjson); + return; + } + + id = atoi(param); + if (id < 0 || id >= numasc) + { + message(io_data, MSG_INVASC, id, NULL, isjson); + return; + } + + int dev = ascdevice(id); + if (dev < 0) // Should never happen + { + message(io_data, MSG_INVASC, id, NULL, isjson); + return; + } + + cgpu = get_devices(dev); + drv = cgpu->drv; + + if (!drv->identify_device) + message(io_data, MSG_ASCNOID, id, NULL, isjson); + else + { + drv->identify_device(cgpu); + message(io_data, MSG_ASCIDENT, id, NULL, isjson); + } +} +#endif + +static void asccount(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + bool io_open; + int count = 0; + +#ifdef HAVE_AN_ASIC + count = numascs(); +#endif + + message(io_data, MSG_NUMASC, 0, NULL, isjson); + io_open = io_add(io_data, isjson ? COMSTR JSON_ASCS : _ASCS COMSTR); + + root = api_add_int(root, "Count", &count, false); + + root = print_data(io_data, root, isjson, false); + if (isjson && io_open) + io_close(io_data); +} + +#ifdef HAVE_AN_ASIC +static void ascset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct cgpu_info *cgpu; + struct device_drv *drv; + char buf[TMPBUFSIZ]; + int numasc = numascs(); + + if (numasc == 0) + { + message(io_data, MSG_ASCNON, 0, NULL, isjson); + return; + } + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISID, 0, NULL, isjson); + return; + } + + char *opt = strchr(param, ','); + if (opt) + *(opt++) = '\0'; + if (!opt || !*opt) + { + message(io_data, MSG_MISASCOPT, 0, NULL, isjson); + return; + } + + int id = atoi(param); + if (id < 0 || id >= numasc) + { + message(io_data, MSG_INVASC, id, NULL, isjson); + return; + } + + int dev = ascdevice(id); + if (dev < 0) // Should never happen + { + message(io_data, MSG_INVASC, id, NULL, isjson); + return; + } + + cgpu = get_devices(dev); + drv = cgpu->drv; + + char *set = strchr(opt, ','); + if (set) + *(set++) = '\0'; + + if (!drv->set_device) + message(io_data, MSG_ASCNOSET, id, NULL, isjson); + else + { + char *ret = drv->set_device(cgpu, opt, set, buf); + if (ret) + { + if (strcasecmp(opt, "help") == 0) + message(io_data, MSG_ASCHELP, id, ret, isjson); + else + message(io_data, MSG_ASCSETERR, id, ret, isjson); + } + else + message(io_data, MSG_ASCSETOK, id, NULL, isjson); + } +} +#endif + +static void lcddata(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + struct cgpu_info *cgpu; + bool io_open; + double ghs = 0.0, last_share_diff = 0.0; + float temp = 0.0; + time_t last_share_time = 0; + time_t last_device_valid_work = 0; + struct pool *pool = NULL; + char *rpc_url = "none", *rpc_user = ""; + int i; + + message(io_data, MSG_LCD, 0, NULL, isjson); + io_open = io_add(io_data, isjson ? COMSTR JSON_LCD : _LCD COMSTR); + + // stop hashmeter() changing some while copying + mutex_lock(&hash_lock); + + root = api_add_elapsed(root, "Elapsed", &(total_secs), true); + + ghs = getAVGhashrate(); + + root = api_add_mhs(root, "GHS av", &ghs, true); + ghs = rolling5 / 1000.0; + root = api_add_mhs(root, "GHS 5m", &ghs, true); + ghs = total_rolling / 1000.0; + root = api_add_mhs(root, "GHS 5s", &ghs, true); + + mutex_unlock(&hash_lock); + + temp = 0; + last_device_valid_work = 0; + for (i = 0; i < total_devices; i++) + { + cgpu = get_devices(i); + if (last_device_valid_work == 0 || + last_device_valid_work < cgpu->last_device_valid_work) + last_device_valid_work = cgpu->last_device_valid_work; + if (temp < cgpu->temp) + temp = cgpu->temp; + } + + last_share_time = 0; + last_share_diff = 0; + for (i = 0; i < total_pools; i++) + { + pool = pools[i]; + + if (pool->removed) + continue; + + if (last_share_time == 0 || last_share_time < pool->last_share_time) + { + last_share_time = pool->last_share_time; + last_share_diff = pool->last_share_diff; + } + } + pool = current_pool(); + if (pool) + { + rpc_url = pool->rpc_url; + rpc_user = pool->rpc_user; + } + + root = api_add_temp(root, "Temperature", &temp, false); + root = api_add_diff(root, "Last Share Difficulty", &last_share_diff, false); + root = api_add_time(root, "Last Share Time", &last_share_time, false); + root = api_add_uint64(root, "Best Share", &best_diff, true); + root = api_add_time(root, "Last Valid Work", &last_device_valid_work, false); + root = api_add_uint(root, "Found Blocks", &found_blocks, true); + root = api_add_escape(root, "Current Pool", rpc_url, true); + root = api_add_escape(root, "User", rpc_user, true); + root = print_data(io_data, root, isjson, false); + if (isjson && io_open) + io_close(io_data); +} + +static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group); + +struct CMDS +{ + char *name; + void (*func)(struct io_data *, SOCKETTYPE, char *, bool, char); + bool iswritemode; + bool joinable; +} cmds[] = +{ + { "version", apiversion, false, true }, + { "config", minerconfig, false, true }, + { "devs", devstatus, false, true }, + { "edevs", edevstatus, false, true }, + { "pools", poolstatus, false, true }, + { "summary", summary, false, true }, + { "noncenum", noncenum, false, true }, +#ifdef HAVE_AN_FPGA + { "pga", pgadev, false, false }, + { "pgaenable", pgaenable, true, false }, + { "pgadisable", pgadisable, true, false }, + { "pgaidentify", pgaidentify, true, false }, +#endif + { "pgacount", pgacount, false, true }, + { "switchpool", switchpool, true, false }, + { "addpool", addpool, true, false }, + { "poolpriority", poolpriority, true, false }, + { "poolquota", poolquota, true, false }, + { "enablepool", enablepool, true, false }, + { "disablepool", disablepool, true, false }, + { "removepool", removepool, true, false }, + { "save", dosave, true, false }, + { "quit", doquit, true, false }, + { "privileged", privileged, true, false }, + { "notify", notify, false, true }, + { "devdetails", devdetails, false, true }, + { "restart", dorestart, true, false }, + { "stats", minerstats, false, true }, + { "estats", minerestats, false, true }, + { "check", checkcommand, false, false }, + { "failover-only", failoveronly, true, false }, + { "coin", minecoin, false, true }, + { "debug", debugstate, true, false }, + { "setconfig", setconfig, true, false }, + { "usbstats", usbstats, false, true }, +#ifdef HAVE_AN_FPGA + { "pgaset", pgaset, true, false }, +#endif + { "zero", dozero, true, false }, + { "hotplug", dohotplug, true, false }, +#ifdef HAVE_AN_ASIC + { "asc", ascdev, false, false }, + { "ascenable", ascenable, true, false }, + { "ascdisable", ascdisable, true, false }, + { "ascidentify", ascidentify, true, false }, + { "ascset", ascset, true, false }, +#endif + { "asccount", asccount, false, true }, + { "lcd", lcddisplay, false, true }, + { "lockstats", lockstats, true, true }, + { NULL, NULL, false, false } +}; + +static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group) +{ + struct api_data *root = NULL; + bool io_open; + char cmdbuf[100]; + bool found, access; + int i; + + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISCHK, 0, NULL, isjson); + return; + } + + found = false; + access = false; + for (i = 0; cmds[i].name != NULL; i++) + { + if (strcmp(cmds[i].name, param) == 0) + { + found = true; + + sprintf(cmdbuf, "|%s|", param); + if (ISPRIVGROUP(group) || strstr(COMMANDS(group), cmdbuf)) + access = true; + + break; + } + } + + message(io_data, MSG_CHECK, 0, NULL, isjson); + io_open = io_add(io_data, isjson ? COMSTR JSON_CHECK : _CHECK COMSTR); + + root = api_add_const(root, "Exists", found ? YES : NO, false); + root = api_add_const(root, "Access", access ? YES : NO, false); + + root = print_data(io_data, root, isjson, false); + if (isjson && io_open) + io_close(io_data); +} + +static void head_join(struct io_data *io_data, char *cmdptr, bool isjson, bool *firstjoin) +{ + char *ptr; + + if (*firstjoin) + { + if (isjson) + io_add(io_data, JSON0); + *firstjoin = false; + } + else + { + if (isjson) + io_add(io_data, JSON_BETWEEN_JOIN); + } + + // External supplied string + ptr = escape_string(cmdptr, isjson); + + if (isjson) + { + io_add(io_data, JSON1); + io_add(io_data, ptr); + io_add(io_data, JSON2); + } + else + { + io_add(io_data, JOIN_CMD); + io_add(io_data, ptr); + io_add(io_data, BETWEEN_JOIN); + } + + if (ptr != cmdptr) + free(ptr); +} + +static void tail_join(struct io_data *io_data, bool isjson) +{ + if (io_data->close) + { + io_add(io_data, JSON_CLOSE); + io_data->close = false; + } + + if (isjson) + { + io_add(io_data, JSON_END); + io_add(io_data, JSON3); + } +} + +static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson) +{ + int count, sendc, res, tosend, len, n; + char *buf = io_data->ptr; + + strcpy(buf, io_data->ptr); + + if (io_data->close) + strcat(buf, JSON_CLOSE); + + if (isjson) + strcat(buf, JSON_END); + + len = strlen(buf); + tosend = len+1; + + applog(LOG_DEBUG, "API: send reply: (%d) '%.10s%s'", tosend, buf, len > 10 ? "..." : BLANK); + + count = sendc = 0; + while (count < 5 && tosend > 0) + { + // allow 50ms per attempt + struct timeval timeout = {0, 50000}; + fd_set wd; + + FD_ZERO(&wd); + FD_SET(c, &wd); + if ((res = select(c + 1, NULL, &wd, NULL, &timeout)) < 1) + { + applog(LOG_WARNING, "API: send select failed (%d)", res); + return; + } + + n = send(c, buf, tosend, 0); + sendc++; + + if (SOCKETFAIL(n)) + { + count++; + if (sock_blocks()) + continue; + + applog(LOG_WARNING, "API: send (%d:%d) failed: %s", len+1, (len+1 - tosend), SOCKERRMSG); + + return; + } + else + { + if (sendc <= 1) + { + if (n == tosend) + applog(LOG_DEBUG, "API: sent all of %d first go", tosend); + else + applog(LOG_DEBUG, "API: sent %d of %d first go", n, tosend); + } + else + { + if (n == tosend) + applog(LOG_DEBUG, "API: sent all of remaining %d (sendc=%d)", tosend, sendc); + else + applog(LOG_DEBUG, "API: sent %d of remaining %d (sendc=%d)", n, tosend, sendc); + } + + tosend -= n; + buf += n; + + if (n == 0) + count++; + } + } +} + +static void tidyup(__maybe_unused void *arg) +{ + mutex_lock(&quit_restart_lock); + + SOCKETTYPE *apisock = (SOCKETTYPE *)arg; + + bye = true; + + if (*apisock != INVSOCK) + { + shutdown(*apisock, SHUT_RDWR); + CLOSESOCKET(*apisock); + *apisock = INVSOCK; + } + + if (ipaccess != NULL) + { + free(ipaccess); + ipaccess = NULL; + } + + io_free(); + + mutex_unlock(&quit_restart_lock); +} + +/* + * Interpret --api-groups G:cmd1:cmd2:cmd3,P:cmd4,*,... + */ +static void setup_groups() +{ + char *api_groups = opt_api_groups ? opt_api_groups : (char *)BLANK; + char *buf, *ptr, *next, *colon; + char group; + char commands[TMPBUFSIZ]; + char cmdbuf[100]; + char *cmd; + bool addstar, did; + int i; + + buf = cgmalloc(strlen(api_groups) + 1); + + strcpy(buf, api_groups); + + next = buf; + // for each group defined + while (next && *next) + { + ptr = next; + next = strchr(ptr, ','); + if (next) + *(next++) = '\0'; + + // Validate the group + if (*(ptr+1) != ':') + { + colon = strchr(ptr, ':'); + if (colon) + *colon = '\0'; + quit(1, "API invalid group name '%s'", ptr); + } + + group = GROUP(*ptr); + if (!VALIDGROUP(group)) + quit(1, "API invalid group name '%c'", *ptr); + + if (group == PRIVGROUP) + quit(1, "API group name can't be '%c'", PRIVGROUP); + + if (group == NOPRIVGROUP) + quit(1, "API group name can't be '%c'", NOPRIVGROUP); + + if (apigroups[GROUPOFFSET(group)].commands != NULL) + quit(1, "API duplicate group name '%c'", *ptr); + + ptr += 2; + + // Validate the command list (and handle '*') + cmd = &(commands[0]); + *(cmd++) = SEPARATOR; + *cmd = '\0'; + addstar = false; + while (ptr && *ptr) + { + colon = strchr(ptr, ':'); + if (colon) + *(colon++) = '\0'; + + if (strcmp(ptr, "*") == 0) + addstar = true; + else + { + did = false; + for (i = 0; cmds[i].name != NULL; i++) + { + if (strcasecmp(ptr, cmds[i].name) == 0) + { + did = true; + break; + } + } + if (did) + { + // skip duplicates + sprintf(cmdbuf, "|%s|", cmds[i].name); + if (strstr(commands, cmdbuf) == NULL) + { + strcpy(cmd, cmds[i].name); + cmd += strlen(cmds[i].name); + *(cmd++) = SEPARATOR; + *cmd = '\0'; + } + } + else + { + quit(1, "API unknown command '%s' in group '%c'", ptr, group); + } + } + + ptr = colon; + } + + // * = allow all non-iswritemode commands + if (addstar) + { + for (i = 0; cmds[i].name != NULL; i++) + { + if (cmds[i].iswritemode == false) + { + // skip duplicates + sprintf(cmdbuf, "|%s|", cmds[i].name); + if (strstr(commands, cmdbuf) == NULL) + { + strcpy(cmd, cmds[i].name); + cmd += strlen(cmds[i].name); + *(cmd++) = SEPARATOR; + *cmd = '\0'; + } + } + } + } + + ptr = apigroups[GROUPOFFSET(group)].commands = cgmalloc(strlen(commands) + 1); + + strcpy(ptr, commands); + } + + // Now define R (NOPRIVGROUP) as all non-iswritemode commands + cmd = &(commands[0]); + *(cmd++) = SEPARATOR; + *cmd = '\0'; + for (i = 0; cmds[i].name != NULL; i++) + { + if (cmds[i].iswritemode == false) + { + strcpy(cmd, cmds[i].name); + cmd += strlen(cmds[i].name); + *(cmd++) = SEPARATOR; + *cmd = '\0'; + } + } + + ptr = apigroups[GROUPOFFSET(NOPRIVGROUP)].commands = cgmalloc(strlen(commands) + 1); + + strcpy(ptr, commands); + + // W (PRIVGROUP) is handled as a special case since it simply means all commands + + free(buf); + return; +} + +/* + * Interpret [W:]IP[/Prefix][,[R|W:]IP2[/Prefix2][,...]] --api-allow option + * ipv6 address should be enclosed with a pair of square brackets and the prefix left outside + * special case of 0/0 allows /0 (means all IP addresses) + */ +#define ALLIP "0/0" +/* + * N.B. IP4 addresses are by Definition 32bit big endian on all platforms + */ +static void setup_ipaccess() +{ + char *buf, *ptr, *comma, *slash, *end, *dot; + int ipcount, mask, i, shift; + char tmp[64], original[64]; + bool ipv6 = false; + char group; + + buf = cgmalloc(strlen(opt_api_allow) + 1); + + strcpy(buf, opt_api_allow); + + ipcount = 1; + ptr = buf; + while (*ptr) + if (*(ptr++) == ',') + ipcount++; + + // possibly more than needed, but never less + ipaccess = cgcalloc(ipcount, sizeof(struct IPACCESS)); + + ips = 0; + ptr = buf; + while (ptr && *ptr) + { + while (*ptr == ' ' || *ptr == '\t') + ptr++; + + if (*ptr == ',') + { + ptr++; + continue; + } + + comma = strchr(ptr, ','); + if (comma) + *(comma++) = '\0'; + + strncpy(original, ptr, sizeof(original)); + original[sizeof(original)-1] = '\0'; + group = NOPRIVGROUP; + + if (isalpha(*ptr) && *(ptr+1) == ':') + { + if (DEFINEDGROUP(*ptr)) + group = GROUP(*ptr); + + ptr += 2; + } + + ipaccess[ips].group = group; + + if (strcmp(ptr, ALLIP) == 0) + { + for (i = 0; i < 16; i++) + { + ipaccess[ips].ip.s6_addr[i] = 0; + ipaccess[ips].mask.s6_addr[i] = 0; + } + } + else + { + end = strchr(ptr, '/'); + if (!end) + { + for (i = 0; i < 16; i++) + ipaccess[ips].mask.s6_addr[i] = 0xff; + end = ptr + strlen(ptr); + } + slash = end--; + if (*ptr == '[' && *end == ']') + { + *(ptr++) = '\0'; + *(end--) = '\0'; + ipv6 = true; + } + else + ipv6 = false; + if (*slash) + { + *(slash++) = '\0'; + mask = atoi(slash); + if (mask < 1 || (mask += ipv6 ? 0 : 96) > 128 ) + { + applog(LOG_ERR, "API: ignored address with " + "invalid mask (%d) '%s'", + mask, original); + goto popipo; // skip invalid/zero + } + + for (i = 0; i < 16; i++) + ipaccess[ips].mask.s6_addr[i] = 0; + + i = 0; + shift = 7; + while (mask-- > 0) + { + ipaccess[ips].mask.s6_addr[i] |= 1 << shift; + if (shift-- == 0) + { + i++; + shift = 7; + } + } + } + + for (i = 0; i < 16; i++) + ipaccess[ips].ip.s6_addr[i] = 0; // missing default to '[::]' + if (ipv6) + { + if (INET_PTON(AF_INET6, ptr, &(ipaccess[ips].ip)) != 1) + { + applog(LOG_ERR, "API: ignored invalid " + "IPv6 address '%s'", + original); + goto popipo; + } + } + else + { + // v4 mapped v6 address, such as "::ffff:255.255.255.255" + dot = strchr(ptr, '.'); + if (!dot) + { + snprintf(tmp, sizeof(tmp), + "::ffff:%s.0.0.0", + ptr); + } + else + { + dot = strchr(dot+1, '.'); + if (!dot) + { + snprintf(tmp, sizeof(tmp), + "::ffff:%s.0.0", + ptr); + } + else + { + dot = strchr(dot+1, '.'); + if (!dot) + { + snprintf(tmp, sizeof(tmp), + "::ffff:%s.0", + ptr); + } + else + { + snprintf(tmp, sizeof(tmp), + "::ffff:%s", + ptr); + } + } + } + if (INET_PTON(AF_INET6, tmp, &(ipaccess[ips].ip)) != 1) + { + applog(LOG_ERR, "API: ignored invalid " + "IPv4 address '%s' (as %s)", + original, tmp); + goto popipo; + } + } + for (i = 0; i < 16; i++) + ipaccess[ips].ip.s6_addr[i] &= ipaccess[ips].mask.s6_addr[i]; + } + + ips++; + popipo: + ptr = comma; + } + + free(buf); +} + +static void *quit_thread(__maybe_unused void *userdata) +{ + // allow thread creator to finish whatever it's doing + mutex_lock(&quit_restart_lock); + mutex_unlock(&quit_restart_lock); + + if (opt_debug) + applog(LOG_DEBUG, "API: killing cgminer"); + + kill_work(); + + return NULL; +} + +static void *restart_thread(__maybe_unused void *userdata) +{ + // allow thread creator to finish whatever it's doing + mutex_lock(&quit_restart_lock); + mutex_unlock(&quit_restart_lock); + + if (opt_debug) + applog(LOG_DEBUG, "API: restarting cgminer"); + + app_restart(); + + return NULL; +} + +static bool check_connect(struct sockaddr_storage *cli, char **connectaddr, char *group) +{ + bool addrok = false; + int i, j; + bool match; + char tmp[30]; + struct in6_addr client_ip; + + *connectaddr = cgmalloc(INET6_ADDRSTRLEN); + getnameinfo((struct sockaddr *)cli, sizeof(*cli), + *connectaddr, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); + + // v4 mapped v6 address, such as "::ffff:255.255.255.255" + if (cli->ss_family == AF_INET) + { + sprintf(tmp, "::ffff:%s", *connectaddr); + INET_PTON(AF_INET6, tmp, &client_ip); + } + else + INET_PTON(AF_INET6, *connectaddr, &client_ip); + + *group = NOPRIVGROUP; + if (opt_api_allow) + { + for (i = 0; i < ips; i++) + { + match = true; + for (j = 0; j < 16; j++) + { + if ((client_ip.s6_addr[j] & ipaccess[i].mask.s6_addr[j]) + != ipaccess[i].ip.s6_addr[j]) + { + match = false; + break; + } + } + if (match) + { + addrok = true; + *group = ipaccess[i].group; + break; + } + } + } + else + { + if (opt_api_network) + addrok = true; + else + addrok = (strcmp(*connectaddr, localaddr) == 0) + || IN6_IS_ADDR_LOOPBACK(&client_ip); + } + + return addrok; +} + +static void mcast() +{ + struct sockaddr_storage came_from; + time_t bindstart; + char *binderror; + SOCKETTYPE mcast_sock = INVSOCK; + SOCKETTYPE reply_sock = INVSOCK; + socklen_t came_from_siz; + char *connectaddr; + ssize_t rep; + int bound; + int count; + int reply_port; + bool addrok; + char group; + + char port_s[10], came_from_port[10]; + struct addrinfo hints, *res, *host, *client; + + char expect[] = "cgminer-"; // first 8 bytes constant + char *expect_code; + size_t expect_code_len; + char buf[1024]; + char replybuf[1024]; + + sprintf(port_s, "%d", opt_api_mcast_port); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + if (getaddrinfo(opt_api_mcast_addr, port_s, &hints, &res) != 0) + quit(1, "Invalid API Multicast Address"); + host = res; + while (host != NULL) + { + mcast_sock = socket(res->ai_family, SOCK_DGRAM, 0); + if (mcast_sock > 0) + break; + host = host->ai_next; + } + if (mcast_sock == INVSOCK) + { + freeaddrinfo(res); + quit(1, "API mcast could not open socket"); + } + + int optval = 1; + if (SOCKETFAIL(setsockopt(mcast_sock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval)))) + { + applog(LOG_ERR, "API mcast setsockopt SO_REUSEADDR failed (%s)%s", SOCKERRMSG, MUNAVAILABLE); + goto die; + } + + // try for more than 1 minute ... in case the old one hasn't completely gone yet + bound = 0; + bindstart = time(NULL); + while (bound == 0) + { + if (SOCKETFAIL(bind(mcast_sock, host->ai_addr, host->ai_addrlen))) + { + binderror = SOCKERRMSG; + if ((time(NULL) - bindstart) > 61) + break; + else + cgsleep_ms(30000); + } + else + bound = 1; + } + + if (bound == 0) + { + applog(LOG_ERR, "API mcast bind to port %d failed (%s)%s", opt_api_mcast_port, binderror, MUNAVAILABLE); + goto die; + } + + switch (host->ai_family) + { + case AF_INET: + { + struct ip_mreq grp; + memset(&grp, 0, sizeof(grp)); + grp.imr_multiaddr.s_addr = ((struct sockaddr_in *)(host->ai_addr))->sin_addr.s_addr; + grp.imr_interface.s_addr = INADDR_ANY; + + if (SOCKETFAIL(setsockopt(mcast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (void *)(&grp), sizeof(grp)))) + { + applog(LOG_ERR, "API mcast join failed (%s)%s", SOCKERRMSG, MUNAVAILABLE); + goto die; + } + break; + } + case AF_INET6: + { + struct ipv6_mreq grp; + memcpy(&grp.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)(host->ai_addr))->sin6_addr), + sizeof(struct in6_addr)); + grp.ipv6mr_interface= 0; + + if (SOCKETFAIL(setsockopt(mcast_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, + (void *)(&grp), sizeof(grp)))) + { + applog(LOG_ERR, "API mcast join failed (%s)%s", SOCKERRMSG, MUNAVAILABLE); + goto die; + } + break; + } + default: + break; + } + freeaddrinfo(res); + + expect_code_len = sizeof(expect) + strlen(opt_api_mcast_code); + expect_code = cgmalloc(expect_code_len + 1); + snprintf(expect_code, expect_code_len+1, "%s%s-", expect, opt_api_mcast_code); + + count = 0; + while (80085) + { + cgsleep_ms(1000); + + count++; + came_from_siz = sizeof(came_from); + if (SOCKETFAIL(rep = recvfrom(mcast_sock, buf, sizeof(buf) - 1, + 0, (struct sockaddr *)(&came_from), &came_from_siz))) + { + applog(LOG_DEBUG, "API mcast failed count=%d (%s) (%d)", + count, SOCKERRMSG, (int)mcast_sock); + continue; + } + + addrok = check_connect(&came_from, &connectaddr, &group); + applog(LOG_DEBUG, "API mcast from %s - %s", + connectaddr, addrok ? "Accepted" : "Ignored"); + if (!addrok) + continue; + + buf[rep] = '\0'; + if (rep > 0 && buf[rep-1] == '\n') + buf[--rep] = '\0'; + + getnameinfo((struct sockaddr *)(&came_from), came_from_siz, + NULL, 0, came_from_port, sizeof(came_from_port), NI_NUMERICHOST); + + applog(LOG_DEBUG, "API mcast request rep=%d (%s) from [%s]:%s", + (int)rep, buf, connectaddr, came_from_port); + + if ((size_t)rep > expect_code_len && memcmp(buf, expect_code, expect_code_len) == 0) + { + reply_port = atoi(&buf[expect_code_len]); + if (reply_port < 1 || reply_port > 65535) + { + applog(LOG_DEBUG, "API mcast request ignored - invalid port (%s)", + &buf[expect_code_len]); + } + else + { + applog(LOG_DEBUG, "API mcast request OK port %s=%d", + &buf[expect_code_len], reply_port); + + if (getaddrinfo(connectaddr, &buf[expect_code_len], &hints, &res) != 0) + { + applog(LOG_ERR, "Invalid client address %s", connectaddr); + continue; + } + client = res; + while (client) + { + reply_sock = socket(res->ai_family, SOCK_DGRAM, 0); + if (mcast_sock > 0) + break; + client = client->ai_next; + } + if (reply_sock == INVSOCK) + { + freeaddrinfo(res); + applog(LOG_ERR, "API mcast could not open socket to client %s", connectaddr); + continue; + } + + snprintf(replybuf, sizeof(replybuf), + "cgm-" API_MCAST_CODE "-%d-%s", + opt_api_port, opt_api_mcast_des); + + rep = sendto(reply_sock, replybuf, strlen(replybuf)+1, + 0, client->ai_addr, client->ai_addrlen); + freeaddrinfo(res); + if (SOCKETFAIL(rep)) + { + applog(LOG_DEBUG, "API mcast send reply failed (%s) (%d)", + SOCKERRMSG, (int)reply_sock); + } + else + { + applog(LOG_DEBUG, "API mcast send reply (%s) succeeded (%d) (%d)", + replybuf, (int)rep, (int)reply_sock); + } + + CLOSESOCKET(reply_sock); + } + } + else + applog(LOG_DEBUG, "API mcast request was no good"); + } + +die: + + CLOSESOCKET(mcast_sock); +} + +static void *mcast_thread(void *userdata) +{ + struct thr_info *mythr = userdata; + + pthread_detach(pthread_self()); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + RenameThread("APIMcast"); + + mcast(); + + PTH(mythr) = 0L; + + return NULL; +} + +void mcast_init() +{ + struct thr_info *thr; + + thr = cgcalloc(1, sizeof(*thr)); + + if (thr_info_create(thr, NULL, mcast_thread, thr)) + quit(1, "API mcast thread create failed"); +} + +void reCalculateAVG() +{ + new_total_mhashes_done = total_mhashes_done; + if(total_secs>0) + new_total_secs = total_secs-1; + else new_total_secs=total_secs; +} + +void api(int api_thr_id) +{ + struct io_data *io_data; + struct thr_info bye_thr; + char buf[TMPBUFSIZ]; + char param_buf[TMPBUFSIZ]; + SOCKETTYPE c; + int n, bound; + char *connectaddr; + char *binderror; + time_t bindstart; + short int port = opt_api_port; + char port_s[10]; + struct sockaddr_storage cli; + socklen_t clisiz; + char cmdbuf[100]; + char *cmd = NULL; + char *param; + bool addrok; + char group; + json_error_t json_err; + json_t *json_config; + json_t *json_val; + bool isjson; + bool did, isjoin, firstjoin; + int i; + struct addrinfo hints, *res, *host; + + SOCKETTYPE *apisock; + + apisock = cgmalloc(sizeof(*apisock)); + *apisock = INVSOCK; + json_config = NULL; + isjoin = false; + + if (!opt_api_listen) + { + applog(LOG_DEBUG, "API not running%s", UNAVAILABLE); + free(apisock); + return; + } + + io_data = sock_io_new(); + + mutex_init(&quit_restart_lock); + + pthread_cleanup_push(tidyup, (void *)apisock); + my_thr_id = api_thr_id; + + setup_groups(); + + if (opt_api_allow) + { + setup_ipaccess(); + + if (ips == 0) + { + applog(LOG_WARNING, "API not running (no valid IPs specified)%s", UNAVAILABLE); + free(apisock); + return; + } + } + + /* This should be done before curl in needed + * to ensure curl has already called WSAStartup() in windows */ + cgsleep_ms(opt_log_interval*1000); + + sprintf(port_s, "%d", port); + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + if (getaddrinfo(opt_api_host, port_s, &hints, &res) != 0) + { + applog(LOG_ERR, "API failed to resolve %s", opt_api_host); + free(apisock); + return; + } + host = res; + while (host) + { + *apisock = socket(res->ai_family, SOCK_STREAM, 0); + if (*apisock > 0) + break; + host = host->ai_next; + } + if (*apisock == INVSOCK) + { + applog(LOG_ERR, "API initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE); + freeaddrinfo(res); + free(apisock); + return; + } + +#ifndef WIN32 + // On linux with SO_REUSEADDR, bind will get the port if the previous + // socket is closed (even if it is still in TIME_WAIT) but fail if + // another program has it open - which is what we want + int optval = 1; + // If it doesn't work, we don't really care - just show a debug message + if (SOCKETFAIL(setsockopt(*apisock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval)))) + applog(LOG_DEBUG, "API setsockopt SO_REUSEADDR failed (ignored): %s", SOCKERRMSG); +#else + // On windows a 2nd program can bind to a port>1024 already in use unless + // SO_EXCLUSIVEADDRUSE is used - however then the bind to a closed port + // in TIME_WAIT will fail until the timeout - so we leave the options alone +#endif + + // try for more than 1 minute ... in case the old one hasn't completely gone yet + bound = 0; + bindstart = time(NULL); + while (bound == 0) + { + if (SOCKETFAIL(bind(*apisock, host->ai_addr, host->ai_addrlen))) + { + binderror = SOCKERRMSG; + if ((time(NULL) - bindstart) > 61) + break; + else + { + applog(LOG_WARNING, "API bind to port %d failed - trying again in 30sec", port); + cgsleep_ms(30000); + } + } + else + bound = 1; + } + freeaddrinfo(res); + + if (bound == 0) + { + applog(LOG_ERR, "API bind to port %d failed (%s)%s", port, binderror, UNAVAILABLE); + free(apisock); + return; + } + + if (SOCKETFAIL(listen(*apisock, QUEUE))) + { + applog(LOG_ERR, "API3 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE); + CLOSESOCKET(*apisock); + free(apisock); + return; + } + + if (opt_api_allow) + applog(LOG_WARNING, "API running in IP access mode on port %d (%d)", port, (int)*apisock); + else + { + if (opt_api_network) + applog(LOG_WARNING, "API running in UNRESTRICTED read access mode on port %d (%d)", port, (int)*apisock); + else + applog(LOG_WARNING, "API running in local read access mode on port %d (%d)", port, (int)*apisock); + } + + if (opt_api_mcast) + mcast_init(); + + strbufs = k_new_list("StrBufs", sizeof(SBITEM), ALLOC_SBITEMS, LIMIT_SBITEMS, false); + + while (!bye) + { + clisiz = sizeof(cli); + if (SOCKETFAIL(c = accept(*apisock, (struct sockaddr *)(&cli), &clisiz))) + { + applog(LOG_ERR, "API failed (%s)%s (%d)", SOCKERRMSG, UNAVAILABLE, (int)*apisock); + goto die; + } + + addrok = check_connect((struct sockaddr_storage *)&cli, &connectaddr, &group); + applog(LOG_DEBUG, "API: connection from %s - %s", + connectaddr, addrok ? "Accepted" : "Ignored"); + + if (addrok) + { + n = recv(c, &buf[0], TMPBUFSIZ-1, 0); + if (SOCKETFAIL(n)) + buf[0] = '\0'; + else + buf[n] = '\0'; + + if (opt_debug) + { + if (SOCKETFAIL(n)) + applog(LOG_DEBUG, "API: recv failed: %s", SOCKERRMSG); + else + applog(LOG_DEBUG, "API: recv command: (%d) '%s'", n, buf); + } + + if (!SOCKETFAIL(n)) + { + // the time of the request in now + when = time(NULL); + io_reinit(io_data); + + did = false; + + if (*buf != ISJSON) + { + isjson = false; + + param = strchr(buf, SEPARATOR); + if (param != NULL) + *(param++) = '\0'; + + cmd = buf; + } + else + { + isjson = true; + + param = NULL; + + json_config = json_loadb(buf, n, 0, &json_err); + + if (!json_is_object(json_config)) + { + message(io_data, MSG_INVJSON, 0, NULL, isjson); + send_result(io_data, c, isjson); + did = true; + } + else + { + json_val = json_object_get(json_config, JSON_COMMAND); + if (json_val == NULL) + { + message(io_data, MSG_MISCMD, 0, NULL, isjson); + send_result(io_data, c, isjson); + did = true; + } + else + { + if (!json_is_string(json_val)) + { + message(io_data, MSG_INVCMD, 0, NULL, isjson); + send_result(io_data, c, isjson); + did = true; + } + else + { + cmd = (char *)json_string_value(json_val); + json_val = json_object_get(json_config, JSON_PARAMETER); + if (json_is_string(json_val)) + param = (char *)json_string_value(json_val); + else if (json_is_integer(json_val)) + { + sprintf(param_buf, "%d", (int)json_integer_value(json_val)); + param = param_buf; + } + else if (json_is_real(json_val)) + { + sprintf(param_buf, "%f", (double)json_real_value(json_val)); + param = param_buf; + } + } + } + } + } + + if (!did) + { + char *cmdptr, *cmdsbuf = NULL; + + if (strchr(cmd, CMDJOIN)) + { + firstjoin = isjoin = true; + // cmd + leading+tailing '|' + '\0' + cmdsbuf = cgmalloc(strlen(cmd) + 3); + strcpy(cmdsbuf, "|"); + param = NULL; + } + else + firstjoin = isjoin = false; + + cmdptr = cmd; + do + { + did = false; + if (isjoin) + { + cmd = strchr(cmdptr, CMDJOIN); + if (cmd) + *(cmd++) = '\0'; + if (!*cmdptr) + goto inochi; + } + + for (i = 0; cmds[i].name != NULL; i++) + { + if (strcmp(cmdptr, cmds[i].name) == 0) + { + sprintf(cmdbuf, "|%s|", cmdptr); + if (isjoin) + { + if (strstr(cmdsbuf, cmdbuf)) + { + did = true; + break; + } + strcat(cmdsbuf, cmdptr); + strcat(cmdsbuf, "|"); + head_join(io_data, cmdptr, isjson, &firstjoin); + if (!cmds[i].joinable) + { + message(io_data, MSG_ACCDENY, 0, cmds[i].name, isjson); + did = true; + tail_join(io_data, isjson); + break; + } + } + if (ISPRIVGROUP(group) || strstr(COMMANDS(group), cmdbuf)) + (cmds[i].func)(io_data, c, param, isjson, group); + else + { + message(io_data, MSG_ACCDENY, 0, cmds[i].name, isjson); + applog(LOG_DEBUG, "API: access denied to '%s' for '%s' command", connectaddr, cmds[i].name); + } + + did = true; + if (!isjoin) + send_result(io_data, c, isjson); + else + tail_join(io_data, isjson); + break; + } + } + + if (!did) + { + if (isjoin) + head_join(io_data, cmdptr, isjson, &firstjoin); + message(io_data, MSG_INVCMD, 0, NULL, isjson); + if (isjoin) + tail_join(io_data, isjson); + else + send_result(io_data, c, isjson); + } + inochi: + if (isjoin) + cmdptr = cmd; + } + while (isjoin && cmdptr); + } + + if (isjoin) + send_result(io_data, c, isjson); + + if (isjson && json_is_object(json_config)) + json_decref(json_config); + } + } + CLOSESOCKET(c); + } +die: + /* Blank line fix for older compilers since pthread_cleanup_pop is a + * macro that gets confused by a label existing immediately before it + */ + ; + pthread_cleanup_pop(true); + + free(apisock); + + if (opt_debug) + applog(LOG_DEBUG, "API: terminating due to: %s", + do_a_quit ? "QUIT" : (do_a_restart ? "RESTART" : (bye ? "BYE" : "UNKNOWN!"))); + + mutex_lock(&quit_restart_lock); + + if (do_a_restart) + { + if (thr_info_create(&bye_thr, NULL, restart_thread, &bye_thr)) + { + mutex_unlock(&quit_restart_lock); + quit(1, "API failed to initiate a restart - aborting"); + } + pthread_detach(bye_thr.pth); + } + else if (do_a_quit) + { + if (thr_info_create(&bye_thr, NULL, quit_thread, &bye_thr)) + { + mutex_unlock(&quit_restart_lock); + quit(1, "API failed to initiate a clean quit - aborting"); + } + pthread_detach(bye_thr.pth); + } + + mutex_unlock(&quit_restart_lock); +} diff --git a/bitmain-board-test.c b/bitmain-board-test.c new file mode 100644 index 0000000000..3af909b747 --- /dev/null +++ b/bitmain-board-test.c @@ -0,0 +1,2310 @@ +/* + * Copyright 2016-2017 Fazio Bai + * Copyright 2016-2017 Clement Duan + * + * 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 +#include +#include + +#ifndef WIN32 +#include +#include +#include +#include +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif +#else +#include "compat.h" +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "elist.h" +#include "miner.h" + + +#include "util.h" +#include "driver-btm-soc.h" + +#include "bitmain-board-test.h" + +// below are defined in driver-btm-c5.c +extern pthread_mutex_t iic_mutex; +extern bool isChainAllCoresOpened[BITMAIN_MAX_CHAIN_NUM]; +extern bool someBoardUpVoltage; +extern int lowest_testOK_temp[BITMAIN_MAX_CHAIN_NUM]; +extern int LOWEST_TEMP_DOWN_FAN; +extern int chain_badcore_num[BITMAIN_MAX_CHAIN_NUM][256]; +extern pthread_mutex_t opencore_readtemp_mutex; +extern unsigned int *axi_fpga_addr; // defined in driver-btm-c5.c +extern unsigned int *fpga_mem_addr; //defined in driver-btm-c5.c +extern int fd_fpga_mem; // fpga memory +extern unsigned int *nonce2_jobid_address; // the value should be filled in NONCE2_AND_JOBID_STORE_ADDRESS + +extern void open_core_one_chain(int chainIndex, bool nullwork_enable); +extern void insert_reg_data(unsigned int *buf); +extern int GetTotalRate(); +extern int getVoltageLimitedFromHashrate(int hashrate_GHz); +extern bool isChainEnough(); +extern void set_PWM(unsigned char pwm_percent); +extern int get_nonce_number_in_fifo(void); +extern int get_return_nonce(unsigned int *buf); +extern int get_nonce_fifo_interrupt(void); +extern void set_nonce_fifo_interrupt(unsigned int value); +extern void set_TW_write_command(unsigned int *value); +extern void set_TW_write_command_vil(unsigned int *value); +extern int get_buffer_space(void); +extern int get_freqvalue_by_index(int index); +extern int getChainAsicFreqIndex(int chainIndex, int asicIndex); +extern int get_hash_on_plug(void); + + +////////// below is only used inside of this file !!! so all static!///////////// +static bool chain_need_opencore[BITMAIN_MAX_CHAIN_NUM]= {false}; +static bool StartSendFlag[BITMAIN_MAX_CHAIN_NUM]; + +static int chain_DataCount[BITMAIN_MAX_CHAIN_NUM]; +static int chain_ValidNonce[BITMAIN_MAX_CHAIN_NUM]; +static int chain_PassCount[BITMAIN_MAX_CHAIN_NUM]; + +static int chain_vol_value[BITMAIN_MAX_CHAIN_NUM]; // the searching vol +static int chain_vol_final[BITMAIN_MAX_CHAIN_NUM]; // the final vol, need saved in PIC +static int chain_vol_added[BITMAIN_MAX_CHAIN_NUM]; // how many vol added , recorded in PIC + +static int last_result[BITMAIN_MAX_CHAIN_NUM][256]; +static int last_result_opencore[BITMAIN_MAX_CHAIN_NUM][256]; + +static int result = 0; +static bool search_freq_result[BITMAIN_MAX_CHAIN_NUM]; // set true as default + +static struct testpatten_cgpu_info cgpu; +static volatile bool gBegin_get_nonce = false; + +static unsigned int send_work_num[BITMAIN_MAX_CHAIN_NUM]; + +static int asic_nonce_num[BITMAIN_MAX_CHAIN_NUM][256]; +static int asic_core_nonce_num[BITMAIN_MAX_CHAIN_NUM][256][256]; // 1st: which asic, 2nd: which core +static int last_nonce_num[BITMAIN_MAX_CHAIN_NUM]; +static int repeated_nonce_num[BITMAIN_MAX_CHAIN_NUM]; +static uint32_t repeated_nonce_id[BITMAIN_MAX_CHAIN_NUM][256]; +static int valid_nonce_num[BITMAIN_MAX_CHAIN_NUM]; // all the received nonce in one test +static int err_nonce_num[BITMAIN_MAX_CHAIN_NUM]; +static int total_valid_nonce_num=0; + +static volatile bool start_receive = false; + +static int testModeOKCounter[BITMAIN_MAX_CHAIN_NUM]; + +static struct configuration Conf; //store information that read from Config.ini +static struct _CONFIG conf; //store the information that handled from Config.ini + +static bool ExitFlag=false; +static bool receiveExit; +static bool sendExit[BITMAIN_MAX_CHAIN_NUM]; + +static void writeLogFile(char *logstr); +static int calculate_asic_number(unsigned int actual_asic_number); +static int calculate_core_number(unsigned int actual_core_number); + + +#define CONFIG_FILE "/etc/config/Config.ini" +#define FORCE_FREQ_FILE "/etc/config/forcefreq.txt" +#define LAST_FORCE_FREQ_FILE "/etc/config/last_forcefreq.txt" + +static bool last_all_pass(int chainIndex) +{ + int i = 0; + for(i=0; i= count) + break; + + new_work = cgpu.works[id] + subid; + + memcpy((uint8_t *)(&new_work->nonce) ,workData+subid*48+44, 4); + new_work->nonce = htonl(new_work->nonce); + + memcpy(new_work->midstate ,workData+subid*48, 32); + memcpy(new_work->data ,workData+subid*48+32, 12); + + new_work->id = subid; + subid++; + } + free(workData); + return subid; +} + +static int read_config() +{ + FILE * file; + int forceFreq,forceFlag; + struct configuration *m_conf = &Conf; + char str[1024] = {0}; + char * temp; + int offset = 0, starttemp = 0; + int i; + file = fopen(CONFIG_FILE, "r"); + char logstr[1024]; + + while(fgets(str, sizeof(str) - 1 , file)) + { + if(str[0] == '#' || str[1] == '#') + continue; + + if((temp = strstr(str, "TestDir="))!=NULL) + { + temp += 8; + for(i = 0; i < 64; i++) + { + cgpu.workdataPathPrefix[i] = *temp++; + //printf("%c", *temp); + if(*temp == '\n' || *temp == '\r') + break; + } + i++; + cgpu.workdataPathPrefix[i] = '\0'; + printf("workdataPathPrefix:%s\n", cgpu.workdataPathPrefix); + } + else if((temp = strstr(str, "DataCount="))!=NULL) + { + temp += 10; + sscanf(temp, "%d", &m_conf->DataCount); + } + else if((temp = strstr(str, "PassCount1="))!=NULL) + { + temp += 11; + sscanf(temp, "%d", &m_conf->PassCount1); + } + else if((temp = strstr(str, "PassCount2="))!=NULL) + { + temp += 11; + sscanf(temp, "%d", &m_conf->PassCount2); + } + else if((temp = strstr(str, "PassCount3="))!=NULL) + { + temp += 11; + sscanf(temp, "%d", &m_conf->PassCount3); + } + else if((temp = strstr(str, "Freq="))!=NULL) + { + temp += 5; + sscanf(temp, "%d", &m_conf->Freq); + + m_conf->force_freq=0; + } + else if((temp = strstr(str, "freq_e="))!=NULL) + { + temp += 7; + sscanf(temp, "%d", &m_conf->freq_e); + } + else if((temp = strstr(str, "UseConfigVol="))!=NULL) + { + temp += 13; + sscanf(temp, "%d", &m_conf->UseConfigVol); + } + else if((temp = strstr(str, "freq_m="))!=NULL) + { + temp += 7; + sscanf(temp, "%d", &m_conf->freq_m); + } + else if((temp = strstr(str, "freq_a="))!=NULL) + { + temp += 7; + sscanf(temp, "%d", &m_conf->freq_a); + } + else if((temp = strstr(str, "freq_t="))!=NULL) + { + temp += 7; + sscanf(temp, "%d", &m_conf->freq_t); + } + else if((temp = strstr(str, "force_freq="))!=NULL) + { + temp += 11; + // sscanf(temp, "%d", &m_conf->force_freq); + } + else if((temp = strstr(str, "Timeout="))!=NULL) + { + temp +=8; + sscanf(temp, "%d", &m_conf->Timeout); + } + else if((temp = strstr(str, "UseFreqPIC="))!=NULL) + { + temp += 11; + sscanf(temp , "%d", &m_conf->UseFreqPIC); + } + else if((temp = strstr(str, "TestMode="))!=NULL) + { + temp += 9; + sscanf(temp, "%d", &m_conf->TestMode); + } + else if((temp = strstr(str, "CheckChain="))!=NULL) + { + temp += 11; + sscanf(temp, "%d", &m_conf->CheckChain); + } + else if((temp = strstr(str, "CommandMode="))!=NULL) + { + temp += 12; + sscanf(temp, "%d", &m_conf->CommandMode); + } + else if((temp = strstr(str, "ValidNonce1="))!=NULL) + { + temp += 12; + sscanf(temp, "%d", &m_conf->ValidNonce1); + } + else if((temp = strstr(str, "ValidNonce2="))!=NULL) + { + temp += 12; + sscanf(temp, "%d", &m_conf->ValidNonce2); + } + else if((temp = strstr(str, "ValidNonce3="))!=NULL) + { + temp += 12; + sscanf(temp, "%d", &m_conf->ValidNonce3); + } + else if((temp = strstr(str, "Pic_VOLTAGE="))!=NULL) + { + temp += 12; + sscanf(temp, "%d", &m_conf->Pic); + } + else if((temp = strstr(str, "Voltage1="))!=NULL) + { + temp += 9; + sscanf(temp, "%d", &m_conf->Voltage1); + } + else if((temp = strstr(str, "Voltage2="))!=NULL) + { + temp += 9; + sscanf(temp, "%d", &m_conf->Voltage2); + } + else if((temp = strstr(str, "Voltage3="))!=NULL) + { + temp += 9; + sscanf(temp, "%d", &m_conf->Voltage3); + } + else if((temp = strstr(str, "final_voltage1="))!=NULL) + { + temp += 15; + sscanf(temp, "%ud", &m_conf->final_voltage1); + } + else if((temp = strstr(str, "final_voltage2="))!=NULL) + { + temp += 15; + sscanf(temp, "%ud", &m_conf->final_voltage2); + } + else if((temp = strstr(str, "final_voltage3="))!=NULL) + { + temp += 15; + sscanf(temp, "%ud", &m_conf->final_voltage3); + } + else if((temp = strstr(str, "freq_gap="))!=NULL) + { + temp += 9; + sscanf(temp, "%ud", &m_conf->freq_gap); + } + else if((temp = strstr(str, "OpenCoreGap="))!=NULL) + { + temp += 12; + sscanf(temp, "%d", &m_conf->OpenCoreGap); + } + else if((temp = strstr(str, "CheckTemp="))!=NULL) + { + temp += 10; + sscanf(temp, "%d", &m_conf->checktemp); + } + else if((temp = strstr(str, "IICPic="))!=NULL) + { + temp += 7; + sscanf(temp, "%d", &m_conf->IICPic); + } + else if((temp = strstr(str, "Open_Core_Num1="))!=NULL) + { + temp += 15; + sscanf(temp, "%ud", &m_conf->OpenCoreNum1); + } + else if((temp = strstr(str, "Open_Core_Num2="))!=NULL) + { + temp += 15; + sscanf(temp, "%ud", &m_conf->OpenCoreNum2); + } + else if((temp = strstr(str, "Open_Core_Num3="))!=NULL) + { + temp += 15; + sscanf(temp, "%ud", &m_conf->OpenCoreNum3); + } + else if((temp = strstr(str, "Open_Core_Num4="))!=NULL) + { + temp += 15; + sscanf(temp, "%ud", &m_conf->OpenCoreNum4); + } + else if((temp = strstr(str, "DAC="))!=NULL) + { + temp += 4; + sscanf(temp, "%ud", &m_conf->dac); + } + else if((temp = strstr(str, "GetTempFrom="))!=NULL) + { + temp += 12; + sscanf(temp, "%ud", &m_conf->GetTempFrom); + } + else if((temp = strstr(str, "TempSel="))!=NULL) + { + temp += 8; + sscanf(temp, "%ud", &m_conf->TempSel); + } + else if((temp = strstr(str, "TempSensor1="))!=NULL) + { + temp += 12; + sscanf(temp, "%ud", &m_conf->TempSensor1); + } + else if((temp = strstr(str, "TempSensor2="))!=NULL) + { + temp += 12; + sscanf(temp, "%ud", &m_conf->TempSensor2); + } + else if((temp = strstr(str, "TempSensor3="))!=NULL) + { + temp += 12; + sscanf(temp, "%ud", &m_conf->TempSensor3); + } + else if((temp = strstr(str, "TempSensor4="))!=NULL) + { + temp += 12; + sscanf(temp, "%ud", &m_conf->TempSensor4); + } + else if((temp = strstr(str, "DefaultTempOffset="))!=NULL) + { + temp += 18; + sscanf(temp, "%d", &offset); + if(offset < 0) + { + offset -= 2*offset; + m_conf->DefaultTempOffset = (signed char)offset; + m_conf->DefaultTempOffset -= 2*m_conf->DefaultTempOffset; + //printf("~~~~~~~~~ m_conf->DefaultTempOffset = %d\n", m_conf->DefaultTempOffset); + } + else + { + m_conf->DefaultTempOffset = offset; + //printf("~~~~~~~~~ m_conf->DefaultTempOffset = %d\n", m_conf->DefaultTempOffset); + } + } + else if((temp = strstr(str, "year="))!=NULL) + { + temp += 5; + sscanf(temp, "%d", &m_conf->year); + //printf("year = %d\n", m_conf->year); + } + else if((temp = strstr(str, "month="))!=NULL) + { + temp += 6; + sscanf(temp, "%d", &m_conf->month); + } + else if((temp = strstr(str, "date="))!=NULL) + { + temp += 5; + sscanf(temp, "%d", &m_conf->date); + } + else if((temp = strstr(str, "hour="))!=NULL) + { + temp += 5; + sscanf(temp, "%d", &m_conf->hour); + } + else if((temp = strstr(str, "minute="))!=NULL) + { + temp += 7; + sscanf(temp, "%d", &m_conf->minute); + } + else if((temp = strstr(str, "second="))!=NULL) + { + temp += 7; + sscanf(temp, "%d", &m_conf->second); + } + else if((temp = strstr(str, "StartSensor="))!=NULL) + { + temp += 12; + sscanf(temp, "%d", &m_conf->StartSensor); + } + else if((temp = strstr(str, "StartTemp="))!=NULL) + { + temp += 10; + sscanf(temp, "%d", &m_conf->StartTemp); + sscanf(temp, "%d", &starttemp); + if(starttemp < 0) + { + starttemp -= 2*starttemp; + m_conf->StartTemp = (signed char)starttemp; + m_conf->StartTemp -= 2*m_conf->StartTemp; + //printf("~~~~~~~~~ m_conf->DefaultTempOffset = %d\n", m_conf->DefaultTempOffset); + } + else + { + m_conf->StartTemp = starttemp; + //printf("~~~~~~~~~ m_conf->DefaultTempOffset = %d\n", m_conf->DefaultTempOffset); + } + } + } + + m_conf->AsicNum=CHAIN_ASIC_NUM; + m_conf->AsicType=ASIC_TYPE; + m_conf->CoreNum=ASIC_CORE_NUM; + return 0; +} + +static int process_config() +{ + uint32_t rBaudrate; + int temp_corenum = 0; + + conf.CommandMode = Conf.CommandMode; + + conf.TempSel = Conf.TempSel; + + conf.GetTempFrom = Conf.GetTempFrom; + + if(Conf.CommandMode == FIL) + { + if(conf.GetTempFrom == 1) // read temp from asic + { + applog(LOG_ERR, "Can't get temperature from ASIC in FIL mode!\n"); + return -1; + } + } + + if(Conf.CommandMode == VIL) + { + if(conf.GetTempFrom == 1) // read temp from asic + { + cgpu.temp_sel = Conf.TempSel; + cgpu.rfs = 1; + cgpu.tfs = 3; + //printf("cgpu.temp_sel = %d, cgpu.rfs = %d, cgpu.tfs = %d\n", cgpu.temp_sel, cgpu.rfs, cgpu.tfs); + + if(Conf.TempSensor1 + Conf.TempSensor2 + Conf.TempSensor3 + Conf.TempSensor4) + { + conf.TempSensor1 = Conf.TempSensor1; + conf.TempSensor2 = Conf.TempSensor2; + conf.TempSensor3 = Conf.TempSensor3; + conf.TempSensor4 = Conf.TempSensor4; + conf.DefaultTempOffset = Conf.DefaultTempOffset; + cgpu.T1_offset_value = Conf.DefaultTempOffset; + cgpu.T2_offset_value = Conf.DefaultTempOffset; + cgpu.T3_offset_value = Conf.DefaultTempOffset; + cgpu.T4_offset_value = Conf.DefaultTempOffset; + conf.StartSensor = Conf.StartSensor; + conf.StartTemp = Conf.StartTemp; + } + else + { + applog(LOG_ERR, "Must set temperature sensor address!\n"); + return -1; + } + } + } + + conf.AsicType = ASIC_TYPE; + + conf.core = Conf.CoreNum; + + conf.freq_e = Conf.freq_e; + + conf.freq_m = Conf.freq_m; + + conf.freq_a = Conf.freq_a; + + conf.freq_t = Conf.freq_t; + + conf.force_freq = Conf.force_freq; + + conf.UseConfigVol = Conf.UseConfigVol; + + conf.OpenCoreNum1 = Conf.OpenCoreNum1; + + conf.OpenCoreNum2 = Conf.OpenCoreNum2; + + conf.OpenCoreNum3 = Conf.OpenCoreNum3; + + conf.OpenCoreNum4 = Conf.OpenCoreNum4; + + conf.asicNum = calculate_asic_number(CHAIN_ASIC_NUM); + + conf.addrInterval = Conf.AddrInterval = CHIP_ADDR_INTERVAL; + + temp_corenum = calculate_core_number(conf.core); + + conf.testMode = Conf.TestMode; + + conf.ValidNonce1 = Conf.ValidNonce1; + + conf.ValidNonce2 = Conf.ValidNonce2; + + conf.ValidNonce3 = Conf.ValidNonce3; + + conf.Pic = Conf.Pic; + + conf.IICPic = Conf.IICPic; + + conf.dac= Conf.dac; + + conf.Voltage1 = Conf.Voltage1; + + conf.Voltage2 = Conf.Voltage2; + + conf.Voltage3 = Conf.Voltage3; + + conf.OpenCoreGap = Conf.OpenCoreGap; + + conf.checktemp = Conf.checktemp; + + if(ASIC_TYPE==1385 || ASIC_TYPE == 1387) + { + conf.freq = Conf.Freq; + } + else + { + printf("%s: ASIC_TYPE = %d, but it is not correct!\n", __FUNCTION__, ASIC_TYPE); + } + + conf.year = Conf.year; + conf.month = Conf.month; + conf.date = Conf.date; + conf.hour = Conf.hour; + conf.minute = Conf.minute; + conf.second = Conf.second; + + if(Conf.Timeout <= 0) + conf.timeout = 0x1000000/temp_corenum*conf.addrInterval/Conf.Freq*95/100; + else + conf.timeout = Conf.Timeout; + + rBaudrate = 1000000 * 5/3 / conf.timeout * (64*8);//64*8 need send bit, ratio=2/3 + conf.baud = 25000000/rBaudrate/8 - 1; + if(conf.baud > DEFAULT_BAUD_VALUE) + { + conf.baud = DEFAULT_BAUD_VALUE; + } + else if(conf.baud <= 0) + { + applog(LOG_ERR, "$$$$Config argument Baudrate:%d err\n", conf.baud); + return -1; + } + + if(Conf.DataCount > MAX_WORK || Conf.DataCount <= 0) + { + applog(LOG_ERR, "$$$$Config argument DataCount:%d err\n", Conf.DataCount); + } + else + conf.dataCount = Conf.DataCount; + + if(Conf.PassCount1 > conf.dataCount || Conf.PassCount1 < 0) + { + applog(LOG_ERR, "$$$$Config argument DataCount:%d err\n", Conf.DataCount); + } + else + conf.passCount1 = Conf.PassCount1; + + if(Conf.PassCount2 > conf.dataCount || Conf.PassCount2 < 0) + { + applog(LOG_ERR, "$$$$Config argument DataCount:%d err\n", Conf.DataCount); + } + else + conf.passCount2 = Conf.PassCount2; + + if(Conf.PassCount3 > conf.dataCount || Conf.PassCount3 < 0) + { + applog(LOG_ERR, "$$$$Config argument DataCount:%d err\n", Conf.DataCount); + } + else + conf.passCount3 = Conf.PassCount3; + + return 0; +} + +static void print_config() +{ + const struct configuration *m_conf = &Conf; + printf("\n\nRead Config.ini\n"); + printf("DataCount:%d\n", m_conf->DataCount); + printf("PassCount1:%d\n", m_conf->PassCount1); + printf("PassCount2:%d\n", m_conf->PassCount2); + printf("PassCount3:%d\n", m_conf->PassCount3); + printf("Freq:%d\n", m_conf->Freq); + printf("Timeout:%d\n", m_conf->Timeout); + printf("OpenCoreGap:%d\n", m_conf->OpenCoreGap); + printf("CheckTemp:%d\n", m_conf->checktemp); + printf("CoreNum:%d\n", m_conf->CoreNum); + printf("freq_e:%d\n", m_conf->freq_e); + printf("AsicNum:%d\n", m_conf->AsicNum); + printf("TestMode:%d\n", m_conf->TestMode); + printf("CheckChain:%d\n", m_conf->CheckChain); + printf("CommandMode:%d\n", m_conf->CommandMode); + printf("AsicType:%d\n", m_conf->AsicType); + printf("ValidNonce1:%d\n", m_conf->ValidNonce1); + printf("ValidNonce2:%d\n", m_conf->ValidNonce2); + printf("ValidNonce3:%d\n", m_conf->ValidNonce3); + printf("Pic:%ud\n", m_conf->Pic); + printf("IICPic:%ud\n", m_conf->IICPic); + printf("dac = %ud\n", m_conf->dac); + printf("Voltage1:%ud\n", m_conf->Voltage1); + printf("Voltage2:%ud\n", m_conf->Voltage2); + printf("Voltage3:%ud\n", m_conf->Voltage3); + printf("OpenCoreNum1 = %ud = 0x%x\n", m_conf->OpenCoreNum1, m_conf->OpenCoreNum1); + printf("OpenCoreNum2 = %ud = 0x%x\n", m_conf->OpenCoreNum2, m_conf->OpenCoreNum2); + printf("OpenCoreNum3 = %ud = 0x%x\n", m_conf->OpenCoreNum3, m_conf->OpenCoreNum3); + printf("OpenCoreNum4 = %ud = 0x%x\n", m_conf->OpenCoreNum4, m_conf->OpenCoreNum4); + printf("GetTempFrom:%d\n", m_conf->GetTempFrom); + printf("TempSel:%d\n", m_conf->TempSel); + printf("TempSensor1:%d\n", m_conf->TempSensor1); + printf("TempSensor2:%d\n", m_conf->TempSensor2); + printf("TempSensor3:%d\n", m_conf->TempSensor3); + printf("TempSensor4:%d\n", m_conf->TempSensor4); + printf("DefaultTempOffset:%d\n", m_conf->DefaultTempOffset); + printf("StartSensor:%d\n", m_conf->StartSensor); + printf("StartTemp:%d\n", m_conf->StartTemp); + printf("year:%04d\n", m_conf->year); + printf("month:%02d\n", m_conf->month); + printf("date:%02d\n", m_conf->date); + printf("hour:%02d\n", m_conf->hour); + printf("minute:%02d\n", m_conf->minute); + printf("second:%02d\n", m_conf->second); + + printf("\n\n"); +} + +static void print_CONFIG(void) +{ + const struct _CONFIG *m_conf = &conf; + printf("\n\nparameter processed after Reading Config.ini\n"); + printf("DataCount:%d\n", m_conf->dataCount); + printf("PassCount1:%d\n", m_conf->passCount1); + printf("PassCount2:%d\n", m_conf->passCount2); + printf("PassCount3:%d\n", m_conf->passCount3); + printf("Freq:%d\n", m_conf->freq); + printf("Timeout:%d\n", m_conf->timeout); + printf("OpenCoreGap:%d\n", m_conf->OpenCoreGap); + printf("CheckTemp:%d\n", m_conf->checktemp); + printf("CoreNum:%d\n", m_conf->core); + printf("AsicNum:%d\n", m_conf->asicNum); + printf("TestMode:%d\n", m_conf->testMode); + printf("CommandMode:%d\n", m_conf->CommandMode); + printf("AsicType:%d\n", m_conf->AsicType); + printf("ValidNonce1:%d\n", m_conf->ValidNonce1); + printf("ValidNonce2:%d\n", m_conf->ValidNonce2); + printf("ValidNonce3:%d\n", m_conf->ValidNonce3); + printf("Pic:%ud\n", m_conf->Pic); + printf("IICPic:%ud\n", m_conf->IICPic); + printf("dac:%ud\n", m_conf->dac); + printf("Voltage1:%ud\n", m_conf->Voltage1); + printf("Voltage2:%ud\n", m_conf->Voltage2); + printf("Voltage3:%ud\n", m_conf->Voltage3); + printf("OpenCoreNum1 = %ud = 0x%x\n", m_conf->OpenCoreNum1, m_conf->OpenCoreNum1); + printf("OpenCoreNum2 = %ud = 0x%x\n", m_conf->OpenCoreNum2, m_conf->OpenCoreNum2); + printf("OpenCoreNum3 = %ud = 0x%x\n", m_conf->OpenCoreNum3, m_conf->OpenCoreNum3); + printf("OpenCoreNum4 = %ud = 0x%x\n", m_conf->OpenCoreNum4, m_conf->OpenCoreNum4); + printf("GetTempFrom:%d\n", m_conf->GetTempFrom); + printf("TempSel:%d\n", m_conf->TempSel); + printf("TempSensor1:%d\n", m_conf->TempSensor1); + printf("TempSensor2:%d\n", m_conf->TempSensor2); + printf("TempSensor3:%d\n", m_conf->TempSensor3); + printf("TempSensor4:%d\n", m_conf->TempSensor4); + printf("DefaultTempOffset:%d\n", m_conf->DefaultTempOffset); + printf("StartSensor:%d\n", m_conf->StartSensor); + printf("StartTemp:%d\n", m_conf->StartTemp); + printf("year:%04d\n", m_conf->year); + printf("month:%02d\n", m_conf->month); + printf("date:%02d\n", m_conf->date); + printf("hour:%02d\n", m_conf->hour); + printf("minute:%02d\n", m_conf->minute); + printf("second:%02d\n", m_conf->second); + printf("\n\n"); +} + +static int get_works() +{ + char strFilePath[64] = {0}; + int i, j, record, loop=0; + unsigned int OpenCoreNum1 = conf.OpenCoreNum1; + unsigned int OpenCoreNum2 = conf.OpenCoreNum2; + unsigned int OpenCoreNum3 = conf.OpenCoreNum3; + unsigned int OpenCoreNum4 = conf.OpenCoreNum4; + //getcwd(Path, 128); + //applog(LOG_DEBUG, "Path:%s\n", Path); + + //printf("%s: loop = %d\n", __FUNCTION__, loop); + + if(CHAIN_ASIC_NUM == 1) + { + for(j=0; j < 32; j++) + { + if(OpenCoreNum1 & 0x00000001) + { + loop++; + } + OpenCoreNum1 = OpenCoreNum1 >> 1; + + if(OpenCoreNum2 & 0x00000001) + { + loop++; + } + OpenCoreNum2 = OpenCoreNum2 >> 1; + + if(OpenCoreNum3 & 0x00000001) + { + loop++; + } + OpenCoreNum3 = OpenCoreNum3 >> 1; + + if(OpenCoreNum4 & 0x00000001) + { + loop++; + } + OpenCoreNum4 = OpenCoreNum4 >> 1; + } + + printf("%s: loop = %d\n", __FUNCTION__, loop); + } + else + { + loop = conf.asicNum; + } + + j=0; + OpenCoreNum1 = conf.OpenCoreNum1; + OpenCoreNum2 = conf.OpenCoreNum2; + OpenCoreNum3 = conf.OpenCoreNum3; + OpenCoreNum4 = conf.OpenCoreNum4; + + for(i = 0; i < loop; i++) + { + if(CHAIN_ASIC_NUM == 1) + { + for(; j < 128; j++) + { + if(j < 32) + { + if(OpenCoreNum1 & 0x00000001) + { + sprintf(strFilePath, "%s%02i.bin", cgpu.workdataPathPrefix, j+1); + printf("dir:%s\n", strFilePath); + OpenCoreNum1 = OpenCoreNum1 >> 1; + j++; + break; + } + else + { + OpenCoreNum1 = OpenCoreNum1 >> 1; + } + } + else if((j >= 32) && (j < 64)) + { + if(OpenCoreNum2 & 0x00000001) + { + sprintf(strFilePath, "%s%02i.bin", cgpu.workdataPathPrefix, j+1); + printf("dir:%s\n", strFilePath); + OpenCoreNum2 = OpenCoreNum2 >> 1; + j++; + break; + } + else + { + OpenCoreNum2 = OpenCoreNum2 >> 1; + } + } + else if((j >= 64) && (j < 96)) + { + if(OpenCoreNum3 & 0x00000001) + { + sprintf(strFilePath, "%s%02i.bin", cgpu.workdataPathPrefix, j+1); + printf("dir:%s\n", strFilePath); + OpenCoreNum3 = OpenCoreNum3 >> 1; + j++; + break; + } + else + { + OpenCoreNum3 = OpenCoreNum3 >> 1; + } + } + else + { + if(OpenCoreNum4 & 0x00000001) + { + sprintf(strFilePath, "%s%02i.bin", cgpu.workdataPathPrefix, j+1); + printf("dir:%s\n", strFilePath); + OpenCoreNum4 = OpenCoreNum4 >> 1; + j++; + break; + } + else + { + OpenCoreNum4 = OpenCoreNum4 >> 1; + } + } + } + } + else + { + sprintf(strFilePath, "%s%02i.bin", cgpu.workdataPathPrefix, i+1); + //applog(LOG_DEBUG, "dir:%s\n", strFilePath); + } + + cgpu.fps[i] = fopen(strFilePath, "rb"); + if(NULL == cgpu.fps[i]) + { + applog(LOG_ERR, "Open test file %s error\n", strFilePath); + return -1; + } + cgpu.subid[i] = load_testpatten_work(i, MAX_WORK); + //applog(LOG_DEBUG, "asic[%d] get work %d\n", i, cgpu.subid[i]); + fclose(cgpu.fps[i]); + } + + cgpu.min_work_subid = cgpu.subid[0]; + record = 0; + for(i = 0; i < loop; i++) + { + if(cgpu.min_work_subid > cgpu.subid[i]) + { + cgpu.min_work_subid = cgpu.subid[i]; + record = i; + } + } + applog(LOG_DEBUG, "min work minertest[%d]:%d\n\n\n", record, cgpu.min_work_subid); + if(conf.dataCount > cgpu.min_work_subid) + { + applog(LOG_ERR, "$$$$dataCount=%d, but min work subid=%d\n", + conf.dataCount, cgpu.min_work_subid); + return -1; + } + return 0; +} + + +static int configMiner() +{ + int ret; + + read_config(); + print_config(); + ret = process_config(); + if(ret < 0) return -EFAULT; + + print_CONFIG(); + ret = get_works(); + if(ret < 0) return -EFAULT; + return 0; +} + +static int calculate_asic_number(unsigned int actual_asic_number) +{ + int i = 0; + if(actual_asic_number == 1) + { + i = 1; + } + else if(actual_asic_number == 2) + { + i = 2; + } + else if((actual_asic_number > 2) && (actual_asic_number <= 4)) + { + i = 4; + } + else if((actual_asic_number > 4) && (actual_asic_number <= 8)) + { + i = 8; + } + else if((actual_asic_number > 8) && (actual_asic_number <= 16)) + { + i = 16; + } + else if((actual_asic_number > 16) && (actual_asic_number <= 32)) + { + i = 32; + } + else if((actual_asic_number > 32) && (actual_asic_number <= 64)) + { + i = 64; + } + else if((actual_asic_number > 64) && (actual_asic_number <= 128)) + { + i = 128; + } + else + { + applog(LOG_DEBUG,"actual_asic_number = %d, but it is error\n", actual_asic_number); + return -1; + } + return i; +} + +static int calculate_core_number(unsigned int actual_core_number) +{ + int i = 0; + if(actual_core_number == 1) + { + i = 1; + } + else if(actual_core_number == 2) + { + i = 2; + } + else if((actual_core_number > 2) && (actual_core_number <= 4)) + { + i = 4; + } + else if((actual_core_number > 4) && (actual_core_number <= 8)) + { + i = 8; + } + else if((actual_core_number > 8) && (actual_core_number <= 16)) + { + i = 16; + } + else if((actual_core_number > 16) && (actual_core_number <= 32)) + { + i = 32; + } + else if((actual_core_number > 32) && (actual_core_number <= 64)) + { + i = 64; + } + else if((actual_core_number > 64) && (actual_core_number <= 128)) + { + i = 128; + } + else + { + applog(LOG_DEBUG,"actual_core_number = %d, but it is error\n", actual_core_number); + return -1; + } + return i; +} + +static int get_result(int chainIndex, int passCount, int validnonce) +{ + char logstr[1024]; + int ret = 3; + int i, j=0, loop=0, m, n; + unsigned int OpenCoreNum1 = conf.OpenCoreNum1; + unsigned int OpenCoreNum2 = conf.OpenCoreNum2; + unsigned int OpenCoreNum3 = conf.OpenCoreNum3; + unsigned int OpenCoreNum4 = conf.OpenCoreNum4; + + printf("\n------------------------------------------------------------------------------------------------------\n"); + if(conf.CommandMode) + { + printf("Command mode is FIL\n"); + } + else + { + printf("Command mode is VIL\n"); + } + + if(cgpu.real_asic_num == 1) + { + printf("Open core number : Conf.OpenCoreNum1 = %ud = 0x%x\n", Conf.OpenCoreNum1, Conf.OpenCoreNum1); + printf("Open core number : Conf.OpenCoreNum2 = %ud = 0x%x\n", Conf.OpenCoreNum2, Conf.OpenCoreNum2); + printf("Open core number : Conf.OpenCoreNum3 = %ud = 0x%x\n", Conf.OpenCoreNum3, Conf.OpenCoreNum3); + printf("Open core number : Conf.OpenCoreNum4 = %ud = 0x%x\n", Conf.OpenCoreNum4, Conf.OpenCoreNum4); + loop = Conf.CoreNum; + } + else + { + loop = cgpu.real_asic_num; + } + sprintf(logstr,"require nonce number:%d\n", passCount); + writeLogFile(logstr); + + sprintf(logstr,"require validnonce number:%d\n", validnonce); + writeLogFile(logstr); + + for(i = 0; i < loop; i++) + { +#ifdef LOG_CHIPS_CORE_DETAIL + if(cgpu.real_asic_num == 1) + { + sprintf(logstr,"core[%02d]=%02d\t", i, asic_nonce_num[chainIndex][i]); + writeLogFile(logstr); + } + else + { + sprintf(logstr,"asic[%02d]=%02d\t", i, asic_nonce_num[chainIndex][i]); + writeLogFile(logstr); + } + + if(i % 8 == 7) + { + sprintf(logstr,"\n"); + writeLogFile(logstr); + } +#endif + if(cgpu.real_asic_num == 1) + { + for(; j < 128; j++) + { + if(j < 32) + { + if(OpenCoreNum1 & 0x00000001) + { + if(asic_nonce_num[chainIndex][j] < passCount) + { + ret = (~0x00000001) & ret; + } + OpenCoreNum1 = OpenCoreNum1 >> 1; + } + else + { + OpenCoreNum1 = OpenCoreNum1 >> 1; + } + } + else if((j >= 32) && (j < 64)) + { + if(OpenCoreNum2 & 0x00000001) + { + if(asic_nonce_num[chainIndex][j] < passCount) + { + ret = (~0x00000001) & ret; + } + OpenCoreNum2 = OpenCoreNum2 >> 1; + } + else + { + OpenCoreNum2 = OpenCoreNum2 >> 1; + } + } + else if((j >= 64) && (j < 96)) + { + if(OpenCoreNum3 & 0x00000001) + { + if(asic_nonce_num[chainIndex][j] < passCount) + { + ret = (~0x00000001) & ret; + } + OpenCoreNum3 = OpenCoreNum3 >> 1; + } + else + { + OpenCoreNum3 = OpenCoreNum3 >> 1; + } + } + else + { + if(OpenCoreNum4 & 0x00000001) + { + if(asic_nonce_num[chainIndex][j] < passCount) + { + ret = (~0x00000001) & ret; + } + OpenCoreNum4 = OpenCoreNum4 >> 1; + } + else + { + OpenCoreNum4 = OpenCoreNum4 >> 1; + } + } + } + } + else + { + if(asic_nonce_num[chainIndex][i] < passCount) + { + ret = (~0x00000001) & ret; + } + } + } + + if((Conf.StartSensor > 0) && (cgpu.real_asic_num != 1)) + { + n = passCount/Conf.CoreNum; +#ifdef LOG_CHIPS_CORE_DETAIL + sprintf(logstr,"\n\n\nBelow ASIC's core didn't receive all the nonce, they should receive %d nonce each!\n\n", n); + writeLogFile(logstr); +#endif + for(i = 0; i < loop; i++) + { + int opened_core_num=0; + for(m=0; m0) // we only check core is open + opened_core_num++; + } + + if(opened_core_num >= Conf.CoreNum-chain_badcore_num[chainIndex][i]) + last_result_opencore[chainIndex][i]=1; + else last_result_opencore[chainIndex][i]=0; + + if(asic_nonce_num[chainIndex][i] < passCount-chain_badcore_num[chainIndex][i]*n) + last_result[chainIndex][i]=0; + else last_result[chainIndex][i]=1; + +#ifdef LOG_CHIPS_CORE_DETAIL + if(asic_nonce_num[chainIndex][i] < passCount) + { + sprintf(logstr,"asic[%02d]=%02d\n", i, asic_nonce_num[chainIndex][i]); + writeLogFile(logstr); + + for(m=0; mmidstate[i]; + } + for(i=0; idata[i]; + } + + // send work + //printf("\n"); + for(j=0; jdata[i]; + } + for(i=0; imidstate[i]; + } + + // send work + buf_vil[0] = (work_vil_1387.work_type << 24) | (work_vil_1387.chain_id << 16) | (work_vil_1387.reserved1[0] << 8) | work_vil_1387.reserved1[1]; + buf_vil[1] = work_vil_1387.work_count; + for(j=2; jmidstate[i]; + } + for(i=0; idata[i]; + } + + // send work + for(j=0; j= CHAIN_ASIC_NUM) + { + which_asic[chainIndex]=0; // then send from chip[0] .... + index[chainIndex]++; // switch to next work + if(index[chainIndex] >= chain_DataCount[chainIndex]) + sendStartFlag[chainIndex]=false; + } + + if(wait_counter>2000) + { + // timeout on wait for fifo ready + sprintf(logstr,"Fatal Error: send work timeout\n"); + writeLogFile(logstr); + break; + } + } + usleep(5000); + + isSendOver=true; + for(i=0; i0) + { + read_loop = nonce_number; + //applog(LOG_DEBUG,"%s: read_loop = %d\n", __FUNCTION__, read_loop); + + for(j=0; j=BITMAIN_MAX_CHAIN_NUM) + { + sprintf(logstr,"Error chain index of nonce!!!\n"); + writeLogFile(logstr); + continue; + } + + if(cgpu.CommandMode) // fil mode + { + work_id[chainIndex] = (buf[0] >> 16) & 0x00007fff; + } + else // vil mode + { + if(ASIC_TYPE == 1387) + { + work_id[chainIndex] = (buf[0] >> 16) & 0x00007fff; + } + else + { + work_id[chainIndex] = (buf[0] >> 24) & 0x0000007f; + } + } + + if((buf[1] == last_nonce[chainIndex]) || (buf[1] == llast_nonce[chainIndex])) + { + last_nonce_num[chainIndex]++; + continue; + } + + if(cgpu.real_asic_num == 1) + { + if(conf.core <= 64) + { + which_core_nonce = (buf[1] & 0x0000003f); + whose_nonce = which_core_nonce; + } + else if((conf.core <= 128) && (conf.core > 64)) + { + which_core_nonce = (buf[1] & 0x0000007f); + if(which_core_nonce <= 56) + { + whose_nonce = which_core_nonce; + } + else if((which_core_nonce >= 64) && (which_core_nonce < 128)) + { + whose_nonce = which_core_nonce - 7; + } + } + else + { + printf("%s: conf.core = %d, but it is error\n", __FUNCTION__, conf.core); + } + nonce_index = 0; + OpenCoreNum1 = conf.OpenCoreNum1; + OpenCoreNum2 = conf.OpenCoreNum2; + OpenCoreNum3 = conf.OpenCoreNum3; + OpenCoreNum4 = conf.OpenCoreNum4; + + for(n=0; n> 1; + } + else + { + OpenCoreNum1 = OpenCoreNum1 >> 1; + } + } + else if((n >= 32) && (n < 64)) + { + if(OpenCoreNum2 & 0x00000001) + { + nonce_index++; + OpenCoreNum2 = OpenCoreNum2 >> 1; + } + else + { + OpenCoreNum2 = OpenCoreNum2 >> 1; + } + } + else if((n >= 64) && (n < 96)) + { + if(OpenCoreNum3 & 0x00000001) + { + nonce_index++; + OpenCoreNum3 = OpenCoreNum3 >> 1; + } + else + { + OpenCoreNum3 = OpenCoreNum3 >> 1; + } + } + else + { + if(OpenCoreNum4 & 0x00000001) + { + nonce_index++; + OpenCoreNum4 = OpenCoreNum4 >> 1; + } + else + { + OpenCoreNum4 = OpenCoreNum4 >> 1; + } + } + } + //printf("%s: nonce_index = 0x%08x\n", __FUNCTION__, nonce_index); + } + else + { + if(CHIP_ADDR_INTERVAL != 0) + { + which_asic_nonce = (buf[1] >> 24) / CHIP_ADDR_INTERVAL; + if(which_asic_nonce >= CHAIN_ASIC_NUM) + { + continue; + } + //printf("%s: which_asic = %d\n", __FUNCTION__, which_asic); + } + else + { + //printf("CHIP_ADDR_INTERVAL==0, default=4\n"); + which_asic_nonce = (buf[1] >> 24) / 4; + if(which_asic_nonce >= conf.asicNum) + { + continue; + } + } + whose_nonce = which_asic_nonce; + nonce_index = which_asic_nonce; + } + //printf("%s: whose_nonce = 0x%08x\n", __FUNCTION__, whose_nonce); + + llast_nonce[chainIndex] = last_nonce[chainIndex]; + last_nonce[chainIndex] = buf[1]; + + if(work_id[chainIndex]>=MAX_WORK) + continue; + + m_nonce[chainIndex] = (cgpu.works[nonce_index] + work_id[chainIndex])->nonce; + //printf("%s: m_nonce = 0x%08x\n", __FUNCTION__, m_nonce); + + if(buf[1] == m_nonce[chainIndex]) + { + //printf("%s: repeated_nonce_id[which_asic] = 0x%08x\n", __FUNCTION__, repeated_nonce_id[which_asic]); + + if(work_id[chainIndex] != repeated_nonce_id[chainIndex][whose_nonce]) + { + repeated_nonce_id[chainIndex][whose_nonce] = work_id[chainIndex]; + asic_nonce_num[chainIndex][whose_nonce]++; + valid_nonce_num[chainIndex]++; + + total_valid_nonce_num++; // used to check and wait all nonce back... + + if(cgpu.real_asic_num != 1) + { + if(conf.core <= 64) + { + which_core_nonce = (buf[1] & 0x0000003f); + } + else if((conf.core <= 128) && (conf.core > 64)) + { + which_core_nonce = (buf[1] & 0x0000007f); + if(which_core_nonce <= 56) + { + which_core_nonce = which_core_nonce; + } + else if((which_core_nonce >= 64) && (which_core_nonce < 128)) + { + which_core_nonce = which_core_nonce - 7; + } + } + else + { + printf("%s: conf.core = %d, but it is error\n", __FUNCTION__, conf.core); + } + asic_core_nonce_num[chainIndex][whose_nonce][which_core_nonce]++; + } + + } + else + { + repeated_nonce_num[chainIndex]++; + //printf("repeat nonce 0x%08x\n", buf[1]); + } + } + else + { + err_nonce_num[chainIndex]++; + //printf("error nonce 0x%08x\n", buf[1]); + } + //printf("\n"); + } + } + } + else //reg value + { + insert_reg_data(buf); // insert to driver-btm-c5.c reg buffer + } + } + } + else usleep(1000); + } + + receiveExit=true; + return 0; +} + +static bool doTestBoard(int test_times) +{ + int i, freq_index = 0; + char logstr[1024]; + int wait_count=0; + int last_send_num; + int last_recv_num; + int vol_value, vol_pic, vol_value_limited; + bool result_flag=true; + + memset(asic_nonce_num, 0, sizeof(asic_nonce_num)); + memset(asic_core_nonce_num, 0, sizeof(asic_core_nonce_num)); + memset(repeated_nonce_id, 0xff, sizeof(repeated_nonce_id)); + memset(err_nonce_num, 0, sizeof(err_nonce_num)); + memset(last_nonce_num, 0, sizeof(last_nonce_num)); + memset(repeated_nonce_num, 0, sizeof(repeated_nonce_num)); + memset(valid_nonce_num, 0, sizeof(valid_nonce_num)); + memset(send_work_num, 0, sizeof(send_work_num)); + + total_valid_nonce_num=0; + + start_receive=true; + + FOR_LOOP_CHAIN + { + cgpu.chain_exist[i] = getChainExistFlag(i); + } + +#ifndef T9_18 + sprintf(logstr,"Check voltage total rate=%d\n",GetTotalRate()); + writeLogFile(logstr); + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) // here must use i from 0 in for loop, because we use j to get the index as config file's voltage value + { + if(cgpu.chain_exist[i]==0) + continue; + + pthread_mutex_lock(&iic_mutex); + vol_pic=get_pic_voltage(i); + pthread_mutex_unlock(&iic_mutex); + + vol_value = getVolValueFromPICvoltage(vol_pic); + + chain_vol_value[i]=(vol_value/10)*10; // must record current voltage!!! + + vol_value_limited=getVoltageLimitedFromHashrate(GetTotalRate()); + + sprintf(logstr,"get PIC voltage=%d [%d] on chain[%d], check: must be < %d\n",chain_vol_value[i],vol_pic,i,vol_value_limited); + writeLogFile(logstr); + + if(chain_vol_value[i] > vol_value_limited) // we will set voltage to the highest voltage for the last chance on test patten + { + chain_vol_value[i]=vol_value_limited; + sprintf(logstr,"will set the voltage limited on chain[%d], change voltage=%d\n",i,chain_vol_value[i]); + writeLogFile(logstr); + + vol_pic=getPICvoltageFromValue(chain_vol_value[i]); + sprintf(logstr,"now set pic voltage=%d on chain[%d]\n",vol_pic,i); + writeLogFile(logstr); + + pthread_mutex_lock(&iic_mutex); + set_pic_voltage(i, vol_pic); + pthread_mutex_unlock(&iic_mutex); + + someBoardUpVoltage=true; + } + } +#endif + + reset_work_data(); + + cgpu.CommandMode = 0; + cgpu.AsicType = ASIC_TYPE; + cgpu.asicNum = conf.asicNum; + cgpu.real_asic_num = CHAIN_ASIC_NUM; + cgpu.core_num = conf.core; + + pthread_mutex_lock(&opencore_readtemp_mutex); + FOR_LOOP_CHAIN + { + if(cgpu.chain_exist[i]==0) + continue; + + cgpu.chain_asic_num[i]=getChainAsicNum(i); + + if(chain_need_opencore[i]) + { + sprintf(logstr,"do open core on Chain[%d]...\n",i); + writeLogFile(logstr); + + open_core_one_chain(i,true); + + sprintf(logstr,"Done open core on Chain[%d]!\n",i); + writeLogFile(logstr); + } + } + pthread_mutex_unlock(&opencore_readtemp_mutex); + + // before the first time for sending work, reset the FPGA's nonce fifo + if(!gBegin_get_nonce) + { + //printf("\n--- clear nonce fifo before send work\n"); + printf("clement2 set_nonce_fifo_interrupt\n"); + set_nonce_fifo_interrupt(get_nonce_fifo_interrupt() | FLUSH_NONCE3_FIFO); + gBegin_get_nonce = true; + } + + FOR_LOOP_CHAIN + { + if(cgpu.chain_exist[i]==0) + continue; + + sprintf(logstr,"start send works on chain[%d]\n",i); + writeLogFile(logstr); + + StartSendFlag[i]=true; + } + + send_func_all(); + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(cgpu.chain_exist[i]==0) + continue; + + sprintf(logstr,"wait recv nonce on chain[%d]\n",i); + writeLogFile(logstr); + + last_recv_num=0; + wait_count=0; + while(wait_count < RECV_WAIT_TIMEOUT && valid_nonce_num[i]0 && isChainEnough()) // up voltage is not suitable for T9+ + { + sprintf(logstr,"Try to add voltage on chain[%d]...\n",i); + writeLogFile(logstr); + + vol_value=getVoltageLimitedFromHashrate(GetTotalRate()); + + if(test_times>=PRE_HEAT_TEST_COUNT-1 && chain_vol_value[i]0) + { + ret = cgpu_init(); + if(ret < 0) + { + printf("cgpu_init Error!\n"); + return false; + } + + ret = configMiner(); + if(ret < 0) + { + printf("configMiner Error!\n"); + return false; + } + + init_once=0; + + printf("single board test start\n"); + + Conf.DataCount=conf.dataCount=TESTMODE_PATTEN_NUM; // fixed to 114 + Conf.PassCount1=conf.passCount1=TESTMODE_PATTEN_NUM; + Conf.PassCount2=conf.passCount2=TESTMODE_PATTEN_NUM; + Conf.PassCount3=conf.passCount3=TESTMODE_PATTEN_NUM; + Conf.ValidNonce1=conf.ValidNonce1=TESTMODE_NONCE_NUM; + Conf.ValidNonce2=conf.ValidNonce2=TESTMODE_NONCE_NUM; + Conf.ValidNonce3=conf.ValidNonce3=TESTMODE_NONCE_NUM; + + ExitFlag=false; + + receiveExit=false; + pthread_create(&cgpu.receive_id, NULL, receive_func, &cgpu); + + for(i=0; i0) + { + ret = cgpu_init(); + if(ret < 0) + { + printf("cgpu_init Error!\n"); + return false; + } + + ret = configMiner(); + if(ret < 0) + { + printf("configMiner Error!\n"); + return false; + } + + init_once=0; + + printf("single board test start\n"); + + Conf.DataCount=conf.dataCount=TESTMODE_PATTEN_NUM; // fixed to 114 + Conf.PassCount1=conf.passCount1=TESTMODE_PATTEN_NUM; + Conf.PassCount2=conf.passCount2=TESTMODE_PATTEN_NUM; + Conf.PassCount3=conf.passCount3=TESTMODE_PATTEN_NUM; + Conf.ValidNonce1=conf.ValidNonce1=TESTMODE_NONCE_NUM; + Conf.ValidNonce2=conf.ValidNonce2=TESTMODE_NONCE_NUM; + Conf.ValidNonce3=conf.ValidNonce3=TESTMODE_NONCE_NUM; + + ExitFlag=false; + + receiveExit=false; + pthread_create(&cgpu.receive_id, NULL, receive_func, &cgpu); + + for(i=0; i + * Copyright 2016-2017 Clement Duan + * + * 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 __BITMAIN_BOARD_TEST_H__ +#define __BITMAIN_BOARD_TEST_H__ +#include + +#define MAX_ASIC_NUM 128 +#define MAX_WORK 5000 + +#define FIL 0x1 +#define VIL 0x0 + +struct configuration +{ + bool AutoStart; + bool Gray; + int NonceMask; //??? + int DataCount; + int PassCount1; + int PassCount2; + int PassCount3; + int Freq; + int Timeout; + bool Regulate; + int Value; + int ReadIntervalTimeout; + int AddrInterval; + int CoreNum; + int AsicNum; + int UseFreqPIC; + int TestMode; + int CheckChain; + int CommandMode; + int AsicType; + int ValidNonce1; + int ValidNonce2; + int ValidNonce3; + unsigned int Pic; + unsigned int Voltage1; + unsigned int Voltage2; + unsigned int Voltage3; + unsigned int final_voltage1; + unsigned int final_voltage2; + unsigned int final_voltage3; + unsigned int freq_gap; + int OpenCoreGap; + int checktemp; + unsigned int IICPic; + unsigned int OpenCoreNum1; + unsigned int OpenCoreNum2; + unsigned int OpenCoreNum3; + unsigned int OpenCoreNum4; + unsigned int dac; + unsigned int GetTempFrom; + unsigned int TempSel; + unsigned int TempSensor1; + unsigned int TempSensor2; + unsigned int TempSensor3; + unsigned int TempSensor4; + signed char DefaultTempOffset; + int freq_e; + int freq_m; + int freq_a; + int freq_t; + int force_freq; + int UseConfigVol; + int StartSensor; + int StartTemp; + int year; + int month; + int date; + int hour; + int minute; + int second; +}; + +struct _CONFIG +{ + int dataCount; + int passCount1; + int passCount2; + int passCount3; + int core; + int freq; + int timeout; + int baud; + bool regulate; + int value; + int addrInterval; + int asicNum; + int testMode; + int CommandMode; + int AsicType; + int ValidNonce1; + int ValidNonce2; + int ValidNonce3; + unsigned int Pic; + unsigned int Voltage1; + unsigned int Voltage2; + unsigned int Voltage3; + int OpenCoreGap; + int checktemp; + unsigned int IICPic; + int UseFreqPIC; + unsigned int freq_gap; + unsigned int OpenCoreNum1; + unsigned int OpenCoreNum2; + unsigned int OpenCoreNum3; + unsigned int OpenCoreNum4; + unsigned int dac; + unsigned int GetTempFrom; + unsigned int TempSel; + unsigned char TempSensor1; + unsigned char TempSensor2; + unsigned char TempSensor3; + unsigned char TempSensor4; + signed char DefaultTempOffset; + int freq_e; + int freq_m; + int freq_a; + int freq_t; + int force_freq; + int UseConfigVol; + unsigned char StartSensor; + signed char StartTemp; + int year; + int month; + int date; + int hour; + int minute; + int second; +}; + +struct testpatten_work +{ + int id; + uint32_t nonce; /* For devices that hash sole work */ + unsigned char data[12]; + unsigned char midstate[32]; +}; + +struct testpatten_cgpu_info +{ + FILE * fps[MAX_ASIC_NUM]; + + pthread_t receive_id, show_id, pic_heart_beat_id, read_temp,freq_id; + pthread_t send_id[BITMAIN_MAX_CHAIN_NUM]; + int device_fd; + int lcd_fd; + + char workdataPathPrefix[64]; + struct testpatten_work *works[MAX_ASIC_NUM]; + //int work_array[MAX_ASIC_NUM]; //work number of every asic + uint32_t results[MAX_ASIC_NUM][MAX_WORK]; + int result_array[MAX_ASIC_NUM]; //return nonce number of every asic + int subid[MAX_ASIC_NUM]; + int min_work_subid; + int index; + int valid_nonce; + int err_nonce; + int repeated_nonce; + + int start_key_fd; + int red_led_fd; + int green_led_fd; + int beep_fd; + + unsigned int real_asic_num; + unsigned int asicNum; + unsigned int core_num; + int freq_e; + int freq_m; + int freq_a; + int freq_t; + int AsicType; + unsigned int chain_num; + unsigned short int frequency; + unsigned int CommandMode; // 1:fil 0:vil + unsigned int chain_exist[BITMAIN_MAX_CHAIN_NUM]; + unsigned int timeout; + unsigned char chain_asic_num[BITMAIN_MAX_CHAIN_NUM]; + unsigned int addrInterval; + unsigned char baud; + unsigned short int freq[BITMAIN_MAX_CHAIN_NUM]; + unsigned int max_asic_num_in_one_chain; + unsigned char temp_sel; + unsigned char rfs; + unsigned char tfs; + signed char T1_offset_value; + signed char T2_offset_value; + signed char T3_offset_value; + signed char T4_offset_value; +}; + +#define PRE_HEAT_TEST_COUNT 2 + +#undef CHECK_ALLNONCE_ADD_VOLTAGE_USERMODE //if defined, when in user mode (restartNum>0), then check nonce num in test patten, if failed, add 0.1V voltage , must according to hashrate + +#define RETRY_FREQ_INDEX 12 // 400M, if search base freq < 400M, will switch to use RETRY_VOLTAGE to search again. +#define REBOOT_TEST_NUM 2 // save into file + +#define ENABLE_SEARCH_LOGFILE //enable log info into kernel info web page. +#define LOG_CHIPS_CORE_DETAIL // if enabled , will show details nonce number info for chips and cores, open for debug + +#define TEST_MODE_OK_NUM 2 // if 8xPatten test mode test OK counter >= TEST_MODE_OK_NUM, then this board is OK, 3 + +#define SEARCH_FREQ_CHANCE_NUM 2 // give each board 2 chances to search freq, the first failed, we can add voltage SEARCH_VOLTAGE_ADD_STEP to search for next chance +#define SEARCH_VOLTAGE_ADD_STEP 30 // means, each chance will add 0.3V to search freq again. + +#define SEARCH_BASEFREQ_PATTEN_NUM 912 +#define SEARCH_BASEFREQ_NONCE_NUM (SEARCH_BASEFREQ_PATTEN_NUM*CHAIN_ASIC_NUM) + +#define SEARCH_FREQ_PATTEN_NUM 114 +#define SEARCH_FREQ_NONCE_NUM (SEARCH_FREQ_PATTEN_NUM*CHAIN_ASIC_NUM) + +#define TESTMODE_PATTEN_NUM 912 +#define TESTMODE_NONCE_NUM (TESTMODE_PATTEN_NUM*CHAIN_ASIC_NUM) + +#define DEFAULT_TEMP_OFFSET -70 + +#define FOR_LOOP_CHAIN for(i=0; i +#include "driver-btm-soc.h" +#endif + + #ifdef USE_COINTERRA #include "driver-cointerra.h" #endif @@ -409,6 +415,24 @@ pthread_cond_t gws_cond; double rolling1, rolling5, rolling15; double total_rolling; double total_mhashes_done; + +#ifdef USE_BITMAIN_SOC +char *opt_version_path = NULL; +char displayed_hash_rate[16] = {0}; +char nonce_num10_string[NONCE_BUFF]; +char nonce_num30_string[NONCE_BUFF]; +char nonce_num60_string[NONCE_BUFF]; +char g_miner_version[256] = {0}; +char g_miner_compiletime[256] = {0}; +char g_miner_type[256] = {0}; + +double new_total_mhashes_done; +double new_total_secs = 1.0; +// only used for total_secs, because we need use system info time, instead of real data time. +time_t total_tv_start_sys; +time_t total_tv_end_sys; +#endif + static struct timeval total_tv_start, total_tv_end; static struct timeval restart_tv_start, update_tv_start; @@ -1272,6 +1296,15 @@ static char *set_null(const char __maybe_unused *arg) return NULL; } +#ifdef USE_BITMAIN_SOC +static char *set_version_path(const char *arg) +{ + opt_set_charp(arg, &opt_version_path); + + return NULL; +} +#endif + /* These options are available from config file or commandline */ static struct opt_table opt_config_table[] = { #ifdef USE_ICARUS @@ -1681,6 +1714,39 @@ static struct opt_table opt_config_table[] = { set_int_0_to_100, NULL, &opt_bf16_alarm_temp, "Set control board alarm temperature range (0 - 100)"), #endif +#ifdef USE_BITMAIN_SOC + OPT_WITH_ARG("--version-file", + set_version_path, NULL, opt_hidden, + "Set miner version file"), + + OPT_WITHOUT_ARG("--bitmain-fan-ctrl", + opt_set_bool, &opt_bitmain_fan_ctrl, + "Enable bitmain miner fan controlling"), + + OPT_WITH_ARG("--bitmain-fan-pwm", + set_int_0_to_100, opt_show_intval, &opt_bitmain_fan_pwm, + "Set bitmain fan pwm percentage 0~100"), + + OPT_WITH_ARG("--bitmain-freq", + set_int_0_to_9999,opt_show_intval, &opt_bitmain_soc_freq, + "Set frequency"), + + OPT_WITH_ARG("--bitmain-voltage", + set_int_0_to_9999,opt_show_intval, &opt_bitmain_soc_voltage, + "Set voltage"), + + OPT_WITHOUT_ARG("--fixed-freq", + opt_set_bool, &opt_fixed_freq, + "Set bitmain miner use fixed freq"), + + OPT_WITHOUT_ARG("--no-pre-heat", + opt_set_false, &opt_pre_heat, + "Set bitmain miner doesn't pre heat"), + + OPT_WITH_ARG("--multi-version", + opt_set_intval, NULL, &opt_multi_version, + "Multi version mining!"), +#endif #ifdef USE_BLOCKERUPTER OPT_WITH_ARG("--bet-clk", opt_set_intval, opt_show_intval, &opt_bet_clk, @@ -4854,6 +4920,9 @@ static void _copy_work(struct work *work, const struct work *base_work, int noff } if (base_work->coinbase) work->coinbase = strdup(base_work->coinbase); +#ifdef USE_BITMAIN_SOC + work->version = base_work->version; +#endif } void set_work_ntime(struct work *work, int ntime) @@ -5694,7 +5763,20 @@ static time_t hashdisplay_t; void zero_stats(void) { int i; +#ifdef USE_BITMAIN_SOC + struct sysinfo sInfo; + if (sysinfo(&sInfo)) + { + applog(LOG_INFO, "Failed to get sysinfo, errno:%u, reason:%s\n", + errno, strerror(errno)); + total_tv_start_sys=time(NULL); + } + else + { + total_tv_start_sys=sInfo.uptime; + } +#endif cgtime(&total_tv_start); copy_time(&tv_hashmeter, &total_tv_start); total_rolling = 0; @@ -5702,6 +5784,9 @@ void zero_stats(void) rolling5 = 0; rolling15 = 0; total_mhashes_done = 0; +#ifdef USE_BITMAIN_SOC + new_total_mhashes_done = 0; +#endif total_getworks = 0; total_accepted = 0; total_rejected = 0; @@ -5712,6 +5797,9 @@ void zero_stats(void) total_go = 0; total_ro = 0; total_secs = 1.0; +#ifdef USE_BITMAIN_SOC + new_total_secs = 1.0; +#endif total_diff1 = 0; found_blocks = 0; total_diff_accepted = 0; @@ -6415,6 +6503,20 @@ static void hashmeter(int thr_id, uint64_t hashes_done) time_t now_t; int diff_t; +#ifdef USE_BITMAIN_SOC + struct sysinfo sInfo; + if (sysinfo(&sInfo)) + { + applog(LOG_INFO, "Failed to get sysinfo, errno:%u, reason:%s\n", + errno, strerror(errno)); + total_tv_end_sys=time(NULL); + } + else + { + total_tv_end_sys=sInfo.uptime; + } +#endif + cgtime(&total_tv_end); tv_tdiff = tdiff(&total_tv_end, &tv_hashmeter); now_t = total_tv_end.tv_sec; @@ -6489,7 +6591,11 @@ static void hashmeter(int thr_id, uint64_t hashes_done) decay_time(&rolling5, hashes_done, tv_tdiff, 300.0); decay_time(&rolling15, hashes_done, tv_tdiff, 900.0); global_hashrate = llround(total_rolling) * 1000000; +#ifndef USE_BITMAIN_SOC total_secs = tdiff(&total_tv_end, &total_tv_start); +#else + total_secs = total_tv_end_sys*1.0-total_tv_start_sys*1.0; +#endif if (showlog) { char displayed_hashes[16], displayed_rolling[16]; char displayed_r1[16], displayed_r5[16], displayed_r15[16]; @@ -7489,6 +7595,40 @@ bool submit_nonce2_nonce(struct thr_info *thr, struct pool *pool, struct pool *r } #endif +#ifdef USE_BITMAIN_SOC +void get_work_by_nonce2(struct thr_info *thr, + struct work **work, + struct pool *pool, + struct pool *real_pool, + uint64_t nonce2, + uint32_t ntime, + uint32_t version) +{ + *work = make_work(); + const int thr_id = thr->id; + struct cgpu_info *cgpu = thr->cgpu; + struct device_drv *drv = cgpu->drv; + cg_wlock(&pool->data_lock); + pool->nonce2 = nonce2; + //if(pool->support_vil) // comment as default + version = Swap32(version); + cg_memcpy(pool->header_bin, &version, 4); + cg_wunlock(&pool->data_lock); + + gen_stratum_work(pool, *work); + + (*work)->pool = real_pool; + + (*work)->thr_id = thr_id; + (*work)->work_block = work_block; + (*work)->pool->works++; + + (*work)->mined = true; + (*work)->version = version; +} +#endif + + /* Generates stratum based work based on the most recent notify information * from the pool. This will keep generating work while a pool is down so we use * other means to detect when the pool has died in stratum_thread */ @@ -9228,6 +9368,20 @@ void print_summary(void) static void clean_up(bool restarting) { +#ifdef USE_BITMAIN_SOC + struct sysinfo sInfo; + if (sysinfo(&sInfo)) + { + applog(LOG_INFO, "Failed to get sysinfo, errno:%u, reason:%s\n", + errno, strerror(errno)); + total_tv_end_sys=time(NULL); + } + else + { + total_tv_end_sys=sInfo.uptime; + } +#endif + #ifdef USE_USBUTILS usb_polling = false; pthread_join(usb_poll_thread, NULL); @@ -9970,6 +10124,31 @@ static void initialise_usb(void) { #define initialise_usb() {} #endif +#ifdef USE_BITMAIN_SOC +void setStartTimePoint() +{ + char logstr[256]; + struct sysinfo sInfo; + if (sysinfo(&sInfo)) + { + sprintf(logstr, "Failed to get sysinfo, errno:%u, reason:%s\n", + errno, strerror(errno)); + writeInitLogFile(logstr); + + total_tv_start_sys=time(NULL); + total_tv_end_sys=total_tv_start_sys+1; + } + else + { + total_tv_start_sys=sInfo.uptime; + total_tv_end_sys=total_tv_start_sys+1; + + sprintf(logstr, "setStartTimePoint total_tv_start_sys=%d total_tv_end_sys=%d\n",total_tv_start_sys, total_tv_end_sys); + writeInitLogFile(logstr); + } +} +#endif + int main(int argc, char *argv[]) { struct sigaction handler; @@ -10113,6 +10292,65 @@ int main(int argc, char *argv[]) set_target(bench_target, 32); } +#ifdef USE_BITMAIN_SOC + if(opt_version_path) + { + FILE * fpversion = fopen(opt_version_path, "rb"); + char tmp[256] = {0}; + int len = 0; + char * start = 0; + + if(fpversion == NULL) + { + applog(LOG_ERR, "Open miner version file %s error", opt_version_path); + } + else + { + len = fread(tmp, 1, 256, fpversion); + + if(len <= 0) + { + applog(LOG_ERR, "Read miner version file %s error %d", opt_version_path, len); + } + else + { + start = strstr(tmp, "\n"); + + if(start == NULL) + { + strcpy(g_miner_compiletime, tmp); + } + else + { + cg_memcpy(g_miner_compiletime, tmp, start-tmp); + strcpy(g_miner_type, start+1); + } + + if(g_miner_compiletime[strlen(g_miner_compiletime)-1] == '\n') + { + g_miner_compiletime[strlen(g_miner_compiletime)-1] = 0; + } + + if(g_miner_compiletime[strlen(g_miner_compiletime)-1] == '\r') + { + g_miner_compiletime[strlen(g_miner_compiletime)-1] = 0; + } + + if(g_miner_type[strlen(g_miner_type)-1] == '\n') + { + g_miner_type[strlen(g_miner_type)-1] = 0; + } + + if(g_miner_type[strlen(g_miner_type)-1] == '\r') + { + g_miner_type[strlen(g_miner_type)-1] = 0; + } + } + } + applog(LOG_ERR, "Miner compile time: %s type: %s", g_miner_compiletime, g_miner_type); + } +#endif + #ifdef HAVE_CURSES if (opt_realquiet || opt_display_devs || opt_decode) use_curses = false; @@ -10346,6 +10584,21 @@ int main(int argc, char *argv[]) cgpu->rolling = cgpu->total_mhashes = 0; } +#ifdef USE_BITMAIN_SOC + struct sysinfo sInfo; + if (sysinfo(&sInfo)) + { + applog(LOG_INFO, "Failed to get sysinfo, errno:%u, reason:%s\n", + errno, strerror(errno)); + total_tv_end_sys=time(NULL); + total_tv_start_sys=time(NULL); + } + else + { + total_tv_end_sys=sInfo.uptime; + total_tv_start_sys=sInfo.uptime; + } +#endif cgtime(&total_tv_start); cgtime(&total_tv_end); cgtime(&tv_hashmeter); diff --git a/configure.ac b/configure.ac index 4d017e4ea7..50a2db8587 100644 --- a/configure.ac +++ b/configure.ac @@ -64,6 +64,7 @@ AC_FUNC_ALLOCA have_win32=false PTHREAD_FLAGS="-lpthread" +LIBZ_LIBS="-lz" DLOPEN_FLAGS="-ldl" WS2_LIBS="" MM_LIBS="" @@ -82,8 +83,6 @@ case $target in ;; esac -CFLAGS="$CFLAGS -Wimplicit-fallthrough=0" - case $target in *-*-linux-gnu*) have_linux=true @@ -298,6 +297,53 @@ if test "x$bitfury16" = xyes; then fi AM_CONDITIONAL([HAS_BITFURY16], [test x$bitfury16 = xyes]) +bitmain_soc="no" +bitmain_R4="no" +bitmain_S9="no" +bitmain_T9="no" +bitmain_T9P="no" + +AC_ARG_ENABLE([bitmain_soc], + [AC_HELP_STRING([--enable-bitmain_soc],[Compile support for Bitmain ASICs STANDALONE(default disabled)])], + [bitmain_soc=$enableval] + ) +AC_ARG_ENABLE([bitmain_R4], + [AC_HELP_STRING([--enable-bitmain_R4],[Compile support for Bitmain R4])], + [bitmain_R4=$enableval] + ) +AC_ARG_ENABLE([bitmain_S9], + [AC_HELP_STRING([--enable-bitmain_S9],[Compile support for Bitmain S9])], + [bitmain_S9=$enableval] + ) +AC_ARG_ENABLE([bitmain_T9], + [AC_HELP_STRING([--enable-bitmain_T9],[Compile support for Bitmain T9])], + [bitmain_T9=$enableval] + ) +AC_ARG_ENABLE([bitmain_T9P], + [AC_HELP_STRING([--enable-bitmain_T9P],[Compile support for Bitmain T9+])], + [bitmain_T9P=$enableval] + ) +if test "x$bitmain_soc" = xyes; then + AC_DEFINE([USE_BITMAIN_SOC], [1], [Defined to 1 if Bitmain ASICs support is wanted]) + if test "x$bitmain_R4" = xyes; then + AC_DEFINE([R4], [1], [Defined to 1 for R4]) + fi + if test "x$bitmain_S9" = xyes; then + AC_DEFINE([S9_63], [1], [Defined to 1 for S9]) + fi + if test "x$bitmain_T9" = xyes; then + AC_DEFINE([S9_PLUS], [1], [Defined to 1 for T9]) + fi + if test "x$bitmain_T9P" = xyes; then + AC_DEFINE([T9_18], [1], [Defined to 1 for T9+]) + fi + if test "x$bitmain_R4$bitmain_S9$bitmain_T9$bitmain_T9P" = xnononono; then + AC_DEFINE([S9_63], [1], [Defined to 1 for default]) + fi + drivercount=x$drivercount + standalone="yes" +fi +AM_CONDITIONAL([HAS_BITMAIN_SOC], [test x$bitmain_soc = xyes]) bitmine_A1="no" @@ -545,6 +591,7 @@ fi AM_CONDITIONAL([NEED_FPGAUTILS], [test x$modminer != xno]) AM_CONDITIONAL([WANT_USBUTILS], [test x$want_usbutils != xfalse]) +AM_CONDITIONAL([NEED_LIBZ], [test x$bitmain_soc != xno]) AM_CONDITIONAL([WANT_LIBBITFURY], [test x$want_libbitfury != xfalse]) AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes]) AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue]) @@ -691,6 +738,7 @@ fi AC_DEFINE_UNQUOTED([CGMINER_PREFIX], ["$prefix/bin"], [Path to cgminer install]) AC_SUBST(JANSSON_LIBS) +AC_SUBST(LIBZ_LIBS) AC_SUBST(PTHREAD_FLAGS) AC_SUBST(DLOPEN_FLAGS) AC_SUBST(PTHREAD_LIBS) @@ -827,6 +875,13 @@ else echo " BitFury16.ASICs......: Disabled" fi +if test "x$bitmain_soc" = xyes; then + echo " Bitmain.ASICs......: Enabled" +else + echo " Bitmain.ASICs......: Disabled" +fi + + if test "x$blockerupter" = xyes; then echo " BlockErupter.ASICs...: Enabled" else @@ -907,7 +962,7 @@ else fi #Add any new device to this, along with a no on the end of the test -if test "x$avalon$avalon2$avalon4$avalon7$avalon_miner$bab$bflsc$bitforce$bitfury$bitfury16$blockerupter$hashfast$hashratio$icarus$klondike$knc$modminer$drillbit$minion$cointerra$bitmine_A1$ants1$ants2$ants3$sp10$sp30$dragonmint_t1" = xnonononononononononononononononononononononononononono; then +if test "x$avalon$avalon2$avalon4$avalon7$avalon_miner$bab$bflsc$bitforce$bitfury$bitfury16$bitmain_soc$blockerupter$hashfast$hashratio$icarus$klondike$knc$modminer$drillbit$minion$cointerra$bitmine_A1$ants1$ants2$ants3$sp10$sp30$dragonmint_t1" = xnononononononononononononononononononononononononononono; then echo AC_MSG_ERROR([No mining devices configured in]) echo @@ -926,7 +981,7 @@ echo "Compilation............: make (or gmake)" echo " CPPFLAGS.............: $CPPFLAGS" echo " CFLAGS...............: $CFLAGS" echo " LDFLAGS..............: $LDFLAGS $PTHREAD_FLAGS" -echo " LDADD................: $DLOPEN_FLAGS $LIBCURL_LIBS $LIBSYSTEMD_LIBS $JANSSON_LIBS $PTHREAD_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $LIBUSB_LIBS $RT_LIBS" +echo " LDADD................: $DLOPEN_FLAGS $LIBCURL_LIBS $LIBSYSTEMD_LIBS $JANSSON_LIBS $LIBZ_LIBS $PTHREAD_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $LIBUSB_LIBS $RT_LIBS" echo echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')" echo " prefix...............: $prefix" diff --git a/driver-btm-soc.c b/driver-btm-soc.c new file mode 100644 index 0000000000..1d158b13a8 --- /dev/null +++ b/driver-btm-soc.c @@ -0,0 +1,11793 @@ +/* + * Copyright 2016-2017 Fazio Bai + * Copyright 2016-2017 Clement Duan + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. See COPYING for more details. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#ifndef WIN32 +#include +#include +#include +#include +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif +#else +#include "compat.h" +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elist.h" +#include "miner.h" +// #include "usbutils.h" +#include "util.h" +#include "driver-btm-soc.h" +#include "sha2-soc.h" + + +#define MAX_CHAR_NUM 1024 + +extern void reCalculateAVG(); +extern void setStartTimePoint(); + +bool someBoardUpVoltage=false; +bool isUseDefaultFreq=false; + +bool doTestPatten=false; +bool startCheckNetworkJob=false; + +unsigned char reset_iic_pic(unsigned char chain); + +extern bool clement_doTestBoard(bool showlog); +bool clement_doTestBoardOnce(bool showlog); + +#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 + +static void hexdump(const uint8_t *p, unsigned int len) +{ + unsigned int i, addr; + unsigned int wordlen = sizeof(unsigned int); + 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); + } +} + +#ifdef R4 +int MIN_PWM_PERCENT; +int MID_PWM_PERCENT; +int MAX_PWM_PERCENT; +int MAX_TEMP; +int MAX_FAN_TEMP; +int MID_FAN_TEMP; +int MIN_FAN_TEMP; +int MAX_PCB_TEMP; +int MAX_FAN_PCB_TEMP; +#endif + +bool is218_Temp=false; + +//interface between bmminer and axi driver +static struct init_config config_parameter; + +//global various +int fd; // axi fpga +int fd_fpga_mem; // fpga memory +int fpga_version; +int pcb_version; +unsigned int *axi_fpga_addr = NULL; // axi address +unsigned int *fpga_mem_addr = NULL; // fpga memory address +unsigned int *nonce2_jobid_address = NULL; // the value should be filled in NONCE2_AND_JOBID_STORE_ADDRESS +unsigned int *job_start_address_1 = NULL; // the value should be filled in JOB_START_ADDRESS +unsigned int *job_start_address_2 = NULL; // the value should be filled in JOB_START_ADDRESS +struct thr_info *read_nonce_reg_id; // thread id for read nonce and register +struct thr_info *check_system_work_id; // thread id for check system +struct thr_info *read_temp_id; +struct thr_info *pic_heart_beat; +struct thr_info *change_voltage_to_old; + +extern void writeLogFile(char *logstr); + + +bool gBegin_get_nonce = false; +struct timeval tv_send_job = {0, 0}; +struct timeval tv_send = {0, 0}; + +pthread_mutex_t reg_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t nonce_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t iic_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t fpga_mutex = PTHREAD_MUTEX_INITIALIZER; + +pthread_mutex_t opencore_readtemp_mutex = PTHREAD_MUTEX_INITIALIZER; + +uint64_t h = 0; + +int opt_multi_version = 1; +uint32_t given_id = 2; +uint32_t c_coinbase_padding = 0; +uint32_t c_merkles_num = 0; +uint32_t l_coinbase_padding = 0; +uint32_t l_merkles_num = 0; +int last_temperature = 0, temp_highest = 0; + +bool opt_bitmain_fan_ctrl = false; +int opt_bitmain_fan_pwm = 0; +int opt_bitmain_soc_freq = 600; +int opt_bitmain_soc_voltage = 176; +int ADD_FREQ = 0; +int ADD_FREQ1 = 0; +uint8_t de_voltage = 176; + +#define ERROR_OVER_MAXTEMP 1 // temp is too high +#define ERROR_FAN_LOST 2 // fan num is not right, some fan lost +#define ERROR_FAN_SPEED 3 // fan speed error +#define ERROR_UNKOWN_STATUS 4 // unkown error, never get this! +int FatalErrorValue=0; + +bool opt_bitmain_new_cmd_type_vil = false; +bool opt_fixed_freq = false; +bool opt_pre_heat = true; + +bool status_error = false; +bool once_error = false; +bool iic_ok = false; +int check_iic = 0; +bool update_temp =false; +bool check_temp_offside = false; + +double chain_asic_RT[BITMAIN_MAX_CHAIN_NUM][CHAIN_ASIC_NUM]= {0}; + +uint64_t rate[BITMAIN_MAX_CHAIN_NUM] = {0}; +uint64_t nonce_num[BITMAIN_MAX_CHAIN_NUM][BITMAIN_DEFAULT_ASIC_NUM][TIMESLICE] = {0}; +int nonce_times = 0; +int rate_error[BITMAIN_MAX_CHAIN_NUM] = {0}; +char displayed_rate[BITMAIN_MAX_CHAIN_NUM][32]; + +uint8_t chain_voltage_pic[BITMAIN_MAX_CHAIN_NUM] = {0xff}; +int chain_voltage_value[BITMAIN_MAX_CHAIN_NUM] = {0}; + +unsigned char hash_board_id[BITMAIN_MAX_CHAIN_NUM][12]; + +int lowest_testOK_temp[BITMAIN_MAX_CHAIN_NUM]= {0}; // board test patten OK, we record temp in PIC, then we need keep board temp >= this lowest temp +int chain_temp_toolow[BITMAIN_MAX_CHAIN_NUM]= {0}; + +int LOWEST_TEMP_DOWN_FAN=MIN_TEMP_CONTINUE_DOWN_FAN; + +#ifdef T9_18 +unsigned char chain_pic_buf[BITMAIN_MAX_CHAIN_NUM][128] = {0}; +#else +unsigned char last_freq[BITMAIN_MAX_CHAIN_NUM][256] = {0}; +unsigned char badcore_num_buf[BITMAIN_MAX_CHAIN_NUM][64] = {0}; +#endif + +int chain_badcore_num[BITMAIN_MAX_CHAIN_NUM][256] = {0}; + +unsigned char show_last_freq[BITMAIN_MAX_CHAIN_NUM][256] = {0}; // only used to showed to users +unsigned char chip_last_freq[BITMAIN_MAX_CHAIN_NUM][256] = {0}; // this is the real value , which set freq into chips + +unsigned char pic_temp_offset[BITMAIN_MAX_CHAIN_NUM] = {0}; +unsigned char base_freq_index[BITMAIN_MAX_CHAIN_NUM] = {0}; + +int x_time[BITMAIN_MAX_CHAIN_NUM][256] = {0}; +int temp_offside[BITMAIN_MAX_CHAIN_NUM] = {0}; + +static bool global_stop = false; + +//Test Core +static int test_core = 8; + + +struct nonce_content temp_nonce_buf[MAX_RETURNED_NONCE_NUM]; +struct reg_content temp_reg_buf[MAX_RETURNED_NONCE_NUM]; +volatile struct nonce_buf nonce_read_out; +volatile struct reg_buf reg_value_buf; + + +#define USE_IIC 1 +#define TEMP_CALI 0 + +static int8_t bottom_Offset[BITMAIN_MAX_CHAIN_NUM][MAX_TEMPCHIP_NUM] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}; +static int8_t middle_Offset[BITMAIN_MAX_CHAIN_NUM][MAX_TEMPCHIP_NUM] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}; + +static int8_t bottom_Offset_sw[BITMAIN_MAX_CHAIN_NUM][MAX_TEMPCHIP_NUM] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}; +static int8_t middle_Offset_sw[BITMAIN_MAX_CHAIN_NUM][MAX_TEMPCHIP_NUM] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}; + +pthread_mutex_t init_log_mutex = PTHREAD_MUTEX_INITIALIZER; + +bool isC5_CtrlBoard=false; +bool isChainAllCoresOpened[BITMAIN_MAX_CHAIN_NUM]= {false}; // is all cores opened flag + +void set_led(bool stop); +void open_core(bool nullwork_enable); + +pthread_mutex_t reinit_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int reinit_counter=0; +void bitmain_core_reInit(); + +signed char getMeddleOffsetForTestPatten(int chainIndex) +{ + return middle_Offset[chainIndex][0]; +} + +unsigned int PHY_MEM_NONCE2_JOBID_ADDRESS=PHY_MEM_NONCE2_JOBID_ADDRESS_XILINX_1GB; // set to XILINX as default + +bool isFixedFreqMode() +{ + return opt_fixed_freq; +} + +bool isC5_Board() +{ + FILE *fd; + char board_type[32]; + int isC5=0; + + memset(board_type,'\0',32); + + fd=fopen("/usr/bin/ctrl_bd","rb"); + if(fd) + { + fread(board_type,1,32,fd); + fclose(fd); + + if(strstr(board_type,"XILINX")) + { + isC5=0; + } + else isC5=1; + } + else + { + isC5=1; + } + + if(isC5) + return true; + else return false; +} + +void software_set_address(); +void set_asic_ticket_mask(unsigned int ticket_mask); +void init_uart_baud(); +void open_core_one_chain(int chainIndex, bool nullwork_enable); +void getAsicNum_preOpenCore(int chainIndex); + +void writeInitLogFile(char *logstr); +void clearInitLogFile(); +void re_send_last_job(); +void saveSearchFailedFlagInfo(char *search_failed_info); + +extern void jump_to_app_CheckAndRestorePIC(int chainIndex); // defined in Clement-bitmain.c + +static unsigned char last_job_buffer[8192]= {23}; + +///////////// below they must be changed at same time!!!! /////////////////////// +typedef enum +{ + TEMP_BOTTOM = 0, // 0 is bottom , 1 is middle + TEMP_MIDDLE +} Temp_Type_E; +//////////////////////////////////////////////////////////////////////////// + +#define MAX_ERROR_LIMIT_ABS ( 2 ) +#define MAX_RETRY_COUNT ( 16 + 1 ) + + +void *gpio0_vaddr=NULL; +struct all_parameters *dev; +unsigned int is_first_job = 0; + +//other equipment related + +// -------------------------------------------------------------- +// CRC16 check table +// -------------------------------------------------------------- +const uint8_t chCRCHTalbe[] = // CRC high byte table +{ + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40 +}; + +const uint8_t chCRCLTalbe[] = // CRC low byte table +{ + 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, + 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, + 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, + 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, + 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, + 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, + 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, + 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, + 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, + 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, + 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, + 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, + 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, + 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, + 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, + 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, + 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, + 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, + 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, + 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, + 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, + 0x41, 0x81, 0x80, 0x40 +}; + + +//crc +uint16_t CRC16(const uint8_t* p_data, uint16_t w_len) +{ + uint8_t chCRCHi = 0xFF; // CRC high byte initialize + uint8_t chCRCLo = 0xFF; // CRC low byte initialize + uint16_t wIndex = 0; // CRC cycling index + + while (w_len--) + { + wIndex = chCRCLo ^ *p_data++; + chCRCLo = chCRCHi ^ chCRCHTalbe[wIndex]; + chCRCHi = chCRCLTalbe[wIndex]; + } + return ((chCRCHi << 8) | chCRCLo); +} + +unsigned char CRC5(unsigned char *ptr, unsigned char len) +{ + unsigned char i, j, k; + unsigned char crc = 0x1f; + + unsigned char crcin[5] = {1, 1, 1, 1, 1}; + unsigned char crcout[5] = {1, 1, 1, 1, 1}; + unsigned char din = 0; + + j = 0x80; + k = 0; + for (i = 0; i < len; i++) + { + if (*ptr & j) + { + din = 1; + } + else + { + din = 0; + } + crcout[0] = crcin[4] ^ din; + crcout[1] = crcin[0]; + crcout[2] = crcin[1] ^ crcin[4] ^ din; + crcout[3] = crcin[2]; + crcout[4] = crcin[3]; + + j = j >> 1; + k++; + if (k == 8) + { + j = 0x80; + k = 0; + ptr++; + } + memcpy(crcin, crcout, 5); + } + crc = 0; + if(crcin[4]) + { + crc |= 0x10; + } + if(crcin[3]) + { + crc |= 0x08; + } + if(crcin[2]) + { + crc |= 0x04; + } + if(crcin[1]) + { + crc |= 0x02; + } + if(crcin[0]) + { + crc |= 0x01; + } + return crc; +} + +unsigned char getPICvoltageFromValue(int vol_value) // vol_value = 940 means 9.4V +{ +#ifdef S9_PLUS +#ifdef S9_PLUS_VOLTAGE2 + unsigned char temp_voltage=1250.809516-127.817623*(vol_value*1.0)/100; +#else + unsigned char temp_voltage=824.784-73.1705*((vol_value*1.0)/100.0); +#endif +#endif + +#ifdef S9_63 + unsigned char temp_voltage = 1608.420446 - 170.423497*(vol_value*1.0)/100.0; +#endif + +#ifdef R4 + unsigned char temp_voltage = 1608.420446 - 170.423497*(vol_value*1.0)/100.0; +#endif + +#ifdef T9_18 + unsigned char temp_voltage = 364.0704 / (4.75*(vol_value*1.0)/100 - 32.79) - 30.72; +#endif + + return temp_voltage; +} + +int getVolValueFromPICvoltage(unsigned char vol_pic) +{ +#ifdef S9_PLUS +#ifdef S9_PLUS_VOLTAGE2 + int vol_value = ((1250.809516 - vol_pic)/127.817623)*100.0; +#else + int vol_value = ((824.784 - vol_pic)/73.1705)*100.0; +#endif +#endif + +#ifdef S9_63 + int vol_value = ((1608.420446 - vol_pic) *100.0)/170.423497; +#endif + +#ifdef R4 + int vol_value = ((1608.420446 - vol_pic) *100.0)/170.423497; +#endif + +#ifdef T9_18 + int vol_value = ((364.0704/(vol_pic+30.72))+32.79)*100/4.75; +#endif + + vol_value=(vol_value/10)*10; + + return vol_value; +} + +int getVoltageLimitedFromHashrate(int hashrate_GHz) +{ + int vol_value; + +#ifdef DEBUG_WITHOUT_FREQ_VOLTAGE_LIMIT + return 940; // just fixed to highest voltage +#endif + +#ifdef R4 + if(isC5_CtrlBoard) + vol_value=R4_MAX_VOLTAGE_C5; + else vol_value=R4_MAX_VOLTAGE_XILINX; +#endif + +#ifdef S9_PLUS + if(hashrate_GHz>=12500) + vol_value=840; + else if(hashrate_GHz>=12000) + vol_value=850; + else if(hashrate_GHz>=11500) + vol_value=870; + else if(hashrate_GHz>=11000) + vol_value=890; + else if(hashrate_GHz>=10500) + vol_value=910; + else if(hashrate_GHz>=10000) + vol_value=930; + else if(hashrate_GHz>=9500) + vol_value=960; + else if(hashrate_GHz>=9000) + vol_value=970; + else + vol_value=970; +#endif + +#ifdef S9_63 + if(hashrate_GHz>=14500) + vol_value=870; + else if(hashrate_GHz>=14000) + vol_value=880; + else if(hashrate_GHz>=13500) + vol_value=900; + else if(hashrate_GHz>=13000) + vol_value=910; + else if(hashrate_GHz>=12500) + vol_value=930; + else + vol_value=940; +#endif + +#ifdef T9_18 + if(hashrate_GHz>=12000) + vol_value=810; + else if(hashrate_GHz>=11500) + vol_value=830; + else if(hashrate_GHz>=11000) + vol_value=850; + else if(hashrate_GHz>=10500) + vol_value=870; + else if(hashrate_GHz>=10000) + vol_value=890; + else if(hashrate_GHz>=9500) + vol_value=920; + else if(hashrate_GHz>=9000) + vol_value=930; + else + vol_value=930; +#endif + + return vol_value; +} + +int getFixedFreqVoltageValue(int freq) +{ + int vol_value; +#ifdef R4 + if(isC5_CtrlBoard) + vol_value=890; + else vol_value=910; +#endif + +#ifdef S9_PLUS + if(freq>=643) // hashrate 12500 + vol_value=840; + else if(freq>=618) // hashrate 12000 + vol_value=850; + else if(freq>=593) // hashrate 11500 + vol_value=870; + else if(freq>=568) // hashrate 11000 + vol_value=890; + else if(freq>=543) // hashrate 10500 + vol_value=910; + else if(freq>=516) // hashrate 10000 + vol_value=930; + else if(freq>=491) // hashrate 9500 + vol_value=960; + else if(freq>=462) // hashrate 9000 + vol_value=970; + else + vol_value=970; +#endif + +#ifdef S9_63 + if(freq>=675) // hashrate 14500 + vol_value=870; + else if(freq>=650) // hashrate 14000 + vol_value=880; + else if(freq>=631) // hashrate 13500 + vol_value=900; + else if(freq>=606) // hashrate 13000 + vol_value=910; + else if(freq>=581) // hashrate 12500 + vol_value=930; + else + vol_value=940; +#endif + +#ifdef T9_18 + if(freq>=650) // hashrate 12000 + vol_value=810; + else if(freq>=625) // hashrate 11500 + vol_value=830; + else if(freq>=600) // hashrate 11000 + vol_value=850; + else if(freq>=575) // hashrate 10500 + vol_value=870; + else if(freq>=543) // hashrate 10000 + vol_value=890; + else if(freq>=516) // hashrate 9500 + vol_value=920; + else if(freq>=491) // hashrate 9000 + vol_value=930; + else + vol_value=930; +#endif + + return vol_value; + +} + +#ifdef T9_18 +void getPICChainIndexOffset(int chainIndex, int *pChain, int *pOffset) +{ + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + switch(chainIndex) + { + case 1: + new_T9_PLUS_chainIndex=1; + new_T9_PLUS_chainOffset=0; + break; + case 8: + new_T9_PLUS_chainIndex=1; + new_T9_PLUS_chainOffset=1; + break; + case 9: + new_T9_PLUS_chainIndex=1; + new_T9_PLUS_chainOffset=2; + break; + case 2: + new_T9_PLUS_chainIndex=2; + new_T9_PLUS_chainOffset=0; + break; + case 10: + new_T9_PLUS_chainIndex=2; + new_T9_PLUS_chainOffset=1; + break; + case 11: + new_T9_PLUS_chainIndex=2; + new_T9_PLUS_chainOffset=2; + break; + case 3: + new_T9_PLUS_chainIndex=3; + new_T9_PLUS_chainOffset=0; + break; + case 12: + new_T9_PLUS_chainIndex=3; + new_T9_PLUS_chainOffset=1; + break; + case 13: + new_T9_PLUS_chainIndex=3; + new_T9_PLUS_chainOffset=2; + break; + default: + new_T9_PLUS_chainIndex=0; + new_T9_PLUS_chainOffset=0; + break; + } + + *pChain=new_T9_PLUS_chainIndex; + *pOffset=new_T9_PLUS_chainOffset; +} +#endif + +int getChainAsicFreqIndex(int chainIndex, int asicIndex) +{ +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; // only used by new T9+ FPGA + getPICChainIndexOffset(chainIndex,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + + return chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+asicIndex]; + } + else + { + return chain_pic_buf[((chainIndex/3)*3)][7+(chainIndex%3)*31+4+asicIndex]; + } +#else + return last_freq[chainIndex][asicIndex*2+3]; +#endif +} + +// pic +unsigned int get_pic_iic() +{ + int ret = -1; + ret = *(axi_fpga_addr + IIC_COMMAND); + + applog(LOG_DEBUG,"%s: IIC_COMMAND is 0x%x\n", __FUNCTION__, ret); + return ret; +} + +unsigned char set_pic_iic(unsigned int data) +{ + unsigned int ret=0; + unsigned char ret_data = 0; + + *((unsigned int *)(axi_fpga_addr + IIC_COMMAND)) = data & 0x7fffffff; + applog(LOG_DEBUG,"%s: set IIC_COMMAND is 0x%x\n", __FUNCTION__, data & 0x7fffffff); + + while(1) + { + ret = get_pic_iic(); + if(ret & 0x80000000) + { + ret_data = (unsigned char)(ret & 0x000000ff); + return ret_data; + } + else + { + applog(LOG_DEBUG,"%s: waiting write pic iic\n", __FUNCTION__); + cgsleep_us(1000); + } + } +} + +unsigned char write_pic_iic(bool read, bool reg_addr_valid, unsigned char reg_addr, unsigned char chain, unsigned char data) +{ + unsigned int value = 0x00000000; + unsigned char ret = 0; + + if(read) + { + value |= IIC_READ; + } + + if(reg_addr_valid) + { + value |= IIC_REG_ADDR_VALID; + value |= IIC_REG_ADDR(reg_addr); + } + + value |= IIC_ADDR_HIGH_4_BIT; + + value |= IIC_CHAIN_NUMBER(chain); + + value |= data; + + ret = set_pic_iic(value); + + return ret; +} + +void send_pic_command(unsigned char chain) +{ + write_pic_iic(false, false, 0x0, chain, PIC_COMMAND_1); + write_pic_iic(false, false, 0x0, chain, PIC_COMMAND_2); +} + +void get_pic_iic_flash_addr_pointer(unsigned char chain, unsigned char *addr_H, unsigned char *addr_L); +void set_pic_iic_flash_addr_pointer(unsigned char chain, unsigned char addr_H, unsigned char addr_L) +{ + unsigned char check_addr_H, check_addr_L; + char logstr[1024]; + int try_count=0; + +#ifdef ENABLE_CHECK_PIC_FLASH_ADDR + do + { +#endif + send_pic_command(chain); + + write_pic_iic(false, false, 0x0, chain, SET_PIC_FLASH_POINTER); + write_pic_iic(false, false, 0x0, chain, addr_H); + write_pic_iic(false, false, 0x0, chain, addr_L); + + // we need check this address, because some PIC lost data of flash!!! + get_pic_iic_flash_addr_pointer(chain,&check_addr_H,&check_addr_L); + if(check_addr_H!=addr_H || check_addr_L!=addr_L) + { + sprintf(logstr,"Error of set PIC FLASH addr: addr_H=%x(%x) addr_L=%x(%x) on Chain[%d]\n",addr_H,check_addr_H,addr_L,check_addr_L,chain); + writeInitLogFile(logstr); +#ifndef ENABLE_CHECK_PIC_FLASH_ADDR + } +#else + try_count++; + if(try_count>3) + break; + + reset_iic_pic(chain); + sleep(5); + } + else break; + } + while(1); +#endif + } + + void send_data_to_pic_iic(unsigned char chain, unsigned char command, unsigned char *buf, unsigned char length) + { + int i=0; + + write_pic_iic(false, false, 0x0, chain, command); + for(i=0; i=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(chain,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + AT24C02_read_bytes(SENSOR_OFFSET_ADDR, value, new_T9_PLUS_chainIndex, 8); + } + else + { + AT24C02_read_bytes(SENSOR_OFFSET_ADDR, value, (chain/3), 8); + } + } +#else + void get_temperature_offset_value(unsigned char chain, unsigned char *value) + { + send_pic_command(chain); + get_data_from_pic_iic(chain, RD_TEMP_OFFSET_VALUE, value, 8); + } +#endif + + unsigned char write_data_into_pic_flash(unsigned char chain) + { + send_pic_command(chain); + + write_pic_iic(false, false, 0x0, chain, WRITE_DATA_INTO_PIC); + + usleep(100000); + + return 0; + } + +#ifdef T9_18 + int dsPIC33EP16GS202_get_pic_sw_version(unsigned char which_iic, unsigned char *version) + { + unsigned char length = 0x04, crc_data[2] = {0xff}, read_back_data[5] = {0xff}; + unsigned short crc = 0; + int retry_count=0; + char logstr[1024]; + + //printf("\n--- %s\n", __FUNCTION__); + + *version = 0xff; + + crc = length + GET_PIC_SOFTWARE_VERSION; + crc_data[0] = (unsigned char)((crc >> 8) & 0x00ff); + crc_data[1] = (unsigned char)((crc >> 0) & 0x00ff); + //printf("--- %s: crc_data[0] = 0x%x, crc_data[1] = 0x%x\n", __FUNCTION__, crc_data[0], crc_data[1]); + + while(retry_count++<3) + { + // pthread_mutex_lock(&iic_mutex); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_1); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_2); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, length); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, GET_PIC_SOFTWARE_VERSION); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[0]); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[1]); + usleep(100*1000); + read_back_data[0] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[1] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[2] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[3] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[4] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + // pthread_mutex_unlock(&iic_mutex); + + //printf("--- %s: read_back_data[0] = 0x%x, read_back_data[1] = 0x%x\n", __FUNCTION__, read_back_data[0], read_back_data[1]); + usleep(100*1000); + + if((read_back_data[1] != GET_PIC_SOFTWARE_VERSION) || (read_back_data[0] != 5)) + { + sprintf(logstr,"%s failed on Chain[%d]!\n", __FUNCTION__,which_iic); + writeInitLogFile(logstr); + sleep(1); + // return 0; // error + } + else + { + crc = read_back_data[0] + read_back_data[1] + read_back_data[2]; + if(((unsigned char)((crc >> 8) & 0x00ff) != read_back_data[3]) || ((unsigned char)((crc >> 0) & 0x00ff) != read_back_data[4])) + { + //printf("\n--- %s failed!\n\n", __FUNCTION__); + // return 0; // error + sleep(1); + } + else + { + *version = read_back_data[2]; + //printf("\n--- %s ok\n\n", __FUNCTION__); + return 1; // ok + } + } + } + return 0; + } + + void get_pic_software_version(unsigned char chain, unsigned char *version) + { + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(chain,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + dsPIC33EP16GS202_get_pic_sw_version(new_T9_PLUS_chainIndex,version); + } + else + { + dsPIC33EP16GS202_get_pic_sw_version(chain/3,version); + } + } + + int dsPIC33EP16GS202_jump_to_app_from_loader(unsigned char which_iic) + { + unsigned char length = 0x04, crc_data[2] = {0xff}, read_back_data[2] = {0xff}; + unsigned short crc = 0; + char logstr[1024]; + int retry_count=0; + + //printf("\n--- %s\n", __FUNCTION__); + + crc = length + JUMP_FROM_LOADER_TO_APP; + crc_data[0] = (unsigned char)((crc >> 8) & 0x00ff); + crc_data[1] = (unsigned char)((crc >> 0) & 0x00ff); + //printf("--- %s: crc_data[0] = 0x%x, crc_data[1] = 0x%x\n", __FUNCTION__, crc_data[0], crc_data[1]); + + while(retry_count++<3) + { + // pthread_mutex_lock(&iic_mutex); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_1); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_2); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, length); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, JUMP_FROM_LOADER_TO_APP); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[0]); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[1]); + usleep(100*1000); + read_back_data[0] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[1] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + // pthread_mutex_unlock(&iic_mutex); + + //printf("--- %s: read_back_data[0] = 0x%x, read_back_data[1] = 0x%x\n", __FUNCTION__, read_back_data[0], read_back_data[1]); + + if((read_back_data[0] != JUMP_FROM_LOADER_TO_APP) || (read_back_data[1] != 1)) + { + sprintf(logstr,"%s failed on Chain[%d]!\n", __FUNCTION__,which_iic); + writeInitLogFile(logstr); + sleep(1); + // return 0; // error + } + else + { + sleep(1); + //printf("\n--- %s ok\n\n", __FUNCTION__); + return 1; // ok + } + } + + return 0; + } + + int dsPIC33EP16GS202_reset_pic(unsigned char which_iic) + { + unsigned char length = 0x04, crc_data[2] = {0xff}, read_back_data[2] = {0xff}; + unsigned short crc = 0; + char logstr[1024]; + int retry_count=0; + + //printf("\n--- %s\n", __FUNCTION__); + + crc = length + RESET_PIC; + crc_data[0] = (unsigned char)((crc >> 8) & 0x00ff); + crc_data[1] = (unsigned char)((crc >> 0) & 0x00ff); + //printf("--- %s: which_iic=%d crc_data[0] = 0x%x, crc_data[1] = 0x%x\n", __FUNCTION__,which_iic, crc_data[0], crc_data[1]); + + while(retry_count++<3) + { + // pthread_mutex_lock(&iic_mutex); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_1); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_2); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, length); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, RESET_PIC); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[0]); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[1]); + usleep(400*1000); + read_back_data[0] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[1] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + // pthread_mutex_unlock(&iic_mutex); + + //printf("--- %s: read_back_data[0] = 0x%x, read_back_data[1] = 0x%x\n", __FUNCTION__, read_back_data[0], read_back_data[1]); + usleep(100*1000); + + if((read_back_data[0] != RESET_PIC) || (read_back_data[1] != 1)) + { + sprintf(logstr,"%s failed on Chain[%d]!\n", __FUNCTION__,which_iic); + writeInitLogFile(logstr); + sleep(1); + // return 0; // error + } + else + { + //printf("\n--- %s ok\n\n", __FUNCTION__); + sleep(1); + return 1; // ok + } + } + return 0; + } + + int dsPIC33EP16GS202_update_pic_app_program(unsigned char which_iic); + void jump_to_app_CheckAndRestorePIC_T9_18(int chainIndex) + { + unsigned char pic_version; + char logstr[1024]; + int try_count=0; + + if(fpga_version>=0xE) + { + if(chainIndex<1 || chainIndex>3) + return; + + sprintf(logstr,"chain[%d] PIC jump to app\n",chainIndex); + writeInitLogFile(logstr); + + dsPIC33EP16GS202_jump_to_app_from_loader(chainIndex); + + get_pic_software_version(chainIndex,&pic_version); + sprintf(logstr,"Check chain[%d] PIC fw version=0x%02x\n",chainIndex,pic_version); + writeInitLogFile(logstr); + +#ifdef ENABLE_RESTORE_PIC_APP +#ifndef DEBUG_PIC_UPGRADE + while(pic_version!=PIC_VERSION && try_count<2) +#endif + { + try_count++; + sprintf(logstr,"chain[%d] PIC need restore ...\n",chainIndex); + writeInitLogFile(logstr); + + dsPIC33EP16GS202_update_pic_app_program(chainIndex); + dsPIC33EP16GS202_jump_to_app_from_loader(chainIndex); + + get_pic_software_version(chainIndex,&pic_version); + sprintf(logstr,"After restore: chain[%d] PIC fw version=0x%02x\n",chainIndex,pic_version); + writeInitLogFile(logstr); + } +#endif + } + else + { + if(chainIndex%3 != 0) + return; + + sprintf(logstr,"chain[%d] PIC jump to app\n",chainIndex); + writeInitLogFile(logstr); + + dsPIC33EP16GS202_jump_to_app_from_loader(chainIndex/3); + + get_pic_software_version(chainIndex,&pic_version); + sprintf(logstr,"Check chain[%d] PIC fw version=0x%02x\n",chainIndex,pic_version); + writeInitLogFile(logstr); + +#ifdef ENABLE_RESTORE_PIC_APP +#ifndef DEBUG_PIC_UPGRADE + while(pic_version!=PIC_VERSION && try_count<2) +#endif + { + try_count++; + sprintf(logstr,"chain[%d] PIC need restore ...\n",chainIndex); + writeInitLogFile(logstr); + + dsPIC33EP16GS202_update_pic_app_program(chainIndex/3); + dsPIC33EP16GS202_jump_to_app_from_loader(chainIndex/3); + + get_pic_software_version(chainIndex,&pic_version); + sprintf(logstr,"After restore: chain[%d] PIC fw version=0x%02x\n",chainIndex,pic_version); + writeInitLogFile(logstr); + } +#endif + } + } + + unsigned char reset_iic_pic(unsigned char chain) + { + if(fpga_version>=0xE) + { + if(chain<1 || chain>3) // T9+ only chain[1] [2] [3] can control the PIC with new FPGA which can support S9 too. + return 1; + + return dsPIC33EP16GS202_reset_pic(chain); + } + else + { + if(chain%3 != 0) + return 1; + + return dsPIC33EP16GS202_reset_pic(chain/3); + } + } +#else + unsigned char jump_to_app_from_loader(unsigned char chain) + { + unsigned char ret=0xff; + + send_pic_command(chain); + write_pic_iic(false, false, 0x0, chain, JUMP_FROM_LOADER_TO_APP); + cgsleep_us(100000); + } + + unsigned char reset_iic_pic(unsigned char chain) + { + unsigned char ret=0xff; + + send_pic_command(chain); + write_pic_iic(false, false, 0x0, chain, RESET_PIC); + cgsleep_us(100000); + } + + void get_pic_software_version(unsigned char chain, unsigned char *version) + { + int i=0; + send_pic_command(chain); + write_pic_iic(false, false, 0x0, chain, GET_PIC_SOFTWARE_VERSION); + + for(i=0; i> 8) & 0x000000ff); + program_data[2*i + 1] = (unsigned char)(data_int & 0x000000ff); + //printf("program_data[%d]=0x%02x, program_data[%d]=0x%02x\n\n", 2*i + 0, program_data[2*i + 0], 2*i + 1, program_data[2*i + 1]); + } + + fclose(pic_program_file); + + // after read upgrade file correct, erase pic + reset_iic_pic(chain); + erase_pic_flash_all(chain); + + // write data into pic + set_pic_iic_flash_addr_pointer(chain, PIC_FLASH_POINTER_START_ADDRESS_H, PIC_FLASH_POINTER_START_ADDRESS_L); + + for(i=0; i3) + { + //printf("^^^^^^^^^^^^^^^^^^^^^\n"); + break; + } + usleep(1*1000); + } + + if(read) + { + value |= IIC_READ; + } + + if(reg_addr_valid) + { + value |= IIC_REG_ADDR_VALID; + value |= IIC_REG_ADDR(reg_addr); + } + + value |= EEPROM_ADDR_HIGH_4_BIT; + + if(fpga_version>=0xE && fpga_version<=0xF)// decrease one , because chain[1] [2] [3] use PIC [0] [1] [2] + which_iic--; + + value |= IIC_SELECT(which_iic); + + value |= data; + + ret = set_iic(value); + + return ret; + } + + + void AT24C02_write_one_byte(unsigned char address, unsigned char data, unsigned char which_iic) + { +// pthread_mutex_lock(&iic_mutex); + write_EEPROM_iic(false, true, address, which_iic, data); +// pthread_mutex_unlock(&iic_mutex); + } + + unsigned char AT24C02_read_one_byte(unsigned char address, unsigned char which_iic) + { + unsigned char data = 0; + +// pthread_mutex_lock(&iic_mutex); + data = write_EEPROM_iic(true, true, address, which_iic, 0); +// pthread_mutex_unlock(&iic_mutex); + + return data; + } + + void AT24C02_write_bytes(unsigned char address, unsigned char *buf, unsigned char which_iic, unsigned char length) + { + unsigned char i = 0; + + //printf("--- %s\n", __FUNCTION__); + + if((address + length) > EEPROM_LENGTH) + { + //printf("\n--- %s: address + length = %d > EEPROM_LENGTH(%d)\n", __FUNCTION__, address + length, EEPROM_LENGTH); + return; + } + + for(i=0; i EEPROM_LENGTH) + { + //printf("\n--- %s: address + length = %d > EEPROM_LENGTH(%d)\n", __FUNCTION__, address + length, EEPROM_LENGTH); + return; + } + + for(i=0; i=0xE) + { + if(chain<1 || chain>3) + return 0; + + AT24C02_read_bytes(FREQ_BADCORE_ADDR,buf,chain,128); + } + else + { + if(chain%3 != 0) + return 0; + + AT24C02_read_bytes(FREQ_BADCORE_ADDR,buf,chain/3,128); + } + return 128; + } + + unsigned char save_freq_badcores(unsigned char chain, unsigned char *buf) + { + if(fpga_version>=0xE) + { + if(chain<1 || chain>3) + return 0; + + AT24C02_write_bytes(FREQ_BADCORE_ADDR,buf,chain,128); + } + else + { + if(chain%3 != 0) + return 0; + + AT24C02_write_bytes(FREQ_BADCORE_ADDR,buf,chain/3,128); + } + return 128; + } + + void AT24C02_save_voltage(unsigned char which_iic, unsigned char voltage) + { + //printf("\n--- %s\n", __FUNCTION__); + + AT24C02_write_one_byte(VOLTAGE_ADDR, voltage, which_iic); + + //printf("%s: voltage = 0x%02x\n", __FUNCTION__, voltage); + } + + unsigned char AT24C02_read_voltage(unsigned char which_iic) + { + return AT24C02_read_one_byte(VOLTAGE_ADDR, which_iic); + } + + + int set_Voltage_S9_plus_plus_BM1387_54(unsigned char which_iic, unsigned char pic_voltage) + { + double temp_voltage = 0; + unsigned char length = 0x07, crc_data[2] = {0xff}, read_back_data[2] = {0xff}; + unsigned short crc = 0; + unsigned char voltage1 = pic_voltage, voltage2 = 0, voltage3 = 0; + int i; + char logstr[1024]; + int retry_count=0; + + //printf("voltage1 = %d\n", voltage1); + + if((voltage1 > 127) || (voltage2 > 127) || (voltage3 > 127)) + { + //printf("\n--- %s voltage1(%d) > 127 \n\n", __FUNCTION__, voltage1); + return 0; // because 4017 just have 127 level + } + + crc = length + SET_VOLTAGE + voltage1 + voltage2 + voltage3; + crc_data[0] = (unsigned char)((crc >> 8) & 0x00ff); + crc_data[1] = (unsigned char)((crc >> 0) & 0x00ff); + //printf("--- %s: crc_data[0] = 0x%x, crc_data[1] = 0x%x\n", __FUNCTION__, crc_data[0], crc_data[1]); + + while(retry_count++<3) + { + // pthread_mutex_lock(&iic_mutex); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_1); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_2); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, length); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, SET_VOLTAGE); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, voltage1); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, voltage2); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, voltage3); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[0]); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[1]); + usleep(100*1000); + read_back_data[0] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[1] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + // pthread_mutex_unlock(&iic_mutex); + + //printf("--- %s: read_back_data[0] = 0x%x, read_back_data[1] = 0x%x\n", __FUNCTION__, read_back_data[0], read_back_data[1]); + + if((read_back_data[0] != SET_VOLTAGE) || (read_back_data[1] != 1)) + { + sprintf(logstr,"%s failed on Chain[%d]!\n\n", __FUNCTION__,which_iic); + writeInitLogFile(logstr); + sleep(1); + // return 0; // error + } + else + { + //printf("\n--- %s ok!\n\n", __FUNCTION__); + + AT24C02_save_voltage(which_iic, voltage1); + + return 1; // ok + } + } + return 0; + } + + void set_voltage_T9_18_into_PIC(unsigned char chain, unsigned char voltage) + { + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; // only used by new T9+ FPGA + getPICChainIndexOffset(chain,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + + set_Voltage_S9_plus_plus_BM1387_54(new_T9_PLUS_chainIndex,voltage); + } + else + { + set_Voltage_S9_plus_plus_BM1387_54(chain/3,voltage); + } + } + + unsigned char getHighestVoltagePIC(int chainIndex) + { + int startIndex; + int i; + unsigned char minVolPIC; + + if(fpga_version>=0xE) + { + switch(chainIndex) + { + case 1: + case 8: + case 9: + minVolPIC=chain_voltage_pic[1]; + for(i=8; i<10; i++) + { + if(minVolPIC>chain_voltage_pic[i]) + minVolPIC=chain_voltage_pic[i]; // the value is lower, means voltage is higher!!! + } + break; + case 2: + case 10: + case 11: + minVolPIC=chain_voltage_pic[2]; + for(i=10; i<12; i++) + { + if(minVolPIC>chain_voltage_pic[i]) + minVolPIC=chain_voltage_pic[i]; // the value is lower, means voltage is higher!!! + } + break; + case 3: + case 12: + case 13: + minVolPIC=chain_voltage_pic[3]; + for(i=12; i<14; i++) + { + if(minVolPIC>chain_voltage_pic[i]) + minVolPIC=chain_voltage_pic[i]; // the value is lower, means voltage is higher!!! + } + break; + default: + minVolPIC=0; + break; + } + } + else + { + startIndex=(chainIndex/3)*3; // get start chainindex, 0,1,2 = 0 3,4,5 = 3 ... + minVolPIC=chain_voltage_pic[chainIndex]; + + for(i=startIndex; ichain_voltage_pic[i]) + minVolPIC=chain_voltage_pic[i]; // the value is lower, means voltage is higher!!! + } + } + + return minVolPIC; + } + + void set_pic_voltage_T9_18(unsigned char chain) + { + char logstr[1024]; + unsigned char vol_pic; + // before call this function, must set chain_voltage_pic[chain] value at first! because T9_18 will only set the highest voltage for 3 chains! + vol_pic=getHighestVoltagePIC(chain); + + sprintf(logstr,"set voltage=%d on chain[%d], the real voltage=%d\n",getVolValueFromPICvoltage(chain_voltage_pic[chain]),chain,getVolValueFromPICvoltage(vol_pic)); + writeInitLogFile(logstr); + + set_voltage_T9_18_into_PIC(chain, vol_pic); + } + + void set_pic_voltage(unsigned char chain, unsigned char voltage) + { + if(fpga_version>=0xE) + { + if(chain>=1 && chain<=3) + set_pic_voltage_T9_18(chain); + } + else + { + if(chain%3==0) + set_pic_voltage_T9_18(chain); + } + } + + unsigned char get_pic_voltage(unsigned char chain) + { + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(chain,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + return AT24C02_read_voltage(new_T9_PLUS_chainIndex); + } + else + { + return AT24C02_read_voltage(chain/3); + } + } +#else + void set_pic_voltage(unsigned char chain, unsigned char voltage) + { + send_pic_command(chain); + applog(LOG_NOTICE,"%s voltage %u",__FUNCTION__,voltage); + write_pic_iic(false, false, 0x0, chain, SET_VOLTAGE); + write_pic_iic(false, false, 0x0, chain, voltage); + cgsleep_us(100000); + } + + unsigned char get_pic_voltage(unsigned char chain) + { + unsigned char ret=0; + send_pic_command(chain); + write_pic_iic(false, false, 0x0, chain, GET_VOLTAGE); + ret = write_pic_iic(true, false, 0x0, chain, 0); + applog(LOG_NOTICE,"%s: voltage = %d\n", __FUNCTION__, ret); + return ret; + } + +#endif + + void set_voltage_setting_time(unsigned char chain, unsigned char *time) + { + send_pic_command(chain); + send_data_to_pic_iic(chain, SET_VOLTAGE_TIME, time, 6); + cgsleep_us(100000); + } + + void set_hash_board_id_number(unsigned char chain, unsigned char *id) + { + send_pic_command(chain); + send_data_to_pic_iic(chain, SET_HASH_BOARD_ID, id, 12); + cgsleep_us(100000); + } + +#ifdef T9_18 + void get_hash_board_id_number(unsigned char chain, unsigned char *id) + { + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(chain,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + AT24C02_read_bytes(HASH_ID_ADDR, id, new_T9_PLUS_chainIndex, 12); + } + else + { + AT24C02_read_bytes(HASH_ID_ADDR, id, chain/3, 12); + } + } +#else + void get_hash_board_id_number(unsigned char chain, unsigned char *id) + { + send_pic_command(chain); + get_data_from_pic_iic(chain, GET_HASH_BOARD_ID, id, 12); + } +#endif + + void write_host_MAC_and_time(unsigned char chain, unsigned char *buf) + { + send_pic_command(chain); + send_data_to_pic_iic(chain, SET_HOST_MAC_ADDRESS, buf, 12); + cgsleep_us(100000); + } + + void enable_pic_dc_dc(unsigned char chain) + { + send_pic_command(chain); + write_pic_iic(false, false, 0x0, chain, ENABLE_VOLTAGE); + write_pic_iic(false, false, 0x0, chain, 1); + } + + void enable_pic_dc_dc_all() + { + int i; + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + enable_pic_dc_dc(i); + cgsleep_ms(1); + } + } + } + +#ifdef T9_18 + int getChainPICMagicNumber(int chainIndex) + { + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(chainIndex,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + return chain_pic_buf[new_T9_PLUS_chainIndex][0]; + } + else + { + return chain_pic_buf[((chainIndex/3)*3)][0]; + } + } + + int dsPIC33EP16GS202_enable_pic_dc_dc(unsigned char which_iic, unsigned char enable) + { + unsigned char length = 0x05, crc_data[2] = {0xff}, read_back_data[2] = {0xff}; + unsigned short crc = 0; + char logstr[1024]; + int retry_count=0; + + //printf("\n--- %s\n", __FUNCTION__); + + crc = length + ENABLE_VOLTAGE + enable; + crc_data[0] = (unsigned char)((crc >> 8) & 0x00ff); + crc_data[1] = (unsigned char)((crc >> 0) & 0x00ff); + //printf("--- %s: crc_data[0] = 0x%x, crc_data[1] = 0x%x\n", __FUNCTION__, crc_data[0], crc_data[1]); + + while(retry_count++<3) + { + // pthread_mutex_lock(&iic_mutex); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_1); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_2); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, length); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, ENABLE_VOLTAGE); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, enable); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[0]); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[1]); + usleep(10*1000); + read_back_data[0] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[1] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + // pthread_mutex_unlock(&iic_mutex); + + //printf("--- %s: read_back_data[0] = 0x%x, read_back_data[1] = 0x%x\n", __FUNCTION__, read_back_data[0], read_back_data[1]); + + if((read_back_data[0] != ENABLE_VOLTAGE) || (read_back_data[1] != 1)) + { + sprintf(logstr,"%s failed on Chain[%d]!\n", __FUNCTION__,which_iic); + writeInitLogFile(logstr); + sleep(1); + // return 0; // error + } + else + { + //printf("\n--- %s ok\n\n", __FUNCTION__); + return 1; // ok + } + } + return 0; + } + + void enable_pic_dac(unsigned char chain) + { + if(fpga_version>=0xE) + { + if(chain<1 || chain>3) + return; + + dsPIC33EP16GS202_enable_pic_dc_dc(chain, 1); // open pic dc-dc + } + else + { + if(chain%3!=0) // only enable DC when enable the first chain of 3 chains, like 0, 3, 6 ... + return; + + dsPIC33EP16GS202_enable_pic_dc_dc(chain/3, 1); // open pic dc-dc + } + } + + void disable_pic_dac(unsigned char chain) + { + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(chain,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + + if(chain!=9 && chain!=11 && chain!=13) // only disable DC when close the last chain of 3 chains, like 8, 11, 13 ... + return; + + dsPIC33EP16GS202_enable_pic_dc_dc(new_T9_PLUS_chainIndex, 0); // open pic dc-dc + } + else + { + if(chain%3 !=2) // only disable DC when close the last chain of 3 chains, like 2, 5, 8 ... + return; + + dsPIC33EP16GS202_enable_pic_dc_dc(chain/3, 0); // open pic dc-dc + } + } + + unsigned int get_iic() + { + int ret = -1; + ret = *(axi_fpga_addr + IIC_COMMAND); + + //applog(LOG_DEBUG,"%s: IIC_COMMAND is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + unsigned char set_iic(unsigned int data) + { + unsigned int ret=0; + unsigned char ret_data = 0; + int wait_counter=0; +#ifdef DEBUG_PRINT_T9_PLUS_PIC_HEART_INFO + char logstr[1024]; +#endif + *((unsigned int *)(axi_fpga_addr + IIC_COMMAND)) = data & 0x7fffffff; + //applog(LOG_DEBUG,"%s: set IIC_COMMAND is 0x%x\n", __FUNCTION__, data & 0x7fffffff); + + while(1) + { + ret = get_iic(); + if(ret & 0x80000000) + { + ret_data = (unsigned char)(ret & 0x000000ff); + return ret_data; + } +#ifdef DEBUG_ENABLE_I2C_TIMEOUT_PROCESS + else + { + wait_counter++; + if(wait_counter>3) + { +#ifdef DEBUG_PRINT_T9_PLUS_PIC_HEART_INFO + set_red_led(true); // open red led + + sprintf(logstr,"Error: set_iic wait IIC timeout!\n"); + writeInitLogFile(logstr); +#endif + break; + } + //applog(LOG_DEBUG,"%s: waiting write pic iic\n", __FUNCTION__); + } +#endif + usleep(1000); + } + } + + unsigned char T9_plus_write_pic_iic(bool read, bool reg_addr_valid, unsigned char reg_addr, unsigned char which_iic, unsigned char data) + { + unsigned int value = 0x00000000, counter = 0; + unsigned int ret = 0; +#ifdef DEBUG_PRINT_T9_PLUS_PIC_HEART_INFO + char logstr[1024]; +#endif + + while(1) + { + ret = get_iic(); + //printf("iic command ret = 0x%08x\n", ret); + if(ret & 0x80000000) + { + break; + } +#ifdef DEBUG_ENABLE_I2C_TIMEOUT_PROCESS + else if(counter++>3) + { +#ifdef DEBUG_PRINT_T9_PLUS_PIC_HEART_INFO + sprintf(logstr,"Error: T9_plus_write_pic_iic wait IIC timeout!\n"); + writeInitLogFile(logstr); +#endif + break; + } +#endif + usleep(1*1000); + } + + if(read) + { + value |= IIC_READ; + } + + if(reg_addr_valid) + { + value |= IIC_REG_ADDR_VALID; + value |= IIC_REG_ADDR(reg_addr); + } + + value |= IIC_ADDR_HIGH_4_BIT; + + if(fpga_version>=0xE && fpga_version<=0xF)// decrease one , because chain[1] [2] [3] use PIC [0] [1] [2] + which_iic--; + + value |= IIC_SELECT(which_iic); + + value |= data; + + return set_iic(value); + } + + int dsPIC33EP16GS202_erase_pic_app_program(unsigned char which_iic) + { + unsigned char length = 0x04, crc_data[2] = {0xff}, read_back_data[2] = {0xff}; + unsigned short crc = 0; + char logstr[1024]; + int retry_count=0; + + crc = length + ERASE_PIC_APP_PROGRAM; + crc_data[0] = (unsigned char)((crc >> 8) & 0x00ff); + crc_data[1] = (unsigned char)((crc >> 0) & 0x00ff); + + while(retry_count++<3) + { + // pthread_mutex_lock(&iic_mutex); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_1); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_2); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, length); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, ERASE_PIC_APP_PROGRAM); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[0]); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[1]); + usleep(100*1000); + read_back_data[0] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[1] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + // pthread_mutex_unlock(&iic_mutex); + + //printf("--- %s: read_back_data[0] = 0x%x, read_back_data[1] = 0x%x\n", __FUNCTION__, read_back_data[0], read_back_data[1]); + usleep(200*1000); + + if((read_back_data[0] != ERASE_PIC_APP_PROGRAM) || (read_back_data[1] != 1)) + { + sprintf(logstr,"%s failed on Chain[%d]!\n", __FUNCTION__,which_iic); + writeInitLogFile(logstr); + sleep(1); + // return 0; // error + } + else + { + //printf("\n--- %s ok\n\n", __FUNCTION__); + return 1; // ok + } + } + return 0; + } + + int dsPIC33EP16GS202_send_data_to_pic(unsigned char which_iic, unsigned char *buf) + { + unsigned char length = 0x14, crc_data[2] = {0xff}, read_back_data[2] = {0xff}, i; + unsigned short crc = 0; + char logstr[1024]; + int retry_count=0; + + crc = length + SEND_DATA_TO_IIC; + for(i=0; i<16; i++) + { + crc += *(buf + i); + } + crc_data[0] = (unsigned char)((crc >> 8) & 0x00ff); + crc_data[1] = (unsigned char)((crc >> 0) & 0x00ff); + + while(retry_count++<3) + { + // pthread_mutex_lock(&iic_mutex); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_1); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_2); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, length); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, SEND_DATA_TO_IIC); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 0)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 1)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 2)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 3)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 4)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 5)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 6)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 7)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 8)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 9)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 10)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 11)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 12)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 13)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 14)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, *(buf + 15)); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[0]); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[1]); + usleep(200*1000); + read_back_data[0] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[1] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + // pthread_mutex_unlock(&iic_mutex); + + //printf("--- %s: read_back_data[0] = 0x%x, read_back_data[1] = 0x%x\n", __FUNCTION__, read_back_data[0], read_back_data[1]); + usleep(100*1000); + + if((read_back_data[0] != SEND_DATA_TO_IIC) || (read_back_data[1] != 1)) + { + sprintf(logstr,"%s failed on Chain[%d]!\n", __FUNCTION__,which_iic); + writeInitLogFile(logstr); + sleep(1); + // return 0; // error + } + else + { + //printf("\n--- %s ok\n\n", __FUNCTION__); + return 1; // ok + } + } + return 0; + } + + int dsPIC33EP16GS202_update_pic_app_program(unsigned char which_iic) + { + unsigned char program_data[14080] = {0}; + FILE * pic_program_file; + unsigned int filesize = 0,i=0,j; + unsigned char data_read[7]= {0,0,0,0,0,0,'\0'}, buf[16]= {0}; + unsigned int data_int = 0; + struct stat statbuff; + unsigned int data_len = 3520, loop = 880; + unsigned int pic_flash_length=0; + int ret = 0; + + //printf("\n--- update pic program\n"); + + // read upgrade file first, if it is wrong, don't erase pic, but just return; + pic_program_file = fopen(DSPIC33EP16GS202_PIC_PROGRAM, "r"); + if(!pic_program_file) + { + //printf("\n%s: open hash_s8_app.txt failed\n", __FUNCTION__); + return; + } + fseek(pic_program_file,0,SEEK_SET); + memset(program_data, 0x0, 14080); + + for(i=0; i> 24) & 0x000000ff); + program_data[4*i + 1] = (unsigned char)((data_int >> 16) & 0x000000ff); + program_data[4*i + 2] = (unsigned char)((data_int >> 8) & 0x000000ff); + program_data[4*i + 3] = (unsigned char)((data_int >> 0) & 0x000000ff); + + //printf("program_data[%d]=0x%02x, program_data[%d]=0x%02x, program_data[%d]=0x%02x, program_data[%d]=0x%02x\n\n", + // 4*i + 0, program_data[4*i + 0], 4*i + 1, program_data[4*i + 1], 4*i + 2, program_data[4*i + 2], 4*i + 3, program_data[4*i + 3]); + } + + fclose(pic_program_file); + + + // after read upgrade file correct, erase pic + ret = dsPIC33EP16GS202_reset_pic(which_iic); + if(ret == 0) + { + //printf("!!! %s: reset pic error!\n\n", __FUNCTION__); + return 0; + } + + ret = dsPIC33EP16GS202_erase_pic_app_program(which_iic); + if(ret == 0) + { + //printf("!!! %s: erase flash error!\n\n", __FUNCTION__); + return 0; + } + + for(i=0; i> 8) & 0x00ff); + crc_data[1] = (unsigned char)((crc >> 0) & 0x00ff); + //printf("--- %s: crc_data[0] = 0x%x, crc_data[1] = 0x%x\n", __FUNCTION__, crc_data[0], crc_data[1]); + + while(retry_count++<3) + { + // pthread_mutex_lock(&iic_mutex); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_1); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, PIC_COMMAND_2); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, length); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, SEND_HEART_BEAT); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[0]); + T9_plus_write_pic_iic(false, false, 0x0, which_iic, crc_data[1]); + usleep(500*1000); + read_back_data[0] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[1] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[2] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[3] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[4] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + read_back_data[5] = T9_plus_write_pic_iic(true, false, 0x0, which_iic, 0); + // pthread_mutex_unlock(&iic_mutex); + + if((read_back_data[1] != SEND_HEART_BEAT) || (read_back_data[2] != 1)) + { +#ifdef DEBUG_PRINT_T9_PLUS_PIC_HEART_INFO + sprintf(logstr,"%s read_back: %02x %02x %02x %02x %02x %02x\n", + __FUNCTION__, read_back_data[0], read_back_data[1], read_back_data[2], read_back_data[3], read_back_data[4], read_back_data[5]); + writeInitLogFile(logstr); + + sprintf(logstr,"%s failed on Chain[%d]!\n", __FUNCTION__,which_iic); + writeInitLogFile(logstr); +#endif + + sleep(1); + // return 0; // error + } + else + { +#ifdef DEBUG_PRINT_T9_PLUS_PIC_HEART_INFO + // sprintf(logstr,"%s ok, HeartBeatReturnWord = %d\n\n", __FUNCTION__, read_back_data[3]); + // writeInitLogFile(logstr); +#endif + return 1; // ok + } + } + return 0; + } + + void pic_heart_beat_each_chain(unsigned char chain) + { + if(fpga_version>=0xE) + { + if(chain<1 || chain>3) // only enable DC when enable the first chain of 3 chains, like 0, 3, 6 ... + return; + + dsPIC33EP16GS202_pic_heart_beat(chain); + } + else + { + if(chain%3!=0) // only enable DC when enable the first chain of 3 chains, like 0, 3, 6 ... + return; + + dsPIC33EP16GS202_pic_heart_beat(chain/3); + } + } +#else + void enable_pic_dac(unsigned char chain) + { + send_pic_command(chain); + write_pic_iic(false, false, 0x0, chain, ENABLE_VOLTAGE); + write_pic_iic(false, false, 0x0, chain, 1); + } + + void disable_pic_dac(unsigned char chain) + { + send_pic_command(chain); + write_pic_iic(false, false, 0x0, chain, ENABLE_VOLTAGE); + write_pic_iic(false, false, 0x0, chain, 0); + } + + void pic_heart_beat_each_chain(unsigned char chain) + { + send_pic_command(chain); + write_pic_iic(false, false, 0x0, chain, SEND_HEART_BEAT); + } +#endif + +//FPGA related + int get_nonce2_and_job_id_store_address(void) + { +// char logstr[256]; + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + NONCE2_AND_JOBID_STORE_ADDRESS)); +// sprintf(logstr,"get NONCE2_AND_JOBID_STORE_ADDRESS is 0x%x\n", ret); +// writeInitLogFile(logstr); + return ret; + } + + void set_nonce2_and_job_id_store_address(unsigned int value) + { + get_nonce2_and_job_id_store_address(); + *((unsigned int *)(axi_fpga_addr + NONCE2_AND_JOBID_STORE_ADDRESS)) = value; + applog(LOG_DEBUG,"%s: set NONCE2_AND_JOBID_STORE_ADDRESS is 0x%x\n", __FUNCTION__, value); + get_nonce2_and_job_id_store_address(); + } + + int get_job_start_address(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + JOB_START_ADDRESS)); + applog(LOG_DEBUG,"%s: JOB_START_ADDRESS is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_job_start_address(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + JOB_START_ADDRESS)) = value; + applog(LOG_DEBUG,"%s: set JOB_START_ADDRESS is 0x%x\n", __FUNCTION__, value); + get_job_start_address(); + } + + void set_bmc_counter(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + BMC_CMD_COUNTER)) = value; + } + + unsigned int read_bmc_counter() + { + unsigned int ret; + ret=*((unsigned int *)(axi_fpga_addr + BMC_CMD_COUNTER)); + return ret; + } + + int get_QN_write_data_command(void) + { + int ret = -1; + ret = *((axi_fpga_addr + QN_WRITE_DATA_COMMAND)); + applog(LOG_DEBUG,"%s: QN_WRITE_DATA_COMMAND is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_QN_write_data_command(unsigned int value) + { + *(axi_fpga_addr + QN_WRITE_DATA_COMMAND) = value; + applog(LOG_DEBUG,"%s: set QN_WRITE_DATA_COMMAND is 0x%x\n", __FUNCTION__, value); + get_QN_write_data_command(); + } + + void set_reset_hashboard(int chainIndex, int resetBit) + { + unsigned int ret; + unsigned int resetFlag; + char logstr[1024]; + ret = *((axi_fpga_addr + RESET_HASHBOARD_COMMAND)); + resetFlag=(1<0) + ret = ret | resetFlag; + else + ret = ret & (~resetFlag); + + sprintf(logstr,"set_reset_hashboard = 0x%08x\n",ret); + writeInitLogFile(logstr); + *(axi_fpga_addr + RESET_HASHBOARD_COMMAND) = ret; + } + + void set_reset_allhashboard(int resetBit) + { + unsigned int ret; + char logstr[1024]; + ret = *((axi_fpga_addr + RESET_HASHBOARD_COMMAND)); + + if(resetBit>0) + ret = ret | 0x0000ffff; + else + ret = ret & 0xffff0000; + + sprintf(logstr,"set_reset_allhashboard = 0x%08x\n",ret); + writeInitLogFile(logstr); + *(axi_fpga_addr + RESET_HASHBOARD_COMMAND) = ret; + } + + + int bitmain_axi_init() + { + unsigned int data; + int ret=0; + + fd = open("/dev/axi_fpga_dev", O_RDWR); + if(fd < 0) + { + applog(LOG_DEBUG,"/dev/axi_fpga_dev open failed. fd = %d\n", fd); + perror("open"); + return -1; + } + + axi_fpga_addr = mmap(NULL, TOTAL_LEN, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if(!axi_fpga_addr) + { + applog(LOG_DEBUG,"mmap axi_fpga_addr failed. axi_fpga_addr = 0x%x\n", axi_fpga_addr); + return -1; + } + applog(LOG_DEBUG,"mmap axi_fpga_addr = 0x%x\n", axi_fpga_addr); + + //check the value in address 0xff200000 + data = *axi_fpga_addr; + if((data & 0x0000FFFF) != HARDWARE_VERSION_VALUE) + { + applog(LOG_DEBUG,"data = 0x%x, and it's not equal to HARDWARE_VERSION_VALUE : 0x%x\n", data, HARDWARE_VERSION_VALUE); + //return -1; + } + applog(LOG_DEBUG,"axi_fpga_addr data = 0x%x\n", data); + + fd_fpga_mem = open("/dev/fpga_mem", O_RDWR); + if(fd_fpga_mem < 0) + { + applog(LOG_DEBUG,"/dev/fpga_mem open failed. fd_fpga_mem = %d\n", fd_fpga_mem); + perror("open"); + return -1; + } + + fpga_mem_addr = mmap(NULL, FPGA_MEM_TOTAL_LEN, PROT_READ|PROT_WRITE, MAP_SHARED, fd_fpga_mem, 0); + if(!fpga_mem_addr) + { + applog(LOG_DEBUG,"mmap fpga_mem_addr failed. fpga_mem_addr = 0x%x\n", fpga_mem_addr); + return -1; + } + applog(LOG_DEBUG,"mmap fpga_mem_addr = 0x%x\n", fpga_mem_addr); + + nonce2_jobid_address = fpga_mem_addr; + job_start_address_1 = fpga_mem_addr + NONCE2_AND_JOBID_STORE_SPACE/sizeof(int); + job_start_address_2 = fpga_mem_addr + (NONCE2_AND_JOBID_STORE_SPACE + JOB_STORE_SPACE)/sizeof(int); + + applog(LOG_DEBUG,"job_start_address_1 = 0x%x\n", job_start_address_1); + applog(LOG_DEBUG,"job_start_address_2 = 0x%x\n", job_start_address_2); + + set_nonce2_and_job_id_store_address(PHY_MEM_NONCE2_JOBID_ADDRESS); + set_job_start_address(PHY_MEM_JOB_START_ADDRESS_1); + + dev = calloc(sizeof(struct all_parameters), sizeof(char)); + if(!dev) + { + applog(LOG_DEBUG,"kmalloc for dev failed.\n"); + return -1; + } + else + { + dev->current_job_start_address = job_start_address_1; + applog(LOG_DEBUG,"kmalloc for dev success.\n"); + } + return ret; + } + + int bitmain_axi_Reinit() + { + int ret=0; + unsigned int data; + char logstr[1024]; + + data = *axi_fpga_addr; + if((data & 0x0000FFFF) != HARDWARE_VERSION_VALUE) + { + sprintf(logstr,"data = 0x%x, and it's not equal to HARDWARE_VERSION_VALUE : 0x%x\n", data, HARDWARE_VERSION_VALUE); + writeInitLogFile(logstr); + } + sprintf(logstr,"axi_fpga_addr data = 0x%x\n", data); + writeInitLogFile(logstr); + + nonce2_jobid_address = fpga_mem_addr; + job_start_address_1 = fpga_mem_addr + NONCE2_AND_JOBID_STORE_SPACE/sizeof(int); + job_start_address_2 = fpga_mem_addr + (NONCE2_AND_JOBID_STORE_SPACE + JOB_STORE_SPACE)/sizeof(int); + + set_nonce2_and_job_id_store_address(PHY_MEM_NONCE2_JOBID_ADDRESS); + set_job_start_address(PHY_MEM_JOB_START_ADDRESS_1); + + return ret; + } + + int bitmain_axi_close() + { + int ret = 0; + + ret = munmap((void *)axi_fpga_addr, TOTAL_LEN); + if(ret<0) + { + applog(LOG_DEBUG,"munmap failed!\n"); + } + + ret = munmap((void *)fpga_mem_addr, FPGA_MEM_TOTAL_LEN); + if(ret<0) + { + applog(LOG_DEBUG,"munmap failed!\n"); + } + + //free_pages((unsigned long)nonce2_jobid_address, NONCE2_AND_JOBID_STORE_SPACE_ORDER); + //free(temp_job_start_address_1); + //free(temp_job_start_address_2); + + close(fd); + close(fd_fpga_mem); + } + + int get_fan_control(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + FAN_CONTROL)); + applog(LOG_DEBUG,"%s: FAN_CONTROL is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_fan_control(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + FAN_CONTROL)) = value; + applog(LOG_DEBUG,"%s: set FAN_CONTROL is 0x%x\n", __FUNCTION__, value); + get_fan_control(); + } + + int get_hash_on_plug(void) + { + int ret = -1; + ret = *(axi_fpga_addr + HASH_ON_PLUG); + + applog(LOG_DEBUG,"%s: HASH_ON_PLUG is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + unsigned int get_crc_count() + { + unsigned int ret; + ret= *((unsigned int *)(axi_fpga_addr + CRC_ERROR_CNT_ADDR)); + return (ret&0xffff); + } + + int get_hardware_version(void) + { + int ret = -1; + ret = *((int *)(axi_fpga_addr + HARDWARE_VERSION)); + + applog(LOG_DEBUG,"%s: HARDWARE_VERSION is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_Hardware_version(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + HARDWARE_VERSION)) = value; + } + + int get_fan_speed(unsigned char *fan_id, unsigned int *fan_speed) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + FAN_SPEED)); + *fan_speed = 0x000000ff & ret; + *fan_id = (unsigned char)(0x00000007 & (ret >> 8)); + if(*fan_speed > 0) + { + applog(LOG_DEBUG,"%s: fan_id is 0x%x, fan_speed is 0x%x\n", __FUNCTION__, *fan_id, *fan_speed); + } + return ret; + } + + int get_temperature_0_3(void) + { + int ret = -1; + ret = *((int *)(axi_fpga_addr + TEMPERATURE_0_3)); + //applog(LOG_DEBUG,"%s: TEMPERATURE_0_3 is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + int get_temperature_4_7(void) + { + int ret = -1; + ret = *((int *)(axi_fpga_addr + TEMPERATURE_4_7)); + //applog(LOG_DEBUG,"%s: TEMPERATURE_4_7 is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + int get_temperature_8_11(void) + { + int ret = -1; + ret = *((int *)(axi_fpga_addr + TEMPERATURE_8_11)); + //applog(LOG_DEBUG,"%s: TEMPERATURE_8_11 is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + int get_temperature_12_15(void) + { + int ret = -1; + ret = *((int *)(axi_fpga_addr + TEMPERATURE_12_15)); + //applog(LOG_DEBUG,"%s: TEMPERATURE_12_15 is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + int get_time_out_control(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + TIME_OUT_CONTROL)); + applog(LOG_DEBUG,"%s: TIME_OUT_CONTROL is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_time_out_control(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + TIME_OUT_CONTROL)) = value; + applog(LOG_DEBUG,"%s: set FAN_CONTROL is 0x%x\n", __FUNCTION__, value); + get_time_out_control(); + } + + int get_BC_command_buffer(unsigned int *buf) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + BC_COMMAND_BUFFER)); + *(buf + 0) = ret; //this is for FIL + ret = *((unsigned int *)(axi_fpga_addr + BC_COMMAND_BUFFER + 1)); + *(buf + 1) = ret; + ret = *((unsigned int *)(axi_fpga_addr + BC_COMMAND_BUFFER + 2)); + *(buf + 2) = ret; + applog(LOG_DEBUG,"%s: BC_COMMAND_BUFFER buf[0]: 0x%x, buf[1]: 0x%x, buf[2]: 0x%x\n", __FUNCTION__, *(buf + 0), *(buf + 1), *(buf + 2)); + return ret; + } + + void set_BC_command_buffer(unsigned int *value) + { + unsigned int buf[4] = {0}; + *((unsigned int *)(axi_fpga_addr + BC_COMMAND_BUFFER)) = *(value + 0); //this is for FIL + *((unsigned int *)(axi_fpga_addr + BC_COMMAND_BUFFER + 1)) = *(value + 1); + *((unsigned int *)(axi_fpga_addr + BC_COMMAND_BUFFER + 2)) = *(value + 2); + applog(LOG_DEBUG,"%s: set BC_COMMAND_BUFFER value[0]: 0x%x, value[1]: 0x%x, value[2]: 0x%x\n", __FUNCTION__, *(value + 0), *(value + 1), *(value + 2)); + get_BC_command_buffer(buf); + } + + int get_nonce_number_in_fifo(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + NONCE_NUMBER_IN_FIFO)); + //applog(LOG_DEBUG,"%s: NONCE_NUMBER_IN_FIFO is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + int get_return_nonce(unsigned int *buf) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + RETURN_NONCE)); + *(buf + 0) = ret; + ret = *((unsigned int *)(axi_fpga_addr + RETURN_NONCE + 1)); + *(buf + 1) = ret; //there is nonce3 + //applog(LOG_DEBUG,"%s: RETURN_NONCE buf[0] is 0x%x, buf[1] is 0x%x\n", __FUNCTION__, *(buf + 0), *(buf + 1)); + return ret; + } + + int get_BC_write_command(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + BC_WRITE_COMMAND)); + applog(LOG_DEBUG,"%s: BC_WRITE_COMMAND is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_BC_write_command(unsigned int value) + { + char logstr[1024]; + int wait_count=0; + *((unsigned int *)(axi_fpga_addr + BC_WRITE_COMMAND)) = value; + //applog(LOG_DEBUG,"%s: set BC_WRITE_COMMAND is 0x%x\n", __FUNCTION__, value); + + if(value & BC_COMMAND_BUFFER_READY) + { + while(get_BC_write_command() & BC_COMMAND_BUFFER_READY) + { + cgsleep_ms(1); + wait_count++; + + if(wait_count>3000) + { + sprintf(logstr,"Error: set_BC_write_command wait buffer ready timeout!\n"); + writeInitLogFile(logstr); + break; + } + //applog(LOG_DEBUG,"%s ---\n", __FUNCTION__); + } + } + else + { + get_BC_write_command(); + } + } + + int get_ticket_mask(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + TICKET_MASK_FPGA)); + applog(LOG_DEBUG,"%s: TICKET_MASK_FPGA is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_ticket_mask(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + TICKET_MASK_FPGA)) = value; + applog(LOG_DEBUG,"%s: set TICKET_MASK_FPGA is 0x%x\n", __FUNCTION__, value); + get_ticket_mask(); + } + + int get_job_id(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + JOB_ID)); + applog(LOG_DEBUG,"%s: JOB_ID is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_job_id(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + JOB_ID)) = value; + applog(LOG_DEBUG,"%s: set JOB_ID is 0x%x\n", __FUNCTION__, value); + get_job_id(); + } + + int get_job_length(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + JOB_LENGTH)); + applog(LOG_DEBUG,"%s: JOB_LENGTH is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_job_length(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + JOB_LENGTH)) = value; + applog(LOG_DEBUG,"%s: set JOB_LENGTH is 0x%x\n", __FUNCTION__, value); + get_job_id(); + } + + + int get_block_header_version(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + BLOCK_HEADER_VERSION)); + applog(LOG_DEBUG,"%s: BLOCK_HEADER_VERSION is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_block_header_version(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + BLOCK_HEADER_VERSION)) = value; + applog(LOG_DEBUG,"%s: set BLOCK_HEADER_VERSION is 0x%x\n", __FUNCTION__, value); + get_block_header_version(); + } + + int get_time_stamp() + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + TIME_STAMP)); + applog(LOG_DEBUG,"%s: TIME_STAMP is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_time_stamp(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + TIME_STAMP)) = value; + applog(LOG_DEBUG,"%s: set TIME_STAMP is 0x%x\n", __FUNCTION__, value); + get_time_stamp(); + } + + int get_target_bits(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + TARGET_BITS)); + applog(LOG_DEBUG,"%s: TARGET_BITS is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_target_bits(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + TARGET_BITS)) = value; + applog(LOG_DEBUG,"%s: set TARGET_BITS is 0x%x\n", __FUNCTION__, value); + get_target_bits(); + } + + int get_pre_header_hash(unsigned int *buf) + { + int ret = -1; + *(buf + 0) = *((unsigned int *)(axi_fpga_addr + PRE_HEADER_HASH)); + *(buf + 1) = *((unsigned int *)(axi_fpga_addr + PRE_HEADER_HASH + 1)); + *(buf + 2) = *((unsigned int *)(axi_fpga_addr + PRE_HEADER_HASH + 2)); + *(buf + 3) = *((unsigned int *)(axi_fpga_addr + PRE_HEADER_HASH + 3)); + *(buf + 4) = *((unsigned int *)(axi_fpga_addr + PRE_HEADER_HASH + 4)); + *(buf + 5) = *((unsigned int *)(axi_fpga_addr + PRE_HEADER_HASH + 5)); + *(buf + 6) = *((unsigned int *)(axi_fpga_addr + PRE_HEADER_HASH + 6)); + *(buf + 7) = *((unsigned int *)(axi_fpga_addr + PRE_HEADER_HASH + 7)); + applog(LOG_DEBUG,"%s: PRE_HEADER_HASH buf[0]: 0x%x, buf[1]: 0x%x, buf[2]: 0x%x, buf[3]: 0x%x, buf[4]: 0x%x, buf[5]: 0x%x, buf[6]: 0x%x, buf[7]: 0x%x\n", __FUNCTION__, *(buf + 0), *(buf + 1), *(buf + 2), *(buf + 3), *(buf + 4), *(buf + 5), *(buf + 6), *(buf + 7)); + ret = *(buf + 7); + return ret; + } + + void set_pre_header_hash(unsigned int *value) + { + unsigned int buf[8] = {0}; + *(axi_fpga_addr + PRE_HEADER_HASH) = *(value + 0); + *(axi_fpga_addr + PRE_HEADER_HASH + 1) = *(value + 1); + *(axi_fpga_addr + PRE_HEADER_HASH + 2) = *(value + 2); + *(axi_fpga_addr + PRE_HEADER_HASH + 3) = *(value + 3); + *(axi_fpga_addr + PRE_HEADER_HASH + 4) = *(value + 4); + *(axi_fpga_addr + PRE_HEADER_HASH + 5) = *(value + 5); + *(axi_fpga_addr + PRE_HEADER_HASH + 6) = *(value + 6); + *(axi_fpga_addr + PRE_HEADER_HASH + 7) = *(value + 7); + applog(LOG_DEBUG,"%s: set PRE_HEADER_HASH value[0]: 0x%x, value[1]: 0x%x, value[2]: 0x%x, value[3]: 0x%x, value[4]: 0x%x, value[5]: 0x%x, value[6]: 0x%x, value[7]: 0x%x\n", __FUNCTION__, *(value + 0), *(value + 1), *(value + 2), *(value + 3), *(value + 4), *(value + 5), *(value + 6), *(value + 7)); + //get_pre_header_hash(buf); + } + + int get_coinbase_length_and_nonce2_length(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + COINBASE_AND_NONCE2_LENGTH)); + applog(LOG_DEBUG,"%s: COINBASE_AND_NONCE2_LENGTH is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_coinbase_length_and_nonce2_length(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + COINBASE_AND_NONCE2_LENGTH)) = value; + applog(LOG_DEBUG,"%s: set COINBASE_AND_NONCE2_LENGTH is 0x%x\n", __FUNCTION__, value); + get_coinbase_length_and_nonce2_length(); + } + + int get_work_nonce2(unsigned int *buf) + { + int ret = -1; + *(buf + 0) = *((unsigned int *)(axi_fpga_addr + WORK_NONCE_2)); + *(buf + 1) = *((unsigned int *)(axi_fpga_addr + WORK_NONCE_2 + 1)); + applog(LOG_DEBUG,"%s: WORK_NONCE_2 buf[0]: 0x%x, buf[1]: 0x%x\n", __FUNCTION__, *(buf + 0), *(buf + 1)); + return ret; + } + + void set_work_nonce2(unsigned int *value) + { + unsigned int buf[2] = {0}; + *((unsigned int *)(axi_fpga_addr + WORK_NONCE_2)) = *(value + 0); + *((unsigned int *)(axi_fpga_addr + WORK_NONCE_2 + 1)) = *(value + 1); + applog(LOG_DEBUG,"%s: set WORK_NONCE_2 value[0]: 0x%x, value[1]: 0x%x\n", __FUNCTION__, *(value + 0), *(value + 1)); + get_work_nonce2(buf); + } + + int get_merkle_bin_number(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + MERKLE_BIN_NUMBER)); + ret = ret & 0x0000ffff; + applog(LOG_DEBUG,"%s: MERKLE_BIN_NUMBER is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_merkle_bin_number(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + MERKLE_BIN_NUMBER)) = value & 0x0000ffff; + applog(LOG_DEBUG,"%s: set MERKLE_BIN_NUMBER is 0x%x\n", __FUNCTION__, value & 0x0000ffff); + get_merkle_bin_number(); + } + + int get_nonce_fifo_interrupt(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + NONCE_FIFO_INTERRUPT)); + applog(LOG_DEBUG,"%s: NONCE_FIFO_INTERRUPT is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_nonce_fifo_interrupt(unsigned int value) + { + *((unsigned int *)(axi_fpga_addr + NONCE_FIFO_INTERRUPT)) = value; + applog(LOG_DEBUG,"%s: set NONCE_FIFO_INTERRUPT is 0x%x\n", __FUNCTION__, value); + get_nonce_fifo_interrupt(); + } + + int get_dhash_acc_control(void) + { + int ret = -1; + ret = *((unsigned int *)(axi_fpga_addr + DHASH_ACC_CONTROL)); + applog(LOG_DEBUG,"%s: DHASH_ACC_CONTROL is 0x%x\n", __FUNCTION__, ret); + return ret; + } + + void set_dhash_acc_control(unsigned int value) + { + int a = 10; + *((unsigned int *)(axi_fpga_addr + DHASH_ACC_CONTROL)) = value; + applog(LOG_DEBUG,"%s: set DHASH_ACC_CONTROL is 0x%x\n", __FUNCTION__, value); + while (a>0) + { + if ((value | NEW_BLOCK) == (get_dhash_acc_control() |NEW_BLOCK)) + break; + *((unsigned int *)(axi_fpga_addr + DHASH_ACC_CONTROL)) = value; + a--; + cgsleep_ms(2); + } + if (a == 0) + applog(LOG_DEBUG,"%s set DHASH_ACC_CONTROL failed!",__FUNCTION__); + } + + void set_TW_write_command(unsigned int *value) + { + unsigned int i; + for(i=0; ichain_num = 0; + + ret = get_hash_on_plug(); + + if(ret < 0) + { + applog(LOG_DEBUG,"%s: get_hash_on_plug functions error\n"); + } + else + { + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if((ret >> i) & 0x1) + { + dev->chain_exist[i] = 1; + dev->chain_num++; + } + else + { + dev->chain_exist[i] = 0; + } + } + } + } + + void check_fan() + { + int i=0, j=0; + unsigned char fan_id = 0; + unsigned int fan_speed; + + for(j=0; j < 2; j++) //means check for twice to make sure find out all fan + { + for(i=0; i < BITMAIN_MAX_FAN_NUM; i++) + { + if(get_fan_speed(&fan_id, &fan_speed) != -1) + { + dev->fan_speed_value[fan_id] = fan_speed * 60 * 2; + if((fan_speed > 0) && (dev->fan_exist[fan_id] == 0)) + { + dev->fan_exist[fan_id] = 1; + dev->fan_num++; + dev->fan_exist_map |= (0x1 << fan_id); + } + else if((fan_speed == 0) && (dev->fan_exist[fan_id] == 1)) + { + dev->fan_exist[fan_id] = 0; + dev->fan_num--; + dev->fan_exist_map &= !(0x1 << fan_id); + } + if(dev->fan_speed_top1 < dev->fan_speed_value[fan_id]) + dev->fan_speed_top1 = dev->fan_speed_value[fan_id]; + } + } + } + } + + void set_PWM(unsigned char pwm_percent) + { + uint16_t pwm_high_value = 0, pwm_low_value = 0; + int temp_pwm_percent = 0; + + temp_pwm_percent = pwm_percent; + + if(temp_pwm_percent < MIN_PWM_PERCENT) + { + temp_pwm_percent = MIN_PWM_PERCENT; + } + + if(temp_pwm_percent > MAX_PWM_PERCENT) + { + temp_pwm_percent = MAX_PWM_PERCENT; + } + + pwm_high_value = temp_pwm_percent * PWM_SCALE / 100; + pwm_low_value = (100 - temp_pwm_percent) * PWM_SCALE / 100; + dev->pwm_value = (pwm_high_value << 16) | pwm_low_value; + dev->pwm_percent = temp_pwm_percent; + + set_fan_control(dev->pwm_value); + } + + bool isTempTooLow() + { + int i; + char logstr[1024]; + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1 && chain_temp_toolow[i]==0 && dev->chain_asic_temp[i][1][PWM_T]>0) + { + if(lowest_testOK_temp[i]<=0) + { + // for old version, there is no lowest_testOK_temp value in PIC + if(dev->chain_asic_temp[i][1][PWM_T]chain_asic_temp[i][1][PWM_T]); + writeLogFile(logstr); + return true; + } + } + else if(dev->chain_asic_temp[i][1][PWM_T]chain_asic_temp[i][1][PWM_T]); + writeLogFile(logstr); + return true; + } + } + } + return false; + } + + void CheckChainTempTooLowFlag() + { + int i; + bool isSomeBoardNotTooLow=false; + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + if(chain_temp_toolow[i]==0) + isSomeBoardNotTooLow=true; + } + } + + if(!isSomeBoardNotTooLow) + { + // all board temp are too low, we will set flag to 0 again! + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + chain_temp_toolow[i]=0; + } + } + } + } + + void setChainTempTooLowFlag() + { + int i; + char logstr[1024]; + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + chain_temp_toolow[i]=0; + if(dev->chain_exist[i] == 1 && dev->chain_asic_maxtemp[i][PWM_T]>0) + { + if(lowest_testOK_temp[i]<=0) + { + // for old version, there is no lowest_testOK_temp value in PIC + if(dev->chain_asic_maxtemp[i][PWM_T]chain_asic_maxtemp[i][PWM_T]); + writeLogFile(logstr); + + chain_temp_toolow[i]=1; //set 1, will ignore this board's temp + } + } + else if(dev->chain_asic_maxtemp[i][PWM_T]chain_asic_maxtemp[i][PWM_T],lowest_testOK_temp[i]); + writeLogFile(logstr); + + chain_temp_toolow[i]=1; //set 1, will ignore this board's temp + } + } + } + + CheckChainTempTooLowFlag(); + } + +#ifdef R4 + void set_PWM_according_to_temperature() + { + char logstr[1024]; + int pwm_percent = 0, temp_change = 0; + temp_highest = dev->temp_top1[PWM_T]; + +#ifdef DEBUG_218_FAN_FULLSPEED + if(is218_Temp) + { + set_PWM(MAX_PWM_PERCENT); + dev->fan_pwm = MAX_PWM_PERCENT; + return; + } +#endif + + if(temp_highest >= MAX_FAN_TEMP) + { + applog(LOG_DEBUG,"%s: Temperature is higher than %d 'C\n", __FUNCTION__, temp_highest); + } + + temp_change = temp_highest - last_temperature; + + sprintf(logstr,"set FAN speed according to: temp_highest=%d temp_top1[PWM_T]=%d temp_change=%d\n",temp_highest,dev->temp_top1[PWM_T],temp_change); + writeLogFile(logstr); + + if(temp_highest >= MAX_FAN_TEMP || temp_highest == 0) + { + set_PWM(MAX_PWM_PERCENT); + dev->fan_pwm = MAX_PWM_PERCENT; + applog(LOG_DEBUG,"%s: Set PWM percent : MAX_PWM_PERCENT\n", __FUNCTION__); + + sprintf(logstr,"temp_highest >= MAX_FAN_TEMP || temp_highest == 0 PWM=%d\n",dev->fan_pwm); + writeLogFile(logstr); + return; + } + + if(temp_highest <= MIN_FAN_TEMP) + { + set_PWM(MIN_PWM_PERCENT); + dev->fan_pwm = MIN_PWM_PERCENT; + applog(LOG_DEBUG,"%s: Set PWM percent : MIN_PWM_PERCENT\n", __FUNCTION__); + + sprintf(logstr,"temp_highest <= MIN_FAN_TEMP PWM=%d\n",dev->fan_pwm); + writeLogFile(logstr); + return; + } + + if(temp_change >= TEMP_INTERVAL || temp_change <= -TEMP_INTERVAL) + { + if(temp_highest > MID_FAN_TEMP) + pwm_percent = MID_PWM_PERCENT + (temp_highest -MID_FAN_TEMP) * MID_PWM_ADJUST_FACTOR; + else + pwm_percent = MIN_PWM_PERCENT + (temp_highest -MIN_FAN_TEMP) * PWM_ADJUST_FACTOR; + + if(dev->temp_top1[PWM_T] > MAX_FAN_TEMP) + pwm_percent = MAX_PWM_PERCENT; + + if(pwm_percent < 0) + { + pwm_percent = 0; + } + if(pwm_percent > MAX_PWM_PERCENT) + { + pwm_percent = MAX_PWM_PERCENT; + } + + dev->fan_pwm = pwm_percent; + applog(LOG_DEBUG,"%s: Set PWM percent : %d\n", __FUNCTION__, pwm_percent); + set_PWM(pwm_percent); + last_temperature = temp_highest; + + sprintf(logstr,"temp_change >= TEMP_INTERVAL || temp_change <= -TEMP_INTERVAL PWM=%d[%d]\n",pwm_percent,dev->fan_pwm); + writeLogFile(logstr); + } + else + { + sprintf(logstr,"keep PWM=%d\n",dev->fan_pwm); + writeLogFile(logstr); + } + } +#else + void set_PWM_according_to_temperature() + { + static int fix_fan_steps=0; + int pwm_percent = dev->fan_pwm, temp_change = 0; + char logstr[1024]; + +#ifdef TWO_CHIP_TEMP_S9 + temp_highest = dev->temp_low1[PWM_T]; +#else + if(is218_Temp) + temp_highest=dev->temp_top1[TEMP_POS_LOCAL]; + else + temp_highest = dev->temp_top1[PWM_T]; +#endif + + temp_change = temp_highest - last_temperature; + +#ifdef DEBUG_218_FAN_FULLSPEED + if(is218_Temp) + { + set_PWM(MAX_PWM_PERCENT); + dev->fan_pwm = MAX_PWM_PERCENT; + return; + } +#endif + + sprintf(logstr,"set FAN speed according to: temp_highest=%d temp_top1[PWM_T]=%d temp_top1[TEMP_POS_LOCAL]=%d temp_change=%d fix_fan_steps=%d\n",temp_highest,dev->temp_top1[PWM_T],dev->temp_top1[TEMP_POS_LOCAL],temp_change,fix_fan_steps); + writeLogFile(logstr); + +#ifndef TWO_CHIP_TEMP_S9 + if(is218_Temp) + { + if(temp_highest >= MAX_FAN_PCB_TEMP || temp_highest == 0)//some board temp is very high than others!!! + { + set_PWM(MAX_PWM_PERCENT); + dev->fan_pwm = MAX_PWM_PERCENT; + + sprintf(logstr,"set full FAN speed...\n"); + writeLogFile(logstr); + return; + } + + if(temp_change >= TEMP_INTERVAL || temp_change <= -TEMP_INTERVAL) + { + sprintf(logstr,"set normal FAN speed...\n"); + writeLogFile(logstr); + + pwm_percent = MIN_PWM_PERCENT + (temp_highest-MIN_FAN_PCB_TEMP) * PWM_ADJUST_FACTOR; + + if(pwm_percent < 0) + pwm_percent = 0; + + if(pwm_percent > MAX_PWM_PERCENT) + pwm_percent=MAX_PWM_PERCENT; + + dev->fan_pwm = pwm_percent; + + last_temperature = temp_highest; + applog(LOG_DEBUG,"%s: Set PWM percent : %d\n", __FUNCTION__, pwm_percent); + set_PWM(pwm_percent); + } + } + else +#endif + { + if(temp_highest >= MAX_FAN_TEMP || temp_highest == 0 || dev->temp_top1[PWM_T]>=MAX_FAN_TEMP || dev->temp_top1[TEMP_POS_LOCAL]>=MAX_FAN_PCB_TEMP)//some board temp is very high than others!!! + { + set_PWM(MAX_PWM_PERCENT); + dev->fan_pwm = MAX_PWM_PERCENT; + + if(fix_fan_steps<0) // if full speed, means too hot, we need set fix_fan_steps=0 , to make sure fan speed up + fix_fan_steps=0; + + sprintf(logstr,"set full FAN speed...\n"); + writeLogFile(logstr); + return; + } + + if(temp_change >= TEMP_INTERVAL || temp_change <= -TEMP_INTERVAL) + { + sprintf(logstr,"set normal FAN speed...with fix_fan_steps=%d\n",fix_fan_steps); + writeLogFile(logstr); + + pwm_percent = MIN_PWM_PERCENT + (temp_highest-MIN_FAN_TEMP+fix_fan_steps) * PWM_ADJUST_FACTOR; + + if(pwm_percent < 0) + pwm_percent = 0; + + if(pwm_percent > MAX_PWM_PERCENT) + pwm_percent=MAX_PWM_PERCENT; + +#ifdef TWO_CHIP_TEMP_S9 + if(dev->temp_top1[PWM_T] > 110 && pwm_percent=MAX_TEMP_NEED_UP_FANSTEP && pwm_percent MAX_PWM_PERCENT) + pwm_percent=MAX_PWM_PERCENT; + } + + dev->fan_pwm = pwm_percent; + + last_temperature = temp_highest; + applog(LOG_DEBUG,"%s: Set PWM percent : %d\n", __FUNCTION__, pwm_percent); + set_PWM(pwm_percent); + } + else + { +#ifdef TWO_CHIP_TEMP_S9 + if(isTempTooLow() && fix_fan_steps > MIN_FAN_TEMP-MIN_TEMP_CONTINUE_DOWN_FAN && pwm_percent > MIN_PWM_PERCENT) +#else + if(temp_highest<=MIN_TEMP_CONTINUE_DOWN_FAN && fix_fan_steps > MIN_FAN_TEMP-MIN_TEMP_CONTINUE_DOWN_FAN && pwm_percent > MIN_PWM_PERCENT) +#endif + { + // if temp is too low, and fan speed > 0 , then we need decrease fix fan steps + fix_fan_steps--; + + sprintf(logstr,"set normal FAN speed... with fix_fan_steps=%d\n",fix_fan_steps); + writeLogFile(logstr); + + pwm_percent = MIN_PWM_PERCENT + (temp_highest-MIN_FAN_TEMP+fix_fan_steps) * PWM_ADJUST_FACTOR; + + if(pwm_percent < 0) + pwm_percent = 0; + + if(pwm_percent > MAX_PWM_PERCENT) + pwm_percent=MAX_PWM_PERCENT; + + dev->fan_pwm = pwm_percent; + set_PWM(pwm_percent); + } +#ifdef TWO_CHIP_TEMP_S9 + else if(dev->temp_top1[PWM_T] > 110 && pwm_percent=MAX_TEMP_NEED_UP_FANSTEP && pwm_percent MAX_PWM_PERCENT) + pwm_percent=MAX_PWM_PERCENT; + + dev->fan_pwm = pwm_percent; + set_PWM(pwm_percent); + } + } + } + } +#endif + + static void get_plldata(int type,int freq,uint32_t * reg_data,uint16_t * reg_data2, uint32_t *vil_data) + { + uint32_t i; + char freq_str[10]; + sprintf(freq_str,"%d", freq); + char plldivider1[32] = {0}; + char plldivider2[32] = {0}; + char vildivider[32] = {0}; + + if(type == 1385) + { + for(i=0; i < sizeof(freq_pll_1385)/sizeof(freq_pll_1385[0]); i++) + { + if( memcmp(freq_pll_1385[i].freq, freq_str, sizeof(freq_pll_1385[i].freq)) == 0) + break; + } + } + + if(i == sizeof(freq_pll_1385)/sizeof(freq_pll_1385[0])) + { + i = 4; + } + + sprintf(plldivider1, "%08x", freq_pll_1385[i].fildiv1); + sprintf(plldivider2, "%04x", freq_pll_1385[i].fildiv2); + sprintf(vildivider, "%04x", freq_pll_1385[i].vilpll); + + *reg_data = freq_pll_1385[i].fildiv1; + *reg_data2 = freq_pll_1385[i].fildiv2; + *vil_data = freq_pll_1385[i].vilpll; + } + + + void set_frequency_with_addr_plldatai(int pllindex,unsigned char mode,unsigned char addr, unsigned char chain) + { + unsigned char buf[9] = {0,0,0,0,0,0,0,0,0}; + unsigned int cmd_buf[3] = {0,0,0}; + int i; + unsigned int ret, value; + uint32_t reg_data_pll = 0; + uint16_t reg_data_pll2 = 0; + uint32_t reg_data_vil = 0; + i = chain; + + reg_data_vil = freq_pll_1385[pllindex].vilpll;; + + //applog(LOG_DEBUG,"%s: i = %d\n", __FUNCTION__, i); + if(!opt_multi_version) // fil mode + { + memset(buf,0,sizeof(buf)); + memset(cmd_buf,0,sizeof(cmd_buf)); + buf[0] = 0; + buf[0] |= SET_PLL_DIVIDER1; + buf[1] = (reg_data_pll >> 16) & 0xff; + buf[2] = (reg_data_pll >> 8) & 0xff; + buf[3] = (reg_data_pll >> 0) & 0xff; + buf[3] |= CRC5(buf, 4*8 - 5); + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + + set_BC_command_buffer(cmd_buf); + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID| (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + + cgsleep_us(3000); + + memset(buf,0,sizeof(buf)); + memset(cmd_buf,0,sizeof(cmd_buf)); + buf[0] = SET_PLL_DIVIDER2; + buf[0] |= COMMAND_FOR_ALL; + buf[1] = 0; //addr + buf[2] = reg_data_pll2 >> 8; + buf[3] = reg_data_pll2& 0x0ff; + buf[3] |= CRC5(buf, 4*8 - 5); + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + + set_BC_command_buffer(cmd_buf); + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID| (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + + cgsleep_us(5000); + } + else // vil + { + memset(buf,0,9); + memset(cmd_buf,0,3*sizeof(int)); + if(mode) + { + buf[0] = VIL_COMMAND_TYPE | VIL_ALL | SET_CONFIG; + } + else + { + buf[0] = VIL_COMMAND_TYPE | SET_CONFIG; + } + + buf[1] = 0x09; + buf[2] = addr; + buf[3] = PLL_PARAMETER; + buf[4] = (reg_data_vil >> 24) & 0xff; + buf[5] = (reg_data_vil >> 16) & 0xff; + buf[6] = (reg_data_vil >> 8) & 0xff; + buf[7] = (reg_data_vil >> 0) & 0xff; + buf[8] = CRC5(buf, 8*8); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + cmd_buf[1] = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];; + cmd_buf[2] = buf[8]<<24; + + while (1) + { + ret = get_BC_write_command(); + if ((ret & 0x80000000) == 0) + break; + cgsleep_us(500); + } + set_BC_command_buffer(cmd_buf); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID| (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + + cgsleep_us(10000); + } + } + + int get_pll_index(int freq) + { + + int i; + char freq_str[10]; + sprintf(freq_str,"%d", freq); + + for(i=0; i < sizeof(freq_pll_1385)/sizeof(freq_pll_1385[0]); i++) + { + if( memcmp(freq_pll_1385[i].freq, freq_str, sizeof(freq_pll_1385[i].freq)) == 0) + break; + } + + + if(i == sizeof(freq_pll_1385)/sizeof(freq_pll_1385[0])) + { + i = -1; + } + + return i; + + } + + int get_freqvalue_by_index(int index) + { + return atoi(freq_pll_1385[index].freq); + } + + int GetTotalRate() + { + int i,j; + int totalrate=0; + for(i=0; ichain_exist[i] == 1) + { + for(j = 0; j < CHAIN_ASIC_NUM; j ++) + { +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + totalrate+=atoi(freq_pll_1385[chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]].freq)*(BM1387_CORE_NUM-chain_badcore_num[i][j]); + } + else + { + totalrate+=atoi(freq_pll_1385[chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]].freq)*(BM1387_CORE_NUM-chain_badcore_num[i][j]); + } +#else + totalrate+=atoi(freq_pll_1385[last_freq[i][j*2+3]].freq)*(BM1387_CORE_NUM-chain_badcore_num[i][j]); +#endif + } + } + } + + return (totalrate/1000); + } + + int GetBoardRate(int chainIndex) + { + int j; + int totalrate=0; + if(dev->chain_exist[chainIndex] == 1) + { + for(j = 0; j < CHAIN_ASIC_NUM; j ++) + { +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(chainIndex,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + totalrate+=atoi(freq_pll_1385[chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]].freq)*(BM1387_CORE_NUM-chain_badcore_num[chainIndex][j]); + } + else + { + totalrate+=atoi(freq_pll_1385[chain_pic_buf[((chainIndex/3)*3)][7+(chainIndex%3)*31+4+j]].freq)*(BM1387_CORE_NUM-chain_badcore_num[chainIndex][j]); + } +#else + totalrate+=atoi(freq_pll_1385[last_freq[chainIndex][j*2+3]].freq)*(BM1387_CORE_NUM-chain_badcore_num[chainIndex][j]); +#endif + } + } + + return (totalrate/1000); + } + +#ifdef R4 + bool isChainEnough() + { + int i,j; + int chainnum=0; + for(i=0; ichain_exist[i] == 1) + { + chainnum++; + } + } + if(chainnum>=2) + return true; + + return false; + } + + static int ConvirtTotalRate(int totalRate) + { + int lowPart; + if(totalRate>=8000 && totalRate<8700) + { + return 8000; + } + else if(totalRate>=8700 && totalRate<9500) + { + return 8700; + } + else + { + lowPart=totalRate%1000; // get the low part rate, GH/s + if(lowPart>500) + lowPart=500; + else lowPart=0; //if lower than 500G, just set zero + + return (((totalRate/1000)*1000)+lowPart); + } + } +#else + bool isChainEnough() + { + int i,j; + int chainnum=0; + for(i=0; ichain_exist[i] == 1) + { + chainnum++; + } + } + +#ifdef T9_18 + if(chainnum>=9) + return true; +#else + if(chainnum>=3) + return true; +#endif + + return false; + } + + static int ConvirtTotalRate(int totalRate) + { + int lowPart=totalRate%1000; // get the low part rate, GH/s + if(lowPart>500) + lowPart=500; + else lowPart=0; //if lower than 500G, just set zero + + return (((totalRate/1000)*1000)+lowPart); + } +#endif + +#if 0 + static void DownOneChipFreqOneStep() + { + int i,j; + uint8_t voltage_array[BITMAIN_MAX_CHAIN_NUM] = {0}; + uint8_t tmp_vol; + int board_rate=0; + int max_freq=0,max_freq_chipIndex=0,max_rate_chainIndex=0; + + memcpy(voltage_array,chain_voltage_pic,sizeof(chain_voltage_pic)); + + // desc order for voltage value + for(i=0; ivoltage_array[j]) + { + tmp_vol=voltage_array[i]; + voltage_array[i]=voltage_array[j]; + voltage_array[j]=tmp_vol; + } + } + } + + for(i=0; i0) + { + board_rate=0; + max_rate_chainIndex=-1; + //find the highest rate board with this voltage + for(j=0; jchain_exist[j] == 1 && chain_voltage_pic[j]==voltage_array[i]) + { + if(board_rate==0 || board_ratechain_asic_num[max_rate_chainIndex]; j ++) + { + if(max_freq==0 || max_freq 250M + if(max_freq<=MIN_FREQ) + continue; + else + { + //down one step + last_freq[max_rate_chainIndex][max_freq_chipIndex*2+3]-=1; // down one step + return; + } + } + } + } +#else + static bool DownOneChipFreqOneStep() + { + int j; + uint8_t tmp_vol; + int board_rate=0; + int max_freq=0,max_freq_chipIndex=0,max_rate_chainIndex=0; + char logstr[1024]; + + board_rate=0; + max_rate_chainIndex=-1; + //find the highest rate board with this voltage + for(j=0; jchain_exist[j] == 1) + { + if(dev->chain_asic_num[j]!=CHAIN_ASIC_NUM) + return false; + + if(board_rate==0 || board_ratechain_asic_num[max_rate_chainIndex]; j ++) + { +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(max_rate_chainIndex,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + + if(max_freq==0 || max_freq 250M + if(max_freq<=MIN_FREQ) + { + sprintf(logstr,"Fatal Error: DownOneChipFreqOneStep Chain[%d] has no chip can down freq!!!\n",max_rate_chainIndex); + writeInitLogFile(logstr); + return false; + } + else + { + //down one step +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(max_rate_chainIndex,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+max_freq_chipIndex]-=1; // down one step + } + else + { + chain_pic_buf[((max_rate_chainIndex/3)*3)][7+(max_rate_chainIndex%3)*31+4+max_freq_chipIndex]-=1; // down one step + } +#else + last_freq[max_rate_chainIndex][max_freq_chipIndex*2+3]-=1; // down one step +#endif + return true; + } + } + +#endif + + static int last_record_freq[BITMAIN_MAX_CHAIN_NUM][256]; + static void ProcessFixFreq() + { + int i,j; + int totalRate=GetTotalRate(); + int fixed_totalRate=ConvirtTotalRate(totalRate); + + if(GetTotalRate()>fixed_totalRate) + { + //need down one step + do + { + //record the current freq + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + for(j = 0; j < CHAIN_ASIC_NUM; j ++) + { +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + last_record_freq[i][j]=chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]; + } + else + { + last_record_freq[i][j]=chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]; + } +#else + last_record_freq[i][j]=last_freq[i][j*2+3]; +#endif + } + } + } + + //do: down one step + if(!DownOneChipFreqOneStep()) + break; // if fatal error, we just break!!! + + } + while(GetTotalRate()>fixed_totalRate); + + // resume the last freq records + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + for(j = 0; j < CHAIN_ASIC_NUM; j ++) + { +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]=last_record_freq[i][j]; + } + else + { + chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]=last_record_freq[i][j]; + } +#else + last_freq[i][j*2+3]=last_record_freq[i][j]; +#endif + } + } + } + } + } + + static void ProcessFixFreqForChips() + { + int i,j; + int totalRate=GetTotalRate(); + int fixed_totalRate=ConvirtTotalRate(totalRate); + + fixed_totalRate=fixed_totalRate*(100+UPRATE_PERCENT)/100; + + if(GetTotalRate()>fixed_totalRate) + { + //need down one step + do + { + //record the current freq + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + for(j = 0; j < CHAIN_ASIC_NUM; j ++) + { +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + last_record_freq[i][j]=chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]; + } + else + { + last_record_freq[i][j]=chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]; + } +#else + last_record_freq[i][j]=last_freq[i][j*2+3]; +#endif + } + } + } + + //do: down one step + if(!DownOneChipFreqOneStep()) + break; // if fatal error, we just break!!! + + } + while(GetTotalRate()>fixed_totalRate); + + // resume the last freq records + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + for(j = 0; j < CHAIN_ASIC_NUM; j ++) + { +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]=last_record_freq[i][j]; + } + else + { + chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]=last_record_freq[i][j]; + } +#else + last_freq[i][j*2+3]=last_record_freq[i][j]; +#endif + } + } + } + } + } + + void writeInitLogFile(char *logstr) + { + FILE *fd; + + pthread_mutex_lock(&init_log_mutex); + fd=fopen("/tmp/freq","a+"); + if(fd) + { + fwrite(logstr,1,strlen(logstr),fd); + fclose(fd); + } + pthread_mutex_unlock(&init_log_mutex); + } + + void clearInitLogFile() + { + FILE *fd; + pthread_mutex_lock(&init_log_mutex); + fd=fopen("/tmp/freq","w"); + if(fd) + fclose(fd); + + if(isFixedFreqMode()) + { + fd=fopen("/tmp/search","w"); + if(fd) + fclose(fd); + fd=fopen("/tmp/freq","w"); + if(fd) + fclose(fd); + fd=fopen("/tmp/lasttemp","w"); + if(fd) + fclose(fd); + } + + pthread_mutex_unlock(&init_log_mutex); + } + + void set_frequency(unsigned short int frequency) + { + unsigned char buf[9] = {0,0,0,0,0,0,0,0,0}; + unsigned int cmd_buf[3] = {0,0,0}; + int i,j,k,max_freq_index = 0,step_down = 0; + unsigned int ret, value; + uint32_t reg_data_pll = 0; + uint16_t reg_data_pll2 = 0; + uint32_t reg_data_vil = 0; + int chain_max_freq,chain_min_freq; + unsigned char vol_pic; + int vol_value; + int default_freq_index=get_pll_index(frequency); + char logstr[1024]; + + applog(LOG_DEBUG,"\n--- %s\n", __FUNCTION__); + + get_plldata(1385, frequency, ®_data_pll, ®_data_pll2, ®_data_vil); + applog(LOG_DEBUG,"%s: frequency = %d\n", __FUNCTION__, frequency); + + //////////////// set default freq when no freq in PIC ////////////////////////////// + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1 && dev->chain_asic_num[i]>0) + { +#ifdef T9_18 + if (isFixedFreqMode() || getChainPICMagicNumber(i) != FREQ_MAGIC) +#else + if (isFixedFreqMode() || last_freq[i][1] != FREQ_MAGIC) +#endif + { + isUseDefaultFreq=true; + +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + chain_pic_buf[new_T9_PLUS_chainIndex][0]=FREQ_MAGIC; + + for(k=0; k<3; k++) // if chain[1] has no magic number, then we need set chain[1] [8] [9] 's freq to default freq!!! + { + for(j = 0; j < CHAIN_ASIC_NUM; j++) + { + chain_pic_buf[new_T9_PLUS_chainIndex][7+k*31+4+j]=default_freq_index; // default is config file's freq + } + } + } + else + { + chain_pic_buf[((i/3)*3)][0]=FREQ_MAGIC; + + for(k=i; k=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + + if(chain_pic_buf[new_T9_PLUS_chainIndex][0]==FREQ_MAGIC && (!isUseDefaultFreq)) + { + sprintf(logstr,"Chain[J%d] has core num in PIC\n",i+1); + writeInitLogFile(logstr); + + for(j = 0; j < CHAIN_ASIC_NUM; j++) + { + if(j%2) + chain_badcore_num[i][j]=(chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+22+(j/2)]&0x0f); + else chain_badcore_num[i][j]=(chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+22+(j/2)]>>4)&0x0f; + + if(chain_badcore_num[i][j]>0) + { + sprintf(logstr,"Chain[J%d] ASIC[%d] has core num=%d\n",i+1,j,chain_badcore_num[i][j]); + writeInitLogFile(logstr); + } + } + } + else + { + sprintf(logstr,"Chain[J%d] has no core num in PIC\n",i+1); + writeInitLogFile(logstr); + + for(j = 0; j < CHAIN_ASIC_NUM; j++) + chain_badcore_num[i][j]=0; // fixed to 0 + } + } + else + { + if(chain_pic_buf[((i/3)*3)][0]==FREQ_MAGIC && (!isUseDefaultFreq)) + { + sprintf(logstr,"Chain[J%d] has core num in PIC\n",i+1); + writeInitLogFile(logstr); + + for(j = 0; j < CHAIN_ASIC_NUM; j++) + { + if(j%2) + chain_badcore_num[i][j]=(chain_pic_buf[((i/3)*3)][7+(i%3)*31+22+(j/2)]&0x0f); + else chain_badcore_num[i][j]=(chain_pic_buf[((i/3)*3)][7+(i%3)*31+22+(j/2)]>>4)&0x0f; + + if(chain_badcore_num[i][j]>0) + { + sprintf(logstr,"Chain[J%d] ASIC[%d] has core num=%d\n",i+1,j,chain_badcore_num[i][j]); + writeInitLogFile(logstr); + } + } + } + else + { + sprintf(logstr,"Chain[J%d] has no core num in PIC\n",i+1); + writeInitLogFile(logstr); + + for(j = 0; j < CHAIN_ASIC_NUM; j++) + chain_badcore_num[i][j]=0; // fixed to 0 + } + } +#else + if(badcore_num_buf[i][0]==BADCORE_MAGIC && (!isUseDefaultFreq)) + { + sprintf(logstr,"Chain[J%d] has core num in PIC\n",i+1); + writeInitLogFile(logstr); + + for(j = 0; j < CHAIN_ASIC_NUM; j++) + { + if(j%2) + chain_badcore_num[i][j]=(badcore_num_buf[i][(j/2)*2+1]&0x0f); + else chain_badcore_num[i][j]=(badcore_num_buf[i][(j/2)*2+1]>>4)&0x0f; + + if(chain_badcore_num[i][j]>0) + { + sprintf(logstr,"Chain[J%d] ASIC[%d] has core num=%d\n",i+1,j,chain_badcore_num[i][j]); + writeInitLogFile(logstr); + } + } + } + else + { + sprintf(logstr,"Chain[J%d] has no core num in PIC\n",i+1); + writeInitLogFile(logstr); + + for(j = 0; j < CHAIN_ASIC_NUM; j++) + chain_badcore_num[i][j]=0; // fixed to 0 + } +#endif + } + } + //////////////////////set default freq END//////////////////////////////////////// + + if(!isUseDefaultFreq) + { + sprintf(logstr,"miner total rate=%dGH/s fixed rate=%dGH/s\n",GetTotalRate(),ConvirtTotalRate(GetTotalRate())); + writeInitLogFile(logstr); + } + + if(!isFixedFreqMode()) + { + //////////////////////// just print freq record, but do not set freq, we need fix freq ///////////////////////// + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + chain_max_freq=0; + chain_min_freq=100; + if(dev->chain_exist[i] == 1 && dev->chain_asic_num[i]>0) + { + vol_pic=get_pic_voltage(i); + vol_value = getVolValueFromPICvoltage(vol_pic); + sprintf(logstr,"read PIC voltage=%d on chain[%d]\n",vol_value,i); + writeInitLogFile(logstr); + + sprintf(logstr,"Chain:%d chipnum=%d\n",i,dev->chain_asic_num[i]); + writeInitLogFile(logstr); +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + + sprintf(logstr,"Chain[J%d] voltage added=0.%dV\n",i+1,chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+2]); + } + else + { + sprintf(logstr,"Chain[J%d] voltage added=0.%dV\n",i+1,chain_pic_buf[((i/3)*3)][7+(i%3)*31+2]); + } +#else + sprintf(logstr,"Chain[J%d] voltage added=0.%dV\n",i+1,last_freq[i][10]&0x3f); +#endif + writeInitLogFile(logstr); + +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + + if(isUseDefaultFreq) + base_freq_index[i]=default_freq_index; + else base_freq_index[i]=chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31]; + sprintf(logstr,"Chain:%d base freq=%s\n",i,freq_pll_1385[base_freq_index[i]].freq); + writeInitLogFile(logstr); + + for(j = 0; j < dev->chain_asic_num[i]; j ++) + { + applog(LOG_DEBUG,"%s: freq index=%d\n", __FUNCTION__,chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]); + + if(chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j] MAX_FREQ) + chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]=MAX_FREQ;// error index, set to index of 850M as max + + if(chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j] > max_freq_index) + max_freq_index = chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]; + + if(chain_max_freqchain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]) + chain_min_freq=chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]; + + // set_frequency_with_addr_plldatai(last_freq[i][j*2+3],0, j * dev->addrInterval,i); + sprintf(logstr,"Asic[%2d]:%s ",j,freq_pll_1385[chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]].freq); + writeInitLogFile(logstr); + if ((j % 8) == 0) + { + sprintf(logstr,"\n"); + writeInitLogFile(logstr); + } + } + } + else + { + if(isUseDefaultFreq) + base_freq_index[i]=default_freq_index; + else base_freq_index[i]=chain_pic_buf[((i/3)*3)][7+(i%3)*31]; + sprintf(logstr,"Chain:%d base freq=%s\n",i,freq_pll_1385[base_freq_index[i]].freq); + writeInitLogFile(logstr); + + for(j = 0; j < dev->chain_asic_num[i]; j ++) + { + applog(LOG_DEBUG,"%s: freq index=%d\n", __FUNCTION__,chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]); + + if(chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j] MAX_FREQ) + chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]=MAX_FREQ;// error index, set to index of 850M as max + + if(chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j] > max_freq_index) + max_freq_index = chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]; + + if(chain_max_freqchain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]) + chain_min_freq=chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]; + + // set_frequency_with_addr_plldatai(last_freq[i][j*2+3],0, j * dev->addrInterval,i); + sprintf(logstr,"Asic[%2d]:%s ",j,freq_pll_1385[chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]].freq); + writeInitLogFile(logstr); + if ((j % 8) == 0) + { + sprintf(logstr,"\n"); + writeInitLogFile(logstr); + } + } + } +#else + pic_temp_offset[i]=((last_freq[i][2]&0x0f)<<4)+(last_freq[i][4]&0x0f); + sprintf(logstr,"Chain:%d temp offset=%d\n",i,(signed char)pic_temp_offset[i]); + writeInitLogFile(logstr); + + if(isUseDefaultFreq) + base_freq_index[i]=default_freq_index; + else base_freq_index[i]=((last_freq[i][6]&0x0f)<<4)+(last_freq[i][8]&0x0f); + sprintf(logstr,"Chain:%d base freq=%s\n",i,freq_pll_1385[base_freq_index[i]].freq); + writeInitLogFile(logstr); + + for(j = 0; j < dev->chain_asic_num[i]; j ++) + { + step_down = last_freq[i][0] & 0x3f; + if(step_down == 0x3f) + step_down = 0; + last_freq[i][j*2+3] -=step_down; // down steps based on the PIC's freq + + applog(LOG_DEBUG,"%s: freq index=%d\n", __FUNCTION__,last_freq[i][j*2+3]); + + if(last_freq[i][j*2+3] MAX_FREQ) + last_freq[i][j*2+3]=MAX_FREQ;// error index, set to index of 850M as max + + if(last_freq[i][j*2+3] > max_freq_index) + max_freq_index = last_freq[i][j*2+3]; + + if(chain_max_freqlast_freq[i][j*2+3]) + chain_min_freq=last_freq[i][j*2+3]; + + // set_frequency_with_addr_plldatai(last_freq[i][j*2+3],0, j * dev->addrInterval,i); + sprintf(logstr,"Asic[%2d]:%s ",j,freq_pll_1385[last_freq[i][j*2+3]].freq); + writeInitLogFile(logstr); + if ((j % 8) == 0) + { + sprintf(logstr,"\n"); + writeInitLogFile(logstr); + } + } +#endif + sprintf(logstr,"\nChain:%d max freq=%s\n",i,freq_pll_1385[chain_max_freq].freq); + writeInitLogFile(logstr); + sprintf(logstr,"Chain:%d min freq=%s\n",i,freq_pll_1385[chain_min_freq].freq); + writeInitLogFile(logstr); + + sprintf(logstr,"\n"); + writeInitLogFile(logstr); + } + } + } + + /////////////////// fix freq and set freq ////////////////////////////////////////// + max_freq_index = 0; + sprintf(logstr,"\nMiner fix freq ...\n"); + writeInitLogFile(logstr); + if((!isUseDefaultFreq) && isChainEnough()) + { + ProcessFixFreqForChips(); //do the real freq fix at first, because this freq is higher than freq showd to users. + } + + // always save real freq into chip_last_freq + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { +#ifdef T9_18 + memcpy(chip_last_freq[i],chain_pic_buf[i],128); +#else + memcpy(chip_last_freq[i],last_freq[i],256); +#endif + } + } + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + chain_max_freq=0; + chain_min_freq=100; + if(dev->chain_exist[i] == 1 && dev->chain_asic_num[i]>0) + { + vol_pic=get_pic_voltage(i); + vol_value = getVolValueFromPICvoltage(vol_pic); + sprintf(logstr,"read PIC voltage=%d on chain[%d]\n",vol_value,i); + writeInitLogFile(logstr); + + sprintf(logstr,"Chain:%d chipnum=%d\n",i,dev->chain_asic_num[i]); + writeInitLogFile(logstr); + + if(!isFixedFreqMode()) + { +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + sprintf(logstr,"Chain[J%d] voltage added=0.%dV\n",i+1,chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+2]); + } + else + { + sprintf(logstr,"Chain[J%d] voltage added=0.%dV\n",i+1,chain_pic_buf[((i/3)*3)][7+(i%3)*31+2]); + } +#else + sprintf(logstr,"Chain[J%d] voltage added=0.%dV\n",i+1,last_freq[i][10]&0x3f); +#endif + writeInitLogFile(logstr); + } + +#ifdef T9_18 + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + + if(!isFixedFreqMode()) + { + if(isUseDefaultFreq) + base_freq_index[i]=default_freq_index; + else base_freq_index[i]=chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31]; + sprintf(logstr,"Chain:%d base freq=%s\n",i,freq_pll_1385[base_freq_index[i]].freq); + writeInitLogFile(logstr); + } + for(j = 0; j < dev->chain_asic_num[i]; j ++) + { + applog(LOG_DEBUG,"%s: freq index=%d\n", __FUNCTION__,chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]); + + if(chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j] MAX_FREQ) + chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]=MAX_FREQ;// error index, set to index of 850M as max + + if(chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j] > max_freq_index) + max_freq_index = chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]; + + if(chain_max_freqchain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]) + chain_min_freq=chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]; + + if(isFixedFreqMode()) // when use fixed freq, we add more 1 step on freq index + //set_frequency_with_addr_plldatai(chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]+1, 0, j * dev->addrInterval, i); + set_frequency_with_addr_plldatai(chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j], 0, j * dev->addrInterval, i); + else + set_frequency_with_addr_plldatai(chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j], 0, j * dev->addrInterval, i); + + sprintf(logstr,"Asic[%2d]:%s ",j,freq_pll_1385[chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]].freq); + writeInitLogFile(logstr); + + if ((j % 8) == 0) + { + sprintf(logstr,"\n"); + writeInitLogFile(logstr); + } + } + + } + else + { + if(!isFixedFreqMode()) + { + if(isUseDefaultFreq) + base_freq_index[i]=default_freq_index; + else base_freq_index[i]=chain_pic_buf[((i/3)*3)][7+(i%3)*31]; + sprintf(logstr,"Chain:%d base freq=%s\n",i,freq_pll_1385[base_freq_index[i]].freq); + writeInitLogFile(logstr); + } + for(j = 0; j < dev->chain_asic_num[i]; j ++) + { + applog(LOG_DEBUG,"%s: freq index=%d\n", __FUNCTION__,chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]); + + if(chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j] MAX_FREQ) + chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]=MAX_FREQ;// error index, set to index of 850M as max + + if(chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j] > max_freq_index) + max_freq_index = chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]; + + if(chain_max_freqchain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]) + chain_min_freq=chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]; + + if(isFixedFreqMode()) // when use fixed freq, we add more 1 step on freq index + //set_frequency_with_addr_plldatai(chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]+1, 0, j * dev->addrInterval, i); + set_frequency_with_addr_plldatai(chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j], 0, j * dev->addrInterval, i); + else + set_frequency_with_addr_plldatai(chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j], 0, j * dev->addrInterval, i); + + sprintf(logstr,"Asic[%2d]:%s ",j,freq_pll_1385[chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]].freq); + writeInitLogFile(logstr); + + if ((j % 8) == 0) + { + sprintf(logstr,"\n"); + writeInitLogFile(logstr); + } + } + } +#else + if(!isFixedFreqMode()) + { + pic_temp_offset[i]=((last_freq[i][2]&0x0f)<<4)+(last_freq[i][4]&0x0f); + sprintf(logstr,"Chain:%d temp offset=%d\n",i,(signed char)pic_temp_offset[i]); + writeInitLogFile(logstr); + + if(isUseDefaultFreq) + base_freq_index[i]=default_freq_index; + else base_freq_index[i]=((last_freq[i][6]&0x0f)<<4)+(last_freq[i][8]&0x0f); + sprintf(logstr,"Chain:%d base freq=%s\n",i,freq_pll_1385[base_freq_index[i]].freq); + writeInitLogFile(logstr); + } + + for(j = 0; j < dev->chain_asic_num[i]; j ++) + { + if(!isFixedFreqMode()) + { + step_down = last_freq[i][0] & 0x3f; + if(step_down == 0x3f) + step_down = 0; + last_freq[i][j*2+3] -=step_down; // down some steps based on the PIC's freq, now NOT USED!!! + } + + applog(LOG_DEBUG,"%s: freq index=%d\n", __FUNCTION__,last_freq[i][j*2+3]); + + if(last_freq[i][j*2+3] MAX_FREQ) + last_freq[i][j*2+3]=MAX_FREQ;// error index, set to index of 850M as max + + if(last_freq[i][j*2+3] > max_freq_index) + max_freq_index = last_freq[i][j*2+3]; + + if(chain_max_freqlast_freq[i][j*2+3]) + chain_min_freq=last_freq[i][j*2+3]; + + if(isFixedFreqMode()) // when use fixed freq, we add more 1 step on freq index + //set_frequency_with_addr_plldatai(last_freq[i][j*2+3]+1,0, j * dev->addrInterval,i); + set_frequency_with_addr_plldatai(last_freq[i][j*2+3],0, j * dev->addrInterval,i); + else + set_frequency_with_addr_plldatai(last_freq[i][j*2+3],0, j * dev->addrInterval,i); + + sprintf(logstr,"Asic[%2d]:%s ",j,freq_pll_1385[last_freq[i][j*2+3]].freq); + writeInitLogFile(logstr); + + if ((j % 8) == 0) + { + sprintf(logstr,"\n"); + writeInitLogFile(logstr); + } + } +#endif + + sprintf(logstr,"\nChain:%d max freq=%s\n",i,freq_pll_1385[chain_max_freq].freq); + writeInitLogFile(logstr); + sprintf(logstr,"Chain:%d min freq=%s\n",i,freq_pll_1385[chain_min_freq].freq); + writeInitLogFile(logstr); + + sprintf(logstr,"\n"); + writeInitLogFile(logstr); + } + } + + value = atoi(freq_pll_1385[max_freq_index].freq); + dev->frequency = value; + sprintf(logstr,"max freq = %d\n",dev->frequency); + writeInitLogFile(logstr); + + if(!isUseDefaultFreq) + { + ProcessFixFreq(); + } + + // always save freq showd to user, into show_last_freq, because the real freq is up 5% when in user mode. + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { +#ifdef T9_18 + memcpy(show_last_freq[i],chain_pic_buf[i],128); +#else + memcpy(show_last_freq[i],last_freq[i],256); +#endif + } + } + +#ifdef DISABLE_TEMP_PROTECT + sprintf(logstr,"\nAttention: Temp Protect Disabled! Debug Mode\n\n"); + writeInitLogFile(logstr); +#endif + } + + void set_frequency_with_addr(unsigned short int frequency,unsigned char mode,unsigned char addr, unsigned char chain) + { + unsigned char buf[9] = {0,0,0,0,0,0,0,0,0}; + unsigned int cmd_buf[3] = {0,0,0}; + int i; + unsigned int ret, value; + uint32_t reg_data_pll = 0; + uint16_t reg_data_pll2 = 0; + uint32_t reg_data_vil = 0; + i = chain; + + applog(LOG_DEBUG,"\n--- %s\n", __FUNCTION__); + + get_plldata(1385, frequency, ®_data_pll, ®_data_pll2, ®_data_vil); + applog(LOG_DEBUG,"%s: frequency = %d\n", __FUNCTION__, frequency); + + //applog(LOG_DEBUG,"%s: i = %d\n", __FUNCTION__, i); + if(!opt_multi_version) // fil mode + { + memset(buf,0,sizeof(buf)); + memset(cmd_buf,0,sizeof(cmd_buf)); + buf[0] = 0; + buf[0] |= SET_PLL_DIVIDER1; + buf[1] = (reg_data_pll >> 16) & 0xff; + buf[2] = (reg_data_pll >> 8) & 0xff; + buf[3] = (reg_data_pll >> 0) & 0xff; + buf[3] |= CRC5(buf, 4*8 - 5); + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + + set_BC_command_buffer(cmd_buf); + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID| (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + + cgsleep_us(3000); + + memset(buf,0,sizeof(buf)); + memset(cmd_buf,0,sizeof(cmd_buf)); + buf[0] = SET_PLL_DIVIDER2; + buf[0] |= COMMAND_FOR_ALL; + buf[1] = 0; //addr + buf[2] = reg_data_pll2 >> 8; + buf[3] = reg_data_pll2& 0x0ff; + buf[3] |= CRC5(buf, 4*8 - 5); + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + + set_BC_command_buffer(cmd_buf); + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID| (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + + dev->freq[i] = frequency; + + cgsleep_us(5000); + } + else // vil + { + memset(buf,0,9); + memset(cmd_buf,0,3*sizeof(int)); + if(mode) + buf[0] = VIL_COMMAND_TYPE | VIL_ALL | SET_CONFIG; + else + buf[0] = VIL_COMMAND_TYPE | SET_CONFIG; + buf[1] = 0x09; + buf[2] = addr; + buf[3] = PLL_PARAMETER; + buf[4] = (reg_data_vil >> 24) & 0xff; + buf[5] = (reg_data_vil >> 16) & 0xff; + buf[6] = (reg_data_vil >> 8) & 0xff; + buf[7] = (reg_data_vil >> 0) & 0xff; + buf[8] = CRC5(buf, 8*8); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + cmd_buf[1] = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];; + cmd_buf[2] = buf[8]<<24; + + set_BC_command_buffer(cmd_buf); + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID| (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + + dev->freq[i] = frequency; + cgsleep_us(10000); + } + } + + + void clear_nonce_fifo() + { + unsigned int buf[2] = {0}; + + pthread_mutex_lock(&nonce_mutex); + nonce_read_out.p_wr = 0; + nonce_read_out.p_rd = 0; + nonce_read_out.nonce_num = 0; + pthread_mutex_unlock(&nonce_mutex); + } + + void clear_register_value_buf() + { + pthread_mutex_lock(®_mutex); + reg_value_buf.p_wr = 0; + reg_value_buf.p_rd = 0; + reg_value_buf.reg_value_num = 0; + //memset(reg_value_buf.reg_buffer, 0, sizeof(struct reg_content)*MAX_NONCE_NUMBER_IN_FIFO); + pthread_mutex_unlock(®_mutex); + } + + void read_asic_register(unsigned char chain, unsigned char mode, unsigned char chip_addr, unsigned char reg_addr) + { + unsigned char buf[5] = {0,0,0,0,0}; + unsigned char buf_vil[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned int cmd_buf[3] = {0,0,0}; + unsigned int ret, value; + char logstr[1024]; + int wait_count=0; + + if(!opt_multi_version) // fil mode + { + buf[0] = GET_STATUS; + buf[1] = chip_addr; + buf[2] = reg_addr; + if (mode) //all + buf[0] |= COMMAND_FOR_ALL; + buf[3] = CRC5(buf, 4*8 - 5); + applog(LOG_DEBUG,"%s: buf[0]=0x%x, buf[1]=0x%x, buf[2]=0x%x, buf[3]=0x%x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + set_BC_command_buffer(cmd_buf); + + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (chain << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + else // vil mode + { + buf[0] = VIL_COMMAND_TYPE | GET_STATUS; + if(mode) + buf[0] |= VIL_ALL; + buf[1] = 0x05; + buf[2] = chip_addr; + buf[3] = reg_addr; + buf[4] = CRC5(buf, 4*8); + applog(LOG_DEBUG,"%s:VIL buf[0]=0x%x, buf[1]=0x%x, buf[2]=0x%x, buf[3]=0x%x, buf[4]=0x%x", __FUNCTION__, buf[0], buf[1], buf[2], buf[3], buf[4]); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + cmd_buf[1] = buf[4]<<24; + + while (1) + { + if (((ret = get_BC_write_command()) & 0x80000000) == 0) + break; + cgsleep_ms(1); + + wait_count++; + + if(wait_count>3000) + { + sprintf(logstr,"Error: clement debug: wait BC ready timeout, PLUG ON=0x%08x..\n",(unsigned int)get_hash_on_plug()); + writeInitLogFile(logstr); + break; + } + } + + set_BC_command_buffer(cmd_buf); + + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (chain << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + } + + void read_temp(unsigned char device,unsigned reg,unsigned char data,unsigned char write,unsigned char chip_addr,int chain) + { + unsigned char buf[9] = {0,0,0,0,0,0,0,0,0}; + unsigned int cmd_buf[3] = {0,0,0}; + unsigned int ret, value,i; + i = chain; + if(!opt_multi_version) + { + //printf("fil mode do not support temp reading"); + } + else + { + buf[0] = VIL_COMMAND_TYPE | SET_CONFIG; + buf[1] = 0x09; + buf[2] = chip_addr; + buf[3] = GENERAL_I2C_COMMAND; + buf[4] = 0x01; + buf[5] = device | write; + buf[6] = reg; + buf[7] = data; + buf[8] = CRC5(buf, 8*8); + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + cmd_buf[1] = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7]; + cmd_buf[2] = buf[8]<<24; + while (1) + { + ret = get_BC_write_command(); + if ((ret & 0x80000000) == 0) + break; + cgsleep_ms(1); + } + set_BC_command_buffer(cmd_buf); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID| (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + + } + + static void suffix_string_soc(uint64_t val, char *buf, size_t bufsiz, int sigdigits,bool display) + { + const double dkilo = 1000.0; + const uint64_t kilo = 1000ull; + const uint64_t mega = 1000000ull; + const uint64_t giga = 1000000000ull; + const uint64_t tera = 1000000000000ull; + const uint64_t peta = 1000000000000000ull; + const uint64_t exa = 1000000000000000000ull; + char suffix[2] = ""; + bool decimal = true; + double dval; + /* + if (val >= exa) + { + val /= peta; + dval = (double)val / dkilo; + strcpy(suffix, "E"); + } + else if (val >= peta) + { + val /= tera; + dval = (double)val / dkilo; + strcpy(suffix, "P"); + } + else if (val >= tera) + { + val /= giga; + dval = (double)val / dkilo; + strcpy(suffix, "T"); + } + else */if (val >= giga) + { + val /= mega; + dval = (double)val / dkilo; + strcpy(suffix, "G"); + } + else if (val >= mega) + { + val /= kilo; + dval = (double)val / dkilo; + strcpy(suffix, "M"); + } + else if (val >= kilo) + { + dval = (double)val / dkilo; + strcpy(suffix, "K"); + } + else + { + dval = val; + decimal = false; + } + + if (!sigdigits) + { + if (decimal) + snprintf(buf, bufsiz, "%.3g%s", dval, suffix); + else + snprintf(buf, bufsiz, "%d%s", (unsigned int)dval, suffix); + } + else + { + /* Always show sigdigits + 1, padded on right with zeroes + * followed by suffix */ + int ndigits = sigdigits - 1 - (dval > 0.0 ? floor(log10(dval)) : 0); + if(display) + snprintf(buf, bufsiz, "%*.*f%s", sigdigits + 1, ndigits, dval, suffix); + else + snprintf(buf, bufsiz, "%*.*f", sigdigits + 1, ndigits, dval); + + } + } + + void showAllBadRTInfo() + { + int i,j; + char logstr[1024]; + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1 +#ifdef DEBUG_XILINX_NONCE_NOTENOUGH + && i!=DISABLE_REG_CHAIN_INDEX +#endif + ) + { + sprintf(logstr,"Check Chain[J%d] ASIC RT error: (asic index start from 1-%d)\n",i+1,CHAIN_ASIC_NUM); + writeLogFile(logstr); + + for(j=0; j100) + { + sprintf(logstr,"Asic[%02d]=%f\n",j+1,chain_asic_RT[i][j]); + writeLogFile(logstr); + } + } + } + } + } + + bool check_asic_reg(unsigned int reg) + { + int i, j, not_reg_data_time=0; + int nonce_number = 0; + unsigned int buf[2] = {0}; + unsigned int reg_value_num=0; + unsigned int temp_nonce = 0; + unsigned char reg_buf[5] = {0,0,0,0,0}; + int read_num = 0; + uint64_t tmp_rate = 0; + int reg_processed_counter=0; + char logstr[1024]; + + rerun_all: + clear_register_value_buf(); + tmp_rate = 0; + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + reg_processed_counter=0; + read_num = 0; + if(dev->chain_exist[i] == 1 +#ifdef DEBUG_XILINX_NONCE_NOTENOUGH + && i!=DISABLE_REG_CHAIN_INDEX +#endif + ) + { + tmp_rate = 0; + + // sprintf(logstr,"do read_asic_register on Chain[%d]...\n",i); + // writeLogFile(logstr); + + read_asic_register(i, 1, 0, reg); + + // sprintf(logstr,"Done read_asic_register on Chain[%d]\n",i); + // writeLogFile(logstr); + + if (reg ==CHIP_ADDRESS) + dev->chain_asic_num[i] = 0; + + if(reg == 0x08) + { + sprintf(logstr,"\nget RT hashrate from Chain[%d]: (asic index start from 1-%d)\n",i,CHAIN_ASIC_NUM); + writeLogFile(logstr); + } + + while(not_reg_data_time < 3) //if there is no register value for 3 times, we can think all asic return their address + { + cgsleep_ms(300); + + pthread_mutex_lock(®_mutex); + reg_value_num = reg_value_buf.reg_value_num; + + if((reg_value_num >= MAX_NONCE_NUMBER_IN_FIFO || reg_value_buf.p_rd >= MAX_NONCE_NUMBER_IN_FIFO) && not_reg_data_time <3) + { + not_reg_data_time ++; + pthread_mutex_unlock(®_mutex); + goto rerun_all; + } + if(not_reg_data_time == 3) + { + pthread_mutex_unlock(®_mutex); + return true; + } + + if(reg_value_num > 0) + { + reg_processed_counter+=reg_value_num; + + if(reg_processed_counter>600) + { + // sprintf(logstr,"read asic reg Error on Chain[%d]\n",i); + // writeInitLogFile(logstr); + + pthread_mutex_unlock(®_mutex); + return false; + } + + // sprintf(logstr,"process reg_value_num=%d on Chain[%d]\n",reg_value_num,i); + // writeLogFile(logstr); + + not_reg_data_time = 0; + + for(j = 0; j < reg_value_num; j++) + { + if(reg_value_buf.reg_buffer[reg_value_buf.p_rd].chain_number != i) + { + // sprintf(logstr,"read asic reg Error: wrong chain number=%d on Chain[%d]\n",i); + // writeInitLogFile(logstr); + + reg_value_buf.p_rd++; + reg_value_buf.reg_value_num--; + if(reg_value_buf.p_rd >= MAX_NONCE_NUMBER_IN_FIFO) + { + reg_value_buf.p_rd = 0; + } + + continue; + } + + reg_buf[3] = (unsigned char)(reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value & 0xff); + reg_buf[2] = (unsigned char)((reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value >> 8) & 0xff); + reg_buf[1] = (unsigned char)((reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value >> 16)& 0xff); + reg_buf[0] = (unsigned char)((reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value >> 24)& 0xff); + +#ifdef ENABLE_REGISTER_CRC_CHECK + if(CRC5(reg_buf, (REGISTER_DATA_LENGTH+3)*8-5) != reg_value_buf.reg_buffer[reg_value_buf.p_rd].crc) + { + sprintf(logstr,"%s: crc is 0x%x, but it should be 0x%x\n", __FUNCTION__, CRC5(reg_buf, (REGISTER_DATA_LENGTH+1)*8-5), reg_value_buf.reg_buffer[reg_value_buf.p_rd].crc); + writeInitLogFile(logstr); + + reg_value_buf.p_rd++; + reg_value_buf.reg_value_num--; + if(reg_value_buf.p_rd >= MAX_NONCE_NUMBER_IN_FIFO) + { + reg_value_buf.p_rd = 0; + } + + continue; + } +#endif + reg_value_buf.p_rd++; + reg_value_buf.reg_value_num--; + if(reg_value_buf.p_rd >= MAX_NONCE_NUMBER_IN_FIFO) + { + reg_value_buf.p_rd = 0; + } + + if(reg == CHIP_ADDRESS) + { + dev->chain_asic_num[i]++; + } + + if(reg == PLL_PARAMETER) + { + sprintf(logstr,"chain[%d]: the asic freq is 0x%x\n", i, reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value); + writeInitLogFile(logstr); + } + + if(reg == TICKET_MASK) + { + sprintf(logstr,"chain[%d]: the asic TICKET_MASK is 0x%x\n", i, reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value); + writeInitLogFile(logstr); + } + + if(reg == 0x08) + { + int ii; + char displayed_rate_asic[32]; + uint64_t temp_hash_rate = 0; + uint8_t rate_buf[10]; + uint8_t displayed_rate[16]; + + read_num ++; + if(read_num<=CHAIN_ASIC_NUM) + { + for(ii = 0; ii < 4; ii++) + { + sprintf(rate_buf + 2*ii,"%02x",reg_buf[ii]); + } + + // sprintf(logstr,"%s: hashrate is %s\n", __FUNCTION__, rate_buf); + // writeInitLogFile(logstr); + + temp_hash_rate = strtol(rate_buf,NULL,16); + temp_hash_rate = (temp_hash_rate << 24); + tmp_rate += temp_hash_rate; + + suffix_string_soc(temp_hash_rate, displayed_rate_asic, sizeof(displayed_rate_asic), 6,false); + sprintf(logstr,"Asic[%02d]=%s ",read_num,displayed_rate_asic); + writeLogFile(logstr); + + chain_asic_RT[i][read_num-1]=atof(displayed_rate_asic); + + if(read_num%8 == 0 || read_num==CHAIN_ASIC_NUM) + { + sprintf(logstr,"\n"); + writeLogFile(logstr); + } + } + } + } + + if(reg == CHIP_ADDRESS) + { + if (dev->chain_asic_num[i] == CHAIN_ASIC_NUM) + { + pthread_mutex_unlock(®_mutex); + break; + } + } + + // sprintf(logstr,"Done reg_value_num=%d on Chain[%d]\n",reg_value_num,i); + // writeLogFile(logstr); + } + else + { + cgsleep_ms(100); + not_reg_data_time++; + + // sprintf(logstr,"not_reg_data_time=%d on Chain[%d]\n",not_reg_data_time,i); + // writeLogFile(logstr); + } + + pthread_mutex_unlock(®_mutex); + } + + not_reg_data_time = 0; + + if(reg == CHIP_ADDRESS) + { + if(dev->chain_asic_num[i] > dev->max_asic_num_in_one_chain) + { + dev->max_asic_num_in_one_chain = dev->chain_asic_num[i]; + } + } + if(read_num == dev->chain_asic_num[i]) + { + rate[i] = tmp_rate; + suffix_string_soc(rate[i], (char * )displayed_rate[i], sizeof(displayed_rate[i]), 6,false); + rate_error[i] = 0; + + // sprintf(logstr,"%s: chain %d hashrate is %s\n", __FUNCTION__, i, displayed_rate[i]); + // writeInitLogFile(logstr); + } + + if(read_num == 0 || status_error ) + { + rate_error[i]++; + if(rate_error[i] > 3 || status_error) + { + rate[i] = 0; + suffix_string_soc(rate[i], (char * )displayed_rate[i], sizeof(displayed_rate[i]), 6,false); + } + } + //set_nonce_fifo_interrupt(get_nonce_fifo_interrupt() & ~(FLUSH_NONCE3_FIFO)); + clear_register_value_buf(); + } + } + + return true; + } + + void reset_one_hashboard(int chainIndex) + { + set_QN_write_data_command(RESET_HASH_BOARD | CHAIN_ID(chainIndex) | RESET_TIME(RESET_HASHBOARD_TIME)); + while(get_QN_write_data_command() & RESET_HASH_BOARD) + { + usleep(10000); + } + sleep(1); + } + + bool check_asic_reg_oneChain(int chainIndex, unsigned int reg) + { + + int i, j, not_reg_data_time=0; + int nonce_number = 0; + unsigned int buf[2] = {0}; + unsigned int reg_value_num=0; + unsigned int temp_nonce = 0; + unsigned char reg_buf[5] = {0,0,0,0,0}; + int read_num = 0; + uint64_t tmp_rate = 0; + int reg_processed_counter=0; + char logstr[1024]; + + rerun_all: + clear_register_value_buf(); + tmp_rate = 0; + //for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + i=chainIndex; + { + reg_processed_counter=0; + read_num = 0; + if(dev->chain_exist[i] == 1) + { + tmp_rate = 0; + + // sprintf(logstr,"do read_asic_register on Chain[%d]...\n",i); + // writeLogFile(logstr); + + read_asic_register(i, 1, 0, reg); + + // sprintf(logstr,"Done read_asic_register on Chain[%d]\n",i); + // writeLogFile(logstr); + + if (reg ==CHIP_ADDRESS) + dev->chain_asic_num[i] = 0; + + while(not_reg_data_time < 3) //if there is no register value for 3 times, we can think all asic return their address + { + cgsleep_ms(300); + + pthread_mutex_lock(®_mutex); + reg_value_num = reg_value_buf.reg_value_num; + + if((reg_value_num >= MAX_NONCE_NUMBER_IN_FIFO || reg_value_buf.p_rd >= MAX_NONCE_NUMBER_IN_FIFO) && not_reg_data_time <3) + { + not_reg_data_time ++; + pthread_mutex_unlock(®_mutex); + goto rerun_all; + } + if(not_reg_data_time == 3) + { + pthread_mutex_unlock(®_mutex); + return true; + } + + if(reg_value_num > 0) + { + reg_processed_counter+=reg_value_num; + + if(reg_processed_counter>600) + { + // sprintf(logstr,"read asic reg Error on Chain[%d]\n",i); + // writeInitLogFile(logstr); + pthread_mutex_unlock(®_mutex); + return false; + } + + // sprintf(logstr,"process reg_value_num=%d on Chain[%d]\n",reg_value_num,i); + // writeLogFile(logstr); + + not_reg_data_time = 0; + + for(j = 0; j < reg_value_num; j++) + { + if(reg_value_buf.reg_buffer[reg_value_buf.p_rd].chain_number != i) + { + reg_value_buf.p_rd++; + reg_value_buf.reg_value_num--; + if(reg_value_buf.p_rd >= MAX_NONCE_NUMBER_IN_FIFO) + { + reg_value_buf.p_rd = 0; + } + + continue; + } + + reg_buf[3] = (unsigned char)(reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value & 0xff); + reg_buf[2] = (unsigned char)((reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value >> 8) & 0xff); + reg_buf[1] = (unsigned char)((reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value >> 16)& 0xff); + reg_buf[0] = (unsigned char)((reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value >> 24)& 0xff); + +#ifdef ENABLE_REGISTER_CRC_CHECK + if(CRC5(reg_buf, (REGISTER_DATA_LENGTH+3)*8-5) != reg_value_buf.reg_buffer[reg_value_buf.p_rd].crc) + { + sprintf(logstr,"%s: crc is 0x%x, but it should be 0x%x\n", __FUNCTION__, CRC5(reg_buf, (REGISTER_DATA_LENGTH+1)*8-5), reg_value_buf.reg_buffer[reg_value_buf.p_rd].crc); + writeInitLogFile(logstr); + + reg_value_buf.p_rd++; + reg_value_buf.reg_value_num--; + if(reg_value_buf.p_rd >= MAX_NONCE_NUMBER_IN_FIFO) + { + reg_value_buf.p_rd = 0; + } + + continue; + } +#endif + reg_value_buf.p_rd++; + reg_value_buf.reg_value_num--; + if(reg_value_buf.p_rd >= MAX_NONCE_NUMBER_IN_FIFO) + { + reg_value_buf.p_rd = 0; + } + + if(reg == CHIP_ADDRESS) + { + dev->chain_asic_num[i]++; + } + + if(reg == PLL_PARAMETER) + { + applog(LOG_DEBUG,"%s: the asic freq is 0x%x\n", __FUNCTION__, reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value); + } + + if(reg == 0x08) + { + int i; + uint64_t temp_hash_rate = 0; + uint8_t rate_buf[10]; + uint8_t displayed_rate[16]; + for(i = 0; i < 4; i++) + { + sprintf(rate_buf + 2*i,"%02x",reg_buf[i]); + } + applog(LOG_DEBUG,"%s: hashrate is %s\n", __FUNCTION__, rate_buf); + temp_hash_rate = strtol(rate_buf,NULL,16); + temp_hash_rate = (temp_hash_rate << 24); + tmp_rate += temp_hash_rate; + read_num ++; + } + } + + if(reg == CHIP_ADDRESS) + { + if (dev->chain_asic_num[i] == CHAIN_ASIC_NUM) + { + pthread_mutex_unlock(®_mutex); + break; + } + } + + // sprintf(logstr,"Done reg_value_num=%d on Chain[%d]\n",reg_value_num,i); + // writeLogFile(logstr); + } + else + { + cgsleep_ms(100); + not_reg_data_time++; + + // sprintf(logstr,"not_reg_data_time=%d on Chain[%d]\n",not_reg_data_time,i); + // writeLogFile(logstr); + } + + pthread_mutex_unlock(®_mutex); + } + + not_reg_data_time = 0; + + if(reg == CHIP_ADDRESS) + { + if(dev->chain_asic_num[i] > dev->max_asic_num_in_one_chain) + { + dev->max_asic_num_in_one_chain = dev->chain_asic_num[i]; + } + } + if(read_num == dev->chain_asic_num[i]) + { + rate[i] = tmp_rate; + suffix_string_soc(rate[i], (char * )displayed_rate[i], sizeof(displayed_rate[i]), 6,false); + rate_error[i] = 0; + applog(LOG_DEBUG,"%s: chain %d hashrate is %s\n", __FUNCTION__, i, displayed_rate[i]); + } + if(read_num == 0 || status_error ) + { + rate_error[i]++; + if(rate_error[i] > 3 || status_error) + { + rate[i] = 0; + suffix_string_soc(rate[i], (char * )displayed_rate[i], sizeof(displayed_rate[i]), 6,false); + } + } + //set_nonce_fifo_interrupt(get_nonce_fifo_interrupt() & ~(FLUSH_NONCE3_FIFO)); + clear_register_value_buf(); + } + } + + return true; + } + + +#define RETRY_NUM 5 + unsigned int check_asic_reg_with_addr(unsigned int reg,unsigned int chip_addr,unsigned int chain, int check_num) + { + int i, j, not_reg_data_time=0; + int nonce_number = 0; + unsigned int reg_value_num=0; + unsigned int reg_buf = 0; + i = chain; + rerun: + clear_register_value_buf(); + read_asic_register(i, 0, chip_addr, reg); + cgsleep_ms(80); + + while(not_reg_data_time < RETRY_NUM) //if there is no register value for 3 times, we can think all asic return their address + { + pthread_mutex_lock(®_mutex); + reg_value_num = reg_value_buf.reg_value_num; + //applog(LOG_NOTICE,"%s: p_wr = %d reg_value_num = %d\n", __FUNCTION__,reg_value_buf.p_wr,reg_value_buf.reg_value_num); + pthread_mutex_unlock(®_mutex); + + applog(LOG_DEBUG,"%s: reg_value_num %d", __FUNCTION__, reg_value_num); + if((reg_value_num >= MAX_NONCE_NUMBER_IN_FIFO || reg_value_buf.p_rd >= MAX_NONCE_NUMBER_IN_FIFO ||reg_value_num ==0 ) && not_reg_data_time = RETRY_NUM) + { + return 0; + } + + pthread_mutex_lock(®_mutex); + for(i = 0; i < reg_value_num; i++) + { + reg_buf = reg_value_buf.reg_buffer[reg_value_buf.p_rd].reg_value; + applog(LOG_DEBUG,"%s: chip %x reg %x reg_buff %x", __FUNCTION__, chip_addr,reg,reg_buf); + reg_value_buf.p_rd++; + reg_value_buf.reg_value_num--; + // clement: why ? I need change it +#if 0 + if(reg_value_buf.p_rd < MAX_NONCE_NUMBER_IN_FIFO) + { + reg_value_buf.p_rd = 0; + } +#else + if(reg_value_buf.p_rd >= MAX_NONCE_NUMBER_IN_FIFO) + { + reg_value_buf.p_rd = 0; + } +#endif + + if(reg == GENERAL_I2C_COMMAND) + { + if((reg_buf & 0xc0000000) == 0x0) + { + pthread_mutex_unlock(®_mutex); + clear_register_value_buf(); + return reg_buf; + } + else + { + pthread_mutex_unlock(®_mutex); + clear_register_value_buf(); + return 0; + } + } + } + pthread_mutex_unlock(®_mutex); + } + //set_nonce_fifo_interrupt(get_nonce_fifo_interrupt() & ~(FLUSH_NONCE3_FIFO)); + clear_register_value_buf(); + return 0; + } + + unsigned int wait_iic_ok(unsigned int chip_addr,unsigned int chain,bool update) + { + int fail_time = 0; + unsigned int ret = 0; + while(fail_time < 2) + { + ret = check_asic_reg_with_addr(GENERAL_I2C_COMMAND,chip_addr,chain,1); + if (ret != 0) + { + return ret; + } + else + { + fail_time++; + cgsleep_ms(1); + } + } + return 0; + } + + unsigned int check_reg_temp(unsigned char device,unsigned reg,unsigned char data,unsigned char write,unsigned char chip_addr,int chain) + { + int fail_time =0; + unsigned int ret; + if(!write) + { + do + { + wait_iic_ok(chip_addr,chain,0); + read_temp(device, reg, data, write,chip_addr,chain); + cgsleep_ms(1); + ret = wait_iic_ok(chip_addr,chain,1); + cgsleep_ms(1); + fail_time++; + } + while (((ret & 0xff00) >>8 != reg || (ret & 0xff) == 0xff || (ret & 0xff) == 0x7f ) && fail_time < 2); + } + else + { + do + { + wait_iic_ok(chip_addr,chain,0); + read_temp(device, reg, data, write,chip_addr,chain); + wait_iic_ok(chip_addr,chain,1); + cgsleep_ms(1); + wait_iic_ok(chip_addr,chain,0); + read_temp(device, reg, 0, 0,chip_addr,chain); + ret = wait_iic_ok(chip_addr,chain,1); + cgsleep_ms(1); + fail_time++; + } + while (((ret & 0xff00) >>8 != reg && (ret & 0xff) != data )&& fail_time < 2); + } + + if (fail_time == 2) + return 0; + else + return ret; + } + +#ifdef USE_N_OFFSET_FIX_TEMP + int8_t calc_offset(int remote, int local) + { + float t_noise; + t_noise = remote - ((1.11-1.008)/1.008)*(273.15 + local) - local; + return (int8_t)(0 - t_noise); + } + + int16_t get_remote(int16_t remote) + { + float t_re_re; +#ifdef EXTEND_TEMP_MODE + remote = remote - 64; +#endif + t_re_re = (1.008 * (remote) - (1.11 - 1.008) * 273.15) / 1.11; + applog(LOG_DEBUG,"remote : %"PRId16" temp : %f",remote,t_re_re); + return (int16_t)(t_re_re); + } + + int16_t get_local(int16_t local) + { + +#ifdef EXTEND_TEMP_MODE + local = local - 64; +#endif + return local; + } + + int8_t do_calibration_sensor_offset(unsigned char device,unsigned char chip_addr,int chain, int temp_chip_index) + { + int8_t offset = 0; + int8_t middle,local = 0; + int16_t ret = 0; + int8_t error_Limit = 0; + int8_t retry_Time_Count = 0; + int get_value_once=0; + int check_ok_counter=0; + char logstr[1024]; + + ret = check_reg_temp(device, 0xfe, 0x0, 0, chip_addr, chain); // Read Local Temp, Without Any Exception? + dev->TempChipType[chain][temp_chip_index]= ret & 0xff; + + if(dev->TempChipType[chain][temp_chip_index]==0x1a) //debug for 218 + is218_Temp=true; + +#ifdef EXTEND_TEMP_MODE + check_reg_temp(device, 0x9, 0x04, 1, chip_addr, chain); +#endif + check_reg_temp(device, 0x11, offset, 1, chip_addr, chain); // Set offset + ret = check_reg_temp(device, 0x0, 0x0, 0, chip_addr, chain); // Read Local Temp, Without Any Exception? + local = get_local(ret & 0xff); + + ret = check_reg_temp(device, 0x1, 0x0, 0, chip_addr, chain); // Read Remote Temp + +#ifdef EXTEND_TEMP_MODE + middle = ret & 0xff - 64; +#else + middle = ret & 0xff; +#endif + offset = calc_offset(middle,local); + ret = check_reg_temp(device, 0x11, offset, 1, chip_addr, chain); //set offset + + sprintf(logstr,"New offset Chain[%d] chip[%d] local:%hhd remote:%hhd offset:%hhd \n",chain,chip_addr,local,middle,offset); + writeInitLogFile(logstr); + + return offset; + } + + +#else + + int16_t get_remote(int16_t remote) + { +#ifdef EXTEND_TEMP_MODE + remote = remote - 64; +#endif + return remote; + } + + int16_t get_local(int16_t local) + { + +#ifdef EXTEND_TEMP_MODE + local = local - 64; +#endif + return local; + } + + + int8_t do_calibration_sensor_offset(unsigned char device,unsigned char chip_addr,int chain, int temp_chip_index) + { + int8_t offset = 0xba; + int8_t middle,local = 0; + unsigned int ret = 0; + int8_t error_Limit = 0; + int8_t retry_Time_Count = 0; + int get_value_once=0; + int check_ok_counter=0; + char logstr[1024]; + + ret = check_reg_temp(device, 0xfe, 0x0, 0, chip_addr, chain); // Read Local Temp, Without Any Exception? + dev->TempChipType[chain][temp_chip_index]= ret & 0xff; + + if(dev->TempChipType[chain][temp_chip_index]==0x1a) //debug for 218 + is218_Temp=true; + +// applog(LOG_NOTICE,"chain %d local:%hhd remote:%hhd offset:%hhd",chain,local,middle,offset); + do + { + ret = check_reg_temp(device, 0x0, 0x0, 0, chip_addr, chain); // Read Local Temp, Without Any Exception? + local = ret & 0xff; + + if ( retry_Time_Count++ > MAX_RETRY_COUNT ) + { + // TODO: What To Do? + applog(LOG_WARNING,"calibration for %d times",retry_Time_Count); + break; + } + + ret = check_reg_temp(device, 0x11, offset, 1, chip_addr, chain); // Set offset + ret = check_reg_temp(device, 0x1, 0x0, 0, chip_addr, chain); // Read Remote Temp + middle = ret & 0xff; + + if(middle==0 && get_value_once==0) + { + error_Limit=MAX_ERROR_LIMIT_ABS+1; //force to do again + offset = offset + 30; // -70 default is out of temp value. + } + else + { + get_value_once=1; // sometime, if temp is 0, there is a chance , local=0 , middle=0, but this is not error, middle really is 0, so if we get one value for the first time, then we will not check middle==0 again!!! + error_Limit = middle - local; + offset = offset + (local - middle); + } +// applog(LOG_NOTICE,"%s chain %d local:%hhd remote:%hhd offset:%hhd", __FUNCTION__,chain,local,middle,offset); + sprintf(logstr,"Chain[%d] chip[%d] local:%hhd remote:%hhd offset:%hhd \n",chain,chip_addr,local,middle,offset); + writeInitLogFile(logstr); + + if(abs(error_Limit) <= MAX_ERROR_LIMIT_ABS) + check_ok_counter++; + else + check_ok_counter=0; + } + while (check_ok_counter<3); + + return offset; + } +#endif + + void set_baud_with_addr(unsigned char bauddiv,int mode,unsigned char chip_addr,int chain,int iic,int open_core,int bottom_or_mid) + { + unsigned char buf[9] = {0,0,0,0,0,0,0,0,0}; + unsigned int cmd_buf[3] = {0,0,0}; + unsigned int ret, value,i; + i = chain; + + //first step: send new bauddiv to ASIC, but FPGA doesn't change its bauddiv, it uses old bauddiv to send BC command to ASIC + if(!opt_multi_version) // fil mode + { + buf[0] = SET_BAUD_OPS; + buf[1] = 0x10; + buf[2] = bauddiv & 0x1f; + buf[0] |= COMMAND_FOR_ALL; + buf[3] = CRC5(buf, 4*8 - 5); + applog(LOG_DEBUG,"%s: buf[0]=0x%x, buf[1]=0x%x, buf[2]=0x%x, buf[3]=0x%x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + set_BC_command_buffer(cmd_buf); + + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + else // vil mode + { + buf[0] = VIL_COMMAND_TYPE | SET_CONFIG; + if(mode) + buf[0] = VIL_COMMAND_TYPE | SET_CONFIG |VIL_ALL; + buf[1] = 0x09; + buf[2] = chip_addr; + buf[3] = MISC_CONTROL; + buf[4] = 0x40; + if(bottom_or_mid) + buf[5] = 0x20; + else + buf[5] = 0x21; + + if(iic) + { + buf[6] = (bauddiv & 0x1f) | 0x40; + buf[7] = 0x60; + } + else + { + buf[6] = (bauddiv & 0x1f); + buf[7] = 0x00; + } + if(open_core) + buf[6] = buf[6]| GATEBCLK; + buf[8] = 0; + buf[8] = CRC5(buf, 8*8); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + cmd_buf[1] = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7]; + cmd_buf[2] = buf[8]<<24; + + while (1) + { + if (((ret = get_BC_write_command()) & 0x80000000) == 0) + break; + cgsleep_ms(1); + } + set_BC_command_buffer(cmd_buf); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID| (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + } + + int8_t calibration_sensor_offset(unsigned char device, int chain) + { + int i; + signed char temp_offset[8]; + unsigned int ret = 0; + char logstr[1024]; + int8_t middle,local = 0; + +#ifdef T9_18 + if(fpga_version>=0xE) + { + if(chain!=8 && chain!=10 && chain!=12) // only chain 8, 10, 12... has temp sensor!!! + return 0; + } + else + { + if(chain%3 != 1) // only chain 1, 4, 7... has temp sensor!!! + return 0; + } +#endif + +#ifndef TWO_CHIP_TEMP_S9 + get_temperature_offset_value(chain,temp_offset); + sprintf(logstr,"Chain[J%d] PIC temp offset=%d,%d,%d,%d,%d,%d,%d,%d\n",chain+1,temp_offset[0],temp_offset[1],temp_offset[2],temp_offset[3],temp_offset[4],temp_offset[5],temp_offset[6],temp_offset[7]); + writeInitLogFile(logstr); + + dev->chain_asic_temp_num[chain]=0; + for(i=0; i<4; i++) + { + if(temp_offset[2*i]>0) + { + dev->TempChipAddr[chain][dev->chain_asic_temp_num[chain]]=(temp_offset[2*i]-1)*4; + middle_Offset[chain][dev->chain_asic_temp_num[chain]] = temp_offset[2*i+1]; + + set_baud_with_addr(dev->baud, 0, dev->TempChipAddr[chain][dev->chain_asic_temp_num[chain]], chain, 1, 0, (int) TEMP_MIDDLE); + check_asic_reg_with_addr(MISC_CONTROL,dev->TempChipAddr[chain][dev->chain_asic_temp_num[chain]],chain,1); + + ret = check_reg_temp(device, 0xfe, 0x0, 0, dev->TempChipAddr[chain][dev->chain_asic_temp_num[chain]], chain); // Read Local Temp, Without Any Exception? + dev->TempChipType[chain][dev->chain_asic_temp_num[chain]]= ret & 0xff; + + sprintf(logstr,"Chain[J%d] chip[%d] use PIC middle temp offset=%d typeID=%02x\n",chain+1,dev->TempChipAddr[chain][dev->chain_asic_temp_num[chain]],middle_Offset[chain][dev->chain_asic_temp_num[chain]],dev->TempChipType[chain][dev->chain_asic_temp_num[chain]]); + writeInitLogFile(logstr); + + if(dev->TempChipType[chain][dev->chain_asic_temp_num[chain]]!=0x1a && dev->TempChipType[chain][dev->chain_asic_temp_num[chain]]!=0x55) + { + dev->chain_asic_temp_num[chain]=0; + break; // error, we just jump out + } + + if(dev->TempChipType[chain][dev->chain_asic_temp_num[chain]]==0x1a) //debug for 218 + is218_Temp=true; +#ifndef USE_N_OFFSET_FIX_TEMP +#ifdef EXTEND_TEMP_MODE + check_reg_temp(device, 0x9, 0x04, 1, dev->TempChipAddr[chain][dev->chain_asic_temp_num[chain]], chain); +#endif + + ret = check_reg_temp(device, 0x0, 0x0, 0, dev->TempChipAddr[chain][dev->chain_asic_temp_num[chain]], chain); // Read Local Temp, Without Any Exception? +#ifdef EXTEND_TEMP_MODE + local = ret & 0xff - 64; +#else + local = ret & 0xff; +#endif + ret = check_reg_temp(device, 0x11, middle_Offset[chain][dev->chain_asic_temp_num[chain]], 1, dev->TempChipAddr[chain][dev->chain_asic_temp_num[chain]], chain); // Set offset + ret = check_reg_temp(device, 0x1, 0x0, 0, dev->TempChipAddr[chain][dev->chain_asic_temp_num[chain]], chain); // Read Remote Temp +#ifdef EXTEND_TEMP_MODE + middle = ret & 0xff - 64; +#else + middle = ret & 0xff; +#endif + + if(local-middle > 2 || local-middle < -2) // we allow 2 degree diff + { + sprintf(logstr,"Warning: Chain[J%d] use PIC temp offset local=%d > middle=%d, need calculate offset ...!\n",chain+1,local,middle); + writeInitLogFile(logstr); +#endif + + middle_Offset[chain][dev->chain_asic_temp_num[chain]] = do_calibration_sensor_offset(device, dev->TempChipAddr[chain][dev->chain_asic_temp_num[chain]],chain,dev->chain_asic_temp_num[chain]); + + sprintf(logstr,"Chain[J%d] chip[%d] get middle temp offset=%d typeID=%02x\n",chain+1,dev->TempChipAddr[chain][i],middle_Offset[chain][dev->chain_asic_temp_num[chain]],dev->TempChipType[chain][dev->chain_asic_temp_num[chain]]); + writeInitLogFile(logstr); +#ifndef USE_N_OFFSET_FIX_TEMP + } +#endif + dev->chain_asic_temp_num[chain]++; + } + } + + if(dev->chain_asic_temp_num[chain]<=0) + { + sprintf(logstr,"Warning: Chain[J%d] has no temp offset in PIC! will fix it\n",chain+1); + writeInitLogFile(logstr); + +#ifdef R4 + dev->chain_asic_temp_num[chain]=2; + dev->TempChipAddr[chain][0]=0x8; + dev->TempChipAddr[chain][1]=0xC; +#endif + +#ifdef S9_PLUS + dev->chain_asic_temp_num[chain]=2; + dev->TempChipAddr[chain][0]=112; // (29-1)* 4 + dev->TempChipAddr[chain][1]=4; // (2-1)* 4 +#endif + +#ifdef S9_63 + dev->chain_asic_temp_num[chain]=1; + dev->TempChipAddr[chain][0]=0xF4; +#endif + +#ifdef T9_18 + dev->chain_asic_temp_num[chain]=2; + dev->TempChipAddr[chain][0]=0; // (1-1)* 4 + dev->TempChipAddr[chain][1]=32; // (9-1)* 4 +#endif + + // Set Each Temp Offset + // 0. Switch To Middle + // 1. Calibration + for(i=0; ichain_asic_temp_num[chain]; i++) + { + set_baud_with_addr(dev->baud, 0, dev->TempChipAddr[chain][i], chain, 1, 0, (int) TEMP_MIDDLE); + check_asic_reg_with_addr(MISC_CONTROL,dev->TempChipAddr[chain][i],chain,1); + middle_Offset[chain][i] = do_calibration_sensor_offset(device, dev->TempChipAddr[chain][i],chain,i); + + sprintf(logstr,"Chain[J%d] chip[%d] get middle temp offset=%d typeID=%02x\n",chain+1,dev->TempChipAddr[chain][i],middle_Offset[chain][i],dev->TempChipType[chain][i]); + writeInitLogFile(logstr); + } + } +#else + dev->chain_asic_temp_num[chain]=2; + dev->TempChipAddr[chain][0]=0xF4; + dev->TempChipAddr[chain][1]=0x60; + + // Set Each Temp Offset + // 0. Switch To Middle + // 1. Calibration + for(i=0; ichain_asic_temp_num[chain]; i++) + { + set_baud_with_addr(dev->baud, 0, dev->TempChipAddr[chain][i], chain, 1, 0, (int) TEMP_MIDDLE); + check_asic_reg_with_addr(MISC_CONTROL,dev->TempChipAddr[chain][i],chain,1); + middle_Offset[chain][i] = do_calibration_sensor_offset(device, dev->TempChipAddr[chain][i],chain,i); + + sprintf(logstr,"Chain[J%d] chip[%d] get middle temp offset=%d typeID=%02x\n",chain+1,dev->TempChipAddr[chain][i],middle_Offset[chain][i],dev->TempChipType[chain][i]); + writeInitLogFile(logstr); + } +#endif + +#ifdef SHOW_BOTTOM_TEMP + // 2. Switch To Bottom + for(i=0; ichain_asic_temp_num[chain]; i++) + { + set_baud_with_addr(dev->baud, 0, dev->TempChipAddr[chain][i], chain, 1, 0, (int) TEMP_BOTTOM); + check_asic_reg_with_addr(MISC_CONTROL,dev->TempChipAddr[chain][i],chain,1); + bottom_Offset[chain][i] = do_calibration_sensor_offset(device, dev->TempChipAddr[chain][i],chain,i); + + sprintf(logstr,"Chain[J%d] chip[%d] get bottom temp offset=%d\n",chain+1,dev->TempChipAddr[chain][i],bottom_Offset[chain][i]); + writeInitLogFile(logstr); + } +#endif + return 0; + } + + void clearTempLogFile() + { + FILE *fd; + fd=fopen("/tmp/temp","w"); + if(fd) + { + fclose(fd); + } + } + + void writeLogFile(char *logstr) + { + FILE *fd; + fd=fopen("/tmp/temp","a+"); + if(fd) + { + fwrite(logstr,1,strlen(logstr),fd); + fclose(fd); + } + } + + void updateLogFile() + { + system("cp /tmp/temp /tmp/lasttemp"); + } + + void saveTestID(int testID) + { + FILE *fd; + char testnumStr[32]; + fd=fopen("/etc/config/testID","wb"); + if(fd) + { + memset(testnumStr,'\0',sizeof(testnumStr)); + sprintf(testnumStr,"%d",testID); + fwrite(testnumStr,1,sizeof(testnumStr),fd); + fclose(fd); + } + } + int readTestID() + { + FILE *fd; + char testnumStr[32]; + fd=fopen("/etc/config/testID","rb"); + if(fd) + { + memset(testnumStr,'\0',sizeof(testnumStr)); + fread(testnumStr,1,sizeof(testnumStr),fd); + fclose(fd); + + return atoi(testnumStr); + } + return 0; + } + + void do8xPattenTest() + { + int i=0; + + doTestPatten=true; + startCheckNetworkJob=false; + pthread_mutex_lock(&reinit_mutex); + + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & ~RUN_BIT); + sleep(3); + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & ~RUN_BIT); + sleep(2); + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { +#ifdef T9_18 + memcpy(chain_pic_buf[i],chip_last_freq[i],128); // restore the real freq for chips +#else + memcpy(last_freq[i],chip_last_freq[i],256); // restore the real freq for chips +#endif + } + } + + set_asic_ticket_mask(0); + clement_doTestBoardOnce(true); + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { +#ifdef T9_18 + memcpy(chain_pic_buf[i],show_last_freq[i],128); // restore the user freq for showed on web for users +#else + memcpy(last_freq[i],show_last_freq[i],256); // restore the user freq for showed on web for users +#endif + } + } + + // must re-set these two address to FPGA + set_nonce2_and_job_id_store_address(PHY_MEM_NONCE2_JOBID_ADDRESS); + set_job_start_address(PHY_MEM_JOB_START_ADDRESS_1); + +#ifndef CAPTURE_PATTEN + set_asic_ticket_mask(63); // clement + cgsleep_ms(10); +#endif + + set_nonce_fifo_interrupt(get_nonce_fifo_interrupt() | FLUSH_NONCE3_FIFO); + clear_nonce_fifo(); + + //set real timeout back + if(opt_multi_version) + set_time_out_control(((dev->timeout * opt_multi_version) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + else + set_time_out_control(((dev->timeout) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + + doTestPatten=false; + pthread_mutex_unlock(&reinit_mutex); + re_send_last_job(); + cgtime(&tv_send_job); + cgtime(&tv_send); + startCheckNetworkJob=true; + } + + void bitmain_reinit_test() + { + char ret=0,j; + uint16_t crc = 0; + + int i=0,x = 0,y = 0; + int hardware_version; + unsigned int data = 0; + bool testRet; + int testCounter=0; + char logstr[1024]; + + pthread_mutex_lock(&iic_mutex); + + // clear all dev values + memset(dev,0x00,sizeof(struct all_parameters)); + dev->current_job_start_address = job_start_address_1; + +#ifdef USE_NEW_RESET_FPGA + set_reset_allhashboard(1); + sleep(RESET_KEEP_TIME); + set_reset_allhashboard(0); + sleep(1); + set_reset_allhashboard(1); +#endif + + //reset FPGA & HASH board + { + set_QN_write_data_command(RESET_HASH_BOARD | RESET_ALL | RESET_FPGA | RESET_TIME(RESET_HASHBOARD_TIME)); +#ifdef USE_NEW_RESET_FPGA + sleep(2); +#else + while(get_QN_write_data_command() & RESET_HASH_BOARD) + { + cgsleep_ms(30); + } + cgsleep_ms(500); +#endif + set_PWM(MAX_PWM_PERCENT); + } + +#ifdef T9_18 + // config fpga into T9+ mode + set_Hardware_version(0x80000000); +#endif + + set_nonce2_and_job_id_store_address(PHY_MEM_NONCE2_JOBID_ADDRESS); + set_job_start_address(PHY_MEM_JOB_START_ADDRESS_1); + //check chain + check_chain(); + +#ifdef USE_NEW_RESET_FPGA + set_reset_allhashboard(1); +#endif + +#ifdef T9_18 + // close DC, T9_18 only can reset PIC to close DC, because of enable_pic_dAc FUNC can not be called for more than 1 time. it cause PIC error with IIC communication + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + reset_iic_pic(i); + jump_to_app_CheckAndRestorePIC_T9_18(i); + } + } + + sleep(1); +#endif + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { +#ifdef ENABLE_HIGH_VOLTAGE_OPENCORE + unsigned char vol_pic; + chain_voltage_pic[i] = get_pic_voltage(i); // read orignal voltage at first! + vol_pic=getPICvoltageFromValue(HIGHEST_VOLTAGE_LIMITED_HW); + + // sprintf(logstr,"Chain[J%d] will use highest voltage=%d [%d] to open core\n",i+1,HIGHEST_VOLTAGE_LIMITED_HW,vol_pic); + // writeInitLogFile(logstr); + +#ifdef T9_18 + if(fpga_version>=0xE) + { + if(i>=1 && i<=3) + set_voltage_T9_18_into_PIC(i, vol_pic); + } + else + { + if(i%3==0) + set_voltage_T9_18_into_PIC(i, vol_pic); + } +#else + set_pic_voltage(i, vol_pic); +#endif + +#endif + +#ifndef T9_18 + disable_pic_dac(i); +#endif + } + } + + cgsleep_ms(1000); + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + int vol_value; + unsigned char vol_pic; + +#ifndef ENABLE_HIGH_VOLTAGE_OPENCORE + chain_voltage_pic[i] = get_pic_voltage(i); +#endif + vol_value = getVolValueFromPICvoltage(chain_voltage_pic[i]); + + sprintf(logstr,"Chain[J%d] working voltage=%d value=%d\n",i+1,chain_voltage_pic[i],vol_value); + writeInitLogFile(logstr); + +#ifdef T9_18 + if(getChainPICMagicNumber(i) == FREQ_MAGIC) +#else + if(last_freq[i][1] == FREQ_MAGIC && last_freq[i][40] == 0x23) //0x23 is backup voltage magic number +#endif + { + if(vol_value < chain_voltage_value[i]) + { + vol_pic=getPICvoltageFromValue(chain_voltage_value[i]); + + sprintf(logstr,"Chain[J%d] will use backup chain_voltage_pic=%d [%d]\n",i+1,chain_voltage_value[i],vol_pic); + writeInitLogFile(logstr); + +#ifndef ENABLE_HIGH_VOLTAGE_OPENCORE + set_pic_voltage(i, vol_pic); + chain_voltage_pic[i] = get_pic_voltage(i); +#else + chain_voltage_pic[i] = vol_pic; +#endif + sprintf(logstr,"Chain[J%d] get working voltage=%d\n",i+1,chain_voltage_pic[i]); + writeInitLogFile(logstr); + } + } + } + } + +#ifdef T9_18 + // set voltage and enable it for only once!!! + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + set_pic_voltage(i, 0); // the second parameter is not used, we set 0 for T9_18 + enable_pic_dac(i); + } + } + sleep(5); // wait for sometime , voltage need time to prepare!!! +#else + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + enable_pic_dac(i); + } + } +#endif + pthread_mutex_unlock(&iic_mutex); + cgsleep_ms(2000); + +#ifdef USE_NEW_RESET_FPGA + set_reset_allhashboard(1); + sleep(RESET_KEEP_TIME); + set_reset_allhashboard(0); + sleep(1); +#else + set_QN_write_data_command(RESET_HASH_BOARD | RESET_ALL | RESET_TIME(RESET_HASHBOARD_TIME)); + while(get_QN_write_data_command() & RESET_HASH_BOARD) + { + cgsleep_ms(30); + } + cgsleep_ms(1000); +#endif + + if(opt_multi_version) + set_dhash_acc_control(get_dhash_acc_control() & (~OPERATION_MODE) | VIL_MODE | VIL_MIDSTATE_NUMBER(opt_multi_version) & (~NEW_BLOCK) & (~RUN_BIT)); + cgsleep_ms(10); + + //set core number + dev->corenum = BM1387_CORE_NUM; + +#ifdef USE_PREINIT_OPENCORE + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + getAsicNum_preOpenCore(i); + + sprintf(logstr,"Chain[J%d] has %d asic\n",i+1,dev->chain_asic_num[i]); + writeInitLogFile(logstr); + + if(dev->chain_asic_num[i] != CHAIN_ASIC_NUM && readRebootTestNum()>0) + { + char error_info[256]; + sprintf(error_info,"J%d:3",i+1); + saveSearchFailedFlagInfo(error_info); + + system("reboot"); + } + + if(dev->chain_asic_num[i]<=0) + { + dev->chain_exist[i]=0; + } + } + } +#else + //check ASIC number for every chain + check_asic_reg(CHIP_ADDRESS); + cgsleep_ms(10); + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + int retry_count=0; + sprintf(logstr,"Chain[J%d] has %d asic\n",i+1,dev->chain_asic_num[i]); + writeInitLogFile(logstr); + +#ifndef T9_18 + while(dev->chain_asic_num[i] != CHAIN_ASIC_NUM && retry_count<6) + { + dev->chain_asic_num[i]=0; + +#ifdef USE_NEW_RESET_FPGA + set_reset_hashboard(i,1); +#endif + pthread_mutex_lock(&iic_mutex); + disable_pic_dac(i); + pthread_mutex_unlock(&iic_mutex); + sleep(1); + + pthread_mutex_lock(&iic_mutex); + enable_pic_dac(i); + pthread_mutex_unlock(&iic_mutex); + sleep(2); + +#ifdef USE_NEW_RESET_FPGA + set_reset_hashboard(i,0); + sleep(1); +#else + reset_one_hashboard(i); +#endif + check_asic_reg_oneChain(i,CHIP_ADDRESS); + + retry_count++; + } +#endif + + if(dev->chain_asic_num[i]<=0) + dev->chain_exist[i]=0; + + sprintf(logstr,"retry Chain[J%d] has %d asic\n",i+1,dev->chain_asic_num[i]); + writeInitLogFile(logstr); + } + } +#endif + + software_set_address(); + cgsleep_ms(10); + + if(config_parameter.frequency_eft) + { + dev->frequency = config_parameter.frequency; + set_frequency(dev->frequency); + sprintf(dev->frequency_t,"%u",dev->frequency); + } + + cgsleep_ms(10); + + //check who control fan + dev->fan_eft = config_parameter.fan_eft; + dev->fan_pwm= config_parameter.fan_pwm_percent; + applog(LOG_DEBUG,"%s: fan_eft : %d fan_pwm : %d\n", __FUNCTION__,dev->fan_eft,dev->fan_pwm); + if(config_parameter.fan_eft) + { + if((config_parameter.fan_pwm_percent >= 0) && (config_parameter.fan_pwm_percent <= 100)) + { + set_PWM(config_parameter.fan_pwm_percent); + } + else + { + set_PWM_according_to_temperature(); + } + } + else + { + set_PWM_according_to_temperature(); + } + + //calculate real timeout + if(config_parameter.timeout_eft) + { + if(config_parameter.timeout_data_integer == 0 && config_parameter.timeout_data_fractions == 0) //driver calculate out timeout value + { + // clement change to 70/100 org: 90/100 +#ifdef CAPTURE_PATTEN + dev->timeout = 0x1000000/calculate_core_number(dev->corenum)*dev->addrInterval/(dev->frequency)*30/100; +#else + dev->timeout = 0x1000000/calculate_core_number(dev->corenum)*dev->addrInterval/(dev->frequency)*90/100; +#endif + // for set_freq_auto test,set timeout when frequency equals 700M + // dev->timeout = 0x1000000/calculate_core_number(dev->corenum)*dev->addrInterval/700*90/100; + applog(LOG_DEBUG,"dev->timeout = %d\n", dev->timeout); + } + else + { + dev->timeout = config_parameter.timeout_data_integer * 1000 + config_parameter.timeout_data_fractions; + } + + if(dev->timeout > MAX_TIMEOUT_VALUE) + { + dev->timeout = MAX_TIMEOUT_VALUE; + } + } + + //set baud + init_uart_baud(); + cgsleep_ms(10); + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1 && dev->chain_asic_num[i] == CHAIN_ASIC_NUM) + { + calibration_sensor_offset(0x98,i); + cgsleep_ms(10); + } + } + +#ifdef T9_18 + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1 && dev->chain_asic_num[i] == CHAIN_ASIC_NUM) + { + if(fpga_version>=0xE) + { + switch(i) // only chain 8, 10, 12... has temp sensor!!! we just copy to other chains. + { + case 1: + case 9: + dev->chain_asic_temp_num[i]=dev->chain_asic_temp_num[8]; + dev->TempChipAddr[i][0]=dev->TempChipAddr[8][0]; + dev->TempChipAddr[i][1]=dev->TempChipAddr[8][1]; + break; + case 2: + case 11: + dev->chain_asic_temp_num[i]=dev->chain_asic_temp_num[10]; + dev->TempChipAddr[i][0]=dev->TempChipAddr[10][0]; + dev->TempChipAddr[i][1]=dev->TempChipAddr[10][1]; + break; + case 3: + case 13: + dev->chain_asic_temp_num[i]=dev->chain_asic_temp_num[12]; + dev->TempChipAddr[i][0]=dev->TempChipAddr[12][0]; + dev->TempChipAddr[i][1]=dev->TempChipAddr[12][1]; + break; + } + } + else + { + if(i%3 != 1) // only chain 1, 4, 7... has temp sensor!!! we just copy chain[1] temp info into chain[0] and chain[2] + { + dev->chain_asic_temp_num[i]=dev->chain_asic_temp_num[((i/3)*3)+1]; + dev->TempChipAddr[i][0]=dev->TempChipAddr[((i/3)*3)+1][0]; + dev->TempChipAddr[i][1]=dev->TempChipAddr[((i/3)*3)+1][1]; + } + } + } + } +#endif + + //set big timeout value for open core + //set_time_out_control((MAX_TIMEOUT_VALUE - 100) | TIME_OUT_VALID); + set_time_out_control(0xc350 | TIME_OUT_VALID); + +#ifdef ENABLE_HIGH_VOLTAGE_OPENCORE + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { +#ifdef USE_OPENCORE_ONEBYONE + opencore_onebyone_onChain(i); +#else + open_core_one_chain(i,true); +#endif + sleep(1); + +#ifdef T9_18 + if(fpga_version>=0xE) + { + if(i==1) + { + // we must try open core on chain [8] and chain[9] ... +#ifdef USE_OPENCORE_ONEBYONE + opencore_onebyone_onChain(8); + sleep(1); + opencore_onebyone_onChain(9); + sleep(1); +#else + open_core_one_chain(8,true); + sleep(1); + open_core_one_chain(9,true); + sleep(1); +#endif + } + else if(i==2) + { +#ifdef USE_OPENCORE_ONEBYONE + opencore_onebyone_onChain(10); + sleep(1); + opencore_onebyone_onChain(11); + sleep(1); +#else + open_core_one_chain(10,true); + sleep(1); + open_core_one_chain(11,true); + sleep(1); +#endif + } + else if(i==3) + { +#ifdef USE_OPENCORE_ONEBYONE + opencore_onebyone_onChain(12); + sleep(1); + opencore_onebyone_onChain(13); + sleep(1); +#else + open_core_one_chain(12,true); + sleep(1); + open_core_one_chain(13,true); + sleep(1); +#endif + } + else break; // we jump out of open core loop. because we have done open core above!!! + + pthread_mutex_lock(&iic_mutex); + set_pic_voltage(i, chain_voltage_pic[i]); + pthread_mutex_unlock(&iic_mutex); + sprintf(logstr,"Chain[J%d] set working voltage=%d [%d]\n",i+1,getVolValueFromPICvoltage(chain_voltage_pic[i]),chain_voltage_pic[i]); + writeInitLogFile(logstr); + } + else + { + if(i%3==2) // only set working voltage when open core done on last chain of 3 chains!!! + { + pthread_mutex_lock(&iic_mutex); + set_pic_voltage(i, chain_voltage_pic[i]); + pthread_mutex_unlock(&iic_mutex); + } + + sprintf(logstr,"Chain[J%d] set working voltage=%d [%d]\n",i+1,getVolValueFromPICvoltage(chain_voltage_pic[i]),chain_voltage_pic[i]); + writeInitLogFile(logstr); + } +#else + pthread_mutex_lock(&iic_mutex); + // restore the normal voltage + set_pic_voltage(i, chain_voltage_pic[i]); + pthread_mutex_unlock(&iic_mutex); + + sprintf(logstr,"Chain[J%d] set working voltage=%d [%d]\n",i+1,getVolValueFromPICvoltage(chain_voltage_pic[i]),chain_voltage_pic[i]); + writeInitLogFile(logstr); +#endif + } + } +#else + open_core(true); +#endif + + //set real timeout back + if(opt_multi_version) + set_time_out_control(((dev->timeout * opt_multi_version) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + else + set_time_out_control(((dev->timeout) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + } + + + void doReInitTest() + { + int i; + + doTestPatten=true; + startCheckNetworkJob=false; + pthread_mutex_lock(&reinit_mutex); + + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & ~RUN_BIT); + sleep(3); + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & ~RUN_BIT); + sleep(2); + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { +#ifdef T9_18 + memcpy(chain_pic_buf[i],show_last_freq[i],128); // restore the user freq for showed on web for users +#else + memcpy(last_freq[i],show_last_freq[i],256); // restore the user freq for showed on web for users +#endif + } + } + + // must re-set these two address to FPGA + set_nonce2_and_job_id_store_address(PHY_MEM_NONCE2_JOBID_ADDRESS); + set_job_start_address(PHY_MEM_JOB_START_ADDRESS_1); + + doTestPatten=false; + bitmain_reinit_test(); + doTestPatten=true; + + // must re-set these two address to FPGA + set_nonce2_and_job_id_store_address(PHY_MEM_NONCE2_JOBID_ADDRESS); + set_job_start_address(PHY_MEM_JOB_START_ADDRESS_1); + +#ifndef CAPTURE_PATTEN + set_asic_ticket_mask(63); // clement + cgsleep_ms(10); +#endif + + set_nonce_fifo_interrupt(get_nonce_fifo_interrupt() | FLUSH_NONCE3_FIFO); + clear_nonce_fifo(); + + //set real timeout back + if(opt_multi_version) + set_time_out_control(((dev->timeout * opt_multi_version) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + else + set_time_out_control(((dev->timeout) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + + doTestPatten=false; + pthread_mutex_unlock(&reinit_mutex); + re_send_last_job(); + cgtime(&tv_send_job); + cgtime(&tv_send); + startCheckNetworkJob=true; + } + + void processTEST() + { + char logstr[1024]; + int testID=readTestID(); + int chainIndex; + int i; + int cur_vol_pic,cur_vol_value,set_vol_value; + + if(testID==11) + { + // test : do 8xPatten test + saveTestID(0); + + sprintf(logstr,"get TEST ID=%d do 8xPatten test\n",testID); + writeInitLogFile(logstr); + + do8xPattenTest(); + } + else if(testID==12) + { + // test : do open core + saveTestID(0); + + sprintf(logstr,"get TEST ID=%d do bitmain_core_reInit test\n",testID); + writeInitLogFile(logstr); + + bitmain_core_reInit(); + reCalculateAVG(); + + sprintf(logstr,"Done bitmain_core_reInit test\n"); + writeInitLogFile(logstr); + + } + else if(testID==13) + { + // test : do re-init + saveTestID(0); + + sprintf(logstr,"get TEST ID=%d do doReInitTest test\n",testID); + writeInitLogFile(logstr); + + doReInitTest(); + reCalculateAVG(); + + sprintf(logstr,"Done doReInitTest test\n"); + writeInitLogFile(logstr); + } + else if(testID==14) + { + // test : do get asicnum + saveTestID(0); + + sprintf(logstr,"get TEST ID=%d do do get asicnum\n",testID); + writeInitLogFile(logstr); + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + dev->chain_asic_num[i]=0; + check_asic_reg_oneChain(i,CHIP_ADDRESS); + + sprintf(logstr,"Chain[J%d] has %d asic\n",i+1,dev->chain_asic_num[i]); + writeInitLogFile(logstr); + } + } + + sprintf(logstr,"Done do get asicnum\n"); + writeInitLogFile(logstr); + } + else if(testID>=101 && testID<=116) + { + // force to add voltage 0.1V on one board + saveTestID(0); + + chainIndex=(testID%100)-1; + + sprintf(logstr,"get TEST ID=%d up voltage 0.1V on Chain[J%d]\n",testID,chainIndex+1); + writeInitLogFile(logstr); + + i=chainIndex; + { + if(dev->chain_exist[i] == 1) + { + cur_vol_pic = get_pic_voltage(i); + cur_vol_value = getVolValueFromPICvoltage(cur_vol_pic); + + if(cur_vol_value+10>940) + { + sprintf(logstr,"Chain[J%d] current vol=%d , too high! will set to 940\n",i+1,cur_vol_value); + writeInitLogFile(logstr); + + set_vol_value=940; + } + else set_vol_value=cur_vol_value+10; + + sprintf(logstr,"Try to up 0.1V on chain[J%d] from vol=%d to %d...\n",i+1,cur_vol_value,set_vol_value); + writeInitLogFile(logstr); + + cur_vol_pic=getPICvoltageFromValue(set_vol_value); + sprintf(logstr,"now set pic voltage=%d on chain[J%d]\n",cur_vol_pic,i+1); + writeInitLogFile(logstr); + + set_pic_voltage(i, cur_vol_pic); + } + else + { + sprintf(logstr,"There is hashboard on Chain[J%d]\n",i+1); + writeInitLogFile(logstr); + } + } + } + else if(testID>=201 && testID<=216) + { + // force to decrease voltage 0.1V on one board + saveTestID(0); + + chainIndex=(testID%100)-1; + + sprintf(logstr,"get TEST ID=%d down voltage 0.1V on Chain[J%d]\n",testID, chainIndex+1); + writeInitLogFile(logstr); + + i=chainIndex; + { + if(dev->chain_exist[i] == 1) + { + cur_vol_pic = get_pic_voltage(i); + cur_vol_value = getVolValueFromPICvoltage(cur_vol_pic); + + if(cur_vol_value-10<860) + { + sprintf(logstr,"Chain[J%d] current vol=%d , too low! will set to 860\n",i+1,cur_vol_value); + writeInitLogFile(logstr); + + set_vol_value=860; + } + else set_vol_value=cur_vol_value-10; + + sprintf(logstr,"Try to down 0.1V on chain[J%d] from vol=%d to %d...\n",i+1,cur_vol_value,set_vol_value); + writeInitLogFile(logstr); + + cur_vol_pic=getPICvoltageFromValue(set_vol_value); + sprintf(logstr,"now set pic voltage=%d on chain[J%d]\n",cur_vol_pic,i+1); + writeInitLogFile(logstr); + + set_pic_voltage(i, cur_vol_pic); + } + else + { + sprintf(logstr,"There is hashboard on Chain[J%d]\n",i+1); + writeInitLogFile(logstr); + } + } + } + } + + int fakeMiddleTempFromPCB(int local_temp) + { + if(local_temp<=0) + return 0; + else if(local_temp<=50) + return local_temp+25; + else if(local_temp<=60) + return local_temp+30; + else + return local_temp+35; + } + +#define OFFSIDE_TOP 125 +#define OFFSIDE_LOW 75 + void * read_temp_func() + { + char logstr[1024]; + char error_info[256]; + struct timeval diff; + int i,j; + unsigned int ret = 0; + unsigned int ret0 = 0; + unsigned int ret1 = 0; + unsigned int ret2 = 0; + unsigned int ret3 = 0; + int chain_asic_temp_error[BITMAIN_MAX_CHAIN_NUM][MAX_TEMPCHIP_NUM]= {0}; + + int16_t temp_top[TEMP_POS_NUM]; + int16_t temp_low[TEMP_POS_NUM]; + bool already_offside = false; + + Temp_Type_E temp_Type = TEMP_MIDDLE; + + int maxtemp[TEMP_POS_NUM]; + int mintemp[TEMP_POS_NUM]; + int cur_fan_num=0; + int fatal_error_counter=0; + + clearTempLogFile(); + +// sprintf(logstr,"start read_temp_func ...\n"); +// writeLogFile(logstr); + + while(1) + { +#if 0 //def DEBUG_XILINX_NONCE_NOTENOUGH + // only change fan speed after read temp value!!! + check_fan(); + + set_PWM(MAX_PWM_PERCENT); + dev->fan_pwm = MAX_PWM_PERCENT; + + sleep(10); + continue; +#endif + +#ifndef KEEP_TEMPFAN_LOG + clearTempLogFile(); +#endif + + sprintf(logstr,"do read_temp_func once...\n"); + writeLogFile(logstr); + + pthread_mutex_lock(&opencore_readtemp_mutex); + + sprintf(logstr,"do check_asic_reg 0x08\n"); + writeLogFile(logstr); + + // read hashrate RT + if(doTestPatten) + usleep(100000); + else + { + // sprintf(logstr,"call check_asic_reg(0x08)\n"); + // writeLogFile(logstr); + if(!check_asic_reg(0x08)) + { + sprintf(logstr,"Error: check_asic_reg 0x08 timeout\n"); + writeInitLogFile(logstr); + } + else showAllBadRTInfo(); + } + + sprintf(logstr,"Done check_asic_reg\n"); + writeLogFile(logstr); + + memset(temp_top,0x00,sizeof(temp_top)); + memset(temp_low,0x00,sizeof(temp_low)); + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1 +#ifdef DEBUG_XILINX_NONCE_NOTENOUGH + && i!=DISABLE_REG_CHAIN_INDEX +#endif + ) //clement for debug + { +#ifdef T9_18 + if(fpga_version>=0xE) + { + if(i!=8 && i!=10 && i!=12) // only 8,10,12... has temp sensor!!! we just copy temp value to other chains! + continue; + } + else + { + if(i%3 != 1) // only 1,4,7... has temp sensor!!! we just copy temp value to other chains! + continue; + } +#endif + + sprintf(logstr,"do read temp on Chain[%d]\n",i); + writeLogFile(logstr); + + maxtemp[TEMP_POS_LOCAL]=0; + maxtemp[TEMP_POS_MIDDLE]=0; + maxtemp[TEMP_POS_BOTTOM]=0; + + mintemp[TEMP_POS_LOCAL]=1000; + mintemp[TEMP_POS_MIDDLE]=1000; + mintemp[TEMP_POS_BOTTOM]=1000; // set 1000, as init value + + for(j=0; jchain_asic_temp_num[i]; j++) + { + // sprintf(logstr,"do read temp chip[%d] addr=%d on Chain[%d]\n",j,TempChipAddr[j],i); + // writeLogFile(logstr); + + sprintf(logstr,"Chain[%d] Chip[%d] TempTypeID=%02x middle offset=%d\n",i, (dev->TempChipAddr[i][j]/4)+1, dev->TempChipType[i][j],middle_Offset[i][j]); + writeLogFile(logstr); + + ret = check_reg_temp(0x98, 0x00, 0x0, 0x0, dev->TempChipAddr[i][j], i); + if (ret != 0) + { + dev->chain_asic_temp[i][j][TEMP_POS_LOCAL] = get_local(ret & 0xff); + + sprintf(logstr,"Chain[%d] Chip[%d] local Temp=%d\n",i, (dev->TempChipAddr[i][j]/4)+1, dev->chain_asic_temp[i][j][TEMP_POS_LOCAL]); + writeLogFile(logstr); + } + else + { + sprintf(logstr,"read failed, old value: Chain[%d] Chip[%d] local Temp=%d\n",i,(dev->TempChipAddr[i][j]/4)+1,dev->chain_asic_temp[i][j][TEMP_POS_LOCAL]); + writeLogFile(logstr); + } + + // 0. Switch To Middle + set_baud_with_addr(dev->baud, 0, dev->TempChipAddr[i][j], i, 1, 0, (int) TEMP_MIDDLE); + check_asic_reg_with_addr(MISC_CONTROL,dev->TempChipAddr[i][j],i,1); + +#if ((!defined USE_N_OFFSET_FIX_TEMP) && (!defined EXTEND_TEMP_MODE)) + if(dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]<125) + { + middle_Offset_sw[i][j]=0; + } + // set middle offset + if(middle_Offset_sw[i][j]!=0) + { + ret = check_reg_temp(0x98, 0x11, middle_Offset_sw[i][j], 1, dev->TempChipAddr[i][j], i); // Set offset + } + else + ret = check_reg_temp(0x98, 0x11, middle_Offset[i][j], 1, dev->TempChipAddr[i][j], i); // Set offset +#endif + ret = check_reg_temp(0x98, 0x01, 0x0, 0x0, dev->TempChipAddr[i][j], i); + if (ret != 0) + { + dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE] = get_remote(ret & 0xff); + +#if ((!defined USE_N_OFFSET_FIX_TEMP) && (!defined EXTEND_TEMP_MODE)) + if(middle_Offset_sw[i][j]!=0) + dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]=dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE] - middle_Offset_sw[i][j]; +#endif + sprintf(logstr,"Chain[%d] Chip[%d] middle Temp=%d\n",i,(dev->TempChipAddr[i][j]/4)+1,dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]); + writeLogFile(logstr); + } + else + { +#if ((!defined USE_N_OFFSET_FIX_TEMP) && (!defined EXTEND_TEMP_MODE)) + if(middle_Offset_sw[i][j]!=0) + { + dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]=0; // set 0, if read failed, when use sw offset. + sprintf(logstr,"read failed on Chain[%d] Chip[%d] middle Temp\n",i,(dev->TempChipAddr[i][j]/4)+1); + writeLogFile(logstr); + } + else + { + middle_Offset_sw[i][j] += MAX_SW_TEMP_OFFSET; + if(((int)middle_Offset[i][j] + (int)middle_Offset_sw[i][j]) > 127) + middle_Offset_sw[i][j] = 127 - middle_Offset[i][j]; + else if(((int)middle_Offset[i][j] + (int)middle_Offset_sw[i][j]) < -128) + middle_Offset_sw[i][j] = -128 - middle_Offset[i][j]; + + ret = check_reg_temp(0x98, 0x11, middle_Offset[i][j] + middle_Offset_sw[i][j], 1, dev->TempChipAddr[i][j], i); // Set offset + + sprintf(logstr,"overflow start using sw offset, old value: Chain[%d] Chip[%d] middle Temp=%d\n",i,(dev->TempChipAddr[i][j]/4)+1,dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]); + writeLogFile(logstr); + } +#else + sprintf(logstr,"read failed on Chain[%d] Chip[%d] middle Temp old value:%d\n",i,(dev->TempChipAddr[i][j]/4)+1,dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]); + writeLogFile(logstr); +#endif + } + +#ifdef SHOW_BOTTOM_TEMP + if(!doTestPatten) + { + ////////////////////////// BOTTOM TEMP ///////////////////////////////// + // 0. Switch To Bottom + set_baud_with_addr(dev->baud, 0, dev->TempChipAddr[i][j], i, 1, 0, (int) TEMP_BOTTOM); + check_asic_reg_with_addr(MISC_CONTROL,dev->TempChipAddr[i][j],i,1); + +#if ((!defined USE_N_OFFSET_FIX_TEMP) && (!defined EXTEND_TEMP_MODE)) + if(dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]<125) + { + bottom_Offset_sw[i][j]=0; + } + + // set Bottom offset + if(bottom_Offset_sw[i][j]!=0) + ret = check_reg_temp(0x98, 0x11, bottom_Offset_sw[i][j], 1, dev->TempChipAddr[i][j], i); // Set offset + else + ret = check_reg_temp(0x98, 0x11, bottom_Offset[i][j], 1, dev->TempChipAddr[i][j], i); // Set offset +#endif + ret = check_reg_temp(0x98, 0x01, 0x0, 0x0, dev->TempChipAddr[i][j], i); + + if (ret != 0) + { + dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM] = get_remote(ret & 0xff); +#if ((!defined USE_N_OFFSET_FIX_TEMP) && (!defined EXTEND_TEMP_MODE)) + if(bottom_Offset_sw[i][j]!=0) + dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]=dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]+(bottom_Offset[i][j]-bottom_Offset_sw[i][j]); +#endif + sprintf(logstr,"Chain[%d] Chip[%d] bottom Temp=%d\n",i,(dev->TempChipAddr[i][j]/4)+1,dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]); + writeLogFile(logstr); + } + else + { +#if ((!defined USE_N_OFFSET_FIX_TEMP) && (!defined EXTEND_TEMP_MODE)) + + if(bottom_Offset_sw[i][j]!=0) + { + dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]=0; // if already set sw offset, still failed, then we set temp to 0 + sprintf(logstr,"read failed on Chain[%d] Chip[%d] bottom Temp\n",i,(dev->TempChipAddr[i][j]/4)+1); + writeLogFile(logstr); + } + else + { + bottom_Offset_sw[i][j]=MAX_SW_TEMP_OFFSET; + ret = check_reg_temp(0x98, 0x11, bottom_Offset_sw[i][j], 1, dev->TempChipAddr[i][j], i); // Set offset + sprintf(logstr,"overflow start using sw offset, old value: Chain[%d] Chip[%d] bottom Temp=%d\n",i,(dev->TempChipAddr[i][j]/4)+1,dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]); + writeLogFile(logstr); + } +#else + sprintf(logstr,"read failed on Chain[%d] Chip[%d] bottom Temp old value:%d\n",i,(dev->TempChipAddr[i][j]/4)+1,dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]); + writeLogFile(logstr); +#endif + } + } +#endif + if(is218_Temp) + { + //set fake middle temp!!! + dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]=fakeMiddleTempFromPCB(dev->chain_asic_temp[i][j][TEMP_POS_LOCAL]); + + sprintf(logstr,"218 fix Chain[%d] Chip[%d] middle Temp = %d\n",i,(dev->TempChipAddr[i][j]/4)+1,dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]); + writeLogFile(logstr); + } + + // below is used to check the temp chip is OK or not! only in reboot test mode, to save ERROR CODE + if(readRebootTestNum()>0) + { + if(dev->chain_asic_temp[i][j][TEMP_POS_LOCAL] > dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]) + { + chain_asic_temp_error[i][j]++; + + if(chain_asic_temp_error[i][j]>1) // error with twice + { + sprintf(error_info,"J%d:6",i+1); + saveSearchFailedFlagInfo(error_info); + + system("reboot"); + } + } + else if(dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]>120) + { + chain_asic_temp_error[i][j]++; + + if(chain_asic_temp_error[i][j]>1) // error with twice + { + sprintf(error_info,"J%d:6",i+1); + saveSearchFailedFlagInfo(error_info); + + system("reboot"); + } + } + else + { + chain_asic_temp_error[i][j]=0; + } + } + + if(dev->chain_asic_temp[i][j][TEMP_POS_LOCAL] > maxtemp[TEMP_POS_LOCAL]) + maxtemp[TEMP_POS_LOCAL]=dev->chain_asic_temp[i][j][TEMP_POS_LOCAL]; + + if(dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE] > maxtemp[TEMP_POS_MIDDLE]) + maxtemp[TEMP_POS_MIDDLE]=dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]; + + if(dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM] > maxtemp[TEMP_POS_BOTTOM]) + maxtemp[TEMP_POS_BOTTOM]=dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]; + + if(dev->chain_asic_temp[i][j][TEMP_POS_LOCAL] < mintemp[TEMP_POS_LOCAL]) + mintemp[TEMP_POS_LOCAL]=dev->chain_asic_temp[i][j][TEMP_POS_LOCAL]; + + if(dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE] < mintemp[TEMP_POS_MIDDLE]) + mintemp[TEMP_POS_MIDDLE]=dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]; + + if(dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM] < mintemp[TEMP_POS_BOTTOM]) + mintemp[TEMP_POS_BOTTOM]=dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]; + } + + dev->chain_asic_maxtemp[i][TEMP_POS_LOCAL]=maxtemp[TEMP_POS_LOCAL]; + dev->chain_asic_maxtemp[i][TEMP_POS_MIDDLE]=maxtemp[TEMP_POS_MIDDLE]; + dev->chain_asic_maxtemp[i][TEMP_POS_BOTTOM]=maxtemp[TEMP_POS_BOTTOM]; + + dev->chain_asic_mintemp[i][TEMP_POS_LOCAL]=mintemp[TEMP_POS_LOCAL]; + dev->chain_asic_mintemp[i][TEMP_POS_MIDDLE]=mintemp[TEMP_POS_MIDDLE]; + dev->chain_asic_mintemp[i][TEMP_POS_BOTTOM]=mintemp[TEMP_POS_BOTTOM]; + + // we use the max temp value of chain, as the PWM control and temp offside check!!!! + if(check_temp_offside) + { + if (dev->chain_asic_maxtemp[i][TEMP_POS_MIDDLE] > OFFSIDE_TOP || dev->chain_asic_maxtemp[i][TEMP_POS_MIDDLE] < OFFSIDE_LOW) + { + if (already_offside == false) + { + temp_offside[i]++; + already_offside = true; + } + } + else + { + already_offside = false; + } + } + if (dev->chain_asic_maxtemp[i][TEMP_POS_LOCAL] > temp_top[TEMP_POS_LOCAL]) + temp_top[TEMP_POS_LOCAL] = dev->chain_asic_maxtemp[i][TEMP_POS_LOCAL]; + if (dev->chain_asic_maxtemp[i][TEMP_POS_MIDDLE] > temp_top[TEMP_POS_MIDDLE]) + temp_top[TEMP_POS_MIDDLE] = dev->chain_asic_maxtemp[i][TEMP_POS_MIDDLE]; + if (dev->chain_asic_maxtemp[i][TEMP_POS_BOTTOM] > temp_top[TEMP_POS_BOTTOM]) + temp_top[TEMP_POS_BOTTOM] = dev->chain_asic_maxtemp[i][TEMP_POS_BOTTOM]; + + if ((dev->chain_asic_mintemp[i][TEMP_POS_LOCAL] < temp_low[TEMP_POS_LOCAL] && dev->chain_asic_mintemp[i][TEMP_POS_LOCAL]>0 && chain_temp_toolow[i]==0) || temp_low[TEMP_POS_LOCAL] == 0) + temp_low[TEMP_POS_LOCAL] = dev->chain_asic_mintemp[i][TEMP_POS_LOCAL]; + if ((dev->chain_asic_mintemp[i][TEMP_POS_MIDDLE] < temp_low[TEMP_POS_MIDDLE] && dev->chain_asic_mintemp[i][TEMP_POS_MIDDLE]>0 && chain_temp_toolow[i]==0) || temp_low[TEMP_POS_MIDDLE] == 0) + temp_low[TEMP_POS_MIDDLE] = dev->chain_asic_mintemp[i][TEMP_POS_MIDDLE]; + if ((dev->chain_asic_mintemp[i][TEMP_POS_BOTTOM] < temp_low[TEMP_POS_BOTTOM] && dev->chain_asic_mintemp[i][TEMP_POS_BOTTOM]>0 && chain_temp_toolow[i]==0) || temp_low[TEMP_POS_BOTTOM] == 0) + temp_low[TEMP_POS_BOTTOM] = dev->chain_asic_mintemp[i][TEMP_POS_BOTTOM]; + + sprintf(logstr,"Done read temp on Chain[%d]\n",i); + writeLogFile(logstr); + } + } + dev->temp_top1[TEMP_POS_LOCAL] = temp_top[TEMP_POS_LOCAL]; + dev->temp_top1[TEMP_POS_MIDDLE] = temp_top[TEMP_POS_MIDDLE]; + dev->temp_top1[TEMP_POS_BOTTOM] = temp_top[TEMP_POS_BOTTOM]; + + dev->temp_low1[TEMP_POS_LOCAL] = temp_low[TEMP_POS_LOCAL]; + dev->temp_low1[TEMP_POS_MIDDLE] = temp_low[TEMP_POS_MIDDLE]; + dev->temp_low1[TEMP_POS_BOTTOM] = temp_low[TEMP_POS_BOTTOM]; + +#ifdef T9_18 + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + if(fpga_version>=0xE) + { + switch(i) // only 8,10,12... has temp sensor!!! we just copy temp value to other chains! + { + case 1: + case 9: + for(j=0; jchain_asic_temp_num[i]; j++) + { + dev->chain_asic_temp[i][j][TEMP_POS_LOCAL]=dev->chain_asic_temp[8][j][TEMP_POS_LOCAL]; + dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]=dev->chain_asic_temp[8][j][TEMP_POS_MIDDLE]; + dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]=dev->chain_asic_temp[8][j][TEMP_POS_BOTTOM]; + } + + dev->chain_asic_maxtemp[i][TEMP_POS_LOCAL]=dev->chain_asic_maxtemp[8][TEMP_POS_LOCAL]; + dev->chain_asic_maxtemp[i][TEMP_POS_MIDDLE]=dev->chain_asic_maxtemp[8][TEMP_POS_MIDDLE]; + dev->chain_asic_maxtemp[i][TEMP_POS_BOTTOM]=dev->chain_asic_maxtemp[8][TEMP_POS_BOTTOM]; + + dev->chain_asic_mintemp[i][TEMP_POS_LOCAL]=dev->chain_asic_mintemp[8][TEMP_POS_LOCAL]; + dev->chain_asic_mintemp[i][TEMP_POS_MIDDLE]=dev->chain_asic_mintemp[8][TEMP_POS_MIDDLE]; + dev->chain_asic_mintemp[i][TEMP_POS_BOTTOM]=dev->chain_asic_mintemp[8][TEMP_POS_BOTTOM]; + break; + case 2: + case 11: + for(j=0; jchain_asic_temp_num[i]; j++) + { + dev->chain_asic_temp[i][j][TEMP_POS_LOCAL]=dev->chain_asic_temp[10][j][TEMP_POS_LOCAL]; + dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]=dev->chain_asic_temp[10][j][TEMP_POS_MIDDLE]; + dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]=dev->chain_asic_temp[10][j][TEMP_POS_BOTTOM]; + } + + dev->chain_asic_maxtemp[i][TEMP_POS_LOCAL]=dev->chain_asic_maxtemp[10][TEMP_POS_LOCAL]; + dev->chain_asic_maxtemp[i][TEMP_POS_MIDDLE]=dev->chain_asic_maxtemp[10][TEMP_POS_MIDDLE]; + dev->chain_asic_maxtemp[i][TEMP_POS_BOTTOM]=dev->chain_asic_maxtemp[10][TEMP_POS_BOTTOM]; + + dev->chain_asic_mintemp[i][TEMP_POS_LOCAL]=dev->chain_asic_mintemp[10][TEMP_POS_LOCAL]; + dev->chain_asic_mintemp[i][TEMP_POS_MIDDLE]=dev->chain_asic_mintemp[10][TEMP_POS_MIDDLE]; + dev->chain_asic_mintemp[i][TEMP_POS_BOTTOM]=dev->chain_asic_mintemp[10][TEMP_POS_BOTTOM]; + break; + case 3: + case 13: + for(j=0; jchain_asic_temp_num[i]; j++) + { + dev->chain_asic_temp[i][j][TEMP_POS_LOCAL]=dev->chain_asic_temp[12][j][TEMP_POS_LOCAL]; + dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]=dev->chain_asic_temp[12][j][TEMP_POS_MIDDLE]; + dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]=dev->chain_asic_temp[12][j][TEMP_POS_BOTTOM]; + } + + dev->chain_asic_maxtemp[i][TEMP_POS_LOCAL]=dev->chain_asic_maxtemp[12][TEMP_POS_LOCAL]; + dev->chain_asic_maxtemp[i][TEMP_POS_MIDDLE]=dev->chain_asic_maxtemp[12][TEMP_POS_MIDDLE]; + dev->chain_asic_maxtemp[i][TEMP_POS_BOTTOM]=dev->chain_asic_maxtemp[12][TEMP_POS_BOTTOM]; + + dev->chain_asic_mintemp[i][TEMP_POS_LOCAL]=dev->chain_asic_mintemp[12][TEMP_POS_LOCAL]; + dev->chain_asic_mintemp[i][TEMP_POS_MIDDLE]=dev->chain_asic_mintemp[12][TEMP_POS_MIDDLE]; + dev->chain_asic_mintemp[i][TEMP_POS_BOTTOM]=dev->chain_asic_mintemp[12][TEMP_POS_BOTTOM]; + break; + } + } + else + { + if(i%3 != 1) // only 1,4,7... has temp sensor!!! we just copy temp value to other chains! + { + for(j=0; jchain_asic_temp_num[i]; j++) + { + dev->chain_asic_temp[i][j][TEMP_POS_LOCAL]=dev->chain_asic_temp[((i/3)*3)+1][j][TEMP_POS_LOCAL]; + dev->chain_asic_temp[i][j][TEMP_POS_MIDDLE]=dev->chain_asic_temp[((i/3)*3)+1][j][TEMP_POS_MIDDLE]; + dev->chain_asic_temp[i][j][TEMP_POS_BOTTOM]=dev->chain_asic_temp[((i/3)*3)+1][j][TEMP_POS_BOTTOM]; + } + + dev->chain_asic_maxtemp[i][TEMP_POS_LOCAL]=dev->chain_asic_maxtemp[((i/3)*3)+1][TEMP_POS_LOCAL]; + dev->chain_asic_maxtemp[i][TEMP_POS_MIDDLE]=dev->chain_asic_maxtemp[((i/3)*3)+1][TEMP_POS_MIDDLE]; + dev->chain_asic_maxtemp[i][TEMP_POS_BOTTOM]=dev->chain_asic_maxtemp[((i/3)*3)+1][TEMP_POS_BOTTOM]; + + dev->chain_asic_mintemp[i][TEMP_POS_LOCAL]=dev->chain_asic_mintemp[((i/3)*3)+1][TEMP_POS_LOCAL]; + dev->chain_asic_mintemp[i][TEMP_POS_MIDDLE]=dev->chain_asic_mintemp[((i/3)*3)+1][TEMP_POS_MIDDLE]; + dev->chain_asic_mintemp[i][TEMP_POS_BOTTOM]=dev->chain_asic_mintemp[((i/3)*3)+1][TEMP_POS_BOTTOM]; + } + } + } + } +#endif + // only change fan speed after read temp value!!! + check_fan(); + + set_PWM_according_to_temperature(); + + if(startCheckNetworkJob) + { + cgtime(&tv_send); + timersub(&tv_send, &tv_send_job, &diff); + cur_fan_num=dev->fan_num; + + if(diff.tv_sec > 120) // we need print network error to log here, below the process will not print this error msg to log!!! + { + sprintf(logstr,"Fatal Error: network connection lost!\n"); + writeInitLogFile(logstr); + } + } + else + { + diff.tv_sec=0; // ignore network job error when in test patten mode + cur_fan_num=MIN_FAN_NUM; + } + +#ifdef DEBUG_NOT_CHECK_FAN_NUM + if(cur_fan_num < MIN_FAN_NUM) + { + sprintf(logstr,"DEBUG Fatal Error: FAN lost! fan num=%d\n",cur_fan_num); + writeInitLogFile(logstr); + + // we keep running... + cur_fan_num=MIN_FAN_NUM; + } +#endif + +#ifndef DISABLE_TEMP_PROTECT + if(diff.tv_sec > 120 || dev->temp_top1[TEMP_POS_LOCAL] > MAX_PCB_TEMP // we use pcb temp to check protect or not + || cur_fan_num < MIN_FAN_NUM /*|| dev->fan_speed_top1 < (MAX_FAN_SPEED * dev->fan_pwm / 150) */ ) + { + fatal_error_counter++; + + if(fatal_error_counter>=3) + { + global_stop = true; // still counter the chip's x times + + if(dev->temp_top1[TEMP_POS_LOCAL] > MAX_PCB_TEMP) + FatalErrorValue=ERROR_OVER_MAXTEMP; + else if(cur_fan_num < MIN_FAN_NUM) + FatalErrorValue=ERROR_FAN_LOST; + else if(dev->fan_speed_top1 < (MAX_FAN_SPEED * cur_fan_num / 150)) + FatalErrorValue=ERROR_FAN_SPEED; + else + FatalErrorValue=ERROR_UNKOWN_STATUS; + + if(dev->temp_top1[TEMP_POS_LOCAL] > MAX_PCB_TEMP + || cur_fan_num < MIN_FAN_NUM /* || dev->fan_speed_top1 < (MAX_FAN_SPEED * dev->fan_pwm / 150) */) + { + status_error = true; // will stop counter the chip's x times + once_error = true; + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + pthread_mutex_lock(&iic_mutex); + disable_pic_dac(i); + pthread_mutex_unlock(&iic_mutex); + } + } + } + + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & ~RUN_BIT); + } + else + { + global_stop = false; + if (!once_error) + status_error = false; + } + } + else + { + fatal_error_counter=0; + + global_stop = false; + if (!once_error) + status_error = false; + } + +#endif + + // set_led(global_stop); + + if(status_error) + { + char error_info[256]; + + switch(FatalErrorValue) + { + case ERROR_OVER_MAXTEMP: + sprintf(logstr,"Fatal Error: Temperature is too high!\n"); + + if(readRebootTestNum()>0) + { + sprintf(error_info,"P:1"); + saveSearchFailedFlagInfo(error_info); + + system("reboot"); + } + break; + case ERROR_FAN_LOST: + sprintf(logstr,"Fatal Error: Fan lost!\n"); + + if(readRebootTestNum()>0) + { + sprintf(error_info,"F:1"); + saveSearchFailedFlagInfo(error_info); + + system("reboot"); + } + break; + case ERROR_FAN_SPEED: + sprintf(logstr,"Fatal Error: Fan speed too low!\n"); + break; + case ERROR_UNKOWN_STATUS: + sprintf(logstr,"Fatal Error: network connection lost!\n"); + break; + default: + sprintf(logstr,"Fatal Error: unkown status.\n"); + break; + } + writeInitLogFile(logstr); + } + + processTEST(); + + sprintf(logstr,"FAN PWM: %d\n",dev->fan_pwm); + writeLogFile(logstr); + + pthread_mutex_unlock(&opencore_readtemp_mutex); + + sprintf(logstr,"read_temp_func Done!\n"); + writeLogFile(logstr); + + sprintf(logstr,"CRC error counter=%d\n",get_crc_count()); + writeLogFile(logstr); + + updateLogFile(); + + if(doTestPatten) + sleep(3); + else sleep(1); + } + } + + void chain_inactive(unsigned char chain) + { + unsigned char buf[5] = {0,0,0,0,5}; + unsigned int cmd_buf[3] = {0,0,0}; + unsigned int ret, value; + + if(!opt_multi_version) // fil mode + { + buf[0] = CHAIN_INACTIVE | COMMAND_FOR_ALL; + buf[1] = 0; + buf[2] = 0; + buf[3] = CRC5(buf, 4*8 - 5); + applog(LOG_DEBUG,"%s: buf[0]=0x%x, buf[1]=0x%x, buf[2]=0x%x, buf[3]=0x%x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + set_BC_command_buffer(cmd_buf); + + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (chain << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + else // vil mode + { + buf[0] = VIL_COMMAND_TYPE | VIL_ALL | CHAIN_INACTIVE; + buf[1] = 0x05; + buf[2] = 0; + buf[3] = 0; + buf[4] = CRC5(buf, 4*8); + applog(LOG_DEBUG,"%s: buf[0]=0x%x, buf[1]=0x%x, buf[2]=0x%x, buf[3]=0x%x, buf[4]=0x%x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3], buf[4]); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + cmd_buf[1] = buf[4]<<24; + while (1) + { + ret = get_BC_write_command(); + if ((ret & 0x80000000) == 0) + break; + cgsleep_ms(1); + } + set_BC_command_buffer(cmd_buf); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (chain << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + } + + void set_address(unsigned char chain, unsigned char mode, unsigned char address) + { + unsigned char buf[9] = {0}; + unsigned int cmd_buf[3] = {0,0,0}; + unsigned int ret, value; + + if(!opt_multi_version) // fil mode + { + buf[0] = SET_ADDRESS; + buf[1] = address; + buf[2] = 0; + if (mode) //all + buf[0] |= COMMAND_FOR_ALL; + buf[3] = CRC5(buf, 4*8 - 5); + applog(LOG_DEBUG,"%s: buf[0]=0x%x, buf[1]=0x%x, buf[2]=0x%x, buf[3]=0x%x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + set_BC_command_buffer(cmd_buf); + + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (chain << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + else // vil mode + { + buf[0] = VIL_COMMAND_TYPE | SET_ADDRESS; + buf[1] = 0x05; + buf[2] = address; + buf[3] = 0; + buf[4] = CRC5(buf, 4*8); + //applog(LOG_DEBUG,"%s: buf[0]=0x%x, buf[1]=0x%x, buf[2]=0x%x, buf[3]=0x%x, buf[4]=0x%x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3], buf[4]); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + cmd_buf[1] = buf[4]<<24; + while (1) + { + ret = get_BC_write_command(); + if ((ret & 0x80000000) == 0) + break; + cgsleep_ms(1); + } + set_BC_command_buffer(cmd_buf); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (chain << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + } + + int calculate_asic_number(unsigned int actual_asic_number) + { + int i = 0; + if(actual_asic_number == 1) + { + i = 1; + } + else if(actual_asic_number == 2) + { + i = 2; + } + else if((actual_asic_number > 2) && (actual_asic_number <= 4)) + { + i = 4; + } + else if((actual_asic_number > 4) && (actual_asic_number <= 8)) + { + i = 8; + } + else if((actual_asic_number > 8) && (actual_asic_number <= 16)) + { + i = 16; + } + else if((actual_asic_number > 16) && (actual_asic_number <= 32)) + { + i = 32; + } + else if((actual_asic_number > 32) && (actual_asic_number <= 64)) + { + i = 64; + } + else if((actual_asic_number > 64) && (actual_asic_number <= 128)) + { + i = 128; + } + else + { + applog(LOG_DEBUG,"actual_asic_number = %d, but it is error\n", actual_asic_number); + return -1; + } + return i; + } + + int calculate_core_number(unsigned int actual_core_number) + { + int i = 0; + if(actual_core_number == 1) + { + i = 1; + } + else if(actual_core_number == 2) + { + i = 2; + } + else if((actual_core_number > 2) && (actual_core_number <= 4)) + { + i = 4; + } + else if((actual_core_number > 4) && (actual_core_number <= 8)) + { + i = 8; + } + else if((actual_core_number > 8) && (actual_core_number <= 16)) + { + i = 16; + } + else if((actual_core_number > 16) && (actual_core_number <= 32)) + { + i = 32; + } + else if((actual_core_number > 32) && (actual_core_number <= 64)) + { + i = 64; + } + else if((actual_core_number > 64) && (actual_core_number <= 128)) + { + i = 128; + } + else + { + applog(LOG_DEBUG,"actual_core_number = %d, but it is error\n", actual_core_number); + return -1; + } + return i; + } + + void software_set_address_onChain(int chainIndex) + { + unsigned int i=chainIndex, j; + unsigned char chip_addr = 0; + unsigned char check_bit = 0; + + dev->check_bit=0; + + applog(LOG_DEBUG,"--- %s\n", __FUNCTION__); + + dev->addrInterval = CHIP_ADDR_INTERVAL; // fix chip addr interval + check_bit = dev->addrInterval - 1; + while(check_bit) + { + check_bit = check_bit >> 1; + dev->check_bit++; + } + + //for(i=0; ichain_exist[i] == 1) + { + chip_addr = 0; + chain_inactive(i); + cgsleep_ms(30); + chain_inactive(i); + cgsleep_ms(30); + chain_inactive(i); + cgsleep_ms(30); + + for(j = 0; j < 0x100/dev->addrInterval; j++) + { + set_address(i, 0, chip_addr); + chip_addr += dev->addrInterval; + cgsleep_ms(30); + } + } + } + } + + void software_set_address() + { + unsigned int i, j; + unsigned char chip_addr = 0; + unsigned char check_bit = 0; + + dev->check_bit=0; + + applog(LOG_DEBUG,"--- %s\n", __FUNCTION__); + + dev->addrInterval = CHIP_ADDR_INTERVAL; + check_bit = dev->addrInterval - 1; + while(check_bit) + { + check_bit = check_bit >> 1; + dev->check_bit++; + } + + for(i=0; ichain_exist[i] == 1 && dev->chain_asic_num[i] > 0) + { + chip_addr = 0; + chain_inactive(i); + cgsleep_ms(30); + chain_inactive(i); + cgsleep_ms(30); + chain_inactive(i); + cgsleep_ms(30); + + for(j = 0; j < 0x100/dev->addrInterval; j++) + { + set_address(i, 0, chip_addr); + chip_addr += dev->addrInterval; + cgsleep_ms(30); + } + } + } + } + + void set_asic_ticket_mask(unsigned int ticket_mask) + { + unsigned char buf[9] = {0}; + unsigned int cmd_buf[3] = {0,0,0}; + unsigned int ret, value,i; + unsigned int tm; + + tm = Swap32(ticket_mask); + + for(i=0; ichain_exist[i] == 1) + { + //first step: send new bauddiv to ASIC, but FPGA doesn't change its bauddiv, it uses old bauddiv to send BC command to ASIC + if(!opt_multi_version) // fil mode + { + buf[0] = SET_BAUD_OPS; + buf[1] = 0x10; + buf[2] = ticket_mask & 0x1f; + buf[0] |= COMMAND_FOR_ALL; + buf[3] = CRC5(buf, 4*8 - 5); + applog(LOG_DEBUG,"%s: buf[0]=0x%x, buf[1]=0x%x, buf[2]=0x%x, buf[3]=0x%x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + set_BC_command_buffer(cmd_buf); + + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + else // vil mode + { + buf[0] = VIL_COMMAND_TYPE | VIL_ALL | SET_CONFIG; + buf[1] = 0x09; + buf[2] = 0; + buf[3] = TICKET_MASK; + buf[4] = tm & 0xff; + buf[5] = (tm >> 8) & 0xff; + buf[6] = (tm >> 16) & 0xff; + buf[7] = (tm >> 24) & 0xff; + buf[8] = CRC5(buf, 8*8); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + cmd_buf[1] = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7]; + cmd_buf[2] = buf[8]<<24; + + set_BC_command_buffer(cmd_buf); + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID| (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + } + } + } + + void set_hcnt(unsigned int hcnt) + { + unsigned char buf[9] = {0}; + unsigned int cmd_buf[3] = {0,0,0}; + unsigned int ret, value,i; + + for(i=0; ichain_exist[i] == 1) + { + if(!opt_multi_version) // fil mode + { + ; + } + else // vil mode + { + /* 20160510 + buf[0] = VIL_COMMAND_TYPE | VIL_ALL | SET_CONFIG; + buf[1] = 0x09; + buf[2] = 0; + buf[3] = MISC_CONTROL; + buf[4] = 0x40; + buf[5] = INV_CLKO | cgpu.temp_sel; + buf[6] = (bauddiv & 0x1f) | (cgpu.rfs << 6); + buf[7] = cgpu.tfs << 5; + buf[8] = CRC5(buf, 8*8); + */ + + buf[0] = VIL_COMMAND_TYPE | VIL_ALL | SET_CONFIG; + buf[1] = 0x09; + buf[2] = 0; + buf[3] = HASH_COUNTING_NUMBER; + buf[4] = hcnt>>24; + buf[5] = hcnt>>16; + buf[6] = hcnt>>8; + buf[7] = hcnt; + buf[8] = CRC5(buf, 8*8); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + cmd_buf[1] = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7]; + cmd_buf[2] = buf[8]<<24; + + set_BC_command_buffer(cmd_buf); + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID| (i << 16) | (ret & 0xFFF0FFFF); + set_BC_write_command(value); + } + } + } + } + + +#if 1 + void set_baud(unsigned char bauddiv,int no_use) + { + unsigned char buf[9] = {0}; + unsigned int cmd_buf[3] = {0,0,0}; + unsigned int ret, value,i; + + if(dev->baud == bauddiv) + { + applog(LOG_DEBUG,"%s: the setting bauddiv(%d) is the same as before\n", __FUNCTION__, bauddiv); + return; + } + + for(i=0; ichain_exist[i] == 1) + { + //first step: send new bauddiv to ASIC, but FPGA doesn't change its bauddiv, it uses old bauddiv to send BC command to ASIC + if(!opt_multi_version) // fil mode + { + buf[0] = SET_BAUD_OPS; + buf[1] = 0x10; + buf[2] = bauddiv & 0x1f; + buf[0] |= COMMAND_FOR_ALL; + buf[3] = CRC5(buf, 4*8 - 5); + applog(LOG_DEBUG,"%s: buf[0]=0x%x, buf[1]=0x%x, buf[2]=0x%x, buf[3]=0x%x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + set_BC_command_buffer(cmd_buf); + + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + else // vil mode + { + buf[0] = VIL_COMMAND_TYPE | VIL_ALL | SET_CONFIG; + buf[1] = 0x09; + buf[2] = 0; + buf[3] = MISC_CONTROL; + buf[4] = 0; + buf[5] = INV_CLKO; + buf[6] = bauddiv & 0x1f; + buf[7] = 0; + buf[8] = CRC5(buf, 8*8); + + cmd_buf[0] = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; + cmd_buf[1] = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7]; + cmd_buf[2] = buf[8]<<24; + applog(LOG_DEBUG,"%s: cmd_buf[0]=0x%x, cmd_buf[1]=0x%x, cmd_buf[2]=0x%x\n", __FUNCTION__, cmd_buf[0], cmd_buf[1], cmd_buf[2]); + + set_BC_command_buffer(cmd_buf); + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID| (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + } + } + } + + // second step: change FPGA's bauddiv + cgsleep_us(50000); + ret = get_BC_write_command(); + value = (ret & 0xffffffe0) | (bauddiv & 0x1f); + set_BC_write_command(value); + dev->baud = bauddiv; + } +#endif + + void init_uart_baud() + { + unsigned int rBaudrate = 0, baud = 0; + unsigned char bauddiv = 0; + int i =0; + char logstr[1024]; + + rBaudrate = 1000000 * 5/3 / dev->timeout * (64*8); //64*8 need send bit, ratio=2/3 + baud = 25000000/rBaudrate/8 - 1; + + if(baud > MAX_BAUD_DIVIDER) + { + bauddiv = MAX_BAUD_DIVIDER; + } + else + { + bauddiv = baud; + } + +#ifdef FIX_BAUD_VALUE + baud = FIX_BAUD_VALUE; +#endif + + sprintf(logstr,"set baud=%d\n",bauddiv); + writeInitLogFile(logstr); + + set_baud(bauddiv,1); + } + +#ifdef DEBUG_PRINT_T9_PLUS_PIC_HEART_INFO + void set_red_led(bool flag) + { + char cmd[100]; + if(isC5_CtrlBoard) + { + if(flag) + { + sprintf(cmd,"echo %d > %s", 1,RED_LED_DEV_C5); + system(cmd); + } + else + { + sprintf(cmd,"echo %d > %s", 0,RED_LED_DEV_C5); + system(cmd); + } + } + else + { + if(flag) + { + sprintf(cmd,"echo %d > %s", 1,RED_LED_DEV_XILINX); + system(cmd); + } + else + { + sprintf(cmd,"echo %d > %s", 0,RED_LED_DEV_XILINX); + system(cmd); + } + } + } +#endif + + void set_led(bool stop) + { + static bool blink = true; + char cmd[100]; + blink = !blink; + +#ifdef DEBUG_PRINT_T9_PLUS_PIC_HEART_INFO + return; // disable LED, we use it to debug +#endif + + if(isC5_CtrlBoard) + { + if(stop) + { + sprintf(cmd,"echo %d > %s", 0,GREEN_LED_DEV_C5); + system(cmd); + sprintf(cmd,"echo %d > %s", (blink)?1:0,RED_LED_DEV_C5); + system(cmd); + } + else + { + sprintf(cmd,"echo %d > %s", 0,RED_LED_DEV_C5); + system(cmd); + sprintf(cmd,"echo %d > %s", (blink)?1:0,GREEN_LED_DEV_C5); + system(cmd); + } + } + else + { + if(stop) + { + sprintf(cmd,"echo %d > %s", 0,GREEN_LED_DEV_XILINX); + system(cmd); + sprintf(cmd,"echo %d > %s", (blink)?1:0,RED_LED_DEV_XILINX); + system(cmd); + } + else + { + sprintf(cmd,"echo %d > %s", 0,RED_LED_DEV_XILINX); + system(cmd); + sprintf(cmd,"echo %d > %s", (blink)?1:0,GREEN_LED_DEV_XILINX); + system(cmd); + } + } + } + + void * pic_heart_beat_func() + { + int i; + while(1) + { + for(i=0; ichain_exist[i]) + { + pthread_mutex_lock(&iic_mutex); + pic_heart_beat_each_chain(i); + pthread_mutex_unlock(&iic_mutex); + cgsleep_ms(10); + } + } + sleep(HEART_BEAT_TIME_GAP); + } + return 0; + } + + void change_pic_voltage_old() + { + int i; + sleep(300); + for(i=0; ichain_exist[i]) + { + while(1) + { + if(tmp_vol > chain_voltage_pic[i]) + break; + tmp_vol += 5; + if(tmp_vol > chain_voltage_pic[i]) + tmp_vol = chain_voltage_pic[i]; + pthread_mutex_lock(&iic_mutex); + set_pic_voltage(i,tmp_vol); + pthread_mutex_unlock(&iic_mutex); + pthread_mutex_lock(&iic_mutex); + get_pic_voltage(i); + pthread_mutex_unlock(&iic_mutex); + if(tmp_vol == chain_voltage_pic[i]) + break; + cgsleep_ms(100); + } + } + } + } + + int get_asic_nonce_num(int chain, int asic, int timeslice) + { + int i = timeslice; + int index = 0; + int nonce = 0; + for (i = 1; i <= timeslice; i++) + { + if(nonce_times%TIMESLICE - i >= 0) + index = nonce_times%TIMESLICE - i; + else + index = nonce_times%TIMESLICE - i + TIMESLICE; + nonce += nonce_num[chain][asic][index]; + } + return nonce; + } + + void get_lastn_nonce_num(char * dest,int n) + { + int i = 0; + int j = 0; + + for(i=0; ichain_exist[i]) + { + char xtime[2048] = "{"; + char tmp[20] = ""; + sprintf(tmp,"Chain%d:{",i+1); + strcat(xtime,tmp); + sprintf(tmp,"N%d=%d",0,get_asic_nonce_num(i,0,n)); + strcat(xtime,tmp); + for (j = 1; j < dev->max_asic_num_in_one_chain; j++) + { + + sprintf(tmp,",N%d=%d",j,get_asic_nonce_num(i,j,n)); + strcat(xtime,tmp); + } + strcat(xtime,"},"); + strcat(dest,xtime); + } + } + dest[(strlen(dest)-1) >= 0 ? (strlen(dest)-1) : 0]='\0'; +// printf("%s\n",dest); + } + + bool if_hashrate_ok() + { + double avg_rate = total_mhashes_done / 1000 / total_secs; + if( avg_rate > ((double)GetTotalRate()) * 0.98) + { + return true; + } + else + { + return false; + } + } + + bool check_hashrate_maybe_ok(double level) + { + double avg_rate = total_mhashes_done / 1000 / total_secs; + if( avg_rate > ((double)GetTotalRate()) * level) + { + return true; + } + else + { + return false; + } + } + + void saveRebootTestNum(int num) + { + FILE *fd; + char testnumStr[32]; + fd=fopen("/etc/config/rebootTest","wb"); + if(fd) + { + memset(testnumStr,'\0',sizeof(testnumStr)); + sprintf(testnumStr,"%d",num); + fwrite(testnumStr,1,sizeof(testnumStr),fd); + fclose(fd); + } + system("sync"); + } + + int readRebootTestNum() + { +#ifdef DISABLE_FINAL_TEST + return 0; // fixed to 0, means miner fw is not in test mode!!! (if in test mode, will stop mining when get some error) +#else + FILE *fd; + char testnumStr[32]; + fd=fopen("/etc/config/rebootTest","rb"); + if(fd) + { + memset(testnumStr,'\0',sizeof(testnumStr)); + fread(testnumStr,1,sizeof(testnumStr),fd); + fclose(fd); + + return atoi(testnumStr); + } + return 0; +#endif + } + + void saveRestartNum(int num) + { + FILE *fd; + char testnumStr[32]; + fd=fopen("/etc/config/restartTest","wb"); + if(fd) + { + memset(testnumStr,'\0',sizeof(testnumStr)); + sprintf(testnumStr,"%d",num); + fwrite(testnumStr,1,sizeof(testnumStr),fd); + fclose(fd); + } + system("sync"); + } + + int readRestartNum() + { +#ifdef DISABLE_FINAL_TEST + return 2; // fixed to 2, means miner fw is in user mode, normal working mode... +#else + FILE *fd; + char testnumStr[32]; + fd=fopen("/etc/config/restartTest","rb"); + if(fd) + { + memset(testnumStr,'\0',sizeof(testnumStr)); + fread(testnumStr,1,sizeof(testnumStr),fd); + fclose(fd); + + return atoi(testnumStr); + } + return 0; +#endif + } + +#ifdef ENABLE_REINIT_WHEN_TESTFAILED + void saveRetryFlag(int retry_flag) + { + FILE *fd; + char testnumStr[32]; + fd=fopen("/etc/config/retryFlag","wb"); + if(fd) + { + memset(testnumStr,'\0',sizeof(testnumStr)); + sprintf(testnumStr,"%d",retry_flag); + fwrite(testnumStr,1,sizeof(testnumStr),fd); + fclose(fd); + } + system("sync"); + } + + int readRetryFlag() + { + FILE *fd; + char testnumStr[32]; + fd=fopen("/etc/config/retryFlag","rb"); + if(fd) + { + memset(testnumStr,'\0',sizeof(testnumStr)); + fread(testnumStr,1,sizeof(testnumStr),fd); + fclose(fd); + + return atoi(testnumStr); + } + return 0; + } +#endif + + void * check_system_work() + { + struct timeval tv_start, tv_end,tv_reboot,tv_reboot_start; + int i = 0, j = 0; + cgtime(&tv_end); + cgtime(&tv_reboot); + copy_time(&tv_start, &tv_end); + copy_time(&tv_reboot_start, &tv_reboot); + + int asic_num = 0, error_asic = 0, avg_num = 0; + int run_counter=0; + int rebootTestNum=readRebootTestNum(); + double rt_board_rate; + double ideal_board_rate; + char logstr[1024]; + int restartNum=readRestartNum(); + +#ifdef DEBUG_REBOOT + static int print_once=1; + + sprintf(logstr,"DEBUG_REBOOT mode: will check hashrate >= 98% after 3000 seconds, then reboot if hashrate OK or stop hashrate low...\n"); + writeInitLogFile(logstr); +#endif + + if(restartNum>0) + { + sprintf(logstr,"restartNum = %d , auto-reinit enabled...\n",restartNum); + writeInitLogFile(logstr); + } + + while(1) + { + struct timeval diff; +#ifdef DEBUG_REINIT + static int debug_counter=0; +#endif + +#ifndef DEBUG_XILINX_NONCE_NOTENOUGH + // must set led in 1 seconds, must be faster, in read temp func ,will be too slow + set_led(global_stop); +#endif + + if(doTestPatten) + { + cgsleep_ms(100); + continue; + } + +#ifdef ENABLE_REINIT_MINING + reinit_counter++; +#endif + +#ifdef DEBUG_REINIT + debug_counter++; + if(debug_counter>120) + { + debug_counter=0; + + sprintf(logstr,"Debug to Re-init %d...\n",debug_counter); + writeInitLogFile(logstr); + + bitmain_core_reInit(); + + sprintf(logstr,"Re-init Done : %d\n",debug_counter); + writeInitLogFile(logstr); + + reinit_counter=0;// wait for 10 min again for next retry init check + } +#endif + cgtime(&tv_end); + cgtime(&tv_reboot); + timersub(&tv_end, &tv_start, &diff); + +#ifdef ENABLE_REINIT_MINING + if(restartNum>0 && (!global_stop) && reinit_counter>600) // normal mining status, we can check hashrate + { +#if 0 + if(reinit_counter>660) // 10min + 60s + { + reinit_counter=600; // check after 60s next time + + // check RT value with ideal value, + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + rt_board_rate=atof(displayed_rate[i]); + ideal_board_rate=GetBoardRate(i); + + if(rt_board_rate*100/ideal_board_rate < CHECK_RT_IDEAL_RATE_PERCENT) + sprintf(logstr,"Chain[%d] RT=%f ideal=%f need re-init\n",i,rt_board_rate,ideal_board_rate); + else sprintf(logstr,"Chain[%d] RT=%f ideal=%f OK\n",i,rt_board_rate,ideal_board_rate); + writeInitLogFile(logstr); + } + } + } +#endif + + if(reinit_counter>600) + { + reinit_counter=666; + + // check RT value with ideal value, + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + rt_board_rate=atof(displayed_rate[i]); + ideal_board_rate=GetBoardRate(i); + + if(rt_board_rate*100/ideal_board_rate < CHECK_RT_IDEAL_RATE_PERCENT) + { + sprintf(logstr,"Chain[%d] RT=%f ideal=%f need re-init\n",i,rt_board_rate,ideal_board_rate); + writeInitLogFile(logstr); + + bitmain_core_reInit(); + + sprintf(logstr,"Re-init Done\n"); + writeInitLogFile(logstr); + + reinit_counter=0; // will wait for 10mins to start check to reinit again + break; + } + } + } + } + } +#endif + +#ifdef DEBUG_REBOOT + if(total_secs > 3000 && print_once>0) + { + if(if_hashrate_ok()) + { + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + disable_pic_dac(i); + } + } + + set_PWM(1); + system("reboot"); + } + else + { + double avg_rate = total_mhashes_done / 1000 / total_secs; + if(print_once>0) + { + print_once--; + + sprintf(logstr,"Failed: avg hashrate=%f is low! will not reboot!!!\n",avg_rate); + writeInitLogFile(logstr); + } + } + } +#endif + +#ifdef REBOOT_TEST_ONCE_1HOUR + if(total_secs > 3000 && rebootTestNum>=1 && rebootTestNum<=3) // not larger than 1 hour, avoid someone treat it as good miner +#else + if(total_secs > 1800 && rebootTestNum>=1 && rebootTestNum<=3) +#endif + { +#ifdef DEBUG_KEEP_REBOOT_EVERY_ONE_HOUR + // we do not set rebootTestNum = 0, so we can debug and reboot every one hour! + system("sync"); + system("reboot"); +#else + //TODO... + if(if_hashrate_ok()) + { +#ifdef REBOOT_TEST_ONCE_1HOUR + saveRebootTestNum(0); + saveRestartNum(2); +#else + saveRebootTestNum((rebootTestNum-1)); + + // reboot test over, will enable re-init by set restart num = 2 + if((rebootTestNum-1)==0) + saveRestartNum(2); +#endif + +#if ((defined ENABLE_FINAL_TEST_WITHOUT_REBOOT) && (defined REBOOT_TEST_ONCE_1HOUR)) + rebootTestNum=0; + restartNum=2; +#else + system("reboot"); +#endif + } + else + { + char error_info[256]; + // keep the log , we can check it + system("cp /tmp/search /etc/config/lastlog -f"); + + saveRebootTestNum(3333); // 3333 is magic number inform that this miner failed on test ! + rebootTestNum=3333; + + sprintf(error_info,"R:1"); + saveSearchFailedFlagInfo(error_info); + + system("reboot"); + } +#endif + } + + if (diff.tv_sec > 300) + check_temp_offside = true; + + if (diff.tv_sec > 60 || (global_stop == true && diff.tv_sec > 30)) + { + run_counter++; // for check asic o or x + +#ifdef ENABLE_REINIT_MINING + if(restartNum>0 && (!global_stop) && reinit_counter>600) + { + for(i=0; ichain_exist[i]) + { + for(j=0; jchain_asic_num[i]; j++) + { + if(dev->chain_asic_nonce[i][j]>0) + break; + } + + if(j>=dev->chain_asic_num[i] && dev->chain_asic_num[i]>0) + { + // all chips get 0 nonce + sprintf(logstr,"Chain[%d] get 0 nonce in 1 min\n",i); + writeInitLogFile(logstr); + + bitmain_core_reInit(); + + sprintf(logstr,"Re-init Done\n"); + writeInitLogFile(logstr); + + reinit_counter=0; // will wait for 10mins to start check to reinit again + break; + } + } + } + } +#endif + + asic_num = 0, error_asic = 0, avg_num = 0; + for(i=0; ichain_exist[i]) + { + asic_num += dev->chain_asic_num[i]; + for(j=0; jchain_asic_num[i]; j++) + { + nonce_num[i][j][nonce_times % TIMESLICE] = dev->chain_asic_nonce[i][j]; + avg_num += dev->chain_asic_nonce[i][j]; + applog(LOG_DEBUG,"%s: chain %d asic %d asic_nonce_num %d", __FUNCTION__, i,j,dev->chain_asic_nonce[i][j]); + } + } + } + nonce_times ++; + memset(nonce_num10_string,0,NONCE_BUFF); + memset(nonce_num30_string,0,NONCE_BUFF); + memset(nonce_num60_string,0,NONCE_BUFF); + get_lastn_nonce_num(nonce_num10_string,10); + get_lastn_nonce_num(nonce_num30_string,30); + get_lastn_nonce_num(nonce_num60_string,60); + + if (asic_num != 0) + { + applog(LOG_DEBUG,"%s: avg_num %d asic_num %d", __FUNCTION__, avg_num,asic_num); + avg_num = avg_num / asic_num / 8; + avg_num = 10; + } + else + { + avg_num = 1; + } + + for(i=0; ichain_exist[i]) + { + int offset = 0; + + for(j=0; jchain_asic_num[i]; j++) + { + if(j%8 == 0) + { + dev->chain_asic_status_string[i][j+offset] = ' '; + offset++; + } +#ifdef DISABLE_SHOWX_ENABLE_XTIMES + if(get_asic_nonce_num(i, j, 1) > 1) // 1 mins check nonce counter + { + dev->chain_asic_status_string[i][j+offset] = 'o'; + } + else + { + dev->chain_asic_status_string[i][j+offset] = 'o'; // still show o, not x + + if(!status_error) + x_time[i][j]++; + } +#else + if(get_asic_nonce_num(i, j, 1) > 1) // 1 mins check nonce counter + { + dev->chain_asic_status_string[i][j+offset] = 'o'; + } + else + { + dev->chain_asic_status_string[i][j+offset] = 'x'; // still show o, not x + + if(!status_error) + x_time[i][j]++; + } +#endif + dev->chain_asic_nonce[i][j] = 0; + } + dev->chain_asic_status_string[i][j+offset] = '\0'; + } + } + + if(run_counter>60) + run_counter=0; + + copy_time(&tv_start, &tv_end); + } + + cgsleep_ms(1000); + } + } + +#ifdef DEBUG_OPENCORE_TWICE + static int debug_once=1; // clement for debug +#endif + void open_core(bool nullwork_enable) + { + unsigned int i = 0, j = 0, k, m, work_id = 0, ret = 0, value = 0, work_fifo_ready = 0, loop=0; + unsigned char gateblk[4] = {0,0,0,0}; + unsigned int cmd_buf[3] = {0,0,0}, buf[TW_WRITE_COMMAND_LEN/sizeof(unsigned int)]= {0}; + unsigned int buf_vil_tw[TW_WRITE_COMMAND_LEN_VIL/sizeof(unsigned int)]= {0}; + unsigned char data[TW_WRITE_COMMAND_LEN] = {0xff}; + unsigned char buf_vil[9] = {0,0,0,0,0,0,0,0,0}; + struct vil_work work_vil; + struct vil_work_1387 work_vil_1387; + char logstr[1024]; + int wati_count=0; + +#ifdef DEBUG_OPENCORE_TWICE + loop = BM1387_CORE_NUM-debug_once; + debug_once=0; +#else + loop = BM1387_CORE_NUM; +#endif + if(!opt_multi_version) // fil mode + { + set_dhash_acc_control(get_dhash_acc_control() & (~OPERATION_MODE)); + set_hash_counting_number(0); + gateblk[0] = SET_BAUD_OPS; + gateblk[1] = 0;//0x10; //16-23 + gateblk[2] = dev->baud | 0x80; //8-15 gateblk=1 + gateblk[0] |= 0x80; + //gateblk[3] = CRC5(gateblk, 4*8 - 5); + gateblk[3] = 0x80; // MMEN=1 + gateblk[3] = 0x80 | (0x1f & CRC5(gateblk, 4*8 - 5)); + applog(LOG_DEBUG,"%s: gateblk[0]=0x%x, gateblk[1]=0x%x, gateblk[2]=0x%x, gateblk[3]=0x%x\n", __FUNCTION__, gateblk[0], gateblk[1], gateblk[2], gateblk[3]); + cmd_buf[0] = gateblk[0]<<24 | gateblk[1]<<16 | gateblk[2]<<8 | gateblk[3]; + + memset(data, 0x00, TW_WRITE_COMMAND_LEN); + data[TW_WRITE_COMMAND_LEN - 1] = 0xff; + data[TW_WRITE_COMMAND_LEN - 12] = 0xff; + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + set_BC_command_buffer(cmd_buf); + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + cgsleep_us(10000); + + for(m=0; mbaud & 0x1f) | GATEBCLK; // enable gateblk + buf_vil[7] = MMEN; // MMEN=1 + + buf_vil[8] = CRC5(buf_vil, 8*8); + + cmd_buf[0] = buf_vil[0]<<24 | buf_vil[1]<<16 | buf_vil[2]<<8 | buf_vil[3]; + cmd_buf[1] = buf_vil[4]<<24 | buf_vil[5]<<16 | buf_vil[6]<<8 | buf_vil[7]; + cmd_buf[2] = buf_vil[8]<<24; + + // prepare special work for openning core + memset(buf_vil_tw, 0x00, TW_WRITE_COMMAND_LEN_VIL/sizeof(unsigned int)); + memset(&work_vil_1387, 0xff, sizeof(struct vil_work_1387)); + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + ret = get_BC_write_command(); //disable null work + ret = BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + ret &= ~BC_COMMAND_EN_NULL_WORK; + set_BC_write_command(ret); + cgsleep_us(1000); + + work_vil_1387.work_type = NORMAL_BLOCK_MARKER; + work_vil_1387.chain_id = 0x80 | i; + work_vil_1387.reserved1[0]= 0; + work_vil_1387.reserved1[1]= 0; + work_vil_1387.work_count = 0; + work_vil_1387.data[0] = 0xff; + work_vil_1387.data[11] = 0xff; + set_BC_command_buffer(cmd_buf); + + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + //ret &= ~BC_COMMAND_EN_NULL_WORK; + set_BC_write_command(value); + cgsleep_us(10000); + + for(m=0; m3000) + { + sprintf(logstr,"Error: send open core work Failed on Chain[%d]!\n",i); + writeInitLogFile(logstr); + + break; + } + } + } + while(1); + + if(wati_count>3000) // failed on send open core work + break; + + if(m==0) //new block + { + work_vil_1387.work_type = NEW_BLOCK_MARKER; + } + else + { + work_vil_1387.work_type = NORMAL_BLOCK_MARKER; + } + + work_vil_1387.chain_id = i | 0x80; //set chain id and enable it + + + buf_vil_tw[0] = (work_vil_1387.work_type<< 24) | (work_vil_1387.chain_id << 16) | (work_vil_1387.reserved1[0] << 8) | work_vil_1387.reserved1[1]; + buf_vil_tw[1] = work_vil_1387.work_count; + for(j=2; jbaud | 0x80; //8-15 gateblk=1 + gateblk[0] |= 0x80; + //gateblk[3] = CRC5(gateblk, 4*8 - 5); + gateblk[3] = 0x80; // MMEN=1 + gateblk[3] = 0x80 | (0x1f & CRC5(gateblk, 4*8 - 5)); + applog(LOG_DEBUG,"%s: gateblk[0]=0x%x, gateblk[1]=0x%x, gateblk[2]=0x%x, gateblk[3]=0x%x\n", __FUNCTION__, gateblk[0], gateblk[1], gateblk[2], gateblk[3]); + cmd_buf[0] = gateblk[0]<<24 | gateblk[1]<<16 | gateblk[2]<<8 | gateblk[3]; + + memset(data, 0x00, TW_WRITE_COMMAND_LEN); + data[TW_WRITE_COMMAND_LEN - 1] = 0xff; + data[TW_WRITE_COMMAND_LEN - 12] = 0xff; + + i=chainIndex; + //for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + set_BC_command_buffer(cmd_buf); + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + cgsleep_us(10000); + + for(m=0; mbaud & 0x1f) | GATEBCLK; // enable gateblk + buf_vil[7] = MMEN; // MMEN=1 + + buf_vil[8] = CRC5(buf_vil, 8*8); + + cmd_buf[0] = buf_vil[0]<<24 | buf_vil[1]<<16 | buf_vil[2]<<8 | buf_vil[3]; + cmd_buf[1] = buf_vil[4]<<24 | buf_vil[5]<<16 | buf_vil[6]<<8 | buf_vil[7]; + cmd_buf[2] = buf_vil[8]<<24; + + // prepare special work for openning core + memset(buf_vil_tw, 0x00, TW_WRITE_COMMAND_LEN_VIL/sizeof(unsigned int)); + memset(&work_vil_1387, 0xff, sizeof(struct vil_work_1387)); + + i=chainIndex; + //for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + ret = get_BC_write_command(); //disable null work + ret = BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + ret &= ~BC_COMMAND_EN_NULL_WORK; + set_BC_write_command(ret); + cgsleep_us(1000); + + work_vil_1387.work_type = NORMAL_BLOCK_MARKER; + work_vil_1387.chain_id = 0x80 | i; + work_vil_1387.reserved1[0]= 0; + work_vil_1387.reserved1[1]= 0; + work_vil_1387.work_count = 0; + work_vil_1387.data[0] = 0xff; + work_vil_1387.data[11] = 0xff; + set_BC_command_buffer(cmd_buf); + + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + //ret &= ~BC_COMMAND_EN_NULL_WORK; + set_BC_write_command(value); + cgsleep_us(10000); + + for(m=0; m3000) + { + sprintf(logstr,"Error: send open core work Failed on Chain[%d]!\n",i); + writeInitLogFile(logstr); + + break; + } + } + } + while(1); + + if(wati_count>3000) // failed on send open core work + break; + + if(m==0) //new block + { + work_vil_1387.work_type = NEW_BLOCK_MARKER; + } + else + { + work_vil_1387.work_type = NORMAL_BLOCK_MARKER; + } + + work_vil_1387.chain_id = i | 0x80; //set chain id and enable it + + + buf_vil_tw[0] = (work_vil_1387.work_type<< 24) | (work_vil_1387.chain_id << 16) | (work_vil_1387.reserved1[0] << 8) | work_vil_1387.reserved1[1]; + buf_vil_tw[1] = work_vil_1387.work_count; + for(j=2; jbaud | 0x80; //8-15 gateblk=1 + gateblk[0] |= 0x80; + //gateblk[3] = CRC5(gateblk, 4*8 - 5); + gateblk[3] = 0x80; // MMEN=1 + gateblk[3] = 0x80 | (0x1f & CRC5(gateblk, 4*8 - 5)); + applog(LOG_DEBUG,"%s: gateblk[0]=0x%x, gateblk[1]=0x%x, gateblk[2]=0x%x, gateblk[3]=0x%x\n", __FUNCTION__, gateblk[0], gateblk[1], gateblk[2], gateblk[3]); + cmd_buf[0] = gateblk[0]<<24 | gateblk[1]<<16 | gateblk[2]<<8 | gateblk[3]; + + memset(data, 0x00, TW_WRITE_COMMAND_LEN); + data[TW_WRITE_COMMAND_LEN - 1] = 0xff; + data[TW_WRITE_COMMAND_LEN - 12] = 0xff; + + i=chainIndex; + //for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + set_BC_command_buffer(cmd_buf); + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + set_BC_write_command(value); + cgsleep_us(10000); + + for(m=0; mbaud & 0x1f) | GATEBCLK; // enable gateblk + buf_vil[7] = MMEN; // MMEN=1 + + buf_vil[8] = CRC5(buf_vil, 8*8); + + cmd_buf[0] = buf_vil[0]<<24 | buf_vil[1]<<16 | buf_vil[2]<<8 | buf_vil[3]; + cmd_buf[1] = buf_vil[4]<<24 | buf_vil[5]<<16 | buf_vil[6]<<8 | buf_vil[7]; + cmd_buf[2] = buf_vil[8]<<24; + + // prepare special work for openning core + memset(buf_vil_tw, 0x00, TW_WRITE_COMMAND_LEN_VIL/sizeof(unsigned int)); + memset(&work_vil_1387, 0xff, sizeof(struct vil_work_1387)); + + i=chainIndex; + //for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + ret = get_BC_write_command(); //disable null work + ret = BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + ret &= ~BC_COMMAND_EN_NULL_WORK; + set_BC_write_command(ret); + cgsleep_us(1000); + + work_vil_1387.work_type = NORMAL_BLOCK_MARKER; + work_vil_1387.chain_id = 0x80 | i; + work_vil_1387.reserved1[0]= 0; + work_vil_1387.reserved1[1]= 0; + work_vil_1387.work_count = 0; + work_vil_1387.data[0] = 0xff; + work_vil_1387.data[11] = 0xff; + set_BC_command_buffer(cmd_buf); + + ret = get_BC_write_command(); + value = BC_COMMAND_BUFFER_READY | BC_COMMAND_EN_CHAIN_ID | (i << 16) | (ret & 0xfff0ffff); + //ret &= ~BC_COMMAND_EN_NULL_WORK; + set_BC_write_command(value); + cgsleep_us(10000); + + for(m=0; m=opencore_num) + { + work_vil_1387.data[0] = 0x0; + work_vil_1387.data[11] = 0x0; + } + else + { + work_vil_1387.data[0] = 0xff; + work_vil_1387.data[11] = 0xff; + } + + wati_count=0; + //applog(LOG_DEBUG,"%s: m = %d\n", __FUNCTION__, m); + do + { + work_fifo_ready = get_buffer_space(); + if(work_fifo_ready & (0x1 << i)) + { + wati_count=0; + break; + } + else //work fifo is full, wait for 50ms + { + //applog(LOG_DEBUG,"%s: chain%d work fifo not ready: 0x%x\n", __FUNCTION__, i, work_fifo_ready); + cgsleep_us(1000); + wati_count++; + + if(wati_count>3000) + { + sprintf(logstr,"Error: send open core work Failed on Chain[%d]!\n",i); + writeInitLogFile(logstr); + + break; + } + } + } + while(1); + + if(wati_count>3000) // failed on send open core work + break; + + if(m==0) //new block + { + work_vil_1387.work_type = NEW_BLOCK_MARKER; + } + else + { + work_vil_1387.work_type = NORMAL_BLOCK_MARKER; + } + + work_vil_1387.chain_id = i | 0x80; //set chain id and enable it + + + buf_vil_tw[0] = (work_vil_1387.work_type<< 24) | (work_vil_1387.chain_id << 16) | (work_vil_1387.reserved1[0] << 8) | work_vil_1387.reserved1[1]; + buf_vil_tw[1] = work_vil_1387.work_count; + for(j=2; jaddrInterval, chainIndex); + } + + dev->timeout = 0x1000000/calculate_core_number(BM1387_CORE_NUM)*dev->addrInterval/freq_value*10/100; // 10% timeout + set_time_out_control(((dev->timeout) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + + //open core : inside of this function, set baud into FPGA, so we need set default before here. + open_core_onChain(chainIndex,BM1387_CORE_NUM,i+1,true); // open 1 cores + + sprintf(logstr,"PreOpenCore: open %d cores Done!\n",i+1); + writeInitLogFile(logstr); + + dev->chain_asic_num[chainIndex]=0; + check_asic_reg_oneChain(chainIndex,CHIP_ADDRESS); + + sprintf(logstr,"PreOpenCore: chain[%d] get asicNum = %d\n",chainIndex, dev->chain_asic_num[chainIndex]); + writeInitLogFile(logstr); + + if(dev->chain_asic_num[chainIndex]==CHAIN_ASIC_NUM) + return; + } + +#ifdef USE_NEW_RESET_FPGA + set_reset_hashboard(chainIndex,1); + sleep(RESET_KEEP_TIME); + set_reset_hashboard(chainIndex,0); + sleep(1); +#else + reset_one_hashboard(chainIndex); +#endif + } + } +#endif + + void insert_reg_data(unsigned int *buf) + { + char logstr[1024]; + + if(reg_value_buf.reg_value_num >= MAX_NONCE_NUMBER_IN_FIFO || reg_value_buf.p_wr >= MAX_NONCE_NUMBER_IN_FIFO) + { + clear_register_value_buf(); + return; + } + pthread_mutex_lock(®_mutex); + + reg_value_buf.reg_buffer[reg_value_buf.p_wr].reg_value = buf[1]; + reg_value_buf.reg_buffer[reg_value_buf.p_wr].crc = (buf[0] >> 24) & 0x1f; + reg_value_buf.reg_buffer[reg_value_buf.p_wr].chain_number = CHAIN_NUMBER(buf[0]); + +#ifdef DEBUG_XILINX_NONCE_NOTENOUGH + if(doTestPatten) + { + if(CHAIN_NUMBER(buf[0])==DISABLE_REG_CHAIN_INDEX) + { + sprintf(logstr,"Fatal Debug Error: get reg data on Chain[%d]!\n",CHAIN_NUMBER(buf[0])); + writeInitLogFile(logstr); + } + } +#endif + + if(reg_value_buf.p_wr < MAX_NONCE_NUMBER_IN_FIFO - 1) + { + reg_value_buf.p_wr++; + } + else + { + reg_value_buf.p_wr = 0; + } + + if(reg_value_buf.reg_value_num < MAX_NONCE_NUMBER_IN_FIFO) + { + reg_value_buf.reg_value_num++; + } + else + { + reg_value_buf.reg_value_num = MAX_NONCE_NUMBER_IN_FIFO; + } + //applog(LOG_NOTICE,"%s: p_wr = %d reg_value_num = %d\n", __FUNCTION__,reg_value_buf.p_wr,reg_value_buf.reg_value_num); + pthread_mutex_unlock(®_mutex); + } + + void * get_nonce_and_register() + { + unsigned int work_id=0, *data_addr=NULL; + unsigned int i=0, j=0, m=0, nonce_number = 0, read_loop=0; + unsigned int buf[2] = {0,0}; + uint64_t n2h = 0, n2l = 0; + char ret = 0; + unsigned int nonce_p_wr=0, nonce_p_rd=0, nonce_nonce_num=0, nonce_loop_back=0; + unsigned int reg_p_wr=0, reg_p_rd=0, reg_reg_value_num=0, reg_loop_back=0; + char *buf_hex = NULL; + + while(1) + { + cgsleep_ms(1); + if(doTestPatten) + { + cgsleep_ms(100); + continue; + } + + i = 0; + read_loop = 0; + + nonce_number = get_nonce_number_in_fifo() & MAX_NONCE_NUMBER_IN_FIFO; + if(nonce_number) + { + read_loop = nonce_number; + applog(LOG_DEBUG,"%s: read_loop = %d\n", __FUNCTION__, read_loop); + + for(j=0; j= MAX_NONCE_NUMBER_IN_FIFO || reg_value_buf.p_wr >= MAX_NONCE_NUMBER_IN_FIFO) + { + clear_register_value_buf(); + continue; + } + pthread_mutex_lock(®_mutex); + + reg_value_buf.reg_buffer[reg_value_buf.p_wr].reg_value = buf[1]; + reg_value_buf.reg_buffer[reg_value_buf.p_wr].crc = (buf[0] >> 24) & 0x1f; + reg_value_buf.reg_buffer[reg_value_buf.p_wr].chain_number = CHAIN_NUMBER(buf[0]); + + if(reg_value_buf.p_wr < MAX_NONCE_NUMBER_IN_FIFO - 1) + { + reg_value_buf.p_wr++; + } + else + { + reg_value_buf.p_wr = 0; + } + + if(reg_value_buf.reg_value_num < MAX_NONCE_NUMBER_IN_FIFO) + { + reg_value_buf.reg_value_num++; + } + else + { + reg_value_buf.reg_value_num = MAX_NONCE_NUMBER_IN_FIFO; + } + //applog(LOG_NOTICE,"%s: p_wr = %d reg_value_num = %d\n", __FUNCTION__,reg_value_buf.p_wr,reg_value_buf.reg_value_num); + pthread_mutex_unlock(®_mutex); + } + } + } + } + } + + int getChainAsicNum(int chainIndex) + { + return dev->chain_asic_num[chainIndex]; + } + + int getChainExistFlag(int chainIndex) + { + return dev->chain_exist[chainIndex]; + } + + void saveSearchFailedFlagInfo(char *search_failed_info) + { + FILE *fd; + fd=fopen("/tmp/searcherror","wb"); + if(fd) + { + fwrite(search_failed_info,1,strlen(search_failed_info)+1,fd); + fclose(fd); + } + + system("cp /tmp/search /tmp/err1.log -f"); + system("cp /tmp/freq /tmp/err2.log -f"); + system("cp /tmp/lasttemp /tmp/err3.log -f"); + system("sync"); + } + + int bitmain_soc_init(struct init_config config) + { + char ret=0,j; + uint16_t crc = 0; + bool test_result; + int i=0,x = 0,y = 0; + int hardware_version; + unsigned int data = 0; + bool testRet; + int testCounter=0; + struct sysinfo si; + char logstr[1024]; + +#ifdef DISABLE_FINAL_TEST // if disable test mode, we need set two value and save into files on flash + saveRestartNum(2); + saveRebootTestNum(0); +#endif + + clearInitLogFile(); + + isC5_CtrlBoard=isC5_Board(); + + if(isC5_CtrlBoard) + { +#ifdef R4 + MIN_PWM_PERCENT=MIN_PWM_PERCENT_C5; + MID_PWM_PERCENT=MID_PWM_PERCENT_C5; + MAX_PWM_PERCENT=MAX_PWM_PERCENT_C5; + MAX_TEMP=MAX_TEMP_C5; + MAX_FAN_TEMP=MAX_FAN_TEMP_C5; + MID_FAN_TEMP=MID_FAN_TEMP_C5; + MIN_FAN_TEMP=MIN_FAN_TEMP_C5; + MAX_PCB_TEMP=MAX_PCB_TEMP_C5; + MAX_FAN_PCB_TEMP=MAX_FAN_PCB_TEMP_C5; +#endif + + PHY_MEM_NONCE2_JOBID_ADDRESS=PHY_MEM_NONCE2_JOBID_ADDRESS_C5; + sprintf(logstr,"This is C5 board.\n"); + } + else + { +#ifdef R4 + MIN_PWM_PERCENT=MIN_PWM_PERCENT_XILINX; + MID_PWM_PERCENT=MID_PWM_PERCENT_XILINX; + MAX_PWM_PERCENT=MAX_PWM_PERCENT_XILINX; + MAX_TEMP=MAX_TEMP_XILINX; + MAX_FAN_TEMP=MAX_FAN_TEMP_XILINX; + MID_FAN_TEMP=MID_FAN_TEMP_XILINX; + MIN_FAN_TEMP=MIN_FAN_TEMP_XILINX; + MAX_PCB_TEMP=MAX_PCB_TEMP_XILINX; + MAX_FAN_PCB_TEMP=MAX_FAN_PCB_TEMP_XILINX; +#endif + + sysinfo(&si); + + if(si.totalram > 1000000000) + { + PHY_MEM_NONCE2_JOBID_ADDRESS=PHY_MEM_NONCE2_JOBID_ADDRESS_XILINX_1GB; + + sprintf(logstr, "Detect 1GB control board of XILINX\n"); + } + else if(si.totalram > 500000000) + { + PHY_MEM_NONCE2_JOBID_ADDRESS=PHY_MEM_NONCE2_JOBID_ADDRESS_XILINX_512MB; + + sprintf(logstr, "Detect 512MB control board of XILINX\n"); + } + else + { + PHY_MEM_NONCE2_JOBID_ADDRESS=PHY_MEM_NONCE2_JOBID_ADDRESS_XILINX_256MB; + + sprintf(logstr, "Detect 256MB control board of XILINX\n"); + } + } + writeInitLogFile(logstr); + +#ifdef R4 // if defined , for R4 63 chips + sprintf(logstr,"Miner Type = R4\n"); + writeInitLogFile(logstr); +#endif + +#ifdef S9_PLUS // if defined , for T9 57 chips + sprintf(logstr,"Miner Type = T9\n"); + writeInitLogFile(logstr); +#endif + +#ifdef S9_63 // if defined , for S9 63 chips + sprintf(logstr,"Miner Type = S9\n"); + writeInitLogFile(logstr); +#endif + +#ifdef T9_18 // if defined , for T9+ 18 chips + sprintf(logstr,"Miner Type = T9+\n"); + writeInitLogFile(logstr); +#endif + + memcpy(&config_parameter, &config, sizeof(struct init_config)); + + if(config_parameter.token_type != INIT_CONFIG_TYPE) + { + applog(LOG_DEBUG,"%s: config_parameter.token_type != 0x%x, it is 0x%x\n", __FUNCTION__, INIT_CONFIG_TYPE, config_parameter.token_type); + return -1; + } + + crc = CRC16((uint8_t*)(&config_parameter), sizeof(struct init_config) - sizeof(uint16_t)); + if(crc != config_parameter.crc) + { + applog(LOG_DEBUG,"%s: config_parameter.crc = 0x%x, but we calculate it as 0x%x\n", __FUNCTION__, config_parameter.crc, crc); + return -2; + } + + read_nonce_reg_id = calloc(1,sizeof(struct thr_info)); + if(thr_info_create(read_nonce_reg_id, NULL, get_nonce_and_register, read_nonce_reg_id)) + { + applog(LOG_DEBUG,"%s: create thread for get nonce and register from FPGA failed\n", __FUNCTION__); + return -5; + } + + pthread_detach(read_nonce_reg_id->pth); + + //init axi + bitmain_axi_init(); + +#ifdef USE_NEW_RESET_FPGA + set_reset_allhashboard(1); + sleep(RESET_KEEP_TIME); + set_reset_allhashboard(0); + sleep(1); + set_reset_allhashboard(1); +#endif + + //reset FPGA & HASH board + if(config_parameter.reset) + { + set_QN_write_data_command(RESET_HASH_BOARD | RESET_ALL | RESET_FPGA | RESET_TIME(RESET_HASHBOARD_TIME)); +#ifdef USE_NEW_RESET_FPGA + sleep(2); +#else + while(get_QN_write_data_command() & RESET_HASH_BOARD) + { + cgsleep_ms(30); + } + cgsleep_ms(500); +#endif + set_PWM(MAX_PWM_PERCENT); + } + +#ifdef T9_18 + // config fpga into T9+ mode + set_Hardware_version(0x80000000); +#endif + +#ifdef DEBUG_PRINT_T9_PLUS_PIC_HEART_INFO + set_red_led(false); // close red led +#endif + + // need read FPGA version at first, used in T9+ + hardware_version = get_hardware_version(); + pcb_version = (hardware_version >> 16) & 0x00007fff; // for T9+ the highest bit is used as config for S9 or T9+ mode, so use 7fff + fpga_version = hardware_version & 0x000000ff; + sprintf(g_miner_version, "%d.%d.%d.%d", fpga_version, pcb_version, SOC_VERSION, BMMINER_VERSION); + +#ifdef USE_NEW_RESET_FPGA + set_reset_allhashboard(1); +#endif + + dev->baud=DEFAULT_BAUD_VALUE; // need set default value as init value + + set_nonce2_and_job_id_store_address(PHY_MEM_NONCE2_JOBID_ADDRESS); + set_job_start_address(PHY_MEM_JOB_START_ADDRESS_1); + + //check chain + check_chain(); + +#ifdef T9_18 + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + + pthread_mutex_lock(&iic_mutex); + if(i>=1 && i<=3) + { + reset_iic_pic(i); + jump_to_app_CheckAndRestorePIC_T9_18(i); + + if(!isFixedFreqMode()) + { + read_freq_badcores(i,chain_pic_buf[i]); + + sprintf(logstr,"Chain[%d] read_freq_badcores : ",i); + writeInitLogFile(logstr); + for(j=0; j<128; j++) + { + sprintf(logstr,"0x%02x ",chain_pic_buf[i][j]); + writeInitLogFile(logstr); + } + sprintf(logstr,"\n"); + writeInitLogFile(logstr); + } + } + + if(!isFixedFreqMode()) + { + if(chain_pic_buf[new_T9_PLUS_chainIndex][0] == FREQ_MAGIC) + { + chain_voltage_value[i]=chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+1]*10; + + sprintf(logstr,"Chain[J%d] has backup chain_voltage=%d\n",i+1,chain_voltage_value[i]); + writeInitLogFile(logstr); + } + + lowest_testOK_temp[i]=(signed char)chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+3]; + + sprintf(logstr,"Chain[J%d] test patten OK temp=%d\n",i+1,lowest_testOK_temp[i]); + writeInitLogFile(logstr); + +#ifdef DISABLE_TEMP_PROTECT // for debug + if(lowest_testOK_temp[i]chain_exist[i] == 1) + { + pthread_mutex_lock(&iic_mutex); + reset_iic_pic(i); + cgsleep_ms(500); + + if(!isFixedFreqMode()) + { + set_pic_iic_flash_addr_pointer(i, PIC_FLASH_POINTER_FREQ_START_ADDRESS_H, PIC_FLASH_POINTER_FREQ_START_ADDRESS_L); + get_data_from_pic_flash(i, last_freq[i]); + get_data_from_pic_flash(i, last_freq[i]+16); + get_data_from_pic_flash(i, last_freq[i]+32); + get_data_from_pic_flash(i, last_freq[i]+48); + get_data_from_pic_flash(i, last_freq[i]+64); + get_data_from_pic_flash(i, last_freq[i]+80); + get_data_from_pic_flash(i, last_freq[i]+96); + get_data_from_pic_flash(i, last_freq[i]+112); + + set_pic_iic_flash_addr_pointer(i, PIC_FLASH_POINTER_BADCORE_START_ADDRESS_H, PIC_FLASH_POINTER_BADCORE_START_ADDRESS_L); + get_data_from_pic_flash(i, badcore_num_buf[i]); + get_data_from_pic_flash(i, badcore_num_buf[i]+16); + get_data_from_pic_flash(i, badcore_num_buf[i]+32); + get_data_from_pic_flash(i, badcore_num_buf[i]+48); + + if(last_freq[i][1] == FREQ_MAGIC && last_freq[i][40] == 0x23) //0x23 is backup voltage magic number + { + chain_voltage_value[i]=(((last_freq[i][36]&0x0f)<<4)+(last_freq[i][38]&0x0f))*10; + + sprintf(logstr,"Chain[J%d] has backup chain_voltage=%d\n",i+1,chain_voltage_value[i]); + writeInitLogFile(logstr); + } + + if(last_freq[i][1] == FREQ_MAGIC && last_freq[i][46] == 0x23) //0x23 is board temp magic number + { + lowest_testOK_temp[i]=(signed char)(((last_freq[i][42]&0x0f)<<4)+(last_freq[i][44]&0x0f)); + + sprintf(logstr,"Chain[J%d] test patten OK temp=%d\n",i+1,lowest_testOK_temp[i]); + writeInitLogFile(logstr); + +#ifdef DISABLE_TEMP_PROTECT // for debug + if(lowest_testOK_temp[i]pth); + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + unsigned char vol_pic; + pthread_mutex_lock(&iic_mutex); + +#ifdef ENABLE_HIGH_VOLTAGE_OPENCORE + chain_voltage_pic[i] = get_pic_voltage(i); // read orignal voltage at first! + + vol_pic=getPICvoltageFromValue(HIGHEST_VOLTAGE_LIMITED_HW); + +#ifdef T9_18 + sprintf(logstr,"Chain[J%d] will use voltage=%d [%d] to open core\n",i+1,HIGHEST_VOLTAGE_LIMITED_HW,vol_pic); + writeInitLogFile(logstr); + + if(fpga_version>=0xE) + { + if(i>=1 && i<=3) + set_voltage_T9_18_into_PIC(i, vol_pic); + } + else + { + if(i%3==0) + set_voltage_T9_18_into_PIC(i, vol_pic); + } +#else + set_pic_voltage(i, vol_pic); +#endif +#endif + +#ifndef T9_18 + enable_pic_dac(i); +#endif + pthread_mutex_unlock(&iic_mutex); + } + } + + if(isFixedFreqMode()) + { + // we must set voltage value according to the freq of config file! + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + chain_voltage_value[i] = getFixedFreqVoltageValue(config_parameter.frequency); + chain_voltage_pic[i] = getPICvoltageFromValue(chain_voltage_value[i]); + + sprintf(logstr,"Fix freq=%d Chain[%d] voltage_pic=%d value=%d\n",config_parameter.frequency,i,chain_voltage_pic[i],chain_voltage_value[i]); + writeInitLogFile(logstr); + } + } + } + + if(!isFixedFreqMode()) + { + cgsleep_ms(100); + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + int vol_value; + unsigned char vol_pic; + pthread_mutex_lock(&iic_mutex); +#ifndef ENABLE_HIGH_VOLTAGE_OPENCORE + chain_voltage_pic[i] = get_pic_voltage(i); +#endif + vol_value = getVolValueFromPICvoltage(chain_voltage_pic[i]); + + sprintf(logstr,"Chain[J%d] orignal chain_voltage_pic=%d value=%d\n",i+1,chain_voltage_pic[i],vol_value); + writeInitLogFile(logstr); + +#ifdef T9_18 + if(getChainPICMagicNumber(i)== FREQ_MAGIC) +#else + if(last_freq[i][1] == FREQ_MAGIC && last_freq[i][40] == 0x23) //0x23 is backup voltage magic number +#endif + { +#ifndef DEBUG_KEEP_USE_PIC_VOLTAGE_WITHOUT_CHECKING_VOLTAGE_OF_SEARCHFREQ + if(vol_value != chain_voltage_value[i]) // if not equal, we need force to set backup voltage to hashbaord!!! + { + vol_pic=getPICvoltageFromValue(chain_voltage_value[i]); + + sprintf(logstr,"Chain[J%d] will use backup chain_voltage_pic=%d [%d]\n",i+1,chain_voltage_value[i],vol_pic); + writeInitLogFile(logstr); + + chain_voltage_pic[i] = vol_pic; + +#ifndef ENABLE_HIGH_VOLTAGE_OPENCORE +#ifndef T9_18 // T9_18 only can call enable_pic_dac once after jump to app!!! + set_pic_voltage(i, vol_pic); + enable_pic_dac(i); +#endif +#endif + sprintf(logstr,"Chain[J%d] get working chain_voltage_pic=%d\n",i+1,chain_voltage_pic[i]); + writeInitLogFile(logstr); + } +#endif + } + + pthread_mutex_unlock(&iic_mutex); + } + } + cgsleep_ms(1000); + } + +#ifdef T9_18 + // set voltage and enable it for only once!!! + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + pthread_mutex_lock(&iic_mutex); +#ifndef ENABLE_HIGH_VOLTAGE_OPENCORE + set_pic_voltage(i, 0); // the second parameter is not used, we set 0 for T9_18 +#endif + enable_pic_dac(i); + pthread_mutex_unlock(&iic_mutex); + } + } + sleep(5); // wait for sometime , voltage need time to prepare!!! +#endif + +#ifdef USE_NEW_RESET_FPGA + set_reset_allhashboard(1); + sleep(RESET_KEEP_TIME); + set_reset_allhashboard(0); + sleep(1); +#else + set_QN_write_data_command(RESET_HASH_BOARD | RESET_ALL | RESET_TIME(RESET_HASHBOARD_TIME)); + while(get_QN_write_data_command() & RESET_HASH_BOARD) + { + cgsleep_ms(30); + } + cgsleep_ms(1000); +#endif + + if(opt_multi_version) + set_dhash_acc_control(get_dhash_acc_control() & (~OPERATION_MODE) & (~ VIL_MIDSTATE_NUMBER(0xf)) | VIL_MIDSTATE_NUMBER(1) | VIL_MODE & (~NEW_BLOCK) & (~RUN_BIT)); + cgsleep_ms(10); + + //set core number + dev->corenum = BM1387_CORE_NUM; + +#ifdef USE_PREINIT_OPENCORE + // must set default baud here !!! because maybe some chip can not receive signal, we must keep default baud, and let those chip has chance to get command on next time!!! + // but if set default baud, it is too slow ,will cause chips work timeout, voltage will be changing always!!! + //set_baud(DEFAULT_BAUD_VALUE,1); // so we do not set it, and only try pre-open core in S9+ + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + getAsicNum_preOpenCore(i); // need set default baud 26 at first!!! + + sprintf(logstr,"Chain[J%d] has %d asic\n",i+1,dev->chain_asic_num[i]); + writeInitLogFile(logstr); + + if(dev->chain_asic_num[i] != CHAIN_ASIC_NUM && readRebootTestNum()>0) + { + char error_info[256]; + sprintf(error_info,"J%d:3",i+1); + saveSearchFailedFlagInfo(error_info); + + system("reboot"); + } + + if(dev->chain_asic_num[i]<=0) + { + dev->chain_exist[i]=0; + } + } + } +#else + //check ASIC number for every chain + check_asic_reg(CHIP_ADDRESS); + cgsleep_ms(10); + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + int retry_count=0; + sprintf(logstr,"Chain[J%d] has %d asic\n",i+1,dev->chain_asic_num[i]); + writeInitLogFile(logstr); + +#ifndef T9_18 + while(dev->chain_asic_num[i] != CHAIN_ASIC_NUM && retry_count<6) + { + dev->chain_asic_num[i]=0; + +#ifdef USE_NEW_RESET_FPGA + set_reset_hashboard(i,1); +#endif + pthread_mutex_lock(&iic_mutex); + disable_pic_dac(i); + pthread_mutex_unlock(&iic_mutex); + sleep(1); + + pthread_mutex_lock(&iic_mutex); + enable_pic_dac(i); + pthread_mutex_unlock(&iic_mutex); + sleep(2); + +#ifdef USE_NEW_RESET_FPGA + set_reset_hashboard(i,0); + sleep(1); +#else + reset_one_hashboard(i); +#endif + + check_asic_reg_oneChain(i,CHIP_ADDRESS); + + sprintf(logstr,"retry Chain[J%d] has %d asic\n",i+1,dev->chain_asic_num[i]); + writeInitLogFile(logstr); + + retry_count++; + } +#endif + if(dev->chain_asic_num[i] != CHAIN_ASIC_NUM && readRebootTestNum()>0) + { + char error_info[256]; + sprintf(error_info,"J%d:3",i+1); + saveSearchFailedFlagInfo(error_info); + + system("reboot"); + } + + if(dev->chain_asic_num[i]<=0) + { + dev->chain_exist[i]=0; + } + } + } +#endif + + // clement for debug +// check_asic_reg(TICKET_MASK); + + software_set_address(); + cgsleep_ms(10); + +// check_asic_reg(CHIP_ADDRESS); +// cgsleep_ms(10); + + if(config_parameter.frequency_eft) + { + dev->frequency = config_parameter.frequency; + set_frequency(dev->frequency); + sprintf(dev->frequency_t,"%u",dev->frequency); + } + + cgsleep_ms(10); + + //check who control fan + dev->fan_eft = config_parameter.fan_eft; + dev->fan_pwm= config_parameter.fan_pwm_percent; + applog(LOG_DEBUG,"%s: fan_eft : %d fan_pwm : %d\n", __FUNCTION__,dev->fan_eft,dev->fan_pwm); + if(config_parameter.fan_eft) + { + if((config_parameter.fan_pwm_percent >= 0) && (config_parameter.fan_pwm_percent <= 100)) + { + set_PWM(config_parameter.fan_pwm_percent); + } + else + { + set_PWM_according_to_temperature(); + } + } + else + { + set_PWM_according_to_temperature(); + } + + //calculate real timeout + if(config_parameter.timeout_eft) + { + if(config_parameter.timeout_data_integer == 0 && config_parameter.timeout_data_fractions == 0) //driver calculate out timeout value + { + // clement change to 70/100 org: 90/100 +#ifdef CAPTURE_PATTEN + dev->timeout = 0x1000000/calculate_core_number(dev->corenum)*dev->addrInterval/(dev->frequency)*10/100; +#else + dev->timeout = 0x1000000/calculate_core_number(dev->corenum)*dev->addrInterval/(dev->frequency)*90/100; +#endif + // for set_freq_auto test,set timeout when frequency equals 700M + // dev->timeout = 0x1000000/calculate_core_number(dev->corenum)*dev->addrInterval/700*90/100; + applog(LOG_DEBUG,"dev->timeout = %d\n", dev->timeout); + } + else + { + dev->timeout = config_parameter.timeout_data_integer * 1000 + config_parameter.timeout_data_fractions; + } + + if(dev->timeout > MAX_TIMEOUT_VALUE) + { + dev->timeout = MAX_TIMEOUT_VALUE; + } + } + + //set baud + init_uart_baud(); + cgsleep_ms(10); + + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1 && dev->chain_asic_num[i] == CHAIN_ASIC_NUM) + { + calibration_sensor_offset(0x98,i); + cgsleep_ms(10); + } + } + +#ifdef T9_18 + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1 && dev->chain_asic_num[i] == CHAIN_ASIC_NUM) + { + if(fpga_version>=0xE) + { + switch(i) // only chain 8, 10, 12... has temp sensor!!! we just copy to other chains + { + case 1: + case 9: + dev->chain_asic_temp_num[i]=dev->chain_asic_temp_num[8]; + dev->TempChipAddr[i][0]=dev->TempChipAddr[8][0]; + dev->TempChipAddr[i][1]=dev->TempChipAddr[8][1]; + break; + case 2: + case 11: + dev->chain_asic_temp_num[i]=dev->chain_asic_temp_num[10]; + dev->TempChipAddr[i][0]=dev->TempChipAddr[10][0]; + dev->TempChipAddr[i][1]=dev->TempChipAddr[10][1]; + break; + case 3: + case 13: + dev->chain_asic_temp_num[i]=dev->chain_asic_temp_num[12]; + dev->TempChipAddr[i][0]=dev->TempChipAddr[12][0]; + dev->TempChipAddr[i][1]=dev->TempChipAddr[12][1]; + break; + } + } + else + { + if(i%3 != 1) // only chain 1, 4, 7... has temp sensor!!! we just copy chain[1] temp info into chain[0] and chain[2] + { + dev->chain_asic_temp_num[i]=dev->chain_asic_temp_num[((i/3)*3)+1]; + dev->TempChipAddr[i][0]=dev->TempChipAddr[((i/3)*3)+1][0]; + dev->TempChipAddr[i][1]=dev->TempChipAddr[((i/3)*3)+1][1]; + } + } + } + } +#endif + +#if 0 + //set big timeout value for open core + //set_time_out_control((MAX_TIMEOUT_VALUE - 100) | TIME_OUT_VALID); + set_time_out_control(0xc350 | TIME_OUT_VALID); +#else + //set testpatten timeout , dev->timeout*0.1 + if(opt_multi_version) + set_time_out_control((((dev->timeout/10) * 1 /*opt_multi_version*/) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + else + set_time_out_control(((dev->timeout/10) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); +#endif + + set_PWM(MAX_PWM_PERCENT); + + if(!isFixedFreqMode()) + { + // below process is check voltage and make sure not too high, must can be processed after set_frequency, because of GetTotalRate function need init to support fixed freq old miner S9 + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) // here must use i from 0 in for loop, because we use j to get the index as config file's voltage value + { + int vol_value_limited,vol_value; + unsigned char vol_pic; + + if(dev->chain_exist[i] == 0) + continue; + + if(isChainEnough()) + { + vol_pic=chain_voltage_pic[i]; + vol_value = getVolValueFromPICvoltage(vol_pic); + vol_value_limited=getVoltageLimitedFromHashrate(GetTotalRate()); + +#ifdef DEBUG_KEEP_USE_PIC_VOLTAGE_WITHOUT_CHECKING_VOLTAGE_OF_SEARCHFREQ + if(vol_value>=HIGHEST_VOLTAGE_LIMITED_HW) // we keep use pic voltage, but we still need check voltage can not be the highest voltage! +#endif + { + sprintf(logstr,"get PIC voltage=%d on chain[%d], check: must be < %d\n",vol_value,i,vol_value_limited); + writeInitLogFile(logstr); + +#ifdef ENABLE_REINIT_WHEN_TESTFAILED + if(readRetryFlag()>0) + { + // we need use higher voltage , but meet the limit rules of power and hashrate + sprintf(logstr,"retryFlag=1 will set the voltage limited on chain[%d], change voltage=%d\n",i,vol_value_limited); + writeInitLogFile(logstr); + + vol_pic=getPICvoltageFromValue(vol_value_limited); + sprintf(logstr,"now set pic voltage=%d on chain[%d]\n",vol_pic,i); + writeInitLogFile(logstr); + + chain_voltage_pic[i]=vol_pic; + +#ifndef ENABLE_HIGH_VOLTAGE_OPENCORE + pthread_mutex_lock(&iic_mutex); + set_pic_voltage(i, vol_pic); + pthread_mutex_unlock(&iic_mutex); +#endif + } + else +#endif + if(vol_value > vol_value_limited) // we will set voltage to the highest voltage for the last chance on test patten + { + sprintf(logstr,"will set the voltage limited on chain[%d], change voltage=%d\n",i,vol_value_limited); + writeInitLogFile(logstr); + + vol_pic=getPICvoltageFromValue(vol_value_limited); + sprintf(logstr,"now set pic voltage=%d on chain[%d]\n",vol_pic,i); + writeInitLogFile(logstr); + + chain_voltage_pic[i]=vol_pic; + +#ifndef ENABLE_HIGH_VOLTAGE_OPENCORE + pthread_mutex_lock(&iic_mutex); + set_pic_voltage(i, vol_pic); + pthread_mutex_unlock(&iic_mutex); +#endif + } + } + } + } + } + +#ifdef ENABLE_HIGH_VOLTAGE_OPENCORE + for(i=0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + int vol_value; + unsigned char vol_pic; + + if(dev->chain_exist[i] == 1) + { +#ifdef USE_OPENCORE_ONEBYONE + opencore_onebyone_onChain(i); +#else + open_core_one_chain(i,true); +#endif + sleep(1); + +#ifdef DEBUG_DOWN_VOLTAGE_TEST + vol_value=getVolValueFromPICvoltage(chain_voltage_pic[i])-DEBUG_DOWN_VOLTAGE_VALUE; + vol_pic=getPICvoltageFromValue(vol_value); + + pthread_mutex_lock(&iic_mutex); + // restore the normal voltage + set_pic_voltage(i, vol_pic); + pthread_mutex_unlock(&iic_mutex); + + sprintf(logstr,"DEBUG MODE Chain[J%d] set working voltage=%d [%d] orignal voltage=%d [%d]\n",i+1,vol_value,vol_pic,getVolValueFromPICvoltage(chain_voltage_pic[i]),chain_voltage_pic[i]); + writeInitLogFile(logstr); +#else + +#ifdef T9_18 + if(fpga_version>=0xE) + { + if(i==1) + { + sprintf(logstr,"open core on chain[1] [8] [9]...\n"); + writeInitLogFile(logstr); + + // we must try open core on chain [8] and chain[9] ... +#ifdef USE_OPENCORE_ONEBYONE + opencore_onebyone_onChain(8); + sleep(1); + opencore_onebyone_onChain(9); + sleep(1); +#else + open_core_one_chain(8,true); + sleep(1); + open_core_one_chain(9,true); + sleep(1); +#endif + } + else if(i==2) + { + sprintf(logstr,"open core on chain[2] [10] [11]...\n"); + writeInitLogFile(logstr); + +#ifdef USE_OPENCORE_ONEBYONE + opencore_onebyone_onChain(10); + sleep(1); + opencore_onebyone_onChain(11); + sleep(1); +#else + open_core_one_chain(10,true); + sleep(1); + open_core_one_chain(11,true); + sleep(1); +#endif + } + else if(i==3) + { + sprintf(logstr,"open core on chain[3] [12] [13]...\n"); + writeInitLogFile(logstr); +#ifdef USE_OPENCORE_ONEBYONE + opencore_onebyone_onChain(12); + sleep(1); + opencore_onebyone_onChain(13); + sleep(1); +#else + open_core_one_chain(12,true); + sleep(1); + open_core_one_chain(13,true); + sleep(1); +#endif + } + else break; // we jump out of open core loop. because we have done open core above!!! + + pthread_mutex_lock(&iic_mutex); + set_pic_voltage(i, chain_voltage_pic[i]); + pthread_mutex_unlock(&iic_mutex); + + sprintf(logstr,"Chain[J%d] set working voltage=%d [%d]\n",i+1,getVolValueFromPICvoltage(chain_voltage_pic[i]),chain_voltage_pic[i]); + writeInitLogFile(logstr); + } + else + { + if(i%3==2) // only set working voltage when open core done on last chain of 3 chains!!! + { + pthread_mutex_lock(&iic_mutex); + set_pic_voltage((i/3)*3, chain_voltage_pic[i]); + pthread_mutex_unlock(&iic_mutex); + } + + sprintf(logstr,"Chain[J%d] set working voltage=%d [%d]\n",i+1,getVolValueFromPICvoltage(chain_voltage_pic[i]),chain_voltage_pic[i]); + writeInitLogFile(logstr); + } +#else + pthread_mutex_lock(&iic_mutex); + // restore the normal voltage + set_pic_voltage(i, chain_voltage_pic[i]); + pthread_mutex_unlock(&iic_mutex); + + sprintf(logstr,"Chain[J%d] set working voltage=%d [%d]\n",i+1,getVolValueFromPICvoltage(chain_voltage_pic[i]),chain_voltage_pic[i]); + writeInitLogFile(logstr); +#endif +#endif + } + } +#else + open_core(true); +#endif + +#ifdef USE_OPENCORE_TWICE + sleep(5); + open_core(true); +#endif + + // clement for debug +// check_asic_reg(TICKET_MASK); + +#ifdef ENABLE_SET_TICKETMASK_BEFORE_TESTPATTEN + // must call it , because when software restart (not system reboot), it cause test patten failed !!! + sleep(5); + set_asic_ticket_mask(0); + set_hcnt(0); + sleep(5); +#endif + + // clement for debug +// check_asic_reg(TICKET_MASK); + +#ifdef FASTER_TESTPATTEN + //set real timeout back + if(opt_multi_version) + set_time_out_control((((dev->timeout/10) * 1 /*opt_multi_version*/) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + else + set_time_out_control(((dev->timeout/10) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); +#else + //set real timeout back + if(opt_multi_version) + set_time_out_control(((dev->timeout * 1 /*opt_multi_version*/) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + else + set_time_out_control(((dev->timeout) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); +#endif + + read_temp_id = calloc(1,sizeof(struct thr_info)); + if(thr_info_create(read_temp_id, NULL, read_temp_func, read_temp_id)) + { + applog(LOG_DEBUG,"%s: create thread for read temp\n", __FUNCTION__); + return -7; + } + pthread_detach(read_temp_id->pth); + +#ifndef CAPTURE_PATTEN + if(!isFixedFreqMode()) + { +//#ifdef ENABLE_PREHEAT + if(opt_pre_heat) + { +#ifdef DEBUG_XILINX_NONCE_NOTENOUGH + set_bmc_counter(0); + sprintf(logstr,"reset bmc counter=0x%08x\n",read_bmc_counter()); + writeInitLogFile(logstr); +#endif + //if(readRebootTestNum()<=0) // we will do preheat every time, even in reboot test mode. + { + doTestPatten=true; + sleep(3); + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { +#ifdef T9_18 + memcpy(chain_pic_buf[i],chip_last_freq[i],128); // restore the real freq for chips +#else + memcpy(last_freq[i],chip_last_freq[i],256); // restore the real freq for chips +#endif + } + } + + someBoardUpVoltage=false; + test_result=clement_doTestBoard(true); + +#ifdef ENABLE_REINIT_WHEN_TESTFAILED +#ifdef DEBUG_FORCE_REINIT + test_result=false; +#endif + if((!test_result) && (readRetryFlag()==0)) + { + // save a flag file to indicate that we need use the higher voltage after open core, but still meet the limit rules of power and hashrate + saveRetryFlag(1); + + // call system to restart bmminer + exit(0); + // while(1)sleep(1); + } + + //if(readRetryFlag()>0) + // saveRetryFlag(0); // clear retry flag if success on test patten! +#endif + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { +#ifdef T9_18 + memcpy(chain_pic_buf[i],show_last_freq[i],128); // restore the user freq for showed on web for users +#else + memcpy(last_freq[i],show_last_freq[i],256); // restore the user freq for showed on web for users +#endif + } + } + + // must re-set these two address to FPGA + set_nonce2_and_job_id_store_address(PHY_MEM_NONCE2_JOBID_ADDRESS); + set_job_start_address(PHY_MEM_JOB_START_ADDRESS_1); + + doTestPatten=false; + } + +#ifdef DEBUG_XILINX_NONCE_NOTENOUGH + sprintf(logstr,"After TEST bmc counter=0x%08x\n",read_bmc_counter()); + writeInitLogFile(logstr); +#endif + } +//#endif + } +#endif + + //clear_nonce_fifo(); +#ifndef CAPTURE_PATTEN + set_asic_ticket_mask(63); // clement + set_hcnt(0); + cgsleep_ms(10); +#endif + +#ifdef FASTER_TESTPATTEN + //set real timeout back + if(opt_multi_version) + set_time_out_control(((dev->timeout * opt_multi_version) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + else + set_time_out_control(((dev->timeout) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); +#endif + + check_system_work_id = calloc(1,sizeof(struct thr_info)); + if(thr_info_create(check_system_work_id, NULL, check_system_work, check_system_work_id)) + { + applog(LOG_DEBUG,"%s: create thread for check system\n", __FUNCTION__); + return -6; + } + pthread_detach(check_system_work_id->pth); + + for(x=0; xchain_exist[x]) + { + int offset = 0; + for(y=0; ychain_asic_num[x]; y++) + { + if(y%8 == 0) + { + dev->chain_asic_status_string[x][y+offset] = ' '; + offset++; + } + dev->chain_asic_status_string[x][y+offset] = 'o'; + dev->chain_asic_nonce[x][y] = 0; + } + dev->chain_asic_status_string[x][y+offset] = '\0'; + } + } + + cgtime(&tv_send_job); + cgtime(&tv_send); + startCheckNetworkJob=true; + + setStartTimePoint(); + return 0; + } + + void bitmain_core_reInit() + { + int i,j; + int vol_value,vol_pic,cur_vol_value,cur_vol_pic; + char logstr[1024]; + + doTestPatten=true; + pthread_mutex_lock(&reinit_mutex); + startCheckNetworkJob=false; + + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & ~RUN_BIT); + sleep(3); + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & ~RUN_BIT); + sleep(2); + + open_core(true); + sprintf(logstr,"bitmain_core_reInit open_core over\n"); + writeInitLogFile(logstr); + + // must re-set these two address to FPGA + set_nonce2_and_job_id_store_address(PHY_MEM_NONCE2_JOBID_ADDRESS); + set_job_start_address(PHY_MEM_JOB_START_ADDRESS_1); + + //clear_nonce_fifo(); +#ifndef CAPTURE_PATTEN + set_asic_ticket_mask(63); // clement + set_hcnt(0); + cgsleep_ms(10); +#endif + set_nonce_fifo_interrupt(get_nonce_fifo_interrupt() | FLUSH_NONCE3_FIFO); + +#if 0 + //set real timeout back + if(opt_multi_version) + set_time_out_control(((dev->timeout * opt_multi_version) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); + else + set_time_out_control(((dev->timeout) & MAX_TIMEOUT_VALUE) | TIME_OUT_VALID); +#endif + + doTestPatten=false; + pthread_mutex_unlock(&reinit_mutex); + re_send_last_job(); + cgtime(&tv_send_job); + cgtime(&tv_send); + startCheckNetworkJob=true; + } + + int parse_job_to_soc(unsigned char **buf,struct pool *pool,uint32_t id) + { + uint16_t crc = 0; + uint32_t buf_len = 0; + uint64_t nonce2 = 0; + unsigned char * tmp_buf; + int i; + static uint64_t pool_send_nu = 0; + struct part_of_job part_job; + char *buf_hex = NULL; + + part_job.token_type = SEND_JOB_TYPE; + part_job.version = 0x00; + part_job.pool_nu = pool_send_nu; + part_job.new_block = pool->swork.clean ?1:0; + part_job.asic_diff_valid = 1; + part_job.asic_diff = 15; + part_job.job_id = id; + + hex2bin((unsigned char *)&part_job.bbversion, pool->bbversion, 4); + hex2bin(part_job.prev_hash, pool->prev_hash, 32); + hex2bin((unsigned char *)&part_job.nbit, pool->nbit, 4); + hex2bin((unsigned char *)&part_job.ntime, pool->ntime, 4); + part_job.coinbase_len = pool->coinbase_len; + part_job.nonce2_offset = pool->nonce2_offset; + part_job.nonce2_bytes_num = pool->n2size; + + nonce2 = htole64(pool->nonce2); + memcpy(&(part_job.nonce2_start_value), pool->coinbase + pool->nonce2_offset,8); + memcpy(&(part_job.nonce2_start_value), &nonce2,pool->n2size); + + part_job.merkles_num = pool->merkles; + buf_len = sizeof(struct part_of_job) + pool->coinbase_len + pool->merkles * 32 + 2; + + tmp_buf = (unsigned char *)malloc(buf_len); + if (unlikely(!tmp_buf)) + quit(1, "Failed to malloc tmp_buf"); + part_job.length = buf_len -8; + + memset(tmp_buf,0,buf_len); + memcpy(tmp_buf,&part_job,sizeof(struct part_of_job)); + memcpy(tmp_buf + sizeof(struct part_of_job), pool->coinbase, pool->coinbase_len); + /* + buf_hex = bin2hex(pool->coinbase,pool->coinbase_len); + printf("coinbase:%s offset:%d n2size:%d nonce2%lld\n",buf_hex,pool->nonce2_offset,pool->n2size,pool->nonce2); + free(buf_hex); + */ + for (i = 0; i < pool->merkles; i++) + { + memcpy(tmp_buf + sizeof(struct part_of_job) + pool->coinbase_len + i * 32, pool->swork.merkle_bin[i], 32); + } + + crc = CRC16((uint8_t *)tmp_buf, buf_len-2); + memcpy(tmp_buf + (buf_len - 2), &crc, 2); + + pool_send_nu++; + *buf = (unsigned char *)malloc(buf_len); + if (unlikely(!tmp_buf)) + quit(1, "Failed to malloc buf"); + memcpy(*buf,tmp_buf,buf_len); + + memcpy(last_job_buffer,tmp_buf,buf_len); + + free(tmp_buf); + return buf_len; + } + + static void show_status(int if_quit) + { + char * buf_hex = NULL; + unsigned int *l_job_start_address = NULL; + unsigned int buf[2] = {0}; + int i = 0; + get_work_nonce2(buf); + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & ~RUN_BIT); + while((unsigned int)get_dhash_acc_control() & RUN_BIT) + { + cgsleep_ms(1); + applog(LOG_DEBUG,"%s: run bit is 1 after set it to 0", __FUNCTION__); + } + + buf_hex = bin2hex((unsigned char *)dev->current_job_start_address,c_coinbase_padding); + + free(buf_hex); + for(i=0; icurrent_job_start_address + c_coinbase_padding+ i*MERKLE_BIN_LEN,32); + free(buf_hex); + } + if(dev->current_job_start_address == job_start_address_1) + { + l_job_start_address = job_start_address_2; + } + else if(dev->current_job_start_address == job_start_address_2) + { + l_job_start_address = job_start_address_1; + } + buf_hex = bin2hex((unsigned char *)l_job_start_address,l_coinbase_padding); + free(buf_hex); + for(i=0; icoinbase,pool->coinbase_len); + printf("%s: nonce2 0x%x\n", __FUNCTION__, nonce2); + printf("%s: coinbase : %s\n", __FUNCTION__, buf_hex); + free(buf_hex); + for(i=0; imerkles; i++) + { + buf_hex = bin2hex(pool->swork.merkle_bin[i],32); + printf("%s: merkle_bin %d : %s\n", __FUNCTION__, i, buf_hex); + free(buf_hex); + } + } + + void re_send_last_job() + { + if(last_job_buffer[0]!=23) + { + pthread_mutex_lock(&reinit_mutex); + send_job(last_job_buffer); + pthread_mutex_unlock(&reinit_mutex); + } + } + + int send_job(unsigned char *buf) + { + unsigned int len = 0, i=0, j=0, coinbase_padding_len = 0; + unsigned short int crc = 0, job_length = 0; + unsigned char *temp_buf = NULL, *coinbase_padding = NULL, *merkles_bin = NULL; + unsigned char buf1[PREV_HASH_LEN] = {0}; + unsigned int buf2[PREV_HASH_LEN] = {0}; + int times = 0; + struct part_of_job *part_job = NULL; + + if(doTestPatten) // do patten , do not send job + return 0; + + if(*(buf + 0) != SEND_JOB_TYPE) + { + applog(LOG_DEBUG,"%s: SEND_JOB_TYPE is wrong : 0x%x\n", __FUNCTION__, *(buf + 0)); + return -1; + } + + len = *((unsigned int *)buf + 4/sizeof(int)); + applog(LOG_DEBUG,"%s: len = 0x%x\n", __FUNCTION__, len); + + temp_buf = malloc(len + 8*sizeof(unsigned char)); + if(!temp_buf) + { + applog(LOG_DEBUG,"%s: malloc buffer failed.\n", __FUNCTION__); + return -2; + } + else + { + memset(temp_buf, 0, len + 8*sizeof(unsigned char)); + memcpy(temp_buf, buf, len + 8*sizeof(unsigned char)); + part_job = (struct part_of_job *)temp_buf; + } + + //write new job data into dev->current_job_start_address + if(dev->current_job_start_address == job_start_address_1) + { + dev->current_job_start_address = job_start_address_2; + } + else if(dev->current_job_start_address == job_start_address_2) + { + dev->current_job_start_address = job_start_address_1; + } + else + { + applog(LOG_DEBUG,"%s: dev->current_job_start_address = 0x%x, but job_start_address_1 = 0x%x, job_start_address_2 = 0x%x\n", __FUNCTION__, dev->current_job_start_address, job_start_address_1, job_start_address_2); + return -3; + } + + + if((part_job->coinbase_len % 64) > 55) + { + coinbase_padding_len = (part_job->coinbase_len/64 + 2) * 64; + } + else + { + coinbase_padding_len = (part_job->coinbase_len/64 + 1) * 64; + } + + coinbase_padding = malloc(coinbase_padding_len); + if(!coinbase_padding) + { + applog(LOG_DEBUG,"%s: malloc coinbase_padding failed.\n", __FUNCTION__); + return -4; + } + else + { + applog(LOG_DEBUG,"%s: coinbase_padding = 0x%x", __FUNCTION__, (unsigned int)coinbase_padding); + } + + if(part_job->merkles_num) + { + merkles_bin = malloc(part_job->merkles_num * MERKLE_BIN_LEN); + if(!merkles_bin) + { + applog(LOG_DEBUG,"%s: malloc merkles_bin failed.\n", __FUNCTION__); + return -5; + } + else + { + applog(LOG_DEBUG,"%s: merkles_bin = 0x%x", __FUNCTION__, (unsigned int)merkles_bin); + } + } + + //applog(LOG_DEBUG,"%s: copy coinbase into memory ...\n", __FUNCTION__); + memset(coinbase_padding, 0, coinbase_padding_len); + memcpy(coinbase_padding, buf + sizeof(struct part_of_job), part_job->coinbase_len); + *(coinbase_padding + part_job->coinbase_len) = 0x80; + *((unsigned int *)coinbase_padding + (coinbase_padding_len - 4)/sizeof(int)) = Swap32((unsigned int)((unsigned long long int)(part_job->coinbase_len * sizeof(char) * 8) & 0x00000000ffffffff)); // 8 means 8 bits + *((unsigned int *)coinbase_padding + (coinbase_padding_len - 8)/sizeof(int)) = Swap32((unsigned int)(((unsigned long long int)(part_job->coinbase_len * sizeof(char) * 8) & 0xffffffff00000000) >> 32)); // 8 means 8 bits + + l_coinbase_padding = c_coinbase_padding; + c_coinbase_padding = coinbase_padding_len; + for(i=0; icurrent_job_start_address + i) = *(coinbase_padding + i); + //applog(LOG_DEBUG,"%s: coinbase_padding_in_ddr[%d] = 0x%x", __FUNCTION__, i, *(((unsigned char *)dev->current_job_start_address + i))); + } + + /* check coinbase & padding in ddr */ + for(i=0; icurrent_job_start_address + i) != *(coinbase_padding + i)) + { + applog(LOG_DEBUG,"%s: coinbase_padding_in_ddr[%d] = 0x%x, but *(coinbase_padding + %d) = 0x%x", __FUNCTION__, i, *(((unsigned char *)dev->current_job_start_address + i)), i, *(coinbase_padding + i)); + } + } + l_merkles_num = c_merkles_num; + c_merkles_num = part_job->merkles_num; + if(part_job->merkles_num) + { + applog(LOG_DEBUG,"%s: copy merkle bin into memory ...\n", __FUNCTION__); + memset(merkles_bin, 0, part_job->merkles_num * MERKLE_BIN_LEN); + memcpy(merkles_bin, buf + sizeof(struct part_of_job) + part_job->coinbase_len , part_job->merkles_num * MERKLE_BIN_LEN); + + for(i=0; i<(part_job->merkles_num * MERKLE_BIN_LEN); i++) + { + *((unsigned char *)dev->current_job_start_address + coinbase_padding_len + i) = *(merkles_bin + i); + //applog(LOG_DEBUG,"%s: merkles_in_ddr[%d] = 0x%x", __FUNCTION__, i, *(((unsigned char *)dev->current_job_start_address + coinbase_padding_len + i))); + } + + for(i=0; i<(part_job->merkles_num * MERKLE_BIN_LEN); i++) + { + if(*((unsigned char *)dev->current_job_start_address + coinbase_padding_len + i) != *(merkles_bin + i)) + { + applog(LOG_DEBUG,"%s: merkles_in_ddr[%d] = 0x%x, but *(merkles_bin + %d) =0x%x", __FUNCTION__, i, *(((unsigned char *)dev->current_job_start_address + coinbase_padding_len + i)), i, *(merkles_bin + i)); + } + } + } + + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & ~RUN_BIT); + while((unsigned int)get_dhash_acc_control() & RUN_BIT) + { + cgsleep_ms(1); + applog(LOG_DEBUG,"%s: run bit is 1 after set it to 0\n", __FUNCTION__); + times++; + } + cgsleep_ms(1); + + + //write new job data into dev->current_job_start_address + if(dev->current_job_start_address == job_start_address_1) + { + set_job_start_address(PHY_MEM_JOB_START_ADDRESS_1); + //applog(LOG_DEBUG,"%s: dev->current_job_start_address = 0x%x\n", __FUNCTION__, (unsigned int)job_start_address_2); + } + else if(dev->current_job_start_address == job_start_address_2) + { + set_job_start_address(PHY_MEM_JOB_START_ADDRESS_2); + //applog(LOG_DEBUG,"%s: dev->current_job_start_address = 0x%x\n", __FUNCTION__, (unsigned int)job_start_address_1); + } + + if(part_job->asic_diff_valid) + { +#ifndef CAPTURE_PATTEN + set_ticket_mask((unsigned int)(part_job->asic_diff & 0x000000ff)); // clement disable it +#endif + dev->diff = part_job->asic_diff & 0xff; + } + + set_job_id(part_job->job_id); + + set_block_header_version(part_job->bbversion); + + memset(buf2, 0, PREV_HASH_LEN*sizeof(unsigned int)); + for(i=0; i<(PREV_HASH_LEN/sizeof(unsigned int)); i++) + { + buf2[i] = ((part_job->prev_hash[4*i + 3]) << 24) | ((part_job->prev_hash[4*i + 2]) << 16) | ((part_job->prev_hash[4*i + 1]) << 8) | (part_job->prev_hash[4*i + 0]); + } + set_pre_header_hash(buf2); + + set_time_stamp(part_job->ntime); + + set_target_bits(part_job->nbit); + + j = (part_job->nonce2_offset << 16) | ((unsigned char)(part_job->nonce2_bytes_num & 0x00ff)) << 8 | (unsigned char)((coinbase_padding_len/64) & 0x000000ff); + set_coinbase_length_and_nonce2_length(j); + + //memset(buf2, 0, PREV_HASH_LEN*sizeof(unsigned int)); + buf2[0] = 0; + buf2[1] = 0; + buf2[0] = ((unsigned long long )(part_job->nonce2_start_value)) & 0xffffffff; + buf2[1] = ((unsigned long long )(part_job->nonce2_start_value) >> 32) & 0xffffffff; + set_work_nonce2(buf2); + + set_merkle_bin_number(part_job->merkles_num); + + job_length = coinbase_padding_len + part_job->merkles_num*MERKLE_BIN_LEN; + set_job_length((unsigned int)job_length & 0x0000ffff); + + cgsleep_ms(1); + + + if(!gBegin_get_nonce) + { + set_nonce_fifo_interrupt(get_nonce_fifo_interrupt() | FLUSH_NONCE3_FIFO); + gBegin_get_nonce = true; + } +#if 1 + //start FPGA generating works + if(part_job->new_block) + { + if(!opt_multi_version) + { + set_dhash_acc_control((unsigned int)get_dhash_acc_control() | NEW_BLOCK ); + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & (~ VIL_MIDSTATE_NUMBER(0xf)) | VIL_MIDSTATE_NUMBER(opt_multi_version)| RUN_BIT | OPERATION_MODE); + } + else + { + set_dhash_acc_control((unsigned int)get_dhash_acc_control() | NEW_BLOCK ); + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & (~ VIL_MIDSTATE_NUMBER(0xf)) | VIL_MIDSTATE_NUMBER(opt_multi_version)| RUN_BIT | OPERATION_MODE |VIL_MODE); + } + } + else + { + if(!opt_multi_version) + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & (~ VIL_MIDSTATE_NUMBER(0xf)) | VIL_MIDSTATE_NUMBER(opt_multi_version)| RUN_BIT| OPERATION_MODE ); + else + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & (~ VIL_MIDSTATE_NUMBER(0xf)) | VIL_MIDSTATE_NUMBER(opt_multi_version)| RUN_BIT| OPERATION_MODE |VIL_MODE); + } +#endif + + free(temp_buf); + free((unsigned char *)coinbase_padding); + if(part_job->merkles_num) + { + free((unsigned char *)merkles_bin); + } + + applog(LOG_DEBUG,"--- %s end\n", __FUNCTION__); + cgtime(&tv_send_job); + return 0; + } + + + static void copy_pool_stratum(struct pool *pool_stratum, struct pool *pool) + { + int i; + int merkles = pool->merkles, job_id_len; + size_t coinbase_len = pool->coinbase_len; + unsigned short crc; + + if (!pool->swork.job_id) + return; + + if (pool_stratum->swork.job_id) + { + job_id_len = strlen(pool->swork.job_id); + crc = CRC16((unsigned char *)pool->swork.job_id, job_id_len); + job_id_len = strlen(pool_stratum->swork.job_id); + + if (CRC16((unsigned char *)pool_stratum->swork.job_id, job_id_len) == crc) + return; + } + + cg_wlock(&pool_stratum->data_lock); + free(pool_stratum->swork.job_id); + free(pool_stratum->nonce1); + free(pool_stratum->coinbase); + + pool_stratum->coinbase = cgcalloc(coinbase_len, 1); + memcpy(pool_stratum->coinbase, pool->coinbase, coinbase_len); + + for (i = 0; i < pool_stratum->merkles; i++) + free(pool_stratum->swork.merkle_bin[i]); + if (merkles) + { + pool_stratum->swork.merkle_bin = cgrealloc(pool_stratum->swork.merkle_bin, + sizeof(char *) * merkles + 1); + for (i = 0; i < merkles; i++) + { + pool_stratum->swork.merkle_bin[i] = cgmalloc(32); + memcpy(pool_stratum->swork.merkle_bin[i], pool->swork.merkle_bin[i], 32); + } + } + + pool_stratum->sdiff = pool->sdiff; + pool_stratum->coinbase_len = pool->coinbase_len; + pool_stratum->nonce2_offset = pool->nonce2_offset; + pool_stratum->n2size = pool->n2size; + pool_stratum->merkles = pool->merkles; + pool_stratum->swork.job_id = strdup(pool->swork.job_id); + pool_stratum->nonce1 = strdup(pool->nonce1); + + memcpy(pool_stratum->ntime, pool->ntime, sizeof(pool_stratum->ntime)); + memcpy(pool_stratum->header_bin, pool->header_bin, sizeof(pool_stratum->header_bin)); + cg_wunlock(&pool_stratum->data_lock); + } + + static bool bitmain_soc_prepare(struct thr_info *thr) + { + struct cgpu_info *bitmain_soc = thr->cgpu; + struct bitmain_soc_info *info = bitmain_soc->device_data; + + info->thr = thr; + mutex_init(&info->lock); + cglock_init(&info->update_lock); + cglock_init(&info->pool0.data_lock); + cglock_init(&info->pool1.data_lock); + cglock_init(&info->pool2.data_lock); + + struct init_config soc_config = + { + .token_type = 0x51, + .version = 0, + .length = 26, + .reset = 1, + .fan_eft = opt_bitmain_fan_ctrl, + .timeout_eft = 1, + .frequency_eft = 1, + .voltage_eft = 1, + .chain_check_time_eft = 1, + .chip_config_eft = 1, + .hw_error_eft = 1, + .beeper_ctrl = 1, + .temp_ctrl = 1, + .chain_freq_eft = 1, + .reserved1 = 0, + .reserved2 = {0}, + .chain_num = 9, + .asic_num = 54, + .fan_pwm_percent = opt_bitmain_fan_pwm, + .temperature = 80, + .frequency = opt_bitmain_soc_freq, + .voltage = {0x07,0x25}, + .chain_check_time_integer = 10, + .chain_check_time_fractions = 10, + .timeout_data_integer = 0, + .timeout_data_fractions = 0, + .reg_data = 0, + .chip_address = 0x04, + .reg_address = 0, + .chain_min_freq = 400, + .chain_max_freq = 600, + }; + soc_config.crc = CRC16((uint8_t *)(&soc_config), sizeof(soc_config)-2); + + bitmain_soc_init(soc_config); + + return true; + } + + static void bitmain_soc_reinit_device(struct cgpu_info *bitmain) + { + if(!status_error) + { + //system("/etc/init.d/bmminer.sh restart > /dev/null 2>&1 &"); + exit(0); + } + } + + + + static void bitmain_soc_detect(__maybe_unused bool hotplug) + { + struct cgpu_info *cgpu = calloc(1, sizeof(*cgpu)); + struct device_drv *drv = &bitmain_soc_drv; + struct bitmain_soc_info *a; + + assert(cgpu); + cgpu->drv = drv; + cgpu->deven = DEV_ENABLED; + cgpu->threads = 1; + cgpu->device_data = calloc(sizeof(struct bitmain_soc_info), 1); + if (unlikely(!(cgpu->device_data))) + quit(1, "Failed to calloc cgpu_info data"); + a = cgpu->device_data; + a->pool0_given_id = 0; + a->pool1_given_id = 1; + a->pool2_given_id = 2; + + assert(add_cgpu(cgpu)); + } + + static __inline void flip_swab(void *dest_p, const void *src_p, unsigned int length) + { + uint32_t *dest = dest_p; + const uint32_t *src = src_p; + int i; + + for (i = 0; i < length/4; i++) + dest[i] = swab32(src[i]); + } + static uint64_t hashtest_submit(struct thr_info *thr, struct work *work, uint32_t nonce, uint8_t *midstate,struct pool *pool,uint64_t nonce2,uint32_t chain_id ) + { + unsigned char hash1[32]; + unsigned char hash2[32]; + int i,j; + unsigned char which_asic_nonce, which_core_nonce; + uint64_t hashes = 0; + static uint64_t pool_diff = 0, net_diff = 0; + static uint64_t pool_diff_bit = 0, net_diff_bit = 0; + + if(pool_diff != (uint64_t)work->sdiff) + { + pool_diff = (uint64_t)work->sdiff; + pool_diff_bit = 0; + uint64_t tmp_pool_diff = pool_diff; + while(tmp_pool_diff > 0) + { + tmp_pool_diff = tmp_pool_diff >> 1; + pool_diff_bit++; + } + pool_diff_bit--; + applog(LOG_DEBUG,"%s: pool_diff:%d work_diff:%d pool_diff_bit:%d ...\n", __FUNCTION__,pool_diff,work->sdiff,pool_diff_bit); + } + + if(net_diff != (uint64_t)current_diff) + { + net_diff = (uint64_t)current_diff; + net_diff_bit = 0; + uint64_t tmp_net_diff = net_diff; + while(tmp_net_diff > 0) + { + tmp_net_diff = tmp_net_diff >> 1; + net_diff_bit++; + } + net_diff_bit--; + applog(LOG_DEBUG,"%s:net_diff:%d current_diff:%d net_diff_bit %d ...\n", __FUNCTION__,net_diff,current_diff,net_diff_bit); + } + + uint32_t *hash2_32 = (uint32_t *)hash1; + __attribute__ ((aligned (4))) sha2_context ctx; + memcpy(ctx.state, (void*)work->midstate, 32); +#if TEST_DHASH + rev((unsigned char*)ctx.state, sizeof(ctx.state)); +#endif + ctx.total[0] = 80; + ctx.total[1] = 00; + memcpy(hash1, (void*)work->data + 64, 12); +#if TEST_DHASH + rev(hash1, 12); +#endif + flip_swab(ctx.buffer, hash1, 12); + memcpy(hash1, &nonce, 4); +#if TEST_DHASH + rev(hash1, 4); +#endif + flip_swab(ctx.buffer + 12, hash1, 4); + + sha2_finish(&ctx, hash1); + + memset( &ctx, 0, sizeof( sha2_context ) ); + sha2(hash1, 32, hash2); + + flip32(hash1, hash2); + + if (hash2_32[7] != 0) + { + if(dev->chain_exist[chain_id] == 1) + { + inc_hw_errors(thr); + dev->chain_hw[chain_id]++; + } + //inc_hw_errors_with_diff(thr,(0x01UL << DEVICE_DIFF)); + //dev->chain_hw[chain_id]+=(0x01UL << DEVICE_DIFF); + applog(LOG_DEBUG,"%s: HASH2_32[7] != 0", __FUNCTION__); + return 0; + } + for(i=0; i < 7; i++) + { + if(be32toh(hash2_32[6 - i]) != 0) + break; + } + +#ifdef CAPTURE_PATTEN + // clement change below: + savelog_nonce(work, nonce); +#endif + + if(i >= pool_diff_bit/32) + { + which_asic_nonce = (nonce >> (24 + dev->check_bit)) & 0xff; + which_core_nonce = (nonce & 0x7f); + applog(LOG_DEBUG,"%s: chain %d which_asic_nonce %d which_core_nonce %d", __FUNCTION__, chain_id, which_asic_nonce, which_core_nonce); + dev->chain_asic_nonce[chain_id][which_asic_nonce]++; + if(be32toh(hash2_32[6 - pool_diff_bit/32]) < ((uint32_t)0xffffffff >> (pool_diff_bit%32))) + { + hashes += (0x01UL << DEVICE_DIFF); + if(current_diff != 0) + { + for(i=0; i < net_diff_bit/32; i++) + { + if(be32toh(hash2_32[6 - i]) != 0) + break; + } + if(i == net_diff_bit/32) + { + if(be32toh(hash2_32[6 - net_diff_bit/32]) < ((uint32_t)0xffffffff >> (net_diff_bit%32))) + { + // to do found block!!! + } + } + } +#ifndef CAPTURE_PATTEN + submit_nonce(thr, work, nonce); // clement disable it , do not submit to pool +#endif + } + else if(be32toh(hash2_32[6 - DEVICE_DIFF/32]) < ((uint32_t)0xffffffff >> (DEVICE_DIFF%32))) + { + hashes += (0x01UL << DEVICE_DIFF); + } + } + return hashes; + } + + void * bitmain_scanhash(void *arg) + { + struct thr_info *thr = (struct thr_info *)arg; + struct cgpu_info *bitmain_soc = thr->cgpu; + struct bitmain_soc_info *info = bitmain_soc->device_data; + double device_tdiff, hwp; + uint32_t a = 0, b = 0; + static uint32_t last_nonce3 = 0; + static uint32_t last_workid = 0; + int i, j; + + h = 0; + pthread_mutex_lock(&nonce_mutex); + cg_rlock(&info->update_lock); + while(nonce_read_out.nonce_num>0) + { + uint32_t nonce3 = nonce_read_out.nonce_buffer[nonce_read_out.p_rd].nonce3; + uint32_t job_id = nonce_read_out.nonce_buffer[nonce_read_out.p_rd].job_id; + uint64_t nonce2 = nonce_read_out.nonce_buffer[nonce_read_out.p_rd].nonce2; + uint32_t chain_id = nonce_read_out.nonce_buffer[nonce_read_out.p_rd].chain_num; + uint32_t work_id = nonce_read_out.nonce_buffer[nonce_read_out.p_rd].work_id; + uint32_t version = Swap32(nonce_read_out.nonce_buffer[nonce_read_out.p_rd].header_version); + uint8_t midstate[32] = {0}; + int i = 0; + for(i=0; i<32; i++) + { + + midstate[(7-(i/4))*4 + (i%4)] = nonce_read_out.nonce_buffer[nonce_read_out.p_rd].midstate[i]; + } + applog(LOG_DEBUG,"%s: job_id:0x%x work_id:0x%x nonce2:0x%llx nonce3:0x%x version:0x%x\n", __FUNCTION__,job_id, work_id,nonce2, nonce3,version); + struct work * work; + + struct pool *pool, *c_pool; + struct pool *pool_stratum0 = &info->pool0; + struct pool *pool_stratum1 = &info->pool1; + struct pool *pool_stratum2 = &info->pool2; + + if(nonce_read_out.p_rd< MAX_NONCE_NUMBER_IN_FIFO-1) + { + nonce_read_out.p_rd++; + } + else + { + nonce_read_out.p_rd = 0; + } + + nonce_read_out.nonce_num--; + + if(nonce3 != last_nonce3 || work_id != last_workid ) + { + last_nonce3 = nonce3; + last_workid = work_id; + } + else + { + if(dev->chain_exist[chain_id] == 1) + { + inc_hw_errors(thr); + dev->chain_hw[chain_id]++; + } + continue; + } + + applog(LOG_DEBUG,"%s: Chain ID J%d ...\n", __FUNCTION__, chain_id + 1); + if( (given_id -2)> job_id && given_id < job_id) + { + applog(LOG_DEBUG,"%s: job_id error ...\n", __FUNCTION__); + if(dev->chain_exist[chain_id] == 1) + { + inc_hw_errors(thr); + dev->chain_hw[chain_id]++; + } + continue; + } + + applog(LOG_DEBUG,"%s: given_id:%d job_id:%d switch:%d ...\n", __FUNCTION__,given_id,job_id,given_id - job_id); + + switch (given_id - job_id) + { + case 0: + pool = pool_stratum0; + break; + case 1: + pool = pool_stratum1; + break; + case 2: + pool = pool_stratum2; + break; + default: + applog(LOG_DEBUG,"%s: job_id non't found ...\n", __FUNCTION__); + if(dev->chain_exist[chain_id] == 1) + { + inc_hw_errors(thr); + dev->chain_hw[chain_id]++; + } + continue; + } + c_pool = pools[pool->pool_no]; + get_work_by_nonce2(thr,&work,pool,c_pool,nonce2,pool->ntime,version); + h += hashtest_submit(thr,work,nonce3,midstate,pool,nonce2,chain_id); + free_work(work); + } + cg_runlock(&info->update_lock); + pthread_mutex_unlock(&nonce_mutex); + cgsleep_ms(1); + if(h != 0) + { + applog(LOG_DEBUG,"%s: hashes %u ...\n", __FUNCTION__,h * 0xffffffffull); + } + h = h * 0xffffffffull; + } + + static int64_t bitmain_soc_scanhash(struct thr_info *thr) + { + h = 0; + pthread_t send_id; + pthread_create(&send_id, NULL, bitmain_scanhash, thr); + pthread_join(send_id, NULL); + return h; + } + + static void bitmain_soc_update(struct cgpu_info *bitmain_soc) + { + struct bitmain_soc_info *info = bitmain_soc->device_data; + struct thr_info *thr = bitmain_soc->thr[0]; + struct work *work; + struct pool *pool; + int i, count = 0; + mutex_lock(&info->lock); + static char *last_job = NULL; + bool same_job = true; + unsigned char *buf = NULL; + thr->work_update = false; + thr->work_restart = false; + /* Step 1: Make sure pool is ready */ + work = get_work(thr, thr->id); + discard_work(work); /* Don't leak memory */ + /* Step 2: Protocol check */ + pool = current_pool(); + if (!pool->has_stratum) + quit(1, "Bitmain S9 has to use stratum pools"); + + /* Step 3: Parse job to c5 formart */ + cg_wlock(&info->update_lock); + cg_rlock(&pool->data_lock); + info->pool_no = pool->pool_no; + copy_pool_stratum(&info->pool2, &info->pool1); + info->pool2_given_id = info->pool1_given_id; + + copy_pool_stratum(&info->pool1, &info->pool0); + info->pool1_given_id = info->pool0_given_id; + + copy_pool_stratum(&info->pool0, pool); + info->pool0_given_id = ++given_id; + parse_job_to_soc(&buf, pool, info->pool0_given_id); + /* Step 4: Send out buf */ + if(!status_error) + { + pthread_mutex_lock(&reinit_mutex); + send_job(buf); + pthread_mutex_unlock(&reinit_mutex); + } + cg_runlock(&pool->data_lock); + cg_wunlock(&info->update_lock); + free(buf); + mutex_unlock(&info->lock); + } + + static void get_bitmain_statline_before(char *buf, size_t bufsiz, struct cgpu_info *bitmain_soc) + { + struct bitmain_soc_info *info = bitmain_soc->device_data; + } + + void remove_dot_char(char *number) + { + char tempStr[64]; + int i,j=0; + for(i=0; i3) + { + memcpy(tempStr,number,(unsigned int)pstr-(unsigned int)number-3); + tempStr[(unsigned int)pstr-(unsigned int)number-3]=','; + strcpy(tempStr+((unsigned int)pstr-(unsigned int)number-3+1),number+((unsigned int)pstr-(unsigned int)number-3)); + } + } + + strcpy(number,tempStr); + } + + + + static struct api_data *bitmain_api_stats(struct cgpu_info *cgpu) + { + struct api_data *root = NULL; + struct bitmain_soc_info *info = cgpu->device_data; + char buf[64]; + int i = 0; + uint64_t hash_rate_all = 0; + char displayed_rate_all[16]; + bool copy_data = true; + + root = api_add_uint8(root, "miner_count", &(dev->chain_num), copy_data); + root = api_add_string(root, "frequency", dev->frequency_t, copy_data); + root = api_add_uint8(root, "fan_num", &(dev->fan_num), copy_data); + + for(i = 0; i < BITMAIN_MAX_FAN_NUM; i++) + { + char fan_name[12]; + sprintf(fan_name,"fan%d", i+1); + root = api_add_uint(root, fan_name, &(dev->fan_speed_value[i]), copy_data); + } + root = api_add_uint8(root, "temp_num", &(dev->chain_num), copy_data); + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + char temp_name[12]; + sprintf(temp_name,"temp%d", i+1); + root = api_add_int16(root, temp_name, &(dev->chain_asic_maxtemp[i][TEMP_POS_LOCAL]), copy_data); + } + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + char temp2_name[12]; + sprintf(temp2_name,"temp2_%d", i+1); + root = api_add_int16(root, temp2_name, &(dev->chain_asic_temp[i][0][TEMP_POS_MIDDLE]), copy_data); + } + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + char temp3_name[12]; + sprintf(temp3_name,"temp3_%d", i+1); + root = api_add_int16(root, temp3_name, &(dev->chain_asic_temp[i][1][TEMP_POS_MIDDLE]), copy_data); + } + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + char freq_sum[12]; + int j = 0; + int temp; + double dev_sum_freq=0; + sprintf(freq_sum,"freq_avg%d",i+1); + + if(dev->chain_exist[i] == 1) + { +#ifdef T9_18 + if(getChainPICMagicNumber(i)== FREQ_MAGIC) + { + for(j = 0; j < dev->chain_asic_num[i]; j++) + { + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + dev_sum_freq += atoi(freq_pll_1385[chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]].freq); + } + else + { + dev_sum_freq += atoi(freq_pll_1385[chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]].freq); + } + } + + if(dev->chain_asic_num[i]>0) + dev_sum_freq=dev_sum_freq/dev->chain_asic_num[i]; + + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } + else + { + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } +#else + if(last_freq[i][1] == FREQ_MAGIC) + { + for(j = 0; j < dev->chain_asic_num[i]; j++) + { + dev_sum_freq += atoi(freq_pll_1385[last_freq[i][j*2+3]].freq); + } + + if(dev->chain_asic_num[i]>0) + dev_sum_freq=dev_sum_freq/dev->chain_asic_num[i]; + + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } + else + { + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } +#endif + } + else + { + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } + } + + if(1) + { + char freq_sum[32]; + int j = 0; + int temp; + double dev_sum_freq=0; + sprintf(freq_sum,"total_rateideal"); + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { +#ifdef T9_18 + if(getChainPICMagicNumber(i)== FREQ_MAGIC) + { + for(j = 0; j < dev->chain_asic_num[i]; j++) + { + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + dev_sum_freq += atoi(freq_pll_1385[chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]].freq)*(BM1387_CORE_NUM-chain_badcore_num[i][j]); + } + else + { + dev_sum_freq += atoi(freq_pll_1385[chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]].freq)*(BM1387_CORE_NUM-chain_badcore_num[i][j]); + } + } + } +#else + if(last_freq[i][1] == FREQ_MAGIC) + { + for(j = 0; j < dev->chain_asic_num[i]; j++) + { + dev_sum_freq += atoi(freq_pll_1385[last_freq[i][j*2+3]].freq)*(BM1387_CORE_NUM-chain_badcore_num[i][j]); + } + } +#endif + } + } + + dev_sum_freq=((dev_sum_freq*1.0)/1000); + + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } + + if(1) + { + char freq_sum[32]; + int j = 0; + int temp; + int total_acn_num=0; + double dev_sum_freq=0; + sprintf(freq_sum,"total_freqavg"); + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { +#ifdef T9_18 + if(getChainPICMagicNumber(i)== FREQ_MAGIC) + { + for(j = 0; j < dev->chain_asic_num[i]; j++) + { + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + dev_sum_freq += atoi(freq_pll_1385[chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]].freq); + } + else + { + dev_sum_freq += atoi(freq_pll_1385[chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]].freq); + } + total_acn_num++; + } + } +#else + if(last_freq[i][1] == FREQ_MAGIC) + { + for(j = 0; j < dev->chain_asic_num[i]; j++) + { + dev_sum_freq += atoi(freq_pll_1385[last_freq[i][j*2+3]].freq); + total_acn_num++; + } + } +#endif + } + } + dev_sum_freq=(dev_sum_freq*1.0/total_acn_num); + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } + + if(1) + { + char freq_sum[32]; + int16_t asic_num_total=0; + sprintf(freq_sum,"total_acn"); + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + asic_num_total+=dev->chain_asic_num[i]; + } + } + root = api_add_int16(root, freq_sum, &asic_num_total, true); + } + + if(1) + { + double total_rate=0; + char freq_sum[32]; + int temp; + + sprintf(freq_sum,"total_rate"); + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1 && strlen(displayed_rate[i])>0) + { + total_rate+=atof(displayed_rate[i]); + } + } + temp=(int)(total_rate*100); + total_rate=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &total_rate, true); + } + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + char freq_sum[32]; + int j = 0; + int temp; + double dev_sum_freq=0; + sprintf(freq_sum,"chain_rateideal%d",i+1); + + if(dev->chain_exist[i] == 1) + { +#ifdef T9_18 + if(getChainPICMagicNumber(i)== FREQ_MAGIC) + { + for(j = 0; j < dev->chain_asic_num[i]; j++) + { + if(fpga_version>=0xE) + { + int new_T9_PLUS_chainIndex,new_T9_PLUS_chainOffset; + getPICChainIndexOffset(i,&new_T9_PLUS_chainIndex,&new_T9_PLUS_chainOffset); + dev_sum_freq += atoi(freq_pll_1385[chain_pic_buf[new_T9_PLUS_chainIndex][7+new_T9_PLUS_chainOffset*31+4+j]].freq)*(BM1387_CORE_NUM-chain_badcore_num[i][j]); + } + else + { + dev_sum_freq += atoi(freq_pll_1385[chain_pic_buf[((i/3)*3)][7+(i%3)*31+4+j]].freq)*(BM1387_CORE_NUM-chain_badcore_num[i][j]); + } + } + + dev_sum_freq=((dev_sum_freq*1.0)/1000); + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } + else + { + dev_sum_freq=((dev_sum_freq*1.0)/1000); + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } +#else + if(last_freq[i][1] == FREQ_MAGIC) + { + for(j = 0; j < dev->chain_asic_num[i]; j++) + { + dev_sum_freq += atoi(freq_pll_1385[last_freq[i][j*2+3]].freq)*(BM1387_CORE_NUM-chain_badcore_num[i][j]); + } + + dev_sum_freq=((dev_sum_freq*1.0)/1000); + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } + else + { + dev_sum_freq=((dev_sum_freq*1.0)/1000); + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } +#endif + } + else + { + dev_sum_freq=((dev_sum_freq*1.0)/1000); + temp=(int)(dev_sum_freq*100); + dev_sum_freq=((temp*1.0)/100); + root = api_add_mhs(root, freq_sum, &dev_sum_freq, true); + } + } + + root = api_add_int(root, "temp_max", &(dev->temp_top1[PWM_T]), copy_data); + total_diff1 = total_diff_accepted + total_diff_rejected + total_diff_stale; + double dev_hwp = (hw_errors + total_diff1) ? + (double)(hw_errors) / (double)(hw_errors + total_diff1) : 0; + root = api_add_percent(root, "Device Hardware%", &(dev_hwp), true); + root = api_add_int(root, "no_matching_work", &hw_errors, copy_data); + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + char chain_name[12]; + sprintf(chain_name,"chain_acn%d",i+1); + root = api_add_uint8(root, chain_name, &(dev->chain_asic_num[i]), copy_data); + } + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + char chain_asic_name[12]; + sprintf(chain_asic_name,"chain_acs%d",i+1); + root = api_add_string(root, chain_asic_name, dev->chain_asic_status_string[i], copy_data); + } + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + char chain_hw[16]; + sprintf(chain_hw,"chain_hw%d",i+1); + root = api_add_uint32(root, chain_hw, &(dev->chain_hw[i]), copy_data); + } + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + char chain_rate[16]; + sprintf(chain_rate,"chain_rate%d",i+1); + + root = api_add_string(root, chain_rate, displayed_rate[i], copy_data); + } + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + bool first = true; + int j = 0; + char chain_xtime[16]; + char xtime[2048] = "{"; + char tmp[20] = ""; + + sprintf(chain_xtime,"chain_xtime%d",i+1); + + if(x_time[i][0] != 0) + { + sprintf(tmp,"X%d=%d",0,x_time[i][0]); + strcat(xtime,tmp); + first = false; + } + for (j = 1; j < dev->chain_asic_num[i]; j++) + { + if(x_time[i][j] != 0) + { + if (first) + { + sprintf(tmp,"X%d=%d",j,x_time[i][j]); + first = false; + } + else + { + sprintf(tmp,",X%d=%d",j,x_time[i][j]); + } + strcat(xtime,tmp); + } + } + strcat(xtime,"}"); + root = api_add_string(root, chain_xtime, xtime, copy_data); + } + } + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + int j = 0; + char chain_offside[20]; + char tmp[20]; + + sprintf(chain_offside,"chain_offside_%d",i+1); + sprintf(tmp,"%d",temp_offside[i]); + root = api_add_string(root, chain_offside, tmp, copy_data); + } + } + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + int j = 0; + char chain_opencore[20]; + char tmp[20]; + + sprintf(chain_opencore,"chain_opencore_%d",i+1); + + if(isChainAllCoresOpened[i]) + sprintf(tmp,"1"); + else sprintf(tmp,"0"); + root = api_add_string(root, chain_opencore, tmp, copy_data); + } + } + + for(i = 0; i < BITMAIN_MAX_CHAIN_NUM; i++) + { + if(dev->chain_exist[i] == 1) + { + hash_rate_all += rate[i]; + } + } + + suffix_string_soc(hash_rate_all, (char * )displayed_hash_rate, sizeof(displayed_hash_rate), 7,false); + + if(1) + { + char param_name[32]; + sprintf(param_name,"miner_version"); + root = api_add_string(root, param_name, g_miner_version, copy_data); + } + + return root; + } + + static void bitmain_soc_shutdown(struct thr_info *thr) + { + unsigned int ret; + thr_info_cancel(check_system_work_id); + thr_info_cancel(read_nonce_reg_id); + thr_info_cancel(read_temp_id); + thr_info_cancel(pic_heart_beat); + + ret = get_BC_write_command(); //disable null work + ret &= ~BC_COMMAND_EN_NULL_WORK; + set_BC_write_command(ret); + set_dhash_acc_control((unsigned int)get_dhash_acc_control() & ~RUN_BIT); + } + + + struct device_drv bitmain_soc_drv = + { + .drv_id = DRIVER_bitmain_soc, + .dname = "Bitmain_SOC", + .name = "BTM_SOC", + .drv_detect = bitmain_soc_detect, + .thread_prepare = bitmain_soc_prepare, + .hash_work = hash_driver_work, + .scanwork = bitmain_soc_scanhash, + .flush_work = bitmain_soc_update, + .update_work = bitmain_soc_update, + .get_api_stats = bitmain_api_stats, + .reinit_device = bitmain_soc_reinit_device, + .get_statline_before = get_bitmain_statline_before, + .thread_shutdown = bitmain_soc_shutdown, + }; + diff --git a/driver-btm-soc.h b/driver-btm-soc.h new file mode 100644 index 0000000000..e83fa083be --- /dev/null +++ b/driver-btm-soc.h @@ -0,0 +1,918 @@ +/* + * Copyright 2016-2017 Fazio Bai + * Copyright 2016-2017 Clement Duan + * + * 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 __DRIVER_BTM_SOC_H__ +#define __DRIVER_BTM_SOC_H__ + +#include "config.h" +//FPGA rgister Address Map +#define HARDWARE_VERSION (0x00000000/sizeof(int)) +#define FAN_SPEED (0x00000004/sizeof(int)) +#define HASH_ON_PLUG (0x00000008/sizeof(int)) +#define BUFFER_SPACE (0x0000000c/sizeof(int)) +#define RETURN_NONCE (0x00000010/sizeof(int)) +#define NONCE_NUMBER_IN_FIFO (0x00000018/sizeof(int)) +#define NONCE_FIFO_INTERRUPT (0x0000001c/sizeof(int)) +#define TEMPERATURE_0_3 (0x00000020/sizeof(int)) +#define TEMPERATURE_4_7 (0x00000024/sizeof(int)) +#define TEMPERATURE_8_11 (0x00000028/sizeof(int)) +#define TEMPERATURE_12_15 (0x0000002c/sizeof(int)) +#define IIC_COMMAND (0x00000030/sizeof(int)) +#define RESET_HASHBOARD_COMMAND (0x00000034/sizeof(int)) +#define BMC_CMD_COUNTER (0x00000038/sizeof(int)) +#define TW_WRITE_COMMAND (0x00000040/sizeof(int)) +#define QN_WRITE_DATA_COMMAND (0x00000080/sizeof(int)) +#define FAN_CONTROL (0x00000084/sizeof(int)) +#define TIME_OUT_CONTROL (0x00000088/sizeof(int)) +#define TICKET_MASK_FPGA (0x0000008c/sizeof(int)) +#define HASH_COUNTING_NUMBER_FPGA (0x00000090/sizeof(int)) +#define SNO (0x00000094/sizeof(int)) +#define BC_WRITE_COMMAND (0x000000c0/sizeof(int)) +#define BC_COMMAND_BUFFER (0x000000c4/sizeof(int)) +#define FPGA_CHIP_ID_ADDR (0x000000f0/sizeof(int)) +#define CRC_ERROR_CNT_ADDR (0x000000f8/sizeof(int)) +#define DHASH_ACC_CONTROL (0x00000100/sizeof(int)) +#define COINBASE_AND_NONCE2_LENGTH (0x00000104/sizeof(int)) +#define WORK_NONCE_2 (0x00000108/sizeof(int)) +#define NONCE2_AND_JOBID_STORE_ADDRESS (0x00000110/sizeof(int)) +#define MERKLE_BIN_NUMBER (0x00000114/sizeof(int)) +#define JOB_START_ADDRESS (0x00000118/sizeof(int)) +#define JOB_LENGTH (0x0000011c/sizeof(int)) +#define JOB_DATA_READY (0x00000120/sizeof(int)) +#define JOB_ID (0x00000124/sizeof(int)) +#define BLOCK_HEADER_VERSION (0x00000130/sizeof(int)) +#define TIME_STAMP (0x00000134/sizeof(int)) +#define TARGET_BITS (0x00000138/sizeof(int)) +#define PRE_HEADER_HASH (0x00000140/sizeof(int)) + +//FPGA registers bit map +//QN_WRITE_DATA_COMMAND +#define RESET_HASH_BOARD (1 << 31) +#define RESET_ALL (1 << 23) +#define CHAIN_ID(id) (id << 16) +#define RESET_FPGA (1 << 15) +#define RESET_TIME(time) (time << 0) +#define TIME_OUT_VALID (1 << 31) +//RETURN_NONCE +#define WORK_ID_OR_CRC (1 << 31) +#define WORK_ID_OR_CRC_VALUE(value) ((value >> 16) & 0x7fff) +#define NONCE_INDICATOR (1 << 7) +#define CHAIN_NUMBER(value) (value & 0xf) +#define REGISTER_DATA_CRC(value) ((value >> 24) & 0x7f) +//BC_WRITE_COMMAND +#define BC_COMMAND_BUFFER_READY (1 << 31) +#define BC_COMMAND_EN_CHAIN_ID (1 << 23) +#define BC_COMMAND_EN_NULL_WORK (1 << 22) +//NONCE2_AND_JOBID_STORE_ADDRESS +#define JOB_ID_OFFSET (0x0/sizeof(int)) +#define HEADER_VERSION_OFFSET (0x4/sizeof(int)) +#define NONCE2_L_OFFSET (0x8/sizeof(int)) +#define NONCE2_H_OFFSET (0xc/sizeof(int)) +#define MIDSTATE_OFFSET 0x20 +//DHASH_ACC_CONTROL +#define VIL_MODE (1 << 15) +#define VIL_MIDSTATE_NUMBER(value) ((value & 0x0f) << 8) +#define NEW_BLOCK (1 << 7) +#define RUN_BIT (1 << 6) +#define OPERATION_MODE (1 << 5) +//NONCE_FIFO_INTERRUPT +#define FLUSH_NONCE3_FIFO (1 << 16) + + +//ASIC macro define +//ASIC register address +#define SOC_VERSION 1 +#define CHIP_ADDRESS 0x0 +#define GOLDEN_NONCE_COUNTER 0x8 +#define PLL_PARAMETER 0xc +#define START_NONCE_OFFSET 0x10 +#define HASH_COUNTING_NUMBER 0x14 +#define TICKET_MASK 0x18 +#define MISC_CONTROL 0x1c +#define GENERAL_I2C_COMMAND 0X20 + +//ASIC command +#define SET_ADDRESS 0x1 +#define SET_PLL_DIVIDER2 0x2 +#define PATTERN_CONTROL 0x3 +#define GET_STATUS 0x4 +#define CHAIN_INACTIVE 0x5 +#define SET_BAUD_OPS 0x6 +#define SET_PLL_DIVIDER1 0x7 +#define SET_CONFIG 0x8 +#define COMMAND_FOR_ALL 0x80 +//other ASIC macro define +#define MAX_BAUD_DIVIDER 26 +#define DEFAULT_BAUD_DIVIDER 26 +#define VIL_COMMAND_TYPE (0x02 << 5) +#define VIL_ALL (0x01 << 4) +#define PAT (0x01 << 7) +#define GRAY (0x01 << 6) +#define INV_CLKO (0x01 << 5) +#define LPD (0x01 << 4) +#define GATEBCLK (0x01 << 7) +#define RFS (0x01 << 6) +#define MMEN (0x01 << 7) +#define TFS(x) ((x & 0x03) << 5) + + +// Pic +#define PIC_FLASH_POINTER_START_ADDRESS_H 0x03 +#define PIC_FLASH_POINTER_START_ADDRESS_L 0x00 +#define PIC_FLASH_POINTER_END_ADDRESS_H 0x0f +#define PIC_FLASH_POINTER_END_ADDRESS_L 0x7f +#define PIC_FLASH_LENGTH (((unsigned int)PIC_FLASH_POINTER_END_ADDRESS_H<<8 + PIC_FLASH_POINTER_END_ADDRESS_L) - ((unsigned int)PIC_FLASH_POINTER_START_ADDRESS_H<<8 + PIC_FLASH_POINTER_START_ADDRESS_L) + 1) +#define PIC_FLASH_SECTOR_LENGTH 32 +#define PIC_SOFTWARE_VERSION_LENGTH 1 +#define PIC_VOLTAGE_TIME_LENGTH 6 +#define PIC_COMMAND_1 0x55 +#define PIC_COMMAND_2 0xaa +#define SET_PIC_FLASH_POINTER 0x01 +#define SEND_DATA_TO_IIC 0x02 // just send data into pic's cache +#define READ_DATA_FROM_IIC 0x03 +#define ERASE_IIC_FLASH 0x04 // erase 32 bytes one time +#define WRITE_DATA_INTO_PIC 0x05 // tell pic write data into flash from cache +#define JUMP_FROM_LOADER_TO_APP 0x06 +#define RESET_PIC 0x07 +#define GET_PIC_FLASH_POINTER 0x08 +#define ERASE_PIC_APP_PROGRAM 0x09 +#define SET_VOLTAGE 0x10 +#define SET_VOLTAGE_TIME 0x11 +#define SET_HASH_BOARD_ID 0x12 +#define GET_HASH_BOARD_ID 0x13 +#define SET_HOST_MAC_ADDRESS 0x14 +#define ENABLE_VOLTAGE 0x15 +#define SEND_HEART_BEAT 0x16 +#define GET_PIC_SOFTWARE_VERSION 0x17 +#define GET_VOLTAGE 0x18 +#define GET_DATE 0x19 +#define GET_WHICH_MAC 0x20 +#define GET_MAC 0x21 +#define WR_TEMP_OFFSET_VALUE 0x22 +#define RD_TEMP_OFFSET_VALUE 0x23 + +//diff freq +#define PIC_FLASH_POINTER_FREQ_START_ADDRESS_H 0x0F +#define PIC_FLASH_POINTER_FREQ_START_ADDRESS_L 0xA0 +#define PIC_FLASH_POINTER_FREQ_END_ADDRESS_H 0x0f +#define PIC_FLASH_POINTER_FREQ_END_ADDRESS_L 0xDF +#define FREQ_MAGIC 0x7D + +// BAD CORE NUM +#define PIC_FLASH_POINTER_BADCORE_START_ADDRESS_H 0x0F +#define PIC_FLASH_POINTER_BADCORE_START_ADDRESS_L 0x80 +#define PIC_FLASH_POINTER_BADCORE_END_ADDRESS_H 0x0f +#define PIC_FLASH_POINTER_BADCORE_END_ADDRESS_L 0x9F +#define BADCORE_MAGIC 0x23 // magic number for bad core num + +#define HEART_BEAT_TIME_GAP 10 // 10s +#define IIC_READ (1 << 25) +#define IIC_WRITE (~IIC_READ) +#define IIC_REG_ADDR_VALID (1 << 24) +//#define IIC_ADDR_HIGH_4_BIT (0x0A << 20) +#define IIC_CHAIN_NUMBER(x) ((x & 0x0f) << 16) +#define IIC_REG_ADDR(x) ((x & 0xff) << 8) + +// AT24C02 +#define AT24C02_ADDRESS 0x50 +#define EEPROM_LENGTH 256 +#define HASH_ID_ADDR 0x80 +#define VOLTAGE_ADDR 0x90 +#define SENSOR_OFFSET_ADDR 0x98 +#define VOLTAGE_SET_TIME 0xA0 +#define VOLTAGE_SET_TIME 0xA0 +#define FREQ_BADCORE_ADDR 0x00 // 128 bytes 0 - 0x7F + +//other FPGA macro define +#define TOTAL_LEN 0x160 +#define FPGA_MEM_TOTAL_LEN (16*1024*1024) // 16M bytes +#define HARDWARE_VERSION_VALUE 0xC501 +#define NONCE2_AND_JOBID_STORE_SPACE (2*1024*1024) // 2M bytes +#define NONCE2_AND_JOBID_STORE_SPACE_ORDER 9 // for 2M bytes space +#define JOB_STORE_SPACE (1 << 16) // for 64K bytes space +#define JOB_START_SPACE (1024*8) // 8K bytes +#define JOB_START_ADDRESS_ALIGN 32 // JOB_START_ADDRESS need 32 bytes aligned +#define NONCE2_AND_JOBID_ALIGN 64 // NONCE2_AND_JOBID_STORE_SPACE need 64 bytes aligned +#define MAX_TIMEOUT_VALUE 0x1ffff // defined in TIME_OUT_CONTROL +#define MAX_NONCE_NUMBER_IN_FIFO 0x1ff // 511 nonce +#define NONCE_DATA_LENGTH 4 // 4 bytes +#define REGISTER_DATA_LENGTH 4 // 4 bytes +#define TW_WRITE_COMMAND_LEN 52 +#define TW_WRITE_COMMAND_LEN_VIL 52 +#define NEW_BLOCK_MARKER 0x11 +#define NORMAL_BLOCK_MARKER 0x01 + +// ATTENTION: if MEM size is changed, must change this micro definition too!!! use MAX size (BYTE) - 16 MB as FPGA start memory address +#define PHY_MEM_NONCE2_JOBID_ADDRESS_XILINX_1GB ((1024-16)*1024*1024) +#define PHY_MEM_NONCE2_JOBID_ADDRESS_XILINX_512MB ((512-16)*1024*1024) // XILINX use 512MB memory +#define PHY_MEM_NONCE2_JOBID_ADDRESS_XILINX_256MB ((256-16)*1024*1024) // XILINX use 256MB memory + +#define PHY_MEM_NONCE2_JOBID_ADDRESS_C5 ((1024-16)*1024*1024) +extern unsigned int PHY_MEM_NONCE2_JOBID_ADDRESS; + +#define PHY_MEM_JOB_START_ADDRESS_1 (PHY_MEM_NONCE2_JOBID_ADDRESS + NONCE2_AND_JOBID_STORE_SPACE) +#define PHY_MEM_JOB_START_ADDRESS_2 (PHY_MEM_JOB_START_ADDRESS_1 + JOB_STORE_SPACE) + +//#include "miner_type.h" // use setminertype to define miner type in this file instead of belows!!! +//#define R4 // if defined , for R4 63 chips +//#define S9_PLUS // if defined , for T9 57 chips +//#define S9_63 // if defined , for S9 63 chips +//#define T9_18 // if defined , for T9+ 18 chips + +#define RESET_KEEP_TIME 3 // keep reset signal for 1 secnods +#undef USE_OPENCORE_ONEBYONE // if defined, we will use open core one by one, do 114 times on open core for each chain! but NOT WORKS!?? +#undef ENABLE_REGISTER_CRC_CHECK //if defined, will drop the register buffer with crc error! +#define REBOOT_TEST_ONCE_1HOUR //if defined, will check hashrate after 1 hour, and reboot only once +#define ENABLE_FINAL_TEST_WITHOUT_REBOOT // when REBOOT_TEST_ONCE_1HOUR enabeld and this defined, the miner will not reboot after test for 1 hours, then we can save time. test system will treat these miners as good with green color. +#define DISABLE_FINAL_TEST //if defined, it will set rebootTestNum=0 and restartNum=2 to indicate the the miner fw is in normal user mode , not test mode +#define DISABLE_SHOWX_ENABLE_XTIMES // if defined, will disable x show on web UI, but will enable x times counter in 1 mins +#define FASTER_TESTPATTEN // will use 9% timeout to test patten +#undef USE_OPENCORE_TWICE +#define ENABLE_REINIT_WHEN_TESTFAILED //if defined, when test failed on patten, we set a flag in file, and will use highest voltage according to the limit rules of power and hashrate. +#define RESET_HASHBOARD_TIME 15 +#define ENABLE_CHECK_PIC_FLASH_ADDR // if enabled, will check PIC FLASH ADDR value , set and read back to compare from PIC +#define ENABLE_RESTORE_PIC_APP // if enabled, will restore PIC APP when the version is not correct!!! + +#ifdef R4 +#define USE_N_OFFSET_FIX_TEMP // if defined, we will use n and offset to fix temp value +#define EXTEND_TEMP_MODE // if defined, we set temp value area from -64 to 191 as extended temp +#define ENABLE_HIGH_VOLTAGE_OPENCORE + +#define PIC_VERSION 0x03 + +#define CHAIN_ASIC_NUM 63 + +#define R4_MAX_VOLTAGE_C5 890 +#define R4_MAX_VOLTAGE_XILINX 910 + +#define FIX_BAUD_VALUE 1 +#define UPRATE_PERCENT 1 // means we need reserved more 1% rate + +#define HIGHEST_VOLTAGE_LIMITED_HW 940 //measn the largest voltage, hw can support +#define USE_NEW_RESET_FPGA +#undef USE_PREINIT_OPENCORE // if defined, we will open core at first ,then get asicnum and do other init process +#endif + +#ifdef S9_PLUS +#define ENABLE_HIGH_VOLTAGE_OPENCORE + +#define S9_PLUS_VOLTAGE2 //if defined, then it support S9+ new board with new voltage controller + +#define PIC_VERSION 0x03 + +#define CHAIN_ASIC_NUM 57 +#define USE_N_OFFSET_FIX_TEMP // if defined, we will use n and offset to fix temp value +#define EXTEND_TEMP_MODE // if defined, we set temp value area from -64 to 191 as extended temp +#define HIGHEST_VOLTAGE_LIMITED_HW 970 //measn the largest voltage, hw can support +#define FIX_BAUD_VALUE 1 +#define UPRATE_PERCENT 2 // means we need reserved more 2% rate +#define USE_NEW_RESET_FPGA +#undef USE_PREINIT_OPENCORE // if defined, we will open core at first ,then get asicnum and do other init process +#endif + +#ifdef S9_63 +#define ENABLE_HIGH_VOLTAGE_OPENCORE + +#define PIC_VERSION 0x03 + +#define CHAIN_ASIC_NUM 63 +#define USE_N_OFFSET_FIX_TEMP // if defined, we will use n and offset to fix temp value +#define EXTEND_TEMP_MODE // if defined, we set temp value area from -64 to 191 as extended temp + +#define FIX_BAUD_VALUE 1 +#define UPRATE_PERCENT 1 // means we need reserved more 1% rate +#define HIGHEST_VOLTAGE_LIMITED_HW 940 //measn the largest voltage, hw can support +#define USE_NEW_RESET_FPGA +#undef USE_PREINIT_OPENCORE // if defined, we will open core at first ,then get asicnum and do other init process +#endif + +#ifdef T9_18 +#define ENABLE_HIGH_VOLTAGE_OPENCORE // T9+ use this , will cause error on chips, because the voltage changing need a long time to balance + +#define PIC_VERSION 0x03 + +#define CHAIN_ASIC_NUM 18 +#define USE_N_OFFSET_FIX_TEMP // if defined, we will use n and offset to fix temp value +#define EXTEND_TEMP_MODE // if defined, we set temp value area from -64 to 191 as extended temp + +#define FIX_BAUD_VALUE 1 +#define UPRATE_PERCENT 2 // means we need reserved more 2% rate +#define HIGHEST_VOLTAGE_LIMITED_HW 930 //measn the largest voltage, hw can support +#define USE_NEW_RESET_FPGA +#undef USE_PREINIT_OPENCORE // if defined, we will open core at first ,then get asicnum and do other init process +#endif + +#ifdef USE_PREINIT_OPENCORE +#define ENABLE_SET_TICKETMASK_BEFORE_TESTPATTEN // a bug, do not know reason: asic ticket mask > 0 even after reset asic!!! +#else +#undef ENABLE_SET_TICKETMASK_BEFORE_TESTPATTEN // a bug, do not know reason: asic ticket mask > 0 even after reset asic!!! +#endif + +#define ASIC_TYPE 1387 // 1385 or 1387 +#define CHIP_ADDR_INTERVAL 4 // fix chip address interval = 4 +#define DEFAULT_BAUD_VALUE 26 +#define ASIC_CORE_NUM 114 + +#define BM1387_CORE_NUM ASIC_CORE_NUM + +// macro define about miner +#define BITMAIN_MAX_CHAIN_NUM 16 +#define BITMAIN_MAX_FAN_NUM 8 // FPGA just can supports 8 fan +#define BITMAIN_DEFAULT_ASIC_NUM 64 // max support 64 ASIC on 1 HASH board +#define MIDSTATE_LEN 32 +#define DATA2_LEN 12 +#define MAX_RETURNED_NONCE_NUM 10 +#define PREV_HASH_LEN 32 +#define MERKLE_BIN_LEN 32 +#define INIT_CONFIG_TYPE 0x51 +#define STATUS_DATA_TYPE 0xa1 +#define SEND_JOB_TYPE 0x52 +#define READ_JOB_TYPE 0xa2 +#define CHECK_SYSTEM_TIME_GAP 10000 // 10s +//fan + +// BELOW IS ALL FOR DEBUG !!! normally all must be undefined!!! +#undef DEBUG_FORCE_REINIT //defined to force to reinit with higher voltage +#undef DEBUG_KEEP_USE_PIC_VOLTAGE_WITHOUT_CHECKING_VOLTAGE_OF_SEARCHFREQ // if defined, will read pic voltage at first , and use this voltage in mining as working voltage, ignore the backup voltage of search freq +#undef DEBUG_ENABLE_I2C_TIMEOUT_PROCESS // if defined, sw will process I2C timeout, but normally FPGA will process timeout, SW do not need this +#undef DEBUG_PRINT_T9_PLUS_PIC_HEART_INFO // if defined, used to debug T9+ bug: pic heart cmd failed! +#undef DEBUG_PIC_UPGRADE // if defined, we will force to write PIC program data once! +#undef DEBUG_KEEP_REBOOT_EVERY_ONE_HOUR // if defined, keep reboot every one hour!!! this is for R4 +#undef DEBUG_NOT_CHECK_FAN_NUM // if defined, we will ignore fan number checking, will keep run even without any fan!!! +#undef DEBUG_WITHOUT_FREQ_VOLTAGE_LIMIT // if defined, we will not limit freq according to voltage! + +#undef DEBUG_DOWN_VOLTAGE_TEST +#ifdef DEBUG_DOWN_VOLTAGE_TEST +#define DEBUG_DOWN_VOLTAGE_VALUE 10 // means down 0.1 V +#endif + +#undef DEBUG_XILINX_NONCE_NOTENOUGH // will disable mutex lock on read temp and send work, but will disable one chain's read temp +#ifdef DEBUG_XILINX_NONCE_NOTENOUGH +#define DISABLE_REG_CHAIN_INDEX 5 //disable which chain's read register +#endif + +#undef DEBUG_OPENCORE_TWICE +#undef ENABLE_REINIT_MINING // if defined, will enable hashrate check in mining, and re-init if low hashrate. +#undef DEBUG_REINIT // reinit per 2mins and will not do pre heat patten test +#undef DEBUG_REBOOT // reboot every 30mins, for test +#undef DEBUG_218_FAN_FULLSPEED //for debug on 218, full speed on fan +#undef DISABLE_TEMP_PROTECT +#undef TWO_CHIP_TEMP_S9 +#undef SHOW_BOTTOM_TEMP +#undef KEEP_TEMPFAN_LOG // if defined, will not clear old temp fan log info +#undef HIGH_TEMP_TEST_S9 //if defined, will use 120 degree as the high temp +#undef CAPTURE_PATTEN + +#define CHECK_RT_IDEAL_RATE_PERCENT 85 // RT rate / ideal rate >= 85% will be OK, or need re init + +typedef enum +{ + TEMP_POS_LOCAL=0, + TEMP_POS_MIDDLE, + TEMP_POS_BOTTOM, + TEMP_POS_NUM=4, // always the last one, to identify the number of temp , must 4 bytes alignment +} TEMP_POSITION; + +#ifdef R4 +#define PWM_T 0 // 0 local temp, 1 middle temp, 2 bottom, as above!!! + +#define MIN_FAN_NUM 1 +#define MAX_FAN_SPEED 3000 +#define TEMP_INTERVAL 2 + +// below are used for R4 on using one app to support C5 and XILINX board +extern int MIN_PWM_PERCENT; +extern int MID_PWM_PERCENT; +extern int MAX_PWM_PERCENT; +extern int MAX_TEMP; +extern int MAX_FAN_TEMP; +extern int MID_FAN_TEMP; +extern int MIN_FAN_TEMP; +extern int MAX_PCB_TEMP; +extern int MAX_FAN_PCB_TEMP; + +#if PWM_T == 1 +#define MIN_PWM_PERCENT_C5 20 +#define MID_PWM_PERCENT_C5 60 +#define MAX_PWM_PERCENT_C5 100 +#define MAX_TEMP_C5 125 +#define MAX_FAN_TEMP_C5 110 +#define MID_FAN_TEMP_C5 90 +#define MIN_FAN_TEMP_C5 60 +#define MAX_PCB_TEMP_C5 100 // use middle to control fan, but use pcb temp to check to stop or not! +#define MAX_FAN_PCB_TEMP_C5 85 //90 use middle to control fan, but use pcb temp to check to stop or not! + +#define MIN_PWM_PERCENT_XILINX 20 +#define MID_PWM_PERCENT_XILINX 60 +#define MAX_PWM_PERCENT_XILINX 100 +#define MAX_TEMP_XILINX 125 +#define MAX_FAN_TEMP_XILINX 110 +#define MID_FAN_TEMP_XILINX 90 +#define MIN_FAN_TEMP_XILINX 60 +#define MAX_PCB_TEMP_XILINX 100 // use middle to control fan, but use pcb temp to check to stop or not! +#define MAX_FAN_PCB_TEMP_XILINX 85 //90 use middle to control fan, but use pcb temp to check to stop or not! +#else +#define MIN_PWM_PERCENT_C5 50 +#define MID_PWM_PERCENT_C5 90 +#define MAX_PWM_PERCENT_C5 100 +#define MAX_TEMP_C5 90 +#define MAX_FAN_TEMP_C5 75 +#define MID_FAN_TEMP_C5 65 +#define MIN_FAN_TEMP_C5 25 +#define MAX_PCB_TEMP_C5 90 // use middle to control fan, but use pcb temp to check to stop or not! +#define MAX_FAN_PCB_TEMP_C5 85 //90 use middle to control fan, but use pcb temp to check to stop or not! + +#define MIN_PWM_PERCENT_XILINX 30 +#define MID_PWM_PERCENT_XILINX 70 +#define MAX_PWM_PERCENT_XILINX 100 +#define MAX_TEMP_XILINX 90 +#define MAX_FAN_TEMP_XILINX 75 +#define MID_FAN_TEMP_XILINX 65 +#define MIN_FAN_TEMP_XILINX 25 +#define MAX_PCB_TEMP_XILINX 90 // use middle to control fan, but use pcb temp to check to stop or not! +#define MAX_FAN_PCB_TEMP_XILINX 85 //90 use middle to control fan, but use pcb temp to check to stop or not! +#endif + +#define TEMP_INTERVAL 2 + +#define MID_PWM_ADJUST_FACTOR ((MAX_PWM_PERCENT-MID_PWM_PERCENT)/(MAX_FAN_TEMP-MID_FAN_TEMP)) +#define PWM_ADJUST_FACTOR ((MID_PWM_PERCENT-MIN_PWM_PERCENT)/(MID_FAN_TEMP-MIN_FAN_TEMP)) +#else +// below is for S9 +#define PWM_T 1 // 0 local temp, 1 middle temp, 2 bottom, as above!!! + +#define MIN_FAN_NUM 2 +#define MAX_FAN_SPEED 6000 +#if PWM_T == 1 +#define MIN_PWM_PERCENT 0 +#define MAX_PWM_PERCENT 100 + +#ifdef HIGH_TEMP_TEST_S9 +#define MAX_TEMP 135 //125 135 145 release:135 +#define MAX_FAN_TEMP 120 // 115 125 135 release:120 +#define MIN_FAN_TEMP 70 //65 75 85 release:70 +#define MAX_PCB_TEMP 105 //100 105 110 release:105 +#define MAX_FAN_PCB_TEMP 95 //95 100 105 release:95 +#define MIN_FAN_PCB_TEMP 45 // Attention: MAX_FAN_PCB_TEMP - MIN_FAN_PCB_TEMP = MAX_FAN_TEMP - MIN_FAN_TEMP +#else +#ifdef TWO_CHIP_TEMP_S9 +#define MAX_TEMP 135 //125 135 145 release:135 +#define MAX_FAN_TEMP 120 // 115 125 135 release:120 +#define MIN_FAN_TEMP 70 //65 75 85 release:70 +#define MAX_PCB_TEMP 105 //100 105 110 release:105 +#define MAX_FAN_PCB_TEMP 95 //95 100 105 release:95 +#define MIN_FAN_PCB_TEMP 45 // Attention: MAX_FAN_PCB_TEMP - MIN_FAN_PCB_TEMP = MAX_FAN_TEMP - MIN_FAN_TEMP +#else +#define MAX_TEMP 125 //125 135 145 release:125 +#define MAX_FAN_TEMP 90 // 115 125 135 release:115 +#define MIN_FAN_TEMP 40 //65 75 85 release:65 +#define MAX_PCB_TEMP 90 //100 105 110 release:95 +#define MAX_FAN_PCB_TEMP 75 //95 100 105 release:85 +#define MIN_FAN_PCB_TEMP 25 // Attention: MAX_FAN_PCB_TEMP - MIN_FAN_PCB_TEMP = MAX_FAN_TEMP - MIN_FAN_TEMP +#endif +#endif +#else +#define MIN_PWM_PERCENT 20 +#define MAX_PWM_PERCENT 100 +#define MAX_TEMP 90 +#define MAX_FAN_TEMP 75 +#define MIN_FAN_TEMP 35 +#define MAX_PCB_TEMP 90 // use middle to control fan, but use pcb temp to check to stop or not! +#endif +#define TEMP_INTERVAL 2 +#define PWM_ADJUST_FACTOR ((MAX_PWM_PERCENT-MIN_PWM_PERCENT)/(MAX_FAN_TEMP-MIN_FAN_TEMP)) +#endif + +#ifdef HIGH_TEMP_TEST_S9 +#define MIN_TEMP_CONTINUE_DOWN_FAN 110 // release: 90 +#define MAX_TEMP_NEED_UP_FANSTEP 120 // release: 100 if temp is higher than 100, then we need make fan much faster +#else +#define MIN_TEMP_CONTINUE_DOWN_FAN 80 // release: 90 +#define MAX_TEMP_NEED_UP_FANSTEP 85 // release: 100 if temp is higher than 100, then we need make fan much faster +#endif + +#define PWM_SCALE 50 //50: 1M=1us, 20KHz?? +//25: 40KHz + +#define PWM_ADJ_SCALE 9/10 +//use for hash test +#define TEST_DHASH 0 +#define DEVICE_DIFF 8 +//use for status check + +#define MAX_TEMPCHIP_NUM 8 // support 8 chip has temp + +#define MIN_FREQ 4 // 8:300M 6:250M 4:200M +#define MAX_FREQ 100 //850M +#define MAX_SW_TEMP_OFFSET -15 +#define BMMINER_VERSION 3 // 3 for auto freq, 1 or 2 for normal ( the old version is 0) + +// for c5, bmminer will detect board type and use it. +#define RED_LED_DEV_C5 "/sys/class/leds/hps_led2/brightness" +#define GREEN_LED_DEV_C5 "/sys/class/leds/hps_led0/brightness" + +// for xilinx, bmminer will detect board type and use it. +#define RED_LED_DEV_XILINX "/sys/class/gpio/gpio943/value" +#define GREEN_LED_DEV_XILINX "/sys/class/gpio/gpio944/value" + +// S9 , T9, R4 PIC PROGRAM +#define PIC_PROGRAM "/etc/config/hash_s8_app.txt" + +// T9+ PIC PROGRAM +#define DSPIC33EP16GS202_PIC_PROGRAM "/etc/config/dsPIC33EP16GS202_app.txt" + + +#define TIMESLICE 60 + +#ifdef T9_18 +#define IIC_ADDR_HIGH_4_BIT (0x04 << 20) +#define EEPROM_ADDR_HIGH_4_BIT (0x0A << 20) +#define IIC_SELECT(x) ((x & 0x03) << 26) + +unsigned int get_iic(); +unsigned char set_iic(unsigned int data); +unsigned char T9_plus_write_pic_iic(bool read, bool reg_addr_valid, unsigned char reg_addr, unsigned char which_iic, unsigned char data); +int dsPIC33EP16GS202_jump_to_app_from_loader(unsigned char which_iic); +#else +#define IIC_ADDR_HIGH_4_BIT (0x0A << 20) +#endif + + +struct init_config +{ + uint8_t token_type; + uint8_t version; + uint16_t length; + uint8_t reset :1; + uint8_t fan_eft :1; + uint8_t timeout_eft :1; + uint8_t frequency_eft :1; + uint8_t voltage_eft :1; + uint8_t chain_check_time_eft :1; + uint8_t chip_config_eft :1; + uint8_t hw_error_eft :1; + uint8_t beeper_ctrl :1; + uint8_t temp_ctrl :1; + uint8_t chain_freq_eft :1; + uint8_t reserved1 :5; + uint8_t reserved2[2]; + uint8_t chain_num; + uint8_t asic_num; + uint8_t fan_pwm_percent; + uint8_t temperature; + uint16_t frequency; + uint8_t voltage[2]; + uint8_t chain_check_time_integer; + uint8_t chain_check_time_fractions; + uint8_t timeout_data_integer; + uint8_t timeout_data_fractions; + uint32_t reg_data; + uint8_t chip_address; + uint8_t reg_address; + uint16_t chain_min_freq; + uint16_t chain_max_freq; + uint16_t crc; +} __attribute__((packed, aligned(4))); + + + +struct bitmain_soc_info +{ + cglock_t update_lock; + + uint8_t data_type; + uint8_t version; + uint16_t length; + uint8_t chip_value_eft :1; + uint8_t reserved1 :7; + uint8_t chain_num; + uint16_t reserved2; + uint8_t fan_num; + uint8_t temp_num; + uint8_t reserved3[2]; + uint32_t fan_exist; + uint32_t temp_exist; + uint16_t diff; + uint16_t reserved4; + uint32_t reg_value; + uint32_t chain_asic_exist[BITMAIN_MAX_CHAIN_NUM][BITMAIN_DEFAULT_ASIC_NUM/32]; + uint32_t chain_asic_status[BITMAIN_MAX_CHAIN_NUM][BITMAIN_DEFAULT_ASIC_NUM/32]; + uint8_t chain_asic_num[BITMAIN_MAX_CHAIN_NUM]; + uint8_t temp[BITMAIN_MAX_CHAIN_NUM]; + uint8_t fan_speed_value[BITMAIN_MAX_FAN_NUM]; + uint16_t freq[BITMAIN_MAX_CHAIN_NUM]; + struct thr_info *thr; + pthread_t read_nonce_thr; + pthread_mutex_t lock; + + struct init_config soc_config; + int pool_no; + struct pool pool0; + struct pool pool1; + struct pool pool2; + uint32_t pool0_given_id; + uint32_t pool1_given_id; + uint32_t pool2_given_id; + + uint16_t crc; +} __attribute__((packed, aligned(4))); + +struct part_of_job +{ + uint8_t token_type; // buf[0] + uint8_t version; + uint16_t reserved; + uint32_t length; // buf[1] + uint8_t pool_nu; // buf[2] + uint8_t new_block :1; + uint8_t asic_diff_valid :1; + uint8_t reserved1 :6; + uint8_t asic_diff; + uint8_t reserved2[1]; + uint32_t job_id; // buf[3] + uint32_t bbversion; // buf[4] + uint8_t prev_hash[32]; // buf[5] - buf[12] + uint32_t ntime; // buf[13] + uint32_t nbit; // buf[14] + uint16_t coinbase_len; // buf[15] + uint16_t nonce2_offset; + uint16_t nonce2_bytes_num; // 4 or 8 bytes // buf[16] + uint16_t merkles_num; + uint64_t nonce2_start_value; //nonce2 start calculate value. // buf[17] - buf[18] +}; +//uint8_t coinbase //this is variable +//uint8_t merkle_bin[32] * merkles_num +//uint16_t crc + +struct nonce_content +{ + uint32_t job_id; + uint32_t work_id; + uint32_t header_version; + uint64_t nonce2; + uint32_t nonce3; + uint32_t chain_num; + uint8_t midstate[MIDSTATE_LEN]; +} __attribute__((packed, aligned(4))); + +struct nonce +{ + uint8_t token_type; + uint8_t version; + uint16_t length; + uint16_t valid_nonce_num; + struct nonce_content nonce_cont[MAX_RETURNED_NONCE_NUM]; + uint16_t crc; +} __attribute__((packed, aligned(4))); + +struct all_parameters +{ + + unsigned int *current_job_start_address; + unsigned int pwm_value; + unsigned int chain_exist[BITMAIN_MAX_CHAIN_NUM]; + unsigned int timeout; + unsigned int fan_exist_map; + unsigned int temp_sensor_map; + unsigned int nonce_error; + unsigned int chain_asic_exist[BITMAIN_MAX_CHAIN_NUM][8]; + unsigned int chain_asic_status[BITMAIN_MAX_CHAIN_NUM][8]; + signed char chain_asic_temp_num[BITMAIN_MAX_CHAIN_NUM]; // the real number of temp chip + unsigned char TempChipType[BITMAIN_MAX_CHAIN_NUM][MAX_TEMPCHIP_NUM]; + unsigned char TempChipAddr[BITMAIN_MAX_CHAIN_NUM][MAX_TEMPCHIP_NUM]; // each temp chip's address: chip index*4, index start from 0 + int16_t chain_asic_temp[BITMAIN_MAX_CHAIN_NUM][MAX_TEMPCHIP_NUM][TEMP_POS_NUM]; // 4 kinds of temp + int16_t chain_asic_maxtemp[BITMAIN_MAX_CHAIN_NUM][TEMP_POS_NUM]; // 4 kinds of temp + int16_t chain_asic_mintemp[BITMAIN_MAX_CHAIN_NUM][TEMP_POS_NUM]; // 4 kinds of temp + int8_t chain_asic_iic[CHAIN_ASIC_NUM]; + uint32_t chain_hw[BITMAIN_MAX_CHAIN_NUM]; + uint64_t chain_asic_nonce[BITMAIN_MAX_CHAIN_NUM][BITMAIN_DEFAULT_ASIC_NUM]; + char chain_asic_status_string[BITMAIN_MAX_CHAIN_NUM][BITMAIN_DEFAULT_ASIC_NUM+8]; + + unsigned long long int total_nonce_num; + + unsigned char fan_exist[BITMAIN_MAX_FAN_NUM]; + unsigned int fan_speed_value[BITMAIN_MAX_FAN_NUM]; + int temp[BITMAIN_MAX_CHAIN_NUM]; + uint8_t chain_asic_num[BITMAIN_MAX_CHAIN_NUM]; + unsigned char check_bit; + unsigned char pwm_percent; + unsigned char chain_num; + unsigned char fan_num; + unsigned char temp_num; + unsigned int fan_speed_top1; + int temp_top1[TEMP_POS_NUM]; + int temp_low1[TEMP_POS_NUM]; + int temp_top1_last; + unsigned char corenum; + unsigned char addrInterval; + unsigned char max_asic_num_in_one_chain; + unsigned char baud; + unsigned char diff; + uint8_t fan_eft; + uint8_t fan_pwm; + + unsigned short int frequency; + char frequency_t[10]; + unsigned short int freq[BITMAIN_MAX_CHAIN_NUM]; +} __attribute__((packed, aligned(4))); + + + +struct nonce_buf +{ + unsigned int p_wr; + unsigned int p_rd; + unsigned int nonce_num; + struct nonce_content nonce_buffer[MAX_NONCE_NUMBER_IN_FIFO]; +} __attribute__((packed, aligned(4))); + +struct reg_content +{ + unsigned int reg_value; + unsigned char crc; + unsigned char chain_number; +} __attribute__((packed, aligned(4))); + +struct reg_buf +{ + unsigned int p_wr; + unsigned int p_rd; + unsigned int reg_value_num; + struct reg_content reg_buffer[MAX_NONCE_NUMBER_IN_FIFO]; +} __attribute__((packed, aligned(4))); + +struct freq_pll +{ + const char *freq; + unsigned int fildiv1; + unsigned int fildiv2; + unsigned int vilpll; +}; + +#define Swap32(l) (((l) >> 24) | (((l) & 0x00ff0000) >> 8) | (((l) & 0x0000ff00) << 8) | ((l) << 24)) + + +struct vil_work +{ + uint8_t type; // Bit[7:5]: Type,fixed 0x01. Bit[4:0]:Reserved + uint8_t length; // data length, from Byte0 to the end. + uint8_t wc_base; // Bit[7]: Reserved. Bit[6:0]: Work count base, muti-Midstate, each Midstate corresponding work count increase one by one. + uint8_t mid_num; // Bit[7:3]: Reserved Bit[2:0]: MSN, midstate num,now support 1,2,4. + //uint32_t sno; // SPAT mode??Start Nonce Number Normal mode??Reserved. + uint8_t midstate[32]; + uint8_t data2[12]; +}; + +struct vil_work_1387 +{ + uint8_t work_type; + uint8_t chain_id; + uint8_t reserved1[2]; + uint32_t work_count; + uint8_t data[12]; + uint8_t midstate[32]; +}; + + +static struct freq_pll freq_pll_1385[] = +{ + {"100",0x020040, 0x0420, 0x200241}, + {"125",0x028040, 0x0420, 0x280241}, + {"150",0x030040, 0x0420, 0x300241}, + {"175",0x038040, 0x0420, 0x380241}, + {"200",0x040040, 0x0420, 0x400241}, + {"225",0x048040, 0x0420, 0x480241}, + {"250",0x050040, 0x0420, 0x500241}, + {"275",0x058040, 0x0420, 0x580241}, + {"300",0x060040, 0x0420, 0x600241}, + {"325",0x068040, 0x0420, 0x680241}, + {"350",0x070040, 0x0420, 0x700241}, + {"375",0x078040, 0x0420, 0x780241}, + {"400",0x080040, 0x0420, 0x800241}, + {"404",0x061040, 0x0320, 0x610231}, + {"406",0x041040, 0x0220, 0x410221}, + {"408",0x062040, 0x0320, 0x620231}, + {"412",0x042040, 0x0220, 0x420221}, + {"416",0x064040, 0x0320, 0x640231}, + {"418",0x043040, 0x0220, 0x430221}, + {"420",0x065040, 0x0320, 0x650231}, + {"425",0x044040, 0x0220, 0x440221}, + {"429",0x067040, 0x0320, 0x670231}, + {"431",0x045040, 0x0220, 0x450221}, + {"433",0x068040, 0x0320, 0x680231}, + {"437",0x046040, 0x0220, 0x460221}, + {"441",0x06a040, 0x0320, 0x6a0231}, + {"443",0x047040, 0x0220, 0x470221}, + {"445",0x06b040, 0x0320, 0x6b0231}, + {"450",0x048040, 0x0220, 0x480221}, + {"454",0x06d040, 0x0320, 0x6d0231}, + {"456",0x049040, 0x0220, 0x490221}, + {"458",0x06e040, 0x0320, 0x6e0231}, + {"462",0x04a040, 0x0220, 0x4a0221}, + {"466",0x070040, 0x0320, 0x700231}, + {"468",0x04b040, 0x0220, 0x4b0221}, + {"470",0x071040, 0x0320, 0x710231}, + {"475",0x04c040, 0x0220, 0x4c0221}, + {"479",0x073040, 0x0320, 0x730231}, + {"481",0x04d040, 0x0220, 0x4d0221}, + {"483",0x074040, 0x0320, 0x740231}, + {"487",0x04e040, 0x0220, 0x4e0221}, + {"491",0x076040, 0x0320, 0x760231}, + {"493",0x04f040, 0x0220, 0x4f0221}, + {"495",0x077040, 0x0320, 0x770231}, + {"500",0x050040, 0x0220, 0x500221}, + {"504",0x079040, 0x0320, 0x790231}, + {"506",0x051040, 0x0220, 0x510221}, + {"508",0x07a040, 0x0320, 0x7a0231}, + {"512",0x052040, 0x0220, 0x520221}, + {"516",0x07c040, 0x0320, 0x7c0231}, + {"518",0x053040, 0x0220, 0x530221}, + {"520",0x07d040, 0x0320, 0x7d0231}, + {"525",0x054040, 0x0220, 0x540221}, + {"529",0x07f040, 0x0320, 0x7f0231}, + {"531",0x055040, 0x0220, 0x550221}, + {"533",0x080040, 0x0320, 0x800231}, + {"537",0x056040, 0x0220, 0x560221}, + {"543",0x057040, 0x0220, 0x570221}, + {"550",0x058040, 0x0220, 0x580221}, + {"556",0x059040, 0x0220, 0x590221}, + {"562",0x05a040, 0x0220, 0x5a0221}, + {"568",0x05b040, 0x0220, 0x5b0221}, + {"575",0x05c040, 0x0220, 0x5c0221}, + {"581",0x05d040, 0x0220, 0x5d0221}, + {"587",0x05e040, 0x0220, 0x5e0221}, + {"593",0x05f040, 0x0220, 0x5f0221}, + {"600",0x060040, 0x0220, 0x600221}, + {"606",0x061040, 0x0220, 0x610221}, + {"612",0x062040, 0x0220, 0x620221}, + {"618",0x063040, 0x0220, 0x630221}, + {"625",0x064040, 0x0220, 0x640221}, + {"631",0x065040, 0x0220, 0x650221}, + {"637",0x066040, 0x0220, 0x660221}, + {"643",0x067040, 0x0220, 0x670221}, + {"650",0x068040, 0x0220, 0x680221}, + {"656",0x069040, 0x0220, 0x690221}, + {"662",0x06a040, 0x0220, 0x6a0221}, + {"668",0x06b040, 0x0220, 0x6b0221}, + {"675",0x06c040, 0x0220, 0x6c0221}, + {"681",0x06d040, 0x0220, 0x6d0221}, + {"687",0x06e040, 0x0220, 0x6e0221}, + {"693",0x06f040, 0x0220, 0x6f0221}, + {"700",0x070040, 0x0220, 0x700221}, + {"706",0x071040, 0x0220, 0x710221}, + {"712",0x072040, 0x0220, 0x720221}, + {"718",0x073040, 0x0220, 0x730221}, + {"725",0x074040, 0x0220, 0x740221}, + {"731",0x075040, 0x0220, 0x750221}, + {"737",0x076040, 0x0220, 0x760221}, + {"743",0x077040, 0x0220, 0x770221}, + {"750",0x078040, 0x0220, 0x780221}, + {"756",0x079040, 0x0220, 0x790221}, + {"762",0x07a040, 0x0220, 0x7a0221}, + {"768",0x07b040, 0x0220, 0x7b0221}, + {"775",0x07c040, 0x0220, 0x7c0221}, + {"781",0x07d040, 0x0220, 0x7d0221}, + {"787",0x07e040, 0x0220, 0x7e0221}, + {"793",0x07f040, 0x0220, 0x7f0221}, + {"800",0x080040, 0x0220, 0x800221}, + {"825",0x042040, 0x0120, 0x420211}, + {"850",0x044040, 0x0120, 0x440211}, + {"875",0x046040, 0x0120, 0x460211}, + {"900",0x048040, 0x0120, 0x480211}, + {"925",0x04a040, 0x0120, 0x4a0211}, + {"950",0x04c040, 0x0120, 0x4c0211}, + {"975",0x04e040, 0x0120, 0x4e0211}, + {"1000",0x050040, 0x0120, 0x500211}, + {"1025",0x052040, 0x0120, 0x520211}, + {"1050",0x054040, 0x0120, 0x540211}, + {"1075",0x056040, 0x0120, 0x560211}, + {"1100",0x058040, 0x0120, 0x580211}, + {"1125",0x05a040, 0x0120, 0x5a0211}, + {"1150",0x05c040, 0x0120, 0x5c0211}, + {"1175",0x05e040, 0x0120, 0x5e0211}, +}; + +extern bool opt_bitmain_fan_ctrl; +extern bool opt_bitmain_new_cmd_type_vil; +extern bool opt_fixed_freq; +extern bool opt_pre_heat; +extern int opt_bitmain_fan_pwm; +extern int opt_bitmain_soc_freq; +extern int opt_bitmain_soc_voltage; +extern int ADD_FREQ; +extern int ADD_FREQ1; +extern int fpga_version; +extern int opt_multi_version; + + + + +#endif + diff --git a/miner.h b/miner.h index fc93f54618..c6c14f7fbd 100644 --- a/miner.h +++ b/miner.h @@ -266,7 +266,8 @@ static inline int fsync (int fd) DRIVER_ADD_COMMAND(knc) \ DRIVER_ADD_COMMAND(minion) \ DRIVER_ADD_COMMAND(sp10) \ - DRIVER_ADD_COMMAND(sp30) + DRIVER_ADD_COMMAND(sp30) \ + DRIVER_ADD_COMMAND(bitmain_soc) #define DRIVER_PARSE_COMMANDS(DRIVER_ADD_COMMAND) \ FPGA_PARSE_COMMANDS(DRIVER_ADD_COMMAND) \ @@ -1215,6 +1216,22 @@ extern uint64_t best_diff; extern struct timeval block_timeval; extern char *workpadding; +#ifdef USE_BITMAIN_SOC +extern char displayed_hash_rate[16]; +#define NONCE_BUFF 4096 +extern char nonce_num10_string[NONCE_BUFF]; +extern char nonce_num30_string[NONCE_BUFF]; +extern char nonce_num60_string[NONCE_BUFF]; +extern char g_miner_version[256]; +extern char g_miner_compiletime[256]; +extern char g_miner_type[256]; +extern double new_total_mhashes_done; +extern double new_total_secs; +extern time_t total_tv_start_sys; +extern time_t total_tv_end_sys; +extern void writeInitLogFile(char *logstr); +#endif + struct curl_ent { CURL *curl; struct list_head node; @@ -1387,6 +1404,11 @@ struct pool { uint32_t current_height; struct timeval tv_lastwork; +#ifdef USE_BITMAIN_SOC + bool support_vil; + int version_num; + int version[4]; +#endif }; #define GETWORK_MODE_TESTPOOL 'T' @@ -1464,6 +1486,9 @@ struct work { struct timeval tv_work_start; struct timeval tv_work_found; char getwork_mode; +#ifdef USE_BITMAIN_SOC + int version; +#endif }; #ifdef USE_MODMINER diff --git a/sha2-soc.c b/sha2-soc.c new file mode 100644 index 0000000000..c461b7b60a --- /dev/null +++ b/sha2-soc.c @@ -0,0 +1,310 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2011, Con Kolivas + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#include +#include "sha2-soc.h" + +extern void dump_hex(uint8_t *data, uint16_t len); +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_ULONG_BE +#define GET_ULONG_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_ULONG_BE +#define PUT_ULONG_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * SHA-256 context setup + */ +void sha2_starts( sha2_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +void sha2_process( sha2_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A, B, C, D, E, F, G, H; + + GET_ULONG_BE( W[ 0], data, 0 ); + GET_ULONG_BE( W[ 1], data, 4 ); + GET_ULONG_BE( W[ 2], data, 8 ); + GET_ULONG_BE( W[ 3], data, 12 ); + GET_ULONG_BE( W[ 4], data, 16 ); + GET_ULONG_BE( W[ 5], data, 20 ); + GET_ULONG_BE( W[ 6], data, 24 ); + GET_ULONG_BE( W[ 7], data, 28 ); + GET_ULONG_BE( W[ 8], data, 32 ); + GET_ULONG_BE( W[ 9], data, 36 ); + GET_ULONG_BE( W[10], data, 40 ); + GET_ULONG_BE( W[11], data, 44 ); + GET_ULONG_BE( W[12], data, 48 ); + GET_ULONG_BE( W[13], data, 52 ); + GET_ULONG_BE( W[14], data, 56 ); + GET_ULONG_BE( W[15], data, 60 ); + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ +( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ +) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + + P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 ); + P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 ); + P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF ); + P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 ); + P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B ); + P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 ); + P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 ); + P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 ); + P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 ); + P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 ); + P( G, H, A, B, C, D, E, F, W[10], 0x243185BE ); + P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 ); + P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 ); + P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE ); + P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 ); + P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 ); + P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 ); + P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 ); + P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 ); + P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC ); + P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F ); + P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA ); + P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC ); + P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA ); + P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 ); + P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D ); + P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 ); + P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 ); + P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 ); + P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 ); + P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 ); + P( B, C, D, E, F, G, H, A, R(31), 0x14292967 ); + P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 ); + P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 ); + P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC ); + P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 ); + P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 ); + P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB ); + P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E ); + P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 ); + P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 ); + P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B ); + P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 ); + P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 ); + P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 ); + P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 ); + P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 ); + P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 ); + P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 ); + P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 ); + P( G, H, A, B, C, D, E, F, R(50), 0x2748774C ); + P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 ); + P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 ); + P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A ); + P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F ); + P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 ); + P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE ); + P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F ); + P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 ); + P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 ); + P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA ); + P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB ); + P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 ); + P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +/* + * SHA-256 process buffer + */ +void sha2_update( sha2_context *ctx, const unsigned char *input, int ilen ) +{ + int fill; + uint32_t left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, fill ); + sha2_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + sha2_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy((void *) (ctx->buffer + left), + (void *) input, ilen ); + } + /* + printk("ctx sha2_update:"); + dump_hex((uint8_t*)ctx,sizeof(*ctx)); + */ +} + +static const unsigned char sha2_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-256 final digest + */ +void sha2_finish( sha2_context *ctx, unsigned char output[32] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_ULONG_BE( high, msglen, 0 ); + PUT_ULONG_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + sha2_update( ctx, (unsigned char *) sha2_padding, padn ); + sha2_update( ctx, msglen, 8 ); + + PUT_ULONG_BE( ctx->state[0], output, 0 ); + PUT_ULONG_BE( ctx->state[1], output, 4 ); + PUT_ULONG_BE( ctx->state[2], output, 8 ); + PUT_ULONG_BE( ctx->state[3], output, 12 ); + PUT_ULONG_BE( ctx->state[4], output, 16 ); + PUT_ULONG_BE( ctx->state[5], output, 20 ); + PUT_ULONG_BE( ctx->state[6], output, 24 ); + + PUT_ULONG_BE( ctx->state[7], output, 28 ); +} + +/* + * output = SHA-256( input buffer ) + */ +void sha2( const unsigned char *input, int ilen, + unsigned char output[32] ) +{ + sha2_context ctx; + + sha2_starts( &ctx ); + sha2_update( &ctx, input, ilen ); + sha2_finish( &ctx, output ); + + memset(&ctx, 0, sizeof(sha2_context)); +} diff --git a/sha2-soc.h b/sha2-soc.h new file mode 100644 index 0000000000..654f011abc --- /dev/null +++ b/sha2-soc.h @@ -0,0 +1,95 @@ +/** + * \file sha2.h + * + * Copyright (C) 2011, Con Kolivas + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * 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 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "miner.h" + +#ifndef POLARSSL_SHA2_H +#define POLARSSL_SHA2_H + + +/** + * \brief SHA-256 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +sha2_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + */ +void sha2_starts( sha2_context *ctx); + +/** + * \brief SHA-256 process buffer + * + * \param ctx SHA-256 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha2_update( sha2_context *ctx, const unsigned char *input, int ilen ); + +/** + * \brief SHA-256 final digest + * + * \param ctx SHA-256 context + * \param output SHA-256 checksum result + */ +void sha2_finish( sha2_context *ctx, unsigned char output[32] ); + +/** + * \brief Output = SHA-256( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-256 checksum result + */ +void sha2( const unsigned char *input, int ilen, + unsigned char output[32]); + + +void sha2_process( sha2_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha2.h */ + + diff --git a/util.c b/util.c index c7c28a8bd1..de1fa09161 100644 --- a/util.c +++ b/util.c @@ -1328,6 +1328,20 @@ void timeraddspec(struct timespec *a, const struct timespec *b) spec_nscheck(a); } +#ifdef USE_BITMAIN_SOC +static int __maybe_unused timespec_to_ms(struct timespec *ts) +{ + return ts->tv_sec * 1000 + ts->tv_nsec / 1000000; +} + +/* Subtract b from a */ +static void __maybe_unused timersubspec(struct timespec *a, const struct timespec *b) +{ + a->tv_sec -= b->tv_sec; + a->tv_nsec -= b->tv_nsec; + spec_nscheck(a); +} +#else /* USE_BITMAIN_SOC */ static int timespec_to_ms(struct timespec *ts) { return ts->tv_sec * 1000 + ts->tv_nsec / 1000000; @@ -1345,6 +1359,7 @@ static void timersubspec(struct timespec *a, const struct timespec *b) a->tv_nsec -= b->tv_nsec; spec_nscheck(a); } +#endif /* USE_BITMAIN_SOC */ char *Strcasestr(char *haystack, const char *needle) { @@ -1475,6 +1490,25 @@ static void nanosleep_abstime(struct timespec *ts_end) /* Reentrant version of cgsleep functions allow start time to be set separately * from the beginning of the actual sleep, allowing scheduling delays to be * counted in the sleep. */ +#ifdef USE_BITMAIN_SOC +void cgsleep_ms_r(cgtimer_t *ts_start, int ms) +{ + struct timespec ts_end; + + ms_to_timespec(&ts_end, ms); + timeraddspec(&ts_end, ts_start); + nanosleep_abstime(&ts_end); +} + +void cgsleep_us_r(cgtimer_t *ts_start, int64_t us) +{ + struct timespec ts_end; + + us_to_timespec(&ts_end, us); + timeraddspec(&ts_end, ts_start); + nanosleep_abstime(&ts_end); +} +#else /* USE_BITMAIN_SOC */ int cgsleep_ms_r(cgtimer_t *ts_start, int ms) { struct timespec ts_end, ts_diff; @@ -1508,6 +1542,7 @@ int64_t cgsleep_us_r(cgtimer_t *ts_start, int64_t us) nanosleep_abstime(&ts_end); return usdiff; } +#endif /* USE_BITMAIN_SOC */ #else /* CLOCK_MONOTONIC */ #ifdef __MACH__ #include diff --git a/util.h b/util.h index c88938a341..cb7e957cc3 100644 --- a/util.h +++ b/util.h @@ -140,8 +140,13 @@ void cgsleep_ms(int ms); void cgsleep_us(int64_t us); void cgtimer_time(cgtimer_t *ts_start); #define cgsleep_prepare_r(ts_start) cgtimer_time(ts_start) +#ifdef USE_BITMAIN_SOC +void cgsleep_ms_r(cgtimer_t *ts_start, int ms); +void cgsleep_us_r(cgtimer_t *ts_start, int64_t us); +#else int cgsleep_ms_r(cgtimer_t *ts_start, int ms); int64_t cgsleep_us_r(cgtimer_t *ts_start, int64_t us); +#endif int cgtimer_to_ms(cgtimer_t *cgt); void cgtimer_sub(cgtimer_t *a, cgtimer_t *b, cgtimer_t *res); double us_tdiff(struct timeval *end, struct timeval *start); From f749b22a45a9e558260e85c65f96428b8a4f3ee2 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Sat, 18 Aug 2018 18:27:06 -0600 Subject: [PATCH 077/113] Use normal cgminer api. --- Makefile.am | 5 +- api-btm.c | 5614 --------------------------------------------------- api.c | 12 +- 3 files changed, 12 insertions(+), 5619 deletions(-) delete mode 100644 api-btm.c diff --git a/Makefile.am b/Makefile.am index a114b2c040..fb9924c76f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,7 +45,7 @@ cgminer_SOURCES := cgminer.c cgminer_SOURCES += elist.h miner.h compat.h bench_block.h \ util.c util.h uthash.h logging.h \ - sha2.c sha2.h + sha2.c sha2.h api.c cgminer_SOURCES += logging.c @@ -116,9 +116,6 @@ if HAS_BITMAIN_SOC cgminer_SOURCES += driver-btm-soc.c driver-btm-soc.h cgminer_SOURCES += bitmain-board-test.c bitmain-board-test.h cgminer_SOURCES += sha2-soc.c sha2-soc.h -cgminer_SOURCES += api-btm.c -else -cgminer_SOURCES += api.c endif if HAS_BITMINE_A1 diff --git a/api-btm.c b/api-btm.c deleted file mode 100644 index ca191aa3a5..0000000000 --- a/api-btm.c +++ /dev/null @@ -1,5614 +0,0 @@ -/* - * Copyright 2011-2014 Andrew Smith - * Copyright 2011-2014 Con Kolivas - * - * 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. - */ -#define _MEMORY_DEBUG_MASTER 1 - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "compat.h" -#include "miner.h" -#include "util.h" -#include "klist.h" - -#if defined(USE_BFLSC) || defined(USE_AVALON) || defined(USE_AVALON2) || defined(USE_AVALON4) || \ - defined(USE_HASHFAST) || defined(USE_BITFURY) || defined(USE_BITFURY16) || defined(USE_BLOCKERUPTER) || defined(USE_KLONDIKE) || \ - defined(USE_KNC) || defined(USE_BAB) || defined(USE_DRILLBIT) || \ - defined(USE_MINION) || defined(USE_COINTERRA) || defined(USE_BITMINE_A1) || \ - defined(USE_ANT_S1) || defined(USE_ANT_S2) || defined(USE_ANT_S3) || defined(USE_SP10) || \ - defined(USE_SP30) || defined(USE_ICARUS) || defined(USE_HASHRATIO) || defined(USE_AVALON_MINER) || \ - defined(USE_AVALON7) || defined(USE_BITMAIN_SOC) -#define HAVE_AN_ASIC 1 -#endif - -#if defined(USE_BITFORCE) || defined(USE_MODMINER) -#define HAVE_AN_FPGA 1 -#endif - -// BUFSIZ varies on Windows and Linux -#define TMPBUFSIZ 8192 - -// Number of requests to queue - normally would be small -// However lots of PGA's may mean more -#define QUEUE 100 - -#if defined WIN32 -static char WSAbuf[1024]; - -struct WSAERRORS -{ - int id; - char *code; -} WSAErrors[] = -{ - { 0, "No error" }, - { WSAEINTR, "Interrupted system call" }, - { WSAEBADF, "Bad file number" }, - { WSAEACCES, "Permission denied" }, - { WSAEFAULT, "Bad address" }, - { WSAEINVAL, "Invalid argument" }, - { WSAEMFILE, "Too many open sockets" }, - { WSAEWOULDBLOCK, "Operation would block" }, - { WSAEINPROGRESS, "Operation now in progress" }, - { WSAEALREADY, "Operation already in progress" }, - { WSAENOTSOCK, "Socket operation on non-socket" }, - { WSAEDESTADDRREQ, "Destination address required" }, - { WSAEMSGSIZE, "Message too long" }, - { WSAEPROTOTYPE, "Protocol wrong type for socket" }, - { WSAENOPROTOOPT, "Bad protocol option" }, - { WSAEPROTONOSUPPORT, "Protocol not supported" }, - { WSAESOCKTNOSUPPORT, "Socket type not supported" }, - { WSAEOPNOTSUPP, "Operation not supported on socket" }, - { WSAEPFNOSUPPORT, "Protocol family not supported" }, - { WSAEAFNOSUPPORT, "Address family not supported" }, - { WSAEADDRINUSE, "Address already in use" }, - { WSAEADDRNOTAVAIL, "Can't assign requested address" }, - { WSAENETDOWN, "Network is down" }, - { WSAENETUNREACH, "Network is unreachable" }, - { WSAENETRESET, "Net connection reset" }, - { WSAECONNABORTED, "Software caused connection abort" }, - { WSAECONNRESET, "Connection reset by peer" }, - { WSAENOBUFS, "No buffer space available" }, - { WSAEISCONN, "Socket is already connected" }, - { WSAENOTCONN, "Socket is not connected" }, - { WSAESHUTDOWN, "Can't send after socket shutdown" }, - { WSAETOOMANYREFS, "Too many references, can't splice" }, - { WSAETIMEDOUT, "Connection timed out" }, - { WSAECONNREFUSED, "Connection refused" }, - { WSAELOOP, "Too many levels of symbolic links" }, - { WSAENAMETOOLONG, "File name too long" }, - { WSAEHOSTDOWN, "Host is down" }, - { WSAEHOSTUNREACH, "No route to host" }, - { WSAENOTEMPTY, "Directory not empty" }, - { WSAEPROCLIM, "Too many processes" }, - { WSAEUSERS, "Too many users" }, - { WSAEDQUOT, "Disc quota exceeded" }, - { WSAESTALE, "Stale NFS file handle" }, - { WSAEREMOTE, "Too many levels of remote in path" }, - { WSASYSNOTREADY, "Network system is unavailable" }, - { WSAVERNOTSUPPORTED, "Winsock version out of range" }, - { WSANOTINITIALISED, "WSAStartup not yet called" }, - { WSAEDISCON, "Graceful shutdown in progress" }, - { WSAHOST_NOT_FOUND, "Host not found" }, - { WSANO_DATA, "No host data of that type was found" }, - { -1, "Unknown error code" } -}; - -char *WSAErrorMsg(void) -{ - int i; - int id = WSAGetLastError(); - - /* Assume none of them are actually -1 */ - for (i = 0; WSAErrors[i].id != -1; i++) - if (WSAErrors[i].id == id) - break; - - sprintf(WSAbuf, "Socket Error: (%d) %s", id, WSAErrors[i].code); - - return &(WSAbuf[0]); -} -#endif - -#if defined(__APPLE__) || defined(__FreeBSD__) -#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP -#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP -#endif - -static const char *UNAVAILABLE = " - API will not be available"; -static const char *MUNAVAILABLE = " - API multicast listener will not be available"; - -static const char *BLANK = ""; -static const char *COMMA = ","; -#define COMSTR "," -static const char SEPARATOR = '|'; -#define SEPSTR "|" -#define CMDJOIN '+' -#define JOIN_CMD "CMD=" -#define BETWEEN_JOIN SEPSTR - -static const char *APIVERSION = "3.1"; -static const char *DEAD = "Dead"; -static const char *SICK = "Sick"; -static const char *NOSTART = "NoStart"; -static const char *INIT = "Initialising"; -static const char *DISABLED = "Disabled"; -static const char *ALIVE = "Alive"; -static const char *REJECTING = "Rejecting"; -static const char *UNKNOWN = "Unknown"; - -static __maybe_unused const char *NONE = "None"; - -static const char *YES = "Y"; -static const char *NO = "N"; -static const char *NULLSTR = "(null)"; - -static const char *TRUESTR = "true"; -static const char *FALSESTR = "false"; - -static const char *SHA256STR = "sha256"; - -static const char *DEVICECODE = "" -#ifdef USE_ANT_S1 - "ANT " -#endif -#ifdef USE_ANT_S2 - "AS2 " -#endif -#ifdef USE_ANT_S3 - "AS3 " -#endif -#ifdef USE_AVALON - "AVA " -#endif -#ifdef USE_BAB - "BaB " -#endif -#ifdef USE_BFLSC - "BAS " -#endif -#ifdef USE_BITFORCE - "BFL " -#endif -#ifdef USE_BITFURY - "BFU " -#endif -#ifdef USE_BLOCKERUPTER - "BET " -#endif -#ifdef USE_DRILLBIT - "DRB " -#endif -#ifdef USE_HASHFAST - "HFA " -#endif -#ifdef USE_HASHRATIO - "HRO " -#endif -#ifdef USE_BITMINE_A1 - "BA1 " -#endif -#ifdef USE_ICARUS - "ICA " -#endif -#ifdef USE_KNC - "KnC " -#endif -#ifdef USE_MINION - "MBA " -#endif -#ifdef USE_MODMINER - "MMQ " -#endif -#ifdef USE_COINTERRA - "CTA " -#endif -#ifdef USE_SP10 - "SPN " -#endif -#ifdef USE_SP30 - "S30 " -#endif - - - ""; - -static const char *OSINFO = -#if defined(__linux) - "Linux"; -#else -#if defined(__APPLE__) - "Apple"; -#else -#if defined (WIN32) - "Windows"; -#else -#if defined(unix) - "Unix"; -#else - "Unknown"; -#endif -#endif -#endif -#endif - -#define _DEVS "DEVS" -#define _POOLS "POOLS" -#define _SUMMARY "SUMMARY" -#define _NONCENUM "NONCENUM" -#define _STATUS "STATUS" -#define _VERSION "VERSION" -#define _MINECONFIG "CONFIG" - -#ifdef HAVE_AN_FPGA -#define _PGA "PGA" -#endif - -#ifdef HAVE_AN_ASIC -#define _ASC "ASC" -#endif - -#define _PGAS "PGAS" -#define _ASCS "ASCS" -#define _NOTIFY "NOTIFY" -#define _DEVDETAILS "DEVDETAILS" -#define _BYE "BYE" -#define _RESTART "RESTART" -#define _MINESTATS "STATS" -#define _CHECK "CHECK" -#define _MINECOIN "COIN" -#define _DEBUGSET "DEBUG" -#define _SETCONFIG "SETCONFIG" -#define _USBSTATS "USBSTATS" -#define _LCD "LCD" - -static const char ISJSON = '{'; -#define JSON0 "{" -#define JSON1 "\"" -#define JSON2 "\":[" -#define JSON3 "]" -#define JSON4 ",\"id\":1" -// If anyone cares, id=0 for truncated output -#define JSON4_TRUNCATED ",\"id\":0" -#define JSON5 "}" -#define JSON6 "\":" - -#define JSON_START JSON0 -#define JSON_DEVS JSON1 _DEVS JSON2 -#define JSON_POOLS JSON1 _POOLS JSON2 -#define JSON_SUMMARY JSON1 _SUMMARY JSON2 -#define JSON_NONCENUM JSON1 _NONCENUM JSON2 - -#define JSON_STATUS JSON1 _STATUS JSON2 -#define JSON_VERSION JSON1 _VERSION JSON2 -#define JSON_MINECONFIG JSON1 _MINECONFIG JSON2 -#define JSON_ACTION JSON0 JSON1 _STATUS JSON6 - -#ifdef HAVE_AN_FPGA -#define JSON_PGA JSON1 _PGA JSON2 -#endif - -#ifdef HAVE_AN_ASIC -#define JSON_ASC JSON1 _ASC JSON2 -#endif - -#define JSON_PGAS JSON1 _PGAS JSON2 -#define JSON_ASCS JSON1 _ASCS JSON2 -#define JSON_NOTIFY JSON1 _NOTIFY JSON2 -#define JSON_DEVDETAILS JSON1 _DEVDETAILS JSON2 -#define JSON_BYE JSON1 _BYE JSON1 -#define JSON_RESTART JSON1 _RESTART JSON1 -#define JSON_CLOSE JSON3 -#define JSON_MINESTATS JSON1 _MINESTATS JSON2 -#define JSON_CHECK JSON1 _CHECK JSON2 -#define JSON_MINECOIN JSON1 _MINECOIN JSON2 -#define JSON_DEBUGSET JSON1 _DEBUGSET JSON2 -#define JSON_SETCONFIG JSON1 _SETCONFIG JSON2 -#define JSON_USBSTATS JSON1 _USBSTATS JSON2 -#define JSON_LCD JSON1 _LCD JSON2 -#define JSON_END JSON4 JSON5 -#define JSON_END_TRUNCATED JSON4_TRUNCATED JSON5 -#define JSON_BETWEEN_JOIN "," - -static const char *JSON_COMMAND = "command"; -static const char *JSON_PARAMETER = "parameter"; - -#define MSG_POOL 7 -#define MSG_NOPOOL 8 -#define MSG_DEVS 9 -#define MSG_NODEVS 10 -#define MSG_SUMM 11 -#define MSG_INVCMD 14 -#define MSG_MISID 15 -#define MSG_NONCE_NUM 16 - -#define MSG_VERSION 22 -#define MSG_INVJSON 23 -#define MSG_MISCMD 24 -#define MSG_MISPID 25 -#define MSG_INVPID 26 -#define MSG_SWITCHP 27 -#define MSG_MISVAL 28 -#define MSG_NOADL 29 -#define MSG_INVINT 31 -#define MSG_MINECONFIG 33 -#define MSG_MISFN 42 -#define MSG_BADFN 43 -#define MSG_SAVED 44 -#define MSG_ACCDENY 45 -#define MSG_ACCOK 46 -#define MSG_ENAPOOL 47 -#define MSG_DISPOOL 48 -#define MSG_ALRENAP 49 -#define MSG_ALRDISP 50 -#define MSG_DISLASTP 51 -#define MSG_MISPDP 52 -#define MSG_INVPDP 53 -#define MSG_TOOMANYP 54 -#define MSG_ADDPOOL 55 - -#ifdef HAVE_AN_FPGA -#define MSG_PGANON 56 -#define MSG_PGADEV 57 -#define MSG_INVPGA 58 -#endif - -#define MSG_NUMPGA 59 -#define MSG_NOTIFY 60 - -#ifdef HAVE_AN_FPGA -#define MSG_PGALRENA 61 -#define MSG_PGALRDIS 62 -#define MSG_PGAENA 63 -#define MSG_PGADIS 64 -#define MSG_PGAUNW 65 -#endif - -#define MSG_REMLASTP 66 -#define MSG_ACTPOOL 67 -#define MSG_REMPOOL 68 -#define MSG_DEVDETAILS 69 -#define MSG_MINESTATS 70 -#define MSG_MISCHK 71 -#define MSG_CHECK 72 -#define MSG_POOLPRIO 73 -#define MSG_DUPPID 74 -#define MSG_MISBOOL 75 -#define MSG_INVBOOL 76 -#define MSG_FOO 77 -#define MSG_MINECOIN 78 -#define MSG_DEBUGSET 79 -#define MSG_PGAIDENT 80 -#define MSG_PGANOID 81 -#define MSG_SETCONFIG 82 -#define MSG_UNKCON 83 -#define MSG_INVNUM 84 -#define MSG_CONPAR 85 -#define MSG_CONVAL 86 -#define MSG_USBSTA 87 -#define MSG_NOUSTA 88 - -#ifdef HAVE_AN_FPGA -#define MSG_MISPGAOPT 89 -#define MSG_PGANOSET 90 -#define MSG_PGAHELP 91 -#define MSG_PGASETOK 92 -#define MSG_PGASETERR 93 -#endif - -#define MSG_ZERMIS 94 -#define MSG_ZERINV 95 -#define MSG_ZERSUM 96 -#define MSG_ZERNOSUM 97 -#define MSG_PGAUSBNODEV 98 -#define MSG_INVHPLG 99 -#define MSG_HOTPLUG 100 -#define MSG_DISHPLG 101 -#define MSG_NOHPLG 102 -#define MSG_MISHPLG 103 - -#define MSG_NUMASC 104 -#ifdef HAVE_AN_ASIC -#define MSG_ASCNON 105 -#define MSG_ASCDEV 106 -#define MSG_INVASC 107 -#define MSG_ASCLRENA 108 -#define MSG_ASCLRDIS 109 -#define MSG_ASCENA 110 -#define MSG_ASCDIS 111 -#define MSG_ASCUNW 112 -#define MSG_ASCIDENT 113 -#define MSG_ASCNOID 114 -#endif -#define MSG_ASCUSBNODEV 115 - -#ifdef HAVE_AN_ASIC -#define MSG_MISASCOPT 116 -#define MSG_ASCNOSET 117 -#define MSG_ASCHELP 118 -#define MSG_ASCSETOK 119 -#define MSG_ASCSETERR 120 -#endif - -#define MSG_INVNEG 121 -#define MSG_SETQUOTA 122 -#define MSG_LOCKOK 123 -#define MSG_LOCKDIS 124 -#define MSG_LCD 125 - -#define MSG_DEPRECATED 126 -enum code_severity -{ - SEVERITY_ERR, - SEVERITY_WARN, - SEVERITY_INFO, - SEVERITY_SUCC, - SEVERITY_FAIL -}; - -enum code_parameters -{ - PARAM_PGA, - PARAM_ASC, - PARAM_PID, - PARAM_PGAMAX, - PARAM_ASCMAX, - PARAM_PMAX, - PARAM_POOLMAX, - -// Single generic case: have the code resolve it - see below - PARAM_DMAX, - - PARAM_CMD, - PARAM_POOL, - PARAM_STR, - PARAM_BOTH, - PARAM_BOOL, - PARAM_SET, - PARAM_INT, - PARAM_NONE -}; - -struct CODES -{ - const enum code_severity severity; - const int code; - const enum code_parameters params; - const char *description; -} codes[] = -{ - { SEVERITY_SUCC, MSG_POOL, PARAM_PMAX, "%d Pool(s)" }, - { SEVERITY_ERR, MSG_NOPOOL, PARAM_NONE, "No pools" }, - - { - SEVERITY_SUCC, MSG_DEVS, PARAM_DMAX, -#ifdef HAVE_AN_ASIC - "%d ASC(s)" -#endif -#if defined(HAVE_AN_ASIC) && defined(HAVE_AN_FPGA) - " - " -#endif -#ifdef HAVE_AN_FPGA - "%d PGA(s)" -#endif - }, - - { - SEVERITY_ERR, MSG_NODEVS, PARAM_NONE, "No " -#ifdef HAVE_AN_ASIC - "ASCs" -#endif -#if defined(HAVE_AN_ASIC) && defined(HAVE_AN_FPGA) - "/" -#endif -#ifdef HAVE_AN_FPGA - "PGAs" -#endif - }, - - { SEVERITY_SUCC, MSG_SUMM, PARAM_NONE, "Summary" }, - { SEVERITY_SUCC, MSG_NONCE_NUM,PARAM_NONE,"Nonce num" }, - { SEVERITY_ERR, MSG_INVCMD, PARAM_NONE, "Invalid command" }, - { SEVERITY_ERR, MSG_MISID, PARAM_NONE, "Missing device id parameter" }, -#ifdef HAVE_AN_FPGA - { SEVERITY_ERR, MSG_PGANON, PARAM_NONE, "No PGAs" }, - { SEVERITY_SUCC, MSG_PGADEV, PARAM_PGA, "PGA%d" }, - { SEVERITY_ERR, MSG_INVPGA, PARAM_PGAMAX, "Invalid PGA id %d - range is 0 - %d" }, - { SEVERITY_INFO, MSG_PGALRENA,PARAM_PGA, "PGA %d already enabled" }, - { SEVERITY_INFO, MSG_PGALRDIS,PARAM_PGA, "PGA %d already disabled" }, - { SEVERITY_INFO, MSG_PGAENA, PARAM_PGA, "PGA %d sent enable message" }, - { SEVERITY_INFO, MSG_PGADIS, PARAM_PGA, "PGA %d set disable flag" }, - { SEVERITY_ERR, MSG_PGAUNW, PARAM_PGA, "PGA %d is not flagged WELL, cannot enable" }, -#endif - { SEVERITY_SUCC, MSG_NUMPGA, PARAM_NONE, "PGA count" }, - { SEVERITY_SUCC, MSG_NUMASC, PARAM_NONE, "ASC count" }, - { SEVERITY_SUCC, MSG_VERSION, PARAM_NONE, "CGMiner versions" }, - { SEVERITY_ERR, MSG_INVJSON, PARAM_NONE, "Invalid JSON" }, - { SEVERITY_ERR, MSG_MISCMD, PARAM_CMD, "Missing JSON '%s'" }, - { SEVERITY_ERR, MSG_MISPID, PARAM_NONE, "Missing pool id parameter" }, - { SEVERITY_ERR, MSG_INVPID, PARAM_POOLMAX, "Invalid pool id %d - range is 0 - %d" }, - { SEVERITY_SUCC, MSG_SWITCHP, PARAM_POOL, "Switching to pool %d:'%s'" }, - { SEVERITY_SUCC, MSG_MINECONFIG,PARAM_NONE, "CGMiner config" }, - { SEVERITY_ERR, MSG_MISFN, PARAM_NONE, "Missing save filename parameter" }, - { SEVERITY_ERR, MSG_BADFN, PARAM_STR, "Can't open or create save file '%s'" }, - { SEVERITY_SUCC, MSG_SAVED, PARAM_STR, "Configuration saved to file '%s'" }, - { SEVERITY_ERR, MSG_ACCDENY, PARAM_STR, "Access denied to '%s' command" }, - { SEVERITY_SUCC, MSG_ACCOK, PARAM_NONE, "Privileged access OK" }, - { SEVERITY_SUCC, MSG_ENAPOOL, PARAM_POOL, "Enabling pool %d:'%s'" }, - { SEVERITY_SUCC, MSG_POOLPRIO,PARAM_NONE, "Changed pool priorities" }, - { SEVERITY_ERR, MSG_DUPPID, PARAM_PID, "Duplicate pool specified %d" }, - { SEVERITY_SUCC, MSG_DISPOOL, PARAM_POOL, "Disabling pool %d:'%s'" }, - { SEVERITY_INFO, MSG_ALRENAP, PARAM_POOL, "Pool %d:'%s' already enabled" }, - { SEVERITY_INFO, MSG_ALRDISP, PARAM_POOL, "Pool %d:'%s' already disabled" }, - { SEVERITY_ERR, MSG_DISLASTP,PARAM_POOL, "Cannot disable last active pool %d:'%s'" }, - { SEVERITY_ERR, MSG_MISPDP, PARAM_NONE, "Missing addpool details" }, - { SEVERITY_ERR, MSG_INVPDP, PARAM_STR, "Invalid addpool details '%s'" }, - { SEVERITY_ERR, MSG_TOOMANYP,PARAM_NONE, "Reached maximum number of pools (%d)" }, - { SEVERITY_SUCC, MSG_ADDPOOL, PARAM_POOL, "Added pool %d: '%s'" }, - { SEVERITY_ERR, MSG_REMLASTP,PARAM_POOL, "Cannot remove last pool %d:'%s'" }, - { SEVERITY_ERR, MSG_ACTPOOL, PARAM_POOL, "Cannot remove active pool %d:'%s'" }, - { SEVERITY_SUCC, MSG_REMPOOL, PARAM_BOTH, "Removed pool %d:'%s'" }, - { SEVERITY_SUCC, MSG_NOTIFY, PARAM_NONE, "Notify" }, - { SEVERITY_SUCC, MSG_DEVDETAILS,PARAM_NONE, "Device Details" }, - { SEVERITY_SUCC, MSG_MINESTATS,PARAM_NONE, "CGMiner stats" }, - { SEVERITY_ERR, MSG_MISCHK, PARAM_NONE, "Missing check cmd" }, - { SEVERITY_SUCC, MSG_CHECK, PARAM_NONE, "Check command" }, - { SEVERITY_ERR, MSG_MISBOOL, PARAM_NONE, "Missing parameter: true/false" }, - { SEVERITY_ERR, MSG_INVBOOL, PARAM_NONE, "Invalid parameter should be true or false" }, - { SEVERITY_SUCC, MSG_FOO, PARAM_BOOL, "Failover-Only set to %s" }, - { SEVERITY_SUCC, MSG_MINECOIN,PARAM_NONE, "CGMiner coin" }, - { SEVERITY_SUCC, MSG_DEBUGSET,PARAM_NONE, "Debug settings" }, -#ifdef HAVE_AN_FPGA - { SEVERITY_SUCC, MSG_PGAIDENT,PARAM_PGA, "Identify command sent to PGA%d" }, - { SEVERITY_WARN, MSG_PGANOID, PARAM_PGA, "PGA%d does not support identify" }, -#endif - { SEVERITY_SUCC, MSG_SETCONFIG,PARAM_SET, "Set config '%s' to %d" }, - { SEVERITY_ERR, MSG_UNKCON, PARAM_STR, "Unknown config '%s'" }, - { SEVERITY_ERR, MSG_DEPRECATED, PARAM_STR, "Deprecated config option '%s'" }, - { SEVERITY_ERR, MSG_INVNUM, PARAM_BOTH, "Invalid number (%d) for '%s' range is 0-9999" }, - { SEVERITY_ERR, MSG_INVNEG, PARAM_BOTH, "Invalid negative number (%d) for '%s'" }, - { SEVERITY_SUCC, MSG_SETQUOTA,PARAM_SET, "Set pool '%s' to quota %d'" }, - { SEVERITY_ERR, MSG_CONPAR, PARAM_NONE, "Missing config parameters 'name,N'" }, - { SEVERITY_ERR, MSG_CONVAL, PARAM_STR, "Missing config value N for '%s,N'" }, - { SEVERITY_SUCC, MSG_USBSTA, PARAM_NONE, "USB Statistics" }, - { SEVERITY_INFO, MSG_NOUSTA, PARAM_NONE, "No USB Statistics" }, -#ifdef HAVE_AN_FPGA - { SEVERITY_ERR, MSG_MISPGAOPT, PARAM_NONE, "Missing option after PGA number" }, - { SEVERITY_WARN, MSG_PGANOSET, PARAM_PGA, "PGA %d does not support pgaset" }, - { SEVERITY_INFO, MSG_PGAHELP, PARAM_BOTH, "PGA %d set help: %s" }, - { SEVERITY_SUCC, MSG_PGASETOK, PARAM_BOTH, "PGA %d set OK" }, - { SEVERITY_ERR, MSG_PGASETERR, PARAM_BOTH, "PGA %d set failed: %s" }, -#endif - { SEVERITY_ERR, MSG_ZERMIS, PARAM_NONE, "Missing zero parameters" }, - { SEVERITY_ERR, MSG_ZERINV, PARAM_STR, "Invalid zero parameter '%s'" }, - { SEVERITY_SUCC, MSG_ZERSUM, PARAM_STR, "Zeroed %s stats with summary" }, - { SEVERITY_SUCC, MSG_ZERNOSUM, PARAM_STR, "Zeroed %s stats without summary" }, -#ifdef USE_USBUTILS - { SEVERITY_ERR, MSG_PGAUSBNODEV, PARAM_PGA, "PGA%d has no device" }, - { SEVERITY_ERR, MSG_ASCUSBNODEV, PARAM_PGA, "ASC%d has no device" }, -#endif - { SEVERITY_ERR, MSG_INVHPLG, PARAM_STR, "Invalid value for hotplug (%s) must be 0..9999" }, - { SEVERITY_SUCC, MSG_HOTPLUG, PARAM_INT, "Hotplug check set to %ds" }, - { SEVERITY_SUCC, MSG_DISHPLG, PARAM_NONE, "Hotplug disabled" }, - { SEVERITY_WARN, MSG_NOHPLG, PARAM_NONE, "Hotplug is not available" }, - { SEVERITY_ERR, MSG_MISHPLG, PARAM_NONE, "Missing hotplug parameter" }, -#ifdef HAVE_AN_ASIC - { SEVERITY_ERR, MSG_ASCNON, PARAM_NONE, "No ASCs" }, - { SEVERITY_SUCC, MSG_ASCDEV, PARAM_ASC, "ASC%d" }, - { SEVERITY_ERR, MSG_INVASC, PARAM_ASCMAX, "Invalid ASC id %d - range is 0 - %d" }, - { SEVERITY_INFO, MSG_ASCLRENA,PARAM_ASC, "ASC %d already enabled" }, - { SEVERITY_INFO, MSG_ASCLRDIS,PARAM_ASC, "ASC %d already disabled" }, - { SEVERITY_INFO, MSG_ASCENA, PARAM_ASC, "ASC %d sent enable message" }, - { SEVERITY_INFO, MSG_ASCDIS, PARAM_ASC, "ASC %d set disable flag" }, - { SEVERITY_ERR, MSG_ASCUNW, PARAM_ASC, "ASC %d is not flagged WELL, cannot enable" }, - { SEVERITY_SUCC, MSG_ASCIDENT,PARAM_ASC, "Identify command sent to ASC%d" }, - { SEVERITY_WARN, MSG_ASCNOID, PARAM_ASC, "ASC%d does not support identify" }, - { SEVERITY_ERR, MSG_MISASCOPT, PARAM_NONE, "Missing option after ASC number" }, - { SEVERITY_WARN, MSG_ASCNOSET, PARAM_ASC, "ASC %d does not support ascset" }, - { SEVERITY_INFO, MSG_ASCHELP, PARAM_BOTH, "ASC %d set help: %s" }, - { SEVERITY_SUCC, MSG_ASCSETOK, PARAM_BOTH, "ASC %d set OK" }, - { SEVERITY_ERR, MSG_ASCSETERR, PARAM_BOTH, "ASC %d set failed: %s" }, -#endif - { SEVERITY_SUCC, MSG_LCD, PARAM_NONE, "LCD" }, - { SEVERITY_SUCC, MSG_LOCKOK, PARAM_NONE, "Lock stats created" }, - { SEVERITY_WARN, MSG_LOCKDIS, PARAM_NONE, "Lock stats not enabled" }, - { SEVERITY_FAIL, 0, 0, NULL } -}; - -static const char *localaddr = "127.0.0.1"; - -static int my_thr_id = 0; -static bool bye; - -// Used to control quit restart access to shutdown variables -static pthread_mutex_t quit_restart_lock; - -static bool do_a_quit; -static bool do_a_restart; - -static time_t when = 0; // when the request occurred - -struct IPACCESS -{ - struct in6_addr ip; - struct in6_addr mask; - char group; -}; - -#define GROUP(g) (toupper(g)) -#define PRIVGROUP GROUP('W') -#define NOPRIVGROUP GROUP('R') -#define ISPRIVGROUP(g) (GROUP(g) == PRIVGROUP) -#define GROUPOFFSET(g) (GROUP(g) - GROUP('A')) -#define VALIDGROUP(g) (GROUP(g) >= GROUP('A') && GROUP(g) <= GROUP('Z')) -#define COMMANDS(g) (apigroups[GROUPOFFSET(g)].commands) -#define DEFINEDGROUP(g) (ISPRIVGROUP(g) || COMMANDS(g) != NULL) - -struct APIGROUPS -{ - // This becomes a string like: "|cmd1|cmd2|cmd3|" so it's quick to search - char *commands; -} apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs) - -static struct IPACCESS *ipaccess = NULL; -static int ips = 0; - -struct io_data -{ - size_t siz; - char *ptr; - char *cur; - bool sock; - bool close; -}; - -struct io_list -{ - struct io_data *io_data; - struct io_list *prev; - struct io_list *next; -}; - -static struct io_list *io_head = NULL; - -#define SOCKBUFALLOCSIZ 65536 - -#define io_new(init) _io_new(init, false) -#define sock_io_new() _io_new(SOCKBUFALLOCSIZ, true) - -#define ALLOC_SBITEMS 2 -#define LIMIT_SBITEMS 0 - -typedef struct sbitem -{ - char *buf; - size_t siz; - size_t tot; -} SBITEM; - -// Size to grow tot if exceeded -#define SBEXTEND 4096 - -#define DATASB(_item) ((SBITEM *)(_item->data)) - -static K_LIST *strbufs; - -static void io_reinit(struct io_data *io_data) -{ - io_data->cur = io_data->ptr; - *(io_data->ptr) = '\0'; - io_data->close = false; -} - -static struct io_data *_io_new(size_t initial, bool socket_buf) -{ - struct io_data *io_data; - struct io_list *io_list; - - io_data = cgmalloc(sizeof(*io_data)); - io_data->ptr = cgmalloc(initial); - io_data->siz = initial; - io_data->sock = socket_buf; - io_reinit(io_data); - - io_list = cgmalloc(sizeof(*io_list)); - - io_list->io_data = io_data; - - if (io_head) - { - io_list->next = io_head; - io_list->prev = io_head->prev; - io_list->next->prev = io_list; - io_list->prev->next = io_list; - } - else - { - io_list->prev = io_list; - io_list->next = io_list; - io_head = io_list; - } - - return io_data; -} - -static bool io_add(struct io_data *io_data, char *buf) -{ - size_t len, dif, tot; - - len = strlen(buf); - dif = io_data->cur - io_data->ptr; - // send will always have enough space to add the JSON - tot = len + 1 + dif + sizeof(JSON_CLOSE) + sizeof(JSON_END); - - if (tot > io_data->siz) - { - size_t new = io_data->siz + (2 * SOCKBUFALLOCSIZ); - - if (new < tot) - new = (2 + (size_t)((float)tot / (float)SOCKBUFALLOCSIZ)) * SOCKBUFALLOCSIZ; - - io_data->ptr = cgrealloc(io_data->ptr, new); - io_data->cur = io_data->ptr + dif; - io_data->siz = new; - } - - memcpy(io_data->cur, buf, len + 1); - io_data->cur += len; - - return true; -} - -static bool io_put(struct io_data *io_data, char *buf) -{ - io_reinit(io_data); - return io_add(io_data, buf); -} - -static void io_close(struct io_data *io_data) -{ - io_data->close = true; -} - -static void io_free() -{ - struct io_list *io_list, *io_next; - - if (io_head) - { - io_list = io_head; - do - { - io_next = io_list->next; - - free(io_list->io_data->ptr); - free(io_list->io_data); - free(io_list); - - io_list = io_next; - } - while (io_list != io_head); - - io_head = NULL; - } -} - -// This is only called when expected to be needed (rarely) -// i.e. strings outside of the codes control (input from the user) -static char *escape_string(char *str, bool isjson) -{ - char *buf, *ptr; - int count; - - count = 0; - for (ptr = str; *ptr; ptr++) - { - switch (*ptr) - { - case ',': - case '|': - case '=': - if (!isjson) - count++; - break; - case '"': - if (isjson) - count++; - break; - case '\\': - count++; - break; - } - } - - if (count == 0) - return str; - - buf = cgmalloc(strlen(str) + count + 1); - - ptr = buf; - while (*str) - switch (*str) - { - case ',': - case '|': - case '=': - if (!isjson) - *(ptr++) = '\\'; - *(ptr++) = *(str++); - break; - case '"': - if (isjson) - *(ptr++) = '\\'; - *(ptr++) = *(str++); - break; - case '\\': - *(ptr++) = '\\'; - *(ptr++) = *(str++); - break; - default: - *(ptr++) = *(str++); - break; - } - - *ptr = '\0'; - - return buf; -} - -static struct api_data *api_add_extra(struct api_data *root, struct api_data *extra) -{ - struct api_data *tmp; - - if (root) - { - if (extra) - { - // extra tail - tmp = extra->prev; - - // extra prev = root tail - extra->prev = root->prev; - - // root tail next = extra - root->prev->next = extra; - - // extra tail next = root - tmp->next = root; - - // root prev = extra tail - root->prev = tmp; - } - } - else - root = extra; - - return root; -} - -static struct api_data *api_add_data_full(struct api_data *root, char *name, enum api_data_type type, void *data, bool copy_data) -{ - struct api_data *api_data; - - api_data = cgmalloc(sizeof(struct api_data)); - - api_data->name = strdup(name); - api_data->type = type; - - if (root == NULL) - { - root = api_data; - root->prev = root; - root->next = root; - } - else - { - api_data->prev = root->prev; - root->prev = api_data; - api_data->next = root; - api_data->prev->next = api_data; - } - - api_data->data_was_malloc = copy_data; - - // Avoid crashing on bad data - if (data == NULL) - { - api_data->type = type = API_CONST; - data = (void *)NULLSTR; - api_data->data_was_malloc = copy_data = false; - } - - if (!copy_data) - api_data->data = data; - else - switch(type) - { - case API_ESCAPE: - case API_STRING: - case API_CONST: - api_data->data = cgmalloc(strlen((char *)data) + 1); - strcpy((char*)(api_data->data), (char *)data); - break; - case API_UINT8: - /* Most OSs won't really alloc less than 4 */ - api_data->data = cgmalloc(4); - *(uint8_t *)api_data->data = *(uint8_t *)data; - break; - case API_INT16: - /* Most OSs won't really alloc less than 4 */ - api_data->data = cgmalloc(4); - *(int16_t *)api_data->data = *(int16_t *)data; - break; - case API_UINT16: - /* Most OSs won't really alloc less than 4 */ - api_data->data = cgmalloc(4); - *(uint16_t *)api_data->data = *(uint16_t *)data; - break; - case API_INT: - api_data->data = cgmalloc(sizeof(int)); - *((int *)(api_data->data)) = *((int *)data); - break; - case API_UINT: - api_data->data = cgmalloc(sizeof(unsigned int)); - *((unsigned int *)(api_data->data)) = *((unsigned int *)data); - break; - case API_UINT32: - api_data->data = cgmalloc(sizeof(uint32_t)); - *((uint32_t *)(api_data->data)) = *((uint32_t *)data); - break; - case API_HEX32: - api_data->data = cgmalloc(sizeof(uint32_t)); - *((uint32_t *)(api_data->data)) = *((uint32_t *)data); - break; - case API_UINT64: - api_data->data = cgmalloc(sizeof(uint64_t)); - *((uint64_t *)(api_data->data)) = *((uint64_t *)data); - break; - case API_INT64: - api_data->data = cgmalloc(sizeof(int64_t)); - *((int64_t *)(api_data->data)) = *((int64_t *)data); - break; - case API_DOUBLE: - case API_ELAPSED: - case API_MHS: - case API_MHTOTAL: - case API_UTILITY: - case API_FREQ: - case API_HS: - case API_DIFF: - case API_PERCENT: - api_data->data = cgmalloc(sizeof(double)); - *((double *)(api_data->data)) = *((double *)data); - break; - case API_BOOL: - api_data->data = cgmalloc(sizeof(bool)); - *((bool *)(api_data->data)) = *((bool *)data); - break; - case API_TIMEVAL: - api_data->data = cgmalloc(sizeof(struct timeval)); - memcpy(api_data->data, data, sizeof(struct timeval)); - break; - case API_TIME: - api_data->data = cgmalloc(sizeof(time_t)); - *(time_t *)(api_data->data) = *((time_t *)data); - break; - case API_VOLTS: - case API_TEMP: - case API_AVG: - api_data->data = cgmalloc(sizeof(float)); - *((float *)(api_data->data)) = *((float *)data); - break; - default: - applog(LOG_ERR, "API: unknown1 data type %d ignored", type); - api_data->type = API_STRING; - api_data->data_was_malloc = false; - api_data->data = (void *)UNKNOWN; - break; - } - - return root; -} - -struct api_data *api_add_escape(struct api_data *root, char *name, char *data, bool copy_data) -{ - return api_add_data_full(root, name, API_ESCAPE, (void *)data, copy_data); -} - -struct api_data *api_add_string(struct api_data *root, char *name, char *data, bool copy_data) -{ - return api_add_data_full(root, name, API_STRING, (void *)data, copy_data); -} - -struct api_data *api_add_const(struct api_data *root, char *name, const char *data, bool copy_data) -{ - return api_add_data_full(root, name, API_CONST, (void *)data, copy_data); -} - -struct api_data *api_add_uint8(struct api_data *root, char *name, uint8_t *data, bool copy_data) -{ - return api_add_data_full(root, name, API_UINT8, (void *)data, copy_data); -} - -struct api_data *api_add_int16(struct api_data *root, char *name, uint16_t *data, bool copy_data) -{ - return api_add_data_full(root, name, API_INT16, (void *)data, copy_data); -} - -struct api_data *api_add_uint16(struct api_data *root, char *name, uint16_t *data, bool copy_data) -{ - return api_add_data_full(root, name, API_UINT16, (void *)data, copy_data); -} - -struct api_data *api_add_int(struct api_data *root, char *name, int *data, bool copy_data) -{ - return api_add_data_full(root, name, API_INT, (void *)data, copy_data); -} - -struct api_data *api_add_uint(struct api_data *root, char *name, unsigned int *data, bool copy_data) -{ - return api_add_data_full(root, name, API_UINT, (void *)data, copy_data); -} - -struct api_data *api_add_uint32(struct api_data *root, char *name, uint32_t *data, bool copy_data) -{ - return api_add_data_full(root, name, API_UINT32, (void *)data, copy_data); -} - -struct api_data *api_add_hex32(struct api_data *root, char *name, uint32_t *data, bool copy_data) -{ - return api_add_data_full(root, name, API_HEX32, (void *)data, copy_data); -} - -struct api_data *api_add_uint64(struct api_data *root, char *name, uint64_t *data, bool copy_data) -{ - return api_add_data_full(root, name, API_UINT64, (void *)data, copy_data); -} - -struct api_data *api_add_int64(struct api_data *root, char *name, int64_t *data, bool copy_data) -{ - return api_add_data_full(root, name, API_INT64, (void *)data, copy_data); -} - -struct api_data *api_add_double(struct api_data *root, char *name, double *data, bool copy_data) -{ - return api_add_data_full(root, name, API_DOUBLE, (void *)data, copy_data); -} - -struct api_data *api_add_elapsed(struct api_data *root, char *name, double *data, bool copy_data) -{ - return api_add_data_full(root, name, API_ELAPSED, (void *)data, copy_data); -} - -struct api_data *api_add_bool(struct api_data *root, char *name, bool *data, bool copy_data) -{ - return api_add_data_full(root, name, API_BOOL, (void *)data, copy_data); -} - -struct api_data *api_add_timeval(struct api_data *root, char *name, struct timeval *data, bool copy_data) -{ - return api_add_data_full(root, name, API_TIMEVAL, (void *)data, copy_data); -} - -struct api_data *api_add_time(struct api_data *root, char *name, time_t *data, bool copy_data) -{ - return api_add_data_full(root, name, API_TIME, (void *)data, copy_data); -} - -struct api_data *api_add_mhs(struct api_data *root, char *name, double *data, bool copy_data) -{ - return api_add_data_full(root, name, API_MHS, (void *)data, copy_data); -} - -struct api_data *api_add_mhtotal(struct api_data *root, char *name, double *data, bool copy_data) -{ - return api_add_data_full(root, name, API_MHTOTAL, (void *)data, copy_data); -} - -struct api_data *api_add_temp(struct api_data *root, char *name, float *data, bool copy_data) -{ - return api_add_data_full(root, name, API_TEMP, (void *)data, copy_data); -} - -struct api_data *api_add_utility(struct api_data *root, char *name, double *data, bool copy_data) -{ - return api_add_data_full(root, name, API_UTILITY, (void *)data, copy_data); -} - -struct api_data *api_add_freq(struct api_data *root, char *name, double *data, bool copy_data) -{ - return api_add_data_full(root, name, API_FREQ, (void *)data, copy_data); -} - -struct api_data *api_add_volts(struct api_data *root, char *name, float *data, bool copy_data) -{ - return api_add_data_full(root, name, API_VOLTS, (void *)data, copy_data); -} - -struct api_data *api_add_hs(struct api_data *root, char *name, double *data, bool copy_data) -{ - return api_add_data_full(root, name, API_HS, (void *)data, copy_data); -} - -struct api_data *api_add_diff(struct api_data *root, char *name, double *data, bool copy_data) -{ - return api_add_data_full(root, name, API_DIFF, (void *)data, copy_data); -} - -struct api_data *api_add_percent(struct api_data *root, char *name, double *data, bool copy_data) -{ - return api_add_data_full(root, name, API_PERCENT, (void *)data, copy_data); -} - -struct api_data *api_add_avg(struct api_data *root, char *name, float *data, bool copy_data) -{ - return api_add_data_full(root, name, API_AVG, (void *)data, copy_data); -} - -static void add_item_buf(K_ITEM *item, const char *str) -{ - size_t old_siz, new_siz, siz, ext; - char *buf; - - buf = DATASB(item)->buf; - siz = (size_t)strlen(str); - - old_siz = DATASB(item)->siz; - new_siz = old_siz + siz + 1; // include '\0' - if (DATASB(item)->tot < new_siz) - { - ext = (siz + 1) + SBEXTEND - ((siz + 1) % SBEXTEND); - DATASB(item)->buf = buf = cgrealloc(DATASB(item)->buf, DATASB(item)->tot + ext); - DATASB(item)->tot += ext; - } - memcpy(buf + old_siz, str, siz + 1); - DATASB(item)->siz += siz; -} - -static struct api_data *print_data(struct io_data *io_data, struct api_data *root, bool isjson, bool precom) -{ - // N.B. strings don't use this buffer so 64 is enough (for now) - char buf[64]; - struct api_data *tmp; - bool done, first = true; - char *original, *escape; - K_ITEM *item; - - K_WLOCK(strbufs); - item = k_unlink_head(strbufs); - K_WUNLOCK(strbufs); - - DATASB(item)->siz = 0; - - if (precom) - add_item_buf(item, COMMA); - - if (isjson) - add_item_buf(item, JSON0); - - while (root) - { - if (!first) - add_item_buf(item, COMMA); - else - first = false; - - if (isjson) - add_item_buf(item, JSON1); - - add_item_buf(item, root->name); - - if (isjson) - add_item_buf(item, JSON1); - - if (isjson) - add_item_buf(item, ":"); - else - add_item_buf(item, "="); - - first = false; - - done = false; - switch(root->type) - { - case API_STRING: - case API_CONST: - if (isjson) - add_item_buf(item, JSON1); - add_item_buf(item, (char *)(root->data)); - if (isjson) - add_item_buf(item, JSON1); - done = true; - break; - case API_ESCAPE: - original = (char *)(root->data); - escape = escape_string((char *)(root->data), isjson); - if (isjson) - add_item_buf(item, JSON1); - add_item_buf(item, escape); - if (isjson) - add_item_buf(item, JSON1); - if (escape != original) - free(escape); - done = true; - break; - case API_UINT8: - snprintf(buf, sizeof(buf), "%u", *(uint8_t *)root->data); - break; - case API_INT16: - snprintf(buf, sizeof(buf), "%d", *(int16_t *)root->data); - break; - case API_UINT16: - snprintf(buf, sizeof(buf), "%u", *(uint16_t *)root->data); - break; - case API_INT: - snprintf(buf, sizeof(buf), "%d", *((int *)(root->data))); - break; - case API_UINT: - snprintf(buf, sizeof(buf), "%u", *((unsigned int *)(root->data))); - break; - case API_UINT32: - snprintf(buf, sizeof(buf), "%"PRIu32, *((uint32_t *)(root->data))); - break; - case API_HEX32: - if (isjson) - add_item_buf(item, JSON1); - snprintf(buf, sizeof(buf), "0x%08x", *((uint32_t *)(root->data))); - add_item_buf(item, buf); - if (isjson) - add_item_buf(item, JSON1); - done = true; - break; - case API_UINT64: - snprintf(buf, sizeof(buf), "%"PRIu64, *((uint64_t *)(root->data))); - break; - case API_INT64: - snprintf(buf, sizeof(buf), "%"PRId64, *((int64_t *)(root->data))); - break; - case API_TIME: - snprintf(buf, sizeof(buf), "%lu", *((unsigned long *)(root->data))); - break; - case API_DOUBLE: - snprintf(buf, sizeof(buf), "%f", *((double *)(root->data))); - break; - case API_ELAPSED: - snprintf(buf, sizeof(buf), "%.0f", *((double *)(root->data))); - break; - case API_UTILITY: - case API_FREQ: - case API_MHS: - snprintf(buf, sizeof(buf), "%.2f", *((double *)(root->data))); - break; - case API_VOLTS: - case API_AVG: - snprintf(buf, sizeof(buf), "%.3f", *((float *)(root->data))); - break; - case API_MHTOTAL: - snprintf(buf, sizeof(buf), "%.4f", *((double *)(root->data))); - break; - case API_HS: - snprintf(buf, sizeof(buf), "%.15f", *((double *)(root->data))); - break; - case API_DIFF: - snprintf(buf, sizeof(buf), "%.8f", *((double *)(root->data))); - break; - case API_BOOL: - snprintf(buf, sizeof(buf), "%s", *((bool *)(root->data)) ? TRUESTR : FALSESTR); - break; - case API_TIMEVAL: - snprintf(buf, sizeof(buf), "%ld.%06ld", - (long)((struct timeval *)(root->data))->tv_sec, - (long)((struct timeval *)(root->data))->tv_usec); - break; - case API_TEMP: - snprintf(buf, sizeof(buf), "%.2f", *((float *)(root->data))); - break; - case API_PERCENT: - snprintf(buf, sizeof(buf), "%.4f", *((double *)(root->data)) * 100.0); - break; - default: - applog(LOG_ERR, "API: unknown2 data type %d ignored", root->type); - if (isjson) - add_item_buf(item, JSON1); - add_item_buf(item, UNKNOWN); - if (isjson) - add_item_buf(item, JSON1); - done = true; - break; - } - - if (!done) - add_item_buf(item, buf); - - free(root->name); - if (root->data_was_malloc) - free(root->data); - - if (root->next == root) - { - free(root); - root = NULL; - } - else - { - tmp = root; - root = tmp->next; - root->prev = tmp->prev; - root->prev->next = root; - free(tmp); - } - } - - if (isjson) - add_item_buf(item, JSON5); - else - add_item_buf(item, SEPSTR); - - io_add(io_data, DATASB(item)->buf); - - K_WLOCK(strbufs); - k_add_head(strbufs, item); - K_WUNLOCK(strbufs); - - return root; -} - -#define DRIVER_COUNT_DRV(X) if (devices[i]->drv->drv_id == DRIVER_##X) \ - count++; - -#ifdef HAVE_AN_ASIC -static int numascs(void) -{ - int count = 0; - int i; - - rd_lock(&devices_lock); - for (i = 0; i < total_devices; i++) - { - ASIC_PARSE_COMMANDS(DRIVER_COUNT_DRV) - } - rd_unlock(&devices_lock); - return count; -} - -static int ascdevice(int ascid) -{ - int count = 0; - int i; - - rd_lock(&devices_lock); - for (i = 0; i < total_devices; i++) - { - ASIC_PARSE_COMMANDS(DRIVER_COUNT_DRV) - if (count == (ascid + 1)) - goto foundit; - } - - rd_unlock(&devices_lock); - return -1; - -foundit: - - rd_unlock(&devices_lock); - return i; -} -#endif - -#ifdef HAVE_AN_FPGA -static int numpgas(void) -{ - int count = 0; - int i; - - rd_lock(&devices_lock); - for (i = 0; i < total_devices; i++) - { - FPGA_PARSE_COMMANDS(DRIVER_COUNT_DRV) - } - rd_unlock(&devices_lock); - return count; -} - -static int pgadevice(int pgaid) -{ - int count = 0; - int i; - - rd_lock(&devices_lock); - for (i = 0; i < total_devices; i++) - { - FPGA_PARSE_COMMANDS(DRIVER_COUNT_DRV) - if (count == (pgaid + 1)) - goto foundit; - } - - rd_unlock(&devices_lock); - return -1; - -foundit: - - rd_unlock(&devices_lock); - return i; -} -#endif - -// All replies (except BYE and RESTART) start with a message -// thus for JSON, message() inserts JSON_START at the front -// and send_result() adds JSON_END at the end -static void message(struct io_data *io_data, int messageid, int paramid, char *param2, bool isjson) -{ - struct api_data *root = NULL; - char buf[TMPBUFSIZ]; - char severity[2]; -#ifdef HAVE_AN_ASIC - int asc; -#endif -#ifdef HAVE_AN_FPGA - int pga; -#endif - int i; - - if (isjson) - io_add(io_data, JSON_START JSON_STATUS); - - for (i = 0; codes[i].severity != SEVERITY_FAIL; i++) - { - if (codes[i].code == messageid) - { - switch (codes[i].severity) - { - case SEVERITY_WARN: - severity[0] = 'W'; - break; - case SEVERITY_INFO: - severity[0] = 'I'; - break; - case SEVERITY_SUCC: - severity[0] = 'S'; - break; - case SEVERITY_ERR: - default: - severity[0] = 'E'; - break; - } - severity[1] = '\0'; - - switch(codes[i].params) - { - case PARAM_PGA: - case PARAM_ASC: - case PARAM_PID: - case PARAM_INT: - sprintf(buf, codes[i].description, paramid); - break; - case PARAM_POOL: - sprintf(buf, codes[i].description, paramid, pools[paramid]->rpc_url); - break; -#ifdef HAVE_AN_FPGA - case PARAM_PGAMAX: - pga = numpgas(); - sprintf(buf, codes[i].description, paramid, pga - 1); - break; -#endif -#ifdef HAVE_AN_ASIC - case PARAM_ASCMAX: - asc = numascs(); - sprintf(buf, codes[i].description, paramid, asc - 1); - break; -#endif - case PARAM_PMAX: - sprintf(buf, codes[i].description, total_pools); - break; - case PARAM_POOLMAX: - sprintf(buf, codes[i].description, paramid, total_pools - 1); - break; - case PARAM_DMAX: -#ifdef HAVE_AN_ASIC - asc = numascs(); -#endif -#ifdef HAVE_AN_FPGA - pga = numpgas(); -#endif - - sprintf(buf, codes[i].description -#ifdef HAVE_AN_ASIC - , asc -#endif -#ifdef HAVE_AN_FPGA - , pga -#endif - ); - break; - case PARAM_CMD: - sprintf(buf, codes[i].description, JSON_COMMAND); - break; - case PARAM_STR: - sprintf(buf, codes[i].description, param2); - break; - case PARAM_BOTH: - sprintf(buf, codes[i].description, paramid, param2); - break; - case PARAM_BOOL: - sprintf(buf, codes[i].description, paramid ? TRUESTR : FALSESTR); - break; - case PARAM_SET: - sprintf(buf, codes[i].description, param2, paramid); - break; - case PARAM_NONE: - default: - strcpy(buf, codes[i].description); - } - - root = api_add_string(root, _STATUS, severity, false); - root = api_add_time(root, "When", &when, false); - root = api_add_int(root, "Code", &messageid, false); - root = api_add_escape(root, "Msg", buf, false); - root = api_add_escape(root, "Description", opt_api_description, false); - - root = print_data(io_data, root, isjson, false); - if (isjson) - io_add(io_data, JSON_CLOSE); - return; - } - } - - root = api_add_string(root, _STATUS, "F", false); - root = api_add_time(root, "When", &when, false); - int id = -1; - root = api_add_int(root, "Code", &id, false); - sprintf(buf, "%d", messageid); - root = api_add_escape(root, "Msg", buf, false); - root = api_add_escape(root, "Description", opt_api_description, false); - - root = print_data(io_data, root, isjson, false); - if (isjson) - io_add(io_data, JSON_CLOSE); -} - -#if LOCK_TRACKING - -#define LOCK_FMT_FFL " - called from %s %s():%d" - -#define LOCKMSG(fmt, ...) fprintf(stderr, "APILOCK: " fmt "\n", ##__VA_ARGS__) -#define LOCKMSGMORE(fmt, ...) fprintf(stderr, " " fmt "\n", ##__VA_ARGS__) -#define LOCKMSGFFL(fmt, ...) fprintf(stderr, "APILOCK: " fmt LOCK_FMT_FFL "\n", ##__VA_ARGS__, file, func, linenum) -#define LOCKMSGFLUSH() fflush(stderr) - -typedef struct lockstat -{ - uint64_t lock_id; - const char *file; - const char *func; - int linenum; - struct timeval tv; -} LOCKSTAT; - -typedef struct lockline -{ - struct lockline *prev; - struct lockstat *stat; - struct lockline *next; -} LOCKLINE; - -typedef struct lockinfo -{ - void *lock; - enum cglock_typ typ; - const char *file; - const char *func; - int linenum; - uint64_t gets; - uint64_t gots; - uint64_t tries; - uint64_t dids; - uint64_t didnts; // should be tries - dids - uint64_t unlocks; - LOCKSTAT lastgot; - LOCKLINE *lockgets; - LOCKLINE *locktries; -} LOCKINFO; - -typedef struct locklist -{ - LOCKINFO *info; - struct locklist *next; -} LOCKLIST; - -static uint64_t lock_id = 1; - -static LOCKLIST *lockhead; - -static void lockmsgnow() -{ - struct timeval now; - struct tm *tm; - time_t dt; - - cgtime(&now); - - dt = now.tv_sec; - tm = localtime(&dt); - - LOCKMSG("%d-%02d-%02d %02d:%02d:%02d", - tm->tm_year + 1900, - tm->tm_mon + 1, - tm->tm_mday, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); -} - -static LOCKLIST *newlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum) -{ - LOCKLIST *list; - - list = cgcalloc(1, sizeof(*list)); - list->info = cgcalloc(1, sizeof(*(list->info))); - list->next = lockhead; - lockhead = list; - - list->info->lock = lock; - list->info->typ = typ; - list->info->file = file; - list->info->func = func; - list->info->linenum = linenum; - - return list; -} - -static LOCKINFO *findlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum) -{ - LOCKLIST *look; - - look = lockhead; - while (look) - { - if (look->info->lock == lock) - break; - look = look->next; - } - - if (!look) - look = newlock(lock, typ, file, func, linenum); - - return look->info; -} - -static void addgettry(LOCKINFO *info, uint64_t id, const char *file, const char *func, const int linenum, bool get) -{ - LOCKSTAT *stat; - LOCKLINE *line; - - stat = cgcalloc(1, sizeof(*stat)); - line = cgcalloc(1, sizeof(*line)); - - if (get) - info->gets++; - else - info->tries++; - - stat->lock_id = id; - stat->file = file; - stat->func = func; - stat->linenum = linenum; - cgtime(&stat->tv); - - line->stat = stat; - - if (get) - { - line->next = info->lockgets; - if (info->lockgets) - info->lockgets->prev = line; - info->lockgets = line; - } - else - { - line->next = info->locktries; - if (info->locktries) - info->locktries->prev = line; - info->locktries = line; - } -} - -static void markgotdid(LOCKINFO *info, uint64_t id, const char *file, const char *func, const int linenum, bool got, int ret) -{ - LOCKLINE *line; - - if (got) - info->gots++; - else - { - if (ret == 0) - info->dids++; - else - info->didnts++; - } - - if (got || ret == 0) - { - info->lastgot.lock_id = id; - info->lastgot.file = file; - info->lastgot.func = func; - info->lastgot.linenum = linenum; - cgtime(&info->lastgot.tv); - } - - if (got) - line = info->lockgets; - else - line = info->locktries; - while (line) - { - if (line->stat->lock_id == id) - break; - line = line->next; - } - - if (!line) - { - lockmsgnow(); - LOCKMSGFFL("ERROR attempt to mark a lock as '%s' that wasn't '%s' id=%"PRIu64, - got ? "got" : "did/didnt", got ? "get" : "try", id); - } - - // Unlink it - if (line->prev) - line->prev->next = line->next; - if (line->next) - line->next->prev = line->prev; - - if (got) - { - if (info->lockgets == line) - info->lockgets = line->next; - } - else - { - if (info->locktries == line) - info->locktries = line->next; - } - - free(line->stat); - free(line); -} - -// Yes this uses locks also ... ;/ -static void locklock() -{ - if (unlikely(pthread_mutex_lock(&lockstat_lock))) - quithere(1, "WTF MUTEX ERROR ON LOCK! errno=%d", errno); -} - -static void lockunlock() -{ - if (unlikely(pthread_mutex_unlock(&lockstat_lock))) - quithere(1, "WTF MUTEX ERROR ON UNLOCK! errno=%d", errno); -} - -uint64_t api_getlock(void *lock, const char *file, const char *func, const int linenum) -{ - LOCKINFO *info; - uint64_t id; - - locklock(); - - info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum); - id = lock_id++; - addgettry(info, id, file, func, linenum, true); - - lockunlock(); - - return id; -} - -void api_gotlock(uint64_t id, void *lock, const char *file, const char *func, const int linenum) -{ - LOCKINFO *info; - - locklock(); - - info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum); - markgotdid(info, id, file, func, linenum, true, 0); - - lockunlock(); -} - -uint64_t api_trylock(void *lock, const char *file, const char *func, const int linenum) -{ - LOCKINFO *info; - uint64_t id; - - locklock(); - - info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum); - id = lock_id++; - addgettry(info, id, file, func, linenum, false); - - lockunlock(); - - return id; -} - -void api_didlock(uint64_t id, int ret, void *lock, const char *file, const char *func, const int linenum) -{ - LOCKINFO *info; - - locklock(); - - info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum); - markgotdid(info, id, file, func, linenum, false, ret); - - lockunlock(); -} - -void api_gunlock(void *lock, const char *file, const char *func, const int linenum) -{ - LOCKINFO *info; - - locklock(); - - info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum); - info->unlocks++; - - lockunlock(); -} - -void api_initlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum) -{ - locklock(); - - findlock(lock, typ, file, func, linenum); - - lockunlock(); -} - -void dsp_det(char *msg, LOCKSTAT *stat) -{ - struct tm *tm; - time_t dt; - - dt = stat->tv.tv_sec; - tm = localtime(&dt); - - LOCKMSGMORE("%s id=%"PRIu64" by %s %s():%d at %d-%02d-%02d %02d:%02d:%02d", - msg, - stat->lock_id, - stat->file, - stat->func, - stat->linenum, - tm->tm_year + 1900, - tm->tm_mon + 1, - tm->tm_mday, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); -} - -void dsp_lock(LOCKINFO *info) -{ - LOCKLINE *line; - char *status; - - LOCKMSG("Lock %p created by %s %s():%d", - info->lock, - info->file, - info->func, - info->linenum); - LOCKMSGMORE("gets:%"PRIu64" gots:%"PRIu64" tries:%"PRIu64 - " dids:%"PRIu64" didnts:%"PRIu64" unlocks:%"PRIu64, - info->gets, - info->gots, - info->tries, - info->dids, - info->didnts, - info->unlocks); - - if (info->gots > 0 || info->dids > 0) - { - if (info->unlocks < info->gots + info->dids) - status = "Last got/did still HELD"; - else - status = "Last got/did (idle)"; - - dsp_det(status, &(info->lastgot)); - } - else - LOCKMSGMORE("... unused ..."); - - if (info->lockgets) - { - LOCKMSGMORE("BLOCKED gets (%"PRIu64")", info->gets - info->gots); - line = info->lockgets; - while (line) - { - dsp_det("", line->stat); - line = line->next; - } - } - else - LOCKMSGMORE("no blocked gets"); - - if (info->locktries) - { - LOCKMSGMORE("BLOCKED tries (%"PRIu64")", info->tries - info->dids - info->didnts); - line = info->lockgets; - while (line) - { - dsp_det("", line->stat); - line = line->next; - } - } - else - LOCKMSGMORE("no blocked tries"); -} - -void show_locks() -{ - LOCKLIST *list; - - locklock(); - - lockmsgnow(); - - list = lockhead; - if (!list) - LOCKMSG("no locks?!?\n"); - else - { - while (list) - { - dsp_lock(list->info); - list = list->next; - } - } - - LOCKMSGFLUSH(); - - lockunlock(); -} -#endif - -static void lockstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ -#if LOCK_TRACKING - show_locks(); - message(io_data, MSG_LOCKOK, 0, NULL, isjson); -#else - message(io_data, MSG_LOCKDIS, 0, NULL, isjson); -#endif -} - -static void apiversion(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - bool io_open; - - message(io_data, MSG_VERSION, 0, NULL, isjson); - io_open = io_add(io_data, isjson ? COMSTR JSON_VERSION : _VERSION COMSTR); - - root = api_add_string(root, "CGMiner", VERSION, false); - root = api_add_const(root, "API", APIVERSION, false); - root = api_add_string(root, "Miner", g_miner_version, false); - root = api_add_string(root, "CompileTime", g_miner_compiletime, false); - root = api_add_string(root, "Type", g_miner_type, false); - - root = print_data(io_data, root, isjson, false); - if (isjson && io_open) - io_close(io_data); -} - -static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - bool io_open; - int asccount = 0; - int pgacount = 0; - -#ifdef HAVE_AN_ASIC - asccount = numascs(); -#endif - -#ifdef HAVE_AN_FPGA - pgacount = numpgas(); -#endif - - message(io_data, MSG_MINECONFIG, 0, NULL, isjson); - io_open = io_add(io_data, isjson ? COMSTR JSON_MINECONFIG : _MINECONFIG COMSTR); - - root = api_add_int(root, "ASC Count", &asccount, false); - root = api_add_int(root, "PGA Count", &pgacount, false); - root = api_add_int(root, "Pool Count", &total_pools, false); - root = api_add_const(root, "Strategy", strategies[pool_strategy].s, false); - root = api_add_int(root, "Log Interval", &opt_log_interval, false); - root = api_add_const(root, "Device Code", DEVICECODE, false); - root = api_add_const(root, "OS", OSINFO, false); -#ifdef USE_USBUTILS - if (hotplug_time == 0) - root = api_add_const(root, "Hotplug", DISABLED, false); - else - root = api_add_int(root, "Hotplug", &hotplug_time, false); -#else - root = api_add_const(root, "Hotplug", NONE, false); -#endif - - root = print_data(io_data, root, isjson, false); - if (isjson && io_open) - io_close(io_data); -} - -static const char *status2str(enum alive status) -{ - switch (status) - { - case LIFE_WELL: - return ALIVE; - case LIFE_SICK: - return SICK; - case LIFE_DEAD: - return DEAD; - case LIFE_NOSTART: - return NOSTART; - case LIFE_INIT: - return INIT; - default: - return UNKNOWN; - } -} - -#ifdef HAVE_AN_ASIC -static void ascstatus(struct io_data *io_data, int asc, bool isjson, bool precom) -{ - struct api_data *root = NULL; - char *enabled; - char *status; - int numasc = numascs(); - - if (numasc > 0 && asc >= 0 && asc < numasc) - { - int dev = ascdevice(asc); - if (dev < 0) // Should never happen - return; - - struct cgpu_info *cgpu = get_devices(dev); - float temp = cgpu->temp; - double dev_runtime; - - dev_runtime = cgpu_runtime(cgpu); - - cgpu->utility = cgpu->accepted / dev_runtime * 60; - - if (cgpu->deven != DEV_DISABLED) - enabled = (char *)YES; - else - enabled = (char *)NO; - - status = (char *)status2str(cgpu->status); - - root = api_add_int(root, "ASC", &asc, false); - root = api_add_string(root, "Name", cgpu->drv->name, false); - root = api_add_int(root, "ID", &(cgpu->device_id), false); - root = api_add_string(root, "Enabled", enabled, false); - root = api_add_string(root, "Status", status, false); - root = api_add_temp(root, "Temperature", &temp, false); - double mhs = cgpu->total_mhashes / dev_runtime; - root = api_add_mhs(root, "MHS av", &mhs, false); - char mhsname[27]; - sprintf(mhsname, "MHS %ds", opt_log_interval); - root = api_add_mhs(root, mhsname, &(cgpu->rolling), false); - root = api_add_int(root, "Accepted", &(cgpu->accepted), false); - root = api_add_int(root, "Rejected", &(cgpu->rejected), false); - root = api_add_int(root, "Hardware Errors", &(cgpu->hw_errors), false); - root = api_add_utility(root, "Utility", &(cgpu->utility), false); - int last_share_pool = cgpu->last_share_pool_time > 0 ? - cgpu->last_share_pool : -1; - root = api_add_int(root, "Last Share Pool", &last_share_pool, false); - root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false); - root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false); - root = api_add_int64(root, "Diff1 Work", &(cgpu->diff1), false); - root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false); - root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false); - root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false); -#ifdef USE_USBUTILS - root = api_add_bool(root, "No Device", &(cgpu->usbinfo.nodev), false); -#endif - root = api_add_time(root, "Last Valid Work", &(cgpu->last_device_valid_work), false); - double hwp = (cgpu->hw_errors + cgpu->diff1) ? - (double)(cgpu->hw_errors) / (double)(cgpu->hw_errors + cgpu->diff1) : 0; - root = api_add_percent(root, "Device Hardware%", &hwp, false); - double rejp = cgpu->diff1 ? - (double)(cgpu->diff_rejected) / (double)(cgpu->diff1) : 0; - root = api_add_percent(root, "Device Rejected%", &rejp, false); - root = api_add_elapsed(root, "Device Elapsed", &(dev_runtime), false); - - root = print_data(io_data, root, isjson, precom); - } -} -#endif - -#ifdef HAVE_AN_FPGA -static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom) -{ - struct api_data *root = NULL; - char *enabled; - char *status; - int numpga = numpgas(); - - if (numpga > 0 && pga >= 0 && pga < numpga) - { - int dev = pgadevice(pga); - if (dev < 0) // Should never happen - return; - - struct cgpu_info *cgpu = get_devices(dev); - double frequency = 0; - float temp = cgpu->temp; - struct timeval now; - double dev_runtime; - - if (cgpu->dev_start_tv.tv_sec == 0) - dev_runtime = total_secs; - else - { - cgtime(&now); - dev_runtime = tdiff(&now, &(cgpu->dev_start_tv)); - } - - if (dev_runtime < 1.0) - dev_runtime = 1.0; - -#ifdef USE_MODMINER - if (cgpu->drv->drv_id == DRIVER_modminer) - frequency = cgpu->clock; -#endif - - cgpu->utility = cgpu->accepted / dev_runtime * 60; - - if (cgpu->deven != DEV_DISABLED) - enabled = (char *)YES; - else - enabled = (char *)NO; - - status = (char *)status2str(cgpu->status); - - root = api_add_int(root, "PGA", &pga, false); - root = api_add_string(root, "Name", cgpu->drv->name, false); - root = api_add_int(root, "ID", &(cgpu->device_id), false); - root = api_add_string(root, "Enabled", enabled, false); - root = api_add_string(root, "Status", status, false); - root = api_add_temp(root, "Temperature", &temp, false); - double mhs = cgpu->total_mhashes / dev_runtime; - root = api_add_mhs(root, "MHS av", &mhs, false); - char mhsname[27]; - sprintf(mhsname, "MHS %ds", opt_log_interval); - root = api_add_mhs(root, mhsname, &(cgpu->rolling), false); - root = api_add_int(root, "Accepted", &(cgpu->accepted), false); - root = api_add_int(root, "Rejected", &(cgpu->rejected), false); - root = api_add_int(root, "Hardware Errors", &(cgpu->hw_errors), false); - root = api_add_utility(root, "Utility", &(cgpu->utility), false); - int last_share_pool = cgpu->last_share_pool_time > 0 ? - cgpu->last_share_pool : -1; - root = api_add_int(root, "Last Share Pool", &last_share_pool, false); - root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false); - root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false); - root = api_add_freq(root, "Frequency", &frequency, false); - root = api_add_int64(root, "Diff1 Work", &(cgpu->diff1), false); - root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false); - root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false); - root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false); -#ifdef USE_USBUTILS - root = api_add_bool(root, "No Device", &(cgpu->usbinfo.nodev), false); -#endif - root = api_add_time(root, "Last Valid Work", &(cgpu->last_device_valid_work), false); - double hwp = (cgpu->hw_errors + cgpu->diff1) ? - (double)(cgpu->hw_errors) / (double)(cgpu->hw_errors + cgpu->diff1) : 0; - root = api_add_percent(root, "Device Hardware%", &hwp, false); - double rejp = cgpu->diff1 ? - (double)(cgpu->diff_rejected) / (double)(cgpu->diff1) : 0; - root = api_add_percent(root, "Device Rejected%", &rejp, false); - root = api_add_elapsed(root, "Device Elapsed", &(dev_runtime), false); - - root = print_data(io_data, root, isjson, precom); - } -} -#endif - -static void devstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - bool io_open = false; - int devcount = 0; - int numasc = 0; - int numpga = 0; - int i; - -#ifdef HAVE_AN_ASIC - numasc = numascs(); -#endif - -#ifdef HAVE_AN_FPGA - numpga = numpgas(); -#endif - - if (numpga == 0 && numasc == 0) - { - message(io_data, MSG_NODEVS, 0, NULL, isjson); - return; - } - - - message(io_data, MSG_DEVS, 0, NULL, isjson); - if (isjson) - io_open = io_add(io_data, COMSTR JSON_DEVS); - -#ifdef HAVE_AN_ASIC - if (numasc > 0) - { - for (i = 0; i < numasc; i++) - { - ascstatus(io_data, i, isjson, isjson && devcount > 0); - - devcount++; - } - } -#endif - -#ifdef HAVE_AN_FPGA - if (numpga > 0) - { - for (i = 0; i < numpga; i++) - { - pgastatus(io_data, i, isjson, isjson && devcount > 0); - - devcount++; - } - } -#endif - - if (isjson && io_open) - io_close(io_data); -} - -static void edevstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - bool io_open = false; - int devcount = 0; - int numasc = 0; - int numpga = 0; - int i; -#ifdef USE_USBUTILS - time_t howoldsec = 0; -#endif - -#ifdef HAVE_AN_ASIC - numasc = numascs(); -#endif - -#ifdef HAVE_AN_FPGA - numpga = numpgas(); -#endif - - if (numpga == 0 && numasc == 0) - { - message(io_data, MSG_NODEVS, 0, NULL, isjson); - return; - } - -#ifdef USE_USBUTILS - if (param && *param) - howoldsec = (time_t)atoi(param); -#endif - - message(io_data, MSG_DEVS, 0, NULL, isjson); - if (isjson) - io_open = io_add(io_data, COMSTR JSON_DEVS); - -#ifdef HAVE_AN_ASIC - if (numasc > 0) - { - for (i = 0; i < numasc; i++) - { -#ifdef USE_USBUTILS - int dev = ascdevice(i); - if (dev < 0) // Should never happen - continue; - - struct cgpu_info *cgpu = get_devices(dev); - if (!cgpu) - continue; - if (cgpu->blacklisted) - continue; - if (cgpu->usbinfo.nodev) - { - if (howoldsec <= 0) - continue; - if ((when - cgpu->usbinfo.last_nodev.tv_sec) >= howoldsec) - continue; - } -#endif - - ascstatus(io_data, i, isjson, isjson && devcount > 0); - - devcount++; - } - } -#endif - -#ifdef HAVE_AN_FPGA - if (numpga > 0) - { - for (i = 0; i < numpga; i++) - { -#ifdef USE_USBUTILS - int dev = pgadevice(i); - if (dev < 0) // Should never happen - continue; - - struct cgpu_info *cgpu = get_devices(dev); - if (!cgpu) - continue; - if (cgpu->blacklisted) - continue; - if (cgpu->usbinfo.nodev) - { - if (howoldsec <= 0) - continue; - if ((when - cgpu->usbinfo.last_nodev.tv_sec) >= howoldsec) - continue; - } -#endif - - pgastatus(io_data, i, isjson, isjson && devcount > 0); - - devcount++; - } - } -#endif - - if (isjson && io_open) - io_close(io_data); -} - -#ifdef HAVE_AN_FPGA -static void pgadev(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - bool io_open = false; - int numpga = numpgas(); - int id; - - if (numpga == 0) - { - message(io_data, MSG_PGANON, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISID, 0, NULL, isjson); - return; - } - - id = atoi(param); - if (id < 0 || id >= numpga) - { - message(io_data, MSG_INVPGA, id, NULL, isjson); - return; - } - - message(io_data, MSG_PGADEV, id, NULL, isjson); - - if (isjson) - io_open = io_add(io_data, COMSTR JSON_PGA); - - pgastatus(io_data, id, isjson, false); - - if (isjson && io_open) - io_close(io_data); -} - -static void pgaenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct cgpu_info *cgpu; - int numpga = numpgas(); - struct thr_info *thr; - int pga; - int id; - int i; - - if (numpga == 0) - { - message(io_data, MSG_PGANON, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISID, 0, NULL, isjson); - return; - } - - id = atoi(param); - if (id < 0 || id >= numpga) - { - message(io_data, MSG_INVPGA, id, NULL, isjson); - return; - } - - int dev = pgadevice(id); - if (dev < 0) // Should never happen - { - message(io_data, MSG_INVPGA, id, NULL, isjson); - return; - } - - cgpu = get_devices(dev); - - applog(LOG_DEBUG, "API: request to pgaenable pgaid %d device %d %s%u", - id, dev, cgpu->drv->name, cgpu->device_id); - - if (cgpu->deven != DEV_DISABLED) - { - message(io_data, MSG_PGALRENA, id, NULL, isjson); - return; - } - -#if 0 /* A DISABLED device wont change status FIXME: should disabling make it WELL? */ - if (cgpu->status != LIFE_WELL) - { - message(io_data, MSG_PGAUNW, id, NULL, isjson); - return; - } -#endif - -#ifdef USE_USBUTILS - if (cgpu->usbinfo.nodev) - { - message(io_data, MSG_PGAUSBNODEV, id, NULL, isjson); - return; - } -#endif - - for (i = 0; i < mining_threads; i++) - { - thr = get_thread(i); - pga = thr->cgpu->cgminer_id; - if (pga == dev) - { - cgpu->deven = DEV_ENABLED; - applog(LOG_DEBUG, "API: Pushing sem post to thread %d", thr->id); - cgsem_post(&thr->sem); - } - } - - message(io_data, MSG_PGAENA, id, NULL, isjson); -} - -static void pgadisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct cgpu_info *cgpu; - int numpga = numpgas(); - int id; - - if (numpga == 0) - { - message(io_data, MSG_PGANON, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISID, 0, NULL, isjson); - return; - } - - id = atoi(param); - if (id < 0 || id >= numpga) - { - message(io_data, MSG_INVPGA, id, NULL, isjson); - return; - } - - int dev = pgadevice(id); - if (dev < 0) // Should never happen - { - message(io_data, MSG_INVPGA, id, NULL, isjson); - return; - } - - cgpu = get_devices(dev); - - applog(LOG_DEBUG, "API: request to pgadisable pgaid %d device %d %s%u", - id, dev, cgpu->drv->name, cgpu->device_id); - - if (cgpu->deven == DEV_DISABLED) - { - message(io_data, MSG_PGALRDIS, id, NULL, isjson); - return; - } - - cgpu->deven = DEV_DISABLED; - - message(io_data, MSG_PGADIS, id, NULL, isjson); -} - -static void pgaidentify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct cgpu_info *cgpu; - struct device_drv *drv; - int numpga = numpgas(); - int id; - - if (numpga == 0) - { - message(io_data, MSG_PGANON, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISID, 0, NULL, isjson); - return; - } - - id = atoi(param); - if (id < 0 || id >= numpga) - { - message(io_data, MSG_INVPGA, id, NULL, isjson); - return; - } - - int dev = pgadevice(id); - if (dev < 0) // Should never happen - { - message(io_data, MSG_INVPGA, id, NULL, isjson); - return; - } - - cgpu = get_devices(dev); - drv = cgpu->drv; - - if (!drv->identify_device) - message(io_data, MSG_PGANOID, id, NULL, isjson); - else - { - drv->identify_device(cgpu); - message(io_data, MSG_PGAIDENT, id, NULL, isjson); - } -} -#endif -static void poolstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - bool io_open = false; - char *status, *lp; - int i; - int hour = 0; - int minute = 0; - int second = 0; - - char lasttime[256] = {0}; - long timediff = 0; - - if (total_pools == 0) - { - message(io_data, MSG_NOPOOL, 0, NULL, isjson); - return; - } - - message(io_data, MSG_POOL, 0, NULL, isjson); - - if (isjson) - io_open = io_add(io_data, COMSTR JSON_POOLS); - - for (i = 0; i < total_pools; i++) - { - struct pool *pool = pools[i]; - - if (pool->removed) - continue; - - switch (pool->enabled) - { - case POOL_DISABLED: - status = (char *)DISABLED; - break; - case POOL_REJECTING: - status = (char *)REJECTING; - break; - case POOL_ENABLED: - if (pool->idle) - status = (char *)DEAD; - else - status = (char *)ALIVE; - break; - default: - status = (char *)UNKNOWN; - break; - } - - if (pool->hdr_path) - lp = (char *)YES; - else - lp = (char *)NO; - - if(pool->last_share_time <= 0) - { - strcpy(lasttime, "0"); - } - else - { - timediff = time(NULL) - pool->last_share_time; - if(timediff < 0) - timediff = 0; - - hour = timediff / 3600; - minute = (timediff % 3600) / 60; - second = (timediff % 3600) % 60; - sprintf(lasttime, "%d:%02d:%02d", hour, minute, second); - } - - root = api_add_int(root, "POOL", &i, false); - root = api_add_escape(root, "URL", pool->rpc_url, false); - root = api_add_string(root, "Status", status, false); - root = api_add_int(root, "Priority", &(pool->prio), false); - root = api_add_int(root, "Quota", &pool->quota, false); - root = api_add_string(root, "Long Poll", lp, false); - root = api_add_uint(root, "Getworks", &(pool->getwork_requested), false); - root = api_add_int64(root, "Accepted", &(pool->accepted), false); - root = api_add_int64(root, "Rejected", &(pool->rejected), false); - //root = api_add_int(root, "Works", &pool->works, false); - root = api_add_uint(root, "Discarded", &(pool->discarded_work), false); - root = api_add_uint(root, "Stale", &(pool->stale_shares), false); - root = api_add_uint(root, "Get Failures", &(pool->getfail_occasions), false); - root = api_add_uint(root, "Remote Failures", &(pool->remotefail_occasions), false); - root = api_add_escape(root, "User", pool->rpc_user, false); - //root = api_add_time(root, "Last Share Time", &(pool->last_share_time), false); - root = api_add_string(root, "Last Share Time", lasttime, false); - root = api_add_string(root, "Diff", pool->diff, false); - root = api_add_int64(root, "Diff1 Shares", &(pool->diff1), false); - if (pool->rpc_proxy) - { - root = api_add_const(root, "Proxy Type", proxytype(pool->rpc_proxytype), false); - root = api_add_escape(root, "Proxy", pool->rpc_proxy, false); - } - else - { - root = api_add_const(root, "Proxy Type", BLANK, false); - root = api_add_const(root, "Proxy", BLANK, false); - } - root = api_add_diff(root, "Difficulty Accepted", &(pool->diff_accepted), false); - root = api_add_diff(root, "Difficulty Rejected", &(pool->diff_rejected), false); - root = api_add_diff(root, "Difficulty Stale", &(pool->diff_stale), false); - root = api_add_diff(root, "Last Share Difficulty", &(pool->last_share_diff), false); - root = api_add_bool(root, "Has Stratum", &(pool->has_stratum), false); - root = api_add_bool(root, "Stratum Active", &(pool->stratum_active), false); - if (pool->stratum_active) - root = api_add_escape(root, "Stratum URL", pool->stratum_url, false); - else - root = api_add_const(root, "Stratum URL", BLANK, false); - root = api_add_bool(root, "Has GBT", &(pool->has_gbt), false); - root = api_add_uint64(root, "Best Share", &(pool->best_diff), true); - double rejp = (pool->diff_accepted + pool->diff_rejected + pool->diff_stale) ? - (double)(pool->diff_rejected) / (double)(pool->diff_accepted + pool->diff_rejected + pool->diff_stale) : 0; - root = api_add_percent(root, "Pool Rejected%", &rejp, false); - double stalep = (pool->diff_accepted + pool->diff_rejected + pool->diff_stale) ? - (double)(pool->diff_stale) / (double)(pool->diff_accepted + pool->diff_rejected + pool->diff_stale) : 0; - root = api_add_percent(root, "Pool Stale%", &stalep, false); - - root = print_data(io_data, root, isjson, isjson && (i > 0)); - } - - if (isjson && io_open) - io_close(io_data); -} - -static double getAVGhashrate() -{ - return (total_mhashes_done - new_total_mhashes_done)/ 1000 / (total_secs - new_total_secs); -} - -static void lcddisplay(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - bool io_open = false; - char *status, *lp; - double ghs; - - char szindex[32] = {0}; - char szpool[32] = {0}; - char szuser[32] = {0}; - - struct pool *pool = current_pool(); - - message(io_data, MSG_POOL, 0, NULL, isjson); - - if (isjson) - io_open = io_add(io_data, COMSTR JSON_POOLS); - - ghs = getAVGhashrate(); - - strcpy(szindex, "0"); - root = api_add_string(root, "LCD", szindex, false); - - root = api_add_string(root, "GHS 5s", displayed_hash_rate, false); - root = api_add_mhs(root, "GHSavg", &(ghs), false); - - if(pool == NULL) - { - strcpy(szpool, "no"); - strcpy(szuser, "no"); - root = api_add_string(root, "pool", szpool, false); - root = api_add_string(root, "user", szuser, false); - } - else - { - root = api_add_string(root, "pool", pool->rpc_url, false); - root = api_add_string(root, "user", pool->rpc_user, false); - } - - root = print_data(io_data, root, isjson, isjson); - - if (isjson && io_open) - io_close(io_data); -} - -static void summary(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - bool io_open; - double utility, ghs, work_utility; - - message(io_data, MSG_SUMM, 0, NULL, isjson); - io_open = io_add(io_data, isjson ? COMSTR JSON_SUMMARY : _SUMMARY COMSTR); - - // stop hashmeter() changing some while copying - mutex_lock(&hash_lock); - total_diff1 = total_diff_accepted + total_diff_rejected + total_diff_stale; - - utility = total_accepted / ( total_secs ? total_secs : 1 ) * 60; - - ghs = getAVGhashrate(); - - work_utility = total_diff1 / ( total_secs ? total_secs : 1 ) * 60; - - root = api_add_elapsed(root, "Elapsed", &(total_secs), true); - - root = api_add_string(root, "GHS 5s", displayed_hash_rate, false); - root = api_add_mhs(root, "GHS av", &(ghs), false); - root = api_add_uint(root, "Found Blocks", &(found_blocks), true); - root = api_add_int64(root, "Getworks", &(total_getworks), true); - root = api_add_int64(root, "Accepted", &(total_accepted), true); - root = api_add_int64(root, "Rejected", &(total_rejected), true); - root = api_add_int(root, "Hardware Errors", &(hw_errors), true); - root = api_add_utility(root, "Utility", &(utility), false); - root = api_add_int64(root, "Discarded", &(total_discarded), true); - root = api_add_int64(root, "Stale", &(total_stale), true); - root = api_add_uint(root, "Get Failures", &(total_go), true); - root = api_add_uint(root, "Local Work", &(local_work), true); - root = api_add_uint(root, "Remote Failures", &(total_ro), true); - root = api_add_uint(root, "Network Blocks", &(new_blocks), true); - root = api_add_mhtotal(root, "Total MH", &(total_mhashes_done), true); - root = api_add_utility(root, "Work Utility", &(work_utility), false); - root = api_add_diff(root, "Difficulty Accepted", &(total_diff_accepted), true); - root = api_add_diff(root, "Difficulty Rejected", &(total_diff_rejected), true); - root = api_add_diff(root, "Difficulty Stale", &(total_diff_stale), true); - root = api_add_uint64(root, "Best Share", &(best_diff), true); - double hwp = (hw_errors + total_diff1) ? - (double)(hw_errors) / (double)(hw_errors + total_diff1) : 0; - root = api_add_percent(root, "Device Hardware%", &hwp, false); - double rejp = total_diff1 ? - (double)(total_diff_rejected) / (double)(total_diff1) : 0; - root = api_add_percent(root, "Device Rejected%", &rejp, false); - double prejp = (total_diff_accepted + total_diff_rejected + total_diff_stale) ? - (double)(total_diff_rejected) / (double)(total_diff_accepted + total_diff_rejected + total_diff_stale) : 0; - root = api_add_percent(root, "Pool Rejected%", &prejp, false); - double stalep = (total_diff_accepted + total_diff_rejected + total_diff_stale) ? - (double)(total_diff_stale) / (double)(total_diff_accepted + total_diff_rejected + total_diff_stale) : 0; - root = api_add_percent(root, "Pool Stale%", &stalep, false); - root = api_add_time(root, "Last getwork", &last_getwork, false); - - mutex_unlock(&hash_lock); - - root = print_data(io_data, root, isjson, false); - if (isjson && io_open) - io_close(io_data); -} - -static void noncenum(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - bool io_open; - - message(io_data, MSG_NONCE_NUM, 0, NULL, isjson); - io_open = io_add(io_data, isjson ? COMSTR JSON_NONCENUM : _NONCENUM COMSTR); - - root = api_add_string(root, "10min nonce",nonce_num10_string, false); - root = api_add_string(root, "30min nonce",nonce_num30_string , false); - root = api_add_string(root, "60min nonce",nonce_num60_string , false); - - root = print_data(io_data, root, isjson, false); - if (isjson && io_open) - io_close(io_data); -} - - -static void pgacount(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - bool io_open; - int count = 0; - -#ifdef HAVE_AN_FPGA - count = numpgas(); -#endif - - message(io_data, MSG_NUMPGA, 0, NULL, isjson); - io_open = io_add(io_data, isjson ? COMSTR JSON_PGAS : _PGAS COMSTR); - - root = api_add_int(root, "Count", &count, false); - - root = print_data(io_data, root, isjson, false); - if (isjson && io_open) - io_close(io_data); -} - -static void switchpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct pool *pool; - int id; - - if (total_pools == 0) - { - message(io_data, MSG_NOPOOL, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISPID, 0, NULL, isjson); - return; - } - - id = atoi(param); - cg_rlock(&control_lock); - if (id < 0 || id >= total_pools) - { - cg_runlock(&control_lock); - message(io_data, MSG_INVPID, id, NULL, isjson); - return; - } - - pool = pools[id]; - pool->enabled = POOL_ENABLED; - cg_runlock(&control_lock); - switch_pools(pool); - - message(io_data, MSG_SWITCHP, id, NULL, isjson); -} - -static void copyadvanceafter(char ch, char **param, char **buf) -{ -#define src_p (*param) -#define dst_b (*buf) - - while (*src_p && *src_p != ch) - { - if (*src_p == '\\' && *(src_p+1) != '\0') - src_p++; - - *(dst_b++) = *(src_p++); - } - if (*src_p) - src_p++; - - *(dst_b++) = '\0'; -} - -static bool pooldetails(char *param, char **url, char **user, char **pass) -{ - char *ptr, *buf; - - ptr = buf = cgmalloc(strlen(param)+1); - - *url = buf; - - // copy url - copyadvanceafter(',', ¶m, &buf); - - if (!(*param)) // missing user - goto exitsama; - - *user = buf; - - // copy user - copyadvanceafter(',', ¶m, &buf); - - if (!*param) // missing pass - goto exitsama; - - *pass = buf; - - // copy pass - copyadvanceafter(',', ¶m, &buf); - - return true; - -exitsama: - free(ptr); - return false; -} - -static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - char *url, *user, *pass; - struct pool *pool; - char *ptr; - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISPDP, 0, NULL, isjson); - return; - } - - if (!pooldetails(param, &url, &user, &pass)) - { - ptr = escape_string(param, isjson); - message(io_data, MSG_INVPDP, 0, ptr, isjson); - if (ptr != param) - free(ptr); - ptr = NULL; - return; - } - - pool = add_pool(); - detect_stratum(pool, url); - add_pool_details(pool, true, url, user, pass); - - ptr = escape_string(url, isjson); - message(io_data, MSG_ADDPOOL, pool->pool_no, ptr, isjson); - if (ptr != url) - free(ptr); - ptr = NULL; -} - -static void enablepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct pool *pool; - int id; - - if (total_pools == 0) - { - message(io_data, MSG_NOPOOL, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISPID, 0, NULL, isjson); - return; - } - - id = atoi(param); - if (id < 0 || id >= total_pools) - { - message(io_data, MSG_INVPID, id, NULL, isjson); - return; - } - - pool = pools[id]; - if (pool->enabled == POOL_ENABLED) - { - message(io_data, MSG_ALRENAP, id, NULL, isjson); - return; - } - - pool->enabled = POOL_ENABLED; - if (pool->prio < current_pool()->prio) - switch_pools(pool); - - message(io_data, MSG_ENAPOOL, id, NULL, isjson); -} - -static void poolpriority(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - char *ptr, *next; - int i, pr, prio = 0; - - // TODO: all cgminer code needs a mutex added everywhere for change - // access to total_pools and also parts of the pools[] array, - // just copying total_pools here wont solve that - - if (total_pools == 0) - { - message(io_data, MSG_NOPOOL, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISPID, 0, NULL, isjson); - return; - } - - bool pools_changed[total_pools]; - int new_prio[total_pools]; - for (i = 0; i < total_pools; ++i) - pools_changed[i] = false; - - next = param; - while (next && *next) - { - ptr = next; - next = strchr(ptr, ','); - if (next) - *(next++) = '\0'; - - i = atoi(ptr); - if (i < 0 || i >= total_pools) - { - message(io_data, MSG_INVPID, i, NULL, isjson); - return; - } - - if (pools_changed[i]) - { - message(io_data, MSG_DUPPID, i, NULL, isjson); - return; - } - - pools_changed[i] = true; - new_prio[i] = prio++; - } - - // Only change them if no errors - for (i = 0; i < total_pools; i++) - { - if (pools_changed[i]) - pools[i]->prio = new_prio[i]; - } - - // In priority order, cycle through the unchanged pools and append them - for (pr = 0; pr < total_pools; pr++) - for (i = 0; i < total_pools; i++) - { - if (!pools_changed[i] && pools[i]->prio == pr) - { - pools[i]->prio = prio++; - pools_changed[i] = true; - break; - } - } - - if (current_pool()->prio) - switch_pools(NULL); - - message(io_data, MSG_POOLPRIO, 0, NULL, isjson); -} - -static void poolquota(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct pool *pool; - int quota, id; - char *comma; - - if (total_pools == 0) - { - message(io_data, MSG_NOPOOL, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISPID, 0, NULL, isjson); - return; - } - - comma = strchr(param, ','); - if (!comma) - { - message(io_data, MSG_CONVAL, 0, param, isjson); - return; - } - - *(comma++) = '\0'; - - id = atoi(param); - if (id < 0 || id >= total_pools) - { - message(io_data, MSG_INVPID, id, NULL, isjson); - return; - } - pool = pools[id]; - - quota = atoi(comma); - if (quota < 0) - { - message(io_data, MSG_INVNEG, quota, pool->rpc_url, isjson); - return; - } - - pool->quota = quota; - adjust_quota_gcd(); - message(io_data, MSG_SETQUOTA, quota, pool->rpc_url, isjson); -} - -static void disablepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct pool *pool; - int id; - - if (total_pools == 0) - { - message(io_data, MSG_NOPOOL, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISPID, 0, NULL, isjson); - return; - } - - id = atoi(param); - if (id < 0 || id >= total_pools) - { - message(io_data, MSG_INVPID, id, NULL, isjson); - return; - } - - pool = pools[id]; - if (pool->enabled == POOL_DISABLED) - { - message(io_data, MSG_ALRDISP, id, NULL, isjson); - return; - } - - if (enabled_pools <= 1) - { - message(io_data, MSG_DISLASTP, id, NULL, isjson); - return; - } - - pool->enabled = POOL_DISABLED; - if (pool == current_pool()) - switch_pools(NULL); - - message(io_data, MSG_DISPOOL, id, NULL, isjson); -} - -static void removepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct pool *pool; - char *rpc_url; - bool dofree = false; - int id; - - if (total_pools == 0) - { - message(io_data, MSG_NOPOOL, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISPID, 0, NULL, isjson); - return; - } - - id = atoi(param); - if (id < 0 || id >= total_pools) - { - message(io_data, MSG_INVPID, id, NULL, isjson); - return; - } - - if (total_pools <= 1) - { - message(io_data, MSG_REMLASTP, id, NULL, isjson); - return; - } - - pool = pools[id]; - if (pool == current_pool()) - switch_pools(NULL); - - if (pool == current_pool()) - { - message(io_data, MSG_ACTPOOL, id, NULL, isjson); - return; - } - - pool->enabled = POOL_DISABLED; - rpc_url = escape_string(pool->rpc_url, isjson); - if (rpc_url != pool->rpc_url) - dofree = true; - - remove_pool(pool); - - message(io_data, MSG_REMPOOL, id, rpc_url, isjson); - - if (dofree) - free(rpc_url); - rpc_url = NULL; -} - -void doquit(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - if (isjson) - io_put(io_data, JSON_ACTION JSON_BYE); - else - io_put(io_data, _BYE); - - bye = true; - do_a_quit = true; -} - -void dorestart(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - if (isjson) - io_put(io_data, JSON_ACTION JSON_RESTART); - else - io_put(io_data, _RESTART); - - bye = true; - do_a_restart = true; -} - -void privileged(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - message(io_data, MSG_ACCOK, 0, NULL, isjson); -} - -void notifystatus(struct io_data *io_data, int device, struct cgpu_info *cgpu, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - char *reason; - - if (cgpu->device_last_not_well == 0) - reason = REASON_NONE; - else - switch(cgpu->device_not_well_reason) - { - case REASON_THREAD_FAIL_INIT: - reason = REASON_THREAD_FAIL_INIT_STR; - break; - case REASON_THREAD_ZERO_HASH: - reason = REASON_THREAD_ZERO_HASH_STR; - break; - case REASON_THREAD_FAIL_QUEUE: - reason = REASON_THREAD_FAIL_QUEUE_STR; - break; - case REASON_DEV_SICK_IDLE_60: - reason = REASON_DEV_SICK_IDLE_60_STR; - break; - case REASON_DEV_DEAD_IDLE_600: - reason = REASON_DEV_DEAD_IDLE_600_STR; - break; - case REASON_DEV_NOSTART: - reason = REASON_DEV_NOSTART_STR; - break; - case REASON_DEV_OVER_HEAT: - reason = REASON_DEV_OVER_HEAT_STR; - break; - case REASON_DEV_THERMAL_CUTOFF: - reason = REASON_DEV_THERMAL_CUTOFF_STR; - break; - case REASON_DEV_COMMS_ERROR: - reason = REASON_DEV_COMMS_ERROR_STR; - break; - default: - reason = REASON_UNKNOWN_STR; - break; - } - - // ALL counters (and only counters) must start the name with a '*' - // Simplifies future external support for identifying new counters - root = api_add_int(root, "NOTIFY", &device, false); - root = api_add_string(root, "Name", cgpu->drv->name, false); - root = api_add_int(root, "ID", &(cgpu->device_id), false); - root = api_add_time(root, "Last Well", &(cgpu->device_last_well), false); - root = api_add_time(root, "Last Not Well", &(cgpu->device_last_not_well), false); - root = api_add_string(root, "Reason Not Well", reason, false); - root = api_add_int(root, "*Thread Fail Init", &(cgpu->thread_fail_init_count), false); - root = api_add_int(root, "*Thread Zero Hash", &(cgpu->thread_zero_hash_count), false); - root = api_add_int(root, "*Thread Fail Queue", &(cgpu->thread_fail_queue_count), false); - root = api_add_int(root, "*Dev Sick Idle 60s", &(cgpu->dev_sick_idle_60_count), false); - root = api_add_int(root, "*Dev Dead Idle 600s", &(cgpu->dev_dead_idle_600_count), false); - root = api_add_int(root, "*Dev Nostart", &(cgpu->dev_nostart_count), false); - root = api_add_int(root, "*Dev Over Heat", &(cgpu->dev_over_heat_count), false); - root = api_add_int(root, "*Dev Thermal Cutoff", &(cgpu->dev_thermal_cutoff_count), false); - root = api_add_int(root, "*Dev Comms Error", &(cgpu->dev_comms_error_count), false); - root = api_add_int(root, "*Dev Throttle", &(cgpu->dev_throttle_count), false); - - root = print_data(io_data, root, isjson, isjson && (device > 0)); -} - -static void notify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, char group) -{ - struct cgpu_info *cgpu; - bool io_open = false; - int i; - - if (total_devices == 0) - { - message(io_data, MSG_NODEVS, 0, NULL, isjson); - return; - } - - message(io_data, MSG_NOTIFY, 0, NULL, isjson); - - if (isjson) - io_open = io_add(io_data, COMSTR JSON_NOTIFY); - - for (i = 0; i < total_devices; i++) - { - cgpu = get_devices(i); - notifystatus(io_data, i, cgpu, isjson, group); - } - - if (isjson && io_open) - io_close(io_data); -} - -static void devdetails(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - bool io_open = false; - struct cgpu_info *cgpu; - int i; - - if (total_devices == 0) - { - message(io_data, MSG_NODEVS, 0, NULL, isjson); - return; - } - - message(io_data, MSG_DEVDETAILS, 0, NULL, isjson); - - if (isjson) - io_open = io_add(io_data, COMSTR JSON_DEVDETAILS); - - for (i = 0; i < total_devices; i++) - { - cgpu = get_devices(i); - - root = api_add_int(root, "DEVDETAILS", &i, false); - root = api_add_string(root, "Name", cgpu->drv->name, false); - root = api_add_int(root, "ID", &(cgpu->device_id), false); - root = api_add_string(root, "Driver", cgpu->drv->dname, false); - root = api_add_const(root, "Kernel", cgpu->kname ? : BLANK, false); - root = api_add_const(root, "Model", cgpu->name ? : BLANK, false); - root = api_add_const(root, "Device Path", cgpu->device_path ? : BLANK, false); - - root = print_data(io_data, root, isjson, isjson && (i > 0)); - } - - if (isjson && io_open) - io_close(io_data); -} - -void dosave(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - char filename[PATH_MAX]; - FILE *fcfg; - char *ptr; - - if (param == NULL || *param == '\0') - { - default_save_file(filename); - param = filename; - } - - fcfg = fopen(param, "w"); - if (!fcfg) - { - ptr = escape_string(param, isjson); - message(io_data, MSG_BADFN, 0, ptr, isjson); - if (ptr != param) - free(ptr); - ptr = NULL; - return; - } - - write_config(fcfg); - fclose(fcfg); - - ptr = escape_string(param, isjson); - message(io_data, MSG_SAVED, 0, ptr, isjson); - if (ptr != param) - free(ptr); - ptr = NULL; -} - -static int itemstats(struct io_data *io_data, int i, char *id, struct cgminer_stats *stats, struct cgminer_pool_stats *pool_stats, struct api_data *extra, struct cgpu_info *cgpu, bool isjson) -{ - struct api_data *root = NULL; - double ghs; - - - ghs = getAVGhashrate(); - - root = api_add_int(root, "STATS", &i, false); - root = api_add_string(root, "ID", id, false); - root = api_add_elapsed(root, "Elapsed", &(total_secs), false); - root = api_add_uint32(root, "Calls", &(stats->getwork_calls), false); - root = api_add_timeval(root, "Wait", &(stats->getwork_wait), false); - root = api_add_timeval(root, "Max", &(stats->getwork_wait_max), false); - root = api_add_timeval(root, "Min", &(stats->getwork_wait_min), false); - root = api_add_string(root, "GHS 5s", displayed_hash_rate, false); - - root = api_add_mhs(root, "GHS av", &(ghs), false); - - /* - if (pool_stats) { - root = api_add_uint32(root, "Pool Calls", &(pool_stats->getwork_calls), false); - root = api_add_uint32(root, "Pool Attempts", &(pool_stats->getwork_attempts), false); - root = api_add_timeval(root, "Pool Wait", &(pool_stats->getwork_wait), false); - root = api_add_timeval(root, "Pool Max", &(pool_stats->getwork_wait_max), false); - root = api_add_timeval(root, "Pool Min", &(pool_stats->getwork_wait_min), false); - root = api_add_double(root, "Pool Av", &(pool_stats->getwork_wait_rolling), false); - root = api_add_bool(root, "Work Had Roll Time", &(pool_stats->hadrolltime), false); - root = api_add_bool(root, "Work Can Roll", &(pool_stats->canroll), false); - root = api_add_bool(root, "Work Had Expire", &(pool_stats->hadexpire), false); - root = api_add_uint32(root, "Work Roll Time", &(pool_stats->rolltime), false); - root = api_add_diff(root, "Work Diff", &(pool_stats->last_diff), false); - root = api_add_diff(root, "Min Diff", &(pool_stats->min_diff), false); - root = api_add_diff(root, "Max Diff", &(pool_stats->max_diff), false); - root = api_add_uint32(root, "Min Diff Count", &(pool_stats->min_diff_count), false); - root = api_add_uint32(root, "Max Diff Count", &(pool_stats->max_diff_count), false); - root = api_add_uint64(root, "Times Sent", &(pool_stats->times_sent), false); - root = api_add_uint64(root, "Bytes Sent", &(pool_stats->bytes_sent), false); - root = api_add_uint64(root, "Times Recv", &(pool_stats->times_received), false); - root = api_add_uint64(root, "Bytes Recv", &(pool_stats->bytes_received), false); - root = api_add_uint64(root, "Net Bytes Sent", &(pool_stats->net_bytes_sent), false); - root = api_add_uint64(root, "Net Bytes Recv", &(pool_stats->net_bytes_received), false); - }*/ - - if (extra) - root = api_add_extra(root, extra); - - if (cgpu) - { -#ifdef USE_USBUTILS - char details[256]; - - if (cgpu->usbinfo.pipe_count) - snprintf(details, sizeof(details), - "%"PRIu64" %"PRIu64"/%"PRIu64"/%"PRIu64" %lu", - cgpu->usbinfo.pipe_count, - cgpu->usbinfo.clear_err_count, - cgpu->usbinfo.retry_err_count, - cgpu->usbinfo.clear_fail_count, - (unsigned long)(cgpu->usbinfo.last_pipe)); - else - strcpy(details, "0"); - - root = api_add_string(root, "USB Pipe", details, true); - - /* - snprintf(details, sizeof(details), - "r%"PRIu64" %.6f w%"PRIu64" %.6f", - cgpu->usbinfo.read_delay_count, - cgpu->usbinfo.total_read_delay, - cgpu->usbinfo.write_delay_count, - cgpu->usbinfo.total_write_delay); - - root = api_add_string(root, "USB Delay", details, true); - - if (cgpu->usbinfo.usb_tmo[0].count == 0 && - cgpu->usbinfo.usb_tmo[1].count == 0 && - cgpu->usbinfo.usb_tmo[2].count == 0) { - snprintf(details, sizeof(details), - "%"PRIu64" 0", cgpu->usbinfo.tmo_count); - } else { - snprintf(details, sizeof(details), - "%"PRIu64" %d=%d/%d/%d/%"PRIu64"/%"PRIu64 - " %d=%d/%d/%d/%"PRIu64"/%"PRIu64 - " %d=%d/%d/%d/%"PRIu64"/%"PRIu64" ", - cgpu->usbinfo.tmo_count, - USB_TMO_0, cgpu->usbinfo.usb_tmo[0].count, - cgpu->usbinfo.usb_tmo[0].min_tmo, - cgpu->usbinfo.usb_tmo[0].max_tmo, - cgpu->usbinfo.usb_tmo[0].total_over, - cgpu->usbinfo.usb_tmo[0].total_tmo, - USB_TMO_1, cgpu->usbinfo.usb_tmo[1].count, - cgpu->usbinfo.usb_tmo[1].min_tmo, - cgpu->usbinfo.usb_tmo[1].max_tmo, - cgpu->usbinfo.usb_tmo[1].total_over, - cgpu->usbinfo.usb_tmo[1].total_tmo, - USB_TMO_2, cgpu->usbinfo.usb_tmo[2].count, - cgpu->usbinfo.usb_tmo[2].min_tmo, - cgpu->usbinfo.usb_tmo[2].max_tmo, - cgpu->usbinfo.usb_tmo[2].total_over, - cgpu->usbinfo.usb_tmo[2].total_tmo); - } - - root = api_add_string(root, "USB tmo", details, true);*/ -#endif - } - - root = print_data(io_data, root, isjson, isjson && (i > 0)); - - return ++i; -} - -static void minerstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct cgpu_info *cgpu; - bool io_open = false; - struct api_data *extra; - char id[20]; - int i, j; - - message(io_data, MSG_MINESTATS, 0, NULL, isjson); - - if (isjson) - io_open = io_add(io_data, COMSTR JSON_MINESTATS); - - i = 0; - for (j = 0; j < total_devices; j++) - { - cgpu = get_devices(j); - - if (cgpu && cgpu->drv) - { - if (cgpu->drv->get_api_stats) - extra = cgpu->drv->get_api_stats(cgpu); - else - extra = NULL; - - sprintf(id, "%s%d", cgpu->drv->name, cgpu->device_id); - i = itemstats(io_data, i, id, &(cgpu->cgminer_stats), NULL, extra, cgpu, isjson); - } - } - - if (isjson && io_open) - io_close(io_data); -} - -static void minerestats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct cgpu_info *cgpu; - bool io_open = false; - struct api_data *extra; - char id[20]; - int i, j; -#ifdef USE_USBUTILS - time_t howoldsec = 0; - - if (param && *param) - howoldsec = (time_t)atoi(param); -#endif - - message(io_data, MSG_MINESTATS, 0, NULL, isjson); - if (isjson) - io_open = io_add(io_data, COMSTR JSON_MINESTATS); - - i = 0; - for (j = 0; j < total_devices; j++) - { - cgpu = get_devices(j); - if (!cgpu) - continue; -#ifdef USE_USBUTILS - if (cgpu->blacklisted) - continue; - if (cgpu->usbinfo.nodev) - { - if (howoldsec <= 0) - continue; - if ((when - cgpu->usbinfo.last_nodev.tv_sec) >= howoldsec) - continue; - } -#endif - if (cgpu->drv) - { - if (cgpu->drv->get_api_stats) - extra = cgpu->drv->get_api_stats(cgpu); - else - extra = NULL; - - sprintf(id, "%s%d", cgpu->drv->name, cgpu->device_id); - i = itemstats(io_data, i, id, &(cgpu->cgminer_stats), NULL, extra, cgpu, isjson); - } - } - - if (isjson && io_open) - io_close(io_data); -} - -static void failoveronly(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - message(io_data, MSG_DEPRECATED, 0, param, isjson); - - - - - -} - -static void minecoin(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - bool io_open; - - message(io_data, MSG_MINECOIN, 0, NULL, isjson); - io_open = io_add(io_data, isjson ? COMSTR JSON_MINECOIN : _MINECOIN COMSTR); - - root = api_add_const(root, "Hash Method", SHA256STR, false); - - cg_rlock(&ch_lock); - root = api_add_timeval(root, "Current Block Time", &block_timeval, true); - root = api_add_string(root, "Current Block Hash", current_hash, true); - cg_runlock(&ch_lock); - - root = api_add_bool(root, "LP", &have_longpoll, false); - root = api_add_diff(root, "Network Difficulty", ¤t_diff, true); - - root = print_data(io_data, root, isjson, false); - if (isjson && io_open) - io_close(io_data); -} - -static void debugstate(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - bool io_open; - - if (param == NULL) - param = (char *)BLANK; - else - *param = tolower(*param); - - switch(*param) - { - case 's': - opt_realquiet = true; - break; - case 'q': - opt_quiet ^= true; - break; - case 'v': - opt_log_output ^= true; - if (opt_log_output) - opt_quiet = false; - break; - case 'd': - opt_debug ^= true; - opt_log_output = opt_debug; - if (opt_debug) - opt_quiet = false; - break; - case 'r': - opt_protocol ^= true; - if (opt_protocol) - opt_quiet = false; - break; - case 'p': - want_per_device_stats ^= true; - opt_log_output = want_per_device_stats; - break; - case 'n': - opt_log_output = false; - opt_debug = false; - opt_quiet = false; - opt_protocol = false; - want_per_device_stats = false; - opt_worktime = false; - break; - case 'w': - opt_worktime ^= true; - break; -#ifdef _MEMORY_DEBUG - case 'y': - cgmemspeedup(); - break; - case 'z': - cgmemrpt(); - break; -#endif - default: - // anything else just reports the settings - break; - } - - message(io_data, MSG_DEBUGSET, 0, NULL, isjson); - io_open = io_add(io_data, isjson ? COMSTR JSON_DEBUGSET : _DEBUGSET COMSTR); - - root = api_add_bool(root, "Silent", &opt_realquiet, false); - root = api_add_bool(root, "Quiet", &opt_quiet, false); - root = api_add_bool(root, "Verbose", &opt_log_output, false); - root = api_add_bool(root, "Debug", &opt_debug, false); - root = api_add_bool(root, "RPCProto", &opt_protocol, false); - root = api_add_bool(root, "PerDevice", &want_per_device_stats, false); - root = api_add_bool(root, "WorkTime", &opt_worktime, false); - - root = print_data(io_data, root, isjson, false); - if (isjson && io_open) - io_close(io_data); -} - -static void setconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - if (!strcasecmp(param, "queue") || ! strcasecmp(param, "scantime") || !strcasecmp(param, "expiry")) - - message(io_data, MSG_DEPRECATED, 0, param, isjson); - - - message(io_data, MSG_UNKCON, 0, param, isjson); - -} - -static void usbstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - -#ifdef USE_USBUTILS - bool io_open = false; - int count = 0; - - root = api_usb_stats(&count); -#endif - - if (!root) - { - message(io_data, MSG_NOUSTA, 0, NULL, isjson); - return; - } - -#ifdef USE_USBUTILS - message(io_data, MSG_USBSTA, 0, NULL, isjson); - - if (isjson) - io_open = io_add(io_data, COMSTR JSON_USBSTATS); - - root = print_data(io_data, root, isjson, false); - - while (42) - { - root = api_usb_stats(&count); - if (!root) - break; - - root = print_data(io_data, root, isjson, isjson); - } - - if (isjson && io_open) - io_close(io_data); -#endif -} - -#ifdef HAVE_AN_FPGA -static void pgaset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct cgpu_info *cgpu; - struct device_drv *drv; - char buf[TMPBUFSIZ]; - int numpga = numpgas(); - - if (numpga == 0) - { - message(io_data, MSG_PGANON, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISID, 0, NULL, isjson); - return; - } - - char *opt = strchr(param, ','); - if (opt) - *(opt++) = '\0'; - if (!opt || !*opt) - { - message(io_data, MSG_MISPGAOPT, 0, NULL, isjson); - return; - } - - int id = atoi(param); - if (id < 0 || id >= numpga) - { - message(io_data, MSG_INVPGA, id, NULL, isjson); - return; - } - - int dev = pgadevice(id); - if (dev < 0) // Should never happen - { - message(io_data, MSG_INVPGA, id, NULL, isjson); - return; - } - - cgpu = get_devices(dev); - drv = cgpu->drv; - - char *set = strchr(opt, ','); - if (set) - *(set++) = '\0'; - - if (!drv->set_device) - message(io_data, MSG_PGANOSET, id, NULL, isjson); - else - { - char *ret = drv->set_device(cgpu, opt, set, buf); - if (ret) - { - if (strcasecmp(opt, "help") == 0) - message(io_data, MSG_PGAHELP, id, ret, isjson); - else - message(io_data, MSG_PGASETERR, id, ret, isjson); - } - else - message(io_data, MSG_PGASETOK, id, NULL, isjson); - } -} -#endif - -static void dozero(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - if (param == NULL || *param == '\0') - { - message(io_data, MSG_ZERMIS, 0, NULL, isjson); - return; - } - - char *sum = strchr(param, ','); - if (sum) - *(sum++) = '\0'; - if (!sum || !*sum) - { - message(io_data, MSG_MISBOOL, 0, NULL, isjson); - return; - } - - bool all = false; - bool bs = false; - if (strcasecmp(param, "all") == 0) - all = true; - else if (strcasecmp(param, "bestshare") == 0) - bs = true; - - if (all == false && bs == false) - { - message(io_data, MSG_ZERINV, 0, param, isjson); - return; - } - - *sum = tolower(*sum); - if (*sum != 't' && *sum != 'f') - { - message(io_data, MSG_INVBOOL, 0, NULL, isjson); - return; - } - - bool dosum = (*sum == 't'); - if (dosum) - print_summary(); - - if (all) - zero_stats(); - if (bs) - zero_bestshare(); - - if (dosum) - message(io_data, MSG_ZERSUM, 0, all ? "All" : "BestShare", isjson); - else - message(io_data, MSG_ZERNOSUM, 0, all ? "All" : "BestShare", isjson); -} - -static void dohotplug(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ -#ifdef USE_USBUTILS - int value; - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISHPLG, 0, NULL, isjson); - return; - } - - value = atoi(param); - if (value < 0 || value > 9999) - { - message(io_data, MSG_INVHPLG, 0, param, isjson); - return; - } - - hotplug_time = value; - - if (value) - message(io_data, MSG_HOTPLUG, value, NULL, isjson); - else - message(io_data, MSG_DISHPLG, 0, NULL, isjson); -#else - message(io_data, MSG_NOHPLG, 0, NULL, isjson); - return; -#endif -} - -#ifdef HAVE_AN_ASIC -static void ascdev(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - bool io_open = false; - int numasc = numascs(); - int id; - - if (numasc == 0) - { - message(io_data, MSG_ASCNON, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISID, 0, NULL, isjson); - return; - } - - id = atoi(param); - if (id < 0 || id >= numasc) - { - message(io_data, MSG_INVASC, id, NULL, isjson); - return; - } - - message(io_data, MSG_ASCDEV, id, NULL, isjson); - - if (isjson) - io_open = io_add(io_data, COMSTR JSON_ASC); - - ascstatus(io_data, id, isjson, false); - - if (isjson && io_open) - io_close(io_data); -} - -static void ascenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct cgpu_info *cgpu; - int numasc = numascs(); - struct thr_info *thr; - int asc; - int id; - int i; - - if (numasc == 0) - { - message(io_data, MSG_ASCNON, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISID, 0, NULL, isjson); - return; - } - - id = atoi(param); - if (id < 0 || id >= numasc) - { - message(io_data, MSG_INVASC, id, NULL, isjson); - return; - } - - int dev = ascdevice(id); - if (dev < 0) // Should never happen - { - message(io_data, MSG_INVASC, id, NULL, isjson); - return; - } - - cgpu = get_devices(dev); - - applog(LOG_DEBUG, "API: request to ascenable ascid %d device %d %s%u", - id, dev, cgpu->drv->name, cgpu->device_id); - - if (cgpu->deven != DEV_DISABLED) - { - message(io_data, MSG_ASCLRENA, id, NULL, isjson); - return; - } - -#if 0 /* A DISABLED device wont change status FIXME: should disabling make it WELL? */ - if (cgpu->status != LIFE_WELL) - { - message(io_data, MSG_ASCUNW, id, NULL, isjson); - return; - } -#endif - -#ifdef USE_USBUTILS - if (cgpu->usbinfo.nodev) - { - message(io_data, MSG_ASCUSBNODEV, id, NULL, isjson); - return; - } -#endif - - for (i = 0; i < mining_threads; i++) - { - thr = get_thread(i); - asc = thr->cgpu->cgminer_id; - if (asc == dev) - { - cgpu->deven = DEV_ENABLED; - applog(LOG_DEBUG, "API: Pushing sem post to thread %d", thr->id); - cgsem_post(&thr->sem); - } - } - - message(io_data, MSG_ASCENA, id, NULL, isjson); -} - -static void ascdisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct cgpu_info *cgpu; - int numasc = numascs(); - int id; - - if (numasc == 0) - { - message(io_data, MSG_ASCNON, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISID, 0, NULL, isjson); - return; - } - - id = atoi(param); - if (id < 0 || id >= numasc) - { - message(io_data, MSG_INVASC, id, NULL, isjson); - return; - } - - int dev = ascdevice(id); - if (dev < 0) // Should never happen - { - message(io_data, MSG_INVASC, id, NULL, isjson); - return; - } - - cgpu = get_devices(dev); - - applog(LOG_DEBUG, "API: request to ascdisable ascid %d device %d %s%u", - id, dev, cgpu->drv->name, cgpu->device_id); - - if (cgpu->deven == DEV_DISABLED) - { - message(io_data, MSG_ASCLRDIS, id, NULL, isjson); - return; - } - - cgpu->deven = DEV_DISABLED; - - message(io_data, MSG_ASCDIS, id, NULL, isjson); -} - -static void ascidentify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) -{ - struct cgpu_info *cgpu; - struct device_drv *drv; - int numasc = numascs(); - int id; - - if (numasc == 0) - { - message(io_data, MSG_ASCNON, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISID, 0, NULL, isjson); - return; - } - - id = atoi(param); - if (id < 0 || id >= numasc) - { - message(io_data, MSG_INVASC, id, NULL, isjson); - return; - } - - int dev = ascdevice(id); - if (dev < 0) // Should never happen - { - message(io_data, MSG_INVASC, id, NULL, isjson); - return; - } - - cgpu = get_devices(dev); - drv = cgpu->drv; - - if (!drv->identify_device) - message(io_data, MSG_ASCNOID, id, NULL, isjson); - else - { - drv->identify_device(cgpu); - message(io_data, MSG_ASCIDENT, id, NULL, isjson); - } -} -#endif - -static void asccount(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - bool io_open; - int count = 0; - -#ifdef HAVE_AN_ASIC - count = numascs(); -#endif - - message(io_data, MSG_NUMASC, 0, NULL, isjson); - io_open = io_add(io_data, isjson ? COMSTR JSON_ASCS : _ASCS COMSTR); - - root = api_add_int(root, "Count", &count, false); - - root = print_data(io_data, root, isjson, false); - if (isjson && io_open) - io_close(io_data); -} - -#ifdef HAVE_AN_ASIC -static void ascset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct cgpu_info *cgpu; - struct device_drv *drv; - char buf[TMPBUFSIZ]; - int numasc = numascs(); - - if (numasc == 0) - { - message(io_data, MSG_ASCNON, 0, NULL, isjson); - return; - } - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISID, 0, NULL, isjson); - return; - } - - char *opt = strchr(param, ','); - if (opt) - *(opt++) = '\0'; - if (!opt || !*opt) - { - message(io_data, MSG_MISASCOPT, 0, NULL, isjson); - return; - } - - int id = atoi(param); - if (id < 0 || id >= numasc) - { - message(io_data, MSG_INVASC, id, NULL, isjson); - return; - } - - int dev = ascdevice(id); - if (dev < 0) // Should never happen - { - message(io_data, MSG_INVASC, id, NULL, isjson); - return; - } - - cgpu = get_devices(dev); - drv = cgpu->drv; - - char *set = strchr(opt, ','); - if (set) - *(set++) = '\0'; - - if (!drv->set_device) - message(io_data, MSG_ASCNOSET, id, NULL, isjson); - else - { - char *ret = drv->set_device(cgpu, opt, set, buf); - if (ret) - { - if (strcasecmp(opt, "help") == 0) - message(io_data, MSG_ASCHELP, id, ret, isjson); - else - message(io_data, MSG_ASCSETERR, id, ret, isjson); - } - else - message(io_data, MSG_ASCSETOK, id, NULL, isjson); - } -} -#endif - -static void lcddata(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) -{ - struct api_data *root = NULL; - struct cgpu_info *cgpu; - bool io_open; - double ghs = 0.0, last_share_diff = 0.0; - float temp = 0.0; - time_t last_share_time = 0; - time_t last_device_valid_work = 0; - struct pool *pool = NULL; - char *rpc_url = "none", *rpc_user = ""; - int i; - - message(io_data, MSG_LCD, 0, NULL, isjson); - io_open = io_add(io_data, isjson ? COMSTR JSON_LCD : _LCD COMSTR); - - // stop hashmeter() changing some while copying - mutex_lock(&hash_lock); - - root = api_add_elapsed(root, "Elapsed", &(total_secs), true); - - ghs = getAVGhashrate(); - - root = api_add_mhs(root, "GHS av", &ghs, true); - ghs = rolling5 / 1000.0; - root = api_add_mhs(root, "GHS 5m", &ghs, true); - ghs = total_rolling / 1000.0; - root = api_add_mhs(root, "GHS 5s", &ghs, true); - - mutex_unlock(&hash_lock); - - temp = 0; - last_device_valid_work = 0; - for (i = 0; i < total_devices; i++) - { - cgpu = get_devices(i); - if (last_device_valid_work == 0 || - last_device_valid_work < cgpu->last_device_valid_work) - last_device_valid_work = cgpu->last_device_valid_work; - if (temp < cgpu->temp) - temp = cgpu->temp; - } - - last_share_time = 0; - last_share_diff = 0; - for (i = 0; i < total_pools; i++) - { - pool = pools[i]; - - if (pool->removed) - continue; - - if (last_share_time == 0 || last_share_time < pool->last_share_time) - { - last_share_time = pool->last_share_time; - last_share_diff = pool->last_share_diff; - } - } - pool = current_pool(); - if (pool) - { - rpc_url = pool->rpc_url; - rpc_user = pool->rpc_user; - } - - root = api_add_temp(root, "Temperature", &temp, false); - root = api_add_diff(root, "Last Share Difficulty", &last_share_diff, false); - root = api_add_time(root, "Last Share Time", &last_share_time, false); - root = api_add_uint64(root, "Best Share", &best_diff, true); - root = api_add_time(root, "Last Valid Work", &last_device_valid_work, false); - root = api_add_uint(root, "Found Blocks", &found_blocks, true); - root = api_add_escape(root, "Current Pool", rpc_url, true); - root = api_add_escape(root, "User", rpc_user, true); - root = print_data(io_data, root, isjson, false); - if (isjson && io_open) - io_close(io_data); -} - -static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group); - -struct CMDS -{ - char *name; - void (*func)(struct io_data *, SOCKETTYPE, char *, bool, char); - bool iswritemode; - bool joinable; -} cmds[] = -{ - { "version", apiversion, false, true }, - { "config", minerconfig, false, true }, - { "devs", devstatus, false, true }, - { "edevs", edevstatus, false, true }, - { "pools", poolstatus, false, true }, - { "summary", summary, false, true }, - { "noncenum", noncenum, false, true }, -#ifdef HAVE_AN_FPGA - { "pga", pgadev, false, false }, - { "pgaenable", pgaenable, true, false }, - { "pgadisable", pgadisable, true, false }, - { "pgaidentify", pgaidentify, true, false }, -#endif - { "pgacount", pgacount, false, true }, - { "switchpool", switchpool, true, false }, - { "addpool", addpool, true, false }, - { "poolpriority", poolpriority, true, false }, - { "poolquota", poolquota, true, false }, - { "enablepool", enablepool, true, false }, - { "disablepool", disablepool, true, false }, - { "removepool", removepool, true, false }, - { "save", dosave, true, false }, - { "quit", doquit, true, false }, - { "privileged", privileged, true, false }, - { "notify", notify, false, true }, - { "devdetails", devdetails, false, true }, - { "restart", dorestart, true, false }, - { "stats", minerstats, false, true }, - { "estats", minerestats, false, true }, - { "check", checkcommand, false, false }, - { "failover-only", failoveronly, true, false }, - { "coin", minecoin, false, true }, - { "debug", debugstate, true, false }, - { "setconfig", setconfig, true, false }, - { "usbstats", usbstats, false, true }, -#ifdef HAVE_AN_FPGA - { "pgaset", pgaset, true, false }, -#endif - { "zero", dozero, true, false }, - { "hotplug", dohotplug, true, false }, -#ifdef HAVE_AN_ASIC - { "asc", ascdev, false, false }, - { "ascenable", ascenable, true, false }, - { "ascdisable", ascdisable, true, false }, - { "ascidentify", ascidentify, true, false }, - { "ascset", ascset, true, false }, -#endif - { "asccount", asccount, false, true }, - { "lcd", lcddisplay, false, true }, - { "lockstats", lockstats, true, true }, - { NULL, NULL, false, false } -}; - -static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group) -{ - struct api_data *root = NULL; - bool io_open; - char cmdbuf[100]; - bool found, access; - int i; - - if (param == NULL || *param == '\0') - { - message(io_data, MSG_MISCHK, 0, NULL, isjson); - return; - } - - found = false; - access = false; - for (i = 0; cmds[i].name != NULL; i++) - { - if (strcmp(cmds[i].name, param) == 0) - { - found = true; - - sprintf(cmdbuf, "|%s|", param); - if (ISPRIVGROUP(group) || strstr(COMMANDS(group), cmdbuf)) - access = true; - - break; - } - } - - message(io_data, MSG_CHECK, 0, NULL, isjson); - io_open = io_add(io_data, isjson ? COMSTR JSON_CHECK : _CHECK COMSTR); - - root = api_add_const(root, "Exists", found ? YES : NO, false); - root = api_add_const(root, "Access", access ? YES : NO, false); - - root = print_data(io_data, root, isjson, false); - if (isjson && io_open) - io_close(io_data); -} - -static void head_join(struct io_data *io_data, char *cmdptr, bool isjson, bool *firstjoin) -{ - char *ptr; - - if (*firstjoin) - { - if (isjson) - io_add(io_data, JSON0); - *firstjoin = false; - } - else - { - if (isjson) - io_add(io_data, JSON_BETWEEN_JOIN); - } - - // External supplied string - ptr = escape_string(cmdptr, isjson); - - if (isjson) - { - io_add(io_data, JSON1); - io_add(io_data, ptr); - io_add(io_data, JSON2); - } - else - { - io_add(io_data, JOIN_CMD); - io_add(io_data, ptr); - io_add(io_data, BETWEEN_JOIN); - } - - if (ptr != cmdptr) - free(ptr); -} - -static void tail_join(struct io_data *io_data, bool isjson) -{ - if (io_data->close) - { - io_add(io_data, JSON_CLOSE); - io_data->close = false; - } - - if (isjson) - { - io_add(io_data, JSON_END); - io_add(io_data, JSON3); - } -} - -static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson) -{ - int count, sendc, res, tosend, len, n; - char *buf = io_data->ptr; - - strcpy(buf, io_data->ptr); - - if (io_data->close) - strcat(buf, JSON_CLOSE); - - if (isjson) - strcat(buf, JSON_END); - - len = strlen(buf); - tosend = len+1; - - applog(LOG_DEBUG, "API: send reply: (%d) '%.10s%s'", tosend, buf, len > 10 ? "..." : BLANK); - - count = sendc = 0; - while (count < 5 && tosend > 0) - { - // allow 50ms per attempt - struct timeval timeout = {0, 50000}; - fd_set wd; - - FD_ZERO(&wd); - FD_SET(c, &wd); - if ((res = select(c + 1, NULL, &wd, NULL, &timeout)) < 1) - { - applog(LOG_WARNING, "API: send select failed (%d)", res); - return; - } - - n = send(c, buf, tosend, 0); - sendc++; - - if (SOCKETFAIL(n)) - { - count++; - if (sock_blocks()) - continue; - - applog(LOG_WARNING, "API: send (%d:%d) failed: %s", len+1, (len+1 - tosend), SOCKERRMSG); - - return; - } - else - { - if (sendc <= 1) - { - if (n == tosend) - applog(LOG_DEBUG, "API: sent all of %d first go", tosend); - else - applog(LOG_DEBUG, "API: sent %d of %d first go", n, tosend); - } - else - { - if (n == tosend) - applog(LOG_DEBUG, "API: sent all of remaining %d (sendc=%d)", tosend, sendc); - else - applog(LOG_DEBUG, "API: sent %d of remaining %d (sendc=%d)", n, tosend, sendc); - } - - tosend -= n; - buf += n; - - if (n == 0) - count++; - } - } -} - -static void tidyup(__maybe_unused void *arg) -{ - mutex_lock(&quit_restart_lock); - - SOCKETTYPE *apisock = (SOCKETTYPE *)arg; - - bye = true; - - if (*apisock != INVSOCK) - { - shutdown(*apisock, SHUT_RDWR); - CLOSESOCKET(*apisock); - *apisock = INVSOCK; - } - - if (ipaccess != NULL) - { - free(ipaccess); - ipaccess = NULL; - } - - io_free(); - - mutex_unlock(&quit_restart_lock); -} - -/* - * Interpret --api-groups G:cmd1:cmd2:cmd3,P:cmd4,*,... - */ -static void setup_groups() -{ - char *api_groups = opt_api_groups ? opt_api_groups : (char *)BLANK; - char *buf, *ptr, *next, *colon; - char group; - char commands[TMPBUFSIZ]; - char cmdbuf[100]; - char *cmd; - bool addstar, did; - int i; - - buf = cgmalloc(strlen(api_groups) + 1); - - strcpy(buf, api_groups); - - next = buf; - // for each group defined - while (next && *next) - { - ptr = next; - next = strchr(ptr, ','); - if (next) - *(next++) = '\0'; - - // Validate the group - if (*(ptr+1) != ':') - { - colon = strchr(ptr, ':'); - if (colon) - *colon = '\0'; - quit(1, "API invalid group name '%s'", ptr); - } - - group = GROUP(*ptr); - if (!VALIDGROUP(group)) - quit(1, "API invalid group name '%c'", *ptr); - - if (group == PRIVGROUP) - quit(1, "API group name can't be '%c'", PRIVGROUP); - - if (group == NOPRIVGROUP) - quit(1, "API group name can't be '%c'", NOPRIVGROUP); - - if (apigroups[GROUPOFFSET(group)].commands != NULL) - quit(1, "API duplicate group name '%c'", *ptr); - - ptr += 2; - - // Validate the command list (and handle '*') - cmd = &(commands[0]); - *(cmd++) = SEPARATOR; - *cmd = '\0'; - addstar = false; - while (ptr && *ptr) - { - colon = strchr(ptr, ':'); - if (colon) - *(colon++) = '\0'; - - if (strcmp(ptr, "*") == 0) - addstar = true; - else - { - did = false; - for (i = 0; cmds[i].name != NULL; i++) - { - if (strcasecmp(ptr, cmds[i].name) == 0) - { - did = true; - break; - } - } - if (did) - { - // skip duplicates - sprintf(cmdbuf, "|%s|", cmds[i].name); - if (strstr(commands, cmdbuf) == NULL) - { - strcpy(cmd, cmds[i].name); - cmd += strlen(cmds[i].name); - *(cmd++) = SEPARATOR; - *cmd = '\0'; - } - } - else - { - quit(1, "API unknown command '%s' in group '%c'", ptr, group); - } - } - - ptr = colon; - } - - // * = allow all non-iswritemode commands - if (addstar) - { - for (i = 0; cmds[i].name != NULL; i++) - { - if (cmds[i].iswritemode == false) - { - // skip duplicates - sprintf(cmdbuf, "|%s|", cmds[i].name); - if (strstr(commands, cmdbuf) == NULL) - { - strcpy(cmd, cmds[i].name); - cmd += strlen(cmds[i].name); - *(cmd++) = SEPARATOR; - *cmd = '\0'; - } - } - } - } - - ptr = apigroups[GROUPOFFSET(group)].commands = cgmalloc(strlen(commands) + 1); - - strcpy(ptr, commands); - } - - // Now define R (NOPRIVGROUP) as all non-iswritemode commands - cmd = &(commands[0]); - *(cmd++) = SEPARATOR; - *cmd = '\0'; - for (i = 0; cmds[i].name != NULL; i++) - { - if (cmds[i].iswritemode == false) - { - strcpy(cmd, cmds[i].name); - cmd += strlen(cmds[i].name); - *(cmd++) = SEPARATOR; - *cmd = '\0'; - } - } - - ptr = apigroups[GROUPOFFSET(NOPRIVGROUP)].commands = cgmalloc(strlen(commands) + 1); - - strcpy(ptr, commands); - - // W (PRIVGROUP) is handled as a special case since it simply means all commands - - free(buf); - return; -} - -/* - * Interpret [W:]IP[/Prefix][,[R|W:]IP2[/Prefix2][,...]] --api-allow option - * ipv6 address should be enclosed with a pair of square brackets and the prefix left outside - * special case of 0/0 allows /0 (means all IP addresses) - */ -#define ALLIP "0/0" -/* - * N.B. IP4 addresses are by Definition 32bit big endian on all platforms - */ -static void setup_ipaccess() -{ - char *buf, *ptr, *comma, *slash, *end, *dot; - int ipcount, mask, i, shift; - char tmp[64], original[64]; - bool ipv6 = false; - char group; - - buf = cgmalloc(strlen(opt_api_allow) + 1); - - strcpy(buf, opt_api_allow); - - ipcount = 1; - ptr = buf; - while (*ptr) - if (*(ptr++) == ',') - ipcount++; - - // possibly more than needed, but never less - ipaccess = cgcalloc(ipcount, sizeof(struct IPACCESS)); - - ips = 0; - ptr = buf; - while (ptr && *ptr) - { - while (*ptr == ' ' || *ptr == '\t') - ptr++; - - if (*ptr == ',') - { - ptr++; - continue; - } - - comma = strchr(ptr, ','); - if (comma) - *(comma++) = '\0'; - - strncpy(original, ptr, sizeof(original)); - original[sizeof(original)-1] = '\0'; - group = NOPRIVGROUP; - - if (isalpha(*ptr) && *(ptr+1) == ':') - { - if (DEFINEDGROUP(*ptr)) - group = GROUP(*ptr); - - ptr += 2; - } - - ipaccess[ips].group = group; - - if (strcmp(ptr, ALLIP) == 0) - { - for (i = 0; i < 16; i++) - { - ipaccess[ips].ip.s6_addr[i] = 0; - ipaccess[ips].mask.s6_addr[i] = 0; - } - } - else - { - end = strchr(ptr, '/'); - if (!end) - { - for (i = 0; i < 16; i++) - ipaccess[ips].mask.s6_addr[i] = 0xff; - end = ptr + strlen(ptr); - } - slash = end--; - if (*ptr == '[' && *end == ']') - { - *(ptr++) = '\0'; - *(end--) = '\0'; - ipv6 = true; - } - else - ipv6 = false; - if (*slash) - { - *(slash++) = '\0'; - mask = atoi(slash); - if (mask < 1 || (mask += ipv6 ? 0 : 96) > 128 ) - { - applog(LOG_ERR, "API: ignored address with " - "invalid mask (%d) '%s'", - mask, original); - goto popipo; // skip invalid/zero - } - - for (i = 0; i < 16; i++) - ipaccess[ips].mask.s6_addr[i] = 0; - - i = 0; - shift = 7; - while (mask-- > 0) - { - ipaccess[ips].mask.s6_addr[i] |= 1 << shift; - if (shift-- == 0) - { - i++; - shift = 7; - } - } - } - - for (i = 0; i < 16; i++) - ipaccess[ips].ip.s6_addr[i] = 0; // missing default to '[::]' - if (ipv6) - { - if (INET_PTON(AF_INET6, ptr, &(ipaccess[ips].ip)) != 1) - { - applog(LOG_ERR, "API: ignored invalid " - "IPv6 address '%s'", - original); - goto popipo; - } - } - else - { - // v4 mapped v6 address, such as "::ffff:255.255.255.255" - dot = strchr(ptr, '.'); - if (!dot) - { - snprintf(tmp, sizeof(tmp), - "::ffff:%s.0.0.0", - ptr); - } - else - { - dot = strchr(dot+1, '.'); - if (!dot) - { - snprintf(tmp, sizeof(tmp), - "::ffff:%s.0.0", - ptr); - } - else - { - dot = strchr(dot+1, '.'); - if (!dot) - { - snprintf(tmp, sizeof(tmp), - "::ffff:%s.0", - ptr); - } - else - { - snprintf(tmp, sizeof(tmp), - "::ffff:%s", - ptr); - } - } - } - if (INET_PTON(AF_INET6, tmp, &(ipaccess[ips].ip)) != 1) - { - applog(LOG_ERR, "API: ignored invalid " - "IPv4 address '%s' (as %s)", - original, tmp); - goto popipo; - } - } - for (i = 0; i < 16; i++) - ipaccess[ips].ip.s6_addr[i] &= ipaccess[ips].mask.s6_addr[i]; - } - - ips++; - popipo: - ptr = comma; - } - - free(buf); -} - -static void *quit_thread(__maybe_unused void *userdata) -{ - // allow thread creator to finish whatever it's doing - mutex_lock(&quit_restart_lock); - mutex_unlock(&quit_restart_lock); - - if (opt_debug) - applog(LOG_DEBUG, "API: killing cgminer"); - - kill_work(); - - return NULL; -} - -static void *restart_thread(__maybe_unused void *userdata) -{ - // allow thread creator to finish whatever it's doing - mutex_lock(&quit_restart_lock); - mutex_unlock(&quit_restart_lock); - - if (opt_debug) - applog(LOG_DEBUG, "API: restarting cgminer"); - - app_restart(); - - return NULL; -} - -static bool check_connect(struct sockaddr_storage *cli, char **connectaddr, char *group) -{ - bool addrok = false; - int i, j; - bool match; - char tmp[30]; - struct in6_addr client_ip; - - *connectaddr = cgmalloc(INET6_ADDRSTRLEN); - getnameinfo((struct sockaddr *)cli, sizeof(*cli), - *connectaddr, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); - - // v4 mapped v6 address, such as "::ffff:255.255.255.255" - if (cli->ss_family == AF_INET) - { - sprintf(tmp, "::ffff:%s", *connectaddr); - INET_PTON(AF_INET6, tmp, &client_ip); - } - else - INET_PTON(AF_INET6, *connectaddr, &client_ip); - - *group = NOPRIVGROUP; - if (opt_api_allow) - { - for (i = 0; i < ips; i++) - { - match = true; - for (j = 0; j < 16; j++) - { - if ((client_ip.s6_addr[j] & ipaccess[i].mask.s6_addr[j]) - != ipaccess[i].ip.s6_addr[j]) - { - match = false; - break; - } - } - if (match) - { - addrok = true; - *group = ipaccess[i].group; - break; - } - } - } - else - { - if (opt_api_network) - addrok = true; - else - addrok = (strcmp(*connectaddr, localaddr) == 0) - || IN6_IS_ADDR_LOOPBACK(&client_ip); - } - - return addrok; -} - -static void mcast() -{ - struct sockaddr_storage came_from; - time_t bindstart; - char *binderror; - SOCKETTYPE mcast_sock = INVSOCK; - SOCKETTYPE reply_sock = INVSOCK; - socklen_t came_from_siz; - char *connectaddr; - ssize_t rep; - int bound; - int count; - int reply_port; - bool addrok; - char group; - - char port_s[10], came_from_port[10]; - struct addrinfo hints, *res, *host, *client; - - char expect[] = "cgminer-"; // first 8 bytes constant - char *expect_code; - size_t expect_code_len; - char buf[1024]; - char replybuf[1024]; - - sprintf(port_s, "%d", opt_api_mcast_port); - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - if (getaddrinfo(opt_api_mcast_addr, port_s, &hints, &res) != 0) - quit(1, "Invalid API Multicast Address"); - host = res; - while (host != NULL) - { - mcast_sock = socket(res->ai_family, SOCK_DGRAM, 0); - if (mcast_sock > 0) - break; - host = host->ai_next; - } - if (mcast_sock == INVSOCK) - { - freeaddrinfo(res); - quit(1, "API mcast could not open socket"); - } - - int optval = 1; - if (SOCKETFAIL(setsockopt(mcast_sock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval)))) - { - applog(LOG_ERR, "API mcast setsockopt SO_REUSEADDR failed (%s)%s", SOCKERRMSG, MUNAVAILABLE); - goto die; - } - - // try for more than 1 minute ... in case the old one hasn't completely gone yet - bound = 0; - bindstart = time(NULL); - while (bound == 0) - { - if (SOCKETFAIL(bind(mcast_sock, host->ai_addr, host->ai_addrlen))) - { - binderror = SOCKERRMSG; - if ((time(NULL) - bindstart) > 61) - break; - else - cgsleep_ms(30000); - } - else - bound = 1; - } - - if (bound == 0) - { - applog(LOG_ERR, "API mcast bind to port %d failed (%s)%s", opt_api_mcast_port, binderror, MUNAVAILABLE); - goto die; - } - - switch (host->ai_family) - { - case AF_INET: - { - struct ip_mreq grp; - memset(&grp, 0, sizeof(grp)); - grp.imr_multiaddr.s_addr = ((struct sockaddr_in *)(host->ai_addr))->sin_addr.s_addr; - grp.imr_interface.s_addr = INADDR_ANY; - - if (SOCKETFAIL(setsockopt(mcast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (void *)(&grp), sizeof(grp)))) - { - applog(LOG_ERR, "API mcast join failed (%s)%s", SOCKERRMSG, MUNAVAILABLE); - goto die; - } - break; - } - case AF_INET6: - { - struct ipv6_mreq grp; - memcpy(&grp.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)(host->ai_addr))->sin6_addr), - sizeof(struct in6_addr)); - grp.ipv6mr_interface= 0; - - if (SOCKETFAIL(setsockopt(mcast_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, - (void *)(&grp), sizeof(grp)))) - { - applog(LOG_ERR, "API mcast join failed (%s)%s", SOCKERRMSG, MUNAVAILABLE); - goto die; - } - break; - } - default: - break; - } - freeaddrinfo(res); - - expect_code_len = sizeof(expect) + strlen(opt_api_mcast_code); - expect_code = cgmalloc(expect_code_len + 1); - snprintf(expect_code, expect_code_len+1, "%s%s-", expect, opt_api_mcast_code); - - count = 0; - while (80085) - { - cgsleep_ms(1000); - - count++; - came_from_siz = sizeof(came_from); - if (SOCKETFAIL(rep = recvfrom(mcast_sock, buf, sizeof(buf) - 1, - 0, (struct sockaddr *)(&came_from), &came_from_siz))) - { - applog(LOG_DEBUG, "API mcast failed count=%d (%s) (%d)", - count, SOCKERRMSG, (int)mcast_sock); - continue; - } - - addrok = check_connect(&came_from, &connectaddr, &group); - applog(LOG_DEBUG, "API mcast from %s - %s", - connectaddr, addrok ? "Accepted" : "Ignored"); - if (!addrok) - continue; - - buf[rep] = '\0'; - if (rep > 0 && buf[rep-1] == '\n') - buf[--rep] = '\0'; - - getnameinfo((struct sockaddr *)(&came_from), came_from_siz, - NULL, 0, came_from_port, sizeof(came_from_port), NI_NUMERICHOST); - - applog(LOG_DEBUG, "API mcast request rep=%d (%s) from [%s]:%s", - (int)rep, buf, connectaddr, came_from_port); - - if ((size_t)rep > expect_code_len && memcmp(buf, expect_code, expect_code_len) == 0) - { - reply_port = atoi(&buf[expect_code_len]); - if (reply_port < 1 || reply_port > 65535) - { - applog(LOG_DEBUG, "API mcast request ignored - invalid port (%s)", - &buf[expect_code_len]); - } - else - { - applog(LOG_DEBUG, "API mcast request OK port %s=%d", - &buf[expect_code_len], reply_port); - - if (getaddrinfo(connectaddr, &buf[expect_code_len], &hints, &res) != 0) - { - applog(LOG_ERR, "Invalid client address %s", connectaddr); - continue; - } - client = res; - while (client) - { - reply_sock = socket(res->ai_family, SOCK_DGRAM, 0); - if (mcast_sock > 0) - break; - client = client->ai_next; - } - if (reply_sock == INVSOCK) - { - freeaddrinfo(res); - applog(LOG_ERR, "API mcast could not open socket to client %s", connectaddr); - continue; - } - - snprintf(replybuf, sizeof(replybuf), - "cgm-" API_MCAST_CODE "-%d-%s", - opt_api_port, opt_api_mcast_des); - - rep = sendto(reply_sock, replybuf, strlen(replybuf)+1, - 0, client->ai_addr, client->ai_addrlen); - freeaddrinfo(res); - if (SOCKETFAIL(rep)) - { - applog(LOG_DEBUG, "API mcast send reply failed (%s) (%d)", - SOCKERRMSG, (int)reply_sock); - } - else - { - applog(LOG_DEBUG, "API mcast send reply (%s) succeeded (%d) (%d)", - replybuf, (int)rep, (int)reply_sock); - } - - CLOSESOCKET(reply_sock); - } - } - else - applog(LOG_DEBUG, "API mcast request was no good"); - } - -die: - - CLOSESOCKET(mcast_sock); -} - -static void *mcast_thread(void *userdata) -{ - struct thr_info *mythr = userdata; - - pthread_detach(pthread_self()); - pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - - RenameThread("APIMcast"); - - mcast(); - - PTH(mythr) = 0L; - - return NULL; -} - -void mcast_init() -{ - struct thr_info *thr; - - thr = cgcalloc(1, sizeof(*thr)); - - if (thr_info_create(thr, NULL, mcast_thread, thr)) - quit(1, "API mcast thread create failed"); -} - -void reCalculateAVG() -{ - new_total_mhashes_done = total_mhashes_done; - if(total_secs>0) - new_total_secs = total_secs-1; - else new_total_secs=total_secs; -} - -void api(int api_thr_id) -{ - struct io_data *io_data; - struct thr_info bye_thr; - char buf[TMPBUFSIZ]; - char param_buf[TMPBUFSIZ]; - SOCKETTYPE c; - int n, bound; - char *connectaddr; - char *binderror; - time_t bindstart; - short int port = opt_api_port; - char port_s[10]; - struct sockaddr_storage cli; - socklen_t clisiz; - char cmdbuf[100]; - char *cmd = NULL; - char *param; - bool addrok; - char group; - json_error_t json_err; - json_t *json_config; - json_t *json_val; - bool isjson; - bool did, isjoin, firstjoin; - int i; - struct addrinfo hints, *res, *host; - - SOCKETTYPE *apisock; - - apisock = cgmalloc(sizeof(*apisock)); - *apisock = INVSOCK; - json_config = NULL; - isjoin = false; - - if (!opt_api_listen) - { - applog(LOG_DEBUG, "API not running%s", UNAVAILABLE); - free(apisock); - return; - } - - io_data = sock_io_new(); - - mutex_init(&quit_restart_lock); - - pthread_cleanup_push(tidyup, (void *)apisock); - my_thr_id = api_thr_id; - - setup_groups(); - - if (opt_api_allow) - { - setup_ipaccess(); - - if (ips == 0) - { - applog(LOG_WARNING, "API not running (no valid IPs specified)%s", UNAVAILABLE); - free(apisock); - return; - } - } - - /* This should be done before curl in needed - * to ensure curl has already called WSAStartup() in windows */ - cgsleep_ms(opt_log_interval*1000); - - sprintf(port_s, "%d", port); - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_PASSIVE; - hints.ai_family = AF_UNSPEC; - if (getaddrinfo(opt_api_host, port_s, &hints, &res) != 0) - { - applog(LOG_ERR, "API failed to resolve %s", opt_api_host); - free(apisock); - return; - } - host = res; - while (host) - { - *apisock = socket(res->ai_family, SOCK_STREAM, 0); - if (*apisock > 0) - break; - host = host->ai_next; - } - if (*apisock == INVSOCK) - { - applog(LOG_ERR, "API initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE); - freeaddrinfo(res); - free(apisock); - return; - } - -#ifndef WIN32 - // On linux with SO_REUSEADDR, bind will get the port if the previous - // socket is closed (even if it is still in TIME_WAIT) but fail if - // another program has it open - which is what we want - int optval = 1; - // If it doesn't work, we don't really care - just show a debug message - if (SOCKETFAIL(setsockopt(*apisock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval)))) - applog(LOG_DEBUG, "API setsockopt SO_REUSEADDR failed (ignored): %s", SOCKERRMSG); -#else - // On windows a 2nd program can bind to a port>1024 already in use unless - // SO_EXCLUSIVEADDRUSE is used - however then the bind to a closed port - // in TIME_WAIT will fail until the timeout - so we leave the options alone -#endif - - // try for more than 1 minute ... in case the old one hasn't completely gone yet - bound = 0; - bindstart = time(NULL); - while (bound == 0) - { - if (SOCKETFAIL(bind(*apisock, host->ai_addr, host->ai_addrlen))) - { - binderror = SOCKERRMSG; - if ((time(NULL) - bindstart) > 61) - break; - else - { - applog(LOG_WARNING, "API bind to port %d failed - trying again in 30sec", port); - cgsleep_ms(30000); - } - } - else - bound = 1; - } - freeaddrinfo(res); - - if (bound == 0) - { - applog(LOG_ERR, "API bind to port %d failed (%s)%s", port, binderror, UNAVAILABLE); - free(apisock); - return; - } - - if (SOCKETFAIL(listen(*apisock, QUEUE))) - { - applog(LOG_ERR, "API3 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE); - CLOSESOCKET(*apisock); - free(apisock); - return; - } - - if (opt_api_allow) - applog(LOG_WARNING, "API running in IP access mode on port %d (%d)", port, (int)*apisock); - else - { - if (opt_api_network) - applog(LOG_WARNING, "API running in UNRESTRICTED read access mode on port %d (%d)", port, (int)*apisock); - else - applog(LOG_WARNING, "API running in local read access mode on port %d (%d)", port, (int)*apisock); - } - - if (opt_api_mcast) - mcast_init(); - - strbufs = k_new_list("StrBufs", sizeof(SBITEM), ALLOC_SBITEMS, LIMIT_SBITEMS, false); - - while (!bye) - { - clisiz = sizeof(cli); - if (SOCKETFAIL(c = accept(*apisock, (struct sockaddr *)(&cli), &clisiz))) - { - applog(LOG_ERR, "API failed (%s)%s (%d)", SOCKERRMSG, UNAVAILABLE, (int)*apisock); - goto die; - } - - addrok = check_connect((struct sockaddr_storage *)&cli, &connectaddr, &group); - applog(LOG_DEBUG, "API: connection from %s - %s", - connectaddr, addrok ? "Accepted" : "Ignored"); - - if (addrok) - { - n = recv(c, &buf[0], TMPBUFSIZ-1, 0); - if (SOCKETFAIL(n)) - buf[0] = '\0'; - else - buf[n] = '\0'; - - if (opt_debug) - { - if (SOCKETFAIL(n)) - applog(LOG_DEBUG, "API: recv failed: %s", SOCKERRMSG); - else - applog(LOG_DEBUG, "API: recv command: (%d) '%s'", n, buf); - } - - if (!SOCKETFAIL(n)) - { - // the time of the request in now - when = time(NULL); - io_reinit(io_data); - - did = false; - - if (*buf != ISJSON) - { - isjson = false; - - param = strchr(buf, SEPARATOR); - if (param != NULL) - *(param++) = '\0'; - - cmd = buf; - } - else - { - isjson = true; - - param = NULL; - - json_config = json_loadb(buf, n, 0, &json_err); - - if (!json_is_object(json_config)) - { - message(io_data, MSG_INVJSON, 0, NULL, isjson); - send_result(io_data, c, isjson); - did = true; - } - else - { - json_val = json_object_get(json_config, JSON_COMMAND); - if (json_val == NULL) - { - message(io_data, MSG_MISCMD, 0, NULL, isjson); - send_result(io_data, c, isjson); - did = true; - } - else - { - if (!json_is_string(json_val)) - { - message(io_data, MSG_INVCMD, 0, NULL, isjson); - send_result(io_data, c, isjson); - did = true; - } - else - { - cmd = (char *)json_string_value(json_val); - json_val = json_object_get(json_config, JSON_PARAMETER); - if (json_is_string(json_val)) - param = (char *)json_string_value(json_val); - else if (json_is_integer(json_val)) - { - sprintf(param_buf, "%d", (int)json_integer_value(json_val)); - param = param_buf; - } - else if (json_is_real(json_val)) - { - sprintf(param_buf, "%f", (double)json_real_value(json_val)); - param = param_buf; - } - } - } - } - } - - if (!did) - { - char *cmdptr, *cmdsbuf = NULL; - - if (strchr(cmd, CMDJOIN)) - { - firstjoin = isjoin = true; - // cmd + leading+tailing '|' + '\0' - cmdsbuf = cgmalloc(strlen(cmd) + 3); - strcpy(cmdsbuf, "|"); - param = NULL; - } - else - firstjoin = isjoin = false; - - cmdptr = cmd; - do - { - did = false; - if (isjoin) - { - cmd = strchr(cmdptr, CMDJOIN); - if (cmd) - *(cmd++) = '\0'; - if (!*cmdptr) - goto inochi; - } - - for (i = 0; cmds[i].name != NULL; i++) - { - if (strcmp(cmdptr, cmds[i].name) == 0) - { - sprintf(cmdbuf, "|%s|", cmdptr); - if (isjoin) - { - if (strstr(cmdsbuf, cmdbuf)) - { - did = true; - break; - } - strcat(cmdsbuf, cmdptr); - strcat(cmdsbuf, "|"); - head_join(io_data, cmdptr, isjson, &firstjoin); - if (!cmds[i].joinable) - { - message(io_data, MSG_ACCDENY, 0, cmds[i].name, isjson); - did = true; - tail_join(io_data, isjson); - break; - } - } - if (ISPRIVGROUP(group) || strstr(COMMANDS(group), cmdbuf)) - (cmds[i].func)(io_data, c, param, isjson, group); - else - { - message(io_data, MSG_ACCDENY, 0, cmds[i].name, isjson); - applog(LOG_DEBUG, "API: access denied to '%s' for '%s' command", connectaddr, cmds[i].name); - } - - did = true; - if (!isjoin) - send_result(io_data, c, isjson); - else - tail_join(io_data, isjson); - break; - } - } - - if (!did) - { - if (isjoin) - head_join(io_data, cmdptr, isjson, &firstjoin); - message(io_data, MSG_INVCMD, 0, NULL, isjson); - if (isjoin) - tail_join(io_data, isjson); - else - send_result(io_data, c, isjson); - } - inochi: - if (isjoin) - cmdptr = cmd; - } - while (isjoin && cmdptr); - } - - if (isjoin) - send_result(io_data, c, isjson); - - if (isjson && json_is_object(json_config)) - json_decref(json_config); - } - } - CLOSESOCKET(c); - } -die: - /* Blank line fix for older compilers since pthread_cleanup_pop is a - * macro that gets confused by a label existing immediately before it - */ - ; - pthread_cleanup_pop(true); - - free(apisock); - - if (opt_debug) - applog(LOG_DEBUG, "API: terminating due to: %s", - do_a_quit ? "QUIT" : (do_a_restart ? "RESTART" : (bye ? "BYE" : "UNKNOWN!"))); - - mutex_lock(&quit_restart_lock); - - if (do_a_restart) - { - if (thr_info_create(&bye_thr, NULL, restart_thread, &bye_thr)) - { - mutex_unlock(&quit_restart_lock); - quit(1, "API failed to initiate a restart - aborting"); - } - pthread_detach(bye_thr.pth); - } - else if (do_a_quit) - { - if (thr_info_create(&bye_thr, NULL, quit_thread, &bye_thr)) - { - mutex_unlock(&quit_restart_lock); - quit(1, "API failed to initiate a clean quit - aborting"); - } - pthread_detach(bye_thr.pth); - } - - mutex_unlock(&quit_restart_lock); -} diff --git a/api.c b/api.c index 0046249c27..8e64890397 100644 --- a/api.c +++ b/api.c @@ -32,7 +32,7 @@ defined(USE_MINION) || defined(USE_COINTERRA) || defined(USE_BITMINE_A1) || \ defined(USE_ANT_S1) || defined(USE_ANT_S2) || defined(USE_ANT_S3) || defined(USE_SP10) || \ defined(USE_SP30) || defined(USE_ICARUS) || defined(USE_HASHRATIO) || defined(USE_AVALON_MINER) || \ - defined(USE_AVALON7) + defined(USE_AVALON7) || defined(USE_BITMAIN_SOC) #define HAVE_AN_ASIC 1 #endif @@ -4869,6 +4869,16 @@ void mcast_init() quit(1, "API mcast thread create failed"); } +#ifdef USE_BITMAIN_SOC +void reCalculateAVG() +{ + new_total_mhashes_done = total_mhashes_done; + if(total_secs>0) + new_total_secs = total_secs-1; + else new_total_secs=total_secs; +} +#endif + void api(int api_thr_id) { struct io_data *io_data; From ed4bf7b72b09311726b0822e141019e71fc77598 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Sun, 19 Aug 2018 10:40:34 +0800 Subject: [PATCH 078/113] fix compiler warnings --- bitmain-board-test.h | 2 ++ cgminer.c | 1 - driver-btm-soc.c | 3 ++- driver-btm-soc.h | 9 ++++++++- miner.h | 8 ++++++++ 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/bitmain-board-test.h b/bitmain-board-test.h index db0d56b711..b9751af517 100644 --- a/bitmain-board-test.h +++ b/bitmain-board-test.h @@ -239,4 +239,6 @@ struct testpatten_cgpu_info static void fix_result_byPercent(int chainIndex); #endif +static int calculate_core_number(unsigned int actual_core_number); + #endif diff --git a/cgminer.c b/cgminer.c index f5b7bc4e7a..02af8477ae 100644 --- a/cgminer.c +++ b/cgminer.c @@ -7601,7 +7601,6 @@ void get_work_by_nonce2(struct thr_info *thr, struct pool *pool, struct pool *real_pool, uint64_t nonce2, - uint32_t ntime, uint32_t version) { *work = make_work(); diff --git a/driver-btm-soc.c b/driver-btm-soc.c index 1d158b13a8..e942dcba8a 100644 --- a/driver-btm-soc.c +++ b/driver-btm-soc.c @@ -69,6 +69,7 @@ unsigned char reset_iic_pic(unsigned char chain); extern bool clement_doTestBoard(bool showlog); bool clement_doTestBoardOnce(bool showlog); +int calculate_core_number(unsigned int actual_core_number); #define hex_print(p) applog(LOG_DEBUG, "%s", p) @@ -11213,7 +11214,7 @@ void set_pic_iic_flash_addr_pointer(unsigned char chain, unsigned char addr_H, u continue; } c_pool = pools[pool->pool_no]; - get_work_by_nonce2(thr,&work,pool,c_pool,nonce2,pool->ntime,version); + get_work_by_nonce2(thr,&work,pool,c_pool,nonce2,version); h += hashtest_submit(thr,work,nonce3,midstate,pool,nonce2,chain_id); free_work(work); } diff --git a/driver-btm-soc.h b/driver-btm-soc.h index e83fa083be..03071f77bf 100644 --- a/driver-btm-soc.h +++ b/driver-btm-soc.h @@ -911,7 +911,14 @@ extern int ADD_FREQ1; extern int fpga_version; extern int opt_multi_version; - +int getChainExistFlag(int chainIndex); +unsigned char get_pic_voltage(unsigned char chain); +int getVolValueFromPICvoltage(unsigned char vol_pic); +unsigned char getPICvoltageFromValue(int vol_value); +void set_pic_voltage(unsigned char chain, unsigned char voltage); +int getChainAsicNum(int chainIndex); +int readRebootTestNum(); +int send_job(unsigned char *buf); #endif diff --git a/miner.h b/miner.h index c6c14f7fbd..194ba16d9b 100644 --- a/miner.h +++ b/miner.h @@ -1157,6 +1157,14 @@ extern void set_target(unsigned char *dest_target, double diff); bool submit_nonce2_nonce(struct thr_info *thr, struct pool *pool, struct pool *real_pool, uint32_t nonce2, uint32_t nonce, uint32_t ntime); #endif +#ifdef USE_BITMAIN_SOC +void get_work_by_nonce2(struct thr_info *thr, + struct work **work, + struct pool *pool, + struct pool *real_pool, + uint64_t nonce2, + uint32_t version); +#endif extern int restart_wait(struct thr_info *thr, unsigned int mstime); extern void raise_cgminer(void); From 00869e55139c4834d48da5e8999d6417b9f7f519 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Fri, 7 Sep 2018 12:41:04 +0800 Subject: [PATCH 079/113] Remove sha2-soc files --- Makefile.am | 1 - driver-btm-soc.c | 291 +++++++++++++++++++++++++++++++++++++++++++- sha2-soc.c | 310 ----------------------------------------------- sha2-soc.h | 95 --------------- 4 files changed, 290 insertions(+), 407 deletions(-) delete mode 100644 sha2-soc.c delete mode 100644 sha2-soc.h diff --git a/Makefile.am b/Makefile.am index fb9924c76f..5fb3f349ca 100644 --- a/Makefile.am +++ b/Makefile.am @@ -115,7 +115,6 @@ endif if HAS_BITMAIN_SOC cgminer_SOURCES += driver-btm-soc.c driver-btm-soc.h cgminer_SOURCES += bitmain-board-test.c bitmain-board-test.h -cgminer_SOURCES += sha2-soc.c sha2-soc.h endif if HAS_BITMINE_A1 diff --git a/driver-btm-soc.c b/driver-btm-soc.c index e942dcba8a..3d439b45b1 100644 --- a/driver-btm-soc.c +++ b/driver-btm-soc.c @@ -51,7 +51,6 @@ // #include "usbutils.h" #include "util.h" #include "driver-btm-soc.h" -#include "sha2-soc.h" #define MAX_CHAR_NUM 1024 @@ -136,6 +135,296 @@ static void hexdump(const uint8_t *p, unsigned int len) } } +/** + * \brief SHA-256 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +sha2_context; + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_ULONG_BE +#define GET_ULONG_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_ULONG_BE +#define PUT_ULONG_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * SHA-256 context setup + */ +void sha2_starts( sha2_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +void sha2_process( sha2_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A, B, C, D, E, F, G, H; + + GET_ULONG_BE( W[ 0], data, 0 ); + GET_ULONG_BE( W[ 1], data, 4 ); + GET_ULONG_BE( W[ 2], data, 8 ); + GET_ULONG_BE( W[ 3], data, 12 ); + GET_ULONG_BE( W[ 4], data, 16 ); + GET_ULONG_BE( W[ 5], data, 20 ); + GET_ULONG_BE( W[ 6], data, 24 ); + GET_ULONG_BE( W[ 7], data, 28 ); + GET_ULONG_BE( W[ 8], data, 32 ); + GET_ULONG_BE( W[ 9], data, 36 ); + GET_ULONG_BE( W[10], data, 40 ); + GET_ULONG_BE( W[11], data, 44 ); + GET_ULONG_BE( W[12], data, 48 ); + GET_ULONG_BE( W[13], data, 52 ); + GET_ULONG_BE( W[14], data, 56 ); + GET_ULONG_BE( W[15], data, 60 ); + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ +( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ +) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + + P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 ); + P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 ); + P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF ); + P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 ); + P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B ); + P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 ); + P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 ); + P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 ); + P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 ); + P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 ); + P( G, H, A, B, C, D, E, F, W[10], 0x243185BE ); + P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 ); + P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 ); + P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE ); + P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 ); + P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 ); + P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 ); + P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 ); + P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 ); + P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC ); + P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F ); + P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA ); + P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC ); + P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA ); + P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 ); + P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D ); + P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 ); + P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 ); + P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 ); + P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 ); + P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 ); + P( B, C, D, E, F, G, H, A, R(31), 0x14292967 ); + P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 ); + P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 ); + P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC ); + P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 ); + P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 ); + P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB ); + P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E ); + P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 ); + P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 ); + P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B ); + P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 ); + P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 ); + P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 ); + P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 ); + P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 ); + P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 ); + P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 ); + P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 ); + P( G, H, A, B, C, D, E, F, R(50), 0x2748774C ); + P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 ); + P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 ); + P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A ); + P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F ); + P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 ); + P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE ); + P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F ); + P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 ); + P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 ); + P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA ); + P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB ); + P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 ); + P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +/* + * SHA-256 process buffer + */ +void sha2_update( sha2_context *ctx, const unsigned char *input, int ilen ) +{ + int fill; + uint32_t left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, fill ); + sha2_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + sha2_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy((void *) (ctx->buffer + left), + (void *) input, ilen ); + } + /* + printk("ctx sha2_update:"); + dump_hex((uint8_t*)ctx,sizeof(*ctx)); + */ +} + +static const unsigned char sha2_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-256 final digest + */ +void sha2_finish( sha2_context *ctx, unsigned char output[32] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_ULONG_BE( high, msglen, 0 ); + PUT_ULONG_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + sha2_update( ctx, (unsigned char *) sha2_padding, padn ); + sha2_update( ctx, msglen, 8 ); + + PUT_ULONG_BE( ctx->state[0], output, 0 ); + PUT_ULONG_BE( ctx->state[1], output, 4 ); + PUT_ULONG_BE( ctx->state[2], output, 8 ); + PUT_ULONG_BE( ctx->state[3], output, 12 ); + PUT_ULONG_BE( ctx->state[4], output, 16 ); + PUT_ULONG_BE( ctx->state[5], output, 20 ); + PUT_ULONG_BE( ctx->state[6], output, 24 ); + + PUT_ULONG_BE( ctx->state[7], output, 28 ); +} + +/* + * output = SHA-256( input buffer ) + */ +void sha2( const unsigned char *input, int ilen, + unsigned char output[32] ) +{ + sha2_context ctx; + + sha2_starts( &ctx ); + sha2_update( &ctx, input, ilen ); + sha2_finish( &ctx, output ); + + memset(&ctx, 0, sizeof(sha2_context)); +} + #ifdef R4 int MIN_PWM_PERCENT; int MID_PWM_PERCENT; diff --git a/sha2-soc.c b/sha2-soc.c deleted file mode 100644 index c461b7b60a..0000000000 --- a/sha2-soc.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * FIPS-180-2 compliant SHA-256 implementation - * - * Copyright (C) 2011, Con Kolivas - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * 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, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * The SHA-256 Secure Hash Standard was published by NIST in 2002. - * - * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf - */ - -#include -#include "sha2-soc.h" - -extern void dump_hex(uint8_t *data, uint16_t len); -/* - * 32-bit integer manipulation macros (big endian) - */ -#ifndef GET_ULONG_BE -#define GET_ULONG_BE(n,b,i) \ -{ \ - (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ - | ( (uint32_t) (b)[(i) + 1] << 16 ) \ - | ( (uint32_t) (b)[(i) + 2] << 8 ) \ - | ( (uint32_t) (b)[(i) + 3] ); \ -} -#endif - -#ifndef PUT_ULONG_BE -#define PUT_ULONG_BE(n,b,i) \ -{ \ - (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ - (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ - (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ - (b)[(i) + 3] = (unsigned char) ( (n) ); \ -} -#endif - -/* - * SHA-256 context setup - */ -void sha2_starts( sha2_context *ctx ) -{ - ctx->total[0] = 0; - ctx->total[1] = 0; - - ctx->state[0] = 0x6A09E667; - ctx->state[1] = 0xBB67AE85; - ctx->state[2] = 0x3C6EF372; - ctx->state[3] = 0xA54FF53A; - ctx->state[4] = 0x510E527F; - ctx->state[5] = 0x9B05688C; - ctx->state[6] = 0x1F83D9AB; - ctx->state[7] = 0x5BE0CD19; -} - -void sha2_process( sha2_context *ctx, const unsigned char data[64] ) -{ - uint32_t temp1, temp2, W[64]; - uint32_t A, B, C, D, E, F, G, H; - - GET_ULONG_BE( W[ 0], data, 0 ); - GET_ULONG_BE( W[ 1], data, 4 ); - GET_ULONG_BE( W[ 2], data, 8 ); - GET_ULONG_BE( W[ 3], data, 12 ); - GET_ULONG_BE( W[ 4], data, 16 ); - GET_ULONG_BE( W[ 5], data, 20 ); - GET_ULONG_BE( W[ 6], data, 24 ); - GET_ULONG_BE( W[ 7], data, 28 ); - GET_ULONG_BE( W[ 8], data, 32 ); - GET_ULONG_BE( W[ 9], data, 36 ); - GET_ULONG_BE( W[10], data, 40 ); - GET_ULONG_BE( W[11], data, 44 ); - GET_ULONG_BE( W[12], data, 48 ); - GET_ULONG_BE( W[13], data, 52 ); - GET_ULONG_BE( W[14], data, 56 ); - GET_ULONG_BE( W[15], data, 60 ); - -#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) -#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) - -#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) -#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) - -#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) -#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) - -#define F0(x,y,z) ((x & y) | (z & (x | y))) -#define F1(x,y,z) (z ^ (x & (y ^ z))) - -#define R(t) \ -( \ - W[t] = S1(W[t - 2]) + W[t - 7] + \ - S0(W[t - 15]) + W[t - 16] \ -) - -#define P(a,b,c,d,e,f,g,h,x,K) \ -{ \ - temp1 = h + S3(e) + F1(e,f,g) + K + x; \ - temp2 = S2(a) + F0(a,b,c); \ - d += temp1; h = temp1 + temp2; \ -} - - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - E = ctx->state[4]; - F = ctx->state[5]; - G = ctx->state[6]; - H = ctx->state[7]; - - P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 ); - P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 ); - P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF ); - P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 ); - P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B ); - P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 ); - P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 ); - P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 ); - P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 ); - P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 ); - P( G, H, A, B, C, D, E, F, W[10], 0x243185BE ); - P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 ); - P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 ); - P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE ); - P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 ); - P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 ); - P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 ); - P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 ); - P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 ); - P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC ); - P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F ); - P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA ); - P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC ); - P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA ); - P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 ); - P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D ); - P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 ); - P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 ); - P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 ); - P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 ); - P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 ); - P( B, C, D, E, F, G, H, A, R(31), 0x14292967 ); - P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 ); - P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 ); - P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC ); - P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 ); - P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 ); - P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB ); - P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E ); - P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 ); - P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 ); - P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B ); - P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 ); - P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 ); - P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 ); - P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 ); - P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 ); - P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 ); - P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 ); - P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 ); - P( G, H, A, B, C, D, E, F, R(50), 0x2748774C ); - P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 ); - P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 ); - P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A ); - P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F ); - P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 ); - P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE ); - P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F ); - P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 ); - P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 ); - P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA ); - P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB ); - P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 ); - P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 ); - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; - ctx->state[4] += E; - ctx->state[5] += F; - ctx->state[6] += G; - ctx->state[7] += H; -} - -/* - * SHA-256 process buffer - */ -void sha2_update( sha2_context *ctx, const unsigned char *input, int ilen ) -{ - int fill; - uint32_t left; - - if( ilen <= 0 ) - return; - - left = ctx->total[0] & 0x3F; - fill = 64 - left; - - ctx->total[0] += ilen; - ctx->total[0] &= 0xFFFFFFFF; - - if( ctx->total[0] < (uint32_t) ilen ) - ctx->total[1]++; - - if( left && ilen >= fill ) - { - memcpy( (void *) (ctx->buffer + left), - (void *) input, fill ); - sha2_process( ctx, ctx->buffer ); - input += fill; - ilen -= fill; - left = 0; - } - - while( ilen >= 64 ) - { - sha2_process( ctx, input ); - input += 64; - ilen -= 64; - } - - if( ilen > 0 ) - { - memcpy((void *) (ctx->buffer + left), - (void *) input, ilen ); - } - /* - printk("ctx sha2_update:"); - dump_hex((uint8_t*)ctx,sizeof(*ctx)); - */ -} - -static const unsigned char sha2_padding[64] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* - * SHA-256 final digest - */ -void sha2_finish( sha2_context *ctx, unsigned char output[32] ) -{ - uint32_t last, padn; - uint32_t high, low; - unsigned char msglen[8]; - - high = ( ctx->total[0] >> 29 ) - | ( ctx->total[1] << 3 ); - low = ( ctx->total[0] << 3 ); - - PUT_ULONG_BE( high, msglen, 0 ); - PUT_ULONG_BE( low, msglen, 4 ); - - last = ctx->total[0] & 0x3F; - padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); - - sha2_update( ctx, (unsigned char *) sha2_padding, padn ); - sha2_update( ctx, msglen, 8 ); - - PUT_ULONG_BE( ctx->state[0], output, 0 ); - PUT_ULONG_BE( ctx->state[1], output, 4 ); - PUT_ULONG_BE( ctx->state[2], output, 8 ); - PUT_ULONG_BE( ctx->state[3], output, 12 ); - PUT_ULONG_BE( ctx->state[4], output, 16 ); - PUT_ULONG_BE( ctx->state[5], output, 20 ); - PUT_ULONG_BE( ctx->state[6], output, 24 ); - - PUT_ULONG_BE( ctx->state[7], output, 28 ); -} - -/* - * output = SHA-256( input buffer ) - */ -void sha2( const unsigned char *input, int ilen, - unsigned char output[32] ) -{ - sha2_context ctx; - - sha2_starts( &ctx ); - sha2_update( &ctx, input, ilen ); - sha2_finish( &ctx, output ); - - memset(&ctx, 0, sizeof(sha2_context)); -} diff --git a/sha2-soc.h b/sha2-soc.h deleted file mode 100644 index 654f011abc..0000000000 --- a/sha2-soc.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * \file sha2.h - * - * Copyright (C) 2011, Con Kolivas - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * 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 2 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, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "miner.h" - -#ifndef POLARSSL_SHA2_H -#define POLARSSL_SHA2_H - - -/** - * \brief SHA-256 context structure - */ -typedef struct -{ - uint32_t total[2]; /*!< number of bytes processed */ - uint32_t state[8]; /*!< intermediate digest state */ - unsigned char buffer[64]; /*!< data block being processed */ - - unsigned char ipad[64]; /*!< HMAC: inner padding */ - unsigned char opad[64]; /*!< HMAC: outer padding */ -} -sha2_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief SHA-256 context setup - * - * \param ctx context to be initialized - */ -void sha2_starts( sha2_context *ctx); - -/** - * \brief SHA-256 process buffer - * - * \param ctx SHA-256 context - * \param input buffer holding the data - * \param ilen length of the input data - */ -void sha2_update( sha2_context *ctx, const unsigned char *input, int ilen ); - -/** - * \brief SHA-256 final digest - * - * \param ctx SHA-256 context - * \param output SHA-256 checksum result - */ -void sha2_finish( sha2_context *ctx, unsigned char output[32] ); - -/** - * \brief Output = SHA-256( input buffer ) - * - * \param input buffer holding the data - * \param ilen length of the input data - * \param output SHA-256 checksum result - */ -void sha2( const unsigned char *input, int ilen, - unsigned char output[32]); - - -void sha2_process( sha2_context *ctx, const unsigned char data[64] ); - -#ifdef __cplusplus -} -#endif - -#endif /* sha2.h */ - - From 45431ea7f1d5935ff3adf7b0bc6e94b0d6f5c369 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Wed, 26 Sep 2018 22:45:41 +0800 Subject: [PATCH 080/113] Update PID controller for adjusting fan --- cgminer.c | 9 ++++ driver-avalon8.c | 105 ++++++++++++++++++++++++----------------------- driver-avalon8.h | 22 ++++++++-- 3 files changed, 81 insertions(+), 55 deletions(-) diff --git a/cgminer.c b/cgminer.c index 804fe0cf36..451c0cc404 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1588,6 +1588,15 @@ static struct opt_table opt_config_table[] = { OPT_WITH_CBARG("--avalon8-cinfo-asic", set_avalon8_asic_otp, NULL, &opt_set_avalon8_asic_otp, "Set Avalon8 cinfo asic index, range:[0, 25], step: 1"), + OPT_WITH_ARG("--avalon8-pid-p", + set_int_0_to_9999, opt_show_intval, &opt_avalon8_pid_p, + "Set Avalon8 pid-p, range 0-9999."), + OPT_WITH_ARG("--avalon8-pid-i", + set_int_0_to_9999, opt_show_intval, &opt_avalon8_pid_i, + "Set Avalon8 pid-i, range 0-9999."), + OPT_WITH_ARG("--avalon8-pid-d", + set_int_0_to_9999, opt_show_intval, &opt_avalon8_pid_d, + "Set Avalon8 pid-d, range 0-9999."), #endif #ifdef USE_AVALON_MINER OPT_WITH_CBARG("--avalonm-voltage", diff --git a/driver-avalon8.c b/driver-avalon8.c index 3a8218313e..f80849b483 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -68,6 +68,10 @@ uint32_t opt_avalon8_roll_enable = AVA8_DEFAULT_ROLL_ENABLE; uint32_t opt_avalon8_spdlow = AVA8_INVALID_SPDLOW; uint32_t opt_avalon8_spdhigh = AVA8_DEFAULT_SPDHIGH; +uint32_t opt_avalon8_pid_p = AVA8_DEFAULT_PID_P; +uint32_t opt_avalon8_pid_i = AVA8_DEFAULT_PID_I; +uint32_t opt_avalon8_pid_d = AVA8_DEFAULT_PID_D; + uint32_t cpm_table[] = { 0x04400000, @@ -450,69 +454,58 @@ static inline int get_temp_max(struct avalon8_info *info, int addr) return max; } -/* Use a PID-like feedback mechanism for optimal temperature and fan speed */ +/* + * Incremental PID controller + * + * controller input: u, output: t + * + * delta_u = P * [e(k) - e(k-1)] + I * e(k) + D * [e(k) - 2*e(k-1) + e(k-2)]; + * e(k) = t(k) - t[target]; + * u(k) = u(k-1) + delta_u; + * + */ static inline uint32_t adjust_fan(struct avalon8_info *info, int id) { - int t, tdiff, delta; + int t; + double delta_u; + double delta_p, delta_i, delta_d; uint32_t pwm; - time_t now_t; - now_t = time(NULL); t = get_temp_max(info, id); - tdiff = t - info->temp_last_max[id]; - if (!tdiff && now_t < info->last_temp_time[id] + AVA8_DEFAULT_FAN_INTERVAL) - goto out; - info->last_temp_time[id] = now_t; - delta = t - info->temp_target[id]; - - /* Check for init value and ignore it */ - if (unlikely(info->temp_last_max[id] == -273)) - tdiff = 0; - info->temp_last_max[id] = t; - - if (t >= info->temp_overheat[id]) { - /* Hit the overheat temperature limit */ - if (info->fan_pct[id] < opt_avalon8_fan_max) { - applog(LOG_WARNING, "Overheat detected on AV8-%d, increasing fan to max", id); - info->fan_pct[id] = opt_avalon8_fan_max; - } - } else if (delta > 0) { - /* Over target temperature. */ - /* Is the temp already coming down */ - if (tdiff < 0) - goto out; - /* Adjust fanspeed by temperature over and any further rise */ - info->fan_pct[id] += delta + tdiff; + /* update target error */ + info->pid_e[id][2] = info->pid_e[id][1]; + info->pid_e[id][1] = info->pid_e[id][0]; + info->pid_e[id][0] = t - info->temp_target[id]; + + if (t > AVA8_DEFAULT_PID_TEMP_MAX) { + info->pid_u[id] = opt_avalon8_fan_max; + } else if (t < AVA8_DEFAULT_PID_TEMP_MIN) { + info->pid_u[id] = opt_avalon8_fan_min; + } else if (!info->pid_0[id]) { + /* first, init u as t */ + info->pid_0[id] = 1; + info->pid_u[id] = t; } else { - /* Below target temperature */ - int diff = tdiff; + delta_p = info->pid_p[id] * (info->pid_e[id][0] - info->pid_e[id][1]); + delta_i = info->pid_i[id] * info->pid_e[id][0]; + delta_d = info->pid_d[id] * (info->pid_e[id][0] - 2 * info->pid_e[id][1] + info->pid_e[id][2]); - if (tdiff > 0) { - int divisor = -delta / AVA8_DEFAULT_TEMP_HYSTERESIS + 1; + /*Parameter I is int type(1, 2, 3...), but should be used as a smaller value (such as 0.1, 0.01...)*/ + delta_u = delta_p + delta_i / 100 + delta_d; - /* Adjust fanspeed by temperature change proportional to - * diff from optimal. */ - diff /= divisor; - } else { - /* Is the temp below optimal and unchanging, gently lower speed */ - if (t < info->temp_target[id] - AVA8_DEFAULT_TEMP_HYSTERESIS && !tdiff) - diff -= 1; - } - info->fan_pct[id] += diff; + info->pid_u[id] += delta_u; } - if (info->fan_pct[id] > opt_avalon8_fan_max) - info->fan_pct[id] = opt_avalon8_fan_max; - else if (info->fan_pct[id] < opt_avalon8_fan_min) - info->fan_pct[id] = opt_avalon8_fan_min; -out: - pwm = get_fan_pwm(info->fan_pct[id]); + if(info->pid_u[id] > opt_avalon8_fan_max) + info->pid_u[id] = opt_avalon8_fan_max; - if (info->cutoff[id]) - pwm = get_fan_pwm(opt_avalon8_fan_max); + if (info->pid_u[id] < opt_avalon8_fan_min) + info->pid_u[id] = opt_avalon8_fan_min; - applog(LOG_DEBUG, "[%d], Adjust_fan: %dC-%d%%(%03x)", id, t, info->fan_pct[id], pwm); + /* Round from float to int */ + info->fan_pct[id] = (int)(info->pid_u[id] + 0.5); + pwm = get_fan_pwm(info->fan_pct[id]); return pwm; } @@ -1547,9 +1540,19 @@ static void detect_modules(struct cgpu_info *avalon8) info->cutoff[i] = 0; info->fan_cpm[i] = 0; info->temp_mm[i] = -273; - info->temp_last_max[i] = -273; info->local_works[i] = 0; info->hw_works[i] = 0; + + /*PID controller*/ + info->pid_u[i] = opt_avalon8_fan_min; + info->pid_p[i] = opt_avalon8_pid_p; + info->pid_i[i] = opt_avalon8_pid_i; + info->pid_d[i] = opt_avalon8_pid_d; + info->pid_e[i][0] = 0; + info->pid_e[i][1] = 0; + info->pid_e[i][2] = 0; + info->pid_0[i] = 0; + for (j = 0; j < info->miner_count[i]; j++) { memset(info->chip_matching_work[i][j], 0, sizeof(uint64_t) * info->asic_count[i]); info->local_works_i[i][j] = 0; diff --git a/driver-avalon8.h b/driver-avalon8.h index 4708661995..a5338ce550 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -21,11 +21,9 @@ #define AVA8_DEFAULT_FAN_MIN 5 /* % */ #define AVA8_DEFAULT_FAN_MAX 100 -#define AVA8_DEFAULT_FAN_INTERVAL 15 /* Seconds */ #define AVA8_DEFAULT_TEMP_TARGET 90 #define AVA8_DEFAULT_TEMP_OVERHEAT 105 -#define AVA8_DEFAULT_TEMP_HYSTERESIS 5 #define AVA8_DEFAULT_VOLTAGE_LEVEL_MIN -15 #define AVA8_DEFAULT_VOLTAGE_LEVEL_MAX 15 @@ -103,6 +101,13 @@ #define AVA831_DEFAULT_SPDLOW 2 #define AVA831_DEFAULT_NONCE_MASK 27 +/* PID CONTROLLER*/ +#define AVA8_DEFAULT_PID_P 2 +#define AVA8_DEFAULT_PID_I 5 +#define AVA8_DEFAULT_PID_D 0 +#define AVA8_DEFAULT_PID_TEMP_MIN 50 +#define AVA8_DEFAULT_PID_TEMP_MAX 100 + #define AVA8_DEFAULT_IIC_DETECT false #define AVA8_PWM_MAX 0x3FF @@ -288,9 +293,15 @@ struct avalon8_info { uint8_t cutoff[AVA8_DEFAULT_MODULARS]; int temp_target[AVA8_DEFAULT_MODULARS]; - int temp_last_max[AVA8_DEFAULT_MODULARS]; int temp_overheat[AVA8_DEFAULT_MODULARS]; - time_t last_temp_time[AVA8_DEFAULT_MODULARS]; + + /* pid controler*/ + int pid_p[AVA8_DEFAULT_MODULARS]; + int pid_i[AVA8_DEFAULT_MODULARS]; + int pid_d[AVA8_DEFAULT_MODULARS]; + double pid_u[AVA8_DEFAULT_MODULARS]; + int pid_e[AVA8_DEFAULT_MODULARS][3]; + int pid_0[AVA8_DEFAULT_MODULARS]; int set_voltage_level[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT]; uint32_t set_frequency[AVA8_DEFAULT_MODULARS][AVA8_DEFAULT_MINER_CNT][AVA8_DEFAULT_PLL_CNT]; @@ -379,6 +390,9 @@ extern uint32_t opt_avalon8_roll_enable; extern uint32_t opt_avalon8_spdlow; extern uint32_t opt_avalon8_spdhigh; extern char *set_avalon8_asic_otp(char *arg); +extern uint32_t opt_avalon8_pid_p; +extern uint32_t opt_avalon8_pid_i; +extern uint32_t opt_avalon8_pid_d; #endif /* USE_AVALON8 */ #endif /* _AVALON8_H_ */ From db73322ddee458a2ce9df29f69824b8b15475faf Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Wed, 26 Sep 2018 22:46:32 +0800 Subject: [PATCH 081/113] Minor update --- driver-avalon8.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon8.h b/driver-avalon8.h index a5338ce550..6b2d52908e 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -368,6 +368,7 @@ extern char *set_avalon8_fan(char *arg); extern char *set_avalon8_freq(char *arg); extern char *set_avalon8_voltage_level(char *arg); extern char *set_avalon8_voltage_level_offset(char *arg); +extern char *set_avalon8_asic_otp(char *arg); extern int opt_avalon8_temp_target; extern int opt_avalon8_polling_delay; extern int opt_avalon8_aucspeed; @@ -389,7 +390,6 @@ extern uint32_t opt_avalon8_h2ltime0_spd; extern uint32_t opt_avalon8_roll_enable; extern uint32_t opt_avalon8_spdlow; extern uint32_t opt_avalon8_spdhigh; -extern char *set_avalon8_asic_otp(char *arg); extern uint32_t opt_avalon8_pid_p; extern uint32_t opt_avalon8_pid_i; extern uint32_t opt_avalon8_pid_d; From 87ff6ea5b89c7f5fbaefce7b336a285c75e23824 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 27 Sep 2018 21:32:26 +0800 Subject: [PATCH 082/113] Update AVA8_DRV_DIFFMAX --- driver-avalon8.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-avalon8.h b/driver-avalon8.h index 6b2d52908e..6a3e6cc4f0 100644 --- a/driver-avalon8.h +++ b/driver-avalon8.h @@ -111,7 +111,7 @@ #define AVA8_DEFAULT_IIC_DETECT false #define AVA8_PWM_MAX 0x3FF -#define AVA8_DRV_DIFFMAX 1024 +#define AVA8_DRV_DIFFMAX 2700 #define AVA8_ASIC_TIMEOUT_CONST 419430400 /* (2^32 * 1000) / (256 * 40) */ #define AVA8_MODULE_DETECT_INTERVAL 30 /* 30 s */ From 0d1b58a6230110de78f53ed9ea92327496d7a07d Mon Sep 17 00:00:00 2001 From: Johnson-Fan Date: Thu, 1 Nov 2018 16:26:33 +0800 Subject: [PATCH 083/113] Fix no hashrate of Avalon7 --- driver-avalon7.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/driver-avalon7.c b/driver-avalon7.c index e65f4a271f..2c8e201487 100644 --- a/driver-avalon7.c +++ b/driver-avalon7.c @@ -1914,6 +1914,8 @@ static int64_t avalon7_scanhash(struct thr_info *thr) switch (info->freq_mode[i]) { case AVA7_FREQ_INIT_MODE: update_settings = true; + /* Make sure to send configuration first */ + thr->work_update = false; for (j = 0; j < info->miner_count[i]; j++) { for (k = 0; k < AVA7_DEFAULT_PLL_CNT; k++) info->set_frequency[i][j][k] = opt_avalon7_freq[k]; From deb1b77ebedfe223f91db54af985acf8da0ed53f Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 1 Nov 2018 17:57:53 +0800 Subject: [PATCH 084/113] Revert "Support clean jobs for different stratum pool" This reverts commit 7de9a9b86fefff65c370c01afc3e90c15109d286. Conflicts: util.c --- README | 1 - cgminer.c | 4 ---- miner.h | 1 - util.c | 37 ++----------------------------------- 4 files changed, 2 insertions(+), 41 deletions(-) diff --git a/README b/README index 427258e0a9..a70270cda3 100644 --- a/README +++ b/README @@ -346,7 +346,6 @@ Options for both config file and command line: --verbose Log verbose output to stderr as well as status output --widescreen Use extra wide display without toggling --worktime Display extra work time debug information ---force-clean-jobs Force clean jobs to miners (default: 20) Options for command line only: --config|-c Load a JSON-format configuration file See example.conf for an example configuration. diff --git a/cgminer.c b/cgminer.c index 451c0cc404..cddb7b2c5a 100644 --- a/cgminer.c +++ b/cgminer.c @@ -476,7 +476,6 @@ static struct stratum_share *stratum_shares = NULL; char *opt_socks_proxy = NULL; int opt_suggest_diff; -int opt_force_clean_jobs = 20; static const char def_conf[] = "cgminer.conf"; static char *default_config; static bool config_loaded; @@ -2101,9 +2100,6 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--worktime", opt_set_bool, &opt_worktime, "Display extra work time debug information"), - OPT_WITH_ARG("--force-clean-jobs", - opt_set_intval, NULL, &opt_force_clean_jobs, - "Force clean jobs to miners (default: 20)"), OPT_ENDTABLE }; diff --git a/miner.h b/miner.h index daad9dd14b..ec8a266b9d 100644 --- a/miner.h +++ b/miner.h @@ -989,7 +989,6 @@ extern bool have_longpoll; extern char *opt_kernel_path; extern char *opt_socks_proxy; extern int opt_suggest_diff; -extern int opt_force_clean_jobs; extern char *cgminer_path; extern bool opt_lowmem; extern bool opt_autofan; diff --git a/util.c b/util.c index 39a5a98f2b..c5aa41306b 100644 --- a/util.c +++ b/util.c @@ -2007,11 +2007,6 @@ static void decode_exit(struct pool __maybe_unused *pool, char __maybe_unused *b static bool parse_notify(struct pool *pool, json_t *val) { -#ifdef USE_AVALON7 - static int32_t th_clean_jobs; - static struct timeval last_notify; - struct timeval current; -#endif char *job_id, *prev_hash, *coinbase1, *coinbase2, *bbversion, *nbit, *ntime, header[260]; unsigned char *cb1 = NULL, *cb2 = NULL; @@ -2164,36 +2159,8 @@ static bool parse_notify(struct pool *pool, json_t *val) if (pool == current_pool()) { opt_work_update = true; #ifdef USE_AVALON7 - if (opt_avalon7_ssplus_enable & pool->has_stratum) { - /* -1:Ignore, 0:Accept, n:Accept after n seconds, n > 0 */ - if (opt_force_clean_jobs == -1 && clean) - opt_clean_jobs = true; - - if (!opt_force_clean_jobs) - opt_clean_jobs = true; - - if (opt_force_clean_jobs > 0) { - if (clean) - opt_clean_jobs = true; - else { - if (!last_notify.tv_sec && !last_notify.tv_usec) - cgtime(&last_notify); - else { - cgtime(¤t); - th_clean_jobs += (int32_t)ms_tdiff(¤t, &last_notify); - cgtime(&last_notify); - } - - if (th_clean_jobs >= opt_force_clean_jobs * 1000) - opt_clean_jobs = true; - } - } - - if (opt_clean_jobs) { - ssp_hasher_update_stratum(pool, true); - th_clean_jobs = 0; - } - } + if (opt_avalon7_ssplus_enable & pool->has_stratum & clean) + ssp_hasher_update_stratum(pool, true); #endif } out: From 0b8adaab3c7443a59dda84a368060f4bd4b6d1ad Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 1 Nov 2018 17:58:10 +0800 Subject: [PATCH 085/113] Revert "Only update stratum work to MM when new block was found" This reverts commit 90262c2342d1b99a71225340be0062c45bac20da. --- driver-avalon7.c | 16 +++------------- util.c | 2 +- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/driver-avalon7.c b/driver-avalon7.c index dd265c638a..1fe3bba7ff 100644 --- a/driver-avalon7.c +++ b/driver-avalon7.c @@ -1949,32 +1949,21 @@ static void avalon7_sswork_update(struct cgpu_info *avalon7) struct pool *pool; int coinbase_len_posthash, coinbase_len_prehash; - cgtime(&info->last_stratum); /* * NOTE: We need mark work_restart to private information, * So that it cann't reset by hash_driver_work */ if (thr->work_restart) info->work_restart = thr->work_restart; - applog(LOG_NOTICE, "%s-%d: New stratum: restart: %d, update: %d, clean: %d", + applog(LOG_DEBUG, "%s-%d: New stratum: restart: %d, update: %d", avalon7->drv->name, avalon7->device_id, - thr->work_restart, thr->work_update, thr->clean_jobs); + thr->work_restart, thr->work_update); /* Step 1: MM protocol check */ pool = current_pool(); if (!pool->has_stratum) quit(1, "%s-%d: MM has to use stratum pools", avalon7->drv->name, avalon7->device_id); - if (opt_avalon7_ssplus_enable) { - if (thr->clean_jobs) { - applog(LOG_DEBUG, "%s-%d: Update the stratum", avalon7->drv->name, avalon7->device_id); - thr->clean_jobs = false; - } else { - applog(LOG_DEBUG, "%s-%d: Ignore the stratum", avalon7->drv->name, avalon7->device_id); - return; - } - } - coinbase_len_prehash = pool->nonce2_offset - (pool->nonce2_offset % SHA256_BLOCK_SIZE); coinbase_len_posthash = pool->coinbase_len - coinbase_len_prehash; @@ -1996,6 +1985,7 @@ static void avalon7_sswork_update(struct cgpu_info *avalon7) /* Step 2: Send out stratum pkgs */ cg_rlock(&pool->data_lock); + cgtime(&info->last_stratum); info->pool_no = pool->pool_no; copy_pool_stratum(&info->pool2, &info->pool1); copy_pool_stratum(&info->pool1, &info->pool0); diff --git a/util.c b/util.c index c5aa41306b..7de2e6212d 100644 --- a/util.c +++ b/util.c @@ -2159,7 +2159,7 @@ static bool parse_notify(struct pool *pool, json_t *val) if (pool == current_pool()) { opt_work_update = true; #ifdef USE_AVALON7 - if (opt_avalon7_ssplus_enable & pool->has_stratum & clean) + if (opt_avalon7_ssplus_enable & pool->has_stratum) ssp_hasher_update_stratum(pool, true); #endif } From a2f909d9dbe05005f1e53cc3ea7c5a4ef143a03c Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 1 Nov 2018 17:58:18 +0800 Subject: [PATCH 086/113] Revert "Add clean_jobs notify" This reverts commit 4cdf957b1e4019ef470c6793437c38ece88b12a8. --- cgminer.c | 19 ------------------- miner.h | 2 -- 2 files changed, 21 deletions(-) diff --git a/cgminer.c b/cgminer.c index cddb7b2c5a..368034f232 100644 --- a/cgminer.c +++ b/cgminer.c @@ -146,7 +146,6 @@ struct strategies strategies[] = { static char packagename[256]; bool opt_work_update; -bool opt_clean_jobs = false; bool opt_protocol; static struct benchfile_layout { int length; @@ -5169,18 +5168,6 @@ static void signal_work_update(void) rd_unlock(&mining_thr_lock); } -static void signal_clean_jobs(void) -{ - int i; - - applog(LOG_NOTICE, "Job clean message received"); - - rd_lock(&mining_thr_lock); - for (i = 0; i < mining_threads; i++) - mining_thr[i]->clean_jobs = true; - rd_unlock(&mining_thr_lock); -} - static void set_curblock(const char *hexstr, const unsigned char *bedata) { int ofs; @@ -5296,7 +5283,6 @@ static bool test_work_current(struct work *work) if (pool->swork.clean) { pool->swork.clean = false; work->longpoll = true; - opt_clean_jobs = true; } if (pool->current_height != height) { pool->current_height = height; @@ -10408,11 +10394,6 @@ int main(int argc, char *argv[]) opt_work_update = false; - if (opt_clean_jobs) { - signal_clean_jobs(); - opt_clean_jobs = false; - } - mutex_lock(stgd_lock); ts = __total_staged(); /* Wait until hash_pop tells us we need to create more work */ diff --git a/miner.h b/miner.h index ec8a266b9d..914a3fa295 100644 --- a/miner.h +++ b/miner.h @@ -572,7 +572,6 @@ struct thr_info { bool work_restart; bool work_update; - bool clean_jobs; }; struct string_elist { @@ -983,7 +982,6 @@ struct pool; #define API_MCAST_ADDR "224.0.0.75" extern bool opt_work_update; -extern bool opt_clean_jobs; extern bool opt_protocol; extern bool have_longpoll; extern char *opt_kernel_path; From 24c4689c77d9bfd53408fb20b0a2a09f126f901b Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 1 Nov 2018 18:00:24 +0800 Subject: [PATCH 087/113] Revert "Add SSP support for Avalon7" This reverts commit 19b6d29400f05b8652dd34f465837e30dbed9aa4. Conflicts: configure.ac driver-avalon7.h --- Makefile.am | 4 - cgminer.c | 48 ---- configure.ac | 1 - driver-avalon7.c | 126 +-------- driver-avalon7.h | 10 - libssplus.c | 646 ----------------------------------------------- libssplus.h | 27 -- miner.h | 1 - util.c | 12 +- 9 files changed, 8 insertions(+), 867 deletions(-) delete mode 100644 libssplus.c delete mode 100644 libssplus.h diff --git a/Makefile.am b/Makefile.am index 42bf4fde4c..69ee9b8ed5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -173,10 +173,6 @@ if NEED_I2C_CONTEXT cgminer_SOURCES += i2c-context.c endif -if SUPPORT_SSP -cgminer_SOURCES += libssplus.c -endif - if HAS_AVALON_MINER cgminer_SOURCES += driver-avalon-miner.c driver-avalon-miner.h endif diff --git a/cgminer.c b/cgminer.c index 368034f232..9f75a01a5d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -84,7 +84,6 @@ char *curly = ":D"; #ifdef USE_AVALON7 #include "driver-avalon7.h" -#include "libssplus.h" #endif #ifdef USE_AVALON8 @@ -1503,9 +1502,6 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--no-avalon7-asic-debug", opt_set_invbool, &opt_avalon7_asic_debug, "Disable A3212 debug."), - OPT_WITHOUT_ARG("--avalon7-ssplus-enable", - opt_set_bool, &opt_avalon7_ssplus_enable, - "Enable avalon7 smart speed plus."), #endif #ifdef USE_AVALON8 OPT_WITH_CBARG("--avalon8-voltage-level", @@ -7424,43 +7420,6 @@ bool submit_nonce2_nonce(struct thr_info *thr, struct pool *pool, struct pool *r free_work(work); return ret; } - -uint32_t gen_merkle_root(struct pool *pool, uint64_t nonce2) -{ - unsigned char merkle_root[32], merkle_sha[64]; - uint32_t *data32, *swap32, tail; - uint64_t nonce2le; - int i; - - /* Update coinbase. Always use an LE encoded nonce2 to fill in values - * from left to right and prevent overflow errors with small n2sizes */ - nonce2le = htole64(nonce2); - cg_memcpy(pool->coinbase + pool->nonce2_offset, &nonce2le, pool->n2size); - - /* Generate merkle root */ - gen_hash(pool->coinbase, merkle_root, pool->coinbase_len); - cg_memcpy(merkle_sha, merkle_root, 32); - for (i = 0; i < pool->merkles; i++) { - cg_memcpy(merkle_sha + 32, pool->swork.merkle_bin[i], 32); - gen_hash(merkle_sha, merkle_root, 64); - cg_memcpy(merkle_sha, merkle_root, 32); - } - data32 = (uint32_t *)merkle_sha; - swap32 = (uint32_t *)merkle_root; - flip32(swap32, data32); - - { - char *merkle_hash; - - merkle_hash = bin2hex((const unsigned char *)merkle_root, 32); - applog(LOG_DEBUG, "[M-N2]: %s-%08x-%08x", merkle_hash, (uint32_t)nonce2le, (uint32_t)nonce2); - free(merkle_hash); - } - - cg_memcpy(&tail, merkle_root + 28, 4); - - return tail; -} #endif /* Generates stratum based work based on the most recent notify information @@ -10136,12 +10095,6 @@ int main(int argc, char *argv[]) gwsched_thr_id = 0; -#ifdef USE_AVALON7 - if (opt_avalon7_ssplus_enable) { - ssp_sorter_init(HT_SIZE, HT_PRB_LMT, HT_PRB_C1, HT_PRB_C2); - ssp_hasher_init(); - } -#endif #ifdef USE_USBUTILS usb_initialise(); @@ -10391,7 +10344,6 @@ int main(int argc, char *argv[]) if (opt_work_update) signal_work_update(); - opt_work_update = false; mutex_lock(stgd_lock); diff --git a/configure.ac b/configure.ac index ae1624022f..01f32fe740 100644 --- a/configure.ac +++ b/configure.ac @@ -543,7 +543,6 @@ AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue]) AM_CONDITIONAL([HAVE_x86_64], [test x$have_x86_64 = xtrue]) AM_CONDITIONAL([WANT_CRC16], [test x$want_crc16 != xfalse]) AM_CONDITIONAL([NEED_I2C_CONTEXT], [test x$avalon4$avalon7$avalon8 != xnonono]) -AM_CONDITIONAL([SUPPORT_SSP], [test x$avalon7 != xno]) if test "x$want_usbutils" != xfalse; then AC_DEFINE([USE_USBUTILS], [1], [Defined to 1 if usbutils support required]) diff --git a/driver-avalon7.c b/driver-avalon7.c index 1fe3bba7ff..7bab0fe814 100644 --- a/driver-avalon7.c +++ b/driver-avalon7.c @@ -14,7 +14,6 @@ #include "driver-avalon7.h" #include "crc.h" #include "sha2.h" -#include "libssplus.h" #include "hexdump.c" #define get_fan_pwm(v) (AVA7_PWM_MAX - (v) * AVA7_PWM_MAX / 100) @@ -56,7 +55,6 @@ uint32_t opt_avalon7_th_ms = AVA7_DEFAULT_TH_MS; uint32_t opt_avalon7_th_timeout = AVA7_DEFAULT_TH_TIMEOUT; uint32_t opt_avalon7_nonce_mask = AVA7_DEFAULT_NONCE_MASK; bool opt_avalon7_asic_debug = true; -bool opt_avalon7_ssplus_enable = false; uint32_t cpm_table[] = { @@ -605,10 +603,10 @@ static int decode_pkg(struct cgpu_info *avalon7, struct avalon7_ret *ar, int mod if (ntime > info->max_ntime) info->max_ntime = ntime; - applog(LOG_NOTICE, "%s-%d-%d: Found! P:%d - N2:%08x N:%08x NR:%d/%d [M:%d, A:%d, C:%d - MW: (%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64")]", + applog(LOG_DEBUG, "%s-%d-%d: Found! P:%d - N2:%08x N:%08x NR:%d/%d [M:%d - MW: (%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64")]", avalon7->drv->name, avalon7->device_id, modular_id, pool_no, nonce2, nonce, ntime, info->max_ntime, - miner, chip_id, nonce & 0x7f, + miner, info->chip_matching_work[modular_id][miner][0], info->chip_matching_work[modular_id][miner][1], info->chip_matching_work[modular_id][miner][2], @@ -681,9 +679,6 @@ static int decode_pkg(struct cgpu_info *avalon7, struct avalon7_ret *ar, int mod memcpy(&tmp, ar->data + 24, 4); info->error_crc[modular_id][ar->idx] += be32toh(tmp); - memcpy(&tmp, ar->data + 28, 4); - info->mm_got_pairs[modular_id] += be32toh(tmp) >> 16; - info->mm_got_invalid_pairs[modular_id] += be32toh(tmp) & 0xffff; break; case AVA7_P_STATUS_PMU: /* TODO: decode ntc led from PMU */ @@ -1355,93 +1350,6 @@ static inline void avalon7_detect(bool __maybe_unused hotplug) avalon7_iic_detect(); } -#ifdef PAIR_CHECK -static void copy_pool_stratum(struct pool *pool_stratum, struct pool *pool); -#endif -static void *avalon7_ssp_fill_pairs(void *userdata) -{ - char threadname[16]; - - struct cgpu_info *avalon7 = userdata; - struct avalon7_info *info = avalon7->device_data; - struct avalon7_pkg send_pkg; - ssp_pair pair; - uint8_t pair_counts; - int i, err, fill_timeout;; - uint32_t tmp; -#ifdef PAIR_CHECK - struct pool pool_mirror, *pool; - uint32_t tail[2]; - uint64_t pass, fail; -#endif - - snprintf(threadname, sizeof(threadname), "%d/Av7ssp", avalon7->device_id); - RenameThread(threadname); - - /* timeout in ms = count of points * 4 * ntime_offset / max_ghs(10T) * 1000 */ - fill_timeout = 80 * 4 * AVA7_DEFAULT_NTIME_OFFSET * 1.0 / 10000 * 1000; - - cgsleep_ms(3000); - while (likely(!avalon7->shutdown)) { -#ifdef PAIR_CHECK - if (ssp_sorter_get_pair(pair)) { - pool = current_pool(); - copy_pool_stratum(&pool_mirror, pool); - tail[0] = gen_merkle_root(&pool_mirror, pair[0]); - tail[1] = gen_merkle_root(&pool_mirror, pair[1]); - if (tail[0] != tail[1]) { - fail++; - applog(LOG_NOTICE, "avalon7_ssp_fill_pairs: tail mismatch (%08x:%08x -> %08x:%08x)", - tail[0], - tail[1], - pair[0], - pair[1]); - applog(LOG_NOTICE, "avalon7_ssp_fill_pairs: tail mismatch detail %08x-%08x, F: %"PRIu64", P: %"PRIu64", Errate: %0.2f", tail[0], tail[1], fail, pass, fail * 1.0 / (pass + fail)); - } else { - applog(LOG_NOTICE, "avalon7_ssp_fill_pairs: tail pass (%08x -> %08x:%08x)", - tail[0], - pair[0], - pair[1]); - pass++; - } - } - cgsleep_ms(opt_avalon7_polling_delay); -#else - for (i = 1; i < AVA7_DEFAULT_MODULARS; i++) { - if (!info->enable[i]) - continue; - - pair_counts = 0; - memset(send_pkg.data, 0, AVA7_P_DATA_LEN); - while (pair_counts < 1) { - if (!ssp_sorter_get_pair(pair)) { - applog(LOG_DEBUG, "%s-%d: Waiting for pairs from ssp_sorter_get_pair", - avalon7->drv->name, avalon7->device_id); - continue; - } - tmp = be32toh(pair[0]); - memcpy(send_pkg.data + pair_counts * 8, &tmp, 4); - tmp = be32toh(pair[1]); - applog(LOG_DEBUG, "send pair %08x-%08x", pair[0], pair[1]); - memcpy(send_pkg.data + pair_counts * 8 + 4, &tmp, 4); - pair_counts++; - info->gen_pairs[i]++; - } - - avalon7_init_pkg(&send_pkg, AVA7_P_PAIRS, 1, 1); - err = avalon7_iic_xfer_pkg(avalon7, i, &send_pkg, NULL); - if (err != AVA7_SEND_OK) { - applog(LOG_NOTICE, "%s-%d: send pair failed %d", - avalon7->drv->name, avalon7->device_id, err); - } - } - cgsleep_ms(fill_timeout); -#endif - } - - return NULL; -} - static bool avalon7_prepare(struct thr_info *thr) { struct cgpu_info *avalon7 = thr->cgpu; @@ -1464,13 +1372,6 @@ static bool avalon7_prepare(struct thr_info *thr) cglock_init(&info->pool1.data_lock); cglock_init(&info->pool2.data_lock); - if (opt_avalon7_ssplus_enable) { - if (pthread_create(&(info->ssp_thr), NULL, avalon7_ssp_fill_pairs, (void *)avalon7)) { - applog(LOG_ERR, "%s-%d: create ssp thread failed", avalon7->drv->name, avalon7->device_id); - return false; - } - } - return true; } @@ -1604,9 +1505,6 @@ static void detect_modules(struct cgpu_info *avalon7) info->power_good[i] = 0; memset(info->pmu_version[i], 0, sizeof(char) * 5 * AVA7_DEFAULT_PMU_CNT); info->diff1[i] = 0; - info->mm_got_pairs[i] = 0; - info->mm_got_invalid_pairs[i] = 0; - info->gen_pairs[i] = 0; applog(LOG_NOTICE, "%s-%d: New module detected! ID[%d-%x]", avalon7->drv->name, avalon7->device_id, i, info->mm_dna[i][AVA7_MM_DNA_LEN - 1]); @@ -1762,22 +1660,17 @@ static void avalon7_init_setting(struct cgpu_info *avalon7, int addr) memset(send_pkg.data, 0, AVA7_P_DATA_LEN); + /* TODO:ss/ssp mode */ + tmp = be32toh(opt_avalon7_freq_sel); memcpy(send_pkg.data + 4, &tmp, 4); - /* - * set flags: - * 0: ss switch - * 1: nonce check - * 2: asic debug - * 3: ssp switch - */ + /* adjust flag [0-5]: reserved, 6: nonce check, 7: autof*/ tmp = 1; if (!opt_avalon7_smart_speed) tmp = 0; tmp |= (1 << 1); /* Enable nonce check */ tmp |= (opt_avalon7_asic_debug << 2); - tmp |= (opt_avalon7_ssplus_enable << 3); send_pkg.data[8] = tmp & 0xff; send_pkg.data[9] = opt_avalon7_nonce_mask & 0xff; @@ -1837,11 +1730,11 @@ static void avalon7_set_freq(struct cgpu_info *avalon7, int addr, int miner_id, for (i = 1; i < AVA7_DEFAULT_PLL_CNT; i++) f = f > freq[i] ? f : freq[i]; - tmp = ((AVA7_ASIC_TIMEOUT_CONST / f) * AVA7_DEFAULT_NTIME_OFFSET / 4) * (opt_avalon7_ssplus_enable ? 2 : 1); + tmp = ((AVA7_ASIC_TIMEOUT_CONST / f) * 40 / 4); tmp = be32toh(tmp); memcpy(send_pkg.data + AVA7_DEFAULT_PLL_CNT * 4, &tmp, 4); - tmp = AVA7_ASIC_TIMEOUT_CONST / f * 98 / 100 * (opt_avalon7_ssplus_enable ? 2 : 1); + tmp = AVA7_ASIC_TIMEOUT_CONST / f * 98 / 100; tmp = be32toh(tmp); memcpy(send_pkg.data + AVA7_DEFAULT_PLL_CNT * 4 + 4, &tmp, 4); applog(LOG_DEBUG, "%s-%d-%d: avalon7 set freq miner %x-%x", @@ -2368,11 +2261,6 @@ static struct api_data *avalon7_api_stats(struct cgpu_info *avalon7) } statbuf[strlen(statbuf) - 1] = ']'; - strcat(statbuf, " PAIRS["); - sprintf(buf, "%"PRIu64" %"PRIu64" %"PRIu64" ", info->mm_got_pairs[i], info->mm_got_invalid_pairs[i], info->gen_pairs[i]); - strcat(statbuf, buf); - statbuf[strlen(statbuf) - 1] = ']'; - strcat(statbuf, " PVT_T["); for (j = 0; j < info->miner_count[i]; j++) { sprintf(buf, "%d-%d/%d-%d/%d ", diff --git a/driver-avalon7.h b/driver-avalon7.h index b8160e6ebc..8c242457e7 100644 --- a/driver-avalon7.h +++ b/driver-avalon7.h @@ -59,7 +59,6 @@ #define AVA7_DEFAULT_PMU_CNT 2 #define AVA7_DEFAULT_POLLING_DELAY 20 /* ms */ -#define AVA7_DEFAULT_NTIME_OFFSET 40 #define AVA7_DEFAULT_SMARTSPEED_OFF 0 #define AVA7_DEFAULT_SMARTSPEED_MODE1 1 @@ -123,7 +122,6 @@ #define AVA7_P_SET_PMU 0x24 #define AVA7_P_SET_PLL 0x25 #define AVA7_P_SET_SS 0x26 -#define AVA7_P_PAIRS 0x27 #define AVA7_P_SET_FAC 0x28 /* Have to send with I2C address */ @@ -281,13 +279,6 @@ struct avalon7_info { uint16_t vout_adc_ratio[AVA7_DEFAULT_MODULARS]; bool conn_overloaded; - - uint64_t mm_got_pairs[AVA7_DEFAULT_MODULARS]; - uint64_t mm_got_invalid_pairs[AVA7_DEFAULT_MODULARS]; - uint64_t gen_pairs[AVA7_DEFAULT_MODULARS]; - - /* SSP */ - pthread_t ssp_thr; }; struct avalon7_iic_info { @@ -333,6 +324,5 @@ extern uint32_t opt_avalon7_th_ms; extern uint32_t opt_avalon7_th_timeout; extern uint32_t opt_avalon7_nonce_mask; extern bool opt_avalon7_asic_debug; -extern bool opt_avalon7_ssplus_enable; #endif /* USE_AVALON7 */ #endif /* _AVALON7_H_ */ diff --git a/libssplus.c b/libssplus.c deleted file mode 100644 index 6f054ed1b1..0000000000 --- a/libssplus.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * Copyright 2016 Mikeqin - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sha2.h" - -#include "libssplus.h" - -#define INSTRUCTIONS_RAM_START 0x42000000 -#define INSTRUCTIONS_RAM_SIZE (1 << 16) -#define POINTS_RAM_START 0xfffc0000 -#define POINTS_RAM_SIZE (256 << 10) - -/* hasher instructions */ -#define INST_DONE 0x00040000 -#define INST_DATA_IRAM 0x0 -#define INST_DATA_LASTHASH_PAD 0x14000000 -#define INST_DATA_LASTHASH_IRAM 0x10000000 -#define INST_DATA_PAD512 0x26000000 -#define INST_MID_INIT 0x0 -#define INST_MID_LASTHASH 0x100000 - -#define NEXT_ADDR(x) (((x) & 0x1ff) << 8) - -#define UNPACK32(x, str) \ -{ \ - *((str) + 3) = (uint8_t) ((x) ); \ - *((str) + 2) = (uint8_t) ((x) >> 8); \ - *((str) + 1) = (uint8_t) ((x) >> 16); \ - *((str) + 0) = (uint8_t) ((x) >> 24); \ -} - -#define SORTER_DEBUG - -struct ssp_hasher_instruction { - uint32_t opcode; - uint8_t data[64]; -}; - -struct ssp_point { - uint32_t nonce2; - uint32_t tail; -}; - -struct ssp_info { - pthread_t hasher_thr; - pthread_mutex_t hasher_lock; - volatile uint32_t *iram_addr; - volatile uint64_t *pram_addr; - bool stratum_update; - bool run; -}; - -struct ssp_pair_element { - uint32_t nonce2[2]; - struct ssp_pair_element *next; -}; - -struct ssp_hashtable { - struct ssp_point *cells; - uint32_t size; - uint32_t max_size; /* must be powers of 2 */ - uint32_t limit; /* probing limit */ - uint32_t c1; - uint32_t c2; -}; - -static struct ssp_info sspinfo; -static struct ssp_hashtable *ssp_ht = NULL; -static struct ssp_pair_element *ssp_pair_head = NULL; -static struct ssp_pair_element *ssp_pair_tail = NULL; - -#ifdef SORTER_DEBUG -static uint32_t pair_count = 0; -static uint32_t consumed = 0; -static uint32_t discarded = 0; -static uint32_t calls = 0; -static struct timeval ssp_ti, ssp_tf; -static double insert_time = .0; - -static uint32_t maxnonce = 0; -static uint32_t ver = 0; -#endif - -static void ssp_sorter_insert(const struct ssp_point *point) -{ - uint32_t i; - uint32_t key; - -#ifdef SORTER_DEBUG - if (calls == 0xffffffff) - applog(LOG_NOTICE, "calls overflow"); - calls++; -#endif - - for (i = 0; i < ssp_ht->limit; i++) { - key = (point->tail + ssp_ht->c1 * i + ssp_ht->c2 * i * i) % - (ssp_ht->max_size); - if (ssp_ht->cells[key].nonce2 == 0 && ssp_ht->cells[key].tail == 0) { - /* insert */ - ssp_ht->cells[key].tail = point->tail; - ssp_ht->cells[key].nonce2 = point->nonce2; - ssp_ht->size++; - goto out; - } - if (ssp_ht->cells[key].tail == point->tail) { - /* get a collision */ - ssp_pair_tail->nonce2[0] = point->nonce2; - ssp_pair_tail->nonce2[1] = ssp_ht->cells[key].nonce2; - ssp_pair_tail->next = (struct ssp_pair_element *)cgmalloc(sizeof(struct ssp_pair_element)); - ssp_pair_tail = ssp_pair_tail->next; -#ifdef SORTER_DEBUG - pair_count++; -#endif - - /* update nonce2 of the point */ - ssp_ht->cells[key].nonce2 = 0; - ssp_ht->cells[key].tail = 0; - /* or just delete it? */ - /* or leave it be? */ - goto out; - } - } - - /* discard */ -#ifdef SORTER_DEBUG - discarded++; -#endif -out: - return; -} - -void ssp_sorter_init(uint32_t max_size, uint32_t limit, uint32_t c1, uint32_t c2) -{ -#ifdef SORTER_DEBUG - cgtime(&ssp_ti); -#endif - - ssp_ht = (struct ssp_hashtable *)cgmalloc(sizeof(struct ssp_hashtable)); - - ssp_ht->max_size = max_size; - ssp_ht->limit = limit; - ssp_ht->c1 = c1; - ssp_ht->c2 = c2; - ssp_ht->size = 0; - ssp_ht->cells = (struct ssp_point *)cgmalloc(sizeof(struct ssp_point) * max_size); - memset(ssp_ht->cells, 0, sizeof(struct ssp_point) * max_size); - - ssp_pair_head = (struct ssp_pair_element *)cgmalloc(sizeof(struct ssp_pair_element)); - ssp_pair_tail = ssp_pair_head; -} - -void ssp_sorter_flush(void) -{ -#ifdef SORTER_DEBUG - double delta_t; - - cgtime(&ssp_tf); - delta_t = tdiff(&ssp_tf, &ssp_ti); - - applog(LOG_NOTICE, "Stratum %d: %f s", ver, delta_t); - applog(LOG_NOTICE, "Stratum %d: get %d pairs. %f pair/s", ver, pair_count, pair_count / delta_t); - applog(LOG_NOTICE, "Stratum %d: consume %d pairs. %f pair/s", ver, consumed, consumed / delta_t); - applog(LOG_NOTICE, "Stratum %d: discard %d points. %f point/s", ver, discarded, discarded / delta_t); - applog(LOG_NOTICE, "Stratum %d: reading discards %d points. %f point/s. %.2f%%", ver, maxnonce - calls, (maxnonce - calls) / delta_t, (maxnonce - calls) * 1.0 / maxnonce * 100); - applog(LOG_NOTICE, "Stratum %d: record %d points. %f%% of hashtable. %f point/s", ver, ssp_ht->size, ssp_ht->size * 100.0 / ssp_ht->max_size, ssp_ht->size / delta_t); - applog(LOG_NOTICE, "Stratum %d: %d calls of sorter_insert. %f call/s", ver, calls, calls / delta_t); - applog(LOG_NOTICE, "Stratum %d: avg call time - %f us", ver, delta_t * 1000000 / calls); - applog(LOG_NOTICE, "Stratum %d: k^2 / 2N / pair - %f", ver, 0.5 * calls * calls / 4294967296 / pair_count); - applog(LOG_NOTICE, "========================================================"); - - cgtime(&ssp_ti); - pair_count = 0; - consumed = 0; - discarded = 0; - calls = 0; - insert_time = 0; - ver++; -#endif - - ssp_ht->size = 0; - memset(ssp_ht->cells, 0, sizeof(struct ssp_point) * ssp_ht->max_size); - - /* MM only use one stratum, we need drop all pairs */ - while (ssp_pair_head != ssp_pair_tail) { - struct ssp_pair_element *tmp; - - tmp = ssp_pair_head; - ssp_pair_head = tmp->next; - free(tmp); - } -} - -int ssp_sorter_get_pair(ssp_pair pair) -{ - struct ssp_pair_element *tmp; - - mutex_lock(&(sspinfo.hasher_lock)); - - if (ssp_pair_head == ssp_pair_tail) { - mutex_unlock(&(sspinfo.hasher_lock)); - return 0; - } - - tmp = ssp_pair_head; - pair[0] = tmp->nonce2[0]; - pair[1] = tmp->nonce2[1]; - - ssp_pair_head = tmp->next; - free(tmp); -#ifdef SORTER_DEBUG - consumed++; -#endif - mutex_unlock(&(sspinfo.hasher_lock)); - return 1; -} - -static void *ssp_hasher_thread(void *userdata) -{ - uint32_t last_nonce2 = 0, point_index = 0, nonce2; - bool valid_nonce2 = false; - struct ssp_info *p_ssp_info = (struct ssp_info *)userdata; - - while (1) { - mutex_lock(&(sspinfo.hasher_lock)); - - if (!p_ssp_info->run) - valid_nonce2 = false; - - if (p_ssp_info->stratum_update) { - p_ssp_info->stratum_update = false; - point_index = 0; - last_nonce2 = 0; - valid_nonce2 = false; - ssp_sorter_flush(); - applog(LOG_NOTICE, "libssplus: stratum update"); - } - - /* Note: hasher is fast enough, so the new job will start with a lower nonce2 */ - nonce2 = (sspinfo.pram_addr[point_index] & 0xffffffff); - if (last_nonce2 > nonce2) - valid_nonce2 = true; - - point_index = (point_index + 1) % (POINTS_RAM_SIZE / sizeof(struct ssp_point)); - if (valid_nonce2) { -#ifdef SORTER_DEBUG - if (nonce2 > maxnonce) - maxnonce = nonce2; -#endif - ssp_sorter_insert((struct ssp_point *)&sspinfo.pram_addr[point_index]); - } - last_nonce2 = nonce2; - - mutex_unlock(&(sspinfo.hasher_lock)); - } - return NULL; -} - -static inline void ssp_hasher_fill_iram(struct ssp_hasher_instruction *p_inst, uint32_t inst_index) -{ - uint8_t i; - volatile uint32_t *p_iram_addr; - uint32_t tmp; - - p_iram_addr = sspinfo.iram_addr + inst_index * 32; - p_iram_addr[0] = p_inst->opcode; - simplelog(LOG_DEBUG, "iram[%d*32+0] = 0x%08x;", inst_index, p_inst->opcode); - - for (i = 0; i < 16; i++) { - tmp = ((p_inst->data[i * 4 + 0] << 24) | - (p_inst->data[i * 4 + 1] << 16) | - (p_inst->data[i * 4 + 2] << 8) | - (p_inst->data[i * 4 + 3])); - p_iram_addr[i + 1] = tmp; - simplelog(LOG_DEBUG, "iram[%d*32+%d] = 0x%08x;", inst_index, i + 1, tmp); - } - p_iram_addr[i + 1] = 0x1; /* flush */ - simplelog(LOG_DEBUG, "iram[%d*32+%d] = 1;", inst_index, i + 1); -} - -static inline void ssp_hasher_stop(void) -{ - sspinfo.iram_addr[31] = 1; - sspinfo.run = false; -} - -static inline void ssp_hasher_start(void) -{ - sspinfo.iram_addr[31] = 0; - sspinfo.run = true; -} - -int ssp_hasher_init(void) -{ - int memfd; - - memfd = open("/dev/mem", O_RDWR | O_SYNC); - if (memfd < 0) { - applog(LOG_ERR, "libssplus: failed open /dev/mem"); - return 1; - } - - sspinfo.iram_addr = (volatile uint32_t *)mmap(NULL, INSTRUCTIONS_RAM_SIZE, - PROT_READ | PROT_WRITE, - MAP_SHARED, memfd, - INSTRUCTIONS_RAM_START); - if (sspinfo.iram_addr == MAP_FAILED) { - close(memfd); - applog(LOG_ERR, "libssplus: mmap instructions ram failed"); - return 1; - } - - sspinfo.pram_addr = (volatile uint64_t *)mmap(NULL, POINTS_RAM_SIZE, - PROT_READ | PROT_WRITE, - MAP_SHARED, memfd, - POINTS_RAM_START); - if (sspinfo.pram_addr == MAP_FAILED) { - close(memfd); - applog(LOG_ERR, "libssplus: mmap points ram failed"); - return 1; - } - close(memfd); - - if (pthread_create(&(sspinfo.hasher_thr), NULL, ssp_hasher_thread, &sspinfo)) { - applog(LOG_ERR, "libssplus: create thread failed"); - return 1; - } - - sspinfo.stratum_update = false; - ssp_hasher_stop(); - mutex_init(&sspinfo.hasher_lock); - - return 0; -} - -static inline void sha256_prehash(const unsigned char *message, unsigned int len, unsigned char *digest) -{ - int i; - sha256_ctx ctx; - - sha256_init(&ctx); - sha256_update(&ctx, message, len); - - for (i = 0; i < 8; i++) - UNPACK32(ctx.h[i], &digest[i << 2]); -} - -void ssp_hasher_update_stratum(struct pool *pool, bool clean) -{ - struct ssp_hasher_instruction inst; - uint32_t coinbase_len_posthash, coinbase_len_prehash; - uint32_t i, len_rem, block_nb; - int merkle_index; - uint32_t inst_index = 0, nonce2_init = 0; - uint64_t coinbase_len_bits = pool->coinbase_len * 8; - - mutex_lock(&(sspinfo.hasher_lock)); - - ssp_hasher_stop(); - /* instruction init */ - inst.opcode = 0; - memset(inst.data, 0, SHA256_BLOCK_SIZE); - inst.data[28] = (nonce2_init >> 24) & 0xff; - inst.data[29] = (nonce2_init >> 16) & 0xff; - inst.data[30] = (nonce2_init >> 8) & 0xff; - inst.data[31] = (nonce2_init) & 0xff; - - coinbase_len_prehash = pool->nonce2_offset - (pool->nonce2_offset % SHA256_BLOCK_SIZE); - sha256_prehash(pool->coinbase, coinbase_len_prehash, inst.data + 32); - ssp_hasher_fill_iram(&inst, inst_index); - inst_index++; - - /* coinbase */ - coinbase_len_posthash = pool->coinbase_len - coinbase_len_prehash; - block_nb = coinbase_len_posthash / SHA256_BLOCK_SIZE; - len_rem = (coinbase_len_posthash % SHA256_BLOCK_SIZE); - for (i = 0; i < block_nb; i++) { - inst.opcode = INST_DATA_IRAM | NEXT_ADDR(inst_index + 1); - if (!i) { - inst.opcode |= (63 - (pool->nonce2_offset % SHA256_BLOCK_SIZE)); - inst.opcode |= INST_MID_INIT; - } else - inst.opcode |= INST_MID_LASTHASH; - memcpy(inst.data, pool->coinbase + coinbase_len_prehash + i * SHA256_BLOCK_SIZE, SHA256_BLOCK_SIZE); - ssp_hasher_fill_iram(&inst, inst_index); - inst_index++; - } - - memset(inst.data, 0, SHA256_BLOCK_SIZE); - inst.opcode = INST_DATA_IRAM | NEXT_ADDR(inst_index + 1); - if (!block_nb) { - inst.opcode |= (63 - (pool->nonce2_offset % SHA256_BLOCK_SIZE)); - inst.opcode |= INST_MID_INIT; - } else - inst.opcode |= INST_MID_LASTHASH; - memcpy(inst.data, pool->coinbase + coinbase_len_prehash + (block_nb * SHA256_BLOCK_SIZE), len_rem); - inst.data[len_rem] = 0x80; - - if (len_rem <= (SHA256_BLOCK_SIZE - 9)) { - for (i = 0; i < 8; i++) - inst.data[63 - i] = (coinbase_len_bits >> (i * 8)) & 0xff; - ssp_hasher_fill_iram(&inst, inst_index); - inst_index++; - } else { - ssp_hasher_fill_iram(&inst, inst_index); - inst_index++; - - memset(inst.data, 0, SHA256_BLOCK_SIZE); - inst.opcode = INST_DATA_IRAM | NEXT_ADDR(inst_index + 1); - inst.opcode |= INST_MID_LASTHASH; - for (i = 0; i < 8; i++) - inst.data[63 - i] = (coinbase_len_bits >> (i * 8)) & 0xff; - ssp_hasher_fill_iram(&inst, inst_index); - inst_index++; - } - - /* double hash coinbase */ - inst.opcode = INST_DATA_LASTHASH_PAD | INST_MID_INIT | NEXT_ADDR(inst_index + 1); - memset(inst.data, 0, SHA256_BLOCK_SIZE); - ssp_hasher_fill_iram(&inst, inst_index); - inst_index++; - - /* merkle branches */ - for (merkle_index = 0; merkle_index < pool->merkles; merkle_index++) { - inst.opcode = INST_DATA_LASTHASH_IRAM | INST_MID_INIT | NEXT_ADDR(inst_index + 1); - memcpy(inst.data + 32, pool->swork.merkle_bin[merkle_index], 32); - ssp_hasher_fill_iram(&inst, inst_index); - inst_index++; - - inst.opcode = INST_DATA_PAD512 | INST_MID_LASTHASH | NEXT_ADDR(inst_index + 1); - memset(inst.data, 0, SHA256_BLOCK_SIZE); - ssp_hasher_fill_iram(&inst, inst_index); - inst_index++; - - inst.opcode = INST_DATA_LASTHASH_PAD | INST_MID_INIT | NEXT_ADDR(inst_index + 1); - memset(inst.data, 0, SHA256_BLOCK_SIZE); - ssp_hasher_fill_iram(&inst, inst_index); - inst_index++; - } - - /* done */ - inst.opcode = INST_DONE; - ssp_hasher_fill_iram(&inst, inst_index); - - sspinfo.stratum_update = true; - ssp_hasher_start(); - mutex_unlock(&(sspinfo.hasher_lock)); -} - -struct testcase { - unsigned char *coinbase; - unsigned char (*merkle_branches)[32]; - unsigned int coinbase_len; - unsigned int merkles; - unsigned int n2size; - unsigned int nonce2_offset; -}; - -#define TESTCASE_COUNT 3 -void ssp_hasher_test(void) -{ - struct pool test_pool[2]; - struct timeval t_start, t_find_pair; - ssp_pair pair; - uint32_t tail[2]; - uint32_t pair_count = 0; - int i, pool_index; - double pair_diff; - struct testcase tc[TESTCASE_COUNT]; - unsigned int tci = 0; - bool stratum_update = true; - bool hasher_update = true; - - /* nonce2 4 bytes without block_nb */ - unsigned char coinbase[] = { - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x64,0x03,0x85,0xc3,0x06,0x37,0xe4,0xb8,0x83,0xe5,0xbd,0xa9,0xe7,0xa5,0x9e,0xe4,0xbb,0x99,0xe9,0xb1,0xbc,0x17,0x60, - 0xcb,0x03,0x29,0xf4,0xa7,0x98,0x99,0xde,0x10,0x87,0xd1,0x01,0xc6,0x1e,0x7a,0x1f,0x0f,0x25,0xc0,0xec,0xc4,0x74,0x65,0x8c,0x69,0x7c,0x78,0x79,0xa4,0x7a,0x02,0x00, - 0x00,0x00,0xf0,0x9f,0x90,0x9f,0x14,0x4d,0x69,0x6e,0x65,0x64,0x20,0x62,0x79,0x20,0x71,0x69,0x6e,0x66,0x65,0x6e,0x67,0x6c,0x69,0x6e,0x67,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x5d,0xcc,0xe0,0x4b,0x00,0x00,0x00,0x00,0x19,0x76,0xa9,0x14,0xc8, - 0x25,0xa1,0xec,0xf2,0xa6,0x83,0x0c,0x44,0x01,0x62,0x0c,0x3a,0x16,0xf1,0x99,0x50,0x57,0xc2,0xab,0x88,0xac,0xa0,0x60,0x82,0x2f - }; - - unsigned char merkle_branches[][32] = { - {0x0d,0x44,0xd1,0xab,0xc4,0x1e,0x2f,0xed,0x72,0xa7,0x46,0xc9,0x68,0x31,0xbd,0x98,0x60,0xe5,0x32,0x6c,0x96,0xf0,0xe8,0x97,0x72,0xf4,0x59,0x0e,0x0c,0x36,0xd9,0x7c}, - {0x10,0x24,0x76,0x6d,0xde,0x67,0xdf,0x66,0x54,0xa8,0xac,0x19,0x8d,0x9d,0xf2,0x45,0xea,0x74,0x60,0x2d,0x0d,0xb7,0xa6,0x34,0x5e,0x2d,0x51,0xe2,0x8a,0x8e,0xb1,0xf6}, - {0x2c,0x03,0x81,0x54,0xf9,0xfc,0xa7,0x7d,0xc8,0x09,0xcf,0xb4,0xc2,0x12,0x11,0xbe,0xbb,0x57,0x8d,0x4f,0x80,0x1f,0x78,0xce,0x5c,0x58,0x10,0xdb,0x03,0xb8,0x33,0xaa}, - {0x61,0xce,0xe4,0xd0,0xb9,0x85,0xf7,0xea,0xb2,0x57,0x39,0x16,0x24,0xb1,0x3d,0xf0,0xd0,0x09,0x65,0x75,0xb2,0xf5,0x95,0x63,0x4b,0x38,0xd8,0xcf,0x8a,0x36,0xe5,0xe9}, - {0x09,0xb4,0x42,0x7c,0xf6,0x18,0xa4,0xe4,0x18,0xd3,0xd1,0xa1,0xe0,0x47,0x7b,0x39,0x6f,0x7c,0x1d,0x70,0x00,0xed,0x07,0xc2,0xd6,0xc1,0x03,0x5b,0x93,0xe8,0x46,0xc6}, - {0x71,0xb0,0x09,0x2f,0x74,0xe9,0x3a,0x86,0x85,0xc6,0x8a,0x27,0xcd,0x2b,0x80,0x13,0xf9,0x4b,0x20,0xcd,0xdb,0x8f,0xfd,0xb2,0x28,0x2e,0x17,0x4f,0xc7,0xd8,0x83,0xd5}, - {0x27,0xc2,0x80,0x96,0xd7,0x8f,0x41,0xfb,0x18,0x2c,0x7c,0xe8,0xce,0x59,0x5a,0x81,0x3f,0x08,0xdb,0xbb,0x02,0xd2,0x43,0x99,0x18,0x04,0x0b,0x61,0x60,0x2f,0x5f,0xba}, - {0xe7,0xf8,0x8a,0x99,0xf3,0x50,0x3c,0xf7,0x81,0x3b,0x9e,0x7e,0xf9,0x6c,0x98,0x85,0x4a,0x67,0x07,0x08,0x61,0x8f,0xe3,0x8c,0x3d,0x78,0xc8,0xd0,0x0e,0x14,0x86,0xf9}, - {0x48,0x56,0x1c,0x47,0x35,0x49,0x4b,0xdb,0x5a,0x19,0xd5,0x27,0xe5,0x7e,0x52,0x59,0x2e,0xe8,0xab,0xae,0xa1,0xc9,0x3e,0x0b,0x09,0x06,0x70,0x81,0xb8,0x38,0xa9,0x22}, - {0x95,0x9c,0x26,0x49,0xa2,0xcc,0xd6,0x96,0x47,0x11,0x49,0xb8,0x31,0x44,0x17,0x01,0xeb,0x32,0xac,0x95,0x07,0xf6,0xd0,0x5c,0x7c,0x0e,0xf9,0x2a,0xd3,0xc2,0xfc,0x27}, - }; - - tc[0].coinbase = coinbase; - tc[0].merkle_branches = merkle_branches; - tc[0].coinbase_len = sizeof(coinbase); - tc[0].merkles = sizeof(merkle_branches) / 32; - tc[0].n2size = 4; - tc[0].nonce2_offset = 142; - - /* nonce2 4 bytes with block_nb */ - unsigned char coinbase1[] = { - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x45,0x03,0x0e,0x47,0x06,0xfa,0xbe,0x6d,0x6d,0x36,0xef,0x89,0xc9,0x76,0xd4,0xb8,0x75,0x52,0xf3,0x52,0x89,0x4a,0x26, - 0xd3,0x07,0x98,0x4b,0x28,0x1d,0x6e,0x3d,0x3a,0xa2,0xa8,0xc8,0x21,0x67,0x33,0x50,0x79,0x95,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xde,0xad,0xbe,0xef,0xca,0xfe, - 0xbe,0x00,0x00,0x00,0x00,0x10,0xe3,0x03,0x2f,0x73,0x6c,0x75,0x73,0x68,0x2f,0x00,0x00,0x00,0x00,0x01,0xeb,0xb9,0xed,0x97,0x00,0x00,0x00,0x00,0x19,0x76,0xa9,0x14, - 0x7c,0x15,0x4e,0xd1,0xdc,0x59,0x60,0x9e,0x3d,0x26,0xab,0xb2,0xdf,0x2e,0xa3,0xd5,0x87,0xcd,0x8c,0x41,0x88,0xac,0x00,0x00,0x00,0x00 - }; - - unsigned char merkle_branches1[][32] = { - {0xf2,0xe1,0xd3,0x58,0x4d,0x02,0x24,0xfb,0x0b,0x7b,0x43,0xc8,0x87,0x41,0x3b,0xb6,0xab,0x3e,0xaf,0x5a,0x79,0x92,0x90,0xc2,0x56,0x9f,0x20,0xb5,0xfe,0x6b,0x0b,0x36}, - {0x36,0xb3,0xff,0xba,0x99,0xb8,0x9f,0xe4,0x0f,0xf3,0x21,0x64,0xf0,0xa1,0x19,0x86,0x0f,0x09,0x13,0x4c,0xe2,0x54,0x1e,0xff,0x38,0xc6,0xab,0x55,0xcc,0x58,0xd2,0xe4}, - {0x13,0xb1,0x66,0xdc,0x92,0x6f,0x3f,0x37,0xdb,0x30,0xec,0x4d,0x7b,0x37,0x38,0xac,0xf5,0x38,0xb6,0x4d,0x1f,0x11,0x6c,0xd2,0xee,0x84,0x5b,0xd2,0x15,0x62,0x99,0x78}, - {0x72,0x24,0xd0,0x31,0x90,0x4a,0x30,0xe0,0x7f,0x8d,0x41,0x48,0xa7,0x26,0x21,0xed,0xd3,0x47,0x0a,0xb7,0x38,0x52,0x0e,0xaf,0x65,0xab,0x3b,0xcd,0xf0,0x1c,0xeb,0x67}, - {0x81,0x85,0xe7,0x18,0x92,0xe5,0xf6,0xc5,0x05,0xba,0xe0,0xdb,0x45,0x45,0xfe,0x86,0x68,0x9a,0x11,0xb8,0x04,0x32,0x14,0x5c,0x72,0x1f,0xf9,0x6c,0xe5,0x26,0x86,0x0a}, - {0xea,0xff,0xbf,0x99,0x8f,0xfc,0x3c,0xa8,0x35,0x14,0x60,0x79,0xa3,0xdc,0x6c,0x97,0x3a,0xe7,0xb0,0xb9,0x64,0x69,0xc7,0x16,0x7b,0x17,0x12,0x46,0x87,0xdd,0x10,0x3f}, - {0x99,0x5a,0x04,0xf1,0x56,0xdf,0x6b,0x09,0x46,0xd2,0x65,0x23,0x6d,0x59,0xdf,0xeb,0xaa,0x60,0xda,0xd0,0x09,0xc3,0x22,0x56,0x14,0xf8,0xbd,0xd1,0x1c,0x74,0x7e,0x71}, - {0xf8,0x3f,0xe9,0x84,0x7c,0x0b,0x35,0x5e,0xfa,0x59,0x06,0x11,0xd2,0x82,0xd2,0x33,0x0b,0x28,0xd2,0x3d,0x18,0x4a,0x45,0x6d,0x05,0xff,0x5f,0x7b,0xaf,0x6a,0xda,0x81}, - {0x13,0xd7,0x5e,0xf4,0xda,0x4b,0x1a,0x2a,0xc9,0x42,0x19,0x7d,0x18,0x5e,0x93,0x4a,0xec,0x72,0x09,0xbc,0x95,0x2a,0xa2,0xdd,0xc6,0x77,0x4f,0xdb,0x1e,0x65,0x2c,0xd7}, - {0x85,0x6b,0x96,0xe8,0x56,0x3e,0xaa,0x9e,0x59,0x3a,0xa7,0xe0,0x29,0xc2,0xd4,0x01,0xc5,0x66,0xf7,0x8d,0x8e,0xf8,0x22,0xda,0xfe,0x79,0x5f,0x10,0x8a,0x59,0x8a,0x28}, - {0xce,0x79,0x63,0xa5,0x43,0xe1,0x00,0x18,0xf2,0x3e,0x3d,0xfd,0x52,0x01,0x17,0x55,0xe5,0xc8,0x47,0x37,0xa0,0xd0,0x86,0x51,0xb8,0x8c,0x89,0x56,0x71,0xf3,0x96,0x49}, - {0x88,0x73,0x89,0x13,0xa3,0xc7,0x3a,0xee,0x99,0x6c,0xc9,0xf5,0x76,0x0a,0xec,0x41,0xf6,0x97,0x99,0xd4,0x9b,0x09,0x36,0x4c,0x12,0xb3,0x6a,0x37,0x9c,0x18,0x42,0xef}, - }; - - tc[1].coinbase = coinbase1; - tc[1].merkle_branches = merkle_branches1; - tc[1].coinbase_len = sizeof(coinbase1); - tc[1].merkles = sizeof(merkle_branches1) / 32; - tc[1].n2size = 4; - tc[1].nonce2_offset = 97; - - /* nonce2 8 bytes */ - unsigned char coinbase2[] = { - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x31,0x03,0x18,0xc4,0x06,0x00,0x04,0xa6,0xfc,0x50,0x58,0x04,0x20,0xb8,0xb4,0x15,0x0c,0x62,0xa4,0x85,0x58,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x63,0x6b,0x70,0x6f,0x6f,0x6c,0x0d,0x2f,0x4b,0x61,0x6e,0x6f,0x20,0x2f,0x42,0x45,0x42,0x4f,0x50,0x2f,0xff,0xff,0xff,0xff,0x02, - 0xe4,0xf2,0x64,0x4d,0x00,0x00,0x00,0x00,0x19,0x76,0xa9,0x14,0x1e,0xff,0xba,0x01,0xe0,0xc6,0x5d,0x69,0x44,0xe5,0x99,0x2e,0x7b,0xa5,0x3d,0x29,0xfc,0x02,0x05,0xca, - 0x88,0xac,0x9b,0xef,0xb3,0x00,0x00,0x00,0x00,0x00,0x19,0x76,0xa9,0x14,0x5d,0xdd,0xa1,0xc1,0x1c,0xe7,0xdf,0x66,0x81,0xcb,0x06,0x4c,0xf9,0xaa,0xb5,0xd6,0xdf,0x44, - 0xbb,0x1b,0x88,0xac,0x00,0x00,0x00,0x00 - }; - - unsigned char merkle_branches2[][32] = { - {0xdf,0x40,0xcf,0x4d,0x90,0x64,0xb3,0x9e,0xce,0x1a,0x32,0x42,0xb0,0x33,0x97,0xea,0x1b,0x43,0x23,0x13,0x8a,0x0a,0x51,0x52,0x7a,0x20,0x74,0xf2,0x71,0xc3,0x88,0x52}, - {0xed,0xb0,0x7a,0x6c,0x50,0x99,0x0f,0xe8,0x9e,0xe7,0x84,0xd7,0x82,0xa0,0xe6,0xd8,0xdd,0x99,0xd6,0x15,0x35,0x63,0xa9,0x3d,0xd3,0x6c,0xb9,0xdb,0x5a,0x1e,0x34,0x5f}, - {0x64,0x98,0xb5,0x26,0x04,0x8f,0x08,0x15,0xd9,0x39,0x0d,0x0f,0x32,0x08,0x57,0x49,0x83,0xcd,0x72,0x52,0x84,0xe3,0x74,0xe0,0xe5,0xda,0x5a,0xcc,0x8e,0xdb,0xe4,0x4c}, - {0x3c,0x78,0x9f,0x8c,0xf7,0x39,0x93,0x52,0x55,0xf4,0x34,0x42,0x9a,0x77,0xe3,0xcf,0x22,0xf6,0x1c,0x4a,0x38,0x2e,0x32,0xfd,0xb5,0xd0,0x3d,0x36,0x9b,0x31,0x79,0x5a}, - {0xc2,0xce,0xd4,0x9b,0x26,0xdf,0x6d,0x83,0x25,0xf8,0x33,0x94,0x60,0xf8,0x8f,0x69,0xbd,0x98,0x07,0x18,0x94,0xa4,0x5a,0x14,0x2a,0x54,0x6e,0x6d,0x88,0xb4,0xc7,0xd2}, - {0x4f,0x62,0x78,0x05,0xdc,0x7e,0x4d,0xc8,0x52,0x6a,0xc8,0xb2,0x86,0xf6,0x52,0x0d,0x17,0x57,0x74,0x59,0x04,0xc3,0x9d,0x38,0xa6,0xf8,0xc3,0x6b,0x74,0xfd,0x5d,0x10}, - {0xe1,0xd3,0xfb,0x46,0x1c,0xb4,0xbe,0xd1,0x55,0xcf,0x9e,0x21,0x2b,0x65,0xe1,0x0f,0xd1,0x65,0x1a,0x2e,0x25,0x78,0x74,0x0f,0x6c,0xb1,0x11,0xa2,0x26,0x34,0xba,0x9e}, - {0x63,0xd0,0x2e,0x76,0xd7,0x54,0xf7,0x67,0xef,0x9a,0x3c,0xa3,0xae,0xa0,0x5e,0xb2,0xc3,0x94,0x75,0x99,0x73,0xf0,0x40,0xa1,0x80,0x9e,0x02,0xf3,0x0e,0xed,0xcd,0x0d}, - {0x7f,0x51,0x79,0xc7,0x36,0x27,0xe7,0x35,0xf4,0x41,0x52,0x04,0x0a,0xd8,0x61,0xe6,0x95,0x97,0xb6,0x89,0x81,0x09,0x17,0x4e,0x09,0x2d,0x28,0xc0,0x37,0x74,0x73,0x52}, - {0x9c,0x37,0x53,0xe0,0x39,0x6f,0x49,0xe4,0x46,0xb9,0xf8,0x82,0x0a,0xaf,0xd0,0x7b,0x38,0xf7,0xea,0x6f,0xf8,0xc3,0x60,0x05,0x96,0x99,0x9b,0x1c,0xbb,0x51,0xd7,0x49}, - {0x20,0xf8,0x90,0x21,0xa8,0x4c,0xb4,0x93,0x0d,0xf8,0x1d,0xfc,0x66,0x81,0xab,0x0e,0x01,0x97,0x95,0x42,0x03,0x36,0x41,0x0f,0xfc,0x2b,0xe2,0x9a,0x31,0x34,0x8e,0x5f}, - }; - - tc[2].coinbase = coinbase2; - tc[2].merkle_branches = merkle_branches2; - tc[2].coinbase_len = sizeof(coinbase2); - tc[2].merkles = sizeof(merkle_branches2) / 32; - tc[2].n2size = 8; - tc[2].nonce2_offset = 62; - - ssp_sorter_init(HT_SIZE, HT_PRB_LMT, HT_PRB_C1, HT_PRB_C2); - ssp_hasher_init(); - - cgtime(&t_start); - while (1) { - if (stratum_update) { - for (pool_index = 0; pool_index < 2; pool_index++) { - test_pool[pool_index].coinbase_len = tc[tci].coinbase_len; - test_pool[pool_index].coinbase = cgcalloc(test_pool[pool_index].coinbase_len, 1); - test_pool[pool_index].merkles = tc[tci].merkles; - - test_pool[pool_index].swork.merkle_bin = cgmalloc(sizeof(char *) * test_pool[pool_index].merkles + 1); - for (i = 0; i < test_pool[pool_index].merkles; i++) { - test_pool[pool_index].swork.merkle_bin[i] = cgmalloc(32); - memcpy(test_pool[pool_index].swork.merkle_bin[i], tc[tci].merkle_branches[i], 32); - } - memcpy(test_pool[pool_index].coinbase, tc[tci].coinbase, test_pool[pool_index].coinbase_len); - test_pool[pool_index].n2size = tc[tci].n2size; - test_pool[pool_index].nonce2_offset = tc[tci].nonce2_offset; - } - stratum_update = false; - hasher_update = true; - } - - if (ssp_sorter_get_pair(pair)) { - cgtime(&t_find_pair); - pair_diff = tdiff(&t_find_pair, &t_start); - applog(LOG_NOTICE, "%0.8fs\tGot a pair %08x-%08x", pair_diff, pair[0], pair[1]); - tail[0] = gen_merkle_root(&test_pool[1], pair[0]); - tail[1] = gen_merkle_root(&test_pool[1], pair[1]); - if (tail[0] != tail[1]) { - applog(LOG_NOTICE, "tail mismatch (%08x:%08x -> %08x:%08x)", - tail[0], - tail[1], - pair[0], - pair[1]); - } else { - applog(LOG_NOTICE, "tail pass (%08x -> %08x:%08x)", - tail[0], - pair[0], - pair[1]); - } - - memcpy(&t_start, &t_find_pair, sizeof(t_find_pair)); - - pair_count++; - if (pair_count == 20) { - stratum_update = true; - pair_count = 0; - tci = (tci + 1) % TESTCASE_COUNT; - - for (pool_index = 0; pool_index < 2; pool_index++) { - free(test_pool[pool_index].coinbase); - for (i = 0; i < test_pool[pool_index].merkles; i++) - free(test_pool[pool_index].swork.merkle_bin[i]); - } - } - } - - if (hasher_update) { - hasher_update = false; - ssp_hasher_update_stratum(&test_pool[0], true); - } - } - - quit(1, "ssp_hasher_test finished\n"); -} diff --git a/libssplus.h b/libssplus.h deleted file mode 100644 index 86fda3fa10..0000000000 --- a/libssplus.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2016 Mikeqin - * - * 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 LIBSSPLUS_H -#define LIBSSPLUS_H - -#define HT_SIZE (1 << 22) -#define HT_PRB_LMT 1 -#define HT_PRB_C1 0 -#define HT_PRB_C2 1 - -typedef uint32_t ssp_pair[2]; - -int ssp_hasher_init(void); -void ssp_hasher_update_stratum(struct pool *pool, bool clean); -void ssp_hasher_test(void); - -void ssp_sorter_init(uint32_t max_size, uint32_t limit, uint32_t c1, uint32_t c2); -void ssp_sorter_flush(void); -int ssp_sorter_get_pair(ssp_pair pair); - -#endif /* LIBSSPLUS_H */ diff --git a/miner.h b/miner.h index 914a3fa295..72c39e83f8 100644 --- a/miner.h +++ b/miner.h @@ -1130,7 +1130,6 @@ extern void set_target(unsigned char *dest_target, double diff); #if defined (USE_AVALON2) || defined (USE_AVALON4) || defined (USE_AVALON7) || defined (USE_AVALON8) || defined (USE_AVALON_MINER) || defined (USE_HASHRATIO) bool submit_nonce2_nonce(struct thr_info *thr, struct pool *pool, struct pool *real_pool, uint32_t nonce2, uint32_t nonce, uint32_t ntime); -uint32_t gen_merkle_root(struct pool *pool, uint64_t nonce2); #endif extern int restart_wait(struct thr_info *thr, unsigned int mstime); diff --git a/util.c b/util.c index 7de2e6212d..3e3cee319d 100644 --- a/util.c +++ b/util.c @@ -44,11 +44,6 @@ #include "elist.h" #include "compat.h" #include "util.h" -#include "libssplus.h" - -#ifdef USE_AVALON7 -#include "driver-avalon7.h" -#endif #define DEFAULT_SOCKWAIT 60 #ifndef STRATUM_USER_AGENT @@ -2156,13 +2151,8 @@ static bool parse_notify(struct pool *pool, json_t *val) /* A notify message is the closest stratum gets to a getwork */ pool->getwork_requested++; total_getworks++; - if (pool == current_pool()) { + if (pool == current_pool()) opt_work_update = true; -#ifdef USE_AVALON7 - if (opt_avalon7_ssplus_enable & pool->has_stratum) - ssp_hasher_update_stratum(pool, true); -#endif - } out: return ret; } From e041ef3280350d47d6a1dba0c049ba7ed42a6372 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 1 Nov 2018 18:02:09 +0800 Subject: [PATCH 088/113] Fix compile error --- driver-avalon8.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver-avalon8.c b/driver-avalon8.c index f80849b483..49f82feda1 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -1995,9 +1995,9 @@ static void avalon8_sswork_update(struct cgpu_info *avalon8) */ if (thr->work_restart) info->work_restart = thr->work_restart; - applog(LOG_NOTICE, "%s-%d: New stratum: restart: %d, update: %d, clean: %d", + applog(LOG_NOTICE, "%s-%d: New stratum: restart: %d, update: %d", avalon8->drv->name, avalon8->device_id, - thr->work_restart, thr->work_update, thr->clean_jobs); + thr->work_restart, thr->work_update); /* Step 1: MM protocol check */ pool = current_pool(); From 676c5ef354a742ac21d22783c36b8a9a7c270142 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 1 Nov 2018 20:07:53 +0800 Subject: [PATCH 089/113] Fix no hashrate of Avalon8 --- driver-avalon8.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/driver-avalon8.c b/driver-avalon8.c index 49f82feda1..056af9599b 100644 --- a/driver-avalon8.c +++ b/driver-avalon8.c @@ -2095,6 +2095,8 @@ static int64_t avalon8_scanhash(struct thr_info *thr) switch (info->freq_mode[i]) { case AVA8_FREQ_INIT_MODE: update_settings = true; + /* Make sure to send configuration first */ + thr->work_update = false; for (j = 0; j < info->miner_count[i]; j++) { for (k = 0; k < AVA8_DEFAULT_PLL_CNT; k++) { if (opt_avalon8_freq[k] != AVA8_DEFAULT_FREQUENCY) From 508be0608e778939c5fe2b94ef38989a04bd2307 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 6 Dec 2018 19:32:30 +0800 Subject: [PATCH 090/113] Update README and ASIC-README for Avalon8 --- ASIC-README | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/ASIC-README b/ASIC-README index 9c4629d161..221b2aec5b 100644 --- a/ASIC-README +++ b/ASIC-README @@ -9,6 +9,7 @@ Currently supported devices include: - Avalon2/3 - Avalon4/4.1/6 - Avalon7 +- Avalon8 - BFx2 USB - Butterfly Labs SC 65/28nm range - BF1 (bitfury) USB (red and blue) @@ -59,6 +60,8 @@ Avalon4/4.1/6 devies need the --enable-avalon4 option when compiling cgminer. Avalon7 will come up as AV7. +Avalon8 will come up as AV8. + Klondike will come up as KLN. Klondike devices need the --enable-klondike option when compiling cgminer. @@ -322,6 +325,35 @@ ASIC SPECIFIC COMMANDS --avalon7-freqadj-temp Set Avalon7 check temperature when run into AVA7_FREQ_TEMPADJ_MODE (default: 104) --avalon7-nonce-mask Set A3212 nonce mask, range 24-32. (default: 31) --no-avalon7-asic-debug Disable A3212 debug. +--avalon8-voltage-level Set Avalon8 default level of core voltage, range:[0, 15], step: 1 +--avalon8-voltage-level-offset Set Avalon8 default offset of core voltage level, range:[-2, 1], step: 1 +--avalon8-freq Set Avalon8 default frequency, range:[25, 1200], step: 25, example: 800 +--avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 4], step: 1, example: 3 (default: 3) +--avalon8-fan Set Avalon8 target fan speed, range:[0, 100], step: 1, example: 0-100 +--avalon8-temp Set Avalon8 target temperature, range:[0, 100] (default: 90) +--avalon8-polling-delay Set Avalon8 polling delay value (ms) (default: 20) +--avalon8-aucspeed Set AUC3 IIC bus speed (default: 400000) +--avalon8-aucxdelay Set AUC3 IIC xfer read delay, 4800 ~= 1ms (default: 19200) +--avalon8-smart-speed Set Avalon8 smart speed, range 0-1. 0 means Disable (default: 1) +--avalon8-th-pass Set A3210 th pass value (default: -1) +--avalon8-th-fail Set A3210 th fail value (default: -1) +--avalon8-th-init Set A3210 th init value (default: 32767) +--avalon8-th-ms Set A3210 th ms value (default: 5) +--avalon8-th-timeout Set A3210 th timeout value (default: 4294967295) +--avalon8-th-add Set A3210 th add value (default: 1) +--avalon8-iic-detect Enable Avalon8 detect through iic controller +--avalon8-nonce-mask Set A3210 nonce mask, range 24-32. (default: -1) +--avalon8-nonce-check Set A3210 nonce check, range 0-1. (default: 1) +--avalon8-roll-enable Set A3210 roll enable, range 0-1. (default: 1) +--avalon8-mux-l2h Set Avalon8 mux l2h, range 0-2. (default: 0) +--avalon8-mux-h2l Set Avalon8 mux h2l, range 0-1. (default: 1) +--avalon8-h2ltime0-spd Set Avalon8 h2ltime0 spd, range 0-255. (default: 3) +--avalon8-spdlow Set Avalon8 spdlow, range 0-3. (default: -1) +--avalon8-spdhigh Set Avalon8 spdhigh, range 0-3. (default: 3) +--avalon8-cinfo-asic Set Avalon8 cinfo asic index, range:[0, 25], step: 1 +--avalon8-pid-p Set Avalon8 pid-p, range 0-9999. (default: 2) +--avalon8-pid-i Set Avalon8 pid-i, range 0-9999. (default: 5) +--avalon8-pid-d Set Avalon8 pid-d, range 0-9999. (default: 0) --bab-options Set BaB options max:def:min:up:down:hz:delay:trf --bet-clk Set clockspeed of ASICMINER Tube/Prisma to (arg+1)*10MHz (default: 23) --bflsc-overheat Set overheat temperature where BFLSC devices throttle, 0 to disable (default: 90) @@ -647,6 +679,38 @@ Avalon7 Devices --avalon7-nonce-mask Set A3212 nonce mask, range 24-32. (default: 31) --no-avalon7-asic-debug Disable A3212 debug. +Avalon8 Devices + +--avalon8-voltage-level Set Avalon8 default level of core voltage, range:[0, 15], step: 1 +--avalon8-voltage-level-offset Set Avalon8 default offset of core voltage level, range:[-2, 1], step: 1 +--avalon8-freq Set Avalon8 default frequency, range:[25, 1200], step: 25, example: 800 +--avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 4], step: 1, example: 3 (default: 3) +--avalon8-fan Set Avalon8 target fan speed, range:[0, 100], step: 1, example: 0-100 +--avalon8-temp Set Avalon8 target temperature, range:[0, 100] (default: 90) +--avalon8-polling-delay Set Avalon8 polling delay value (ms) (default: 20) +--avalon8-aucspeed Set AUC3 IIC bus speed (default: 400000) +--avalon8-aucxdelay Set AUC3 IIC xfer read delay, 4800 ~= 1ms (default: 19200) +--avalon8-smart-speed Set Avalon8 smart speed, range 0-1. 0 means Disable (default: 1) +--avalon8-th-pass Set A3210 th pass value (default: -1) +--avalon8-th-fail Set A3210 th fail value (default: -1) +--avalon8-th-init Set A3210 th init value (default: 32767) +--avalon8-th-ms Set A3210 th ms value (default: 5) +--avalon8-th-timeout Set A3210 th timeout value (default: 4294967295) +--avalon8-th-add Set A3210 th add value (default: 1) +--avalon8-iic-detect Enable Avalon8 detect through iic controller +--avalon8-nonce-mask Set A3210 nonce mask, range 24-32. (default: -1) +--avalon8-nonce-check Set A3210 nonce check, range 0-1. (default: 1) +--avalon8-roll-enable Set A3210 roll enable, range 0-1. (default: 1) +--avalon8-mux-l2h Set Avalon8 mux l2h, range 0-2. (default: 0) +--avalon8-mux-h2l Set Avalon8 mux h2l, range 0-1. (default: 1) +--avalon8-h2ltime0-spd Set Avalon8 h2ltime0 spd, range 0-255. (default: 3) +--avalon8-spdlow Set Avalon8 spdlow, range 0-3. (default: -1) +--avalon8-spdhigh Set Avalon8 spdhigh, range 0-3. (default: 3) +--avalon8-cinfo-asic Set Avalon8 cinfo asic index, range:[0, 25], step: 1 +--avalon8-pid-p Set Avalon8 pid-p, range 0-9999. (default: 2) +--avalon8-pid-i Set Avalon8 pid-i, range 0-9999. (default: 5) +--avalon8-pid-d Set Avalon8 pid-d, range 0-9999. (default: 0) + BFLSC Devices --bflsc-overheat Set overheat temperature where BFLSC devices throttle, 0 to disable (default: 90) diff --git a/README b/README index e81d9b18c7..665d7de6d0 100644 --- a/README +++ b/README @@ -128,6 +128,7 @@ CGMiner specific configuration options: --enable-avalon2 Compile support for Avalon2/3 (default disabled) --enable-avalon4 Compile support for Avalon4/4.1/6 (default disabled) --enable-avalon7 Compile support for Avalon7 (default disabled) + --enable-avalon8 Compile support for Avalon8 (default disabled) --enable-bab Compile support for BlackArrow Bitfury (default disabled) --enable-bflsc Compile support for BFL ASICs (default disabled) @@ -258,6 +259,35 @@ Options for both config file and command line: --avalon7-freqadj-temp Set Avalon7 check temperature when run into AVA7_FREQ_TEMPADJ_MODE (default: 104) --avalon7-nonce-mask Set A3212 nonce mask, range 24-32. (default: 31) --no-avalon7-asic-debug Disable A3212 debug. +--avalon8-voltage-level Set Avalon8 default level of core voltage, range:[0, 15], step: 1 +--avalon8-voltage-level-offset Set Avalon8 default offset of core voltage level, range:[-2, 1], step: 1 +--avalon8-freq Set Avalon8 default frequency, range:[25, 1200], step: 25, example: 800 +--avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 4], step: 1, example: 3 (default: 3) +--avalon8-fan Set Avalon8 target fan speed, range:[0, 100], step: 1, example: 0-100 +--avalon8-temp Set Avalon8 target temperature, range:[0, 100] (default: 90) +--avalon8-polling-delay Set Avalon8 polling delay value (ms) (default: 20) +--avalon8-aucspeed Set AUC3 IIC bus speed (default: 400000) +--avalon8-aucxdelay Set AUC3 IIC xfer read delay, 4800 ~= 1ms (default: 19200) +--avalon8-smart-speed Set Avalon8 smart speed, range 0-1. 0 means Disable (default: 1) +--avalon8-th-pass Set A3210 th pass value (default: -1) +--avalon8-th-fail Set A3210 th fail value (default: -1) +--avalon8-th-init Set A3210 th init value (default: 32767) +--avalon8-th-ms Set A3210 th ms value (default: 5) +--avalon8-th-timeout Set A3210 th timeout value (default: 4294967295) +--avalon8-th-add Set A3210 th add value (default: 1) +--avalon8-iic-detect Enable Avalon8 detect through iic controller +--avalon8-nonce-mask Set A3210 nonce mask, range 24-32. (default: -1) +--avalon8-nonce-check Set A3210 nonce check, range 0-1. (default: 1) +--avalon8-roll-enable Set A3210 roll enable, range 0-1. (default: 1) +--avalon8-mux-l2h Set Avalon8 mux l2h, range 0-2. (default: 0) +--avalon8-mux-h2l Set Avalon8 mux h2l, range 0-1. (default: 1) +--avalon8-h2ltime0-spd Set Avalon8 h2ltime0 spd, range 0-255. (default: 3) +--avalon8-spdlow Set Avalon8 spdlow, range 0-3. (default: -1) +--avalon8-spdhigh Set Avalon8 spdhigh, range 0-3. (default: 3) +--avalon8-cinfo-asic Set Avalon8 cinfo asic index, range:[0, 25], step: 1 +--avalon8-pid-p Set Avalon8 pid-p, range 0-9999. (default: 2) +--avalon8-pid-i Set Avalon8 pid-i, range 0-9999. (default: 5) +--avalon8-pid-d Set Avalon8 pid-d, range 0-9999. (default: 0) --bab-options Set BaB options max:def:min:up:down:hz:delay:trf --balance Change multipool strategy from failover to even share balance --benchfile Run cgminer in benchmark mode using a work file - produces no shares @@ -451,6 +481,35 @@ ASIC only options: --avalon7-freqadj-temp Set Avalon7 check temperature when run into AVA7_FREQ_TEMPADJ_MODE (default: 104) --avalon7-nonce-mask Set A3212 nonce mask, range 24-32. (default: 31) --no-avalon7-asic-debug Disable A3212 debug. +--avalon8-voltage-level Set Avalon8 default level of core voltage, range:[0, 15], step: 1 +--avalon8-voltage-level-offset Set Avalon8 default offset of core voltage level, range:[-2, 1], step: 1 +--avalon8-freq Set Avalon8 default frequency, range:[25, 1200], step: 25, example: 800 +--avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 4], step: 1, example: 3 (default: 3) +--avalon8-fan Set Avalon8 target fan speed, range:[0, 100], step: 1, example: 0-100 +--avalon8-temp Set Avalon8 target temperature, range:[0, 100] (default: 90) +--avalon8-polling-delay Set Avalon8 polling delay value (ms) (default: 20) +--avalon8-aucspeed Set AUC3 IIC bus speed (default: 400000) +--avalon8-aucxdelay Set AUC3 IIC xfer read delay, 4800 ~= 1ms (default: 19200) +--avalon8-smart-speed Set Avalon8 smart speed, range 0-1. 0 means Disable (default: 1) +--avalon8-th-pass Set A3210 th pass value (default: -1) +--avalon8-th-fail Set A3210 th fail value (default: -1) +--avalon8-th-init Set A3210 th init value (default: 32767) +--avalon8-th-ms Set A3210 th ms value (default: 5) +--avalon8-th-timeout Set A3210 th timeout value (default: 4294967295) +--avalon8-th-add Set A3210 th add value (default: 1) +--avalon8-iic-detect Enable Avalon8 detect through iic controller +--avalon8-nonce-mask Set A3210 nonce mask, range 24-32. (default: -1) +--avalon8-nonce-check Set A3210 nonce check, range 0-1. (default: 1) +--avalon8-roll-enable Set A3210 roll enable, range 0-1. (default: 1) +--avalon8-mux-l2h Set Avalon8 mux l2h, range 0-2. (default: 0) +--avalon8-mux-h2l Set Avalon8 mux h2l, range 0-1. (default: 1) +--avalon8-h2ltime0-spd Set Avalon8 h2ltime0 spd, range 0-255. (default: 3) +--avalon8-spdlow Set Avalon8 spdlow, range 0-3. (default: -1) +--avalon8-spdhigh Set Avalon8 spdhigh, range 0-3. (default: 3) +--avalon8-cinfo-asic Set Avalon8 cinfo asic index, range:[0, 25], step: 1 +--avalon8-pid-p Set Avalon8 pid-p, range 0-9999. (default: 2) +--avalon8-pid-i Set Avalon8 pid-i, range 0-9999. (default: 5) +--avalon8-pid-d Set Avalon8 pid-d, range 0-9999. (default: 0) --bab-options Set BaB options max:def:min:up:down:hz:delay:trf --bflsc-overheat Set overheat temperature where BFLSC devices throttle, 0 to disable (default: 90) --bitburner-fury-options Override avalon-options for BitBurner Fury boards baud:miners:asic:timeout:freq @@ -1173,6 +1232,7 @@ USB on any hardware are the following: --enable-avalon2 --enable-avalon4 --enable-avalon7 +--enable-avalon8 --enable-bflsc --enable-bitfury --enable-cointerra From 737e241a255fc9c0ea58e9f4fb242bf61539cd43 Mon Sep 17 00:00:00 2001 From: Johnson-Fan <1314zhengyi@gmail.com> Date: Thu, 6 Dec 2018 20:07:56 +0800 Subject: [PATCH 091/113] Fix --avalon8-freq-sel range --- ASIC-README | 4 ++-- README | 4 ++-- cgminer.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ASIC-README b/ASIC-README index 221b2aec5b..c92c1517e5 100644 --- a/ASIC-README +++ b/ASIC-README @@ -328,7 +328,7 @@ ASIC SPECIFIC COMMANDS --avalon8-voltage-level Set Avalon8 default level of core voltage, range:[0, 15], step: 1 --avalon8-voltage-level-offset Set Avalon8 default offset of core voltage level, range:[-2, 1], step: 1 --avalon8-freq Set Avalon8 default frequency, range:[25, 1200], step: 25, example: 800 ---avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 4], step: 1, example: 3 (default: 3) +--avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 3], step: 1, example: 3 (default: 3) --avalon8-fan Set Avalon8 target fan speed, range:[0, 100], step: 1, example: 0-100 --avalon8-temp Set Avalon8 target temperature, range:[0, 100] (default: 90) --avalon8-polling-delay Set Avalon8 polling delay value (ms) (default: 20) @@ -684,7 +684,7 @@ Avalon8 Devices --avalon8-voltage-level Set Avalon8 default level of core voltage, range:[0, 15], step: 1 --avalon8-voltage-level-offset Set Avalon8 default offset of core voltage level, range:[-2, 1], step: 1 --avalon8-freq Set Avalon8 default frequency, range:[25, 1200], step: 25, example: 800 ---avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 4], step: 1, example: 3 (default: 3) +--avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 3], step: 1, example: 3 (default: 3) --avalon8-fan Set Avalon8 target fan speed, range:[0, 100], step: 1, example: 0-100 --avalon8-temp Set Avalon8 target temperature, range:[0, 100] (default: 90) --avalon8-polling-delay Set Avalon8 polling delay value (ms) (default: 20) diff --git a/README b/README index 665d7de6d0..1c690abc99 100644 --- a/README +++ b/README @@ -262,7 +262,7 @@ Options for both config file and command line: --avalon8-voltage-level Set Avalon8 default level of core voltage, range:[0, 15], step: 1 --avalon8-voltage-level-offset Set Avalon8 default offset of core voltage level, range:[-2, 1], step: 1 --avalon8-freq Set Avalon8 default frequency, range:[25, 1200], step: 25, example: 800 ---avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 4], step: 1, example: 3 (default: 3) +--avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 3], step: 1, example: 3 (default: 3) --avalon8-fan Set Avalon8 target fan speed, range:[0, 100], step: 1, example: 0-100 --avalon8-temp Set Avalon8 target temperature, range:[0, 100] (default: 90) --avalon8-polling-delay Set Avalon8 polling delay value (ms) (default: 20) @@ -484,7 +484,7 @@ ASIC only options: --avalon8-voltage-level Set Avalon8 default level of core voltage, range:[0, 15], step: 1 --avalon8-voltage-level-offset Set Avalon8 default offset of core voltage level, range:[-2, 1], step: 1 --avalon8-freq Set Avalon8 default frequency, range:[25, 1200], step: 25, example: 800 ---avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 4], step: 1, example: 3 (default: 3) +--avalon8-freq-sel Set Avalon8 default frequency select, range:[0, 3], step: 1, example: 3 (default: 3) --avalon8-fan Set Avalon8 target fan speed, range:[0, 100], step: 1, example: 0-100 --avalon8-temp Set Avalon8 target temperature, range:[0, 100] (default: 90) --avalon8-polling-delay Set Avalon8 polling delay value (ms) (default: 20) diff --git a/cgminer.c b/cgminer.c index ab222c7fed..54739e4139 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1574,8 +1574,8 @@ static struct opt_table opt_config_table[] = { set_avalon8_freq, NULL, &opt_set_avalon8_freq, "Set Avalon8 default frequency, range:[25, 1200], step: 25, example: 800"), OPT_WITH_ARG("--avalon8-freq-sel", - set_int_0_to_4, opt_show_intval, &opt_avalon8_freq_sel, - "Set Avalon8 default frequency select, range:[0, 4], step: 1, example: 3"), + set_int_0_to_3, opt_show_intval, &opt_avalon8_freq_sel, + "Set Avalon8 default frequency select, range:[0, 3], step: 1, example: 3"), OPT_WITH_CBARG("--avalon8-fan", set_avalon8_fan, NULL, &opt_set_avalon8_fan, "Set Avalon8 target fan speed, range:[0, 100], step: 1, example: 0-100"), From 10c89fdad077ddd1d29ad9f324399799fbd94263 Mon Sep 17 00:00:00 2001 From: vthoang Date: Sat, 6 Apr 2019 20:28:16 +0100 Subject: [PATCH 092/113] Terminus R606 code - first commit --- cgminer.c | 31 +- driver-gekko.c | 1016 +++++++++++++++++++++++++++++++++--------------- driver-gekko.h | 52 ++- miner.h | 7 +- usbutils.c | 12 + usbutils.h | 1 + util.c | 20 +- 7 files changed, 804 insertions(+), 335 deletions(-) diff --git a/cgminer.c b/cgminer.c index bd5ff01bc9..538f3bc9b6 100644 --- a/cgminer.c +++ b/cgminer.c @@ -223,7 +223,7 @@ bool use_curses = true; #else bool use_curses; #endif -static bool opt_widescreen; +bool opt_widescreen; static bool alt_status; static bool switch_status; static bool opt_submit_stale = true; @@ -296,18 +296,22 @@ int opt_bet_clk = 0; #endif #ifdef USE_GEKKO char *opt_gekko_serial = NULL; -bool opt_gekko_boost = 0; +bool opt_gekko_noboost = 0; bool opt_gekko_gsc_detect = 0; bool opt_gekko_gsd_detect = 0; bool opt_gekko_gse_detect = 0; bool opt_gekko_gsh_detect = 0; +bool opt_gekko_gsi_detect = 0; float opt_gekko_gsc_freq = 150; float opt_gekko_gsd_freq = 100; float opt_gekko_gse_freq = 150; +float opt_gekko_tune_up = 92; +float opt_gekko_tune_down = 95; int opt_gekko_gsh_freq = 100; +int opt_gekko_gsi_freq = 100; int opt_gekko_gsh_vcore = 400; int opt_gekko_start_freq = 100; -int opt_gekko_step_freq = 25; +int opt_gekko_step_freq = 6; int opt_gekko_step_delay = 15; #endif #ifdef USE_HASHRATIO @@ -1904,9 +1908,12 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--gekko-newpac-detect", opt_set_bool, &opt_gekko_gsh_detect, "Detect GekkoScience NewPac BM1387"), - OPT_WITHOUT_ARG("--gekko-newpac-boost", - opt_set_bool, &opt_gekko_boost, - "Enable GekkoScience NewPac AsicBoost"), + OPT_WITHOUT_ARG("--gekko-r606-detect", + opt_set_bool, &opt_gekko_gsi_detect, + "Detect GekkoScience Terminus BM1387"), + OPT_WITHOUT_ARG("--gekko-noboost", + opt_set_bool, &opt_gekko_noboost, + "Disable GekkoScience NewPac/R606 AsicBoost"), OPT_WITH_ARG("--gekko-terminus-freq", set_float_0_to_500, opt_show_floatval, &opt_gekko_gse_freq, "Set GekkoScience Terminus BM1384 frequency in MHz, range 6.25-500"), @@ -1916,12 +1923,18 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--gekko-compac-freq", set_float_0_to_500, opt_show_floatval, &opt_gekko_gsc_freq, "Set GekkoScience Compac BM1384 frequency in MHz, range 6.25-500"), + OPT_WITH_ARG("--gekko-tune-down", + set_float_0_to_500, opt_show_floatval, &opt_gekko_tune_down, + "Set GekkoScience miner minimum hash quality, range 0-100"), + OPT_WITH_ARG("--gekko-tune-up", + set_float_0_to_500, opt_show_floatval, &opt_gekko_tune_up, + "Set GekkoScience miner ramping hash threshold, rante 0-99"), OPT_WITH_ARG("--gekko-newpac-freq", set_int_0_to_9999, opt_show_intval, &opt_gekko_gsh_freq, "Set GekkoScience NewPac BM1387 frequency in MHz, range 50-900"), - OPT_WITH_ARG("--gekko-newpac-vcore", - set_int_0_to_9999, opt_show_intval, &opt_gekko_gsh_vcore, - "Set GekkoScience NewPac BM1387 VCORE in mV, range 300-810"), + OPT_WITH_ARG("--gekko-r606-freq", + set_int_0_to_9999, opt_show_intval, &opt_gekko_gsi_freq, + "Set GekkoScience Terminus R606 frequency in MHz, range 50-900"), OPT_WITH_ARG("--gekko-start-freq", set_int_0_to_9999, opt_show_intval, &opt_gekko_start_freq, "Ramp start frequency MHz 25-500"), diff --git a/driver-gekko.c b/driver-gekko.c index b48a253ca2..2a0d640e18 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -4,6 +4,10 @@ #include static bool compac_prepare(struct thr_info *thr); +static uint8_t dev_init_count[0xffff] = {0}; +static uint8_t *init_count; +static uint32_t stat_len; +static uint32_t chip_max; uint32_t bmcrc(unsigned char *ptr, uint32_t len) { @@ -28,21 +32,27 @@ void dumpbuffer(struct cgpu_info *compac, int LOG_LEVEL, char *note, unsigned ch { struct COMPAC_INFO *info = compac->device_data; if (opt_log_output || LOG_LEVEL <= opt_log_level) { - char str[1024]; + char str[2048]; const char * hex = "0123456789ABCDEF"; char * pout = str; int i = 0; - for(; i < 0xFF && i < len - 1; ++i){ + for(; i < 768 && i < len - 1; ++i){ *pout++ = hex[(*ptr>>4)&0xF]; *pout++ = hex[(*ptr++)&0xF]; - *pout++ = ':'; + if (i % 42 == 41) { + *pout = 0; + pout = str; + applog(LOG_LEVEL, "%i: %s %s: %s", compac->cgminer_id, compac->drv->name, note, str); + } else { + *pout++ = ':'; + } } *pout++ = hex[(*ptr>>4)&0xF]; *pout++ = hex[(*ptr)&0xF]; *pout = 0; + applog(LOG_LEVEL, "%d: %s %d - %s: %s", compac->cgminer_id, compac->drv->name, compac->device_id, note, str); - applog(LOG_LEVEL, "%s %i: %s: %s", compac->drv->name, compac->device_id, note, str); } } @@ -91,7 +101,7 @@ static int compac_micro_send(struct cgpu_info *compac, uint8_t cmd, uint8_t chan micro_temp = 32 + 1.8 * temp; if (micro_temp != info->micro_temp) { info->micro_temp = micro_temp; - applog(LOG_WARNING, "%s %d: micro temp changed to %d°C / %.1f°F", compac->drv->name, compac->device_id, temp, info->micro_temp); + applog(LOG_WARNING, "%d: %s %d - micro temp changed to %d°C / %.1f°F", compac->cgminer_id, compac->drv->name, compac->device_id, temp, info->micro_temp); } break; default: @@ -124,6 +134,9 @@ static void compac_send(struct cgpu_info *compac, unsigned char *req_tx, uint32_ info->cmd[bytes - 1] |= bmcrc(req_tx, crc_bits); cgsleep_ms(1); + + int log_level = (bytes < info->task_len) ? LOG_INFO : LOG_INFO; + dumpbuffer(compac, LOG_INFO, "TX", info->cmd, bytes); usb_write(compac, info->cmd, bytes, &read_bytes, C_REQUESTRESULTS); } @@ -133,7 +146,7 @@ static void compac_send_chain_inactive(struct cgpu_info *compac) struct COMPAC_INFO *info = compac->device_data; int i; - applog(LOG_INFO,"%s %d: sending chain inactive for %d chip(s)", compac->drv->name, compac->device_id, info->chips); + applog(LOG_INFO,"%d: %s %d - sending chain inactive for %d chip(s)", compac->cgminer_id, compac->drv->name, compac->device_id, info->chips); if (info->asic_type == BM1387) { unsigned char buffer[5] = {0x55, 0x05, 0x00, 0x00, 0x00}; compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8);; // chain inactive @@ -145,6 +158,16 @@ static void compac_send_chain_inactive(struct cgpu_info *compac) buffer[2] = (0x100 / info->chips) * i; compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8);; } + + cgsleep_ms(10); + unsigned char baudrate[] = { 0x58, 0x09, 0x00, 0x1C, 0x00, 0x20, 0x07, 0x00, 0x19 }; + info->bauddiv = 0x01; // 1.5Mbps baud. + baudrate[6] = info->bauddiv; + compac_send(compac, (char *)baudrate, sizeof(baudrate), 8 * sizeof(baudrate) - 8); + cgsleep_ms(10); + usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, (info->bauddiv + 1), (FTDI_INDEX_BAUD_BTS & 0xff00) | info->interface, C_SETBAUD); + cgsleep_ms(10); + unsigned char gateblk[9] = {0x58, 0x09, 0x00, 0x1C, 0x40, 0x20, 0x99, 0x80, 0x01}; gateblk[6] = 0x80 | info->bauddiv; compac_send(compac, (char *)gateblk, sizeof(gateblk), 8 * sizeof(gateblk) - 8);; // chain inactive @@ -163,13 +186,75 @@ static void compac_send_chain_inactive(struct cgpu_info *compac) } if (info->mining_state != MINER_MINING) { - applog(info->log_startup, "%s %d: open cores @ %.2fMHz", compac->drv->name, compac->device_id, info->frequency); + applog(LOG_INFO, "%d: %s %d - open cores", compac->cgminer_id, compac->drv->name, compac->device_id); info->zero_check = 0; info->task_hcn = 0; info->mining_state = MINER_OPEN_CORE; } } +static void compac_update_rates(struct cgpu_info *compac) +{ + struct COMPAC_INFO *info = compac->device_data; + struct ASIC_INFO *asic; + float average_frequency = 0; + int i; + + for (i = 0; i < info->chips; i++) { + asic = &info->asics[i]; + asic->hashrate = asic->frequency * info->cores * 1000000; + asic->fullscan_ms = 1000.0 * 0xffffffffull / asic->hashrate; + average_frequency += asic->frequency; + } + + average_frequency = average_frequency / info->chips; + if (average_frequency != info->frequency) { + applog(LOG_INFO,"%d: %s %d - frequency updated %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency, average_frequency); + info->frequency = average_frequency; + info->wu_max = 0; + } + + info->hashrate = info->chips * info->frequency * info->cores * 1000000; + info->fullscan_ms = 1000.0 * 0xffffffffull / info->hashrate; + info->scanhash_ms = bound(info->fullscan_ms / 2, 1, 100); + info->ticket_mask = bound(pow(2, ceil(log(info->hashrate / (2.0 * 0xffffffffull)) / log(2))) - 1, 0, 4000); + info->ticket_mask = (info->asic_type == BM1387) ? 0 : info->ticket_mask; + info->difficulty = info->ticket_mask + 1; + info->wu = 0.0139091 * info->cores * info->chips * info->frequency; +} + +static void compac_set_frequency_single(struct cgpu_info *compac, float frequency, int asic_id) +{ + struct COMPAC_INFO *info = compac->device_data; + struct ASIC_INFO *asic = &info->asics[asic_id]; + uint32_t i, r, r1, r2, r3, p1, p2, pll; + + if (info->asic_type == BM1387) { + unsigned char buffer[] = {0x48, 0x09, 0x00, 0x0C, 0x00, 0x50, 0x02, 0x41, 0x00}; //250MHz -- osc of 25MHz + frequency = bound(frequency, 50, 900); + frequency = ceil(100 * (frequency) / 625.0) * 6.25; + + if (frequency < 400) { + buffer[7] = 0x41; + buffer[5] = (frequency * 8) / 25; + } else { + buffer[7] = 0x21; + buffer[5] = (frequency * 4) / 25; + } + buffer[2] = (0x100 / info->chips) * asic_id; + + //asic->frequency = frequency; + applog(LOG_INFO, "%d: %s %d - setting chip[%d] frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, asic_id, asic->frequency, frequency); + compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); + + //unsigned char gateblk[9] = {0x48, 0x09, 0x00, 0x1C, 0x40, 0x20, 0x99, 0x80, 0x01}; + //gateblk[6] = 0x80 | info->bauddiv; + //gateblk[2] = (0x100 / info->chips) * id; + //compac_send(compac, (char *)gateblk, sizeof(gateblk), 8 * sizeof(gateblk) - 8);; // chain inactive + + } +} + static void compac_set_frequency(struct cgpu_info *compac, float frequency) { struct COMPAC_INFO *info = compac->device_data; @@ -183,16 +268,27 @@ static void compac_set_frequency(struct cgpu_info *compac, float frequency) if (frequency < 400) { buffer[7] = 0x41; buffer[5] = (frequency * 8) / 25; - } else if (frequency < 600) { + } else { buffer[7] = 0x21; buffer[5] = (frequency * 4) / 25; + } +/* } else { buffer[7] = 0x11; buffer[5] = (frequency * 2) / 25; } - applog(LOG_WARNING, "%s %d: setting frequency to %.2fMHz", compac->drv->name, compac->device_id, frequency); - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); +*/ + + //applog(LOG_WARNING, "%d: %s %d - setting frequency to %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, frequency); + //compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); + + for (i = 0; i < info->chips; i++) { + compac_set_frequency_single(compac, frequency, i); + } + info->frequency = frequency; + info->last_frequency_ping = (struct timeval){0}; + } else if (info->asic_type == BM1384) { unsigned char buffer[] = {0x82, 0x0b, 0x83, 0x00}; @@ -219,7 +315,7 @@ static void compac_set_frequency(struct cgpu_info *compac, float frequency) buffer[1] = (pll >> 8) & 0xff; buffer[2] = (pll) & 0xff; - applog(LOG_WARNING, "%s %d: setting frequency to %.2fMHz", compac->drv->name, compac->device_id, frequency); + applog(LOG_INFO, "%d: %s %d - setting frequency to %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, frequency); compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); buffer[0] = 0x84; buffer[1] = 0x00; @@ -228,14 +324,64 @@ static void compac_set_frequency(struct cgpu_info *compac, float frequency) buffer[2] = 0x04; compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); } + compac_update_rates(compac); +} - info->hashrate = info->chips * info->frequency * info->cores * 1000000; - info->fullscan_ms = 1000.0 * 0xffffffffull / info->hashrate; - info->scanhash_ms = bound(info->fullscan_ms / 2, 1, 100); - info->ticket_mask = bound(pow(2, ceil(log(info->hashrate / (2.0 * 0xffffffffull)) / log(2))) - 1, 0, 4000); - info->ticket_mask = (info->asic_type == BM1387) ? 0 : info->ticket_mask; - info->difficulty = info->ticket_mask + 1; +static void compac_update_work(struct cgpu_info *compac) +{ + struct COMPAC_INFO *info = compac->device_data; + int i; + + for (i = 0; i < JOB_MAX; i++) { + info->active_work[i] = false; + } + info->update_work = 1; +} + +static void compac_flush_buffer(struct cgpu_info *compac) +{ + int read_bytes = 1; + unsigned char resp[32]; + + while (read_bytes) { + usb_read_timeout(compac, (char *)resp, 32, &read_bytes, 1, C_REQUESTRESULTS); + } +} + +static void compac_flush_work(struct cgpu_info *compac) +{ + compac_flush_buffer(compac); + compac_update_work(compac); +} + +static void compac_toggle_reset(struct cgpu_info *compac) +{ + struct COMPAC_INFO *info = compac->device_data; + unsigned short usb_val; + + applog(LOG_WARNING,"%d: %s %d - Toggling ASIC nRST to reset", compac->cgminer_id, compac->drv->name, compac->device_id); + + usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET, info->interface, C_RESET); + usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, FTDI_VALUE_DATA_BTS, info->interface, C_SETDATA); + usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_BTS, (FTDI_INDEX_BAUD_BTS & 0xff00) | info->interface, C_SETBAUD); + usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW, FTDI_VALUE_FLOW, info->interface, C_SETFLOW); + + usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_PURGE_TX, info->interface, C_PURGETX); + usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_PURGE_RX, info->interface, C_PURGERX); + + usb_val = (FTDI_BITMODE_CBUS << 8) | 0xF2; // low byte: bitmask - 1111 0010 - CB1(HI) + usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_BITMODE, usb_val, info->interface, C_SETMODEM); + cgsleep_ms(30); + + usb_val = (FTDI_BITMODE_CBUS << 8) | 0xF0; // low byte: bitmask - 1111 0000 - CB1(LO) + usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_BITMODE, usb_val, info->interface, C_SETMODEM); + cgsleep_ms(30); + + usb_val = (FTDI_BITMODE_CBUS << 8) | 0xF2; // low byte: bitmask - 1111 0010 - CB1(HI) + usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_BITMODE, usb_val, info->interface, C_SETMODEM); + cgsleep_ms(200); + cgtime(&info->last_reset); } static uint64_t compac_check_nonce(struct cgpu_info *compac) @@ -270,7 +416,7 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) info->nonces++; info->nonceless = 0; if (nonce == info->prev_nonce) { - applog(LOG_INFO, "%s %d: Duplicate Nonce : %08x @ %02x [%02x %02x %02x %02x %02x %02x %02x]", compac->drv->name, compac->device_id, nonce, job_id, + applog(LOG_INFO, "%d: %s %d - Duplicate Nonce : %08x @ %02x [%02x %02x %02x %02x %02x %02x %02x]", compac->cgminer_id, compac->drv->name, compac->device_id, nonce, job_id, info->rx[0], info->rx[1], info->rx[2], info->rx[3], info->rx[4], info->rx[5], info->rx[6]); info->dups++; if (info->dups == 1) { @@ -284,12 +430,12 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) hashes = info->difficulty * 0xffffffffull; info->prev_nonce = nonce; - applog(LOG_INFO, "%s %d: Device reported nonce: %08x @ %02x", compac->drv->name, compac->device_id, nonce, job_id); + applog(LOG_INFO, "%d: %s %d - Device reported nonce: %08x @ %02x", compac->cgminer_id, compac->drv->name, compac->device_id, nonce, job_id); struct work *work = info->work[job_id]; bool active_work = info->active_work[job_id]; - - if (info->vmask) { + int midnum = 0; + if (!opt_gekko_noboost && info->vmask) { // force check last few nonces by [job_id - 1] if (info->asic_type == BM1387) { for (i = 0; i <= 3; i++) { @@ -301,7 +447,10 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) work->micro_job_id = pow(2, i); memcpy(work->data, &(work->pool->vmask_001[work->micro_job_id]), 4); if (test_nonce(work, nonce)) { - applog(LOG_INFO, "%s %d: AsicBoost nonce found : midstate%d", compac->drv->name, compac->device_id, i); + midnum = i; + if (i > 0) { + info->boosted = true; + } break; } } @@ -315,78 +464,30 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) return hashes; } - work->device_diff = info->difficulty; + //work->device_diff = info->difficulty; if (submit_nonce(info->thr, work, nonce)) { + int asic_id = floor(info->rx[0] / (0x100 / info->chips)); + struct ASIC_INFO *asic = &info->asics[asic_id]; + cgtime(&asic->last_nonce); cgtime(&info->last_nonce); + + if (midnum > 0) { + applog(LOG_INFO, "%d: %s %d - AsicBoost nonce found : midstate%d", compac->cgminer_id, compac->drv->name, compac->device_id, midnum); + } + info->accepted++; info->failing = false; } else { if (hwe != compac->hw_errors) { cgtime(&info->last_hwerror); + compac_flush_buffer(compac); } } return hashes; } -static void compac_update_work(struct cgpu_info *compac) -{ - struct COMPAC_INFO *info = compac->device_data; - int i; - - for (i = 0; i < JOB_MAX; i++) { - info->active_work[i] = false; - } - info->update_work = 1; -} - -static void compac_flush_buffer(struct cgpu_info *compac) -{ - int read_bytes = 1; - unsigned char resp[32]; - - while (read_bytes) { - usb_read_timeout(compac, (char *)resp, 32, &read_bytes, 1, C_REQUESTRESULTS); - } -} - -static void compac_flush_work(struct cgpu_info *compac) -{ - compac_flush_buffer(compac); - compac_update_work(compac); -} - -static void compac_toggle_reset(struct cgpu_info *compac) -{ - struct COMPAC_INFO *info = compac->device_data; - unsigned short usb_val; - - applog(LOG_WARNING,"%s %d: Toggling ASIC nRST to reset", compac->drv->name, compac->device_id); - - usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET, info->interface, C_RESET); - usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, FTDI_VALUE_DATA_BTS, info->interface, C_SETDATA); - usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_BTS, (FTDI_INDEX_BAUD_BTS & 0xff00) | info->interface, C_SETBAUD); - usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW, FTDI_VALUE_FLOW, info->interface, C_SETFLOW); - - usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_PURGE_TX, info->interface, C_PURGETX); - usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_PURGE_RX, info->interface, C_PURGERX); - - usb_val = (FTDI_BITMODE_CBUS << 8) | 0xF2; // low byte: bitmask - 1111 0010 - CB1(HI) - usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_BITMODE, usb_val, info->interface, C_SETMODEM); - cgsleep_ms(30); - - usb_val = (FTDI_BITMODE_CBUS << 8) | 0xF0; // low byte: bitmask - 1111 0000 - CB1(LO) - usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_BITMODE, usb_val, info->interface, C_SETMODEM); - cgsleep_ms(30); - - usb_val = (FTDI_BITMODE_CBUS << 8) | 0xF2; // low byte: bitmask - 1111 0010 - CB1(HI) - usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_BITMODE, usb_val, info->interface, C_SETMODEM); - cgsleep_ms(30); - - cgtime(&info->last_reset); -} - static void busy_work(struct COMPAC_INFO *info) { memset(info->task, 0, info->task_len); @@ -395,7 +496,7 @@ static void busy_work(struct COMPAC_INFO *info) info->task[0] = 0x21; info->task[1] = info->task_len; info->task[2] = info->job_id & 0xff; - info->task[3] = ((opt_gekko_boost) ? 0x04 : 0x01); + info->task[3] = ((!opt_gekko_noboost && info->vmask) ? 0x04 : 0x01); memset(info->task + 8, 0xff, 12); unsigned short crc = crc16_false(info->task, info->task_len - 2); @@ -420,12 +521,12 @@ static void init_task(struct COMPAC_INFO *info) info->task[0] = 0x21; info->task[1] = info->task_len; info->task[2] = info->job_id & 0xff; - info->task[3] = ((opt_gekko_boost) ? 0x04 : 0x01); + info->task[3] = ((!opt_gekko_noboost && info->vmask) ? 0x04 : 0x01); if (info->mining_state == MINER_MINING) { stuff_reverse(info->task + 8, work->data + 64, 12); stuff_reverse(info->task + 20, work->midstate, 32); - if (opt_gekko_boost) { + if (!opt_gekko_noboost && info->vmask) { stuff_reverse(info->task + 20 + 32, work->midstate1, 32); stuff_reverse(info->task + 20 + 32 + 32, work->midstate2, 32); stuff_reverse(info->task + 20 + 32 + 32 + 32, work->midstate3, 32); @@ -455,12 +556,16 @@ static void *compac_mine(void *object) struct work *old_work = NULL; struct timeval now; + struct timeval last_frequency_report; struct sched_param param; - int i, read_bytes, sleep_ms, policy, ret_nice; + int i, read_bytes, sleep_ms, policy, ret_nice, ping_itr; uint32_t err = 0; uint64_t hashes = 0; uint64_t max_task_wait = 0; - float wait_factor = ((opt_gekko_boost && info->asic_type == BM1387) ? 1.8 : 0.6); + char str_frequency[1024]; + float wait_factor = ((!opt_gekko_noboost && info->vmask && info->asic_type == BM1387) ? 2.25 : 0.75); + + bool adjustable = 0; #ifndef WIN32 ret_nice = nice(-15); @@ -470,7 +575,7 @@ static void *compac_mine(void *object) pthread_setschedparam(pthread_self(), policy, ¶m); ret_nice = param.sched_priority; #endif /* WIN32 */ - applog(LOG_INFO, "%s %d: work thread niceness (%d)", compac->drv->name, compac->device_id, ret_nice); + applog(LOG_INFO, "%d: %s %d - work thread niceness (%d)", compac->cgminer_id, compac->drv->name, compac->device_id, ret_nice); max_task_wait = bound(wait_factor * info->fullscan_ms, 1, 3 * info->fullscan_ms); sleep_ms = bound(ceil(max_task_wait/8.0), 1, 200); @@ -478,76 +583,148 @@ static void *compac_mine(void *object) while (info->mining_state != MINER_SHUTDOWN) { cgtime(&now); - if (compac->deven == DEV_DISABLED || compac->usbinfo.nodev || info->mining_state != MINER_MINING) { + if (info->chips == 0 || compac->deven == DEV_DISABLED || compac->usbinfo.nodev || info->mining_state != MINER_MINING) { cgsleep_ms(10); } else if (info->update_work || (ms_tdiff(&now, &info->last_task) > max_task_wait)) { + uint64_t hashrate_15, hashrate_5m, hashrate_1m, hashrate_li, hashrate_tm; + double dev_runtime, wu; + bool low_eff = 0; info->update_work = 0; - + max_task_wait = bound(wait_factor * info->fullscan_ms, 1, 3 * info->fullscan_ms); - sleep_ms = bound(ceil(max_task_wait/15.0), 1, 200); - - if (info->asic_type == BM1387 && ms_tdiff(&now, &info->monitor_time) > 30000) { - int max_nononce = 3000.0 * (200.0 / info->frequency_requested); - if (ms_tdiff(&now, &info->last_nonce) > max_nononce) { - applog(LOG_WARNING,"%s %d: missing nonces", compac->drv->name, compac->device_id); - info->mining_state = MINER_RESET; - continue; - } + sleep_ms = bound(ceil(max_task_wait/100.0), 1, 200); + + dev_runtime = cgpu_runtime(compac); + wu = compac->diff1 / dev_runtime * 60; + + if (wu > info->wu_max) { + info->wu_max = wu; + cgtime(&info->last_wu_increase); } - if (ms_tdiff(&now, &info->last_frequency_ping) > 5000) { - if (info->asic_type == BM1387) { - unsigned char buffer[] = {0x54, 0x05, 0x00, 0x0C, 0x00}; // PLL_PARAMETER - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); - } else if (info->asic_type == BM1384) { - unsigned char buffer[] = {0x84, 0x00, 0x04, 0x00}; - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); - } - cgtime(&info->last_frequency_ping); - - if (info->asic_type == BM1384 || info->asic_type == BM1387) { - uint64_t hashrate_5m, hashrate_1m; - hashrate_1m = (double)compac->rolling1 * 1000000ull; - hashrate_5m = (double)compac->rolling5 * 1000000ull; - if ((hashrate_1m < (info->healthy * info->hashrate)) && ms_tdiff(&now, &info->monitor_time) > (3 * 60 * 1000)) { - applog(LOG_WARNING, "%" PRIu64 " : %" PRIu64 " : %" PRIu64, hashrate_1m, hashrate_5m, info->hashrate); - applog(LOG_WARNING,"%s %d: unhealthy miner", compac->drv->name, compac->device_id); - info->mining_state = MINER_RESET; - continue; - } - - if (ms_tdiff(&now, &info->last_frequency_report) > (30 + 7500 * 3)) { - applog(LOG_WARNING,"%s %d: asic(s) went offline", compac->drv->name, compac->device_id); + hashrate_li = (double)compac->rolling * 1000000ull; + hashrate_1m = (double)compac->rolling1 * 1000000ull; + hashrate_5m = (double)compac->rolling5 * 1000000ull; + hashrate_15 = (double)compac->rolling15 * 1000000ull; + hashrate_tm = (double)compac->total_mhashes / dev_runtime * 1000000ull;; + + info->eff_li = 100.0 * (1.0 * hashrate_li / info->hashrate); + info->eff_1m = 100.0 * (1.0 * hashrate_1m / info->hashrate); + info->eff_5m = 100.0 * (1.0 * hashrate_5m / info->hashrate); + info->eff_15 = 100.0 * (1.0 * hashrate_15 / info->hashrate); + info->eff_wu = 100.0 * (1.0 * wu / info->wu); + info->eff_tm = 100.0 * (1.0 * hashrate_tm / info->hashrate); + + info->eff_li = (info->eff_li > 100) ? 100 : info->eff_li; + info->eff_1m = (info->eff_1m > 100) ? 100 : info->eff_1m; + info->eff_5m = (info->eff_5m > 100) ? 100 : info->eff_5m; + info->eff_15 = (info->eff_15 > 100) ? 100 : info->eff_15; + info->eff_wu = (info->eff_wu > 100) ? 100 : info->eff_wu; + info->eff_tm = (info->eff_tm > 100) ? 100 : info->eff_tm; + + info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; + + if (abs(info->eff_1m - info->eff_5m) < 2.5 && info->eff_5m > 10.0 && info->eff_15 < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_1m < opt_gekko_tune_down) { + low_eff = 1; + } + + if (ms_tdiff(&now, &info->monitor_time) > MS_SECOND_5 && ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_5) { + for (i = 0; i < info->chips; i++) { + struct ASIC_INFO *asic = &info->asics[i]; + if (ms_tdiff(&now, &asic->last_nonce) > asic->fullscan_ms * 20 * info->difficulty) { + float new_frequency; + if (info->frequency_requested > asic->frequency) { + new_frequency = asic->frequency; + } else { + new_frequency = asic->frequency - 6.25; + } + asic->last_state = asic->state; + asic->state = ASIC_HALFDEAD; + cgtime(&asic->state_change_time); + cgtime(&info->monitor_time); + applog(LOG_WARNING,"%d: %s %d - missing nonces from chip[%d]", compac->cgminer_id, compac->drv->name, compac->device_id, i); + if (ms_tdiff(&now, &info->last_frequency_adjust) < MS_MINUTE_10) { + applog(LOG_WARNING,"%d: %s %d - target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); + info->frequency_requested = new_frequency; + cgtime(&info->last_frequency_adjust); + } info->mining_state = MINER_RESET; continue; } } } - - if (info->accepted > 10 && ms_tdiff(&now, &info->last_frequency_ping) > 100 && - ms_tdiff(&info->last_nonce, &info->last_frequency_adjust) > 0 && - ms_tdiff(&now, &info->last_frequency_adjust) >= bound(opt_gekko_step_delay, 1, 600) * 1000) { - if (info->frequency != info->frequency_requested) { - float new_frequency; - if (info->frequency < info->frequency_requested) { - new_frequency = info->frequency + opt_gekko_step_freq; - if (new_frequency > info->frequency_requested) { - new_frequency = info->frequency_requested; + + if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10 && ms_tdiff(&now, &info->last_pool_lost) > MS_MINUTE_10) { + float new_frequency = info->frequency - 6.25; + applog(LOG_WARNING,"%d: %s %d - low eff: (1m)%.1f (5m)%.1f (15m)%.1f - [%.1f]", compac->cgminer_id, compac->drv->name, compac->device_id, info->eff_1m, info->eff_5m, info->eff_15, opt_gekko_tune_down); + applog(LOG_WARNING,"%d: %s %d - low eff: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); + info->frequency_requested = new_frequency; + for (i = 0; i < info->chips; i++) + { + struct ASIC_INFO *asic = &info->asics[i]; + asic->frequency_requested = new_frequency; + } + cgtime(&info->last_frequency_adjust); + cgtime(&info->monitor_time); + } + + if (ms_tdiff(&now, &info->last_frequency_ping) > MS_SECOND_5 || (info->frequency_of != info->chips && ms_tdiff(&now, &info->last_frequency_ping) > 50)) { + + info->frequency_of--; + + if (info->frequency_of == (info->chips - 1) && info->eff_gs >= opt_gekko_tune_up) + adjustable = 1; + + if (info->frequency_of < 0) { + info->frequency_of = info->chips; + ping_itr = (ping_itr + 1) % 2; + adjustable = 0; + } else { + struct ASIC_INFO *asic = &info->asics[info->frequency_of]; + if (ping_itr == 1 && asic->frequency != asic->frequency_requested) { + float new_frequency; + if (asic->frequency < asic->frequency_requested) { + new_frequency = asic->frequency + opt_gekko_step_freq; + if (new_frequency > asic->frequency_requested) { + new_frequency = asic->frequency_requested; + } + if (new_frequency < info->frequency_start) { + new_frequency = info->frequency_start; + } + if (!adjustable) { + new_frequency = asic->frequency; + if (info->frequency_of == info->chips) + applog(LOG_INFO,"%d: %s %d - pending frequency change - waiting for hashrate to catch up", compac->cgminer_id, compac->drv->name, compac->device_id); + } + } else { + new_frequency = asic->frequency_requested; } - } else { - new_frequency = info->frequency - opt_gekko_step_freq; - if (new_frequency < info->frequency_requested) { - new_frequency = info->frequency_requested; + if (asic->frequency != new_frequency) { + cgtime(&info->monitor_time); + if (info->asic_type == BM1387) { + compac_set_frequency_single(compac, new_frequency, info->frequency_of); + } else if (info->asic_type == BM1384) { + if (info->frequency_of == 0) { + compac_set_frequency(compac, new_frequency); + compac_send_chain_inactive(compac); + } + } } } - compac_set_frequency(compac, new_frequency); - compac_send_chain_inactive(compac); - info->update_work = 1; - info->accepted = 0; - } - cgtime(&info->last_frequency_adjust); + if (info->asic_type == BM1387) { + unsigned char buffer[] = {0x44, 0x05, 0x00, 0x0C, 0x00}; // PLL_PARAMETER + buffer[2] = (0x100 / info->chips) * info->frequency_of; + compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); + cgtime(&info->last_frequency_ping); + } else if (info->asic_type == BM1384) { + unsigned char buffer[] = {0x04, 0x00, 0x04, 0x00}; + buffer[1] = (0x100 / info->chips) * info->frequency_of; + compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); + cgtime(&info->last_frequency_ping); + } + } } work = get_queued(compac); @@ -558,25 +735,39 @@ static void *compac_mine(void *object) info->work[info->job_id] = work; info->active_work[info->job_id] = 1; info->vmask = work->pool->vmask; + if (info->asic_type == BM1387) { + if (!opt_gekko_noboost && info->vmask) { + info->task_len = 150; + } else { + info->task_len = 54; + } + } init_task(info); } else { + struct pool *cp; + cp = current_pool(); busy_work(info); + info->busy_work++; + if (!cp->stratum_active) + cgtime(&info->last_pool_lost); cgtime(&info->monitor_time); } err = usb_write(compac, (char *)info->task, info->task_len, &read_bytes, C_SENDWORK); + //dumpbuffer(compac, LOG_WARNING, "TASK.TX", info->task, info->task_len); if (err != LIBUSB_SUCCESS) { - applog(LOG_WARNING,"%s %d: usb failure (%d)", compac->drv->name, compac->device_id, err); + applog(LOG_WARNING,"%d: %s %d - usb failure (%d)", compac->cgminer_id, compac->drv->name, compac->device_id, err); info->mining_state = MINER_RESET; continue; } if (read_bytes != info->task_len) { if (ms_tdiff(&now, &info->last_write_error) > (5 * 1000)) { - applog(LOG_WARNING,"%s %d: usb write error [%d:%d]", compac->drv->name, compac->device_id, read_bytes, info->task_len); + applog(LOG_WARNING,"%d: %s %d - usb write error [%d:%d]", compac->cgminer_id, compac->drv->name, compac->device_id, read_bytes, info->task_len); cgtime(&info->last_write_error); } } - thread_yield(); + + sched_yield(); if (old_work) { mutex_lock(&info->lock); work_completed(compac, old_work); @@ -591,87 +782,195 @@ static void *compac_mine(void *object) } } -static void *compac_listen(void *object) +static void *compac_handle_rx(void *object, int read_bytes) { struct cgpu_info *compac = (struct cgpu_info *)object; struct COMPAC_INFO *info = compac->device_data; - int read_bytes, crc_ok, cmd_resp; - uint32_t err = 0; + struct ASIC_INFO *asic; + int crc_ok, cmd_resp, i; struct timeval now; - while (info->mining_state != MINER_SHUTDOWN) { - memset(info->rx, 0, info->rx_len); - thread_yield(); - err = usb_read_timeout(compac, (char *)info->rx, info->rx_len, &read_bytes, 200, C_GETRESULTS); - cgtime(&now); + cgtime(&now); - if (read_bytes > 0) { - cmd_resp = (info->rx[read_bytes - 1] <= 0x1F && bmcrc(info->rx, 8 * read_bytes - 5) == info->rx[read_bytes - 1]) ? 1 : 0; - dumpbuffer(compac, LOG_INFO, "RX", info->rx, read_bytes); + cmd_resp = (info->rx[read_bytes - 1] <= 0x1F && bmcrc(info->rx, 8 * read_bytes - 5) == info->rx[read_bytes - 1]) ? 1 : 0; - if (cmd_resp && info->rx[0] == 0x80) { - float frequency; - cgtime(&info->last_frequency_report); + int log_level = (cmd_resp) ? LOG_INFO : LOG_INFO; + dumpbuffer(compac, log_level, "RX", info->rx, read_bytes); - if (info->asic_type == BM1387 && (info->rx[2] == 0 || (info->rx[3] >> 4) == 0 || (info->rx[3] & 0x0f) == 0)) { - dumpbuffer(compac, LOG_WARNING, "RX", info->rx, read_bytes); - applog(LOG_WARNING,"%s %d: bad frequency", compac->drv->name, compac->device_id); - } else { - if (info->asic_type == BM1387) { - frequency = 25.0 * info->rx[1] / (info->rx[2] * (info->rx[3] >> 4) * (info->rx[3] & 0x0f)); - } else if (info->asic_type == BM1384) { - frequency = (info->rx[1] + 1) * 6.25 / (1 + info->rx[2] & 0x0f) * pow(2, (3 - info->rx[3])) + ((info->rx[2] >> 4) * 6.25); - } + if (cmd_resp && info->rx[0] == 0x80) { + float frequency; + cgtime(&info->last_frequency_report); - if (frequency != info->frequency) { - applog(LOG_WARNING,"%s %d: frequency changed %.2fMHz -> %.2fMHz", compac->drv->name, compac->device_id, info->frequency, frequency); + if (info->asic_type == BM1387 && (info->rx[2] == 0 || (info->rx[3] >> 4) == 0 || (info->rx[3] & 0x0f) == 0)) { + dumpbuffer(compac, LOG_WARNING, "RX", info->rx, read_bytes); + applog(LOG_WARNING,"%d: %s %d - bad frequency", compac->cgminer_id, compac->drv->name, compac->device_id); + } else { + if (info->asic_type == BM1387) { + frequency = 25.0 * info->rx[1] / (info->rx[2] * (info->rx[3] >> 4) * (info->rx[3] & 0x0f)); + } else if (info->asic_type == BM1384) { + frequency = (info->rx[1] + 1) * 6.25 / (1 + info->rx[2] & 0x0f) * pow(2, (3 - info->rx[3])) + ((info->rx[2] >> 4) * 6.25); + } + + if (info->frequency_of != info->chips) { + asic = &info->asics[info->frequency_of]; + if (frequency != asic->frequency) { + if (frequency < asic->frequency && frequency != asic->frequency_requested) { + applog(LOG_INFO,"%d: %s %d - chip[%d] reported frequency at %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_of, frequency); } else { - applog(LOG_INFO,"%s %d: chip reported frequency of %.2fMHz", compac->drv->name, compac->device_id, frequency); + applog(LOG_INFO,"%d: %s %d - chip[%d] reported new frequency of %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_of, frequency); } + asic->frequency = frequency; + info->report = 1; + } else { + applog(LOG_INFO,"%d: %s %d - chip[%d] reported frequency of %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_of, frequency); + } + } else { + applog(LOG_INFO,"%d: %s %d - [-1] reported frequency of %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, frequency); + if (frequency != info->frequency) { info->frequency = frequency; - info->hashrate = info->chips * info->frequency * info->cores * 1000000; - info->fullscan_ms = 1000.0 * 0xffffffffull / info->hashrate; - info->scanhash_ms = bound(info->fullscan_ms / 2, 1, 100); - info->ticket_mask = bound(pow(2, ceil(log(info->hashrate / (2.0 * 0xffffffffull)) / log(2))) - 1, 0, 4000); - info->ticket_mask = (info->asic_type == BM1387) ? 0 : info->ticket_mask; - info->difficulty = info->ticket_mask + 1; - } + } + + compac_update_rates(compac); + } + } + switch (info->mining_state) { + case MINER_CHIP_COUNT: + case MINER_CHIP_COUNT_XX: + if (cmd_resp && info->rx[0] == 0x13) { + struct ASIC_INFO *asic = &info->asics[info->chips]; + asic->frequency = info->frequency_default; + asic->frequency_requested = info->frequency_requested; + cgtime(&asic->last_nonce); + info->chips++; + info->mining_state = MINER_CHIP_COUNT_XX; + compac_update_rates(compac); + } + break; + case MINER_OPEN_CORE: + if ((info->rx[0] == 0x72 && info->rx[1] == 0x03 && info->rx[2] == 0xEA && info->rx[3] == 0x83) || + (info->rx[0] == 0xE1 && info->rx[0] == 0x6B && info->rx[0] == 0xF8 && info->rx[0] == 0x09)) { + //open core nonces = healthy chips. + info->zero_check++; } + break; + case MINER_MINING: + if (!cmd_resp) { + sched_yield(); + mutex_lock(&info->lock); + info->hashes += compac_check_nonce(compac); + mutex_unlock(&info->lock); + } + break; + default: + break; + } +} - switch (info->mining_state) { - case MINER_CHIP_COUNT: - case MINER_CHIP_COUNT_XX: - if (cmd_resp && info->rx[0] == 0x13) { - info->chips++; - info->mining_state = MINER_CHIP_COUNT_XX; - } - break; - case MINER_OPEN_CORE: - if ((info->rx[0] == 0x72 && info->rx[1] == 0x03 && info->rx[2] == 0xEA && info->rx[3] == 0x83) || - (info->rx[0] == 0xE1 && info->rx[0] == 0x6B && info->rx[0] == 0xF8 && info->rx[0] == 0x09)) { - //open core nonces = healthy chips. - info->zero_check++; +static void *compac_listen(void *object) +{ + struct cgpu_info *compac = (struct cgpu_info *)object; + struct COMPAC_INFO *info = compac->device_data; + struct timeval now; + unsigned char rx[BUFFER_MAX]; + unsigned char *prx = rx; + int read_bytes, cmd_resp, i, pos, rx_bytes; + uint32_t err = 0; + + memset(rx, 0, BUFFER_MAX); + memset(info->rx, 0, BUFFER_MAX); + + pos = 0; + rx_bytes = 0; + + while (info->mining_state != MINER_SHUTDOWN) { + + cgtime(&now); + + if (info->mining_state == MINER_CHIP_COUNT) { + if (info->asic_type == BM1387) { + unsigned char buffer[] = {0x54, 0x05, 0x00, 0x00, 0x00}; + compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); + } else if (info->asic_type == BM1384) { + unsigned char buffer[] = {0x84, 0x00, 0x00, 0x00}; + compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); + } + err = usb_read_timeout(compac, rx, BUFFER_MAX, &read_bytes, 1000, C_GETRESULTS); + dumpbuffer(compac, LOG_INFO, "CMD.RX", rx, read_bytes); + + rx_bytes = read_bytes; + info->mining_state = MINER_CHIP_COUNT_XX; + } else { + err = usb_read_timeout(compac, &rx[pos], info->rx_len, &read_bytes, 20, C_GETRESULTS); + rx_bytes += read_bytes; + } + + if (read_bytes > 0) { + + if (rx_bytes < info->rx_len) { + applog(LOG_INFO, "%d: %s %d - Buffered %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, rx_bytes); + dumpbuffer(compac, LOG_INFO, "Partial-RX", rx, rx_bytes); + pos = rx_bytes; + continue; + } + + if (rx_bytes >= info->rx_len) + cmd_resp = (rx[read_bytes - 1] <= 0x1F && bmcrc(prx, 8 * read_bytes - 5) == rx[read_bytes - 1]) ? 1 : 0; + + if (info->mining_state == MINER_CHIP_COUNT_XX || cmd_resp) { + if (rx_bytes % info->rx_len == 2) { + // fix up trial 1 + int shift = 0; + int extra = 0; + for (i = 0; i < (rx_bytes - shift); i++) { + if (rx[i] == 0x01) { + shift = 2; + extra = rx[i + 1]; + } + rx[i] = rx[i + shift]; } - break; - case MINER_MINING: - if (!cmd_resp) { - thread_yield(); - mutex_lock(&info->lock); - info->hashes += compac_check_nonce(compac); - mutex_unlock(&info->lock); + rx_bytes -= shift; + applog(LOG_INFO, "%d: %s %d - Extra Data - 0x01 0x%02x", compac->cgminer_id, compac->drv->name, compac->device_id, extra & 0xff); + } + } + + if (rx_bytes % info->rx_len != 0) { + int n_read_bytes; + pos = rx_bytes; + err = usb_read_timeout(compac, &rx[pos], BUFFER_MAX - pos, &n_read_bytes, 1, C_GETRESULTS); + rx_bytes += n_read_bytes; + + if (rx_bytes % info->rx_len != 0 && rx_bytes >= info->rx_len) { + int extra_bytes = rx_bytes % info->rx_len; + for (i = extra_bytes; i < rx_bytes; i++) { + rx[i - extra_bytes] = rx[i]; } - break; - default: - break; + rx_bytes -= extra_bytes; + applog(LOG_INFO, "%d: %s %d - Fixing buffer alignment, dumping initial %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, extra_bytes); + } + } + + if (rx_bytes % info->rx_len == 0) { + for (i = 0; i < rx_bytes; i += info->rx_len) { + memcpy(info->rx, &rx[i], info->rx_len); + compac_handle_rx(compac, info->rx_len); + } + pos = 0; + rx_bytes = 0; } } else { + if (rx_bytes > 0) + applog(LOG_INFO, "%d: %s %d - Second read, no data dumping (c) %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, rx_bytes); + + pos = 0; + rx_bytes = 0; + // RX line is idle, let's squeeze in a command to the micro if needed. if (info->asic_type == BM1387) { - if (ms_tdiff(&now, &info->last_micro_ping) > 5000 && ms_tdiff(&now, &info->last_task) > 1 && ms_tdiff(&now, &info->last_task) < 3) { + if (ms_tdiff(&now, &info->last_micro_ping) > MS_SECOND_5 && ms_tdiff(&now, &info->last_task) > 1 && ms_tdiff(&now, &info->last_task) < 3) { compac_micro_send(compac, M1_GET_TEMP, 0x00, 0x00); cgtime(&info->last_micro_ping); } @@ -679,14 +978,21 @@ static void *compac_listen(void *object) switch (info->mining_state) { case MINER_CHIP_COUNT_XX: - applog(info->log_startup, "%s %d: found %d chip(s)", compac->drv->name, compac->device_id, info->chips); - info->mining_state = MINER_CHIP_COUNT_OK; + if (info->chips < info->expected_chips) { + applog(LOG_WARNING, "%d: %s %d - found %d/%d chip(s)", compac->cgminer_id, compac->drv->name, compac->device_id, info->chips, info->expected_chips); + info->mining_state = MINER_RESET; + } else { + applog(LOG_WARNING, "%d: %s %d - found %d chip(s)", compac->cgminer_id, compac->drv->name, compac->device_id, info->chips); + info->mining_state = MINER_CHIP_COUNT_OK; + (*init_count) = 0; + } break; default: break; } } } + } static bool compac_init(struct thr_info *thr) @@ -694,11 +1000,15 @@ static bool compac_init(struct thr_info *thr) int i; struct cgpu_info *compac = thr->cgpu; struct COMPAC_INFO *info = compac->device_data; - + + info->boosted = false; info->prev_nonce = 0; info->fail_count = 0; + info->busy_work = 0; + info->frequency_default = 200; + info->frequency = 200; + info->frequency_of = info->chips; info->scanhash_ms = 10; - info->log_startup = LOG_WARNING; memset(info->rx, 0, BUFFER_MAX); memset(info->tx, 0, BUFFER_MAX); @@ -713,7 +1023,7 @@ static bool compac_init(struct thr_info *thr) cgtime(&info->last_write_error); cgtime(&info->last_frequency_adjust); - cgtime(&info->last_frequency_ping); + info->last_frequency_ping = (struct timeval){0}; cgtime(&info->last_micro_ping); cgtime(&info->last_scanhash); cgtime(&info->last_reset); @@ -739,7 +1049,11 @@ static bool compac_init(struct thr_info *thr) break; case IDENT_GSH: info->frequency_requested = opt_gekko_gsh_freq; - info->frequency_start = opt_gekko_gsh_freq; + info->frequency_start = opt_gekko_start_freq; + break; + case IDENT_GSI: + info->frequency_requested = opt_gekko_gsi_freq; + info->frequency_start = opt_gekko_start_freq; break; default: info->frequency_requested = 200; @@ -755,22 +1069,25 @@ static bool compac_init(struct thr_info *thr) if (!info->rthr.pth) { pthread_mutex_init(&info->lock, NULL); pthread_mutex_init(&info->wlock, NULL); + pthread_mutex_init(&info->rlock, NULL); if (thr_info_create(&(info->rthr), NULL, compac_listen, (void *)compac)) { - applog(LOG_ERR, "%s %i: read thread create failed", compac->drv->name, compac->device_id); + applog(LOG_ERR, "%d: %s %d - read thread create failed", compac->cgminer_id, compac->drv->name, compac->device_id); return false; } else { - applog(LOG_INFO, "%s %i: read thread created", compac->drv->name, compac->device_id); + applog(LOG_INFO, "%d: %s %d - read thread created", compac->cgminer_id, compac->drv->name, compac->device_id); } + pthread_detach(info->rthr.pth); + + cgsleep_ms(100); if (thr_info_create(&(info->wthr), NULL, compac_mine, (void *)compac)) { - applog(LOG_ERR, "%s %i: write thread create failed", compac->drv->name, compac->device_id); + applog(LOG_ERR, "%d: %s %d - write thread create failed", compac->cgminer_id, compac->drv->name, compac->device_id); return false; } else { - applog(LOG_INFO, "%s %i: write thread created", compac->drv->name, compac->device_id); + applog(LOG_INFO, "%d: %s %d - write thread created", compac->cgminer_id, compac->drv->name, compac->device_id); } - pthread_detach(info->rthr.pth); pthread_detach(info->wthr.pth); } @@ -786,38 +1103,39 @@ static int64_t compac_scanwork(struct thr_info *thr) int read_bytes; uint32_t err = 0; uint64_t hashes = 0; + + if (info->chips == 0) + cgsleep_ms(10); if (compac->usbinfo.nodev) return -1; - thread_yield(); + sched_yield(); cgtime(&now); switch (info->mining_state) { case MINER_INIT: - info->mining_state = MINER_CHIP_COUNT; + cgsleep_ms(50); + compac_flush_buffer(compac); info->chips = 0; info->ramping = 0; - - if (info->asic_type == BM1387) { - unsigned char buffer[] = {0x54, 0x05, 0x00, 0x00, 0x00}; - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); - } else if (info->asic_type == BM1384) { - unsigned char buffer[] = {0x84, 0x00, 0x00, 0x00}; - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); + if (info->frequency_start > info->frequency_requested) { + info->frequency_start = info->frequency_requested; } + info->mining_state = MINER_CHIP_COUNT; return 0; break; case MINER_CHIP_COUNT: - if (ms_tdiff(&now, &info->last_reset) > 5000) { - applog(LOG_WARNING, "%s %d: found 0 chip(s)", compac->drv->name, compac->device_id); + if (ms_tdiff(&now, &info->last_reset) > MS_SECOND_5) { + applog(LOG_INFO, "%d: %s %d - found 0 chip(s)", compac->cgminer_id, compac->drv->name, compac->device_id); info->mining_state = MINER_RESET; return 0; } + cgsleep_ms(10); break; case MINER_CHIP_COUNT_OK: cgsleep_ms(50); - compac_set_frequency(compac, info->frequency_start); + //x//compac_set_frequency(compac, info->frequency_start); compac_send_chain_inactive(compac); return 0; break; @@ -843,53 +1161,52 @@ static int64_t compac_scanwork(struct thr_info *thr) return 0; break; case MINER_OPEN_CORE_OK: - applog(info->log_startup, "%s %d: start work @ %.2fMHz", compac->drv->name, compac->device_id, info->frequency); + applog(LOG_INFO, "%d: %s %d - start work", compac->cgminer_id, compac->drv->name, compac->device_id); cgtime(&info->start_time); cgtime(&info->monitor_time); cgtime(&info->last_frequency_adjust); - cgtime(&info->last_frequency_ping); + info->last_frequency_ping = (struct timeval){0}; cgtime(&info->last_frequency_report); cgtime(&info->last_micro_ping); cgtime(&info->last_nonce); compac_flush_buffer(compac); - info->log_startup = LOG_WARNING; info->mining_state = MINER_MINING; return 0; break; case MINER_MINING: - if (ms_tdiff(&now, &info->start_time) > ( 15 * 1000 )) { - info->log_startup = LOG_INFO; - } break; case MINER_RESET: + compac_flush_work(compac); if (info->asic_type == BM1387) { - compac_flush_work(compac); compac_toggle_reset(compac); - compac_prepare(thr); - - info->fail_count++; - info->mining_state = MINER_INIT; - return 0; - } else { - usb_nodev(compac); - return -1; + } else if (info->asic_type == BM1384) { + compac_set_frequency(compac, info->frequency_default); + compac_send_chain_inactive(compac); } + compac_prepare(thr); + + info->fail_count++; + info->mining_state = MINER_INIT; + cgtime(&info->last_reset); + return 0; break; case MINER_MINING_DUPS: info->mining_state = MINER_MINING; + /* Handled by per chip checks if ((int)info->frequency == 200) { //possible terminus reset condition. - compac_set_frequency(compac, info->frequency); - compac_send_chain_inactive(compac); - cgtime(&info->last_frequency_adjust); + //compac_set_frequency(compac, info->frequency); + //compac_send_chain_inactive(compac); + //cgtime(&info->last_frequency_adjust); } else { //check for reset condition - if (info->asic_type == BM1384) { - unsigned char buffer[] = {0x84, 0x00, 0x04, 0x00}; - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); - } - cgtime(&info->last_frequency_ping); + //if (info->asic_type == BM1384) { + // unsigned char buffer[] = {0x84, 0x00, 0x04, 0x00}; + // compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); + //} + //cgtime(&info->last_frequency_ping); } + */ break; default: break; @@ -923,7 +1240,7 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb info->ident = usb_ident(compac); - if (opt_gekko_gsc_detect || opt_gekko_gsd_detect || opt_gekko_gse_detect || opt_gekko_gsh_detect) { + if (opt_gekko_gsc_detect || opt_gekko_gsd_detect || opt_gekko_gse_detect || opt_gekko_gsh_detect || opt_gekko_gsi_detect) { exclude_me = (info->ident == IDENT_BSC && !opt_gekko_gsc_detect); exclude_me |= (info->ident == IDENT_GSC && !opt_gekko_gsc_detect); exclude_me |= (info->ident == IDENT_BSD && !opt_gekko_gsd_detect); @@ -931,6 +1248,7 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb exclude_me |= (info->ident == IDENT_BSE && !opt_gekko_gse_detect); exclude_me |= (info->ident == IDENT_GSE && !opt_gekko_gse_detect); exclude_me |= (info->ident == IDENT_GSH && !opt_gekko_gsh_detect); + exclude_me |= (info->ident == IDENT_GSI && !opt_gekko_gsi_detect); } if (opt_gekko_serial != NULL && (strstr(opt_gekko_serial, compac->usbdev->serial_string) == NULL)) { @@ -966,20 +1284,28 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb break; case IDENT_GSH: info->asic_type = BM1387; + info->expected_chips = 2; + break; + case IDENT_GSI: + info->asic_type = BM1387; + info->expected_chips = 12; + break; + default: + quit(1, "%d: %s compac_detect_one() invalid %s ident=%d", + compac->cgminer_id, compac->drv->dname, compac->drv->dname, info->ident); + } + + switch (info->asic_type) { + case BM1387: info->rx_len = 7; info->task_len = 54; - if (opt_gekko_boost) { - info->task_len += 96; - } info->cores = 114; info->max_job_id = 0x7f; info->healthy = 0.75; - compac_toggle_reset(compac); break; default: - quit(1, "%s compac_detect_one() invalid %s ident=%d", - compac->drv->dname, compac->drv->dname, info->ident); + break; } info->interface = usb_interface(compac); @@ -997,7 +1323,7 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb } compac->unique_id[8] = 0; - applog(LOG_WARNING, "%s %d: %s (%s)", compac->drv->name, compac->device_id, compac->usbdev->prod_string, compac->unique_id); + applog(LOG_WARNING, "%d: %s %d - %s (%s)", compac->cgminer_id, compac->drv->name, compac->device_id, compac->usbdev->prod_string, compac->unique_id); return compac; } @@ -1014,7 +1340,15 @@ static bool compac_prepare(struct thr_info *thr) int i; int read_bytes = 1; bool miner_ok = true; + int device = compac->usbinfo.bus_number * 0xff + compac->usbinfo.device_address; + + init_count = &dev_init_count[device]; + (*init_count)++; + if ((*init_count) > 1) { + applog(LOG_WARNING, "%d: %s %d - init_count %d", compac->cgminer_id, compac->drv->name, compac->device_id, *init_count); + } + info->thr = thr; info->bauddiv = 0x19; // 115200 //info->bauddiv = 0x0D; // 214286 @@ -1022,57 +1356,34 @@ static bool compac_prepare(struct thr_info *thr) //Sanity check and abort to prevent miner thread from being created. if (info->asic_type == BM1387) { - unsigned char buffer[] = { 0x58, 0x09, 0x00, 0x1C, 0x00, 0x20, 0x07, 0x00, 0x19 }; - info->bauddiv = 0x01; // 1.5Mbps baud. - buffer[6] = info->bauddiv; - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); - cgsleep_ms(1); - usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, (info->bauddiv + 1), (FTDI_INDEX_BAUD_BTS & 0xff00) | info->interface, C_SETBAUD); - cgsleep_ms(1); - // Ping Micro + info->micro_found = 0; +/* if (info->asic_type == BM1387) { info->vcore = bound(opt_gekko_gsh_vcore, 300, 810); info->micro_found = 1; if (!compac_micro_send(compac, M1_GET_TEMP, 0x00, 0x00)) { info->micro_found = 0; - applog(LOG_INFO, "%s %d: micro not found : dummy mode", compac->drv->name, compac->device_id); + applog(LOG_INFO, "%d: %s %d - micro not found : dummy mode", compac->cgminer_id, compac->drv->name, compac->device_id); } else { uint8_t vcc = (info->vcore / 1000.0 - 0.3) / 0.002; - applog(LOG_INFO, "%s %d: requesting vcore of %dmV (%x)", compac->drv->name, compac->device_id, info->vcore, vcc); + applog(LOG_INFO, "%d: %s %d - requesting vcore of %dmV (%x)", compac->cgminer_id, compac->drv->name, compac->device_id, info->vcore, vcc); compac_micro_send(compac, M2_SET_VCORE, 0x00, vcc); // Default 400mV } } - } - - if (info->mining_state == MINER_INIT) { - if (info->asic_type == BM1387) { - unsigned char buffer[] = {0x54, 0x05, 0x00, 0x00, 0x00}; - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); - } else if (info->asic_type == BM1384) { - unsigned char buffer[] = {0x84, 0x00, 0x00, 0x00}; - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); - } - - miner_ok = false; - while (read_bytes) { - memset(info->rx, 0, info->rx_len); - usb_read_timeout(compac, (char *)info->rx, info->rx_len, &read_bytes, 50, C_GETRESULTS); - if (read_bytes > 0 && info->rx[0] == 0x13) { - dumpbuffer(compac, LOG_INFO, "RX", info->rx, read_bytes); - miner_ok = true; - } - } +*/ - if (!miner_ok) { - applog(LOG_WARNING, "%s %d: found 0 chip(s)", compac->drv->name, compac->device_id); - if (info->ident == IDENT_BSD || info->ident == IDENT_GSD) { - //Don't bother retyring, will just waste resources. - compac->deven = DEV_DISABLED; - } + } + + if ((*init_count) != 0 && (*init_count) % 5 == 0) { + if ((*init_count) >= 15) { + compac->deven = DEV_DISABLED; + } else { + applog(LOG_WARNING, "%d: %s %d - forcing usb_nodev()", compac->cgminer_id, compac->drv->name, compac->device_id); + usb_nodev(compac); } + } else if ((*init_count) > 1) { + cgsleep_ms(MS_SECOND_5); } return true; @@ -1081,26 +1392,105 @@ static bool compac_prepare(struct thr_info *thr) static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) { struct COMPAC_INFO *info = compac->device_data; + struct timeval now; + int i; + + char ab[2]; + char asic_stat[64]; + char asic_statline[512]; + char ms_stat[64]; + char eff_stat[64]; + uint32_t len = 0; + + memset(asic_statline, 0, 512); + memset(asic_stat, 0, 64); + memset(ms_stat, 0, 64); + memset(eff_stat, 0, 64); + if (info->chips == 0) { + sprintf(asic_statline, "found 0 chip(s)"); + + for (i = strlen(asic_statline); i < stat_len; i++) + asic_statline[i] = ' '; + + tailsprintf(buf, bufsiz, "%s", asic_statline); return; } + + ab[0] = (info->boosted) ? '+' : 0; + ab[1] = 0; + + if (info->chips > chip_max) + chip_max = info->chips; + + cgtime(&now); + + if (opt_widescreen) { + asic_stat[0] = '['; + + for (i = 1; i <= info->chips; i++) { + struct ASIC_INFO *asic = &info->asics[i - 1]; + + switch (asic->state) { + case ASIC_HEALTHY: + asic_stat[i] = 'o'; + break; + case ASIC_HALFDEAD: + asic_stat[i] = '-'; + break; + case ASIC_ALMOST_DEAD: + asic_stat[i] = '!'; + break; + case ASIC_DEAD: + asic_stat[i] = 'x'; + break; + } + + } + asic_stat[info->chips + 1] = ']'; + for (i = 1; i <= (chip_max - info->chips) + 1; i++) + asic_stat[info->chips + 1 + i] = ' '; + } + + sprintf(ms_stat, "(%d/%d/%d)", info->scanhash_ms, info->task_ms, info->fullscan_ms); + + uint8_t wuc = (ms_tdiff(&now, &info->last_wu_increase) > MS_MINUTE_1) ? 32 : 94; + + if (info->eff_gs >= 99.9 && info->eff_wu >= 98.9) { + sprintf(eff_stat, "| 100.0%% WU:100%%"); + } else if (info->eff_wu >= 98.9) { + sprintf(eff_stat, "| %5.1f%% WU:100%%", info->eff_gs); + } else { + sprintf(eff_stat, "| %5.1f%% WU:%c%2.0f%%", info->eff_gs, wuc, info->eff_wu); + } + + if (info->asic_type == BM1387) { if (info->micro_found) { - tailsprintf(buf, bufsiz, "BM1387:%i %.2fMHz (%d/%d/%d/%.0fF)", info->chips, info->frequency, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz (%d/%d/%d/%.0fF)", info->chips, ab, info->frequency, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); } else { if (opt_log_output) { - tailsprintf(buf, bufsiz, "BM1387:%i %.2fMHz (%d/%d/%d)", info->chips, info->frequency, info->scanhash_ms, info->task_ms, info->fullscan_ms); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz %s%-13s", info->chips, ab, info->frequency, asic_stat, ms_stat); } else { - tailsprintf(buf, bufsiz, "BM1387:%i %.2fMHz", info->chips, info->frequency); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz %s%s", info->chips, ab, info->frequency, asic_stat, eff_stat); } } } else { if (opt_log_output) { - tailsprintf(buf, bufsiz, "BM1384:%i %.2fMHz (%d/%d/%d)", info->chips, info->frequency, info->scanhash_ms, info->task_ms, info->fullscan_ms); + sprintf(asic_statline, "BM1384:%02d %.2fMHz %s%-13s", info->chips, info->frequency, asic_stat, ms_stat); } else { - tailsprintf(buf, bufsiz, "BM1384:%i %.2fMHz", info->chips, info->frequency_requested); + sprintf(asic_statline, "BM1384:%02d %.2fMHz %s%s", info->chips, info->frequency, asic_stat, eff_stat); } } + + len = strlen(asic_statline); + if (len > stat_len) + stat_len = len; + + for (i = len; i < stat_len; i++) + asic_statline[i] = ' '; + + tailsprintf(buf, bufsiz, "%s", asic_statline); } static struct api_data *compac_api_stats(struct cgpu_info *compac) @@ -1120,12 +1510,14 @@ static void compac_shutdown(struct thr_info *thr) { struct cgpu_info *compac = thr->cgpu; struct COMPAC_INFO *info = compac->device_data; + applog(LOG_WARNING, "%d: %s %d - shutting down", compac->cgminer_id, compac->drv->name, compac->device_id); if (!compac->usbinfo.nodev) { if (info->asic_type == BM1387) { compac_micro_send(compac, M2_SET_VCORE, 0x00, 0x00); // 300mV compac_toggle_reset(compac); - } else if (info->asic_type == BM1384 && info->frequency != 100) { - compac_set_frequency(compac, 100); + } else if (info->asic_type == BM1384 && info->frequency != info->frequency_default) { + compac_set_frequency(compac, info->frequency_default); + compac_send_chain_inactive(compac); } } info->mining_state = MINER_SHUTDOWN; @@ -1168,17 +1560,17 @@ void stuff_msb(unsigned char *dst, uint32_t x) } struct device_drv gekko_drv = { - .drv_id = DRIVER_gekko, - .dname = "GekkoScience", - .name = "GSX", - .hash_work = hash_queued_work, - .get_api_stats = compac_api_stats, - .get_statline_before = compac_statline, - .drv_detect = compac_detect, - .scanwork = compac_scanwork, - .flush_work = compac_flush_work, - .update_work = compac_update_work, - .thread_prepare = compac_prepare, - .thread_init = compac_init, - .thread_shutdown = compac_shutdown, + .drv_id = DRIVER_gekko, + .dname = "GekkoScience", + .name = "GSX", + .hash_work = hash_queued_work, + .get_api_stats = compac_api_stats, + .get_statline_before = compac_statline, + .drv_detect = compac_detect, + .scanwork = compac_scanwork, + .flush_work = compac_flush_work, + .update_work = compac_update_work, + .thread_prepare = compac_prepare, + .thread_init = compac_init, + .thread_shutdown = compac_shutdown, }; diff --git a/driver-gekko.h b/driver-gekko.h index b79195b63a..c7de5ffa4c 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -2,14 +2,14 @@ #include "miner.h" #include "usbutils.h" -#if defined(WIN32) || defined(__APPLE__) -#define thread_yield() sched_yield() -#else -#define thread_yield() pthread_yield(NULL) -#endif - #define JOB_MAX 0x7F #define BUFFER_MAX 0xFF +#define MS_SECOND_1 1000 +#define MS_SECOND_5 1000 * 5 +#define MS_SECOND_30 1000 * 30 +#define MS_MINUTE_1 1000 * 60 +#define MS_MINUTE_10 1000 * 60 * 10 +#define MS_HOUR_1 1000 * 60 * 60 enum miner_state { MINER_INIT = 1, @@ -49,6 +49,25 @@ enum micro_command { M2_SET_VCORE = (0x1C << 3) }; +enum asic_state { + ASIC_HEALTHY = 0, + ASIC_HALFDEAD, + ASIC_ALMOST_DEAD, + ASIC_DEAD +}; + +struct ASIC_INFO { + struct timeval last_nonce; // Last time nonce was found + float frequency; + float frequency_requested; // Requested Frequency + enum asic_state state; + enum asic_state last_state; + struct timeval state_change_time; // Device startup time + + uint32_t fullscan_ms; // Estimated time(ms) for full nonce range + uint64_t hashrate; // Estimated hashrate = cores x chips x frequency +}; + struct COMPAC_INFO { enum sub_ident ident; // Miner identity @@ -60,11 +79,20 @@ struct COMPAC_INFO { pthread_mutex_t lock; // Mutex pthread_mutex_t wlock; // Mutex Serialize Writes + pthread_mutex_t rlock; // Mutex Serialize Reads float frequency; // Chip Frequency float frequency_requested; // Requested Frequency float frequency_start; // Starting Frequency + float frequency_default; // ASIC Frequency on RESET float healthy; // Lower percentile before tagging asic unhealthy + float eff_gs; + float eff_tm; + float eff_li; + float eff_1m; + float eff_5m; + float eff_15; + float eff_wu; float micro_temp; // Micro Reported Temp @@ -72,16 +100,17 @@ struct COMPAC_INFO { uint32_t task_ms; // Avg time(ms) between task sent to device uint32_t fullscan_ms; // Estimated time(ms) for full nonce range uint64_t hashrate; // Estimated hashrate = cores x chips x frequency + uint64_t busy_work; uint64_t task_hcn; // Hash Count Number - max nonce iter. uint32_t prev_nonce; // Last nonce found int failing; // Flag failing sticks int fail_count; // Track failures. + int frequency_of; // Frequency check token int accepted; // Nonces accepted int dups; // Duplicates found int interface; // USB interface - int log_startup; // LOG_WARNING first 15 seconds, then LOG_INFO int nonceless; // Tasks sent. Resets when nonce is found. int nonces; // Nonces found int zero_check; // Received nonces from zero work @@ -89,11 +118,17 @@ struct COMPAC_INFO { int micro_found; // Found a micro to communicate with bool vmask; // Current pool's vmask + bool boosted; // Good nonce found for midstate2/3/4 + bool report; + + double wu; + double wu_max; // Max WU since last frequency change uint32_t bauddiv; // Baudrate divider uint32_t chips; // Stores number of chips found uint32_t cores; // Stores number of core per chp uint32_t difficulty; // For computing hashrate + uint32_t expected_chips; // Number of chips for device uint64_t hashes; // Hashes completed uint32_t job_id; // JobId incrementer uint32_t low_hash; // Tracks of low hashrate @@ -118,7 +153,10 @@ struct COMPAC_INFO { struct timeval last_chain_inactive; // Last sent chain inactive struct timeval last_micro_ping; // Last time of micro controller poll struct timeval last_write_error; // Last usb write error message + struct timeval last_wu_increase; // Last wu_max change + struct timeval last_pool_lost; // Last time we lost pool + struct ASIC_INFO asics[64]; bool active_work[JOB_MAX]; // Tag good and stale work struct work *work[JOB_MAX]; // Work ring buffer diff --git a/miner.h b/miner.h index e2fb5260c4..fe6b4f4a07 100644 --- a/miner.h +++ b/miner.h @@ -999,6 +999,7 @@ struct pool; #define API_MCAST_CODE "FTW" #define API_MCAST_ADDR "224.0.0.75" +extern bool opt_widescreen; extern bool opt_work_update; extern bool opt_protocol; extern bool have_longpoll; @@ -1040,15 +1041,19 @@ extern char *opt_bitburner_fury_options; #endif #ifdef USE_GEKKO extern char *opt_gekko_serial; -extern bool opt_gekko_boost; +extern bool opt_gekko_noboost; extern bool opt_gekko_gsc_detect; extern bool opt_gekko_gsd_detect; extern bool opt_gekko_gse_detect; extern bool opt_gekko_gsh_detect; +extern bool opt_gekko_gsi_detect; extern float opt_gekko_gsc_freq; extern float opt_gekko_gsd_freq; extern float opt_gekko_gse_freq; +extern float opt_gekko_tune_down; +extern float opt_gekko_tune_up; extern int opt_gekko_gsh_freq; +extern int opt_gekko_gsi_freq; extern int opt_gekko_gsh_vcore; extern int opt_gekko_start_freq; extern int opt_gekko_step_freq; diff --git a/usbutils.c b/usbutils.c index f45272554d..227db2f9e2 100644 --- a/usbutils.c +++ b/usbutils.c @@ -1062,6 +1062,18 @@ static struct usb_find_devices find_dev[] = { .timeout = COMPAC_TIMEOUT_MS, .latency = LATENCY_UNUSED, INTINFO(gek2_ints) }, + { + .drv = DRIVER_gekko, + .name = "GSI", + .ident = IDENT_GSI, + .idVendor = 0x0403, + .idProduct = 0x6015, + .iManufacturer = "GekkoScience", + .iProduct = "R606 Bitcoin Miner", + .config = 1, + .timeout = COMPAC_TIMEOUT_MS, + .latency = LATENCY_UNUSED, + INTINFO(gek2_ints) }, #endif { DRIVER_MAX, NULL, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, NULL } }; diff --git a/usbutils.h b/usbutils.h index 32f4f9b8da..35591113ea 100644 --- a/usbutils.h +++ b/usbutils.h @@ -196,6 +196,7 @@ enum sub_ident { IDENT_GSD, IDENT_GSE, IDENT_GSH, + IDENT_GSI, IDENT_HFA, IDENT_HRO, IDENT_ICA, diff --git a/util.c b/util.c index 66007f39ba..543aca119f 100644 --- a/util.c +++ b/util.c @@ -2245,11 +2245,6 @@ static bool configure_stratum_mining(struct pool *pool) json_t *response, *value, *res_val, *err_val; json_error_t err; -#ifdef USE_GEKKO - if (!opt_gekko_boost) - return true; -#endif - snprintf(s, RBUFSIZE, "{\"id\": %d, \"method\": \"mining.configure\", \"params\": " "[[\""STRATUM_VERSION_ROLLING"\"], " @@ -3085,7 +3080,7 @@ static bool setup_stratum_socket(struct pool *pool) * we can connect to quickly. */ noblock_socket(sockd); if (connect(sockd, p->ai_addr, p->ai_addrlen) == -1) { - struct timeval tv_timeout = {1, 0}; + struct timeval tv_timeout = {2, 0}; int selret; fd_set rw; @@ -3229,8 +3224,21 @@ bool initiate_stratum(struct pool *pool) } /* Attempt to configure stratum protocol feature set first. */ +#ifdef USE_GEKKO + configure_stratum_mining(pool); + if (!pool->stratum_active) { + //repair damage done by configure_stratum_mining + if (!setup_stratum_socket(pool)) { + sockd = false; + goto out; + } + + sockd = true; + } +#else if (!configure_stratum_mining(pool)) goto out; +#endif if (recvd) { sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++); From 6e1b09d7f77458d6800f8b3221f6c29edbf3fb54 Mon Sep 17 00:00:00 2001 From: vthoang Date: Sun, 7 Apr 2019 04:03:32 +0100 Subject: [PATCH 093/113] fix WU calculation. fix zero chip not resetting --- driver-gekko.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index 2a0d640e18..fcd69869be 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -185,7 +185,7 @@ static void compac_send_chain_inactive(struct cgpu_info *compac) //compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); } - if (info->mining_state != MINER_MINING) { + if (info->mining_state == MINER_CHIP_COUNT_OK) { applog(LOG_INFO, "%d: %s %d - open cores", compac->cgminer_id, compac->drv->name, compac->device_id); info->zero_check = 0; info->task_hcn = 0; @@ -464,7 +464,7 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) return hashes; } - //work->device_diff = info->difficulty; + work->device_diff = info->difficulty; if (submit_nonce(info->thr, work, nonce)) { int asic_id = floor(info->rx[0] / (0x100 / info->chips)); @@ -983,8 +983,12 @@ static void *compac_listen(void *object) info->mining_state = MINER_RESET; } else { applog(LOG_WARNING, "%d: %s %d - found %d chip(s)", compac->cgminer_id, compac->drv->name, compac->device_id, info->chips); - info->mining_state = MINER_CHIP_COUNT_OK; - (*init_count) = 0; + if (info->chips > 0) { + info->mining_state = MINER_CHIP_COUNT_OK; + (*init_count) = 0; + } else { + info->mining_state = MINER_RESET; + } } break; default: From a4535645262f05a6511005b8f0a5c8d956b3c6c7 Mon Sep 17 00:00:00 2001 From: vthoang Date: Sun, 7 Apr 2019 17:12:20 +0100 Subject: [PATCH 094/113] add WU to tune-down, as a longer term health metric. --- driver-gekko.c | 122 ++++++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index fcd69869be..ca18b45f23 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -134,9 +134,9 @@ static void compac_send(struct cgpu_info *compac, unsigned char *req_tx, uint32_ info->cmd[bytes - 1] |= bmcrc(req_tx, crc_bits); cgsleep_ms(1); - + int log_level = (bytes < info->task_len) ? LOG_INFO : LOG_INFO; - + dumpbuffer(compac, LOG_INFO, "TX", info->cmd, bytes); usb_write(compac, info->cmd, bytes, &read_bytes, C_REQUESTRESULTS); } @@ -158,7 +158,7 @@ static void compac_send_chain_inactive(struct cgpu_info *compac) buffer[2] = (0x100 / info->chips) * i; compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8);; } - + cgsleep_ms(10); unsigned char baudrate[] = { 0x58, 0x09, 0x00, 0x1C, 0x00, 0x20, 0x07, 0x00, 0x19 }; info->bauddiv = 0x01; // 1.5Mbps baud. @@ -167,7 +167,7 @@ static void compac_send_chain_inactive(struct cgpu_info *compac) cgsleep_ms(10); usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, (info->bauddiv + 1), (FTDI_INDEX_BAUD_BTS & 0xff00) | info->interface, C_SETBAUD); cgsleep_ms(10); - + unsigned char gateblk[9] = {0x58, 0x09, 0x00, 0x1C, 0x40, 0x20, 0x99, 0x80, 0x01}; gateblk[6] = 0x80 | info->bauddiv; compac_send(compac, (char *)gateblk, sizeof(gateblk), 8 * sizeof(gateblk) - 8);; // chain inactive @@ -206,21 +206,21 @@ static void compac_update_rates(struct cgpu_info *compac) asic->fullscan_ms = 1000.0 * 0xffffffffull / asic->hashrate; average_frequency += asic->frequency; } - + average_frequency = average_frequency / info->chips; if (average_frequency != info->frequency) { applog(LOG_INFO,"%d: %s %d - frequency updated %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency, average_frequency); info->frequency = average_frequency; info->wu_max = 0; } - + info->hashrate = info->chips * info->frequency * info->cores * 1000000; info->fullscan_ms = 1000.0 * 0xffffffffull / info->hashrate; info->scanhash_ms = bound(info->fullscan_ms / 2, 1, 100); info->ticket_mask = bound(pow(2, ceil(log(info->hashrate / (2.0 * 0xffffffffull)) / log(2))) - 1, 0, 4000); info->ticket_mask = (info->asic_type == BM1387) ? 0 : info->ticket_mask; info->difficulty = info->ticket_mask + 1; - info->wu = 0.0139091 * info->cores * info->chips * info->frequency; + info->wu = 0.0139091 * info->cores * info->chips * info->frequency; } static void compac_set_frequency_single(struct cgpu_info *compac, float frequency, int asic_id) @@ -242,7 +242,7 @@ static void compac_set_frequency_single(struct cgpu_info *compac, float frequenc buffer[5] = (frequency * 4) / 25; } buffer[2] = (0x100 / info->chips) * asic_id; - + //asic->frequency = frequency; applog(LOG_INFO, "%d: %s %d - setting chip[%d] frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, asic_id, asic->frequency, frequency); compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); @@ -251,7 +251,7 @@ static void compac_set_frequency_single(struct cgpu_info *compac, float frequenc //gateblk[6] = 0x80 | info->bauddiv; //gateblk[2] = (0x100 / info->chips) * id; //compac_send(compac, (char *)gateblk, sizeof(gateblk), 8 * sizeof(gateblk) - 8);; // chain inactive - + } } @@ -278,7 +278,7 @@ static void compac_set_frequency(struct cgpu_info *compac, float frequency) buffer[5] = (frequency * 2) / 25; } */ - + //applog(LOG_WARNING, "%d: %s %d - setting frequency to %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, frequency); //compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); @@ -288,7 +288,7 @@ static void compac_set_frequency(struct cgpu_info *compac, float frequency) info->frequency = frequency; info->last_frequency_ping = (struct timeval){0}; - + } else if (info->asic_type == BM1384) { unsigned char buffer[] = {0x82, 0x0b, 0x83, 0x00}; @@ -469,13 +469,13 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) if (submit_nonce(info->thr, work, nonce)) { int asic_id = floor(info->rx[0] / (0x100 / info->chips)); struct ASIC_INFO *asic = &info->asics[asic_id]; - cgtime(&asic->last_nonce); + cgtime(&asic->last_nonce); cgtime(&info->last_nonce); if (midnum > 0) { applog(LOG_INFO, "%d: %s %d - AsicBoost nonce found : midstate%d", compac->cgminer_id, compac->drv->name, compac->device_id, midnum); } - + info->accepted++; info->failing = false; } else { @@ -564,7 +564,7 @@ static void *compac_mine(void *object) uint64_t max_task_wait = 0; char str_frequency[1024]; float wait_factor = ((!opt_gekko_noboost && info->vmask && info->asic_type == BM1387) ? 2.25 : 0.75); - + bool adjustable = 0; #ifndef WIN32 @@ -591,13 +591,13 @@ static void *compac_mine(void *object) bool low_eff = 0; info->update_work = 0; - + max_task_wait = bound(wait_factor * info->fullscan_ms, 1, 3 * info->fullscan_ms); sleep_ms = bound(ceil(max_task_wait/100.0), 1, 200); dev_runtime = cgpu_runtime(compac); wu = compac->diff1 / dev_runtime * 60; - + if (wu > info->wu_max) { info->wu_max = wu; cgtime(&info->last_wu_increase); @@ -608,27 +608,27 @@ static void *compac_mine(void *object) hashrate_5m = (double)compac->rolling5 * 1000000ull; hashrate_15 = (double)compac->rolling15 * 1000000ull; hashrate_tm = (double)compac->total_mhashes / dev_runtime * 1000000ull;; - + info->eff_li = 100.0 * (1.0 * hashrate_li / info->hashrate); info->eff_1m = 100.0 * (1.0 * hashrate_1m / info->hashrate); - info->eff_5m = 100.0 * (1.0 * hashrate_5m / info->hashrate); - info->eff_15 = 100.0 * (1.0 * hashrate_15 / info->hashrate); + info->eff_5m = 100.0 * (1.0 * hashrate_5m / info->hashrate); + info->eff_15 = 100.0 * (1.0 * hashrate_15 / info->hashrate); info->eff_wu = 100.0 * (1.0 * wu / info->wu); info->eff_tm = 100.0 * (1.0 * hashrate_tm / info->hashrate); - + info->eff_li = (info->eff_li > 100) ? 100 : info->eff_li; info->eff_1m = (info->eff_1m > 100) ? 100 : info->eff_1m; info->eff_5m = (info->eff_5m > 100) ? 100 : info->eff_5m; info->eff_15 = (info->eff_15 > 100) ? 100 : info->eff_15; info->eff_wu = (info->eff_wu > 100) ? 100 : info->eff_wu; info->eff_tm = (info->eff_tm > 100) ? 100 : info->eff_tm; - + info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; - if (abs(info->eff_1m - info->eff_5m) < 2.5 && info->eff_5m > 10.0 && info->eff_15 < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_1m < opt_gekko_tune_down) { + if (abs(info->eff_1m - info->eff_5m) < 1.5 && info->eff_5m > 10.0 && info->eff_15 < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { low_eff = 1; } - + if (ms_tdiff(&now, &info->monitor_time) > MS_SECOND_5 && ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_5) { for (i = 0; i < info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i]; @@ -654,7 +654,7 @@ static void *compac_mine(void *object) } } } - + if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10 && ms_tdiff(&now, &info->last_pool_lost) > MS_MINUTE_10) { float new_frequency = info->frequency - 6.25; applog(LOG_WARNING,"%d: %s %d - low eff: (1m)%.1f (5m)%.1f (15m)%.1f - [%.1f]", compac->cgminer_id, compac->drv->name, compac->device_id, info->eff_1m, info->eff_5m, info->eff_15, opt_gekko_tune_down); @@ -668,7 +668,7 @@ static void *compac_mine(void *object) cgtime(&info->last_frequency_adjust); cgtime(&info->monitor_time); } - + if (ms_tdiff(&now, &info->last_frequency_ping) > MS_SECOND_5 || (info->frequency_of != info->chips && ms_tdiff(&now, &info->last_frequency_ping) > 50)) { info->frequency_of--; @@ -680,7 +680,7 @@ static void *compac_mine(void *object) info->frequency_of = info->chips; ping_itr = (ping_itr + 1) % 2; adjustable = 0; - } else { + } else { struct ASIC_INFO *asic = &info->asics[info->frequency_of]; if (ping_itr == 1 && asic->frequency != asic->frequency_requested) { float new_frequency; @@ -810,7 +810,7 @@ static void *compac_handle_rx(void *object, int read_bytes) } else if (info->asic_type == BM1384) { frequency = (info->rx[1] + 1) * 6.25 / (1 + info->rx[2] & 0x0f) * pow(2, (3 - info->rx[3])) + ((info->rx[2] >> 4) * 6.25); } - + if (info->frequency_of != info->chips) { asic = &info->asics[info->frequency_of]; if (frequency != asic->frequency) { @@ -831,7 +831,7 @@ static void *compac_handle_rx(void *object, int read_bytes) info->frequency = frequency; } } - + compac_update_rates(compac); } } @@ -886,9 +886,9 @@ static void *compac_listen(void *object) rx_bytes = 0; while (info->mining_state != MINER_SHUTDOWN) { - + cgtime(&now); - + if (info->mining_state == MINER_CHIP_COUNT) { if (info->asic_type == BM1387) { unsigned char buffer[] = {0x54, 0x05, 0x00, 0x00, 0x00}; @@ -899,26 +899,26 @@ static void *compac_listen(void *object) } err = usb_read_timeout(compac, rx, BUFFER_MAX, &read_bytes, 1000, C_GETRESULTS); dumpbuffer(compac, LOG_INFO, "CMD.RX", rx, read_bytes); - + rx_bytes = read_bytes; info->mining_state = MINER_CHIP_COUNT_XX; } else { err = usb_read_timeout(compac, &rx[pos], info->rx_len, &read_bytes, 20, C_GETRESULTS); rx_bytes += read_bytes; } - + if (read_bytes > 0) { - + if (rx_bytes < info->rx_len) { applog(LOG_INFO, "%d: %s %d - Buffered %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, rx_bytes); dumpbuffer(compac, LOG_INFO, "Partial-RX", rx, rx_bytes); pos = rx_bytes; continue; } - + if (rx_bytes >= info->rx_len) cmd_resp = (rx[read_bytes - 1] <= 0x1F && bmcrc(prx, 8 * read_bytes - 5) == rx[read_bytes - 1]) ? 1 : 0; - + if (info->mining_state == MINER_CHIP_COUNT_XX || cmd_resp) { if (rx_bytes % info->rx_len == 2) { // fix up trial 1 @@ -934,14 +934,14 @@ static void *compac_listen(void *object) rx_bytes -= shift; applog(LOG_INFO, "%d: %s %d - Extra Data - 0x01 0x%02x", compac->cgminer_id, compac->drv->name, compac->device_id, extra & 0xff); } - } + } if (rx_bytes % info->rx_len != 0) { int n_read_bytes; pos = rx_bytes; err = usb_read_timeout(compac, &rx[pos], BUFFER_MAX - pos, &n_read_bytes, 1, C_GETRESULTS); rx_bytes += n_read_bytes; - + if (rx_bytes % info->rx_len != 0 && rx_bytes >= info->rx_len) { int extra_bytes = rx_bytes % info->rx_len; for (i = extra_bytes; i < rx_bytes; i++) { @@ -951,7 +951,7 @@ static void *compac_listen(void *object) applog(LOG_INFO, "%d: %s %d - Fixing buffer alignment, dumping initial %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, extra_bytes); } } - + if (rx_bytes % info->rx_len == 0) { for (i = 0; i < rx_bytes; i += info->rx_len) { memcpy(info->rx, &rx[i], info->rx_len); @@ -964,10 +964,10 @@ static void *compac_listen(void *object) if (rx_bytes > 0) applog(LOG_INFO, "%d: %s %d - Second read, no data dumping (c) %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, rx_bytes); - + pos = 0; rx_bytes = 0; - + // RX line is idle, let's squeeze in a command to the micro if needed. if (info->asic_type == BM1387) { if (ms_tdiff(&now, &info->last_micro_ping) > MS_SECOND_5 && ms_tdiff(&now, &info->last_task) > 1 && ms_tdiff(&now, &info->last_task) < 3) { @@ -1004,7 +1004,7 @@ static bool compac_init(struct thr_info *thr) int i; struct cgpu_info *compac = thr->cgpu; struct COMPAC_INFO *info = compac->device_data; - + info->boosted = false; info->prev_nonce = 0; info->fail_count = 0; @@ -1082,7 +1082,7 @@ static bool compac_init(struct thr_info *thr) applog(LOG_INFO, "%d: %s %d - read thread created", compac->cgminer_id, compac->drv->name, compac->device_id); } pthread_detach(info->rthr.pth); - + cgsleep_ms(100); if (thr_info_create(&(info->wthr), NULL, compac_mine, (void *)compac)) { @@ -1107,7 +1107,7 @@ static int64_t compac_scanwork(struct thr_info *thr) int read_bytes; uint32_t err = 0; uint64_t hashes = 0; - + if (info->chips == 0) cgsleep_ms(10); @@ -1298,7 +1298,7 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb quit(1, "%d: %s compac_detect_one() invalid %s ident=%d", compac->cgminer_id, compac->drv->dname, compac->drv->dname, info->ident); } - + switch (info->asic_type) { case BM1387: info->rx_len = 7; @@ -1352,7 +1352,7 @@ static bool compac_prepare(struct thr_info *thr) if ((*init_count) > 1) { applog(LOG_WARNING, "%d: %s %d - init_count %d", compac->cgminer_id, compac->drv->name, compac->device_id, *init_count); } - + info->thr = thr; info->bauddiv = 0x19; // 115200 //info->bauddiv = 0x0D; // 214286 @@ -1378,7 +1378,7 @@ static bool compac_prepare(struct thr_info *thr) */ } - + if ((*init_count) != 0 && (*init_count) % 5 == 0) { if ((*init_count) >= 15) { compac->deven = DEV_DISABLED; @@ -1398,7 +1398,7 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) struct COMPAC_INFO *info = compac->device_data; struct timeval now; int i; - + char ab[2]; char asic_stat[64]; char asic_statline[512]; @@ -1416,25 +1416,25 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) for (i = strlen(asic_statline); i < stat_len; i++) asic_statline[i] = ' '; - + tailsprintf(buf, bufsiz, "%s", asic_statline); return; } - + ab[0] = (info->boosted) ? '+' : 0; ab[1] = 0; if (info->chips > chip_max) chip_max = info->chips; - + cgtime(&now); if (opt_widescreen) { asic_stat[0] = '['; - + for (i = 1; i <= info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i - 1]; - + switch (asic->state) { case ASIC_HEALTHY: asic_stat[i] = 'o'; @@ -1455,20 +1455,20 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) for (i = 1; i <= (chip_max - info->chips) + 1; i++) asic_stat[info->chips + 1 + i] = ' '; } - + sprintf(ms_stat, "(%d/%d/%d)", info->scanhash_ms, info->task_ms, info->fullscan_ms); - + uint8_t wuc = (ms_tdiff(&now, &info->last_wu_increase) > MS_MINUTE_1) ? 32 : 94; - + if (info->eff_gs >= 99.9 && info->eff_wu >= 98.9) { sprintf(eff_stat, "| 100.0%% WU:100%%"); } else if (info->eff_wu >= 98.9) { - sprintf(eff_stat, "| %5.1f%% WU:100%%", info->eff_gs); + sprintf(eff_stat, "| %5.1f%% WU:100%%", info->eff_gs); } else { sprintf(eff_stat, "| %5.1f%% WU:%c%2.0f%%", info->eff_gs, wuc, info->eff_wu); } - - + + if (info->asic_type == BM1387) { if (info->micro_found) { sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz (%d/%d/%d/%.0fF)", info->chips, ab, info->frequency, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); @@ -1486,14 +1486,14 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) sprintf(asic_statline, "BM1384:%02d %.2fMHz %s%s", info->chips, info->frequency, asic_stat, eff_stat); } } - + len = strlen(asic_statline); if (len > stat_len) stat_len = len; - + for (i = len; i < stat_len; i++) asic_statline[i] = ' '; - + tailsprintf(buf, bufsiz, "%s", asic_statline); } From 0b579181f56678dfcbf2f3219b3041af82abffb3 Mon Sep 17 00:00:00 2001 From: vthoang Date: Sun, 7 Apr 2019 22:00:28 +0100 Subject: [PATCH 095/113] add one hour health check --- driver-gekko.c | 34 ++++++++++++++++++++++++++-------- driver-gekko.h | 1 + 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index ca18b45f23..7410171c3f 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -476,6 +476,10 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) applog(LOG_INFO, "%d: %s %d - AsicBoost nonce found : midstate%d", compac->cgminer_id, compac->drv->name, compac->device_id, midnum); } + if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10) { + info->nononce_reset = 0; + } + info->accepted++; info->failing = false; } else { @@ -625,32 +629,45 @@ static void *compac_mine(void *object) info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; - if (abs(info->eff_1m - info->eff_5m) < 1.5 && info->eff_5m > 10.0 && info->eff_15 < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { - low_eff = 1; + if (abs(info->eff_1m - info->eff_5m) < 1.5 || ms_tdiff(&now, &info->last_frequency_adjust) > MS_HOUR_1) { + // Check after one hour or when 5m average approaches 1.5% of 1m. + if (info->eff_5m > 10.0 && info->eff_15 < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { + low_eff = 1; + } } if (ms_tdiff(&now, &info->monitor_time) > MS_SECOND_5 && ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_5) { for (i = 0; i < info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i]; if (ms_tdiff(&now, &asic->last_nonce) > asic->fullscan_ms * 20 * info->difficulty) { - float new_frequency; - if (info->frequency_requested > asic->frequency) { - new_frequency = asic->frequency; + float new_frequency = info->frequency_requested; + if (info->eff_wu > opt_gekko_tune_down && info->nononce_reset < 3) { + // High WU - give it some credit, retry at current target frequency + } else if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10) { + // Been running for 10 minutes, retry at current target frequency } else { - new_frequency = asic->frequency - 6.25; + if (info->frequency_requested > info->frequency) { + // Set to current frequency + new_frequency = info->frequency; + } else { + // Step back frequency + new_frequency = asic->frequency - 6.25; + } } asic->last_state = asic->state; asic->state = ASIC_HALFDEAD; cgtime(&asic->state_change_time); cgtime(&info->monitor_time); applog(LOG_WARNING,"%d: %s %d - missing nonces from chip[%d]", compac->cgminer_id, compac->drv->name, compac->device_id, i); - if (ms_tdiff(&now, &info->last_frequency_adjust) < MS_MINUTE_10) { + if (new_frequency != info->frequency_requested) { applog(LOG_WARNING,"%d: %s %d - target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); info->frequency_requested = new_frequency; + info->nononce_reset = 0; cgtime(&info->last_frequency_adjust); } + info->nononce_reset++; info->mining_state = MINER_RESET; - continue; + break; } } } @@ -1009,6 +1026,7 @@ static bool compac_init(struct thr_info *thr) info->prev_nonce = 0; info->fail_count = 0; info->busy_work = 0; + info->nononce_reset = 0; info->frequency_default = 200; info->frequency = 200; info->frequency_of = info->chips; diff --git a/driver-gekko.h b/driver-gekko.h index c7de5ffa4c..f1f71b1c78 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -113,6 +113,7 @@ struct COMPAC_INFO { int interface; // USB interface int nonceless; // Tasks sent. Resets when nonce is found. int nonces; // Nonces found + int nononce_reset; // Count missing nonces int zero_check; // Received nonces from zero work int vcore; // Core voltage int micro_found; // Found a micro to communicate with From 363d87933c5d781fcdf813307a057361623f848f Mon Sep 17 00:00:00 2001 From: vthoang Date: Mon, 8 Apr 2019 01:08:59 +0100 Subject: [PATCH 096/113] found a r606 plateau during ramp match --- driver-gekko.c | 25 ++++++++++++++++--------- driver-gekko.h | 1 + 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index 7410171c3f..3a2acd0aca 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -359,7 +359,7 @@ static void compac_toggle_reset(struct cgpu_info *compac) struct COMPAC_INFO *info = compac->device_data; unsigned short usb_val; - applog(LOG_WARNING,"%d: %s %d - Toggling ASIC nRST to reset", compac->cgminer_id, compac->drv->name, compac->device_id); + applog(LOG_INFO,"%d: %s %d - Toggling ASIC nRST to reset", compac->cgminer_id, compac->drv->name, compac->device_id); usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET, info->interface, C_RESET); usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, FTDI_VALUE_DATA_BTS, info->interface, C_SETDATA); @@ -636,6 +636,10 @@ static void *compac_mine(void *object) } } + if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_HOUR_1) { + info->nononce_reset = 0; + } + if (ms_tdiff(&now, &info->monitor_time) > MS_SECOND_5 && ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_5) { for (i = 0; i < info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i]; @@ -644,7 +648,11 @@ static void *compac_mine(void *object) if (info->eff_wu > opt_gekko_tune_down && info->nononce_reset < 3) { // High WU - give it some credit, retry at current target frequency } else if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10) { - // Been running for 10 minutes, retry at current target frequency + // Been running for 10 minutes, possible plateau + if (info->frequency_requested > info->frequency) { + // Move requested frequency closer to plateau value + new_frequency = info->frequency + 6.25; + } } else { if (info->frequency_requested > info->frequency) { // Set to current frequency @@ -658,11 +666,10 @@ static void *compac_mine(void *object) asic->state = ASIC_HALFDEAD; cgtime(&asic->state_change_time); cgtime(&info->monitor_time); - applog(LOG_WARNING,"%d: %s %d - missing nonces from chip[%d]", compac->cgminer_id, compac->drv->name, compac->device_id, i); + applog(LOG_INFO,"%d: %s %d - missing nonces from chip[%d]", compac->cgminer_id, compac->drv->name, compac->device_id, i); if (new_frequency != info->frequency_requested) { - applog(LOG_WARNING,"%d: %s %d - target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); + applog(LOG_WARNING,"%d: %s %d - no nonce: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); info->frequency_requested = new_frequency; - info->nononce_reset = 0; cgtime(&info->last_frequency_adjust); } info->nononce_reset++; @@ -674,7 +681,7 @@ static void *compac_mine(void *object) if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10 && ms_tdiff(&now, &info->last_pool_lost) > MS_MINUTE_10) { float new_frequency = info->frequency - 6.25; - applog(LOG_WARNING,"%d: %s %d - low eff: (1m)%.1f (5m)%.1f (15m)%.1f - [%.1f]", compac->cgminer_id, compac->drv->name, compac->device_id, info->eff_1m, info->eff_5m, info->eff_15, opt_gekko_tune_down); + applog(LOG_WARNING,"%d: %s %d - low eff: (1m)%.1f (5m)%.1f (15m)%.1f (WU)%.1f - [%.1f]", compac->cgminer_id, compac->drv->name, compac->device_id, info->eff_1m, info->eff_5m, info->eff_15, info->eff_wu, opt_gekko_tune_down); applog(LOG_WARNING,"%d: %s %d - low eff: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); info->frequency_requested = new_frequency; for (i = 0; i < info->chips; i++) @@ -996,10 +1003,10 @@ static void *compac_listen(void *object) switch (info->mining_state) { case MINER_CHIP_COUNT_XX: if (info->chips < info->expected_chips) { - applog(LOG_WARNING, "%d: %s %d - found %d/%d chip(s)", compac->cgminer_id, compac->drv->name, compac->device_id, info->chips, info->expected_chips); + applog(LOG_INFO, "%d: %s %d - found %d/%d chip(s)", compac->cgminer_id, compac->drv->name, compac->device_id, info->chips, info->expected_chips); info->mining_state = MINER_RESET; } else { - applog(LOG_WARNING, "%d: %s %d - found %d chip(s)", compac->cgminer_id, compac->drv->name, compac->device_id, info->chips); + applog(LOG_INFO, "%d: %s %d - found %d chip(s)", compac->cgminer_id, compac->drv->name, compac->device_id, info->chips); if (info->chips > 0) { info->mining_state = MINER_CHIP_COUNT_OK; (*init_count) = 0; @@ -1368,7 +1375,7 @@ static bool compac_prepare(struct thr_info *thr) (*init_count)++; if ((*init_count) > 1) { - applog(LOG_WARNING, "%d: %s %d - init_count %d", compac->cgminer_id, compac->drv->name, compac->device_id, *init_count); + applog(LOG_INFO, "%d: %s %d - init_count %d", compac->cgminer_id, compac->drv->name, compac->device_id, *init_count); } info->thr = thr; diff --git a/driver-gekko.h b/driver-gekko.h index f1f71b1c78..8138b99265 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -9,6 +9,7 @@ #define MS_SECOND_30 1000 * 30 #define MS_MINUTE_1 1000 * 60 #define MS_MINUTE_10 1000 * 60 * 10 +#define MS_MINUTE_30 1000 * 60 * 30 #define MS_HOUR_1 1000 * 60 * 60 enum miner_state { From 67a12a6ccfb55dca711f7872e7c10f46b75af7ca Mon Sep 17 00:00:00 2001 From: vthoang Date: Wed, 10 Apr 2019 15:55:17 +0100 Subject: [PATCH 097/113] redo no nonce handling. --- driver-gekko.c | 76 ++++++++++++++++++++++++++++---------------------- driver-gekko.h | 6 ++-- 2 files changed, 47 insertions(+), 35 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index 3a2acd0aca..de0814aa99 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -476,10 +476,6 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) applog(LOG_INFO, "%d: %s %d - AsicBoost nonce found : midstate%d", compac->cgminer_id, compac->drv->name, compac->device_id, midnum); } - if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10) { - info->nononce_reset = 0; - } - info->accepted++; info->failing = false; } else { @@ -629,37 +625,40 @@ static void *compac_mine(void *object) info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; - if (abs(info->eff_1m - info->eff_5m) < 1.5 || ms_tdiff(&now, &info->last_frequency_adjust) > MS_HOUR_1) { - // Check after one hour or when 5m average approaches 1.5% of 1m. - if (info->eff_5m > 10.0 && info->eff_15 < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { - low_eff = 1; - } - } - - if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_HOUR_1) { - info->nononce_reset = 0; + if (info->eff_5m > 10.0 && info->eff_15 < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { + low_eff = 1; } if (ms_tdiff(&now, &info->monitor_time) > MS_SECOND_5 && ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_5) { for (i = 0; i < info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i]; - if (ms_tdiff(&now, &asic->last_nonce) > asic->fullscan_ms * 20 * info->difficulty) { + if (ms_tdiff(&now, &asic->last_nonce) > MS_SECOND_30) { float new_frequency = info->frequency_requested; - if (info->eff_wu > opt_gekko_tune_down && info->nononce_reset < 3) { - // High WU - give it some credit, retry at current target frequency - } else if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10) { - // Been running for 10 minutes, possible plateau - if (info->frequency_requested > info->frequency) { - // Move requested frequency closer to plateau value - new_frequency = info->frequency + 6.25; + + if (info->nononce_reset < 3) { + // Capture failure high/low frequencies using first three resets + if ((info->frequency - 6.25) > info->frequency_fail_high) { + info->frequency_fail_high = (info->frequency - 6.25); + } + if ((info->frequency - 6.25) < info->frequency_fail_low) { + info->frequency_fail_low = (info->frequency - 6.25); } + applog(LOG_WARNING,"%d: %s %d - no nonce: (%d/3) %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->nononce_reset + 1, info->frequency_fail_high); } else { if (info->frequency_requested > info->frequency) { - // Set to current frequency - new_frequency = info->frequency; + if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_30) { + // Been running for 30 minutes, possible plateau + // Move requested frequency closer to plateau value + new_frequency = info->frequency; + } else { + // Set to current highest detected fail frequency + new_frequency = info->frequency_fail_high; + } } else { - // Step back frequency - new_frequency = asic->frequency - 6.25; + if (ms_tdiff(&now, &info->last_frequency_adjust) < MS_MINUTE_30) { + // Step back frequency + new_frequency = info->frequency - 6.25; + } } } asic->last_state = asic->state; @@ -670,7 +669,6 @@ static void *compac_mine(void *object) if (new_frequency != info->frequency_requested) { applog(LOG_WARNING,"%d: %s %d - no nonce: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); info->frequency_requested = new_frequency; - cgtime(&info->last_frequency_adjust); } info->nononce_reset++; info->mining_state = MINER_RESET; @@ -679,7 +677,7 @@ static void *compac_mine(void *object) } } - if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10 && ms_tdiff(&now, &info->last_pool_lost) > MS_MINUTE_10) { + if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10 && ms_tdiff(&now, &info->last_wu_increase) > MS_MINUTE_30 && ms_tdiff(&now, &info->last_pool_lost) > MS_MINUTE_10) { float new_frequency = info->frequency - 6.25; applog(LOG_WARNING,"%d: %s %d - low eff: (1m)%.1f (5m)%.1f (15m)%.1f (WU)%.1f - [%.1f]", compac->cgminer_id, compac->drv->name, compac->device_id, info->eff_1m, info->eff_5m, info->eff_15, info->eff_wu, opt_gekko_tune_down); applog(LOG_WARNING,"%d: %s %d - low eff: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); @@ -827,7 +825,7 @@ static void *compac_handle_rx(void *object, int read_bytes) if (info->asic_type == BM1387 && (info->rx[2] == 0 || (info->rx[3] >> 4) == 0 || (info->rx[3] & 0x0f) == 0)) { dumpbuffer(compac, LOG_WARNING, "RX", info->rx, read_bytes); - applog(LOG_WARNING,"%d: %s %d - bad frequency", compac->cgminer_id, compac->drv->name, compac->device_id); + applog(LOG_WARNING,"%d: %s %d - invalid frequency report", compac->cgminer_id, compac->drv->name, compac->device_id); } else { if (info->asic_type == BM1387) { frequency = 25.0 * info->rx[1] / (info->rx[2] * (info->rx[3] >> 4) * (info->rx[3] & 0x0f)); @@ -1034,8 +1032,10 @@ static bool compac_init(struct thr_info *thr) info->fail_count = 0; info->busy_work = 0; info->nononce_reset = 0; - info->frequency_default = 200; info->frequency = 200; + info->frequency_default = 200; + info->frequency_fail_high = 0; + info->frequency_fail_low = 999; info->frequency_of = info->chips; info->scanhash_ms = 10; @@ -1064,7 +1064,7 @@ static bool compac_init(struct thr_info *thr) case IDENT_BSC: case IDENT_GSC: info->frequency_requested = opt_gekko_gsc_freq; - info->frequency_start = info->frequency_requested; + info->frequency_start = opt_gekko_start_freq; break; case IDENT_BSD: case IDENT_GSD: @@ -1221,6 +1221,14 @@ static int64_t compac_scanwork(struct thr_info *thr) break; case MINER_MINING_DUPS: info->mining_state = MINER_MINING; + applog(LOG_WARNING, "%d: %s %d - mining dup nonces", compac->cgminer_id, compac->drv->name, compac->device_id); + if (info->asic_type == BM1384) { + compac_set_frequency(compac, info->frequency); + compac_send_chain_inactive(compac); + } else { + info->mining_state = MINER_MINING; + } + /* Handled by per chip checks if ((int)info->frequency == 200) { //possible terminus reset condition. @@ -1408,7 +1416,7 @@ static bool compac_prepare(struct thr_info *thr) if ((*init_count) >= 15) { compac->deven = DEV_DISABLED; } else { - applog(LOG_WARNING, "%d: %s %d - forcing usb_nodev()", compac->cgminer_id, compac->drv->name, compac->device_id); + applog(LOG_INFO, "%d: %s %d - forcing usb_nodev()", compac->cgminer_id, compac->drv->name, compac->device_id); usb_nodev(compac); } } else if ((*init_count) > 1) { @@ -1437,7 +1445,9 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) memset(eff_stat, 0, 64); if (info->chips == 0) { - sprintf(asic_statline, "found 0 chip(s)"); + if ((*init_count) > 1) { + sprintf(asic_statline, "found 0 chip(s)"); + } for (i = strlen(asic_statline); i < stat_len; i++) asic_statline[i] = ' '; @@ -1539,7 +1549,7 @@ static void compac_shutdown(struct thr_info *thr) { struct cgpu_info *compac = thr->cgpu; struct COMPAC_INFO *info = compac->device_data; - applog(LOG_WARNING, "%d: %s %d - shutting down", compac->cgminer_id, compac->drv->name, compac->device_id); + applog(LOG_INFO, "%d: %s %d - shutting down", compac->cgminer_id, compac->drv->name, compac->device_id); if (!compac->usbinfo.nodev) { if (info->asic_type == BM1387) { compac_micro_send(compac, M2_SET_VCORE, 0x00, 0x00); // 300mV diff --git a/driver-gekko.h b/driver-gekko.h index 8138b99265..3f557fa999 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -82,10 +82,12 @@ struct COMPAC_INFO { pthread_mutex_t wlock; // Mutex Serialize Writes pthread_mutex_t rlock; // Mutex Serialize Reads - float frequency; // Chip Frequency + float frequency; // Chip Average Frequency + float frequency_default; // ASIC Frequency on RESET float frequency_requested; // Requested Frequency float frequency_start; // Starting Frequency - float frequency_default; // ASIC Frequency on RESET + float frequency_fail_high; // Highest Frequency of Chip Failure + float frequency_fail_low; // Lowest Frequency of Chip Failure float healthy; // Lower percentile before tagging asic unhealthy float eff_gs; float eff_tm; From 0efd17cc3e98b7f4c5db3af7ea366c090a30c45d Mon Sep 17 00:00:00 2001 From: vthoang Date: Wed, 10 Apr 2019 16:21:43 +0100 Subject: [PATCH 098/113] limit tune down to once per hour, give it a little time to think it over --- driver-gekko.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-gekko.c b/driver-gekko.c index de0814aa99..921fe2cc71 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -677,7 +677,7 @@ static void *compac_mine(void *object) } } - if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10 && ms_tdiff(&now, &info->last_wu_increase) > MS_MINUTE_30 && ms_tdiff(&now, &info->last_pool_lost) > MS_MINUTE_10) { + if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_HOUR_1 && ms_tdiff(&now, &info->last_wu_increase) > MS_MINUTE_30 && ms_tdiff(&now, &info->last_pool_lost) > MS_MINUTE_10) { float new_frequency = info->frequency - 6.25; applog(LOG_WARNING,"%d: %s %d - low eff: (1m)%.1f (5m)%.1f (15m)%.1f (WU)%.1f - [%.1f]", compac->cgminer_id, compac->drv->name, compac->device_id, info->eff_1m, info->eff_5m, info->eff_15, info->eff_wu, opt_gekko_tune_down); applog(LOG_WARNING,"%d: %s %d - low eff: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); From bcab82b9c6dcad7e7ab24b4554ac4380a7b57b45 Mon Sep 17 00:00:00 2001 From: vthoang Date: Thu, 11 Apr 2019 07:14:13 +0100 Subject: [PATCH 099/113] use high hashrate to set lower frequency boundary --- driver-gekko.c | 81 ++++++++++++++++++++++++++++++++++---------------- driver-gekko.h | 10 +++++-- 2 files changed, 63 insertions(+), 28 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index 921fe2cc71..9a9abe7466 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -419,6 +419,10 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) applog(LOG_INFO, "%d: %s %d - Duplicate Nonce : %08x @ %02x [%02x %02x %02x %02x %02x %02x %02x]", compac->cgminer_id, compac->drv->name, compac->device_id, nonce, job_id, info->rx[0], info->rx[1], info->rx[2], info->rx[3], info->rx[4], info->rx[5], info->rx[6]); info->dups++; + int asic_id = floor(info->rx[0] / (0x100 / info->chips)); + struct ASIC_INFO *asic = &info->asics[asic_id]; + asic->dups++; + if (info->dups == 1) { info->mining_state = MINER_MINING_DUPS; } @@ -588,6 +592,7 @@ static void *compac_mine(void *object) } else if (info->update_work || (ms_tdiff(&now, &info->last_task) > max_task_wait)) { uint64_t hashrate_15, hashrate_5m, hashrate_1m, hashrate_li, hashrate_tm; double dev_runtime, wu; + float frequency_computed; bool low_eff = 0; info->update_work = 0; @@ -623,6 +628,11 @@ static void *compac_mine(void *object) info->eff_wu = (info->eff_wu > 100) ? 100 : info->eff_wu; info->eff_tm = (info->eff_tm > 100) ? 100 : info->eff_tm; + frequency_computed = ((hashrate_5m / 1000000.0) / info->cores) / info->chips; + if (frequency_computed > info->frequency_computed && frequency_computed < 900) { + info->frequency_computed = frequency_computed; + } + info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; if (info->eff_5m > 10.0 && info->eff_15 < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { @@ -632,7 +642,7 @@ static void *compac_mine(void *object) if (ms_tdiff(&now, &info->monitor_time) > MS_SECOND_5 && ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_5) { for (i = 0; i < info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i]; - if (ms_tdiff(&now, &asic->last_nonce) > MS_SECOND_30) { + if (ms_tdiff(&now, &asic->last_nonce) > asic->fullscan_ms * 60 * info->chips || asic->dups > 3) { float new_frequency = info->frequency_requested; if (info->nononce_reset < 3) { @@ -643,29 +653,36 @@ static void *compac_mine(void *object) if ((info->frequency - 6.25) < info->frequency_fail_low) { info->frequency_fail_low = (info->frequency - 6.25); } - applog(LOG_WARNING,"%d: %s %d - no nonce: (%d/3) %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->nononce_reset + 1, info->frequency_fail_high); + applog(LOG_WARNING,"%d: %s %d - asic plateau: (%d/3) %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->nononce_reset + 1, info->frequency_fail_high); } else { - if (info->frequency_requested > info->frequency) { + if (info->frequency_fail_high > info->frequency) { if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_30) { // Been running for 30 minutes, possible plateau // Move requested frequency closer to plateau value - new_frequency = info->frequency; - } else { - // Set to current highest detected fail frequency - new_frequency = info->frequency_fail_high; + info->frequency_fail_high = info->frequency; } } else { - if (ms_tdiff(&now, &info->last_frequency_adjust) < MS_MINUTE_30) { + if (ms_tdiff(&now, &asic->state_change_time) < MS_MINUTE_30) { // Step back frequency - new_frequency = info->frequency - 6.25; + info->frequency_fail_high -= 6.25; } } + if (info->frequency_fail_high < info->frequency_computed) { + info->frequency_fail_high = info->frequency_computed; + } + new_frequency = info->frequency_fail_high; + new_frequency = ceil(100 * (new_frequency) / 625.0) * 6.25; } asic->last_state = asic->state; asic->state = ASIC_HALFDEAD; cgtime(&asic->state_change_time); cgtime(&info->monitor_time); - applog(LOG_INFO,"%d: %s %d - missing nonces from chip[%d]", compac->cgminer_id, compac->drv->name, compac->device_id, i); + if (asic->dups > 3) { + applog(LOG_WARNING,"%d: %s %d - duplicate nonces from chip[%d]", compac->cgminer_id, compac->drv->name, compac->device_id, i); + asic->dups = 0; + } else { + applog(LOG_WARNING,"%d: %s %d - missing nonces from chip[%d]", compac->cgminer_id, compac->drv->name, compac->device_id, i); + } if (new_frequency != info->frequency_requested) { applog(LOG_WARNING,"%d: %s %d - no nonce: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); info->frequency_requested = new_frequency; @@ -679,16 +696,30 @@ static void *compac_mine(void *object) if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_HOUR_1 && ms_tdiff(&now, &info->last_wu_increase) > MS_MINUTE_30 && ms_tdiff(&now, &info->last_pool_lost) > MS_MINUTE_10) { float new_frequency = info->frequency - 6.25; + if (new_frequency < info->frequency_computed) { + new_frequency = info->frequency_computed; + } + new_frequency = ceil(100 * (new_frequency) / 625.0) * 6.25; + + cgtime(&info->last_frequency_adjust); + cgtime(&info->monitor_time); + applog(LOG_WARNING,"%d: %s %d - low eff: (1m)%.1f (5m)%.1f (15m)%.1f (WU)%.1f - [%.1f]", compac->cgminer_id, compac->drv->name, compac->device_id, info->eff_1m, info->eff_5m, info->eff_15, info->eff_wu, opt_gekko_tune_down); + + if (new_frequency == info->frequency) { + info->mining_state = MINER_RESET; + continue; + } + applog(LOG_WARNING,"%d: %s %d - low eff: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); info->frequency_requested = new_frequency; + info->frequency_fail_high = new_frequency; + for (i = 0; i < info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i]; - asic->frequency_requested = new_frequency; + asic->frequency_requested = info->frequency_requested; } - cgtime(&info->last_frequency_adjust); - cgtime(&info->monitor_time); } if (ms_tdiff(&now, &info->last_frequency_ping) > MS_SECOND_5 || (info->frequency_of != info->chips && ms_tdiff(&now, &info->last_frequency_ping) > 50)) { @@ -835,6 +866,7 @@ static void *compac_handle_rx(void *object, int read_bytes) if (info->frequency_of != info->chips) { asic = &info->asics[info->frequency_of]; + cgtime(&asic->last_frequency_reply); if (frequency != asic->frequency) { if (frequency < asic->frequency && frequency != asic->frequency_requested) { applog(LOG_INFO,"%d: %s %d - chip[%d] reported frequency at %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_of, frequency); @@ -1221,13 +1253,12 @@ static int64_t compac_scanwork(struct thr_info *thr) break; case MINER_MINING_DUPS: info->mining_state = MINER_MINING; - applog(LOG_WARNING, "%d: %s %d - mining dup nonces", compac->cgminer_id, compac->drv->name, compac->device_id); - if (info->asic_type == BM1384) { - compac_set_frequency(compac, info->frequency); - compac_send_chain_inactive(compac); - } else { - info->mining_state = MINER_MINING; - } + //applog(LOG_WARNING, "%d: %s %d - mining dup nonces", compac->cgminer_id, compac->drv->name, compac->device_id); + //if (ms_tdiff(&now, &info->last_dup_fix) > MS_SECOND_5) { + // applog(LOG_WARNING, "%d: %s %d - readdressing asics", compac->cgminer_id, compac->drv->name, compac->device_id); + // compac_send_chain_inactive(compac); + // cgtime(&info->last_dup_fix); + //} /* Handled by per chip checks if ((int)info->frequency == 200) { @@ -1506,19 +1537,19 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) if (info->asic_type == BM1387) { if (info->micro_found) { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz (%d/%d/%d/%.0fF)", info->chips, ab, info->frequency, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz P:%.2fMHz (%d/%d/%d/%.0fF)", info->chips, ab, info->frequency, info->frequency_computed, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); } else { if (opt_log_output) { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz %s%-13s", info->chips, ab, info->frequency, asic_stat, ms_stat); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz %s%-13s", info->chips, ab, info->frequency, info->frequency_computed, asic_stat, ms_stat); } else { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz %s%s", info->chips, ab, info->frequency, asic_stat, eff_stat); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz P:%.2fMHz %s%s", info->chips, ab, info->frequency, info->frequency_computed, asic_stat, eff_stat); } } } else { if (opt_log_output) { - sprintf(asic_statline, "BM1384:%02d %.2fMHz %s%-13s", info->chips, info->frequency, asic_stat, ms_stat); + sprintf(asic_statline, "BM1384:%02d %.2fMHz P:%.2fMHz %s%-13s", info->chips, info->frequency, info->frequency_computed, asic_stat, ms_stat); } else { - sprintf(asic_statline, "BM1384:%02d %.2fMHz %s%s", info->chips, info->frequency, asic_stat, eff_stat); + sprintf(asic_statline, "BM1384:%02d %.2fMHz P:%.2fMHz %s%s", info->chips, info->frequency, info->frequency_computed, asic_stat, eff_stat); } } diff --git a/driver-gekko.h b/driver-gekko.h index 3f557fa999..152c18cf8a 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -58,12 +58,14 @@ enum asic_state { }; struct ASIC_INFO { - struct timeval last_nonce; // Last time nonce was found + struct timeval last_nonce; // Last time nonce was found float frequency; - float frequency_requested; // Requested Frequency + float frequency_requested; // Requested Frequency + int dups; // Duplicate nonce counter enum asic_state state; enum asic_state last_state; - struct timeval state_change_time; // Device startup time + struct timeval state_change_time; // Device startup time + struct timeval last_frequency_reply; // Last time of frequency reply uint32_t fullscan_ms; // Estimated time(ms) for full nonce range uint64_t hashrate; // Estimated hashrate = cores x chips x frequency @@ -88,6 +90,7 @@ struct COMPAC_INFO { float frequency_start; // Starting Frequency float frequency_fail_high; // Highest Frequency of Chip Failure float frequency_fail_low; // Lowest Frequency of Chip Failure + float frequency_computed; // Highest hashrate seen as a frequency value float healthy; // Lower percentile before tagging asic unhealthy float eff_gs; float eff_tm; @@ -147,6 +150,7 @@ struct COMPAC_INFO { struct timeval start_time; // Device startup time struct timeval monitor_time; // Health check reference point struct timeval last_scanhash; // Last time inside scanhash loop + struct timeval last_dup_fix; // Last time nonce dup fix was attempted struct timeval last_reset; // Last time reset was triggered struct timeval last_task; // Last time work was sent struct timeval last_nonce; // Last time nonce was found From 6f287348bf4dc94bfa44f675c5352ddb3258d116 Mon Sep 17 00:00:00 2001 From: vthoang Date: Thu, 11 Apr 2019 08:03:12 +0100 Subject: [PATCH 100/113] added computed peak to display, allow fast ramp while less than peak --- driver-gekko.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index 9a9abe7466..f20912bcfd 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -726,7 +726,7 @@ static void *compac_mine(void *object) info->frequency_of--; - if (info->frequency_of == (info->chips - 1) && info->eff_gs >= opt_gekko_tune_up) + if (info->frequency_of == (info->chips - 1) && (info->eff_gs >= opt_gekko_tune_up || info->frequency < info->frequency_computed)) adjustable = 1; if (info->frequency_of < 0) { @@ -1537,19 +1537,19 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) if (info->asic_type == BM1387) { if (info->micro_found) { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz P:%.2fMHz (%d/%d/%d/%.0fF)", info->chips, ab, info->frequency, info->frequency_computed, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.2fMHz P:%.2fMHz (%d/%d/%d/%.0fF)", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); } else { if (opt_log_output) { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz %s%-13s", info->chips, ab, info->frequency, info->frequency_computed, asic_stat, ms_stat); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.2fMHz P:%.2fMHz %s%-13s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, ms_stat); } else { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz P:%.2fMHz %s%s", info->chips, ab, info->frequency, info->frequency_computed, asic_stat, eff_stat); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.2fMHz P:%.2fMHz %s%s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, eff_stat); } } } else { if (opt_log_output) { - sprintf(asic_statline, "BM1384:%02d %.2fMHz P:%.2fMHz %s%-13s", info->chips, info->frequency, info->frequency_computed, asic_stat, ms_stat); + sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%.2fMHz P:%.2fMHz %s%-13s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, ms_stat); } else { - sprintf(asic_statline, "BM1384:%02d %.2fMHz P:%.2fMHz %s%s", info->chips, info->frequency, info->frequency_computed, asic_stat, eff_stat); + sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%.2fMHz P:%.2fMHz %s%s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, eff_stat); } } From 78116c7f707acf00e70a73beb9b3a95ac35c4843 Mon Sep 17 00:00:00 2001 From: vthoang Date: Sat, 13 Apr 2019 13:49:14 +0100 Subject: [PATCH 101/113] increase potential rate for frequency increase. really fast return to computed peak on resets --- driver-gekko.c | 91 ++++++++++++++++++++++++++++++-------------------- driver-gekko.h | 1 + 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index f20912bcfd..0c64bb51a9 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -279,12 +279,8 @@ static void compac_set_frequency(struct cgpu_info *compac, float frequency) } */ - //applog(LOG_WARNING, "%d: %s %d - setting frequency to %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, frequency); - //compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); - - for (i = 0; i < info->chips; i++) { - compac_set_frequency_single(compac, frequency, i); - } + applog(LOG_INFO, "%d: %s %d - setting frequency to %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, frequency); + compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); info->frequency = frequency; info->last_frequency_ping = (struct timeval){0}; @@ -562,7 +558,7 @@ static void *compac_mine(void *object) struct timeval now; struct timeval last_frequency_report; struct sched_param param; - int i, read_bytes, sleep_ms, policy, ret_nice, ping_itr; + int i, j, read_bytes, sleep_ms, policy, ret_nice, ping_itr; uint32_t err = 0; uint64_t hashes = 0; uint64_t max_task_wait = 0; @@ -581,7 +577,7 @@ static void *compac_mine(void *object) #endif /* WIN32 */ applog(LOG_INFO, "%d: %s %d - work thread niceness (%d)", compac->cgminer_id, compac->drv->name, compac->device_id, ret_nice); - max_task_wait = bound(wait_factor * info->fullscan_ms, 1, 3 * info->fullscan_ms); + max_task_wait = bound(wait_factor * info->fullscan_ms, 0, 3 * info->fullscan_ms); sleep_ms = bound(ceil(max_task_wait/8.0), 1, 200); while (info->mining_state != MINER_SHUTDOWN) { @@ -628,12 +624,20 @@ static void *compac_mine(void *object) info->eff_wu = (info->eff_wu > 100) ? 100 : info->eff_wu; info->eff_tm = (info->eff_tm > 100) ? 100 : info->eff_tm; - frequency_computed = ((hashrate_5m / 1000000.0) / info->cores) / info->chips; + info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; + + frequency_computed = info->eff_gs / 100.0 * info->frequency; if (frequency_computed > info->frequency_computed && frequency_computed < 900) { info->frequency_computed = frequency_computed; } - info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; + //frequency_computed = ((hashrate_5m / 1000000.0) / info->cores) / info->chips; + //if (frequency_computed > info->frequency) { + // frequency_computed = info->frequency; + //} + //if (frequency_computed > info->frequency_computed && frequency_computed < 900) { + // info->frequency_computed = frequency_computed; + //} if (info->eff_5m > 10.0 && info->eff_15 < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { low_eff = 1; @@ -642,8 +646,19 @@ static void *compac_mine(void *object) if (ms_tdiff(&now, &info->monitor_time) > MS_SECOND_5 && ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_5) { for (i = 0; i < info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i]; + float old_frequency, new_frequency; if (ms_tdiff(&now, &asic->last_nonce) > asic->fullscan_ms * 60 * info->chips || asic->dups > 3) { - float new_frequency = info->frequency_requested; + new_frequency = info->frequency_requested; + + char freq_buf[512]; + char freq_chip_buf[10]; + memset(freq_buf, 0, 512); + for (j = 0; j < info->chips; j++) { + struct ASIC_INFO *asjc = &info->asics[j]; + sprintf(freq_chip_buf, "[%d:%.2f]", j, asjc->frequency); + strcat(freq_buf, freq_chip_buf); + } + applog(LOG_INFO,"%d: %s %d - %s", compac->cgminer_id, compac->drv->name, compac->device_id, freq_buf); if (info->nononce_reset < 3) { // Capture failure high/low frequencies using first three resets @@ -654,18 +669,15 @@ static void *compac_mine(void *object) info->frequency_fail_low = (info->frequency - 6.25); } applog(LOG_WARNING,"%d: %s %d - asic plateau: (%d/3) %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->nononce_reset + 1, info->frequency_fail_high); - } else { - if (info->frequency_fail_high > info->frequency) { - if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_30) { - // Been running for 30 minutes, possible plateau - // Move requested frequency closer to plateau value - info->frequency_fail_high = info->frequency; - } + } + + if (info->nononce_reset >= 2) { + if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_30) { + // Been running for 30 minutes, possible plateau + // Overlook the incident } else { - if (ms_tdiff(&now, &asic->state_change_time) < MS_MINUTE_30) { - // Step back frequency - info->frequency_fail_high -= 6.25; - } + // Step back frequency + info->frequency_fail_high -= 6.25; } if (info->frequency_fail_high < info->frequency_computed) { info->frequency_fail_high = info->frequency_computed; @@ -673,28 +685,37 @@ static void *compac_mine(void *object) new_frequency = info->frequency_fail_high; new_frequency = ceil(100 * (new_frequency) / 625.0) * 6.25; } + info->nononce_reset++; asic->last_state = asic->state; asic->state = ASIC_HALFDEAD; cgtime(&asic->state_change_time); cgtime(&info->monitor_time); + if (asic->dups > 3) { - applog(LOG_WARNING,"%d: %s %d - duplicate nonces from chip[%d]", compac->cgminer_id, compac->drv->name, compac->device_id, i); + applog(LOG_INFO,"%d: %s %d - duplicate nonces from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); asic->dups = 0; } else { - applog(LOG_WARNING,"%d: %s %d - missing nonces from chip[%d]", compac->cgminer_id, compac->drv->name, compac->device_id, i); + applog(LOG_INFO,"%d: %s %d - missing nonces from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); } - if (new_frequency != info->frequency_requested) { - applog(LOG_WARNING,"%d: %s %d - no nonce: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); + + old_frequency = info->frequency_requested; + if (new_frequency != old_frequency) { info->frequency_requested = new_frequency; + for (i = 0; i < info->chips; i++) + { + struct ASIC_INFO *asjc = &info->asics[i]; + asjc->frequency_requested = info->frequency_requested; + } + applog(LOG_WARNING,"%d: %s %d - plateau: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, old_frequency, new_frequency); } - info->nononce_reset++; + info->mining_state = MINER_RESET; break; } } } - if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_HOUR_1 && ms_tdiff(&now, &info->last_wu_increase) > MS_MINUTE_30 && ms_tdiff(&now, &info->last_pool_lost) > MS_MINUTE_10) { + if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_HOUR_1) { float new_frequency = info->frequency - 6.25; if (new_frequency < info->frequency_computed) { new_frequency = info->frequency_computed; @@ -722,7 +743,7 @@ static void *compac_mine(void *object) } } - if (ms_tdiff(&now, &info->last_frequency_ping) > MS_SECOND_5 || (info->frequency_of != info->chips && ms_tdiff(&now, &info->last_frequency_ping) > 50)) { + if (ms_tdiff(&now, &info->last_frequency_ping) > MS_SECOND_1 / 2 || (info->frequency_of != info->chips && ms_tdiff(&now, &info->last_frequency_ping) > 20)) { info->frequency_of--; @@ -731,11 +752,11 @@ static void *compac_mine(void *object) if (info->frequency_of < 0) { info->frequency_of = info->chips; - ping_itr = (ping_itr + 1) % 2; + ping_itr = (ping_itr + 1) % 1; adjustable = 0; } else { struct ASIC_INFO *asic = &info->asics[info->frequency_of]; - if (ping_itr == 1 && asic->frequency != asic->frequency_requested) { + if (ping_itr == 0 && asic->frequency != asic->frequency_requested) { float new_frequency; if (asic->frequency < asic->frequency_requested) { new_frequency = asic->frequency + opt_gekko_step_freq; @@ -747,8 +768,6 @@ static void *compac_mine(void *object) } if (!adjustable) { new_frequency = asic->frequency; - if (info->frequency_of == info->chips) - applog(LOG_INFO,"%d: %s %d - pending frequency change - waiting for hashrate to catch up", compac->cgminer_id, compac->drv->name, compac->device_id); } } else { new_frequency = asic->frequency_requested; @@ -855,8 +874,8 @@ static void *compac_handle_rx(void *object, int read_bytes) cgtime(&info->last_frequency_report); if (info->asic_type == BM1387 && (info->rx[2] == 0 || (info->rx[3] >> 4) == 0 || (info->rx[3] & 0x0f) == 0)) { - dumpbuffer(compac, LOG_WARNING, "RX", info->rx, read_bytes); - applog(LOG_WARNING,"%d: %s %d - invalid frequency report", compac->cgminer_id, compac->drv->name, compac->device_id); + dumpbuffer(compac, LOG_INFO, "RX", info->rx, read_bytes); + applog(LOG_INFO,"%d: %s %d - invalid frequency report", compac->cgminer_id, compac->drv->name, compac->device_id); } else { if (info->asic_type == BM1387) { frequency = 25.0 * info->rx[1] / (info->rx[2] * (info->rx[3] >> 4) * (info->rx[3] & 0x0f)); @@ -1196,7 +1215,7 @@ static int64_t compac_scanwork(struct thr_info *thr) break; case MINER_CHIP_COUNT_OK: cgsleep_ms(50); - //x//compac_set_frequency(compac, info->frequency_start); + //compac_set_frequency(compac, info->frequency_start); compac_send_chain_inactive(compac); return 0; break; diff --git a/driver-gekko.h b/driver-gekko.h index 152c18cf8a..b7322e1f1a 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -155,6 +155,7 @@ struct COMPAC_INFO { struct timeval last_task; // Last time work was sent struct timeval last_nonce; // Last time nonce was found struct timeval last_hwerror; // Last time hw error was detected + struct timeval last_fast_forward; // Last time of ramp jump to peak struct timeval last_frequency_adjust; // Last time of frequency adjust struct timeval last_frequency_ping; // Last time of frequency poll struct timeval last_frequency_report; // Last change of frequency report From 5e485cee2e1ebf2eb8a1db47f0d44d575cabac9e Mon Sep 17 00:00:00 2001 From: vthoang Date: Wed, 17 Apr 2019 03:23:15 +0100 Subject: [PATCH 102/113] update fallback to peak condition. start using microseconds. --- driver-gekko.c | 208 +++++++++++++++++++++++-------------------------- driver-gekko.h | 11 ++- 2 files changed, 108 insertions(+), 111 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index 0c64bb51a9..2ffb527bf9 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -133,7 +133,7 @@ static void compac_send(struct cgpu_info *compac, unsigned char *req_tx, uint32_ } info->cmd[bytes - 1] |= bmcrc(req_tx, crc_bits); - cgsleep_ms(1); + usleep(100); int log_level = (bytes < info->task_len) ? LOG_INFO : LOG_INFO; @@ -150,12 +150,15 @@ static void compac_send_chain_inactive(struct cgpu_info *compac) if (info->asic_type == BM1387) { unsigned char buffer[5] = {0x55, 0x05, 0x00, 0x00, 0x00}; compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8);; // chain inactive + cgsleep_ms(5); compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8);; // chain inactive + cgsleep_ms(5); compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8);; // chain inactive for (i = 0; i < info->chips; i++) { buffer[0] = 0x41; buffer[1] = 0x05; buffer[2] = (0x100 / info->chips) * i; + cgsleep_ms(5); compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8);; } @@ -204,6 +207,7 @@ static void compac_update_rates(struct cgpu_info *compac) asic = &info->asics[i]; asic->hashrate = asic->frequency * info->cores * 1000000; asic->fullscan_ms = 1000.0 * 0xffffffffull / asic->hashrate; + asic->fullscan_us = 1000.0 * 1000.0 * 0xffffffffull / asic->hashrate; average_frequency += asic->frequency; } @@ -216,11 +220,16 @@ static void compac_update_rates(struct cgpu_info *compac) info->hashrate = info->chips * info->frequency * info->cores * 1000000; info->fullscan_ms = 1000.0 * 0xffffffffull / info->hashrate; + info->fullscan_us = 1000.0 * 1000.0 * 0xffffffffull / info->hashrate; info->scanhash_ms = bound(info->fullscan_ms / 2, 1, 100); info->ticket_mask = bound(pow(2, ceil(log(info->hashrate / (2.0 * 0xffffffffull)) / log(2))) - 1, 0, 4000); info->ticket_mask = (info->asic_type == BM1387) ? 0 : info->ticket_mask; info->difficulty = info->ticket_mask + 1; info->wu = 0.0139091 * info->cores * info->chips * info->frequency; + + info->wait_factor = ((!opt_gekko_noboost && info->vmask && info->asic_type == BM1387) ? 1.80 : 0.60); + info->max_task_wait = bound(info->wait_factor * info->fullscan_us, 1, 3 * info->fullscan_us); + } static void compac_set_frequency_single(struct cgpu_info *compac, float frequency, int asic_id) @@ -411,24 +420,25 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) info->nonces++; info->nonceless = 0; - if (nonce == info->prev_nonce) { + + int asic_id = floor(info->rx[0] / (0x100 / info->chips)); + struct ASIC_INFO *asic = &info->asics[asic_id]; + + if (nonce == asic->prev_nonce) { applog(LOG_INFO, "%d: %s %d - Duplicate Nonce : %08x @ %02x [%02x %02x %02x %02x %02x %02x %02x]", compac->cgminer_id, compac->drv->name, compac->device_id, nonce, job_id, info->rx[0], info->rx[1], info->rx[2], info->rx[3], info->rx[4], info->rx[5], info->rx[6]); info->dups++; - int asic_id = floor(info->rx[0] / (0x100 / info->chips)); - struct ASIC_INFO *asic = &info->asics[asic_id]; asic->dups++; - + cgtime(&info->last_dup_time); if (info->dups == 1) { info->mining_state = MINER_MINING_DUPS; } return hashes; - } else { - info->dups = 0; } hashes = info->difficulty * 0xffffffffull; info->prev_nonce = nonce; + asic->prev_nonce = nonce; applog(LOG_INFO, "%d: %s %d - Device reported nonce: %08x @ %02x", compac->cgminer_id, compac->drv->name, compac->device_id, nonce, job_id); @@ -467,10 +477,8 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) work->device_diff = info->difficulty; if (submit_nonce(info->thr, work, nonce)) { - int asic_id = floor(info->rx[0] / (0x100 / info->chips)); - struct ASIC_INFO *asic = &info->asics[asic_id]; - cgtime(&asic->last_nonce); cgtime(&info->last_nonce); + cgtime(&asic->last_nonce); if (midnum > 0) { applog(LOG_INFO, "%d: %s %d - AsicBoost nonce found : midstate%d", compac->cgminer_id, compac->drv->name, compac->device_id, midnum); @@ -478,6 +486,8 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) info->accepted++; info->failing = false; + info->dups = 0; + asic->dups = 0; } else { if (hwe != compac->hw_errors) { cgtime(&info->last_hwerror); @@ -557,13 +567,13 @@ static void *compac_mine(void *object) struct timeval now; struct timeval last_frequency_report; + struct timeval last_eff_calculations = (struct timeval){0}; + struct sched_param param; - int i, j, read_bytes, sleep_ms, policy, ret_nice, ping_itr; + int i, j, read_bytes, sleep_us, policy, ret_nice, ping_itr; uint32_t err = 0; uint64_t hashes = 0; - uint64_t max_task_wait = 0; char str_frequency[1024]; - float wait_factor = ((!opt_gekko_noboost && info->vmask && info->asic_type == BM1387) ? 2.25 : 0.75); bool adjustable = 0; @@ -577,15 +587,14 @@ static void *compac_mine(void *object) #endif /* WIN32 */ applog(LOG_INFO, "%d: %s %d - work thread niceness (%d)", compac->cgminer_id, compac->drv->name, compac->device_id, ret_nice); - max_task_wait = bound(wait_factor * info->fullscan_ms, 0, 3 * info->fullscan_ms); - sleep_ms = bound(ceil(max_task_wait/8.0), 1, 200); + sleep_us = 100; while (info->mining_state != MINER_SHUTDOWN) { cgtime(&now); if (info->chips == 0 || compac->deven == DEV_DISABLED || compac->usbinfo.nodev || info->mining_state != MINER_MINING) { cgsleep_ms(10); - } else if (info->update_work || (ms_tdiff(&now, &info->last_task) > max_task_wait)) { + } else if (info->update_work || (us_tdiff(&now, &info->last_task) > info->max_task_wait)) { uint64_t hashrate_15, hashrate_5m, hashrate_1m, hashrate_li, hashrate_tm; double dev_runtime, wu; float frequency_computed; @@ -593,56 +602,54 @@ static void *compac_mine(void *object) info->update_work = 0; - max_task_wait = bound(wait_factor * info->fullscan_ms, 1, 3 * info->fullscan_ms); - sleep_ms = bound(ceil(max_task_wait/100.0), 1, 200); + sleep_us = bound(ceil(info->max_task_wait/10.0), 1, (info->max_task_wait / 2)); - dev_runtime = cgpu_runtime(compac); - wu = compac->diff1 / dev_runtime * 60; + if (ms_tdiff(&now, &last_eff_calculations) > MS_SECOND_1) { + // throttle everthing except work to once per second - if (wu > info->wu_max) { - info->wu_max = wu; - cgtime(&info->last_wu_increase); - } + dev_runtime = cgpu_runtime(compac); + wu = compac->diff1 / dev_runtime * 60; - hashrate_li = (double)compac->rolling * 1000000ull; - hashrate_1m = (double)compac->rolling1 * 1000000ull; - hashrate_5m = (double)compac->rolling5 * 1000000ull; - hashrate_15 = (double)compac->rolling15 * 1000000ull; - hashrate_tm = (double)compac->total_mhashes / dev_runtime * 1000000ull;; - - info->eff_li = 100.0 * (1.0 * hashrate_li / info->hashrate); - info->eff_1m = 100.0 * (1.0 * hashrate_1m / info->hashrate); - info->eff_5m = 100.0 * (1.0 * hashrate_5m / info->hashrate); - info->eff_15 = 100.0 * (1.0 * hashrate_15 / info->hashrate); - info->eff_wu = 100.0 * (1.0 * wu / info->wu); - info->eff_tm = 100.0 * (1.0 * hashrate_tm / info->hashrate); - - info->eff_li = (info->eff_li > 100) ? 100 : info->eff_li; - info->eff_1m = (info->eff_1m > 100) ? 100 : info->eff_1m; - info->eff_5m = (info->eff_5m > 100) ? 100 : info->eff_5m; - info->eff_15 = (info->eff_15 > 100) ? 100 : info->eff_15; - info->eff_wu = (info->eff_wu > 100) ? 100 : info->eff_wu; - info->eff_tm = (info->eff_tm > 100) ? 100 : info->eff_tm; - - info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; - - frequency_computed = info->eff_gs / 100.0 * info->frequency; - if (frequency_computed > info->frequency_computed && frequency_computed < 900) { - info->frequency_computed = frequency_computed; - } - - //frequency_computed = ((hashrate_5m / 1000000.0) / info->cores) / info->chips; - //if (frequency_computed > info->frequency) { - // frequency_computed = info->frequency; - //} - //if (frequency_computed > info->frequency_computed && frequency_computed < 900) { - // info->frequency_computed = frequency_computed; - //} + if (wu > info->wu_max) { + info->wu_max = wu; + cgtime(&info->last_wu_increase); + } - if (info->eff_5m > 10.0 && info->eff_15 < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { - low_eff = 1; + hashrate_li = (double)compac->rolling * 1000000ull; + hashrate_1m = (double)compac->rolling1 * 1000000ull; + hashrate_5m = (double)compac->rolling5 * 1000000ull; + hashrate_15 = (double)compac->rolling15 * 1000000ull; + hashrate_tm = (double)compac->total_mhashes / dev_runtime * 1000000ull;; + + info->eff_li = 100.0 * (1.0 * hashrate_li / info->hashrate); + info->eff_1m = 100.0 * (1.0 * hashrate_1m / info->hashrate); + info->eff_5m = 100.0 * (1.0 * hashrate_5m / info->hashrate); + info->eff_15 = 100.0 * (1.0 * hashrate_15 / info->hashrate); + info->eff_wu = 100.0 * (1.0 * wu / info->wu); + info->eff_tm = 100.0 * (1.0 * hashrate_tm / info->hashrate); + + info->eff_li = (info->eff_li > 100) ? 100 : info->eff_li; + info->eff_1m = (info->eff_1m > 100) ? 100 : info->eff_1m; + info->eff_5m = (info->eff_5m > 100) ? 100 : info->eff_5m; + info->eff_15 = (info->eff_15 > 100) ? 100 : info->eff_15; + info->eff_wu = (info->eff_wu > 100) ? 100 : info->eff_wu; + info->eff_tm = (info->eff_tm > 100) ? 100 : info->eff_tm; + + info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; + + //frequency_computed = ((hashrate_5m / 1000000.0) / info->cores) / info->chips; + frequency_computed = info->eff_gs / 100.0 * info->frequency; + if (frequency_computed > info->frequency_computed && frequency_computed < 900) { + info->frequency_computed = frequency_computed; + cgtime(&info->last_computed_increase); + } + if (info->eff_5m > 10.0 && info->eff_1m < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { + low_eff = 1; + } + cgtime(&last_eff_calculations); } + if (ms_tdiff(&now, &info->monitor_time) > MS_SECOND_5 && ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_5) { for (i = 0; i < info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i]; @@ -706,7 +713,7 @@ static void *compac_mine(void *object) struct ASIC_INFO *asjc = &info->asics[i]; asjc->frequency_requested = info->frequency_requested; } - applog(LOG_WARNING,"%d: %s %d - plateau: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, old_frequency, new_frequency); + applog(LOG_WARNING,"%d: %s %d - plateau adjust: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, old_frequency, new_frequency); } info->mining_state = MINER_RESET; @@ -715,47 +722,51 @@ static void *compac_mine(void *object) } } - if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_HOUR_1) { + if (ms_tdiff(&now, &info->last_computed_increase) > MS_MINUTE_5 && info->frequency_computed < info->frequency ) { float new_frequency = info->frequency - 6.25; if (new_frequency < info->frequency_computed) { new_frequency = info->frequency_computed; } new_frequency = ceil(100 * (new_frequency) / 625.0) * 6.25; - cgtime(&info->last_frequency_adjust); - cgtime(&info->monitor_time); - +/* applog(LOG_WARNING,"%d: %s %d - low eff: (1m)%.1f (5m)%.1f (15m)%.1f (WU)%.1f - [%.1f]", compac->cgminer_id, compac->drv->name, compac->device_id, info->eff_1m, info->eff_5m, info->eff_15, info->eff_wu, opt_gekko_tune_down); if (new_frequency == info->frequency) { info->mining_state = MINER_RESET; continue; } - - applog(LOG_WARNING,"%d: %s %d - low eff: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); - info->frequency_requested = new_frequency; - info->frequency_fail_high = new_frequency; - - for (i = 0; i < info->chips; i++) - { - struct ASIC_INFO *asic = &info->asics[i]; - asic->frequency_requested = info->frequency_requested; +*/ + if (new_frequency != info->frequency) { + applog(LOG_WARNING,"%d: %s %d - peak adjust: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); + cgtime(&info->last_computed_increase); + info->frequency_requested = new_frequency; + info->frequency_fail_high = new_frequency; + + for (i = 0; i < info->chips; i++) + { + struct ASIC_INFO *asic = &info->asics[i]; + asic->frequency_requested = info->frequency_requested; + } } } - if (ms_tdiff(&now, &info->last_frequency_ping) > MS_SECOND_1 / 2 || (info->frequency_of != info->chips && ms_tdiff(&now, &info->last_frequency_ping) > 20)) { + if (ms_tdiff(&now, &info->last_frequency_ping) > MS_SECOND_1 || (info->frequency_of != info->chips && ms_tdiff(&now, &info->last_frequency_ping) > 10)) { info->frequency_of--; + struct ASIC_INFO *asic = &info->asics[info->frequency_of]; - if (info->frequency_of == (info->chips - 1) && (info->eff_gs >= opt_gekko_tune_up || info->frequency < info->frequency_computed)) + if (info->frequency_of == (info->chips - 1) && + (info->eff_gs >= opt_gekko_tune_up || asic->frequency < info->frequency_computed) && + ms_tdiff(&now, &info->last_dup_time) > MS_MINUTE_5) { adjustable = 1; + } if (info->frequency_of < 0) { info->frequency_of = info->chips; ping_itr = (ping_itr + 1) % 1; adjustable = 0; } else { - struct ASIC_INFO *asic = &info->asics[info->frequency_of]; if (ping_itr == 0 && asic->frequency != asic->frequency_requested) { float new_frequency; if (asic->frequency < asic->frequency_requested) { @@ -849,8 +860,9 @@ static void *compac_mine(void *object) info->task_ms = (info->task_ms * 9 + ms_tdiff(&now, &info->last_task)) / 10; cgtime(&info->last_task); + } else { + usleep(sleep_us); } - cgsleep_ms(sleep_ms); } } @@ -904,7 +916,6 @@ static void *compac_handle_rx(void *object, int read_bytes) info->frequency = frequency; } } - compac_update_rates(compac); } } @@ -1103,6 +1114,7 @@ static bool compac_init(struct thr_info *thr) cgtime(&info->last_write_error); cgtime(&info->last_frequency_adjust); + cgtime(&info->last_computed_increase); info->last_frequency_ping = (struct timeval){0}; cgtime(&info->last_micro_ping); cgtime(&info->last_scanhash); @@ -1246,6 +1258,7 @@ static int64_t compac_scanwork(struct thr_info *thr) cgtime(&info->monitor_time); cgtime(&info->last_frequency_adjust); info->last_frequency_ping = (struct timeval){0}; + info->last_dup_time = (struct timeval){0}; cgtime(&info->last_frequency_report); cgtime(&info->last_micro_ping); cgtime(&info->last_nonce); @@ -1261,7 +1274,7 @@ static int64_t compac_scanwork(struct thr_info *thr) compac_toggle_reset(compac); } else if (info->asic_type == BM1384) { compac_set_frequency(compac, info->frequency_default); - compac_send_chain_inactive(compac); + //compac_send_chain_inactive(compac); } compac_prepare(thr); @@ -1272,35 +1285,13 @@ static int64_t compac_scanwork(struct thr_info *thr) break; case MINER_MINING_DUPS: info->mining_state = MINER_MINING; - //applog(LOG_WARNING, "%d: %s %d - mining dup nonces", compac->cgminer_id, compac->drv->name, compac->device_id); - //if (ms_tdiff(&now, &info->last_dup_fix) > MS_SECOND_5) { - // applog(LOG_WARNING, "%d: %s %d - readdressing asics", compac->cgminer_id, compac->drv->name, compac->device_id); - // compac_send_chain_inactive(compac); - // cgtime(&info->last_dup_fix); - //} - - /* Handled by per chip checks - if ((int)info->frequency == 200) { - //possible terminus reset condition. - //compac_set_frequency(compac, info->frequency); - //compac_send_chain_inactive(compac); - //cgtime(&info->last_frequency_adjust); - } else { - //check for reset condition - //if (info->asic_type == BM1384) { - // unsigned char buffer[] = {0x84, 0x00, 0x04, 0x00}; - // compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); - //} - //cgtime(&info->last_frequency_ping); - } - */ break; default: break; } hashes = info->hashes; info->hashes -= hashes; - cgsleep_ms(info->scanhash_ms); + usleep(500); return hashes; } @@ -1553,22 +1544,21 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) sprintf(eff_stat, "| %5.1f%% WU:%c%2.0f%%", info->eff_gs, wuc, info->eff_wu); } - if (info->asic_type == BM1387) { if (info->micro_found) { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.2fMHz P:%.2fMHz (%d/%d/%d/%.0fF)", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.0f P:%.0f (%d/%d/%d/%.0fF)", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); } else { if (opt_log_output) { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.2fMHz P:%.2fMHz %s%-13s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, ms_stat); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.0f P:%.0f %s%s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, ms_stat); } else { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.2fMHz P:%.2fMHz %s%s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, eff_stat); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.0f P:%.0f %s %s%s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat, eff_stat); } } } else { if (opt_log_output) { - sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%.2fMHz P:%.2fMHz %s%-13s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, ms_stat); + sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%.0f P:%.0f %s%s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, ms_stat); } else { - sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%.2fMHz P:%.2fMHz %s%s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, eff_stat); + sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%.0f P:%.0f %s%s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, eff_stat); } } diff --git a/driver-gekko.h b/driver-gekko.h index b7322e1f1a..69e19599a0 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -8,6 +8,8 @@ #define MS_SECOND_5 1000 * 5 #define MS_SECOND_30 1000 * 30 #define MS_MINUTE_1 1000 * 60 +#define MS_MINUTE_2 1000 * 60 * 2 +#define MS_MINUTE_5 1000 * 60 * 5 #define MS_MINUTE_10 1000 * 60 * 10 #define MS_MINUTE_30 1000 * 60 * 30 #define MS_HOUR_1 1000 * 60 * 60 @@ -66,8 +68,9 @@ struct ASIC_INFO { enum asic_state last_state; struct timeval state_change_time; // Device startup time struct timeval last_frequency_reply; // Last time of frequency reply - + uint32_t prev_nonce; // Last nonce found uint32_t fullscan_ms; // Estimated time(ms) for full nonce range + uint32_t fullscan_us; // Estimated time(us) for full nonce range uint64_t hashrate; // Estimated hashrate = cores x chips x frequency }; @@ -101,10 +104,12 @@ struct COMPAC_INFO { float eff_wu; float micro_temp; // Micro Reported Temp + float wait_factor; // Used to compute max_task_wait uint32_t scanhash_ms; // Sleep time inside scanhash loop uint32_t task_ms; // Avg time(ms) between task sent to device uint32_t fullscan_ms; // Estimated time(ms) for full nonce range + uint32_t fullscan_us; // Estimated time(us) for full nonce range uint64_t hashrate; // Estimated hashrate = cores x chips x frequency uint64_t busy_work; @@ -140,6 +145,7 @@ struct COMPAC_INFO { uint32_t job_id; // JobId incrementer uint32_t low_hash; // Tracks of low hashrate uint32_t max_job_id; // JobId cap + uint64_t max_task_wait; // Micro seconds to wait before next task is sent uint32_t ramping; // Ramping incrementer uint32_t rx_len; // rx length uint32_t task_len; // task length @@ -149,8 +155,9 @@ struct COMPAC_INFO { struct timeval start_time; // Device startup time struct timeval monitor_time; // Health check reference point + struct timeval last_computed_increase; // Last frequency computed change struct timeval last_scanhash; // Last time inside scanhash loop - struct timeval last_dup_fix; // Last time nonce dup fix was attempted + struct timeval last_dup_time; // Last time nonce dup detected was attempted struct timeval last_reset; // Last time reset was triggered struct timeval last_task; // Last time work was sent struct timeval last_nonce; // Last time nonce was found From 7f04144c9f5948799979ab8cac2b359ade679f6b Mon Sep 17 00:00:00 2001 From: vthoang Date: Thu, 18 Apr 2019 13:27:51 +0100 Subject: [PATCH 103/113] adjustment to mitigate observation on WIN32 --- driver-gekko.c | 135 ++++++++++++++++++++++++++----------------------- driver-gekko.h | 3 ++ 2 files changed, 76 insertions(+), 62 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index 2ffb527bf9..0e48d4a614 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -364,7 +364,7 @@ static void compac_toggle_reset(struct cgpu_info *compac) struct COMPAC_INFO *info = compac->device_data; unsigned short usb_val; - applog(LOG_INFO,"%d: %s %d - Toggling ASIC nRST to reset", compac->cgminer_id, compac->drv->name, compac->device_id); + applog(info->log_wide,"%d: %s %d - Toggling ASIC nRST to reset", compac->cgminer_id, compac->drv->name, compac->device_id); usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET, info->interface, C_RESET); usb_transfer(compac, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, FTDI_VALUE_DATA_BTS, info->interface, C_SETDATA); @@ -427,12 +427,14 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) if (nonce == asic->prev_nonce) { applog(LOG_INFO, "%d: %s %d - Duplicate Nonce : %08x @ %02x [%02x %02x %02x %02x %02x %02x %02x]", compac->cgminer_id, compac->drv->name, compac->device_id, nonce, job_id, info->rx[0], info->rx[1], info->rx[2], info->rx[3], info->rx[4], info->rx[5], info->rx[6]); +#ifndef WIN32 info->dups++; asic->dups++; cgtime(&info->last_dup_time); if (info->dups == 1) { info->mining_state = MINER_MINING_DUPS; } +#endif return hashes; } @@ -567,7 +569,6 @@ static void *compac_mine(void *object) struct timeval now; struct timeval last_frequency_report; - struct timeval last_eff_calculations = (struct timeval){0}; struct sched_param param; int i, j, read_bytes, sleep_us, policy, ret_nice, ping_itr; @@ -602,54 +603,65 @@ static void *compac_mine(void *object) info->update_work = 0; - sleep_us = bound(ceil(info->max_task_wait/10.0), 1, (info->max_task_wait / 2)); + sleep_us = bound(ceil(info->max_task_wait / 10), 1, 1000 * 1000); - if (ms_tdiff(&now, &last_eff_calculations) > MS_SECOND_1) { - // throttle everthing except work to once per second + dev_runtime = cgpu_runtime(compac); + wu = compac->diff1 / dev_runtime * 60; - dev_runtime = cgpu_runtime(compac); - wu = compac->diff1 / dev_runtime * 60; + if (wu > info->wu_max) { + info->wu_max = wu; + cgtime(&info->last_wu_increase); + } - if (wu > info->wu_max) { - info->wu_max = wu; - cgtime(&info->last_wu_increase); - } + hashrate_li = (double)compac->rolling * 1000000ull; + hashrate_1m = (double)compac->rolling1 * 1000000ull; + hashrate_5m = (double)compac->rolling5 * 1000000ull; + hashrate_15 = (double)compac->rolling15 * 1000000ull; + hashrate_tm = (double)compac->total_mhashes / dev_runtime * 1000000ull;; + + info->eff_li = 100.0 * (1.0 * hashrate_li / info->hashrate); + info->eff_1m = 100.0 * (1.0 * hashrate_1m / info->hashrate); + info->eff_5m = 100.0 * (1.0 * hashrate_5m / info->hashrate); + info->eff_15 = 100.0 * (1.0 * hashrate_15 / info->hashrate); + info->eff_wu = 100.0 * (1.0 * wu / info->wu); + info->eff_tm = 100.0 * (1.0 * hashrate_tm / info->hashrate); + + info->eff_li = (info->eff_li > 100) ? 100 : info->eff_li; + info->eff_1m = (info->eff_1m > 100) ? 100 : info->eff_1m; + info->eff_5m = (info->eff_5m > 100) ? 100 : info->eff_5m; + info->eff_15 = (info->eff_15 > 100) ? 100 : info->eff_15; + info->eff_wu = (info->eff_wu > 100) ? 100 : info->eff_wu; + info->eff_tm = (info->eff_tm > 100) ? 100 : info->eff_tm; + + info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; + + //frequency_computed = ((hashrate_5m / 1000000.0) / info->cores) / info->chips; + //frequency_computed = info->eff_gs / 100.0 * info->frequency; + frequency_computed = ((info->eff_tm > info->eff_5m) ? info->eff_tm : info->eff_5m) / 100.0 * info->frequency; + if (frequency_computed > info->frequency_computed && frequency_computed < 900) { + info->frequency_computed = frequency_computed; + cgtime(&info->last_computed_increase); + } + if (info->eff_5m > 10.0 && info->eff_1m < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { + low_eff = 1; + } - hashrate_li = (double)compac->rolling * 1000000ull; - hashrate_1m = (double)compac->rolling1 * 1000000ull; - hashrate_5m = (double)compac->rolling5 * 1000000ull; - hashrate_15 = (double)compac->rolling15 * 1000000ull; - hashrate_tm = (double)compac->total_mhashes / dev_runtime * 1000000ull;; - - info->eff_li = 100.0 * (1.0 * hashrate_li / info->hashrate); - info->eff_1m = 100.0 * (1.0 * hashrate_1m / info->hashrate); - info->eff_5m = 100.0 * (1.0 * hashrate_5m / info->hashrate); - info->eff_15 = 100.0 * (1.0 * hashrate_15 / info->hashrate); - info->eff_wu = 100.0 * (1.0 * wu / info->wu); - info->eff_tm = 100.0 * (1.0 * hashrate_tm / info->hashrate); - - info->eff_li = (info->eff_li > 100) ? 100 : info->eff_li; - info->eff_1m = (info->eff_1m > 100) ? 100 : info->eff_1m; - info->eff_5m = (info->eff_5m > 100) ? 100 : info->eff_5m; - info->eff_15 = (info->eff_15 > 100) ? 100 : info->eff_15; - info->eff_wu = (info->eff_wu > 100) ? 100 : info->eff_wu; - info->eff_tm = (info->eff_tm > 100) ? 100 : info->eff_tm; - - info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; - - //frequency_computed = ((hashrate_5m / 1000000.0) / info->cores) / info->chips; - frequency_computed = info->eff_gs / 100.0 * info->frequency; - if (frequency_computed > info->frequency_computed && frequency_computed < 900) { - info->frequency_computed = frequency_computed; - cgtime(&info->last_computed_increase); - } - if (info->eff_5m > 10.0 && info->eff_1m < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { - low_eff = 1; + // unhealthy mining condition + if (low_eff) { + // only respond when target and peak converges + if (ceil(100 * (info->frequency_requested) / 625.0) * 6.25 == ceil(100 * (info->frequency_computed) / 625.0) * 6.25) { + // throttle reaction to once per half hour + if (ms_tdiff(&now, &info->last_low_eff_reset) > MS_MINUTE_10) { + applog(info->log_wide,"%d: %s %d - low eff: (1m)%.1f (5m)%.1f (15m)%.1f (WU)%.1f - [%.1f]", compac->cgminer_id, compac->drv->name, compac->device_id, info->eff_1m, info->eff_5m, info->eff_15, info->eff_wu, opt_gekko_tune_down); + info->low_eff_resets++; + info->mining_state = MINER_RESET; + cgtime(&info->last_low_eff_reset); + continue; + } } - cgtime(&last_eff_calculations); } - + // search for plateau if (ms_tdiff(&now, &info->monitor_time) > MS_SECOND_5 && ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_5) { for (i = 0; i < info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i]; @@ -699,10 +711,10 @@ static void *compac_mine(void *object) cgtime(&info->monitor_time); if (asic->dups > 3) { - applog(LOG_INFO,"%d: %s %d - duplicate nonces from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); + applog(info->log_wide,"%d: %s %d - duplicate nonces from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); asic->dups = 0; } else { - applog(LOG_INFO,"%d: %s %d - missing nonces from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); + applog(info->log_wide,"%d: %s %d - missing nonces from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); } old_frequency = info->frequency_requested; @@ -722,6 +734,7 @@ static void *compac_mine(void *object) } } + // move target fequency towards peak frequency, once peak is done increasing. if (ms_tdiff(&now, &info->last_computed_increase) > MS_MINUTE_5 && info->frequency_computed < info->frequency ) { float new_frequency = info->frequency - 6.25; if (new_frequency < info->frequency_computed) { @@ -729,14 +742,6 @@ static void *compac_mine(void *object) } new_frequency = ceil(100 * (new_frequency) / 625.0) * 6.25; -/* - applog(LOG_WARNING,"%d: %s %d - low eff: (1m)%.1f (5m)%.1f (15m)%.1f (WU)%.1f - [%.1f]", compac->cgminer_id, compac->drv->name, compac->device_id, info->eff_1m, info->eff_5m, info->eff_15, info->eff_wu, opt_gekko_tune_down); - - if (new_frequency == info->frequency) { - info->mining_state = MINER_RESET; - continue; - } -*/ if (new_frequency != info->frequency) { applog(LOG_WARNING,"%d: %s %d - peak adjust: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_requested, new_frequency); cgtime(&info->last_computed_increase); @@ -751,14 +756,15 @@ static void *compac_mine(void *object) } } - if (ms_tdiff(&now, &info->last_frequency_ping) > MS_SECOND_1 || (info->frequency_of != info->chips && ms_tdiff(&now, &info->last_frequency_ping) > 10)) { + // move running frequency towards target. + if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_1 || (info->frequency_of != info->chips && ms_tdiff(&now, &info->last_frequency_ping) > 10)) { info->frequency_of--; struct ASIC_INFO *asic = &info->asics[info->frequency_of]; if (info->frequency_of == (info->chips - 1) && - (info->eff_gs >= opt_gekko_tune_up || asic->frequency < info->frequency_computed) && - ms_tdiff(&now, &info->last_dup_time) > MS_MINUTE_5) { + ((ms_tdiff(&now, &info->last_dup_time) > MS_MINUTE_2 && (info->eff_gs >= opt_gekko_tune_up || asic->frequency < info->frequency_computed)) || + (ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_30 && (info->eff_1m > 98.0 || asic->frequency < info->frequency_computed)))) { adjustable = 1; } @@ -784,6 +790,7 @@ static void *compac_mine(void *object) new_frequency = asic->frequency_requested; } if (asic->frequency != new_frequency) { + cgtime(&info->last_frequency_adjust); cgtime(&info->monitor_time); if (info->asic_type == BM1387) { compac_set_frequency_single(compac, new_frequency, info->frequency_of); @@ -1093,7 +1100,9 @@ static bool compac_init(struct thr_info *thr) info->prev_nonce = 0; info->fail_count = 0; info->busy_work = 0; + info->log_wide = (opt_widescreen) ? LOG_WARNING : LOG_INFO; info->nononce_reset = 0; + info->low_eff_resets = 0; info->frequency = 200; info->frequency_default = 200; info->frequency_fail_high = 0; @@ -1263,6 +1272,8 @@ static int64_t compac_scanwork(struct thr_info *thr) cgtime(&info->last_micro_ping); cgtime(&info->last_nonce); compac_flush_buffer(compac); + compac_update_rates(compac); + info->update_work = 1; info->mining_state = MINER_MINING; return 0; break; @@ -1548,17 +1559,17 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) if (info->micro_found) { sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.0f P:%.0f (%d/%d/%d/%.0fF)", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); } else { - if (opt_log_output) { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.0f P:%.0f %s%s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, ms_stat); + if (opt_widescreen) { + sprintf(asic_statline, "BM1387:%02d%-1s %.0f/%.0f/%.0f %s %s%s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat, eff_stat); } else { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.0f P:%.0f %s %s%s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat, eff_stat); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%-3.0f P:%-3.0f %-13s %s%s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat, eff_stat); } } } else { - if (opt_log_output) { - sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%.0f P:%.0f %s%s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, ms_stat); + if (opt_widescreen) { + sprintf(asic_statline, "BM1384:%02d %.0f/%.0f/%.0f %s %s%s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat, eff_stat); } else { - sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%.0f P:%.0f %s%s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, asic_stat, eff_stat); + sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%-3.0f P:%-3.0f %-13s %s%s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat, eff_stat); } } diff --git a/driver-gekko.h b/driver-gekko.h index 69e19599a0..688a1d5874 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -122,6 +122,7 @@ struct COMPAC_INFO { int accepted; // Nonces accepted int dups; // Duplicates found int interface; // USB interface + int low_eff_resets; // Count of low_eff resets int nonceless; // Tasks sent. Resets when nonce is found. int nonces; // Nonces found int nononce_reset; // Count missing nonces @@ -143,6 +144,7 @@ struct COMPAC_INFO { uint32_t expected_chips; // Number of chips for device uint64_t hashes; // Hashes completed uint32_t job_id; // JobId incrementer + uint32_t log_wide; // Extra output in widescreen mode uint32_t low_hash; // Tracks of low hashrate uint32_t max_job_id; // JobId cap uint64_t max_task_wait; // Micro seconds to wait before next task is sent @@ -167,6 +169,7 @@ struct COMPAC_INFO { struct timeval last_frequency_ping; // Last time of frequency poll struct timeval last_frequency_report; // Last change of frequency report struct timeval last_chain_inactive; // Last sent chain inactive + struct timeval last_low_eff_reset; // Last time responded to low_eff condition struct timeval last_micro_ping; // Last time of micro controller poll struct timeval last_write_error; // Last usb write error message struct timeval last_wu_increase; // Last wu_max change From 2a03170673fa3298fd6dadc85de12cbebce015b0 Mon Sep 17 00:00:00 2001 From: vthoang Date: Tue, 23 Apr 2019 04:00:26 +0100 Subject: [PATCH 104/113] updated to only count successfully tested nonce in hashrate. switch some values to float for more granularity. --- driver-gekko.c | 50 ++++++++++++++++++++++++++++---------------------- driver-gekko.h | 8 ++++---- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index 0e48d4a614..72ab4569c4 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -218,14 +218,14 @@ static void compac_update_rates(struct cgpu_info *compac) info->wu_max = 0; } + info->wu = info->chips * info->frequency * info->cores / 71.6; info->hashrate = info->chips * info->frequency * info->cores * 1000000; info->fullscan_ms = 1000.0 * 0xffffffffull / info->hashrate; info->fullscan_us = 1000.0 * 1000.0 * 0xffffffffull / info->hashrate; - info->scanhash_ms = bound(info->fullscan_ms / 2, 1, 100); info->ticket_mask = bound(pow(2, ceil(log(info->hashrate / (2.0 * 0xffffffffull)) / log(2))) - 1, 0, 4000); info->ticket_mask = (info->asic_type == BM1387) ? 0 : info->ticket_mask; info->difficulty = info->ticket_mask + 1; - info->wu = 0.0139091 * info->cores * info->chips * info->frequency; + info->scanhash_ms = info->fullscan_ms * info->difficulty; info->wait_factor = ((!opt_gekko_noboost && info->vmask && info->asic_type == BM1387) ? 1.80 : 0.60); info->max_task_wait = bound(info->wait_factor * info->fullscan_us, 1, 3 * info->fullscan_us); @@ -438,7 +438,6 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) return hashes; } - hashes = info->difficulty * 0xffffffffull; info->prev_nonce = nonce; asic->prev_nonce = nonce; @@ -486,6 +485,8 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) applog(LOG_INFO, "%d: %s %d - AsicBoost nonce found : midstate%d", compac->cgminer_id, compac->drv->name, compac->device_id, midnum); } + hashes = info->difficulty * 0xffffffffull; + info->accepted++; info->failing = false; info->dups = 0; @@ -493,7 +494,6 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) } else { if (hwe != compac->hw_errors) { cgtime(&info->last_hwerror); - compac_flush_buffer(compac); } } @@ -647,7 +647,7 @@ static void *compac_mine(void *object) } // unhealthy mining condition - if (low_eff) { + if (low_eff & ms_tdiff(&now, &info->last_low_eff_reset) > MS_MINUTE_1) { // only respond when target and peak converges if (ceil(100 * (info->frequency_requested) / 625.0) * 6.25 == ceil(100 * (info->frequency_computed) / 625.0) * 6.25) { // throttle reaction to once per half hour @@ -1124,6 +1124,7 @@ static bool compac_init(struct thr_info *thr) cgtime(&info->last_write_error); cgtime(&info->last_frequency_adjust); cgtime(&info->last_computed_increase); + cgtime(&info->last_low_eff_reset); info->last_frequency_ping = (struct timeval){0}; cgtime(&info->last_micro_ping); cgtime(&info->last_scanhash); @@ -1204,6 +1205,7 @@ static int64_t compac_scanwork(struct thr_info *thr) int read_bytes; uint32_t err = 0; uint64_t hashes = 0; + uint32_t sleep_us = bound(info->scanhash_ms * 1000, 250, MS_SECOND_1 / 2 * 1000); if (info->chips == 0) cgsleep_ms(10); @@ -1300,9 +1302,13 @@ static int64_t compac_scanwork(struct thr_info *thr) default: break; } + + mutex_lock(&info->lock); hashes = info->hashes; - info->hashes -= hashes; - usleep(500); + info->hashes = 0; + mutex_unlock(&info->lock); + + usleep(sleep_us); return hashes; } @@ -1412,8 +1418,6 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb } compac->unique_id[8] = 0; - applog(LOG_WARNING, "%d: %s %d - %s (%s)", compac->cgminer_id, compac->drv->name, compac->device_id, compac->usbdev->prod_string, compac->unique_id); - return compac; } @@ -1434,7 +1438,9 @@ static bool compac_prepare(struct thr_info *thr) init_count = &dev_init_count[device]; (*init_count)++; - if ((*init_count) > 1) { + if ((*init_count) == 1) { + applog(LOG_WARNING, "%d: %s %d - %s (%s)", compac->cgminer_id, compac->drv->name, compac->device_id, compac->usbdev->prod_string, compac->unique_id); + } else { applog(LOG_INFO, "%d: %s %d - init_count %d", compac->cgminer_id, compac->drv->name, compac->device_id, *init_count); } @@ -1465,14 +1471,14 @@ static bool compac_prepare(struct thr_info *thr) } if ((*init_count) != 0 && (*init_count) % 5 == 0) { - if ((*init_count) >= 15) { + applog(LOG_INFO, "%d: %s %d - forcing usb_nodev()", compac->cgminer_id, compac->drv->name, compac->device_id); + usb_nodev(compac); + } else if ((*init_count) > 1) { + if ((*init_count) > 10) { compac->deven = DEV_DISABLED; } else { - applog(LOG_INFO, "%d: %s %d - forcing usb_nodev()", compac->cgminer_id, compac->drv->name, compac->device_id); - usb_nodev(compac); + cgsleep_ms(MS_SECOND_5); } - } else if ((*init_count) > 1) { - cgsleep_ms(MS_SECOND_5); } return true; @@ -1501,7 +1507,7 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) sprintf(asic_statline, "found 0 chip(s)"); } - for (i = strlen(asic_statline); i < stat_len; i++) + for (i = strlen(asic_statline); i < stat_len + 16; i++) asic_statline[i] = ' '; tailsprintf(buf, bufsiz, "%s", asic_statline); @@ -1543,7 +1549,7 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) asic_stat[info->chips + 1 + i] = ' '; } - sprintf(ms_stat, "(%d/%d/%d)", info->scanhash_ms, info->task_ms, info->fullscan_ms); + sprintf(ms_stat, "(%.0f/%.0f/%.0f)", info->scanhash_ms, info->task_ms, info->fullscan_ms); uint8_t wuc = (ms_tdiff(&now, &info->last_wu_increase) > MS_MINUTE_1) ? 32 : 94; @@ -1560,16 +1566,16 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.0f P:%.0f (%d/%d/%d/%.0fF)", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); } else { if (opt_widescreen) { - sprintf(asic_statline, "BM1387:%02d%-1s %.0f/%.0f/%.0f %s %s%s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat, eff_stat); + sprintf(asic_statline, "BM1387:%02d%-1s %.0f/%.0f/%3.0f %s %s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat); } else { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%-3.0f P:%-3.0f %-13s %s%s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat, eff_stat); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%-3.0f P:%-3.0f %-13s %s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat); } } } else { if (opt_widescreen) { - sprintf(asic_statline, "BM1384:%02d %.0f/%.0f/%.0f %s %s%s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat, eff_stat); + sprintf(asic_statline, "BM1384:%02d %.0f/%.0f/%.0f %s %s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat); } else { - sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%-3.0f P:%-3.0f %-13s %s%s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat, eff_stat); + sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%-3.0f P:%-3.0f %-13s %s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat); } } @@ -1580,7 +1586,7 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) for (i = len; i < stat_len; i++) asic_statline[i] = ' '; - tailsprintf(buf, bufsiz, "%s", asic_statline); + tailsprintf(buf, bufsiz, "%s%s", asic_statline, eff_stat); } static struct api_data *compac_api_stats(struct cgpu_info *compac) diff --git a/driver-gekko.h b/driver-gekko.h index 688a1d5874..69aa30c56a 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -69,7 +69,7 @@ struct ASIC_INFO { struct timeval state_change_time; // Device startup time struct timeval last_frequency_reply; // Last time of frequency reply uint32_t prev_nonce; // Last nonce found - uint32_t fullscan_ms; // Estimated time(ms) for full nonce range + float fullscan_ms; // Estimated time(ms) for full nonce range uint32_t fullscan_us; // Estimated time(us) for full nonce range uint64_t hashrate; // Estimated hashrate = cores x chips x frequency }; @@ -106,9 +106,9 @@ struct COMPAC_INFO { float micro_temp; // Micro Reported Temp float wait_factor; // Used to compute max_task_wait - uint32_t scanhash_ms; // Sleep time inside scanhash loop - uint32_t task_ms; // Avg time(ms) between task sent to device - uint32_t fullscan_ms; // Estimated time(ms) for full nonce range + float fullscan_ms; // Estimated time(ms) for full nonce range + float scanhash_ms; // Sleep time inside scanhash loop + float task_ms; // Avg time(ms) between task sent to device uint32_t fullscan_us; // Estimated time(us) for full nonce range uint64_t hashrate; // Estimated hashrate = cores x chips x frequency uint64_t busy_work; From 532985ea1f717340edebc6f1d80f51b4a8ddf5a0 Mon Sep 17 00:00:00 2001 From: vthoang Date: Tue, 23 Apr 2019 04:27:47 +0100 Subject: [PATCH 105/113] reduce hashrate check interval - WIN32 --- driver-gekko.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index 72ab4569c4..c978f16496 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -225,7 +225,7 @@ static void compac_update_rates(struct cgpu_info *compac) info->ticket_mask = bound(pow(2, ceil(log(info->hashrate / (2.0 * 0xffffffffull)) / log(2))) - 1, 0, 4000); info->ticket_mask = (info->asic_type == BM1387) ? 0 : info->ticket_mask; info->difficulty = info->ticket_mask + 1; - info->scanhash_ms = info->fullscan_ms * info->difficulty; + info->scanhash_ms = info->fullscan_ms * info->difficulty / 4; info->wait_factor = ((!opt_gekko_noboost && info->vmask && info->asic_type == BM1387) ? 1.80 : 0.60); info->max_task_wait = bound(info->wait_factor * info->fullscan_us, 1, 3 * info->fullscan_us); @@ -1205,7 +1205,7 @@ static int64_t compac_scanwork(struct thr_info *thr) int read_bytes; uint32_t err = 0; uint64_t hashes = 0; - uint32_t sleep_us = bound(info->scanhash_ms * 1000, 250, MS_SECOND_1 / 2 * 1000); + uint32_t sleep_us = bound(info->scanhash_ms * 1000, 100, MS_SECOND_1 / 2 * 1000); if (info->chips == 0) cgsleep_ms(10); From 66920e67be448f104df77dcca597832f84063121 Mon Sep 17 00:00:00 2001 From: vthoang Date: Wed, 24 Apr 2019 15:45:44 +0100 Subject: [PATCH 106/113] slow down frequency pings. increase max frequency setting. --- driver-gekko.c | 163 +++++++++++++++++++++++++++++++------------------ driver-gekko.h | 10 ++- 2 files changed, 111 insertions(+), 62 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index c978f16496..0d9dbc380b 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -240,7 +240,7 @@ static void compac_set_frequency_single(struct cgpu_info *compac, float frequenc if (info->asic_type == BM1387) { unsigned char buffer[] = {0x48, 0x09, 0x00, 0x0C, 0x00, 0x50, 0x02, 0x41, 0x00}; //250MHz -- osc of 25MHz - frequency = bound(frequency, 50, 900); + frequency = bound(frequency, 50, 1200); frequency = ceil(100 * (frequency) / 625.0) * 6.25; if (frequency < 400) { @@ -253,6 +253,9 @@ static void compac_set_frequency_single(struct cgpu_info *compac, float frequenc buffer[2] = (0x100 / info->chips) * asic_id; //asic->frequency = frequency; + asic->frequency_set = frequency; + asic->frequency_attempt++; + applog(LOG_INFO, "%d: %s %d - setting chip[%d] frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, asic_id, asic->frequency, frequency); compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); @@ -271,7 +274,7 @@ static void compac_set_frequency(struct cgpu_info *compac, float frequency) if (info->asic_type == BM1387) { unsigned char buffer[] = {0x58, 0x09, 0x00, 0x0C, 0x00, 0x50, 0x02, 0x41, 0x00}; //250MHz -- osc of 25MHz - frequency = bound(frequency, 50, 900); + frequency = bound(frequency, 50, 1200); frequency = ceil(100 * (frequency) / 625.0) * 6.25; if (frequency < 400) { @@ -568,7 +571,7 @@ static void *compac_mine(void *object) struct work *old_work = NULL; struct timeval now; - struct timeval last_frequency_report; + struct timeval last_movement = (struct timeval){0}; struct sched_param param; int i, j, read_bytes, sleep_us, policy, ret_nice, ping_itr; @@ -638,7 +641,7 @@ static void *compac_mine(void *object) //frequency_computed = ((hashrate_5m / 1000000.0) / info->cores) / info->chips; //frequency_computed = info->eff_gs / 100.0 * info->frequency; frequency_computed = ((info->eff_tm > info->eff_5m) ? info->eff_tm : info->eff_5m) / 100.0 * info->frequency; - if (frequency_computed > info->frequency_computed && frequency_computed < 900) { + if (frequency_computed > info->frequency_computed && frequency_computed < 1200) { info->frequency_computed = frequency_computed; cgtime(&info->last_computed_increase); } @@ -647,11 +650,11 @@ static void *compac_mine(void *object) } // unhealthy mining condition - if (low_eff & ms_tdiff(&now, &info->last_low_eff_reset) > MS_MINUTE_1) { + if (low_eff & ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10) { // only respond when target and peak converges if (ceil(100 * (info->frequency_requested) / 625.0) * 6.25 == ceil(100 * (info->frequency_computed) / 625.0) * 6.25) { // throttle reaction to once per half hour - if (ms_tdiff(&now, &info->last_low_eff_reset) > MS_MINUTE_10) { + if (ms_tdiff(&now, &info->last_low_eff_reset) > MS_MINUTE_30) { applog(info->log_wide,"%d: %s %d - low eff: (1m)%.1f (5m)%.1f (15m)%.1f (WU)%.1f - [%.1f]", compac->cgminer_id, compac->drv->name, compac->device_id, info->eff_1m, info->eff_5m, info->eff_15, info->eff_wu, opt_gekko_tune_down); info->low_eff_resets++; info->mining_state = MINER_RESET; @@ -666,18 +669,19 @@ static void *compac_mine(void *object) for (i = 0; i < info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i]; float old_frequency, new_frequency; - if (ms_tdiff(&now, &asic->last_nonce) > asic->fullscan_ms * 60 * info->chips || asic->dups > 3) { + + if (ms_tdiff(&now, &asic->last_nonce) > asic->fullscan_ms * 60 * info->chips || asic->dups > 3 || asic->frequency_attempt > 10 || ms_tdiff(&now, &asic->last_frequency_reply) > MS_SECOND_30) { new_frequency = info->frequency_requested; - char freq_buf[512]; - char freq_chip_buf[10]; - memset(freq_buf, 0, 512); - for (j = 0; j < info->chips; j++) { - struct ASIC_INFO *asjc = &info->asics[j]; - sprintf(freq_chip_buf, "[%d:%.2f]", j, asjc->frequency); - strcat(freq_buf, freq_chip_buf); - } - applog(LOG_INFO,"%d: %s %d - %s", compac->cgminer_id, compac->drv->name, compac->device_id, freq_buf); + char freq_buf[512]; + char freq_chip_buf[10]; + memset(freq_buf, 0, 512); + for (j = 0; j < info->chips; j++) { + struct ASIC_INFO *asjc = &info->asics[j]; + sprintf(freq_chip_buf, "[%d:%.2f]", j, asjc->frequency); + strcat(freq_buf, freq_chip_buf); + } + applog(LOG_INFO,"%d: %s %d - %s", compac->cgminer_id, compac->drv->name, compac->device_id, freq_buf); if (info->nononce_reset < 3) { // Capture failure high/low frequencies using first three resets @@ -710,7 +714,13 @@ static void *compac_mine(void *object) cgtime(&asic->state_change_time); cgtime(&info->monitor_time); - if (asic->dups > 3) { + if (ms_tdiff(&now, &asic->last_frequency_reply) > MS_SECOND_30) { + applog(info->log_wide,"%d: %s %d - no frequency reply from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); + asic->frequency_attempt = 0; + } else if (asic->frequency_attempt > 10) { + applog(info->log_wide,"%d: %s %d - frequency set fail to chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); + asic->frequency_attempt = 0; + } else if (asic->dups > 3) { applog(info->log_wide,"%d: %s %d - duplicate nonces from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); asic->dups = 0; } else { @@ -720,11 +730,6 @@ static void *compac_mine(void *object) old_frequency = info->frequency_requested; if (new_frequency != old_frequency) { info->frequency_requested = new_frequency; - for (i = 0; i < info->chips; i++) - { - struct ASIC_INFO *asjc = &info->asics[i]; - asjc->frequency_requested = info->frequency_requested; - } applog(LOG_WARNING,"%d: %s %d - plateau adjust: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, old_frequency, new_frequency); } @@ -735,7 +740,7 @@ static void *compac_mine(void *object) } // move target fequency towards peak frequency, once peak is done increasing. - if (ms_tdiff(&now, &info->last_computed_increase) > MS_MINUTE_5 && info->frequency_computed < info->frequency ) { + if (ms_tdiff(&now, &info->last_computed_increase) > MS_MINUTE_10 && info->frequency_computed < info->frequency ) { float new_frequency = info->frequency - 6.25; if (new_frequency < info->frequency_computed) { new_frequency = info->frequency_computed; @@ -747,38 +752,58 @@ static void *compac_mine(void *object) cgtime(&info->last_computed_increase); info->frequency_requested = new_frequency; info->frequency_fail_high = new_frequency; - - for (i = 0; i < info->chips; i++) - { - struct ASIC_INFO *asic = &info->asics[i]; - asic->frequency_requested = info->frequency_requested; - } } } // move running frequency towards target. - if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_1 || (info->frequency_of != info->chips && ms_tdiff(&now, &info->last_frequency_ping) > 10)) { + if (ms_tdiff(&now, &last_movement) > 20 && (ms_tdiff(&now, &info->last_frequency_ping) > MS_SECOND_1 || info->frequency_of != info->chips)) { info->frequency_of--; - struct ASIC_INFO *asic = &info->asics[info->frequency_of]; + cgtime(&last_movement); + bool frequency_updated = 0; - if (info->frequency_of == (info->chips - 1) && - ((ms_tdiff(&now, &info->last_dup_time) > MS_MINUTE_2 && (info->eff_gs >= opt_gekko_tune_up || asic->frequency < info->frequency_computed)) || - (ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_30 && (info->eff_1m > 98.0 || asic->frequency < info->frequency_computed)))) { + // standard check for ramp up + if (info->frequency_of == (info->chips - 1) && info->eff_gs >= opt_gekko_tune_up) { adjustable = 1; } + // seeing dup, hold off. + if (ms_tdiff(&now, &info->last_dup_time) < MS_MINUTE_1) { + adjustable = 0; + } + if (info->frequency_of < 0) { info->frequency_of = info->chips; ping_itr = (ping_itr + 1) % 1; adjustable = 0; } else { - if (ping_itr == 0 && asic->frequency != asic->frequency_requested) { + struct ASIC_INFO *asic = &info->asics[info->frequency_of]; + if (ping_itr == 0 && asic->frequency != info->frequency_requested) { float new_frequency; - if (asic->frequency < asic->frequency_requested) { + + // catching up after reset + if (asic->frequency < info->frequency_computed) { + adjustable = 1; + } + + // chip speeds aren't matching - special override + if (!info->frequency_syncd) { + if (asic->frequency >= info->frequency) { + adjustable = 0; + } else { + adjustable = 1; + } + } + + // limit to one adjust per 5 seconds if above peak. + if (asic->frequency > info->frequency_computed && ms_tdiff(&now, &asic->last_frequency_adjust) < MS_SECOND_5) { + adjustable = 0; + } + + if (asic->frequency < info->frequency_requested) { new_frequency = asic->frequency + opt_gekko_step_freq; - if (new_frequency > asic->frequency_requested) { - new_frequency = asic->frequency_requested; + if (new_frequency > info->frequency_requested) { + new_frequency = info->frequency_requested; } if (new_frequency < info->frequency_start) { new_frequency = info->frequency_start; @@ -787,11 +812,13 @@ static void *compac_mine(void *object) new_frequency = asic->frequency; } } else { - new_frequency = asic->frequency_requested; + new_frequency = info->frequency_requested; } if (asic->frequency != new_frequency) { cgtime(&info->last_frequency_adjust); + cgtime(&asic->last_frequency_adjust); cgtime(&info->monitor_time); + frequency_updated = 1; if (info->asic_type == BM1387) { compac_set_frequency_single(compac, new_frequency, info->frequency_of); } else if (info->asic_type == BM1384) { @@ -803,16 +830,20 @@ static void *compac_mine(void *object) } } - if (info->asic_type == BM1387) { - unsigned char buffer[] = {0x44, 0x05, 0x00, 0x0C, 0x00}; // PLL_PARAMETER - buffer[2] = (0x100 / info->chips) * info->frequency_of; - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); - cgtime(&info->last_frequency_ping); - } else if (info->asic_type == BM1384) { - unsigned char buffer[] = {0x04, 0x00, 0x04, 0x00}; - buffer[1] = (0x100 / info->chips) * info->frequency_of; - compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); - cgtime(&info->last_frequency_ping); + if (frequency_updated || ms_tdiff(&now, &asic->last_frequency_ping) > MS_SECOND_5) { + if (info->asic_type == BM1387) { + unsigned char buffer[] = {0x44, 0x05, 0x00, 0x0C, 0x00}; // PLL_PARAMETER + buffer[2] = (0x100 / info->chips) * info->frequency_of; + compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); + cgtime(&info->last_frequency_ping); + cgtime(&asic->last_frequency_ping); + } else if (info->asic_type == BM1384) { + unsigned char buffer[] = {0x04, 0x00, 0x04, 0x00}; + buffer[1] = (0x100 / info->chips) * info->frequency_of; + compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 5); + cgtime(&info->last_frequency_ping); + cgtime(&asic->last_frequency_ping); + } } } } @@ -890,6 +921,7 @@ static void *compac_handle_rx(void *object, int read_bytes) if (cmd_resp && info->rx[0] == 0x80) { float frequency; + int frequency_of = info->frequency_of; cgtime(&info->last_frequency_report); if (info->asic_type == BM1387 && (info->rx[2] == 0 || (info->rx[3] >> 4) == 0 || (info->rx[3] & 0x0f) == 0)) { @@ -902,26 +934,37 @@ static void *compac_handle_rx(void *object, int read_bytes) frequency = (info->rx[1] + 1) * 6.25 / (1 + info->rx[2] & 0x0f) * pow(2, (3 - info->rx[3])) + ((info->rx[2] >> 4) * 6.25); } - if (info->frequency_of != info->chips) { - asic = &info->asics[info->frequency_of]; + if (frequency_of != info->chips) { + asic = &info->asics[frequency_of]; cgtime(&asic->last_frequency_reply); if (frequency != asic->frequency) { - if (frequency < asic->frequency && frequency != asic->frequency_requested) { + bool syncd = 1; + if (frequency < asic->frequency && frequency != info->frequency_requested) { applog(LOG_INFO,"%d: %s %d - chip[%d] reported frequency at %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_of, frequency); } else { applog(LOG_INFO,"%d: %s %d - chip[%d] reported new frequency of %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_of, frequency); } asic->frequency = frequency; - info->report = 1; - + if (asic->frequency == asic->frequency_set) { + asic->frequency_attempt = 0; + } + for (i = 1; i < info->chips; i++) { + if (info->asics[i].frequency != info->asics[i - 1].frequency) { + syncd = 0; + } + } + if (info->frequency_syncd != syncd) { + info->frequency_syncd = syncd; + applog(LOG_INFO,"%d: %s %d - syncd [%d]", compac->cgminer_id, compac->drv->name, compac->device_id, syncd); + } } else { applog(LOG_INFO,"%d: %s %d - chip[%d] reported frequency of %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->frequency_of, frequency); } } else { - applog(LOG_INFO,"%d: %s %d - [-1] reported frequency of %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, frequency); - if (frequency != info->frequency) { - info->frequency = frequency; - } + //applog(LOG_INFO,"%d: %s %d - [-1] reported frequency of %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, frequency); + //if (frequency != info->frequency) { + // info->frequency = frequency; + //} } compac_update_rates(compac); } @@ -932,8 +975,9 @@ static void *compac_handle_rx(void *object, int read_bytes) case MINER_CHIP_COUNT_XX: if (cmd_resp && info->rx[0] == 0x13) { struct ASIC_INFO *asic = &info->asics[info->chips]; + memset(asic, 0, sizeof(struct ASIC_INFO)); asic->frequency = info->frequency_default; - asic->frequency_requested = info->frequency_requested; + asic->frequency_attempt = 0; cgtime(&asic->last_nonce); info->chips++; info->mining_state = MINER_CHIP_COUNT_XX; @@ -1222,6 +1266,7 @@ static int64_t compac_scanwork(struct thr_info *thr) compac_flush_buffer(compac); info->chips = 0; info->ramping = 0; + info->frequency_syncd = 1; if (info->frequency_start > info->frequency_requested) { info->frequency_start = info->frequency_requested; } diff --git a/driver-gekko.h b/driver-gekko.h index 69aa30c56a..c0cd8690d7 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -61,12 +61,15 @@ enum asic_state { struct ASIC_INFO { struct timeval last_nonce; // Last time nonce was found - float frequency; - float frequency_requested; // Requested Frequency - int dups; // Duplicate nonce counter + float frequency; // Current frequency + float frequency_set; // set_frequency + uint32_t frequency_attempt; // attempts of set_frequency + uint32_t dups; // Duplicate nonce counter enum asic_state state; enum asic_state last_state; struct timeval state_change_time; // Device startup time + struct timeval last_frequency_adjust; // Last time of frequency adjust + struct timeval last_frequency_ping; // Last time of frequency ping struct timeval last_frequency_reply; // Last time of frequency reply uint32_t prev_nonce; // Last nonce found float fullscan_ms; // Estimated time(ms) for full nonce range @@ -133,6 +136,7 @@ struct COMPAC_INFO { bool vmask; // Current pool's vmask bool boosted; // Good nonce found for midstate2/3/4 bool report; + bool frequency_syncd; // All asics share same frequency double wu; double wu_max; // Max WU since last frequency change From c333ad13129d6006fb957dfec24fc2f1edd64abf Mon Sep 17 00:00:00 2001 From: vthoang Date: Wed, 24 Apr 2019 19:54:27 +0100 Subject: [PATCH 107/113] pause full ms per usb_write to keep data from slipping into the same frame --- driver-gekko.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index 0d9dbc380b..0e60718532 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -133,12 +133,13 @@ static void compac_send(struct cgpu_info *compac, unsigned char *req_tx, uint32_ } info->cmd[bytes - 1] |= bmcrc(req_tx, crc_bits); - usleep(100); - int log_level = (bytes < info->task_len) ? LOG_INFO : LOG_INFO; dumpbuffer(compac, LOG_INFO, "TX", info->cmd, bytes); usb_write(compac, info->cmd, bytes, &read_bytes, C_REQUESTRESULTS); + + //let the usb frame propagate + cgsleep_ms(1); } static void compac_send_chain_inactive(struct cgpu_info *compac) @@ -888,7 +889,8 @@ static void *compac_mine(void *object) } } - sched_yield(); + //let the usb frame propagate + cgsleep_ms(1); if (old_work) { mutex_lock(&info->lock); work_completed(compac, old_work); From 5c757f5f7930d42d87affd99d66f3106cf19474b Mon Sep 17 00:00:00 2001 From: vthoang Date: Sun, 28 Apr 2019 14:41:54 +0100 Subject: [PATCH 108/113] set R606 default frequency to 400. clean-up plateau detection. --- cgminer.c | 2 +- driver-gekko.c | 110 ++++++++++++++++++++++++++++++++++++------------- driver-gekko.h | 11 ++++- 3 files changed, 92 insertions(+), 31 deletions(-) diff --git a/cgminer.c b/cgminer.c index 538f3bc9b6..59bae1087f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -308,7 +308,7 @@ float opt_gekko_gse_freq = 150; float opt_gekko_tune_up = 92; float opt_gekko_tune_down = 95; int opt_gekko_gsh_freq = 100; -int opt_gekko_gsi_freq = 100; +int opt_gekko_gsi_freq = 400; int opt_gekko_gsh_vcore = 400; int opt_gekko_start_freq = 100; int opt_gekko_step_freq = 6; diff --git a/driver-gekko.c b/driver-gekko.c index 0e60718532..baf15e6151 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -257,7 +257,7 @@ static void compac_set_frequency_single(struct cgpu_info *compac, float frequenc asic->frequency_set = frequency; asic->frequency_attempt++; - applog(LOG_INFO, "%d: %s %d - setting chip[%d] frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, asic_id, asic->frequency, frequency); + applog(LOG_INFO, "%d: %s %d - setting chip[%d] frequency (%d) %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, asic_id, asic->frequency_attempt, asic->frequency, frequency); compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); //unsigned char gateblk[9] = {0x48, 0x09, 0x00, 0x1C, 0x40, 0x20, 0x99, 0x80, 0x01}; @@ -409,6 +409,12 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) job_id = info->rx[4] ^ 0x80; } + if ((info->rx[0] == 0x72 && info->rx[1] == 0x03 && info->rx[2] == 0xEA && info->rx[3] == 0x83) || + (info->rx[0] == 0xE1 && info->rx[1] == 0x6B && info->rx[2] == 0xF8 && info->rx[3] == 0x09)) { + //busy work nonces + return hashes; + } + if (job_id > info->max_job_id || (abs(info->job_id - job_id) > 3 && abs(info->max_job_id - job_id + info->job_id) > 3)) { return hashes; } @@ -490,6 +496,7 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) } hashes = info->difficulty * 0xffffffffull; + info->xhashes += info->difficulty; info->accepted++; info->failing = false; @@ -573,6 +580,7 @@ static void *compac_mine(void *object) struct timeval now; struct timeval last_movement = (struct timeval){0}; + struct timeval last_plateau_check = (struct timeval){0}; struct sched_param param; int i, j, read_bytes, sleep_us, policy, ret_nice, ping_itr; @@ -641,17 +649,17 @@ static void *compac_mine(void *object) //frequency_computed = ((hashrate_5m / 1000000.0) / info->cores) / info->chips; //frequency_computed = info->eff_gs / 100.0 * info->frequency; - frequency_computed = ((info->eff_tm > info->eff_5m) ? info->eff_tm : info->eff_5m) / 100.0 * info->frequency; + frequency_computed = ((info->eff_tm > info->eff_5m) ? info->eff_tm : ((info->eff_5m + info->eff_1m) / 2)) / 100.0 * info->frequency; if (frequency_computed > info->frequency_computed && frequency_computed < 1200) { info->frequency_computed = frequency_computed; cgtime(&info->last_computed_increase); } - if (info->eff_5m > 10.0 && info->eff_1m < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { + if (info->asic_type == BM1387 && info->eff_5m > 10.0 && info->eff_1m < opt_gekko_tune_down && info->eff_5m < opt_gekko_tune_down && info->eff_15 < opt_gekko_tune_down && info->eff_wu < opt_gekko_tune_down) { low_eff = 1; } // unhealthy mining condition - if (low_eff & ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10) { + if (low_eff && ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_10) { // only respond when target and peak converges if (ceil(100 * (info->frequency_requested) / 625.0) * 6.25 == ceil(100 * (info->frequency_computed) / 625.0) * 6.25) { // throttle reaction to once per half hour @@ -666,16 +674,31 @@ static void *compac_mine(void *object) } // search for plateau - if (ms_tdiff(&now, &info->monitor_time) > MS_SECOND_5 && ms_tdiff(&now, &info->last_frequency_adjust) > MS_SECOND_5) { + if (ms_tdiff(&now, &last_plateau_check) > MS_SECOND_5) { + cgtime(&last_plateau_check); for (i = 0; i < info->chips; i++) { struct ASIC_INFO *asic = &info->asics[i]; - float old_frequency, new_frequency; + int plateau_type = 0; + + // missing nonces + plateau_type = (ms_tdiff(&now, &asic->last_nonce) > asic->fullscan_ms * 60) ? PT_NONONCE : plateau_type; - if (ms_tdiff(&now, &asic->last_nonce) > asic->fullscan_ms * 60 * info->chips || asic->dups > 3 || asic->frequency_attempt > 10 || ms_tdiff(&now, &asic->last_frequency_reply) > MS_SECOND_30) { + // asic check-in failed + plateau_type = (ms_tdiff(&now, &asic->last_frequency_reply) > MS_SECOND_30) ? PT_FREQNR : plateau_type; + + // getting duplicate nonces + plateau_type = (asic->dups > 3) ? PT_DUPNONCE : plateau_type; + + // set frequency requests not honored + plateau_type = (asic->frequency_attempt > 3) ? PT_FREQSET : plateau_type; + + if (plateau_type) { + float old_frequency, new_frequency; new_frequency = info->frequency_requested; char freq_buf[512]; char freq_chip_buf[10]; + memset(freq_buf, 0, 512); for (j = 0; j < info->chips; j++) { struct ASIC_INFO *asjc = &info->asics[j]; @@ -684,7 +707,7 @@ static void *compac_mine(void *object) } applog(LOG_INFO,"%d: %s %d - %s", compac->cgminer_id, compac->drv->name, compac->device_id, freq_buf); - if (info->nononce_reset < 3) { + if (info->plateau_reset < 3) { // Capture failure high/low frequencies using first three resets if ((info->frequency - 6.25) > info->frequency_fail_high) { info->frequency_fail_high = (info->frequency - 6.25); @@ -692,10 +715,10 @@ static void *compac_mine(void *object) if ((info->frequency - 6.25) < info->frequency_fail_low) { info->frequency_fail_low = (info->frequency - 6.25); } - applog(LOG_WARNING,"%d: %s %d - asic plateau: (%d/3) %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->nononce_reset + 1, info->frequency_fail_high); + applog(LOG_WARNING,"%d: %s %d - asic plateau: (%d/3) %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, info->plateau_reset + 1, info->frequency_fail_high); } - if (info->nononce_reset >= 2) { + if (info->plateau_reset >= 2) { if (ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_30) { // Been running for 30 minutes, possible plateau // Overlook the incident @@ -709,23 +732,30 @@ static void *compac_mine(void *object) new_frequency = info->frequency_fail_high; new_frequency = ceil(100 * (new_frequency) / 625.0) * 6.25; } - info->nononce_reset++; + info->plateau_reset++; asic->last_state = asic->state; asic->state = ASIC_HALFDEAD; cgtime(&asic->state_change_time); cgtime(&info->monitor_time); - if (ms_tdiff(&now, &asic->last_frequency_reply) > MS_SECOND_30) { - applog(info->log_wide,"%d: %s %d - no frequency reply from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); - asic->frequency_attempt = 0; - } else if (asic->frequency_attempt > 10) { - applog(info->log_wide,"%d: %s %d - frequency set fail to chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); - asic->frequency_attempt = 0; - } else if (asic->dups > 3) { - applog(info->log_wide,"%d: %s %d - duplicate nonces from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); - asic->dups = 0; - } else { - applog(info->log_wide,"%d: %s %d - missing nonces from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); + switch (plateau_type) { + case PT_FREQNR: + applog(info->log_wide,"%d: %s %d - no frequency reply from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); + asic->frequency_attempt = 0; + break; + case PT_FREQSET: + applog(info->log_wide,"%d: %s %d - frequency set fail to chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); + asic->frequency_attempt = 0; + break; + case PT_DUPNONCE: + applog(info->log_wide,"%d: %s %d - duplicate nonces from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); + asic->dups = 0; + break; + case PT_NONONCE: + applog(info->log_wide,"%d: %s %d - missing nonces from chip[%d] - %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, i, info->frequency); + break; + default: + break; } old_frequency = info->frequency_requested; @@ -734,14 +764,17 @@ static void *compac_mine(void *object) applog(LOG_WARNING,"%d: %s %d - plateau adjust: target frequency %.2fMHz -> %.2fMHz", compac->cgminer_id, compac->drv->name, compac->device_id, old_frequency, new_frequency); } - info->mining_state = MINER_RESET; + if (plateau_type == PT_NONONCE || info->asic_type == BM1387) { + // BM1384 is less tolerant to sudden drops in frequency. Ignore other indicators except no nonce. + info->mining_state = MINER_RESET; + } break; } } } // move target fequency towards peak frequency, once peak is done increasing. - if (ms_tdiff(&now, &info->last_computed_increase) > MS_MINUTE_10 && info->frequency_computed < info->frequency ) { + if (ms_tdiff(&now, &info->last_computed_increase) > MS_MINUTE_5 && ms_tdiff(&now, &info->last_frequency_adjust) > MS_MINUTE_5 && info->frequency_computed < info->frequency ) { float new_frequency = info->frequency - 6.25; if (new_frequency < info->frequency_computed) { new_frequency = info->frequency_computed; @@ -753,6 +786,11 @@ static void *compac_mine(void *object) cgtime(&info->last_computed_increase); info->frequency_requested = new_frequency; info->frequency_fail_high = new_frequency; + if(info->eff_gs < 90 && info->asic_type == BM1387) { + //hashing is a bit low. clear out settings before changing + info->mining_state = MINER_RESET; + continue; + } } } @@ -762,7 +800,6 @@ static void *compac_mine(void *object) info->frequency_of--; cgtime(&last_movement); bool frequency_updated = 0; - // standard check for ramp up if (info->frequency_of == (info->chips - 1) && info->eff_gs >= opt_gekko_tune_up) { adjustable = 1; @@ -773,6 +810,11 @@ static void *compac_mine(void *object) adjustable = 0; } + // getting garbage frequency reply, hold off. + if (ms_tdiff(&now, &info->last_frequency_invalid) < MS_MINUTE_5) { + adjustable = 0; + } + if (info->frequency_of < 0) { info->frequency_of = info->chips; ping_itr = (ping_itr + 1) % 1; @@ -809,6 +851,10 @@ static void *compac_mine(void *object) if (new_frequency < info->frequency_start) { new_frequency = info->frequency_start; } + // limit to one adjust per 5 seconds if last set failed. + if (new_frequency == asic->frequency_set && ms_tdiff(&now, &asic->last_frequency_adjust) < MS_SECOND_5) { + adjustable = 0; + } if (!adjustable) { new_frequency = asic->frequency; } @@ -928,6 +974,7 @@ static void *compac_handle_rx(void *object, int read_bytes) if (info->asic_type == BM1387 && (info->rx[2] == 0 || (info->rx[3] >> 4) == 0 || (info->rx[3] & 0x0f) == 0)) { dumpbuffer(compac, LOG_INFO, "RX", info->rx, read_bytes); + cgtime(&info->last_frequency_invalid); applog(LOG_INFO,"%d: %s %d - invalid frequency report", compac->cgminer_id, compac->drv->name, compac->device_id); } else { if (info->asic_type == BM1387) { @@ -981,6 +1028,7 @@ static void *compac_handle_rx(void *object, int read_bytes) asic->frequency = info->frequency_default; asic->frequency_attempt = 0; cgtime(&asic->last_nonce); + cgtime(&asic->last_frequency_reply); info->chips++; info->mining_state = MINER_CHIP_COUNT_XX; compac_update_rates(compac); @@ -1147,7 +1195,7 @@ static bool compac_init(struct thr_info *thr) info->fail_count = 0; info->busy_work = 0; info->log_wide = (opt_widescreen) ? LOG_WARNING : LOG_INFO; - info->nononce_reset = 0; + info->plateau_reset = 0; info->low_eff_resets = 0; info->frequency = 200; info->frequency_default = 200; @@ -1172,6 +1220,7 @@ static bool compac_init(struct thr_info *thr) cgtime(&info->last_computed_increase); cgtime(&info->last_low_eff_reset); info->last_frequency_ping = (struct timeval){0}; + info->last_frequency_invalid = (struct timeval){0}; cgtime(&info->last_micro_ping); cgtime(&info->last_scanhash); cgtime(&info->last_reset); @@ -1251,6 +1300,7 @@ static int64_t compac_scanwork(struct thr_info *thr) int read_bytes; uint32_t err = 0; uint64_t hashes = 0; + uint64_t xhashes = 0; uint32_t sleep_us = bound(info->scanhash_ms * 1000, 100, MS_SECOND_1 / 2 * 1000); if (info->chips == 0) @@ -1352,12 +1402,14 @@ static int64_t compac_scanwork(struct thr_info *thr) mutex_lock(&info->lock); hashes = info->hashes; + xhashes = info->xhashes; info->hashes = 0; + info->xhashes = 0; mutex_unlock(&info->lock); - usleep(sleep_us); - - return hashes; + cgsleep_ms(1); + return xhashes * 0xffffffffull; + //return hashes; } static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb_find_devices *found) diff --git a/driver-gekko.h b/driver-gekko.h index c0cd8690d7..b27a4bf9b1 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -33,6 +33,13 @@ enum miner_asic { BM1387 }; +enum plateau_type { + PT_NONONCE = 1, + PT_FREQSET, + PT_FREQNR, + PT_DUPNONCE +}; + enum micro_command { M1_GET_FAN = (0x00 << 3), M1_GET_RPM = (0x01 << 3), @@ -128,7 +135,7 @@ struct COMPAC_INFO { int low_eff_resets; // Count of low_eff resets int nonceless; // Tasks sent. Resets when nonce is found. int nonces; // Nonces found - int nononce_reset; // Count missing nonces + int plateau_reset; // Count plateau based resets int zero_check; // Received nonces from zero work int vcore; // Core voltage int micro_found; // Found a micro to communicate with @@ -147,6 +154,7 @@ struct COMPAC_INFO { uint32_t difficulty; // For computing hashrate uint32_t expected_chips; // Number of chips for device uint64_t hashes; // Hashes completed + uint64_t xhashes; // Hashes completed / 0xffffffffull uint32_t job_id; // JobId incrementer uint32_t log_wide; // Extra output in widescreen mode uint32_t low_hash; // Tracks of low hashrate @@ -172,6 +180,7 @@ struct COMPAC_INFO { struct timeval last_frequency_adjust; // Last time of frequency adjust struct timeval last_frequency_ping; // Last time of frequency poll struct timeval last_frequency_report; // Last change of frequency report + struct timeval last_frequency_invalid; // Last change of frequency report anomaly struct timeval last_chain_inactive; // Last sent chain inactive struct timeval last_low_eff_reset; // Last time responded to low_eff condition struct timeval last_micro_ping; // Last time of micro controller poll From 0d524aae219a42f0da29a1ee9aac4ceb50600f1d Mon Sep 17 00:00:00 2001 From: vthoang Date: Tue, 30 Apr 2019 18:27:37 +0100 Subject: [PATCH 109/113] scan rx buffer to re-align to reply's checksum. set pool's reported vmask to 0 on noboost, drops vmask from mining.submit. --- driver-gekko.c | 87 ++++++++++++++++++++++++++++++++++++++++++-------- driver-gekko.h | 2 ++ 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/driver-gekko.c b/driver-gekko.c index baf15e6151..16ec98d0e3 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -451,7 +451,7 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) info->prev_nonce = nonce; asic->prev_nonce = nonce; - applog(LOG_INFO, "%d: %s %d - Device reported nonce: %08x @ %02x", compac->cgminer_id, compac->drv->name, compac->device_id, nonce, job_id); + applog(LOG_INFO, "%d: %s %d - Device reported nonce: %08x @ %02x (%d)", compac->cgminer_id, compac->drv->name, compac->device_id, nonce, job_id, info->tracker); struct work *work = info->work[job_id]; bool active_work = info->active_work[job_id]; @@ -799,26 +799,31 @@ static void *compac_mine(void *object) info->frequency_of--; cgtime(&last_movement); + info->tracker = info->tracker = 0; bool frequency_updated = 0; // standard check for ramp up if (info->frequency_of == (info->chips - 1) && info->eff_gs >= opt_gekko_tune_up) { adjustable = 1; + info->tracker = info->tracker * 10 + 1; } // seeing dup, hold off. if (ms_tdiff(&now, &info->last_dup_time) < MS_MINUTE_1) { - adjustable = 0; + //adjustable = 0; + info->tracker = info->tracker * 10 + 2; } // getting garbage frequency reply, hold off. if (ms_tdiff(&now, &info->last_frequency_invalid) < MS_MINUTE_5) { adjustable = 0; + info->tracker = info->tracker * 10 + 3; } if (info->frequency_of < 0) { info->frequency_of = info->chips; ping_itr = (ping_itr + 1) % 1; adjustable = 0; + info->tracker = info->tracker * 10 + 4; } else { struct ASIC_INFO *asic = &info->asics[info->frequency_of]; if (ping_itr == 0 && asic->frequency != info->frequency_requested) { @@ -827,20 +832,24 @@ static void *compac_mine(void *object) // catching up after reset if (asic->frequency < info->frequency_computed) { adjustable = 1; + info->tracker = info->tracker * 10 + 5; } // chip speeds aren't matching - special override if (!info->frequency_syncd) { if (asic->frequency >= info->frequency) { adjustable = 0; + info->tracker = info->tracker * 10 + 6; } else { adjustable = 1; + info->tracker = info->tracker * 10 + 7; } } // limit to one adjust per 5 seconds if above peak. if (asic->frequency > info->frequency_computed && ms_tdiff(&now, &asic->last_frequency_adjust) < MS_SECOND_5) { adjustable = 0; + info->tracker = info->tracker * 10 + 8; } if (asic->frequency < info->frequency_requested) { @@ -898,6 +907,9 @@ static void *compac_mine(void *object) work = get_queued(compac); if (work) { + if (opt_gekko_noboost) { + work->pool->vmask = 0; + } info->job_id = (info->job_id + 1) % (info->max_job_id - 3); old_work = info->work[info->job_id]; info->work[info->job_id] = work; @@ -952,7 +964,7 @@ static void *compac_mine(void *object) } } -static void *compac_handle_rx(void *object, int read_bytes) +static void *compac_handle_rx(void *object, int read_bytes, int path) { struct cgpu_info *compac = (struct cgpu_info *)object; struct COMPAC_INFO *info = compac->device_data; @@ -962,10 +974,14 @@ static void *compac_handle_rx(void *object, int read_bytes) cgtime(&now); - cmd_resp = (info->rx[read_bytes - 1] <= 0x1F && bmcrc(info->rx, 8 * read_bytes - 5) == info->rx[read_bytes - 1]) ? 1 : 0; + cmd_resp = (info->rx[read_bytes - 1] <= 0x1f && bmcrc(info->rx, 8 * read_bytes - 5) == info->rx[read_bytes - 1]) ? 1 : 0; int log_level = (cmd_resp) ? LOG_INFO : LOG_INFO; - dumpbuffer(compac, log_level, "RX", info->rx, read_bytes); + if (path) { + dumpbuffer(compac, log_level, "RX1", info->rx, read_bytes); + } else { + dumpbuffer(compac, log_level, "RX0", info->rx, read_bytes); + } if (cmd_resp && info->rx[0] == 0x80) { float frequency; @@ -973,7 +989,6 @@ static void *compac_handle_rx(void *object, int read_bytes) cgtime(&info->last_frequency_report); if (info->asic_type == BM1387 && (info->rx[2] == 0 || (info->rx[3] >> 4) == 0 || (info->rx[3] & 0x0f) == 0)) { - dumpbuffer(compac, LOG_INFO, "RX", info->rx, read_bytes); cgtime(&info->last_frequency_invalid); applog(LOG_INFO,"%d: %s %d - invalid frequency report", compac->cgminer_id, compac->drv->name, compac->device_id); } else { @@ -1061,7 +1076,7 @@ static void *compac_listen(void *object) struct timeval now; unsigned char rx[BUFFER_MAX]; unsigned char *prx = rx; - int read_bytes, cmd_resp, i, pos, rx_bytes; + int read_bytes, cmd_resp, i, j, pos, rx_bytes; uint32_t err = 0; memset(rx, 0, BUFFER_MAX); @@ -1090,6 +1105,7 @@ static void *compac_listen(void *object) } else { err = usb_read_timeout(compac, &rx[pos], info->rx_len, &read_bytes, 20, C_GETRESULTS); rx_bytes += read_bytes; + pos = rx_bytes; } if (read_bytes > 0) { @@ -1097,12 +1113,11 @@ static void *compac_listen(void *object) if (rx_bytes < info->rx_len) { applog(LOG_INFO, "%d: %s %d - Buffered %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, rx_bytes); dumpbuffer(compac, LOG_INFO, "Partial-RX", rx, rx_bytes); - pos = rx_bytes; continue; } if (rx_bytes >= info->rx_len) - cmd_resp = (rx[read_bytes - 1] <= 0x1F && bmcrc(prx, 8 * read_bytes - 5) == rx[read_bytes - 1]) ? 1 : 0; + cmd_resp = (rx[read_bytes - 1] <= 0x1f && bmcrc(prx, 8 * read_bytes - 5) == rx[read_bytes - 1]) ? 1 : 0; if (info->mining_state == MINER_CHIP_COUNT_XX || cmd_resp) { if (rx_bytes % info->rx_len == 2) { @@ -1117,14 +1132,55 @@ static void *compac_listen(void *object) rx[i] = rx[i + shift]; } rx_bytes -= shift; + pos = rx_bytes; applog(LOG_INFO, "%d: %s %d - Extra Data - 0x01 0x%02x", compac->cgminer_id, compac->drv->name, compac->device_id, extra & 0xff); } } - if (rx_bytes % info->rx_len != 0) { + if (rx_bytes >= info->rx_len) { + bool crc_match = false; + int new_pos = 0; + for (i = 0; i <= (int)(rx_bytes - info->rx_len); i++) { + bool rx_okay = false; + + if (bmcrc(&rx[i], 8 * info->rx_len - 5) == (rx[i + info->rx_len - 1] & 0x1f)) { + // crc checksum is good + crc_match = true; + rx_okay = true; + } + if (info->asic_type == BM1384 && rx[i + info->rx_len - 1] >= 0x80 && rx[i + info->rx_len - 1] <= 0x9f) { + // bm1384 nonce + rx_okay = true; + } + if (rx_okay) { + memcpy(info->rx, &rx[i], info->rx_len); + compac_handle_rx(compac, info->rx_len, 0); + new_pos = i + info->rx_len; + } + } + if (new_pos > rx_bytes) { + rx_bytes = 0; + pos = 0; + } else if (new_pos > 0) { + for (i = new_pos; i < rx_bytes; i++) { + rx[i - new_pos] = rx[i]; + } + rx_bytes -= new_pos; + pos = rx_bytes; + } + } + + if (rx_bytes > (BUFFER_MAX - info->rx_len)) { + applog(LOG_INFO, "%d: %s %d - Buffer not useful, dumping (b) %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, rx_bytes); + dumpbuffer(compac, LOG_INFO, "NO-CRC-RX", rx, rx_bytes); + pos = 0; + rx_bytes = 0; + } +/* + if (bmcrc(&rx[rx_bytes - info->rx_len], 8 * info->rx_len - 5) != info->rx[rx_bytes - 1]) { int n_read_bytes; pos = rx_bytes; - err = usb_read_timeout(compac, &rx[pos], BUFFER_MAX - pos, &n_read_bytes, 1, C_GETRESULTS); + err = usb_read_timeout(compac, &rx[pos], BUFFER_MAX - pos, &n_read_bytes, 5, C_GETRESULTS); rx_bytes += n_read_bytes; if (rx_bytes % info->rx_len != 0 && rx_bytes >= info->rx_len) { @@ -1136,19 +1192,21 @@ static void *compac_listen(void *object) applog(LOG_INFO, "%d: %s %d - Fixing buffer alignment, dumping initial %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, extra_bytes); } } - if (rx_bytes % info->rx_len == 0) { for (i = 0; i < rx_bytes; i += info->rx_len) { memcpy(info->rx, &rx[i], info->rx_len); - compac_handle_rx(compac, info->rx_len); + compac_handle_rx(compac, info->rx_len, 1); } pos = 0; rx_bytes = 0; } +*/ } else { - if (rx_bytes > 0) + if (rx_bytes > 0) { applog(LOG_INFO, "%d: %s %d - Second read, no data dumping (c) %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, rx_bytes); + dumpbuffer(compac, LOG_INFO, "EXTRA-RX", rx, rx_bytes); + } pos = 0; rx_bytes = 0; @@ -1470,6 +1528,7 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb info->task_len = 64; info->tx_len = 4; info->healthy = 0.33; + opt_gekko_tune_up = 97; usb_transfer_data(compac, CP210X_TYPE_OUT, CP210X_REQUEST_IFC_ENABLE, CP210X_VALUE_UART_ENABLE, info->interface, NULL, 0, C_ENABLE_UART); usb_transfer_data(compac, CP210X_TYPE_OUT, CP210X_REQUEST_DATA, CP210X_VALUE_DATA, info->interface, NULL, 0, C_SETDATA); diff --git a/driver-gekko.h b/driver-gekko.h index b27a4bf9b1..4ecb2e08c2 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -6,6 +6,7 @@ #define BUFFER_MAX 0xFF #define MS_SECOND_1 1000 #define MS_SECOND_5 1000 * 5 +#define MS_SECOND_15 1000 * 15 #define MS_SECOND_30 1000 * 30 #define MS_MINUTE_1 1000 * 60 #define MS_MINUTE_2 1000 * 60 * 2 @@ -131,6 +132,7 @@ struct COMPAC_INFO { int frequency_of; // Frequency check token int accepted; // Nonces accepted int dups; // Duplicates found + int tracker; // Track code execution path int interface; // USB interface int low_eff_resets; // Count of low_eff resets int nonceless; // Tasks sent. Resets when nonce is found. From ef74c2700e0534b6d2ab744abc021f64e5546fce Mon Sep 17 00:00:00 2001 From: VH Date: Sat, 11 May 2019 15:24:19 +0100 Subject: [PATCH 110/113] Fixed statline overflow. Suspend periodic frequency checks. Step down BM1384 frequency on shutdown. --- cgminer.c | 4 ++ driver-gekko.c | 109 +++++++++++++++++++++++++++++++------------------ driver-gekko.h | 20 +++++---- miner.h | 1 + 4 files changed, 85 insertions(+), 49 deletions(-) diff --git a/cgminer.c b/cgminer.c index 59bae1087f..cbc0ec581f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -307,6 +307,7 @@ float opt_gekko_gsd_freq = 100; float opt_gekko_gse_freq = 150; float opt_gekko_tune_up = 92; float opt_gekko_tune_down = 95; +float opt_gekko_wait_factor = 0; int opt_gekko_gsh_freq = 100; int opt_gekko_gsi_freq = 400; int opt_gekko_gsh_vcore = 400; @@ -1929,6 +1930,9 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--gekko-tune-up", set_float_0_to_500, opt_show_floatval, &opt_gekko_tune_up, "Set GekkoScience miner ramping hash threshold, rante 0-99"), + OPT_WITH_ARG("--gekko-usbwf", + set_float_0_to_500, opt_show_floatval, &opt_gekko_wait_factor, + "Set GekkoScience miner wait factor, range 0.1-10.0"), OPT_WITH_ARG("--gekko-newpac-freq", set_int_0_to_9999, opt_show_intval, &opt_gekko_gsh_freq, "Set GekkoScience NewPac BM1387 frequency in MHz, range 50-900"), diff --git a/driver-gekko.c b/driver-gekko.c index 16ec98d0e3..0915cc84b3 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -4,6 +4,7 @@ #include static bool compac_prepare(struct thr_info *thr); +static bool last_widescreen; static uint8_t dev_init_count[0xffff] = {0}; static uint8_t *init_count; static uint32_t stat_len; @@ -229,6 +230,9 @@ static void compac_update_rates(struct cgpu_info *compac) info->scanhash_ms = info->fullscan_ms * info->difficulty / 4; info->wait_factor = ((!opt_gekko_noboost && info->vmask && info->asic_type == BM1387) ? 1.80 : 0.60); + if (opt_gekko_wait_factor > 0 && info->asic_type == BM1387) { + info->wait_factor = opt_gekko_wait_factor; + } info->max_task_wait = bound(info->wait_factor * info->fullscan_us, 1, 3 * info->fullscan_us); } @@ -296,7 +300,6 @@ static void compac_set_frequency(struct cgpu_info *compac, float frequency) compac_send(compac, (char *)buffer, sizeof(buffer), 8 * sizeof(buffer) - 8); info->frequency = frequency; - info->last_frequency_ping = (struct timeval){0}; } else if (info->asic_type == BM1384) { unsigned char buffer[] = {0x82, 0x0b, 0x83, 0x00}; @@ -581,6 +584,7 @@ static void *compac_mine(void *object) struct timeval now; struct timeval last_movement = (struct timeval){0}; struct timeval last_plateau_check = (struct timeval){0}; + struct timeval last_frequency_check = (struct timeval){0}; struct sched_param param; int i, j, read_bytes, sleep_us, policy, ret_nice, ping_itr; @@ -612,6 +616,7 @@ static void *compac_mine(void *object) double dev_runtime, wu; float frequency_computed; bool low_eff = 0; + bool frequency_updated = 0; info->update_work = 0; @@ -684,7 +689,7 @@ static void *compac_mine(void *object) plateau_type = (ms_tdiff(&now, &asic->last_nonce) > asic->fullscan_ms * 60) ? PT_NONONCE : plateau_type; // asic check-in failed - plateau_type = (ms_tdiff(&now, &asic->last_frequency_reply) > MS_SECOND_30) ? PT_FREQNR : plateau_type; + plateau_type = (ms_tdiff(&asic->last_frequency_ping, &asic->last_frequency_reply) > MS_SECOND_30 && ms_tdiff(&now, &asic->last_frequency_reply) > MS_SECOND_30) ? PT_FREQNR : plateau_type; // getting duplicate nonces plateau_type = (asic->dups > 3) ? PT_DUPNONCE : plateau_type; @@ -795,14 +800,14 @@ static void *compac_mine(void *object) } // move running frequency towards target. - if (ms_tdiff(&now, &last_movement) > 20 && (ms_tdiff(&now, &info->last_frequency_ping) > MS_SECOND_1 || info->frequency_of != info->chips)) { + if (ms_tdiff(&now, &last_movement) > 20 && (ms_tdiff(&now, &info->last_frequency_ping) > MS_SECOND_1 || info->frequency_fo != info->chips)) { - info->frequency_of--; + info->frequency_fo--; cgtime(&last_movement); info->tracker = info->tracker = 0; - bool frequency_updated = 0; + // standard check for ramp up - if (info->frequency_of == (info->chips - 1) && info->eff_gs >= opt_gekko_tune_up) { + if (info->frequency_fo == (info->chips - 1) && info->eff_gs >= info->tune_up) { adjustable = 1; info->tracker = info->tracker * 10 + 1; } @@ -819,13 +824,13 @@ static void *compac_mine(void *object) info->tracker = info->tracker * 10 + 3; } - if (info->frequency_of < 0) { - info->frequency_of = info->chips; + if (info->frequency_fo < 0) { + info->frequency_fo = info->chips; ping_itr = (ping_itr + 1) % 1; adjustable = 0; info->tracker = info->tracker * 10 + 4; } else { - struct ASIC_INFO *asic = &info->asics[info->frequency_of]; + struct ASIC_INFO *asic = &info->asics[info->frequency_fo]; if (ping_itr == 0 && asic->frequency != info->frequency_requested) { float new_frequency; @@ -874,19 +879,28 @@ static void *compac_mine(void *object) cgtime(&info->last_frequency_adjust); cgtime(&asic->last_frequency_adjust); cgtime(&info->monitor_time); + asic->frequency_updated = 1; frequency_updated = 1; if (info->asic_type == BM1387) { - compac_set_frequency_single(compac, new_frequency, info->frequency_of); + compac_set_frequency_single(compac, new_frequency, info->frequency_fo); } else if (info->asic_type == BM1384) { - if (info->frequency_of == 0) { + if (info->frequency_fo == 0) { compac_set_frequency(compac, new_frequency); compac_send_chain_inactive(compac); } } } } + } + } - if (frequency_updated || ms_tdiff(&now, &asic->last_frequency_ping) > MS_SECOND_5) { + if (!frequency_updated && ms_tdiff(&now, &last_frequency_check) > 20) { + cgtime(&last_frequency_check); + for (i = 0; i < info->chips; i++) { + struct ASIC_INFO *asic = &info->asics[i]; + if (asic->frequency_updated) { + asic->frequency_updated = 0; + info->frequency_of = i; if (info->asic_type == BM1387) { unsigned char buffer[] = {0x44, 0x05, 0x00, 0x0C, 0x00}; // PLL_PARAMETER buffer[2] = (0x100 / info->chips) * info->frequency_of; @@ -900,6 +914,7 @@ static void *compac_mine(void *object) cgtime(&info->last_frequency_ping); cgtime(&asic->last_frequency_ping); } + break; } } } @@ -1042,8 +1057,9 @@ static void *compac_handle_rx(void *object, int read_bytes, int path) memset(asic, 0, sizeof(struct ASIC_INFO)); asic->frequency = info->frequency_default; asic->frequency_attempt = 0; + asic->last_frequency_ping = (struct timeval){0}; + asic->last_frequency_reply = (struct timeval){0}; cgtime(&asic->last_nonce); - cgtime(&asic->last_frequency_reply); info->chips++; info->mining_state = MINER_CHIP_COUNT_XX; compac_update_rates(compac); @@ -1103,6 +1119,14 @@ static void *compac_listen(void *object) rx_bytes = read_bytes; info->mining_state = MINER_CHIP_COUNT_XX; } else { + + if (rx_bytes >= (BUFFER_MAX - info->rx_len)) { + applog(LOG_INFO, "%d: %s %d - Buffer not useful, dumping (b) %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, rx_bytes); + dumpbuffer(compac, LOG_INFO, "NO-CRC-RX", rx, rx_bytes); + pos = 0; + rx_bytes = 0; + } + err = usb_read_timeout(compac, &rx[pos], info->rx_len, &read_bytes, 20, C_GETRESULTS); rx_bytes += read_bytes; pos = rx_bytes; @@ -1170,12 +1194,6 @@ static void *compac_listen(void *object) } } - if (rx_bytes > (BUFFER_MAX - info->rx_len)) { - applog(LOG_INFO, "%d: %s %d - Buffer not useful, dumping (b) %d bytes", compac->cgminer_id, compac->drv->name, compac->device_id, rx_bytes); - dumpbuffer(compac, LOG_INFO, "NO-CRC-RX", rx, rx_bytes); - pos = 0; - rx_bytes = 0; - } /* if (bmcrc(&rx[rx_bytes - info->rx_len], 8 * info->rx_len - 5) != info->rx[rx_bytes - 1]) { int n_read_bytes; @@ -1259,7 +1277,7 @@ static bool compac_init(struct thr_info *thr) info->frequency_default = 200; info->frequency_fail_high = 0; info->frequency_fail_low = 999; - info->frequency_of = info->chips; + info->frequency_fo = info->chips; info->scanhash_ms = 10; memset(info->rx, 0, BUFFER_MAX); @@ -1277,7 +1295,6 @@ static bool compac_init(struct thr_info *thr) cgtime(&info->last_frequency_adjust); cgtime(&info->last_computed_increase); cgtime(&info->last_low_eff_reset); - info->last_frequency_ping = (struct timeval){0}; info->last_frequency_invalid = (struct timeval){0}; cgtime(&info->last_micro_ping); cgtime(&info->last_scanhash); @@ -1423,7 +1440,6 @@ static int64_t compac_scanwork(struct thr_info *thr) cgtime(&info->start_time); cgtime(&info->monitor_time); cgtime(&info->last_frequency_adjust); - info->last_frequency_ping = (struct timeval){0}; info->last_dup_time = (struct timeval){0}; cgtime(&info->last_frequency_report); cgtime(&info->last_micro_ping); @@ -1522,13 +1538,6 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb case IDENT_BSE: case IDENT_GSE: info->asic_type = BM1384; - info->cores = 55; - info->max_job_id = 0x1f; - info->rx_len = 5; - info->task_len = 64; - info->tx_len = 4; - info->healthy = 0.33; - opt_gekko_tune_up = 97; usb_transfer_data(compac, CP210X_TYPE_OUT, CP210X_REQUEST_IFC_ENABLE, CP210X_VALUE_UART_ENABLE, info->interface, NULL, 0, C_ENABLE_UART); usb_transfer_data(compac, CP210X_TYPE_OUT, CP210X_REQUEST_DATA, CP210X_VALUE_DATA, info->interface, NULL, 0, C_SETDATA); @@ -1549,12 +1558,19 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb } switch (info->asic_type) { + case BM1384: + info->rx_len = 5; + info->task_len = 64; + info->cores = 55; + info->max_job_id = 0x1f; + info->tune_up = 99; + break; case BM1387: info->rx_len = 7; info->task_len = 54; info->cores = 114; info->max_job_id = 0x7f; - info->healthy = 0.75; + info->tune_up = opt_gekko_tune_up; compac_toggle_reset(compac); break; default: @@ -1665,7 +1681,7 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) sprintf(asic_statline, "found 0 chip(s)"); } - for (i = strlen(asic_statline); i < stat_len + 16; i++) + for (i = strlen(asic_statline); i < stat_len + 15; i++) asic_statline[i] = ' '; tailsprintf(buf, bufsiz, "%s", asic_statline); @@ -1707,44 +1723,51 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) asic_stat[info->chips + 1 + i] = ' '; } - sprintf(ms_stat, "(%.0f/%.0f/%.0f)", info->scanhash_ms, info->task_ms, info->fullscan_ms); + sprintf(ms_stat, "(%.0f:%.0f)", info->task_ms, info->fullscan_ms); uint8_t wuc = (ms_tdiff(&now, &info->last_wu_increase) > MS_MINUTE_1) ? 32 : 94; if (info->eff_gs >= 99.9 && info->eff_wu >= 98.9) { - sprintf(eff_stat, "| 100.0%% WU:100%%"); + sprintf(eff_stat, "| 100%% WU:100%%"); + } else if (info->eff_gs >= 99.9) { + sprintf(eff_stat, "| 100%% WU:%c%2.0f%%", wuc, info->eff_wu); } else if (info->eff_wu >= 98.9) { - sprintf(eff_stat, "| %5.1f%% WU:100%%", info->eff_gs); + sprintf(eff_stat, "| %4.1f%% WU:100%%", info->eff_gs); } else { - sprintf(eff_stat, "| %5.1f%% WU:%c%2.0f%%", info->eff_gs, wuc, info->eff_wu); + sprintf(eff_stat, "| %4.1f%% WU:%c%2.0f%%", info->eff_gs, wuc, info->eff_wu); } if (info->asic_type == BM1387) { if (info->micro_found) { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.0f P:%.0f (%d/%d/%d/%.0fF)", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, info->scanhash_ms, info->task_ms, info->fullscan_ms, info->micro_temp); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%.0f P:%.0f %s %.0fF", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, info->micro_temp); } else { if (opt_widescreen) { sprintf(asic_statline, "BM1387:%02d%-1s %.0f/%.0f/%3.0f %s %s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat); } else { - sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%-3.0f P:%-3.0f %-13s %s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat); + sprintf(asic_statline, "BM1387:%02d%-1s %.2fMHz T:%-3.0f P:%-3.0f %s %s", info->chips, ab, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat); } } } else { if (opt_widescreen) { sprintf(asic_statline, "BM1384:%02d %.0f/%.0f/%.0f %s %s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat); } else { - sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%-3.0f P:%-3.0f %-13s %s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat); + sprintf(asic_statline, "BM1384:%02d %.2fMHz T:%-3.0f P:%-3.0f %s %s", info->chips, info->frequency, info->frequency_requested, info->frequency_computed, ms_stat, asic_stat); } } len = strlen(asic_statline); - if (len > stat_len) + if (len > stat_len || opt_widescreen != last_widescreen) { stat_len = len; + last_widescreen = opt_widescreen; + } for (i = len; i < stat_len; i++) asic_statline[i] = ' '; - tailsprintf(buf, bufsiz, "%s%s", asic_statline, eff_stat); + strcat(asic_statline, eff_stat); + asic_statline[63] = 0; + + tailsprintf(buf, bufsiz, "%s", asic_statline); } static struct api_data *compac_api_stats(struct cgpu_info *compac) @@ -1770,6 +1793,12 @@ static void compac_shutdown(struct thr_info *thr) compac_micro_send(compac, M2_SET_VCORE, 0x00, 0x00); // 300mV compac_toggle_reset(compac); } else if (info->asic_type == BM1384 && info->frequency != info->frequency_default) { + float frequency = info->frequency - 25; + while (frequency > info->frequency_default) { + compac_set_frequency(compac, frequency); + frequency -= 25; + cgsleep_ms(100); + } compac_set_frequency(compac, info->frequency_default); compac_send_chain_inactive(compac); } diff --git a/driver-gekko.h b/driver-gekko.h index 4ecb2e08c2..da54e36972 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -71,6 +71,7 @@ struct ASIC_INFO { struct timeval last_nonce; // Last time nonce was found float frequency; // Current frequency float frequency_set; // set_frequency + bool frequency_updated; // Initiate check for new frequency uint32_t frequency_attempt; // attempts of set_frequency uint32_t dups; // Duplicate nonce counter enum asic_state state; @@ -105,14 +106,15 @@ struct COMPAC_INFO { float frequency_fail_high; // Highest Frequency of Chip Failure float frequency_fail_low; // Lowest Frequency of Chip Failure float frequency_computed; // Highest hashrate seen as a frequency value - float healthy; // Lower percentile before tagging asic unhealthy - float eff_gs; - float eff_tm; - float eff_li; - float eff_1m; - float eff_5m; - float eff_15; - float eff_wu; + float eff_gs; // hash : expected hash + float eff_tm; // hash : expected hash + float eff_li; // hash : expected hash + float eff_1m; // hash : expected hash + float eff_5m; // hash : expected hash + float eff_15; // hash : expected hash + float eff_wu; // wu : expected wu + float tune_up; // Increase frequency when eff_gs is above value + float tune_down; // Decrease frequency when eff_gs is below value float micro_temp; // Micro Reported Temp float wait_factor; // Used to compute max_task_wait @@ -129,6 +131,7 @@ struct COMPAC_INFO { int failing; // Flag failing sticks int fail_count; // Track failures. + int frequency_fo; // Frequency check token int frequency_of; // Frequency check token int accepted; // Nonces accepted int dups; // Duplicates found @@ -166,7 +169,6 @@ struct COMPAC_INFO { uint32_t rx_len; // rx length uint32_t task_len; // task length uint32_t ticket_mask; // Used to reduce flashes per second - uint32_t tx_len; // tx length uint32_t update_work; // Notification of work update struct timeval start_time; // Device startup time diff --git a/miner.h b/miner.h index fe6b4f4a07..a407f8d40d 100644 --- a/miner.h +++ b/miner.h @@ -1052,6 +1052,7 @@ extern float opt_gekko_gsd_freq; extern float opt_gekko_gse_freq; extern float opt_gekko_tune_down; extern float opt_gekko_tune_up; +extern float opt_gekko_wait_factor; extern int opt_gekko_gsh_freq; extern int opt_gekko_gsi_freq; extern int opt_gekko_gsh_vcore; From a62385f5cd76ce5f0bf6fea6d9ba8691d6fffb0f Mon Sep 17 00:00:00 2001 From: VH Date: Mon, 13 May 2019 21:41:07 +0100 Subject: [PATCH 111/113] AB option to use 2 instead of 4 midstate. ignore stray 0x80 message in frequency detect. add some mutex locking --- cgminer.c | 4 ++++ driver-gekko.c | 51 ++++++++++++++++++++++++++++++++++---------------- driver-gekko.h | 3 +++ miner.h | 1 + util.c | 7 ++++++- 5 files changed, 49 insertions(+), 17 deletions(-) diff --git a/cgminer.c b/cgminer.c index cbc0ec581f..6f6bf40ac2 100644 --- a/cgminer.c +++ b/cgminer.c @@ -297,6 +297,7 @@ int opt_bet_clk = 0; #ifdef USE_GEKKO char *opt_gekko_serial = NULL; bool opt_gekko_noboost = 0; +bool opt_gekko_lowboost = 0; bool opt_gekko_gsc_detect = 0; bool opt_gekko_gsd_detect = 0; bool opt_gekko_gse_detect = 0; @@ -1915,6 +1916,9 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--gekko-noboost", opt_set_bool, &opt_gekko_noboost, "Disable GekkoScience NewPac/R606 AsicBoost"), + OPT_WITHOUT_ARG("--gekko-lowboost", + opt_set_bool, &opt_gekko_lowboost, + "GekkoScience NewPac/R606 AsicBoost - 2 midstate"), OPT_WITH_ARG("--gekko-terminus-freq", set_float_0_to_500, opt_show_floatval, &opt_gekko_gse_freq, "Set GekkoScience Terminus BM1384 frequency in MHz, range 6.25-500"), diff --git a/driver-gekko.c b/driver-gekko.c index 0915cc84b3..f48e63d45a 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -4,6 +4,7 @@ #include static bool compac_prepare(struct thr_info *thr); +static pthread_mutex_t static_lock = PTHREAD_MUTEX_INITIALIZER; static bool last_widescreen; static uint8_t dev_init_count[0xffff] = {0}; static uint8_t *init_count; @@ -205,12 +206,14 @@ static void compac_update_rates(struct cgpu_info *compac) float average_frequency = 0; int i; + info->frequency_asic = 0; for (i = 0; i < info->chips; i++) { asic = &info->asics[i]; asic->hashrate = asic->frequency * info->cores * 1000000; asic->fullscan_ms = 1000.0 * 0xffffffffull / asic->hashrate; asic->fullscan_us = 1000.0 * 1000.0 * 0xffffffffull / asic->hashrate; average_frequency += asic->frequency; + info->frequency_asic = (asic->frequency > info->frequency_asic ) ? asic->frequency : info->frequency_asic; } average_frequency = average_frequency / info->chips; @@ -229,7 +232,7 @@ static void compac_update_rates(struct cgpu_info *compac) info->difficulty = info->ticket_mask + 1; info->scanhash_ms = info->fullscan_ms * info->difficulty / 4; - info->wait_factor = ((!opt_gekko_noboost && info->vmask && info->asic_type == BM1387) ? 1.80 : 0.60); + info->wait_factor = ((!opt_gekko_noboost && info->vmask && info->asic_type == BM1387) ? 0.60 * info->midstates : 0.60); if (opt_gekko_wait_factor > 0 && info->asic_type == BM1387) { info->wait_factor = opt_gekko_wait_factor; } @@ -462,7 +465,7 @@ static uint64_t compac_check_nonce(struct cgpu_info *compac) if (!opt_gekko_noboost && info->vmask) { // force check last few nonces by [job_id - 1] if (info->asic_type == BM1387) { - for (i = 0; i <= 3; i++) { + for (i = 0; i < info->midstates; i++) { if (job_id >= i) { if (info->active_work[job_id - i]) { work = info->work[job_id - i]; @@ -547,15 +550,18 @@ static void init_task(struct COMPAC_INFO *info) info->task[0] = 0x21; info->task[1] = info->task_len; info->task[2] = info->job_id & 0xff; - info->task[3] = ((!opt_gekko_noboost && info->vmask) ? 0x04 : 0x01); + info->task[3] = ((!opt_gekko_noboost && info->vmask) ? info->midstates : 0x01); if (info->mining_state == MINER_MINING) { stuff_reverse(info->task + 8, work->data + 64, 12); stuff_reverse(info->task + 20, work->midstate, 32); if (!opt_gekko_noboost && info->vmask) { - stuff_reverse(info->task + 20 + 32, work->midstate1, 32); - stuff_reverse(info->task + 20 + 32 + 32, work->midstate2, 32); - stuff_reverse(info->task + 20 + 32 + 32 + 32, work->midstate3, 32); + if (info->midstates > 1); + stuff_reverse(info->task + 20 + 32, work->midstate1, 32); + if (info->midstates > 2); + stuff_reverse(info->task + 20 + 32 + 32, work->midstate2, 32); + if (info->midstates > 3); + stuff_reverse(info->task + 20 + 32 + 32 + 32, work->midstate3, 32); } } else { memset(info->task + 8, 0xff, 12); @@ -859,6 +865,9 @@ static void *compac_mine(void *object) if (asic->frequency < info->frequency_requested) { new_frequency = asic->frequency + opt_gekko_step_freq; + if (new_frequency < info->frequency_asic) { + new_frequency = info->frequency_asic; + } if (new_frequency > info->frequency_requested) { new_frequency = info->frequency_requested; } @@ -932,7 +941,7 @@ static void *compac_mine(void *object) info->vmask = work->pool->vmask; if (info->asic_type == BM1387) { if (!opt_gekko_noboost && info->vmask) { - info->task_len = 150; + info->task_len = 54 + 32 * (info->midstates - 1); } else { info->task_len = 54; } @@ -998,12 +1007,13 @@ static void *compac_handle_rx(void *object, int read_bytes, int path) dumpbuffer(compac, log_level, "RX0", info->rx, read_bytes); } - if (cmd_resp && info->rx[0] == 0x80) { + if (cmd_resp && info->rx[0] == 0x80 && info->frequency_of != info->chips) { float frequency; int frequency_of = info->frequency_of; + info->frequency_of = info->chips; cgtime(&info->last_frequency_report); - if (info->asic_type == BM1387 && (info->rx[2] == 0 || (info->rx[3] >> 4) == 0 || (info->rx[3] & 0x0f) == 0)) { + if (info->asic_type == BM1387 && (info->rx[2] == 0 || (info->rx[3] >> 4) == 0 || (info->rx[3] & 0x0f) != 1 || (info->rx[4]) != 0 || (info->rx[5]) != 0)) { cgtime(&info->last_frequency_invalid); applog(LOG_INFO,"%d: %s %d - invalid frequency report", compac->cgminer_id, compac->drv->name, compac->device_id); } else { @@ -1246,7 +1256,10 @@ static void *compac_listen(void *object) applog(LOG_INFO, "%d: %s %d - found %d chip(s)", compac->cgminer_id, compac->drv->name, compac->device_id, info->chips); if (info->chips > 0) { info->mining_state = MINER_CHIP_COUNT_OK; + mutex_lock(&static_lock); (*init_count) = 0; + info->init_count = 0; + mutex_unlock(&static_lock); } else { info->mining_state = MINER_RESET; } @@ -1570,6 +1583,7 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb info->task_len = 54; info->cores = 114; info->max_job_id = 0x7f; + info->midstates = (opt_gekko_lowboost) ? 2 : 4; info->tune_up = opt_gekko_tune_up; compac_toggle_reset(compac); break; @@ -1607,15 +1621,18 @@ static bool compac_prepare(struct thr_info *thr) int i; int read_bytes = 1; bool miner_ok = true; - int device = compac->usbinfo.bus_number * 0xff + compac->usbinfo.device_address; + int device = (compac->usbinfo.bus_number * 0xff + compac->usbinfo.device_address) % 0xffff; + mutex_lock(&static_lock); init_count = &dev_init_count[device]; (*init_count)++; + info->init_count = (*init_count); + mutex_unlock(&static_lock); - if ((*init_count) == 1) { + if (info->init_count == 1) { applog(LOG_WARNING, "%d: %s %d - %s (%s)", compac->cgminer_id, compac->drv->name, compac->device_id, compac->usbdev->prod_string, compac->unique_id); } else { - applog(LOG_INFO, "%d: %s %d - init_count %d", compac->cgminer_id, compac->drv->name, compac->device_id, *init_count); + applog(LOG_INFO, "%d: %s %d - init_count %d", compac->cgminer_id, compac->drv->name, compac->device_id, info->init_count); } info->thr = thr; @@ -1644,11 +1661,11 @@ static bool compac_prepare(struct thr_info *thr) } - if ((*init_count) != 0 && (*init_count) % 5 == 0) { + if (info->init_count != 0 && info->init_count % 5 == 0) { applog(LOG_INFO, "%d: %s %d - forcing usb_nodev()", compac->cgminer_id, compac->drv->name, compac->device_id); usb_nodev(compac); - } else if ((*init_count) > 1) { - if ((*init_count) > 10) { + } else if (info->init_count > 1) { + if (info->init_count > 10) { compac->deven = DEV_DISABLED; } else { cgsleep_ms(MS_SECOND_5); @@ -1677,7 +1694,7 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) memset(eff_stat, 0, 64); if (info->chips == 0) { - if ((*init_count) > 1) { + if (info->init_count > 1) { sprintf(asic_statline, "found 0 chip(s)"); } @@ -1757,8 +1774,10 @@ static void compac_statline(char *buf, size_t bufsiz, struct cgpu_info *compac) len = strlen(asic_statline); if (len > stat_len || opt_widescreen != last_widescreen) { + mutex_lock(&static_lock); stat_len = len; last_widescreen = opt_widescreen; + mutex_unlock(&static_lock); } for (i = len; i < stat_len; i++) diff --git a/driver-gekko.h b/driver-gekko.h index da54e36972..7a19f5afb1 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -100,6 +100,7 @@ struct COMPAC_INFO { pthread_mutex_t rlock; // Mutex Serialize Reads float frequency; // Chip Average Frequency + float frequency_asic; // Highest of current asics. float frequency_default; // ASIC Frequency on RESET float frequency_requested; // Requested Frequency float frequency_start; // Starting Frequency @@ -137,7 +138,9 @@ struct COMPAC_INFO { int dups; // Duplicates found int tracker; // Track code execution path int interface; // USB interface + int init_count; // USB interface initialization counter int low_eff_resets; // Count of low_eff resets + int midstates; // Number of midstates int nonceless; // Tasks sent. Resets when nonce is found. int nonces; // Nonces found int plateau_reset; // Count plateau based resets diff --git a/miner.h b/miner.h index a407f8d40d..ebde919307 100644 --- a/miner.h +++ b/miner.h @@ -1042,6 +1042,7 @@ extern char *opt_bitburner_fury_options; #ifdef USE_GEKKO extern char *opt_gekko_serial; extern bool opt_gekko_noboost; +extern bool opt_gekko_lowboost; extern bool opt_gekko_gsc_detect; extern bool opt_gekko_gsd_detect; extern bool opt_gekko_gse_detect; diff --git a/util.c b/util.c index 543aca119f..10643c3d8b 100644 --- a/util.c +++ b/util.c @@ -3226,7 +3226,7 @@ bool initiate_stratum(struct pool *pool) /* Attempt to configure stratum protocol feature set first. */ #ifdef USE_GEKKO configure_stratum_mining(pool); - if (!pool->stratum_active) { + if (!pool->sock) { //repair damage done by configure_stratum_mining if (!setup_stratum_socket(pool)) { sockd = false; @@ -3234,6 +3234,11 @@ bool initiate_stratum(struct pool *pool) } sockd = true; + + if (recvd) { + /* Get rid of any crap lying around if we're resending */ + clear_sock(pool); + } } #else if (!configure_stratum_mining(pool)) From d76cd8a54e113122fb7d4c30ee524f199f10407b Mon Sep 17 00:00:00 2001 From: VH Date: Mon, 27 May 2019 01:36:55 +0100 Subject: [PATCH 112/113] adjust wait_factor for noboost (improve speed), adjust bauddiv for WIN32 (AB-4), fix buffer overrun, change frequency_computed formula --- cgminer.c | 18 ++++++---- driver-gekko.c | 95 +++++++++++++++++++++++++++++++++++++------------- driver-gekko.h | 6 ++-- miner.h | 3 +- 4 files changed, 88 insertions(+), 34 deletions(-) diff --git a/cgminer.c b/cgminer.c index 6f6bf40ac2..ffc4d1f154 100644 --- a/cgminer.c +++ b/cgminer.c @@ -306,14 +306,15 @@ bool opt_gekko_gsi_detect = 0; float opt_gekko_gsc_freq = 150; float opt_gekko_gsd_freq = 100; float opt_gekko_gse_freq = 150; -float opt_gekko_tune_up = 92; +float opt_gekko_tune_up = 97; float opt_gekko_tune_down = 95; -float opt_gekko_wait_factor = 0; +float opt_gekko_wait_factor = 0.5; +float opt_gekko_step_freq = 6.25; int opt_gekko_gsh_freq = 100; -int opt_gekko_gsi_freq = 400; +int opt_gekko_gsi_freq = 550; +int opt_gekko_bauddiv = 0; int opt_gekko_gsh_vcore = 400; int opt_gekko_start_freq = 100; -int opt_gekko_step_freq = 6; int opt_gekko_step_delay = 15; #endif #ifdef USE_HASHRATIO @@ -1934,9 +1935,12 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--gekko-tune-up", set_float_0_to_500, opt_show_floatval, &opt_gekko_tune_up, "Set GekkoScience miner ramping hash threshold, rante 0-99"), - OPT_WITH_ARG("--gekko-usbwf", + OPT_WITH_ARG("--gekko-wait-factor", set_float_0_to_500, opt_show_floatval, &opt_gekko_wait_factor, - "Set GekkoScience miner wait factor, range 0.1-10.0"), + "Set GekkoScience miner task send wait factor, range 0.01-1.00"), + OPT_WITH_ARG("--gekko-bauddiv", + set_int_0_to_9999, opt_show_intval, &opt_gekko_bauddiv, + "Set GekkoScience BM1387 baud divider {0: auto, 1: 1.5M, 7: 375K, 13: 214K, 25: 115K}"), OPT_WITH_ARG("--gekko-newpac-freq", set_int_0_to_9999, opt_show_intval, &opt_gekko_gsh_freq, "Set GekkoScience NewPac BM1387 frequency in MHz, range 50-900"), @@ -1947,7 +1951,7 @@ static struct opt_table opt_config_table[] = { set_int_0_to_9999, opt_show_intval, &opt_gekko_start_freq, "Ramp start frequency MHz 25-500"), OPT_WITH_ARG("--gekko-step-freq", - set_int_0_to_9999, opt_show_intval, &opt_gekko_step_freq, + set_float_0_to_500, opt_show_intval, &opt_gekko_step_freq, "Ramp frequency step MHz 1-100"), OPT_WITH_ARG("--gekko-step-delay", set_int_0_to_9999, opt_show_intval, &opt_gekko_step_delay, diff --git a/driver-gekko.c b/driver-gekko.c index f48e63d45a..d42b9d88dc 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -167,7 +167,16 @@ static void compac_send_chain_inactive(struct cgpu_info *compac) cgsleep_ms(10); unsigned char baudrate[] = { 0x58, 0x09, 0x00, 0x1C, 0x00, 0x20, 0x07, 0x00, 0x19 }; - info->bauddiv = 0x01; // 1.5Mbps baud. + if (opt_gekko_bauddiv) { + info->bauddiv = opt_gekko_bauddiv; + } else { + info->bauddiv = 0x01; // 1.5Mbps baud. +#ifdef WIN32 + if (info->midstates == 4) + info->bauddiv = 0x0D; // 214Kbps baud. +#endif + } + applog(LOG_INFO, "%d: %s %d - setting bauddiv : %02x", compac->cgminer_id, compac->drv->name, compac->device_id, info->bauddiv); baudrate[6] = info->bauddiv; compac_send(compac, (char *)baudrate, sizeof(baudrate), 8 * sizeof(baudrate) - 8); cgsleep_ms(10); @@ -232,12 +241,18 @@ static void compac_update_rates(struct cgpu_info *compac) info->difficulty = info->ticket_mask + 1; info->scanhash_ms = info->fullscan_ms * info->difficulty / 4; - info->wait_factor = ((!opt_gekko_noboost && info->vmask && info->asic_type == BM1387) ? 0.60 * info->midstates : 0.60); - if (opt_gekko_wait_factor > 0 && info->asic_type == BM1387) { - info->wait_factor = opt_gekko_wait_factor; - } + info->wait_factor = ((!opt_gekko_noboost && info->vmask && info->asic_type == BM1387) ? opt_gekko_wait_factor * info->midstates : opt_gekko_wait_factor); info->max_task_wait = bound(info->wait_factor * info->fullscan_us, 1, 3 * info->fullscan_us); + if (info->asic_type == BM1387) { + if (opt_gekko_tune_up > 95) { + info->tune_up = 100.0 * ((info->frequency - 6.25 * (600 / info->frequency)) / info->frequency); + } else { + info->tune_up = opt_gekko_tune_up; + } + } else { + info->tune_up = 99; + } } static void compac_set_frequency_single(struct cgpu_info *compac, float frequency, int asic_id) @@ -588,6 +603,7 @@ static void *compac_mine(void *object) struct work *old_work = NULL; struct timeval now; + struct timeval last_rolling = (struct timeval){0}; struct timeval last_movement = (struct timeval){0}; struct timeval last_plateau_check = (struct timeval){0}; struct timeval last_frequency_check = (struct timeval){0}; @@ -595,7 +611,9 @@ static void *compac_mine(void *object) struct sched_param param; int i, j, read_bytes, sleep_us, policy, ret_nice, ping_itr; uint32_t err = 0; + uint32_t itr = 0; uint64_t hashes = 0; + double rolling_minute[SAMPLE_SIZE] = {0}; char str_frequency[1024]; bool adjustable = 0; @@ -618,7 +636,7 @@ static void *compac_mine(void *object) if (info->chips == 0 || compac->deven == DEV_DISABLED || compac->usbinfo.nodev || info->mining_state != MINER_MINING) { cgsleep_ms(10); } else if (info->update_work || (us_tdiff(&now, &info->last_task) > info->max_task_wait)) { - uint64_t hashrate_15, hashrate_5m, hashrate_1m, hashrate_li, hashrate_tm; + uint64_t hashrate_15, hashrate_5m, hashrate_1m, hashrate_li, hashrate_tm, hashrate_gs; double dev_runtime, wu; float frequency_computed; bool low_eff = 0; @@ -626,7 +644,7 @@ static void *compac_mine(void *object) info->update_work = 0; - sleep_us = bound(ceil(info->max_task_wait / 10), 1, 1000 * 1000); + sleep_us = bound(ceil(info->max_task_wait / 100), 1, 1000 * 1000); dev_runtime = cgpu_runtime(compac); wu = compac->diff1 / dev_runtime * 60; @@ -636,12 +654,28 @@ static void *compac_mine(void *object) cgtime(&info->last_wu_increase); } + if (ms_tdiff(&now, &last_rolling) > MS_SECOND_1 * 60.0 / SAMPLE_SIZE) { + double new_rolling = 0; + double high_rolling = 0; + cgtime(&last_rolling); + rolling_minute[itr] = compac->rolling; + itr = (itr + 1) % SAMPLE_SIZE; + for (i = 0; i < SAMPLE_SIZE; i++) { + high_rolling = (rolling_minute[i] != 0) ? rolling_minute[i] : high_rolling; + new_rolling += high_rolling; + } + new_rolling /= SAMPLE_SIZE; + info->rolling = new_rolling; + } + + hashrate_gs = (double)info->rolling * 1000000ull; hashrate_li = (double)compac->rolling * 1000000ull; hashrate_1m = (double)compac->rolling1 * 1000000ull; hashrate_5m = (double)compac->rolling5 * 1000000ull; hashrate_15 = (double)compac->rolling15 * 1000000ull; hashrate_tm = (double)compac->total_mhashes / dev_runtime * 1000000ull;; + info->eff_gs = 100.0 * (1.0 * hashrate_gs / info->hashrate); info->eff_li = 100.0 * (1.0 * hashrate_li / info->hashrate); info->eff_1m = 100.0 * (1.0 * hashrate_1m / info->hashrate); info->eff_5m = 100.0 * (1.0 * hashrate_5m / info->hashrate); @@ -649,6 +683,7 @@ static void *compac_mine(void *object) info->eff_wu = 100.0 * (1.0 * wu / info->wu); info->eff_tm = 100.0 * (1.0 * hashrate_tm / info->hashrate); + info->eff_gs = (info->eff_gs > 100) ? 100 : info->eff_gs; info->eff_li = (info->eff_li > 100) ? 100 : info->eff_li; info->eff_1m = (info->eff_1m > 100) ? 100 : info->eff_1m; info->eff_5m = (info->eff_5m > 100) ? 100 : info->eff_5m; @@ -656,12 +691,13 @@ static void *compac_mine(void *object) info->eff_wu = (info->eff_wu > 100) ? 100 : info->eff_wu; info->eff_tm = (info->eff_tm > 100) ? 100 : info->eff_tm; - info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; + //info->eff_gs = (((info->eff_tm > info->eff_1m) ? info->eff_tm : info->eff_1m) * 3 + info->eff_li) / 4; + frequency_computed = ((hashrate_gs / 1000000.0) / info->cores) / info->chips; //frequency_computed = ((hashrate_5m / 1000000.0) / info->cores) / info->chips; //frequency_computed = info->eff_gs / 100.0 * info->frequency; - frequency_computed = ((info->eff_tm > info->eff_5m) ? info->eff_tm : ((info->eff_5m + info->eff_1m) / 2)) / 100.0 * info->frequency; - if (frequency_computed > info->frequency_computed && frequency_computed < 1200) { + //frequency_computed = ((info->eff_tm > info->eff_5m) ? info->eff_tm : ((info->eff_5m + info->eff_1m) / 2)) / 100.0 * info->frequency; + if (frequency_computed > info->frequency_computed && frequency_computed <= info->frequency) { info->frequency_computed = frequency_computed; cgtime(&info->last_computed_increase); } @@ -708,9 +744,10 @@ static void *compac_mine(void *object) new_frequency = info->frequency_requested; char freq_buf[512]; - char freq_chip_buf[10]; + char freq_chip_buf[15]; memset(freq_buf, 0, 512); + memset(freq_chip_buf, 0, 15); for (j = 0; j < info->chips; j++) { struct ASIC_INFO *asjc = &info->asics[j]; sprintf(freq_chip_buf, "[%d:%.2f]", j, asjc->frequency); @@ -825,7 +862,7 @@ static void *compac_mine(void *object) } // getting garbage frequency reply, hold off. - if (ms_tdiff(&now, &info->last_frequency_invalid) < MS_MINUTE_5) { + if (ms_tdiff(&now, &info->last_frequency_invalid) < MS_MINUTE_1) { adjustable = 0; info->tracker = info->tracker * 10 + 3; } @@ -846,34 +883,42 @@ static void *compac_mine(void *object) info->tracker = info->tracker * 10 + 5; } + // startup exception + if (asic->frequency < info->frequency_start) { + adjustable = 1; + info->tracker = info->tracker * 10 + 6; + } + // chip speeds aren't matching - special override if (!info->frequency_syncd) { if (asic->frequency >= info->frequency) { adjustable = 0; - info->tracker = info->tracker * 10 + 6; + info->tracker = info->tracker * 10 + 7; } else { adjustable = 1; - info->tracker = info->tracker * 10 + 7; + info->tracker = info->tracker * 10 + 8; } } - // limit to one adjust per 5 seconds if above peak. - if (asic->frequency > info->frequency_computed && ms_tdiff(&now, &asic->last_frequency_adjust) < MS_SECOND_5) { + // limit to one adjust per 1 seconds if above peak. + if (asic->frequency > info->frequency_computed && ms_tdiff(&now, &asic->last_frequency_adjust) < MS_SECOND_1) { adjustable = 0; - info->tracker = info->tracker * 10 + 8; + info->tracker = info->tracker * 10 + 9; } if (asic->frequency < info->frequency_requested) { - new_frequency = asic->frequency + opt_gekko_step_freq; if (new_frequency < info->frequency_asic) { new_frequency = info->frequency_asic; + } else { + new_frequency = asic->frequency + opt_gekko_step_freq; } if (new_frequency > info->frequency_requested) { new_frequency = info->frequency_requested; } - if (new_frequency < info->frequency_start) { - new_frequency = info->frequency_start; - } + //if (new_frequency < info->frequency_start) { + //new_frequency = info->frequency_start; + //new_frequency = asic->frequency + opt_gekko_step_freq; + //} // limit to one adjust per 5 seconds if last set failed. if (new_frequency == asic->frequency_set && ms_tdiff(&now, &asic->last_frequency_adjust) < MS_SECOND_5) { adjustable = 0; @@ -1338,7 +1383,11 @@ static bool compac_init(struct thr_info *thr) break; case IDENT_GSI: info->frequency_requested = opt_gekko_gsi_freq; - info->frequency_start = opt_gekko_start_freq; + if (opt_gekko_start_freq == 100) { + info->frequency_start = 550; + } else { + info->frequency_start = opt_gekko_start_freq; + } break; default: info->frequency_requested = 200; @@ -1576,7 +1625,6 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb info->task_len = 64; info->cores = 55; info->max_job_id = 0x1f; - info->tune_up = 99; break; case BM1387: info->rx_len = 7; @@ -1584,7 +1632,6 @@ static struct cgpu_info *compac_detect_one(struct libusb_device *dev, struct usb info->cores = 114; info->max_job_id = 0x7f; info->midstates = (opt_gekko_lowboost) ? 2 : 4; - info->tune_up = opt_gekko_tune_up; compac_toggle_reset(compac); break; default: diff --git a/driver-gekko.h b/driver-gekko.h index 7a19f5afb1..631dc2fdb4 100644 --- a/driver-gekko.h +++ b/driver-gekko.h @@ -2,8 +2,9 @@ #include "miner.h" #include "usbutils.h" -#define JOB_MAX 0x7F -#define BUFFER_MAX 0xFF +#define JOB_MAX 0x7F +#define BUFFER_MAX 0xFF +#define SAMPLE_SIZE 0x78 #define MS_SECOND_1 1000 #define MS_SECOND_5 1000 * 5 #define MS_SECOND_15 1000 * 15 @@ -155,6 +156,7 @@ struct COMPAC_INFO { double wu; double wu_max; // Max WU since last frequency change + double rolling; uint32_t bauddiv; // Baudrate divider uint32_t chips; // Stores number of chips found diff --git a/miner.h b/miner.h index ebde919307..9aad106447 100644 --- a/miner.h +++ b/miner.h @@ -1054,11 +1054,12 @@ extern float opt_gekko_gse_freq; extern float opt_gekko_tune_down; extern float opt_gekko_tune_up; extern float opt_gekko_wait_factor; +extern float opt_gekko_step_freq; +extern int opt_gekko_bauddiv; extern int opt_gekko_gsh_freq; extern int opt_gekko_gsi_freq; extern int opt_gekko_gsh_vcore; extern int opt_gekko_start_freq; -extern int opt_gekko_step_freq; extern int opt_gekko_step_delay; #endif #ifdef USE_KLONDIKE From 9e51f0b52ac3a76fb392e9f5994da0c62e94cbc1 Mon Sep 17 00:00:00 2001 From: VH Date: Mon, 27 May 2019 03:05:10 +0100 Subject: [PATCH 113/113] wait for chips to converge at current frequency --- driver-gekko.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-gekko.c b/driver-gekko.c index d42b9d88dc..1c0004018a 100644 --- a/driver-gekko.c +++ b/driver-gekko.c @@ -894,7 +894,7 @@ static void *compac_mine(void *object) if (asic->frequency >= info->frequency) { adjustable = 0; info->tracker = info->tracker * 10 + 7; - } else { + } else if (asic->frequency < info->frequency_asic) { adjustable = 1; info->tracker = info->tracker * 10 + 8; }