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#include "enic_clsf.h" 26#include "vnic_rss.h" 27#include "vnic_stats.h" 28 29struct enic_stat { 30 char name[ETH_GSTRING_LEN]; 31 unsigned int index; 32}; 33 34#define ENIC_TX_STAT(stat) { \ 35 .name = #stat, \ 36 .index = offsetof(struct vnic_tx_stats, stat) / sizeof(u64) \ 37} 38 39#define ENIC_RX_STAT(stat) { \ 40 .name = #stat, \ 41 .index = offsetof(struct vnic_rx_stats, stat) / sizeof(u64) \ 42} 43 44#define ENIC_GEN_STAT(stat) { \ 45 .name = #stat, \ 46 .index = offsetof(struct vnic_gen_stats, stat) / sizeof(u64)\ 47} 48 49static const struct enic_stat enic_tx_stats[] = { 50 ENIC_TX_STAT(tx_frames_ok), 51 ENIC_TX_STAT(tx_unicast_frames_ok), 52 ENIC_TX_STAT(tx_multicast_frames_ok), 53 ENIC_TX_STAT(tx_broadcast_frames_ok), 54 ENIC_TX_STAT(tx_bytes_ok), 55 ENIC_TX_STAT(tx_unicast_bytes_ok), 56 ENIC_TX_STAT(tx_multicast_bytes_ok), 57 ENIC_TX_STAT(tx_broadcast_bytes_ok), 58 ENIC_TX_STAT(tx_drops), 59 ENIC_TX_STAT(tx_errors), 60 ENIC_TX_STAT(tx_tso), 61}; 62 63static const struct enic_stat enic_rx_stats[] = { 64 ENIC_RX_STAT(rx_frames_ok), 65 ENIC_RX_STAT(rx_frames_total), 66 ENIC_RX_STAT(rx_unicast_frames_ok), 67 ENIC_RX_STAT(rx_multicast_frames_ok), 68 ENIC_RX_STAT(rx_broadcast_frames_ok), 69 ENIC_RX_STAT(rx_bytes_ok), 70 ENIC_RX_STAT(rx_unicast_bytes_ok), 71 ENIC_RX_STAT(rx_multicast_bytes_ok), 72 ENIC_RX_STAT(rx_broadcast_bytes_ok), 73 ENIC_RX_STAT(rx_drop), 74 ENIC_RX_STAT(rx_no_bufs), 75 ENIC_RX_STAT(rx_errors), 76 ENIC_RX_STAT(rx_rss), 77 ENIC_RX_STAT(rx_crc_errors), 78 ENIC_RX_STAT(rx_frames_64), 79 ENIC_RX_STAT(rx_frames_127), 80 ENIC_RX_STAT(rx_frames_255), 81 ENIC_RX_STAT(rx_frames_511), 82 ENIC_RX_STAT(rx_frames_1023), 83 ENIC_RX_STAT(rx_frames_1518), 84 ENIC_RX_STAT(rx_frames_to_max), 85}; 86 87static const struct enic_stat enic_gen_stats[] = { 88 ENIC_GEN_STAT(dma_map_error), 89}; 90 91static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats); 92static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats); 93static const unsigned int enic_n_gen_stats = ARRAY_SIZE(enic_gen_stats); 94 95static void enic_intr_coal_set_rx(struct enic *enic, u32 timer) 96{ 97 int i; 98 int intr; 99 100 for (i = 0; i < enic->rq_count; i++) { 101 intr = enic_msix_rq_intr(enic, i); 102 vnic_intr_coalescing_timer_set(&enic->intr[intr], timer); 103 } 104} 105 106static int enic_get_settings(struct net_device *netdev, 107 struct ethtool_cmd *ecmd) 108{ 109 struct enic *enic = netdev_priv(netdev); 110 111 ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); 112 ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); 113 ecmd->port = PORT_FIBRE; 114 ecmd->transceiver = XCVR_EXTERNAL; 115 116 if (netif_carrier_ok(netdev)) { 117 ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev)); 118 ecmd->duplex = DUPLEX_FULL; 119 } else { 120 ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN); 121 ecmd->duplex = DUPLEX_UNKNOWN; 122 } 123 124 ecmd->autoneg = AUTONEG_DISABLE; 125 126 return 0; 127} 128 129static void enic_get_drvinfo(struct net_device *netdev, 130 struct ethtool_drvinfo *drvinfo) 131{ 132 struct enic *enic = netdev_priv(netdev); 133 struct vnic_devcmd_fw_info *fw_info; 134 int err; 135 136 err = enic_dev_fw_info(enic, &fw_info); 137 /* return only when pci_zalloc_consistent fails in vnic_dev_fw_info 138 * For other failures, like devcmd failure, we return previously 139 * recorded info. 140 */ 141 if (err == -ENOMEM) 142 return; 143 144 strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); 145 strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); 146 strlcpy(drvinfo->fw_version, fw_info->fw_version, 147 sizeof(drvinfo->fw_version)); 148 strlcpy(drvinfo->bus_info, pci_name(enic->pdev), 149 sizeof(drvinfo->bus_info)); 150} 151 152static void enic_get_strings(struct net_device *netdev, u32 stringset, 153 u8 *data) 154{ 155 unsigned int i; 156 157 switch (stringset) { 158 case ETH_SS_STATS: 159 for (i = 0; i < enic_n_tx_stats; i++) { 160 memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN); 161 data += ETH_GSTRING_LEN; 162 } 163 for (i = 0; i < enic_n_rx_stats; i++) { 164 memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN); 165 data += ETH_GSTRING_LEN; 166 } 167 for (i = 0; i < enic_n_gen_stats; i++) { 168 memcpy(data, enic_gen_stats[i].name, ETH_GSTRING_LEN); 169 data += ETH_GSTRING_LEN; 170 } 171 break; 172 } 173} 174 175static int enic_get_sset_count(struct net_device *netdev, int sset) 176{ 177 switch (sset) { 178 case ETH_SS_STATS: 179 return enic_n_tx_stats + enic_n_rx_stats + enic_n_gen_stats; 180 default: 181 return -EOPNOTSUPP; 182 } 183} 184 185static void enic_get_ethtool_stats(struct net_device *netdev, 186 struct ethtool_stats *stats, u64 *data) 187{ 188 struct enic *enic = netdev_priv(netdev); 189 struct vnic_stats *vstats; 190 unsigned int i; 191 int err; 192 193 err = enic_dev_stats_dump(enic, &vstats); 194 /* return only when pci_zalloc_consistent fails in vnic_dev_stats_dump 195 * For other failures, like devcmd failure, we return previously 196 * recorded stats. 197 */ 198 if (err == -ENOMEM) 199 return; 200 201 for (i = 0; i < enic_n_tx_stats; i++) 202 *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index]; 203 for (i = 0; i < enic_n_rx_stats; i++) 204 *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index]; 205 for (i = 0; i < enic_n_gen_stats; i++) 206 *(data++) = ((u64 *)&enic->gen_stats)[enic_gen_stats[i].index]; 207} 208 209static u32 enic_get_msglevel(struct net_device *netdev) 210{ 211 struct enic *enic = netdev_priv(netdev); 212 return enic->msg_enable; 213} 214 215static void enic_set_msglevel(struct net_device *netdev, u32 value) 216{ 217 struct enic *enic = netdev_priv(netdev); 218 enic->msg_enable = value; 219} 220 221static int enic_get_coalesce(struct net_device *netdev, 222 struct ethtool_coalesce *ecmd) 223{ 224 struct enic *enic = netdev_priv(netdev); 225 struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting; 226 227 ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs; 228 ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs; 229 if (rxcoal->use_adaptive_rx_coalesce) 230 ecmd->use_adaptive_rx_coalesce = 1; 231 ecmd->rx_coalesce_usecs_low = rxcoal->small_pkt_range_start; 232 ecmd->rx_coalesce_usecs_high = rxcoal->range_end; 233 234 return 0; 235} 236 237static int enic_set_coalesce(struct net_device *netdev, 238 struct ethtool_coalesce *ecmd) 239{ 240 struct enic *enic = netdev_priv(netdev); 241 u32 tx_coalesce_usecs; 242 u32 rx_coalesce_usecs; 243 u32 rx_coalesce_usecs_low; 244 u32 rx_coalesce_usecs_high; 245 u32 coalesce_usecs_max; 246 unsigned int i, intr; 247 struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting; 248 249 coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev); 250 tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs, 251 coalesce_usecs_max); 252 rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs, 253 coalesce_usecs_max); 254 255 rx_coalesce_usecs_low = min_t(u32, ecmd->rx_coalesce_usecs_low, 256 coalesce_usecs_max); 257 rx_coalesce_usecs_high = min_t(u32, ecmd->rx_coalesce_usecs_high, 258 coalesce_usecs_max); 259 260 switch (vnic_dev_get_intr_mode(enic->vdev)) { 261 case VNIC_DEV_INTR_MODE_INTX: 262 if (tx_coalesce_usecs != rx_coalesce_usecs) 263 return -EINVAL; 264 if (ecmd->use_adaptive_rx_coalesce || 265 ecmd->rx_coalesce_usecs_low || 266 ecmd->rx_coalesce_usecs_high) 267 return -EINVAL; 268 269 intr = enic_legacy_io_intr(); 270 vnic_intr_coalescing_timer_set(&enic->intr[intr], 271 tx_coalesce_usecs); 272 break; 273 case VNIC_DEV_INTR_MODE_MSI: 274 if (tx_coalesce_usecs != rx_coalesce_usecs) 275 return -EINVAL; 276 if (ecmd->use_adaptive_rx_coalesce || 277 ecmd->rx_coalesce_usecs_low || 278 ecmd->rx_coalesce_usecs_high) 279 return -EINVAL; 280 281 vnic_intr_coalescing_timer_set(&enic->intr[0], 282 tx_coalesce_usecs); 283 break; 284 case VNIC_DEV_INTR_MODE_MSIX: 285 if (ecmd->rx_coalesce_usecs_high && 286 (rx_coalesce_usecs_high < 287 rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF)) 288 return -EINVAL; 289 290 for (i = 0; i < enic->wq_count; i++) { 291 intr = enic_msix_wq_intr(enic, i); 292 vnic_intr_coalescing_timer_set(&enic->intr[intr], 293 tx_coalesce_usecs); 294 } 295 296 rxcoal->use_adaptive_rx_coalesce = 297 !!ecmd->use_adaptive_rx_coalesce; 298 if (!rxcoal->use_adaptive_rx_coalesce) 299 enic_intr_coal_set_rx(enic, rx_coalesce_usecs); 300 301 if (ecmd->rx_coalesce_usecs_high) { 302 rxcoal->range_end = rx_coalesce_usecs_high; 303 rxcoal->small_pkt_range_start = rx_coalesce_usecs_low; 304 rxcoal->large_pkt_range_start = rx_coalesce_usecs_low + 305 ENIC_AIC_LARGE_PKT_DIFF; 306 } 307 break; 308 default: 309 break; 310 } 311 312 enic->tx_coalesce_usecs = tx_coalesce_usecs; 313 enic->rx_coalesce_usecs = rx_coalesce_usecs; 314 315 return 0; 316} 317 318static int enic_grxclsrlall(struct enic *enic, struct ethtool_rxnfc *cmd, 319 u32 *rule_locs) 320{ 321 int j, ret = 0, cnt = 0; 322 323 cmd->data = enic->rfs_h.max - enic->rfs_h.free; 324 for (j = 0; j < (1 << ENIC_RFS_FLW_BITSHIFT); j++) { 325 struct hlist_head *hhead; 326 struct hlist_node *tmp; 327 struct enic_rfs_fltr_node *n; 328 329 hhead = &enic->rfs_h.ht_head[j]; 330 hlist_for_each_entry_safe(n, tmp, hhead, node) { 331 if (cnt == cmd->rule_cnt) 332 return -EMSGSIZE; 333 rule_locs[cnt] = n->fltr_id; 334 cnt++; 335 } 336 } 337 cmd->rule_cnt = cnt; 338 339 return ret; 340} 341 342static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd) 343{ 344 struct ethtool_rx_flow_spec *fsp = 345 (struct ethtool_rx_flow_spec *)&cmd->fs; 346 struct enic_rfs_fltr_node *n; 347 348 n = htbl_fltr_search(enic, (u16)fsp->location); 349 if (!n) 350 return -EINVAL; 351 switch (n->keys.ip_proto) { 352 case IPPROTO_TCP: 353 fsp->flow_type = TCP_V4_FLOW; 354 break; 355 case IPPROTO_UDP: 356 fsp->flow_type = UDP_V4_FLOW; 357 break; 358 default: 359 return -EINVAL; 360 break; 361 } 362 363 fsp->h_u.tcp_ip4_spec.ip4src = n->keys.src; 364 fsp->m_u.tcp_ip4_spec.ip4src = (__u32)~0; 365 366 fsp->h_u.tcp_ip4_spec.ip4dst = n->keys.dst; 367 fsp->m_u.tcp_ip4_spec.ip4dst = (__u32)~0; 368 369 fsp->h_u.tcp_ip4_spec.psrc = n->keys.port16[0]; 370 fsp->m_u.tcp_ip4_spec.psrc = (__u16)~0; 371 372 fsp->h_u.tcp_ip4_spec.pdst = n->keys.port16[1]; 373 fsp->m_u.tcp_ip4_spec.pdst = (__u16)~0; 374 375 fsp->ring_cookie = n->rq_id; 376 377 return 0; 378} 379 380static int enic_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 381 u32 *rule_locs) 382{ 383 struct enic *enic = netdev_priv(dev); 384 int ret = 0; 385 386 switch (cmd->cmd) { 387 case ETHTOOL_GRXRINGS: 388 cmd->data = enic->rq_count; 389 break; 390 case ETHTOOL_GRXCLSRLCNT: 391 spin_lock_bh(&enic->rfs_h.lock); 392 cmd->rule_cnt = enic->rfs_h.max - enic->rfs_h.free; 393 cmd->data = enic->rfs_h.max; 394 spin_unlock_bh(&enic->rfs_h.lock); 395 break; 396 case ETHTOOL_GRXCLSRLALL: 397 spin_lock_bh(&enic->rfs_h.lock); 398 ret = enic_grxclsrlall(enic, cmd, rule_locs); 399 spin_unlock_bh(&enic->rfs_h.lock); 400 break; 401 case ETHTOOL_GRXCLSRULE: 402 spin_lock_bh(&enic->rfs_h.lock); 403 ret = enic_grxclsrule(enic, cmd); 404 spin_unlock_bh(&enic->rfs_h.lock); 405 break; 406 default: 407 ret = -EOPNOTSUPP; 408 break; 409 } 410 411 return ret; 412} 413 414static int enic_get_tunable(struct net_device *dev, 415 const struct ethtool_tunable *tuna, void *data) 416{ 417 struct enic *enic = netdev_priv(dev); 418 int ret = 0; 419 420 switch (tuna->id) { 421 case ETHTOOL_RX_COPYBREAK: 422 *(u32 *)data = enic->rx_copybreak; 423 break; 424 default: 425 ret = -EINVAL; 426 break; 427 } 428 429 return ret; 430} 431 432static int enic_set_tunable(struct net_device *dev, 433 const struct ethtool_tunable *tuna, 434 const void *data) 435{ 436 struct enic *enic = netdev_priv(dev); 437 int ret = 0; 438 439 switch (tuna->id) { 440 case ETHTOOL_RX_COPYBREAK: 441 enic->rx_copybreak = *(u32 *)data; 442 break; 443 default: 444 ret = -EINVAL; 445 break; 446 } 447 448 return ret; 449} 450 451static u32 enic_get_rxfh_key_size(struct net_device *netdev) 452{ 453 return ENIC_RSS_LEN; 454} 455 456static int enic_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey, 457 u8 *hfunc) 458{ 459 struct enic *enic = netdev_priv(netdev); 460 461 if (hkey) 462 memcpy(hkey, enic->rss_key, ENIC_RSS_LEN); 463 464 if (hfunc) 465 *hfunc = ETH_RSS_HASH_TOP; 466 467 return 0; 468} 469 470static int enic_set_rxfh(struct net_device *netdev, const u32 *indir, 471 const u8 *hkey, const u8 hfunc) 472{ 473 struct enic *enic = netdev_priv(netdev); 474 475 if ((hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) || 476 indir) 477 return -EINVAL; 478 479 if (hkey) 480 memcpy(enic->rss_key, hkey, ENIC_RSS_LEN); 481 482 return __enic_set_rsskey(enic); 483} 484 485static const struct ethtool_ops enic_ethtool_ops = { 486 .get_settings = enic_get_settings, 487 .get_drvinfo = enic_get_drvinfo, 488 .get_msglevel = enic_get_msglevel, 489 .set_msglevel = enic_set_msglevel, 490 .get_link = ethtool_op_get_link, 491 .get_strings = enic_get_strings, 492 .get_sset_count = enic_get_sset_count, 493 .get_ethtool_stats = enic_get_ethtool_stats, 494 .get_coalesce = enic_get_coalesce, 495 .set_coalesce = enic_set_coalesce, 496 .get_rxnfc = enic_get_rxnfc, 497 .get_tunable = enic_get_tunable, 498 .set_tunable = enic_set_tunable, 499 .get_rxfh_key_size = enic_get_rxfh_key_size, 500 .get_rxfh = enic_get_rxfh, 501 .set_rxfh = enic_set_rxfh, 502}; 503 504void enic_set_ethtool_ops(struct net_device *netdev) 505{ 506 netdev->ethtool_ops = &enic_ethtool_ops; 507} 508