diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2010-12-07 14:11:26 -0500 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2010-12-07 14:11:26 -0500 |
commit | c39d35ebffeea5996a6f8fd8430fae9acfb8aeaf (patch) | |
tree | af09ac5b15429b41d4b5c54fd63c1ac769d67b39 /drivers | |
parent | 8891681af928f1da795cd4bd59043e5e0fadd6c8 (diff) |
sfc: Generalise filter spec initialisation
Move search_depth arrays into per-table state.
Define initialisation function efx_filter_init_rx() which sets
everything apart from the match fields.
Define efx_filter_set_{ipv4_local,ipv4_full,eth_local}() to set the
match fields. This allows some simplification of callers and later
support for additional protocols and more flexible matching using
multiple calls to these functions.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/sfc/ethtool.c | 82 | ||||
-rw-r--r-- | drivers/net/sfc/filter.c | 214 | ||||
-rw-r--r-- | drivers/net/sfc/filter.h | 143 |
3 files changed, 248 insertions, 191 deletions
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 0f46c1a3171e..5e50e57b0ae2 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/netdevice.h> | 11 | #include <linux/netdevice.h> |
12 | #include <linux/ethtool.h> | 12 | #include <linux/ethtool.h> |
13 | #include <linux/rtnetlink.h> | 13 | #include <linux/rtnetlink.h> |
14 | #include <linux/in.h> | ||
14 | #include "net_driver.h" | 15 | #include "net_driver.h" |
15 | #include "workarounds.h" | 16 | #include "workarounds.h" |
16 | #include "selftest.h" | 17 | #include "selftest.h" |
@@ -920,6 +921,7 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev, | |||
920 | struct ethhdr *mac_entry = &ntuple->fs.h_u.ether_spec; | 921 | struct ethhdr *mac_entry = &ntuple->fs.h_u.ether_spec; |
921 | struct ethhdr *mac_mask = &ntuple->fs.m_u.ether_spec; | 922 | struct ethhdr *mac_mask = &ntuple->fs.m_u.ether_spec; |
922 | struct efx_filter_spec filter; | 923 | struct efx_filter_spec filter; |
924 | int rc; | ||
923 | 925 | ||
924 | /* Range-check action */ | 926 | /* Range-check action */ |
925 | if (ntuple->fs.action < ETHTOOL_RXNTUPLE_ACTION_CLEAR || | 927 | if (ntuple->fs.action < ETHTOOL_RXNTUPLE_ACTION_CLEAR || |
@@ -929,9 +931,16 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev, | |||
929 | if (~ntuple->fs.data_mask) | 931 | if (~ntuple->fs.data_mask) |
930 | return -EINVAL; | 932 | return -EINVAL; |
931 | 933 | ||
934 | efx_filter_init_rx(&filter, EFX_FILTER_PRI_MANUAL, 0, | ||
935 | (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) ? | ||
936 | 0xfff : ntuple->fs.action); | ||
937 | |||
932 | switch (ntuple->fs.flow_type) { | 938 | switch (ntuple->fs.flow_type) { |
933 | case TCP_V4_FLOW: | 939 | case TCP_V4_FLOW: |
934 | case UDP_V4_FLOW: | 940 | case UDP_V4_FLOW: { |
941 | u8 proto = (ntuple->fs.flow_type == TCP_V4_FLOW ? | ||
942 | IPPROTO_TCP : IPPROTO_UDP); | ||
943 | |||
935 | /* Must match all of destination, */ | 944 | /* Must match all of destination, */ |
936 | if (ip_mask->ip4dst | ip_mask->pdst) | 945 | if (ip_mask->ip4dst | ip_mask->pdst) |
937 | return -EINVAL; | 946 | return -EINVAL; |
@@ -943,7 +952,22 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev, | |||
943 | /* and nothing else */ | 952 | /* and nothing else */ |
944 | if ((u8)~ip_mask->tos | (u16)~ntuple->fs.vlan_tag_mask) | 953 | if ((u8)~ip_mask->tos | (u16)~ntuple->fs.vlan_tag_mask) |
945 | return -EINVAL; | 954 | return -EINVAL; |
955 | |||
956 | if (!ip_mask->ip4src) | ||
957 | rc = efx_filter_set_ipv4_full(&filter, proto, | ||
958 | ip_entry->ip4dst, | ||
959 | ip_entry->pdst, | ||
960 | ip_entry->ip4src, | ||
961 | ip_entry->psrc); | ||
962 | else | ||
963 | rc = efx_filter_set_ipv4_local(&filter, proto, | ||
964 | ip_entry->ip4dst, | ||
965 | ip_entry->pdst); | ||
966 | if (rc) | ||
967 | return rc; | ||
946 | break; | 968 | break; |
969 | } | ||
970 | |||
947 | case ETHER_FLOW: | 971 | case ETHER_FLOW: |
948 | /* Must match all of destination, */ | 972 | /* Must match all of destination, */ |
949 | if (!is_zero_ether_addr(mac_mask->h_dest)) | 973 | if (!is_zero_ether_addr(mac_mask->h_dest)) |
@@ -956,58 +980,24 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev, | |||
956 | if (!is_broadcast_ether_addr(mac_mask->h_source) || | 980 | if (!is_broadcast_ether_addr(mac_mask->h_source) || |
957 | mac_mask->h_proto != htons(0xffff)) | 981 | mac_mask->h_proto != htons(0xffff)) |
958 | return -EINVAL; | 982 | return -EINVAL; |
983 | |||
984 | rc = efx_filter_set_eth_local( | ||
985 | &filter, | ||
986 | (ntuple->fs.vlan_tag_mask == 0xf000) ? | ||
987 | ntuple->fs.vlan_tag : EFX_FILTER_VID_UNSPEC, | ||
988 | mac_entry->h_dest); | ||
989 | if (rc) | ||
990 | return rc; | ||
959 | break; | 991 | break; |
992 | |||
960 | default: | 993 | default: |
961 | return -EINVAL; | 994 | return -EINVAL; |
962 | } | 995 | } |
963 | 996 | ||
964 | filter.priority = EFX_FILTER_PRI_MANUAL; | 997 | if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR) |
965 | filter.flags = 0; | ||
966 | |||
967 | switch (ntuple->fs.flow_type) { | ||
968 | case TCP_V4_FLOW: | ||
969 | if (!ip_mask->ip4src) | ||
970 | efx_filter_set_rx_tcp_full(&filter, | ||
971 | htonl(ip_entry->ip4src), | ||
972 | htons(ip_entry->psrc), | ||
973 | htonl(ip_entry->ip4dst), | ||
974 | htons(ip_entry->pdst)); | ||
975 | else | ||
976 | efx_filter_set_rx_tcp_wild(&filter, | ||
977 | htonl(ip_entry->ip4dst), | ||
978 | htons(ip_entry->pdst)); | ||
979 | break; | ||
980 | case UDP_V4_FLOW: | ||
981 | if (!ip_mask->ip4src) | ||
982 | efx_filter_set_rx_udp_full(&filter, | ||
983 | htonl(ip_entry->ip4src), | ||
984 | htons(ip_entry->psrc), | ||
985 | htonl(ip_entry->ip4dst), | ||
986 | htons(ip_entry->pdst)); | ||
987 | else | ||
988 | efx_filter_set_rx_udp_wild(&filter, | ||
989 | htonl(ip_entry->ip4dst), | ||
990 | htons(ip_entry->pdst)); | ||
991 | break; | ||
992 | case ETHER_FLOW: | ||
993 | if (ntuple->fs.vlan_tag_mask == 0xf000) | ||
994 | efx_filter_set_rx_mac_full(&filter, | ||
995 | ntuple->fs.vlan_tag & 0xfff, | ||
996 | mac_entry->h_dest); | ||
997 | else | ||
998 | efx_filter_set_rx_mac_wild(&filter, mac_entry->h_dest); | ||
999 | break; | ||
1000 | } | ||
1001 | |||
1002 | if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR) { | ||
1003 | return efx_filter_remove_filter(efx, &filter); | 998 | return efx_filter_remove_filter(efx, &filter); |
1004 | } else { | 999 | else |
1005 | if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) | ||
1006 | filter.dmaq_id = 0xfff; | ||
1007 | else | ||
1008 | filter.dmaq_id = ntuple->fs.action; | ||
1009 | return efx_filter_insert_filter(efx, &filter, true); | 1000 | return efx_filter_insert_filter(efx, &filter, true); |
1010 | } | ||
1011 | } | 1001 | } |
1012 | 1002 | ||
1013 | static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, | 1003 | static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, |
diff --git a/drivers/net/sfc/filter.c b/drivers/net/sfc/filter.c index e96e6e852f16..d4722c41c4ce 100644 --- a/drivers/net/sfc/filter.c +++ b/drivers/net/sfc/filter.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * by the Free Software Foundation, incorporated herein by reference. | 7 | * by the Free Software Foundation, incorporated herein by reference. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/in.h> | ||
10 | #include "efx.h" | 11 | #include "efx.h" |
11 | #include "filter.h" | 12 | #include "filter.h" |
12 | #include "io.h" | 13 | #include "io.h" |
@@ -33,18 +34,19 @@ enum efx_filter_table_id { | |||
33 | }; | 34 | }; |
34 | 35 | ||
35 | struct efx_filter_table { | 36 | struct efx_filter_table { |
37 | enum efx_filter_table_id id; | ||
36 | u32 offset; /* address of table relative to BAR */ | 38 | u32 offset; /* address of table relative to BAR */ |
37 | unsigned size; /* number of entries */ | 39 | unsigned size; /* number of entries */ |
38 | unsigned step; /* step between entries */ | 40 | unsigned step; /* step between entries */ |
39 | unsigned used; /* number currently used */ | 41 | unsigned used; /* number currently used */ |
40 | unsigned long *used_bitmap; | 42 | unsigned long *used_bitmap; |
41 | struct efx_filter_spec *spec; | 43 | struct efx_filter_spec *spec; |
44 | unsigned search_depth[EFX_FILTER_TYPE_COUNT]; | ||
42 | }; | 45 | }; |
43 | 46 | ||
44 | struct efx_filter_state { | 47 | struct efx_filter_state { |
45 | spinlock_t lock; | 48 | spinlock_t lock; |
46 | struct efx_filter_table table[EFX_FILTER_TABLE_COUNT]; | 49 | struct efx_filter_table table[EFX_FILTER_TABLE_COUNT]; |
47 | unsigned search_depth[EFX_FILTER_TYPE_COUNT]; | ||
48 | }; | 50 | }; |
49 | 51 | ||
50 | /* The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit | 52 | /* The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit |
@@ -71,68 +73,203 @@ static u16 efx_filter_increment(u32 key) | |||
71 | } | 73 | } |
72 | 74 | ||
73 | static enum efx_filter_table_id | 75 | static enum efx_filter_table_id |
74 | efx_filter_type_table_id(enum efx_filter_type type) | 76 | efx_filter_spec_table_id(const struct efx_filter_spec *spec) |
77 | { | ||
78 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_TCP_FULL >> 2)); | ||
79 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_TCP_WILD >> 2)); | ||
80 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_UDP_FULL >> 2)); | ||
81 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_UDP_WILD >> 2)); | ||
82 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_FULL >> 2)); | ||
83 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_WILD >> 2)); | ||
84 | EFX_BUG_ON_PARANOID(spec->type == EFX_FILTER_UNSPEC); | ||
85 | return spec->type >> 2; | ||
86 | } | ||
87 | |||
88 | static struct efx_filter_table * | ||
89 | efx_filter_spec_table(struct efx_filter_state *state, | ||
90 | const struct efx_filter_spec *spec) | ||
75 | { | 91 | { |
76 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_TCP_FULL >> 2)); | 92 | if (spec->type == EFX_FILTER_UNSPEC) |
77 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_TCP_WILD >> 2)); | 93 | return NULL; |
78 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_UDP_FULL >> 2)); | 94 | else |
79 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_UDP_WILD >> 2)); | 95 | return &state->table[efx_filter_spec_table_id(spec)]; |
80 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_RX_MAC_FULL >> 2)); | ||
81 | BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_RX_MAC_WILD >> 2)); | ||
82 | return type >> 2; | ||
83 | } | 96 | } |
84 | 97 | ||
85 | static void | 98 | static void efx_filter_table_reset_search_depth(struct efx_filter_table *table) |
86 | efx_filter_table_reset_search_depth(struct efx_filter_state *state, | ||
87 | enum efx_filter_table_id table_id) | ||
88 | { | 99 | { |
89 | memset(state->search_depth + (table_id << 2), 0, | 100 | memset(table->search_depth, 0, sizeof(table->search_depth)); |
90 | sizeof(state->search_depth[0]) << 2); | ||
91 | } | 101 | } |
92 | 102 | ||
93 | static void efx_filter_push_rx_limits(struct efx_nic *efx) | 103 | static void efx_filter_push_rx_limits(struct efx_nic *efx) |
94 | { | 104 | { |
95 | struct efx_filter_state *state = efx->filter_state; | 105 | struct efx_filter_state *state = efx->filter_state; |
106 | struct efx_filter_table *table; | ||
96 | efx_oword_t filter_ctl; | 107 | efx_oword_t filter_ctl; |
97 | 108 | ||
98 | efx_reado(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL); | 109 | efx_reado(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL); |
99 | 110 | ||
111 | table = &state->table[EFX_FILTER_TABLE_RX_IP]; | ||
100 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_FULL_SRCH_LIMIT, | 112 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_FULL_SRCH_LIMIT, |
101 | state->search_depth[EFX_FILTER_RX_TCP_FULL] + | 113 | table->search_depth[EFX_FILTER_TCP_FULL] + |
102 | FILTER_CTL_SRCH_FUDGE_FULL); | 114 | FILTER_CTL_SRCH_FUDGE_FULL); |
103 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_WILD_SRCH_LIMIT, | 115 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_WILD_SRCH_LIMIT, |
104 | state->search_depth[EFX_FILTER_RX_TCP_WILD] + | 116 | table->search_depth[EFX_FILTER_TCP_WILD] + |
105 | FILTER_CTL_SRCH_FUDGE_WILD); | 117 | FILTER_CTL_SRCH_FUDGE_WILD); |
106 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_FULL_SRCH_LIMIT, | 118 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_FULL_SRCH_LIMIT, |
107 | state->search_depth[EFX_FILTER_RX_UDP_FULL] + | 119 | table->search_depth[EFX_FILTER_UDP_FULL] + |
108 | FILTER_CTL_SRCH_FUDGE_FULL); | 120 | FILTER_CTL_SRCH_FUDGE_FULL); |
109 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_WILD_SRCH_LIMIT, | 121 | EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_WILD_SRCH_LIMIT, |
110 | state->search_depth[EFX_FILTER_RX_UDP_WILD] + | 122 | table->search_depth[EFX_FILTER_UDP_WILD] + |
111 | FILTER_CTL_SRCH_FUDGE_WILD); | 123 | FILTER_CTL_SRCH_FUDGE_WILD); |
112 | 124 | ||
113 | if (state->table[EFX_FILTER_TABLE_RX_MAC].size) { | 125 | table = &state->table[EFX_FILTER_TABLE_RX_MAC]; |
126 | if (table->size) { | ||
114 | EFX_SET_OWORD_FIELD( | 127 | EFX_SET_OWORD_FIELD( |
115 | filter_ctl, FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT, | 128 | filter_ctl, FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT, |
116 | state->search_depth[EFX_FILTER_RX_MAC_FULL] + | 129 | table->search_depth[EFX_FILTER_MAC_FULL] + |
117 | FILTER_CTL_SRCH_FUDGE_FULL); | 130 | FILTER_CTL_SRCH_FUDGE_FULL); |
118 | EFX_SET_OWORD_FIELD( | 131 | EFX_SET_OWORD_FIELD( |
119 | filter_ctl, FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT, | 132 | filter_ctl, FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT, |
120 | state->search_depth[EFX_FILTER_RX_MAC_WILD] + | 133 | table->search_depth[EFX_FILTER_MAC_WILD] + |
121 | FILTER_CTL_SRCH_FUDGE_WILD); | 134 | FILTER_CTL_SRCH_FUDGE_WILD); |
122 | } | 135 | } |
123 | 136 | ||
124 | efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL); | 137 | efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL); |
125 | } | 138 | } |
126 | 139 | ||
140 | static inline void __efx_filter_set_ipv4(struct efx_filter_spec *spec, | ||
141 | __be32 host1, __be16 port1, | ||
142 | __be32 host2, __be16 port2) | ||
143 | { | ||
144 | spec->data[0] = ntohl(host1) << 16 | ntohs(port1); | ||
145 | spec->data[1] = ntohs(port2) << 16 | ntohl(host1) >> 16; | ||
146 | spec->data[2] = ntohl(host2); | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * efx_filter_set_ipv4_local - specify IPv4 host, transport protocol and port | ||
151 | * @spec: Specification to initialise | ||
152 | * @proto: Transport layer protocol number | ||
153 | * @host: Local host address (network byte order) | ||
154 | * @port: Local port (network byte order) | ||
155 | */ | ||
156 | int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto, | ||
157 | __be32 host, __be16 port) | ||
158 | { | ||
159 | __be32 host1; | ||
160 | __be16 port1; | ||
161 | |||
162 | EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX)); | ||
163 | |||
164 | /* This cannot currently be combined with other filtering */ | ||
165 | if (spec->type != EFX_FILTER_UNSPEC) | ||
166 | return -EPROTONOSUPPORT; | ||
167 | |||
168 | if (port == 0) | ||
169 | return -EINVAL; | ||
170 | |||
171 | switch (proto) { | ||
172 | case IPPROTO_TCP: | ||
173 | spec->type = EFX_FILTER_TCP_WILD; | ||
174 | break; | ||
175 | case IPPROTO_UDP: | ||
176 | spec->type = EFX_FILTER_UDP_WILD; | ||
177 | break; | ||
178 | default: | ||
179 | return -EPROTONOSUPPORT; | ||
180 | } | ||
181 | |||
182 | /* Filter is constructed in terms of source and destination, | ||
183 | * with the odd wrinkle that the ports are swapped in a UDP | ||
184 | * wildcard filter. We need to convert from local and remote | ||
185 | * (= zero for wildcard) addresses. | ||
186 | */ | ||
187 | host1 = 0; | ||
188 | if (proto != IPPROTO_UDP) { | ||
189 | port1 = 0; | ||
190 | } else { | ||
191 | port1 = port; | ||
192 | port = 0; | ||
193 | } | ||
194 | |||
195 | __efx_filter_set_ipv4(spec, host1, port1, host, port); | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * efx_filter_set_ipv4_full - specify IPv4 hosts, transport protocol and ports | ||
201 | * @spec: Specification to initialise | ||
202 | * @proto: Transport layer protocol number | ||
203 | * @host: Local host address (network byte order) | ||
204 | * @port: Local port (network byte order) | ||
205 | * @rhost: Remote host address (network byte order) | ||
206 | * @rport: Remote port (network byte order) | ||
207 | */ | ||
208 | int efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto, | ||
209 | __be32 host, __be16 port, | ||
210 | __be32 rhost, __be16 rport) | ||
211 | { | ||
212 | EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX)); | ||
213 | |||
214 | /* This cannot currently be combined with other filtering */ | ||
215 | if (spec->type != EFX_FILTER_UNSPEC) | ||
216 | return -EPROTONOSUPPORT; | ||
217 | |||
218 | if (port == 0 || rport == 0) | ||
219 | return -EINVAL; | ||
220 | |||
221 | switch (proto) { | ||
222 | case IPPROTO_TCP: | ||
223 | spec->type = EFX_FILTER_TCP_FULL; | ||
224 | break; | ||
225 | case IPPROTO_UDP: | ||
226 | spec->type = EFX_FILTER_UDP_FULL; | ||
227 | break; | ||
228 | default: | ||
229 | return -EPROTONOSUPPORT; | ||
230 | } | ||
231 | |||
232 | __efx_filter_set_ipv4(spec, rhost, rport, host, port); | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | /** | ||
237 | * efx_filter_set_eth_local - specify local Ethernet address and optional VID | ||
238 | * @spec: Specification to initialise | ||
239 | * @vid: VLAN ID to match, or %EFX_FILTER_VID_UNSPEC | ||
240 | * @addr: Local Ethernet MAC address | ||
241 | */ | ||
242 | int efx_filter_set_eth_local(struct efx_filter_spec *spec, | ||
243 | u16 vid, const u8 *addr) | ||
244 | { | ||
245 | EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX)); | ||
246 | |||
247 | /* This cannot currently be combined with other filtering */ | ||
248 | if (spec->type != EFX_FILTER_UNSPEC) | ||
249 | return -EPROTONOSUPPORT; | ||
250 | |||
251 | if (vid == EFX_FILTER_VID_UNSPEC) { | ||
252 | spec->type = EFX_FILTER_MAC_WILD; | ||
253 | spec->data[0] = 0; | ||
254 | } else { | ||
255 | spec->type = EFX_FILTER_MAC_FULL; | ||
256 | spec->data[0] = vid; | ||
257 | } | ||
258 | |||
259 | spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5]; | ||
260 | spec->data[2] = addr[0] << 8 | addr[1]; | ||
261 | return 0; | ||
262 | } | ||
263 | |||
127 | /* Build a filter entry and return its n-tuple key. */ | 264 | /* Build a filter entry and return its n-tuple key. */ |
128 | static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec) | 265 | static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec) |
129 | { | 266 | { |
130 | u32 data3; | 267 | u32 data3; |
131 | 268 | ||
132 | switch (efx_filter_type_table_id(spec->type)) { | 269 | switch (efx_filter_spec_table_id(spec)) { |
133 | case EFX_FILTER_TABLE_RX_IP: { | 270 | case EFX_FILTER_TABLE_RX_IP: { |
134 | bool is_udp = (spec->type == EFX_FILTER_RX_UDP_FULL || | 271 | bool is_udp = (spec->type == EFX_FILTER_UDP_FULL || |
135 | spec->type == EFX_FILTER_RX_UDP_WILD); | 272 | spec->type == EFX_FILTER_UDP_WILD); |
136 | EFX_POPULATE_OWORD_7( | 273 | EFX_POPULATE_OWORD_7( |
137 | *filter, | 274 | *filter, |
138 | FRF_BZ_RSS_EN, | 275 | FRF_BZ_RSS_EN, |
@@ -149,7 +286,7 @@ static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec) | |||
149 | } | 286 | } |
150 | 287 | ||
151 | case EFX_FILTER_TABLE_RX_MAC: { | 288 | case EFX_FILTER_TABLE_RX_MAC: { |
152 | bool is_wild = spec->type == EFX_FILTER_RX_MAC_WILD; | 289 | bool is_wild = spec->type == EFX_FILTER_MAC_WILD; |
153 | EFX_POPULATE_OWORD_8( | 290 | EFX_POPULATE_OWORD_8( |
154 | *filter, | 291 | *filter, |
155 | FRF_CZ_RMFT_RSS_EN, | 292 | FRF_CZ_RMFT_RSS_EN, |
@@ -234,23 +371,21 @@ int efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec, | |||
234 | bool replace) | 371 | bool replace) |
235 | { | 372 | { |
236 | struct efx_filter_state *state = efx->filter_state; | 373 | struct efx_filter_state *state = efx->filter_state; |
237 | enum efx_filter_table_id table_id = | 374 | struct efx_filter_table *table = efx_filter_spec_table(state, spec); |
238 | efx_filter_type_table_id(spec->type); | ||
239 | struct efx_filter_table *table = &state->table[table_id]; | ||
240 | struct efx_filter_spec *saved_spec; | 375 | struct efx_filter_spec *saved_spec; |
241 | efx_oword_t filter; | 376 | efx_oword_t filter; |
242 | int filter_idx, depth; | 377 | int filter_idx, depth; |
243 | u32 key; | 378 | u32 key; |
244 | int rc; | 379 | int rc; |
245 | 380 | ||
246 | if (table->size == 0) | 381 | if (!table || table->size == 0) |
247 | return -EINVAL; | 382 | return -EINVAL; |
248 | 383 | ||
249 | key = efx_filter_build(&filter, spec); | 384 | key = efx_filter_build(&filter, spec); |
250 | 385 | ||
251 | netif_vdbg(efx, hw, efx->net_dev, | 386 | netif_vdbg(efx, hw, efx->net_dev, |
252 | "%s: type %d search_depth=%d", __func__, spec->type, | 387 | "%s: type %d search_depth=%d", __func__, spec->type, |
253 | state->search_depth[spec->type]); | 388 | table->search_depth[spec->type]); |
254 | 389 | ||
255 | spin_lock_bh(&state->lock); | 390 | spin_lock_bh(&state->lock); |
256 | 391 | ||
@@ -277,8 +412,8 @@ int efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec, | |||
277 | } | 412 | } |
278 | *saved_spec = *spec; | 413 | *saved_spec = *spec; |
279 | 414 | ||
280 | if (state->search_depth[spec->type] < depth) { | 415 | if (table->search_depth[spec->type] < depth) { |
281 | state->search_depth[spec->type] = depth; | 416 | table->search_depth[spec->type] = depth; |
282 | efx_filter_push_rx_limits(efx); | 417 | efx_filter_push_rx_limits(efx); |
283 | } | 418 | } |
284 | 419 | ||
@@ -287,7 +422,7 @@ int efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec, | |||
287 | netif_vdbg(efx, hw, efx->net_dev, | 422 | netif_vdbg(efx, hw, efx->net_dev, |
288 | "%s: filter type %d index %d rxq %u set", | 423 | "%s: filter type %d index %d rxq %u set", |
289 | __func__, spec->type, filter_idx, spec->dmaq_id); | 424 | __func__, spec->type, filter_idx, spec->dmaq_id); |
290 | rc = efx_filter_make_id(table_id, filter_idx); | 425 | rc = efx_filter_make_id(table->id, filter_idx); |
291 | 426 | ||
292 | out: | 427 | out: |
293 | spin_unlock_bh(&state->lock); | 428 | spin_unlock_bh(&state->lock); |
@@ -321,15 +456,16 @@ static void efx_filter_table_clear_entry(struct efx_nic *efx, | |||
321 | int efx_filter_remove_filter(struct efx_nic *efx, struct efx_filter_spec *spec) | 456 | int efx_filter_remove_filter(struct efx_nic *efx, struct efx_filter_spec *spec) |
322 | { | 457 | { |
323 | struct efx_filter_state *state = efx->filter_state; | 458 | struct efx_filter_state *state = efx->filter_state; |
324 | enum efx_filter_table_id table_id = | 459 | struct efx_filter_table *table = efx_filter_spec_table(state, spec); |
325 | efx_filter_type_table_id(spec->type); | ||
326 | struct efx_filter_table *table = &state->table[table_id]; | ||
327 | struct efx_filter_spec *saved_spec; | 460 | struct efx_filter_spec *saved_spec; |
328 | efx_oword_t filter; | 461 | efx_oword_t filter; |
329 | int filter_idx, depth; | 462 | int filter_idx, depth; |
330 | u32 key; | 463 | u32 key; |
331 | int rc; | 464 | int rc; |
332 | 465 | ||
466 | if (!table) | ||
467 | return -EINVAL; | ||
468 | |||
333 | key = efx_filter_build(&filter, spec); | 469 | key = efx_filter_build(&filter, spec); |
334 | 470 | ||
335 | spin_lock_bh(&state->lock); | 471 | spin_lock_bh(&state->lock); |
@@ -347,7 +483,7 @@ int efx_filter_remove_filter(struct efx_nic *efx, struct efx_filter_spec *spec) | |||
347 | 483 | ||
348 | efx_filter_table_clear_entry(efx, table, filter_idx); | 484 | efx_filter_table_clear_entry(efx, table, filter_idx); |
349 | if (table->used == 0) | 485 | if (table->used == 0) |
350 | efx_filter_table_reset_search_depth(state, table_id); | 486 | efx_filter_table_reset_search_depth(table); |
351 | rc = 0; | 487 | rc = 0; |
352 | 488 | ||
353 | out: | 489 | out: |
@@ -369,7 +505,7 @@ static void efx_filter_table_clear(struct efx_nic *efx, | |||
369 | if (table->spec[filter_idx].priority <= priority) | 505 | if (table->spec[filter_idx].priority <= priority) |
370 | efx_filter_table_clear_entry(efx, table, filter_idx); | 506 | efx_filter_table_clear_entry(efx, table, filter_idx); |
371 | if (table->used == 0) | 507 | if (table->used == 0) |
372 | efx_filter_table_reset_search_depth(state, table_id); | 508 | efx_filter_table_reset_search_depth(table); |
373 | 509 | ||
374 | spin_unlock_bh(&state->lock); | 510 | spin_unlock_bh(&state->lock); |
375 | } | 511 | } |
@@ -427,6 +563,7 @@ int efx_probe_filters(struct efx_nic *efx) | |||
427 | 563 | ||
428 | if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { | 564 | if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { |
429 | table = &state->table[EFX_FILTER_TABLE_RX_IP]; | 565 | table = &state->table[EFX_FILTER_TABLE_RX_IP]; |
566 | table->id = EFX_FILTER_TABLE_RX_IP; | ||
430 | table->offset = FR_BZ_RX_FILTER_TBL0; | 567 | table->offset = FR_BZ_RX_FILTER_TBL0; |
431 | table->size = FR_BZ_RX_FILTER_TBL0_ROWS; | 568 | table->size = FR_BZ_RX_FILTER_TBL0_ROWS; |
432 | table->step = FR_BZ_RX_FILTER_TBL0_STEP; | 569 | table->step = FR_BZ_RX_FILTER_TBL0_STEP; |
@@ -434,6 +571,7 @@ int efx_probe_filters(struct efx_nic *efx) | |||
434 | 571 | ||
435 | if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) { | 572 | if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) { |
436 | table = &state->table[EFX_FILTER_TABLE_RX_MAC]; | 573 | table = &state->table[EFX_FILTER_TABLE_RX_MAC]; |
574 | table->id = EFX_FILTER_TABLE_RX_MAC; | ||
437 | table->offset = FR_CZ_RX_MAC_FILTER_TBL0; | 575 | table->offset = FR_CZ_RX_MAC_FILTER_TBL0; |
438 | table->size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS; | 576 | table->size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS; |
439 | table->step = FR_CZ_RX_MAC_FILTER_TBL0_STEP; | 577 | table->step = FR_CZ_RX_MAC_FILTER_TBL0_STEP; |
diff --git a/drivers/net/sfc/filter.h b/drivers/net/sfc/filter.h index d11e4aa78133..872f2132a496 100644 --- a/drivers/net/sfc/filter.h +++ b/drivers/net/sfc/filter.h | |||
@@ -14,23 +14,25 @@ | |||
14 | 14 | ||
15 | /** | 15 | /** |
16 | * enum efx_filter_type - type of hardware filter | 16 | * enum efx_filter_type - type of hardware filter |
17 | * @EFX_FILTER_RX_TCP_FULL: RX, matching TCP/IPv4 4-tuple | 17 | * @EFX_FILTER_TCP_FULL: Matching TCP/IPv4 4-tuple |
18 | * @EFX_FILTER_RX_TCP_WILD: RX, matching TCP/IPv4 destination (host, port) | 18 | * @EFX_FILTER_TCP_WILD: Matching TCP/IPv4 destination (host, port) |
19 | * @EFX_FILTER_RX_UDP_FULL: RX, matching UDP/IPv4 4-tuple | 19 | * @EFX_FILTER_UDP_FULL: Matching UDP/IPv4 4-tuple |
20 | * @EFX_FILTER_RX_UDP_WILD: RX, matching UDP/IPv4 destination (host, port) | 20 | * @EFX_FILTER_UDP_WILD: Matching UDP/IPv4 destination (host, port) |
21 | * @EFX_FILTER_RX_MAC_FULL: RX, matching Ethernet destination MAC address, VID | 21 | * @EFX_FILTER_MAC_FULL: Matching Ethernet destination MAC address, VID |
22 | * @EFX_FILTER_RX_MAC_WILD: RX, matching Ethernet destination MAC address | 22 | * @EFX_FILTER_MAC_WILD: Matching Ethernet destination MAC address |
23 | * @EFX_FILTER_UNSPEC: Match type is unspecified | ||
23 | * | 24 | * |
24 | * Falcon NICs only support the RX TCP/IPv4 and UDP/IPv4 filter types. | 25 | * Falcon NICs only support the TCP/IPv4 and UDP/IPv4 filter types. |
25 | */ | 26 | */ |
26 | enum efx_filter_type { | 27 | enum efx_filter_type { |
27 | EFX_FILTER_RX_TCP_FULL = 0, | 28 | EFX_FILTER_TCP_FULL = 0, |
28 | EFX_FILTER_RX_TCP_WILD, | 29 | EFX_FILTER_TCP_WILD, |
29 | EFX_FILTER_RX_UDP_FULL, | 30 | EFX_FILTER_UDP_FULL, |
30 | EFX_FILTER_RX_UDP_WILD, | 31 | EFX_FILTER_UDP_WILD, |
31 | EFX_FILTER_RX_MAC_FULL = 4, | 32 | EFX_FILTER_MAC_FULL = 4, |
32 | EFX_FILTER_RX_MAC_WILD, | 33 | EFX_FILTER_MAC_WILD, |
33 | EFX_FILTER_TYPE_COUNT, | 34 | EFX_FILTER_TYPE_COUNT, /* number of specific types */ |
35 | EFX_FILTER_UNSPEC = 0xf, | ||
34 | }; | 36 | }; |
35 | 37 | ||
36 | /** | 38 | /** |
@@ -57,13 +59,13 @@ enum efx_filter_priority { | |||
57 | * @EFX_FILTER_FLAG_RX_OVERRIDE_IP: Enables a MAC filter to override | 59 | * @EFX_FILTER_FLAG_RX_OVERRIDE_IP: Enables a MAC filter to override |
58 | * any IP filter that matches the same packet. By default, IP | 60 | * any IP filter that matches the same packet. By default, IP |
59 | * filters take precedence. | 61 | * filters take precedence. |
60 | * | 62 | * @EFX_FILTER_FLAG_RX: Filter is for RX |
61 | * Currently, no flags are defined for TX filters. | ||
62 | */ | 63 | */ |
63 | enum efx_filter_flags { | 64 | enum efx_filter_flags { |
64 | EFX_FILTER_FLAG_RX_RSS = 0x01, | 65 | EFX_FILTER_FLAG_RX_RSS = 0x01, |
65 | EFX_FILTER_FLAG_RX_SCATTER = 0x02, | 66 | EFX_FILTER_FLAG_RX_SCATTER = 0x02, |
66 | EFX_FILTER_FLAG_RX_OVERRIDE_IP = 0x04, | 67 | EFX_FILTER_FLAG_RX_OVERRIDE_IP = 0x04, |
68 | EFX_FILTER_FLAG_RX = 0x08, | ||
67 | }; | 69 | }; |
68 | 70 | ||
69 | /** | 71 | /** |
@@ -85,99 +87,26 @@ struct efx_filter_spec { | |||
85 | u32 data[3]; | 87 | u32 data[3]; |
86 | }; | 88 | }; |
87 | 89 | ||
88 | /** | 90 | static inline void efx_filter_init_rx(struct efx_filter_spec *spec, |
89 | * efx_filter_set_rx_tcp_full - specify RX filter with TCP/IPv4 full match | 91 | enum efx_filter_priority priority, |
90 | * @spec: Specification to initialise | 92 | enum efx_filter_flags flags, |
91 | * @shost: Source host address (host byte order) | 93 | unsigned rxq_id) |
92 | * @sport: Source port (host byte order) | ||
93 | * @dhost: Destination host address (host byte order) | ||
94 | * @dport: Destination port (host byte order) | ||
95 | */ | ||
96 | static inline void | ||
97 | efx_filter_set_rx_tcp_full(struct efx_filter_spec *spec, | ||
98 | u32 shost, u16 sport, u32 dhost, u16 dport) | ||
99 | { | ||
100 | spec->type = EFX_FILTER_RX_TCP_FULL; | ||
101 | spec->data[0] = sport | shost << 16; | ||
102 | spec->data[1] = dport << 16 | shost >> 16; | ||
103 | spec->data[2] = dhost; | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * efx_filter_set_rx_tcp_wild - specify RX filter with TCP/IPv4 wildcard match | ||
108 | * @spec: Specification to initialise | ||
109 | * @dhost: Destination host address (host byte order) | ||
110 | * @dport: Destination port (host byte order) | ||
111 | */ | ||
112 | static inline void | ||
113 | efx_filter_set_rx_tcp_wild(struct efx_filter_spec *spec, u32 dhost, u16 dport) | ||
114 | { | ||
115 | spec->type = EFX_FILTER_RX_TCP_WILD; | ||
116 | spec->data[0] = 0; | ||
117 | spec->data[1] = dport << 16; | ||
118 | spec->data[2] = dhost; | ||
119 | } | ||
120 | |||
121 | /** | ||
122 | * efx_filter_set_rx_udp_full - specify RX filter with UDP/IPv4 full match | ||
123 | * @spec: Specification to initialise | ||
124 | * @shost: Source host address (host byte order) | ||
125 | * @sport: Source port (host byte order) | ||
126 | * @dhost: Destination host address (host byte order) | ||
127 | * @dport: Destination port (host byte order) | ||
128 | */ | ||
129 | static inline void | ||
130 | efx_filter_set_rx_udp_full(struct efx_filter_spec *spec, | ||
131 | u32 shost, u16 sport, u32 dhost, u16 dport) | ||
132 | { | ||
133 | spec->type = EFX_FILTER_RX_UDP_FULL; | ||
134 | spec->data[0] = sport | shost << 16; | ||
135 | spec->data[1] = dport << 16 | shost >> 16; | ||
136 | spec->data[2] = dhost; | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * efx_filter_set_rx_udp_wild - specify RX filter with UDP/IPv4 wildcard match | ||
141 | * @spec: Specification to initialise | ||
142 | * @dhost: Destination host address (host byte order) | ||
143 | * @dport: Destination port (host byte order) | ||
144 | */ | ||
145 | static inline void | ||
146 | efx_filter_set_rx_udp_wild(struct efx_filter_spec *spec, u32 dhost, u16 dport) | ||
147 | { | ||
148 | spec->type = EFX_FILTER_RX_UDP_WILD; | ||
149 | spec->data[0] = dport; | ||
150 | spec->data[1] = 0; | ||
151 | spec->data[2] = dhost; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * efx_filter_set_rx_mac_full - specify RX filter with MAC full match | ||
156 | * @spec: Specification to initialise | ||
157 | * @vid: VLAN ID | ||
158 | * @addr: Destination MAC address | ||
159 | */ | ||
160 | static inline void efx_filter_set_rx_mac_full(struct efx_filter_spec *spec, | ||
161 | u16 vid, const u8 *addr) | ||
162 | { | 94 | { |
163 | spec->type = EFX_FILTER_RX_MAC_FULL; | 95 | spec->type = EFX_FILTER_UNSPEC; |
164 | spec->data[0] = vid; | 96 | spec->priority = priority; |
165 | spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5]; | 97 | spec->flags = EFX_FILTER_FLAG_RX | flags; |
166 | spec->data[2] = addr[0] << 8 | addr[1]; | 98 | spec->dmaq_id = rxq_id; |
167 | } | 99 | } |
168 | 100 | ||
169 | /** | 101 | extern int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto, |
170 | * efx_filter_set_rx_mac_full - specify RX filter with MAC wildcard match | 102 | __be32 host, __be16 port); |
171 | * @spec: Specification to initialise | 103 | extern int efx_filter_set_ipv4_full(struct efx_filter_spec *spec, u8 proto, |
172 | * @addr: Destination MAC address | 104 | __be32 host, __be16 port, |
173 | */ | 105 | __be32 rhost, __be16 rport); |
174 | static inline void efx_filter_set_rx_mac_wild(struct efx_filter_spec *spec, | 106 | extern int efx_filter_set_eth_local(struct efx_filter_spec *spec, |
175 | const u8 *addr) | 107 | u16 vid, const u8 *addr); |
176 | { | 108 | enum { |
177 | spec->type = EFX_FILTER_RX_MAC_WILD; | 109 | EFX_FILTER_VID_UNSPEC = 0xffff, |
178 | spec->data[0] = 0; | 110 | }; |
179 | spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5]; | ||
180 | spec->data[2] = addr[0] << 8 | addr[1]; | ||
181 | } | ||
182 | 111 | ||
183 | #endif /* EFX_FILTER_H */ | 112 | #endif /* EFX_FILTER_H */ |