18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci/* ethtool support for ice */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "ice.h" 78c2ecf20Sopenharmony_ci#include "ice_flow.h" 88c2ecf20Sopenharmony_ci#include "ice_fltr.h" 98c2ecf20Sopenharmony_ci#include "ice_lib.h" 108c2ecf20Sopenharmony_ci#include "ice_dcb_lib.h" 118c2ecf20Sopenharmony_ci#include <net/dcbnl.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistruct ice_stats { 148c2ecf20Sopenharmony_ci char stat_string[ETH_GSTRING_LEN]; 158c2ecf20Sopenharmony_ci int sizeof_stat; 168c2ecf20Sopenharmony_ci int stat_offset; 178c2ecf20Sopenharmony_ci}; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define ICE_STAT(_type, _name, _stat) { \ 208c2ecf20Sopenharmony_ci .stat_string = _name, \ 218c2ecf20Sopenharmony_ci .sizeof_stat = sizeof_field(_type, _stat), \ 228c2ecf20Sopenharmony_ci .stat_offset = offsetof(_type, _stat) \ 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define ICE_VSI_STAT(_name, _stat) \ 268c2ecf20Sopenharmony_ci ICE_STAT(struct ice_vsi, _name, _stat) 278c2ecf20Sopenharmony_ci#define ICE_PF_STAT(_name, _stat) \ 288c2ecf20Sopenharmony_ci ICE_STAT(struct ice_pf, _name, _stat) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic int ice_q_stats_len(struct net_device *netdev) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci return ((np->vsi->alloc_txq + np->vsi->alloc_rxq) * 358c2ecf20Sopenharmony_ci (sizeof(struct ice_q_stats) / sizeof(u64))); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define ICE_PF_STATS_LEN ARRAY_SIZE(ice_gstrings_pf_stats) 398c2ecf20Sopenharmony_ci#define ICE_VSI_STATS_LEN ARRAY_SIZE(ice_gstrings_vsi_stats) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define ICE_PFC_STATS_LEN ( \ 428c2ecf20Sopenharmony_ci (sizeof_field(struct ice_pf, stats.priority_xoff_rx) + \ 438c2ecf20Sopenharmony_ci sizeof_field(struct ice_pf, stats.priority_xon_rx) + \ 448c2ecf20Sopenharmony_ci sizeof_field(struct ice_pf, stats.priority_xoff_tx) + \ 458c2ecf20Sopenharmony_ci sizeof_field(struct ice_pf, stats.priority_xon_tx)) \ 468c2ecf20Sopenharmony_ci / sizeof(u64)) 478c2ecf20Sopenharmony_ci#define ICE_ALL_STATS_LEN(n) (ICE_PF_STATS_LEN + ICE_PFC_STATS_LEN + \ 488c2ecf20Sopenharmony_ci ICE_VSI_STATS_LEN + ice_q_stats_len(n)) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic const struct ice_stats ice_gstrings_vsi_stats[] = { 518c2ecf20Sopenharmony_ci ICE_VSI_STAT("rx_unicast", eth_stats.rx_unicast), 528c2ecf20Sopenharmony_ci ICE_VSI_STAT("tx_unicast", eth_stats.tx_unicast), 538c2ecf20Sopenharmony_ci ICE_VSI_STAT("rx_multicast", eth_stats.rx_multicast), 548c2ecf20Sopenharmony_ci ICE_VSI_STAT("tx_multicast", eth_stats.tx_multicast), 558c2ecf20Sopenharmony_ci ICE_VSI_STAT("rx_broadcast", eth_stats.rx_broadcast), 568c2ecf20Sopenharmony_ci ICE_VSI_STAT("tx_broadcast", eth_stats.tx_broadcast), 578c2ecf20Sopenharmony_ci ICE_VSI_STAT("rx_bytes", eth_stats.rx_bytes), 588c2ecf20Sopenharmony_ci ICE_VSI_STAT("tx_bytes", eth_stats.tx_bytes), 598c2ecf20Sopenharmony_ci ICE_VSI_STAT("rx_dropped", eth_stats.rx_discards), 608c2ecf20Sopenharmony_ci ICE_VSI_STAT("rx_unknown_protocol", eth_stats.rx_unknown_protocol), 618c2ecf20Sopenharmony_ci ICE_VSI_STAT("rx_alloc_fail", rx_buf_failed), 628c2ecf20Sopenharmony_ci ICE_VSI_STAT("rx_pg_alloc_fail", rx_page_failed), 638c2ecf20Sopenharmony_ci ICE_VSI_STAT("rx_gro_dropped", rx_gro_dropped), 648c2ecf20Sopenharmony_ci ICE_VSI_STAT("tx_errors", eth_stats.tx_errors), 658c2ecf20Sopenharmony_ci ICE_VSI_STAT("tx_linearize", tx_linearize), 668c2ecf20Sopenharmony_ci ICE_VSI_STAT("tx_busy", tx_busy), 678c2ecf20Sopenharmony_ci ICE_VSI_STAT("tx_restart", tx_restart), 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cienum ice_ethtool_test_id { 718c2ecf20Sopenharmony_ci ICE_ETH_TEST_REG = 0, 728c2ecf20Sopenharmony_ci ICE_ETH_TEST_EEPROM, 738c2ecf20Sopenharmony_ci ICE_ETH_TEST_INTR, 748c2ecf20Sopenharmony_ci ICE_ETH_TEST_LOOP, 758c2ecf20Sopenharmony_ci ICE_ETH_TEST_LINK, 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic const char ice_gstrings_test[][ETH_GSTRING_LEN] = { 798c2ecf20Sopenharmony_ci "Register test (offline)", 808c2ecf20Sopenharmony_ci "EEPROM test (offline)", 818c2ecf20Sopenharmony_ci "Interrupt test (offline)", 828c2ecf20Sopenharmony_ci "Loopback test (offline)", 838c2ecf20Sopenharmony_ci "Link test (on/offline)", 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define ICE_TEST_LEN (sizeof(ice_gstrings_test) / ETH_GSTRING_LEN) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* These PF_STATs might look like duplicates of some NETDEV_STATs, 898c2ecf20Sopenharmony_ci * but they aren't. This device is capable of supporting multiple 908c2ecf20Sopenharmony_ci * VSIs/netdevs on a single PF. The NETDEV_STATs are for individual 918c2ecf20Sopenharmony_ci * netdevs whereas the PF_STATs are for the physical function that's 928c2ecf20Sopenharmony_ci * hosting these netdevs. 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * The PF_STATs are appended to the netdev stats only when ethtool -S 958c2ecf20Sopenharmony_ci * is queried on the base PF netdev. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_cistatic const struct ice_stats ice_gstrings_pf_stats[] = { 988c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_bytes.nic", stats.eth.rx_bytes), 998c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_bytes.nic", stats.eth.tx_bytes), 1008c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_unicast.nic", stats.eth.rx_unicast), 1018c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_unicast.nic", stats.eth.tx_unicast), 1028c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_multicast.nic", stats.eth.rx_multicast), 1038c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_multicast.nic", stats.eth.tx_multicast), 1048c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_broadcast.nic", stats.eth.rx_broadcast), 1058c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_broadcast.nic", stats.eth.tx_broadcast), 1068c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_errors.nic", stats.eth.tx_errors), 1078c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_timeout.nic", tx_timeout_count), 1088c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_size_64.nic", stats.rx_size_64), 1098c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_size_64.nic", stats.tx_size_64), 1108c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_size_127.nic", stats.rx_size_127), 1118c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_size_127.nic", stats.tx_size_127), 1128c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_size_255.nic", stats.rx_size_255), 1138c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_size_255.nic", stats.tx_size_255), 1148c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_size_511.nic", stats.rx_size_511), 1158c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_size_511.nic", stats.tx_size_511), 1168c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_size_1023.nic", stats.rx_size_1023), 1178c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_size_1023.nic", stats.tx_size_1023), 1188c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_size_1522.nic", stats.rx_size_1522), 1198c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_size_1522.nic", stats.tx_size_1522), 1208c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_size_big.nic", stats.rx_size_big), 1218c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_size_big.nic", stats.tx_size_big), 1228c2ecf20Sopenharmony_ci ICE_PF_STAT("link_xon_rx.nic", stats.link_xon_rx), 1238c2ecf20Sopenharmony_ci ICE_PF_STAT("link_xon_tx.nic", stats.link_xon_tx), 1248c2ecf20Sopenharmony_ci ICE_PF_STAT("link_xoff_rx.nic", stats.link_xoff_rx), 1258c2ecf20Sopenharmony_ci ICE_PF_STAT("link_xoff_tx.nic", stats.link_xoff_tx), 1268c2ecf20Sopenharmony_ci ICE_PF_STAT("tx_dropped_link_down.nic", stats.tx_dropped_link_down), 1278c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_undersize.nic", stats.rx_undersize), 1288c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_fragments.nic", stats.rx_fragments), 1298c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_oversize.nic", stats.rx_oversize), 1308c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_jabber.nic", stats.rx_jabber), 1318c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_csum_bad.nic", hw_csum_rx_error), 1328c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_length_errors.nic", stats.rx_len_errors), 1338c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_dropped.nic", stats.eth.rx_discards), 1348c2ecf20Sopenharmony_ci ICE_PF_STAT("rx_crc_errors.nic", stats.crc_errors), 1358c2ecf20Sopenharmony_ci ICE_PF_STAT("illegal_bytes.nic", stats.illegal_bytes), 1368c2ecf20Sopenharmony_ci ICE_PF_STAT("mac_local_faults.nic", stats.mac_local_faults), 1378c2ecf20Sopenharmony_ci ICE_PF_STAT("mac_remote_faults.nic", stats.mac_remote_faults), 1388c2ecf20Sopenharmony_ci ICE_PF_STAT("fdir_sb_match.nic", stats.fd_sb_match), 1398c2ecf20Sopenharmony_ci ICE_PF_STAT("fdir_sb_status.nic", stats.fd_sb_status), 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic const u32 ice_regs_dump_list[] = { 1438c2ecf20Sopenharmony_ci PFGEN_STATE, 1448c2ecf20Sopenharmony_ci PRTGEN_STATUS, 1458c2ecf20Sopenharmony_ci QRX_CTRL(0), 1468c2ecf20Sopenharmony_ci QINT_TQCTL(0), 1478c2ecf20Sopenharmony_ci QINT_RQCTL(0), 1488c2ecf20Sopenharmony_ci PFINT_OICR_ENA, 1498c2ecf20Sopenharmony_ci QRX_ITR(0), 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistruct ice_priv_flag { 1538c2ecf20Sopenharmony_ci char name[ETH_GSTRING_LEN]; 1548c2ecf20Sopenharmony_ci u32 bitno; /* bit position in pf->flags */ 1558c2ecf20Sopenharmony_ci}; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#define ICE_PRIV_FLAG(_name, _bitno) { \ 1588c2ecf20Sopenharmony_ci .name = _name, \ 1598c2ecf20Sopenharmony_ci .bitno = _bitno, \ 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic const struct ice_priv_flag ice_gstrings_priv_flags[] = { 1638c2ecf20Sopenharmony_ci ICE_PRIV_FLAG("link-down-on-close", ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA), 1648c2ecf20Sopenharmony_ci ICE_PRIV_FLAG("fw-lldp-agent", ICE_FLAG_FW_LLDP_AGENT), 1658c2ecf20Sopenharmony_ci ICE_PRIV_FLAG("vf-true-promisc-support", 1668c2ecf20Sopenharmony_ci ICE_FLAG_VF_TRUE_PROMISC_ENA), 1678c2ecf20Sopenharmony_ci ICE_PRIV_FLAG("mdd-auto-reset-vf", ICE_FLAG_MDD_AUTO_RESET_VF), 1688c2ecf20Sopenharmony_ci ICE_PRIV_FLAG("legacy-rx", ICE_FLAG_LEGACY_RX), 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#define ICE_PRIV_FLAG_ARRAY_SIZE ARRAY_SIZE(ice_gstrings_priv_flags) 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void 1748c2ecf20Sopenharmony_ciice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 1778c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 1788c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 1798c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 1808c2ecf20Sopenharmony_ci struct ice_orom_info *orom; 1818c2ecf20Sopenharmony_ci struct ice_nvm_info *nvm; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci nvm = &hw->nvm; 1848c2ecf20Sopenharmony_ci orom = &nvm->orom; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Display NVM version (from which the firmware version can be 1898c2ecf20Sopenharmony_ci * determined) which contains more pertinent information. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), 1928c2ecf20Sopenharmony_ci "%x.%02x 0x%x %d.%d.%d", nvm->major_ver, nvm->minor_ver, 1938c2ecf20Sopenharmony_ci nvm->eetrack, orom->major, orom->build, orom->patch); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci strscpy(drvinfo->bus_info, pci_name(pf->pdev), 1968c2ecf20Sopenharmony_ci sizeof(drvinfo->bus_info)); 1978c2ecf20Sopenharmony_ci drvinfo->n_priv_flags = ICE_PRIV_FLAG_ARRAY_SIZE; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int ice_get_regs_len(struct net_device __always_unused *netdev) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci return sizeof(ice_regs_dump_list); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic void 2068c2ecf20Sopenharmony_ciice_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 2098c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 2108c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 2118c2ecf20Sopenharmony_ci u32 *regs_buf = (u32 *)p; 2128c2ecf20Sopenharmony_ci unsigned int i; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci regs->version = 1; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ice_regs_dump_list); ++i) 2178c2ecf20Sopenharmony_ci regs_buf[i] = rd32(hw, ice_regs_dump_list[i]); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic u32 ice_get_msglevel(struct net_device *netdev) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 2238c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci#ifndef CONFIG_DYNAMIC_DEBUG 2268c2ecf20Sopenharmony_ci if (pf->hw.debug_mask) 2278c2ecf20Sopenharmony_ci netdev_info(netdev, "hw debug_mask: 0x%llX\n", 2288c2ecf20Sopenharmony_ci pf->hw.debug_mask); 2298c2ecf20Sopenharmony_ci#endif /* !CONFIG_DYNAMIC_DEBUG */ 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return pf->msg_enable; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void ice_set_msglevel(struct net_device *netdev, u32 data) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 2378c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci#ifndef CONFIG_DYNAMIC_DEBUG 2408c2ecf20Sopenharmony_ci if (ICE_DBG_USER & data) 2418c2ecf20Sopenharmony_ci pf->hw.debug_mask = data; 2428c2ecf20Sopenharmony_ci else 2438c2ecf20Sopenharmony_ci pf->msg_enable = data; 2448c2ecf20Sopenharmony_ci#else 2458c2ecf20Sopenharmony_ci pf->msg_enable = data; 2468c2ecf20Sopenharmony_ci#endif /* !CONFIG_DYNAMIC_DEBUG */ 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int ice_get_eeprom_len(struct net_device *netdev) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 2528c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return (int)pf->hw.nvm.flash_size; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic int 2588c2ecf20Sopenharmony_ciice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, 2598c2ecf20Sopenharmony_ci u8 *bytes) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 2628c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 2638c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 2648c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 2658c2ecf20Sopenharmony_ci enum ice_status status; 2668c2ecf20Sopenharmony_ci struct device *dev; 2678c2ecf20Sopenharmony_ci int ret = 0; 2688c2ecf20Sopenharmony_ci u8 *buf; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci eeprom->magic = hw->vendor_id | (hw->device_id << 16); 2738c2ecf20Sopenharmony_ci netdev_dbg(netdev, "GEEPROM cmd 0x%08x, offset 0x%08x, len 0x%08x\n", 2748c2ecf20Sopenharmony_ci eeprom->cmd, eeprom->offset, eeprom->len); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci buf = kzalloc(eeprom->len, GFP_KERNEL); 2778c2ecf20Sopenharmony_ci if (!buf) 2788c2ecf20Sopenharmony_ci return -ENOMEM; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci status = ice_acquire_nvm(hw, ICE_RES_READ); 2818c2ecf20Sopenharmony_ci if (status) { 2828c2ecf20Sopenharmony_ci dev_err(dev, "ice_acquire_nvm failed, err %s aq_err %s\n", 2838c2ecf20Sopenharmony_ci ice_stat_str(status), 2848c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 2858c2ecf20Sopenharmony_ci ret = -EIO; 2868c2ecf20Sopenharmony_ci goto out; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci status = ice_read_flat_nvm(hw, eeprom->offset, &eeprom->len, buf, 2908c2ecf20Sopenharmony_ci false); 2918c2ecf20Sopenharmony_ci if (status) { 2928c2ecf20Sopenharmony_ci dev_err(dev, "ice_read_flat_nvm failed, err %s aq_err %s\n", 2938c2ecf20Sopenharmony_ci ice_stat_str(status), 2948c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 2958c2ecf20Sopenharmony_ci ret = -EIO; 2968c2ecf20Sopenharmony_ci goto release; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci memcpy(bytes, buf, eeprom->len); 3008c2ecf20Sopenharmony_cirelease: 3018c2ecf20Sopenharmony_ci ice_release_nvm(hw); 3028c2ecf20Sopenharmony_ciout: 3038c2ecf20Sopenharmony_ci kfree(buf); 3048c2ecf20Sopenharmony_ci return ret; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/** 3088c2ecf20Sopenharmony_ci * ice_active_vfs - check if there are any active VFs 3098c2ecf20Sopenharmony_ci * @pf: board private structure 3108c2ecf20Sopenharmony_ci * 3118c2ecf20Sopenharmony_ci * Returns true if an active VF is found, otherwise returns false 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_cistatic bool ice_active_vfs(struct ice_pf *pf) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci unsigned int i; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci ice_for_each_vf(pf, i) { 3188c2ecf20Sopenharmony_ci struct ice_vf *vf = &pf->vf[i]; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) 3218c2ecf20Sopenharmony_ci return true; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return false; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci/** 3288c2ecf20Sopenharmony_ci * ice_link_test - perform a link test on a given net_device 3298c2ecf20Sopenharmony_ci * @netdev: network interface device structure 3308c2ecf20Sopenharmony_ci * 3318c2ecf20Sopenharmony_ci * This function performs one of the self-tests required by ethtool. 3328c2ecf20Sopenharmony_ci * Returns 0 on success, non-zero on failure. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_cistatic u64 ice_link_test(struct net_device *netdev) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 3378c2ecf20Sopenharmony_ci enum ice_status status; 3388c2ecf20Sopenharmony_ci bool link_up = false; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci netdev_info(netdev, "link test\n"); 3418c2ecf20Sopenharmony_ci status = ice_get_link_status(np->vsi->port_info, &link_up); 3428c2ecf20Sopenharmony_ci if (status) { 3438c2ecf20Sopenharmony_ci netdev_err(netdev, "link query error, status = %s\n", 3448c2ecf20Sopenharmony_ci ice_stat_str(status)); 3458c2ecf20Sopenharmony_ci return 1; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (!link_up) 3498c2ecf20Sopenharmony_ci return 2; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/** 3558c2ecf20Sopenharmony_ci * ice_eeprom_test - perform an EEPROM test on a given net_device 3568c2ecf20Sopenharmony_ci * @netdev: network interface device structure 3578c2ecf20Sopenharmony_ci * 3588c2ecf20Sopenharmony_ci * This function performs one of the self-tests required by ethtool. 3598c2ecf20Sopenharmony_ci * Returns 0 on success, non-zero on failure. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_cistatic u64 ice_eeprom_test(struct net_device *netdev) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 3648c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci netdev_info(netdev, "EEPROM test\n"); 3678c2ecf20Sopenharmony_ci return !!(ice_nvm_validate_checksum(&pf->hw)); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci/** 3718c2ecf20Sopenharmony_ci * ice_reg_pattern_test 3728c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 3738c2ecf20Sopenharmony_ci * @reg: reg to be tested 3748c2ecf20Sopenharmony_ci * @mask: bits to be touched 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_cistatic int ice_reg_pattern_test(struct ice_hw *hw, u32 reg, u32 mask) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct ice_pf *pf = (struct ice_pf *)hw->back; 3798c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 3808c2ecf20Sopenharmony_ci static const u32 patterns[] = { 3818c2ecf20Sopenharmony_ci 0x5A5A5A5A, 0xA5A5A5A5, 3828c2ecf20Sopenharmony_ci 0x00000000, 0xFFFFFFFF 3838c2ecf20Sopenharmony_ci }; 3848c2ecf20Sopenharmony_ci u32 val, orig_val; 3858c2ecf20Sopenharmony_ci unsigned int i; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci orig_val = rd32(hw, reg); 3888c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(patterns); ++i) { 3898c2ecf20Sopenharmony_ci u32 pattern = patterns[i] & mask; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci wr32(hw, reg, pattern); 3928c2ecf20Sopenharmony_ci val = rd32(hw, reg); 3938c2ecf20Sopenharmony_ci if (val == pattern) 3948c2ecf20Sopenharmony_ci continue; 3958c2ecf20Sopenharmony_ci dev_err(dev, "%s: reg pattern test failed - reg 0x%08x pat 0x%08x val 0x%08x\n" 3968c2ecf20Sopenharmony_ci , __func__, reg, pattern, val); 3978c2ecf20Sopenharmony_ci return 1; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci wr32(hw, reg, orig_val); 4018c2ecf20Sopenharmony_ci val = rd32(hw, reg); 4028c2ecf20Sopenharmony_ci if (val != orig_val) { 4038c2ecf20Sopenharmony_ci dev_err(dev, "%s: reg restore test failed - reg 0x%08x orig 0x%08x val 0x%08x\n" 4048c2ecf20Sopenharmony_ci , __func__, reg, orig_val, val); 4058c2ecf20Sopenharmony_ci return 1; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci return 0; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci/** 4128c2ecf20Sopenharmony_ci * ice_reg_test - perform a register test on a given net_device 4138c2ecf20Sopenharmony_ci * @netdev: network interface device structure 4148c2ecf20Sopenharmony_ci * 4158c2ecf20Sopenharmony_ci * This function performs one of the self-tests required by ethtool. 4168c2ecf20Sopenharmony_ci * Returns 0 on success, non-zero on failure. 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_cistatic u64 ice_reg_test(struct net_device *netdev) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 4218c2ecf20Sopenharmony_ci struct ice_hw *hw = np->vsi->port_info->hw; 4228c2ecf20Sopenharmony_ci u32 int_elements = hw->func_caps.common_cap.num_msix_vectors ? 4238c2ecf20Sopenharmony_ci hw->func_caps.common_cap.num_msix_vectors - 1 : 1; 4248c2ecf20Sopenharmony_ci struct ice_diag_reg_test_info { 4258c2ecf20Sopenharmony_ci u32 address; 4268c2ecf20Sopenharmony_ci u32 mask; 4278c2ecf20Sopenharmony_ci u32 elem_num; 4288c2ecf20Sopenharmony_ci u32 elem_size; 4298c2ecf20Sopenharmony_ci } ice_reg_list[] = { 4308c2ecf20Sopenharmony_ci {GLINT_ITR(0, 0), 0x00000fff, int_elements, 4318c2ecf20Sopenharmony_ci GLINT_ITR(0, 1) - GLINT_ITR(0, 0)}, 4328c2ecf20Sopenharmony_ci {GLINT_ITR(1, 0), 0x00000fff, int_elements, 4338c2ecf20Sopenharmony_ci GLINT_ITR(1, 1) - GLINT_ITR(1, 0)}, 4348c2ecf20Sopenharmony_ci {GLINT_ITR(0, 0), 0x00000fff, int_elements, 4358c2ecf20Sopenharmony_ci GLINT_ITR(2, 1) - GLINT_ITR(2, 0)}, 4368c2ecf20Sopenharmony_ci {GLINT_CTL, 0xffff0001, 1, 0} 4378c2ecf20Sopenharmony_ci }; 4388c2ecf20Sopenharmony_ci unsigned int i; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci netdev_dbg(netdev, "Register test\n"); 4418c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ice_reg_list); ++i) { 4428c2ecf20Sopenharmony_ci u32 j; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci for (j = 0; j < ice_reg_list[i].elem_num; ++j) { 4458c2ecf20Sopenharmony_ci u32 mask = ice_reg_list[i].mask; 4468c2ecf20Sopenharmony_ci u32 reg = ice_reg_list[i].address + 4478c2ecf20Sopenharmony_ci (j * ice_reg_list[i].elem_size); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* bail on failure (non-zero return) */ 4508c2ecf20Sopenharmony_ci if (ice_reg_pattern_test(hw, reg, mask)) 4518c2ecf20Sopenharmony_ci return 1; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci/** 4598c2ecf20Sopenharmony_ci * ice_lbtest_prepare_rings - configure Tx/Rx test rings 4608c2ecf20Sopenharmony_ci * @vsi: pointer to the VSI structure 4618c2ecf20Sopenharmony_ci * 4628c2ecf20Sopenharmony_ci * Function configures rings of a VSI for loopback test without 4638c2ecf20Sopenharmony_ci * enabling interrupts or informing the kernel about new queues. 4648c2ecf20Sopenharmony_ci * 4658c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure. 4668c2ecf20Sopenharmony_ci */ 4678c2ecf20Sopenharmony_cistatic int ice_lbtest_prepare_rings(struct ice_vsi *vsi) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci int status; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci status = ice_vsi_setup_tx_rings(vsi); 4728c2ecf20Sopenharmony_ci if (status) 4738c2ecf20Sopenharmony_ci goto err_setup_tx_ring; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci status = ice_vsi_setup_rx_rings(vsi); 4768c2ecf20Sopenharmony_ci if (status) 4778c2ecf20Sopenharmony_ci goto err_setup_rx_ring; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci status = ice_vsi_cfg(vsi); 4808c2ecf20Sopenharmony_ci if (status) 4818c2ecf20Sopenharmony_ci goto err_setup_rx_ring; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci status = ice_vsi_start_all_rx_rings(vsi); 4848c2ecf20Sopenharmony_ci if (status) 4858c2ecf20Sopenharmony_ci goto err_start_rx_ring; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return status; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cierr_start_rx_ring: 4908c2ecf20Sopenharmony_ci ice_vsi_free_rx_rings(vsi); 4918c2ecf20Sopenharmony_cierr_setup_rx_ring: 4928c2ecf20Sopenharmony_ci ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0); 4938c2ecf20Sopenharmony_cierr_setup_tx_ring: 4948c2ecf20Sopenharmony_ci ice_vsi_free_tx_rings(vsi); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci return status; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci/** 5008c2ecf20Sopenharmony_ci * ice_lbtest_disable_rings - disable Tx/Rx test rings after loopback test 5018c2ecf20Sopenharmony_ci * @vsi: pointer to the VSI structure 5028c2ecf20Sopenharmony_ci * 5038c2ecf20Sopenharmony_ci * Function stops and frees VSI rings after a loopback test. 5048c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure. 5058c2ecf20Sopenharmony_ci */ 5068c2ecf20Sopenharmony_cistatic int ice_lbtest_disable_rings(struct ice_vsi *vsi) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci int status; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci status = ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0); 5118c2ecf20Sopenharmony_ci if (status) 5128c2ecf20Sopenharmony_ci netdev_err(vsi->netdev, "Failed to stop Tx rings, VSI %d error %d\n", 5138c2ecf20Sopenharmony_ci vsi->vsi_num, status); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci status = ice_vsi_stop_all_rx_rings(vsi); 5168c2ecf20Sopenharmony_ci if (status) 5178c2ecf20Sopenharmony_ci netdev_err(vsi->netdev, "Failed to stop Rx rings, VSI %d error %d\n", 5188c2ecf20Sopenharmony_ci vsi->vsi_num, status); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci ice_vsi_free_tx_rings(vsi); 5218c2ecf20Sopenharmony_ci ice_vsi_free_rx_rings(vsi); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return status; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci/** 5278c2ecf20Sopenharmony_ci * ice_lbtest_create_frame - create test packet 5288c2ecf20Sopenharmony_ci * @pf: pointer to the PF structure 5298c2ecf20Sopenharmony_ci * @ret_data: allocated frame buffer 5308c2ecf20Sopenharmony_ci * @size: size of the packet data 5318c2ecf20Sopenharmony_ci * 5328c2ecf20Sopenharmony_ci * Function allocates a frame with a test pattern on specific offsets. 5338c2ecf20Sopenharmony_ci * Returns 0 on success, non-zero on failure. 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_cistatic int ice_lbtest_create_frame(struct ice_pf *pf, u8 **ret_data, u16 size) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci u8 *data; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (!pf) 5408c2ecf20Sopenharmony_ci return -EINVAL; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci data = devm_kzalloc(ice_pf_to_dev(pf), size, GFP_KERNEL); 5438c2ecf20Sopenharmony_ci if (!data) 5448c2ecf20Sopenharmony_ci return -ENOMEM; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* Since the ethernet test frame should always be at least 5478c2ecf20Sopenharmony_ci * 64 bytes long, fill some octets in the payload with test data. 5488c2ecf20Sopenharmony_ci */ 5498c2ecf20Sopenharmony_ci memset(data, 0xFF, size); 5508c2ecf20Sopenharmony_ci data[32] = 0xDE; 5518c2ecf20Sopenharmony_ci data[42] = 0xAD; 5528c2ecf20Sopenharmony_ci data[44] = 0xBE; 5538c2ecf20Sopenharmony_ci data[46] = 0xEF; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci *ret_data = data; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return 0; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci/** 5618c2ecf20Sopenharmony_ci * ice_lbtest_check_frame - verify received loopback frame 5628c2ecf20Sopenharmony_ci * @frame: pointer to the raw packet data 5638c2ecf20Sopenharmony_ci * 5648c2ecf20Sopenharmony_ci * Function verifies received test frame with a pattern. 5658c2ecf20Sopenharmony_ci * Returns true if frame matches the pattern, false otherwise. 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_cistatic bool ice_lbtest_check_frame(u8 *frame) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci /* Validate bytes of a frame under offsets chosen earlier */ 5708c2ecf20Sopenharmony_ci if (frame[32] == 0xDE && 5718c2ecf20Sopenharmony_ci frame[42] == 0xAD && 5728c2ecf20Sopenharmony_ci frame[44] == 0xBE && 5738c2ecf20Sopenharmony_ci frame[46] == 0xEF && 5748c2ecf20Sopenharmony_ci frame[48] == 0xFF) 5758c2ecf20Sopenharmony_ci return true; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return false; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci/** 5818c2ecf20Sopenharmony_ci * ice_diag_send - send test frames to the test ring 5828c2ecf20Sopenharmony_ci * @tx_ring: pointer to the transmit ring 5838c2ecf20Sopenharmony_ci * @data: pointer to the raw packet data 5848c2ecf20Sopenharmony_ci * @size: size of the packet to send 5858c2ecf20Sopenharmony_ci * 5868c2ecf20Sopenharmony_ci * Function sends loopback packets on a test Tx ring. 5878c2ecf20Sopenharmony_ci */ 5888c2ecf20Sopenharmony_cistatic int ice_diag_send(struct ice_ring *tx_ring, u8 *data, u16 size) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct ice_tx_desc *tx_desc; 5918c2ecf20Sopenharmony_ci struct ice_tx_buf *tx_buf; 5928c2ecf20Sopenharmony_ci dma_addr_t dma; 5938c2ecf20Sopenharmony_ci u64 td_cmd; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci tx_desc = ICE_TX_DESC(tx_ring, tx_ring->next_to_use); 5968c2ecf20Sopenharmony_ci tx_buf = &tx_ring->tx_buf[tx_ring->next_to_use]; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci dma = dma_map_single(tx_ring->dev, data, size, DMA_TO_DEVICE); 5998c2ecf20Sopenharmony_ci if (dma_mapping_error(tx_ring->dev, dma)) 6008c2ecf20Sopenharmony_ci return -EINVAL; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci tx_desc->buf_addr = cpu_to_le64(dma); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* These flags are required for a descriptor to be pushed out */ 6058c2ecf20Sopenharmony_ci td_cmd = (u64)(ICE_TX_DESC_CMD_EOP | ICE_TX_DESC_CMD_RS); 6068c2ecf20Sopenharmony_ci tx_desc->cmd_type_offset_bsz = 6078c2ecf20Sopenharmony_ci cpu_to_le64(ICE_TX_DESC_DTYPE_DATA | 6088c2ecf20Sopenharmony_ci (td_cmd << ICE_TXD_QW1_CMD_S) | 6098c2ecf20Sopenharmony_ci ((u64)0 << ICE_TXD_QW1_OFFSET_S) | 6108c2ecf20Sopenharmony_ci ((u64)size << ICE_TXD_QW1_TX_BUF_SZ_S) | 6118c2ecf20Sopenharmony_ci ((u64)0 << ICE_TXD_QW1_L2TAG1_S)); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci tx_buf->next_to_watch = tx_desc; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* Force memory write to complete before letting h/w know 6168c2ecf20Sopenharmony_ci * there are new descriptors to fetch. 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_ci wmb(); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci tx_ring->next_to_use++; 6218c2ecf20Sopenharmony_ci if (tx_ring->next_to_use >= tx_ring->count) 6228c2ecf20Sopenharmony_ci tx_ring->next_to_use = 0; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci writel_relaxed(tx_ring->next_to_use, tx_ring->tail); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* Wait until the packets get transmitted to the receive queue. */ 6278c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 6288c2ecf20Sopenharmony_ci dma_unmap_single(tx_ring->dev, dma, size, DMA_TO_DEVICE); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci#define ICE_LB_FRAME_SIZE 64 6348c2ecf20Sopenharmony_ci/** 6358c2ecf20Sopenharmony_ci * ice_lbtest_receive_frames - receive and verify test frames 6368c2ecf20Sopenharmony_ci * @rx_ring: pointer to the receive ring 6378c2ecf20Sopenharmony_ci * 6388c2ecf20Sopenharmony_ci * Function receives loopback packets and verify their correctness. 6398c2ecf20Sopenharmony_ci * Returns number of received valid frames. 6408c2ecf20Sopenharmony_ci */ 6418c2ecf20Sopenharmony_cistatic int ice_lbtest_receive_frames(struct ice_ring *rx_ring) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct ice_rx_buf *rx_buf; 6448c2ecf20Sopenharmony_ci int valid_frames, i; 6458c2ecf20Sopenharmony_ci u8 *received_buf; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci valid_frames = 0; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci for (i = 0; i < rx_ring->count; i++) { 6508c2ecf20Sopenharmony_ci union ice_32b_rx_flex_desc *rx_desc; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci rx_desc = ICE_RX_DESC(rx_ring, i); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (!(rx_desc->wb.status_error0 & 6558c2ecf20Sopenharmony_ci (cpu_to_le16(BIT(ICE_RX_FLEX_DESC_STATUS0_DD_S)) | 6568c2ecf20Sopenharmony_ci cpu_to_le16(BIT(ICE_RX_FLEX_DESC_STATUS0_EOF_S))))) 6578c2ecf20Sopenharmony_ci continue; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci rx_buf = &rx_ring->rx_buf[i]; 6608c2ecf20Sopenharmony_ci received_buf = page_address(rx_buf->page) + rx_buf->page_offset; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (ice_lbtest_check_frame(received_buf)) 6638c2ecf20Sopenharmony_ci valid_frames++; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci return valid_frames; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci/** 6708c2ecf20Sopenharmony_ci * ice_loopback_test - perform a loopback test on a given net_device 6718c2ecf20Sopenharmony_ci * @netdev: network interface device structure 6728c2ecf20Sopenharmony_ci * 6738c2ecf20Sopenharmony_ci * This function performs one of the self-tests required by ethtool. 6748c2ecf20Sopenharmony_ci * Returns 0 on success, non-zero on failure. 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_cistatic u64 ice_loopback_test(struct net_device *netdev) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 6798c2ecf20Sopenharmony_ci struct ice_vsi *orig_vsi = np->vsi, *test_vsi; 6808c2ecf20Sopenharmony_ci struct ice_pf *pf = orig_vsi->back; 6818c2ecf20Sopenharmony_ci struct ice_ring *tx_ring, *rx_ring; 6828c2ecf20Sopenharmony_ci u8 broadcast[ETH_ALEN], ret = 0; 6838c2ecf20Sopenharmony_ci int num_frames, valid_frames; 6848c2ecf20Sopenharmony_ci struct device *dev; 6858c2ecf20Sopenharmony_ci u8 *tx_frame; 6868c2ecf20Sopenharmony_ci int i; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 6898c2ecf20Sopenharmony_ci netdev_info(netdev, "loopback test\n"); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci test_vsi = ice_lb_vsi_setup(pf, pf->hw.port_info); 6928c2ecf20Sopenharmony_ci if (!test_vsi) { 6938c2ecf20Sopenharmony_ci netdev_err(netdev, "Failed to create a VSI for the loopback test\n"); 6948c2ecf20Sopenharmony_ci return 1; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci test_vsi->netdev = netdev; 6988c2ecf20Sopenharmony_ci tx_ring = test_vsi->tx_rings[0]; 6998c2ecf20Sopenharmony_ci rx_ring = test_vsi->rx_rings[0]; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (ice_lbtest_prepare_rings(test_vsi)) { 7028c2ecf20Sopenharmony_ci ret = 2; 7038c2ecf20Sopenharmony_ci goto lbtest_vsi_close; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (ice_alloc_rx_bufs(rx_ring, rx_ring->count)) { 7078c2ecf20Sopenharmony_ci ret = 3; 7088c2ecf20Sopenharmony_ci goto lbtest_rings_dis; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* Enable MAC loopback in firmware */ 7128c2ecf20Sopenharmony_ci if (ice_aq_set_mac_loopback(&pf->hw, true, NULL)) { 7138c2ecf20Sopenharmony_ci ret = 4; 7148c2ecf20Sopenharmony_ci goto lbtest_mac_dis; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* Test VSI needs to receive broadcast packets */ 7188c2ecf20Sopenharmony_ci eth_broadcast_addr(broadcast); 7198c2ecf20Sopenharmony_ci if (ice_fltr_add_mac(test_vsi, broadcast, ICE_FWD_TO_VSI)) { 7208c2ecf20Sopenharmony_ci ret = 5; 7218c2ecf20Sopenharmony_ci goto lbtest_mac_dis; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (ice_lbtest_create_frame(pf, &tx_frame, ICE_LB_FRAME_SIZE)) { 7258c2ecf20Sopenharmony_ci ret = 7; 7268c2ecf20Sopenharmony_ci goto remove_mac_filters; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci num_frames = min_t(int, tx_ring->count, 32); 7308c2ecf20Sopenharmony_ci for (i = 0; i < num_frames; i++) { 7318c2ecf20Sopenharmony_ci if (ice_diag_send(tx_ring, tx_frame, ICE_LB_FRAME_SIZE)) { 7328c2ecf20Sopenharmony_ci ret = 8; 7338c2ecf20Sopenharmony_ci goto lbtest_free_frame; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci valid_frames = ice_lbtest_receive_frames(rx_ring); 7388c2ecf20Sopenharmony_ci if (!valid_frames) 7398c2ecf20Sopenharmony_ci ret = 9; 7408c2ecf20Sopenharmony_ci else if (valid_frames != num_frames) 7418c2ecf20Sopenharmony_ci ret = 10; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cilbtest_free_frame: 7448c2ecf20Sopenharmony_ci devm_kfree(dev, tx_frame); 7458c2ecf20Sopenharmony_ciremove_mac_filters: 7468c2ecf20Sopenharmony_ci if (ice_fltr_remove_mac(test_vsi, broadcast, ICE_FWD_TO_VSI)) 7478c2ecf20Sopenharmony_ci netdev_err(netdev, "Could not remove MAC filter for the test VSI\n"); 7488c2ecf20Sopenharmony_cilbtest_mac_dis: 7498c2ecf20Sopenharmony_ci /* Disable MAC loopback after the test is completed. */ 7508c2ecf20Sopenharmony_ci if (ice_aq_set_mac_loopback(&pf->hw, false, NULL)) 7518c2ecf20Sopenharmony_ci netdev_err(netdev, "Could not disable MAC loopback\n"); 7528c2ecf20Sopenharmony_cilbtest_rings_dis: 7538c2ecf20Sopenharmony_ci if (ice_lbtest_disable_rings(test_vsi)) 7548c2ecf20Sopenharmony_ci netdev_err(netdev, "Could not disable test rings\n"); 7558c2ecf20Sopenharmony_cilbtest_vsi_close: 7568c2ecf20Sopenharmony_ci test_vsi->netdev = NULL; 7578c2ecf20Sopenharmony_ci if (ice_vsi_release(test_vsi)) 7588c2ecf20Sopenharmony_ci netdev_err(netdev, "Failed to remove the test VSI\n"); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci return ret; 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci/** 7648c2ecf20Sopenharmony_ci * ice_intr_test - perform an interrupt test on a given net_device 7658c2ecf20Sopenharmony_ci * @netdev: network interface device structure 7668c2ecf20Sopenharmony_ci * 7678c2ecf20Sopenharmony_ci * This function performs one of the self-tests required by ethtool. 7688c2ecf20Sopenharmony_ci * Returns 0 on success, non-zero on failure. 7698c2ecf20Sopenharmony_ci */ 7708c2ecf20Sopenharmony_cistatic u64 ice_intr_test(struct net_device *netdev) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 7738c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 7748c2ecf20Sopenharmony_ci u16 swic_old = pf->sw_int_count; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci netdev_info(netdev, "interrupt test\n"); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci wr32(&pf->hw, GLINT_DYN_CTL(pf->oicr_idx), 7798c2ecf20Sopenharmony_ci GLINT_DYN_CTL_SW_ITR_INDX_M | 7808c2ecf20Sopenharmony_ci GLINT_DYN_CTL_INTENA_MSK_M | 7818c2ecf20Sopenharmony_ci GLINT_DYN_CTL_SWINT_TRIG_M); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 7848c2ecf20Sopenharmony_ci return (swic_old == pf->sw_int_count); 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci/** 7888c2ecf20Sopenharmony_ci * ice_self_test - handler function for performing a self-test by ethtool 7898c2ecf20Sopenharmony_ci * @netdev: network interface device structure 7908c2ecf20Sopenharmony_ci * @eth_test: ethtool_test structure 7918c2ecf20Sopenharmony_ci * @data: required by ethtool.self_test 7928c2ecf20Sopenharmony_ci * 7938c2ecf20Sopenharmony_ci * This function is called after invoking 'ethtool -t devname' command where 7948c2ecf20Sopenharmony_ci * devname is the name of the network device on which ethtool should operate. 7958c2ecf20Sopenharmony_ci * It performs a set of self-tests to check if a device works properly. 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_cistatic void 7988c2ecf20Sopenharmony_ciice_self_test(struct net_device *netdev, struct ethtool_test *eth_test, 7998c2ecf20Sopenharmony_ci u64 *data) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 8028c2ecf20Sopenharmony_ci bool if_running = netif_running(netdev); 8038c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 8048c2ecf20Sopenharmony_ci struct device *dev; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (eth_test->flags == ETH_TEST_FL_OFFLINE) { 8098c2ecf20Sopenharmony_ci netdev_info(netdev, "offline testing starting\n"); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci set_bit(__ICE_TESTING, pf->state); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (ice_active_vfs(pf)) { 8148c2ecf20Sopenharmony_ci dev_warn(dev, "Please take active VFs and Netqueues offline and restart the adapter before running NIC diagnostics\n"); 8158c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_REG] = 1; 8168c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_EEPROM] = 1; 8178c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_INTR] = 1; 8188c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_LOOP] = 1; 8198c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_LINK] = 1; 8208c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 8218c2ecf20Sopenharmony_ci clear_bit(__ICE_TESTING, pf->state); 8228c2ecf20Sopenharmony_ci goto skip_ol_tests; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci /* If the device is online then take it offline */ 8258c2ecf20Sopenharmony_ci if (if_running) 8268c2ecf20Sopenharmony_ci /* indicate we're in test mode */ 8278c2ecf20Sopenharmony_ci ice_stop(netdev); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_LINK] = ice_link_test(netdev); 8308c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_EEPROM] = ice_eeprom_test(netdev); 8318c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_INTR] = ice_intr_test(netdev); 8328c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_LOOP] = ice_loopback_test(netdev); 8338c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_REG] = ice_reg_test(netdev); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci if (data[ICE_ETH_TEST_LINK] || 8368c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_EEPROM] || 8378c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_LOOP] || 8388c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_INTR] || 8398c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_REG]) 8408c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci clear_bit(__ICE_TESTING, pf->state); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (if_running) { 8458c2ecf20Sopenharmony_ci int status = ice_open(netdev); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (status) { 8488c2ecf20Sopenharmony_ci dev_err(dev, "Could not open device %s, err %d\n", 8498c2ecf20Sopenharmony_ci pf->int_name, status); 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci } else { 8538c2ecf20Sopenharmony_ci /* Online tests */ 8548c2ecf20Sopenharmony_ci netdev_info(netdev, "online testing starting\n"); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_LINK] = ice_link_test(netdev); 8578c2ecf20Sopenharmony_ci if (data[ICE_ETH_TEST_LINK]) 8588c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* Offline only tests, not run in online; pass by default */ 8618c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_REG] = 0; 8628c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_EEPROM] = 0; 8638c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_INTR] = 0; 8648c2ecf20Sopenharmony_ci data[ICE_ETH_TEST_LOOP] = 0; 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ciskip_ol_tests: 8688c2ecf20Sopenharmony_ci netdev_info(netdev, "testing finished\n"); 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_cistatic void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 8748c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 8758c2ecf20Sopenharmony_ci char *p = (char *)data; 8768c2ecf20Sopenharmony_ci unsigned int i; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci switch (stringset) { 8798c2ecf20Sopenharmony_ci case ETH_SS_STATS: 8808c2ecf20Sopenharmony_ci for (i = 0; i < ICE_VSI_STATS_LEN; i++) { 8818c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, "%s", 8828c2ecf20Sopenharmony_ci ice_gstrings_vsi_stats[i].stat_string); 8838c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci ice_for_each_alloc_txq(vsi, i) { 8878c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, 8888c2ecf20Sopenharmony_ci "tx_queue_%u_packets", i); 8898c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 8908c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, "tx_queue_%u_bytes", i); 8918c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci ice_for_each_alloc_rxq(vsi, i) { 8958c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, 8968c2ecf20Sopenharmony_ci "rx_queue_%u_packets", i); 8978c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 8988c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_bytes", i); 8998c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_PF) 9038c2ecf20Sopenharmony_ci return; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci for (i = 0; i < ICE_PF_STATS_LEN; i++) { 9068c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, "%s", 9078c2ecf20Sopenharmony_ci ice_gstrings_pf_stats[i].stat_string); 9088c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) { 9128c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, 9138c2ecf20Sopenharmony_ci "tx_priority_%u_xon.nic", i); 9148c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 9158c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, 9168c2ecf20Sopenharmony_ci "tx_priority_%u_xoff.nic", i); 9178c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) { 9208c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, 9218c2ecf20Sopenharmony_ci "rx_priority_%u_xon.nic", i); 9228c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 9238c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, 9248c2ecf20Sopenharmony_ci "rx_priority_%u_xoff.nic", i); 9258c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci break; 9288c2ecf20Sopenharmony_ci case ETH_SS_TEST: 9298c2ecf20Sopenharmony_ci memcpy(data, ice_gstrings_test, ICE_TEST_LEN * ETH_GSTRING_LEN); 9308c2ecf20Sopenharmony_ci break; 9318c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 9328c2ecf20Sopenharmony_ci for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) { 9338c2ecf20Sopenharmony_ci snprintf(p, ETH_GSTRING_LEN, "%s", 9348c2ecf20Sopenharmony_ci ice_gstrings_priv_flags[i].name); 9358c2ecf20Sopenharmony_ci p += ETH_GSTRING_LEN; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci break; 9388c2ecf20Sopenharmony_ci default: 9398c2ecf20Sopenharmony_ci break; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic int 9448c2ecf20Sopenharmony_ciice_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 9478c2ecf20Sopenharmony_ci bool led_active; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci switch (state) { 9508c2ecf20Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 9518c2ecf20Sopenharmony_ci led_active = true; 9528c2ecf20Sopenharmony_ci break; 9538c2ecf20Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 9548c2ecf20Sopenharmony_ci led_active = false; 9558c2ecf20Sopenharmony_ci break; 9568c2ecf20Sopenharmony_ci default: 9578c2ecf20Sopenharmony_ci return -EINVAL; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (ice_aq_set_port_id_led(np->vsi->port_info, !led_active, NULL)) 9618c2ecf20Sopenharmony_ci return -EIO; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci return 0; 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci/** 9678c2ecf20Sopenharmony_ci * ice_set_fec_cfg - Set link FEC options 9688c2ecf20Sopenharmony_ci * @netdev: network interface device structure 9698c2ecf20Sopenharmony_ci * @req_fec: FEC mode to configure 9708c2ecf20Sopenharmony_ci */ 9718c2ecf20Sopenharmony_cistatic int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 9748c2ecf20Sopenharmony_ci struct ice_aqc_set_phy_cfg_data config = { 0 }; 9758c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 9768c2ecf20Sopenharmony_ci struct ice_port_info *pi; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci pi = vsi->port_info; 9798c2ecf20Sopenharmony_ci if (!pi) 9808c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* Changing the FEC parameters is not supported if not the PF VSI */ 9838c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_PF) { 9848c2ecf20Sopenharmony_ci netdev_info(netdev, "Changing FEC parameters only supported for PF VSI\n"); 9858c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* Proceed only if requesting different FEC mode */ 9898c2ecf20Sopenharmony_ci if (pi->phy.curr_user_fec_req == req_fec) 9908c2ecf20Sopenharmony_ci return 0; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* Copy the current user PHY configuration. The current user PHY 9938c2ecf20Sopenharmony_ci * configuration is initialized during probe from PHY capabilities 9948c2ecf20Sopenharmony_ci * software mode, and updated on set PHY configuration. 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_ci memcpy(&config, &pi->phy.curr_user_phy_cfg, sizeof(config)); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci ice_cfg_phy_fec(pi, &config, req_fec); 9998c2ecf20Sopenharmony_ci config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (ice_aq_set_phy_cfg(pi->hw, pi, &config, NULL)) 10028c2ecf20Sopenharmony_ci return -EAGAIN; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci /* Save requested FEC config */ 10058c2ecf20Sopenharmony_ci pi->phy.curr_user_fec_req = req_fec; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci return 0; 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci/** 10118c2ecf20Sopenharmony_ci * ice_set_fecparam - Set FEC link options 10128c2ecf20Sopenharmony_ci * @netdev: network interface device structure 10138c2ecf20Sopenharmony_ci * @fecparam: Ethtool structure to retrieve FEC parameters 10148c2ecf20Sopenharmony_ci */ 10158c2ecf20Sopenharmony_cistatic int 10168c2ecf20Sopenharmony_ciice_set_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam) 10178c2ecf20Sopenharmony_ci{ 10188c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 10198c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 10208c2ecf20Sopenharmony_ci enum ice_fec_mode fec; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci switch (fecparam->fec) { 10238c2ecf20Sopenharmony_ci case ETHTOOL_FEC_AUTO: 10248c2ecf20Sopenharmony_ci fec = ICE_FEC_AUTO; 10258c2ecf20Sopenharmony_ci break; 10268c2ecf20Sopenharmony_ci case ETHTOOL_FEC_RS: 10278c2ecf20Sopenharmony_ci fec = ICE_FEC_RS; 10288c2ecf20Sopenharmony_ci break; 10298c2ecf20Sopenharmony_ci case ETHTOOL_FEC_BASER: 10308c2ecf20Sopenharmony_ci fec = ICE_FEC_BASER; 10318c2ecf20Sopenharmony_ci break; 10328c2ecf20Sopenharmony_ci case ETHTOOL_FEC_OFF: 10338c2ecf20Sopenharmony_ci case ETHTOOL_FEC_NONE: 10348c2ecf20Sopenharmony_ci fec = ICE_FEC_NONE; 10358c2ecf20Sopenharmony_ci break; 10368c2ecf20Sopenharmony_ci default: 10378c2ecf20Sopenharmony_ci dev_warn(ice_pf_to_dev(vsi->back), "Unsupported FEC mode: %d\n", 10388c2ecf20Sopenharmony_ci fecparam->fec); 10398c2ecf20Sopenharmony_ci return -EINVAL; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci return ice_set_fec_cfg(netdev, fec); 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci/** 10468c2ecf20Sopenharmony_ci * ice_get_fecparam - Get link FEC options 10478c2ecf20Sopenharmony_ci * @netdev: network interface device structure 10488c2ecf20Sopenharmony_ci * @fecparam: Ethtool structure to retrieve FEC parameters 10498c2ecf20Sopenharmony_ci */ 10508c2ecf20Sopenharmony_cistatic int 10518c2ecf20Sopenharmony_ciice_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 10548c2ecf20Sopenharmony_ci struct ice_aqc_get_phy_caps_data *caps; 10558c2ecf20Sopenharmony_ci struct ice_link_status *link_info; 10568c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 10578c2ecf20Sopenharmony_ci struct ice_port_info *pi; 10588c2ecf20Sopenharmony_ci enum ice_status status; 10598c2ecf20Sopenharmony_ci int err = 0; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci pi = vsi->port_info; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (!pi) 10648c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10658c2ecf20Sopenharmony_ci link_info = &pi->phy.link_info; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci /* Set FEC mode based on negotiated link info */ 10688c2ecf20Sopenharmony_ci switch (link_info->fec_info) { 10698c2ecf20Sopenharmony_ci case ICE_AQ_LINK_25G_KR_FEC_EN: 10708c2ecf20Sopenharmony_ci fecparam->active_fec = ETHTOOL_FEC_BASER; 10718c2ecf20Sopenharmony_ci break; 10728c2ecf20Sopenharmony_ci case ICE_AQ_LINK_25G_RS_528_FEC_EN: 10738c2ecf20Sopenharmony_ci case ICE_AQ_LINK_25G_RS_544_FEC_EN: 10748c2ecf20Sopenharmony_ci fecparam->active_fec = ETHTOOL_FEC_RS; 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci default: 10778c2ecf20Sopenharmony_ci fecparam->active_fec = ETHTOOL_FEC_OFF; 10788c2ecf20Sopenharmony_ci break; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci caps = kzalloc(sizeof(*caps), GFP_KERNEL); 10828c2ecf20Sopenharmony_ci if (!caps) 10838c2ecf20Sopenharmony_ci return -ENOMEM; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA, 10868c2ecf20Sopenharmony_ci caps, NULL); 10878c2ecf20Sopenharmony_ci if (status) { 10888c2ecf20Sopenharmony_ci err = -EAGAIN; 10898c2ecf20Sopenharmony_ci goto done; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci /* Set supported/configured FEC modes based on PHY capability */ 10938c2ecf20Sopenharmony_ci if (caps->caps & ICE_AQC_PHY_EN_AUTO_FEC) 10948c2ecf20Sopenharmony_ci fecparam->fec |= ETHTOOL_FEC_AUTO; 10958c2ecf20Sopenharmony_ci if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN || 10968c2ecf20Sopenharmony_ci caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ || 10978c2ecf20Sopenharmony_ci caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN || 10988c2ecf20Sopenharmony_ci caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ) 10998c2ecf20Sopenharmony_ci fecparam->fec |= ETHTOOL_FEC_BASER; 11008c2ecf20Sopenharmony_ci if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ || 11018c2ecf20Sopenharmony_ci caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ || 11028c2ecf20Sopenharmony_ci caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN) 11038c2ecf20Sopenharmony_ci fecparam->fec |= ETHTOOL_FEC_RS; 11048c2ecf20Sopenharmony_ci if (caps->link_fec_options == 0) 11058c2ecf20Sopenharmony_ci fecparam->fec |= ETHTOOL_FEC_OFF; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cidone: 11088c2ecf20Sopenharmony_ci kfree(caps); 11098c2ecf20Sopenharmony_ci return err; 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci/** 11138c2ecf20Sopenharmony_ci * ice_nway_reset - restart autonegotiation 11148c2ecf20Sopenharmony_ci * @netdev: network interface device structure 11158c2ecf20Sopenharmony_ci */ 11168c2ecf20Sopenharmony_cistatic int ice_nway_reset(struct net_device *netdev) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 11198c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 11208c2ecf20Sopenharmony_ci struct ice_port_info *pi; 11218c2ecf20Sopenharmony_ci enum ice_status status; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci pi = vsi->port_info; 11248c2ecf20Sopenharmony_ci /* If VSI state is up, then restart autoneg with link up */ 11258c2ecf20Sopenharmony_ci if (!test_bit(__ICE_DOWN, vsi->back->state)) 11268c2ecf20Sopenharmony_ci status = ice_aq_set_link_restart_an(pi, true, NULL); 11278c2ecf20Sopenharmony_ci else 11288c2ecf20Sopenharmony_ci status = ice_aq_set_link_restart_an(pi, false, NULL); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci if (status) { 11318c2ecf20Sopenharmony_ci netdev_info(netdev, "link restart failed, err %s aq_err %s\n", 11328c2ecf20Sopenharmony_ci ice_stat_str(status), 11338c2ecf20Sopenharmony_ci ice_aq_str(pi->hw->adminq.sq_last_status)); 11348c2ecf20Sopenharmony_ci return -EIO; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci return 0; 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci/** 11418c2ecf20Sopenharmony_ci * ice_get_priv_flags - report device private flags 11428c2ecf20Sopenharmony_ci * @netdev: network interface device structure 11438c2ecf20Sopenharmony_ci * 11448c2ecf20Sopenharmony_ci * The get string set count and the string set should be matched for each 11458c2ecf20Sopenharmony_ci * flag returned. Add new strings for each flag to the ice_gstrings_priv_flags 11468c2ecf20Sopenharmony_ci * array. 11478c2ecf20Sopenharmony_ci * 11488c2ecf20Sopenharmony_ci * Returns a u32 bitmap of flags. 11498c2ecf20Sopenharmony_ci */ 11508c2ecf20Sopenharmony_cistatic u32 ice_get_priv_flags(struct net_device *netdev) 11518c2ecf20Sopenharmony_ci{ 11528c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 11538c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 11548c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 11558c2ecf20Sopenharmony_ci u32 i, ret_flags = 0; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) { 11588c2ecf20Sopenharmony_ci const struct ice_priv_flag *priv_flag; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci priv_flag = &ice_gstrings_priv_flags[i]; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (test_bit(priv_flag->bitno, pf->flags)) 11638c2ecf20Sopenharmony_ci ret_flags |= BIT(i); 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci return ret_flags; 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci/** 11708c2ecf20Sopenharmony_ci * ice_set_priv_flags - set private flags 11718c2ecf20Sopenharmony_ci * @netdev: network interface device structure 11728c2ecf20Sopenharmony_ci * @flags: bit flags to be set 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_cistatic int ice_set_priv_flags(struct net_device *netdev, u32 flags) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 11778c2ecf20Sopenharmony_ci DECLARE_BITMAP(change_flags, ICE_PF_FLAGS_NBITS); 11788c2ecf20Sopenharmony_ci DECLARE_BITMAP(orig_flags, ICE_PF_FLAGS_NBITS); 11798c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 11808c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 11818c2ecf20Sopenharmony_ci struct device *dev; 11828c2ecf20Sopenharmony_ci int ret = 0; 11838c2ecf20Sopenharmony_ci u32 i; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci if (flags > BIT(ICE_PRIV_FLAG_ARRAY_SIZE)) 11868c2ecf20Sopenharmony_ci return -EINVAL; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 11898c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_ETHTOOL_CTXT, pf->flags); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci bitmap_copy(orig_flags, pf->flags, ICE_PF_FLAGS_NBITS); 11928c2ecf20Sopenharmony_ci for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) { 11938c2ecf20Sopenharmony_ci const struct ice_priv_flag *priv_flag; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci priv_flag = &ice_gstrings_priv_flags[i]; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci if (flags & BIT(i)) 11988c2ecf20Sopenharmony_ci set_bit(priv_flag->bitno, pf->flags); 11998c2ecf20Sopenharmony_ci else 12008c2ecf20Sopenharmony_ci clear_bit(priv_flag->bitno, pf->flags); 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci bitmap_xor(change_flags, pf->flags, orig_flags, ICE_PF_FLAGS_NBITS); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci /* Do not allow change to link-down-on-close when Total Port Shutdown 12068c2ecf20Sopenharmony_ci * is enabled. 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, change_flags) && 12098c2ecf20Sopenharmony_ci test_bit(ICE_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags)) { 12108c2ecf20Sopenharmony_ci dev_err(dev, "Setting link-down-on-close not supported on this port\n"); 12118c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags); 12128c2ecf20Sopenharmony_ci ret = -EINVAL; 12138c2ecf20Sopenharmony_ci goto ethtool_exit; 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_FW_LLDP_AGENT, change_flags)) { 12178c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags)) { 12188c2ecf20Sopenharmony_ci enum ice_status status; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci /* Disable FW LLDP engine */ 12218c2ecf20Sopenharmony_ci status = ice_cfg_lldp_mib_change(&pf->hw, false); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci /* If unregistering for LLDP events fails, this is 12248c2ecf20Sopenharmony_ci * not an error state, as there shouldn't be any 12258c2ecf20Sopenharmony_ci * events to respond to. 12268c2ecf20Sopenharmony_ci */ 12278c2ecf20Sopenharmony_ci if (status) 12288c2ecf20Sopenharmony_ci dev_info(dev, "Failed to unreg for LLDP events\n"); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* The AQ call to stop the FW LLDP agent will generate 12318c2ecf20Sopenharmony_ci * an error if the agent is already stopped. 12328c2ecf20Sopenharmony_ci */ 12338c2ecf20Sopenharmony_ci status = ice_aq_stop_lldp(&pf->hw, true, true, NULL); 12348c2ecf20Sopenharmony_ci if (status) 12358c2ecf20Sopenharmony_ci dev_warn(dev, "Fail to stop LLDP agent\n"); 12368c2ecf20Sopenharmony_ci /* Use case for having the FW LLDP agent stopped 12378c2ecf20Sopenharmony_ci * will likely not need DCB, so failure to init is 12388c2ecf20Sopenharmony_ci * not a concern of ethtool 12398c2ecf20Sopenharmony_ci */ 12408c2ecf20Sopenharmony_ci status = ice_init_pf_dcb(pf, true); 12418c2ecf20Sopenharmony_ci if (status) 12428c2ecf20Sopenharmony_ci dev_warn(dev, "Fail to init DCB\n"); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci pf->dcbx_cap &= ~DCB_CAP_DCBX_LLD_MANAGED; 12458c2ecf20Sopenharmony_ci pf->dcbx_cap |= DCB_CAP_DCBX_HOST; 12468c2ecf20Sopenharmony_ci } else { 12478c2ecf20Sopenharmony_ci enum ice_status status; 12488c2ecf20Sopenharmony_ci bool dcbx_agent_status; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* AQ command to start FW LLDP agent will return an 12518c2ecf20Sopenharmony_ci * error if the agent is already started 12528c2ecf20Sopenharmony_ci */ 12538c2ecf20Sopenharmony_ci status = ice_aq_start_lldp(&pf->hw, true, NULL); 12548c2ecf20Sopenharmony_ci if (status) 12558c2ecf20Sopenharmony_ci dev_warn(dev, "Fail to start LLDP Agent\n"); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci /* AQ command to start FW DCBX agent will fail if 12588c2ecf20Sopenharmony_ci * the agent is already started 12598c2ecf20Sopenharmony_ci */ 12608c2ecf20Sopenharmony_ci status = ice_aq_start_stop_dcbx(&pf->hw, true, 12618c2ecf20Sopenharmony_ci &dcbx_agent_status, 12628c2ecf20Sopenharmony_ci NULL); 12638c2ecf20Sopenharmony_ci if (status) 12648c2ecf20Sopenharmony_ci dev_dbg(dev, "Failed to start FW DCBX\n"); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci dev_info(dev, "FW DCBX agent is %s\n", 12678c2ecf20Sopenharmony_ci dcbx_agent_status ? "ACTIVE" : "DISABLED"); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci /* Failure to configure MIB change or init DCB is not 12708c2ecf20Sopenharmony_ci * relevant to ethtool. Print notification that 12718c2ecf20Sopenharmony_ci * registration/init failed but do not return error 12728c2ecf20Sopenharmony_ci * state to ethtool 12738c2ecf20Sopenharmony_ci */ 12748c2ecf20Sopenharmony_ci status = ice_init_pf_dcb(pf, true); 12758c2ecf20Sopenharmony_ci if (status) 12768c2ecf20Sopenharmony_ci dev_dbg(dev, "Fail to init DCB\n"); 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci /* Remove rule to direct LLDP packets to default VSI. 12798c2ecf20Sopenharmony_ci * The FW LLDP engine will now be consuming them. 12808c2ecf20Sopenharmony_ci */ 12818c2ecf20Sopenharmony_ci ice_cfg_sw_lldp(vsi, false, false); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* Register for MIB change events */ 12848c2ecf20Sopenharmony_ci status = ice_cfg_lldp_mib_change(&pf->hw, true); 12858c2ecf20Sopenharmony_ci if (status) 12868c2ecf20Sopenharmony_ci dev_dbg(dev, "Fail to enable MIB change events\n"); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci pf->dcbx_cap &= ~DCB_CAP_DCBX_HOST; 12898c2ecf20Sopenharmony_ci pf->dcbx_cap |= DCB_CAP_DCBX_LLD_MANAGED; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci ice_nway_reset(netdev); 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_LEGACY_RX, change_flags)) { 12958c2ecf20Sopenharmony_ci /* down and up VSI so that changes of Rx cfg are reflected. */ 12968c2ecf20Sopenharmony_ci ice_down(vsi); 12978c2ecf20Sopenharmony_ci ice_up(vsi); 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci /* don't allow modification of this flag when a single VF is in 13008c2ecf20Sopenharmony_ci * promiscuous mode because it's not supported 13018c2ecf20Sopenharmony_ci */ 13028c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, change_flags) && 13038c2ecf20Sopenharmony_ci ice_is_any_vf_in_promisc(pf)) { 13048c2ecf20Sopenharmony_ci dev_err(dev, "Changing vf-true-promisc-support flag while VF(s) are in promiscuous mode not supported\n"); 13058c2ecf20Sopenharmony_ci /* toggle bit back to previous state */ 13068c2ecf20Sopenharmony_ci change_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, pf->flags); 13078c2ecf20Sopenharmony_ci ret = -EAGAIN; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ciethtool_exit: 13108c2ecf20Sopenharmony_ci clear_bit(ICE_FLAG_ETHTOOL_CTXT, pf->flags); 13118c2ecf20Sopenharmony_ci return ret; 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_cistatic int ice_get_sset_count(struct net_device *netdev, int sset) 13158c2ecf20Sopenharmony_ci{ 13168c2ecf20Sopenharmony_ci switch (sset) { 13178c2ecf20Sopenharmony_ci case ETH_SS_STATS: 13188c2ecf20Sopenharmony_ci /* The number (and order) of strings reported *must* remain 13198c2ecf20Sopenharmony_ci * constant for a given netdevice. This function must not 13208c2ecf20Sopenharmony_ci * report a different number based on run time parameters 13218c2ecf20Sopenharmony_ci * (such as the number of queues in use, or the setting of 13228c2ecf20Sopenharmony_ci * a private ethtool flag). This is due to the nature of the 13238c2ecf20Sopenharmony_ci * ethtool stats API. 13248c2ecf20Sopenharmony_ci * 13258c2ecf20Sopenharmony_ci * Userspace programs such as ethtool must make 3 separate 13268c2ecf20Sopenharmony_ci * ioctl requests, one for size, one for the strings, and 13278c2ecf20Sopenharmony_ci * finally one for the stats. Since these cross into 13288c2ecf20Sopenharmony_ci * userspace, changes to the number or size could result in 13298c2ecf20Sopenharmony_ci * undefined memory access or incorrect string<->value 13308c2ecf20Sopenharmony_ci * correlations for statistics. 13318c2ecf20Sopenharmony_ci * 13328c2ecf20Sopenharmony_ci * Even if it appears to be safe, changes to the size or 13338c2ecf20Sopenharmony_ci * order of strings will suffer from race conditions and are 13348c2ecf20Sopenharmony_ci * not safe. 13358c2ecf20Sopenharmony_ci */ 13368c2ecf20Sopenharmony_ci return ICE_ALL_STATS_LEN(netdev); 13378c2ecf20Sopenharmony_ci case ETH_SS_TEST: 13388c2ecf20Sopenharmony_ci return ICE_TEST_LEN; 13398c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 13408c2ecf20Sopenharmony_ci return ICE_PRIV_FLAG_ARRAY_SIZE; 13418c2ecf20Sopenharmony_ci default: 13428c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci} 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_cistatic void 13478c2ecf20Sopenharmony_ciice_get_ethtool_stats(struct net_device *netdev, 13488c2ecf20Sopenharmony_ci struct ethtool_stats __always_unused *stats, u64 *data) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 13518c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 13528c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 13538c2ecf20Sopenharmony_ci struct ice_ring *ring; 13548c2ecf20Sopenharmony_ci unsigned int j; 13558c2ecf20Sopenharmony_ci int i = 0; 13568c2ecf20Sopenharmony_ci char *p; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci ice_update_pf_stats(pf); 13598c2ecf20Sopenharmony_ci ice_update_vsi_stats(vsi); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci for (j = 0; j < ICE_VSI_STATS_LEN; j++) { 13628c2ecf20Sopenharmony_ci p = (char *)vsi + ice_gstrings_vsi_stats[j].stat_offset; 13638c2ecf20Sopenharmony_ci data[i++] = (ice_gstrings_vsi_stats[j].sizeof_stat == 13648c2ecf20Sopenharmony_ci sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci /* populate per queue stats */ 13688c2ecf20Sopenharmony_ci rcu_read_lock(); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci ice_for_each_alloc_txq(vsi, j) { 13718c2ecf20Sopenharmony_ci ring = READ_ONCE(vsi->tx_rings[j]); 13728c2ecf20Sopenharmony_ci if (ring) { 13738c2ecf20Sopenharmony_ci data[i++] = ring->stats.pkts; 13748c2ecf20Sopenharmony_ci data[i++] = ring->stats.bytes; 13758c2ecf20Sopenharmony_ci } else { 13768c2ecf20Sopenharmony_ci data[i++] = 0; 13778c2ecf20Sopenharmony_ci data[i++] = 0; 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci ice_for_each_alloc_rxq(vsi, j) { 13828c2ecf20Sopenharmony_ci ring = READ_ONCE(vsi->rx_rings[j]); 13838c2ecf20Sopenharmony_ci if (ring) { 13848c2ecf20Sopenharmony_ci data[i++] = ring->stats.pkts; 13858c2ecf20Sopenharmony_ci data[i++] = ring->stats.bytes; 13868c2ecf20Sopenharmony_ci } else { 13878c2ecf20Sopenharmony_ci data[i++] = 0; 13888c2ecf20Sopenharmony_ci data[i++] = 0; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci rcu_read_unlock(); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_PF) 13958c2ecf20Sopenharmony_ci return; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci for (j = 0; j < ICE_PF_STATS_LEN; j++) { 13988c2ecf20Sopenharmony_ci p = (char *)pf + ice_gstrings_pf_stats[j].stat_offset; 13998c2ecf20Sopenharmony_ci data[i++] = (ice_gstrings_pf_stats[j].sizeof_stat == 14008c2ecf20Sopenharmony_ci sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 14018c2ecf20Sopenharmony_ci } 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci for (j = 0; j < ICE_MAX_USER_PRIORITY; j++) { 14048c2ecf20Sopenharmony_ci data[i++] = pf->stats.priority_xon_tx[j]; 14058c2ecf20Sopenharmony_ci data[i++] = pf->stats.priority_xoff_tx[j]; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci for (j = 0; j < ICE_MAX_USER_PRIORITY; j++) { 14098c2ecf20Sopenharmony_ci data[i++] = pf->stats.priority_xon_rx[j]; 14108c2ecf20Sopenharmony_ci data[i++] = pf->stats.priority_xoff_rx[j]; 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci#define ICE_PHY_TYPE_LOW_MASK_MIN_1G (ICE_PHY_TYPE_LOW_100BASE_TX | \ 14158c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100M_SGMII) 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci#define ICE_PHY_TYPE_LOW_MASK_MIN_25G (ICE_PHY_TYPE_LOW_MASK_MIN_1G | \ 14188c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_1000BASE_T | \ 14198c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_1000BASE_SX | \ 14208c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_1000BASE_LX | \ 14218c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_1000BASE_KX | \ 14228c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_1G_SGMII | \ 14238c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_2500BASE_T | \ 14248c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_2500BASE_X | \ 14258c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_2500BASE_KX | \ 14268c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_5GBASE_T | \ 14278c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_5GBASE_KR | \ 14288c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_10GBASE_T | \ 14298c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_10G_SFI_DA | \ 14308c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_10GBASE_SR | \ 14318c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_10GBASE_LR | \ 14328c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_10GBASE_KR_CR1 | \ 14338c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC | \ 14348c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_10G_SFI_C2C) 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci#define ICE_PHY_TYPE_LOW_MASK_100G (ICE_PHY_TYPE_LOW_100GBASE_CR4 | \ 14378c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_SR4 | \ 14388c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_LR4 | \ 14398c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_KR4 | \ 14408c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100G_CAUI4_AOC_ACC | \ 14418c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100G_CAUI4 | \ 14428c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100G_AUI4_AOC_ACC | \ 14438c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100G_AUI4 | \ 14448c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4 | \ 14458c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4 | \ 14468c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_CP2 | \ 14478c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_SR2 | \ 14488c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_DR) 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci#define ICE_PHY_TYPE_HIGH_MASK_100G (ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4 | \ 14518c2ecf20Sopenharmony_ci ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC |\ 14528c2ecf20Sopenharmony_ci ICE_PHY_TYPE_HIGH_100G_CAUI2 | \ 14538c2ecf20Sopenharmony_ci ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC | \ 14548c2ecf20Sopenharmony_ci ICE_PHY_TYPE_HIGH_100G_AUI2) 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci/** 14578c2ecf20Sopenharmony_ci * ice_mask_min_supported_speeds 14588c2ecf20Sopenharmony_ci * @phy_types_high: PHY type high 14598c2ecf20Sopenharmony_ci * @phy_types_low: PHY type low to apply minimum supported speeds mask 14608c2ecf20Sopenharmony_ci * 14618c2ecf20Sopenharmony_ci * Apply minimum supported speeds mask to PHY type low. These are the speeds 14628c2ecf20Sopenharmony_ci * for ethtool supported link mode. 14638c2ecf20Sopenharmony_ci */ 14648c2ecf20Sopenharmony_cistatic 14658c2ecf20Sopenharmony_civoid ice_mask_min_supported_speeds(u64 phy_types_high, u64 *phy_types_low) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci /* if QSFP connection with 100G speed, minimum supported speed is 25G */ 14688c2ecf20Sopenharmony_ci if (*phy_types_low & ICE_PHY_TYPE_LOW_MASK_100G || 14698c2ecf20Sopenharmony_ci phy_types_high & ICE_PHY_TYPE_HIGH_MASK_100G) 14708c2ecf20Sopenharmony_ci *phy_types_low &= ~ICE_PHY_TYPE_LOW_MASK_MIN_25G; 14718c2ecf20Sopenharmony_ci else 14728c2ecf20Sopenharmony_ci *phy_types_low &= ~ICE_PHY_TYPE_LOW_MASK_MIN_1G; 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci#define ice_ethtool_advertise_link_mode(aq_link_speed, ethtool_link_mode) \ 14768c2ecf20Sopenharmony_ci do { \ 14778c2ecf20Sopenharmony_ci if (req_speeds & (aq_link_speed) || \ 14788c2ecf20Sopenharmony_ci (!req_speeds && \ 14798c2ecf20Sopenharmony_ci (adv_phy_type_lo & phy_type_mask_lo || \ 14808c2ecf20Sopenharmony_ci adv_phy_type_hi & phy_type_mask_hi))) \ 14818c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising,\ 14828c2ecf20Sopenharmony_ci ethtool_link_mode); \ 14838c2ecf20Sopenharmony_ci } while (0) 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci/** 14868c2ecf20Sopenharmony_ci * ice_phy_type_to_ethtool - convert the phy_types to ethtool link modes 14878c2ecf20Sopenharmony_ci * @netdev: network interface device structure 14888c2ecf20Sopenharmony_ci * @ks: ethtool link ksettings struct to fill out 14898c2ecf20Sopenharmony_ci */ 14908c2ecf20Sopenharmony_cistatic void 14918c2ecf20Sopenharmony_ciice_phy_type_to_ethtool(struct net_device *netdev, 14928c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *ks) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 14958c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 14968c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 14978c2ecf20Sopenharmony_ci u64 phy_type_mask_lo = 0; 14988c2ecf20Sopenharmony_ci u64 phy_type_mask_hi = 0; 14998c2ecf20Sopenharmony_ci u64 adv_phy_type_lo = 0; 15008c2ecf20Sopenharmony_ci u64 adv_phy_type_hi = 0; 15018c2ecf20Sopenharmony_ci u64 phy_types_high = 0; 15028c2ecf20Sopenharmony_ci u64 phy_types_low = 0; 15038c2ecf20Sopenharmony_ci u16 req_speeds; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci req_speeds = vsi->port_info->phy.link_info.req_speeds; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci /* Check if lenient mode is supported and enabled, or in strict mode. 15088c2ecf20Sopenharmony_ci * 15098c2ecf20Sopenharmony_ci * In lenient mode the Supported link modes are the PHY types without 15108c2ecf20Sopenharmony_ci * media. The Advertising link mode is either 1. the user requested 15118c2ecf20Sopenharmony_ci * speed, 2. the override PHY mask, or 3. the PHY types with media. 15128c2ecf20Sopenharmony_ci * 15138c2ecf20Sopenharmony_ci * In strict mode Supported link mode are the PHY type with media, 15148c2ecf20Sopenharmony_ci * and Advertising link modes are the media PHY type or the speed 15158c2ecf20Sopenharmony_ci * requested by user. 15168c2ecf20Sopenharmony_ci */ 15178c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) { 15188c2ecf20Sopenharmony_ci struct ice_link_default_override_tlv *ldo; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci ldo = &pf->link_dflt_override; 15218c2ecf20Sopenharmony_ci phy_types_low = le64_to_cpu(pf->nvm_phy_type_lo); 15228c2ecf20Sopenharmony_ci phy_types_high = le64_to_cpu(pf->nvm_phy_type_hi); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci ice_mask_min_supported_speeds(phy_types_high, &phy_types_low); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* If override enabled and PHY mask set, then 15278c2ecf20Sopenharmony_ci * Advertising link mode is the intersection of the PHY 15288c2ecf20Sopenharmony_ci * types without media and the override PHY mask. 15298c2ecf20Sopenharmony_ci */ 15308c2ecf20Sopenharmony_ci if (ldo->options & ICE_LINK_OVERRIDE_EN && 15318c2ecf20Sopenharmony_ci (ldo->phy_type_low || ldo->phy_type_high)) { 15328c2ecf20Sopenharmony_ci adv_phy_type_lo = 15338c2ecf20Sopenharmony_ci le64_to_cpu(pf->nvm_phy_type_lo) & 15348c2ecf20Sopenharmony_ci ldo->phy_type_low; 15358c2ecf20Sopenharmony_ci adv_phy_type_hi = 15368c2ecf20Sopenharmony_ci le64_to_cpu(pf->nvm_phy_type_hi) & 15378c2ecf20Sopenharmony_ci ldo->phy_type_high; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci } else { 15408c2ecf20Sopenharmony_ci phy_types_low = vsi->port_info->phy.phy_type_low; 15418c2ecf20Sopenharmony_ci phy_types_high = vsi->port_info->phy.phy_type_high; 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci /* If Advertising link mode PHY type is not using override PHY type, 15458c2ecf20Sopenharmony_ci * then use PHY type with media. 15468c2ecf20Sopenharmony_ci */ 15478c2ecf20Sopenharmony_ci if (!adv_phy_type_lo && !adv_phy_type_hi) { 15488c2ecf20Sopenharmony_ci adv_phy_type_lo = vsi->port_info->phy.phy_type_low; 15498c2ecf20Sopenharmony_ci adv_phy_type_hi = vsi->port_info->phy.phy_type_high; 15508c2ecf20Sopenharmony_ci } 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ks, supported); 15538c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ks, advertising); 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_100BASE_TX | 15568c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100M_SGMII; 15578c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 15588c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 15598c2ecf20Sopenharmony_ci 100baseT_Full); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100MB, 15628c2ecf20Sopenharmony_ci 100baseT_Full); 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_1000BASE_T | 15668c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_1G_SGMII; 15678c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 15688c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 15698c2ecf20Sopenharmony_ci 1000baseT_Full); 15708c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_1000MB, 15718c2ecf20Sopenharmony_ci 1000baseT_Full); 15728c2ecf20Sopenharmony_ci } 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_1000BASE_KX; 15758c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 15768c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 15778c2ecf20Sopenharmony_ci 1000baseKX_Full); 15788c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_1000MB, 15798c2ecf20Sopenharmony_ci 1000baseKX_Full); 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_1000BASE_SX | 15838c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_1000BASE_LX; 15848c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 15858c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 15868c2ecf20Sopenharmony_ci 1000baseX_Full); 15878c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_1000MB, 15888c2ecf20Sopenharmony_ci 1000baseX_Full); 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_2500BASE_T; 15928c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 15938c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 15948c2ecf20Sopenharmony_ci 2500baseT_Full); 15958c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_2500MB, 15968c2ecf20Sopenharmony_ci 2500baseT_Full); 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_2500BASE_X | 16008c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_2500BASE_KX; 16018c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 16028c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16038c2ecf20Sopenharmony_ci 2500baseX_Full); 16048c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_2500MB, 16058c2ecf20Sopenharmony_ci 2500baseX_Full); 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_5GBASE_T | 16098c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_5GBASE_KR; 16108c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 16118c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16128c2ecf20Sopenharmony_ci 5000baseT_Full); 16138c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_5GB, 16148c2ecf20Sopenharmony_ci 5000baseT_Full); 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_10GBASE_T | 16188c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_10G_SFI_DA | 16198c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC | 16208c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_10G_SFI_C2C; 16218c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 16228c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16238c2ecf20Sopenharmony_ci 10000baseT_Full); 16248c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_10GB, 16258c2ecf20Sopenharmony_ci 10000baseT_Full); 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_10GBASE_KR_CR1; 16298c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 16308c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16318c2ecf20Sopenharmony_ci 10000baseKR_Full); 16328c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_10GB, 16338c2ecf20Sopenharmony_ci 10000baseKR_Full); 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_10GBASE_SR; 16378c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 16388c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16398c2ecf20Sopenharmony_ci 10000baseSR_Full); 16408c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_10GB, 16418c2ecf20Sopenharmony_ci 10000baseSR_Full); 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_10GBASE_LR; 16458c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 16468c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16478c2ecf20Sopenharmony_ci 10000baseLR_Full); 16488c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_10GB, 16498c2ecf20Sopenharmony_ci 10000baseLR_Full); 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_25GBASE_T | 16538c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_25GBASE_CR | 16548c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_25GBASE_CR_S | 16558c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_25GBASE_CR1 | 16568c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC | 16578c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_25G_AUI_C2C; 16588c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 16598c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16608c2ecf20Sopenharmony_ci 25000baseCR_Full); 16618c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_25GB, 16628c2ecf20Sopenharmony_ci 25000baseCR_Full); 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_25GBASE_SR | 16668c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_25GBASE_LR; 16678c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 16688c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16698c2ecf20Sopenharmony_ci 25000baseSR_Full); 16708c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_25GB, 16718c2ecf20Sopenharmony_ci 25000baseSR_Full); 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_25GBASE_KR | 16758c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_25GBASE_KR_S | 16768c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_25GBASE_KR1; 16778c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 16788c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16798c2ecf20Sopenharmony_ci 25000baseKR_Full); 16808c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_25GB, 16818c2ecf20Sopenharmony_ci 25000baseKR_Full); 16828c2ecf20Sopenharmony_ci } 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_40GBASE_KR4; 16858c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 16868c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16878c2ecf20Sopenharmony_ci 40000baseKR4_Full); 16888c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_40GB, 16898c2ecf20Sopenharmony_ci 40000baseKR4_Full); 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_40GBASE_CR4 | 16938c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC | 16948c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_40G_XLAUI; 16958c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 16968c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16978c2ecf20Sopenharmony_ci 40000baseCR4_Full); 16988c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_40GB, 16998c2ecf20Sopenharmony_ci 40000baseCR4_Full); 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_40GBASE_SR4; 17038c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 17048c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 17058c2ecf20Sopenharmony_ci 40000baseSR4_Full); 17068c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_40GB, 17078c2ecf20Sopenharmony_ci 40000baseSR4_Full); 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_40GBASE_LR4; 17118c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 17128c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 17138c2ecf20Sopenharmony_ci 40000baseLR4_Full); 17148c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_40GB, 17158c2ecf20Sopenharmony_ci 40000baseLR4_Full); 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_50GBASE_CR2 | 17198c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50G_LAUI2_AOC_ACC | 17208c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50G_LAUI2 | 17218c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50G_AUI2_AOC_ACC | 17228c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50G_AUI2 | 17238c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50GBASE_CP | 17248c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50GBASE_SR | 17258c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50G_AUI1_AOC_ACC | 17268c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50G_AUI1; 17278c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 17288c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 17298c2ecf20Sopenharmony_ci 50000baseCR2_Full); 17308c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_50GB, 17318c2ecf20Sopenharmony_ci 50000baseCR2_Full); 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_50GBASE_KR2 | 17358c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50GBASE_KR_PAM4; 17368c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 17378c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 17388c2ecf20Sopenharmony_ci 50000baseKR2_Full); 17398c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_50GB, 17408c2ecf20Sopenharmony_ci 50000baseKR2_Full); 17418c2ecf20Sopenharmony_ci } 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_50GBASE_SR2 | 17448c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50GBASE_LR2 | 17458c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50GBASE_FR | 17468c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_50GBASE_LR; 17478c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 17488c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 17498c2ecf20Sopenharmony_ci 50000baseSR2_Full); 17508c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_50GB, 17518c2ecf20Sopenharmony_ci 50000baseSR2_Full); 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_100GBASE_CR4 | 17558c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100G_CAUI4_AOC_ACC | 17568c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100G_CAUI4 | 17578c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100G_AUI4_AOC_ACC | 17588c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100G_AUI4 | 17598c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4 | 17608c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_CP2; 17618c2ecf20Sopenharmony_ci phy_type_mask_hi = ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC | 17628c2ecf20Sopenharmony_ci ICE_PHY_TYPE_HIGH_100G_CAUI2 | 17638c2ecf20Sopenharmony_ci ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC | 17648c2ecf20Sopenharmony_ci ICE_PHY_TYPE_HIGH_100G_AUI2; 17658c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo || 17668c2ecf20Sopenharmony_ci phy_types_high & phy_type_mask_hi) { 17678c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 17688c2ecf20Sopenharmony_ci 100000baseCR4_Full); 17698c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB, 17708c2ecf20Sopenharmony_ci 100000baseCR4_Full); 17718c2ecf20Sopenharmony_ci } 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_100GBASE_SR4 | 17748c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_SR2; 17758c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 17768c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 17778c2ecf20Sopenharmony_ci 100000baseSR4_Full); 17788c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB, 17798c2ecf20Sopenharmony_ci 100000baseSR4_Full); 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_100GBASE_LR4 | 17838c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_DR; 17848c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo) { 17858c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 17868c2ecf20Sopenharmony_ci 100000baseLR4_ER4_Full); 17878c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB, 17888c2ecf20Sopenharmony_ci 100000baseLR4_ER4_Full); 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci phy_type_mask_lo = ICE_PHY_TYPE_LOW_100GBASE_KR4 | 17928c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4; 17938c2ecf20Sopenharmony_ci phy_type_mask_hi = ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4; 17948c2ecf20Sopenharmony_ci if (phy_types_low & phy_type_mask_lo || 17958c2ecf20Sopenharmony_ci phy_types_high & phy_type_mask_hi) { 17968c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 17978c2ecf20Sopenharmony_ci 100000baseKR4_Full); 17988c2ecf20Sopenharmony_ci ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB, 17998c2ecf20Sopenharmony_ci 100000baseKR4_Full); 18008c2ecf20Sopenharmony_ci } 18018c2ecf20Sopenharmony_ci} 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci#define TEST_SET_BITS_TIMEOUT 50 18048c2ecf20Sopenharmony_ci#define TEST_SET_BITS_SLEEP_MAX 2000 18058c2ecf20Sopenharmony_ci#define TEST_SET_BITS_SLEEP_MIN 1000 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci/** 18088c2ecf20Sopenharmony_ci * ice_get_settings_link_up - Get Link settings for when link is up 18098c2ecf20Sopenharmony_ci * @ks: ethtool ksettings to fill in 18108c2ecf20Sopenharmony_ci * @netdev: network interface device structure 18118c2ecf20Sopenharmony_ci */ 18128c2ecf20Sopenharmony_cistatic void 18138c2ecf20Sopenharmony_ciice_get_settings_link_up(struct ethtool_link_ksettings *ks, 18148c2ecf20Sopenharmony_ci struct net_device *netdev) 18158c2ecf20Sopenharmony_ci{ 18168c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 18178c2ecf20Sopenharmony_ci struct ice_port_info *pi = np->vsi->port_info; 18188c2ecf20Sopenharmony_ci struct ice_link_status *link_info; 18198c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci link_info = &vsi->port_info->phy.link_info; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci /* Get supported and advertised settings from PHY ability with media */ 18248c2ecf20Sopenharmony_ci ice_phy_type_to_ethtool(netdev, ks); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci switch (link_info->link_speed) { 18278c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_100GB: 18288c2ecf20Sopenharmony_ci ks->base.speed = SPEED_100000; 18298c2ecf20Sopenharmony_ci break; 18308c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_50GB: 18318c2ecf20Sopenharmony_ci ks->base.speed = SPEED_50000; 18328c2ecf20Sopenharmony_ci break; 18338c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_40GB: 18348c2ecf20Sopenharmony_ci ks->base.speed = SPEED_40000; 18358c2ecf20Sopenharmony_ci break; 18368c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_25GB: 18378c2ecf20Sopenharmony_ci ks->base.speed = SPEED_25000; 18388c2ecf20Sopenharmony_ci break; 18398c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_20GB: 18408c2ecf20Sopenharmony_ci ks->base.speed = SPEED_20000; 18418c2ecf20Sopenharmony_ci break; 18428c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_10GB: 18438c2ecf20Sopenharmony_ci ks->base.speed = SPEED_10000; 18448c2ecf20Sopenharmony_ci break; 18458c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_5GB: 18468c2ecf20Sopenharmony_ci ks->base.speed = SPEED_5000; 18478c2ecf20Sopenharmony_ci break; 18488c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_2500MB: 18498c2ecf20Sopenharmony_ci ks->base.speed = SPEED_2500; 18508c2ecf20Sopenharmony_ci break; 18518c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_1000MB: 18528c2ecf20Sopenharmony_ci ks->base.speed = SPEED_1000; 18538c2ecf20Sopenharmony_ci break; 18548c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_100MB: 18558c2ecf20Sopenharmony_ci ks->base.speed = SPEED_100; 18568c2ecf20Sopenharmony_ci break; 18578c2ecf20Sopenharmony_ci default: 18588c2ecf20Sopenharmony_ci netdev_info(netdev, "WARNING: Unrecognized link_speed (0x%x).\n", 18598c2ecf20Sopenharmony_ci link_info->link_speed); 18608c2ecf20Sopenharmony_ci break; 18618c2ecf20Sopenharmony_ci } 18628c2ecf20Sopenharmony_ci ks->base.duplex = DUPLEX_FULL; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci if (link_info->an_info & ICE_AQ_AN_COMPLETED) 18658c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, lp_advertising, 18668c2ecf20Sopenharmony_ci Autoneg); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci /* Set flow control negotiated Rx/Tx pause */ 18698c2ecf20Sopenharmony_ci switch (pi->fc.current_mode) { 18708c2ecf20Sopenharmony_ci case ICE_FC_FULL: 18718c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause); 18728c2ecf20Sopenharmony_ci break; 18738c2ecf20Sopenharmony_ci case ICE_FC_TX_PAUSE: 18748c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause); 18758c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, lp_advertising, 18768c2ecf20Sopenharmony_ci Asym_Pause); 18778c2ecf20Sopenharmony_ci break; 18788c2ecf20Sopenharmony_ci case ICE_FC_RX_PAUSE: 18798c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, lp_advertising, 18808c2ecf20Sopenharmony_ci Asym_Pause); 18818c2ecf20Sopenharmony_ci break; 18828c2ecf20Sopenharmony_ci case ICE_FC_PFC: 18838c2ecf20Sopenharmony_ci default: 18848c2ecf20Sopenharmony_ci ethtool_link_ksettings_del_link_mode(ks, lp_advertising, Pause); 18858c2ecf20Sopenharmony_ci ethtool_link_ksettings_del_link_mode(ks, lp_advertising, 18868c2ecf20Sopenharmony_ci Asym_Pause); 18878c2ecf20Sopenharmony_ci break; 18888c2ecf20Sopenharmony_ci } 18898c2ecf20Sopenharmony_ci} 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci/** 18928c2ecf20Sopenharmony_ci * ice_get_settings_link_down - Get the Link settings when link is down 18938c2ecf20Sopenharmony_ci * @ks: ethtool ksettings to fill in 18948c2ecf20Sopenharmony_ci * @netdev: network interface device structure 18958c2ecf20Sopenharmony_ci * 18968c2ecf20Sopenharmony_ci * Reports link settings that can be determined when link is down 18978c2ecf20Sopenharmony_ci */ 18988c2ecf20Sopenharmony_cistatic void 18998c2ecf20Sopenharmony_ciice_get_settings_link_down(struct ethtool_link_ksettings *ks, 19008c2ecf20Sopenharmony_ci struct net_device *netdev) 19018c2ecf20Sopenharmony_ci{ 19028c2ecf20Sopenharmony_ci /* link is down and the driver needs to fall back on 19038c2ecf20Sopenharmony_ci * supported PHY types to figure out what info to display 19048c2ecf20Sopenharmony_ci */ 19058c2ecf20Sopenharmony_ci ice_phy_type_to_ethtool(netdev, ks); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci /* With no link, speed and duplex are unknown */ 19088c2ecf20Sopenharmony_ci ks->base.speed = SPEED_UNKNOWN; 19098c2ecf20Sopenharmony_ci ks->base.duplex = DUPLEX_UNKNOWN; 19108c2ecf20Sopenharmony_ci} 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci/** 19138c2ecf20Sopenharmony_ci * ice_get_link_ksettings - Get Link Speed and Duplex settings 19148c2ecf20Sopenharmony_ci * @netdev: network interface device structure 19158c2ecf20Sopenharmony_ci * @ks: ethtool ksettings 19168c2ecf20Sopenharmony_ci * 19178c2ecf20Sopenharmony_ci * Reports speed/duplex settings based on media_type 19188c2ecf20Sopenharmony_ci */ 19198c2ecf20Sopenharmony_cistatic int 19208c2ecf20Sopenharmony_ciice_get_link_ksettings(struct net_device *netdev, 19218c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *ks) 19228c2ecf20Sopenharmony_ci{ 19238c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 19248c2ecf20Sopenharmony_ci struct ice_aqc_get_phy_caps_data *caps; 19258c2ecf20Sopenharmony_ci struct ice_link_status *hw_link_info; 19268c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 19278c2ecf20Sopenharmony_ci enum ice_status status; 19288c2ecf20Sopenharmony_ci int err = 0; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ks, supported); 19318c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ks, advertising); 19328c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ks, lp_advertising); 19338c2ecf20Sopenharmony_ci hw_link_info = &vsi->port_info->phy.link_info; 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci /* set speed and duplex */ 19368c2ecf20Sopenharmony_ci if (hw_link_info->link_info & ICE_AQ_LINK_UP) 19378c2ecf20Sopenharmony_ci ice_get_settings_link_up(ks, netdev); 19388c2ecf20Sopenharmony_ci else 19398c2ecf20Sopenharmony_ci ice_get_settings_link_down(ks, netdev); 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci /* set autoneg settings */ 19428c2ecf20Sopenharmony_ci ks->base.autoneg = (hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ? 19438c2ecf20Sopenharmony_ci AUTONEG_ENABLE : AUTONEG_DISABLE; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci /* set media type settings */ 19468c2ecf20Sopenharmony_ci switch (vsi->port_info->phy.media_type) { 19478c2ecf20Sopenharmony_ci case ICE_MEDIA_FIBER: 19488c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, FIBRE); 19498c2ecf20Sopenharmony_ci ks->base.port = PORT_FIBRE; 19508c2ecf20Sopenharmony_ci break; 19518c2ecf20Sopenharmony_ci case ICE_MEDIA_BASET: 19528c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, TP); 19538c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, TP); 19548c2ecf20Sopenharmony_ci ks->base.port = PORT_TP; 19558c2ecf20Sopenharmony_ci break; 19568c2ecf20Sopenharmony_ci case ICE_MEDIA_BACKPLANE: 19578c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, Backplane); 19588c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, 19598c2ecf20Sopenharmony_ci Backplane); 19608c2ecf20Sopenharmony_ci ks->base.port = PORT_NONE; 19618c2ecf20Sopenharmony_ci break; 19628c2ecf20Sopenharmony_ci case ICE_MEDIA_DA: 19638c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, FIBRE); 19648c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, FIBRE); 19658c2ecf20Sopenharmony_ci ks->base.port = PORT_DA; 19668c2ecf20Sopenharmony_ci break; 19678c2ecf20Sopenharmony_ci default: 19688c2ecf20Sopenharmony_ci ks->base.port = PORT_OTHER; 19698c2ecf20Sopenharmony_ci break; 19708c2ecf20Sopenharmony_ci } 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci /* flow control is symmetric and always supported */ 19738c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, Pause); 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci caps = kzalloc(sizeof(*caps), GFP_KERNEL); 19768c2ecf20Sopenharmony_ci if (!caps) 19778c2ecf20Sopenharmony_ci return -ENOMEM; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci status = ice_aq_get_phy_caps(vsi->port_info, false, 19808c2ecf20Sopenharmony_ci ICE_AQC_REPORT_ACTIVE_CFG, caps, NULL); 19818c2ecf20Sopenharmony_ci if (status) { 19828c2ecf20Sopenharmony_ci err = -EIO; 19838c2ecf20Sopenharmony_ci goto done; 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci /* Set the advertised flow control based on the PHY capability */ 19878c2ecf20Sopenharmony_ci if ((caps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) && 19888c2ecf20Sopenharmony_ci (caps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE)) { 19898c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, Pause); 19908c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, 19918c2ecf20Sopenharmony_ci Asym_Pause); 19928c2ecf20Sopenharmony_ci } else if (caps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) { 19938c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, 19948c2ecf20Sopenharmony_ci Asym_Pause); 19958c2ecf20Sopenharmony_ci } else if (caps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE) { 19968c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, Pause); 19978c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, 19988c2ecf20Sopenharmony_ci Asym_Pause); 19998c2ecf20Sopenharmony_ci } else { 20008c2ecf20Sopenharmony_ci ethtool_link_ksettings_del_link_mode(ks, advertising, Pause); 20018c2ecf20Sopenharmony_ci ethtool_link_ksettings_del_link_mode(ks, advertising, 20028c2ecf20Sopenharmony_ci Asym_Pause); 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci /* Set advertised FEC modes based on PHY capability */ 20068c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ || 20098c2ecf20Sopenharmony_ci caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ) 20108c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, 20118c2ecf20Sopenharmony_ci FEC_BASER); 20128c2ecf20Sopenharmony_ci if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ || 20138c2ecf20Sopenharmony_ci caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ) 20148c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci status = ice_aq_get_phy_caps(vsi->port_info, false, 20178c2ecf20Sopenharmony_ci ICE_AQC_REPORT_TOPO_CAP_MEDIA, caps, NULL); 20188c2ecf20Sopenharmony_ci if (status) { 20198c2ecf20Sopenharmony_ci err = -EIO; 20208c2ecf20Sopenharmony_ci goto done; 20218c2ecf20Sopenharmony_ci } 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci /* Set supported FEC modes based on PHY capability */ 20248c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE); 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN || 20278c2ecf20Sopenharmony_ci caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN) 20288c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER); 20298c2ecf20Sopenharmony_ci if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN) 20308c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS); 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci /* Set supported and advertised autoneg */ 20338c2ecf20Sopenharmony_ci if (ice_is_phy_caps_an_enabled(caps)) { 20348c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); 20358c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_cidone: 20398c2ecf20Sopenharmony_ci kfree(caps); 20408c2ecf20Sopenharmony_ci return err; 20418c2ecf20Sopenharmony_ci} 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci/** 20448c2ecf20Sopenharmony_ci * ice_ksettings_find_adv_link_speed - Find advertising link speed 20458c2ecf20Sopenharmony_ci * @ks: ethtool ksettings 20468c2ecf20Sopenharmony_ci */ 20478c2ecf20Sopenharmony_cistatic u16 20488c2ecf20Sopenharmony_ciice_ksettings_find_adv_link_speed(const struct ethtool_link_ksettings *ks) 20498c2ecf20Sopenharmony_ci{ 20508c2ecf20Sopenharmony_ci u16 adv_link_speed = 0; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 20538c2ecf20Sopenharmony_ci 100baseT_Full)) 20548c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_100MB; 20558c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 20568c2ecf20Sopenharmony_ci 1000baseX_Full)) 20578c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_1000MB; 20588c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 20598c2ecf20Sopenharmony_ci 1000baseT_Full) || 20608c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 20618c2ecf20Sopenharmony_ci 1000baseKX_Full)) 20628c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_1000MB; 20638c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 20648c2ecf20Sopenharmony_ci 2500baseT_Full)) 20658c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_2500MB; 20668c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 20678c2ecf20Sopenharmony_ci 2500baseX_Full)) 20688c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_2500MB; 20698c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 20708c2ecf20Sopenharmony_ci 5000baseT_Full)) 20718c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_5GB; 20728c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 20738c2ecf20Sopenharmony_ci 10000baseT_Full) || 20748c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 20758c2ecf20Sopenharmony_ci 10000baseKR_Full)) 20768c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_10GB; 20778c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 20788c2ecf20Sopenharmony_ci 10000baseSR_Full) || 20798c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 20808c2ecf20Sopenharmony_ci 10000baseLR_Full)) 20818c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_10GB; 20828c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 20838c2ecf20Sopenharmony_ci 25000baseCR_Full) || 20848c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 20858c2ecf20Sopenharmony_ci 25000baseSR_Full) || 20868c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 20878c2ecf20Sopenharmony_ci 25000baseKR_Full)) 20888c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_25GB; 20898c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 20908c2ecf20Sopenharmony_ci 40000baseCR4_Full) || 20918c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 20928c2ecf20Sopenharmony_ci 40000baseSR4_Full) || 20938c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 20948c2ecf20Sopenharmony_ci 40000baseLR4_Full) || 20958c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 20968c2ecf20Sopenharmony_ci 40000baseKR4_Full)) 20978c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_40GB; 20988c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 20998c2ecf20Sopenharmony_ci 50000baseCR2_Full) || 21008c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 21018c2ecf20Sopenharmony_ci 50000baseKR2_Full)) 21028c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_50GB; 21038c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 21048c2ecf20Sopenharmony_ci 50000baseSR2_Full)) 21058c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_50GB; 21068c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 21078c2ecf20Sopenharmony_ci 100000baseCR4_Full) || 21088c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 21098c2ecf20Sopenharmony_ci 100000baseSR4_Full) || 21108c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 21118c2ecf20Sopenharmony_ci 100000baseLR4_ER4_Full) || 21128c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(ks, advertising, 21138c2ecf20Sopenharmony_ci 100000baseKR4_Full)) 21148c2ecf20Sopenharmony_ci adv_link_speed |= ICE_AQ_LINK_SPEED_100GB; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci return adv_link_speed; 21178c2ecf20Sopenharmony_ci} 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci/** 21208c2ecf20Sopenharmony_ci * ice_setup_autoneg 21218c2ecf20Sopenharmony_ci * @p: port info 21228c2ecf20Sopenharmony_ci * @ks: ethtool_link_ksettings 21238c2ecf20Sopenharmony_ci * @config: configuration that will be sent down to FW 21248c2ecf20Sopenharmony_ci * @autoneg_enabled: autonegotiation is enabled or not 21258c2ecf20Sopenharmony_ci * @autoneg_changed: will there a change in autonegotiation 21268c2ecf20Sopenharmony_ci * @netdev: network interface device structure 21278c2ecf20Sopenharmony_ci * 21288c2ecf20Sopenharmony_ci * Setup PHY autonegotiation feature 21298c2ecf20Sopenharmony_ci */ 21308c2ecf20Sopenharmony_cistatic int 21318c2ecf20Sopenharmony_ciice_setup_autoneg(struct ice_port_info *p, struct ethtool_link_ksettings *ks, 21328c2ecf20Sopenharmony_ci struct ice_aqc_set_phy_cfg_data *config, 21338c2ecf20Sopenharmony_ci u8 autoneg_enabled, u8 *autoneg_changed, 21348c2ecf20Sopenharmony_ci struct net_device *netdev) 21358c2ecf20Sopenharmony_ci{ 21368c2ecf20Sopenharmony_ci int err = 0; 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci *autoneg_changed = 0; 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci /* Check autoneg */ 21418c2ecf20Sopenharmony_ci if (autoneg_enabled == AUTONEG_ENABLE) { 21428c2ecf20Sopenharmony_ci /* If autoneg was not already enabled */ 21438c2ecf20Sopenharmony_ci if (!(p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED)) { 21448c2ecf20Sopenharmony_ci /* If autoneg is not supported, return error */ 21458c2ecf20Sopenharmony_ci if (!ethtool_link_ksettings_test_link_mode(ks, 21468c2ecf20Sopenharmony_ci supported, 21478c2ecf20Sopenharmony_ci Autoneg)) { 21488c2ecf20Sopenharmony_ci netdev_info(netdev, "Autoneg not supported on this phy.\n"); 21498c2ecf20Sopenharmony_ci err = -EINVAL; 21508c2ecf20Sopenharmony_ci } else { 21518c2ecf20Sopenharmony_ci /* Autoneg is allowed to change */ 21528c2ecf20Sopenharmony_ci config->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; 21538c2ecf20Sopenharmony_ci *autoneg_changed = 1; 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci } else { 21578c2ecf20Sopenharmony_ci /* If autoneg is currently enabled */ 21588c2ecf20Sopenharmony_ci if (p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED) { 21598c2ecf20Sopenharmony_ci /* If autoneg is supported 10GBASE_T is the only PHY 21608c2ecf20Sopenharmony_ci * that can disable it, so otherwise return error 21618c2ecf20Sopenharmony_ci */ 21628c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, 21638c2ecf20Sopenharmony_ci supported, 21648c2ecf20Sopenharmony_ci Autoneg)) { 21658c2ecf20Sopenharmony_ci netdev_info(netdev, "Autoneg cannot be disabled on this phy\n"); 21668c2ecf20Sopenharmony_ci err = -EINVAL; 21678c2ecf20Sopenharmony_ci } else { 21688c2ecf20Sopenharmony_ci /* Autoneg is allowed to change */ 21698c2ecf20Sopenharmony_ci config->caps &= ~ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; 21708c2ecf20Sopenharmony_ci *autoneg_changed = 1; 21718c2ecf20Sopenharmony_ci } 21728c2ecf20Sopenharmony_ci } 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci return err; 21768c2ecf20Sopenharmony_ci} 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci/** 21798c2ecf20Sopenharmony_ci * ice_set_phy_type_from_speed - set phy_types based on speeds 21808c2ecf20Sopenharmony_ci * and advertised modes 21818c2ecf20Sopenharmony_ci * @ks: ethtool link ksettings struct 21828c2ecf20Sopenharmony_ci * @phy_type_low: pointer to the lower part of phy_type 21838c2ecf20Sopenharmony_ci * @phy_type_high: pointer to the higher part of phy_type 21848c2ecf20Sopenharmony_ci * @adv_link_speed: targeted link speeds bitmap 21858c2ecf20Sopenharmony_ci */ 21868c2ecf20Sopenharmony_cistatic void 21878c2ecf20Sopenharmony_ciice_set_phy_type_from_speed(const struct ethtool_link_ksettings *ks, 21888c2ecf20Sopenharmony_ci u64 *phy_type_low, u64 *phy_type_high, 21898c2ecf20Sopenharmony_ci u16 adv_link_speed) 21908c2ecf20Sopenharmony_ci{ 21918c2ecf20Sopenharmony_ci /* Handle 1000M speed in a special way because ice_update_phy_type 21928c2ecf20Sopenharmony_ci * enables all link modes, but having mixed copper and optical 21938c2ecf20Sopenharmony_ci * standards is not supported. 21948c2ecf20Sopenharmony_ci */ 21958c2ecf20Sopenharmony_ci adv_link_speed &= ~ICE_AQ_LINK_SPEED_1000MB; 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 21988c2ecf20Sopenharmony_ci 1000baseT_Full)) 21998c2ecf20Sopenharmony_ci *phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_T | 22008c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_1G_SGMII; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 22038c2ecf20Sopenharmony_ci 1000baseKX_Full)) 22048c2ecf20Sopenharmony_ci *phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_KX; 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(ks, advertising, 22078c2ecf20Sopenharmony_ci 1000baseX_Full)) 22088c2ecf20Sopenharmony_ci *phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_SX | 22098c2ecf20Sopenharmony_ci ICE_PHY_TYPE_LOW_1000BASE_LX; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci ice_update_phy_type(phy_type_low, phy_type_high, adv_link_speed); 22128c2ecf20Sopenharmony_ci} 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci/** 22158c2ecf20Sopenharmony_ci * ice_set_link_ksettings - Set Speed and Duplex 22168c2ecf20Sopenharmony_ci * @netdev: network interface device structure 22178c2ecf20Sopenharmony_ci * @ks: ethtool ksettings 22188c2ecf20Sopenharmony_ci * 22198c2ecf20Sopenharmony_ci * Set speed/duplex per media_types advertised/forced 22208c2ecf20Sopenharmony_ci */ 22218c2ecf20Sopenharmony_cistatic int 22228c2ecf20Sopenharmony_ciice_set_link_ksettings(struct net_device *netdev, 22238c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *ks) 22248c2ecf20Sopenharmony_ci{ 22258c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 22268c2ecf20Sopenharmony_ci struct ethtool_link_ksettings safe_ks, copy_ks; 22278c2ecf20Sopenharmony_ci u8 autoneg, timeout = TEST_SET_BITS_TIMEOUT; 22288c2ecf20Sopenharmony_ci struct ice_aqc_get_phy_caps_data *phy_caps; 22298c2ecf20Sopenharmony_ci struct ice_aqc_set_phy_cfg_data config; 22308c2ecf20Sopenharmony_ci u16 adv_link_speed, curr_link_speed; 22318c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 22328c2ecf20Sopenharmony_ci struct ice_port_info *pi; 22338c2ecf20Sopenharmony_ci u8 autoneg_changed = 0; 22348c2ecf20Sopenharmony_ci enum ice_status status; 22358c2ecf20Sopenharmony_ci u64 phy_type_high = 0; 22368c2ecf20Sopenharmony_ci u64 phy_type_low = 0; 22378c2ecf20Sopenharmony_ci int err = 0; 22388c2ecf20Sopenharmony_ci bool linkup; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci pi = np->vsi->port_info; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci if (!pi) 22438c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci if (pi->phy.media_type != ICE_MEDIA_BASET && 22468c2ecf20Sopenharmony_ci pi->phy.media_type != ICE_MEDIA_FIBER && 22478c2ecf20Sopenharmony_ci pi->phy.media_type != ICE_MEDIA_BACKPLANE && 22488c2ecf20Sopenharmony_ci pi->phy.media_type != ICE_MEDIA_DA && 22498c2ecf20Sopenharmony_ci pi->phy.link_info.link_info & ICE_AQ_LINK_UP) 22508c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci phy_caps = kzalloc(sizeof(*phy_caps), GFP_KERNEL); 22538c2ecf20Sopenharmony_ci if (!phy_caps) 22548c2ecf20Sopenharmony_ci return -ENOMEM; 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci /* Get the PHY capabilities based on media */ 22578c2ecf20Sopenharmony_ci status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA, 22588c2ecf20Sopenharmony_ci phy_caps, NULL); 22598c2ecf20Sopenharmony_ci if (status) { 22608c2ecf20Sopenharmony_ci err = -EAGAIN; 22618c2ecf20Sopenharmony_ci goto done; 22628c2ecf20Sopenharmony_ci } 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci /* copy the ksettings to copy_ks to avoid modifying the original */ 22658c2ecf20Sopenharmony_ci memcpy(©_ks, ks, sizeof(copy_ks)); 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci /* save autoneg out of ksettings */ 22688c2ecf20Sopenharmony_ci autoneg = copy_ks.base.autoneg; 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci memset(&safe_ks, 0, sizeof(safe_ks)); 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci /* Get link modes supported by hardware.*/ 22738c2ecf20Sopenharmony_ci ice_phy_type_to_ethtool(netdev, &safe_ks); 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci /* and check against modes requested by user. 22768c2ecf20Sopenharmony_ci * Return an error if unsupported mode was set. 22778c2ecf20Sopenharmony_ci */ 22788c2ecf20Sopenharmony_ci if (!bitmap_subset(copy_ks.link_modes.advertising, 22798c2ecf20Sopenharmony_ci safe_ks.link_modes.supported, 22808c2ecf20Sopenharmony_ci __ETHTOOL_LINK_MODE_MASK_NBITS)) { 22818c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) 22828c2ecf20Sopenharmony_ci netdev_info(netdev, "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n"); 22838c2ecf20Sopenharmony_ci err = -EINVAL; 22848c2ecf20Sopenharmony_ci goto done; 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci /* get our own copy of the bits to check against */ 22888c2ecf20Sopenharmony_ci memset(&safe_ks, 0, sizeof(safe_ks)); 22898c2ecf20Sopenharmony_ci safe_ks.base.cmd = copy_ks.base.cmd; 22908c2ecf20Sopenharmony_ci safe_ks.base.link_mode_masks_nwords = 22918c2ecf20Sopenharmony_ci copy_ks.base.link_mode_masks_nwords; 22928c2ecf20Sopenharmony_ci ice_get_link_ksettings(netdev, &safe_ks); 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci /* set autoneg back to what it currently is */ 22958c2ecf20Sopenharmony_ci copy_ks.base.autoneg = safe_ks.base.autoneg; 22968c2ecf20Sopenharmony_ci /* we don't compare the speed */ 22978c2ecf20Sopenharmony_ci copy_ks.base.speed = safe_ks.base.speed; 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci /* If copy_ks.base and safe_ks.base are not the same now, then they are 23008c2ecf20Sopenharmony_ci * trying to set something that we do not support. 23018c2ecf20Sopenharmony_ci */ 23028c2ecf20Sopenharmony_ci if (memcmp(©_ks.base, &safe_ks.base, sizeof(copy_ks.base))) { 23038c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 23048c2ecf20Sopenharmony_ci goto done; 23058c2ecf20Sopenharmony_ci } 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci while (test_and_set_bit(__ICE_CFG_BUSY, pf->state)) { 23088c2ecf20Sopenharmony_ci timeout--; 23098c2ecf20Sopenharmony_ci if (!timeout) { 23108c2ecf20Sopenharmony_ci err = -EBUSY; 23118c2ecf20Sopenharmony_ci goto done; 23128c2ecf20Sopenharmony_ci } 23138c2ecf20Sopenharmony_ci usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX); 23148c2ecf20Sopenharmony_ci } 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci /* Copy the current user PHY configuration. The current user PHY 23178c2ecf20Sopenharmony_ci * configuration is initialized during probe from PHY capabilities 23188c2ecf20Sopenharmony_ci * software mode, and updated on set PHY configuration. 23198c2ecf20Sopenharmony_ci */ 23208c2ecf20Sopenharmony_ci memcpy(&config, &pi->phy.curr_user_phy_cfg, sizeof(config)); 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci /* Check autoneg */ 23258c2ecf20Sopenharmony_ci err = ice_setup_autoneg(pi, &safe_ks, &config, autoneg, &autoneg_changed, 23268c2ecf20Sopenharmony_ci netdev); 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci if (err) 23298c2ecf20Sopenharmony_ci goto done; 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci /* Call to get the current link speed */ 23328c2ecf20Sopenharmony_ci pi->phy.get_link_info = true; 23338c2ecf20Sopenharmony_ci status = ice_get_link_status(pi, &linkup); 23348c2ecf20Sopenharmony_ci if (status) { 23358c2ecf20Sopenharmony_ci err = -EAGAIN; 23368c2ecf20Sopenharmony_ci goto done; 23378c2ecf20Sopenharmony_ci } 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci curr_link_speed = pi->phy.curr_user_speed_req; 23408c2ecf20Sopenharmony_ci adv_link_speed = ice_ksettings_find_adv_link_speed(ks); 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci /* If speed didn't get set, set it to what it currently is. 23438c2ecf20Sopenharmony_ci * This is needed because if advertise is 0 (as it is when autoneg 23448c2ecf20Sopenharmony_ci * is disabled) then speed won't get set. 23458c2ecf20Sopenharmony_ci */ 23468c2ecf20Sopenharmony_ci if (!adv_link_speed) 23478c2ecf20Sopenharmony_ci adv_link_speed = curr_link_speed; 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci /* Convert the advertise link speeds to their corresponded PHY_TYPE */ 23508c2ecf20Sopenharmony_ci ice_set_phy_type_from_speed(ks, &phy_type_low, &phy_type_high, 23518c2ecf20Sopenharmony_ci adv_link_speed); 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci if (!autoneg_changed && adv_link_speed == curr_link_speed) { 23548c2ecf20Sopenharmony_ci netdev_info(netdev, "Nothing changed, exiting without setting anything.\n"); 23558c2ecf20Sopenharmony_ci goto done; 23568c2ecf20Sopenharmony_ci } 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci /* save the requested speeds */ 23598c2ecf20Sopenharmony_ci pi->phy.link_info.req_speeds = adv_link_speed; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci /* set link and auto negotiation so changes take effect */ 23628c2ecf20Sopenharmony_ci config.caps |= ICE_AQ_PHY_ENA_LINK; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci /* check if there is a PHY type for the requested advertised speed */ 23658c2ecf20Sopenharmony_ci if (!(phy_type_low || phy_type_high)) { 23668c2ecf20Sopenharmony_ci netdev_info(netdev, "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n"); 23678c2ecf20Sopenharmony_ci err = -EAGAIN; 23688c2ecf20Sopenharmony_ci goto done; 23698c2ecf20Sopenharmony_ci } 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci /* intersect requested advertised speed PHY types with media PHY types 23728c2ecf20Sopenharmony_ci * for set PHY configuration 23738c2ecf20Sopenharmony_ci */ 23748c2ecf20Sopenharmony_ci config.phy_type_high = cpu_to_le64(phy_type_high) & 23758c2ecf20Sopenharmony_ci phy_caps->phy_type_high; 23768c2ecf20Sopenharmony_ci config.phy_type_low = cpu_to_le64(phy_type_low) & 23778c2ecf20Sopenharmony_ci phy_caps->phy_type_low; 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci if (!(config.phy_type_high || config.phy_type_low)) { 23808c2ecf20Sopenharmony_ci /* If there is no intersection and lenient mode is enabled, then 23818c2ecf20Sopenharmony_ci * intersect the requested advertised speed with NVM media type 23828c2ecf20Sopenharmony_ci * PHY types. 23838c2ecf20Sopenharmony_ci */ 23848c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) { 23858c2ecf20Sopenharmony_ci config.phy_type_high = cpu_to_le64(phy_type_high) & 23868c2ecf20Sopenharmony_ci pf->nvm_phy_type_hi; 23878c2ecf20Sopenharmony_ci config.phy_type_low = cpu_to_le64(phy_type_low) & 23888c2ecf20Sopenharmony_ci pf->nvm_phy_type_lo; 23898c2ecf20Sopenharmony_ci } else { 23908c2ecf20Sopenharmony_ci netdev_info(netdev, "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n"); 23918c2ecf20Sopenharmony_ci err = -EAGAIN; 23928c2ecf20Sopenharmony_ci goto done; 23938c2ecf20Sopenharmony_ci } 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci /* If link is up put link down */ 23978c2ecf20Sopenharmony_ci if (pi->phy.link_info.link_info & ICE_AQ_LINK_UP) { 23988c2ecf20Sopenharmony_ci /* Tell the OS link is going down, the link will go 23998c2ecf20Sopenharmony_ci * back up when fw says it is ready asynchronously 24008c2ecf20Sopenharmony_ci */ 24018c2ecf20Sopenharmony_ci ice_print_link_msg(np->vsi, false); 24028c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 24038c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(netdev); 24048c2ecf20Sopenharmony_ci } 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci /* make the aq call */ 24078c2ecf20Sopenharmony_ci status = ice_aq_set_phy_cfg(&pf->hw, pi, &config, NULL); 24088c2ecf20Sopenharmony_ci if (status) { 24098c2ecf20Sopenharmony_ci netdev_info(netdev, "Set phy config failed,\n"); 24108c2ecf20Sopenharmony_ci err = -EAGAIN; 24118c2ecf20Sopenharmony_ci goto done; 24128c2ecf20Sopenharmony_ci } 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci /* Save speed request */ 24158c2ecf20Sopenharmony_ci pi->phy.curr_user_speed_req = adv_link_speed; 24168c2ecf20Sopenharmony_cidone: 24178c2ecf20Sopenharmony_ci kfree(phy_caps); 24188c2ecf20Sopenharmony_ci clear_bit(__ICE_CFG_BUSY, pf->state); 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci return err; 24218c2ecf20Sopenharmony_ci} 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci/** 24248c2ecf20Sopenharmony_ci * ice_parse_hdrs - parses headers from RSS hash input 24258c2ecf20Sopenharmony_ci * @nfc: ethtool rxnfc command 24268c2ecf20Sopenharmony_ci * 24278c2ecf20Sopenharmony_ci * This function parses the rxnfc command and returns intended 24288c2ecf20Sopenharmony_ci * header types for RSS configuration 24298c2ecf20Sopenharmony_ci */ 24308c2ecf20Sopenharmony_cistatic u32 ice_parse_hdrs(struct ethtool_rxnfc *nfc) 24318c2ecf20Sopenharmony_ci{ 24328c2ecf20Sopenharmony_ci u32 hdrs = ICE_FLOW_SEG_HDR_NONE; 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci switch (nfc->flow_type) { 24358c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 24368c2ecf20Sopenharmony_ci hdrs |= ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV4; 24378c2ecf20Sopenharmony_ci break; 24388c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 24398c2ecf20Sopenharmony_ci hdrs |= ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV4; 24408c2ecf20Sopenharmony_ci break; 24418c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 24428c2ecf20Sopenharmony_ci hdrs |= ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV4; 24438c2ecf20Sopenharmony_ci break; 24448c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 24458c2ecf20Sopenharmony_ci hdrs |= ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV6; 24468c2ecf20Sopenharmony_ci break; 24478c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 24488c2ecf20Sopenharmony_ci hdrs |= ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV6; 24498c2ecf20Sopenharmony_ci break; 24508c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 24518c2ecf20Sopenharmony_ci hdrs |= ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV6; 24528c2ecf20Sopenharmony_ci break; 24538c2ecf20Sopenharmony_ci default: 24548c2ecf20Sopenharmony_ci break; 24558c2ecf20Sopenharmony_ci } 24568c2ecf20Sopenharmony_ci return hdrs; 24578c2ecf20Sopenharmony_ci} 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci#define ICE_FLOW_HASH_FLD_IPV4_SA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) 24608c2ecf20Sopenharmony_ci#define ICE_FLOW_HASH_FLD_IPV6_SA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA) 24618c2ecf20Sopenharmony_ci#define ICE_FLOW_HASH_FLD_IPV4_DA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) 24628c2ecf20Sopenharmony_ci#define ICE_FLOW_HASH_FLD_IPV6_DA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA) 24638c2ecf20Sopenharmony_ci#define ICE_FLOW_HASH_FLD_TCP_SRC_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT) 24648c2ecf20Sopenharmony_ci#define ICE_FLOW_HASH_FLD_TCP_DST_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT) 24658c2ecf20Sopenharmony_ci#define ICE_FLOW_HASH_FLD_UDP_SRC_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT) 24668c2ecf20Sopenharmony_ci#define ICE_FLOW_HASH_FLD_UDP_DST_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT) 24678c2ecf20Sopenharmony_ci#define ICE_FLOW_HASH_FLD_SCTP_SRC_PORT \ 24688c2ecf20Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT) 24698c2ecf20Sopenharmony_ci#define ICE_FLOW_HASH_FLD_SCTP_DST_PORT \ 24708c2ecf20Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT) 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci/** 24738c2ecf20Sopenharmony_ci * ice_parse_hash_flds - parses hash fields from RSS hash input 24748c2ecf20Sopenharmony_ci * @nfc: ethtool rxnfc command 24758c2ecf20Sopenharmony_ci * 24768c2ecf20Sopenharmony_ci * This function parses the rxnfc command and returns intended 24778c2ecf20Sopenharmony_ci * hash fields for RSS configuration 24788c2ecf20Sopenharmony_ci */ 24798c2ecf20Sopenharmony_cistatic u64 ice_parse_hash_flds(struct ethtool_rxnfc *nfc) 24808c2ecf20Sopenharmony_ci{ 24818c2ecf20Sopenharmony_ci u64 hfld = ICE_HASH_INVALID; 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci if (nfc->data & RXH_IP_SRC || nfc->data & RXH_IP_DST) { 24848c2ecf20Sopenharmony_ci switch (nfc->flow_type) { 24858c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 24868c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 24878c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 24888c2ecf20Sopenharmony_ci if (nfc->data & RXH_IP_SRC) 24898c2ecf20Sopenharmony_ci hfld |= ICE_FLOW_HASH_FLD_IPV4_SA; 24908c2ecf20Sopenharmony_ci if (nfc->data & RXH_IP_DST) 24918c2ecf20Sopenharmony_ci hfld |= ICE_FLOW_HASH_FLD_IPV4_DA; 24928c2ecf20Sopenharmony_ci break; 24938c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 24948c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 24958c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 24968c2ecf20Sopenharmony_ci if (nfc->data & RXH_IP_SRC) 24978c2ecf20Sopenharmony_ci hfld |= ICE_FLOW_HASH_FLD_IPV6_SA; 24988c2ecf20Sopenharmony_ci if (nfc->data & RXH_IP_DST) 24998c2ecf20Sopenharmony_ci hfld |= ICE_FLOW_HASH_FLD_IPV6_DA; 25008c2ecf20Sopenharmony_ci break; 25018c2ecf20Sopenharmony_ci default: 25028c2ecf20Sopenharmony_ci break; 25038c2ecf20Sopenharmony_ci } 25048c2ecf20Sopenharmony_ci } 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci if (nfc->data & RXH_L4_B_0_1 || nfc->data & RXH_L4_B_2_3) { 25078c2ecf20Sopenharmony_ci switch (nfc->flow_type) { 25088c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 25098c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 25108c2ecf20Sopenharmony_ci if (nfc->data & RXH_L4_B_0_1) 25118c2ecf20Sopenharmony_ci hfld |= ICE_FLOW_HASH_FLD_TCP_SRC_PORT; 25128c2ecf20Sopenharmony_ci if (nfc->data & RXH_L4_B_2_3) 25138c2ecf20Sopenharmony_ci hfld |= ICE_FLOW_HASH_FLD_TCP_DST_PORT; 25148c2ecf20Sopenharmony_ci break; 25158c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 25168c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 25178c2ecf20Sopenharmony_ci if (nfc->data & RXH_L4_B_0_1) 25188c2ecf20Sopenharmony_ci hfld |= ICE_FLOW_HASH_FLD_UDP_SRC_PORT; 25198c2ecf20Sopenharmony_ci if (nfc->data & RXH_L4_B_2_3) 25208c2ecf20Sopenharmony_ci hfld |= ICE_FLOW_HASH_FLD_UDP_DST_PORT; 25218c2ecf20Sopenharmony_ci break; 25228c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 25238c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 25248c2ecf20Sopenharmony_ci if (nfc->data & RXH_L4_B_0_1) 25258c2ecf20Sopenharmony_ci hfld |= ICE_FLOW_HASH_FLD_SCTP_SRC_PORT; 25268c2ecf20Sopenharmony_ci if (nfc->data & RXH_L4_B_2_3) 25278c2ecf20Sopenharmony_ci hfld |= ICE_FLOW_HASH_FLD_SCTP_DST_PORT; 25288c2ecf20Sopenharmony_ci break; 25298c2ecf20Sopenharmony_ci default: 25308c2ecf20Sopenharmony_ci break; 25318c2ecf20Sopenharmony_ci } 25328c2ecf20Sopenharmony_ci } 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci return hfld; 25358c2ecf20Sopenharmony_ci} 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci/** 25388c2ecf20Sopenharmony_ci * ice_set_rss_hash_opt - Enable/Disable flow types for RSS hash 25398c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 25408c2ecf20Sopenharmony_ci * @nfc: ethtool rxnfc command 25418c2ecf20Sopenharmony_ci * 25428c2ecf20Sopenharmony_ci * Returns Success if the flow input set is supported. 25438c2ecf20Sopenharmony_ci */ 25448c2ecf20Sopenharmony_cistatic int 25458c2ecf20Sopenharmony_ciice_set_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc) 25468c2ecf20Sopenharmony_ci{ 25478c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 25488c2ecf20Sopenharmony_ci enum ice_status status; 25498c2ecf20Sopenharmony_ci struct device *dev; 25508c2ecf20Sopenharmony_ci u64 hashed_flds; 25518c2ecf20Sopenharmony_ci u32 hdrs; 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 25548c2ecf20Sopenharmony_ci if (ice_is_safe_mode(pf)) { 25558c2ecf20Sopenharmony_ci dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n", 25568c2ecf20Sopenharmony_ci vsi->vsi_num); 25578c2ecf20Sopenharmony_ci return -EINVAL; 25588c2ecf20Sopenharmony_ci } 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci hashed_flds = ice_parse_hash_flds(nfc); 25618c2ecf20Sopenharmony_ci if (hashed_flds == ICE_HASH_INVALID) { 25628c2ecf20Sopenharmony_ci dev_dbg(dev, "Invalid hash fields, vsi num = %d\n", 25638c2ecf20Sopenharmony_ci vsi->vsi_num); 25648c2ecf20Sopenharmony_ci return -EINVAL; 25658c2ecf20Sopenharmony_ci } 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci hdrs = ice_parse_hdrs(nfc); 25688c2ecf20Sopenharmony_ci if (hdrs == ICE_FLOW_SEG_HDR_NONE) { 25698c2ecf20Sopenharmony_ci dev_dbg(dev, "Header type is not valid, vsi num = %d\n", 25708c2ecf20Sopenharmony_ci vsi->vsi_num); 25718c2ecf20Sopenharmony_ci return -EINVAL; 25728c2ecf20Sopenharmony_ci } 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci status = ice_add_rss_cfg(&pf->hw, vsi->idx, hashed_flds, hdrs); 25758c2ecf20Sopenharmony_ci if (status) { 25768c2ecf20Sopenharmony_ci dev_dbg(dev, "ice_add_rss_cfg failed, vsi num = %d, error = %s\n", 25778c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 25788c2ecf20Sopenharmony_ci return -EINVAL; 25798c2ecf20Sopenharmony_ci } 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci return 0; 25828c2ecf20Sopenharmony_ci} 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci/** 25858c2ecf20Sopenharmony_ci * ice_get_rss_hash_opt - Retrieve hash fields for a given flow-type 25868c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 25878c2ecf20Sopenharmony_ci * @nfc: ethtool rxnfc command 25888c2ecf20Sopenharmony_ci */ 25898c2ecf20Sopenharmony_cistatic void 25908c2ecf20Sopenharmony_ciice_get_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc) 25918c2ecf20Sopenharmony_ci{ 25928c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 25938c2ecf20Sopenharmony_ci struct device *dev; 25948c2ecf20Sopenharmony_ci u64 hash_flds; 25958c2ecf20Sopenharmony_ci u32 hdrs; 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci nfc->data = 0; 26008c2ecf20Sopenharmony_ci if (ice_is_safe_mode(pf)) { 26018c2ecf20Sopenharmony_ci dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n", 26028c2ecf20Sopenharmony_ci vsi->vsi_num); 26038c2ecf20Sopenharmony_ci return; 26048c2ecf20Sopenharmony_ci } 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci hdrs = ice_parse_hdrs(nfc); 26078c2ecf20Sopenharmony_ci if (hdrs == ICE_FLOW_SEG_HDR_NONE) { 26088c2ecf20Sopenharmony_ci dev_dbg(dev, "Header type is not valid, vsi num = %d\n", 26098c2ecf20Sopenharmony_ci vsi->vsi_num); 26108c2ecf20Sopenharmony_ci return; 26118c2ecf20Sopenharmony_ci } 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci hash_flds = ice_get_rss_cfg(&pf->hw, vsi->idx, hdrs); 26148c2ecf20Sopenharmony_ci if (hash_flds == ICE_HASH_INVALID) { 26158c2ecf20Sopenharmony_ci dev_dbg(dev, "No hash fields found for the given header type, vsi num = %d\n", 26168c2ecf20Sopenharmony_ci vsi->vsi_num); 26178c2ecf20Sopenharmony_ci return; 26188c2ecf20Sopenharmony_ci } 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci if (hash_flds & ICE_FLOW_HASH_FLD_IPV4_SA || 26218c2ecf20Sopenharmony_ci hash_flds & ICE_FLOW_HASH_FLD_IPV6_SA) 26228c2ecf20Sopenharmony_ci nfc->data |= (u64)RXH_IP_SRC; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci if (hash_flds & ICE_FLOW_HASH_FLD_IPV4_DA || 26258c2ecf20Sopenharmony_ci hash_flds & ICE_FLOW_HASH_FLD_IPV6_DA) 26268c2ecf20Sopenharmony_ci nfc->data |= (u64)RXH_IP_DST; 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci if (hash_flds & ICE_FLOW_HASH_FLD_TCP_SRC_PORT || 26298c2ecf20Sopenharmony_ci hash_flds & ICE_FLOW_HASH_FLD_UDP_SRC_PORT || 26308c2ecf20Sopenharmony_ci hash_flds & ICE_FLOW_HASH_FLD_SCTP_SRC_PORT) 26318c2ecf20Sopenharmony_ci nfc->data |= (u64)RXH_L4_B_0_1; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci if (hash_flds & ICE_FLOW_HASH_FLD_TCP_DST_PORT || 26348c2ecf20Sopenharmony_ci hash_flds & ICE_FLOW_HASH_FLD_UDP_DST_PORT || 26358c2ecf20Sopenharmony_ci hash_flds & ICE_FLOW_HASH_FLD_SCTP_DST_PORT) 26368c2ecf20Sopenharmony_ci nfc->data |= (u64)RXH_L4_B_2_3; 26378c2ecf20Sopenharmony_ci} 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci/** 26408c2ecf20Sopenharmony_ci * ice_set_rxnfc - command to set Rx flow rules. 26418c2ecf20Sopenharmony_ci * @netdev: network interface device structure 26428c2ecf20Sopenharmony_ci * @cmd: ethtool rxnfc command 26438c2ecf20Sopenharmony_ci * 26448c2ecf20Sopenharmony_ci * Returns 0 for success and negative values for errors 26458c2ecf20Sopenharmony_ci */ 26468c2ecf20Sopenharmony_cistatic int ice_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) 26478c2ecf20Sopenharmony_ci{ 26488c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 26498c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci switch (cmd->cmd) { 26528c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 26538c2ecf20Sopenharmony_ci return ice_add_fdir_ethtool(vsi, cmd); 26548c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 26558c2ecf20Sopenharmony_ci return ice_del_fdir_ethtool(vsi, cmd); 26568c2ecf20Sopenharmony_ci case ETHTOOL_SRXFH: 26578c2ecf20Sopenharmony_ci return ice_set_rss_hash_opt(vsi, cmd); 26588c2ecf20Sopenharmony_ci default: 26598c2ecf20Sopenharmony_ci break; 26608c2ecf20Sopenharmony_ci } 26618c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 26628c2ecf20Sopenharmony_ci} 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci/** 26658c2ecf20Sopenharmony_ci * ice_get_rxnfc - command to get Rx flow classification rules 26668c2ecf20Sopenharmony_ci * @netdev: network interface device structure 26678c2ecf20Sopenharmony_ci * @cmd: ethtool rxnfc command 26688c2ecf20Sopenharmony_ci * @rule_locs: buffer to rturn Rx flow classification rules 26698c2ecf20Sopenharmony_ci * 26708c2ecf20Sopenharmony_ci * Returns Success if the command is supported. 26718c2ecf20Sopenharmony_ci */ 26728c2ecf20Sopenharmony_cistatic int 26738c2ecf20Sopenharmony_ciice_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, 26748c2ecf20Sopenharmony_ci u32 __always_unused *rule_locs) 26758c2ecf20Sopenharmony_ci{ 26768c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 26778c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 26788c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 26798c2ecf20Sopenharmony_ci struct ice_hw *hw; 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci hw = &vsi->back->hw; 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci switch (cmd->cmd) { 26848c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 26858c2ecf20Sopenharmony_ci cmd->data = vsi->rss_size; 26868c2ecf20Sopenharmony_ci ret = 0; 26878c2ecf20Sopenharmony_ci break; 26888c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 26898c2ecf20Sopenharmony_ci cmd->rule_cnt = hw->fdir_active_fltr; 26908c2ecf20Sopenharmony_ci /* report total rule count */ 26918c2ecf20Sopenharmony_ci cmd->data = ice_get_fdir_cnt_all(hw); 26928c2ecf20Sopenharmony_ci ret = 0; 26938c2ecf20Sopenharmony_ci break; 26948c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 26958c2ecf20Sopenharmony_ci ret = ice_get_ethtool_fdir_entry(hw, cmd); 26968c2ecf20Sopenharmony_ci break; 26978c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 26988c2ecf20Sopenharmony_ci ret = ice_get_fdir_fltr_ids(hw, cmd, (u32 *)rule_locs); 26998c2ecf20Sopenharmony_ci break; 27008c2ecf20Sopenharmony_ci case ETHTOOL_GRXFH: 27018c2ecf20Sopenharmony_ci ice_get_rss_hash_opt(vsi, cmd); 27028c2ecf20Sopenharmony_ci ret = 0; 27038c2ecf20Sopenharmony_ci break; 27048c2ecf20Sopenharmony_ci default: 27058c2ecf20Sopenharmony_ci break; 27068c2ecf20Sopenharmony_ci } 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci return ret; 27098c2ecf20Sopenharmony_ci} 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_cistatic void 27128c2ecf20Sopenharmony_ciice_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) 27138c2ecf20Sopenharmony_ci{ 27148c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 27158c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci ring->rx_max_pending = ICE_MAX_NUM_DESC; 27188c2ecf20Sopenharmony_ci ring->tx_max_pending = ICE_MAX_NUM_DESC; 27198c2ecf20Sopenharmony_ci ring->rx_pending = vsi->rx_rings[0]->count; 27208c2ecf20Sopenharmony_ci ring->tx_pending = vsi->tx_rings[0]->count; 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci /* Rx mini and jumbo rings are not supported */ 27238c2ecf20Sopenharmony_ci ring->rx_mini_max_pending = 0; 27248c2ecf20Sopenharmony_ci ring->rx_jumbo_max_pending = 0; 27258c2ecf20Sopenharmony_ci ring->rx_mini_pending = 0; 27268c2ecf20Sopenharmony_ci ring->rx_jumbo_pending = 0; 27278c2ecf20Sopenharmony_ci} 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_cistatic int 27308c2ecf20Sopenharmony_ciice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) 27318c2ecf20Sopenharmony_ci{ 27328c2ecf20Sopenharmony_ci struct ice_ring *tx_rings = NULL, *rx_rings = NULL; 27338c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 27348c2ecf20Sopenharmony_ci struct ice_ring *xdp_rings = NULL; 27358c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 27368c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 27378c2ecf20Sopenharmony_ci int i, timeout = 50, err = 0; 27388c2ecf20Sopenharmony_ci u16 new_rx_cnt, new_tx_cnt; 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci if (ring->tx_pending > ICE_MAX_NUM_DESC || 27418c2ecf20Sopenharmony_ci ring->tx_pending < ICE_MIN_NUM_DESC || 27428c2ecf20Sopenharmony_ci ring->rx_pending > ICE_MAX_NUM_DESC || 27438c2ecf20Sopenharmony_ci ring->rx_pending < ICE_MIN_NUM_DESC) { 27448c2ecf20Sopenharmony_ci netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n", 27458c2ecf20Sopenharmony_ci ring->tx_pending, ring->rx_pending, 27468c2ecf20Sopenharmony_ci ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC, 27478c2ecf20Sopenharmony_ci ICE_REQ_DESC_MULTIPLE); 27488c2ecf20Sopenharmony_ci return -EINVAL; 27498c2ecf20Sopenharmony_ci } 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci new_tx_cnt = ALIGN(ring->tx_pending, ICE_REQ_DESC_MULTIPLE); 27528c2ecf20Sopenharmony_ci if (new_tx_cnt != ring->tx_pending) 27538c2ecf20Sopenharmony_ci netdev_info(netdev, "Requested Tx descriptor count rounded up to %d\n", 27548c2ecf20Sopenharmony_ci new_tx_cnt); 27558c2ecf20Sopenharmony_ci new_rx_cnt = ALIGN(ring->rx_pending, ICE_REQ_DESC_MULTIPLE); 27568c2ecf20Sopenharmony_ci if (new_rx_cnt != ring->rx_pending) 27578c2ecf20Sopenharmony_ci netdev_info(netdev, "Requested Rx descriptor count rounded up to %d\n", 27588c2ecf20Sopenharmony_ci new_rx_cnt); 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci /* if nothing to do return success */ 27618c2ecf20Sopenharmony_ci if (new_tx_cnt == vsi->tx_rings[0]->count && 27628c2ecf20Sopenharmony_ci new_rx_cnt == vsi->rx_rings[0]->count) { 27638c2ecf20Sopenharmony_ci netdev_dbg(netdev, "Nothing to change, descriptor count is same as requested\n"); 27648c2ecf20Sopenharmony_ci return 0; 27658c2ecf20Sopenharmony_ci } 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci /* If there is a AF_XDP UMEM attached to any of Rx rings, 27688c2ecf20Sopenharmony_ci * disallow changing the number of descriptors -- regardless 27698c2ecf20Sopenharmony_ci * if the netdev is running or not. 27708c2ecf20Sopenharmony_ci */ 27718c2ecf20Sopenharmony_ci if (ice_xsk_any_rx_ring_ena(vsi)) 27728c2ecf20Sopenharmony_ci return -EBUSY; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci while (test_and_set_bit(__ICE_CFG_BUSY, pf->state)) { 27758c2ecf20Sopenharmony_ci timeout--; 27768c2ecf20Sopenharmony_ci if (!timeout) 27778c2ecf20Sopenharmony_ci return -EBUSY; 27788c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 27798c2ecf20Sopenharmony_ci } 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci /* set for the next time the netdev is started */ 27828c2ecf20Sopenharmony_ci if (!netif_running(vsi->netdev)) { 27838c2ecf20Sopenharmony_ci for (i = 0; i < vsi->alloc_txq; i++) 27848c2ecf20Sopenharmony_ci vsi->tx_rings[i]->count = new_tx_cnt; 27858c2ecf20Sopenharmony_ci for (i = 0; i < vsi->alloc_rxq; i++) 27868c2ecf20Sopenharmony_ci vsi->rx_rings[i]->count = new_rx_cnt; 27878c2ecf20Sopenharmony_ci if (ice_is_xdp_ena_vsi(vsi)) 27888c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_xdp_txq; i++) 27898c2ecf20Sopenharmony_ci vsi->xdp_rings[i]->count = new_tx_cnt; 27908c2ecf20Sopenharmony_ci vsi->num_tx_desc = (u16)new_tx_cnt; 27918c2ecf20Sopenharmony_ci vsi->num_rx_desc = (u16)new_rx_cnt; 27928c2ecf20Sopenharmony_ci netdev_dbg(netdev, "Link is down, descriptor count change happens when link is brought up\n"); 27938c2ecf20Sopenharmony_ci goto done; 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci if (new_tx_cnt == vsi->tx_rings[0]->count) 27978c2ecf20Sopenharmony_ci goto process_rx; 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci /* alloc updated Tx resources */ 28008c2ecf20Sopenharmony_ci netdev_info(netdev, "Changing Tx descriptor count from %d to %d\n", 28018c2ecf20Sopenharmony_ci vsi->tx_rings[0]->count, new_tx_cnt); 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci tx_rings = kcalloc(vsi->num_txq, sizeof(*tx_rings), GFP_KERNEL); 28048c2ecf20Sopenharmony_ci if (!tx_rings) { 28058c2ecf20Sopenharmony_ci err = -ENOMEM; 28068c2ecf20Sopenharmony_ci goto done; 28078c2ecf20Sopenharmony_ci } 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci ice_for_each_txq(vsi, i) { 28108c2ecf20Sopenharmony_ci /* clone ring and setup updated count */ 28118c2ecf20Sopenharmony_ci tx_rings[i] = *vsi->tx_rings[i]; 28128c2ecf20Sopenharmony_ci tx_rings[i].count = new_tx_cnt; 28138c2ecf20Sopenharmony_ci tx_rings[i].desc = NULL; 28148c2ecf20Sopenharmony_ci tx_rings[i].tx_buf = NULL; 28158c2ecf20Sopenharmony_ci err = ice_setup_tx_ring(&tx_rings[i]); 28168c2ecf20Sopenharmony_ci if (err) { 28178c2ecf20Sopenharmony_ci while (i--) 28188c2ecf20Sopenharmony_ci ice_clean_tx_ring(&tx_rings[i]); 28198c2ecf20Sopenharmony_ci kfree(tx_rings); 28208c2ecf20Sopenharmony_ci goto done; 28218c2ecf20Sopenharmony_ci } 28228c2ecf20Sopenharmony_ci } 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci if (!ice_is_xdp_ena_vsi(vsi)) 28258c2ecf20Sopenharmony_ci goto process_rx; 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci /* alloc updated XDP resources */ 28288c2ecf20Sopenharmony_ci netdev_info(netdev, "Changing XDP descriptor count from %d to %d\n", 28298c2ecf20Sopenharmony_ci vsi->xdp_rings[0]->count, new_tx_cnt); 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci xdp_rings = kcalloc(vsi->num_xdp_txq, sizeof(*xdp_rings), GFP_KERNEL); 28328c2ecf20Sopenharmony_ci if (!xdp_rings) { 28338c2ecf20Sopenharmony_ci err = -ENOMEM; 28348c2ecf20Sopenharmony_ci goto free_tx; 28358c2ecf20Sopenharmony_ci } 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_xdp_txq; i++) { 28388c2ecf20Sopenharmony_ci /* clone ring and setup updated count */ 28398c2ecf20Sopenharmony_ci xdp_rings[i] = *vsi->xdp_rings[i]; 28408c2ecf20Sopenharmony_ci xdp_rings[i].count = new_tx_cnt; 28418c2ecf20Sopenharmony_ci xdp_rings[i].desc = NULL; 28428c2ecf20Sopenharmony_ci xdp_rings[i].tx_buf = NULL; 28438c2ecf20Sopenharmony_ci err = ice_setup_tx_ring(&xdp_rings[i]); 28448c2ecf20Sopenharmony_ci if (err) { 28458c2ecf20Sopenharmony_ci while (i--) 28468c2ecf20Sopenharmony_ci ice_clean_tx_ring(&xdp_rings[i]); 28478c2ecf20Sopenharmony_ci kfree(xdp_rings); 28488c2ecf20Sopenharmony_ci goto free_tx; 28498c2ecf20Sopenharmony_ci } 28508c2ecf20Sopenharmony_ci ice_set_ring_xdp(&xdp_rings[i]); 28518c2ecf20Sopenharmony_ci } 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ciprocess_rx: 28548c2ecf20Sopenharmony_ci if (new_rx_cnt == vsi->rx_rings[0]->count) 28558c2ecf20Sopenharmony_ci goto process_link; 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci /* alloc updated Rx resources */ 28588c2ecf20Sopenharmony_ci netdev_info(netdev, "Changing Rx descriptor count from %d to %d\n", 28598c2ecf20Sopenharmony_ci vsi->rx_rings[0]->count, new_rx_cnt); 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci rx_rings = kcalloc(vsi->num_rxq, sizeof(*rx_rings), GFP_KERNEL); 28628c2ecf20Sopenharmony_ci if (!rx_rings) { 28638c2ecf20Sopenharmony_ci err = -ENOMEM; 28648c2ecf20Sopenharmony_ci goto done; 28658c2ecf20Sopenharmony_ci } 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci ice_for_each_rxq(vsi, i) { 28688c2ecf20Sopenharmony_ci /* clone ring and setup updated count */ 28698c2ecf20Sopenharmony_ci rx_rings[i] = *vsi->rx_rings[i]; 28708c2ecf20Sopenharmony_ci rx_rings[i].count = new_rx_cnt; 28718c2ecf20Sopenharmony_ci rx_rings[i].desc = NULL; 28728c2ecf20Sopenharmony_ci rx_rings[i].rx_buf = NULL; 28738c2ecf20Sopenharmony_ci /* this is to allow wr32 to have something to write to 28748c2ecf20Sopenharmony_ci * during early allocation of Rx buffers 28758c2ecf20Sopenharmony_ci */ 28768c2ecf20Sopenharmony_ci rx_rings[i].tail = vsi->back->hw.hw_addr + PRTGEN_STATUS; 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci err = ice_setup_rx_ring(&rx_rings[i]); 28798c2ecf20Sopenharmony_ci if (err) 28808c2ecf20Sopenharmony_ci goto rx_unwind; 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci /* allocate Rx buffers */ 28838c2ecf20Sopenharmony_ci err = ice_alloc_rx_bufs(&rx_rings[i], 28848c2ecf20Sopenharmony_ci ICE_DESC_UNUSED(&rx_rings[i])); 28858c2ecf20Sopenharmony_cirx_unwind: 28868c2ecf20Sopenharmony_ci if (err) { 28878c2ecf20Sopenharmony_ci while (i) { 28888c2ecf20Sopenharmony_ci i--; 28898c2ecf20Sopenharmony_ci ice_free_rx_ring(&rx_rings[i]); 28908c2ecf20Sopenharmony_ci } 28918c2ecf20Sopenharmony_ci kfree(rx_rings); 28928c2ecf20Sopenharmony_ci err = -ENOMEM; 28938c2ecf20Sopenharmony_ci goto free_tx; 28948c2ecf20Sopenharmony_ci } 28958c2ecf20Sopenharmony_ci } 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ciprocess_link: 28988c2ecf20Sopenharmony_ci /* Bring interface down, copy in the new ring info, then restore the 28998c2ecf20Sopenharmony_ci * interface. if VSI is up, bring it down and then back up 29008c2ecf20Sopenharmony_ci */ 29018c2ecf20Sopenharmony_ci if (!test_and_set_bit(__ICE_DOWN, vsi->state)) { 29028c2ecf20Sopenharmony_ci ice_down(vsi); 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci if (tx_rings) { 29058c2ecf20Sopenharmony_ci ice_for_each_txq(vsi, i) { 29068c2ecf20Sopenharmony_ci ice_free_tx_ring(vsi->tx_rings[i]); 29078c2ecf20Sopenharmony_ci *vsi->tx_rings[i] = tx_rings[i]; 29088c2ecf20Sopenharmony_ci } 29098c2ecf20Sopenharmony_ci kfree(tx_rings); 29108c2ecf20Sopenharmony_ci } 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci if (rx_rings) { 29138c2ecf20Sopenharmony_ci ice_for_each_rxq(vsi, i) { 29148c2ecf20Sopenharmony_ci ice_free_rx_ring(vsi->rx_rings[i]); 29158c2ecf20Sopenharmony_ci /* copy the real tail offset */ 29168c2ecf20Sopenharmony_ci rx_rings[i].tail = vsi->rx_rings[i]->tail; 29178c2ecf20Sopenharmony_ci /* this is to fake out the allocation routine 29188c2ecf20Sopenharmony_ci * into thinking it has to realloc everything 29198c2ecf20Sopenharmony_ci * but the recycling logic will let us re-use 29208c2ecf20Sopenharmony_ci * the buffers allocated above 29218c2ecf20Sopenharmony_ci */ 29228c2ecf20Sopenharmony_ci rx_rings[i].next_to_use = 0; 29238c2ecf20Sopenharmony_ci rx_rings[i].next_to_clean = 0; 29248c2ecf20Sopenharmony_ci rx_rings[i].next_to_alloc = 0; 29258c2ecf20Sopenharmony_ci *vsi->rx_rings[i] = rx_rings[i]; 29268c2ecf20Sopenharmony_ci } 29278c2ecf20Sopenharmony_ci kfree(rx_rings); 29288c2ecf20Sopenharmony_ci } 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_ci if (xdp_rings) { 29318c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_xdp_txq; i++) { 29328c2ecf20Sopenharmony_ci ice_free_tx_ring(vsi->xdp_rings[i]); 29338c2ecf20Sopenharmony_ci *vsi->xdp_rings[i] = xdp_rings[i]; 29348c2ecf20Sopenharmony_ci } 29358c2ecf20Sopenharmony_ci kfree(xdp_rings); 29368c2ecf20Sopenharmony_ci } 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci vsi->num_tx_desc = new_tx_cnt; 29398c2ecf20Sopenharmony_ci vsi->num_rx_desc = new_rx_cnt; 29408c2ecf20Sopenharmony_ci ice_up(vsi); 29418c2ecf20Sopenharmony_ci } 29428c2ecf20Sopenharmony_ci goto done; 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_cifree_tx: 29458c2ecf20Sopenharmony_ci /* error cleanup if the Rx allocations failed after getting Tx */ 29468c2ecf20Sopenharmony_ci if (tx_rings) { 29478c2ecf20Sopenharmony_ci ice_for_each_txq(vsi, i) 29488c2ecf20Sopenharmony_ci ice_free_tx_ring(&tx_rings[i]); 29498c2ecf20Sopenharmony_ci kfree(tx_rings); 29508c2ecf20Sopenharmony_ci } 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_cidone: 29538c2ecf20Sopenharmony_ci clear_bit(__ICE_CFG_BUSY, pf->state); 29548c2ecf20Sopenharmony_ci return err; 29558c2ecf20Sopenharmony_ci} 29568c2ecf20Sopenharmony_ci 29578c2ecf20Sopenharmony_ci/** 29588c2ecf20Sopenharmony_ci * ice_get_pauseparam - Get Flow Control status 29598c2ecf20Sopenharmony_ci * @netdev: network interface device structure 29608c2ecf20Sopenharmony_ci * @pause: ethernet pause (flow control) parameters 29618c2ecf20Sopenharmony_ci * 29628c2ecf20Sopenharmony_ci * Get requested flow control status from PHY capability. 29638c2ecf20Sopenharmony_ci * If autoneg is true, then ethtool will send the ETHTOOL_GSET ioctl which 29648c2ecf20Sopenharmony_ci * is handled by ice_get_link_ksettings. ice_get_link_ksettings will report 29658c2ecf20Sopenharmony_ci * the negotiated Rx/Tx pause via lp_advertising. 29668c2ecf20Sopenharmony_ci */ 29678c2ecf20Sopenharmony_cistatic void 29688c2ecf20Sopenharmony_ciice_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) 29698c2ecf20Sopenharmony_ci{ 29708c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 29718c2ecf20Sopenharmony_ci struct ice_port_info *pi = np->vsi->port_info; 29728c2ecf20Sopenharmony_ci struct ice_aqc_get_phy_caps_data *pcaps; 29738c2ecf20Sopenharmony_ci struct ice_dcbx_cfg *dcbx_cfg; 29748c2ecf20Sopenharmony_ci enum ice_status status; 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ci /* Initialize pause params */ 29778c2ecf20Sopenharmony_ci pause->rx_pause = 0; 29788c2ecf20Sopenharmony_ci pause->tx_pause = 0; 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg; 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); 29838c2ecf20Sopenharmony_ci if (!pcaps) 29848c2ecf20Sopenharmony_ci return; 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci /* Get current PHY config */ 29878c2ecf20Sopenharmony_ci status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps, 29888c2ecf20Sopenharmony_ci NULL); 29898c2ecf20Sopenharmony_ci if (status) 29908c2ecf20Sopenharmony_ci goto out; 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci pause->autoneg = ice_is_phy_caps_an_enabled(pcaps) ? AUTONEG_ENABLE : 29938c2ecf20Sopenharmony_ci AUTONEG_DISABLE; 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci if (dcbx_cfg->pfc.pfcena) 29968c2ecf20Sopenharmony_ci /* PFC enabled so report LFC as off */ 29978c2ecf20Sopenharmony_ci goto out; 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci if (pcaps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) 30008c2ecf20Sopenharmony_ci pause->tx_pause = 1; 30018c2ecf20Sopenharmony_ci if (pcaps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE) 30028c2ecf20Sopenharmony_ci pause->rx_pause = 1; 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ciout: 30058c2ecf20Sopenharmony_ci kfree(pcaps); 30068c2ecf20Sopenharmony_ci} 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci/** 30098c2ecf20Sopenharmony_ci * ice_set_pauseparam - Set Flow Control parameter 30108c2ecf20Sopenharmony_ci * @netdev: network interface device structure 30118c2ecf20Sopenharmony_ci * @pause: return Tx/Rx flow control status 30128c2ecf20Sopenharmony_ci */ 30138c2ecf20Sopenharmony_cistatic int 30148c2ecf20Sopenharmony_ciice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) 30158c2ecf20Sopenharmony_ci{ 30168c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 30178c2ecf20Sopenharmony_ci struct ice_aqc_get_phy_caps_data *pcaps; 30188c2ecf20Sopenharmony_ci struct ice_link_status *hw_link_info; 30198c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 30208c2ecf20Sopenharmony_ci struct ice_dcbx_cfg *dcbx_cfg; 30218c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 30228c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 30238c2ecf20Sopenharmony_ci struct ice_port_info *pi; 30248c2ecf20Sopenharmony_ci enum ice_status status; 30258c2ecf20Sopenharmony_ci u8 aq_failures; 30268c2ecf20Sopenharmony_ci bool link_up; 30278c2ecf20Sopenharmony_ci int err = 0; 30288c2ecf20Sopenharmony_ci u32 is_an; 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci pi = vsi->port_info; 30318c2ecf20Sopenharmony_ci hw_link_info = &pi->phy.link_info; 30328c2ecf20Sopenharmony_ci dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg; 30338c2ecf20Sopenharmony_ci link_up = hw_link_info->link_info & ICE_AQ_LINK_UP; 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci /* Changing the port's flow control is not supported if this isn't the 30368c2ecf20Sopenharmony_ci * PF VSI 30378c2ecf20Sopenharmony_ci */ 30388c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_PF) { 30398c2ecf20Sopenharmony_ci netdev_info(netdev, "Changing flow control parameters only supported for PF VSI\n"); 30408c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 30418c2ecf20Sopenharmony_ci } 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_ci /* Get pause param reports configured and negotiated flow control pause 30448c2ecf20Sopenharmony_ci * when ETHTOOL_GLINKSETTINGS is defined. Since ETHTOOL_GLINKSETTINGS is 30458c2ecf20Sopenharmony_ci * defined get pause param pause->autoneg reports SW configured setting, 30468c2ecf20Sopenharmony_ci * so compare pause->autoneg with SW configured to prevent the user from 30478c2ecf20Sopenharmony_ci * using set pause param to chance autoneg. 30488c2ecf20Sopenharmony_ci */ 30498c2ecf20Sopenharmony_ci pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); 30508c2ecf20Sopenharmony_ci if (!pcaps) 30518c2ecf20Sopenharmony_ci return -ENOMEM; 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci /* Get current PHY config */ 30548c2ecf20Sopenharmony_ci status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps, 30558c2ecf20Sopenharmony_ci NULL); 30568c2ecf20Sopenharmony_ci if (status) { 30578c2ecf20Sopenharmony_ci kfree(pcaps); 30588c2ecf20Sopenharmony_ci return -EIO; 30598c2ecf20Sopenharmony_ci } 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci is_an = ice_is_phy_caps_an_enabled(pcaps) ? AUTONEG_ENABLE : 30628c2ecf20Sopenharmony_ci AUTONEG_DISABLE; 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_ci kfree(pcaps); 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ci if (pause->autoneg != is_an) { 30678c2ecf20Sopenharmony_ci netdev_info(netdev, "To change autoneg please use: ethtool -s <dev> autoneg <on|off>\n"); 30688c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 30698c2ecf20Sopenharmony_ci } 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci /* If we have link and don't have autoneg */ 30728c2ecf20Sopenharmony_ci if (!test_bit(__ICE_DOWN, pf->state) && 30738c2ecf20Sopenharmony_ci !(hw_link_info->an_info & ICE_AQ_AN_COMPLETED)) { 30748c2ecf20Sopenharmony_ci /* Send message that it might not necessarily work*/ 30758c2ecf20Sopenharmony_ci netdev_info(netdev, "Autoneg did not complete so changing settings may not result in an actual change.\n"); 30768c2ecf20Sopenharmony_ci } 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci if (dcbx_cfg->pfc.pfcena) { 30798c2ecf20Sopenharmony_ci netdev_info(netdev, "Priority flow control enabled. Cannot set link flow control.\n"); 30808c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 30818c2ecf20Sopenharmony_ci } 30828c2ecf20Sopenharmony_ci if (pause->rx_pause && pause->tx_pause) 30838c2ecf20Sopenharmony_ci pi->fc.req_mode = ICE_FC_FULL; 30848c2ecf20Sopenharmony_ci else if (pause->rx_pause && !pause->tx_pause) 30858c2ecf20Sopenharmony_ci pi->fc.req_mode = ICE_FC_RX_PAUSE; 30868c2ecf20Sopenharmony_ci else if (!pause->rx_pause && pause->tx_pause) 30878c2ecf20Sopenharmony_ci pi->fc.req_mode = ICE_FC_TX_PAUSE; 30888c2ecf20Sopenharmony_ci else if (!pause->rx_pause && !pause->tx_pause) 30898c2ecf20Sopenharmony_ci pi->fc.req_mode = ICE_FC_NONE; 30908c2ecf20Sopenharmony_ci else 30918c2ecf20Sopenharmony_ci return -EINVAL; 30928c2ecf20Sopenharmony_ci 30938c2ecf20Sopenharmony_ci /* Set the FC mode and only restart AN if link is up */ 30948c2ecf20Sopenharmony_ci status = ice_set_fc(pi, &aq_failures, link_up); 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci if (aq_failures & ICE_SET_FC_AQ_FAIL_GET) { 30978c2ecf20Sopenharmony_ci netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with err %s aq_err %s\n", 30988c2ecf20Sopenharmony_ci ice_stat_str(status), 30998c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 31008c2ecf20Sopenharmony_ci err = -EAGAIN; 31018c2ecf20Sopenharmony_ci } else if (aq_failures & ICE_SET_FC_AQ_FAIL_SET) { 31028c2ecf20Sopenharmony_ci netdev_info(netdev, "Set fc failed on the set_phy_config call with err %s aq_err %s\n", 31038c2ecf20Sopenharmony_ci ice_stat_str(status), 31048c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 31058c2ecf20Sopenharmony_ci err = -EAGAIN; 31068c2ecf20Sopenharmony_ci } else if (aq_failures & ICE_SET_FC_AQ_FAIL_UPDATE) { 31078c2ecf20Sopenharmony_ci netdev_info(netdev, "Set fc failed on the get_link_info call with err %s aq_err %s\n", 31088c2ecf20Sopenharmony_ci ice_stat_str(status), 31098c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 31108c2ecf20Sopenharmony_ci err = -EAGAIN; 31118c2ecf20Sopenharmony_ci } 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci return err; 31148c2ecf20Sopenharmony_ci} 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci/** 31178c2ecf20Sopenharmony_ci * ice_get_rxfh_key_size - get the RSS hash key size 31188c2ecf20Sopenharmony_ci * @netdev: network interface device structure 31198c2ecf20Sopenharmony_ci * 31208c2ecf20Sopenharmony_ci * Returns the table size. 31218c2ecf20Sopenharmony_ci */ 31228c2ecf20Sopenharmony_cistatic u32 ice_get_rxfh_key_size(struct net_device __always_unused *netdev) 31238c2ecf20Sopenharmony_ci{ 31248c2ecf20Sopenharmony_ci return ICE_VSIQF_HKEY_ARRAY_SIZE; 31258c2ecf20Sopenharmony_ci} 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci/** 31288c2ecf20Sopenharmony_ci * ice_get_rxfh_indir_size - get the Rx flow hash indirection table size 31298c2ecf20Sopenharmony_ci * @netdev: network interface device structure 31308c2ecf20Sopenharmony_ci * 31318c2ecf20Sopenharmony_ci * Returns the table size. 31328c2ecf20Sopenharmony_ci */ 31338c2ecf20Sopenharmony_cistatic u32 ice_get_rxfh_indir_size(struct net_device *netdev) 31348c2ecf20Sopenharmony_ci{ 31358c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci return np->vsi->rss_table_size; 31388c2ecf20Sopenharmony_ci} 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci/** 31418c2ecf20Sopenharmony_ci * ice_get_rxfh - get the Rx flow hash indirection table 31428c2ecf20Sopenharmony_ci * @netdev: network interface device structure 31438c2ecf20Sopenharmony_ci * @indir: indirection table 31448c2ecf20Sopenharmony_ci * @key: hash key 31458c2ecf20Sopenharmony_ci * @hfunc: hash function 31468c2ecf20Sopenharmony_ci * 31478c2ecf20Sopenharmony_ci * Reads the indirection table directly from the hardware. 31488c2ecf20Sopenharmony_ci */ 31498c2ecf20Sopenharmony_cistatic int 31508c2ecf20Sopenharmony_ciice_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc) 31518c2ecf20Sopenharmony_ci{ 31528c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 31538c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 31548c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 31558c2ecf20Sopenharmony_ci int ret = 0, i; 31568c2ecf20Sopenharmony_ci u8 *lut; 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci if (hfunc) 31598c2ecf20Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_ci if (!indir) 31628c2ecf20Sopenharmony_ci return 0; 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 31658c2ecf20Sopenharmony_ci /* RSS not supported return error here */ 31668c2ecf20Sopenharmony_ci netdev_warn(netdev, "RSS is not configured on this VSI!\n"); 31678c2ecf20Sopenharmony_ci return -EIO; 31688c2ecf20Sopenharmony_ci } 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_ci lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); 31718c2ecf20Sopenharmony_ci if (!lut) 31728c2ecf20Sopenharmony_ci return -ENOMEM; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci if (ice_get_rss(vsi, key, lut, vsi->rss_table_size)) { 31758c2ecf20Sopenharmony_ci ret = -EIO; 31768c2ecf20Sopenharmony_ci goto out; 31778c2ecf20Sopenharmony_ci } 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci for (i = 0; i < vsi->rss_table_size; i++) 31808c2ecf20Sopenharmony_ci indir[i] = (u32)(lut[i]); 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_ciout: 31838c2ecf20Sopenharmony_ci kfree(lut); 31848c2ecf20Sopenharmony_ci return ret; 31858c2ecf20Sopenharmony_ci} 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci/** 31888c2ecf20Sopenharmony_ci * ice_set_rxfh - set the Rx flow hash indirection table 31898c2ecf20Sopenharmony_ci * @netdev: network interface device structure 31908c2ecf20Sopenharmony_ci * @indir: indirection table 31918c2ecf20Sopenharmony_ci * @key: hash key 31928c2ecf20Sopenharmony_ci * @hfunc: hash function 31938c2ecf20Sopenharmony_ci * 31948c2ecf20Sopenharmony_ci * Returns -EINVAL if the table specifies an invalid queue ID, otherwise 31958c2ecf20Sopenharmony_ci * returns 0 after programming the table. 31968c2ecf20Sopenharmony_ci */ 31978c2ecf20Sopenharmony_cistatic int 31988c2ecf20Sopenharmony_ciice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key, 31998c2ecf20Sopenharmony_ci const u8 hfunc) 32008c2ecf20Sopenharmony_ci{ 32018c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 32028c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 32038c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 32048c2ecf20Sopenharmony_ci struct device *dev; 32058c2ecf20Sopenharmony_ci u8 *seed = NULL; 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 32088c2ecf20Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 32098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 32128c2ecf20Sopenharmony_ci /* RSS not supported return error here */ 32138c2ecf20Sopenharmony_ci netdev_warn(netdev, "RSS is not configured on this VSI!\n"); 32148c2ecf20Sopenharmony_ci return -EIO; 32158c2ecf20Sopenharmony_ci } 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci if (key) { 32188c2ecf20Sopenharmony_ci if (!vsi->rss_hkey_user) { 32198c2ecf20Sopenharmony_ci vsi->rss_hkey_user = 32208c2ecf20Sopenharmony_ci devm_kzalloc(dev, ICE_VSIQF_HKEY_ARRAY_SIZE, 32218c2ecf20Sopenharmony_ci GFP_KERNEL); 32228c2ecf20Sopenharmony_ci if (!vsi->rss_hkey_user) 32238c2ecf20Sopenharmony_ci return -ENOMEM; 32248c2ecf20Sopenharmony_ci } 32258c2ecf20Sopenharmony_ci memcpy(vsi->rss_hkey_user, key, ICE_VSIQF_HKEY_ARRAY_SIZE); 32268c2ecf20Sopenharmony_ci seed = vsi->rss_hkey_user; 32278c2ecf20Sopenharmony_ci } 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci if (!vsi->rss_lut_user) { 32308c2ecf20Sopenharmony_ci vsi->rss_lut_user = devm_kzalloc(dev, vsi->rss_table_size, 32318c2ecf20Sopenharmony_ci GFP_KERNEL); 32328c2ecf20Sopenharmony_ci if (!vsi->rss_lut_user) 32338c2ecf20Sopenharmony_ci return -ENOMEM; 32348c2ecf20Sopenharmony_ci } 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci /* Each 32 bits pointed by 'indir' is stored with a lut entry */ 32378c2ecf20Sopenharmony_ci if (indir) { 32388c2ecf20Sopenharmony_ci int i; 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci for (i = 0; i < vsi->rss_table_size; i++) 32418c2ecf20Sopenharmony_ci vsi->rss_lut_user[i] = (u8)(indir[i]); 32428c2ecf20Sopenharmony_ci } else { 32438c2ecf20Sopenharmony_ci ice_fill_rss_lut(vsi->rss_lut_user, vsi->rss_table_size, 32448c2ecf20Sopenharmony_ci vsi->rss_size); 32458c2ecf20Sopenharmony_ci } 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci if (ice_set_rss(vsi, seed, vsi->rss_lut_user, vsi->rss_table_size)) 32488c2ecf20Sopenharmony_ci return -EIO; 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_ci return 0; 32518c2ecf20Sopenharmony_ci} 32528c2ecf20Sopenharmony_ci 32538c2ecf20Sopenharmony_ci/** 32548c2ecf20Sopenharmony_ci * ice_get_max_txq - return the maximum number of Tx queues for in a PF 32558c2ecf20Sopenharmony_ci * @pf: PF structure 32568c2ecf20Sopenharmony_ci */ 32578c2ecf20Sopenharmony_cistatic int ice_get_max_txq(struct ice_pf *pf) 32588c2ecf20Sopenharmony_ci{ 32598c2ecf20Sopenharmony_ci return min3(pf->num_lan_msix, (u16)num_online_cpus(), 32608c2ecf20Sopenharmony_ci (u16)pf->hw.func_caps.common_cap.num_txq); 32618c2ecf20Sopenharmony_ci} 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_ci/** 32648c2ecf20Sopenharmony_ci * ice_get_max_rxq - return the maximum number of Rx queues for in a PF 32658c2ecf20Sopenharmony_ci * @pf: PF structure 32668c2ecf20Sopenharmony_ci */ 32678c2ecf20Sopenharmony_cistatic int ice_get_max_rxq(struct ice_pf *pf) 32688c2ecf20Sopenharmony_ci{ 32698c2ecf20Sopenharmony_ci return min3(pf->num_lan_msix, (u16)num_online_cpus(), 32708c2ecf20Sopenharmony_ci (u16)pf->hw.func_caps.common_cap.num_rxq); 32718c2ecf20Sopenharmony_ci} 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci/** 32748c2ecf20Sopenharmony_ci * ice_get_combined_cnt - return the current number of combined channels 32758c2ecf20Sopenharmony_ci * @vsi: PF VSI pointer 32768c2ecf20Sopenharmony_ci * 32778c2ecf20Sopenharmony_ci * Go through all queue vectors and count ones that have both Rx and Tx ring 32788c2ecf20Sopenharmony_ci * attached 32798c2ecf20Sopenharmony_ci */ 32808c2ecf20Sopenharmony_cistatic u32 ice_get_combined_cnt(struct ice_vsi *vsi) 32818c2ecf20Sopenharmony_ci{ 32828c2ecf20Sopenharmony_ci u32 combined = 0; 32838c2ecf20Sopenharmony_ci int q_idx; 32848c2ecf20Sopenharmony_ci 32858c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, q_idx) { 32868c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[q_idx]; 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci if (q_vector->rx.ring && q_vector->tx.ring) 32898c2ecf20Sopenharmony_ci combined++; 32908c2ecf20Sopenharmony_ci } 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci return combined; 32938c2ecf20Sopenharmony_ci} 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ci/** 32968c2ecf20Sopenharmony_ci * ice_get_channels - get the current and max supported channels 32978c2ecf20Sopenharmony_ci * @dev: network interface device structure 32988c2ecf20Sopenharmony_ci * @ch: ethtool channel data structure 32998c2ecf20Sopenharmony_ci */ 33008c2ecf20Sopenharmony_cistatic void 33018c2ecf20Sopenharmony_ciice_get_channels(struct net_device *dev, struct ethtool_channels *ch) 33028c2ecf20Sopenharmony_ci{ 33038c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(dev); 33048c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 33058c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci /* report maximum channels */ 33088c2ecf20Sopenharmony_ci ch->max_rx = ice_get_max_rxq(pf); 33098c2ecf20Sopenharmony_ci ch->max_tx = ice_get_max_txq(pf); 33108c2ecf20Sopenharmony_ci ch->max_combined = min_t(int, ch->max_rx, ch->max_tx); 33118c2ecf20Sopenharmony_ci 33128c2ecf20Sopenharmony_ci /* report current channels */ 33138c2ecf20Sopenharmony_ci ch->combined_count = ice_get_combined_cnt(vsi); 33148c2ecf20Sopenharmony_ci ch->rx_count = vsi->num_rxq - ch->combined_count; 33158c2ecf20Sopenharmony_ci ch->tx_count = vsi->num_txq - ch->combined_count; 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci /* report other queues */ 33188c2ecf20Sopenharmony_ci ch->other_count = test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1 : 0; 33198c2ecf20Sopenharmony_ci ch->max_other = ch->other_count; 33208c2ecf20Sopenharmony_ci} 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_ci/** 33238c2ecf20Sopenharmony_ci * ice_get_valid_rss_size - return valid number of RSS queues 33248c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 33258c2ecf20Sopenharmony_ci * @new_size: requested RSS queues 33268c2ecf20Sopenharmony_ci */ 33278c2ecf20Sopenharmony_cistatic int ice_get_valid_rss_size(struct ice_hw *hw, int new_size) 33288c2ecf20Sopenharmony_ci{ 33298c2ecf20Sopenharmony_ci struct ice_hw_common_caps *caps = &hw->func_caps.common_cap; 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci return min_t(int, new_size, BIT(caps->rss_table_entry_width)); 33328c2ecf20Sopenharmony_ci} 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci/** 33358c2ecf20Sopenharmony_ci * ice_vsi_set_dflt_rss_lut - set default RSS LUT with requested RSS size 33368c2ecf20Sopenharmony_ci * @vsi: VSI to reconfigure RSS LUT on 33378c2ecf20Sopenharmony_ci * @req_rss_size: requested range of queue numbers for hashing 33388c2ecf20Sopenharmony_ci * 33398c2ecf20Sopenharmony_ci * Set the VSI's RSS parameters, configure the RSS LUT based on these. 33408c2ecf20Sopenharmony_ci */ 33418c2ecf20Sopenharmony_cistatic int ice_vsi_set_dflt_rss_lut(struct ice_vsi *vsi, int req_rss_size) 33428c2ecf20Sopenharmony_ci{ 33438c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 33448c2ecf20Sopenharmony_ci enum ice_status status; 33458c2ecf20Sopenharmony_ci struct device *dev; 33468c2ecf20Sopenharmony_ci struct ice_hw *hw; 33478c2ecf20Sopenharmony_ci int err = 0; 33488c2ecf20Sopenharmony_ci u8 *lut; 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 33518c2ecf20Sopenharmony_ci hw = &pf->hw; 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_ci if (!req_rss_size) 33548c2ecf20Sopenharmony_ci return -EINVAL; 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_ci lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); 33578c2ecf20Sopenharmony_ci if (!lut) 33588c2ecf20Sopenharmony_ci return -ENOMEM; 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci /* set RSS LUT parameters */ 33618c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) 33628c2ecf20Sopenharmony_ci vsi->rss_size = 1; 33638c2ecf20Sopenharmony_ci else 33648c2ecf20Sopenharmony_ci vsi->rss_size = ice_get_valid_rss_size(hw, req_rss_size); 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_ci /* create/set RSS LUT */ 33678c2ecf20Sopenharmony_ci ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size); 33688c2ecf20Sopenharmony_ci status = ice_aq_set_rss_lut(hw, vsi->idx, vsi->rss_lut_type, lut, 33698c2ecf20Sopenharmony_ci vsi->rss_table_size); 33708c2ecf20Sopenharmony_ci if (status) { 33718c2ecf20Sopenharmony_ci dev_err(dev, "Cannot set RSS lut, err %s aq_err %s\n", 33728c2ecf20Sopenharmony_ci ice_stat_str(status), 33738c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 33748c2ecf20Sopenharmony_ci err = -EIO; 33758c2ecf20Sopenharmony_ci } 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci kfree(lut); 33788c2ecf20Sopenharmony_ci return err; 33798c2ecf20Sopenharmony_ci} 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci/** 33828c2ecf20Sopenharmony_ci * ice_set_channels - set the number channels 33838c2ecf20Sopenharmony_ci * @dev: network interface device structure 33848c2ecf20Sopenharmony_ci * @ch: ethtool channel data structure 33858c2ecf20Sopenharmony_ci */ 33868c2ecf20Sopenharmony_cistatic int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch) 33878c2ecf20Sopenharmony_ci{ 33888c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(dev); 33898c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 33908c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 33918c2ecf20Sopenharmony_ci int new_rx = 0, new_tx = 0; 33928c2ecf20Sopenharmony_ci u32 curr_combined; 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci /* do not support changing channels in Safe Mode */ 33958c2ecf20Sopenharmony_ci if (ice_is_safe_mode(pf)) { 33968c2ecf20Sopenharmony_ci netdev_err(dev, "Changing channel in Safe Mode is not supported\n"); 33978c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 33988c2ecf20Sopenharmony_ci } 33998c2ecf20Sopenharmony_ci /* do not support changing other_count */ 34008c2ecf20Sopenharmony_ci if (ch->other_count != (test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1U : 0U)) 34018c2ecf20Sopenharmony_ci return -EINVAL; 34028c2ecf20Sopenharmony_ci 34038c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_FD_ENA, pf->flags) && pf->hw.fdir_active_fltr) { 34048c2ecf20Sopenharmony_ci netdev_err(dev, "Cannot set channels when Flow Director filters are active\n"); 34058c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 34068c2ecf20Sopenharmony_ci } 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_ci curr_combined = ice_get_combined_cnt(vsi); 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ci /* these checks are for cases where user didn't specify a particular 34118c2ecf20Sopenharmony_ci * value on cmd line but we get non-zero value anyway via 34128c2ecf20Sopenharmony_ci * get_channels(); look at ethtool.c in ethtool repository (the user 34138c2ecf20Sopenharmony_ci * space part), particularly, do_schannels() routine 34148c2ecf20Sopenharmony_ci */ 34158c2ecf20Sopenharmony_ci if (ch->rx_count == vsi->num_rxq - curr_combined) 34168c2ecf20Sopenharmony_ci ch->rx_count = 0; 34178c2ecf20Sopenharmony_ci if (ch->tx_count == vsi->num_txq - curr_combined) 34188c2ecf20Sopenharmony_ci ch->tx_count = 0; 34198c2ecf20Sopenharmony_ci if (ch->combined_count == curr_combined) 34208c2ecf20Sopenharmony_ci ch->combined_count = 0; 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_ci if (!(ch->combined_count || (ch->rx_count && ch->tx_count))) { 34238c2ecf20Sopenharmony_ci netdev_err(dev, "Please specify at least 1 Rx and 1 Tx channel\n"); 34248c2ecf20Sopenharmony_ci return -EINVAL; 34258c2ecf20Sopenharmony_ci } 34268c2ecf20Sopenharmony_ci 34278c2ecf20Sopenharmony_ci new_rx = ch->combined_count + ch->rx_count; 34288c2ecf20Sopenharmony_ci new_tx = ch->combined_count + ch->tx_count; 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci if (new_rx > ice_get_max_rxq(pf)) { 34318c2ecf20Sopenharmony_ci netdev_err(dev, "Maximum allowed Rx channels is %d\n", 34328c2ecf20Sopenharmony_ci ice_get_max_rxq(pf)); 34338c2ecf20Sopenharmony_ci return -EINVAL; 34348c2ecf20Sopenharmony_ci } 34358c2ecf20Sopenharmony_ci if (new_tx > ice_get_max_txq(pf)) { 34368c2ecf20Sopenharmony_ci netdev_err(dev, "Maximum allowed Tx channels is %d\n", 34378c2ecf20Sopenharmony_ci ice_get_max_txq(pf)); 34388c2ecf20Sopenharmony_ci return -EINVAL; 34398c2ecf20Sopenharmony_ci } 34408c2ecf20Sopenharmony_ci 34418c2ecf20Sopenharmony_ci ice_vsi_recfg_qs(vsi, new_rx, new_tx); 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_ci if (!netif_is_rxfh_configured(dev)) 34448c2ecf20Sopenharmony_ci return ice_vsi_set_dflt_rss_lut(vsi, new_rx); 34458c2ecf20Sopenharmony_ci 34468c2ecf20Sopenharmony_ci /* Update rss_size due to change in Rx queues */ 34478c2ecf20Sopenharmony_ci vsi->rss_size = ice_get_valid_rss_size(&pf->hw, new_rx); 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci return 0; 34508c2ecf20Sopenharmony_ci} 34518c2ecf20Sopenharmony_ci 34528c2ecf20Sopenharmony_ci/** 34538c2ecf20Sopenharmony_ci * ice_get_wol - get current Wake on LAN configuration 34548c2ecf20Sopenharmony_ci * @netdev: network interface device structure 34558c2ecf20Sopenharmony_ci * @wol: Ethtool structure to retrieve WoL settings 34568c2ecf20Sopenharmony_ci */ 34578c2ecf20Sopenharmony_cistatic void ice_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) 34588c2ecf20Sopenharmony_ci{ 34598c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 34608c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci if (np->vsi->type != ICE_VSI_PF) 34638c2ecf20Sopenharmony_ci netdev_warn(netdev, "Wake on LAN is not supported on this interface!\n"); 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci /* Get WoL settings based on the HW capability */ 34668c2ecf20Sopenharmony_ci if (ice_is_wol_supported(&pf->hw)) { 34678c2ecf20Sopenharmony_ci wol->supported = WAKE_MAGIC; 34688c2ecf20Sopenharmony_ci wol->wolopts = pf->wol_ena ? WAKE_MAGIC : 0; 34698c2ecf20Sopenharmony_ci } else { 34708c2ecf20Sopenharmony_ci wol->supported = 0; 34718c2ecf20Sopenharmony_ci wol->wolopts = 0; 34728c2ecf20Sopenharmony_ci } 34738c2ecf20Sopenharmony_ci} 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci/** 34768c2ecf20Sopenharmony_ci * ice_set_wol - set Wake on LAN on supported device 34778c2ecf20Sopenharmony_ci * @netdev: network interface device structure 34788c2ecf20Sopenharmony_ci * @wol: Ethtool structure to set WoL 34798c2ecf20Sopenharmony_ci */ 34808c2ecf20Sopenharmony_cistatic int ice_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) 34818c2ecf20Sopenharmony_ci{ 34828c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 34838c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 34848c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_PF || !ice_is_wol_supported(&pf->hw)) 34878c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 34888c2ecf20Sopenharmony_ci 34898c2ecf20Sopenharmony_ci /* only magic packet is supported */ 34908c2ecf20Sopenharmony_ci if (wol->wolopts && wol->wolopts != WAKE_MAGIC) 34918c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_ci /* Set WoL only if there is a new value */ 34948c2ecf20Sopenharmony_ci if (pf->wol_ena != !!wol->wolopts) { 34958c2ecf20Sopenharmony_ci pf->wol_ena = !!wol->wolopts; 34968c2ecf20Sopenharmony_ci device_set_wakeup_enable(ice_pf_to_dev(pf), pf->wol_ena); 34978c2ecf20Sopenharmony_ci netdev_dbg(netdev, "WoL magic packet %sabled\n", 34988c2ecf20Sopenharmony_ci pf->wol_ena ? "en" : "dis"); 34998c2ecf20Sopenharmony_ci } 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci return 0; 35028c2ecf20Sopenharmony_ci} 35038c2ecf20Sopenharmony_ci 35048c2ecf20Sopenharmony_cienum ice_container_type { 35058c2ecf20Sopenharmony_ci ICE_RX_CONTAINER, 35068c2ecf20Sopenharmony_ci ICE_TX_CONTAINER, 35078c2ecf20Sopenharmony_ci}; 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci/** 35108c2ecf20Sopenharmony_ci * ice_get_rc_coalesce - get ITR values for specific ring container 35118c2ecf20Sopenharmony_ci * @ec: ethtool structure to fill with driver's coalesce settings 35128c2ecf20Sopenharmony_ci * @c_type: container type, Rx or Tx 35138c2ecf20Sopenharmony_ci * @rc: ring container that the ITR values will come from 35148c2ecf20Sopenharmony_ci * 35158c2ecf20Sopenharmony_ci * Query the device for ice_ring_container specific ITR values. This is 35168c2ecf20Sopenharmony_ci * done per ice_ring_container because each q_vector can have 1 or more rings 35178c2ecf20Sopenharmony_ci * and all of said ring(s) will have the same ITR values. 35188c2ecf20Sopenharmony_ci * 35198c2ecf20Sopenharmony_ci * Returns 0 on success, negative otherwise. 35208c2ecf20Sopenharmony_ci */ 35218c2ecf20Sopenharmony_cistatic int 35228c2ecf20Sopenharmony_ciice_get_rc_coalesce(struct ethtool_coalesce *ec, enum ice_container_type c_type, 35238c2ecf20Sopenharmony_ci struct ice_ring_container *rc) 35248c2ecf20Sopenharmony_ci{ 35258c2ecf20Sopenharmony_ci if (!rc->ring) 35268c2ecf20Sopenharmony_ci return -EINVAL; 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_ci switch (c_type) { 35298c2ecf20Sopenharmony_ci case ICE_RX_CONTAINER: 35308c2ecf20Sopenharmony_ci ec->use_adaptive_rx_coalesce = ITR_IS_DYNAMIC(rc->itr_setting); 35318c2ecf20Sopenharmony_ci ec->rx_coalesce_usecs = rc->itr_setting & ~ICE_ITR_DYNAMIC; 35328c2ecf20Sopenharmony_ci ec->rx_coalesce_usecs_high = rc->ring->q_vector->intrl; 35338c2ecf20Sopenharmony_ci break; 35348c2ecf20Sopenharmony_ci case ICE_TX_CONTAINER: 35358c2ecf20Sopenharmony_ci ec->use_adaptive_tx_coalesce = ITR_IS_DYNAMIC(rc->itr_setting); 35368c2ecf20Sopenharmony_ci ec->tx_coalesce_usecs = rc->itr_setting & ~ICE_ITR_DYNAMIC; 35378c2ecf20Sopenharmony_ci break; 35388c2ecf20Sopenharmony_ci default: 35398c2ecf20Sopenharmony_ci dev_dbg(ice_pf_to_dev(rc->ring->vsi->back), "Invalid c_type %d\n", c_type); 35408c2ecf20Sopenharmony_ci return -EINVAL; 35418c2ecf20Sopenharmony_ci } 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_ci return 0; 35448c2ecf20Sopenharmony_ci} 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_ci/** 35478c2ecf20Sopenharmony_ci * ice_get_q_coalesce - get a queue's ITR/INTRL (coalesce) settings 35488c2ecf20Sopenharmony_ci * @vsi: VSI associated to the queue for getting ITR/INTRL (coalesce) settings 35498c2ecf20Sopenharmony_ci * @ec: coalesce settings to program the device with 35508c2ecf20Sopenharmony_ci * @q_num: update ITR/INTRL (coalesce) settings for this queue number/index 35518c2ecf20Sopenharmony_ci * 35528c2ecf20Sopenharmony_ci * Return 0 on success, and negative under the following conditions: 35538c2ecf20Sopenharmony_ci * 1. Getting Tx or Rx ITR/INTRL (coalesce) settings failed. 35548c2ecf20Sopenharmony_ci * 2. The q_num passed in is not a valid number/index for Tx and Rx rings. 35558c2ecf20Sopenharmony_ci */ 35568c2ecf20Sopenharmony_cistatic int 35578c2ecf20Sopenharmony_ciice_get_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num) 35588c2ecf20Sopenharmony_ci{ 35598c2ecf20Sopenharmony_ci if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { 35608c2ecf20Sopenharmony_ci if (ice_get_rc_coalesce(ec, ICE_RX_CONTAINER, 35618c2ecf20Sopenharmony_ci &vsi->rx_rings[q_num]->q_vector->rx)) 35628c2ecf20Sopenharmony_ci return -EINVAL; 35638c2ecf20Sopenharmony_ci if (ice_get_rc_coalesce(ec, ICE_TX_CONTAINER, 35648c2ecf20Sopenharmony_ci &vsi->tx_rings[q_num]->q_vector->tx)) 35658c2ecf20Sopenharmony_ci return -EINVAL; 35668c2ecf20Sopenharmony_ci } else if (q_num < vsi->num_rxq) { 35678c2ecf20Sopenharmony_ci if (ice_get_rc_coalesce(ec, ICE_RX_CONTAINER, 35688c2ecf20Sopenharmony_ci &vsi->rx_rings[q_num]->q_vector->rx)) 35698c2ecf20Sopenharmony_ci return -EINVAL; 35708c2ecf20Sopenharmony_ci } else if (q_num < vsi->num_txq) { 35718c2ecf20Sopenharmony_ci if (ice_get_rc_coalesce(ec, ICE_TX_CONTAINER, 35728c2ecf20Sopenharmony_ci &vsi->tx_rings[q_num]->q_vector->tx)) 35738c2ecf20Sopenharmony_ci return -EINVAL; 35748c2ecf20Sopenharmony_ci } else { 35758c2ecf20Sopenharmony_ci return -EINVAL; 35768c2ecf20Sopenharmony_ci } 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci return 0; 35798c2ecf20Sopenharmony_ci} 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci/** 35828c2ecf20Sopenharmony_ci * __ice_get_coalesce - get ITR/INTRL values for the device 35838c2ecf20Sopenharmony_ci * @netdev: pointer to the netdev associated with this query 35848c2ecf20Sopenharmony_ci * @ec: ethtool structure to fill with driver's coalesce settings 35858c2ecf20Sopenharmony_ci * @q_num: queue number to get the coalesce settings for 35868c2ecf20Sopenharmony_ci * 35878c2ecf20Sopenharmony_ci * If the caller passes in a negative q_num then we return coalesce settings 35888c2ecf20Sopenharmony_ci * based on queue number 0, else use the actual q_num passed in. 35898c2ecf20Sopenharmony_ci */ 35908c2ecf20Sopenharmony_cistatic int 35918c2ecf20Sopenharmony_ci__ice_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, 35928c2ecf20Sopenharmony_ci int q_num) 35938c2ecf20Sopenharmony_ci{ 35948c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 35958c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci if (q_num < 0) 35988c2ecf20Sopenharmony_ci q_num = 0; 35998c2ecf20Sopenharmony_ci 36008c2ecf20Sopenharmony_ci if (ice_get_q_coalesce(vsi, ec, q_num)) 36018c2ecf20Sopenharmony_ci return -EINVAL; 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci return 0; 36048c2ecf20Sopenharmony_ci} 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_cistatic int 36078c2ecf20Sopenharmony_ciice_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) 36088c2ecf20Sopenharmony_ci{ 36098c2ecf20Sopenharmony_ci return __ice_get_coalesce(netdev, ec, -1); 36108c2ecf20Sopenharmony_ci} 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_cistatic int 36138c2ecf20Sopenharmony_ciice_get_per_q_coalesce(struct net_device *netdev, u32 q_num, 36148c2ecf20Sopenharmony_ci struct ethtool_coalesce *ec) 36158c2ecf20Sopenharmony_ci{ 36168c2ecf20Sopenharmony_ci return __ice_get_coalesce(netdev, ec, q_num); 36178c2ecf20Sopenharmony_ci} 36188c2ecf20Sopenharmony_ci 36198c2ecf20Sopenharmony_ci/** 36208c2ecf20Sopenharmony_ci * ice_set_rc_coalesce - set ITR values for specific ring container 36218c2ecf20Sopenharmony_ci * @c_type: container type, Rx or Tx 36228c2ecf20Sopenharmony_ci * @ec: ethtool structure from user to update ITR settings 36238c2ecf20Sopenharmony_ci * @rc: ring container that the ITR values will come from 36248c2ecf20Sopenharmony_ci * @vsi: VSI associated to the ring container 36258c2ecf20Sopenharmony_ci * 36268c2ecf20Sopenharmony_ci * Set specific ITR values. This is done per ice_ring_container because each 36278c2ecf20Sopenharmony_ci * q_vector can have 1 or more rings and all of said ring(s) will have the same 36288c2ecf20Sopenharmony_ci * ITR values. 36298c2ecf20Sopenharmony_ci * 36308c2ecf20Sopenharmony_ci * Returns 0 on success, negative otherwise. 36318c2ecf20Sopenharmony_ci */ 36328c2ecf20Sopenharmony_cistatic int 36338c2ecf20Sopenharmony_ciice_set_rc_coalesce(enum ice_container_type c_type, struct ethtool_coalesce *ec, 36348c2ecf20Sopenharmony_ci struct ice_ring_container *rc, struct ice_vsi *vsi) 36358c2ecf20Sopenharmony_ci{ 36368c2ecf20Sopenharmony_ci const char *c_type_str = (c_type == ICE_RX_CONTAINER) ? "rx" : "tx"; 36378c2ecf20Sopenharmony_ci u32 use_adaptive_coalesce, coalesce_usecs; 36388c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 36398c2ecf20Sopenharmony_ci u16 itr_setting; 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_ci if (!rc->ring) 36428c2ecf20Sopenharmony_ci return -EINVAL; 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci switch (c_type) { 36458c2ecf20Sopenharmony_ci case ICE_RX_CONTAINER: 36468c2ecf20Sopenharmony_ci if (ec->rx_coalesce_usecs_high > ICE_MAX_INTRL || 36478c2ecf20Sopenharmony_ci (ec->rx_coalesce_usecs_high && 36488c2ecf20Sopenharmony_ci ec->rx_coalesce_usecs_high < pf->hw.intrl_gran)) { 36498c2ecf20Sopenharmony_ci netdev_info(vsi->netdev, "Invalid value, %s-usecs-high valid values are 0 (disabled), %d-%d\n", 36508c2ecf20Sopenharmony_ci c_type_str, pf->hw.intrl_gran, 36518c2ecf20Sopenharmony_ci ICE_MAX_INTRL); 36528c2ecf20Sopenharmony_ci return -EINVAL; 36538c2ecf20Sopenharmony_ci } 36548c2ecf20Sopenharmony_ci if (ec->rx_coalesce_usecs_high != rc->ring->q_vector->intrl) { 36558c2ecf20Sopenharmony_ci rc->ring->q_vector->intrl = ec->rx_coalesce_usecs_high; 36568c2ecf20Sopenharmony_ci wr32(&pf->hw, GLINT_RATE(rc->ring->q_vector->reg_idx), 36578c2ecf20Sopenharmony_ci ice_intrl_usec_to_reg(ec->rx_coalesce_usecs_high, 36588c2ecf20Sopenharmony_ci pf->hw.intrl_gran)); 36598c2ecf20Sopenharmony_ci } 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci use_adaptive_coalesce = ec->use_adaptive_rx_coalesce; 36628c2ecf20Sopenharmony_ci coalesce_usecs = ec->rx_coalesce_usecs; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci break; 36658c2ecf20Sopenharmony_ci case ICE_TX_CONTAINER: 36668c2ecf20Sopenharmony_ci use_adaptive_coalesce = ec->use_adaptive_tx_coalesce; 36678c2ecf20Sopenharmony_ci coalesce_usecs = ec->tx_coalesce_usecs; 36688c2ecf20Sopenharmony_ci 36698c2ecf20Sopenharmony_ci break; 36708c2ecf20Sopenharmony_ci default: 36718c2ecf20Sopenharmony_ci dev_dbg(ice_pf_to_dev(pf), "Invalid container type %d\n", 36728c2ecf20Sopenharmony_ci c_type); 36738c2ecf20Sopenharmony_ci return -EINVAL; 36748c2ecf20Sopenharmony_ci } 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci itr_setting = rc->itr_setting & ~ICE_ITR_DYNAMIC; 36778c2ecf20Sopenharmony_ci if (coalesce_usecs != itr_setting && use_adaptive_coalesce) { 36788c2ecf20Sopenharmony_ci netdev_info(vsi->netdev, "%s interrupt throttling cannot be changed if adaptive-%s is enabled\n", 36798c2ecf20Sopenharmony_ci c_type_str, c_type_str); 36808c2ecf20Sopenharmony_ci return -EINVAL; 36818c2ecf20Sopenharmony_ci } 36828c2ecf20Sopenharmony_ci 36838c2ecf20Sopenharmony_ci if (coalesce_usecs > ICE_ITR_MAX) { 36848c2ecf20Sopenharmony_ci netdev_info(vsi->netdev, "Invalid value, %s-usecs range is 0-%d\n", 36858c2ecf20Sopenharmony_ci c_type_str, ICE_ITR_MAX); 36868c2ecf20Sopenharmony_ci return -EINVAL; 36878c2ecf20Sopenharmony_ci } 36888c2ecf20Sopenharmony_ci 36898c2ecf20Sopenharmony_ci if (use_adaptive_coalesce) { 36908c2ecf20Sopenharmony_ci rc->itr_setting |= ICE_ITR_DYNAMIC; 36918c2ecf20Sopenharmony_ci } else { 36928c2ecf20Sopenharmony_ci /* save the user set usecs */ 36938c2ecf20Sopenharmony_ci rc->itr_setting = coalesce_usecs; 36948c2ecf20Sopenharmony_ci /* device ITR granularity is in 2 usec increments */ 36958c2ecf20Sopenharmony_ci rc->target_itr = ITR_REG_ALIGN(rc->itr_setting); 36968c2ecf20Sopenharmony_ci } 36978c2ecf20Sopenharmony_ci 36988c2ecf20Sopenharmony_ci return 0; 36998c2ecf20Sopenharmony_ci} 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci/** 37028c2ecf20Sopenharmony_ci * ice_set_q_coalesce - set a queue's ITR/INTRL (coalesce) settings 37038c2ecf20Sopenharmony_ci * @vsi: VSI associated to the queue that need updating 37048c2ecf20Sopenharmony_ci * @ec: coalesce settings to program the device with 37058c2ecf20Sopenharmony_ci * @q_num: update ITR/INTRL (coalesce) settings for this queue number/index 37068c2ecf20Sopenharmony_ci * 37078c2ecf20Sopenharmony_ci * Return 0 on success, and negative under the following conditions: 37088c2ecf20Sopenharmony_ci * 1. Setting Tx or Rx ITR/INTRL (coalesce) settings failed. 37098c2ecf20Sopenharmony_ci * 2. The q_num passed in is not a valid number/index for Tx and Rx rings. 37108c2ecf20Sopenharmony_ci */ 37118c2ecf20Sopenharmony_cistatic int 37128c2ecf20Sopenharmony_ciice_set_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num) 37138c2ecf20Sopenharmony_ci{ 37148c2ecf20Sopenharmony_ci if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { 37158c2ecf20Sopenharmony_ci if (ice_set_rc_coalesce(ICE_RX_CONTAINER, ec, 37168c2ecf20Sopenharmony_ci &vsi->rx_rings[q_num]->q_vector->rx, 37178c2ecf20Sopenharmony_ci vsi)) 37188c2ecf20Sopenharmony_ci return -EINVAL; 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_ci if (ice_set_rc_coalesce(ICE_TX_CONTAINER, ec, 37218c2ecf20Sopenharmony_ci &vsi->tx_rings[q_num]->q_vector->tx, 37228c2ecf20Sopenharmony_ci vsi)) 37238c2ecf20Sopenharmony_ci return -EINVAL; 37248c2ecf20Sopenharmony_ci } else if (q_num < vsi->num_rxq) { 37258c2ecf20Sopenharmony_ci if (ice_set_rc_coalesce(ICE_RX_CONTAINER, ec, 37268c2ecf20Sopenharmony_ci &vsi->rx_rings[q_num]->q_vector->rx, 37278c2ecf20Sopenharmony_ci vsi)) 37288c2ecf20Sopenharmony_ci return -EINVAL; 37298c2ecf20Sopenharmony_ci } else if (q_num < vsi->num_txq) { 37308c2ecf20Sopenharmony_ci if (ice_set_rc_coalesce(ICE_TX_CONTAINER, ec, 37318c2ecf20Sopenharmony_ci &vsi->tx_rings[q_num]->q_vector->tx, 37328c2ecf20Sopenharmony_ci vsi)) 37338c2ecf20Sopenharmony_ci return -EINVAL; 37348c2ecf20Sopenharmony_ci } else { 37358c2ecf20Sopenharmony_ci return -EINVAL; 37368c2ecf20Sopenharmony_ci } 37378c2ecf20Sopenharmony_ci 37388c2ecf20Sopenharmony_ci return 0; 37398c2ecf20Sopenharmony_ci} 37408c2ecf20Sopenharmony_ci 37418c2ecf20Sopenharmony_ci/** 37428c2ecf20Sopenharmony_ci * ice_print_if_odd_usecs - print message if user tries to set odd [tx|rx]-usecs 37438c2ecf20Sopenharmony_ci * @netdev: netdev used for print 37448c2ecf20Sopenharmony_ci * @itr_setting: previous user setting 37458c2ecf20Sopenharmony_ci * @use_adaptive_coalesce: if adaptive coalesce is enabled or being enabled 37468c2ecf20Sopenharmony_ci * @coalesce_usecs: requested value of [tx|rx]-usecs 37478c2ecf20Sopenharmony_ci * @c_type_str: either "rx" or "tx" to match user set field of [tx|rx]-usecs 37488c2ecf20Sopenharmony_ci */ 37498c2ecf20Sopenharmony_cistatic void 37508c2ecf20Sopenharmony_ciice_print_if_odd_usecs(struct net_device *netdev, u16 itr_setting, 37518c2ecf20Sopenharmony_ci u32 use_adaptive_coalesce, u32 coalesce_usecs, 37528c2ecf20Sopenharmony_ci const char *c_type_str) 37538c2ecf20Sopenharmony_ci{ 37548c2ecf20Sopenharmony_ci if (use_adaptive_coalesce) 37558c2ecf20Sopenharmony_ci return; 37568c2ecf20Sopenharmony_ci 37578c2ecf20Sopenharmony_ci itr_setting = ITR_TO_REG(itr_setting); 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci if (itr_setting != coalesce_usecs && (coalesce_usecs % 2)) 37608c2ecf20Sopenharmony_ci netdev_info(netdev, "User set %s-usecs to %d, device only supports even values. Rounding down and attempting to set %s-usecs to %d\n", 37618c2ecf20Sopenharmony_ci c_type_str, coalesce_usecs, c_type_str, 37628c2ecf20Sopenharmony_ci ITR_REG_ALIGN(coalesce_usecs)); 37638c2ecf20Sopenharmony_ci} 37648c2ecf20Sopenharmony_ci 37658c2ecf20Sopenharmony_ci/** 37668c2ecf20Sopenharmony_ci * __ice_set_coalesce - set ITR/INTRL values for the device 37678c2ecf20Sopenharmony_ci * @netdev: pointer to the netdev associated with this query 37688c2ecf20Sopenharmony_ci * @ec: ethtool structure to fill with driver's coalesce settings 37698c2ecf20Sopenharmony_ci * @q_num: queue number to get the coalesce settings for 37708c2ecf20Sopenharmony_ci * 37718c2ecf20Sopenharmony_ci * If the caller passes in a negative q_num then we set the coalesce settings 37728c2ecf20Sopenharmony_ci * for all Tx/Rx queues, else use the actual q_num passed in. 37738c2ecf20Sopenharmony_ci */ 37748c2ecf20Sopenharmony_cistatic int 37758c2ecf20Sopenharmony_ci__ice_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, 37768c2ecf20Sopenharmony_ci int q_num) 37778c2ecf20Sopenharmony_ci{ 37788c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 37798c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_ci if (q_num < 0) { 37828c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[0]; 37838c2ecf20Sopenharmony_ci int v_idx; 37848c2ecf20Sopenharmony_ci 37858c2ecf20Sopenharmony_ci if (q_vector) { 37868c2ecf20Sopenharmony_ci ice_print_if_odd_usecs(netdev, q_vector->rx.itr_setting, 37878c2ecf20Sopenharmony_ci ec->use_adaptive_rx_coalesce, 37888c2ecf20Sopenharmony_ci ec->rx_coalesce_usecs, "rx"); 37898c2ecf20Sopenharmony_ci 37908c2ecf20Sopenharmony_ci ice_print_if_odd_usecs(netdev, q_vector->tx.itr_setting, 37918c2ecf20Sopenharmony_ci ec->use_adaptive_tx_coalesce, 37928c2ecf20Sopenharmony_ci ec->tx_coalesce_usecs, "tx"); 37938c2ecf20Sopenharmony_ci } 37948c2ecf20Sopenharmony_ci 37958c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, v_idx) { 37968c2ecf20Sopenharmony_ci /* In some cases if DCB is configured the num_[rx|tx]q 37978c2ecf20Sopenharmony_ci * can be less than vsi->num_q_vectors. This check 37988c2ecf20Sopenharmony_ci * accounts for that so we don't report a false failure 37998c2ecf20Sopenharmony_ci */ 38008c2ecf20Sopenharmony_ci if (v_idx >= vsi->num_rxq && v_idx >= vsi->num_txq) 38018c2ecf20Sopenharmony_ci goto set_complete; 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci if (ice_set_q_coalesce(vsi, ec, v_idx)) 38048c2ecf20Sopenharmony_ci return -EINVAL; 38058c2ecf20Sopenharmony_ci } 38068c2ecf20Sopenharmony_ci goto set_complete; 38078c2ecf20Sopenharmony_ci } 38088c2ecf20Sopenharmony_ci 38098c2ecf20Sopenharmony_ci if (ice_set_q_coalesce(vsi, ec, q_num)) 38108c2ecf20Sopenharmony_ci return -EINVAL; 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ciset_complete: 38138c2ecf20Sopenharmony_ci 38148c2ecf20Sopenharmony_ci return 0; 38158c2ecf20Sopenharmony_ci} 38168c2ecf20Sopenharmony_ci 38178c2ecf20Sopenharmony_cistatic int 38188c2ecf20Sopenharmony_ciice_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) 38198c2ecf20Sopenharmony_ci{ 38208c2ecf20Sopenharmony_ci return __ice_set_coalesce(netdev, ec, -1); 38218c2ecf20Sopenharmony_ci} 38228c2ecf20Sopenharmony_ci 38238c2ecf20Sopenharmony_cistatic int 38248c2ecf20Sopenharmony_ciice_set_per_q_coalesce(struct net_device *netdev, u32 q_num, 38258c2ecf20Sopenharmony_ci struct ethtool_coalesce *ec) 38268c2ecf20Sopenharmony_ci{ 38278c2ecf20Sopenharmony_ci return __ice_set_coalesce(netdev, ec, q_num); 38288c2ecf20Sopenharmony_ci} 38298c2ecf20Sopenharmony_ci 38308c2ecf20Sopenharmony_ci#define ICE_I2C_EEPROM_DEV_ADDR 0xA0 38318c2ecf20Sopenharmony_ci#define ICE_I2C_EEPROM_DEV_ADDR2 0xA2 38328c2ecf20Sopenharmony_ci#define ICE_MODULE_TYPE_SFP 0x03 38338c2ecf20Sopenharmony_ci#define ICE_MODULE_TYPE_QSFP_PLUS 0x0D 38348c2ecf20Sopenharmony_ci#define ICE_MODULE_TYPE_QSFP28 0x11 38358c2ecf20Sopenharmony_ci#define ICE_MODULE_SFF_ADDR_MODE 0x04 38368c2ecf20Sopenharmony_ci#define ICE_MODULE_SFF_DIAG_CAPAB 0x40 38378c2ecf20Sopenharmony_ci#define ICE_MODULE_REVISION_ADDR 0x01 38388c2ecf20Sopenharmony_ci#define ICE_MODULE_SFF_8472_COMP 0x5E 38398c2ecf20Sopenharmony_ci#define ICE_MODULE_SFF_8472_SWAP 0x5C 38408c2ecf20Sopenharmony_ci#define ICE_MODULE_QSFP_MAX_LEN 640 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_ci/** 38438c2ecf20Sopenharmony_ci * ice_get_module_info - get SFF module type and revision information 38448c2ecf20Sopenharmony_ci * @netdev: network interface device structure 38458c2ecf20Sopenharmony_ci * @modinfo: module EEPROM size and layout information structure 38468c2ecf20Sopenharmony_ci */ 38478c2ecf20Sopenharmony_cistatic int 38488c2ecf20Sopenharmony_ciice_get_module_info(struct net_device *netdev, 38498c2ecf20Sopenharmony_ci struct ethtool_modinfo *modinfo) 38508c2ecf20Sopenharmony_ci{ 38518c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 38528c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 38538c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 38548c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 38558c2ecf20Sopenharmony_ci enum ice_status status; 38568c2ecf20Sopenharmony_ci u8 sff8472_comp = 0; 38578c2ecf20Sopenharmony_ci u8 sff8472_swap = 0; 38588c2ecf20Sopenharmony_ci u8 sff8636_rev = 0; 38598c2ecf20Sopenharmony_ci u8 value = 0; 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, 0x00, 0x00, 38628c2ecf20Sopenharmony_ci 0, &value, 1, 0, NULL); 38638c2ecf20Sopenharmony_ci if (status) 38648c2ecf20Sopenharmony_ci return -EIO; 38658c2ecf20Sopenharmony_ci 38668c2ecf20Sopenharmony_ci switch (value) { 38678c2ecf20Sopenharmony_ci case ICE_MODULE_TYPE_SFP: 38688c2ecf20Sopenharmony_ci status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, 38698c2ecf20Sopenharmony_ci ICE_MODULE_SFF_8472_COMP, 0x00, 0, 38708c2ecf20Sopenharmony_ci &sff8472_comp, 1, 0, NULL); 38718c2ecf20Sopenharmony_ci if (status) 38728c2ecf20Sopenharmony_ci return -EIO; 38738c2ecf20Sopenharmony_ci status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, 38748c2ecf20Sopenharmony_ci ICE_MODULE_SFF_8472_SWAP, 0x00, 0, 38758c2ecf20Sopenharmony_ci &sff8472_swap, 1, 0, NULL); 38768c2ecf20Sopenharmony_ci if (status) 38778c2ecf20Sopenharmony_ci return -EIO; 38788c2ecf20Sopenharmony_ci 38798c2ecf20Sopenharmony_ci if (sff8472_swap & ICE_MODULE_SFF_ADDR_MODE) { 38808c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8079; 38818c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 38828c2ecf20Sopenharmony_ci } else if (sff8472_comp && 38838c2ecf20Sopenharmony_ci (sff8472_swap & ICE_MODULE_SFF_DIAG_CAPAB)) { 38848c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 38858c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 38868c2ecf20Sopenharmony_ci } else { 38878c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8079; 38888c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 38898c2ecf20Sopenharmony_ci } 38908c2ecf20Sopenharmony_ci break; 38918c2ecf20Sopenharmony_ci case ICE_MODULE_TYPE_QSFP_PLUS: 38928c2ecf20Sopenharmony_ci case ICE_MODULE_TYPE_QSFP28: 38938c2ecf20Sopenharmony_ci status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, 38948c2ecf20Sopenharmony_ci ICE_MODULE_REVISION_ADDR, 0x00, 0, 38958c2ecf20Sopenharmony_ci &sff8636_rev, 1, 0, NULL); 38968c2ecf20Sopenharmony_ci if (status) 38978c2ecf20Sopenharmony_ci return -EIO; 38988c2ecf20Sopenharmony_ci /* Check revision compliance */ 38998c2ecf20Sopenharmony_ci if (sff8636_rev > 0x02) { 39008c2ecf20Sopenharmony_ci /* Module is SFF-8636 compliant */ 39018c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8636; 39028c2ecf20Sopenharmony_ci modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN; 39038c2ecf20Sopenharmony_ci } else { 39048c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8436; 39058c2ecf20Sopenharmony_ci modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN; 39068c2ecf20Sopenharmony_ci } 39078c2ecf20Sopenharmony_ci break; 39088c2ecf20Sopenharmony_ci default: 39098c2ecf20Sopenharmony_ci netdev_warn(netdev, "SFF Module Type not recognized.\n"); 39108c2ecf20Sopenharmony_ci return -EINVAL; 39118c2ecf20Sopenharmony_ci } 39128c2ecf20Sopenharmony_ci return 0; 39138c2ecf20Sopenharmony_ci} 39148c2ecf20Sopenharmony_ci 39158c2ecf20Sopenharmony_ci/** 39168c2ecf20Sopenharmony_ci * ice_get_module_eeprom - fill buffer with SFF EEPROM contents 39178c2ecf20Sopenharmony_ci * @netdev: network interface device structure 39188c2ecf20Sopenharmony_ci * @ee: EEPROM dump request structure 39198c2ecf20Sopenharmony_ci * @data: buffer to be filled with EEPROM contents 39208c2ecf20Sopenharmony_ci */ 39218c2ecf20Sopenharmony_cistatic int 39228c2ecf20Sopenharmony_ciice_get_module_eeprom(struct net_device *netdev, 39238c2ecf20Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 39248c2ecf20Sopenharmony_ci{ 39258c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 39268c2ecf20Sopenharmony_ci u8 addr = ICE_I2C_EEPROM_DEV_ADDR; 39278c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 39288c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 39298c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 39308c2ecf20Sopenharmony_ci enum ice_status status; 39318c2ecf20Sopenharmony_ci bool is_sfp = false; 39328c2ecf20Sopenharmony_ci unsigned int i; 39338c2ecf20Sopenharmony_ci u16 offset = 0; 39348c2ecf20Sopenharmony_ci u8 value = 0; 39358c2ecf20Sopenharmony_ci u8 page = 0; 39368c2ecf20Sopenharmony_ci 39378c2ecf20Sopenharmony_ci status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, 0, 39388c2ecf20Sopenharmony_ci &value, 1, 0, NULL); 39398c2ecf20Sopenharmony_ci if (status) 39408c2ecf20Sopenharmony_ci return -EIO; 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci if (!ee || !ee->len || !data) 39438c2ecf20Sopenharmony_ci return -EINVAL; 39448c2ecf20Sopenharmony_ci 39458c2ecf20Sopenharmony_ci if (value == ICE_MODULE_TYPE_SFP) 39468c2ecf20Sopenharmony_ci is_sfp = true; 39478c2ecf20Sopenharmony_ci 39488c2ecf20Sopenharmony_ci for (i = 0; i < ee->len; i++) { 39498c2ecf20Sopenharmony_ci offset = i + ee->offset; 39508c2ecf20Sopenharmony_ci 39518c2ecf20Sopenharmony_ci /* Check if we need to access the other memory page */ 39528c2ecf20Sopenharmony_ci if (is_sfp) { 39538c2ecf20Sopenharmony_ci if (offset >= ETH_MODULE_SFF_8079_LEN) { 39548c2ecf20Sopenharmony_ci offset -= ETH_MODULE_SFF_8079_LEN; 39558c2ecf20Sopenharmony_ci addr = ICE_I2C_EEPROM_DEV_ADDR2; 39568c2ecf20Sopenharmony_ci } 39578c2ecf20Sopenharmony_ci } else { 39588c2ecf20Sopenharmony_ci while (offset >= ETH_MODULE_SFF_8436_LEN) { 39598c2ecf20Sopenharmony_ci /* Compute memory page number and offset. */ 39608c2ecf20Sopenharmony_ci offset -= ETH_MODULE_SFF_8436_LEN / 2; 39618c2ecf20Sopenharmony_ci page++; 39628c2ecf20Sopenharmony_ci } 39638c2ecf20Sopenharmony_ci } 39648c2ecf20Sopenharmony_ci 39658c2ecf20Sopenharmony_ci status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, !is_sfp, 39668c2ecf20Sopenharmony_ci &value, 1, 0, NULL); 39678c2ecf20Sopenharmony_ci if (status) 39688c2ecf20Sopenharmony_ci value = 0; 39698c2ecf20Sopenharmony_ci data[i] = value; 39708c2ecf20Sopenharmony_ci } 39718c2ecf20Sopenharmony_ci return 0; 39728c2ecf20Sopenharmony_ci} 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_cistatic const struct ethtool_ops ice_ethtool_ops = { 39758c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 39768c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE | 39778c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_RX_USECS_HIGH, 39788c2ecf20Sopenharmony_ci .get_link_ksettings = ice_get_link_ksettings, 39798c2ecf20Sopenharmony_ci .set_link_ksettings = ice_set_link_ksettings, 39808c2ecf20Sopenharmony_ci .get_drvinfo = ice_get_drvinfo, 39818c2ecf20Sopenharmony_ci .get_regs_len = ice_get_regs_len, 39828c2ecf20Sopenharmony_ci .get_regs = ice_get_regs, 39838c2ecf20Sopenharmony_ci .get_wol = ice_get_wol, 39848c2ecf20Sopenharmony_ci .set_wol = ice_set_wol, 39858c2ecf20Sopenharmony_ci .get_msglevel = ice_get_msglevel, 39868c2ecf20Sopenharmony_ci .set_msglevel = ice_set_msglevel, 39878c2ecf20Sopenharmony_ci .self_test = ice_self_test, 39888c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 39898c2ecf20Sopenharmony_ci .get_eeprom_len = ice_get_eeprom_len, 39908c2ecf20Sopenharmony_ci .get_eeprom = ice_get_eeprom, 39918c2ecf20Sopenharmony_ci .get_coalesce = ice_get_coalesce, 39928c2ecf20Sopenharmony_ci .set_coalesce = ice_set_coalesce, 39938c2ecf20Sopenharmony_ci .get_strings = ice_get_strings, 39948c2ecf20Sopenharmony_ci .set_phys_id = ice_set_phys_id, 39958c2ecf20Sopenharmony_ci .get_ethtool_stats = ice_get_ethtool_stats, 39968c2ecf20Sopenharmony_ci .get_priv_flags = ice_get_priv_flags, 39978c2ecf20Sopenharmony_ci .set_priv_flags = ice_set_priv_flags, 39988c2ecf20Sopenharmony_ci .get_sset_count = ice_get_sset_count, 39998c2ecf20Sopenharmony_ci .get_rxnfc = ice_get_rxnfc, 40008c2ecf20Sopenharmony_ci .set_rxnfc = ice_set_rxnfc, 40018c2ecf20Sopenharmony_ci .get_ringparam = ice_get_ringparam, 40028c2ecf20Sopenharmony_ci .set_ringparam = ice_set_ringparam, 40038c2ecf20Sopenharmony_ci .nway_reset = ice_nway_reset, 40048c2ecf20Sopenharmony_ci .get_pauseparam = ice_get_pauseparam, 40058c2ecf20Sopenharmony_ci .set_pauseparam = ice_set_pauseparam, 40068c2ecf20Sopenharmony_ci .get_rxfh_key_size = ice_get_rxfh_key_size, 40078c2ecf20Sopenharmony_ci .get_rxfh_indir_size = ice_get_rxfh_indir_size, 40088c2ecf20Sopenharmony_ci .get_rxfh = ice_get_rxfh, 40098c2ecf20Sopenharmony_ci .set_rxfh = ice_set_rxfh, 40108c2ecf20Sopenharmony_ci .get_channels = ice_get_channels, 40118c2ecf20Sopenharmony_ci .set_channels = ice_set_channels, 40128c2ecf20Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 40138c2ecf20Sopenharmony_ci .get_per_queue_coalesce = ice_get_per_q_coalesce, 40148c2ecf20Sopenharmony_ci .set_per_queue_coalesce = ice_set_per_q_coalesce, 40158c2ecf20Sopenharmony_ci .get_fecparam = ice_get_fecparam, 40168c2ecf20Sopenharmony_ci .set_fecparam = ice_set_fecparam, 40178c2ecf20Sopenharmony_ci .get_module_info = ice_get_module_info, 40188c2ecf20Sopenharmony_ci .get_module_eeprom = ice_get_module_eeprom, 40198c2ecf20Sopenharmony_ci}; 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_cistatic const struct ethtool_ops ice_ethtool_safe_mode_ops = { 40228c2ecf20Sopenharmony_ci .get_link_ksettings = ice_get_link_ksettings, 40238c2ecf20Sopenharmony_ci .set_link_ksettings = ice_set_link_ksettings, 40248c2ecf20Sopenharmony_ci .get_drvinfo = ice_get_drvinfo, 40258c2ecf20Sopenharmony_ci .get_regs_len = ice_get_regs_len, 40268c2ecf20Sopenharmony_ci .get_regs = ice_get_regs, 40278c2ecf20Sopenharmony_ci .get_wol = ice_get_wol, 40288c2ecf20Sopenharmony_ci .set_wol = ice_set_wol, 40298c2ecf20Sopenharmony_ci .get_msglevel = ice_get_msglevel, 40308c2ecf20Sopenharmony_ci .set_msglevel = ice_set_msglevel, 40318c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 40328c2ecf20Sopenharmony_ci .get_eeprom_len = ice_get_eeprom_len, 40338c2ecf20Sopenharmony_ci .get_eeprom = ice_get_eeprom, 40348c2ecf20Sopenharmony_ci .get_strings = ice_get_strings, 40358c2ecf20Sopenharmony_ci .get_ethtool_stats = ice_get_ethtool_stats, 40368c2ecf20Sopenharmony_ci .get_sset_count = ice_get_sset_count, 40378c2ecf20Sopenharmony_ci .get_ringparam = ice_get_ringparam, 40388c2ecf20Sopenharmony_ci .set_ringparam = ice_set_ringparam, 40398c2ecf20Sopenharmony_ci .nway_reset = ice_nway_reset, 40408c2ecf20Sopenharmony_ci .get_channels = ice_get_channels, 40418c2ecf20Sopenharmony_ci}; 40428c2ecf20Sopenharmony_ci 40438c2ecf20Sopenharmony_ci/** 40448c2ecf20Sopenharmony_ci * ice_set_ethtool_safe_mode_ops - setup safe mode ethtool ops 40458c2ecf20Sopenharmony_ci * @netdev: network interface device structure 40468c2ecf20Sopenharmony_ci */ 40478c2ecf20Sopenharmony_civoid ice_set_ethtool_safe_mode_ops(struct net_device *netdev) 40488c2ecf20Sopenharmony_ci{ 40498c2ecf20Sopenharmony_ci netdev->ethtool_ops = &ice_ethtool_safe_mode_ops; 40508c2ecf20Sopenharmony_ci} 40518c2ecf20Sopenharmony_ci 40528c2ecf20Sopenharmony_ci/** 40538c2ecf20Sopenharmony_ci * ice_set_ethtool_ops - setup netdev ethtool ops 40548c2ecf20Sopenharmony_ci * @netdev: network interface device structure 40558c2ecf20Sopenharmony_ci * 40568c2ecf20Sopenharmony_ci * setup netdev ethtool ops with ice specific ops 40578c2ecf20Sopenharmony_ci */ 40588c2ecf20Sopenharmony_civoid ice_set_ethtool_ops(struct net_device *netdev) 40598c2ecf20Sopenharmony_ci{ 40608c2ecf20Sopenharmony_ci netdev->ethtool_ops = &ice_ethtool_ops; 40618c2ecf20Sopenharmony_ci} 4062