Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : *
3 : : * Copyright(c) 2019-2021 Xilinx, Inc.
4 : : * Copyright(c) 2007-2019 Solarflare Communications Inc.
5 : : */
6 : :
7 : : #include "efx.h"
8 : : #include "efx_impl.h"
9 : :
10 : : #if EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10()
11 : :
12 : : #if EFSYS_OPT_FILTER
13 : :
14 : : #define EFE_SPEC(eftp, index) ((eftp)->eft_entry[(index)].efe_spec)
15 : :
16 : : static efx_filter_spec_t *
17 : : ef10_filter_entry_spec(
18 : : __in const ef10_filter_table_t *eftp,
19 : : __in unsigned int index)
20 : : {
21 : 0 : return ((efx_filter_spec_t *)(EFE_SPEC(eftp, index) &
22 : : ~(uintptr_t)EFX_EF10_FILTER_FLAGS));
23 : : }
24 : :
25 : : static boolean_t
26 : : ef10_filter_entry_is_busy(
27 : : __in const ef10_filter_table_t *eftp,
28 : : __in unsigned int index)
29 : : {
30 [ # # # # : 0 : if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_BUSY)
# # ]
31 : : return (B_TRUE);
32 : : else
33 : : return (B_FALSE);
34 : : }
35 : :
36 : : static boolean_t
37 : : ef10_filter_entry_is_auto_old(
38 : : __in const ef10_filter_table_t *eftp,
39 : : __in unsigned int index)
40 : : {
41 [ # # # # ]: 0 : if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_AUTO_OLD)
42 : : return (B_TRUE);
43 : : else
44 : : return (B_FALSE);
45 : : }
46 : :
47 : : static void
48 : : ef10_filter_set_entry(
49 : : __inout ef10_filter_table_t *eftp,
50 : : __in unsigned int index,
51 : : __in_opt const efx_filter_spec_t *efsp)
52 : : {
53 : 0 : EFE_SPEC(eftp, index) = (uintptr_t)efsp;
54 : 0 : }
55 : :
56 : : static void
57 : : ef10_filter_set_entry_busy(
58 : : __inout ef10_filter_table_t *eftp,
59 : : __in unsigned int index)
60 : : {
61 : 0 : EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_BUSY;
62 : 0 : }
63 : :
64 : : static void
65 : : ef10_filter_set_entry_not_busy(
66 : : __inout ef10_filter_table_t *eftp,
67 : : __in unsigned int index)
68 : : {
69 : 0 : EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_BUSY;
70 : : }
71 : :
72 : : static void
73 : 0 : ef10_filter_set_entry_auto_old(
74 : : __inout ef10_filter_table_t *eftp,
75 : : __in unsigned int index)
76 : : {
77 [ # # ]: 0 : EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL);
78 : 0 : EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD;
79 : 0 : }
80 : :
81 : : static void
82 : 0 : ef10_filter_set_entry_not_auto_old(
83 : : __inout ef10_filter_table_t *eftp,
84 : : __in unsigned int index)
85 : : {
86 : 0 : EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD;
87 [ # # ]: 0 : EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL);
88 : 0 : }
89 : :
90 : : __checkReturn efx_rc_t
91 : 0 : ef10_filter_init(
92 : : __in efx_nic_t *enp)
93 : : {
94 : : efx_rc_t rc;
95 : : ef10_filter_table_t *eftp;
96 : :
97 [ # # ]: 0 : EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
98 : :
99 : : #define MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match))
100 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST ==
101 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_IP));
102 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST ==
103 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_IP));
104 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC ==
105 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_MAC));
106 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT ==
107 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_PORT));
108 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC ==
109 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_MAC));
110 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT ==
111 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_PORT));
112 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE ==
113 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_ETHER_TYPE));
114 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID ==
115 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_INNER_VLAN));
116 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID ==
117 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN));
118 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO ==
119 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO));
120 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_VNI_OR_VSID ==
121 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_VNI_OR_VSID));
122 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_LOC_MAC ==
123 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_MAC));
124 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST ==
125 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST));
126 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST ==
127 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST));
128 : : EFX_STATIC_ASSERT(EFX_FILTER_MATCH_UNKNOWN_MCAST_DST ==
129 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST));
130 : : EFX_STATIC_ASSERT((uint32_t)EFX_FILTER_MATCH_UNKNOWN_UCAST_DST ==
131 : : MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_UCAST_DST));
132 : : #undef MATCH_MASK
133 : :
134 : 0 : EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp);
135 : :
136 [ # # ]: 0 : if (!eftp) {
137 : : rc = ENOMEM;
138 : 0 : goto fail1;
139 : : }
140 : :
141 : 0 : enp->en_filter.ef_ef10_filter_table = eftp;
142 : :
143 : 0 : return (0);
144 : :
145 : : fail1:
146 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
147 : :
148 : 0 : return (rc);
149 : : }
150 : :
151 : : void
152 : 0 : ef10_filter_fini(
153 : : __in efx_nic_t *enp)
154 : : {
155 [ # # ]: 0 : EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
156 : :
157 [ # # ]: 0 : if (enp->en_filter.ef_ef10_filter_table != NULL) {
158 : 0 : EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t),
159 : : enp->en_filter.ef_ef10_filter_table);
160 : : }
161 : 0 : }
162 : :
163 : : static __checkReturn efx_rc_t
164 : 0 : efx_mcdi_filter_op_add(
165 : : __in efx_nic_t *enp,
166 : : __in efx_filter_spec_t *spec,
167 : : __in unsigned int filter_op,
168 : : __inout ef10_filter_handle_t *handle)
169 : : {
170 : : efx_mcdi_req_t req;
171 : 0 : EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FILTER_OP_V3_IN_LEN,
172 : : MC_CMD_FILTER_OP_EXT_OUT_LEN);
173 : : efx_filter_match_flags_t match_flags;
174 : : efx_port_t *epp = &(enp->en_port);
175 : : uint32_t port_id;
176 : : efx_rc_t rc;
177 : :
178 : 0 : req.emr_cmd = MC_CMD_FILTER_OP;
179 : 0 : req.emr_in_buf = payload;
180 : 0 : req.emr_in_length = MC_CMD_FILTER_OP_V3_IN_LEN;
181 : 0 : req.emr_out_buf = payload;
182 : 0 : req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN;
183 : :
184 : : /*
185 : : * Remove EFX match flags that do not correspond
186 : : * to the MCDI match flags
187 : : */
188 : 0 : match_flags = spec->efs_match_flags & ~EFX_FILTER_MATCH_ENCAP_TYPE;
189 : 0 : match_flags &= ~EFX_FILTER_MATCH_MPORT;
190 : :
191 [ # # # ]: 0 : switch (filter_op) {
192 : 0 : case MC_CMD_FILTER_OP_IN_OP_REPLACE:
193 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO,
194 : : handle->efh_lo);
195 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_HI,
196 : : handle->efh_hi);
197 : : /* Fall through */
198 : 0 : case MC_CMD_FILTER_OP_IN_OP_INSERT:
199 : : case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE:
200 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP, filter_op);
201 : : break;
202 : : default:
203 : 0 : EFSYS_ASSERT(0);
204 : : rc = EINVAL;
205 : : goto fail1;
206 : : }
207 : :
208 [ # # ]: 0 : if (spec->efs_match_flags & EFX_FILTER_MATCH_MPORT)
209 : 0 : port_id = spec->efs_ingress_mport;
210 : : else
211 : 0 : port_id = enp->en_vport_id;
212 : :
213 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_PORT_ID, port_id);
214 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_MATCH_FIELDS,
215 : : match_flags);
216 [ # # ]: 0 : if (spec->efs_dmaq_id == EFX_FILTER_SPEC_RX_DMAQ_ID_DROP) {
217 : : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST,
218 : : MC_CMD_FILTER_OP_EXT_IN_RX_DEST_DROP);
219 : : } else {
220 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST,
221 : : MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST);
222 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_QUEUE,
223 : : spec->efs_dmaq_id);
224 : : }
225 : :
226 : : #if EFSYS_OPT_RX_SCALE
227 [ # # ]: 0 : if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) {
228 : : uint32_t rss_context;
229 : :
230 [ # # ]: 0 : if (spec->efs_rss_context == EFX_RSS_CONTEXT_DEFAULT)
231 : 0 : rss_context = enp->en_rss_context;
232 : : else
233 : : rss_context = spec->efs_rss_context;
234 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_CONTEXT,
235 : : rss_context);
236 : : }
237 : : #endif
238 : :
239 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_MODE,
240 : : spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ?
241 : : MC_CMD_FILTER_OP_EXT_IN_RX_MODE_RSS :
242 : : MC_CMD_FILTER_OP_EXT_IN_RX_MODE_SIMPLE);
243 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_TX_DEST,
244 : : MC_CMD_FILTER_OP_EXT_IN_TX_DEST_DEFAULT);
245 : :
246 [ # # ]: 0 : if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) {
247 : : /*
248 : : * NOTE: Unlike most MCDI requests, the filter fields
249 : : * are presented in network (big endian) byte order.
250 : : */
251 : : memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_SRC_MAC),
252 [ # # # ]: 0 : spec->efs_rem_mac, EFX_MAC_ADDR_LEN);
253 : : memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_MAC),
254 : 0 : spec->efs_loc_mac, EFX_MAC_ADDR_LEN);
255 : :
256 : 0 : MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_SRC_PORT,
257 : : __CPU_TO_BE_16(spec->efs_rem_port));
258 : 0 : MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_DST_PORT,
259 : : __CPU_TO_BE_16(spec->efs_loc_port));
260 : :
261 : 0 : MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_ETHER_TYPE,
262 : : __CPU_TO_BE_16(spec->efs_ether_type));
263 : :
264 : 0 : MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_INNER_VLAN,
265 : : __CPU_TO_BE_16(spec->efs_inner_vid));
266 : 0 : MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_OUTER_VLAN,
267 : : __CPU_TO_BE_16(spec->efs_outer_vid));
268 : :
269 : : /* IP protocol (in low byte, high byte is zero) */
270 : 0 : MCDI_IN_SET_BYTE(req, FILTER_OP_EXT_IN_IP_PROTO,
271 : : spec->efs_ip_proto);
272 : :
273 : : EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) ==
274 : : MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN);
275 : : EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) ==
276 : : MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN);
277 : :
278 : : memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_SRC_IP),
279 : 0 : &spec->efs_rem_host.eo_byte[0],
280 : : MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN);
281 : : memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_IP),
282 : 0 : &spec->efs_loc_host.eo_byte[0],
283 : : MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN);
284 : :
285 : : /*
286 : : * On Medford, filters for encapsulated packets match based on
287 : : * the ether type and IP protocol in the outer frame. In
288 : : * addition we need to fill in the VNI or VSID type field.
289 : : */
290 [ # # # ]: 0 : switch (spec->efs_encap_type) {
291 : : case EFX_TUNNEL_PROTOCOL_NONE:
292 : : break;
293 : 0 : case EFX_TUNNEL_PROTOCOL_VXLAN:
294 : : case EFX_TUNNEL_PROTOCOL_GENEVE:
295 [ # # ]: 0 : MCDI_IN_POPULATE_DWORD_1(req,
296 : : FILTER_OP_EXT_IN_VNI_OR_VSID,
297 : : FILTER_OP_EXT_IN_VNI_TYPE,
298 : : spec->efs_encap_type == EFX_TUNNEL_PROTOCOL_VXLAN ?
299 : : MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_VXLAN :
300 : : MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_GENEVE);
301 : 0 : break;
302 : : case EFX_TUNNEL_PROTOCOL_NVGRE:
303 : : MCDI_IN_POPULATE_DWORD_1(req,
304 : : FILTER_OP_EXT_IN_VNI_OR_VSID,
305 : : FILTER_OP_EXT_IN_VSID_TYPE,
306 : : MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_NVGRE);
307 : : break;
308 : : default:
309 : 0 : EFSYS_ASSERT(0);
310 : : rc = EINVAL;
311 : : goto fail2;
312 : : }
313 : :
314 : : memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_VNI_OR_VSID),
315 : 0 : spec->efs_vni_or_vsid, EFX_VNI_OR_VSID_LEN);
316 : :
317 : : memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_IFRM_DST_MAC),
318 : 0 : spec->efs_ifrm_loc_mac, EFX_MAC_ADDR_LEN);
319 : : }
320 : :
321 : : /*
322 : : * Set the "MARK" or "FLAG" action for all packets matching this filter
323 : : * if necessary (only useful with equal stride packed stream Rx mode
324 : : * which provide the information in pseudo-header).
325 : : * These actions require MC_CMD_FILTER_OP_V3_IN msgrequest.
326 : : */
327 [ # # ]: 0 : if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) &&
328 : : (spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG)) {
329 : : rc = EINVAL;
330 : 0 : goto fail3;
331 : : }
332 [ # # ]: 0 : if (spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) {
333 : 0 : MCDI_IN_SET_DWORD_FIELD(req, FILTER_OP_V3_IN_MATCH_ACTION_FLAGS,
334 : : FILTER_OP_V3_IN_MATCH_SET_MARK, 1);
335 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_V3_IN_MATCH_MARK_VALUE,
336 : : spec->efs_mark);
337 [ # # ]: 0 : } else if (spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG) {
338 : 0 : MCDI_IN_SET_DWORD_FIELD(req, FILTER_OP_V3_IN_MATCH_ACTION_FLAGS,
339 : : FILTER_OP_V3_IN_MATCH_SET_FLAG, 1);
340 : : }
341 : :
342 [ # # ]: 0 : if (epp->ep_vlan_strip) {
343 : 0 : MCDI_IN_SET_DWORD_FIELD(req, FILTER_OP_V3_IN_MATCH_ACTION_FLAGS,
344 : : FILTER_OP_V3_IN_MATCH_STRIP_VLAN, 1);
345 : : }
346 : :
347 : 0 : efx_mcdi_execute(enp, &req);
348 : :
349 [ # # ]: 0 : if (req.emr_rc != 0) {
350 : : rc = req.emr_rc;
351 : 0 : goto fail4;
352 : : }
353 : :
354 [ # # ]: 0 : if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) {
355 : : rc = EMSGSIZE;
356 : 0 : goto fail5;
357 : : }
358 : :
359 : 0 : handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_LO);
360 : 0 : handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_HI);
361 : :
362 : 0 : return (0);
363 : :
364 : : fail5:
365 : : EFSYS_PROBE(fail5);
366 : : fail4:
367 : : EFSYS_PROBE(fail4);
368 : : fail3:
369 : : EFSYS_PROBE(fail3);
370 : : fail2:
371 : : EFSYS_PROBE(fail2);
372 : : fail1:
373 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
374 : :
375 : : return (rc);
376 : :
377 : : }
378 : :
379 : : static __checkReturn efx_rc_t
380 : 0 : efx_mcdi_filter_op_delete(
381 : : __in efx_nic_t *enp,
382 : : __in unsigned int filter_op,
383 : : __inout ef10_filter_handle_t *handle)
384 : : {
385 : : efx_mcdi_req_t req;
386 : 0 : EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FILTER_OP_EXT_IN_LEN,
387 : : MC_CMD_FILTER_OP_EXT_OUT_LEN);
388 : : efx_rc_t rc;
389 : :
390 : 0 : req.emr_cmd = MC_CMD_FILTER_OP;
391 : 0 : req.emr_in_buf = payload;
392 : 0 : req.emr_in_length = MC_CMD_FILTER_OP_EXT_IN_LEN;
393 : 0 : req.emr_out_buf = payload;
394 : 0 : req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN;
395 : :
396 [ # # # ]: 0 : switch (filter_op) {
397 : 0 : case MC_CMD_FILTER_OP_IN_OP_REMOVE:
398 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP,
399 : : MC_CMD_FILTER_OP_IN_OP_REMOVE);
400 : 0 : break;
401 : 0 : case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE:
402 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP,
403 : : MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE);
404 : 0 : break;
405 : : default:
406 : 0 : EFSYS_ASSERT(0);
407 : : rc = EINVAL;
408 : : goto fail1;
409 : : }
410 : :
411 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO, handle->efh_lo);
412 : 0 : MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_HI, handle->efh_hi);
413 : :
414 : 0 : efx_mcdi_execute_quiet(enp, &req);
415 : :
416 [ # # ]: 0 : if (req.emr_rc != 0) {
417 : : rc = req.emr_rc;
418 : 0 : goto fail2;
419 : : }
420 : :
421 [ # # ]: 0 : if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) {
422 : : rc = EMSGSIZE;
423 : 0 : goto fail3;
424 : : }
425 : :
426 : : return (0);
427 : :
428 : : fail3:
429 : : EFSYS_PROBE(fail3);
430 : :
431 : : fail2:
432 : : EFSYS_PROBE(fail2);
433 : : fail1:
434 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
435 : :
436 : : return (rc);
437 : : }
438 : :
439 : : static __checkReturn boolean_t
440 : 0 : ef10_filter_equal(
441 : : __in const efx_filter_spec_t *left,
442 : : __in const efx_filter_spec_t *right)
443 : : {
444 : : /* FIXME: Consider rx vs tx filters (look at efs_flags) */
445 [ # # ]: 0 : if (left->efs_match_flags != right->efs_match_flags)
446 : : return (B_FALSE);
447 [ # # # # ]: 0 : if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host))
448 : : return (B_FALSE);
449 [ # # # # ]: 0 : if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host))
450 : : return (B_FALSE);
451 [ # # ]: 0 : if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN))
452 : : return (B_FALSE);
453 [ # # ]: 0 : if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN))
454 : : return (B_FALSE);
455 [ # # ]: 0 : if (left->efs_rem_port != right->efs_rem_port)
456 : : return (B_FALSE);
457 [ # # ]: 0 : if (left->efs_loc_port != right->efs_loc_port)
458 : : return (B_FALSE);
459 [ # # ]: 0 : if (left->efs_inner_vid != right->efs_inner_vid)
460 : : return (B_FALSE);
461 [ # # ]: 0 : if (left->efs_outer_vid != right->efs_outer_vid)
462 : : return (B_FALSE);
463 [ # # ]: 0 : if (left->efs_ether_type != right->efs_ether_type)
464 : : return (B_FALSE);
465 [ # # ]: 0 : if (left->efs_ip_proto != right->efs_ip_proto)
466 : : return (B_FALSE);
467 [ # # ]: 0 : if (left->efs_encap_type != right->efs_encap_type)
468 : : return (B_FALSE);
469 [ # # ]: 0 : if (memcmp(left->efs_vni_or_vsid, right->efs_vni_or_vsid,
470 : : EFX_VNI_OR_VSID_LEN))
471 : : return (B_FALSE);
472 [ # # ]: 0 : if (memcmp(left->efs_ifrm_loc_mac, right->efs_ifrm_loc_mac,
473 : : EFX_MAC_ADDR_LEN))
474 : 0 : return (B_FALSE);
475 : :
476 : : return (B_TRUE);
477 : :
478 : : }
479 : :
480 : : static __checkReturn boolean_t
481 : 0 : ef10_filter_same_dest(
482 : : __in const efx_filter_spec_t *left,
483 : : __in const efx_filter_spec_t *right)
484 : : {
485 [ # # ]: 0 : if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
486 [ # # ]: 0 : (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) {
487 [ # # ]: 0 : if (left->efs_rss_context == right->efs_rss_context)
488 : 0 : return (B_TRUE);
489 [ # # ]: 0 : } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) &&
490 [ # # ]: 0 : (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) {
491 [ # # ]: 0 : if (left->efs_dmaq_id == right->efs_dmaq_id)
492 : 0 : return (B_TRUE);
493 : : }
494 : : return (B_FALSE);
495 : : }
496 : :
497 : : static __checkReturn uint32_t
498 : : ef10_filter_hash(
499 : : __in efx_filter_spec_t *spec)
500 : : {
501 : : EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t))
502 : : == 0);
503 : : EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) %
504 : : sizeof (uint32_t)) == 0);
505 : :
506 : : /*
507 : : * As the area of the efx_filter_spec_t we need to hash is DWORD
508 : : * aligned and an exact number of DWORDs in size we can use the
509 : : * optimised efx_hash_dwords() rather than efx_hash_bytes()
510 : : */
511 : 0 : return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid,
512 : : (sizeof (efx_filter_spec_t) -
513 : : EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) /
514 : : sizeof (uint32_t), 0));
515 : : }
516 : :
517 : : /*
518 : : * Decide whether a filter should be exclusive or else should allow
519 : : * delivery to additional recipients. Currently we decide that
520 : : * filters for specific local unicast MAC and IP addresses are
521 : : * exclusive.
522 : : */
523 : : static __checkReturn boolean_t
524 : 0 : ef10_filter_is_exclusive(
525 : : __in efx_filter_spec_t *spec)
526 : : {
527 [ # # ]: 0 : if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) &&
528 [ # # ]: 0 : !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac))
529 : : return (B_TRUE);
530 : :
531 [ # # ]: 0 : if ((spec->efs_match_flags &
532 : : (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) ==
533 : : (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) {
534 [ # # ]: 0 : if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) &&
535 [ # # ]: 0 : ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe))
536 : : return (B_TRUE);
537 [ # # ]: 0 : if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) &&
538 [ # # ]: 0 : (spec->efs_loc_host.eo_u8[0] != 0xff))
539 : 0 : return (B_TRUE);
540 : : }
541 : :
542 : : return (B_FALSE);
543 : : }
544 : :
545 : : __checkReturn efx_rc_t
546 : 0 : ef10_filter_restore(
547 : : __in efx_nic_t *enp)
548 : : {
549 : : int tbl_id;
550 : : efx_filter_spec_t *spec;
551 : 0 : ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
552 : : boolean_t restoring;
553 : : efsys_lock_state_t state;
554 : : efx_rc_t rc;
555 : :
556 [ # # ]: 0 : EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
557 : :
558 [ # # ]: 0 : for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) {
559 : :
560 : 0 : EFSYS_LOCK(enp->en_eslp, state);
561 : :
562 : 0 : spec = ef10_filter_entry_spec(eftp, tbl_id);
563 [ # # ]: 0 : if (spec == NULL) {
564 : : restoring = B_FALSE;
565 : : } else if (ef10_filter_entry_is_busy(eftp, tbl_id)) {
566 : : /* Ignore busy entries. */
567 : : restoring = B_FALSE;
568 : : } else {
569 : : ef10_filter_set_entry_busy(eftp, tbl_id);
570 : : restoring = B_TRUE;
571 : : }
572 : :
573 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
574 : :
575 [ # # ]: 0 : if (restoring == B_FALSE)
576 : 0 : continue;
577 : :
578 [ # # ]: 0 : if (ef10_filter_is_exclusive(spec)) {
579 : 0 : rc = efx_mcdi_filter_op_add(enp, spec,
580 : : MC_CMD_FILTER_OP_IN_OP_INSERT,
581 : : &eftp->eft_entry[tbl_id].efe_handle);
582 : : } else {
583 : 0 : rc = efx_mcdi_filter_op_add(enp, spec,
584 : : MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
585 : : &eftp->eft_entry[tbl_id].efe_handle);
586 : : }
587 : :
588 [ # # ]: 0 : if (rc != 0)
589 : 0 : goto fail1;
590 : :
591 : 0 : EFSYS_LOCK(enp->en_eslp, state);
592 : :
593 : : ef10_filter_set_entry_not_busy(eftp, tbl_id);
594 : :
595 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
596 : : }
597 : :
598 : : return (0);
599 : :
600 : : fail1:
601 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
602 : :
603 : 0 : return (rc);
604 : : }
605 : :
606 : : enum ef10_filter_add_action_e {
607 : : /* Insert a new filter */
608 : : EF10_FILTER_ADD_NEW,
609 : : /*
610 : : * Replace old filter with a new, overriding the old one
611 : : * if it has lower priority.
612 : : */
613 : : EF10_FILTER_ADD_REPLACE,
614 : : /* Store new, lower priority filter as overridden by old filter */
615 : : EF10_FILTER_ADD_STORE,
616 : : /* Special case for AUTO filters, remove AUTO_OLD flag */
617 : : EF10_FILTER_ADD_REFRESH,
618 : : };
619 : :
620 : : static __checkReturn efx_rc_t
621 : 0 : ef10_filter_add_lookup_equal_spec(
622 : : __in efx_filter_spec_t *spec,
623 : : __in efx_filter_spec_t *probe_spec,
624 : : __in efx_filter_replacement_policy_t policy,
625 : : __out boolean_t *found)
626 : : {
627 : : efx_rc_t rc;
628 : :
629 : : /* Refreshing AUTO filter */
630 [ # # ]: 0 : if (spec->efs_priority == EFX_FILTER_PRI_AUTO &&
631 [ # # ]: 0 : probe_spec->efs_priority == EFX_FILTER_PRI_AUTO) {
632 : 0 : *found = B_TRUE;
633 : 0 : return (0);
634 : : }
635 : :
636 : : /*
637 : : * With exclusive filters, higher priority ones
638 : : * override lower priority ones, and lower priority
639 : : * ones are stored in case the higher priority one
640 : : * is removed.
641 : : */
642 [ # # ]: 0 : if (ef10_filter_is_exclusive(spec)) {
643 [ # # # # ]: 0 : switch (policy) {
644 : 0 : case EFX_FILTER_REPLACEMENT_HIGHER_OR_EQUAL_PRIORITY:
645 [ # # ]: 0 : if (spec->efs_priority == probe_spec->efs_priority) {
646 : 0 : *found = B_TRUE;
647 : 0 : break;
648 : : }
649 : : /* Fall-through */
650 : : case EFX_FILTER_REPLACEMENT_HIGHER_PRIORITY:
651 [ # # ]: 0 : if (spec->efs_priority > probe_spec->efs_priority) {
652 : 0 : *found = B_TRUE;
653 : 0 : break;
654 : : }
655 : : /* Fall-through */
656 : : case EFX_FILTER_REPLACEMENT_NEVER:
657 : : /*
658 : : * Lower priority filter needs to be
659 : : * stored. It does *not* replace the
660 : : * old one. That is why EEXIST is not
661 : : * returned in that case.
662 : : */
663 [ # # ]: 0 : if (spec->efs_priority < probe_spec->efs_priority) {
664 : 0 : *found = B_TRUE;
665 : 0 : break;
666 : : } else {
667 : : rc = EEXIST;
668 : 0 : goto fail1;
669 : : }
670 : : default:
671 : 0 : EFSYS_ASSERT(0);
672 : : rc = EEXIST;
673 : : goto fail2;
674 : : }
675 : : } else {
676 : 0 : *found = B_FALSE;
677 : : }
678 : :
679 : : return (0);
680 : :
681 : : fail2:
682 : : EFSYS_PROBE(fail2);
683 : :
684 : : fail1:
685 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
686 : :
687 : 0 : return (rc);
688 : : }
689 : :
690 : :
691 : : static void
692 : 0 : ef10_filter_add_select_action(
693 : : __in efx_filter_spec_t *saved_spec,
694 : : __in efx_filter_spec_t *spec,
695 : : __out enum ef10_filter_add_action_e *action,
696 : : __out efx_filter_spec_t **overridden_spec)
697 : : {
698 : : efx_filter_spec_t *overridden = NULL;
699 : :
700 [ # # ]: 0 : if (saved_spec == NULL) {
701 : 0 : *action = EF10_FILTER_ADD_NEW;
702 [ # # ]: 0 : } else if (ef10_filter_is_exclusive(spec) == B_FALSE) {
703 : : /*
704 : : * Non-exclusive filters are always stored in separate entries
705 : : * in the table. The only case involving a saved spec is
706 : : * refreshing an AUTO filter.
707 : : */
708 [ # # ]: 0 : EFSYS_ASSERT(saved_spec->efs_overridden_spec == NULL);
709 [ # # ]: 0 : EFSYS_ASSERT(spec->efs_priority == EFX_FILTER_PRI_AUTO);
710 [ # # ]: 0 : EFSYS_ASSERT(saved_spec->efs_priority == EFX_FILTER_PRI_AUTO);
711 : 0 : *action = EF10_FILTER_ADD_REFRESH;
712 : : } else {
713 : : /* Exclusive filters stored in the same entry */
714 [ # # ]: 0 : if (spec->efs_priority > saved_spec->efs_priority) {
715 : : /*
716 : : * Insert a high priority filter over a lower priority
717 : : * one. Only two priority levels are implemented, so
718 : : * there must not already be an overridden filter.
719 : : */
720 : : EFX_STATIC_ASSERT(EFX_FILTER_NPRI == 2);
721 [ # # ]: 0 : EFSYS_ASSERT(saved_spec->efs_overridden_spec == NULL);
722 : : overridden = saved_spec;
723 : 0 : *action = EF10_FILTER_ADD_REPLACE;
724 [ # # ]: 0 : } else if (spec->efs_priority == saved_spec->efs_priority) {
725 : : /* Replace in-place or refresh an existing filter */
726 [ # # ]: 0 : if (spec->efs_priority == EFX_FILTER_PRI_AUTO)
727 : 0 : *action = EF10_FILTER_ADD_REFRESH;
728 : : else
729 : 0 : *action = EF10_FILTER_ADD_REPLACE;
730 : : } else {
731 : : /*
732 : : * Insert a lower priority filter, storing it in case
733 : : * the higher priority filter is removed.
734 : : *
735 : : * Currently there are only two priority levels, so this
736 : : * must be an AUTO filter.
737 : : */
738 : : EFX_STATIC_ASSERT(EFX_FILTER_NPRI == 2);
739 [ # # ]: 0 : EFSYS_ASSERT(spec->efs_priority == EFX_FILTER_PRI_AUTO);
740 [ # # ]: 0 : if (saved_spec->efs_overridden_spec != NULL) {
741 : 0 : *action = EF10_FILTER_ADD_REFRESH;
742 : : } else {
743 : : overridden = spec;
744 : 0 : *action = EF10_FILTER_ADD_STORE;
745 : : }
746 : : }
747 : : }
748 : :
749 : 0 : *overridden_spec = overridden;
750 : 0 : }
751 : :
752 : : static __checkReturn efx_rc_t
753 : 0 : ef10_filter_add_execute_action(
754 : : __in efx_nic_t *enp,
755 : : __in efx_filter_spec_t *saved_spec,
756 : : __in efx_filter_spec_t *spec,
757 : : __in efx_filter_spec_t *overridden_spec,
758 : : __in enum ef10_filter_add_action_e action,
759 : : __in int ins_index)
760 : : {
761 : 0 : ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
762 : : efsys_lock_state_t state;
763 : : efx_rc_t rc;
764 : :
765 : 0 : EFSYS_LOCK(enp->en_eslp, state);
766 : :
767 [ # # ]: 0 : if (action == EF10_FILTER_ADD_REFRESH) {
768 : 0 : ef10_filter_set_entry_not_auto_old(eftp, ins_index);
769 : 0 : goto out_unlock;
770 [ # # ]: 0 : } else if (action == EF10_FILTER_ADD_STORE) {
771 [ # # ]: 0 : EFSYS_ASSERT(overridden_spec != NULL);
772 : 0 : saved_spec->efs_overridden_spec = overridden_spec;
773 : 0 : goto out_unlock;
774 : : }
775 : :
776 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
777 : :
778 [ # # # ]: 0 : switch (action) {
779 : 0 : case EF10_FILTER_ADD_REPLACE:
780 : : /*
781 : : * On replacing the filter handle may change after a
782 : : * successful replace operation.
783 : : */
784 : 0 : rc = efx_mcdi_filter_op_add(enp, spec,
785 : : MC_CMD_FILTER_OP_IN_OP_REPLACE,
786 : : &eftp->eft_entry[ins_index].efe_handle);
787 : 0 : break;
788 : 0 : case EF10_FILTER_ADD_NEW:
789 [ # # ]: 0 : if (ef10_filter_is_exclusive(spec)) {
790 : 0 : rc = efx_mcdi_filter_op_add(enp, spec,
791 : : MC_CMD_FILTER_OP_IN_OP_INSERT,
792 : : &eftp->eft_entry[ins_index].efe_handle);
793 : : } else {
794 : 0 : rc = efx_mcdi_filter_op_add(enp, spec,
795 : : MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
796 : : &eftp->eft_entry[ins_index].efe_handle);
797 : : }
798 : : break;
799 : 0 : default:
800 : : rc = EINVAL;
801 : 0 : EFSYS_ASSERT(0);
802 : : break;
803 : : }
804 [ # # ]: 0 : if (rc != 0)
805 : 0 : goto fail1;
806 : :
807 : 0 : EFSYS_LOCK(enp->en_eslp, state);
808 : :
809 [ # # ]: 0 : if (action == EF10_FILTER_ADD_REPLACE) {
810 : : /* Update the fields that may differ */
811 : 0 : saved_spec->efs_priority = spec->efs_priority;
812 : 0 : saved_spec->efs_flags = spec->efs_flags;
813 : 0 : saved_spec->efs_rss_context = spec->efs_rss_context;
814 : 0 : saved_spec->efs_dmaq_id = spec->efs_dmaq_id;
815 : :
816 [ # # ]: 0 : if (overridden_spec != NULL)
817 : 0 : saved_spec->efs_overridden_spec = overridden_spec;
818 : : }
819 : :
820 : 0 : out_unlock:
821 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
822 : :
823 : 0 : return (0);
824 : :
825 : : fail1:
826 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
827 : :
828 : 0 : return (rc);
829 : : }
830 : :
831 : : /*
832 : : * An arbitrary search limit for the software hash table. As per the linux net
833 : : * driver.
834 : : */
835 : : #define EF10_FILTER_SEARCH_LIMIT 200
836 : :
837 : : static __checkReturn efx_rc_t
838 : 0 : ef10_filter_add_internal(
839 : : __in efx_nic_t *enp,
840 : : __inout efx_filter_spec_t *spec,
841 : : __in efx_filter_replacement_policy_t policy,
842 : : __out_opt uint32_t *filter_id)
843 : : {
844 : : efx_rc_t rc;
845 : 0 : ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
846 : : enum ef10_filter_add_action_e action;
847 : 0 : efx_filter_spec_t *overridden_spec = NULL;
848 : : efx_filter_spec_t *saved_spec;
849 : : uint32_t hash;
850 : : unsigned int depth;
851 : : int ins_index;
852 : : efsys_lock_state_t state;
853 : : boolean_t locked = B_FALSE;
854 : :
855 [ # # ]: 0 : EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
856 : :
857 [ # # ]: 0 : EFSYS_ASSERT(spec->efs_overridden_spec == NULL);
858 : :
859 : : hash = ef10_filter_hash(spec);
860 : :
861 : : /*
862 : : * FIXME: Add support for inserting filters of different priorities
863 : : * and removing lower priority multicast filters (bug 42378)
864 : : */
865 : :
866 : : /*
867 : : * Find any existing filters with the same match tuple or
868 : : * else a free slot to insert at. If any of them are busy,
869 : : * we have to wait and retry.
870 : : */
871 : 0 : retry:
872 : 0 : EFSYS_LOCK(enp->en_eslp, state);
873 : : locked = B_TRUE;
874 : :
875 : : ins_index = -1;
876 : :
877 [ # # ]: 0 : for (depth = 1; depth <= EF10_FILTER_SEARCH_LIMIT; depth++) {
878 : : unsigned int probe_index;
879 : : efx_filter_spec_t *probe_spec;
880 : :
881 : 0 : probe_index = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1);
882 : : probe_spec = ef10_filter_entry_spec(eftp, probe_index);
883 : :
884 [ # # ]: 0 : if (probe_spec == NULL) {
885 [ # # ]: 0 : if (ins_index < 0)
886 : 0 : ins_index = probe_index;
887 [ # # ]: 0 : } else if (ef10_filter_equal(spec, probe_spec)) {
888 : : boolean_t found;
889 : :
890 : : if (ef10_filter_entry_is_busy(eftp, probe_index)) {
891 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
892 : : locked = B_FALSE;
893 : 0 : goto retry;
894 : : }
895 : :
896 : 0 : rc = ef10_filter_add_lookup_equal_spec(spec,
897 : : probe_spec, policy, &found);
898 [ # # ]: 0 : if (rc != 0)
899 : 0 : goto fail1;
900 : :
901 [ # # ]: 0 : if (found != B_FALSE) {
902 : 0 : ins_index = probe_index;
903 : 0 : break;
904 : : }
905 : : }
906 : : }
907 : :
908 : : /*
909 : : * Once we reach the maximum search depth, use the first suitable slot
910 : : * or return EBUSY if there was none.
911 : : */
912 [ # # ]: 0 : if (ins_index < 0) {
913 : : rc = EBUSY;
914 : 0 : goto fail2;
915 : : }
916 : :
917 : : /*
918 : : * Mark software table entry busy. We might yet fail to insert,
919 : : * but any attempt to insert a conflicting filter while we're
920 : : * waiting for the firmware must find the busy entry.
921 : : */
922 : 0 : ef10_filter_set_entry_busy(eftp, ins_index);
923 : :
924 : : saved_spec = ef10_filter_entry_spec(eftp, ins_index);
925 : 0 : ef10_filter_add_select_action(saved_spec, spec, &action,
926 : : &overridden_spec);
927 : :
928 : : /*
929 : : * Allocate a new filter if found entry is empty or
930 : : * a filter should be overridden.
931 : : */
932 [ # # # # ]: 0 : if (overridden_spec != NULL || saved_spec == NULL) {
933 : : efx_filter_spec_t *new_spec;
934 : :
935 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
936 : : locked = B_FALSE;
937 : :
938 : 0 : EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*new_spec), new_spec);
939 [ # # ]: 0 : if (new_spec == NULL) {
940 : : rc = ENOMEM;
941 : 0 : overridden_spec = NULL;
942 : 0 : goto fail3;
943 : : }
944 : :
945 : 0 : EFSYS_LOCK(enp->en_eslp, state);
946 : : locked = B_TRUE;
947 : :
948 [ # # ]: 0 : if (saved_spec == NULL) {
949 : 0 : *new_spec = *spec;
950 : : ef10_filter_set_entry(eftp, ins_index, new_spec);
951 : : } else {
952 : 0 : *new_spec = *overridden_spec;
953 : 0 : overridden_spec = new_spec;
954 : : }
955 : : }
956 : :
957 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
958 : : locked = B_FALSE;
959 : :
960 : 0 : rc = ef10_filter_add_execute_action(enp, saved_spec, spec,
961 : : overridden_spec, action, ins_index);
962 [ # # ]: 0 : if (rc != 0)
963 : 0 : goto fail4;
964 : :
965 [ # # ]: 0 : if (filter_id)
966 : 0 : *filter_id = ins_index;
967 : :
968 : 0 : EFSYS_LOCK(enp->en_eslp, state);
969 : : ef10_filter_set_entry_not_busy(eftp, ins_index);
970 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
971 : :
972 : 0 : return (0);
973 : :
974 : : fail4:
975 : : EFSYS_PROBE(fail4);
976 : :
977 : : EFSYS_ASSERT(locked == B_FALSE);
978 : 0 : EFSYS_LOCK(enp->en_eslp, state);
979 : :
980 [ # # ]: 0 : if (action == EF10_FILTER_ADD_NEW) {
981 : 0 : EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec),
982 : : ef10_filter_entry_spec(eftp, ins_index));
983 : : ef10_filter_set_entry(eftp, ins_index, NULL);
984 : : }
985 : :
986 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
987 : :
988 [ # # ]: 0 : if (overridden_spec != NULL)
989 : 0 : EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), overridden_spec);
990 : :
991 : 0 : fail3:
992 : : EFSYS_PROBE(fail3);
993 : :
994 : : EFSYS_ASSERT(locked == B_FALSE);
995 : 0 : EFSYS_LOCK(enp->en_eslp, state);
996 : :
997 : : ef10_filter_set_entry_not_busy(eftp, ins_index);
998 : :
999 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
1000 : :
1001 : : fail2:
1002 : : EFSYS_PROBE(fail2);
1003 : :
1004 : : fail1:
1005 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1006 : :
1007 : : if (locked)
1008 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
1009 : :
1010 : : return (rc);
1011 : : }
1012 : :
1013 : : __checkReturn efx_rc_t
1014 : 0 : ef10_filter_add(
1015 : : __in efx_nic_t *enp,
1016 : : __inout efx_filter_spec_t *spec,
1017 : : __in enum efx_filter_replacement_policy_e policy)
1018 : : {
1019 : : efx_rc_t rc;
1020 : :
1021 : 0 : rc = ef10_filter_add_internal(enp, spec, policy, NULL);
1022 [ # # ]: 0 : if (rc != 0)
1023 : 0 : goto fail1;
1024 : :
1025 : : return (0);
1026 : :
1027 : : fail1:
1028 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1029 : :
1030 : 0 : return (rc);
1031 : : }
1032 : :
1033 : : /*
1034 : : * Delete a filter by index from the filter table with priority
1035 : : * that is not higher than specified.
1036 : : */
1037 : : static __checkReturn efx_rc_t
1038 : 0 : ef10_filter_delete_internal(
1039 : : __in efx_nic_t *enp,
1040 : : __in uint32_t filter_id,
1041 : : __in efx_filter_priority_t priority)
1042 : : {
1043 : : efx_rc_t rc;
1044 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1045 : : efx_filter_spec_t *spec;
1046 : : efsys_lock_state_t state;
1047 : 0 : uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS;
1048 : :
1049 : : /*
1050 : : * Find the software table entry and mark it busy. Don't
1051 : : * remove it yet; any attempt to update while we're waiting
1052 : : * for the firmware must find the busy entry.
1053 : : *
1054 : : * FIXME: What if the busy flag is never cleared?
1055 : : */
1056 : 0 : EFSYS_LOCK(enp->en_eslp, state);
1057 : 0 : while (ef10_filter_entry_is_busy(table, filter_idx)) {
1058 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
1059 : 0 : EFSYS_SPIN(1);
1060 : 0 : EFSYS_LOCK(enp->en_eslp, state);
1061 : : }
1062 [ # # ]: 0 : if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) {
1063 [ # # ]: 0 : if (spec->efs_priority <= priority)
1064 : : ef10_filter_set_entry_busy(table, filter_idx);
1065 : : }
1066 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
1067 : :
1068 [ # # ]: 0 : if (spec == NULL) {
1069 : : rc = ENOENT;
1070 : 0 : goto fail1;
1071 : : }
1072 : :
1073 [ # # ]: 0 : if (spec->efs_priority > priority) {
1074 : : /*
1075 : : * Applied filter stays, but overridden filter is removed since
1076 : : * next user request to delete the applied filter should not
1077 : : * restore outdated filter.
1078 : : */
1079 [ # # ]: 0 : if (spec->efs_overridden_spec != NULL) {
1080 [ # # ]: 0 : EFSYS_ASSERT(spec->efs_overridden_spec->efs_overridden_spec ==
1081 : : NULL);
1082 : 0 : EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec),
1083 : : spec->efs_overridden_spec);
1084 : 0 : spec->efs_overridden_spec = NULL;
1085 : : }
1086 : : } else {
1087 : : /*
1088 : : * Try to remove the hardware filter or replace it with the
1089 : : * saved automatic filter. This may fail if the MC has
1090 : : * rebooted (which frees all hardware filter resources).
1091 : : */
1092 [ # # ]: 0 : if (spec->efs_overridden_spec != NULL) {
1093 : 0 : rc = efx_mcdi_filter_op_add(enp,
1094 : : spec->efs_overridden_spec,
1095 : : MC_CMD_FILTER_OP_IN_OP_REPLACE,
1096 : : &table->eft_entry[filter_idx].efe_handle);
1097 [ # # ]: 0 : } else if (ef10_filter_is_exclusive(spec)) {
1098 : 0 : rc = efx_mcdi_filter_op_delete(enp,
1099 : : MC_CMD_FILTER_OP_IN_OP_REMOVE,
1100 : : &table->eft_entry[filter_idx].efe_handle);
1101 : : } else {
1102 : 0 : rc = efx_mcdi_filter_op_delete(enp,
1103 : : MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE,
1104 : : &table->eft_entry[filter_idx].efe_handle);
1105 : : }
1106 : :
1107 : : /* Free the software table entry */
1108 : 0 : EFSYS_LOCK(enp->en_eslp, state);
1109 : : ef10_filter_set_entry_not_busy(table, filter_idx);
1110 : : ef10_filter_set_entry(table, filter_idx,
1111 : 0 : spec->efs_overridden_spec);
1112 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
1113 : :
1114 : 0 : EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1115 : :
1116 : : /* Check result of hardware filter removal */
1117 [ # # ]: 0 : if (rc != 0)
1118 : 0 : goto fail2;
1119 : : }
1120 : :
1121 : : return (0);
1122 : :
1123 : : fail2:
1124 : : EFSYS_PROBE(fail2);
1125 : :
1126 : : fail1:
1127 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1128 : :
1129 : : return (rc);
1130 : : }
1131 : :
1132 : : static void
1133 : 0 : ef10_filter_delete_auto(
1134 : : __in efx_nic_t *enp,
1135 : : __in uint32_t filter_id)
1136 : : {
1137 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1138 : 0 : uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS;
1139 : :
1140 : : /*
1141 : : * AUTO_OLD flag is cleared since the auto filter that is to be removed
1142 : : * may not be the filter at the specified index itself, but the filter
1143 : : * that is overridden by it.
1144 : : */
1145 : 0 : ef10_filter_set_entry_not_auto_old(table, filter_idx);
1146 : :
1147 : 0 : (void) ef10_filter_delete_internal(enp, filter_idx,
1148 : : EFX_FILTER_PRI_AUTO);
1149 : 0 : }
1150 : :
1151 : : __checkReturn efx_rc_t
1152 : 0 : ef10_filter_delete(
1153 : : __in efx_nic_t *enp,
1154 : : __inout efx_filter_spec_t *spec)
1155 : : {
1156 : : efx_rc_t rc;
1157 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1158 : : efx_filter_spec_t *saved_spec;
1159 : : unsigned int hash;
1160 : : unsigned int depth;
1161 : : unsigned int i;
1162 : : efsys_lock_state_t state;
1163 : : boolean_t locked = B_FALSE;
1164 : :
1165 [ # # ]: 0 : EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
1166 : :
1167 : : hash = ef10_filter_hash(spec);
1168 : :
1169 : 0 : EFSYS_LOCK(enp->en_eslp, state);
1170 : : locked = B_TRUE;
1171 : :
1172 : : depth = 1;
1173 : : for (;;) {
1174 : 0 : i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1);
1175 : : saved_spec = ef10_filter_entry_spec(table, i);
1176 [ # # # # ]: 0 : if (saved_spec && ef10_filter_equal(spec, saved_spec) &&
1177 [ # # ]: 0 : ef10_filter_same_dest(spec, saved_spec) &&
1178 [ # # ]: 0 : saved_spec->efs_priority == EFX_FILTER_PRI_MANUAL) {
1179 : : break;
1180 : : }
1181 [ # # ]: 0 : if (depth == EF10_FILTER_SEARCH_LIMIT) {
1182 : : rc = ENOENT;
1183 : 0 : goto fail1;
1184 : : }
1185 : 0 : depth++;
1186 : : }
1187 : :
1188 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
1189 : : locked = B_FALSE;
1190 : :
1191 : 0 : rc = ef10_filter_delete_internal(enp, i, EFX_FILTER_PRI_MANUAL);
1192 [ # # ]: 0 : if (rc != 0)
1193 : 0 : goto fail2;
1194 : :
1195 : : return (0);
1196 : :
1197 : : fail2:
1198 : : EFSYS_PROBE(fail2);
1199 : :
1200 : : fail1:
1201 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1202 : :
1203 : : if (locked)
1204 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
1205 : :
1206 : : return (rc);
1207 : : }
1208 : :
1209 : : static __checkReturn efx_rc_t
1210 : 0 : efx_mcdi_get_parser_disp_info(
1211 : : __in efx_nic_t *enp,
1212 : : __out_ecount(buffer_length) uint32_t *buffer,
1213 : : __in size_t buffer_length,
1214 : : __in boolean_t encap,
1215 : : __out size_t *list_lengthp)
1216 : : {
1217 : : efx_mcdi_req_t req;
1218 : 0 : EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PARSER_DISP_INFO_IN_LEN,
1219 : : MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX);
1220 : : size_t matches_count;
1221 : : size_t list_size;
1222 : : efx_rc_t rc;
1223 : :
1224 : 0 : req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO;
1225 : 0 : req.emr_in_buf = payload;
1226 : 0 : req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN;
1227 : 0 : req.emr_out_buf = payload;
1228 : 0 : req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX;
1229 : :
1230 [ # # ]: 0 : MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, encap ?
1231 : : MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_ENCAP_RX_MATCHES :
1232 : : MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES);
1233 : :
1234 : 0 : efx_mcdi_execute(enp, &req);
1235 : :
1236 [ # # ]: 0 : if (req.emr_rc != 0) {
1237 : : rc = req.emr_rc;
1238 : 0 : goto fail1;
1239 : : }
1240 : :
1241 [ # # ]: 0 : if (req.emr_out_length_used < MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMIN) {
1242 : : rc = EMSGSIZE;
1243 : 0 : goto fail2;
1244 : : }
1245 : :
1246 : 0 : matches_count = MCDI_OUT_DWORD(req,
1247 : : GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES);
1248 : :
1249 : 0 : if (req.emr_out_length_used <
1250 [ # # ]: 0 : MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(matches_count)) {
1251 : : rc = EMSGSIZE;
1252 : 0 : goto fail3;
1253 : : }
1254 : :
1255 : 0 : *list_lengthp = matches_count;
1256 : :
1257 [ # # ]: 0 : if (buffer_length < matches_count) {
1258 : : rc = ENOSPC;
1259 : 0 : goto fail4;
1260 : : }
1261 : :
1262 : : /*
1263 : : * Check that the elements in the list in the MCDI response are the size
1264 : : * we expect, so we can just copy them directly. Any conversion of the
1265 : : * flags is handled by the caller.
1266 : : */
1267 : : EFX_STATIC_ASSERT(sizeof (uint32_t) ==
1268 : : MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN);
1269 : :
1270 : 0 : list_size = matches_count *
1271 : : MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN;
1272 : : memcpy(buffer,
1273 : 0 : MCDI_OUT2(req, uint32_t,
1274 : : GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES),
1275 : : list_size);
1276 : :
1277 : 0 : return (0);
1278 : :
1279 : : fail4:
1280 : : EFSYS_PROBE(fail4);
1281 : : fail3:
1282 : : EFSYS_PROBE(fail3);
1283 : : fail2:
1284 : : EFSYS_PROBE(fail2);
1285 : : fail1:
1286 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1287 : :
1288 : : return (rc);
1289 : : }
1290 : :
1291 : : __checkReturn efx_rc_t
1292 : 0 : ef10_filter_supported_filters(
1293 : : __in efx_nic_t *enp,
1294 : : __out_ecount(buffer_length) uint32_t *buffer,
1295 : : __in size_t buffer_length,
1296 : : __out size_t *list_lengthp)
1297 : : {
1298 : : efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1299 : : size_t mcdi_list_length;
1300 : : size_t mcdi_encap_list_length;
1301 : : size_t list_length;
1302 : : uint32_t i;
1303 : : uint32_t next_buf_idx;
1304 : : size_t next_buf_length;
1305 : : efx_rc_t rc;
1306 : : boolean_t no_space = B_FALSE;
1307 : : efx_filter_match_flags_t all_filter_flags =
1308 : : (EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_LOC_HOST |
1309 : : EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_REM_PORT |
1310 : : EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT |
1311 : : EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_INNER_VID |
1312 : : EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_IP_PROTO |
1313 : : EFX_FILTER_MATCH_VNI_OR_VSID |
1314 : : EFX_FILTER_MATCH_IFRM_LOC_MAC |
1315 : : EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST |
1316 : : EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST |
1317 : : EFX_FILTER_MATCH_ENCAP_TYPE |
1318 : : EFX_FILTER_MATCH_UNKNOWN_MCAST_DST |
1319 : : EFX_FILTER_MATCH_UNKNOWN_UCAST_DST);
1320 : :
1321 : : /*
1322 : : * Two calls to MC_CMD_GET_PARSER_DISP_INFO are needed: one to get the
1323 : : * list of supported filters for ordinary packets, and then another to
1324 : : * get the list of supported filters for encapsulated packets. To
1325 : : * distinguish the second list from the first, the
1326 : : * EFX_FILTER_MATCH_ENCAP_TYPE flag is added to each filter for
1327 : : * encapsulated packets.
1328 : : */
1329 : 0 : rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length, B_FALSE,
1330 : : &mcdi_list_length);
1331 [ # # ]: 0 : if (rc != 0) {
1332 [ # # ]: 0 : if (rc == ENOSPC)
1333 : : no_space = B_TRUE;
1334 : : else
1335 : 0 : goto fail1;
1336 : : }
1337 : :
1338 : : if (no_space) {
1339 : : next_buf_idx = 0;
1340 : : next_buf_length = 0;
1341 : : } else {
1342 [ # # ]: 0 : EFSYS_ASSERT(mcdi_list_length <= buffer_length);
1343 : 0 : next_buf_idx = mcdi_list_length;
1344 : 0 : next_buf_length = buffer_length - mcdi_list_length;
1345 : : }
1346 : :
1347 [ # # ]: 0 : if (encp->enc_tunnel_encapsulations_supported != 0) {
1348 : 0 : rc = efx_mcdi_get_parser_disp_info(enp, &buffer[next_buf_idx],
1349 : : next_buf_length, B_TRUE, &mcdi_encap_list_length);
1350 [ # # ]: 0 : if (rc != 0) {
1351 [ # # ]: 0 : if (rc == ENOSPC) {
1352 : : no_space = B_TRUE;
1353 [ # # ]: 0 : } else if (rc == EINVAL) {
1354 : : /*
1355 : : * Do not fail if the MCDI do not recognize the
1356 : : * query for encapsulated packet filters.
1357 : : */
1358 : 0 : mcdi_encap_list_length = 0;
1359 : : } else
1360 : 0 : goto fail2;
1361 : : } else {
1362 : : for (i = next_buf_idx;
1363 [ # # ]: 0 : i < next_buf_idx + mcdi_encap_list_length; i++)
1364 : 0 : buffer[i] |= EFX_FILTER_MATCH_ENCAP_TYPE;
1365 : : }
1366 : : } else {
1367 : 0 : mcdi_encap_list_length = 0;
1368 : : }
1369 : :
1370 [ # # ]: 0 : if (no_space) {
1371 : 0 : *list_lengthp = mcdi_list_length + mcdi_encap_list_length;
1372 : : rc = ENOSPC;
1373 : 0 : goto fail3;
1374 : : }
1375 : :
1376 : : /*
1377 : : * The static assertions in ef10_filter_init() ensure that the values of
1378 : : * the EFX_FILTER_MATCH flags match those used by MCDI, so they don't
1379 : : * need to be converted.
1380 : : *
1381 : : * In case support is added to MCDI for additional flags, remove any
1382 : : * matches from the list which include flags we don't support. The order
1383 : : * of the matches is preserved as they are ordered from highest to
1384 : : * lowest priority.
1385 : : */
1386 [ # # ]: 0 : EFSYS_ASSERT(mcdi_list_length + mcdi_encap_list_length <=
1387 : : buffer_length);
1388 : : list_length = 0;
1389 [ # # ]: 0 : for (i = 0; i < mcdi_list_length + mcdi_encap_list_length; i++) {
1390 [ # # ]: 0 : if ((buffer[i] & ~all_filter_flags) == 0) {
1391 : 0 : buffer[list_length] = buffer[i];
1392 : 0 : list_length++;
1393 : : }
1394 : : }
1395 : :
1396 : 0 : *list_lengthp = list_length;
1397 : :
1398 : 0 : return (0);
1399 : :
1400 : : fail3:
1401 : : EFSYS_PROBE(fail3);
1402 : : fail2:
1403 : : EFSYS_PROBE(fail2);
1404 : : fail1:
1405 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1406 : :
1407 : : return (rc);
1408 : : }
1409 : :
1410 : : static __checkReturn efx_rc_t
1411 : 0 : ef10_filter_insert_unicast(
1412 : : __in efx_nic_t *enp,
1413 : : __in_ecount(6) uint8_t const *addr,
1414 : : __in efx_filter_flags_t filter_flags)
1415 : : {
1416 : 0 : ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1417 : : efx_filter_spec_t spec;
1418 : : efx_rc_t rc;
1419 : :
1420 : : /* Insert the filter for the local station address */
1421 : 0 : efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1422 : : filter_flags,
1423 : : eftp->eft_default_rxq);
1424 : 0 : rc = efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC,
1425 : : addr);
1426 [ # # ]: 0 : if (rc != 0)
1427 : 0 : goto fail1;
1428 : :
1429 : 0 : rc = ef10_filter_add_internal(enp, &spec, EFX_FILTER_REPLACEMENT_NEVER,
1430 : 0 : &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]);
1431 [ # # ]: 0 : if (rc != 0)
1432 : 0 : goto fail2;
1433 : :
1434 : 0 : eftp->eft_unicst_filter_count++;
1435 [ # # ]: 0 : EFSYS_ASSERT(eftp->eft_unicst_filter_count <=
1436 : : EFX_EF10_FILTER_UNICAST_FILTERS_MAX);
1437 : :
1438 : : return (0);
1439 : :
1440 : : fail2:
1441 : : EFSYS_PROBE(fail2);
1442 : : fail1:
1443 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1444 : : return (rc);
1445 : : }
1446 : :
1447 : : static __checkReturn efx_rc_t
1448 : 0 : ef10_filter_insert_all_unicast(
1449 : : __in efx_nic_t *enp,
1450 : : __in efx_filter_flags_t filter_flags)
1451 : : {
1452 : 0 : ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1453 : : efx_filter_spec_t spec;
1454 : : efx_rc_t rc;
1455 : :
1456 : : /* Insert the unknown unicast filter */
1457 : 0 : efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1458 : : filter_flags,
1459 : : eftp->eft_default_rxq);
1460 : 0 : rc = efx_filter_spec_set_uc_def(&spec);
1461 [ # # ]: 0 : if (rc != 0)
1462 : 0 : goto fail1;
1463 : 0 : rc = ef10_filter_add_internal(enp, &spec, EFX_FILTER_REPLACEMENT_NEVER,
1464 : 0 : &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]);
1465 [ # # ]: 0 : if (rc != 0)
1466 : 0 : goto fail2;
1467 : :
1468 : 0 : eftp->eft_unicst_filter_count++;
1469 [ # # ]: 0 : EFSYS_ASSERT(eftp->eft_unicst_filter_count <=
1470 : : EFX_EF10_FILTER_UNICAST_FILTERS_MAX);
1471 : :
1472 : : return (0);
1473 : :
1474 : : fail2:
1475 : : EFSYS_PROBE(fail2);
1476 : : fail1:
1477 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1478 : : return (rc);
1479 : : }
1480 : :
1481 : : static __checkReturn efx_rc_t
1482 : 0 : ef10_filter_insert_multicast_list(
1483 : : __in efx_nic_t *enp,
1484 : : __in boolean_t mulcst,
1485 : : __in boolean_t brdcst,
1486 : : __in_ecount(6*count) uint8_t const *addrs,
1487 : : __in uint32_t count,
1488 : : __in efx_filter_flags_t filter_flags,
1489 : : __in boolean_t rollback)
1490 : : {
1491 : 0 : ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1492 : : efx_filter_spec_t spec;
1493 : : uint8_t addr[6];
1494 : : uint32_t i;
1495 : : uint32_t filter_index;
1496 : : uint32_t filter_count;
1497 : : efx_rc_t rc;
1498 : :
1499 [ # # ]: 0 : if (mulcst == B_FALSE)
1500 : : count = 0;
1501 : :
1502 [ # # # # ]: 0 : if (count + (brdcst ? 1 : 0) >
1503 : : EFX_ARRAY_SIZE(eftp->eft_mulcst_filter_indexes)) {
1504 : : /* Too many MAC addresses */
1505 : : rc = EINVAL;
1506 : 0 : goto fail1;
1507 : : }
1508 : :
1509 : : /* Insert/renew multicast address list filters */
1510 : : filter_count = 0;
1511 [ # # ]: 0 : for (i = 0; i < count; i++) {
1512 : 0 : efx_filter_spec_init_rx(&spec,
1513 : : EFX_FILTER_PRI_AUTO,
1514 : : filter_flags,
1515 : : eftp->eft_default_rxq);
1516 : :
1517 : 0 : rc = efx_filter_spec_set_eth_local(&spec,
1518 : : EFX_FILTER_SPEC_VID_UNSPEC,
1519 : 0 : &addrs[i * EFX_MAC_ADDR_LEN]);
1520 [ # # ]: 0 : if (rc != 0) {
1521 [ # # ]: 0 : if (rollback == B_TRUE) {
1522 : : /* Only stop upon failure if told to rollback */
1523 : 0 : goto rollback;
1524 : : } else {
1525 : : /*
1526 : : * Don't try to add a filter with a corrupt
1527 : : * specification.
1528 : : */
1529 : 0 : continue;
1530 : : }
1531 : : }
1532 : :
1533 : 0 : rc = ef10_filter_add_internal(enp, &spec,
1534 : : EFX_FILTER_REPLACEMENT_NEVER, &filter_index);
1535 : :
1536 [ # # ]: 0 : if (rc == 0) {
1537 : 0 : eftp->eft_mulcst_filter_indexes[filter_count] =
1538 : : filter_index;
1539 : 0 : filter_count++;
1540 [ # # ]: 0 : } else if (rollback == B_TRUE) {
1541 : : /* Only stop upon failure if told to rollback */
1542 : 0 : goto rollback;
1543 : : }
1544 : :
1545 : : }
1546 : :
1547 [ # # ]: 0 : if (brdcst == B_TRUE) {
1548 : : /* Insert/renew broadcast address filter */
1549 : 0 : efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1550 : : filter_flags,
1551 : : eftp->eft_default_rxq);
1552 : :
1553 : 0 : EFX_MAC_BROADCAST_ADDR_SET(addr);
1554 : 0 : rc = efx_filter_spec_set_eth_local(&spec,
1555 : : EFX_FILTER_SPEC_VID_UNSPEC, addr);
1556 [ # # ]: 0 : if ((rc != 0) && (rollback == B_TRUE)) {
1557 : : /* Only stop upon failure if told to rollback */
1558 : 0 : goto rollback;
1559 : : }
1560 : :
1561 : 0 : rc = ef10_filter_add_internal(enp, &spec,
1562 : : EFX_FILTER_REPLACEMENT_NEVER, &filter_index);
1563 : :
1564 [ # # ]: 0 : if (rc == 0) {
1565 : 0 : eftp->eft_mulcst_filter_indexes[filter_count] =
1566 : : filter_index;
1567 : 0 : filter_count++;
1568 [ # # ]: 0 : } else if (rollback == B_TRUE) {
1569 : : /* Only stop upon failure if told to rollback */
1570 : 0 : goto rollback;
1571 : : }
1572 : : }
1573 : :
1574 : 0 : eftp->eft_mulcst_filter_count = filter_count;
1575 : 0 : eftp->eft_using_all_mulcst = B_FALSE;
1576 : :
1577 : 0 : return (0);
1578 : :
1579 : 0 : rollback:
1580 : : /* Remove any filters we have inserted */
1581 : : i = filter_count;
1582 [ # # ]: 0 : while (i--) {
1583 : 0 : ef10_filter_delete_auto(enp,
1584 : : eftp->eft_mulcst_filter_indexes[i]);
1585 : : }
1586 : 0 : eftp->eft_mulcst_filter_count = 0;
1587 : :
1588 : : fail1:
1589 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1590 : :
1591 : : return (rc);
1592 : : }
1593 : :
1594 : : static __checkReturn efx_rc_t
1595 : 0 : ef10_filter_insert_all_multicast(
1596 : : __in efx_nic_t *enp,
1597 : : __in efx_filter_flags_t filter_flags)
1598 : : {
1599 : 0 : ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1600 : : efx_filter_spec_t spec;
1601 : : efx_rc_t rc;
1602 : :
1603 : : /* Insert the unknown multicast filter */
1604 : 0 : efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1605 : : filter_flags,
1606 : : eftp->eft_default_rxq);
1607 : 0 : rc = efx_filter_spec_set_mc_def(&spec);
1608 [ # # ]: 0 : if (rc != 0)
1609 : 0 : goto fail1;
1610 : :
1611 : 0 : rc = ef10_filter_add_internal(enp, &spec, EFX_FILTER_REPLACEMENT_NEVER,
1612 : : &eftp->eft_mulcst_filter_indexes[0]);
1613 [ # # ]: 0 : if (rc != 0)
1614 : 0 : goto fail2;
1615 : :
1616 : 0 : eftp->eft_mulcst_filter_count = 1;
1617 : 0 : eftp->eft_using_all_mulcst = B_TRUE;
1618 : :
1619 : : /*
1620 : : * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic.
1621 : : */
1622 : :
1623 : 0 : return (0);
1624 : :
1625 : : fail2:
1626 : : EFSYS_PROBE(fail2);
1627 : : fail1:
1628 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1629 : :
1630 : : return (rc);
1631 : : }
1632 : :
1633 : : typedef struct ef10_filter_encap_entry_s {
1634 : : uint16_t ether_type;
1635 : : efx_tunnel_protocol_t encap_type;
1636 : : uint32_t inner_frame_match;
1637 : : } ef10_filter_encap_entry_t;
1638 : :
1639 : : #define EF10_ENCAP_FILTER_ENTRY(ipv, encap_type, inner_frame_match) \
1640 : : { EFX_ETHER_TYPE_##ipv, EFX_TUNNEL_PROTOCOL_##encap_type, \
1641 : : EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_##inner_frame_match }
1642 : :
1643 : : static ef10_filter_encap_entry_t ef10_filter_encap_list[] = {
1644 : : EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, UCAST_DST),
1645 : : EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, MCAST_DST),
1646 : : EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, UCAST_DST),
1647 : : EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, MCAST_DST),
1648 : :
1649 : : EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, UCAST_DST),
1650 : : EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, MCAST_DST),
1651 : : EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, UCAST_DST),
1652 : : EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, MCAST_DST),
1653 : :
1654 : : EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, UCAST_DST),
1655 : : EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, MCAST_DST),
1656 : : EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, UCAST_DST),
1657 : : EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, MCAST_DST),
1658 : : };
1659 : :
1660 : : #undef EF10_ENCAP_FILTER_ENTRY
1661 : :
1662 : : static __checkReturn efx_rc_t
1663 : 0 : ef10_filter_insert_encap_filters(
1664 : : __in efx_nic_t *enp,
1665 : : __in boolean_t mulcst,
1666 : : __in efx_filter_flags_t filter_flags)
1667 : : {
1668 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1669 : : uint32_t i;
1670 : : efx_rc_t rc;
1671 : :
1672 : : EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(ef10_filter_encap_list) <=
1673 : : EFX_ARRAY_SIZE(table->eft_encap_filter_indexes));
1674 : :
1675 : : /*
1676 : : * On Medford, full-featured firmware can identify packets as being
1677 : : * tunnel encapsulated, even if no encapsulated packet offloads are in
1678 : : * use. When packets are identified as such, ordinary filters are not
1679 : : * applied, only ones specific to encapsulated packets. Hence we need to
1680 : : * insert filters for encapsulated packets in order to receive them.
1681 : : *
1682 : : * Separate filters need to be inserted for each ether type,
1683 : : * encapsulation type, and inner frame type (unicast or multicast). To
1684 : : * keep things simple and reduce the number of filters needed, catch-all
1685 : : * filters for all combinations of types are inserted, even if
1686 : : * all_unicst or all_mulcst have not been set. (These catch-all filters
1687 : : * may well, however, fail to insert on unprivileged functions.)
1688 : : */
1689 : 0 : table->eft_encap_filter_count = 0;
1690 [ # # ]: 0 : for (i = 0; i < EFX_ARRAY_SIZE(ef10_filter_encap_list); i++) {
1691 : : efx_filter_spec_t spec;
1692 : : ef10_filter_encap_entry_t *encap_filter =
1693 : : &ef10_filter_encap_list[i];
1694 : :
1695 : : /*
1696 : : * Skip multicast filters if we've not been asked for
1697 : : * any multicast traffic.
1698 : : */
1699 [ # # ]: 0 : if ((mulcst == B_FALSE) &&
1700 [ # # ]: 0 : (encap_filter->inner_frame_match ==
1701 : : EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST))
1702 : 0 : continue;
1703 : :
1704 : 0 : efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1705 : : filter_flags,
1706 : : table->eft_default_rxq);
1707 : 0 : efx_filter_spec_set_ether_type(&spec, encap_filter->ether_type);
1708 : 0 : rc = efx_filter_spec_set_encap_type(&spec,
1709 : : encap_filter->encap_type,
1710 : 0 : encap_filter->inner_frame_match);
1711 [ # # ]: 0 : if (rc != 0)
1712 : 0 : goto fail1;
1713 : :
1714 : 0 : rc = ef10_filter_add_internal(enp, &spec,
1715 : : EFX_FILTER_REPLACEMENT_NEVER,
1716 : : &table->eft_encap_filter_indexes[
1717 : 0 : table->eft_encap_filter_count]);
1718 [ # # ]: 0 : if (rc != 0) {
1719 [ # # ]: 0 : if (rc != EACCES)
1720 : 0 : goto fail2;
1721 : : } else {
1722 : 0 : table->eft_encap_filter_count++;
1723 : : }
1724 : : }
1725 : :
1726 : : return (0);
1727 : :
1728 : : fail2:
1729 : : EFSYS_PROBE(fail2);
1730 : : fail1:
1731 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1732 : :
1733 : : return (rc);
1734 : : }
1735 : :
1736 : : static void
1737 : 0 : ef10_filter_remove_old(
1738 : : __in efx_nic_t *enp)
1739 : : {
1740 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1741 : : uint32_t i;
1742 : :
1743 [ # # ]: 0 : for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) {
1744 : : if (ef10_filter_entry_is_auto_old(table, i)) {
1745 : 0 : ef10_filter_delete_auto(enp, i);
1746 : : }
1747 : : }
1748 : 0 : }
1749 : :
1750 : :
1751 : : static __checkReturn efx_rc_t
1752 : 0 : ef10_filter_get_workarounds(
1753 : : __in efx_nic_t *enp)
1754 : : {
1755 : : efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1756 : 0 : uint32_t implemented = 0;
1757 : 0 : uint32_t enabled = 0;
1758 : : efx_rc_t rc;
1759 : :
1760 : 0 : rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled);
1761 [ # # ]: 0 : if (rc == 0) {
1762 : : /* Check if chained multicast filter support is enabled */
1763 [ # # ]: 0 : if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807)
1764 : 0 : encp->enc_bug26807_workaround = B_TRUE;
1765 : : else
1766 : 0 : encp->enc_bug26807_workaround = B_FALSE;
1767 [ # # ]: 0 : } else if (rc == ENOTSUP) {
1768 : : /*
1769 : : * Firmware is too old to support GET_WORKAROUNDS, and support
1770 : : * for this workaround was implemented later.
1771 : : */
1772 : 0 : encp->enc_bug26807_workaround = B_FALSE;
1773 : : } else {
1774 : 0 : goto fail1;
1775 : : }
1776 : :
1777 : : return (0);
1778 : :
1779 : : fail1:
1780 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1781 : :
1782 : 0 : return (rc);
1783 : :
1784 : : }
1785 : :
1786 : : static void
1787 : 0 : ef10_filter_remove_all_existing_filters(
1788 : : __in efx_nic_t *enp)
1789 : : {
1790 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1791 : : efx_port_t *epp = &(enp->en_port);
1792 : : unsigned int i;
1793 : :
1794 [ # # ]: 0 : for (i = 0; i < table->eft_unicst_filter_count; i++) {
1795 : 0 : ef10_filter_delete_auto(enp,
1796 : : table->eft_unicst_filter_indexes[i]);
1797 : : }
1798 : 0 : table->eft_unicst_filter_count = 0;
1799 : :
1800 [ # # ]: 0 : for (i = 0; i < table->eft_mulcst_filter_count; i++) {
1801 : 0 : ef10_filter_delete_auto(enp,
1802 : : table->eft_mulcst_filter_indexes[i]);
1803 : : }
1804 : 0 : table->eft_mulcst_filter_count = 0;
1805 : :
1806 [ # # ]: 0 : for (i = 0; i < table->eft_encap_filter_count; i++) {
1807 : 0 : ef10_filter_delete_auto(enp,
1808 : : table->eft_encap_filter_indexes[i]);
1809 : : }
1810 : 0 : table->eft_encap_filter_count = 0;
1811 : :
1812 : 0 : epp->ep_all_unicst_inserted = B_FALSE;
1813 : 0 : epp->ep_all_mulcst_inserted = B_FALSE;
1814 : 0 : }
1815 : :
1816 : : static void
1817 : 0 : ef10_filter_mark_old_filters(
1818 : : __in efx_nic_t *enp)
1819 : : {
1820 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1821 : : unsigned int i;
1822 : :
1823 [ # # ]: 0 : for (i = 0; i < table->eft_unicst_filter_count; i++) {
1824 : 0 : ef10_filter_set_entry_auto_old(table,
1825 : : table->eft_unicst_filter_indexes[i]);
1826 : : }
1827 [ # # ]: 0 : for (i = 0; i < table->eft_mulcst_filter_count; i++) {
1828 : 0 : ef10_filter_set_entry_auto_old(table,
1829 : : table->eft_mulcst_filter_indexes[i]);
1830 : : }
1831 [ # # ]: 0 : for (i = 0; i < table->eft_encap_filter_count; i++) {
1832 : 0 : ef10_filter_set_entry_auto_old(table,
1833 : : table->eft_encap_filter_indexes[i]);
1834 : : }
1835 : 0 : }
1836 : :
1837 : : static __checkReturn efx_rc_t
1838 : 0 : ef10_filter_insert_renew_unicst_filters(
1839 : : __in efx_nic_t *enp,
1840 : : __in_ecount(6) uint8_t const *mac_addr,
1841 : : __in boolean_t all_unicst,
1842 : : __in efx_filter_flags_t filter_flags,
1843 : : __out boolean_t *all_unicst_inserted)
1844 : : {
1845 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1846 : : efx_port_t *epp = &(enp->en_port);
1847 : : efx_rc_t rc;
1848 : :
1849 : : /*
1850 : : * Firmware does not perform chaining on unicast filters. As traffic is
1851 : : * therefore only delivered to the first matching filter, we should
1852 : : * always insert the specific filter for our MAC address, to try and
1853 : : * ensure we get that traffic.
1854 : : *
1855 : : * (If the filter for our MAC address has already been inserted by
1856 : : * another function, we won't receive traffic sent to us, even if we
1857 : : * insert a unicast mismatch filter. To prevent traffic stealing, this
1858 : : * therefore relies on the privilege model only allowing functions to
1859 : : * insert filters for their own MAC address unless explicitly given
1860 : : * additional privileges by the user. This also means that, even on a
1861 : : * privileged function, inserting a unicast mismatch filter may not
1862 : : * catch all traffic in multi PCI function scenarios.)
1863 : : */
1864 : 0 : table->eft_unicst_filter_count = 0;
1865 : 0 : rc = ef10_filter_insert_unicast(enp, mac_addr, filter_flags);
1866 : 0 : *all_unicst_inserted = B_FALSE;
1867 [ # # ]: 0 : if (all_unicst || (rc != 0)) {
1868 : : efx_rc_t all_unicst_rc;
1869 : :
1870 : 0 : all_unicst_rc = ef10_filter_insert_all_unicast(enp,
1871 : : filter_flags);
1872 [ # # ]: 0 : if (all_unicst_rc == 0) {
1873 : 0 : *all_unicst_inserted = B_TRUE;
1874 : 0 : epp->ep_all_unicst_inserted = B_TRUE;
1875 [ # # ]: 0 : } else if (rc != 0)
1876 : 0 : goto fail1;
1877 : : }
1878 : :
1879 : : return (0);
1880 : :
1881 : : fail1:
1882 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1883 : :
1884 : 0 : return (rc);
1885 : : }
1886 : :
1887 : : static __checkReturn efx_rc_t
1888 : 0 : ef10_filter_insert_renew_mulcst_filters(
1889 : : __in efx_nic_t *enp,
1890 : : __in boolean_t mulcst,
1891 : : __in boolean_t all_mulcst,
1892 : : __in boolean_t brdcst,
1893 : : __in_ecount(6*count) uint8_t const *addrs,
1894 : : __in uint32_t count,
1895 : : __in efx_filter_flags_t filter_flags,
1896 : : __in boolean_t all_unicst_inserted,
1897 : : __out boolean_t *all_mulcst_inserted)
1898 : : {
1899 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1900 : : efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1901 : : efx_port_t *epp = &(enp->en_port);
1902 : : efx_rc_t rc;
1903 : :
1904 : 0 : *all_mulcst_inserted = B_FALSE;
1905 : :
1906 [ # # ]: 0 : if (all_mulcst == B_TRUE) {
1907 : : efx_rc_t all_mulcst_rc;
1908 : :
1909 : : /*
1910 : : * Insert the all multicast filter. If that fails, try to insert
1911 : : * all of our multicast filters (but without rollback on
1912 : : * failure).
1913 : : */
1914 : 0 : all_mulcst_rc = ef10_filter_insert_all_multicast(enp,
1915 : : filter_flags);
1916 [ # # ]: 0 : if (all_mulcst_rc == 0) {
1917 : 0 : epp->ep_all_mulcst_inserted = B_TRUE;
1918 : 0 : *all_mulcst_inserted = B_TRUE;
1919 : : } else {
1920 : 0 : rc = ef10_filter_insert_multicast_list(enp, B_TRUE,
1921 : : brdcst, addrs, count, filter_flags, B_FALSE);
1922 [ # # ]: 0 : if (rc != 0)
1923 : 0 : goto fail1;
1924 : : }
1925 : : } else {
1926 : : /*
1927 : : * Insert filters for multicast addresses.
1928 : : * If any insertion fails, then rollback and try to insert the
1929 : : * all multicast filter instead.
1930 : : * If that also fails, try to insert all of the multicast
1931 : : * filters (but without rollback on failure).
1932 : : */
1933 : 0 : rc = ef10_filter_insert_multicast_list(enp, mulcst, brdcst,
1934 : : addrs, count, filter_flags, B_TRUE);
1935 [ # # ]: 0 : if (rc != 0) {
1936 [ # # ]: 0 : if ((table->eft_using_all_mulcst == B_FALSE) &&
1937 [ # # ]: 0 : (encp->enc_bug26807_workaround == B_TRUE)) {
1938 : : /*
1939 : : * Multicast filter chaining is on, so remove
1940 : : * old filters before inserting the multicast
1941 : : * all filter to avoid duplicate delivery caused
1942 : : * by packets matching multiple filters.
1943 : : */
1944 : 0 : ef10_filter_remove_old(enp);
1945 [ # # ]: 0 : if (all_unicst_inserted == B_FALSE)
1946 : 0 : epp->ep_all_unicst_inserted = B_FALSE;
1947 [ # # ]: 0 : if (*all_mulcst_inserted == B_FALSE)
1948 : 0 : epp->ep_all_mulcst_inserted = B_FALSE;
1949 : : }
1950 : :
1951 : 0 : rc = ef10_filter_insert_all_multicast(enp,
1952 : : filter_flags);
1953 [ # # ]: 0 : if (rc == 0) {
1954 : 0 : epp->ep_all_mulcst_inserted = B_TRUE;
1955 : 0 : *all_mulcst_inserted = B_TRUE;
1956 : : } else {
1957 : 0 : rc = ef10_filter_insert_multicast_list(enp,
1958 : : mulcst, brdcst,
1959 : : addrs, count, filter_flags, B_FALSE);
1960 [ # # ]: 0 : if (rc != 0)
1961 : 0 : goto fail2;
1962 : : }
1963 : : }
1964 : : }
1965 : :
1966 : : return (0);
1967 : :
1968 : : fail2:
1969 : : EFSYS_PROBE1(fail2, efx_rc_t, rc);
1970 : :
1971 : : fail1:
1972 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
1973 : :
1974 : : return (rc);
1975 : : }
1976 : :
1977 : : /*
1978 : : * Reconfigure all filters.
1979 : : * If all_unicst and/or all mulcst filters cannot be applied then
1980 : : * return ENOTSUP (Note the filters for the specified addresses are
1981 : : * still applied in this case).
1982 : : */
1983 : : __checkReturn efx_rc_t
1984 : 0 : ef10_filter_reconfigure(
1985 : : __in efx_nic_t *enp,
1986 : : __in_ecount(6) uint8_t const *mac_addr,
1987 : : __in boolean_t all_unicst,
1988 : : __in boolean_t mulcst,
1989 : : __in boolean_t all_mulcst,
1990 : : __in boolean_t brdcst,
1991 : : __in_ecount(6*count) uint8_t const *addrs,
1992 : : __in uint32_t count)
1993 : : {
1994 : : efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1995 : : efx_port_t *epp = &(enp->en_port);
1996 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1997 : : efx_filter_flags_t filter_flags;
1998 : : unsigned int i;
1999 : 0 : boolean_t all_unicst_inserted = B_FALSE;
2000 : 0 : boolean_t all_mulcst_inserted = B_FALSE;
2001 : : efx_rc_t rc;
2002 : :
2003 [ # # ]: 0 : if (table->eft_default_rxq == NULL) {
2004 : : /*
2005 : : * Filters direct traffic to the default RXQ, and so cannot be
2006 : : * inserted until it is available. Any currently configured
2007 : : * filters must be removed (ignore errors in case the MC
2008 : : * has rebooted, which removes hardware filters).
2009 : : */
2010 : 0 : ef10_filter_remove_all_existing_filters(enp);
2011 : 0 : return (0);
2012 : : }
2013 : :
2014 [ # # ]: 0 : if (table->eft_using_rss)
2015 : : filter_flags = EFX_FILTER_FLAG_RX_RSS;
2016 : : else
2017 : : filter_flags = 0;
2018 : :
2019 : : /* Mark old filters which may need to be removed */
2020 : 0 : ef10_filter_mark_old_filters(enp);
2021 : :
2022 : : /* Insert or renew unicast filters */
2023 : 0 : rc = ef10_filter_insert_renew_unicst_filters(enp, mac_addr, all_unicst,
2024 : : filter_flags,
2025 : : &all_unicst_inserted);
2026 [ # # ]: 0 : if (rc != 0)
2027 : 0 : goto fail1;
2028 : :
2029 : : /*
2030 : : * WORKAROUND_BUG26807 controls firmware support for chained multicast
2031 : : * filters, and can only be enabled or disabled when the hardware filter
2032 : : * table is empty.
2033 : : *
2034 : : * Chained multicast filters require support from the datapath firmware,
2035 : : * and may not be available (e.g. low-latency variants or old Huntington
2036 : : * firmware).
2037 : : *
2038 : : * Firmware will reset (FLR) functions which have inserted filters in
2039 : : * the hardware filter table when the workaround is enabled/disabled.
2040 : : * Functions without any hardware filters are not reset.
2041 : : *
2042 : : * Re-check if the workaround is enabled after adding unicast hardware
2043 : : * filters. This ensures that encp->enc_bug26807_workaround matches the
2044 : : * firmware state, and that later changes to enable/disable the
2045 : : * workaround will result in this function seeing a reset (FLR).
2046 : : *
2047 : : * In common-code drivers, we only support multiple PCI function
2048 : : * scenarios with firmware that supports multicast chaining, so we can
2049 : : * assume it is enabled for such cases and hence simplify the filter
2050 : : * insertion logic. Firmware that does not support multicast chaining
2051 : : * does not support multiple PCI function configurations either, so
2052 : : * filter insertion is much simpler and the same strategies can still be
2053 : : * used.
2054 : : */
2055 [ # # ]: 0 : if ((rc = ef10_filter_get_workarounds(enp)) != 0)
2056 : 0 : goto fail2;
2057 : :
2058 [ # # ]: 0 : if ((table->eft_using_all_mulcst != all_mulcst) &&
2059 [ # # ]: 0 : (encp->enc_bug26807_workaround == B_TRUE)) {
2060 : : /*
2061 : : * Multicast filter chaining is enabled, so traffic that matches
2062 : : * more than one multicast filter will be replicated and
2063 : : * delivered to multiple recipients. To avoid this duplicate
2064 : : * delivery, remove old multicast filters before inserting new
2065 : : * multicast filters.
2066 : : */
2067 : 0 : ef10_filter_remove_old(enp);
2068 [ # # ]: 0 : if (all_unicst_inserted == B_FALSE)
2069 : 0 : epp->ep_all_unicst_inserted = B_FALSE;
2070 : :
2071 : 0 : epp->ep_all_mulcst_inserted = B_FALSE;
2072 : : }
2073 : :
2074 : : /* Insert or renew multicast filters */
2075 : 0 : rc = ef10_filter_insert_renew_mulcst_filters(enp, mulcst, all_mulcst,
2076 : : brdcst, addrs, count,
2077 : : filter_flags,
2078 : : all_unicst_inserted,
2079 : : &all_mulcst_inserted);
2080 [ # # ]: 0 : if (rc != 0)
2081 : 0 : goto fail3;
2082 : :
2083 [ # # ]: 0 : if (encp->enc_tunnel_encapsulations_supported != 0) {
2084 : : /* Try to insert filters for encapsulated packets. */
2085 : 0 : (void) ef10_filter_insert_encap_filters(enp,
2086 : : mulcst || all_mulcst || brdcst,
2087 : : filter_flags);
2088 : : }
2089 : :
2090 : : /* Remove old filters which were not renewed */
2091 : 0 : ef10_filter_remove_old(enp);
2092 [ # # ]: 0 : if (all_unicst_inserted == B_FALSE)
2093 : 0 : epp->ep_all_unicst_inserted = B_FALSE;
2094 [ # # ]: 0 : if (all_mulcst_inserted == B_FALSE)
2095 : 0 : epp->ep_all_mulcst_inserted = B_FALSE;
2096 : :
2097 : : /* report if any optional flags were rejected */
2098 [ # # # # : 0 : if (((all_unicst != B_FALSE) && (all_unicst_inserted == B_FALSE)) ||
# # ]
2099 [ # # ]: 0 : ((all_mulcst != B_FALSE) && (all_mulcst_inserted == B_FALSE))) {
2100 : : rc = ENOTSUP;
2101 : : }
2102 : :
2103 : : return (rc);
2104 : :
2105 : : fail3:
2106 : : EFSYS_PROBE(fail3);
2107 : 0 : fail2:
2108 : : EFSYS_PROBE(fail2);
2109 : 0 : fail1:
2110 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
2111 : :
2112 : : /* Clear auto old flags */
2113 [ # # ]: 0 : for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) {
2114 : : if (ef10_filter_entry_is_auto_old(table, i)) {
2115 : 0 : ef10_filter_set_entry_not_auto_old(table, i);
2116 : : }
2117 : : }
2118 : :
2119 : : return (rc);
2120 : : }
2121 : :
2122 : : __checkReturn efx_rc_t
2123 : 0 : ef10_filter_get_count(
2124 : : __in efx_nic_t *enp,
2125 : : __out uint32_t *countp)
2126 : : {
2127 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
2128 : : uint32_t filter_count;
2129 : :
2130 [ # # ]: 0 : EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
2131 [ # # ]: 0 : EFSYS_ASSERT(countp != NULL);
2132 : :
2133 : 0 : filter_count = table->eft_unicst_filter_count +
2134 : 0 : table->eft_mulcst_filter_count +
2135 : 0 : table->eft_encap_filter_count;
2136 : :
2137 : 0 : *countp = filter_count;
2138 : :
2139 : 0 : return (0);
2140 : : }
2141 : :
2142 : : void
2143 : 0 : ef10_filter_get_default_rxq(
2144 : : __in efx_nic_t *enp,
2145 : : __out efx_rxq_t **erpp,
2146 : : __out boolean_t *using_rss)
2147 : : {
2148 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
2149 : :
2150 : 0 : *erpp = table->eft_default_rxq;
2151 : 0 : *using_rss = table->eft_using_rss;
2152 : 0 : }
2153 : :
2154 : :
2155 : : void
2156 : 0 : ef10_filter_default_rxq_set(
2157 : : __in efx_nic_t *enp,
2158 : : __in efx_rxq_t *erp,
2159 : : __in boolean_t using_rss)
2160 : : {
2161 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
2162 : :
2163 : : #if EFSYS_OPT_RX_SCALE
2164 [ # # # # ]: 0 : EFSYS_ASSERT((using_rss == B_FALSE) ||
2165 : : (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID));
2166 : 0 : table->eft_using_rss = using_rss;
2167 : : #else
2168 : : EFSYS_ASSERT(using_rss == B_FALSE);
2169 : : table->eft_using_rss = B_FALSE;
2170 : : #endif
2171 : 0 : table->eft_default_rxq = erp;
2172 : 0 : }
2173 : :
2174 : : void
2175 : 0 : ef10_filter_default_rxq_clear(
2176 : : __in efx_nic_t *enp)
2177 : : {
2178 : 0 : ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
2179 : :
2180 : 0 : table->eft_default_rxq = NULL;
2181 : 0 : table->eft_using_rss = B_FALSE;
2182 : 0 : }
2183 : :
2184 : :
2185 : : #endif /* EFSYS_OPT_FILTER */
2186 : :
2187 : : #endif /* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */
|