Drillbit: Add support for protocol V4, with device-agnostic board configuration data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
diff --git a/driver-drillbit.c b/driver-drillbit.c
index 06864eb..a680e9f 100644
--- a/driver-drillbit.c
+++ b/driver-drillbit.c
@@ -53,26 +53,35 @@ typedef struct {
#define SZ_SERIALISED_WORKRESULT (4+4*MAX_RESULTS)
static void deserialise_work_result(WorkResult *work_result, const char *buf);
+/* V4 config is the preferred one, used internally, non-ASIC-specific */
+typedef struct {
+ uint16_t core_voltage; // Millivolts
+ uint16_t clock_freq; // Clock frequency in MHz (or clock level 30-48 for Bitfury internal clock level)
+ uint8_t clock_div2; // Apply the /2 clock divider (both internal and external), where available
+ uint8_t use_ext_clock; // Flag. Ignored on boards without external clocks
+} BoardConfig;
+
#define CONFIG_PW1 (1<<0)
#define CONFIG_PW2 (1<<1)
-// Possible core voltage settings on PW1 & PW2
+// Possible core voltage settings on PW1 & PW2, used by legacy V3 config only
#define CONFIG_CORE_065V 0
#define CONFIG_CORE_075V CONFIG_PW2
#define CONFIG_CORE_085V CONFIG_PW1
#define CONFIG_CORE_095V (CONFIG_PW1|CONFIG_PW2)
+/* V3 config is for backwards compatibility with older firmwares */
typedef struct {
uint8_t core_voltage; // Set to flags defined above
uint8_t int_clock_level; // Clock level (30-48 without divider), see asic.c for details
- uint8_t clock_div2; // Apply the /2 clock divider (both internal and external)
+ uint8_t clock_div2; // Apply the /2 clock divider (both internal and external)
uint8_t use_ext_clock; // Ignored on boards without external clocks
uint16_t ext_clock_freq;
- uint16_t core_voltage_mv; // set to a plain human-readable integer value (not serialised atm)
-} BoardConfig;
+ } BoardConfigV3;
#define SZ_SERIALISED_BOARDCONFIG 6
-static void serialise_board_config(char *buf, const BoardConfig *boardconfig);
+static void serialise_board_configV4(char *buf, BoardConfig *boardconfig);
+static void serialise_board_configV3(char *buf, BoardConfigV3 *boardconfig);
typedef struct {
uint8_t protocol_version;
@@ -101,12 +110,10 @@ typedef struct {
static config_setting default_settings = {
key: { 0 },
config: {
- core_voltage: CONFIG_CORE_085V,
- core_voltage_mv: 850,
+ core_voltage: 850,
+ clock_freq: 200,
use_ext_clock: 0,
- int_clock_level: 40,
clock_div2: 0,
- ext_clock_freq: 200
},
};
@@ -248,7 +255,7 @@ static bool drillbit_getinfo(struct cgpu_info *drillbit, struct drillbit_info *i
}
const int MIN_VERSION = 2;
- const int MAX_VERSION = 3;
+ const int MAX_VERSION = 4;
if (identity.protocol_version < MIN_VERSION) {
drvlog(LOG_ERR, "Unknown device protocol version %d.", identity.protocol_version);
return false;
@@ -264,7 +271,7 @@ static bool drillbit_getinfo(struct cgpu_info *drillbit, struct drillbit_info *i
}
// load identity data into device info structure
- info->version = identity.protocol_version;
+ info->protocol_version = identity.protocol_version;
if (strncmp(identity.product, "DRILLBIT", sizeof(identity.product)) == 0) {
// Hack: first production firmwares all described themselves as DRILLBIT, so fill in the gaps
if (identity.num_chips == 1)
@@ -279,7 +286,7 @@ static bool drillbit_getinfo(struct cgpu_info *drillbit, struct drillbit_info *i
info->capabilities = identity.capabilities;
drvlog(LOG_INFO, "Getinfo returned version %d, product %s serial %08x num_chips %d",
- info->version, info->product, info->serial, info->num_chips);
+ info->protocol_version, info->product, info->serial, info->num_chips);
drillbit_empty_buffer(drillbit);
return true;
@@ -359,32 +366,47 @@ static void drillbit_send_config(struct cgpu_info *drillbit)
struct drillbit_info *info = drillbit->device_data;
char cmd;
int amount;
- char buf[SZ_SERIALISED_BOARDCONFIG];
+ char buf[SZ_SERIALISED_BOARDCONFIG+1];
+ size_t size;
config_setting *setting;
+ BoardConfigV3 v3_config;
// Find the relevant board config
setting = find_settings(drillbit);
drvlog(LOG_NOTICE, "Config: %s:%d:%d:%d Serial: %08x",
setting->config.use_ext_clock ? "ext" : "int",
- setting->config.use_ext_clock ? setting->config.ext_clock_freq : setting->config.int_clock_level,
+ setting->config.clock_freq,
setting->config.clock_div2 ? 2 : 1,
- setting->config.core_voltage_mv,
+ setting->config.core_voltage,
info->serial);
- drvlog(LOG_INFO, "Sending board configuration voltage=%d use_ext_clock=%d int_clock_level=%d clock_div2=%d ext_clock_freq=%d",
- setting->config.core_voltage, setting->config.use_ext_clock,
- setting->config.int_clock_level,
- setting->config.clock_div2, setting->config.ext_clock_freq);
-
if (setting->config.use_ext_clock && !(info->capabilities & CAP_EXT_CLOCK)) {
drvlog(LOG_WARNING, "Chosen configuration specifies external clock but this device (serial %08x) has no external clock!", info->serial);
}
- cmd = 'C';
- usb_write_timeout(drillbit, &cmd, 1, &amount, TIMEOUT, C_BF_REQWORK);
-
- serialise_board_config(buf, &setting->config);
- usb_write_timeout(drillbit, buf, SZ_SERIALISED_BOARDCONFIG, &amount, TIMEOUT, C_BF_CONFIG);
+ if(info->protocol_version <= 3) {
+ /* Make up a backwards compatible V3 config structure to send to the miner */
+ if(setting->config.core_voltage >= 950)
+ v3_config.core_voltage = CONFIG_CORE_095V;
+ else if (setting->config.core_voltage >= 850)
+ v3_config.core_voltage = CONFIG_CORE_085V;
+ else if (setting->config.core_voltage >= 750)
+ v3_config.core_voltage = CONFIG_CORE_075V;
+ else
+ v3_config.core_voltage = CONFIG_CORE_065V;
+ if(setting->config.clock_freq > 64)
+ v3_config.int_clock_level = setting->config.clock_freq / 5;
+ else
+ v3_config.int_clock_level = setting->config.clock_freq;
+ v3_config.clock_div2 = setting->config.clock_div2;
+ v3_config.use_ext_clock = setting->config.use_ext_clock;
+ v3_config.ext_clock_freq = setting->config.clock_freq;
+ serialise_board_configV3(&buf[1], &v3_config);
+ } else {
+ serialise_board_configV4(&buf[1], &setting->config);
+ }
+ buf[0] = 'C';
+ usb_write_timeout(drillbit, buf, sizeof(buf), &amount, TIMEOUT, C_BF_CONFIG);
/* Expect a single 'C' byte as acknowledgement */
usb_read_simple_response(drillbit, 'C', C_BF_CONFIG); // TODO: verify response
@@ -475,42 +497,13 @@ static bool drillbit_parse_options(struct cgpu_info *drillbit)
if (!strcmp("int",clksrc)) {
parsed_config.use_ext_clock = 0;
- if (freq < 0 || freq > 63) {
- quithere(1, "Invalid internal oscillator level %d. Recommended range is %s for this clock divider (possible is 0-63)", freq, parsed_config.clock_div2 ? "48-57":"30-48");
- }
- if (parsed_config.clock_div2 && (freq < 48 || freq > 57)) {
- drvlog(LOG_WARNING, "Internal oscillator level %d outside recommended range 48-57.", freq);
- }
- if (!parsed_config.clock_div2 && (freq < 30 || freq > 48)) {
- drvlog(LOG_WARNING, "Internal oscillator level %d outside recommended range 30-48.", freq);
- }
- parsed_config.int_clock_level = freq;
- } else if (!strcmp("ext", clksrc)) {
+ }
+ else if (!strcmp("ext", clksrc)) {
parsed_config.use_ext_clock = 1;
- parsed_config.ext_clock_freq = freq;
- if (freq < 80 || freq > 230) {
- drvlog(LOG_WARNING, "Warning: recommended external clock frequencies are 80-230MHz. Value %d may produce unexpected results.", freq);
- }
} else
quithere(1, "Invalid clock source. Valid choices are int, ext.");
- parsed_config.core_voltage_mv = voltage;
- switch(voltage) {
- case 650:
- voltage = CONFIG_CORE_065V;
- break;
- case 750:
- voltage = CONFIG_CORE_075V;
- break;
- case 850:
- voltage = CONFIG_CORE_085V;
- break;
- case 950:
- voltage = CONFIG_CORE_095V;
- break;
- default:
- quithere(1, "Invalid core voltage %d. Valid values 650,750,850,950mV)", voltage);
- }
+ parsed_config.clock_freq = freq;
parsed_config.core_voltage = voltage;
// Add the new set of settings to the configuration choices hash table
@@ -896,7 +889,7 @@ static struct api_data *drillbit_api_stats(struct cgpu_info *cgpu)
char serial[16];
int version;
- version = info->version;
+ version = info->protocol_version;
root = api_add_int(root, "Protocol Version", &version, true);
root = api_add_string(root, "Product", info->product, false);
sprintf(serial, "%08x", info->serial);
@@ -975,7 +968,7 @@ static void deserialise_work_result(WorkResult *wr, const char *buf)
DESERIALISE(wr->nonce[i]);
}
-static void serialise_board_config(char *buf, const BoardConfig *bc)
+static void serialise_board_configV3(char *buf, BoardConfigV3 *bc)
{
size_t offset = 0;
SERIALISE(bc->core_voltage);
@@ -985,6 +978,16 @@ static void serialise_board_config(char *buf, const BoardConfig *bc)
SERIALISE(bc->ext_clock_freq);
}
+static void serialise_board_configV4(char *buf, BoardConfig *bc)
+{
+ size_t offset = 0;
+ SERIALISE(bc->core_voltage);
+ SERIALISE(bc->clock_freq);
+ SERIALISE(bc->clock_div2);
+ SERIALISE(bc->use_ext_clock);
+}
+
+
static void deserialise_identity(Identity *id, const char *buf)
{
size_t offset = 0;
diff --git a/driver-drillbit.h b/driver-drillbit.h
index 7377352..20a75c0 100644
--- a/driver-drillbit.h
+++ b/driver-drillbit.h
@@ -20,7 +20,7 @@ struct drillbit_chip_info;
/* drillbit_info structure applies to entire device */
struct drillbit_info {
struct cgpu_info *base_cgpu;
- uint8_t version;
+ uint8_t protocol_version;
uint8_t num_chips;
uint16_t capabilities;
char product[8];