diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_ethtool.c')
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_ethtool.c | 839 |
1 files changed, 835 insertions, 4 deletions
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index eff37a6c0afa..ac98f1d96892 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c | |||
@@ -2,10 +2,120 @@ | |||
2 | /* Copyright (c) 2018 Intel Corporation */ | 2 | /* Copyright (c) 2018 Intel Corporation */ |
3 | 3 | ||
4 | /* ethtool support for igc */ | 4 | /* ethtool support for igc */ |
5 | #include <linux/if_vlan.h> | ||
5 | #include <linux/pm_runtime.h> | 6 | #include <linux/pm_runtime.h> |
6 | 7 | ||
7 | #include "igc.h" | 8 | #include "igc.h" |
8 | 9 | ||
10 | /* forward declaration */ | ||
11 | struct igc_stats { | ||
12 | char stat_string[ETH_GSTRING_LEN]; | ||
13 | int sizeof_stat; | ||
14 | int stat_offset; | ||
15 | }; | ||
16 | |||
17 | #define IGC_STAT(_name, _stat) { \ | ||
18 | .stat_string = _name, \ | ||
19 | .sizeof_stat = FIELD_SIZEOF(struct igc_adapter, _stat), \ | ||
20 | .stat_offset = offsetof(struct igc_adapter, _stat) \ | ||
21 | } | ||
22 | |||
23 | static const struct igc_stats igc_gstrings_stats[] = { | ||
24 | IGC_STAT("rx_packets", stats.gprc), | ||
25 | IGC_STAT("tx_packets", stats.gptc), | ||
26 | IGC_STAT("rx_bytes", stats.gorc), | ||
27 | IGC_STAT("tx_bytes", stats.gotc), | ||
28 | IGC_STAT("rx_broadcast", stats.bprc), | ||
29 | IGC_STAT("tx_broadcast", stats.bptc), | ||
30 | IGC_STAT("rx_multicast", stats.mprc), | ||
31 | IGC_STAT("tx_multicast", stats.mptc), | ||
32 | IGC_STAT("multicast", stats.mprc), | ||
33 | IGC_STAT("collisions", stats.colc), | ||
34 | IGC_STAT("rx_crc_errors", stats.crcerrs), | ||
35 | IGC_STAT("rx_no_buffer_count", stats.rnbc), | ||
36 | IGC_STAT("rx_missed_errors", stats.mpc), | ||
37 | IGC_STAT("tx_aborted_errors", stats.ecol), | ||
38 | IGC_STAT("tx_carrier_errors", stats.tncrs), | ||
39 | IGC_STAT("tx_window_errors", stats.latecol), | ||
40 | IGC_STAT("tx_abort_late_coll", stats.latecol), | ||
41 | IGC_STAT("tx_deferred_ok", stats.dc), | ||
42 | IGC_STAT("tx_single_coll_ok", stats.scc), | ||
43 | IGC_STAT("tx_multi_coll_ok", stats.mcc), | ||
44 | IGC_STAT("tx_timeout_count", tx_timeout_count), | ||
45 | IGC_STAT("rx_long_length_errors", stats.roc), | ||
46 | IGC_STAT("rx_short_length_errors", stats.ruc), | ||
47 | IGC_STAT("rx_align_errors", stats.algnerrc), | ||
48 | IGC_STAT("tx_tcp_seg_good", stats.tsctc), | ||
49 | IGC_STAT("tx_tcp_seg_failed", stats.tsctfc), | ||
50 | IGC_STAT("rx_flow_control_xon", stats.xonrxc), | ||
51 | IGC_STAT("rx_flow_control_xoff", stats.xoffrxc), | ||
52 | IGC_STAT("tx_flow_control_xon", stats.xontxc), | ||
53 | IGC_STAT("tx_flow_control_xoff", stats.xofftxc), | ||
54 | IGC_STAT("rx_long_byte_count", stats.gorc), | ||
55 | IGC_STAT("tx_dma_out_of_sync", stats.doosync), | ||
56 | IGC_STAT("tx_smbus", stats.mgptc), | ||
57 | IGC_STAT("rx_smbus", stats.mgprc), | ||
58 | IGC_STAT("dropped_smbus", stats.mgpdc), | ||
59 | IGC_STAT("os2bmc_rx_by_bmc", stats.o2bgptc), | ||
60 | IGC_STAT("os2bmc_tx_by_bmc", stats.b2ospc), | ||
61 | IGC_STAT("os2bmc_tx_by_host", stats.o2bspc), | ||
62 | IGC_STAT("os2bmc_rx_by_host", stats.b2ogprc), | ||
63 | IGC_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), | ||
64 | IGC_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped), | ||
65 | IGC_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), | ||
66 | }; | ||
67 | |||
68 | #define IGC_NETDEV_STAT(_net_stat) { \ | ||
69 | .stat_string = __stringify(_net_stat), \ | ||
70 | .sizeof_stat = FIELD_SIZEOF(struct rtnl_link_stats64, _net_stat), \ | ||
71 | .stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \ | ||
72 | } | ||
73 | |||
74 | static const struct igc_stats igc_gstrings_net_stats[] = { | ||
75 | IGC_NETDEV_STAT(rx_errors), | ||
76 | IGC_NETDEV_STAT(tx_errors), | ||
77 | IGC_NETDEV_STAT(tx_dropped), | ||
78 | IGC_NETDEV_STAT(rx_length_errors), | ||
79 | IGC_NETDEV_STAT(rx_over_errors), | ||
80 | IGC_NETDEV_STAT(rx_frame_errors), | ||
81 | IGC_NETDEV_STAT(rx_fifo_errors), | ||
82 | IGC_NETDEV_STAT(tx_fifo_errors), | ||
83 | IGC_NETDEV_STAT(tx_heartbeat_errors) | ||
84 | }; | ||
85 | |||
86 | enum igc_diagnostics_results { | ||
87 | TEST_REG = 0, | ||
88 | TEST_EEP, | ||
89 | TEST_IRQ, | ||
90 | TEST_LOOP, | ||
91 | TEST_LINK | ||
92 | }; | ||
93 | |||
94 | static const char igc_gstrings_test[][ETH_GSTRING_LEN] = { | ||
95 | [TEST_REG] = "Register test (offline)", | ||
96 | [TEST_EEP] = "Eeprom test (offline)", | ||
97 | [TEST_IRQ] = "Interrupt test (offline)", | ||
98 | [TEST_LOOP] = "Loopback test (offline)", | ||
99 | [TEST_LINK] = "Link test (on/offline)" | ||
100 | }; | ||
101 | |||
102 | #define IGC_TEST_LEN (sizeof(igc_gstrings_test) / ETH_GSTRING_LEN) | ||
103 | |||
104 | #define IGC_GLOBAL_STATS_LEN \ | ||
105 | (sizeof(igc_gstrings_stats) / sizeof(struct igc_stats)) | ||
106 | #define IGC_NETDEV_STATS_LEN \ | ||
107 | (sizeof(igc_gstrings_net_stats) / sizeof(struct igc_stats)) | ||
108 | #define IGC_RX_QUEUE_STATS_LEN \ | ||
109 | (sizeof(struct igc_rx_queue_stats) / sizeof(u64)) | ||
110 | #define IGC_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */ | ||
111 | #define IGC_QUEUE_STATS_LEN \ | ||
112 | ((((struct igc_adapter *)netdev_priv(netdev))->num_rx_queues * \ | ||
113 | IGC_RX_QUEUE_STATS_LEN) + \ | ||
114 | (((struct igc_adapter *)netdev_priv(netdev))->num_tx_queues * \ | ||
115 | IGC_TX_QUEUE_STATS_LEN)) | ||
116 | #define IGC_STATS_LEN \ | ||
117 | (IGC_GLOBAL_STATS_LEN + IGC_NETDEV_STATS_LEN + IGC_QUEUE_STATS_LEN) | ||
118 | |||
9 | static const char igc_priv_flags_strings[][ETH_GSTRING_LEN] = { | 119 | static const char igc_priv_flags_strings[][ETH_GSTRING_LEN] = { |
10 | #define IGC_PRIV_FLAGS_LEGACY_RX BIT(0) | 120 | #define IGC_PRIV_FLAGS_LEGACY_RX BIT(0) |
11 | "legacy-rx", | 121 | "legacy-rx", |
@@ -545,6 +655,127 @@ static int igc_set_pauseparam(struct net_device *netdev, | |||
545 | return retval; | 655 | return retval; |
546 | } | 656 | } |
547 | 657 | ||
658 | static void igc_get_strings(struct net_device *netdev, u32 stringset, u8 *data) | ||
659 | { | ||
660 | struct igc_adapter *adapter = netdev_priv(netdev); | ||
661 | u8 *p = data; | ||
662 | int i; | ||
663 | |||
664 | switch (stringset) { | ||
665 | case ETH_SS_TEST: | ||
666 | memcpy(data, *igc_gstrings_test, | ||
667 | IGC_TEST_LEN * ETH_GSTRING_LEN); | ||
668 | break; | ||
669 | case ETH_SS_STATS: | ||
670 | for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) { | ||
671 | memcpy(p, igc_gstrings_stats[i].stat_string, | ||
672 | ETH_GSTRING_LEN); | ||
673 | p += ETH_GSTRING_LEN; | ||
674 | } | ||
675 | for (i = 0; i < IGC_NETDEV_STATS_LEN; i++) { | ||
676 | memcpy(p, igc_gstrings_net_stats[i].stat_string, | ||
677 | ETH_GSTRING_LEN); | ||
678 | p += ETH_GSTRING_LEN; | ||
679 | } | ||
680 | for (i = 0; i < adapter->num_tx_queues; i++) { | ||
681 | sprintf(p, "tx_queue_%u_packets", i); | ||
682 | p += ETH_GSTRING_LEN; | ||
683 | sprintf(p, "tx_queue_%u_bytes", i); | ||
684 | p += ETH_GSTRING_LEN; | ||
685 | sprintf(p, "tx_queue_%u_restart", i); | ||
686 | p += ETH_GSTRING_LEN; | ||
687 | } | ||
688 | for (i = 0; i < adapter->num_rx_queues; i++) { | ||
689 | sprintf(p, "rx_queue_%u_packets", i); | ||
690 | p += ETH_GSTRING_LEN; | ||
691 | sprintf(p, "rx_queue_%u_bytes", i); | ||
692 | p += ETH_GSTRING_LEN; | ||
693 | sprintf(p, "rx_queue_%u_drops", i); | ||
694 | p += ETH_GSTRING_LEN; | ||
695 | sprintf(p, "rx_queue_%u_csum_err", i); | ||
696 | p += ETH_GSTRING_LEN; | ||
697 | sprintf(p, "rx_queue_%u_alloc_failed", i); | ||
698 | p += ETH_GSTRING_LEN; | ||
699 | } | ||
700 | /* BUG_ON(p - data != IGC_STATS_LEN * ETH_GSTRING_LEN); */ | ||
701 | break; | ||
702 | case ETH_SS_PRIV_FLAGS: | ||
703 | memcpy(data, igc_priv_flags_strings, | ||
704 | IGC_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); | ||
705 | break; | ||
706 | } | ||
707 | } | ||
708 | |||
709 | static int igc_get_sset_count(struct net_device *netdev, int sset) | ||
710 | { | ||
711 | switch (sset) { | ||
712 | case ETH_SS_STATS: | ||
713 | return IGC_STATS_LEN; | ||
714 | case ETH_SS_TEST: | ||
715 | return IGC_TEST_LEN; | ||
716 | case ETH_SS_PRIV_FLAGS: | ||
717 | return IGC_PRIV_FLAGS_STR_LEN; | ||
718 | default: | ||
719 | return -ENOTSUPP; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | static void igc_get_ethtool_stats(struct net_device *netdev, | ||
724 | struct ethtool_stats *stats, u64 *data) | ||
725 | { | ||
726 | struct igc_adapter *adapter = netdev_priv(netdev); | ||
727 | struct rtnl_link_stats64 *net_stats = &adapter->stats64; | ||
728 | unsigned int start; | ||
729 | struct igc_ring *ring; | ||
730 | int i, j; | ||
731 | char *p; | ||
732 | |||
733 | spin_lock(&adapter->stats64_lock); | ||
734 | igc_update_stats(adapter); | ||
735 | |||
736 | for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) { | ||
737 | p = (char *)adapter + igc_gstrings_stats[i].stat_offset; | ||
738 | data[i] = (igc_gstrings_stats[i].sizeof_stat == | ||
739 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; | ||
740 | } | ||
741 | for (j = 0; j < IGC_NETDEV_STATS_LEN; j++, i++) { | ||
742 | p = (char *)net_stats + igc_gstrings_net_stats[j].stat_offset; | ||
743 | data[i] = (igc_gstrings_net_stats[j].sizeof_stat == | ||
744 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; | ||
745 | } | ||
746 | for (j = 0; j < adapter->num_tx_queues; j++) { | ||
747 | u64 restart2; | ||
748 | |||
749 | ring = adapter->tx_ring[j]; | ||
750 | do { | ||
751 | start = u64_stats_fetch_begin_irq(&ring->tx_syncp); | ||
752 | data[i] = ring->tx_stats.packets; | ||
753 | data[i + 1] = ring->tx_stats.bytes; | ||
754 | data[i + 2] = ring->tx_stats.restart_queue; | ||
755 | } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); | ||
756 | do { | ||
757 | start = u64_stats_fetch_begin_irq(&ring->tx_syncp2); | ||
758 | restart2 = ring->tx_stats.restart_queue2; | ||
759 | } while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start)); | ||
760 | data[i + 2] += restart2; | ||
761 | |||
762 | i += IGC_TX_QUEUE_STATS_LEN; | ||
763 | } | ||
764 | for (j = 0; j < adapter->num_rx_queues; j++) { | ||
765 | ring = adapter->rx_ring[j]; | ||
766 | do { | ||
767 | start = u64_stats_fetch_begin_irq(&ring->rx_syncp); | ||
768 | data[i] = ring->rx_stats.packets; | ||
769 | data[i + 1] = ring->rx_stats.bytes; | ||
770 | data[i + 2] = ring->rx_stats.drops; | ||
771 | data[i + 3] = ring->rx_stats.csum_err; | ||
772 | data[i + 4] = ring->rx_stats.alloc_failed; | ||
773 | } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); | ||
774 | i += IGC_RX_QUEUE_STATS_LEN; | ||
775 | } | ||
776 | spin_unlock(&adapter->stats64_lock); | ||
777 | } | ||
778 | |||
548 | static int igc_get_coalesce(struct net_device *netdev, | 779 | static int igc_get_coalesce(struct net_device *netdev, |
549 | struct ethtool_coalesce *ec) | 780 | struct ethtool_coalesce *ec) |
550 | { | 781 | { |
@@ -643,6 +874,605 @@ static int igc_set_coalesce(struct net_device *netdev, | |||
643 | return 0; | 874 | return 0; |
644 | } | 875 | } |
645 | 876 | ||
877 | #define ETHER_TYPE_FULL_MASK ((__force __be16)~0) | ||
878 | static int igc_get_ethtool_nfc_entry(struct igc_adapter *adapter, | ||
879 | struct ethtool_rxnfc *cmd) | ||
880 | { | ||
881 | struct ethtool_rx_flow_spec *fsp = &cmd->fs; | ||
882 | struct igc_nfc_filter *rule = NULL; | ||
883 | |||
884 | /* report total rule count */ | ||
885 | cmd->data = IGC_MAX_RXNFC_FILTERS; | ||
886 | |||
887 | hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { | ||
888 | if (fsp->location <= rule->sw_idx) | ||
889 | break; | ||
890 | } | ||
891 | |||
892 | if (!rule || fsp->location != rule->sw_idx) | ||
893 | return -EINVAL; | ||
894 | |||
895 | if (rule->filter.match_flags) { | ||
896 | fsp->flow_type = ETHER_FLOW; | ||
897 | fsp->ring_cookie = rule->action; | ||
898 | if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) { | ||
899 | fsp->h_u.ether_spec.h_proto = rule->filter.etype; | ||
900 | fsp->m_u.ether_spec.h_proto = ETHER_TYPE_FULL_MASK; | ||
901 | } | ||
902 | if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) { | ||
903 | fsp->flow_type |= FLOW_EXT; | ||
904 | fsp->h_ext.vlan_tci = rule->filter.vlan_tci; | ||
905 | fsp->m_ext.vlan_tci = htons(VLAN_PRIO_MASK); | ||
906 | } | ||
907 | if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) { | ||
908 | ether_addr_copy(fsp->h_u.ether_spec.h_dest, | ||
909 | rule->filter.dst_addr); | ||
910 | /* As we only support matching by the full | ||
911 | * mask, return the mask to userspace | ||
912 | */ | ||
913 | eth_broadcast_addr(fsp->m_u.ether_spec.h_dest); | ||
914 | } | ||
915 | if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) { | ||
916 | ether_addr_copy(fsp->h_u.ether_spec.h_source, | ||
917 | rule->filter.src_addr); | ||
918 | /* As we only support matching by the full | ||
919 | * mask, return the mask to userspace | ||
920 | */ | ||
921 | eth_broadcast_addr(fsp->m_u.ether_spec.h_source); | ||
922 | } | ||
923 | |||
924 | return 0; | ||
925 | } | ||
926 | return -EINVAL; | ||
927 | } | ||
928 | |||
929 | static int igc_get_ethtool_nfc_all(struct igc_adapter *adapter, | ||
930 | struct ethtool_rxnfc *cmd, | ||
931 | u32 *rule_locs) | ||
932 | { | ||
933 | struct igc_nfc_filter *rule; | ||
934 | int cnt = 0; | ||
935 | |||
936 | /* report total rule count */ | ||
937 | cmd->data = IGC_MAX_RXNFC_FILTERS; | ||
938 | |||
939 | hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { | ||
940 | if (cnt == cmd->rule_cnt) | ||
941 | return -EMSGSIZE; | ||
942 | rule_locs[cnt] = rule->sw_idx; | ||
943 | cnt++; | ||
944 | } | ||
945 | |||
946 | cmd->rule_cnt = cnt; | ||
947 | |||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | static int igc_get_rss_hash_opts(struct igc_adapter *adapter, | ||
952 | struct ethtool_rxnfc *cmd) | ||
953 | { | ||
954 | cmd->data = 0; | ||
955 | |||
956 | /* Report default options for RSS on igc */ | ||
957 | switch (cmd->flow_type) { | ||
958 | case TCP_V4_FLOW: | ||
959 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | ||
960 | /* Fall through */ | ||
961 | case UDP_V4_FLOW: | ||
962 | if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV4_UDP) | ||
963 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | ||
964 | /* Fall through */ | ||
965 | case SCTP_V4_FLOW: | ||
966 | /* Fall through */ | ||
967 | case AH_ESP_V4_FLOW: | ||
968 | /* Fall through */ | ||
969 | case AH_V4_FLOW: | ||
970 | /* Fall through */ | ||
971 | case ESP_V4_FLOW: | ||
972 | /* Fall through */ | ||
973 | case IPV4_FLOW: | ||
974 | cmd->data |= RXH_IP_SRC | RXH_IP_DST; | ||
975 | break; | ||
976 | case TCP_V6_FLOW: | ||
977 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | ||
978 | /* Fall through */ | ||
979 | case UDP_V6_FLOW: | ||
980 | if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV6_UDP) | ||
981 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | ||
982 | /* Fall through */ | ||
983 | case SCTP_V6_FLOW: | ||
984 | /* Fall through */ | ||
985 | case AH_ESP_V6_FLOW: | ||
986 | /* Fall through */ | ||
987 | case AH_V6_FLOW: | ||
988 | /* Fall through */ | ||
989 | case ESP_V6_FLOW: | ||
990 | /* Fall through */ | ||
991 | case IPV6_FLOW: | ||
992 | cmd->data |= RXH_IP_SRC | RXH_IP_DST; | ||
993 | break; | ||
994 | default: | ||
995 | return -EINVAL; | ||
996 | } | ||
997 | |||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | static int igc_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, | ||
1002 | u32 *rule_locs) | ||
1003 | { | ||
1004 | struct igc_adapter *adapter = netdev_priv(dev); | ||
1005 | int ret = -EOPNOTSUPP; | ||
1006 | |||
1007 | switch (cmd->cmd) { | ||
1008 | case ETHTOOL_GRXRINGS: | ||
1009 | cmd->data = adapter->num_rx_queues; | ||
1010 | ret = 0; | ||
1011 | break; | ||
1012 | case ETHTOOL_GRXCLSRLCNT: | ||
1013 | cmd->rule_cnt = adapter->nfc_filter_count; | ||
1014 | ret = 0; | ||
1015 | break; | ||
1016 | case ETHTOOL_GRXCLSRULE: | ||
1017 | ret = igc_get_ethtool_nfc_entry(adapter, cmd); | ||
1018 | break; | ||
1019 | case ETHTOOL_GRXCLSRLALL: | ||
1020 | ret = igc_get_ethtool_nfc_all(adapter, cmd, rule_locs); | ||
1021 | break; | ||
1022 | case ETHTOOL_GRXFH: | ||
1023 | ret = igc_get_rss_hash_opts(adapter, cmd); | ||
1024 | break; | ||
1025 | default: | ||
1026 | break; | ||
1027 | } | ||
1028 | |||
1029 | return ret; | ||
1030 | } | ||
1031 | |||
1032 | #define UDP_RSS_FLAGS (IGC_FLAG_RSS_FIELD_IPV4_UDP | \ | ||
1033 | IGC_FLAG_RSS_FIELD_IPV6_UDP) | ||
1034 | static int igc_set_rss_hash_opt(struct igc_adapter *adapter, | ||
1035 | struct ethtool_rxnfc *nfc) | ||
1036 | { | ||
1037 | u32 flags = adapter->flags; | ||
1038 | |||
1039 | /* RSS does not support anything other than hashing | ||
1040 | * to queues on src and dst IPs and ports | ||
1041 | */ | ||
1042 | if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | | ||
1043 | RXH_L4_B_0_1 | RXH_L4_B_2_3)) | ||
1044 | return -EINVAL; | ||
1045 | |||
1046 | switch (nfc->flow_type) { | ||
1047 | case TCP_V4_FLOW: | ||
1048 | case TCP_V6_FLOW: | ||
1049 | if (!(nfc->data & RXH_IP_SRC) || | ||
1050 | !(nfc->data & RXH_IP_DST) || | ||
1051 | !(nfc->data & RXH_L4_B_0_1) || | ||
1052 | !(nfc->data & RXH_L4_B_2_3)) | ||
1053 | return -EINVAL; | ||
1054 | break; | ||
1055 | case UDP_V4_FLOW: | ||
1056 | if (!(nfc->data & RXH_IP_SRC) || | ||
1057 | !(nfc->data & RXH_IP_DST)) | ||
1058 | return -EINVAL; | ||
1059 | switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { | ||
1060 | case 0: | ||
1061 | flags &= ~IGC_FLAG_RSS_FIELD_IPV4_UDP; | ||
1062 | break; | ||
1063 | case (RXH_L4_B_0_1 | RXH_L4_B_2_3): | ||
1064 | flags |= IGC_FLAG_RSS_FIELD_IPV4_UDP; | ||
1065 | break; | ||
1066 | default: | ||
1067 | return -EINVAL; | ||
1068 | } | ||
1069 | break; | ||
1070 | case UDP_V6_FLOW: | ||
1071 | if (!(nfc->data & RXH_IP_SRC) || | ||
1072 | !(nfc->data & RXH_IP_DST)) | ||
1073 | return -EINVAL; | ||
1074 | switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { | ||
1075 | case 0: | ||
1076 | flags &= ~IGC_FLAG_RSS_FIELD_IPV6_UDP; | ||
1077 | break; | ||
1078 | case (RXH_L4_B_0_1 | RXH_L4_B_2_3): | ||
1079 | flags |= IGC_FLAG_RSS_FIELD_IPV6_UDP; | ||
1080 | break; | ||
1081 | default: | ||
1082 | return -EINVAL; | ||
1083 | } | ||
1084 | break; | ||
1085 | case AH_ESP_V4_FLOW: | ||
1086 | case AH_V4_FLOW: | ||
1087 | case ESP_V4_FLOW: | ||
1088 | case SCTP_V4_FLOW: | ||
1089 | case AH_ESP_V6_FLOW: | ||
1090 | case AH_V6_FLOW: | ||
1091 | case ESP_V6_FLOW: | ||
1092 | case SCTP_V6_FLOW: | ||
1093 | if (!(nfc->data & RXH_IP_SRC) || | ||
1094 | !(nfc->data & RXH_IP_DST) || | ||
1095 | (nfc->data & RXH_L4_B_0_1) || | ||
1096 | (nfc->data & RXH_L4_B_2_3)) | ||
1097 | return -EINVAL; | ||
1098 | break; | ||
1099 | default: | ||
1100 | return -EINVAL; | ||
1101 | } | ||
1102 | |||
1103 | /* if we changed something we need to update flags */ | ||
1104 | if (flags != adapter->flags) { | ||
1105 | struct igc_hw *hw = &adapter->hw; | ||
1106 | u32 mrqc = rd32(IGC_MRQC); | ||
1107 | |||
1108 | if ((flags & UDP_RSS_FLAGS) && | ||
1109 | !(adapter->flags & UDP_RSS_FLAGS)) | ||
1110 | dev_err(&adapter->pdev->dev, | ||
1111 | "enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n"); | ||
1112 | |||
1113 | adapter->flags = flags; | ||
1114 | |||
1115 | /* Perform hash on these packet types */ | ||
1116 | mrqc |= IGC_MRQC_RSS_FIELD_IPV4 | | ||
1117 | IGC_MRQC_RSS_FIELD_IPV4_TCP | | ||
1118 | IGC_MRQC_RSS_FIELD_IPV6 | | ||
1119 | IGC_MRQC_RSS_FIELD_IPV6_TCP; | ||
1120 | |||
1121 | mrqc &= ~(IGC_MRQC_RSS_FIELD_IPV4_UDP | | ||
1122 | IGC_MRQC_RSS_FIELD_IPV6_UDP); | ||
1123 | |||
1124 | if (flags & IGC_FLAG_RSS_FIELD_IPV4_UDP) | ||
1125 | mrqc |= IGC_MRQC_RSS_FIELD_IPV4_UDP; | ||
1126 | |||
1127 | if (flags & IGC_FLAG_RSS_FIELD_IPV6_UDP) | ||
1128 | mrqc |= IGC_MRQC_RSS_FIELD_IPV6_UDP; | ||
1129 | |||
1130 | wr32(IGC_MRQC, mrqc); | ||
1131 | } | ||
1132 | |||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | static int igc_rxnfc_write_etype_filter(struct igc_adapter *adapter, | ||
1137 | struct igc_nfc_filter *input) | ||
1138 | { | ||
1139 | struct igc_hw *hw = &adapter->hw; | ||
1140 | u8 i; | ||
1141 | u32 etqf; | ||
1142 | u16 etype; | ||
1143 | |||
1144 | /* find an empty etype filter register */ | ||
1145 | for (i = 0; i < MAX_ETYPE_FILTER; ++i) { | ||
1146 | if (!adapter->etype_bitmap[i]) | ||
1147 | break; | ||
1148 | } | ||
1149 | if (i == MAX_ETYPE_FILTER) { | ||
1150 | dev_err(&adapter->pdev->dev, "ethtool -N: etype filters are all used.\n"); | ||
1151 | return -EINVAL; | ||
1152 | } | ||
1153 | |||
1154 | adapter->etype_bitmap[i] = true; | ||
1155 | |||
1156 | etqf = rd32(IGC_ETQF(i)); | ||
1157 | etype = ntohs(input->filter.etype & ETHER_TYPE_FULL_MASK); | ||
1158 | |||
1159 | etqf |= IGC_ETQF_FILTER_ENABLE; | ||
1160 | etqf &= ~IGC_ETQF_ETYPE_MASK; | ||
1161 | etqf |= (etype & IGC_ETQF_ETYPE_MASK); | ||
1162 | |||
1163 | etqf &= ~IGC_ETQF_QUEUE_MASK; | ||
1164 | etqf |= ((input->action << IGC_ETQF_QUEUE_SHIFT) | ||
1165 | & IGC_ETQF_QUEUE_MASK); | ||
1166 | etqf |= IGC_ETQF_QUEUE_ENABLE; | ||
1167 | |||
1168 | wr32(IGC_ETQF(i), etqf); | ||
1169 | |||
1170 | input->etype_reg_index = i; | ||
1171 | |||
1172 | return 0; | ||
1173 | } | ||
1174 | |||
1175 | static int igc_rxnfc_write_vlan_prio_filter(struct igc_adapter *adapter, | ||
1176 | struct igc_nfc_filter *input) | ||
1177 | { | ||
1178 | struct igc_hw *hw = &adapter->hw; | ||
1179 | u8 vlan_priority; | ||
1180 | u16 queue_index; | ||
1181 | u32 vlapqf; | ||
1182 | |||
1183 | vlapqf = rd32(IGC_VLAPQF); | ||
1184 | vlan_priority = (ntohs(input->filter.vlan_tci) & VLAN_PRIO_MASK) | ||
1185 | >> VLAN_PRIO_SHIFT; | ||
1186 | queue_index = (vlapqf >> (vlan_priority * 4)) & IGC_VLAPQF_QUEUE_MASK; | ||
1187 | |||
1188 | /* check whether this vlan prio is already set */ | ||
1189 | if (vlapqf & IGC_VLAPQF_P_VALID(vlan_priority) && | ||
1190 | queue_index != input->action) { | ||
1191 | dev_err(&adapter->pdev->dev, "ethtool rxnfc set vlan prio filter failed.\n"); | ||
1192 | return -EEXIST; | ||
1193 | } | ||
1194 | |||
1195 | vlapqf |= IGC_VLAPQF_P_VALID(vlan_priority); | ||
1196 | vlapqf |= IGC_VLAPQF_QUEUE_SEL(vlan_priority, input->action); | ||
1197 | |||
1198 | wr32(IGC_VLAPQF, vlapqf); | ||
1199 | |||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | int igc_add_filter(struct igc_adapter *adapter, struct igc_nfc_filter *input) | ||
1204 | { | ||
1205 | struct igc_hw *hw = &adapter->hw; | ||
1206 | int err = -EINVAL; | ||
1207 | |||
1208 | if (hw->mac.type == igc_i225 && | ||
1209 | !(input->filter.match_flags & ~IGC_FILTER_FLAG_SRC_MAC_ADDR)) { | ||
1210 | dev_err(&adapter->pdev->dev, | ||
1211 | "i225 doesn't support flow classification rules specifying only source addresses.\n"); | ||
1212 | return -EOPNOTSUPP; | ||
1213 | } | ||
1214 | |||
1215 | if (input->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) { | ||
1216 | err = igc_rxnfc_write_etype_filter(adapter, input); | ||
1217 | if (err) | ||
1218 | return err; | ||
1219 | } | ||
1220 | |||
1221 | if (input->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) { | ||
1222 | err = igc_add_mac_steering_filter(adapter, | ||
1223 | input->filter.dst_addr, | ||
1224 | input->action, 0); | ||
1225 | err = min_t(int, err, 0); | ||
1226 | if (err) | ||
1227 | return err; | ||
1228 | } | ||
1229 | |||
1230 | if (input->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) { | ||
1231 | err = igc_add_mac_steering_filter(adapter, | ||
1232 | input->filter.src_addr, | ||
1233 | input->action, | ||
1234 | IGC_MAC_STATE_SRC_ADDR); | ||
1235 | err = min_t(int, err, 0); | ||
1236 | if (err) | ||
1237 | return err; | ||
1238 | } | ||
1239 | |||
1240 | if (input->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) | ||
1241 | err = igc_rxnfc_write_vlan_prio_filter(adapter, input); | ||
1242 | |||
1243 | return err; | ||
1244 | } | ||
1245 | |||
1246 | static void igc_clear_etype_filter_regs(struct igc_adapter *adapter, | ||
1247 | u16 reg_index) | ||
1248 | { | ||
1249 | struct igc_hw *hw = &adapter->hw; | ||
1250 | u32 etqf = rd32(IGC_ETQF(reg_index)); | ||
1251 | |||
1252 | etqf &= ~IGC_ETQF_QUEUE_ENABLE; | ||
1253 | etqf &= ~IGC_ETQF_QUEUE_MASK; | ||
1254 | etqf &= ~IGC_ETQF_FILTER_ENABLE; | ||
1255 | |||
1256 | wr32(IGC_ETQF(reg_index), etqf); | ||
1257 | |||
1258 | adapter->etype_bitmap[reg_index] = false; | ||
1259 | } | ||
1260 | |||
1261 | static void igc_clear_vlan_prio_filter(struct igc_adapter *adapter, | ||
1262 | u16 vlan_tci) | ||
1263 | { | ||
1264 | struct igc_hw *hw = &adapter->hw; | ||
1265 | u8 vlan_priority; | ||
1266 | u32 vlapqf; | ||
1267 | |||
1268 | vlan_priority = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; | ||
1269 | |||
1270 | vlapqf = rd32(IGC_VLAPQF); | ||
1271 | vlapqf &= ~IGC_VLAPQF_P_VALID(vlan_priority); | ||
1272 | vlapqf &= ~IGC_VLAPQF_QUEUE_SEL(vlan_priority, | ||
1273 | IGC_VLAPQF_QUEUE_MASK); | ||
1274 | |||
1275 | wr32(IGC_VLAPQF, vlapqf); | ||
1276 | } | ||
1277 | |||
1278 | int igc_erase_filter(struct igc_adapter *adapter, struct igc_nfc_filter *input) | ||
1279 | { | ||
1280 | if (input->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) | ||
1281 | igc_clear_etype_filter_regs(adapter, | ||
1282 | input->etype_reg_index); | ||
1283 | |||
1284 | if (input->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) | ||
1285 | igc_clear_vlan_prio_filter(adapter, | ||
1286 | ntohs(input->filter.vlan_tci)); | ||
1287 | |||
1288 | if (input->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) | ||
1289 | igc_del_mac_steering_filter(adapter, input->filter.src_addr, | ||
1290 | input->action, | ||
1291 | IGC_MAC_STATE_SRC_ADDR); | ||
1292 | |||
1293 | if (input->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) | ||
1294 | igc_del_mac_steering_filter(adapter, input->filter.dst_addr, | ||
1295 | input->action, 0); | ||
1296 | |||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | static int igc_update_ethtool_nfc_entry(struct igc_adapter *adapter, | ||
1301 | struct igc_nfc_filter *input, | ||
1302 | u16 sw_idx) | ||
1303 | { | ||
1304 | struct igc_nfc_filter *rule, *parent; | ||
1305 | int err = -EINVAL; | ||
1306 | |||
1307 | parent = NULL; | ||
1308 | rule = NULL; | ||
1309 | |||
1310 | hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { | ||
1311 | /* hash found, or no matching entry */ | ||
1312 | if (rule->sw_idx >= sw_idx) | ||
1313 | break; | ||
1314 | parent = rule; | ||
1315 | } | ||
1316 | |||
1317 | /* if there is an old rule occupying our place remove it */ | ||
1318 | if (rule && rule->sw_idx == sw_idx) { | ||
1319 | if (!input) | ||
1320 | err = igc_erase_filter(adapter, rule); | ||
1321 | |||
1322 | hlist_del(&rule->nfc_node); | ||
1323 | kfree(rule); | ||
1324 | adapter->nfc_filter_count--; | ||
1325 | } | ||
1326 | |||
1327 | /* If no input this was a delete, err should be 0 if a rule was | ||
1328 | * successfully found and removed from the list else -EINVAL | ||
1329 | */ | ||
1330 | if (!input) | ||
1331 | return err; | ||
1332 | |||
1333 | /* initialize node */ | ||
1334 | INIT_HLIST_NODE(&input->nfc_node); | ||
1335 | |||
1336 | /* add filter to the list */ | ||
1337 | if (parent) | ||
1338 | hlist_add_behind(&input->nfc_node, &parent->nfc_node); | ||
1339 | else | ||
1340 | hlist_add_head(&input->nfc_node, &adapter->nfc_filter_list); | ||
1341 | |||
1342 | /* update counts */ | ||
1343 | adapter->nfc_filter_count++; | ||
1344 | |||
1345 | return 0; | ||
1346 | } | ||
1347 | |||
1348 | static int igc_add_ethtool_nfc_entry(struct igc_adapter *adapter, | ||
1349 | struct ethtool_rxnfc *cmd) | ||
1350 | { | ||
1351 | struct net_device *netdev = adapter->netdev; | ||
1352 | struct ethtool_rx_flow_spec *fsp = | ||
1353 | (struct ethtool_rx_flow_spec *)&cmd->fs; | ||
1354 | struct igc_nfc_filter *input, *rule; | ||
1355 | int err = 0; | ||
1356 | |||
1357 | if (!(netdev->hw_features & NETIF_F_NTUPLE)) | ||
1358 | return -EOPNOTSUPP; | ||
1359 | |||
1360 | /* Don't allow programming if the action is a queue greater than | ||
1361 | * the number of online Rx queues. | ||
1362 | */ | ||
1363 | if (fsp->ring_cookie == RX_CLS_FLOW_DISC || | ||
1364 | fsp->ring_cookie >= adapter->num_rx_queues) { | ||
1365 | dev_err(&adapter->pdev->dev, "ethtool -N: The specified action is invalid\n"); | ||
1366 | return -EINVAL; | ||
1367 | } | ||
1368 | |||
1369 | /* Don't allow indexes to exist outside of available space */ | ||
1370 | if (fsp->location >= IGC_MAX_RXNFC_FILTERS) { | ||
1371 | dev_err(&adapter->pdev->dev, "Location out of range\n"); | ||
1372 | return -EINVAL; | ||
1373 | } | ||
1374 | |||
1375 | if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW) | ||
1376 | return -EINVAL; | ||
1377 | |||
1378 | input = kzalloc(sizeof(*input), GFP_KERNEL); | ||
1379 | if (!input) | ||
1380 | return -ENOMEM; | ||
1381 | |||
1382 | if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) { | ||
1383 | input->filter.etype = fsp->h_u.ether_spec.h_proto; | ||
1384 | input->filter.match_flags = IGC_FILTER_FLAG_ETHER_TYPE; | ||
1385 | } | ||
1386 | |||
1387 | /* Only support matching addresses by the full mask */ | ||
1388 | if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_source)) { | ||
1389 | input->filter.match_flags |= IGC_FILTER_FLAG_SRC_MAC_ADDR; | ||
1390 | ether_addr_copy(input->filter.src_addr, | ||
1391 | fsp->h_u.ether_spec.h_source); | ||
1392 | } | ||
1393 | |||
1394 | /* Only support matching addresses by the full mask */ | ||
1395 | if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_dest)) { | ||
1396 | input->filter.match_flags |= IGC_FILTER_FLAG_DST_MAC_ADDR; | ||
1397 | ether_addr_copy(input->filter.dst_addr, | ||
1398 | fsp->h_u.ether_spec.h_dest); | ||
1399 | } | ||
1400 | |||
1401 | if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) { | ||
1402 | if (fsp->m_ext.vlan_tci != htons(VLAN_PRIO_MASK)) { | ||
1403 | err = -EINVAL; | ||
1404 | goto err_out; | ||
1405 | } | ||
1406 | input->filter.vlan_tci = fsp->h_ext.vlan_tci; | ||
1407 | input->filter.match_flags |= IGC_FILTER_FLAG_VLAN_TCI; | ||
1408 | } | ||
1409 | |||
1410 | input->action = fsp->ring_cookie; | ||
1411 | input->sw_idx = fsp->location; | ||
1412 | |||
1413 | spin_lock(&adapter->nfc_lock); | ||
1414 | |||
1415 | hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { | ||
1416 | if (!memcmp(&input->filter, &rule->filter, | ||
1417 | sizeof(input->filter))) { | ||
1418 | err = -EEXIST; | ||
1419 | dev_err(&adapter->pdev->dev, | ||
1420 | "ethtool: this filter is already set\n"); | ||
1421 | goto err_out_w_lock; | ||
1422 | } | ||
1423 | } | ||
1424 | |||
1425 | err = igc_add_filter(adapter, input); | ||
1426 | if (err) | ||
1427 | goto err_out_w_lock; | ||
1428 | |||
1429 | igc_update_ethtool_nfc_entry(adapter, input, input->sw_idx); | ||
1430 | |||
1431 | spin_unlock(&adapter->nfc_lock); | ||
1432 | return 0; | ||
1433 | |||
1434 | err_out_w_lock: | ||
1435 | spin_unlock(&adapter->nfc_lock); | ||
1436 | err_out: | ||
1437 | kfree(input); | ||
1438 | return err; | ||
1439 | } | ||
1440 | |||
1441 | static int igc_del_ethtool_nfc_entry(struct igc_adapter *adapter, | ||
1442 | struct ethtool_rxnfc *cmd) | ||
1443 | { | ||
1444 | struct ethtool_rx_flow_spec *fsp = | ||
1445 | (struct ethtool_rx_flow_spec *)&cmd->fs; | ||
1446 | int err; | ||
1447 | |||
1448 | spin_lock(&adapter->nfc_lock); | ||
1449 | err = igc_update_ethtool_nfc_entry(adapter, NULL, fsp->location); | ||
1450 | spin_unlock(&adapter->nfc_lock); | ||
1451 | |||
1452 | return err; | ||
1453 | } | ||
1454 | |||
1455 | static int igc_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) | ||
1456 | { | ||
1457 | struct igc_adapter *adapter = netdev_priv(dev); | ||
1458 | int ret = -EOPNOTSUPP; | ||
1459 | |||
1460 | switch (cmd->cmd) { | ||
1461 | case ETHTOOL_SRXFH: | ||
1462 | ret = igc_set_rss_hash_opt(adapter, cmd); | ||
1463 | break; | ||
1464 | case ETHTOOL_SRXCLSRLINS: | ||
1465 | ret = igc_add_ethtool_nfc_entry(adapter, cmd); | ||
1466 | break; | ||
1467 | case ETHTOOL_SRXCLSRLDEL: | ||
1468 | ret = igc_del_ethtool_nfc_entry(adapter, cmd); | ||
1469 | default: | ||
1470 | break; | ||
1471 | } | ||
1472 | |||
1473 | return ret; | ||
1474 | } | ||
1475 | |||
646 | void igc_write_rss_indir_tbl(struct igc_adapter *adapter) | 1476 | void igc_write_rss_indir_tbl(struct igc_adapter *adapter) |
647 | { | 1477 | { |
648 | struct igc_hw *hw = &adapter->hw; | 1478 | struct igc_hw *hw = &adapter->hw; |
@@ -885,17 +1715,13 @@ static int igc_get_link_ksettings(struct net_device *netdev, | |||
885 | if (hw->mac.type == igc_i225 && | 1715 | if (hw->mac.type == igc_i225 && |
886 | (status & IGC_STATUS_SPEED_2500)) { | 1716 | (status & IGC_STATUS_SPEED_2500)) { |
887 | speed = SPEED_2500; | 1717 | speed = SPEED_2500; |
888 | hw_dbg("2500 Mbs, "); | ||
889 | } else { | 1718 | } else { |
890 | speed = SPEED_1000; | 1719 | speed = SPEED_1000; |
891 | hw_dbg("1000 Mbs, "); | ||
892 | } | 1720 | } |
893 | } else if (status & IGC_STATUS_SPEED_100) { | 1721 | } else if (status & IGC_STATUS_SPEED_100) { |
894 | speed = SPEED_100; | 1722 | speed = SPEED_100; |
895 | hw_dbg("100 Mbs, "); | ||
896 | } else { | 1723 | } else { |
897 | speed = SPEED_10; | 1724 | speed = SPEED_10; |
898 | hw_dbg("10 Mbs, "); | ||
899 | } | 1725 | } |
900 | if ((status & IGC_STATUS_FD) || | 1726 | if ((status & IGC_STATUS_FD) || |
901 | hw->phy.media_type != igc_media_type_copper) | 1727 | hw->phy.media_type != igc_media_type_copper) |
@@ -1011,8 +1837,13 @@ static const struct ethtool_ops igc_ethtool_ops = { | |||
1011 | .set_ringparam = igc_set_ringparam, | 1837 | .set_ringparam = igc_set_ringparam, |
1012 | .get_pauseparam = igc_get_pauseparam, | 1838 | .get_pauseparam = igc_get_pauseparam, |
1013 | .set_pauseparam = igc_set_pauseparam, | 1839 | .set_pauseparam = igc_set_pauseparam, |
1840 | .get_strings = igc_get_strings, | ||
1841 | .get_sset_count = igc_get_sset_count, | ||
1842 | .get_ethtool_stats = igc_get_ethtool_stats, | ||
1014 | .get_coalesce = igc_get_coalesce, | 1843 | .get_coalesce = igc_get_coalesce, |
1015 | .set_coalesce = igc_set_coalesce, | 1844 | .set_coalesce = igc_set_coalesce, |
1845 | .get_rxnfc = igc_get_rxnfc, | ||
1846 | .set_rxnfc = igc_set_rxnfc, | ||
1016 | .get_rxfh_indir_size = igc_get_rxfh_indir_size, | 1847 | .get_rxfh_indir_size = igc_get_rxfh_indir_size, |
1017 | .get_rxfh = igc_get_rxfh, | 1848 | .get_rxfh = igc_get_rxfh, |
1018 | .set_rxfh = igc_set_rxfh, | 1849 | .set_rxfh = igc_set_rxfh, |