Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[deliverable/linux.git] / drivers / net / sfc / filter.c
CommitLineData
64eebcfd
BH
1/****************************************************************************
2 * Driver for Solarflare Solarstorm network controllers and boards
3 * Copyright 2005-2010 Solarflare Communications Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published
7 * by the Free Software Foundation, incorporated herein by reference.
8 */
9
c39d35eb 10#include <linux/in.h>
64eebcfd
BH
11#include "efx.h"
12#include "filter.h"
13#include "io.h"
14#include "nic.h"
15#include "regs.h"
16
17/* "Fudge factors" - difference between programmed value and actual depth.
18 * Due to pipelined implementation we need to program H/W with a value that
19 * is larger than the hop limit we want.
20 */
21#define FILTER_CTL_SRCH_FUDGE_WILD 3
22#define FILTER_CTL_SRCH_FUDGE_FULL 1
23
993284df
BH
24/* Hard maximum hop limit. Hardware will time-out beyond 200-something.
25 * We also need to avoid infinite loops in efx_filter_search() when the
26 * table is full.
27 */
28#define FILTER_CTL_SRCH_MAX 200
29
8891681a
BH
30enum efx_filter_table_id {
31 EFX_FILTER_TABLE_RX_IP = 0,
32 EFX_FILTER_TABLE_RX_MAC,
33 EFX_FILTER_TABLE_COUNT,
34};
35
64eebcfd 36struct efx_filter_table {
c39d35eb 37 enum efx_filter_table_id id;
64eebcfd
BH
38 u32 offset; /* address of table relative to BAR */
39 unsigned size; /* number of entries */
40 unsigned step; /* step between entries */
41 unsigned used; /* number currently used */
42 unsigned long *used_bitmap;
43 struct efx_filter_spec *spec;
c39d35eb 44 unsigned search_depth[EFX_FILTER_TYPE_COUNT];
64eebcfd
BH
45};
46
47struct efx_filter_state {
48 spinlock_t lock;
49 struct efx_filter_table table[EFX_FILTER_TABLE_COUNT];
64eebcfd
BH
50};
51
52/* The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
53 * key derived from the n-tuple. The initial LFSR state is 0xffff. */
54static u16 efx_filter_hash(u32 key)
55{
56 u16 tmp;
57
58 /* First 16 rounds */
59 tmp = 0x1fff ^ key >> 16;
60 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
61 tmp = tmp ^ tmp >> 9;
62 /* Last 16 rounds */
63 tmp = tmp ^ tmp << 13 ^ key;
64 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
65 return tmp ^ tmp >> 9;
66}
67
68/* To allow for hash collisions, filter search continues at these
69 * increments from the first possible entry selected by the hash. */
70static u16 efx_filter_increment(u32 key)
71{
72 return key * 2 - 1;
73}
74
75static enum efx_filter_table_id
c39d35eb
BH
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)
64eebcfd 91{
c39d35eb
BH
92 if (spec->type == EFX_FILTER_UNSPEC)
93 return NULL;
94 else
95 return &state->table[efx_filter_spec_table_id(spec)];
64eebcfd
BH
96}
97
c39d35eb 98static void efx_filter_table_reset_search_depth(struct efx_filter_table *table)
64eebcfd 99{
c39d35eb 100 memset(table->search_depth, 0, sizeof(table->search_depth));
64eebcfd
BH
101}
102
103static void efx_filter_push_rx_limits(struct efx_nic *efx)
104{
105 struct efx_filter_state *state = efx->filter_state;
c39d35eb 106 struct efx_filter_table *table;
64eebcfd
BH
107 efx_oword_t filter_ctl;
108
109 efx_reado(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL);
110
c39d35eb 111 table = &state->table[EFX_FILTER_TABLE_RX_IP];
64eebcfd 112 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_FULL_SRCH_LIMIT,
c39d35eb 113 table->search_depth[EFX_FILTER_TCP_FULL] +
64eebcfd
BH
114 FILTER_CTL_SRCH_FUDGE_FULL);
115 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_WILD_SRCH_LIMIT,
c39d35eb 116 table->search_depth[EFX_FILTER_TCP_WILD] +
64eebcfd
BH
117 FILTER_CTL_SRCH_FUDGE_WILD);
118 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_FULL_SRCH_LIMIT,
c39d35eb 119 table->search_depth[EFX_FILTER_UDP_FULL] +
64eebcfd
BH
120 FILTER_CTL_SRCH_FUDGE_FULL);
121 EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_WILD_SRCH_LIMIT,
c39d35eb 122 table->search_depth[EFX_FILTER_UDP_WILD] +
64eebcfd
BH
123 FILTER_CTL_SRCH_FUDGE_WILD);
124
c39d35eb
BH
125 table = &state->table[EFX_FILTER_TABLE_RX_MAC];
126 if (table->size) {
64eebcfd
BH
127 EFX_SET_OWORD_FIELD(
128 filter_ctl, FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
c39d35eb 129 table->search_depth[EFX_FILTER_MAC_FULL] +
64eebcfd
BH
130 FILTER_CTL_SRCH_FUDGE_FULL);
131 EFX_SET_OWORD_FIELD(
132 filter_ctl, FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
c39d35eb 133 table->search_depth[EFX_FILTER_MAC_WILD] +
64eebcfd
BH
134 FILTER_CTL_SRCH_FUDGE_WILD);
135 }
136
137 efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL);
138}
139
c39d35eb
BH
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
64eebcfd
BH
264/* Build a filter entry and return its n-tuple key. */
265static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
266{
267 u32 data3;
268
c39d35eb 269 switch (efx_filter_spec_table_id(spec)) {
64eebcfd 270 case EFX_FILTER_TABLE_RX_IP: {
c39d35eb
BH
271 bool is_udp = (spec->type == EFX_FILTER_UDP_FULL ||
272 spec->type == EFX_FILTER_UDP_WILD);
64eebcfd
BH
273 EFX_POPULATE_OWORD_7(
274 *filter,
275 FRF_BZ_RSS_EN,
276 !!(spec->flags & EFX_FILTER_FLAG_RX_RSS),
277 FRF_BZ_SCATTER_EN,
278 !!(spec->flags & EFX_FILTER_FLAG_RX_SCATTER),
279 FRF_BZ_TCP_UDP, is_udp,
280 FRF_BZ_RXQ_ID, spec->dmaq_id,
281 EFX_DWORD_2, spec->data[2],
282 EFX_DWORD_1, spec->data[1],
283 EFX_DWORD_0, spec->data[0]);
284 data3 = is_udp;
285 break;
286 }
287
288 case EFX_FILTER_TABLE_RX_MAC: {
c39d35eb 289 bool is_wild = spec->type == EFX_FILTER_MAC_WILD;
64eebcfd
BH
290 EFX_POPULATE_OWORD_8(
291 *filter,
292 FRF_CZ_RMFT_RSS_EN,
293 !!(spec->flags & EFX_FILTER_FLAG_RX_RSS),
294 FRF_CZ_RMFT_SCATTER_EN,
295 !!(spec->flags & EFX_FILTER_FLAG_RX_SCATTER),
296 FRF_CZ_RMFT_IP_OVERRIDE,
297 !!(spec->flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP),
298 FRF_CZ_RMFT_RXQ_ID, spec->dmaq_id,
299 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
300 FRF_CZ_RMFT_DEST_MAC_HI, spec->data[2],
301 FRF_CZ_RMFT_DEST_MAC_LO, spec->data[1],
302 FRF_CZ_RMFT_VLAN_ID, spec->data[0]);
303 data3 = is_wild;
304 break;
305 }
306
307 default:
308 BUG();
309 }
310
311 return spec->data[0] ^ spec->data[1] ^ spec->data[2] ^ data3;
312}
313
314static bool efx_filter_equal(const struct efx_filter_spec *left,
315 const struct efx_filter_spec *right)
316{
317 if (left->type != right->type ||
318 memcmp(left->data, right->data, sizeof(left->data)))
319 return false;
320
321 return true;
322}
323
324static int efx_filter_search(struct efx_filter_table *table,
325 struct efx_filter_spec *spec, u32 key,
326 bool for_insert, int *depth_required)
327{
328 unsigned hash, incr, filter_idx, depth;
329 struct efx_filter_spec *cmp;
330
331 hash = efx_filter_hash(key);
332 incr = efx_filter_increment(key);
333
334 for (depth = 1, filter_idx = hash & (table->size - 1);
993284df
BH
335 depth <= FILTER_CTL_SRCH_MAX &&
336 test_bit(filter_idx, table->used_bitmap);
64eebcfd
BH
337 ++depth) {
338 cmp = &table->spec[filter_idx];
339 if (efx_filter_equal(spec, cmp))
340 goto found;
341 filter_idx = (filter_idx + incr) & (table->size - 1);
342 }
343 if (!for_insert)
344 return -ENOENT;
993284df
BH
345 if (depth > FILTER_CTL_SRCH_MAX)
346 return -EBUSY;
64eebcfd
BH
347found:
348 *depth_required = depth;
349 return filter_idx;
350}
351
8891681a
BH
352/* Construct/deconstruct external filter IDs */
353
354static inline int
355efx_filter_make_id(enum efx_filter_table_id table_id, unsigned index)
356{
357 return table_id << 16 | index;
358}
359
64eebcfd
BH
360/**
361 * efx_filter_insert_filter - add or replace a filter
362 * @efx: NIC in which to insert the filter
363 * @spec: Specification for the filter
364 * @replace: Flag for whether the specified filter may replace a filter
365 * with an identical match expression and equal or lower priority
366 *
8891681a 367 * On success, return the filter ID.
64eebcfd
BH
368 * On failure, return a negative error code.
369 */
370int efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
371 bool replace)
372{
373 struct efx_filter_state *state = efx->filter_state;
c39d35eb 374 struct efx_filter_table *table = efx_filter_spec_table(state, spec);
64eebcfd
BH
375 struct efx_filter_spec *saved_spec;
376 efx_oword_t filter;
377 int filter_idx, depth;
378 u32 key;
379 int rc;
380
c39d35eb 381 if (!table || table->size == 0)
64eebcfd
BH
382 return -EINVAL;
383
384 key = efx_filter_build(&filter, spec);
385
386 netif_vdbg(efx, hw, efx->net_dev,
387 "%s: type %d search_depth=%d", __func__, spec->type,
c39d35eb 388 table->search_depth[spec->type]);
64eebcfd
BH
389
390 spin_lock_bh(&state->lock);
391
392 rc = efx_filter_search(table, spec, key, true, &depth);
393 if (rc < 0)
394 goto out;
395 filter_idx = rc;
396 BUG_ON(filter_idx >= table->size);
397 saved_spec = &table->spec[filter_idx];
398
399 if (test_bit(filter_idx, table->used_bitmap)) {
400 /* Should we replace the existing filter? */
401 if (!replace) {
402 rc = -EEXIST;
403 goto out;
404 }
405 if (spec->priority < saved_spec->priority) {
406 rc = -EPERM;
407 goto out;
408 }
409 } else {
410 __set_bit(filter_idx, table->used_bitmap);
411 ++table->used;
412 }
413 *saved_spec = *spec;
414
c39d35eb
BH
415 if (table->search_depth[spec->type] < depth) {
416 table->search_depth[spec->type] = depth;
64eebcfd
BH
417 efx_filter_push_rx_limits(efx);
418 }
419
420 efx_writeo(efx, &filter, table->offset + table->step * filter_idx);
421
422 netif_vdbg(efx, hw, efx->net_dev,
423 "%s: filter type %d index %d rxq %u set",
424 __func__, spec->type, filter_idx, spec->dmaq_id);
c39d35eb 425 rc = efx_filter_make_id(table->id, filter_idx);
64eebcfd
BH
426
427out:
428 spin_unlock_bh(&state->lock);
429 return rc;
430}
431
432static void efx_filter_table_clear_entry(struct efx_nic *efx,
433 struct efx_filter_table *table,
434 int filter_idx)
435{
436 static efx_oword_t filter;
437
438 if (test_bit(filter_idx, table->used_bitmap)) {
439 __clear_bit(filter_idx, table->used_bitmap);
440 --table->used;
441 memset(&table->spec[filter_idx], 0, sizeof(table->spec[0]));
442
443 efx_writeo(efx, &filter,
444 table->offset + table->step * filter_idx);
445 }
446}
447
448/**
449 * efx_filter_remove_filter - remove a filter by specification
450 * @efx: NIC from which to remove the filter
451 * @spec: Specification for the filter
452 *
453 * On success, return zero.
454 * On failure, return a negative error code.
455 */
456int efx_filter_remove_filter(struct efx_nic *efx, struct efx_filter_spec *spec)
457{
458 struct efx_filter_state *state = efx->filter_state;
c39d35eb 459 struct efx_filter_table *table = efx_filter_spec_table(state, spec);
64eebcfd
BH
460 struct efx_filter_spec *saved_spec;
461 efx_oword_t filter;
462 int filter_idx, depth;
463 u32 key;
464 int rc;
465
c39d35eb
BH
466 if (!table)
467 return -EINVAL;
468
64eebcfd
BH
469 key = efx_filter_build(&filter, spec);
470
471 spin_lock_bh(&state->lock);
472
473 rc = efx_filter_search(table, spec, key, false, &depth);
474 if (rc < 0)
475 goto out;
476 filter_idx = rc;
477 saved_spec = &table->spec[filter_idx];
478
479 if (spec->priority < saved_spec->priority) {
480 rc = -EPERM;
481 goto out;
482 }
483
484 efx_filter_table_clear_entry(efx, table, filter_idx);
485 if (table->used == 0)
c39d35eb 486 efx_filter_table_reset_search_depth(table);
64eebcfd
BH
487 rc = 0;
488
489out:
490 spin_unlock_bh(&state->lock);
491 return rc;
492}
493
8891681a
BH
494static void efx_filter_table_clear(struct efx_nic *efx,
495 enum efx_filter_table_id table_id,
496 enum efx_filter_priority priority)
64eebcfd
BH
497{
498 struct efx_filter_state *state = efx->filter_state;
499 struct efx_filter_table *table = &state->table[table_id];
500 int filter_idx;
501
502 spin_lock_bh(&state->lock);
503
504 for (filter_idx = 0; filter_idx < table->size; ++filter_idx)
505 if (table->spec[filter_idx].priority <= priority)
506 efx_filter_table_clear_entry(efx, table, filter_idx);
507 if (table->used == 0)
c39d35eb 508 efx_filter_table_reset_search_depth(table);
64eebcfd
BH
509
510 spin_unlock_bh(&state->lock);
511}
512
8891681a
BH
513/**
514 * efx_filter_clear_rx - remove RX filters by priority
515 * @efx: NIC from which to remove the filters
516 * @priority: Maximum priority to remove
517 */
518void efx_filter_clear_rx(struct efx_nic *efx, enum efx_filter_priority priority)
519{
520 efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_IP, priority);
521 efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_MAC, priority);
522}
523
64eebcfd
BH
524/* Restore filter stater after reset */
525void efx_restore_filters(struct efx_nic *efx)
526{
527 struct efx_filter_state *state = efx->filter_state;
528 enum efx_filter_table_id table_id;
529 struct efx_filter_table *table;
530 efx_oword_t filter;
531 int filter_idx;
532
533 spin_lock_bh(&state->lock);
534
535 for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
536 table = &state->table[table_id];
537 for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
538 if (!test_bit(filter_idx, table->used_bitmap))
539 continue;
540 efx_filter_build(&filter, &table->spec[filter_idx]);
541 efx_writeo(efx, &filter,
542 table->offset + table->step * filter_idx);
543 }
544 }
545
546 efx_filter_push_rx_limits(efx);
547
548 spin_unlock_bh(&state->lock);
549}
550
551int efx_probe_filters(struct efx_nic *efx)
552{
553 struct efx_filter_state *state;
554 struct efx_filter_table *table;
555 unsigned table_id;
556
557 state = kzalloc(sizeof(*efx->filter_state), GFP_KERNEL);
558 if (!state)
559 return -ENOMEM;
560 efx->filter_state = state;
561
562 spin_lock_init(&state->lock);
563
564 if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
565 table = &state->table[EFX_FILTER_TABLE_RX_IP];
c39d35eb 566 table->id = EFX_FILTER_TABLE_RX_IP;
64eebcfd
BH
567 table->offset = FR_BZ_RX_FILTER_TBL0;
568 table->size = FR_BZ_RX_FILTER_TBL0_ROWS;
569 table->step = FR_BZ_RX_FILTER_TBL0_STEP;
570 }
571
572 if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) {
573 table = &state->table[EFX_FILTER_TABLE_RX_MAC];
c39d35eb 574 table->id = EFX_FILTER_TABLE_RX_MAC;
64eebcfd
BH
575 table->offset = FR_CZ_RX_MAC_FILTER_TBL0;
576 table->size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
577 table->step = FR_CZ_RX_MAC_FILTER_TBL0_STEP;
578 }
579
580 for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
581 table = &state->table[table_id];
582 if (table->size == 0)
583 continue;
584 table->used_bitmap = kcalloc(BITS_TO_LONGS(table->size),
585 sizeof(unsigned long),
586 GFP_KERNEL);
587 if (!table->used_bitmap)
588 goto fail;
89bf67f1 589 table->spec = vzalloc(table->size * sizeof(*table->spec));
64eebcfd
BH
590 if (!table->spec)
591 goto fail;
64eebcfd
BH
592 }
593
594 return 0;
595
596fail:
597 efx_remove_filters(efx);
598 return -ENOMEM;
599}
600
601void efx_remove_filters(struct efx_nic *efx)
602{
603 struct efx_filter_state *state = efx->filter_state;
604 enum efx_filter_table_id table_id;
605
606 for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
607 kfree(state->table[table_id].used_bitmap);
608 vfree(state->table[table_id].spec);
609 }
610 kfree(state);
611}
This page took 0.122326 seconds and 5 git commands to generate.