18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2007 Mellanox Technologies. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/kernel.h> 358c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 368c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 378c2ecf20Sopenharmony_ci#include <linux/mlx4/driver.h> 388c2ecf20Sopenharmony_ci#include <linux/mlx4/device.h> 398c2ecf20Sopenharmony_ci#include <linux/in.h> 408c2ecf20Sopenharmony_ci#include <net/ip.h> 418c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include "mlx4_en.h" 448c2ecf20Sopenharmony_ci#include "en_port.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define EN_ETHTOOL_QP_ATTACH (1ull << 63) 478c2ecf20Sopenharmony_ci#define EN_ETHTOOL_SHORT_MASK cpu_to_be16(0xffff) 488c2ecf20Sopenharmony_ci#define EN_ETHTOOL_WORD_MASK cpu_to_be32(0xffffffff) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciint mlx4_en_moderation_update(struct mlx4_en_priv *priv) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci int i, t; 538c2ecf20Sopenharmony_ci int err = 0; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci for (t = 0 ; t < MLX4_EN_NUM_TX_TYPES; t++) { 568c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 578c2ecf20Sopenharmony_ci priv->tx_cq[t][i]->moder_cnt = priv->tx_frames; 588c2ecf20Sopenharmony_ci priv->tx_cq[t][i]->moder_time = priv->tx_usecs; 598c2ecf20Sopenharmony_ci if (priv->port_up) { 608c2ecf20Sopenharmony_ci err = mlx4_en_set_cq_moder(priv, 618c2ecf20Sopenharmony_ci priv->tx_cq[t][i]); 628c2ecf20Sopenharmony_ci if (err) 638c2ecf20Sopenharmony_ci return err; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (priv->adaptive_rx_coal) 698c2ecf20Sopenharmony_ci return 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 728c2ecf20Sopenharmony_ci priv->rx_cq[i]->moder_cnt = priv->rx_frames; 738c2ecf20Sopenharmony_ci priv->rx_cq[i]->moder_time = priv->rx_usecs; 748c2ecf20Sopenharmony_ci priv->last_moder_time[i] = MLX4_EN_AUTO_CONF; 758c2ecf20Sopenharmony_ci if (priv->port_up) { 768c2ecf20Sopenharmony_ci err = mlx4_en_set_cq_moder(priv, priv->rx_cq[i]); 778c2ecf20Sopenharmony_ci if (err) 788c2ecf20Sopenharmony_ci return err; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return err; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void 868c2ecf20Sopenharmony_cimlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 898c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); 928c2ecf20Sopenharmony_ci strlcpy(drvinfo->version, DRV_VERSION, 938c2ecf20Sopenharmony_ci sizeof(drvinfo->version)); 948c2ecf20Sopenharmony_ci snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), 958c2ecf20Sopenharmony_ci "%d.%d.%d", 968c2ecf20Sopenharmony_ci (u16) (mdev->dev->caps.fw_ver >> 32), 978c2ecf20Sopenharmony_ci (u16) ((mdev->dev->caps.fw_ver >> 16) & 0xffff), 988c2ecf20Sopenharmony_ci (u16) (mdev->dev->caps.fw_ver & 0xffff)); 998c2ecf20Sopenharmony_ci strlcpy(drvinfo->bus_info, pci_name(mdev->dev->persist->pdev), 1008c2ecf20Sopenharmony_ci sizeof(drvinfo->bus_info)); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic const char mlx4_en_priv_flags[][ETH_GSTRING_LEN] = { 1048c2ecf20Sopenharmony_ci "blueflame", 1058c2ecf20Sopenharmony_ci "phv-bit" 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic const char main_strings[][ETH_GSTRING_LEN] = { 1098c2ecf20Sopenharmony_ci /* main statistics */ 1108c2ecf20Sopenharmony_ci "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", 1118c2ecf20Sopenharmony_ci "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", 1128c2ecf20Sopenharmony_ci "rx_length_errors", "rx_over_errors", "rx_crc_errors", 1138c2ecf20Sopenharmony_ci "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", 1148c2ecf20Sopenharmony_ci "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", 1158c2ecf20Sopenharmony_ci "tx_heartbeat_errors", "tx_window_errors", 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* port statistics */ 1188c2ecf20Sopenharmony_ci "tso_packets", 1198c2ecf20Sopenharmony_ci "xmit_more", 1208c2ecf20Sopenharmony_ci "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_pages", 1218c2ecf20Sopenharmony_ci "rx_csum_good", "rx_csum_none", "rx_csum_complete", "tx_chksum_offload", 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* pf statistics */ 1248c2ecf20Sopenharmony_ci "pf_rx_packets", 1258c2ecf20Sopenharmony_ci "pf_rx_bytes", 1268c2ecf20Sopenharmony_ci "pf_tx_packets", 1278c2ecf20Sopenharmony_ci "pf_tx_bytes", 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* priority flow control statistics rx */ 1308c2ecf20Sopenharmony_ci "rx_pause_prio_0", "rx_pause_duration_prio_0", 1318c2ecf20Sopenharmony_ci "rx_pause_transition_prio_0", 1328c2ecf20Sopenharmony_ci "rx_pause_prio_1", "rx_pause_duration_prio_1", 1338c2ecf20Sopenharmony_ci "rx_pause_transition_prio_1", 1348c2ecf20Sopenharmony_ci "rx_pause_prio_2", "rx_pause_duration_prio_2", 1358c2ecf20Sopenharmony_ci "rx_pause_transition_prio_2", 1368c2ecf20Sopenharmony_ci "rx_pause_prio_3", "rx_pause_duration_prio_3", 1378c2ecf20Sopenharmony_ci "rx_pause_transition_prio_3", 1388c2ecf20Sopenharmony_ci "rx_pause_prio_4", "rx_pause_duration_prio_4", 1398c2ecf20Sopenharmony_ci "rx_pause_transition_prio_4", 1408c2ecf20Sopenharmony_ci "rx_pause_prio_5", "rx_pause_duration_prio_5", 1418c2ecf20Sopenharmony_ci "rx_pause_transition_prio_5", 1428c2ecf20Sopenharmony_ci "rx_pause_prio_6", "rx_pause_duration_prio_6", 1438c2ecf20Sopenharmony_ci "rx_pause_transition_prio_6", 1448c2ecf20Sopenharmony_ci "rx_pause_prio_7", "rx_pause_duration_prio_7", 1458c2ecf20Sopenharmony_ci "rx_pause_transition_prio_7", 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* flow control statistics rx */ 1488c2ecf20Sopenharmony_ci "rx_pause", "rx_pause_duration", "rx_pause_transition", 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* priority flow control statistics tx */ 1518c2ecf20Sopenharmony_ci "tx_pause_prio_0", "tx_pause_duration_prio_0", 1528c2ecf20Sopenharmony_ci "tx_pause_transition_prio_0", 1538c2ecf20Sopenharmony_ci "tx_pause_prio_1", "tx_pause_duration_prio_1", 1548c2ecf20Sopenharmony_ci "tx_pause_transition_prio_1", 1558c2ecf20Sopenharmony_ci "tx_pause_prio_2", "tx_pause_duration_prio_2", 1568c2ecf20Sopenharmony_ci "tx_pause_transition_prio_2", 1578c2ecf20Sopenharmony_ci "tx_pause_prio_3", "tx_pause_duration_prio_3", 1588c2ecf20Sopenharmony_ci "tx_pause_transition_prio_3", 1598c2ecf20Sopenharmony_ci "tx_pause_prio_4", "tx_pause_duration_prio_4", 1608c2ecf20Sopenharmony_ci "tx_pause_transition_prio_4", 1618c2ecf20Sopenharmony_ci "tx_pause_prio_5", "tx_pause_duration_prio_5", 1628c2ecf20Sopenharmony_ci "tx_pause_transition_prio_5", 1638c2ecf20Sopenharmony_ci "tx_pause_prio_6", "tx_pause_duration_prio_6", 1648c2ecf20Sopenharmony_ci "tx_pause_transition_prio_6", 1658c2ecf20Sopenharmony_ci "tx_pause_prio_7", "tx_pause_duration_prio_7", 1668c2ecf20Sopenharmony_ci "tx_pause_transition_prio_7", 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* flow control statistics tx */ 1698c2ecf20Sopenharmony_ci "tx_pause", "tx_pause_duration", "tx_pause_transition", 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* packet statistics */ 1728c2ecf20Sopenharmony_ci "rx_multicast_packets", 1738c2ecf20Sopenharmony_ci "rx_broadcast_packets", 1748c2ecf20Sopenharmony_ci "rx_jabbers", 1758c2ecf20Sopenharmony_ci "rx_in_range_length_error", 1768c2ecf20Sopenharmony_ci "rx_out_range_length_error", 1778c2ecf20Sopenharmony_ci "tx_multicast_packets", 1788c2ecf20Sopenharmony_ci "tx_broadcast_packets", 1798c2ecf20Sopenharmony_ci "rx_prio_0_packets", "rx_prio_0_bytes", 1808c2ecf20Sopenharmony_ci "rx_prio_1_packets", "rx_prio_1_bytes", 1818c2ecf20Sopenharmony_ci "rx_prio_2_packets", "rx_prio_2_bytes", 1828c2ecf20Sopenharmony_ci "rx_prio_3_packets", "rx_prio_3_bytes", 1838c2ecf20Sopenharmony_ci "rx_prio_4_packets", "rx_prio_4_bytes", 1848c2ecf20Sopenharmony_ci "rx_prio_5_packets", "rx_prio_5_bytes", 1858c2ecf20Sopenharmony_ci "rx_prio_6_packets", "rx_prio_6_bytes", 1868c2ecf20Sopenharmony_ci "rx_prio_7_packets", "rx_prio_7_bytes", 1878c2ecf20Sopenharmony_ci "rx_novlan_packets", "rx_novlan_bytes", 1888c2ecf20Sopenharmony_ci "tx_prio_0_packets", "tx_prio_0_bytes", 1898c2ecf20Sopenharmony_ci "tx_prio_1_packets", "tx_prio_1_bytes", 1908c2ecf20Sopenharmony_ci "tx_prio_2_packets", "tx_prio_2_bytes", 1918c2ecf20Sopenharmony_ci "tx_prio_3_packets", "tx_prio_3_bytes", 1928c2ecf20Sopenharmony_ci "tx_prio_4_packets", "tx_prio_4_bytes", 1938c2ecf20Sopenharmony_ci "tx_prio_5_packets", "tx_prio_5_bytes", 1948c2ecf20Sopenharmony_ci "tx_prio_6_packets", "tx_prio_6_bytes", 1958c2ecf20Sopenharmony_ci "tx_prio_7_packets", "tx_prio_7_bytes", 1968c2ecf20Sopenharmony_ci "tx_novlan_packets", "tx_novlan_bytes", 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* xdp statistics */ 1998c2ecf20Sopenharmony_ci "rx_xdp_drop", 2008c2ecf20Sopenharmony_ci "rx_xdp_tx", 2018c2ecf20Sopenharmony_ci "rx_xdp_tx_full", 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* phy statistics */ 2048c2ecf20Sopenharmony_ci "rx_packets_phy", "rx_bytes_phy", 2058c2ecf20Sopenharmony_ci "tx_packets_phy", "tx_bytes_phy", 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic const char mlx4_en_test_names[][ETH_GSTRING_LEN]= { 2098c2ecf20Sopenharmony_ci "Interrupt Test", 2108c2ecf20Sopenharmony_ci "Link Test", 2118c2ecf20Sopenharmony_ci "Speed Test", 2128c2ecf20Sopenharmony_ci "Register Test", 2138c2ecf20Sopenharmony_ci "Loopback Test", 2148c2ecf20Sopenharmony_ci}; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic u32 mlx4_en_get_msglevel(struct net_device *dev) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void mlx4_en_set_msglevel(struct net_device *dev, u32 val) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable = val; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic void mlx4_en_get_wol(struct net_device *netdev, 2278c2ecf20Sopenharmony_ci struct ethtool_wolinfo *wol) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(netdev); 2308c2ecf20Sopenharmony_ci struct mlx4_caps *caps = &priv->mdev->dev->caps; 2318c2ecf20Sopenharmony_ci int err = 0; 2328c2ecf20Sopenharmony_ci u64 config = 0; 2338c2ecf20Sopenharmony_ci u64 mask; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if ((priv->port < 1) || (priv->port > 2)) { 2368c2ecf20Sopenharmony_ci en_err(priv, "Failed to get WoL information\n"); 2378c2ecf20Sopenharmony_ci return; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci mask = (priv->port == 1) ? MLX4_DEV_CAP_FLAG_WOL_PORT1 : 2418c2ecf20Sopenharmony_ci MLX4_DEV_CAP_FLAG_WOL_PORT2; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!(caps->flags & mask)) { 2448c2ecf20Sopenharmony_ci wol->supported = 0; 2458c2ecf20Sopenharmony_ci wol->wolopts = 0; 2468c2ecf20Sopenharmony_ci return; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (caps->wol_port[priv->port]) 2508c2ecf20Sopenharmony_ci wol->supported = WAKE_MAGIC; 2518c2ecf20Sopenharmony_ci else 2528c2ecf20Sopenharmony_ci wol->supported = 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci err = mlx4_wol_read(priv->mdev->dev, &config, priv->port); 2558c2ecf20Sopenharmony_ci if (err) { 2568c2ecf20Sopenharmony_ci en_err(priv, "Failed to get WoL information\n"); 2578c2ecf20Sopenharmony_ci return; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if ((config & MLX4_EN_WOL_ENABLED) && (config & MLX4_EN_WOL_MAGIC)) 2618c2ecf20Sopenharmony_ci wol->wolopts = WAKE_MAGIC; 2628c2ecf20Sopenharmony_ci else 2638c2ecf20Sopenharmony_ci wol->wolopts = 0; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int mlx4_en_set_wol(struct net_device *netdev, 2678c2ecf20Sopenharmony_ci struct ethtool_wolinfo *wol) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(netdev); 2708c2ecf20Sopenharmony_ci u64 config = 0; 2718c2ecf20Sopenharmony_ci int err = 0; 2728c2ecf20Sopenharmony_ci u64 mask; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if ((priv->port < 1) || (priv->port > 2)) 2758c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci mask = (priv->port == 1) ? MLX4_DEV_CAP_FLAG_WOL_PORT1 : 2788c2ecf20Sopenharmony_ci MLX4_DEV_CAP_FLAG_WOL_PORT2; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (!(priv->mdev->dev->caps.flags & mask)) 2818c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (wol->supported & ~WAKE_MAGIC) 2848c2ecf20Sopenharmony_ci return -EINVAL; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci err = mlx4_wol_read(priv->mdev->dev, &config, priv->port); 2878c2ecf20Sopenharmony_ci if (err) { 2888c2ecf20Sopenharmony_ci en_err(priv, "Failed to get WoL info, unable to modify\n"); 2898c2ecf20Sopenharmony_ci return err; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) { 2938c2ecf20Sopenharmony_ci config |= MLX4_EN_WOL_DO_MODIFY | MLX4_EN_WOL_ENABLED | 2948c2ecf20Sopenharmony_ci MLX4_EN_WOL_MAGIC; 2958c2ecf20Sopenharmony_ci } else { 2968c2ecf20Sopenharmony_ci config &= ~(MLX4_EN_WOL_ENABLED | MLX4_EN_WOL_MAGIC); 2978c2ecf20Sopenharmony_ci config |= MLX4_EN_WOL_DO_MODIFY; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci err = mlx4_wol_write(priv->mdev->dev, config, priv->port); 3018c2ecf20Sopenharmony_ci if (err) 3028c2ecf20Sopenharmony_ci en_err(priv, "Failed to set WoL information\n"); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return err; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistruct bitmap_iterator { 3088c2ecf20Sopenharmony_ci unsigned long *stats_bitmap; 3098c2ecf20Sopenharmony_ci unsigned int count; 3108c2ecf20Sopenharmony_ci unsigned int iterator; 3118c2ecf20Sopenharmony_ci bool advance_array; /* if set, force no increments */ 3128c2ecf20Sopenharmony_ci}; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic inline void bitmap_iterator_init(struct bitmap_iterator *h, 3158c2ecf20Sopenharmony_ci unsigned long *stats_bitmap, 3168c2ecf20Sopenharmony_ci int count) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci h->iterator = 0; 3198c2ecf20Sopenharmony_ci h->advance_array = !bitmap_empty(stats_bitmap, count); 3208c2ecf20Sopenharmony_ci h->count = h->advance_array ? bitmap_weight(stats_bitmap, count) 3218c2ecf20Sopenharmony_ci : count; 3228c2ecf20Sopenharmony_ci h->stats_bitmap = stats_bitmap; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic inline int bitmap_iterator_test(struct bitmap_iterator *h) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci return !h->advance_array ? 1 : test_bit(h->iterator, h->stats_bitmap); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic inline int bitmap_iterator_inc(struct bitmap_iterator *h) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci return h->iterator++; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic inline unsigned int 3368c2ecf20Sopenharmony_cibitmap_iterator_count(struct bitmap_iterator *h) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci return h->count; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int mlx4_en_get_sset_count(struct net_device *dev, int sset) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 3448c2ecf20Sopenharmony_ci struct bitmap_iterator it; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci bitmap_iterator_init(&it, priv->stats_bitmap.bitmap, NUM_ALL_STATS); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci switch (sset) { 3498c2ecf20Sopenharmony_ci case ETH_SS_STATS: 3508c2ecf20Sopenharmony_ci return bitmap_iterator_count(&it) + 3518c2ecf20Sopenharmony_ci (priv->tx_ring_num[TX] * 2) + 3528c2ecf20Sopenharmony_ci (priv->rx_ring_num * (3 + NUM_XDP_STATS)); 3538c2ecf20Sopenharmony_ci case ETH_SS_TEST: 3548c2ecf20Sopenharmony_ci return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.flags 3558c2ecf20Sopenharmony_ci & MLX4_DEV_CAP_FLAG_UC_LOOPBACK) * 2; 3568c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 3578c2ecf20Sopenharmony_ci return ARRAY_SIZE(mlx4_en_priv_flags); 3588c2ecf20Sopenharmony_ci default: 3598c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic void mlx4_en_get_ethtool_stats(struct net_device *dev, 3648c2ecf20Sopenharmony_ci struct ethtool_stats *stats, uint64_t *data) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 3678c2ecf20Sopenharmony_ci int index = 0; 3688c2ecf20Sopenharmony_ci int i; 3698c2ecf20Sopenharmony_ci struct bitmap_iterator it; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci bitmap_iterator_init(&it, priv->stats_bitmap.bitmap, NUM_ALL_STATS); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci spin_lock_bh(&priv->stats_lock); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci mlx4_en_fold_software_stats(dev); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci for (i = 0; i < NUM_MAIN_STATS; i++, bitmap_iterator_inc(&it)) 3788c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 3798c2ecf20Sopenharmony_ci data[index++] = ((unsigned long *)&dev->stats)[i]; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci for (i = 0; i < NUM_PORT_STATS; i++, bitmap_iterator_inc(&it)) 3828c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 3838c2ecf20Sopenharmony_ci data[index++] = ((unsigned long *)&priv->port_stats)[i]; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci for (i = 0; i < NUM_PF_STATS; i++, bitmap_iterator_inc(&it)) 3868c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 3878c2ecf20Sopenharmony_ci data[index++] = 3888c2ecf20Sopenharmony_ci ((unsigned long *)&priv->pf_stats)[i]; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci for (i = 0; i < NUM_FLOW_PRIORITY_STATS_RX; 3918c2ecf20Sopenharmony_ci i++, bitmap_iterator_inc(&it)) 3928c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 3938c2ecf20Sopenharmony_ci data[index++] = 3948c2ecf20Sopenharmony_ci ((u64 *)&priv->rx_priority_flowstats)[i]; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci for (i = 0; i < NUM_FLOW_STATS_RX; i++, bitmap_iterator_inc(&it)) 3978c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 3988c2ecf20Sopenharmony_ci data[index++] = ((u64 *)&priv->rx_flowstats)[i]; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci for (i = 0; i < NUM_FLOW_PRIORITY_STATS_TX; 4018c2ecf20Sopenharmony_ci i++, bitmap_iterator_inc(&it)) 4028c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 4038c2ecf20Sopenharmony_ci data[index++] = 4048c2ecf20Sopenharmony_ci ((u64 *)&priv->tx_priority_flowstats)[i]; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci for (i = 0; i < NUM_FLOW_STATS_TX; i++, bitmap_iterator_inc(&it)) 4078c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 4088c2ecf20Sopenharmony_ci data[index++] = ((u64 *)&priv->tx_flowstats)[i]; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci for (i = 0; i < NUM_PKT_STATS; i++, bitmap_iterator_inc(&it)) 4118c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 4128c2ecf20Sopenharmony_ci data[index++] = ((unsigned long *)&priv->pkstats)[i]; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci for (i = 0; i < NUM_XDP_STATS; i++, bitmap_iterator_inc(&it)) 4158c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 4168c2ecf20Sopenharmony_ci data[index++] = ((unsigned long *)&priv->xdp_stats)[i]; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci for (i = 0; i < NUM_PHY_STATS; i++, bitmap_iterator_inc(&it)) 4198c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 4208c2ecf20Sopenharmony_ci data[index++] = ((unsigned long *)&priv->phy_stats)[i]; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[TX]; i++) { 4238c2ecf20Sopenharmony_ci data[index++] = priv->tx_ring[TX][i]->packets; 4248c2ecf20Sopenharmony_ci data[index++] = priv->tx_ring[TX][i]->bytes; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 4278c2ecf20Sopenharmony_ci data[index++] = priv->rx_ring[i]->packets; 4288c2ecf20Sopenharmony_ci data[index++] = priv->rx_ring[i]->bytes; 4298c2ecf20Sopenharmony_ci data[index++] = priv->rx_ring[i]->dropped; 4308c2ecf20Sopenharmony_ci data[index++] = priv->rx_ring[i]->xdp_drop; 4318c2ecf20Sopenharmony_ci data[index++] = priv->rx_ring[i]->xdp_tx; 4328c2ecf20Sopenharmony_ci data[index++] = priv->rx_ring[i]->xdp_tx_full; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->stats_lock); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic void mlx4_en_self_test(struct net_device *dev, 4398c2ecf20Sopenharmony_ci struct ethtool_test *etest, u64 *buf) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci mlx4_en_ex_selftest(dev, &etest->flags, buf); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic void mlx4_en_get_strings(struct net_device *dev, 4458c2ecf20Sopenharmony_ci uint32_t stringset, uint8_t *data) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 4488c2ecf20Sopenharmony_ci int index = 0; 4498c2ecf20Sopenharmony_ci int i, strings = 0; 4508c2ecf20Sopenharmony_ci struct bitmap_iterator it; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci bitmap_iterator_init(&it, priv->stats_bitmap.bitmap, NUM_ALL_STATS); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci switch (stringset) { 4558c2ecf20Sopenharmony_ci case ETH_SS_TEST: 4568c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_EN_NUM_SELF_TEST - 2; i++) 4578c2ecf20Sopenharmony_ci strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]); 4588c2ecf20Sopenharmony_ci if (priv->mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UC_LOOPBACK) 4598c2ecf20Sopenharmony_ci for (; i < MLX4_EN_NUM_SELF_TEST; i++) 4608c2ecf20Sopenharmony_ci strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]); 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci case ETH_SS_STATS: 4648c2ecf20Sopenharmony_ci /* Add main counters */ 4658c2ecf20Sopenharmony_ci for (i = 0; i < NUM_MAIN_STATS; i++, strings++, 4668c2ecf20Sopenharmony_ci bitmap_iterator_inc(&it)) 4678c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 4688c2ecf20Sopenharmony_ci strcpy(data + (index++) * ETH_GSTRING_LEN, 4698c2ecf20Sopenharmony_ci main_strings[strings]); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci for (i = 0; i < NUM_PORT_STATS; i++, strings++, 4728c2ecf20Sopenharmony_ci bitmap_iterator_inc(&it)) 4738c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 4748c2ecf20Sopenharmony_ci strcpy(data + (index++) * ETH_GSTRING_LEN, 4758c2ecf20Sopenharmony_ci main_strings[strings]); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci for (i = 0; i < NUM_PF_STATS; i++, strings++, 4788c2ecf20Sopenharmony_ci bitmap_iterator_inc(&it)) 4798c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 4808c2ecf20Sopenharmony_ci strcpy(data + (index++) * ETH_GSTRING_LEN, 4818c2ecf20Sopenharmony_ci main_strings[strings]); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci for (i = 0; i < NUM_FLOW_STATS; i++, strings++, 4848c2ecf20Sopenharmony_ci bitmap_iterator_inc(&it)) 4858c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 4868c2ecf20Sopenharmony_ci strcpy(data + (index++) * ETH_GSTRING_LEN, 4878c2ecf20Sopenharmony_ci main_strings[strings]); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci for (i = 0; i < NUM_PKT_STATS; i++, strings++, 4908c2ecf20Sopenharmony_ci bitmap_iterator_inc(&it)) 4918c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 4928c2ecf20Sopenharmony_ci strcpy(data + (index++) * ETH_GSTRING_LEN, 4938c2ecf20Sopenharmony_ci main_strings[strings]); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci for (i = 0; i < NUM_XDP_STATS; i++, strings++, 4968c2ecf20Sopenharmony_ci bitmap_iterator_inc(&it)) 4978c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 4988c2ecf20Sopenharmony_ci strcpy(data + (index++) * ETH_GSTRING_LEN, 4998c2ecf20Sopenharmony_ci main_strings[strings]); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci for (i = 0; i < NUM_PHY_STATS; i++, strings++, 5028c2ecf20Sopenharmony_ci bitmap_iterator_inc(&it)) 5038c2ecf20Sopenharmony_ci if (bitmap_iterator_test(&it)) 5048c2ecf20Sopenharmony_ci strcpy(data + (index++) * ETH_GSTRING_LEN, 5058c2ecf20Sopenharmony_ci main_strings[strings]); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[TX]; i++) { 5088c2ecf20Sopenharmony_ci sprintf(data + (index++) * ETH_GSTRING_LEN, 5098c2ecf20Sopenharmony_ci "tx%d_packets", i); 5108c2ecf20Sopenharmony_ci sprintf(data + (index++) * ETH_GSTRING_LEN, 5118c2ecf20Sopenharmony_ci "tx%d_bytes", i); 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 5148c2ecf20Sopenharmony_ci sprintf(data + (index++) * ETH_GSTRING_LEN, 5158c2ecf20Sopenharmony_ci "rx%d_packets", i); 5168c2ecf20Sopenharmony_ci sprintf(data + (index++) * ETH_GSTRING_LEN, 5178c2ecf20Sopenharmony_ci "rx%d_bytes", i); 5188c2ecf20Sopenharmony_ci sprintf(data + (index++) * ETH_GSTRING_LEN, 5198c2ecf20Sopenharmony_ci "rx%d_dropped", i); 5208c2ecf20Sopenharmony_ci sprintf(data + (index++) * ETH_GSTRING_LEN, 5218c2ecf20Sopenharmony_ci "rx%d_xdp_drop", i); 5228c2ecf20Sopenharmony_ci sprintf(data + (index++) * ETH_GSTRING_LEN, 5238c2ecf20Sopenharmony_ci "rx%d_xdp_tx", i); 5248c2ecf20Sopenharmony_ci sprintf(data + (index++) * ETH_GSTRING_LEN, 5258c2ecf20Sopenharmony_ci "rx%d_xdp_tx_full", i); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 5298c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mlx4_en_priv_flags); i++) 5308c2ecf20Sopenharmony_ci strcpy(data + i * ETH_GSTRING_LEN, 5318c2ecf20Sopenharmony_ci mlx4_en_priv_flags[i]); 5328c2ecf20Sopenharmony_ci break; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic u32 mlx4_en_autoneg_get(struct net_device *dev) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 5408c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 5418c2ecf20Sopenharmony_ci u32 autoneg = AUTONEG_DISABLE; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if ((mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP) && 5448c2ecf20Sopenharmony_ci (priv->port_state.flags & MLX4_EN_PORT_ANE)) 5458c2ecf20Sopenharmony_ci autoneg = AUTONEG_ENABLE; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci return autoneg; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic void ptys2ethtool_update_supported_port(unsigned long *mask, 5518c2ecf20Sopenharmony_ci struct mlx4_ptys_reg *ptys_reg) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci u32 eth_proto = be32_to_cpu(ptys_reg->eth_proto_cap); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_T) 5568c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_1000BASE_T) 5578c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_100BASE_TX))) { 5588c2ecf20Sopenharmony_ci __set_bit(ETHTOOL_LINK_MODE_TP_BIT, mask); 5598c2ecf20Sopenharmony_ci } else if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_CR) 5608c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_10GBASE_SR) 5618c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_56GBASE_SR4) 5628c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_40GBASE_CR4) 5638c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_40GBASE_SR4) 5648c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_1000BASE_CX_SGMII))) { 5658c2ecf20Sopenharmony_ci __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, mask); 5668c2ecf20Sopenharmony_ci } else if (eth_proto & (MLX4_PROT_MASK(MLX4_56GBASE_KR4) 5678c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_40GBASE_KR4) 5688c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_20GBASE_KR2) 5698c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_10GBASE_KR) 5708c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_10GBASE_KX4) 5718c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_1000BASE_KX))) { 5728c2ecf20Sopenharmony_ci __set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, mask); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic u32 ptys_get_active_port(struct mlx4_ptys_reg *ptys_reg) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci u32 eth_proto = be32_to_cpu(ptys_reg->eth_proto_oper); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (!eth_proto) /* link down */ 5818c2ecf20Sopenharmony_ci eth_proto = be32_to_cpu(ptys_reg->eth_proto_cap); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_T) 5848c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_1000BASE_T) 5858c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_100BASE_TX))) { 5868c2ecf20Sopenharmony_ci return PORT_TP; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_SR) 5908c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_56GBASE_SR4) 5918c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_40GBASE_SR4) 5928c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_1000BASE_CX_SGMII))) { 5938c2ecf20Sopenharmony_ci return PORT_FIBRE; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_CR) 5978c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_56GBASE_CR4) 5988c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_40GBASE_CR4))) { 5998c2ecf20Sopenharmony_ci return PORT_DA; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (eth_proto & (MLX4_PROT_MASK(MLX4_56GBASE_KR4) 6038c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_40GBASE_KR4) 6048c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_20GBASE_KR2) 6058c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_10GBASE_KR) 6068c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_10GBASE_KX4) 6078c2ecf20Sopenharmony_ci | MLX4_PROT_MASK(MLX4_1000BASE_KX))) { 6088c2ecf20Sopenharmony_ci return PORT_NONE; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci return PORT_OTHER; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci#define MLX4_LINK_MODES_SZ \ 6148c2ecf20Sopenharmony_ci (sizeof_field(struct mlx4_ptys_reg, eth_proto_cap) * 8) 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cienum ethtool_report { 6178c2ecf20Sopenharmony_ci SUPPORTED = 0, 6188c2ecf20Sopenharmony_ci ADVERTISED = 1, 6198c2ecf20Sopenharmony_ci}; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistruct ptys2ethtool_config { 6228c2ecf20Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); 6238c2ecf20Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(advertised); 6248c2ecf20Sopenharmony_ci u32 speed; 6258c2ecf20Sopenharmony_ci}; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic unsigned long *ptys2ethtool_link_mode(struct ptys2ethtool_config *cfg, 6288c2ecf20Sopenharmony_ci enum ethtool_report report) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci switch (report) { 6318c2ecf20Sopenharmony_ci case SUPPORTED: 6328c2ecf20Sopenharmony_ci return cfg->supported; 6338c2ecf20Sopenharmony_ci case ADVERTISED: 6348c2ecf20Sopenharmony_ci return cfg->advertised; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci return NULL; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci#define MLX4_BUILD_PTYS2ETHTOOL_CONFIG(reg_, speed_, ...) \ 6408c2ecf20Sopenharmony_ci ({ \ 6418c2ecf20Sopenharmony_ci struct ptys2ethtool_config *cfg; \ 6428c2ecf20Sopenharmony_ci static const unsigned int modes[] = { __VA_ARGS__ }; \ 6438c2ecf20Sopenharmony_ci unsigned int i; \ 6448c2ecf20Sopenharmony_ci cfg = &ptys2ethtool_map[reg_]; \ 6458c2ecf20Sopenharmony_ci cfg->speed = speed_; \ 6468c2ecf20Sopenharmony_ci bitmap_zero(cfg->supported, \ 6478c2ecf20Sopenharmony_ci __ETHTOOL_LINK_MODE_MASK_NBITS); \ 6488c2ecf20Sopenharmony_ci bitmap_zero(cfg->advertised, \ 6498c2ecf20Sopenharmony_ci __ETHTOOL_LINK_MODE_MASK_NBITS); \ 6508c2ecf20Sopenharmony_ci for (i = 0 ; i < ARRAY_SIZE(modes) ; ++i) { \ 6518c2ecf20Sopenharmony_ci __set_bit(modes[i], cfg->supported); \ 6528c2ecf20Sopenharmony_ci __set_bit(modes[i], cfg->advertised); \ 6538c2ecf20Sopenharmony_ci } \ 6548c2ecf20Sopenharmony_ci }) 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci/* Translates mlx4 link mode to equivalent ethtool Link modes/speed */ 6578c2ecf20Sopenharmony_cistatic struct ptys2ethtool_config ptys2ethtool_map[MLX4_LINK_MODES_SZ]; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_civoid __init mlx4_en_init_ptys2ethtool_map(void) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_100BASE_TX, SPEED_100, 6628c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_100baseT_Full_BIT); 6638c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_1000BASE_T, SPEED_1000, 6648c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseT_Full_BIT); 6658c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_1000BASE_CX_SGMII, SPEED_1000, 6668c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseX_Full_BIT); 6678c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_1000BASE_KX, SPEED_1000, 6688c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_1000baseKX_Full_BIT); 6698c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_T, SPEED_10000, 6708c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseT_Full_BIT); 6718c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_CX4, SPEED_10000, 6728c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT); 6738c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_KX4, SPEED_10000, 6748c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT); 6758c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_KR, SPEED_10000, 6768c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); 6778c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_CR, SPEED_10000, 6788c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseCR_Full_BIT); 6798c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_SR, SPEED_10000, 6808c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_10000baseSR_Full_BIT); 6818c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_20GBASE_KR2, SPEED_20000, 6828c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT, 6838c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT); 6848c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_40GBASE_CR4, SPEED_40000, 6858c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT); 6868c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_40GBASE_KR4, SPEED_40000, 6878c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT); 6888c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_40GBASE_SR4, SPEED_40000, 6898c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT); 6908c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_56GBASE_KR4, SPEED_56000, 6918c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT); 6928c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_56GBASE_CR4, SPEED_56000, 6938c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT); 6948c2ecf20Sopenharmony_ci MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_56GBASE_SR4, SPEED_56000, 6958c2ecf20Sopenharmony_ci ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT); 6968c2ecf20Sopenharmony_ci}; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic void ptys2ethtool_update_link_modes(unsigned long *link_modes, 6998c2ecf20Sopenharmony_ci u32 eth_proto, 7008c2ecf20Sopenharmony_ci enum ethtool_report report) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci int i; 7038c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_LINK_MODES_SZ; i++) { 7048c2ecf20Sopenharmony_ci if (eth_proto & MLX4_PROT_MASK(i)) 7058c2ecf20Sopenharmony_ci bitmap_or(link_modes, link_modes, 7068c2ecf20Sopenharmony_ci ptys2ethtool_link_mode(&ptys2ethtool_map[i], 7078c2ecf20Sopenharmony_ci report), 7088c2ecf20Sopenharmony_ci __ETHTOOL_LINK_MODE_MASK_NBITS); 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic u32 ethtool2ptys_link_modes(const unsigned long *link_modes, 7138c2ecf20Sopenharmony_ci enum ethtool_report report) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci int i; 7168c2ecf20Sopenharmony_ci u32 ptys_modes = 0; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_LINK_MODES_SZ; i++) { 7198c2ecf20Sopenharmony_ci if (bitmap_intersects( 7208c2ecf20Sopenharmony_ci ptys2ethtool_link_mode(&ptys2ethtool_map[i], 7218c2ecf20Sopenharmony_ci report), 7228c2ecf20Sopenharmony_ci link_modes, 7238c2ecf20Sopenharmony_ci __ETHTOOL_LINK_MODE_MASK_NBITS)) 7248c2ecf20Sopenharmony_ci ptys_modes |= 1 << i; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci return ptys_modes; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci/* Convert actual speed (SPEED_XXX) to ptys link modes */ 7308c2ecf20Sopenharmony_cistatic u32 speed2ptys_link_modes(u32 speed) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci int i; 7338c2ecf20Sopenharmony_ci u32 ptys_modes = 0; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_LINK_MODES_SZ; i++) { 7368c2ecf20Sopenharmony_ci if (ptys2ethtool_map[i].speed == speed) 7378c2ecf20Sopenharmony_ci ptys_modes |= 1 << i; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci return ptys_modes; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic int 7438c2ecf20Sopenharmony_ciethtool_get_ptys_link_ksettings(struct net_device *dev, 7448c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *link_ksettings) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 7478c2ecf20Sopenharmony_ci struct mlx4_ptys_reg ptys_reg; 7488c2ecf20Sopenharmony_ci u32 eth_proto; 7498c2ecf20Sopenharmony_ci int ret; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci memset(&ptys_reg, 0, sizeof(ptys_reg)); 7528c2ecf20Sopenharmony_ci ptys_reg.local_port = priv->port; 7538c2ecf20Sopenharmony_ci ptys_reg.proto_mask = MLX4_PTYS_EN; 7548c2ecf20Sopenharmony_ci ret = mlx4_ACCESS_PTYS_REG(priv->mdev->dev, 7558c2ecf20Sopenharmony_ci MLX4_ACCESS_REG_QUERY, &ptys_reg); 7568c2ecf20Sopenharmony_ci if (ret) { 7578c2ecf20Sopenharmony_ci en_warn(priv, "Failed to run mlx4_ACCESS_PTYS_REG status(%x)", 7588c2ecf20Sopenharmony_ci ret); 7598c2ecf20Sopenharmony_ci return ret; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "ptys_reg.proto_mask %x\n", 7628c2ecf20Sopenharmony_ci ptys_reg.proto_mask); 7638c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "ptys_reg.eth_proto_cap %x\n", 7648c2ecf20Sopenharmony_ci be32_to_cpu(ptys_reg.eth_proto_cap)); 7658c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "ptys_reg.eth_proto_admin %x\n", 7668c2ecf20Sopenharmony_ci be32_to_cpu(ptys_reg.eth_proto_admin)); 7678c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "ptys_reg.eth_proto_oper %x\n", 7688c2ecf20Sopenharmony_ci be32_to_cpu(ptys_reg.eth_proto_oper)); 7698c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "ptys_reg.eth_proto_lp_adv %x\n", 7708c2ecf20Sopenharmony_ci be32_to_cpu(ptys_reg.eth_proto_lp_adv)); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* reset supported/advertising masks */ 7738c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); 7748c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci ptys2ethtool_update_supported_port(link_ksettings->link_modes.supported, 7778c2ecf20Sopenharmony_ci &ptys_reg); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci eth_proto = be32_to_cpu(ptys_reg.eth_proto_cap); 7808c2ecf20Sopenharmony_ci ptys2ethtool_update_link_modes(link_ksettings->link_modes.supported, 7818c2ecf20Sopenharmony_ci eth_proto, SUPPORTED); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci eth_proto = be32_to_cpu(ptys_reg.eth_proto_admin); 7848c2ecf20Sopenharmony_ci ptys2ethtool_update_link_modes(link_ksettings->link_modes.advertising, 7858c2ecf20Sopenharmony_ci eth_proto, ADVERTISED); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, supported, 7888c2ecf20Sopenharmony_ci Pause); 7898c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, supported, 7908c2ecf20Sopenharmony_ci Asym_Pause); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (priv->prof->tx_pause) 7938c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, 7948c2ecf20Sopenharmony_ci advertising, Pause); 7958c2ecf20Sopenharmony_ci if (priv->prof->tx_pause ^ priv->prof->rx_pause) 7968c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, 7978c2ecf20Sopenharmony_ci advertising, Asym_Pause); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci link_ksettings->base.port = ptys_get_active_port(&ptys_reg); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (mlx4_en_autoneg_get(dev)) { 8028c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, 8038c2ecf20Sopenharmony_ci supported, Autoneg); 8048c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, 8058c2ecf20Sopenharmony_ci advertising, Autoneg); 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci link_ksettings->base.autoneg 8098c2ecf20Sopenharmony_ci = (priv->port_state.flags & MLX4_EN_PORT_ANC) ? 8108c2ecf20Sopenharmony_ci AUTONEG_ENABLE : AUTONEG_DISABLE; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci eth_proto = be32_to_cpu(ptys_reg.eth_proto_lp_adv); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(link_ksettings, lp_advertising); 8158c2ecf20Sopenharmony_ci ptys2ethtool_update_link_modes( 8168c2ecf20Sopenharmony_ci link_ksettings->link_modes.lp_advertising, 8178c2ecf20Sopenharmony_ci eth_proto, ADVERTISED); 8188c2ecf20Sopenharmony_ci if (priv->port_state.flags & MLX4_EN_PORT_ANC) 8198c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, 8208c2ecf20Sopenharmony_ci lp_advertising, Autoneg); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci link_ksettings->base.phy_address = 0; 8238c2ecf20Sopenharmony_ci link_ksettings->base.mdio_support = 0; 8248c2ecf20Sopenharmony_ci link_ksettings->base.eth_tp_mdix = ETH_TP_MDI_INVALID; 8258c2ecf20Sopenharmony_ci link_ksettings->base.eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci return ret; 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic void 8318c2ecf20Sopenharmony_ciethtool_get_default_link_ksettings( 8328c2ecf20Sopenharmony_ci struct net_device *dev, struct ethtool_link_ksettings *link_ksettings) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 8358c2ecf20Sopenharmony_ci int trans_type; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci link_ksettings->base.autoneg = AUTONEG_DISABLE; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); 8408c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, supported, 8418c2ecf20Sopenharmony_ci 10000baseT_Full); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); 8448c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, advertising, 8458c2ecf20Sopenharmony_ci 10000baseT_Full); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci trans_type = priv->port_state.transceiver; 8488c2ecf20Sopenharmony_ci if (trans_type > 0 && trans_type <= 0xC) { 8498c2ecf20Sopenharmony_ci link_ksettings->base.port = PORT_FIBRE; 8508c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, 8518c2ecf20Sopenharmony_ci supported, FIBRE); 8528c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, 8538c2ecf20Sopenharmony_ci advertising, FIBRE); 8548c2ecf20Sopenharmony_ci } else if (trans_type == 0x80 || trans_type == 0) { 8558c2ecf20Sopenharmony_ci link_ksettings->base.port = PORT_TP; 8568c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, 8578c2ecf20Sopenharmony_ci supported, TP); 8588c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, 8598c2ecf20Sopenharmony_ci advertising, TP); 8608c2ecf20Sopenharmony_ci } else { 8618c2ecf20Sopenharmony_ci link_ksettings->base.port = -1; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic int 8668c2ecf20Sopenharmony_cimlx4_en_get_link_ksettings(struct net_device *dev, 8678c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *link_ksettings) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 8708c2ecf20Sopenharmony_ci int ret = -EINVAL; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) 8738c2ecf20Sopenharmony_ci return -ENOMEM; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "query port state.flags ANC(%x) ANE(%x)\n", 8768c2ecf20Sopenharmony_ci priv->port_state.flags & MLX4_EN_PORT_ANC, 8778c2ecf20Sopenharmony_ci priv->port_state.flags & MLX4_EN_PORT_ANE); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL) 8808c2ecf20Sopenharmony_ci ret = ethtool_get_ptys_link_ksettings(dev, link_ksettings); 8818c2ecf20Sopenharmony_ci if (ret) /* ETH PROT CRTL is not supported or PTYS CMD failed */ 8828c2ecf20Sopenharmony_ci ethtool_get_default_link_ksettings(dev, link_ksettings); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev)) { 8858c2ecf20Sopenharmony_ci link_ksettings->base.speed = priv->port_state.link_speed; 8868c2ecf20Sopenharmony_ci link_ksettings->base.duplex = DUPLEX_FULL; 8878c2ecf20Sopenharmony_ci } else { 8888c2ecf20Sopenharmony_ci link_ksettings->base.speed = SPEED_UNKNOWN; 8898c2ecf20Sopenharmony_ci link_ksettings->base.duplex = DUPLEX_UNKNOWN; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci return 0; 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci/* Calculate PTYS admin according ethtool speed (SPEED_XXX) */ 8958c2ecf20Sopenharmony_cistatic __be32 speed_set_ptys_admin(struct mlx4_en_priv *priv, u32 speed, 8968c2ecf20Sopenharmony_ci __be32 proto_cap) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci __be32 proto_admin = 0; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (!speed) { /* Speed = 0 ==> Reset Link modes */ 9018c2ecf20Sopenharmony_ci proto_admin = proto_cap; 9028c2ecf20Sopenharmony_ci en_info(priv, "Speed was set to 0, Reset advertised Link Modes to default (%x)\n", 9038c2ecf20Sopenharmony_ci be32_to_cpu(proto_cap)); 9048c2ecf20Sopenharmony_ci } else { 9058c2ecf20Sopenharmony_ci u32 ptys_link_modes = speed2ptys_link_modes(speed); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci proto_admin = cpu_to_be32(ptys_link_modes) & proto_cap; 9088c2ecf20Sopenharmony_ci en_info(priv, "Setting Speed to %d\n", speed); 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci return proto_admin; 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistatic int 9148c2ecf20Sopenharmony_cimlx4_en_set_link_ksettings(struct net_device *dev, 9158c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *link_ksettings) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 9188c2ecf20Sopenharmony_ci struct mlx4_ptys_reg ptys_reg; 9198c2ecf20Sopenharmony_ci __be32 proto_admin; 9208c2ecf20Sopenharmony_ci u8 cur_autoneg; 9218c2ecf20Sopenharmony_ci int ret; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci u32 ptys_adv = ethtool2ptys_link_modes( 9248c2ecf20Sopenharmony_ci link_ksettings->link_modes.advertising, ADVERTISED); 9258c2ecf20Sopenharmony_ci const int speed = link_ksettings->base.speed; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci en_dbg(DRV, priv, 9288c2ecf20Sopenharmony_ci "Set Speed=%d adv={%*pbl} autoneg=%d duplex=%d\n", 9298c2ecf20Sopenharmony_ci speed, __ETHTOOL_LINK_MODE_MASK_NBITS, 9308c2ecf20Sopenharmony_ci link_ksettings->link_modes.advertising, 9318c2ecf20Sopenharmony_ci link_ksettings->base.autoneg, 9328c2ecf20Sopenharmony_ci link_ksettings->base.duplex); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if (!(priv->mdev->dev->caps.flags2 & 9358c2ecf20Sopenharmony_ci MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL) || 9368c2ecf20Sopenharmony_ci (link_ksettings->base.duplex == DUPLEX_HALF)) 9378c2ecf20Sopenharmony_ci return -EINVAL; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci memset(&ptys_reg, 0, sizeof(ptys_reg)); 9408c2ecf20Sopenharmony_ci ptys_reg.local_port = priv->port; 9418c2ecf20Sopenharmony_ci ptys_reg.proto_mask = MLX4_PTYS_EN; 9428c2ecf20Sopenharmony_ci ret = mlx4_ACCESS_PTYS_REG(priv->mdev->dev, 9438c2ecf20Sopenharmony_ci MLX4_ACCESS_REG_QUERY, &ptys_reg); 9448c2ecf20Sopenharmony_ci if (ret) { 9458c2ecf20Sopenharmony_ci en_warn(priv, "Failed to QUERY mlx4_ACCESS_PTYS_REG status(%x)\n", 9468c2ecf20Sopenharmony_ci ret); 9478c2ecf20Sopenharmony_ci return 0; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci cur_autoneg = ptys_reg.flags & MLX4_PTYS_AN_DISABLE_ADMIN ? 9518c2ecf20Sopenharmony_ci AUTONEG_DISABLE : AUTONEG_ENABLE; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (link_ksettings->base.autoneg == AUTONEG_DISABLE) { 9548c2ecf20Sopenharmony_ci proto_admin = speed_set_ptys_admin(priv, speed, 9558c2ecf20Sopenharmony_ci ptys_reg.eth_proto_cap); 9568c2ecf20Sopenharmony_ci if ((be32_to_cpu(proto_admin) & 9578c2ecf20Sopenharmony_ci (MLX4_PROT_MASK(MLX4_1000BASE_CX_SGMII) | 9588c2ecf20Sopenharmony_ci MLX4_PROT_MASK(MLX4_1000BASE_KX))) && 9598c2ecf20Sopenharmony_ci (ptys_reg.flags & MLX4_PTYS_AN_DISABLE_CAP)) 9608c2ecf20Sopenharmony_ci ptys_reg.flags |= MLX4_PTYS_AN_DISABLE_ADMIN; 9618c2ecf20Sopenharmony_ci } else { 9628c2ecf20Sopenharmony_ci proto_admin = cpu_to_be32(ptys_adv); 9638c2ecf20Sopenharmony_ci ptys_reg.flags &= ~MLX4_PTYS_AN_DISABLE_ADMIN; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci proto_admin &= ptys_reg.eth_proto_cap; 9678c2ecf20Sopenharmony_ci if (!proto_admin) { 9688c2ecf20Sopenharmony_ci en_warn(priv, "Not supported link mode(s) requested, check supported link modes.\n"); 9698c2ecf20Sopenharmony_ci return -EINVAL; /* nothing to change due to bad input */ 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if ((proto_admin == ptys_reg.eth_proto_admin) && 9738c2ecf20Sopenharmony_ci ((ptys_reg.flags & MLX4_PTYS_AN_DISABLE_CAP) && 9748c2ecf20Sopenharmony_ci (link_ksettings->base.autoneg == cur_autoneg))) 9758c2ecf20Sopenharmony_ci return 0; /* Nothing to change */ 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "mlx4_ACCESS_PTYS_REG SET: ptys_reg.eth_proto_admin = 0x%x\n", 9788c2ecf20Sopenharmony_ci be32_to_cpu(proto_admin)); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci ptys_reg.eth_proto_admin = proto_admin; 9818c2ecf20Sopenharmony_ci ret = mlx4_ACCESS_PTYS_REG(priv->mdev->dev, MLX4_ACCESS_REG_WRITE, 9828c2ecf20Sopenharmony_ci &ptys_reg); 9838c2ecf20Sopenharmony_ci if (ret) { 9848c2ecf20Sopenharmony_ci en_warn(priv, "Failed to write mlx4_ACCESS_PTYS_REG eth_proto_admin(0x%x) status(0x%x)", 9858c2ecf20Sopenharmony_ci be32_to_cpu(ptys_reg.eth_proto_admin), ret); 9868c2ecf20Sopenharmony_ci return ret; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci mutex_lock(&priv->mdev->state_lock); 9908c2ecf20Sopenharmony_ci if (priv->port_up) { 9918c2ecf20Sopenharmony_ci en_warn(priv, "Port link mode changed, restarting port...\n"); 9928c2ecf20Sopenharmony_ci mlx4_en_stop_port(dev, 1); 9938c2ecf20Sopenharmony_ci if (mlx4_en_start_port(dev)) 9948c2ecf20Sopenharmony_ci en_err(priv, "Failed restarting port %d\n", priv->port); 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci mutex_unlock(&priv->mdev->state_lock); 9978c2ecf20Sopenharmony_ci return 0; 9988c2ecf20Sopenharmony_ci} 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_cistatic int mlx4_en_get_coalesce(struct net_device *dev, 10018c2ecf20Sopenharmony_ci struct ethtool_coalesce *coal) 10028c2ecf20Sopenharmony_ci{ 10038c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci coal->tx_coalesce_usecs = priv->tx_usecs; 10068c2ecf20Sopenharmony_ci coal->tx_max_coalesced_frames = priv->tx_frames; 10078c2ecf20Sopenharmony_ci coal->tx_max_coalesced_frames_irq = priv->tx_work_limit; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs = priv->rx_usecs; 10108c2ecf20Sopenharmony_ci coal->rx_max_coalesced_frames = priv->rx_frames; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci coal->pkt_rate_low = priv->pkt_rate_low; 10138c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs_low = priv->rx_usecs_low; 10148c2ecf20Sopenharmony_ci coal->pkt_rate_high = priv->pkt_rate_high; 10158c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs_high = priv->rx_usecs_high; 10168c2ecf20Sopenharmony_ci coal->rate_sample_interval = priv->sample_interval; 10178c2ecf20Sopenharmony_ci coal->use_adaptive_rx_coalesce = priv->adaptive_rx_coal; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci return 0; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic int mlx4_en_set_coalesce(struct net_device *dev, 10238c2ecf20Sopenharmony_ci struct ethtool_coalesce *coal) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (!coal->tx_max_coalesced_frames_irq) 10288c2ecf20Sopenharmony_ci return -EINVAL; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if (coal->tx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME || 10318c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME || 10328c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs_low > MLX4_EN_MAX_COAL_TIME || 10338c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs_high > MLX4_EN_MAX_COAL_TIME) { 10348c2ecf20Sopenharmony_ci netdev_info(dev, "%s: maximum coalesce time supported is %d usecs\n", 10358c2ecf20Sopenharmony_ci __func__, MLX4_EN_MAX_COAL_TIME); 10368c2ecf20Sopenharmony_ci return -ERANGE; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (coal->tx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS || 10408c2ecf20Sopenharmony_ci coal->rx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS) { 10418c2ecf20Sopenharmony_ci netdev_info(dev, "%s: maximum coalesced frames supported is %d\n", 10428c2ecf20Sopenharmony_ci __func__, MLX4_EN_MAX_COAL_PKTS); 10438c2ecf20Sopenharmony_ci return -ERANGE; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci priv->rx_frames = (coal->rx_max_coalesced_frames == 10478c2ecf20Sopenharmony_ci MLX4_EN_AUTO_CONF) ? 10488c2ecf20Sopenharmony_ci MLX4_EN_RX_COAL_TARGET : 10498c2ecf20Sopenharmony_ci coal->rx_max_coalesced_frames; 10508c2ecf20Sopenharmony_ci priv->rx_usecs = (coal->rx_coalesce_usecs == 10518c2ecf20Sopenharmony_ci MLX4_EN_AUTO_CONF) ? 10528c2ecf20Sopenharmony_ci MLX4_EN_RX_COAL_TIME : 10538c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci /* Setting TX coalescing parameters */ 10568c2ecf20Sopenharmony_ci if (coal->tx_coalesce_usecs != priv->tx_usecs || 10578c2ecf20Sopenharmony_ci coal->tx_max_coalesced_frames != priv->tx_frames) { 10588c2ecf20Sopenharmony_ci priv->tx_usecs = coal->tx_coalesce_usecs; 10598c2ecf20Sopenharmony_ci priv->tx_frames = coal->tx_max_coalesced_frames; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* Set adaptive coalescing params */ 10638c2ecf20Sopenharmony_ci priv->pkt_rate_low = coal->pkt_rate_low; 10648c2ecf20Sopenharmony_ci priv->rx_usecs_low = coal->rx_coalesce_usecs_low; 10658c2ecf20Sopenharmony_ci priv->pkt_rate_high = coal->pkt_rate_high; 10668c2ecf20Sopenharmony_ci priv->rx_usecs_high = coal->rx_coalesce_usecs_high; 10678c2ecf20Sopenharmony_ci priv->sample_interval = coal->rate_sample_interval; 10688c2ecf20Sopenharmony_ci priv->adaptive_rx_coal = coal->use_adaptive_rx_coalesce; 10698c2ecf20Sopenharmony_ci priv->tx_work_limit = coal->tx_max_coalesced_frames_irq; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci return mlx4_en_moderation_update(priv); 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_cistatic int mlx4_en_set_pauseparam(struct net_device *dev, 10758c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 10788c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 10798c2ecf20Sopenharmony_ci u8 tx_pause, tx_ppp, rx_pause, rx_ppp; 10808c2ecf20Sopenharmony_ci int err; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (pause->autoneg) 10838c2ecf20Sopenharmony_ci return -EINVAL; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci tx_pause = !!(pause->tx_pause); 10868c2ecf20Sopenharmony_ci rx_pause = !!(pause->rx_pause); 10878c2ecf20Sopenharmony_ci rx_ppp = (tx_pause || rx_pause) ? 0 : priv->prof->rx_ppp; 10888c2ecf20Sopenharmony_ci tx_ppp = (tx_pause || rx_pause) ? 0 : priv->prof->tx_ppp; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci err = mlx4_SET_PORT_general(mdev->dev, priv->port, 10918c2ecf20Sopenharmony_ci priv->rx_skb_size + ETH_FCS_LEN, 10928c2ecf20Sopenharmony_ci tx_pause, tx_ppp, rx_pause, rx_ppp); 10938c2ecf20Sopenharmony_ci if (err) { 10948c2ecf20Sopenharmony_ci en_err(priv, "Failed setting pause params, err = %d\n", err); 10958c2ecf20Sopenharmony_ci return err; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, 10998c2ecf20Sopenharmony_ci rx_ppp, rx_pause, tx_ppp, tx_pause); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci priv->prof->tx_pause = tx_pause; 11028c2ecf20Sopenharmony_ci priv->prof->rx_pause = rx_pause; 11038c2ecf20Sopenharmony_ci priv->prof->tx_ppp = tx_ppp; 11048c2ecf20Sopenharmony_ci priv->prof->rx_ppp = rx_ppp; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci return err; 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic void mlx4_en_get_pause_stats(struct net_device *dev, 11108c2ecf20Sopenharmony_ci struct ethtool_pause_stats *stats) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 11138c2ecf20Sopenharmony_ci struct bitmap_iterator it; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci bitmap_iterator_init(&it, priv->stats_bitmap.bitmap, NUM_ALL_STATS); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci spin_lock_bh(&priv->stats_lock); 11188c2ecf20Sopenharmony_ci if (test_bit(FLOW_PRIORITY_STATS_IDX_TX_FRAMES, 11198c2ecf20Sopenharmony_ci priv->stats_bitmap.bitmap)) 11208c2ecf20Sopenharmony_ci stats->tx_pause_frames = priv->tx_flowstats.tx_pause; 11218c2ecf20Sopenharmony_ci if (test_bit(FLOW_PRIORITY_STATS_IDX_RX_FRAMES, 11228c2ecf20Sopenharmony_ci priv->stats_bitmap.bitmap)) 11238c2ecf20Sopenharmony_ci stats->rx_pause_frames = priv->rx_flowstats.rx_pause; 11248c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->stats_lock); 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic void mlx4_en_get_pauseparam(struct net_device *dev, 11288c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci pause->tx_pause = priv->prof->tx_pause; 11338c2ecf20Sopenharmony_ci pause->rx_pause = priv->prof->rx_pause; 11348c2ecf20Sopenharmony_ci} 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_cistatic int mlx4_en_set_ringparam(struct net_device *dev, 11378c2ecf20Sopenharmony_ci struct ethtool_ringparam *param) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 11408c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 11418c2ecf20Sopenharmony_ci struct mlx4_en_port_profile new_prof; 11428c2ecf20Sopenharmony_ci struct mlx4_en_priv *tmp; 11438c2ecf20Sopenharmony_ci u32 rx_size, tx_size; 11448c2ecf20Sopenharmony_ci int port_up = 0; 11458c2ecf20Sopenharmony_ci int err = 0; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (param->rx_jumbo_pending || param->rx_mini_pending) 11488c2ecf20Sopenharmony_ci return -EINVAL; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci if (param->rx_pending < MLX4_EN_MIN_RX_SIZE) { 11518c2ecf20Sopenharmony_ci en_warn(priv, "%s: rx_pending (%d) < min (%d)\n", 11528c2ecf20Sopenharmony_ci __func__, param->rx_pending, 11538c2ecf20Sopenharmony_ci MLX4_EN_MIN_RX_SIZE); 11548c2ecf20Sopenharmony_ci return -EINVAL; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci if (param->tx_pending < MLX4_EN_MIN_TX_SIZE) { 11578c2ecf20Sopenharmony_ci en_warn(priv, "%s: tx_pending (%d) < min (%lu)\n", 11588c2ecf20Sopenharmony_ci __func__, param->tx_pending, 11598c2ecf20Sopenharmony_ci MLX4_EN_MIN_TX_SIZE); 11608c2ecf20Sopenharmony_ci return -EINVAL; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci rx_size = roundup_pow_of_two(param->rx_pending); 11648c2ecf20Sopenharmony_ci tx_size = roundup_pow_of_two(param->tx_pending); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (rx_size == (priv->port_up ? priv->rx_ring[0]->actual_size : 11678c2ecf20Sopenharmony_ci priv->rx_ring[0]->size) && 11688c2ecf20Sopenharmony_ci tx_size == priv->tx_ring[TX][0]->size) 11698c2ecf20Sopenharmony_ci return 0; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 11728c2ecf20Sopenharmony_ci if (!tmp) 11738c2ecf20Sopenharmony_ci return -ENOMEM; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 11768c2ecf20Sopenharmony_ci memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); 11778c2ecf20Sopenharmony_ci new_prof.tx_ring_size = tx_size; 11788c2ecf20Sopenharmony_ci new_prof.rx_ring_size = rx_size; 11798c2ecf20Sopenharmony_ci err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, true); 11808c2ecf20Sopenharmony_ci if (err) 11818c2ecf20Sopenharmony_ci goto out; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci if (priv->port_up) { 11848c2ecf20Sopenharmony_ci port_up = 1; 11858c2ecf20Sopenharmony_ci mlx4_en_stop_port(dev, 1); 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci mlx4_en_safe_replace_resources(priv, tmp); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (port_up) { 11918c2ecf20Sopenharmony_ci err = mlx4_en_start_port(dev); 11928c2ecf20Sopenharmony_ci if (err) 11938c2ecf20Sopenharmony_ci en_err(priv, "Failed starting port\n"); 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci err = mlx4_en_moderation_update(priv); 11978c2ecf20Sopenharmony_ciout: 11988c2ecf20Sopenharmony_ci kfree(tmp); 11998c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 12008c2ecf20Sopenharmony_ci return err; 12018c2ecf20Sopenharmony_ci} 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_cistatic void mlx4_en_get_ringparam(struct net_device *dev, 12048c2ecf20Sopenharmony_ci struct ethtool_ringparam *param) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci memset(param, 0, sizeof(*param)); 12098c2ecf20Sopenharmony_ci param->rx_max_pending = MLX4_EN_MAX_RX_SIZE; 12108c2ecf20Sopenharmony_ci param->tx_max_pending = MLX4_EN_MAX_TX_SIZE; 12118c2ecf20Sopenharmony_ci param->rx_pending = priv->port_up ? 12128c2ecf20Sopenharmony_ci priv->rx_ring[0]->actual_size : priv->rx_ring[0]->size; 12138c2ecf20Sopenharmony_ci param->tx_pending = priv->tx_ring[TX][0]->size; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic u32 mlx4_en_get_rxfh_indir_size(struct net_device *dev) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci return rounddown_pow_of_two(priv->rx_ring_num); 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic u32 mlx4_en_get_rxfh_key_size(struct net_device *netdev) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci return MLX4_EN_RSS_KEY_SIZE; 12268c2ecf20Sopenharmony_ci} 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_cistatic int mlx4_en_check_rxfh_func(struct net_device *dev, u8 hfunc) 12298c2ecf20Sopenharmony_ci{ 12308c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci /* check if requested function is supported by the device */ 12338c2ecf20Sopenharmony_ci if (hfunc == ETH_RSS_HASH_TOP) { 12348c2ecf20Sopenharmony_ci if (!(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_TOP)) 12358c2ecf20Sopenharmony_ci return -EINVAL; 12368c2ecf20Sopenharmony_ci if (!(dev->features & NETIF_F_RXHASH)) 12378c2ecf20Sopenharmony_ci en_warn(priv, "Toeplitz hash function should be used in conjunction with RX hashing for optimal performance\n"); 12388c2ecf20Sopenharmony_ci return 0; 12398c2ecf20Sopenharmony_ci } else if (hfunc == ETH_RSS_HASH_XOR) { 12408c2ecf20Sopenharmony_ci if (!(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_XOR)) 12418c2ecf20Sopenharmony_ci return -EINVAL; 12428c2ecf20Sopenharmony_ci if (dev->features & NETIF_F_RXHASH) 12438c2ecf20Sopenharmony_ci en_warn(priv, "Enabling both XOR Hash function and RX Hashing can limit RPS functionality\n"); 12448c2ecf20Sopenharmony_ci return 0; 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci return -EINVAL; 12488c2ecf20Sopenharmony_ci} 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cistatic int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key, 12518c2ecf20Sopenharmony_ci u8 *hfunc) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 12548c2ecf20Sopenharmony_ci u32 n = mlx4_en_get_rxfh_indir_size(dev); 12558c2ecf20Sopenharmony_ci u32 i, rss_rings; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci rss_rings = priv->prof->rss_rings ?: n; 12588c2ecf20Sopenharmony_ci rss_rings = rounddown_pow_of_two(rss_rings); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 12618c2ecf20Sopenharmony_ci if (!ring_index) 12628c2ecf20Sopenharmony_ci break; 12638c2ecf20Sopenharmony_ci ring_index[i] = i % rss_rings; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci if (key) 12668c2ecf20Sopenharmony_ci memcpy(key, priv->rss_key, MLX4_EN_RSS_KEY_SIZE); 12678c2ecf20Sopenharmony_ci if (hfunc) 12688c2ecf20Sopenharmony_ci *hfunc = priv->rss_hash_fn; 12698c2ecf20Sopenharmony_ci return 0; 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_cistatic int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index, 12738c2ecf20Sopenharmony_ci const u8 *key, const u8 hfunc) 12748c2ecf20Sopenharmony_ci{ 12758c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 12768c2ecf20Sopenharmony_ci u32 n = mlx4_en_get_rxfh_indir_size(dev); 12778c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 12788c2ecf20Sopenharmony_ci int port_up = 0; 12798c2ecf20Sopenharmony_ci int err = 0; 12808c2ecf20Sopenharmony_ci int i; 12818c2ecf20Sopenharmony_ci int rss_rings = 0; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* Calculate RSS table size and make sure flows are spread evenly 12848c2ecf20Sopenharmony_ci * between rings 12858c2ecf20Sopenharmony_ci */ 12868c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 12878c2ecf20Sopenharmony_ci if (!ring_index) 12888c2ecf20Sopenharmony_ci break; 12898c2ecf20Sopenharmony_ci if (i > 0 && !ring_index[i] && !rss_rings) 12908c2ecf20Sopenharmony_ci rss_rings = i; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci if (ring_index[i] != (i % (rss_rings ?: n))) 12938c2ecf20Sopenharmony_ci return -EINVAL; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci if (!rss_rings) 12978c2ecf20Sopenharmony_ci rss_rings = n; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci /* RSS table size must be an order of 2 */ 13008c2ecf20Sopenharmony_ci if (!is_power_of_2(rss_rings)) 13018c2ecf20Sopenharmony_ci return -EINVAL; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE) { 13048c2ecf20Sopenharmony_ci err = mlx4_en_check_rxfh_func(dev, hfunc); 13058c2ecf20Sopenharmony_ci if (err) 13068c2ecf20Sopenharmony_ci return err; 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 13108c2ecf20Sopenharmony_ci if (priv->port_up) { 13118c2ecf20Sopenharmony_ci port_up = 1; 13128c2ecf20Sopenharmony_ci mlx4_en_stop_port(dev, 1); 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci if (ring_index) 13168c2ecf20Sopenharmony_ci priv->prof->rss_rings = rss_rings; 13178c2ecf20Sopenharmony_ci if (key) 13188c2ecf20Sopenharmony_ci memcpy(priv->rss_key, key, MLX4_EN_RSS_KEY_SIZE); 13198c2ecf20Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE) 13208c2ecf20Sopenharmony_ci priv->rss_hash_fn = hfunc; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci if (port_up) { 13238c2ecf20Sopenharmony_ci err = mlx4_en_start_port(dev); 13248c2ecf20Sopenharmony_ci if (err) 13258c2ecf20Sopenharmony_ci en_err(priv, "Failed starting port\n"); 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 13298c2ecf20Sopenharmony_ci return err; 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci#define all_zeros_or_all_ones(field) \ 13338c2ecf20Sopenharmony_ci ((field) == 0 || (field) == (__force typeof(field))-1) 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_cistatic int mlx4_en_validate_flow(struct net_device *dev, 13368c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci struct ethtool_usrip4_spec *l3_mask; 13398c2ecf20Sopenharmony_ci struct ethtool_tcpip4_spec *l4_mask; 13408c2ecf20Sopenharmony_ci struct ethhdr *eth_mask; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci if (cmd->fs.location >= MAX_NUM_OF_FS_RULES) 13438c2ecf20Sopenharmony_ci return -EINVAL; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci if (cmd->fs.flow_type & FLOW_MAC_EXT) { 13468c2ecf20Sopenharmony_ci /* dest mac mask must be ff:ff:ff:ff:ff:ff */ 13478c2ecf20Sopenharmony_ci if (!is_broadcast_ether_addr(cmd->fs.m_ext.h_dest)) 13488c2ecf20Sopenharmony_ci return -EINVAL; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { 13528c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 13538c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 13548c2ecf20Sopenharmony_ci if (cmd->fs.m_u.tcp_ip4_spec.tos) 13558c2ecf20Sopenharmony_ci return -EINVAL; 13568c2ecf20Sopenharmony_ci l4_mask = &cmd->fs.m_u.tcp_ip4_spec; 13578c2ecf20Sopenharmony_ci /* don't allow mask which isn't all 0 or 1 */ 13588c2ecf20Sopenharmony_ci if (!all_zeros_or_all_ones(l4_mask->ip4src) || 13598c2ecf20Sopenharmony_ci !all_zeros_or_all_ones(l4_mask->ip4dst) || 13608c2ecf20Sopenharmony_ci !all_zeros_or_all_ones(l4_mask->psrc) || 13618c2ecf20Sopenharmony_ci !all_zeros_or_all_ones(l4_mask->pdst)) 13628c2ecf20Sopenharmony_ci return -EINVAL; 13638c2ecf20Sopenharmony_ci break; 13648c2ecf20Sopenharmony_ci case IP_USER_FLOW: 13658c2ecf20Sopenharmony_ci l3_mask = &cmd->fs.m_u.usr_ip4_spec; 13668c2ecf20Sopenharmony_ci if (l3_mask->l4_4_bytes || l3_mask->tos || l3_mask->proto || 13678c2ecf20Sopenharmony_ci cmd->fs.h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4 || 13688c2ecf20Sopenharmony_ci (!l3_mask->ip4src && !l3_mask->ip4dst) || 13698c2ecf20Sopenharmony_ci !all_zeros_or_all_ones(l3_mask->ip4src) || 13708c2ecf20Sopenharmony_ci !all_zeros_or_all_ones(l3_mask->ip4dst)) 13718c2ecf20Sopenharmony_ci return -EINVAL; 13728c2ecf20Sopenharmony_ci break; 13738c2ecf20Sopenharmony_ci case ETHER_FLOW: 13748c2ecf20Sopenharmony_ci eth_mask = &cmd->fs.m_u.ether_spec; 13758c2ecf20Sopenharmony_ci /* source mac mask must not be set */ 13768c2ecf20Sopenharmony_ci if (!is_zero_ether_addr(eth_mask->h_source)) 13778c2ecf20Sopenharmony_ci return -EINVAL; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci /* dest mac mask must be ff:ff:ff:ff:ff:ff */ 13808c2ecf20Sopenharmony_ci if (!is_broadcast_ether_addr(eth_mask->h_dest)) 13818c2ecf20Sopenharmony_ci return -EINVAL; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (!all_zeros_or_all_ones(eth_mask->h_proto)) 13848c2ecf20Sopenharmony_ci return -EINVAL; 13858c2ecf20Sopenharmony_ci break; 13868c2ecf20Sopenharmony_ci default: 13878c2ecf20Sopenharmony_ci return -EINVAL; 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci if ((cmd->fs.flow_type & FLOW_EXT)) { 13918c2ecf20Sopenharmony_ci if (cmd->fs.m_ext.vlan_etype || 13928c2ecf20Sopenharmony_ci !((cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK)) == 13938c2ecf20Sopenharmony_ci 0 || 13948c2ecf20Sopenharmony_ci (cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK)) == 13958c2ecf20Sopenharmony_ci cpu_to_be16(VLAN_VID_MASK))) 13968c2ecf20Sopenharmony_ci return -EINVAL; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (cmd->fs.m_ext.vlan_tci) { 13998c2ecf20Sopenharmony_ci if (be16_to_cpu(cmd->fs.h_ext.vlan_tci) >= VLAN_N_VID) 14008c2ecf20Sopenharmony_ci return -EINVAL; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci return 0; 14068c2ecf20Sopenharmony_ci} 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_cistatic int mlx4_en_ethtool_add_mac_rule(struct ethtool_rxnfc *cmd, 14098c2ecf20Sopenharmony_ci struct list_head *rule_list_h, 14108c2ecf20Sopenharmony_ci struct mlx4_spec_list *spec_l2, 14118c2ecf20Sopenharmony_ci unsigned char *mac) 14128c2ecf20Sopenharmony_ci{ 14138c2ecf20Sopenharmony_ci __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci spec_l2->id = MLX4_NET_TRANS_RULE_ID_ETH; 14168c2ecf20Sopenharmony_ci memcpy(spec_l2->eth.dst_mac_msk, &mac_msk, ETH_ALEN); 14178c2ecf20Sopenharmony_ci memcpy(spec_l2->eth.dst_mac, mac, ETH_ALEN); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if ((cmd->fs.flow_type & FLOW_EXT) && 14208c2ecf20Sopenharmony_ci (cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK))) { 14218c2ecf20Sopenharmony_ci spec_l2->eth.vlan_id = cmd->fs.h_ext.vlan_tci; 14228c2ecf20Sopenharmony_ci spec_l2->eth.vlan_id_msk = cpu_to_be16(VLAN_VID_MASK); 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci list_add_tail(&spec_l2->list, rule_list_h); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci return 0; 14288c2ecf20Sopenharmony_ci} 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_cistatic int mlx4_en_ethtool_add_mac_rule_by_ipv4(struct mlx4_en_priv *priv, 14318c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd, 14328c2ecf20Sopenharmony_ci struct list_head *rule_list_h, 14338c2ecf20Sopenharmony_ci struct mlx4_spec_list *spec_l2, 14348c2ecf20Sopenharmony_ci __be32 ipv4_dst) 14358c2ecf20Sopenharmony_ci{ 14368c2ecf20Sopenharmony_ci#ifdef CONFIG_INET 14378c2ecf20Sopenharmony_ci unsigned char mac[ETH_ALEN]; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci if (!ipv4_is_multicast(ipv4_dst)) { 14408c2ecf20Sopenharmony_ci if (cmd->fs.flow_type & FLOW_MAC_EXT) 14418c2ecf20Sopenharmony_ci memcpy(&mac, cmd->fs.h_ext.h_dest, ETH_ALEN); 14428c2ecf20Sopenharmony_ci else 14438c2ecf20Sopenharmony_ci memcpy(&mac, priv->dev->dev_addr, ETH_ALEN); 14448c2ecf20Sopenharmony_ci } else { 14458c2ecf20Sopenharmony_ci ip_eth_mc_map(ipv4_dst, mac); 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci return mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2, &mac[0]); 14498c2ecf20Sopenharmony_ci#else 14508c2ecf20Sopenharmony_ci return -EINVAL; 14518c2ecf20Sopenharmony_ci#endif 14528c2ecf20Sopenharmony_ci} 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_cistatic int add_ip_rule(struct mlx4_en_priv *priv, 14558c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd, 14568c2ecf20Sopenharmony_ci struct list_head *list_h) 14578c2ecf20Sopenharmony_ci{ 14588c2ecf20Sopenharmony_ci int err; 14598c2ecf20Sopenharmony_ci struct mlx4_spec_list *spec_l2 = NULL; 14608c2ecf20Sopenharmony_ci struct mlx4_spec_list *spec_l3 = NULL; 14618c2ecf20Sopenharmony_ci struct ethtool_usrip4_spec *l3_mask = &cmd->fs.m_u.usr_ip4_spec; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL); 14648c2ecf20Sopenharmony_ci spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL); 14658c2ecf20Sopenharmony_ci if (!spec_l2 || !spec_l3) { 14668c2ecf20Sopenharmony_ci err = -ENOMEM; 14678c2ecf20Sopenharmony_ci goto free_spec; 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci err = mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h, spec_l2, 14718c2ecf20Sopenharmony_ci cmd->fs.h_u. 14728c2ecf20Sopenharmony_ci usr_ip4_spec.ip4dst); 14738c2ecf20Sopenharmony_ci if (err) 14748c2ecf20Sopenharmony_ci goto free_spec; 14758c2ecf20Sopenharmony_ci spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4; 14768c2ecf20Sopenharmony_ci spec_l3->ipv4.src_ip = cmd->fs.h_u.usr_ip4_spec.ip4src; 14778c2ecf20Sopenharmony_ci if (l3_mask->ip4src) 14788c2ecf20Sopenharmony_ci spec_l3->ipv4.src_ip_msk = EN_ETHTOOL_WORD_MASK; 14798c2ecf20Sopenharmony_ci spec_l3->ipv4.dst_ip = cmd->fs.h_u.usr_ip4_spec.ip4dst; 14808c2ecf20Sopenharmony_ci if (l3_mask->ip4dst) 14818c2ecf20Sopenharmony_ci spec_l3->ipv4.dst_ip_msk = EN_ETHTOOL_WORD_MASK; 14828c2ecf20Sopenharmony_ci list_add_tail(&spec_l3->list, list_h); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci return 0; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_cifree_spec: 14878c2ecf20Sopenharmony_ci kfree(spec_l2); 14888c2ecf20Sopenharmony_ci kfree(spec_l3); 14898c2ecf20Sopenharmony_ci return err; 14908c2ecf20Sopenharmony_ci} 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_cistatic int add_tcp_udp_rule(struct mlx4_en_priv *priv, 14938c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd, 14948c2ecf20Sopenharmony_ci struct list_head *list_h, int proto) 14958c2ecf20Sopenharmony_ci{ 14968c2ecf20Sopenharmony_ci int err; 14978c2ecf20Sopenharmony_ci struct mlx4_spec_list *spec_l2 = NULL; 14988c2ecf20Sopenharmony_ci struct mlx4_spec_list *spec_l3 = NULL; 14998c2ecf20Sopenharmony_ci struct mlx4_spec_list *spec_l4 = NULL; 15008c2ecf20Sopenharmony_ci struct ethtool_tcpip4_spec *l4_mask = &cmd->fs.m_u.tcp_ip4_spec; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL); 15038c2ecf20Sopenharmony_ci spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL); 15048c2ecf20Sopenharmony_ci spec_l4 = kzalloc(sizeof(*spec_l4), GFP_KERNEL); 15058c2ecf20Sopenharmony_ci if (!spec_l2 || !spec_l3 || !spec_l4) { 15068c2ecf20Sopenharmony_ci err = -ENOMEM; 15078c2ecf20Sopenharmony_ci goto free_spec; 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci if (proto == TCP_V4_FLOW) { 15138c2ecf20Sopenharmony_ci err = mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h, 15148c2ecf20Sopenharmony_ci spec_l2, 15158c2ecf20Sopenharmony_ci cmd->fs.h_u. 15168c2ecf20Sopenharmony_ci tcp_ip4_spec.ip4dst); 15178c2ecf20Sopenharmony_ci if (err) 15188c2ecf20Sopenharmony_ci goto free_spec; 15198c2ecf20Sopenharmony_ci spec_l4->id = MLX4_NET_TRANS_RULE_ID_TCP; 15208c2ecf20Sopenharmony_ci spec_l3->ipv4.src_ip = cmd->fs.h_u.tcp_ip4_spec.ip4src; 15218c2ecf20Sopenharmony_ci spec_l3->ipv4.dst_ip = cmd->fs.h_u.tcp_ip4_spec.ip4dst; 15228c2ecf20Sopenharmony_ci spec_l4->tcp_udp.src_port = cmd->fs.h_u.tcp_ip4_spec.psrc; 15238c2ecf20Sopenharmony_ci spec_l4->tcp_udp.dst_port = cmd->fs.h_u.tcp_ip4_spec.pdst; 15248c2ecf20Sopenharmony_ci } else { 15258c2ecf20Sopenharmony_ci err = mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h, 15268c2ecf20Sopenharmony_ci spec_l2, 15278c2ecf20Sopenharmony_ci cmd->fs.h_u. 15288c2ecf20Sopenharmony_ci udp_ip4_spec.ip4dst); 15298c2ecf20Sopenharmony_ci if (err) 15308c2ecf20Sopenharmony_ci goto free_spec; 15318c2ecf20Sopenharmony_ci spec_l4->id = MLX4_NET_TRANS_RULE_ID_UDP; 15328c2ecf20Sopenharmony_ci spec_l3->ipv4.src_ip = cmd->fs.h_u.udp_ip4_spec.ip4src; 15338c2ecf20Sopenharmony_ci spec_l3->ipv4.dst_ip = cmd->fs.h_u.udp_ip4_spec.ip4dst; 15348c2ecf20Sopenharmony_ci spec_l4->tcp_udp.src_port = cmd->fs.h_u.udp_ip4_spec.psrc; 15358c2ecf20Sopenharmony_ci spec_l4->tcp_udp.dst_port = cmd->fs.h_u.udp_ip4_spec.pdst; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (l4_mask->ip4src) 15398c2ecf20Sopenharmony_ci spec_l3->ipv4.src_ip_msk = EN_ETHTOOL_WORD_MASK; 15408c2ecf20Sopenharmony_ci if (l4_mask->ip4dst) 15418c2ecf20Sopenharmony_ci spec_l3->ipv4.dst_ip_msk = EN_ETHTOOL_WORD_MASK; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci if (l4_mask->psrc) 15448c2ecf20Sopenharmony_ci spec_l4->tcp_udp.src_port_msk = EN_ETHTOOL_SHORT_MASK; 15458c2ecf20Sopenharmony_ci if (l4_mask->pdst) 15468c2ecf20Sopenharmony_ci spec_l4->tcp_udp.dst_port_msk = EN_ETHTOOL_SHORT_MASK; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci list_add_tail(&spec_l3->list, list_h); 15498c2ecf20Sopenharmony_ci list_add_tail(&spec_l4->list, list_h); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci return 0; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_cifree_spec: 15548c2ecf20Sopenharmony_ci kfree(spec_l2); 15558c2ecf20Sopenharmony_ci kfree(spec_l3); 15568c2ecf20Sopenharmony_ci kfree(spec_l4); 15578c2ecf20Sopenharmony_ci return err; 15588c2ecf20Sopenharmony_ci} 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_cistatic int mlx4_en_ethtool_to_net_trans_rule(struct net_device *dev, 15618c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd, 15628c2ecf20Sopenharmony_ci struct list_head *rule_list_h) 15638c2ecf20Sopenharmony_ci{ 15648c2ecf20Sopenharmony_ci int err; 15658c2ecf20Sopenharmony_ci struct ethhdr *eth_spec; 15668c2ecf20Sopenharmony_ci struct mlx4_spec_list *spec_l2; 15678c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci err = mlx4_en_validate_flow(dev, cmd); 15708c2ecf20Sopenharmony_ci if (err) 15718c2ecf20Sopenharmony_ci return err; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { 15748c2ecf20Sopenharmony_ci case ETHER_FLOW: 15758c2ecf20Sopenharmony_ci spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL); 15768c2ecf20Sopenharmony_ci if (!spec_l2) 15778c2ecf20Sopenharmony_ci return -ENOMEM; 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci eth_spec = &cmd->fs.h_u.ether_spec; 15808c2ecf20Sopenharmony_ci mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2, 15818c2ecf20Sopenharmony_ci ð_spec->h_dest[0]); 15828c2ecf20Sopenharmony_ci spec_l2->eth.ether_type = eth_spec->h_proto; 15838c2ecf20Sopenharmony_ci if (eth_spec->h_proto) 15848c2ecf20Sopenharmony_ci spec_l2->eth.ether_type_enable = 1; 15858c2ecf20Sopenharmony_ci break; 15868c2ecf20Sopenharmony_ci case IP_USER_FLOW: 15878c2ecf20Sopenharmony_ci err = add_ip_rule(priv, cmd, rule_list_h); 15888c2ecf20Sopenharmony_ci break; 15898c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 15908c2ecf20Sopenharmony_ci err = add_tcp_udp_rule(priv, cmd, rule_list_h, TCP_V4_FLOW); 15918c2ecf20Sopenharmony_ci break; 15928c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 15938c2ecf20Sopenharmony_ci err = add_tcp_udp_rule(priv, cmd, rule_list_h, UDP_V4_FLOW); 15948c2ecf20Sopenharmony_ci break; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci return err; 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic int mlx4_en_flow_replace(struct net_device *dev, 16018c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 16028c2ecf20Sopenharmony_ci{ 16038c2ecf20Sopenharmony_ci int err; 16048c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 16058c2ecf20Sopenharmony_ci struct ethtool_flow_id *loc_rule; 16068c2ecf20Sopenharmony_ci struct mlx4_spec_list *spec, *tmp_spec; 16078c2ecf20Sopenharmony_ci u32 qpn; 16088c2ecf20Sopenharmony_ci u64 reg_id; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci struct mlx4_net_trans_rule rule = { 16118c2ecf20Sopenharmony_ci .queue_mode = MLX4_NET_TRANS_Q_FIFO, 16128c2ecf20Sopenharmony_ci .exclusive = 0, 16138c2ecf20Sopenharmony_ci .allow_loopback = 1, 16148c2ecf20Sopenharmony_ci .promisc_mode = MLX4_FS_REGULAR, 16158c2ecf20Sopenharmony_ci }; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci rule.port = priv->port; 16188c2ecf20Sopenharmony_ci rule.priority = MLX4_DOMAIN_ETHTOOL | cmd->fs.location; 16198c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rule.list); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci /* Allow direct QP attaches if the EN_ETHTOOL_QP_ATTACH flag is set */ 16228c2ecf20Sopenharmony_ci if (cmd->fs.ring_cookie == RX_CLS_FLOW_DISC) 16238c2ecf20Sopenharmony_ci qpn = priv->drop_qp.qpn; 16248c2ecf20Sopenharmony_ci else if (cmd->fs.ring_cookie & EN_ETHTOOL_QP_ATTACH) { 16258c2ecf20Sopenharmony_ci qpn = cmd->fs.ring_cookie & (EN_ETHTOOL_QP_ATTACH - 1); 16268c2ecf20Sopenharmony_ci } else { 16278c2ecf20Sopenharmony_ci if (cmd->fs.ring_cookie >= priv->rx_ring_num) { 16288c2ecf20Sopenharmony_ci en_warn(priv, "rxnfc: RX ring (%llu) doesn't exist\n", 16298c2ecf20Sopenharmony_ci cmd->fs.ring_cookie); 16308c2ecf20Sopenharmony_ci return -EINVAL; 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci qpn = priv->rss_map.qps[cmd->fs.ring_cookie].qpn; 16338c2ecf20Sopenharmony_ci if (!qpn) { 16348c2ecf20Sopenharmony_ci en_warn(priv, "rxnfc: RX ring (%llu) is inactive\n", 16358c2ecf20Sopenharmony_ci cmd->fs.ring_cookie); 16368c2ecf20Sopenharmony_ci return -EINVAL; 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci rule.qpn = qpn; 16408c2ecf20Sopenharmony_ci err = mlx4_en_ethtool_to_net_trans_rule(dev, cmd, &rule.list); 16418c2ecf20Sopenharmony_ci if (err) 16428c2ecf20Sopenharmony_ci goto out_free_list; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci loc_rule = &priv->ethtool_rules[cmd->fs.location]; 16458c2ecf20Sopenharmony_ci if (loc_rule->id) { 16468c2ecf20Sopenharmony_ci err = mlx4_flow_detach(priv->mdev->dev, loc_rule->id); 16478c2ecf20Sopenharmony_ci if (err) { 16488c2ecf20Sopenharmony_ci en_err(priv, "Fail to detach network rule at location %d. registration id = %llx\n", 16498c2ecf20Sopenharmony_ci cmd->fs.location, loc_rule->id); 16508c2ecf20Sopenharmony_ci goto out_free_list; 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci loc_rule->id = 0; 16538c2ecf20Sopenharmony_ci memset(&loc_rule->flow_spec, 0, 16548c2ecf20Sopenharmony_ci sizeof(struct ethtool_rx_flow_spec)); 16558c2ecf20Sopenharmony_ci list_del(&loc_rule->list); 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci err = mlx4_flow_attach(priv->mdev->dev, &rule, ®_id); 16588c2ecf20Sopenharmony_ci if (err) { 16598c2ecf20Sopenharmony_ci en_err(priv, "Fail to attach network rule at location %d\n", 16608c2ecf20Sopenharmony_ci cmd->fs.location); 16618c2ecf20Sopenharmony_ci goto out_free_list; 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci loc_rule->id = reg_id; 16648c2ecf20Sopenharmony_ci memcpy(&loc_rule->flow_spec, &cmd->fs, 16658c2ecf20Sopenharmony_ci sizeof(struct ethtool_rx_flow_spec)); 16668c2ecf20Sopenharmony_ci list_add_tail(&loc_rule->list, &priv->ethtool_list); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ciout_free_list: 16698c2ecf20Sopenharmony_ci list_for_each_entry_safe(spec, tmp_spec, &rule.list, list) { 16708c2ecf20Sopenharmony_ci list_del(&spec->list); 16718c2ecf20Sopenharmony_ci kfree(spec); 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci return err; 16748c2ecf20Sopenharmony_ci} 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_cistatic int mlx4_en_flow_detach(struct net_device *dev, 16778c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 16788c2ecf20Sopenharmony_ci{ 16798c2ecf20Sopenharmony_ci int err = 0; 16808c2ecf20Sopenharmony_ci struct ethtool_flow_id *rule; 16818c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci if (cmd->fs.location >= MAX_NUM_OF_FS_RULES) 16848c2ecf20Sopenharmony_ci return -EINVAL; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci rule = &priv->ethtool_rules[cmd->fs.location]; 16878c2ecf20Sopenharmony_ci if (!rule->id) { 16888c2ecf20Sopenharmony_ci err = -ENOENT; 16898c2ecf20Sopenharmony_ci goto out; 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci err = mlx4_flow_detach(priv->mdev->dev, rule->id); 16938c2ecf20Sopenharmony_ci if (err) { 16948c2ecf20Sopenharmony_ci en_err(priv, "Fail to detach network rule at location %d. registration id = 0x%llx\n", 16958c2ecf20Sopenharmony_ci cmd->fs.location, rule->id); 16968c2ecf20Sopenharmony_ci goto out; 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci rule->id = 0; 16998c2ecf20Sopenharmony_ci memset(&rule->flow_spec, 0, sizeof(struct ethtool_rx_flow_spec)); 17008c2ecf20Sopenharmony_ci list_del(&rule->list); 17018c2ecf20Sopenharmony_ciout: 17028c2ecf20Sopenharmony_ci return err; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci} 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_cistatic int mlx4_en_get_flow(struct net_device *dev, struct ethtool_rxnfc *cmd, 17078c2ecf20Sopenharmony_ci int loc) 17088c2ecf20Sopenharmony_ci{ 17098c2ecf20Sopenharmony_ci int err = 0; 17108c2ecf20Sopenharmony_ci struct ethtool_flow_id *rule; 17118c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci if (loc < 0 || loc >= MAX_NUM_OF_FS_RULES) 17148c2ecf20Sopenharmony_ci return -EINVAL; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci rule = &priv->ethtool_rules[loc]; 17178c2ecf20Sopenharmony_ci if (rule->id) 17188c2ecf20Sopenharmony_ci memcpy(&cmd->fs, &rule->flow_spec, 17198c2ecf20Sopenharmony_ci sizeof(struct ethtool_rx_flow_spec)); 17208c2ecf20Sopenharmony_ci else 17218c2ecf20Sopenharmony_ci err = -ENOENT; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci return err; 17248c2ecf20Sopenharmony_ci} 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_cistatic int mlx4_en_get_num_flows(struct mlx4_en_priv *priv) 17278c2ecf20Sopenharmony_ci{ 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci int i, res = 0; 17308c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NUM_OF_FS_RULES; i++) { 17318c2ecf20Sopenharmony_ci if (priv->ethtool_rules[i].id) 17328c2ecf20Sopenharmony_ci res++; 17338c2ecf20Sopenharmony_ci } 17348c2ecf20Sopenharmony_ci return res; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_cistatic int mlx4_en_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 17398c2ecf20Sopenharmony_ci u32 *rule_locs) 17408c2ecf20Sopenharmony_ci{ 17418c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 17428c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 17438c2ecf20Sopenharmony_ci int err = 0; 17448c2ecf20Sopenharmony_ci int i = 0, priority = 0; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci if ((cmd->cmd == ETHTOOL_GRXCLSRLCNT || 17478c2ecf20Sopenharmony_ci cmd->cmd == ETHTOOL_GRXCLSRULE || 17488c2ecf20Sopenharmony_ci cmd->cmd == ETHTOOL_GRXCLSRLALL) && 17498c2ecf20Sopenharmony_ci (mdev->dev->caps.steering_mode != 17508c2ecf20Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED || !priv->port_up)) 17518c2ecf20Sopenharmony_ci return -EINVAL; 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci switch (cmd->cmd) { 17548c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 17558c2ecf20Sopenharmony_ci cmd->data = priv->rx_ring_num; 17568c2ecf20Sopenharmony_ci break; 17578c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 17588c2ecf20Sopenharmony_ci cmd->rule_cnt = mlx4_en_get_num_flows(priv); 17598c2ecf20Sopenharmony_ci break; 17608c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 17618c2ecf20Sopenharmony_ci err = mlx4_en_get_flow(dev, cmd, cmd->fs.location); 17628c2ecf20Sopenharmony_ci break; 17638c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 17648c2ecf20Sopenharmony_ci cmd->data = MAX_NUM_OF_FS_RULES; 17658c2ecf20Sopenharmony_ci while ((!err || err == -ENOENT) && priority < cmd->rule_cnt) { 17668c2ecf20Sopenharmony_ci err = mlx4_en_get_flow(dev, cmd, i); 17678c2ecf20Sopenharmony_ci if (!err) 17688c2ecf20Sopenharmony_ci rule_locs[priority++] = i; 17698c2ecf20Sopenharmony_ci i++; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci err = 0; 17728c2ecf20Sopenharmony_ci break; 17738c2ecf20Sopenharmony_ci default: 17748c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 17758c2ecf20Sopenharmony_ci break; 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci return err; 17798c2ecf20Sopenharmony_ci} 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_cistatic int mlx4_en_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 17828c2ecf20Sopenharmony_ci{ 17838c2ecf20Sopenharmony_ci int err = 0; 17848c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 17858c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci if (mdev->dev->caps.steering_mode != 17888c2ecf20Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED || !priv->port_up) 17898c2ecf20Sopenharmony_ci return -EINVAL; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci switch (cmd->cmd) { 17928c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 17938c2ecf20Sopenharmony_ci err = mlx4_en_flow_replace(dev, cmd); 17948c2ecf20Sopenharmony_ci break; 17958c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 17968c2ecf20Sopenharmony_ci err = mlx4_en_flow_detach(dev, cmd); 17978c2ecf20Sopenharmony_ci break; 17988c2ecf20Sopenharmony_ci default: 17998c2ecf20Sopenharmony_ci en_warn(priv, "Unsupported ethtool command. (%d)\n", cmd->cmd); 18008c2ecf20Sopenharmony_ci return -EINVAL; 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci return err; 18048c2ecf20Sopenharmony_ci} 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_cistatic int mlx4_en_get_max_num_rx_rings(struct net_device *dev) 18078c2ecf20Sopenharmony_ci{ 18088c2ecf20Sopenharmony_ci return min_t(int, num_online_cpus(), MAX_RX_RINGS); 18098c2ecf20Sopenharmony_ci} 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_cistatic void mlx4_en_get_channels(struct net_device *dev, 18128c2ecf20Sopenharmony_ci struct ethtool_channels *channel) 18138c2ecf20Sopenharmony_ci{ 18148c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci channel->max_rx = mlx4_en_get_max_num_rx_rings(dev); 18178c2ecf20Sopenharmony_ci channel->max_tx = priv->mdev->profile.max_num_tx_rings_p_up; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci channel->rx_count = priv->rx_ring_num; 18208c2ecf20Sopenharmony_ci channel->tx_count = priv->tx_ring_num[TX] / 18218c2ecf20Sopenharmony_ci priv->prof->num_up; 18228c2ecf20Sopenharmony_ci} 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_cistatic int mlx4_en_set_channels(struct net_device *dev, 18258c2ecf20Sopenharmony_ci struct ethtool_channels *channel) 18268c2ecf20Sopenharmony_ci{ 18278c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 18288c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 18298c2ecf20Sopenharmony_ci struct mlx4_en_port_profile new_prof; 18308c2ecf20Sopenharmony_ci struct mlx4_en_priv *tmp; 18318c2ecf20Sopenharmony_ci int total_tx_count; 18328c2ecf20Sopenharmony_ci int port_up = 0; 18338c2ecf20Sopenharmony_ci int xdp_count; 18348c2ecf20Sopenharmony_ci int err = 0; 18358c2ecf20Sopenharmony_ci u8 up; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci if (!channel->tx_count || !channel->rx_count) 18388c2ecf20Sopenharmony_ci return -EINVAL; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 18418c2ecf20Sopenharmony_ci if (!tmp) 18428c2ecf20Sopenharmony_ci return -ENOMEM; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 18458c2ecf20Sopenharmony_ci xdp_count = priv->tx_ring_num[TX_XDP] ? channel->rx_count : 0; 18468c2ecf20Sopenharmony_ci total_tx_count = channel->tx_count * priv->prof->num_up + xdp_count; 18478c2ecf20Sopenharmony_ci if (total_tx_count > MAX_TX_RINGS) { 18488c2ecf20Sopenharmony_ci err = -EINVAL; 18498c2ecf20Sopenharmony_ci en_err(priv, 18508c2ecf20Sopenharmony_ci "Total number of TX and XDP rings (%d) exceeds the maximum supported (%d)\n", 18518c2ecf20Sopenharmony_ci total_tx_count, MAX_TX_RINGS); 18528c2ecf20Sopenharmony_ci goto out; 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); 18568c2ecf20Sopenharmony_ci new_prof.num_tx_rings_p_up = channel->tx_count; 18578c2ecf20Sopenharmony_ci new_prof.tx_ring_num[TX] = channel->tx_count * priv->prof->num_up; 18588c2ecf20Sopenharmony_ci new_prof.tx_ring_num[TX_XDP] = xdp_count; 18598c2ecf20Sopenharmony_ci new_prof.rx_ring_num = channel->rx_count; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, true); 18628c2ecf20Sopenharmony_ci if (err) 18638c2ecf20Sopenharmony_ci goto out; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci if (priv->port_up) { 18668c2ecf20Sopenharmony_ci port_up = 1; 18678c2ecf20Sopenharmony_ci mlx4_en_stop_port(dev, 1); 18688c2ecf20Sopenharmony_ci } 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci mlx4_en_safe_replace_resources(priv, tmp); 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci netif_set_real_num_rx_queues(dev, priv->rx_ring_num); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci up = (priv->prof->num_up == MLX4_EN_NUM_UP_LOW) ? 18758c2ecf20Sopenharmony_ci 0 : priv->prof->num_up; 18768c2ecf20Sopenharmony_ci mlx4_en_setup_tc(dev, up); 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci en_warn(priv, "Using %d TX rings\n", priv->tx_ring_num[TX]); 18798c2ecf20Sopenharmony_ci en_warn(priv, "Using %d RX rings\n", priv->rx_ring_num); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci if (port_up) { 18828c2ecf20Sopenharmony_ci err = mlx4_en_start_port(dev); 18838c2ecf20Sopenharmony_ci if (err) 18848c2ecf20Sopenharmony_ci en_err(priv, "Failed starting port\n"); 18858c2ecf20Sopenharmony_ci } 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci err = mlx4_en_moderation_update(priv); 18888c2ecf20Sopenharmony_ciout: 18898c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 18908c2ecf20Sopenharmony_ci kfree(tmp); 18918c2ecf20Sopenharmony_ci return err; 18928c2ecf20Sopenharmony_ci} 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_cistatic int mlx4_en_get_ts_info(struct net_device *dev, 18958c2ecf20Sopenharmony_ci struct ethtool_ts_info *info) 18968c2ecf20Sopenharmony_ci{ 18978c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 18988c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 18998c2ecf20Sopenharmony_ci int ret; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci ret = ethtool_op_get_ts_info(dev, info); 19028c2ecf20Sopenharmony_ci if (ret) 19038c2ecf20Sopenharmony_ci return ret; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) { 19068c2ecf20Sopenharmony_ci info->so_timestamping |= 19078c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 19088c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 19098c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci info->tx_types = 19128c2ecf20Sopenharmony_ci (1 << HWTSTAMP_TX_OFF) | 19138c2ecf20Sopenharmony_ci (1 << HWTSTAMP_TX_ON); 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci info->rx_filters = 19168c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_NONE) | 19178c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_ALL); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci if (mdev->ptp_clock) 19208c2ecf20Sopenharmony_ci info->phc_index = ptp_clock_index(mdev->ptp_clock); 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci return ret; 19248c2ecf20Sopenharmony_ci} 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_cistatic int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags) 19278c2ecf20Sopenharmony_ci{ 19288c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 19298c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 19308c2ecf20Sopenharmony_ci bool bf_enabled_new = !!(flags & MLX4_EN_PRIV_FLAGS_BLUEFLAME); 19318c2ecf20Sopenharmony_ci bool bf_enabled_old = !!(priv->pflags & MLX4_EN_PRIV_FLAGS_BLUEFLAME); 19328c2ecf20Sopenharmony_ci bool phv_enabled_new = !!(flags & MLX4_EN_PRIV_FLAGS_PHV); 19338c2ecf20Sopenharmony_ci bool phv_enabled_old = !!(priv->pflags & MLX4_EN_PRIV_FLAGS_PHV); 19348c2ecf20Sopenharmony_ci int i; 19358c2ecf20Sopenharmony_ci int ret = 0; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci if (bf_enabled_new != bf_enabled_old) { 19388c2ecf20Sopenharmony_ci int t; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci if (bf_enabled_new) { 19418c2ecf20Sopenharmony_ci bool bf_supported = true; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) 19448c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) 19458c2ecf20Sopenharmony_ci bf_supported &= 19468c2ecf20Sopenharmony_ci priv->tx_ring[t][i]->bf_alloced; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci if (!bf_supported) { 19498c2ecf20Sopenharmony_ci en_err(priv, "BlueFlame is not supported\n"); 19508c2ecf20Sopenharmony_ci return -EINVAL; 19518c2ecf20Sopenharmony_ci } 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci priv->pflags |= MLX4_EN_PRIV_FLAGS_BLUEFLAME; 19548c2ecf20Sopenharmony_ci } else { 19558c2ecf20Sopenharmony_ci priv->pflags &= ~MLX4_EN_PRIV_FLAGS_BLUEFLAME; 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) 19598c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) 19608c2ecf20Sopenharmony_ci priv->tx_ring[t][i]->bf_enabled = 19618c2ecf20Sopenharmony_ci bf_enabled_new; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci en_info(priv, "BlueFlame %s\n", 19648c2ecf20Sopenharmony_ci bf_enabled_new ? "Enabled" : "Disabled"); 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci if (phv_enabled_new != phv_enabled_old) { 19688c2ecf20Sopenharmony_ci ret = set_phv_bit(mdev->dev, priv->port, (int)phv_enabled_new); 19698c2ecf20Sopenharmony_ci if (ret) 19708c2ecf20Sopenharmony_ci return ret; 19718c2ecf20Sopenharmony_ci else if (phv_enabled_new) 19728c2ecf20Sopenharmony_ci priv->pflags |= MLX4_EN_PRIV_FLAGS_PHV; 19738c2ecf20Sopenharmony_ci else 19748c2ecf20Sopenharmony_ci priv->pflags &= ~MLX4_EN_PRIV_FLAGS_PHV; 19758c2ecf20Sopenharmony_ci en_info(priv, "PHV bit %s\n", 19768c2ecf20Sopenharmony_ci phv_enabled_new ? "Enabled" : "Disabled"); 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci return 0; 19798c2ecf20Sopenharmony_ci} 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_cistatic u32 mlx4_en_get_priv_flags(struct net_device *dev) 19828c2ecf20Sopenharmony_ci{ 19838c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci return priv->pflags; 19868c2ecf20Sopenharmony_ci} 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_cistatic int mlx4_en_get_tunable(struct net_device *dev, 19898c2ecf20Sopenharmony_ci const struct ethtool_tunable *tuna, 19908c2ecf20Sopenharmony_ci void *data) 19918c2ecf20Sopenharmony_ci{ 19928c2ecf20Sopenharmony_ci const struct mlx4_en_priv *priv = netdev_priv(dev); 19938c2ecf20Sopenharmony_ci int ret = 0; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci switch (tuna->id) { 19968c2ecf20Sopenharmony_ci case ETHTOOL_TX_COPYBREAK: 19978c2ecf20Sopenharmony_ci *(u32 *)data = priv->prof->inline_thold; 19988c2ecf20Sopenharmony_ci break; 19998c2ecf20Sopenharmony_ci default: 20008c2ecf20Sopenharmony_ci ret = -EINVAL; 20018c2ecf20Sopenharmony_ci break; 20028c2ecf20Sopenharmony_ci } 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci return ret; 20058c2ecf20Sopenharmony_ci} 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_cistatic int mlx4_en_set_tunable(struct net_device *dev, 20088c2ecf20Sopenharmony_ci const struct ethtool_tunable *tuna, 20098c2ecf20Sopenharmony_ci const void *data) 20108c2ecf20Sopenharmony_ci{ 20118c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 20128c2ecf20Sopenharmony_ci int val, ret = 0; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci switch (tuna->id) { 20158c2ecf20Sopenharmony_ci case ETHTOOL_TX_COPYBREAK: 20168c2ecf20Sopenharmony_ci val = *(u32 *)data; 20178c2ecf20Sopenharmony_ci if (val < MIN_PKT_LEN || val > MAX_INLINE) 20188c2ecf20Sopenharmony_ci ret = -EINVAL; 20198c2ecf20Sopenharmony_ci else 20208c2ecf20Sopenharmony_ci priv->prof->inline_thold = val; 20218c2ecf20Sopenharmony_ci break; 20228c2ecf20Sopenharmony_ci default: 20238c2ecf20Sopenharmony_ci ret = -EINVAL; 20248c2ecf20Sopenharmony_ci break; 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci return ret; 20288c2ecf20Sopenharmony_ci} 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_cistatic int mlx4_en_get_module_info(struct net_device *dev, 20318c2ecf20Sopenharmony_ci struct ethtool_modinfo *modinfo) 20328c2ecf20Sopenharmony_ci{ 20338c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 20348c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 20358c2ecf20Sopenharmony_ci int ret; 20368c2ecf20Sopenharmony_ci u8 data[4]; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci /* Read first 2 bytes to get Module & REV ID */ 20398c2ecf20Sopenharmony_ci ret = mlx4_get_module_info(mdev->dev, priv->port, 20408c2ecf20Sopenharmony_ci 0/*offset*/, 2/*size*/, data); 20418c2ecf20Sopenharmony_ci if (ret < 2) 20428c2ecf20Sopenharmony_ci return -EIO; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci switch (data[0] /* identifier */) { 20458c2ecf20Sopenharmony_ci case MLX4_MODULE_ID_QSFP: 20468c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8436; 20478c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 20488c2ecf20Sopenharmony_ci break; 20498c2ecf20Sopenharmony_ci case MLX4_MODULE_ID_QSFP_PLUS: 20508c2ecf20Sopenharmony_ci if (data[1] >= 0x3) { /* revision id */ 20518c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8636; 20528c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 20538c2ecf20Sopenharmony_ci } else { 20548c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8436; 20558c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 20568c2ecf20Sopenharmony_ci } 20578c2ecf20Sopenharmony_ci break; 20588c2ecf20Sopenharmony_ci case MLX4_MODULE_ID_QSFP28: 20598c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8636; 20608c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 20618c2ecf20Sopenharmony_ci break; 20628c2ecf20Sopenharmony_ci case MLX4_MODULE_ID_SFP: 20638c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 20648c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 20658c2ecf20Sopenharmony_ci break; 20668c2ecf20Sopenharmony_ci default: 20678c2ecf20Sopenharmony_ci return -EINVAL; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci return 0; 20718c2ecf20Sopenharmony_ci} 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_cistatic int mlx4_en_get_module_eeprom(struct net_device *dev, 20748c2ecf20Sopenharmony_ci struct ethtool_eeprom *ee, 20758c2ecf20Sopenharmony_ci u8 *data) 20768c2ecf20Sopenharmony_ci{ 20778c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 20788c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 20798c2ecf20Sopenharmony_ci int offset = ee->offset; 20808c2ecf20Sopenharmony_ci int i = 0, ret; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci if (ee->len == 0) 20838c2ecf20Sopenharmony_ci return -EINVAL; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci memset(data, 0, ee->len); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci while (i < ee->len) { 20888c2ecf20Sopenharmony_ci en_dbg(DRV, priv, 20898c2ecf20Sopenharmony_ci "mlx4_get_module_info i(%d) offset(%d) len(%d)\n", 20908c2ecf20Sopenharmony_ci i, offset, ee->len - i); 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci ret = mlx4_get_module_info(mdev->dev, priv->port, 20938c2ecf20Sopenharmony_ci offset, ee->len - i, data + i); 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci if (!ret) /* Done reading */ 20968c2ecf20Sopenharmony_ci return 0; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci if (ret < 0) { 20998c2ecf20Sopenharmony_ci en_err(priv, 21008c2ecf20Sopenharmony_ci "mlx4_get_module_info i(%d) offset(%d) bytes_to_read(%d) - FAILED (0x%x)\n", 21018c2ecf20Sopenharmony_ci i, offset, ee->len - i, ret); 21028c2ecf20Sopenharmony_ci return ret; 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci i += ret; 21068c2ecf20Sopenharmony_ci offset += ret; 21078c2ecf20Sopenharmony_ci } 21088c2ecf20Sopenharmony_ci return 0; 21098c2ecf20Sopenharmony_ci} 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_cistatic int mlx4_en_set_phys_id(struct net_device *dev, 21128c2ecf20Sopenharmony_ci enum ethtool_phys_id_state state) 21138c2ecf20Sopenharmony_ci{ 21148c2ecf20Sopenharmony_ci int err; 21158c2ecf20Sopenharmony_ci u16 beacon_duration; 21168c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 21178c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_BEACON)) 21208c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci switch (state) { 21238c2ecf20Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 21248c2ecf20Sopenharmony_ci beacon_duration = PORT_BEACON_MAX_LIMIT; 21258c2ecf20Sopenharmony_ci break; 21268c2ecf20Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 21278c2ecf20Sopenharmony_ci beacon_duration = 0; 21288c2ecf20Sopenharmony_ci break; 21298c2ecf20Sopenharmony_ci default: 21308c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 21318c2ecf20Sopenharmony_ci } 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci err = mlx4_SET_PORT_BEACON(mdev->dev, priv->port, beacon_duration); 21348c2ecf20Sopenharmony_ci return err; 21358c2ecf20Sopenharmony_ci} 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ciconst struct ethtool_ops mlx4_en_ethtool_ops = { 21388c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 21398c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES | 21408c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ | 21418c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_PKT_RATE_RX_USECS, 21428c2ecf20Sopenharmony_ci .get_drvinfo = mlx4_en_get_drvinfo, 21438c2ecf20Sopenharmony_ci .get_link_ksettings = mlx4_en_get_link_ksettings, 21448c2ecf20Sopenharmony_ci .set_link_ksettings = mlx4_en_set_link_ksettings, 21458c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 21468c2ecf20Sopenharmony_ci .get_strings = mlx4_en_get_strings, 21478c2ecf20Sopenharmony_ci .get_sset_count = mlx4_en_get_sset_count, 21488c2ecf20Sopenharmony_ci .get_ethtool_stats = mlx4_en_get_ethtool_stats, 21498c2ecf20Sopenharmony_ci .self_test = mlx4_en_self_test, 21508c2ecf20Sopenharmony_ci .set_phys_id = mlx4_en_set_phys_id, 21518c2ecf20Sopenharmony_ci .get_wol = mlx4_en_get_wol, 21528c2ecf20Sopenharmony_ci .set_wol = mlx4_en_set_wol, 21538c2ecf20Sopenharmony_ci .get_msglevel = mlx4_en_get_msglevel, 21548c2ecf20Sopenharmony_ci .set_msglevel = mlx4_en_set_msglevel, 21558c2ecf20Sopenharmony_ci .get_coalesce = mlx4_en_get_coalesce, 21568c2ecf20Sopenharmony_ci .set_coalesce = mlx4_en_set_coalesce, 21578c2ecf20Sopenharmony_ci .get_pause_stats = mlx4_en_get_pause_stats, 21588c2ecf20Sopenharmony_ci .get_pauseparam = mlx4_en_get_pauseparam, 21598c2ecf20Sopenharmony_ci .set_pauseparam = mlx4_en_set_pauseparam, 21608c2ecf20Sopenharmony_ci .get_ringparam = mlx4_en_get_ringparam, 21618c2ecf20Sopenharmony_ci .set_ringparam = mlx4_en_set_ringparam, 21628c2ecf20Sopenharmony_ci .get_rxnfc = mlx4_en_get_rxnfc, 21638c2ecf20Sopenharmony_ci .set_rxnfc = mlx4_en_set_rxnfc, 21648c2ecf20Sopenharmony_ci .get_rxfh_indir_size = mlx4_en_get_rxfh_indir_size, 21658c2ecf20Sopenharmony_ci .get_rxfh_key_size = mlx4_en_get_rxfh_key_size, 21668c2ecf20Sopenharmony_ci .get_rxfh = mlx4_en_get_rxfh, 21678c2ecf20Sopenharmony_ci .set_rxfh = mlx4_en_set_rxfh, 21688c2ecf20Sopenharmony_ci .get_channels = mlx4_en_get_channels, 21698c2ecf20Sopenharmony_ci .set_channels = mlx4_en_set_channels, 21708c2ecf20Sopenharmony_ci .get_ts_info = mlx4_en_get_ts_info, 21718c2ecf20Sopenharmony_ci .set_priv_flags = mlx4_en_set_priv_flags, 21728c2ecf20Sopenharmony_ci .get_priv_flags = mlx4_en_get_priv_flags, 21738c2ecf20Sopenharmony_ci .get_tunable = mlx4_en_get_tunable, 21748c2ecf20Sopenharmony_ci .set_tunable = mlx4_en_set_tunable, 21758c2ecf20Sopenharmony_ci .get_module_info = mlx4_en_get_module_info, 21768c2ecf20Sopenharmony_ci .get_module_eeprom = mlx4_en_get_module_eeprom 21778c2ecf20Sopenharmony_ci}; 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci 2183