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