dma.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <strings.h>
  4. #include <stdlib.h>
  5. #include <stdint.h>
  6. #include <stdarg.h>
  7. #include <fcntl.h>
  8. #include <unistd.h>
  9. #include <sys/ioctl.h>
  10. #include <sys/mman.h>
  11. #include <arpa/inet.h>
  12. #include <sys/time.h>
  13. #include <errno.h>
  14. #include <assert.h>
  15. #include "error.h"
  16. #include "pcilib.h"
  17. #include "pci.h"
  18. #include "dma.h"
  19. #include "tools.h"
  20. #include "pagecpy.h"
  21. const pcilib_dma_description_t *pcilib_get_dma_description(pcilib_t *ctx) {
  22. int err;
  23. err = pcilib_init_dma(ctx);
  24. if (err) {
  25. pcilib_error("Error (%i) while initializing DMA", err);
  26. return NULL;
  27. }
  28. if (!ctx->dma_ctx) return NULL;
  29. return &ctx->dma;
  30. }
  31. pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_engine_addr_t dma) {
  32. pcilib_dma_engine_t i;
  33. const pcilib_dma_description_t *dma_info = pcilib_get_dma_description(ctx);
  34. if (!dma_info) {
  35. pcilib_error("DMA Engine is not configured in the current model");
  36. return PCILIB_ERROR_NOTSUPPORTED;
  37. }
  38. for (i = 0; dma_info->engines[i].addr_bits; i++) {
  39. if ((dma_info->engines[i].addr == dma)&&((dma_info->engines[i].direction&direction)==direction)) break;
  40. }
  41. if (dma_info->engines[i].addr_bits) return i;
  42. return PCILIB_DMA_ENGINE_INVALID;
  43. }
  44. pcilib_dma_engine_t pcilib_add_dma_engine(pcilib_t *ctx, pcilib_dma_engine_description_t *desc) {
  45. pcilib_dma_engine_t engine = ctx->num_engines++;
  46. memcpy (&ctx->engines[engine], desc, sizeof(pcilib_dma_engine_description_t));
  47. return engine;
  48. }
  49. int pcilib_init_dma(pcilib_t *ctx) {
  50. int err;
  51. pcilib_dma_context_t *dma_ctx = NULL;
  52. const pcilib_dma_description_t *info = &ctx->dma;
  53. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  54. pcilib_dma_engine_t dma;
  55. if (ctx->dma_ctx)
  56. return 0;
  57. if ((ctx->event_ctx)&&(model_info->api)&&(model_info->api->init_dma)) {
  58. err = pcilib_init_register_banks(ctx);
  59. if (err) {
  60. pcilib_error("Error (%i) while initializing register banks", err);
  61. return err;
  62. }
  63. dma_ctx = model_info->api->init_dma(ctx->event_ctx);
  64. } else if ((ctx->dma.api)&&(ctx->dma.api->init)) {
  65. err = pcilib_init_register_banks(ctx);
  66. if (err) {
  67. pcilib_error("Error (%i) while initializing register banks", err);
  68. return err;
  69. }
  70. dma_ctx = ctx->dma.api->init(ctx, (ctx->dma.model?ctx->dma.model:ctx->model), ctx->dma.args);
  71. }
  72. if (dma_ctx) {
  73. for (dma = 0; info->engines[dma].addr_bits; dma++) {
  74. if (info->engines[dma].direction&PCILIB_DMA_FROM_DEVICE) {
  75. ctx->dma_rlock[dma] = pcilib_get_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, "dma%ir/%s", info->engines[dma].addr, info->name);
  76. if (!ctx->dma_rlock[dma]) break;
  77. }
  78. if (info->engines[dma].direction&PCILIB_DMA_TO_DEVICE) {
  79. ctx->dma_wlock[dma] = pcilib_get_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, "dma%iw/%s", info->engines[dma].addr, info->name);
  80. if (!ctx->dma_wlock[dma]) break;
  81. }
  82. }
  83. if (info->engines[dma].addr_bits) {
  84. if (ctx->dma.api->free)
  85. ctx->dma.api->free(dma_ctx);
  86. pcilib_error("Failed to intialize DMA locks");
  87. return PCILIB_ERROR_FAILED;
  88. }
  89. dma_ctx->pcilib = ctx;
  90. // DS: parameters?
  91. ctx->dma_ctx = dma_ctx;
  92. }
  93. return 0;
  94. }
  95. int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
  96. const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx);
  97. if (!info) {
  98. pcilib_error("DMA is not supported by the device");
  99. return PCILIB_ERROR_NOTSUPPORTED;
  100. }
  101. if (!info->api) {
  102. pcilib_error("DMA Engine is not configured in the current model");
  103. return PCILIB_ERROR_NOTAVAILABLE;
  104. }
  105. if (!info->api->start_dma) {
  106. return 0;
  107. }
  108. return info->api->start_dma(ctx->dma_ctx, dma, flags);
  109. }
  110. int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
  111. const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx);
  112. if (!info) {
  113. pcilib_error("DMA is not supported by the device");
  114. return PCILIB_ERROR_NOTSUPPORTED;
  115. }
  116. if (!info->api) {
  117. pcilib_error("DMA Engine is not configured in the current model");
  118. return PCILIB_ERROR_NOTAVAILABLE;
  119. }
  120. if (!info->api->stop_dma) {
  121. return 0;
  122. }
  123. return info->api->stop_dma(ctx->dma_ctx, dma, flags);
  124. }
  125. int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags) {
  126. const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx);
  127. if ((!info)||(!info->api)||(!info->api->enable_irq)) return 0;
  128. return info->api->enable_irq(ctx->dma_ctx, irq_type, flags);
  129. }
  130. int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) {
  131. const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx);
  132. if ((!info)||(!info->api)||(!info->api->disable_irq)) return 0;
  133. return info->api->disable_irq(ctx->dma_ctx, flags);
  134. }
  135. int pcilib_acknowledge_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source) {
  136. const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx);
  137. if ((!info)||(!info->api)||(!info->api->acknowledge_irq)) return 0;
  138. return info->api->acknowledge_irq(ctx->dma_ctx, irq_type, irq_source);
  139. }
  140. typedef struct {
  141. size_t size;
  142. void *data;
  143. size_t pos;
  144. pcilib_dma_flags_t flags;
  145. } pcilib_dma_read_callback_context_t;
  146. static int pcilib_dma_read_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
  147. pcilib_dma_read_callback_context_t *ctx = (pcilib_dma_read_callback_context_t*)arg;
  148. if (ctx->pos + bufsize > ctx->size) {
  149. if ((ctx->flags&PCILIB_DMA_FLAG_IGNORE_ERRORS) == 0)
  150. pcilib_error("Buffer size (%li) is not large enough for DMA packet, at least %li bytes is required", ctx->size, ctx->pos + bufsize);
  151. return -PCILIB_ERROR_TOOBIG;
  152. }
  153. pcilib_pagecpy(ctx->data + ctx->pos, buf, bufsize);
  154. ctx->pos += bufsize;
  155. if (flags & PCILIB_DMA_FLAG_EOP) {
  156. if ((ctx->pos < ctx->size)&&(ctx->flags&PCILIB_DMA_FLAG_MULTIPACKET)) {
  157. if (ctx->flags&PCILIB_DMA_FLAG_WAIT) return PCILIB_STREAMING_WAIT;
  158. else return PCILIB_STREAMING_CONTINUE;
  159. }
  160. return PCILIB_STREAMING_STOP;
  161. }
  162. return PCILIB_STREAMING_REQ_FRAGMENT;
  163. }
  164. static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
  165. struct timeval *tv = (struct timeval*)arg;
  166. struct timeval cur;
  167. if (tv) {
  168. gettimeofday(&cur, NULL);
  169. if ((cur.tv_sec > tv->tv_sec)||((cur.tv_sec == tv->tv_sec)&&(cur.tv_usec > tv->tv_usec))) return PCILIB_STREAMING_STOP;
  170. }
  171. return PCILIB_STREAMING_REQ_PACKET;
  172. }
  173. int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr) {
  174. int err;
  175. const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx);
  176. if (!info) {
  177. pcilib_error("DMA is not supported by the device");
  178. return PCILIB_ERROR_NOTSUPPORTED;
  179. }
  180. if (!info->api) {
  181. pcilib_error("DMA Engine is not configured in the current model");
  182. return PCILIB_ERROR_NOTAVAILABLE;
  183. }
  184. if (!info->api->stream) {
  185. pcilib_error("The DMA read is not supported by configured DMA engine");
  186. return PCILIB_ERROR_NOTSUPPORTED;
  187. }
  188. // DS: We should check we are not going outside of allocated engine space
  189. if (!info->engines[dma].addr_bits) {
  190. pcilib_error("The DMA engine (%i) is not supported by device", dma);
  191. return PCILIB_ERROR_NOTAVAILABLE;
  192. }
  193. if ((info->engines[dma].direction&PCILIB_DMA_FROM_DEVICE) == 0) {
  194. pcilib_error("The selected engine (%i) is S2C-only and does not support reading", dma);
  195. return PCILIB_ERROR_NOTSUPPORTED;
  196. }
  197. err = pcilib_try_lock(ctx->dma_rlock[dma]);
  198. if (err) {
  199. if ((err == PCILIB_ERROR_BUSY)||(err == PCILIB_ERROR_TIMEOUT))
  200. pcilib_error("DMA engine (%i) is busy", dma);
  201. else
  202. pcilib_error("Error (%i) locking DMA engine (%i)", err, dma);
  203. return err;
  204. }
  205. err = info->api->stream(ctx->dma_ctx, dma, addr, size, flags, timeout, cb, cbattr);
  206. pcilib_unlock(ctx->dma_rlock[dma]);
  207. return err;
  208. }
  209. int pcilib_read_dma_custom(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *read_bytes) {
  210. int err;
  211. pcilib_dma_read_callback_context_t opts = {
  212. size, buf, 0, flags
  213. };
  214. err = pcilib_stream_dma(ctx, dma, addr, size, flags, timeout, pcilib_dma_read_callback, &opts);
  215. if (read_bytes) *read_bytes = opts.pos;
  216. return err;
  217. }
  218. int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *read_bytes) {
  219. int err;
  220. pcilib_dma_read_callback_context_t opts = {
  221. size, buf, 0, 0
  222. };
  223. err = pcilib_stream_dma(ctx, dma, addr, size, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_read_callback, &opts);
  224. if (read_bytes) *read_bytes = opts.pos;
  225. return err;
  226. }
  227. int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma) {
  228. int err;
  229. struct timeval tv, cur;
  230. gettimeofday(&tv, NULL);
  231. tv.tv_usec += PCILIB_DMA_SKIP_TIMEOUT;
  232. tv.tv_sec += tv.tv_usec / 1000000;
  233. tv.tv_usec += tv.tv_usec % 1000000;
  234. do {
  235. // IMMEDIATE timeout is not working properly, so default is set
  236. err = pcilib_stream_dma(ctx, dma, 0, 0, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_skip_callback, &tv);
  237. gettimeofday(&cur, NULL);
  238. } while ((!err)&&((cur.tv_sec < tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec < tv.tv_usec))));
  239. if ((cur.tv_sec > tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec > tv.tv_usec))) return PCILIB_ERROR_TIMEOUT;
  240. return 0;
  241. }
  242. int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written) {
  243. int err;
  244. const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx);
  245. if (!info) {
  246. pcilib_error("DMA is not supported by the device");
  247. return PCILIB_ERROR_NOTSUPPORTED;
  248. }
  249. if (!info->api) {
  250. pcilib_error("DMA Engine is not configured in the current model");
  251. return PCILIB_ERROR_NOTAVAILABLE;
  252. }
  253. if (!info->api->push) {
  254. pcilib_error("The DMA write is not supported by configured DMA engine");
  255. return PCILIB_ERROR_NOTSUPPORTED;
  256. }
  257. // DS: We should check we don't exceed allocated engine range
  258. if (!info->engines[dma].addr_bits) {
  259. pcilib_error("The DMA engine (%i) is not supported by device", dma);
  260. return PCILIB_ERROR_NOTAVAILABLE;
  261. }
  262. if ((info->engines[dma].direction&PCILIB_DMA_TO_DEVICE) == 0) {
  263. pcilib_error("The selected engine (%i) is C2S-only and does not support writes", dma);
  264. return PCILIB_ERROR_NOTSUPPORTED;
  265. }
  266. err = pcilib_try_lock(ctx->dma_wlock[dma]);
  267. if (err) {
  268. if (err == PCILIB_ERROR_BUSY)
  269. pcilib_error("DMA engine (%i) is busy", dma);
  270. else
  271. pcilib_error("Error (%i) locking DMA engine (%i)", err, dma);
  272. return err;
  273. }
  274. err = info->api->push(ctx->dma_ctx, dma, addr, size, flags, timeout, buf, written);
  275. pcilib_unlock(ctx->dma_wlock[dma]);
  276. return err;
  277. }
  278. int pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *written_bytes) {
  279. return pcilib_push_dma(ctx, dma, addr, size, PCILIB_DMA_FLAG_EOP|PCILIB_DMA_FLAG_WAIT, PCILIB_DMA_TIMEOUT, buf, written_bytes);
  280. }
  281. double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) {
  282. const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx);
  283. if (!info) {
  284. pcilib_error("DMA is not supported by the device");
  285. return 0;
  286. }
  287. if (!info->api) {
  288. pcilib_error("DMA Engine is not configured in the current model");
  289. return -1;
  290. }
  291. if (!info->api->benchmark) {
  292. pcilib_error("The DMA benchmark is not supported by configured DMA engine");
  293. return -1;
  294. }
  295. return info->api->benchmark(ctx->dma_ctx, dma, addr, size, iterations, direction);
  296. }
  297. int pcilib_get_dma_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) {
  298. const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx);
  299. if (!info) {
  300. pcilib_error("DMA is not supported by the device");
  301. return 0;
  302. }
  303. if (!info->api) {
  304. pcilib_error("DMA Engine is not configured in the current model");
  305. return -1;
  306. }
  307. if (!info->api->status) {
  308. memset(status, 0, sizeof(pcilib_dma_engine_status_t));
  309. return -1;
  310. }
  311. // DS: We should check we don't exceed allocated engine range
  312. if (!info->engines[dma].addr_bits) {
  313. pcilib_error("The DMA engine (%i) is not supported by device", dma);
  314. return -1;
  315. }
  316. return info->api->status(ctx->dma_ctx, dma, status, n_buffers, buffers);
  317. }