dma.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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 <errno.h>
  13. #include <assert.h>
  14. #include "error.h"
  15. #include "pcilib.h"
  16. #include "pci.h"
  17. #include "dma.h"
  18. const pcilib_dma_info_t *pcilib_get_dma_info(pcilib_t *ctx) {
  19. if (!ctx->dma_ctx) {
  20. pcilib_model_t model = pcilib_get_model(ctx);
  21. pcilib_dma_api_description_t *api = pcilib_model[model].dma_api;
  22. if ((api)&&(api->init)) {
  23. pcilib_map_register_space(ctx);
  24. ctx->dma_ctx = api->init(ctx);
  25. }
  26. if (!ctx->dma_ctx) return NULL;
  27. }
  28. return &ctx->dma_info;
  29. }
  30. pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_engine_addr_t dma) {
  31. pcilib_dma_engine_t i;
  32. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  33. if (!info) {
  34. pcilib_error("DMA Engine is not configured in the current model");
  35. return PCILIB_ERROR_NOTSUPPORTED;
  36. }
  37. for (i = 0; info->engines[i]; i++) {
  38. if ((info->engines[i]->addr == dma)&&((info->engines[i]->direction&direction)==direction)) break;
  39. }
  40. if (info->engines[i]) return i;
  41. return PCILIB_DMA_INVALID;
  42. }
  43. int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_engine_t engine, pcilib_dma_engine_description_t *desc) {
  44. ctx->dma_info.engines[engine] = desc;
  45. }
  46. typedef struct {
  47. size_t size;
  48. void *data;
  49. size_t pos;
  50. } pcilib_dma_read_callback_context_t;
  51. static int pcilib_dma_read_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
  52. pcilib_dma_read_callback_context_t *ctx = (pcilib_dma_read_callback_context_t*)arg;
  53. if (ctx->pos + bufsize > ctx->size) {
  54. pcilib_error("Buffer size (%li) is not large enough for DMA packet, at least %li bytes is required", ctx->size, ctx->pos + bufsize);
  55. return PCILIB_ERROR_INVALID_DATA;
  56. }
  57. memcpy(ctx->data + ctx->pos, buf, bufsize);
  58. ctx->pos += bufsize;
  59. if (flags & PCILIB_DMA_FLAG_EOP) return 0;
  60. return 1;
  61. }
  62. static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
  63. return 1;
  64. }
  65. size_t pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, pcilib_dma_callback_t cb, void *cbattr) {
  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 0;
  71. }
  72. if (!ctx->model_info.dma_api) {
  73. pcilib_error("DMA Engine is not configured in the current model");
  74. return 0;
  75. }
  76. if (!ctx->model_info.dma_api->stream) {
  77. pcilib_error("The DMA read is not supported by configured DMA engine");
  78. return 0;
  79. }
  80. if (!info->engines[dma]) {
  81. pcilib_error("The DMA engine (%i) is not supported by device", dma);
  82. return 0;
  83. }
  84. if (info->engines[dma]->direction&PCILIB_DMA_FROM_DEVICE == 0) {
  85. pcilib_error("The selected engine (%i) is S2C-only and does not support reading", dma);
  86. return 0;
  87. }
  88. return ctx->model_info.dma_api->stream(ctx->dma_ctx, dma, addr, size, flags, timeout, cb, cbattr);
  89. }
  90. size_t pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf) {
  91. int err;
  92. pcilib_dma_read_callback_context_t opts = {
  93. size, buf, 0
  94. };
  95. return pcilib_stream_dma(ctx, dma, addr, size, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_read_callback, &opts);
  96. }
  97. int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma) {
  98. size_t skipped;
  99. do {
  100. // IMMEDIATE timeout is not working properly, so default is set
  101. skipped = pcilib_stream_dma(ctx, dma, 0, 0, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_skip_callback, NULL);
  102. } while (skipped > 0);
  103. return 0;
  104. }
  105. size_t pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, void *buf) {
  106. int err;
  107. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  108. if (!info) {
  109. pcilib_error("DMA is not supported by the device");
  110. return 0;
  111. }
  112. if (!ctx->model_info.dma_api) {
  113. pcilib_error("DMA Engine is not configured in the current model");
  114. return 0;
  115. }
  116. if (!ctx->model_info.dma_api->push) {
  117. pcilib_error("The DMA write is not supported by configured DMA engine");
  118. return 0;
  119. }
  120. if (!info->engines[dma]) {
  121. pcilib_error("The DMA engine (%i) is not supported by device", dma);
  122. return 0;
  123. }
  124. if (info->engines[dma]->direction&PCILIB_DMA_TO_DEVICE == 0) {
  125. pcilib_error("The selected engine (%i) is C2S-only and does not support writes", dma);
  126. return 0;
  127. }
  128. return ctx->model_info.dma_api->push(ctx->dma_ctx, dma, addr, size, flags, timeout, buf);
  129. }
  130. size_t pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf) {
  131. return pcilib_push_dma(ctx, dma, addr, size, PCILIB_DMA_FLAG_EOP, PCILIB_DMA_TIMEOUT, buf);
  132. }
  133. 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) {
  134. int err;
  135. const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
  136. if (!info) {
  137. pcilib_error("DMA is not supported by the device");
  138. return 0;
  139. }
  140. if (!ctx->model_info.dma_api) {
  141. pcilib_error("DMA Engine is not configured in the current model");
  142. return -1;
  143. }
  144. if (!ctx->model_info.dma_api->benchmark) {
  145. pcilib_error("The DMA benchmark is not supported by configured DMA engine");
  146. return -1;
  147. }
  148. if (!info->engines[dma]) {
  149. pcilib_error("The DMA engine (%i) is not supported by device", dma);
  150. return -1;
  151. }
  152. return ctx->model_info.dma_api->benchmark(ctx->dma_ctx, dma, addr, size, iterations, direction);
  153. }