diff options
Diffstat (limited to 'drivers/net/ethernet/sfc')
-rw-r--r-- | drivers/net/ethernet/sfc/ethtool.c | 211 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/filter.c | 455 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/filter.h | 220 |
3 files changed, 494 insertions, 392 deletions
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index ec5cacd427ec..58ae28b8820d 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c | |||
@@ -799,11 +799,12 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) | |||
799 | return efx_reset(efx, rc); | 799 | return efx_reset(efx, rc); |
800 | } | 800 | } |
801 | 801 | ||
802 | /* MAC address mask including only MC flag */ | 802 | /* MAC address mask including only I/G bit */ |
803 | static const u8 mac_addr_mc_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; | 803 | static const u8 mac_addr_ig_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; |
804 | 804 | ||
805 | #define IP4_ADDR_FULL_MASK ((__force __be32)~0) | 805 | #define IP4_ADDR_FULL_MASK ((__force __be32)~0) |
806 | #define PORT_FULL_MASK ((__force __be16)~0) | 806 | #define PORT_FULL_MASK ((__force __be16)~0) |
807 | #define ETHER_TYPE_FULL_MASK ((__force __be16)~0) | ||
807 | 808 | ||
808 | static int efx_ethtool_get_class_rule(struct efx_nic *efx, | 809 | static int efx_ethtool_get_class_rule(struct efx_nic *efx, |
809 | struct ethtool_rx_flow_spec *rule) | 810 | struct ethtool_rx_flow_spec *rule) |
@@ -813,8 +814,6 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx, | |||
813 | struct ethhdr *mac_entry = &rule->h_u.ether_spec; | 814 | struct ethhdr *mac_entry = &rule->h_u.ether_spec; |
814 | struct ethhdr *mac_mask = &rule->m_u.ether_spec; | 815 | struct ethhdr *mac_mask = &rule->m_u.ether_spec; |
815 | struct efx_filter_spec spec; | 816 | struct efx_filter_spec spec; |
816 | u16 vid; | ||
817 | u8 proto; | ||
818 | int rc; | 817 | int rc; |
819 | 818 | ||
820 | rc = efx_filter_get_filter_safe(efx, EFX_FILTER_PRI_MANUAL, | 819 | rc = efx_filter_get_filter_safe(efx, EFX_FILTER_PRI_MANUAL, |
@@ -827,39 +826,67 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx, | |||
827 | else | 826 | else |
828 | rule->ring_cookie = spec.dmaq_id; | 827 | rule->ring_cookie = spec.dmaq_id; |
829 | 828 | ||
830 | if (spec.type == EFX_FILTER_MC_DEF || spec.type == EFX_FILTER_UC_DEF) { | 829 | if ((spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) && |
831 | rule->flow_type = ETHER_FLOW; | 830 | spec.ether_type == htons(ETH_P_IP) && |
832 | memcpy(mac_mask->h_dest, mac_addr_mc_mask, ETH_ALEN); | 831 | (spec.match_flags & EFX_FILTER_MATCH_IP_PROTO) && |
833 | if (spec.type == EFX_FILTER_MC_DEF) | 832 | (spec.ip_proto == IPPROTO_TCP || spec.ip_proto == IPPROTO_UDP) && |
834 | memcpy(mac_entry->h_dest, mac_addr_mc_mask, ETH_ALEN); | 833 | !(spec.match_flags & |
835 | return 0; | 834 | ~(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_OUTER_VID | |
836 | } | 835 | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_REM_HOST | |
837 | 836 | EFX_FILTER_MATCH_IP_PROTO | | |
838 | rc = efx_filter_get_eth_local(&spec, &vid, mac_entry->h_dest); | 837 | EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_PORT))) { |
839 | if (rc == 0) { | 838 | rule->flow_type = ((spec.ip_proto == IPPROTO_TCP) ? |
839 | TCP_V4_FLOW : UDP_V4_FLOW); | ||
840 | if (spec.match_flags & EFX_FILTER_MATCH_LOC_HOST) { | ||
841 | ip_entry->ip4dst = spec.loc_host[0]; | ||
842 | ip_mask->ip4dst = IP4_ADDR_FULL_MASK; | ||
843 | } | ||
844 | if (spec.match_flags & EFX_FILTER_MATCH_REM_HOST) { | ||
845 | ip_entry->ip4src = spec.rem_host[0]; | ||
846 | ip_mask->ip4src = IP4_ADDR_FULL_MASK; | ||
847 | } | ||
848 | if (spec.match_flags & EFX_FILTER_MATCH_LOC_PORT) { | ||
849 | ip_entry->pdst = spec.loc_port; | ||
850 | ip_mask->pdst = PORT_FULL_MASK; | ||
851 | } | ||
852 | if (spec.match_flags & EFX_FILTER_MATCH_REM_PORT) { | ||
853 | ip_entry->psrc = spec.rem_port; | ||
854 | ip_mask->psrc = PORT_FULL_MASK; | ||
855 | } | ||
856 | } else if (!(spec.match_flags & | ||
857 | ~(EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG | | ||
858 | EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_ETHER_TYPE | | ||
859 | EFX_FILTER_MATCH_OUTER_VID))) { | ||
840 | rule->flow_type = ETHER_FLOW; | 860 | rule->flow_type = ETHER_FLOW; |
841 | memset(mac_mask->h_dest, ~0, ETH_ALEN); | 861 | if (spec.match_flags & |
842 | if (vid != EFX_FILTER_VID_UNSPEC) { | 862 | (EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG)) { |
843 | rule->flow_type |= FLOW_EXT; | 863 | memcpy(mac_entry->h_dest, spec.loc_mac, ETH_ALEN); |
844 | rule->h_ext.vlan_tci = htons(vid); | 864 | if (spec.match_flags & EFX_FILTER_MATCH_LOC_MAC) |
845 | rule->m_ext.vlan_tci = htons(0xfff); | 865 | memset(mac_mask->h_dest, ~0, ETH_ALEN); |
866 | else | ||
867 | memcpy(mac_mask->h_dest, mac_addr_ig_mask, | ||
868 | ETH_ALEN); | ||
846 | } | 869 | } |
847 | return 0; | 870 | if (spec.match_flags & EFX_FILTER_MATCH_REM_MAC) { |
871 | memcpy(mac_entry->h_source, spec.rem_mac, ETH_ALEN); | ||
872 | memset(mac_mask->h_source, ~0, ETH_ALEN); | ||
873 | } | ||
874 | if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) { | ||
875 | mac_entry->h_proto = spec.ether_type; | ||
876 | mac_mask->h_proto = ETHER_TYPE_FULL_MASK; | ||
877 | } | ||
878 | } else { | ||
879 | /* The above should handle all filters that we insert */ | ||
880 | WARN_ON(1); | ||
881 | return -EINVAL; | ||
848 | } | 882 | } |
849 | 883 | ||
850 | rc = efx_filter_get_ipv4_local(&spec, &proto, | 884 | if (spec.match_flags & EFX_FILTER_MATCH_OUTER_VID) { |
851 | &ip_entry->ip4dst, &ip_entry->pdst); | 885 | rule->flow_type |= FLOW_EXT; |
852 | if (rc != 0) { | 886 | rule->h_ext.vlan_tci = spec.outer_vid; |
853 | rc = efx_filter_get_ipv4_full( | 887 | rule->m_ext.vlan_tci = htons(0xfff); |
854 | &spec, &proto, &ip_entry->ip4dst, &ip_entry->pdst, | ||
855 | &ip_entry->ip4src, &ip_entry->psrc); | ||
856 | EFX_WARN_ON_PARANOID(rc); | ||
857 | ip_mask->ip4src = IP4_ADDR_FULL_MASK; | ||
858 | ip_mask->psrc = PORT_FULL_MASK; | ||
859 | } | 888 | } |
860 | rule->flow_type = (proto == IPPROTO_TCP) ? TCP_V4_FLOW : UDP_V4_FLOW; | 889 | |
861 | ip_mask->ip4dst = IP4_ADDR_FULL_MASK; | ||
862 | ip_mask->pdst = PORT_FULL_MASK; | ||
863 | return rc; | 890 | return rc; |
864 | } | 891 | } |
865 | 892 | ||
@@ -969,80 +996,78 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx, | |||
969 | (rule->ring_cookie == RX_CLS_FLOW_DISC) ? | 996 | (rule->ring_cookie == RX_CLS_FLOW_DISC) ? |
970 | EFX_FILTER_RX_DMAQ_ID_DROP : rule->ring_cookie); | 997 | EFX_FILTER_RX_DMAQ_ID_DROP : rule->ring_cookie); |
971 | 998 | ||
972 | switch (rule->flow_type) { | 999 | switch (rule->flow_type & ~FLOW_EXT) { |
973 | case TCP_V4_FLOW: | 1000 | case TCP_V4_FLOW: |
974 | case UDP_V4_FLOW: { | 1001 | case UDP_V4_FLOW: |
975 | u8 proto = (rule->flow_type == TCP_V4_FLOW ? | 1002 | spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE | |
976 | IPPROTO_TCP : IPPROTO_UDP); | 1003 | EFX_FILTER_MATCH_IP_PROTO); |
977 | 1004 | spec.ether_type = htons(ETH_P_IP); | |
978 | /* Must match all of destination, */ | 1005 | spec.ip_proto = ((rule->flow_type & ~FLOW_EXT) == TCP_V4_FLOW ? |
979 | if (!(ip_mask->ip4dst == IP4_ADDR_FULL_MASK && | 1006 | IPPROTO_TCP : IPPROTO_UDP); |
980 | ip_mask->pdst == PORT_FULL_MASK)) | 1007 | if (ip_mask->ip4dst) { |
981 | return -EINVAL; | 1008 | if (ip_mask->ip4dst != IP4_ADDR_FULL_MASK) |
982 | /* all or none of source, */ | 1009 | return -EINVAL; |
983 | if ((ip_mask->ip4src || ip_mask->psrc) && | 1010 | spec.match_flags |= EFX_FILTER_MATCH_LOC_HOST; |
984 | !(ip_mask->ip4src == IP4_ADDR_FULL_MASK && | 1011 | spec.loc_host[0] = ip_entry->ip4dst; |
985 | ip_mask->psrc == PORT_FULL_MASK)) | 1012 | } |
986 | return -EINVAL; | 1013 | if (ip_mask->ip4src) { |
987 | /* and nothing else */ | 1014 | if (ip_mask->ip4src != IP4_ADDR_FULL_MASK) |
988 | if (ip_mask->tos || rule->m_ext.vlan_tci) | 1015 | return -EINVAL; |
1016 | spec.match_flags |= EFX_FILTER_MATCH_REM_HOST; | ||
1017 | spec.rem_host[0] = ip_entry->ip4src; | ||
1018 | } | ||
1019 | if (ip_mask->pdst) { | ||
1020 | if (ip_mask->pdst != PORT_FULL_MASK) | ||
1021 | return -EINVAL; | ||
1022 | spec.match_flags |= EFX_FILTER_MATCH_LOC_PORT; | ||
1023 | spec.loc_port = ip_entry->pdst; | ||
1024 | } | ||
1025 | if (ip_mask->psrc) { | ||
1026 | if (ip_mask->psrc != PORT_FULL_MASK) | ||
1027 | return -EINVAL; | ||
1028 | spec.match_flags |= EFX_FILTER_MATCH_REM_PORT; | ||
1029 | spec.rem_port = ip_entry->psrc; | ||
1030 | } | ||
1031 | if (ip_mask->tos) | ||
989 | return -EINVAL; | 1032 | return -EINVAL; |
990 | |||
991 | if (ip_mask->ip4src) | ||
992 | rc = efx_filter_set_ipv4_full(&spec, proto, | ||
993 | ip_entry->ip4dst, | ||
994 | ip_entry->pdst, | ||
995 | ip_entry->ip4src, | ||
996 | ip_entry->psrc); | ||
997 | else | ||
998 | rc = efx_filter_set_ipv4_local(&spec, proto, | ||
999 | ip_entry->ip4dst, | ||
1000 | ip_entry->pdst); | ||
1001 | if (rc) | ||
1002 | return rc; | ||
1003 | break; | 1033 | break; |
1004 | } | ||
1005 | |||
1006 | case ETHER_FLOW | FLOW_EXT: | ||
1007 | case ETHER_FLOW: { | ||
1008 | u16 vlan_tag_mask = (rule->flow_type & FLOW_EXT ? | ||
1009 | ntohs(rule->m_ext.vlan_tci) : 0); | ||
1010 | 1034 | ||
1011 | /* Must not match on source address or Ethertype */ | 1035 | case ETHER_FLOW: |
1012 | if (!is_zero_ether_addr(mac_mask->h_source) || | 1036 | if (!is_zero_ether_addr(mac_mask->h_dest)) { |
1013 | mac_mask->h_proto) | 1037 | if (ether_addr_equal(mac_mask->h_dest, |
1014 | return -EINVAL; | 1038 | mac_addr_ig_mask)) |
1015 | 1039 | spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG; | |
1016 | /* Is it a default UC or MC filter? */ | 1040 | else if (is_broadcast_ether_addr(mac_mask->h_dest)) |
1017 | if (ether_addr_equal(mac_mask->h_dest, mac_addr_mc_mask) && | 1041 | spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC; |
1018 | vlan_tag_mask == 0) { | ||
1019 | if (is_multicast_ether_addr(mac_entry->h_dest)) | ||
1020 | rc = efx_filter_set_mc_def(&spec); | ||
1021 | else | 1042 | else |
1022 | rc = efx_filter_set_uc_def(&spec); | 1043 | return -EINVAL; |
1044 | memcpy(spec.loc_mac, mac_entry->h_dest, ETH_ALEN); | ||
1023 | } | 1045 | } |
1024 | /* Otherwise, it must match all of destination and all | 1046 | if (!is_zero_ether_addr(mac_mask->h_source)) { |
1025 | * or none of VID. | 1047 | if (!is_broadcast_ether_addr(mac_mask->h_source)) |
1026 | */ | 1048 | return -EINVAL; |
1027 | else if (is_broadcast_ether_addr(mac_mask->h_dest) && | 1049 | spec.match_flags |= EFX_FILTER_MATCH_REM_MAC; |
1028 | (vlan_tag_mask == 0xfff || vlan_tag_mask == 0)) { | 1050 | memcpy(spec.rem_mac, mac_entry->h_source, ETH_ALEN); |
1029 | rc = efx_filter_set_eth_local( | 1051 | } |
1030 | &spec, | 1052 | if (mac_mask->h_proto) { |
1031 | vlan_tag_mask ? | 1053 | if (mac_mask->h_proto != ETHER_TYPE_FULL_MASK) |
1032 | ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC, | 1054 | return -EINVAL; |
1033 | mac_entry->h_dest); | 1055 | spec.match_flags |= EFX_FILTER_MATCH_ETHER_TYPE; |
1034 | } else { | 1056 | spec.ether_type = mac_entry->h_proto; |
1035 | rc = -EINVAL; | ||
1036 | } | 1057 | } |
1037 | if (rc) | ||
1038 | return rc; | ||
1039 | break; | 1058 | break; |
1040 | } | ||
1041 | 1059 | ||
1042 | default: | 1060 | default: |
1043 | return -EINVAL; | 1061 | return -EINVAL; |
1044 | } | 1062 | } |
1045 | 1063 | ||
1064 | if ((rule->flow_type & FLOW_EXT) && rule->m_ext.vlan_tci) { | ||
1065 | if (rule->m_ext.vlan_tci != htons(0xfff)) | ||
1066 | return -EINVAL; | ||
1067 | spec.match_flags |= EFX_FILTER_MATCH_OUTER_VID; | ||
1068 | spec.outer_vid = rule->h_ext.vlan_tci; | ||
1069 | } | ||
1070 | |||
1046 | rc = efx_filter_insert_filter(efx, &spec, true); | 1071 | rc = efx_filter_insert_filter(efx, &spec, true); |
1047 | if (rc < 0) | 1072 | if (rc < 0) |
1048 | return rc; | 1073 | return rc; |
diff --git a/drivers/net/ethernet/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c index c547630cfee4..96f8f2e34403 100644 --- a/drivers/net/ethernet/sfc/filter.c +++ b/drivers/net/ethernet/sfc/filter.c | |||
@@ -32,6 +32,18 @@ | |||
32 | * counter-productive. */ | 32 | * counter-productive. */ |
33 | #define EFX_FARCH_FILTER_CTL_SRCH_HINT_MAX 5 | 33 | #define EFX_FARCH_FILTER_CTL_SRCH_HINT_MAX 5 |
34 | 34 | ||
35 | enum efx_farch_filter_type { | ||
36 | EFX_FARCH_FILTER_TCP_FULL = 0, | ||
37 | EFX_FARCH_FILTER_TCP_WILD, | ||
38 | EFX_FARCH_FILTER_UDP_FULL, | ||
39 | EFX_FARCH_FILTER_UDP_WILD, | ||
40 | EFX_FARCH_FILTER_MAC_FULL = 4, | ||
41 | EFX_FARCH_FILTER_MAC_WILD, | ||
42 | EFX_FARCH_FILTER_UC_DEF = 8, | ||
43 | EFX_FARCH_FILTER_MC_DEF, | ||
44 | EFX_FARCH_FILTER_TYPE_COUNT, /* number of specific types */ | ||
45 | }; | ||
46 | |||
35 | enum efx_farch_filter_table_id { | 47 | enum efx_farch_filter_table_id { |
36 | EFX_FARCH_FILTER_TABLE_RX_IP = 0, | 48 | EFX_FARCH_FILTER_TABLE_RX_IP = 0, |
37 | EFX_FARCH_FILTER_TABLE_RX_MAC, | 49 | EFX_FARCH_FILTER_TABLE_RX_MAC, |
@@ -62,7 +74,7 @@ struct efx_farch_filter_table { | |||
62 | unsigned used; /* number currently used */ | 74 | unsigned used; /* number currently used */ |
63 | unsigned long *used_bitmap; | 75 | unsigned long *used_bitmap; |
64 | struct efx_farch_filter_spec *spec; | 76 | struct efx_farch_filter_spec *spec; |
65 | unsigned search_depth[EFX_FILTER_TYPE_COUNT]; | 77 | unsigned search_depth[EFX_FARCH_FILTER_TYPE_COUNT]; |
66 | }; | 78 | }; |
67 | 79 | ||
68 | struct efx_filter_state { | 80 | struct efx_filter_state { |
@@ -106,33 +118,22 @@ static enum efx_farch_filter_table_id | |||
106 | efx_farch_filter_spec_table_id(const struct efx_farch_filter_spec *spec) | 118 | efx_farch_filter_spec_table_id(const struct efx_farch_filter_spec *spec) |
107 | { | 119 | { |
108 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != | 120 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != |
109 | (EFX_FILTER_TCP_FULL >> 2)); | 121 | (EFX_FARCH_FILTER_TCP_FULL >> 2)); |
110 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != | 122 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != |
111 | (EFX_FILTER_TCP_WILD >> 2)); | 123 | (EFX_FARCH_FILTER_TCP_WILD >> 2)); |
112 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != | 124 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != |
113 | (EFX_FILTER_UDP_FULL >> 2)); | 125 | (EFX_FARCH_FILTER_UDP_FULL >> 2)); |
114 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != | 126 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_IP != |
115 | (EFX_FILTER_UDP_WILD >> 2)); | 127 | (EFX_FARCH_FILTER_UDP_WILD >> 2)); |
116 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_MAC != | 128 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_MAC != |
117 | (EFX_FILTER_MAC_FULL >> 2)); | 129 | (EFX_FARCH_FILTER_MAC_FULL >> 2)); |
118 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_MAC != | 130 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_RX_MAC != |
119 | (EFX_FILTER_MAC_WILD >> 2)); | 131 | (EFX_FARCH_FILTER_MAC_WILD >> 2)); |
120 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_TX_MAC != | 132 | BUILD_BUG_ON(EFX_FARCH_FILTER_TABLE_TX_MAC != |
121 | EFX_FARCH_FILTER_TABLE_RX_MAC + 2); | 133 | EFX_FARCH_FILTER_TABLE_RX_MAC + 2); |
122 | EFX_BUG_ON_PARANOID(spec->type == EFX_FILTER_UNSPEC); | ||
123 | return (spec->type >> 2) + ((spec->flags & EFX_FILTER_FLAG_TX) ? 2 : 0); | 134 | return (spec->type >> 2) + ((spec->flags & EFX_FILTER_FLAG_TX) ? 2 : 0); |
124 | } | 135 | } |
125 | 136 | ||
126 | static struct efx_farch_filter_table * | ||
127 | efx_farch_filter_spec_table(struct efx_filter_state *state, | ||
128 | const struct efx_farch_filter_spec *spec) | ||
129 | { | ||
130 | if (spec->type == EFX_FILTER_UNSPEC) | ||
131 | return NULL; | ||
132 | else | ||
133 | return &state->table[efx_farch_filter_spec_table_id(spec)]; | ||
134 | } | ||
135 | |||
136 | static void | 137 | static void |
137 | efx_farch_filter_table_reset_search_depth(struct efx_farch_filter_table *table) | 138 | efx_farch_filter_table_reset_search_depth(struct efx_farch_filter_table *table) |
138 | { | 139 | { |
@@ -149,27 +150,27 @@ static void efx_farch_filter_push_rx_config(struct efx_nic *efx) | |||
149 | 150 | ||
150 | table = &state->table[EFX_FARCH_FILTER_TABLE_RX_IP]; | 151 | table = &state->table[EFX_FARCH_FILTER_TABLE_RX_IP]; |
151 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_FULL_SRCH_LIMIT, | 152 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_FULL_SRCH_LIMIT, |
152 | table->search_depth[EFX_FILTER_TCP_FULL] + | 153 | table->search_depth[EFX_FARCH_FILTER_TCP_FULL] + |
153 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); | 154 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); |
154 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_WILD_SRCH_LIMIT, | 155 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_WILD_SRCH_LIMIT, |
155 | table->search_depth[EFX_FILTER_TCP_WILD] + | 156 | table->search_depth[EFX_FARCH_FILTER_TCP_WILD] + |
156 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); | 157 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); |
157 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_FULL_SRCH_LIMIT, | 158 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_FULL_SRCH_LIMIT, |
158 | table->search_depth[EFX_FILTER_UDP_FULL] + | 159 | table->search_depth[EFX_FARCH_FILTER_UDP_FULL] + |
159 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); | 160 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); |
160 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_WILD_SRCH_LIMIT, | 161 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_WILD_SRCH_LIMIT, |
161 | table->search_depth[EFX_FILTER_UDP_WILD] + | 162 | table->search_depth[EFX_FARCH_FILTER_UDP_WILD] + |
162 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); | 163 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); |
163 | 164 | ||
164 | table = &state->table[EFX_FARCH_FILTER_TABLE_RX_MAC]; | 165 | table = &state->table[EFX_FARCH_FILTER_TABLE_RX_MAC]; |
165 | if (table->size) { | 166 | if (table->size) { |
166 | EFX_SET_OWORD_FIELD( | 167 | EFX_SET_OWORD_FIELD( |
167 | filter_ctl, FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT, | 168 | filter_ctl, FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT, |
168 | table->search_depth[EFX_FILTER_MAC_FULL] + | 169 | table->search_depth[EFX_FARCH_FILTER_MAC_FULL] + |
169 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); | 170 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); |
170 | EFX_SET_OWORD_FIELD( | 171 | EFX_SET_OWORD_FIELD( |
171 | filter_ctl, FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT, | 172 | filter_ctl, FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT, |
172 | table->search_depth[EFX_FILTER_MAC_WILD] + | 173 | table->search_depth[EFX_FARCH_FILTER_MAC_WILD] + |
173 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); | 174 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); |
174 | } | 175 | } |
175 | 176 | ||
@@ -225,223 +226,202 @@ static void efx_farch_filter_push_tx_limits(struct efx_nic *efx) | |||
225 | if (table->size) { | 226 | if (table->size) { |
226 | EFX_SET_OWORD_FIELD( | 227 | EFX_SET_OWORD_FIELD( |
227 | tx_cfg, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE, | 228 | tx_cfg, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE, |
228 | table->search_depth[EFX_FILTER_MAC_FULL] + | 229 | table->search_depth[EFX_FARCH_FILTER_MAC_FULL] + |
229 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); | 230 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_FULL); |
230 | EFX_SET_OWORD_FIELD( | 231 | EFX_SET_OWORD_FIELD( |
231 | tx_cfg, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE, | 232 | tx_cfg, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE, |
232 | table->search_depth[EFX_FILTER_MAC_WILD] + | 233 | table->search_depth[EFX_FARCH_FILTER_MAC_WILD] + |
233 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); | 234 | EFX_FARCH_FILTER_CTL_SRCH_FUDGE_WILD); |
234 | } | 235 | } |
235 | 236 | ||
236 | efx_writeo(efx, &tx_cfg, FR_AZ_TX_CFG); | 237 | efx_writeo(efx, &tx_cfg, FR_AZ_TX_CFG); |
237 | } | 238 | } |
238 | 239 | ||
239 | static inline void __efx_filter_set_ipv4(struct efx_filter_spec *spec, | 240 | static int |
240 | __be32 host1, __be16 port1, | 241 | efx_farch_filter_from_gen_spec(struct efx_farch_filter_spec *spec, |
241 | __be32 host2, __be16 port2) | 242 | const struct efx_filter_spec *gen_spec) |
242 | { | ||
243 | spec->data[0] = ntohl(host1) << 16 | ntohs(port1); | ||
244 | spec->data[1] = ntohs(port2) << 16 | ntohl(host1) >> 16; | ||
245 | spec->data[2] = ntohl(host2); | ||
246 | } | ||
247 | |||
248 | static inline void __efx_filter_get_ipv4(const struct efx_filter_spec *spec, | ||
249 | __be32 *host1, __be16 *port1, | ||
250 | __be32 *host2, __be16 *port2) | ||
251 | { | ||
252 | *host1 = htonl(spec->data[0] >> 16 | spec->data[1] << 16); | ||
253 | *port1 = htons(spec->data[0]); | ||
254 | *host2 = htonl(spec->data[2]); | ||
255 | *port2 = htons(spec->data[1] >> 16); | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * efx_filter_set_ipv4_local - specify IPv4 host, transport protocol and port | ||
260 | * @spec: Specification to initialise | ||
261 | * @proto: Transport layer protocol number | ||
262 | * @host: Local host address (network byte order) | ||
263 | * @port: Local port (network byte order) | ||
264 | */ | ||
265 | int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto, | ||
266 | __be32 host, __be16 port) | ||
267 | { | 243 | { |
268 | __be32 host1; | 244 | bool is_full = false; |
269 | __be16 port1; | ||
270 | |||
271 | EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX)); | ||
272 | |||
273 | /* This cannot currently be combined with other filtering */ | ||
274 | if (spec->type != EFX_FILTER_UNSPEC) | ||
275 | return -EPROTONOSUPPORT; | ||
276 | 245 | ||
277 | if (port == 0) | 246 | if ((gen_spec->flags & EFX_FILTER_FLAG_RX_RSS) && |
247 | gen_spec->rss_context != EFX_FILTER_RSS_CONTEXT_DEFAULT) | ||
278 | return -EINVAL; | 248 | return -EINVAL; |
279 | 249 | ||
280 | switch (proto) { | 250 | spec->priority = gen_spec->priority; |
281 | case IPPROTO_TCP: | 251 | spec->flags = gen_spec->flags; |
282 | spec->type = EFX_FILTER_TCP_WILD; | 252 | spec->dmaq_id = gen_spec->dmaq_id; |
283 | break; | ||
284 | case IPPROTO_UDP: | ||
285 | spec->type = EFX_FILTER_UDP_WILD; | ||
286 | break; | ||
287 | default: | ||
288 | return -EPROTONOSUPPORT; | ||
289 | } | ||
290 | |||
291 | /* Filter is constructed in terms of source and destination, | ||
292 | * with the odd wrinkle that the ports are swapped in a UDP | ||
293 | * wildcard filter. We need to convert from local and remote | ||
294 | * (= zero for wildcard) addresses. | ||
295 | */ | ||
296 | host1 = 0; | ||
297 | if (proto != IPPROTO_UDP) { | ||
298 | port1 = 0; | ||
299 | } else { | ||
300 | port1 = port; | ||
301 | port = 0; | ||
302 | } | ||
303 | |||
304 | __efx_filter_set_ipv4(spec, host1, port1, host, port); | ||
305 | return 0; | ||
306 | } | ||
307 | 253 | ||
308 | int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec, | 254 | switch (gen_spec->match_flags) { |
309 | u8 *proto, __be32 *host, __be16 *port) | 255 | case (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | |
310 | { | 256 | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | |
311 | __be32 host1; | 257 | EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT): |
312 | __be16 port1; | 258 | is_full = true; |
259 | /* fall through */ | ||
260 | case (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | | ||
261 | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT): { | ||
262 | __be32 rhost, host1, host2; | ||
263 | __be16 rport, port1, port2; | ||
313 | 264 | ||
314 | switch (spec->type) { | 265 | EFX_BUG_ON_PARANOID(!(gen_spec->flags & EFX_FILTER_FLAG_RX)); |
315 | case EFX_FILTER_TCP_WILD: | ||
316 | *proto = IPPROTO_TCP; | ||
317 | __efx_filter_get_ipv4(spec, &host1, &port1, host, port); | ||
318 | return 0; | ||
319 | case EFX_FILTER_UDP_WILD: | ||
320 | *proto = IPPROTO_UDP; | ||
321 | __efx_filter_get_ipv4(spec, &host1, port, host, &port1); | ||
322 | return 0; | ||
323 | default: | ||
324 | return -EINVAL; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | /** | ||
329 | * efx_filter_set_ipv4_full - specify IPv4 hosts, transport protocol and ports | ||
330 | * @spec: Specification to initialise | ||
331 | * @proto: Transport layer protocol number | ||
332 | * @host: Local host address (network byte order) | ||
333 | * @port: Local port (network byte order) | ||
334 | * @rhost: Remote host address (network byte order) | ||
335 | * @rport: Remote port (network byte order) | ||
336 | */ | ||
337 | int efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto, | ||
338 | __be32 host, __be16 port, | ||
339 | __be32 rhost, __be16 rport) | ||
340 | { | ||
341 | EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX)); | ||
342 | 266 | ||
343 | /* This cannot currently be combined with other filtering */ | 267 | if (gen_spec->ether_type != htons(ETH_P_IP)) |
344 | if (spec->type != EFX_FILTER_UNSPEC) | 268 | return -EPROTONOSUPPORT; |
345 | return -EPROTONOSUPPORT; | 269 | if (gen_spec->loc_port == 0 || |
270 | (is_full && gen_spec->rem_port == 0)) | ||
271 | return -EADDRNOTAVAIL; | ||
272 | switch (gen_spec->ip_proto) { | ||
273 | case IPPROTO_TCP: | ||
274 | spec->type = (is_full ? EFX_FARCH_FILTER_TCP_FULL : | ||
275 | EFX_FARCH_FILTER_TCP_WILD); | ||
276 | break; | ||
277 | case IPPROTO_UDP: | ||
278 | spec->type = (is_full ? EFX_FARCH_FILTER_UDP_FULL : | ||
279 | EFX_FARCH_FILTER_UDP_WILD); | ||
280 | break; | ||
281 | default: | ||
282 | return -EPROTONOSUPPORT; | ||
283 | } | ||
346 | 284 | ||
347 | if (port == 0 || rport == 0) | 285 | /* Filter is constructed in terms of source and destination, |
348 | return -EINVAL; | 286 | * with the odd wrinkle that the ports are swapped in a UDP |
287 | * wildcard filter. We need to convert from local and remote | ||
288 | * (= zero for wildcard) addresses. | ||
289 | */ | ||
290 | rhost = is_full ? gen_spec->rem_host[0] : 0; | ||
291 | rport = is_full ? gen_spec->rem_port : 0; | ||
292 | host1 = rhost; | ||
293 | host2 = gen_spec->loc_host[0]; | ||
294 | if (!is_full && gen_spec->ip_proto == IPPROTO_UDP) { | ||
295 | port1 = gen_spec->loc_port; | ||
296 | port2 = rport; | ||
297 | } else { | ||
298 | port1 = rport; | ||
299 | port2 = gen_spec->loc_port; | ||
300 | } | ||
301 | spec->data[0] = ntohl(host1) << 16 | ntohs(port1); | ||
302 | spec->data[1] = ntohs(port2) << 16 | ntohl(host1) >> 16; | ||
303 | spec->data[2] = ntohl(host2); | ||
349 | 304 | ||
350 | switch (proto) { | ||
351 | case IPPROTO_TCP: | ||
352 | spec->type = EFX_FILTER_TCP_FULL; | ||
353 | break; | 305 | break; |
354 | case IPPROTO_UDP: | ||
355 | spec->type = EFX_FILTER_UDP_FULL; | ||
356 | break; | ||
357 | default: | ||
358 | return -EPROTONOSUPPORT; | ||
359 | } | 306 | } |
360 | 307 | ||
361 | __efx_filter_set_ipv4(spec, rhost, rport, host, port); | 308 | case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID: |
362 | return 0; | 309 | is_full = true; |
363 | } | 310 | /* fall through */ |
364 | 311 | case EFX_FILTER_MATCH_LOC_MAC: | |
365 | int efx_filter_get_ipv4_full(const struct efx_filter_spec *spec, | 312 | spec->type = (is_full ? EFX_FARCH_FILTER_MAC_FULL : |
366 | u8 *proto, __be32 *host, __be16 *port, | 313 | EFX_FARCH_FILTER_MAC_WILD); |
367 | __be32 *rhost, __be16 *rport) | 314 | spec->data[0] = is_full ? ntohs(gen_spec->outer_vid) : 0; |
368 | { | 315 | spec->data[1] = (gen_spec->loc_mac[2] << 24 | |
369 | switch (spec->type) { | 316 | gen_spec->loc_mac[3] << 16 | |
370 | case EFX_FILTER_TCP_FULL: | 317 | gen_spec->loc_mac[4] << 8 | |
371 | *proto = IPPROTO_TCP; | 318 | gen_spec->loc_mac[5]); |
319 | spec->data[2] = (gen_spec->loc_mac[0] << 8 | | ||
320 | gen_spec->loc_mac[1]); | ||
372 | break; | 321 | break; |
373 | case EFX_FILTER_UDP_FULL: | 322 | |
374 | *proto = IPPROTO_UDP; | 323 | case EFX_FILTER_MATCH_LOC_MAC_IG: |
324 | spec->type = (is_multicast_ether_addr(gen_spec->loc_mac) ? | ||
325 | EFX_FARCH_FILTER_MC_DEF : | ||
326 | EFX_FARCH_FILTER_UC_DEF); | ||
327 | memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */ | ||
375 | break; | 328 | break; |
329 | |||
376 | default: | 330 | default: |
377 | return -EINVAL; | 331 | return -EPROTONOSUPPORT; |
378 | } | 332 | } |
379 | 333 | ||
380 | __efx_filter_get_ipv4(spec, rhost, rport, host, port); | ||
381 | return 0; | 334 | return 0; |
382 | } | 335 | } |
383 | 336 | ||
384 | /** | 337 | static void |
385 | * efx_filter_set_eth_local - specify local Ethernet address and optional VID | 338 | efx_farch_filter_to_gen_spec(struct efx_filter_spec *gen_spec, |
386 | * @spec: Specification to initialise | 339 | const struct efx_farch_filter_spec *spec) |
387 | * @vid: VLAN ID to match, or %EFX_FILTER_VID_UNSPEC | ||
388 | * @addr: Local Ethernet MAC address | ||
389 | */ | ||
390 | int efx_filter_set_eth_local(struct efx_filter_spec *spec, | ||
391 | u16 vid, const u8 *addr) | ||
392 | { | 340 | { |
393 | EFX_BUG_ON_PARANOID(!(spec->flags & | 341 | bool is_full = false; |
394 | (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX))); | ||
395 | |||
396 | /* This cannot currently be combined with other filtering */ | ||
397 | if (spec->type != EFX_FILTER_UNSPEC) | ||
398 | return -EPROTONOSUPPORT; | ||
399 | |||
400 | if (vid == EFX_FILTER_VID_UNSPEC) { | ||
401 | spec->type = EFX_FILTER_MAC_WILD; | ||
402 | spec->data[0] = 0; | ||
403 | } else { | ||
404 | spec->type = EFX_FILTER_MAC_FULL; | ||
405 | spec->data[0] = vid; | ||
406 | } | ||
407 | 342 | ||
408 | spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5]; | 343 | /* *gen_spec should be completely initialised, to be consistent |
409 | spec->data[2] = addr[0] << 8 | addr[1]; | 344 | * with efx_filter_init_{rx,tx}() and in case we want to copy |
410 | return 0; | 345 | * it back to userland. |
411 | } | 346 | */ |
347 | memset(gen_spec, 0, sizeof(*gen_spec)); | ||
412 | 348 | ||
413 | /** | 349 | gen_spec->priority = spec->priority; |
414 | * efx_filter_set_uc_def - specify matching otherwise-unmatched unicast | 350 | gen_spec->flags = spec->flags; |
415 | * @spec: Specification to initialise | 351 | gen_spec->dmaq_id = spec->dmaq_id; |
416 | */ | ||
417 | int efx_filter_set_uc_def(struct efx_filter_spec *spec) | ||
418 | { | ||
419 | EFX_BUG_ON_PARANOID(!(spec->flags & | ||
420 | (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX))); | ||
421 | 352 | ||
422 | if (spec->type != EFX_FILTER_UNSPEC) | 353 | switch (spec->type) { |
423 | return -EINVAL; | 354 | case EFX_FARCH_FILTER_TCP_FULL: |
355 | case EFX_FARCH_FILTER_UDP_FULL: | ||
356 | is_full = true; | ||
357 | /* fall through */ | ||
358 | case EFX_FARCH_FILTER_TCP_WILD: | ||
359 | case EFX_FARCH_FILTER_UDP_WILD: { | ||
360 | __be32 host1, host2; | ||
361 | __be16 port1, port2; | ||
362 | |||
363 | gen_spec->match_flags = | ||
364 | EFX_FILTER_MATCH_ETHER_TYPE | | ||
365 | EFX_FILTER_MATCH_IP_PROTO | | ||
366 | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT; | ||
367 | if (is_full) | ||
368 | gen_spec->match_flags |= (EFX_FILTER_MATCH_REM_HOST | | ||
369 | EFX_FILTER_MATCH_REM_PORT); | ||
370 | gen_spec->ether_type = htons(ETH_P_IP); | ||
371 | gen_spec->ip_proto = | ||
372 | (spec->type == EFX_FARCH_FILTER_TCP_FULL || | ||
373 | spec->type == EFX_FARCH_FILTER_TCP_WILD) ? | ||
374 | IPPROTO_TCP : IPPROTO_UDP; | ||
375 | |||
376 | host1 = htonl(spec->data[0] >> 16 | spec->data[1] << 16); | ||
377 | port1 = htons(spec->data[0]); | ||
378 | host2 = htonl(spec->data[2]); | ||
379 | port2 = htons(spec->data[1] >> 16); | ||
380 | if (spec->flags & EFX_FILTER_FLAG_TX) { | ||
381 | gen_spec->loc_host[0] = host1; | ||
382 | gen_spec->rem_host[0] = host2; | ||
383 | } else { | ||
384 | gen_spec->loc_host[0] = host2; | ||
385 | gen_spec->rem_host[0] = host1; | ||
386 | } | ||
387 | if (!!(gen_spec->flags & EFX_FILTER_FLAG_TX) ^ | ||
388 | (!is_full && gen_spec->ip_proto == IPPROTO_UDP)) { | ||
389 | gen_spec->loc_port = port1; | ||
390 | gen_spec->rem_port = port2; | ||
391 | } else { | ||
392 | gen_spec->loc_port = port2; | ||
393 | gen_spec->rem_port = port1; | ||
394 | } | ||
424 | 395 | ||
425 | spec->type = EFX_FILTER_UC_DEF; | 396 | break; |
426 | memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */ | 397 | } |
427 | return 0; | ||
428 | } | ||
429 | 398 | ||
430 | /** | 399 | case EFX_FARCH_FILTER_MAC_FULL: |
431 | * efx_filter_set_mc_def - specify matching otherwise-unmatched multicast | 400 | is_full = true; |
432 | * @spec: Specification to initialise | 401 | /* fall through */ |
433 | */ | 402 | case EFX_FARCH_FILTER_MAC_WILD: |
434 | int efx_filter_set_mc_def(struct efx_filter_spec *spec) | 403 | gen_spec->match_flags = EFX_FILTER_MATCH_LOC_MAC; |
435 | { | 404 | if (is_full) |
436 | EFX_BUG_ON_PARANOID(!(spec->flags & | 405 | gen_spec->match_flags |= EFX_FILTER_MATCH_OUTER_VID; |
437 | (EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX))); | 406 | gen_spec->loc_mac[0] = spec->data[2] >> 8; |
407 | gen_spec->loc_mac[1] = spec->data[2]; | ||
408 | gen_spec->loc_mac[2] = spec->data[1] >> 24; | ||
409 | gen_spec->loc_mac[3] = spec->data[1] >> 16; | ||
410 | gen_spec->loc_mac[4] = spec->data[1] >> 8; | ||
411 | gen_spec->loc_mac[5] = spec->data[1]; | ||
412 | gen_spec->outer_vid = htons(spec->data[0]); | ||
413 | break; | ||
438 | 414 | ||
439 | if (spec->type != EFX_FILTER_UNSPEC) | 415 | case EFX_FARCH_FILTER_UC_DEF: |
440 | return -EINVAL; | 416 | case EFX_FARCH_FILTER_MC_DEF: |
417 | gen_spec->match_flags = EFX_FILTER_MATCH_LOC_MAC_IG; | ||
418 | gen_spec->loc_mac[0] = spec->type == EFX_FARCH_FILTER_MC_DEF; | ||
419 | break; | ||
441 | 420 | ||
442 | spec->type = EFX_FILTER_MC_DEF; | 421 | default: |
443 | memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */ | 422 | WARN_ON(1); |
444 | return 0; | 423 | break; |
424 | } | ||
445 | } | 425 | } |
446 | 426 | ||
447 | static void | 427 | static void |
@@ -455,7 +435,7 @@ efx_farch_filter_reset_rx_def(struct efx_nic *efx, unsigned filter_idx) | |||
455 | /* If there's only one channel then disable RSS for non VF | 435 | /* If there's only one channel then disable RSS for non VF |
456 | * traffic, thereby allowing VFs to use RSS when the PF can't. | 436 | * traffic, thereby allowing VFs to use RSS when the PF can't. |
457 | */ | 437 | */ |
458 | spec->type = EFX_FILTER_UC_DEF + filter_idx; | 438 | spec->type = EFX_FARCH_FILTER_UC_DEF + filter_idx; |
459 | spec->priority = EFX_FILTER_PRI_MANUAL; | 439 | spec->priority = EFX_FILTER_PRI_MANUAL; |
460 | spec->flags = (EFX_FILTER_FLAG_RX | | 440 | spec->flags = (EFX_FILTER_FLAG_RX | |
461 | (efx->n_rx_channels > 1 ? EFX_FILTER_FLAG_RX_RSS : 0) | | 441 | (efx->n_rx_channels > 1 ? EFX_FILTER_FLAG_RX_RSS : 0) | |
@@ -464,29 +444,6 @@ efx_farch_filter_reset_rx_def(struct efx_nic *efx, unsigned filter_idx) | |||
464 | table->used_bitmap[0] |= 1 << filter_idx; | 444 | table->used_bitmap[0] |= 1 << filter_idx; |
465 | } | 445 | } |
466 | 446 | ||
467 | int efx_filter_get_eth_local(const struct efx_filter_spec *spec, | ||
468 | u16 *vid, u8 *addr) | ||
469 | { | ||
470 | switch (spec->type) { | ||
471 | case EFX_FILTER_MAC_WILD: | ||
472 | *vid = EFX_FILTER_VID_UNSPEC; | ||
473 | break; | ||
474 | case EFX_FILTER_MAC_FULL: | ||
475 | *vid = spec->data[0]; | ||
476 | break; | ||
477 | default: | ||
478 | return -EINVAL; | ||
479 | } | ||
480 | |||
481 | addr[0] = spec->data[2] >> 8; | ||
482 | addr[1] = spec->data[2]; | ||
483 | addr[2] = spec->data[1] >> 24; | ||
484 | addr[3] = spec->data[1] >> 16; | ||
485 | addr[4] = spec->data[1] >> 8; | ||
486 | addr[5] = spec->data[1]; | ||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | /* Build a filter entry and return its n-tuple key. */ | 447 | /* Build a filter entry and return its n-tuple key. */ |
491 | static u32 efx_farch_filter_build(efx_oword_t *filter, | 448 | static u32 efx_farch_filter_build(efx_oword_t *filter, |
492 | struct efx_farch_filter_spec *spec) | 449 | struct efx_farch_filter_spec *spec) |
@@ -495,8 +452,8 @@ static u32 efx_farch_filter_build(efx_oword_t *filter, | |||
495 | 452 | ||
496 | switch (efx_farch_filter_spec_table_id(spec)) { | 453 | switch (efx_farch_filter_spec_table_id(spec)) { |
497 | case EFX_FARCH_FILTER_TABLE_RX_IP: { | 454 | case EFX_FARCH_FILTER_TABLE_RX_IP: { |
498 | bool is_udp = (spec->type == EFX_FILTER_UDP_FULL || | 455 | bool is_udp = (spec->type == EFX_FARCH_FILTER_UDP_FULL || |
499 | spec->type == EFX_FILTER_UDP_WILD); | 456 | spec->type == EFX_FARCH_FILTER_UDP_WILD); |
500 | EFX_POPULATE_OWORD_7( | 457 | EFX_POPULATE_OWORD_7( |
501 | *filter, | 458 | *filter, |
502 | FRF_BZ_RSS_EN, | 459 | FRF_BZ_RSS_EN, |
@@ -513,7 +470,7 @@ static u32 efx_farch_filter_build(efx_oword_t *filter, | |||
513 | } | 470 | } |
514 | 471 | ||
515 | case EFX_FARCH_FILTER_TABLE_RX_MAC: { | 472 | case EFX_FARCH_FILTER_TABLE_RX_MAC: { |
516 | bool is_wild = spec->type == EFX_FILTER_MAC_WILD; | 473 | bool is_wild = spec->type == EFX_FARCH_FILTER_MAC_WILD; |
517 | EFX_POPULATE_OWORD_7( | 474 | EFX_POPULATE_OWORD_7( |
518 | *filter, | 475 | *filter, |
519 | FRF_CZ_RMFT_RSS_EN, | 476 | FRF_CZ_RMFT_RSS_EN, |
@@ -530,7 +487,7 @@ static u32 efx_farch_filter_build(efx_oword_t *filter, | |||
530 | } | 487 | } |
531 | 488 | ||
532 | case EFX_FARCH_FILTER_TABLE_TX_MAC: { | 489 | case EFX_FARCH_FILTER_TABLE_TX_MAC: { |
533 | bool is_wild = spec->type == EFX_FILTER_MAC_WILD; | 490 | bool is_wild = spec->type == EFX_FARCH_FILTER_MAC_WILD; |
534 | EFX_POPULATE_OWORD_5(*filter, | 491 | EFX_POPULATE_OWORD_5(*filter, |
535 | FRF_CZ_TMFT_TXQ_ID, spec->dmaq_id, | 492 | FRF_CZ_TMFT_TXQ_ID, spec->dmaq_id, |
536 | FRF_CZ_TMFT_WILDCARD_MATCH, is_wild, | 493 | FRF_CZ_TMFT_WILDCARD_MATCH, is_wild, |
@@ -573,15 +530,15 @@ static bool efx_farch_filter_equal(const struct efx_farch_filter_spec *left, | |||
573 | 530 | ||
574 | #define EFX_FARCH_FILTER_MATCH_PRI_COUNT 5 | 531 | #define EFX_FARCH_FILTER_MATCH_PRI_COUNT 5 |
575 | 532 | ||
576 | static const u8 efx_farch_filter_type_match_pri[EFX_FILTER_TYPE_COUNT] = { | 533 | static const u8 efx_farch_filter_type_match_pri[EFX_FARCH_FILTER_TYPE_COUNT] = { |
577 | [EFX_FILTER_TCP_FULL] = 0, | 534 | [EFX_FARCH_FILTER_TCP_FULL] = 0, |
578 | [EFX_FILTER_UDP_FULL] = 0, | 535 | [EFX_FARCH_FILTER_UDP_FULL] = 0, |
579 | [EFX_FILTER_TCP_WILD] = 1, | 536 | [EFX_FARCH_FILTER_TCP_WILD] = 1, |
580 | [EFX_FILTER_UDP_WILD] = 1, | 537 | [EFX_FARCH_FILTER_UDP_WILD] = 1, |
581 | [EFX_FILTER_MAC_FULL] = 2, | 538 | [EFX_FARCH_FILTER_MAC_FULL] = 2, |
582 | [EFX_FILTER_MAC_WILD] = 3, | 539 | [EFX_FARCH_FILTER_MAC_WILD] = 3, |
583 | [EFX_FILTER_UC_DEF] = 4, | 540 | [EFX_FARCH_FILTER_UC_DEF] = 4, |
584 | [EFX_FILTER_MC_DEF] = 4, | 541 | [EFX_FARCH_FILTER_MC_DEF] = 4, |
585 | }; | 542 | }; |
586 | 543 | ||
587 | static const enum efx_farch_filter_table_id efx_farch_filter_range_table[] = { | 544 | static const enum efx_farch_filter_table_id efx_farch_filter_range_table[] = { |
@@ -672,11 +629,12 @@ s32 efx_filter_insert_filter(struct efx_nic *efx, | |||
672 | unsigned int depth = 0; | 629 | unsigned int depth = 0; |
673 | int rc; | 630 | int rc; |
674 | 631 | ||
675 | /* XXX efx_farch_filter_spec and efx_filter_spec will diverge in future */ | 632 | rc = efx_farch_filter_from_gen_spec(&spec, gen_spec); |
676 | memcpy(&spec, gen_spec, sizeof(*gen_spec)); | 633 | if (rc) |
634 | return rc; | ||
677 | 635 | ||
678 | table = efx_farch_filter_spec_table(state, &spec); | 636 | table = &state->table[efx_farch_filter_spec_table_id(&spec)]; |
679 | if (!table || table->size == 0) | 637 | if (table->size == 0) |
680 | return -EINVAL; | 638 | return -EINVAL; |
681 | 639 | ||
682 | netif_vdbg(efx, hw, efx->net_dev, | 640 | netif_vdbg(efx, hw, efx->net_dev, |
@@ -687,8 +645,8 @@ s32 efx_filter_insert_filter(struct efx_nic *efx, | |||
687 | /* One filter spec per type */ | 645 | /* One filter spec per type */ |
688 | BUILD_BUG_ON(EFX_FARCH_FILTER_INDEX_UC_DEF != 0); | 646 | BUILD_BUG_ON(EFX_FARCH_FILTER_INDEX_UC_DEF != 0); |
689 | BUILD_BUG_ON(EFX_FARCH_FILTER_INDEX_MC_DEF != | 647 | BUILD_BUG_ON(EFX_FARCH_FILTER_INDEX_MC_DEF != |
690 | EFX_FILTER_MC_DEF - EFX_FILTER_UC_DEF); | 648 | EFX_FARCH_FILTER_MC_DEF - EFX_FARCH_FILTER_UC_DEF); |
691 | rep_index = spec.type - EFX_FILTER_UC_DEF; | 649 | rep_index = spec.type - EFX_FARCH_FILTER_UC_DEF; |
692 | ins_index = rep_index; | 650 | ins_index = rep_index; |
693 | 651 | ||
694 | spin_lock_bh(&state->lock); | 652 | spin_lock_bh(&state->lock); |
@@ -911,8 +869,7 @@ int efx_filter_get_filter_safe(struct efx_nic *efx, | |||
911 | 869 | ||
912 | if (test_bit(filter_idx, table->used_bitmap) && | 870 | if (test_bit(filter_idx, table->used_bitmap) && |
913 | spec->priority == priority) { | 871 | spec->priority == priority) { |
914 | /* XXX efx_farch_filter_spec and efx_filter_spec will diverge */ | 872 | efx_farch_filter_to_gen_spec(spec_buf, spec); |
915 | memcpy(spec_buf, spec, sizeof(*spec)); | ||
916 | rc = 0; | 873 | rc = 0; |
917 | } else { | 874 | } else { |
918 | rc = -ENOENT; | 875 | rc = -ENOENT; |
diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h index b1170d44171e..1b410defccec 100644 --- a/drivers/net/ethernet/sfc/filter.h +++ b/drivers/net/ethernet/sfc/filter.h | |||
@@ -11,32 +11,49 @@ | |||
11 | #define EFX_FILTER_H | 11 | #define EFX_FILTER_H |
12 | 12 | ||
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/if_ether.h> | ||
15 | #include <asm/byteorder.h> | ||
14 | 16 | ||
15 | /** | 17 | /** |
16 | * enum efx_filter_type - type of hardware filter | 18 | * enum efx_filter_match_flags - Flags for hardware filter match type |
17 | * @EFX_FILTER_TCP_FULL: Matching TCP/IPv4 4-tuple | 19 | * @EFX_FILTER_MATCH_REM_HOST: Match by remote IP host address |
18 | * @EFX_FILTER_TCP_WILD: Matching TCP/IPv4 destination (host, port) | 20 | * @EFX_FILTER_MATCH_LOC_HOST: Match by local IP host address |
19 | * @EFX_FILTER_UDP_FULL: Matching UDP/IPv4 4-tuple | 21 | * @EFX_FILTER_MATCH_REM_MAC: Match by remote MAC address |
20 | * @EFX_FILTER_UDP_WILD: Matching UDP/IPv4 destination (host, port) | 22 | * @EFX_FILTER_MATCH_REM_PORT: Match by remote TCP/UDP port |
21 | * @EFX_FILTER_MAC_FULL: Matching Ethernet destination MAC address, VID | 23 | * @EFX_FILTER_MATCH_LOC_MAC: Match by local MAC address |
22 | * @EFX_FILTER_MAC_WILD: Matching Ethernet destination MAC address | 24 | * @EFX_FILTER_MATCH_LOC_PORT: Match by local TCP/UDP port |
23 | * @EFX_FILTER_UC_DEF: Matching all otherwise unmatched unicast | 25 | * @EFX_FILTER_MATCH_ETHER_TYPE: Match by Ether-type |
24 | * @EFX_FILTER_MC_DEF: Matching all otherwise unmatched multicast | 26 | * @EFX_FILTER_MATCH_INNER_VID: Match by inner VLAN ID |
25 | * @EFX_FILTER_UNSPEC: Match type is unspecified | 27 | * @EFX_FILTER_MATCH_OUTER_VID: Match by outer VLAN ID |
28 | * @EFX_FILTER_MATCH_IP_PROTO: Match by IP transport protocol | ||
29 | * @EFX_FILTER_MATCH_LOC_MAC_IG: Match by local MAC address I/G bit. | ||
30 | * Used for RX default unicast and multicast/broadcast filters. | ||
26 | * | 31 | * |
27 | * Falcon NICs only support the TCP/IPv4 and UDP/IPv4 filter types. | 32 | * Only some combinations are supported, depending on NIC type: |
33 | * | ||
34 | * - Falcon supports RX filters matching by {TCP,UDP}/IPv4 4-tuple or | ||
35 | * local 2-tuple (only implemented for Falcon B0) | ||
36 | * | ||
37 | * - Siena supports RX and TX filters matching by {TCP,UDP}/IPv4 4-tuple | ||
38 | * or local 2-tuple, or local MAC with or without outer VID, and RX | ||
39 | * default filters | ||
40 | * | ||
41 | * - Huntington supports filter matching controlled by firmware, potentially | ||
42 | * using {TCP,UDP}/IPv{4,6} 4-tuple or local 2-tuple, local MAC or I/G bit, | ||
43 | * with or without outer and inner VID | ||
28 | */ | 44 | */ |
29 | enum efx_filter_type { | 45 | enum efx_filter_match_flags { |
30 | EFX_FILTER_TCP_FULL = 0, | 46 | EFX_FILTER_MATCH_REM_HOST = 0x0001, |
31 | EFX_FILTER_TCP_WILD, | 47 | EFX_FILTER_MATCH_LOC_HOST = 0x0002, |
32 | EFX_FILTER_UDP_FULL, | 48 | EFX_FILTER_MATCH_REM_MAC = 0x0004, |
33 | EFX_FILTER_UDP_WILD, | 49 | EFX_FILTER_MATCH_REM_PORT = 0x0008, |
34 | EFX_FILTER_MAC_FULL = 4, | 50 | EFX_FILTER_MATCH_LOC_MAC = 0x0010, |
35 | EFX_FILTER_MAC_WILD, | 51 | EFX_FILTER_MATCH_LOC_PORT = 0x0020, |
36 | EFX_FILTER_UC_DEF = 8, | 52 | EFX_FILTER_MATCH_ETHER_TYPE = 0x0040, |
37 | EFX_FILTER_MC_DEF, | 53 | EFX_FILTER_MATCH_INNER_VID = 0x0080, |
38 | EFX_FILTER_TYPE_COUNT, /* number of specific types */ | 54 | EFX_FILTER_MATCH_OUTER_VID = 0x0100, |
39 | EFX_FILTER_UNSPEC = 0xf, | 55 | EFX_FILTER_MATCH_IP_PROTO = 0x0200, |
56 | EFX_FILTER_MATCH_LOC_MAC_IG = 0x0400, | ||
40 | }; | 57 | }; |
41 | 58 | ||
42 | /** | 59 | /** |
@@ -73,29 +90,55 @@ enum efx_filter_flags { | |||
73 | 90 | ||
74 | /** | 91 | /** |
75 | * struct efx_filter_spec - specification for a hardware filter | 92 | * struct efx_filter_spec - specification for a hardware filter |
76 | * @type: Type of match to be performed, from &enum efx_filter_type | 93 | * @match_flags: Match type flags, from &enum efx_filter_match_flags |
77 | * @priority: Priority of the filter, from &enum efx_filter_priority | 94 | * @priority: Priority of the filter, from &enum efx_filter_priority |
78 | * @flags: Miscellaneous flags, from &enum efx_filter_flags | 95 | * @flags: Miscellaneous flags, from &enum efx_filter_flags |
96 | * @rss_context: RSS context to use, if %EFX_FILTER_FLAG_RX_RSS is set | ||
79 | * @dmaq_id: Source/target queue index, or %EFX_FILTER_RX_DMAQ_ID_DROP for | 97 | * @dmaq_id: Source/target queue index, or %EFX_FILTER_RX_DMAQ_ID_DROP for |
80 | * an RX drop filter | 98 | * an RX drop filter |
81 | * @data: Match data (type-dependent) | 99 | * @outer_vid: Outer VLAN ID to match, if %EFX_FILTER_MATCH_OUTER_VID is set |
100 | * @inner_vid: Inner VLAN ID to match, if %EFX_FILTER_MATCH_INNER_VID is set | ||
101 | * @loc_mac: Local MAC address to match, if %EFX_FILTER_MATCH_LOC_MAC or | ||
102 | * %EFX_FILTER_MATCH_LOC_MAC_IG is set | ||
103 | * @rem_mac: Remote MAC address to match, if %EFX_FILTER_MATCH_REM_MAC is set | ||
104 | * @ether_type: Ether-type to match, if %EFX_FILTER_MATCH_ETHER_TYPE is set | ||
105 | * @ip_proto: IP transport protocol to match, if %EFX_FILTER_MATCH_IP_PROTO | ||
106 | * is set | ||
107 | * @loc_host: Local IP host to match, if %EFX_FILTER_MATCH_LOC_HOST is set | ||
108 | * @rem_host: Remote IP host to match, if %EFX_FILTER_MATCH_REM_HOST is set | ||
109 | * @loc_port: Local TCP/UDP port to match, if %EFX_FILTER_MATCH_LOC_PORT is set | ||
110 | * @rem_port: Remote TCP/UDP port to match, if %EFX_FILTER_MATCH_REM_PORT is set | ||
82 | * | 111 | * |
83 | * Use the efx_filter_set_*() functions to initialise the @type and | 112 | * The efx_filter_init_rx() or efx_filter_init_tx() function *must* be |
84 | * @data fields. | 113 | * used to initialise the structure. The efx_filter_set_*() functions |
114 | * may then be used to set @rss_context, @match_flags and related | ||
115 | * fields. | ||
85 | * | 116 | * |
86 | * The @priority field is used by software to determine whether a new | 117 | * The @priority field is used by software to determine whether a new |
87 | * filter may replace an old one. The hardware priority of a filter | 118 | * filter may replace an old one. The hardware priority of a filter |
88 | * depends on the filter type. | 119 | * depends on which fields are matched. |
89 | */ | 120 | */ |
90 | struct efx_filter_spec { | 121 | struct efx_filter_spec { |
91 | u8 type:4; | 122 | u32 match_flags:12; |
92 | u8 priority:4; | 123 | u32 priority:2; |
93 | u8 flags; | 124 | u32 flags:6; |
94 | u16 dmaq_id; | 125 | u32 dmaq_id:12; |
95 | u32 data[3]; | 126 | u32 rss_context; |
127 | __be16 outer_vid __aligned(4); /* allow jhash2() of match values */ | ||
128 | __be16 inner_vid; | ||
129 | u8 loc_mac[ETH_ALEN]; | ||
130 | u8 rem_mac[ETH_ALEN]; | ||
131 | __be16 ether_type; | ||
132 | u8 ip_proto; | ||
133 | __be32 loc_host[4]; | ||
134 | __be32 rem_host[4]; | ||
135 | __be16 loc_port; | ||
136 | __be16 rem_port; | ||
137 | /* total 64 bytes */ | ||
96 | }; | 138 | }; |
97 | 139 | ||
98 | enum { | 140 | enum { |
141 | EFX_FILTER_RSS_CONTEXT_DEFAULT = 0xffffffff, | ||
99 | EFX_FILTER_RX_DMAQ_ID_DROP = 0xfff | 142 | EFX_FILTER_RX_DMAQ_ID_DROP = 0xfff |
100 | }; | 143 | }; |
101 | 144 | ||
@@ -104,39 +147,116 @@ static inline void efx_filter_init_rx(struct efx_filter_spec *spec, | |||
104 | enum efx_filter_flags flags, | 147 | enum efx_filter_flags flags, |
105 | unsigned rxq_id) | 148 | unsigned rxq_id) |
106 | { | 149 | { |
107 | spec->type = EFX_FILTER_UNSPEC; | 150 | memset(spec, 0, sizeof(*spec)); |
108 | spec->priority = priority; | 151 | spec->priority = priority; |
109 | spec->flags = EFX_FILTER_FLAG_RX | flags; | 152 | spec->flags = EFX_FILTER_FLAG_RX | flags; |
153 | spec->rss_context = EFX_FILTER_RSS_CONTEXT_DEFAULT; | ||
110 | spec->dmaq_id = rxq_id; | 154 | spec->dmaq_id = rxq_id; |
111 | } | 155 | } |
112 | 156 | ||
113 | static inline void efx_filter_init_tx(struct efx_filter_spec *spec, | 157 | static inline void efx_filter_init_tx(struct efx_filter_spec *spec, |
114 | unsigned txq_id) | 158 | unsigned txq_id) |
115 | { | 159 | { |
116 | spec->type = EFX_FILTER_UNSPEC; | 160 | memset(spec, 0, sizeof(*spec)); |
117 | spec->priority = EFX_FILTER_PRI_REQUIRED; | 161 | spec->priority = EFX_FILTER_PRI_REQUIRED; |
118 | spec->flags = EFX_FILTER_FLAG_TX; | 162 | spec->flags = EFX_FILTER_FLAG_TX; |
119 | spec->dmaq_id = txq_id; | 163 | spec->dmaq_id = txq_id; |
120 | } | 164 | } |
121 | 165 | ||
122 | extern int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto, | 166 | /** |
123 | __be32 host, __be16 port); | 167 | * efx_filter_set_ipv4_local - specify IPv4 host, transport protocol and port |
124 | extern int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec, | 168 | * @spec: Specification to initialise |
125 | u8 *proto, __be32 *host, __be16 *port); | 169 | * @proto: Transport layer protocol number |
126 | extern int efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto, | 170 | * @host: Local host address (network byte order) |
127 | __be32 host, __be16 port, | 171 | * @port: Local port (network byte order) |
128 | __be32 rhost, __be16 rport); | 172 | */ |
129 | extern int efx_filter_get_ipv4_full(const struct efx_filter_spec *spec, | 173 | static inline int |
130 | u8 *proto, __be32 *host, __be16 *port, | 174 | efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto, |
131 | __be32 *rhost, __be16 *rport); | 175 | __be32 host, __be16 port) |
132 | extern int efx_filter_set_eth_local(struct efx_filter_spec *spec, | 176 | { |
133 | u16 vid, const u8 *addr); | 177 | spec->match_flags |= |
134 | extern int efx_filter_get_eth_local(const struct efx_filter_spec *spec, | 178 | EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | |
135 | u16 *vid, u8 *addr); | 179 | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT; |
136 | extern int efx_filter_set_uc_def(struct efx_filter_spec *spec); | 180 | spec->ether_type = htons(ETH_P_IP); |
137 | extern int efx_filter_set_mc_def(struct efx_filter_spec *spec); | 181 | spec->ip_proto = proto; |
182 | spec->loc_host[0] = host; | ||
183 | spec->loc_port = port; | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * efx_filter_set_ipv4_full - specify IPv4 hosts, transport protocol and ports | ||
189 | * @spec: Specification to initialise | ||
190 | * @proto: Transport layer protocol number | ||
191 | * @lhost: Local host address (network byte order) | ||
192 | * @lport: Local port (network byte order) | ||
193 | * @rhost: Remote host address (network byte order) | ||
194 | * @rport: Remote port (network byte order) | ||
195 | */ | ||
196 | static inline int | ||
197 | efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto, | ||
198 | __be32 lhost, __be16 lport, | ||
199 | __be32 rhost, __be16 rport) | ||
200 | { | ||
201 | spec->match_flags |= | ||
202 | EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | | ||
203 | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | | ||
204 | EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT; | ||
205 | spec->ether_type = htons(ETH_P_IP); | ||
206 | spec->ip_proto = proto; | ||
207 | spec->loc_host[0] = lhost; | ||
208 | spec->loc_port = lport; | ||
209 | spec->rem_host[0] = rhost; | ||
210 | spec->rem_port = rport; | ||
211 | return 0; | ||
212 | } | ||
213 | |||
138 | enum { | 214 | enum { |
139 | EFX_FILTER_VID_UNSPEC = 0xffff, | 215 | EFX_FILTER_VID_UNSPEC = 0xffff, |
140 | }; | 216 | }; |
141 | 217 | ||
218 | /** | ||
219 | * efx_filter_set_eth_local - specify local Ethernet address and/or VID | ||
220 | * @spec: Specification to initialise | ||
221 | * @vid: Outer VLAN ID to match, or %EFX_FILTER_VID_UNSPEC | ||
222 | * @addr: Local Ethernet MAC address, or %NULL | ||
223 | */ | ||
224 | static inline int efx_filter_set_eth_local(struct efx_filter_spec *spec, | ||
225 | u16 vid, const u8 *addr) | ||
226 | { | ||
227 | if (vid == EFX_FILTER_VID_UNSPEC && addr == NULL) | ||
228 | return -EINVAL; | ||
229 | |||
230 | if (vid != EFX_FILTER_VID_UNSPEC) { | ||
231 | spec->match_flags |= EFX_FILTER_MATCH_OUTER_VID; | ||
232 | spec->outer_vid = htons(vid); | ||
233 | } | ||
234 | if (addr != NULL) { | ||
235 | spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC; | ||
236 | memcpy(spec->loc_mac, addr, ETH_ALEN); | ||
237 | } | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * efx_filter_set_uc_def - specify matching otherwise-unmatched unicast | ||
243 | * @spec: Specification to initialise | ||
244 | */ | ||
245 | static inline int efx_filter_set_uc_def(struct efx_filter_spec *spec) | ||
246 | { | ||
247 | spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG; | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * efx_filter_set_mc_def - specify matching otherwise-unmatched multicast | ||
253 | * @spec: Specification to initialise | ||
254 | */ | ||
255 | static inline int efx_filter_set_mc_def(struct efx_filter_spec *spec) | ||
256 | { | ||
257 | spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG; | ||
258 | spec->loc_mac[0] = 1; | ||
259 | return 0; | ||
260 | } | ||
261 | |||
142 | #endif /* EFX_FILTER_H */ | 262 | #endif /* EFX_FILTER_H */ |