/ driver-avalon-miner.c
driver-avalon-miner.c
1 /* 2 * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org> 3 * Copyright 2012-2014 Xiangfu <xiangfu@openmobilefree.com> 4 * Copyright 2014-2015 Mikeqin <Fengling.Qin@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the Free 8 * Software Foundation; either version 3 of the License, or (at your option) 9 * any later version. See COPYING for more details. 10 */ 11 #include <math.h> 12 #include "config.h" 13 #include "miner.h" 14 #include "driver-avalon-miner.h" 15 #include "crc.h" 16 #include "sha2.h" 17 #include "hexdump.c" 18 19 #define UNPACK32(x, str) \ 20 { \ 21 *((str) + 3) = (uint8_t) ((x) ); \ 22 *((str) + 2) = (uint8_t) ((x) >> 8); \ 23 *((str) + 1) = (uint8_t) ((x) >> 16); \ 24 *((str) + 0) = (uint8_t) ((x) >> 24); \ 25 } 26 27 #define PACK32(str, x) \ 28 { \ 29 *(x) = ((uint32_t) *((str) + 3) ) \ 30 | ((uint32_t) *((str) + 2) << 8) \ 31 | ((uint32_t) *((str) + 1) << 16) \ 32 | ((uint32_t) *((str) + 0) << 24); \ 33 } 34 35 #define V_REF 3.3 36 #define R_REF 10000 37 #define R0 10000 38 #define BCOEFFICIENT 3450 39 #define T0 25 40 41 static uint32_t opt_avalonm_freq[3] = {AVAM_DEFAULT_FREQUENCY, AVAM_DEFAULT_FREQUENCY, AVAM_DEFAULT_FREQUENCY}; 42 uint8_t opt_avalonm_ntime_offset = 0; 43 int opt_avalonm_voltage = AVAM_DEFAULT_VOLTAGE; 44 uint32_t opt_avalonm_spispeed = AVAM_DEFAULT_SPISPEED; 45 bool opt_avalonm_autof; 46 static uint32_t g_freq_array[][2] = { 47 {100, 0x1e678447}, 48 {113, 0x22688447}, 49 {125, 0x1c470447}, 50 {138, 0x2a6a8447}, 51 {150, 0x22488447}, 52 {163, 0x326c8447}, 53 {175, 0x1a268447}, 54 {188, 0x1c270447}, 55 {200, 0x1e278447}, 56 {213, 0x20280447}, 57 {225, 0x22288447}, 58 {238, 0x24290447}, 59 {250, 0x26298447}, 60 {263, 0x282a0447}, 61 {275, 0x2a2a8447}, 62 {288, 0x2c2b0447}, 63 {300, 0x2e2b8447}, 64 {313, 0x302c0447}, 65 {325, 0x322c8447}, 66 {338, 0x342d0447}, 67 {350, 0x1a068447}, 68 {363, 0x382e0447}, 69 {375, 0x1c070447}, 70 {388, 0x3c2f0447}, 71 {400, 0x1e078447} 72 }; 73 74 static uint16_t encode_voltage(uint32_t v) 75 { 76 if (v == 0) 77 return 0xff; 78 79 return (((0x59 - (v - 5000) / 125) & 0xff) << 1 | 1); 80 } 81 82 static uint32_t decode_voltage(uint8_t v) 83 { 84 if (v == 0xff) 85 return 0; 86 87 return (0x59 - (v >> 1)) * 125 + 5000; 88 } 89 90 static uint32_t decode_cpm(uint32_t cpm) 91 { 92 int i; 93 94 for (i = 0; i < sizeof(g_freq_array) / sizeof(g_freq_array[0]); i++) { 95 if (g_freq_array[i][1] == cpm) 96 return g_freq_array[i][0]; 97 } 98 99 return 0; 100 } 101 102 static int avalonm_init_pkg(struct avalonm_pkg *pkg, uint8_t type, uint8_t idx, uint8_t cnt) 103 { 104 unsigned short crc; 105 106 pkg->head[0] = AVAM_H1; 107 pkg->head[1] = AVAM_H2; 108 109 pkg->type = type; 110 pkg->opt = 0; 111 pkg->idx = idx; 112 pkg->cnt = cnt; 113 114 crc = crc16(pkg->data, AVAM_P_DATA_LEN); 115 116 pkg->crc[0] = (crc & 0xff00) >> 8; 117 pkg->crc[1] = crc & 0x00ff; 118 return 0; 119 } 120 121 static float convert_temp(uint32_t adc) 122 { 123 float ret, resistance; 124 125 if (adc >= 1023) 126 return -273.15; 127 128 resistance = (1023.0 / adc) - 1; 129 resistance = R_REF / resistance; 130 ret = resistance / R0; 131 ret = log(ret); 132 ret /= BCOEFFICIENT; 133 ret += 1.0 / (T0 + 273.15); 134 ret = 1.0 / ret; 135 ret -= 273.15; 136 137 return ret; 138 } 139 140 static float convert_voltage(uint32_t adc, float percent) 141 { 142 float voltage; 143 144 voltage = adc * V_REF / 1023 / percent; 145 return voltage; 146 } 147 148 static void process_nonce(struct cgpu_info *avalonm, uint8_t *report) 149 { 150 struct avalonm_info *info = avalonm->device_data; 151 struct work *work; 152 uint8_t ntime, chip_id; 153 uint32_t nonce, id; 154 155 PACK32(report, &id); 156 chip_id = report[6]; 157 if (chip_id >= info->asic_cnts) { 158 applog(LOG_DEBUG, "%s-%d: chip_id >= info->asic_cnts(%d > %d)", 159 avalonm->drv->name, avalonm->device_id, 160 chip_id, info->asic_cnts); 161 return; 162 } 163 164 ntime = report[7]; 165 PACK32(report + 8, &nonce); 166 nonce -= 0x4000; 167 info->usbfifo_cnt = report[13]; 168 info->workfifo_cnt = report[14]; 169 info->noncefifo_cnt = report[15]; 170 171 applog(LOG_DEBUG, "%s-%d: Found! - ID: %08x CID: %02x N:%08x NR:%d", 172 avalonm->drv->name, avalonm->device_id, 173 id, chip_id, nonce, ntime); 174 175 work = clone_queued_work_byid(avalonm, id); 176 if (!work) 177 return; 178 179 if(!submit_noffset_nonce(info->thr, work, nonce, ntime)) { 180 info->hw_work[chip_id]++; 181 info->hw_work_i[chip_id][info->time_i]++; 182 } 183 184 info->matching_work[chip_id]++; 185 free_work(work); 186 info->nonce_cnts++; 187 } 188 189 static int decode_pkg(struct thr_info *thr, struct avalonm_ret *ar) 190 { 191 struct cgpu_info *avalonm = thr->cgpu; 192 struct avalonm_info *info = avalonm->device_data; 193 uint32_t ret, tmp, i, freq[3]; 194 unsigned int expected_crc; 195 unsigned int actual_crc; 196 197 if (ar->head[0] != AVAM_H1 && ar->head[1] != AVAM_H2) { 198 applog(LOG_DEBUG, "%s-%d: H1 %02x, H2 %02x", 199 avalonm->drv->name, avalonm->device_id, 200 ar->head[0], ar->head[1]); 201 info->crcerr_cnt++; 202 return 0; 203 } 204 205 expected_crc = crc16(ar->data, AVAM_P_DATA_LEN); 206 actual_crc = (ar->crc[1] & 0xff) | ((ar->crc[0] & 0xff) << 8); 207 if (expected_crc != actual_crc) { 208 applog(LOG_DEBUG, "%s-%d: %02x: expected crc(%04x), actual_crc(%04x)", 209 avalonm->drv->name, avalonm->device_id, 210 ar->type, expected_crc, actual_crc); 211 return 0; 212 } 213 214 switch(ar->type) { 215 case AVAM_P_NONCE_M: 216 ret = ar->type; 217 applog(LOG_DEBUG, "%s-%d: AVAM_P_NONCE", avalonm->drv->name, avalonm->device_id); 218 hexdump(ar->data, 32); 219 process_nonce(avalonm, ar->data); 220 if (ar->data[22] != 0xff) { 221 process_nonce(avalonm, ar->data + 16); 222 } 223 break; 224 case AVAM_P_STATUS_M: 225 ret = ar->type; 226 applog(LOG_DEBUG, "%s-%d: AVAM_P_STATUS_M", avalonm->drv->name, avalonm->device_id); 227 hexdump(ar->data, 32); 228 memcpy(&tmp, ar->data, 4); 229 if (!strncmp(info->ver, "3U", 2)) 230 info->get_frequency[0][0] = be32toh(tmp); 231 else 232 info->spi_speed = be32toh(tmp); 233 memcpy(&tmp, ar->data + 4, 4); 234 info->led_status = be32toh(tmp); 235 memcpy(&tmp, ar->data + 8, 4); 236 info->fan_pwm = be32toh(tmp); 237 memcpy(&tmp, ar->data + 12, 4); 238 if (!strncmp(info->ver, "3U", 2)) 239 info->get_voltage = convert_voltage(be32toh(tmp), 0.5); 240 else 241 info->get_voltage = decode_voltage((uint8_t)be32toh(tmp)); 242 memcpy(&tmp, ar->data + 16, 4); 243 info->adc[0] = be32toh(tmp); 244 memcpy(&tmp, ar->data + 20, 4); 245 info->adc[1] = be32toh(tmp); 246 memcpy(&tmp, ar->data + 24, 4); 247 info->adc[2] = be32toh(tmp); 248 memcpy(&tmp, ar->data + 28 , 4); 249 info->power_good = be32toh(tmp); 250 251 /* power off notice */ 252 if (!info->get_voltage) { 253 usb_buffer_clear(avalonm); 254 applog(LOG_NOTICE, "%s-%d: AVAM_P_STATUS_M Power off notice", avalonm->drv->name, avalonm->device_id); 255 info->power_on = 1; 256 memset(info->set_frequency, 0, sizeof(uint32_t) * info->asic_cnts * 3); 257 for (i = 1; i <= info->asic_cnts; i++) 258 FLAG_SET(info->freq_set, i); 259 } 260 break; 261 case AVAM_P_STATUS_FREQ: 262 applog(LOG_DEBUG, "%s-%d: AVAM_P_STATUS_FREQ", avalonm->drv->name, avalonm->device_id); 263 memcpy(&tmp, ar->data, 4); 264 tmp = be32toh(tmp); 265 freq[0] = decode_cpm(tmp); 266 memcpy(&tmp, ar->data + 4, 4); 267 tmp = be32toh(tmp); 268 freq[1] = decode_cpm(tmp); 269 memcpy(&tmp, ar->data + 8, 4); 270 tmp = be32toh(tmp); 271 freq[2] = decode_cpm(tmp); 272 273 if (!ar->opt) { 274 for (i = 0; i < info->asic_cnts; i++) { 275 info->get_frequency[i][0] = freq[0]; 276 info->get_frequency[i][1] = freq[1]; 277 info->get_frequency[i][2] = freq[2]; 278 } 279 } 280 281 if (ar->opt) { 282 info->get_frequency[ar->opt - 1][0] = freq[0]; 283 info->get_frequency[ar->opt - 1][1] = freq[1]; 284 info->get_frequency[ar->opt - 1][2] = freq[2]; 285 } 286 break; 287 default: 288 applog(LOG_DEBUG, "%s-%d: Unknown response (%x)", avalonm->drv->name, avalonm->device_id, 289 ar->type); 290 ret = 0; 291 break; 292 } 293 294 return ret; 295 } 296 297 static int avalonm_send_pkg(struct cgpu_info *avalonm, const struct avalonm_pkg *pkg) 298 { 299 int err = -1; 300 int writecnt; 301 302 if (unlikely(avalonm->usbinfo.nodev)) 303 return -1; 304 305 err = usb_write(avalonm, (char *)pkg, AVAM_P_COUNT, &writecnt, C_AVAM_WRITE); 306 if (err || writecnt != AVAM_P_COUNT) { 307 applog(LOG_DEBUG, "%s-%d: avalonm_send_pkg %d, w(%d-%d)!", avalonm->drv->name, avalonm->device_id, err, AVAM_P_COUNT, writecnt); 308 return -1; 309 } 310 311 return writecnt; 312 } 313 314 static int avalonm_receive_pkg(struct cgpu_info *avalonm, struct avalonm_ret *ret) 315 { 316 int err = -1; 317 int readcnt; 318 319 if (unlikely(avalonm->usbinfo.nodev)) 320 return -1; 321 322 err = usb_read(avalonm, (char*)ret, AVAM_P_COUNT, &readcnt, C_AVAM_READ); 323 if (err || readcnt != AVAM_P_COUNT) { 324 applog(LOG_DEBUG, "%s-%d: avalonm_receive_pkg %d, w(%d-%d)!", avalonm->drv->name, avalonm->device_id, err, AVAM_P_COUNT, readcnt); 325 return -1; 326 } 327 328 return readcnt; 329 } 330 331 static int avalonm_xfer_pkg(struct cgpu_info *avalonm, const struct avalonm_pkg *pkg, struct avalonm_ret *ret) 332 { 333 if (sizeof(struct avalonm_pkg) != avalonm_send_pkg(avalonm, pkg)) 334 return AVAM_SEND_ERROR; 335 336 if (sizeof(struct avalonm_ret) != avalonm_receive_pkg(avalonm, ret)) 337 return AVAM_SEND_ERROR; 338 339 return AVAM_SEND_OK; 340 } 341 342 static int avalonm_get_frequency(struct cgpu_info *avalonm, uint8_t asic_index) 343 { 344 struct avalonm_info *info = avalonm->device_data; 345 struct thr_info *thr = info->thr; 346 struct avalonm_pkg send_pkg; 347 struct avalonm_ret ar; 348 int ret = 0; 349 350 memset(send_pkg.data, 0, AVAM_P_DATA_LEN); 351 avalonm_init_pkg(&send_pkg, AVAM_P_GET_FREQ, 1, 1); 352 send_pkg.opt = asic_index; 353 ret = avalonm_xfer_pkg(avalonm, &send_pkg, &ar); 354 if (ret == AVAM_SEND_OK) { 355 ret = decode_pkg(thr, &ar); 356 } 357 358 return ret; 359 } 360 361 static void avalonm_set_spispeed(struct cgpu_info *avalonm, uint32_t speed) 362 { 363 struct avalonm_pkg send_pkg; 364 int tmp; 365 366 memset(send_pkg.data, 0, AVAM_P_DATA_LEN); 367 tmp = speed | 0x80000000; 368 tmp = be32toh(tmp); 369 memcpy(send_pkg.data, &tmp, 4); 370 avalonm_init_pkg(&send_pkg, AVAM_P_SETM, 1, 1); 371 avalonm_send_pkg(avalonm, &send_pkg); 372 } 373 374 static struct cgpu_info *avalonm_detect_one(struct libusb_device *dev, struct usb_find_devices *found) 375 { 376 struct cgpu_info *avalonm = usb_alloc_cgpu(&avalonm_drv, 1); 377 struct avalonm_info *info; 378 struct avalonm_pkg send_pkg; 379 struct avalonm_ret ar; 380 int ret, i; 381 382 if (!usb_init(avalonm, dev, found)) { 383 applog(LOG_ERR, "Avalonm failed usb_init"); 384 avalonm = usb_free_cgpu(avalonm); 385 return NULL; 386 } 387 388 usb_buffer_clear(avalonm); 389 update_usb_stats(avalonm); 390 391 /* Cleanup the usb fifo */ 392 while (avalonm_receive_pkg(avalonm, &ar) != -1); 393 394 /* We have an Avalonm connected */ 395 avalonm->threads = 1; 396 memset(send_pkg.data, 0, AVAM_P_DATA_LEN); 397 avalonm_init_pkg(&send_pkg, AVAM_P_DETECT, 1, 1); 398 ret = avalonm_xfer_pkg(avalonm, &send_pkg, &ar); 399 if ((ret != AVAM_SEND_OK) || (ar.type != AVAM_P_ACKDETECT)) { 400 applog(LOG_DEBUG, "%s-%d: Failed to detect Avalon miner", avalonm->drv->name, avalonm->device_id); 401 return NULL; 402 } 403 404 add_cgpu(avalonm); 405 406 applog(LOG_DEBUG, "%s-%d: Found at %s", avalonm->drv->name, avalonm->device_id, 407 avalonm->device_path); 408 409 avalonm->device_data = cgcalloc(sizeof(struct avalonm_info), 1); 410 info = avalonm->device_data; 411 info->thr = NULL; 412 memcpy(info->dna, ar.data, AVAM_MM_DNA_LEN); 413 memcpy(info->ver, ar.data + AVAM_MM_DNA_LEN, AVAM_MM_VER_LEN); 414 info->ver[AVAM_MM_VER_LEN] = '\0'; 415 memcpy(&info->asic_cnts, ar.data + AVAM_MM_DNA_LEN + AVAM_MM_VER_LEN, 4); 416 info->asic_cnts = be32toh(info->asic_cnts); 417 if (opt_avalonm_ntime_offset >= info->asic_cnts) 418 quit(1, "%s-%d: invalid opt_avalonm_ntime_offset, should 0-%d", avalonm->drv->name, avalonm->device_id, info->asic_cnts - 1); 419 420 memset(info->set_frequency, 0, sizeof(uint32_t) * info->asic_cnts * 3); 421 memset(info->get_frequency, 0, sizeof(uint32_t) * info->asic_cnts * 3); 422 for (i = 0; i < info->asic_cnts; i++) { 423 info->opt_freq[i][0] = opt_avalonm_freq[0]; 424 info->opt_freq[i][1] = opt_avalonm_freq[1]; 425 info->opt_freq[i][2] = opt_avalonm_freq[2]; 426 } 427 info->set_voltage = 0; 428 info->opt_voltage = opt_avalonm_voltage; 429 info->nonce_cnts = 0; 430 info->usbfifo_cnt = 0; 431 info->workfifo_cnt = 0; 432 info->noncefifo_cnt = 0; 433 info->crcerr_cnt = 0; 434 info->power_good = 0; 435 info->spi_speed = 0; 436 info->led_status = 0; 437 info->fan_pwm = 0; 438 info->get_voltage = 0; 439 info->freq_update = 0; 440 info->freq_set = 0; 441 FLAG_SET(info->freq_set, AVAM_ASIC_ALL); 442 memset(info->hw_work, 0, sizeof(int) * info->asic_cnts); 443 memset(info->matching_work, 0, sizeof(uint64_t) * info->asic_cnts); 444 info->adc[0] = info->adc[1] = info->adc[2] = 0; 445 446 avalonm_set_spispeed(avalonm, opt_avalonm_spispeed); 447 cgtime(&info->elapsed); 448 info->lastadj = info->lasttime = info->elapsed; 449 info->time_i = 0; 450 memset(info->hw_work_i, 0, sizeof(int) * info->asic_cnts * AVAM_DEFAULT_MOV_TIMES); 451 return avalonm; 452 } 453 454 static uint32_t avalonm_get_cpm(uint32_t freq) 455 { 456 int i; 457 458 for (i = 0; i < (sizeof(g_freq_array) / sizeof(g_freq_array[0]) - 1); i++) { 459 if (freq >= g_freq_array[i][0] && freq < g_freq_array[i+1][0]) 460 return g_freq_array[i][1]; 461 } 462 463 /* check if the final freq match */ 464 if (freq == g_freq_array[i][0]) 465 return g_freq_array[i][1]; 466 467 /* return the lowest freq if not found */ 468 return g_freq_array[0][1]; 469 } 470 471 static void avalonm_set_freq(struct cgpu_info *avalonm, uint8_t asic_index, uint32_t freq[]) 472 { 473 struct avalonm_info *info = avalonm->device_data; 474 struct avalonm_pkg send_pkg; 475 uint32_t tmp, i; 476 uint8_t index, change = 0; 477 uint32_t max_freq = 0; 478 479 if (asic_index == AVAM_ASIC_ALL) { 480 index = 0; 481 for (i = 0; i < info->asic_cnts; i++) { 482 if ((info->set_frequency[i][0] == freq[0]) && 483 (info->set_frequency[i][1] == freq[1]) && 484 (info->set_frequency[i][2] == freq[2])) 485 continue; 486 487 change = 1; 488 info->set_frequency[i][0] = freq[0]; 489 info->set_frequency[i][1] = freq[1]; 490 info->set_frequency[i][2] = freq[2]; 491 FLAG_SET(info->freq_update, AVAM_ASIC_ALL); 492 } 493 } 494 495 if (asic_index != AVAM_ASIC_ALL) { 496 index = asic_index - 1; 497 if (!((info->set_frequency[index][0] == freq[0]) && 498 (info->set_frequency[index][1] == freq[1]) && 499 (info->set_frequency[index][2] == freq[2]))) { 500 change = 1; 501 info->set_frequency[index][0] = freq[0]; 502 info->set_frequency[index][1] = freq[1]; 503 info->set_frequency[index][2] = freq[2]; 504 FLAG_SET(info->freq_update, asic_index); 505 } 506 } 507 508 if (!change) 509 return; 510 511 for (i = 0; i < info->asic_cnts; i++) { 512 if (max_freq < info->set_frequency[i][0]) 513 max_freq = info->set_frequency[i][0]; 514 515 if (max_freq < info->set_frequency[i][1]) 516 max_freq = info->set_frequency[i][1]; 517 518 if (max_freq < info->set_frequency[i][2]) 519 max_freq = info->set_frequency[i][2]; 520 } 521 522 info->delay_ms = CAL_DELAY(max_freq); 523 524 memset(send_pkg.data, 0, AVAM_P_DATA_LEN); 525 tmp = avalonm_get_cpm(freq[0]); 526 tmp = be32toh(tmp); 527 memcpy(send_pkg.data, &tmp, 4); 528 tmp = avalonm_get_cpm(freq[1]); 529 tmp = be32toh(tmp); 530 memcpy(send_pkg.data + 4, &tmp, 4); 531 tmp = avalonm_get_cpm(freq[2]); 532 tmp = be32toh(tmp); 533 memcpy(send_pkg.data + 8, &tmp, 4); 534 535 avalonm_init_pkg(&send_pkg, AVAM_P_SET_FREQ, 1, 1); 536 send_pkg.opt = asic_index; 537 avalonm_send_pkg(avalonm, &send_pkg); 538 applog(LOG_NOTICE, "%s-%d: Avalonm set asic_index %d freq %d,%d,%d", 539 avalonm->drv->name, avalonm->device_id, 540 asic_index, 541 freq[0], 542 freq[1], 543 freq[2]); 544 } 545 546 static void avalonm_set_voltage(struct cgpu_info *avalonm) 547 { 548 struct avalonm_info *info = avalonm->device_data; 549 struct avalonm_pkg send_pkg; 550 uint16_t tmp; 551 552 if (!info->power_on && (info->set_voltage == info->opt_voltage)) 553 return; 554 555 info->set_voltage = info->opt_voltage; 556 memset(send_pkg.data, 0, AVAM_P_DATA_LEN); 557 /* Use shifter to set voltage */ 558 tmp = info->set_voltage; 559 tmp = encode_voltage(tmp); 560 tmp = htobe16(tmp); 561 memcpy(send_pkg.data, &tmp, 2); 562 563 /* Package the data */ 564 avalonm_init_pkg(&send_pkg, AVAM_P_SET_VOLT, 1, 1); 565 avalonm_send_pkg(avalonm, &send_pkg); 566 applog(LOG_NOTICE, "%s-%d: Avalonm set volt %d", 567 avalonm->drv->name, avalonm->device_id, 568 info->set_voltage); 569 570 if (info->power_on) 571 cgsleep_ms(1000); 572 573 info->power_on = 0; 574 } 575 576 static inline void avalonm_detect(bool __maybe_unused hotplug) 577 { 578 usb_detect(&avalonm_drv, avalonm_detect_one); 579 } 580 581 static int avalonm_get_reports(void *userdata) 582 { 583 struct cgpu_info *avalonm = (struct cgpu_info *)userdata; 584 struct avalonm_info *info = avalonm->device_data; 585 struct thr_info *thr = info->thr; 586 struct avalonm_pkg send_pkg; 587 struct avalonm_ret ar; 588 int ret = 0; 589 590 memset(send_pkg.data, 0, AVAM_P_DATA_LEN); 591 avalonm_init_pkg(&send_pkg, AVAM_P_POLLING, 1, 1); 592 ret = avalonm_xfer_pkg(avalonm, &send_pkg, &ar); 593 if (ret == AVAM_SEND_OK) { 594 ret = decode_pkg(thr, &ar); 595 } 596 597 return ret; 598 } 599 600 static void rev(unsigned char *s, size_t l) 601 { 602 size_t i, j; 603 unsigned char t; 604 605 for (i = 0, j = l - 1; i < j; i++, j--) { 606 t = s[i]; 607 s[i] = s[j]; 608 s[j] = t; 609 } 610 } 611 612 static int64_t avalonm_scanhash(struct thr_info *thr) 613 { 614 struct cgpu_info *avalonm = thr->cgpu; 615 struct avalonm_info *info = avalonm->device_data; 616 int64_t hash_count, ms_timeout; 617 struct timeval current; 618 double device_tdiff; 619 uint32_t i, j, tmp; 620 621 /* Half nonce range */ 622 ms_timeout = 0x80000000ll / 1000; 623 624 /* Wait until avalon_send_tasks signals us that it has completed 625 * sending its work or a full nonce range timeout has occurred. We use 626 * cgsems to never miss a wakeup. */ 627 cgsem_mswait(&info->qsem, ms_timeout); 628 629 hash_count = info->nonce_cnts++; 630 info->nonce_cnts = 0; 631 632 cgtime(¤t); 633 device_tdiff = tdiff(¤t, &(info->lastadj)); 634 if (opt_avalonm_autof && (device_tdiff > AVAM_DEFAULT_ADJ_INTERVAL || device_tdiff < 0)) { 635 copy_time(&info->lastadj, ¤t); 636 637 for (i = 0; i < AVAM_DEFAULT_ASIC_COUNT; i++) { 638 tmp = 0; 639 for (j = 0; j < AVAM_DEFAULT_MOV_TIMES; j++) 640 tmp += info->hw_work_i[i][j]; 641 642 if (tmp > AVAM_HW_HIGH && (info->opt_freq[i][0] > opt_avalonm_freq[0] - (uint32_t)(12 * 12.5))) { 643 if ((info->opt_freq[i][0] == AVAM_DEFAULT_FREQUENCY_MIN) && 644 (info->opt_freq[i][1] == AVAM_DEFAULT_FREQUENCY_MIN) && 645 (info->opt_freq[i][2] == AVAM_DEFAULT_FREQUENCY_MIN)) 646 continue; 647 648 if (info->opt_freq[i][0] * 10 % 125) 649 info->opt_freq[i][0] -= 13; 650 else 651 info->opt_freq[i][0] -= 12; 652 653 if (info->opt_freq[i][1] * 10 % 125) 654 info->opt_freq[i][1] -= 13; 655 else 656 info->opt_freq[i][1] -= 12; 657 658 if (info->opt_freq[i][2] * 10 % 125) 659 info->opt_freq[i][2] -= 13; 660 else 661 info->opt_freq[i][2] -= 12; 662 663 if (info->opt_freq[i][0] < AVAM_DEFAULT_FREQUENCY_MIN) 664 info->opt_freq[i][0] = AVAM_DEFAULT_FREQUENCY_MIN; 665 666 if (info->opt_freq[i][1] < AVAM_DEFAULT_FREQUENCY_MIN) 667 info->opt_freq[i][1] = AVAM_DEFAULT_FREQUENCY_MIN; 668 669 if (info->opt_freq[i][2] < AVAM_DEFAULT_FREQUENCY_MIN) 670 info->opt_freq[i][2] = AVAM_DEFAULT_FREQUENCY_MIN; 671 672 FLAG_SET(info->freq_set, i + 1); 673 applog(LOG_NOTICE, "%s-%d: Automatic decrease [%d] freq to %d,%d,%d", 674 avalonm->drv->name, avalonm->device_id, i, 675 info->opt_freq[i][0], 676 info->opt_freq[i][1], 677 info->opt_freq[i][2]); 678 } 679 680 if (tmp < AVAM_HW_LOW && (info->opt_freq[i][0] < opt_avalonm_freq[0] + (uint32_t)(8 * 12.5))) { 681 if ((info->opt_freq[i][0] == AVAM_DEFAULT_FREQUENCY_MAX) && 682 (info->opt_freq[i][1] == AVAM_DEFAULT_FREQUENCY_MAX) && 683 (info->opt_freq[i][2] == AVAM_DEFAULT_FREQUENCY_MAX)) 684 continue; 685 686 if (info->opt_freq[i][0] * 10 % 125) 687 info->opt_freq[i][0] += 12; 688 else 689 info->opt_freq[i][0] += 13; 690 691 if (info->opt_freq[i][1] * 10 % 125) 692 info->opt_freq[i][1] += 12; 693 else 694 info->opt_freq[i][1] += 13; 695 696 if (info->opt_freq[i][2] * 10 % 125) 697 info->opt_freq[i][2] += 12; 698 else 699 info->opt_freq[i][2] += 13; 700 701 if (info->opt_freq[i][0] > AVAM_DEFAULT_FREQUENCY_MAX) 702 info->opt_freq[i][0] = AVAM_DEFAULT_FREQUENCY_MAX; 703 704 if (info->opt_freq[i][1] > AVAM_DEFAULT_FREQUENCY_MAX) 705 info->opt_freq[i][1] = AVAM_DEFAULT_FREQUENCY_MAX; 706 707 if (info->opt_freq[i][2] > AVAM_DEFAULT_FREQUENCY_MAX) 708 info->opt_freq[i][2] = AVAM_DEFAULT_FREQUENCY_MAX; 709 710 FLAG_SET(info->freq_set, i + 1); 711 applog(LOG_NOTICE, "%s-%d: Automatic increase [%d] freq to %d,%d,%d", 712 avalonm->drv->name, avalonm->device_id, i, 713 info->opt_freq[i][0], 714 info->opt_freq[i][1], 715 info->opt_freq[i][2]); 716 } 717 } 718 } 719 720 return hash_count * 0xffffffffull; 721 } 722 723 static void avalonm_rotate_array(struct cgpu_info *avalonm, struct avalonm_info *info) 724 { 725 mutex_lock(&info->qlock); 726 avalonm->queued = 0; 727 if (++avalonm->work_array >= AVAM_DEFAULT_ARRAY_SIZE) 728 avalonm->work_array = 0; 729 mutex_unlock(&info->qlock); 730 } 731 732 static void *avalonm_process_tasks(void *userdata) 733 { 734 char threadname[16]; 735 736 struct cgpu_info *avalonm = userdata; 737 struct avalonm_info *info = avalonm->device_data; 738 struct work *work; 739 struct avalonm_pkg send_pkg; 740 741 int start_count, end_count, i, j, k, ret; 742 int avalon_get_work_count = info->asic_cnts; 743 struct timeval current; 744 double device_tdiff; 745 746 snprintf(threadname, sizeof(threadname), "%d/AvmProc", avalonm->device_id); 747 RenameThread(threadname); 748 749 while (likely(!avalonm->shutdown)) { 750 if (unlikely(avalonm->usbinfo.nodev)) { 751 applog(LOG_ERR, "%s-%d: Device disappeared, shutting down thread", 752 avalonm->drv->name, avalonm->device_id); 753 goto out; 754 } 755 756 cgtime(¤t); 757 device_tdiff = tdiff(¤t, &(info->lasttime)); 758 if (device_tdiff >= AVAM_DEFAULT_MOV_TIMES || device_tdiff < 0) { 759 copy_time(&info->lasttime, ¤t); 760 if (info->time_i++ >= AVAM_DEFAULT_MOV_TIMES) 761 info->time_i = 0; 762 763 for(i = 0; i < AVAM_DEFAULT_ASIC_COUNT; i++) 764 info->hw_work_i[i][info->time_i] = 0; 765 } 766 767 /* Give other threads a chance to acquire qlock. */ 768 i = 0; 769 do { 770 cgsleep_ms(40); 771 } while (!avalonm->shutdown && avalonm->queued < avalon_get_work_count); 772 773 mutex_lock(&info->qlock); 774 775 start_count = avalonm->work_array * avalon_get_work_count; 776 end_count = start_count + avalon_get_work_count; 777 778 for (i = start_count, j = 0; i < end_count; i++, j++) { 779 work = avalonm->works[i]; 780 if (likely(j < avalonm->queued && avalonm->works[i] && j < (info->asic_cnts - opt_avalonm_ntime_offset))) { 781 /* Configuration */ 782 avalonm_set_voltage(avalonm); 783 784 if (FLAG_GET(info->freq_set, 0)) { 785 avalonm_set_freq(avalonm, AVAM_ASIC_ALL, info->opt_freq[0]); 786 FLAG_CLEAR(info->freq_set, 0); 787 cgsleep_ms(20); 788 } 789 790 for (k = 1; k <= info->asic_cnts; k++) { 791 if (FLAG_GET(info->freq_set, k)) { 792 avalonm_set_freq(avalonm, k, info->opt_freq[k - 1]); 793 FLAG_CLEAR(info->freq_set, k); 794 cgsleep_ms(20); 795 } 796 } 797 798 /* P_WORK part 1: midstate */ 799 memcpy(send_pkg.data, work->midstate, AVAM_P_DATA_LEN); 800 rev((void *)(send_pkg.data), AVAM_P_DATA_LEN); 801 avalonm_init_pkg(&send_pkg, AVAM_P_WORK, 1, 2); 802 hexdump(send_pkg.data, 32); 803 avalonm_send_pkg(avalonm, &send_pkg); 804 if (info->freq_update) 805 cgsleep_ms(300); 806 807 /* P_WORK part 2: 808 * id(6)+reserved(2)+ntime(1)+fan(3)+led(4)+reserved(4)+data(12) */ 809 memset(send_pkg.data, 0, AVAM_P_DATA_LEN); 810 811 UNPACK32(work->id, send_pkg.data); 812 813 /* always roll work 0 */ 814 if (j == 0) 815 send_pkg.data[8] = opt_avalonm_ntime_offset; 816 else 817 send_pkg.data[8] = 0; 818 819 /* TODO led */ 820 UNPACK32(0, send_pkg.data + 12); 821 822 memcpy(send_pkg.data + 20, work->data + 64, 12); 823 rev((void *)(send_pkg.data + 20), 12); 824 avalonm_init_pkg(&send_pkg, AVAM_P_WORK, 2, 2); 825 hexdump(send_pkg.data, 32); 826 avalonm_send_pkg(avalonm, &send_pkg); 827 if (info->freq_update) 828 cgsleep_ms(300); 829 } 830 } 831 832 mutex_unlock(&info->qlock); 833 avalonm_rotate_array(avalonm, info); 834 835 cgsem_post(&info->qsem); 836 837 /* little delay, let asics process more job */ 838 if (!strncmp(info->ver, "3U", 2)) 839 cgsleep_ms(400); 840 841 /* Get result */ 842 do { 843 ret = avalonm_get_reports(avalonm); 844 cgsleep_ms(5); 845 } while (ret != AVAM_P_STATUS_M); 846 847 if (info->freq_update) { 848 applog(LOG_NOTICE, "%s-%d: avalonm_process_tasks freq change flag %02x", 849 avalonm->drv->name, avalonm->device_id, 850 info->freq_update); 851 if (FLAG_GET(info->freq_update, 0)) { 852 avalonm_get_frequency(avalonm, 0); 853 FLAG_CLEAR(info->freq_update, 0); 854 } 855 856 for (i = 1; i <= info->asic_cnts; i++) { 857 if (FLAG_GET(info->freq_update, i)) { 858 avalonm_get_frequency(avalonm, i); 859 FLAG_CLEAR(info->freq_update, i); 860 } 861 } 862 } 863 864 cgsleep_ms(info->delay_ms); 865 } 866 867 out: 868 return NULL; 869 } 870 871 static bool avalonm_prepare(struct thr_info *thr) 872 { 873 struct cgpu_info *avalonm = thr->cgpu; 874 struct avalonm_info *info = avalonm->device_data; 875 876 free(avalonm->works); 877 avalonm->works = calloc(info->asic_cnts * sizeof(struct work *), 878 AVAM_DEFAULT_ARRAY_SIZE); 879 if (!avalonm->works) 880 quit(1, "Failed to calloc avalon miner works in avalonm_prepare"); 881 882 info->thr = thr; 883 info->delay_ms = CAL_DELAY(AVAM_DEFAULT_FREQUENCY); 884 info->power_on = 1; 885 886 mutex_init(&info->lock); 887 mutex_init(&info->qlock); 888 cgsem_init(&info->qsem); 889 890 if (pthread_create(&info->process_thr, NULL, avalonm_process_tasks, (void *)avalonm)) 891 quit(1, "Failed to create avalonm process_thr"); 892 893 return true; 894 } 895 896 static void avalonm_shutdown(struct thr_info *thr) 897 { 898 struct cgpu_info *avalonm = thr->cgpu; 899 struct avalonm_info *info = avalonm->device_data; 900 901 pthread_join(info->process_thr, NULL); 902 903 cgsem_destroy(&info->qsem); 904 mutex_destroy(&info->qlock); 905 mutex_destroy(&info->lock); 906 free(avalonm->works); 907 avalonm->works = NULL; 908 } 909 910 char *set_avalonm_freq(char *arg) 911 { 912 char *colon1, *colon2; 913 int val1 = 0, val2 = 0, val3 = 0; 914 915 if (!(*arg)) 916 return NULL; 917 918 colon1 = strchr(arg, ':'); 919 if (colon1) 920 *(colon1++) = '\0'; 921 922 if (*arg) { 923 val1 = atoi(arg); 924 if (val1 < AVAM_DEFAULT_FREQUENCY_MIN || val1 > AVAM_DEFAULT_FREQUENCY_MAX) 925 return "Invalid value1 passed to set_avalonm_freq"; 926 } 927 928 if (colon1 && *colon1) { 929 colon2 = strchr(colon1, ':'); 930 if (colon2) 931 *(colon2++) = '\0'; 932 933 if (*colon1) { 934 val2 = atoi(colon1); 935 if (val2 < AVAM_DEFAULT_FREQUENCY_MIN || val2 > AVAM_DEFAULT_FREQUENCY_MAX) 936 return "Invalid value2 passed to set_avalonm_freq"; 937 } 938 939 if (colon2 && *colon2) { 940 val3 = atoi(colon2); 941 if (val3 < AVAM_DEFAULT_FREQUENCY_MIN || val3 > AVAM_DEFAULT_FREQUENCY_MAX) 942 return "Invalid value3 passed to set_avalonm_freq"; 943 } 944 } 945 946 if (!val1) 947 val3 = val2 = val1 = AVAM_DEFAULT_FREQUENCY; 948 949 if (!val2) 950 val3 = val2 = val1; 951 952 if (!val3) 953 val3 = val2; 954 955 opt_avalonm_freq[0] = val1; 956 opt_avalonm_freq[1] = val2; 957 opt_avalonm_freq[2] = val3; 958 applog(LOG_NOTICE, "Update all asic frequency to %d", 959 (opt_avalonm_freq[0] * 4 + opt_avalonm_freq[1] * 4 + opt_avalonm_freq[2]) / 9); 960 961 return NULL; 962 } 963 964 char *set_avalonm_device_freq(struct cgpu_info *avalonm, char *arg) 965 { 966 struct avalonm_info *info = avalonm->device_data; 967 char *colon1, *colon2; 968 int val1 = 0, val2 = 0, val3 = 0; 969 int asic_index = AVAM_ASIC_ALL; 970 uint8_t i; 971 972 if (!(*arg)) 973 return NULL; 974 975 colon1 = strchr(arg, '-'); 976 if (colon1) { 977 sscanf(arg, "%d-", &asic_index); 978 arg = colon1 + 1; 979 if (asic_index < 0 || asic_index > info->asic_cnts) { 980 applog(LOG_ERR, "invalid asic index: %d, valid range 0-%d", asic_index, info->asic_cnts); 981 return "Invalid asic index to set_avalonm_freq"; 982 } 983 } 984 985 colon1 = strchr(arg, ':'); 986 if (colon1) 987 *(colon1++) = '\0'; 988 989 if (*arg) { 990 val1 = atoi(arg); 991 if (val1 < AVAM_DEFAULT_FREQUENCY_MIN || val1 > AVAM_DEFAULT_FREQUENCY_MAX) 992 return "Invalid value1 passed to set_avalonm_freq"; 993 } 994 995 if (colon1 && *colon1) { 996 colon2 = strchr(colon1, ':'); 997 if (colon2) 998 *(colon2++) = '\0'; 999 1000 if (*colon1) { 1001 val2 = atoi(colon1); 1002 if (val2 < AVAM_DEFAULT_FREQUENCY_MIN || val2 > AVAM_DEFAULT_FREQUENCY_MAX) 1003 return "Invalid value2 passed to set_avalonm_freq"; 1004 } 1005 1006 if (colon2 && *colon2) { 1007 val3 = atoi(colon2); 1008 if (val3 < AVAM_DEFAULT_FREQUENCY_MIN || val3 > AVAM_DEFAULT_FREQUENCY_MAX) 1009 return "Invalid value3 passed to set_avalonm_freq"; 1010 } 1011 } 1012 1013 if (!val1) 1014 val3 = val2 = val1 = AVAM_DEFAULT_FREQUENCY; 1015 1016 if (!val2) 1017 val3 = val2 = val1; 1018 1019 if (!val3) 1020 val3 = val2; 1021 1022 if (!asic_index) { 1023 for (i = 0; i < info->asic_cnts; i++) { 1024 info->opt_freq[i][0] = val1; 1025 info->opt_freq[i][1] = val2; 1026 info->opt_freq[i][2] = val3; 1027 } 1028 FLAG_SET(info->freq_set, AVAM_ASIC_ALL); 1029 applog(LOG_NOTICE, "Update all asic frequency to %d", 1030 (val1 * 4 + val2 * 4 + val3) / 9); 1031 } 1032 1033 if (asic_index) { 1034 info->opt_freq[asic_index - 1][0] = val1; 1035 info->opt_freq[asic_index - 1][1] = val2; 1036 info->opt_freq[asic_index - 1][2] = val3; 1037 1038 FLAG_SET(info->freq_set, asic_index); 1039 applog(LOG_NOTICE, "Update asic %d frequency to %d", 1040 asic_index - 1, 1041 (val1 * 4 + val2 * 4 + val3) / 9); 1042 } 1043 1044 return NULL; 1045 } 1046 1047 char *set_avalonm_voltage(char *arg) 1048 { 1049 int val, ret; 1050 1051 ret = sscanf(arg, "%d", &val); 1052 if (ret < 1) 1053 return "No values passed to avalonm-voltage"; 1054 1055 if (val < AVAM_DEFAULT_VOLTAGE_MIN || val > AVAM_DEFAULT_VOLTAGE_MAX) 1056 return "Invalid value passed to avalonm-voltage"; 1057 1058 opt_avalonm_voltage = val; 1059 1060 return NULL; 1061 } 1062 1063 char *set_avalonm_device_voltage(struct cgpu_info *avalonm, char *arg) 1064 { 1065 struct avalonm_info *info = avalonm->device_data; 1066 int val, ret; 1067 1068 ret = sscanf(arg, "%d", &val); 1069 if (ret < 1) 1070 return "No values passed to avalonm-voltage"; 1071 1072 if (val < AVAM_DEFAULT_VOLTAGE_MIN || val > AVAM_DEFAULT_VOLTAGE_MAX) 1073 return "Invalid value passed to avalonm-voltage"; 1074 1075 info->opt_voltage = val; 1076 applog(LOG_NOTICE, "%s-%d: Update voltage to %d", 1077 avalonm->drv->name, avalonm->device_id, info->opt_voltage); 1078 1079 return NULL; 1080 } 1081 1082 static char *avalonm_set_device(struct cgpu_info *avalonm, char *option, char *setting, char *replybuf) 1083 { 1084 if (strcasecmp(option, "help") == 0) { 1085 sprintf(replybuf, "frequency|voltage"); 1086 return replybuf; 1087 } 1088 1089 if (strcasecmp(option, "frequency") == 0) { 1090 if (!setting || !*setting) { 1091 sprintf(replybuf, "missing frequency value"); 1092 return replybuf; 1093 } 1094 1095 if (set_avalonm_device_freq(avalonm, setting)) { 1096 sprintf(replybuf, "invalid frequency value, valid range %d-%d", 1097 AVAM_DEFAULT_FREQUENCY_MIN, AVAM_DEFAULT_FREQUENCY_MAX); 1098 return replybuf; 1099 } 1100 1101 return NULL; 1102 } 1103 1104 if (strcasecmp(option, "voltage") == 0) { 1105 if (!setting || !*setting) { 1106 sprintf(replybuf, "missing voltage value"); 1107 return replybuf; 1108 } 1109 1110 if (set_avalonm_device_voltage(avalonm, setting)) { 1111 sprintf(replybuf, "invalid voltage value, valid range %d-%d", 1112 AVAM_DEFAULT_VOLTAGE_MIN, AVAM_DEFAULT_VOLTAGE_MAX); 1113 return replybuf; 1114 } 1115 1116 return NULL; 1117 } 1118 1119 sprintf(replybuf, "Unknown option: %s", option); 1120 return replybuf; 1121 } 1122 1123 #define STATBUFLEN 512 1124 static struct api_data *avalonm_api_stats(struct cgpu_info *cgpu) 1125 { 1126 struct api_data *root = NULL; 1127 struct avalonm_info *info = cgpu->device_data; 1128 char buf[256]; 1129 char statbuf[STATBUFLEN]; 1130 uint32_t i, j, tmp; 1131 struct timeval now; 1132 1133 memset(statbuf, 0, STATBUFLEN); 1134 1135 sprintf(buf, "VER[%s]", info->ver); 1136 strcat(statbuf, buf); 1137 1138 sprintf(buf, " DNA[%02x%02x%02x%02x%02x%02x%02x%02x]", 1139 info->dna[0], 1140 info->dna[1], 1141 info->dna[2], 1142 info->dna[3], 1143 info->dna[4], 1144 info->dna[5], 1145 info->dna[6], 1146 info->dna[7]); 1147 strcat(statbuf, buf); 1148 1149 cgtime(&now); 1150 sprintf(buf, " Elapsed[%.0f]", tdiff(&now, &(info->elapsed))); 1151 strcat(statbuf, buf); 1152 1153 sprintf(buf, " Chips[%d]", info->asic_cnts); 1154 strcat(statbuf, buf); 1155 1156 sprintf(buf, " Crc[%d]", info->crcerr_cnt); 1157 strcat(statbuf, buf); 1158 1159 sprintf(buf, " Speed[%d]", info->spi_speed); 1160 strcat(statbuf, buf); 1161 1162 if (!strncmp(info->ver, "3U", 2)) 1163 sprintf(buf, " Vol[%.2f]", (float)info->get_voltage); 1164 else 1165 sprintf(buf, " Vol[%.4f]", (float)info->get_voltage / 10000); 1166 strcat(statbuf, buf); 1167 1168 if (!strncmp(info->ver, "3U", 2)) 1169 sprintf(buf, " V_CORE[%.2f]", convert_voltage(info->adc[0], 1)); 1170 else 1171 sprintf(buf, " V12[%.2f]", convert_voltage(info->adc[0], (10 / 110))); 1172 strcat(statbuf, buf); 1173 1174 if (!strncmp(info->ver, "3U", 2)) 1175 sprintf(buf, " T[%d]", info->adc[1]); 1176 else 1177 sprintf(buf, " TC[%.2f]", convert_temp(info->adc[1])); 1178 strcat(statbuf, buf); 1179 1180 if (!strncmp(info->ver, "3U", 2)) { 1181 sprintf(buf, " V0_9[%.2f]", convert_voltage(info->adc[2] & 0xffff, 1)); 1182 strcat(statbuf, buf); 1183 sprintf(buf, " V1_8[%.2f]", convert_voltage((info->adc[2] >> 16) & 0xffff, 1)); 1184 } else 1185 sprintf(buf, " TF[%.2f]", convert_temp(info->adc[2])); 1186 strcat(statbuf, buf); 1187 1188 if (!strncmp(info->ver, "3U", 2)) { 1189 sprintf(buf, " Freq[%d]", info->get_frequency[0][0]); 1190 strcat(statbuf, buf); 1191 } else { 1192 strcat(statbuf, " Freq["); 1193 for (i = 0; i < info->asic_cnts; i++) { 1194 sprintf(buf, "%d %d %d ", 1195 info->get_frequency[i][0], 1196 info->get_frequency[i][1], 1197 info->get_frequency[i][2]); 1198 strcat(statbuf, buf); 1199 } 1200 statbuf[strlen(statbuf) - 1] = ']'; 1201 } 1202 1203 strcat(statbuf, " HW["); 1204 for (i = 0; i < info->asic_cnts; i++) { 1205 sprintf(buf, "%d ", info->hw_work[i]); 1206 strcat(statbuf, buf); 1207 } 1208 statbuf[strlen(statbuf) - 1] = ']'; 1209 1210 /* simple moving the sum of hardware error */ 1211 strcat(statbuf, " SHW["); 1212 for (i = 0; i < info->asic_cnts; i++) { 1213 tmp = 0; 1214 for (j = 0; j < AVAM_DEFAULT_MOV_TIMES; j++) 1215 tmp += info->hw_work_i[i][j]; 1216 1217 sprintf(buf, "%d ", tmp); 1218 strcat(statbuf, buf); 1219 } 1220 statbuf[strlen(statbuf) - 1] = ']'; 1221 1222 strcat(statbuf, " MW["); 1223 for (i = 0; i < info->asic_cnts; i++) { 1224 sprintf(buf, "%ld ", info->matching_work[i]); 1225 strcat(statbuf, buf); 1226 } 1227 statbuf[strlen(statbuf) - 1] = ']'; 1228 1229 sprintf(buf, " Led[%d]", info->led_status); 1230 strcat(statbuf, buf); 1231 1232 sprintf(buf, " PG[%d]", info->power_good); 1233 strcat(statbuf, buf); 1234 1235 root = api_add_string(root, "AVAM Dev", statbuf, true); 1236 1237 sprintf(buf, "%d %d %d", 1238 info->usbfifo_cnt, 1239 info->workfifo_cnt, 1240 info->noncefifo_cnt); 1241 1242 root = api_add_string(root, "AVAM Fifo", buf, true); 1243 root = api_add_uint8(root, "AVAM ntime", &opt_avalonm_ntime_offset, true); 1244 root = api_add_bool(root, "Automatic Frequency", &opt_avalonm_autof, true); 1245 return root; 1246 } 1247 1248 static void avalonm_statline_before(char *buf, size_t bufsiz, struct cgpu_info *avalonm) 1249 { 1250 struct avalonm_info *info = avalonm->device_data; 1251 int frequency; 1252 1253 if (!strncmp(info->ver, "3U", 2)) 1254 tailsprintf(buf, bufsiz, "%4dMhz %.2fV", info->get_frequency[0][0], (float)info->get_voltage); 1255 else { 1256 frequency = (info->set_frequency[0][0] * 4 + info->set_frequency[0][1] * 4 + info->set_frequency[0][2]) / 9; 1257 tailsprintf(buf, bufsiz, "%4dMhz %.4fV", frequency, (float)info->get_voltage / 10000); 1258 } 1259 } 1260 1261 /* We use a replacement algorithm to only remove references to work done from 1262 * the buffer when we need the extra space for new work. */ 1263 static bool avalonm_fill(struct cgpu_info *avalonm) 1264 { 1265 struct avalonm_info *info = avalonm->device_data; 1266 int subid, slot, ac; 1267 struct work *work; 1268 bool ret = true; 1269 1270 ac = info->asic_cnts; 1271 mutex_lock(&info->qlock); 1272 if (avalonm->queued >= ac) 1273 goto out_unlock; 1274 work = get_queued(avalonm); 1275 if (unlikely(!work)) { 1276 ret = false; 1277 goto out_unlock; 1278 } 1279 subid = avalonm->queued++; 1280 work->subid = subid; 1281 slot = avalonm->work_array * ac + subid; 1282 if (likely(avalonm->works[slot])) 1283 work_completed(avalonm, avalonm->works[slot]); 1284 avalonm->works[slot] = work; 1285 if (avalonm->queued < ac) 1286 ret = false; 1287 out_unlock: 1288 mutex_unlock(&info->qlock); 1289 1290 return ret; 1291 } 1292 1293 static void avalonm_flush_work(struct cgpu_info *avalonm) 1294 { 1295 1296 struct avalonm_info *info = avalonm->device_data; 1297 1298 /* Will overwrite any work queued. Do this unlocked since it's just 1299 * changing a single non-critical value and prevents deadlocks */ 1300 avalonm->queued = 0; 1301 1302 /* Signal main loop we need more work */ 1303 cgsem_post(&info->qsem); 1304 } 1305 1306 struct device_drv avalonm_drv = { 1307 .drv_id = DRIVER_avalonm, 1308 .dname = "avalonm", 1309 .name = "AVM", 1310 .set_device = avalonm_set_device, 1311 .get_api_stats = avalonm_api_stats, 1312 .get_statline_before = avalonm_statline_before, 1313 .drv_detect = avalonm_detect, 1314 .thread_prepare = avalonm_prepare, 1315 1316 .hash_work = hash_queued_work, 1317 .scanwork = avalonm_scanhash, 1318 .queue_full = avalonm_fill, 1319 .flush_work = avalonm_flush_work, 1320 1321 .thread_shutdown = avalonm_shutdown, 1322 };