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