Commit 865eddcf authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'mlx5-misc-enhancements-2025-03-04'

Tariq Toukan says:

====================
mlx5 misc enhancements 2025-03-04

This series introduces enhancements to the mlx5 core and Eth drivers.

Patches 1-3 by Shahar introduce support for configuring lanes alongside
speed when autonegotiation is disabled. The combination of speed and the
number of lanes corresponds to a specific link mode (in the extended
mask typically used in newer hardware), allowing the user to select a
precise link mode when autonegotiation is off, instead of just choosing
the speed.

Patch 4 by Amir extends the multi-port LAG support.

Patches 5-6 by Leon enhance IPsec matching logic.

v1: https://lore.kernel.org/20250226114752.104838-1-tariqt@nvidia.com
====================

Link: https://patch.msgid.link/20250304160620.417580-1-tariqt@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 92d36905 ca7992f5
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable,
int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
{
	struct mlx5_port_eth_proto eproto;
	const struct mlx5_link_info *info;
	bool force_legacy = false;
	bool ext;
	int err;
@@ -94,9 +95,13 @@ int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
		if (err)
			goto out;
	}
	*speed = mlx5_port_ptys2speed(mdev, eproto.oper, force_legacy);
	if (!(*speed))
	info = mlx5_port_ptys2info(mdev, eproto.oper, force_legacy);
	if (!info) {
		*speed = SPEED_UNKNOWN;
		err = -EINVAL;
		goto out;
	}
	*speed = info->speed;

out:
	return err;
+66 −15
Original line number Diff line number Diff line
@@ -277,12 +277,12 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry,
	case XFRM_DEV_OFFLOAD_IN:
		src = attrs->dmac;
		dst = attrs->smac;
		pkey = &attrs->saddr.a4;
		pkey = &attrs->addrs.saddr.a4;
		break;
	case XFRM_DEV_OFFLOAD_OUT:
		src = attrs->smac;
		dst = attrs->dmac;
		pkey = &attrs->daddr.a4;
		pkey = &attrs->addrs.daddr.a4;
		break;
	default:
		return;
@@ -303,6 +303,16 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry,
	neigh_release(n);
}

static void mlx5e_ipsec_state_mask(struct mlx5e_ipsec_addr *addrs)
{
	/*
	 * State doesn't have subnet prefixes in outer headers.
	 * The match is performed for exaxt source/destination addresses.
	 */
	memset(addrs->smask.m6, 0xFF, sizeof(__be32) * 4);
	memset(addrs->dmask.m6, 0xFF, sizeof(__be32) * 4);
}

void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry,
					struct mlx5_accel_esp_xfrm_attrs *attrs)
{
@@ -374,9 +384,11 @@ void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry,
	attrs->spi = be32_to_cpu(x->id.spi);

	/* source , destination ips */
	memcpy(&attrs->saddr, x->props.saddr.a6, sizeof(attrs->saddr));
	memcpy(&attrs->daddr, x->id.daddr.a6, sizeof(attrs->daddr));
	attrs->family = x->props.family;
	memcpy(&attrs->addrs.saddr, x->props.saddr.a6,
	       sizeof(attrs->addrs.saddr));
	memcpy(&attrs->addrs.daddr, x->id.daddr.a6, sizeof(attrs->addrs.daddr));
	attrs->addrs.family = x->props.family;
	mlx5e_ipsec_state_mask(&attrs->addrs);
	attrs->type = x->xso.type;
	attrs->reqid = x->props.reqid;
	attrs->upspec.dport = ntohs(x->sel.dport);
@@ -428,7 +440,8 @@ static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev,
	}
	if (x->encap) {
		if (!(mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ESPINUDP)) {
			NL_SET_ERR_MSG_MOD(extack, "Encapsulation is not supported");
			NL_SET_ERR_MSG_MOD(extack,
					   "Encapsulation is not supported");
			return -EINVAL;
		}

@@ -853,13 +866,13 @@ static int mlx5e_ipsec_netevent_event(struct notifier_block *nb,
	xa_for_each_marked(&ipsec->sadb, idx, sa_entry, MLX5E_IPSEC_TUNNEL_SA) {
		attrs = &sa_entry->attrs;

		if (attrs->family == AF_INET) {
			if (!neigh_key_eq32(n, &attrs->saddr.a4) &&
			    !neigh_key_eq32(n, &attrs->daddr.a4))
		if (attrs->addrs.family == AF_INET) {
			if (!neigh_key_eq32(n, &attrs->addrs.saddr.a4) &&
			    !neigh_key_eq32(n, &attrs->addrs.daddr.a4))
				continue;
		} else {
			if (!neigh_key_eq128(n, &attrs->saddr.a4) &&
			    !neigh_key_eq128(n, &attrs->daddr.a4))
			if (!neigh_key_eq128(n, &attrs->addrs.saddr.a4) &&
			    !neigh_key_eq128(n, &attrs->addrs.daddr.a4))
				continue;
		}

@@ -1035,7 +1048,7 @@ static void mlx5e_xfrm_update_stats(struct xfrm_state *x)
	 * by removing always available headers.
	 */
	headers = sizeof(struct ethhdr);
	if (sa_entry->attrs.family == AF_INET)
	if (sa_entry->attrs.addrs.family == AF_INET)
		headers += sizeof(struct iphdr);
	else
		headers += sizeof(struct ipv6hdr);
@@ -1044,6 +1057,43 @@ static void mlx5e_xfrm_update_stats(struct xfrm_state *x)
	x->curlft.bytes += success_bytes - headers * success_packets;
}

static __be32 word_to_mask(int prefix)
{
	if (prefix < 0)
		return 0;

	if (!prefix || prefix > 31)
		return cpu_to_be32(0xFFFFFFFF);

	return cpu_to_be32(((1U << prefix) - 1) << (32 - prefix));
}

static void mlx5e_ipsec_policy_mask(struct mlx5e_ipsec_addr *addrs,
				    struct xfrm_selector *sel)
{
	int i;

	if (addrs->family == AF_INET) {
		addrs->smask.m4 = word_to_mask(sel->prefixlen_s);
		addrs->saddr.a4 &= addrs->smask.m4;
		addrs->dmask.m4 = word_to_mask(sel->prefixlen_d);
		addrs->daddr.a4 &= addrs->dmask.m4;
		return;
	}

	for (i = 0; i < 4; i++) {
		if (sel->prefixlen_s != 32 * i)
			addrs->smask.m6[i] =
				word_to_mask(sel->prefixlen_s - 32 * i);
		addrs->saddr.a6[i] &= addrs->smask.m6[i];

		if (sel->prefixlen_d != 32 * i)
			addrs->dmask.m6[i] =
				word_to_mask(sel->prefixlen_d - 32 * i);
		addrs->daddr.a6[i] &= addrs->dmask.m6[i];
	}
}

static int mlx5e_xfrm_validate_policy(struct mlx5_core_dev *mdev,
				      struct xfrm_policy *x,
				      struct netlink_ext_ack *extack)
@@ -1116,9 +1166,10 @@ mlx5e_ipsec_build_accel_pol_attrs(struct mlx5e_ipsec_pol_entry *pol_entry,
	sel = &x->selector;
	memset(attrs, 0, sizeof(*attrs));

	memcpy(&attrs->saddr, sel->saddr.a6, sizeof(attrs->saddr));
	memcpy(&attrs->daddr, sel->daddr.a6, sizeof(attrs->daddr));
	attrs->family = sel->family;
	memcpy(&attrs->addrs.saddr, sel->saddr.a6, sizeof(attrs->addrs.saddr));
	memcpy(&attrs->addrs.daddr, sel->daddr.a6, sizeof(attrs->addrs.daddr));
	attrs->addrs.family = sel->family;
	mlx5e_ipsec_policy_mask(&attrs->addrs, sel);
	attrs->dir = x->xdo.dir;
	attrs->action = x->action;
	attrs->type = XFRM_DEV_OFFLOAD_PACKET;
+17 −18
Original line number Diff line number Diff line
@@ -76,27 +76,36 @@ struct mlx5_replay_esn {
	u8 trigger : 1;
};

struct mlx5_accel_esp_xfrm_attrs {
	u32   spi;
	u32   mode;
	struct aes_gcm_keymat aes_gcm;

struct mlx5e_ipsec_addr {
	union {
		__be32 a4;
		__be32 a6[4];
	} saddr;

	union {
		__be32 m4;
		__be32 m6[4];
	} smask;
	union {
		__be32 a4;
		__be32 a6[4];
	} daddr;
	union {
		__be32 m4;
		__be32 m6[4];
	} dmask;
	u8 family;
};

struct mlx5_accel_esp_xfrm_attrs {
	u32   spi;
	u32   mode;
	struct aes_gcm_keymat aes_gcm;
	struct mlx5e_ipsec_addr addrs;
	struct upspec upspec;
	u8 dir : 2;
	u8 type : 2;
	u8 drop : 1;
	u8 encap : 1;
	u8 family;
	struct mlx5_replay_esn replay_esn;
	u32 authsize;
	u32 reqid;
@@ -279,18 +288,8 @@ struct mlx5e_ipsec_sa_entry {
};

struct mlx5_accel_pol_xfrm_attrs {
	union {
		__be32 a4;
		__be32 a6[4];
	} saddr;

	union {
		__be32 a4;
		__be32 a6[4];
	} daddr;

	struct mlx5e_ipsec_addr addrs;
	struct upspec upspec;
	u8 family;
	u8 action;
	u8 type : 2;
	u8 dir : 2;
+54 −41
Original line number Diff line number Diff line
@@ -1484,9 +1484,14 @@ static void tx_ft_put_policy(struct mlx5e_ipsec *ipsec, u32 prio, int type)
	mutex_unlock(&tx->ft.mutex);
}

static void setup_fte_addr4(struct mlx5_flow_spec *spec, __be32 *saddr,
			    __be32 *daddr)
static void setup_fte_addr4(struct mlx5_flow_spec *spec,
			    struct mlx5e_ipsec_addr *addrs)
{
	__be32 *saddr = &addrs->saddr.a4;
	__be32 *smask = &addrs->smask.m4;
	__be32 *daddr = &addrs->daddr.a4;
	__be32 *dmask = &addrs->dmask.m4;

	if (!*saddr && !*daddr)
		return;

@@ -1498,21 +1503,26 @@ static void setup_fte_addr4(struct mlx5_flow_spec *spec, __be32 *saddr,
	if (*saddr) {
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
				    outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4), saddr, 4);
		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
				 outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4);
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
				    outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4), smask, 4);
	}

	if (*daddr) {
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
				    outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4), daddr, 4);
		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
				 outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
				    outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4), dmask, 4);
	}
}

static void setup_fte_addr6(struct mlx5_flow_spec *spec, __be32 *saddr,
			    __be32 *daddr)
static void setup_fte_addr6(struct mlx5_flow_spec *spec,
			    struct mlx5e_ipsec_addr *addrs)
{
	__be32 *saddr = addrs->saddr.a6;
	__be32 *smask = addrs->smask.m6;
	__be32 *daddr = addrs->daddr.a6;
	__be32 *dmask = addrs->dmask.m6;

	if (addr6_all_zero(saddr) && addr6_all_zero(daddr))
		return;

@@ -1524,15 +1534,15 @@ static void setup_fte_addr6(struct mlx5_flow_spec *spec, __be32 *saddr,
	if (!addr6_all_zero(saddr)) {
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
				    outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), saddr, 16);
		memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
				    outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), 0xff, 16);
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
				    outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), dmask, 16);
	}

	if (!addr6_all_zero(daddr)) {
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
				    outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), daddr, 16);
		memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
				    outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 0xff, 16);
		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
				    outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), smask, 16);
	}
}

@@ -1722,7 +1732,7 @@ setup_pkt_tunnel_reformat(struct mlx5_core_dev *mdev,
	if (attrs->dir == XFRM_DEV_OFFLOAD_OUT) {
		bfflen += sizeof(*esp_hdr) + 8;

		switch (attrs->family) {
		switch (attrs->addrs.family) {
		case AF_INET:
			bfflen += sizeof(*iphdr);
			break;
@@ -1739,7 +1749,7 @@ setup_pkt_tunnel_reformat(struct mlx5_core_dev *mdev,
		return -ENOMEM;

	eth_hdr = (struct ethhdr *)reformatbf;
	switch (attrs->family) {
	switch (attrs->addrs.family) {
	case AF_INET:
		eth_hdr->h_proto = htons(ETH_P_IP);
		break;
@@ -1762,11 +1772,11 @@ setup_pkt_tunnel_reformat(struct mlx5_core_dev *mdev,
		reformat_params->param_0 = attrs->authsize;

		hdr = reformatbf + sizeof(*eth_hdr);
		switch (attrs->family) {
		switch (attrs->addrs.family) {
		case AF_INET:
			iphdr = (struct iphdr *)hdr;
			memcpy(&iphdr->saddr, &attrs->saddr.a4, 4);
			memcpy(&iphdr->daddr, &attrs->daddr.a4, 4);
			memcpy(&iphdr->saddr, &attrs->addrs.saddr.a4, 4);
			memcpy(&iphdr->daddr, &attrs->addrs.daddr.a4, 4);
			iphdr->version = 4;
			iphdr->ihl = 5;
			iphdr->ttl = IPSEC_TUNNEL_DEFAULT_TTL;
@@ -1775,8 +1785,8 @@ setup_pkt_tunnel_reformat(struct mlx5_core_dev *mdev,
			break;
		case AF_INET6:
			ipv6hdr = (struct ipv6hdr *)hdr;
			memcpy(&ipv6hdr->saddr, &attrs->saddr.a6, 16);
			memcpy(&ipv6hdr->daddr, &attrs->daddr.a6, 16);
			memcpy(&ipv6hdr->saddr, &attrs->addrs.saddr.a6, 16);
			memcpy(&ipv6hdr->daddr, &attrs->addrs.daddr.a6, 16);
			ipv6hdr->nexthdr = IPPROTO_ESP;
			ipv6hdr->version = 6;
			ipv6hdr->hop_limit = IPSEC_TUNNEL_DEFAULT_TTL;
@@ -1810,7 +1820,7 @@ static int get_reformat_type(struct mlx5_accel_esp_xfrm_attrs *attrs)
			return MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT_OVER_UDP;
		return MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT;
	case XFRM_DEV_OFFLOAD_OUT:
		if (attrs->family == AF_INET) {
		if (attrs->addrs.family == AF_INET) {
			if (attrs->encap)
				return MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_UDPV4;
			return MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV4;
@@ -2003,7 +2013,7 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
	struct mlx5_fc *counter;
	int err = 0;

	rx = rx_ft_get(mdev, ipsec, attrs->family, attrs->type);
	rx = rx_ft_get(mdev, ipsec, attrs->addrs.family, attrs->type);
	if (IS_ERR(rx))
		return PTR_ERR(rx);

@@ -2013,10 +2023,10 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
		goto err_alloc;
	}

	if (attrs->family == AF_INET)
		setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
	if (attrs->addrs.family == AF_INET)
		setup_fte_addr4(spec, &attrs->addrs);
	else
		setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6);
		setup_fte_addr6(spec, &attrs->addrs);

	setup_fte_spi(spec, attrs->spi, attrs->encap);
	if (!attrs->encap)
@@ -2116,7 +2126,7 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
err_mod_header:
	kvfree(spec);
err_alloc:
	rx_ft_put(ipsec, attrs->family, attrs->type);
	rx_ft_put(ipsec, attrs->addrs.family, attrs->type);
	return err;
}

@@ -2148,10 +2158,10 @@ static int tx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)

	switch (attrs->type) {
	case XFRM_DEV_OFFLOAD_CRYPTO:
		if (attrs->family == AF_INET)
			setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
		if (attrs->addrs.family == AF_INET)
			setup_fte_addr4(spec, &attrs->addrs);
		else
			setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6);
			setup_fte_addr6(spec, &attrs->addrs);
		setup_fte_spi(spec, attrs->spi, false);
		setup_fte_esp(spec);
		setup_fte_reg_a(spec);
@@ -2235,10 +2245,10 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
	}

	tx = ipsec_tx(ipsec, attrs->type);
	if (attrs->family == AF_INET)
		setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
	if (attrs->addrs.family == AF_INET)
		setup_fte_addr4(spec, &attrs->addrs);
	else
		setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6);
		setup_fte_addr6(spec, &attrs->addrs);

	setup_fte_no_frags(spec);
	setup_fte_upper_proto_match(spec, &attrs->upspec);
@@ -2308,12 +2318,12 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
	struct mlx5e_ipsec_rx *rx;
	int err, dstn = 0;

	ft = rx_ft_get_policy(mdev, pol_entry->ipsec, attrs->family, attrs->prio,
			      attrs->type);
	ft = rx_ft_get_policy(mdev, pol_entry->ipsec, attrs->addrs.family,
			      attrs->prio, attrs->type);
	if (IS_ERR(ft))
		return PTR_ERR(ft);

	rx = ipsec_rx(pol_entry->ipsec, attrs->family, attrs->type);
	rx = ipsec_rx(pol_entry->ipsec, attrs->addrs.family, attrs->type);

	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
	if (!spec) {
@@ -2321,10 +2331,10 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
		goto err_alloc;
	}

	if (attrs->family == AF_INET)
		setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
	if (attrs->addrs.family == AF_INET)
		setup_fte_addr4(spec, &attrs->addrs);
	else
		setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6);
		setup_fte_addr6(spec, &attrs->addrs);

	setup_fte_no_frags(spec);
	setup_fte_upper_proto_match(spec, &attrs->upspec);
@@ -2364,7 +2374,8 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
err_action:
	kvfree(spec);
err_alloc:
	rx_ft_put_policy(pol_entry->ipsec, attrs->family, attrs->prio, attrs->type);
	rx_ft_put_policy(pol_entry->ipsec, attrs->addrs.family, attrs->prio,
			 attrs->type);
	return err;
}

@@ -2638,7 +2649,8 @@ void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
		mlx5_fc_destroy(mdev, ipsec_rule->replay.fc);
	}
	mlx5_esw_ipsec_rx_id_mapping_remove(sa_entry);
	rx_ft_put(sa_entry->ipsec, sa_entry->attrs.family, sa_entry->attrs.type);
	rx_ft_put(sa_entry->ipsec, sa_entry->attrs.addrs.family,
		  sa_entry->attrs.type);
}

int mlx5e_accel_ipsec_fs_add_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
@@ -2674,7 +2686,8 @@ void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
	mlx5e_ipsec_unblock_tc_offload(pol_entry->ipsec->mdev);

	if (pol_entry->attrs.dir == XFRM_DEV_OFFLOAD_IN) {
		rx_ft_put_policy(pol_entry->ipsec, pol_entry->attrs.family,
		rx_ft_put_policy(pol_entry->ipsec,
				 pol_entry->attrs.addrs.family,
				 pol_entry->attrs.prio, pol_entry->attrs.type);
		return;
	}
@@ -2814,7 +2827,7 @@ bool mlx5e_ipsec_fs_tunnel_enabled(struct mlx5e_ipsec_sa_entry *sa_entry)
	struct mlx5e_ipsec_rx *rx;
	struct mlx5e_ipsec_tx *tx;

	rx = ipsec_rx(sa_entry->ipsec, attrs->family, attrs->type);
	rx = ipsec_rx(sa_entry->ipsec, attrs->addrs.family, attrs->type);
	tx = ipsec_tx(sa_entry->ipsec, attrs->type);
	if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
		return tx->allow_tunnel_mode;
+27 −20
Original line number Diff line number Diff line
@@ -42,6 +42,9 @@
#include "lib/clock.h"
#include "en/fs_ethtool.h"

#define LANES_UNKNOWN		 0
#define MAX_LANES		 8

void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv,
			       struct ethtool_drvinfo *drvinfo)
{
@@ -1076,32 +1079,34 @@ static void ptys2ethtool_supported_advertised_port(struct mlx5_core_dev *mdev,
	}
}

static void get_speed_duplex(struct net_device *netdev,
static void get_link_properties(struct net_device *netdev,
				u32 eth_proto_oper, bool force_legacy,
				u16 data_rate_oper,
				struct ethtool_link_ksettings *link_ksettings)
{
	struct mlx5e_priv *priv = netdev_priv(netdev);
	u32 speed = SPEED_UNKNOWN;
	const struct mlx5_link_info *info;
	u8 duplex = DUPLEX_UNKNOWN;
	u32 speed = SPEED_UNKNOWN;
	u32 lanes = LANES_UNKNOWN;

	if (!netif_carrier_ok(netdev))
		goto out;

	speed = mlx5_port_ptys2speed(priv->mdev, eth_proto_oper, force_legacy);
	if (!speed) {
		if (data_rate_oper)
	info = mlx5_port_ptys2info(priv->mdev, eth_proto_oper, force_legacy);
	if (info) {
		speed = info->speed;
		lanes = info->lanes;
		duplex = DUPLEX_FULL;
	} else if (data_rate_oper) {
		speed = 100 * data_rate_oper;
		else
			speed = SPEED_UNKNOWN;
		goto out;
		lanes = MAX_LANES;
	}

	duplex = DUPLEX_FULL;

out:
	link_ksettings->base.speed = speed;
	link_ksettings->base.duplex = duplex;
	link_ksettings->base.speed = speed;
	link_ksettings->lanes = lanes;
}

static void get_supported(struct mlx5_core_dev *mdev, u32 eth_proto_cap,
@@ -1238,7 +1243,7 @@ static int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
	get_supported(mdev, eth_proto_cap, link_ksettings);
	get_advertising(eth_proto_admin, tx_pause, rx_pause, link_ksettings,
			admin_ext);
	get_speed_duplex(priv->netdev, eth_proto_oper, !admin_ext,
	get_link_properties(priv->netdev, eth_proto_oper, !admin_ext,
			    data_rate_oper, link_ksettings);

	eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap;
@@ -1349,6 +1354,7 @@ static int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
{
	struct mlx5_core_dev *mdev = priv->mdev;
	struct mlx5_port_eth_proto eproto;
	struct mlx5_link_info info = {};
	const unsigned long *adver;
	bool an_changes = false;
	u8 an_disable_admin;
@@ -1359,7 +1365,6 @@ static int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
	u32 link_modes;
	u8 an_status;
	u8 autoneg;
	u32 speed;
	bool ext;
	int err;

@@ -1367,7 +1372,8 @@ static int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,

	adver = link_ksettings->link_modes.advertising;
	autoneg = link_ksettings->base.autoneg;
	speed = link_ksettings->base.speed;
	info.speed = link_ksettings->base.speed;
	info.lanes = link_ksettings->lanes;

	ext_supported = mlx5_ptys_ext_supported(mdev);
	ext_requested = ext_link_mode_requested(adver);
@@ -1384,7 +1390,7 @@ static int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
		goto out;
	}
	link_modes = autoneg == AUTONEG_ENABLE ? ethtool2ptys_adver_func(adver) :
		mlx5_port_speed2linkmodes(mdev, speed, !ext);
		mlx5_port_info2linkmodes(mdev, &info, !ext);

	err = mlx5e_speed_validate(priv->netdev, ext, link_modes, autoneg);
	if (err)
@@ -2615,6 +2621,7 @@ static void mlx5e_get_ts_stats(struct net_device *netdev,
}

const struct ethtool_ops mlx5e_ethtool_ops = {
	.cap_link_lanes_supported = true,
	.cap_rss_ctx_supported	= true,
	.rxfh_per_ctx_key	= true,
	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
Loading