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