software.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <sys/file.h>
  6. #include "tools.h"
  7. #include "model.h"
  8. #include "error.h"
  9. #include "kmem.h"
  10. #include "pcilib.h"
  11. #include "pci.h"
  12. #include "datacpy.h"
  13. typedef struct pcilib_software_register_bank_context_s pcilib_software_register_bank_context_t;
  14. /**
  15. * structure defining the context of software registers
  16. */
  17. struct pcilib_software_register_bank_context_s {
  18. pcilib_register_bank_context_t bank_ctx; /**< the bank context associated with the software registers */
  19. pcilib_kmem_handle_t *kmem; /**< the kernel memory for software registers */
  20. volatile void *addr; /**< the virtual adress of the allocated kernel memory*/
  21. };
  22. void pcilib_software_registers_close(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx) {
  23. if (((pcilib_software_register_bank_context_t*)bank_ctx)->kmem)
  24. pcilib_free_kernel_memory(ctx, ((pcilib_software_register_bank_context_t*)bank_ctx)->kmem, PCILIB_KMEM_FLAG_REUSE);
  25. free(bank_ctx);
  26. }
  27. pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pcilib_register_bank_t bank, const char* model, const void *args) {
  28. int err;
  29. pcilib_software_register_bank_context_t *bank_ctx;
  30. pcilib_kmem_handle_t *handle;
  31. pcilib_lock_t *lock;
  32. pcilib_kmem_reuse_state_t reused;
  33. const pcilib_register_bank_description_t *bank_desc = ctx->banks + bank;
  34. if (bank_desc->size > PCILIB_KMEM_PAGE_SIZE) {
  35. pcilib_error("Currently software register banks are limited to %lu bytes, but %lu requested", PCILIB_KMEM_PAGE_SIZE, bank_desc->size);
  36. return NULL;
  37. }
  38. bank_ctx = calloc(1, sizeof(pcilib_software_register_bank_context_t));
  39. if (!bank_ctx) {
  40. pcilib_error("Memory allocation for bank context has failed");
  41. return NULL;
  42. }
  43. /*we get a lock to protect the creation of the kernel space for software registers against multiple creations*/
  44. lock = pcilib_get_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, "softreg/%s", bank_desc->name);
  45. if (!lock) {
  46. pcilib_software_registers_close(ctx, (pcilib_register_bank_context_t*)bank_ctx);
  47. pcilib_error("Failed to initialize a lock to protect bank %s with software registers", bank_desc->name);
  48. return NULL;
  49. }
  50. err = pcilib_lock(lock);
  51. if (err) {
  52. pcilib_return_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, lock);
  53. pcilib_software_registers_close(ctx, (pcilib_register_bank_context_t*)bank_ctx);
  54. pcilib_error("Error (%i) obtaining lock on bank %s with software registers", err, bank_desc->name);
  55. return NULL;
  56. }
  57. /*creation of the kernel space*/
  58. handle = pcilib_alloc_kernel_memory(ctx, PCILIB_KMEM_TYPE_PAGE, 1, PCILIB_KMEM_PAGE_SIZE, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_SOFTWARE_REGISTERS, bank_desc->addr), PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT);
  59. if (!handle) {
  60. pcilib_unlock(lock);
  61. pcilib_return_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, lock);
  62. pcilib_software_registers_close(ctx, (pcilib_register_bank_context_t*)bank_ctx);
  63. pcilib_error("Allocation of kernel memory for software registers has failed");
  64. return NULL;
  65. }
  66. bank_ctx->kmem = handle;
  67. bank_ctx->addr = pcilib_kmem_get_block_ua(ctx, handle, 0);
  68. reused = pcilib_kmem_is_reused(ctx, handle);
  69. if ((reused & PCILIB_KMEM_REUSE_REUSED) == 0) {
  70. pcilib_register_t i;
  71. if (reused & PCILIB_KMEM_REUSE_PARTIAL) {
  72. pcilib_unlock(lock);
  73. pcilib_return_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, lock);
  74. pcilib_software_registers_close(ctx, (pcilib_register_bank_context_t*)bank_ctx);
  75. pcilib_error("Inconsistent software registers are found (only part of required buffers is available)");
  76. return NULL;
  77. }
  78. /* here we fill the software registers with their default value*/
  79. for (i = 0; ctx->model_info.registers[i].name != NULL; i++) {
  80. if ((ctx->model_info.registers[i].bank == ctx->banks[bank].addr)&&(ctx->model_info.registers[i].type == PCILIB_REGISTER_STANDARD)) {
  81. *(pcilib_register_value_t*)(bank_ctx->addr + ctx->model_info.registers[i].addr) = ctx->model_info.registers[i].defvalue;
  82. }
  83. }
  84. }
  85. pcilib_unlock(lock);
  86. pcilib_return_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, lock);
  87. return (pcilib_register_bank_context_t*)bank_ctx;
  88. }
  89. uintptr_t pcilib_software_registers_resolve(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx, pcilib_address_resolution_flags_t flags, pcilib_register_addr_t addr) {
  90. if (addr == PCILIB_REGISTER_ADDRESS_INVALID) addr = 0;
  91. switch (flags&PCILIB_ADDRESS_RESOLUTION_MASK_ADDRESS_TYPE) {
  92. case 0:
  93. return (uintptr_t)((pcilib_software_register_bank_context_t*)bank_ctx)->addr + addr;
  94. case PCILIB_ADDRESS_RESOLUTION_FLAG_PHYS_ADDRESS:
  95. return pcilib_kmem_get_block_pa(ctx, ((pcilib_software_register_bank_context_t*)bank_ctx)->kmem, 0) + addr;
  96. }
  97. return PCILIB_ADDRESS_INVALID;
  98. }
  99. int pcilib_software_registers_read(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx, pcilib_register_addr_t addr, pcilib_register_value_t *value){
  100. const pcilib_register_bank_description_t *b = bank_ctx->bank;
  101. int access = b->access / 8;
  102. pcilib_register_value_t val = 0;
  103. if ((addr + sizeof(pcilib_register_value_t)) > bank_ctx->bank->size) {
  104. pcilib_error("Trying to access space outside of the define register bank (bank: %s, addr: 0x%lx)", bank_ctx->bank->name, addr);
  105. return PCILIB_ERROR_INVALID_ADDRESS;
  106. }
  107. pcilib_datacpy(&val, (void*)((pcilib_software_register_bank_context_t*)bank_ctx)->addr + addr, access, 1, b->raw_endianess);
  108. *value = val;
  109. return 0;
  110. }
  111. int pcilib_software_registers_write(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx, pcilib_register_addr_t addr, pcilib_register_value_t value) {
  112. const pcilib_register_bank_description_t *b = bank_ctx->bank;
  113. int access = b->access / 8;
  114. if ((addr + sizeof(pcilib_register_value_t)) > bank_ctx->bank->size) {
  115. pcilib_error("Trying to access space outside of the define register bank (bank: %s, addr: 0x%lx)", bank_ctx->bank->name, addr);
  116. return PCILIB_ERROR_INVALID_ADDRESS;
  117. }
  118. // we consider this atomic operation and, therefore, do no locking
  119. pcilib_datacpy((void*)((pcilib_software_register_bank_context_t*)bank_ctx)->addr + addr, &value, access, 1, b->raw_endianess);
  120. return 0;
  121. }