]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Octeontx2-pf: ethtool: support multi advertise mode
authorHariprasad Kelam <hkelam@marvell.com>
Wed, 25 Jun 2025 09:21:07 +0000 (14:51 +0530)
committerJakub Kicinski <kuba@kernel.org>
Fri, 27 Jun 2025 23:55:59 +0000 (16:55 -0700)
Current implementation considers only first advertise
mode and passes the same to firmware to process.
This patch extends code such that user can advertise
multiple modes on the given interface.

Below are high level changes:

1. Remove unnecessary speed/duplex/autoneg validation as its
   already verified as part of "set_link_ksettings"

2. Since scratch csr framework designed to support single mode at a time,
   use "shared firmware data" for multi mode support.

Signed-off-by: Hariprasad Kelam <hkelam@marvell.com>
Link: https://patch.msgid.link/20250625092107.9746-4-hkelam@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/marvell/octeontx2/af/cgx.c
drivers/net/ethernet/marvell/octeontx2/af/cgx.h
drivers/net/ethernet/marvell/octeontx2/af/mbox.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c

index 5c2435f39308d6e1daae001ef54df6536734fa44..846ee2b9edf12e897cecdbf22d46878a0b5603f3 100644 (file)
@@ -1185,15 +1185,10 @@ static void set_mod_args(struct cgx_set_link_mode_args *args,
        int mode_baseidx;
        u8 cgx_mode;
 
-       /* Fill default values incase of user did not pass
-        * valid parameters
-        */
-       if (args->duplex == DUPLEX_UNKNOWN)
-               args->duplex = duplex;
-       if (args->speed == SPEED_UNKNOWN)
-               args->speed = speed;
-       if (args->an == AUTONEG_UNKNOWN)
-               args->an = autoneg;
+       if (args->multimode) {
+               args->mode |= mode;
+               return;
+       }
 
        /* Derive mode_base_idx and mode fields based
         * on cgx_mode value
@@ -1494,18 +1489,29 @@ int cgx_get_fwdata_base(u64 *base)
 }
 
 int cgx_set_link_mode(void *cgxd, struct cgx_set_link_mode_args args,
+                     struct cgx_lmac_fwdata_s *linkmodes,
                      int cgx_id, int lmac_id)
 {
        struct cgx *cgx = cgxd;
        u64 req = 0, resp;
+       u8 bit;
 
        if (!cgx)
                return -ENODEV;
 
-       if (args.mode)
-               otx2_map_ethtool_link_modes(args.mode, &args);
-       if (!args.speed && args.duplex && !args.an)
-               return -EINVAL;
+       for_each_set_bit(bit, args.advertising,
+                        __ETHTOOL_LINK_MODE_MASK_NBITS)
+               otx2_map_ethtool_link_modes(bit, &args);
+
+       if (args.multimode) {
+               if (linkmodes->advertised_link_modes_own != CGX_CMD_OWN_NS)
+                       return -EBUSY;
+
+               linkmodes->advertised_link_modes = args.mode;
+               /* Update ownership */
+               linkmodes->advertised_link_modes_own = CGX_CMD_OWN_FIRMWARE;
+               args.mode = GENMASK_ULL(41, 0);
+       }
 
        req = FIELD_SET(CMDREG_ID, CGX_CMD_MODE_CHANGE, req);
        req = FIELD_SET(CMDMODECHANGE_SPEED,
index 1cf12e5c7da873e972628eff34a69c774c1659ee..950231e7ea710617e1b5991d48a18e484b5eca5d 100644 (file)
@@ -171,6 +171,7 @@ int cgx_set_fec(u64 fec, int cgx_id, int lmac_id);
 int cgx_get_fec_stats(void *cgxd, int lmac_id, struct cgx_fec_stats_rsp *rsp);
 int cgx_get_phy_fec_stats(void *cgxd, int lmac_id);
 int cgx_set_link_mode(void *cgxd, struct cgx_set_link_mode_args args,
+                     struct cgx_lmac_fwdata_s *linkmodes,
                      int cgx_id, int lmac_id);
 u64 cgx_features_get(void *cgxd);
 struct mac_ops *get_mac_ops(void *cgxd);
index 2fc6b0ba7494977b516e137c8ec41c0b7e53f925..0bc0dc79868b13dbb0c8cd3a06321ea2ae140f2f 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/etherdevice.h>
 #include <linux/sizes.h>
+#include <linux/ethtool.h>
 
 #include "rvu_struct.h"
 #include "common.h"
@@ -658,7 +659,8 @@ struct cgx_lmac_fwdata_s {
        u64 supported_link_modes;
        /* only applicable if AN is supported */
        u64 advertised_fec;
-       u64 advertised_link_modes;
+       u64 advertised_link_modes_own:1; /* CGX_CMD_OWN */
+       u64 advertised_link_modes:63;
        /* Only applicable if SFP/QSFP slot is present */
        struct sfp_eeprom_s sfp_eeprom;
        struct phy_s phy;
@@ -676,11 +678,12 @@ struct cgx_set_link_mode_args {
        u8 duplex;
        u8 an;
        u8 mode_baseidx;
+       u8 multimode;
        u64 mode;
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
 };
 
 struct cgx_set_link_mode_req {
-#define AUTONEG_UNKNOWN                0xff
        struct mbox_msghdr hdr;
        struct cgx_set_link_mode_args args;
 };
index b79db887ab9b2119b4893c784d0d0d58d1d47f41..890a1a5df2ded717c6101e51238065f2afc1a659 100644 (file)
@@ -1223,6 +1223,7 @@ int rvu_mbox_handler_cgx_set_link_mode(struct rvu *rvu,
                                       struct cgx_set_link_mode_rsp *rsp)
 {
        int pf = rvu_get_pf(rvu->pdev, req->hdr.pcifunc);
+       struct cgx_lmac_fwdata_s *linkmodes;
        u8 cgx_idx, lmac;
        void *cgxd;
 
@@ -1231,7 +1232,13 @@ int rvu_mbox_handler_cgx_set_link_mode(struct rvu *rvu,
 
        rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac);
        cgxd = rvu_cgx_pdata(cgx_idx, rvu);
-       rsp->status = cgx_set_link_mode(cgxd, req->args, cgx_idx, lmac);
+       if (rvu->hw->lmac_per_cgx == CGX_LMACS_USX)
+               linkmodes = &rvu->fwdata->cgx_fw_data_usx[cgx_idx][lmac];
+       else
+               linkmodes = &rvu->fwdata->cgx_fw_data[cgx_idx][lmac];
+
+       rsp->status = cgx_set_link_mode(cgxd, req->args, linkmodes,
+                                       cgx_idx, lmac);
        return 0;
 }
 
index ae1cdd51b9fb3ea3c8ff4cff30050334cd01fe20..20de517dfb098b20d74511b15d7e977163f5b9d0 100644 (file)
@@ -1212,23 +1212,10 @@ static int otx2_get_link_ksettings(struct net_device *netdev,
        return 0;
 }
 
-static void otx2_get_advertised_mode(const struct ethtool_link_ksettings *cmd,
-                                    u64 *mode)
-{
-       u32 bit_pos;
-
-       /* Firmware does not support requesting multiple advertised modes
-        * return first set bit
-        */
-       bit_pos = find_first_bit(cmd->link_modes.advertising,
-                                __ETHTOOL_LINK_MODE_MASK_NBITS);
-       if (bit_pos != __ETHTOOL_LINK_MODE_MASK_NBITS)
-               *mode = bit_pos;
-}
-
 static int otx2_set_link_ksettings(struct net_device *netdev,
                                   const struct ethtool_link_ksettings *cmd)
 {
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
        struct otx2_nic *pf = netdev_priv(netdev);
        struct ethtool_link_ksettings cur_ks;
        struct cgx_set_link_mode_req *req;
@@ -1265,7 +1252,20 @@ static int otx2_set_link_ksettings(struct net_device *netdev,
         */
        req->args.duplex = cmd->base.duplex ^ 0x1;
        req->args.an = cmd->base.autoneg;
-       otx2_get_advertised_mode(cmd, &req->args.mode);
+       /* Mask unsupported modes and send message to AF */
+       linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, mask);
+       linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, mask);
+       linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, mask);
+
+       linkmode_copy(req->args.advertising,
+                     cmd->link_modes.advertising);
+       linkmode_andnot(req->args.advertising,
+                       req->args.advertising, mask);
+
+       /* inform AF that we need parse this differently */
+       if (bitmap_weight(req->args.advertising,
+                         __ETHTOOL_LINK_MODE_MASK_NBITS) >= 2)
+               req->args.multimode = true;
 
        err = otx2_sync_mbox_msg(&pf->mbox);
 end: