nwl.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. #define _PCILIB_DMA_NWL_C
  2. #define _BSD_SOURCE
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7. #include <sys/time.h>
  8. #include "pci.h"
  9. #include "dma.h"
  10. #include "pcilib.h"
  11. #include "error.h"
  12. #include "tools.h"
  13. #include "nwl.h"
  14. #include "nwl_defines.h"
  15. #include "nwl_register.h"
  16. #define NWL_XAUI_ENGINE 0
  17. #define NWL_XRAWDATA_ENGINE 1
  18. #define NWL_FIX_EOP_FOR_BIG_PACKETS // requires precise sizes in read requests
  19. typedef struct {
  20. pcilib_dma_engine_description_t desc;
  21. char *base_addr;
  22. size_t ring_size, page_size;
  23. size_t head, tail;
  24. pcilib_kmem_handle_t *ring;
  25. pcilib_kmem_handle_t *pages;
  26. int started; // indicates if DMA buffers are initialized and reading is allowed
  27. int writting; // indicates if we are in middle of writting packet
  28. } pcilib_nwl_engine_description_t;
  29. struct nwl_dma_s {
  30. pcilib_t *pcilib;
  31. pcilib_register_bank_description_t *dma_bank;
  32. char *base_addr;
  33. pcilib_dma_engine_t n_engines;
  34. pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1];
  35. };
  36. #define nwl_read_register(var, ctx, base, reg) pcilib_datacpy(&var, base + reg, 4, 1, ctx->dma_bank->raw_endianess)
  37. #define nwl_write_register(var, ctx, base, reg) pcilib_datacpy(base + reg, &var, 4, 1, ctx->dma_bank->raw_endianess)
  38. static int nwl_add_registers(nwl_dma_t *ctx) {
  39. int err;
  40. size_t n, i, j;
  41. int length;
  42. const char *names[NWL_MAX_DMA_ENGINE_REGISTERS];
  43. uintptr_t addr[NWL_MAX_DMA_ENGINE_REGISTERS];
  44. // We don't want DMA registers
  45. if (pcilib_find_bank_by_addr(ctx->pcilib, PCILIB_REGISTER_BANK_DMA) == PCILIB_REGISTER_BANK_INVALID) return 0;
  46. err = pcilib_add_registers(ctx->pcilib, 0, nwl_dma_registers);
  47. if (err) return err;
  48. err = pcilib_add_registers(ctx->pcilib, 0, nwl_xrawdata_registers);
  49. if (err) return err;
  50. for (n = 0; nwl_dma_engine_registers[n].bits; n++) {
  51. names[n] = nwl_dma_engine_registers[n].name;
  52. addr[n] = nwl_dma_engine_registers[n].addr;
  53. }
  54. if (ctx->n_engines > 9) length = 2;
  55. else length = 1;
  56. for (i = 0; i < ctx->n_engines; i++) {
  57. for (j = 0; nwl_dma_engine_registers[j].bits; j++) {
  58. const char *direction;
  59. nwl_dma_engine_registers[j].name = nwl_dma_engine_register_names[i * NWL_MAX_DMA_ENGINE_REGISTERS + j];
  60. nwl_dma_engine_registers[j].addr = addr[j] + (ctx->engines[i].base_addr - ctx->base_addr);
  61. // printf("%lx %lx\n", (ctx->engines[i].base_addr - ctx->base_addr), nwl_dma_engine_registers[j].addr);
  62. switch (ctx->engines[i].desc.direction) {
  63. case PCILIB_DMA_FROM_DEVICE:
  64. direction = "r";
  65. break;
  66. case PCILIB_DMA_TO_DEVICE:
  67. direction = "w";
  68. break;
  69. default:
  70. direction = "";
  71. }
  72. sprintf((char*)nwl_dma_engine_registers[j].name, names[j], length, ctx->engines[i].desc.addr, direction);
  73. }
  74. err = pcilib_add_registers(ctx->pcilib, n, nwl_dma_engine_registers);
  75. if (err) return err;
  76. }
  77. for (n = 0; nwl_dma_engine_registers[n].bits; n++) {
  78. nwl_dma_engine_registers[n].name = names[n];
  79. nwl_dma_engine_registers[n].addr = addr[n];
  80. }
  81. return 0;
  82. }
  83. static int nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, char *base) {
  84. uint32_t val;
  85. info->base_addr = base;
  86. nwl_read_register(val, ctx, base, REG_DMA_ENG_CAP);
  87. if ((val & DMA_ENG_PRESENT_MASK) == 0) return PCILIB_ERROR_NOTAVAILABLE;
  88. info->desc.addr = (val & DMA_ENG_NUMBER) >> DMA_ENG_NUMBER_SHIFT;
  89. if ((info->desc.addr > PCILIB_MAX_DMA_ENGINES)||(info->desc.addr < 0)) return PCILIB_ERROR_INVALID_DATA;
  90. switch (val & DMA_ENG_DIRECTION_MASK) {
  91. case DMA_ENG_C2S:
  92. info->desc.direction = PCILIB_DMA_FROM_DEVICE;
  93. break;
  94. default:
  95. info->desc.direction = PCILIB_DMA_TO_DEVICE;
  96. }
  97. switch (val & DMA_ENG_TYPE_MASK) {
  98. case DMA_ENG_BLOCK:
  99. info->desc.type = PCILIB_DMA_TYPE_BLOCK;
  100. break;
  101. case DMA_ENG_PACKET:
  102. info->desc.type = PCILIB_DMA_TYPE_PACKET;
  103. break;
  104. default:
  105. info->desc.type = PCILIB_DMA_TYPE_UNKNOWN;
  106. }
  107. info->desc.addr_bits = (val & DMA_ENG_BD_MAX_BC) >> DMA_ENG_BD_MAX_BC_SHIFT;
  108. return 0;
  109. }
  110. static int nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
  111. uint32_t val;
  112. struct timeval start, cur;
  113. pcilib_nwl_engine_description_t *info = ctx->engines + dma;
  114. char *base = ctx->engines[dma].base_addr;
  115. return 0;
  116. if (info->desc.addr == NWL_XRAWDATA_ENGINE) {
  117. // Stop Generators
  118. nwl_read_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
  119. val = ~(LOOPBACK|PKTCHKR|PKTGENR);
  120. nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
  121. nwl_read_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
  122. val = ~(LOOPBACK|PKTCHKR|PKTGENR);
  123. nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
  124. // Skip everything in read queue (could be we need to start and skip as well)
  125. if (info->started) pcilib_skip_dma(ctx->pcilib, dma);
  126. }
  127. // Disable IRQ
  128. nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
  129. val &= ~(DMA_ENG_INT_ENABLE);
  130. nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
  131. // Reseting
  132. val = DMA_ENG_DISABLE|DMA_ENG_USER_RESET; nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
  133. gettimeofday(&start, NULL);
  134. do {
  135. nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
  136. gettimeofday(&cur, NULL);
  137. } while ((val & (DMA_ENG_STATE_MASK|DMA_ENG_USER_RESET))&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT));
  138. if (val & (DMA_ENG_STATE_MASK|DMA_ENG_USER_RESET)) {
  139. pcilib_error("Timeout during reset of DMA engine %i", info->desc.addr);
  140. return PCILIB_ERROR_TIMEOUT;
  141. }
  142. val = DMA_ENG_RESET; nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
  143. gettimeofday(&start, NULL);
  144. do {
  145. nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
  146. gettimeofday(&cur, NULL);
  147. } while ((val & DMA_ENG_RESET)&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT));
  148. if (val & DMA_ENG_RESET) {
  149. pcilib_error("Timeout during reset of DMA engine %i", info->desc.addr);
  150. return PCILIB_ERROR_TIMEOUT;
  151. }
  152. // Acknowledge asserted engine interrupts
  153. if (val & DMA_ENG_INT_ACTIVE_MASK) {
  154. val |= DMA_ENG_ALLINT_MASK;
  155. nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
  156. }
  157. // Clean buffers
  158. if (info->ring) {
  159. pcilib_free_kernel_memory(ctx->pcilib, info->ring);
  160. info->ring = NULL;
  161. }
  162. if (info->pages) {
  163. pcilib_free_kernel_memory(ctx->pcilib, info->pages);
  164. info->pages = NULL;
  165. }
  166. info->started = 0;
  167. return 0;
  168. }
  169. pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib) {
  170. int i;
  171. int err;
  172. uint32_t val;
  173. pcilib_dma_engine_t n_engines;
  174. pcilib_model_description_t *model_info = pcilib_get_model_description(pcilib);
  175. nwl_dma_t *ctx = malloc(sizeof(nwl_dma_t));
  176. if (ctx) {
  177. memset(ctx, 0, sizeof(nwl_dma_t));
  178. ctx->pcilib = pcilib;
  179. pcilib_register_bank_t dma_bank = pcilib_find_bank_by_addr(pcilib, PCILIB_REGISTER_BANK_DMA);
  180. if (dma_bank == PCILIB_REGISTER_BANK_INVALID) {
  181. free(ctx);
  182. pcilib_error("DMA Register Bank could not be found");
  183. return NULL;
  184. }
  185. ctx->dma_bank = model_info->banks + dma_bank;
  186. ctx->base_addr = pcilib_resolve_register_address(pcilib, ctx->dma_bank->bar, ctx->dma_bank->read_addr);
  187. val = 0;
  188. nwl_read_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
  189. nwl_read_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
  190. for (i = 0, n_engines = 0; i < 2 * PCILIB_MAX_DMA_ENGINES; i++) {
  191. char *addr = ctx->base_addr + DMA_OFFSET + i * DMA_ENGINE_PER_SIZE;
  192. memset(ctx->engines + n_engines, 0, sizeof(pcilib_nwl_engine_description_t));
  193. err = nwl_read_engine_config(ctx, ctx->engines + n_engines, addr);
  194. if (!err) err = nwl_stop_engine(ctx, n_engines);
  195. if (!err) {
  196. ctx->engines[n_engines].base_addr = addr;
  197. pcilib_set_dma_engine_description(pcilib, n_engines, (pcilib_dma_engine_description_t*)(ctx->engines + n_engines));
  198. ++n_engines;
  199. }
  200. }
  201. pcilib_set_dma_engine_description(pcilib, n_engines, NULL);
  202. ctx->n_engines = n_engines;
  203. err = nwl_add_registers(ctx);
  204. if (err) {
  205. free(ctx);
  206. pcilib_error("Failed to add DMA registers");
  207. return NULL;
  208. }
  209. }
  210. return (pcilib_dma_context_t*)ctx;
  211. }
  212. void dma_nwl_free(pcilib_dma_context_t *vctx) {
  213. pcilib_dma_engine_t i;
  214. nwl_dma_t *ctx = (nwl_dma_t*)vctx;
  215. if (ctx) {
  216. for (i = 0; i < ctx->n_engines; i++) nwl_stop_engine(vctx, i);
  217. free(ctx);
  218. }
  219. }
  220. #define PCILIB_NWL_ALIGNMENT 64 // in bytes
  221. #define PCILIB_NWL_DMA_DESCRIPTOR_SIZE 64 // in bytes
  222. #define PCILIB_NWL_DMA_PAGES 512 // 1024
  223. #define NWL_RING_GET(data, offset) *(uint32_t*)(((char*)(data)) + (offset))
  224. #define NWL_RING_SET(data, offset, val) *(uint32_t*)(((char*)(data)) + (offset)) = (val)
  225. #define NWL_RING_UPDATE(data, offset, mask, val) *(uint32_t*)(((char*)(data)) + (offset)) = ((*(uint32_t*)(((char*)(data)) + (offset)))&(mask))|(val)
  226. int dma_nwl_sync_buffers(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, pcilib_kmem_handle_t *kmem) {
  227. switch (info->desc.direction) {
  228. case PCILIB_DMA_FROM_DEVICE:
  229. return pcilib_sync_kernel_memory(ctx->pcilib, kmem, PCILIB_KMEM_SYNC_FROMDEVICE);
  230. case PCILIB_DMA_TO_DEVICE:
  231. return pcilib_sync_kernel_memory(ctx->pcilib, kmem, PCILIB_KMEM_SYNC_TODEVICE);
  232. }
  233. return 0;
  234. }
  235. int dma_nwl_allocate_engine_buffers(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info) {
  236. int err = 0;
  237. int i;
  238. uint32_t val;
  239. uint32_t buf_sz;
  240. uint64_t buf_pa;
  241. char *base = info->base_addr;
  242. if (info->pages) return 0;
  243. pcilib_kmem_handle_t *ring = pcilib_alloc_kernel_memory(ctx->pcilib, PCILIB_KMEM_TYPE_CONSISTENT, 1, PCILIB_NWL_DMA_PAGES * PCILIB_NWL_DMA_DESCRIPTOR_SIZE, PCILIB_NWL_ALIGNMENT, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA, info->desc.addr), 0);
  244. pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->pcilib, PCILIB_KMEM_TYPE_PAGE, PCILIB_NWL_DMA_PAGES, 0, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA, info->desc.addr), 0);
  245. if ((ring)&&(pages)) err = dma_nwl_sync_buffers(ctx, info, pages);
  246. else err = PCILIB_ERROR_FAILED;
  247. if (err) {
  248. if (pages) pcilib_free_kernel_memory(ctx->pcilib, pages);
  249. if (ring) pcilib_free_kernel_memory(ctx->pcilib, ring);
  250. return err;
  251. }
  252. unsigned char *data = (unsigned char*)pcilib_kmem_get_ua(ctx->pcilib, ring);
  253. uint32_t ring_pa = pcilib_kmem_get_pa(ctx->pcilib, ring);
  254. memset(data, 0, PCILIB_NWL_DMA_PAGES * PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
  255. for (i = 0; i < PCILIB_NWL_DMA_PAGES; i++, data += PCILIB_NWL_DMA_DESCRIPTOR_SIZE) {
  256. buf_pa = pcilib_kmem_get_block_pa(ctx->pcilib, pages, i);
  257. buf_sz = pcilib_kmem_get_block_size(ctx->pcilib, pages, i);
  258. NWL_RING_SET(data, DMA_BD_NDESC_OFFSET, ring_pa + ((i + 1) % PCILIB_NWL_DMA_PAGES) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
  259. NWL_RING_SET(data, DMA_BD_BUFAL_OFFSET, buf_pa&0xFFFFFFFF);
  260. NWL_RING_SET(data, DMA_BD_BUFAH_OFFSET, buf_pa>>32);
  261. NWL_RING_SET(data, DMA_BD_BUFL_CTRL_OFFSET, buf_sz);
  262. /*
  263. if (info->desc.direction == PCILIB_DMA_TO_DEVICE) {
  264. NWL_RING_SET(data, DMA_BD_BUFL_STATUS_OFFSET, buf_sz);
  265. }
  266. */
  267. }
  268. val = ring_pa;
  269. nwl_write_register(val, ctx, base, REG_DMA_ENG_NEXT_BD);
  270. nwl_write_register(val, ctx, base, REG_SW_NEXT_BD);
  271. info->ring = ring;
  272. info->pages = pages;
  273. info->page_size = buf_sz;
  274. info->ring_size = PCILIB_NWL_DMA_PAGES;
  275. info->head = 0;
  276. info->tail = 0;
  277. return 0;
  278. }
  279. static int dma_nwl_start(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info) {
  280. int err;
  281. uint32_t ring_pa;
  282. uint32_t val;
  283. if (info->started) return 0;
  284. err = dma_nwl_allocate_engine_buffers(ctx, info);
  285. if (err) return err;
  286. ring_pa = pcilib_kmem_get_pa(ctx->pcilib, info->ring);
  287. nwl_write_register(ring_pa, ctx, info->base_addr, REG_DMA_ENG_NEXT_BD);
  288. nwl_write_register(ring_pa, ctx, info->base_addr, REG_SW_NEXT_BD);
  289. __sync_synchronize();
  290. nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_CTRL_STATUS);
  291. val |= (DMA_ENG_ENABLE);
  292. nwl_write_register(val, ctx, info->base_addr, REG_DMA_ENG_CTRL_STATUS);
  293. __sync_synchronize();
  294. if (info->desc.direction == PCILIB_DMA_FROM_DEVICE) {
  295. ring_pa += (info->ring_size - 1) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
  296. nwl_write_register(ring_pa, ctx, info->base_addr, REG_SW_NEXT_BD);
  297. // nwl_read_register(val, ctx, info->base_addr, 0x18);
  298. info->tail = 0;
  299. info->head = (info->ring_size - 1);
  300. } else {
  301. info->tail = 0;
  302. info->head = 0;
  303. }
  304. info->started = 1;
  305. return 0;
  306. }
  307. static size_t dma_nwl_clean_buffers(nwl_dma_t * ctx, pcilib_nwl_engine_description_t *info) {
  308. size_t res = 0;
  309. uint32_t status, control;
  310. unsigned char *ring = pcilib_kmem_get_ua(ctx->pcilib, info->ring);
  311. ring += info->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
  312. next_buffer:
  313. status = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET)&DMA_BD_STATUS_MASK;
  314. // control = NWL_RING_GET(ring, DMA_BD_BUFL_CTRL_OFFSET)&DMA_BD_CTRL_MASK;
  315. if (status & DMA_BD_ERROR_MASK) {
  316. pcilib_error("NWL DMA Engine reported error in ring descriptor");
  317. return (size_t)-1;
  318. }
  319. if (status & DMA_BD_SHORT_MASK) {
  320. pcilib_error("NWL DMA Engine reported short error");
  321. return (size_t)-1;
  322. }
  323. if (status & DMA_BD_COMP_MASK) {
  324. info->tail++;
  325. if (info->tail == info->ring_size) {
  326. ring -= (info->tail - 1) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
  327. info->tail = 0;
  328. } else {
  329. ring += PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
  330. }
  331. res++;
  332. if (info->tail != info->head) goto next_buffer;
  333. }
  334. // printf("====> Cleaned: %i\n", res);
  335. return res;
  336. }
  337. static size_t dma_nwl_get_next_buffer(nwl_dma_t * ctx, pcilib_nwl_engine_description_t *info, size_t n_buffers, size_t timeout) {
  338. struct timeval start, cur;
  339. size_t res, n = 0;
  340. size_t head;
  341. for (head = info->head; (((head + 1)%info->ring_size) != info->tail)&&(n < n_buffers); head++, n++);
  342. if (n == n_buffers) return info->head;
  343. gettimeofday(&start, NULL);
  344. res = dma_nwl_clean_buffers(ctx, info);
  345. if (res == (size_t)-1) return PCILIB_DMA_BUFFER_INVALID;
  346. else n += res;
  347. while (n < n_buffers) {
  348. if (timeout != PCILIB_TIMEOUT_INFINITE) {
  349. gettimeofday(&cur, NULL);
  350. if (((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) > timeout) break;
  351. }
  352. usleep (10);
  353. res = dma_nwl_clean_buffers(ctx, info);
  354. if (res == (size_t)-1) return PCILIB_DMA_BUFFER_INVALID;
  355. else if (res > 0) {
  356. gettimeofday(&start, NULL);
  357. n += res;
  358. }
  359. }
  360. if (n < n_buffers) return PCILIB_DMA_BUFFER_INVALID;
  361. return info->head;
  362. }
  363. static int dma_nwl_push_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, size_t size, int eop, size_t timeout) {
  364. int flags;
  365. uint32_t val;
  366. unsigned char *ring = pcilib_kmem_get_ua(ctx->pcilib, info->ring);
  367. uint32_t ring_pa = pcilib_kmem_get_pa(ctx->pcilib, info->ring);
  368. ring += info->head * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
  369. if (!info->writting) {
  370. flags |= DMA_BD_SOP_MASK;
  371. info->writting = 1;
  372. }
  373. if (eop) {
  374. flags |= DMA_BD_EOP_MASK;
  375. info->writting = 0;
  376. }
  377. NWL_RING_SET(ring, DMA_BD_BUFL_CTRL_OFFSET, size|flags);
  378. NWL_RING_SET(ring, DMA_BD_BUFL_STATUS_OFFSET, size);
  379. info->head++;
  380. if (info->head == info->ring_size) info->head = 0;
  381. val = ring_pa + info->head * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
  382. nwl_write_register(val, ctx, info->base_addr, REG_SW_NEXT_BD);
  383. // nwl_read_register(val, ctx, info->base_addr, 0x18);
  384. // usleep(10000);
  385. // nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_LAST_BD);
  386. // printf("Last BD(Write): %lx %lx\n", ring, val);
  387. return 0;
  388. }
  389. static size_t dma_nwl_wait_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, size_t *size, int *eop, size_t timeout) {
  390. uint32_t val;
  391. struct timeval start, cur;
  392. uint32_t status_size, status, control;
  393. // usleep(10000);
  394. unsigned char *ring = pcilib_kmem_get_ua(ctx->pcilib, info->ring);
  395. // status_size = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET);
  396. // printf("Status0: %lx\n", status_size);
  397. ring += info->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
  398. gettimeofday(&start, NULL);
  399. // printf("Waiting %li\n", info->tail);
  400. // nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_LAST_BD);
  401. // printf("Last BD(Read): %lx %lx\n", ring, val);
  402. do {
  403. status_size = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET);
  404. status = status_size & DMA_BD_STATUS_MASK;
  405. // printf("%i: %lx\n", info->tail, status_size);
  406. if (status & DMA_BD_ERROR_MASK) {
  407. pcilib_error("NWL DMA Engine reported error in ring descriptor");
  408. return (size_t)-1;
  409. }
  410. if (status & DMA_BD_COMP_MASK) {
  411. if (status & DMA_BD_EOP_MASK) *eop = 1;
  412. else *eop = 0;
  413. *size = status_size & DMA_BD_BUFL_MASK;
  414. // printf("Status: %lx\n", status_size);
  415. return info->tail;
  416. }
  417. usleep(10);
  418. gettimeofday(&cur, NULL);
  419. } while ((timeout == PCILIB_TIMEOUT_INFINITE)||(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < timeout));
  420. // printf("Final status: %lx\n", status_size);
  421. return (size_t)-1;
  422. }
  423. static int dma_nwl_return_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info) {
  424. uint32_t val;
  425. unsigned char *ring = pcilib_kmem_get_ua(ctx->pcilib, info->ring);
  426. uint32_t ring_pa = pcilib_kmem_get_pa(ctx->pcilib, info->ring);
  427. size_t bufsz = pcilib_kmem_get_block_size(ctx->pcilib, info->pages, info->tail);
  428. ring += info->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
  429. // printf("Returning: %i\n", info->tail);
  430. NWL_RING_SET(ring, DMA_BD_BUFL_CTRL_OFFSET, bufsz);
  431. NWL_RING_SET(ring, DMA_BD_BUFL_STATUS_OFFSET, 0);
  432. val = ring_pa + info->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
  433. nwl_write_register(val, ctx, info->base_addr, REG_SW_NEXT_BD);
  434. // nwl_read_register(val, ctx, info->base_addr, 0x18);
  435. info->tail++;
  436. if (info->tail == info->ring_size) info->tail = 0;
  437. }
  438. size_t dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, void *data) {
  439. int err;
  440. size_t pos;
  441. size_t bufnum;
  442. nwl_dma_t *ctx = (nwl_dma_t*)vctx;
  443. pcilib_nwl_engine_description_t *info = ctx->engines + dma;
  444. err = dma_nwl_start(ctx, info);
  445. if (err) return 0;
  446. for (pos = 0; pos < size; pos += info->page_size) {
  447. int block_size = min2(size - pos, info->page_size);
  448. bufnum = dma_nwl_get_next_buffer(ctx, info, 1, timeout);
  449. if (bufnum == PCILIB_DMA_BUFFER_INVALID) return pos;
  450. //sync
  451. void *buf = pcilib_kmem_get_block_ua(ctx->pcilib, info->pages, bufnum);
  452. memcpy(buf, data, block_size);
  453. err = dma_nwl_push_buffer(ctx, info, block_size, (flags&PCILIB_DMA_FLAG_EOP)&&((pos + block_size) == size), timeout);
  454. if (err) return pos;
  455. }
  456. return size;
  457. }
  458. size_t dma_nwl_stream_read(pcilib_dma_context_t *vctx, 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) {
  459. int err, ret;
  460. size_t res = 0;
  461. size_t bufnum;
  462. size_t bufsize;
  463. nwl_dma_t *ctx = (nwl_dma_t*)vctx;
  464. size_t buf_size;
  465. int eop;
  466. pcilib_nwl_engine_description_t *info = ctx->engines + dma;
  467. err = dma_nwl_start(ctx, info);
  468. if (err) return 0;
  469. do {
  470. bufnum = dma_nwl_wait_buffer(ctx, info, &bufsize, &eop, timeout);
  471. if (bufnum == PCILIB_DMA_BUFFER_INVALID) return 0;
  472. #ifdef NWL_FIX_EOP_FOR_BIG_PACKETS
  473. if (size > 65536) {
  474. // printf("%i %i\n", res + bufsize, size);
  475. if ((res+bufsize) < size) eop = 0;
  476. else if ((res+bufsize) == size) eop = 1;
  477. }
  478. #endif /* NWL_FIX_EOP_FOR_BIG_PACKETS */
  479. //sync
  480. void *buf = pcilib_kmem_get_block_ua(ctx->pcilib, info->pages, bufnum);
  481. ret = cb(cbattr, eop?PCILIB_DMA_FLAG_EOP:0, bufsize, buf);
  482. dma_nwl_return_buffer(ctx, info);
  483. res += bufsize;
  484. // printf("%i %i %i (%li)\n", ret, res, eop, size);
  485. } while (ret);
  486. return res;
  487. }
  488. double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) {
  489. int i;
  490. int res;
  491. int err;
  492. size_t bytes;
  493. uint32_t val;
  494. uint32_t *buf, *cmp;
  495. const char *error = NULL;
  496. size_t us = 0;
  497. struct timeval start, cur;
  498. nwl_dma_t *ctx = (nwl_dma_t*)vctx;
  499. pcilib_dma_engine_t readid = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_FROM_DEVICE, dma);
  500. pcilib_dma_engine_t writeid = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_TO_DEVICE, dma);
  501. if (size%sizeof(uint32_t)) size = 1 + size / sizeof(uint32_t);
  502. else size /= sizeof(uint32_t);
  503. // Stop Generators and drain old data
  504. nwl_read_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
  505. val = ~(LOOPBACK|PKTCHKR|PKTGENR);
  506. nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
  507. nwl_read_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
  508. val = ~(LOOPBACK|PKTCHKR|PKTGENR);
  509. nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
  510. /*
  511. nwl_stop_engine(ctx, readid);
  512. nwl_stop_engine(ctx, writeid);
  513. err = dma_nwl_start(ctx, ctx->engines + readid);
  514. if (err) return -1;
  515. err = dma_nwl_start(ctx, ctx->engines + writeid);
  516. if (err) return -1;
  517. */
  518. __sync_synchronize();
  519. pcilib_skip_dma(ctx->pcilib, readid);
  520. // Set size and required mode
  521. val = size * sizeof(uint32_t);
  522. nwl_write_register(val, ctx, ctx->base_addr, PKT_SIZE_ADDRESS);
  523. switch (direction) {
  524. case PCILIB_DMA_BIDIRECTIONAL:
  525. val = LOOPBACK;
  526. break;
  527. case PCILIB_DMA_TO_DEVICE:
  528. return -1;
  529. case PCILIB_DMA_FROM_DEVICE:
  530. val = PKTGENR;
  531. break;
  532. }
  533. nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
  534. nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
  535. // Allocate memory and prepare data
  536. buf = malloc(size * sizeof(uint32_t));
  537. cmp = malloc(size * sizeof(uint32_t));
  538. if ((!buf)||(!cmp)) {
  539. if (buf) free(buf);
  540. if (cmp) free(cmp);
  541. return -1;
  542. }
  543. memset(cmp, 0x13, size * sizeof(uint32_t));
  544. // Benchmark
  545. for (i = 0; i < iterations; i++) {
  546. // printf("Iteration: %i\n", i);
  547. gettimeofday(&start, NULL);
  548. if (direction&PCILIB_DMA_TO_DEVICE) {
  549. memcpy(buf, cmp, size * sizeof(uint32_t));
  550. bytes = pcilib_write_dma(ctx->pcilib, writeid, addr, size * sizeof(uint32_t), buf);
  551. if (bytes != size * sizeof(uint32_t)) {
  552. error = "Write failed";
  553. break;
  554. }
  555. }
  556. memset(buf, 0, size * sizeof(uint32_t));
  557. bytes = pcilib_read_dma(ctx->pcilib, readid, addr, size * sizeof(uint32_t), buf);
  558. gettimeofday(&cur, NULL);
  559. us += ((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec));
  560. if (bytes != size * sizeof(uint32_t)) {
  561. printf("RF: %li %li\n", bytes, size * 4);
  562. error = "Read failed";
  563. break;
  564. }
  565. if (direction == PCILIB_DMA_BIDIRECTIONAL) {
  566. res = memcmp(buf, cmp, size * sizeof(uint32_t));
  567. if (res) {
  568. error = "Written and read values does not match";
  569. break;
  570. }
  571. }
  572. }
  573. // Stop Generators and drain data if necessary
  574. nwl_read_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
  575. val = ~(LOOPBACK|PKTCHKR|PKTGENR);
  576. nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
  577. nwl_read_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
  578. val = ~(LOOPBACK|PKTCHKR|PKTGENR);
  579. nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
  580. __sync_synchronize();
  581. if (direction == PCILIB_DMA_FROM_DEVICE) {
  582. pcilib_skip_dma(ctx->pcilib, readid);
  583. }
  584. free(cmp);
  585. free(buf);
  586. return error?-1:(1. * size * sizeof(uint32_t) * iterations * 1000000) / (1024. * 1024. * us);
  587. }