driver-avalon.c 7.6 KB

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