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