Browse Source

Merge pull request #452 from kanoi/master

bflsc driver support for v2 firmware
nfactor-troky
kanoi 12 years ago
parent
commit
0bfe17206a
  1. 167
      driver-bflsc.c

167
driver-bflsc.c

@ -30,6 +30,21 @@
#define BLANK "" #define BLANK ""
#define LFSTR "<LF>" #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
*/
enum driver_version {
BFLSC_DRVUNDEF = 0,
BFLSC_DRV1,
BFLSC_DRV2
};
/* /*
* With Firmware 1.0.0 and a result queue of 20 the Max is: * With Firmware 1.0.0 and a result queue of 20 the Max is:
* inprocess = 12 * inprocess = 12
@ -37,6 +52,14 @@
* 64+1+24+1+1+(1+8)*8+1 per line = 164 * 20 * 64+1+24+1+1+(1+8)*8+1 per line = 164 * 20
* OK = 3 * OK = 3
* Total: 3304 * 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) #define BFLSC_BUFSIZ (0x1000)
@ -49,6 +72,7 @@
#define BFLSC_DI_XLINKPRESENT "XLINK PRESENT" #define BFLSC_DI_XLINKPRESENT "XLINK PRESENT"
#define BFLSC_DI_DEVICESINCHAIN "DEVICES IN CHAIN" #define BFLSC_DI_DEVICESINCHAIN "DEVICES IN CHAIN"
#define BFLSC_DI_CHAINPRESENCE "CHAIN PRESENCE MASK" #define BFLSC_DI_CHAINPRESENCE "CHAIN PRESENCE MASK"
#define BFLSC_DI_CHIPS "CHIP PARALLELIZATION"
#define FULLNONCE 0x100000000ULL #define FULLNONCE 0x100000000ULL
@ -73,6 +97,7 @@ struct bflsc_dev {
int engines; // each engine represents a 'thread' in a chip int engines; // each engine represents a 'thread' in a chip
char *xlink_mode; char *xlink_mode;
char *xlink_present; char *xlink_present;
char *chips;
// Status // Status
bool dead; // TODO: handle seperate x-link devices failing? bool dead; // TODO: handle seperate x-link devices failing?
@ -103,6 +128,7 @@ struct bflsc_dev {
}; };
struct bflsc_info { struct bflsc_info {
enum driver_version driver_version;
pthread_rwlock_t stat_lock; pthread_rwlock_t stat_lock;
struct thr_info results_thr; struct thr_info results_thr;
uint64_t hashes_sent; uint64_t hashes_sent;
@ -117,6 +143,12 @@ struct bflsc_info {
bool flash_led; bool flash_led;
bool not_first_work; // allow ignoring the first nonce error bool not_first_work; // allow ignoring the first nonce error
bool fanauto; 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 '@' #define BFLSC_XLINKHDR '@'
@ -147,9 +179,15 @@ struct QueueJobStructure {
#define QUE_RES_LINES_MIN 3 #define QUE_RES_LINES_MIN 3
#define QUE_MIDSTATE 0 #define QUE_MIDSTATE 0
#define QUE_BLOCKDATA 1 #define QUE_BLOCKDATA 1
#define QUE_NONCECOUNT 2
#define QUE_FLD_MIN 3 #define QUE_NONCECOUNT_V1 2
#define QUE_FLD_MAX 11 #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_SIGNATURE 0xc1
#define BFLSC_EOW 0xfe #define BFLSC_EOW 0xfe
@ -296,12 +334,20 @@ struct SaveString {
#define BAJ_LATENCY LATENCY_STD #define BAJ_LATENCY LATENCY_STD
#define BAL_LATENCY LATENCY_STD #define BAL_LATENCY LATENCY_STD
#define BAS_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 BAM_LATENCY 2
#define BFLSC_TEMP_SLEEPMS 5 #define BFLSC_TEMP_SLEEPMS 5
#define BFLSC_QUE_SIZE 20
#define BFLSC_QUE_FULL_ENOUGH 13 #define BFLSC_QUE_SIZE_V1 20
#define BFLSC_QUE_WATERMARK 6 #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 // Must drop this far below cutoff before resuming work
#define BFLSC_TEMP_RECOVER 5 #define BFLSC_TEMP_RECOVER 5
@ -318,6 +364,29 @@ static const char *blank = "";
struct device_drv bflsc_drv; 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) == 0) {
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) static void xlinkstr(char *xlink, int dev, struct bflsc_info *sc_info)
{ {
if (dev > 0) if (dev > 0)
@ -747,12 +816,7 @@ static bool getinfo(struct cgpu_info *bflsc, int dev)
} }
if (strcmp(firstname, BFLSC_DI_FIRMWARE) == 0) { if (strcmp(firstname, BFLSC_DI_FIRMWARE) == 0) {
sc_dev.firmware = strdup(fields[0]); sc_dev.firmware = strdup(fields[0]);
if (strcmp(sc_dev.firmware, "1.0.0")) { sc_info->driver_version = drv_ver(bflsc, sc_dev.firmware);
tmp = str_text(items[i]);
applog(LOG_WARNING, "%s detect (%s) Warning unknown firmware '%s'",
bflsc->drv->dname, bflsc->device_path, tmp);
free(tmp);
}
} }
else if (strcmp(firstname, BFLSC_DI_ENGINES) == 0) { else if (strcmp(firstname, BFLSC_DI_ENGINES) == 0) {
sc_dev.engines = atoi(fields[0]); sc_dev.engines = atoi(fields[0]);
@ -777,10 +841,18 @@ static bool getinfo(struct cgpu_info *bflsc, int dev)
free(tmp); free(tmp);
goto mata; goto mata;
} }
else if (strcmp(firstname, BFLSC_DI_CHIPS) == 0)
sc_dev.chips = strdup(fields[0]);
} }
freebreakdown(&count, &firstname, &fields); 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)); sc_info->sc_devs = calloc(sc_info->sc_count, sizeof(struct bflsc_dev));
if (unlikely(!sc_info->sc_devs)) if (unlikely(!sc_info->sc_devs))
quit(1, "Failed to calloc in getinfo"); quit(1, "Failed to calloc in getinfo");
@ -887,6 +959,29 @@ reinit:
if (!getinfo(bflsc, 0)) if (!getinfo(bflsc, 0))
goto unshin; 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->scan_sleep_time = BAS_SCAN_TIME;
sc_info->results_sleep_time = BAS_RES_TIME; sc_info->results_sleep_time = BAS_RES_TIME;
sc_info->default_ms_work = BAS_WORK_TIME; sc_info->default_ms_work = BAS_WORK_TIME;
@ -1280,7 +1375,7 @@ static void process_nonces(struct cgpu_info *bflsc, int dev, char *xlink, char *
bool res; bool res;
char *tmp; char *tmp;
if (count < QUE_FLD_MIN) { if (count < sc_info->que_fld_min) {
tmp = str_text(data); tmp = str_text(data);
applog(LOG_ERR, "%s%i:%s work returned too small (%d,%s)", applog(LOG_ERR, "%s%i:%s work returned too small (%d,%s)",
bflsc->drv->name, bflsc->device_id, xlink, count, tmp); bflsc->drv->name, bflsc->device_id, xlink, count, tmp);
@ -1289,18 +1384,18 @@ static void process_nonces(struct cgpu_info *bflsc, int dev, char *xlink, char *
return; 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", 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); bflsc->drv->name, bflsc->device_id, xlink, count, sc_info->que_fld_max);
count = QUE_FLD_MAX; count = sc_info->que_fld_max;
inc_hw_errors(bflsc->thr[0]); inc_hw_errors(bflsc->thr[0]);
} }
num = atoi(fields[QUE_NONCECOUNT]); num = atoi(fields[sc_info->que_noncecount]);
if (num != count - QUE_FLD_MIN) { if (num != count - sc_info->que_fld_min) {
tmp = str_text(data); tmp = str_text(data);
applog(LOG_ERR, "%s%i:%s incorrect data count (%d) will use %d instead from (%s)", 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); free(tmp);
inc_hw_errors(bflsc->thr[0]); inc_hw_errors(bflsc->thr[0]);
} }
@ -1327,7 +1422,7 @@ static void process_nonces(struct cgpu_info *bflsc, int dev, char *xlink, char *
} }
res = false; 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) { if (strlen(fields[i]) != 8) {
tmp = str_text(data); tmp = str_text(data);
applog(LOG_ERR, "%s%i:%s invalid nonce (%s) will try to process anyway", applog(LOG_ERR, "%s%i:%s invalid nonce (%s) will try to process anyway",
@ -1593,7 +1688,7 @@ re_send:
} }
if (!getokerr(bflsc, C_QUEJOBSTATUS, &err, &amount, buf, sizeof(buf))) { 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 // and report a code bug LOG_ERR - coz it should never happen
// Try twice // Try twice
@ -1648,7 +1743,7 @@ static bool bflsc_queue_full(struct cgpu_info *bflsc)
} }
if (dev == -1) { 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 // The first device with the smallest amount queued
for (i = 0; i < sc_info->sc_count; i++) { for (i = 0; i < sc_info->sc_count; i++) {
if (i != tried && sc_info->sc_devs[i].work_queued < que && if (i != tried && sc_info->sc_devs[i].work_queued < que &&
@ -1657,7 +1752,7 @@ static bool bflsc_queue_full(struct cgpu_info *bflsc)
que = sc_info->sc_devs[i].work_queued; que = sc_info->sc_devs[i].work_queued;
} }
} }
if (que > BFLSC_QUE_FULL_ENOUGH) if (que > sc_info->que_full_enough)
dev = -1; dev = -1;
} }
rd_unlock(&(sc_info->stat_lock)); rd_unlock(&(sc_info->stat_lock));
@ -1740,10 +1835,10 @@ static int64_t bflsc_scanwork(struct thr_info *thr)
waited = restart_wait(sc_info->scan_sleep_time); waited = restart_wait(sc_info->scan_sleep_time);
if (waited == ETIMEDOUT) { if (waited == ETIMEDOUT) {
unsigned int old_sleep_time, new_sleep_time = 0; 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 /* Only adjust the scan_sleep_time if we did not receive a
* restart message while waiting. Try to adjust sleep time * 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); rd_lock(&sc_info->stat_lock);
@ -1756,9 +1851,9 @@ static int64_t bflsc_scanwork(struct thr_info *thr)
new_sleep_time = old_sleep_time; new_sleep_time = old_sleep_time;
/* Increase slowly but decrease quickly */ /* 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; 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; new_sleep_time = old_sleep_time * 2 / 3;
/* Do not sleep more than BFLSC_MAX_SLEEP so we can always /* Do not sleep more than BFLSC_MAX_SLEEP so we can always
@ -1870,6 +1965,7 @@ static struct api_data *bflsc_api_stats(struct cgpu_info *bflsc)
{ {
struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data);
struct api_data *root = NULL; struct api_data *root = NULL;
int i;
//if no x-link ... etc //if no x-link ... etc
rd_lock(&(sc_info->stat_lock)); rd_lock(&(sc_info->stat_lock));
@ -1882,7 +1978,24 @@ static struct api_data *bflsc_api_stats(struct cgpu_info *bflsc)
root = api_add_temp(root, "Temp2 Max", &(sc_info->sc_devs[0].temp2_max), true); root = api_add_temp(root, "Temp2 Max", &(sc_info->sc_devs[0].temp2_max), true);
root = api_add_time(root, "Temp1 Max Time", &(sc_info->sc_devs[0].temp1_max_time), true); root = api_add_time(root, "Temp1 Max Time", &(sc_info->sc_devs[0].temp1_max_time), true);
root = api_add_time(root, "Temp2 Max Time", &(sc_info->sc_devs[0].temp2_max_time), true); root = api_add_time(root, "Temp2 Max Time", &(sc_info->sc_devs[0].temp2_max_time), true);
root = api_add_int(root, "Work Queued", &(sc_info->sc_devs[0].work_queued), true);
root = api_add_int(root, "Work Complete", &(sc_info->sc_devs[0].work_complete), true);
root = api_add_bool(root, "Overheat", &(sc_info->sc_devs[0].overheat), true);
root = api_add_uint64(root, "Flush ID", &(sc_info->sc_devs[0].flush_id), true);
root = api_add_uint64(root, "Result ID", &(sc_info->sc_devs[0].result_id), true);
root = api_add_bool(root, "Flushed", &(sc_info->sc_devs[0].flushed), true);
root = api_add_uint(root, "Scan Sleep", &(sc_info->scan_sleep_time), true);
root = api_add_uint(root, "Results Sleep", &(sc_info->results_sleep_time), true);
root = api_add_uint(root, "Work ms", &(sc_info->default_ms_work), true);
rd_unlock(&(sc_info->stat_lock)); rd_unlock(&(sc_info->stat_lock));
i = (int)(sc_info->driver_version);
root = api_add_int(root, "Driver", &i, true);
root = api_add_string(root, "Firmware", sc_info->sc_devs[0].firmware, false);
root = api_add_string(root, "Chips", sc_info->sc_devs[0].chips, false);
root = api_add_int(root, "Que Size", &(sc_info->que_size), false);
root = api_add_int(root, "Que Full", &(sc_info->que_full_enough), false);
root = api_add_int(root, "Que Watermark", &(sc_info->que_watermark), false);
root = api_add_escape(root, "GetInfo", sc_info->sc_devs[0].getinfo, false); root = api_add_escape(root, "GetInfo", sc_info->sc_devs[0].getinfo, false);
/* /*

Loading…
Cancel
Save