Commit 5f21226b authored by Hariprasad Kelam's avatar Hariprasad Kelam Committed by Jakub Kicinski
Browse files

Octeontx2-pf: ethtool: support multi advertise mode



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: default avatarHariprasad Kelam <hkelam@marvell.com>
Link: https://patch.msgid.link/20250625092107.9746-4-hkelam@marvell.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent ad97e72f
Loading
Loading
Loading
Loading
+19 −13
Original line number Diff line number Diff line
@@ -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,
+1 −0
Original line number Diff line number Diff line
@@ -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);
+5 −2
Original line number Diff line number Diff line
@@ -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;
};
+8 −1
Original line number Diff line number Diff line
@@ -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;
}

+15 −15
Original line number Diff line number Diff line
@@ -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: