xref: /linux/drivers/net/ethernet/broadcom/bnge/bnge_link.c (revision 4a75900989c964fc839a615542f96353b1c7bc80)
17626cd3dSBhargava Marreddy // SPDX-License-Identifier: GPL-2.0
27626cd3dSBhargava Marreddy // Copyright (c) 2026 Broadcom.
37626cd3dSBhargava Marreddy 
47626cd3dSBhargava Marreddy #include <linux/linkmode.h>
57626cd3dSBhargava Marreddy 
67626cd3dSBhargava Marreddy #include "bnge.h"
77626cd3dSBhargava Marreddy #include "bnge_link.h"
87626cd3dSBhargava Marreddy #include "bnge_hwrm_lib.h"
97626cd3dSBhargava Marreddy 
10169f6e8dSBhargava Marreddy enum bnge_media_type {
11169f6e8dSBhargava Marreddy 	BNGE_MEDIA_UNKNOWN = 0,
12169f6e8dSBhargava Marreddy 	BNGE_MEDIA_CR,
13169f6e8dSBhargava Marreddy 	BNGE_MEDIA_SR,
14169f6e8dSBhargava Marreddy 	BNGE_MEDIA_LR_ER_FR,
15169f6e8dSBhargava Marreddy 	BNGE_MEDIA_KR,
16169f6e8dSBhargava Marreddy 	__BNGE_MEDIA_END,
17169f6e8dSBhargava Marreddy };
18169f6e8dSBhargava Marreddy 
19169f6e8dSBhargava Marreddy static const enum bnge_media_type bnge_phy_types[] = {
20169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR4] = BNGE_MEDIA_CR,
21169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR4] = BNGE_MEDIA_SR,
22169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR4] = BNGE_MEDIA_LR_ER_FR,
23169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER4] = BNGE_MEDIA_LR_ER_FR,
24169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR10] = BNGE_MEDIA_SR,
25169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR4] = BNGE_MEDIA_CR,
26169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR4] = BNGE_MEDIA_SR,
27169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR4] = BNGE_MEDIA_LR_ER_FR,
28169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER4] = BNGE_MEDIA_LR_ER_FR,
29169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASECR] = BNGE_MEDIA_CR,
30169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASESR] = BNGE_MEDIA_SR,
31169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASELR] = BNGE_MEDIA_LR_ER_FR,
32169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASEER] = BNGE_MEDIA_LR_ER_FR,
33169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR2] = BNGE_MEDIA_CR,
34169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR2] = BNGE_MEDIA_SR,
35169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR2] = BNGE_MEDIA_LR_ER_FR,
36169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER2] = BNGE_MEDIA_LR_ER_FR,
37169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR] = BNGE_MEDIA_CR,
38169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR] = BNGE_MEDIA_SR,
39169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR] = BNGE_MEDIA_LR_ER_FR,
40169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER] = BNGE_MEDIA_LR_ER_FR,
41169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR2] = BNGE_MEDIA_CR,
42169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR2] = BNGE_MEDIA_SR,
43169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR2] = BNGE_MEDIA_LR_ER_FR,
44169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER2] = BNGE_MEDIA_LR_ER_FR,
45169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR8] = BNGE_MEDIA_CR,
46169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR8] = BNGE_MEDIA_SR,
47169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR8] = BNGE_MEDIA_LR_ER_FR,
48169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER8] = BNGE_MEDIA_LR_ER_FR,
49169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR4] = BNGE_MEDIA_CR,
50169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR4] = BNGE_MEDIA_SR,
51169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR4] = BNGE_MEDIA_LR_ER_FR,
52169f6e8dSBhargava Marreddy 	[PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4] = BNGE_MEDIA_LR_ER_FR,
53169f6e8dSBhargava Marreddy };
54169f6e8dSBhargava Marreddy 
557626cd3dSBhargava Marreddy static u32 bnge_fw_to_ethtool_speed(u16 fw_link_speed)
567626cd3dSBhargava Marreddy {
577626cd3dSBhargava Marreddy 	switch (fw_link_speed) {
587626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_50GB:
597626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_50GB_PAM4:
607626cd3dSBhargava Marreddy 		return SPEED_50000;
617626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_100GB:
627626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_100GB_PAM4:
637626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_100GB_PAM4_112:
647626cd3dSBhargava Marreddy 		return SPEED_100000;
657626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_200GB:
667626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_200GB_PAM4:
677626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_200GB_PAM4_112:
687626cd3dSBhargava Marreddy 		return SPEED_200000;
697626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_400GB:
707626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_400GB_PAM4:
717626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_400GB_PAM4_112:
727626cd3dSBhargava Marreddy 		return SPEED_400000;
737626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_800GB:
747626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_800GB_PAM4_112:
757626cd3dSBhargava Marreddy 		return SPEED_800000;
767626cd3dSBhargava Marreddy 	default:
777626cd3dSBhargava Marreddy 		return SPEED_UNKNOWN;
787626cd3dSBhargava Marreddy 	}
797626cd3dSBhargava Marreddy }
807626cd3dSBhargava Marreddy 
817626cd3dSBhargava Marreddy static void bnge_set_auto_speed(struct bnge_net *bn)
827626cd3dSBhargava Marreddy {
837626cd3dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info = &bn->eth_link_info;
847626cd3dSBhargava Marreddy 	struct bnge_link_info *link_info;
857626cd3dSBhargava Marreddy 
867626cd3dSBhargava Marreddy 	link_info = &bn->bd->link_info;
877626cd3dSBhargava Marreddy 	elink_info->advertising = link_info->auto_link_speeds2;
887626cd3dSBhargava Marreddy }
897626cd3dSBhargava Marreddy 
907626cd3dSBhargava Marreddy static void bnge_set_force_speed(struct bnge_net *bn)
917626cd3dSBhargava Marreddy {
927626cd3dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info = &bn->eth_link_info;
937626cd3dSBhargava Marreddy 	struct bnge_link_info *link_info;
947626cd3dSBhargava Marreddy 
957626cd3dSBhargava Marreddy 	link_info = &bn->bd->link_info;
967626cd3dSBhargava Marreddy 	elink_info->req_link_speed = link_info->force_link_speed2;
977626cd3dSBhargava Marreddy 	switch (elink_info->req_link_speed) {
987626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_50GB_PAM4:
997626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_100GB_PAM4:
1007626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_200GB_PAM4:
1017626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_400GB_PAM4:
1027626cd3dSBhargava Marreddy 		elink_info->req_signal_mode = BNGE_SIG_MODE_PAM4;
1037626cd3dSBhargava Marreddy 		break;
1047626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_100GB_PAM4_112:
1057626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_200GB_PAM4_112:
1067626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_400GB_PAM4_112:
1077626cd3dSBhargava Marreddy 	case BNGE_LINK_SPEED_800GB_PAM4_112:
1087626cd3dSBhargava Marreddy 		elink_info->req_signal_mode = BNGE_SIG_MODE_PAM4_112;
1097626cd3dSBhargava Marreddy 		break;
1107626cd3dSBhargava Marreddy 	default:
1117626cd3dSBhargava Marreddy 		elink_info->req_signal_mode = BNGE_SIG_MODE_NRZ;
1127626cd3dSBhargava Marreddy 		break;
1137626cd3dSBhargava Marreddy 	}
1147626cd3dSBhargava Marreddy }
1157626cd3dSBhargava Marreddy 
1167626cd3dSBhargava Marreddy void bnge_init_ethtool_link_settings(struct bnge_net *bn)
1177626cd3dSBhargava Marreddy {
1187626cd3dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info = &bn->eth_link_info;
1197626cd3dSBhargava Marreddy 	struct bnge_link_info *link_info;
1207626cd3dSBhargava Marreddy 	struct bnge_dev *bd = bn->bd;
1217626cd3dSBhargava Marreddy 
1227626cd3dSBhargava Marreddy 	link_info = &bd->link_info;
1237626cd3dSBhargava Marreddy 
1247626cd3dSBhargava Marreddy 	if (BNGE_AUTO_MODE(link_info->auto_mode)) {
1257626cd3dSBhargava Marreddy 		elink_info->autoneg = BNGE_AUTONEG_SPEED;
1267626cd3dSBhargava Marreddy 		if (link_info->auto_pause_setting &
1277626cd3dSBhargava Marreddy 		    PORT_PHY_QCFG_RESP_AUTO_PAUSE_AUTONEG_PAUSE)
1287626cd3dSBhargava Marreddy 			elink_info->autoneg |= BNGE_AUTONEG_FLOW_CTRL;
1297626cd3dSBhargava Marreddy 		bnge_set_auto_speed(bn);
1307626cd3dSBhargava Marreddy 	} else {
1317626cd3dSBhargava Marreddy 		elink_info->autoneg = 0;
1327626cd3dSBhargava Marreddy 		elink_info->advertising = 0;
1337626cd3dSBhargava Marreddy 		bnge_set_force_speed(bn);
1347626cd3dSBhargava Marreddy 		elink_info->req_duplex = link_info->duplex_setting;
1357626cd3dSBhargava Marreddy 	}
1367626cd3dSBhargava Marreddy 	if (elink_info->autoneg & BNGE_AUTONEG_FLOW_CTRL)
1377626cd3dSBhargava Marreddy 		elink_info->req_flow_ctrl =
1387626cd3dSBhargava Marreddy 			link_info->auto_pause_setting & BNGE_LINK_PAUSE_BOTH;
1397626cd3dSBhargava Marreddy 	else
1407626cd3dSBhargava Marreddy 		elink_info->req_flow_ctrl = link_info->force_pause_setting;
1417626cd3dSBhargava Marreddy }
1427626cd3dSBhargava Marreddy 
1437626cd3dSBhargava Marreddy int bnge_probe_phy(struct bnge_net *bn, bool fw_dflt)
1447626cd3dSBhargava Marreddy {
1457626cd3dSBhargava Marreddy 	struct bnge_dev *bd = bn->bd;
1467626cd3dSBhargava Marreddy 	int rc;
1477626cd3dSBhargava Marreddy 
1487626cd3dSBhargava Marreddy 	bd->phy_flags = 0;
1497626cd3dSBhargava Marreddy 	rc = bnge_hwrm_phy_qcaps(bd);
1507626cd3dSBhargava Marreddy 	if (rc) {
1517626cd3dSBhargava Marreddy 		netdev_err(bn->netdev,
1527626cd3dSBhargava Marreddy 			   "Probe PHY can't get PHY qcaps (rc: %d)\n", rc);
1537626cd3dSBhargava Marreddy 		return rc;
1547626cd3dSBhargava Marreddy 	}
1557626cd3dSBhargava Marreddy 	if (bd->phy_flags & BNGE_PHY_FL_NO_FCS)
1567626cd3dSBhargava Marreddy 		bn->netdev->priv_flags |= IFF_SUPP_NOFCS;
1577626cd3dSBhargava Marreddy 	else
1587626cd3dSBhargava Marreddy 		bn->netdev->priv_flags &= ~IFF_SUPP_NOFCS;
1597626cd3dSBhargava Marreddy 	if (!fw_dflt)
1607626cd3dSBhargava Marreddy 		return 0;
1617626cd3dSBhargava Marreddy 
1627626cd3dSBhargava Marreddy 	rc = bnge_update_link(bn, false);
1637626cd3dSBhargava Marreddy 	if (rc) {
1647626cd3dSBhargava Marreddy 		netdev_err(bn->netdev, "Probe PHY can't update link (rc: %d)\n",
1657626cd3dSBhargava Marreddy 			   rc);
1667626cd3dSBhargava Marreddy 		return rc;
1677626cd3dSBhargava Marreddy 	}
1687626cd3dSBhargava Marreddy 	bnge_init_ethtool_link_settings(bn);
1697626cd3dSBhargava Marreddy 
1707626cd3dSBhargava Marreddy 	return 0;
1717626cd3dSBhargava Marreddy }
1727626cd3dSBhargava Marreddy 
1737626cd3dSBhargava Marreddy void bnge_hwrm_set_link_common(struct bnge_net *bn,
1747626cd3dSBhargava Marreddy 			       struct hwrm_port_phy_cfg_input *req)
1757626cd3dSBhargava Marreddy {
1767626cd3dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info = &bn->eth_link_info;
1777626cd3dSBhargava Marreddy 
1787626cd3dSBhargava Marreddy 	if (elink_info->autoneg & BNGE_AUTONEG_SPEED) {
1797626cd3dSBhargava Marreddy 		req->auto_mode |= PORT_PHY_CFG_REQ_AUTO_MODE_SPEED_MASK;
1807626cd3dSBhargava Marreddy 		req->enables |= cpu_to_le32(BNGE_PHY_AUTO_SPEEDS2_MASK);
1817626cd3dSBhargava Marreddy 		req->auto_link_speeds2_mask =
1827626cd3dSBhargava Marreddy 			cpu_to_le16(elink_info->advertising);
1837626cd3dSBhargava Marreddy 		req->enables |= cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_AUTO_MODE);
1847626cd3dSBhargava Marreddy 		req->flags |= cpu_to_le32(BNGE_PHY_FLAGS_RESTART_AUTO);
1857626cd3dSBhargava Marreddy 	} else {
1867626cd3dSBhargava Marreddy 		req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE);
1877626cd3dSBhargava Marreddy 		req->force_link_speeds2 =
1887626cd3dSBhargava Marreddy 			cpu_to_le16(elink_info->req_link_speed);
1897626cd3dSBhargava Marreddy 		req->enables |=
1907626cd3dSBhargava Marreddy 			cpu_to_le32(BNGE_PHY_FLAGS_ENA_FORCE_SPEEDS2);
1917626cd3dSBhargava Marreddy 		netif_info(bn, link, bn->netdev,
1927626cd3dSBhargava Marreddy 			   "Forcing FW speed2: %d\n",
1937626cd3dSBhargava Marreddy 			   (u32)elink_info->req_link_speed);
1947626cd3dSBhargava Marreddy 	}
1957626cd3dSBhargava Marreddy 
1967626cd3dSBhargava Marreddy 	/* tell FW that the setting takes effect immediately */
1977626cd3dSBhargava Marreddy 	req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_RESET_PHY);
1987626cd3dSBhargava Marreddy }
1997626cd3dSBhargava Marreddy 
2007626cd3dSBhargava Marreddy static bool bnge_auto_speed_updated(struct bnge_net *bn)
2017626cd3dSBhargava Marreddy {
2027626cd3dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info = &bn->eth_link_info;
2037626cd3dSBhargava Marreddy 	struct bnge_link_info *link_info = &bn->bd->link_info;
2047626cd3dSBhargava Marreddy 
2057626cd3dSBhargava Marreddy 	return elink_info->advertising != link_info->auto_link_speeds2;
2067626cd3dSBhargava Marreddy }
2077626cd3dSBhargava Marreddy 
2087626cd3dSBhargava Marreddy void bnge_hwrm_set_pause_common(struct bnge_net *bn,
2097626cd3dSBhargava Marreddy 				struct hwrm_port_phy_cfg_input *req)
2107626cd3dSBhargava Marreddy {
2117626cd3dSBhargava Marreddy 	if (bn->eth_link_info.autoneg & BNGE_AUTONEG_FLOW_CTRL) {
2127626cd3dSBhargava Marreddy 		req->auto_pause = PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE;
2137626cd3dSBhargava Marreddy 		if (bn->eth_link_info.req_flow_ctrl & BNGE_LINK_PAUSE_RX)
2147626cd3dSBhargava Marreddy 			req->auto_pause |= PORT_PHY_CFG_REQ_AUTO_PAUSE_RX;
2157626cd3dSBhargava Marreddy 		if (bn->eth_link_info.req_flow_ctrl & BNGE_LINK_PAUSE_TX)
2167626cd3dSBhargava Marreddy 			req->auto_pause |= PORT_PHY_CFG_REQ_AUTO_PAUSE_TX;
2177626cd3dSBhargava Marreddy 		req->enables |=
2187626cd3dSBhargava Marreddy 			cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_AUTO_PAUSE);
2197626cd3dSBhargava Marreddy 	} else {
2207626cd3dSBhargava Marreddy 		if (bn->eth_link_info.req_flow_ctrl & BNGE_LINK_PAUSE_RX)
2217626cd3dSBhargava Marreddy 			req->force_pause |= PORT_PHY_CFG_REQ_FORCE_PAUSE_RX;
2227626cd3dSBhargava Marreddy 		if (bn->eth_link_info.req_flow_ctrl & BNGE_LINK_PAUSE_TX)
2237626cd3dSBhargava Marreddy 			req->force_pause |= PORT_PHY_CFG_REQ_FORCE_PAUSE_TX;
2247626cd3dSBhargava Marreddy 		req->enables |=
2257626cd3dSBhargava Marreddy 			cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_FORCE_PAUSE);
2267626cd3dSBhargava Marreddy 		req->auto_pause = req->force_pause;
2277626cd3dSBhargava Marreddy 		req->enables |=
2287626cd3dSBhargava Marreddy 			cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_AUTO_PAUSE);
2297626cd3dSBhargava Marreddy 	}
2307626cd3dSBhargava Marreddy }
2317626cd3dSBhargava Marreddy 
2327626cd3dSBhargava Marreddy static bool bnge_force_speed_updated(struct bnge_net *bn)
2337626cd3dSBhargava Marreddy {
2347626cd3dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info = &bn->eth_link_info;
2357626cd3dSBhargava Marreddy 	struct bnge_link_info *link_info = &bn->bd->link_info;
2367626cd3dSBhargava Marreddy 
2377626cd3dSBhargava Marreddy 	return elink_info->req_link_speed != link_info->force_link_speed2;
2387626cd3dSBhargava Marreddy }
2397626cd3dSBhargava Marreddy 
2407626cd3dSBhargava Marreddy int bnge_update_phy_setting(struct bnge_net *bn)
2417626cd3dSBhargava Marreddy {
2427626cd3dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info;
2437626cd3dSBhargava Marreddy 	struct bnge_link_info *link_info;
2447626cd3dSBhargava Marreddy 	struct bnge_dev *bd = bn->bd;
2457626cd3dSBhargava Marreddy 	bool update_pause = false;
2467626cd3dSBhargava Marreddy 	bool update_link = false;
2477626cd3dSBhargava Marreddy 	bool hw_pause_autoneg;
2487626cd3dSBhargava Marreddy 	bool pause_autoneg;
2497626cd3dSBhargava Marreddy 	int rc;
2507626cd3dSBhargava Marreddy 
2517626cd3dSBhargava Marreddy 	link_info = &bd->link_info;
2527626cd3dSBhargava Marreddy 	elink_info = &bn->eth_link_info;
2537626cd3dSBhargava Marreddy 	rc = bnge_update_link(bn, true);
2547626cd3dSBhargava Marreddy 	if (rc) {
2557626cd3dSBhargava Marreddy 		netdev_err(bn->netdev, "failed to update link (rc: %d)\n",
2567626cd3dSBhargava Marreddy 			   rc);
2577626cd3dSBhargava Marreddy 		return rc;
2587626cd3dSBhargava Marreddy 	}
2597626cd3dSBhargava Marreddy 
2607626cd3dSBhargava Marreddy 	pause_autoneg = !!(elink_info->autoneg & BNGE_AUTONEG_FLOW_CTRL);
2617626cd3dSBhargava Marreddy 	hw_pause_autoneg = !!(link_info->auto_pause_setting &
2627626cd3dSBhargava Marreddy 			      PORT_PHY_QCFG_RESP_AUTO_PAUSE_AUTONEG_PAUSE);
2637626cd3dSBhargava Marreddy 
2647626cd3dSBhargava Marreddy 	/* Check if pause autonegotiation state has changed */
2657626cd3dSBhargava Marreddy 	if (pause_autoneg != hw_pause_autoneg) {
2667626cd3dSBhargava Marreddy 		update_pause = true;
2677626cd3dSBhargava Marreddy 	} else if (pause_autoneg) {
2687626cd3dSBhargava Marreddy 		/* If pause autoneg is enabled, check if the
2697626cd3dSBhargava Marreddy 		 * requested RX/TX bits changed
2707626cd3dSBhargava Marreddy 		 */
2717626cd3dSBhargava Marreddy 		if ((link_info->auto_pause_setting & BNGE_LINK_PAUSE_BOTH) !=
2727626cd3dSBhargava Marreddy 		    elink_info->req_flow_ctrl)
2737626cd3dSBhargava Marreddy 			update_pause = true;
2747626cd3dSBhargava Marreddy 	} else {
2757626cd3dSBhargava Marreddy 		/* If pause autoneg is disabled, check if the
2767626cd3dSBhargava Marreddy 		 * forced RX/TX bits changed
2777626cd3dSBhargava Marreddy 		 */
2787626cd3dSBhargava Marreddy 		if (link_info->force_pause_setting != elink_info->req_flow_ctrl)
2797626cd3dSBhargava Marreddy 			update_pause = true;
2807626cd3dSBhargava Marreddy 	}
2817626cd3dSBhargava Marreddy 
2827626cd3dSBhargava Marreddy 	/* Force update if link change is requested */
2837626cd3dSBhargava Marreddy 	if (elink_info->force_link_chng)
2847626cd3dSBhargava Marreddy 		update_pause = true;
2857626cd3dSBhargava Marreddy 
2867626cd3dSBhargava Marreddy 	/* Check if link speed or duplex settings have changed */
2877626cd3dSBhargava Marreddy 	if (!(elink_info->autoneg & BNGE_AUTONEG_SPEED)) {
2887626cd3dSBhargava Marreddy 		if (BNGE_AUTO_MODE(link_info->auto_mode) ||
2897626cd3dSBhargava Marreddy 		    bnge_force_speed_updated(bn) ||
2907626cd3dSBhargava Marreddy 		    elink_info->req_duplex != link_info->duplex_setting)
2917626cd3dSBhargava Marreddy 			update_link = true;
2927626cd3dSBhargava Marreddy 	} else {
2937626cd3dSBhargava Marreddy 		if (link_info->auto_mode == BNGE_LINK_AUTO_NONE ||
2947626cd3dSBhargava Marreddy 		    bnge_auto_speed_updated(bn))
2957626cd3dSBhargava Marreddy 			update_link = true;
2967626cd3dSBhargava Marreddy 	}
2977626cd3dSBhargava Marreddy 
2987626cd3dSBhargava Marreddy 	/* The last close may have shut down the link, so need to call
2997626cd3dSBhargava Marreddy 	 * PHY_CFG to bring it back up.
3007626cd3dSBhargava Marreddy 	 */
3017626cd3dSBhargava Marreddy 	if (!BNGE_LINK_IS_UP(bd))
3027626cd3dSBhargava Marreddy 		update_link = true;
3037626cd3dSBhargava Marreddy 
3047626cd3dSBhargava Marreddy 	if (update_link)
3057626cd3dSBhargava Marreddy 		rc = bnge_hwrm_set_link_setting(bn, update_pause);
3067626cd3dSBhargava Marreddy 	else if (update_pause)
3077626cd3dSBhargava Marreddy 		rc = bnge_hwrm_set_pause(bn);
3087626cd3dSBhargava Marreddy 
3097626cd3dSBhargava Marreddy 	if (rc) {
3107626cd3dSBhargava Marreddy 		netdev_err(bn->netdev,
3117626cd3dSBhargava Marreddy 			   "failed to update PHY setting (rc: %d)\n", rc);
3127626cd3dSBhargava Marreddy 		return rc;
3137626cd3dSBhargava Marreddy 	}
3147626cd3dSBhargava Marreddy 
3157626cd3dSBhargava Marreddy 	return 0;
3167626cd3dSBhargava Marreddy }
3177626cd3dSBhargava Marreddy 
3187626cd3dSBhargava Marreddy void bnge_get_port_module_status(struct bnge_net *bn)
3197626cd3dSBhargava Marreddy {
3207626cd3dSBhargava Marreddy 	struct hwrm_port_phy_qcfg_output *resp;
3217626cd3dSBhargava Marreddy 	struct bnge_link_info *link_info;
3227626cd3dSBhargava Marreddy 	struct bnge_dev *bd = bn->bd;
3237626cd3dSBhargava Marreddy 	u8 module_status;
3247626cd3dSBhargava Marreddy 
3257626cd3dSBhargava Marreddy 	link_info = &bd->link_info;
3267626cd3dSBhargava Marreddy 	resp = &link_info->phy_qcfg_resp;
3277626cd3dSBhargava Marreddy 
3287626cd3dSBhargava Marreddy 	if (bnge_update_link(bn, true))
3297626cd3dSBhargava Marreddy 		return;
3307626cd3dSBhargava Marreddy 
3317626cd3dSBhargava Marreddy 	module_status = link_info->module_status;
3327626cd3dSBhargava Marreddy 	switch (module_status) {
3337626cd3dSBhargava Marreddy 	case PORT_PHY_QCFG_RESP_MODULE_STATUS_DISABLETX:
3347626cd3dSBhargava Marreddy 	case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN:
3357626cd3dSBhargava Marreddy 	case PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG:
3367626cd3dSBhargava Marreddy 		netdev_warn(bn->netdev,
3377626cd3dSBhargava Marreddy 			    "Unqualified SFP+ module detected on port %d\n",
3387626cd3dSBhargava Marreddy 			    bd->pf.port_id);
3397626cd3dSBhargava Marreddy 		netdev_warn(bn->netdev, "Module part number %.*s\n",
3407626cd3dSBhargava Marreddy 			    (int)sizeof(resp->phy_vendor_partnumber),
3417626cd3dSBhargava Marreddy 			    resp->phy_vendor_partnumber);
3427626cd3dSBhargava Marreddy 		if (module_status == PORT_PHY_QCFG_RESP_MODULE_STATUS_DISABLETX)
3437626cd3dSBhargava Marreddy 			netdev_warn(bn->netdev, "TX is disabled\n");
3447626cd3dSBhargava Marreddy 		if (module_status == PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN)
3457626cd3dSBhargava Marreddy 			netdev_warn(bn->netdev, "SFP+ module is shut down\n");
3467626cd3dSBhargava Marreddy 		break;
3477626cd3dSBhargava Marreddy 	}
3487626cd3dSBhargava Marreddy }
3497626cd3dSBhargava Marreddy 
350169f6e8dSBhargava Marreddy static void bnge_set_default_adv_speeds(struct bnge_net *bn)
351169f6e8dSBhargava Marreddy {
352169f6e8dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info = &bn->eth_link_info;
353169f6e8dSBhargava Marreddy 	struct bnge_link_info *link_info = &bn->bd->link_info;
354169f6e8dSBhargava Marreddy 
355169f6e8dSBhargava Marreddy 	elink_info->advertising = link_info->support_auto_speeds2;
356169f6e8dSBhargava Marreddy }
357169f6e8dSBhargava Marreddy 
3587626cd3dSBhargava Marreddy static bool bnge_support_dropped(u16 advertising, u16 supported)
3597626cd3dSBhargava Marreddy {
3607626cd3dSBhargava Marreddy 	return (advertising & ~supported) != 0;
3617626cd3dSBhargava Marreddy }
3627626cd3dSBhargava Marreddy 
3637626cd3dSBhargava Marreddy bool bnge_support_speed_dropped(struct bnge_net *bn)
3647626cd3dSBhargava Marreddy {
3657626cd3dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info = &bn->eth_link_info;
3667626cd3dSBhargava Marreddy 	struct bnge_link_info *link_info = &bn->bd->link_info;
3677626cd3dSBhargava Marreddy 
3687626cd3dSBhargava Marreddy 	/* Check if any advertised speeds are no longer supported. The caller
3697626cd3dSBhargava Marreddy 	 * holds the netdev instance lock, so we can modify link_info settings.
3707626cd3dSBhargava Marreddy 	 */
3717626cd3dSBhargava Marreddy 	if (bnge_support_dropped(elink_info->advertising,
3727626cd3dSBhargava Marreddy 				 link_info->support_auto_speeds2)) {
3737626cd3dSBhargava Marreddy 		elink_info->advertising = link_info->support_auto_speeds2;
3747626cd3dSBhargava Marreddy 		return true;
3757626cd3dSBhargava Marreddy 	}
3767626cd3dSBhargava Marreddy 	return false;
3777626cd3dSBhargava Marreddy }
3787626cd3dSBhargava Marreddy 
3797626cd3dSBhargava Marreddy static char *bnge_report_fec(struct bnge_link_info *link_info)
3807626cd3dSBhargava Marreddy {
3817626cd3dSBhargava Marreddy 	u8 active_fec = link_info->active_fec_sig_mode &
3827626cd3dSBhargava Marreddy 			PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK;
3837626cd3dSBhargava Marreddy 
3847626cd3dSBhargava Marreddy 	switch (active_fec) {
3857626cd3dSBhargava Marreddy 	default:
3867626cd3dSBhargava Marreddy 	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE:
3877626cd3dSBhargava Marreddy 		return "None";
3887626cd3dSBhargava Marreddy 	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE:
3897626cd3dSBhargava Marreddy 		return "Clause 74 BaseR";
3907626cd3dSBhargava Marreddy 	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE:
3917626cd3dSBhargava Marreddy 		return "Clause 91 RS(528,514)";
3927626cd3dSBhargava Marreddy 	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE:
3937626cd3dSBhargava Marreddy 		return "Clause 91 RS544_1XN";
3947626cd3dSBhargava Marreddy 	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE:
3957626cd3dSBhargava Marreddy 		return "Clause 91 RS(544,514)";
3967626cd3dSBhargava Marreddy 	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE:
3977626cd3dSBhargava Marreddy 		return "Clause 91 RS272_1XN";
3987626cd3dSBhargava Marreddy 	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE:
3997626cd3dSBhargava Marreddy 		return "Clause 91 RS(272,257)";
4007626cd3dSBhargava Marreddy 	}
4017626cd3dSBhargava Marreddy }
4027626cd3dSBhargava Marreddy 
4037626cd3dSBhargava Marreddy void bnge_report_link(struct bnge_dev *bd)
4047626cd3dSBhargava Marreddy {
4057626cd3dSBhargava Marreddy 	if (BNGE_LINK_IS_UP(bd)) {
4067626cd3dSBhargava Marreddy 		const char *signal = "";
4077626cd3dSBhargava Marreddy 		const char *flow_ctrl;
4087626cd3dSBhargava Marreddy 		const char *duplex;
4097626cd3dSBhargava Marreddy 		u32 speed;
4107626cd3dSBhargava Marreddy 		u16 fec;
4117626cd3dSBhargava Marreddy 
4127626cd3dSBhargava Marreddy 		netif_carrier_on(bd->netdev);
4137626cd3dSBhargava Marreddy 		speed = bnge_fw_to_ethtool_speed(bd->link_info.link_speed);
4147626cd3dSBhargava Marreddy 		if (speed == SPEED_UNKNOWN) {
4157626cd3dSBhargava Marreddy 			netdev_info(bd->netdev,
4167626cd3dSBhargava Marreddy 				    "NIC Link is Up, speed unknown\n");
4177626cd3dSBhargava Marreddy 			return;
4187626cd3dSBhargava Marreddy 		}
4197626cd3dSBhargava Marreddy 		if (bd->link_info.duplex == BNGE_LINK_DUPLEX_FULL)
4207626cd3dSBhargava Marreddy 			duplex = "full";
4217626cd3dSBhargava Marreddy 		else
4227626cd3dSBhargava Marreddy 			duplex = "half";
4237626cd3dSBhargava Marreddy 		if (bd->link_info.pause == BNGE_LINK_PAUSE_BOTH)
4247626cd3dSBhargava Marreddy 			flow_ctrl = "ON - receive & transmit";
4257626cd3dSBhargava Marreddy 		else if (bd->link_info.pause == BNGE_LINK_PAUSE_TX)
4267626cd3dSBhargava Marreddy 			flow_ctrl = "ON - transmit";
4277626cd3dSBhargava Marreddy 		else if (bd->link_info.pause == BNGE_LINK_PAUSE_RX)
4287626cd3dSBhargava Marreddy 			flow_ctrl = "ON - receive";
4297626cd3dSBhargava Marreddy 		else
4307626cd3dSBhargava Marreddy 			flow_ctrl = "none";
4317626cd3dSBhargava Marreddy 		if (bd->link_info.phy_qcfg_resp.option_flags &
4327626cd3dSBhargava Marreddy 		    PORT_PHY_QCFG_RESP_OPTION_FLAGS_SIGNAL_MODE_KNOWN) {
4337626cd3dSBhargava Marreddy 			u8 sig_mode = bd->link_info.active_fec_sig_mode &
4347626cd3dSBhargava Marreddy 				      PORT_PHY_QCFG_RESP_SIGNAL_MODE_MASK;
4357626cd3dSBhargava Marreddy 			switch (sig_mode) {
4367626cd3dSBhargava Marreddy 			case PORT_PHY_QCFG_RESP_SIGNAL_MODE_NRZ:
4377626cd3dSBhargava Marreddy 				signal = "(NRZ) ";
4387626cd3dSBhargava Marreddy 				break;
4397626cd3dSBhargava Marreddy 			case PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4:
4407626cd3dSBhargava Marreddy 				signal = "(PAM4 56Gbps) ";
4417626cd3dSBhargava Marreddy 				break;
4427626cd3dSBhargava Marreddy 			case PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112:
4437626cd3dSBhargava Marreddy 				signal = "(PAM4 112Gbps) ";
4447626cd3dSBhargava Marreddy 				break;
4457626cd3dSBhargava Marreddy 			default:
4467626cd3dSBhargava Marreddy 				break;
4477626cd3dSBhargava Marreddy 			}
4487626cd3dSBhargava Marreddy 		}
4497626cd3dSBhargava Marreddy 		netdev_info(bd->netdev, "NIC Link is Up, %u Mbps %s%s duplex, Flow control: %s\n",
4507626cd3dSBhargava Marreddy 			    speed, signal, duplex, flow_ctrl);
4517626cd3dSBhargava Marreddy 		fec = bd->link_info.fec_cfg;
4527626cd3dSBhargava Marreddy 		if (!(fec & PORT_PHY_QCFG_RESP_FEC_CFG_FEC_NONE_SUPPORTED))
4537626cd3dSBhargava Marreddy 			netdev_info(bd->netdev, "FEC autoneg %s encoding: %s\n",
4547626cd3dSBhargava Marreddy 				    (fec & BNGE_FEC_AUTONEG) ? "on" : "off",
4557626cd3dSBhargava Marreddy 				    bnge_report_fec(&bd->link_info));
4567626cd3dSBhargava Marreddy 	} else {
4577626cd3dSBhargava Marreddy 		netif_carrier_off(bd->netdev);
4587626cd3dSBhargava Marreddy 		netdev_info(bd->netdev, "NIC Link is Down\n");
4597626cd3dSBhargava Marreddy 	}
4607626cd3dSBhargava Marreddy }
461169f6e8dSBhargava Marreddy 
462169f6e8dSBhargava Marreddy static void bnge_get_ethtool_modes(struct bnge_net *bn,
463169f6e8dSBhargava Marreddy 				   struct ethtool_link_ksettings *lk_ksettings)
464169f6e8dSBhargava Marreddy {
465169f6e8dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info;
466169f6e8dSBhargava Marreddy 	struct bnge_link_info *link_info;
467169f6e8dSBhargava Marreddy 	struct bnge_dev *bd = bn->bd;
468169f6e8dSBhargava Marreddy 
469169f6e8dSBhargava Marreddy 	elink_info = &bn->eth_link_info;
470169f6e8dSBhargava Marreddy 	link_info = &bd->link_info;
471169f6e8dSBhargava Marreddy 
472169f6e8dSBhargava Marreddy 	if (!(bd->phy_flags & BNGE_PHY_FL_NO_PAUSE)) {
473169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
474169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.supported);
475169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
476169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.supported);
477169f6e8dSBhargava Marreddy 	}
478169f6e8dSBhargava Marreddy 
479169f6e8dSBhargava Marreddy 	if (link_info->support_auto_speeds2)
480169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
481169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.supported);
482169f6e8dSBhargava Marreddy 
483169f6e8dSBhargava Marreddy 	if (~elink_info->autoneg & BNGE_AUTONEG_FLOW_CTRL)
484169f6e8dSBhargava Marreddy 		return;
485169f6e8dSBhargava Marreddy 
486169f6e8dSBhargava Marreddy 	if (link_info->auto_pause_setting & BNGE_LINK_PAUSE_RX)
487169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
488169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.advertising);
489169f6e8dSBhargava Marreddy 	if (hweight8(link_info->auto_pause_setting & BNGE_LINK_PAUSE_BOTH) == 1)
490169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
491169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.advertising);
492169f6e8dSBhargava Marreddy 	if (link_info->lp_pause & BNGE_LINK_PAUSE_RX)
493169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
494169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.lp_advertising);
495169f6e8dSBhargava Marreddy 	if (hweight8(link_info->lp_pause & BNGE_LINK_PAUSE_BOTH) == 1)
496169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
497169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.lp_advertising);
498169f6e8dSBhargava Marreddy }
499169f6e8dSBhargava Marreddy 
500169f6e8dSBhargava Marreddy u32 bnge_get_link(struct net_device *dev)
501169f6e8dSBhargava Marreddy {
502169f6e8dSBhargava Marreddy 	struct bnge_net *bn = netdev_priv(dev);
503169f6e8dSBhargava Marreddy 
504169f6e8dSBhargava Marreddy 	return BNGE_LINK_IS_UP(bn->bd);
505169f6e8dSBhargava Marreddy }
506169f6e8dSBhargava Marreddy 
507169f6e8dSBhargava Marreddy static enum bnge_media_type
508169f6e8dSBhargava Marreddy bnge_get_media(struct bnge_link_info *link_info)
509169f6e8dSBhargava Marreddy {
510169f6e8dSBhargava Marreddy 	switch (link_info->media_type) {
511169f6e8dSBhargava Marreddy 	case PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC:
512169f6e8dSBhargava Marreddy 		return BNGE_MEDIA_CR;
513169f6e8dSBhargava Marreddy 	default:
514169f6e8dSBhargava Marreddy 		if (link_info->phy_type < ARRAY_SIZE(bnge_phy_types))
515169f6e8dSBhargava Marreddy 			return bnge_phy_types[link_info->phy_type];
516169f6e8dSBhargava Marreddy 		return BNGE_MEDIA_UNKNOWN;
517169f6e8dSBhargava Marreddy 	}
518169f6e8dSBhargava Marreddy }
519169f6e8dSBhargava Marreddy 
520169f6e8dSBhargava Marreddy enum bnge_link_speed_indices {
521169f6e8dSBhargava Marreddy 	BNGE_LINK_SPEED_UNKNOWN = 0,
522169f6e8dSBhargava Marreddy 	BNGE_LINK_SPEED_50GB_IDX,
523169f6e8dSBhargava Marreddy 	BNGE_LINK_SPEED_100GB_IDX,
524169f6e8dSBhargava Marreddy 	BNGE_LINK_SPEED_200GB_IDX,
525169f6e8dSBhargava Marreddy 	BNGE_LINK_SPEED_400GB_IDX,
526169f6e8dSBhargava Marreddy 	BNGE_LINK_SPEED_800GB_IDX,
527169f6e8dSBhargava Marreddy 	__BNGE_LINK_SPEED_END
528169f6e8dSBhargava Marreddy };
529169f6e8dSBhargava Marreddy 
530169f6e8dSBhargava Marreddy static enum bnge_link_speed_indices bnge_fw_speed_idx(u16 speed)
531169f6e8dSBhargava Marreddy {
532169f6e8dSBhargava Marreddy 	switch (speed) {
533169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_50GB:
534169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_50GB_PAM4:
535169f6e8dSBhargava Marreddy 		return BNGE_LINK_SPEED_50GB_IDX;
536169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_100GB:
537169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_100GB_PAM4:
538169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_100GB_PAM4_112:
539169f6e8dSBhargava Marreddy 		return BNGE_LINK_SPEED_100GB_IDX;
540169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_200GB:
541169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_200GB_PAM4:
542169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_200GB_PAM4_112:
543169f6e8dSBhargava Marreddy 		return BNGE_LINK_SPEED_200GB_IDX;
544169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_400GB:
545169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_400GB_PAM4:
546169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_400GB_PAM4_112:
547169f6e8dSBhargava Marreddy 		return BNGE_LINK_SPEED_400GB_IDX;
548169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_800GB:
549169f6e8dSBhargava Marreddy 	case BNGE_LINK_SPEED_800GB_PAM4_112:
550169f6e8dSBhargava Marreddy 		return BNGE_LINK_SPEED_800GB_IDX;
551169f6e8dSBhargava Marreddy 	default:
552169f6e8dSBhargava Marreddy 		return BNGE_LINK_SPEED_UNKNOWN;
553169f6e8dSBhargava Marreddy 	}
554169f6e8dSBhargava Marreddy }
555169f6e8dSBhargava Marreddy 
556169f6e8dSBhargava Marreddy /* Compile-time link mode mapping table.
557169f6e8dSBhargava Marreddy  * Indexed by [speed_idx][sig_mode][media].
558169f6e8dSBhargava Marreddy  */
559169f6e8dSBhargava Marreddy #define BNGE_LINK_M(speed, sig, media, lm)	\
560169f6e8dSBhargava Marreddy 	[BNGE_LINK_SPEED_##speed##_IDX]	\
561169f6e8dSBhargava Marreddy 	[BNGE_SIG_MODE_##sig]		\
562169f6e8dSBhargava Marreddy 	[BNGE_MEDIA_##media] = ETHTOOL_LINK_MODE_##lm##_Full_BIT
563169f6e8dSBhargava Marreddy 
564169f6e8dSBhargava Marreddy static const enum ethtool_link_mode_bit_indices
565169f6e8dSBhargava Marreddy bnge_link_modes[__BNGE_LINK_SPEED_END]
566169f6e8dSBhargava Marreddy 	       [BNGE_SIG_MODE_MAX]
567169f6e8dSBhargava Marreddy 	       [__BNGE_MEDIA_END] = {
568169f6e8dSBhargava Marreddy 	/* 50GB PAM4 */
569169f6e8dSBhargava Marreddy 	BNGE_LINK_M(50GB,  PAM4, CR,        50000baseCR),
570169f6e8dSBhargava Marreddy 	BNGE_LINK_M(50GB,  PAM4, SR,        50000baseSR),
571169f6e8dSBhargava Marreddy 	BNGE_LINK_M(50GB,  PAM4, LR_ER_FR,  50000baseLR_ER_FR),
572169f6e8dSBhargava Marreddy 	BNGE_LINK_M(50GB,  PAM4, KR,        50000baseKR),
573169f6e8dSBhargava Marreddy 
574169f6e8dSBhargava Marreddy 	/* 100GB NRZ */
575169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, NRZ,  CR,        100000baseCR4),
576169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, NRZ,  SR,        100000baseSR4),
577169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, NRZ,  LR_ER_FR,  100000baseLR4_ER4),
578169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, NRZ,  KR,        100000baseKR4),
579169f6e8dSBhargava Marreddy 
580169f6e8dSBhargava Marreddy 	/* 100GB PAM4 */
581169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, PAM4, CR,        100000baseCR2),
582169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, PAM4, SR,        100000baseSR2),
583169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, PAM4, LR_ER_FR,  100000baseLR2_ER2_FR2),
584169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, PAM4, KR,        100000baseKR2),
585169f6e8dSBhargava Marreddy 
586169f6e8dSBhargava Marreddy 	/* 100GB PAM4_112 */
587169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, PAM4_112, CR,        100000baseCR),
588169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, PAM4_112, SR,        100000baseSR),
589169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, PAM4_112, LR_ER_FR,  100000baseLR_ER_FR),
590169f6e8dSBhargava Marreddy 	BNGE_LINK_M(100GB, PAM4_112, KR,        100000baseKR),
591169f6e8dSBhargava Marreddy 
592169f6e8dSBhargava Marreddy 	/* 200GB PAM4 */
593169f6e8dSBhargava Marreddy 	BNGE_LINK_M(200GB, PAM4, CR,        200000baseCR4),
594169f6e8dSBhargava Marreddy 	BNGE_LINK_M(200GB, PAM4, SR,        200000baseSR4),
595169f6e8dSBhargava Marreddy 	BNGE_LINK_M(200GB, PAM4, LR_ER_FR,  200000baseLR4_ER4_FR4),
596169f6e8dSBhargava Marreddy 	BNGE_LINK_M(200GB, PAM4, KR,        200000baseKR4),
597169f6e8dSBhargava Marreddy 
598169f6e8dSBhargava Marreddy 	/* 200GB PAM4_112 */
599169f6e8dSBhargava Marreddy 	BNGE_LINK_M(200GB, PAM4_112, CR,        200000baseCR2),
600169f6e8dSBhargava Marreddy 	BNGE_LINK_M(200GB, PAM4_112, SR,        200000baseSR2),
601169f6e8dSBhargava Marreddy 	BNGE_LINK_M(200GB, PAM4_112, LR_ER_FR,  200000baseLR2_ER2_FR2),
602169f6e8dSBhargava Marreddy 	BNGE_LINK_M(200GB, PAM4_112, KR,        200000baseKR2),
603169f6e8dSBhargava Marreddy 
604169f6e8dSBhargava Marreddy 	/* 400GB PAM4 */
605169f6e8dSBhargava Marreddy 	BNGE_LINK_M(400GB, PAM4, CR,        400000baseCR8),
606169f6e8dSBhargava Marreddy 	BNGE_LINK_M(400GB, PAM4, SR,        400000baseSR8),
607169f6e8dSBhargava Marreddy 	BNGE_LINK_M(400GB, PAM4, LR_ER_FR,  400000baseLR8_ER8_FR8),
608169f6e8dSBhargava Marreddy 	BNGE_LINK_M(400GB, PAM4, KR,        400000baseKR8),
609169f6e8dSBhargava Marreddy 
610169f6e8dSBhargava Marreddy 	/* 400GB PAM4_112 */
611169f6e8dSBhargava Marreddy 	BNGE_LINK_M(400GB, PAM4_112, CR,        400000baseCR4),
612169f6e8dSBhargava Marreddy 	BNGE_LINK_M(400GB, PAM4_112, SR,        400000baseSR4),
613169f6e8dSBhargava Marreddy 	BNGE_LINK_M(400GB, PAM4_112, LR_ER_FR,  400000baseLR4_ER4_FR4),
614169f6e8dSBhargava Marreddy 	BNGE_LINK_M(400GB, PAM4_112, KR,        400000baseKR4),
615169f6e8dSBhargava Marreddy 
616169f6e8dSBhargava Marreddy 	/* 800GB PAM4_112 */
617169f6e8dSBhargava Marreddy 	BNGE_LINK_M(800GB, PAM4_112, CR,        800000baseCR8),
618169f6e8dSBhargava Marreddy 	BNGE_LINK_M(800GB, PAM4_112, SR,        800000baseSR8),
619169f6e8dSBhargava Marreddy 	BNGE_LINK_M(800GB, PAM4_112, KR,        800000baseKR8),
620169f6e8dSBhargava Marreddy };
621169f6e8dSBhargava Marreddy 
622169f6e8dSBhargava Marreddy #define BNGE_LINK_MODE_UNKNOWN -1
623169f6e8dSBhargava Marreddy 
624169f6e8dSBhargava Marreddy static enum ethtool_link_mode_bit_indices
625169f6e8dSBhargava Marreddy bnge_get_link_mode(struct bnge_net *bn)
626169f6e8dSBhargava Marreddy {
627169f6e8dSBhargava Marreddy 	enum ethtool_link_mode_bit_indices link_mode;
628169f6e8dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info;
629169f6e8dSBhargava Marreddy 	enum bnge_link_speed_indices speed;
630169f6e8dSBhargava Marreddy 	struct bnge_link_info *link_info;
631169f6e8dSBhargava Marreddy 	struct bnge_dev *bd = bn->bd;
632169f6e8dSBhargava Marreddy 	enum bnge_media_type media;
633169f6e8dSBhargava Marreddy 	u8 sig_mode;
634169f6e8dSBhargava Marreddy 
635169f6e8dSBhargava Marreddy 	elink_info = &bn->eth_link_info;
636169f6e8dSBhargava Marreddy 	link_info = &bd->link_info;
637169f6e8dSBhargava Marreddy 
638169f6e8dSBhargava Marreddy 	if (link_info->phy_link_status != BNGE_LINK_LINK)
639169f6e8dSBhargava Marreddy 		return BNGE_LINK_MODE_UNKNOWN;
640169f6e8dSBhargava Marreddy 
641169f6e8dSBhargava Marreddy 	media = bnge_get_media(link_info);
642169f6e8dSBhargava Marreddy 	if (BNGE_AUTO_MODE(link_info->auto_mode)) {
643169f6e8dSBhargava Marreddy 		speed = bnge_fw_speed_idx(link_info->link_speed);
644169f6e8dSBhargava Marreddy 		sig_mode = link_info->active_fec_sig_mode &
645169f6e8dSBhargava Marreddy 			PORT_PHY_QCFG_RESP_SIGNAL_MODE_MASK;
646169f6e8dSBhargava Marreddy 	} else {
647169f6e8dSBhargava Marreddy 		speed = bnge_fw_speed_idx(elink_info->req_link_speed);
648169f6e8dSBhargava Marreddy 		sig_mode = elink_info->req_signal_mode;
649169f6e8dSBhargava Marreddy 	}
650169f6e8dSBhargava Marreddy 	if (sig_mode >= BNGE_SIG_MODE_MAX)
651169f6e8dSBhargava Marreddy 		return BNGE_LINK_MODE_UNKNOWN;
652169f6e8dSBhargava Marreddy 
653169f6e8dSBhargava Marreddy 	/* Since ETHTOOL_LINK_MODE_10baseT_Half_BIT is defined as 0 and
654169f6e8dSBhargava Marreddy 	 * not actually supported, the zeroes in this map can be safely
655169f6e8dSBhargava Marreddy 	 * used to represent unknown link modes.
656169f6e8dSBhargava Marreddy 	 */
657169f6e8dSBhargava Marreddy 	link_mode = bnge_link_modes[speed][sig_mode][media];
658169f6e8dSBhargava Marreddy 	if (!link_mode)
659169f6e8dSBhargava Marreddy 		return BNGE_LINK_MODE_UNKNOWN;
660169f6e8dSBhargava Marreddy 
661169f6e8dSBhargava Marreddy 	return link_mode;
662169f6e8dSBhargava Marreddy }
663169f6e8dSBhargava Marreddy 
664169f6e8dSBhargava Marreddy static const u16 bnge_nrz_speeds2_masks[__BNGE_LINK_SPEED_END] = {
665169f6e8dSBhargava Marreddy 	[BNGE_LINK_SPEED_100GB_IDX] = BNGE_LINK_SPEEDS2_MSK_100GB,
666169f6e8dSBhargava Marreddy };
667169f6e8dSBhargava Marreddy 
668169f6e8dSBhargava Marreddy static const u16 bnge_pam4_speeds2_masks[__BNGE_LINK_SPEED_END] = {
669169f6e8dSBhargava Marreddy 	[BNGE_LINK_SPEED_50GB_IDX] = BNGE_LINK_SPEEDS2_MSK_50GB_PAM4,
670169f6e8dSBhargava Marreddy 	[BNGE_LINK_SPEED_100GB_IDX] = BNGE_LINK_SPEEDS2_MSK_100GB_PAM4,
671169f6e8dSBhargava Marreddy 	[BNGE_LINK_SPEED_200GB_IDX] = BNGE_LINK_SPEEDS2_MSK_200GB_PAM4,
672169f6e8dSBhargava Marreddy 	[BNGE_LINK_SPEED_400GB_IDX] = BNGE_LINK_SPEEDS2_MSK_400GB_PAM4,
673169f6e8dSBhargava Marreddy };
674169f6e8dSBhargava Marreddy 
675169f6e8dSBhargava Marreddy static const u16 bnge_pam4_112_speeds2_masks[__BNGE_LINK_SPEED_END] = {
676169f6e8dSBhargava Marreddy 	[BNGE_LINK_SPEED_100GB_IDX] = BNGE_LINK_SPEEDS2_MSK_100GB_PAM4_112,
677169f6e8dSBhargava Marreddy 	[BNGE_LINK_SPEED_200GB_IDX] = BNGE_LINK_SPEEDS2_MSK_200GB_PAM4_112,
678169f6e8dSBhargava Marreddy 	[BNGE_LINK_SPEED_400GB_IDX] = BNGE_LINK_SPEEDS2_MSK_400GB_PAM4_112,
679169f6e8dSBhargava Marreddy 	[BNGE_LINK_SPEED_800GB_IDX] = BNGE_LINK_SPEEDS2_MSK_800GB_PAM4_112,
680169f6e8dSBhargava Marreddy };
681169f6e8dSBhargava Marreddy 
682169f6e8dSBhargava Marreddy static enum bnge_link_speed_indices
683169f6e8dSBhargava Marreddy bnge_encoding_speed_idx(u8 sig_mode, u16 speed_msk)
684169f6e8dSBhargava Marreddy {
685169f6e8dSBhargava Marreddy 	const u16 *speeds;
686169f6e8dSBhargava Marreddy 	int idx, len;
687169f6e8dSBhargava Marreddy 
688169f6e8dSBhargava Marreddy 	switch (sig_mode) {
689169f6e8dSBhargava Marreddy 	case BNGE_SIG_MODE_NRZ:
690169f6e8dSBhargava Marreddy 		speeds = bnge_nrz_speeds2_masks;
691169f6e8dSBhargava Marreddy 		len = ARRAY_SIZE(bnge_nrz_speeds2_masks);
692169f6e8dSBhargava Marreddy 		break;
693169f6e8dSBhargava Marreddy 	case BNGE_SIG_MODE_PAM4:
694169f6e8dSBhargava Marreddy 		speeds = bnge_pam4_speeds2_masks;
695169f6e8dSBhargava Marreddy 		len = ARRAY_SIZE(bnge_pam4_speeds2_masks);
696169f6e8dSBhargava Marreddy 		break;
697169f6e8dSBhargava Marreddy 	case BNGE_SIG_MODE_PAM4_112:
698169f6e8dSBhargava Marreddy 		speeds = bnge_pam4_112_speeds2_masks;
699169f6e8dSBhargava Marreddy 		len = ARRAY_SIZE(bnge_pam4_112_speeds2_masks);
700169f6e8dSBhargava Marreddy 		break;
701169f6e8dSBhargava Marreddy 	default:
702169f6e8dSBhargava Marreddy 		return BNGE_LINK_SPEED_UNKNOWN;
703169f6e8dSBhargava Marreddy 	}
704169f6e8dSBhargava Marreddy 
705169f6e8dSBhargava Marreddy 	for (idx = 0; idx < len; idx++) {
706169f6e8dSBhargava Marreddy 		if (speeds[idx] == speed_msk)
707169f6e8dSBhargava Marreddy 			return idx;
708169f6e8dSBhargava Marreddy 	}
709169f6e8dSBhargava Marreddy 
710169f6e8dSBhargava Marreddy 	return BNGE_LINK_SPEED_UNKNOWN;
711169f6e8dSBhargava Marreddy }
712169f6e8dSBhargava Marreddy 
713169f6e8dSBhargava Marreddy #define BNGE_FW_SPEED_MSK_BITS 16
714169f6e8dSBhargava Marreddy 
715169f6e8dSBhargava Marreddy static void
716169f6e8dSBhargava Marreddy __bnge_get_ethtool_speeds(unsigned long fw_mask, enum bnge_media_type media,
717169f6e8dSBhargava Marreddy 			  u8 sig_mode, unsigned long *et_mask)
718169f6e8dSBhargava Marreddy {
719169f6e8dSBhargava Marreddy 	enum ethtool_link_mode_bit_indices link_mode;
720169f6e8dSBhargava Marreddy 	enum bnge_link_speed_indices speed;
721169f6e8dSBhargava Marreddy 	u8 bit;
722169f6e8dSBhargava Marreddy 
723169f6e8dSBhargava Marreddy 	for_each_set_bit(bit, &fw_mask, BNGE_FW_SPEED_MSK_BITS) {
724169f6e8dSBhargava Marreddy 		speed = bnge_encoding_speed_idx(sig_mode, 1 << bit);
725169f6e8dSBhargava Marreddy 		if (!speed)
726169f6e8dSBhargava Marreddy 			continue;
727169f6e8dSBhargava Marreddy 
728169f6e8dSBhargava Marreddy 		link_mode = bnge_link_modes[speed][sig_mode][media];
729169f6e8dSBhargava Marreddy 		if (!link_mode)
730169f6e8dSBhargava Marreddy 			continue;
731169f6e8dSBhargava Marreddy 
732169f6e8dSBhargava Marreddy 		linkmode_set_bit(link_mode, et_mask);
733169f6e8dSBhargava Marreddy 	}
734169f6e8dSBhargava Marreddy }
735169f6e8dSBhargava Marreddy 
736169f6e8dSBhargava Marreddy static void
737169f6e8dSBhargava Marreddy bnge_get_ethtool_speeds(unsigned long fw_mask, enum bnge_media_type media,
738169f6e8dSBhargava Marreddy 			u8 sig_mode, unsigned long *et_mask)
739169f6e8dSBhargava Marreddy {
740169f6e8dSBhargava Marreddy 	if (media) {
741169f6e8dSBhargava Marreddy 		__bnge_get_ethtool_speeds(fw_mask, media, sig_mode, et_mask);
742169f6e8dSBhargava Marreddy 		return;
743169f6e8dSBhargava Marreddy 	}
744169f6e8dSBhargava Marreddy 
745169f6e8dSBhargava Marreddy 	/* list speeds for all media if unknown */
746169f6e8dSBhargava Marreddy 	for (media = 1; media < __BNGE_MEDIA_END; media++)
747169f6e8dSBhargava Marreddy 		__bnge_get_ethtool_speeds(fw_mask, media, sig_mode, et_mask);
748169f6e8dSBhargava Marreddy }
749169f6e8dSBhargava Marreddy 
750169f6e8dSBhargava Marreddy static void
751169f6e8dSBhargava Marreddy bnge_get_all_ethtool_support_speeds(struct bnge_dev *bd,
752169f6e8dSBhargava Marreddy 				    enum bnge_media_type media,
753169f6e8dSBhargava Marreddy 				    struct ethtool_link_ksettings *lk_ksettings)
754169f6e8dSBhargava Marreddy {
755169f6e8dSBhargava Marreddy 	u16 sp = bd->link_info.support_speeds2;
756169f6e8dSBhargava Marreddy 
757169f6e8dSBhargava Marreddy 	bnge_get_ethtool_speeds(sp, media, BNGE_SIG_MODE_NRZ,
758169f6e8dSBhargava Marreddy 				lk_ksettings->link_modes.supported);
759169f6e8dSBhargava Marreddy 	bnge_get_ethtool_speeds(sp, media, BNGE_SIG_MODE_PAM4,
760169f6e8dSBhargava Marreddy 				lk_ksettings->link_modes.supported);
761169f6e8dSBhargava Marreddy 	bnge_get_ethtool_speeds(sp, media, BNGE_SIG_MODE_PAM4_112,
762169f6e8dSBhargava Marreddy 				lk_ksettings->link_modes.supported);
763169f6e8dSBhargava Marreddy }
764169f6e8dSBhargava Marreddy 
765169f6e8dSBhargava Marreddy static void
766169f6e8dSBhargava Marreddy bnge_get_all_ethtool_adv_speeds(struct bnge_net *bn,
767169f6e8dSBhargava Marreddy 				enum bnge_media_type media,
768169f6e8dSBhargava Marreddy 				struct ethtool_link_ksettings *lk_ksettings)
769169f6e8dSBhargava Marreddy {
770169f6e8dSBhargava Marreddy 	u16 sp = bn->eth_link_info.advertising;
771169f6e8dSBhargava Marreddy 
772169f6e8dSBhargava Marreddy 	bnge_get_ethtool_speeds(sp, media, BNGE_SIG_MODE_NRZ,
773169f6e8dSBhargava Marreddy 				lk_ksettings->link_modes.advertising);
774169f6e8dSBhargava Marreddy 	bnge_get_ethtool_speeds(sp, media, BNGE_SIG_MODE_PAM4,
775169f6e8dSBhargava Marreddy 				lk_ksettings->link_modes.advertising);
776169f6e8dSBhargava Marreddy 	bnge_get_ethtool_speeds(sp, media, BNGE_SIG_MODE_PAM4_112,
777169f6e8dSBhargava Marreddy 				lk_ksettings->link_modes.advertising);
778169f6e8dSBhargava Marreddy }
779169f6e8dSBhargava Marreddy 
780169f6e8dSBhargava Marreddy static void
781169f6e8dSBhargava Marreddy bnge_get_all_ethtool_lp_speeds(struct bnge_dev *bd,
782169f6e8dSBhargava Marreddy 			       enum bnge_media_type media,
783169f6e8dSBhargava Marreddy 			       struct ethtool_link_ksettings *lk_ksettings)
784169f6e8dSBhargava Marreddy {
785169f6e8dSBhargava Marreddy 	u16 sp = bd->link_info.lp_auto_link_speeds;
786169f6e8dSBhargava Marreddy 
787169f6e8dSBhargava Marreddy 	bnge_get_ethtool_speeds(sp, media, BNGE_SIG_MODE_NRZ,
788169f6e8dSBhargava Marreddy 				lk_ksettings->link_modes.lp_advertising);
789169f6e8dSBhargava Marreddy 	bnge_get_ethtool_speeds(sp, media, BNGE_SIG_MODE_PAM4,
790169f6e8dSBhargava Marreddy 				lk_ksettings->link_modes.lp_advertising);
791169f6e8dSBhargava Marreddy 	bnge_get_ethtool_speeds(sp, media, BNGE_SIG_MODE_PAM4_112,
792169f6e8dSBhargava Marreddy 				lk_ksettings->link_modes.lp_advertising);
793169f6e8dSBhargava Marreddy }
794169f6e8dSBhargava Marreddy 
795169f6e8dSBhargava Marreddy static void bnge_update_speed(u32 *delta, bool installed_media, u16 *speeds,
796169f6e8dSBhargava Marreddy 			      u16 speed_msk, const unsigned long *et_mask,
797169f6e8dSBhargava Marreddy 			      enum ethtool_link_mode_bit_indices mode)
798169f6e8dSBhargava Marreddy {
799169f6e8dSBhargava Marreddy 	bool mode_desired = linkmode_test_bit(mode, et_mask);
800169f6e8dSBhargava Marreddy 
801169f6e8dSBhargava Marreddy 	if (!mode || !mode_desired)
802169f6e8dSBhargava Marreddy 		return;
803169f6e8dSBhargava Marreddy 
804169f6e8dSBhargava Marreddy 	/* installed media takes priority; for non-installed media, only allow
805169f6e8dSBhargava Marreddy 	 * one change per fw_speed bit (many to one mapping).
806169f6e8dSBhargava Marreddy 	 */
807169f6e8dSBhargava Marreddy 	if (installed_media || !(*delta & speed_msk)) {
808169f6e8dSBhargava Marreddy 		*speeds |= speed_msk;
809169f6e8dSBhargava Marreddy 		*delta |= speed_msk;
810169f6e8dSBhargava Marreddy 	}
811169f6e8dSBhargava Marreddy }
812169f6e8dSBhargava Marreddy 
813169f6e8dSBhargava Marreddy static void bnge_set_ethtool_speeds(struct bnge_net *bn,
814169f6e8dSBhargava Marreddy 				    const unsigned long *et_mask)
815169f6e8dSBhargava Marreddy {
816169f6e8dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info = &bn->eth_link_info;
817169f6e8dSBhargava Marreddy 	enum bnge_media_type media;
818169f6e8dSBhargava Marreddy 	u32 delta_pam4_112 = 0;
819169f6e8dSBhargava Marreddy 	u32 delta_pam4 = 0;
820169f6e8dSBhargava Marreddy 	u32 delta_nrz = 0;
821169f6e8dSBhargava Marreddy 	int i, m;
822169f6e8dSBhargava Marreddy 
823169f6e8dSBhargava Marreddy 	elink_info->advertising = 0;
824169f6e8dSBhargava Marreddy 
825169f6e8dSBhargava Marreddy 	media = bnge_get_media(&bn->bd->link_info);
826169f6e8dSBhargava Marreddy 	for (i = 1; i < __BNGE_LINK_SPEED_END; i++) {
827169f6e8dSBhargava Marreddy 		/* accept any legal media from user */
828169f6e8dSBhargava Marreddy 		for (m = 1; m < __BNGE_MEDIA_END; m++) {
829169f6e8dSBhargava Marreddy 			bnge_update_speed(&delta_nrz, m == media,
830169f6e8dSBhargava Marreddy 					  &elink_info->advertising,
831169f6e8dSBhargava Marreddy 					  bnge_nrz_speeds2_masks[i], et_mask,
832169f6e8dSBhargava Marreddy 					  bnge_link_modes[i][BNGE_SIG_MODE_NRZ][m]);
833169f6e8dSBhargava Marreddy 			bnge_update_speed(&delta_pam4, m == media,
834169f6e8dSBhargava Marreddy 					  &elink_info->advertising,
835169f6e8dSBhargava Marreddy 					  bnge_pam4_speeds2_masks[i], et_mask,
836169f6e8dSBhargava Marreddy 					  bnge_link_modes[i][BNGE_SIG_MODE_PAM4][m]);
837169f6e8dSBhargava Marreddy 			bnge_update_speed(&delta_pam4_112, m == media,
838169f6e8dSBhargava Marreddy 					  &elink_info->advertising,
839169f6e8dSBhargava Marreddy 					  bnge_pam4_112_speeds2_masks[i],
840169f6e8dSBhargava Marreddy 					  et_mask,
841169f6e8dSBhargava Marreddy 					  bnge_link_modes[i][BNGE_SIG_MODE_PAM4_112][m]);
842169f6e8dSBhargava Marreddy 		}
843169f6e8dSBhargava Marreddy 	}
844169f6e8dSBhargava Marreddy }
845169f6e8dSBhargava Marreddy 
846169f6e8dSBhargava Marreddy static void
847169f6e8dSBhargava Marreddy bnge_fw_to_ethtool_advertised_fec(struct bnge_link_info *link_info,
848169f6e8dSBhargava Marreddy 				  struct ethtool_link_ksettings *lk_ksettings)
849169f6e8dSBhargava Marreddy {
850169f6e8dSBhargava Marreddy 	u16 fec_cfg = link_info->fec_cfg;
851169f6e8dSBhargava Marreddy 
852169f6e8dSBhargava Marreddy 	if ((fec_cfg & BNGE_FEC_NONE) || !(fec_cfg & BNGE_FEC_AUTONEG)) {
853169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
854169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.advertising);
855169f6e8dSBhargava Marreddy 		return;
856169f6e8dSBhargava Marreddy 	}
857169f6e8dSBhargava Marreddy 	if (fec_cfg & BNGE_FEC_ENC_BASE_R)
858169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
859169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.advertising);
860169f6e8dSBhargava Marreddy 	if (fec_cfg & BNGE_FEC_ENC_RS)
861169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
862169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.advertising);
863169f6e8dSBhargava Marreddy 	if (fec_cfg & BNGE_FEC_ENC_LLRS)
864169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
865169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.advertising);
866169f6e8dSBhargava Marreddy }
867169f6e8dSBhargava Marreddy 
868169f6e8dSBhargava Marreddy static void
869169f6e8dSBhargava Marreddy bnge_fw_to_ethtool_support_fec(struct bnge_link_info *link_info,
870169f6e8dSBhargava Marreddy 			       struct ethtool_link_ksettings *lk_ksettings)
871169f6e8dSBhargava Marreddy {
872169f6e8dSBhargava Marreddy 	u16 fec_cfg = link_info->fec_cfg;
873169f6e8dSBhargava Marreddy 
874169f6e8dSBhargava Marreddy 	if (fec_cfg & BNGE_FEC_NONE) {
875169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
876169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.supported);
877169f6e8dSBhargava Marreddy 		return;
878169f6e8dSBhargava Marreddy 	}
879169f6e8dSBhargava Marreddy 	if (fec_cfg & BNGE_FEC_ENC_BASE_R_CAP)
880169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
881169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.supported);
882169f6e8dSBhargava Marreddy 	if (fec_cfg & BNGE_FEC_ENC_RS_CAP)
883169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
884169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.supported);
885169f6e8dSBhargava Marreddy 	if (fec_cfg & BNGE_FEC_ENC_LLRS_CAP)
886169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
887169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.supported);
888169f6e8dSBhargava Marreddy }
889169f6e8dSBhargava Marreddy 
890169f6e8dSBhargava Marreddy static void bnge_get_default_speeds(struct bnge_net *bn,
891169f6e8dSBhargava Marreddy 				    struct ethtool_link_ksettings *lk_ksettings)
892169f6e8dSBhargava Marreddy {
893169f6e8dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info = &bn->eth_link_info;
894169f6e8dSBhargava Marreddy 	struct ethtool_link_settings *base = &lk_ksettings->base;
895169f6e8dSBhargava Marreddy 	struct bnge_link_info *link_info;
896169f6e8dSBhargava Marreddy 	struct bnge_dev *bd = bn->bd;
897169f6e8dSBhargava Marreddy 
898169f6e8dSBhargava Marreddy 	link_info = &bd->link_info;
899169f6e8dSBhargava Marreddy 
900169f6e8dSBhargava Marreddy 	if (link_info->link_state == BNGE_LINK_STATE_UP) {
901169f6e8dSBhargava Marreddy 		base->speed = bnge_fw_to_ethtool_speed(link_info->link_speed);
902169f6e8dSBhargava Marreddy 		base->duplex = DUPLEX_HALF;
903169f6e8dSBhargava Marreddy 		if (link_info->duplex & BNGE_LINK_DUPLEX_FULL)
904169f6e8dSBhargava Marreddy 			base->duplex = DUPLEX_FULL;
905169f6e8dSBhargava Marreddy 		lk_ksettings->lanes = link_info->active_lanes;
906169f6e8dSBhargava Marreddy 	} else if (!elink_info->autoneg) {
907169f6e8dSBhargava Marreddy 		base->speed =
908169f6e8dSBhargava Marreddy 			bnge_fw_to_ethtool_speed(elink_info->req_link_speed);
909169f6e8dSBhargava Marreddy 		base->duplex = DUPLEX_HALF;
910169f6e8dSBhargava Marreddy 		if (elink_info->req_duplex == BNGE_LINK_DUPLEX_FULL)
911169f6e8dSBhargava Marreddy 			base->duplex = DUPLEX_FULL;
912169f6e8dSBhargava Marreddy 	}
913169f6e8dSBhargava Marreddy }
914169f6e8dSBhargava Marreddy 
915169f6e8dSBhargava Marreddy int bnge_get_link_ksettings(struct net_device *dev,
916169f6e8dSBhargava Marreddy 			    struct ethtool_link_ksettings *lk_ksettings)
917169f6e8dSBhargava Marreddy {
918169f6e8dSBhargava Marreddy 	struct ethtool_link_settings *base = &lk_ksettings->base;
919169f6e8dSBhargava Marreddy 	enum ethtool_link_mode_bit_indices link_mode;
920169f6e8dSBhargava Marreddy 	struct bnge_net *bn = netdev_priv(dev);
921169f6e8dSBhargava Marreddy 	struct bnge_link_info *link_info;
922169f6e8dSBhargava Marreddy 	struct bnge_dev *bd = bn->bd;
923169f6e8dSBhargava Marreddy 	enum bnge_media_type media;
924169f6e8dSBhargava Marreddy 
925169f6e8dSBhargava Marreddy 	ethtool_link_ksettings_zero_link_mode(lk_ksettings, lp_advertising);
926169f6e8dSBhargava Marreddy 	ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising);
927169f6e8dSBhargava Marreddy 	ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported);
928169f6e8dSBhargava Marreddy 	base->duplex = DUPLEX_UNKNOWN;
929169f6e8dSBhargava Marreddy 	base->speed = SPEED_UNKNOWN;
930169f6e8dSBhargava Marreddy 	link_info = &bd->link_info;
931169f6e8dSBhargava Marreddy 
932169f6e8dSBhargava Marreddy 	bnge_get_ethtool_modes(bn, lk_ksettings);
933169f6e8dSBhargava Marreddy 	media = bnge_get_media(link_info);
934169f6e8dSBhargava Marreddy 	bnge_get_all_ethtool_support_speeds(bd, media, lk_ksettings);
935169f6e8dSBhargava Marreddy 	bnge_fw_to_ethtool_support_fec(link_info, lk_ksettings);
936169f6e8dSBhargava Marreddy 	link_mode = bnge_get_link_mode(bn);
937169f6e8dSBhargava Marreddy 	if (link_mode != BNGE_LINK_MODE_UNKNOWN)
938169f6e8dSBhargava Marreddy 		ethtool_params_from_link_mode(lk_ksettings, link_mode);
939169f6e8dSBhargava Marreddy 	else
940169f6e8dSBhargava Marreddy 		bnge_get_default_speeds(bn, lk_ksettings);
941169f6e8dSBhargava Marreddy 
942169f6e8dSBhargava Marreddy 	if (bn->eth_link_info.autoneg) {
943169f6e8dSBhargava Marreddy 		bnge_fw_to_ethtool_advertised_fec(link_info, lk_ksettings);
944169f6e8dSBhargava Marreddy 		linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
945169f6e8dSBhargava Marreddy 				 lk_ksettings->link_modes.advertising);
946169f6e8dSBhargava Marreddy 		base->autoneg = AUTONEG_ENABLE;
947169f6e8dSBhargava Marreddy 		bnge_get_all_ethtool_adv_speeds(bn, media, lk_ksettings);
948169f6e8dSBhargava Marreddy 		if (link_info->phy_link_status == BNGE_LINK_LINK)
949169f6e8dSBhargava Marreddy 			bnge_get_all_ethtool_lp_speeds(bd, media, lk_ksettings);
950169f6e8dSBhargava Marreddy 	} else {
951169f6e8dSBhargava Marreddy 		base->autoneg = AUTONEG_DISABLE;
952169f6e8dSBhargava Marreddy 	}
953169f6e8dSBhargava Marreddy 
954169f6e8dSBhargava Marreddy 	linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
955169f6e8dSBhargava Marreddy 			 lk_ksettings->link_modes.supported);
956169f6e8dSBhargava Marreddy 	linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
957169f6e8dSBhargava Marreddy 			 lk_ksettings->link_modes.advertising);
958169f6e8dSBhargava Marreddy 
959169f6e8dSBhargava Marreddy 	if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC)
960169f6e8dSBhargava Marreddy 		base->port = PORT_DA;
961169f6e8dSBhargava Marreddy 	else
962169f6e8dSBhargava Marreddy 		base->port = PORT_FIBRE;
963169f6e8dSBhargava Marreddy 	base->phy_address = link_info->phy_addr;
964169f6e8dSBhargava Marreddy 
965169f6e8dSBhargava Marreddy 	return 0;
966169f6e8dSBhargava Marreddy }
967169f6e8dSBhargava Marreddy 
968169f6e8dSBhargava Marreddy static bool bnge_lanes_match(u32 user_lanes, u32 supported_lanes)
969169f6e8dSBhargava Marreddy {
970169f6e8dSBhargava Marreddy 	/* 0 means lanes unspecified (auto) */
971169f6e8dSBhargava Marreddy 	return !user_lanes || user_lanes == supported_lanes;
972169f6e8dSBhargava Marreddy }
973169f6e8dSBhargava Marreddy 
974169f6e8dSBhargava Marreddy static int
975169f6e8dSBhargava Marreddy bnge_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 user_lanes)
976169f6e8dSBhargava Marreddy {
977169f6e8dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info;
978169f6e8dSBhargava Marreddy 	struct bnge_net *bn = netdev_priv(dev);
979169f6e8dSBhargava Marreddy 	u8 sig_mode = BNGE_SIG_MODE_NRZ;
980169f6e8dSBhargava Marreddy 	u16 support_spds2;
981169f6e8dSBhargava Marreddy 	u16 fw_speed = 0;
982169f6e8dSBhargava Marreddy 
983169f6e8dSBhargava Marreddy 	elink_info = &bn->eth_link_info;
984169f6e8dSBhargava Marreddy 	support_spds2 = bn->bd->link_info.support_speeds2;
985169f6e8dSBhargava Marreddy 
986169f6e8dSBhargava Marreddy 	switch (ethtool_speed) {
987169f6e8dSBhargava Marreddy 	case SPEED_50000:
988169f6e8dSBhargava Marreddy 		if (bnge_lanes_match(user_lanes, 1) &&
989169f6e8dSBhargava Marreddy 		    (support_spds2 & BNGE_LINK_SPEEDS2_MSK_50GB_PAM4)) {
990169f6e8dSBhargava Marreddy 			fw_speed = BNGE_LINK_SPEED_50GB_PAM4;
991169f6e8dSBhargava Marreddy 			sig_mode = BNGE_SIG_MODE_PAM4;
992169f6e8dSBhargava Marreddy 		}
993169f6e8dSBhargava Marreddy 		break;
994169f6e8dSBhargava Marreddy 	case SPEED_100000:
995169f6e8dSBhargava Marreddy 		if (bnge_lanes_match(user_lanes, 4) &&
996169f6e8dSBhargava Marreddy 		    (support_spds2 & BNGE_LINK_SPEEDS2_MSK_100GB)) {
997169f6e8dSBhargava Marreddy 			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB;
998169f6e8dSBhargava Marreddy 		} else if (bnge_lanes_match(user_lanes, 2) &&
999169f6e8dSBhargava Marreddy 			   (support_spds2 & BNGE_LINK_SPEEDS2_MSK_100GB_PAM4)) {
1000169f6e8dSBhargava Marreddy 			fw_speed = BNGE_LINK_SPEED_100GB_PAM4;
1001169f6e8dSBhargava Marreddy 			sig_mode = BNGE_SIG_MODE_PAM4;
1002169f6e8dSBhargava Marreddy 		} else if (bnge_lanes_match(user_lanes, 1) &&
1003169f6e8dSBhargava Marreddy 			   (support_spds2 & BNGE_LINK_SPEEDS2_MSK_100GB_PAM4_112)) {
1004169f6e8dSBhargava Marreddy 			fw_speed = BNGE_LINK_SPEED_100GB_PAM4_112;
1005169f6e8dSBhargava Marreddy 			sig_mode = BNGE_SIG_MODE_PAM4_112;
1006169f6e8dSBhargava Marreddy 		}
1007169f6e8dSBhargava Marreddy 		break;
1008169f6e8dSBhargava Marreddy 	case SPEED_200000:
1009169f6e8dSBhargava Marreddy 		if (bnge_lanes_match(user_lanes, 4) &&
1010169f6e8dSBhargava Marreddy 		    (support_spds2 & BNGE_LINK_SPEEDS2_MSK_200GB_PAM4)) {
1011169f6e8dSBhargava Marreddy 			fw_speed = BNGE_LINK_SPEED_200GB_PAM4;
1012169f6e8dSBhargava Marreddy 			sig_mode = BNGE_SIG_MODE_PAM4;
1013169f6e8dSBhargava Marreddy 		} else if (bnge_lanes_match(user_lanes, 2) &&
1014169f6e8dSBhargava Marreddy 			   (support_spds2 & BNGE_LINK_SPEEDS2_MSK_200GB_PAM4_112)) {
1015169f6e8dSBhargava Marreddy 			fw_speed = BNGE_LINK_SPEED_200GB_PAM4_112;
1016169f6e8dSBhargava Marreddy 			sig_mode = BNGE_SIG_MODE_PAM4_112;
1017169f6e8dSBhargava Marreddy 		}
1018169f6e8dSBhargava Marreddy 		break;
1019169f6e8dSBhargava Marreddy 	case SPEED_400000:
1020169f6e8dSBhargava Marreddy 		if (bnge_lanes_match(user_lanes, 8) &&
1021169f6e8dSBhargava Marreddy 		    (support_spds2 & BNGE_LINK_SPEEDS2_MSK_400GB_PAM4)) {
1022169f6e8dSBhargava Marreddy 			fw_speed = BNGE_LINK_SPEED_400GB_PAM4;
1023169f6e8dSBhargava Marreddy 			sig_mode = BNGE_SIG_MODE_PAM4;
1024169f6e8dSBhargava Marreddy 		} else if (bnge_lanes_match(user_lanes, 4) &&
1025169f6e8dSBhargava Marreddy 			   (support_spds2 & BNGE_LINK_SPEEDS2_MSK_400GB_PAM4_112)) {
1026169f6e8dSBhargava Marreddy 			fw_speed = BNGE_LINK_SPEED_400GB_PAM4_112;
1027169f6e8dSBhargava Marreddy 			sig_mode = BNGE_SIG_MODE_PAM4_112;
1028169f6e8dSBhargava Marreddy 		}
1029169f6e8dSBhargava Marreddy 		break;
1030169f6e8dSBhargava Marreddy 	case SPEED_800000:
1031169f6e8dSBhargava Marreddy 		if (bnge_lanes_match(user_lanes, 8) &&
1032169f6e8dSBhargava Marreddy 		    (support_spds2 & BNGE_LINK_SPEEDS2_MSK_800GB_PAM4_112)) {
1033169f6e8dSBhargava Marreddy 			fw_speed = BNGE_LINK_SPEED_800GB_PAM4_112;
1034169f6e8dSBhargava Marreddy 			sig_mode = BNGE_SIG_MODE_PAM4_112;
1035169f6e8dSBhargava Marreddy 		}
1036169f6e8dSBhargava Marreddy 		break;
1037169f6e8dSBhargava Marreddy 	default:
1038169f6e8dSBhargava Marreddy 		break;
1039169f6e8dSBhargava Marreddy 	}
1040169f6e8dSBhargava Marreddy 
1041169f6e8dSBhargava Marreddy 	if (!fw_speed) {
1042169f6e8dSBhargava Marreddy 		if (user_lanes)
1043169f6e8dSBhargava Marreddy 			netdev_err(dev, "unsupported speed or number of lanes!\n");
1044169f6e8dSBhargava Marreddy 		else
1045169f6e8dSBhargava Marreddy 			netdev_err(dev, "unsupported speed!\n");
1046169f6e8dSBhargava Marreddy 		return -EINVAL;
1047169f6e8dSBhargava Marreddy 	}
1048169f6e8dSBhargava Marreddy 
1049169f6e8dSBhargava Marreddy 	if (elink_info->req_link_speed == fw_speed &&
1050169f6e8dSBhargava Marreddy 	    elink_info->req_signal_mode == sig_mode &&
1051169f6e8dSBhargava Marreddy 	    elink_info->autoneg == 0)
1052169f6e8dSBhargava Marreddy 		return -EALREADY;
1053169f6e8dSBhargava Marreddy 
1054169f6e8dSBhargava Marreddy 	elink_info->req_link_speed = fw_speed;
1055169f6e8dSBhargava Marreddy 	elink_info->req_signal_mode = sig_mode;
1056169f6e8dSBhargava Marreddy 	elink_info->req_duplex = BNGE_LINK_DUPLEX_FULL;
1057169f6e8dSBhargava Marreddy 	elink_info->autoneg = 0;
1058169f6e8dSBhargava Marreddy 	elink_info->advertising = 0;
1059169f6e8dSBhargava Marreddy 
1060169f6e8dSBhargava Marreddy 	return 0;
1061169f6e8dSBhargava Marreddy }
1062169f6e8dSBhargava Marreddy 
1063169f6e8dSBhargava Marreddy int bnge_set_link_ksettings(struct net_device *dev,
1064169f6e8dSBhargava Marreddy 			    const struct ethtool_link_ksettings *lk_ksettings)
1065169f6e8dSBhargava Marreddy {
1066169f6e8dSBhargava Marreddy 	const struct ethtool_link_settings *base = &lk_ksettings->base;
1067169f6e8dSBhargava Marreddy 	struct bnge_ethtool_link_info old_elink_info;
1068169f6e8dSBhargava Marreddy 	struct bnge_ethtool_link_info *elink_info;
1069169f6e8dSBhargava Marreddy 	struct bnge_net *bn = netdev_priv(dev);
1070169f6e8dSBhargava Marreddy 	struct bnge_dev *bd = bn->bd;
1071169f6e8dSBhargava Marreddy 	bool set_pause = false;
1072169f6e8dSBhargava Marreddy 	int rc = 0;
1073169f6e8dSBhargava Marreddy 
1074169f6e8dSBhargava Marreddy 	if (!BNGE_PHY_CFG_ABLE(bd))
1075169f6e8dSBhargava Marreddy 		return -EOPNOTSUPP;
1076169f6e8dSBhargava Marreddy 
1077169f6e8dSBhargava Marreddy 	elink_info = &bn->eth_link_info;
1078169f6e8dSBhargava Marreddy 	old_elink_info = *elink_info;
1079169f6e8dSBhargava Marreddy 
1080169f6e8dSBhargava Marreddy 	if (base->autoneg == AUTONEG_ENABLE) {
1081169f6e8dSBhargava Marreddy 		bnge_set_ethtool_speeds(bn,
1082169f6e8dSBhargava Marreddy 					lk_ksettings->link_modes.advertising);
1083169f6e8dSBhargava Marreddy 		elink_info->autoneg |= BNGE_AUTONEG_SPEED;
1084169f6e8dSBhargava Marreddy 		if (!elink_info->advertising)
1085169f6e8dSBhargava Marreddy 			bnge_set_default_adv_speeds(bn);
1086169f6e8dSBhargava Marreddy 		/* any change to autoneg will cause link change, therefore the
1087169f6e8dSBhargava Marreddy 		 * driver should put back the original pause setting in autoneg
1088169f6e8dSBhargava Marreddy 		 */
1089169f6e8dSBhargava Marreddy 		if (!(bd->phy_flags & BNGE_PHY_FL_NO_PAUSE))
1090169f6e8dSBhargava Marreddy 			set_pause = true;
1091169f6e8dSBhargava Marreddy 	} else {
1092169f6e8dSBhargava Marreddy 		if (base->duplex == DUPLEX_HALF) {
1093169f6e8dSBhargava Marreddy 			netdev_err(dev, "HALF DUPLEX is not supported!\n");
1094169f6e8dSBhargava Marreddy 			rc = -EINVAL;
1095169f6e8dSBhargava Marreddy 			goto set_setting_exit;
1096169f6e8dSBhargava Marreddy 		}
1097169f6e8dSBhargava Marreddy 		rc = bnge_force_link_speed(dev, base->speed,
1098169f6e8dSBhargava Marreddy 					   lk_ksettings->lanes);
1099169f6e8dSBhargava Marreddy 		if (rc) {
1100169f6e8dSBhargava Marreddy 			if (rc == -EALREADY)
1101169f6e8dSBhargava Marreddy 				rc = 0;
1102169f6e8dSBhargava Marreddy 			goto set_setting_exit;
1103169f6e8dSBhargava Marreddy 		}
1104169f6e8dSBhargava Marreddy 	}
1105169f6e8dSBhargava Marreddy 
1106169f6e8dSBhargava Marreddy 	if (netif_running(dev)) {
1107169f6e8dSBhargava Marreddy 		rc = bnge_hwrm_set_link_setting(bn, set_pause);
1108169f6e8dSBhargava Marreddy 		if (rc)
1109169f6e8dSBhargava Marreddy 			*elink_info = old_elink_info;
1110169f6e8dSBhargava Marreddy 	}
1111169f6e8dSBhargava Marreddy 
1112169f6e8dSBhargava Marreddy set_setting_exit:
1113169f6e8dSBhargava Marreddy 	return rc;
1114169f6e8dSBhargava Marreddy }
1115*4a759009SBhargava Marreddy 
1116*4a759009SBhargava Marreddy void bnge_link_async_event_process(struct bnge_net *bn, u16 event_id)
1117*4a759009SBhargava Marreddy {
1118*4a759009SBhargava Marreddy 	switch (event_id) {
1119*4a759009SBhargava Marreddy 	case ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE:
1120*4a759009SBhargava Marreddy 		set_bit(BNGE_LINK_SPEED_CHNG_SP_EVENT, &bn->sp_event);
1121*4a759009SBhargava Marreddy 		break;
1122*4a759009SBhargava Marreddy 	case ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE:
1123*4a759009SBhargava Marreddy 	case ASYNC_EVENT_CMPL_EVENT_ID_PORT_PHY_CFG_CHANGE:
1124*4a759009SBhargava Marreddy 		set_bit(BNGE_LINK_CFG_CHANGE_SP_EVENT, &bn->sp_event);
1125*4a759009SBhargava Marreddy 		break;
1126*4a759009SBhargava Marreddy 	case ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE:
1127*4a759009SBhargava Marreddy 		set_bit(BNGE_LINK_CHNG_SP_EVENT, &bn->sp_event);
1128*4a759009SBhargava Marreddy 		break;
1129*4a759009SBhargava Marreddy 	default:
1130*4a759009SBhargava Marreddy 		break;
1131*4a759009SBhargava Marreddy 	}
1132*4a759009SBhargava Marreddy }
1133