]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/sfxge/common/ef10_filter.c
MFC r310755
[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 #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_quiet(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_insert_unicast(
986         __in                            efx_nic_t *enp,
987         __in_ecount(6)                  uint8_t const *addr,
988         __in                            efx_filter_flags_t filter_flags)
989 {
990         ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
991         efx_filter_spec_t spec;
992         efx_rc_t rc;
993
994         /* Insert the filter for the local station address */
995         efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
996             filter_flags,
997             eftp->eft_default_rxq);
998         efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, addr);
999
1000         rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1001             &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]);
1002         if (rc != 0)
1003                 goto fail1;
1004
1005         eftp->eft_unicst_filter_count++;
1006         EFSYS_ASSERT(eftp->eft_unicst_filter_count <=
1007                     EFX_EF10_FILTER_UNICAST_FILTERS_MAX);
1008
1009         return (0);
1010
1011 fail1:
1012         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1013         return (rc);
1014 }
1015
1016 static  __checkReturn   efx_rc_t
1017 ef10_filter_insert_all_unicast(
1018         __in                            efx_nic_t *enp,
1019         __in                            efx_filter_flags_t filter_flags)
1020 {
1021         ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1022         efx_filter_spec_t spec;
1023         efx_rc_t rc;
1024
1025         /* Insert the unknown unicast filter */
1026         efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1027             filter_flags,
1028             eftp->eft_default_rxq);
1029         efx_filter_spec_set_uc_def(&spec);
1030         rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1031             &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]);
1032         if (rc != 0)
1033                 goto fail1;
1034
1035         eftp->eft_unicst_filter_count++;
1036         EFSYS_ASSERT(eftp->eft_unicst_filter_count <=
1037                     EFX_EF10_FILTER_UNICAST_FILTERS_MAX);
1038
1039         return (0);
1040
1041 fail1:
1042         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1043         return (rc);
1044 }
1045
1046 static  __checkReturn   efx_rc_t
1047 ef10_filter_insert_multicast_list(
1048         __in                            efx_nic_t *enp,
1049         __in                            boolean_t mulcst,
1050         __in                            boolean_t brdcst,
1051         __in_ecount(6*count)            uint8_t const *addrs,
1052         __in                            uint32_t count,
1053         __in                            efx_filter_flags_t filter_flags,
1054         __in                            boolean_t rollback)
1055 {
1056         ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1057         efx_filter_spec_t spec;
1058         uint8_t addr[6];
1059         uint32_t i;
1060         uint32_t filter_index;
1061         uint32_t filter_count;
1062         efx_rc_t rc;
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 */
1070                 rc = EINVAL;
1071                 goto fail1;
1072         }
1073
1074         /* Insert/renew multicast address list filters */
1075         filter_count = 0;
1076         for (i = 0; i < count; i++) {
1077                 efx_filter_spec_init_rx(&spec,
1078                     EFX_FILTER_PRI_AUTO,
1079                     filter_flags,
1080                     eftp->eft_default_rxq);
1081
1082                 efx_filter_spec_set_eth_local(&spec,
1083                     EFX_FILTER_SPEC_VID_UNSPEC,
1084                     &addrs[i * EFX_MAC_ADDR_LEN]);
1085
1086                 rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1087                                             &filter_index);
1088
1089                 if (rc == 0) {
1090                         eftp->eft_mulcst_filter_indexes[filter_count] =
1091                                 filter_index;
1092                         filter_count++;
1093                 } else if (rollback == B_TRUE) {
1094                         /* Only stop upon failure if told to rollback */
1095                         goto rollback;
1096                 }
1097
1098         }
1099
1100         if (brdcst == B_TRUE) {
1101                 /* Insert/renew broadcast address filter */
1102                 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1103                     filter_flags,
1104                     eftp->eft_default_rxq);
1105
1106                 EFX_MAC_BROADCAST_ADDR_SET(addr);
1107                 efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC,
1108                     addr);
1109
1110                 rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1111                                             &filter_index);
1112
1113                 if (rc == 0) {
1114                         eftp->eft_mulcst_filter_indexes[filter_count] =
1115                                 filter_index;
1116                         filter_count++;
1117                 } else if (rollback == B_TRUE) {
1118                         /* Only stop upon failure if told to rollback */
1119                         goto rollback;
1120                 }
1121         }
1122
1123         eftp->eft_mulcst_filter_count = filter_count;
1124         eftp->eft_using_all_mulcst = B_FALSE;
1125
1126         return (0);
1127
1128 rollback:
1129         /* Remove any filters we have inserted */
1130         i = filter_count;
1131         while (i--) {
1132                 (void) ef10_filter_delete_internal(enp,
1133                     eftp->eft_mulcst_filter_indexes[i]);
1134         }
1135         eftp->eft_mulcst_filter_count = 0;
1136
1137 fail1:
1138         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1139
1140         return (rc);
1141 }
1142
1143 static  __checkReturn   efx_rc_t
1144 ef10_filter_insert_all_multicast(
1145         __in                            efx_nic_t *enp,
1146         __in                            efx_filter_flags_t filter_flags)
1147 {
1148         ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1149         efx_filter_spec_t spec;
1150         efx_rc_t rc;
1151
1152         /* Insert the unknown multicast filter */
1153         efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1154             filter_flags,
1155             eftp->eft_default_rxq);
1156         efx_filter_spec_set_mc_def(&spec);
1157
1158         rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1159             &eftp->eft_mulcst_filter_indexes[0]);
1160         if (rc != 0)
1161                 goto fail1;
1162
1163         eftp->eft_mulcst_filter_count = 1;
1164         eftp->eft_using_all_mulcst = B_TRUE;
1165
1166         /*
1167          * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic.
1168          */
1169
1170         return (0);
1171
1172 fail1:
1173         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1174
1175         return (rc);
1176 }
1177
1178 static                  void
1179 ef10_filter_remove_old(
1180         __in            efx_nic_t *enp)
1181 {
1182         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1183         uint32_t i;
1184
1185         for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) {
1186                 if (ef10_filter_entry_is_auto_old(table, i)) {
1187                         (void) ef10_filter_delete_internal(enp, i);
1188                 }
1189         }
1190 }
1191
1192
1193 static  __checkReturn   efx_rc_t
1194 ef10_filter_get_workarounds(
1195         __in                            efx_nic_t *enp)
1196 {
1197         efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1198         uint32_t implemented = 0;
1199         uint32_t enabled = 0;
1200         efx_rc_t rc;
1201
1202         rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled);
1203         if (rc == 0) {
1204                 /* Check if chained multicast filter support is enabled */
1205                 if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807)
1206                         encp->enc_bug26807_workaround = B_TRUE;
1207                 else
1208                         encp->enc_bug26807_workaround = B_FALSE;
1209         } else if (rc == ENOTSUP) {
1210                 /*
1211                  * Firmware is too old to support GET_WORKAROUNDS, and support
1212                  * for this workaround was implemented later.
1213                  */
1214                 encp->enc_bug26807_workaround = B_FALSE;
1215         } else {
1216                 goto fail1;
1217         }
1218
1219         return (0);
1220
1221 fail1:
1222         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1223
1224         return (rc);
1225
1226 }
1227
1228
1229 /*
1230  * Reconfigure all filters.
1231  * If all_unicst and/or all mulcst filters cannot be applied then
1232  * return ENOTSUP (Note the filters for the specified addresses are
1233  * still applied in this case).
1234  */
1235         __checkReturn   efx_rc_t
1236 ef10_filter_reconfigure(
1237         __in                            efx_nic_t *enp,
1238         __in_ecount(6)                  uint8_t const *mac_addr,
1239         __in                            boolean_t all_unicst,
1240         __in                            boolean_t mulcst,
1241         __in                            boolean_t all_mulcst,
1242         __in                            boolean_t brdcst,
1243         __in_ecount(6*count)            uint8_t const *addrs,
1244         __in                            uint32_t count)
1245 {
1246         efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1247         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1248         efx_filter_flags_t filter_flags;
1249         unsigned int i;
1250         efx_rc_t all_unicst_rc = 0;
1251         efx_rc_t all_mulcst_rc = 0;
1252         efx_rc_t rc;
1253
1254         if (table->eft_default_rxq == NULL) {
1255                 /*
1256                  * Filters direct traffic to the default RXQ, and so cannot be
1257                  * inserted until it is available. Any currently configured
1258                  * filters must be removed (ignore errors in case the MC
1259                  * has rebooted, which removes hardware filters).
1260                  */
1261                 for (i = 0; i < table->eft_unicst_filter_count; i++) {
1262                         (void) ef10_filter_delete_internal(enp,
1263                                         table->eft_unicst_filter_indexes[i]);
1264                 }
1265                 table->eft_unicst_filter_count = 0;
1266
1267                 for (i = 0; i < table->eft_mulcst_filter_count; i++) {
1268                         (void) ef10_filter_delete_internal(enp,
1269                                         table->eft_mulcst_filter_indexes[i]);
1270                 }
1271                 table->eft_mulcst_filter_count = 0;
1272
1273                 return (0);
1274         }
1275
1276         if (table->eft_using_rss)
1277                 filter_flags = EFX_FILTER_FLAG_RX_RSS;
1278         else
1279                 filter_flags = 0;
1280
1281         /* Mark old filters which may need to be removed */
1282         for (i = 0; i < table->eft_unicst_filter_count; i++) {
1283                 ef10_filter_set_entry_auto_old(table,
1284                                         table->eft_unicst_filter_indexes[i]);
1285         }
1286         for (i = 0; i < table->eft_mulcst_filter_count; i++) {
1287                 ef10_filter_set_entry_auto_old(table,
1288                                         table->eft_mulcst_filter_indexes[i]);
1289         }
1290
1291         /*
1292          * Insert or renew unicast filters.
1293          *
1294          * Frimware does not perform chaining on unicast filters. As traffic is
1295          * therefore only delivered to the first matching filter, we should
1296          * always insert the specific filter for our MAC address, to try and
1297          * ensure we get that traffic.
1298          *
1299          * (If the filter for our MAC address has already been inserted by
1300          * another function, we won't receive traffic sent to us, even if we
1301          * insert a unicast mismatch filter. To prevent traffic stealing, this
1302          * therefore relies on the privilege model only allowing functions to
1303          * insert filters for their own MAC address unless explicitly given
1304          * additional privileges by the user. This also means that, even on a
1305          * priviliged function, inserting a unicast mismatch filter may not
1306          * catch all traffic in multi PCI function scenarios.)
1307          */
1308         table->eft_unicst_filter_count = 0;
1309         rc = ef10_filter_insert_unicast(enp, mac_addr, filter_flags);
1310         if (all_unicst || (rc != 0)) {
1311                 all_unicst_rc = ef10_filter_insert_all_unicast(enp,
1312                                                     filter_flags);
1313                 if ((rc != 0) && (all_unicst_rc != 0))
1314                         goto fail1;
1315         }
1316
1317         /*
1318          * WORKAROUND_BUG26807 controls firmware support for chained multicast
1319          * filters, and can only be enabled or disabled when the hardware filter
1320          * table is empty.
1321          *
1322          * Chained multicast filters require support from the datapath firmware,
1323          * and may not be available (e.g. low-latency variants or old Huntington
1324          * firmware).
1325          *
1326          * Firmware will reset (FLR) functions which have inserted filters in
1327          * the hardware filter table when the workaround is enabled/disabled.
1328          * Functions without any hardware filters are not reset.
1329          *
1330          * Re-check if the workaround is enabled after adding unicast hardware
1331          * filters. This ensures that encp->enc_bug26807_workaround matches the
1332          * firmware state, and that later changes to enable/disable the
1333          * workaround will result in this function seeing a reset (FLR).
1334          *
1335          * In common-code drivers, we only support multiple PCI function
1336          * scenarios with firmware that supports multicast chaining, so we can
1337          * assume it is enabled for such cases and hence simplify the filter
1338          * insertion logic. Firmware that does not support multicast chaining
1339          * does not support multiple PCI function configurations either, so
1340          * filter insertion is much simpler and the same strategies can still be
1341          * used.
1342          */
1343         if ((rc = ef10_filter_get_workarounds(enp)) != 0)
1344                 goto fail2;
1345
1346         if ((table->eft_using_all_mulcst != all_mulcst) &&
1347             (encp->enc_bug26807_workaround == B_TRUE)) {
1348                 /*
1349                  * Multicast filter chaining is enabled, so traffic that matches
1350                  * more than one multicast filter will be replicated and
1351                  * delivered to multiple recipients.  To avoid this duplicate
1352                  * delivery, remove old multicast filters before inserting new
1353                  * multicast filters.
1354                  */
1355                 ef10_filter_remove_old(enp);
1356         }
1357
1358         /* Insert or renew multicast filters */
1359         if (all_mulcst == B_TRUE) {
1360                 /*
1361                  * Insert the all multicast filter. If that fails, try to insert
1362                  * all of our multicast filters (but without rollback on
1363                  * failure).
1364                  */
1365                 all_mulcst_rc = ef10_filter_insert_all_multicast(enp,
1366                                                             filter_flags);
1367                 if (all_mulcst_rc != 0) {
1368                         rc = ef10_filter_insert_multicast_list(enp, B_TRUE,
1369                             brdcst, addrs, count, filter_flags, B_FALSE);
1370                         if (rc != 0)
1371                                 goto fail3;
1372                 }
1373         } else {
1374                 /*
1375                  * Insert filters for multicast addresses.
1376                  * If any insertion fails, then rollback and try to insert the
1377                  * all multicast filter instead.
1378                  * If that also fails, try to insert all of the multicast
1379                  * filters (but without rollback on failure).
1380                  */
1381                 rc = ef10_filter_insert_multicast_list(enp, mulcst, brdcst,
1382                             addrs, count, filter_flags, B_TRUE);
1383                 if (rc != 0) {
1384                         if ((table->eft_using_all_mulcst == B_FALSE) &&
1385                             (encp->enc_bug26807_workaround == B_TRUE)) {
1386                                 /*
1387                                  * Multicast filter chaining is on, so remove
1388                                  * old filters before inserting the multicast
1389                                  * all filter to avoid duplicate delivery caused
1390                                  * by packets matching multiple filters.
1391                                  */
1392                                 ef10_filter_remove_old(enp);
1393                         }
1394
1395                         rc = ef10_filter_insert_all_multicast(enp,
1396                                                             filter_flags);
1397                         if (rc != 0) {
1398                                 rc = ef10_filter_insert_multicast_list(enp,
1399                                     mulcst, brdcst,
1400                                     addrs, count, filter_flags, B_FALSE);
1401                                 if (rc != 0)
1402                                         goto fail4;
1403                         }
1404                 }
1405         }
1406
1407         /* Remove old filters which were not renewed */
1408         ef10_filter_remove_old(enp);
1409
1410         /* report if any optional flags were rejected */
1411         if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) ||
1412             ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) {
1413                 rc = ENOTSUP;
1414         }
1415
1416         return (rc);
1417
1418 fail4:
1419         EFSYS_PROBE(fail4);
1420 fail3:
1421         EFSYS_PROBE(fail3);
1422 fail2:
1423         EFSYS_PROBE(fail2);
1424 fail1:
1425         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1426
1427         /* Clear auto old flags */
1428         for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) {
1429                 if (ef10_filter_entry_is_auto_old(table, i)) {
1430                         ef10_filter_set_entry_not_auto_old(table, i);
1431                 }
1432         }
1433
1434         return (rc);
1435 }
1436
1437                 void
1438 ef10_filter_get_default_rxq(
1439         __in            efx_nic_t *enp,
1440         __out           efx_rxq_t **erpp,
1441         __out           boolean_t *using_rss)
1442 {
1443         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1444
1445         *erpp = table->eft_default_rxq;
1446         *using_rss = table->eft_using_rss;
1447 }
1448
1449
1450                 void
1451 ef10_filter_default_rxq_set(
1452         __in            efx_nic_t *enp,
1453         __in            efx_rxq_t *erp,
1454         __in            boolean_t using_rss)
1455 {
1456         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1457
1458 #if EFSYS_OPT_RX_SCALE
1459         EFSYS_ASSERT((using_rss == B_FALSE) ||
1460             (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID));
1461         table->eft_using_rss = using_rss;
1462 #else
1463         EFSYS_ASSERT(using_rss == B_FALSE);
1464         table->eft_using_rss = B_FALSE;
1465 #endif
1466         table->eft_default_rxq = erp;
1467 }
1468
1469                 void
1470 ef10_filter_default_rxq_clear(
1471         __in            efx_nic_t *enp)
1472 {
1473         ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1474
1475         table->eft_default_rxq = NULL;
1476         table->eft_using_rss = B_FALSE;
1477 }
1478
1479
1480 #endif /* EFSYS_OPT_FILTER */
1481
1482 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */