From 8f18d4c8b0f92da9bd2ae218860d8f49e2e473a7 Mon Sep 17 00:00:00 2001 From: Kano Date: Wed, 19 Jun 2013 00:52:13 +1000 Subject: [PATCH] bflsc driver support for v2 firmware --- driver-bflsc.c | 150 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 123 insertions(+), 27 deletions(-) diff --git a/driver-bflsc.c b/driver-bflsc.c index 3dc3172d..4c53ae32 100644 --- a/driver-bflsc.c +++ b/driver-bflsc.c @@ -30,6 +30,22 @@ #define BLANK "" #define LFSTR "" +/* + * 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 @@ * 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 @@ #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 { 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 { }; 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 { 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 { #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 { #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 = ""; 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) } 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) 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: 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 * 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 * 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 * } 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: } 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) } 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) 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) 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) 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