driver-avalon.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /*
  2. * This program is free software; you can redistribute it and/or modify it
  3. * under the terms of the GNU General Public License as published by the Free
  4. * Software Foundation; either version 3 of the License, or (at your option)
  5. * any later version. See COPYING for more details.
  6. */
  7. #include "config.h"
  8. #include <limits.h>
  9. #include <pthread.h>
  10. #include <stdio.h>
  11. #include <sys/time.h>
  12. #include <sys/types.h>
  13. #include <dirent.h>
  14. #include <unistd.h>
  15. #ifndef WIN32
  16. #include <termios.h>
  17. #include <sys/stat.h>
  18. #include <fcntl.h>
  19. #ifndef O_CLOEXEC
  20. #define O_CLOEXEC 0
  21. #endif
  22. #else
  23. #include <windows.h>
  24. #include <io.h>
  25. #endif
  26. #include "elist.h"
  27. #include "miner.h"
  28. #include "fpgautils.h"
  29. #include "avalon.h"
  30. // The serial I/O speed - Linux uses a define 'B115200' in bits/termios.h
  31. #define AVALON_IO_SPEED 115200
  32. // The size of a successful nonce read
  33. #define AVALON_READ_SIZE 4
  34. #define TIME_FACTOR 10
  35. // Ensure the sizes are correct for the Serial read
  36. #if (AVALON_READ_SIZE != 4)
  37. #error AVALON_READ_SIZE must be 4
  38. #endif
  39. #define ASSERT1(condition) __maybe_unused static char sizeof_uint32_t_must_be_4[(condition)?1:-1]
  40. ASSERT1(sizeof(uint32_t) == 4);
  41. #define AVALON_READ_TIME(baud) ((double)AVALON_READ_SIZE * (double)8.0 / (double)(baud))
  42. #define AVALON_READ_FAULT_DECISECONDS 1
  43. #define END_CONDITION 0x0000ffff
  44. // One for each possible device
  45. struct device_api avalon_api;
  46. static void rev(unsigned char *s, size_t l)
  47. {
  48. size_t i, j;
  49. unsigned char t;
  50. for (i = 0, j = l - 1; i < j; i++, j--) {
  51. t = s[i];
  52. s[i] = s[j];
  53. s[j] = t;
  54. }
  55. }
  56. #define avalon_open2(devpath, baud, purge) serial_open(devpath, baud, AVALON_READ_FAULT_DECISECONDS, purge)
  57. #define avalon_open(devpath, baud) avalon_open2(devpath, baud, false)
  58. #define AVA_GETS_ERROR -1
  59. #define AVA_GETS_OK 0
  60. #define AVA_GETS_RESTART 1
  61. #define AVA_GETS_TIMEOUT 2
  62. static int avalon_gets(unsigned char *buf, int fd, struct thr_info *thr)
  63. {
  64. ssize_t ret = 0;
  65. int rc = 0;
  66. int read_amount = AVALON_READ_SIZE;
  67. // Read reply 1 byte at a time to get earliest tv_finish
  68. while (true) {
  69. ret = read(fd, buf, 1);
  70. if (ret < 0)
  71. return AVA_GETS_ERROR;
  72. if (ret >= read_amount)
  73. return AVA_GETS_OK;
  74. if (ret > 0) {
  75. buf += ret;
  76. read_amount -= ret;
  77. continue;
  78. }
  79. rc++;
  80. if (rc >= 8) {
  81. if (opt_debug) {
  82. applog(LOG_DEBUG,
  83. "Avalon Read: No data in %.2f seconds",
  84. (float)rc/(float)TIME_FACTOR);
  85. }
  86. return AVA_GETS_TIMEOUT;
  87. }
  88. if (thr && thr->work_restart) {
  89. if (opt_debug) {
  90. applog(LOG_DEBUG,
  91. "Avalon Read: Work restart at %.2f seconds",
  92. (float)(rc)/(float)TIME_FACTOR);
  93. }
  94. return AVA_GETS_RESTART;
  95. }
  96. }
  97. }
  98. static int avalon_write(int fd, const void *buf, size_t bufLen)
  99. {
  100. size_t ret;
  101. ret = write(fd, buf, bufLen);
  102. if (unlikely(ret != bufLen))
  103. return 1;
  104. return 0;
  105. }
  106. #define avalon_close(fd) close(fd)
  107. static void do_avalon_close(struct thr_info *thr)
  108. {
  109. struct cgpu_info *avalon = thr->cgpu;
  110. avalon_close(avalon->device_fd);
  111. avalon->device_fd = -1;
  112. }
  113. static bool avalon_detect_one(const char *devpath)
  114. {
  115. int fd;
  116. // Block 171874 nonce = (0xa2870100) = 0x000187a2
  117. // N.B. golden_ob MUST take less time to calculate
  118. // than the timeout set in avalon_open()
  119. // This one takes ~0.53ms on Rev3 Avalon
  120. const char golden_ob[] =
  121. "4679ba4ec99876bf4bfe086082b40025"
  122. "4df6c356451471139a3afa71e48f544a"
  123. "00000000000000000000000000000000"
  124. "0000000087320b1a1426674f2fa722ce";
  125. const char golden_nonce[] = "000187a2";
  126. unsigned char ob_bin[64], nonce_bin[AVALON_READ_SIZE];
  127. char *nonce_hex;
  128. applog(LOG_DEBUG, "Avalon Detect: Attempting to open %s", devpath);
  129. fd = avalon_open2(devpath, AVALON_IO_SPEED, true);
  130. if (unlikely(fd == -1)) {
  131. applog(LOG_ERR, "Avalon Detect: Failed to open %s", devpath);
  132. return false;
  133. }
  134. hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
  135. avalon_write(fd, ob_bin, sizeof(ob_bin));
  136. memset(nonce_bin, 0, sizeof(nonce_bin));
  137. avalon_gets(nonce_bin, fd, NULL);
  138. avalon_close(fd);
  139. nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin));
  140. if (strncmp(nonce_hex, golden_nonce, 8)) {
  141. applog(LOG_ERR,
  142. "Avalon Detect: "
  143. "Test failed at %s: get %s, should: %s",
  144. devpath, nonce_hex, golden_nonce);
  145. free(nonce_hex);
  146. return false;
  147. }
  148. applog(LOG_DEBUG,
  149. "Avalon Detect: "
  150. "Test succeeded at %s: got %s",
  151. devpath, nonce_hex);
  152. free(nonce_hex);
  153. /* We have a real Avalon! */
  154. struct cgpu_info *avalon;
  155. avalon = calloc(1, sizeof(struct cgpu_info));
  156. avalon->api = &avalon_api;
  157. avalon->device_path = strdup(devpath);
  158. avalon->device_fd = -1;
  159. avalon->threads = 1;
  160. add_cgpu(avalon);
  161. applog(LOG_INFO, "Found Avalon at %s, mark as %d",
  162. devpath, avalon->device_id);
  163. return true;
  164. }
  165. static void avalon_detect()
  166. {
  167. serial_detect(&avalon_api, avalon_detect_one);
  168. }
  169. static bool avalon_prepare(struct thr_info *thr)
  170. {
  171. struct cgpu_info *avalon = thr->cgpu;
  172. struct timeval now;
  173. avalon->device_fd = -1;
  174. int fd = avalon_open(avalon->device_path, AVALON_IO_SPEED);
  175. if (unlikely(-1 == fd)) {
  176. applog(LOG_ERR, "Failed to open Avalon on %s",
  177. avalon->device_path);
  178. return false;
  179. }
  180. avalon->device_fd = fd;
  181. applog(LOG_INFO, "Opened Avalon on %s", avalon->device_path);
  182. gettimeofday(&now, NULL);
  183. get_datestamp(avalon->init, &now);
  184. return true;
  185. }
  186. static int64_t avalon_scanhash(struct thr_info *thr, struct work *work,
  187. __maybe_unused int64_t max_nonce)
  188. {
  189. struct cgpu_info *avalon;
  190. int fd;
  191. int ret;
  192. unsigned char ob_bin[64], nonce_bin[AVALON_READ_SIZE];
  193. char *ob_hex;
  194. uint32_t nonce;
  195. int curr_hw_errors;
  196. bool was_hw_error;
  197. avalon = thr->cgpu;
  198. if (avalon->device_fd == -1)
  199. if (!avalon_prepare(thr)) {
  200. applog(LOG_ERR, "AVA%i: Comms error", avalon->device_id);
  201. dev_error(avalon, REASON_DEV_COMMS_ERROR);
  202. // fail the device if the reopen attempt fails
  203. return -1;
  204. }
  205. fd = avalon->device_fd;
  206. memset(ob_bin, 0, sizeof(ob_bin));
  207. memcpy(ob_bin, work->midstate, 32);
  208. memcpy(ob_bin + 52, work->data + 64, 12);
  209. rev(ob_bin, 32);
  210. rev(ob_bin + 52, 12);
  211. #ifndef WIN32
  212. tcflush(fd, TCOFLUSH);
  213. #endif
  214. ret = avalon_write(fd, ob_bin, sizeof(ob_bin));
  215. if (ret) {
  216. do_avalon_close(thr);
  217. applog(LOG_ERR, "AVA%i: Comms error", avalon->device_id);
  218. dev_error(avalon, REASON_DEV_COMMS_ERROR);
  219. return 0; /* This should never happen */
  220. }
  221. if (opt_debug) {
  222. ob_hex = bin2hex(ob_bin, sizeof(ob_bin));
  223. applog(LOG_DEBUG, "Avalon %d sent: %s",
  224. avalon->device_id, ob_hex);
  225. free(ob_hex);
  226. }
  227. /* Avalon will return 4 bytes (AVALON_READ_SIZE) nonces or nothing */
  228. memset(nonce_bin, 0, sizeof(nonce_bin));
  229. ret = avalon_gets(nonce_bin, fd, thr);
  230. if (ret == AVA_GETS_ERROR) {
  231. do_avalon_close(thr);
  232. applog(LOG_ERR, "AVA%i: Comms error", avalon->device_id);
  233. dev_error(avalon, REASON_DEV_COMMS_ERROR);
  234. return 0;
  235. }
  236. work->blk.nonce = 0xffffffff;
  237. // aborted before becoming idle, get new work
  238. if (ret == AVA_GETS_TIMEOUT || ret == AVA_GETS_RESTART) {
  239. return 0xFFFFFFFF;
  240. }
  241. memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
  242. #if !defined (__BIG_ENDIAN__) && !defined(MIPSEB)
  243. nonce = swab32(nonce);
  244. #endif
  245. curr_hw_errors = avalon->hw_errors;
  246. submit_nonce(thr, work, nonce);
  247. was_hw_error = (curr_hw_errors > avalon->hw_errors);
  248. // Force a USB close/reopen on any hw error
  249. if (was_hw_error)
  250. do_avalon_close(thr);
  251. // ignore possible end condition values ... and hw errors
  252. return 0xffffffff;
  253. }
  254. static void avalon_shutdown(struct thr_info *thr)
  255. {
  256. do_avalon_close(thr);
  257. }
  258. struct device_api avalon_api = {
  259. .dname = "avalon",
  260. .name = "AVA",
  261. .api_detect = avalon_detect,
  262. .thread_prepare = avalon_prepare,
  263. .scanhash = avalon_scanhash,
  264. .thread_shutdown = avalon_shutdown,
  265. };