0% found this document useful (0 votes)
77 views95 pages

Driver Bitfury16

This document contains C header code for configuring and initializing a Bitfury mining board driver. It defines various constants for settings like timeouts, thresholds, and intervals. It also declares structures for PID settings, chip mappings, and other configuration options. Logging and timing functions are implemented to support the driver operations.

Uploaded by

alexandr
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
77 views95 pages

Driver Bitfury16

This document contains C header code for configuring and initializing a Bitfury mining board driver. It defines various constants for settings like timeouts, thresholds, and intervals. It also declares structures for PID settings, chip mappings, and other configuration options. Logging and timing functions are implemented to support the driver operations.

Uploaded by

alexandr
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 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