1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright(c) 2019-2021 Xilinx, Inc.
4 * Copyright(c) 2018-2019 Solarflare Communications Inc.
5 */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10
11 #if EFSYS_OPT_EVB
12
13 #if EFSYS_OPT_SIENA
14 static const efx_evb_ops_t __efx_evb_dummy_ops = {
15 NULL, /* eeo_init */
16 NULL, /* eeo_fini */
17 NULL, /* eeo_vswitch_alloc */
18 NULL, /* eeo_vswitch_free */
19 NULL, /* eeo_vport_alloc */
20 NULL, /* eeo_vport_free */
21 NULL, /* eeo_vport_mac_addr_add */
22 NULL, /* eeo_vport_mac_addr_del */
23 NULL, /* eeo_vadaptor_alloc */
24 NULL, /* eeo_vadaptor_free */
25 NULL, /* eeo_vport_assign */
26 NULL, /* eeo_vport_reconfigure */
27 NULL, /* eeo_vport_stats */
28 };
29 #endif /* EFSYS_OPT_SIENA */
30
31 #if EFX_OPTS_EF10()
32 static const efx_evb_ops_t __efx_evb_ef10_ops = {
33 ef10_evb_init, /* eeo_init */
34 ef10_evb_fini, /* eeo_fini */
35 ef10_evb_vswitch_alloc, /* eeo_vswitch_alloc */
36 ef10_evb_vswitch_free, /* eeo_vswitch_free */
37 ef10_evb_vport_alloc, /* eeo_vport_alloc */
38 ef10_evb_vport_free, /* eeo_vport_free */
39 ef10_evb_vport_mac_addr_add, /* eeo_vport_mac_addr_add */
40 ef10_evb_vport_mac_addr_del, /* eeo_vport_mac_addr_del */
41 ef10_evb_vadaptor_alloc, /* eeo_vadaptor_alloc */
42 ef10_evb_vadaptor_free, /* eeo_vadaptor_free */
43 ef10_evb_vport_assign, /* eeo_vport_assign */
44 ef10_evb_vport_reconfigure, /* eeo_vport_reconfigure */
45 ef10_evb_vport_stats, /* eeo_vport_stats */
46 };
47 #endif /* EFX_OPTS_EF10() */
48
49 #if EFSYS_OPT_RIVERHEAD
50 static const efx_evb_ops_t __efx_evb_rhead_ops = {
51 ef10_evb_init, /* eeo_init */
52 ef10_evb_fini, /* eeo_fini */
53 ef10_evb_vswitch_alloc, /* eeo_vswitch_alloc */
54 ef10_evb_vswitch_free, /* eeo_vswitch_free */
55 ef10_evb_vport_alloc, /* eeo_vport_alloc */
56 ef10_evb_vport_free, /* eeo_vport_free */
57 ef10_evb_vport_mac_addr_add, /* eeo_vport_mac_addr_add */
58 ef10_evb_vport_mac_addr_del, /* eeo_vport_mac_addr_del */
59 ef10_evb_vadaptor_alloc, /* eeo_vadaptor_alloc */
60 ef10_evb_vadaptor_free, /* eeo_vadaptor_free */
61 ef10_evb_vport_assign, /* eeo_vport_assign */
62 ef10_evb_vport_reconfigure, /* eeo_vport_reconfigure */
63 ef10_evb_vport_stats, /* eeo_vport_stats */
64 };
65 #endif /* EFSYS_OPT_RIVERHEAD */
66
67 __checkReturn efx_rc_t
efx_evb_init(__in efx_nic_t * enp)68 efx_evb_init(
69 __in efx_nic_t *enp)
70 {
71 const efx_evb_ops_t *eeop;
72 efx_rc_t rc;
73 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
74
75 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
76 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
77 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EVB));
78
79 switch (enp->en_family) {
80 #if EFSYS_OPT_SIENA
81 case EFX_FAMILY_SIENA:
82 eeop = &__efx_evb_dummy_ops;
83 break;
84 #endif /* EFSYS_OPT_SIENA */
85
86 #if EFSYS_OPT_HUNTINGTON
87 case EFX_FAMILY_HUNTINGTON:
88 eeop = &__efx_evb_ef10_ops;
89 break;
90 #endif /* EFSYS_OPT_HUNTINGTON */
91
92 #if EFSYS_OPT_MEDFORD
93 case EFX_FAMILY_MEDFORD:
94 eeop = &__efx_evb_ef10_ops;
95 break;
96 #endif /* EFSYS_OPT_MEDFORD */
97
98 #if EFSYS_OPT_MEDFORD2
99 case EFX_FAMILY_MEDFORD2:
100 eeop = &__efx_evb_ef10_ops;
101 break;
102 #endif /* EFSYS_OPT_MEDFORD2 */
103
104 #if EFSYS_OPT_RIVERHEAD
105 case EFX_FAMILY_RIVERHEAD:
106 eeop = &__efx_evb_rhead_ops;
107 break;
108 #endif /* EFSYS_OPT_RIVERHEAD */
109
110 default:
111 EFSYS_ASSERT(0);
112 rc = ENOTSUP;
113 goto fail1;
114 }
115
116 if (!encp->enc_datapath_cap_evb || !eeop->eeo_init) {
117 rc = ENOTSUP;
118 goto fail2;
119 }
120
121 if ((rc = eeop->eeo_init(enp)) != 0)
122 goto fail3;
123
124 enp->en_eeop = eeop;
125 enp->en_mod_flags |= EFX_MOD_EVB;
126 return (0);
127
128 fail3:
129 EFSYS_PROBE(fail3);
130 fail2:
131 EFSYS_PROBE(fail2);
132 fail1:
133 EFSYS_PROBE1(fail1, efx_rc_t, rc);
134
135 return (rc);
136 }
137
138 void
efx_evb_fini(__in efx_nic_t * enp)139 efx_evb_fini(
140 __in efx_nic_t *enp)
141 {
142 const efx_evb_ops_t *eeop = enp->en_eeop;
143
144 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
145 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE);
146 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
147 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
148
149 if (eeop && eeop->eeo_fini)
150 eeop->eeo_fini(enp);
151
152 enp->en_eeop = NULL;
153 enp->en_mod_flags &= ~EFX_MOD_EVB;
154 }
155
156 /*
157 * efx_is_zero_eth_addr returns TRUE if the passed MAC address has all bytes
158 * equal to zero. A vport is assigned a MAC address after creation and this
159 * function checks if that has happened. It is called in the clean-up function
160 * before calling eeo_vport_mac_addr_del to ensure that the vport actually had
161 * an allocated MAC address.
162 */
163
164 __checkReturn boolean_t
efx_is_zero_eth_addr(__in_bcount (EFX_MAC_ADDR_LEN)const uint8_t * addrp)165 efx_is_zero_eth_addr(
166 __in_bcount(EFX_MAC_ADDR_LEN) const uint8_t *addrp)
167 {
168 return (!(addrp[0] | addrp[1] | addrp[2] |
169 addrp[3] | addrp[4] | addrp[5]));
170 }
171
172 static void
efx_evb_free_vport(__in efx_nic_t * enp,__in efx_vswitch_id_t vswitch_id,__inout efx_vport_config_t * configp)173 efx_evb_free_vport(
174 __in efx_nic_t *enp,
175 __in efx_vswitch_id_t vswitch_id,
176 __inout efx_vport_config_t *configp)
177 {
178 const efx_evb_ops_t *eeop = enp->en_eeop;
179
180 /* If any callback fails, continue clean-up with others functions */
181 if (EFX_VPORT_PCI_FUNCTION_IS_PF(configp)) {
182 /* free vadaptor */
183 if ((configp->evc_vport_id != EFX_VPORT_ID_INVALID) &&
184 (eeop->eeo_vadaptor_free(enp, vswitch_id,
185 configp->evc_vport_id) != 0)) {
186 EFSYS_PROBE2(eeo_vadaptor_free,
187 uint16_t, configp->evc_function,
188 uint32_t, configp->evc_vport_id);
189 }
190 } else {
191 if (configp->evc_vport_assigned == B_TRUE) {
192 if (eeop->eeo_vport_assign(enp, vswitch_id,
193 EVB_PORT_ID_NULL,
194 configp->evc_function) != 0) {
195 EFSYS_PROBE1(eeo_vport_assign,
196 uint16_t, configp->evc_function);
197 }
198 configp->evc_vport_assigned = B_FALSE;
199 }
200 }
201
202 /*
203 * Call eeo_vport_mac_addr_del after checking that this vport is
204 * actually allocated a MAC address in call to efx_evb_configure_vport
205 */
206 if (!efx_is_zero_eth_addr(configp->evc_mac_addr)) {
207 if (eeop->eeo_vport_mac_addr_del(enp, vswitch_id,
208 configp->evc_vport_id,
209 configp->evc_mac_addr) != 0) {
210 EFSYS_PROBE1(eeo_vport_mac_addr_del,
211 uint16_t, configp->evc_function);
212 }
213 memset(configp->evc_mac_addr, 0x00, EFX_MAC_ADDR_LEN);
214 }
215
216 if (configp->evc_vport_id != EFX_VPORT_ID_INVALID) {
217 if (eeop->eeo_vport_free(enp, vswitch_id,
218 configp->evc_vport_id) != 0) {
219 EFSYS_PROBE1(eeo_vport_free,
220 uint16_t, configp->evc_function);
221 }
222 configp->evc_vport_id = EFX_VPORT_ID_INVALID;
223 }
224 }
225
226 static void
efx_evb_free_vports(__in efx_nic_t * enp,__in efx_vswitch_id_t vswitch_id,__in uint32_t num_vports,__inout_ecount (num_vports)efx_vport_config_t * vport_configp)227 efx_evb_free_vports(
228 __in efx_nic_t *enp,
229 __in efx_vswitch_id_t vswitch_id,
230 __in uint32_t num_vports,
231 __inout_ecount(num_vports) efx_vport_config_t *vport_configp)
232 {
233 efx_vport_config_t *configp;
234 uint32_t i;
235
236 if (vport_configp == NULL) {
237 EFSYS_PROBE(null_vport_config);
238 return;
239 }
240
241 for (i = 0; i < num_vports; i++) {
242 configp = vport_configp + i;
243 efx_evb_free_vport(enp, vswitch_id, configp);
244 }
245 }
246
247 static __checkReturn efx_rc_t
efx_evb_configure_vport(__in efx_nic_t * enp,__in efx_vswitch_id_t vswitch_id,__in const efx_evb_ops_t * eeop,__inout efx_vport_config_t * configp)248 efx_evb_configure_vport(
249 __in efx_nic_t *enp,
250 __in efx_vswitch_id_t vswitch_id,
251 __in const efx_evb_ops_t *eeop,
252 __inout efx_vport_config_t *configp)
253 {
254 efx_rc_t rc;
255 efx_vport_id_t vport_id;
256
257 if ((rc = eeop->eeo_vport_alloc(enp, vswitch_id,
258 EFX_VPORT_TYPE_NORMAL, configp->evc_vid,
259 configp->evc_vlan_restrict, &vport_id)) != 0)
260 goto fail1;
261
262 configp->evc_vport_id = vport_id;
263
264 if ((rc = eeop->eeo_vport_mac_addr_add(enp, vswitch_id,
265 configp->evc_vport_id,
266 configp->evc_mac_addr)) != 0)
267 goto fail2;
268
269 if (EFX_VPORT_PCI_FUNCTION_IS_PF(configp)) {
270 if ((rc = eeop->eeo_vadaptor_alloc(enp, vswitch_id,
271 configp->evc_vport_id)) != 0)
272 goto fail3;
273 } else {
274 if ((rc = eeop->eeo_vport_assign(enp, vswitch_id,
275 configp->evc_vport_id,
276 configp->evc_function)) != 0)
277 goto fail4;
278 configp->evc_vport_assigned = B_TRUE;
279 }
280
281 return (0);
282
283 fail4:
284 EFSYS_PROBE(fail4);
285 fail3:
286 EFSYS_PROBE(fail3);
287 fail2:
288 EFSYS_PROBE(fail2);
289 fail1:
290 EFSYS_PROBE1(fail1, efx_rc_t, rc);
291
292 return (rc);
293 }
294
295 __checkReturn efx_rc_t
efx_evb_vswitch_create(__in efx_nic_t * enp,__in uint32_t num_vports,__inout_ecount (num_vports)efx_vport_config_t * vport_configp,__deref_out efx_vswitch_t ** evpp)296 efx_evb_vswitch_create(
297 __in efx_nic_t *enp,
298 __in uint32_t num_vports,
299 __inout_ecount(num_vports) efx_vport_config_t *vport_configp,
300 __deref_out efx_vswitch_t **evpp)
301 {
302 efx_vswitch_t *evp;
303 efx_rc_t rc;
304 efx_vswitch_id_t vswitch_id;
305 efx_vport_config_t *configp;
306 const efx_evb_ops_t *eeop = enp->en_eeop;
307 uint32_t i;
308
309 /* vport_configp is a caller allocated array filled in with vports
310 * configuration. Index 0 carries the PF vport configuration and next
311 * num_vports - 1 indices carry VFs configuration.
312 */
313 EFSYS_ASSERT((num_vports != 0) && (vport_configp != NULL) &&
314 (evpp != NULL));
315 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB);
316 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC));
317
318 if ((eeop->eeo_vswitch_alloc == NULL) ||
319 (eeop->eeo_vport_alloc == NULL) ||
320 (eeop->eeo_vport_free == NULL) ||
321 (eeop->eeo_vport_mac_addr_add == NULL) ||
322 (eeop->eeo_vport_mac_addr_del == NULL) ||
323 (eeop->eeo_vadaptor_alloc == NULL) ||
324 (eeop->eeo_vadaptor_free == NULL) ||
325 (eeop->eeo_vport_assign == NULL) ||
326 (eeop->eeo_vswitch_free == NULL)) {
327 rc = ENOTSUP;
328 goto fail1;
329 }
330
331 /* Allocate a vSwitch object */
332 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_vswitch_t), evp);
333
334 if (evp == NULL) {
335 rc = ENOMEM;
336 goto fail2;
337 }
338
339 if ((rc = eeop->eeo_vswitch_alloc(enp, &vswitch_id)) != 0)
340 goto fail3;
341
342 evp->ev_enp = enp;
343 evp->ev_num_vports = num_vports;
344 evp->ev_evcp = vport_configp;
345 evp->ev_vswitch_id = vswitch_id;
346
347 for (i = 0; i < num_vports; i++) {
348 configp = vport_configp + i;
349
350 if ((rc = efx_evb_configure_vport(enp, vswitch_id, eeop,
351 configp)) != 0)
352 goto fail4;
353 }
354
355 enp->en_vswitchp = evp;
356 *evpp = evp;
357 return (0);
358
359 fail4:
360 EFSYS_PROBE(fail4);
361 efx_evb_free_vports(enp, vswitch_id, i + 1, vport_configp);
362 /* Free the vSwitch */
363 eeop->eeo_vswitch_free(enp, vswitch_id);
364
365 fail3:
366 EFSYS_PROBE(fail3);
367 /* Free the vSwitch object */
368 EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_vswitch_t), evp);
369
370 fail2:
371 EFSYS_PROBE(fail2);
372
373 fail1:
374 EFSYS_PROBE1(fail1, efx_rc_t, rc);
375
376 return (rc);
377 }
378
379 __checkReturn efx_rc_t
efx_evb_vport_mac_set(__in efx_nic_t * enp,__in efx_vswitch_t * evp,__in efx_vport_id_t vport_id,__in_bcount (EFX_MAC_ADDR_LEN)uint8_t * addrp)380 efx_evb_vport_mac_set(
381 __in efx_nic_t *enp,
382 __in efx_vswitch_t *evp,
383 __in efx_vport_id_t vport_id,
384 __in_bcount(EFX_MAC_ADDR_LEN) uint8_t *addrp)
385 {
386 const efx_evb_ops_t *eeop = enp->en_eeop;
387 efx_rc_t rc;
388
389 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB);
390
391 if (eeop->eeo_vport_reconfigure == NULL) {
392 rc = ENOTSUP;
393 goto fail1;
394 }
395
396 if (addrp == NULL) {
397 rc = EINVAL;
398 goto fail2;
399 }
400
401 rc = eeop->eeo_vport_reconfigure(enp, evp->ev_vswitch_id, vport_id,
402 NULL, addrp, NULL);
403 if (rc != 0)
404 goto fail3;
405
406 return (0);
407
408 fail3:
409 EFSYS_PROBE(fail3);
410 fail2:
411 EFSYS_PROBE(fail2);
412 fail1:
413 EFSYS_PROBE1(fail1, efx_rc_t, rc);
414 return (rc);
415 }
416
417 __checkReturn efx_rc_t
efx_evb_vport_vlan_set(__in efx_nic_t * enp,__in efx_vswitch_t * evp,__in efx_vport_id_t vport_id,__in uint16_t vid)418 efx_evb_vport_vlan_set(
419 __in efx_nic_t *enp,
420 __in efx_vswitch_t *evp,
421 __in efx_vport_id_t vport_id,
422 __in uint16_t vid)
423 {
424 const efx_evb_ops_t *eeop = enp->en_eeop;
425 efx_rc_t rc;
426
427 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB);
428
429 if (eeop->eeo_vport_reconfigure == NULL) {
430 rc = ENOTSUP;
431 goto fail1;
432 }
433
434 rc = eeop->eeo_vport_reconfigure(enp, evp->ev_vswitch_id, vport_id,
435 &vid, NULL, NULL);
436 if (rc != 0)
437 goto fail2;
438
439 return (0);
440
441 fail2:
442 EFSYS_PROBE(fail2);
443 fail1:
444 EFSYS_PROBE1(fail1, efx_rc_t, rc);
445 return (rc);
446 }
447
448 __checkReturn efx_rc_t
efx_evb_vport_reset(__in efx_nic_t * enp,__in efx_vswitch_t * evp,__in efx_vport_id_t vport_id,__in_bcount (EFX_MAC_ADDR_LEN)uint8_t * addrp,__in uint16_t vid,__out boolean_t * is_fn_resetp)449 efx_evb_vport_reset(
450 __in efx_nic_t *enp,
451 __in efx_vswitch_t *evp,
452 __in efx_vport_id_t vport_id,
453 __in_bcount(EFX_MAC_ADDR_LEN) uint8_t *addrp,
454 __in uint16_t vid,
455 __out boolean_t *is_fn_resetp)
456 {
457 const efx_evb_ops_t *eeop = enp->en_eeop;
458 efx_rc_t rc;
459
460 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB);
461
462 if (eeop->eeo_vport_reconfigure == NULL) {
463 rc = ENOTSUP;
464 goto fail1;
465 }
466
467 if (is_fn_resetp == NULL) {
468 rc = EINVAL;
469 goto fail2;
470 }
471
472 rc = eeop->eeo_vport_reconfigure(enp, evp->ev_vswitch_id, vport_id,
473 &vid, addrp, is_fn_resetp);
474 if (rc != 0)
475 goto fail3;
476
477 return (0);
478
479 fail3:
480 EFSYS_PROBE(fail3);
481 fail2:
482 EFSYS_PROBE(fail2);
483 fail1:
484 EFSYS_PROBE1(fail1, efx_rc_t, rc);
485 return (rc);
486 }
487 __checkReturn efx_rc_t
efx_evb_vswitch_destroy(__in efx_nic_t * enp,__in efx_vswitch_t * evp)488 efx_evb_vswitch_destroy(
489 __in efx_nic_t *enp,
490 __in efx_vswitch_t *evp)
491 {
492 const efx_evb_ops_t *eeop = enp->en_eeop;
493 efx_vswitch_id_t vswitch_id;
494 efx_rc_t rc;
495
496 EFSYS_ASSERT(evp != NULL);
497 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB);
498
499 if ((eeop->eeo_vport_mac_addr_del == NULL) ||
500 (eeop->eeo_vadaptor_free == NULL) ||
501 (eeop->eeo_vport_assign == NULL) ||
502 (eeop->eeo_vport_free == NULL) ||
503 (eeop->eeo_vswitch_free == NULL)) {
504 rc = ENOTSUP;
505 goto fail1;
506 }
507
508 vswitch_id = evp->ev_vswitch_id;
509 efx_evb_free_vports(enp, vswitch_id,
510 evp->ev_num_vports, evp->ev_evcp);
511
512 /* Free the vSwitch object */
513 EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_vswitch_t), evp);
514 enp->en_vswitchp = NULL;
515
516 /* Free the vSwitch */
517 if ((rc = eeop->eeo_vswitch_free(enp, vswitch_id)) != 0)
518 goto fail2;
519
520 return (0);
521
522 fail2:
523 EFSYS_PROBE(fail2);
524
525 fail1:
526 EFSYS_PROBE1(fail1, efx_rc_t, rc);
527 return (rc);
528 }
529
530 __checkReturn efx_rc_t
efx_evb_vport_stats(__in efx_nic_t * enp,__in efx_vswitch_t * evp,__in efx_vport_id_t vport_id,__out efsys_mem_t * stats_bufferp)531 efx_evb_vport_stats(
532 __in efx_nic_t *enp,
533 __in efx_vswitch_t *evp,
534 __in efx_vport_id_t vport_id,
535 __out efsys_mem_t *stats_bufferp)
536 {
537 efx_rc_t rc;
538 const efx_evb_ops_t *eeop = enp->en_eeop;
539
540 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB);
541
542 if (eeop->eeo_vport_stats == NULL) {
543 rc = ENOTSUP;
544 goto fail1;
545 }
546
547 if (stats_bufferp == NULL) {
548 rc = EINVAL;
549 goto fail2;
550 }
551
552 rc = eeop->eeo_vport_stats(enp, evp->ev_vswitch_id,
553 vport_id, stats_bufferp);
554 if (rc != 0)
555 goto fail3;
556
557 return (0);
558
559 fail3:
560 EFSYS_PROBE(fail3);
561 fail2:
562 EFSYS_PROBE(fail2);
563 fail1:
564 EFSYS_PROBE1(fail1, efx_rc_t, rc);
565 return (rc);
566 }
567
568 #endif
569