net/funeth: Support for ethtool -m
authorDimitris Michailidis <d.michailidis@fungible.com>
Mon, 27 Jun 2022 18:20:00 +0000 (11:20 -0700)
committerJakub Kicinski <kuba@kernel.org>
Wed, 29 Jun 2022 04:26:26 +0000 (21:26 -0700)
Add the FW command for reading port module memory pages and implement
ethtool's get_module_eeprom_by_page operation.

Signed-off-by: Dimitris Michailidis <dmichail@fungible.com>
Link: https://lore.kernel.org/r/20220627182000.8198-1-dmichail@fungible.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/fungible/funcore/fun_hci.h
drivers/net/ethernet/fungible/funeth/funeth_ethtool.c

index 257203e..f218196 100644 (file)
@@ -442,6 +442,7 @@ enum fun_port_lane_attr {
 };
 
 enum fun_admin_port_subop {
+       FUN_ADMIN_PORT_SUBOP_XCVR_READ = 0x23,
        FUN_ADMIN_PORT_SUBOP_INETADDR_EVENT = 0x24,
 };
 
@@ -595,6 +596,19 @@ struct fun_admin_port_req {
 
                        struct fun_admin_read48_req read48[];
                } read;
+               struct fun_admin_port_xcvr_read_req {
+                       u8 subop;
+                       u8 rsvd0;
+                       __be16 flags;
+                       __be32 id;
+
+                       u8 bank;
+                       u8 page;
+                       u8 offset;
+                       u8 length;
+                       u8 dev_addr;
+                       u8 rsvd1[3];
+               } xcvr_read;
                struct fun_admin_port_inetaddr_event_req {
                        __u8 subop;
                        __u8 rsvd0;
@@ -625,6 +639,15 @@ struct fun_admin_port_req {
                .id = cpu_to_be32(_id),                          \
        }
 
+#define FUN_ADMIN_PORT_XCVR_READ_REQ_INIT(_flags, _id, _bank, _page,   \
+                                         _offset, _length, _dev_addr) \
+       ((struct fun_admin_port_xcvr_read_req) {                       \
+               .subop = FUN_ADMIN_PORT_SUBOP_XCVR_READ,               \
+               .flags = cpu_to_be16(_flags), .id = cpu_to_be32(_id),  \
+               .bank = (_bank), .page = (_page), .offset = (_offset), \
+               .length = (_length), .dev_addr = (_dev_addr),          \
+       })
+
 struct fun_admin_port_rsp {
        struct fun_admin_rsp_common common;
 
@@ -659,6 +682,23 @@ struct fun_admin_port_rsp {
        } u;
 };
 
+struct fun_admin_port_xcvr_read_rsp {
+       struct fun_admin_rsp_common common;
+
+       u8 subop;
+       u8 rsvd0[3];
+       __be32 id;
+
+       u8 bank;
+       u8 page;
+       u8 offset;
+       u8 length;
+       u8 dev_addr;
+       u8 rsvd1[3];
+
+       u8 data[128];
+};
+
 enum fun_xcvr_type {
        FUN_XCVR_BASET = 0x0,
        FUN_XCVR_CU = 0x1,
index da42dd5..31aa185 100644 (file)
@@ -1118,6 +1118,39 @@ static int fun_set_fecparam(struct net_device *netdev,
        return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_FEC, fec_mode);
 }
 
+static int fun_get_port_module_page(struct net_device *netdev,
+                                   const struct ethtool_module_eeprom *req,
+                                   struct netlink_ext_ack *extack)
+{
+       union {
+               struct fun_admin_port_req req;
+               struct fun_admin_port_xcvr_read_rsp rsp;
+       } cmd;
+       struct funeth_priv *fp = netdev_priv(netdev);
+       int rc;
+
+       if (fp->port_caps & FUN_PORT_CAP_VPORT) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "Specified port is virtual, only physical ports have modules");
+               return -EOPNOTSUPP;
+       }
+
+       cmd.req.common = FUN_ADMIN_REQ_COMMON_INIT2(FUN_ADMIN_OP_PORT,
+                                                   sizeof(cmd.req));
+       cmd.req.u.xcvr_read =
+               FUN_ADMIN_PORT_XCVR_READ_REQ_INIT(0, netdev->dev_port,
+                                                 req->bank, req->page,
+                                                 req->offset, req->length,
+                                                 req->i2c_address);
+       rc = fun_submit_admin_sync_cmd(fp->fdev, &cmd.req.common, &cmd.rsp,
+                                      sizeof(cmd.rsp), 0);
+       if (rc)
+               return rc;
+
+       memcpy(req->data, cmd.rsp.data, req->length);
+       return req->length;
+}
+
 static const struct ethtool_ops fun_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
                                     ETHTOOL_COALESCE_MAX_FRAMES,
@@ -1156,6 +1189,7 @@ static const struct ethtool_ops fun_ethtool_ops = {
        .get_eth_mac_stats   = fun_get_802_3_stats,
        .get_eth_ctrl_stats  = fun_get_802_3_ctrl_stats,
        .get_rmon_stats      = fun_get_rmon_stats,
+       .get_module_eeprom_by_page = fun_get_port_module_page,
 };
 
 void fun_set_ethtool_ops(struct net_device *netdev)