You are on page 1of 95

#include "config.

h"

#include "math.h"
#include "miner.h"

#include "bf16-communication.h"
#include "bf16-ctrldevice.h"
#include "bf16-mspcontrol.h"
#include "bf16-spidevice.h"
#include "bf16-uartdevice.h"
#include "driver-bitfury16.h"

#ifdef FILELOG
#define LOGFILE "/var/log/cgminer.log"
#endif

#define DISABLE_SEND_CMD_ERROR

#define POWER_WAIT_INTERVAL 100000


#define RENONCE_SEND 5
#define RENONCE_STAGE2_LIMIT 80
#define RENONCE_STAGE3_LIMIT 60
#define RENONCE_QUEUE_LEN 100

#define RENONCE_COUNT 29

/* chip nonce queue len */


#define NONCE_CHIP_QUEUE_LEN 7
#define RENONCE_CHIP_QUEUE_LEN 40

#define WORK_TIMEOUT 2.0

/* statistics intervals */
#define AVG_TIME_DELTA 5.0
#define AVG_TIME_INTERVAL 5.0

/* power chain alarm interval */


#define ICHAIN_ALARM_INTERVAL 60
#define U_LOSS 0.2

/* power chain reenable timeout */


#define CHAIN_REENABLE_INTERVAL 10
#define CHAIN_WORK_INTERVAL 1200

/* disable chip if no good nonces received during CHIP_FAILING_INTERVAL */


#define RENONCE_CHIP_FAILING_INTERVAL 15.0
#define CHIP_FAILING_INTERVAL 30.0
#define CHIP_RECOVERY_INTERVAL 5.0

/* chip is considered to be failed after CHIP_ERROR_FAIL_LIMIT recovery attempts */


#define CHIP_ERROR_FAIL_LIMIT 10
/* this value should be less than CHIP_ERROR_FAIL_LIMIT */
#define RENONCE_CHIP_ERROR_FAIL_LIMIT 8
#define CHIP_ERROR_LIMIT 5

#define CHIP_TASK_STATUS_INTERVAL 7000


#define CHIP_TASK_SWITCH_INTERVAL 5000000

#define CHIP_RESTART_LIMIT 120


/* alarm intervals */
#define LED_GREEN_INTERVAL 1000000
#define LED_RED_INTERVAL 1000000
#define LED_RED_NET_INTERVAL 500000
#define BUZZER_INTERVAL 1000000

/* threads delay */
#define CHIPWORKER_DELAY 1000000
#define NONCEWORKER_DELAY 30000
#define RENONCEWORKER_DELAY 30000
#define HWMONITOR_DELAY 1000000
#define STATISTICS_DELAY 400000
#define ALARM_DELAY 500000

/* hold 3 works for each chip */


#define WORK_QUEUE_LEN 3 * CHIPS_NUM

/* set clock to all chips and exit */


bool opt_bf16_set_clock = false;

/* enable board mining statistics output */


bool opt_bf16_stats_enabled = false;

/* disable automatic power management */


bool opt_bf16_power_management_disabled = false;

/* renonce configuration */
int opt_bf16_renonce = RENONCE_ONE_CHIP;

/* chip clock value */


char* opt_bf16_clock = NULL;
uint8_t bf16_chip_clock = 0x32;

/* renonce chip clock value */


char* opt_bf16_renonce_clock = NULL;
uint8_t bf16_renonce_chip_clock = 0x2d;

/* fan speed */
int opt_bf16_fan_speed = -1;

/* target temp */
int opt_bf16_target_temp = -1;

/* alarm temp */
int opt_bf16_alarm_temp = -1;

/* test chip communication */


char* opt_bf16_test_chip = NULL;

/* number of bits to fixate */


static uint32_t mask_bits = 10;

/* default chip mask */


static uint32_t mask = 0x00000000;

/* initial pid state */


static bf_pid_t pid = {
.i_state = 0,
.i_max = 300,
.i_min = -10,
};

#ifdef MINER_X5
bool opt_bf16_manual_pid_enabled = false;
bool manual_pid_enabled = false;

static bf_bcm250_map_t bcm250_map[CHIPBOARD_NUM][BCM250_NUM] = {


{
{
.channel_path = { BF250_LOCAL, BF250_NONE },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
},
{
.channel_path = { BF250_CHAN1, BF250_LOCAL },
.first_good_chip = 7,
.last_good_chip = BF16_NUM,
.chips_num = 4
},
{
.channel_path = { BF250_CHAN2, BF250_LOCAL },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
}
},
{
{
.channel_path = { BF250_LOCAL, BF250_NONE },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
},
{
.channel_path = { BF250_CHAN1, BF250_LOCAL },
.first_good_chip = 7,
.last_good_chip = BF16_NUM,
.chips_num = 4
},
{
.channel_path = { BF250_CHAN2, BF250_LOCAL },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
}
}
};
#endif

#ifdef MINER_X6
bool opt_bf16_manual_pid_disabled = false;
bool manual_pid_enabled = false;

static bf_bcm250_map_t bcm250_map[CHIPBOARD_NUM][BCM250_NUM] = {


{
{
.channel_path = { BF250_LOCAL, BF250_NONE, BF250_NONE,
BF250_NONE },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
},
{
.channel_path = { BF250_CHAN1, BF250_LOCAL, BF250_NONE,
BF250_NONE },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
},
{
.channel_path = { BF250_CHAN2, BF250_LOCAL, BF250_NONE,
BF250_NONE },
.first_good_chip = 0,
.last_good_chip = 4,
.chips_num = 4
},
{
.channel_path = { BF250_CHAN2, BF250_CHAN2, BF250_LOCAL,
BF250_NONE },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
},
{
.channel_path = { BF250_CHAN2, BF250_CHAN2, BF250_CHAN1,
BF250_LOCAL },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
},
{
.channel_path = { BF250_CHAN2, BF250_CHAN2, BF250_CHAN2,
BF250_LOCAL },
.first_good_chip = 0,
.last_good_chip = 4,
.chips_num = 4
}
},
{
{
.channel_path = { BF250_LOCAL, BF250_NONE, BF250_NONE,
BF250_NONE },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
},
{
.channel_path = { BF250_CHAN1, BF250_LOCAL, BF250_NONE,
BF250_NONE },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
},
{
.channel_path = { BF250_CHAN2, BF250_LOCAL, BF250_NONE,
BF250_NONE },
.first_good_chip = 0,
.last_good_chip = 4,
.chips_num = 4
},
{
.channel_path = { BF250_CHAN2, BF250_CHAN2, BF250_LOCAL,
BF250_NONE },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
},
{
.channel_path = { BF250_CHAN2, BF250_CHAN2, BF250_CHAN1,
BF250_LOCAL },
.first_good_chip = 0,
.last_good_chip = BF16_NUM,
.chips_num = BF16_NUM
},
{
.channel_path = { BF250_CHAN2, BF250_CHAN2, BF250_CHAN2,
BF250_LOCAL },
.first_good_chip = 0,
.last_good_chip = 4,
.chips_num = 4
}
}
};
#endif

/* each array element contains chip address assosiated to corresponting chipboard *


* e.g. first array element - renonce chip address for the first chipboard and so *
* on */
static bf_chip_address_t renonce_chip_address[CHIPBOARD_NUM] = {
{
.board_id = 0,
.bcm250_id = 0,
.chip_id = 0
},
{
.board_id = 1,
.bcm250_id = 0,
.chip_id = 0
}
};

#ifdef FILELOG
static int filelog(struct bitfury16_info *info, const char* format, ...)
{
char fmt[1024];
char datetime[64];
struct timeval tv = {0, 0};
struct tm *tm;

if (info->logfile == NULL)
return -1;

gettimeofday(&tv, NULL);
const time_t tmp_time = tv.tv_sec;
int ms = (int)(tv.tv_usec / 1000);
tm = localtime(&tmp_time);

snprintf(datetime, sizeof(datetime), " [%d-%02d-%02d %02d:%02d:%02d.%03d] ",


tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_hour,
tm->tm_min,
tm->tm_sec, ms);

memset(fmt, 0, sizeof(fmt));
sprintf(fmt, "%s%s\n", datetime, format);

va_list args;
va_start(args, format);

mutex_lock(&info->logfile_mutex);
vfprintf(info->logfile, fmt, args);
fflush(info->logfile);
mutex_unlock(&info->logfile_mutex);

va_end(args);

return 0;
}
#endif

static double timediff(struct timeval time1, struct timeval time2)


{
double time1_val = 1000000 * time1.tv_sec + time1.tv_usec;
double time2_val = 1000000 * time2.tv_sec + time2.tv_usec;

return (double)(time2_val - time1_val) / 1000000.0;


}

static uint32_t timediff_us(struct timeval time1, struct timeval time2)


{
uint32_t time1_val = 1000000 * time1.tv_sec + time1.tv_usec;
uint32_t time2_val = 1000000 * time2.tv_sec + time2.tv_usec;

return (time2_val - time1_val);


}

static void get_average(float* average, float delta, float time_diff, float


interval)
{
float ftotal, fprop;

fprop = 1.0 - 1 / (exp((float)time_diff/(float)interval));


ftotal = 1.0 + fprop;
*average += (delta / time_diff * fprop);
*average /= ftotal;
}

static uint8_t renonce_chip(bf_chip_address_t chip_address)


{
uint8_t board_id = chip_address.board_id;
if ((renonce_chip_address[board_id].bcm250_id == chip_address.bcm250_id) &&
(renonce_chip_address[board_id].chip_id == chip_address.chip_id))
return 1;

return 0;
}

static void get_next_chip_address(struct bitfury16_info *info, bf_chip_address_t*


chip_address)
{
uint8_t board_id = chip_address->board_id;
uint8_t bcm250_id = chip_address->bcm250_id;
uint8_t chip_id = chip_address->chip_id;

uint8_t last_good_chip = info-


>chipboard[board_id].bcm250[bcm250_id].last_good_chip - 1;
if (last_good_chip == chip_id) {
#ifdef MINER_X5
bcm250_id = (bcm250_id + 1) % BCM250_NUM;
chip_id = info->chipboard[board_id].bcm250[bcm250_id].first_good_chip;
#endif

#ifdef MINER_X6
if (opt_bf16_power_management_disabled == false) {
bcm250_id = (bcm250_id + 1) % BCM250_NUM;

/* do not set bcm250_id to disabled chain */


/* second power chain disabled */
if ((info->chipboard[board_id].p_chain2_enabled == 0) &&
(info->chipboard[board_id].power2_disabled == true) &&
(bcm250_id >= BCM250_NUM / 2) && (bcm250_id < BCM250_NUM))
{
bcm250_id = 0;
}

chip_id = info-
>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
} else {
chip_id = info-
>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
}
#endif
} else
chip_id++;

chip_address->bcm250_id = bcm250_id;
chip_address->chip_id = chip_id;
}

static int8_t change_renonce_chip_address(struct cgpu_info *bitfury,


bf_chip_address_t chip_address)
{
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);

uint8_t board_id = chip_address.board_id;


uint8_t bcm250_id = chip_address.bcm250_id;
uint8_t chip_id = chip_address.chip_id;
bf_chip_address_t new_chip_address = { board_id, bcm250_id, chip_id };

bool found = false;


uint8_t chip_count = 0;
while (true) {
get_next_chip_address(info, &new_chip_address);
chip_count++;

uint8_t new_board_id = new_chip_address.board_id;


uint8_t new_bcm250_id = new_chip_address.bcm250_id;
uint8_t new_chip_id = new_chip_address.chip_id;

/* enabled chip found */


if (info-
>chipboard[new_board_id].bcm250[new_bcm250_id].chips[new_chip_id].status !=
DISABLED) {
found = true;
break;
}

/* we have run full loop chipboard */


#ifdef MINER_X5
if (chip_count == info->chipboard[board_id].chips_num)
break;
#endif

#ifdef MINER_X6
if (opt_bf16_power_management_disabled == false) {
if ((info->chipboard[board_id].p_chain2_enabled == 0) &&
(info->chipboard[board_id].power2_disabled == true)) {
if (chip_count == info->chipboard[board_id].chips_num / 2)
break;
} else {
if (chip_count == info->chipboard[board_id].chips_num)
break;
}
} else {
if (chip_count == info->chipboard[board_id].chips_num)
break;
}
#endif
}

if ((found == true) &&


(memcmp(&new_chip_address, &renonce_chip_address[board_id],
sizeof(bf_chip_address_t)) != 0)) {
board_id = new_chip_address.board_id;
bcm250_id = new_chip_address.bcm250_id;
chip_id = new_chip_address.chip_id;

renonce_chip_address[board_id].bcm250_id = bcm250_id;
renonce_chip_address[board_id].chip_id = chip_id;

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status
= UNINITIALIZED;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time = time(NULL);
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_time, NULL);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count = 0;

applog(LOG_NOTICE, "%s: changed renonce chip address to: [%d:%d:%2d]",


bitfury->drv->name,
board_id, bcm250_id, chip_id);

#ifdef FILELOG
filelog(info, "%s: changed renonce chip address to: [%d:%d:%2d]",
bitfury->drv->name,
board_id, bcm250_id, chip_id);
#endif

return 0;
} else {
info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status =
DISABLED;

applog(LOG_NOTICE, "%s: failed to find working renonce chip.


disabling...",
bitfury->drv->name);

#ifdef FILELOG
filelog(info, "%s: failed to find working renonce chip. disabling...",
bitfury->drv->name);
#endif

return -1;
}
}

static void increase_good_nonces(struct bitfury16_info *info, bf_chip_address_t


chip_address)
{
uint8_t board_id = chip_address.board_id;
uint8_t bcm250_id = chip_address.bcm250_id;
uint8_t chip_id = chip_address.chip_id;

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_good_dx++;
info->chipboard[board_id].bcm250[bcm250_id].nonces_good_dx++;
info->chipboard[board_id].nonces_good_dx++;
info->nonces_good_dx++;
}

static void increase_bad_nonces(struct bitfury16_info *info, bf_chip_address_t


chip_address)
{
uint8_t board_id = chip_address.board_id;
uint8_t bcm250_id = chip_address.bcm250_id;
uint8_t chip_id = chip_address.chip_id;

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_bad_dx++;
info->chipboard[board_id].bcm250[bcm250_id].nonces_bad_dx++;
info->chipboard[board_id].nonces_bad_dx++;
info->nonces_bad_dx++;
}
static void increase_re_nonces(struct bitfury16_info *info, bf_chip_address_t
chip_address)
{
uint8_t board_id = chip_address.board_id;
uint8_t bcm250_id = chip_address.bcm250_id;
uint8_t chip_id = chip_address.chip_id;

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_re_dx++;
info->chipboard[board_id].bcm250[bcm250_id].nonces_re_dx++;
info->chipboard[board_id].nonces_re_dx++;
info->nonces_re_dx++;
}

static void increase_re_good_nonces(struct bitfury16_info *info, bf_chip_address_t


chip_address)
{
uint8_t board_id = chip_address.board_id;
uint8_t bcm250_id = chip_address.bcm250_id;
uint8_t chip_id = chip_address.chip_id;

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_re_good_dx+
+;

if (renonce_chip(chip_address) == 0) {
info->chipboard[board_id].bcm250[bcm250_id].nonces_re_good_dx++;
info->chipboard[board_id].nonces_re_good_dx++;
info->nonces_re_good_dx++;
}
}

static void increase_re_bad_nonces(struct bitfury16_info *info, bf_chip_address_t


chip_address)
{
uint8_t board_id = chip_address.board_id;
uint8_t bcm250_id = chip_address.bcm250_id;
uint8_t chip_id = chip_address.chip_id;

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_re_bad_dx+
+;

if (renonce_chip(chip_address) == 0) {
info->chipboard[board_id].bcm250[bcm250_id].nonces_re_bad_dx++;
info->chipboard[board_id].nonces_re_bad_dx++;
info->nonces_re_bad_dx++;
}
}

static void increase_total_nonces(struct bitfury16_info *info, bf_chip_address_t


chip_address)
{
uint8_t board_id = chip_address.board_id;
uint8_t bcm250_id = chip_address.bcm250_id;
uint8_t chip_id = chip_address.chip_id;

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_dx++;

if ((renonce_chip(chip_address) == 0) ||
(opt_bf16_renonce == RENONCE_DISABLED)) {
info->chipboard[board_id].bcm250[bcm250_id].nonces_dx++;
info->chipboard[board_id].nonces_dx++;
info->nonces_dx++;
}
}

static void increase_task_switch(struct bitfury16_info *info, bf_chip_address_t


chip_address)
{
uint8_t board_id = chip_address.board_id;
uint8_t bcm250_id = chip_address.bcm250_id;
uint8_t chip_id = chip_address.chip_id;

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].task_switch_dx++;
info->chipboard[board_id].bcm250[bcm250_id].task_switch_dx++;
info->chipboard[board_id].task_switch_dx++;
info->task_switch_dx++;
}

static void increase_errors(struct bitfury16_info *info, bf_chip_address_t


chip_address)
{
uint8_t board_id = chip_address.board_id;
uint8_t bcm250_id = chip_address.bcm250_id;
uint8_t chip_id = chip_address.chip_id;

/* update timing interval */


time_t curr_time = time(NULL);
if (curr_time - info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_error_time <= 1)
info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate+
+;
else
info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate =
0;

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_error_time =
curr_time;

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].errors++;

if ((renonce_chip(chip_address) == 0) ||
(opt_bf16_renonce == RENONCE_DISABLED))
info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status =
UNINITIALIZED;

/* mark chip as FAILING if error rate too high*/


if (info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate >=
CHIP_ERROR_LIMIT) {
#ifdef FILELOG
filelog(info, "BF16: chip [%d:%d:%2d] error rate too high: [%d], "
"marked as failing, recovery_count: [%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count);
#endif

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status =
FAILING;
info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate =
0;
}
}

static uint8_t* init_channel_path(uint8_t board_id, uint8_t btc250_num, uint8_t*


channel_depth, uint8_t channel_length)
{
uint8_t i, j;
uint8_t* channel_path = cgcalloc(channel_length, sizeof(uint8_t));

for (i = 0, j = 0; i < CHANNEL_DEPTH; i++) {


if (bcm250_map[board_id][btc250_num].channel_path[i] != BF250_NONE)
(*channel_depth)++;

int8_t shift = 8*(j + 1) - 3*(i + 1);


if (shift < 0) {
channel_path[j] |= bcm250_map[board_id]
[btc250_num].channel_path[i] >> abs(shift);
channel_path[j + 1] |= bcm250_map[board_id]
[btc250_num].channel_path[i] << (8 - abs(shift));
j++;
} else
channel_path[j] |= bcm250_map[board_id]
[btc250_num].channel_path[i] << shift;
}

return channel_path;
}

static int8_t parse_chip_address(struct cgpu_info *bitfury, char* address,


bf_chip_address_t* chip_address)
{
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);

int8_t board_id = 0;
int8_t bcm250_id = 0;
int8_t chip_id = 0;

char buff[16];

if (address == NULL)
return -1;

/* board_id */
char* start = strchr(address, '[');
char* end = strchr(address, ':');
if ((start == NULL) || (end == NULL))
return -1;
uint8_t len = end - start;

memset(buff, 0, sizeof(buff));
cg_memcpy(buff, start + 1, len);
board_id = atoi(buff);

/* bcm250_id */
start = end;
end = strchr(start + 1, ':');
if (end == NULL)
return -1;
len = end - start;

memset(buff, 0, sizeof(buff));
cg_memcpy(buff, start + 1, len);
bcm250_id = atoi(buff);

/* chip_id */
start = end;
end = strchr(start + 1, ']');
if (end == NULL)
return -1;
len = end - start;

memset(buff, 0, sizeof(buff));
cg_memcpy(buff, start + 1, len);
chip_id = atoi(buff);

if ((board_id < 0) || (board_id >= CHIPBOARD_NUM)) {


applog(LOG_ERR, "%s: invalid board_id %d: [0 - %d] specified",
bitfury->drv->name,
board_id, CHIPBOARD_NUM);
return -1;
}

if ((bcm250_id < 0) || (bcm250_id >= BCM250_NUM)) {


applog(LOG_ERR, "%s: invalid bcm250_id %d: [0 - %d] specified",
bitfury->drv->name,
bcm250_id, BCM250_NUM);
return -1;
}

uint8_t first_good_chip = info-


>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
uint8_t last_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].last_good_chip;

if ((chip_id >= first_good_chip) && (chip_id < last_good_chip)) {


chip_address->board_id = board_id;
chip_address->bcm250_id = bcm250_id;
chip_address->chip_id = chip_id;
} else {
applog(LOG_ERR, "%s: invalid chip_id %d: [%d - %d] specified",
bitfury->drv->name,
chip_id, first_good_chip, last_good_chip);
return -1;
}

applog(LOG_NOTICE, "%s: parsed chip address: [%d:%d:%2d]",


bitfury->drv->name,
chip_address->board_id,
chip_address->bcm250_id,
chip_address->chip_id);

return 0;
}
static void update_bcm250_map(struct cgpu_info *bitfury, uint8_t board_id)
{
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);

#ifdef MINER_X5
info->chipboard[board_id].board_type = CHIPBOARD_X5;

switch (info->chipboard[board_id].board_ver) {
/* 23 chip board version */
case 5:
info->chipboard[board_id].board_rev = CHIPBOARD_REV2;

bcm250_map[board_id][0].last_good_chip = BF16_NUM - 2;
bcm250_map[board_id][0].chips_num = BF16_NUM - 2;

bcm250_map[board_id][1].first_good_chip = 6;
bcm250_map[board_id][1].chips_num = 5;

bcm250_map[board_id][2].last_good_chip = BF16_NUM - 2;
bcm250_map[board_id][2].chips_num = BF16_NUM - 2;
break;

/* 24 chip board version */


case 7:
info->chipboard[board_id].board_rev = CHIPBOARD_REV2;

bcm250_map[board_id][0].last_good_chip = BF16_NUM - 2;
bcm250_map[board_id][0].chips_num = BF16_NUM - 2;

bcm250_map[board_id][1].first_good_chip = 6;
bcm250_map[board_id][1].chips_num = 5;

bcm250_map[board_id][2].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][2].chips_num = BF16_NUM - 1;
break;

/* 25 chip board version */


case 9:
info->chipboard[board_id].board_rev = CHIPBOARD_REV2;

bcm250_map[board_id][0].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][0].chips_num = BF16_NUM - 1;

bcm250_map[board_id][1].first_good_chip = 6;
bcm250_map[board_id][1].chips_num = 5;

bcm250_map[board_id][2].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][2].chips_num = BF16_NUM - 1;
break;

/* 26 chip board version */


case 11:
info->chipboard[board_id].board_rev = CHIPBOARD_REV2;

bcm250_map[board_id][0].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][0].chips_num = BF16_NUM - 1;
bcm250_map[board_id][1].first_good_chip = 6;
bcm250_map[board_id][1].chips_num = 5;
break;

/* 27 chip board version */


case 13:
info->chipboard[board_id].board_rev = CHIPBOARD_REV2;

bcm250_map[board_id][1].first_good_chip = 6;
bcm250_map[board_id][1].chips_num = 5;
break;

/* 26 chip board version - default */


case 1:
case 2:
info->chipboard[board_id].board_rev = CHIPBOARD_REV1;
default:
break;
}
#endif

#ifdef MINER_X6
info->chipboard[board_id].board_type = CHIPBOARD_X6;

switch (info->chipboard[board_id].board_ver) {
/* 46 chip board version */
case 4:
info->chipboard[board_id].board_rev = CHIPBOARD_REV2;

bcm250_map[board_id][0].last_good_chip = BF16_NUM - 2;
bcm250_map[board_id][0].chips_num = BF16_NUM - 2;

bcm250_map[board_id][1].first_good_chip = 1;
bcm250_map[board_id][1].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][1].chips_num = BF16_NUM - 2;

bcm250_map[board_id][2].last_good_chip = 5;
bcm250_map[board_id][2].chips_num = 5;

bcm250_map[board_id][3].last_good_chip = BF16_NUM - 2;
bcm250_map[board_id][3].chips_num = BF16_NUM - 2;

bcm250_map[board_id][4].first_good_chip = 1;
bcm250_map[board_id][4].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][4].chips_num = BF16_NUM - 1;

bcm250_map[board_id][5].last_good_chip = 5;
bcm250_map[board_id][5].chips_num = 5;
break;

/* 48 chip board version */


case 6:
info->chipboard[board_id].board_rev = CHIPBOARD_REV2;

bcm250_map[board_id][0].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][0].chips_num = BF16_NUM - 1;

bcm250_map[board_id][1].first_good_chip = 1;
bcm250_map[board_id][1].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][1].chips_num = BF16_NUM - 2;

bcm250_map[board_id][2].last_good_chip = 5;
bcm250_map[board_id][2].chips_num = 5;

bcm250_map[board_id][3].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][3].chips_num = BF16_NUM - 1;

bcm250_map[board_id][4].first_good_chip = 1;
bcm250_map[board_id][4].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][4].chips_num = BF16_NUM - 1;

bcm250_map[board_id][5].last_good_chip = 5;
bcm250_map[board_id][5].chips_num = 5;
break;

/* 50 chip board version */


case 8:
info->chipboard[board_id].board_rev = CHIPBOARD_REV2;

bcm250_map[board_id][0].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][0].chips_num = BF16_NUM - 1;

bcm250_map[board_id][1].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][1].chips_num = BF16_NUM - 1;

bcm250_map[board_id][2].last_good_chip = 5;
bcm250_map[board_id][2].chips_num = 5;

bcm250_map[board_id][3].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][3].chips_num = BF16_NUM - 1;

bcm250_map[board_id][4].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][4].chips_num = BF16_NUM - 1;

bcm250_map[board_id][5].last_good_chip = 5;
bcm250_map[board_id][5].chips_num = 5;
break;

/* 52 chip board version */


case 10:
info->chipboard[board_id].board_rev = CHIPBOARD_REV2;

bcm250_map[board_id][1].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][1].chips_num = BF16_NUM - 1;

bcm250_map[board_id][2].last_good_chip = 5;
bcm250_map[board_id][2].chips_num = 5;

bcm250_map[board_id][4].last_good_chip = BF16_NUM - 1;
bcm250_map[board_id][4].chips_num = BF16_NUM - 1;

bcm250_map[board_id][5].last_good_chip = 5;
bcm250_map[board_id][5].chips_num = 5;
break;

/* 54 chip board version */


case 12:
info->chipboard[board_id].board_rev = CHIPBOARD_REV2;
bcm250_map[board_id][2].last_good_chip = 5;
bcm250_map[board_id][2].chips_num = 5;

bcm250_map[board_id][5].last_good_chip = 5;
bcm250_map[board_id][5].chips_num = 5;
break;

/* 46 chip board version */


case 14:;
info->chipboard[board_id].board_rev = CHIPBOARD_REV3;

uint8_t bcm250_channel_path[3][CHANNEL_DEPTH] = {
{ BF250_CHAN1, BF250_CHAN1, BF250_LOCAL, BF250_NONE },
{ BF250_CHAN1, BF250_CHAN1, BF250_CHAN1, BF250_LOCAL },
{ BF250_CHAN1, BF250_CHAN1, BF250_CHAN2, BF250_LOCAL },
};

bcm250_map[board_id][0].first_good_chip = 0;
bcm250_map[board_id][0].last_good_chip = 1;
bcm250_map[board_id][0].chips_num = 1;

bcm250_map[board_id][2].first_good_chip = 0;
bcm250_map[board_id][2].last_good_chip = BF16_NUM;
bcm250_map[board_id][2].chips_num = BF16_NUM;

bcm250_map[board_id][3].first_good_chip = 0;
bcm250_map[board_id][3].last_good_chip = 1;
bcm250_map[board_id][3].chips_num = 1;
cg_memcpy(bcm250_map[board_id][3].channel_path,
bcm250_channel_path[0], sizeof(bcm250_map[board_id][3].channel_path));

cg_memcpy(bcm250_map[board_id][4].channel_path,
bcm250_channel_path[1], sizeof(bcm250_map[board_id][4].channel_path));

bcm250_map[board_id][5].first_good_chip = 0;
bcm250_map[board_id][5].last_good_chip = BF16_NUM;
bcm250_map[board_id][5].chips_num = BF16_NUM;
cg_memcpy(bcm250_map[board_id][5].channel_path,
bcm250_channel_path[2], sizeof(bcm250_map[board_id][5].channel_path));
break;

/* 52 chip board version - default */


case 3:
info->chipboard[board_id].board_rev = CHIPBOARD_REV1;
default:
break;
}
#endif
}

static void reinit_x5(struct bitfury16_info *info, bool chip_reinit)


{
uint8_t board_id, bcm250_id, chip_id;

/* reinit board chips */


for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
for (bcm250_id = 0; bcm250_id < BCM250_NUM; bcm250_id++) {
uint8_t first_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
uint8_t last_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].last_good_chip;

for (chip_id = first_good_chip; chip_id < last_good_chip;


chip_id++) {
if (chip_reinit == true) {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status =
UNINITIALIZED;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time = time(NULL);
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_error_time = time(NULL);
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_time, NULL);
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].switch_time, NULL);
} else {
if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count <
CHIP_ERROR_FAIL_LIMIT)
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status = UNINITIALIZED;
}

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time = time(NULL);
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_time, NULL);
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].switch_time, NULL);
}
}
}

/* send reset to all boards */


spi_emit_reset(SPI_CHANNEL1);
spi_emit_reset(SPI_CHANNEL2);
}

static void init_x5(struct cgpu_info *bitfury)


{
uint8_t board_id, bcm250_id, chip_id;
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);

info->chipboard = cgcalloc(CHIPBOARD_NUM, sizeof(bf_chipboard_t));

/* channel size in bytes */


info->channel_length = (CHANNEL_DEPTH * 3) / 8 + 1;
info->ialarm_count = 1;

info->work_list = workd_list_init();
info->stale_work_list = workd_list_init();
info->noncework_list = noncework_list_init();

if (opt_bf16_renonce != RENONCE_DISABLED) {
info->renoncework_list = renoncework_list_init();
info->renonce_id = 1;
info->renonce_list = renonce_list_init();
}

for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {


/* detect board */
char buff[256];
memset(buff, 0, sizeof(buff));

device_ctrl_txrx(board_id + 1, 0, F_BDET, buff);


parse_board_detect(bitfury, board_id, buff);

if (info->chipboard[board_id].detected == true) {
applog(LOG_NOTICE, "%s: BOARD%d detected", bitfury->drv->name,
board_id + 1);

info->chipboard[board_id].bcm250 = cgcalloc(BCM250_NUM,
sizeof(bf_bcm250_t));
cmd_buffer_init(&info->chipboard[board_id].cmd_buffer);

get_board_info(bitfury, board_id);
update_bcm250_map(bitfury, board_id);

info->chipboard_num++;
info->chipboard[board_id].bcm250_num = BCM250_NUM;

cg_memcpy(&info->chipboard[board_id].pid, &pid,
sizeof(bf_pid_t));

uint8_t chips_num = 0;
for (bcm250_id = 0; bcm250_id < BCM250_NUM; bcm250_id++) {
info->chipboard[board_id].bcm250[bcm250_id].channel_path
= init_channel_path(board_id, bcm250_id,
&info-
>chipboard[board_id].bcm250[bcm250_id].channel_depth, info->channel_length);
info->chipboard[board_id].bcm250[bcm250_id].first_good_chip
= bcm250_map[board_id][bcm250_id].first_good_chip;
info->chipboard[board_id].bcm250[bcm250_id].last_good_chip
= bcm250_map[board_id][bcm250_id].last_good_chip;
info->chipboard[board_id].bcm250[bcm250_id].chips_num
= bcm250_map[board_id][bcm250_id].chips_num;
chips_num += bcm250_map[board_id][bcm250_id].chips_num;

uint8_t first_good_chip = info-


>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
uint8_t last_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].last_good_chip;

for (chip_id = first_good_chip; chip_id < last_good_chip;


chip_id++) {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status =
UNINITIALIZED;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time = time(NULL);
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonce_list =
nonce_list_init();
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_time, NULL);
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].switch_time, NULL);
}
}

info->chipboard[board_id].chips_num = chips_num;
info->chips_num += info->chipboard[board_id].chips_num;
} else
applog(LOG_NOTICE, "%s: BOARD%d not found", bitfury->drv->name,
board_id + 1);

applog(LOG_INFO, "%s: initialized board X5.%d", bitfury->drv->name,


board_id);
}

applog(LOG_INFO, "%s: initialized X5", bitfury->drv->name);


}

static void deinit_x5(struct cgpu_info *bitfury)


{
uint8_t board_id, bcm250_id, chip_id;
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);

workd_list_deinit(info->work_list, bitfury);
workd_list_deinit(info->stale_work_list, bitfury);

noncework_list_deinit(info->noncework_list);

if (opt_bf16_renonce != RENONCE_DISABLED) {
renoncework_list_deinit(info->renoncework_list);
info->renonce_id = 1;
renonce_list_deinit(info->renonce_list);
}

for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {


for (bcm250_id = 0; bcm250_id < BCM250_NUM; bcm250_id++) {
free(info->chipboard[board_id].bcm250[bcm250_id].channel_path);

uint8_t first_good_chip = info-


>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
uint8_t last_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].last_good_chip;

for (chip_id = first_good_chip; chip_id < last_good_chip;


chip_id++)
nonce_list_deinit(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonce_list);
}
free(info->chipboard[board_id].bcm250);

cmd_buffer_deinit(&info->chipboard[board_id].cmd_buffer);
}
free(info->chipboard);
}

static void bitfury16_set_clock(struct cgpu_info *bitfury)


{
uint8_t board_id, bcm250_id, chip_id;
struct bitfury16_info *info = (struct bitfury16_info *)bitfury->device_data;

/* send reset to all boards */


spi_emit_reset(SPI_CHANNEL1);
spi_emit_reset(SPI_CHANNEL2);

/* board loop */
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
applog(LOG_NOTICE, "%s: CHIPBOARD [%d]:", bitfury->drv->name,
board_id);
/* concentrator loop */
for (bcm250_id = 0; bcm250_id < BCM250_NUM; bcm250_id++) {
applog(LOG_NOTICE, "%s: BCM250 [%d]:", bitfury->drv->name,
bcm250_id);

spi_emit_reset(board_id + 1);

/* build channel */
create_channel(board_id + 1, info-
>chipboard[board_id].bcm250[bcm250_id].channel_path, info->channel_length);

uint8_t channel_depth = info-


>chipboard[board_id].bcm250[bcm250_id].channel_depth;
uint8_t first_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
uint8_t last_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].last_good_chip;

uint8_t result;
bool fail;
/* chips loop */
for (chip_id = first_good_chip; chip_id < last_good_chip;
chip_id++) {
fail = false;
bf_chip_address_t chip_address = { board_id, bcm250_id,
chip_id };

result = send_toggle(board_id + 1, channel_depth,


chip_address);
if (result != 0)
fail = true;

result = set_clock(board_id + 1, channel_depth,


chip_address, bf16_chip_clock);
if ((result != 0) && (fail != true))
fail = true;

if (fail == false)
applog(LOG_NOTICE, "%s: CHIP [%2d]: OK", bitfury-
>drv->name, chip_id);
else
applog(LOG_NOTICE, "%s: CHIP [%2d]: FAIL", bitfury-
>drv->name, chip_id);
}

/* destroy channel */
destroy_channel(board_id + 1, info-
>chipboard[board_id].bcm250[bcm250_id].channel_depth);
}
}

deinit_x5(bitfury);
}

static void bitfury16_test_chip(struct cgpu_info *bitfury, bf_chip_address_t


chip_address)
{
struct bitfury16_info *info = (struct bitfury16_info *)bitfury->device_data;

uint8_t board_id = chip_address.board_id;


uint8_t bcm250_id = chip_address.bcm250_id;
uint8_t chip_id = chip_address.chip_id;

/* send reset to board */


spi_emit_reset(board_id + 1);

/* build channel */
create_channel(board_id + 1, info-
>chipboard[board_id].bcm250[bcm250_id].channel_path, info->channel_length);

uint8_t channel_depth = info-


>chipboard[board_id].bcm250[bcm250_id].channel_depth;

uint8_t result;
bool fail = false;

result = send_toggle(board_id + 1, channel_depth, chip_address);


if (result != 0)
fail = true;

result = set_clock(board_id + 1, channel_depth, chip_address,


bf16_chip_clock);
if ((result != 0) && (fail != true))
fail = true;

if (fail == false)
applog(LOG_NOTICE, "%s: CHIP [%2d]: OK", bitfury->drv->name, chip_id);
else
applog(LOG_NOTICE, "%s: CHIP [%2d]: FAIL", bitfury->drv->name,
chip_id);

/* destroy channel */
destroy_channel(board_id + 1, info-
>chipboard[board_id].bcm250[bcm250_id].channel_depth);

deinit_x5(bitfury);
}

static void bitfury16_identify(__maybe_unused struct cgpu_info *bitfury)


{
}
static void set_fan_speed(struct cgpu_info *bitfury)
{
struct bitfury16_info *info = (struct bitfury16_info *)bitfury->device_data;
uint8_t board_id;

for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {


if (info->chipboard[board_id].detected == true) {
if (opt_bf16_fan_speed == -1) {
if (device_uart_transfer(board_id + 1, "F") < 0)
quit(1, "%s: %s() failed to set BOARD%d fan speed",
bitfury->drv->name, __func__, board_id +
1);

applog(LOG_INFO, "%s: set BOARD%d fan speed to auto mode",


bitfury->drv->name, board_id + 1);
} else {
char uart_cmd[8];
sprintf(uart_cmd, "F:%d", opt_bf16_fan_speed);

if (device_uart_transfer(board_id + 1, uart_cmd) < 0)


quit(1, "%s: %s() failed to set BOARD%d fan speed",
bitfury->drv->name, __func__, board_id +
1);

applog(LOG_INFO, "%s: set BOARD%d fan speed to [%d]",


bitfury->drv->name, board_id + 1,
opt_bf16_fan_speed);
}
}
}
}

static void bitfury16_detect(bool hotplug)


{
struct cgpu_info *bitfury = NULL;
struct bitfury16_info *info = NULL;
uint8_t board_id, bcm250_id, chip_id;

if (hotplug)
return;

bitfury = cgmalloc(sizeof(struct cgpu_info));


if (unlikely(!bitfury))
quit(1, "%s: %s() failed to malloc bitfury",
bitfury->drv->name, __func__);

bitfury->drv = &bitfury16_drv;
bitfury->deven = DEV_ENABLED;
bitfury->threads = 1;

info = cgmalloc(sizeof(struct bitfury16_info));


if (unlikely(!info))
quit(1, "%s: %s() failed to malloc info",
bitfury->drv->name, __func__);

bitfury->device_data = info;

/* manual PID option */


#ifdef MINER_X5
manual_pid_enabled = opt_bf16_manual_pid_enabled;
#endif

#ifdef MINER_X6
manual_pid_enabled = !opt_bf16_manual_pid_disabled;
#endif

/* renonce chip address and renonce chip clock */


if (opt_bf16_renonce != RENONCE_DISABLED) {
if (opt_bf16_renonce_clock != NULL)
bf16_renonce_chip_clock = strtol(opt_bf16_renonce_clock, NULL,
16);
} else
/* default chip clock if renonce is disabled */
bf16_chip_clock = 0x2d;

/* general chip clock */


if (opt_bf16_clock != NULL)
bf16_chip_clock = strtol(opt_bf16_clock, NULL, 16);
else if ((opt_bf16_set_clock == true) || (opt_bf16_test_chip != NULL))
/* default chip clock if set_clock option is set */
bf16_chip_clock = 0x20;

/* open devices */
if (open_spi_device(SPI_CHANNEL1) < 0)
quit(1, "%s: %s() failed to open [%s] device",
bitfury->drv->name, __func__, spi0_device_name);

applog(LOG_INFO, "%s: opened [%s] device", bitfury->drv->name,


spi0_device_name);

if (open_spi_device(SPI_CHANNEL2) < 0)
quit(1, "%s: %s() failed to open [%s] device",
bitfury->drv->name, __func__, spi1_device_name);

applog(LOG_INFO, "%s: opened [%s] device", bitfury->drv->name,


spi1_device_name);

if (open_ctrl_device() < 0)
quit(1, "%s: %s() failed to open [%s] device",
bitfury->drv->name, __func__, ctrl_device_name);

applog(LOG_INFO, "%s: opened [%s] device", bitfury->drv->name,


ctrl_device_name);

if (open_uart_device(UART_CHANNEL1) < 0)
quit(1, "%s: %s() failed to open [%s] device",
bitfury->drv->name, __func__, uart1_device_name);

applog(LOG_INFO, "%s: opened [%s] device", bitfury->drv->name,


uart1_device_name);

if (open_uart_device(UART_CHANNEL2) < 0)
quit(1, "%s: %s() failed to open [%s] device",
bitfury->drv->name, __func__, uart2_device_name);

applog(LOG_INFO, "%s: opened [%s] device", bitfury->drv->name,


uart2_device_name);
init_x5(bitfury);

/* send reset to boards */


for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if (info->chipboard[board_id].detected == true) {
device_ctrl_transfer(board_id + 1, 1, F_BRST);
cgsleep_us(POWER_WAIT_INTERVAL);
device_ctrl_transfer(board_id + 1, 0, F_BRST);
cgsleep_us(POWER_WAIT_INTERVAL);

applog(LOG_INFO, "%s: sent reset to BOARD%d",


bitfury->drv->name, board_id + 1);
}
}

/* check if board power is present */


for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
/* read hw sensor data */
char buff[256];

if (info->chipboard[board_id].detected == true) {
memset(buff, 0, sizeof(buff));
if (device_uart_txrx(board_id + 1, "S", buff) < 0)
quit(1, "%s: %s() failed to get BOARD%d status",
bitfury->drv->name, __func__, board_id + 1);

if (parse_hwstats(info, board_id, buff) < 0)


applog(LOG_ERR, "%s: failed to parse hw stats",
bitfury->drv->name);

/* disable board if power voltage is incorrect */


if ((info->chipboard[board_id].u_board < 10.0) ||
(info->chipboard[board_id].u_board > 15.0)) {

/* concentrator loop */
for (bcm250_id = 0; bcm250_id < BCM250_NUM; bcm250_id++) {
uint8_t first_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
uint8_t last_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].last_good_chip;

/* chips loop */
for (chip_id = first_good_chip; chip_id <
last_good_chip; chip_id++)
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status = DISABLED;
}

applog(LOG_ERR, "%s: incorrect U board detected [%.1f] on


BOARD%d, "
"disabling board...",
bitfury->drv->name,
info->chipboard[board_id].u_board,
board_id + 1);
} else {
info->chipboard[board_id].active = true;
info->active_chipboard_num++;
}
}
}

/* enable power chain */


for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if (enable_power_chain(bitfury, board_id, 0) < 0)
info->chipboard[board_id].detected = false;
else {
#ifdef MINER_X5
info->chipboard[board_id].power_enable_time = time(NULL);
info->chipboard[board_id].power_disable_count = 1;
#endif

#ifdef MINER_X6
info->chipboard[board_id].power1_enable_time = time(NULL);
info->chipboard[board_id].power2_enable_time = time(NULL);
info->chipboard[board_id].power1_disable_count = 1;
info->chipboard[board_id].power2_disable_count = 1;
#endif
}
}

/* wait for power chain to enable */


cgsleep_us(POWER_WAIT_INTERVAL);

if (opt_bf16_set_clock == true) {
applog(LOG_INFO, "%s: setting clock [%02x] to all chips",
bitfury->drv->name, bf16_chip_clock);

bitfury16_set_clock(bitfury);

quit(0, "Done.");
}

if (opt_bf16_test_chip != NULL) {
bf_chip_address_t chip_address = { 0, 0, 0 };

if (parse_chip_address(bitfury, opt_bf16_test_chip, &chip_address) < 0)


{
quit(1, "%s: %s() error parsing chip address...",
bitfury->drv->name, __func__);
}

applog(LOG_INFO, "%s: testing communicaton with chip [%d:%d:%2d]",


bitfury->drv->name,
chip_address.board_id,
chip_address.bcm250_id,
chip_address.chip_id);

bitfury16_test_chip(bitfury, chip_address);

quit(0, "Done.");
}

/* fan speed */
if ((opt_bf16_fan_speed != -1) &&
(manual_pid_enabled == true)) {
manual_pid_enabled = false;
}
set_fan_speed(bitfury);

for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {


if (info->chipboard[board_id].detected == true) {
/* target temp */
if (opt_bf16_target_temp == -1) {
if (device_uart_transfer(board_id + 1, "T") < 0)
quit(1, "%s: %s() failed to set BOARD%d target temp",
bitfury->drv->name, __func__, board_id +
1);

applog(LOG_INFO, "%s: set BOARD%d target temp to default


value",
bitfury->drv->name, board_id + 1);
} else {
char uart_cmd[8];
sprintf(uart_cmd, "T:%d", opt_bf16_target_temp);

if (device_uart_transfer(board_id + 1, uart_cmd) < 0)


quit(1, "%s: %s() failed to set BOARD%d target temp",
bitfury->drv->name, __func__, board_id +
1);

applog(LOG_INFO, "%s: set BOARD%d target temp to [%d]",


bitfury->drv->name, board_id + 1,
opt_bf16_target_temp);
}

/* alarm temp */
if (opt_bf16_alarm_temp == -1) {
if (device_uart_transfer(board_id + 1, "C") < 0)
quit(1, "%s: %s() failed to set BOARD%d alarm temp",
bitfury->drv->name, __func__, board_id +
1);

applog(LOG_INFO, "%s: set BOARD%d alarm temp to default


value",
bitfury->drv->name, board_id + 1);
} else {
char uart_cmd[8];
sprintf(uart_cmd, "C:%d", opt_bf16_alarm_temp);

if (device_uart_transfer(board_id + 1, uart_cmd) < 0)


quit(1, "%s: %s() failed to set BOARD%d alarm temp",
bitfury->drv->name, __func__, board_id +
1);

applog(LOG_INFO, "%s: set BOARD%d alarm temp to [%d]",


bitfury->drv->name, board_id + 1,
opt_bf16_alarm_temp);
}
}
}

/* count number of renonce chips */


if (opt_bf16_renonce != RENONCE_DISABLED) {
info->renonce_chips = opt_bf16_renonce;
uint8_t renonce_chips = 0;
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if ((info->chipboard[board_id].detected == true) &&
(info->chipboard[board_id].active == true)) {
if (opt_bf16_renonce == RENONCE_ONE_CHIP) {
if (renonce_chips != info->renonce_chips)
renonce_chips++;
else {
renonce_chip_address[board_id].board_id = -1;
renonce_chip_address[board_id].bcm250_id = -1;
renonce_chip_address[board_id].chip_id = -1;
}
} else
renonce_chips++;
} else {
renonce_chip_address[board_id].board_id = -1;
renonce_chip_address[board_id].bcm250_id = -1;
renonce_chip_address[board_id].chip_id = -1;
}
}

if (renonce_chips != info->renonce_chips) {
applog(LOG_ERR, "%s: expected to find [%d] renonce chips, but
found only [%d]",
bitfury->drv->name, opt_bf16_renonce, renonce_chips);

info->renonce_chips = renonce_chips;
}
} else {
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
renonce_chip_address[board_id].board_id = -1;
renonce_chip_address[board_id].bcm250_id = -1;
renonce_chip_address[board_id].chip_id = -1;
}
}

/* correct renonce chip address */


if (opt_bf16_renonce != RENONCE_DISABLED) {
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if ((info->chipboard[board_id].detected == true) &&
(info->chipboard[board_id].active == true) &&
(renonce_chip_address[board_id].board_id != -1)) {
bcm250_id = renonce_chip_address[board_id].bcm250_id;

uint8_t first_good_chip = info-


>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
uint8_t last_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].last_good_chip;

if (renonce_chip_address[board_id].chip_id >=
last_good_chip)
renonce_chip_address[board_id].chip_id =
last_good_chip - 1;
else if (renonce_chip_address[board_id].chip_id <
first_good_chip)
renonce_chip_address[board_id].chip_id =
first_good_chip;
}
}
}

#ifdef FILELOG
info->logfile = fopen(LOGFILE, "a");
if (info->logfile == NULL)
applog(LOG_ERR, "%s: failed to open logfile [%s]: %s",
bitfury->drv->name, LOGFILE, strerror(errno));
else
mutex_init(&info->logfile_mutex);
#endif

/* exit if no boards present */


if ((info->chipboard_num == 0) ||
(info->active_chipboard_num == 0)) {
deinit_x5(bitfury);

/* close devices */
close_spi_device(SPI_CHANNEL1);
close_spi_device(SPI_CHANNEL2);
close_ctrl_device();
close_uart_device(UART_CHANNEL1);
close_uart_device(UART_CHANNEL2);

#ifdef FILELOG
fclose(info->logfile);
#endif

applog(LOG_ERR, "%s: no boards present. exiting...",


bitfury->drv->name);

free(info);
free(bitfury);

return;
}

mutex_init(&info->nonces_good_lock);

if (!add_cgpu(bitfury))
quit(1, "%s: %s() failed to add_cgpu",
bitfury->drv->name, __func__);

info->initialised = true;

applog(LOG_INFO, "%s: chip driver initialized", bitfury->drv->name);


#ifdef FILELOG
filelog(info, "%s: cgminer started", bitfury->drv->name);
#endif
}

static uint8_t chip_task_update(struct cgpu_info *bitfury, bf_chip_address_t


chip_address)
{
uint8_t i;
int8_t ret = 0;
bf_works_t work;
time_t curr_time_t;
struct timeval curr_time;
uint8_t board_id = chip_address.board_id;
uint8_t bcm250_id = chip_address.bcm250_id;
uint8_t chip_id = chip_address.chip_id;

struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-


>device_data);
bf_cmd_buffer_t* cmd_buffer = &info->chipboard[board_id].cmd_buffer;

if (cmd_buffer->status != EMPTY)
return -1;

switch (info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status) {

/* fill chip buffer with toggle task */


case UNINITIALIZED:
applog(LOG_DEBUG, "%s: chipworker_thr: chip [%d:%d:%2d], prepare
toggle_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);

uint8_t toggle[4] = { 0xa5, 0x00, 0x00, 0x02 };

ret = cmd_buffer_push(cmd_buffer,
info->chipboard[board_id].bcm250[bcm250_id].channel_depth,
chip_address, chip_address,
work, 0, CHIP_CMD_TOGGLE, 3, toggle);

if (ret < 0)
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:%2d], error
prepare toggle_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);
break;

/* fill chip buffer with set clock task */


case TOGGLE_SET:
applog(LOG_DEBUG, "%s: chipworker_thr: chip [%d:%d:%2d], prepare
set_clock_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);

uint8_t clock_buf[4];
memset(clock_buf, 0, sizeof(clock_buf));

/* init renonce chip with lower clock */


if ((renonce_chip(chip_address) == 1) &&
(opt_bf16_renonce != RENONCE_DISABLED)) {
gen_clock_data(bf16_renonce_chip_clock, 1, clock_buf);
info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].clock
= bf16_renonce_chip_clock;
} else {
gen_clock_data(bf16_chip_clock, 1, clock_buf);
info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].clock
= bf16_chip_clock;
}

ret = cmd_buffer_push(cmd_buffer,
info->chipboard[board_id].bcm250[bcm250_id].channel_depth,
chip_address, chip_address,
work, 0, CHIP_CMD_SET_CLOCK, 3, clock_buf);

if (ret < 0)
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:%2d], error
prepare set_clock_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);
break;

/* fill chip buffer with chip mask */


case CLOCK_SET:
applog(LOG_DEBUG, "%s: chipworker_thr: chip [%d:%d:%2d], prepare
set_mask_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);

uint8_t noncemask[4];
memset(noncemask, 0, sizeof(noncemask));

for (i = 0; i < 4; i++)


noncemask[i] = (mask >> (8*(4 - i - 1))) & 0xff;

ret = cmd_buffer_push(cmd_buffer,
info->chipboard[board_id].bcm250[bcm250_id].channel_depth,
chip_address, chip_address,
work, 0, CHIP_CMD_SET_MASK, 3, noncemask);

if (ret < 0)
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:%2d], error
prepare set_mask_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);
break;

/* fill chip buffer with new task */


case MASK_SET:
if ((renonce_chip(chip_address) == 0) ||
(opt_bf16_renonce == RENONCE_DISABLED)) {
applog(LOG_DEBUG, "%s: chipworker_thr: chip [%d:%d:%2d], prepare
send_task_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);

L_LOCK(info->work_list);
L_LOCK(info->stale_work_list);
if (info->work_list->count > 0) {
memset(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork.task, 0,
sizeof(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork.task));

bf_data_t* wdata = info->work_list->head;

workd_list_push(info->stale_work_list, WORKD(wdata));
workd_list_remove(info->work_list, &info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork);

gen_task_data(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork.payload.midstate,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork.payload.m7,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork.payload.ntime,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork.payload.nbits, mask,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork.task);

ret = cmd_buffer_push(cmd_buffer,
info-
>chipboard[board_id].bcm250[bcm250_id].channel_depth, chip_address, chip_address,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork, 0,
CHIP_CMD_TASK_WRITE, 79,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork.task);

if (ret < 0)
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:
%2d], error prepare send_task_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);
}
#if 0
else
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:%2d],
error prepare send_task_cmd: no works available",
bitfury->drv->name,
board_id, bcm250_id, chip_id);
#endif
L_UNLOCK(info->stale_work_list);
L_UNLOCK(info->work_list);
}

break;

/* fill chip buffer with check status task */


case TASK_SENT:
gettimeofday(&curr_time, NULL);

if (((renonce_chip(chip_address) == 0) ||
(opt_bf16_renonce == RENONCE_DISABLED)) &&
(timediff_us(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_time, curr_time) >
CHIP_TASK_STATUS_INTERVAL)) {
applog(LOG_DEBUG, "%s: chipworker_thr: chip [%d:%d:%2d], prepare
task_status_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);

ret = cmd_buffer_push(cmd_buffer,
info-
>chipboard[board_id].bcm250[bcm250_id].channel_depth, chip_address, chip_address,
work, 0, CHIP_CMD_TASK_STATUS, 0, NULL);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_time.tv_sec =
curr_time.tv_sec;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_time.tv_usec =
curr_time.tv_usec;

if (ret < 0)
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:%2d],
error prepare task_status_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);
}
break;

/* fill chip buffer with read nonces task */


case TASK_SWITCHED:
if ((renonce_chip(chip_address) == 0) ||
(opt_bf16_renonce == RENONCE_DISABLED)) {
applog(LOG_DEBUG, "%s: chipworker_thr: chip [%d:%d:%2d], prepare
read_nonce_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);

ret = cmd_buffer_push(cmd_buffer,
info-
>chipboard[board_id].bcm250[bcm250_id].channel_depth, chip_address, chip_address,
work, 0, CHIP_CMD_READ_NONCE, 0, NULL);

if (ret < 0)
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:%2d],
error prepare read_nonce_cmd",
bitfury->drv->name,
board_id, bcm250_id, chip_id);
}

break;

/* mark chip as UNINITIALIZED and start all over again */


case FAILING:
curr_time_t = time(NULL);
time_t time_diff = curr_time_t - info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_error_time;

if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count <
CHIP_ERROR_FAIL_LIMIT) {
if (time_diff >= info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count *
CHIP_RECOVERY_INTERVAL) {

/* change renonce chip address if


RENONCE_CHIP_ERROR_FAIL_LIMIT reached */
if ((renonce_chip(chip_address) == 1) &&
(opt_bf16_renonce != RENONCE_DISABLED)) {
if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count ==
RENONCE_CHIP_ERROR_FAIL_LIMIT) {
applog(LOG_ERR, "%s: chipworker_thr: renonce
chip [%d:%d:%2d] failed. trying to switch to another one...",
bitfury->drv->name,
chip_address.board_id,
chip_address.bcm250_id,
chip_address.chip_id);

if (change_renonce_chip_address(bitfury,
chip_address) == 0) {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status =
UNINITIALIZED;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time =
curr_time_t;
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_time, NULL);
}
} else {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status =
UNINITIALIZED;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time =
curr_time_t;
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_time, NULL);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count++;
}
} else {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status =
UNINITIALIZED;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time =
curr_time_t;
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_time, NULL);
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].switch_time, NULL);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count++;

#ifdef FILELOG
filelog(info, "BF16: chip [%d:%d:%2d] recovered
time_diff: [%d], "
"recovery_count: [%d], error_rate: [%d]",
board_id, bcm250_id, chip_id,
time_diff,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}
}
}
/* mark chip as DISABLED and never communicate to it again */
else if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status != DISABLED) {
info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status
= DISABLED;

#ifdef FILELOG
filelog(info, "BF16: disabling chip [%d:%d:%2d] recovery_count:
[%d], error_rate: [%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}
break;

case DISABLED:
default:
break;
}

return ret;
}

static uint8_t renonce_task_update_loop(struct cgpu_info *bitfury, uint8_t


board_id,
bf_renonce_stage_t stage, uint8_t renonce_count)
{
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);
bf_cmd_buffer_t* cmd_buffer = &info->chipboard[board_id].cmd_buffer;

uint8_t bcm250_id = renonce_chip_address[board_id].bcm250_id;


uint8_t chip_id = renonce_chip_address[board_id].chip_id;

uint8_t nonces = 0;

if (info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status <
FAILING) {
L_LOCK(info->renonce_list);
bf_data_t* rdata = info->renonce_list->head;
while ((rdata != NULL) && (nonces < renonce_count)) {
uint8_t ret = 1;

if ((RENONCE(rdata)->sent == false) &&


(RENONCE(rdata)->stage == stage)) {
/* generate work mask */
uint32_t nonce_mask = gen_mask(RENONCE(rdata)->nonce,
mask_bits);
nonce_mask = ntohl(nonce_mask);

switch (RENONCE(rdata)->stage) {
case RENONCE_STAGE0:
case RENONCE_STAGE2:
/* generate chip work with new mask */
cg_memcpy(RENONCE(rdata)->owork.task + 19*4,
&nonce_mask, sizeof(nonce_mask));

/* send task and read nonces at the same time


*/
ret = cmd_buffer_push(cmd_buffer,
info-
>chipboard[board_id].bcm250[bcm250_id].channel_depth,
renonce_chip_address[board_id],
RENONCE(rdata)->src_address,
RENONCE(rdata)->owork,
RENONCE(rdata)->id,
(CHIP_CMD_TASK_WRITE |
CHIP_CMD_TASK_SWITCH | CHIP_CMD_READ_NONCE), 79,
RENONCE(rdata)->owork.task);
break;
case RENONCE_STAGE1:
case RENONCE_STAGE3:
/* generate chip work with new mask */
cg_memcpy(RENONCE(rdata)->cwork.task + 19*4,
&nonce_mask, sizeof(nonce_mask));

/* send task and read nonces at the same time


*/
ret = cmd_buffer_push(cmd_buffer,
info-
>chipboard[board_id].bcm250[bcm250_id].channel_depth,
renonce_chip_address[board_id],
RENONCE(rdata)->src_address,
RENONCE(rdata)->cwork,
RENONCE(rdata)->id,
(CHIP_CMD_TASK_WRITE |
CHIP_CMD_TASK_SWITCH | CHIP_CMD_READ_NONCE), 79,
RENONCE(rdata)->cwork.task);
break;
case RENONCE_STAGE_FINISHED:
default:
break;
}
}

if (ret == 0) {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status = TASK_SWITCHED;
RENONCE(rdata)->sent = true;
RENONCE(rdata)->received = false;
nonces++;
}

rdata = rdata->next;
}
L_UNLOCK(info->renonce_list);
}

return nonces;
}

static void renonce_task_update(struct cgpu_info *bitfury, uint8_t board_id,


uint8_t renonce_count)
{
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);
bf_cmd_buffer_t* cmd_buffer = &info->chipboard[board_id].cmd_buffer;
bf_works_t work;
uint8_t i;

uint8_t bcm250_id = renonce_chip_address[board_id].bcm250_id;


uint8_t chip_id = renonce_chip_address[board_id].chip_id;

cmd_buffer_push_create_channel(cmd_buffer,
info->chipboard[board_id].bcm250[bcm250_id].channel_path,
info->channel_length);

if (info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status <
FAILING) {
uint8_t toggle[4] = { 0xa5, 0x00, 0x00, 0x02 };

cmd_buffer_push(cmd_buffer,
info->chipboard[board_id].bcm250[bcm250_id].channel_depth,
renonce_chip_address[board_id],
renonce_chip_address[board_id],
work, 0, CHIP_CMD_TOGGLE, 3, toggle);

uint8_t clock_buf[4];
memset(clock_buf, 0, sizeof(clock_buf));
gen_clock_data(bf16_renonce_chip_clock, 1, clock_buf);

cmd_buffer_push(cmd_buffer,
info->chipboard[board_id].bcm250[bcm250_id].channel_depth,
renonce_chip_address[board_id],
renonce_chip_address[board_id],
work, 0, CHIP_CMD_SET_CLOCK, 3, clock_buf);

uint8_t noncemask[4];
memset(noncemask, 0, sizeof(noncemask));

for (i = 0; i < 4; i++)


noncemask[i] = (mask >> (8*(4 - i - 1))) & 0xff;

cmd_buffer_push(cmd_buffer,
info->chipboard[board_id].bcm250[bcm250_id].channel_depth,
renonce_chip_address[board_id],
renonce_chip_address[board_id],
work, 0, CHIP_CMD_SET_MASK, 3, noncemask);

bf_renonce_stage_t stage = RENONCE_STAGE0;


while ((renonce_count > 0) && (stage != RENONCE_STAGE_FINISHED)) {
renonce_count -= renonce_task_update_loop(bitfury, board_id,
stage++, renonce_count);
}
}

cmd_buffer_push_destroy_channel(cmd_buffer,
info->chipboard[board_id].
bcm250[renonce_chip_address[board_id].bcm250_id].channel_depth);
}

static void fill_cmd_buffer_loop(struct cgpu_info *bitfury, uint8_t board_id, bool


do_renonce, uint16_t renonce_count)
{
uint8_t bcm250_id, chip_id;
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);
bf_cmd_buffer_t* cmd_buffer = &info->chipboard[board_id].cmd_buffer;

/* concentrator loop */
for (bcm250_id = 0; bcm250_id < BCM250_NUM; bcm250_id++) {
uint8_t first_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
uint8_t last_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].last_good_chip;

cmd_buffer_push_create_channel(cmd_buffer,
info->chipboard[board_id].bcm250[bcm250_id].channel_path,
info->channel_length);

/* chips loop */
for (chip_id = first_good_chip; chip_id < last_good_chip; chip_id++) {
bf_chip_address_t chip_address = { board_id, bcm250_id,
chip_id };
chip_task_update(bitfury, chip_address);
}

cmd_buffer_push_destroy_channel(cmd_buffer,
info->chipboard[board_id].bcm250[bcm250_id].channel_depth);
}

if (do_renonce == true) {
uint8_t count = (cmd_buffer->free_bytes - (2 + 11 + 11 + 11 + 8)) /
136;
if (count < renonce_count) {
if (count > 0)
renonce_task_update(bitfury, board_id, count);
} else if (renonce_count > 0)
renonce_task_update(bitfury, board_id, renonce_count);
}

cmd_buffer->status = TX_READY;
}

static void fill_cmd_buffer(struct cgpu_info *bitfury, uint8_t board_id)


{
static uint8_t do_renonce[CHIPBOARD_NUM];
uint16_t renonce_count = 0;

struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-


>device_data);
bf_cmd_buffer_t* cmd_buffer = &info->chipboard[board_id].cmd_buffer;

if (cmd_buffer->status == EMPTY) {
if ((opt_bf16_renonce == RENONCE_DISABLED) ||
(renonce_chip_address[board_id].board_id == -1)) {

fill_cmd_buffer_loop(bitfury, board_id, false, 0);


} else {
L_LOCK(info->renonce_list);
bf_data_t* rdata = info->renonce_list->head;
while (rdata != NULL) {
if (RENONCE(rdata)->sent == false)
renonce_count++;
rdata = rdata->next;
}
L_UNLOCK(info->renonce_list);

if (do_renonce[board_id] < RENONCE_SEND) {


fill_cmd_buffer_loop(bitfury, board_id, true,
renonce_count);

do_renonce[board_id]++;
} else {
if (renonce_count >= RENONCE_COUNT) {
renonce_task_update(bitfury, board_id,
RENONCE_COUNT);

do_renonce[board_id] = 0;
cmd_buffer->status = TX_READY;
} else {
fill_cmd_buffer_loop(bitfury, board_id, true,
renonce_count);

do_renonce[board_id]++;
}
}
}
}
}

static uint8_t update_chip_status(struct cgpu_info *bitfury, bf_cmd_status_t


cmd_status)
{
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);
uint8_t board_id = cmd_status.chip_address.board_id;
uint8_t bcm250_id = cmd_status.chip_address.bcm250_id;
uint8_t chip_id = cmd_status.chip_address.chip_id;

switch (info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status) {

case UNINITIALIZED:
case TOGGLE_SET:
case CLOCK_SET:
case MASK_SET:
applog(LOG_DEBUG, "%s: chipworker_thr: chip [%d:%d:%2d], send_cmd
[%s]",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
get_cmd_description(cmd_status.cmd_code));

/* update chip status */


if (cmd_status.checksum_error == false)
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status++;

else {
#ifndef DISABLE_SEND_CMD_ERROR
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:%2d]: error
send_cmd [%s]. "
"checksum: expected: [%02x]; received: [%02x]",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
get_cmd_description(cmd_status.cmd_code),
cmd_status.checksum_expected,
cmd_status.checksum_received);
#endif

/* increase error counters */


increase_errors(info, cmd_status.chip_address);
}
break;

case TASK_SENT:
applog(LOG_DEBUG, "%s: chipworker_thr: chip [%d:%d:%2d], send_cmd
[%s]",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
get_cmd_description(cmd_status.cmd_code));

/* read task status from chip*/


if (cmd_status.checksum_error == false) {
uint8_t new_buff = ((cmd_status.status & 0x0f) == 0x0f) ? 1 : 0;

/* status cmd counter */


info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd_dx++;
info->chipboard[board_id].bcm250[bcm250_id].status_cmd_dx++;
info->chipboard[board_id].status_cmd_dx++;
info->status_cmd_dx++;

/* check if chip task has switched */


if (new_buff != info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].curr_buff) {
gettimeofday(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].switch_time, NULL);
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].curr_buff = new_buff;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status++;

/* task switch counter */


increase_task_switch(info, cmd_status.chip_address);

} else {
/* task not switched */
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd_none_dx++;
info-
>chipboard[board_id].bcm250[bcm250_id].status_cmd_none_dx++;
info->chipboard[board_id].status_cmd_none_dx++;
info->status_cmd_none_dx++;

/* check if chip hang */


struct timeval curr_time;
gettimeofday(&curr_time, NULL);

if ((timediff_us(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].switch_time, curr_time) >
CHIP_TASK_SWITCH_INTERVAL) &&
(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status < FAILING)) {
increase_errors(info, cmd_status.chip_address);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status = FAILING;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_error_time = time(NULL);

applog(LOG_ERR, "%s: nonceworker_thr: chip [%d:%d:


%2d], "
"failed: no task switch during last
[%.3f] seconds",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
CHIP_TASK_SWITCH_INTERVAL / 1000000.0);

#ifdef FILELOG
filelog(info, "BF16: no task switch for chip [%d:%d:
%2d], "
"error count: [%d], recovery_count: [%d],
error_rate: [%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].errors,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}
}
} else {
#ifndef DISABLE_SEND_CMD_ERROR
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:%2d]: error
send_cmd [%s]. "
"checksum: expected: [%02x]; received: [%02x]",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
get_cmd_description(cmd_status.cmd_code),
cmd_status.checksum_expected,
cmd_status.checksum_received);
#endif

/* increase error counters */


increase_errors(info, cmd_status.chip_address);
}
break;

case TASK_SWITCHED:
applog(LOG_DEBUG, "%s: chipworker_thr: chip [%d:%d:%2d], send_cmd
[%s]",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
get_cmd_description(cmd_status.cmd_code));

if (cmd_status.checksum_error == false) {
if ((renonce_chip(cmd_status.chip_address) == 1) &&
(opt_bf16_renonce != RENONCE_DISABLED)) {

/* task switch counter */


if (cmd_status.cmd_code & CHIP_CMD_READ_NONCE)
increase_task_switch(info, cmd_status.chip_address);
} else if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status < FAILING) {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].task_processed++;

if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].task_processed >=
CHIP_RESTART_LIMIT) {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status = UNINITIALIZED;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].task_processed = 0;
} else
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status = MASK_SET;
}

return 1;
} else {
#ifndef DISABLE_SEND_CMD_ERROR
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:%2d]: error
send_cmd [%s]. "
"checksum: expected: [%02x]; received: [%02x]",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
get_cmd_description(cmd_status.cmd_code),
cmd_status.checksum_expected,
cmd_status.checksum_received);
#endif

/* increase error counters */


increase_errors(info, cmd_status.chip_address);
}

break;

case FAILING:
case DISABLED:
default:
break;
}

return 0;
}

static uint8_t process_nonces(struct cgpu_info *bitfury, bf_cmd_status_t


cmd_status, uint32_t* nonces)
{
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);

uint8_t i;
uint32_t found_nonces[12];

uint8_t board_id = cmd_status.chip_address.board_id;


uint8_t bcm250_id = cmd_status.chip_address.bcm250_id;
uint8_t chip_id = cmd_status.chip_address.chip_id;
if ((cmd_status.checksum_error == false) &&
(cmd_status.nonce_checksum_error == false)) {
cg_memcpy(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].rx, nonces,
sizeof(found_nonces));

uint8_t found = find_nonces(info-


>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].rx,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].rx_prev,
found_nonces);

/* check if chip is still mining */


if (found == 0) {
time_t curr_time = time(NULL);
time_t time_diff = curr_time - info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time;

if ((renonce_chip(cmd_status.chip_address) == 1) &&
(opt_bf16_renonce != RENONCE_DISABLED)) {
if ((time_diff >= RENONCE_CHIP_FAILING_INTERVAL) &&
(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status < FAILING)) {
increase_errors(info, cmd_status.chip_address);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status = FAILING;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_error_time = curr_time;

applog(LOG_ERR, "%s: nonceworker_thr: renonce chip


[%d:%d:%2d] "
"failed: no good nonces during last
[%.1f] seconds",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
RENONCE_CHIP_FAILING_INTERVAL);

#ifdef FILELOG
filelog(info, "BF16: no good nonces from renonce chip
[%d:%d:%2d], "
"error count: [%d] recovery_count: [%d],
error_rate: [%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].errors,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}
} else {
if ((time_diff >= CHIP_FAILING_INTERVAL) &&
(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status < FAILING)) {
increase_errors(info, cmd_status.chip_address);
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status = FAILING;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_error_time = curr_time;

applog(LOG_ERR, "%s: nonceworker_thr: chip [%d:%d:


%2d], "
"failed: no good nonces during last
[%.1f] seconds",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
CHIP_FAILING_INTERVAL);

#ifdef FILELOG
filelog(info, "BF16: no good nonces from chip [%d:%d:
%2d], "
"error count: [%d], recovery_count: [%d],
error_rate: [%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].errors,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}
}
}

/* increase stage if no nonces received */


if ((renonce_chip(cmd_status.chip_address) == 1) &&
(opt_bf16_renonce != RENONCE_DISABLED)) {
L_LOCK(info->renonce_list);
bf_data_t* rdata = info->renonce_list->head;
while (rdata != NULL) {
if (RENONCE(rdata)->id == cmd_status.id) {
if (found == 0) {
RENONCE(rdata)->stage++;
RENONCE(rdata)->sent = false;

/* clear renonces list if we are running too


slow */
if ((RENONCE(rdata)->stage >= RENONCE_STAGE2)
&&
(info->renonce_list->count >
RENONCE_STAGE2_LIMIT)) {
info->unmatched++;
increase_re_bad_nonces(info,
RENONCE(rdata)->src_address);
bf_data_t* rndata = rdata->next;
renonce_list_remove(info->renonce_list,
rdata);
rdata = rndata;
continue;
}

if ((RENONCE(rdata)->stage >= RENONCE_STAGE3)


&&
(info->renonce_list->count >
RENONCE_STAGE3_LIMIT)) {
info->unmatched++;
increase_re_bad_nonces(info,
RENONCE(rdata)->src_address);
bf_data_t* rndata = rdata->next;
renonce_list_remove(info->renonce_list,
rdata);
rdata = rndata;
continue;
}

/* remove expired renonce */


if (RENONCE(rdata)->stage ==
RENONCE_STAGE_FINISHED) {
info->unmatched++;
increase_re_bad_nonces(info,
RENONCE(rdata)->src_address);
bf_data_t* rndata = rdata->next;
renonce_list_remove(info->renonce_list,
rdata);
rdata = rndata;
continue;
}
}

RENONCE(rdata)->received = true;
break;
}
rdata = rdata->next;
}
L_UNLOCK(info->renonce_list);
}

bf_list_t* nonce_list = info-


>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonce_list;
for (i = 0; i < found; i++) {
L_LOCK(nonce_list);
int8_t res = nonce_list_push(nonce_list, found_nonces[i]);
L_UNLOCK(nonce_list);
if (res < 0)
continue;

increase_total_nonces(info, cmd_status.chip_address);

/* check if nonce has errors and add it to renonce list */


if ((opt_bf16_renonce != RENONCE_DISABLED) &&
(renonce_chip(cmd_status.chip_address) == 0) &&
(found_nonces[i] & 0xfff00000) == 0xaaa00000) {
increase_re_nonces(info, cmd_status.src_address);

L_LOCK(info->renonce_list);
if (info->renonce_list->count < RENONCE_QUEUE_LEN) {
renonce_list_push(info->renonce_list,
info->renonce_id++,
found_nonces[i],
cmd_status.chip_address,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].owork);
} else
increase_re_bad_nonces(info,
cmd_status.chip_address);
L_UNLOCK(info->renonce_list);

applog(LOG_DEBUG, "%s: chipworker_thr: pushing renonce


task: nonce: [%08x]",
bitfury->drv->name,
found_nonces[i]);
continue;
}

/* add nonces to noncework list */


if ((renonce_chip(cmd_status.chip_address) == 1) &&
(opt_bf16_renonce != RENONCE_DISABLED)) {
L_LOCK(info->renoncework_list);
renoncework_list_push(info->renoncework_list,
cmd_status.chip_address, found_nonces[i]);
L_UNLOCK(info->renoncework_list);
} else {
L_LOCK(info->noncework_list);
noncework_list_push(info->noncework_list,
cmd_status.chip_address,
cmd_status.src_address,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].owork,
found_nonces[i]);
L_UNLOCK(info->noncework_list);
}

applog(LOG_DEBUG, "%s: chipworker_thr: pushing nonce task: nonce:


[%08x]",
bitfury->drv->name,
found_nonces[i]);
}

/* rotate works and buffers */


cg_memcpy(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].rx_prev,
info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].rx,
sizeof(found_nonces));

cg_memcpy(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].owork,
&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].cwork, sizeof(bf_works_t));

/* remove old nonces from nonce list */


L_LOCK(nonce_list);
if ((renonce_chip(cmd_status.chip_address) == 1) &&
(opt_bf16_renonce != RENONCE_DISABLED)) {
while (nonce_list->count > RENONCE_CHIP_QUEUE_LEN)
nonce_list_pop(nonce_list);
} else {
while (nonce_list->count > NONCE_CHIP_QUEUE_LEN)
nonce_list_pop(nonce_list);
}
L_UNLOCK(nonce_list);
} else {
if (cmd_status.checksum_error != 0) {
#ifndef DISABLE_SEND_CMD_ERROR
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:%2d]: error
send_cmd [%s]. "
"checksum: expected: [%02x]; received: [%02x]",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
get_cmd_description(cmd_status.cmd_code),
cmd_status.checksum_expected,
cmd_status.checksum_received);
#endif

/* increase error counters */


increase_errors(info, cmd_status.chip_address);
}

if (cmd_status.nonce_checksum_error != 0) {
if ((renonce_chip(cmd_status.chip_address) == 0) ||
(opt_bf16_renonce == RENONCE_DISABLED)) {
applog(LOG_ERR, "%s: chipworker_thr: chip [%d:%d:%2d]:
error receiving data. "
"nonce checksum: expected: [%02x]; received:
[%02x]",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
cmd_status.checksum_expected,
cmd_status.checksum_received);

/* increase error counters */


increase_errors(info, cmd_status.chip_address);
}
}
}

return 0;
}

/* routine sending-receiving data to chipboard */


static void process_cmd_buffer(struct cgpu_info *bitfury, uint8_t board_id)
{
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);
uint8_t i;
bf_cmd_status_t cmd_status;
bf_cmd_buffer_t* cmd_buffer = &info->chipboard[board_id].cmd_buffer;

if (cmd_buffer->status == EXECUTED) {
/* process extracted data */
uint16_t cmd_number = cmd_buffer->cmd_list->count;
for (i = 0; i < cmd_number; i++) {
uint32_t nonces[12];

cmd_buffer_pop(cmd_buffer, &cmd_status, nonces);


if ((cmd_status.cmd_code == CHIP_CMD_CREATE_CHANNEL) ||
(cmd_status.cmd_code == CHIP_CMD_TASK_SWITCH))
continue;

uint8_t task_switch = update_chip_status(bitfury, cmd_status);

/* analyze nonces */
if ((cmd_status.cmd_code & CHIP_CMD_READ_NONCE) &&
(task_switch == 1)) {
process_nonces(bitfury, cmd_status, nonces);
}
}

cmd_buffer_clear(cmd_buffer);
}
}

static void *bitfury_chipworker(void *userdata)


{
struct cgpu_info *bitfury = (struct cgpu_info *)userdata;
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);
uint8_t board_id;

applog(LOG_INFO, "%s: started chipworker thread", bitfury->drv->name);

while (bitfury->shutdown == false) {


if (info->initialised) {
break;
}
cgsleep_us(30);
}

/* send reset sequence to boards */


spi_emit_reset(SPI_CHANNEL1);
spi_emit_reset(SPI_CHANNEL2);

while (bitfury->shutdown == false) {


if ((info->a_temp == false) &&
(info->a_ichain == false)) {
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if (info->chipboard[board_id].detected == true) {
/* prepare send buffer */
struct timeval start_time, stop_time;
gettimeofday(&start_time, NULL);

if (info->chipboard[board_id].cmd_buffer.status ==
EMPTY)
fill_cmd_buffer(bitfury, board_id);

gettimeofday(&stop_time, NULL);

#if 0
applog(LOG_ERR, "%s: chipworker_thr: board %d buffer
prepare: time elapsed: [%.6f]",
bitfury->drv->name, board_id,
timediff(start_time, stop_time));
#endif

gettimeofday(&start_time, NULL);
/* send buffer to chipboard */
if (info->chipboard[board_id].cmd_buffer.status ==
TX_READY) {
spi_emit_reset(board_id + 1);

cmd_buffer_exec(board_id + 1, &info-
>chipboard[board_id].cmd_buffer);
info->chipboard[board_id].bytes_transmitted_dx
+= info->chipboard[board_id].cmd_buffer.tx_offset;
info->chipboard[board_id].bytes_transmitted
+= info->chipboard[board_id].cmd_buffer.tx_offset;
}

gettimeofday(&stop_time, NULL);

#if 0
applog(LOG_ERR, "%s: chipworker_thr: board %d TX/RX
time: [%.6f]",
bitfury->drv->name, board_id,
timediff(start_time, stop_time));
#endif

gettimeofday(&start_time, NULL);

/* analyze received data */


if (info->chipboard[board_id].cmd_buffer.status ==
EXECUTED) {
process_cmd_buffer(bitfury, board_id);
}

gettimeofday(&stop_time, NULL);

#if 0
applog(LOG_ERR, "%s: chipworker_thr: board %d buffer
processing: time elapsed: [%.6f]",
bitfury->drv->name, board_id,
timediff(start_time, stop_time));
#endif
}
}
} else
cgsleep_us(CHIPWORKER_DELAY);
}

applog(LOG_INFO, "%s: chipworker_thr: exiting...", bitfury->drv->name);


return NULL;
}

static int16_t cleanup_older(struct cgpu_info *bitfury)


{
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);
time_t curr_time = time(NULL);
uint16_t released = 0;

/* clear stale work list */


L_LOCK(info->stale_work_list);
bf_data_t* wdata = info->stale_work_list->head;
while (wdata != NULL) {
if (curr_time - WORKD(wdata)->generated >= WORK_TIMEOUT) {
workd_list_pop(info->stale_work_list, bitfury);
released++;
} else
break;
wdata = info->stale_work_list->head;
}
L_UNLOCK(info->stale_work_list);

applog(LOG_INFO, "%s: released %d works", bitfury->drv->name, released);


return released;
}

static void *bitfury_nonceworker(void *userdata)


{
struct cgpu_info *bitfury = (struct cgpu_info *)userdata;
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);

applog(LOG_INFO, "%s: started nonceworker thread", bitfury->drv->name);

while (bitfury->shutdown == false) {


if (info->initialised) {
break;
}
cgsleep_us(30);
}

applog(LOG_INFO, "%s: nonceworker loop started", bitfury->drv->name);

while (bitfury->shutdown == false) {


struct timeval start_time, stop_time;
gettimeofday(&start_time, NULL);

uint32_t nonce_cnt = 0;

/* general nonces processing */


L_LOCK(info->noncework_list);
bf_data_t* nwdata = info->noncework_list->head;
while (nwdata != NULL) {
uint8_t board_id = NONCEWORK(nwdata)->chip_address.board_id;
uint8_t bcm250_id = NONCEWORK(nwdata)->chip_address.bcm250_id;
uint8_t chip_id = NONCEWORK(nwdata)->chip_address.chip_id;

nonce_cnt++;

/* general chip results processing */


if (test_nonce(&NONCEWORK(nwdata)->owork.work, NONCEWORK(nwdata)-
>nonce)) {
applog(LOG_DEBUG, "%s: nonceworker_thr: chip [%d:%d:%2d],
valid nonce [%08x]",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
NONCEWORK(nwdata)->nonce);

submit_tested_work(info->thr, &NONCEWORK(nwdata)-
>owork.work);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time = time(NULL);

if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count > 0) {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count = 0;

#ifdef FILELOG
filelog(info, "BF16: good nonce for chip [%d:%d:%2d]
"
"setting recovery_count to [0],
error_rate: [%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}

increase_good_nonces(info, NONCEWORK(nwdata)-
>chip_address);

mutex_lock(&info->nonces_good_lock);
info->nonces_good_cg++;
mutex_unlock(&info->nonces_good_lock);
} else if (test_nonce(&NONCEWORK(nwdata)->cwork.work,
NONCEWORK(nwdata)->nonce)) {
applog(LOG_DEBUG, "%s: nonceworker_thr: chip [%d:%d:%2d],
valid nonce [%08x]",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
NONCEWORK(nwdata)->nonce);

submit_tested_work(info->thr, &NONCEWORK(nwdata)-
>cwork.work);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time = time(NULL);

if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count > 0) {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count = 0;

#ifdef FILELOG
filelog(info, "BF16: good nonce for chip [%d:%d:%2d]
"
"setting recovery_count to 0, error_rate:
[%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}

increase_good_nonces(info, NONCEWORK(nwdata)-
>chip_address);

mutex_lock(&info->nonces_good_lock);
info->nonces_good_cg++;
mutex_unlock(&info->nonces_good_lock);
} else {
time_t curr_time = time(NULL);
time_t time_diff = curr_time - info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time;

if ((time_diff >= CHIP_FAILING_INTERVAL) &&


(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status < FAILING)) {
increase_errors(info, NONCEWORK(nwdata)-
>chip_address);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status = FAILING;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_error_time = curr_time;

applog(LOG_ERR, "%s: nonceworker_thr: chip [%d:%d:


%2d], "
"failed: no good nonces during last
[%.1f] seconds",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
CHIP_FAILING_INTERVAL);

#ifdef FILELOG
filelog(info, "BF16: no good nonces from chip [%d:%d:
%2d], "
"error count: [%d], recovery_count: [%d],
error_rate: [%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].errors,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}

if (opt_bf16_renonce != RENONCE_DISABLED) {
/* add failed nonce to renonce list */
increase_bad_nonces(info, NONCEWORK(nwdata)-
>chip_address);

L_LOCK(info->renonce_list);
if (info->renonce_list->count < RENONCE_QUEUE_LEN) {
renonce_list_push(info->renonce_list,
info->renonce_id++,
NONCEWORK(nwdata)->nonce,
NONCEWORK(nwdata)->chip_address,
NONCEWORK(nwdata)->cwork,
NONCEWORK(nwdata)->owork);
} else
increase_re_bad_nonces(info, NONCEWORK(nwdata)-
>chip_address);
L_UNLOCK(info->renonce_list);

applog(LOG_DEBUG, "%s: nonceworker_thr: pushing


renonce task: nonce: [%08x]",
bitfury->drv->name,
NONCEWORK(nwdata)->nonce);
} else
increase_bad_nonces(info, NONCEWORK(nwdata)-
>chip_address);
}

/* remove nonce from list */


noncework_list_pop(info->noncework_list);
nwdata = info->noncework_list->head;
}
L_UNLOCK(info->noncework_list);

/* cleanup older works */


cleanup_older(bitfury);

gettimeofday(&stop_time, NULL);

#if 0
applog(LOG_DEBUG, "%s: nonceworker_thr: nonces processed [%d]: time
elapsed: [%.6f]",
bitfury->drv->name,
nonce_cnt, timediff(start_time, stop_time));
#endif

cgsleep_us(NONCEWORKER_DELAY);
}

applog(LOG_INFO, "%s: nonceworker_thr: exiting...", bitfury->drv->name);


return NULL;
}

static bool test_renonce(struct cgpu_info *bitfury, bf_data_t* rdata, bf_data_t*


rnwdata, bool owork)
{
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);

uint8_t board_id = RENONCEWORK(rnwdata)->src_address.board_id;


uint8_t bcm250_id = renonce_chip_address[board_id].bcm250_id;
uint8_t chip_id = renonce_chip_address[board_id].chip_id;

if (owork == true) {
if (test_nonce(&RENONCE(rdata)->owork.work, RENONCEWORK(rnwdata)-
>nonce)) {
applog(LOG_DEBUG, "%s: renonceworker_thr: restored renonce:
nonce: [%08x]",
bitfury->drv->name,
RENONCEWORK(rnwdata)->nonce);

submit_tested_work(info->thr, &RENONCE(rdata)->owork.work);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time = time(NULL);

if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count > 0) {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count = 0;

#ifdef FILELOG
filelog(info, "BF16: good nonce for renonce chip [%d:%d:
%2d] "
"setting recovery_count to 0, error_rate:
[%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}

increase_re_good_nonces(info, RENONCE(rdata)->src_address);
increase_re_good_nonces(info, renonce_chip_address[board_id]);

mutex_lock(&info->nonces_good_lock);
info->nonces_good_cg++;
mutex_unlock(&info->nonces_good_lock);

RENONCE(rdata)->match = true;
} else {
time_t curr_time = time(NULL);
time_t time_diff = curr_time - info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time;

if ((time_diff >= RENONCE_CHIP_FAILING_INTERVAL) &&


(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status < FAILING)) {
increase_errors(info, renonce_chip_address[board_id]);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status = FAILING;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_error_time = curr_time;

applog(LOG_ERR, "%s: nonceworker_thr: renonce chip [%d:%d:


%2d] "
"failed: no good nonces during last [%.1f]
seconds",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
RENONCE_CHIP_FAILING_INTERVAL);

#ifdef FILELOG
filelog(info, "BF16: no good nonces from renonce chip [%d:
%d:%2d], "
"error count: [%d] recovery_count: [%d],
error_rate: [%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].errors,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}
}
} else {
if (test_nonce(&RENONCE(rdata)->cwork.work, RENONCEWORK(rnwdata)-
>nonce)) {
applog(LOG_DEBUG, "%s: renonceworker_thr: restored renonce:
nonce: [%08x]",
bitfury->drv->name,
RENONCEWORK(rnwdata)->nonce);

submit_tested_work(info->thr, &RENONCE(rdata)->cwork.work);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time = time(NULL);

if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count > 0) {
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count = 0;

#ifdef FILELOG
filelog(info, "BF16: good nonce for renonce chip [%d:%d:
%2d] "
"setting recovery_count to 0, error_rate:
[%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}

increase_re_good_nonces(info, RENONCE(rdata)->src_address);
increase_re_good_nonces(info, renonce_chip_address[board_id]);

mutex_lock(&info->nonces_good_lock);
info->nonces_good_cg++;
mutex_unlock(&info->nonces_good_lock);

RENONCE(rdata)->match = true;
} else {
time_t curr_time = time(NULL);
time_t time_diff = curr_time - info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_nonce_time;

if ((time_diff >= RENONCE_CHIP_FAILING_INTERVAL) &&


(info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status < FAILING)) {
increase_errors(info, renonce_chip_address[board_id]);

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status = FAILING;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].last_error_time = curr_time;

applog(LOG_ERR, "%s: nonceworker_thr: renonce chip [%d:%d:


%2d] "
"failed: no good nonces during last [%.1f]
seconds",
bitfury->drv->name,
board_id, bcm250_id, chip_id,
RENONCE_CHIP_FAILING_INTERVAL);
#ifdef FILELOG
filelog(info, "BF16: no good nonces from renonce chip [%d:
%d:%2d], "
"error count: [%d] recovery_count: [%d],
error_rate: [%d]",
board_id, bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].errors,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].recovery_count,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].error_rate);
#endif
}
}
}

return RENONCE(rdata)->match;
}

static void *bitfury_renonceworker(void *userdata)


{
struct cgpu_info *bitfury = (struct cgpu_info *)userdata;
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);
bf_list_t* id_list = nonce_list_init();

applog(LOG_INFO, "%s: started renonceworker thread", bitfury->drv->name);

while (bitfury->shutdown == false) {


if (info->initialised) {
break;
}
cgsleep_us(30);
}

applog(LOG_INFO, "%s: renonceworker loop started", bitfury->drv->name);

while (bitfury->shutdown == false) {


struct timeval start_time, stop_time;
gettimeofday(&start_time, NULL);

uint32_t nonce_cnt = 0;

/* renonce chip results processing */


L_LOCK(info->renoncework_list);
bf_data_t* rnwdata = info->renoncework_list->head;
while (rnwdata != NULL) {
nonce_cnt++;

/* find nonce by id */
L_LOCK(info->renonce_list);
bf_data_t* rdata = info->renonce_list->head;
while (rdata != NULL) {
if (match_nonce(RENONCEWORK(rnwdata)->nonce,
RENONCE(rdata)->nonce, mask_bits)) {
if (RENONCE(rdata)->match == false) {
switch (RENONCE(rdata)->stage) {
case RENONCE_STAGE0:
if (test_renonce(bitfury, rdata,
rnwdata, true) == true)
info->stage0_match++;
else
info->stage0_mismatch++;
break;
case RENONCE_STAGE1:
case RENONCE_STAGE2:
case RENONCE_STAGE3:
/* test old work first */
if (test_renonce(bitfury, rdata,
rnwdata, true) == true) {
if (RENONCE(rdata)->stage ==
RENONCE_STAGE1)
info->stage1_mismatch++;

if (RENONCE(rdata)->stage ==
RENONCE_STAGE2)
info->stage2_match++;

if (RENONCE(rdata)->stage ==
RENONCE_STAGE3)
info->stage3_mismatch++;
} else {
if (test_renonce(bitfury,
rdata, rnwdata, false) == true) {
if (RENONCE(rdata)-
>stage == RENONCE_STAGE1)
info-
>stage1_match++;

if (RENONCE(rdata)-
>stage == RENONCE_STAGE2)
info-
>stage2_mismatch++;

if (RENONCE(rdata)-
>stage == RENONCE_STAGE3)
info-
>stage3_match++;
}
}
break;
default:
applog(LOG_ERR, "%s:
renonceworker_thr: invalid renonce stage arrived: [%d]",
bitfury->drv->name,
RENONCE(rdata)->stage);
}
}
nonce_list_push(id_list, RENONCE(rdata)->id);

if (RENONCE(rdata)->match == true)
break;
}

rdata = rdata->next;
}
L_UNLOCK(info->renonce_list);

/* remove nonce from list */


renoncework_list_pop(info->renoncework_list);
rnwdata = info->renoncework_list->head;
}
L_UNLOCK(info->renoncework_list);

L_LOCK(info->renonce_list);
bf_data_t* rdata = info->renonce_list->head;
while (rdata != NULL) {
if (RENONCE(rdata)->match == true) {
bf_data_t* rndata = rdata->next;
renonce_list_remove(info->renonce_list, rdata);
rdata = rndata;
continue;
}

/* update stage */
bf_data_t* ndata = id_list->head;
while (ndata != NULL) {
if (NONCE(ndata)->nonce == RENONCE(rdata)->id) {
RENONCE(rdata)->stage++;
RENONCE(rdata)->sent = false;
RENONCE(rdata)->received = false;
break;
}
ndata = ndata->next;
}

/* update tasks with wrong or dup nonces recieved */


if ((RENONCE(rdata)->stage != RENONCE_STAGE_FINISHED) &&
(RENONCE(rdata)->received == true)) {
RENONCE(rdata)->stage++;
RENONCE(rdata)->sent = false;
RENONCE(rdata)->received = false;
}

/* clear renonces list if we are running too slow */


if ((RENONCE(rdata)->stage >= RENONCE_STAGE2) &&
(info->renonce_list->count > RENONCE_STAGE2_LIMIT)) {
info->unmatched++;
increase_re_bad_nonces(info, RENONCE(rdata)->src_address);
bf_data_t* rndata = rdata->next;
renonce_list_remove(info->renonce_list, rdata);
rdata = rndata;
continue;
}

if ((RENONCE(rdata)->stage >= RENONCE_STAGE3) &&


(info->renonce_list->count > RENONCE_STAGE3_LIMIT)) {
info->unmatched++;
increase_re_bad_nonces(info, RENONCE(rdata)->src_address);
bf_data_t* rndata = rdata->next;
renonce_list_remove(info->renonce_list, rdata);
rdata = rndata;
continue;
}
if ((RENONCE(rdata)->stage == RENONCE_STAGE_FINISHED) &&
(RENONCE(rdata)->sent == false)) {
info->unmatched++;
increase_re_bad_nonces(info, RENONCE(rdata)->src_address);
bf_data_t* rndata = rdata->next;
renonce_list_remove(info->renonce_list, rdata);
rdata = rndata;
continue;
}

rdata = rdata->next;
}
L_UNLOCK(info->renonce_list);

/* clear id list */
bf_data_t* ndata = id_list->head;
while (ndata != NULL) {
nonce_list_pop(id_list);
ndata = id_list->head;
}

gettimeofday(&stop_time, NULL);

#if 0
applog(LOG_DEBUG, "%s: renonceworker_thr: nonces processed [%d]: time
elapsed: [%.6f]",
bitfury->drv->name,
nonce_cnt, timediff(start_time, stop_time));
#endif

cgsleep_us(RENONCEWORKER_DELAY);
}

applog(LOG_INFO, "%s: renonceworker_thr: exiting...", bitfury->drv->name);


return NULL;
}

int16_t update_pid(bf_pid_t *pid, int16_t error)


{
int16_t pTerm, iTerm;

pTerm = 2 * error;

pid->i_state += error;
if(pid->i_state > pid->i_max)
pid->i_state = pid->i_max;
else if(pid->i_state < pid->i_min)
pid->i_state = pid->i_min;

iTerm = pid->i_state;

return (pTerm + iTerm);


}

static void *bitfury_hwmonitor(void *userdata)


{
struct cgpu_info *bitfury = (struct cgpu_info *)userdata;
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);
uint8_t board_id, bcm250_id, chip_id;
time_t curr_time;

applog(LOG_INFO, "%s: started hwmonitor thread", bitfury->drv->name);

while (bitfury->shutdown == false) {


if (info->initialised) {
break;
}
cgsleep_us(30);
}

applog(LOG_INFO, "%s: hwmonitor loop started", bitfury->drv->name);

while (bitfury->shutdown == false) {


float max_temp = 0.0;
float t_alarm = 100.0;

bool a_temp = false;


bool a_ichain = false;
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
/* read hw sensor data */
char buff[256];

if (info->chipboard[board_id].detected == true) {
memset(buff, 0, sizeof(buff));
if (device_uart_txrx(board_id + 1, "S", buff) < 0)
quit(1, "%s: %s() failed to get BOARD%d status",
bitfury->drv->name, __func__, board_id + 1);

if (parse_hwstats(info, board_id, buff) < 0)


applog(LOG_ERR, "%s: failed to parse hw stats",
bitfury->drv->name);

info->chipboard[board_id].p_chain1 = info-
>chipboard[board_id].u_chain1 * info->chipboard[board_id].i_chain1;
info->chipboard[board_id].p_chain2 = info-
>chipboard[board_id].u_chain2 * info->chipboard[board_id].i_chain2;

/* fan power calculation */


if (info->chipboard[board_id].rpm != 0) {
if (info->chipboard[board_id].fan_speed > 40)
info->chipboard[board_id].p_fan = (0.1 + 0.0236
* (info->chipboard[board_id].fan_speed - 40)) *
(info->chipboard[board_id].u_board +
U_LOSS);
else
info->chipboard[board_id].p_fan = 1.23;
} else {
info->chipboard[board_id].p_fan = 0.0;
}

/* board power calculation */


#ifdef MINER_X5
float i_board = info->chipboard[board_id].i_chain1;
#endif

#ifdef MINER_X6
float i_board = info->chipboard[board_id].i_chain1 + info-
>chipboard[board_id].i_chain2;
#endif
info->chipboard[board_id].p_board = ((info-
>chipboard[board_id].u_board + U_LOSS) * i_board + 2.0 +
info->chipboard[board_id].p_fan);

if (info->chipboard[board_id].a_temp == 1)
a_temp = true;

if ((info->chipboard[board_id].a_ichain1 == 1) ||
(info->chipboard[board_id].a_ichain2 == 1))
a_ichain = true;

if (max_temp < info->chipboard[board_id].temp)


max_temp = info->chipboard[board_id].temp;

if (t_alarm > info->chipboard[board_id].t_alarm)


t_alarm = info->chipboard[board_id].t_alarm;
}
}

/* enable temp alarm */


if ((a_temp == true) && (info->a_temp == false)) {
applog(LOG_ERR, "%s: temperature alarm enabled: [%5.1f]!!!",
bitfury->drv->name, max_temp);

/* enable fans to full speed*/


for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if (info->chipboard[board_id].detected == true) {
if (device_uart_transfer(board_id + 1, "F:100") < 0)
quit(1, "%s: %s() failed to set BOARD%d fan
speed",
bitfury->drv->name, __func__,
board_id + 1);

applog(LOG_INFO, "%s: set BOARD%d fan speed to max


speed",
bitfury->drv->name, board_id + 1);
}
}
}

/* temp alarm recovery */


if ((a_temp == false) && (info->a_temp == true)) {
applog(LOG_ERR, "%s: temperature alarm recovery: [%5.1f]",
bitfury->drv->name, max_temp);

/* restore fans speed */


set_fan_speed(bitfury);

reinit_x5(info, false);
}

/* enable power chain alarm */


if ((a_ichain == true) && (info->a_ichain == false)) {
applog(LOG_ERR, "%s: power chain alarm enabled!!!",
bitfury->drv->name);
info->ialarm_start = time(NULL);
}

/* power chain alarm recovery */


if ((a_ichain == false) && (info->a_ichain == true)) {
if (info->ialarm_count > 1) {
applog(LOG_ERR, "%s: power chain alarm recovery",
bitfury->drv->name);

info->ialarm_count = 1;
info->ialarm_buzzer = false;
info->ialarm_start = time(NULL);

reinit_x5(info, false);
}
}

info->a_temp = a_temp;
info->a_ichain = a_ichain;

if (info->a_temp == true)
applog(LOG_ERR, "%s: ALARM: board temp: [%5.1f] alarm temp:
[%5.1f]",
bitfury->drv->name, max_temp, t_alarm);

if (info->a_ichain == true) {
curr_time = time(NULL);

if (curr_time - info->ialarm_start >= info->ialarm_count *


ICHAIN_ALARM_INTERVAL) {
info->ialarm_count *= 2;
info->ialarm_start = curr_time;

/* enable power chain */


for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
enable_power_chain(bitfury, board_id, 0);
#ifdef MINER_X5
info->chipboard[board_id].power_enable_time =
curr_time;
#endif
#ifdef MINER_X6
info->chipboard[board_id].power1_enable_time =
curr_time;
info->chipboard[board_id].power2_enable_time =
curr_time;
#endif
}
}
} else if (opt_bf16_power_management_disabled == false) {
if (info->a_net == true) {
/* disable power chain if no internet available */
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if (info->chipboard[board_id].detected == true) {
#ifdef MINER_X5
if (info->chipboard[board_id].p_chain1_enabled
== 1) {
#endif
#ifdef MINER_X6
if ((info->chipboard[board_id].p_chain1_enabled
== 1) ||
(info-
>chipboard[board_id].p_chain2_enabled == 1)) {
#endif
disable_power_chain(bitfury, board_id,
0);
}
}
}
} else {
/* enable power chain - internet recovery */
bool recovery = false;
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if (info->chipboard[board_id].detected == true) {
#ifdef MINER_X5
if ((info->chipboard[board_id].p_chain1_enabled
== 0) &&
(info->chipboard[board_id].power_disabled
== false)) {
enable_power_chain(bitfury, board_id, 0);
info-
>chipboard[board_id].power_enable_time = time(NULL);

/* wait for power chain to enable */


cgsleep_us(POWER_WAIT_INTERVAL);

reinit_x5(info, false);
}
#endif

#ifdef MINER_X6
if ((info->chipboard[board_id].p_chain1_enabled
== 0) &&
(info-
>chipboard[board_id].power1_disabled == false)){
enable_power_chain(bitfury, board_id, 1);
info-
>chipboard[board_id].power1_enable_time = time(NULL);
recovery = true;
}

if ((info->chipboard[board_id].p_chain2_enabled
== 0) &&
(info-
>chipboard[board_id].power2_disabled == false)) {
enable_power_chain(bitfury, board_id, 2);
info-
>chipboard[board_id].power2_enable_time = time(NULL);
recovery = true;
}
#endif
}
}

/* reinit chips on alarm recovery */


if (recovery == true) {
/* wait for power chain to enable */
cgsleep_us(POWER_WAIT_INTERVAL);

reinit_x5(info, false);
}
}
}

/* board temperature regulation */


char uart_cmd[8];
if (manual_pid_enabled == false) {
sprintf(uart_cmd, "N:%d", (int)max_temp);
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if (info->chipboard[board_id].detected == true) {
if (device_uart_transfer(board_id + 1, uart_cmd) < 0)
quit(1, "%s: %s() failed to set BOARD%d next
temp",
bitfury->drv->name, __func__,
board_id + 1);

applog(LOG_INFO, "%s: set BOARD%d next temp to


[%5.1f]",
bitfury->drv->name, board_id + 1,
max_temp);
}
}
} else {
uint8_t max_fan_speed = 0;
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if (info->chipboard[board_id].detected == true) {
uint16_t pid_temp = 10 * info-
>chipboard[board_id].temp;
if (10 * max_temp > pid_temp)
pid_temp = 10 * max_temp;

int16_t fan_speed = update_pid(&info-


>chipboard[board_id].pid,
(pid_temp - 10 * info-
>chipboard[board_id].target_temp) / 10);

if (fan_speed > 100)


fan_speed = 100;
else if (fan_speed < 0)
fan_speed = 0;

if (max_fan_speed < fan_speed)


max_fan_speed = fan_speed;
}
}

sprintf(uart_cmd, "F:%d", max_fan_speed);


for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if (info->chipboard[board_id].detected == true) {
if (device_uart_transfer(board_id + 1, uart_cmd) < 0)
quit(1, "%s: %s() failed to set BOARD%d fan
speed",
bitfury->drv->name, __func__,
board_id + 1);

applog(LOG_INFO, "%s: set BOARD%d fan speed to [%d]",


bitfury->drv->name, board_id + 1,
max_fan_speed);
}
}
}

/* board power management */


if (opt_bf16_power_management_disabled == false) {
curr_time = time(NULL);

for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {


if (info->chipboard[board_id].detected == true) {
#ifdef MINER_X5
uint8_t disabled_chips = 0;
uint8_t total_chips = 0;
#endif

#ifdef MINER_X6
uint8_t disabled_chips_chain1 = 0;
uint8_t total_chips_chain1 = 0;
uint8_t disabled_chips_chain2 = 0;
uint8_t total_chips_chain2 = 0;
#endif
for (bcm250_id = 0; bcm250_id < BCM250_NUM;
bcm250_id++) {
uint8_t first_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
uint8_t last_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].last_good_chip;

/* chips loop */
for (chip_id = first_good_chip; chip_id <
last_good_chip; chip_id++) {
#ifdef MINER_X5
total_chips++;

if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status == DISABLED)
disabled_chips++;
#endif

#ifdef MINER_X6
if (bcm250_id < BCM250_NUM / 2) {
total_chips_chain1++;

if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status == DISABLED)
disabled_chips_chain1++;
}

if ((bcm250_id >= BCM250_NUM / 2) &&


(bcm250_id < BCM250_NUM)) {
total_chips_chain2++;

if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status == DISABLED)
disabled_chips_chain2++;
}
#endif
}
}
#ifdef MINER_X5
/* disable chain power if all chips failed */
if ((total_chips == disabled_chips) &&
(info->chipboard[board_id].p_chain1_enabled ==
1)) {
disable_power_chain(bitfury, board_id, 0);

/* increase disable counter until we reach long


enough work time */
time_t work_interval = curr_time - info-
>chipboard[board_id].power_enable_time;
if (work_interval < CHAIN_WORK_INTERVAL)
info-
>chipboard[board_id].power_disable_count *= 2;

info->chipboard[board_id].power_disabled =
true;
info->chipboard[board_id].power_disable_time =
curr_time;
info->chipboard[board_id].chips_disabled =
info->chipboard[board_id].chips_num;
}

/* enable disabled chain */


if ((info->chipboard[board_id].p_chain1_enabled == 0)
&&
(info->chipboard[board_id].power_disabled ==
true) &&
(curr_time - info-
>chipboard[board_id].power_disable_time >= info-
>chipboard[board_id].power_disable_count * CHAIN_REENABLE_INTERVAL)) {
time_t disable_interval = curr_time - info-
>chipboard[board_id].power_disable_time;
info->chipboard[board_id].power_disable_time =
curr_time;
info->chipboard[board_id].chips_disabled =
0;

enable_power_chain(bitfury, board_id, 0);


info->chipboard[board_id].power_enable_time =
curr_time;
info->chipboard[board_id].power_disabled =
false;

/* wait for power chain to enable */


cgsleep_us(POWER_WAIT_INTERVAL);

reinit_x5(info, true);
applog(LOG_NOTICE, "%s: reenabled power on
BOARD%d: time interval [%d]",
bitfury->drv->name,
board_id + 1,
(int)disable_interval);
#ifdef FILELOG
filelog(info, "%s: reenabled power on BOARD%d:
time interval [%d]",
bitfury->drv->name,
board_id + 1,
(int)disable_interval);
#endif
}
#endif

#ifdef MINER_X6
/* disable power on chain 1 only if chips on both
chains failed
* as chain 2 data channel depends on chain 1
*/
if ((total_chips_chain1 == disabled_chips_chain1) &&
(info->chipboard[board_id].p_chain1_enabled ==
1) &&
(info->chipboard[board_id].power2_disabled ==
true)) {
disable_power_chain(bitfury, board_id, 0);

/* increase disable counter until we reach long


enough work time */
time_t work_interval = curr_time - info-
>chipboard[board_id].power1_enable_time;
if (work_interval < CHAIN_WORK_INTERVAL)
info-
>chipboard[board_id].power1_disable_count *= 2;

info->chipboard[board_id].power1_disabled =
true;
info->chipboard[board_id].power2_disabled =
true;
info->chipboard[board_id].power1_disable_time =
curr_time;
info->chipboard[board_id].power2_disable_time =
curr_time;
info->chipboard[board_id].chips_disabled =
info->chipboard[board_id].chips_num;
} else
if ((total_chips_chain2 == disabled_chips_chain2) &&
(info->chipboard[board_id].p_chain2_enabled ==
1)) {
disable_power_chain(bitfury, board_id, 2);

/* increase disable counter until we reach long


enough work time */
time_t work_interval = curr_time - info-
>chipboard[board_id].power2_enable_time;
if (work_interval < CHAIN_WORK_INTERVAL)
info-
>chipboard[board_id].power2_disable_count *= 2;

info->chipboard[board_id].power2_disabled =
true;
info->chipboard[board_id].power2_disable_time =
curr_time;
info->chipboard[board_id].chips_disabled =
info->chipboard[board_id].chips_num / 2;
}

/* HW FIX: try to reenable disabled chain */


if ((info->chipboard[board_id].p_chain1_enabled == 0)
&&
(info->chipboard[board_id].power1_disabled ==
true) &&
(curr_time - info-
>chipboard[board_id].power1_disable_time >= info-
>chipboard[board_id].power1_disable_count * CHAIN_REENABLE_INTERVAL)) {
time_t disable_interval = curr_time - info-
>chipboard[board_id].power1_disable_time;
info->chipboard[board_id].power1_disable_time =
curr_time;
info->chipboard[board_id].power2_disable_time =
curr_time;
info->chipboard[board_id].chips_disabled =
0;

enable_power_chain(bitfury, board_id, 0);


info->chipboard[board_id].power1_enable_time =
curr_time;
info->chipboard[board_id].power2_enable_time =
curr_time;
info->chipboard[board_id].power1_disabled =
false;
info->chipboard[board_id].power2_disabled =
false;

/* wait for power chain to enable */


cgsleep_us(POWER_WAIT_INTERVAL);

reinit_x5(info, true);
applog(LOG_NOTICE, "%s: reenabled power on
BOARD%d: time interval [%d]",
bitfury->drv->name,
board_id + 1,
(int)disable_interval);
#ifdef FILELOG
filelog(info, "%s: reenabled power on BOARD%d:
time interval [%d]",
bitfury->drv->name,
board_id + 1,
(int)disable_interval);
#endif

} else
if ((info->chipboard[board_id].p_chain2_enabled == 0)
&&
(info->chipboard[board_id].power2_disabled ==
true) &&
(curr_time - info-
>chipboard[board_id].power2_disable_time >= info-
>chipboard[board_id].power2_disable_count * CHAIN_REENABLE_INTERVAL)) {
time_t disable_interval = curr_time - info-
>chipboard[board_id].power2_disable_time;
info->chipboard[board_id].power2_disable_time =
curr_time;
info->chipboard[board_id].chips_disabled =
0;

enable_power_chain(bitfury, board_id, 2);


info->chipboard[board_id].power2_enable_time =
curr_time;
info->chipboard[board_id].power2_disabled =
false;

/* wait for power chain to enable */


cgsleep_us(POWER_WAIT_INTERVAL);

reinit_x5(info, true);
applog(LOG_NOTICE, "%s: reenabled chainboard 2
on BOARD%d: time interval [%d]",
bitfury->drv->name,
board_id + 1,
(int)disable_interval);
#ifdef FILELOG
filelog(info, "%s: reenabled chainboard 2 on
BOARD%d: time interval [%d]",
bitfury->drv->name,
board_id + 1,
(int)disable_interval);
#endif
}
#endif
/* switch renonce chip to next board */
if ((info->renonce_chips == 1) &&
(renonce_chip_address[board_id].board_id ==
board_id) &&
#ifdef MINER_X5
(info->chipboard[board_id].power_disabled ==
true)) {
#endif
#ifdef MINER_X6
(info->chipboard[board_id].power1_disabled ==
true) &&
(info->chipboard[board_id].power2_disabled ==
true)) {
#endif
uint8_t next_board_id = (board_id + 1) %
CHIPBOARD_NUM;
uint8_t next_bcm250_id =
renonce_chip_address[board_id].bcm250_id;
uint8_t next_chip_id =
renonce_chip_address[board_id].chip_id;

/* board id should be set last */


renonce_chip_address[next_board_id].bcm250_id =
next_bcm250_id;
renonce_chip_address[next_board_id].chip_id =
next_chip_id;
renonce_chip_address[next_board_id].board_id =
next_board_id;

info-
>chipboard[next_board_id].bcm250[next_bcm250_id].chips[next_chip_id].status =
UNINITIALIZED;

applog(LOG_NOTICE, "%s: changed renonce chip


address to: [%d:%d:%2d]",
bitfury->drv->name,
next_board_id, next_bcm250_id,
next_chip_id);
renonce_chip_address[board_id].board_id = -1;
renonce_chip_address[board_id].bcm250_id = -1;
renonce_chip_address[board_id].chip_id = -1;
}
}
}
}

cgsleep_us(HWMONITOR_DELAY);
}

applog(LOG_INFO, "%s: hwmonitor_thr: exiting...", bitfury->drv->name);


return NULL;
}

static void *bitfury_alarm(void *userdata)


{
struct cgpu_info *bitfury = (struct cgpu_info *)userdata;
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);

struct pool *pool;


int i;
time_t curr_time_t;
struct timeval curr_time;

applog(LOG_INFO, "%s: started alarm thread", bitfury->drv->name);

/* blink lamps once */


led_red_enable(info);
led_green_enable(info);

cgsleep_ms(1000);

led_red_disable(info);
led_green_disable(info);
buzzer_disable(info);

applog(LOG_INFO, "%s: alarm loop started", bitfury->drv->name);

while (bitfury->shutdown == false) {


curr_time_t = time(NULL);
gettimeofday(&curr_time, NULL);
/* check if there are enabled pools present */
bool idle = true;
for (i = 0; i < total_pools; i++) {
pool = pools[i];
if (pool->idle == false)
idle = false;
}

if (idle == true)
info->a_net = true;
else
info->a_net = false;

/* temperature alarm processing */


if ((info->a_temp == true) && (info->a_ichain == false)) {
if (timediff_us(info->led_red_switch, curr_time) >=
LED_RED_INTERVAL) {
if (info->led_red_enabled == true)
led_red_disable(info);
else
led_red_enable(info);
}

/* enable buzzer */
if (timediff_us(info->buzzer_switch, curr_time) >=
BUZZER_INTERVAL) {
if (info->buzzer_enabled == true)
buzzer_disable(info);
else
buzzer_enable(info);
}
} else if ((info->a_ichain == false) && (info->a_net == false)) {
if (info->led_red_enabled == true)
led_red_disable(info);

if (info->buzzer_enabled == true)
buzzer_disable(info);
}

/* power chain alarm processing */


if ((info->a_ichain == true) && (info->a_temp == false)) {
if (timediff_us(info->led_red_switch, curr_time) >=
LED_RED_INTERVAL) {
if (info->led_red_enabled == true)
led_red_disable(info);
else
led_red_enable(info);
}

if (info->ialarm_buzzer == false) {
buzzer_enable(info);
cgsleep_ms(1000);
buzzer_disable(info);

info->ialarm_buzzer = true;
}

/* enable buzzer */
if (curr_time_t - info->ialarm_start >= info->ialarm_count *
ICHAIN_ALARM_INTERVAL) {
buzzer_enable(info);
cgsleep_ms(1000);
buzzer_disable(info);
}
} else if ((info->a_temp == false) && (info->a_net == false)) {
if (info->led_red_enabled == true)
led_red_disable(info);

if (info->buzzer_enabled == true)
buzzer_disable(info);
}

/* blink green lamp if there are enabled pools present and no alarms
active */
if ((info->a_net == false) && (info->a_temp == false) && (info-
>a_ichain == false)) {
if (info->led_red_enabled == true)
led_red_disable(info);

if (timediff_us(info->led_green_switch, curr_time) >=


LED_GREEN_INTERVAL) {
if (info->led_green_enabled == true)
led_green_disable(info);
else
led_green_enable(info);
}
} else {
if (info->led_green_enabled == true)
led_green_disable(info);

if ((info->a_temp == false) && (info->a_ichain == false)) {


if (timediff_us(info->led_red_switch, curr_time) >=
LED_RED_NET_INTERVAL) {
if (info->led_red_enabled == true)
led_red_disable(info);
else
led_red_enable(info);
}
}
}

cgsleep_us(ALARM_DELAY);
}

led_red_disable(info);
led_green_disable(info);
buzzer_disable(info);

applog(LOG_INFO, "%s: alarm_thr: exiting...", bitfury->drv->name);


return NULL;
}

static void *bitfury_statistics(void *userdata)


{
struct cgpu_info *bitfury = (struct cgpu_info *)userdata;
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);

struct timeval start_time, stop_time;


uint8_t board_id, bcm250_id, chip_id;

float u_board;
float i_total;
float p_total;
float u_chip;
float p_chip;

time_t time0 = time(NULL);


time_t time1 = time(NULL);
time_t time2;

/* statistics calculation loop */


while (bitfury->shutdown == false) {
time2 = time(NULL);
if (time2 - time1 >= AVG_TIME_DELTA) {
gettimeofday(&start_time, NULL);

u_board = 0.0;
i_total = 0.0;
p_total = 0.0;
u_chip = 0.0;
p_chip = 0.0;

info->chips_failed = 0;
info->chips_disabled = 0;

for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {


if (info->chipboard[board_id].detected == true) {
info->chipboard[board_id].chips_failed = 0;
info->chips_disabled += info-
>chipboard[board_id].chips_disabled;

/* concentrator loop */
for (bcm250_id = 0; bcm250_id < BCM250_NUM;
bcm250_id++) {
uint8_t first_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
uint8_t last_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].last_good_chip;

info-
>chipboard[board_id].bcm250[bcm250_id].chips_failed = 0;

/* chips loop */
for (chip_id = first_good_chip; chip_id <
last_good_chip; chip_id++) {

if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status >= FAILING) {
info-
>chipboard[board_id].bcm250[bcm250_id].chips_failed++;
info-
>chipboard[board_id].chips_failed++;
info->chips_failed++;
}

if (opt_bf16_stats_enabled) {
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].task_switch,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].task_switch_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd_none,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd_none_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);

get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);

get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate_good,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_good_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate_diff,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_diff_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate_bad,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_bad_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);

if (opt_bf16_renonce !=
RENONCE_DISABLED) {
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate_re,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_re_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate_re_good,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_re_good_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate_re_bad,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_re_bad_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);
}
}
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].task_switch_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd_none_dx = 0;

info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_good_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_diff_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_bad_dx = 0;

if (opt_bf16_renonce != RENONCE_DISABLED)
{
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_re_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_re_good_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces_re_bad_dx = 0;
}

if (opt_bf16_stats_enabled) {
if (opt_bf16_renonce !=
RENONCE_DISABLED)
applog(LOG_NOTICE, "STATS:
chp [%d:%d:%2d], tsk/s [%4.0f], "
"ncs/s [%4.0f],
sts/s [%3.0f], none/s [%3.0f], hr/s [%8.3f] hr+/s [%8.3f] rhr/s [%8.3f]",
board_id,
bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].task_switch,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd_none,
CHIP_COEFF * info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate,
CHIP_COEFF * info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate_good,
CHIP_COEFF *
(info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate_good +

info->chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate_re_good));
else
applog(LOG_NOTICE, "STATS:
chp [%d:%d:%2d], tsk/s [%4.0f], "
"ncs/s [%3.0f],
sts/s [%3.0f], none/s [%3.0f], hr/s [%8.3f] hr+/s [%8.3f]",
board_id,
bcm250_id, chip_id,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].task_switch,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].nonces,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd,
info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status_cmd_none,
CHIP_COEFF * info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate,
CHIP_COEFF * info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].hashrate_good);
}
}

if (opt_bf16_stats_enabled) {
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].task_switch,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].task_switch_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].status_cmd,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].status_cmd_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].status_cmd_none,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].status_cmd_none_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);

get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].nonces,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].nonces_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);

get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].hashrate,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].nonces_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].hashrate_good,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].nonces_good_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].hashrate_diff,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].nonces_diff_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].hashrate_bad,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].nonces_bad_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);

if (opt_bf16_renonce != RENONCE_DISABLED)
{
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].hashrate_re,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].nonces_re_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].hashrate_re_good,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].nonces_re_good_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].bcm250[bcm250_id].hashrate_re_bad,
(float)info-
>chipboard[board_id].bcm250[bcm250_id].nonces_re_bad_dx,
(float)(time2 -
time1), AVG_TIME_INTERVAL);
}
}

info-
>chipboard[board_id].bcm250[bcm250_id].task_switch_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].status_cmd_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].status_cmd_none_dx = 0;

info-
>chipboard[board_id].bcm250[bcm250_id].nonces_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].nonces_good_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].nonces_diff_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].nonces_bad_dx = 0;

if (opt_bf16_renonce != RENONCE_DISABLED) {
info-
>chipboard[board_id].bcm250[bcm250_id].nonces_re_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].nonces_re_good_dx = 0;
info-
>chipboard[board_id].bcm250[bcm250_id].nonces_re_bad_dx = 0;
}
}

if (opt_bf16_stats_enabled) {
get_average(&info-
>chipboard[board_id].task_switch,
(float)info-
>chipboard[board_id].task_switch_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].status_cmd,
(float)info-
>chipboard[board_id].status_cmd_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].status_cmd_none,
(float)info-
>chipboard[board_id].status_cmd_none_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);

get_average(&info->chipboard[board_id].nonces,
(float)info-
>chipboard[board_id].nonces_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
}

get_average(&info->chipboard[board_id].hashrate,
(float)info-
>chipboard[board_id].nonces_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info->chipboard[board_id].hashrate_good,
(float)info-
>chipboard[board_id].nonces_good_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info->chipboard[board_id].hashrate_diff,
(float)info-
>chipboard[board_id].nonces_diff_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info->chipboard[board_id].hashrate_bad,
(float)info-
>chipboard[board_id].nonces_bad_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);

info->chipboard[board_id].task_switch_dx = 0;
info->chipboard[board_id].status_cmd_dx = 0;
info->chipboard[board_id].status_cmd_none_dx = 0;

info->chipboard[board_id].nonces_dx = 0;
info->chipboard[board_id].nonces_good_dx = 0;
info->chipboard[board_id].nonces_diff_dx = 0;
info->chipboard[board_id].nonces_bad_dx = 0;

u_board += (info->chipboard[board_id].u_board
+ U_LOSS);
#ifdef MINER_X5
i_total += (info-
>chipboard[board_id].i_chain1);
u_chip += (info-
>chipboard[board_id].u_chain1);
p_chip += (info-
>chipboard[board_id].p_chain1);
#endif

#ifdef MINER_X6
i_total += (info->chipboard[board_id].i_chain1
+ info->chipboard[board_id].i_chain2);
u_chip += (info->chipboard[board_id].u_chain1
+ info->chipboard[board_id].u_chain2);
p_chip += (info->chipboard[board_id].p_chain1
+ info->chipboard[board_id].p_chain2);
#endif
p_total += info->chipboard[board_id].p_board;

if (opt_bf16_renonce != RENONCE_DISABLED) {
get_average(&info-
>chipboard[board_id].hashrate_re,
(float)info-
>chipboard[board_id].nonces_re_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].hashrate_re_good,
(float)info-
>chipboard[board_id].nonces_re_good_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);
get_average(&info-
>chipboard[board_id].hashrate_re_bad,
(float)info-
>chipboard[board_id].nonces_re_bad_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);

info->chipboard[board_id].nonces_re_dx =
0;
info->chipboard[board_id].nonces_re_good_dx =
0;
info->chipboard[board_id].nonces_re_bad_dx =
0;
}

get_average(&info->chipboard[board_id].txrx_speed,
(float)info-
>chipboard[board_id].bytes_transmitted_dx,
(float)(time2 - time1),
AVG_TIME_INTERVAL);

info->chipboard[board_id].bytes_transmitted_dx = 0;

if (opt_bf16_stats_enabled) {
if (opt_bf16_renonce != RENONCE_DISABLED) {
applog(LOG_NOTICE, "STATS: board [%d]
hrate: good: [%8.3f] re_good: [%8.3f] => "
"[%8.3f] toren: [%8.3f] bad:
[%8.3f] total: [%8.3f]",
board_id,
CHIP_COEFF * (info-
>chipboard[board_id].hashrate_good),
CHIP_COEFF * (info-
>chipboard[board_id].hashrate_re_good),
CHIP_COEFF * (info-
>chipboard[board_id].hashrate_good + info->chipboard[board_id].hashrate_re_good),
CHIP_COEFF * (info-
>chipboard[board_id].hashrate - info->chipboard[board_id].hashrate_good),
CHIP_COEFF * (info-
>chipboard[board_id].hashrate_bad),
CHIP_COEFF * (info-
>chipboard[board_id].hashrate));
} else {
applog(LOG_NOTICE, "STATS: board [%d]
hrate: good: [%8.3f] "
"bad: [%8.3f] total:
[%8.3f]",
board_id,
CHIP_COEFF * (info-
>chipboard[board_id].hashrate_good),
CHIP_COEFF * (info-
>chipboard[board_id].hashrate_bad),
CHIP_COEFF * (info-
>chipboard[board_id].hashrate));
}

#ifdef MINER_X5
applog(LOG_NOTICE, "STATS: TX/RX: [%5.3f]
Mbit/s UB: [%3.1f] "
"U1: [%3.1f] I1: [%3.1f] T: [%3.1f]
RPM: [%4d] FAN: [%3d]",
8.0 * info-
>chipboard[board_id].txrx_speed / 1000000,
info->chipboard[board_id].u_board +
U_LOSS,
info->chipboard[board_id].u_chain1,
info->chipboard[board_id].i_chain1,
info->chipboard[board_id].temp,
info->chipboard[board_id].rpm,
info-
>chipboard[board_id].fan_speed);
#endif

#ifdef MINER_X6
applog(LOG_NOTICE, "STATS: TX/RX: [%5.3f]
Mbit/s UB: [%3.1f] "
"U1: [%3.1f] U2: [%3.1f] I1:
[%3.1f] I2: [%3.1f] T: [%3.1f] RPM: [%4d] FAN: [%3d]",
8.0 * info-
>chipboard[board_id].txrx_speed / 1000000,
info->chipboard[board_id].u_board +
U_LOSS,
info->chipboard[board_id].u_chain1,
info->chipboard[board_id].u_chain2,
info->chipboard[board_id].i_chain1,
info->chipboard[board_id].i_chain2,
info->chipboard[board_id].temp,
info->chipboard[board_id].rpm,
info-
>chipboard[board_id].fan_speed);
#endif

applog(LOG_NOTICE, "STATS: ver: [%d] fw: [%d]


hwid: [%s]",
info-
>chipboard[board_id].board_ver,
info-
>chipboard[board_id].board_fwver,
info-
>chipboard[board_id].board_hwid);
}
}
}

if (opt_bf16_stats_enabled) {
get_average(&info->task_switch,
(float)info->task_switch_dx,
(float)(time2 - time1), AVG_TIME_INTERVAL);
get_average(&info->status_cmd,
(float)info->status_cmd_dx,
(float)(time2 - time1), AVG_TIME_INTERVAL);
get_average(&info->status_cmd_none,
(float)info->status_cmd_none_dx,
(float)(time2 - time1), AVG_TIME_INTERVAL);

get_average(&info->chipboard[board_id].nonces,
(float)info->chipboard[board_id].nonces_dx,
(float)(time2 - time1), AVG_TIME_INTERVAL);
}

get_average(&info->hashrate,
(float)info->nonces_dx,
(float)(time2 - time1), AVG_TIME_INTERVAL);
get_average(&info->hashrate_good,
(float)info->nonces_good_dx,
(float)(time2 - time1), AVG_TIME_INTERVAL);
get_average(&info->hashrate_diff,
(float)info->nonces_diff_dx,
(float)(time2 - time1), AVG_TIME_INTERVAL);
get_average(&info->hashrate_bad,
(float)info->nonces_bad_dx,
(float)(time2 - time1), AVG_TIME_INTERVAL);

info->task_switch_dx = 0;
info->status_cmd_dx = 0;
info->status_cmd_none_dx = 0;

info->nonces_dx = 0;
info->nonces_good_dx = 0;
info->nonces_diff_dx = 0;
info->nonces_bad_dx = 0;

if (opt_bf16_renonce != RENONCE_DISABLED) {
get_average(&info->hashrate_re,
(float)info->nonces_re_dx,
(float)(time2 - time1), AVG_TIME_INTERVAL);
get_average(&info->hashrate_re_good,
(float)info->nonces_re_good_dx,
(float)(time2 - time1), AVG_TIME_INTERVAL);
get_average(&info->hashrate_re_bad,
(float)info->nonces_re_bad_dx,
(float)(time2 - time1), AVG_TIME_INTERVAL);

info->nonces_re_dx = 0;
info->nonces_re_good_dx = 0;
info->nonces_re_bad_dx = 0;
}

time1 = time2;

gettimeofday(&stop_time, NULL);

uint32_t uptime = time2 - time0;


uint32_t hours = uptime / 3600;
uint8_t minutes = (uptime - hours * 3600) / 60;
uint8_t seconds = uptime - hours * 3600 - minutes * 60;

info->u_avg = u_board / info->active_chipboard_num;


info->i_total = i_total;
info->p_total = p_total;
info->u_chip = u_chip;
info->p_chip = p_chip;

if (opt_bf16_stats_enabled) {
if (opt_bf16_renonce != RENONCE_DISABLED) {
applog(LOG_NOTICE, "STATS: rencs: [%d] stale: [%d]
nws: [%d] rnws: [%d] failed: [%d]",
info->renonce_list->count,
info->stale_work_list->count,
info->noncework_list->count,
info->renoncework_list->count,
info->chips_failed);

applog(LOG_NOTICE, "STATS: %4.0fGH/s osc: 0x%02x


re_osc: 0x%02x "
"%3.1fV %3.1fA %4.1fW %.3fW/GH",
CHIP_COEFF * (info->hashrate_good + info-
>hashrate_re_good),
bf16_chip_clock,
bf16_renonce_chip_clock,
info->u_avg,
info->i_total,
info->p_total,
(info->a_net == true) ?
0.0 :
info->p_total / (CHIP_COEFF *
(info->hashrate_good + info->hashrate_re_good)));

applog(LOG_NOTICE, "STATS: TOTAL: %5.1fGH/s %5.3fV


%3.1fA %5.2fW "
"CHIP: %5.1fGH/s GOOD: %4.1fGH/s RENONCE:
%4.1fGH/s BAD: %4.1fGH/s",
CHIP_COEFF * info->hashrate / (info-
>chips_num - info->renonce_chips - info->chips_failed),
info->u_chip / (info->chips_num - info-
>chips_disabled),
(info->a_net == true) ? 0.0 : info-
>p_chip / info->u_chip,
info->p_chip / (info->chips_num - info-
>chips_disabled),
CHIP_COEFF * (info->hashrate_good + info-
>hashrate_re_good) / (info->chips_num - info->renonce_chips - info->chips_failed),
CHIP_COEFF * info->hashrate_good / (info-
>chips_num - info->renonce_chips - info->chips_failed),
CHIP_COEFF * info->hashrate_re_good /
(info->chips_num - info->renonce_chips - info->chips_failed),
CHIP_COEFF * info->hashrate_re_bad /
(info->chips_num - info->renonce_chips - info->chips_failed));

#if 1
applog(LOG_NOTICE, "STATS: m0: [%lu] mm0: [%lu] m1:
[%lu] mm1: [%lu] m2: [%lu] mm2: [%lu] "
"m3: [%lu] mm3: [%lu] um: [%lu]",
info->stage0_match / (time2 - time0),
info->stage0_mismatch / (time2 - time0),
info->stage1_match / (time2 - time0),
info->stage1_mismatch / (time2 - time0),
info->stage2_match / (time2 - time0),
info->stage2_mismatch / (time2 - time0),
info->stage3_match / (time2 - time0),
info->stage3_mismatch / (time2 - time0),
info->unmatched / (time2 - time0));
#endif
} else {
applog(LOG_NOTICE, "STATS: stale: [%d] nws: [%d]",
info->stale_work_list->count, info-
>noncework_list->count);

applog(LOG_NOTICE, "STATS: %4.0fGH/s osc: 0x%02x"


"%3.1fV %3.1fA %4.1fW %.3fW/GH",
CHIP_COEFF * info->hashrate_good,
bf16_chip_clock,
info->u_avg,
info->i_total,
info->p_total,
(info->a_net == true) ?
0.0 :
info->p_total / (CHIP_COEFF * info-
>hashrate_good));

applog(LOG_NOTICE, "STATS: TOTAL: %5.1fGH/s %5.3fV


%3.1fA %5.2fW "
"CHIP: %5.1fGH/s GOOD: %4.1fGH/s BAD:
%4.1fGH/s",
CHIP_COEFF * info->hashrate / (info-
>chips_num - info->chips_failed),
info->u_chip / (info->chips_num - info-
>chips_disabled),
(info->a_net == true) ? 0.0 : info-
>p_chip / info->u_chip,
info->p_chip / (info->chips_num - info-
>chips_disabled),
CHIP_COEFF * info->hashrate_good / (info-
>chips_num - info->chips_failed),
CHIP_COEFF * info->hashrate_good / (info-
>chips_num - info->chips_failed),
CHIP_COEFF * info->hashrate_bad / (info-
>chips_num - info->chips_failed));
}

applog(LOG_NOTICE, "STATS: uptime: [%4d:%02d:%02d] time


elapsed: [%.6f] ",
hours, minutes, seconds, timediff(start_time,
stop_time));
}
}

cgsleep_us(STATISTICS_DELAY);
}

applog(LOG_INFO, "%s: statistics_thr: exiting...", bitfury->drv->name);


return NULL;
}

static bool bitfury16_thread_prepare(struct thr_info *thr)


{
struct cgpu_info *bitfury = thr->cgpu;
struct bitfury16_info *info = (struct bitfury16_info *)(bitfury-
>device_data);

info->thr = thr;

if (thr_info_create(&(info->chipworker_thr), NULL, bitfury_chipworker, (void


*)bitfury)) {
applog(LOG_ERR, "%s: %s() chipworker thread create failed",
bitfury->drv->name, __func__);
return false;
}
pthread_detach(info->chipworker_thr.pth);

applog(LOG_INFO, "%s: thread prepare: starting chipworker thread", bitfury-


>drv->name);

if (thr_info_create(&(info->nonceworker_thr), NULL, bitfury_nonceworker,


(void *)bitfury)) {
applog(LOG_ERR, "%s: %s() nonceworker thread create failed",
bitfury->drv->name, __func__);
return false;
}
pthread_detach(info->nonceworker_thr.pth);

applog(LOG_INFO, "%s: thread prepare: starting nonceworker thread", bitfury-


>drv->name);

if (opt_bf16_renonce != RENONCE_DISABLED) {
if (thr_info_create(&(info->renonceworker_thr), NULL,
bitfury_renonceworker, (void *)bitfury)) {
applog(LOG_ERR, "%s: %s() renonceworker thread create failed",
bitfury->drv->name, __func__);
return false;
}
pthread_detach(info->renonceworker_thr.pth);

applog(LOG_INFO, "%s: thread prepare: starting renonceworker thread",


bitfury->drv->name);
}

if (thr_info_create(&(info->hwmonitor_thr), NULL, bitfury_hwmonitor, (void


*)bitfury)) {
applog(LOG_ERR, "%s: %s() hwmonitor thread create failed",
bitfury->drv->name, __func__);
return false;
}
pthread_detach(info->hwmonitor_thr.pth);

applog(LOG_INFO, "%s: thread prepare: starting hwmonitor thread", bitfury-


>drv->name);

if (thr_info_create(&(info->alarm_thr), NULL, bitfury_alarm, (void


*)bitfury)) {
applog(LOG_ERR, "%s: %s() alarm thread create failed",
bitfury->drv->name, __func__);
return false;
}
pthread_detach(info->alarm_thr.pth);

applog(LOG_INFO, "%s: thread prepare: starting alarm thread", bitfury->drv-


>name);

if (thr_info_create(&(info->statistics_thr), NULL, bitfury_statistics, (void


*)bitfury)) {
applog(LOG_ERR, "%s: %s() statistics thread create failed",
bitfury->drv->name, __func__);
return false;
}
pthread_detach(info->statistics_thr.pth);

applog(LOG_INFO, "%s: thread prepare: starting statistics thread", bitfury-


>drv->name);

return true;
}

static int64_t bitfury16_scanwork(struct thr_info *thr)


{
struct cgpu_info *bitfury = thr->cgpu;
struct bitfury16_info *info = bitfury->device_data;
int64_t hashcount = 0;

applog(LOG_INFO, "%s: scan work", bitfury->drv->name);

mutex_lock(&info->nonces_good_lock);
if (info->nonces_good_cg) {
hashcount += 0xffffffffull * info->nonces_good_cg;
info->nonces_good_cg = 0;
}
mutex_unlock(&info->nonces_good_lock);

return hashcount;
}

static void prepare_work(struct cgpu_info *bitfury, struct work *work, bool rolled)
{
struct bitfury16_info *info = (struct bitfury16_info *)bitfury->device_data;
bf_workd_t* wdata = cgmalloc(sizeof(bf_workd_t));

wdata->work = work;
wdata->rolled = rolled;
wdata->generated = time(NULL);

/* generate task payload */


cg_memcpy(wdata->payload.midstate, work->midstate, 32);
wdata->payload.m7 = *(uint32_t *)(work->data + 64);
wdata->payload.ntime = *(uint32_t *)(work->data + 68);
wdata->payload.nbits = *(uint32_t *)(work->data + 72);

workd_list_push(info->work_list, wdata);
}

static bool bitfury16_queue_full(struct cgpu_info *bitfury)


{
struct bitfury16_info *info = (struct bitfury16_info *)bitfury->device_data;
struct work *work, *usework;
uint16_t need = 0;
uint16_t generated = 0;
uint16_t roll, roll_limit;
bool rolled;

if (info->initialised == false) {
cgsleep_us(30);
return true;
}

L_LOCK(info->work_list);
uint16_t work_count = info->work_list->count;
L_UNLOCK(info->work_list);
if (work_count < WORK_QUEUE_LEN)
need = WORK_QUEUE_LEN - work_count;
else
return true;

/* Ensure we do enough rolling to reduce CPU


but dont roll too much to have them end up stale */
work = get_queued(bitfury);
if (work) {
roll_limit = work->drv_rolllimit;
roll = 0;

L_LOCK(info->work_list);
do {
if (roll == 0) {
usework = work;
rolled = false;
} else {
usework = copy_work_noffset(work, roll);
rolled = true;
}

prepare_work(bitfury, usework, rolled);


generated++;
} while ((--need > 0) && (++roll <= roll_limit));
L_UNLOCK(info->work_list);
applog(LOG_INFO, "%s: queue full: generated %d works", bitfury->drv-
>name, generated);
} else
cgsleep_us(30);

if (need > 0)
return false;
else
return true;
}

static void bitfury16_flush_work(struct cgpu_info *bitfury)


{
struct bitfury16_info *info = (struct bitfury16_info *)bitfury->device_data;
uint16_t flushed = 0;

if (info->initialised == false)
return;

bf_works_t works;

/* flush work list */


L_LOCK(info->work_list);
L_LOCK(info->stale_work_list);
bf_data_t* wdata = info->work_list->head;
while (wdata != NULL) {
workd_list_push(info->stale_work_list, WORKD(wdata));
workd_list_remove(info->work_list, &works);

wdata = info->work_list->head;
flushed++;
}
L_UNLOCK(info->stale_work_list);
L_UNLOCK(info->work_list);

/* flush nonces list */


L_LOCK(info->noncework_list);
bf_data_t* nwdata = info->noncework_list->head;
while (nwdata != NULL) {
noncework_list_pop(info->noncework_list);
nwdata = info->noncework_list->head;
}
L_UNLOCK(info->noncework_list);

if (opt_bf16_renonce != RENONCE_DISABLED) {
/* flush renonces list */
L_LOCK(info->renonce_list);
bf_data_t* rdata = info->renonce_list->head;
while (rdata != NULL) {
renonce_list_pop(info->renonce_list);
rdata = info->renonce_list->head;
}
L_UNLOCK(info->renonce_list);

/* flush renoncework list */


L_LOCK(info->renoncework_list);
bf_data_t* rnwdata = info->renoncework_list->head;
while (rnwdata != NULL) {
renoncework_list_pop(info->renoncework_list);
rnwdata = info->renoncework_list->head;
}
L_UNLOCK(info->renoncework_list);
}

applog(LOG_INFO, "%s: flushed %d works", bitfury->drv->name, flushed);


}

static struct api_data *bitfury16_api_stats(struct cgpu_info *bitfury)


{
uint8_t board_id, bcm250_id, chip_id;
struct bitfury16_info *info = bitfury->device_data;
char data[128];
char value[128];
struct api_data *root = NULL;

applog(LOG_INFO, "%s: API stats", bitfury->drv->name);

if (info->initialised == false)
return NULL;

#ifdef MINER_X5
root = api_add_string(root, "Device name", "Bitfury X5", true);
#endif
#ifdef MINER_X6
root = api_add_string(root, "Device name", "Bitfury X6", true);
#endif
root = api_add_uint8(root, "Boards number", &info->chipboard_num, false);
root = api_add_uint8(root, "Boards detected", &info->chipboard_num, false);
root = api_add_uint8(root, "Chips number", &info->chips_num, false);

/* software revision chages according to comments in CHANGELOG */


root = api_add_string(root, "hwv1", "1", true);
root = api_add_string(root, "hwv2", "2", true);
root = api_add_string(root, "hwv3", "11", true);
root = api_add_string(root, "hwv4", "0", true);
root = api_add_string(root, "hwv5", "0", true);

/* U avg */
sprintf(value, "%.1f", info->u_avg);
root = api_add_string(root, "U avg", value, true);

/* I total */
sprintf(value, "%.1f", info->i_total);
root = api_add_string(root, "I total", value, true);

/* P total */
sprintf(value, "%.1f", info->p_total);
root = api_add_string(root, "P total", value, true);

if (opt_bf16_renonce != RENONCE_DISABLED) {
/* Efficiency */
sprintf(value, "%.3f",
(info->a_net == true) ?
0.0 :
info->p_total / (CHIP_COEFF * (info->hashrate_good +
info->hashrate_re_good)));
root = api_add_string(root, "Efficiency", value, true);
/* Chip GHS total avg */
sprintf(value, "%.1f", CHIP_COEFF * info->hashrate / (info->chips_num -
info->renonce_chips - info->chips_failed));
root = api_add_string(root, "Chip GHS total avg", value, true);

/* Chip GHS avg */


sprintf(value, "%.1f", CHIP_COEFF * (info->hashrate_good + info-
>hashrate_re_good) / (info->chips_num - info->renonce_chips - info->chips_failed));
root = api_add_string(root, "Chip GHS avg", value, true);

/* Chip GHS good avg */


sprintf(value, "%.1f", CHIP_COEFF * info->hashrate_good / (info-
>chips_num - info->renonce_chips - info->chips_failed));
root = api_add_string(root, "Chip GHS good avg", value, true);

/* Chip GHS re avg */


sprintf(value, "%.1f", CHIP_COEFF * info->hashrate_re_good / (info-
>chips_num - info->renonce_chips - info->chips_failed));
root = api_add_string(root, "Chip GHS re avg", value, true);

/* Chip GHS bad avg */


sprintf(value, "%.1f", CHIP_COEFF * info->hashrate_re_bad / (info-
>chips_num - info->renonce_chips - info->chips_failed));
root = api_add_string(root, "Chip GHS bad avg", value, true);
} else {
/* Efficiency */
sprintf(value, "%.3f",
(info->a_net == true) ?
0.0 :
info->p_total / (CHIP_COEFF * info->hashrate_good));
root = api_add_string(root, "Efficiency", value, true);

/* Chip GHS total avg */


sprintf(value, "%.1f", CHIP_COEFF * info->hashrate / (info->chips_num -
info->chips_failed));
root = api_add_string(root, "Chip GHS total avg", value, true);

/* Chip GHS avg */


sprintf(value, "%.1f", CHIP_COEFF * info->hashrate_good / (info-
>chips_num - info->chips_failed));
root = api_add_string(root, "Chip GHS avg", value, true);

/* Chip GHS good avg */


sprintf(value, "%.1f", CHIP_COEFF * info->hashrate_good / (info-
>chips_num - info->chips_failed));
root = api_add_string(root, "Chip GHS good avg", value, true);

/* Chip GHS re avg */


sprintf(value, "%.1f", 0.0);
root = api_add_string(root, "Chip GHS re avg", value, true);

/* Chip GHS bad avg */


sprintf(value, "%.1f", CHIP_COEFF * info->hashrate_bad / (info-
>chips_num - info->chips_failed));
root = api_add_string(root, "Chip GHS bad avg", value, true);
}

/* U Chip avg */
sprintf(value, "%.3f", info->u_chip / (info->chips_num - info-
>chips_disabled));
root = api_add_string(root, "U Chip avg", value, true);

/* I Chip avg */
sprintf(value, "%.1f", (info->a_net == true) ? 0.0 : info->p_chip / info-
>u_chip);
root = api_add_string(root, "I Chip avg", value, true);

/* P Chip avg */
sprintf(value, "%.2f", info->p_chip / (info->chips_num - info-
>chips_disabled));
root = api_add_string(root, "P Chip avg", value, true);

for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {


/* board status */
sprintf(data, "Board%d detected", board_id);
if (info->chipboard[board_id].detected == true)
root = api_add_string(root, data, "1", true);
else
root = api_add_string(root, data, "0", true);

/* number of concentratord on board */


sprintf(data, "Board%d BTC250", board_id);
root = api_add_uint8(root, data, &info->chipboard[board_id].bcm250_num,
false);

/* number of chips on board */


sprintf(data, "Board%d BTC16", board_id);
root = api_add_uint8(root, data, &info->chipboard[board_id].chips_num,
false);

/* number of good chips on board */


sprintf(data, "Board%d BTC16 good", board_id);
uint8_t chips_good = info->chipboard[board_id].chips_num - info-
>chipboard[board_id].chips_failed;
root = api_add_uint8(root, data, &chips_good, true);

sprintf(data, "Board%d Clock", board_id);


if (info->chipboard[board_id].detected == true)
sprintf(value, "%d (0x%02x)", bf16_chip_clock, bf16_chip_clock);
else
sprintf(value, "%d (0x%02x)", 0, 0);

root = api_add_string(root, data, value, true);

sprintf(data, "Board%d GHS av", board_id);


if (opt_bf16_renonce != RENONCE_DISABLED) {
sprintf(value, "%.2f",
CHIP_COEFF * (info->chipboard[board_id].hashrate_good
+ info->chipboard[board_id].hashrate_re_good));
} else {
sprintf(value, "%.2f", CHIP_COEFF * (info-
>chipboard[board_id].hashrate_good));
}
root = api_add_string(root, data, value, true);

/* number of chips per concentrator */


uint8_t i = 0;
memset(value, 0, sizeof(value));

for (bcm250_id = 0; bcm250_id < BCM250_NUM; bcm250_id++) {


sprintf(data, "Board%d BTC250_%d BTC16", board_id, bcm250_id);
root = api_add_uint8(root, data, &info-
>chipboard[board_id].bcm250[bcm250_id].chips_num, false);

uint8_t first_good_chip = info-


>chipboard[board_id].bcm250[bcm250_id].first_good_chip;
uint8_t last_good_chip = info-
>chipboard[board_id].bcm250[bcm250_id].last_good_chip;

/* chips loop */
for (chip_id = first_good_chip; chip_id < last_good_chip;
chip_id++, i++) {
bf_chip_address_t chip_address;
chip_address.board_id = board_id;
chip_address.bcm250_id = bcm250_id;
chip_address.chip_id = chip_id;

if (info-
>chipboard[board_id].bcm250[bcm250_id].chips[chip_id].status < FAILING) {
if ((opt_bf16_renonce != RENONCE_DISABLED) &&
(renonce_chip(chip_address) == 1))
value[i] = 'O';
else
value[i] = 'o';
} else {
if ((opt_bf16_renonce != RENONCE_DISABLED) &&
(renonce_chip(chip_address) == 1))
value[i] = 'X';
else
value[i] = 'x';
}
}

if (bcm250_id != BCM250_NUM - 1)
value[i++] = ' ';
}

sprintf(data, "Board%d BF16 Status", board_id);


root = api_add_string(root, data, value, true);

/* MSP version data */


/* board version */
sprintf(data, "Board%d Ver", board_id);
root = api_add_uint32(root, data, &info->chipboard[board_id].board_ver,
false);

/* board firmware version */


sprintf(data, "Board%d FW", board_id);
root = api_add_uint32(root, data, &info-
>chipboard[board_id].board_fwver, false);

/* board hardware id */
sprintf(data, "Board%d HWID", board_id);
root = api_add_string(root, data, info->chipboard[board_id].board_hwid,
true);
/* MSP hw data */
/* T */
sprintf(data, "Board%d T", board_id);
sprintf(value, "%.1f", info->chipboard[board_id].temp);
root = api_add_string(root, data, value, true);

/* UB */
sprintf(data, "Board%d UB", board_id);
sprintf(value, "%.1f", info->chipboard[board_id].u_board);
root = api_add_string(root, data, value, true);

/* P1 */
sprintf(data, "Board%d P1", board_id);
root = api_add_uint8(root, data, &info-
>chipboard[board_id].p_chain1_enabled, false);

/* P2 */
sprintf(data, "Board%d P2", board_id);
root = api_add_uint8(root, data, &info-
>chipboard[board_id].p_chain2_enabled, false);

/* U1 */
sprintf(data, "Board%d U1", board_id);
sprintf(value, "%.1f", info->chipboard[board_id].u_chain1);
root = api_add_string(root, data, value, true);

/* U2 */
sprintf(data, "Board%d U2", board_id);
sprintf(value, "%.1f", info->chipboard[board_id].u_chain2);
root = api_add_string(root, data, value, true);

/* I1 */
sprintf(data, "Board%d I1", board_id);
sprintf(value, "%.1f", info->chipboard[board_id].i_chain1);
root = api_add_string(root, data, value, true);

/* I2 */
sprintf(data, "Board%d I2", board_id);
sprintf(value, "%.1f", info->chipboard[board_id].i_chain2);
root = api_add_string(root, data, value, true);

/* RPM */
sprintf(data, "Board%d PRM", board_id);
root = api_add_uint32(root, data, &info->chipboard[board_id].rpm,
true);

/* A */
sprintf(data, "Board%d T_Alarm", board_id);
root = api_add_uint8(root, data, &info->chipboard[board_id].a_temp,
true);

sprintf(data, "Board%d I1_Alarm", board_id);


root = api_add_uint8(root, data, &info->chipboard[board_id].a_ichain1,
true);

sprintf(data, "Board%d I2_Alarm", board_id);


root = api_add_uint8(root, data, &info->chipboard[board_id].a_ichain2,
true);
/* F */
sprintf(data, "Board%d F", board_id);
root = api_add_uint8(root, data, &info->chipboard[board_id].fan_speed,
false);

/* AI */
sprintf(data, "Board%d AI", board_id);
sprintf(value, "%.1f", info->chipboard[board_id].i_alarm);
root = api_add_string(root, data, value, true);

/* AT */
sprintf(data, "Board%d AT", board_id);
sprintf(value, "%.0f", info->chipboard[board_id].t_alarm);
root = api_add_string(root, data, value, true);

/* AG */
sprintf(data, "Board%d AG", board_id);
sprintf(value, "%.0f", info->chipboard[board_id].t_gisteresis);
root = api_add_string(root, data, value, true);

/* FM */
sprintf(data, "Board%d FM", board_id);
#ifdef MINER_X5
sprintf(value, "%c", info->chipboard[board_id].fan_mode);
#endif

#ifdef MINER_X6
if (manual_pid_enabled == true)
sprintf(value, "A");
else
sprintf(value, "%c", info->chipboard[board_id].fan_mode);
#endif
root = api_add_string(root, data, value, true);

/* TT */
sprintf(data, "Board%d TT", board_id);
sprintf(value, "%.0f", info->chipboard[board_id].target_temp);
root = api_add_string(root, data, value, true);
}

return root;
}

static void bitfury16_shutdown(struct thr_info *thr)


{
struct cgpu_info *bitfury = thr->cgpu;
struct bitfury16_info *info = (struct bitfury16_info *)bitfury->device_data;
uint8_t board_id;

bitfury->shutdown = true;

cgsleep_ms(300);

/* flush next board temp to default value */


if (manual_pid_enabled == false) {
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if (info->chipboard[board_id].detected == true) {
if (device_uart_transfer(board_id + 1, "N") < 0)
quit(1, "%s: %s() failed to set BOARD%d next temp",
bitfury->drv->name, __func__, board_id +
1);

applog(LOG_INFO, "%s: set BOARD%d next temp to default


value",
bitfury->drv->name, board_id + 1);
}
}
} else {
for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
if (info->chipboard[board_id].detected == true) {
if (device_uart_transfer(board_id + 1, "F") < 0)
quit(1, "%s: %s() failed to set BOARD%d fan speed to
auto mode",
bitfury->drv->name, __func__, board_id +
1);

applog(LOG_INFO, "%s: set BOARD%d fan speed to auto mode",


bitfury->drv->name, board_id + 1);
}
}
}

/* disable power chain */


for (board_id = 0; board_id < CHIPBOARD_NUM; board_id++) {
disable_power_chain(bitfury, board_id, 0);
}

mutex_destroy(&info->nonces_good_lock);

/* close devices */
close_spi_device(SPI_CHANNEL1);
close_spi_device(SPI_CHANNEL2);
close_ctrl_device();
close_uart_device(UART_CHANNEL1);
close_uart_device(UART_CHANNEL2);

#ifdef FILELOG
filelog(info, "%s: cgminer stopped", bitfury->drv->name);
fclose(info->logfile);
mutex_destroy(&info->logfile_mutex);
#endif

applog(LOG_INFO, "%s: driver shutdown", bitfury->drv->name);


}

/* Currently hardcoded to BF1 devices */


struct device_drv bitfury16_drv = {
.drv_id = DRIVER_bitfury16,
.dname = "bitfury16",
.name = "BF16",
.drv_detect = bitfury16_detect,
.get_api_stats = bitfury16_api_stats,
.identify_device = bitfury16_identify,
.thread_prepare = bitfury16_thread_prepare,
.hash_work = hash_queued_work,
.scanwork = bitfury16_scanwork,
.queue_full = bitfury16_queue_full,
.flush_work = bitfury16_flush_work,
.thread_shutdown = bitfury16_shutdown
};

You might also like