ddrio.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. #define _XOPEN_SOURCE 500
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdbool.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7. #include <getopt.h>
  8. #include <time.h>
  9. #include <assert.h>
  10. #include <pcilib.h>
  11. #include <pcilib/bar.h>
  12. #include <pcilib/kmem.h>
  13. #include "hf-interface.h"
  14. /* this should actually come from the distributed pcitool sources */
  15. #include "pciDriver.h"
  16. #ifndef NDEBUG
  17. #define WR32(addr, value) *(uint32_t *) (bar + (addr)) = (value);\
  18. printf ("WR32N %4x <- %x\n", (addr), (value));
  19. #define WR32_sleep(addr, value) *(uint32_t *) (bar + (addr)) = (value); usleep (1000);\
  20. printf ("WR32S %4x <- %x\n", (addr), (value));
  21. #define WR64(addr, value) *(uint64_t *) (bar + (addr)) = (value);\
  22. printf ("WR64N %4x <- %x\n", (addr), (value));
  23. #define WR64_sleep(addr, value) *(uint64_t *) (bar + (addr)) = (value); usleep (1000);\
  24. printf ("WR64S %4x <- %x\n", (addr), (value));
  25. #else
  26. #define WR32(addr, value) *(uint32_t *) (bar + (addr)) = (value);
  27. #define WR32_sleep(addr, value) *(uint32_t *) (bar + (addr)) = (value); usleep (1000);
  28. #define WR64(addr, value) *(uint64_t *) (bar + (addr)) = (value);
  29. #define WR64_sleep(addr, value) *(uint64_t *) (bar + (addr)) = (value); usleep (1000);
  30. #endif
  31. #define RD32(addr) (*(uint32_t *) (bar + (addr)))
  32. #define RD64(addr) (*(uint64_t *) (bar + (addr)))
  33. #define KMEM_USE_RING PCILIB_KMEM_USE(PCILIB_KMEM_USE_USER, 1)
  34. #define KMEM_DEFAULT_FLAGS PCILIB_KMEM_FLAG_HARDWARE | \
  35. PCILIB_KMEM_FLAG_PERSISTENT | \
  36. PCILIB_KMEM_FLAG_EXCLUSIVE
  37. typedef struct {
  38. const char *input;
  39. const char *output;
  40. bool keep;
  41. bool verbose;
  42. size_t size;
  43. enum {
  44. COPY_UINT64 = 0,
  45. COPY_MEMCPY,
  46. } copy;
  47. int number;
  48. } Options;
  49. static void
  50. usage (void)
  51. {
  52. printf ("Usage: ddr [OPTION] [FILE]\n"
  53. "Options:\n"
  54. " -h, --help Show this help message and exit\n"
  55. " -v, --verbose Be more verbose\n"
  56. " -k, --keep-data Keep data and don't reset DMA\n"
  57. " -o, --output Output filename\n"
  58. " -i, --input Input filename\n"
  59. " -s, --size Size of data (leave if reading supplied input)\n"
  60. " -n, --number Number of times data should be read\n"
  61. " -c, --copy Copy method, either `memcpy' or `64'\n");
  62. }
  63. static void
  64. parse_options (int argc, char *const *argv, Options *opts)
  65. {
  66. enum {
  67. OPT_HELP = 'h',
  68. OPT_VERBOSE = 'v',
  69. OPT_KEEP = 'k',
  70. OPT_INPUT = 'i',
  71. OPT_OUTPUT = 'o',
  72. OPT_SIZE = 's',
  73. OPT_COPY = 'c',
  74. OPT_NUMBER = 'n',
  75. };
  76. static struct option long_options[] = {
  77. { "help", no_argument, 0, OPT_HELP },
  78. { "verbose", no_argument, 0, OPT_VERBOSE },
  79. { "keep", no_argument, 0, OPT_KEEP },
  80. { "input", required_argument, 0, OPT_INPUT },
  81. { "output", required_argument, 0, OPT_OUTPUT },
  82. { "size", required_argument, 0, OPT_SIZE },
  83. { "copy", required_argument, 0, OPT_COPY },
  84. { "number", 0, 0, OPT_NUMBER },
  85. { 0, 0, 0, 0 },
  86. };
  87. int ret;
  88. int index;
  89. if (argc == 1) {
  90. usage ();
  91. exit (0);
  92. }
  93. memset (opts, 0, sizeof (Options));
  94. opts->number = 1;
  95. while ((ret = getopt_long (argc, argv, "i:o:s:c:n:khv", long_options, &index)) != -1) {
  96. switch (ret) {
  97. case OPT_HELP:
  98. usage ();
  99. exit (0);
  100. case OPT_VERBOSE:
  101. opts->verbose = true;
  102. break;
  103. case OPT_KEEP:
  104. opts->keep = true;
  105. break;
  106. case OPT_INPUT:
  107. opts->input = optarg;
  108. break;
  109. case OPT_OUTPUT:
  110. opts->output = optarg;
  111. break;
  112. case OPT_SIZE:
  113. opts->size = (size_t) atol (optarg);
  114. break;
  115. case OPT_COPY:
  116. if (!strcmp (optarg, "memcpy"))
  117. opts->copy = COPY_MEMCPY;
  118. else if (!strcmp (optarg, "64"))
  119. opts->copy = COPY_UINT64;
  120. break;
  121. case OPT_NUMBER:
  122. opts->number = atoi (optarg);
  123. break;
  124. default:
  125. break;
  126. }
  127. }
  128. }
  129. static double
  130. elapsed_seconds (struct timespec *start, struct timespec *end)
  131. {
  132. return (end->tv_sec + end->tv_nsec / 1000000000.0) - (start->tv_sec + start->tv_nsec / 1000000000.0);
  133. }
  134. static void
  135. reset_dma (pcilib_t *pci, volatile void *bar)
  136. {
  137. uint32_t value;
  138. WR32_sleep (HF_REG_BASE, HF_BASE_RESET);
  139. WR32_sleep (HF_REG_BASE, 0);
  140. value = RD32 (HF_REG_BASE);
  141. assert (value == 0x14021700 || value == 0x14031700);
  142. }
  143. static void
  144. reset_ddr_data (pcilib_t *pci, volatile void *bar, Options *opts)
  145. {
  146. reset_dma (pci, bar);
  147. /* reset DDR and FIFOs */
  148. WR32_sleep (HF_REG_CONTROL,
  149. HF_CONTROL_RESET |
  150. HF_CONTROL_SOFT_RESET |
  151. HF_CONTROL_SOURCE_RX_FIFO);
  152. /* write only in DDR mode, disable read */
  153. WR32_sleep (HF_REG_CONTROL,
  154. HF_CONTROL_SOURCE_RX_FIFO);
  155. }
  156. static void
  157. copy_data (volatile void *bar, char *data, size_t size, Options *opts)
  158. {
  159. if (opts->verbose)
  160. printf ("Writing %zu bytes\n", size);
  161. switch (opts->copy) {
  162. case COPY_MEMCPY:
  163. memcpy (bar + 0x9400, data, size);
  164. break;
  165. case COPY_UINT64:
  166. {
  167. uint64_t *src = (uint64_t *) data;
  168. uint64_t *dst = (uint64_t *) (bar + 0x9400);
  169. int remaining;
  170. for (size_t i = 0; i < size / 8; i++)
  171. dst[0] = src[i];
  172. remaining = size % 8;
  173. for (int i = 0; i < remaining; i++)
  174. ((uint8_t *) bar + 0x9400)[0] = data[size - 1 - i];
  175. }
  176. break;
  177. default:
  178. break;
  179. }
  180. }
  181. static void
  182. write_to_ddr (pcilib_t *pci, volatile void *bar, Options *opts)
  183. {
  184. FILE *fp;
  185. char *data;
  186. size_t size;
  187. size_t read_size;
  188. if ((fp = fopen (opts->input, "rb")) == NULL) {
  189. fprintf (stderr, "Could not open `%s'\n", opts->input);
  190. return;
  191. }
  192. if (opts->size == 0) {
  193. fseek (fp, 0, SEEK_END);
  194. size = (size_t) ftell (fp);
  195. rewind (fp);
  196. opts->size = size;
  197. }
  198. else
  199. size = opts->size;
  200. data = malloc (size);
  201. read_size = fread (data, 1, size, fp);
  202. if (read_size != size) {
  203. fprintf (stderr, "Could only read %zu/%zu bytes, expect inconsistencies\n",
  204. read_size, size);
  205. }
  206. copy_data (bar, data, size, opts);
  207. if (size >= 4096 && size % 4096) {
  208. size_t remaining = 4096 - size % 4096;
  209. memset (data, 0, remaining);
  210. copy_data (bar, data, remaining, opts);
  211. }
  212. free (data);
  213. fclose (fp);
  214. }
  215. static void
  216. read_from_ddr (pcilib_t *pci, volatile void *bar, Options *opts)
  217. {
  218. pcilib_kmem_handle_t *kmem_data;
  219. pcilib_kmem_handle_t *kmem_desc;
  220. uintptr_t bus_addr_data;
  221. uintptr_t bus_addr_desc;
  222. volatile uint32_t *data;
  223. volatile uint32_t *desc;
  224. uint32_t hardware_ptr;
  225. size_t size;
  226. FILE *fp = NULL;
  227. int started = 0;
  228. const size_t mem_size = 4096;
  229. const int flag_index = 2;
  230. struct timespec start;
  231. struct timespec end;
  232. if (opts->size == 0) {
  233. fprintf (stderr, "Read size is zero, not going to read\n");
  234. return;
  235. }
  236. if (opts->output) {
  237. if ((fp = fopen (opts->output, "wb")) == NULL) {
  238. fprintf (stderr, "Could not open `%s'\n", opts->output);
  239. return;
  240. }
  241. }
  242. kmem_data = pcilib_alloc_kernel_memory (pci, PCILIB_KMEM_TYPE_CONSISTENT, 1, mem_size, mem_size, PCILIB_KMEM_USE_DMA_PAGES, KMEM_DEFAULT_FLAGS);
  243. kmem_desc = pcilib_alloc_kernel_memory (pci, PCILIB_KMEM_TYPE_CONSISTENT, 1, 128, 4096, KMEM_USE_RING, KMEM_DEFAULT_FLAGS);
  244. data = (uint32_t *) pcilib_kmem_get_block_ua (pci, kmem_data, 0);
  245. desc = (uint32_t *) pcilib_kmem_get_block_ua (pci, kmem_desc, 0);
  246. bus_addr_data = pcilib_kmem_get_block_ba (pci, kmem_data, 0);
  247. bus_addr_desc = pcilib_kmem_get_block_ba (pci, kmem_desc, 0);
  248. /* DMA config */
  249. WR32_sleep (HF_REG_NUM_PACKETS, 0x20);
  250. WR32_sleep (HF_REG_PACKET_LENGTH, 0x20);
  251. WR32_sleep (HF_REG_UPDATE_THRESHOLD, 1);
  252. WR64_sleep (HF_REG_UPDATE_ADDRESS, bus_addr_desc);
  253. WR32_sleep (HF_REG_TIMER_THRESHOLD, 0x20000);
  254. if (opts->verbose)
  255. printf ("Reading %i times %zu B\n", opts->number, opts->size);
  256. clock_gettime (CLOCK_MONOTONIC, &start);
  257. for (int i = 0; i < opts->number; i++) {
  258. size = opts->size;
  259. hardware_ptr = 0;
  260. /* enable multi-read from DDR */
  261. WR32_sleep (HF_REG_CONTROL,
  262. HF_CONTROL_ENABLE_READ |
  263. HF_CONTROL_ENABLE_MULTI_READ |
  264. HF_CONTROL_SOURCE_RX_FIFO);
  265. WR32_sleep (HF_REG_CONTROL,
  266. HF_CONTROL_ENABLE_READ |
  267. HF_CONTROL_SOURCE_RX_FIFO);
  268. desc[flag_index] = 0;
  269. while (size >= mem_size) {
  270. desc[flag_index] = 0;
  271. /* set write addr */
  272. WR64 (HF_REG_DESCRIPTOR_ADDRESS, bus_addr_data);
  273. /* start DMA */
  274. if (!started) {
  275. WR32_sleep (HF_REG_DMA, HF_DMA_START);
  276. started = 1;
  277. }
  278. do {
  279. hardware_ptr = desc[flag_index];
  280. }
  281. while (hardware_ptr != (bus_addr_data & 0xFFFFFFFF));
  282. if (fp != NULL)
  283. fwrite (data, 1, mem_size, fp);
  284. size -= mem_size;
  285. }
  286. memset (data, 0xf0, mem_size);
  287. if (size > 0) {
  288. desc[flag_index] = 0;
  289. if (opts->verbose)
  290. printf ("Read remaining %zu bytes\n", size);
  291. WR64_sleep (HF_REG_DESCRIPTOR_ADDRESS, bus_addr_data);
  292. /* start DMA */
  293. if (!started) {
  294. WR32_sleep (HF_REG_DMA, HF_DMA_START);
  295. started = 1;
  296. }
  297. do {
  298. hardware_ptr = desc[flag_index];
  299. }
  300. while (hardware_ptr != (bus_addr_data & 0xFFFFFFFF));
  301. if (fp != NULL)
  302. fwrite (data, 1, size, fp);
  303. }
  304. if (opts->verbose)
  305. printf ("Descriptor: update_pattern=%x empty=%x last_address=%lx\n", desc[0], 1 & desc[1], desc[2] | (((uint64_t) desc[3]) << 32));
  306. }
  307. clock_gettime (CLOCK_MONOTONIC, &end);
  308. WR32_sleep (HF_REG_DMA, HF_DMA_STOP);
  309. if (fp)
  310. fclose (fp);
  311. pcilib_free_kernel_memory (pci, kmem_data, KMEM_DEFAULT_FLAGS);
  312. pcilib_free_kernel_memory (pci, kmem_desc, KMEM_DEFAULT_FLAGS);
  313. if (opts->verbose) {
  314. double time;
  315. time = elapsed_seconds (&start, &end);
  316. printf ("Read in %f s equivalent to %3.5f MB/s\n",
  317. time, opts->size * opts->number / 1024. / 1024. / time);
  318. }
  319. }
  320. int
  321. main (int argc, char const* argv[])
  322. {
  323. static const char *DEVICE = "/dev/fpga0";
  324. Options opts;
  325. pcilib_t *pci;
  326. volatile void *bar;
  327. parse_options (argc, (char *const *) argv, &opts);
  328. pci = pcilib_open (DEVICE, "pci");
  329. if (pci == NULL) {
  330. fprintf (stderr, "Could not open `%s'", DEVICE);
  331. return 1;
  332. }
  333. pcilib_map_bar (pci, PCILIB_BAR0);
  334. bar = pcilib_resolve_bar_address (pci, PCILIB_BAR0, 0);
  335. /* reset dbg tx */
  336. WR32_sleep (HF_REG_DEBUG_REQUESTER_RESET, 1);
  337. WR32_sleep (HF_REG_DEBUG_REQUESTER_RESET, 0);
  338. WR32_sleep (HF_REG_DEBUG_COMPLETER_RESET, 1);
  339. WR32_sleep (HF_REG_DEBUG_COMPLETER_RESET, 0);
  340. /* configure interconnect */
  341. WR32_sleep (HF_REG_INTERCONNECT,
  342. HF_INTERCONNECT_MASTER_DMA |
  343. HF_INTERCONNECT_DDR_TO_DMA |
  344. HF_INTERCONNECT_DDR_FROM_64);
  345. if (opts.input != NULL) {
  346. if (!opts.keep) {
  347. if (opts.verbose)
  348. printf ("Reset DDR and data\n");
  349. reset_ddr_data (pci, bar, &opts);
  350. }
  351. write_to_ddr (pci, bar, &opts);
  352. }
  353. if (opts.input == NULL)
  354. read_from_ddr (pci, bar, &opts);
  355. pcilib_unmap_bar (pci, PCILIB_BAR0, (void *) bar);
  356. pcilib_close (pci);
  357. }