driver-gridseed.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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. #define GRIDSEED_MAX_QUEUED 10
  19. BFG_REGISTER_DRIVER(gridseed_drv)
  20. /*
  21. * helper functions
  22. */
  23. static
  24. struct cgpu_info *gridseed_alloc_device(const char *path, struct device_drv *driver, struct gc3355_orb_info *info)
  25. {
  26. struct cgpu_info *device = calloc(1, sizeof(struct cgpu_info));
  27. if (unlikely(!device))
  28. quit(1, "Failed to malloc cgpu_info");
  29. device->drv = driver;
  30. device->device_path = strdup(path);
  31. device->device_fd = -1;
  32. device->threads = 1;
  33. device->procs = GC3355_ORB_DEFAULT_CHIPS;
  34. device->device_data = info;
  35. return device;
  36. }
  37. static
  38. struct gc3355_orb_info *gridseed_alloc_info()
  39. {
  40. struct gc3355_orb_info *info = calloc(1, sizeof(struct gc3355_orb_info));
  41. if (unlikely(!info))
  42. quit(1, "Failed to malloc gc3355_orb_info");
  43. info->freq = GRIDSEED_DEFAULT_FREQUENCY;
  44. return info;
  45. }
  46. static
  47. void gridseed_empty_work(int fd)
  48. {
  49. unsigned char buf[GC3355_READ_SIZE];
  50. gc3355_read(fd, (char *)buf, GC3355_READ_SIZE);
  51. }
  52. /*
  53. * device detection
  54. */
  55. static
  56. bool gridseed_detect_custom(const char *path, struct device_drv *driver, struct gc3355_orb_info *info)
  57. {
  58. int fd = gc3355_open(path);
  59. if(fd < 0)
  60. return false;
  61. gridseed_empty_work(fd);
  62. uint32_t fw_version = gc3355_get_firmware_version(fd);
  63. if (fw_version == -1)
  64. {
  65. applog(LOG_ERR, "%s: Invalid detect response from %s", gridseed_drv.dname, path);
  66. gc3355_close(fd);
  67. return false;
  68. }
  69. if (serial_claim_v(path, driver))
  70. return false;
  71. struct cgpu_info *device = gridseed_alloc_device(path, driver, info);
  72. if (!add_cgpu(device))
  73. return false;
  74. device->device_fd = fd;
  75. gc3355_init_usborb(device->device_fd, info->freq, false, false);
  76. applog(LOG_INFO, "Found %"PRIpreprv" at %s", device->proc_repr, path);
  77. applog(LOG_DEBUG, "%"PRIpreprv": Init: firmware=%d", device->proc_repr, fw_version);
  78. return true;
  79. }
  80. static
  81. bool gridseed_detect_one(const char *path)
  82. {
  83. struct gc3355_orb_info *info = gridseed_alloc_info();
  84. if (!gridseed_detect_custom(path, &gridseed_drv, info))
  85. {
  86. free(info);
  87. return false;
  88. }
  89. return true;
  90. }
  91. static
  92. bool gridseed_lowl_probe(const struct lowlevel_device_info * const info)
  93. {
  94. return vcom_lowl_probe_wrapper(info, gridseed_detect_one);
  95. }
  96. /*
  97. * setup & shutdown
  98. */
  99. static
  100. bool gridseed_thread_prepare(struct thr_info *thr)
  101. {
  102. thr->cgpu_data = calloc(1, sizeof(*thr->cgpu_data));
  103. if (opt_scrypt)
  104. {
  105. struct cgpu_info *device = thr->cgpu;
  106. device->min_nonce_diff = 1./0x10000;
  107. }
  108. return true;
  109. }
  110. static
  111. bool gridseed_set_queue_full(const struct cgpu_info * const device, int needwork);
  112. static
  113. bool gridseed_thread_init(struct thr_info *master_thr)
  114. {
  115. struct cgpu_info * const device = master_thr->cgpu, *proc;
  116. gridseed_set_queue_full(device, 0);
  117. timer_set_now(&master_thr->tv_poll);
  118. // kick off queue minerloop
  119. gridseed_set_queue_full(device, device->procs * 2);
  120. return true;
  121. }
  122. static
  123. void gridseed_thread_shutdown(struct thr_info *thr)
  124. {
  125. struct cgpu_info *device = thr->cgpu;
  126. gc3355_close(device->device_fd);
  127. free(thr->cgpu_data);
  128. }
  129. static
  130. void gridseed_reinit_device(struct cgpu_info * const proc)
  131. {
  132. timer_set_now(&proc->thr[0]->tv_poll);
  133. }
  134. /*
  135. * queued mining loop
  136. */
  137. static
  138. bool gridseed_set_queue_full(const struct cgpu_info * const device, int needwork)
  139. {
  140. struct gc3355_orb_info * const info = device->device_data;
  141. struct thr_info * const master_thr = device->thr[0];
  142. if (needwork != -1)
  143. info->needwork = needwork;
  144. const bool full = (device->device_fd == -1 || !info->needwork);
  145. if (full == master_thr->queue_full)
  146. return full;
  147. for (const struct cgpu_info *proc = device; proc; proc = proc->next_proc)
  148. {
  149. struct thr_info * const thr = proc->thr[0];
  150. thr->queue_full = full;
  151. }
  152. return full;
  153. }
  154. static
  155. bool gridseed_send_work(const struct cgpu_info * const device, struct work *work)
  156. {
  157. struct gc3355_orb_info * const info = device->device_data;
  158. int work_size = opt_scrypt ? 156 : 52;
  159. unsigned char cmd[work_size];
  160. if (opt_scrypt)
  161. {
  162. gc3355_scrypt_reset(device->device_fd);
  163. gc3355_scrypt_prepare_work(cmd, work);
  164. }
  165. else
  166. gc3355_sha2_prepare_work(cmd, work, true);
  167. // send work
  168. if (sizeof(cmd) != gc3355_write(device->device_fd, cmd, sizeof(cmd)))
  169. {
  170. applog(LOG_ERR, "%s: Failed to send work", device->dev_repr);
  171. return false;
  172. }
  173. return true;
  174. }
  175. static
  176. void gridseed_prune_queue(const struct cgpu_info * const device, struct work *work)
  177. {
  178. struct thr_info * const master_thr = device->thr[0];
  179. // prune queue
  180. int prunequeue = HASH_COUNT(master_thr->work_list) - GRIDSEED_MAX_QUEUED;
  181. if (prunequeue > 0)
  182. {
  183. struct work *tmp;
  184. applog(LOG_DEBUG, "%s: Pruning %d old work item%s",
  185. device->dev_repr, prunequeue, prunequeue == 1 ? "" : "s");
  186. HASH_ITER(hh, master_thr->work_list, work, tmp)
  187. {
  188. HASH_DEL(master_thr->work_list, work);
  189. free_work(work);
  190. if (--prunequeue < 1)
  191. break;
  192. }
  193. }
  194. }
  195. // send work to the device & queue work
  196. static
  197. bool gridseed_queue_append(struct thr_info * const thr, struct work *work)
  198. {
  199. const struct cgpu_info * const device = thr->cgpu->device;
  200. struct gc3355_orb_info * const info = device->device_data;
  201. struct thr_info * const master_thr = device->thr[0];
  202. // if queue is full (-1 is a check flag) do not append new work
  203. if (gridseed_set_queue_full(device, -1))
  204. return false;
  205. // send work
  206. if (!gridseed_send_work(device, work))
  207. return false;
  208. // store work in queue
  209. HASH_ADD(hh, master_thr->work_list, id, sizeof(work->id), work);
  210. // prune queue
  211. gridseed_prune_queue(device, work);
  212. // sets info->needwork equal to 2nd arg and updates "full" flags
  213. gridseed_set_queue_full(device, info->needwork - 1);
  214. return true;
  215. }
  216. static
  217. void gridseed_queue_flush(struct thr_info * const thr)
  218. {
  219. const struct cgpu_info *device = thr->cgpu;
  220. if (device != device->device)
  221. return;
  222. gridseed_set_queue_full(device, device->procs);
  223. }
  224. static
  225. const struct cgpu_info *gridseed_proc_by_id(const struct cgpu_info * const dev, int procid)
  226. {
  227. const struct cgpu_info *proc = dev;
  228. for (int i = 0; i < procid; ++i)
  229. {
  230. proc = proc->next_proc;
  231. if (unlikely(!proc))
  232. return NULL;
  233. }
  234. return proc;
  235. }
  236. static
  237. void gridseed_submit_nonce(struct thr_info * const master_thr, const unsigned char buf[GC3355_READ_SIZE])
  238. {
  239. struct work *work;
  240. uint32_t nonce;
  241. int workid;
  242. struct cgpu_info * const device = master_thr->cgpu;
  243. struct gc3355_orb_info * const info = device->device_data;
  244. // extract workid from buffer
  245. memcpy(&workid, buf + 8, 4);
  246. // extract nonce from buffer
  247. memcpy(&nonce, buf + 4, 4);
  248. // extract chip # from nonce
  249. const int chip = nonce / ((uint32_t)0xffffffff / GC3355_ORB_DEFAULT_CHIPS);
  250. // find processor by device & chip
  251. const struct cgpu_info *proc = gridseed_proc_by_id(device, chip);
  252. // default process to device
  253. if (unlikely(!proc))
  254. proc = device;
  255. // the thread specific to the ASIC chip:
  256. struct thr_info * thr = proc->thr[0];
  257. nonce = htole32(nonce);
  258. // find the queued work for this nonce, by workid
  259. HASH_FIND(hh, master_thr->work_list, &workid, sizeof(workid), work);
  260. if (work)
  261. {
  262. submit_nonce(thr, work, nonce);
  263. HASH_DEL(master_thr->work_list, work);
  264. gridseed_set_queue_full(device, info->needwork + 2);
  265. }
  266. }
  267. static
  268. void gridseed_estimate_hashes(const struct cgpu_info * const device)
  269. {
  270. const struct cgpu_info *proc = device;
  271. const struct gc3355_orb_info *info = device->device_data;
  272. while (true)
  273. {
  274. hashes_done2(proc->thr[0], info->freq * 0xA4, NULL);
  275. proc = proc->next_proc;
  276. if (unlikely(!proc))
  277. return;
  278. }
  279. }
  280. #define GRIDSEED_SHORT_WORK_DELAY_MS 20
  281. #define GRIDSEED_LONG_WORK_DELAY_MS 30
  282. // read from device for nonce or command
  283. static
  284. void gridseed_poll(struct thr_info * const master_thr)
  285. {
  286. struct cgpu_info * const device = master_thr->cgpu;
  287. int fd = device->device_fd;
  288. unsigned char buf[GC3355_READ_SIZE];
  289. int read = 0;
  290. struct timeval tv_timeout;
  291. timer_set_delay_from_now(&tv_timeout, GRIDSEED_LONG_WORK_DELAY_MS * 1000); // X MS
  292. bool timeout = false;
  293. while (!master_thr->work_restart && (read = gc3355_read(device->device_fd, (char *)buf, GC3355_READ_SIZE)) > 0)
  294. {
  295. if (buf[0] == 0x55)
  296. {
  297. switch(buf[1]) {
  298. case 0xaa:
  299. // Queue length result
  300. // could watch for watchdog reset here
  301. break;
  302. case 0x10: // BTC result
  303. case 0x20: // LTC result
  304. {
  305. gridseed_submit_nonce(master_thr, buf);
  306. break;
  307. }
  308. }
  309. } else
  310. {
  311. applog(LOG_ERR, "%"PRIpreprv": Unrecognized response", device->proc_repr);
  312. break;
  313. }
  314. if (timer_passed(&tv_timeout, NULL))
  315. {
  316. // allow work to be sent to the device
  317. applog(LOG_DEBUG, "%s poll: timeout met", device->dev_repr);
  318. timeout = true;
  319. break;
  320. }
  321. }
  322. gridseed_estimate_hashes(device);
  323. // allow work to be sent to the device
  324. timer_set_delay_from_now(&master_thr->tv_poll, GRIDSEED_SHORT_WORK_DELAY_MS * 1000); // X MS
  325. }
  326. /*
  327. * specify settings / options
  328. */
  329. // support for --set-device dualminer:clock=freq
  330. static
  331. char *gridseed_set_device(struct cgpu_info *device, char *option, char *setting, char *replybuf)
  332. {
  333. if (strcasecmp(option, "clock") == 0)
  334. {
  335. int val = atoi(setting);
  336. struct gc3355_orb_info *info = (struct gc3355_orb_info *)(device->device_data);
  337. info->freq = val;
  338. int fd = device->device_fd;
  339. gc3355_set_pll_freq(fd, val);
  340. return NULL;
  341. }
  342. sprintf(replybuf, "Unknown option: %s", option);
  343. return replybuf;
  344. }
  345. struct device_drv gridseed_drv =
  346. {
  347. // metadata
  348. .dname = "gridseed",
  349. .name = "GSD",
  350. .supported_algos = POW_SCRYPT,
  351. // detect device
  352. .lowl_probe = gridseed_lowl_probe,
  353. // initialize device
  354. .thread_prepare = gridseed_thread_prepare,
  355. .thread_init = gridseed_thread_init,
  356. .reinit_device = gridseed_reinit_device,
  357. // specify mining type - scanhash
  358. .minerloop = minerloop_queue,
  359. // queued mining hooks
  360. .queue_append = gridseed_queue_append,
  361. .queue_flush = gridseed_queue_flush,
  362. .poll = gridseed_poll,
  363. // teardown device
  364. .thread_shutdown = gridseed_thread_shutdown,
  365. // specify settings / options
  366. .set_device = gridseed_set_device,
  367. };