driver-knc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /*
  2. * Copyright 2013 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 <stddef.h>
  12. #include <stdint.h>
  13. #include <sys/ioctl.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>
  17. #ifdef HAVE_LINUX_I2C_DEV_USER_H
  18. #include <linux/i2c-dev-user.h>
  19. #else
  20. #include <linux/i2c-dev.h>
  21. #endif
  22. #include <linux/spi/spidev.h>
  23. #include <uthash.h>
  24. #include "deviceapi.h"
  25. #include "logging.h"
  26. #include "miner.h"
  27. #include "spidevc.h"
  28. #define KNC_POLL_INTERVAL_US 10000
  29. #define KNC_SPI_SPEED 3000000
  30. #define KNC_SPI_DELAY 0
  31. #define KNC_SPI_MODE (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
  32. #define KNC_SPI_BITS 8
  33. static const char * const i2cpath = "/dev/i2c-2";
  34. enum knc_request_cmd {
  35. KNC_REQ_SUBMIT_WORK = 2,
  36. KNC_REQ_FLUSH_QUEUE = 3,
  37. };
  38. enum knc_reply_type {
  39. KNC_REPLY_NONCE_FOUND = 1,
  40. KNC_REPLY_WORK_DONE = 2,
  41. };
  42. struct device_drv knc_drv;
  43. struct knc_device {
  44. int i2c;
  45. struct spi_port *spi;
  46. struct work *workqueue;
  47. int workqueue_size;
  48. int workqueue_max;
  49. struct work *devicework;
  50. };
  51. struct knc_core {
  52. int asicno;
  53. };
  54. static
  55. bool knc_detect_one(const char *devpath)
  56. {
  57. static struct cgpu_info *prev_cgpu = NULL;
  58. struct cgpu_info *cgpu;
  59. int i;
  60. const int fd = open(i2cpath, O_RDWR);
  61. char *leftover = NULL;
  62. const int i2cslave = strtol(devpath, &leftover, 0);
  63. uint8_t buf[0x20];
  64. if (leftover && leftover[0])
  65. return false;
  66. if (unlikely(fd == -1))
  67. {
  68. applog(LOG_DEBUG, "%s: Failed to open %s", __func__, i2cpath);
  69. return false;
  70. }
  71. if (ioctl(fd, I2C_SLAVE, i2cslave))
  72. {
  73. close(fd);
  74. applog(LOG_DEBUG, "%s: Failed to select i2c slave 0x%x",
  75. __func__, i2cslave);
  76. return false;
  77. }
  78. i = i2c_smbus_read_i2c_block_data(fd, 0, 0x20, buf);
  79. close(fd);
  80. if (-1 == i)
  81. {
  82. applog(LOG_DEBUG, "%s: 0x%x: Failed to read i2c block data",
  83. __func__, i2cslave);
  84. return false;
  85. }
  86. for (i = 0; ; ++i)
  87. {
  88. if (buf[i] == 3)
  89. break;
  90. if (i == 0x1f)
  91. return false;
  92. }
  93. cgpu = malloc(sizeof(*cgpu));
  94. *cgpu = (struct cgpu_info){
  95. .drv = &knc_drv,
  96. .device_path = strdup(devpath),
  97. .deven = DEV_ENABLED,
  98. .procs = 192,
  99. .threads = prev_cgpu ? 0 : 1,
  100. };
  101. const bool rv = add_cgpu_slave(cgpu, prev_cgpu);
  102. prev_cgpu = cgpu;
  103. return rv;
  104. }
  105. static int knc_detect_auto(void)
  106. {
  107. const int first = 0x20, last = 0x26;
  108. char devpath[4];
  109. int found = 0, i;
  110. for (i = first; i <= last; ++i)
  111. {
  112. sprintf(devpath, "%d", i);
  113. if (knc_detect_one(devpath))
  114. ++found;
  115. }
  116. return found;
  117. }
  118. static void knc_detect(void)
  119. {
  120. generic_detect(&knc_drv, knc_detect_one, knc_detect_auto, GDF_REQUIRE_DNAME | GDF_DEFAULT_NOAUTO);
  121. }
  122. static
  123. bool knc_spi_open(const char *repr, struct spi_port * const spi)
  124. {
  125. const char * const spipath = "/dev/spidev1.0";
  126. const int fd = open(spipath, O_RDWR);
  127. const uint8_t lsbfirst = 0;
  128. if (fd == -1)
  129. return false;
  130. if (ioctl(fd, SPI_IOC_WR_MODE , &spi->mode )) goto fail;
  131. if (ioctl(fd, SPI_IOC_WR_LSB_FIRST , &lsbfirst )) goto fail;
  132. if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &spi->bits )) goto fail;
  133. if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ , &spi->speed)) goto fail;
  134. spi->fd = fd;
  135. return true;
  136. fail:
  137. close(fd);
  138. spi->fd = -1;
  139. applog(LOG_WARNING, "%s: Failed to open %s", repr, spipath);
  140. return false;
  141. }
  142. static
  143. bool knc_spi_txrx(struct spi_port * const spi)
  144. {
  145. const void * const wrbuf = spi_gettxbuf(spi);
  146. void * const rdbuf = spi_getrxbuf(spi);
  147. const size_t bufsz = spi_getbufsz(spi);
  148. const int fd = spi->fd;
  149. struct spi_ioc_transfer xf = {
  150. .tx_buf = (uintptr_t) wrbuf,
  151. .rx_buf = (uintptr_t) rdbuf,
  152. .len = bufsz,
  153. .delay_usecs = spi->delay,
  154. .speed_hz = spi->speed,
  155. .bits_per_word = spi->bits,
  156. };
  157. return (ioctl(fd, SPI_IOC_MESSAGE(1), &xf) > 0);
  158. }
  159. static
  160. bool knc_init(struct thr_info * const thr)
  161. {
  162. const int max_cores = 192;
  163. struct thr_info *mythr;
  164. struct cgpu_info * const cgpu = thr->cgpu, *proc;
  165. struct knc_device *knc;
  166. struct knc_core *knccore;
  167. struct spi_port *spi;
  168. const int i2c = open(i2cpath, O_RDWR);
  169. int i2cslave, i, j;
  170. uint8_t buf[0x20];
  171. if (unlikely(i2c == -1))
  172. {
  173. applog(LOG_DEBUG, "%s: Failed to open %s", __func__, i2cpath);
  174. return false;
  175. }
  176. for (proc = cgpu; proc; )
  177. {
  178. if (proc->device != proc)
  179. {
  180. applog(LOG_WARNING, "%"PRIpreprv": Extra processor?", proc->proc_repr);
  181. continue;
  182. }
  183. i2cslave = atoi(proc->device_path);
  184. if (ioctl(i2c, I2C_SLAVE, i2cslave))
  185. {
  186. applog(LOG_DEBUG, "%s: Failed to select i2c slave 0x%x",
  187. __func__, i2cslave);
  188. return false;
  189. }
  190. for (i = 0; i < max_cores; i += 0x20)
  191. {
  192. i2c_smbus_read_i2c_block_data(i2c, i, 0x20, buf);
  193. for (j = 0; j < 0x20; ++j)
  194. {
  195. mythr = proc->thr[0];
  196. mythr->cgpu_data = knccore = malloc(sizeof(*knccore));
  197. *knccore = (struct knc_core){
  198. .asicno = i2cslave - 0x20,
  199. };
  200. if (proc != cgpu)
  201. {
  202. mythr->queue_full = true;
  203. proc->device_data = NULL;
  204. }
  205. if (buf[j] != 3)
  206. proc->deven = DEV_DISABLED;
  207. proc = proc->next_proc;
  208. if ((!proc) || proc->device == proc)
  209. goto nomorecores;
  210. }
  211. }
  212. nomorecores: ;
  213. }
  214. cgpu->device_data = knc = malloc(sizeof(*knc));
  215. spi = malloc(sizeof(*spi));
  216. *knc = (struct knc_device){
  217. .i2c = i2c,
  218. .spi = spi,
  219. .workqueue_max = 1,
  220. };
  221. *spi = (struct spi_port){
  222. .txrx = knc_spi_txrx,
  223. .cgpu = cgpu,
  224. .repr = knc_drv.dname,
  225. .logprio = LOG_ERR,
  226. .speed = KNC_SPI_SPEED,
  227. .delay = KNC_SPI_DELAY,
  228. .mode = KNC_SPI_MODE,
  229. .bits = KNC_SPI_BITS,
  230. };
  231. if (!knc_spi_open(cgpu->dev_repr, spi))
  232. return false;
  233. timer_set_now(&thr->tv_poll);
  234. return true;
  235. }
  236. static
  237. void knc_remove_local_queue(struct knc_device * const knc, struct work * const work)
  238. {
  239. DL_DELETE(knc->workqueue, work);
  240. free_work(work);
  241. --knc->workqueue_size;
  242. }
  243. static
  244. void knc_prune_local_queue(struct thr_info *thr)
  245. {
  246. struct cgpu_info * const cgpu = thr->cgpu;
  247. struct knc_device * const knc = cgpu->device_data;
  248. struct work *work, *tmp;
  249. DL_FOREACH_SAFE(knc->workqueue, work, tmp)
  250. {
  251. if (stale_work(work, false))
  252. knc_remove_local_queue(knc, work);
  253. }
  254. thr->queue_full = (knc->workqueue_size >= knc->workqueue_max);
  255. }
  256. static
  257. bool knc_queue_append(struct thr_info * const thr, struct work * const work)
  258. {
  259. struct cgpu_info * const cgpu = thr->cgpu;
  260. struct knc_device * const knc = cgpu->device_data;
  261. if (knc->workqueue_size >= knc->workqueue_max)
  262. {
  263. knc_prune_local_queue(thr);
  264. if (thr->queue_full)
  265. return false;
  266. }
  267. DL_APPEND(knc->workqueue, work);
  268. ++knc->workqueue_size;
  269. thr->queue_full = (knc->workqueue_size >= knc->workqueue_max);
  270. if (thr->queue_full)
  271. knc_prune_local_queue(thr);
  272. return true;
  273. }
  274. static
  275. void knc_queue_flush(struct thr_info * const thr)
  276. {
  277. struct cgpu_info * const cgpu = thr->cgpu;
  278. struct knc_device * const knc = cgpu->device_data;
  279. struct work *work, *tmp;
  280. if (!knc)
  281. return;
  282. DL_FOREACH_SAFE(knc->workqueue, work, tmp)
  283. {
  284. knc_remove_local_queue(knc, work);
  285. }
  286. thr->queue_full = false;
  287. }
  288. static inline
  289. uint16_t get_u16be(const void * const p)
  290. {
  291. const uint8_t * const b = p;
  292. return (((uint16_t)b[0]) << 8) | b[1];
  293. }
  294. static inline
  295. uint32_t get_u32be(const void * const p)
  296. {
  297. const uint8_t * const b = p;
  298. return (((uint32_t)b[0]) << 0x18)
  299. | (((uint32_t)b[1]) << 0x10)
  300. | (((uint32_t)b[2]) << 8)
  301. | b[3];
  302. }
  303. static
  304. void knc_poll(struct thr_info * const thr)
  305. {
  306. struct thr_info *mythr;
  307. struct cgpu_info * const cgpu = thr->cgpu, *proc;
  308. struct knc_device * const knc = cgpu->device_data;
  309. struct spi_port * const spi = knc->spi;
  310. struct knc_core *knccore;
  311. struct work *work, *tmp;
  312. uint8_t buf[0x30], *rxbuf;
  313. int works_sent = 0, asicno, i;
  314. uint16_t workaccept;
  315. uint32_t nonce, coreno;
  316. size_t spi_req_sz = 0x1000;
  317. unsigned long delay_usecs = KNC_POLL_INTERVAL_US;
  318. knc_prune_local_queue(thr);
  319. spi_clear_buf(spi);
  320. DL_FOREACH(knc->workqueue, work)
  321. {
  322. buf[0] = KNC_REQ_SUBMIT_WORK << 4;
  323. buf[1] = 0;
  324. buf[2] = work->id >> 8;
  325. buf[3] = work->id & 0xff;
  326. for (i = 0; i < 0x20; ++i)
  327. buf[4 + i] = work->midstate[0x1f - i];
  328. for (i = 0; i < 0xc; ++i)
  329. buf[0x24 + i] = work->data[0x4b - i];
  330. spi_emit_buf(spi, buf, sizeof(buf));
  331. ++works_sent;
  332. }
  333. spi_emit_nop(spi, spi_req_sz - spi_getbufsz(spi));
  334. spi_txrx(spi);
  335. rxbuf = spi_getrxbuf(spi);
  336. if (rxbuf[3] & 1)
  337. applog(LOG_DEBUG, "%s: Receive buffer overflow reported", knc_drv.dname);
  338. workaccept = get_u16be(&rxbuf[6]);
  339. applog(LOG_DEBUG, "%s: %lu/%d jobs accepted to queue (max=%d)",
  340. knc_drv.dname, (unsigned long)workaccept, works_sent, knc->workqueue_max);
  341. if (workaccept)
  342. {
  343. if (workaccept >= knc->workqueue_max)
  344. {
  345. knc->workqueue_max = workaccept;
  346. delay_usecs = 0;
  347. }
  348. DL_FOREACH_SAFE(knc->workqueue, work, tmp)
  349. {
  350. --knc->workqueue_size;
  351. DL_DELETE(knc->workqueue, work);
  352. HASH_ADD_INT(knc->devicework, id, work);
  353. if (!--workaccept)
  354. break;
  355. }
  356. thr->queue_full = (knc->workqueue_size >= knc->workqueue_max);
  357. }
  358. while (true)
  359. {
  360. rxbuf += 0xc;
  361. spi_req_sz -= 0xc;
  362. if (spi_req_sz < 0xc)
  363. break;
  364. const int rtype = rxbuf[0] >> 6;
  365. if (rtype && opt_debug)
  366. {
  367. char x[(0xc * 2) + 1];
  368. bin2hex(x, rxbuf, 0xc);
  369. applog(LOG_DEBUG, "%s: RECV: %s", knc_drv.dname, x);
  370. }
  371. if (rtype != KNC_REPLY_NONCE_FOUND && rtype != KNC_REPLY_WORK_DONE)
  372. continue;
  373. asicno = (rxbuf[0] & 0x38) >> 3;
  374. coreno = get_u32be(&rxbuf[8]);
  375. proc = cgpu;
  376. while (true)
  377. {
  378. knccore = proc->thr[0]->cgpu_data;
  379. if (knccore->asicno == asicno)
  380. break;
  381. do {
  382. proc = proc->next_proc;
  383. } while(proc != proc->device);
  384. }
  385. for (i = 0; i < coreno; ++i)
  386. proc = proc->next_proc;
  387. mythr = proc->thr[0];
  388. i = get_u16be(&rxbuf[2]);
  389. HASH_FIND_INT(knc->devicework, &i, work);
  390. if (!work)
  391. {
  392. const char * const msgtype = (rtype == KNC_REPLY_NONCE_FOUND) ? "nonce found" : "work done";
  393. applog(LOG_WARNING, "%"PRIpreprv": Got %s message about unknown work 0x%04x",
  394. proc->proc_repr, msgtype, i);
  395. if (KNC_REPLY_NONCE_FOUND == rtype)
  396. {
  397. nonce = get_u32be(&rxbuf[4]);
  398. inc_hw_errors2(mythr, NULL, &nonce);
  399. }
  400. else
  401. inc_hw_errors2(mythr, NULL, NULL);
  402. continue;
  403. }
  404. switch (rtype)
  405. {
  406. case KNC_REPLY_NONCE_FOUND:
  407. nonce = get_u32be(&rxbuf[4]);
  408. nonce = le32toh(nonce);
  409. submit_nonce(mythr, work, nonce);
  410. break;
  411. case KNC_REPLY_WORK_DONE:
  412. HASH_DEL(knc->devicework, work);
  413. free_work(work);
  414. hashes_done2(mythr, 0x100000000, NULL);
  415. break;
  416. }
  417. }
  418. timer_set_delay_from_now(&thr->tv_poll, delay_usecs);
  419. }
  420. struct device_drv knc_drv = {
  421. .dname = "knc",
  422. .name = "KNC",
  423. .drv_detect = knc_detect,
  424. .thread_init = knc_init,
  425. .minerloop = minerloop_queue,
  426. .queue_append = knc_queue_append,
  427. .queue_flush = knc_queue_flush,
  428. .poll = knc_poll,
  429. };