driver-avalon.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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(uint8_t *s, size_t l)
  36. {
  37. size_t i, j;
  38. uint8_t 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: modify from lancelot to avalon */
  46. static inline void avalon_create_task(uint8_t *t, struct work *work)
  47. {
  48. memset(t, 0, 64);
  49. memcpy(t, work->midstate, 32);
  50. memcpy(t + 52, work->data + 64, 12);
  51. rev(t, 32);
  52. rev(t + 52, 12);
  53. }
  54. /* TODO:receive data from avalon */
  55. static void *avalon_gets(void *userdata)
  56. {
  57. ssize_t ret = 0;
  58. int rc = 0;
  59. int read_amount = AVALON_READ_SIZE;
  60. uint8_t buf[AVALON_READ_SIZE];
  61. struct thr_info *mythr = userdata;
  62. const int thr_id = mythr->id;
  63. struct cgpu_info *avalon = mythr->cgpu;
  64. struct device_api *api = avalon->api;
  65. int fd = avalon->device_fd;
  66. uint8_t *buf_p = buf;
  67. // Read reply 1 byte at a time to get earliest tv_finish
  68. while (true) {
  69. ret = read(fd, buf_p, 1);
  70. /* Not return should be continue */
  71. if (ret < 0)
  72. continue;
  73. if (ret >= read_amount) {
  74. /* Match the work in avalon_send_buffer
  75. * send signal to miner thread */
  76. buf_p = buf;
  77. if (opt_debug) {
  78. applog(LOG_DEBUG,
  79. "Avalon Read: counte: ", ret);
  80. }
  81. continue;
  82. }
  83. if (ret > 0) {
  84. buf_p += ret;
  85. read_amount -= ret;
  86. continue;
  87. }
  88. /* There is no TIMEOUT in avalon read */
  89. rc++;
  90. if (rc >= 8) {
  91. if (opt_debug) {
  92. applog(LOG_DEBUG,
  93. "Avalon Read: No data in %d seconds", rc);
  94. }
  95. buf_p = buf;
  96. rc = 0;
  97. continue;
  98. }
  99. if (mythr && mythr->work_restart) {
  100. rc = 0;
  101. buf_p = buf;
  102. if (opt_debug) {
  103. applog(LOG_DEBUG,
  104. "Avalon Read: Work restart at %.2f seconds",
  105. (float)(rc)/(float)TIME_FACTOR);
  106. }
  107. continue;
  108. }
  109. /* TODO: maybe we should nanosleep() a little here */
  110. }
  111. out:
  112. if (api->thread_shutdown)
  113. api->thread_shutdown(mythr);
  114. thread_reportin(mythr);
  115. applog(LOG_ERR, "Thread %d failure, exiting", thr_id);
  116. tq_freeze(mythr->q);
  117. return NULL;
  118. }
  119. int avalon_gets2(uint8_t *nonce_bin, int *fd, int n)
  120. {
  121. }
  122. /* TODO:
  123. * 1. there are have to add N ms before two task write */
  124. static int avalon_write(int fd, const void *buf, size_t bufLen)
  125. {
  126. size_t ret;
  127. ret = write(fd, buf, bufLen);
  128. if (unlikely(ret != bufLen))
  129. return 1;
  130. return 0;
  131. }
  132. static void do_avalon_close(struct thr_info *thr)
  133. {
  134. struct cgpu_info *avalon = thr->cgpu;
  135. avalon_close(avalon->device_fd);
  136. avalon->device_fd = -1;
  137. }
  138. /* TODO: send AVALON_RESET to device. it will retrun avalon info */
  139. static bool avalon_detect_one(const char *devpath)
  140. {
  141. int fd;
  142. const char golden_ob[] =
  143. "4679ba4ec99876bf4bfe086082b40025"
  144. "4df6c356451471139a3afa71e48f544a"
  145. "00000000000000000000000000000000"
  146. "0000000087320b1a1426674f2fa722ce";
  147. const char golden_nonce[] = "000187a2";
  148. uint8_t ob_bin[64], nonce_bin[AVALON_READ_SIZE];
  149. char *nonce_hex = "000187a2";
  150. applog(LOG_DEBUG, "Avalon Detect: Attempting to open %s", devpath);
  151. fd = avalon_open2(devpath, AVALON_IO_SPEED, true);
  152. if (unlikely(fd == -1)) {
  153. applog(LOG_ERR, "Avalon Detect: Failed to open %s", devpath);
  154. return false;
  155. }
  156. hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
  157. avalon_write(fd, ob_bin, sizeof(ob_bin));
  158. memset(nonce_bin, 0, sizeof(nonce_bin));
  159. avalon_gets2(nonce_bin, fd, NULL);
  160. avalon_close(fd);
  161. if (strncmp(nonce_hex, golden_nonce, 8)) {
  162. applog(LOG_ERR,
  163. "Avalon Detect: "
  164. "Test failed at %s: get %s, should: %s",
  165. devpath, nonce_hex, golden_nonce);
  166. free(nonce_hex);
  167. /* return false; FIXME: for testing. already return true */
  168. }
  169. applog(LOG_DEBUG,
  170. "Avalon Detect: "
  171. "Test succeeded at %s: got %s",
  172. devpath, nonce_hex);
  173. /* We have a real Avalon! */
  174. struct cgpu_info *avalon;
  175. avalon = calloc(1, sizeof(struct cgpu_info));
  176. avalon->api = &avalon_api;
  177. avalon->device_path = strdup(devpath);
  178. avalon->device_fd = -1;
  179. avalon->threads = AVALON_MINER_THREADS; /* The miner_thread */
  180. mutex_init(&avalon->device_mutex);
  181. add_cgpu(avalon);
  182. applog(LOG_INFO, "Found Avalon at %s, mark as %d",
  183. devpath, avalon->device_id);
  184. return true;
  185. }
  186. static void avalon_detect()
  187. {
  188. serial_detect(&avalon_api, avalon_detect_one);
  189. }
  190. static bool avalon_prepare(struct thr_info *thr)
  191. {
  192. struct cgpu_info *avalon = thr->cgpu;
  193. struct timeval now;
  194. avalon->device_fd = -1;
  195. int fd = avalon_open(avalon->device_path, AVALON_IO_SPEED);
  196. if (unlikely(-1 == fd)) {
  197. applog(LOG_ERR, "Failed to open Avalon on %s",
  198. avalon->device_path);
  199. return false;
  200. }
  201. avalon->device_fd = fd;
  202. applog(LOG_INFO, "Opened Avalon on %s", avalon->device_path);
  203. gettimeofday(&now, NULL);
  204. get_datestamp(avalon->init, &now);
  205. return true;
  206. }
  207. /* TODO:
  208. * 1. write work to device
  209. * 2. while CTS HIGH, read data
  210. * 3. match to work
  211. * 4. submit nonce */
  212. static int64_t avalon_scanhash(struct thr_info *thr, struct work *work,
  213. __maybe_unused int64_t max_nonce)
  214. {
  215. struct cgpu_info *avalon;
  216. int fd;
  217. int ret;
  218. uint8_t ob_bin[64], nonce_bin[AVALON_READ_SIZE];
  219. char *ob_hex;
  220. uint32_t nonce;
  221. int64_t hash_count;
  222. int curr_hw_errors, i;
  223. bool was_hw_error;
  224. int count;
  225. int read_count;
  226. uint32_t values;
  227. avalon = thr->cgpu;
  228. if (avalon->device_fd == -1)
  229. return -1;
  230. fd = avalon->device_fd;
  231. avalon_create_task(ob_bin, work);
  232. #ifndef WIN32
  233. tcflush(fd, TCOFLUSH);
  234. #endif
  235. /* TODO: write 20 task */
  236. ret = avalon_write(fd, ob_bin, sizeof(ob_bin));
  237. if (ret) {
  238. do_avalon_close(thr);
  239. applog(LOG_ERR, "AVA%i: Comms error", avalon->device_id);
  240. dev_error(avalon, REASON_DEV_COMMS_ERROR);
  241. return 0; /* This should never happen */
  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(thr);
  246. if (ret == AVA_GETS_ERROR) {
  247. do_avalon_close(thr);
  248. applog(LOG_ERR, "ICA%i: Comms error", avalon->device_id);
  249. dev_error(avalon, REASON_DEV_COMMS_ERROR);
  250. return 0;
  251. }
  252. work->blk.nonce = 0xffffffff;
  253. memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
  254. #if !defined (__BIG_ENDIAN__) && !defined(MIPSEB)
  255. nonce = swab32(nonce);
  256. #endif
  257. curr_hw_errors = avalon->hw_errors;
  258. submit_nonce(thr, work, nonce);
  259. was_hw_error = (curr_hw_errors > avalon->hw_errors);
  260. // Force a USB close/reopen on any hw error
  261. if (was_hw_error)
  262. do_avalon_close(thr);
  263. if (opt_debug) {
  264. ob_hex = bin2hex(ob_bin, sizeof(ob_bin));
  265. applog(LOG_DEBUG, "Avalon %d sent: %s",
  266. avalon->device_id, ob_hex);
  267. free(ob_hex);
  268. }
  269. return hash_count;
  270. }
  271. /* TODO: close the avalon_read_thread */
  272. static void avalon_shutdown(struct thr_info *thr)
  273. {
  274. do_avalon_close(thr);
  275. }
  276. struct device_api avalon_api = {
  277. .dname = "avalon",
  278. .name = "AVA",
  279. .api_detect = avalon_detect,
  280. .thread_prepare = avalon_prepare,
  281. .scanhash = avalon_scanhash,
  282. .thread_shutdown = avalon_shutdown,
  283. };