]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/sfxge/common/ef10_filter.c
MFC r310816
[FreeBSD/stable/10.git] / sys / dev / sfxge / common / ef10_filter.c
1 /*-
2  * Copyright (c) 2007-2016 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 || EFSYS_OPT_MEDFORD
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         EFX_STATIC_ASSERT(EFX_FILTER_MATCH_UNKNOWN_MCAST_DST ==
149             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST));
150         EFX_STATIC_ASSERT((uint32_t)EFX_FILTER_MATCH_UNKNOWN_UCAST_DST ==
151             MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST));
152 #undef MATCH_MASK
153
154         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp);
155
156         if (!eftp) {
157                 rc = ENOMEM;
158                 goto fail1;
159         }
160
161         enp->en_filter.ef_ef10_filter_table = eftp;
162
163         return (0);
164
165 fail1:
166         EFSYS_PROBE1(fail1, efx_rc_t, rc);
167
168         return (rc);
169 }
170
171                         void
172 ef10_filter_fini(
173         __in            efx_nic_t *enp)
174 {
175         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
176                     enp->en_family == EFX_FAMILY_MEDFORD);
177
178         if (enp->en_filter.ef_ef10_filter_table != NULL) {
179                 EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t),
180                     enp->en_filter.ef_ef10_filter_table);
181         }
182 }
183
184 static  __checkReturn   efx_rc_t
185 efx_mcdi_filter_op_add(
186         __in            efx_nic_t *enp,
187         __in            efx_filter_spec_t *spec,
188         __in            unsigned int filter_op,
189         __inout         ef10_filter_handle_t *handle)
190 {
191         efx_mcdi_req_t req;
192         uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN,
193                             MC_CMD_FILTER_OP_OUT_LEN)];
194         efx_rc_t rc;
195
196         memset(payload, 0, sizeof (payload));
197         req.emr_cmd = MC_CMD_FILTER_OP;
198         req.emr_in_buf = payload;
199         req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN;
200         req.emr_out_buf = payload;
201         req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN;
202
203         switch (filter_op) {
204         case MC_CMD_FILTER_OP_IN_OP_REPLACE:
205                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO,
206                     handle->efh_lo);
207                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI,
208                     handle->efh_hi);
209                 /* Fall through */
210         case MC_CMD_FILTER_OP_IN_OP_INSERT:
211         case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE:
212                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, filter_op);
213                 break;
214         default:
215                 EFSYS_ASSERT(0);
216                 rc = EINVAL;
217                 goto fail1;
218         }
219
220         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_PORT_ID,
221             EVB_PORT_ID_ASSIGNED);
222         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_MATCH_FIELDS,
223             spec->efs_match_flags);
224         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_DEST,
225             MC_CMD_FILTER_OP_IN_RX_DEST_HOST);
226         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_QUEUE,
227             spec->efs_dmaq_id);
228         if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) {
229                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_CONTEXT,
230                     spec->efs_rss_context);
231         }
232         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_MODE,
233             spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ?
234             MC_CMD_FILTER_OP_IN_RX_MODE_RSS :
235             MC_CMD_FILTER_OP_IN_RX_MODE_SIMPLE);
236         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_TX_DEST,
237             MC_CMD_FILTER_OP_IN_TX_DEST_DEFAULT);
238
239         if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) {
240                 /*
241                  * NOTE: Unlike most MCDI requests, the filter fields
242                  * are presented in network (big endian) byte order.
243                  */
244                 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_MAC),
245                     spec->efs_rem_mac, EFX_MAC_ADDR_LEN);
246                 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_MAC),
247                     spec->efs_loc_mac, EFX_MAC_ADDR_LEN);
248
249                 MCDI_IN_SET_WORD(req, FILTER_OP_IN_SRC_PORT,
250                     __CPU_TO_BE_16(spec->efs_rem_port));
251                 MCDI_IN_SET_WORD(req, FILTER_OP_IN_DST_PORT,
252                     __CPU_TO_BE_16(spec->efs_loc_port));
253
254                 MCDI_IN_SET_WORD(req, FILTER_OP_IN_ETHER_TYPE,
255                     __CPU_TO_BE_16(spec->efs_ether_type));
256
257                 MCDI_IN_SET_WORD(req, FILTER_OP_IN_INNER_VLAN,
258                     __CPU_TO_BE_16(spec->efs_inner_vid));
259                 MCDI_IN_SET_WORD(req, FILTER_OP_IN_OUTER_VLAN,
260                     __CPU_TO_BE_16(spec->efs_outer_vid));
261
262                 /* IP protocol (in low byte, high byte is zero) */
263                 MCDI_IN_SET_BYTE(req, FILTER_OP_IN_IP_PROTO,
264                     spec->efs_ip_proto);
265
266                 EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) ==
267                     MC_CMD_FILTER_OP_IN_SRC_IP_LEN);
268                 EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) ==
269                     MC_CMD_FILTER_OP_IN_DST_IP_LEN);
270
271                 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_IP),
272                     &spec->efs_rem_host.eo_byte[0],
273                     MC_CMD_FILTER_OP_IN_SRC_IP_LEN);
274                 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_IP),
275                     &spec->efs_loc_host.eo_byte[0],
276                     MC_CMD_FILTER_OP_IN_DST_IP_LEN);
277         }
278
279         efx_mcdi_execute(enp, &req);
280
281         if (req.emr_rc != 0) {
282                 rc = req.emr_rc;
283                 goto fail2;
284         }
285
286         if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) {
287                 rc = EMSGSIZE;
288                 goto fail3;
289         }
290
291         handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_LO);
292         handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_HI);
293
294         return (0);
295
296 fail3:
297         EFSYS_PROBE(fail3);
298 fail2:
299         EFSYS_PROBE(fail2);
300 fail1:
301         EFSYS_PROBE1(fail1, efx_rc_t, rc);
302
303         return (rc);
304
305 }
306
307 static  __checkReturn   efx_rc_t
308 efx_mcdi_filter_op_delete(
309         __in            efx_nic_t *enp,
310         __in            unsigned int filter_op,
311         __inout         ef10_filter_handle_t *handle)
312 {
313         efx_mcdi_req_t req;
314         uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN,
315                             MC_CMD_FILTER_OP_OUT_LEN)];
316         efx_rc_t rc;
317
318         memset(payload, 0, sizeof (payload));
319         req.emr_cmd = MC_CMD_FILTER_OP;
320         req.emr_in_buf = payload;
321         req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN;
322         req.emr_out_buf = payload;
323         req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN;
324
325         switch (filter_op) {
326         case MC_CMD_FILTER_OP_IN_OP_REMOVE:
327                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP,
328                     MC_CMD_FILTER_OP_IN_OP_REMOVE);
329                 break;
330         case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE:
331                 MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP,
332                     MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE);
333                 break;
334         default:
335                 EFSYS_ASSERT(0);
336                 rc = EINVAL;
337                 goto fail1;
338         }
339
340         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, handle->efh_lo);
341         MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, handle->efh_hi);
342
343         efx_mcdi_execute_quiet(enp, &req);
344
345         if (req.emr_rc != 0) {
346                 rc = req.emr_rc;
347                 goto fail2;
348         }
349
350         if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) {
351                 rc = EMSGSIZE;
352                 goto fail3;
353         }
354
355         return (0);
356
357 fail3:
358         EFSYS_PROBE(fail3);
359
360 fail2:
361         EFSYS_PROBE(fail2);
362 fail1:
363         EFSYS_PROBE1(fail1, efx_rc_t, rc);
364
365         return (rc);
366 }
367
368 static  __checkReturn   boolean_t
369 ef10_filter_equal(
370         __in            const efx_filter_spec_t *left,
371         __in            const efx_filter_spec_t *right)
372 {
373         /* FIXME: Consider rx vs tx filters (look at efs_flags) */
374         if (left->efs_match_flags != right->efs_match_flags)
375                 return (B_FALSE);
376         if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host))
377                 return (B_FALSE);
378         if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host))
379                 return (B_FALSE);
380         if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN))
381                 return (B_FALSE);
382         if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN))
383                 return (B_FALSE);
384         if (left->efs_rem_port != right->efs_rem_port)
385                 return (B_FALSE);
386         if (left->efs_loc_port != right->efs_loc_port)
387                 return (B_FALSE);
388         if (left->efs_inner_vid != right->efs_inner_vid)
389                 return (B_FALSE);
390         if (left->efs_outer_vid != right->efs_outer_vid)
391                 return (B_FALSE);
392         if (left->efs_ether_type != right->efs_ether_type)
393                 return (B_FALSE);
394         if (left->efs_ip_proto != right->efs_ip_proto)
395                 return (B_FALSE);
396
397         return (B_TRUE);
398
399 }
400
401 static  __checkReturn   boolean_t
402 ef10_filter_same_dest(
403         __in            const efx_filter_spec_t *left,
404         __in            const efx_filter_spec_t *right)
405 {
406         if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
407             (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) {
408                 if (left->efs_rss_context == right->efs_rss_context)
409                         return (B_TRUE);
410         } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) &&
411             (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) {
412                 if (left->efs_dmaq_id == right->efs_dmaq_id)
413                         return (B_TRUE);
414         }
415         return (B_FALSE);
416 }
417
418 static  __checkReturn   uint32_t
419 ef10_filter_hash(
420         __in            efx_filter_spec_t *spec)
421 {
422         EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t))
423                             == 0);
424         EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) %
425                             sizeof (uint32_t)) == 0);
426
427         /*
428          * As the area of the efx_filter_spec_t we need to hash is DWORD
429          * aligned and an exact number of DWORDs in size we can use the
430          * optimised efx_hash_dwords() rather than efx_hash_bytes()
431          */
432         return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid,
433                         (sizeof (efx_filter_spec_t) -
434                         EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) /
435                         sizeof (uint32_t), 0));
436 }
437
438 /*
439  * Decide whether a filter should be exclusive or else should allow
440  * delivery to additional recipients.  Currently we decide that
441  * filters for specific local unicast MAC and IP addresses are
442  * exclusive.
443  */
444 static  __checkReturn   boolean_t
445 ef10_filter_is_exclusive(
446         __in            efx_filter_spec_t *spec)
447 {
448         if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) &&
449             !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac))
450                 return (B_TRUE);
451
452         if ((spec->efs_match_flags &
453                 (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) ==
454             (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) {
455                 if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) &&
456                     ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe))
457                         return (B_TRUE);
458                 if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) &&
459                     (spec->efs_loc_host.eo_u8[0] != 0xff))
460                         return (B_TRUE);
461         }
462
463         return (B_FALSE);
464 }
465
466         __checkReturn   efx_rc_t
467 ef10_filter_restore(
468         __in            efx_nic_t *enp)
469 {
470         int tbl_id;
471         efx_filter_spec_t *spec;
472         ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
473         boolean_t restoring;
474         efsys_lock_state_t state;
475         efx_rc_t rc;
476
477         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
478                     enp->en_family == EFX_FAMILY_MEDFORD);
479
480         for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) {
481
482                 EFSYS_LOCK(enp->en_eslp, state);
483
484                 spec = ef10_filter_entry_spec(eftp, tbl_id);
485                 if (spec == NULL) {
486                         restoring = B_FALSE;
487                 } else if (ef10_filter_entry_is_busy(eftp, tbl_id)) {
488                         /* Ignore busy entries. */
489                         restoring = B_FALSE;
490                 } else {
491                         ef10_filter_set_entry_busy(eftp, tbl_id);
492                         restoring = B_TRUE;
493                 }
494
495                 EFSYS_UNLOCK(enp->en_eslp, state);
496
497                 if (restoring == B_FALSE)
498                         continue;
499
500                 if (ef10_filter_is_exclusive(spec)) {
501                         rc = efx_mcdi_filter_op_add(enp, spec,
502                             MC_CMD_FILTER_OP_IN_OP_INSERT,
503                             &eftp->eft_entry[tbl_id].efe_handle);
504                 } else {
505                         rc = efx_mcdi_filter_op_add(enp, spec,
506                             MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
507                             &eftp->eft_entry[tbl_id].efe_handle);
508                 }
509
510                 if (rc != 0)
511                         goto fail1;
512
513                 EFSYS_LOCK(enp->en_eslp, state);
514
515                 ef10_filter_set_entry_not_busy(eftp, tbl_id);
516
517                 EFSYS_UNLOCK(enp->en_eslp, state);
518         }
519
520         return (0);
521
522 fail1:
523         EFSYS_PROBE1(fail1, efx_rc_t, rc);
524
525         return (rc);
526 }
527
528 /*
529  * An arbitrary search limit for the software hash table. As per the linux net
530  * driver.
531  */
532 #define EF10_FILTER_SEARCH_LIMIT 200
533
534 static  __checkReturn   efx_rc_t
535 ef10_filter_add_internal(
536         __in            efx_nic_t *enp,
537         __inout         efx_filter_spec_t *spec,
538         __in            boolean_t may_replace,
539         __out_opt       uint32_t *filter_id)
540 {
541         efx_rc_t rc;
542         ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
543         efx_filter_spec_t *saved_spec;
544         uint32_t hash;
545         unsigned int depth;
546         int ins_index;
547         boolean_t replacing = B_FALSE;
548         unsigned int i;
549         efsys_lock_state_t state;
550         boolean_t locked = B_FALSE;
551
552         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
553                     enp->en_family == EFX_FAMILY_MEDFORD);
554
555 #if EFSYS_OPT_RX_SCALE
556         spec->efs_rss_context = enp->en_rss_context;
557 #endif
558
559         hash = ef10_filter_hash(spec);
560
561         /*
562          * FIXME: Add support for inserting filters of different priorities
563          * and removing lower priority multicast filters (bug 42378)
564          */
565
566         /*
567          * Find any existing filters with the same match tuple or
568          * else a free slot to insert at.  If any of them are busy,
569          * we have to wait and retry.
570          */
571         for (;;) {
572                 ins_index = -1;
573                 depth = 1;
574                 EFSYS_LOCK(enp->en_eslp, state);
575                 locked = B_TRUE;
576
577                 for (;;) {
578                         i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1);
579                         saved_spec = ef10_filter_entry_spec(eftp, i);
580
581                         if (!saved_spec) {
582                                 if (ins_index < 0) {
583                                         ins_index = i;
584                                 }
585                         } else if (ef10_filter_equal(spec, saved_spec)) {
586                                 if (ef10_filter_entry_is_busy(eftp, i))
587                                         break;
588                                 if (saved_spec->efs_priority
589                                             == EFX_FILTER_PRI_AUTO) {
590                                         ins_index = i;
591                                         goto found;
592                                 } else if (ef10_filter_is_exclusive(spec)) {
593                                         if (may_replace) {
594                                                 ins_index = i;
595                                                 goto found;
596                                         } else {
597                                                 rc = EEXIST;
598                                                 goto fail1;
599                                         }
600                                 }
601
602                                 /* Leave existing */
603                         }
604
605                         /*
606                          * Once we reach the maximum search depth, use
607                          * the first suitable slot or return EBUSY if
608                          * there was none.
609                          */
610                         if (depth == EF10_FILTER_SEARCH_LIMIT) {
611                                 if (ins_index < 0) {
612                                         rc = EBUSY;
613                                         goto fail2;
614                                 }
615                                 goto found;
616                         }
617                         depth++;
618                 }
619                 EFSYS_UNLOCK(enp->en_eslp, state);
620                 locked = B_FALSE;
621         }
622
623 found:
624         /*
625          * Create a software table entry if necessary, and mark it
626          * busy.  We might yet fail to insert, but any attempt to
627          * insert a conflicting filter while we're waiting for the
628          * firmware must find the busy entry.
629          */
630         saved_spec = ef10_filter_entry_spec(eftp, ins_index);
631         if (saved_spec) {
632                 if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) {
633                         /* This is a filter we are refreshing */
634                         ef10_filter_set_entry_not_auto_old(eftp, ins_index);
635                         goto out_unlock;
636
637                 }
638                 replacing = B_TRUE;
639         } else {
640                 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec);
641                 if (!saved_spec) {
642                         rc = ENOMEM;
643                         goto fail3;
644                 }
645                 *saved_spec = *spec;
646                 ef10_filter_set_entry(eftp, ins_index, saved_spec);
647         }
648         ef10_filter_set_entry_busy(eftp, ins_index);
649
650         EFSYS_UNLOCK(enp->en_eslp, state);
651         locked = B_FALSE;
652
653         /*
654          * On replacing the filter handle may change after after a successful
655          * replace operation.
656          */
657         if (replacing) {
658                 rc = efx_mcdi_filter_op_add(enp, spec,
659                     MC_CMD_FILTER_OP_IN_OP_REPLACE,
660                     &eftp->eft_entry[ins_index].efe_handle);
661         } else if (ef10_filter_is_exclusive(spec)) {
662                 rc = efx_mcdi_filter_op_add(enp, spec,
663                     MC_CMD_FILTER_OP_IN_OP_INSERT,
664                     &eftp->eft_entry[ins_index].efe_handle);
665         } else {
666                 rc = efx_mcdi_filter_op_add(enp, spec,
667                     MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
668                     &eftp->eft_entry[ins_index].efe_handle);
669         }
670
671         if (rc != 0)
672                 goto fail4;
673
674         EFSYS_LOCK(enp->en_eslp, state);
675         locked = B_TRUE;
676
677         if (replacing) {
678                 /* Update the fields that may differ */
679                 saved_spec->efs_priority = spec->efs_priority;
680                 saved_spec->efs_flags = spec->efs_flags;
681                 saved_spec->efs_rss_context = spec->efs_rss_context;
682                 saved_spec->efs_dmaq_id = spec->efs_dmaq_id;
683         }
684
685         ef10_filter_set_entry_not_busy(eftp, ins_index);
686
687 out_unlock:
688
689         EFSYS_UNLOCK(enp->en_eslp, state);
690         locked = B_FALSE;
691
692         if (filter_id)
693                 *filter_id = ins_index;
694
695         return (0);
696
697 fail4:
698         EFSYS_PROBE(fail4);
699
700         if (!replacing) {
701                 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec);
702                 saved_spec = NULL;
703         }
704         ef10_filter_set_entry_not_busy(eftp, ins_index);
705         ef10_filter_set_entry(eftp, ins_index, NULL);
706
707 fail3:
708         EFSYS_PROBE(fail3);
709
710 fail2:
711         EFSYS_PROBE(fail2);
712
713 fail1:
714         EFSYS_PROBE1(fail1, efx_rc_t, rc);
715
716         if (locked)
717                 EFSYS_UNLOCK(enp->en_eslp, state);
718
719         return (rc);
720 }
721
722         __checkReturn   efx_rc_t
723 ef10_filter_add(
724         __in            efx_nic_t *enp,
725         __inout         efx_filter_spec_t *spec,
726         __in            boolean_t may_replace)
727 {
728         efx_rc_t rc;
729
730         rc = ef10_filter_add_internal(enp, spec, may_replace, NULL);
731         if (rc != 0)
732                 goto fail1;
733
734         return (0);
735
736 fail1:
737         EFSYS_PROBE1(fail1, efx_rc_t, rc);
738
739         return (rc);
740 }
741
742
743 static  __checkReturn   efx_rc_t
744 ef10_filter_delete_internal(
745         __in            efx_nic_t *enp,
746         __in            uint32_t filter_id)
747 {
748         efx_rc_t rc;
749         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
750         efx_filter_spec_t *spec;
751         efsys_lock_state_t state;
752         uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS;
753
754         /*
755          * Find the software table entry and mark it busy.  Don't
756          * remove it yet; any attempt to update while we're waiting
757          * for the firmware must find the busy entry.
758          *
759          * FIXME: What if the busy flag is never cleared?
760          */
761         EFSYS_LOCK(enp->en_eslp, state);
762         while (ef10_filter_entry_is_busy(table, filter_idx)) {
763                 EFSYS_UNLOCK(enp->en_eslp, state);
764                 EFSYS_SPIN(1);
765                 EFSYS_LOCK(enp->en_eslp, state);
766         }
767         if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) {
768                 ef10_filter_set_entry_busy(table, filter_idx);
769         }
770         EFSYS_UNLOCK(enp->en_eslp, state);
771
772         if (spec == NULL) {
773                 rc = ENOENT;
774                 goto fail1;
775         }
776
777         /*
778          * Try to remove the hardware filter. This may fail if the MC has
779          * rebooted (which frees all hardware filter resources).
780          */
781         if (ef10_filter_is_exclusive(spec)) {
782                 rc = efx_mcdi_filter_op_delete(enp,
783                     MC_CMD_FILTER_OP_IN_OP_REMOVE,
784                     &table->eft_entry[filter_idx].efe_handle);
785         } else {
786                 rc = efx_mcdi_filter_op_delete(enp,
787                     MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE,
788                     &table->eft_entry[filter_idx].efe_handle);
789         }
790
791         /* Free the software table entry */
792         EFSYS_LOCK(enp->en_eslp, state);
793         ef10_filter_set_entry_not_busy(table, filter_idx);
794         ef10_filter_set_entry(table, filter_idx, NULL);
795         EFSYS_UNLOCK(enp->en_eslp, state);
796
797         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
798
799         /* Check result of hardware filter removal */
800         if (rc != 0)
801                 goto fail2;
802
803         return (0);
804
805 fail2:
806         EFSYS_PROBE(fail2);
807
808 fail1:
809         EFSYS_PROBE1(fail1, efx_rc_t, rc);
810
811         return (rc);
812 }
813
814         __checkReturn   efx_rc_t
815 ef10_filter_delete(
816         __in            efx_nic_t *enp,
817         __inout         efx_filter_spec_t *spec)
818 {
819         efx_rc_t rc;
820         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
821         efx_filter_spec_t *saved_spec;
822         unsigned int hash;
823         unsigned int depth;
824         unsigned int i;
825         efsys_lock_state_t state;
826         boolean_t locked = B_FALSE;
827
828         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
829                     enp->en_family == EFX_FAMILY_MEDFORD);
830
831         hash = ef10_filter_hash(spec);
832
833         EFSYS_LOCK(enp->en_eslp, state);
834         locked = B_TRUE;
835
836         depth = 1;
837         for (;;) {
838                 i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1);
839                 saved_spec = ef10_filter_entry_spec(table, i);
840                 if (saved_spec && ef10_filter_equal(spec, saved_spec) &&
841                     ef10_filter_same_dest(spec, saved_spec)) {
842                         break;
843                 }
844                 if (depth == EF10_FILTER_SEARCH_LIMIT) {
845                         rc = ENOENT;
846                         goto fail1;
847                 }
848                 depth++;
849         }
850
851         EFSYS_UNLOCK(enp->en_eslp, state);
852         locked = B_FALSE;
853
854         rc = ef10_filter_delete_internal(enp, i);
855         if (rc != 0)
856                 goto fail2;
857
858         return (0);
859
860 fail2:
861         EFSYS_PROBE(fail2);
862
863 fail1:
864         EFSYS_PROBE1(fail1, efx_rc_t, rc);
865
866         if (locked)
867                 EFSYS_UNLOCK(enp->en_eslp, state);
868
869         return (rc);
870 }
871
872 static  __checkReturn   efx_rc_t
873 efx_mcdi_get_parser_disp_info(
874         __in                            efx_nic_t *enp,
875         __out_ecount(buffer_length)     uint32_t *buffer,
876         __in                            size_t buffer_length,
877         __out                           size_t *list_lengthp)
878 {
879         efx_mcdi_req_t req;
880         uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN,
881                             MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)];
882         size_t matches_count;
883         size_t list_size;
884         efx_rc_t rc;
885
886         (void) memset(payload, 0, sizeof (payload));
887         req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO;
888         req.emr_in_buf = payload;
889         req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN;
890         req.emr_out_buf = payload;
891         req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX;
892
893         MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP,
894             MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES);
895
896         efx_mcdi_execute(enp, &req);
897
898         if (req.emr_rc != 0) {
899                 rc = req.emr_rc;
900                 goto fail1;
901         }
902
903         matches_count = MCDI_OUT_DWORD(req,
904             GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES);
905
906         if (req.emr_out_length_used <
907             MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(matches_count)) {
908                 rc = EMSGSIZE;
909                 goto fail2;
910         }
911
912         *list_lengthp = matches_count;
913
914         if (buffer_length < matches_count) {
915                 rc = ENOSPC;
916                 goto fail3;
917         }
918
919         /*
920          * Check that the elements in the list in the MCDI response are the size
921          * we expect, so we can just copy them directly. Any conversion of the
922          * flags is handled by the caller.
923          */
924         EFX_STATIC_ASSERT(sizeof (uint32_t) ==
925             MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN);
926
927         list_size = matches_count *
928                 MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN;
929         memcpy(buffer,
930             MCDI_OUT2(req, uint32_t,
931                     GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES),
932             list_size);
933
934         return (0);
935
936 fail3:
937         EFSYS_PROBE(fail3);
938 fail2:
939         EFSYS_PROBE(fail2);
940 fail1:
941         EFSYS_PROBE1(fail1, efx_rc_t, rc);
942
943         return (rc);
944 }
945
946         __checkReturn   efx_rc_t
947 ef10_filter_supported_filters(
948         __in                            efx_nic_t *enp,
949         __out_ecount(buffer_length)     uint32_t *buffer,
950         __in                            size_t buffer_length,
951         __out                           size_t *list_lengthp)
952 {
953
954         size_t mcdi_list_length;
955         size_t list_length;
956         uint32_t i;
957         efx_rc_t rc;
958         uint32_t all_filter_flags =
959             (EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_LOC_HOST |
960             EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_REM_PORT |
961             EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT |
962             EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_INNER_VID |
963             EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_IP_PROTO |
964             EFX_FILTER_MATCH_UNKNOWN_MCAST_DST |
965             EFX_FILTER_MATCH_UNKNOWN_UCAST_DST);
966
967         rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length,
968                                             &mcdi_list_length);
969         if (rc != 0) {
970                 if (rc == ENOSPC) {
971                         /* Pass through mcdi_list_length for the list length */
972                         *list_lengthp = mcdi_list_length;
973                 }
974                 goto fail1;
975         }
976
977         /*
978          * The static assertions in ef10_filter_init() ensure that the values of
979          * the EFX_FILTER_MATCH flags match those used by MCDI, so they don't
980          * need to be converted.
981          *
982          * In case support is added to MCDI for additional flags, remove any
983          * matches from the list which include flags we don't support. The order
984          * of the matches is preserved as they are ordered from highest to
985          * lowest priority.
986          */
987         EFSYS_ASSERT(mcdi_list_length <= buffer_length);
988         list_length = 0;
989         for (i = 0; i < mcdi_list_length; i++) {
990                 if ((buffer[i] & ~all_filter_flags) == 0) {
991                         buffer[list_length] = buffer[i];
992                         list_length++;
993                 }
994         }
995
996         *list_lengthp = list_length;
997
998         return (0);
999
1000 fail1:
1001         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1002
1003         return (rc);
1004 }
1005
1006 static  __checkReturn   efx_rc_t
1007 ef10_filter_insert_unicast(
1008         __in                            efx_nic_t *enp,
1009         __in_ecount(6)                  uint8_t const *addr,
1010         __in                            efx_filter_flags_t filter_flags)
1011 {
1012         ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1013         efx_filter_spec_t spec;
1014         efx_rc_t rc;
1015
1016         /* Insert the filter for the local station address */
1017         efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1018             filter_flags,
1019             eftp->eft_default_rxq);
1020         efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, addr);
1021
1022         rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1023             &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]);
1024         if (rc != 0)
1025                 goto fail1;
1026
1027         eftp->eft_unicst_filter_count++;
1028         EFSYS_ASSERT(eftp->eft_unicst_filter_count <=
1029                     EFX_EF10_FILTER_UNICAST_FILTERS_MAX);
1030
1031         return (0);
1032
1033 fail1:
1034         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1035         return (rc);
1036 }
1037
1038 static  __checkReturn   efx_rc_t
1039 ef10_filter_insert_all_unicast(
1040         __in                            efx_nic_t *enp,
1041         __in                            efx_filter_flags_t filter_flags)
1042 {
1043         ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1044         efx_filter_spec_t spec;
1045         efx_rc_t rc;
1046
1047         /* Insert the unknown unicast filter */
1048         efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1049             filter_flags,
1050             eftp->eft_default_rxq);
1051         efx_filter_spec_set_uc_def(&spec);
1052         rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1053             &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]);
1054         if (rc != 0)
1055                 goto fail1;
1056
1057         eftp->eft_unicst_filter_count++;
1058         EFSYS_ASSERT(eftp->eft_unicst_filter_count <=
1059                     EFX_EF10_FILTER_UNICAST_FILTERS_MAX);
1060
1061         return (0);
1062
1063 fail1:
1064         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1065         return (rc);
1066 }
1067
1068 static  __checkReturn   efx_rc_t
1069 ef10_filter_insert_multicast_list(
1070         __in                            efx_nic_t *enp,
1071         __in                            boolean_t mulcst,
1072         __in                            boolean_t brdcst,
1073         __in_ecount(6*count)            uint8_t const *addrs,
1074         __in                            uint32_t count,
1075         __in                            efx_filter_flags_t filter_flags,
1076         __in                            boolean_t rollback)
1077 {
1078         ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1079         efx_filter_spec_t spec;
1080         uint8_t addr[6];
1081         uint32_t i;
1082         uint32_t filter_index;
1083         uint32_t filter_count;
1084         efx_rc_t rc;
1085
1086         if (mulcst == B_FALSE)
1087                 count = 0;
1088
1089         if (count + (brdcst ? 1 : 0) >
1090             EFX_ARRAY_SIZE(eftp->eft_mulcst_filter_indexes)) {
1091                 /* Too many MAC addresses */
1092                 rc = EINVAL;
1093                 goto fail1;
1094         }
1095
1096         /* Insert/renew multicast address list filters */
1097         filter_count = 0;
1098         for (i = 0; i < count; i++) {
1099                 efx_filter_spec_init_rx(&spec,
1100                     EFX_FILTER_PRI_AUTO,
1101                     filter_flags,
1102                     eftp->eft_default_rxq);
1103
1104                 efx_filter_spec_set_eth_local(&spec,
1105                     EFX_FILTER_SPEC_VID_UNSPEC,
1106                     &addrs[i * EFX_MAC_ADDR_LEN]);
1107
1108                 rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1109                                             &filter_index);
1110
1111                 if (rc == 0) {
1112                         eftp->eft_mulcst_filter_indexes[filter_count] =
1113                                 filter_index;
1114                         filter_count++;
1115                 } else if (rollback == B_TRUE) {
1116                         /* Only stop upon failure if told to rollback */
1117                         goto rollback;
1118                 }
1119
1120         }
1121
1122         if (brdcst == B_TRUE) {
1123                 /* Insert/renew broadcast address filter */
1124                 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1125                     filter_flags,
1126                     eftp->eft_default_rxq);
1127
1128                 EFX_MAC_BROADCAST_ADDR_SET(addr);
1129                 efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC,
1130                     addr);
1131
1132                 rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1133                                             &filter_index);
1134
1135                 if (rc == 0) {
1136                         eftp->eft_mulcst_filter_indexes[filter_count] =
1137                                 filter_index;
1138                         filter_count++;
1139                 } else if (rollback == B_TRUE) {
1140                         /* Only stop upon failure if told to rollback */
1141                         goto rollback;
1142                 }
1143         }
1144
1145         eftp->eft_mulcst_filter_count = filter_count;
1146         eftp->eft_using_all_mulcst = B_FALSE;
1147
1148         return (0);
1149
1150 rollback:
1151         /* Remove any filters we have inserted */
1152         i = filter_count;
1153         while (i--) {
1154                 (void) ef10_filter_delete_internal(enp,
1155                     eftp->eft_mulcst_filter_indexes[i]);
1156         }
1157         eftp->eft_mulcst_filter_count = 0;
1158
1159 fail1:
1160         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1161
1162         return (rc);
1163 }
1164
1165 static  __checkReturn   efx_rc_t
1166 ef10_filter_insert_all_multicast(
1167         __in                            efx_nic_t *enp,
1168         __in                            efx_filter_flags_t filter_flags)
1169 {
1170         ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1171         efx_filter_spec_t spec;
1172         efx_rc_t rc;
1173
1174         /* Insert the unknown multicast filter */
1175         efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1176             filter_flags,
1177             eftp->eft_default_rxq);
1178         efx_filter_spec_set_mc_def(&spec);
1179
1180         rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1181             &eftp->eft_mulcst_filter_indexes[0]);
1182         if (rc != 0)
1183                 goto fail1;
1184
1185         eftp->eft_mulcst_filter_count = 1;
1186         eftp->eft_using_all_mulcst = B_TRUE;
1187
1188         /*
1189          * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic.
1190          */
1191
1192         return (0);
1193
1194 fail1:
1195         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1196
1197         return (rc);
1198 }
1199
1200 static                  void
1201 ef10_filter_remove_old(
1202         __in            efx_nic_t *enp)
1203 {
1204         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1205         uint32_t i;
1206
1207         for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) {
1208                 if (ef10_filter_entry_is_auto_old(table, i)) {
1209                         (void) ef10_filter_delete_internal(enp, i);
1210                 }
1211         }
1212 }
1213
1214
1215 static  __checkReturn   efx_rc_t
1216 ef10_filter_get_workarounds(
1217         __in                            efx_nic_t *enp)
1218 {
1219         efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1220         uint32_t implemented = 0;
1221         uint32_t enabled = 0;
1222         efx_rc_t rc;
1223
1224         rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled);
1225         if (rc == 0) {
1226                 /* Check if chained multicast filter support is enabled */
1227                 if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807)
1228                         encp->enc_bug26807_workaround = B_TRUE;
1229                 else
1230                         encp->enc_bug26807_workaround = B_FALSE;
1231         } else if (rc == ENOTSUP) {
1232                 /*
1233                  * Firmware is too old to support GET_WORKAROUNDS, and support
1234                  * for this workaround was implemented later.
1235                  */
1236                 encp->enc_bug26807_workaround = B_FALSE;
1237         } else {
1238                 goto fail1;
1239         }
1240
1241         return (0);
1242
1243 fail1:
1244         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1245
1246         return (rc);
1247
1248 }
1249
1250
1251 /*
1252  * Reconfigure all filters.
1253  * If all_unicst and/or all mulcst filters cannot be applied then
1254  * return ENOTSUP (Note the filters for the specified addresses are
1255  * still applied in this case).
1256  */
1257         __checkReturn   efx_rc_t
1258 ef10_filter_reconfigure(
1259         __in                            efx_nic_t *enp,
1260         __in_ecount(6)                  uint8_t const *mac_addr,
1261         __in                            boolean_t all_unicst,
1262         __in                            boolean_t mulcst,
1263         __in                            boolean_t all_mulcst,
1264         __in                            boolean_t brdcst,
1265         __in_ecount(6*count)            uint8_t const *addrs,
1266         __in                            uint32_t count)
1267 {
1268         efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1269         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1270         efx_filter_flags_t filter_flags;
1271         unsigned int i;
1272         efx_rc_t all_unicst_rc = 0;
1273         efx_rc_t all_mulcst_rc = 0;
1274         efx_rc_t rc;
1275
1276         if (table->eft_default_rxq == NULL) {
1277                 /*
1278                  * Filters direct traffic to the default RXQ, and so cannot be
1279                  * inserted until it is available. Any currently configured
1280                  * filters must be removed (ignore errors in case the MC
1281                  * has rebooted, which removes hardware filters).
1282                  */
1283                 for (i = 0; i < table->eft_unicst_filter_count; i++) {
1284                         (void) ef10_filter_delete_internal(enp,
1285                                         table->eft_unicst_filter_indexes[i]);
1286                 }
1287                 table->eft_unicst_filter_count = 0;
1288
1289                 for (i = 0; i < table->eft_mulcst_filter_count; i++) {
1290                         (void) ef10_filter_delete_internal(enp,
1291                                         table->eft_mulcst_filter_indexes[i]);
1292                 }
1293                 table->eft_mulcst_filter_count = 0;
1294
1295                 return (0);
1296         }
1297
1298         if (table->eft_using_rss)
1299                 filter_flags = EFX_FILTER_FLAG_RX_RSS;
1300         else
1301                 filter_flags = 0;
1302
1303         /* Mark old filters which may need to be removed */
1304         for (i = 0; i < table->eft_unicst_filter_count; i++) {
1305                 ef10_filter_set_entry_auto_old(table,
1306                                         table->eft_unicst_filter_indexes[i]);
1307         }
1308         for (i = 0; i < table->eft_mulcst_filter_count; i++) {
1309                 ef10_filter_set_entry_auto_old(table,
1310                                         table->eft_mulcst_filter_indexes[i]);
1311         }
1312
1313         /*
1314          * Insert or renew unicast filters.
1315          *
1316          * Frimware does not perform chaining on unicast filters. As traffic is
1317          * therefore only delivered to the first matching filter, we should
1318          * always insert the specific filter for our MAC address, to try and
1319          * ensure we get that traffic.
1320          *
1321          * (If the filter for our MAC address has already been inserted by
1322          * another function, we won't receive traffic sent to us, even if we
1323          * insert a unicast mismatch filter. To prevent traffic stealing, this
1324          * therefore relies on the privilege model only allowing functions to
1325          * insert filters for their own MAC address unless explicitly given
1326          * additional privileges by the user. This also means that, even on a
1327          * priviliged function, inserting a unicast mismatch filter may not
1328          * catch all traffic in multi PCI function scenarios.)
1329          */
1330         table->eft_unicst_filter_count = 0;
1331         rc = ef10_filter_insert_unicast(enp, mac_addr, filter_flags);
1332         if (all_unicst || (rc != 0)) {
1333                 all_unicst_rc = ef10_filter_insert_all_unicast(enp,
1334                                                     filter_flags);
1335                 if ((rc != 0) && (all_unicst_rc != 0))
1336                         goto fail1;
1337         }
1338
1339         /*
1340          * WORKAROUND_BUG26807 controls firmware support for chained multicast
1341          * filters, and can only be enabled or disabled when the hardware filter
1342          * table is empty.
1343          *
1344          * Chained multicast filters require support from the datapath firmware,
1345          * and may not be available (e.g. low-latency variants or old Huntington
1346          * firmware).
1347          *
1348          * Firmware will reset (FLR) functions which have inserted filters in
1349          * the hardware filter table when the workaround is enabled/disabled.
1350          * Functions without any hardware filters are not reset.
1351          *
1352          * Re-check if the workaround is enabled after adding unicast hardware
1353          * filters. This ensures that encp->enc_bug26807_workaround matches the
1354          * firmware state, and that later changes to enable/disable the
1355          * workaround will result in this function seeing a reset (FLR).
1356          *
1357          * In common-code drivers, we only support multiple PCI function
1358          * scenarios with firmware that supports multicast chaining, so we can
1359          * assume it is enabled for such cases and hence simplify the filter
1360          * insertion logic. Firmware that does not support multicast chaining
1361          * does not support multiple PCI function configurations either, so
1362          * filter insertion is much simpler and the same strategies can still be
1363          * used.
1364          */
1365         if ((rc = ef10_filter_get_workarounds(enp)) != 0)
1366                 goto fail2;
1367
1368         if ((table->eft_using_all_mulcst != all_mulcst) &&
1369             (encp->enc_bug26807_workaround == B_TRUE)) {
1370                 /*
1371                  * Multicast filter chaining is enabled, so traffic that matches
1372                  * more than one multicast filter will be replicated and
1373                  * delivered to multiple recipients.  To avoid this duplicate
1374                  * delivery, remove old multicast filters before inserting new
1375                  * multicast filters.
1376                  */
1377                 ef10_filter_remove_old(enp);
1378         }
1379
1380         /* Insert or renew multicast filters */
1381         if (all_mulcst == B_TRUE) {
1382                 /*
1383                  * Insert the all multicast filter. If that fails, try to insert
1384                  * all of our multicast filters (but without rollback on
1385                  * failure).
1386                  */
1387                 all_mulcst_rc = ef10_filter_insert_all_multicast(enp,
1388                                                             filter_flags);
1389                 if (all_mulcst_rc != 0) {
1390                         rc = ef10_filter_insert_multicast_list(enp, B_TRUE,
1391                             brdcst, addrs, count, filter_flags, B_FALSE);
1392                         if (rc != 0)
1393                                 goto fail3;
1394                 }
1395         } else {
1396                 /*
1397                  * Insert filters for multicast addresses.
1398                  * If any insertion fails, then rollback and try to insert the
1399                  * all multicast filter instead.
1400                  * If that also fails, try to insert all of the multicast
1401                  * filters (but without rollback on failure).
1402                  */
1403                 rc = ef10_filter_insert_multicast_list(enp, mulcst, brdcst,
1404                             addrs, count, filter_flags, B_TRUE);
1405                 if (rc != 0) {
1406                         if ((table->eft_using_all_mulcst == B_FALSE) &&
1407                             (encp->enc_bug26807_workaround == B_TRUE)) {
1408                                 /*
1409                                  * Multicast filter chaining is on, so remove
1410                                  * old filters before inserting the multicast
1411                                  * all filter to avoid duplicate delivery caused
1412                                  * by packets matching multiple filters.
1413                                  */
1414                                 ef10_filter_remove_old(enp);
1415                         }
1416
1417                         rc = ef10_filter_insert_all_multicast(enp,
1418                                                             filter_flags);
1419                         if (rc != 0) {
1420                                 rc = ef10_filter_insert_multicast_list(enp,
1421                                     mulcst, brdcst,
1422                                     addrs, count, filter_flags, B_FALSE);
1423                                 if (rc != 0)
1424                                         goto fail4;
1425                         }
1426                 }
1427         }
1428
1429         /* Remove old filters which were not renewed */
1430         ef10_filter_remove_old(enp);
1431
1432         /* report if any optional flags were rejected */
1433         if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) ||
1434             ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) {
1435                 rc = ENOTSUP;
1436         }
1437
1438         return (rc);
1439
1440 fail4:
1441         EFSYS_PROBE(fail4);
1442 fail3:
1443         EFSYS_PROBE(fail3);
1444 fail2:
1445         EFSYS_PROBE(fail2);
1446 fail1:
1447         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1448
1449         /* Clear auto old flags */
1450         for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) {
1451                 if (ef10_filter_entry_is_auto_old(table, i)) {
1452                         ef10_filter_set_entry_not_auto_old(table, i);
1453                 }
1454         }
1455
1456         return (rc);
1457 }
1458
1459                 void
1460 ef10_filter_get_default_rxq(
1461         __in            efx_nic_t *enp,
1462         __out           efx_rxq_t **erpp,
1463         __out           boolean_t *using_rss)
1464 {
1465         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1466
1467         *erpp = table->eft_default_rxq;
1468         *using_rss = table->eft_using_rss;
1469 }
1470
1471
1472                 void
1473 ef10_filter_default_rxq_set(
1474         __in            efx_nic_t *enp,
1475         __in            efx_rxq_t *erp,
1476         __in            boolean_t using_rss)
1477 {
1478         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1479
1480 #if EFSYS_OPT_RX_SCALE
1481         EFSYS_ASSERT((using_rss == B_FALSE) ||
1482             (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID));
1483         table->eft_using_rss = using_rss;
1484 #else
1485         EFSYS_ASSERT(using_rss == B_FALSE);
1486         table->eft_using_rss = B_FALSE;
1487 #endif
1488         table->eft_default_rxq = erp;
1489 }
1490
1491                 void
1492 ef10_filter_default_rxq_clear(
1493         __in            efx_nic_t *enp)
1494 {
1495         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1496
1497         table->eft_default_rxq = NULL;
1498         table->eft_using_rss = B_FALSE;
1499 }
1500
1501
1502 #endif /* EFSYS_OPT_FILTER */
1503
1504 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */