]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/dev/sfxge/common/hunt_filter.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / dev / sfxge / common / hunt_filter.c
1 /*-
2  * Copyright (c) 2007-2015 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "efsys.h"
35 #include "efx.h"
36 #include "efx_types.h"
37 #include "efx_regs_mcdi.h"
38 #include "efx_impl.h"
39
40 #if EFSYS_OPT_HUNTINGTON
41
42 #if EFSYS_OPT_FILTER
43
44 #define HFE_SPEC(hftp, index)   ((hftp)->hft_entry[(index)].hfe_spec)
45
46 static                  efx_filter_spec_t *
47 hunt_filter_entry_spec(
48         __in            const hunt_filter_table_t *hftp,
49         __in            unsigned int index)
50 {
51         return ((efx_filter_spec_t *)(HFE_SPEC(hftp, index) &
52                 ~(uintptr_t)EFX_HUNT_FILTER_FLAGS));
53 }
54
55 static                  boolean_t
56 hunt_filter_entry_is_busy(
57         __in            const hunt_filter_table_t *hftp,
58         __in            unsigned int index)
59 {
60         if (HFE_SPEC(hftp, index) & EFX_HUNT_FILTER_FLAG_BUSY)
61                 return (B_TRUE);
62         else
63                 return (B_FALSE);
64 }
65
66 static                  boolean_t
67 hunt_filter_entry_is_auto_old(
68         __in            const hunt_filter_table_t *hftp,
69         __in            unsigned int index)
70 {
71         if (HFE_SPEC(hftp, index) & EFX_HUNT_FILTER_FLAG_AUTO_OLD)
72                 return (B_TRUE);
73         else
74                 return (B_FALSE);
75 }
76
77 static                  void
78 hunt_filter_set_entry(
79         __inout         hunt_filter_table_t *hftp,
80         __in            unsigned int index,
81         __in_opt        const efx_filter_spec_t *efsp)
82 {
83         HFE_SPEC(hftp, index) = (uintptr_t)efsp;
84 }
85
86 static                  void
87 hunt_filter_set_entry_busy(
88         __inout         hunt_filter_table_t *hftp,
89         __in            unsigned int index)
90 {
91         HFE_SPEC(hftp, index) |= (uintptr_t)EFX_HUNT_FILTER_FLAG_BUSY;
92 }
93
94 static                  void
95 hunt_filter_set_entry_not_busy(
96         __inout         hunt_filter_table_t *hftp,
97         __in            unsigned int index)
98 {
99         HFE_SPEC(hftp, index) &= ~(uintptr_t)EFX_HUNT_FILTER_FLAG_BUSY;
100 }
101
102 static                  void
103 hunt_filter_set_entry_auto_old(
104         __inout         hunt_filter_table_t *hftp,
105         __in            unsigned int index)
106 {
107         EFSYS_ASSERT(hunt_filter_entry_spec(hftp, index) != NULL);
108         HFE_SPEC(hftp, index) |= (uintptr_t)EFX_HUNT_FILTER_FLAG_AUTO_OLD;
109 }
110
111 static                  void
112 hunt_filter_set_entry_not_auto_old(
113         __inout         hunt_filter_table_t *hftp,
114         __in            unsigned int index)
115 {
116         HFE_SPEC(hftp, index) &= ~(uintptr_t)EFX_HUNT_FILTER_FLAG_AUTO_OLD;
117         EFSYS_ASSERT(hunt_filter_entry_spec(hftp, index) != NULL);
118 }
119
120         __checkReturn   int
121 hunt_filter_init(
122         __in            efx_nic_t *enp)
123 {
124         int rc;
125         hunt_filter_table_t *hftp;
126
127         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
128
129 #define MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match))
130         EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST ==
131             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_IP));
132         EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST ==
133             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_IP));
134         EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC ==
135             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_MAC));
136         EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT ==
137             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_PORT));
138         EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC ==
139             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_MAC));
140         EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT ==
141             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_PORT));
142         EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE ==
143             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_ETHER_TYPE));
144         EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID ==
145             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_INNER_VLAN));
146         EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID ==
147             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_OUTER_VLAN));
148         EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO ==
149             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_IP_PROTO));
150 #undef MATCH_MASK
151
152         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (hunt_filter_table_t), hftp);
153
154         if (!hftp) {
155                 rc = ENOMEM;
156                 goto fail1;
157         }
158
159         enp->en_filter.ef_hunt_filter_table = hftp;
160
161         return (0);
162
163 fail1:
164         EFSYS_PROBE1(fail1, int, rc);
165
166         return (rc);
167 }
168
169                         void
170 hunt_filter_fini(
171         __in            efx_nic_t *enp)
172 {
173         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
174
175         if (enp->en_filter.ef_hunt_filter_table != NULL) {
176                 EFSYS_KMEM_FREE(enp->en_esip, sizeof (hunt_filter_table_t),
177                     enp->en_filter.ef_hunt_filter_table);
178         }
179 }
180
181 static  __checkReturn   int
182 efx_mcdi_filter_op_add(
183         __in            efx_nic_t *enp,
184         __in            efx_filter_spec_t *spec,
185         __in            unsigned int filter_op,
186         __inout         hunt_filter_handle_t *handle)
187 {
188         efx_mcdi_req_t req;
189         uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN,
190                             MC_CMD_FILTER_OP_OUT_LEN)];
191         uint32_t match_fields = 0;
192         int rc;
193
194         memset(payload, 0, sizeof (payload));
195         req.emr_cmd = MC_CMD_FILTER_OP;
196         req.emr_in_buf = payload;
197         req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN;
198         req.emr_out_buf = payload;
199         req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN;
200
201         switch (filter_op) {
202         case MC_CMD_FILTER_OP_IN_OP_REPLACE:
203                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO,
204                     handle->hfh_lo);
205                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI,
206                     handle->hfh_hi);
207                 /* Fall through */
208         case MC_CMD_FILTER_OP_IN_OP_INSERT:
209         case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE:
210                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, filter_op);
211                 break;
212         default:
213                 EFSYS_ASSERT(0);
214                 rc = EINVAL;
215                 goto fail1;
216         }
217
218         if (spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) {
219                 /*
220                  * The LOC_MAC_IG match flag can represent unknown unicast
221                  *  or multicast filters - use the MAC address to distinguish
222                  *  them.
223                  */
224                 if (EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac))
225                         match_fields |= 1U <<
226                                 MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN;
227                 else
228                         match_fields |= 1U <<
229                                 MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN;
230         }
231
232         match_fields |= spec->efs_match_flags & (~EFX_FILTER_MATCH_LOC_MAC_IG);
233
234         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_PORT_ID,
235             EVB_PORT_ID_ASSIGNED);
236         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_MATCH_FIELDS,
237             match_fields);
238         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_DEST,
239             MC_CMD_FILTER_OP_IN_RX_DEST_HOST);
240         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_QUEUE,
241             spec->efs_dmaq_id);
242         if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) {
243                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_CONTEXT,
244                     spec->efs_rss_context);
245         }
246         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_MODE,
247             spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ?
248             MC_CMD_FILTER_OP_IN_RX_MODE_RSS :
249             MC_CMD_FILTER_OP_IN_RX_MODE_SIMPLE);
250         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_TX_DEST,
251             MC_CMD_FILTER_OP_IN_TX_DEST_DEFAULT);
252
253         if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) {
254                 /*
255                  * NOTE: Unlike most MCDI requests, the filter fields
256                  * are presented in network (big endian) byte order.
257                  */
258                 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_MAC),
259                     spec->efs_rem_mac, EFX_MAC_ADDR_LEN);
260                 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_MAC),
261                     spec->efs_loc_mac, EFX_MAC_ADDR_LEN);
262
263                 MCDI_IN_SET_WORD(req, FILTER_OP_IN_SRC_PORT,
264                     __CPU_TO_BE_16(spec->efs_rem_port));
265                 MCDI_IN_SET_WORD(req, FILTER_OP_IN_DST_PORT,
266                     __CPU_TO_BE_16(spec->efs_loc_port));
267
268                 MCDI_IN_SET_WORD(req, FILTER_OP_IN_ETHER_TYPE,
269                     __CPU_TO_BE_16(spec->efs_ether_type));
270
271                 MCDI_IN_SET_WORD(req, FILTER_OP_IN_INNER_VLAN,
272                     __CPU_TO_BE_16(spec->efs_inner_vid));
273                 MCDI_IN_SET_WORD(req, FILTER_OP_IN_OUTER_VLAN,
274                     __CPU_TO_BE_16(spec->efs_outer_vid));
275
276                 /* IP protocol (in low byte, high byte is zero) */
277                 MCDI_IN_SET_BYTE(req, FILTER_OP_IN_IP_PROTO,
278                     spec->efs_ip_proto);
279
280                 EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) ==
281                     MC_CMD_FILTER_OP_IN_SRC_IP_LEN);
282                 EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) ==
283                     MC_CMD_FILTER_OP_IN_DST_IP_LEN);
284
285                 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_IP),
286                     &spec->efs_rem_host.eo_byte[0],
287                     MC_CMD_FILTER_OP_IN_SRC_IP_LEN);
288                 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_IP),
289                     &spec->efs_loc_host.eo_byte[0],
290                     MC_CMD_FILTER_OP_IN_DST_IP_LEN);
291         }
292
293         efx_mcdi_execute(enp, &req);
294
295         if (req.emr_rc != 0) {
296                 rc = req.emr_rc;
297                 goto fail2;
298         }
299
300         if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) {
301                 rc = EMSGSIZE;
302                 goto fail3;
303         }
304
305         handle->hfh_lo = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_LO);
306         handle->hfh_hi = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_HI);
307
308         return (0);
309
310 fail3:
311         EFSYS_PROBE(fail3);
312 fail2:
313         EFSYS_PROBE(fail2);
314 fail1:
315         EFSYS_PROBE1(fail1, int, rc);
316
317         return (rc);
318
319 }
320
321 static  __checkReturn   int
322 efx_mcdi_filter_op_delete(
323         __in            efx_nic_t *enp,
324         __in            unsigned int filter_op,
325         __inout         hunt_filter_handle_t *handle)
326 {
327         efx_mcdi_req_t req;
328         uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN,
329                             MC_CMD_FILTER_OP_OUT_LEN)];
330         int rc;
331
332         memset(payload, 0, sizeof (payload));
333         req.emr_cmd = MC_CMD_FILTER_OP;
334         req.emr_in_buf = payload;
335         req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN;
336         req.emr_out_buf = payload;
337         req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN;
338
339         switch (filter_op) {
340         case MC_CMD_FILTER_OP_IN_OP_REMOVE:
341                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP,
342                     MC_CMD_FILTER_OP_IN_OP_REMOVE);
343                 break;
344         case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE:
345                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP,
346                     MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE);
347                 break;
348         default:
349                 EFSYS_ASSERT(0);
350                 rc = EINVAL;
351                 goto fail1;
352         }
353
354         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, handle->hfh_lo);
355         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, handle->hfh_hi);
356
357         efx_mcdi_execute(enp, &req);
358
359         if (req.emr_rc != 0) {
360                 rc = req.emr_rc;
361                 goto fail2;
362         }
363
364         if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) {
365                 rc = EMSGSIZE;
366                 goto fail3;
367         }
368
369         return (0);
370
371 fail3:
372         EFSYS_PROBE(fail3);
373
374 fail2:
375         EFSYS_PROBE(fail2);
376 fail1:
377         EFSYS_PROBE1(fail1, int, rc);
378
379         return (rc);
380 }
381
382 static  __checkReturn   boolean_t
383 hunt_filter_equal(
384         __in            const efx_filter_spec_t *left,
385         __in            const efx_filter_spec_t *right)
386 {
387         /* FIXME: Consider rx vs tx filters (look at efs_flags) */
388         if (left->efs_match_flags != right->efs_match_flags)
389                 return (B_FALSE);
390         if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host))
391                 return (B_FALSE);
392         if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host))
393                 return (B_FALSE);
394         if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN))
395                 return (B_FALSE);
396         if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN))
397                 return (B_FALSE);
398         if (left->efs_rem_port != right->efs_rem_port)
399                 return (B_FALSE);
400         if (left->efs_loc_port != right->efs_loc_port)
401                 return (B_FALSE);
402         if (left->efs_inner_vid != right->efs_inner_vid)
403                 return (B_FALSE);
404         if (left->efs_outer_vid != right->efs_outer_vid)
405                 return (B_FALSE);
406         if (left->efs_ether_type != right->efs_ether_type)
407                 return (B_FALSE);
408         if (left->efs_ip_proto != right->efs_ip_proto)
409                 return (B_FALSE);
410
411         return (B_TRUE);
412
413 }
414
415 static  __checkReturn   boolean_t
416 hunt_filter_same_dest(
417         __in            const efx_filter_spec_t *left,
418         __in            const efx_filter_spec_t *right)
419 {
420         if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
421             (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) {
422                 if (left->efs_rss_context == right->efs_rss_context)
423                         return (B_TRUE);
424         } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) &&
425             (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) {
426                 if (left->efs_dmaq_id == right->efs_dmaq_id)
427                         return (B_TRUE);
428         }
429         return (B_FALSE);
430 }
431
432 static  __checkReturn   uint32_t
433 hunt_filter_hash(
434         __in            efx_filter_spec_t *spec)
435 {
436         EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t))
437                             == 0);
438         EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) %
439                             sizeof (uint32_t)) == 0);
440
441         /*
442          * As the area of the efx_filter_spec_t we need to hash is DWORD
443          * aligned and an exact number of DWORDs in size we can use the
444          * optimised efx_hash_dwords() rather than efx_hash_bytes()
445          */
446         return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid,
447                         (sizeof (efx_filter_spec_t) -
448                         EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) /
449                         sizeof (uint32_t), 0));
450 }
451
452 /*
453  * Decide whether a filter should be exclusive or else should allow
454  * delivery to additional recipients.  Currently we decide that
455  * filters for specific local unicast MAC and IP addresses are
456  * exclusive.
457  */
458 static  __checkReturn   boolean_t
459 hunt_filter_is_exclusive(
460         __in            efx_filter_spec_t *spec)
461 {
462         if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) &&
463             !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac))
464                 return (B_TRUE);
465
466         if ((spec->efs_match_flags &
467                 (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) ==
468             (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) {
469                 if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) &&
470                     ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe))
471                         return (B_TRUE);
472                 if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) &&
473                     (spec->efs_loc_host.eo_u8[0] != 0xff))
474                         return (B_TRUE);
475         }
476
477         return (B_FALSE);
478 }
479
480         __checkReturn   int
481 hunt_filter_restore(
482         __in            efx_nic_t *enp)
483 {
484         int tbl_id;
485         efx_filter_spec_t *spec;
486         hunt_filter_table_t *hftp = enp->en_filter.ef_hunt_filter_table;
487         boolean_t restoring;
488         int state;
489         int rc;
490
491         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
492
493         for (tbl_id = 0; tbl_id < EFX_HUNT_FILTER_TBL_ROWS; tbl_id++) {
494
495                 EFSYS_LOCK(enp->en_eslp, state);
496
497                 spec = hunt_filter_entry_spec(hftp, tbl_id);
498                 if (spec == NULL) {
499                         restoring = B_FALSE;
500                 } else if (hunt_filter_entry_is_busy(hftp, tbl_id)) {
501                         /* Ignore busy entries. */
502                         restoring = B_FALSE;
503                 } else {
504                         hunt_filter_set_entry_busy(hftp, tbl_id);
505                         restoring = B_TRUE;
506                 }
507
508                 EFSYS_UNLOCK(enp->en_eslp, state);
509
510                 if (restoring == B_FALSE)
511                         continue;
512
513                 if (hunt_filter_is_exclusive(spec)) {
514                         rc = efx_mcdi_filter_op_add(enp, spec,
515                             MC_CMD_FILTER_OP_IN_OP_INSERT,
516                             &hftp->hft_entry[tbl_id].hfe_handle);
517                 } else {
518                         rc = efx_mcdi_filter_op_add(enp, spec,
519                             MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
520                             &hftp->hft_entry[tbl_id].hfe_handle);
521                 }
522
523                 if (rc != 0)
524                         goto fail1;
525
526                 EFSYS_LOCK(enp->en_eslp, state);
527
528                 hunt_filter_set_entry_not_busy(hftp, tbl_id);
529
530                 EFSYS_UNLOCK(enp->en_eslp, state);
531         }
532
533         return (0);
534
535 fail1:
536         EFSYS_PROBE1(fail1, int, rc);
537
538         return (rc);
539 }
540
541 /*
542  * An arbitrary search limit for the software hash table. As per the linux net
543  * driver.
544  */
545 #define EFX_HUNT_FILTER_SEARCH_LIMIT 200
546
547 static  __checkReturn   int
548 hunt_filter_add_internal(
549         __in            efx_nic_t *enp,
550         __inout         efx_filter_spec_t *spec,
551         __in            boolean_t may_replace,
552         __out_opt       uint32_t *filter_id)
553 {
554         int rc;
555         hunt_filter_table_t *hftp = enp->en_filter.ef_hunt_filter_table;
556         efx_filter_spec_t *saved_spec;
557         uint32_t hash;
558         unsigned int depth;
559         int ins_index;
560         boolean_t replacing = B_FALSE;
561         unsigned int i;
562         int state;
563         boolean_t locked = B_FALSE;
564
565         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
566
567 #if EFSYS_OPT_RX_SCALE
568         spec->efs_rss_context = enp->en_rss_context;
569 #endif
570
571         hash = hunt_filter_hash(spec);
572
573         /*
574          * FIXME: Add support for inserting filters of different priorities
575          * and removing lower priority multicast filters (bug 42378)
576          */
577
578         /*
579          * Find any existing filters with the same match tuple or
580          * else a free slot to insert at.  If any of them are busy,
581          * we have to wait and retry.
582          */
583         for (;;) {
584                 ins_index = -1;
585                 depth = 1;
586                 EFSYS_LOCK(enp->en_eslp, state);
587                 locked = B_TRUE;
588
589                 for (;;) {
590                         i = (hash + depth) & (EFX_HUNT_FILTER_TBL_ROWS - 1);
591                         saved_spec = hunt_filter_entry_spec(hftp, i);
592
593                         if (!saved_spec) {
594                                 if (ins_index < 0) {
595                                         ins_index = i;
596                                 }
597                         } else if (hunt_filter_equal(spec, saved_spec)) {
598                                 if (hunt_filter_entry_is_busy(hftp, i))
599                                         break;
600                                 if (saved_spec->efs_priority
601                                             == EFX_FILTER_PRI_AUTO) {
602                                         ins_index = i;
603                                         goto found;
604                                 } else if (hunt_filter_is_exclusive(spec)) {
605                                         if (may_replace) {
606                                                 ins_index = i;
607                                                 goto found;
608                                         } else {
609                                                 rc = EEXIST;
610                                                 goto fail1;
611                                         }
612                                 }
613
614                                 /* Leave existing */
615                         }
616
617                         /*
618                          * Once we reach the maximum search depth, use
619                          * the first suitable slot or return EBUSY if
620                          * there was none.
621                          */
622                         if (depth == EFX_HUNT_FILTER_SEARCH_LIMIT) {
623                                 if (ins_index < 0) {
624                                         rc = EBUSY;
625                                         goto fail2;
626                                 }
627                                 goto found;
628                         }
629                         depth++;
630                 }
631                 EFSYS_UNLOCK(enp->en_eslp, state);
632                 locked = B_FALSE;
633         }
634
635 found:
636         /*
637          * Create a software table entry if necessary, and mark it
638          * busy.  We might yet fail to insert, but any attempt to
639          * insert a conflicting filter while we're waiting for the
640          * firmware must find the busy entry.
641          */
642         saved_spec = hunt_filter_entry_spec(hftp, ins_index);
643         if (saved_spec) {
644                 if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) {
645                         /* This is a filter we are refreshing */
646                         hunt_filter_set_entry_not_auto_old(hftp, ins_index);
647                         goto out_unlock;
648
649                 }
650                 replacing = B_TRUE;
651         } else {
652                 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec);
653                 if (!saved_spec) {
654                         rc = ENOMEM;
655                         goto fail3;
656                 }
657                 *saved_spec = *spec;
658                 hunt_filter_set_entry(hftp, ins_index, saved_spec);
659         }
660         hunt_filter_set_entry_busy(hftp, ins_index);
661
662         EFSYS_UNLOCK(enp->en_eslp, state);
663         locked = B_FALSE;
664
665         /*
666          * On replacing the filter handle may change after after a successful
667          * replace operation.
668          */
669         if (replacing) {
670                 rc = efx_mcdi_filter_op_add(enp, spec,
671                     MC_CMD_FILTER_OP_IN_OP_REPLACE,
672                     &hftp->hft_entry[ins_index].hfe_handle);
673         } else if (hunt_filter_is_exclusive(spec)) {
674                 rc = efx_mcdi_filter_op_add(enp, spec,
675                     MC_CMD_FILTER_OP_IN_OP_INSERT,
676                     &hftp->hft_entry[ins_index].hfe_handle);
677         } else {
678                 rc = efx_mcdi_filter_op_add(enp, spec,
679                     MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
680                     &hftp->hft_entry[ins_index].hfe_handle);
681         }
682
683         if (rc != 0)
684                 goto fail4;
685
686         EFSYS_LOCK(enp->en_eslp, state);
687         locked = B_TRUE;
688
689         if (replacing) {
690                 /* Update the fields that may differ */
691                 saved_spec->efs_priority = spec->efs_priority;
692                 saved_spec->efs_flags = spec->efs_flags;
693                 saved_spec->efs_rss_context = spec->efs_rss_context;
694                 saved_spec->efs_dmaq_id = spec->efs_dmaq_id;
695         }
696
697         hunt_filter_set_entry_not_busy(hftp, ins_index);
698
699 out_unlock:
700
701         EFSYS_UNLOCK(enp->en_eslp, state);
702         locked = B_FALSE;
703
704         if (filter_id)
705                 *filter_id = ins_index;
706
707         return (0);
708
709 fail4:
710         EFSYS_PROBE(fail4);
711
712         if (!replacing) {
713                 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec);
714                 saved_spec = NULL;
715         }
716         hunt_filter_set_entry_not_busy(hftp, ins_index);
717         hunt_filter_set_entry(hftp, ins_index, NULL);
718
719 fail3:
720         EFSYS_PROBE(fail3);
721
722 fail2:
723         EFSYS_PROBE(fail2);
724
725 fail1:
726         EFSYS_PROBE1(fail1, int, rc);
727
728         if (locked)
729                 EFSYS_UNLOCK(enp->en_eslp, state);
730
731         return (rc);
732 }
733
734         __checkReturn   int
735 hunt_filter_add(
736         __in            efx_nic_t *enp,
737         __inout         efx_filter_spec_t *spec,
738         __in            boolean_t may_replace)
739 {
740         int rc;
741
742         rc = hunt_filter_add_internal(enp, spec, may_replace, NULL);
743         if (rc != 0)
744                 goto fail1;
745
746         return (0);
747
748 fail1:
749         EFSYS_PROBE1(fail1, int, rc);
750
751         return (rc);
752 }
753
754
755 static  __checkReturn   int
756 hunt_filter_delete_internal(
757         __in            efx_nic_t *enp,
758         __in            uint32_t filter_id)
759 {
760         int rc;
761         hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table;
762         efx_filter_spec_t *spec;
763         int state;
764         uint32_t filter_idx = filter_id % EFX_HUNT_FILTER_TBL_ROWS;
765
766         /*
767          * Find the software table entry and mark it busy.  Don't
768          * remove it yet; any attempt to update while we're waiting
769          * for the firmware must find the busy entry.
770          *
771          * FIXME: What if the busy flag is never cleared?
772          */
773         EFSYS_LOCK(enp->en_eslp, state);
774         while (hunt_filter_entry_is_busy(table, filter_idx)) {
775                 EFSYS_UNLOCK(enp->en_eslp, state);
776                 EFSYS_SPIN(1);
777                 EFSYS_LOCK(enp->en_eslp, state);
778         }
779         if ((spec = hunt_filter_entry_spec(table, filter_idx)) != NULL) {
780                 hunt_filter_set_entry_busy(table, filter_idx);
781         }
782         EFSYS_UNLOCK(enp->en_eslp, state);
783
784         if (spec == NULL) {
785                 rc = ENOENT;
786                 goto fail1;
787         }
788
789         /*
790          * Try to remove the hardware filter. This may fail if the MC has
791          * rebooted (which frees all hardware filter resources).
792          */
793         if (hunt_filter_is_exclusive(spec)) {
794                 rc = efx_mcdi_filter_op_delete(enp,
795                     MC_CMD_FILTER_OP_IN_OP_REMOVE,
796                     &table->hft_entry[filter_idx].hfe_handle);
797         } else {
798                 rc = efx_mcdi_filter_op_delete(enp,
799                     MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE,
800                     &table->hft_entry[filter_idx].hfe_handle);
801         }
802
803         /* Free the software table entry */
804         EFSYS_LOCK(enp->en_eslp, state);
805         hunt_filter_set_entry_not_busy(table, filter_idx);
806         hunt_filter_set_entry(table, filter_idx, NULL);
807         EFSYS_UNLOCK(enp->en_eslp, state);
808
809         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
810
811         /* Check result of hardware filter removal */
812         if (rc != 0)
813                 goto fail2;
814
815         return (0);
816
817 fail2:
818         EFSYS_PROBE(fail2);
819
820 fail1:
821         EFSYS_PROBE1(fail1, int, rc);
822
823         return (rc);
824 }
825
826         __checkReturn   int
827 hunt_filter_delete(
828         __in            efx_nic_t *enp,
829         __inout         efx_filter_spec_t *spec)
830 {
831         int rc;
832         hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table;
833         efx_filter_spec_t *saved_spec;
834         unsigned int hash;
835         unsigned int depth;
836         unsigned int i;
837         int state;
838         boolean_t locked = B_FALSE;
839
840         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
841
842         hash = hunt_filter_hash(spec);
843
844         EFSYS_LOCK(enp->en_eslp, state);
845         locked = B_TRUE;
846
847         depth = 1;
848         for (;;) {
849                 i = (hash + depth) & (EFX_HUNT_FILTER_TBL_ROWS - 1);
850                 saved_spec = hunt_filter_entry_spec(table, i);
851                 if (saved_spec && hunt_filter_equal(spec, saved_spec) &&
852                     hunt_filter_same_dest(spec, saved_spec)) {
853                         break;
854                 }
855                 if (depth == EFX_HUNT_FILTER_SEARCH_LIMIT) {
856                         rc = ENOENT;
857                         goto fail1;
858                 }
859                 depth++;
860         }
861
862         EFSYS_UNLOCK(enp->en_eslp, state);
863         locked = B_FALSE;
864
865         rc = hunt_filter_delete_internal(enp, i);
866         if (rc != 0)
867                 goto fail2;
868
869         return (0);
870
871 fail2:
872         EFSYS_PROBE(fail2);
873
874 fail1:
875         EFSYS_PROBE1(fail1, int, rc);
876
877         if (locked)
878                 EFSYS_UNLOCK(enp->en_eslp, state);
879
880         return (rc);
881 }
882
883 static  __checkReturn   int
884 efx_mcdi_get_parser_disp_info(
885         __in            efx_nic_t *enp,
886         __out           uint32_t *list,
887         __out           size_t *length)
888 {
889         efx_mcdi_req_t req;
890         uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN,
891                             MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)];
892         int rc;
893         uint32_t i;
894         boolean_t support_unknown_ucast = B_FALSE;
895         boolean_t support_unknown_mcast = B_FALSE;
896
897         (void) memset(payload, 0, sizeof (payload));
898         req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO;
899         req.emr_in_buf = payload;
900         req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN;
901         req.emr_out_buf = payload;
902         req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX;
903
904         MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP,
905             MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES);
906
907         efx_mcdi_execute(enp, &req);
908
909         if (req.emr_rc != 0) {
910                 rc = req.emr_rc;
911                 goto fail1;
912         }
913
914         *length = MCDI_OUT_DWORD(req,
915             GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES);
916
917         if (req.emr_out_length_used <
918             MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(*length)) {
919                 rc = EMSGSIZE;
920                 goto fail2;
921         }
922
923         memcpy(list,
924             MCDI_OUT2(req,
925             uint32_t,
926             GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES),
927             (*length) * sizeof (uint32_t));
928         EFX_STATIC_ASSERT(sizeof (uint32_t) ==
929             MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN);
930
931         /*
932          * Remove UNKNOWN UCAST and MCAST flags, and if both are present, change
933          * the lower priority one to LOC_MAC_IG.
934          */
935         for (i = 0; i < *length; i++) {
936                 if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN) {
937                         list[i] &=
938                         (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN);
939                         support_unknown_ucast = B_TRUE;
940                 }
941                 if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) {
942                         list[i] &=
943                         (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN);
944                         support_unknown_mcast = B_TRUE;
945                 }
946
947                 if (support_unknown_ucast && support_unknown_mcast) {
948                         list[i] &= EFX_FILTER_MATCH_LOC_MAC_IG;
949                         break;
950                 }
951         }
952
953         return (0);
954
955 fail2:
956         EFSYS_PROBE(fail2);
957 fail1:
958         EFSYS_PROBE1(fail1, int, rc);
959
960         return (rc);
961 }
962
963         __checkReturn   int
964 hunt_filter_supported_filters(
965         __in            efx_nic_t *enp,
966         __out           uint32_t *list,
967         __out           size_t *length)
968 {
969         int rc;
970
971         if ((rc = efx_mcdi_get_parser_disp_info(enp, list, length) != 0))
972                 goto fail1;
973
974         return (0);
975
976 fail1:
977         EFSYS_PROBE1(fail1, int, rc);
978
979         return (rc);
980 }
981
982 static  __checkReturn   int
983 hunt_filter_unicast_refresh(
984         __in                            efx_nic_t *enp,
985         __in_ecount(6)                  uint8_t const *addr,
986         __in                            boolean_t all_unicst,
987         __in                            efx_filter_flag_t filter_flags)
988 {
989         hunt_filter_table_t *hftp = enp->en_filter.ef_hunt_filter_table;
990         efx_filter_spec_t spec;
991         int rc;
992
993         if (all_unicst == B_TRUE)
994                 goto use_uc_def;
995
996         /* Insert the filter for the local station address */
997         efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
998             filter_flags,
999             hftp->hft_default_rxq);
1000         efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, addr);
1001
1002         rc = hunt_filter_add_internal(enp, &spec, B_TRUE,
1003             &hftp->hft_unicst_filter_index);
1004         if (rc != 0) {
1005                 /*
1006                  * Fall back to an unknown filter. We may be able to subscribe
1007                  * to it even if we couldn't insert the unicast filter.
1008                  */
1009                 goto use_uc_def;
1010         }
1011         hftp->hft_unicst_filter_set = B_TRUE;
1012
1013         return (0);
1014
1015 use_uc_def:
1016         /* Insert the unknown unicast filter */
1017         efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1018             filter_flags,
1019             hftp->hft_default_rxq);
1020         efx_filter_spec_set_uc_def(&spec);
1021         rc = hunt_filter_add_internal(enp, &spec, B_TRUE,
1022             &hftp->hft_unicst_filter_index);
1023         if (rc != 0)
1024                 goto fail1;
1025
1026         hftp->hft_unicst_filter_set = B_TRUE;
1027
1028         return (0);
1029
1030 fail1:
1031         EFSYS_PROBE1(fail1, int, rc);
1032
1033         if (hftp->hft_unicst_filter_set != B_FALSE) {
1034                 (void) hunt_filter_delete_internal(enp,
1035                     hftp->hft_unicst_filter_index);
1036
1037                 hftp->hft_unicst_filter_set = B_FALSE;
1038         }
1039
1040         return (rc);
1041 }
1042
1043 static  __checkReturn   int
1044 hunt_filter_multicast_refresh(
1045         __in                            efx_nic_t *enp,
1046         __in                            boolean_t mulcst,
1047         __in                            boolean_t all_mulcst,
1048         __in                            boolean_t brdcst,
1049         __in_ecount(6*count)            uint8_t const *addrs,
1050         __in                            int count,
1051         __in                            efx_filter_flag_t filter_flags)
1052 {
1053         hunt_filter_table_t *hftp = enp->en_filter.ef_hunt_filter_table;
1054         efx_filter_spec_t spec;
1055         uint8_t addr[6];
1056         unsigned i;
1057         int rc;
1058
1059         if (all_mulcst == B_TRUE)
1060                 goto use_mc_def;
1061
1062         if (mulcst == B_FALSE)
1063                 count = 0;
1064
1065         if (count + (brdcst ? 1 : 0) >
1066             EFX_ARRAY_SIZE(hftp->hft_mulcst_filter_indexes)) {
1067                 /* Too many MAC addresses; use unknown multicast filter */
1068                 goto use_mc_def;
1069         }
1070
1071         /* Insert/renew multicast address list filters */
1072         hftp->hft_mulcst_filter_count = count;
1073         for (i = 0; i < hftp->hft_mulcst_filter_count; i++) {
1074                 efx_filter_spec_init_rx(&spec,
1075                     EFX_FILTER_PRI_AUTO,
1076                     filter_flags,
1077                     hftp->hft_default_rxq);
1078
1079                 efx_filter_spec_set_eth_local(&spec,
1080                     EFX_FILTER_SPEC_VID_UNSPEC,
1081                     &addrs[i * EFX_MAC_ADDR_LEN]);
1082
1083                 rc = hunt_filter_add_internal(enp, &spec, B_TRUE,
1084                     &hftp->hft_mulcst_filter_indexes[i]);
1085                 if (rc != 0) {
1086                         /* Rollback, then use unknown multicast filter */
1087                         goto rollback;
1088                 }
1089         }
1090
1091         if (brdcst == B_TRUE) {
1092                 /* Insert/renew broadcast address filter */
1093                 hftp->hft_mulcst_filter_count++;
1094                 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1095                     filter_flags,
1096                     hftp->hft_default_rxq);
1097
1098                 EFX_MAC_BROADCAST_ADDR_SET(addr);
1099                 efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC,
1100                     addr);
1101
1102                 rc = hunt_filter_add_internal(enp, &spec, B_TRUE,
1103                     &hftp->hft_mulcst_filter_indexes[
1104                         hftp->hft_mulcst_filter_count - 1]);
1105                 if (rc != 0) {
1106                         /* Rollback, then use unknown multicast filter */
1107                         goto rollback;
1108                 }
1109         }
1110
1111         return (0);
1112
1113 rollback:
1114         /*
1115          * Rollback by removing any filters we have inserted
1116          * before inserting the unknown multicast filter.
1117          */
1118         while (i--) {
1119                 (void) hunt_filter_delete_internal(enp,
1120                     hftp->hft_mulcst_filter_indexes[i]);
1121         }
1122         hftp->hft_mulcst_filter_count = 0;
1123
1124 use_mc_def:
1125         /* Insert the unknown multicast filter */
1126         efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1127             filter_flags,
1128             hftp->hft_default_rxq);
1129         efx_filter_spec_set_mc_def(&spec);
1130
1131         rc = hunt_filter_add_internal(enp, &spec, B_TRUE,
1132             &hftp->hft_mulcst_filter_indexes[0]);
1133         if (rc != 0)
1134                 goto fail1;
1135
1136         hftp->hft_mulcst_filter_count = 1;
1137
1138         /*
1139          * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic.
1140          */
1141
1142         return (0);
1143
1144 fail1:
1145         EFSYS_PROBE1(fail1, int, rc);
1146
1147         return (rc);
1148
1149 }
1150
1151
1152 static  __checkReturn   int
1153 hunt_filter_get_workarounds(
1154         __in                            efx_nic_t *enp)
1155 {
1156         efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1157         uint32_t implemented = 0;
1158         uint32_t enabled = 0;
1159         int rc;
1160
1161         rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled);
1162         if (rc == 0) {
1163                 /* Check if chained multicast filter support is enabled */
1164                 if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807)
1165                         encp->enc_bug26807_workaround = B_TRUE;
1166                 else
1167                         encp->enc_bug26807_workaround = B_FALSE;
1168         } else if (rc == ENOTSUP) {
1169                 /*
1170                  * Firmware is too old to support GET_WORKAROUNDS, and support
1171                  * for this workaround was implemented later.
1172                  */
1173                 encp->enc_bug26807_workaround = B_FALSE;
1174         } else {
1175                 goto fail1;
1176         }
1177
1178         return (0);
1179
1180 fail1:
1181         EFSYS_PROBE1(fail1, int, rc);
1182
1183         return (rc);
1184
1185 }
1186
1187
1188 /*
1189  * Reconfigure all filters.
1190  * If all_unicst and/or all mulcst filters cannot be applied then
1191  * return ENOTSUP (Note the filters for the specified addresses are
1192  * still applied in this case).
1193  */
1194         __checkReturn   int
1195 hunt_filter_reconfigure(
1196         __in                            efx_nic_t *enp,
1197         __in_ecount(6)                  uint8_t const *mac_addr,
1198         __in                            boolean_t all_unicst,
1199         __in                            boolean_t mulcst,
1200         __in                            boolean_t all_mulcst,
1201         __in                            boolean_t brdcst,
1202         __in_ecount(6*count)            uint8_t const *addrs,
1203         __in                            int count)
1204 {
1205         hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table;
1206         efx_filter_flag_t filter_flags;
1207         unsigned i;
1208         int all_unicst_rc;
1209         int all_mulcst_rc;
1210         int rc;
1211
1212         if (table->hft_default_rxq == NULL) {
1213                 /*
1214                  * Filters direct traffic to the default RXQ, and so cannot be
1215                  * inserted until it is available. Any currently configured
1216                  * filters must be removed (ignore errors in case the MC
1217                  * has rebooted, which removes hardware filters).
1218                  */
1219                 if (table->hft_unicst_filter_set != B_FALSE) {
1220                         (void) hunt_filter_delete_internal(enp,
1221                                                 table->hft_unicst_filter_index);
1222                         table->hft_unicst_filter_set = B_FALSE;
1223                 }
1224                 for (i = 0; i < table->hft_mulcst_filter_count; i++) {
1225                         (void) hunt_filter_delete_internal(enp,
1226                                         table->hft_mulcst_filter_indexes[i]);
1227                 }
1228                 table->hft_mulcst_filter_count = 0;
1229
1230                 return (0);
1231         }
1232
1233         if (table->hft_using_rss)
1234                 filter_flags = EFX_FILTER_FLAG_RX_RSS;
1235         else
1236                 filter_flags = 0;
1237
1238         /* Mark old filters which may need to be removed */
1239         if (table->hft_unicst_filter_set != B_FALSE) {
1240                 hunt_filter_set_entry_auto_old(table,
1241                                             table->hft_unicst_filter_index);
1242         }
1243         for (i = 0; i < table->hft_mulcst_filter_count; i++) {
1244                 hunt_filter_set_entry_auto_old(table,
1245                                         table->hft_mulcst_filter_indexes[i]);
1246         }
1247
1248         /* Insert or renew unicast filters */
1249         if ((all_unicst_rc = hunt_filter_unicast_refresh(enp, mac_addr,
1250                     all_unicst, filter_flags)) !=  0) {
1251                 if (all_unicst == B_FALSE) {
1252                         rc = all_unicst_rc;
1253                         goto fail1;
1254                 }
1255                 /* Retry without all_unicast flag */
1256                 rc = hunt_filter_unicast_refresh(enp, mac_addr,
1257                         B_FALSE, filter_flags);
1258                 if (rc != 0)
1259                         goto fail2;
1260         }
1261
1262         /*
1263          * WORKAROUND_BUG26807 controls firmware support for chained multicast
1264          * filters, and can only be enabled or disabled when the hardware filter
1265          * table is empty.
1266          *
1267          * Firmware will reset (FLR) functions which have inserted filters in
1268          * the hardware filter table when the workaround is enabled/disabled.
1269          * Functions without any hardware filters are not reset.
1270          *
1271          * Re-check if the workaround is enabled after adding unicast hardware
1272          * filters. This ensures that encp->enc_workaround_bug26807 matches the
1273          * firmware state, and that later changes to enable/disable the
1274          * workaround will result in this function seeing a reset (FLR).
1275          */
1276         if ((rc = hunt_filter_get_workarounds(enp)) != 0)
1277                 goto fail3;
1278
1279         /* Insert or renew multicast filters */
1280         if ((all_mulcst_rc = hunt_filter_multicast_refresh(enp, mulcst,
1281                                 all_mulcst, brdcst,
1282                                 addrs, count, filter_flags)) != 0) {
1283                 if (all_mulcst == B_FALSE) {
1284                         rc = all_mulcst_rc;
1285                         goto fail4;
1286                 }
1287                 /* Retry without all_mulcast flag */
1288                 rc = hunt_filter_multicast_refresh(enp, mulcst,
1289                                                 B_FALSE, brdcst,
1290                                                 addrs, count, filter_flags);
1291                 if (rc != 0)
1292                         goto fail5;
1293         }
1294
1295         /* Remove old filters which were not renewed */
1296         for (i = 0; i < EFX_ARRAY_SIZE(table->hft_entry); i++) {
1297                 if (hunt_filter_entry_is_auto_old(table, i)) {
1298                         (void) hunt_filter_delete_internal(enp, i);
1299                 }
1300         }
1301
1302         /* report if any optional flags were rejected */
1303         if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) ||
1304             ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) {
1305                 rc = ENOTSUP;
1306         }
1307
1308         return (rc);
1309
1310 fail5:
1311         EFSYS_PROBE(fail5);
1312 fail4:
1313         EFSYS_PROBE(fail4);
1314 fail3:
1315         EFSYS_PROBE(fail3);
1316 fail2:
1317         EFSYS_PROBE(fail2);
1318 fail1:
1319         EFSYS_PROBE1(fail1, int, rc);
1320
1321         /* Clear auto old flags */
1322         for (i = 0; i < EFX_ARRAY_SIZE(table->hft_entry); i++) {
1323                 if (hunt_filter_entry_is_auto_old(table, i)) {
1324                         hunt_filter_set_entry_not_auto_old(table, i);
1325                 }
1326         }
1327
1328         return (rc);
1329 }
1330
1331                 void
1332 hunt_filter_get_default_rxq(
1333         __in            efx_nic_t *enp,
1334         __out           efx_rxq_t **erpp,
1335         __out           boolean_t *using_rss)
1336 {
1337         hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table;
1338
1339         *erpp = table->hft_default_rxq;
1340         *using_rss = table->hft_using_rss;
1341 }
1342
1343
1344                 void
1345 hunt_filter_default_rxq_set(
1346         __in            efx_nic_t *enp,
1347         __in            efx_rxq_t *erp,
1348         __in            boolean_t using_rss)
1349 {
1350         hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table;
1351
1352 #if EFSYS_OPT_RX_SCALE
1353         EFSYS_ASSERT((using_rss == B_FALSE) ||
1354             (enp->en_rss_context != HUNTINGTON_RSS_CONTEXT_INVALID));
1355         table->hft_using_rss = using_rss;
1356 #else
1357         EFSYS_ASSERT(using_rss == B_FALSE);
1358         table->hft_using_rss = B_FALSE;
1359 #endif
1360         table->hft_default_rxq = erp;
1361 }
1362
1363                 void
1364 hunt_filter_default_rxq_clear(
1365         __in            efx_nic_t *enp)
1366 {
1367         hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table;
1368
1369         table->hft_default_rxq = NULL;
1370         table->hft_using_rss = B_FALSE;
1371 }
1372
1373
1374 #endif /* EFSYS_OPT_FILTER */
1375
1376 #endif /* EFSYS_OPT_HUNTINGTON */