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