Browse Source

Provide API calls for register and bank address resolution

Suren A. Chilingaryan 8 years ago
parent
commit
ca7353be48
8 changed files with 123 additions and 5 deletions
  1. 39 0
      pcilib/bank.c
  2. 21 0
      pcilib/bank.h
  3. 1 0
      pcilib/pcilib.h
  4. 33 2
      protocols/default.c
  5. 2 1
      protocols/default.h
  6. 1 1
      protocols/property.h
  7. 15 0
      protocols/software.c
  8. 11 1
      protocols/software.h

+ 39 - 0
pcilib/bank.c

@@ -272,6 +272,45 @@ pcilib_register_protocol_t pcilib_find_register_protocol(pcilib_t *ctx, const ch
     return pcilib_find_register_protocol_by_name(ctx, protocol);
 }
 
+uintptr_t pcilib_resolve_bank_address_by_id(pcilib_t *ctx, pcilib_address_resolution_flags_t flags, pcilib_register_bank_t bank) {
+    pcilib_register_bank_context_t *bctx = ctx->bank_ctx[bank];
+
+    if (!bctx->api->resolve)
+	return PCILIB_ADDRESS_INVALID;
+	
+    return bctx->api->resolve(ctx, bctx, flags, PCILIB_REGISTER_ADDRESS_INVALID);
+}
+
+uintptr_t pcilib_resolve_bank_address(pcilib_t *ctx, pcilib_address_resolution_flags_t flags, const char *bank) {
+    pcilib_register_bank_t bank_id = pcilib_find_register_bank(ctx, bank);
+    if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
+	if (bank) pcilib_error("Invalid register bank is specified (%s)", bank);
+	else pcilib_error("Register bank should be specified");
+	return PCILIB_ADDRESS_INVALID;
+    }
+
+    return pcilib_resolve_bank_address_by_id(ctx, flags, bank_id);
+}
+
+uintptr_t pcilib_resolve_register_address_by_id(pcilib_t *ctx, pcilib_address_resolution_flags_t flags, pcilib_register_t reg) {
+    pcilib_register_bank_context_t *bctx = ctx->bank_ctx[ctx->register_ctx[reg].bank];
+
+    if (!bctx->api->resolve)
+	return PCILIB_ADDRESS_INVALID;
+
+    return bctx->api->resolve(ctx, bctx, 0, ctx->registers[reg].addr);
+}
+
+uintptr_t pcilib_resolve_register_address(pcilib_t *ctx, pcilib_address_resolution_flags_t flags, const char *bank, const char *regname) {
+    pcilib_register_t reg = pcilib_find_register(ctx, bank, regname);
+    if (reg == PCILIB_REGISTER_INVALID) {
+	pcilib_error("Register (%s) is not found", regname);
+	return PCILIB_ADDRESS_INVALID;
+    }
+
+    return pcilib_resolve_register_address_by_id(ctx, flags, reg);
+}
+
 int pcilib_get_register_bank_attr_by_id(pcilib_t *ctx, pcilib_register_bank_t bank, const char *attr, pcilib_value_t *val) {
     assert(bank < ctx->num_banks);
 

+ 21 - 0
pcilib/bank.h

@@ -12,6 +12,10 @@
 #define PCILIB_REGISTER_BANK_PROPERTY           65                                      /**< Registers abstracting properties and other computed registers */
 #define PCILIB_REGISTER_BANK_DMACONF		96					/**< DMA configuration in the software registers */
 #define PCILIB_REGISTER_BANK_DMA		97					/**< First BANK address to be used by DMA engines */
+#define PCILIB_REGISTER_BANK_DMA0		PCILIB_REGISTER_BANK_DMA		/**< First BANK address to be used by DMA engines */
+#define PCILIB_REGISTER_BANK_DMA1		(PCILIB_REGISTER_BANK_DMA + 1)		/**< Second BANK address to be used by DMA engines */
+#define PCILIB_REGISTER_BANK_DMA2		(PCILIB_REGISTER_BANK_DMA + 2)		/**< Third BANK address to be used by DMA engines */
+#define PCILIB_REGISTER_BANK_DMA3		(PCILIB_REGISTER_BANK_DMA + 3)		/**< Fourth BANK address to be used by DMA engines */
 #define PCILIB_REGISTER_BANK_DYNAMIC		128					/**< First BANK address to map dynamic XML configuration */
 #define PCILIB_REGISTER_PROTOCOL_INVALID	((pcilib_register_protocol_t)-1)
 #define PCILIB_REGISTER_PROTOCOL0		0					/**< First PROTOCOL address to be used in the event engine */
@@ -34,11 +38,22 @@ typedef enum {
     PCILIB_MODEL_MODIFICATION_FLAG_SKIP_EXISTING = 2				/**< If flag is set, pcilib will just skip existing registers/banks/etc instead of reporting a error */
 } pcilib_model_modification_flags_t;
 
+typedef enum {
+    PCILIB_ADDRESS_RESOLUTION_FLAGS_DEFAULT = 0,
+    PCILIB_ADDRESS_RESOLUTION_FLAG_BUS_ADDRESS = 1,				/**< Resolve bus address instead of VA */
+    PCILIB_ADDRESS_RESOLUTION_FLAG_PHYS_ADDRESS = 2,				/**< Resolve hardware address instead of VA */
+    PCILIB_ADDRESS_RESOLUTION_MASK_ADDRESS_TYPE = 3,
+    PCILIB_ADDRESS_RESOLUTION_FLAG_READ_ONLY = 4,				/**< Request read-only memory, in case if read-write resolution is impossible */
+    PCILIB_ADDRESS_RESOLUTION_FLAG_WRITE_ONLY = 8,				/**< Request write-only resolution, in case if read-write resolution is impossible */
+    PCILIB_ADDRESS_RESOLUTION_MASK_ACCESS_MODE = 12
+} pcilib_address_resolution_flags_t;
+
 typedef struct {
     pcilib_version_t version;
 
     pcilib_register_bank_context_t *(*init)(pcilib_t *ctx, pcilib_register_bank_t bank, const char *model, const void *args);			/**< Optional API call to initialize bank context */
     void (*free)(pcilib_t *pcilib, pcilib_register_bank_context_t *ctx);									/**< Optional API call to cleanup bank context */
+    uintptr_t (*resolve)(pcilib_t *pcilib, pcilib_register_bank_context_t *ctx, pcilib_address_resolution_flags_t flags, pcilib_register_addr_t addr); /**< Resolves register virtual address (if supported) */
     int (*read)(pcilib_t *pcilib, pcilib_register_bank_context_t *ctx, pcilib_register_addr_t addr, pcilib_register_value_t *value);		/**< Read from register, mandatory for RO/RW registers */
     int (*write)(pcilib_t *pcilib, pcilib_register_bank_context_t *ctx, pcilib_register_addr_t addr, pcilib_register_value_t value);		/**< Write to register, mandatory for WO/RW registers */
 } pcilib_register_protocol_api_description_t;
@@ -164,6 +179,12 @@ pcilib_register_protocol_t pcilib_find_register_protocol_by_addr(pcilib_t *ctx,
 pcilib_register_protocol_t pcilib_find_register_protocol_by_name(pcilib_t *ctx, const char *name);
 pcilib_register_protocol_t pcilib_find_register_protocol(pcilib_t *ctx, const char *name);
 
+uintptr_t pcilib_resolve_bank_address_by_id(pcilib_t *ctx, pcilib_address_resolution_flags_t flags, pcilib_register_bank_t bank);
+uintptr_t pcilib_resolve_bank_address(pcilib_t *ctx, pcilib_address_resolution_flags_t flags, const char *bank);
+
+uintptr_t pcilib_resolve_register_address_by_id(pcilib_t *ctx, pcilib_address_resolution_flags_t flags, pcilib_register_t reg);
+uintptr_t pcilib_resolve_register_address(pcilib_t *ctx, pcilib_address_resolution_flags_t flags, const char *bank, const char *regname);
+
 int pcilib_get_register_bank_attr_by_id(pcilib_t *ctx, pcilib_register_bank_t bank, const char *attr, pcilib_value_t *val);
 int pcilib_get_register_bank_attr(pcilib_t *ctx, const char *bankname, const char *attr, pcilib_value_t *val);
 

+ 1 - 0
pcilib/pcilib.h

@@ -185,6 +185,7 @@ typedef struct {
 #define PCILIB_DMA_FLAGS_DEFAULT	((pcilib_dma_flags_t)0)
 #define PCILIB_DMA_ENGINE_ADDR_INVALID	((pcilib_dma_engine_addr_t)-1)
 #define PCILIB_REGISTER_INVALID		((pcilib_register_t)-1)
+#define PCILIB_REGISTER_ADDRESS_INVALID	((pcilib_register_addr_t)-1)
 #define PCILIB_ADDRESS_INVALID		((uintptr_t)-1)
 #define PCILIB_EVENT0			1
 #define PCILIB_EVENT1			2

+ 33 - 2
protocols/default.c

@@ -7,9 +7,40 @@
 #include "error.h"
 #include "bar.h"
 #include "datacpy.h"
+#include "pci.h"
 
 #define default_datacpy(dst, src, access, bank)   pcilib_datacpy(dst, src, access, 1, bank->raw_endianess)
 
+uintptr_t pcilib_default_resolve(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx, pcilib_address_resolution_flags_t flags, pcilib_register_addr_t reg_addr) {
+    uintptr_t addr;
+    const pcilib_register_bank_description_t *b = bank_ctx->bank;
+
+    if (reg_addr == PCILIB_REGISTER_ADDRESS_INVALID) reg_addr = 0;
+
+    switch (flags&PCILIB_ADDRESS_RESOLUTION_MASK_ACCESS_MODE) {
+     case 0:
+	if (b->read_addr != b->write_addr)
+	    return PCILIB_ADDRESS_INVALID;
+     case PCILIB_ADDRESS_RESOLUTION_FLAG_READ_ONLY:
+	addr = b->read_addr + reg_addr;
+	break;
+     case PCILIB_ADDRESS_RESOLUTION_FLAG_WRITE_ONLY:
+        addr = b->write_addr + reg_addr;
+     default:
+        return PCILIB_ADDRESS_INVALID;
+    }
+
+    switch (flags&PCILIB_ADDRESS_RESOLUTION_MASK_ADDRESS_TYPE) {
+     case 0:
+        return (uintptr_t)pcilib_resolve_bar_address(ctx, b->bar, addr);
+     case PCILIB_ADDRESS_RESOLUTION_FLAG_BUS_ADDRESS:
+     case PCILIB_ADDRESS_RESOLUTION_FLAG_PHYS_ADDRESS:
+        return ctx->board_info.bar_start[b->bar] + addr;
+    }
+
+    return PCILIB_ADDRESS_INVALID;
+}
+
 int pcilib_default_read(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx, pcilib_register_addr_t addr, pcilib_register_value_t *value) {
     char *ptr;
     pcilib_register_value_t val = 0;
@@ -18,7 +49,7 @@ int pcilib_default_read(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx,
 
     int access = b->access / 8;
 
-    ptr =  pcilib_resolve_register_address(ctx, b->bar, b->read_addr + addr);
+    ptr =  pcilib_resolve_bar_address(ctx, b->bar, b->read_addr + addr);
     default_datacpy(&val, ptr, access, b);
 
 //    *value = val&BIT_MASK(bits);
@@ -35,7 +66,7 @@ int pcilib_default_write(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx
 
     int access = b->access / 8;
 
-    ptr =  pcilib_resolve_register_address(ctx, b->bar, b->write_addr + addr);
+    ptr =  pcilib_resolve_bar_address(ctx, b->bar, b->write_addr + addr);
     default_datacpy(ptr, &value, access, b);
 
     return 0;

+ 2 - 1
protocols/default.h

@@ -5,12 +5,13 @@
 #include "version.h"
 #include "model.h"
 
+uintptr_t pcilib_default_resolve(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx, pcilib_address_resolution_flags_t flags, pcilib_register_addr_t addr);
 int pcilib_default_read(pcilib_t *ctx, pcilib_register_bank_context_t *bank, pcilib_register_addr_t addr, pcilib_register_value_t *value);
 int pcilib_default_write(pcilib_t *ctx, pcilib_register_bank_context_t *bank, pcilib_register_addr_t addr, pcilib_register_value_t value);
 
 #ifdef _PCILIB_EXPORT_C
 const pcilib_register_protocol_api_description_t pcilib_default_protocol_api =
-    { PCILIB_VERSION, NULL, NULL, pcilib_default_read, pcilib_default_write };
+    { PCILIB_VERSION, NULL, NULL, pcilib_default_resolve, pcilib_default_read, pcilib_default_write };
 #endif /* _PCILIB_EXPORT_C */
 
 #endif /* _PCILIB_PROTOCOL_DEFAULT_H */

+ 1 - 1
protocols/property.h

@@ -10,7 +10,7 @@ int pcilib_property_registers_write(pcilib_t *ctx, pcilib_register_bank_context_
 
 #ifdef _PCILIB_EXPORT_C
 const pcilib_register_protocol_api_description_t pcilib_property_protocol_api =
-    { PCILIB_VERSION, NULL, NULL, pcilib_property_registers_read, pcilib_property_registers_write };
+    { PCILIB_VERSION, NULL, NULL, NULL, pcilib_property_registers_read, pcilib_property_registers_write };
 #endif /* _PCILIB_EXPORT_C */
 
 #endif /* _PCILIB_PROTOCOL_PROPERTY_H */

+ 15 - 0
protocols/software.c

@@ -105,6 +105,21 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc
 	return (pcilib_register_bank_context_t*)bank_ctx;
 }
 
+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) {
+    if (addr == PCILIB_REGISTER_ADDRESS_INVALID) addr = 0;
+
+    switch (flags&PCILIB_ADDRESS_RESOLUTION_MASK_ADDRESS_TYPE) {
+     case 0:
+        return (uintptr_t)((pcilib_software_register_bank_context_t*)bank_ctx)->addr + addr;
+
+     case PCILIB_ADDRESS_RESOLUTION_FLAG_PHYS_ADDRESS:
+	return pcilib_kmem_get_block_pa(ctx, ((pcilib_software_register_bank_context_t*)bank_ctx)->kmem, 0) + addr;
+    }
+
+    return PCILIB_ADDRESS_INVALID;
+}
+
+
 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){
     const pcilib_register_bank_description_t *b = bank_ctx->bank;
     int access = b->access / 8;

+ 11 - 1
protocols/software.h

@@ -27,6 +27,16 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc
  */
 void pcilib_software_registers_close(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx);
 
+/**
+ * this function resolve the virtual address of the register for direct access
+ * @param[in] - ctx the pcilib_t structure runnning
+ * @param[in] - bank_ctx the bank context that was returned by the initialisation function
+ * @param[in] - flags 
+ * @param[in] - addr the adress of the register we want to read
+ * @return virtual address or PCILIB_ADDRESS_INVALID on error 
+ */
+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);
+
 /**
  * this function read the value of a said register in the kernel space.
  * @param[in] - ctx the pcilib_t structure runnning
@@ -52,7 +62,7 @@ int pcilib_software_registers_write(pcilib_t *ctx,pcilib_register_bank_context_t
  * software protocol addition to the protocol api.
  */
 const pcilib_register_protocol_api_description_t pcilib_software_protocol_api =
-  { PCILIB_VERSION, pcilib_software_registers_open, pcilib_software_registers_close,pcilib_software_registers_read, pcilib_software_registers_write }; /**< we add there the protocol to the list of possible protocols*/
+  { PCILIB_VERSION, pcilib_software_registers_open, pcilib_software_registers_close, pcilib_software_registers_resolve, pcilib_software_registers_read, pcilib_software_registers_write }; 
 #endif /* _PCILIB_EXPORT_C */
 
 #endif /* _PCILIB_PROTOCOL_SOFTWARE_H */