All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ido Schimmel <idosch@idosch.org>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, kuba@kernel.org, jiri@nvidia.com,
	andrew@lunn.ch, vladyslavt@nvidia.com, moshe@nvidia.com,
	vadimp@nvidia.com, mkubecek@suse.cz, mlxsw@nvidia.com,
	Ido Schimmel <idosch@nvidia.com>
Subject: [RFC PATCH ethtool-next 2/2] ethtool: Add ability to write to transceiver module EEPROM
Date: Wed, 23 Jun 2021 11:08:25 +0300	[thread overview]
Message-ID: <20210623080825.2612270-3-idosch@idosch.org> (raw)
In-Reply-To: <20210623080825.2612270-1-idosch@idosch.org>

From: Ido Schimmel <idosch@nvidia.com>

Implement support for writing to a transceiver module EEPROM using the
'ETHTOOL_MSG_MODULE_EEPROM_SET' message. While the netlink API allows
for multi-byte writes, the command line interface is limited to
single-byte writes. Example:

 # ethtool -M swp11 offset 0x80 page 3 bank 0 i2c 0x50 value 0x44

This is in accordance with the '-E' option which allows changing a byte
in the EEPROM of a network device.

Upon a successful write, a 'ETHTOOL_MSG_MODULE_EEPROM_NTF' notification
is sent to user space. Example:

 # ethtool --monitor
 listening...

 Module EEPROM write for swp11:
 offset: 128
 length: 1
 page: 3
 bank: 0
 i2c address: 0x50

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 ethtool.8.in            |  29 ++++++++++
 ethtool.c               |  10 ++++
 netlink/desc-ethtool.c  |   2 +
 netlink/extapi.h        |   2 +
 netlink/module-eeprom.c | 125 +++++++++++++++++++++++++++++++++++++++-
 netlink/monitor.c       |   4 ++
 netlink/netlink.h       |   1 +
 7 files changed, 171 insertions(+), 2 deletions(-)

diff --git a/ethtool.8.in b/ethtool.8.in
index 115322a21932..4c77c4bcaefa 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -369,6 +369,14 @@ ethtool \- query or control network driver and hardware settings
 .BN bank
 .BN i2c
 .HP
+.B ethtool \-M|\-\-change\-module\-eeprom
+.I devname
+.BN offset \ N
+.BN page \ N
+.BN bank \ N
+.BN i2c \ N
+.BN value \ N
+.HP
 .B ethtool \-\-show\-priv\-flags
 .I devname
 .HP
@@ -1188,6 +1196,27 @@ and
 .I length
 parameters are treated relatively to EEPROM page boundaries.
 .TP
+.B \-M \-\-change\-module\-eeprom
+Changes a single byte in the module EEPROM at the specified address to a
+specific value.
+.RS 4
+.TP
+.BI offset \ N
+Specifies the offset within a page to write to.
+.TP
+.BI page \ N
+Specifies the page number to write to.
+.TP
+.BI bank \ N
+Specifies the bank number to write to. If not specified, kernel assumes bank 0.
+.TP
+.BI i2c \ N
+Specifies the I2C address of the page to write to.
+.TP
+.BI value \ N
+Specifies the value to write.
+.RE
+.TP
 .B \-\-show\-priv\-flags
 Queries the specified network device for its private flags.  The
 names and meanings of private flags (if any) are defined by each
diff --git a/ethtool.c b/ethtool.c
index 33a0a492cb15..601bb409d0ae 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -5907,6 +5907,16 @@ static const struct option args[] = {
 			  "		[ bank N ]\n"
 			  "		[ i2c N ]\n"
 	},
+	{
+		.opts	= "-M|--change-module-eeprom",
+		.nlfunc = nl_setmodule,
+		.help	= "Change byte in device module EEPROM",
+		.xhelp	= "		[ offset N ]\n"
+			  "		[ page N ]\n"
+			  "		[ bank N ]\n"
+			  "		[ i2c N ]\n"
+			  "		[ value N ]\n"
+	},
 	{
 		.opts	= "--show-eee",
 		.func	= do_geee,
diff --git a/netlink/desc-ethtool.c b/netlink/desc-ethtool.c
index d6fc4e2d03df..4b86cd849f7d 100644
--- a/netlink/desc-ethtool.c
+++ b/netlink/desc-ethtool.c
@@ -408,6 +408,7 @@ const struct pretty_nlmsg_desc ethnl_umsg_desc[] = {
 	NLMSG_DESC(ETHTOOL_MSG_FEC_SET, fec),
 	NLMSG_DESC(ETHTOOL_MSG_STATS_GET, stats),
 	NLMSG_DESC(ETHTOOL_MSG_MODULE_EEPROM_GET, module_eeprom),
+	NLMSG_DESC(ETHTOOL_MSG_MODULE_EEPROM_SET, module_eeprom),
 };
 
 const unsigned int ethnl_umsg_n_desc = ARRAY_SIZE(ethnl_umsg_desc);
@@ -447,6 +448,7 @@ const struct pretty_nlmsg_desc ethnl_kmsg_desc[] = {
 	NLMSG_DESC(ETHTOOL_MSG_FEC_NTF, fec),
 	NLMSG_DESC(ETHTOOL_MSG_STATS_GET_REPLY, stats),
 	NLMSG_DESC(ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY, module_eeprom),
+	NLMSG_DESC(ETHTOOL_MSG_MODULE_EEPROM_NTF, module_eeprom),
 };
 
 const unsigned int ethnl_kmsg_n_desc = ARRAY_SIZE(ethnl_kmsg_desc);
diff --git a/netlink/extapi.h b/netlink/extapi.h
index 91bf02b5e3be..0579c2abdb5d 100644
--- a/netlink/extapi.h
+++ b/netlink/extapi.h
@@ -45,6 +45,7 @@ bool nl_gstats_chk(struct cmd_context *ctx);
 int nl_gstats(struct cmd_context *ctx);
 int nl_monitor(struct cmd_context *ctx);
 int nl_getmodule(struct cmd_context *ctx);
+int nl_setmodule(struct cmd_context *ctx);
 
 void nl_monitor_usage(void);
 
@@ -99,6 +100,7 @@ static inline void nl_monitor_usage(void)
 #define nl_gstats_chk		NULL
 #define nl_gstats		NULL
 #define nl_getmodule		NULL
+#define nl_setmodule		NULL
 
 #endif /* ETHTOOL_ENABLE_NETLINK */
 
diff --git a/netlink/module-eeprom.c b/netlink/module-eeprom.c
index 355d1de047a8..5ce74e6b7731 100644
--- a/netlink/module-eeprom.c
+++ b/netlink/module-eeprom.c
@@ -1,7 +1,7 @@
 /*
- * module-eeprom.c - netlink implementation of module eeprom get command
+ * module-eeprom.c - netlink implementation of module eeprom commands
  *
- * ethtool -m <dev>
+ * Implementation of "ethtool -m <dev>" and "ethtool -M <dev> ..."
  */
 
 #include <errno.h>
@@ -18,6 +18,8 @@
 #include "netlink.h"
 #include "parser.h"
 
+/* MODULE_EEPROM_GET */
+
 #define ETH_I2C_ADDRESS_LOW	0x50
 #define ETH_I2C_ADDRESS_HIGH	0x51
 #define ETH_I2C_MAX_ADDRESS	0x7F
@@ -340,6 +342,43 @@ static void decoder_print(void)
 	}
 }
 
+int module_eeprom_ntf_cb(const struct nlmsghdr *nlhdr, void *data)
+{
+	const struct nlattr *tb[ETHTOOL_A_MODULE_EEPROM_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tb);
+	struct nl_context *nlctx = data;
+	bool silent;
+	int err_ret;
+	int ret;
+
+	silent = nlctx->is_dump || nlctx->is_monitor;
+	err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
+	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
+	if (ret < 0)
+		return err_ret;
+	if (!tb[ETHTOOL_A_MODULE_EEPROM_OFFSET] ||
+	    !tb[ETHTOOL_A_MODULE_EEPROM_LENGTH] ||
+	    !tb[ETHTOOL_A_MODULE_EEPROM_PAGE] ||
+	    !tb[ETHTOOL_A_MODULE_EEPROM_BANK] ||
+	    !tb[ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS])
+		return err_ret;
+	nlctx->devname = get_dev_name(tb[ETHTOOL_A_FEC_HEADER]);
+	if (!dev_ok(nlctx))
+		return err_ret;
+
+	if (silent)
+		putchar('\n');
+	printf("Module EEPROM write for %s:\n", nlctx->devname);
+	show_u32(tb[ETHTOOL_A_MODULE_EEPROM_OFFSET], "offset: ");
+	show_u32(tb[ETHTOOL_A_MODULE_EEPROM_LENGTH], "length: ");
+	printf("page: %u\n", mnl_attr_get_u8(tb[ETHTOOL_A_MODULE_EEPROM_PAGE]));
+	printf("bank: %u\n", mnl_attr_get_u8(tb[ETHTOOL_A_MODULE_EEPROM_BANK]));
+	printf("i2c address: 0x%x\n",
+	       mnl_attr_get_u8(tb[ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS]));
+
+	return MNL_CB_OK;
+}
+
 int nl_getmodule(struct cmd_context *ctx)
 {
 	struct ethtool_module_eeprom request = {0};
@@ -414,3 +453,85 @@ cleanup:
 	cache_free();
 	return ret;
 }
+
+/* MODULE_EEPROM_SET */
+
+static const struct param_parser setmodule_params[] = {
+	{
+		.arg		= "offset",
+		.type		= ETHTOOL_A_MODULE_EEPROM_OFFSET,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "page",
+		.type		= ETHTOOL_A_MODULE_EEPROM_PAGE,
+		.handler	= nl_parse_direct_u8,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "bank",
+		.type		= ETHTOOL_A_MODULE_EEPROM_BANK,
+		.handler	= nl_parse_direct_u8,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "i2c",
+		.type		= ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS,
+		.handler	= nl_parse_direct_u8,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "value",
+		.type		= ETHTOOL_A_MODULE_EEPROM_DATA,
+		.handler	= nl_parse_direct_u8,
+		.min_argc	= 1,
+	},
+	{}
+};
+
+int nl_setmodule(struct cmd_context *ctx)
+{
+	struct nl_context *nlctx = ctx->nlctx;
+	struct nl_msg_buff *msgbuff;
+	struct nl_socket *nlsk;
+	int ret;
+
+	if (netlink_cmd_check(ctx, ETHTOOL_MSG_MODULE_EEPROM_SET, false))
+		return -EOPNOTSUPP;
+	if (!ctx->argc) {
+		fprintf(stderr, "ethtool (-M): parameters missing\n");
+		return 1;
+	}
+
+	nlctx->cmd = "-M";
+	nlctx->argp = ctx->argp;
+	nlctx->argc = ctx->argc;
+	nlctx->devname = ctx->devname;
+	nlsk = nlctx->ethnl_socket;
+	msgbuff = &nlsk->msgbuff;
+
+	ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_MODULE_EEPROM_SET,
+		       NLM_F_REQUEST | NLM_F_ACK);
+	if (ret < 0)
+		return 2;
+	if (ethnla_fill_header(msgbuff, ETHTOOL_A_MODULE_EEPROM_HEADER,
+			       ctx->devname, 0))
+		return -EMSGSIZE;
+
+	ret = nl_parser(nlctx, setmodule_params, NULL, PARSER_GROUP_NONE, NULL);
+	if (ret < 0)
+		return 1;
+
+	if (ethnla_put_u32(msgbuff, ETHTOOL_A_MODULE_EEPROM_LENGTH, 1))
+		return -EMSGSIZE;
+
+	ret = nlsock_sendmsg(nlsk, NULL);
+	if (ret < 0)
+		return 83;
+	ret = nlsock_process_reply(nlsk, nomsg_reply_cb, nlctx);
+	if (ret == 0)
+		return 0;
+	else
+		return nlctx->exit_code ?: 83;
+}
diff --git a/netlink/monitor.c b/netlink/monitor.c
index 0c4df9e78ee3..ca4ebc7b0b9b 100644
--- a/netlink/monitor.c
+++ b/netlink/monitor.c
@@ -71,6 +71,10 @@ static struct {
 		.cmd	= ETHTOOL_MSG_FEC_NTF,
 		.cb	= fec_reply_cb,
 	},
+	{
+		.cmd	= ETHTOOL_MSG_MODULE_EEPROM_NTF,
+		.cb	= module_eeprom_ntf_cb,
+	},
 };
 
 static void clear_filter(struct nl_context *nlctx)
diff --git a/netlink/netlink.h b/netlink/netlink.h
index 70fa666b20e5..096a907c65c7 100644
--- a/netlink/netlink.h
+++ b/netlink/netlink.h
@@ -91,6 +91,7 @@ int cable_test_ntf_cb(const struct nlmsghdr *nlhdr, void *data);
 int cable_test_tdr_reply_cb(const struct nlmsghdr *nlhdr, void *data);
 int cable_test_tdr_ntf_cb(const struct nlmsghdr *nlhdr, void *data);
 int fec_reply_cb(const struct nlmsghdr *nlhdr, void *data);
+int module_eeprom_ntf_cb(const struct nlmsghdr *nlhdr, void *data);
 
 /* dump helpers */
 
-- 
2.31.1


      parent reply	other threads:[~2021-06-23  8:09 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-23  8:08 [RFC PATCH ethtool-next 0/2] ethtool: Add ability to write to transceiver module EEPROMs Ido Schimmel
2021-06-23  8:08 ` [RFC PATCH ethtool-next 1/2] Update UAPI header copies Ido Schimmel
2021-06-23  8:08 ` Ido Schimmel [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210623080825.2612270-3-idosch@idosch.org \
    --to=idosch@idosch.org \
    --cc=andrew@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=idosch@nvidia.com \
    --cc=jiri@nvidia.com \
    --cc=kuba@kernel.org \
    --cc=mkubecek@suse.cz \
    --cc=mlxsw@nvidia.com \
    --cc=moshe@nvidia.com \
    --cc=netdev@vger.kernel.org \
    --cc=vadimp@nvidia.com \
    --cc=vladyslavt@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.