|
@@ -0,0 +1,1870 @@
|
|
|
|
|
+/*
|
|
|
|
|
+ * Copyright 2013 Andrew Smith
|
|
|
|
|
+ * Copyright 2013 bitfury
|
|
|
|
|
+ *
|
|
|
|
|
+ * BitFury GPIO code based on chainminer code:
|
|
|
|
|
+ * https://github.com/bfsb/chainminer
|
|
|
|
|
+ *
|
|
|
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
|
|
|
+ * under the terms of the GNU General Public License as published by the Free
|
|
|
|
|
+ * Software Foundation; either version 3 of the License, or (at your option)
|
|
|
|
|
+ * any later version. See COPYING for more details.
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+#include "config.h"
|
|
|
|
|
+#include "compat.h"
|
|
|
|
|
+#include "miner.h"
|
|
|
|
|
+#include "sha2.h"
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Tested on RPi running Raspbian with BlackArrow BitFury V1 16 chip GPIO board
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+#ifndef LINUX
|
|
|
|
|
+static void bab_detect(__maybe_unused bool hotplug)
|
|
|
|
|
+{
|
|
|
|
|
+}
|
|
|
|
|
+#else
|
|
|
|
|
+
|
|
|
|
|
+#include <unistd.h>
|
|
|
|
|
+#include <linux/spi/spidev.h>
|
|
|
|
|
+#include <sys/mman.h>
|
|
|
|
|
+#include <sys/ioctl.h>
|
|
|
|
|
+#include <fcntl.h>
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_SPI_BUS 0
|
|
|
|
|
+#define BAB_SPI_CHIP 0
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_SPI_SPEED 96000
|
|
|
|
|
+#define BAB_SPI_BUFSIZ 1024
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_ADDR(_n) (*((babinfo->gpio) + (_n)))
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_INP_GPIO(_n) BAB_ADDR((_n) / 10) &= (~(7 << (((_n) % 10) * 3)))
|
|
|
|
|
+#define BAB_OUT_GPIO(_n) BAB_ADDR((_n) / 10) |= (1 << (((_n) % 10) * 3))
|
|
|
|
|
+#define BAB_OUT_GPIO_V(_n, _v) BAB_ADDR((_n) / 10) |= (((_v) <= 3 ? (_v) + 4 : \
|
|
|
|
|
+ ((_v) == 4 ? 3 : 2)) << (((_n) % 10) * 3))
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_GPIO_SET BAB_ADDR(7)
|
|
|
|
|
+#define BAB_GPIO_CLR BAB_ADDR(10)
|
|
|
|
|
+#define BAB_GPIO_LEVEL BAB_ADDR(13)
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_MAXCHIPS 256
|
|
|
|
|
+#define BAB_MAXBUF (BAB_MAXCHIPS * 512)
|
|
|
|
|
+#define BAB_MAXBANKS 4
|
|
|
|
|
+#define BAB_CORES 16
|
|
|
|
|
+#define BAB_X_COORD 21
|
|
|
|
|
+#define BAB_Y_COORD 36
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_BREAK ((uint8_t *)"\04")
|
|
|
|
|
+#define BAB_ASYNC ((uint8_t *)"\05")
|
|
|
|
|
+#define BAB_SYNC ((uint8_t *)"\06")
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_FFL " - from %s %s() line %d"
|
|
|
|
|
+#define BAB_FFL_HERE __FILE__, __func__, __LINE__
|
|
|
|
|
+#define BAB_FFL_PASS file, func, line
|
|
|
|
|
+
|
|
|
|
|
+#define bab_reset(_bank, _times) _bab_reset(babcgpu, babinfo, _bank, _times)
|
|
|
|
|
+#define bab_txrx(_buf, _siz, _det) _bab_txrx(babcgpu, babinfo, _buf, _siz, _det, BAB_FFL_HERE)
|
|
|
|
|
+#define bab_add_buf(_data) _bab_add_buf(babcgpu, babinfo, _data, sizeof(_data)-1, BAB_FFL_HERE)
|
|
|
|
|
+#define BAB_ADD_BREAK() _bab_add_buf(babcgpu, babinfo, BAB_BREAK, 1, BAB_FFL_HERE)
|
|
|
|
|
+#define BAB_ADD_ASYNC() _bab_add_buf(babcgpu, babinfo, BAB_ASYNC, 1, BAB_FFL_HERE)
|
|
|
|
|
+#define bab_config_reg(_reg, _ena) _bab_config_reg(babcgpu, babinfo, _reg, _ena, BAB_FFL_HERE)
|
|
|
|
|
+#define bab_add_data(_addr, _data, _siz) _bab_add_data(babcgpu, babinfo, _addr, (const uint8_t *)(_data), _siz, BAB_FFL_HERE)
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_ADD_MIN 4
|
|
|
|
|
+#define BAB_ADD_MAX 128
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_STATE_DONE 0
|
|
|
|
|
+#define BAB_STATE_READY 1
|
|
|
|
|
+#define BAB_STATE_SENDING 2
|
|
|
|
|
+#define BAB_STATE_SENT 3
|
|
|
|
|
+#define BAB_STATE_READING 4
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_SPI_BUFFERS 2
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_BASEA 4
|
|
|
|
|
+#define BAB_BASEB 61
|
|
|
|
|
+#define BAB_COUNTERS 16
|
|
|
|
|
+static const uint8_t bab_counters[BAB_COUNTERS] = {
|
|
|
|
|
+ 64, 64,
|
|
|
|
|
+ BAB_BASEA, BAB_BASEA+4,
|
|
|
|
|
+ BAB_BASEA+2, BAB_BASEA+2+16,
|
|
|
|
|
+ BAB_BASEA, BAB_BASEA+1,
|
|
|
|
|
+ (BAB_BASEB)%65, (BAB_BASEB+1)%65,
|
|
|
|
|
+ (BAB_BASEB+3)%65, (BAB_BASEB+3+16)%65,
|
|
|
|
|
+ (BAB_BASEB+4)%65, (BAB_BASEB+4+4)%65,
|
|
|
|
|
+ (BAB_BASEB+3+3)%65, (BAB_BASEB+3+1+3)%65
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_W1 16
|
|
|
|
|
+static const uint32_t bab_w1[BAB_W1] = {
|
|
|
|
|
+ 0, 0, 0, 0xffffffff,
|
|
|
|
|
+ 0x80000000, 0, 0, 0,
|
|
|
|
|
+ 0, 0, 0, 0,
|
|
|
|
|
+ 0, 0, 0, 0x00000280
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_W2 8
|
|
|
|
|
+static const uint32_t bab_w2[BAB_W2] = {
|
|
|
|
|
+ 0x80000000, 0, 0, 0,
|
|
|
|
|
+ 0, 0, 0, 0x00000100
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_TEST_DATA 19
|
|
|
|
|
+static const uint32_t bab_test_data[BAB_TEST_DATA] = {
|
|
|
|
|
+ 0xb0e72d8e, 0x1dc5b862, 0xe9e7c4a6, 0x3050f1f5,
|
|
|
|
|
+ 0x8a1a6b7e, 0x7ec384e8, 0x42c1c3fc, 0x8ed158a1,
|
|
|
|
|
+ 0x8a1a6b7e, 0x6f484872, 0x4ff0bb9b, 0x12c97f07,
|
|
|
|
|
+ 0xb0e72d8e, 0x55d979bc, 0x39403296, 0x40f09e84,
|
|
|
|
|
+ 0x8a0bb7b7, 0x33af304f, 0x0b290c1a //, 0xf0c4e61f
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+//maximum number of chips on alternative bank
|
|
|
|
|
+// #define BANKCHIPS 64
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * maximum chip speed available for auto tuner
|
|
|
|
|
+ * speed/nrate/hrate/watt
|
|
|
|
|
+ * 53/ 97/ 100/ 84
|
|
|
|
|
+ * 54/ 98/ 107/ 88
|
|
|
|
|
+ * 55/ 99/ 115/ 93
|
|
|
|
|
+ * 56/ 101/ 125/ 99
|
|
|
|
|
+ */
|
|
|
|
|
+#define BAB_MAXSPEED 57
|
|
|
|
|
+#define BAB_DEFSPEED 54
|
|
|
|
|
+#define BAB_MINSPEED 52
|
|
|
|
|
+
|
|
|
|
|
+#define MIDSTATE_BYTES 32
|
|
|
|
|
+#define MERKLE_OFFSET 64
|
|
|
|
|
+#define MERKLE_BYTES 12
|
|
|
|
|
+#define BLOCK_HEADER_BYTES 80
|
|
|
|
|
+
|
|
|
|
|
+#define MIDSTATE_UINTS (MIDSTATE_BYTES / sizeof(uint32_t))
|
|
|
|
|
+#define DATA_UINTS ((BLOCK_HEADER_BYTES / sizeof(uint32_t)) - 1)
|
|
|
|
|
+
|
|
|
|
|
+// Auto adjust
|
|
|
|
|
+#define BAB_AUTO_REG 0
|
|
|
|
|
+#define BAB_AUTO_VAL 0x01
|
|
|
|
|
+// iclk
|
|
|
|
|
+#define BAB_ICLK_REG 1
|
|
|
|
|
+#define BAB_ICLK_VAL 0x02
|
|
|
|
|
+// No fast clock
|
|
|
|
|
+#define BAB_FAST_REG 2
|
|
|
|
|
+#define BAB_FAST_VAL 0x04
|
|
|
|
|
+// Divide by 2
|
|
|
|
|
+#define BAB_DIV2_REG 3
|
|
|
|
|
+#define BAB_DIV2_VAL 0x08
|
|
|
|
|
+// Slow Clock
|
|
|
|
|
+#define BAB_SLOW_REG 4
|
|
|
|
|
+#define BAB_SLOW_VAL 0x10
|
|
|
|
|
+// No oclk
|
|
|
|
|
+#define BAB_OCLK_REG 6
|
|
|
|
|
+#define BAB_OCLK_VAL 0x20
|
|
|
|
|
+// Has configured
|
|
|
|
|
+#define BAB_CFGD_VAL 0x40
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_DEFCONF (BAB_AUTO_VAL | \
|
|
|
|
|
+ BAB_ICLK_VAL | \
|
|
|
|
|
+ BAB_DIV2_VAL | \
|
|
|
|
|
+ BAB_SLOW_VAL)
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_REG_CLR_FROM 7
|
|
|
|
|
+#define BAB_REG_CLR_TO 11
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_AUTO_SET(_c) ((_c) & BAB_AUTO_VAL)
|
|
|
|
|
+#define BAB_ICLK_SET(_c) ((_c) & BAB_ICLK_VAL)
|
|
|
|
|
+#define BAB_FAST_SET(_c) ((_c) & BAB_FAST_VAL)
|
|
|
|
|
+#define BAB_DIV2_SET(_c) ((_c) & BAB_DIV2_VAL)
|
|
|
|
|
+#define BAB_SLOW_SET(_c) ((_c) & BAB_SLOW_VAL)
|
|
|
|
|
+#define BAB_OCLK_SET(_c) ((_c) & BAB_OCLK_VAL)
|
|
|
|
|
+#define BAB_CFGD_SET(_c) ((_c) & BAB_CFGD_VAL)
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_AUTO_BIT(_c) (BAB_AUTO_SET(_c) ? true : false)
|
|
|
|
|
+#define BAB_ICLK_BIT(_c) (BAB_ICLK_SET(_c) ? false : true)
|
|
|
|
|
+#define BAB_FAST_BIT(_c) (BAB_FAST_SET(_c) ? true : false)
|
|
|
|
|
+#define BAB_DIV2_BIT(_c) (BAB_DIV2_SET(_c) ? false : true)
|
|
|
|
|
+#define BAB_SLOW_BIT(_c) (BAB_SLOW_SET(_c) ? true : false)
|
|
|
|
|
+#define BAB_OCLK_BIT(_c) (BAB_OCLK_SET(_c) ? true : false)
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_COUNT_ADDR 0x0100
|
|
|
|
|
+#define BAB_W1A_ADDR 0x1000
|
|
|
|
|
+#define BAB_W1B_ADDR 0x1400
|
|
|
|
|
+#define BAB_W2_ADDR 0x1900
|
|
|
|
|
+#define BAB_INP_ADDR 0x3000
|
|
|
|
|
+#define BAB_OSC_ADDR 0x6000
|
|
|
|
|
+#define BAB_REG_ADDR 0x7000
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * valid: 0x01 0x03 0x07 0x0F 0x1F 0x3F 0x7F 0xFF
|
|
|
|
|
+ * max { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00 }
|
|
|
|
|
+ * max { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00 }
|
|
|
|
|
+ * avg { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00 }
|
|
|
|
|
+ * slo { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00 }
|
|
|
|
|
+ * min { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
|
|
|
|
+ * good: 0x1F (97) 0x3F (104) 0x7F (109) 0xFF (104)
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_OSC 8
|
|
|
|
|
+static const uint8_t bab_osc_bits[BAB_OSC] =
|
|
|
|
|
+ { 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
|
|
|
|
|
+
|
|
|
|
|
+static const uint8_t bab_reg_ena[4] = { 0xc1, 0x6a, 0x59, 0xe3 };
|
|
|
|
|
+static const uint8_t bab_reg_dis[4] = { 0x00, 0x00, 0x00, 0x00 };
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_NONCE_OFFSETS 3
|
|
|
|
|
+static const uint32_t bab_nonce_offsets[] = {-0x800000, 0, -0x400000};
|
|
|
|
|
+
|
|
|
|
|
+struct bab_work_send {
|
|
|
|
|
+ uint32_t midstate[MIDSTATE_UINTS];
|
|
|
|
|
+ uint32_t ms3steps[MIDSTATE_UINTS];
|
|
|
|
|
+ uint32_t merkle7;
|
|
|
|
|
+ uint32_t ntime;
|
|
|
|
|
+ uint32_t bits;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_REPLY_NONCES 16
|
|
|
|
|
+struct bab_work_reply {
|
|
|
|
|
+ uint32_t nonce[BAB_REPLY_NONCES];
|
|
|
|
|
+ uint32_t jobsel;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+#define MAX_BLISTS 4096
|
|
|
|
|
+
|
|
|
|
|
+typedef struct blist {
|
|
|
|
|
+ struct blist *prev;
|
|
|
|
|
+ struct blist *next;
|
|
|
|
|
+ struct work *work;
|
|
|
|
|
+ int nonces;
|
|
|
|
|
+} BLIST;
|
|
|
|
|
+
|
|
|
|
|
+#define MAX_RLISTS 256
|
|
|
|
|
+
|
|
|
|
|
+typedef struct rlist {
|
|
|
|
|
+ struct rlist *prev;
|
|
|
|
|
+ struct rlist *next;
|
|
|
|
|
+ int chip;
|
|
|
|
|
+ uint32_t nonce;
|
|
|
|
|
+ bool first_second;
|
|
|
|
|
+} RLIST;
|
|
|
|
|
+
|
|
|
|
|
+struct bab_info {
|
|
|
|
|
+ struct thr_info spi_thr;
|
|
|
|
|
+ struct thr_info res_thr;
|
|
|
|
|
+
|
|
|
|
|
+ pthread_mutex_t spi_lock;
|
|
|
|
|
+ pthread_mutex_t res_lock;
|
|
|
|
|
+ pthread_mutex_t did_lock;
|
|
|
|
|
+ cglock_t blist_lock;
|
|
|
|
|
+
|
|
|
|
|
+ // All GPIO goes through this
|
|
|
|
|
+ volatile unsigned *gpio;
|
|
|
|
|
+
|
|
|
|
|
+ int spifd;
|
|
|
|
|
+ int chips;
|
|
|
|
|
+ uint32_t chip_spis[BAB_MAXCHIPS+1];
|
|
|
|
|
+
|
|
|
|
|
+ int buffer;
|
|
|
|
|
+ int buf_status[BAB_SPI_BUFFERS];
|
|
|
|
|
+ uint8_t buf_write[BAB_SPI_BUFFERS][BAB_MAXBUF];
|
|
|
|
|
+ uint8_t buf_read[BAB_SPI_BUFFERS][BAB_MAXBUF];
|
|
|
|
|
+ uint32_t buf_used[BAB_SPI_BUFFERS];
|
|
|
|
|
+ uint32_t chip_off[BAB_SPI_BUFFERS][BAB_MAXCHIPS+1];
|
|
|
|
|
+ uint32_t bank_off[BAB_SPI_BUFFERS][BAB_MAXBANKS+2];
|
|
|
|
|
+
|
|
|
|
|
+ struct bab_work_send chip_input[BAB_MAXCHIPS];
|
|
|
|
|
+ struct bab_work_reply chip_results[BAB_MAXCHIPS];
|
|
|
|
|
+ struct bab_work_reply chip_prev[BAB_MAXCHIPS];
|
|
|
|
|
+
|
|
|
|
|
+ uint8_t chip_fast[BAB_MAXCHIPS];
|
|
|
|
|
+ uint8_t chip_conf[BAB_MAXCHIPS];
|
|
|
|
|
+ uint8_t old_fast[BAB_MAXCHIPS];
|
|
|
|
|
+ uint8_t old_conf[BAB_MAXCHIPS];
|
|
|
|
|
+ uint8_t chip_bank[BAB_MAXCHIPS+1];
|
|
|
|
|
+
|
|
|
|
|
+ uint8_t osc[BAB_OSC];
|
|
|
|
|
+
|
|
|
|
|
+ int fixchip;
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * Ignore errors in the first work reply since
|
|
|
|
|
+ * they may be from a previous run or random junk
|
|
|
|
|
+ * There can be >100 with just a 16 chip board
|
|
|
|
|
+ */
|
|
|
|
|
+ uint32_t initial_ignored;
|
|
|
|
|
+ bool nonce_before[BAB_MAXCHIPS];
|
|
|
|
|
+ bool not_first_reply[BAB_MAXCHIPS];
|
|
|
|
|
+
|
|
|
|
|
+ // Stats
|
|
|
|
|
+ struct timeval chip_start[BAB_MAXCHIPS];
|
|
|
|
|
+ int chip_busy[BAB_MAXCHIPS];
|
|
|
|
|
+ uint64_t core_good[BAB_MAXCHIPS][BAB_CORES];
|
|
|
|
|
+ uint64_t core_bad[BAB_MAXCHIPS][BAB_CORES];
|
|
|
|
|
+ uint64_t chip_spie[BAB_MAXCHIPS]; // spi errors
|
|
|
|
|
+ uint64_t chip_miso[BAB_MAXCHIPS]; // msio errors
|
|
|
|
|
+ uint64_t chip_nonces[BAB_MAXCHIPS];
|
|
|
|
|
+ uint64_t chip_good[BAB_MAXCHIPS];
|
|
|
|
|
+ uint64_t chip_bad[BAB_MAXCHIPS];
|
|
|
|
|
+ uint64_t chip_ncore[BAB_MAXCHIPS][BAB_X_COORD][BAB_Y_COORD];
|
|
|
|
|
+
|
|
|
|
|
+ uint64_t untested_nonces;
|
|
|
|
|
+ uint64_t tested_nonces;
|
|
|
|
|
+
|
|
|
|
|
+ uint64_t new_nonces;
|
|
|
|
|
+ uint64_t ok_nonces;
|
|
|
|
|
+
|
|
|
|
|
+ uint64_t nonce_offset_count[BAB_NONCE_OFFSETS];
|
|
|
|
|
+ uint64_t total_tests;
|
|
|
|
|
+ uint64_t max_tests_per_nonce;
|
|
|
|
|
+ uint64_t total_links;
|
|
|
|
|
+ uint64_t max_links;
|
|
|
|
|
+
|
|
|
|
|
+ int blist_count;
|
|
|
|
|
+ int bfree_count;
|
|
|
|
|
+ int work_count;
|
|
|
|
|
+ int chip_count;
|
|
|
|
|
+ BLIST *bfree_list;
|
|
|
|
|
+ BLIST *work_list;
|
|
|
|
|
+ BLIST *chip_list[BAB_MAXCHIPS];
|
|
|
|
|
+
|
|
|
|
|
+ int rlist_count;
|
|
|
|
|
+ int rfree_count;
|
|
|
|
|
+ int res_count;
|
|
|
|
|
+ RLIST *rfree_list;
|
|
|
|
|
+ RLIST *res_list_head;
|
|
|
|
|
+ RLIST *res_list_tail;
|
|
|
|
|
+
|
|
|
|
|
+ struct timeval last_did;
|
|
|
|
|
+
|
|
|
|
|
+ bool initialised;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+static BLIST *new_blist_set(struct cgpu_info *babcgpu)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ BLIST *blist = NULL;
|
|
|
|
|
+ int i;
|
|
|
|
|
+
|
|
|
|
|
+ blist = calloc(MAX_BLISTS, sizeof(*blist));
|
|
|
|
|
+ if (!blist)
|
|
|
|
|
+ quithere(1, "Failed to calloc blist - when old count=%d", babinfo->blist_count);
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->blist_count += MAX_BLISTS;
|
|
|
|
|
+ babinfo->bfree_count = MAX_BLISTS;
|
|
|
|
|
+
|
|
|
|
|
+ blist[0].prev = NULL;
|
|
|
|
|
+ blist[0].next = &(blist[1]);
|
|
|
|
|
+ for (i = 1; i < MAX_BLISTS-1; i++) {
|
|
|
|
|
+ blist[i].prev = &blist[i-1];
|
|
|
|
|
+ blist[i].next = &blist[i+1];
|
|
|
|
|
+ }
|
|
|
|
|
+ blist[MAX_BLISTS-1].prev = &(blist[MAX_BLISTS-2]);
|
|
|
|
|
+ blist[MAX_BLISTS-1].next = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ return blist;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static BLIST *next_work(struct cgpu_info *babcgpu, int chip)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ BLIST *bitem;
|
|
|
|
|
+
|
|
|
|
|
+ cg_wlock(&babinfo->blist_lock);
|
|
|
|
|
+ bitem = babinfo->work_list;
|
|
|
|
|
+ if (bitem) {
|
|
|
|
|
+ // Unlink it from work
|
|
|
|
|
+ if (bitem->next)
|
|
|
|
|
+ bitem->next->prev = NULL;
|
|
|
|
|
+ babinfo->work_list = bitem->next;
|
|
|
|
|
+ babinfo->work_count--;
|
|
|
|
|
+
|
|
|
|
|
+ // Add it to the chip
|
|
|
|
|
+ bitem->next = babinfo->chip_list[chip];
|
|
|
|
|
+ bitem->prev = NULL;
|
|
|
|
|
+ if (bitem->next)
|
|
|
|
|
+ bitem->next->prev = bitem;
|
|
|
|
|
+ babinfo->chip_list[chip] = bitem;
|
|
|
|
|
+ babinfo->chip_count++;
|
|
|
|
|
+ }
|
|
|
|
|
+ cg_wunlock(&babinfo->blist_lock);
|
|
|
|
|
+
|
|
|
|
|
+ return bitem;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void discard_last(struct cgpu_info *babcgpu, int chip)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ BLIST *bitem;
|
|
|
|
|
+
|
|
|
|
|
+ cg_wlock(&babinfo->blist_lock);
|
|
|
|
|
+ bitem = babinfo->chip_list[chip];
|
|
|
|
|
+ if (bitem) {
|
|
|
|
|
+ // Unlink it from the chip
|
|
|
|
|
+ if (bitem->next)
|
|
|
|
|
+ bitem->next->prev = NULL;
|
|
|
|
|
+ babinfo->chip_list[chip] = bitem->next;
|
|
|
|
|
+ babinfo->chip_count--;
|
|
|
|
|
+
|
|
|
|
|
+ // Put it in the free list
|
|
|
|
|
+ bitem->next = babinfo->bfree_list;
|
|
|
|
|
+ bitem->prev = NULL;
|
|
|
|
|
+ if (bitem->next)
|
|
|
|
|
+ bitem->next->prev = bitem;
|
|
|
|
|
+ babinfo->bfree_list = bitem;
|
|
|
|
|
+ babinfo->bfree_count++;
|
|
|
|
|
+ }
|
|
|
|
|
+ cg_wunlock(&babinfo->blist_lock);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static BLIST *store_work(struct cgpu_info *babcgpu, struct work *work)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ BLIST *bitem = NULL;
|
|
|
|
|
+ int ran_out = 0;
|
|
|
|
|
+
|
|
|
|
|
+ cg_wlock(&babinfo->blist_lock);
|
|
|
|
|
+
|
|
|
|
|
+ if (babinfo->bfree_list == NULL) {
|
|
|
|
|
+ ran_out = babinfo->blist_count;
|
|
|
|
|
+ babinfo->bfree_list = new_blist_set(babcgpu);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // unlink from free
|
|
|
|
|
+ bitem = babinfo->bfree_list;
|
|
|
|
|
+ babinfo->bfree_list = babinfo->bfree_list->next;
|
|
|
|
|
+ if (babinfo->bfree_list)
|
|
|
|
|
+ babinfo->bfree_list->prev = NULL;
|
|
|
|
|
+ babinfo->bfree_count--;
|
|
|
|
|
+
|
|
|
|
|
+ // add to work
|
|
|
|
|
+ bitem->next = babinfo->work_list;
|
|
|
|
|
+ bitem->prev = NULL;
|
|
|
|
|
+ if (bitem->next)
|
|
|
|
|
+ bitem->next->prev = bitem;
|
|
|
|
|
+ babinfo->work_list = bitem;
|
|
|
|
|
+ babinfo->work_count++;
|
|
|
|
|
+
|
|
|
|
|
+ bitem->work = work;
|
|
|
|
|
+ bitem->nonces = 0;
|
|
|
|
|
+
|
|
|
|
|
+ cg_wunlock(&babinfo->blist_lock);
|
|
|
|
|
+
|
|
|
|
|
+ if (ran_out > 0) {
|
|
|
|
|
+ applog(LOG_ERR, "%s%i: BLIST used count exceeded %d, now %d (work=%d chip=%d)",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id,
|
|
|
|
|
+ ran_out, babinfo->blist_count,
|
|
|
|
|
+ babinfo->work_count,
|
|
|
|
|
+ babinfo->chip_count);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return bitem;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void free_blist(struct cgpu_info *babcgpu, BLIST *bhead, int chip)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ struct work *work;
|
|
|
|
|
+ BLIST *bitem;
|
|
|
|
|
+
|
|
|
|
|
+ if (!bhead)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ // Unlink it from the chip
|
|
|
|
|
+ cg_wlock(&babinfo->blist_lock);
|
|
|
|
|
+ if (unlikely(bhead == babinfo->chip_list[chip])) {
|
|
|
|
|
+ // Removing the chip head is an error
|
|
|
|
|
+ bhead = bhead->next;
|
|
|
|
|
+ babinfo->chip_list[chip]->next = NULL;
|
|
|
|
|
+ } else
|
|
|
|
|
+ bhead->prev->next = NULL;
|
|
|
|
|
+ bitem = bhead;
|
|
|
|
|
+ while (bitem) {
|
|
|
|
|
+ babinfo->chip_count--;
|
|
|
|
|
+ bitem = bitem->next;
|
|
|
|
|
+ }
|
|
|
|
|
+ cg_wunlock(&babinfo->blist_lock);
|
|
|
|
|
+
|
|
|
|
|
+ while (bhead) {
|
|
|
|
|
+ bitem = bhead;
|
|
|
|
|
+ bhead = bitem->next;
|
|
|
|
|
+
|
|
|
|
|
+ // add to free
|
|
|
|
|
+ cg_wlock(&babinfo->blist_lock);
|
|
|
|
|
+ bitem->next = babinfo->bfree_list;
|
|
|
|
|
+ if (babinfo->bfree_list)
|
|
|
|
|
+ babinfo->bfree_list->prev = bitem;
|
|
|
|
|
+ bitem->prev = NULL;
|
|
|
|
|
+ babinfo->bfree_list = bitem;
|
|
|
|
|
+ babinfo->bfree_count++;
|
|
|
|
|
+ work = bitem->work;
|
|
|
|
|
+ cg_wunlock(&babinfo->blist_lock);
|
|
|
|
|
+
|
|
|
|
|
+ work_completed(babcgpu, work);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static RLIST *new_rlist_set(struct cgpu_info *babcgpu)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ RLIST *rlist = NULL;
|
|
|
|
|
+ int i;
|
|
|
|
|
+
|
|
|
|
|
+ rlist = calloc(MAX_RLISTS, sizeof(*rlist));
|
|
|
|
|
+ if (!rlist)
|
|
|
|
|
+ quithere(1, "Failed to calloc rlist - when old count=%d", babinfo->rlist_count);
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->rlist_count += MAX_RLISTS;
|
|
|
|
|
+ babinfo->rfree_count = MAX_RLISTS;
|
|
|
|
|
+
|
|
|
|
|
+ rlist[0].prev = NULL;
|
|
|
|
|
+ rlist[0].next = &(rlist[1]);
|
|
|
|
|
+ for (i = 1; i < MAX_RLISTS-1; i++) {
|
|
|
|
|
+ rlist[i].prev = &rlist[i-1];
|
|
|
|
|
+ rlist[i].next = &rlist[i+1];
|
|
|
|
|
+ }
|
|
|
|
|
+ rlist[MAX_RLISTS-1].prev = &(rlist[MAX_RLISTS-2]);
|
|
|
|
|
+ rlist[MAX_RLISTS-1].next = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ return rlist;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static RLIST *store_nonce(struct cgpu_info *babcgpu, int chip, uint32_t nonce, bool first_second)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ RLIST *ritem = NULL;
|
|
|
|
|
+ int ran_out = 0;
|
|
|
|
|
+
|
|
|
|
|
+ mutex_lock(&(babinfo->res_lock));
|
|
|
|
|
+
|
|
|
|
|
+ if (babinfo->rfree_list == NULL) {
|
|
|
|
|
+ ran_out = babinfo->rlist_count;
|
|
|
|
|
+ babinfo->rfree_list = new_rlist_set(babcgpu);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // unlink from rfree
|
|
|
|
|
+ ritem = babinfo->rfree_list;
|
|
|
|
|
+ babinfo->rfree_list = babinfo->rfree_list->next;
|
|
|
|
|
+ if (babinfo->rfree_list)
|
|
|
|
|
+ babinfo->rfree_list->prev = NULL;
|
|
|
|
|
+ babinfo->rfree_count--;
|
|
|
|
|
+
|
|
|
|
|
+ // add to head of results
|
|
|
|
|
+ ritem->next = babinfo->res_list_head;
|
|
|
|
|
+ ritem->prev = NULL;
|
|
|
|
|
+ babinfo->res_list_head = ritem;
|
|
|
|
|
+ if (ritem->next)
|
|
|
|
|
+ ritem->next->prev = ritem;
|
|
|
|
|
+ else
|
|
|
|
|
+ babinfo->res_list_tail = ritem;
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->res_count++;
|
|
|
|
|
+
|
|
|
|
|
+ ritem->chip = chip;
|
|
|
|
|
+ ritem->nonce = nonce;
|
|
|
|
|
+ ritem->first_second = first_second;
|
|
|
|
|
+
|
|
|
|
|
+ mutex_unlock(&(babinfo->res_lock));
|
|
|
|
|
+
|
|
|
|
|
+ if (ran_out > 0) {
|
|
|
|
|
+ applog(LOG_ERR, "%s%i: RLIST used count exceeded %d, now %d (work=%d chip=%d)",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id,
|
|
|
|
|
+ ran_out, babinfo->rlist_count,
|
|
|
|
|
+ babinfo->work_count,
|
|
|
|
|
+ babinfo->chip_count);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return ritem;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static bool oldest_nonce(struct cgpu_info *babcgpu, int *chip, uint32_t *nonce, bool *first_second)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ RLIST *ritem = NULL;
|
|
|
|
|
+ bool found = false;
|
|
|
|
|
+
|
|
|
|
|
+ mutex_lock(&(babinfo->res_lock));
|
|
|
|
|
+
|
|
|
|
|
+ if (babinfo->res_list_tail) {
|
|
|
|
|
+ // unlink from res
|
|
|
|
|
+ ritem = babinfo->res_list_tail;
|
|
|
|
|
+ if (ritem->prev) {
|
|
|
|
|
+ ritem->prev->next = NULL;
|
|
|
|
|
+ babinfo->res_list_tail = ritem->prev;
|
|
|
|
|
+ } else
|
|
|
|
|
+ babinfo->res_list_head = babinfo->res_list_tail = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->res_count--;
|
|
|
|
|
+
|
|
|
|
|
+ found = true;
|
|
|
|
|
+ *chip = ritem->chip;
|
|
|
|
|
+ *nonce = ritem->nonce;
|
|
|
|
|
+ *first_second = ritem->first_second;
|
|
|
|
|
+
|
|
|
|
|
+ // add to rfree
|
|
|
|
|
+ ritem->next = babinfo->rfree_list;
|
|
|
|
|
+ ritem->prev = NULL;
|
|
|
|
|
+ if (ritem->next)
|
|
|
|
|
+ ritem->next->prev = ritem;
|
|
|
|
|
+ babinfo->rfree_list = ritem;
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->rfree_count++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ mutex_unlock(&(babinfo->res_lock));
|
|
|
|
|
+
|
|
|
|
|
+ return found;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void _bab_reset(__maybe_unused struct cgpu_info *babcgpu, struct bab_info *babinfo, int bank, int times)
|
|
|
|
|
+{
|
|
|
|
|
+ const int banks[4] = { 18, 23, 24, 25 };
|
|
|
|
|
+ int i;
|
|
|
|
|
+
|
|
|
|
|
+ BAB_INP_GPIO(10);
|
|
|
|
|
+ BAB_OUT_GPIO(10);
|
|
|
|
|
+ BAB_INP_GPIO(11);
|
|
|
|
|
+ BAB_OUT_GPIO(11);
|
|
|
|
|
+
|
|
|
|
|
+ if (bank) {
|
|
|
|
|
+ for (i = 0; i < 4; i++) {
|
|
|
|
|
+ BAB_INP_GPIO(banks[i]);
|
|
|
|
|
+ BAB_OUT_GPIO(banks[i]);
|
|
|
|
|
+ if (bank == i+1)
|
|
|
|
|
+ BAB_GPIO_SET = 1 << banks[i];
|
|
|
|
|
+ else
|
|
|
|
|
+ BAB_GPIO_CLR = 1 << banks[i];
|
|
|
|
|
+ }
|
|
|
|
|
+ cgsleep_us(4096);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ for (i = 0; i < 4; i++)
|
|
|
|
|
+ BAB_INP_GPIO(banks[i]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ BAB_GPIO_SET = 1 << 11;
|
|
|
|
|
+ for (i = 0; i < times; i++) { // 1us = 1MHz
|
|
|
|
|
+ BAB_GPIO_SET = 1 << 10;
|
|
|
|
|
+ cgsleep_us(1);
|
|
|
|
|
+ BAB_GPIO_CLR = 1 << 10;
|
|
|
|
|
+ cgsleep_us(1);
|
|
|
|
|
+ }
|
|
|
|
|
+ BAB_GPIO_CLR = 1 << 11;
|
|
|
|
|
+ BAB_INP_GPIO(11);
|
|
|
|
|
+ BAB_INP_GPIO(10);
|
|
|
|
|
+ BAB_INP_GPIO(9);
|
|
|
|
|
+ BAB_OUT_GPIO_V(11, 0);
|
|
|
|
|
+ BAB_OUT_GPIO_V(10, 0);
|
|
|
|
|
+ BAB_OUT_GPIO_V(9, 0);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TODO: handle a false return where this is called?
|
|
|
|
|
+static bool _bab_txrx(struct cgpu_info *babcgpu, struct bab_info *babinfo, int buf, uint32_t siz, bool detect_ignore, const char *file, const char *func, const int line)
|
|
|
|
|
+{
|
|
|
|
|
+ int bank, i;
|
|
|
|
|
+ uint32_t pos;
|
|
|
|
|
+ struct spi_ioc_transfer tran;
|
|
|
|
|
+ uintptr_t rbuf, wbuf;
|
|
|
|
|
+
|
|
|
|
|
+ wbuf = (uintptr_t)(babinfo->buf_write[buf]);
|
|
|
|
|
+ rbuf = (uintptr_t)(babinfo->buf_read[buf]);
|
|
|
|
|
+
|
|
|
|
|
+ memset(&tran, 0, sizeof(tran));
|
|
|
|
|
+ tran.delay_usecs = 0;
|
|
|
|
|
+ tran.speed_hz = BAB_SPI_SPEED;
|
|
|
|
|
+
|
|
|
|
|
+ i = 0;
|
|
|
|
|
+ pos = 0;
|
|
|
|
|
+ for (bank = 0; bank <= BAB_MAXBANKS; bank++) {
|
|
|
|
|
+ if (babinfo->bank_off[buf][bank]) {
|
|
|
|
|
+ bab_reset(bank, 64);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (unlikely(bank > BAB_MAXBANKS)) {
|
|
|
|
|
+ applog(LOG_ERR, "%s%d: %s() failed to find a bank" BAB_FFL,
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id,
|
|
|
|
|
+ __func__, BAB_FFL_PASS);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ while (siz > 0) {
|
|
|
|
|
+ tran.tx_buf = wbuf;
|
|
|
|
|
+ tran.rx_buf = rbuf;
|
|
|
|
|
+ tran.speed_hz = BAB_SPI_SPEED;
|
|
|
|
|
+ if (pos == babinfo->bank_off[buf][bank]) {
|
|
|
|
|
+ for (; ++bank <= BAB_MAXBANKS; ) {
|
|
|
|
|
+ if (babinfo->bank_off[buf][bank] > pos) {
|
|
|
|
|
+ bab_reset(bank, 64);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (siz < BAB_SPI_BUFSIZ)
|
|
|
|
|
+ tran.len = siz;
|
|
|
|
|
+ else
|
|
|
|
|
+ tran.len = BAB_SPI_BUFSIZ;
|
|
|
|
|
+
|
|
|
|
|
+ if (pos < babinfo->bank_off[buf][bank] &&
|
|
|
|
|
+ babinfo->bank_off[buf][bank] < (pos + tran.len))
|
|
|
|
|
+ tran.len = babinfo->bank_off[buf][bank] - pos;
|
|
|
|
|
+
|
|
|
|
|
+ for (; i < babinfo->chips; i++) {
|
|
|
|
|
+ if (!babinfo->chip_off[buf][i])
|
|
|
|
|
+ continue;
|
|
|
|
|
+ if (babinfo->chip_off[buf][i] >= pos + tran.len) {
|
|
|
|
|
+ tran.speed_hz = babinfo->chip_spis[i];
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (unlikely(i > babinfo->chips)) {
|
|
|
|
|
+ applog(LOG_ERR, "%s%d: %s() failed to find chip" BAB_FFL,
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id,
|
|
|
|
|
+ __func__, BAB_FFL_PASS);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (unlikely(babinfo->chip_spis[i] == BAB_SPI_SPEED)) {
|
|
|
|
|
+ applog(LOG_DEBUG, "%s%d: %s() chip[%d] speed %d shouldn't be %d" BAB_FFL,
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id,
|
|
|
|
|
+ __func__, i, (int)babinfo->chip_spis[i],
|
|
|
|
|
+ BAB_SPI_SPEED, BAB_FFL_PASS);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (unlikely(tran.speed_hz == BAB_SPI_SPEED)) {
|
|
|
|
|
+ applog(LOG_DEBUG, "%s%d: %s() transfer speed %d shouldn't be %d" BAB_FFL,
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id,
|
|
|
|
|
+ __func__, (int)tran.speed_hz,
|
|
|
|
|
+ BAB_SPI_SPEED, BAB_FFL_PASS);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (ioctl(babinfo->spifd, SPI_IOC_MESSAGE(1), (void *)&tran) < 0) {
|
|
|
|
|
+ if (!detect_ignore || errno != 110) {
|
|
|
|
|
+ applog(LOG_ERR, "%s%d: ioctl failed err=%d" BAB_FFL,
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id,
|
|
|
|
|
+ errno, BAB_FFL_PASS);
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ siz -= tran.len;
|
|
|
|
|
+ wbuf += tran.len;
|
|
|
|
|
+ rbuf += tran.len;
|
|
|
|
|
+ pos += tran.len;
|
|
|
|
|
+ }
|
|
|
|
|
+ mutex_lock(&(babinfo->did_lock));
|
|
|
|
|
+ cgtime(&(babinfo->last_did));
|
|
|
|
|
+ mutex_unlock(&(babinfo->did_lock));
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void _bab_add_buf_rev(__maybe_unused struct cgpu_info *babcgpu, struct bab_info *babinfo, const uint8_t *data, uint32_t siz, const char *file, const char *func, const int line)
|
|
|
|
|
+{
|
|
|
|
|
+ uint8_t tmp;
|
|
|
|
|
+ uint32_t now_used, i;
|
|
|
|
|
+ int buf;
|
|
|
|
|
+
|
|
|
|
|
+ buf = babinfo->buffer;
|
|
|
|
|
+ now_used = babinfo->buf_used[buf];
|
|
|
|
|
+ if (now_used + siz >= BAB_MAXBUF) {
|
|
|
|
|
+ quitfrom(1, file, func, line,
|
|
|
|
|
+ "%s() buffer %d limit of %d exceeded=%d siz=%d",
|
|
|
|
|
+ __func__, buf, BAB_MAXBUF, now_used + siz, siz);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < siz; i++) {
|
|
|
|
|
+ tmp = data[i];
|
|
|
|
|
+ tmp = ((tmp & 0xaa)>>1) | ((tmp & 0x55) << 1);
|
|
|
|
|
+ tmp = ((tmp & 0xcc)>>2) | ((tmp & 0x33) << 2);
|
|
|
|
|
+ tmp = ((tmp & 0xf0)>>4) | ((tmp & 0x0f) << 4);
|
|
|
|
|
+ babinfo->buf_write[buf][now_used + i] = tmp;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->buf_used[buf] += siz;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void _bab_add_buf(__maybe_unused struct cgpu_info *babcgpu, struct bab_info *babinfo, const uint8_t *data, size_t siz, const char *file, const char *func, const int line)
|
|
|
|
|
+{
|
|
|
|
|
+ uint32_t now_used;
|
|
|
|
|
+ int buf;
|
|
|
|
|
+
|
|
|
|
|
+ buf = babinfo->buffer;
|
|
|
|
|
+ now_used = babinfo->buf_used[buf];
|
|
|
|
|
+ if (now_used + siz >= BAB_MAXBUF) {
|
|
|
|
|
+ quitfrom(1, file, func, line,
|
|
|
|
|
+ "%s() buffer %d limit of %d exceeded=%d siz=%d",
|
|
|
|
|
+ __func__, buf, BAB_MAXBUF, (int)(now_used + siz), (int)siz);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ memcpy(&(babinfo->buf_write[buf][now_used]), data, siz);
|
|
|
|
|
+ babinfo->buf_used[buf] += siz;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void _bab_add_data(struct cgpu_info *babcgpu, struct bab_info *babinfo, uint32_t addr, const uint8_t *data, size_t siz, const char *file, const char *func, const int line)
|
|
|
|
|
+{
|
|
|
|
|
+ uint8_t tmp[3];
|
|
|
|
|
+ int trf_siz;
|
|
|
|
|
+
|
|
|
|
|
+ if (siz < BAB_ADD_MIN || siz > BAB_ADD_MAX) {
|
|
|
|
|
+ quitfrom(1, file, func, line,
|
|
|
|
|
+ "%s() called with invalid siz=%d (min=%d max=%d)",
|
|
|
|
|
+ __func__, (int)siz, BAB_ADD_MIN, BAB_ADD_MAX);
|
|
|
|
|
+ }
|
|
|
|
|
+ trf_siz = siz / 4;
|
|
|
|
|
+ tmp[0] = (trf_siz - 1) | 0xE0;
|
|
|
|
|
+ tmp[1] = (addr >> 8) & 0xff;
|
|
|
|
|
+ tmp[2] = addr & 0xff;
|
|
|
|
|
+ _bab_add_buf(babcgpu, babinfo, tmp, sizeof(tmp), BAB_FFL_PASS);
|
|
|
|
|
+ _bab_add_buf_rev(babcgpu, babinfo, data, siz, BAB_FFL_PASS);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void _bab_config_reg(struct cgpu_info *babcgpu, struct bab_info *babinfo, uint32_t reg, bool enable, const char *file, const char *func, const int line)
|
|
|
|
|
+{
|
|
|
|
|
+ if (enable) {
|
|
|
|
|
+ _bab_add_data(babcgpu, babinfo, BAB_REG_ADDR + reg*32,
|
|
|
|
|
+ bab_reg_ena, sizeof(bab_reg_ena), BAB_FFL_PASS);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ _bab_add_data(babcgpu, babinfo, BAB_REG_ADDR + reg*32,
|
|
|
|
|
+ bab_reg_dis, sizeof(bab_reg_dis), BAB_FFL_PASS);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void bab_set_osc(struct bab_info *babinfo, int chip)
|
|
|
|
|
+{
|
|
|
|
|
+ int fast, i;
|
|
|
|
|
+
|
|
|
|
|
+ fast = babinfo->chip_fast[chip];
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < BAB_OSC && fast > BAB_OSC; i++, fast -= BAB_OSC) {
|
|
|
|
|
+ babinfo->osc[i] = 0xff;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (i < BAB_OSC && fast > 0 && fast <= BAB_OSC)
|
|
|
|
|
+ babinfo->osc[i++] = bab_osc_bits[fast - 1];
|
|
|
|
|
+ for (; i < BAB_OSC; i++)
|
|
|
|
|
+ babinfo->osc[i] = 0x00;
|
|
|
|
|
+
|
|
|
|
|
+ applog(LOG_DEBUG, "@osc(chip=%d) fast=%d 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", chip, fast, babinfo->osc[0], babinfo->osc[1], babinfo->osc[2], babinfo->osc[3], babinfo->osc[4], babinfo->osc[5], babinfo->osc[6], babinfo->osc[7]);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static bool bab_put(struct cgpu_info *babcgpu, struct bab_info *babinfo)
|
|
|
|
|
+{
|
|
|
|
|
+ int buf, i, reg, bank = 0;
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->buffer = -1;
|
|
|
|
|
+
|
|
|
|
|
+ mutex_lock(&(babinfo->spi_lock));
|
|
|
|
|
+ if (babinfo->buf_status[0] == BAB_STATE_DONE) {
|
|
|
|
|
+ babinfo->buffer = 0;
|
|
|
|
|
+ } else if (babinfo->buf_status[1] == BAB_STATE_DONE) {
|
|
|
|
|
+ babinfo->buffer = 1;
|
|
|
|
|
+ } else if (babinfo->buf_status[0] == BAB_STATE_READY) {
|
|
|
|
|
+ babinfo->buf_status[0] = BAB_STATE_DONE;
|
|
|
|
|
+ babinfo->buffer = 0;
|
|
|
|
|
+ } else if (babinfo->buf_status[1] == BAB_STATE_READY) {
|
|
|
|
|
+ babinfo->buf_status[1] = BAB_STATE_DONE;
|
|
|
|
|
+ babinfo->buffer = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ mutex_unlock(&(babinfo->spi_lock));
|
|
|
|
|
+
|
|
|
|
|
+ if (babinfo->buffer == -1)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ buf = babinfo->buffer;
|
|
|
|
|
+ babinfo->buf_used[buf] = 0;
|
|
|
|
|
+ memset(babinfo->bank_off[buf], 0, sizeof(babinfo->bank_off) / BAB_SPI_BUFFERS);
|
|
|
|
|
+
|
|
|
|
|
+ BAB_ADD_BREAK();
|
|
|
|
|
+ for (i = 0; i < babinfo->chips; i++) {
|
|
|
|
|
+ if (babinfo->chip_bank[i] != bank) {
|
|
|
|
|
+ babinfo->bank_off[buf][bank] = babinfo->buf_used[buf];
|
|
|
|
|
+ bank = babinfo->chip_bank[i];
|
|
|
|
|
+ BAB_ADD_BREAK();
|
|
|
|
|
+ }
|
|
|
|
|
+ if (i == babinfo->fixchip &&
|
|
|
|
|
+ (BAB_CFGD_SET(babinfo->chip_conf[i]) ||
|
|
|
|
|
+ !babinfo->chip_conf[i])) {
|
|
|
|
|
+ bab_set_osc(babinfo, i);
|
|
|
|
|
+ bab_add_data(BAB_OSC_ADDR, babinfo->osc, sizeof(babinfo->osc));
|
|
|
|
|
+ bab_config_reg(BAB_ICLK_REG, BAB_ICLK_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ bab_config_reg(BAB_FAST_REG, BAB_FAST_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ bab_config_reg(BAB_DIV2_REG, BAB_DIV2_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ bab_config_reg(BAB_SLOW_REG, BAB_SLOW_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ bab_config_reg(BAB_OCLK_REG, BAB_OCLK_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ for (reg = BAB_REG_CLR_FROM; reg <= BAB_REG_CLR_TO; reg++)
|
|
|
|
|
+ bab_config_reg(reg, false);
|
|
|
|
|
+ if (babinfo->chip_conf[i]) {
|
|
|
|
|
+ bab_add_data(BAB_COUNT_ADDR, bab_counters, sizeof(bab_counters));
|
|
|
|
|
+ bab_add_data(BAB_W1A_ADDR, bab_w1, sizeof(bab_w1));
|
|
|
|
|
+ bab_add_data(BAB_W1B_ADDR, bab_w1, sizeof(bab_w1)/2);
|
|
|
|
|
+ bab_add_data(BAB_W2_ADDR, bab_w2, sizeof(bab_w2));
|
|
|
|
|
+ babinfo->chip_conf[i] ^= BAB_CFGD_VAL;
|
|
|
|
|
+ }
|
|
|
|
|
+ babinfo->old_fast[i] = babinfo->chip_fast[i];
|
|
|
|
|
+ babinfo->old_conf[i] = babinfo->chip_conf[i];
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (babinfo->old_fast[i] != babinfo->chip_fast[i]) {
|
|
|
|
|
+ bab_set_osc(babinfo, i);
|
|
|
|
|
+ bab_add_data(BAB_OSC_ADDR, babinfo->osc, sizeof(babinfo->osc));
|
|
|
|
|
+ babinfo->old_fast[i] = babinfo->chip_fast[i];
|
|
|
|
|
+ }
|
|
|
|
|
+ if (babinfo->old_conf[i] != babinfo->chip_conf[i]) {
|
|
|
|
|
+ if (BAB_ICLK_SET(babinfo->old_conf[i]) !=
|
|
|
|
|
+ BAB_ICLK_SET(babinfo->chip_conf[i]))
|
|
|
|
|
+ bab_config_reg(BAB_ICLK_REG,
|
|
|
|
|
+ BAB_ICLK_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ if (BAB_FAST_SET(babinfo->old_conf[i]) !=
|
|
|
|
|
+ BAB_FAST_SET(babinfo->chip_conf[i]))
|
|
|
|
|
+ bab_config_reg(BAB_FAST_REG,
|
|
|
|
|
+ BAB_FAST_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ if (BAB_DIV2_SET(babinfo->old_conf[i]) !=
|
|
|
|
|
+ BAB_DIV2_SET(babinfo->chip_conf[i]))
|
|
|
|
|
+ bab_config_reg(BAB_DIV2_REG,
|
|
|
|
|
+ BAB_DIV2_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ if (BAB_SLOW_SET(babinfo->old_conf[i]) !=
|
|
|
|
|
+ BAB_SLOW_SET(babinfo->chip_conf[i]))
|
|
|
|
|
+ bab_config_reg(BAB_SLOW_REG,
|
|
|
|
|
+ BAB_SLOW_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ if (BAB_OCLK_SET(babinfo->old_conf[i]) !=
|
|
|
|
|
+ BAB_OCLK_SET(babinfo->chip_conf[i]))
|
|
|
|
|
+ bab_config_reg(BAB_OCLK_REG,
|
|
|
|
|
+ BAB_OCLK_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ babinfo->old_conf[i] = babinfo->chip_conf[i];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ babinfo->chip_off[buf][i] = babinfo->buf_used[buf] + 3;
|
|
|
|
|
+ if (babinfo->chip_conf[i])
|
|
|
|
|
+ bab_add_data(BAB_INP_ADDR, (uint8_t *)(&(babinfo->chip_input[i])),
|
|
|
|
|
+ sizeof(babinfo->chip_input[i]));
|
|
|
|
|
+
|
|
|
|
|
+ BAB_ADD_ASYNC();
|
|
|
|
|
+ }
|
|
|
|
|
+ babinfo->chip_off[buf][i] = babinfo->buf_used[buf];
|
|
|
|
|
+ babinfo->bank_off[buf][bank] = babinfo->buf_used[buf];
|
|
|
|
|
+
|
|
|
|
|
+ mutex_lock(&(babinfo->spi_lock));
|
|
|
|
|
+ babinfo->buf_status[buf] = BAB_STATE_READY;
|
|
|
|
|
+ mutex_unlock(&(babinfo->spi_lock));
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->fixchip = (babinfo->fixchip + 1) % babinfo->chips;
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static bool bab_get(__maybe_unused struct cgpu_info *babcgpu, struct bab_info *babinfo)
|
|
|
|
|
+{
|
|
|
|
|
+ int buf, i;
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->buffer = -1;
|
|
|
|
|
+
|
|
|
|
|
+ mutex_lock(&(babinfo->spi_lock));
|
|
|
|
|
+ if (babinfo->buf_status[0] == BAB_STATE_SENT) {
|
|
|
|
|
+ babinfo->buf_status[0] = BAB_STATE_READING;
|
|
|
|
|
+ babinfo->buffer = 0;
|
|
|
|
|
+ } else if (babinfo->buf_status[1] == BAB_STATE_SENT) {
|
|
|
|
|
+ babinfo->buf_status[1] = BAB_STATE_READING;
|
|
|
|
|
+ babinfo->buffer = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ mutex_unlock(&(babinfo->spi_lock));
|
|
|
|
|
+
|
|
|
|
|
+ if (babinfo->buffer == -1)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ buf = babinfo->buffer;
|
|
|
|
|
+ for (i = 0; i < babinfo->chips; i++) {
|
|
|
|
|
+ if (babinfo->chip_conf[i] & 0x7f) {
|
|
|
|
|
+ memcpy((void *)&(babinfo->chip_results[i]),
|
|
|
|
|
+ (void *)(babinfo->buf_read[buf] + babinfo->chip_off[buf][i]),
|
|
|
|
|
+ sizeof(babinfo->chip_results[0]));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ mutex_lock(&(babinfo->spi_lock));
|
|
|
|
|
+ babinfo->buf_status[buf] = BAB_STATE_DONE;
|
|
|
|
|
+ mutex_unlock(&(babinfo->spi_lock));
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void bab_detect_chips(struct cgpu_info *babcgpu, struct bab_info *babinfo, int bank, int first, int last)
|
|
|
|
|
+{
|
|
|
|
|
+ int buf, i, reg, j;
|
|
|
|
|
+
|
|
|
|
|
+ if (sizeof(struct bab_work_send) != sizeof(bab_test_data)) {
|
|
|
|
|
+ quithere(1, "struct bab_work_send (%d) and bab_test_data (%d)"
|
|
|
|
|
+ " must be the same size",
|
|
|
|
|
+ (int)sizeof(struct bab_work_send),
|
|
|
|
|
+ (int)sizeof(bab_test_data));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ memset(babinfo->bank_off, 0, sizeof(babinfo->bank_off));
|
|
|
|
|
+
|
|
|
|
|
+ buf = babinfo->buffer = 0;
|
|
|
|
|
+ babinfo->buf_used[buf] = 0;
|
|
|
|
|
+ BAB_ADD_BREAK();
|
|
|
|
|
+ for (i = first; i < last && i < BAB_MAXCHIPS; i++) {
|
|
|
|
|
+ bab_set_osc(babinfo, i);
|
|
|
|
|
+ bab_add_data(BAB_OSC_ADDR, babinfo->osc, sizeof(babinfo->osc));
|
|
|
|
|
+ bab_config_reg(BAB_ICLK_REG, BAB_ICLK_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ bab_config_reg(BAB_FAST_REG, BAB_FAST_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ bab_config_reg(BAB_DIV2_REG, BAB_DIV2_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ bab_config_reg(BAB_SLOW_REG, BAB_SLOW_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ bab_config_reg(BAB_OCLK_REG, BAB_OCLK_BIT(babinfo->chip_conf[i]));
|
|
|
|
|
+ for (reg = BAB_REG_CLR_FROM; reg <= BAB_REG_CLR_TO; reg++)
|
|
|
|
|
+ bab_config_reg(reg, false);
|
|
|
|
|
+ bab_add_data(BAB_COUNT_ADDR, bab_counters, sizeof(bab_counters));
|
|
|
|
|
+ bab_add_data(BAB_W1A_ADDR, bab_w1, sizeof(bab_w1));
|
|
|
|
|
+ bab_add_data(BAB_W1B_ADDR, bab_w1, sizeof(bab_w1)/2);
|
|
|
|
|
+ bab_add_data(BAB_W2_ADDR, bab_w2, sizeof(bab_w2));
|
|
|
|
|
+ babinfo->chip_off[buf][i] = babinfo->buf_used[buf] + 3;
|
|
|
|
|
+ bab_add_data(BAB_INP_ADDR, bab_test_data, sizeof(bab_test_data));
|
|
|
|
|
+ babinfo->chip_off[buf][i+1] = babinfo->buf_used[buf];
|
|
|
|
|
+ babinfo->bank_off[buf][bank] = babinfo->buf_used[buf];
|
|
|
|
|
+ babinfo->chips = i + 1;
|
|
|
|
|
+ bab_txrx(buf, babinfo->buf_used[buf], false);
|
|
|
|
|
+ babinfo->buf_used[buf] = 0;
|
|
|
|
|
+ BAB_ADD_BREAK();
|
|
|
|
|
+ for (j = first; j <= i; j++) {
|
|
|
|
|
+ babinfo->chip_off[buf][j] = babinfo->buf_used[buf] + 3;
|
|
|
|
|
+ BAB_ADD_ASYNC();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ buf = babinfo->buffer = 1;
|
|
|
|
|
+ babinfo->buf_used[buf] = 0;
|
|
|
|
|
+ BAB_ADD_BREAK();
|
|
|
|
|
+ for (i = first; i < last && i < BAB_MAXCHIPS; i++) {
|
|
|
|
|
+ babinfo->chip_off[buf][i] = babinfo->buf_used[buf] + 3;
|
|
|
|
|
+ bab_add_data(BAB_INP_ADDR, bab_test_data, sizeof(bab_test_data));
|
|
|
|
|
+ BAB_ADD_ASYNC();
|
|
|
|
|
+ }
|
|
|
|
|
+ babinfo->chip_off[buf][i] = babinfo->buf_used[buf];
|
|
|
|
|
+ babinfo->bank_off[buf][bank] = babinfo->buf_used[buf];
|
|
|
|
|
+ babinfo->chips = i;
|
|
|
|
|
+ bab_txrx(buf, babinfo->buf_used[buf], true);
|
|
|
|
|
+ babinfo->buf_used[buf] = 0;
|
|
|
|
|
+ babinfo->chips = first;
|
|
|
|
|
+ for (i = first; i < last && i < BAB_MAXCHIPS; i++) {
|
|
|
|
|
+ uint32_t tmp[DATA_UINTS-1];
|
|
|
|
|
+ memcpy(tmp, babinfo->buf_read[buf]+babinfo->chip_off[buf][i], sizeof(tmp));
|
|
|
|
|
+ for (j = 0; j < BAB_SPI_BUFFERS; j++)
|
|
|
|
|
+ babinfo->chip_off[j][i] = 0;
|
|
|
|
|
+ for (j = 0; j < BAB_REPLY_NONCES; j++) {
|
|
|
|
|
+ if (tmp[j] != 0xffffffff && tmp[j] != 0x00000000) {
|
|
|
|
|
+ babinfo->chip_bank[i] = bank;
|
|
|
|
|
+ babinfo->chips = i + 1;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ for (i = first ; i < babinfo->chips; i++)
|
|
|
|
|
+ babinfo->chip_bank[i] = bank;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static const char *bab_modules[] = {
|
|
|
|
|
+ "i2c-dev",
|
|
|
|
|
+ "i2c-bcm2708",
|
|
|
|
|
+ "spidev",
|
|
|
|
|
+ "spi-bcm2708",
|
|
|
|
|
+ NULL
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+static const char *bab_memory = "/dev/mem";
|
|
|
|
|
+
|
|
|
|
|
+static int bab_memory_addr = 0x20200000;
|
|
|
|
|
+
|
|
|
|
|
+static struct {
|
|
|
|
|
+ int request;
|
|
|
|
|
+ int value;
|
|
|
|
|
+} bab_ioc[] = {
|
|
|
|
|
+ { SPI_IOC_RD_MODE, 0 },
|
|
|
|
|
+ { SPI_IOC_WR_MODE, 0 },
|
|
|
|
|
+ { SPI_IOC_RD_BITS_PER_WORD, 8 },
|
|
|
|
|
+ { SPI_IOC_WR_BITS_PER_WORD, 8 },
|
|
|
|
|
+ { SPI_IOC_RD_MAX_SPEED_HZ, 1000000 },
|
|
|
|
|
+ { SPI_IOC_WR_MAX_SPEED_HZ, 1000000 },
|
|
|
|
|
+ { -1, -1 }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+static bool bab_init_gpio(struct cgpu_info *babcgpu, struct bab_info *babinfo, int bus, int chip)
|
|
|
|
|
+{
|
|
|
|
|
+ int i, err, memfd, data;
|
|
|
|
|
+ char buf[64];
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; bab_modules[i]; i++) {
|
|
|
|
|
+ snprintf(buf, sizeof(buf), "modprobe %s", bab_modules[i]);
|
|
|
|
|
+ err = system(buf);
|
|
|
|
|
+ if (err) {
|
|
|
|
|
+ applog(LOG_ERR, "%s failed to modprobe %s (%d) - you need to be root?",
|
|
|
|
|
+ babcgpu->drv->dname,
|
|
|
|
|
+ bab_modules[i], err);
|
|
|
|
|
+ goto bad_out;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ memfd = open(bab_memory, O_RDWR | O_SYNC);
|
|
|
|
|
+ if (memfd < 0) {
|
|
|
|
|
+ applog(LOG_ERR, "%s failed open %s (%d)",
|
|
|
|
|
+ babcgpu->drv->dname,
|
|
|
|
|
+ bab_memory, errno);
|
|
|
|
|
+ goto bad_out;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->gpio = (volatile unsigned *)mmap(NULL, BAB_SPI_BUFSIZ,
|
|
|
|
|
+ PROT_READ | PROT_WRITE,
|
|
|
|
|
+ MAP_SHARED, memfd,
|
|
|
|
|
+ bab_memory_addr);
|
|
|
|
|
+ if (babinfo->gpio == MAP_FAILED) {
|
|
|
|
|
+ close(memfd);
|
|
|
|
|
+ applog(LOG_ERR, "%s failed mmap gpio (%d)",
|
|
|
|
|
+ babcgpu->drv->dname,
|
|
|
|
|
+ errno);
|
|
|
|
|
+ goto bad_out;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ close(memfd);
|
|
|
|
|
+
|
|
|
|
|
+ snprintf(buf, sizeof(buf), "/dev/spidev%d.%d", bus, chip);
|
|
|
|
|
+ babinfo->spifd = open(buf, O_RDWR);
|
|
|
|
|
+ if (babinfo->spifd < 0) {
|
|
|
|
|
+ applog(LOG_ERR, "%s failed to open spidev (%d)",
|
|
|
|
|
+ babcgpu->drv->dname,
|
|
|
|
|
+ errno);
|
|
|
|
|
+ goto map_out;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ babcgpu->device_path = strdup(buf);
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; bab_ioc[i].value != -1; i++) {
|
|
|
|
|
+ data = bab_ioc[i].value;
|
|
|
|
|
+ err = ioctl(babinfo->spifd, bab_ioc[i].request, (void *)&data);
|
|
|
|
|
+ if (err < 0) {
|
|
|
|
|
+ applog(LOG_ERR, "%s failed ioctl (%d) (%d)",
|
|
|
|
|
+ babcgpu->drv->dname,
|
|
|
|
|
+ i, errno);
|
|
|
|
|
+ goto close_out;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < BAB_MAXCHIPS; i++)
|
|
|
|
|
+ babinfo->chip_spis[i] = (int)((1000000.0 / (100.0 + 31.0 * (i + 1))) * 1000);
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+
|
|
|
|
|
+close_out:
|
|
|
|
|
+ close(babinfo->spifd);
|
|
|
|
|
+ babinfo->spifd = 0;
|
|
|
|
|
+ free(babcgpu->device_path);
|
|
|
|
|
+ babcgpu->device_path = NULL;
|
|
|
|
|
+map_out:
|
|
|
|
|
+ munmap((void *)(babinfo->gpio), BAB_SPI_BUFSIZ);
|
|
|
|
|
+ babinfo->gpio = NULL;
|
|
|
|
|
+bad_out:
|
|
|
|
|
+ return false;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void bab_init_chips(struct cgpu_info *babcgpu, struct bab_info *babinfo)
|
|
|
|
|
+{
|
|
|
|
|
+ bab_detect_chips(babcgpu, babinfo, 0, 0, BAB_MAXCHIPS);
|
|
|
|
|
+ memcpy(babinfo->old_conf, babinfo->chip_conf, sizeof(babinfo->old_conf));
|
|
|
|
|
+ memcpy(babinfo->old_fast, babinfo->chip_fast, sizeof(babinfo->old_fast));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void bab_detect(bool hotplug)
|
|
|
|
|
+{
|
|
|
|
|
+ struct cgpu_info *babcgpu = NULL;
|
|
|
|
|
+ struct bab_info *babinfo = NULL;
|
|
|
|
|
+ int i;
|
|
|
|
|
+
|
|
|
|
|
+ if (hotplug)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ babcgpu = calloc(1, sizeof(*babcgpu));
|
|
|
|
|
+ if (unlikely(!babcgpu))
|
|
|
|
|
+ quithere(1, "Failed to calloc babcgpu");
|
|
|
|
|
+
|
|
|
|
|
+ babcgpu->drv = &bab_drv;
|
|
|
|
|
+ babcgpu->deven = DEV_ENABLED;
|
|
|
|
|
+ babcgpu->threads = 1;
|
|
|
|
|
+
|
|
|
|
|
+ babinfo = calloc(1, sizeof(*babinfo));
|
|
|
|
|
+ if (unlikely(!babinfo))
|
|
|
|
|
+ quithere(1, "Failed to calloc babinfo");
|
|
|
|
|
+ babcgpu->device_data = (void *)babinfo;
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < BAB_MAXCHIPS; i++) {
|
|
|
|
|
+ babinfo->chip_conf[i] = BAB_DEFCONF;
|
|
|
|
|
+ babinfo->chip_fast[i] = BAB_DEFSPEED;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ mutex_init(&babinfo->spi_lock);
|
|
|
|
|
+
|
|
|
|
|
+ if (!bab_init_gpio(babcgpu, babinfo, BAB_SPI_BUS, BAB_SPI_CHIP))
|
|
|
|
|
+ goto unalloc;
|
|
|
|
|
+
|
|
|
|
|
+ applog(LOG_WARNING, "%s V1 testing for %d chips ...", babcgpu->drv->dname, BAB_MAXCHIPS);
|
|
|
|
|
+
|
|
|
|
|
+ bab_init_chips(babcgpu, babinfo);
|
|
|
|
|
+
|
|
|
|
|
+ applog(LOG_WARNING, "%s found %d chips", babcgpu->drv->dname, babinfo->chips);
|
|
|
|
|
+
|
|
|
|
|
+ if (babinfo->chips == 0)
|
|
|
|
|
+ goto cleanup;
|
|
|
|
|
+
|
|
|
|
|
+ if (!add_cgpu(babcgpu))
|
|
|
|
|
+ goto cleanup;
|
|
|
|
|
+
|
|
|
|
|
+ mutex_init(&babinfo->res_lock);
|
|
|
|
|
+ mutex_init(&babinfo->did_lock);
|
|
|
|
|
+ cglock_init(&babinfo->blist_lock);
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->initialised = true;
|
|
|
|
|
+
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+cleanup:
|
|
|
|
|
+ close(babinfo->spifd);
|
|
|
|
|
+ munmap((void *)(babinfo->gpio), BAB_SPI_BUFSIZ);
|
|
|
|
|
+unalloc:
|
|
|
|
|
+ mutex_destroy(&babinfo->spi_lock);
|
|
|
|
|
+ free(babinfo);
|
|
|
|
|
+ free(babcgpu);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void bab_identify(__maybe_unused struct cgpu_info *babcgpu)
|
|
|
|
|
+{
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_LONG_WAIT_uS 1200000
|
|
|
|
|
+#define BAB_WAIT_MSG_EVERY 10
|
|
|
|
|
+#define BAB_LONG_WAIT_SLEEP_uS 100000
|
|
|
|
|
+#define BAB_STD_WAIT_uS 3000
|
|
|
|
|
+
|
|
|
|
|
+// thread to do spi txrx
|
|
|
|
|
+static void *bab_spi(void *userdata)
|
|
|
|
|
+{
|
|
|
|
|
+ struct cgpu_info *babcgpu = (struct cgpu_info *)userdata;
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ struct timeval start, stop;
|
|
|
|
|
+ double wait;
|
|
|
|
|
+ int i, buf, msgs;
|
|
|
|
|
+
|
|
|
|
|
+ applog(LOG_DEBUG, "%s%i: SPIing...",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id);
|
|
|
|
|
+
|
|
|
|
|
+ // Wait until we're ready
|
|
|
|
|
+ while (babcgpu->shutdown == false) {
|
|
|
|
|
+ if (babinfo->initialised) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ cgsleep_ms(3);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ msgs = 0;
|
|
|
|
|
+ cgtime(&start);
|
|
|
|
|
+ while (babcgpu->shutdown == false) {
|
|
|
|
|
+ buf = -1;
|
|
|
|
|
+ mutex_lock(&(babinfo->spi_lock));
|
|
|
|
|
+ for (i = 0; i < BAB_SPI_BUFFERS; i++) {
|
|
|
|
|
+ if (babinfo->buf_status[i] == BAB_STATE_READY) {
|
|
|
|
|
+ babinfo->buf_status[i] = BAB_STATE_SENDING;
|
|
|
|
|
+ buf = i;
|
|
|
|
|
+ cgtime(&start);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ mutex_unlock(&(babinfo->spi_lock));
|
|
|
|
|
+
|
|
|
|
|
+ if (buf == -1) {
|
|
|
|
|
+ cgtime(&stop);
|
|
|
|
|
+ wait = us_tdiff(&stop, &start);
|
|
|
|
|
+ if (wait > BAB_LONG_WAIT_uS) {
|
|
|
|
|
+ if ((msgs++ % BAB_WAIT_MSG_EVERY) == 0) {
|
|
|
|
|
+ applog(LOG_WARNING, "%s%i: SPI waiting %.0fus ...",
|
|
|
|
|
+ babcgpu->drv->name,
|
|
|
|
|
+ babcgpu->device_id,
|
|
|
|
|
+ (float)wait);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ cgsleep_us(BAB_LONG_WAIT_SLEEP_uS);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bab_txrx(buf, babinfo->buf_used[buf], false);
|
|
|
|
|
+ cgtime(&stop);
|
|
|
|
|
+ wait = us_tdiff(&stop, &start);
|
|
|
|
|
+ if (wait < BAB_STD_WAIT_uS)
|
|
|
|
|
+ cgsleep_us((uint64_t)(BAB_STD_WAIT_uS - wait));
|
|
|
|
|
+ else if (wait > BAB_LONG_WAIT_uS) {
|
|
|
|
|
+ applog(LOG_DEBUG, "%s%i: SPI waited %.0fus",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id,
|
|
|
|
|
+ (float)wait);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ mutex_lock(&(babinfo->spi_lock));
|
|
|
|
|
+ babinfo->buf_status[i] = BAB_STATE_SENT;
|
|
|
|
|
+ mutex_unlock(&(babinfo->spi_lock));
|
|
|
|
|
+ msgs = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void bab_flush_work(struct cgpu_info *babcgpu)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+
|
|
|
|
|
+ applog(LOG_DEBUG, "%s%i: flushing work",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id);
|
|
|
|
|
+
|
|
|
|
|
+ mutex_lock(&(babinfo->did_lock));
|
|
|
|
|
+ memset(&(babinfo->last_did), 0, sizeof(babinfo->last_did));
|
|
|
|
|
+ mutex_unlock(&(babinfo->did_lock));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void ms3steps(uint32_t *p)
|
|
|
|
|
+{
|
|
|
|
|
+ uint32_t a, b, c, d, e, f, g, h, new_e, new_a;
|
|
|
|
|
+ int i;
|
|
|
|
|
+
|
|
|
|
|
+ a = p[0];
|
|
|
|
|
+ b = p[1];
|
|
|
|
|
+ c = p[2];
|
|
|
|
|
+ d = p[3];
|
|
|
|
|
+ e = p[4];
|
|
|
|
|
+ f = p[5];
|
|
|
|
|
+ g = p[6];
|
|
|
|
|
+ h = p[7];
|
|
|
|
|
+ for (i = 0; i < 3; i++) {
|
|
|
|
|
+ new_e = p[i+16] + sha256_k[i] + h + CH(e,f,g) + SHA256_F2(e) + d;
|
|
|
|
|
+ new_a = p[i+16] + sha256_k[i] + h + CH(e,f,g) + SHA256_F2(e) +
|
|
|
|
|
+ SHA256_F1(a) + MAJ(a,b,c);
|
|
|
|
|
+ d = c;
|
|
|
|
|
+ c = b;
|
|
|
|
|
+ b = a;
|
|
|
|
|
+ a = new_a;
|
|
|
|
|
+ h = g;
|
|
|
|
|
+ g = f;
|
|
|
|
|
+ f = e;
|
|
|
|
|
+ e = new_e;
|
|
|
|
|
+ }
|
|
|
|
|
+ p[15] = a;
|
|
|
|
|
+ p[14] = b;
|
|
|
|
|
+ p[13] = c;
|
|
|
|
|
+ p[12] = d;
|
|
|
|
|
+ p[11] = e;
|
|
|
|
|
+ p[10] = f;
|
|
|
|
|
+ p[9] = g;
|
|
|
|
|
+ p[8] = h;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#define DATA_MERKLE7 16
|
|
|
|
|
+#define DATA_NTIME 17
|
|
|
|
|
+#define DATA_BITS 18
|
|
|
|
|
+#define DATA_NONCE 19
|
|
|
|
|
+
|
|
|
|
|
+#define WORK_MERKLE7 (16*4)
|
|
|
|
|
+#define WORK_NTIME (17*4)
|
|
|
|
|
+#define WORK_BITS (18*4)
|
|
|
|
|
+#define WORK_NONCE (19*4)
|
|
|
|
|
+
|
|
|
|
|
+static uint32_t decnonce(uint32_t in)
|
|
|
|
|
+{
|
|
|
|
|
+ uint32_t out;
|
|
|
|
|
+
|
|
|
|
|
+ /* First part load */
|
|
|
|
|
+ out = (in & 0xFF) << 24;
|
|
|
|
|
+ in >>= 8;
|
|
|
|
|
+
|
|
|
|
|
+ /* Byte reversal */
|
|
|
|
|
+ in = (((in & 0xaaaaaaaa) >> 1) | ((in & 0x55555555) << 1));
|
|
|
|
|
+ in = (((in & 0xcccccccc) >> 2) | ((in & 0x33333333) << 2));
|
|
|
|
|
+ in = (((in & 0xf0f0f0f0) >> 4) | ((in & 0x0f0f0f0f) << 4));
|
|
|
|
|
+
|
|
|
|
|
+ out |= (in >> 2) & 0x3FFFFF;
|
|
|
|
|
+
|
|
|
|
|
+ /* Extraction */
|
|
|
|
|
+ if (in & 1)
|
|
|
|
|
+ out |= (1 << 23);
|
|
|
|
|
+ if (in & 2)
|
|
|
|
|
+ out |= (1 << 22);
|
|
|
|
|
+
|
|
|
|
|
+ out -= 0x800004;
|
|
|
|
|
+ return out;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Find the matching work item by checking the nonce against each work
|
|
|
|
|
+ * item for the chip
|
|
|
|
|
+ * Discard any work items older than a match
|
|
|
|
|
+ */
|
|
|
|
|
+static bool oknonce(struct thr_info *thr, struct cgpu_info *babcgpu, int chip, uint32_t nonce)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ BLIST *bitem;
|
|
|
|
|
+ unsigned int links, tests;
|
|
|
|
|
+ int i;
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->chip_nonces[chip]++;
|
|
|
|
|
+
|
|
|
|
|
+ nonce = decnonce(nonce);
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * We can grab the head of the chip work queue and then
|
|
|
|
|
+ * release the lock and follow it to the end
|
|
|
|
|
+ * since the other thread will only add items above the
|
|
|
|
|
+ * head - it wont touch the list->next pointers from the
|
|
|
|
|
+ * head to the end - only the head->prev pointer may get
|
|
|
|
|
+ * changed
|
|
|
|
|
+ */
|
|
|
|
|
+ cg_rlock(&babinfo->blist_lock);
|
|
|
|
|
+ bitem = babinfo->chip_list[chip];
|
|
|
|
|
+ cg_runlock(&babinfo->blist_lock);
|
|
|
|
|
+
|
|
|
|
|
+ if (!bitem) {
|
|
|
|
|
+ applog(LOG_ERR, "%s%i: chip %d has no work!",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id, chip);
|
|
|
|
|
+ babinfo->untested_nonces++;
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ babinfo->tested_nonces++;
|
|
|
|
|
+
|
|
|
|
|
+ tests = 0;
|
|
|
|
|
+ links = 0;
|
|
|
|
|
+ while (bitem) {
|
|
|
|
|
+ if (!bitem->work) {
|
|
|
|
|
+ applog(LOG_ERR, "%s%i: chip %d bitem links %d has no work!",
|
|
|
|
|
+ babcgpu->drv->name,
|
|
|
|
|
+ babcgpu->device_id,
|
|
|
|
|
+ chip, links);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ for (i = 0; i < BAB_NONCE_OFFSETS; i++) {
|
|
|
|
|
+ tests++;
|
|
|
|
|
+ if (test_nonce(bitem->work, nonce + bab_nonce_offsets[i])) {
|
|
|
|
|
+ submit_tested_work(thr, bitem->work);
|
|
|
|
|
+ babinfo->nonce_offset_count[i]++;
|
|
|
|
|
+ babinfo->chip_good[chip]++;
|
|
|
|
|
+ bitem->nonces++;
|
|
|
|
|
+ babinfo->new_nonces++;
|
|
|
|
|
+ babinfo->ok_nonces++;
|
|
|
|
|
+ free_blist(babcgpu, bitem->next, chip);
|
|
|
|
|
+ babinfo->total_tests += tests;
|
|
|
|
|
+ if (babinfo->max_tests_per_nonce < tests)
|
|
|
|
|
+ babinfo->max_tests_per_nonce = tests;
|
|
|
|
|
+ babinfo->total_links += links;
|
|
|
|
|
+ if (babinfo->max_links < links)
|
|
|
|
|
+ babinfo->max_links = links;
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ bitem = bitem->next;
|
|
|
|
|
+ links++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (babinfo->not_first_reply[chip]) {
|
|
|
|
|
+ babinfo->chip_bad[chip]++;
|
|
|
|
|
+ inc_hw_errors(thr);
|
|
|
|
|
+ } else
|
|
|
|
|
+ babinfo->initial_ignored++;
|
|
|
|
|
+
|
|
|
|
|
+ return false;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Results checking thread
|
|
|
|
|
+static void *bab_res(void *userdata)
|
|
|
|
|
+{
|
|
|
|
|
+ struct cgpu_info *babcgpu = (struct cgpu_info *)userdata;
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ struct thr_info *thr = babcgpu->thr[0];
|
|
|
|
|
+ bool first_second;
|
|
|
|
|
+ uint32_t nonce;
|
|
|
|
|
+ int chip;
|
|
|
|
|
+
|
|
|
|
|
+ applog(LOG_DEBUG, "%s%i: Results...",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id);
|
|
|
|
|
+
|
|
|
|
|
+ // Wait until we're ready
|
|
|
|
|
+ while (babcgpu->shutdown == false) {
|
|
|
|
|
+ if (babinfo->initialised) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ cgsleep_ms(3);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ while (babcgpu->shutdown == false) {
|
|
|
|
|
+ if (!oldest_nonce(babcgpu, &chip, &nonce, &first_second)) {
|
|
|
|
|
+ cgsleep_ms(3);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (first_second)
|
|
|
|
|
+ babinfo->not_first_reply[chip] = true;
|
|
|
|
|
+
|
|
|
|
|
+ oknonce(thr, babcgpu, chip, nonce);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static bool bab_do_work(struct cgpu_info *babcgpu)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ int busy, newbusy, match, work_items = 0;
|
|
|
|
|
+ int spi, mis, miso;
|
|
|
|
|
+ int i, j;
|
|
|
|
|
+ BLIST *bitem;
|
|
|
|
|
+ bool res, got_a_nonce;
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < babinfo->chips; i++) {
|
|
|
|
|
+ bitem = next_work(babcgpu, i);
|
|
|
|
|
+ if (!bitem) {
|
|
|
|
|
+ applog(LOG_ERR, "%s%i: short work list (%i) expected %d - discarded",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id,
|
|
|
|
|
+ i, babinfo->chips);
|
|
|
|
|
+ for (j = 0; j < i; i++)
|
|
|
|
|
+ discard_last(babcgpu, j);
|
|
|
|
|
+
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ memcpy((void *)&(babinfo->chip_input[i].midstate[0]),
|
|
|
|
|
+ bitem->work->midstate, sizeof(bitem->work->midstate));
|
|
|
|
|
+ memcpy((void *)&(babinfo->chip_input[i].merkle7),
|
|
|
|
|
+ (void *)&(bitem->work->data[WORK_MERKLE7]), 12);
|
|
|
|
|
+
|
|
|
|
|
+ ms3steps((void *)&(babinfo->chip_input[i]));
|
|
|
|
|
+ work_items++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Send
|
|
|
|
|
+ res = bab_put(babcgpu, babinfo);
|
|
|
|
|
+ if (!res) {
|
|
|
|
|
+ applog(LOG_DEBUG, "%s%i: couldn't put work ...",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Receive
|
|
|
|
|
+ res = bab_get(babcgpu, babinfo);
|
|
|
|
|
+ if (!res) {
|
|
|
|
|
+ applog(LOG_DEBUG, "%s%i: didn't get work reply ...",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ applog(LOG_DEBUG, "%s%i: Did get work reply ...",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id);
|
|
|
|
|
+
|
|
|
|
|
+ spi = mis = miso = 0;
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < babinfo->chips; i++) {
|
|
|
|
|
+ match = 0;
|
|
|
|
|
+ newbusy = busy = babinfo->chip_busy[i];
|
|
|
|
|
+
|
|
|
|
|
+ if (!babinfo->chip_conf[i])
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ for (j = 1; j < BAB_REPLY_NONCES; j++) {
|
|
|
|
|
+ if (babinfo->chip_results[i].nonce[(busy+j) % BAB_REPLY_NONCES] !=
|
|
|
|
|
+ babinfo->chip_prev[i].nonce[(busy+j) % BAB_REPLY_NONCES])
|
|
|
|
|
+ newbusy = (busy+j) % BAB_REPLY_NONCES;
|
|
|
|
|
+ else
|
|
|
|
|
+ match++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!match) {
|
|
|
|
|
+ if (!miso) {
|
|
|
|
|
+ mis++;
|
|
|
|
|
+// ignore for now ... babinfo->chip_miso[i]++;
|
|
|
|
|
+ }
|
|
|
|
|
+ miso = 1;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ miso = 0;
|
|
|
|
|
+ if (babinfo->chip_results[i].jobsel != 0xffffffff &&
|
|
|
|
|
+ babinfo->chip_results[i].jobsel != 0x00000000) {
|
|
|
|
|
+ spi++;
|
|
|
|
|
+ babinfo->chip_spie[i]++;
|
|
|
|
|
+ applog(LOG_DEBUG, "%s%i: SPI ERROR on chip %d (0x%08x)",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id,
|
|
|
|
|
+ i, babinfo->chip_results[i].jobsel);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+// Not used yet
|
|
|
|
|
+// if (babinfo->chip_results[i].jobsel != babinfo->chip_prev[i].jobsel) {
|
|
|
|
|
+
|
|
|
|
|
+ got_a_nonce = false;
|
|
|
|
|
+ for (; newbusy != busy; busy = (busy + 1) % BAB_REPLY_NONCES) {
|
|
|
|
|
+ if (babinfo->chip_results[i].nonce[busy] == 0xffffffff ||
|
|
|
|
|
+ babinfo->chip_results[i].nonce[busy] == 0x00000000) {
|
|
|
|
|
+ babinfo->chip_results[i].nonce[busy] = babinfo->chip_prev[i].nonce[busy];
|
|
|
|
|
+ spi = 1;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ store_nonce(babcgpu, i,
|
|
|
|
|
+ babinfo->chip_results[i].nonce[busy],
|
|
|
|
|
+ babinfo->nonce_before[i]);
|
|
|
|
|
+
|
|
|
|
|
+ got_a_nonce = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * We only care about this after the first reply we find a nonce
|
|
|
|
|
+ * After that, the value has no more effect
|
|
|
|
|
+ */
|
|
|
|
|
+ if (got_a_nonce)
|
|
|
|
|
+ babinfo->nonce_before[i] = true;
|
|
|
|
|
+
|
|
|
|
|
+ mis += miso;
|
|
|
|
|
+ babinfo->chip_miso[i] += miso;
|
|
|
|
|
+ babinfo->chip_busy[i] = busy;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ memcpy((void *)(&(babinfo->chip_prev[0])),
|
|
|
|
|
+ (void *)(&(babinfo->chip_results[0])),
|
|
|
|
|
+ sizeof(babinfo->chip_prev));
|
|
|
|
|
+
|
|
|
|
|
+ applog(LOG_DEBUG, "Work: items:%d spi:%d miso:%d",
|
|
|
|
|
+ work_items, spi, mis);
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static bool bab_thread_prepare(struct thr_info *thr)
|
|
|
|
|
+{
|
|
|
|
|
+ struct cgpu_info *babcgpu = thr->cgpu;
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+
|
|
|
|
|
+ if (thr_info_create(&(babinfo->spi_thr), NULL, bab_spi, (void *)babcgpu)) {
|
|
|
|
|
+ applog(LOG_ERR, "%s%i: SPI thread create failed",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ pthread_detach(babinfo->spi_thr.pth);
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * We require a seperate results checking thread since there is a lot
|
|
|
|
|
+ * of work done checking the results multiple times - thus we don't
|
|
|
|
|
+ * want that delay affecting sending/receiving work to/from the device
|
|
|
|
|
+ */
|
|
|
|
|
+ if (thr_info_create(&(babinfo->res_thr), NULL, bab_res, (void *)babcgpu)) {
|
|
|
|
|
+ applog(LOG_ERR, "%s%i: Results thread create failed",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ pthread_detach(babinfo->res_thr.pth);
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void bab_shutdown(struct thr_info *thr)
|
|
|
|
|
+{
|
|
|
|
|
+ struct cgpu_info *babcgpu = thr->cgpu;
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ int i;
|
|
|
|
|
+
|
|
|
|
|
+ applog(LOG_DEBUG, "%s%i: shutting down",
|
|
|
|
|
+ babcgpu->drv->name, babcgpu->device_id);
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < babinfo->chips; i++)
|
|
|
|
|
+// TODO: bab_shutdown(babcgpu, babinfo, i);
|
|
|
|
|
+ ;
|
|
|
|
|
+
|
|
|
|
|
+ babcgpu->shutdown = true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static bool bab_queue_full(struct cgpu_info *babcgpu)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ struct work *work;
|
|
|
|
|
+ bool ret;
|
|
|
|
|
+
|
|
|
|
|
+ if (babinfo->work_count >= babinfo->chips)
|
|
|
|
|
+ ret = true;
|
|
|
|
|
+ else {
|
|
|
|
|
+ work = get_queued(babcgpu);
|
|
|
|
|
+ if (work)
|
|
|
|
|
+ store_work(babcgpu, work);
|
|
|
|
|
+ else
|
|
|
|
|
+ // Avoid a hard loop when we can't get work fast enough
|
|
|
|
|
+ cgsleep_ms(10);
|
|
|
|
|
+
|
|
|
|
|
+ ret = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return ret;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * 1.0s per nonce = 4.2GH/s
|
|
|
|
|
+ * So anything around 4GH/s or less per chip should be fine
|
|
|
|
|
+ */
|
|
|
|
|
+#define BAB_STD_WORK_uS 1000000
|
|
|
|
|
+
|
|
|
|
|
+#define BAB_STD_DELAY_uS 30000
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * TODO: allow this to run through more than once - the second+
|
|
|
|
|
+ * time not sending any new work unless a flush occurs since:
|
|
|
|
|
+ * at the moment we have BAB_STD_WORK_uS latency added to earliest replies
|
|
|
|
|
+ */
|
|
|
|
|
+static int64_t bab_scanwork(__maybe_unused struct thr_info *thr)
|
|
|
|
|
+{
|
|
|
|
|
+ struct cgpu_info *babcgpu = thr->cgpu;
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ int64_t hashcount = 0;
|
|
|
|
|
+ struct timeval now;
|
|
|
|
|
+ double delay;
|
|
|
|
|
+
|
|
|
|
|
+ bab_do_work(babcgpu);
|
|
|
|
|
+
|
|
|
|
|
+ // Sleep now so we get the work "bab_queue_full()" just before we use it
|
|
|
|
|
+ while (80085) {
|
|
|
|
|
+ cgtime(&now);
|
|
|
|
|
+ mutex_lock(&(babinfo->did_lock));
|
|
|
|
|
+ delay = us_tdiff(&now, &(babinfo->last_did));
|
|
|
|
|
+ mutex_unlock(&(babinfo->did_lock));
|
|
|
|
|
+ if (delay < (BAB_STD_WORK_uS - BAB_STD_DELAY_uS))
|
|
|
|
|
+ cgsleep_us(BAB_STD_DELAY_uS);
|
|
|
|
|
+ else
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (babinfo->new_nonces) {
|
|
|
|
|
+ hashcount += 0xffffffffull * babinfo->new_nonces;
|
|
|
|
|
+ babinfo->new_nonces = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return hashcount;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#define CHIPS_PER_STAT 16
|
|
|
|
|
+
|
|
|
|
|
+static struct api_data *bab_api_stats(struct cgpu_info *babcgpu)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bab_info *babinfo = (struct bab_info *)(babcgpu->device_data);
|
|
|
|
|
+ struct api_data *root = NULL;
|
|
|
|
|
+ char data[2048];
|
|
|
|
|
+ char buf[32];
|
|
|
|
|
+ int i, to, j;
|
|
|
|
|
+
|
|
|
|
|
+ if (babinfo->initialised == false)
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+
|
|
|
|
|
+ root = api_add_int(root, "Chips", &(babinfo->chips), true);
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < babinfo->chips; i += CHIPS_PER_STAT) {
|
|
|
|
|
+ to = i + CHIPS_PER_STAT - 1;
|
|
|
|
|
+ if (to >= babinfo->chips)
|
|
|
|
|
+ to = babinfo->chips - 1;
|
|
|
|
|
+
|
|
|
|
|
+ data[0] = '\0';
|
|
|
|
|
+ for (j = i; j <= to; j++) {
|
|
|
|
|
+ snprintf(buf, sizeof(buf),
|
|
|
|
|
+ "%s%"PRIu64,
|
|
|
|
|
+ j == i ? "" : " ",
|
|
|
|
|
+ babinfo->chip_nonces[j]);
|
|
|
|
|
+ strcat(data, buf);
|
|
|
|
|
+ }
|
|
|
|
|
+ snprintf(buf, sizeof(buf), "Nonces %d - %d", i, to);
|
|
|
|
|
+ root = api_add_string(root, buf, data, true);
|
|
|
|
|
+
|
|
|
|
|
+ data[0] = '\0';
|
|
|
|
|
+ for (j = i; j <= to; j++) {
|
|
|
|
|
+ snprintf(buf, sizeof(buf),
|
|
|
|
|
+ "%s%"PRIu64,
|
|
|
|
|
+ j == i ? "" : " ",
|
|
|
|
|
+ babinfo->chip_good[j]);
|
|
|
|
|
+ strcat(data, buf);
|
|
|
|
|
+ }
|
|
|
|
|
+ snprintf(buf, sizeof(buf), "Good %d - %d", i, to);
|
|
|
|
|
+ root = api_add_string(root, buf, data, true);
|
|
|
|
|
+
|
|
|
|
|
+ data[0] = '\0';
|
|
|
|
|
+ for (j = i; j <= to; j++) {
|
|
|
|
|
+ snprintf(buf, sizeof(buf),
|
|
|
|
|
+ "%s%"PRIu64,
|
|
|
|
|
+ j == i ? "" : " ",
|
|
|
|
|
+ babinfo->chip_bad[j]);
|
|
|
|
|
+ strcat(data, buf);
|
|
|
|
|
+ }
|
|
|
|
|
+ snprintf(buf, sizeof(buf), "Bad %d - %d", i, to);
|
|
|
|
|
+ root = api_add_string(root, buf, data, true);
|
|
|
|
|
+
|
|
|
|
|
+ data[0] = '\0';
|
|
|
|
|
+ for (j = i; j <= to; j++) {
|
|
|
|
|
+ snprintf(buf, sizeof(buf),
|
|
|
|
|
+ "%s0x%02x",
|
|
|
|
|
+ j == i ? "" : " ",
|
|
|
|
|
+ (int)(babinfo->chip_conf[j]));
|
|
|
|
|
+ strcat(data, buf);
|
|
|
|
|
+ }
|
|
|
|
|
+ snprintf(buf, sizeof(buf), "Conf %d - %d", i, to);
|
|
|
|
|
+ root = api_add_string(root, buf, data, true);
|
|
|
|
|
+
|
|
|
|
|
+ data[0] = '\0';
|
|
|
|
|
+ for (j = i; j <= to; j++) {
|
|
|
|
|
+ snprintf(buf, sizeof(buf),
|
|
|
|
|
+ "%s0x%02x",
|
|
|
|
|
+ j == i ? "" : " ",
|
|
|
|
|
+ (int)(babinfo->chip_fast[j]));
|
|
|
|
|
+ strcat(data, buf);
|
|
|
|
|
+ }
|
|
|
|
|
+ snprintf(buf, sizeof(buf), "Fast %d - %d", i, to);
|
|
|
|
|
+ root = api_add_string(root, buf, data, true);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < BAB_NONCE_OFFSETS; i++) {
|
|
|
|
|
+ snprintf(buf, sizeof(buf), "Nonce Offset 0x%08x", bab_nonce_offsets[i]);
|
|
|
|
|
+ root = api_add_uint64(root, buf, &(babinfo->nonce_offset_count[i]), true);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ root = api_add_uint64(root, "Tested", &(babinfo->tested_nonces), true);
|
|
|
|
|
+ root = api_add_uint64(root, "Total Tests", &(babinfo->total_tests), true);
|
|
|
|
|
+ root = api_add_uint64(root, "Max Tests", &(babinfo->max_tests_per_nonce), true);
|
|
|
|
|
+ float avg = babinfo->tested_nonces ? (float)(babinfo->total_tests) /
|
|
|
|
|
+ (float)(babinfo->tested_nonces) : 0;
|
|
|
|
|
+// TODO: add a API_AVG which is 3 places - double/float?
|
|
|
|
|
+ root = api_add_volts(root, "Avg Tests", &avg, true);
|
|
|
|
|
+ root = api_add_uint64(root, "Untested", &(babinfo->untested_nonces), true);
|
|
|
|
|
+
|
|
|
|
|
+ root = api_add_uint64(root, "Work Links", &(babinfo->total_links), true);
|
|
|
|
|
+ root = api_add_uint64(root, "Max Links", &(babinfo->max_links), true);
|
|
|
|
|
+ avg = babinfo->tested_nonces ? (float)(babinfo->total_links) /
|
|
|
|
|
+ (float)(babinfo->tested_nonces) : 0;
|
|
|
|
|
+ root = api_add_volts(root, "Avg Links", &avg, true);
|
|
|
|
|
+
|
|
|
|
|
+ root = api_add_uint32(root, "Initial Ignored", &(babinfo->initial_ignored), true);
|
|
|
|
|
+
|
|
|
|
|
+ root = api_add_int(root, "BList Count", &(babinfo->blist_count), true);
|
|
|
|
|
+ root = api_add_int(root, "BFree Count", &(babinfo->bfree_count), true);
|
|
|
|
|
+ root = api_add_int(root, "Work Count", &(babinfo->work_count), true);
|
|
|
|
|
+ root = api_add_int(root, "Chip Count", &(babinfo->chip_count), true);
|
|
|
|
|
+
|
|
|
|
|
+ root = api_add_int(root, "RList Count", &(babinfo->rlist_count), true);
|
|
|
|
|
+ root = api_add_int(root, "RFree Count", &(babinfo->rfree_count), true);
|
|
|
|
|
+ root = api_add_int(root, "Result Count", &(babinfo->res_count), true);
|
|
|
|
|
+
|
|
|
|
|
+ return root;
|
|
|
|
|
+}
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+struct device_drv bab_drv = {
|
|
|
|
|
+ .drv_id = DRIVER_bab,
|
|
|
|
|
+ .dname = "BlackArrowBitFuryGPIO",
|
|
|
|
|
+ .name = "BaB",
|
|
|
|
|
+ .drv_detect = bab_detect,
|
|
|
|
|
+#ifdef LINUX
|
|
|
|
|
+ .get_api_stats = bab_api_stats,
|
|
|
|
|
+//TODO: .get_statline_before = get_bab_statline_before,
|
|
|
|
|
+ .identify_device = bab_identify,
|
|
|
|
|
+ .thread_prepare = bab_thread_prepare,
|
|
|
|
|
+ .hash_work = hash_queued_work,
|
|
|
|
|
+ .scanwork = bab_scanwork,
|
|
|
|
|
+ .queue_full = bab_queue_full,
|
|
|
|
|
+ .flush_work = bab_flush_work,
|
|
|
|
|
+ .thread_shutdown = bab_shutdown
|
|
|
|
|
+#endif
|
|
|
|
|
+};
|