pci.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. //#define PCILIB_FILE_IO
  2. #define _BSD_SOURCE
  3. #define _POSIX_C_SOURCE 200809L
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <strings.h>
  7. #include <stdlib.h>
  8. #include <stdint.h>
  9. #include <fcntl.h>
  10. #include <unistd.h>
  11. #include <sys/ioctl.h>
  12. #include <sys/mman.h>
  13. #include <arpa/inet.h>
  14. #include <errno.h>
  15. #include <assert.h>
  16. #include "pcilib.h"
  17. #include "pci.h"
  18. #include "tools.h"
  19. #include "error.h"
  20. #include "model.h"
  21. static int pcilib_detect_model(pcilib_t *ctx, const char *model) {
  22. int i, j;
  23. // Registers & Banks must be copied!
  24. if (model) {
  25. // Check for DMA models
  26. for (i = 0; pcilib_dma[i].name; i++) {
  27. if (!strcasecmp(model, pcilib_dma[i].name))
  28. break;
  29. }
  30. if (pcilib_dma[i].api) {
  31. memcpy(&ctx->dma, &pcilib_dma[i], sizeof(pcilib_dma_description_t));
  32. ctx->model_info.dma = &ctx->dma;
  33. if (pcilib_dma[i].banks)
  34. pcilib_add_register_banks(ctx, 0, pcilib_dma[i].banks);
  35. if (pcilib_dma[i].registers)
  36. pcilib_add_registers(ctx, 0, pcilib_dma[i].registers);
  37. if (pcilib_dma[i].engines) {
  38. for (j = 0; pcilib_dma[i].engines[j].addr_bits; j++)
  39. memcpy(ctx->engines, pcilib_dma[i].engines, j * sizeof(pcilib_dma_engine_description_t));
  40. ctx->num_engines = j;
  41. } else
  42. ctx->dma.engines = ctx->engines;
  43. return 0;
  44. }
  45. // Check for XML models (DMA + XML registers)
  46. // Check for specified model
  47. // Iterate other all other models
  48. }
  49. // Check for all installed models
  50. // memcpy(&ctx->model_info, model, sizeof(pcilib_model_description_t));
  51. // how we reconcile the banks from event model and dma description? The banks specified in the DMA description should override corresponding banks of events...
  52. if (model)
  53. return PCILIB_ERROR_NOTFOUND;
  54. // Otherwise, simple pci access (all model members are set to NULL)
  55. return 0;
  56. }
  57. pcilib_t *pcilib_open(const char *device, const char *model) {
  58. int err;
  59. size_t i;
  60. pcilib_t *ctx = malloc(sizeof(pcilib_t));
  61. if (ctx) {
  62. memset(ctx, 0, sizeof(pcilib_t));
  63. ctx->handle = open(device, O_RDWR);
  64. if (ctx->handle < 0) {
  65. pcilib_error("Error opening device (%s)", device);
  66. free(ctx);
  67. return NULL;
  68. }
  69. ctx->page_mask = (uintptr_t)-1;
  70. ctx->model = model?strdup(model):NULL;
  71. ctx->alloc_reg = PCILIB_DEFAULT_REGISTER_SPACE;
  72. ctx->registers = (pcilib_register_description_t *)malloc(PCILIB_DEFAULT_REGISTER_SPACE * sizeof(pcilib_register_description_t));
  73. /* ctx->banks = (pcilib_register_bank_context_t *)malloc(PCILIB_MAX_BANKS * sizeof(pcilib_register_bank_context_t));
  74. ctx->ranges = (pcilib_register_range_t *)malloc(PCILIB_MAX_RANGES * sizeof(pcilib_register_range_t));
  75. ctx->protocols
  76. ctx->engines*/
  77. if ((!ctx->registers)/*||(!ctx->banks)||(!ctx->ranges)*/) {
  78. pcilib_error("Error allocating memory for register model");
  79. pcilib_close(ctx);
  80. free(ctx);
  81. return NULL;
  82. }
  83. memset(ctx->registers, 0, sizeof(pcilib_register_description_t));
  84. memset(ctx->banks, 0, sizeof(pcilib_register_bank_description_t));
  85. memset(ctx->ranges, 0, sizeof(pcilib_register_range_t));
  86. for (i = 0; pcilib_protocols[i].api; i++);
  87. memcpy(ctx->protocols, pcilib_protocols, i * sizeof(pcilib_register_protocol_description_t));
  88. ctx->model_info.registers = ctx->registers;
  89. ctx->model_info.banks = ctx->banks;
  90. ctx->model_info.protocols = ctx->protocols;
  91. ctx->model_info.ranges = ctx->ranges;
  92. err = pcilib_detect_model(ctx, model);
  93. if (err) {
  94. const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
  95. if (board_info)
  96. pcilib_error("Error (%i) configuring model %s (%x:%x)", err, (model?model:""), board_info->vendor_id, board_info->device_id);
  97. else
  98. pcilib_error("Error (%i) configuring model %s", err, (model?model:""));
  99. pcilib_close(ctx);
  100. free(ctx);
  101. return NULL;
  102. }
  103. err = pcilib_init_register_banks(ctx);
  104. if (err) {
  105. pcilib_error("Error (%i) initializing regiser banks\n", err);
  106. pcilib_close(ctx);
  107. free(ctx);
  108. return NULL;
  109. }
  110. err = pcilib_init_event_engine(ctx);
  111. if (err) {
  112. pcilib_error("Error (%i) initializing event engine\n", err);
  113. pcilib_close(ctx);
  114. free(ctx);
  115. return NULL;
  116. }
  117. }
  118. return ctx;
  119. }
  120. const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx) {
  121. int ret;
  122. if (ctx->page_mask == (uintptr_t)-1) {
  123. ret = ioctl( ctx->handle, PCIDRIVER_IOC_PCI_INFO, &ctx->board_info );
  124. if (ret) {
  125. pcilib_error("PCIDRIVER_IOC_PCI_INFO ioctl have failed");
  126. return NULL;
  127. }
  128. ctx->page_mask = pcilib_get_page_mask();
  129. }
  130. return &ctx->board_info;
  131. }
  132. pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx) {
  133. return ctx->event_ctx;
  134. }
  135. static pcilib_bar_t pcilib_detect_bar(pcilib_t *ctx, uintptr_t addr, size_t size) {
  136. int n = 0;
  137. pcilib_bar_t i;
  138. const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
  139. if (!board_info) return PCILIB_BAR_INVALID;
  140. for (i = 0; i < PCILIB_MAX_BARS; i++) {
  141. if (board_info->bar_length[i] > 0) {
  142. if ((addr >= board_info->bar_start[i])&&((board_info->bar_start[i] + board_info->bar_length[i]) >= (addr + size))) return i;
  143. if (n) n = -1;
  144. else n = i + 1;
  145. }
  146. }
  147. if (n > 0) return n - 1;
  148. return PCILIB_BAR_INVALID;
  149. }
  150. int pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *addr, size_t size) {
  151. const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
  152. if (!board_info) return PCILIB_ERROR_NOTFOUND;
  153. if (*bar == PCILIB_BAR_DETECT) {
  154. *bar = pcilib_detect_bar(ctx, *addr, size);
  155. if (*bar == PCILIB_BAR_INVALID) {
  156. pcilib_error("The requested data block at address 0x%x with size %zu does not belongs to any available memory bank", *addr, size);
  157. return PCILIB_ERROR_NOTFOUND;
  158. }
  159. if (*addr < board_info->bar_start[*bar])
  160. *addr += board_info->bar_start[*bar];
  161. } else {
  162. if ((*addr < board_info->bar_start[*bar])||((board_info->bar_start[*bar] + board_info->bar_length[*bar]) < (((uintptr_t)*addr) + size))) {
  163. if ((board_info->bar_length[*bar]) >= (((uintptr_t)*addr) + size)) {
  164. *addr += board_info->bar_start[*bar];
  165. } else {
  166. pcilib_error("The requested data block at address 0x%x with size %zu does not belong the specified memory bank (Bar %i: starting at 0x%x with size 0x%x)", *addr, size, *bar, board_info->bar_start[*bar], board_info->bar_length[*bar]);
  167. return PCILIB_ERROR_NOTFOUND;
  168. }
  169. }
  170. }
  171. *addr -= board_info->bar_start[*bar];
  172. *addr += board_info->bar_start[*bar] & ctx->page_mask;
  173. return 0;
  174. }
  175. void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar) {
  176. void *res;
  177. int ret;
  178. const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
  179. if (!board_info) return NULL;
  180. if (ctx->bar_space[bar]) return ctx->bar_space[bar];
  181. ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_PCI );
  182. if (ret) {
  183. pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed", bar);
  184. return NULL;
  185. }
  186. ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_AREA, PCIDRIVER_BAR0 + bar );
  187. if (ret) {
  188. pcilib_error("PCIDRIVER_IOC_MMAP_AREA ioctl have failed for bank %i", bar);
  189. return NULL;
  190. }
  191. #ifdef PCILIB_FILE_IO
  192. file_io_handle = open("/root/data", O_RDWR);
  193. res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->file_io_handle, 0 );
  194. #else
  195. res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 );
  196. #endif
  197. if ((!res)||(res == MAP_FAILED)) {
  198. pcilib_error("Failed to mmap data bank %i", bar);
  199. return NULL;
  200. }
  201. return res;
  202. }
  203. void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data) {
  204. const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
  205. if (!board_info) return;
  206. if (ctx->bar_space[bar]) return;
  207. munmap(data, board_info->bar_length[bar]);
  208. #ifdef PCILIB_FILE_IO
  209. close(ctx->file_io_handle);
  210. #endif
  211. }
  212. int pcilib_map_register_space(pcilib_t *ctx) {
  213. int err;
  214. pcilib_register_bank_t i;
  215. if (!ctx->reg_bar_mapped) {
  216. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  217. const pcilib_register_bank_description_t *banks = model_info->banks;
  218. for (i = 0; ((banks)&&(banks[i].access)); i++) {
  219. // uint32_t buf[2];
  220. void *reg_space;
  221. pcilib_bar_t bar = banks[i].bar;
  222. if (bar == PCILIB_BAR_DETECT) {
  223. uintptr_t addr = banks[0].read_addr;
  224. err = pcilib_detect_address(ctx, &bar, &addr, 1);
  225. if (err) return err;
  226. if (!ctx->bar_space[bar]) {
  227. reg_space = pcilib_map_bar(ctx, bar);
  228. // pcilib_memcpy(&buf, reg_space, 8);
  229. if (reg_space) {
  230. ctx->bar_space[bar] = reg_space;
  231. } else {
  232. return PCILIB_ERROR_FAILED;
  233. }
  234. }
  235. } else if (!ctx->bar_space[bar]) {
  236. reg_space = pcilib_map_bar(ctx, bar);
  237. if (reg_space) {
  238. ctx->bar_space[bar] = reg_space;
  239. } else {
  240. return PCILIB_ERROR_FAILED;
  241. }
  242. // pcilib_memcpy(&buf, reg_space, 8);
  243. }
  244. if (!i) ctx->reg_bar = bar;
  245. }
  246. ctx->reg_bar_mapped = 1;
  247. }
  248. return 0;
  249. }
  250. int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr) {
  251. int err;
  252. pcilib_bar_t i;
  253. if (!ctx->data_bar_mapped) {
  254. const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
  255. if (!board_info) return PCILIB_ERROR_FAILED;
  256. err = pcilib_map_register_space(ctx);
  257. if (err) {
  258. pcilib_error("Error mapping register space");
  259. return err;
  260. }
  261. int data_bar = -1;
  262. for (i = 0; i < PCILIB_MAX_BARS; i++) {
  263. if ((ctx->bar_space[i])||(!board_info->bar_length[i])) continue;
  264. if (addr) {
  265. if (board_info->bar_start[i] == addr) {
  266. data_bar = i;
  267. break;
  268. }
  269. } else {
  270. if (data_bar >= 0) {
  271. data_bar = -1;
  272. break;
  273. }
  274. data_bar = i;
  275. }
  276. }
  277. if (data_bar < 0) {
  278. if (addr) pcilib_error("Unable to find the specified data space (%lx)", addr);
  279. else pcilib_error("Unable to find the data space");
  280. return PCILIB_ERROR_NOTFOUND;
  281. }
  282. ctx->data_bar = data_bar;
  283. if (!ctx->bar_space[data_bar]) {
  284. char *data_space = pcilib_map_bar(ctx, data_bar);
  285. if (data_space) ctx->bar_space[data_bar] = data_space;
  286. else {
  287. pcilib_error("Unable to map the data space");
  288. return PCILIB_ERROR_FAILED;
  289. }
  290. }
  291. ctx->data_bar_mapped = 0;
  292. }
  293. return 0;
  294. }
  295. char *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr) {
  296. if (bar == PCILIB_BAR_DETECT) {
  297. // First checking the default register bar
  298. size_t offset = addr - ctx->board_info.bar_start[ctx->reg_bar];
  299. if ((addr > ctx->board_info.bar_start[ctx->reg_bar])&&(offset < ctx->board_info.bar_length[ctx->reg_bar])) {
  300. if (!ctx->bar_space[ctx->reg_bar]) {
  301. pcilib_error("The register bar is not mapped");
  302. return NULL;
  303. }
  304. return ctx->bar_space[ctx->reg_bar] + offset + (ctx->board_info.bar_start[ctx->reg_bar] & ctx->page_mask);
  305. }
  306. // Otherwise trying to detect
  307. bar = pcilib_detect_bar(ctx, addr, 1);
  308. if (bar != PCILIB_BAR_INVALID) {
  309. size_t offset = addr - ctx->board_info.bar_start[bar];
  310. if ((offset < ctx->board_info.bar_length[bar])&&(ctx->bar_space[bar])) {
  311. if (!ctx->bar_space[bar]) {
  312. pcilib_error("The requested bar (%i) is not mapped", bar);
  313. return NULL;
  314. }
  315. return ctx->bar_space[bar] + offset + (ctx->board_info.bar_start[bar] & ctx->page_mask);
  316. }
  317. }
  318. } else {
  319. if (!ctx->bar_space[bar]) {
  320. pcilib_error("The requested bar (%i) is not mapped", bar);
  321. return NULL;
  322. }
  323. if (addr < ctx->board_info.bar_length[bar]) {
  324. return ctx->bar_space[bar] + addr + (ctx->board_info.bar_start[bar] & ctx->page_mask);
  325. }
  326. if ((addr >= ctx->board_info.bar_start[bar])&&(addr < (ctx->board_info.bar_start[bar] + ctx->board_info.bar_length[ctx->reg_bar]))) {
  327. return ctx->bar_space[bar] + (addr - ctx->board_info.bar_start[bar]) + (ctx->board_info.bar_start[bar] & ctx->page_mask);
  328. }
  329. }
  330. return NULL;
  331. }
  332. char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size) {
  333. int err;
  334. err = pcilib_map_data_space(ctx, addr);
  335. if (err) {
  336. pcilib_error("Failed to map the specified address space (%lx)", addr);
  337. return NULL;
  338. }
  339. if (size) *size = ctx->board_info.bar_length[ctx->data_bar];
  340. return ctx->bar_space[ctx->data_bar] + (ctx->board_info.bar_start[ctx->data_bar] & ctx->page_mask);
  341. }
  342. void pcilib_close(pcilib_t *ctx) {
  343. pcilib_bar_t i;
  344. if (ctx) {
  345. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  346. const pcilib_event_api_description_t *eapi = model_info->api;
  347. const pcilib_dma_api_description_t *dapi = NULL;
  348. if (model_info->dma) dapi = model_info->dma->api;
  349. if ((eapi)&&(eapi->free)) eapi->free(ctx->event_ctx);
  350. if ((dapi)&&(dapi->free)) dapi->free(ctx->dma_ctx);
  351. pcilib_free_register_banks(ctx);
  352. if (ctx->kmem_list) {
  353. pcilib_warning("Not all kernel buffers are properly cleaned");
  354. while (ctx->kmem_list) {
  355. pcilib_free_kernel_memory(ctx, ctx->kmem_list, 0);
  356. }
  357. }
  358. for (i = 0; i < PCILIB_MAX_BARS; i++) {
  359. if (ctx->bar_space[i]) {
  360. char *ptr = ctx->bar_space[i];
  361. ctx->bar_space[i] = NULL;
  362. pcilib_unmap_bar(ctx, i, ptr);
  363. }
  364. }
  365. if (ctx->registers)
  366. free(ctx->registers);
  367. if (ctx->model)
  368. free(ctx->model);
  369. if (ctx->handle >= 0)
  370. close(ctx->handle);
  371. free(ctx);
  372. }
  373. }
  374. int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
  375. void *data;
  376. pcilib_detect_address(ctx, &bar, &addr, size);
  377. data = pcilib_map_bar(ctx, bar);
  378. pcilib_memcpy(buf, data + addr, size);
  379. pcilib_unmap_bar(ctx, bar, data);
  380. return 0;
  381. }
  382. int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
  383. void *data;
  384. pcilib_detect_address(ctx, &bar, &addr, size);
  385. data = pcilib_map_bar(ctx, bar);
  386. pcilib_memcpy(data + addr, buf, size);
  387. pcilib_unmap_bar(ctx, bar, data);
  388. return 0;
  389. }
  390. int pcilib_read_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) {
  391. int i;
  392. void *data;
  393. pcilib_detect_address(ctx, &bar, &addr, fifo_size);
  394. data = pcilib_map_bar(ctx, bar);
  395. for (i = 0; i < n; i++) {
  396. pcilib_memcpy(buf + i * fifo_size, data + addr, fifo_size);
  397. }
  398. pcilib_unmap_bar(ctx, bar, data);
  399. return 0;
  400. }
  401. int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) {
  402. int i;
  403. void *data;
  404. pcilib_detect_address(ctx, &bar, &addr, fifo_size);
  405. data = pcilib_map_bar(ctx, bar);
  406. for (i = 0; i < n; i++) {
  407. pcilib_memcpy(data + addr, buf + i * fifo_size, fifo_size);
  408. }
  409. pcilib_unmap_bar(ctx, bar, data);
  410. return 0;
  411. }