diff options
Diffstat (limited to 'mpm/tools/tlv_eeprom/eeprom-init.c')
-rw-r--r-- | mpm/tools/tlv_eeprom/eeprom-init.c | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/mpm/tools/tlv_eeprom/eeprom-init.c b/mpm/tools/tlv_eeprom/eeprom-init.c new file mode 100644 index 000000000..6cca434fc --- /dev/null +++ b/mpm/tools/tlv_eeprom/eeprom-init.c @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2019 Ettus Research, a National Instruments Brand + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "tlv_eeprom.h" +#include "tlv_eeprom_io.h" +#include "usrp_eeprom.h" + +#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((*x))) + +int parse_board_info(int argc, char **argv, void *data) +{ + struct usrp_eeprom_board_info *info = data; + + if (!argc) { + sprintf(data, "<pid> <rev> <compat_rev> <serial>"); + return 0; + } + + assert(argc >= 4); + + info->pid = strtoul(argv[0], NULL, 0); + info->rev = strtoul(argv[1], NULL, 0); + info->compat_rev = strtoul(argv[2], NULL, 0); + strncpy(info->serial, argv[3], 8); + info->serial[7] = '\0'; + + return 4; +} +static struct usrp_eeprom_board_info board_info; + +int parse_module_info(int argc, char **argv, void *data) +{ + struct usrp_eeprom_module_info *info = data; + + if (!argc) { + sprintf(data, "<pid> <rev> <serial>"); + return 0; + } + + assert(argc >= 3); + + info->pid = strtoul(argv[0], NULL, 0); + info->rev = strtoul(argv[1], NULL, 0); + strncpy(info->serial, argv[2], 8); + info->serial[7] = '\0'; + + return 3; +} +static struct usrp_eeprom_module_info module_info; + +int parse_mac(int argc, char **argv, void *data) +{ + struct usrp_eeprom_mac_addr *mac = data; + int ret; + + if (!argc) { + sprintf(data, "<mac_addr>"); + return 0; + } + + assert(argc >= 1); + + ret = sscanf(*argv, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + mac->addr + 0, mac->addr + 1, mac->addr + 2, + mac->addr + 3, mac->addr + 4, mac->addr + 5); + assert(ret == 6); + + return 1; +} +static struct usrp_eeprom_mac_addr mac_addrs[USRP_EEPROM_MAX_MAC_ADDRS]; + +int parse_db_pwr_seq(int argc, char **argv, void *data) +{ + struct usrp_eeprom_db_pwr_seq *seq = data; + uint8_t i; + + if (!argc) { + sprintf(data, "<nsteps> [delay supply_mask]..."); + return 0; + } + + assert(argc >= 1); + seq->nsteps = strtoul(argv[0], NULL, 0); + assert(argc >= 1 + (2 * seq->nsteps)); + + argv++; + for (i = 0; i < seq->nsteps; i++) { + seq->steps[i].delay = strtoul(*argv++, NULL, 0); + seq->steps[i].supply_mask = strtoul(*argv++, NULL, 0); + } + + return 1 + 2 * i; +} +static struct usrp_eeprom_db_pwr_seq db_pwr_seq; + +int parse_mcu_flags(int argc, char **argv, void *data) +{ + struct usrp_eeprom_mcu_flags *flags = data; + unsigned long tmp; + int i; + + if (!argc) { + sprintf(data, "<flags[0]> <flags[1]> <flags[2]> " + "<flags[3]> <flags[4]> <flags[5]>"); + return 0; + } + + assert(argc >= ARRAY_SIZE(flags->flags)); + for (i = 0; i < ARRAY_SIZE(flags->flags); i++) { + tmp = strtoul(argv[i], NULL, 0); + assert(tmp <= 0xFF); + + flags->flags[i] = tmp; + } + + return i; +} +static struct usrp_eeprom_mcu_flags mcu_flags; + +int parse_fan_limits(int argc, char **argv, void *data) +{ + struct usrp_eeprom_fan_limits *fan_limits = data; + int i; + + if (!argc) { + sprintf(data, "<fan min rpm> <fan start rpm> <fan max rpm>"); + return 0; + } + + assert(argc >= 3); + fan_limits->min = strtoul(argv[0], NULL, 0); + fan_limits->start = strtoul(argv[1], NULL, 0); + fan_limits->max = strtoul(argv[2], NULL, 0); + + return 3; +} +static struct usrp_eeprom_fan_limits fan_limits; + +int parse_fan_fixed_capacity(int argc, char **argv, void *data) +{ + struct usrp_eeprom_fan_fixed_capacity *fan_fixed_capacity = data; + + if (!argc) { + sprintf(data, "<fan fixed capacity>"); + return 0; + } + + fan_fixed_capacity->capacity = strtoul(argv[0], NULL, 0); + + return 1; +} +static struct usrp_eeprom_fan_fixed_capacity fan_fixed_capacity; + +int parse_clkaux_tuning_word(int argc, char **argv, void *data) +{ + struct usrp_eeprom_clkaux_tuning_word *clkaux_tuning_word = data; + + if (!argc) { + sprintf(data, "<dac tuning word>"); + return 0; + } + + clkaux_tuning_word->tuning_word = strtoul(argv[0], NULL, 0); + + return 1; +} +static struct usrp_eeprom_clkaux_tuning_word clkaux_tuning_word; + +struct arg_parser { + const char *arg; + const char *alias; + void *store; + size_t size; + uint8_t tag; + int (*parse)(int, char **, void *); + int dirty; +}; + +#define PARSER_(name_, alias_, data_, tag_, parser_) { \ + .arg = #name_, \ + .alias = alias_, \ + .store = &(data_), \ + .size = sizeof((data_)), \ + .tag = (tag_), \ + .parse = (parser_), \ +} + +#define PARSER(param_, tag_) PARSER_(param_, NULL, param_, tag_, parse_ ##param_) +#define MAC_PARSER_ALIAS(idx_, alias_) PARSER_( mac_addr_ ## idx_, (alias_), mac_addrs[(idx_)], USRP_EEPROM_MAC_ADDR_TAG((idx_)), parse_mac) +#define MAC_PARSER(idx_) MAC_PARSER_ALIAS(idx_, NULL) + +static struct arg_parser parsers[] = { + PARSER(board_info, USRP_EEPROM_BOARD_INFO_TAG), + PARSER(module_info, USRP_EEPROM_MODULE_INFO_TAG), + MAC_PARSER_ALIAS(0, "eth0_mac"), + MAC_PARSER_ALIAS(1, "qsfp0_mac"), + MAC_PARSER_ALIAS(2, "qsfp1_mac"), + MAC_PARSER(3), + MAC_PARSER(4), + MAC_PARSER(5), + MAC_PARSER(6), + MAC_PARSER(7), + MAC_PARSER(8), + MAC_PARSER(9), + MAC_PARSER(10), + MAC_PARSER(11), + MAC_PARSER(12), + PARSER(db_pwr_seq, USRP_EEPROM_DB_PWR_SEQ_TAG), + PARSER(mcu_flags, USRP_EEPROM_MCU_FLAGS), + PARSER(fan_limits, USRP_EEPROM_FAN_LIMITS), + PARSER(fan_fixed_capacity, USRP_EEPROM_FAN_FIXED_CAPACITY), + PARSER(clkaux_tuning_word, USRP_EEPROM_CLKAUX_TUNING_WORD), +}; + +static struct arg_parser *parser_lookup(const char *arg) +{ + for (size_t i = 0; i < ARRAY_SIZE(parsers); i++) { + if (!strcmp(parsers[i].arg, arg)) + return parsers + i; + if (parsers[i].alias && !strcmp(parsers[i].alias, arg)) + return parsers + i; + } + + return NULL; +} + +#ifdef TLV_EEPROM_UPDATE +static void tlv_update(uint8_t tag, uint8_t len, const void *val) +{ + struct arg_parser *parser = NULL; + + for (size_t i = 0; i < ARRAY_SIZE(parsers); i++) { + if (parsers[i].tag == tag) + parser = parsers + i; + } + + if (!parser) { + fprintf(stderr, "found unknown tag %02x len %u", tag, len); + fprintf(stderr, "cannot use this utility to update\n"); + exit(EXIT_FAILURE); + } + + assert(len == parser->size); + memcpy(parser->store, val, len); + parser->dirty = 1; +} + +static void handle_update(const char *filename) +{ + struct tlv_eeprom *eeprom; + + eeprom = tlv_eeprom_read_from_file(filename); + if (!eeprom) { + perror("failed to read"); + exit(EXIT_FAILURE); + } + + if (tlv_eeprom_validate(eeprom, USRP_EEPROM_MAGIC)) { + fprintf(stderr, "contents invalid, cannot update\n"); + exit(EXIT_FAILURE); + } + + tlv_for_each(eeprom->tlv, eeprom->size, tlv_update); + free(eeprom); +} +#else +static void handle_update(const char *filename) +{ +} +#endif + +static void validate_file_matches(const struct tlv_eeprom *eeprom, + const char *filename) +{ + struct tlv_eeprom *file_eeprom; + + file_eeprom = tlv_eeprom_read_from_file(filename); + if (!file_eeprom) { + perror("failed to read for validate"); + exit(EXIT_FAILURE); + } + + if (memcmp(file_eeprom, eeprom, sizeof(*eeprom))) { + fprintf(stderr, "eeprom validation failed! " + "values read do not match what was written. " + "perhaps the eeprom was write-protected?\n"); + exit(EXIT_FAILURE); + } + + free(file_eeprom); +} + +static void usage(const char *argv0) +{ + const struct arg_parser *p; + char buffer[4096]; + + fprintf(stderr, "usage: %s <output_file>\n", argv0); + for (size_t i = 0; i < ARRAY_SIZE(parsers); i++) { + p = parsers + i; + p->parse(0, NULL, buffer); + fprintf(stderr, "\t--%s %s\n", p->arg, buffer); + } +} + +int main(int argc, char **argv) +{ + struct arg_parser *parser; + const char *output_file; + struct tlv_eeprom eeprom; + uint8_t *ptr; + int ret; + + if (argc < 2) { + usage(argv[0]); + return 1; + } + + output_file = argv[1]; + handle_update(output_file); + + argc -= 2; + argv += 2; + + while (argc > 0) { + if (strncmp("--", *argv, 2)) { + fprintf(stderr, "unexpected arg\n"); + return 1; + } + + *argv += 2; + parser = parser_lookup(*argv); + if (!parser) { + fprintf(stderr, "unknown type: %s\n", *argv); + return 1; + } + + argc--; + argv++; + + ret = parser->parse(argc, argv, parser->store); + if (ret < 0) { + fprintf(stderr, "parsing failed\n"); + return 1; + } + parser->dirty = 1; + + argc -= ret; + argv += ret; + } + + /* + * Now that the data's been parsed, write back any changed fields + */ + memset(&eeprom, 0, sizeof(eeprom)); + ptr = eeprom.tlv; + for (size_t i = 0; i < ARRAY_SIZE(parsers); i++) { + parser = parsers + i; + if (!parser->dirty) + continue; + ptr += tlv_write(ptr, parser->tag, parser->size, parser->store); + } + + tlv_eeprom_seal(&eeprom, USRP_EEPROM_MAGIC, ptr - eeprom.tlv); + tlv_eeprom_write_to_file(&eeprom, output_file); + validate_file_matches(&eeprom, output_file); + + return 0; +} |