|
|
@@ -81,6 +81,7 @@ enum bitforce_style {
|
|
|
struct bitforce_lowl_interface {
|
|
|
bool (*open)(struct cgpu_info *);
|
|
|
void (*close)(struct cgpu_info *);
|
|
|
+ ssize_t (*read)(void *, size_t, struct cgpu_info *);
|
|
|
void (*gets)(char *, size_t, struct cgpu_info *);
|
|
|
ssize_t (*write)(struct cgpu_info *, const void *, ssize_t);
|
|
|
bool (*set_timeout)(struct cgpu_info* , uint8_t);
|
|
|
@@ -117,6 +118,7 @@ struct bitforce_data {
|
|
|
float temp[2];
|
|
|
long *volts;
|
|
|
int volts_count;
|
|
|
+ unsigned max_queueid;
|
|
|
|
|
|
bool probed;
|
|
|
bool supports_fanspeed;
|
|
|
@@ -145,6 +147,28 @@ void bitforce_vcom_close(struct cgpu_info * const dev)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static
|
|
|
+ssize_t bitforce_vcom_read(void * const buf_p, size_t bufLen, struct cgpu_info * const dev)
|
|
|
+{
|
|
|
+ uint8_t *buf = buf_p;
|
|
|
+ const int fd = dev->device_fd;
|
|
|
+ ssize_t rv, ret = 0;
|
|
|
+ while (bufLen > 0)
|
|
|
+ {
|
|
|
+ rv = read(fd, buf, bufLen);
|
|
|
+ if (rv <= 0)
|
|
|
+ {
|
|
|
+ if (ret > 0)
|
|
|
+ return ret;
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+ buf += rv;
|
|
|
+ bufLen -= rv;
|
|
|
+ ret += rv;
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static
|
|
|
void bitforce_vcom_gets(char *buf, size_t bufLen, struct cgpu_info * const dev)
|
|
|
{
|
|
|
@@ -175,6 +199,7 @@ bool bitforce_vcom_set_timeout(struct cgpu_info * const dev, const uint8_t timeo
|
|
|
static struct bitforce_lowl_interface bfllif_vcom = {
|
|
|
.open = bitforce_vcom_open,
|
|
|
.close = bitforce_vcom_close,
|
|
|
+ .read = bitforce_vcom_read,
|
|
|
.gets = bitforce_vcom_gets,
|
|
|
.write = bitforce_vcom_write,
|
|
|
.set_timeout = bitforce_vcom_set_timeout,
|
|
|
@@ -210,7 +235,7 @@ void bitforce_pci_close(struct cgpu_info * const dev)
|
|
|
}
|
|
|
|
|
|
static
|
|
|
-void bitforce_pci_gets(char * const buf, size_t bufLen, struct cgpu_info * const dev)
|
|
|
+void _bitforce_pci_read(struct cgpu_info * const dev)
|
|
|
{
|
|
|
struct bitforce_data * const devdata = dev->device_data;
|
|
|
const uint32_t looking_for = (uint32_t)devdata->lasttag << 0x10;
|
|
|
@@ -230,7 +255,35 @@ void bitforce_pci_gets(char * const buf, size_t bufLen, struct cgpu_info * const
|
|
|
if (lowl_pci_read_data(devdata->lph, buf, resp, 1, 0))
|
|
|
bytes_postappend(b, resp);
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+static
|
|
|
+ssize_t bitforce_pci_read(void * const buf, const size_t bufLen, struct cgpu_info * const dev)
|
|
|
+{
|
|
|
+ struct bitforce_data * const devdata = dev->device_data;
|
|
|
+ bytes_t *b = &devdata->getsbuf;
|
|
|
|
|
|
+ _bitforce_pci_read(dev);
|
|
|
+ ssize_t datalen = bytes_len(b);
|
|
|
+ if (datalen <= 0)
|
|
|
+ return datalen;
|
|
|
+
|
|
|
+ if (datalen > bufLen)
|
|
|
+ datalen = bufLen;
|
|
|
+
|
|
|
+ memcpy(buf, bytes_buf(b), datalen);
|
|
|
+ bytes_shift(b, datalen);
|
|
|
+
|
|
|
+ return datalen;
|
|
|
+}
|
|
|
+
|
|
|
+static
|
|
|
+void bitforce_pci_gets(char * const buf, size_t bufLen, struct cgpu_info * const dev)
|
|
|
+{
|
|
|
+ struct bitforce_data * const devdata = dev->device_data;
|
|
|
+ bytes_t *b = &devdata->getsbuf;
|
|
|
+
|
|
|
+ _bitforce_pci_read(dev);
|
|
|
ssize_t linelen = (bytes_find(b, '\n') + 1) ?: bytes_len(b);
|
|
|
if (linelen > --bufLen)
|
|
|
linelen = bufLen;
|
|
|
@@ -262,6 +315,7 @@ ssize_t bitforce_pci_write(struct cgpu_info * const dev, const void * const bufp
|
|
|
static struct bitforce_lowl_interface bfllif_pci = {
|
|
|
.open = bitforce_pci_open,
|
|
|
.close = bitforce_pci_close,
|
|
|
+ .read = bitforce_pci_read,
|
|
|
.gets = bitforce_pci_gets,
|
|
|
.write = bitforce_pci_write,
|
|
|
};
|
|
|
@@ -287,6 +341,30 @@ bool bitforce_open(struct cgpu_info * const proc)
|
|
|
return devdata->lowlif->open(dev);
|
|
|
}
|
|
|
|
|
|
+static
|
|
|
+ssize_t bitforce_read(struct cgpu_info * const proc, void * const buf, const size_t bufLen)
|
|
|
+{
|
|
|
+ struct cgpu_info * const dev = proc->device;
|
|
|
+ struct bitforce_data * const devdata = dev->device_data;
|
|
|
+ ssize_t rv;
|
|
|
+
|
|
|
+ if (likely(devdata->is_open))
|
|
|
+ rv = devdata->lowlif->read(buf, bufLen, dev);
|
|
|
+ else
|
|
|
+ rv = -1;
|
|
|
+
|
|
|
+ if (unlikely(opt_dev_protocol))
|
|
|
+ {
|
|
|
+ size_t datalen = (rv > 0) ? rv : 0;
|
|
|
+ char hex[(rv * 2) + 1];
|
|
|
+ bin2hex(hex, buf, datalen);
|
|
|
+ applog(LOG_DEBUG, "DEVPROTO: %s: READ(%lu): %s",
|
|
|
+ dev->dev_repr, (unsigned long)bufLen, hex);
|
|
|
+ }
|
|
|
+
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+
|
|
|
static
|
|
|
void bitforce_gets(char * const buf, const size_t bufLen, struct cgpu_info * const proc)
|
|
|
{
|
|
|
@@ -409,18 +487,16 @@ struct bitforce_init_data {
|
|
|
enum bitforce_style style;
|
|
|
long devmask;
|
|
|
int *parallels;
|
|
|
+ unsigned queue_depth;
|
|
|
+ unsigned long scan_interval_ms;
|
|
|
+ unsigned max_queueid;
|
|
|
};
|
|
|
|
|
|
static
|
|
|
int bitforce_chips_to_plan_for(int parallel, int chipcount) {
|
|
|
if (parallel < 1)
|
|
|
return parallel;
|
|
|
- if (chipcount > 15) return 32;
|
|
|
- if (chipcount > 7) return 16;
|
|
|
- if (chipcount > 3) return 8;
|
|
|
- if (chipcount > 1) return 4;
|
|
|
- if (chipcount ) return 2;
|
|
|
- return 1;
|
|
|
+ return upper_power_of_two_u32(chipcount);
|
|
|
}
|
|
|
|
|
|
static
|
|
|
@@ -509,6 +585,7 @@ bool bitforce_detect_oneof(const char * const devpath, struct bitforce_lowl_inte
|
|
|
*initdata = (struct bitforce_init_data){
|
|
|
.lowlif = lowlif,
|
|
|
.style = BFS_FPGA,
|
|
|
+ .queue_depth = BITFORCE_MAX_QUEUED_MAX,
|
|
|
};
|
|
|
bitforce_cmd1b(&dummy_cgpu, pdevbuf, sizeof(pdevbuf), "ZCX", 3);
|
|
|
for (int i = 0; (!pdevbuf[0]) && i < 4; ++i)
|
|
|
@@ -530,6 +607,9 @@ bool bitforce_detect_oneof(const char * const devpath, struct bitforce_lowl_inte
|
|
|
if (!strncasecmp(pdevbuf, "CHANNEL", 7))
|
|
|
maxchipno = max(maxchipno, atoi(&pdevbuf[7]));
|
|
|
else
|
|
|
+ if (!strncasecmp(pdevbuf, "CORTEX-", 7))
|
|
|
+ maxchipno = max(maxchipno, strtol(&pdevbuf[7], NULL, 0x10));
|
|
|
+ else
|
|
|
if (!strncasecmp(pdevbuf, "DEVICES IN CHAIN:", 17))
|
|
|
procs = atoi(&pdevbuf[17]);
|
|
|
else
|
|
|
@@ -548,6 +628,15 @@ bool bitforce_detect_oneof(const char * const devpath, struct bitforce_lowl_inte
|
|
|
initdata->style = BFS_28NM;
|
|
|
}
|
|
|
else
|
|
|
+ if (!strncasecmp(pdevbuf, "Queue Depth:", 12))
|
|
|
+ initdata->queue_depth = atoi(&pdevbuf[12]);
|
|
|
+ else
|
|
|
+ if (!strncasecmp(pdevbuf, "Scan Interval:", 14))
|
|
|
+ initdata->scan_interval_ms = atoi(&pdevbuf[14]);
|
|
|
+ else
|
|
|
+ if (!strncasecmp(pdevbuf, "Max Queue ID:", 13))
|
|
|
+ initdata->max_queueid = strtol(&pdevbuf[13], NULL, 0x10);
|
|
|
+ else
|
|
|
if (!strncasecmp(pdevbuf, "MANUFACTURER:", 13))
|
|
|
{
|
|
|
manuf = &pdevbuf[13];
|
|
|
@@ -1554,6 +1643,7 @@ static bool bitforce_thread_init(struct thr_info *thr)
|
|
|
.sleep_ms_default = BITFORCE_SLEEP_MS,
|
|
|
.parallel = abs(initdata->parallels[boardno]),
|
|
|
.parallel_protocol = (initdata->parallels[boardno] != -1),
|
|
|
+ .max_queueid = initdata->max_queueid,
|
|
|
};
|
|
|
thr->cgpu_data = procdata = malloc(sizeof(*procdata));
|
|
|
*procdata = (struct bitforce_proc_data){
|
|
|
@@ -1584,8 +1674,8 @@ static bool bitforce_thread_init(struct thr_info *thr)
|
|
|
data->queued_max = data->parallel * 2;
|
|
|
if (data->queued_max < BITFORCE_MIN_QUEUED_MAX)
|
|
|
data->queued_max = BITFORCE_MIN_QUEUED_MAX;
|
|
|
- if (data->queued_max > BITFORCE_MAX_QUEUED_MAX)
|
|
|
- data->queued_max = BITFORCE_MAX_QUEUED_MAX;
|
|
|
+ if (data->queued_max > initdata->queue_depth)
|
|
|
+ data->queued_max = initdata->queue_depth;
|
|
|
}
|
|
|
else
|
|
|
bitforce_change_mode(bitforce, BFP_WORK);
|
|
|
@@ -1604,6 +1694,10 @@ static bool bitforce_thread_init(struct thr_info *thr)
|
|
|
if (opt_bfl_noncerange)
|
|
|
bitforce_change_mode(bitforce, BFP_RANGE);
|
|
|
}
|
|
|
+
|
|
|
+ if (initdata->scan_interval_ms)
|
|
|
+ bitforce->sleep_ms = initdata->scan_interval_ms;
|
|
|
+
|
|
|
bitforce->status = LIFE_INIT2;
|
|
|
|
|
|
first_on_this_board = procdata;
|
|
|
@@ -1963,7 +2057,27 @@ retry:
|
|
|
if (data->missing_zwx)
|
|
|
queued_ok = 1;
|
|
|
else
|
|
|
- queued_ok = atoi(&buf[9]);
|
|
|
+ {
|
|
|
+ char *p;
|
|
|
+ queued_ok = strtol(&buf[9], &p, 0);
|
|
|
+ if (data->max_queueid)
|
|
|
+ {
|
|
|
+ if (unlikely(p[0] != ':'))
|
|
|
+ applog(LOG_ERR, "%"PRIpreprv": Successfully queued %d/%d jobs, but no queue ids returned (queued<=%d)", bitforce->proc_repr, queued_ok, data->ready_to_queue, data->queued + queued_ok);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // NOTE: work is set to just-before the first item from the build-command loop earlier
|
|
|
+ // NOTE: This ugly statement ends up with the first work item queued
|
|
|
+ work = work ? (work->next ?: work) : thr->work_list;
|
|
|
+ for (int i = data->ready_to_queue; i > 0; --i, (work = work->next))
|
|
|
+ {
|
|
|
+ work->device_id = strtol(&p[1], &p, 0x10);
|
|
|
+ if (unlikely(!p[0]))
|
|
|
+ --p;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
data->queued += queued_ok;
|
|
|
applog(LOG_DEBUG, "%"PRIpreprv": Successfully queued %d/%d jobs on device (queued<=%d)",
|
|
|
bitforce->proc_repr,
|
|
|
@@ -2028,27 +2142,39 @@ again:
|
|
|
if ( (noncebuf = next_line(buf)) )
|
|
|
noncebuf[-1] = '\0';
|
|
|
|
|
|
- if (strlen(buf) <= 90)
|
|
|
+ if (data->max_queueid)
|
|
|
{
|
|
|
- applog(LOG_ERR, "%"PRIpreprv": Gibberish within queue results: %s", bitforce->proc_repr, buf);
|
|
|
- continue;
|
|
|
+ const work_device_id_t queueid = strtol(buf, &end, 0x10);
|
|
|
+ if (unlikely(!end[0]))
|
|
|
+ goto gibberish;
|
|
|
+ DL_SEARCH_SCALAR(thr->work_list, thiswork, device_id, queueid);
|
|
|
}
|
|
|
-
|
|
|
- hex2bin(midstate, buf, 32);
|
|
|
- hex2bin(datatail, &buf[65], 12);
|
|
|
-
|
|
|
- thiswork = NULL;
|
|
|
- DL_FOREACH(thr->work_list, work)
|
|
|
+ else
|
|
|
{
|
|
|
- if (unlikely(memcmp(work->midstate, midstate, 32)))
|
|
|
- continue;
|
|
|
- if (unlikely(memcmp(&work->data[64], datatail, 12)))
|
|
|
+ if (strlen(buf) <= 90)
|
|
|
+ {
|
|
|
+gibberish:
|
|
|
+ applog(LOG_ERR, "%"PRIpreprv": Gibberish within queue results: %s", bitforce->proc_repr, buf);
|
|
|
continue;
|
|
|
- thiswork = work;
|
|
|
- break;
|
|
|
+ }
|
|
|
+
|
|
|
+ hex2bin(midstate, buf, 32);
|
|
|
+ hex2bin(datatail, &buf[65], 12);
|
|
|
+
|
|
|
+ thiswork = NULL;
|
|
|
+ DL_FOREACH(thr->work_list, work)
|
|
|
+ {
|
|
|
+ if (unlikely(memcmp(work->midstate, midstate, 32)))
|
|
|
+ continue;
|
|
|
+ if (unlikely(memcmp(&work->data[64], datatail, 12)))
|
|
|
+ continue;
|
|
|
+ thiswork = work;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ end = &buf[89];
|
|
|
}
|
|
|
|
|
|
- end = &buf[89];
|
|
|
chip_cgpu = bitforce;
|
|
|
if (data->parallel_protocol)
|
|
|
{
|
|
|
@@ -2084,7 +2210,7 @@ again:
|
|
|
applog(LOG_ERR, "%"PRIpreprv": Missing nonces in queue results: %s", chip_cgpu->proc_repr, buf);
|
|
|
goto finishresult;
|
|
|
}
|
|
|
- bitforce_process_result_nonces(chip_thr, work, &end[1]);
|
|
|
+ bitforce_process_result_nonces(chip_thr, thiswork, &end[1]);
|
|
|
}
|
|
|
++fcount;
|
|
|
++counts[chipno];
|
|
|
@@ -2194,9 +2320,157 @@ bool bitforce_queue_append(struct thr_info *thr, struct work *work)
|
|
|
struct _jobinfo {
|
|
|
uint8_t key[32+12];
|
|
|
int instances;
|
|
|
+ int flushed_instances;
|
|
|
UT_hash_handle hh;
|
|
|
};
|
|
|
|
|
|
+static
|
|
|
+void _bitforce_queue_flush_add_to_processing(struct _jobinfo ** const processing_p, struct _jobinfo * const this, const size_t keysz, const bool was_flushed)
|
|
|
+{
|
|
|
+ struct _jobinfo *item;
|
|
|
+ HASH_FIND(hh, *processing_p, &this->key[0], keysz, item);
|
|
|
+ if (likely(!item))
|
|
|
+ {
|
|
|
+ item = this;
|
|
|
+ this->flushed_instances = this->instances = 0;
|
|
|
+ HASH_ADD(hh, *processing_p, key, keysz, this);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // This should really only happen in testing/benchmarking...
|
|
|
+ free(this);
|
|
|
+ }
|
|
|
+ if (was_flushed)
|
|
|
+ ++item->flushed_instances;
|
|
|
+ else
|
|
|
+ ++item->instances;
|
|
|
+}
|
|
|
+
|
|
|
+static
|
|
|
+void bitforce_delete_last_n_work(struct thr_info * const thr, int n)
|
|
|
+{
|
|
|
+ while (n--)
|
|
|
+ work_list_del(&thr->work_list, thr->work_list->prev);
|
|
|
+}
|
|
|
+
|
|
|
+static
|
|
|
+void bitforce_queue_flush_sanity_check(struct thr_info * const thr, struct _jobinfo ** const processing_p, const size_t keysz, const bool ignore_race)
|
|
|
+{
|
|
|
+ struct cgpu_info * const bitforce = thr->cgpu;
|
|
|
+ struct bitforce_data * const data = bitforce->device_data;
|
|
|
+ struct work *work, *tmp;
|
|
|
+ struct _jobinfo *item, *this;
|
|
|
+ uint8_t key[keysz];
|
|
|
+ char hex[(keysz * 2) + 1];
|
|
|
+
|
|
|
+ // Iterate over the work_list and delete anything not in the hash
|
|
|
+ DL_FOREACH_SAFE(thr->work_list, work, tmp)
|
|
|
+ {
|
|
|
+ if (data->max_queueid)
|
|
|
+ {
|
|
|
+ memcpy(&key[0], &work->device_id, sizeof(work->device_id));
|
|
|
+ snprintf(hex, sizeof(hex), "%04x", work->device_id);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ memcpy(&key[ 0], work->midstate, 32);
|
|
|
+ memcpy(&key[32], &work->data[64], 12);
|
|
|
+ bin2hex(hex, key, keysz);
|
|
|
+ }
|
|
|
+ HASH_FIND(hh, *processing_p, &key[0], keysz, item);
|
|
|
+ if (unlikely(!item))
|
|
|
+ {
|
|
|
+ applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device is missing queued job! %s", bitforce->proc_repr, hex);
|
|
|
+ work_list_del(&thr->work_list, work);
|
|
|
+ --data->queued;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (item->instances)
|
|
|
+ {
|
|
|
+ applog(LOG_DEBUG, "%"PRIpreprv": Queue flush: %s inprogress", bitforce->proc_repr, hex);
|
|
|
+ --item->instances;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ --item->flushed_instances;
|
|
|
+ work_list_del(&thr->work_list, work);
|
|
|
+ // NOTE: data->queued is decremented later via bitforce_finish_flush
|
|
|
+ applog(LOG_DEBUG, "%"PRIpreprv": Queue flush: %s flushed", bitforce->proc_repr, hex);
|
|
|
+ }
|
|
|
+ if (likely(!(item->instances + item->flushed_instances)))
|
|
|
+ {
|
|
|
+ HASH_DEL(*processing_p, item);
|
|
|
+ free(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (unlikely(*processing_p))
|
|
|
+ {
|
|
|
+ HASH_ITER(hh, *processing_p, item, this)
|
|
|
+ {
|
|
|
+ bin2hex(hex, &item->key[0], keysz);
|
|
|
+ if (item->instances && !ignore_race)
|
|
|
+ applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device %s unknown work %s (%d)", bitforce->proc_repr, "is processing", hex, item->instances);
|
|
|
+ if (item->flushed_instances)
|
|
|
+ applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device %s unknown work %s (%d)", bitforce->proc_repr, "flushed", hex, item->flushed_instances);
|
|
|
+
|
|
|
+ HASH_DEL(*processing_p, item);
|
|
|
+ free(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static
|
|
|
+void bitforce_finish_flush(struct thr_info * const thr, const int flushed)
|
|
|
+{
|
|
|
+ struct cgpu_info *bitforce = thr->cgpu;
|
|
|
+ struct bitforce_data * const data = bitforce->device_data;
|
|
|
+
|
|
|
+ data->queued -= flushed;
|
|
|
+
|
|
|
+ applog(LOG_DEBUG, "%"PRIpreprv": Flushed %u jobs from device and %d from driver (queued<=%d)",
|
|
|
+ bitforce->proc_repr, flushed, data->ready_to_queue, data->queued);
|
|
|
+
|
|
|
+ bitforce_set_queue_full(thr);
|
|
|
+ data->just_flushed = true;
|
|
|
+ data->want_to_send_queue = false;
|
|
|
+ data->ready_to_queue = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static
|
|
|
+void bitforce_process_flb_result(struct thr_info * const thr, int inproc, int flushed)
|
|
|
+{
|
|
|
+ struct cgpu_info *bitforce = thr->cgpu;
|
|
|
+
|
|
|
+ size_t total = inproc + flushed, readsz;
|
|
|
+ uint16_t buf[total];
|
|
|
+ readsz = bitforce_read(bitforce, buf, total * 2) / 2;
|
|
|
+ if (unlikely(readsz != total))
|
|
|
+ {
|
|
|
+ applog(LOG_ERR, "%"PRIpreprv": Short read for FLB result", bitforce->proc_repr);
|
|
|
+ if (readsz < inproc)
|
|
|
+ {
|
|
|
+ inproc = readsz;
|
|
|
+ flushed = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ flushed = readsz - inproc;
|
|
|
+ }
|
|
|
+
|
|
|
+ const int keysz = sizeof(work_device_id_t);
|
|
|
+ struct _jobinfo *processing = NULL, *this;
|
|
|
+ for (int i = inproc + flushed; i--; )
|
|
|
+ {
|
|
|
+ this = malloc(sizeof(*this));
|
|
|
+ const work_device_id_t queueid = be16toh(buf[i]);
|
|
|
+ memcpy(&this->key[0], &queueid, sizeof(queueid));
|
|
|
+ _bitforce_queue_flush_add_to_processing(&processing, this, keysz, !(i < inproc));
|
|
|
+ }
|
|
|
+
|
|
|
+ bitforce_queue_flush_sanity_check(thr, &processing, keysz, false);
|
|
|
+
|
|
|
+ bitforce_finish_flush(thr, flushed);
|
|
|
+}
|
|
|
+
|
|
|
static
|
|
|
void bitforce_queue_flush(struct thr_info *thr)
|
|
|
{
|
|
|
@@ -2208,23 +2482,40 @@ void bitforce_queue_flush(struct thr_info *thr)
|
|
|
struct bitforce_data *data = bitforce->device_data;
|
|
|
char *buf = &data->noncebuf[0], *buf2 = NULL;
|
|
|
const char *cmd = "ZqX";
|
|
|
+ int inproc = -1;
|
|
|
unsigned flushed;
|
|
|
- struct _jobinfo *processing = NULL, *item, *this;
|
|
|
+ struct _jobinfo *processing = NULL, *this;
|
|
|
+
|
|
|
+ // First, eliminate all unsent works
|
|
|
+ bitforce_delete_last_n_work(thr, data->ready_to_queue);
|
|
|
|
|
|
if (data->parallel == 1)
|
|
|
// Pre-parallelization neither needs nor supports "ZqX"
|
|
|
cmd = "ZQX";
|
|
|
- // TODO: Call "ZQX" most of the time: don't need to do sanity checks so often
|
|
|
+ else
|
|
|
+ if (data->max_queueid)
|
|
|
+ cmd = "FLB";
|
|
|
bitforce_zox(thr, cmd);
|
|
|
if (!strncasecmp(buf, "OK:FLUSHED", 10))
|
|
|
flushed = atoi(&buf[10]);
|
|
|
else
|
|
|
if ((!strncasecmp(buf, "COUNT:", 6)) && (buf2 = strstr(buf, "FLUSHED:")) )
|
|
|
{
|
|
|
+ inproc = atoi(&buf[6]);
|
|
|
flushed = atoi(&buf2[8]);
|
|
|
buf2 = next_line(buf2);
|
|
|
}
|
|
|
else
|
|
|
+ if ((!strncasecmp(buf, "BIN-InP:", 8)) && (buf2 = strstr(buf, "FLUSHED:")) )
|
|
|
+ {
|
|
|
+ inproc = atoi(&buf[8]);
|
|
|
+ flushed = atoi(&buf2[8]);
|
|
|
+ if (unlikely(data->queued != inproc + flushed))
|
|
|
+ applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device work count mismatch (dev inproc=%d, dev flushed=%u, queued=%d)", bitforce->proc_repr, inproc, flushed, data->queued);
|
|
|
+ bitforce_process_flb_result(thr, inproc, flushed);
|
|
|
+ goto final;
|
|
|
+ }
|
|
|
+ else
|
|
|
if (!strncasecmp(buf, "OK", 2))
|
|
|
{
|
|
|
applog(LOG_DEBUG, "%"PRIpreprv": Didn't report flush count", bitforce->proc_repr);
|
|
|
@@ -2246,83 +2537,46 @@ void bitforce_queue_flush(struct thr_info *thr)
|
|
|
flushed = data->queued;
|
|
|
}
|
|
|
|
|
|
- data->queued -= flushed;
|
|
|
-
|
|
|
- applog(LOG_DEBUG, "%"PRIpreprv": Flushed %u jobs from device and %d from driver (queued<=%d)",
|
|
|
- bitforce->proc_repr, flushed, data->ready_to_queue, data->queued);
|
|
|
-
|
|
|
- flushed += data->ready_to_queue;
|
|
|
- data->ready_to_queue = 0;
|
|
|
- while (flushed--)
|
|
|
- work_list_del(&thr->work_list, thr->work_list->prev);
|
|
|
- bitforce_set_queue_full(thr);
|
|
|
- data->just_flushed = true;
|
|
|
- data->want_to_send_queue = false;
|
|
|
+ bitforce_delete_last_n_work(thr, flushed);
|
|
|
+ bitforce_finish_flush(thr, flushed);
|
|
|
|
|
|
// "ZqX" returns jobs in progress, allowing us to sanity check
|
|
|
// NOTE: Must process buffer into hash table BEFORE calling bitforce_queue_do_results, which clobbers it
|
|
|
// NOTE: Must do actual sanity check AFTER calling bitforce_queue_do_results, to ensure we don't delete completed jobs
|
|
|
+
|
|
|
+ const size_t keysz = data->max_queueid ? sizeof(work_device_id_t) : sizeof(this->key);
|
|
|
+
|
|
|
if (buf2)
|
|
|
{
|
|
|
// First, turn buf2 into a hash
|
|
|
for ( ; buf2[0]; buf2 = next_line(buf2))
|
|
|
{
|
|
|
this = malloc(sizeof(*this));
|
|
|
- hex2bin(&this->key[ 0], &buf2[ 0], 32);
|
|
|
- hex2bin(&this->key[32], &buf2[65], 12);
|
|
|
- HASH_FIND(hh, processing, &this->key[0], sizeof(this->key), item);
|
|
|
- if (likely(!item))
|
|
|
+ if (data->max_queueid)
|
|
|
{
|
|
|
- this->instances = 1;
|
|
|
- HASH_ADD(hh, processing, key, sizeof(this->key), this);
|
|
|
+ const work_device_id_t queueid = strtol(buf2, NULL, 0x10);
|
|
|
+ memcpy(&this->key[0], &queueid, sizeof(queueid));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- // This should really only happen in testing/benchmarking...
|
|
|
- ++item->instances;
|
|
|
- free(this);
|
|
|
+ hex2bin(&this->key[ 0], &buf2[ 0], 32);
|
|
|
+ hex2bin(&this->key[32], &buf2[65], 12);
|
|
|
}
|
|
|
+ _bitforce_queue_flush_add_to_processing(&processing, this, keysz, false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bitforce_queue_do_results(thr);
|
|
|
|
|
|
if (buf2)
|
|
|
+ // There is a race condition where the flush may have reported a job as in progress even though we completed and processed its results just now - so we just silence the sanity check
|
|
|
+ bitforce_queue_flush_sanity_check(thr, &processing, keysz, true);
|
|
|
+
|
|
|
+final:
|
|
|
+ if (unlikely(inproc != -1 && inproc != data->queued))
|
|
|
{
|
|
|
- struct work *work, *tmp;
|
|
|
- uint8_t key[32+12];
|
|
|
-
|
|
|
- // Now iterate over the work_list and delete anything not in the hash
|
|
|
- DL_FOREACH_SAFE(thr->work_list, work, tmp)
|
|
|
- {
|
|
|
- memcpy(&key[ 0], work->midstate, 32);
|
|
|
- memcpy(&key[32], &work->data[64], 12);
|
|
|
- HASH_FIND(hh, processing, &key[0], sizeof(key), item);
|
|
|
- if (unlikely(!item))
|
|
|
- {
|
|
|
- char hex[89];
|
|
|
- bin2hex(hex, key, 32+12);
|
|
|
- applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device is missing queued job! %s", bitforce->proc_repr, hex);
|
|
|
- work_list_del(&thr->work_list, work);
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (likely(!--item->instances))
|
|
|
- {
|
|
|
- HASH_DEL(processing, item);
|
|
|
- free(item);
|
|
|
- }
|
|
|
- }
|
|
|
- if (unlikely( (flushed = HASH_COUNT(processing)) ))
|
|
|
- {
|
|
|
- //applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device is working on %d unknown jobs!", bitforce->proc_repr, flushed);
|
|
|
- // FIXME: Probably these were jobs finished after ZqX, included in the result check we just did
|
|
|
- // NOTE: We need to do that result check first to avoid deleting work_list items for things just solved
|
|
|
- HASH_ITER(hh, processing, item, this)
|
|
|
- {
|
|
|
- HASH_DEL(processing, item);
|
|
|
- free(item);
|
|
|
- }
|
|
|
- }
|
|
|
+ applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device work inprogress count mismatch (dev inproc=%d, queued=%d)", bitforce->proc_repr, inproc, data->queued);
|
|
|
+ data->queued = inproc;
|
|
|
}
|
|
|
}
|
|
|
|