1 /** 2 * Copyright 2013 Cisco Systems, Inc. All rights reserved. 3 * 4 * This program is free software; you may redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; version 2 of the License. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 15 * SOFTWARE. 16 * 17 */ 18 19 #include <linux/netdevice.h> 20 #include <linux/ethtool.h> 21 22 #include "enic_res.h" 23 #include "enic.h" 24 #include "enic_dev.h" 25 26 struct enic_stat { 27 char name[ETH_GSTRING_LEN]; 28 unsigned int index; 29 }; 30 31 #define ENIC_TX_STAT(stat) { \ 32 .name = #stat, \ 33 .index = offsetof(struct vnic_tx_stats, stat) / sizeof(u64) \ 34 } 35 36 #define ENIC_RX_STAT(stat) { \ 37 .name = #stat, \ 38 .index = offsetof(struct vnic_rx_stats, stat) / sizeof(u64) \ 39 } 40 41 static const struct enic_stat enic_tx_stats[] = { 42 ENIC_TX_STAT(tx_frames_ok), 43 ENIC_TX_STAT(tx_unicast_frames_ok), 44 ENIC_TX_STAT(tx_multicast_frames_ok), 45 ENIC_TX_STAT(tx_broadcast_frames_ok), 46 ENIC_TX_STAT(tx_bytes_ok), 47 ENIC_TX_STAT(tx_unicast_bytes_ok), 48 ENIC_TX_STAT(tx_multicast_bytes_ok), 49 ENIC_TX_STAT(tx_broadcast_bytes_ok), 50 ENIC_TX_STAT(tx_drops), 51 ENIC_TX_STAT(tx_errors), 52 ENIC_TX_STAT(tx_tso), 53 }; 54 55 static const struct enic_stat enic_rx_stats[] = { 56 ENIC_RX_STAT(rx_frames_ok), 57 ENIC_RX_STAT(rx_frames_total), 58 ENIC_RX_STAT(rx_unicast_frames_ok), 59 ENIC_RX_STAT(rx_multicast_frames_ok), 60 ENIC_RX_STAT(rx_broadcast_frames_ok), 61 ENIC_RX_STAT(rx_bytes_ok), 62 ENIC_RX_STAT(rx_unicast_bytes_ok), 63 ENIC_RX_STAT(rx_multicast_bytes_ok), 64 ENIC_RX_STAT(rx_broadcast_bytes_ok), 65 ENIC_RX_STAT(rx_drop), 66 ENIC_RX_STAT(rx_no_bufs), 67 ENIC_RX_STAT(rx_errors), 68 ENIC_RX_STAT(rx_rss), 69 ENIC_RX_STAT(rx_crc_errors), 70 ENIC_RX_STAT(rx_frames_64), 71 ENIC_RX_STAT(rx_frames_127), 72 ENIC_RX_STAT(rx_frames_255), 73 ENIC_RX_STAT(rx_frames_511), 74 ENIC_RX_STAT(rx_frames_1023), 75 ENIC_RX_STAT(rx_frames_1518), 76 ENIC_RX_STAT(rx_frames_to_max), 77 }; 78 79 static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats); 80 static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats); 81 82 static int enic_get_settings(struct net_device *netdev, 83 struct ethtool_cmd *ecmd) 84 { 85 struct enic *enic = netdev_priv(netdev); 86 87 ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); 88 ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); 89 ecmd->port = PORT_FIBRE; 90 ecmd->transceiver = XCVR_EXTERNAL; 91 92 if (netif_carrier_ok(netdev)) { 93 ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev)); 94 ecmd->duplex = DUPLEX_FULL; 95 } else { 96 ethtool_cmd_speed_set(ecmd, -1); 97 ecmd->duplex = -1; 98 } 99 100 ecmd->autoneg = AUTONEG_DISABLE; 101 102 return 0; 103 } 104 105 static void enic_get_drvinfo(struct net_device *netdev, 106 struct ethtool_drvinfo *drvinfo) 107 { 108 struct enic *enic = netdev_priv(netdev); 109 struct vnic_devcmd_fw_info *fw_info; 110 111 enic_dev_fw_info(enic, &fw_info); 112 113 strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); 114 strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); 115 strlcpy(drvinfo->fw_version, fw_info->fw_version, 116 sizeof(drvinfo->fw_version)); 117 strlcpy(drvinfo->bus_info, pci_name(enic->pdev), 118 sizeof(drvinfo->bus_info)); 119 } 120 121 static void enic_get_strings(struct net_device *netdev, u32 stringset, 122 u8 *data) 123 { 124 unsigned int i; 125 126 switch (stringset) { 127 case ETH_SS_STATS: 128 for (i = 0; i < enic_n_tx_stats; i++) { 129 memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN); 130 data += ETH_GSTRING_LEN; 131 } 132 for (i = 0; i < enic_n_rx_stats; i++) { 133 memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN); 134 data += ETH_GSTRING_LEN; 135 } 136 break; 137 } 138 } 139 140 static int enic_get_sset_count(struct net_device *netdev, int sset) 141 { 142 switch (sset) { 143 case ETH_SS_STATS: 144 return enic_n_tx_stats + enic_n_rx_stats; 145 default: 146 return -EOPNOTSUPP; 147 } 148 } 149 150 static void enic_get_ethtool_stats(struct net_device *netdev, 151 struct ethtool_stats *stats, u64 *data) 152 { 153 struct enic *enic = netdev_priv(netdev); 154 struct vnic_stats *vstats; 155 unsigned int i; 156 157 enic_dev_stats_dump(enic, &vstats); 158 159 for (i = 0; i < enic_n_tx_stats; i++) 160 *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index]; 161 for (i = 0; i < enic_n_rx_stats; i++) 162 *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index]; 163 } 164 165 static u32 enic_get_msglevel(struct net_device *netdev) 166 { 167 struct enic *enic = netdev_priv(netdev); 168 return enic->msg_enable; 169 } 170 171 static void enic_set_msglevel(struct net_device *netdev, u32 value) 172 { 173 struct enic *enic = netdev_priv(netdev); 174 enic->msg_enable = value; 175 } 176 177 static int enic_get_coalesce(struct net_device *netdev, 178 struct ethtool_coalesce *ecmd) 179 { 180 struct enic *enic = netdev_priv(netdev); 181 182 ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs; 183 ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs; 184 185 return 0; 186 } 187 188 static int enic_set_coalesce(struct net_device *netdev, 189 struct ethtool_coalesce *ecmd) 190 { 191 struct enic *enic = netdev_priv(netdev); 192 u32 tx_coalesce_usecs; 193 u32 rx_coalesce_usecs; 194 unsigned int i, intr; 195 196 tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs, 197 vnic_dev_get_intr_coal_timer_max(enic->vdev)); 198 rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs, 199 vnic_dev_get_intr_coal_timer_max(enic->vdev)); 200 201 switch (vnic_dev_get_intr_mode(enic->vdev)) { 202 case VNIC_DEV_INTR_MODE_INTX: 203 if (tx_coalesce_usecs != rx_coalesce_usecs) 204 return -EINVAL; 205 206 intr = enic_legacy_io_intr(); 207 vnic_intr_coalescing_timer_set(&enic->intr[intr], 208 tx_coalesce_usecs); 209 break; 210 case VNIC_DEV_INTR_MODE_MSI: 211 if (tx_coalesce_usecs != rx_coalesce_usecs) 212 return -EINVAL; 213 214 vnic_intr_coalescing_timer_set(&enic->intr[0], 215 tx_coalesce_usecs); 216 break; 217 case VNIC_DEV_INTR_MODE_MSIX: 218 for (i = 0; i < enic->wq_count; i++) { 219 intr = enic_msix_wq_intr(enic, i); 220 vnic_intr_coalescing_timer_set(&enic->intr[intr], 221 tx_coalesce_usecs); 222 } 223 224 for (i = 0; i < enic->rq_count; i++) { 225 intr = enic_msix_rq_intr(enic, i); 226 vnic_intr_coalescing_timer_set(&enic->intr[intr], 227 rx_coalesce_usecs); 228 } 229 230 break; 231 default: 232 break; 233 } 234 235 enic->tx_coalesce_usecs = tx_coalesce_usecs; 236 enic->rx_coalesce_usecs = rx_coalesce_usecs; 237 238 return 0; 239 } 240 241 static const struct ethtool_ops enic_ethtool_ops = { 242 .get_settings = enic_get_settings, 243 .get_drvinfo = enic_get_drvinfo, 244 .get_msglevel = enic_get_msglevel, 245 .set_msglevel = enic_set_msglevel, 246 .get_link = ethtool_op_get_link, 247 .get_strings = enic_get_strings, 248 .get_sset_count = enic_get_sset_count, 249 .get_ethtool_stats = enic_get_ethtool_stats, 250 .get_coalesce = enic_get_coalesce, 251 .set_coalesce = enic_set_coalesce, 252 }; 253 254 void enic_set_ethtool_ops(struct net_device *netdev) 255 { 256 SET_ETHTOOL_OPS(netdev, &enic_ethtool_ops); 257 } 258