|
|
@ -225,6 +225,11 @@ static void rev(unsigned char *s, size_t l) |
|
|
|
#define icarus_open2(devpath, baud, purge) serial_open(devpath, baud, ICARUS_READ_FAULT_DECISECONDS, purge) |
|
|
|
#define icarus_open2(devpath, baud, purge) serial_open(devpath, baud, ICARUS_READ_FAULT_DECISECONDS, purge) |
|
|
|
#define icarus_open(devpath, baud) icarus_open2(devpath, baud, false) |
|
|
|
#define icarus_open(devpath, baud) icarus_open2(devpath, baud, false) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define ICA_GETS_ERROR -1 |
|
|
|
|
|
|
|
#define ICA_GETS_OK 0 |
|
|
|
|
|
|
|
#define ICA_GETS_RESTART 1 |
|
|
|
|
|
|
|
#define ICA_GETS_TIMEOUT 2 |
|
|
|
|
|
|
|
|
|
|
|
static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count) |
|
|
|
static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ssize_t ret = 0; |
|
|
|
ssize_t ret = 0; |
|
|
@ -235,12 +240,14 @@ static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, st |
|
|
|
// Read reply 1 byte at a time to get earliest tv_finish
|
|
|
|
// Read reply 1 byte at a time to get earliest tv_finish
|
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
ret = read(fd, buf, 1); |
|
|
|
ret = read(fd, buf, 1); |
|
|
|
|
|
|
|
if (ret < 0) |
|
|
|
|
|
|
|
return ICA_GETS_ERROR; |
|
|
|
|
|
|
|
|
|
|
|
if (first) |
|
|
|
if (first) |
|
|
|
gettimeofday(tv_finish, NULL); |
|
|
|
gettimeofday(tv_finish, NULL); |
|
|
|
|
|
|
|
|
|
|
|
if (ret >= read_amount) |
|
|
|
if (ret >= read_amount) |
|
|
|
return 0; |
|
|
|
return ICA_GETS_OK; |
|
|
|
|
|
|
|
|
|
|
|
if (ret > 0) { |
|
|
|
if (ret > 0) { |
|
|
|
buf += ret; |
|
|
|
buf += ret; |
|
|
@ -256,16 +263,16 @@ static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, st |
|
|
|
"Icarus Read: No data in %.2f seconds", |
|
|
|
"Icarus Read: No data in %.2f seconds", |
|
|
|
(float)rc/(float)TIME_FACTOR); |
|
|
|
(float)rc/(float)TIME_FACTOR); |
|
|
|
} |
|
|
|
} |
|
|
|
return 1; |
|
|
|
return ICA_GETS_TIMEOUT; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (thr->work_restart) { |
|
|
|
if (thr && thr->work_restart) { |
|
|
|
if (opt_debug) { |
|
|
|
if (opt_debug) { |
|
|
|
applog(LOG_DEBUG, |
|
|
|
applog(LOG_DEBUG, |
|
|
|
"Icarus Read: Work restart at %.2f seconds", |
|
|
|
"Icarus Read: Work restart at %.2f seconds", |
|
|
|
(float)(rc)/(float)TIME_FACTOR); |
|
|
|
(float)(rc)/(float)TIME_FACTOR); |
|
|
|
} |
|
|
|
} |
|
|
|
return 1; |
|
|
|
return ICA_GETS_RESTART; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -283,6 +290,13 @@ static int icarus_write(int fd, const void *buf, size_t bufLen) |
|
|
|
|
|
|
|
|
|
|
|
#define icarus_close(fd) close(fd) |
|
|
|
#define icarus_close(fd) close(fd) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void do_icarus_close(struct thr_info *thr) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct cgpu_info *icarus = thr->cgpu; |
|
|
|
|
|
|
|
icarus_close(icarus->device_fd); |
|
|
|
|
|
|
|
icarus->device_fd = -1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static const char *timing_mode_str(enum timing_mode timing_mode) |
|
|
|
static const char *timing_mode_str(enum timing_mode timing_mode) |
|
|
|
{ |
|
|
|
{ |
|
|
|
switch(timing_mode) { |
|
|
|
switch(timing_mode) { |
|
|
@ -535,10 +549,7 @@ static bool icarus_detect_one(const char *devpath) |
|
|
|
gettimeofday(&tv_start, NULL); |
|
|
|
gettimeofday(&tv_start, NULL); |
|
|
|
|
|
|
|
|
|
|
|
memset(nonce_bin, 0, sizeof(nonce_bin)); |
|
|
|
memset(nonce_bin, 0, sizeof(nonce_bin)); |
|
|
|
struct thr_info dummy = { |
|
|
|
icarus_gets(nonce_bin, fd, &tv_finish, NULL, 1); |
|
|
|
.work_restart = false, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
icarus_gets(nonce_bin, fd, &tv_finish, &dummy, 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
icarus_close(fd); |
|
|
|
icarus_close(fd); |
|
|
|
|
|
|
|
|
|
|
@ -565,6 +576,7 @@ static bool icarus_detect_one(const char *devpath) |
|
|
|
icarus = calloc(1, sizeof(struct cgpu_info)); |
|
|
|
icarus = calloc(1, sizeof(struct cgpu_info)); |
|
|
|
icarus->api = &icarus_api; |
|
|
|
icarus->api = &icarus_api; |
|
|
|
icarus->device_path = strdup(devpath); |
|
|
|
icarus->device_path = strdup(devpath); |
|
|
|
|
|
|
|
icarus->device_fd = -1; |
|
|
|
icarus->threads = 1; |
|
|
|
icarus->threads = 1; |
|
|
|
add_cgpu(icarus); |
|
|
|
add_cgpu(icarus); |
|
|
|
icarus_info = realloc(icarus_info, sizeof(struct ICARUS_INFO *) * (total_devices + 1)); |
|
|
|
icarus_info = realloc(icarus_info, sizeof(struct ICARUS_INFO *) * (total_devices + 1)); |
|
|
@ -609,6 +621,8 @@ static bool icarus_prepare(struct thr_info *thr) |
|
|
|
|
|
|
|
|
|
|
|
struct timeval now; |
|
|
|
struct timeval now; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
icarus->device_fd = -1; |
|
|
|
|
|
|
|
|
|
|
|
int fd = icarus_open(icarus->device_path, icarus_info[icarus->device_id]->baud); |
|
|
|
int fd = icarus_open(icarus->device_path, icarus_info[icarus->device_id]->baud); |
|
|
|
if (unlikely(-1 == fd)) { |
|
|
|
if (unlikely(-1 == fd)) { |
|
|
|
applog(LOG_ERR, "Failed to open Icarus on %s", |
|
|
|
applog(LOG_ERR, "Failed to open Icarus on %s", |
|
|
@ -655,6 +669,17 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, |
|
|
|
elapsed.tv_sec = elapsed.tv_usec = 0; |
|
|
|
elapsed.tv_sec = elapsed.tv_usec = 0; |
|
|
|
|
|
|
|
|
|
|
|
icarus = thr->cgpu; |
|
|
|
icarus = thr->cgpu; |
|
|
|
|
|
|
|
if (icarus->device_fd == -1) |
|
|
|
|
|
|
|
if (!icarus_prepare(thr)) { |
|
|
|
|
|
|
|
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); |
|
|
|
|
|
|
|
icarus->device_last_not_well = time(NULL); |
|
|
|
|
|
|
|
icarus->device_not_well_reason = REASON_DEV_COMMS_ERROR; |
|
|
|
|
|
|
|
icarus->dev_comms_error_count++; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fail the device if the reopen attempt fails
|
|
|
|
|
|
|
|
return -1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fd = icarus->device_fd; |
|
|
|
fd = icarus->device_fd; |
|
|
|
|
|
|
|
|
|
|
|
memset(ob_bin, 0, sizeof(ob_bin)); |
|
|
|
memset(ob_bin, 0, sizeof(ob_bin)); |
|
|
@ -666,8 +691,14 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, |
|
|
|
tcflush(fd, TCOFLUSH); |
|
|
|
tcflush(fd, TCOFLUSH); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
ret = icarus_write(fd, ob_bin, sizeof(ob_bin)); |
|
|
|
ret = icarus_write(fd, ob_bin, sizeof(ob_bin)); |
|
|
|
if (ret) |
|
|
|
if (ret) { |
|
|
|
return -1; /* This should never happen */ |
|
|
|
do_icarus_close(thr); |
|
|
|
|
|
|
|
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); |
|
|
|
|
|
|
|
icarus->device_last_not_well = time(NULL); |
|
|
|
|
|
|
|
icarus->device_not_well_reason = REASON_DEV_COMMS_ERROR; |
|
|
|
|
|
|
|
icarus->dev_comms_error_count++; |
|
|
|
|
|
|
|
return 0; /* This should never happen */ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
gettimeofday(&tv_start, NULL); |
|
|
|
gettimeofday(&tv_start, NULL); |
|
|
|
|
|
|
|
|
|
|
@ -684,12 +715,19 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, |
|
|
|
memset(nonce_bin, 0, sizeof(nonce_bin)); |
|
|
|
memset(nonce_bin, 0, sizeof(nonce_bin)); |
|
|
|
info = icarus_info[icarus->device_id]; |
|
|
|
info = icarus_info[icarus->device_id]; |
|
|
|
ret = icarus_gets(nonce_bin, fd, &tv_finish, thr, info->read_count); |
|
|
|
ret = icarus_gets(nonce_bin, fd, &tv_finish, thr, info->read_count); |
|
|
|
|
|
|
|
if (ret == ICA_GETS_ERROR) { |
|
|
|
|
|
|
|
do_icarus_close(thr); |
|
|
|
|
|
|
|
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); |
|
|
|
|
|
|
|
icarus->device_last_not_well = time(NULL); |
|
|
|
|
|
|
|
icarus->device_not_well_reason = REASON_DEV_COMMS_ERROR; |
|
|
|
|
|
|
|
icarus->dev_comms_error_count++; |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
work->blk.nonce = 0xffffffff; |
|
|
|
work->blk.nonce = 0xffffffff; |
|
|
|
memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// aborted before becoming idle, get new work
|
|
|
|
// aborted before becoming idle, get new work
|
|
|
|
if (nonce == 0 && ret) { |
|
|
|
if (ret == ICA_GETS_TIMEOUT || ret == ICA_GETS_RESTART) { |
|
|
|
timersub(&tv_finish, &tv_start, &elapsed); |
|
|
|
timersub(&tv_finish, &tv_start, &elapsed); |
|
|
|
|
|
|
|
|
|
|
|
// ONLY up to just when it aborted
|
|
|
|
// ONLY up to just when it aborted
|
|
|
@ -711,6 +749,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, |
|
|
|
return estimate_hashes; |
|
|
|
return estimate_hashes; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin)); |
|
|
|
|
|
|
|
|
|
|
|
#if !defined (__BIG_ENDIAN__) && !defined(MIPSEB) |
|
|
|
#if !defined (__BIG_ENDIAN__) && !defined(MIPSEB) |
|
|
|
nonce = swab32(nonce); |
|
|
|
nonce = swab32(nonce); |
|
|
|
#endif |
|
|
|
#endif |
|
|
@ -719,6 +759,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, |
|
|
|
submit_nonce(thr, work, nonce); |
|
|
|
submit_nonce(thr, work, nonce); |
|
|
|
was_hw_error = (curr_hw_errors > icarus->hw_errors); |
|
|
|
was_hw_error = (curr_hw_errors > icarus->hw_errors); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Force a USB close/reopen on any hw error
|
|
|
|
|
|
|
|
if (was_hw_error) |
|
|
|
|
|
|
|
do_icarus_close(thr); |
|
|
|
|
|
|
|
|
|
|
|
hash_count = (nonce & info->nonce_mask); |
|
|
|
hash_count = (nonce & info->nonce_mask); |
|
|
|
hash_count++; |
|
|
|
hash_count++; |
|
|
|
hash_count *= info->fpga_count; |
|
|
|
hash_count *= info->fpga_count; |
|
|
@ -864,8 +908,7 @@ static struct api_data *icarus_api_stats(struct cgpu_info *cgpu) |
|
|
|
|
|
|
|
|
|
|
|
static void icarus_shutdown(struct thr_info *thr) |
|
|
|
static void icarus_shutdown(struct thr_info *thr) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct cgpu_info *icarus = thr->cgpu; |
|
|
|
do_icarus_close(thr); |
|
|
|
icarus_close(icarus->device_fd); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct device_api icarus_api = { |
|
|
|
struct device_api icarus_api = { |
|
|
|