aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2010-12-07 14:11:26 -0500
committerBen Hutchings <bhutchings@solarflare.com>2010-12-07 14:11:26 -0500
commitc39d35ebffeea5996a6f8fd8430fae9acfb8aeaf (patch)
treeaf09ac5b15429b41d4b5c54fd63c1ac769d67b39 /drivers
parent8891681af928f1da795cd4bd59043e5e0fadd6c8 (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.c82
-rw-r--r--drivers/net/sfc/filter.c214
-rw-r--r--drivers/net/sfc/filter.h143
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
1013static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, 1003static 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
35struct efx_filter_table { 36struct 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
44struct efx_filter_state { 47struct 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
73static enum efx_filter_table_id 75static enum efx_filter_table_id
74efx_filter_type_table_id(enum efx_filter_type type) 76efx_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
88static struct efx_filter_table *
89efx_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
85static void 98static void efx_filter_table_reset_search_depth(struct efx_filter_table *table)
86efx_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
93static void efx_filter_push_rx_limits(struct efx_nic *efx) 103static 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
140static 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 */
156int 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 */
208int 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 */
242int 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. */
128static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec) 265static 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
292out: 427out:
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,
321int efx_filter_remove_filter(struct efx_nic *efx, struct efx_filter_spec *spec) 456int 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
353out: 489out:
@@ -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 */
26enum efx_filter_type { 27enum 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 */
63enum efx_filter_flags { 64enum 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/** 90static 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 */
96static inline void
97efx_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 */
112static inline void
113efx_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 */
129static inline void
130efx_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 */
145static inline void
146efx_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 */
160static 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/** 101extern 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 103extern 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);
174static inline void efx_filter_set_rx_mac_wild(struct efx_filter_spec *spec, 106extern int efx_filter_set_eth_local(struct efx_filter_spec *spec,
175 const u8 *addr) 107 u16 vid, const u8 *addr);
176{ 108enum {
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 */