1f13bbc2fSNeel Patel /** 2f13bbc2fSNeel Patel * Copyright 2013 Cisco Systems, Inc. All rights reserved. 3f13bbc2fSNeel Patel * 4f13bbc2fSNeel Patel * This program is free software; you may redistribute it and/or modify 5f13bbc2fSNeel Patel * it under the terms of the GNU General Public License as published by 6f13bbc2fSNeel Patel * the Free Software Foundation; version 2 of the License. 7f13bbc2fSNeel Patel * 8f13bbc2fSNeel Patel * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 9f13bbc2fSNeel Patel * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 10f13bbc2fSNeel Patel * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 11f13bbc2fSNeel Patel * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 12f13bbc2fSNeel Patel * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 13f13bbc2fSNeel Patel * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14f13bbc2fSNeel Patel * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 15f13bbc2fSNeel Patel * SOFTWARE. 16f13bbc2fSNeel Patel * 17f13bbc2fSNeel Patel */ 18f13bbc2fSNeel Patel 19f13bbc2fSNeel Patel #include <linux/netdevice.h> 20f13bbc2fSNeel Patel #include <linux/ethtool.h> 21f13bbc2fSNeel Patel 22f13bbc2fSNeel Patel #include "enic_res.h" 23f13bbc2fSNeel Patel #include "enic.h" 24f13bbc2fSNeel Patel #include "enic_dev.h" 25f13bbc2fSNeel Patel 26f13bbc2fSNeel Patel struct enic_stat { 27f13bbc2fSNeel Patel char name[ETH_GSTRING_LEN]; 28f13bbc2fSNeel Patel unsigned int index; 29f13bbc2fSNeel Patel }; 30f13bbc2fSNeel Patel 31f13bbc2fSNeel Patel #define ENIC_TX_STAT(stat) { \ 32f13bbc2fSNeel Patel .name = #stat, \ 33f13bbc2fSNeel Patel .index = offsetof(struct vnic_tx_stats, stat) / sizeof(u64) \ 34f13bbc2fSNeel Patel } 35f13bbc2fSNeel Patel 36f13bbc2fSNeel Patel #define ENIC_RX_STAT(stat) { \ 37f13bbc2fSNeel Patel .name = #stat, \ 38f13bbc2fSNeel Patel .index = offsetof(struct vnic_rx_stats, stat) / sizeof(u64) \ 39f13bbc2fSNeel Patel } 40f13bbc2fSNeel Patel 41f13bbc2fSNeel Patel static const struct enic_stat enic_tx_stats[] = { 42f13bbc2fSNeel Patel ENIC_TX_STAT(tx_frames_ok), 43f13bbc2fSNeel Patel ENIC_TX_STAT(tx_unicast_frames_ok), 44f13bbc2fSNeel Patel ENIC_TX_STAT(tx_multicast_frames_ok), 45f13bbc2fSNeel Patel ENIC_TX_STAT(tx_broadcast_frames_ok), 46f13bbc2fSNeel Patel ENIC_TX_STAT(tx_bytes_ok), 47f13bbc2fSNeel Patel ENIC_TX_STAT(tx_unicast_bytes_ok), 48f13bbc2fSNeel Patel ENIC_TX_STAT(tx_multicast_bytes_ok), 49f13bbc2fSNeel Patel ENIC_TX_STAT(tx_broadcast_bytes_ok), 50f13bbc2fSNeel Patel ENIC_TX_STAT(tx_drops), 51f13bbc2fSNeel Patel ENIC_TX_STAT(tx_errors), 52f13bbc2fSNeel Patel ENIC_TX_STAT(tx_tso), 53f13bbc2fSNeel Patel }; 54f13bbc2fSNeel Patel 55f13bbc2fSNeel Patel static const struct enic_stat enic_rx_stats[] = { 56f13bbc2fSNeel Patel ENIC_RX_STAT(rx_frames_ok), 57f13bbc2fSNeel Patel ENIC_RX_STAT(rx_frames_total), 58f13bbc2fSNeel Patel ENIC_RX_STAT(rx_unicast_frames_ok), 59f13bbc2fSNeel Patel ENIC_RX_STAT(rx_multicast_frames_ok), 60f13bbc2fSNeel Patel ENIC_RX_STAT(rx_broadcast_frames_ok), 61f13bbc2fSNeel Patel ENIC_RX_STAT(rx_bytes_ok), 62f13bbc2fSNeel Patel ENIC_RX_STAT(rx_unicast_bytes_ok), 63f13bbc2fSNeel Patel ENIC_RX_STAT(rx_multicast_bytes_ok), 64f13bbc2fSNeel Patel ENIC_RX_STAT(rx_broadcast_bytes_ok), 65f13bbc2fSNeel Patel ENIC_RX_STAT(rx_drop), 66f13bbc2fSNeel Patel ENIC_RX_STAT(rx_no_bufs), 67f13bbc2fSNeel Patel ENIC_RX_STAT(rx_errors), 68f13bbc2fSNeel Patel ENIC_RX_STAT(rx_rss), 69f13bbc2fSNeel Patel ENIC_RX_STAT(rx_crc_errors), 70f13bbc2fSNeel Patel ENIC_RX_STAT(rx_frames_64), 71f13bbc2fSNeel Patel ENIC_RX_STAT(rx_frames_127), 72f13bbc2fSNeel Patel ENIC_RX_STAT(rx_frames_255), 73f13bbc2fSNeel Patel ENIC_RX_STAT(rx_frames_511), 74f13bbc2fSNeel Patel ENIC_RX_STAT(rx_frames_1023), 75f13bbc2fSNeel Patel ENIC_RX_STAT(rx_frames_1518), 76f13bbc2fSNeel Patel ENIC_RX_STAT(rx_frames_to_max), 77f13bbc2fSNeel Patel }; 78f13bbc2fSNeel Patel 79f13bbc2fSNeel Patel static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats); 80f13bbc2fSNeel Patel static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats); 81f13bbc2fSNeel Patel 827c2ce6e6SSujith Sankar void enic_intr_coal_set_rx(struct enic *enic, u32 timer) 837c2ce6e6SSujith Sankar { 847c2ce6e6SSujith Sankar int i; 857c2ce6e6SSujith Sankar int intr; 867c2ce6e6SSujith Sankar 877c2ce6e6SSujith Sankar for (i = 0; i < enic->rq_count; i++) { 887c2ce6e6SSujith Sankar intr = enic_msix_rq_intr(enic, i); 897c2ce6e6SSujith Sankar vnic_intr_coalescing_timer_set(&enic->intr[intr], timer); 907c2ce6e6SSujith Sankar } 917c2ce6e6SSujith Sankar } 927c2ce6e6SSujith Sankar 93f13bbc2fSNeel Patel static int enic_get_settings(struct net_device *netdev, 94f13bbc2fSNeel Patel struct ethtool_cmd *ecmd) 95f13bbc2fSNeel Patel { 96f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 97f13bbc2fSNeel Patel 98f13bbc2fSNeel Patel ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); 99f13bbc2fSNeel Patel ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); 100f13bbc2fSNeel Patel ecmd->port = PORT_FIBRE; 101f13bbc2fSNeel Patel ecmd->transceiver = XCVR_EXTERNAL; 102f13bbc2fSNeel Patel 103f13bbc2fSNeel Patel if (netif_carrier_ok(netdev)) { 104f13bbc2fSNeel Patel ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev)); 105f13bbc2fSNeel Patel ecmd->duplex = DUPLEX_FULL; 106f13bbc2fSNeel Patel } else { 107537fae01SJiri Pirko ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN); 108537fae01SJiri Pirko ecmd->duplex = DUPLEX_UNKNOWN; 109f13bbc2fSNeel Patel } 110f13bbc2fSNeel Patel 111f13bbc2fSNeel Patel ecmd->autoneg = AUTONEG_DISABLE; 112f13bbc2fSNeel Patel 113f13bbc2fSNeel Patel return 0; 114f13bbc2fSNeel Patel } 115f13bbc2fSNeel Patel 116f13bbc2fSNeel Patel static void enic_get_drvinfo(struct net_device *netdev, 117f13bbc2fSNeel Patel struct ethtool_drvinfo *drvinfo) 118f13bbc2fSNeel Patel { 119f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 120f13bbc2fSNeel Patel struct vnic_devcmd_fw_info *fw_info; 121f13bbc2fSNeel Patel 122f13bbc2fSNeel Patel enic_dev_fw_info(enic, &fw_info); 123f13bbc2fSNeel Patel 124f13bbc2fSNeel Patel strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); 125f13bbc2fSNeel Patel strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); 126f13bbc2fSNeel Patel strlcpy(drvinfo->fw_version, fw_info->fw_version, 127f13bbc2fSNeel Patel sizeof(drvinfo->fw_version)); 128f13bbc2fSNeel Patel strlcpy(drvinfo->bus_info, pci_name(enic->pdev), 129f13bbc2fSNeel Patel sizeof(drvinfo->bus_info)); 130f13bbc2fSNeel Patel } 131f13bbc2fSNeel Patel 132f13bbc2fSNeel Patel static void enic_get_strings(struct net_device *netdev, u32 stringset, 133f13bbc2fSNeel Patel u8 *data) 134f13bbc2fSNeel Patel { 135f13bbc2fSNeel Patel unsigned int i; 136f13bbc2fSNeel Patel 137f13bbc2fSNeel Patel switch (stringset) { 138f13bbc2fSNeel Patel case ETH_SS_STATS: 139f13bbc2fSNeel Patel for (i = 0; i < enic_n_tx_stats; i++) { 140f13bbc2fSNeel Patel memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN); 141f13bbc2fSNeel Patel data += ETH_GSTRING_LEN; 142f13bbc2fSNeel Patel } 143f13bbc2fSNeel Patel for (i = 0; i < enic_n_rx_stats; i++) { 144f13bbc2fSNeel Patel memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN); 145f13bbc2fSNeel Patel data += ETH_GSTRING_LEN; 146f13bbc2fSNeel Patel } 147f13bbc2fSNeel Patel break; 148f13bbc2fSNeel Patel } 149f13bbc2fSNeel Patel } 150f13bbc2fSNeel Patel 151f13bbc2fSNeel Patel static int enic_get_sset_count(struct net_device *netdev, int sset) 152f13bbc2fSNeel Patel { 153f13bbc2fSNeel Patel switch (sset) { 154f13bbc2fSNeel Patel case ETH_SS_STATS: 155f13bbc2fSNeel Patel return enic_n_tx_stats + enic_n_rx_stats; 156f13bbc2fSNeel Patel default: 157f13bbc2fSNeel Patel return -EOPNOTSUPP; 158f13bbc2fSNeel Patel } 159f13bbc2fSNeel Patel } 160f13bbc2fSNeel Patel 161f13bbc2fSNeel Patel static void enic_get_ethtool_stats(struct net_device *netdev, 162f13bbc2fSNeel Patel struct ethtool_stats *stats, u64 *data) 163f13bbc2fSNeel Patel { 164f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 165f13bbc2fSNeel Patel struct vnic_stats *vstats; 166f13bbc2fSNeel Patel unsigned int i; 167f13bbc2fSNeel Patel 168f13bbc2fSNeel Patel enic_dev_stats_dump(enic, &vstats); 169f13bbc2fSNeel Patel 170f13bbc2fSNeel Patel for (i = 0; i < enic_n_tx_stats; i++) 171f13bbc2fSNeel Patel *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index]; 172f13bbc2fSNeel Patel for (i = 0; i < enic_n_rx_stats; i++) 173f13bbc2fSNeel Patel *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index]; 174f13bbc2fSNeel Patel } 175f13bbc2fSNeel Patel 176f13bbc2fSNeel Patel static u32 enic_get_msglevel(struct net_device *netdev) 177f13bbc2fSNeel Patel { 178f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 179f13bbc2fSNeel Patel return enic->msg_enable; 180f13bbc2fSNeel Patel } 181f13bbc2fSNeel Patel 182f13bbc2fSNeel Patel static void enic_set_msglevel(struct net_device *netdev, u32 value) 183f13bbc2fSNeel Patel { 184f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 185f13bbc2fSNeel Patel enic->msg_enable = value; 186f13bbc2fSNeel Patel } 187f13bbc2fSNeel Patel 188f13bbc2fSNeel Patel static int enic_get_coalesce(struct net_device *netdev, 189f13bbc2fSNeel Patel struct ethtool_coalesce *ecmd) 190f13bbc2fSNeel Patel { 191f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 1927c2ce6e6SSujith Sankar struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting; 193f13bbc2fSNeel Patel 194f13bbc2fSNeel Patel ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs; 195f13bbc2fSNeel Patel ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs; 1967c2ce6e6SSujith Sankar if (rxcoal->use_adaptive_rx_coalesce) 1977c2ce6e6SSujith Sankar ecmd->use_adaptive_rx_coalesce = 1; 1987c2ce6e6SSujith Sankar ecmd->rx_coalesce_usecs_low = rxcoal->small_pkt_range_start; 1997c2ce6e6SSujith Sankar ecmd->rx_coalesce_usecs_high = rxcoal->range_end; 200f13bbc2fSNeel Patel 201f13bbc2fSNeel Patel return 0; 202f13bbc2fSNeel Patel } 203f13bbc2fSNeel Patel 204f13bbc2fSNeel Patel static int enic_set_coalesce(struct net_device *netdev, 205f13bbc2fSNeel Patel struct ethtool_coalesce *ecmd) 206f13bbc2fSNeel Patel { 207f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 208f13bbc2fSNeel Patel u32 tx_coalesce_usecs; 209f13bbc2fSNeel Patel u32 rx_coalesce_usecs; 2107c2ce6e6SSujith Sankar u32 rx_coalesce_usecs_low; 2117c2ce6e6SSujith Sankar u32 rx_coalesce_usecs_high; 2127c2ce6e6SSujith Sankar u32 coalesce_usecs_max; 213f13bbc2fSNeel Patel unsigned int i, intr; 2147c2ce6e6SSujith Sankar struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting; 215f13bbc2fSNeel Patel 2167c2ce6e6SSujith Sankar coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev); 217f13bbc2fSNeel Patel tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs, 2187c2ce6e6SSujith Sankar coalesce_usecs_max); 219f13bbc2fSNeel Patel rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs, 2207c2ce6e6SSujith Sankar coalesce_usecs_max); 2217c2ce6e6SSujith Sankar 2227c2ce6e6SSujith Sankar rx_coalesce_usecs_low = min_t(u32, ecmd->rx_coalesce_usecs_low, 2237c2ce6e6SSujith Sankar coalesce_usecs_max); 2247c2ce6e6SSujith Sankar rx_coalesce_usecs_high = min_t(u32, ecmd->rx_coalesce_usecs_high, 2257c2ce6e6SSujith Sankar coalesce_usecs_max); 226f13bbc2fSNeel Patel 227f13bbc2fSNeel Patel switch (vnic_dev_get_intr_mode(enic->vdev)) { 228f13bbc2fSNeel Patel case VNIC_DEV_INTR_MODE_INTX: 229f13bbc2fSNeel Patel if (tx_coalesce_usecs != rx_coalesce_usecs) 230f13bbc2fSNeel Patel return -EINVAL; 2317c2ce6e6SSujith Sankar if (ecmd->use_adaptive_rx_coalesce || 2327c2ce6e6SSujith Sankar ecmd->rx_coalesce_usecs_low || 2337c2ce6e6SSujith Sankar ecmd->rx_coalesce_usecs_high) 234a16a3361SGovindarajulu Varadarajan return -EINVAL; 235f13bbc2fSNeel Patel 236f13bbc2fSNeel Patel intr = enic_legacy_io_intr(); 237f13bbc2fSNeel Patel vnic_intr_coalescing_timer_set(&enic->intr[intr], 238f13bbc2fSNeel Patel tx_coalesce_usecs); 239f13bbc2fSNeel Patel break; 240f13bbc2fSNeel Patel case VNIC_DEV_INTR_MODE_MSI: 241f13bbc2fSNeel Patel if (tx_coalesce_usecs != rx_coalesce_usecs) 242f13bbc2fSNeel Patel return -EINVAL; 2437c2ce6e6SSujith Sankar if (ecmd->use_adaptive_rx_coalesce || 2447c2ce6e6SSujith Sankar ecmd->rx_coalesce_usecs_low || 2457c2ce6e6SSujith Sankar ecmd->rx_coalesce_usecs_high) 246a16a3361SGovindarajulu Varadarajan return -EINVAL; 247f13bbc2fSNeel Patel 248f13bbc2fSNeel Patel vnic_intr_coalescing_timer_set(&enic->intr[0], 249f13bbc2fSNeel Patel tx_coalesce_usecs); 250f13bbc2fSNeel Patel break; 251f13bbc2fSNeel Patel case VNIC_DEV_INTR_MODE_MSIX: 252a16a3361SGovindarajulu Varadarajan if (ecmd->rx_coalesce_usecs_high && 253a16a3361SGovindarajulu Varadarajan (rx_coalesce_usecs_high < 254a16a3361SGovindarajulu Varadarajan rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF)) 255a16a3361SGovindarajulu Varadarajan return -EINVAL; 256a16a3361SGovindarajulu Varadarajan 257f13bbc2fSNeel Patel for (i = 0; i < enic->wq_count; i++) { 258f13bbc2fSNeel Patel intr = enic_msix_wq_intr(enic, i); 259f13bbc2fSNeel Patel vnic_intr_coalescing_timer_set(&enic->intr[intr], 260f13bbc2fSNeel Patel tx_coalesce_usecs); 261f13bbc2fSNeel Patel } 262f13bbc2fSNeel Patel 263a16a3361SGovindarajulu Varadarajan rxcoal->use_adaptive_rx_coalesce = 264a16a3361SGovindarajulu Varadarajan !!ecmd->use_adaptive_rx_coalesce; 265a16a3361SGovindarajulu Varadarajan if (!rxcoal->use_adaptive_rx_coalesce) 2667c2ce6e6SSujith Sankar enic_intr_coal_set_rx(enic, rx_coalesce_usecs); 267f13bbc2fSNeel Patel 2687c2ce6e6SSujith Sankar if (ecmd->rx_coalesce_usecs_high) { 2697c2ce6e6SSujith Sankar rxcoal->range_end = rx_coalesce_usecs_high; 2707c2ce6e6SSujith Sankar rxcoal->small_pkt_range_start = rx_coalesce_usecs_low; 2717c2ce6e6SSujith Sankar rxcoal->large_pkt_range_start = rx_coalesce_usecs_low + 2727c2ce6e6SSujith Sankar ENIC_AIC_LARGE_PKT_DIFF; 2737c2ce6e6SSujith Sankar } 274f13bbc2fSNeel Patel break; 275f13bbc2fSNeel Patel default: 276f13bbc2fSNeel Patel break; 277f13bbc2fSNeel Patel } 278f13bbc2fSNeel Patel 279f13bbc2fSNeel Patel enic->tx_coalesce_usecs = tx_coalesce_usecs; 280f13bbc2fSNeel Patel enic->rx_coalesce_usecs = rx_coalesce_usecs; 281f13bbc2fSNeel Patel 282f13bbc2fSNeel Patel return 0; 283f13bbc2fSNeel Patel } 284f13bbc2fSNeel Patel 285f13bbc2fSNeel Patel static const struct ethtool_ops enic_ethtool_ops = { 286f13bbc2fSNeel Patel .get_settings = enic_get_settings, 287f13bbc2fSNeel Patel .get_drvinfo = enic_get_drvinfo, 288f13bbc2fSNeel Patel .get_msglevel = enic_get_msglevel, 289f13bbc2fSNeel Patel .set_msglevel = enic_set_msglevel, 290f13bbc2fSNeel Patel .get_link = ethtool_op_get_link, 291f13bbc2fSNeel Patel .get_strings = enic_get_strings, 292f13bbc2fSNeel Patel .get_sset_count = enic_get_sset_count, 293f13bbc2fSNeel Patel .get_ethtool_stats = enic_get_ethtool_stats, 294f13bbc2fSNeel Patel .get_coalesce = enic_get_coalesce, 295f13bbc2fSNeel Patel .set_coalesce = enic_set_coalesce, 296f13bbc2fSNeel Patel }; 297f13bbc2fSNeel Patel 298f13bbc2fSNeel Patel void enic_set_ethtool_ops(struct net_device *netdev) 299f13bbc2fSNeel Patel { 3007ad24ea4SWilfried Klaebe netdev->ethtool_ops = &enic_ethtool_ops; 301f13bbc2fSNeel Patel } 302