driver-rockminer.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * Copyright 2014 Luke Dashjr
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the Free
  6. * Software Foundation; either version 3 of the License, or (at your option)
  7. * any later version. See COPYING for more details.
  8. */
  9. #include "config.h"
  10. #include <stdbool.h>
  11. #include <stdint.h>
  12. #include <string.h>
  13. #include <unistd.h>
  14. #include "deviceapi.h"
  15. #include "lowl-vcom.h"
  16. #include "miner.h"
  17. #define ROCKMINER_MIN_FREQ_MHZ 200
  18. #define ROCKMINER_DEF_FREQ_MHZ 270
  19. #define ROCKMINER_POLL_US 0
  20. #define ROCKMINER_RETRY_US 5000000
  21. #define ROCKMINER_MAX_CHIPS 64
  22. #define ROCKMINER_WORK_REQ_SIZE 0x40
  23. #define ROCKMINER_REPLY_SIZE 8
  24. enum rockminer_replies {
  25. ROCKMINER_REPLY_NONCE_FOUND = 0,
  26. ROCKMINER_REPLY_TASK_COMPLETE = 1,
  27. ROCKMINER_REPLY_GET_TASK = 2,
  28. };
  29. BFG_REGISTER_DRIVER(rockminer_drv)
  30. struct rockminer_chip_data {
  31. uint8_t next_work_req[ROCKMINER_WORK_REQ_SIZE];
  32. struct work *works[2];
  33. uint8_t last_taskid;
  34. };
  35. static
  36. void rockminer_job_buf_init(uint8_t * const buf, const uint8_t chipid)
  37. {
  38. memset(&buf[0x20], 0, 0x10);
  39. buf[0x30] = 0xaa;
  40. // 0x31 is frequency, filled in elsewhere
  41. buf[0x32] = chipid;
  42. buf[0x33] = 0x55;
  43. }
  44. static
  45. void rockminer_job_buf_set_freq(uint8_t * const buf, const unsigned short freq)
  46. {
  47. buf[0x31] = (freq / 10) - 1;
  48. }
  49. static const uint8_t golden_midstate[] = {
  50. 0x4a, 0x54, 0x8f, 0xe4, 0x71, 0xfa, 0x3a, 0x9a,
  51. 0x13, 0x71, 0x14, 0x45, 0x56, 0xc3, 0xf6, 0x4d,
  52. 0x25, 0x00, 0xb4, 0x82, 0x60, 0x08, 0xfe, 0x4b,
  53. 0xbf, 0x76, 0x98, 0xc9, 0x4e, 0xba, 0x79, 0x46,
  54. };
  55. static const uint8_t golden_datatail[] = {
  56. 0xce, 0x22, 0xa7, 0x2f,
  57. 0x4f, 0x67, 0x26, 0x14, 0x1a, 0x0b, 0x32, 0x87,
  58. };
  59. static const uint8_t golden_result[] = {
  60. 0x00, 0x01, 0x87, 0xa2,
  61. };
  62. int8_t rockminer_bisect_chips(const int fd, uint8_t * const buf)
  63. {
  64. static const int max_concurrent_tests = 4;
  65. int concurrent_tests = max_concurrent_tests;
  66. uint8_t tests[max_concurrent_tests];
  67. uint8_t reply[ROCKMINER_REPLY_SIZE];
  68. uint8_t minvalid = 0, maxvalid = ROCKMINER_MAX_CHIPS - 1;
  69. uint8_t pertest;
  70. char msg[0x10];
  71. ssize_t rsz;
  72. do {
  73. pertest = (maxvalid + 1 - minvalid) / concurrent_tests;
  74. if (!pertest)
  75. pertest = 1;
  76. msg[0] = '\0';
  77. for (int i = 0; i < concurrent_tests; ++i)
  78. {
  79. uint8_t chipid = (minvalid + pertest * (i + 1)) - 1;
  80. if (chipid > maxvalid)
  81. {
  82. concurrent_tests = i;
  83. break;
  84. }
  85. tests[i] = chipid;
  86. buf[0x32] = chipid;
  87. if (write(fd, buf, ROCKMINER_WORK_REQ_SIZE) != ROCKMINER_WORK_REQ_SIZE)
  88. applogr(-1, LOG_DEBUG, "%s(%d): Error sending request for chip %d", __func__, fd, chipid);
  89. tailsprintf(msg, sizeof(msg), "%d ", chipid);
  90. }
  91. msg[strlen(msg)-1] = '\0';
  92. applog(LOG_DEBUG, "%s(%d): Testing chips %s (within range %d-%d)", __func__, fd, msg, minvalid, maxvalid);
  93. while ( (rsz = read(fd, reply, sizeof(reply))) == sizeof(reply))
  94. {
  95. const uint8_t chipid = reply[5] & 0x3f;
  96. if (chipid > minvalid)
  97. {
  98. applog(LOG_DEBUG, "%s(%d): Saw chip %d", __func__, fd, chipid);
  99. minvalid = chipid;
  100. if (minvalid >= tests[concurrent_tests-1])
  101. break;
  102. }
  103. }
  104. for (int i = concurrent_tests; i--; )
  105. {
  106. if (tests[i] > minvalid)
  107. {
  108. applog(LOG_DEBUG, "%s(%d): Didn't see chip %d", __func__, fd, tests[i]);
  109. maxvalid = tests[i] - 1;
  110. }
  111. else
  112. break;
  113. }
  114. } while (minvalid != maxvalid);
  115. return maxvalid + 1;
  116. }
  117. static
  118. bool rockminer_detect_one(const char * const devpath)
  119. {
  120. int fd, chips;
  121. uint8_t buf[ROCKMINER_WORK_REQ_SIZE], reply[ROCKMINER_REPLY_SIZE];
  122. ssize_t rsz;
  123. fd = serial_open(devpath, 0, 1, true);
  124. if (fd < 0)
  125. return_via_applog(err, , LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Failed to open", devpath);
  126. applog(LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Successfully opened", devpath);
  127. rockminer_job_buf_init(buf, 0);
  128. rockminer_job_buf_set_freq(buf, ROCKMINER_MIN_FREQ_MHZ);
  129. memcpy(&buf[ 0], golden_midstate, 0x20);
  130. memcpy(&buf[0x34], golden_datatail, 0xc);
  131. if (write(fd, buf, sizeof(buf)) != sizeof(buf))
  132. return_via_applog(err, , LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Error sending request to ", devpath);
  133. while (true)
  134. {
  135. rsz = read(fd, reply, sizeof(reply));
  136. if (rsz != sizeof(reply))
  137. return_via_applog(err, , LOG_DEBUG, "%s: Short read from %s (%d)", rockminer_drv.dname, devpath, rsz);
  138. if ((!memcmp(reply, golden_result, sizeof(golden_result))) && (reply[4] & 0xf) == ROCKMINER_REPLY_NONCE_FOUND)
  139. break;
  140. }
  141. applog(LOG_DEBUG, "%s: Found chip 0 on %s, probing for total chip count", rockminer_drv.dname, devpath);
  142. chips = rockminer_bisect_chips(fd, buf);
  143. applog(LOG_DEBUG, "%s: Identified %d chips on %s", rockminer_drv.dname, chips, devpath);
  144. if (serial_claim_v(devpath, &rockminer_drv))
  145. goto err;
  146. serial_close(fd);
  147. struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
  148. *cgpu = (struct cgpu_info){
  149. .drv = &rockminer_drv,
  150. .device_path = strdup(devpath),
  151. .deven = DEV_ENABLED,
  152. .procs = chips,
  153. .threads = 1,
  154. };
  155. // NOTE: Xcode's clang has a bug where it cannot find fields inside anonymous unions (more details in fpgautils)
  156. cgpu->device_fd = -1;
  157. return add_cgpu(cgpu);
  158. err:
  159. if (fd >= 0)
  160. serial_close(fd);
  161. return false;
  162. }
  163. static
  164. bool rockminer_lowl_probe(const struct lowlevel_device_info * const info)
  165. {
  166. return vcom_lowl_probe_wrapper(info, rockminer_detect_one);
  167. }
  168. static
  169. bool rockminer_init(struct thr_info * const master_thr)
  170. {
  171. struct cgpu_info * const dev = master_thr->cgpu;
  172. for_each_managed_proc(proc, dev)
  173. {
  174. struct thr_info * const thr = proc->thr[0];
  175. struct rockminer_chip_data * const chip = malloc(sizeof(*chip));
  176. thr->cgpu_data = chip;
  177. *chip = (struct rockminer_chip_data){
  178. .last_taskid = 0,
  179. };
  180. rockminer_job_buf_init(chip->next_work_req, proc->proc_id);
  181. rockminer_job_buf_set_freq(chip->next_work_req, ROCKMINER_DEF_FREQ_MHZ);
  182. }
  183. timer_set_now(&master_thr->tv_poll);
  184. return true;
  185. }
  186. static
  187. void rockminer_dead(struct cgpu_info * const dev)
  188. {
  189. serial_close(dev->device_fd);
  190. dev->device_fd = -1;
  191. for_each_managed_proc(proc, dev)
  192. {
  193. struct thr_info * const thr = proc->thr[0];
  194. thr->queue_full = true;
  195. }
  196. }
  197. static
  198. bool rockminer_queue_append(struct thr_info * const thr, struct work * const work)
  199. {
  200. struct cgpu_info * const proc = thr->cgpu;
  201. struct cgpu_info * const dev = proc->device;
  202. struct rockminer_chip_data * const chip = thr->cgpu_data;
  203. const int fd = dev->device_fd;
  204. thr->queue_full = true;
  205. if (fd < 0)
  206. return false;
  207. memcpy(&chip->next_work_req[ 0], work->midstate, 0x20);
  208. memcpy(&chip->next_work_req[0x34], &work->data[0x40], 0xc);
  209. if (write(fd, chip->next_work_req, sizeof(chip->next_work_req)) != sizeof(chip->next_work_req))
  210. {
  211. rockminer_dead(dev);
  212. applogr(false, LOG_ERR, "%"PRIpreprv": Failed to send work", proc->proc_repr);
  213. }
  214. chip->last_taskid = chip->last_taskid ? 0 : 1;
  215. if (chip->works[chip->last_taskid])
  216. free_work(chip->works[chip->last_taskid]);
  217. chip->works[chip->last_taskid] = work;
  218. return true;
  219. }
  220. static
  221. void rockminer_queue_flush(__maybe_unused struct thr_info * const thr)
  222. {
  223. }
  224. static
  225. void rockminer_poll(struct thr_info * const master_thr)
  226. {
  227. struct cgpu_info * const dev = master_thr->cgpu;
  228. int fd = dev->device_fd;
  229. uint8_t reply[ROCKMINER_REPLY_SIZE];
  230. ssize_t rsz;
  231. if (fd < 0)
  232. {
  233. fd = serial_open(dev->device_path, 0, 1, true);
  234. if (fd < 0)
  235. {
  236. timer_set_delay_from_now(&master_thr->tv_poll, ROCKMINER_RETRY_US);
  237. applogr(, LOG_ERR, "%s: Failed to open %s", dev->dev_repr, dev->device_path);
  238. }
  239. dev->device_fd = fd;
  240. for_each_managed_proc(proc, dev)
  241. {
  242. struct thr_info * const thr = proc->thr[0];
  243. thr->queue_full = false;
  244. }
  245. }
  246. while ( (rsz = read(fd, reply, sizeof(reply))) == sizeof(reply))
  247. {
  248. // const uint8_t status = reply[4] >> 4;
  249. const enum rockminer_replies cmd = reply[4] & 0xf;
  250. // const uint8_t prodid = reply[5] >> 6;
  251. const uint8_t chipid = reply[5] & 0x3f;
  252. const uint8_t taskid = reply[6] & 1;
  253. // const uint8_t temp = reply[7];
  254. struct cgpu_info * const proc = device_proc_by_id(dev, chipid);
  255. if (unlikely(!proc))
  256. {
  257. applog(LOG_ERR, "%s: Chip id %d out of range", dev->dev_repr, chipid);
  258. continue;
  259. }
  260. struct thr_info * const thr = proc->thr[0];
  261. struct rockminer_chip_data * const chip = thr->cgpu_data;
  262. switch (cmd) {
  263. case ROCKMINER_REPLY_NONCE_FOUND:
  264. {
  265. const uint32_t nonce = upk_u32be(reply, 0);
  266. struct work *work;
  267. if (chip->works[taskid] && test_nonce(chip->works[taskid], nonce, false))
  268. {}
  269. else
  270. if (chip->works[taskid ? 0 : 1] && test_nonce(chip->works[taskid ? 0 : 1], nonce, false))
  271. {
  272. applog(LOG_DEBUG, "%"PRIpreprv": We have task ids inverted; fixing", proc->proc_repr);
  273. work = chip->works[0];
  274. chip->works[0] = chip->works[1];
  275. chip->works[1] = work;
  276. chip->last_taskid = chip->last_taskid ? 0 : 1;
  277. }
  278. work = chip->works[taskid];
  279. submit_nonce(thr, work, nonce);
  280. break;
  281. }
  282. case ROCKMINER_REPLY_TASK_COMPLETE:
  283. hashes_done2(thr, 0x100000000, NULL);
  284. break;
  285. case ROCKMINER_REPLY_GET_TASK:
  286. thr->queue_full = false;
  287. break;
  288. }
  289. }
  290. if (rsz < 0)
  291. rockminer_dead(dev);
  292. timer_set_delay_from_now(&master_thr->tv_poll, ROCKMINER_POLL_US);
  293. }
  294. struct device_drv rockminer_drv = {
  295. .dname = "rockminer",
  296. .name = "RKM",
  297. .lowl_probe = rockminer_lowl_probe,
  298. .thread_init = rockminer_init,
  299. .minerloop = minerloop_queue,
  300. .queue_append = rockminer_queue_append,
  301. .queue_flush = rockminer_queue_flush,
  302. .poll = rockminer_poll,
  303. };