driver-gridseed.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /*
  2. * Copyright 2014 Luke Dashjr
  3. * Copyright 2014 Nate Woolls
  4. * Copyright 2014 GridSeed Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the Free
  8. * Software Foundation; either version 3 of the License, or (at your option)
  9. * any later version. See COPYING for more details.
  10. */
  11. #include "config.h"
  12. #include <stdbool.h>
  13. #include "deviceapi.h"
  14. #include "lowlevel.h"
  15. #include "lowl-vcom.h"
  16. #include "gc3355.h"
  17. #define GRIDSEED_DEFAULT_FREQUENCY 600
  18. // 60Kh/s at 700MHz in ms
  19. #define GRIDSEED_HASH_SPEED 0.08571428571429
  20. // GridSeed driver currently scans a full nonce range
  21. #define GRIDSEED_MAX_NONCE 0xffffffff
  22. BFG_REGISTER_DRIVER(gridseed_drv)
  23. static const struct bfg_set_device_definition gridseed_set_device_funcs_probe[];
  24. static const struct bfg_set_device_definition gridseed_set_device_funcs_live[];
  25. /*
  26. * helper functions
  27. */
  28. static
  29. struct cgpu_info *gridseed_alloc_device(const char *path, struct device_drv *driver, struct gc3355_info *info)
  30. {
  31. struct cgpu_info *device = calloc(1, sizeof(struct cgpu_info));
  32. if (unlikely(!device))
  33. quit(1, "Failed to malloc cgpu_info");
  34. device->drv = driver;
  35. device->device_path = strdup(path);
  36. device->device_fd = -1;
  37. device->threads = 1;
  38. device->device_data = info;
  39. device->set_device_funcs = gridseed_set_device_funcs_live;
  40. return device;
  41. }
  42. static
  43. struct gc3355_info *gridseed_alloc_info()
  44. {
  45. struct gc3355_info *info = calloc(1, sizeof(struct gc3355_info));
  46. if (unlikely(!info))
  47. quit(1, "Failed to malloc gc3355_info");
  48. info->freq = GRIDSEED_DEFAULT_FREQUENCY;
  49. return info;
  50. }
  51. static
  52. void gridseed_empty_work(int fd)
  53. {
  54. unsigned char buf[GC3355_READ_SIZE];
  55. gc3355_read(fd, (char *)buf, GC3355_READ_SIZE);
  56. }
  57. static
  58. struct thr_info *gridseed_thread_by_chip(const struct cgpu_info * const device, uint32_t const chip)
  59. {
  60. const struct cgpu_info *proc = device_proc_by_id(device, chip);
  61. if (unlikely(!proc))
  62. proc = device;
  63. return proc->thr[0];
  64. }
  65. // return the number of hashes done in elapsed_ms
  66. static
  67. int64_t gridseed_calculate_chip_hashes_ms(const struct cgpu_info * const device, int const elapsed_ms)
  68. {
  69. struct gc3355_info *info = device->device_data;
  70. return GRIDSEED_HASH_SPEED * (double)elapsed_ms * (double)(info->freq);
  71. }
  72. // return the number of hashes done since start_tv
  73. static
  74. int64_t gridseed_calculate_chip_hashes(const struct cgpu_info * const device, struct timeval const start_tv)
  75. {
  76. struct timeval now_tv;
  77. timer_set_now(&now_tv);
  78. int elapsed_ms = ms_tdiff(&now_tv, &start_tv);
  79. return gridseed_calculate_chip_hashes_ms(device, elapsed_ms);
  80. }
  81. // adjust calculated hashes that overflow possible values
  82. static
  83. int64_t gridseed_fix_hashes_done(int64_t const hashes_done)
  84. {
  85. int64_t result = hashes_done;
  86. // not possible to complete more than 0xffffffff nonces
  87. if (unlikely(result > 0xffffffff))
  88. result = 0xffffffff;
  89. return result;
  90. }
  91. // report on hashes done since start_tv
  92. // return the number of hashes done since start_tv
  93. static
  94. int64_t gridseed_hashes_done(struct cgpu_info * const device, struct timeval const start_tv, int64_t previous_hashes)
  95. {
  96. int64_t total_chip_hashes = gridseed_calculate_chip_hashes(device, start_tv);
  97. total_chip_hashes = gridseed_fix_hashes_done(total_chip_hashes);
  98. int64_t previous_chip_hashes = previous_hashes / device->procs;
  99. int64_t recent_chip_hashes = total_chip_hashes - previous_chip_hashes;
  100. int64_t total_hashes = 0;
  101. for_each_managed_proc(proc, device)
  102. {
  103. total_hashes += recent_chip_hashes;
  104. hashes_done2(proc->thr[0], recent_chip_hashes, NULL);
  105. }
  106. return total_hashes;
  107. }
  108. // return duration in seconds for device to scan a nonce range
  109. static
  110. uint32_t gridseed_nonce_range_duration(const struct cgpu_info * const device)
  111. {
  112. struct gc3355_info *info = device->device_data;
  113. // total hashrate of this device:
  114. uint32_t hashes_per_sec = gridseed_calculate_chip_hashes_ms(device, 1000) * info->chips;
  115. // amount of time it takes this device to scan a nonce range:
  116. uint32_t nonce_range_sec = 0xffffffff / hashes_per_sec;
  117. return nonce_range_sec;
  118. }
  119. /*
  120. * device detection
  121. */
  122. static
  123. bool gridseed_detect_custom(const char *path, struct device_drv *driver, struct gc3355_info *info)
  124. {
  125. int fd = gc3355_open(path);
  126. if(fd < 0)
  127. return false;
  128. gridseed_empty_work(fd);
  129. int64_t fw_version = gc3355_get_firmware_version(fd);
  130. if (fw_version == -1)
  131. {
  132. applog(LOG_DEBUG, "%s: Invalid detect response from %s", gridseed_drv.dname, path);
  133. gc3355_close(fd);
  134. return false;
  135. }
  136. if (serial_claim_v(path, driver))
  137. return false;
  138. info->chips = GC3355_ORB_DEFAULT_CHIPS;
  139. if((fw_version & 0xffff) == 0x1402)
  140. info->chips = GC3355_BLADE_DEFAULT_CHIPS;
  141. //pick up any user-defined settings passed in via --set
  142. drv_set_defaults(driver, gridseed_set_device_funcs_probe, info, path, detectone_meta_info.serial, 1);
  143. struct cgpu_info *device = gridseed_alloc_device(path, driver, info);
  144. device->device_fd = fd;
  145. device->procs = info->chips;
  146. if (!add_cgpu(device))
  147. return false;
  148. gc3355_init_miner(device->device_fd, info->freq);
  149. applog(LOG_INFO, "Found %"PRIpreprv" at %s", device->proc_repr, path);
  150. applog(LOG_DEBUG, "%"PRIpreprv": Init: firmware=%"PRId64", chips=%d", device->proc_repr, fw_version, info->chips);
  151. return true;
  152. }
  153. static
  154. bool gridseed_detect_one(const char *path)
  155. {
  156. struct gc3355_info *info = gridseed_alloc_info();
  157. if (!gridseed_detect_custom(path, &gridseed_drv, info))
  158. {
  159. free(info);
  160. return false;
  161. }
  162. return true;
  163. }
  164. static
  165. bool gridseed_lowl_probe(const struct lowlevel_device_info * const info)
  166. {
  167. return vcom_lowl_probe_wrapper(info, gridseed_detect_one);
  168. }
  169. /*
  170. * setup & shutdown
  171. */
  172. static
  173. bool gridseed_thread_prepare(struct thr_info *thr)
  174. {
  175. thr->cgpu_data = calloc(1, sizeof(*thr->cgpu_data));
  176. struct cgpu_info *device = thr->cgpu;
  177. device->min_nonce_diff = 1./0x10000;
  178. return true;
  179. }
  180. static
  181. void gridseed_thread_shutdown(struct thr_info *thr)
  182. {
  183. struct cgpu_info *device = thr->cgpu;
  184. gc3355_close(device->device_fd);
  185. free(thr->cgpu_data);
  186. }
  187. /*
  188. * scanhash mining loop
  189. */
  190. // send work to the device
  191. static
  192. bool gridseed_job_start(const struct thr_info * const thr, struct work * const work)
  193. {
  194. struct cgpu_info *device = thr->cgpu;
  195. unsigned char cmd[156];
  196. gc3355_scrypt_reset(device->device_fd);
  197. gc3355_scrypt_prepare_work(cmd, work);
  198. // See https://github.com/gridseed/gc3355-doc/blob/master/GC3355_DataSheet.pdf
  199. // WAIT: Before start a new transaction, WAIT Cycle must be inserted.
  200. // WAIT Cycle value is programmable register in UART and default wait
  201. // time is UART receive 32 bits time (One DATA Cycle).
  202. // Note: prevents register corruption
  203. cgsleep_ms(100);
  204. // send work
  205. if (sizeof(cmd) != gc3355_write(device->device_fd, cmd, sizeof(cmd)))
  206. {
  207. applog(LOG_ERR, "%s: Failed to send work", device->dev_repr);
  208. dev_error(device, REASON_DEV_COMMS_ERROR);
  209. return false;
  210. }
  211. // after sending work to the device, minerloop_scanhash-based
  212. // drivers must set work->blk.nonce to the last nonce to hash
  213. work->blk.nonce = GRIDSEED_MAX_NONCE;
  214. return true;
  215. }
  216. static
  217. void gridseed_submit_nonce(struct thr_info * const thr, const unsigned char buf[GC3355_READ_SIZE], struct work * const work)
  218. {
  219. struct cgpu_info *device = thr->cgpu;
  220. uint32_t nonce = *(uint32_t *)(buf + 4);
  221. nonce = le32toh(nonce);
  222. uint32_t chip = nonce / (GRIDSEED_MAX_NONCE / device->procs);
  223. struct thr_info *proc_thr = gridseed_thread_by_chip(device, chip);
  224. submit_nonce(proc_thr, work, nonce);
  225. }
  226. // read from device for nonce or command
  227. // unless the device can target specific nonce ranges, the scanhash routine should loop
  228. // until the device has processed the work item, scanning the full nonce range
  229. // return the total number of hashes done
  230. static
  231. int64_t gridseed_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
  232. {
  233. struct cgpu_info *device = thr->cgpu;
  234. struct timeval start_tv, nonce_range_tv, report_hashes_tv;
  235. // amount of time it takes this device to scan a nonce range:
  236. uint32_t nonce_full_range_sec = gridseed_nonce_range_duration(device);
  237. // timer to break out of scanning should we close in on an entire nonce range
  238. // should break out before the range is scanned, so we are doing 99% of the range
  239. uint64_t nonce_near_range_usec = (nonce_full_range_sec * 1000000. * 0.99);
  240. timer_set_delay_from_now(&nonce_range_tv, nonce_near_range_usec);
  241. // timer to calculate hashes every 10s
  242. const uint32_t report_delay = 10 * 1000000;
  243. timer_set_delay_from_now(&report_hashes_tv, report_delay);
  244. // start the job
  245. timer_set_now(&start_tv);
  246. gridseed_job_start(thr, work);
  247. // scan for results
  248. unsigned char buf[GC3355_READ_SIZE];
  249. int read = 0;
  250. int fd = device->device_fd;
  251. int64_t total_hashes = 0;
  252. bool range_nearly_scanned = false;
  253. while (!thr->work_restart // true when new work is available (miner.c)
  254. && ((read = gc3355_read(fd, (char *)buf, GC3355_READ_SIZE)) >= 0) // only check for failure - allow 0 bytes
  255. && !(range_nearly_scanned = timer_passed(&nonce_range_tv, NULL))) // true when we've nearly scanned a nonce range
  256. {
  257. if (timer_passed(&report_hashes_tv, NULL))
  258. {
  259. total_hashes += gridseed_hashes_done(device, start_tv, total_hashes);
  260. timer_set_delay_from_now(&report_hashes_tv, report_delay);
  261. }
  262. if (read == 0)
  263. continue;
  264. if ((buf[0] == 0x55) && (buf[1] == 0x20))
  265. gridseed_submit_nonce(thr, buf, work);
  266. else
  267. applog(LOG_ERR, "%"PRIpreprv": Unrecognized response", device->proc_repr);
  268. }
  269. if (read == -1)
  270. {
  271. applog(LOG_ERR, "%s: Failed to read result", device->dev_repr);
  272. dev_error(device, REASON_DEV_COMMS_ERROR);
  273. }
  274. // calculate remaining hashes for elapsed time
  275. // e.g. work_restart ~report_delay after report_hashes_tv
  276. gridseed_hashes_done(device, start_tv, total_hashes);
  277. return 0;
  278. }
  279. /*
  280. * specify settings / options
  281. */
  282. // support for --set-device
  283. // must be set before probing the device
  284. static
  285. const char *gridseed_set_clock(struct cgpu_info * const device, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
  286. {
  287. struct gc3355_info * const info = device->device_data;
  288. int val = atoi(setting);
  289. if ((info->freq != val) && // method called for each processor, we only want to set pll once
  290. (device->device_fd > 0)) // we may not be mining yet, in which case just store freq
  291. gc3355_set_pll_freq(device->device_fd, val); // clock was set via RPC or TUI
  292. info->freq = val;
  293. return NULL;
  294. }
  295. static
  296. const char *gridseed_set_chips(struct cgpu_info * const device, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
  297. {
  298. struct gc3355_info * const info = device->device_data;
  299. int val = atoi(setting);
  300. info->chips = val;
  301. return NULL;
  302. }
  303. // for setting clock and chips during probe / detect
  304. static
  305. const struct bfg_set_device_definition gridseed_set_device_funcs_probe[] = {
  306. { "clock", gridseed_set_clock, NULL },
  307. { "chips", gridseed_set_chips, NULL },
  308. { NULL },
  309. };
  310. // for setting clock while mining
  311. static
  312. const struct bfg_set_device_definition gridseed_set_device_funcs_live[] = {
  313. { "clock", gridseed_set_clock, NULL },
  314. { NULL },
  315. };
  316. struct device_drv gridseed_drv =
  317. {
  318. // metadata
  319. .dname = "gridseed",
  320. .name = "GSD",
  321. .supported_algos = POW_SCRYPT,
  322. // detect device
  323. .lowl_probe = gridseed_lowl_probe,
  324. // initialize device
  325. .thread_prepare = gridseed_thread_prepare,
  326. // specify mining type - scanhash
  327. .minerloop = minerloop_scanhash,
  328. // scanhash mining hooks
  329. .scanhash = gridseed_scanhash,
  330. // teardown device
  331. .thread_shutdown = gridseed_thread_shutdown,
  332. };