New upstream version 18.02
[deb_dpdk.git] / drivers / net / sfc / base / efx_tunnel.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright (c) 2007-2018 Solarflare Communications Inc.
4  * All rights reserved.
5  */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10
11 #if EFSYS_OPT_TUNNEL
12
13 #if EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON
14 static const efx_tunnel_ops_t   __efx_tunnel_dummy_ops = {
15         NULL,   /* eto_udp_encap_supported */
16         NULL,   /* eto_reconfigure */
17 };
18 #endif /* EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON */
19
20 #if EFSYS_OPT_MEDFORD
21 static  __checkReturn   boolean_t
22 medford_udp_encap_supported(
23         __in            efx_nic_t *enp);
24
25 static  __checkReturn   efx_rc_t
26 medford_tunnel_reconfigure(
27         __in            efx_nic_t *enp);
28
29 static const efx_tunnel_ops_t   __efx_tunnel_medford_ops = {
30         medford_udp_encap_supported,    /* eto_udp_encap_supported */
31         medford_tunnel_reconfigure,     /* eto_reconfigure */
32 };
33 #endif /* EFSYS_OPT_MEDFORD */
34
35 static  __checkReturn           efx_rc_t
36 efx_mcdi_set_tunnel_encap_udp_ports(
37         __in                    efx_nic_t *enp,
38         __in                    efx_tunnel_cfg_t *etcp,
39         __in                    boolean_t unloading,
40         __out                   boolean_t *resetting)
41 {
42         efx_mcdi_req_t req;
43         uint8_t payload[MAX(MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LENMAX,
44                             MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN)];
45         efx_word_t flags;
46         efx_rc_t rc;
47         unsigned int i;
48         unsigned int entries_num;
49
50         if (etcp == NULL)
51                 entries_num = 0;
52         else
53                 entries_num = etcp->etc_udp_entries_num;
54
55         (void) memset(payload, 0, sizeof (payload));
56         req.emr_cmd = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS;
57         req.emr_in_buf = payload;
58         req.emr_in_length =
59             MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LEN(entries_num);
60         req.emr_out_buf = payload;
61         req.emr_out_length = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN;
62
63         EFX_POPULATE_WORD_1(flags,
64             MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_UNLOADING,
65             (unloading == B_TRUE) ? 1 : 0);
66         MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_FLAGS,
67             EFX_WORD_FIELD(flags, EFX_WORD_0));
68
69         MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_NUM_ENTRIES,
70             entries_num);
71
72         for (i = 0; i < entries_num; ++i) {
73                 uint16_t mcdi_udp_protocol;
74
75                 switch (etcp->etc_udp_entries[i].etue_protocol) {
76                 case EFX_TUNNEL_PROTOCOL_VXLAN:
77                         mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_VXLAN;
78                         break;
79                 case EFX_TUNNEL_PROTOCOL_GENEVE:
80                         mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE;
81                         break;
82                 default:
83                         rc = EINVAL;
84                         goto fail1;
85                 }
86
87                 /*
88                  * UDP port is MCDI native little-endian in the request
89                  * and EFX_POPULATE_DWORD cares about conversion from
90                  * host/CPU byte order to little-endian.
91                  */
92                 EFX_STATIC_ASSERT(sizeof (efx_dword_t) ==
93                     TUNNEL_ENCAP_UDP_PORT_ENTRY_LEN);
94                 EFX_POPULATE_DWORD_2(
95                     MCDI_IN2(req, efx_dword_t,
96                         SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES)[i],
97                     TUNNEL_ENCAP_UDP_PORT_ENTRY_UDP_PORT,
98                     etcp->etc_udp_entries[i].etue_port,
99                     TUNNEL_ENCAP_UDP_PORT_ENTRY_PROTOCOL,
100                     mcdi_udp_protocol);
101         }
102
103         efx_mcdi_execute(enp, &req);
104
105         if (req.emr_rc != 0) {
106                 rc = req.emr_rc;
107                 goto fail2;
108         }
109
110         if (req.emr_out_length_used !=
111             MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN) {
112                 rc = EMSGSIZE;
113                 goto fail3;
114         }
115
116         *resetting = MCDI_OUT_WORD_FIELD(req,
117             SET_TUNNEL_ENCAP_UDP_PORTS_OUT_FLAGS,
118             SET_TUNNEL_ENCAP_UDP_PORTS_OUT_RESETTING);
119
120         return (0);
121
122 fail3:
123         EFSYS_PROBE(fail3);
124
125 fail2:
126         EFSYS_PROBE(fail2);
127
128 fail1:
129         EFSYS_PROBE1(fail1, efx_rc_t, rc);
130
131         return (rc);
132 }
133
134         __checkReturn   efx_rc_t
135 efx_tunnel_init(
136         __in            efx_nic_t *enp)
137 {
138         efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
139         const efx_tunnel_ops_t *etop;
140         efx_rc_t rc;
141
142         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
143         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
144         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TUNNEL));
145
146         EFX_STATIC_ASSERT(EFX_TUNNEL_MAXNENTRIES ==
147             MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES_MAXNUM);
148
149         switch (enp->en_family) {
150 #if EFSYS_OPT_SIENA
151         case EFX_FAMILY_SIENA:
152                 etop = &__efx_tunnel_dummy_ops;
153                 break;
154 #endif /* EFSYS_OPT_SIENA */
155
156 #if EFSYS_OPT_HUNTINGTON
157         case EFX_FAMILY_HUNTINGTON:
158                 etop = &__efx_tunnel_dummy_ops;
159                 break;
160 #endif /* EFSYS_OPT_HUNTINGTON */
161
162 #if EFSYS_OPT_MEDFORD
163         case EFX_FAMILY_MEDFORD:
164                 etop = &__efx_tunnel_medford_ops;
165                 break;
166 #endif /* EFSYS_OPT_MEDFORD */
167
168         default:
169                 EFSYS_ASSERT(0);
170                 rc = ENOTSUP;
171                 goto fail1;
172         }
173
174         memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries));
175         etcp->etc_udp_entries_num = 0;
176
177         enp->en_etop = etop;
178         enp->en_mod_flags |= EFX_MOD_TUNNEL;
179
180         return (0);
181
182 fail1:
183         EFSYS_PROBE1(fail1, efx_rc_t, rc);
184
185         enp->en_etop = NULL;
186         enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
187
188         return (rc);
189 }
190
191                         void
192 efx_tunnel_fini(
193         __in            efx_nic_t *enp)
194 {
195         boolean_t resetting;
196
197         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
198         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
199         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
200
201         if ((enp->en_etop->eto_udp_encap_supported != NULL) &&
202             enp->en_etop->eto_udp_encap_supported(enp)) {
203                 /*
204                  * The UNLOADING flag allows the MC to suppress the datapath
205                  * reset if it was set on the last call to
206                  * MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS by all functions
207                  */
208                 (void) efx_mcdi_set_tunnel_encap_udp_ports(enp, NULL, B_TRUE,
209                     &resetting);
210         }
211
212         enp->en_etop = NULL;
213         enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
214 }
215
216 static  __checkReturn   efx_rc_t
217 efx_tunnel_config_find_udp_tunnel_entry(
218         __in            efx_tunnel_cfg_t *etcp,
219         __in            uint16_t port,
220         __out           unsigned int *entryp)
221 {
222         unsigned int i;
223
224         for (i = 0; i < etcp->etc_udp_entries_num; ++i) {
225                 efx_tunnel_udp_entry_t *p = &etcp->etc_udp_entries[i];
226
227                 if (p->etue_port == port) {
228                         *entryp = i;
229                         return (0);
230                 }
231         }
232
233         return (ENOENT);
234 }
235
236         __checkReturn   efx_rc_t
237 efx_tunnel_config_udp_add(
238         __in            efx_nic_t *enp,
239         __in            uint16_t port /* host/cpu-endian */,
240         __in            efx_tunnel_protocol_t protocol)
241 {
242         const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
243         efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
244         efsys_lock_state_t state;
245         efx_rc_t rc;
246         unsigned int entry;
247
248         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
249
250         if (protocol >= EFX_TUNNEL_NPROTOS) {
251                 rc = EINVAL;
252                 goto fail1;
253         }
254
255         if ((encp->enc_tunnel_encapsulations_supported &
256             (1u << protocol)) == 0) {
257                 rc = ENOTSUP;
258                 goto fail2;
259         }
260
261         EFSYS_LOCK(enp->en_eslp, state);
262
263         rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
264         if (rc == 0) {
265                 rc = EEXIST;
266                 goto fail3;
267         }
268
269         if (etcp->etc_udp_entries_num ==
270             encp->enc_tunnel_config_udp_entries_max) {
271                 rc = ENOSPC;
272                 goto fail4;
273         }
274
275         etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_port = port;
276         etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_protocol =
277             protocol;
278
279         etcp->etc_udp_entries_num++;
280
281         EFSYS_UNLOCK(enp->en_eslp, state);
282
283         return (0);
284
285 fail4:
286         EFSYS_PROBE(fail4);
287
288 fail3:
289         EFSYS_PROBE(fail3);
290         EFSYS_UNLOCK(enp->en_eslp, state);
291
292 fail2:
293         EFSYS_PROBE(fail2);
294
295 fail1:
296         EFSYS_PROBE1(fail1, efx_rc_t, rc);
297
298         return (rc);
299 }
300
301         __checkReturn   efx_rc_t
302 efx_tunnel_config_udp_remove(
303         __in            efx_nic_t *enp,
304         __in            uint16_t port /* host/cpu-endian */,
305         __in            efx_tunnel_protocol_t protocol)
306 {
307         efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
308         efsys_lock_state_t state;
309         unsigned int entry;
310         efx_rc_t rc;
311
312         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
313
314         EFSYS_LOCK(enp->en_eslp, state);
315
316         rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
317         if (rc != 0)
318                 goto fail1;
319
320         if (etcp->etc_udp_entries[entry].etue_protocol != protocol) {
321                 rc = EINVAL;
322                 goto fail2;
323         }
324
325         EFSYS_ASSERT3U(etcp->etc_udp_entries_num, >, 0);
326         etcp->etc_udp_entries_num--;
327
328         if (entry < etcp->etc_udp_entries_num) {
329                 memmove(&etcp->etc_udp_entries[entry],
330                     &etcp->etc_udp_entries[entry + 1],
331                     (etcp->etc_udp_entries_num - entry) *
332                     sizeof (etcp->etc_udp_entries[0]));
333         }
334
335         memset(&etcp->etc_udp_entries[etcp->etc_udp_entries_num], 0,
336             sizeof (etcp->etc_udp_entries[0]));
337
338         EFSYS_UNLOCK(enp->en_eslp, state);
339
340         return (0);
341
342 fail2:
343         EFSYS_PROBE(fail2);
344
345 fail1:
346         EFSYS_PROBE1(fail1, efx_rc_t, rc);
347         EFSYS_UNLOCK(enp->en_eslp, state);
348
349         return (rc);
350 }
351
352                         void
353 efx_tunnel_config_clear(
354         __in                    efx_nic_t *enp)
355 {
356         efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
357         efsys_lock_state_t state;
358
359         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
360
361         EFSYS_LOCK(enp->en_eslp, state);
362
363         etcp->etc_udp_entries_num = 0;
364         memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries));
365
366         EFSYS_UNLOCK(enp->en_eslp, state);
367 }
368
369         __checkReturn   efx_rc_t
370 efx_tunnel_reconfigure(
371         __in            efx_nic_t *enp)
372 {
373         const efx_tunnel_ops_t *etop = enp->en_etop;
374         efx_rc_t rc;
375
376         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
377
378         if (etop->eto_reconfigure == NULL) {
379                 rc = ENOTSUP;
380                 goto fail1;
381         }
382
383         if ((rc = enp->en_etop->eto_reconfigure(enp)) != 0)
384                 goto fail2;
385
386         return (0);
387
388 fail2:
389         EFSYS_PROBE(fail2);
390
391 fail1:
392         EFSYS_PROBE1(fail1, efx_rc_t, rc);
393
394         return (rc);
395 }
396
397 #if EFSYS_OPT_MEDFORD
398 static  __checkReturn           boolean_t
399 medford_udp_encap_supported(
400         __in            efx_nic_t *enp)
401 {
402         const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
403         uint32_t udp_tunnels_mask = 0;
404
405         udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_VXLAN);
406         udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_GENEVE);
407
408         return ((encp->enc_tunnel_encapsulations_supported &
409             udp_tunnels_mask) == 0 ? B_FALSE : B_TRUE);
410 }
411
412 static  __checkReturn   efx_rc_t
413 medford_tunnel_reconfigure(
414         __in            efx_nic_t *enp)
415 {
416         efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
417         efx_rc_t rc;
418         boolean_t resetting;
419         efsys_lock_state_t state;
420         efx_tunnel_cfg_t etc;
421
422         EFSYS_LOCK(enp->en_eslp, state);
423         memcpy(&etc, etcp, sizeof (etc));
424         EFSYS_UNLOCK(enp->en_eslp, state);
425
426         if (medford_udp_encap_supported(enp) == B_FALSE) {
427                 /*
428                  * It is OK to apply empty UDP tunnel ports when UDP
429                  * tunnel encapsulations are not supported - just nothing
430                  * should be done.
431                  */
432                 if (etc.etc_udp_entries_num == 0)
433                         return (0);
434                 rc = ENOTSUP;
435                 goto fail1;
436         } else {
437                 /*
438                  * All PCI functions can see a reset upon the
439                  * MCDI request completion
440                  */
441                 rc = efx_mcdi_set_tunnel_encap_udp_ports(enp, &etc, B_FALSE,
442                     &resetting);
443                 if (rc != 0)
444                         goto fail2;
445
446                 /*
447                  * Although the caller should be able to handle MC reboot,
448                  * it might come in handy to report the impending reboot
449                  * by returning EAGAIN
450                  */
451                 return ((resetting) ? EAGAIN : 0);
452         }
453 fail2:
454         EFSYS_PROBE(fail2);
455
456 fail1:
457         EFSYS_PROBE1(fail1, efx_rc_t, rc);
458
459         return (rc);
460 }
461 #endif /* EFSYS_OPT_MEDFORD */
462
463 #endif /* EFSYS_OPT_TUNNEL */