Merge pull request #626 from kanoi/master minion changes for SPI problems
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 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
diff --git a/API-README b/API-README
index 62d3c47..29ee2a5 100644
--- a/API-README
+++ b/API-README
@@ -443,6 +443,12 @@ The list of requests - a (*) means it requires privileged access - and replies:
AVA+BTB opt=freq val=256 to 1024 - chip frequency
BTB opt=millivolts val=1000 to 1400 - corevoltage
MBA opt=reset val=0 to chipcount - reset a chip
+ MBA opt=freq val=0-chip:100-1400 - set chip freq
+ MBA opt=ledcount val=0-100 - chip count for led
+ MBA opt=ledlimit val=0-200 - led off below GHs
+ MBA opt=spidelay val=0-9999 - SPI per I/O delay
+ MBA opt=spireset i|s0-9999 - SPI regular reset
+ MBA opt=spisleep val=0-9999 - SPI reset sleep ms
lcd LCD An all-in-one short status summary of the miner
e.g. Elapsed,GHS av,GHS 5m,GHS 5s,Temp,
diff --git a/ASIC-README b/ASIC-README
index 3756238..2e9ef1e 100644
--- a/ASIC-README
+++ b/ASIC-README
@@ -241,10 +241,16 @@ ASIC SPECIFIC COMMANDS
--hfa-temp-target <arg> Set the hashfast target temperature (0 to disable) (default: 88)
--klondike-options <arg> Set klondike options clock:temptarget
--minion-chipreport <arg> Seconds to report chip 5min hashrate, range 0-100 (default: 0=disabled)
---minion-freq <arg> Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1000)
+--minion-freq <arg> Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1200)
+--minion-idlecount Report when IdleCount is >0 or changes
+--minion-ledcount Turn off led when more than this many chips below the ledlimit (default: 0)
+--minion-ledlimit Turn off led when chips GHs are below this (default: 90)
--minion-idlecount Report when IdleCount is >0 or changes
--minion-noautofreq Disable automatic frequency adjustment
--minion-overheat Enable directly halting any chip when the status exceeds 100C
+--minion-spidelay Add a delay in microseconds after each SPI I/O
+--minion-spireset SPI regular reset: iNNN for I/O count or sNNN for seconds - 0 means none
+--minion-spisleep Sleep time in milliseconds when doing an SPI reset
--minion-temp <arg> Set minion chip temperature threshold, single value or comma list, range 120-160 (default: 135C)
--nfu-bits <arg> Set nanofury bits for overclocking, range 32-63 (default: 50)
--rock-freq <arg> Set RockMiner frequency in MHz, range 125-500 (default: 270)
diff --git a/README b/README
index eb60b17..f537172 100644
--- a/README
+++ b/README
@@ -219,10 +219,15 @@ Options for both config file and command line:
--log|-l <arg> Interval in seconds between log output (default: 5)
--lowmem Minimise caching of shares for low memory applications
--minion-chipreport <arg> Seconds to report chip 5min hashrate, range 0-100 (default: 0=disabled)
---minion-freq <arg> Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1000)
+--minion-freq <arg> Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1200)
--minion-idlecount Report when IdleCount is >0 or changes
+--minion-ledcount Turn off led when more than this many chips below the ledlimit (default: 0)
+--minion-ledlimit Turn off led when chips GHs are below this (default: 90)
--minion-noautofreq Disable automatic frequency adjustment
--minion-overheat Enable directly halting any chip when the status exceeds 100C
+--minion-spidelay Add a delay in microseconds after each SPI I/O
+--minion-spireset SPI regular reset: iNNN for I/O count or sNNN for seconds - 0 means none
+--minion-spisleep Sleep time in milliseconds when doing an SPI reset
--minion-temp <arg> Set minion chip temperature threshold, single value or comma list, range 120-160 (default: 135C)
--monitor|-m <arg> Use custom pipe cmd for output messages
--nfu-bits <arg> Set nanofury bits for overclocking, range 32-63 (default: 50)
diff --git a/cgminer.c b/cgminer.c
index bf063eb..a339d18 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -250,8 +250,14 @@ int opt_minion_chipreport;
char *opt_minion_cores;
char *opt_minion_freq;
bool opt_minion_idlecount;
+int opt_minion_ledcount;
+int opt_minion_ledlimit = 98;
bool opt_minion_noautofreq;
bool opt_minion_overheat;
+int opt_minion_spidelay;
+char *opt_minion_spireset;
+int opt_minion_spisleep = 200;
+int opt_minion_spiusec;
char *opt_minion_temp;
#endif
@@ -1349,21 +1355,39 @@ static struct opt_table opt_config_table[] = {
OPT_WITH_ARG("--minion-chipreport",
set_int_0_to_100, opt_show_intval, &opt_minion_chipreport,
"Seconds to report chip 5min hashrate, range 0-100 (default: 0=disabled)"),
- OPT_WITH_ARG("--minion-freq",
- opt_set_charp, NULL, &opt_minion_freq,
- "Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1000)"),
OPT_WITH_ARG("--minion-cores",
opt_set_charp, NULL, &opt_minion_cores,
opt_hidden),
+ OPT_WITH_ARG("--minion-freq",
+ opt_set_charp, NULL, &opt_minion_freq,
+ "Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1200)"),
OPT_WITHOUT_ARG("--minion-idlecount",
opt_set_bool, &opt_minion_idlecount,
"Report when IdleCount is >0 or changes"),
+ OPT_WITH_ARG("--minion-ledcount",
+ set_int_0_to_100, opt_show_intval, &opt_minion_ledcount,
+ "Turn off led when more than this many chips below the ledlimit (default: 0)"),
+ OPT_WITH_ARG("--minion-ledlimit",
+ set_int_0_to_200, opt_show_intval, &opt_minion_ledlimit,
+ "Turn off led when chips GHs are below this (default: 90)"),
OPT_WITHOUT_ARG("--minion-noautofreq",
opt_set_bool, &opt_minion_noautofreq,
"Disable automatic frequency adjustment"),
OPT_WITHOUT_ARG("--minion-overheat",
opt_set_bool, &opt_minion_overheat,
"Enable directly halting any chip when the status exceeds 100C"),
+ OPT_WITH_ARG("--minion-spidelay",
+ set_int_0_to_9999, opt_show_intval, &opt_minion_spidelay,
+ "Add a delay in microseconds after each SPI I/O"),
+ OPT_WITH_ARG("--minion-spireset",
+ opt_set_charp, NULL, &opt_minion_spireset,
+ "SPI regular reset: iNNN for I/O count or sNNN for seconds - 0 means none"),
+ OPT_WITH_ARG("--minion-spisleep",
+ set_int_0_to_9999, opt_show_intval, &opt_minion_spisleep,
+ "Sleep time in milliseconds when doing an SPI reset"),
+ OPT_WITH_ARG("--minion-spiusec",
+ set_int_0_to_9999, NULL, &opt_minion_spiusec,
+ opt_hidden),
OPT_WITH_ARG("--minion-temp",
opt_set_charp, NULL, &opt_minion_temp,
"Set minion chip temperature threshold, single value or comma list, range 120-160 (default: 135C)"),
diff --git a/driver-minion.c b/driver-minion.c
index 2bb3831..ade2e0c 100644
--- a/driver-minion.c
+++ b/driver-minion.c
@@ -37,6 +37,17 @@ static void minion_detect(__maybe_unused bool hotplug)
// The code is always in - this just decides if it does it
static bool minreread = false;
+#if MINION_ROCKCHIP == 1
+#define MINION_POWERCYCLE_GPIO 173
+#define MINION_CHIP_OFF "1"
+#define MINION_CHIP_ON "0"
+#define MINION_CHIP_DELAY 100
+#endif
+
+// Power cycle if the xff_list is full and the tail is less than
+// this long ago
+#define MINION_POWER_TIME 60
+
/*
* Use pins for board selection
* If disabled, it will test chips just as 'pin 0'
@@ -152,6 +163,7 @@ static struct minion_select_pins {
// All SYS data sizes are DATA_SIZ
#define MINION_SYS_CHIP_SIG 0x00
#define MINION_SYS_CHIP_STA 0x01
+#define MINION_SYS_SPI_LED 0x02
#define MINION_SYS_TEMP_CTL 0x03
#define MINION_SYS_FREQ_CTL 0x04
#define MINION_SYS_NONCE_LED 0x05
@@ -344,6 +356,12 @@ struct minion_header {
#define MINION_CHIP_SIG_SHIFT3 (((MINION_CHIP_SIG & 0xffffff00) >> 8) & 0x00ffffff)
#define MINION_CHIP_SIG_SHIFT4 (((MINION_CHIP_SIG & 0xffff0000) >> 16) & 0x0000ffff)
+#define MINION_SPI_LED_ON 0xa5a5
+#define MINION_SPI_LED_OFF 0x0
+
+// Time since first nonce/last reset before turning on the LED
+#define MINION_LED_TEST_TIME 600
+
#define MINION_FREQ_MIN 100
#define MINION_FREQ_DEF 1200
#define MINION_FREQ_MAX 1400
@@ -407,6 +425,8 @@ struct minion_status {
uint32_t idle;
uint32_t last_rpt_idle;
struct timeval idle_rpt;
+ struct timeval first_nonce;
+ uint64_t from_first_good;
};
#define ENABLE_CORE(_core, _n) ((_core[_n >> 3]) |= (1 << (_n % 8)))
@@ -594,11 +614,20 @@ typedef struct perf_item {
#define ALLOC_PERF_ITEMS 128
#define LIMIT_PERF_ITEMS 0
+// *** 0xff error history
+typedef struct xff_item {
+ time_t when;
+} XFF_ITEM;
+
+#define ALLOC_XFF_ITEMS 100
+#define LIMIT_XFF_ITEMS 100
+
#define DATA_WORK(_item) ((WORK_ITEM *)(_item->data))
#define DATA_TASK(_item) ((TASK_ITEM *)(_item->data))
#define DATA_RES(_item) ((RES_ITEM *)(_item->data))
#define DATA_HIST(_item) ((HIST_ITEM *)(_item->data))
#define DATA_PERF(_item) ((PERF_ITEM *)(_item->data))
+#define DATA_XFF(_item) ((XFF_ITEM *)(_item->data))
// Set this to 1 to enable iostats processing
// N.B. it slows down mining
@@ -730,6 +759,12 @@ struct minion_info {
char gpiointvalue[64];
int gpiointfd;
+ // I/O or seconds
+ bool spi_reset_io;
+ int spi_reset_count;
+ time_t last_spi_reset;
+ uint64_t spi_resets;
+
// TODO: need to track disabled chips - done?
int chips;
bool has_chip[MINION_CHIPS];
@@ -826,6 +861,15 @@ struct minion_info {
K_LIST *pfree_list;
K_STORE *p_list[MINION_CHIPS];
+ // 0xff history
+ K_LIST *xfree_list;
+ K_STORE *xff_list;
+ time_t last_power_cycle;
+ uint64_t power_cycles;
+ time_t last_xff;
+ uint64_t xffs;
+ uint64_t last_displayed_xff;
+
// Gets reset to zero each time it is used in reporting
int res_err_count[MINION_CHIPS];
@@ -852,9 +896,136 @@ struct minion_info {
double wt_max;
uint64_t wt_bands[TIME_BANDS+1];
+ bool lednow[MINION_CHIPS];
+ bool setled[MINION_CHIPS];
+
bool initialised;
};
+#if MINION_ROCKCHIP == 1
+static bool minion_toggle_gpio(struct cgpu_info *minioncgpu, int gpionum)
+{
+ struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
+ char pindir[64], ena[64], pin[8], dir[64];
+ char gpiointvalue[64];
+ struct stat st;
+ int file, err, chip;
+ ssize_t ret;
+
+ snprintf(pindir, sizeof(pindir), MINION_GPIO_SYS MINION_GPIO_PIN, gpionum);
+ memset(&st, 0, sizeof(st));
+
+ if (stat(pindir, &st) == 0) { // already exists
+ if (!S_ISDIR(st.st_mode)) {
+ applog(LOG_ERR, "%s: failed1 to enable GPIO pin %d"
+ " - not a directory",
+ minioncgpu->drv->dname, gpionum);
+ return false;
+ }
+ } else {
+ snprintf(ena, sizeof(ena), MINION_GPIO_SYS MINION_GPIO_ENA);
+ file = open(ena, O_WRONLY | O_SYNC);
+ if (file == -1) {
+ applog(LOG_ERR, "%s: failed2 to export GPIO pin %d (%d)"
+ " - you need to be root?",
+ minioncgpu->drv->dname,
+ gpionum, errno);
+ return false;
+ }
+ snprintf(pin, sizeof(pin), MINION_GPIO_ENA_VAL, gpionum);
+ ret = write(file, pin, (size_t)strlen(pin));
+ if (ret != (ssize_t)strlen(pin)) {
+ if (ret < 0)
+ err = errno;
+ else
+ err = (int)ret;
+ close(file);
+ applog(LOG_ERR, "%s: failed3 to export GPIO pin %d (%d:%d)",
+ minioncgpu->drv->dname,
+ gpionum, err, (int)strlen(pin));
+ return false;
+ }
+ close(file);
+
+ // Check again if it exists
+ memset(&st, 0, sizeof(st));
+ if (stat(pindir, &st) != 0) {
+ applog(LOG_ERR, "%s: failed4 to export GPIO pin %d (%d)",
+ minioncgpu->drv->dname,
+ gpionum, errno);
+ return false;
+ }
+ }
+
+ // Set the pin attributes
+ // Direction
+ snprintf(dir, sizeof(dir), MINION_GPIO_SYS MINION_GPIO_PIN MINION_GPIO_DIR, gpionum);
+ file = open(dir, O_WRONLY | O_SYNC);
+ if (file == -1) {
+ applog(LOG_ERR, "%s: failed5 to configure GPIO pin %d (%d)"
+ " - you need to be root?",
+ minioncgpu->drv->dname,
+ gpionum, errno);
+ return false;
+ }
+ ret = write(file, MINION_GPIO_DIR_WRITE, sizeof(MINION_GPIO_DIR_WRITE)-1);
+ if (ret != sizeof(MINION_GPIO_DIR_WRITE)-1) {
+ if (ret < 0)
+ err = errno;
+ else
+ err = (int)ret;
+ close(file);
+ applog(LOG_ERR, "%s: failed6 to configure GPIO pin %d (%d:%d)",
+ minioncgpu->drv->dname, gpionum,
+ err, (int)sizeof(MINION_GPIO_DIR_WRITE)-1);
+ return false;
+ }
+ close(file);
+
+ // Open it
+ snprintf(gpiointvalue, sizeof(gpiointvalue),
+ MINION_GPIO_SYS MINION_GPIO_PIN MINION_GPIO_VALUE,
+ gpionum);
+ int fd = open(gpiointvalue, O_WRONLY);
+ if (fd == -1) {
+ applog(LOG_ERR, "%s: failed7 to access GPIO pin %d (%d)",
+ minioncgpu->drv->dname,
+ gpionum, errno);
+ return false;
+ }
+
+ ret = write(fd, MINION_CHIP_OFF, sizeof(MINION_CHIP_OFF)-1);
+ if (ret != sizeof(MINION_CHIP_OFF)-1) {
+ close(fd);
+ applog(LOG_ERR, "%s: failed8 to toggle off GPIO pin %d (%d:%d)",
+ minioncgpu->drv->dname,
+ gpionum, (int)ret, errno);
+ return false;
+ }
+
+ cgsleep_ms(MINION_CHIP_DELAY);
+
+ ret = write(fd, MINION_CHIP_ON, sizeof(MINION_CHIP_ON)-1);
+ if (ret != sizeof(MINION_CHIP_OFF)-1) {
+ close(fd);
+ applog(LOG_ERR, "%s: failed9 to toggle on GPIO pin %d (%d:%d)",
+ minioncgpu->drv->dname,
+ gpionum, (int)ret, errno);
+ return false;
+ }
+
+ close(fd);
+ minioninfo->last_power_cycle = time(NULL);
+ minioninfo->power_cycles++;
+ // Reset all chip led counters
+ for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
+ if (minioninfo->has_chip[chip])
+ minioninfo->chip_status[chip].first_nonce.tv_sec = 0L;
+ }
+ return true;
+}
+#endif
+
static void ready_work(struct cgpu_info *minioncgpu, struct work *work, bool rolled)
{
struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
@@ -916,6 +1087,8 @@ static const char *addr2txt(uint8_t addr)
return "RChipSig";
case READ_ADDR(MINION_SYS_CHIP_STA):
return "RChipSta";
+ case WRITE_ADDR(MINION_SYS_SPI_LED):
+ return "WLed";
case WRITE_ADDR(MINION_SYS_MISC_CTL):
return "WMiscCtrl";
case WRITE_ADDR(MINION_SYS_RSTN_CTL):
@@ -1026,6 +1199,7 @@ static void display_ioctl(int reply, uint32_t osiz, uint8_t *obuf, uint32_t rsiz
case READ_ADDR(MINION_SYS_CHIP_SIG):
case READ_ADDR(MINION_SYS_CHIP_STA):
break;
+ case WRITE_ADDR(MINION_SYS_SPI_LED):
case WRITE_ADDR(MINION_SYS_MISC_CTL):
case WRITE_ADDR(MINION_SYS_RSTN_CTL):
if (osiz > HSIZE()) {
@@ -1131,7 +1305,10 @@ static int __do_ioctl(struct cgpu_info *minioncgpu, struct minion_info *minionin
uint32_t rsiz, uint64_t *ioseq, MINION_FFL_ARGS)
{
struct spi_ioc_transfer tran;
- bool fail = false;
+ bool fail = false, powercycle = false, show = false;
+ double lastshow, total;
+ K_ITEM *xitem;
+ time_t now;
int ret;
#if MINION_SHOW_IO
char dataw[DATA_ALL], datar[DATA_ALL];
@@ -1176,7 +1353,7 @@ static int __do_ioctl(struct cgpu_info *minioncgpu, struct minion_info *minionin
else
return MINION_OVERSIZE_TASK;
- tran.delay_usecs = 0;
+ tran.delay_usecs = opt_minion_spiusec;
tran.speed_hz = MINION_SPI_SPEED;
#if MINION_SHOW_IO
@@ -1204,8 +1381,9 @@ static int __do_ioctl(struct cgpu_info *minioncgpu, struct minion_info *minionin
// Pin back high after I/O
set_pin(minioninfo, pin, true);
}
+ now = time(NULL);
if (ret >= 0 && rbuf[0] == 0xff && rbuf[ret-1] == 0xff &&
- obuf[1] == READ_ADDR(MINION_RES_DATA)) {
+ (obuf[1] == READ_ADDR(MINION_RES_DATA) || obuf[1] == READ_ADDR(MINION_SYS_FIFO_STA))) {
int i;
fail = true;
for (i = 1; i < ret-2; i++) {
@@ -1214,9 +1392,64 @@ static int __do_ioctl(struct cgpu_info *minioncgpu, struct minion_info *minionin
break;
}
}
- if (fail)
+ if (fail) {
+ powercycle = show = false;
+ minioninfo->xffs++;
+ minioninfo->last_xff = now;
+
+ if (minioninfo->xfree_list->count > 0)
+ xitem = k_unlink_head(minioninfo->xfree_list);
+ else
+ xitem = k_unlink_tail(minioninfo->xff_list);
+ DATA_XFF(xitem)->when = now;
+ if (!minioninfo->xff_list->head)
+ show = true;
+ else {
+ // xff_list is full
+ if (minioninfo->xfree_list->count == 0) {
+ total = DATA_XFF(xitem)->when -
+ DATA_XFF(minioninfo->xff_list->tail)->when;
+ if (total <= MINION_POWER_TIME) {
+ powercycle = true;
+ // Discard the history
+ k_list_transfer_to_head(minioninfo->xff_list,
+ minioninfo->xfree_list);
+ k_add_head(minioninfo->xfree_list, xitem);
+ xitem = NULL;
+ }
+ }
+
+ if (!powercycle) {
+ lastshow = DATA_XFF(xitem)->when -
+ DATA_XFF(minioninfo->xff_list->head)->when;
+ show = (lastshow >= 5);
+ }
+ }
+ if (xitem)
+ k_add_head(minioninfo->xff_list, xitem);
+
+#if MINION_ROCKCHIP == 1
+ if (powercycle)
+ minion_toggle_gpio(minioncgpu, MINION_POWERCYCLE_GPIO);
+#endif
minion_init_spi(minioncgpu, minioninfo, 0, 0, true);
+ }
+ } else if (minioninfo->spi_reset_count) {
+ if (minioninfo->spi_reset_io) {
+ if (*ioseq > 0 && (*ioseq % minioninfo->spi_reset_count) == 0)
+ minion_init_spi(minioncgpu, minioninfo, 0, 0, true);
+ } else {
+ if (minioninfo->last_spi_reset == 0)
+ minioninfo->last_spi_reset = now;
+ else {
+ if ((now - minioninfo->last_spi_reset) >= minioninfo->spi_reset_count)
+ minion_init_spi(minioncgpu, minioninfo, 0, 0, true);
+ minioninfo->last_spi_reset = now;
+ }
+ }
}
+ if (opt_minion_spidelay)
+ cgsleep_ms(opt_minion_spidelay);
mutex_unlock(&(minioninfo->spi_lock));
IO_STAT_NOW(&lfin);
IO_STAT_NOW(&tsd);
@@ -1224,9 +1457,26 @@ static int __do_ioctl(struct cgpu_info *minioncgpu, struct minion_info *minionin
IO_STAT_STORE(&sta, &fin, &lsta, &lfin, &tsd, obuf, osiz, ret, 1);
if (fail) {
- applog(LOG_ERR, "%s%d: ioctl %"PRIu64" returned all 0xff - resetting",
- minioncgpu->drv->name, minioncgpu->device_id,
- *ioseq);
+ if (powercycle) {
+ applog(LOG_ERR, "%s%d: power cycle ioctl %"PRIu64" (%"PRIu64")",
+ minioncgpu->drv->name, minioncgpu->device_id, *ioseq,
+ minioninfo->xffs - minioninfo->last_displayed_xff);
+ minioninfo->last_displayed_xff = minioninfo->xffs;
+ } else if (show) {
+ char *what = "unk";
+ switch (obuf[1]) {
+ case READ_ADDR(MINION_RES_DATA):
+ what = "nonce";
+ break;
+ case READ_ADDR(MINION_SYS_FIFO_STA):
+ what = "fifo";
+ break;
+ }
+ applog(LOG_ERR, "%s%d: reset ioctl %"PRIu64" %s all 0xff (%"PRIu64")",
+ minioncgpu->drv->name, minioncgpu->device_id,
+ *ioseq, what, minioninfo->xffs - minioninfo->last_displayed_xff);
+ minioninfo->last_displayed_xff = minioninfo->xffs;
+ }
}
#if MINION_SHOW_IO
@@ -1465,6 +1715,8 @@ static void init_chip(struct cgpu_info *minioncgpu, struct minion_info *minionin
minioninfo->reset_time[chip] = (int)((float)(MINION_RESET_s * MINION_FREQ_DEF) /
minioninfo->init_freq[chip]);
+
+ minioninfo->chip_status[chip].first_nonce.tv_sec = 0L;
}
static void enable_chip_cores(struct cgpu_info *minioncgpu, struct minion_info *minioninfo, int chip)
@@ -1747,10 +1999,13 @@ static bool minion_init_spi(struct cgpu_info *minioncgpu, struct minion_info *mi
if (reset) {
// TODO: maybe slow it down?
close(minioninfo->spifd);
- cgsleep_ms(100);
+ if (opt_minion_spisleep)
+ cgsleep_ms(opt_minion_spisleep);
minioninfo->spifd = open(minioncgpu->device_path, O_RDWR);
if (minioninfo->spifd < 0)
goto bad_out;
+ minioninfo->spi_resets++;
+// minioninfo->chip_status[chip].first_nonce.tv_sec = 0L;
} else {
for (i = 0; minion_modules[i]; i++) {
snprintf(buf, sizeof(buf), "modprobe %s", minion_modules[i]);
@@ -2031,6 +2286,33 @@ static void minion_process_options(struct minion_info *minioninfo)
int i, core1, core2;
bool cleared;
+ if (opt_minion_spireset && *opt_minion_spireset) {
+ bool is_io = true;
+ int val;
+
+ switch (tolower(*opt_minion_spireset)) {
+ case 'i':
+ is_io = true;
+ break;
+ case 's':
+ is_io = false;
+ break;
+ default:
+ applog(LOG_WARNING, "ERR: Invalid SPI reset '%s'",
+ opt_minion_spireset);
+ goto skip;
+ }
+ val = atoi(opt_minion_spireset+1);
+ if (val < 0 || val > 9999) {
+ applog(LOG_WARNING, "ERR: Invalid SPI reset '%s'",
+ opt_minion_spireset);
+ } else {
+ minioninfo->spi_reset_io = is_io;
+ minioninfo->spi_reset_count = val;
+ minioninfo->last_spi_reset = time(NULL);
+ }
+ }
+skip:
last_freq = MINION_FREQ_DEF;
if (opt_minion_freq && *opt_minion_freq) {
buf = freq = strdup(opt_minion_freq);
@@ -2265,6 +2547,10 @@ static void minion_detect(bool hotplug)
for (i = 0; i < (int)MINION_CHIPS; i++)
minioninfo->p_list[i] = k_new_store(minioninfo->pfree_list);
+ minioninfo->xfree_list = k_new_list("0xff", sizeof(XFF_ITEM),
+ ALLOC_XFF_ITEMS, LIMIT_XFF_ITEMS, true);
+ minioninfo->xff_list = k_new_store(minioninfo->xfree_list);
+
cgsem_init(&(minioninfo->task_ready));
cgsem_init(&(minioninfo->nonce_ready));
cgsem_init(&(minioninfo->scan_work));
@@ -2285,14 +2571,20 @@ unalloc:
free(minioncgpu);
}
-static char *minion_set(struct cgpu_info *minioncgpu, char *option, char *setting, char *replybuf)
+static char *minion_api_set(struct cgpu_info *minioncgpu, char *option, char *setting, char *replybuf)
{
struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- int chip;
+ int chip, val;
+ char *colon;
if (strcasecmp(option, "help") == 0) {
- sprintf(replybuf, "reset: chip 0-%d",
- minioninfo->chips - 1);
+ sprintf(replybuf, "reset: chip 0-%d freq: 0-%d:%d-%d "
+ "ledcount: 0-100 ledlimit: 0-200 "
+ "spidelay: 0-9999 spireset i|s0-9999 "
+ "spisleep: 0-9999",
+ minioninfo->chips - 1,
+ minioninfo->chips - 1,
+ MINION_FREQ_MIN, MINION_FREQ_MAX);
return replybuf;
}
@@ -2319,6 +2611,173 @@ static char *minion_set(struct cgpu_info *minioncgpu, char *option, char *settin
return NULL;
}
+ // This must do a reset also - but changes the freq
+ if (strcasecmp(option, "freq") == 0) {
+ if (!setting || !*setting) {
+ sprintf(replybuf, "missing chip:freq");
+ return replybuf;
+ }
+
+ colon = strchr(setting, ':');
+ if (!colon) {
+ sprintf(replybuf, "missing ':' for chip:freq");
+ return replybuf;
+ }
+
+ *(colon++) = '\0';
+ if (!*colon) {
+ sprintf(replybuf, "missing freq in chip:freq");
+ return replybuf;
+ }
+
+ chip = atoi(setting);
+ if (chip < 0 || chip >= minioninfo->chips) {
+ sprintf(replybuf, "invalid freq: chip '%s' valid range 0-%d",
+ setting,
+ minioninfo->chips);
+ return replybuf;
+ }
+
+ if (!minioninfo->has_chip[chip]) {
+ sprintf(replybuf, "unable to modify chip %d - chip disabled",
+ chip);
+ return replybuf;
+ }
+
+ val = atoi(colon);
+ if (val < MINION_FREQ_MIN || val > MINION_FREQ_MAX) {
+ sprintf(replybuf, "invalid freq: '%s' valid range %d-%d",
+ setting,
+ MINION_FREQ_MIN, MINION_FREQ_MAX);
+ return replybuf;
+ }
+
+ minioninfo->init_freq[chip] = val - (val % MINION_FREQ_FACTOR);
+ minioninfo->flag_reset[chip] = true;
+ minioninfo->do_reset[chip] = 0.0;
+
+ return NULL;
+ }
+
+ if (strcasecmp(option, "ledcount") == 0) {
+ if (!setting || !*setting) {
+ sprintf(replybuf, "missing ledcount value");
+ return replybuf;
+ }
+
+ val = atoi(setting);
+ if (val < 0 || val > 100) {
+ sprintf(replybuf, "invalid ledcount: '%s' valid range 0-100",
+ setting);
+ return replybuf;
+ }
+
+ opt_minion_ledcount = val;
+ return NULL;
+ }
+
+ if (strcasecmp(option, "ledlimit") == 0) {
+ if (!setting || !*setting) {
+ sprintf(replybuf, "missing ledlimit value");
+ return replybuf;
+ }
+
+ val = atoi(setting);
+ if (val < 0 || val > 200) {
+ sprintf(replybuf, "invalid ledlimit: GHs '%s' valid range 0-200",
+ setting);
+ return replybuf;
+ }
+
+ opt_minion_ledlimit = val;
+ return NULL;
+ }
+
+ if (strcasecmp(option, "spidelay") == 0) {
+ if (!setting || !*setting) {
+ sprintf(replybuf, "missing spidelay value");
+ return replybuf;
+ }
+
+ val = atoi(setting);
+ if (val < 0 || val > 9999) {
+ sprintf(replybuf, "invalid spidelay: ms '%s' valid range 0-9999",
+ setting);
+ return replybuf;
+ }
+
+ opt_minion_spidelay = val;
+ return NULL;
+ }
+
+ if (strcasecmp(option, "spireset") == 0) {
+ bool is_io = true;
+
+ if (!setting || !*setting) {
+ sprintf(replybuf, "missing spireset value");
+ return replybuf;
+ }
+
+ switch (tolower(*setting)) {
+ case 'i':
+ is_io = true;
+ break;
+ case 's':
+ is_io = false;
+ break;
+ default:
+ sprintf(replybuf, "invalid spireset: '%s' must start with i or s",
+ setting);
+ return replybuf;
+ }
+ val = atoi(setting+1);
+ if (val < 0 || val > 9999) {
+ sprintf(replybuf, "invalid spireset: %c '%s' valid range 0-9999",
+ *setting, setting+1);
+ return replybuf;
+ }
+
+ minioninfo->spi_reset_io = is_io;
+ minioninfo->spi_reset_count = val;
+ minioninfo->last_spi_reset = time(NULL);
+
+ return NULL;
+ }
+
+ if (strcasecmp(option, "spisleep") == 0) {
+ if (!setting || !*setting) {
+ sprintf(replybuf, "missing spisleep value");
+ return replybuf;
+ }
+
+ val = atoi(setting);
+ if (val < 0 || val > 9999) {
+ sprintf(replybuf, "invalid spisleep: ms '%s' valid range 0-9999",
+ setting);
+ return replybuf;
+ }
+
+ opt_minion_spisleep = val;
+ return NULL;
+ }
+
+ if (strcasecmp(option, "spiusec") == 0) {
+ if (!setting || !*setting) {
+ sprintf(replybuf, "missing spiusec value");
+ return replybuf;
+ }
+
+ val = atoi(setting);
+ if (val < 0 || val > 9999) {
+ sprintf(replybuf, "invalid spiusec: '%s' valid range 0-9999",
+ setting);
+ return replybuf;
+ }
+
+ opt_minion_spiusec = val;
+ return NULL;
+ }
+
sprintf(replybuf, "Unknown option: %s", option);
return replybuf;
}
@@ -2385,6 +2844,7 @@ static void *minion_spi_write(void *userdata)
// TODO: case MINION_SYS_TEMP_CTL:
// TODO: case MINION_SYS_FREQ_CTL:
case READ_ADDR(MINION_SYS_CHIP_STA):
+ case WRITE_ADDR(MINION_SYS_SPI_LED):
case WRITE_ADDR(MINION_SYS_RSTN_CTL):
case WRITE_ADDR(MINION_SYS_INT_CLR):
case READ_ADDR(MINION_SYS_IDLE_CNT):
@@ -2564,6 +3024,7 @@ static void *minion_spi_write(void *userdata)
}
break;
case WRITE_ADDR(MINION_SYS_INT_CLR):
+ case WRITE_ADDR(MINION_SYS_SPI_LED):
break;
default:
break;
@@ -2689,19 +3150,20 @@ static void *minion_spi_reply(void *userdata)
if (fifo_task.reply < (int)(fifo_task.osiz)) {
char *buf = bin2hex((unsigned char *)(&(fifo_task.rbuf[fifo_task.osiz - fifo_task.rsiz])),
(int)(fifo_task.rsiz));
- applog(LOG_ERR, "%s%i: Chip %d Bad fifo reply (%s) size %d, should be %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, buf,
- fifo_task.reply, (int)(fifo_task.osiz));
+ applog(LOG_DEBUG, "%s%i: Chip %d Bad fifo reply (%s) size %d, should be %d",
+ minioncgpu->drv->name, minioncgpu->device_id,
+ chip, buf,
+ fifo_task.reply, (int)(fifo_task.osiz));
free(buf);
minioninfo->spi_errors++;
minioninfo->fifo_spi_errors[chip]++;
minioninfo->res_err_count[chip]++;
} else {
if (fifo_task.reply > (int)(fifo_task.osiz)) {
- applog(LOG_ERR, "%s%i: Chip %d Unexpected fifo reply size %d, expected only %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, fifo_task.reply, (int)(fifo_task.osiz));
+ applog(LOG_DEBUG, "%s%i: Chip %d Unexpected fifo reply size %d, "
+ "expected only %d",
+ minioncgpu->drv->name, minioncgpu->device_id,
+ chip, fifo_task.reply, (int)(fifo_task.osiz));
}
res = FIFO_RES(fifo_task.rbuf, fifo_task.osiz - fifo_task.rsiz);
cmd = FIFO_CMD(fifo_task.rbuf, fifo_task.osiz - fifo_task.rsiz);
@@ -2709,9 +3171,11 @@ static void *minion_spi_reply(void *userdata)
if (res <= MINION_QUE_MAX && cmd <= MINION_QUE_MAX)
break;
- applog(LOG_ERR, "%s%i: Chip %d Bad fifo reply res %d (max is %d) cmd %d (max is %d)",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, (int)res, MINION_QUE_MAX, (int)cmd, MINION_QUE_MAX);
+ applog(LOG_DEBUG, "%s%i: Chip %d Bad fifo reply res %d (max is %d) "
+ "cmd %d (max is %d)",
+ minioncgpu->drv->name, minioncgpu->device_id,
+ chip, (int)res, MINION_QUE_MAX,
+ (int)cmd, MINION_QUE_MAX);
minioninfo->spi_errors++;
minioninfo->fifo_spi_errors[chip]++;
minioninfo->res_err_count[chip]++;
@@ -2878,6 +3342,12 @@ repeek:
K_WLOCK(minioninfo->rnonce_list);
k_add_head(minioninfo->rnonce_list, item);
K_WUNLOCK(minioninfo->rnonce_list);
+
+ if (!(minioninfo->chip_status[chip].first_nonce.tv_sec)) {
+ cgtime(&(minioninfo->chip_status[chip].first_nonce));
+ minioninfo->chip_status[chip].from_first_good = 0;
+ }
+
cgsem_post(&(minioninfo->nonce_ready));
} else {
minioninfo->res_err_count[chip]++;
@@ -3208,6 +3678,7 @@ retest:
minioninfo->nonces_recovered[chip]++;
chip_good = ++(minioninfo->chip_good[chip]);
+ minioninfo->chip_status[chip].from_first_good++;
minioninfo->core_good[chip][core]++;
DATA_WORK(item)->nonces++;
@@ -3508,6 +3979,37 @@ static void sys_chip_sta(struct cgpu_info *minioncgpu, int chip)
k_add_head(minioninfo->task_list, item);
K_WUNLOCK(minioninfo->task_list);
}
+
+ if (minioninfo->lednow[chip] != minioninfo->setled[chip]) {
+ uint32_t led;
+
+ minioninfo->lednow[chip] = minioninfo->setled[chip];
+ if (minioninfo->lednow[chip])
+ led = MINION_SPI_LED_ON;
+ else
+ led = MINION_SPI_LED_OFF;
+
+ K_WLOCK(minioninfo->tfree_list);
+ item = k_unlink_head(minioninfo->tfree_list);
+ DATA_TASK(item)->tid = ++(minioninfo->next_tid);
+ K_WUNLOCK(minioninfo->tfree_list);
+
+ DATA_TASK(item)->chip = chip;
+ DATA_TASK(item)->write = true;
+ DATA_TASK(item)->address = MINION_SYS_SPI_LED;
+ DATA_TASK(item)->task_id = 0;
+ DATA_TASK(item)->wsiz = MINION_SYS_SIZ;
+ DATA_TASK(item)->rsiz = 0;
+ DATA_TASK(item)->wbuf[0] = led & 0xff;
+ DATA_TASK(item)->wbuf[1] = (led >> 8) & 0xff;
+ DATA_TASK(item)->wbuf[2] = (led >> 16) & 0xff;
+ DATA_TASK(item)->wbuf[3] = (led >> 24) & 0xff;
+ DATA_TASK(item)->urgent = false;
+
+ K_WLOCK(minioninfo->task_list);
+ k_add_head(minioninfo->task_list, item);
+ K_WUNLOCK(minioninfo->task_list);
+ }
}
}
}
@@ -3972,10 +4474,10 @@ static void chip_report(struct cgpu_info *minioncgpu)
char buf[512];
char res_err_msg[2];
size_t len;
- double elapsed, ghs, expect, howlong;
+ double elapsed, ghs, ghs2, expect, howlong;
+ char ghs2_display[64];
K_ITEM *pitem;
- int msdiff;
- int chip;
+ int msdiff, chip;
int res_err_count;
cgtime(&now);
@@ -3985,39 +4487,54 @@ static void chip_report(struct cgpu_info *minioncgpu)
return;
}
+ // Always run the calculations to check chip GHs for the LED
+ buf[0] = '\0';
+ res_err_msg[0] = '\0';
+ res_err_msg[1] = '\0';
+ K_RLOCK(minioninfo->hfree_list);
+ for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
+ if (minioninfo->has_chip[chip]) {
+ len = strlen(buf);
+ if (minioninfo->hchip_list[chip]->count < 2)
+ ghs = 0.0;
+ else {
+ ghs = 0xffffffffull * (minioninfo->hchip_list[chip]->count - 1);
+ ghs /= 1000000000.0;
+ ghs /= tdiff(&now, &(DATA_HIST(minioninfo->hchip_list[chip]->tail)->when));
+ }
+ if (minioninfo->chip_status[chip].first_nonce.tv_sec &&
+ tdiff(&now, &minioninfo->chip_status[chip].first_nonce) < MINION_LED_TEST_TIME) {
+ ghs2_display[0] = '\0';
+ minioninfo->setled[chip] = false;
+ } else {
+ ghs2 = 0xffffffffull * (minioninfo->chip_status[chip].from_first_good - 1);
+ ghs2 /= 1000000000.0;
+ ghs2 /= tdiff(&now, &minioninfo->chip_status[chip].first_nonce);
+ minioninfo->setled[chip] = (ghs2 >= opt_minion_ledlimit);
+ snprintf(ghs2_display, sizeof(ghs2_display), "[%.2f]", ghs2);
+ }
+
+ res_err_count = minioninfo->res_err_count[chip];
+ minioninfo->res_err_count[chip] = 0;
+ if (res_err_count > 100)
+ res_err_msg[0] = '!';
+ else if (res_err_count > 50)
+ res_err_msg[0] = '*';
+ else if (res_err_count > 0)
+ res_err_msg[0] = '\'';
+ else
+ res_err_msg[0] = '\0';
+ snprintf(buf + len, sizeof(buf) - len,
+ " %d=%s%.2f%s", chip, res_err_msg, ghs, ghs2_display);
+ minioninfo->history_ghs[chip] = ghs;
+ }
+ }
+ K_RUNLOCK(minioninfo->hfree_list);
+
+ // But only display it if required
if (opt_minion_chipreport > 0) {
msdiff = ms_tdiff(&now, &(minioninfo->chip_rpt));
if (msdiff >= (opt_minion_chipreport * 1000)) {
- buf[0] = '\0';
- res_err_msg[0] = '\0';
- res_err_msg[1] = '\0';
- K_RLOCK(minioninfo->hfree_list);
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip]) {
- len = strlen(buf);
- if (minioninfo->hchip_list[chip]->count < 2)
- ghs = 0.0;
- else {
- ghs = 0xffffffffull * (minioninfo->hchip_list[chip]->count - 1);
- ghs /= 1000000000.0;
- ghs /= tdiff(&now, &(DATA_HIST(minioninfo->hchip_list[chip]->tail)->when));
- }
- res_err_count = minioninfo->res_err_count[chip];
- minioninfo->res_err_count[chip] = 0;
- if (res_err_count > 100)
- res_err_msg[0] = '!';
- else if (res_err_count > 50)
- res_err_msg[0] = '*';
- else if (res_err_count > 0)
- res_err_msg[0] = '\'';
- else
- res_err_msg[0] = '\0';
- snprintf(buf + len, sizeof(buf) - len,
- " %d=%s%.2f", chip, res_err_msg, ghs);
- minioninfo->history_ghs[chip] = ghs;
- }
- }
- K_RUNLOCK(minioninfo->hfree_list);
memcpy(&(minioninfo->chip_chk), &now, sizeof(now));
applogsiz(LOG_WARNING, 512,
"%s%d: Chip GHs%s",
@@ -4457,6 +4974,22 @@ static struct api_data *minion_api_stats(struct cgpu_info *minioncgpu)
root = api_add_int(root, "RFree Count", &(minioninfo->rfree_list->count), true);
root = api_add_int(root, "RNonce Count", &(minioninfo->rnonce_list->count), true);
+ root = api_add_int(root, "XFree Count", &(minioninfo->xfree_list->count), true);
+ root = api_add_int(root, "XFF Count", &(minioninfo->xff_list->count), true);
+ root = api_add_uint64(root, "XFFs", &(minioninfo->xffs), true);
+ root = api_add_uint64(root, "SPI Resets", &(minioninfo->spi_resets), true);
+ root = api_add_uint64(root, "Power Cycles", &(minioninfo->power_cycles), true);
+
+ root = api_add_int(root, "Chip Report", &opt_minion_chipreport, true);
+ root = api_add_int(root, "LED Count", &opt_minion_ledcount, true);
+ root = api_add_int(root, "LED Limit", &opt_minion_ledlimit, true);
+ bool b = !opt_minion_noautofreq;
+ root = api_add_bool(root, "Auto Freq", &b, true);
+ root = api_add_int(root, "SPI Delay", &opt_minion_spidelay, true);
+ root = api_add_bool(root, "SPI Reset I/O", &(minioninfo->spi_reset_io), true);
+ root = api_add_int(root, "SPI Reset", &(minioninfo->spi_reset_count), true);
+ root = api_add_int(root, "SPI Reset Sleep", &opt_minion_spisleep, true);
+
#if DO_IO_STATS
#define sta_api(_name, _iostat) \
do { \
@@ -4565,7 +5098,7 @@ struct device_drv minion_drv = {
#ifdef LINUX
.get_api_stats = minion_api_stats,
.get_statline_before = minion_get_statline_before,
- .set_device = minion_set,
+ .set_device = minion_api_set,
.identify_device = minion_identify,
.thread_prepare = minion_thread_prepare,
.hash_work = hash_queued_work,
diff --git a/miner.h b/miner.h
index 74c8345..8e1c71b 100644
--- a/miner.h
+++ b/miner.h
@@ -1024,8 +1024,14 @@ extern int opt_minion_chipreport;
extern char *opt_minion_cores;
extern char *opt_minion_freq;
extern bool opt_minion_idlecount;
+extern int opt_minion_ledcount;
+extern int opt_minion_ledlimit;
extern bool opt_minion_noautofreq;
extern bool opt_minion_overheat;
+extern int opt_minion_spidelay;
+extern char *opt_minion_spireset;
+extern int opt_minion_spisleep;
+extern int opt_minion_spiusec;
extern char *opt_minion_temp;
#endif
#ifdef USE_USBUTILS