123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- #include <stdio.h>
- #include <string.h>
- #include <strings.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <stdarg.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- #include <sys/mman.h>
- #include <arpa/inet.h>
- #include <errno.h>
- #include <assert.h>
- #include "pci.h"
- #include "tools.h"
- #include "error.h"
- int pcilib_init_register_banks(pcilib_t *ctx) {
- int err;
- size_t start = ctx->num_banks_init;
- err = pcilib_map_register_space(ctx);
- if (err) return err;
- for (; ctx->num_banks_init < ctx->num_banks; ctx->num_banks_init++) {
- pcilib_register_bank_context_t *bank_ctx;
- pcilib_register_protocol_t protocol;
- const pcilib_register_protocol_api_description_t *bapi;
- protocol = pcilib_find_register_protocol_by_addr(ctx, ctx->banks[ctx->num_banks_init].protocol);
- if (protocol == PCILIB_REGISTER_PROTOCOL_INVALID) {
- const char *name = ctx->banks[ctx->num_banks_init].name;
- if (!name) name = "unnamed";
- pcilib_error("Invalid register protocol address (%u) is specified for bank %i (%s)", ctx->banks[ctx->num_banks_init].protocol, ctx->banks[ctx->num_banks_init].addr, name);
- pcilib_free_register_banks(ctx, start);
- return PCILIB_ERROR_INVALID_BANK;
- }
-
- bapi = ctx->protocols[protocol].api;
- if (bapi->init) {
- const char *model = ctx->protocols[protocol].model;
- if (!model) model = ctx->model;
- bank_ctx = bapi->init(ctx, ctx->num_banks_init, model, ctx->protocols[protocol].args);
- } else
- bank_ctx = (pcilib_register_bank_context_t*)malloc(sizeof(pcilib_register_bank_context_t));
-
- if (!bank_ctx) {
- pcilib_free_register_banks(ctx, start);
- return PCILIB_ERROR_FAILED;
- }
-
- bank_ctx->bank = ctx->banks + ctx->num_banks_init;
- bank_ctx->api = bapi;
- bank_ctx->xml = ctx->xml.bank_nodes[ctx->num_banks_init];
- ctx->bank_ctx[ctx->num_banks_init] = bank_ctx;
- }
- return 0;
- }
- void pcilib_free_register_banks(pcilib_t *ctx, pcilib_register_bank_t start) {
- size_t i;
- for (i = start; i < ctx->num_banks_init; i++) {
- const pcilib_register_protocol_api_description_t *bapi = ctx->bank_ctx[i]->api;
-
- if (ctx->bank_ctx[i]) {
- if (bapi->free)
- bapi->free(ctx, ctx->bank_ctx[i]);
- else
- free(ctx->bank_ctx[i]);
-
- ctx->bank_ctx[i] = NULL;
- }
- }
- ctx->num_banks_init = start;
- }
- int pcilib_add_register_banks(pcilib_t *ctx, pcilib_model_modification_flags_t flags, size_t n, const pcilib_register_bank_description_t *banks, pcilib_register_bank_t *ids) {
- int err;
- size_t i;
- pcilib_register_bank_t bank;
- size_t dyn_banks = ctx->dyn_banks;
- size_t num_banks = ctx->num_banks;
- size_t cur_banks = num_banks;
-
- if (!n) {
- for (n = 0; banks[n].access; n++);
- }
- if ((ctx->num_banks + n + 1) > PCILIB_MAX_REGISTER_BANKS)
- return PCILIB_ERROR_TOOBIG;
- for (i = 0; i < n; i++) {
- // Try to find if the bank is already existing...
- bank = pcilib_find_register_bank_by_name(ctx, banks[i].name);
- if ((bank == PCILIB_REGISTER_BANK_INVALID)&&(banks[i].addr != PCILIB_REGISTER_BANK_DYNAMIC))
- bank = pcilib_find_register_bank_by_addr(ctx, banks[i].addr);
- if (bank == PCILIB_REGISTER_BANK_INVALID) {
- bank = num_banks++;
- } else if (flags&PCILIB_MODEL_MODIFICATION_FLAG_SKIP_EXISTING) {
- if (ids) ids[i] = bank;
- continue;
- } else if ((flags&PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE) == 0) {
- if (pcilib_find_register_bank_by_name(ctx, banks[i].name) == PCILIB_REGISTER_BANK_INVALID)
- pcilib_error("The bank %s is already existing and override flag is not set", banks[i].name);
- else
- pcilib_error("The bank with address 0x%lx is already existing and override flag is not set", banks[i].addr);
- memset(ctx->banks + ctx->num_banks, 0, sizeof(pcilib_register_bank_description_t));
- return PCILIB_ERROR_EXIST;
- }
-
- memcpy(ctx->banks + bank, banks + i, sizeof(pcilib_register_bank_description_t));
- if (ids) ids[i] = bank;
-
- if (banks[i].addr == PCILIB_REGISTER_BANK_DYNAMIC) {
- ctx->banks[bank].addr = PCILIB_REGISTER_BANK_DYNAMIC + dyn_banks + 1;
- dyn_banks++;
- }
- }
- ctx->num_banks = num_banks;
- // If banks are already initialized, we need to re-run the initialization code
- if (ctx->reg_bar_mapped) {
- ctx->reg_bar_mapped = 0;
- err = pcilib_init_register_banks(ctx);
- if (err) {
- ctx->num_banks = cur_banks;
- memset(ctx->banks + ctx->num_banks, 0, sizeof(pcilib_register_bank_description_t));
- return err;
- }
- }
- ctx->dyn_banks = dyn_banks;
- return 0;
- }
- int pcilib_add_register_protocols(pcilib_t *ctx, pcilib_model_modification_flags_t flags, size_t n, const pcilib_register_protocol_description_t *protocols, pcilib_register_protocol_t *ids) {
- // DS: Override existing banks
-
- if (!n) {
- for (n = 0; protocols[n].api; n++);
- }
- if ((ctx->num_protocols + n + 1) > PCILIB_MAX_REGISTER_PROTOCOLS)
- return PCILIB_ERROR_TOOBIG;
-
- memcpy(ctx->protocols + ctx->num_protocols, protocols, n * sizeof(pcilib_register_protocol_description_t));
- ctx->num_protocols += n;
- return 0;
- }
- int pcilib_add_register_ranges(pcilib_t *ctx, pcilib_model_modification_flags_t flags, size_t n, const pcilib_register_range_t *ranges) {
- if (!n) {
- for (n = 0; ranges[n].end; n++);
- }
- if ((ctx->num_ranges + n + 1) > PCILIB_MAX_REGISTER_RANGES)
- return PCILIB_ERROR_TOOBIG;
-
- memcpy(ctx->ranges + ctx->num_ranges, ranges, n * sizeof(pcilib_register_range_t));
- ctx->num_ranges += n;
- return 0;
- }
- pcilib_register_bank_t pcilib_find_register_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) {
- pcilib_register_bank_t i;
- for (i = 0; ctx->banks[i].access; i++)
- if (ctx->banks[i].addr == bank) return i;
- return PCILIB_REGISTER_BANK_INVALID;
- }
- pcilib_register_bank_t pcilib_find_register_bank_by_name(pcilib_t *ctx, const char *bankname) {
- pcilib_register_bank_t i;
- for (i = 0; ctx->banks[i].access; i++)
- if (!strcasecmp(ctx->banks[i].name, bankname)) return i;
- return PCILIB_REGISTER_BANK_INVALID;
- }
- pcilib_register_bank_t pcilib_find_register_bank(pcilib_t *ctx, const char *bank) {
- pcilib_register_bank_t res;
- unsigned long addr;
-
- if (!bank) {
- const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
- const pcilib_register_bank_description_t *banks = model_info->banks;
- if ((banks)&&(banks[0].access)) return (pcilib_register_bank_t)0;
- return PCILIB_REGISTER_BANK_INVALID;
- }
-
- if (pcilib_isxnumber(bank)&&(sscanf(bank,"%lx", &addr) == 1)) {
- res = pcilib_find_register_bank_by_addr(ctx, addr);
- if (res != PCILIB_REGISTER_BANK_INVALID) return res;
- }
-
- return pcilib_find_register_bank_by_name(ctx, bank);
- }
- // DS: FIXME create hash during map_register space
- pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const char *reg) {
- pcilib_register_t i;
- pcilib_register_bank_t bank_id;
- pcilib_register_bank_addr_t bank_addr = 0;
- pcilib_register_context_t *reg_ctx;
- const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
- const pcilib_register_description_t *registers = model_info->registers;
-
- if (bank) {
- bank_id = pcilib_find_register_bank(ctx, bank);
- if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
- pcilib_error("Invalid bank (%s) is specified", bank);
- return PCILIB_REGISTER_INVALID;
- }
-
- bank_addr = model_info->banks[bank_id].addr;
- // ToDo: we can use additionaly per-bank hashes
- for (i = 0; registers[i].bits; i++) {
- if ((!strcasecmp(registers[i].name, reg))&&((!bank)||(registers[i].bank == bank_addr))) return i;
- }
- } else {
- HASH_FIND_STR(ctx->reg_hash, reg, reg_ctx);
- if (reg_ctx) return reg_ctx->reg;
- }
- return PCILIB_REGISTER_INVALID;
- };
- pcilib_register_protocol_t pcilib_find_register_protocol_by_addr(pcilib_t *ctx, pcilib_register_protocol_addr_t protocol) {
- pcilib_register_protocol_t i;
- for (i = 0; ctx->protocols[i].api; i++)
- if (ctx->protocols[i].addr == protocol) return i;
- return PCILIB_REGISTER_PROTOCOL_INVALID;
- }
- pcilib_register_protocol_t pcilib_find_register_protocol_by_name(pcilib_t *ctx, const char *name) {
- pcilib_register_protocol_t i;
- for (i = 0; ctx->protocols[i].api; i++)
- if (!strcasecmp(ctx->protocols[i].name, name)) return i;
- return PCILIB_REGISTER_PROTOCOL_INVALID;
- }
- pcilib_register_protocol_t pcilib_find_register_protocol(pcilib_t *ctx, const char *protocol) {
- pcilib_register_bank_t res;
- unsigned long addr;
- if (pcilib_isxnumber(protocol)&&(sscanf(protocol,"%lx", &addr) == 1)) {
- res = pcilib_find_register_protocol_by_addr(ctx, addr);
- if (res != PCILIB_REGISTER_BANK_INVALID) return res;
- }
- 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);
- return pcilib_get_xml_attr(ctx, ctx->bank_ctx[bank]->xml, attr, val);
- }
- int pcilib_get_register_bank_attr(pcilib_t *ctx, const char *bankname, const char *attr, pcilib_value_t *val) {
- pcilib_register_bank_t bank;
- bank = pcilib_find_register_bank_by_name(ctx, bankname);
- if (bank == PCILIB_REGISTER_BANK_INVALID) {
- pcilib_error("Bank (%s) is not found", bankname);
- return PCILIB_ERROR_NOTFOUND;
- }
- return pcilib_get_register_bank_attr_by_id(ctx, bank, attr, val);
- }
|