ddrio.c 12 KB

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