dma.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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. const pcilib_dma_info_t *pcilib_get_dma_info(pcilib_t *ctx) {
  20. if (!ctx->dma_ctx) {
  21. pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  22. if ((ctx->event_ctx)&&(model_info->event_api->init_dma)) {
  23. pcilib_map_register_space(ctx);
  24. ctx->dma_ctx = model_info->event_api->init_dma(ctx->event_ctx);
  25. } else if ((model_info->dma_api)&&(model_info->dma_api->init)) {
  26. pcilib_map_register_space(ctx);
  27. ctx->dma_ctx = model_info->dma_api->init(ctx, PCILIB_DMA_MODIFICATION_DEFAULT, NULL);
  28. }
  29. if (!ctx->dma_ctx) return NULL;
  30. }
  31. return &ctx->dma_info;
  32. }
  33. pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_engine_addr_t dma) {
  34. pcilib_dma_engine_t i;
  35. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  36. if (!info) {
  37. pcilib_error("DMA Engine is not configured in the current model");
  38. return PCILIB_ERROR_NOTSUPPORTED;
  39. }
  40. for (i = 0; info->engines[i]; i++) {
  41. if ((info->engines[i]->addr == dma)&&((info->engines[i]->direction&direction)==direction)) break;
  42. }
  43. if (info->engines[i]) return i;
  44. return PCILIB_DMA_ENGINE_INVALID;
  45. }
  46. int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_engine_t engine, pcilib_dma_engine_description_t *desc) {
  47. ctx->dma_info.engines[engine] = desc;
  48. }
  49. int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
  50. int err;
  51. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  52. if (!info) {
  53. pcilib_error("DMA is not supported by the device");
  54. return PCILIB_ERROR_NOTSUPPORTED;
  55. }
  56. if (!ctx->model_info.dma_api) {
  57. pcilib_error("DMA Engine is not configured in the current model");
  58. return PCILIB_ERROR_NOTAVAILABLE;
  59. }
  60. if (!ctx->model_info.dma_api->start_dma) {
  61. return 0;
  62. }
  63. return ctx->model_info.dma_api->start_dma(ctx->dma_ctx, dma, flags);
  64. }
  65. int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
  66. int err;
  67. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  68. if (!info) {
  69. pcilib_error("DMA is not supported by the device");
  70. return PCILIB_ERROR_NOTSUPPORTED;
  71. }
  72. if (!ctx->model_info.dma_api) {
  73. pcilib_error("DMA Engine is not configured in the current model");
  74. return PCILIB_ERROR_NOTAVAILABLE;
  75. }
  76. if (!ctx->model_info.dma_api->stop_dma) {
  77. return 0;
  78. }
  79. return ctx->model_info.dma_api->stop_dma(ctx->dma_ctx, dma, flags);
  80. }
  81. int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags) {
  82. int err;
  83. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  84. if (!info) {
  85. pcilib_error("DMA is not supported by the device");
  86. return PCILIB_ERROR_NOTSUPPORTED;
  87. }
  88. if (!ctx->model_info.dma_api) {
  89. pcilib_error("DMA Engine is not configured in the current model");
  90. return PCILIB_ERROR_NOTAVAILABLE;
  91. }
  92. if (!ctx->model_info.dma_api->enable_irq) {
  93. return 0;
  94. }
  95. return ctx->model_info.dma_api->enable_irq(ctx->dma_ctx, irq_type, flags);
  96. }
  97. int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) {
  98. int err;
  99. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  100. if (!info) {
  101. pcilib_error("DMA is not supported by the device");
  102. return PCILIB_ERROR_NOTSUPPORTED;
  103. }
  104. if (!ctx->model_info.dma_api) {
  105. pcilib_error("DMA Engine is not configured in the current model");
  106. return PCILIB_ERROR_NOTAVAILABLE;
  107. }
  108. if (!ctx->model_info.dma_api->disable_irq) {
  109. return 0;
  110. }
  111. return ctx->model_info.dma_api->disable_irq(ctx->dma_ctx, flags);
  112. }
  113. int pcilib_acknowledge_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source) {
  114. int err;
  115. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  116. if (!info) {
  117. pcilib_error("DMA is not supported by the device");
  118. return PCILIB_ERROR_NOTSUPPORTED;
  119. }
  120. if (!ctx->model_info.dma_api) {
  121. pcilib_error("DMA Engine is not configured in the current model");
  122. return PCILIB_ERROR_NOTAVAILABLE;
  123. }
  124. if (!ctx->model_info.dma_api->acknowledge_irq) {
  125. return 0;
  126. }
  127. return ctx->model_info.dma_api->acknowledge_irq(ctx->dma_ctx, irq_type, irq_source);
  128. }
  129. typedef struct {
  130. size_t size;
  131. void *data;
  132. size_t pos;
  133. pcilib_dma_flags_t flags;
  134. } pcilib_dma_read_callback_context_t;
  135. static int pcilib_dma_read_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
  136. pcilib_dma_read_callback_context_t *ctx = (pcilib_dma_read_callback_context_t*)arg;
  137. if (ctx->pos + bufsize > ctx->size) {
  138. if ((ctx->flags&PCILIB_DMA_FLAG_IGNORE_ERRORS) == 0)
  139. pcilib_error("Buffer size (%li) is not large enough for DMA packet, at least %li bytes is required", ctx->size, ctx->pos + bufsize);
  140. return -PCILIB_ERROR_TOOBIG;
  141. }
  142. memcpy(ctx->data + ctx->pos, buf, bufsize);
  143. ctx->pos += bufsize;
  144. if (flags & PCILIB_DMA_FLAG_EOP) {
  145. if ((ctx->pos < ctx->size)&&(ctx->flags&PCILIB_DMA_FLAG_MULTIPACKET)) {
  146. if (ctx->flags&PCILIB_DMA_FLAG_WAIT) return PCILIB_STREAMING_WAIT;
  147. else return PCILIB_STREAMING_CONTINUE;
  148. }
  149. return PCILIB_STREAMING_STOP;
  150. }
  151. return PCILIB_STREAMING_REQ_FRAGMENT;
  152. }
  153. static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
  154. struct timeval *tv = (struct timeval*)arg;
  155. struct timeval cur;
  156. if (tv) {
  157. gettimeofday(&cur, NULL);
  158. if ((cur.tv_sec > tv->tv_sec)||((cur.tv_sec == tv->tv_sec)&&(cur.tv_usec > tv->tv_usec))) return PCILIB_STREAMING_STOP;
  159. }
  160. return PCILIB_STREAMING_REQ_PACKET;
  161. }
  162. 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) {
  163. int err;
  164. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  165. if (!info) {
  166. pcilib_error("DMA is not supported by the device");
  167. return PCILIB_ERROR_NOTSUPPORTED;
  168. }
  169. if (!ctx->model_info.dma_api) {
  170. pcilib_error("DMA Engine is not configured in the current model");
  171. return PCILIB_ERROR_NOTAVAILABLE;
  172. }
  173. if (!ctx->model_info.dma_api->stream) {
  174. pcilib_error("The DMA read is not supported by configured DMA engine");
  175. return PCILIB_ERROR_NOTSUPPORTED;
  176. }
  177. if (!info->engines[dma]) {
  178. pcilib_error("The DMA engine (%i) is not supported by device", dma);
  179. return PCILIB_ERROR_NOTAVAILABLE;
  180. }
  181. if (info->engines[dma]->direction&PCILIB_DMA_FROM_DEVICE == 0) {
  182. pcilib_error("The selected engine (%i) is S2C-only and does not support reading", dma);
  183. return PCILIB_ERROR_NOTSUPPORTED;
  184. }
  185. return ctx->model_info.dma_api->stream(ctx->dma_ctx, dma, addr, size, flags, timeout, cb, cbattr);
  186. }
  187. 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) {
  188. int err;
  189. pcilib_dma_read_callback_context_t opts = {
  190. size, buf, 0, flags
  191. };
  192. err = pcilib_stream_dma(ctx, dma, addr, size, flags, timeout, pcilib_dma_read_callback, &opts);
  193. if (read_bytes) *read_bytes = opts.pos;
  194. return err;
  195. }
  196. int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *read_bytes) {
  197. int err;
  198. pcilib_dma_read_callback_context_t opts = {
  199. size, buf, 0, 0
  200. };
  201. err = pcilib_stream_dma(ctx, dma, addr, size, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_read_callback, &opts);
  202. if (read_bytes) *read_bytes = opts.pos;
  203. return err;
  204. }
  205. int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma) {
  206. int err;
  207. struct timeval tv, cur;
  208. gettimeofday(&tv, NULL);
  209. tv.tv_usec += PCILIB_DMA_SKIP_TIMEOUT;
  210. tv.tv_sec += tv.tv_usec / 1000000;
  211. tv.tv_usec += tv.tv_usec % 1000000;
  212. do {
  213. // IMMEDIATE timeout is not working properly, so default is set
  214. err = pcilib_stream_dma(ctx, dma, 0, 0, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_skip_callback, &tv);
  215. gettimeofday(&cur, NULL);
  216. } while ((!err)&&((cur.tv_sec < tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec < tv.tv_usec))));
  217. if ((cur.tv_sec > tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec > tv.tv_usec))) return PCILIB_ERROR_TIMEOUT;
  218. return 0;
  219. }
  220. 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) {
  221. int err;
  222. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  223. if (!info) {
  224. pcilib_error("DMA is not supported by the device");
  225. return PCILIB_ERROR_NOTSUPPORTED;
  226. }
  227. if (!ctx->model_info.dma_api) {
  228. pcilib_error("DMA Engine is not configured in the current model");
  229. return PCILIB_ERROR_NOTAVAILABLE;
  230. }
  231. if (!ctx->model_info.dma_api->push) {
  232. pcilib_error("The DMA write is not supported by configured DMA engine");
  233. return PCILIB_ERROR_NOTSUPPORTED;
  234. }
  235. if (!info->engines[dma]) {
  236. pcilib_error("The DMA engine (%i) is not supported by device", dma);
  237. return PCILIB_ERROR_NOTAVAILABLE;
  238. }
  239. if (info->engines[dma]->direction&PCILIB_DMA_TO_DEVICE == 0) {
  240. pcilib_error("The selected engine (%i) is C2S-only and does not support writes", dma);
  241. return PCILIB_ERROR_NOTSUPPORTED;
  242. }
  243. return ctx->model_info.dma_api->push(ctx->dma_ctx, dma, addr, size, flags, timeout, buf, written);
  244. }
  245. int pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *written_bytes) {
  246. return pcilib_push_dma(ctx, dma, addr, size, PCILIB_DMA_FLAG_EOP|PCILIB_DMA_FLAG_WAIT, PCILIB_DMA_TIMEOUT, buf, written_bytes);
  247. }
  248. 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) {
  249. int err;
  250. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  251. if (!info) {
  252. pcilib_error("DMA is not supported by the device");
  253. return 0;
  254. }
  255. if (!ctx->model_info.dma_api) {
  256. pcilib_error("DMA Engine is not configured in the current model");
  257. return -1;
  258. }
  259. if (!ctx->model_info.dma_api->benchmark) {
  260. pcilib_error("The DMA benchmark is not supported by configured DMA engine");
  261. return -1;
  262. }
  263. if (!info->engines[dma]) {
  264. pcilib_error("The DMA engine (%i) is not supported by device", dma);
  265. return -1;
  266. }
  267. return ctx->model_info.dma_api->benchmark(ctx->dma_ctx, dma, addr, size, iterations, direction);
  268. }
  269. 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) {
  270. int err;
  271. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  272. if (!info) {
  273. pcilib_error("DMA is not supported by the device");
  274. return 0;
  275. }
  276. if (!ctx->model_info.dma_api) {
  277. pcilib_error("DMA Engine is not configured in the current model");
  278. return -1;
  279. }
  280. if (!ctx->model_info.dma_api->status) {
  281. memset(status, 0, sizeof(pcilib_dma_engine_status_t));
  282. return -1;
  283. }
  284. if (!info->engines[dma]) {
  285. pcilib_error("The DMA engine (%i) is not supported by device", dma);
  286. return -1;
  287. }
  288. return ctx->model_info.dma_api->status(ctx->dma_ctx, dma, status, n_buffers, buffers);
  289. }