aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@nvidia.com>2021-10-12 16:25:21 +0300
committerMichal Kubecek <mkubecek@suse.cz>2021-11-08 18:17:57 +0100
commit2ccda2570d6508520e73ce0e7598e978cac3d94e (patch)
treeb772a4435a4ed7e88d85e2b365f19d54f13ea446
parent9fdf45ca172678ae6717bd593ea9fa4cf6bfcb90 (diff)
downloadethtool-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.h11
-rw-r--r--netlink/module-eeprom.c105
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;
}