.. | .. |
---|
1 | 1 | /* |
---|
2 | 2 | * Linux driver for VMware's vmxnet3 ethernet NIC. |
---|
3 | 3 | * |
---|
4 | | - * Copyright (C) 2008-2016, VMware, Inc. All Rights Reserved. |
---|
| 4 | + * Copyright (C) 2008-2021, VMware, Inc. All Rights Reserved. |
---|
5 | 5 | * |
---|
6 | 6 | * This program is free software; you can redistribute it and/or modify it |
---|
7 | 7 | * under the terms of the GNU General Public License as published by the |
---|
.. | .. |
---|
26 | 26 | |
---|
27 | 27 | |
---|
28 | 28 | #include "vmxnet3_int.h" |
---|
| 29 | +#include <net/vxlan.h> |
---|
| 30 | +#include <net/geneve.h> |
---|
| 31 | + |
---|
| 32 | +#define VXLAN_UDP_PORT 8472 |
---|
29 | 33 | |
---|
30 | 34 | struct vmxnet3_stat_desc { |
---|
31 | 35 | char desc[ETH_GSTRING_LEN]; |
---|
.. | .. |
---|
257 | 261 | } |
---|
258 | 262 | } |
---|
259 | 263 | |
---|
| 264 | +netdev_features_t vmxnet3_fix_features(struct net_device *netdev, |
---|
| 265 | + netdev_features_t features) |
---|
| 266 | +{ |
---|
| 267 | + /* If Rx checksum is disabled, then LRO should also be disabled */ |
---|
| 268 | + if (!(features & NETIF_F_RXCSUM)) |
---|
| 269 | + features &= ~NETIF_F_LRO; |
---|
| 270 | + |
---|
| 271 | + return features; |
---|
| 272 | +} |
---|
| 273 | + |
---|
| 274 | +netdev_features_t vmxnet3_features_check(struct sk_buff *skb, |
---|
| 275 | + struct net_device *netdev, |
---|
| 276 | + netdev_features_t features) |
---|
| 277 | +{ |
---|
| 278 | + struct vmxnet3_adapter *adapter = netdev_priv(netdev); |
---|
| 279 | + |
---|
| 280 | + /* Validate if the tunneled packet is being offloaded by the device */ |
---|
| 281 | + if (VMXNET3_VERSION_GE_4(adapter) && |
---|
| 282 | + skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL) { |
---|
| 283 | + u8 l4_proto = 0; |
---|
| 284 | + u16 port; |
---|
| 285 | + struct udphdr *udph; |
---|
| 286 | + |
---|
| 287 | + switch (vlan_get_protocol(skb)) { |
---|
| 288 | + case htons(ETH_P_IP): |
---|
| 289 | + l4_proto = ip_hdr(skb)->protocol; |
---|
| 290 | + break; |
---|
| 291 | + case htons(ETH_P_IPV6): |
---|
| 292 | + l4_proto = ipv6_hdr(skb)->nexthdr; |
---|
| 293 | + break; |
---|
| 294 | + default: |
---|
| 295 | + return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); |
---|
| 296 | + } |
---|
| 297 | + |
---|
| 298 | + switch (l4_proto) { |
---|
| 299 | + case IPPROTO_UDP: |
---|
| 300 | + udph = udp_hdr(skb); |
---|
| 301 | + port = be16_to_cpu(udph->dest); |
---|
| 302 | + /* Check if offloaded port is supported */ |
---|
| 303 | + if (port != GENEVE_UDP_PORT && |
---|
| 304 | + port != IANA_VXLAN_UDP_PORT && |
---|
| 305 | + port != VXLAN_UDP_PORT) { |
---|
| 306 | + return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); |
---|
| 307 | + } |
---|
| 308 | + break; |
---|
| 309 | + default: |
---|
| 310 | + return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); |
---|
| 311 | + } |
---|
| 312 | + } |
---|
| 313 | + return features; |
---|
| 314 | +} |
---|
| 315 | + |
---|
| 316 | +static void vmxnet3_enable_encap_offloads(struct net_device *netdev) |
---|
| 317 | +{ |
---|
| 318 | + struct vmxnet3_adapter *adapter = netdev_priv(netdev); |
---|
| 319 | + |
---|
| 320 | + if (VMXNET3_VERSION_GE_4(adapter)) { |
---|
| 321 | + netdev->hw_enc_features |= NETIF_F_SG | NETIF_F_RXCSUM | |
---|
| 322 | + NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_TX | |
---|
| 323 | + NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_TSO | NETIF_F_TSO6 | |
---|
| 324 | + NETIF_F_LRO | NETIF_F_GSO_UDP_TUNNEL | |
---|
| 325 | + NETIF_F_GSO_UDP_TUNNEL_CSUM; |
---|
| 326 | + } |
---|
| 327 | +} |
---|
| 328 | + |
---|
| 329 | +static void vmxnet3_disable_encap_offloads(struct net_device *netdev) |
---|
| 330 | +{ |
---|
| 331 | + struct vmxnet3_adapter *adapter = netdev_priv(netdev); |
---|
| 332 | + |
---|
| 333 | + if (VMXNET3_VERSION_GE_4(adapter)) { |
---|
| 334 | + netdev->hw_enc_features &= ~(NETIF_F_SG | NETIF_F_RXCSUM | |
---|
| 335 | + NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_TX | |
---|
| 336 | + NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_TSO | NETIF_F_TSO6 | |
---|
| 337 | + NETIF_F_LRO | NETIF_F_GSO_UDP_TUNNEL | |
---|
| 338 | + NETIF_F_GSO_UDP_TUNNEL_CSUM); |
---|
| 339 | + } |
---|
| 340 | +} |
---|
| 341 | + |
---|
260 | 342 | int vmxnet3_set_features(struct net_device *netdev, netdev_features_t features) |
---|
261 | 343 | { |
---|
262 | 344 | struct vmxnet3_adapter *adapter = netdev_priv(netdev); |
---|
263 | 345 | unsigned long flags; |
---|
264 | 346 | netdev_features_t changed = features ^ netdev->features; |
---|
| 347 | + netdev_features_t tun_offload_mask = NETIF_F_GSO_UDP_TUNNEL | |
---|
| 348 | + NETIF_F_GSO_UDP_TUNNEL_CSUM; |
---|
| 349 | + u8 udp_tun_enabled = (netdev->features & tun_offload_mask) != 0; |
---|
265 | 350 | |
---|
266 | 351 | if (changed & (NETIF_F_RXCSUM | NETIF_F_LRO | |
---|
267 | | - NETIF_F_HW_VLAN_CTAG_RX)) { |
---|
| 352 | + NETIF_F_HW_VLAN_CTAG_RX | tun_offload_mask)) { |
---|
268 | 353 | if (features & NETIF_F_RXCSUM) |
---|
269 | 354 | adapter->shared->devRead.misc.uptFeatures |= |
---|
270 | 355 | UPT1_F_RXCSUM; |
---|
.. | .. |
---|
286 | 371 | else |
---|
287 | 372 | adapter->shared->devRead.misc.uptFeatures &= |
---|
288 | 373 | ~UPT1_F_RXVLAN; |
---|
| 374 | + |
---|
| 375 | + if ((features & tun_offload_mask) != 0 && !udp_tun_enabled) { |
---|
| 376 | + vmxnet3_enable_encap_offloads(netdev); |
---|
| 377 | + adapter->shared->devRead.misc.uptFeatures |= |
---|
| 378 | + UPT1_F_RXINNEROFLD; |
---|
| 379 | + } else if ((features & tun_offload_mask) == 0 && |
---|
| 380 | + udp_tun_enabled) { |
---|
| 381 | + vmxnet3_disable_encap_offloads(netdev); |
---|
| 382 | + adapter->shared->devRead.misc.uptFeatures &= |
---|
| 383 | + ~UPT1_F_RXINNEROFLD; |
---|
| 384 | + } |
---|
289 | 385 | |
---|
290 | 386 | spin_lock_irqsave(&adapter->cmd_lock, flags); |
---|
291 | 387 | VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, |
---|
.. | .. |
---|
545 | 641 | } |
---|
546 | 642 | |
---|
547 | 643 | if (VMXNET3_VERSION_GE_3(adapter)) { |
---|
548 | | - if (param->rx_mini_pending < 0 || |
---|
549 | | - param->rx_mini_pending > VMXNET3_RXDATA_DESC_MAX_SIZE) { |
---|
| 644 | + if (param->rx_mini_pending > VMXNET3_RXDATA_DESC_MAX_SIZE) |
---|
550 | 645 | return -EINVAL; |
---|
551 | | - } |
---|
552 | 646 | } else if (param->rx_mini_pending != 0) { |
---|
553 | 647 | return -EINVAL; |
---|
554 | 648 | } |
---|
.. | .. |
---|
657 | 751 | return err; |
---|
658 | 752 | } |
---|
659 | 753 | |
---|
| 754 | +static int |
---|
| 755 | +vmxnet3_get_rss_hash_opts(struct vmxnet3_adapter *adapter, |
---|
| 756 | + struct ethtool_rxnfc *info) |
---|
| 757 | +{ |
---|
| 758 | + enum Vmxnet3_RSSField rss_fields; |
---|
| 759 | + |
---|
| 760 | + if (netif_running(adapter->netdev)) { |
---|
| 761 | + unsigned long flags; |
---|
| 762 | + |
---|
| 763 | + spin_lock_irqsave(&adapter->cmd_lock, flags); |
---|
| 764 | + |
---|
| 765 | + VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, |
---|
| 766 | + VMXNET3_CMD_GET_RSS_FIELDS); |
---|
| 767 | + rss_fields = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD); |
---|
| 768 | + spin_unlock_irqrestore(&adapter->cmd_lock, flags); |
---|
| 769 | + } else { |
---|
| 770 | + rss_fields = adapter->rss_fields; |
---|
| 771 | + } |
---|
| 772 | + |
---|
| 773 | + info->data = 0; |
---|
| 774 | + |
---|
| 775 | + /* Report default options for RSS on vmxnet3 */ |
---|
| 776 | + switch (info->flow_type) { |
---|
| 777 | + case TCP_V4_FLOW: |
---|
| 778 | + case TCP_V6_FLOW: |
---|
| 779 | + info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3 | |
---|
| 780 | + RXH_IP_SRC | RXH_IP_DST; |
---|
| 781 | + break; |
---|
| 782 | + case UDP_V4_FLOW: |
---|
| 783 | + if (rss_fields & VMXNET3_RSS_FIELDS_UDPIP4) |
---|
| 784 | + info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
---|
| 785 | + info->data |= RXH_IP_SRC | RXH_IP_DST; |
---|
| 786 | + break; |
---|
| 787 | + case AH_ESP_V4_FLOW: |
---|
| 788 | + case AH_V4_FLOW: |
---|
| 789 | + case ESP_V4_FLOW: |
---|
| 790 | + if (rss_fields & VMXNET3_RSS_FIELDS_ESPIP4) |
---|
| 791 | + info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
---|
| 792 | + fallthrough; |
---|
| 793 | + case SCTP_V4_FLOW: |
---|
| 794 | + case IPV4_FLOW: |
---|
| 795 | + info->data |= RXH_IP_SRC | RXH_IP_DST; |
---|
| 796 | + break; |
---|
| 797 | + case UDP_V6_FLOW: |
---|
| 798 | + if (rss_fields & VMXNET3_RSS_FIELDS_UDPIP6) |
---|
| 799 | + info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
---|
| 800 | + info->data |= RXH_IP_SRC | RXH_IP_DST; |
---|
| 801 | + break; |
---|
| 802 | + case AH_ESP_V6_FLOW: |
---|
| 803 | + case AH_V6_FLOW: |
---|
| 804 | + case ESP_V6_FLOW: |
---|
| 805 | + case SCTP_V6_FLOW: |
---|
| 806 | + case IPV6_FLOW: |
---|
| 807 | + info->data |= RXH_IP_SRC | RXH_IP_DST; |
---|
| 808 | + break; |
---|
| 809 | + default: |
---|
| 810 | + return -EINVAL; |
---|
| 811 | + } |
---|
| 812 | + |
---|
| 813 | + return 0; |
---|
| 814 | +} |
---|
| 815 | + |
---|
| 816 | +static int |
---|
| 817 | +vmxnet3_set_rss_hash_opt(struct net_device *netdev, |
---|
| 818 | + struct vmxnet3_adapter *adapter, |
---|
| 819 | + struct ethtool_rxnfc *nfc) |
---|
| 820 | +{ |
---|
| 821 | + enum Vmxnet3_RSSField rss_fields = adapter->rss_fields; |
---|
| 822 | + |
---|
| 823 | + /* RSS does not support anything other than hashing |
---|
| 824 | + * to queues on src and dst IPs and ports |
---|
| 825 | + */ |
---|
| 826 | + if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | |
---|
| 827 | + RXH_L4_B_0_1 | RXH_L4_B_2_3)) |
---|
| 828 | + return -EINVAL; |
---|
| 829 | + |
---|
| 830 | + switch (nfc->flow_type) { |
---|
| 831 | + case TCP_V4_FLOW: |
---|
| 832 | + case TCP_V6_FLOW: |
---|
| 833 | + if (!(nfc->data & RXH_IP_SRC) || |
---|
| 834 | + !(nfc->data & RXH_IP_DST) || |
---|
| 835 | + !(nfc->data & RXH_L4_B_0_1) || |
---|
| 836 | + !(nfc->data & RXH_L4_B_2_3)) |
---|
| 837 | + return -EINVAL; |
---|
| 838 | + break; |
---|
| 839 | + case UDP_V4_FLOW: |
---|
| 840 | + if (!(nfc->data & RXH_IP_SRC) || |
---|
| 841 | + !(nfc->data & RXH_IP_DST)) |
---|
| 842 | + return -EINVAL; |
---|
| 843 | + switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { |
---|
| 844 | + case 0: |
---|
| 845 | + rss_fields &= ~VMXNET3_RSS_FIELDS_UDPIP4; |
---|
| 846 | + break; |
---|
| 847 | + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): |
---|
| 848 | + rss_fields |= VMXNET3_RSS_FIELDS_UDPIP4; |
---|
| 849 | + break; |
---|
| 850 | + default: |
---|
| 851 | + return -EINVAL; |
---|
| 852 | + } |
---|
| 853 | + break; |
---|
| 854 | + case UDP_V6_FLOW: |
---|
| 855 | + if (!(nfc->data & RXH_IP_SRC) || |
---|
| 856 | + !(nfc->data & RXH_IP_DST)) |
---|
| 857 | + return -EINVAL; |
---|
| 858 | + switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { |
---|
| 859 | + case 0: |
---|
| 860 | + rss_fields &= ~VMXNET3_RSS_FIELDS_UDPIP6; |
---|
| 861 | + break; |
---|
| 862 | + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): |
---|
| 863 | + rss_fields |= VMXNET3_RSS_FIELDS_UDPIP6; |
---|
| 864 | + break; |
---|
| 865 | + default: |
---|
| 866 | + return -EINVAL; |
---|
| 867 | + } |
---|
| 868 | + break; |
---|
| 869 | + case ESP_V4_FLOW: |
---|
| 870 | + case AH_V4_FLOW: |
---|
| 871 | + case AH_ESP_V4_FLOW: |
---|
| 872 | + if (!(nfc->data & RXH_IP_SRC) || |
---|
| 873 | + !(nfc->data & RXH_IP_DST)) |
---|
| 874 | + return -EINVAL; |
---|
| 875 | + switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { |
---|
| 876 | + case 0: |
---|
| 877 | + rss_fields &= ~VMXNET3_RSS_FIELDS_ESPIP4; |
---|
| 878 | + break; |
---|
| 879 | + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): |
---|
| 880 | + rss_fields |= VMXNET3_RSS_FIELDS_ESPIP4; |
---|
| 881 | + break; |
---|
| 882 | + default: |
---|
| 883 | + return -EINVAL; |
---|
| 884 | + } |
---|
| 885 | + break; |
---|
| 886 | + case ESP_V6_FLOW: |
---|
| 887 | + case AH_V6_FLOW: |
---|
| 888 | + case AH_ESP_V6_FLOW: |
---|
| 889 | + case SCTP_V4_FLOW: |
---|
| 890 | + case SCTP_V6_FLOW: |
---|
| 891 | + if (!(nfc->data & RXH_IP_SRC) || |
---|
| 892 | + !(nfc->data & RXH_IP_DST) || |
---|
| 893 | + (nfc->data & RXH_L4_B_0_1) || |
---|
| 894 | + (nfc->data & RXH_L4_B_2_3)) |
---|
| 895 | + return -EINVAL; |
---|
| 896 | + break; |
---|
| 897 | + default: |
---|
| 898 | + return -EINVAL; |
---|
| 899 | + } |
---|
| 900 | + |
---|
| 901 | + /* if we changed something we need to update flags */ |
---|
| 902 | + if (rss_fields != adapter->rss_fields) { |
---|
| 903 | + adapter->default_rss_fields = false; |
---|
| 904 | + if (netif_running(netdev)) { |
---|
| 905 | + struct Vmxnet3_DriverShared *shared = adapter->shared; |
---|
| 906 | + union Vmxnet3_CmdInfo *cmdInfo = &shared->cu.cmdInfo; |
---|
| 907 | + unsigned long flags; |
---|
| 908 | + |
---|
| 909 | + spin_lock_irqsave(&adapter->cmd_lock, flags); |
---|
| 910 | + cmdInfo->setRssFields = rss_fields; |
---|
| 911 | + VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, |
---|
| 912 | + VMXNET3_CMD_SET_RSS_FIELDS); |
---|
| 913 | + |
---|
| 914 | + /* Not all requested RSS may get applied, so get and |
---|
| 915 | + * cache what was actually applied. |
---|
| 916 | + */ |
---|
| 917 | + VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, |
---|
| 918 | + VMXNET3_CMD_GET_RSS_FIELDS); |
---|
| 919 | + adapter->rss_fields = |
---|
| 920 | + VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD); |
---|
| 921 | + spin_unlock_irqrestore(&adapter->cmd_lock, flags); |
---|
| 922 | + } else { |
---|
| 923 | + /* When the device is activated, we will try to apply |
---|
| 924 | + * these rules and cache the applied value later. |
---|
| 925 | + */ |
---|
| 926 | + adapter->rss_fields = rss_fields; |
---|
| 927 | + } |
---|
| 928 | + } |
---|
| 929 | + return 0; |
---|
| 930 | +} |
---|
660 | 931 | |
---|
661 | 932 | static int |
---|
662 | 933 | vmxnet3_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info, |
---|
663 | 934 | u32 *rules) |
---|
664 | 935 | { |
---|
665 | 936 | struct vmxnet3_adapter *adapter = netdev_priv(netdev); |
---|
| 937 | + int err = 0; |
---|
| 938 | + |
---|
666 | 939 | switch (info->cmd) { |
---|
667 | 940 | case ETHTOOL_GRXRINGS: |
---|
668 | 941 | info->data = adapter->num_rx_queues; |
---|
669 | | - return 0; |
---|
| 942 | + break; |
---|
| 943 | + case ETHTOOL_GRXFH: |
---|
| 944 | + if (!VMXNET3_VERSION_GE_4(adapter)) { |
---|
| 945 | + err = -EOPNOTSUPP; |
---|
| 946 | + break; |
---|
| 947 | + } |
---|
| 948 | +#ifdef VMXNET3_RSS |
---|
| 949 | + if (!adapter->rss) { |
---|
| 950 | + err = -EOPNOTSUPP; |
---|
| 951 | + break; |
---|
| 952 | + } |
---|
| 953 | +#endif |
---|
| 954 | + err = vmxnet3_get_rss_hash_opts(adapter, info); |
---|
| 955 | + break; |
---|
| 956 | + default: |
---|
| 957 | + err = -EOPNOTSUPP; |
---|
| 958 | + break; |
---|
670 | 959 | } |
---|
671 | | - return -EOPNOTSUPP; |
---|
| 960 | + |
---|
| 961 | + return err; |
---|
| 962 | +} |
---|
| 963 | + |
---|
| 964 | +static int |
---|
| 965 | +vmxnet3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info) |
---|
| 966 | +{ |
---|
| 967 | + struct vmxnet3_adapter *adapter = netdev_priv(netdev); |
---|
| 968 | + int err = 0; |
---|
| 969 | + |
---|
| 970 | + if (!VMXNET3_VERSION_GE_4(adapter)) { |
---|
| 971 | + err = -EOPNOTSUPP; |
---|
| 972 | + goto done; |
---|
| 973 | + } |
---|
| 974 | +#ifdef VMXNET3_RSS |
---|
| 975 | + if (!adapter->rss) { |
---|
| 976 | + err = -EOPNOTSUPP; |
---|
| 977 | + goto done; |
---|
| 978 | + } |
---|
| 979 | +#endif |
---|
| 980 | + |
---|
| 981 | + switch (info->cmd) { |
---|
| 982 | + case ETHTOOL_SRXFH: |
---|
| 983 | + err = vmxnet3_set_rss_hash_opt(netdev, adapter, info); |
---|
| 984 | + break; |
---|
| 985 | + default: |
---|
| 986 | + err = -EOPNOTSUPP; |
---|
| 987 | + break; |
---|
| 988 | + } |
---|
| 989 | + |
---|
| 990 | +done: |
---|
| 991 | + return err; |
---|
672 | 992 | } |
---|
673 | 993 | |
---|
674 | 994 | #ifdef VMXNET3_RSS |
---|
.. | .. |
---|
774 | 1094 | if (!VMXNET3_VERSION_GE_3(adapter)) |
---|
775 | 1095 | return -EOPNOTSUPP; |
---|
776 | 1096 | |
---|
777 | | - if (ec->rx_coalesce_usecs_irq || |
---|
778 | | - ec->rx_max_coalesced_frames_irq || |
---|
779 | | - ec->tx_coalesce_usecs || |
---|
780 | | - ec->tx_coalesce_usecs_irq || |
---|
781 | | - ec->tx_max_coalesced_frames_irq || |
---|
782 | | - ec->stats_block_coalesce_usecs || |
---|
783 | | - ec->use_adaptive_tx_coalesce || |
---|
784 | | - ec->pkt_rate_low || |
---|
785 | | - ec->rx_coalesce_usecs_low || |
---|
786 | | - ec->rx_max_coalesced_frames_low || |
---|
787 | | - ec->tx_coalesce_usecs_low || |
---|
788 | | - ec->tx_max_coalesced_frames_low || |
---|
789 | | - ec->pkt_rate_high || |
---|
790 | | - ec->rx_coalesce_usecs_high || |
---|
791 | | - ec->rx_max_coalesced_frames_high || |
---|
792 | | - ec->tx_coalesce_usecs_high || |
---|
793 | | - ec->tx_max_coalesced_frames_high || |
---|
794 | | - ec->rate_sample_interval) { |
---|
795 | | - return -EINVAL; |
---|
796 | | - } |
---|
797 | | - |
---|
798 | 1097 | if ((ec->rx_coalesce_usecs == 0) && |
---|
799 | 1098 | (ec->use_adaptive_rx_coalesce == 0) && |
---|
800 | 1099 | (ec->tx_max_coalesced_frames == 0) && |
---|
.. | .. |
---|
885 | 1184 | } |
---|
886 | 1185 | |
---|
887 | 1186 | static const struct ethtool_ops vmxnet3_ethtool_ops = { |
---|
| 1187 | + .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS | |
---|
| 1188 | + ETHTOOL_COALESCE_MAX_FRAMES | |
---|
| 1189 | + ETHTOOL_COALESCE_USE_ADAPTIVE_RX, |
---|
888 | 1190 | .get_drvinfo = vmxnet3_get_drvinfo, |
---|
889 | 1191 | .get_regs_len = vmxnet3_get_regs_len, |
---|
890 | 1192 | .get_regs = vmxnet3_get_regs, |
---|
.. | .. |
---|
899 | 1201 | .get_ringparam = vmxnet3_get_ringparam, |
---|
900 | 1202 | .set_ringparam = vmxnet3_set_ringparam, |
---|
901 | 1203 | .get_rxnfc = vmxnet3_get_rxnfc, |
---|
| 1204 | + .set_rxnfc = vmxnet3_set_rxnfc, |
---|
902 | 1205 | #ifdef VMXNET3_RSS |
---|
903 | 1206 | .get_rxfh_indir_size = vmxnet3_get_rss_indir_size, |
---|
904 | 1207 | .get_rxfh = vmxnet3_get_rss, |
---|