diff options
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/software.c | 47 |
1 files changed, 39 insertions, 8 deletions
diff --git a/protocols/software.c b/protocols/software.c index 5534dc7..55f62e8 100644 --- a/protocols/software.c +++ b/protocols/software.c @@ -13,10 +13,10 @@ typedef struct pcilib_software_register_bank_context_s pcilib_software_register_bank_context_t; struct pcilib_software_register_bank_context_s { - pcilib_register_bank_context_t bank_ctx; + pcilib_register_bank_context_t bank_ctx; /**< the bank context associated with the software registers */ - pcilib_kmem_handle_t *kmem; - void *addr; + pcilib_kmem_handle_t *kmem; /**< the kernel memory for software registers */ + void *addr; /**< the virtual adress of the allocated kernel memory*/ }; /** @@ -40,8 +40,10 @@ void pcilib_software_registers_close(pcilib_t *ctx, pcilib_register_bank_context * @return a bank context with the adress of the kernel space memory related to it */ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pcilib_register_bank_t bank, const char* model, const void *args) { + int err; pcilib_software_register_bank_context_t *bank_ctx; pcilib_kmem_handle_t *handle; + pcilib_lock_t *lock; pcilib_kmem_reuse_state_t reused; const pcilib_register_bank_description_t *bank_desc = ctx->banks + bank; @@ -52,11 +54,33 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc } bank_ctx = calloc(1, sizeof(pcilib_software_register_bank_context_t)); + if (!bank_ctx) { + pcilib_error("Memory allocation for bank context has failed"); + return NULL; + } + + lock = pcilib_get_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, "softreg/%s", bank_desc->name); + if (!lock) { + pcilib_software_registers_close(ctx, (pcilib_register_bank_context_t*)bank_ctx); + pcilib_error("Failed to initialize a lock to protect bank %s with software registers", bank_desc->name); + return NULL; + } + + err = pcilib_lock(lock); + if (err) { + pcilib_return_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, lock); + pcilib_software_registers_close(ctx, (pcilib_register_bank_context_t*)bank_ctx); + pcilib_error("Error (%i) obtaining lock on bank %s with software registers", err, bank_desc->name); + return NULL; + } + - 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), PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT); + 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); if (!handle) { - pcilib_error("Allocation of kernel memory for software registers has failed"); + pcilib_unlock(lock); + pcilib_return_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, lock); pcilib_software_registers_close(ctx, (pcilib_register_bank_context_t*)bank_ctx); + pcilib_error("Allocation of kernel memory for software registers has failed"); return NULL; } @@ -68,8 +92,10 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc pcilib_register_t i; if (reused & PCILIB_KMEM_REUSE_PARTIAL) { - pcilib_error("Inconsistent software registers are found (only part of required buffers is available)"); + pcilib_unlock(lock); + pcilib_return_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, lock); pcilib_software_registers_close(ctx, (pcilib_register_bank_context_t*)bank_ctx); + pcilib_error("Inconsistent software registers are found (only part of required buffers is available)"); return NULL; } @@ -80,6 +106,9 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc } } + pcilib_unlock(lock); + pcilib_return_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, lock); + return (pcilib_register_bank_context_t*)bank_ctx; } @@ -97,7 +126,8 @@ int pcilib_software_registers_read(pcilib_t *ctx, pcilib_register_bank_context_t pcilib_error("Trying to access space outside of the define register bank (bank: %s, addr: 0x%lx)", bank_ctx->bank->name, addr); return PCILIB_ERROR_INVALID_ADDRESS; } - + + // we consider this atomic operation and, therefore, do no locking *value = *(pcilib_register_value_t*)(((pcilib_software_register_bank_context_t*)bank_ctx)->addr + addr); return 0; } @@ -111,12 +141,13 @@ int pcilib_software_registers_read(pcilib_t *ctx, pcilib_register_bank_context_t * @param[out] value the value we want to write in the register * @return 0 in case of success */ -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){ +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) { if ((addr + sizeof(pcilib_register_value_t)) > bank_ctx->bank->size) { pcilib_error("Trying to access space outside of the define register bank (bank: %s, addr: 0x%lx)", bank_ctx->bank->name, addr); return PCILIB_ERROR_INVALID_ADDRESS; } + // we consider this atomic operation and, therefore, do no locking *(pcilib_register_value_t*)(((pcilib_software_register_bank_context_t*)bank_ctx)->addr + addr) = value; return 0; } |