From 55255f2ce3a2234850249efcabd9ba32d0a89a9c Mon Sep 17 00:00:00 2001 From: "Suren A. Chilingaryan" Date: Mon, 19 Oct 2015 15:58:46 +0200 Subject: Support computed (property-based) registers --- pcilib/bank.h | 6 +++-- pcilib/export.c | 9 +++++++- pcilib/export.h | 2 ++ pcilib/property.c | 34 +++++++++++++++++++++++++++-- pcilib/property.h | 20 +++++++++++++++-- pcilib/register.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++-------- pcilib/register.h | 7 +++--- pcilib/view.c | 18 +++++++++++++++ pcilib/view.h | 4 +++- pcilib/xml.c | 38 +++++++++++++++++++++++++++----- 10 files changed, 177 insertions(+), 26 deletions(-) (limited to 'pcilib') diff --git a/pcilib/bank.h b/pcilib/bank.h index ba149b9..2f90321 100644 --- a/pcilib/bank.h +++ b/pcilib/bank.h @@ -8,13 +8,15 @@ #define PCILIB_REGISTER_BANK1 1 #define PCILIB_REGISTER_BANK2 2 #define PCILIB_REGISTER_BANK3 3 -#define PCILIB_REGISTER_BANK_DMA 64 /**< First BANK address to be used by DMA engines */ -#define PCILIB_REGISTER_BANK_DMACONF 65 /**< DMA configuration in the software registers */ +#define PCILIB_REGISTER_BANK_PROPERTY 64 /**< Registers abstracting properties and other computed registers */ +#define PCILIB_REGISTER_BANK_DMA 96 /**< First BANK address to be used by DMA engines */ +#define PCILIB_REGISTER_BANK_DMACONF 96 /**< DMA configuration in the software registers */ #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 */ #define PCILIB_REGISTER_PROTOCOL_DEFAULT 64 /**< Default memmap based protocol */ #define PCILIB_REGISTER_PROTOCOL_SOFTWARE 65 /**< Software registers */ +#define PCILIB_REGISTER_PROTOCOL_PROPERTY 66 /**< Protocol to access registers interfacing properties */ #define PCILIB_REGISTER_PROTOCOL_DMA 96 /**< First PROTOCOL address to be used by DMA engines */ #define PCILIB_REGISTER_PROTOCOL_DYNAMIC 128 /**< First PROTOCOL address to be used by plugins */ diff --git a/pcilib/export.c b/pcilib/export.c index ffb1c4b..8e1a7d2 100644 --- a/pcilib/export.c +++ b/pcilib/export.c @@ -10,13 +10,20 @@ const char *pcilib_data_types[] = { "default", "string", "double", "long" }; #include "protocols/default.h" #include "protocols/software.h" +#include "protocols/property.h" const pcilib_register_protocol_description_t pcilib_protocols[] = { { PCILIB_REGISTER_PROTOCOL_DEFAULT, &pcilib_default_protocol_api, NULL, NULL, "default", "" }, - { PCILIB_REGISTER_PROTOCOL_SOFTWARE, &pcilib_register_software_protocol_api, NULL, NULL, "software_registers", "" }, + { PCILIB_REGISTER_PROTOCOL_SOFTWARE, &pcilib_software_protocol_api, NULL, NULL, "software_registers", "" }, + { PCILIB_REGISTER_PROTOCOL_PROPERTY, &pcilib_property_protocol_api, NULL, NULL, "property_registers", "" }, { 0 } }; +const pcilib_register_bank_description_t pcilib_property_register_bank = + { PCILIB_REGISTER_BANK_PROPERTY, PCILIB_REGISTER_PROTOCOL_PROPERTY, PCILIB_BAR_NOBAR, 0, 0, 32, 0, PCILIB_HOST_ENDIAN, PCILIB_HOST_ENDIAN, "%lu", "property", "Computed registers interfacing properties"}; + + + #include "dma/nwl.h" #include "dma/ipe.h" diff --git a/pcilib/export.h b/pcilib/export.h index 6fb08c3..7d3ff35 100644 --- a/pcilib/export.h +++ b/pcilib/export.h @@ -13,6 +13,8 @@ extern const pcilib_dma_description_t pcilib_dma[]; extern const pcilib_register_protocol_api_description_t pcilib_default_protocol_api; +extern const pcilib_register_bank_description_t pcilib_property_register_bank; + extern const pcilib_dma_description_t pcilib_ipedma; extern const pcilib_dma_description_t pcilib_nwldma; diff --git a/pcilib/property.c b/pcilib/property.c index 276360a..1a20de1 100644 --- a/pcilib/property.c +++ b/pcilib/property.c @@ -15,7 +15,34 @@ #include "tools.h" #include "error.h" -int pcilib_add_register_properties(pcilib_t *ctx, size_t n, const pcilib_register_bank_t *banks, const pcilib_register_description_t *registers) { + +int pcilib_add_registers_from_properties(pcilib_t *ctx, size_t n, pcilib_view_context_t* const *view_ctx, pcilib_view_description_t* const *v) { + pcilib_view_t i; + pcilib_register_t pos = 0; + pcilib_register_description_t regs[n]; + + for (i = 0; i < n; i++) { + if ((v[i]->flags&PCILIB_VIEW_FLAG_REGISTER) == 0) continue; + + regs[pos++] = (pcilib_register_description_t){ + .addr = view_ctx[i]->view, + .bits = 8 * sizeof(pcilib_register_value_t), + .mode = v[i]->mode, + .type = PCILIB_REGISTER_PROPERTY, + .bank = PCILIB_REGISTER_BANK_PROPERTY, + .name = (v[i]->regname?v[i]->regname:v[i]->name), + .description = v[i]->description + }; + } + + if (pos) + return pcilib_add_registers(ctx, 0, pos, regs, NULL); + + return 0; +} + + +int pcilib_add_properties_from_registers(pcilib_t *ctx, size_t n, const pcilib_register_bank_t *banks, const pcilib_register_description_t *registers) { int err; pcilib_register_t i; @@ -26,12 +53,15 @@ int pcilib_add_register_properties(pcilib_t *ctx, size_t n, const pcilib_registe for (i = 0; i < n; i++) { + char *view_name; pcilib_access_mode_t mode = 0; pcilib_register_view_description_t v; pcilib_register_bank_description_t *b = &ctx->banks[banks[i]]; - char *view_name = malloc(strlen(registers[i].name) + strlen(b->name) + 13); + if (registers[i].type == PCILIB_REGISTER_PROPERTY) continue; + + view_name = malloc(strlen(registers[i].name) + strlen(b->name) + 13); if (!view_name) { pcilib_clean_views(ctx, cur_view); return PCILIB_ERROR_MEMORY; diff --git a/pcilib/property.h b/pcilib/property.h index bec11c8..75ec053 100644 --- a/pcilib/property.h +++ b/pcilib/property.h @@ -5,7 +5,7 @@ extern "C" { #endif /** - * This is internal function used to add property view for all model registers. It is automatically + * This is an internal function used to add property view for all model registers. It is automatically * called from pcilib_add_registers and should not be called by the users. On error no new views are * initalized. * @param[in,out] ctx - pcilib context @@ -14,7 +14,23 @@ extern "C" { * @param[in] desc - register descriptions * @return - error or 0 on success */ -int pcilib_add_register_properties(pcilib_t *ctx, size_t n, const pcilib_register_bank_t *banks, const pcilib_register_description_t *desc); +int pcilib_add_properties_from_registers(pcilib_t *ctx, size_t n, const pcilib_register_bank_t *banks, const pcilib_register_description_t *registers); + + +/** + * To reduce number of required interfaces, some of the property views may be also mapped into the + * model as registers. The client application, then, is able to use either register or property APIs + * to access them. This is an internal function which processes the supplied views, finds which views + * have to be mapped in the register space, and finally pushes corresponding registers into the model. + * The function is automatically called from pcilib_add_views and should never be called by the user. + * On error no new registers are added. + * @param[in,out] ctx - pcilib context + * @param[in] n - number of views to analyze. + * @param[in] view_ctx - views to analyze + * @param[in] view - array of pointers to corresponding view descriptions + * @return - error or 0 on success + */ +int pcilib_add_registers_from_properties(pcilib_t *ctx, size_t n, pcilib_view_context_t* const *view_ctx, pcilib_view_description_t* const *view); #ifdef __cplusplus } diff --git a/pcilib/register.c b/pcilib/register.c index 08af871..a166bbd 100644 --- a/pcilib/register.c +++ b/pcilib/register.c @@ -74,8 +74,17 @@ int pcilib_add_registers(pcilib_t *ctx, pcilib_model_modification_flags_t flags, bank_addr = registers[i].bank; bank = pcilib_find_register_bank_by_addr(ctx, bank_addr); if (bank == PCILIB_REGISTER_BANK_INVALID) { - pcilib_error("Invalid bank address (0x%lx) is specified for register %s", bank_addr, registers[i].name); - return PCILIB_ERROR_INVALID_BANK; + // We need to add a bank first in this case + if (registers[i].type == PCILIB_REGISTER_PROPERTY) { + err = pcilib_add_register_banks(ctx, 0, 1, &pcilib_property_register_bank, &bank); + } else { + err = PCILIB_ERROR_INVALID_BANK; + } + + if (err) { + pcilib_error("Invalid bank address (0x%lx) is specified for register %s", bank_addr, registers[i].name); + return err; + } } } @@ -91,7 +100,7 @@ int pcilib_add_registers(pcilib_t *ctx, pcilib_model_modification_flags_t flags, banks[i] = bank; } - err = pcilib_add_register_properties(ctx, n, banks, registers); + err = pcilib_add_properties_from_registers(ctx, n, banks, registers); if (err) return err; for (i = 0; i < n; i++) { @@ -148,7 +157,9 @@ void pcilib_clean_registers(pcilib_t *ctx, pcilib_register_t start) { static int pcilib_read_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, pcilib_register_size_t offset, pcilib_register_size_t bits, pcilib_register_value_t *buf) { int err; + size_t i; + size_t space_size; pcilib_register_bank_context_t *bctx = ctx->bank_ctx[bank]; const pcilib_register_protocol_api_description_t *bapi = bctx->api; @@ -163,14 +174,31 @@ static int pcilib_read_register_space_internal(pcilib_t *ctx, pcilib_register_ba return PCILIB_ERROR_NOTSUPPORTED; } - if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) { + if (b->protocol == PCILIB_REGISTER_PROTOCOL_PROPERTY) space_size = ctx->num_views; + else space_size = b->size; + + if (((addr + n) > space_size)||(((addr + n) == space_size)&&(bits))) { if ((b->format)&&(strchr(b->format, 'x'))) - pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); + pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, space_size); else - pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); + pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, space_size); return PCILIB_ERROR_OUTOFRANGE; } + if (b->protocol == PCILIB_REGISTER_PROTOCOL_PROPERTY) { + for (i = 0; i < (bits?(n+1):n); i++) { + if ((ctx->views[i]->flags&PCILIB_VIEW_FLAG_REGISTER) == 0) { + pcilib_error("Accessing invalid register %u (associated view does not provide register functionality)", addr + i); + return PCILIB_ERROR_INVALID_REQUEST; + } + + if ((ctx->views[i]->mode&PCILIB_ACCESS_R) == 0) { + pcilib_error("Read access is not allowed to register %u", addr + i); + return PCILIB_ERROR_NOTPERMITED; + } + } + } + //err = pcilib_init_register_banks(ctx); //if (err) return err; @@ -259,7 +287,9 @@ int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, p static int pcilib_write_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, pcilib_register_size_t offset, pcilib_register_size_t bits, pcilib_register_value_t rwmask, pcilib_register_value_t *buf) { int err; + size_t i; + size_t space_size; pcilib_register_bank_context_t *bctx = ctx->bank_ctx[bank]; const pcilib_register_protocol_api_description_t *bapi = bctx->api; @@ -274,14 +304,31 @@ static int pcilib_write_register_space_internal(pcilib_t *ctx, pcilib_register_b return PCILIB_ERROR_NOTSUPPORTED; } - if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) { + if (b->protocol == PCILIB_REGISTER_PROTOCOL_PROPERTY) space_size = ctx->num_views; + else space_size = b->size; + + if (((addr + n) > space_size)||(((addr + n) == space_size)&&(bits))) { if ((b->format)&&(strchr(b->format, 'x'))) - pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); + pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, space_size); else - pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); + pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, space_size); return PCILIB_ERROR_OUTOFRANGE; } + if (b->protocol == PCILIB_REGISTER_PROTOCOL_PROPERTY) { + for (i = 0; i < (bits?(n+1):n); i++) { + if ((ctx->views[i]->flags&PCILIB_VIEW_FLAG_REGISTER) == 0) { + pcilib_error("Accessing invalid register %u (associated view does not provide register functionality)", addr + i); + return PCILIB_ERROR_INVALID_REQUEST; + } + + if ((ctx->views[i]->mode&PCILIB_ACCESS_W) == 0) { + pcilib_error("Write access is not allowed to register %u", addr + i); + return PCILIB_ERROR_NOTPERMITED; + } + } + } + //err = pcilib_init_register_banks(ctx); //if (err) return err; diff --git a/pcilib/register.h b/pcilib/register.h index f3df309..0963b22 100644 --- a/pcilib/register.h +++ b/pcilib/register.h @@ -11,9 +11,10 @@ typedef enum { - PCILIB_REGISTER_STANDARD = 0, - PCILIB_REGISTER_FIFO, - PCILIB_REGISTER_BITS + PCILIB_REGISTER_STANDARD = 0, /**< Standard register */ + PCILIB_REGISTER_FIFO, /**< FIFO register */ + PCILIB_REGISTER_BITS, /**< Besides a big standard register, the register bit-fields may be described by bit registers */ + PCILIB_REGISTER_PROPERTY /**< A special register bound to a property and gettings/setting it value through it */ } pcilib_register_type_t; typedef struct { diff --git a/pcilib/view.c b/pcilib/view.c index d14e8aa..e31fdba 100644 --- a/pcilib/view.c +++ b/pcilib/view.c @@ -9,8 +9,11 @@ #include "view.h" #include "error.h" #include "value.h" +#include "property.h" int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_description_t *desc, pcilib_view_context_t **refs) { + int err; + size_t i; void *ptr; @@ -25,6 +28,11 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti } } + if (!refs) { + refs = (pcilib_view_context_t**)alloca(n * sizeof(pcilib_view_context_t*)); + if (!refs) return PCILIB_ERROR_MEMORY; + } + if ((ctx->num_views + n + 1) > ctx->alloc_views) { size_t size; pcilib_view_description_t **views; @@ -48,6 +56,7 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti pcilib_view_t view = pcilib_find_view_by_name(ctx, v->name); if (view != PCILIB_VIEW_INVALID) { + ctx->views[ctx->num_views + i] = NULL; pcilib_clean_views(ctx, ctx->num_views); pcilib_error("View %s is already defined in the model", v->name); return PCILIB_ERROR_EXIST; @@ -55,6 +64,7 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti cur = (pcilib_view_description_t*)malloc(v->api->description_size); if (!cur) { + ctx->views[ctx->num_views + i] = NULL; pcilib_clean_views(ctx, ctx->num_views); return PCILIB_ERROR_MEMORY; } @@ -68,6 +78,7 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti if (!view_ctx) { free(cur); + ctx->views[ctx->num_views + i] = NULL; pcilib_clean_views(ctx, ctx->num_views); return PCILIB_ERROR_FAILED; } @@ -85,6 +96,13 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti } ctx->views[ctx->num_views + n] = NULL; + + err = pcilib_add_registers_from_properties(ctx, n, refs, ctx->views + ctx->num_views); + if (err) { + pcilib_clean_views(ctx, ctx->num_views); + return err; + } + ctx->num_views += n; return 0; diff --git a/pcilib/view.h b/pcilib/view.h index ec775b7..33d4d96 100644 --- a/pcilib/view.h +++ b/pcilib/view.h @@ -12,7 +12,8 @@ typedef struct pcilib_view_context_s pcilib_view_context_t; typedef struct pcilib_view_description_s pcilib_view_description_t; typedef enum { - PCILIB_VIEW_FLAG_PROPERTY = 1 /**< Indicates that view does not depend on a value and is independent property */ + PCILIB_VIEW_FLAG_PROPERTY = 1, /**< Indicates that view does not depend on a value and is independent property */ + PCILIB_VIEW_FLAG_REGISTER = 2 /**< Indicates that view does not depend on a value and should be mapped to the register space */ } pcilib_view_flags_t; typedef struct { @@ -32,6 +33,7 @@ struct pcilib_view_description_s { pcilib_access_mode_t mode; /**< Specifies if the view is read/write-only */ const char *unit; /**< Returned unit (if any) */ const char *name; /**< Name of the view */ + const char *regname; /**< Specifies the register name if the view should be mapped to register space */ const char *description; /**< Short description */ }; diff --git a/pcilib/xml.c b/pcilib/xml.c index b022fd8..1238ba8 100644 --- a/pcilib/xml.c +++ b/pcilib/xml.c @@ -184,12 +184,16 @@ static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_descript desc->mode = PCILIB_REGISTER_W; } else if (!strcasecmp(value, "RW")) { desc->mode = PCILIB_REGISTER_RW; - } else if (!strcasecmp(value, "W")) { - desc->mode = PCILIB_REGISTER_W; } else if (!strcasecmp(value, "RW1C")) { desc->mode = PCILIB_REGISTER_RW1C; } else if (!strcasecmp(value, "W1C")) { desc->mode = PCILIB_REGISTER_W1C; + } else if (!strcasecmp(value, "RW1I")) { + desc->mode = PCILIB_REGISTER_RW1I; + } else if (!strcasecmp(value, "W1I")) { + desc->mode = PCILIB_REGISTER_W1I; + } else if (!strcasecmp(value, "-")) { + desc->mode = 0; } else { pcilib_error("Invalid access mode (%s) is specified in the XML register description", value); return PCILIB_ERROR_INVALID_DATA; @@ -487,11 +491,16 @@ static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDoc if (!strcasecmp(name, "name")) { // Overriden by path - if (!desc->name) - desc->name = value; + if (desc->name) continue; + if (*value == '/') + desc->flags |= PCILIB_VIEW_FLAG_PROPERTY; + desc->name = value; } else if (!strcasecmp(name, "path")) { desc->name = value; desc->flags |= PCILIB_VIEW_FLAG_PROPERTY; + } else if (!strcasecmp(name, "register")) { + desc->regname = value; + desc->flags |= PCILIB_VIEW_FLAG_REGISTER; } else if (!strcasecmp((char*)name, "description")) { desc->description = value; } else if (!strcasecmp((char*)name, "unit")) { @@ -504,6 +513,19 @@ static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDoc pcilib_error("Invalid type (%s) of register view is specified in the XML bank description", value); return PCILIB_ERROR_INVALID_DATA; } + } else if (!strcasecmp(name, "mode")) { + if (!strcasecmp(value, "R")) { + desc->mode = PCILIB_REGISTER_R; + } else if (!strcasecmp(value, "W")) { + desc->mode = PCILIB_REGISTER_W; + } else if (!strcasecmp(value, "RW")) { + desc->mode = PCILIB_REGISTER_RW; + } else if (!strcasecmp(value, "-")) { + desc->mode = 0; + } else { + pcilib_error("Invalid access mode (%s) is specified in the XML register description", value); + return PCILIB_ERROR_INVALID_DATA; + } } } @@ -516,10 +538,12 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp const char *value, *name; pcilib_view_context_t *view_ctx; + pcilib_access_mode_t mode = 0; pcilib_transform_view_description_t desc = {0}; desc.base.api = &pcilib_transform_view_api; desc.base.type = PCILIB_TYPE_DOUBLE; + desc.base.mode = PCILIB_ACCESS_RW; err = pcilib_xml_parse_view(ctx, xpath, doc, node, (pcilib_view_description_t*)&desc); if (err) return err; @@ -540,7 +564,7 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp } } desc.read_from_reg = value; - if ((value)&&(*value)) desc.base.mode |= PCILIB_ACCESS_R; + if ((value)&&(*value)) mode |= PCILIB_ACCESS_R; } else if (!strcasecmp(name, "write_to_register")) { if (desc.base.flags&PCILIB_VIEW_FLAG_PROPERTY) { if (strstr(value, "$value")) { @@ -549,10 +573,12 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp } } desc.write_to_reg = value; - if ((value)&&(*value)) desc.base.mode |= PCILIB_ACCESS_W; + if ((value)&&(*value)) mode |= PCILIB_ACCESS_W; } } + desc.base.mode &= mode; + err = pcilib_add_views_custom(ctx, 1, (pcilib_view_description_t*)&desc, &view_ctx); if (err) return err; -- cgit v1.2.3