|
|
@@ -148,6 +148,7 @@ static const char *MODE_UNKNOWN_STR = "unknown";
|
|
|
|
|
|
BFG_REGISTER_DRIVER(icarus_drv)
|
|
|
extern const struct bfg_set_device_definition icarus_set_device_funcs[];
|
|
|
+extern const struct bfg_set_device_definition icarus_set_device_funcs_live[];
|
|
|
|
|
|
extern void convert_icarus_to_cairnsmore(struct cgpu_info *);
|
|
|
|
|
|
@@ -312,9 +313,8 @@ static const char *timing_mode_str(enum timing_mode timing_mode)
|
|
|
}
|
|
|
|
|
|
static
|
|
|
-const char *icarus_set_timing(struct cgpu_info * const proc, const char * const optname, const char * const buf, char * const replybuf, enum bfg_set_device_replytype * const out_success)
|
|
|
+const char *_icarus_set_timing(struct ICARUS_INFO * const info, const char * const repr, const struct device_drv * const drv, const char * const buf)
|
|
|
{
|
|
|
- struct ICARUS_INFO * const info = proc->device_data;
|
|
|
double Hs;
|
|
|
char *eq;
|
|
|
|
|
|
@@ -387,7 +387,7 @@ const char *icarus_set_timing(struct cgpu_info * const proc, const char * const
|
|
|
int def_read_count = ICARUS_READ_COUNT_TIMING;
|
|
|
|
|
|
if (info->timing_mode == MODE_DEFAULT) {
|
|
|
- if (proc->drv == &icarus_drv) {
|
|
|
+ if (drv == &icarus_drv) {
|
|
|
info->do_default_detection = 0x10;
|
|
|
} else {
|
|
|
def_read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
|
|
|
@@ -404,13 +404,20 @@ const char *icarus_set_timing(struct cgpu_info * const proc, const char * const
|
|
|
info->min_data_count = MIN_DATA_COUNT;
|
|
|
|
|
|
applog(LOG_DEBUG, "%"PRIpreprv": Init: mode=%s read_count=%d limit=%dms Hs=%e",
|
|
|
- proc->proc_repr,
|
|
|
+ repr,
|
|
|
timing_mode_str(info->timing_mode),
|
|
|
info->read_count, info->read_count_limit, info->Hs);
|
|
|
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+static
|
|
|
+const char *icarus_set_timing(struct cgpu_info * const proc, const char * const optname, const char * const buf, char * const replybuf, enum bfg_set_device_replytype * const out_success)
|
|
|
+{
|
|
|
+ struct ICARUS_INFO * const info = proc->device_data;
|
|
|
+ return _icarus_set_timing(info, proc->proc_repr, proc->drv, buf);
|
|
|
+}
|
|
|
+
|
|
|
static uint32_t mask(int work_division)
|
|
|
{
|
|
|
return 0xffffffff / work_division;
|
|
|
@@ -437,6 +444,56 @@ int icarus_excess_nonce_size(int fd, struct ICARUS_INFO *info)
|
|
|
return bytes_read;
|
|
|
}
|
|
|
|
|
|
+int icarus_probe_work_division(const int fd, const char * const repr, struct ICARUS_INFO * const info)
|
|
|
+{
|
|
|
+ struct timeval tv_finish;
|
|
|
+
|
|
|
+ // For reading the nonce from Icarus
|
|
|
+ unsigned char res_bin[info->read_size];
|
|
|
+ // For storing the the 32-bit nonce
|
|
|
+ uint32_t res;
|
|
|
+ int work_division = 0;
|
|
|
+
|
|
|
+ applog(LOG_DEBUG, "%s: Work division not specified - autodetecting", repr);
|
|
|
+
|
|
|
+ // Special packet to probe work_division
|
|
|
+ unsigned char pkt[64] =
|
|
|
+ "\x2e\x4c\x8f\x91\xfd\x59\x5d\x2d\x7e\xa2\x0a\xaa\xcb\x64\xa2\xa0"
|
|
|
+ "\x43\x82\x86\x02\x77\xcf\x26\xb6\xa1\xee\x04\xc5\x6a\x5b\x50\x4a"
|
|
|
+ "BFGMiner Probe\0\0"
|
|
|
+ "BFG\0\x64\x61\x01\x1a\xc9\x06\xa9\x51\xfb\x9b\x3c\x73";
|
|
|
+
|
|
|
+ icarus_write(fd, pkt, sizeof(pkt));
|
|
|
+ memset(res_bin, 0, sizeof(res_bin));
|
|
|
+ if (ICA_GETS_OK == icarus_gets(res_bin, fd, &tv_finish, NULL, info->read_count, info->read_size))
|
|
|
+ {
|
|
|
+ memcpy(&res, res_bin, sizeof(res));
|
|
|
+ res = icarus_nonce32toh(info, res);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ res = 0;
|
|
|
+
|
|
|
+ switch (res) {
|
|
|
+ case 0x04C0FDB4:
|
|
|
+ work_division = 1;
|
|
|
+ break;
|
|
|
+ case 0x82540E46:
|
|
|
+ work_division = 2;
|
|
|
+ break;
|
|
|
+ case 0x417C0F36:
|
|
|
+ work_division = 4;
|
|
|
+ break;
|
|
|
+ case 0x60C994D5:
|
|
|
+ work_division = 8;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ applog(LOG_ERR, "%s: Work division autodetection failed (assuming 2): got %08x", repr, res);
|
|
|
+ work_division = 2;
|
|
|
+ }
|
|
|
+ applog(LOG_DEBUG, "%s: Work division autodetection got %08x (=%d)", repr, res, work_division);
|
|
|
+ return work_division;
|
|
|
+}
|
|
|
+
|
|
|
bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct ICARUS_INFO *info)
|
|
|
{
|
|
|
struct timeval tv_start, tv_finish;
|
|
|
@@ -543,6 +600,20 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
|
|
|
if (serial_claim_v(devpath, api))
|
|
|
return false;
|
|
|
|
|
|
+ _icarus_set_timing(info, api->dname, api, "");
|
|
|
+ if (!info->fpga_count)
|
|
|
+ {
|
|
|
+ if (!info->work_division)
|
|
|
+ {
|
|
|
+ fd = icarus_open2(devpath, baud, true);
|
|
|
+ info->work_division = icarus_probe_work_division(fd, api->dname, info);
|
|
|
+ icarus_close(fd);
|
|
|
+ }
|
|
|
+ info->fpga_count = info->work_division;
|
|
|
+ }
|
|
|
+ // Lock fpga_count from set_work_division
|
|
|
+ info->user_set |= IUS_FPGA_COUNT;
|
|
|
+
|
|
|
/* We have a real Icarus! */
|
|
|
struct cgpu_info *icarus;
|
|
|
icarus = calloc(1, sizeof(struct cgpu_info));
|
|
|
@@ -550,7 +621,8 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
|
|
|
icarus->device_path = strdup(devpath);
|
|
|
icarus->device_fd = -1;
|
|
|
icarus->threads = 1;
|
|
|
- icarus->set_device_funcs = icarus_set_device_funcs;
|
|
|
+ icarus->procs = info->fpga_count;
|
|
|
+ icarus->set_device_funcs = icarus_set_device_funcs_live;
|
|
|
add_cgpu(icarus);
|
|
|
|
|
|
applog(LOG_INFO, "Found %"PRIpreprv" at %s",
|
|
|
@@ -564,7 +636,6 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
|
|
|
icarus->device_data = info;
|
|
|
|
|
|
timersub(&tv_finish, &tv_start, &(info->golden_tv));
|
|
|
- icarus_set_timing(icarus, NULL, "", NULL, NULL);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
@@ -639,55 +710,7 @@ bool icarus_init(struct thr_info *thr)
|
|
|
BFGINIT(state->ob_bin, calloc(1, info->ob_size));
|
|
|
|
|
|
if (!info->work_division)
|
|
|
- {
|
|
|
- struct timeval tv_finish;
|
|
|
-
|
|
|
- // For reading the nonce from Icarus
|
|
|
- unsigned char res_bin[info->read_size];
|
|
|
- // For storing the the 32-bit nonce
|
|
|
- uint32_t res;
|
|
|
-
|
|
|
- applog(LOG_DEBUG, "%"PRIpreprv": Work division not specified - autodetecting", icarus->proc_repr);
|
|
|
-
|
|
|
- // Special packet to probe work_division
|
|
|
- unsigned char pkt[64] =
|
|
|
- "\x2e\x4c\x8f\x91\xfd\x59\x5d\x2d\x7e\xa2\x0a\xaa\xcb\x64\xa2\xa0"
|
|
|
- "\x43\x82\x86\x02\x77\xcf\x26\xb6\xa1\xee\x04\xc5\x6a\x5b\x50\x4a"
|
|
|
- "BFGMiner Probe\0\0"
|
|
|
- "BFG\0\x64\x61\x01\x1a\xc9\x06\xa9\x51\xfb\x9b\x3c\x73";
|
|
|
-
|
|
|
- icarus_write(fd, pkt, sizeof(pkt));
|
|
|
- memset(res_bin, 0, sizeof(res_bin));
|
|
|
- if (ICA_GETS_OK == icarus_gets(res_bin, fd, &tv_finish, NULL, info->read_count, info->read_size))
|
|
|
- {
|
|
|
- memcpy(&res, res_bin, sizeof(res));
|
|
|
- res = icarus_nonce32toh(info, res);
|
|
|
- }
|
|
|
- else
|
|
|
- res = 0;
|
|
|
-
|
|
|
- switch (res) {
|
|
|
- case 0x04C0FDB4:
|
|
|
- info->work_division = 1;
|
|
|
- break;
|
|
|
- case 0x82540E46:
|
|
|
- info->work_division = 2;
|
|
|
- break;
|
|
|
- case 0x417C0F36:
|
|
|
- info->work_division = 4;
|
|
|
- break;
|
|
|
- case 0x60C994D5:
|
|
|
- info->work_division = 8;
|
|
|
- break;
|
|
|
- default:
|
|
|
- applog(LOG_ERR, "%"PRIpreprv": Work division autodetection failed (assuming 2): got %08x", icarus->proc_repr, res);
|
|
|
- info->work_division = 2;
|
|
|
- }
|
|
|
- applog(LOG_DEBUG, "%"PRIpreprv": Work division autodetection got %08x (=%d)", icarus->proc_repr, res, info->work_division);
|
|
|
- }
|
|
|
-
|
|
|
- if (!info->fpga_count)
|
|
|
- info->fpga_count = info->work_division;
|
|
|
+ info->work_division = icarus_probe_work_division(fd, icarus->proc_repr, info);
|
|
|
|
|
|
if (!is_power_of_two(info->work_division))
|
|
|
info->work_division = upper_power_of_two_u32(info->work_division);
|
|
|
@@ -696,6 +719,18 @@ bool icarus_init(struct thr_info *thr)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+static
|
|
|
+struct thr_info *icarus_thread_for_nonce(const struct cgpu_info * const icarus, const uint32_t nonce)
|
|
|
+{
|
|
|
+ struct ICARUS_INFO * const info = icarus->device_data;
|
|
|
+ unsigned proc_id = 0;
|
|
|
+ for (int i = info->work_division, j = 0; i /= 2; ++j)
|
|
|
+ if (nonce & (1 << (31 - j)))
|
|
|
+ proc_id |= (1 << j);
|
|
|
+ const struct cgpu_info * const proc = device_proc_by_id(icarus, proc_id) ?: icarus;
|
|
|
+ return proc->thr[0];
|
|
|
+}
|
|
|
+
|
|
|
static bool icarus_reopen(struct cgpu_info *icarus, struct icarus_state *state, int *fdp)
|
|
|
{
|
|
|
struct ICARUS_INFO *info = icarus->device_data;
|
|
|
@@ -819,7 +854,7 @@ void handle_identify(struct thr_info * const thr, int ret, const bool was_first_
|
|
|
{
|
|
|
memcpy(&nonce, nonce_bin, sizeof(nonce));
|
|
|
nonce = icarus_nonce32toh(info, nonce);
|
|
|
- submit_nonce(thr, state->last_work, nonce);
|
|
|
+ submit_nonce(icarus_thread_for_nonce(icarus, nonce), state->last_work, nonce);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -964,7 +999,7 @@ keepwaiting:
|
|
|
if (nonce_work == state->last2_work)
|
|
|
{
|
|
|
// nonce was for the last job; submit and keep processing the current one
|
|
|
- submit_nonce(thr, nonce_work, nonce);
|
|
|
+ submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
|
|
|
goto keepwaiting;
|
|
|
}
|
|
|
if (info->continue_search)
|
|
|
@@ -972,7 +1007,7 @@ keepwaiting:
|
|
|
read_count = info->read_count - ((timer_elapsed_us(&state->tv_workstart, NULL) / (1000000 / TIME_FACTOR)) + 1);
|
|
|
if (read_count)
|
|
|
{
|
|
|
- submit_nonce(thr, nonce_work, nonce);
|
|
|
+ submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
|
|
|
goto keepwaiting;
|
|
|
}
|
|
|
}
|
|
|
@@ -1026,7 +1061,7 @@ keepwaiting:
|
|
|
|
|
|
if (ret == ICA_GETS_OK && !was_hw_error)
|
|
|
{
|
|
|
- submit_nonce(thr, nonce_work, nonce);
|
|
|
+ submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
|
|
|
|
|
|
icarus_transition_work(state, work);
|
|
|
|
|
|
@@ -1047,7 +1082,8 @@ keepwaiting:
|
|
|
|
|
|
if (ret == ICA_GETS_OK)
|
|
|
{
|
|
|
- inc_hw_errors(thr, state->last_work, nonce);
|
|
|
+ // We can't be sure which processor got the error, but at least this is a decent guess
|
|
|
+ inc_hw_errors(icarus_thread_for_nonce(icarus, nonce), state->last_work, nonce);
|
|
|
estimate_hashes -= ICARUS_READ_TIME(info->baud, info->read_size);
|
|
|
}
|
|
|
|
|
|
@@ -1217,6 +1253,18 @@ out:
|
|
|
if (unlikely(state->identify))
|
|
|
handle_identify(thr, ret, was_first_run);
|
|
|
|
|
|
+ int hash_count_per_proc = hash_count / icarus->procs;
|
|
|
+ if (hash_count_per_proc > 0)
|
|
|
+ {
|
|
|
+ for_each_managed_proc(proc, icarus)
|
|
|
+ {
|
|
|
+ struct thr_info * const proc_thr = proc->thr[0];
|
|
|
+
|
|
|
+ hashes_done2(proc_thr, hash_count_per_proc, NULL);
|
|
|
+ hash_count -= hash_count_per_proc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return hash_count;
|
|
|
}
|
|
|
|
|
|
@@ -1298,7 +1346,7 @@ const char *icarus_set_fpga_count(struct cgpu_info * const proc, const char * co
|
|
|
{
|
|
|
struct ICARUS_INFO * const info = proc->device_data;
|
|
|
const int fpga_count = atoi(newvalue);
|
|
|
- if (fpga_count < 1 || fpga_count > info->work_division)
|
|
|
+ if (fpga_count < 1 || (fpga_count > info->work_division && info->work_division))
|
|
|
return "Invalid fpga_count: must be >0 and <=work_division";
|
|
|
info->fpga_count = fpga_count;
|
|
|
return NULL;
|
|
|
@@ -1342,6 +1390,14 @@ const struct bfg_set_device_definition icarus_set_device_funcs[] = {
|
|
|
{NULL},
|
|
|
};
|
|
|
|
|
|
+const struct bfg_set_device_definition icarus_set_device_funcs_live[] = {
|
|
|
+ {"baud" , icarus_set_baud , "serial baud rate"},
|
|
|
+ {"work_division", icarus_set_work_division, "number of pieces work is split into"},
|
|
|
+ {"reopen" , icarus_set_reopen , "how often to reopen device: never, timeout, cycle, (or now for a one-shot reopen)"},
|
|
|
+ {"timing" , icarus_set_timing , "timing of device; see README.FPGA"},
|
|
|
+ {NULL},
|
|
|
+};
|
|
|
+
|
|
|
struct device_drv icarus_drv = {
|
|
|
.dname = "icarus",
|
|
|
.name = "ICA",
|