Professional Documents
Culture Documents
#include "config.h"
#include "compat.h"
#include "miner.h"
#ifndef LINUX
#ifdef USE_ANT_S1
static void ants1_detect(__maybe_unused bool hotplug)
{
}
#endif
#ifdef USE_ANT_S2
#ifdef USE_ANT_S3
static void ants3_detect(__maybe_unused bool hotplug)
{
}
#else
static void ants2_detect(__maybe_unused bool hotplug)
{
}
#endif
#endif
#else // LINUX
#include "elist.h"
#if (defined(USE_ANT_S1) || defined(USE_ANT_S3))
#include "usbutils.h"
#else
#define C_BITMAIN_READ 0
#define C_BITMAIN_DATA_RXSTATUS 0
#endif
#include "driver-bitmain.h"
#include "hexdump.c"
#include "util.h"
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#ifdef USE_ANT_S1
#define ANTDRV ants1_drv
#else
#ifdef USE_ANT_S3
#define ANTDRV ants3_drv
#else
#define ANTDRV ants2_drv
#endif
#endif
#define BITMAIN_CALC_DIFF1 1
while (w_len--) {
wIndex = chCRCLo ^ *p_data++;
chCRCLo = chCRCHi ^ chCRCHTalbe[wIndex];
chCRCHi = chCRCLTalbe[wIndex];
}
return ((chCRCHi << 8) | chCRCLo);
}
#ifdef USE_ANT_S1
static bool get_options(int this_option_offset, int *baud, int *chain_num,
int *asic_num, int *timeout, int *frequency,
uint8_t *reg_data)
{
char buf[BUFSIZ+1];
char *ptr, *comma, *colon, *colon2, *colon3, *colon4, *colon5;
size_t max;
int tmp;
if (opt_bitmain_options == NULL)
buf[0] = '\0';
else {
// Always use the first set if more than one
ptr = opt_bitmain_options;
comma = strchr(ptr, ',');
if (comma)
*comma = '\0';
max = strlen(ptr);
if (max > BUFSIZ)
max = BUFSIZ;
strncpy(buf, ptr, max);
buf[max] = '\0';
}
if (!(*buf))
return false;
tmp = atoi(buf);
switch (tmp) {
case 115200:
*baud = 115200;
break;
case 57600:
*baud = 57600;
break;
case 38400:
*baud = 38400;
break;
case 19200:
*baud = 19200;
break;
default:
quit(1, "Invalid bitmain-options for baud (%s) "
"must be 115200, 57600, 38400 or 19200", buf);
}
if (*colon) {
tmp = atoi(colon);
if (tmp > 0)
*chain_num = tmp;
else {
quit(1, "Invalid bitmain-options for "
"chain_num (%s) must be 1 ~ %d",
colon, BITMAIN_DEFAULT_CHAIN_NUM);
}
}
tmp = atoi(colon2);
if (tmp > 0 && tmp <= BITMAIN_DEFAULT_ASIC_NUM)
*asic_num = tmp;
else {
quit(1, "Invalid bitmain-options for "
"asic_num (%s) must be 1 ~ %d",
colon2, BITMAIN_DEFAULT_ASIC_NUM);
}
tmp = atoi(colon3);
if (tmp > 0 && tmp <= 0xff)
*timeout = tmp;
else {
quit(1, "Invalid bitmain-options for "
"timeout (%s) must be 1 ~ %d",
colon3, 0xff);
}
if (colon4 && *colon4) {
colon5 = strchr(colon4, ':');
if (colon5)
*(colon5++) = '\0';
tmp = atoi(colon4);
if (tmp < BITMAIN_MIN_FREQUENCY ||
tmp > BITMAIN_MAX_FREQUENCY) {
quit(1, "Invalid bitmain-options for
frequency,"
" must be %d <= frequency <= %d",
BITMAIN_MIN_FREQUENCY,
BITMAIN_MAX_FREQUENCY);
} else
*frequency = tmp;
if (opt_bitmain_options == NULL)
buf[0] = '\0';
else {
// Always use the first set if more than one
ptr = opt_bitmain_options;
comma = strchr(ptr, ',');
if (comma)
*comma = '\0';
max = strlen(ptr);
if (max > BUFSIZ)
max = BUFSIZ;
strncpy(buf, ptr, max);
buf[max] = '\0';
}
if (!(*buf))
return false;
colon = strchr(buf, ':');
if (colon)
*(colon++) = '\0';
tmp = atoi(buf);
switch (tmp) {
case 115200:
*baud = 115200;
break;
case 57600:
*baud = 57600;
break;
case 38400:
*baud = 38400;
break;
case 19200:
*baud = 19200;
break;
default:
quit(1, "Invalid bitmain-options for baud (%s) "
"must be 115200, 57600, 38400 or 19200", buf);
}
if (*colon) {
tmp = atoi(colon);
if (tmp > 0)
*chain_num = tmp;
else {
quit(1, "Invalid bitmain-options for "
"chain_num (%s) must be 1 ~ %d",
colon, BITMAIN_DEFAULT_CHAIN_NUM);
}
}
tmp = atoi(colon2);
if (tmp > 0 && tmp <= BITMAIN_DEFAULT_ASIC_NUM)
*asic_num = tmp;
else {
quit(1, "Invalid bitmain-options for "
"asic_num (%s) must be 1 ~ %d",
colon2, BITMAIN_DEFAULT_ASIC_NUM);
}
}
}
return true;
}
#endif
#ifdef USE_ANT_S1
static int bitmain_set_txconfig(struct bitmain_txconfig_token *bm,
uint8_t reset, uint8_t fan_eft, uint8_t timeout_eft,
uint8_t frequency_eft,
uint8_t voltage_eft, uint8_t chain_check_time_eft, uint8_t
chip_config_eft,
uint8_t hw_error_eft, uint8_t chain_num, uint8_t asic_num,
uint8_t fan_pwm_data, uint8_t timeout_data,
uint16_t frequency, uint8_t voltage, uint8_t
chain_check_time,
uint8_t chip_address, uint8_t reg_address, uint8_t *
reg_data)
#else
static int bitmain_set_txconfig(struct bitmain_txconfig_token *bm,
uint8_t reset, uint8_t fan_eft, uint8_t timeout_eft,
uint8_t frequency_eft,
uint8_t voltage_eft, uint8_t chain_check_time_eft, uint8_t
chip_config_eft,
uint8_t hw_error_eft, uint8_t beeper_ctrl, uint8_t
temp_over_ctrl,
uint8_t chain_num, uint8_t asic_num,
uint8_t fan_pwm_data, uint8_t timeout_data,
uint16_t frequency, uint8_t *voltage, uint8_t
chain_check_time,
uint8_t chip_address, uint8_t reg_address, uint8_t *
reg_data)
#endif
{
uint16_t crc = 0;
int datalen = 0;
#ifdef USE_ANT_S2
uint8_t version = 0;
#endif
uint8_t *sendbuf = (uint8_t *)bm;
if (unlikely(!bm)) {
applog(LOG_WARNING, "%s: %s() bm is null", ANTDRV.dname, __func__);
return -1;
}
bm->token_type = BITMAIN_TOKEN_TYPE_TXCONFIG;
#ifdef USE_ANT_S1
bm->length = datalen-2;
#else
bm->version = version;
bm->length = datalen-4;
bm->length = htole16(bm->length);
#endif
bm->reset = reset;
bm->fan_eft = fan_eft;
bm->timeout_eft = timeout_eft;
bm->frequency_eft = frequency_eft;
bm->voltage_eft = voltage_eft;
bm->chain_check_time_eft = chain_check_time_eft;
bm->chip_config_eft = chip_config_eft;
bm->hw_error_eft = hw_error_eft;
#ifdef USE_ANT_S1
sendbuf[2] = bitswap(sendbuf[2]);
#else
bm->beeper_ctrl = beeper_ctrl;
bm->temp_over_ctrl = temp_over_ctrl;
sendbuf[4] = bitswap(sendbuf[4]);
sendbuf[5] = bitswap(sendbuf[5]);
#endif
bm->chain_num = chain_num;
bm->asic_num = asic_num;
bm->fan_pwm_data = fan_pwm_data;
bm->timeout_data = timeout_data;
bm->frequency = htole16(frequency);
#ifdef USE_ANT_S1
bm->voltage = voltage;
#else
bm->voltage[0] = voltage[0];
bm->voltage[1] = voltage[1];
#endif
bm->chain_check_time = chain_check_time;
#ifdef USE_ANT_S1
applogsiz(LOG_DEBUG, 512, "%s: %s() reset(%d) faneft(%d) touteft(%d)
freqeft(%d)"
" volteft(%d) chainceft(%d) chipceft(%d) hweft(%d) mnum(%d)"
" anum(%d) fanpwmdata(%d) toutdata(%d) freq(%d) volt(%d)"
" chainctime(%d) regdata(%02x%02x%02x%02x) chipaddr(%02x)"
" regaddr(%02x) crc(%04x)",
ANTDRV.dname, __func__,
(int)reset, (int)fan_eft, (int)timeout_eft, (int)frequency_eft,
(int)voltage_eft, (int)chain_check_time_eft,
(int)chip_config_eft,
(int)hw_error_eft, (int)chain_num, (int)asic_num,
(int)fan_pwm_data,
(int)timeout_data, (int)frequency, (int)voltage,
(int)chain_check_time,
(int)reg_data[0], (int)reg_data[1], (int)reg_data[2],
(int)reg_data[3],
(int)chip_address, (int)reg_address, (int)crc);
#else
applogsiz(LOG_DEBUG, 512, "%s: %s() v(%d) reset(%d) faneft(%d) touteft(%d)
freqeft(%d)"
" volteft(%d) chainceft(%d) chipceft(%d) hweft(%d)"
" beepctrl(%d) toverctl(%d) mnum(%d)"
" anum(%d) fanpwmdata(%d) toutdata(%d) freq(%d) volt(%02x%02x)"
" chainctime(%d) regdata(%02x%02x%02x%02x) chipaddr(%02x)"
" regaddr(%02x) crc(%04x)",
ANTDRV.dname, __func__,
(int)version, (int)reset, (int)fan_eft, (int)timeout_eft,
(int)frequency_eft, (int)voltage_eft, (int)chain_check_time_eft,
(int)chip_config_eft, (int)hw_error_eft, (int)beeper_ctrl,
(int)temp_over_ctrl, (int)chain_num, (int)asic_num,
(int)fan_pwm_data,
(int)timeout_data, (int)frequency, (int)voltage[0],
(int)voltage[1],
(int)chain_check_time, (int)reg_data[0], (int)reg_data[1],
(int)reg_data[2], (int)reg_data[3], (int)chip_address,
(int)reg_address, (int)crc);
#endif
return datalen;
}
*sentcount = 0;
if (unlikely(!bm)) {
applog(LOG_WARNING, "%s: %s() bm is null", ANTDRV.dname, __func__);
return -1;
}
memset(bm, 0, sizeof(struct bitmain_txtask_token));
bm->token_type = BITMAIN_TOKEN_TYPE_TXTASK;
#ifdef USE_ANT_S2
bm->version = version;
if (info->wbuild->head)
quithere(1, "%s: %s() wbuild wasn't empty", ANTDRV.dname, __func__);
#endif
datalen = 10;
applog(LOG_DEBUG, "%s: send work count %d", ANTDRV.dname, info->work_ready-
>count);
while (info->work_ready->count) {
witem = k_unlink_tail(info->work_ready);
if (DATAW(witem)->work->work_block > *last_work_block) {
applog(LOG_ERR, "%s: send task new block %d old(%d)",
ANTDRV.dname,
DATAW(witem)->work->work_block, *last_work_block);
new_block = 1;
*last_work_block = DATAW(witem)->work->work_block;
}
wid = DATAW(witem)->wid;
bm->works[cursentcount].work_id = htole32(wid);
applog(LOG_DEBUG, "%s: send task work id:%"PRIu32" %"PRIu32,
ANTDRV.dname,
wid, bm->works[cursentcount].work_id);
memcpy(bm->works[cursentcount].midstate, DATAW(witem)->work->midstate,
32);
memcpy(bm->works[cursentcount].data2, DATAW(witem)->work->data + 64,
12);
cursentcount++;
#ifdef USE_ANT_S1
k_add_head(info->work_list, witem);
#else
k_add_head(info->wbuild, witem);
diffbits = (int)floor(log2(DATAW(witem)->work->sdiff));
if (diffbits < 0)
diffbits = 0;
// Limit to 4096 so solo mining has reasonable mining stats
if (diffbits > 12)
diffbits = 12;
}
if (cursentcount <= 0) {
applog(LOG_ERR, "%s: send work count %d", ANTDRV.dname, cursentcount);
return 0;
}
#ifdef USE_ANT_S2
workdiff = pow(2.0, (double)lowestdiffbits);
witem = info->wbuild->head;
while (witem) {
DATAW(witem)->work->device_diff = workdiff;
witem = witem->next;
}
k_list_transfer_to_head(info->wbuild, info->work_list);
#endif
datalen += 48*cursentcount;
bm->length = datalen-4;
bm->length = htole16(bm->length);
//len = datalen-3;
//len = htole16(len);
//memcpy(sendbuf+1, &len, 2);
bm->new_block = new_block;
#ifdef USE_ANT_S2
bm->diff = lowestdiffbits;
#endif
sendbuf[4] = bitswap(sendbuf[4]);
*sentcount = cursentcount;
#ifdef USE_ANT_S1
applog(LOG_DEBUG, "%s: TxTask Token: new_block(%d) work_num(%d)"
" crc(%04x)",
ANTDRV.dname,
(int)new_block, cursentcount, (int)crc);
#else
applog(LOG_DEBUG, "%s: TxTask Token: v(%d) new_block(%d)"
" diff(%d work:%f) work_num(%d) crc(%04x)",
ANTDRV.dname,
(int)version, (int)new_block, lowestdiffbits, workdiff,
cursentcount, (int)crc);
#endif
applog(LOG_DEBUG, "%s: TxTask Token: %d %d %02x%02x%02x%02x%02x%02x",
ANTDRV.dname,
datalen, bm->length,
sendbuf[0], sendbuf[1], sendbuf[2],
sendbuf[3], sendbuf[4], sendbuf[5]);
return datalen;
}
if (unlikely(!bm)) {
applog(LOG_WARNING, "%s: %s() bm is null", ANTDRV.dname, __func__);
return -1;
}
bm->token_type = BITMAIN_TOKEN_TYPE_RXSTATUS;
#ifdef USE_ANT_S1
bm->length = datalen-2;
#else
bm->version = version;
bm->length = datalen-4;
bm->length = htole16(bm->length);
#endif
bm->chip_status_eft = chip_status_eft;
bm->detect_get = detect_get;
#ifdef USE_ANT_S1
sendbuf[2] = bitswap(sendbuf[2]);
#else
sendbuf[4] = bitswap(sendbuf[4]);
#endif
bm->chip_address = chip_address;
bm->reg_address = reg_address;
#ifdef USE_ANT_S1
applog(LOG_DEBUG, "%s: RxStatus Token: chip_status_eft(%d) detect_get(%d)"
" chip_address(%02x) reg_address(%02x) crc(%04x)",
ANTDRV.dname,
(int)chip_status_eft, (int)detect_get, chip_address,
reg_address, crc);
#else
applog(LOG_DEBUG, "%s: RxStatus Token: v(%d) chip_status_eft(%d)
detect_get(%d)"
" chip_address(%02x) reg_address(%02x) crc(%04x)",
ANTDRV.dname,
(int)version, (int)chip_status_eft, (int)detect_get,
chip_address, reg_address, crc);
#endif
return datalen;
}
if (unlikely(!bm)) {
applog(LOG_ERR, "%s: %s() bm is null", ANTDRV.dname, __func__);
return -1;
}
if (unlikely(!data || datalen <= 0)) {
applog(LOG_ERR, "%s: %s() parameter invalid data is null"
" or datalen(%d) error",
ANTDRV.dname, __func__, datalen);
return -1;
}
#ifdef USE_ANT_S1
memcpy(bm, data, sizeof(struct bitmain_rxstatus_data));
if (bm->data_type != BITMAIN_DATA_TYPE_RXSTATUS) {
applog(LOG_ERR, "%s: %s() datatype(%02x) error",
ANTDRV.dname, __func__,
bm->data_type);
return -1;
}
if (bm->length+2 != datalen) {
applog(LOG_ERR, "%s: %s() length(%d) datalen(%d) error",
ANTDRV.dname, __func__,
bm->length, datalen);
return -1;
}
crc = CRC16(data, datalen-2);
memcpy(&(bm->crc), data+datalen-2, 2);
bm->crc = htole16(bm->crc);
if (crc != bm->crc) {
applog(LOG_ERR, "%s: %s() check crc(%d)"
" != bm crc(%d) datalen(%d)",
ANTDRV.dname, __func__,
crc, bm->crc, datalen);
return -1;
}
bm->fifo_space = htole32(bm->fifo_space);
bm->nonce_error = htole32(bm->nonce_error);
if (bm->chain_num*5 + bm->temp_num + bm->fan_num + 22 != datalen) {
applog(LOG_ERR, "%s: %s() chain_num(%d) temp_num(%d)"
" fan_num(%d) not match datalen(%d)",
ANTDRV.dname, __func__,
bm->chain_num, bm->temp_num, bm->fan_num, datalen);
return -1;
}
if (bm->chain_num > BITMAIN_MAX_CHAIN_NUM) {
applog(LOG_ERR, "%s: %s() chain_num=%d error",
ANTDRV.dname, __func__,
bm->chain_num);
return -1;
}
if (bm->chain_num > 0) {
memcpy(bm->chain_asic_status, data+20, bm->chain_num*4);
memcpy(bm->chain_asic_num, data+20+bm->chain_num*4, bm->chain_num);
}
for (i = 0; i < bm->chain_num; i++)
bm->chain_asic_status[i] = htole32(bm->chain_asic_status[i]);
if (bm->temp_num > 0)
memcpy(bm->temp, data+20+bm->chain_num*5, bm->temp_num);
if (bm->fan_num > 0)
memcpy(bm->fan, data+20+bm->chain_num*5+bm->temp_num, bm->fan_num);
applog(LOG_DEBUG, "%s: RxStatus Data chipvalueeft(%d) version(%d)
fifospace(%d)"
" regvalue(%d) chainnum(%d) tempnum(%d) fannum(%d) crc(%04x)",
ANTDRV.dname,
bm->chip_value_eft, bm->version, bm->fifo_space, bm->reg_value,
bm->chain_num, bm->temp_num, bm->fan_num, bm->crc);
applog(LOG_DEBUG, "%s: RxStatus Data chain info:", ANTDRV.dname);
for (i = 0; i < bm->chain_num; i++) {
applog(LOG_DEBUG, "%s: RxStatus Data chain(%d) asic num=%d asic_status=
%08x",
ANTDRV.dname,
i+1, bm->chain_asic_num[i], bm->chain_asic_status[i]);
}
#else // USE_ANT_S2
memset(bm, 0, sizeof(struct bitmain_rxstatus_data));
memcpy(bm, data, 28);
if (bm->data_type != BITMAIN_DATA_TYPE_RXSTATUS) {
applog(LOG_ERR, "%s: %s() datatype(%02x) error",
ANTDRV.dname, __func__,
bm->data_type);
return -1;
}
if (bm->version != version) {
applog(LOG_ERR, "%s: %s() version(%02x) error",
ANTDRV.dname, __func__,
bm->version);
return -1;
}
bm->length = htole16(bm->length);
if (bm->length+4 != datalen) {
applog(LOG_ERR, "%s: %s() length(%d) datalen(%d) error",
ANTDRV.dname, __func__,
bm->length, datalen);
return -1;
}
crc = CRC16(data, datalen-2);
memcpy(&(bm->crc), data+datalen-2, 2);
bm->crc = htole16(bm->crc);
if (crc != bm->crc) {
applog(LOG_ERR, "%s: %s() check crc(%d)"
" != bm crc(%d) datalen(%d)",
ANTDRV.dname, __func__,
crc, bm->crc, datalen);
return -1;
}
bm->fifo_space = htole16(bm->fifo_space);
bm->fan_exist = htole16(bm->fan_exist);
bm->temp_exist = htole32(bm->temp_exist);
bm->nonce_error = htole32(bm->nonce_error);
if (bm->chain_num > BITMAIN_MAX_CHAIN_NUM) {
applog(LOG_ERR, "%s: %s() chain_num=%d error",
ANTDRV.dname, __func__,
bm->chain_num);
return -1;
}
dataindex = 28;
if (bm->chain_num > 0) {
memcpy(bm->chain_asic_num,
data+datalen-2-bm->chain_num-bm->temp_num-bm->fan_num,
bm->chain_num);
}
for (i = 0; i < bm->chain_num; i++) {
asic_num = bm->chain_asic_num[i];
if (asic_num < 0)
asic_num = 1;
else {
if (asic_num % 32 == 0)
asic_num = asic_num / 32;
else
asic_num = asic_num / 32 + 1;
}
memcpy((uint8_t *)bm->chain_asic_exist+i*32, data+dataindex,
asic_num*4);
dataindex += asic_num*4;
}
for(i = 0; i < bm->chain_num; i++) {
asic_num = bm->chain_asic_num[i];
if (asic_num < 0)
asic_num = 1;
else {
if (asic_num % 32 == 0)
asic_num = asic_num / 32;
else
asic_num = asic_num / 32 + 1;
}
memcpy((uint8_t *)bm->chain_asic_status+i*32, data+dataindex,
asic_num*4);
dataindex += asic_num*4;
}
dataindex += bm->chain_num;
if ((dataindex + bm->temp_num + bm->fan_num + 2) != datalen) {
applog(LOG_ERR, "%s: %s() dataindex(%d) chain_num(%d) temp_num(%d)"
" fan_num(%d) not match datalen(%d)",
ANTDRV.dname, __func__,
dataindex, bm->chain_num, bm->temp_num, bm->fan_num,
datalen);
return -1;
}
for (i = 0; i < bm->chain_num; i++) {
for (j = 0; j < 8; j++) {
bm->chain_asic_exist[i*8+j] = htole32(bm-
>chain_asic_exist[i*8+j]);
bm->chain_asic_status[i*8+j] = htole32(bm-
>chain_asic_status[i*8+j]);
}
}
if (bm->temp_num > 0) {
memcpy(bm->temp, data+dataindex, bm->temp_num);
dataindex += bm->temp_num;
}
if (bm->fan_num > 0) {
memcpy(bm->fan, data+dataindex, bm->fan_num);
dataindex += bm->fan_num;
}
applog(LOG_DEBUG, "%s: RxStatus Data chipv_e(%d) chainnum(%d) fifos(%d)"
" v1(%d) v2(%d) v3(%d) v4(%d) fann(%d) tempn(%d) fanet(%04x)"
" tempet(%08x) ne(%d) regvalue(%d) crc(%04x)",
ANTDRV.dname,
bm->chip_value_eft, bm->chain_num, bm->fifo_space,
bm->hw_version[0], bm->hw_version[1], bm->hw_version[2],
bm->hw_version[3], bm->fan_num, bm->temp_num, bm->fan_exist,
bm->temp_exist, bm->nonce_error, bm->reg_value, bm->crc);
applog(LOG_DEBUG, "%s: RxStatus Data chain info:", ANTDRV.dname);
for (i = 0; i < bm->chain_num; i++) {
applog(LOG_DEBUG, "%s: RxStatus Data chain(%d) asic num=%d asic_exists=
%08x"
" asic_status=%08x",
ANTDRV.dname,
i+1, bm->chain_asic_num[i], bm->chain_asic_exist[i*8],
bm->chain_asic_status[i*8]);
}
#endif
if (bm->data_type != BITMAIN_DATA_TYPE_RXNONCE) {
applog(LOG_ERR, "%s: %s() datatype(%02x) error",
ANTDRV.dname, __func__,
bm->data_type);
return -1;
}
#ifdef USE_ANT_S1
if (bm->length+2 != datalen) {
applog(LOG_ERR, "%s: %s() length(%d) error",
ANTDRV.dname, __func__,
bm->length);
return -1;
}
#else
if (bm->version != version) {
applog(LOG_ERR, "%s: %s() version(%02x) error",
ANTDRV.dname, __func__,
bm->version);
return -1;
}
bm->length = htole16(bm->length);
if (bm->length+4 != datalen) {
applog(LOG_ERR, "%s: %s() length(%d) datalen(%d) error",
ANTDRV.dname, __func__,
bm->length, datalen);
return -1;
}
#endif
crc = CRC16(data, datalen-2);
memcpy(&(bm->crc), data+datalen-2, 2);
bm->crc = htole16(bm->crc);
if (crc != bm->crc) {
applog(LOG_ERR, "%s: %s() check crc(%d)"
" != bm crc(%d) datalen(%d)",
ANTDRV.dname, __func__,
crc, bm->crc, datalen);
return -1;
}
#ifdef USE_ANT_S1
curnoncenum = (datalen-4)/8;
#else
bm->fifo_space = htole16(bm->fifo_space);
bm->diff = htole16(bm->diff);
bm->total_nonce_num = htole64(bm->total_nonce_num);
curnoncenum = (datalen-14)/8;
#endif
applog(LOG_DEBUG, "%s: RxNonce Data: nonce_num(%d) fifo_space(%d)",
ANTDRV.dname, curnoncenum, bm->fifo_space);
for (i = 0; i < curnoncenum; i++) {
bm->nonces[i].work_id = htole32(bm->nonces[i].work_id);
bm->nonces[i].nonce = htole32(bm->nonces[i].nonce);
applog(LOG_DEBUG, "%s: RxNonce Data %d: work_id(%"PRIu32") nonce(%08x)
(%d)",
ANTDRV.dname,
i, bm->nonces[i].work_id,
bm->nonces[i].nonce, bm->nonces[i].nonce);
}
*nonce_num = curnoncenum;
return 0;
}
if (unlikely(err != 0)) {
applog(LOG_ERR, "%s%d: usb_write error on %s() err=%d",
bitmain->drv->name, bitmain->device_id, __func__, err);
return BTM_SEND_ERROR;
}
if (amount != len) {
applog(LOG_ERR, "%s%d: usb_write length mismatch on %s() "
"amount=%d len=%d",
bitmain->drv->name, bitmain->device_id, __func__,
amount, (int)len);
return BTM_SEND_ERROR;
}
#else
sent = 0;
if (datalen <= 0) {
return 0;
}
//info = bitmain->device_data;
//delay = datalen * 10 * 1000000;
//delay = delay / info->baud;
//delay += 4000;
if (opt_debug) {
applog(LOG_DEBUG, "%s: Sent(%d):", ANTDRV.dname, datalen);
hexdump(data, datalen);
}
//cgsleep_prepare_r(&ts_start);
applog(LOG_DEBUG, "%s: %s() start", ANTDRV.dname, __func__);
ret = bitmain_write(bitmain, (char *)data, datalen, ep);
applog(LOG_DEBUG, "%s: %s() stop ret=%d datalen=%d",
ANTDRV.dname, __func__, ret, datalen);
//cgsleep_us_r(&ts_start, delay);
return ret;
}
inc_hw_errors(thr);
info->no_matching_work++;
}
*temp_avg = 0.0;
info->fan_num = bm->fan_num;
for (i = 0; i < bm->fan_num; i++)
info->fan[i] = bm->fan[i] * BITMAIN_FAN_FACTOR;
info->temp_num = bm->temp_num;
info->temp_hi = 0;
for (i = 0; i < bm->temp_num; i++) {
info->temp[i] = bm->temp[i];
/* if (bm->temp[i] & 0x80) {
bm->temp[i] &= 0x7f;
info->temp[i] = 0 - ((~bm->temp[i] & 0x7f) + 1);
}*/
*temp_avg += info->temp[i];
if (bm->temp_num > 0) {
*temp_avg = *temp_avg / bm->temp_num;
info->temp_avg = *temp_avg;
}
}
j++;
}
applog(LOG_DEBUG, "%s%d: %s() RxStatus Data
chain(%d)"
" asic_num=%d asic_status=%08x-%s",
bitmain->drv->name, bitmain->device_id,
__func__,
n, info->chain_asic_num[n],
info->chain_asic_status[n],
info->chain_asic_status_t[n]);
}
mutex_unlock(&info->qlock);
if (errordiff > 0) {
for (j = 0; j < errordiff; j++) {
bitmain_inc_nvw(info, thr);
}
mutex_lock(&info->qlock);
info->last_nonce_error += errordiff;
mutex_unlock(&info->qlock);
}
bitmain_update_temps(bitmain, info, &rxstatusdata);
}
found = true;
spare = buf[i+1] + 2 + i;
if (spare > *offset) {
applog(LOG_ERR, "%s%d: %s() spare(%d) > offset(%d)",
bitmain->drv->name, bitmain->device_id,
__func__, spare, *offset);
spare = *offset;
}
break;
} else if (buf[i] == 0xa2) {
struct bitmain_rxnonce_data rxnoncedata;
int nonce_num = 0;
applog(LOG_DEBUG, "%s%d: %s() RxNonce Data",
bitmain->drv->name, bitmain->device_id,
__func__);
if (*offset < 2) {
return;
}
if (buf[i+1] > 70) {
applog(LOG_ERR, "%s%d: %s() RxNonce Data datalen=%d error",
bitmain->drv->name, bitmain->device_id,
__func__, buf[i+1]+2);
continue;
}
if (*offset < buf[i+1] + 2) {
return;
}
if (bitmain_parse_rxnonce(buf+i, buf[i+1]+2, &rxnoncedata,
&nonce_num) != 0) {
applog(LOG_ERR, "%s%d: %s() RxNonce Data error len=%d",
bitmain->drv->name, bitmain->device_id,
__func__, buf[i+1]+2);
} else {
for (j = 0; j < nonce_num; j++) {
uint32_t wid = rxnoncedata.nonces[j].work_id;
searches = 0;
mutex_lock(&info->qlock);
witem = info->work_list->head;
while (witem) {
searches++;
if (DATAW(witem)->wid == wid)
break;
witem = witem->next;
}
mutex_unlock(&info->qlock);
if (witem) {
if (info->work_search == 0) {
info->min_search = searches;
info->max_search = searches;
} else {
if (info->min_search > searches)
info->min_search = searches;
if (info->max_search < searches)
info->max_search = searches;
}
info->work_search++;
info->tot_search += searches;
work = DATAW(witem)->work;
applog(LOG_DEBUG, "%s%d: %s() RxNonce Data find
"
"work(%"PRIu32")(%08x)",
bitmain->drv->name,
bitmain->device_id,
__func__, wid,
rxnoncedata.nonces[j].nonce);
rxnoncedata.nonces[j].work_id);
}
}
} else {
if (info->failed_search == 0) {
info->min_failed = searches;
info->max_failed = searches;
} else {
if (info->min_failed > searches)
info->min_failed = searches;
if (info->max_failed < searches)
info->max_failed = searches;
}
info->failed_search++;
info->tot_failed += searches;
mutex_lock(&info->qlock);
uint32_t min = 0, max = 0;
int count = 0;
if (info->work_list->tail) {
min = DATAW(info->work_list->tail)->wid;
max = DATAW(info->work_list->head)->wid;
count = info->work_list->count;
}
mutex_unlock(&info->qlock);
applog(LOG_ERR, "%s%d: %s() Work not found"
" for id (%"PRIu32") (min=%"
PRIu32" max=%"PRIu32" count=%d)",
bitmain->drv->name,
bitmain->device_id,
__func__, wid,
min, max, count);
}
}
mutex_lock(&info->qlock);
info->fifo_space = rxnoncedata.fifo_space;
mutex_unlock(&info->qlock);
applog(LOG_DEBUG, "%s%d: %s() RxNonce Data fifo space=%d",
bitmain->drv->name, bitmain->device_id,
__func__, rxnoncedata.fifo_space);
}
found = true;
spare = buf[i+1] + 2 + i;
if (spare > *offset) {
applog(LOG_ERR, "%s%d: %s() RxNonce Data space(%d) >
offset(%d)",
bitmain->drv->name, bitmain->device_id,
__func__,
spare, *offset);
spare = *offset;
}
break;
} else {
applog(LOG_ERR, "%s%d: %s() data type error=%02x",
bitmain->drv->name, bitmain->device_id,
__func__, buf[i]);
}
}
if (!found) {
spare = *offset - BITMAIN_READ_SIZE;
/* We are buffering and haven't accumulated one more corrupt
* work result. */
if (spare < (int)BITMAIN_READ_SIZE)
return;
bitmain_inc_nvw(info, thr);
}
*offset -= spare;
memmove(buf, buf + spare, *offset);
#else // S2
int i, j, n, m, r, errordiff, spare = BITMAIN_READ_SIZE;
uint32_t checkbit = 0x00000000;
bool found = false;
struct work *work = NULL;
struct bitmain_packet_head packethead;
int asicnum = 0, mod = 0, tmp = 0;
uint64_t searches;
K_ITEM *witem;
if (errordiff > 0) {
for (j = 0; j < errordiff; j++)
bitmain_inc_nvw(info, thr);
mutex_lock(&info->qlock);
info->last_nonce_error += errordiff;
mutex_unlock(&info->qlock);
}
bitmain_update_temps(bitmain, info, &rxstatusdata);
}
found = true;
spare = packethead.length + 4 + i;
if (spare > *offset) {
applog(LOG_ERR, "%s%d: %s() spare(%d) > offset(%d)",
bitmain->drv->name, bitmain->device_id,
__func__, spare, *offset);
spare = *offset;
}
break;
} else if (buf[i] == 0xa2) {
struct bitmain_rxnonce_data rxnoncedata;
int nonce_num = 0;
applog(LOG_DEBUG, "%s%d: %s() RxNonce Data",
bitmain->drv->name, bitmain->device_id,
__func__);
if (*offset < 4)
return;
memcpy(&packethead, buf+i, sizeof(struct bitmain_packet_head));
packethead.length = htole16(packethead.length);
if (packethead.length > 1030) {
applog(LOG_ERR, "%s%d: %s() RxNonce Data datalen=%d error",
bitmain->drv->name, bitmain->device_id,
__func__, packethead.length+4);
continue;
}
if (*offset < packethead.length + 4)
return;
if (bitmain_parse_rxnonce(buf+i, packethead.length+4,
&rxnoncedata, &nonce_num) != 0) {
applog(LOG_ERR, "%s%d: %s() RxNonce Data error len=%d",
bitmain->drv->name, bitmain->device_id,
__func__, packethead.length+4);
} else {
for (j = 0; j < nonce_num; j++) {
uint32_t wid = rxnoncedata.nonces[j].work_id;
searches = 0;
mutex_lock(&info->qlock);
witem = info->work_list->head;
while (witem && DATAW(witem)->work) {
searches++;
if (DATAW(witem)->wid == wid)
break;
witem = witem->next;
}
if (witem && DATAW(witem)->work) {
work = DATAW(witem)->work;
mutex_unlock(&info->qlock);
if (info->work_search == 0) {
info->min_search = searches;
info->max_search = searches;
} else {
if (info->min_search > searches)
info->min_search = searches;
if (info->max_search < searches)
info->max_search = searches;
}
info->work_search++;
info->tot_search += searches;
rxnoncedata.nonces[j].work_id);
}
}
} else {
mutex_unlock(&info->qlock);
if (info->failed_search == 0) {
info->min_failed = searches;
info->max_failed = searches;
} else {
if (info->min_failed > searches)
info->min_failed = searches;
if (info->max_failed < searches)
info->max_failed = searches;
}
info->failed_search++;
info->tot_failed += searches;
found = true;
spare = packethead.length + 4 + i;
if (spare > *offset) {
applog(LOG_ERR, "%s%d: %s() RxNonce Data space(%d) >
offset(%d)",
bitmain->drv->name, bitmain->device_id,
__func__,
spare, *offset);
spare = *offset;
}
break;
} else {
applog(LOG_ERR, "%s%d: %s() data type error=%02x",
bitmain->drv->name, bitmain->device_id,
__func__, buf[i]);
}
}
if (!found) {
spare = *offset - BITMAIN_READ_SIZE;
/* We are buffering and haven't accumulated one more corrupt
* work result. */
if (spare < (int)BITMAIN_READ_SIZE)
return;
bitmain_inc_nvw(info, thr);
}
*offset -= spare;
memmove(buf, buf + spare, *offset);
#endif
}
while (likely(!bitmain->shutdown)) {
unsigned char buf[rsize];
if (unlikely(info->reset)) {
bitmain_running_reset(info);
/* Discard anything in the buffer */
offset = 0;
}
#ifdef USE_ANT_S1
// 2ms shouldn't be too much
cgsleep_ms(2);
#endif
if (ret < 1) {
errorcount++;
info->read_bad++;
#ifdef USE_ANT_S1
if (errorcount > 100) {
#else
if (errorcount > 3) {
#endif
// applog(LOG_ERR, "%s%d: read errorcount>100 ret=%d",
// bitmain->drv->name, bitmain->device_id, ret);
cgsleep_ms(20);
errorcount = 0;
}
#ifndef USE_ANT_S1
if (errorcount > 0)
cgsleep_ms(1);
#endif
continue;
}
if (opt_debug) {
applog(LOG_DEBUG, "%s%d: get:",
bitmain->drv->name, bitmain->device_id);
hexdump((uint8_t *)buf, ret);
}
info->read_size += ret;
if (info->read_good == 0)
info->read_sizemin = info->read_sizemax = ret;
else {
if (info->read_sizemin > ret)
info->read_sizemin = ret;
if (info->read_sizemax < ret)
info->read_sizemax = ret;
}
info->read_good++;
if (ret == 18)
info->read_18s++;
memcpy(readbuf+offset, buf, ret);
offset += ret;
}
return NULL;
}
/*
static void bitmain_set_timeout(struct bitmain_info *info)
{
info->timeout = BITMAIN_TIMEOUT_FACTOR / info->frequency;
}
*/
info->thr = thr;
mutex_init(&info->lock);
mutex_init(&info->qlock);
if (unlikely(pthread_cond_init(&info->qcond, NULL)))
quit(1, "Failed to pthread_cond_init bitmain qcond");
cgsem_init(&info->write_sem);
bitmain_init(bitmain);
return true;
}
j++;
}
applog(LOG_ERR, "%s%d: %s()
parse_rxstatus chain(%d) "
"asic_num=%d asic_status=
%08x-%s",
bitmain->drv->name, bitmain-
>device_id,
__func__, i, info-
>chain_asic_num[i],
info->chain_asic_status[i],
info-
>chain_asic_status_t[i]);
}
#else // S2
memcpy(&packethead, data+i, sizeof(struct
bitmain_packet_head));
packethead.length = htole16(packethead.length);
memcpy(info->chain_asic_exist,
rxstatusdata.chain_asic_exist,
BITMAIN_MAX_CHAIN_NUM*32);
memcpy(info->chain_asic_status,
rxstatusdata.chain_asic_status,
BITMAIN_MAX_CHAIN_NUM*32);
for (i = 0; i < rxstatusdata.chain_num; i++) {
info->chain_asic_num[i] =
rxstatusdata.chain_asic_num[i];
memset(info->chain_asic_status_t[i], 0,
320);
j = 0;
if (info->chain_asic_num[i] <= 0)
asicnum = 0;
else {
if (info->chain_asic_num[i] % 32 ==
0)
asicnum = info-
>chain_asic_num[i] / 32;
else
asicnum = info-
>chain_asic_num[i] / 32 + 1;
}
if (asicnum > 0) {
for (m = asicnum-1; m >= 0; m--) {
for (r = 0; r < 32; r++) {
if (r%8 == 0 && r != 0)
{
info-
>chain_asic_status_t[i][j] = ' ';
j++;
}
checkbit = num2bit(r);
if
(rxstatusdata.chain_asic_exist[i*8+m] & checkbit) {
if
(rxstatusdata.chain_asic_status[i*8+m] & checkbit)
info-
>chain_asic_status_t[i][j] = 'o';
else
info-
>chain_asic_status_t[i][j] = 'x';
} else
info-
>chain_asic_status_t[i][j] = '-';
j++;
}
info->chain_asic_status_t[i]
[j] = ' ';
j++;
}
}
applog(LOG_DEBUG, "%s%d: %s() chain(%d)
asic_num=%d "
"asic_exist=%08x%08x%08x
%08x%08x%08x%08x%08x "
"asic_status=%08x%08x%08x
%08x%08x%08x%08x%08x",
bitmain->drv->name,
bitmain->device_id,
__func__, i, info-
>chain_asic_num[i],
info-
>chain_asic_exist[i*8+0],
info-
>chain_asic_exist[i*8+1],
info-
>chain_asic_exist[i*8+2],
info-
>chain_asic_exist[i*8+3],
info-
>chain_asic_exist[i*8+4],
info-
>chain_asic_exist[i*8+5],
info-
>chain_asic_exist[i*8+6],
info-
>chain_asic_exist[i*8+7],
info-
>chain_asic_status[i*8+0],
info-
>chain_asic_status[i*8+1],
info-
>chain_asic_status[i*8+2],
info-
>chain_asic_status[i*8+3],
info-
>chain_asic_status[i*8+4],
info-
>chain_asic_status[i*8+5],
info-
>chain_asic_status[i*8+6],
info-
>chain_asic_status[i*8+7]);
applog(LOG_ERR, "%s%d: %s() chain(%d) "
"asic_num=%d asic_status=%s",
bitmain->drv->name, bitmain-
>device_id,
__func__, i, info-
>chain_asic_num[i],
info-
>chain_asic_status_t[i]);
}
#endif
bitmain_update_temps(bitmain, info,
&rxstatusdata);
statusok = 1;
break;
}
}
if (statusok)
break;
}
}
trycount--;
p.tv_sec = 0;
p.tv_nsec = BITMAIN_RESET_PITCH;
nanosleep(&p, NULL);
}
p.tv_sec = 0;
p.tv_nsec = BITMAIN_RESET_PITCH;
nanosleep(&p, NULL);
cgtime(&info->last_status_time);
if (statusok) {
applog(LOG_ERR, "%s%d: %s() set_txconfig",
bitmain->drv->name, bitmain->device_id, __func__);
#ifdef USE_ANT_S1
if (opt_bitmain_hwerror)
eft = 1;
else
eft = 0;
#ifdef USE_ANT_S1
static void ant_info(struct bitmain_info *info, int baud, int chain_num, int
asic_num, int timeout, int frequency, uint8_t *reg_data)
#else
static void ant_info(struct bitmain_info *info, int baud, int chain_num, int
asic_num)
#endif
{
info->baud = baud;
info->chain_num = chain_num;
info->asic_num = asic_num;
#ifdef USE_ANT_S1
info->timeout = timeout;
info->frequency = frequency;
memcpy(info->reg_data, reg_data, 4);
info->voltage = BITMAIN_DEFAULT_VOLTAGE;
#else
info->timeout = BITMAIN_DEFAULT_TIMEOUT;
info->frequency = BITMAIN_DEFAULT_FREQUENCY;
memset(info->reg_data, BITMAIN_DEFAULT_REG_DATA, 4);
info->voltage[0] = BITMAIN_VOLTAGE0_DEF;
info->voltage[1] = BITMAIN_VOLTAGE1_DEF;
if (opt_bitmain_freq) {
char buf[BUFSIZ+1];
char *colon, *colon2;
uint8_t reg_data[4];
int timeout, freq;
size_t len;
if (opt_bitmain_voltage) {
unsigned char v[2];
if (hex2bin(v, opt_bitmain_voltage, 2)) {
info->voltage[0] = (uint8_t)(v[0]);
info->voltage[1] = (uint8_t)(v[1]);
}
}
#endif
info->fan_pwm = BITMAIN_DEFAULT_FAN_MIN_PWM;
info->temp_max = 0;
/* This is for check the temp/fan every 3~4s */
info->temp_history_count = (4 / (float)((float)info->timeout *
((float)1.67/0x32))) + 1;
if (info->temp_history_count <= 0)
info->temp_history_count = 1;
info->temp_history_index = 0;
info->temp_sum = 0;
}
if (!opt_bitmain_options || !(*opt_bitmain_options)) {
applog(LOG_ERR, "%s: no bitmain-options specified", ANTDRV.dname);
return NULL;
}
baud = BITMAIN_IO_SPEED;
chain_num = BITMAIN_DEFAULT_CHAIN_NUM;
asic_num = BITMAIN_DEFAULT_ASIC_NUM;
#ifdef USE_ANT_S1
timeout = BITMAIN_DEFAULT_TIMEOUT;
frequency = BITMAIN_DEFAULT_FREQUENCY;
#endif
#ifdef USE_ANT_S1
configured = get_options(++option_offset, &baud, &chain_num,
&asic_num, &timeout, &frequency, reg_data);
#else
configured = get_options(++option_offset, &baud, &chain_num, &asic_num);
#endif
#ifdef USE_ANT_S1
if (configured)
ant_info(info, baud, chain_num, asic_num, timeout, frequency,
reg_data);
else
ant_info(info, BITMAIN_IO_SPEED, BITMAIN_DEFAULT_CHAIN_NUM,
BITMAIN_DEFAULT_ASIC_NUM, BITMAIN_DEFAULT_TIMEOUT,
BITMAIN_DEFAULT_FREQUENCY, reg_data);
#else
if (configured)
ant_info(info, baud, chain_num, asic_num);
else
ant_info(info, BITMAIN_IO_SPEED, BITMAIN_DEFAULT_CHAIN_NUM,
BITMAIN_DEFAULT_ASIC_NUM);
#endif
if (!add_cgpu(bitmain))
goto unshin;
update_usb_stats(bitmain);
info->errorcount = 0;
return bitmain;
unshin:
usb_uninit(bitmain);
shin:
free(bitmain->device_data);
bitmain->device_data = NULL;
bitmain = usb_free_cgpu(bitmain);
return NULL;
}
#else // S2 (and only S2)
static void ser_detect()
{
int baud, chain_num = 0, asic_num = 0;
struct cgpu_info *bitmain;
struct bitmain_info *info;
bool configured;
int ret;
if (!opt_bitmain_options || !(*opt_bitmain_options)) {
applog(LOG_ERR, "%s: no bitmain-options specified", ANTDRV.dname);
return;
}
bitmain->drv = &ANTDRV;
bitmain->deven = DEV_ENABLED;
bitmain->threads = 1;
bitmain->device_path = strdup(opt_bitmain_dev);
if (configured)
ant_info(info, baud, chain_num, asic_num);
else
ant_info(info, BITMAIN_IO_SPEED, BITMAIN_DEFAULT_CHAIN_NUM,
BITMAIN_DEFAULT_ASIC_NUM);
if (!add_cgpu(bitmain))
goto cleen;
ret = bitmain_initialize(bitmain);
if (ret && !configured)
goto cleen;
info->errorcount = 0;
dupalloc(bitmain, 10);
return;
cleen:
if (info->device_fd != -1)
close(info->device_fd);
free(bitmain->device_path);
giveup:
free(info);
free(bitmain);
}
#endif
#ifdef USE_ANT_S1
static void ants1_detect(bool __maybe_unused hotplug)
{
usb_detect(&ANTDRV, bitmain_detect_one);
}
#endif
#ifdef USE_ANT_S3
static void ants3_detect(bool __maybe_unused hotplug)
{
usb_detect(&ANTDRV, bitmain_detect_one);
}
#else
#ifdef USE_ANT_S2
static bool first_ant = true;
first_ant = false;
ser_detect();
}
#endif
#endif
pthread_join(info->read_thr, NULL);
bitmain_running_reset(info);
info->no_matching_work = 0;
cgsem_destroy(&info->write_sem);
}
#ifdef USE_ANT_S1
/*
* Overheat just means delay the next work
* since the temperature reply is only found with a work reply,
* we can only sleep and hope it will cool down
* TODO: of course it may be possible to read the temperature
* without sending work ...
*/
if (info->overheat == true) {
if (info->overheat_sleep_ms == 0)
info->overheat_sleep_ms = BITMAIN_OVERHEAT_SLEEP_MS_DEF;
/*
* If we slept and we are still here, and the temp didn't drop,
* increment the sleep time to find a sleep time that causes a
* temperature drop
*/
if (info->overheat_slept) {
if (info->overheat_temp > info->temp_hi)
info->overheat_temp = info->temp_hi;
else {
if (info->overheat_sleep_ms <
BITMAIN_OVERHEAT_SLEEP_MS_MAX)
info->overheat_sleep_ms +=
BITMAIN_OVERHEAT_SLEEP_MS_STEP;
}
}
}
#endif
if (info->fifo_space > 0) {
work = get_queued(bitmain);
if (!work) {
if (info->fifo_space < BITMAIN_MAX_WORK_NUM)
neednum = info->fifo_space;
else
neednum = BITMAIN_MAX_WORK_NUM;
queuednum = info->queued;
roll_limit = work->drv_rolllimit;
info->fill_rolltot += roll_limit;
if (info->fill_roll == 0)
info->fill_rollmin = info->fill_rollmax = roll_limit;
else {
if (info->fill_rollmin > roll_limit)
info->fill_rollmin = roll_limit;
if (info->fill_rollmax < roll_limit)
info->fill_rollmax = roll_limit;
}
info->fill_roll++;
roll = 0;
}
info->fill_totalneeded += neednum;
info->fill_need[neednum]++;
queuednum = info->queued;
applog(LOG_DEBUG, "%s%d: Work task queued(%d) fifo space(%d)
needsend(%d)",
bitmain->drv->name, bitmain->device_id,
queuednum, info->fifo_space, neednum);
info->fill_want += (neednum - queuednum);
while (queuednum < neednum && roll <= roll_limit) {
applog(LOG_DEBUG, "%s%d: get work queued number:%d"
" neednum:%d",
bitmain->drv->name,
bitmain->device_id,
queuednum, neednum);
witem = k_unlink_tail(info->work_list);
if (DATAW(witem)->work) {
// Was it rolled?
if (DATAW(witem)->work->devflag)
free_work(DATAW(witem)->work);
else
work_completed(bitmain, DATAW(witem)->work);
}
DATAW(witem)->work = usework;
DATAW(witem)->wid = ++info->last_wid;
info->queued++;
k_add_head(info->work_ready, witem);
queuednum++;
roll++;
}
if (queuednum < BITMAIN_MAX_DEAL_QUEUE_NUM) {
if (queuednum < neednum) {
info->fill_toosmall++;
info->fill_less += (neednum - queuednum);
applog(LOG_DEBUG, "%s%d: Not enough work to send, queue
num=%d",
bitmain->drv->name, bitmain->device_id,
queuednum);
goto out_unlock;
}
}
info->fill_sends++;
sendnum = queuednum < neednum ? queuednum : neednum;
info->fill_totalsend += sendnum;
info->fill_send[sendnum]++;
info->fill_sendless[neednum - sendnum]++;
sendlen = bitmain_set_txtask(info, sendbuf, &(info->last_work_block),
&sentcount);
info->queued -= sendnum;
info->send_full_space += sendnum;
if (info->queued < 0)
info->queued = 0;
out_unlock:
cgtime(&now);
timediff = now.tv_sec - info->last_status_time.tv_sec;
if (timediff < 0)
timediff = -timediff;
if (timediff > BITMAIN_SEND_STATUS_TIME) {
info->fill_sendstatus++;
applog(LOG_DEBUG, "%s%d: Send RX Status Token fifo_space(%d)
timediff(%d)",
bitmain->drv->name, bitmain->device_id,
info->fifo_space, timediff);
copy_time(&(info->last_status_time), &now);
mutex_lock(&info->qlock);
hash_count = 0xffffffffull * (uint64_t)info->nonces;
info->results += info->nonces;
if (info->results > chain_num)
info->results = chain_num;
if (!info->reset)
info->results--;
info->nonces = 0;
mutex_unlock(&info->qlock);
needptr = needbuf;
for (i = 0; i <= BITMAIN_MAX_WORK_NUM; i++) {
len = sizeof(needbuf) - (needptr - needbuf);
if (len > 1) {
snprintf(needptr, len, "%s%"PRIu64,
i ? "/" : "", info->need_nowork[i]);
needptr += strlen(needptr);
}
}
len = sizeof(needbuf) - (needptr - needbuf);
if (len > 1)
snprintf(needptr, len, " %"PRIu64, info->need_over);
root = api_add_string(root, "need_nowork", needbuf, true);
avg = info->fill_roll ? (float)(info->fill_rolltot) / (float)(info-
>fill_roll) : 0;
snprintf(rollbuf, sizeof(rollbuf), "%"PRIu64"/%d/%d/%.2fav",
info->fill_roll, info->fill_rollmin, info->fill_rollmax, avg);
root = api_add_string(root, "roll", rollbuf, true);
i = BITMAIN_SEND_STATUS_TIME;
root = api_add_int(root, "send_status_time", &i, true);
root = api_add_timeval(root, "last_status_time", &(info->last_status_time),
true);
root = api_add_uint64(root, "fill_sendstatus", &(info->fill_sendstatus),
true);
root = api_add_uint64(root, "read_good", &(info->read_good), true);
avg = info->read_good ? (float)(info->read_size) / (float)(info->read_good) :
0;
snprintf(fillbuf, sizeof(fillbuf), "%"PRIu64"/%d/%d/%.2fav",
info->read_size, info->read_sizemin, info->read_sizemax, avg);
root = api_add_string(root, "read_size", fillbuf, true);
root = api_add_uint64(root, "read_18s", &(info->read_18s), true);
root = api_add_uint64(root, "read_bad", &(info->readbuf_over), true);
root = api_add_uint64(root, "readbuf_over", &(info->readbuf_over), true);
#ifdef USE_ANT_S2
root = api_add_bool(root, "opt_bitmain_beeper", &opt_bitmain_beeper, false);
root = api_add_bool(root, "opt_bitmain_tempoverctrl",
&opt_bitmain_tempoverctrl, false);
#endif
root = api_add_int(root, "opt_bitmain_temp", &opt_bitmain_temp, false);
root = api_add_int(root, "opt_bitmain_workdelay", &opt_bitmain_workdelay,
false);
root = api_add_int(root, "opt_bitmain_overheat", &opt_bitmain_overheat,
false);
root = api_add_int(root, "opt_bitmain_fan_min", &opt_bitmain_fan_min, false);
root = api_add_int(root, "opt_bitmain_fan_max", &opt_bitmain_fan_max, false);
root = api_add_bool(root, "opt_bitmain_auto", &opt_bitmain_auto, false);
return root;
}
if (val1 < 0 || val1 > 100 || val2 < 0 || val2 > 100 || val2 < val1)
return "Invalid value passed to bitmain-fan";
return NULL;
}
#endif // LINUX
#ifdef USE_ANT_S1
struct device_drv ants1_drv = {
.drv_id = DRIVER_ants1,
.dname = "BitmainAntS1",
.name = "ANT",
.drv_detect = ants1_detect,
#ifdef LINUX
.thread_prepare = bitmain_prepare,
.hash_work = hash_queued_work,
.queue_full = bitmain_fill,
.scanwork = bitmain_scanhash,
.flush_work = bitmain_flush_work,
.get_api_stats = bitmain_api_stats,
.get_statline_before = get_bitmain_statline_before,
.reinit_device = bitmain_init,
.thread_shutdown = bitmain_shutdown,
#endif
};
#endif
#ifdef USE_ANT_S2
#ifdef USE_ANT_S3
struct device_drv ants3_drv = {
.drv_id = DRIVER_ants3,
.dname = "BitmainAntS3",
.name = "AS3",
.drv_detect = ants3_detect,
#else
struct device_drv ants2_drv = {
.drv_id = DRIVER_ants2,
.dname = "BitmainAntS2",
.name = "AS2",
.drv_detect = ants2_detect,
#endif
#ifdef LINUX
.thread_prepare = bitmain_prepare,
.hash_work = hash_queued_work,
.queue_full = bitmain_fill,
.scanwork = bitmain_scanhash,
.flush_work = bitmain_flush_work,
.get_api_stats = bitmain_api_stats,
.get_statline_before = get_bitmain_statline_before,
.reinit_device = bitmain_init,
.thread_shutdown = bitmain_shutdown,
#endif
};
#endif