|
|
|
@ -30,6 +30,22 @@
@@ -30,6 +30,22 @@
|
|
|
|
|
#define BLANK "" |
|
|
|
|
#define LFSTR "<LF>" |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Firmware |
|
|
|
|
* DRV_V2 expects (beyond V1) the GetInfo to return the chip count |
|
|
|
|
* The queues are 40 instead of 20 and are *usually* consumed and filled |
|
|
|
|
* in bursts due to e.g. a 16 chip device doing 16 items at a time and |
|
|
|
|
* returning 16 results at a time |
|
|
|
|
* If the device has varying chip speeds, it will gradually break up the |
|
|
|
|
* burst of results as we progress from the last LP |
|
|
|
|
* The next LP will restart all chips approximately together again |
|
|
|
|
*/ |
|
|
|
|
enum driver_version { |
|
|
|
|
BFLSC_DRVUNDEF = 0, |
|
|
|
|
BFLSC_DRV1, |
|
|
|
|
BFLSC_DRV2 |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* With Firmware 1.0.0 and a result queue of 20 the Max is: |
|
|
|
|
* inprocess = 12 |
|
|
|
@ -37,6 +53,14 @@
@@ -37,6 +53,14 @@
|
|
|
|
|
* 64+1+24+1+1+(1+8)*8+1 per line = 164 * 20 |
|
|
|
|
* OK = 3 |
|
|
|
|
* Total: 3304 |
|
|
|
|
* |
|
|
|
|
* With Firmware 1.2.* and a result queue of 40 but a limit of 15 replies: |
|
|
|
|
* inprocess = 12 |
|
|
|
|
* max count = 9 |
|
|
|
|
* 64+1+24+1+1+1+1+(1+8)*8+1 per line = 166 * 15 |
|
|
|
|
* OK = 3 |
|
|
|
|
* Total: 2514 |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
#define BFLSC_BUFSIZ (0x1000) |
|
|
|
|
|
|
|
|
@ -49,6 +73,7 @@
@@ -49,6 +73,7 @@
|
|
|
|
|
#define BFLSC_DI_XLINKPRESENT "XLINK PRESENT" |
|
|
|
|
#define BFLSC_DI_DEVICESINCHAIN "DEVICES IN CHAIN" |
|
|
|
|
#define BFLSC_DI_CHAINPRESENCE "CHAIN PRESENCE MASK" |
|
|
|
|
#define BFLSC_DI_CHIPS "CHIP PARALLELIZATION" |
|
|
|
|
|
|
|
|
|
#define FULLNONCE 0x100000000ULL |
|
|
|
|
|
|
|
|
@ -73,6 +98,7 @@ struct bflsc_dev {
@@ -73,6 +98,7 @@ struct bflsc_dev {
|
|
|
|
|
int engines; // each engine represents a 'thread' in a chip
|
|
|
|
|
char *xlink_mode; |
|
|
|
|
char *xlink_present; |
|
|
|
|
char *chips; |
|
|
|
|
|
|
|
|
|
// Status
|
|
|
|
|
bool dead; // TODO: handle seperate x-link devices failing?
|
|
|
|
@ -103,6 +129,7 @@ struct bflsc_dev {
@@ -103,6 +129,7 @@ struct bflsc_dev {
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct bflsc_info { |
|
|
|
|
enum driver_version driver_version; |
|
|
|
|
pthread_rwlock_t stat_lock; |
|
|
|
|
struct thr_info results_thr; |
|
|
|
|
uint64_t hashes_sent; |
|
|
|
@ -117,6 +144,12 @@ struct bflsc_info {
@@ -117,6 +144,12 @@ struct bflsc_info {
|
|
|
|
|
bool flash_led; |
|
|
|
|
bool not_first_work; // allow ignoring the first nonce error
|
|
|
|
|
bool fanauto; |
|
|
|
|
int que_size; |
|
|
|
|
int que_full_enough; |
|
|
|
|
int que_watermark; |
|
|
|
|
int que_noncecount; |
|
|
|
|
int que_fld_min; |
|
|
|
|
int que_fld_max; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#define BFLSC_XLINKHDR '@' |
|
|
|
@ -147,9 +180,15 @@ struct QueueJobStructure {
@@ -147,9 +180,15 @@ struct QueueJobStructure {
|
|
|
|
|
#define QUE_RES_LINES_MIN 3 |
|
|
|
|
#define QUE_MIDSTATE 0 |
|
|
|
|
#define QUE_BLOCKDATA 1 |
|
|
|
|
#define QUE_NONCECOUNT 2 |
|
|
|
|
#define QUE_FLD_MIN 3 |
|
|
|
|
#define QUE_FLD_MAX 11 |
|
|
|
|
|
|
|
|
|
#define QUE_NONCECOUNT_V1 2 |
|
|
|
|
#define QUE_FLD_MIN_V1 3 |
|
|
|
|
#define QUE_FLD_MAX_V1 11 |
|
|
|
|
|
|
|
|
|
#define QUE_CHIP_V2 2 |
|
|
|
|
#define QUE_NONCECOUNT_V2 3 |
|
|
|
|
#define QUE_FLD_MIN_V2 4 |
|
|
|
|
#define QUE_FLD_MAX_V2 12 |
|
|
|
|
|
|
|
|
|
#define BFLSC_SIGNATURE 0xc1 |
|
|
|
|
#define BFLSC_EOW 0xfe |
|
|
|
@ -296,12 +335,20 @@ struct SaveString {
@@ -296,12 +335,20 @@ struct SaveString {
|
|
|
|
|
#define BAJ_LATENCY LATENCY_STD |
|
|
|
|
#define BAL_LATENCY LATENCY_STD |
|
|
|
|
#define BAS_LATENCY LATENCY_STD |
|
|
|
|
// For now a BAM doesn't really exist - it's currently 8 independent BASs
|
|
|
|
|
#define BAM_LATENCY 2 |
|
|
|
|
|
|
|
|
|
#define BFLSC_TEMP_SLEEPMS 5 |
|
|
|
|
#define BFLSC_QUE_SIZE 20 |
|
|
|
|
#define BFLSC_QUE_FULL_ENOUGH 13 |
|
|
|
|
#define BFLSC_QUE_WATERMARK 6 |
|
|
|
|
|
|
|
|
|
#define BFLSC_QUE_SIZE_V1 20 |
|
|
|
|
#define BFLSC_QUE_FULL_ENOUGH_V1 13 |
|
|
|
|
#define BFLSC_QUE_WATERMARK_V1 6 |
|
|
|
|
|
|
|
|
|
// TODO: use 5 batch jobs
|
|
|
|
|
// TODO: base these numbers on the chip count?
|
|
|
|
|
#define BFLSC_QUE_SIZE_V2 40 |
|
|
|
|
#define BFLSC_QUE_FULL_ENOUGH_V2 35 |
|
|
|
|
#define BFLSC_QUE_WATERMARK_V2 20 |
|
|
|
|
|
|
|
|
|
// Must drop this far below cutoff before resuming work
|
|
|
|
|
#define BFLSC_TEMP_RECOVER 5 |
|
|
|
@ -318,6 +365,29 @@ static const char *blank = "";
@@ -318,6 +365,29 @@ static const char *blank = "";
|
|
|
|
|
|
|
|
|
|
struct device_drv bflsc_drv; |
|
|
|
|
|
|
|
|
|
static enum driver_version drv_ver(struct cgpu_info *bflsc, const char *ver) |
|
|
|
|
{ |
|
|
|
|
char *tmp; |
|
|
|
|
|
|
|
|
|
if (strcmp(ver, "1.0.0") == 0) |
|
|
|
|
return BFLSC_DRV1; |
|
|
|
|
|
|
|
|
|
if (strncmp(ver, "1.0", 3) == 0 || strncmp(ver, "1.1", 3)) { |
|
|
|
|
applog(LOG_WARNING, "%s detect (%s) Warning assuming firmware '%s' is Ver1", |
|
|
|
|
bflsc->drv->dname, bflsc->device_path, ver); |
|
|
|
|
return BFLSC_DRV1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (strncmp(ver, "1.2", 3) == 0) |
|
|
|
|
return BFLSC_DRV2; |
|
|
|
|
|
|
|
|
|
tmp = str_text((char *)ver); |
|
|
|
|
applog(LOG_WARNING, "%s detect (%s) Warning unknown firmware '%s' using Ver2", |
|
|
|
|
bflsc->drv->dname, bflsc->device_path, tmp); |
|
|
|
|
free(tmp); |
|
|
|
|
return BFLSC_DRV2; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void xlinkstr(char *xlink, int dev, struct bflsc_info *sc_info) |
|
|
|
|
{ |
|
|
|
|
if (dev > 0) |
|
|
|
@ -747,12 +817,7 @@ static bool getinfo(struct cgpu_info *bflsc, int dev)
@@ -747,12 +817,7 @@ static bool getinfo(struct cgpu_info *bflsc, int dev)
|
|
|
|
|
} |
|
|
|
|
if (strcmp(firstname, BFLSC_DI_FIRMWARE) == 0) { |
|
|
|
|
sc_dev.firmware = strdup(fields[0]); |
|
|
|
|
if (strcmp(sc_dev.firmware, "1.0.0")) { |
|
|
|
|
tmp = str_text(items[i]); |
|
|
|
|
applog(LOG_WARNING, "%s detect (%s) Warning unknown firmware '%s'", |
|
|
|
|
bflsc->drv->dname, bflsc->device_path, tmp); |
|
|
|
|
free(tmp); |
|
|
|
|
} |
|
|
|
|
sc_info->driver_version = drv_ver(bflsc, sc_dev.firmware); |
|
|
|
|
} |
|
|
|
|
else if (strcmp(firstname, BFLSC_DI_ENGINES) == 0) { |
|
|
|
|
sc_dev.engines = atoi(fields[0]); |
|
|
|
@ -777,10 +842,18 @@ static bool getinfo(struct cgpu_info *bflsc, int dev)
@@ -777,10 +842,18 @@ static bool getinfo(struct cgpu_info *bflsc, int dev)
|
|
|
|
|
free(tmp); |
|
|
|
|
goto mata; |
|
|
|
|
} |
|
|
|
|
else if (strcmp(firstname, BFLSC_DI_CHIPS) == 0) |
|
|
|
|
sc_dev.chips = strdup(fields[0]); |
|
|
|
|
} |
|
|
|
|
freebreakdown(&count, &firstname, &fields); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (sc_info->driver_version == BFLSC_DRVUNDEF) { |
|
|
|
|
applog(LOG_WARNING, "%s detect (%s) missing %s", |
|
|
|
|
bflsc->drv->dname, bflsc->device_path, BFLSC_DI_FIRMWARE); |
|
|
|
|
goto ne; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sc_info->sc_devs = calloc(sc_info->sc_count, sizeof(struct bflsc_dev)); |
|
|
|
|
if (unlikely(!sc_info->sc_devs)) |
|
|
|
|
quit(1, "Failed to calloc in getinfo"); |
|
|
|
@ -887,6 +960,29 @@ reinit:
@@ -887,6 +960,29 @@ reinit:
|
|
|
|
|
if (!getinfo(bflsc, 0)) |
|
|
|
|
goto unshin; |
|
|
|
|
|
|
|
|
|
switch (sc_info->driver_version) { |
|
|
|
|
case BFLSC_DRV1: |
|
|
|
|
sc_info->que_size = BFLSC_QUE_SIZE_V1; |
|
|
|
|
sc_info->que_full_enough = BFLSC_QUE_FULL_ENOUGH_V1; |
|
|
|
|
sc_info->que_watermark = BFLSC_QUE_WATERMARK_V1; |
|
|
|
|
sc_info->que_noncecount = QUE_NONCECOUNT_V1; |
|
|
|
|
sc_info->que_fld_min = QUE_FLD_MIN_V1; |
|
|
|
|
sc_info->que_fld_max = QUE_FLD_MAX_V1; |
|
|
|
|
break; |
|
|
|
|
case BFLSC_DRV2: |
|
|
|
|
case BFLSC_DRVUNDEF: |
|
|
|
|
default: |
|
|
|
|
sc_info->driver_version = BFLSC_DRV2; |
|
|
|
|
|
|
|
|
|
sc_info->que_size = BFLSC_QUE_SIZE_V2; |
|
|
|
|
sc_info->que_full_enough = BFLSC_QUE_FULL_ENOUGH_V2; |
|
|
|
|
sc_info->que_watermark = BFLSC_QUE_WATERMARK_V2; |
|
|
|
|
sc_info->que_noncecount = QUE_NONCECOUNT_V2; |
|
|
|
|
sc_info->que_fld_min = QUE_FLD_MIN_V2; |
|
|
|
|
sc_info->que_fld_max = QUE_FLD_MAX_V2; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sc_info->scan_sleep_time = BAS_SCAN_TIME; |
|
|
|
|
sc_info->results_sleep_time = BAS_RES_TIME; |
|
|
|
|
sc_info->default_ms_work = BAS_WORK_TIME; |
|
|
|
@ -1280,7 +1376,7 @@ static void process_nonces(struct cgpu_info *bflsc, int dev, char *xlink, char *
@@ -1280,7 +1376,7 @@ static void process_nonces(struct cgpu_info *bflsc, int dev, char *xlink, char *
|
|
|
|
|
bool res; |
|
|
|
|
char *tmp; |
|
|
|
|
|
|
|
|
|
if (count < QUE_FLD_MIN) { |
|
|
|
|
if (count < sc_info->que_fld_min) { |
|
|
|
|
tmp = str_text(data); |
|
|
|
|
applog(LOG_ERR, "%s%i:%s work returned too small (%d,%s)", |
|
|
|
|
bflsc->drv->name, bflsc->device_id, xlink, count, tmp); |
|
|
|
@ -1289,18 +1385,18 @@ static void process_nonces(struct cgpu_info *bflsc, int dev, char *xlink, char *
@@ -1289,18 +1385,18 @@ static void process_nonces(struct cgpu_info *bflsc, int dev, char *xlink, char *
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (count > QUE_FLD_MAX) { |
|
|
|
|
if (count > sc_info->que_fld_max) { |
|
|
|
|
applog(LOG_ERR, "%s%i:%s work returned too large (%d) processing %d anyway", |
|
|
|
|
bflsc->drv->name, bflsc->device_id, xlink, count, QUE_FLD_MAX); |
|
|
|
|
count = QUE_FLD_MAX; |
|
|
|
|
bflsc->drv->name, bflsc->device_id, xlink, count, sc_info->que_fld_max); |
|
|
|
|
count = sc_info->que_fld_max; |
|
|
|
|
inc_hw_errors(bflsc->thr[0]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
num = atoi(fields[QUE_NONCECOUNT]); |
|
|
|
|
if (num != count - QUE_FLD_MIN) { |
|
|
|
|
num = atoi(fields[sc_info->que_noncecount]); |
|
|
|
|
if (num != count - sc_info->que_fld_min) { |
|
|
|
|
tmp = str_text(data); |
|
|
|
|
applog(LOG_ERR, "%s%i:%s incorrect data count (%d) will use %d instead from (%s)", |
|
|
|
|
bflsc->drv->name, bflsc->device_id, xlink, num, count - QUE_FLD_MAX, tmp); |
|
|
|
|
bflsc->drv->name, bflsc->device_id, xlink, num, count - sc_info->que_fld_max, tmp); |
|
|
|
|
free(tmp); |
|
|
|
|
inc_hw_errors(bflsc->thr[0]); |
|
|
|
|
} |
|
|
|
@ -1327,7 +1423,7 @@ static void process_nonces(struct cgpu_info *bflsc, int dev, char *xlink, char *
@@ -1327,7 +1423,7 @@ static void process_nonces(struct cgpu_info *bflsc, int dev, char *xlink, char *
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
res = false; |
|
|
|
|
for (i = QUE_FLD_MIN; i < count; i++) { |
|
|
|
|
for (i = sc_info->que_fld_min; i < count; i++) { |
|
|
|
|
if (strlen(fields[i]) != 8) { |
|
|
|
|
tmp = str_text(data); |
|
|
|
|
applog(LOG_ERR, "%s%i:%s invalid nonce (%s) will try to process anyway", |
|
|
|
@ -1593,7 +1689,7 @@ re_send:
@@ -1593,7 +1689,7 @@ re_send:
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!getokerr(bflsc, C_QUEJOBSTATUS, &err, &amount, buf, sizeof(buf))) { |
|
|
|
|
// TODO: check for QUEUE FULL and set work_queued to BFLSC_QUE_SIZE
|
|
|
|
|
// TODO: check for QUEUE FULL and set work_queued to sc_info->que_size
|
|
|
|
|
// and report a code bug LOG_ERR - coz it should never happen
|
|
|
|
|
|
|
|
|
|
// Try twice
|
|
|
|
@ -1648,7 +1744,7 @@ static bool bflsc_queue_full(struct cgpu_info *bflsc)
@@ -1648,7 +1744,7 @@ static bool bflsc_queue_full(struct cgpu_info *bflsc)
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (dev == -1) { |
|
|
|
|
que = BFLSC_QUE_SIZE * 10; // 10x is certainly above the MAX it could be
|
|
|
|
|
que = sc_info->que_size * 10; // 10x is certainly above the MAX it could be
|
|
|
|
|
// The first device with the smallest amount queued
|
|
|
|
|
for (i = 0; i < sc_info->sc_count; i++) { |
|
|
|
|
if (i != tried && sc_info->sc_devs[i].work_queued < que && |
|
|
|
@ -1657,7 +1753,7 @@ static bool bflsc_queue_full(struct cgpu_info *bflsc)
@@ -1657,7 +1753,7 @@ static bool bflsc_queue_full(struct cgpu_info *bflsc)
|
|
|
|
|
que = sc_info->sc_devs[i].work_queued; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (que > BFLSC_QUE_FULL_ENOUGH) |
|
|
|
|
if (que > sc_info->que_full_enough) |
|
|
|
|
dev = -1; |
|
|
|
|
} |
|
|
|
|
rd_unlock(&(sc_info->stat_lock)); |
|
|
|
@ -1740,10 +1836,10 @@ static int64_t bflsc_scanwork(struct thr_info *thr)
@@ -1740,10 +1836,10 @@ static int64_t bflsc_scanwork(struct thr_info *thr)
|
|
|
|
|
waited = restart_wait(sc_info->scan_sleep_time); |
|
|
|
|
if (waited == ETIMEDOUT) { |
|
|
|
|
unsigned int old_sleep_time, new_sleep_time = 0; |
|
|
|
|
int min_queued = BFLSC_QUE_SIZE; |
|
|
|
|
int min_queued = sc_info->que_size; |
|
|
|
|
/* Only adjust the scan_sleep_time if we did not receive a
|
|
|
|
|
* restart message while waiting. Try to adjust sleep time |
|
|
|
|
* so we drop to BFLSC_QUE_WATERMARK before getting more work. |
|
|
|
|
* so we drop to sc_info->que_watermark before getting more work. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
rd_lock(&sc_info->stat_lock); |
|
|
|
@ -1756,9 +1852,9 @@ static int64_t bflsc_scanwork(struct thr_info *thr)
@@ -1756,9 +1852,9 @@ static int64_t bflsc_scanwork(struct thr_info *thr)
|
|
|
|
|
new_sleep_time = old_sleep_time; |
|
|
|
|
|
|
|
|
|
/* Increase slowly but decrease quickly */ |
|
|
|
|
if (min_queued > BFLSC_QUE_WATERMARK && old_sleep_time < BFLSC_MAX_SLEEP) |
|
|
|
|
if (min_queued > sc_info->que_watermark && old_sleep_time < BFLSC_MAX_SLEEP) |
|
|
|
|
new_sleep_time = old_sleep_time * 21 / 20; |
|
|
|
|
else if (min_queued < BFLSC_QUE_WATERMARK) |
|
|
|
|
else if (min_queued < sc_info->que_watermark) |
|
|
|
|
new_sleep_time = old_sleep_time * 2 / 3; |
|
|
|
|
|
|
|
|
|
/* Do not sleep more than BFLSC_MAX_SLEEP so we can always
|
|
|
|
|