1c5760d03SDavid VomLehn /* 2c5760d03SDavid VomLehn * aQuantia Corporation Network Driver 3c5760d03SDavid VomLehn * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved 4c5760d03SDavid VomLehn * 5c5760d03SDavid VomLehn * This program is free software; you can redistribute it and/or modify it 6c5760d03SDavid VomLehn * under the terms and conditions of the GNU General Public License, 7c5760d03SDavid VomLehn * version 2, as published by the Free Software Foundation. 8c5760d03SDavid VomLehn */ 9c5760d03SDavid VomLehn 10c5760d03SDavid VomLehn /* File aq_ethtool.c: Definition of ethertool related functions. */ 11c5760d03SDavid VomLehn 12c5760d03SDavid VomLehn #include "aq_ethtool.h" 13c5760d03SDavid VomLehn #include "aq_nic.h" 14c1af5427SAnton Mikaev #include "aq_vec.h" 158d0bcb01SDmitry Bogdanov #include "aq_filters.h" 16c5760d03SDavid VomLehn 17c5760d03SDavid VomLehn static void aq_ethtool_get_regs(struct net_device *ndev, 18c5760d03SDavid VomLehn struct ethtool_regs *regs, void *p) 19c5760d03SDavid VomLehn { 20c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 21c5760d03SDavid VomLehn u32 regs_count = aq_nic_get_regs_count(aq_nic); 22c5760d03SDavid VomLehn 23c5760d03SDavid VomLehn memset(p, 0, regs_count * sizeof(u32)); 24c5760d03SDavid VomLehn aq_nic_get_regs(aq_nic, regs, p); 25c5760d03SDavid VomLehn } 26c5760d03SDavid VomLehn 27c5760d03SDavid VomLehn static int aq_ethtool_get_regs_len(struct net_device *ndev) 28c5760d03SDavid VomLehn { 29c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 30c5760d03SDavid VomLehn u32 regs_count = aq_nic_get_regs_count(aq_nic); 31c5760d03SDavid VomLehn 32c5760d03SDavid VomLehn return regs_count * sizeof(u32); 33c5760d03SDavid VomLehn } 34c5760d03SDavid VomLehn 35c5760d03SDavid VomLehn static u32 aq_ethtool_get_link(struct net_device *ndev) 36c5760d03SDavid VomLehn { 37c5760d03SDavid VomLehn return ethtool_op_get_link(ndev); 38c5760d03SDavid VomLehn } 39c5760d03SDavid VomLehn 40f8244ab5SPhilippe Reynes static int aq_ethtool_get_link_ksettings(struct net_device *ndev, 41f8244ab5SPhilippe Reynes struct ethtool_link_ksettings *cmd) 42c5760d03SDavid VomLehn { 43c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 44c5760d03SDavid VomLehn 45f8244ab5SPhilippe Reynes aq_nic_get_link_ksettings(aq_nic, cmd); 46f8244ab5SPhilippe Reynes cmd->base.speed = netif_carrier_ok(ndev) ? 47f8244ab5SPhilippe Reynes aq_nic_get_link_speed(aq_nic) : 0U; 48c5760d03SDavid VomLehn 49c5760d03SDavid VomLehn return 0; 50c5760d03SDavid VomLehn } 51c5760d03SDavid VomLehn 52f8244ab5SPhilippe Reynes static int 53f8244ab5SPhilippe Reynes aq_ethtool_set_link_ksettings(struct net_device *ndev, 54f8244ab5SPhilippe Reynes const struct ethtool_link_ksettings *cmd) 55c5760d03SDavid VomLehn { 56c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 57c5760d03SDavid VomLehn 58f8244ab5SPhilippe Reynes return aq_nic_set_link_ksettings(aq_nic, cmd); 59c5760d03SDavid VomLehn } 60c5760d03SDavid VomLehn 61c5760d03SDavid VomLehn static const char aq_ethtool_stat_names[][ETH_GSTRING_LEN] = { 62c5760d03SDavid VomLehn "InPackets", 63c5760d03SDavid VomLehn "InUCast", 64c5760d03SDavid VomLehn "InMCast", 65c5760d03SDavid VomLehn "InBCast", 66c5760d03SDavid VomLehn "InErrors", 67c5760d03SDavid VomLehn "OutPackets", 68c5760d03SDavid VomLehn "OutUCast", 69c5760d03SDavid VomLehn "OutMCast", 70c5760d03SDavid VomLehn "OutBCast", 7198bc036dSIgor Russkikh "InUCastOctets", 7298bc036dSIgor Russkikh "OutUCastOctets", 7398bc036dSIgor Russkikh "InMCastOctets", 7498bc036dSIgor Russkikh "OutMCastOctets", 7598bc036dSIgor Russkikh "InBCastOctets", 7698bc036dSIgor Russkikh "OutBCastOctets", 7798bc036dSIgor Russkikh "InOctets", 7898bc036dSIgor Russkikh "OutOctets", 79c5760d03SDavid VomLehn "InPacketsDma", 80c5760d03SDavid VomLehn "OutPacketsDma", 81c5760d03SDavid VomLehn "InOctetsDma", 82c5760d03SDavid VomLehn "OutOctetsDma", 83c5760d03SDavid VomLehn "InDroppedDma", 845d8d84e9SIgor Russkikh }; 855d8d84e9SIgor Russkikh 865d8d84e9SIgor Russkikh static const char aq_ethtool_queue_stat_names[][ETH_GSTRING_LEN] = { 875d8d84e9SIgor Russkikh "Queue[%d] InPackets", 885d8d84e9SIgor Russkikh "Queue[%d] OutPackets", 895d8d84e9SIgor Russkikh "Queue[%d] Restarts", 905d8d84e9SIgor Russkikh "Queue[%d] InJumboPackets", 915d8d84e9SIgor Russkikh "Queue[%d] InLroPackets", 925d8d84e9SIgor Russkikh "Queue[%d] InErrors", 93c5760d03SDavid VomLehn }; 94c5760d03SDavid VomLehn 95c5760d03SDavid VomLehn static void aq_ethtool_stats(struct net_device *ndev, 96c5760d03SDavid VomLehn struct ethtool_stats *stats, u64 *data) 97c5760d03SDavid VomLehn { 98c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 995d8d84e9SIgor Russkikh struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 100c5760d03SDavid VomLehn 1015d8d84e9SIgor Russkikh memset(data, 0, (ARRAY_SIZE(aq_ethtool_stat_names) + 1025d8d84e9SIgor Russkikh ARRAY_SIZE(aq_ethtool_queue_stat_names) * 1035d8d84e9SIgor Russkikh cfg->vecs) * sizeof(u64)); 104c5760d03SDavid VomLehn aq_nic_get_stats(aq_nic, data); 105c5760d03SDavid VomLehn } 106c5760d03SDavid VomLehn 107c5760d03SDavid VomLehn static void aq_ethtool_get_drvinfo(struct net_device *ndev, 108c5760d03SDavid VomLehn struct ethtool_drvinfo *drvinfo) 109c5760d03SDavid VomLehn { 110c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 111c5760d03SDavid VomLehn struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 112c5760d03SDavid VomLehn struct pci_dev *pdev = to_pci_dev(ndev->dev.parent); 113c5760d03SDavid VomLehn u32 firmware_version = aq_nic_get_fw_version(aq_nic); 114c5760d03SDavid VomLehn u32 regs_count = aq_nic_get_regs_count(aq_nic); 115c5760d03SDavid VomLehn 116c5760d03SDavid VomLehn strlcat(drvinfo->driver, AQ_CFG_DRV_NAME, sizeof(drvinfo->driver)); 117c5760d03SDavid VomLehn strlcat(drvinfo->version, AQ_CFG_DRV_VERSION, sizeof(drvinfo->version)); 118c5760d03SDavid VomLehn 119c5760d03SDavid VomLehn snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), 120c5760d03SDavid VomLehn "%u.%u.%u", firmware_version >> 24, 121c5760d03SDavid VomLehn (firmware_version >> 16) & 0xFFU, firmware_version & 0xFFFFU); 122c5760d03SDavid VomLehn 123c5760d03SDavid VomLehn strlcpy(drvinfo->bus_info, pdev ? pci_name(pdev) : "", 124c5760d03SDavid VomLehn sizeof(drvinfo->bus_info)); 1255d8d84e9SIgor Russkikh drvinfo->n_stats = ARRAY_SIZE(aq_ethtool_stat_names) + 1265d8d84e9SIgor Russkikh cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names); 127c5760d03SDavid VomLehn drvinfo->testinfo_len = 0; 128c5760d03SDavid VomLehn drvinfo->regdump_len = regs_count; 129c5760d03SDavid VomLehn drvinfo->eedump_len = 0; 130c5760d03SDavid VomLehn } 131c5760d03SDavid VomLehn 132c5760d03SDavid VomLehn static void aq_ethtool_get_strings(struct net_device *ndev, 133c5760d03SDavid VomLehn u32 stringset, u8 *data) 134c5760d03SDavid VomLehn { 1355d8d84e9SIgor Russkikh int i, si; 136c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 137c5760d03SDavid VomLehn struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 1385d8d84e9SIgor Russkikh u8 *p = data; 139c5760d03SDavid VomLehn 1405d8d84e9SIgor Russkikh if (stringset == ETH_SS_STATS) { 141ff83dbf2SNikita Danilov memcpy(p, aq_ethtool_stat_names, 1425d8d84e9SIgor Russkikh sizeof(aq_ethtool_stat_names)); 1435d8d84e9SIgor Russkikh p = p + sizeof(aq_ethtool_stat_names); 1445d8d84e9SIgor Russkikh for (i = 0; i < cfg->vecs; i++) { 1455d8d84e9SIgor Russkikh for (si = 0; 1465d8d84e9SIgor Russkikh si < ARRAY_SIZE(aq_ethtool_queue_stat_names); 1475d8d84e9SIgor Russkikh si++) { 1485d8d84e9SIgor Russkikh snprintf(p, ETH_GSTRING_LEN, 1495d8d84e9SIgor Russkikh aq_ethtool_queue_stat_names[si], i); 1505d8d84e9SIgor Russkikh p += ETH_GSTRING_LEN; 1515d8d84e9SIgor Russkikh } 1525d8d84e9SIgor Russkikh } 1535d8d84e9SIgor Russkikh } 154c5760d03SDavid VomLehn } 155c5760d03SDavid VomLehn 156c5760d03SDavid VomLehn static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset) 157c5760d03SDavid VomLehn { 158c5760d03SDavid VomLehn int ret = 0; 159c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 160c5760d03SDavid VomLehn struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 161c5760d03SDavid VomLehn 162c5760d03SDavid VomLehn switch (stringset) { 163c5760d03SDavid VomLehn case ETH_SS_STATS: 1645d8d84e9SIgor Russkikh ret = ARRAY_SIZE(aq_ethtool_stat_names) + 1655d8d84e9SIgor Russkikh cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names); 166c5760d03SDavid VomLehn break; 167c5760d03SDavid VomLehn default: 168c5760d03SDavid VomLehn ret = -EOPNOTSUPP; 169c5760d03SDavid VomLehn } 170c5760d03SDavid VomLehn return ret; 171c5760d03SDavid VomLehn } 172c5760d03SDavid VomLehn 173c5760d03SDavid VomLehn static u32 aq_ethtool_get_rss_indir_size(struct net_device *ndev) 174c5760d03SDavid VomLehn { 175c5760d03SDavid VomLehn return AQ_CFG_RSS_INDIRECTION_TABLE_MAX; 176c5760d03SDavid VomLehn } 177c5760d03SDavid VomLehn 178c5760d03SDavid VomLehn static u32 aq_ethtool_get_rss_key_size(struct net_device *ndev) 179c5760d03SDavid VomLehn { 180c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 181c5760d03SDavid VomLehn struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 182c5760d03SDavid VomLehn 183c5760d03SDavid VomLehn return sizeof(cfg->aq_rss.hash_secret_key); 184c5760d03SDavid VomLehn } 185c5760d03SDavid VomLehn 186c5760d03SDavid VomLehn static int aq_ethtool_get_rss(struct net_device *ndev, u32 *indir, u8 *key, 187c5760d03SDavid VomLehn u8 *hfunc) 188c5760d03SDavid VomLehn { 189c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 190c5760d03SDavid VomLehn struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 191c5760d03SDavid VomLehn unsigned int i = 0U; 192c5760d03SDavid VomLehn 193c5760d03SDavid VomLehn if (hfunc) 194c5760d03SDavid VomLehn *hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */ 195c5760d03SDavid VomLehn if (indir) { 196c5760d03SDavid VomLehn for (i = 0; i < AQ_CFG_RSS_INDIRECTION_TABLE_MAX; i++) 197c5760d03SDavid VomLehn indir[i] = cfg->aq_rss.indirection_table[i]; 198c5760d03SDavid VomLehn } 199c5760d03SDavid VomLehn if (key) 200c5760d03SDavid VomLehn memcpy(key, cfg->aq_rss.hash_secret_key, 201c5760d03SDavid VomLehn sizeof(cfg->aq_rss.hash_secret_key)); 202c5760d03SDavid VomLehn return 0; 203c5760d03SDavid VomLehn } 204c5760d03SDavid VomLehn 20539163767SDmitry Bogdanov static int aq_ethtool_set_rss(struct net_device *netdev, const u32 *indir, 20639163767SDmitry Bogdanov const u8 *key, const u8 hfunc) 20739163767SDmitry Bogdanov { 20839163767SDmitry Bogdanov struct aq_nic_s *aq_nic = netdev_priv(netdev); 20939163767SDmitry Bogdanov struct aq_nic_cfg_s *cfg; 21039163767SDmitry Bogdanov unsigned int i = 0U; 21139163767SDmitry Bogdanov u32 rss_entries; 21239163767SDmitry Bogdanov int err = 0; 21339163767SDmitry Bogdanov 21439163767SDmitry Bogdanov cfg = aq_nic_get_cfg(aq_nic); 21539163767SDmitry Bogdanov rss_entries = cfg->aq_rss.indirection_table_size; 21639163767SDmitry Bogdanov 21739163767SDmitry Bogdanov /* We do not allow change in unsupported parameters */ 21839163767SDmitry Bogdanov if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 21939163767SDmitry Bogdanov return -EOPNOTSUPP; 22039163767SDmitry Bogdanov /* Fill out the redirection table */ 22139163767SDmitry Bogdanov if (indir) 22239163767SDmitry Bogdanov for (i = 0; i < rss_entries; i++) 22339163767SDmitry Bogdanov cfg->aq_rss.indirection_table[i] = indir[i]; 22439163767SDmitry Bogdanov 22539163767SDmitry Bogdanov /* Fill out the rss hash key */ 22639163767SDmitry Bogdanov if (key) { 22739163767SDmitry Bogdanov memcpy(cfg->aq_rss.hash_secret_key, key, 22839163767SDmitry Bogdanov sizeof(cfg->aq_rss.hash_secret_key)); 22939163767SDmitry Bogdanov err = aq_nic->aq_hw_ops->hw_rss_hash_set(aq_nic->aq_hw, 23039163767SDmitry Bogdanov &cfg->aq_rss); 23139163767SDmitry Bogdanov if (err) 23239163767SDmitry Bogdanov return err; 23339163767SDmitry Bogdanov } 23439163767SDmitry Bogdanov 23539163767SDmitry Bogdanov err = aq_nic->aq_hw_ops->hw_rss_set(aq_nic->aq_hw, &cfg->aq_rss); 23639163767SDmitry Bogdanov 23739163767SDmitry Bogdanov return err; 23839163767SDmitry Bogdanov } 23939163767SDmitry Bogdanov 240c5760d03SDavid VomLehn static int aq_ethtool_get_rxnfc(struct net_device *ndev, 241c5760d03SDavid VomLehn struct ethtool_rxnfc *cmd, 242c5760d03SDavid VomLehn u32 *rule_locs) 243c5760d03SDavid VomLehn { 244c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 245c5760d03SDavid VomLehn struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 246c5760d03SDavid VomLehn int err = 0; 247c5760d03SDavid VomLehn 248c5760d03SDavid VomLehn switch (cmd->cmd) { 249c5760d03SDavid VomLehn case ETHTOOL_GRXRINGS: 250c5760d03SDavid VomLehn cmd->data = cfg->vecs; 251c5760d03SDavid VomLehn break; 2528d0bcb01SDmitry Bogdanov case ETHTOOL_GRXCLSRLCNT: 2538d0bcb01SDmitry Bogdanov cmd->rule_cnt = aq_get_rxnfc_count_all_rules(aq_nic); 2548d0bcb01SDmitry Bogdanov break; 2558d0bcb01SDmitry Bogdanov case ETHTOOL_GRXCLSRULE: 2568d0bcb01SDmitry Bogdanov err = aq_get_rxnfc_rule(aq_nic, cmd); 2578d0bcb01SDmitry Bogdanov break; 2588d0bcb01SDmitry Bogdanov case ETHTOOL_GRXCLSRLALL: 2598d0bcb01SDmitry Bogdanov err = aq_get_rxnfc_all_rules(aq_nic, cmd, rule_locs); 2608d0bcb01SDmitry Bogdanov break; 2618d0bcb01SDmitry Bogdanov default: 2628d0bcb01SDmitry Bogdanov err = -EOPNOTSUPP; 2638d0bcb01SDmitry Bogdanov break; 2648d0bcb01SDmitry Bogdanov } 265c5760d03SDavid VomLehn 2668d0bcb01SDmitry Bogdanov return err; 2678d0bcb01SDmitry Bogdanov } 2688d0bcb01SDmitry Bogdanov 2698d0bcb01SDmitry Bogdanov static int aq_ethtool_set_rxnfc(struct net_device *ndev, 2708d0bcb01SDmitry Bogdanov struct ethtool_rxnfc *cmd) 2718d0bcb01SDmitry Bogdanov { 2728d0bcb01SDmitry Bogdanov int err = 0; 2738d0bcb01SDmitry Bogdanov struct aq_nic_s *aq_nic = netdev_priv(ndev); 2748d0bcb01SDmitry Bogdanov 2758d0bcb01SDmitry Bogdanov switch (cmd->cmd) { 2768d0bcb01SDmitry Bogdanov case ETHTOOL_SRXCLSRLINS: 2778d0bcb01SDmitry Bogdanov err = aq_add_rxnfc_rule(aq_nic, cmd); 2788d0bcb01SDmitry Bogdanov break; 2798d0bcb01SDmitry Bogdanov case ETHTOOL_SRXCLSRLDEL: 2808d0bcb01SDmitry Bogdanov err = aq_del_rxnfc_rule(aq_nic, cmd); 2818d0bcb01SDmitry Bogdanov break; 282c5760d03SDavid VomLehn default: 283c5760d03SDavid VomLehn err = -EOPNOTSUPP; 284c5760d03SDavid VomLehn break; 285c5760d03SDavid VomLehn } 286c5760d03SDavid VomLehn 287c5760d03SDavid VomLehn return err; 288c5760d03SDavid VomLehn } 289c5760d03SDavid VomLehn 2902660d226SWei Yongjun static int aq_ethtool_get_coalesce(struct net_device *ndev, 291b82ee71aSIgor Russkikh struct ethtool_coalesce *coal) 292b82ee71aSIgor Russkikh { 293b82ee71aSIgor Russkikh struct aq_nic_s *aq_nic = netdev_priv(ndev); 294b82ee71aSIgor Russkikh struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 295b82ee71aSIgor Russkikh 296b82ee71aSIgor Russkikh if (cfg->itr == AQ_CFG_INTERRUPT_MODERATION_ON || 297b82ee71aSIgor Russkikh cfg->itr == AQ_CFG_INTERRUPT_MODERATION_AUTO) { 298b82ee71aSIgor Russkikh coal->rx_coalesce_usecs = cfg->rx_itr; 299b82ee71aSIgor Russkikh coal->tx_coalesce_usecs = cfg->tx_itr; 300b82ee71aSIgor Russkikh coal->rx_max_coalesced_frames = 0; 301b82ee71aSIgor Russkikh coal->tx_max_coalesced_frames = 0; 302b82ee71aSIgor Russkikh } else { 303b82ee71aSIgor Russkikh coal->rx_coalesce_usecs = 0; 304b82ee71aSIgor Russkikh coal->tx_coalesce_usecs = 0; 305b82ee71aSIgor Russkikh coal->rx_max_coalesced_frames = 1; 306b82ee71aSIgor Russkikh coal->tx_max_coalesced_frames = 1; 307b82ee71aSIgor Russkikh } 308b82ee71aSIgor Russkikh return 0; 309b82ee71aSIgor Russkikh } 310b82ee71aSIgor Russkikh 3112660d226SWei Yongjun static int aq_ethtool_set_coalesce(struct net_device *ndev, 312b82ee71aSIgor Russkikh struct ethtool_coalesce *coal) 313b82ee71aSIgor Russkikh { 314b82ee71aSIgor Russkikh struct aq_nic_s *aq_nic = netdev_priv(ndev); 315b82ee71aSIgor Russkikh struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 316b82ee71aSIgor Russkikh 317b82ee71aSIgor Russkikh /* This is not yet supported 318b82ee71aSIgor Russkikh */ 319b82ee71aSIgor Russkikh if (coal->use_adaptive_rx_coalesce || coal->use_adaptive_tx_coalesce) 320b82ee71aSIgor Russkikh return -EOPNOTSUPP; 321b82ee71aSIgor Russkikh 322b82ee71aSIgor Russkikh /* Atlantic only supports timing based coalescing 323b82ee71aSIgor Russkikh */ 324b82ee71aSIgor Russkikh if (coal->rx_max_coalesced_frames > 1 || 325b82ee71aSIgor Russkikh coal->rx_coalesce_usecs_irq || 326b82ee71aSIgor Russkikh coal->rx_max_coalesced_frames_irq) 327b82ee71aSIgor Russkikh return -EOPNOTSUPP; 328b82ee71aSIgor Russkikh 329b82ee71aSIgor Russkikh if (coal->tx_max_coalesced_frames > 1 || 330b82ee71aSIgor Russkikh coal->tx_coalesce_usecs_irq || 331b82ee71aSIgor Russkikh coal->tx_max_coalesced_frames_irq) 332b82ee71aSIgor Russkikh return -EOPNOTSUPP; 333b82ee71aSIgor Russkikh 334b82ee71aSIgor Russkikh /* We do not support frame counting. Check this 335b82ee71aSIgor Russkikh */ 336b82ee71aSIgor Russkikh if (!(coal->rx_max_coalesced_frames == !coal->rx_coalesce_usecs)) 337b82ee71aSIgor Russkikh return -EOPNOTSUPP; 338b82ee71aSIgor Russkikh if (!(coal->tx_max_coalesced_frames == !coal->tx_coalesce_usecs)) 339b82ee71aSIgor Russkikh return -EOPNOTSUPP; 340b82ee71aSIgor Russkikh 341b82ee71aSIgor Russkikh if (coal->rx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX || 342b82ee71aSIgor Russkikh coal->tx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX) 343b82ee71aSIgor Russkikh return -EINVAL; 344b82ee71aSIgor Russkikh 345b82ee71aSIgor Russkikh cfg->itr = AQ_CFG_INTERRUPT_MODERATION_ON; 346b82ee71aSIgor Russkikh 347b82ee71aSIgor Russkikh cfg->rx_itr = coal->rx_coalesce_usecs; 348b82ee71aSIgor Russkikh cfg->tx_itr = coal->tx_coalesce_usecs; 349b82ee71aSIgor Russkikh 350b82ee71aSIgor Russkikh return aq_nic_update_interrupt_moderation_settings(aq_nic); 351b82ee71aSIgor Russkikh } 352b82ee71aSIgor Russkikh 353a0da96c0SYana Esina static void aq_ethtool_get_wol(struct net_device *ndev, 354a0da96c0SYana Esina struct ethtool_wolinfo *wol) 355a0da96c0SYana Esina { 356a0da96c0SYana Esina struct aq_nic_s *aq_nic = netdev_priv(ndev); 357a0da96c0SYana Esina struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 358a0da96c0SYana Esina 359a0da96c0SYana Esina wol->supported = WAKE_MAGIC; 360a0da96c0SYana Esina wol->wolopts = 0; 361a0da96c0SYana Esina 362a0da96c0SYana Esina if (cfg->wol) 363a0da96c0SYana Esina wol->wolopts |= WAKE_MAGIC; 364a0da96c0SYana Esina } 365a0da96c0SYana Esina 366a0da96c0SYana Esina static int aq_ethtool_set_wol(struct net_device *ndev, 367a0da96c0SYana Esina struct ethtool_wolinfo *wol) 368a0da96c0SYana Esina { 369a0da96c0SYana Esina struct pci_dev *pdev = to_pci_dev(ndev->dev.parent); 370a0da96c0SYana Esina struct aq_nic_s *aq_nic = netdev_priv(ndev); 371a0da96c0SYana Esina struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 372a0da96c0SYana Esina int err = 0; 373a0da96c0SYana Esina 374a0da96c0SYana Esina if (wol->wolopts & WAKE_MAGIC) 375a0da96c0SYana Esina cfg->wol |= AQ_NIC_WOL_ENABLED; 376a0da96c0SYana Esina else 377a0da96c0SYana Esina cfg->wol &= ~AQ_NIC_WOL_ENABLED; 378a0da96c0SYana Esina err = device_set_wakeup_enable(&pdev->dev, wol->wolopts); 379a0da96c0SYana Esina 380a0da96c0SYana Esina return err; 381a0da96c0SYana Esina } 382a0da96c0SYana Esina 38392ab6407SYana Esina static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed) 38492ab6407SYana Esina { 38592ab6407SYana Esina u32 rate = 0; 38692ab6407SYana Esina 38792ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_10G) 38892ab6407SYana Esina rate |= SUPPORTED_10000baseT_Full; 38992ab6407SYana Esina 39092ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_2GS) 39192ab6407SYana Esina rate |= SUPPORTED_2500baseX_Full; 39292ab6407SYana Esina 39392ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_1G) 39492ab6407SYana Esina rate |= SUPPORTED_1000baseT_Full; 39592ab6407SYana Esina 39692ab6407SYana Esina return rate; 39792ab6407SYana Esina } 39892ab6407SYana Esina 39992ab6407SYana Esina static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee) 40092ab6407SYana Esina { 40192ab6407SYana Esina struct aq_nic_s *aq_nic = netdev_priv(ndev); 40292ab6407SYana Esina u32 rate, supported_rates; 40392ab6407SYana Esina int err = 0; 40492ab6407SYana Esina 40592ab6407SYana Esina if (!aq_nic->aq_fw_ops->get_eee_rate) 40692ab6407SYana Esina return -EOPNOTSUPP; 40792ab6407SYana Esina 40892ab6407SYana Esina err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate, 40992ab6407SYana Esina &supported_rates); 41092ab6407SYana Esina if (err < 0) 41192ab6407SYana Esina return err; 41292ab6407SYana Esina 41392ab6407SYana Esina eee->supported = eee_mask_to_ethtool_mask(supported_rates); 41492ab6407SYana Esina 41592ab6407SYana Esina if (aq_nic->aq_nic_cfg.eee_speeds) 41692ab6407SYana Esina eee->advertised = eee->supported; 41792ab6407SYana Esina 41892ab6407SYana Esina eee->lp_advertised = eee_mask_to_ethtool_mask(rate); 41992ab6407SYana Esina 42092ab6407SYana Esina eee->eee_enabled = !!eee->advertised; 42192ab6407SYana Esina 42292ab6407SYana Esina eee->tx_lpi_enabled = eee->eee_enabled; 42392ab6407SYana Esina if (eee->advertised & eee->lp_advertised) 42492ab6407SYana Esina eee->eee_active = true; 42592ab6407SYana Esina 42692ab6407SYana Esina return 0; 42792ab6407SYana Esina } 42892ab6407SYana Esina 42992ab6407SYana Esina static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee) 43092ab6407SYana Esina { 43192ab6407SYana Esina struct aq_nic_s *aq_nic = netdev_priv(ndev); 43292ab6407SYana Esina u32 rate, supported_rates; 43392ab6407SYana Esina struct aq_nic_cfg_s *cfg; 43492ab6407SYana Esina int err = 0; 43592ab6407SYana Esina 43692ab6407SYana Esina cfg = aq_nic_get_cfg(aq_nic); 43792ab6407SYana Esina 43892ab6407SYana Esina if (unlikely(!aq_nic->aq_fw_ops->get_eee_rate || 43992ab6407SYana Esina !aq_nic->aq_fw_ops->set_eee_rate)) 44092ab6407SYana Esina return -EOPNOTSUPP; 44192ab6407SYana Esina 44292ab6407SYana Esina err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate, 44392ab6407SYana Esina &supported_rates); 44492ab6407SYana Esina if (err < 0) 44592ab6407SYana Esina return err; 44692ab6407SYana Esina 44792ab6407SYana Esina if (eee->eee_enabled) { 44892ab6407SYana Esina rate = supported_rates; 44992ab6407SYana Esina cfg->eee_speeds = rate; 45092ab6407SYana Esina } else { 45192ab6407SYana Esina rate = 0; 45292ab6407SYana Esina cfg->eee_speeds = 0; 45392ab6407SYana Esina } 45492ab6407SYana Esina 45592ab6407SYana Esina return aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate); 45692ab6407SYana Esina } 45792ab6407SYana Esina 458b8d68b62SAnton Mikaev static int aq_ethtool_nway_reset(struct net_device *ndev) 459b8d68b62SAnton Mikaev { 460b8d68b62SAnton Mikaev struct aq_nic_s *aq_nic = netdev_priv(ndev); 461b8d68b62SAnton Mikaev 462b8d68b62SAnton Mikaev if (unlikely(!aq_nic->aq_fw_ops->renegotiate)) 463b8d68b62SAnton Mikaev return -EOPNOTSUPP; 464b8d68b62SAnton Mikaev 465b8d68b62SAnton Mikaev if (netif_running(ndev)) 466b8d68b62SAnton Mikaev return aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw); 467b8d68b62SAnton Mikaev 468b8d68b62SAnton Mikaev return 0; 469b8d68b62SAnton Mikaev } 470b8d68b62SAnton Mikaev 471288551deSIgor Russkikh static void aq_ethtool_get_pauseparam(struct net_device *ndev, 472288551deSIgor Russkikh struct ethtool_pauseparam *pause) 473288551deSIgor Russkikh { 474288551deSIgor Russkikh struct aq_nic_s *aq_nic = netdev_priv(ndev); 47535e8e8b4SIgor Russkikh u32 fc = aq_nic->aq_nic_cfg.flow_control; 476288551deSIgor Russkikh 477288551deSIgor Russkikh pause->autoneg = 0; 478288551deSIgor Russkikh 47935e8e8b4SIgor Russkikh pause->rx_pause = !!(fc & AQ_NIC_FC_RX); 48035e8e8b4SIgor Russkikh pause->tx_pause = !!(fc & AQ_NIC_FC_TX); 48135e8e8b4SIgor Russkikh 482288551deSIgor Russkikh } 483288551deSIgor Russkikh 484288551deSIgor Russkikh static int aq_ethtool_set_pauseparam(struct net_device *ndev, 485288551deSIgor Russkikh struct ethtool_pauseparam *pause) 486288551deSIgor Russkikh { 487288551deSIgor Russkikh struct aq_nic_s *aq_nic = netdev_priv(ndev); 488288551deSIgor Russkikh int err = 0; 489288551deSIgor Russkikh 490288551deSIgor Russkikh if (!aq_nic->aq_fw_ops->set_flow_control) 491288551deSIgor Russkikh return -EOPNOTSUPP; 492288551deSIgor Russkikh 493288551deSIgor Russkikh if (pause->autoneg == AUTONEG_ENABLE) 494288551deSIgor Russkikh return -EOPNOTSUPP; 495288551deSIgor Russkikh 496288551deSIgor Russkikh if (pause->rx_pause) 497288551deSIgor Russkikh aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_RX; 498288551deSIgor Russkikh else 499288551deSIgor Russkikh aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_RX; 500288551deSIgor Russkikh 501288551deSIgor Russkikh if (pause->tx_pause) 502288551deSIgor Russkikh aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_TX; 503288551deSIgor Russkikh else 504288551deSIgor Russkikh aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX; 505288551deSIgor Russkikh 506288551deSIgor Russkikh err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw); 507288551deSIgor Russkikh 508288551deSIgor Russkikh return err; 509288551deSIgor Russkikh } 510288551deSIgor Russkikh 511c1af5427SAnton Mikaev static void aq_get_ringparam(struct net_device *ndev, 512c1af5427SAnton Mikaev struct ethtool_ringparam *ring) 513c1af5427SAnton Mikaev { 514c1af5427SAnton Mikaev struct aq_nic_s *aq_nic = netdev_priv(ndev); 515c1af5427SAnton Mikaev struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic); 516c1af5427SAnton Mikaev 517c1af5427SAnton Mikaev ring->rx_pending = aq_nic_cfg->rxds; 518c1af5427SAnton Mikaev ring->tx_pending = aq_nic_cfg->txds; 519c1af5427SAnton Mikaev 520c1af5427SAnton Mikaev ring->rx_max_pending = aq_nic_cfg->aq_hw_caps->rxds_max; 521c1af5427SAnton Mikaev ring->tx_max_pending = aq_nic_cfg->aq_hw_caps->txds_max; 522c1af5427SAnton Mikaev } 523c1af5427SAnton Mikaev 524c1af5427SAnton Mikaev static int aq_set_ringparam(struct net_device *ndev, 525c1af5427SAnton Mikaev struct ethtool_ringparam *ring) 526c1af5427SAnton Mikaev { 527c1af5427SAnton Mikaev int err = 0; 528c1af5427SAnton Mikaev bool ndev_running = false; 529c1af5427SAnton Mikaev struct aq_nic_s *aq_nic = netdev_priv(ndev); 530c1af5427SAnton Mikaev struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic); 531c1af5427SAnton Mikaev const struct aq_hw_caps_s *hw_caps = aq_nic_cfg->aq_hw_caps; 532c1af5427SAnton Mikaev 533c1af5427SAnton Mikaev if (ring->rx_mini_pending || ring->rx_jumbo_pending) { 534c1af5427SAnton Mikaev err = -EOPNOTSUPP; 535c1af5427SAnton Mikaev goto err_exit; 536c1af5427SAnton Mikaev } 537c1af5427SAnton Mikaev 538c1af5427SAnton Mikaev if (netif_running(ndev)) { 539c1af5427SAnton Mikaev ndev_running = true; 540c1af5427SAnton Mikaev dev_close(ndev); 541c1af5427SAnton Mikaev } 542c1af5427SAnton Mikaev 543c1af5427SAnton Mikaev aq_nic_free_vectors(aq_nic); 544c1af5427SAnton Mikaev 545c1af5427SAnton Mikaev aq_nic_cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min); 546c1af5427SAnton Mikaev aq_nic_cfg->rxds = min(aq_nic_cfg->rxds, hw_caps->rxds_max); 547c1af5427SAnton Mikaev aq_nic_cfg->rxds = ALIGN(aq_nic_cfg->rxds, AQ_HW_RXD_MULTIPLE); 548c1af5427SAnton Mikaev 549c1af5427SAnton Mikaev aq_nic_cfg->txds = max(ring->tx_pending, hw_caps->txds_min); 550c1af5427SAnton Mikaev aq_nic_cfg->txds = min(aq_nic_cfg->txds, hw_caps->txds_max); 551c1af5427SAnton Mikaev aq_nic_cfg->txds = ALIGN(aq_nic_cfg->txds, AQ_HW_TXD_MULTIPLE); 552c1af5427SAnton Mikaev 553c1af5427SAnton Mikaev for (aq_nic->aq_vecs = 0; aq_nic->aq_vecs < aq_nic_cfg->vecs; 554c1af5427SAnton Mikaev aq_nic->aq_vecs++) { 555c1af5427SAnton Mikaev aq_nic->aq_vec[aq_nic->aq_vecs] = 556c1af5427SAnton Mikaev aq_vec_alloc(aq_nic, aq_nic->aq_vecs, aq_nic_cfg); 557c1af5427SAnton Mikaev if (unlikely(!aq_nic->aq_vec[aq_nic->aq_vecs])) { 558c1af5427SAnton Mikaev err = -ENOMEM; 559c1af5427SAnton Mikaev goto err_exit; 560c1af5427SAnton Mikaev } 561c1af5427SAnton Mikaev } 562c1af5427SAnton Mikaev if (ndev_running) 56300f54e68SPetr Machata err = dev_open(ndev, NULL); 564c1af5427SAnton Mikaev 565c1af5427SAnton Mikaev err_exit: 566c1af5427SAnton Mikaev return err; 567c1af5427SAnton Mikaev } 568c1af5427SAnton Mikaev 569c5760d03SDavid VomLehn const struct ethtool_ops aq_ethtool_ops = { 570c5760d03SDavid VomLehn .get_link = aq_ethtool_get_link, 571c5760d03SDavid VomLehn .get_regs_len = aq_ethtool_get_regs_len, 572c5760d03SDavid VomLehn .get_regs = aq_ethtool_get_regs, 573c5760d03SDavid VomLehn .get_drvinfo = aq_ethtool_get_drvinfo, 574c5760d03SDavid VomLehn .get_strings = aq_ethtool_get_strings, 575c5760d03SDavid VomLehn .get_rxfh_indir_size = aq_ethtool_get_rss_indir_size, 576a0da96c0SYana Esina .get_wol = aq_ethtool_get_wol, 577a0da96c0SYana Esina .set_wol = aq_ethtool_set_wol, 578b8d68b62SAnton Mikaev .nway_reset = aq_ethtool_nway_reset, 579c1af5427SAnton Mikaev .get_ringparam = aq_get_ringparam, 580c1af5427SAnton Mikaev .set_ringparam = aq_set_ringparam, 58192ab6407SYana Esina .get_eee = aq_ethtool_get_eee, 58292ab6407SYana Esina .set_eee = aq_ethtool_set_eee, 583288551deSIgor Russkikh .get_pauseparam = aq_ethtool_get_pauseparam, 584288551deSIgor Russkikh .set_pauseparam = aq_ethtool_set_pauseparam, 585c5760d03SDavid VomLehn .get_rxfh_key_size = aq_ethtool_get_rss_key_size, 586c5760d03SDavid VomLehn .get_rxfh = aq_ethtool_get_rss, 58739163767SDmitry Bogdanov .set_rxfh = aq_ethtool_set_rss, 588c5760d03SDavid VomLehn .get_rxnfc = aq_ethtool_get_rxnfc, 5898d0bcb01SDmitry Bogdanov .set_rxnfc = aq_ethtool_set_rxnfc, 590c5760d03SDavid VomLehn .get_sset_count = aq_ethtool_get_sset_count, 591f8244ab5SPhilippe Reynes .get_ethtool_stats = aq_ethtool_stats, 592f8244ab5SPhilippe Reynes .get_link_ksettings = aq_ethtool_get_link_ksettings, 593f8244ab5SPhilippe Reynes .set_link_ksettings = aq_ethtool_set_link_ksettings, 594b82ee71aSIgor Russkikh .get_coalesce = aq_ethtool_get_coalesce, 595b82ee71aSIgor Russkikh .set_coalesce = aq_ethtool_set_coalesce, 596c5760d03SDavid VomLehn }; 597