1133fac0eSSudarsana Kalluru /* QLogic qede NIC Driver 2133fac0eSSudarsana Kalluru * Copyright (c) 2015 QLogic Corporation 3133fac0eSSudarsana Kalluru * 4133fac0eSSudarsana Kalluru * This software is available under the terms of the GNU General Public License 5133fac0eSSudarsana Kalluru * (GPL) Version 2, available from the file COPYING in the main directory of 6133fac0eSSudarsana Kalluru * this source tree. 7133fac0eSSudarsana Kalluru */ 8133fac0eSSudarsana Kalluru 9133fac0eSSudarsana Kalluru #include <linux/version.h> 10133fac0eSSudarsana Kalluru #include <linux/types.h> 11133fac0eSSudarsana Kalluru #include <linux/netdevice.h> 1216f46bf0SSudarsana Reddy Kalluru #include <linux/etherdevice.h> 13133fac0eSSudarsana Kalluru #include <linux/ethtool.h> 14133fac0eSSudarsana Kalluru #include <linux/string.h> 15133fac0eSSudarsana Kalluru #include <linux/pci.h> 16133fac0eSSudarsana Kalluru #include <linux/capability.h> 17133fac0eSSudarsana Kalluru #include "qede.h" 18133fac0eSSudarsana Kalluru 19133fac0eSSudarsana Kalluru #define QEDE_STAT_OFFSET(stat_name) (offsetof(struct qede_stats, stat_name)) 20133fac0eSSudarsana Kalluru #define QEDE_STAT_STRING(stat_name) (#stat_name) 21133fac0eSSudarsana Kalluru #define _QEDE_STAT(stat_name, pf_only) \ 22133fac0eSSudarsana Kalluru {QEDE_STAT_OFFSET(stat_name), QEDE_STAT_STRING(stat_name), pf_only} 23133fac0eSSudarsana Kalluru #define QEDE_PF_STAT(stat_name) _QEDE_STAT(stat_name, true) 24133fac0eSSudarsana Kalluru #define QEDE_STAT(stat_name) _QEDE_STAT(stat_name, false) 25133fac0eSSudarsana Kalluru 26133fac0eSSudarsana Kalluru #define QEDE_RQSTAT_OFFSET(stat_name) \ 27133fac0eSSudarsana Kalluru (offsetof(struct qede_rx_queue, stat_name)) 28133fac0eSSudarsana Kalluru #define QEDE_RQSTAT_STRING(stat_name) (#stat_name) 29133fac0eSSudarsana Kalluru #define QEDE_RQSTAT(stat_name) \ 30133fac0eSSudarsana Kalluru {QEDE_RQSTAT_OFFSET(stat_name), QEDE_RQSTAT_STRING(stat_name)} 3116f46bf0SSudarsana Reddy Kalluru 3216f46bf0SSudarsana Reddy Kalluru #define QEDE_SELFTEST_POLL_COUNT 100 3316f46bf0SSudarsana Reddy Kalluru 34133fac0eSSudarsana Kalluru static const struct { 35133fac0eSSudarsana Kalluru u64 offset; 36133fac0eSSudarsana Kalluru char string[ETH_GSTRING_LEN]; 37133fac0eSSudarsana Kalluru } qede_rqstats_arr[] = { 38133fac0eSSudarsana Kalluru QEDE_RQSTAT(rx_hw_errors), 39133fac0eSSudarsana Kalluru QEDE_RQSTAT(rx_alloc_errors), 40133fac0eSSudarsana Kalluru }; 41133fac0eSSudarsana Kalluru 42133fac0eSSudarsana Kalluru #define QEDE_NUM_RQSTATS ARRAY_SIZE(qede_rqstats_arr) 43133fac0eSSudarsana Kalluru #define QEDE_RQSTATS_DATA(dev, sindex, rqindex) \ 44133fac0eSSudarsana Kalluru (*((u64 *)(((char *)(dev->fp_array[(rqindex)].rxq)) +\ 45133fac0eSSudarsana Kalluru qede_rqstats_arr[(sindex)].offset))) 46133fac0eSSudarsana Kalluru static const struct { 47133fac0eSSudarsana Kalluru u64 offset; 48133fac0eSSudarsana Kalluru char string[ETH_GSTRING_LEN]; 49133fac0eSSudarsana Kalluru bool pf_only; 50133fac0eSSudarsana Kalluru } qede_stats_arr[] = { 51133fac0eSSudarsana Kalluru QEDE_STAT(rx_ucast_bytes), 52133fac0eSSudarsana Kalluru QEDE_STAT(rx_mcast_bytes), 53133fac0eSSudarsana Kalluru QEDE_STAT(rx_bcast_bytes), 54133fac0eSSudarsana Kalluru QEDE_STAT(rx_ucast_pkts), 55133fac0eSSudarsana Kalluru QEDE_STAT(rx_mcast_pkts), 56133fac0eSSudarsana Kalluru QEDE_STAT(rx_bcast_pkts), 57133fac0eSSudarsana Kalluru 58133fac0eSSudarsana Kalluru QEDE_STAT(tx_ucast_bytes), 59133fac0eSSudarsana Kalluru QEDE_STAT(tx_mcast_bytes), 60133fac0eSSudarsana Kalluru QEDE_STAT(tx_bcast_bytes), 61133fac0eSSudarsana Kalluru QEDE_STAT(tx_ucast_pkts), 62133fac0eSSudarsana Kalluru QEDE_STAT(tx_mcast_pkts), 63133fac0eSSudarsana Kalluru QEDE_STAT(tx_bcast_pkts), 64133fac0eSSudarsana Kalluru 65133fac0eSSudarsana Kalluru QEDE_PF_STAT(rx_64_byte_packets), 66d4967cf3SYuval Mintz QEDE_PF_STAT(rx_65_to_127_byte_packets), 67d4967cf3SYuval Mintz QEDE_PF_STAT(rx_128_to_255_byte_packets), 68d4967cf3SYuval Mintz QEDE_PF_STAT(rx_256_to_511_byte_packets), 69d4967cf3SYuval Mintz QEDE_PF_STAT(rx_512_to_1023_byte_packets), 70d4967cf3SYuval Mintz QEDE_PF_STAT(rx_1024_to_1518_byte_packets), 71d4967cf3SYuval Mintz QEDE_PF_STAT(rx_1519_to_1522_byte_packets), 72d4967cf3SYuval Mintz QEDE_PF_STAT(rx_1519_to_2047_byte_packets), 73d4967cf3SYuval Mintz QEDE_PF_STAT(rx_2048_to_4095_byte_packets), 74d4967cf3SYuval Mintz QEDE_PF_STAT(rx_4096_to_9216_byte_packets), 75d4967cf3SYuval Mintz QEDE_PF_STAT(rx_9217_to_16383_byte_packets), 76133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_64_byte_packets), 77133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_65_to_127_byte_packets), 78133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_128_to_255_byte_packets), 79133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_256_to_511_byte_packets), 80133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_512_to_1023_byte_packets), 81133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_1024_to_1518_byte_packets), 82133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_1519_to_2047_byte_packets), 83133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_2048_to_4095_byte_packets), 84133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_4096_to_9216_byte_packets), 85133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_9217_to_16383_byte_packets), 86133fac0eSSudarsana Kalluru 87133fac0eSSudarsana Kalluru QEDE_PF_STAT(rx_mac_crtl_frames), 88133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_mac_ctrl_frames), 89133fac0eSSudarsana Kalluru QEDE_PF_STAT(rx_pause_frames), 90133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_pause_frames), 91133fac0eSSudarsana Kalluru QEDE_PF_STAT(rx_pfc_frames), 92133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_pfc_frames), 93133fac0eSSudarsana Kalluru 94133fac0eSSudarsana Kalluru QEDE_PF_STAT(rx_crc_errors), 95133fac0eSSudarsana Kalluru QEDE_PF_STAT(rx_align_errors), 96133fac0eSSudarsana Kalluru QEDE_PF_STAT(rx_carrier_errors), 97133fac0eSSudarsana Kalluru QEDE_PF_STAT(rx_oversize_packets), 98133fac0eSSudarsana Kalluru QEDE_PF_STAT(rx_jabbers), 99133fac0eSSudarsana Kalluru QEDE_PF_STAT(rx_undersize_packets), 100133fac0eSSudarsana Kalluru QEDE_PF_STAT(rx_fragments), 101133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_lpi_entry_count), 102133fac0eSSudarsana Kalluru QEDE_PF_STAT(tx_total_collisions), 103133fac0eSSudarsana Kalluru QEDE_PF_STAT(brb_truncates), 104133fac0eSSudarsana Kalluru QEDE_PF_STAT(brb_discards), 105133fac0eSSudarsana Kalluru QEDE_STAT(no_buff_discards), 106133fac0eSSudarsana Kalluru QEDE_PF_STAT(mftag_filter_discards), 107133fac0eSSudarsana Kalluru QEDE_PF_STAT(mac_filter_discards), 108133fac0eSSudarsana Kalluru QEDE_STAT(tx_err_drop_pkts), 109133fac0eSSudarsana Kalluru 110133fac0eSSudarsana Kalluru QEDE_STAT(coalesced_pkts), 111133fac0eSSudarsana Kalluru QEDE_STAT(coalesced_events), 112133fac0eSSudarsana Kalluru QEDE_STAT(coalesced_aborts_num), 113133fac0eSSudarsana Kalluru QEDE_STAT(non_coalesced_pkts), 114133fac0eSSudarsana Kalluru QEDE_STAT(coalesced_bytes), 115133fac0eSSudarsana Kalluru }; 116133fac0eSSudarsana Kalluru 117133fac0eSSudarsana Kalluru #define QEDE_STATS_DATA(dev, index) \ 118133fac0eSSudarsana Kalluru (*((u64 *)(((char *)(dev)) + offsetof(struct qede_dev, stats) \ 119133fac0eSSudarsana Kalluru + qede_stats_arr[(index)].offset))) 120133fac0eSSudarsana Kalluru 121133fac0eSSudarsana Kalluru #define QEDE_NUM_STATS ARRAY_SIZE(qede_stats_arr) 122133fac0eSSudarsana Kalluru 123f3e72109SYuval Mintz enum { 124f3e72109SYuval Mintz QEDE_PRI_FLAG_CMT, 125f3e72109SYuval Mintz QEDE_PRI_FLAG_LEN, 126f3e72109SYuval Mintz }; 127f3e72109SYuval Mintz 128f3e72109SYuval Mintz static const char qede_private_arr[QEDE_PRI_FLAG_LEN][ETH_GSTRING_LEN] = { 129f3e72109SYuval Mintz "Coupled-Function", 130f3e72109SYuval Mintz }; 131f3e72109SYuval Mintz 1323044a02eSSudarsana Reddy Kalluru enum qede_ethtool_tests { 13316f46bf0SSudarsana Reddy Kalluru QEDE_ETHTOOL_INT_LOOPBACK, 1343044a02eSSudarsana Reddy Kalluru QEDE_ETHTOOL_INTERRUPT_TEST, 1353044a02eSSudarsana Reddy Kalluru QEDE_ETHTOOL_MEMORY_TEST, 1363044a02eSSudarsana Reddy Kalluru QEDE_ETHTOOL_REGISTER_TEST, 1373044a02eSSudarsana Reddy Kalluru QEDE_ETHTOOL_CLOCK_TEST, 1383044a02eSSudarsana Reddy Kalluru QEDE_ETHTOOL_TEST_MAX 1393044a02eSSudarsana Reddy Kalluru }; 1403044a02eSSudarsana Reddy Kalluru 1413044a02eSSudarsana Reddy Kalluru static const char qede_tests_str_arr[QEDE_ETHTOOL_TEST_MAX][ETH_GSTRING_LEN] = { 14216f46bf0SSudarsana Reddy Kalluru "Internal loopback (offline)", 1433044a02eSSudarsana Reddy Kalluru "Interrupt (online)\t", 1443044a02eSSudarsana Reddy Kalluru "Memory (online)\t\t", 1453044a02eSSudarsana Reddy Kalluru "Register (online)\t", 1463044a02eSSudarsana Reddy Kalluru "Clock (online)\t\t", 1473044a02eSSudarsana Reddy Kalluru }; 1483044a02eSSudarsana Reddy Kalluru 149133fac0eSSudarsana Kalluru static void qede_get_strings_stats(struct qede_dev *edev, u8 *buf) 150133fac0eSSudarsana Kalluru { 151133fac0eSSudarsana Kalluru int i, j, k; 152133fac0eSSudarsana Kalluru 153133fac0eSSudarsana Kalluru for (i = 0, j = 0; i < QEDE_NUM_STATS; i++) { 154fefb0202SYuval Mintz if (IS_VF(edev) && qede_stats_arr[i].pf_only) 155fefb0202SYuval Mintz continue; 156133fac0eSSudarsana Kalluru strcpy(buf + j * ETH_GSTRING_LEN, 157133fac0eSSudarsana Kalluru qede_stats_arr[i].string); 158133fac0eSSudarsana Kalluru j++; 159133fac0eSSudarsana Kalluru } 160133fac0eSSudarsana Kalluru 161133fac0eSSudarsana Kalluru for (k = 0; k < QEDE_NUM_RQSTATS; k++, j++) 162133fac0eSSudarsana Kalluru strcpy(buf + j * ETH_GSTRING_LEN, 163133fac0eSSudarsana Kalluru qede_rqstats_arr[k].string); 164133fac0eSSudarsana Kalluru } 165133fac0eSSudarsana Kalluru 166133fac0eSSudarsana Kalluru static void qede_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 167133fac0eSSudarsana Kalluru { 168133fac0eSSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 169133fac0eSSudarsana Kalluru 170133fac0eSSudarsana Kalluru switch (stringset) { 171133fac0eSSudarsana Kalluru case ETH_SS_STATS: 172133fac0eSSudarsana Kalluru qede_get_strings_stats(edev, buf); 173133fac0eSSudarsana Kalluru break; 174f3e72109SYuval Mintz case ETH_SS_PRIV_FLAGS: 175f3e72109SYuval Mintz memcpy(buf, qede_private_arr, 176f3e72109SYuval Mintz ETH_GSTRING_LEN * QEDE_PRI_FLAG_LEN); 177f3e72109SYuval Mintz break; 1783044a02eSSudarsana Reddy Kalluru case ETH_SS_TEST: 1793044a02eSSudarsana Reddy Kalluru memcpy(buf, qede_tests_str_arr, 1803044a02eSSudarsana Reddy Kalluru ETH_GSTRING_LEN * QEDE_ETHTOOL_TEST_MAX); 1813044a02eSSudarsana Reddy Kalluru break; 182133fac0eSSudarsana Kalluru default: 183133fac0eSSudarsana Kalluru DP_VERBOSE(edev, QED_MSG_DEBUG, 184133fac0eSSudarsana Kalluru "Unsupported stringset 0x%08x\n", stringset); 185133fac0eSSudarsana Kalluru } 186133fac0eSSudarsana Kalluru } 187133fac0eSSudarsana Kalluru 188133fac0eSSudarsana Kalluru static void qede_get_ethtool_stats(struct net_device *dev, 189133fac0eSSudarsana Kalluru struct ethtool_stats *stats, u64 *buf) 190133fac0eSSudarsana Kalluru { 191133fac0eSSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 192133fac0eSSudarsana Kalluru int sidx, cnt = 0; 193133fac0eSSudarsana Kalluru int qid; 194133fac0eSSudarsana Kalluru 195133fac0eSSudarsana Kalluru qede_fill_by_demand_stats(edev); 196133fac0eSSudarsana Kalluru 197133fac0eSSudarsana Kalluru mutex_lock(&edev->qede_lock); 198133fac0eSSudarsana Kalluru 199fefb0202SYuval Mintz for (sidx = 0; sidx < QEDE_NUM_STATS; sidx++) { 200fefb0202SYuval Mintz if (IS_VF(edev) && qede_stats_arr[sidx].pf_only) 201fefb0202SYuval Mintz continue; 202133fac0eSSudarsana Kalluru buf[cnt++] = QEDE_STATS_DATA(edev, sidx); 203fefb0202SYuval Mintz } 204133fac0eSSudarsana Kalluru 205133fac0eSSudarsana Kalluru for (sidx = 0; sidx < QEDE_NUM_RQSTATS; sidx++) { 206133fac0eSSudarsana Kalluru buf[cnt] = 0; 207133fac0eSSudarsana Kalluru for (qid = 0; qid < edev->num_rss; qid++) 208133fac0eSSudarsana Kalluru buf[cnt] += QEDE_RQSTATS_DATA(edev, sidx, qid); 209133fac0eSSudarsana Kalluru cnt++; 210133fac0eSSudarsana Kalluru } 211133fac0eSSudarsana Kalluru 212133fac0eSSudarsana Kalluru mutex_unlock(&edev->qede_lock); 213133fac0eSSudarsana Kalluru } 214133fac0eSSudarsana Kalluru 215133fac0eSSudarsana Kalluru static int qede_get_sset_count(struct net_device *dev, int stringset) 216133fac0eSSudarsana Kalluru { 217133fac0eSSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 218133fac0eSSudarsana Kalluru int num_stats = QEDE_NUM_STATS; 219133fac0eSSudarsana Kalluru 220133fac0eSSudarsana Kalluru switch (stringset) { 221133fac0eSSudarsana Kalluru case ETH_SS_STATS: 222fefb0202SYuval Mintz if (IS_VF(edev)) { 223fefb0202SYuval Mintz int i; 224fefb0202SYuval Mintz 225fefb0202SYuval Mintz for (i = 0; i < QEDE_NUM_STATS; i++) 226fefb0202SYuval Mintz if (qede_stats_arr[i].pf_only) 227fefb0202SYuval Mintz num_stats--; 228fefb0202SYuval Mintz } 229133fac0eSSudarsana Kalluru return num_stats + QEDE_NUM_RQSTATS; 230f3e72109SYuval Mintz case ETH_SS_PRIV_FLAGS: 231f3e72109SYuval Mintz return QEDE_PRI_FLAG_LEN; 2323044a02eSSudarsana Reddy Kalluru case ETH_SS_TEST: 2336ecb0a0cSYuval Mintz if (!IS_VF(edev)) 2343044a02eSSudarsana Reddy Kalluru return QEDE_ETHTOOL_TEST_MAX; 2356ecb0a0cSYuval Mintz else 2366ecb0a0cSYuval Mintz return 0; 237133fac0eSSudarsana Kalluru default: 238133fac0eSSudarsana Kalluru DP_VERBOSE(edev, QED_MSG_DEBUG, 239133fac0eSSudarsana Kalluru "Unsupported stringset 0x%08x\n", stringset); 240133fac0eSSudarsana Kalluru return -EINVAL; 241133fac0eSSudarsana Kalluru } 242133fac0eSSudarsana Kalluru } 243133fac0eSSudarsana Kalluru 244f3e72109SYuval Mintz static u32 qede_get_priv_flags(struct net_device *dev) 245f3e72109SYuval Mintz { 246f3e72109SYuval Mintz struct qede_dev *edev = netdev_priv(dev); 247f3e72109SYuval Mintz 248f3e72109SYuval Mintz return (!!(edev->dev_info.common.num_hwfns > 1)) << QEDE_PRI_FLAG_CMT; 249f3e72109SYuval Mintz } 250f3e72109SYuval Mintz 251133fac0eSSudarsana Kalluru static int qede_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 252133fac0eSSudarsana Kalluru { 253133fac0eSSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 254133fac0eSSudarsana Kalluru struct qed_link_output current_link; 255133fac0eSSudarsana Kalluru 256133fac0eSSudarsana Kalluru memset(¤t_link, 0, sizeof(current_link)); 257133fac0eSSudarsana Kalluru edev->ops->common->get_link(edev->cdev, ¤t_link); 258133fac0eSSudarsana Kalluru 259133fac0eSSudarsana Kalluru cmd->supported = current_link.supported_caps; 260133fac0eSSudarsana Kalluru cmd->advertising = current_link.advertised_caps; 261133fac0eSSudarsana Kalluru if ((edev->state == QEDE_STATE_OPEN) && (current_link.link_up)) { 262133fac0eSSudarsana Kalluru ethtool_cmd_speed_set(cmd, current_link.speed); 263133fac0eSSudarsana Kalluru cmd->duplex = current_link.duplex; 264133fac0eSSudarsana Kalluru } else { 265133fac0eSSudarsana Kalluru cmd->duplex = DUPLEX_UNKNOWN; 266133fac0eSSudarsana Kalluru ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN); 267133fac0eSSudarsana Kalluru } 268133fac0eSSudarsana Kalluru cmd->port = current_link.port; 269133fac0eSSudarsana Kalluru cmd->autoneg = (current_link.autoneg) ? AUTONEG_ENABLE : 270133fac0eSSudarsana Kalluru AUTONEG_DISABLE; 271133fac0eSSudarsana Kalluru cmd->lp_advertising = current_link.lp_caps; 272133fac0eSSudarsana Kalluru 273133fac0eSSudarsana Kalluru return 0; 274133fac0eSSudarsana Kalluru } 275133fac0eSSudarsana Kalluru 276133fac0eSSudarsana Kalluru static int qede_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 277133fac0eSSudarsana Kalluru { 278133fac0eSSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 279133fac0eSSudarsana Kalluru struct qed_link_output current_link; 280133fac0eSSudarsana Kalluru struct qed_link_params params; 281133fac0eSSudarsana Kalluru u32 speed; 282133fac0eSSudarsana Kalluru 283fe7cd2bfSYuval Mintz if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { 284133fac0eSSudarsana Kalluru DP_INFO(edev, 285fe7cd2bfSYuval Mintz "Link settings are not allowed to be changed\n"); 286133fac0eSSudarsana Kalluru return -EOPNOTSUPP; 287133fac0eSSudarsana Kalluru } 288133fac0eSSudarsana Kalluru 289133fac0eSSudarsana Kalluru memset(¤t_link, 0, sizeof(current_link)); 290133fac0eSSudarsana Kalluru memset(¶ms, 0, sizeof(params)); 291133fac0eSSudarsana Kalluru edev->ops->common->get_link(edev->cdev, ¤t_link); 292133fac0eSSudarsana Kalluru 293133fac0eSSudarsana Kalluru speed = ethtool_cmd_speed(cmd); 294133fac0eSSudarsana Kalluru params.override_flags |= QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS; 295133fac0eSSudarsana Kalluru params.override_flags |= QED_LINK_OVERRIDE_SPEED_AUTONEG; 296133fac0eSSudarsana Kalluru if (cmd->autoneg == AUTONEG_ENABLE) { 297133fac0eSSudarsana Kalluru params.autoneg = true; 298133fac0eSSudarsana Kalluru params.forced_speed = 0; 299133fac0eSSudarsana Kalluru params.adv_speeds = cmd->advertising; 300133fac0eSSudarsana Kalluru } else { /* forced speed */ 301133fac0eSSudarsana Kalluru params.override_flags |= QED_LINK_OVERRIDE_SPEED_FORCED_SPEED; 302133fac0eSSudarsana Kalluru params.autoneg = false; 303133fac0eSSudarsana Kalluru params.forced_speed = speed; 304133fac0eSSudarsana Kalluru switch (speed) { 305133fac0eSSudarsana Kalluru case SPEED_10000: 306133fac0eSSudarsana Kalluru if (!(current_link.supported_caps & 307133fac0eSSudarsana Kalluru SUPPORTED_10000baseKR_Full)) { 308133fac0eSSudarsana Kalluru DP_INFO(edev, "10G speed not supported\n"); 309133fac0eSSudarsana Kalluru return -EINVAL; 310133fac0eSSudarsana Kalluru } 311133fac0eSSudarsana Kalluru params.adv_speeds = SUPPORTED_10000baseKR_Full; 312133fac0eSSudarsana Kalluru break; 313133fac0eSSudarsana Kalluru case SPEED_40000: 314133fac0eSSudarsana Kalluru if (!(current_link.supported_caps & 315133fac0eSSudarsana Kalluru SUPPORTED_40000baseLR4_Full)) { 316133fac0eSSudarsana Kalluru DP_INFO(edev, "40G speed not supported\n"); 317133fac0eSSudarsana Kalluru return -EINVAL; 318133fac0eSSudarsana Kalluru } 319133fac0eSSudarsana Kalluru params.adv_speeds = SUPPORTED_40000baseLR4_Full; 320133fac0eSSudarsana Kalluru break; 321133fac0eSSudarsana Kalluru default: 322133fac0eSSudarsana Kalluru DP_INFO(edev, "Unsupported speed %u\n", speed); 323133fac0eSSudarsana Kalluru return -EINVAL; 324133fac0eSSudarsana Kalluru } 325133fac0eSSudarsana Kalluru } 326133fac0eSSudarsana Kalluru 327133fac0eSSudarsana Kalluru params.link_up = true; 328133fac0eSSudarsana Kalluru edev->ops->common->set_link(edev->cdev, ¶ms); 329133fac0eSSudarsana Kalluru 330133fac0eSSudarsana Kalluru return 0; 331133fac0eSSudarsana Kalluru } 332133fac0eSSudarsana Kalluru 333133fac0eSSudarsana Kalluru static void qede_get_drvinfo(struct net_device *ndev, 334133fac0eSSudarsana Kalluru struct ethtool_drvinfo *info) 335133fac0eSSudarsana Kalluru { 336133fac0eSSudarsana Kalluru char mfw[ETHTOOL_FWVERS_LEN], storm[ETHTOOL_FWVERS_LEN]; 337133fac0eSSudarsana Kalluru struct qede_dev *edev = netdev_priv(ndev); 338133fac0eSSudarsana Kalluru 339133fac0eSSudarsana Kalluru strlcpy(info->driver, "qede", sizeof(info->driver)); 340133fac0eSSudarsana Kalluru strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version)); 341133fac0eSSudarsana Kalluru 342133fac0eSSudarsana Kalluru snprintf(storm, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d", 343133fac0eSSudarsana Kalluru edev->dev_info.common.fw_major, 344133fac0eSSudarsana Kalluru edev->dev_info.common.fw_minor, 345133fac0eSSudarsana Kalluru edev->dev_info.common.fw_rev, 346133fac0eSSudarsana Kalluru edev->dev_info.common.fw_eng); 347133fac0eSSudarsana Kalluru 348133fac0eSSudarsana Kalluru snprintf(mfw, ETHTOOL_FWVERS_LEN, "%d.%d.%d.%d", 349133fac0eSSudarsana Kalluru (edev->dev_info.common.mfw_rev >> 24) & 0xFF, 350133fac0eSSudarsana Kalluru (edev->dev_info.common.mfw_rev >> 16) & 0xFF, 351133fac0eSSudarsana Kalluru (edev->dev_info.common.mfw_rev >> 8) & 0xFF, 352133fac0eSSudarsana Kalluru edev->dev_info.common.mfw_rev & 0xFF); 353133fac0eSSudarsana Kalluru 354133fac0eSSudarsana Kalluru if ((strlen(storm) + strlen(mfw) + strlen("mfw storm ")) < 355133fac0eSSudarsana Kalluru sizeof(info->fw_version)) { 356133fac0eSSudarsana Kalluru snprintf(info->fw_version, sizeof(info->fw_version), 357133fac0eSSudarsana Kalluru "mfw %s storm %s", mfw, storm); 358133fac0eSSudarsana Kalluru } else { 359133fac0eSSudarsana Kalluru snprintf(info->fw_version, sizeof(info->fw_version), 360133fac0eSSudarsana Kalluru "%s %s", mfw, storm); 361133fac0eSSudarsana Kalluru } 362133fac0eSSudarsana Kalluru 363133fac0eSSudarsana Kalluru strlcpy(info->bus_info, pci_name(edev->pdev), sizeof(info->bus_info)); 364133fac0eSSudarsana Kalluru } 365133fac0eSSudarsana Kalluru 366133fac0eSSudarsana Kalluru static u32 qede_get_msglevel(struct net_device *ndev) 367133fac0eSSudarsana Kalluru { 368133fac0eSSudarsana Kalluru struct qede_dev *edev = netdev_priv(ndev); 369133fac0eSSudarsana Kalluru 370133fac0eSSudarsana Kalluru return ((u32)edev->dp_level << QED_LOG_LEVEL_SHIFT) | 371133fac0eSSudarsana Kalluru edev->dp_module; 372133fac0eSSudarsana Kalluru } 373133fac0eSSudarsana Kalluru 374133fac0eSSudarsana Kalluru static void qede_set_msglevel(struct net_device *ndev, u32 level) 375133fac0eSSudarsana Kalluru { 376133fac0eSSudarsana Kalluru struct qede_dev *edev = netdev_priv(ndev); 377133fac0eSSudarsana Kalluru u32 dp_module = 0; 378133fac0eSSudarsana Kalluru u8 dp_level = 0; 379133fac0eSSudarsana Kalluru 380133fac0eSSudarsana Kalluru qede_config_debug(level, &dp_module, &dp_level); 381133fac0eSSudarsana Kalluru 382133fac0eSSudarsana Kalluru edev->dp_level = dp_level; 383133fac0eSSudarsana Kalluru edev->dp_module = dp_module; 384133fac0eSSudarsana Kalluru edev->ops->common->update_msglvl(edev->cdev, 385133fac0eSSudarsana Kalluru dp_module, dp_level); 386133fac0eSSudarsana Kalluru } 387133fac0eSSudarsana Kalluru 38832a7a570SSudarsana Kalluru static int qede_nway_reset(struct net_device *dev) 38932a7a570SSudarsana Kalluru { 39032a7a570SSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 39132a7a570SSudarsana Kalluru struct qed_link_output current_link; 39232a7a570SSudarsana Kalluru struct qed_link_params link_params; 39332a7a570SSudarsana Kalluru 394fe7cd2bfSYuval Mintz if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { 395fe7cd2bfSYuval Mintz DP_INFO(edev, 396fe7cd2bfSYuval Mintz "Link settings are not allowed to be changed\n"); 397fe7cd2bfSYuval Mintz return -EOPNOTSUPP; 398fe7cd2bfSYuval Mintz } 399fe7cd2bfSYuval Mintz 40032a7a570SSudarsana Kalluru if (!netif_running(dev)) 40132a7a570SSudarsana Kalluru return 0; 40232a7a570SSudarsana Kalluru 40332a7a570SSudarsana Kalluru memset(¤t_link, 0, sizeof(current_link)); 40432a7a570SSudarsana Kalluru edev->ops->common->get_link(edev->cdev, ¤t_link); 40532a7a570SSudarsana Kalluru if (!current_link.link_up) 40632a7a570SSudarsana Kalluru return 0; 40732a7a570SSudarsana Kalluru 40832a7a570SSudarsana Kalluru /* Toggle the link */ 40932a7a570SSudarsana Kalluru memset(&link_params, 0, sizeof(link_params)); 41032a7a570SSudarsana Kalluru link_params.link_up = false; 41132a7a570SSudarsana Kalluru edev->ops->common->set_link(edev->cdev, &link_params); 41232a7a570SSudarsana Kalluru link_params.link_up = true; 41332a7a570SSudarsana Kalluru edev->ops->common->set_link(edev->cdev, &link_params); 41432a7a570SSudarsana Kalluru 41532a7a570SSudarsana Kalluru return 0; 41632a7a570SSudarsana Kalluru } 41732a7a570SSudarsana Kalluru 418133fac0eSSudarsana Kalluru static u32 qede_get_link(struct net_device *dev) 419133fac0eSSudarsana Kalluru { 420133fac0eSSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 421133fac0eSSudarsana Kalluru struct qed_link_output current_link; 422133fac0eSSudarsana Kalluru 423133fac0eSSudarsana Kalluru memset(¤t_link, 0, sizeof(current_link)); 424133fac0eSSudarsana Kalluru edev->ops->common->get_link(edev->cdev, ¤t_link); 425133fac0eSSudarsana Kalluru 426133fac0eSSudarsana Kalluru return current_link.link_up; 427133fac0eSSudarsana Kalluru } 428133fac0eSSudarsana Kalluru 42901ef7e05SSudarsana Kalluru static void qede_get_ringparam(struct net_device *dev, 43001ef7e05SSudarsana Kalluru struct ethtool_ringparam *ering) 43101ef7e05SSudarsana Kalluru { 43201ef7e05SSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 43301ef7e05SSudarsana Kalluru 43401ef7e05SSudarsana Kalluru ering->rx_max_pending = NUM_RX_BDS_MAX; 43501ef7e05SSudarsana Kalluru ering->rx_pending = edev->q_num_rx_buffers; 43601ef7e05SSudarsana Kalluru ering->tx_max_pending = NUM_TX_BDS_MAX; 43701ef7e05SSudarsana Kalluru ering->tx_pending = edev->q_num_tx_buffers; 43801ef7e05SSudarsana Kalluru } 43901ef7e05SSudarsana Kalluru 44001ef7e05SSudarsana Kalluru static int qede_set_ringparam(struct net_device *dev, 44101ef7e05SSudarsana Kalluru struct ethtool_ringparam *ering) 44201ef7e05SSudarsana Kalluru { 44301ef7e05SSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 44401ef7e05SSudarsana Kalluru 44501ef7e05SSudarsana Kalluru DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 44601ef7e05SSudarsana Kalluru "Set ring params command parameters: rx_pending = %d, tx_pending = %d\n", 44701ef7e05SSudarsana Kalluru ering->rx_pending, ering->tx_pending); 44801ef7e05SSudarsana Kalluru 44901ef7e05SSudarsana Kalluru /* Validate legality of configuration */ 45001ef7e05SSudarsana Kalluru if (ering->rx_pending > NUM_RX_BDS_MAX || 45101ef7e05SSudarsana Kalluru ering->rx_pending < NUM_RX_BDS_MIN || 45201ef7e05SSudarsana Kalluru ering->tx_pending > NUM_TX_BDS_MAX || 45301ef7e05SSudarsana Kalluru ering->tx_pending < NUM_TX_BDS_MIN) { 45401ef7e05SSudarsana Kalluru DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 45501ef7e05SSudarsana Kalluru "Can only support Rx Buffer size [0%08x,...,0x%08x] and Tx Buffer size [0x%08x,...,0x%08x]\n", 45601ef7e05SSudarsana Kalluru NUM_RX_BDS_MIN, NUM_RX_BDS_MAX, 45701ef7e05SSudarsana Kalluru NUM_TX_BDS_MIN, NUM_TX_BDS_MAX); 45801ef7e05SSudarsana Kalluru return -EINVAL; 45901ef7e05SSudarsana Kalluru } 46001ef7e05SSudarsana Kalluru 46101ef7e05SSudarsana Kalluru /* Change ring size and re-load */ 46201ef7e05SSudarsana Kalluru edev->q_num_rx_buffers = ering->rx_pending; 46301ef7e05SSudarsana Kalluru edev->q_num_tx_buffers = ering->tx_pending; 46401ef7e05SSudarsana Kalluru 46501ef7e05SSudarsana Kalluru if (netif_running(edev->ndev)) 46601ef7e05SSudarsana Kalluru qede_reload(edev, NULL, NULL); 46701ef7e05SSudarsana Kalluru 46801ef7e05SSudarsana Kalluru return 0; 46901ef7e05SSudarsana Kalluru } 47001ef7e05SSudarsana Kalluru 4710f7db144SSudarsana Kalluru static void qede_get_pauseparam(struct net_device *dev, 4720f7db144SSudarsana Kalluru struct ethtool_pauseparam *epause) 4730f7db144SSudarsana Kalluru { 4740f7db144SSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 4750f7db144SSudarsana Kalluru struct qed_link_output current_link; 4760f7db144SSudarsana Kalluru 4770f7db144SSudarsana Kalluru memset(¤t_link, 0, sizeof(current_link)); 4780f7db144SSudarsana Kalluru edev->ops->common->get_link(edev->cdev, ¤t_link); 4790f7db144SSudarsana Kalluru 4800f7db144SSudarsana Kalluru if (current_link.pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE) 4810f7db144SSudarsana Kalluru epause->autoneg = true; 4820f7db144SSudarsana Kalluru if (current_link.pause_config & QED_LINK_PAUSE_RX_ENABLE) 4830f7db144SSudarsana Kalluru epause->rx_pause = true; 4840f7db144SSudarsana Kalluru if (current_link.pause_config & QED_LINK_PAUSE_TX_ENABLE) 4850f7db144SSudarsana Kalluru epause->tx_pause = true; 4860f7db144SSudarsana Kalluru 4870f7db144SSudarsana Kalluru DP_VERBOSE(edev, QED_MSG_DEBUG, 4880f7db144SSudarsana Kalluru "ethtool_pauseparam: cmd %d autoneg %d rx_pause %d tx_pause %d\n", 4890f7db144SSudarsana Kalluru epause->cmd, epause->autoneg, epause->rx_pause, 4900f7db144SSudarsana Kalluru epause->tx_pause); 4910f7db144SSudarsana Kalluru } 4920f7db144SSudarsana Kalluru 4930f7db144SSudarsana Kalluru static int qede_set_pauseparam(struct net_device *dev, 4940f7db144SSudarsana Kalluru struct ethtool_pauseparam *epause) 4950f7db144SSudarsana Kalluru { 4960f7db144SSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 4970f7db144SSudarsana Kalluru struct qed_link_params params; 4980f7db144SSudarsana Kalluru struct qed_link_output current_link; 4990f7db144SSudarsana Kalluru 500fe7cd2bfSYuval Mintz if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { 5010f7db144SSudarsana Kalluru DP_INFO(edev, 502fe7cd2bfSYuval Mintz "Pause settings are not allowed to be changed\n"); 5030f7db144SSudarsana Kalluru return -EOPNOTSUPP; 5040f7db144SSudarsana Kalluru } 5050f7db144SSudarsana Kalluru 5060f7db144SSudarsana Kalluru memset(¤t_link, 0, sizeof(current_link)); 5070f7db144SSudarsana Kalluru edev->ops->common->get_link(edev->cdev, ¤t_link); 5080f7db144SSudarsana Kalluru 5090f7db144SSudarsana Kalluru memset(¶ms, 0, sizeof(params)); 5100f7db144SSudarsana Kalluru params.override_flags |= QED_LINK_OVERRIDE_PAUSE_CONFIG; 5110f7db144SSudarsana Kalluru if (epause->autoneg) { 5120f7db144SSudarsana Kalluru if (!(current_link.supported_caps & SUPPORTED_Autoneg)) { 5130f7db144SSudarsana Kalluru DP_INFO(edev, "autoneg not supported\n"); 5140f7db144SSudarsana Kalluru return -EINVAL; 5150f7db144SSudarsana Kalluru } 5160f7db144SSudarsana Kalluru params.pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE; 5170f7db144SSudarsana Kalluru } 5180f7db144SSudarsana Kalluru if (epause->rx_pause) 5190f7db144SSudarsana Kalluru params.pause_config |= QED_LINK_PAUSE_RX_ENABLE; 5200f7db144SSudarsana Kalluru if (epause->tx_pause) 5210f7db144SSudarsana Kalluru params.pause_config |= QED_LINK_PAUSE_TX_ENABLE; 5220f7db144SSudarsana Kalluru 5230f7db144SSudarsana Kalluru params.link_up = true; 5240f7db144SSudarsana Kalluru edev->ops->common->set_link(edev->cdev, ¶ms); 5250f7db144SSudarsana Kalluru 5260f7db144SSudarsana Kalluru return 0; 5270f7db144SSudarsana Kalluru } 5280f7db144SSudarsana Kalluru 529133fac0eSSudarsana Kalluru static void qede_update_mtu(struct qede_dev *edev, union qede_reload_args *args) 530133fac0eSSudarsana Kalluru { 531133fac0eSSudarsana Kalluru edev->ndev->mtu = args->mtu; 532133fac0eSSudarsana Kalluru } 533133fac0eSSudarsana Kalluru 534133fac0eSSudarsana Kalluru /* Netdevice NDOs */ 535133fac0eSSudarsana Kalluru #define ETH_MAX_JUMBO_PACKET_SIZE 9600 536133fac0eSSudarsana Kalluru #define ETH_MIN_PACKET_SIZE 60 537133fac0eSSudarsana Kalluru int qede_change_mtu(struct net_device *ndev, int new_mtu) 538133fac0eSSudarsana Kalluru { 539133fac0eSSudarsana Kalluru struct qede_dev *edev = netdev_priv(ndev); 540133fac0eSSudarsana Kalluru union qede_reload_args args; 541133fac0eSSudarsana Kalluru 542133fac0eSSudarsana Kalluru if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) || 543133fac0eSSudarsana Kalluru ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE)) { 544133fac0eSSudarsana Kalluru DP_ERR(edev, "Can't support requested MTU size\n"); 545133fac0eSSudarsana Kalluru return -EINVAL; 546133fac0eSSudarsana Kalluru } 547133fac0eSSudarsana Kalluru 548133fac0eSSudarsana Kalluru DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 549133fac0eSSudarsana Kalluru "Configuring MTU size of %d\n", new_mtu); 550133fac0eSSudarsana Kalluru 551133fac0eSSudarsana Kalluru /* Set the mtu field and re-start the interface if needed*/ 552133fac0eSSudarsana Kalluru args.mtu = new_mtu; 553133fac0eSSudarsana Kalluru 554133fac0eSSudarsana Kalluru if (netif_running(edev->ndev)) 555133fac0eSSudarsana Kalluru qede_reload(edev, &qede_update_mtu, &args); 556133fac0eSSudarsana Kalluru 557133fac0eSSudarsana Kalluru qede_update_mtu(edev, &args); 558133fac0eSSudarsana Kalluru 559133fac0eSSudarsana Kalluru return 0; 560133fac0eSSudarsana Kalluru } 561133fac0eSSudarsana Kalluru 5628edf049dSSudarsana Kalluru static void qede_get_channels(struct net_device *dev, 5638edf049dSSudarsana Kalluru struct ethtool_channels *channels) 5648edf049dSSudarsana Kalluru { 5658edf049dSSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 5668edf049dSSudarsana Kalluru 5678edf049dSSudarsana Kalluru channels->max_combined = QEDE_MAX_RSS_CNT(edev); 5688edf049dSSudarsana Kalluru channels->combined_count = QEDE_RSS_CNT(edev); 5698edf049dSSudarsana Kalluru } 5708edf049dSSudarsana Kalluru 5718edf049dSSudarsana Kalluru static int qede_set_channels(struct net_device *dev, 5728edf049dSSudarsana Kalluru struct ethtool_channels *channels) 5738edf049dSSudarsana Kalluru { 5748edf049dSSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 5758edf049dSSudarsana Kalluru 5768edf049dSSudarsana Kalluru DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 5778edf049dSSudarsana Kalluru "set-channels command parameters: rx = %d, tx = %d, other = %d, combined = %d\n", 5788edf049dSSudarsana Kalluru channels->rx_count, channels->tx_count, 5798edf049dSSudarsana Kalluru channels->other_count, channels->combined_count); 5808edf049dSSudarsana Kalluru 5818edf049dSSudarsana Kalluru /* We don't support separate rx / tx, nor `other' channels. */ 5828edf049dSSudarsana Kalluru if (channels->rx_count || channels->tx_count || 5838edf049dSSudarsana Kalluru channels->other_count || (channels->combined_count == 0) || 5848edf049dSSudarsana Kalluru (channels->combined_count > QEDE_MAX_RSS_CNT(edev))) { 5858edf049dSSudarsana Kalluru DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 5868edf049dSSudarsana Kalluru "command parameters not supported\n"); 5878edf049dSSudarsana Kalluru return -EINVAL; 5888edf049dSSudarsana Kalluru } 5898edf049dSSudarsana Kalluru 5908edf049dSSudarsana Kalluru /* Check if there was a change in the active parameters */ 5918edf049dSSudarsana Kalluru if (channels->combined_count == QEDE_RSS_CNT(edev)) { 5928edf049dSSudarsana Kalluru DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 5938edf049dSSudarsana Kalluru "No change in active parameters\n"); 5948edf049dSSudarsana Kalluru return 0; 5958edf049dSSudarsana Kalluru } 5968edf049dSSudarsana Kalluru 5978edf049dSSudarsana Kalluru /* We need the number of queues to be divisible between the hwfns */ 5988edf049dSSudarsana Kalluru if (channels->combined_count % edev->dev_info.common.num_hwfns) { 5998edf049dSSudarsana Kalluru DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN), 6008edf049dSSudarsana Kalluru "Number of channels must be divisable by %04x\n", 6018edf049dSSudarsana Kalluru edev->dev_info.common.num_hwfns); 6028edf049dSSudarsana Kalluru return -EINVAL; 6038edf049dSSudarsana Kalluru } 6048edf049dSSudarsana Kalluru 6058edf049dSSudarsana Kalluru /* Set number of queues and reload if necessary */ 6068edf049dSSudarsana Kalluru edev->req_rss = channels->combined_count; 6078edf049dSSudarsana Kalluru if (netif_running(dev)) 6088edf049dSSudarsana Kalluru qede_reload(edev, NULL, NULL); 6098edf049dSSudarsana Kalluru 6108edf049dSSudarsana Kalluru return 0; 6118edf049dSSudarsana Kalluru } 6128edf049dSSudarsana Kalluru 6133d971cbdSSudarsana Kalluru static int qede_set_phys_id(struct net_device *dev, 6143d971cbdSSudarsana Kalluru enum ethtool_phys_id_state state) 6153d971cbdSSudarsana Kalluru { 6163d971cbdSSudarsana Kalluru struct qede_dev *edev = netdev_priv(dev); 6173d971cbdSSudarsana Kalluru u8 led_state = 0; 6183d971cbdSSudarsana Kalluru 6193d971cbdSSudarsana Kalluru switch (state) { 6203d971cbdSSudarsana Kalluru case ETHTOOL_ID_ACTIVE: 6213d971cbdSSudarsana Kalluru return 1; /* cycle on/off once per second */ 6223d971cbdSSudarsana Kalluru 6233d971cbdSSudarsana Kalluru case ETHTOOL_ID_ON: 6243d971cbdSSudarsana Kalluru led_state = QED_LED_MODE_ON; 6253d971cbdSSudarsana Kalluru break; 6263d971cbdSSudarsana Kalluru 6273d971cbdSSudarsana Kalluru case ETHTOOL_ID_OFF: 6283d971cbdSSudarsana Kalluru led_state = QED_LED_MODE_OFF; 6293d971cbdSSudarsana Kalluru break; 6303d971cbdSSudarsana Kalluru 6313d971cbdSSudarsana Kalluru case ETHTOOL_ID_INACTIVE: 6323d971cbdSSudarsana Kalluru led_state = QED_LED_MODE_RESTORE; 6333d971cbdSSudarsana Kalluru break; 6343d971cbdSSudarsana Kalluru } 6353d971cbdSSudarsana Kalluru 6363d971cbdSSudarsana Kalluru edev->ops->common->set_led(edev->cdev, led_state); 6373d971cbdSSudarsana Kalluru 6383d971cbdSSudarsana Kalluru return 0; 6393d971cbdSSudarsana Kalluru } 6403d971cbdSSudarsana Kalluru 641961acdeaSSudarsana Reddy Kalluru static int qede_get_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info) 642961acdeaSSudarsana Reddy Kalluru { 643961acdeaSSudarsana Reddy Kalluru info->data = RXH_IP_SRC | RXH_IP_DST; 644961acdeaSSudarsana Reddy Kalluru 645961acdeaSSudarsana Reddy Kalluru switch (info->flow_type) { 646961acdeaSSudarsana Reddy Kalluru case TCP_V4_FLOW: 647961acdeaSSudarsana Reddy Kalluru case TCP_V6_FLOW: 648961acdeaSSudarsana Reddy Kalluru info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 649961acdeaSSudarsana Reddy Kalluru break; 650961acdeaSSudarsana Reddy Kalluru case UDP_V4_FLOW: 651961acdeaSSudarsana Reddy Kalluru if (edev->rss_params.rss_caps & QED_RSS_IPV4_UDP) 652961acdeaSSudarsana Reddy Kalluru info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 653961acdeaSSudarsana Reddy Kalluru break; 654961acdeaSSudarsana Reddy Kalluru case UDP_V6_FLOW: 655961acdeaSSudarsana Reddy Kalluru if (edev->rss_params.rss_caps & QED_RSS_IPV6_UDP) 656961acdeaSSudarsana Reddy Kalluru info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 657961acdeaSSudarsana Reddy Kalluru break; 658961acdeaSSudarsana Reddy Kalluru case IPV4_FLOW: 659961acdeaSSudarsana Reddy Kalluru case IPV6_FLOW: 660961acdeaSSudarsana Reddy Kalluru break; 661961acdeaSSudarsana Reddy Kalluru default: 662961acdeaSSudarsana Reddy Kalluru info->data = 0; 663961acdeaSSudarsana Reddy Kalluru break; 664961acdeaSSudarsana Reddy Kalluru } 665961acdeaSSudarsana Reddy Kalluru 666961acdeaSSudarsana Reddy Kalluru return 0; 667961acdeaSSudarsana Reddy Kalluru } 668961acdeaSSudarsana Reddy Kalluru 669961acdeaSSudarsana Reddy Kalluru static int qede_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, 670961acdeaSSudarsana Reddy Kalluru u32 *rules __always_unused) 671961acdeaSSudarsana Reddy Kalluru { 672961acdeaSSudarsana Reddy Kalluru struct qede_dev *edev = netdev_priv(dev); 673961acdeaSSudarsana Reddy Kalluru 674961acdeaSSudarsana Reddy Kalluru switch (info->cmd) { 675961acdeaSSudarsana Reddy Kalluru case ETHTOOL_GRXRINGS: 676961acdeaSSudarsana Reddy Kalluru info->data = edev->num_rss; 677961acdeaSSudarsana Reddy Kalluru return 0; 678961acdeaSSudarsana Reddy Kalluru case ETHTOOL_GRXFH: 679961acdeaSSudarsana Reddy Kalluru return qede_get_rss_flags(edev, info); 680961acdeaSSudarsana Reddy Kalluru default: 681961acdeaSSudarsana Reddy Kalluru DP_ERR(edev, "Command parameters not supported\n"); 682961acdeaSSudarsana Reddy Kalluru return -EOPNOTSUPP; 683961acdeaSSudarsana Reddy Kalluru } 684961acdeaSSudarsana Reddy Kalluru } 685961acdeaSSudarsana Reddy Kalluru 686961acdeaSSudarsana Reddy Kalluru static int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info) 687961acdeaSSudarsana Reddy Kalluru { 688961acdeaSSudarsana Reddy Kalluru struct qed_update_vport_params vport_update_params; 689961acdeaSSudarsana Reddy Kalluru u8 set_caps = 0, clr_caps = 0; 690961acdeaSSudarsana Reddy Kalluru 691961acdeaSSudarsana Reddy Kalluru DP_VERBOSE(edev, QED_MSG_DEBUG, 692961acdeaSSudarsana Reddy Kalluru "Set rss flags command parameters: flow type = %d, data = %llu\n", 693961acdeaSSudarsana Reddy Kalluru info->flow_type, info->data); 694961acdeaSSudarsana Reddy Kalluru 695961acdeaSSudarsana Reddy Kalluru switch (info->flow_type) { 696961acdeaSSudarsana Reddy Kalluru case TCP_V4_FLOW: 697961acdeaSSudarsana Reddy Kalluru case TCP_V6_FLOW: 698961acdeaSSudarsana Reddy Kalluru /* For TCP only 4-tuple hash is supported */ 699961acdeaSSudarsana Reddy Kalluru if (info->data ^ (RXH_IP_SRC | RXH_IP_DST | 700961acdeaSSudarsana Reddy Kalluru RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 701961acdeaSSudarsana Reddy Kalluru DP_INFO(edev, "Command parameters not supported\n"); 702961acdeaSSudarsana Reddy Kalluru return -EINVAL; 703961acdeaSSudarsana Reddy Kalluru } 704961acdeaSSudarsana Reddy Kalluru return 0; 705961acdeaSSudarsana Reddy Kalluru case UDP_V4_FLOW: 706961acdeaSSudarsana Reddy Kalluru /* For UDP either 2-tuple hash or 4-tuple hash is supported */ 707961acdeaSSudarsana Reddy Kalluru if (info->data == (RXH_IP_SRC | RXH_IP_DST | 708961acdeaSSudarsana Reddy Kalluru RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 709961acdeaSSudarsana Reddy Kalluru set_caps = QED_RSS_IPV4_UDP; 710961acdeaSSudarsana Reddy Kalluru DP_VERBOSE(edev, QED_MSG_DEBUG, 711961acdeaSSudarsana Reddy Kalluru "UDP 4-tuple enabled\n"); 712961acdeaSSudarsana Reddy Kalluru } else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) { 713961acdeaSSudarsana Reddy Kalluru clr_caps = QED_RSS_IPV4_UDP; 714961acdeaSSudarsana Reddy Kalluru DP_VERBOSE(edev, QED_MSG_DEBUG, 715961acdeaSSudarsana Reddy Kalluru "UDP 4-tuple disabled\n"); 716961acdeaSSudarsana Reddy Kalluru } else { 717961acdeaSSudarsana Reddy Kalluru return -EINVAL; 718961acdeaSSudarsana Reddy Kalluru } 719961acdeaSSudarsana Reddy Kalluru break; 720961acdeaSSudarsana Reddy Kalluru case UDP_V6_FLOW: 721961acdeaSSudarsana Reddy Kalluru /* For UDP either 2-tuple hash or 4-tuple hash is supported */ 722961acdeaSSudarsana Reddy Kalluru if (info->data == (RXH_IP_SRC | RXH_IP_DST | 723961acdeaSSudarsana Reddy Kalluru RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 724961acdeaSSudarsana Reddy Kalluru set_caps = QED_RSS_IPV6_UDP; 725961acdeaSSudarsana Reddy Kalluru DP_VERBOSE(edev, QED_MSG_DEBUG, 726961acdeaSSudarsana Reddy Kalluru "UDP 4-tuple enabled\n"); 727961acdeaSSudarsana Reddy Kalluru } else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) { 728961acdeaSSudarsana Reddy Kalluru clr_caps = QED_RSS_IPV6_UDP; 729961acdeaSSudarsana Reddy Kalluru DP_VERBOSE(edev, QED_MSG_DEBUG, 730961acdeaSSudarsana Reddy Kalluru "UDP 4-tuple disabled\n"); 731961acdeaSSudarsana Reddy Kalluru } else { 732961acdeaSSudarsana Reddy Kalluru return -EINVAL; 733961acdeaSSudarsana Reddy Kalluru } 734961acdeaSSudarsana Reddy Kalluru break; 735961acdeaSSudarsana Reddy Kalluru case IPV4_FLOW: 736961acdeaSSudarsana Reddy Kalluru case IPV6_FLOW: 737961acdeaSSudarsana Reddy Kalluru /* For IP only 2-tuple hash is supported */ 738961acdeaSSudarsana Reddy Kalluru if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) { 739961acdeaSSudarsana Reddy Kalluru DP_INFO(edev, "Command parameters not supported\n"); 740961acdeaSSudarsana Reddy Kalluru return -EINVAL; 741961acdeaSSudarsana Reddy Kalluru } 742961acdeaSSudarsana Reddy Kalluru return 0; 743961acdeaSSudarsana Reddy Kalluru case SCTP_V4_FLOW: 744961acdeaSSudarsana Reddy Kalluru case AH_ESP_V4_FLOW: 745961acdeaSSudarsana Reddy Kalluru case AH_V4_FLOW: 746961acdeaSSudarsana Reddy Kalluru case ESP_V4_FLOW: 747961acdeaSSudarsana Reddy Kalluru case SCTP_V6_FLOW: 748961acdeaSSudarsana Reddy Kalluru case AH_ESP_V6_FLOW: 749961acdeaSSudarsana Reddy Kalluru case AH_V6_FLOW: 750961acdeaSSudarsana Reddy Kalluru case ESP_V6_FLOW: 751961acdeaSSudarsana Reddy Kalluru case IP_USER_FLOW: 752961acdeaSSudarsana Reddy Kalluru case ETHER_FLOW: 753961acdeaSSudarsana Reddy Kalluru /* RSS is not supported for these protocols */ 754961acdeaSSudarsana Reddy Kalluru if (info->data) { 755961acdeaSSudarsana Reddy Kalluru DP_INFO(edev, "Command parameters not supported\n"); 756961acdeaSSudarsana Reddy Kalluru return -EINVAL; 757961acdeaSSudarsana Reddy Kalluru } 758961acdeaSSudarsana Reddy Kalluru return 0; 759961acdeaSSudarsana Reddy Kalluru default: 760961acdeaSSudarsana Reddy Kalluru return -EINVAL; 761961acdeaSSudarsana Reddy Kalluru } 762961acdeaSSudarsana Reddy Kalluru 763961acdeaSSudarsana Reddy Kalluru /* No action is needed if there is no change in the rss capability */ 764961acdeaSSudarsana Reddy Kalluru if (edev->rss_params.rss_caps == ((edev->rss_params.rss_caps & 765961acdeaSSudarsana Reddy Kalluru ~clr_caps) | set_caps)) 766961acdeaSSudarsana Reddy Kalluru return 0; 767961acdeaSSudarsana Reddy Kalluru 768961acdeaSSudarsana Reddy Kalluru /* Update internal configuration */ 769961acdeaSSudarsana Reddy Kalluru edev->rss_params.rss_caps = (edev->rss_params.rss_caps & ~clr_caps) | 770961acdeaSSudarsana Reddy Kalluru set_caps; 771961acdeaSSudarsana Reddy Kalluru edev->rss_params_inited |= QEDE_RSS_CAPS_INITED; 772961acdeaSSudarsana Reddy Kalluru 773961acdeaSSudarsana Reddy Kalluru /* Re-configure if possible */ 774961acdeaSSudarsana Reddy Kalluru if (netif_running(edev->ndev)) { 775961acdeaSSudarsana Reddy Kalluru memset(&vport_update_params, 0, sizeof(vport_update_params)); 776961acdeaSSudarsana Reddy Kalluru vport_update_params.update_rss_flg = 1; 777961acdeaSSudarsana Reddy Kalluru vport_update_params.vport_id = 0; 778961acdeaSSudarsana Reddy Kalluru memcpy(&vport_update_params.rss_params, &edev->rss_params, 779961acdeaSSudarsana Reddy Kalluru sizeof(vport_update_params.rss_params)); 780961acdeaSSudarsana Reddy Kalluru return edev->ops->vport_update(edev->cdev, 781961acdeaSSudarsana Reddy Kalluru &vport_update_params); 782961acdeaSSudarsana Reddy Kalluru } 783961acdeaSSudarsana Reddy Kalluru 784961acdeaSSudarsana Reddy Kalluru return 0; 785961acdeaSSudarsana Reddy Kalluru } 786961acdeaSSudarsana Reddy Kalluru 787961acdeaSSudarsana Reddy Kalluru static int qede_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info) 788961acdeaSSudarsana Reddy Kalluru { 789961acdeaSSudarsana Reddy Kalluru struct qede_dev *edev = netdev_priv(dev); 790961acdeaSSudarsana Reddy Kalluru 791961acdeaSSudarsana Reddy Kalluru switch (info->cmd) { 792961acdeaSSudarsana Reddy Kalluru case ETHTOOL_SRXFH: 793961acdeaSSudarsana Reddy Kalluru return qede_set_rss_flags(edev, info); 794961acdeaSSudarsana Reddy Kalluru default: 795961acdeaSSudarsana Reddy Kalluru DP_INFO(edev, "Command parameters not supported\n"); 796961acdeaSSudarsana Reddy Kalluru return -EOPNOTSUPP; 797961acdeaSSudarsana Reddy Kalluru } 798961acdeaSSudarsana Reddy Kalluru } 799961acdeaSSudarsana Reddy Kalluru 800961acdeaSSudarsana Reddy Kalluru static u32 qede_get_rxfh_indir_size(struct net_device *dev) 801961acdeaSSudarsana Reddy Kalluru { 802961acdeaSSudarsana Reddy Kalluru return QED_RSS_IND_TABLE_SIZE; 803961acdeaSSudarsana Reddy Kalluru } 804961acdeaSSudarsana Reddy Kalluru 805961acdeaSSudarsana Reddy Kalluru static u32 qede_get_rxfh_key_size(struct net_device *dev) 806961acdeaSSudarsana Reddy Kalluru { 807961acdeaSSudarsana Reddy Kalluru struct qede_dev *edev = netdev_priv(dev); 808961acdeaSSudarsana Reddy Kalluru 809961acdeaSSudarsana Reddy Kalluru return sizeof(edev->rss_params.rss_key); 810961acdeaSSudarsana Reddy Kalluru } 811961acdeaSSudarsana Reddy Kalluru 812961acdeaSSudarsana Reddy Kalluru static int qede_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc) 813961acdeaSSudarsana Reddy Kalluru { 814961acdeaSSudarsana Reddy Kalluru struct qede_dev *edev = netdev_priv(dev); 815961acdeaSSudarsana Reddy Kalluru int i; 816961acdeaSSudarsana Reddy Kalluru 817961acdeaSSudarsana Reddy Kalluru if (hfunc) 818961acdeaSSudarsana Reddy Kalluru *hfunc = ETH_RSS_HASH_TOP; 819961acdeaSSudarsana Reddy Kalluru 820961acdeaSSudarsana Reddy Kalluru if (!indir) 821961acdeaSSudarsana Reddy Kalluru return 0; 822961acdeaSSudarsana Reddy Kalluru 823961acdeaSSudarsana Reddy Kalluru for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++) 824961acdeaSSudarsana Reddy Kalluru indir[i] = edev->rss_params.rss_ind_table[i]; 825961acdeaSSudarsana Reddy Kalluru 826961acdeaSSudarsana Reddy Kalluru if (key) 827961acdeaSSudarsana Reddy Kalluru memcpy(key, edev->rss_params.rss_key, 828961acdeaSSudarsana Reddy Kalluru qede_get_rxfh_key_size(dev)); 829961acdeaSSudarsana Reddy Kalluru 830961acdeaSSudarsana Reddy Kalluru return 0; 831961acdeaSSudarsana Reddy Kalluru } 832961acdeaSSudarsana Reddy Kalluru 833961acdeaSSudarsana Reddy Kalluru static int qede_set_rxfh(struct net_device *dev, const u32 *indir, 834961acdeaSSudarsana Reddy Kalluru const u8 *key, const u8 hfunc) 835961acdeaSSudarsana Reddy Kalluru { 836961acdeaSSudarsana Reddy Kalluru struct qed_update_vport_params vport_update_params; 837961acdeaSSudarsana Reddy Kalluru struct qede_dev *edev = netdev_priv(dev); 838961acdeaSSudarsana Reddy Kalluru int i; 839961acdeaSSudarsana Reddy Kalluru 840961acdeaSSudarsana Reddy Kalluru if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 841961acdeaSSudarsana Reddy Kalluru return -EOPNOTSUPP; 842961acdeaSSudarsana Reddy Kalluru 843961acdeaSSudarsana Reddy Kalluru if (!indir && !key) 844961acdeaSSudarsana Reddy Kalluru return 0; 845961acdeaSSudarsana Reddy Kalluru 846961acdeaSSudarsana Reddy Kalluru if (indir) { 847961acdeaSSudarsana Reddy Kalluru for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++) 848961acdeaSSudarsana Reddy Kalluru edev->rss_params.rss_ind_table[i] = indir[i]; 849961acdeaSSudarsana Reddy Kalluru edev->rss_params_inited |= QEDE_RSS_INDIR_INITED; 850961acdeaSSudarsana Reddy Kalluru } 851961acdeaSSudarsana Reddy Kalluru 852961acdeaSSudarsana Reddy Kalluru if (key) { 853961acdeaSSudarsana Reddy Kalluru memcpy(&edev->rss_params.rss_key, key, 854961acdeaSSudarsana Reddy Kalluru qede_get_rxfh_key_size(dev)); 855961acdeaSSudarsana Reddy Kalluru edev->rss_params_inited |= QEDE_RSS_KEY_INITED; 856961acdeaSSudarsana Reddy Kalluru } 857961acdeaSSudarsana Reddy Kalluru 858961acdeaSSudarsana Reddy Kalluru if (netif_running(edev->ndev)) { 859961acdeaSSudarsana Reddy Kalluru memset(&vport_update_params, 0, sizeof(vport_update_params)); 860961acdeaSSudarsana Reddy Kalluru vport_update_params.update_rss_flg = 1; 861961acdeaSSudarsana Reddy Kalluru vport_update_params.vport_id = 0; 862961acdeaSSudarsana Reddy Kalluru memcpy(&vport_update_params.rss_params, &edev->rss_params, 863961acdeaSSudarsana Reddy Kalluru sizeof(vport_update_params.rss_params)); 864961acdeaSSudarsana Reddy Kalluru return edev->ops->vport_update(edev->cdev, 865961acdeaSSudarsana Reddy Kalluru &vport_update_params); 866961acdeaSSudarsana Reddy Kalluru } 867961acdeaSSudarsana Reddy Kalluru 868961acdeaSSudarsana Reddy Kalluru return 0; 869961acdeaSSudarsana Reddy Kalluru } 870961acdeaSSudarsana Reddy Kalluru 87116f46bf0SSudarsana Reddy Kalluru /* This function enables the interrupt generation and the NAPI on the device */ 87216f46bf0SSudarsana Reddy Kalluru static void qede_netif_start(struct qede_dev *edev) 87316f46bf0SSudarsana Reddy Kalluru { 87416f46bf0SSudarsana Reddy Kalluru int i; 87516f46bf0SSudarsana Reddy Kalluru 87616f46bf0SSudarsana Reddy Kalluru if (!netif_running(edev->ndev)) 87716f46bf0SSudarsana Reddy Kalluru return; 87816f46bf0SSudarsana Reddy Kalluru 87916f46bf0SSudarsana Reddy Kalluru for_each_rss(i) { 88016f46bf0SSudarsana Reddy Kalluru /* Update and reenable interrupts */ 88116f46bf0SSudarsana Reddy Kalluru qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_ENABLE, 1); 88216f46bf0SSudarsana Reddy Kalluru napi_enable(&edev->fp_array[i].napi); 88316f46bf0SSudarsana Reddy Kalluru } 88416f46bf0SSudarsana Reddy Kalluru } 88516f46bf0SSudarsana Reddy Kalluru 88616f46bf0SSudarsana Reddy Kalluru /* This function disables the NAPI and the interrupt generation on the device */ 88716f46bf0SSudarsana Reddy Kalluru static void qede_netif_stop(struct qede_dev *edev) 88816f46bf0SSudarsana Reddy Kalluru { 88916f46bf0SSudarsana Reddy Kalluru int i; 89016f46bf0SSudarsana Reddy Kalluru 89116f46bf0SSudarsana Reddy Kalluru for_each_rss(i) { 89216f46bf0SSudarsana Reddy Kalluru napi_disable(&edev->fp_array[i].napi); 89316f46bf0SSudarsana Reddy Kalluru /* Disable interrupts */ 89416f46bf0SSudarsana Reddy Kalluru qed_sb_ack(edev->fp_array[i].sb_info, IGU_INT_DISABLE, 0); 89516f46bf0SSudarsana Reddy Kalluru } 89616f46bf0SSudarsana Reddy Kalluru } 89716f46bf0SSudarsana Reddy Kalluru 89816f46bf0SSudarsana Reddy Kalluru static int qede_selftest_transmit_traffic(struct qede_dev *edev, 89916f46bf0SSudarsana Reddy Kalluru struct sk_buff *skb) 90016f46bf0SSudarsana Reddy Kalluru { 90116f46bf0SSudarsana Reddy Kalluru struct qede_tx_queue *txq = &edev->fp_array[0].txqs[0]; 90216f46bf0SSudarsana Reddy Kalluru struct eth_tx_1st_bd *first_bd; 90316f46bf0SSudarsana Reddy Kalluru dma_addr_t mapping; 90416f46bf0SSudarsana Reddy Kalluru int i, idx, val; 90516f46bf0SSudarsana Reddy Kalluru 90616f46bf0SSudarsana Reddy Kalluru /* Fill the entry in the SW ring and the BDs in the FW ring */ 90716f46bf0SSudarsana Reddy Kalluru idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; 90816f46bf0SSudarsana Reddy Kalluru txq->sw_tx_ring[idx].skb = skb; 90916f46bf0SSudarsana Reddy Kalluru first_bd = qed_chain_produce(&txq->tx_pbl); 91016f46bf0SSudarsana Reddy Kalluru memset(first_bd, 0, sizeof(*first_bd)); 91116f46bf0SSudarsana Reddy Kalluru val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT; 91216f46bf0SSudarsana Reddy Kalluru first_bd->data.bd_flags.bitfields = val; 913351a4dedSYuval Mintz val = skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK; 914351a4dedSYuval Mintz first_bd->data.bitfields |= (val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT); 91516f46bf0SSudarsana Reddy Kalluru 91616f46bf0SSudarsana Reddy Kalluru /* Map skb linear data for DMA and set in the first BD */ 91716f46bf0SSudarsana Reddy Kalluru mapping = dma_map_single(&edev->pdev->dev, skb->data, 91816f46bf0SSudarsana Reddy Kalluru skb_headlen(skb), DMA_TO_DEVICE); 91916f46bf0SSudarsana Reddy Kalluru if (unlikely(dma_mapping_error(&edev->pdev->dev, mapping))) { 92016f46bf0SSudarsana Reddy Kalluru DP_NOTICE(edev, "SKB mapping failed\n"); 92116f46bf0SSudarsana Reddy Kalluru return -ENOMEM; 92216f46bf0SSudarsana Reddy Kalluru } 92316f46bf0SSudarsana Reddy Kalluru BD_SET_UNMAP_ADDR_LEN(first_bd, mapping, skb_headlen(skb)); 92416f46bf0SSudarsana Reddy Kalluru 92516f46bf0SSudarsana Reddy Kalluru /* update the first BD with the actual num BDs */ 92616f46bf0SSudarsana Reddy Kalluru first_bd->data.nbds = 1; 92716f46bf0SSudarsana Reddy Kalluru txq->sw_tx_prod++; 92816f46bf0SSudarsana Reddy Kalluru /* 'next page' entries are counted in the producer value */ 92916f46bf0SSudarsana Reddy Kalluru val = cpu_to_le16(qed_chain_get_prod_idx(&txq->tx_pbl)); 93016f46bf0SSudarsana Reddy Kalluru txq->tx_db.data.bd_prod = val; 93116f46bf0SSudarsana Reddy Kalluru 93216f46bf0SSudarsana Reddy Kalluru /* wmb makes sure that the BDs data is updated before updating the 93316f46bf0SSudarsana Reddy Kalluru * producer, otherwise FW may read old data from the BDs. 93416f46bf0SSudarsana Reddy Kalluru */ 93516f46bf0SSudarsana Reddy Kalluru wmb(); 93616f46bf0SSudarsana Reddy Kalluru barrier(); 93716f46bf0SSudarsana Reddy Kalluru writel(txq->tx_db.raw, txq->doorbell_addr); 93816f46bf0SSudarsana Reddy Kalluru 93916f46bf0SSudarsana Reddy Kalluru /* mmiowb is needed to synchronize doorbell writes from more than one 94016f46bf0SSudarsana Reddy Kalluru * processor. It guarantees that the write arrives to the device before 94116f46bf0SSudarsana Reddy Kalluru * the queue lock is released and another start_xmit is called (possibly 94216f46bf0SSudarsana Reddy Kalluru * on another CPU). Without this barrier, the next doorbell can bypass 94316f46bf0SSudarsana Reddy Kalluru * this doorbell. This is applicable to IA64/Altix systems. 94416f46bf0SSudarsana Reddy Kalluru */ 94516f46bf0SSudarsana Reddy Kalluru mmiowb(); 94616f46bf0SSudarsana Reddy Kalluru 94716f46bf0SSudarsana Reddy Kalluru for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) { 94816f46bf0SSudarsana Reddy Kalluru if (qede_txq_has_work(txq)) 94916f46bf0SSudarsana Reddy Kalluru break; 95016f46bf0SSudarsana Reddy Kalluru usleep_range(100, 200); 95116f46bf0SSudarsana Reddy Kalluru } 95216f46bf0SSudarsana Reddy Kalluru 95316f46bf0SSudarsana Reddy Kalluru if (!qede_txq_has_work(txq)) { 95416f46bf0SSudarsana Reddy Kalluru DP_NOTICE(edev, "Tx completion didn't happen\n"); 95516f46bf0SSudarsana Reddy Kalluru return -1; 95616f46bf0SSudarsana Reddy Kalluru } 95716f46bf0SSudarsana Reddy Kalluru 95816f46bf0SSudarsana Reddy Kalluru first_bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl); 95916f46bf0SSudarsana Reddy Kalluru dma_unmap_page(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), 96016f46bf0SSudarsana Reddy Kalluru BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE); 96116f46bf0SSudarsana Reddy Kalluru txq->sw_tx_cons++; 96216f46bf0SSudarsana Reddy Kalluru txq->sw_tx_ring[idx].skb = NULL; 96316f46bf0SSudarsana Reddy Kalluru 96416f46bf0SSudarsana Reddy Kalluru return 0; 96516f46bf0SSudarsana Reddy Kalluru } 96616f46bf0SSudarsana Reddy Kalluru 96716f46bf0SSudarsana Reddy Kalluru static int qede_selftest_receive_traffic(struct qede_dev *edev) 96816f46bf0SSudarsana Reddy Kalluru { 96916f46bf0SSudarsana Reddy Kalluru struct qede_rx_queue *rxq = edev->fp_array[0].rxq; 97016f46bf0SSudarsana Reddy Kalluru u16 hw_comp_cons, sw_comp_cons, sw_rx_index, len; 97116f46bf0SSudarsana Reddy Kalluru struct eth_fast_path_rx_reg_cqe *fp_cqe; 97216f46bf0SSudarsana Reddy Kalluru struct sw_rx_data *sw_rx_data; 97316f46bf0SSudarsana Reddy Kalluru union eth_rx_cqe *cqe; 97416f46bf0SSudarsana Reddy Kalluru u8 *data_ptr; 97516f46bf0SSudarsana Reddy Kalluru int i; 97616f46bf0SSudarsana Reddy Kalluru 97716f46bf0SSudarsana Reddy Kalluru /* The packet is expected to receive on rx-queue 0 even though RSS is 97816f46bf0SSudarsana Reddy Kalluru * enabled. This is because the queue 0 is configured as the default 97916f46bf0SSudarsana Reddy Kalluru * queue and that the loopback traffic is not IP. 98016f46bf0SSudarsana Reddy Kalluru */ 98116f46bf0SSudarsana Reddy Kalluru for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) { 98216f46bf0SSudarsana Reddy Kalluru if (qede_has_rx_work(rxq)) 98316f46bf0SSudarsana Reddy Kalluru break; 98416f46bf0SSudarsana Reddy Kalluru usleep_range(100, 200); 98516f46bf0SSudarsana Reddy Kalluru } 98616f46bf0SSudarsana Reddy Kalluru 98716f46bf0SSudarsana Reddy Kalluru if (!qede_has_rx_work(rxq)) { 98816f46bf0SSudarsana Reddy Kalluru DP_NOTICE(edev, "Failed to receive the traffic\n"); 98916f46bf0SSudarsana Reddy Kalluru return -1; 99016f46bf0SSudarsana Reddy Kalluru } 99116f46bf0SSudarsana Reddy Kalluru 99216f46bf0SSudarsana Reddy Kalluru hw_comp_cons = le16_to_cpu(*rxq->hw_cons_ptr); 99316f46bf0SSudarsana Reddy Kalluru sw_comp_cons = qed_chain_get_cons_idx(&rxq->rx_comp_ring); 99416f46bf0SSudarsana Reddy Kalluru 99516f46bf0SSudarsana Reddy Kalluru /* Memory barrier to prevent the CPU from doing speculative reads of CQE 99616f46bf0SSudarsana Reddy Kalluru * / BD before reading hw_comp_cons. If the CQE is read before it is 99716f46bf0SSudarsana Reddy Kalluru * written by FW, then FW writes CQE and SB, and then the CPU reads the 99816f46bf0SSudarsana Reddy Kalluru * hw_comp_cons, it will use an old CQE. 99916f46bf0SSudarsana Reddy Kalluru */ 100016f46bf0SSudarsana Reddy Kalluru rmb(); 100116f46bf0SSudarsana Reddy Kalluru 100216f46bf0SSudarsana Reddy Kalluru /* Get the CQE from the completion ring */ 100316f46bf0SSudarsana Reddy Kalluru cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring); 100416f46bf0SSudarsana Reddy Kalluru 100516f46bf0SSudarsana Reddy Kalluru /* Get the data from the SW ring */ 100616f46bf0SSudarsana Reddy Kalluru sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX; 100716f46bf0SSudarsana Reddy Kalluru sw_rx_data = &rxq->sw_rx_ring[sw_rx_index]; 100816f46bf0SSudarsana Reddy Kalluru fp_cqe = &cqe->fast_path_regular; 100916f46bf0SSudarsana Reddy Kalluru len = le16_to_cpu(fp_cqe->len_on_first_bd); 101016f46bf0SSudarsana Reddy Kalluru data_ptr = (u8 *)(page_address(sw_rx_data->data) + 101116f46bf0SSudarsana Reddy Kalluru fp_cqe->placement_offset + sw_rx_data->page_offset); 101216f46bf0SSudarsana Reddy Kalluru for (i = ETH_HLEN; i < len; i++) 101316f46bf0SSudarsana Reddy Kalluru if (data_ptr[i] != (unsigned char)(i & 0xff)) { 101416f46bf0SSudarsana Reddy Kalluru DP_NOTICE(edev, "Loopback test failed\n"); 101516f46bf0SSudarsana Reddy Kalluru qede_recycle_rx_bd_ring(rxq, edev, 1); 101616f46bf0SSudarsana Reddy Kalluru return -1; 101716f46bf0SSudarsana Reddy Kalluru } 101816f46bf0SSudarsana Reddy Kalluru 101916f46bf0SSudarsana Reddy Kalluru qede_recycle_rx_bd_ring(rxq, edev, 1); 102016f46bf0SSudarsana Reddy Kalluru 102116f46bf0SSudarsana Reddy Kalluru return 0; 102216f46bf0SSudarsana Reddy Kalluru } 102316f46bf0SSudarsana Reddy Kalluru 102416f46bf0SSudarsana Reddy Kalluru static int qede_selftest_run_loopback(struct qede_dev *edev, u32 loopback_mode) 102516f46bf0SSudarsana Reddy Kalluru { 102616f46bf0SSudarsana Reddy Kalluru struct qed_link_params link_params; 102716f46bf0SSudarsana Reddy Kalluru struct sk_buff *skb = NULL; 102816f46bf0SSudarsana Reddy Kalluru int rc = 0, i; 102916f46bf0SSudarsana Reddy Kalluru u32 pkt_size; 103016f46bf0SSudarsana Reddy Kalluru u8 *packet; 103116f46bf0SSudarsana Reddy Kalluru 103216f46bf0SSudarsana Reddy Kalluru if (!netif_running(edev->ndev)) { 103316f46bf0SSudarsana Reddy Kalluru DP_NOTICE(edev, "Interface is down\n"); 103416f46bf0SSudarsana Reddy Kalluru return -EINVAL; 103516f46bf0SSudarsana Reddy Kalluru } 103616f46bf0SSudarsana Reddy Kalluru 103716f46bf0SSudarsana Reddy Kalluru qede_netif_stop(edev); 103816f46bf0SSudarsana Reddy Kalluru 103916f46bf0SSudarsana Reddy Kalluru /* Bring up the link in Loopback mode */ 104016f46bf0SSudarsana Reddy Kalluru memset(&link_params, 0, sizeof(link_params)); 104116f46bf0SSudarsana Reddy Kalluru link_params.link_up = true; 104216f46bf0SSudarsana Reddy Kalluru link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE; 104316f46bf0SSudarsana Reddy Kalluru link_params.loopback_mode = loopback_mode; 104416f46bf0SSudarsana Reddy Kalluru edev->ops->common->set_link(edev->cdev, &link_params); 104516f46bf0SSudarsana Reddy Kalluru 104616f46bf0SSudarsana Reddy Kalluru /* Wait for loopback configuration to apply */ 104716f46bf0SSudarsana Reddy Kalluru msleep_interruptible(500); 104816f46bf0SSudarsana Reddy Kalluru 104916f46bf0SSudarsana Reddy Kalluru /* prepare the loopback packet */ 105016f46bf0SSudarsana Reddy Kalluru pkt_size = edev->ndev->mtu + ETH_HLEN; 105116f46bf0SSudarsana Reddy Kalluru 105216f46bf0SSudarsana Reddy Kalluru skb = netdev_alloc_skb(edev->ndev, pkt_size); 105316f46bf0SSudarsana Reddy Kalluru if (!skb) { 105416f46bf0SSudarsana Reddy Kalluru DP_INFO(edev, "Can't allocate skb\n"); 105516f46bf0SSudarsana Reddy Kalluru rc = -ENOMEM; 105616f46bf0SSudarsana Reddy Kalluru goto test_loopback_exit; 105716f46bf0SSudarsana Reddy Kalluru } 105816f46bf0SSudarsana Reddy Kalluru packet = skb_put(skb, pkt_size); 105916f46bf0SSudarsana Reddy Kalluru ether_addr_copy(packet, edev->ndev->dev_addr); 106016f46bf0SSudarsana Reddy Kalluru ether_addr_copy(packet + ETH_ALEN, edev->ndev->dev_addr); 106116f46bf0SSudarsana Reddy Kalluru memset(packet + (2 * ETH_ALEN), 0x77, (ETH_HLEN - (2 * ETH_ALEN))); 106216f46bf0SSudarsana Reddy Kalluru for (i = ETH_HLEN; i < pkt_size; i++) 106316f46bf0SSudarsana Reddy Kalluru packet[i] = (unsigned char)(i & 0xff); 106416f46bf0SSudarsana Reddy Kalluru 106516f46bf0SSudarsana Reddy Kalluru rc = qede_selftest_transmit_traffic(edev, skb); 106616f46bf0SSudarsana Reddy Kalluru if (rc) 106716f46bf0SSudarsana Reddy Kalluru goto test_loopback_exit; 106816f46bf0SSudarsana Reddy Kalluru 106916f46bf0SSudarsana Reddy Kalluru rc = qede_selftest_receive_traffic(edev); 107016f46bf0SSudarsana Reddy Kalluru if (rc) 107116f46bf0SSudarsana Reddy Kalluru goto test_loopback_exit; 107216f46bf0SSudarsana Reddy Kalluru 107316f46bf0SSudarsana Reddy Kalluru DP_VERBOSE(edev, NETIF_MSG_RX_STATUS, "Loopback test successful\n"); 107416f46bf0SSudarsana Reddy Kalluru 107516f46bf0SSudarsana Reddy Kalluru test_loopback_exit: 107616f46bf0SSudarsana Reddy Kalluru dev_kfree_skb(skb); 107716f46bf0SSudarsana Reddy Kalluru 107816f46bf0SSudarsana Reddy Kalluru /* Bring up the link in Normal mode */ 107916f46bf0SSudarsana Reddy Kalluru memset(&link_params, 0, sizeof(link_params)); 108016f46bf0SSudarsana Reddy Kalluru link_params.link_up = true; 108116f46bf0SSudarsana Reddy Kalluru link_params.override_flags = QED_LINK_OVERRIDE_LOOPBACK_MODE; 108216f46bf0SSudarsana Reddy Kalluru link_params.loopback_mode = QED_LINK_LOOPBACK_NONE; 108316f46bf0SSudarsana Reddy Kalluru edev->ops->common->set_link(edev->cdev, &link_params); 108416f46bf0SSudarsana Reddy Kalluru 108516f46bf0SSudarsana Reddy Kalluru /* Wait for loopback configuration to apply */ 108616f46bf0SSudarsana Reddy Kalluru msleep_interruptible(500); 108716f46bf0SSudarsana Reddy Kalluru 108816f46bf0SSudarsana Reddy Kalluru qede_netif_start(edev); 108916f46bf0SSudarsana Reddy Kalluru 109016f46bf0SSudarsana Reddy Kalluru return rc; 109116f46bf0SSudarsana Reddy Kalluru } 109216f46bf0SSudarsana Reddy Kalluru 10933044a02eSSudarsana Reddy Kalluru static void qede_self_test(struct net_device *dev, 10943044a02eSSudarsana Reddy Kalluru struct ethtool_test *etest, u64 *buf) 10953044a02eSSudarsana Reddy Kalluru { 10963044a02eSSudarsana Reddy Kalluru struct qede_dev *edev = netdev_priv(dev); 10973044a02eSSudarsana Reddy Kalluru 10983044a02eSSudarsana Reddy Kalluru DP_VERBOSE(edev, QED_MSG_DEBUG, 10993044a02eSSudarsana Reddy Kalluru "Self-test command parameters: offline = %d, external_lb = %d\n", 11003044a02eSSudarsana Reddy Kalluru (etest->flags & ETH_TEST_FL_OFFLINE), 11013044a02eSSudarsana Reddy Kalluru (etest->flags & ETH_TEST_FL_EXTERNAL_LB) >> 2); 11023044a02eSSudarsana Reddy Kalluru 11033044a02eSSudarsana Reddy Kalluru memset(buf, 0, sizeof(u64) * QEDE_ETHTOOL_TEST_MAX); 11043044a02eSSudarsana Reddy Kalluru 110516f46bf0SSudarsana Reddy Kalluru if (etest->flags & ETH_TEST_FL_OFFLINE) { 110616f46bf0SSudarsana Reddy Kalluru if (qede_selftest_run_loopback(edev, 110716f46bf0SSudarsana Reddy Kalluru QED_LINK_LOOPBACK_INT_PHY)) { 110816f46bf0SSudarsana Reddy Kalluru buf[QEDE_ETHTOOL_INT_LOOPBACK] = 1; 110916f46bf0SSudarsana Reddy Kalluru etest->flags |= ETH_TEST_FL_FAILED; 111016f46bf0SSudarsana Reddy Kalluru } 111116f46bf0SSudarsana Reddy Kalluru } 111216f46bf0SSudarsana Reddy Kalluru 11133044a02eSSudarsana Reddy Kalluru if (edev->ops->common->selftest->selftest_interrupt(edev->cdev)) { 11143044a02eSSudarsana Reddy Kalluru buf[QEDE_ETHTOOL_INTERRUPT_TEST] = 1; 11153044a02eSSudarsana Reddy Kalluru etest->flags |= ETH_TEST_FL_FAILED; 11163044a02eSSudarsana Reddy Kalluru } 11173044a02eSSudarsana Reddy Kalluru 11183044a02eSSudarsana Reddy Kalluru if (edev->ops->common->selftest->selftest_memory(edev->cdev)) { 11193044a02eSSudarsana Reddy Kalluru buf[QEDE_ETHTOOL_MEMORY_TEST] = 1; 11203044a02eSSudarsana Reddy Kalluru etest->flags |= ETH_TEST_FL_FAILED; 11213044a02eSSudarsana Reddy Kalluru } 11223044a02eSSudarsana Reddy Kalluru 11233044a02eSSudarsana Reddy Kalluru if (edev->ops->common->selftest->selftest_register(edev->cdev)) { 11243044a02eSSudarsana Reddy Kalluru buf[QEDE_ETHTOOL_REGISTER_TEST] = 1; 11253044a02eSSudarsana Reddy Kalluru etest->flags |= ETH_TEST_FL_FAILED; 11263044a02eSSudarsana Reddy Kalluru } 11273044a02eSSudarsana Reddy Kalluru 11283044a02eSSudarsana Reddy Kalluru if (edev->ops->common->selftest->selftest_clock(edev->cdev)) { 11293044a02eSSudarsana Reddy Kalluru buf[QEDE_ETHTOOL_CLOCK_TEST] = 1; 11303044a02eSSudarsana Reddy Kalluru etest->flags |= ETH_TEST_FL_FAILED; 11313044a02eSSudarsana Reddy Kalluru } 11323044a02eSSudarsana Reddy Kalluru } 11333044a02eSSudarsana Reddy Kalluru 1134133fac0eSSudarsana Kalluru static const struct ethtool_ops qede_ethtool_ops = { 1135133fac0eSSudarsana Kalluru .get_settings = qede_get_settings, 1136133fac0eSSudarsana Kalluru .set_settings = qede_set_settings, 1137133fac0eSSudarsana Kalluru .get_drvinfo = qede_get_drvinfo, 1138133fac0eSSudarsana Kalluru .get_msglevel = qede_get_msglevel, 1139133fac0eSSudarsana Kalluru .set_msglevel = qede_set_msglevel, 114032a7a570SSudarsana Kalluru .nway_reset = qede_nway_reset, 1141133fac0eSSudarsana Kalluru .get_link = qede_get_link, 114201ef7e05SSudarsana Kalluru .get_ringparam = qede_get_ringparam, 114301ef7e05SSudarsana Kalluru .set_ringparam = qede_set_ringparam, 11440f7db144SSudarsana Kalluru .get_pauseparam = qede_get_pauseparam, 11450f7db144SSudarsana Kalluru .set_pauseparam = qede_set_pauseparam, 1146133fac0eSSudarsana Kalluru .get_strings = qede_get_strings, 11473d971cbdSSudarsana Kalluru .set_phys_id = qede_set_phys_id, 1148133fac0eSSudarsana Kalluru .get_ethtool_stats = qede_get_ethtool_stats, 1149f3e72109SYuval Mintz .get_priv_flags = qede_get_priv_flags, 1150133fac0eSSudarsana Kalluru .get_sset_count = qede_get_sset_count, 1151961acdeaSSudarsana Reddy Kalluru .get_rxnfc = qede_get_rxnfc, 1152961acdeaSSudarsana Reddy Kalluru .set_rxnfc = qede_set_rxnfc, 1153961acdeaSSudarsana Reddy Kalluru .get_rxfh_indir_size = qede_get_rxfh_indir_size, 1154961acdeaSSudarsana Reddy Kalluru .get_rxfh_key_size = qede_get_rxfh_key_size, 1155961acdeaSSudarsana Reddy Kalluru .get_rxfh = qede_get_rxfh, 1156961acdeaSSudarsana Reddy Kalluru .set_rxfh = qede_set_rxfh, 11578edf049dSSudarsana Kalluru .get_channels = qede_get_channels, 11588edf049dSSudarsana Kalluru .set_channels = qede_set_channels, 11593044a02eSSudarsana Reddy Kalluru .self_test = qede_self_test, 1160133fac0eSSudarsana Kalluru }; 1161133fac0eSSudarsana Kalluru 1162fefb0202SYuval Mintz static const struct ethtool_ops qede_vf_ethtool_ops = { 1163fefb0202SYuval Mintz .get_settings = qede_get_settings, 1164fefb0202SYuval Mintz .get_drvinfo = qede_get_drvinfo, 1165fefb0202SYuval Mintz .get_msglevel = qede_get_msglevel, 1166fefb0202SYuval Mintz .set_msglevel = qede_set_msglevel, 1167fefb0202SYuval Mintz .get_link = qede_get_link, 1168fefb0202SYuval Mintz .get_ringparam = qede_get_ringparam, 1169fefb0202SYuval Mintz .set_ringparam = qede_set_ringparam, 1170fefb0202SYuval Mintz .get_strings = qede_get_strings, 1171fefb0202SYuval Mintz .get_ethtool_stats = qede_get_ethtool_stats, 1172fefb0202SYuval Mintz .get_priv_flags = qede_get_priv_flags, 1173fefb0202SYuval Mintz .get_sset_count = qede_get_sset_count, 1174fefb0202SYuval Mintz .get_rxnfc = qede_get_rxnfc, 1175fefb0202SYuval Mintz .set_rxnfc = qede_set_rxnfc, 1176fefb0202SYuval Mintz .get_rxfh_indir_size = qede_get_rxfh_indir_size, 1177fefb0202SYuval Mintz .get_rxfh_key_size = qede_get_rxfh_key_size, 1178fefb0202SYuval Mintz .get_rxfh = qede_get_rxfh, 1179fefb0202SYuval Mintz .set_rxfh = qede_set_rxfh, 1180fefb0202SYuval Mintz .get_channels = qede_get_channels, 1181fefb0202SYuval Mintz .set_channels = qede_set_channels, 1182fefb0202SYuval Mintz }; 1183fefb0202SYuval Mintz 1184133fac0eSSudarsana Kalluru void qede_set_ethtool_ops(struct net_device *dev) 1185133fac0eSSudarsana Kalluru { 1186fefb0202SYuval Mintz struct qede_dev *edev = netdev_priv(dev); 1187fefb0202SYuval Mintz 1188fefb0202SYuval Mintz if (IS_VF(edev)) 1189fefb0202SYuval Mintz dev->ethtool_ops = &qede_vf_ethtool_ops; 1190fefb0202SYuval Mintz else 1191133fac0eSSudarsana Kalluru dev->ethtool_ops = &qede_ethtool_ops; 1192133fac0eSSudarsana Kalluru } 1193