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 82f13bbc2fSNeel Patel static int enic_get_settings(struct net_device *netdev, 83f13bbc2fSNeel Patel struct ethtool_cmd *ecmd) 84f13bbc2fSNeel Patel { 85f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 86f13bbc2fSNeel Patel 87f13bbc2fSNeel Patel ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); 88f13bbc2fSNeel Patel ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); 89f13bbc2fSNeel Patel ecmd->port = PORT_FIBRE; 90f13bbc2fSNeel Patel ecmd->transceiver = XCVR_EXTERNAL; 91f13bbc2fSNeel Patel 92f13bbc2fSNeel Patel if (netif_carrier_ok(netdev)) { 93f13bbc2fSNeel Patel ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev)); 94f13bbc2fSNeel Patel ecmd->duplex = DUPLEX_FULL; 95f13bbc2fSNeel Patel } else { 96f13bbc2fSNeel Patel ethtool_cmd_speed_set(ecmd, -1); 97f13bbc2fSNeel Patel ecmd->duplex = -1; 98f13bbc2fSNeel Patel } 99f13bbc2fSNeel Patel 100f13bbc2fSNeel Patel ecmd->autoneg = AUTONEG_DISABLE; 101f13bbc2fSNeel Patel 102f13bbc2fSNeel Patel return 0; 103f13bbc2fSNeel Patel } 104f13bbc2fSNeel Patel 105f13bbc2fSNeel Patel static void enic_get_drvinfo(struct net_device *netdev, 106f13bbc2fSNeel Patel struct ethtool_drvinfo *drvinfo) 107f13bbc2fSNeel Patel { 108f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 109f13bbc2fSNeel Patel struct vnic_devcmd_fw_info *fw_info; 110f13bbc2fSNeel Patel 111f13bbc2fSNeel Patel enic_dev_fw_info(enic, &fw_info); 112f13bbc2fSNeel Patel 113f13bbc2fSNeel Patel strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); 114f13bbc2fSNeel Patel strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); 115f13bbc2fSNeel Patel strlcpy(drvinfo->fw_version, fw_info->fw_version, 116f13bbc2fSNeel Patel sizeof(drvinfo->fw_version)); 117f13bbc2fSNeel Patel strlcpy(drvinfo->bus_info, pci_name(enic->pdev), 118f13bbc2fSNeel Patel sizeof(drvinfo->bus_info)); 119f13bbc2fSNeel Patel } 120f13bbc2fSNeel Patel 121f13bbc2fSNeel Patel static void enic_get_strings(struct net_device *netdev, u32 stringset, 122f13bbc2fSNeel Patel u8 *data) 123f13bbc2fSNeel Patel { 124f13bbc2fSNeel Patel unsigned int i; 125f13bbc2fSNeel Patel 126f13bbc2fSNeel Patel switch (stringset) { 127f13bbc2fSNeel Patel case ETH_SS_STATS: 128f13bbc2fSNeel Patel for (i = 0; i < enic_n_tx_stats; i++) { 129f13bbc2fSNeel Patel memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN); 130f13bbc2fSNeel Patel data += ETH_GSTRING_LEN; 131f13bbc2fSNeel Patel } 132f13bbc2fSNeel Patel for (i = 0; i < enic_n_rx_stats; i++) { 133f13bbc2fSNeel Patel memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN); 134f13bbc2fSNeel Patel data += ETH_GSTRING_LEN; 135f13bbc2fSNeel Patel } 136f13bbc2fSNeel Patel break; 137f13bbc2fSNeel Patel } 138f13bbc2fSNeel Patel } 139f13bbc2fSNeel Patel 140f13bbc2fSNeel Patel static int enic_get_sset_count(struct net_device *netdev, int sset) 141f13bbc2fSNeel Patel { 142f13bbc2fSNeel Patel switch (sset) { 143f13bbc2fSNeel Patel case ETH_SS_STATS: 144f13bbc2fSNeel Patel return enic_n_tx_stats + enic_n_rx_stats; 145f13bbc2fSNeel Patel default: 146f13bbc2fSNeel Patel return -EOPNOTSUPP; 147f13bbc2fSNeel Patel } 148f13bbc2fSNeel Patel } 149f13bbc2fSNeel Patel 150f13bbc2fSNeel Patel static void enic_get_ethtool_stats(struct net_device *netdev, 151f13bbc2fSNeel Patel struct ethtool_stats *stats, u64 *data) 152f13bbc2fSNeel Patel { 153f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 154f13bbc2fSNeel Patel struct vnic_stats *vstats; 155f13bbc2fSNeel Patel unsigned int i; 156f13bbc2fSNeel Patel 157f13bbc2fSNeel Patel enic_dev_stats_dump(enic, &vstats); 158f13bbc2fSNeel Patel 159f13bbc2fSNeel Patel for (i = 0; i < enic_n_tx_stats; i++) 160f13bbc2fSNeel Patel *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index]; 161f13bbc2fSNeel Patel for (i = 0; i < enic_n_rx_stats; i++) 162f13bbc2fSNeel Patel *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index]; 163f13bbc2fSNeel Patel } 164f13bbc2fSNeel Patel 165f13bbc2fSNeel Patel static u32 enic_get_msglevel(struct net_device *netdev) 166f13bbc2fSNeel Patel { 167f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 168f13bbc2fSNeel Patel return enic->msg_enable; 169f13bbc2fSNeel Patel } 170f13bbc2fSNeel Patel 171f13bbc2fSNeel Patel static void enic_set_msglevel(struct net_device *netdev, u32 value) 172f13bbc2fSNeel Patel { 173f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 174f13bbc2fSNeel Patel enic->msg_enable = value; 175f13bbc2fSNeel Patel } 176f13bbc2fSNeel Patel 177f13bbc2fSNeel Patel static int enic_get_coalesce(struct net_device *netdev, 178f13bbc2fSNeel Patel struct ethtool_coalesce *ecmd) 179f13bbc2fSNeel Patel { 180f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 181f13bbc2fSNeel Patel 182f13bbc2fSNeel Patel ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs; 183f13bbc2fSNeel Patel ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs; 184f13bbc2fSNeel Patel 185f13bbc2fSNeel Patel return 0; 186f13bbc2fSNeel Patel } 187f13bbc2fSNeel Patel 188f13bbc2fSNeel Patel static int enic_set_coalesce(struct net_device *netdev, 189f13bbc2fSNeel Patel struct ethtool_coalesce *ecmd) 190f13bbc2fSNeel Patel { 191f13bbc2fSNeel Patel struct enic *enic = netdev_priv(netdev); 192f13bbc2fSNeel Patel u32 tx_coalesce_usecs; 193f13bbc2fSNeel Patel u32 rx_coalesce_usecs; 194f13bbc2fSNeel Patel unsigned int i, intr; 195f13bbc2fSNeel Patel 196f13bbc2fSNeel Patel tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs, 197f13bbc2fSNeel Patel vnic_dev_get_intr_coal_timer_max(enic->vdev)); 198f13bbc2fSNeel Patel rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs, 199f13bbc2fSNeel Patel vnic_dev_get_intr_coal_timer_max(enic->vdev)); 200f13bbc2fSNeel Patel 201f13bbc2fSNeel Patel switch (vnic_dev_get_intr_mode(enic->vdev)) { 202f13bbc2fSNeel Patel case VNIC_DEV_INTR_MODE_INTX: 203f13bbc2fSNeel Patel if (tx_coalesce_usecs != rx_coalesce_usecs) 204f13bbc2fSNeel Patel return -EINVAL; 205f13bbc2fSNeel Patel 206f13bbc2fSNeel Patel intr = enic_legacy_io_intr(); 207f13bbc2fSNeel Patel vnic_intr_coalescing_timer_set(&enic->intr[intr], 208f13bbc2fSNeel Patel tx_coalesce_usecs); 209f13bbc2fSNeel Patel break; 210f13bbc2fSNeel Patel case VNIC_DEV_INTR_MODE_MSI: 211f13bbc2fSNeel Patel if (tx_coalesce_usecs != rx_coalesce_usecs) 212f13bbc2fSNeel Patel return -EINVAL; 213f13bbc2fSNeel Patel 214f13bbc2fSNeel Patel vnic_intr_coalescing_timer_set(&enic->intr[0], 215f13bbc2fSNeel Patel tx_coalesce_usecs); 216f13bbc2fSNeel Patel break; 217f13bbc2fSNeel Patel case VNIC_DEV_INTR_MODE_MSIX: 218f13bbc2fSNeel Patel for (i = 0; i < enic->wq_count; i++) { 219f13bbc2fSNeel Patel intr = enic_msix_wq_intr(enic, i); 220f13bbc2fSNeel Patel vnic_intr_coalescing_timer_set(&enic->intr[intr], 221f13bbc2fSNeel Patel tx_coalesce_usecs); 222f13bbc2fSNeel Patel } 223f13bbc2fSNeel Patel 224f13bbc2fSNeel Patel for (i = 0; i < enic->rq_count; i++) { 225f13bbc2fSNeel Patel intr = enic_msix_rq_intr(enic, i); 226f13bbc2fSNeel Patel vnic_intr_coalescing_timer_set(&enic->intr[intr], 227f13bbc2fSNeel Patel rx_coalesce_usecs); 228f13bbc2fSNeel Patel } 229f13bbc2fSNeel Patel 230f13bbc2fSNeel Patel break; 231f13bbc2fSNeel Patel default: 232f13bbc2fSNeel Patel break; 233f13bbc2fSNeel Patel } 234f13bbc2fSNeel Patel 235f13bbc2fSNeel Patel enic->tx_coalesce_usecs = tx_coalesce_usecs; 236f13bbc2fSNeel Patel enic->rx_coalesce_usecs = rx_coalesce_usecs; 237f13bbc2fSNeel Patel 238f13bbc2fSNeel Patel return 0; 239f13bbc2fSNeel Patel } 240f13bbc2fSNeel Patel 241f13bbc2fSNeel Patel static const struct ethtool_ops enic_ethtool_ops = { 242f13bbc2fSNeel Patel .get_settings = enic_get_settings, 243f13bbc2fSNeel Patel .get_drvinfo = enic_get_drvinfo, 244f13bbc2fSNeel Patel .get_msglevel = enic_get_msglevel, 245f13bbc2fSNeel Patel .set_msglevel = enic_set_msglevel, 246f13bbc2fSNeel Patel .get_link = ethtool_op_get_link, 247f13bbc2fSNeel Patel .get_strings = enic_get_strings, 248f13bbc2fSNeel Patel .get_sset_count = enic_get_sset_count, 249f13bbc2fSNeel Patel .get_ethtool_stats = enic_get_ethtool_stats, 250f13bbc2fSNeel Patel .get_coalesce = enic_get_coalesce, 251f13bbc2fSNeel Patel .set_coalesce = enic_set_coalesce, 252f13bbc2fSNeel Patel }; 253f13bbc2fSNeel Patel 254f13bbc2fSNeel Patel void enic_set_ethtool_ops(struct net_device *netdev) 255f13bbc2fSNeel Patel { 256f13bbc2fSNeel Patel SET_ETHTOOL_OPS(netdev, &enic_ethtool_ops); 257f13bbc2fSNeel Patel } 258