driver-avalon.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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 /* Should be 48 */
  34. #define TIME_FACTOR 10
  35. // Ensure the sizes are correct for the Serial read
  36. #define ASSERT1(condition) __maybe_unused static char sizeof_uint32_t_must_be_4[(condition)?1:-1]
  37. ASSERT1(sizeof(uint32_t) == 4);
  38. #define AVALON_READ_FAULT_DECISECONDS 1
  39. // One for each possible device
  40. struct device_api avalon_api;
  41. static void rev(unsigned char *s, size_t l)
  42. {
  43. size_t i, j;
  44. unsigned char t;
  45. for (i = 0, j = l - 1; i < j; i++, j--) {
  46. t = s[i];
  47. s[i] = s[j];
  48. s[j] = t;
  49. }
  50. }
  51. #define avalon_open2(devpath, baud, purge) serial_open(devpath, baud, AVALON_READ_FAULT_DECISECONDS, purge)
  52. #define avalon_open(devpath, baud) avalon_open2(devpath, baud, false)
  53. #define AVA_GETS_ERROR -1
  54. #define AVA_GETS_OK 0
  55. #define AVA_GETS_RESTART 1
  56. #define AVA_GETS_TIMEOUT 2
  57. /* TODO: this should be a avalon_read_thread
  58. * 1. receive data from avalon
  59. * 2. match the data to avalon_send_buffer
  60. * 3. send AVALON_FOUND_NONCE signal to work-thread_id
  61. */
  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. /* Not return should be continue */
  71. if (ret < 0)
  72. return AVA_GETS_ERROR;
  73. /* Match the work in avalon_send_buffer
  74. * send signal to miner thread */
  75. if (ret >= read_amount)
  76. return AVA_GETS_OK;
  77. if (ret > 0) {
  78. buf += ret;
  79. read_amount -= ret;
  80. continue;
  81. }
  82. /* There is no TIMEOUT in avalon read */
  83. rc++;
  84. if (rc >= 8) {
  85. if (opt_debug) {
  86. applog(LOG_DEBUG,
  87. "Avalon Read: No data in %.2f seconds",
  88. (float)rc/(float)TIME_FACTOR);
  89. }
  90. return AVA_GETS_TIMEOUT;
  91. }
  92. /* TODO: not sure about this */
  93. if (thr && thr->work_restart) {
  94. if (opt_debug) {
  95. applog(LOG_DEBUG,
  96. "Avalon Read: Work restart at %.2f seconds",
  97. (float)(rc)/(float)TIME_FACTOR);
  98. }
  99. return AVA_GETS_RESTART;
  100. }
  101. }
  102. }
  103. /* TODO: add mutex on write
  104. * 1. add the last_write time
  105. * 2. there are have to N ms befoew two task write */
  106. static int avalon_write(int fd, const void *buf, size_t bufLen)
  107. {
  108. size_t ret;
  109. ret = write(fd, buf, bufLen);
  110. if (unlikely(ret != bufLen))
  111. return 1;
  112. return 0;
  113. }
  114. #define avalon_close(fd) close(fd)
  115. static void do_avalon_close(struct thr_info *thr)
  116. {
  117. struct cgpu_info *avalon = thr->cgpu;
  118. avalon_close(avalon->device_fd);
  119. avalon->device_fd = -1;
  120. }
  121. /* TODO: send AVALON_RESET to device. it will retrun avalon info */
  122. static bool avalon_detect_one(const char *devpath)
  123. {
  124. int fd;
  125. const char golden_ob[] =
  126. "4679ba4ec99876bf4bfe086082b40025"
  127. "4df6c356451471139a3afa71e48f544a"
  128. "00000000000000000000000000000000"
  129. "0000000087320b1a1426674f2fa722ce";
  130. const char golden_nonce[] = "000187a2";
  131. unsigned char ob_bin[64], nonce_bin[AVALON_READ_SIZE];
  132. char *nonce_hex;
  133. applog(LOG_DEBUG, "Avalon Detect: Attempting to open %s", devpath);
  134. fd = avalon_open2(devpath, AVALON_IO_SPEED, true);
  135. if (unlikely(fd == -1)) {
  136. applog(LOG_ERR, "Avalon Detect: Failed to open %s", devpath);
  137. return false;
  138. }
  139. hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
  140. avalon_write(fd, ob_bin, sizeof(ob_bin));
  141. memset(nonce_bin, 0, sizeof(nonce_bin));
  142. avalon_gets(nonce_bin, fd, NULL);
  143. avalon_close(fd);
  144. nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin));
  145. if (strncmp(nonce_hex, golden_nonce, 8)) {
  146. applog(LOG_ERR,
  147. "Avalon Detect: "
  148. "Test failed at %s: get %s, should: %s",
  149. devpath, nonce_hex, golden_nonce);
  150. free(nonce_hex);
  151. return false;
  152. }
  153. applog(LOG_DEBUG,
  154. "Avalon Detect: "
  155. "Test succeeded at %s: got %s",
  156. devpath, nonce_hex);
  157. free(nonce_hex);
  158. /* We have a real Avalon! */
  159. struct cgpu_info *avalon;
  160. avalon = calloc(1, sizeof(struct cgpu_info));
  161. avalon->api = &avalon_api;
  162. avalon->device_path = strdup(devpath);
  163. avalon->device_fd = -1;
  164. avalon->threads = 1; /* The miner_thread */
  165. add_cgpu(avalon);
  166. applog(LOG_INFO, "Found Avalon at %s, mark as %d",
  167. devpath, avalon->device_id);
  168. return true;
  169. }
  170. static void avalon_detect()
  171. {
  172. serial_detect(&avalon_api, avalon_detect_one);
  173. }
  174. /* TODO:
  175. * 1. check if the avalon_read_thread started
  176. * 2. start the avalon_read_thread */
  177. static bool avalon_prepare(struct thr_info *thr)
  178. {
  179. struct cgpu_info *avalon = thr->cgpu;
  180. struct timeval now;
  181. avalon->device_fd = -1;
  182. int fd = avalon_open(avalon->device_path, AVALON_IO_SPEED);
  183. if (unlikely(-1 == fd)) {
  184. applog(LOG_ERR, "Failed to open Avalon on %s",
  185. avalon->device_path);
  186. return false;
  187. }
  188. avalon->device_fd = fd;
  189. applog(LOG_INFO, "Opened Avalon on %s", avalon->device_path);
  190. gettimeofday(&now, NULL);
  191. get_datestamp(avalon->init, &now);
  192. return true;
  193. }
  194. /* TODO:
  195. * 1. write work to device (mutex on write)
  196. * add work to avalon_send_buffer (mutex on add)
  197. * 2. wait signal from avalon_read_thread in N seconds
  198. * 3. N seconds reach, retrun 0xffffffff
  199. * 4. receive AVALON_FOUND_NONCE signal
  200. * 5. remove work from avalon_send_buff
  201. * 6. submit_nonce */
  202. static int64_t avalon_scanhash(struct thr_info *thr, struct work *work,
  203. __maybe_unused int64_t max_nonce)
  204. {
  205. struct cgpu_info *avalon;
  206. int fd;
  207. int ret;
  208. unsigned char ob_bin[64], nonce_bin[AVALON_READ_SIZE];
  209. char *ob_hex;
  210. uint32_t nonce;
  211. int curr_hw_errors;
  212. bool was_hw_error;
  213. avalon = thr->cgpu;
  214. if (avalon->device_fd == -1)
  215. if (!avalon_prepare(thr)) {
  216. applog(LOG_ERR, "AVA%i: Comms error", avalon->device_id);
  217. dev_error(avalon, REASON_DEV_COMMS_ERROR);
  218. // fail the device if the reopen attempt fails
  219. return -1;
  220. }
  221. fd = avalon->device_fd;
  222. memset(ob_bin, 0, sizeof(ob_bin));
  223. memcpy(ob_bin, work->midstate, 32);
  224. memcpy(ob_bin + 52, work->data + 64, 12);
  225. rev(ob_bin, 32);
  226. rev(ob_bin + 52, 12);
  227. #ifndef WIN32
  228. tcflush(fd, TCOFLUSH);
  229. #endif
  230. ret = avalon_write(fd, ob_bin, sizeof(ob_bin));
  231. if (ret) {
  232. do_avalon_close(thr);
  233. applog(LOG_ERR, "AVA%i: Comms error", avalon->device_id);
  234. dev_error(avalon, REASON_DEV_COMMS_ERROR);
  235. return 0; /* This should never happen */
  236. }
  237. if (opt_debug) {
  238. ob_hex = bin2hex(ob_bin, sizeof(ob_bin));
  239. applog(LOG_DEBUG, "Avalon %d sent: %s",
  240. avalon->device_id, ob_hex);
  241. free(ob_hex);
  242. }
  243. /* Avalon will return 4 bytes (AVALON_READ_SIZE) nonces or nothing */
  244. memset(nonce_bin, 0, sizeof(nonce_bin));
  245. ret = avalon_gets(nonce_bin, fd, thr);
  246. if (ret == AVA_GETS_ERROR) {
  247. do_avalon_close(thr);
  248. applog(LOG_ERR, "AVA%i: Comms error", avalon->device_id);
  249. dev_error(avalon, REASON_DEV_COMMS_ERROR);
  250. return 0;
  251. }
  252. work->blk.nonce = 0xffffffff;
  253. // aborted before becoming idle, get new work
  254. if (ret == AVA_GETS_TIMEOUT || ret == AVA_GETS_RESTART) {
  255. return 0xFFFFFFFF;
  256. }
  257. memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
  258. #if !defined (__BIG_ENDIAN__) && !defined(MIPSEB)
  259. nonce = swab32(nonce);
  260. #endif
  261. curr_hw_errors = avalon->hw_errors;
  262. submit_nonce(thr, work, nonce);
  263. was_hw_error = (curr_hw_errors > avalon->hw_errors);
  264. // Force a USB close/reopen on any hw error
  265. if (was_hw_error)
  266. do_avalon_close(thr);
  267. // ignore possible end condition values ... and hw errors
  268. return 0xffffffff;
  269. }
  270. /* TODO: close the avalon_read_thread */
  271. static void avalon_shutdown(struct thr_info *thr)
  272. {
  273. do_avalon_close(thr);
  274. }
  275. struct device_api avalon_api = {
  276. .dname = "avalon",
  277. .name = "AVA",
  278. .api_detect = avalon_detect,
  279. .thread_prepare = avalon_prepare,
  280. .scanhash = avalon_scanhash,
  281. .thread_shutdown = avalon_shutdown,
  282. };