Browse Source

Merge pull request #467 from someone42/master

Support for BitBurner boards
nfactor-troky
kanoi 11 years ago
parent
commit
8dc0935639
  1. 3
      cgminer.c
  2. 119
      driver-avalon.c
  3. 5
      driver-avalon.h
  4. 19
      usbutils.c
  5. 9
      usbutils.h

3
cgminer.c

@ -1075,6 +1075,9 @@ static struct opt_table opt_config_table[] = {
OPT_WITH_ARG("--avalon-temp", OPT_WITH_ARG("--avalon-temp",
set_int_0_to_100, opt_show_intval, &opt_avalon_temp, set_int_0_to_100, opt_show_intval, &opt_avalon_temp,
"Set avalon target temperature"), "Set avalon target temperature"),
OPT_WITH_ARG("--bitburner-voltage",
opt_set_intval, NULL, &opt_bitburner_core_voltage,
"Set BitBurner core voltage, in millivolts"),
#endif #endif
OPT_WITHOUT_ARG("--load-balance", OPT_WITHOUT_ARG("--load-balance",
set_loadbalance, &pool_strategy, set_loadbalance, &pool_strategy,

119
driver-avalon.c

@ -46,6 +46,7 @@ int opt_avalon_fan_min = AVALON_DEFAULT_FAN_MIN_PWM;
int opt_avalon_fan_max = AVALON_DEFAULT_FAN_MAX_PWM; int opt_avalon_fan_max = AVALON_DEFAULT_FAN_MAX_PWM;
int opt_avalon_freq_min = AVALON_MIN_FREQUENCY; int opt_avalon_freq_min = AVALON_MIN_FREQUENCY;
int opt_avalon_freq_max = AVALON_MAX_FREQUENCY; int opt_avalon_freq_max = AVALON_MAX_FREQUENCY;
int opt_bitburner_core_voltage = BITBURNER_DEFAULT_CORE_VOLTAGE;
bool opt_avalon_auto; bool opt_avalon_auto;
static int option_offset = -1; static int option_offset = -1;
@ -291,7 +292,7 @@ static int avalon_reset(struct cgpu_info *avalon, bool initial)
return -1; return -1;
if (!initial) { if (!initial) {
applog(LOG_ERR, "AVA%d reset sequence sent", avalon->device_id); applog(LOG_ERR, "%s%d reset sequence sent", avalon->drv->name, avalon->device_id);
return 0; return 0;
} }
@ -308,7 +309,7 @@ static int avalon_reset(struct cgpu_info *avalon, bool initial)
spare = ret - 10; spare = ret - 10;
buf = tmp = (uint8_t *)&ar; buf = tmp = (uint8_t *)&ar;
if (opt_debug) { if (opt_debug) {
applog(LOG_DEBUG, "AVA%d reset: get:", avalon->device_id); applog(LOG_DEBUG, "%s%d reset: get:", avalon->drv->name, avalon->device_id);
hexdump(tmp, AVALON_READ_SIZE); hexdump(tmp, AVALON_READ_SIZE);
} }
@ -327,13 +328,13 @@ static int avalon_reset(struct cgpu_info *avalon, bool initial)
} }
if (i != 11) { if (i != 11) {
applog(LOG_ERR, "AVA%d: Reset failed! not an Avalon?" applog(LOG_ERR, "%s%d: Reset failed! not an Avalon?"
" (%d: %02x %02x %02x %02x)", avalon->device_id, " (%d: %02x %02x %02x %02x)", avalon->drv->name, avalon->device_id,
i, buf[0], buf[1], buf[2], buf[3]); i, buf[0], buf[1], buf[2], buf[3]);
/* FIXME: return 1; */ /* FIXME: return 1; */
} else } else
applog(LOG_WARNING, "AVA%d: Reset succeeded", applog(LOG_WARNING, "%s%d: Reset succeeded",
avalon->device_id); avalon->drv->name, avalon->device_id);
return 0; return 0;
} }
@ -509,7 +510,7 @@ static void avalon_idle(struct cgpu_info *avalon, struct avalon_info *info)
info->frequency); info->frequency);
avalon_send_task(&at, avalon); avalon_send_task(&at, avalon);
} }
applog(LOG_WARNING, "AVA%i: Idling %d miners", avalon->device_id, i); applog(LOG_WARNING, "%s%i: Idling %d miners", avalon->drv->name, avalon->device_id, i);
wait_avalon_ready(avalon); wait_avalon_ready(avalon);
} }
@ -601,6 +602,51 @@ static void avalon_initialise(struct cgpu_info *avalon)
avalon->drv->name, avalon->device_id, err); avalon->drv->name, avalon->device_id, err);
} }
static void bitburner_set_core_voltage(struct cgpu_info *avalon, int core_voltage)
{
uint8_t buf[2];
int err;
if (usb_ident(avalon) == IDENT_BTB) {
buf[0] = (uint8_t)core_voltage;
buf[1] = (uint8_t)(core_voltage >> 8);
err = usb_transfer_data(avalon, FTDI_TYPE_OUT, BITBURNER_REQUEST,
BITBURNER_VALUE, BITBURNER_INDEX_SET_VOLTAGE,
(uint32_t *)buf, sizeof(buf), C_BB_SET_VOLTAGE);
if (unlikely(err < 0)) {
applog(LOG_ERR, "%s%i: SetCoreVoltage failed: err = %d",
avalon->drv->name, avalon->device_id, err);
} else {
applog(LOG_WARNING, "%s%i: Core voltage set to %d millivolts",
avalon->drv->name, avalon->device_id,
core_voltage);
}
}
}
static int bitburner_get_core_voltage(struct cgpu_info *avalon)
{
uint8_t buf[2];
int err;
int amount;
if (usb_ident(avalon) == IDENT_BTB) {
err = usb_transfer_read(avalon, FTDI_TYPE_IN, BITBURNER_REQUEST,
BITBURNER_VALUE, BITBURNER_INDEX_GET_VOLTAGE,
(char *)buf, sizeof(buf), &amount,
C_BB_GET_VOLTAGE);
if (unlikely(err != 0 || amount != 2)) {
applog(LOG_ERR, "%s%i: GetCoreVoltage failed: err = %d, amount = %d",
avalon->drv->name, avalon->device_id, err, amount);
return 0;
} else {
return (int)(buf[0] + ((unsigned int)buf[1] << 8));
}
} else {
return 0;
}
}
static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found) static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found)
{ {
int baud, miner_count, asic_count, timeout, frequency = 0; int baud, miner_count, asic_count, timeout, frequency = 0;
@ -672,6 +718,10 @@ static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found
avalon->device_path, info->miner_count, info->asic_count, info->timeout, avalon->device_path, info->miner_count, info->asic_count, info->timeout,
info->frequency); info->frequency);
if (usb_ident(avalon) == IDENT_BTB &&
opt_bitburner_core_voltage != BITBURNER_DEFAULT_CORE_VOLTAGE)
bitburner_set_core_voltage(avalon, opt_bitburner_core_voltage);
return true; return true;
unshin: unshin:
@ -908,8 +958,8 @@ static void *avalon_send_tasks(void *userdata)
if (!info->optimal) { if (!info->optimal) {
if (info->fan_pwm >= opt_avalon_fan_max) { if (info->fan_pwm >= opt_avalon_fan_max) {
applog(LOG_WARNING, applog(LOG_WARNING,
"AVA%i: Above optimal temperature, throttling", "%s%i: Above optimal temperature, throttling",
avalon->device_id); avalon->drv->name, avalon->device_id);
avalon_dec_freq(info); avalon_dec_freq(info);
} }
} else if (info->auto_nonces >= (AVALON_AUTO_CYCLE * 19 / 20) && } else if (info->auto_nonces >= (AVALON_AUTO_CYCLE * 19 / 20) &&
@ -932,8 +982,8 @@ static void *avalon_send_tasks(void *userdata)
for (i = start_count, j = 0; i < end_count; i++, j++) { for (i = start_count, j = 0; i < end_count; i++, j++) {
if (avalon_buffer_full(avalon)) { if (avalon_buffer_full(avalon)) {
applog(LOG_INFO, applog(LOG_INFO,
"AVA%i: Buffer full after only %d of %d work queued", "%s%i: Buffer full after only %d of %d work queued",
avalon->device_id, j, avalon_get_work_count); avalon->drv->name, avalon->device_id, j, avalon_get_work_count);
break; break;
} }
@ -961,8 +1011,8 @@ static void *avalon_send_tasks(void *userdata)
ret = avalon_send_task(&at, avalon); ret = avalon_send_task(&at, avalon);
if (unlikely(ret == AVA_SEND_ERROR)) { if (unlikely(ret == AVA_SEND_ERROR)) {
applog(LOG_ERR, "AVA%i: Comms error(buffer)", applog(LOG_ERR, "%s%i: Comms error(buffer)",
avalon->device_id); avalon->drv->name, avalon->device_id);
dev_error(avalon, REASON_DEV_COMMS_ERROR); dev_error(avalon, REASON_DEV_COMMS_ERROR);
info->reset = true; info->reset = true;
break; break;
@ -974,8 +1024,8 @@ static void *avalon_send_tasks(void *userdata)
mutex_unlock(&info->qlock); mutex_unlock(&info->qlock);
if (unlikely(idled)) { if (unlikely(idled)) {
applog(LOG_WARNING, "AVA%i: Idled %d miners", applog(LOG_WARNING, "%s%i: Idled %d miners",
avalon->device_id, idled); avalon->drv->name, avalon->device_id, idled);
} }
} }
return NULL; return NULL;
@ -1129,16 +1179,19 @@ static void avalon_update_temps(struct cgpu_info *avalon, struct avalon_info *in
info->temp_sum += avalon->temp; info->temp_sum += avalon->temp;
applog(LOG_DEBUG, "Avalon: temp_index: %d, temp_count: %d, temp_old: %d", applog(LOG_DEBUG, "Avalon: temp_index: %d, temp_count: %d, temp_old: %d",
info->temp_history_index, info->temp_history_count, info->temp_old); info->temp_history_index, info->temp_history_count, info->temp_old);
if (usb_ident(avalon) == IDENT_BTB) {
info->core_voltage = bitburner_get_core_voltage(avalon);
}
if (info->temp_history_index == info->temp_history_count) { if (info->temp_history_index == info->temp_history_count) {
adjust_fan(info); adjust_fan(info);
info->temp_history_index = 0; info->temp_history_index = 0;
info->temp_sum = 0; info->temp_sum = 0;
} }
if (unlikely(info->temp_old >= opt_avalon_overheat)) { if (unlikely(info->temp_old >= opt_avalon_overheat)) {
applog(LOG_WARNING, "AVA%d overheat! Idling", avalon->device_id); applog(LOG_WARNING, "%s%d overheat! Idling", avalon->drv->name, avalon->device_id);
info->overheat = true; info->overheat = true;
} else if (info->overheat && info->temp_old <= opt_avalon_temp) { } else if (info->overheat && info->temp_old <= opt_avalon_temp) {
applog(LOG_WARNING, "AVA%d cooled, restarting", avalon->device_id); applog(LOG_WARNING, "%s%d cooled, restarting", avalon->drv->name, avalon->device_id);
info->overheat = false; info->overheat = false;
} }
} }
@ -1148,13 +1201,17 @@ static void get_avalon_statline_before(char *buf, size_t bufsiz, struct cgpu_inf
struct avalon_info *info = avalon->device_data; struct avalon_info *info = avalon->device_data;
int lowfan = 10000; int lowfan = 10000;
/* Find the lowest fan speed of the ASIC cooling fans. */ if (usb_ident(avalon) == IDENT_BTB) {
if (info->fan1 >= 0 && info->fan1 < lowfan) tailsprintf(buf, bufsiz, "%2d/%3dC %4dmV | ", info->temp0, info->temp2, info->core_voltage);
lowfan = info->fan1; } else {
if (info->fan2 >= 0 && info->fan2 < lowfan) /* Find the lowest fan speed of the ASIC cooling fans. */
lowfan = info->fan2; if (info->fan1 >= 0 && info->fan1 < lowfan)
lowfan = info->fan1;
if (info->fan2 >= 0 && info->fan2 < lowfan)
lowfan = info->fan2;
tailsprintf(buf, bufsiz, "%2d/%3dC %04dR | ", info->temp0, info->temp2, lowfan); tailsprintf(buf, bufsiz, "%2d/%3dC %04dR | ", info->temp0, info->temp2, lowfan);
}
} }
/* We use a replacement algorithm to only remove references to work done from /* We use a replacement algorithm to only remove references to work done from
@ -1231,15 +1288,17 @@ static int64_t avalon_scanhash(struct thr_info *thr)
/* Check for nothing but consecutive bad results or consistently less /* Check for nothing but consecutive bad results or consistently less
* results than we should be getting and reset the FPGA if necessary */ * results than we should be getting and reset the FPGA if necessary */
if (avalon->results < -miner_count && !info->reset) { if (usb_ident(avalon) != IDENT_BTB) {
applog(LOG_ERR, "AVA%d: Result return rate low, resetting!", if (avalon->results < -miner_count && !info->reset) {
avalon->device_id); applog(LOG_ERR, "%s%d: Result return rate low, resetting!",
info->reset = true; avalon->drv->name, avalon->device_id);
info->reset = true;
}
} }
if (unlikely(avalon->usbinfo.nodev)) { if (unlikely(avalon->usbinfo.nodev)) {
applog(LOG_ERR, "AVA%d: Device disappeared, shutting down thread", applog(LOG_ERR, "%s%d: Device disappeared, shutting down thread",
avalon->device_id); avalon->drv->name, avalon->device_id);
avalon->shutdown = true; avalon->shutdown = true;
} }
@ -1279,6 +1338,8 @@ static struct api_data *avalon_api_stats(struct cgpu_info *cgpu)
root = api_add_int(root, "temp3", &(info->temp2), false); root = api_add_int(root, "temp3", &(info->temp2), false);
root = api_add_int(root, "temp_max", &(info->temp_max), false); root = api_add_int(root, "temp_max", &(info->temp_max), false);
root = api_add_int(root, "core_voltage", &(info->core_voltage), false);
root = api_add_int(root, "no_matching_work", &(info->no_matching_work), false); root = api_add_int(root, "no_matching_work", &(info->no_matching_work), false);
for (i = 0; i < info->miner_count; i++) { for (i = 0; i < info->miner_count; i++) {
char mcw[24]; char mcw[24];

5
driver-avalon.h

@ -33,6 +33,8 @@
#define AVALON_TEMP_HYSTERESIS 3 #define AVALON_TEMP_HYSTERESIS 3
#define AVALON_TEMP_OVERHEAT 60 #define AVALON_TEMP_OVERHEAT 60
#define BITBURNER_DEFAULT_CORE_VOLTAGE 1200 /* in millivolts */
#define AVALON_DEFAULT_TIMEOUT 0x2D #define AVALON_DEFAULT_TIMEOUT 0x2D
#define AVALON_MIN_FREQUENCY 256 #define AVALON_MIN_FREQUENCY 256
#define AVALON_MAX_FREQUENCY 450 #define AVALON_MAX_FREQUENCY 450
@ -113,6 +115,8 @@ struct avalon_info {
int temp_old; int temp_old;
int fan_pwm; int fan_pwm;
int core_voltage;
int no_matching_work; int no_matching_work;
int matching_work[AVALON_DEFAULT_MINER_NUM]; int matching_work[AVALON_DEFAULT_MINER_NUM];
@ -161,6 +165,7 @@ extern int opt_avalon_fan_max;
extern int opt_avalon_freq_min; extern int opt_avalon_freq_min;
extern int opt_avalon_freq_max; extern int opt_avalon_freq_max;
extern bool opt_avalon_auto; extern bool opt_avalon_auto;
extern int opt_bitburner_core_voltage;
extern char *set_avalon_fan(char *arg); extern char *set_avalon_fan(char *arg);
extern char *set_avalon_freq(char *arg); extern char *set_avalon_freq(char *arg);

19
usbutils.c

@ -190,6 +190,21 @@ static struct usb_find_devices find_dev[] = {
.eps = mmq_eps }, .eps = mmq_eps },
#endif #endif
#ifdef USE_AVALON #ifdef USE_AVALON
{
.drv = DRV_AVALON,
.name = "BTB",
.ident = IDENT_BTB,
.idVendor = IDVENDOR_FTDI,
.idProduct = 0x6001,
.iManufacturer = "Burnin Electronics",
.iProduct = "BitBurner",
.kernel = 0,
.config = 1,
.interface = 0,
.timeout = AVALON_TIMEOUT_MS,
.latency = 10,
.epcount = ARRAY_SIZE(ava_eps),
.eps = ava_eps },
{ {
.drv = DRV_AVALON, .drv = DRV_AVALON,
.name = "AVA", .name = "AVA",
@ -535,6 +550,8 @@ static const char *C_AVALON_RESET_S = "AvalonReset";
static const char *C_GET_AVALON_RESET_S = "GetAvalonReset"; static const char *C_GET_AVALON_RESET_S = "GetAvalonReset";
static const char *C_FTDI_STATUS_S = "FTDIStatus"; static const char *C_FTDI_STATUS_S = "FTDIStatus";
static const char *C_ENABLE_UART_S = "EnableUART"; static const char *C_ENABLE_UART_S = "EnableUART";
static const char *C_BB_SET_VOLTAGE_S = "SetCoreVoltage";
static const char *C_BB_GET_VOLTAGE_S = "GetCoreVoltage";
#ifdef EOL #ifdef EOL
#undef EOL #undef EOL
@ -1023,6 +1040,8 @@ static void cgusb_check_init()
usb_commands[C_GET_AVALON_RESET] = C_GET_AVALON_RESET_S; usb_commands[C_GET_AVALON_RESET] = C_GET_AVALON_RESET_S;
usb_commands[C_FTDI_STATUS] = C_FTDI_STATUS_S; usb_commands[C_FTDI_STATUS] = C_FTDI_STATUS_S;
usb_commands[C_ENABLE_UART] = C_ENABLE_UART_S; usb_commands[C_ENABLE_UART] = C_ENABLE_UART_S;
usb_commands[C_BB_SET_VOLTAGE] = C_BB_SET_VOLTAGE_S;
usb_commands[C_BB_GET_VOLTAGE] = C_BB_GET_VOLTAGE_S;
stats_initialised = true; stats_initialised = true;
} }

9
usbutils.h

@ -48,6 +48,12 @@
#define FTDI_VALUE_DATA_AVA 8 #define FTDI_VALUE_DATA_AVA 8
// BitBurner
#define BITBURNER_REQUEST ((uint8_t)0x42)
#define BITBURNER_VALUE 0x4242
#define BITBURNER_INDEX_SET_VOLTAGE 1
#define BITBURNER_INDEX_GET_VOLTAGE 2
// CMR = 115200 & 57600 // CMR = 115200 & 57600
#define FTDI_VALUE_BAUD_CMR_115 0xc068 #define FTDI_VALUE_BAUD_CMR_115 0xc068
#define FTDI_INDEX_BAUD_CMR_115 0x0200 #define FTDI_INDEX_BAUD_CMR_115 0x0200
@ -121,6 +127,7 @@ enum sub_ident {
IDENT_BFL, IDENT_BFL,
IDENT_MMQ, IDENT_MMQ,
IDENT_AVA, IDENT_AVA,
IDENT_BTB,
IDENT_ICA, IDENT_ICA,
IDENT_AMU, IDENT_AMU,
IDENT_BLT, IDENT_BLT,
@ -304,6 +311,8 @@ enum usb_cmds {
C_GET_AVALON_RESET, C_GET_AVALON_RESET,
C_FTDI_STATUS, C_FTDI_STATUS,
C_ENABLE_UART, C_ENABLE_UART,
C_BB_SET_VOLTAGE,
C_BB_GET_VOLTAGE,
C_MAX C_MAX
}; };

Loading…
Cancel
Save