* [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump
@ 2026-05-19 12:36 Danielle Ratson
2026-05-19 12:36 ` [PATCH ethtool-next v2 1/5] module-common: Add module_dump_eeprom_hex() helper Danielle Ratson
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Danielle Ratson @ 2026-05-19 12:36 UTC (permalink / raw)
To: netdev; +Cc: mkubecek, idosch, petrm, Danielle Ratson
The existing 'ethtool -m' command can dump module EEPROM data either as
a parsed pretty-print or as a raw/hex dump. The pretty-printer reads
multiple pages per module type, but decodes only specific fields from them.
In practice, both outputs are often needed together for offline debugging:
the pretty-print to identify the module type and decoded fields, and the
hex dump for fields the pretty-printer does not decode. However, there is
no single command that provides the raw hex dump of all relevant pages,
organized by page boundary. This is especially problematic for CMIS
transceivers where the existing hex dump does not provide Upper Pages
beyond Page 02h, let alone banked pages.
This series adds 'pages on|off' sub-option to 'hex on|off' for
'ethtool -m':
$ ethtool -m hex on pages on
That produces a hex dump organized by page, matching exactly the pages read
by the pretty-printer for each module type.
Each page is preceded by a header identifying the page number and, for
banked modules, the bank number. For SFP, where the two memory regions
are separate I2C addresses rather than pages, the header shows the I2C
address instead.
In JSON context (--json), each function emits a "pages" array with one
object per page, containing page/bank or I2C address, offset, length and
data. Consumers that need a stable, machine-parseable form of the hex
dump can use this output instead of the text format.
SFF-8636 Output examples (values zeroed to omit vendor-specific
identifiers):
$ ethtool -m swp61 hex on pages on
Page: 0x0
Offset Values
------ ------
0x0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Page: 0x0
Offset Values
------ ------
0x0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
$ ethtool -j -m swp61 hex on pages on
[ {
"pages": [ {
"bank": 0,
"page": 0,
"offset": 0,
"length": 128,
"i2c_address": 80,
"data": ["0","0",...,"0"]
},{
"bank": 0,
"page": 0,
"offset": 128,
"length": 128,
"i2c_address": 80,
"data": ["0","0",...,"0"]
} ]
} ]
v2:
* Add JSON output support: each per-type function emits a "pages"
array with one object per page containing bank, page, offset,
length, i2c_address and data.
* The shared module_dump_eeprom_hex() helper takes a struct
module_eeprom_dump with print_bank / print_i2c flags selecting
which header fields are printed
* In JSON context all fields are emitted unconditionally.
* Document the JSON output format in the man page.
Danielle Ratson (5):
module-common: Add module_dump_eeprom_hex() helper
sfpid: Refactor sff8079_show_all_nl() to separate page retrieval from
display
module: Add per-type EEPROM page hex dump functions
netlink: module-eeprom: Add 'hex on pages on' option for
page-organized hex dump
ethtool: Add man page and bash completion for 'pages on|off'
cmis.c | 70 +++++++++++++++++++++++++++----
cmis.h | 2 +-
ethtool.8.in | 18 ++++++++
ethtool.c | 1 +
internal.h | 4 +-
module-common.c | 38 +++++++++++++++++
module-common.h | 12 ++++++
netlink/module-eeprom.c | 43 +++++++++++++++----
qsfp.c | 67 +++++++++++++++++++++++++----
sfpid.c | 79 +++++++++++++++++++++++++++--------
shell-completion/bash/ethtool | 2 +
11 files changed, 294 insertions(+), 42 deletions(-)
--
2.51.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH ethtool-next v2 1/5] module-common: Add module_dump_eeprom_hex() helper
2026-05-19 12:36 [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump Danielle Ratson
@ 2026-05-19 12:36 ` Danielle Ratson
2026-05-19 12:36 ` [PATCH ethtool-next v2 2/5] sfpid: Refactor sff8079_show_all_nl() to separate page retrieval from display Danielle Ratson
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Danielle Ratson @ 2026-05-19 12:36 UTC (permalink / raw)
To: netdev; +Cc: mkubecek, idosch, petrm, Danielle Ratson
Add module_dump_eeprom_hex() as the shared building block for the
per-type EEPROM page hex dump functions added in the next patch. It
prints a per-page header followed by a hex dump; the header format is
selected by print_i2c / print_bank flags in struct module_eeprom_dump.
In JSON context, the flags are ignored and all metadata fields are
emitted as one object inside the enclosing "pages" array.
Assisted-by: Claude:claude-sonnet-4.6
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Danielle Ratson <danieller@nvidia.com>
---
module-common.c | 38 ++++++++++++++++++++++++++++++++++++++
module-common.h | 12 ++++++++++++
2 files changed, 50 insertions(+)
diff --git a/module-common.c b/module-common.c
index 4e9a0a7..1cfe243 100644
--- a/module-common.c
+++ b/module-common.c
@@ -656,3 +656,41 @@ void module_show_dom_mod_lvl_monitors(const struct sff_diags *sd)
PRINT_VCC_ALL("Module voltage", "module_voltage_measurement",
sd->sfp_voltage[MCURR]);
}
+
+/* Print one EEPROM memory block with a descriptive header followed by hex
+ * dump. The header is selected by the dump->print_i2c and dump->print_bank
+ * flags: "Page: 0xN" is always printed, an I2C-addressed block prints
+ * "I2C Address: 0xN" and a banked page prints "Bank: 0xN".
+ *
+ * In JSON context, all fields (bank, page, offset, length, i2c_address) are
+ * emitted unconditionally as a JSON object inside the enclosing "pages"
+ * array.
+ */
+void module_dump_eeprom_hex(const struct module_eeprom_dump *dump)
+{
+ u32 i;
+
+ if (is_json_context()) {
+ open_json_object(NULL);
+ print_uint(PRINT_JSON, "bank", "%u", dump->bank);
+ print_uint(PRINT_JSON, "page", "%u", dump->page);
+ print_uint(PRINT_JSON, "offset", "%u", dump->offset);
+ print_uint(PRINT_JSON, "length", "%u", dump->length);
+ print_uint(PRINT_JSON, "i2c_address", "%u", dump->i2c_address);
+ open_json_array("data", "");
+ for (i = 0; i < dump->length; i++)
+ print_hex(PRINT_JSON, NULL, "%02x", dump->data[i]);
+ close_json_array("");
+ close_json_object();
+ return;
+ }
+
+ if (dump->print_i2c)
+ printf("I2C Address: 0x%02x\n", dump->i2c_address);
+ if (dump->print_bank)
+ printf("Bank: 0x%x\n", dump->bank);
+ printf("Page: 0x%x\n\n", dump->page);
+
+ dump_hex(stdout, dump->data, dump->length, dump->offset);
+ printf("\n");
+}
diff --git a/module-common.h b/module-common.h
index 985b518..4063448 100644
--- a/module-common.h
+++ b/module-common.h
@@ -261,6 +261,17 @@ struct module_aw_chan {
__u8 adver_value; /* Supported if (offset & value) != 0. */
};
+struct module_eeprom_dump {
+ u32 offset;
+ u32 length;
+ u8 page;
+ u8 bank;
+ u8 i2c_address;
+ bool print_bank;
+ bool print_i2c;
+ const u8 *data;
+};
+
extern const struct module_aw_mod module_aw_mod_flags[];
extern const struct module_aw_chan module_aw_chan_flags[];
@@ -283,5 +294,6 @@ void module_show_identifier(const __u8 *id, int id_offset);
void module_show_connector(const __u8 *id, int ctor_offset);
void module_show_mit_compliance(u16 value);
void module_show_dom_mod_lvl_monitors(const struct sff_diags *sd);
+void module_dump_eeprom_hex(const struct module_eeprom_dump *dump);
#endif /* MODULE_COMMON_H__ */
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH ethtool-next v2 2/5] sfpid: Refactor sff8079_show_all_nl() to separate page retrieval from display
2026-05-19 12:36 [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump Danielle Ratson
2026-05-19 12:36 ` [PATCH ethtool-next v2 1/5] module-common: Add module_dump_eeprom_hex() helper Danielle Ratson
@ 2026-05-19 12:36 ` Danielle Ratson
2026-05-19 12:37 ` [PATCH ethtool-next v2 3/5] module: Add per-type EEPROM page hex dump functions Danielle Ratson
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Danielle Ratson @ 2026-05-19 12:36 UTC (permalink / raw)
To: netdev; +Cc: mkubecek, idosch, petrm, Danielle Ratson
Restructure sff8079_show_all_nl() to first retrieve all the necessary
pages (A0h and optionally A2h) and then pretty-print them, matching the
pattern already used in cmis_show_all_nl() and sff8636_show_all_nl().
This prepares for the next patch which extends the function with a hex
dump mode.
Note that if reading A2h fails, the function now returns an error
without producing partial output, matching the behavior of the other
parsers.
Assisted-by: Claude:claude-sonnet-4.6
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Danielle Ratson <danieller@nvidia.com>
---
sfpid.c | 29 ++++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)
diff --git a/sfpid.c b/sfpid.c
index 228b3ee..f753917 100644
--- a/sfpid.c
+++ b/sfpid.c
@@ -500,6 +500,7 @@ static int sff8079_get_eeprom_page(struct cmd_context *ctx, u8 i2c_address,
int sff8079_show_all_nl(struct cmd_context *ctx)
{
+ bool a2h_present;
u8 *buf;
int ret;
@@ -516,24 +517,26 @@ int sff8079_show_all_nl(struct cmd_context *ctx)
if (ret)
goto out;
+ /* Check if A2h page is present */
+ a2h_present = buf[92] & (1 << 6);
+
+ if (a2h_present) {
+ /* Read A2h page */
+ ret = sff8079_get_eeprom_page(ctx, SFF8079_I2C_ADDRESS_HIGH,
+ buf + ETH_MODULE_SFF_8079_LEN);
+ if (ret) {
+ fprintf(stderr, "Failed to read Page A2h\n");
+ goto out;
+ }
+ }
+
new_json_obj(ctx->json);
open_json_object(NULL);
sff8079_show_all_common(buf);
- /* Finish if A2h page is not present */
- if (!(buf[92] & (1 << 6)))
- goto out_json;
-
- /* Read A2h page */
- ret = sff8079_get_eeprom_page(ctx, SFF8079_I2C_ADDRESS_HIGH,
- buf + ETH_MODULE_SFF_8079_LEN);
- if (ret) {
- fprintf(stderr, "Failed to read Page A2h.\n");
- goto out_json;
- }
+ if (a2h_present)
+ sff8472_show_all(buf);
- sff8472_show_all(buf);
-out_json:
close_json_object();
delete_json_obj();
out:
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH ethtool-next v2 3/5] module: Add per-type EEPROM page hex dump functions
2026-05-19 12:36 [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump Danielle Ratson
2026-05-19 12:36 ` [PATCH ethtool-next v2 1/5] module-common: Add module_dump_eeprom_hex() helper Danielle Ratson
2026-05-19 12:36 ` [PATCH ethtool-next v2 2/5] sfpid: Refactor sff8079_show_all_nl() to separate page retrieval from display Danielle Ratson
@ 2026-05-19 12:37 ` Danielle Ratson
2026-05-19 12:37 ` [PATCH ethtool-next v2 4/5] netlink: module-eeprom: Add 'hex on pages on' option for page-organized hex dump Danielle Ratson
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Danielle Ratson @ 2026-05-19 12:37 UTC (permalink / raw)
To: netdev; +Cc: mkubecek, idosch, petrm, Danielle Ratson
Extend sff8079_show_all_nl(), cmis_show_all_nl() and
sff8636_show_all_nl() with a bool dump_pages parameter to support
hex dump output alongside their existing pretty-print output. Each
function first retrieves all the necessary pages and then either
pretty-prints them or performs a hex dump according to the argument.
The hex dump and pretty-print logic is extracted into dedicated static
functions for each parser type:
- cmis_hex_dump() / cmis_pretty_print()
- sff8636_hex_dump() / sff8636_pretty_print()
- sff8079_hex_dump() / sff8079_pretty_print()
Each function dumps the same pages as the corresponding pretty-printer:
- CMIS: uses cmis_memory_map_init_pages() to read the lower memory and
relevant upper pages across all supported banks, using generic iteration
over the memory map. Each block is labeled with "Bank: 0xN" followed by
"Page: 0xM".
- SFF-8636: uses sff8636_memory_map_init_pages() to read the lower memory
and relevant upper pages, using generic iteration over the memory map.
Each block is labeled "Page: 0xN".
- SFF-8079: uses sff8079_get_eeprom_page() to read A0h lower and optional
A2h lower. Each block is labeled with "I2C Address: 0xN" followed by
"Page: 0xM".
In JSON context (--json), each function emits a "pages" array with one
object per page containing bank, page, offset, length, i2c_address and
data. Consumers that need a stable, machine-parseable form of the hex
dump can use this output instead of the text format.
Assisted-by: Claude:claude-sonnet-4.6
Reviewed-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Danielle Ratson <danieller@nvidia.com>
---
cmis.c | 70 ++++++++++++++++++++++++++++++++++++-----
cmis.h | 2 +-
internal.h | 4 +--
netlink/module-eeprom.c | 6 ++--
qsfp.c | 67 ++++++++++++++++++++++++++++++++++-----
sfpid.c | 60 +++++++++++++++++++++++++++++------
6 files changed, 179 insertions(+), 30 deletions(-)
diff --git a/cmis.c b/cmis.c
index 996e9eb..f494268 100644
--- a/cmis.c
+++ b/cmis.c
@@ -1022,6 +1022,64 @@ void cmis_show_all_ioctl(const __u8 *id)
cmis_show_all_common(&map);
}
+static void cmis_hex_dump(struct cmd_context *ctx,
+ const struct cmis_memory_map *map)
+{
+ struct module_eeprom_dump dump = {
+ .length = CMIS_PAGE_SIZE,
+ .i2c_address = CMIS_I2C_ADDRESS,
+ .print_bank = true,
+ };
+ u8 bank, page;
+
+ new_json_obj(ctx->json);
+ if (is_json_context()) {
+ open_json_object(NULL);
+ open_json_array("pages", "");
+ }
+
+ dump.data = map->lower_memory;
+ module_dump_eeprom_hex(&dump);
+
+ for (bank = 0; bank < CMIS_MAX_BANKS; bank++) {
+ for (page = 0; page < CMIS_MAX_PAGES; page++) {
+ const __u8 *buf = map->upper_memory[bank][page];
+
+ if (!buf)
+ continue;
+
+ /* Upper memory starts at one page size into
+ * the buffer, since pages are accessed at
+ * offset between page size and twice the
+ * page size.
+ */
+ dump.offset = CMIS_PAGE_SIZE;
+ dump.page = page;
+ dump.bank = bank;
+ dump.data = buf + CMIS_PAGE_SIZE;
+ module_dump_eeprom_hex(&dump);
+ }
+ }
+
+ if (is_json_context()) {
+ close_json_array("");
+ close_json_object();
+ }
+ delete_json_obj();
+}
+
+static void cmis_pretty_print(struct cmd_context *ctx,
+ const struct cmis_memory_map *map)
+{
+ new_json_obj(ctx->json);
+ open_json_object(NULL);
+
+ cmis_show_all_common(map);
+
+ close_json_object();
+ delete_json_obj();
+}
+
static void cmis_request_init(struct ethtool_module_eeprom *request, u8 bank,
u8 page, u32 offset)
{
@@ -1117,21 +1175,19 @@ cmis_memory_map_init_pages(struct cmd_context *ctx,
return 0;
}
-int cmis_show_all_nl(struct cmd_context *ctx)
+int cmis_show_all_nl(struct cmd_context *ctx, bool dump_pages)
{
struct cmis_memory_map map = {};
int ret;
- new_json_obj(ctx->json);
- open_json_object(NULL);
-
ret = cmis_memory_map_init_pages(ctx, &map);
if (ret < 0)
return ret;
- cmis_show_all_common(&map);
- close_json_object();
- delete_json_obj();
+ if (dump_pages)
+ cmis_hex_dump(ctx, &map);
+ else
+ cmis_pretty_print(ctx, &map);
return 0;
}
diff --git a/cmis.h b/cmis.h
index 007632a..82fd245 100644
--- a/cmis.h
+++ b/cmis.h
@@ -201,6 +201,6 @@
void cmis_show_all_ioctl(const __u8 *id);
-int cmis_show_all_nl(struct cmd_context *ctx);
+int cmis_show_all_nl(struct cmd_context *ctx, bool dump_pages);
#endif /* CMIS_H__ */
diff --git a/internal.h b/internal.h
index cbf3c09..19fff41 100644
--- a/internal.h
+++ b/internal.h
@@ -381,14 +381,14 @@ int rxclass_rule_del(struct cmd_context *ctx, __u32 loc);
/* Module EEPROM parsing code */
void sff8079_show_all_ioctl(const __u8 *id);
-int sff8079_show_all_nl(struct cmd_context *ctx);
+int sff8079_show_all_nl(struct cmd_context *ctx, bool dump_pages);
/* Optics diagnostics */
void sff8472_show_all(const __u8 *id);
/* QSFP Optics diagnostics */
void sff8636_show_all_ioctl(const __u8 *id, __u32 eeprom_len);
-int sff8636_show_all_nl(struct cmd_context *ctx);
+int sff8636_show_all_nl(struct cmd_context *ctx, bool dump_pages);
/* FUJITSU Extended Socket network device */
int fjes_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
diff --git a/netlink/module-eeprom.c b/netlink/module-eeprom.c
index ce6a7d9..7e4e6ac 100644
--- a/netlink/module-eeprom.c
+++ b/netlink/module-eeprom.c
@@ -228,18 +228,18 @@ static int eeprom_parse(struct cmd_context *ctx)
case MODULE_ID_GBIC:
case MODULE_ID_SOLDERED_MODULE:
case MODULE_ID_SFP:
- return sff8079_show_all_nl(ctx);
+ return sff8079_show_all_nl(ctx, false);
case MODULE_ID_QSFP:
case MODULE_ID_QSFP28:
case MODULE_ID_QSFP_PLUS:
- return sff8636_show_all_nl(ctx);
+ return sff8636_show_all_nl(ctx, false);
case MODULE_ID_QSFP_DD:
case MODULE_ID_OSFP:
case MODULE_ID_DSFP:
case MODULE_ID_QSFP_PLUS_CMIS:
case MODULE_ID_SFP_DD_CMIS:
case MODULE_ID_SFP_PLUS_CMIS:
- return cmis_show_all_nl(ctx);
+ return cmis_show_all_nl(ctx, false);
#endif
default:
/* If we cannot recognize the memory map, default to dumping
diff --git a/qsfp.c b/qsfp.c
index 09d9ace..383d234 100644
--- a/qsfp.c
+++ b/qsfp.c
@@ -62,9 +62,11 @@
#include "cmis.h"
#include "netlink/extapi.h"
+#define SFF8636_MAX_PAGES 4
+
struct sff8636_memory_map {
const __u8 *lower_memory;
- const __u8 *upper_memory[4];
+ const __u8 *upper_memory[SFF8636_MAX_PAGES];
#define page_00h upper_memory[0x0]
#define page_03h upper_memory[0x3]
};
@@ -1078,21 +1080,72 @@ sff8636_memory_map_init_pages(struct cmd_context *ctx,
return 0;
}
-int sff8636_show_all_nl(struct cmd_context *ctx)
+static void sff8636_hex_dump(struct cmd_context *ctx,
+ const struct sff8636_memory_map *map)
{
- struct sff8636_memory_map map = {};
- int ret;
+ struct module_eeprom_dump dump = {
+ .length = SFF8636_PAGE_SIZE,
+ .i2c_address = SFF8636_I2C_ADDRESS,
+ };
+ u8 page;
+ new_json_obj(ctx->json);
+ if (is_json_context()) {
+ open_json_object(NULL);
+ open_json_array("pages", "");
+ }
+
+ dump.data = map->lower_memory;
+ module_dump_eeprom_hex(&dump);
+
+ for (page = 0; page < SFF8636_MAX_PAGES; page++) {
+ const __u8 *buf = map->upper_memory[page];
+
+ if (!buf)
+ continue;
+
+ /* Upper memory starts at one page size into the
+ * buffer, since pages are accessed at offset between
+ * page size and twice the page size.
+ */
+ dump.offset = SFF8636_PAGE_SIZE;
+ dump.page = page;
+ dump.data = buf + SFF8636_PAGE_SIZE;
+ module_dump_eeprom_hex(&dump);
+ }
+
+ if (is_json_context()) {
+ close_json_array("");
+ close_json_object();
+ }
+ delete_json_obj();
+}
+
+static void sff8636_pretty_print(struct cmd_context *ctx,
+ const struct sff8636_memory_map *map)
+{
new_json_obj(ctx->json);
open_json_object(NULL);
+ sff8636_show_all_common(map);
+
+ close_json_object();
+ delete_json_obj();
+}
+
+int sff8636_show_all_nl(struct cmd_context *ctx, bool dump_pages)
+{
+ struct sff8636_memory_map map = {};
+ int ret;
+
ret = sff8636_memory_map_init_pages(ctx, &map);
if (ret < 0)
return ret;
- sff8636_show_all_common(&map);
- close_json_object();
- delete_json_obj();
+ if (dump_pages)
+ sff8636_hex_dump(ctx, &map);
+ else
+ sff8636_pretty_print(ctx, &map);
return 0;
}
diff --git a/sfpid.c b/sfpid.c
index f753917..9a7f927 100644
--- a/sfpid.c
+++ b/sfpid.c
@@ -498,7 +498,52 @@ static int sff8079_get_eeprom_page(struct cmd_context *ctx, u8 i2c_address,
return ret;
}
-int sff8079_show_all_nl(struct cmd_context *ctx)
+static void sff8079_hex_dump(struct cmd_context *ctx, const u8 *buf,
+ bool a2h_present)
+{
+ struct module_eeprom_dump dump = {
+ .length = SFF8079_PAGE_SIZE,
+ .print_i2c = true,
+ };
+
+ new_json_obj(ctx->json);
+ if (is_json_context()) {
+ open_json_object(NULL);
+ open_json_array("pages", "");
+ }
+
+ dump.i2c_address = SFF8079_I2C_ADDRESS_LOW;
+ dump.data = buf;
+ module_dump_eeprom_hex(&dump);
+
+ if (a2h_present) {
+ dump.i2c_address = SFF8079_I2C_ADDRESS_HIGH;
+ dump.data = buf + ETH_MODULE_SFF_8079_LEN;
+ module_dump_eeprom_hex(&dump);
+ }
+
+ if (is_json_context()) {
+ close_json_array("");
+ close_json_object();
+ }
+ delete_json_obj();
+}
+
+static void sff8079_pretty_print(struct cmd_context *ctx, const u8 *buf,
+ bool a2h_present)
+{
+ new_json_obj(ctx->json);
+ open_json_object(NULL);
+ sff8079_show_all_common(buf);
+
+ if (a2h_present)
+ sff8472_show_all(buf);
+
+ close_json_object();
+ delete_json_obj();
+}
+
+int sff8079_show_all_nl(struct cmd_context *ctx, bool dump_pages)
{
bool a2h_present;
u8 *buf;
@@ -530,15 +575,10 @@ int sff8079_show_all_nl(struct cmd_context *ctx)
}
}
- new_json_obj(ctx->json);
- open_json_object(NULL);
- sff8079_show_all_common(buf);
-
- if (a2h_present)
- sff8472_show_all(buf);
-
- close_json_object();
- delete_json_obj();
+ if (dump_pages)
+ sff8079_hex_dump(ctx, buf, a2h_present);
+ else
+ sff8079_pretty_print(ctx, buf, a2h_present);
out:
free(buf);
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH ethtool-next v2 4/5] netlink: module-eeprom: Add 'hex on pages on' option for page-organized hex dump
2026-05-19 12:36 [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump Danielle Ratson
` (2 preceding siblings ...)
2026-05-19 12:37 ` [PATCH ethtool-next v2 3/5] module: Add per-type EEPROM page hex dump functions Danielle Ratson
@ 2026-05-19 12:37 ` Danielle Ratson
2026-05-19 12:37 ` [PATCH ethtool-next v2 5/5] ethtool: Add man page and bash completion for 'pages on|off' Danielle Ratson
2026-05-19 14:10 ` [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump Andrew Lunn
5 siblings, 0 replies; 7+ messages in thread
From: Danielle Ratson @ 2026-05-19 12:37 UTC (permalink / raw)
To: netdev; +Cc: mkubecek, idosch, petrm, Danielle Ratson
Add 'pages on|off' sub-option to 'hex on|off' for 'ethtool -m'.
When 'hex on pages on' is specified, eeprom_parse() dispatches to the
appropriate per-type function with dump_pages=true, producing a hex dump
of all relevant EEPROM pages with a per-page header showing the page
number and optional bank number.
eeprom_parse() is extended with a bool dump_pages parameter to select
between pretty-print and hex dump output, avoiding duplication of the
module-type dispatch logic.
Unlike plain 'hex on', 'hex on pages on' does not fall back to the ioctl
path, as page selection is handled internally by the per-type functions.
Unknown module types fall back to dumping the lower 128 bytes.
'pages' and 'hex' are both parsed as independent flat options, since the
parameter parser does not support context-dependent argument recognition.
The requirement for 'hex on' when using 'pages on' is enforced by an
explicit validation check.
SFF-8636 Output example (values zeroed to omit vendor-specific
identifiers):
$ ethtool -m swp61 hex on pages on
Page: 0x0
Offset Values
------ ------
0x0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Page: 0x0
Offset Values
------ ------
0x0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Note: 'Page: 0x0' appears twice in the output. The first block is the
lower memory (bytes 0x00-0x7f), which is always accessible. The second
block is upper memory page 00h (bytes 0x80-0xff). Both carry the same
page label but are distinguished by their offset range in the hex dump.
Assisted-by: Claude:claude-sonnet-4.6
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Danielle Ratson <danieller@nvidia.com>
---
ethtool.c | 1 +
netlink/module-eeprom.c | 43 ++++++++++++++++++++++++++++++++++-------
2 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/ethtool.c b/ethtool.c
index 2444d85..8869c06 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -6165,6 +6165,7 @@ static const struct option args[] = {
.help = "Query/Decode Module EEPROM information and optical diagnostics if available",
.xhelp = " [ raw on|off ]\n"
" [ hex on|off ]\n"
+ " [ pages on|off ]\n"
" [ offset N ]\n"
" [ length N ]\n"
" [ page N ]\n"
diff --git a/netlink/module-eeprom.c b/netlink/module-eeprom.c
index 7e4e6ac..ce88475 100644
--- a/netlink/module-eeprom.c
+++ b/netlink/module-eeprom.c
@@ -25,6 +25,7 @@ struct cmd_params {
unsigned long present;
u8 dump_hex;
u8 dump_raw;
+ u8 dump_pages;
u32 offset;
u32 length;
u32 page;
@@ -83,6 +84,12 @@ static const struct param_parser getmodule_params[] = {
.dest_offset = offsetof(struct cmd_params, i2c_address),
.min_argc = 1,
},
+ {
+ .arg = "pages",
+ .handler = nl_parse_u8bool,
+ .dest_offset = offsetof(struct cmd_params, dump_pages),
+ .min_argc = 1,
+ },
{}
};
@@ -207,7 +214,7 @@ static int eeprom_dump_hex(struct cmd_context *ctx)
return 0;
}
-static int eeprom_parse(struct cmd_context *ctx)
+static int eeprom_parse(struct cmd_context *ctx, bool dump_pages)
{
struct ethtool_module_eeprom request = {
.length = 1,
@@ -228,18 +235,18 @@ static int eeprom_parse(struct cmd_context *ctx)
case MODULE_ID_GBIC:
case MODULE_ID_SOLDERED_MODULE:
case MODULE_ID_SFP:
- return sff8079_show_all_nl(ctx, false);
+ return sff8079_show_all_nl(ctx, dump_pages);
case MODULE_ID_QSFP:
case MODULE_ID_QSFP28:
case MODULE_ID_QSFP_PLUS:
- return sff8636_show_all_nl(ctx, false);
+ return sff8636_show_all_nl(ctx, dump_pages);
case MODULE_ID_QSFP_DD:
case MODULE_ID_OSFP:
case MODULE_ID_DSFP:
case MODULE_ID_QSFP_PLUS_CMIS:
case MODULE_ID_SFP_DD_CMIS:
case MODULE_ID_SFP_PLUS_CMIS:
- return cmis_show_all_nl(ctx, false);
+ return cmis_show_all_nl(ctx, dump_pages);
#endif
default:
/* If we cannot recognize the memory map, default to dumping
@@ -272,10 +279,28 @@ int nl_getmodule(struct cmd_context *ctx)
return -EINVAL;
}
+ if (getmodule_cmd_params.dump_pages && !getmodule_cmd_params.dump_hex) {
+ fprintf(stderr, "Pages dump requires hex on\n");
+ return -EINVAL;
+ }
+
+ if (getmodule_cmd_params.dump_pages &&
+ (getmodule_cmd_params.present & (1 << PARAM_PAGE |
+ 1 << PARAM_BANK |
+ 1 << PARAM_OFFSET |
+ 1 << PARAM_LENGTH |
+ 1 << PARAM_I2C))) {
+ fprintf(stderr,
+ "Pages dump cannot be combined with offset, length, page, bank or i2c\n");
+ return -EINVAL;
+ }
+
/* When complete hex/raw dump of the EEPROM is requested, fallback to
- * ioctl. Netlink can only request specific pages.
+ * ioctl. Netlink can only request specific pages. Skip fallback when
+ * pages dump is requested, as it handles page selection internally.
*/
if ((getmodule_cmd_params.dump_hex || getmodule_cmd_params.dump_raw) &&
+ !getmodule_cmd_params.dump_pages &&
!(getmodule_cmd_params.present & (1 << PARAM_PAGE |
1 << PARAM_BANK |
1 << PARAM_I2C))) {
@@ -300,7 +325,11 @@ int nl_getmodule(struct cmd_context *ctx)
if (request.page && !request.offset)
request.offset = 128;
- if (getmodule_cmd_params.dump_hex || getmodule_cmd_params.dump_raw) {
+ if (getmodule_cmd_params.dump_pages) {
+ ret = eeprom_parse(ctx, true);
+ if (ret < 0)
+ goto cleanup;
+ } else if (getmodule_cmd_params.dump_hex || getmodule_cmd_params.dump_raw) {
ret = nl_get_eeprom_page(ctx, &request);
if (ret < 0)
goto cleanup;
@@ -311,7 +340,7 @@ int nl_getmodule(struct cmd_context *ctx)
dump_hex(stdout, request.data, request.length,
request.offset);
} else {
- ret = eeprom_parse(ctx);
+ ret = eeprom_parse(ctx, false);
if (ret < 0)
goto cleanup;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH ethtool-next v2 5/5] ethtool: Add man page and bash completion for 'pages on|off'
2026-05-19 12:36 [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump Danielle Ratson
` (3 preceding siblings ...)
2026-05-19 12:37 ` [PATCH ethtool-next v2 4/5] netlink: module-eeprom: Add 'hex on pages on' option for page-organized hex dump Danielle Ratson
@ 2026-05-19 12:37 ` Danielle Ratson
2026-05-19 14:10 ` [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump Andrew Lunn
5 siblings, 0 replies; 7+ messages in thread
From: Danielle Ratson @ 2026-05-19 12:37 UTC (permalink / raw)
To: netdev; +Cc: mkubecek, idosch, petrm, Danielle Ratson
Add 'pages on|off' to the bash completion for ethtool -m and the
ethtool man page.
The man page documents that 'pages on' requires 'hex on', describes the
per-page header format, and notes that it cannot be combined with
offset, length, page, bank or i2c parameters.
Assisted-by: Claude:claude-sonnet-4.6
Reviewed-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Danielle Ratson <danieller@nvidia.com>
---
ethtool.8.in | 18 ++++++++++++++++++
shell-completion/bash/ethtool | 2 ++
2 files changed, 20 insertions(+)
diff --git a/ethtool.8.in b/ethtool.8.in
index 32b971a..d4c4768 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -403,6 +403,7 @@ ethtool \- query or control network driver and hardware settings
.I devname
.B2 raw on off
.B2 hex on off
+.B2 pages on off
.BN offset
.BN length
.BN page
@@ -1431,6 +1432,23 @@ allowed. In such a case
and
.I length
parameters are treated relatively to EEPROM page boundaries.
+When
+.B hex on pages on
+is specified, dumps all relevant EEPROM pages in hex, organized by page.
+Each page is preceded by a header identifying the page number. For banked pages,
+the bank number is also shown, and for SFP modules, the I2C address is also
+shown, as different parts of the EEPROM memory map are accessible via different
+I2C addresses. The set of pages dumped matches what the pretty-printer reads for
+each module type. This option cannot be combined with
+.I offset, length, page, bank
+or
+.I i2c
+parameters. When combined with
+.BI \-\-json ,
+the output is a JSON object with a "pages" array. Each element is an
+object with the fields "bank", "page", "offset", "length", "i2c_address"
+and "data", emitted unconditionally regardless of module type. "data" is
+an array of lowercase hex strings, one per byte.
.TP
.B \-\-show\-priv\-flags
Queries the specified network device for its private flags. The
diff --git a/shell-completion/bash/ethtool b/shell-completion/bash/ethtool
index 57c39c4..7a319a9 100644
--- a/shell-completion/bash/ethtool
+++ b/shell-completion/bash/ethtool
@@ -671,11 +671,13 @@ _ethtool_module_info()
[hex]=1
[length]=1
[offset]=1
+ [pages]=1
[raw]=1
)
case "$prev" in
hex|\
+ pages|\
raw)
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
return ;;
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump
2026-05-19 12:36 [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump Danielle Ratson
` (4 preceding siblings ...)
2026-05-19 12:37 ` [PATCH ethtool-next v2 5/5] ethtool: Add man page and bash completion for 'pages on|off' Danielle Ratson
@ 2026-05-19 14:10 ` Andrew Lunn
5 siblings, 0 replies; 7+ messages in thread
From: Andrew Lunn @ 2026-05-19 14:10 UTC (permalink / raw)
To: Danielle Ratson; +Cc: netdev, mkubecek, idosch, petrm
Thanks for adding json support.
> $ ethtool -j -m swp61 hex on pages on
> [ {
> "pages": [ {
> "bank": 0,
> "page": 0,
> "offset": 0,
> "length": 128,
> "i2c_address": 80,
> "data": ["0","0",...,"0"]
What is the value of length? It seems to be something you can
determine from data itself. Is there a legitimate case for
length != len(data)?
Andrew
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-05-19 14:10 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-19 12:36 [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump Danielle Ratson
2026-05-19 12:36 ` [PATCH ethtool-next v2 1/5] module-common: Add module_dump_eeprom_hex() helper Danielle Ratson
2026-05-19 12:36 ` [PATCH ethtool-next v2 2/5] sfpid: Refactor sff8079_show_all_nl() to separate page retrieval from display Danielle Ratson
2026-05-19 12:37 ` [PATCH ethtool-next v2 3/5] module: Add per-type EEPROM page hex dump functions Danielle Ratson
2026-05-19 12:37 ` [PATCH ethtool-next v2 4/5] netlink: module-eeprom: Add 'hex on pages on' option for page-organized hex dump Danielle Ratson
2026-05-19 12:37 ` [PATCH ethtool-next v2 5/5] ethtool: Add man page and bash completion for 'pages on|off' Danielle Ratson
2026-05-19 14:10 ` [PATCH ethtool-next v2 0/5] ethtool: Add 'pages on|off' option for module EEPROM hex dump Andrew Lunn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox