driver-rockminer.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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_MAX_CHIPS 64
  19. #define ROCKMINER_WORK_REQ_SIZE 0x40
  20. #define ROCKMINER_REPLY_SIZE 8
  21. enum rockminer_replies {
  22. ROCKMINER_REPLY_NONCE_FOUND = 0,
  23. };
  24. BFG_REGISTER_DRIVER(rockminer_drv)
  25. struct rockminer_chip_data {
  26. uint8_t next_work_req[ROCKMINER_WORK_REQ_SIZE];
  27. };
  28. static
  29. void rockminer_job_buf_init(uint8_t * const buf, const uint8_t chipid)
  30. {
  31. memset(&buf[0x20], 0, 0x10);
  32. buf[0x30] = 0xaa;
  33. // 0x31 is frequency, filled in elsewhere
  34. buf[0x32] = chipid;
  35. buf[0x33] = 0x55;
  36. }
  37. static
  38. void rockminer_job_buf_set_freq(uint8_t * const buf, const unsigned short freq)
  39. {
  40. buf[0x31] = (freq / 10) - 1;
  41. }
  42. static const uint8_t golden_midstate[] = {
  43. 0x4a, 0x54, 0x8f, 0xe4, 0x71, 0xfa, 0x3a, 0x9a,
  44. 0x13, 0x71, 0x14, 0x45, 0x56, 0xc3, 0xf6, 0x4d,
  45. 0x25, 0x00, 0xb4, 0x82, 0x60, 0x08, 0xfe, 0x4b,
  46. 0xbf, 0x76, 0x98, 0xc9, 0x4e, 0xba, 0x79, 0x46,
  47. };
  48. static const uint8_t golden_datatail[] = {
  49. 0xce, 0x22, 0xa7, 0x2f,
  50. 0x4f, 0x67, 0x26, 0x14, 0x1a, 0x0b, 0x32, 0x87,
  51. };
  52. static const uint8_t golden_result[] = {
  53. 0x00, 0x01, 0x87, 0xa2,
  54. };
  55. int8_t rockminer_bisect_chips(const int fd, uint8_t * const buf)
  56. {
  57. static const int max_concurrent_tests = 4;
  58. int concurrent_tests = max_concurrent_tests;
  59. uint8_t tests[max_concurrent_tests];
  60. uint8_t reply[ROCKMINER_REPLY_SIZE];
  61. uint8_t minvalid = 0, maxvalid = ROCKMINER_MAX_CHIPS - 1;
  62. uint8_t pertest;
  63. char msg[0x10];
  64. ssize_t rsz;
  65. do {
  66. pertest = (maxvalid + 1 - minvalid) / concurrent_tests;
  67. if (!pertest)
  68. pertest = 1;
  69. msg[0] = '\0';
  70. for (int i = 0; i < concurrent_tests; ++i)
  71. {
  72. uint8_t chipid = (minvalid + pertest * (i + 1)) - 1;
  73. if (chipid > maxvalid)
  74. {
  75. concurrent_tests = i;
  76. break;
  77. }
  78. tests[i] = chipid;
  79. buf[0x32] = chipid;
  80. if (write(fd, buf, ROCKMINER_WORK_REQ_SIZE) != ROCKMINER_WORK_REQ_SIZE)
  81. applogr(-1, LOG_DEBUG, "%s(%d): Error sending request for chip %d", __func__, fd, chipid);
  82. tailsprintf(msg, sizeof(msg), "%d ", chipid);
  83. }
  84. msg[strlen(msg)-1] = '\0';
  85. applog(LOG_DEBUG, "%s(%d): Testing chips %s (within range %d-%d)", __func__, fd, msg, minvalid, maxvalid);
  86. while ( (rsz = read(fd, reply, sizeof(reply))) == sizeof(reply))
  87. {
  88. const uint8_t chipid = reply[5] & 0x3f;
  89. if (chipid > minvalid)
  90. {
  91. applog(LOG_DEBUG, "%s(%d): Saw chip %d", __func__, fd, chipid);
  92. minvalid = chipid;
  93. if (minvalid >= tests[concurrent_tests-1])
  94. break;
  95. }
  96. }
  97. for (int i = concurrent_tests; i--; )
  98. {
  99. if (tests[i] > minvalid)
  100. {
  101. applog(LOG_DEBUG, "%s(%d): Didn't see chip %d", __func__, fd, tests[i]);
  102. maxvalid = tests[i] - 1;
  103. }
  104. else
  105. break;
  106. }
  107. } while (minvalid != maxvalid);
  108. return maxvalid + 1;
  109. }
  110. static
  111. bool rockminer_detect_one(const char * const devpath)
  112. {
  113. int fd, chips;
  114. uint8_t buf[ROCKMINER_WORK_REQ_SIZE], reply[ROCKMINER_REPLY_SIZE];
  115. ssize_t rsz;
  116. fd = serial_open(devpath, 0, 1, true);
  117. if (fd < 0)
  118. return_via_applog(err, , LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Failed to open", devpath);
  119. applog(LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Successfully opened", devpath);
  120. rockminer_job_buf_init(buf, 0);
  121. rockminer_job_buf_set_freq(buf, ROCKMINER_MIN_FREQ_MHZ);
  122. memcpy(&buf[ 0], golden_midstate, 0x20);
  123. memcpy(&buf[0x34], golden_datatail, 0xc);
  124. if (write(fd, buf, sizeof(buf)) != sizeof(buf))
  125. return_via_applog(err, , LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Error sending request to ", devpath);
  126. while (true)
  127. {
  128. rsz = read(fd, reply, sizeof(reply));
  129. if (rsz != sizeof(reply))
  130. return_via_applog(err, , LOG_DEBUG, "%s: Short read from %s (%d)", rockminer_drv.dname, devpath, rsz);
  131. if ((!memcmp(reply, golden_result, sizeof(golden_result))) && (reply[4] & 0xf) == ROCKMINER_REPLY_NONCE_FOUND)
  132. break;
  133. }
  134. applog(LOG_DEBUG, "%s: Found chip 0 on %s, probing for total chip count", rockminer_drv.dname, devpath);
  135. chips = rockminer_bisect_chips(fd, buf);
  136. applog(LOG_DEBUG, "%s: Identified %d chips on %s", rockminer_drv.dname, chips, devpath);
  137. if (serial_claim_v(devpath, &rockminer_drv))
  138. goto err;
  139. serial_close(fd);
  140. struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
  141. *cgpu = (struct cgpu_info){
  142. .drv = &rockminer_drv,
  143. .device_path = strdup(devpath),
  144. .deven = DEV_ENABLED,
  145. .procs = chips,
  146. .threads = 1,
  147. };
  148. // NOTE: Xcode's clang has a bug where it cannot find fields inside anonymous unions (more details in fpgautils)
  149. cgpu->device_fd = -1;
  150. return add_cgpu(cgpu);
  151. err:
  152. if (fd >= 0)
  153. serial_close(fd);
  154. return false;
  155. }
  156. static
  157. bool rockminer_lowl_probe(const struct lowlevel_device_info * const info)
  158. {
  159. return vcom_lowl_probe_wrapper(info, rockminer_detect_one);
  160. }
  161. struct device_drv rockminer_drv = {
  162. .dname = "rockminer",
  163. .name = "RKM",
  164. .lowl_probe = rockminer_lowl_probe,
  165. };