ipe.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. #define _PCILIB_DMA_IPE_C
  2. #define _BSD_SOURCE
  3. #define _DEFAULT_SOURCE
  4. #define _POSIX_C_SOURCE 199309L
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <unistd.h>
  9. #include <sched.h>
  10. #include <time.h>
  11. #include <sys/time.h>
  12. #include <arpa/inet.h>
  13. #include "pci.h"
  14. #include "pcilib.h"
  15. #include "error.h"
  16. #include "tools.h"
  17. #include "debug.h"
  18. #include "bar.h"
  19. #include "ipe.h"
  20. #include "ipe_private.h"
  21. pcilib_dma_context_t *dma_ipe_init(pcilib_t *pcilib, const char *model, const void *arg) {
  22. int err = 0;
  23. pcilib_register_value_t version_value;
  24. // const pcilib_model_description_t *model_info = pcilib_get_model_description(pcilib);
  25. ipe_dma_t *ctx = malloc(sizeof(ipe_dma_t));
  26. if (ctx) {
  27. memset(ctx, 0, sizeof(ipe_dma_t));
  28. ctx->dmactx.pcilib = pcilib;
  29. pcilib_register_bank_t dma_bankc = pcilib_find_register_bank_by_addr(pcilib, PCILIB_REGISTER_BANK_DMACONF);
  30. pcilib_register_bank_t dma_bank0 = pcilib_find_register_bank_by_addr(pcilib, PCILIB_REGISTER_BANK_DMA0);
  31. pcilib_register_bank_t dma_bank1 = pcilib_find_register_bank_by_addr(pcilib, PCILIB_REGISTER_BANK_DMA1);
  32. if ((dma_bankc == PCILIB_REGISTER_BANK_INVALID)||(dma_bank0 == PCILIB_REGISTER_BANK_INVALID)||(dma_bank1 == PCILIB_REGISTER_BANK_INVALID)) {
  33. free(ctx);
  34. pcilib_error("DMA Register Bank could not be found");
  35. return NULL;
  36. }
  37. ctx->base_addr[0] = (void*)pcilib_resolve_bank_address_by_id(pcilib, 0, dma_bank0);
  38. ctx->base_addr[1] = (void*)pcilib_resolve_bank_address_by_id(pcilib, 0, dma_bank1);
  39. ctx->base_addr[2] = (void*)pcilib_resolve_bank_address_by_id(pcilib, 0, dma_bankc);
  40. RD(IPEDMA_REG_VERSION, version_value);
  41. ctx->version = IPEDMA_VERSION(version_value);
  42. if ((model)&&(!strcasecmp(model, "ipecamera"))) {
  43. ctx->gen = 2;
  44. } else {
  45. if (IPEDMA_GENERATION(version_value) > 2) {
  46. ctx->gen = 3;
  47. } else {
  48. ctx->gen = 2;
  49. }
  50. err = pcilib_add_registers(pcilib, PCILIB_MODEL_MODIFICATON_FLAGS_DEFAULT, 0, ipe_dma_app_registers, NULL);
  51. }
  52. if (ctx->gen > 2) {
  53. ctx->mode64 = 1;
  54. ctx->addr64 = 1;
  55. #ifdef IPEDMA_STREAMING_MODE
  56. if (IPEDMA_STREAMING(version_value)) ctx->streaming = 1;
  57. #endif /* IPEDMA_STREAMING_MODE */
  58. ctx->reg_last_read = IPEDMA_REG3_LAST_READ;
  59. if (!err)
  60. err = pcilib_add_registers(pcilib, PCILIB_MODEL_MODIFICATON_FLAGS_DEFAULT, 0, ipe_dma_v3_registers, NULL);
  61. } else {
  62. #ifdef IPEDMA_ENFORCE_64BIT_MODE
  63. // According to Lorenzo, some gen2 boards have problems with 64-bit addressing. Therefore, we only enable it for gen3 boards unless enforced
  64. ctx->mode64 = 1;
  65. #endif /* IPEDMA_ENFORCE_64BIT_MODE */
  66. ctx->addr64 = 0;
  67. ctx->streaming = 0;
  68. ctx->reg_last_read = IPEDMA_REG2_LAST_READ;
  69. if (!err)
  70. err = pcilib_add_registers(pcilib, PCILIB_MODEL_MODIFICATON_FLAGS_DEFAULT, 0, ipe_dma_v2_registers, NULL);
  71. }
  72. pcilib_info("IPEDMA gen%lu version %lu (64-bit mode: %u, 64-bit addressing: %u, streaming: %u)", ctx->gen, ctx->version, ctx->mode64, ctx->addr64, ctx->streaming);
  73. if (err) {
  74. free(ctx);
  75. pcilib_error("Error (%i) registering firmware-dependent IPEDMA registers", err);
  76. return NULL;
  77. }
  78. }
  79. return (pcilib_dma_context_t*)ctx;
  80. }
  81. void dma_ipe_free(pcilib_dma_context_t *vctx) {
  82. ipe_dma_t *ctx = (ipe_dma_t*)vctx;
  83. if (ctx) {
  84. dma_ipe_stop(vctx, PCILIB_DMA_ENGINE_ALL, PCILIB_DMA_FLAGS_DEFAULT);
  85. free(ctx);
  86. }
  87. }
  88. static void dma_ipe_disable(ipe_dma_t *ctx) {
  89. // Disable DMA
  90. WR(IPEDMA_REG_CONTROL, 0x0);
  91. usleep(IPEDMA_RESET_DELAY);
  92. // Reset DMA engine
  93. WR(IPEDMA_REG_RESET, 0x1);
  94. usleep(IPEDMA_RESET_DELAY);
  95. WR(IPEDMA_REG_RESET, 0x0);
  96. usleep(IPEDMA_RESET_DELAY);
  97. // Reseting configured DMA pages
  98. if (ctx->gen < 3) {
  99. WR(IPEDMA_REG2_PAGE_COUNT, 0);
  100. }
  101. usleep(IPEDMA_RESET_DELAY);
  102. }
  103. int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
  104. int err;
  105. int mask = 32;
  106. size_t i, num_pages;
  107. ipe_dma_t *ctx = (ipe_dma_t*)vctx;
  108. pcilib_kmem_handle_t *desc = NULL;
  109. pcilib_kmem_handle_t *pages = NULL;
  110. #ifndef IPEDMA_TLP_SIZE
  111. const pcilib_pcie_link_info_t *link_info;
  112. #endif /* ! IPEDMA_TLP_SIZE */
  113. int preserve = 0;
  114. pcilib_kmem_flags_t kflags;
  115. pcilib_kmem_reuse_state_t reuse_desc, reuse_pages;
  116. volatile void *desc_va;
  117. volatile void *last_written_addr_ptr;
  118. pcilib_register_value_t value;
  119. uintptr_t dma_region = 0;
  120. int tlp_size;
  121. uint32_t address64;
  122. if (dma == PCILIB_DMA_ENGINE_INVALID) return 0;
  123. else if (dma > 1) return PCILIB_ERROR_INVALID_BANK;
  124. if (!ctx->started) ctx->started = 1;
  125. if (flags&PCILIB_DMA_FLAG_PERSISTENT) ctx->preserve = 1;
  126. if (ctx->pages) return 0;
  127. #ifdef IPEDMA_TLP_SIZE
  128. tlp_size = IPEDMA_TLP_SIZE;
  129. #else /* IPEDMA_TLP_SIZE */
  130. link_info = pcilib_get_pcie_link_info(vctx->pcilib);
  131. if (link_info) {
  132. tlp_size = 1<<link_info->payload;
  133. # ifdef IPEDMA_MAX_TLP_SIZE
  134. if (tlp_size > IPEDMA_MAX_TLP_SIZE)
  135. tlp_size = IPEDMA_MAX_TLP_SIZE;
  136. # endif /* IPEDMA_MAX_TLP_SIZE */
  137. } else tlp_size = 128;
  138. #endif /* IPEDMA_TLP_SIZE */
  139. if (!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "dma_timeout", &value))
  140. ctx->dma_timeout = value;
  141. else
  142. ctx->dma_timeout = IPEDMA_DMA_TIMEOUT;
  143. if (!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "dma_page_size", &value)) {
  144. if (value % IPEDMA_PAGE_SIZE) {
  145. pcilib_error("Invalid DMA page size (%lu) is configured", value);
  146. return PCILIB_ERROR_INVALID_ARGUMENT;
  147. }
  148. //if ((value)&&((value / (tlp_size * IPEDMA_CORES)) > ...seems no limit...)) { ... fail ... }
  149. ctx->page_size = value;
  150. } else
  151. ctx->page_size = IPEDMA_PAGE_SIZE;
  152. if ((!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "dma_pages", &value))&&(value > 0))
  153. ctx->ring_size = value;
  154. else
  155. ctx->ring_size = IPEDMA_DMA_PAGES;
  156. if (!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "dma_region_low", &value)) {
  157. dma_region = value;
  158. if (!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "dma_region_low", &value))
  159. dma_region |= ((uintptr_t)value)<<32;
  160. }
  161. if (!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "ipedma_flags", &value))
  162. ctx->dma_flags = value;
  163. else
  164. ctx->dma_flags = 0;
  165. #ifdef IPEDMA_CONFIGURE_DMA_MASK
  166. if (ctx->addr64) mask = 64;
  167. err = pcilib_set_dma_mask(ctx->dmactx.pcilib, mask);
  168. if (err) {
  169. pcilib_error("Error (%i) configuring dma mask (%i)", err, mask);
  170. return err;
  171. }
  172. #endif /* IPEDMA_CONFIGURE_DMA_MASK */
  173. kflags = PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_EXCLUSIVE|PCILIB_KMEM_FLAG_HARDWARE|(ctx->preserve?PCILIB_KMEM_FLAG_PERSISTENT:0);
  174. desc = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_CONSISTENT, 1, IPEDMA_DESCRIPTOR_SIZE, IPEDMA_DESCRIPTOR_ALIGNMENT, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, 0x00), kflags);
  175. if (dma_region)
  176. pages = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_REGION_C2S, ctx->ring_size, ctx->page_size, dma_region, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags);
  177. else
  178. pages = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, ctx->ring_size, ctx->page_size, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags);
  179. if (!desc||!pages) {
  180. if (pages) pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, KMEM_FLAG_REUSE);
  181. if (desc) pcilib_free_kernel_memory(ctx->dmactx.pcilib, desc, KMEM_FLAG_REUSE);
  182. pcilib_error("Can't allocate required kernel memory for IPEDMA engine (%lu pages of %lu bytes + %lu byte descriptor)", ctx->ring_size, ctx->page_size, (unsigned long)IPEDMA_DESCRIPTOR_SIZE);
  183. return PCILIB_ERROR_MEMORY;
  184. }
  185. reuse_desc = pcilib_kmem_is_reused(ctx->dmactx.pcilib, desc);
  186. reuse_pages = pcilib_kmem_is_reused(ctx->dmactx.pcilib, pages);
  187. if ((reuse_pages & PCILIB_KMEM_REUSE_PARTIAL)||(reuse_desc & PCILIB_KMEM_REUSE_PARTIAL)) {
  188. dma_ipe_disable(ctx);
  189. pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, KMEM_FLAG_REUSE);
  190. pcilib_free_kernel_memory(ctx->dmactx.pcilib, desc, KMEM_FLAG_REUSE);
  191. if (((flags&PCILIB_DMA_FLAG_STOP) == 0)||(dma_region)) {
  192. pcilib_error("Inconsistent DMA buffers are found (buffers are only partially re-used). This is very wrong, please stop DMA engine and correct configuration...");
  193. return PCILIB_ERROR_INVALID_STATE;
  194. }
  195. pcilib_warning("Inconsistent DMA buffers are found (buffers are only partially re-used), reinitializing...");
  196. desc = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_CONSISTENT, 1, IPEDMA_DESCRIPTOR_SIZE, IPEDMA_DESCRIPTOR_ALIGNMENT, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, 0x00), kflags|PCILIB_KMEM_FLAG_MASS);
  197. pages = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, ctx->ring_size, ctx->page_size, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags|PCILIB_KMEM_FLAG_MASS);
  198. if (!desc||!pages) {
  199. if (pages) pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, KMEM_FLAG_REUSE);
  200. if (desc) pcilib_free_kernel_memory(ctx->dmactx.pcilib, desc, KMEM_FLAG_REUSE);
  201. return PCILIB_ERROR_MEMORY;
  202. }
  203. } else if (reuse_desc != reuse_pages) {
  204. pcilib_warning("Inconsistent DMA buffers (modes of ring and page buffers does not match), reinitializing....");
  205. } else if (reuse_desc & PCILIB_KMEM_REUSE_REUSED) {
  206. if ((reuse_desc & PCILIB_KMEM_REUSE_PERSISTENT) == 0) pcilib_warning("Lost DMA buffers are found (non-persistent mode), reinitializing...");
  207. else if ((reuse_desc & PCILIB_KMEM_REUSE_HARDWARE) == 0) pcilib_warning("Lost DMA buffers are found (missing HW reference), reinitializing...");
  208. else {
  209. if (ctx->streaming)
  210. preserve = 1;
  211. else {
  212. RD(IPEDMA_REG2_PAGE_COUNT, value);
  213. if (value != ctx->ring_size)
  214. pcilib_warning("Inconsistent DMA buffers are found (Number of allocated buffers (%lu) does not match current request (%lu)), reinitializing...", value + 1, IPEDMA_DMA_PAGES);
  215. else
  216. preserve = 1;
  217. }
  218. }
  219. }
  220. desc_va = pcilib_kmem_get_ua(ctx->dmactx.pcilib, desc);
  221. if (ctx->addr64) last_written_addr_ptr = desc_va + 2 * sizeof(uint32_t);
  222. else if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
  223. else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
  224. // get page size if default size was used
  225. if (!ctx->page_size) {
  226. ctx->page_size = pcilib_kmem_get_block_size(ctx->dmactx.pcilib, pages, 0);
  227. }
  228. if (preserve) {
  229. ctx->reused = 1;
  230. ctx->preserve = 1;
  231. // Detect the current state of DMA engine
  232. RD(ctx->reg_last_read, value);
  233. // Numbered from 1 in FPGA
  234. # ifdef IPEDMA_BUG_LAST_READ
  235. if (value == ctx->ring_size)
  236. value = 0;
  237. # else /* IPEDMA_BUG_LAST_READ */
  238. value--;
  239. # endif /* IPEDMA_BUG_LAST_READ */
  240. ctx->last_read = value;
  241. } else {
  242. ctx->reused = 0;
  243. dma_ipe_disable(ctx);
  244. // Verify PCIe link status
  245. RD(IPEDMA_REG_RESET, value);
  246. if ((value != 0x14031700)&&(value != 0x14021700))
  247. pcilib_warning("PCIe is not ready, code is %lx", value);
  248. // Enable 64 bit addressing and configure TLP and PACKET sizes (40 bit mode can be used with big pre-allocated buffers later)
  249. if (ctx->mode64) address64 = 0x8000 | (0<<24);
  250. else address64 = 0;
  251. WR(IPEDMA_REG_TLP_SIZE, address64 | (tlp_size>>2));
  252. WR(IPEDMA_REG_TLP_COUNT, ctx->page_size / (tlp_size * IPEDMA_CORES));
  253. // Setting progress register threshold
  254. WR(IPEDMA_REG_UPDATE_THRESHOLD, IPEDMA_DMA_PROGRESS_THRESHOLD);
  255. // Reseting configured DMA pages
  256. if (ctx->gen < 3) {
  257. WR(IPEDMA_REG2_PAGE_COUNT, 0);
  258. }
  259. // Setting current read position and configuring progress register
  260. #ifdef IPEDMA_BUG_LAST_READ
  261. WR(ctx->reg_last_read, ctx->ring_size - 1);
  262. #else /* IPEDMA_BUG_LAST_READ */
  263. WR(ctx->reg_last_read, ctx->ring_size);
  264. #endif /* IPEDMA_BUG_LAST_READ */
  265. // Instructing DMA engine that writting should start from the first DMA page
  266. if (ctx->addr64) {
  267. WR64(IPEDMA_REG3_UPDATE_ADDR, pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, desc, 0));
  268. *(uint64_t*)last_written_addr_ptr = 0;
  269. } else {
  270. WR(IPEDMA_REG2_UPDATE_ADDR, pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, desc, 0));
  271. *(uint32_t*)last_written_addr_ptr = 0;
  272. }
  273. // In ring buffer mode, the hardware taking care to preserve an empty buffer to help distinguish between
  274. // completely empty and completely full cases. In streaming mode, it is our responsibility to track this
  275. // information. Therefore, we always keep the last buffer free
  276. num_pages = ctx->ring_size;
  277. if (ctx->streaming) num_pages--;
  278. for (i = 0; i < num_pages; i++) {
  279. uintptr_t bus_addr_check, bus_addr = pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, pages, i);
  280. if (ctx->addr64) {
  281. WR64(IPEDMA_REG3_PAGE_ADDR, bus_addr);
  282. } else {
  283. WR(IPEDMA_REG2_PAGE_ADDR, bus_addr);
  284. }
  285. if (bus_addr%4096) printf("Bad address %lu: %lx\n", i, bus_addr);
  286. if ((!ctx->addr64)&&(!ctx->streaming)) {
  287. RD(IPEDMA_REG2_PAGE_ADDR, bus_addr_check);
  288. if (bus_addr_check != bus_addr) {
  289. pcilib_error("Written (%x) and read (%x) bus addresses does not match\n", bus_addr, bus_addr_check);
  290. }
  291. }
  292. usleep(IPEDMA_ADD_PAGE_DELAY);
  293. }
  294. // Enable DMA
  295. WR(IPEDMA_REG_CONTROL, 0x1);
  296. ctx->last_read = ctx->ring_size - 1;
  297. }
  298. ctx->last_read_addr = pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, pages, ctx->last_read);
  299. ctx->desc = desc;
  300. ctx->pages = pages;
  301. return 0;
  302. }
  303. int dma_ipe_stop(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
  304. pcilib_kmem_flags_t kflags;
  305. ipe_dma_t *ctx = (ipe_dma_t*)vctx;
  306. if (!ctx->started) return 0;
  307. if ((dma != PCILIB_DMA_ENGINE_INVALID)&&(dma > 1)) return PCILIB_ERROR_INVALID_BANK;
  308. // ignoring previous setting if flag specified
  309. if (flags&PCILIB_DMA_FLAG_PERSISTENT) {
  310. ctx->preserve = 0;
  311. }
  312. if (ctx->preserve) {
  313. kflags = PCILIB_KMEM_FLAG_REUSE;
  314. } else {
  315. kflags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT;
  316. ctx->started = 0;
  317. dma_ipe_disable(ctx);
  318. }
  319. // Clean buffers
  320. if (ctx->desc) {
  321. pcilib_free_kernel_memory(ctx->dmactx.pcilib, ctx->desc, kflags);
  322. ctx->desc = NULL;
  323. }
  324. if (ctx->pages) {
  325. pcilib_free_kernel_memory(ctx->dmactx.pcilib, ctx->pages, kflags);
  326. ctx->pages = NULL;
  327. }
  328. return 0;
  329. }
  330. static size_t dma_ipe_find_buffer_by_bus_addr(ipe_dma_t *ctx, uintptr_t bus_addr) {
  331. size_t i;
  332. for (i = 0; i < ctx->ring_size; i++) {
  333. uintptr_t buf_addr = pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, ctx->pages, i);
  334. if (bus_addr == buf_addr)
  335. return i;
  336. }
  337. return (size_t)-1;
  338. }
  339. int dma_ipe_get_status(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) {
  340. size_t i;
  341. ipe_dma_t *ctx = (ipe_dma_t*)vctx;
  342. void *desc_va = (void*)pcilib_kmem_get_ua(ctx->dmactx.pcilib, ctx->desc);
  343. volatile void *last_written_addr_ptr;
  344. uint64_t last_written_addr;
  345. if (!status) return -1;
  346. if (ctx->addr64) {
  347. last_written_addr_ptr = desc_va + 2 * sizeof(uint32_t);
  348. last_written_addr = *(uint64_t*)last_written_addr_ptr;
  349. } else {
  350. if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
  351. else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
  352. last_written_addr = *(uint32_t*)last_written_addr_ptr;
  353. }
  354. pcilib_debug(DMA, "Current DMA status - last read: %4u, last_read_addr: %4u (0x%x), last_written: %4lu (0x%lx)", ctx->last_read,
  355. dma_ipe_find_buffer_by_bus_addr(ctx, ctx->last_read_addr), ctx->last_read_addr,
  356. dma_ipe_find_buffer_by_bus_addr(ctx, last_written_addr), last_written_addr
  357. );
  358. status->started = ctx->started;
  359. status->ring_size = ctx->ring_size;
  360. status->buffer_size = ctx->page_size;
  361. status->written_buffers = 0;
  362. status->written_bytes = 0;
  363. // For simplicity, we keep last_read here, and fix in the end
  364. status->ring_tail = ctx->last_read;
  365. status->ring_head = dma_ipe_find_buffer_by_bus_addr(ctx, last_written_addr);
  366. if (status->ring_head == (size_t)-1) {
  367. if (last_written_addr) {
  368. pcilib_warning("DMA is in unknown state, last_written_addr does not correspond any of available buffers");
  369. return PCILIB_ERROR_FAILED;
  370. }
  371. status->ring_head = 0;
  372. status->ring_tail = 0;
  373. }
  374. if (n_buffers > ctx->ring_size) n_buffers = ctx->ring_size;
  375. if (buffers)
  376. memset(buffers, 0, n_buffers * sizeof(pcilib_dma_buffer_status_t));
  377. if (status->ring_head >= status->ring_tail) {
  378. for (i = status->ring_tail + 1; i <= status->ring_head; i++) {
  379. status->written_buffers++;
  380. status->written_bytes += ctx->page_size;
  381. if ((buffers)&&(i < n_buffers)) {
  382. buffers[i].used = 1;
  383. buffers[i].size = ctx->page_size;
  384. buffers[i].first = 1;
  385. buffers[i].last = 1;
  386. }
  387. }
  388. } else {
  389. for (i = 0; i <= status->ring_head; i++) {
  390. status->written_buffers++;
  391. status->written_bytes += ctx->page_size;
  392. if ((buffers)&&(i < n_buffers)) {
  393. buffers[i].used = 1;
  394. buffers[i].size = ctx->page_size;
  395. buffers[i].first = 1;
  396. buffers[i].last = 1;
  397. }
  398. }
  399. for (i = status->ring_tail + 1; i < status->ring_size; i++) {
  400. status->written_buffers++;
  401. status->written_bytes += ctx->page_size;
  402. if ((buffers)&&(i < n_buffers)) {
  403. buffers[i].used = 1;
  404. buffers[i].size = ctx->page_size;
  405. buffers[i].first = 1;
  406. buffers[i].last = 1;
  407. }
  408. }
  409. }
  410. // We actually keep last_read in the ring_tail, so need to increase
  411. if (status->ring_tail != status->ring_head) {
  412. status->ring_tail++;
  413. if (status->ring_tail == status->ring_size) status->ring_tail = 0;
  414. }
  415. return 0;
  416. }
  417. int dma_ipe_stream_read(pcilib_dma_context_t *vctx, 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) {
  418. int err, ret = PCILIB_STREAMING_REQ_PACKET;
  419. pcilib_timeout_t wait = 0;
  420. struct timeval start, cur;
  421. volatile void *desc_va;
  422. volatile void *last_written_addr_ptr;
  423. // uint32_t empty_detected_dummy = 0;
  424. volatile uint32_t *empty_detected_ptr;
  425. pcilib_dma_flags_t packet_flags = PCILIB_DMA_FLAG_EOP;
  426. size_t nodata_sleep;
  427. struct timespec sleep_ts = {0};
  428. size_t cur_read;
  429. ipe_dma_t *ctx = (ipe_dma_t*)vctx;
  430. err = dma_ipe_start(vctx, dma, PCILIB_DMA_FLAGS_DEFAULT);
  431. if (err) return err;
  432. desc_va = (void*)pcilib_kmem_get_ua(ctx->dmactx.pcilib, ctx->desc);
  433. if (ctx->addr64) {
  434. last_written_addr_ptr = desc_va + 2 * sizeof(uint32_t);
  435. empty_detected_ptr = desc_va + sizeof(uint32_t);
  436. // empty_detected_ptr = &empty_detected_dummy;
  437. } else {
  438. if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
  439. else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
  440. empty_detected_ptr = NULL; // Not properly supported
  441. // empty_detected_ptr = last_written_addr_ptr - 2;
  442. }
  443. switch (sched_getscheduler(0)) {
  444. case SCHED_FIFO:
  445. case SCHED_RR:
  446. if (ctx->dma_flags&IPEDMA_FLAG_NOSLEEP)
  447. nodata_sleep = 0;
  448. else
  449. nodata_sleep = IPEDMA_NODATA_SLEEP;
  450. break;
  451. default:
  452. pcilib_info_once("Streaming DMA data using non real-time thread (may cause extra CPU load)", errno);
  453. nodata_sleep = 0;
  454. }
  455. do {
  456. switch (ret&PCILIB_STREAMING_TIMEOUT_MASK) {
  457. case PCILIB_STREAMING_CONTINUE:
  458. // Hardware indicates that there is no more data pending and we can safely stop if there is no data in the kernel buffers already
  459. #ifdef IPEDMA_SUPPORT_EMPTY_DETECTED
  460. if ((empty_detected_ptr)&&(*empty_detected_ptr))
  461. wait = 0;
  462. else
  463. #endif /* IPEDMA_SUPPORT_EMPTY_DETECTED */
  464. wait = ctx->dma_timeout;
  465. break;
  466. case PCILIB_STREAMING_WAIT:
  467. wait = (timeout > ctx->dma_timeout)?timeout:ctx->dma_timeout;
  468. break;
  469. // case PCILIB_STREAMING_CHECK: wait = 0; break;
  470. }
  471. pcilib_debug(DMA, "Waiting for data in %4u - last_read: %4u, last_read_addr: %4u (0x%08x), last_written: %4u (0x%08x)", ctx->last_read + 1, ctx->last_read,
  472. dma_ipe_find_buffer_by_bus_addr(ctx, ctx->last_read_addr), ctx->last_read_addr,
  473. dma_ipe_find_buffer_by_bus_addr(ctx, DEREF(last_written_addr_ptr)), DEREF(last_written_addr_ptr)
  474. );
  475. gettimeofday(&start, NULL);
  476. memcpy(&cur, &start, sizeof(struct timeval));
  477. while (((DEREF(last_written_addr_ptr) == 0)||(ctx->last_read_addr == DEREF(last_written_addr_ptr)))&&((wait == PCILIB_TIMEOUT_INFINITE)||(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < wait))) {
  478. if (nodata_sleep) {
  479. sleep_ts.tv_nsec = nodata_sleep;
  480. nanosleep(&sleep_ts, NULL);
  481. }
  482. #ifdef IPEDMA_SUPPORT_EMPTY_DETECTED
  483. if ((ret != PCILIB_STREAMING_REQ_PACKET)&&(empty_detected_ptr)&&(*empty_detected_ptr)) break;
  484. #endif /* IPEDMA_SUPPORT_EMPTY_DETECTED */
  485. gettimeofday(&cur, NULL);
  486. }
  487. // Failing out if we exited on timeout
  488. if ((ctx->last_read_addr == DEREF(last_written_addr_ptr))||(DEREF(last_written_addr_ptr) == 0)) {
  489. #ifdef IPEDMA_SUPPORT_EMPTY_DETECTED
  490. # ifdef PCILIB_DEBUG_DMA
  491. if ((wait)&&(empty_detected_ptr)&&(DEREF(last_written_addr_ptr))&&(!*empty_detected_ptr))
  492. pcilib_debug(DMA, "The empty_detected flag is not set, but no data arrived within %lu us", wait);
  493. # endif /* PCILIB_DEBUG_DMA */
  494. #endif /* IPEDMA_SUPPORT_EMPTY_DETECTED */
  495. return (ret&PCILIB_STREAMING_FAIL)?PCILIB_ERROR_TIMEOUT:0;
  496. }
  497. // Getting next page to read
  498. cur_read = ctx->last_read + 1;
  499. if (cur_read == ctx->ring_size) cur_read = 0;
  500. pcilib_debug(DMA, "Got buffer %4u - last read: %4u, last_read_addr: %4u (0x%x), last_written: %4u (0x%x)", cur_read, ctx->last_read,
  501. dma_ipe_find_buffer_by_bus_addr(ctx, ctx->last_read_addr), ctx->last_read_addr,
  502. dma_ipe_find_buffer_by_bus_addr(ctx, DEREF(last_written_addr_ptr)), DEREF(last_written_addr_ptr)
  503. );
  504. #ifdef IPEDMA_DETECT_PACKETS
  505. if ((empty_detected_ptr)&&(*empty_detected_ptr)&&(pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, ctx->pages, cur_read) == DEREF(last_written_addr_ptr))) packet_flags = PCILIB_DMA_FLAG_EOP;
  506. else packet_flags = 0;
  507. #endif /* IPEDMA_DETECT_PACKETS */
  508. if ((ctx->dma_flags&IPEDMA_FLAG_NOSYNC) == 0)
  509. pcilib_kmem_sync_block(ctx->dmactx.pcilib, ctx->pages, PCILIB_KMEM_SYNC_FROMDEVICE, cur_read);
  510. void *buf = (void*)pcilib_kmem_get_block_ua(ctx->dmactx.pcilib, ctx->pages, cur_read);
  511. ret = cb(cbattr, packet_flags, ctx->page_size, buf);
  512. if (ret < 0) return -ret;
  513. // We don't need this because hardware does not intend to read anything from the memory
  514. //pcilib_kmem_sync_block(ctx->dmactx.pcilib, ctx->pages, PCILIB_KMEM_SYNC_TODEVICE, cur_read);
  515. // Return buffer into the DMA pool when processed
  516. if (ctx->streaming) {
  517. size_t last_free;
  518. // We always keep 1 buffer free to distinguish between completely full and empty cases
  519. if (cur_read) last_free = cur_read - 1;
  520. else last_free = ctx->ring_size - 1;
  521. uintptr_t buf_ba = pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, ctx->pages, last_free);
  522. if (ctx->addr64) {
  523. WR64(IPEDMA_REG3_PAGE_ADDR, buf_ba);
  524. } else {
  525. WR(IPEDMA_REG2_PAGE_ADDR, buf_ba);
  526. }
  527. # ifdef IPEDMA_STREAMING_CHECKS
  528. pcilib_register_value_t streaming_status;
  529. RD(IPEDMA_REG_STREAMING_STATUS, streaming_status);
  530. if (streaming_status)
  531. pcilib_error("Invalid status (0x%lx) adding a DMA buffer into the queue", streaming_status);
  532. # endif /* IPEDMA_STREAMING_MODE */
  533. }
  534. // Numbered from 1
  535. #ifdef IPEDMA_BUG_LAST_READ
  536. WR(ctx->reg_last_read, cur_read?cur_read:ctx->ring_size);
  537. #else /* IPEDMA_BUG_LAST_READ */
  538. WR(ctx->reg_last_read, cur_read + 1);
  539. #endif /* IPEDMA_BUG_LAST_READ */
  540. pcilib_debug(DMA, "Buffer returned %4u - last read: %4u, last_read_addr: %4u (0x%x), last_written: %4u (0x%x)", cur_read, ctx->last_read,
  541. dma_ipe_find_buffer_by_bus_addr(ctx, ctx->last_read_addr), ctx->last_read_addr,
  542. dma_ipe_find_buffer_by_bus_addr(ctx, DEREF(last_written_addr_ptr)), DEREF(last_written_addr_ptr)
  543. );
  544. ctx->last_read = cur_read;
  545. ctx->last_read_addr = pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, ctx->pages, cur_read);
  546. } while (ret);
  547. return 0;
  548. }