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) { 1415d8d84e9SIgor Russkikh 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 205c5760d03SDavid VomLehn static int aq_ethtool_get_rxnfc(struct net_device *ndev, 206c5760d03SDavid VomLehn struct ethtool_rxnfc *cmd, 207c5760d03SDavid VomLehn u32 *rule_locs) 208c5760d03SDavid VomLehn { 209c5760d03SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev); 210c5760d03SDavid VomLehn struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 211c5760d03SDavid VomLehn int err = 0; 212c5760d03SDavid VomLehn 213c5760d03SDavid VomLehn switch (cmd->cmd) { 214c5760d03SDavid VomLehn case ETHTOOL_GRXRINGS: 215c5760d03SDavid VomLehn cmd->data = cfg->vecs; 216c5760d03SDavid VomLehn break; 2178d0bcb01SDmitry Bogdanov case ETHTOOL_GRXCLSRLCNT: 2188d0bcb01SDmitry Bogdanov cmd->rule_cnt = aq_get_rxnfc_count_all_rules(aq_nic); 2198d0bcb01SDmitry Bogdanov break; 2208d0bcb01SDmitry Bogdanov case ETHTOOL_GRXCLSRULE: 2218d0bcb01SDmitry Bogdanov err = aq_get_rxnfc_rule(aq_nic, cmd); 2228d0bcb01SDmitry Bogdanov break; 2238d0bcb01SDmitry Bogdanov case ETHTOOL_GRXCLSRLALL: 2248d0bcb01SDmitry Bogdanov err = aq_get_rxnfc_all_rules(aq_nic, cmd, rule_locs); 2258d0bcb01SDmitry Bogdanov break; 2268d0bcb01SDmitry Bogdanov default: 2278d0bcb01SDmitry Bogdanov err = -EOPNOTSUPP; 2288d0bcb01SDmitry Bogdanov break; 2298d0bcb01SDmitry Bogdanov } 230c5760d03SDavid VomLehn 2318d0bcb01SDmitry Bogdanov return err; 2328d0bcb01SDmitry Bogdanov } 2338d0bcb01SDmitry Bogdanov 2348d0bcb01SDmitry Bogdanov static int aq_ethtool_set_rxnfc(struct net_device *ndev, 2358d0bcb01SDmitry Bogdanov struct ethtool_rxnfc *cmd) 2368d0bcb01SDmitry Bogdanov { 2378d0bcb01SDmitry Bogdanov int err = 0; 2388d0bcb01SDmitry Bogdanov struct aq_nic_s *aq_nic = netdev_priv(ndev); 2398d0bcb01SDmitry Bogdanov 2408d0bcb01SDmitry Bogdanov switch (cmd->cmd) { 2418d0bcb01SDmitry Bogdanov case ETHTOOL_SRXCLSRLINS: 2428d0bcb01SDmitry Bogdanov err = aq_add_rxnfc_rule(aq_nic, cmd); 2438d0bcb01SDmitry Bogdanov break; 2448d0bcb01SDmitry Bogdanov case ETHTOOL_SRXCLSRLDEL: 2458d0bcb01SDmitry Bogdanov err = aq_del_rxnfc_rule(aq_nic, cmd); 2468d0bcb01SDmitry Bogdanov break; 247c5760d03SDavid VomLehn default: 248c5760d03SDavid VomLehn err = -EOPNOTSUPP; 249c5760d03SDavid VomLehn break; 250c5760d03SDavid VomLehn } 251c5760d03SDavid VomLehn 252c5760d03SDavid VomLehn return err; 253c5760d03SDavid VomLehn } 254c5760d03SDavid VomLehn 2552660d226SWei Yongjun static int aq_ethtool_get_coalesce(struct net_device *ndev, 256b82ee71aSIgor Russkikh struct ethtool_coalesce *coal) 257b82ee71aSIgor Russkikh { 258b82ee71aSIgor Russkikh struct aq_nic_s *aq_nic = netdev_priv(ndev); 259b82ee71aSIgor Russkikh struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 260b82ee71aSIgor Russkikh 261b82ee71aSIgor Russkikh if (cfg->itr == AQ_CFG_INTERRUPT_MODERATION_ON || 262b82ee71aSIgor Russkikh cfg->itr == AQ_CFG_INTERRUPT_MODERATION_AUTO) { 263b82ee71aSIgor Russkikh coal->rx_coalesce_usecs = cfg->rx_itr; 264b82ee71aSIgor Russkikh coal->tx_coalesce_usecs = cfg->tx_itr; 265b82ee71aSIgor Russkikh coal->rx_max_coalesced_frames = 0; 266b82ee71aSIgor Russkikh coal->tx_max_coalesced_frames = 0; 267b82ee71aSIgor Russkikh } else { 268b82ee71aSIgor Russkikh coal->rx_coalesce_usecs = 0; 269b82ee71aSIgor Russkikh coal->tx_coalesce_usecs = 0; 270b82ee71aSIgor Russkikh coal->rx_max_coalesced_frames = 1; 271b82ee71aSIgor Russkikh coal->tx_max_coalesced_frames = 1; 272b82ee71aSIgor Russkikh } 273b82ee71aSIgor Russkikh return 0; 274b82ee71aSIgor Russkikh } 275b82ee71aSIgor Russkikh 2762660d226SWei Yongjun static int aq_ethtool_set_coalesce(struct net_device *ndev, 277b82ee71aSIgor Russkikh struct ethtool_coalesce *coal) 278b82ee71aSIgor Russkikh { 279b82ee71aSIgor Russkikh struct aq_nic_s *aq_nic = netdev_priv(ndev); 280b82ee71aSIgor Russkikh struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 281b82ee71aSIgor Russkikh 282b82ee71aSIgor Russkikh /* This is not yet supported 283b82ee71aSIgor Russkikh */ 284b82ee71aSIgor Russkikh if (coal->use_adaptive_rx_coalesce || coal->use_adaptive_tx_coalesce) 285b82ee71aSIgor Russkikh return -EOPNOTSUPP; 286b82ee71aSIgor Russkikh 287b82ee71aSIgor Russkikh /* Atlantic only supports timing based coalescing 288b82ee71aSIgor Russkikh */ 289b82ee71aSIgor Russkikh if (coal->rx_max_coalesced_frames > 1 || 290b82ee71aSIgor Russkikh coal->rx_coalesce_usecs_irq || 291b82ee71aSIgor Russkikh coal->rx_max_coalesced_frames_irq) 292b82ee71aSIgor Russkikh return -EOPNOTSUPP; 293b82ee71aSIgor Russkikh 294b82ee71aSIgor Russkikh if (coal->tx_max_coalesced_frames > 1 || 295b82ee71aSIgor Russkikh coal->tx_coalesce_usecs_irq || 296b82ee71aSIgor Russkikh coal->tx_max_coalesced_frames_irq) 297b82ee71aSIgor Russkikh return -EOPNOTSUPP; 298b82ee71aSIgor Russkikh 299b82ee71aSIgor Russkikh /* We do not support frame counting. Check this 300b82ee71aSIgor Russkikh */ 301b82ee71aSIgor Russkikh if (!(coal->rx_max_coalesced_frames == !coal->rx_coalesce_usecs)) 302b82ee71aSIgor Russkikh return -EOPNOTSUPP; 303b82ee71aSIgor Russkikh if (!(coal->tx_max_coalesced_frames == !coal->tx_coalesce_usecs)) 304b82ee71aSIgor Russkikh return -EOPNOTSUPP; 305b82ee71aSIgor Russkikh 306b82ee71aSIgor Russkikh if (coal->rx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX || 307b82ee71aSIgor Russkikh coal->tx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX) 308b82ee71aSIgor Russkikh return -EINVAL; 309b82ee71aSIgor Russkikh 310b82ee71aSIgor Russkikh cfg->itr = AQ_CFG_INTERRUPT_MODERATION_ON; 311b82ee71aSIgor Russkikh 312b82ee71aSIgor Russkikh cfg->rx_itr = coal->rx_coalesce_usecs; 313b82ee71aSIgor Russkikh cfg->tx_itr = coal->tx_coalesce_usecs; 314b82ee71aSIgor Russkikh 315b82ee71aSIgor Russkikh return aq_nic_update_interrupt_moderation_settings(aq_nic); 316b82ee71aSIgor Russkikh } 317b82ee71aSIgor Russkikh 318a0da96c0SYana Esina static void aq_ethtool_get_wol(struct net_device *ndev, 319a0da96c0SYana Esina struct ethtool_wolinfo *wol) 320a0da96c0SYana Esina { 321a0da96c0SYana Esina struct aq_nic_s *aq_nic = netdev_priv(ndev); 322a0da96c0SYana Esina struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 323a0da96c0SYana Esina 324a0da96c0SYana Esina wol->supported = WAKE_MAGIC; 325a0da96c0SYana Esina wol->wolopts = 0; 326a0da96c0SYana Esina 327a0da96c0SYana Esina if (cfg->wol) 328a0da96c0SYana Esina wol->wolopts |= WAKE_MAGIC; 329a0da96c0SYana Esina } 330a0da96c0SYana Esina 331a0da96c0SYana Esina static int aq_ethtool_set_wol(struct net_device *ndev, 332a0da96c0SYana Esina struct ethtool_wolinfo *wol) 333a0da96c0SYana Esina { 334a0da96c0SYana Esina struct pci_dev *pdev = to_pci_dev(ndev->dev.parent); 335a0da96c0SYana Esina struct aq_nic_s *aq_nic = netdev_priv(ndev); 336a0da96c0SYana Esina struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); 337a0da96c0SYana Esina int err = 0; 338a0da96c0SYana Esina 339a0da96c0SYana Esina if (wol->wolopts & WAKE_MAGIC) 340a0da96c0SYana Esina cfg->wol |= AQ_NIC_WOL_ENABLED; 341a0da96c0SYana Esina else 342a0da96c0SYana Esina cfg->wol &= ~AQ_NIC_WOL_ENABLED; 343a0da96c0SYana Esina err = device_set_wakeup_enable(&pdev->dev, wol->wolopts); 344a0da96c0SYana Esina 345a0da96c0SYana Esina return err; 346a0da96c0SYana Esina } 347a0da96c0SYana Esina 34892ab6407SYana Esina static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed) 34992ab6407SYana Esina { 35092ab6407SYana Esina u32 rate = 0; 35192ab6407SYana Esina 35292ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_10G) 35392ab6407SYana Esina rate |= SUPPORTED_10000baseT_Full; 35492ab6407SYana Esina 35592ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_2GS) 35692ab6407SYana Esina rate |= SUPPORTED_2500baseX_Full; 35792ab6407SYana Esina 35892ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_1G) 35992ab6407SYana Esina rate |= SUPPORTED_1000baseT_Full; 36092ab6407SYana Esina 36192ab6407SYana Esina return rate; 36292ab6407SYana Esina } 36392ab6407SYana Esina 36492ab6407SYana Esina static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee) 36592ab6407SYana Esina { 36692ab6407SYana Esina struct aq_nic_s *aq_nic = netdev_priv(ndev); 36792ab6407SYana Esina u32 rate, supported_rates; 36892ab6407SYana Esina int err = 0; 36992ab6407SYana Esina 37092ab6407SYana Esina if (!aq_nic->aq_fw_ops->get_eee_rate) 37192ab6407SYana Esina return -EOPNOTSUPP; 37292ab6407SYana Esina 37392ab6407SYana Esina err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate, 37492ab6407SYana Esina &supported_rates); 37592ab6407SYana Esina if (err < 0) 37692ab6407SYana Esina return err; 37792ab6407SYana Esina 37892ab6407SYana Esina eee->supported = eee_mask_to_ethtool_mask(supported_rates); 37992ab6407SYana Esina 38092ab6407SYana Esina if (aq_nic->aq_nic_cfg.eee_speeds) 38192ab6407SYana Esina eee->advertised = eee->supported; 38292ab6407SYana Esina 38392ab6407SYana Esina eee->lp_advertised = eee_mask_to_ethtool_mask(rate); 38492ab6407SYana Esina 38592ab6407SYana Esina eee->eee_enabled = !!eee->advertised; 38692ab6407SYana Esina 38792ab6407SYana Esina eee->tx_lpi_enabled = eee->eee_enabled; 38892ab6407SYana Esina if (eee->advertised & eee->lp_advertised) 38992ab6407SYana Esina eee->eee_active = true; 39092ab6407SYana Esina 39192ab6407SYana Esina return 0; 39292ab6407SYana Esina } 39392ab6407SYana Esina 39492ab6407SYana Esina static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee) 39592ab6407SYana Esina { 39692ab6407SYana Esina struct aq_nic_s *aq_nic = netdev_priv(ndev); 39792ab6407SYana Esina u32 rate, supported_rates; 39892ab6407SYana Esina struct aq_nic_cfg_s *cfg; 39992ab6407SYana Esina int err = 0; 40092ab6407SYana Esina 40192ab6407SYana Esina cfg = aq_nic_get_cfg(aq_nic); 40292ab6407SYana Esina 40392ab6407SYana Esina if (unlikely(!aq_nic->aq_fw_ops->get_eee_rate || 40492ab6407SYana Esina !aq_nic->aq_fw_ops->set_eee_rate)) 40592ab6407SYana Esina return -EOPNOTSUPP; 40692ab6407SYana Esina 40792ab6407SYana Esina err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate, 40892ab6407SYana Esina &supported_rates); 40992ab6407SYana Esina if (err < 0) 41092ab6407SYana Esina return err; 41192ab6407SYana Esina 41292ab6407SYana Esina if (eee->eee_enabled) { 41392ab6407SYana Esina rate = supported_rates; 41492ab6407SYana Esina cfg->eee_speeds = rate; 41592ab6407SYana Esina } else { 41692ab6407SYana Esina rate = 0; 41792ab6407SYana Esina cfg->eee_speeds = 0; 41892ab6407SYana Esina } 41992ab6407SYana Esina 42092ab6407SYana Esina return aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate); 42192ab6407SYana Esina } 42292ab6407SYana Esina 423b8d68b62SAnton Mikaev static int aq_ethtool_nway_reset(struct net_device *ndev) 424b8d68b62SAnton Mikaev { 425b8d68b62SAnton Mikaev struct aq_nic_s *aq_nic = netdev_priv(ndev); 426b8d68b62SAnton Mikaev 427b8d68b62SAnton Mikaev if (unlikely(!aq_nic->aq_fw_ops->renegotiate)) 428b8d68b62SAnton Mikaev return -EOPNOTSUPP; 429b8d68b62SAnton Mikaev 430b8d68b62SAnton Mikaev if (netif_running(ndev)) 431b8d68b62SAnton Mikaev return aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw); 432b8d68b62SAnton Mikaev 433b8d68b62SAnton Mikaev return 0; 434b8d68b62SAnton Mikaev } 435b8d68b62SAnton Mikaev 436288551deSIgor Russkikh static void aq_ethtool_get_pauseparam(struct net_device *ndev, 437288551deSIgor Russkikh struct ethtool_pauseparam *pause) 438288551deSIgor Russkikh { 439288551deSIgor Russkikh struct aq_nic_s *aq_nic = netdev_priv(ndev); 44035e8e8b4SIgor Russkikh u32 fc = aq_nic->aq_nic_cfg.flow_control; 441288551deSIgor Russkikh 442288551deSIgor Russkikh pause->autoneg = 0; 443288551deSIgor Russkikh 44435e8e8b4SIgor Russkikh pause->rx_pause = !!(fc & AQ_NIC_FC_RX); 44535e8e8b4SIgor Russkikh pause->tx_pause = !!(fc & AQ_NIC_FC_TX); 44635e8e8b4SIgor Russkikh 447288551deSIgor Russkikh } 448288551deSIgor Russkikh 449288551deSIgor Russkikh static int aq_ethtool_set_pauseparam(struct net_device *ndev, 450288551deSIgor Russkikh struct ethtool_pauseparam *pause) 451288551deSIgor Russkikh { 452288551deSIgor Russkikh struct aq_nic_s *aq_nic = netdev_priv(ndev); 453288551deSIgor Russkikh int err = 0; 454288551deSIgor Russkikh 455288551deSIgor Russkikh if (!aq_nic->aq_fw_ops->set_flow_control) 456288551deSIgor Russkikh return -EOPNOTSUPP; 457288551deSIgor Russkikh 458288551deSIgor Russkikh if (pause->autoneg == AUTONEG_ENABLE) 459288551deSIgor Russkikh return -EOPNOTSUPP; 460288551deSIgor Russkikh 461288551deSIgor Russkikh if (pause->rx_pause) 462288551deSIgor Russkikh aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_RX; 463288551deSIgor Russkikh else 464288551deSIgor Russkikh aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_RX; 465288551deSIgor Russkikh 466288551deSIgor Russkikh if (pause->tx_pause) 467288551deSIgor Russkikh aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_TX; 468288551deSIgor Russkikh else 469288551deSIgor Russkikh aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX; 470288551deSIgor Russkikh 471288551deSIgor Russkikh err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw); 472288551deSIgor Russkikh 473288551deSIgor Russkikh return err; 474288551deSIgor Russkikh } 475288551deSIgor Russkikh 476c1af5427SAnton Mikaev static void aq_get_ringparam(struct net_device *ndev, 477c1af5427SAnton Mikaev struct ethtool_ringparam *ring) 478c1af5427SAnton Mikaev { 479c1af5427SAnton Mikaev struct aq_nic_s *aq_nic = netdev_priv(ndev); 480c1af5427SAnton Mikaev struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic); 481c1af5427SAnton Mikaev 482c1af5427SAnton Mikaev ring->rx_pending = aq_nic_cfg->rxds; 483c1af5427SAnton Mikaev ring->tx_pending = aq_nic_cfg->txds; 484c1af5427SAnton Mikaev 485c1af5427SAnton Mikaev ring->rx_max_pending = aq_nic_cfg->aq_hw_caps->rxds_max; 486c1af5427SAnton Mikaev ring->tx_max_pending = aq_nic_cfg->aq_hw_caps->txds_max; 487c1af5427SAnton Mikaev } 488c1af5427SAnton Mikaev 489c1af5427SAnton Mikaev static int aq_set_ringparam(struct net_device *ndev, 490c1af5427SAnton Mikaev struct ethtool_ringparam *ring) 491c1af5427SAnton Mikaev { 492c1af5427SAnton Mikaev int err = 0; 493c1af5427SAnton Mikaev bool ndev_running = false; 494c1af5427SAnton Mikaev struct aq_nic_s *aq_nic = netdev_priv(ndev); 495c1af5427SAnton Mikaev struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic); 496c1af5427SAnton Mikaev const struct aq_hw_caps_s *hw_caps = aq_nic_cfg->aq_hw_caps; 497c1af5427SAnton Mikaev 498c1af5427SAnton Mikaev if (ring->rx_mini_pending || ring->rx_jumbo_pending) { 499c1af5427SAnton Mikaev err = -EOPNOTSUPP; 500c1af5427SAnton Mikaev goto err_exit; 501c1af5427SAnton Mikaev } 502c1af5427SAnton Mikaev 503c1af5427SAnton Mikaev if (netif_running(ndev)) { 504c1af5427SAnton Mikaev ndev_running = true; 505c1af5427SAnton Mikaev dev_close(ndev); 506c1af5427SAnton Mikaev } 507c1af5427SAnton Mikaev 508c1af5427SAnton Mikaev aq_nic_free_vectors(aq_nic); 509c1af5427SAnton Mikaev 510c1af5427SAnton Mikaev aq_nic_cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min); 511c1af5427SAnton Mikaev aq_nic_cfg->rxds = min(aq_nic_cfg->rxds, hw_caps->rxds_max); 512c1af5427SAnton Mikaev aq_nic_cfg->rxds = ALIGN(aq_nic_cfg->rxds, AQ_HW_RXD_MULTIPLE); 513c1af5427SAnton Mikaev 514c1af5427SAnton Mikaev aq_nic_cfg->txds = max(ring->tx_pending, hw_caps->txds_min); 515c1af5427SAnton Mikaev aq_nic_cfg->txds = min(aq_nic_cfg->txds, hw_caps->txds_max); 516c1af5427SAnton Mikaev aq_nic_cfg->txds = ALIGN(aq_nic_cfg->txds, AQ_HW_TXD_MULTIPLE); 517c1af5427SAnton Mikaev 518c1af5427SAnton Mikaev for (aq_nic->aq_vecs = 0; aq_nic->aq_vecs < aq_nic_cfg->vecs; 519c1af5427SAnton Mikaev aq_nic->aq_vecs++) { 520c1af5427SAnton Mikaev aq_nic->aq_vec[aq_nic->aq_vecs] = 521c1af5427SAnton Mikaev aq_vec_alloc(aq_nic, aq_nic->aq_vecs, aq_nic_cfg); 522c1af5427SAnton Mikaev if (unlikely(!aq_nic->aq_vec[aq_nic->aq_vecs])) { 523c1af5427SAnton Mikaev err = -ENOMEM; 524c1af5427SAnton Mikaev goto err_exit; 525c1af5427SAnton Mikaev } 526c1af5427SAnton Mikaev } 527c1af5427SAnton Mikaev if (ndev_running) 528*00f54e68SPetr Machata err = dev_open(ndev, NULL); 529c1af5427SAnton Mikaev 530c1af5427SAnton Mikaev err_exit: 531c1af5427SAnton Mikaev return err; 532c1af5427SAnton Mikaev } 533c1af5427SAnton Mikaev 534c5760d03SDavid VomLehn const struct ethtool_ops aq_ethtool_ops = { 535c5760d03SDavid VomLehn .get_link = aq_ethtool_get_link, 536c5760d03SDavid VomLehn .get_regs_len = aq_ethtool_get_regs_len, 537c5760d03SDavid VomLehn .get_regs = aq_ethtool_get_regs, 538c5760d03SDavid VomLehn .get_drvinfo = aq_ethtool_get_drvinfo, 539c5760d03SDavid VomLehn .get_strings = aq_ethtool_get_strings, 540c5760d03SDavid VomLehn .get_rxfh_indir_size = aq_ethtool_get_rss_indir_size, 541a0da96c0SYana Esina .get_wol = aq_ethtool_get_wol, 542a0da96c0SYana Esina .set_wol = aq_ethtool_set_wol, 543b8d68b62SAnton Mikaev .nway_reset = aq_ethtool_nway_reset, 544c1af5427SAnton Mikaev .get_ringparam = aq_get_ringparam, 545c1af5427SAnton Mikaev .set_ringparam = aq_set_ringparam, 54692ab6407SYana Esina .get_eee = aq_ethtool_get_eee, 54792ab6407SYana Esina .set_eee = aq_ethtool_set_eee, 548288551deSIgor Russkikh .get_pauseparam = aq_ethtool_get_pauseparam, 549288551deSIgor Russkikh .set_pauseparam = aq_ethtool_set_pauseparam, 550c5760d03SDavid VomLehn .get_rxfh_key_size = aq_ethtool_get_rss_key_size, 551c5760d03SDavid VomLehn .get_rxfh = aq_ethtool_get_rss, 552c5760d03SDavid VomLehn .get_rxnfc = aq_ethtool_get_rxnfc, 5538d0bcb01SDmitry Bogdanov .set_rxnfc = aq_ethtool_set_rxnfc, 554c5760d03SDavid VomLehn .get_sset_count = aq_ethtool_get_sset_count, 555f8244ab5SPhilippe Reynes .get_ethtool_stats = aq_ethtool_stats, 556f8244ab5SPhilippe Reynes .get_link_ksettings = aq_ethtool_get_link_ksettings, 557f8244ab5SPhilippe Reynes .set_link_ksettings = aq_ethtool_set_link_ksettings, 558b82ee71aSIgor Russkikh .get_coalesce = aq_ethtool_get_coalesce, 559b82ee71aSIgor Russkikh .set_coalesce = aq_ethtool_set_coalesce, 560c5760d03SDavid VomLehn }; 561