diff options
author | Ido Schimmel <idosch@nvidia.com> | 2021-10-12 16:25:21 +0300 |
---|---|---|
committer | Michal Kubecek <mkubecek@suse.cz> | 2021-11-08 18:17:57 +0100 |
commit | 2ccda2570d6508520e73ce0e7598e978cac3d94e (patch) | |
tree | b772a4435a4ed7e88d85e2b365f19d54f13ea446 | |
parent | 9fdf45ca172678ae6717bd593ea9fa4cf6bfcb90 (diff) | |
download | ethtool-2ccda2570d6508520e73ce0e7598e978cac3d94e.tar.gz |
netlink: eeprom: Export a function to request an EEPROM page
The function will be used by the EEPROM parsing code (e.g., cmis.c) to
request a specific page for parsing.
All the data buffers used to store EEPROM page contents are stored on a
linked list that is flushed on exit. This relieves callers from the need
to explicitly free the requested pages.
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
-rw-r--r-- | netlink/extapi.h | 11 | ||||
-rw-r--r-- | netlink/module-eeprom.c | 105 |
2 files changed, 116 insertions, 0 deletions
diff --git a/netlink/extapi.h b/netlink/extapi.h index 91bf02b..129e293 100644 --- a/netlink/extapi.h +++ b/netlink/extapi.h @@ -48,6 +48,9 @@ int nl_getmodule(struct cmd_context *ctx); void nl_monitor_usage(void); +int nl_get_eeprom_page(struct cmd_context *ctx, + struct ethtool_module_eeprom *request); + #else /* ETHTOOL_ENABLE_NETLINK */ static inline void netlink_run_handler(struct cmd_context *ctx __maybe_unused, @@ -73,6 +76,14 @@ static inline void nl_monitor_usage(void) { } +static inline int +nl_get_eeprom_page(struct cmd_context *ctx __maybe_unused, + struct ethtool_module_eeprom *request __maybe_unused) +{ + fprintf(stderr, "Netlink not supported by ethtool.\n"); + return -EOPNOTSUPP; +} + #define nl_gset NULL #define nl_sset NULL #define nl_permaddr NULL diff --git a/netlink/module-eeprom.c b/netlink/module-eeprom.c index 101d594..ee55088 100644 --- a/netlink/module-eeprom.c +++ b/netlink/module-eeprom.c @@ -341,6 +341,110 @@ static void decoder_print(void) } #endif +static struct list_head eeprom_page_list = LIST_HEAD_INIT(eeprom_page_list); + +struct eeprom_page_entry { + struct list_head list; /* Member of eeprom_page_list */ + void *data; +}; + +static int eeprom_page_list_add(void *data) +{ + struct eeprom_page_entry *entry; + + entry = malloc(sizeof(*entry)); + if (!entry) + return -ENOMEM; + + entry->data = data; + list_add(&entry->list, &eeprom_page_list); + + return 0; +} + +static void eeprom_page_list_flush(void) +{ + struct eeprom_page_entry *entry; + struct list_head *head, *next; + + list_for_each_safe(head, next, &eeprom_page_list) { + entry = (struct eeprom_page_entry *) head; + free(entry->data); + list_del(head); + free(entry); + } +} + +static int get_eeprom_page_reply_cb(const struct nlmsghdr *nlhdr, void *data) +{ + const struct nlattr *tb[ETHTOOL_A_MODULE_EEPROM_DATA + 1] = {}; + struct ethtool_module_eeprom *request = data; + DECLARE_ATTR_TB_INFO(tb); + u8 *eeprom_data; + int ret; + + ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info); + if (ret < 0) + return ret; + + if (!tb[ETHTOOL_A_MODULE_EEPROM_DATA]) + return MNL_CB_ERROR; + + eeprom_data = mnl_attr_get_payload(tb[ETHTOOL_A_MODULE_EEPROM_DATA]); + request->data = malloc(request->length); + if (!request->data) + return MNL_CB_ERROR; + memcpy(request->data, eeprom_data, request->length); + + ret = eeprom_page_list_add(request->data); + if (ret < 0) + goto err_list_add; + + return MNL_CB_OK; + +err_list_add: + free(request->data); + return MNL_CB_ERROR; +} + +int nl_get_eeprom_page(struct cmd_context *ctx, + struct ethtool_module_eeprom *request) +{ + struct nl_context *nlctx = ctx->nlctx; + struct nl_socket *nlsock; + struct nl_msg_buff *msg; + int ret; + + if (!request || request->i2c_address > ETH_I2C_MAX_ADDRESS) + return -EINVAL; + + nlsock = nlctx->ethnl_socket; + msg = &nlsock->msgbuff; + + ret = nlsock_prep_get_request(nlsock, ETHTOOL_MSG_MODULE_EEPROM_GET, + ETHTOOL_A_MODULE_EEPROM_HEADER, 0); + if (ret < 0) + return ret; + + if (ethnla_put_u32(msg, ETHTOOL_A_MODULE_EEPROM_LENGTH, + request->length) || + ethnla_put_u32(msg, ETHTOOL_A_MODULE_EEPROM_OFFSET, + request->offset) || + ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_PAGE, + request->page) || + ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_BANK, + request->bank) || + ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS, + request->i2c_address)) + return -EMSGSIZE; + + ret = nlsock_sendmsg(nlsock, NULL); + if (ret < 0) + return ret; + return nlsock_process_reply(nlsock, get_eeprom_page_reply_cb, + (void *)request); +} + int nl_getmodule(struct cmd_context *ctx) { struct cmd_params getmodule_cmd_params = {}; @@ -425,6 +529,7 @@ int nl_getmodule(struct cmd_context *ctx) } cleanup: + eeprom_page_list_flush(); cache_free(); return ret; } |