The "show port <port_id> module_eeprom" command only prints
a hexdump of the pluggable module EEPROM, which has to be
decoded by hand against the SFF specifications.

Add the "show port <port_id> module_eeprom decode" command
to print the fields decoded by rte_eth_module_eeprom_parse(),
such as the vendor, the transceiver type and the digital
diagnostics, in the same form as "ethtool -m".

The EEPROM read is moved to a helper shared by both commands.

Signed-off-by: Roman Khromenok <[email protected]>
---
This adds the testpmd hook for rte_eth_module_eeprom_parse(),
which is in dpdk-next-net for 26.11. The patch is based on
next-net/for-main.

Tested with net_null returning a synthetic SFF-8472 image
(not part of the patch), built with gcc and with clang
ASan/UBSan, no reports:

testpmd> show port 0 module_eeprom decode
Port 0 module EEPROM (type 0x2, 512 bytes):
        Identifier                                : 0x03 (SFP)
        ...
        Vendor name                               : TESTVENDOR
        ...
        Laser bias current                        : 8.000 mA
        Laser output power                        : 0.5000 mW / -3.01 dBm
        Receiver signal average optical power     : 0.4000 mW / -3.98 dBm
        Module temperature                        : 37.50 degrees C / 99.50 
degrees F
        Module voltage                            : 3.3000 V

 app/test-pmd/cmdline.c                      | 48 ++++++++++++++
 app/test-pmd/config.c                       | 72 ++++++++++++++++-----
 app/test-pmd/testpmd.h                      |  1 +
 doc/guides/rel_notes/release_26_11.rst      |  2 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  8 +++
 5 files changed, 115 insertions(+), 16 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index d52a0eff42..51078a2a73 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -172,6 +172,9 @@ static void cmd_help_long_parsed(void *parsed_result,
                        "show port port_id (module_eeprom|eeprom)\n"
                        "    Display the module EEPROM or EEPROM information 
for port_id.\n\n"
 
+                       "show port (port_id) module_eeprom decode\n"
+                       "    Display the decoded module EEPROM of port_id.\n\n"
+
                        "set port (port_id) eeprom (accept_risk) magic 
(magic_num)"
                        " value (value) offset (offset)\n"
                        "    Set the device eeprom for certain port.\nNote:\n"
@@ -7826,6 +7829,50 @@ static cmdline_parse_inst_t cmd_showeeprom = {
        },
 };
 
+struct cmd_showeeprom_decode_result {
+       cmdline_fixed_string_t show;
+       cmdline_fixed_string_t port;
+       uint16_t portnum;
+       cmdline_fixed_string_t module_eeprom;
+       cmdline_fixed_string_t decode;
+};
+
+static void cmd_showeeprom_decode_parsed(void *parsed_result,
+               __rte_unused struct cmdline *cl,
+               __rte_unused void *data)
+{
+       struct cmd_showeeprom_decode_result *res = parsed_result;
+
+       port_module_eeprom_decode_display(res->portnum);
+}
+
+static cmdline_parse_token_string_t cmd_showeeprom_decode_show =
+       TOKEN_STRING_INITIALIZER(struct cmd_showeeprom_decode_result, show, 
"show");
+static cmdline_parse_token_string_t cmd_showeeprom_decode_port =
+       TOKEN_STRING_INITIALIZER(struct cmd_showeeprom_decode_result, port, 
"port");
+static cmdline_parse_token_num_t cmd_showeeprom_decode_portnum =
+       TOKEN_NUM_INITIALIZER(struct cmd_showeeprom_decode_result, portnum,
+                       RTE_UINT16);
+static cmdline_parse_token_string_t cmd_showeeprom_decode_module_eeprom =
+       TOKEN_STRING_INITIALIZER(struct cmd_showeeprom_decode_result, 
module_eeprom,
+                       "module_eeprom");
+static cmdline_parse_token_string_t cmd_showeeprom_decode_decode =
+       TOKEN_STRING_INITIALIZER(struct cmd_showeeprom_decode_result, decode, 
"decode");
+
+static cmdline_parse_inst_t cmd_showeeprom_decode = {
+       .f = cmd_showeeprom_decode_parsed,
+       .data = NULL,
+       .help_str = "show port <port_id> module_eeprom decode",
+       .tokens = {
+               (void *)&cmd_showeeprom_decode_show,
+               (void *)&cmd_showeeprom_decode_port,
+               (void *)&cmd_showeeprom_decode_portnum,
+               (void *)&cmd_showeeprom_decode_module_eeprom,
+               (void *)&cmd_showeeprom_decode_decode,
+               NULL,
+       },
+};
+
 /* *** SET PORT EEPROM *** */
 struct cmd_seteeprom_result {
        cmdline_fixed_string_t set;
@@ -14219,6 +14266,7 @@ static cmdline_parse_ctx_t builtin_ctx[] = {
        &cmd_showport,
        &cmd_showqueue,
        &cmd_showeeprom,
+       &cmd_showeeprom_decode,
        &cmd_seteeprom,
        &cmd_showportall,
        &cmd_representor_info,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 9d1fa2f4d1..ec348cf854 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -1145,20 +1145,18 @@ port_eeprom_set(portid_t port_id,
                fprintf(stderr, "Unable to set EEPROM: %s\n", 
rte_strerror(-ret));
 }
 
-void
-port_module_eeprom_display(portid_t port_id)
+static int
+port_module_eeprom_read(portid_t port_id, struct rte_eth_dev_module_info 
*minfo,
+               struct rte_dev_eeprom_info *einfo)
 {
-       struct rte_eth_dev_module_info minfo;
-       struct rte_dev_eeprom_info einfo;
        int ret;
 
        if (port_id_is_invalid(port_id, ENABLED_WARN)) {
                print_valid_ports();
-               return;
+               return -EINVAL;
        }
 
-
-       ret = rte_eth_dev_get_module_info(port_id, &minfo);
+       ret = rte_eth_dev_get_module_info(port_id, minfo);
        if (ret != 0) {
                switch (ret) {
                case -ENODEV:
@@ -1175,20 +1173,20 @@ port_module_eeprom_display(portid_t port_id)
                                ret);
                        break;
                }
-               return;
+               return ret;
        }
 
-       einfo.offset = 0;
-       einfo.length = minfo.eeprom_len;
-       einfo.data = calloc(1, minfo.eeprom_len);
-       if (!einfo.data) {
+       einfo->offset = 0;
+       einfo->length = minfo->eeprom_len;
+       einfo->data = calloc(1, minfo->eeprom_len);
+       if (!einfo->data) {
                fprintf(stderr,
                        "Allocation of port %u eeprom data failed\n",
                        port_id);
-               return;
+               return -ENOMEM;
        }
 
-       ret = rte_eth_dev_get_module_eeprom(port_id, &einfo);
+       ret = rte_eth_dev_get_module_eeprom(port_id, einfo);
        if (ret != 0) {
                switch (ret) {
                case -ENODEV:
@@ -1205,15 +1203,57 @@ port_module_eeprom_display(portid_t port_id)
                                ret);
                        break;
                }
-               free(einfo.data);
-               return;
+               free(einfo->data);
+               einfo->data = NULL;
+               return ret;
        }
 
+       return 0;
+}
+
+void
+port_module_eeprom_display(portid_t port_id)
+{
+       struct rte_eth_dev_module_info minfo;
+       struct rte_dev_eeprom_info einfo;
+
+       if (port_module_eeprom_read(port_id, &minfo, &einfo) != 0)
+               return;
+
        rte_hexdump(stdout, "hexdump", einfo.data, einfo.length);
        printf("Finish -- Port: %d MODULE EEPROM length: %d bytes\n", port_id, 
einfo.length);
        free(einfo.data);
 }
 
+static void
+port_module_eeprom_field_print(const char *name, const char *value,
+               __rte_unused void *arg)
+{
+       printf("\t%-41s : %s\n", name, value);
+}
+
+void
+port_module_eeprom_decode_display(portid_t port_id)
+{
+       struct rte_eth_dev_module_info minfo;
+       struct rte_dev_eeprom_info einfo;
+       int ret;
+
+       if (port_module_eeprom_read(port_id, &minfo, &einfo) != 0)
+               return;
+
+       printf("Port %u module EEPROM (type 0x%x, %u bytes):\n",
+               port_id, minfo.type, einfo.length);
+       ret = rte_eth_module_eeprom_parse(minfo.type, einfo.data, einfo.length,
+                       port_module_eeprom_field_print, NULL);
+       if (ret == -ENOTSUP)
+               fprintf(stderr, "Unsupported module type: 0x%x\n", minfo.type);
+       else if (ret != 0)
+               fprintf(stderr, "Unable to decode module EEPROM: %s\n",
+                       rte_strerror(-ret));
+       free(einfo.data);
+}
+
 int
 port_id_is_invalid(portid_t port_id, enum print_warning warning)
 {
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index d23950ab9d..2ca4aaf086 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -990,6 +990,7 @@ void port_eeprom_display(portid_t port_id);
 void port_eeprom_set(portid_t port_id, uint32_t magic, uint32_t offset,
                     uint32_t length, uint8_t *value);
 void port_module_eeprom_display(portid_t port_id);
+void port_module_eeprom_decode_display(portid_t port_id);
 void port_summary_header_display(void);
 void rx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void tx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
diff --git a/doc/guides/rel_notes/release_26_11.rst 
b/doc/guides/rel_notes/release_26_11.rst
index d25dc72edf..d0c896634b 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -84,6 +84,8 @@ New Features
   It can decode data read with ``rte_eth_dev_get_module_eeprom()``
   or obtained from any other source with the same layout,
   such as the Linux ethtool ``ETHTOOL_GMODULEEEPROM`` ioctl.
+  The testpmd command ``show port (port_id) module_eeprom decode``
+  uses it to display the decoded module EEPROM.
 
 * **Updated AF_XDP driver.**
 
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst 
b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 30cac0ad8c..a967bbef76 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -222,6 +222,14 @@ Display the EEPROM information of a port::
 
    testpmd> show port (port_id) (module_eeprom|eeprom)
 
+show port module_eeprom decode
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Display the module EEPROM of a port decoded according to the SFF 
specifications,
+for example the vendor, the transceiver type and the digital diagnostics::
+
+   testpmd> show port (port_id) module_eeprom decode
+
 set eeprom
 ~~~~~~~~~~
 
-- 
2.47.3

Reply via email to