]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/dpdk/drivers/net/sfc/base/efx_tunnel.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / dpdk / drivers / net / sfc / base / efx_tunnel.c
CommitLineData
11fdf7f2
TL
1/* SPDX-License-Identifier: BSD-3-Clause
2 *
f67539c2
TL
3 * Copyright(c) 2019-2020 Xilinx, Inc.
4 * Copyright(c) 2007-2019 Solarflare Communications Inc.
11fdf7f2
TL
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
14static 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 || EFSYS_OPT_MEDFORD2
21static __checkReturn boolean_t
22ef10_udp_encap_supported(
23 __in efx_nic_t *enp);
24
25static __checkReturn efx_rc_t
26ef10_tunnel_reconfigure(
27 __in efx_nic_t *enp);
28
29static const efx_tunnel_ops_t __efx_tunnel_ef10_ops = {
30 ef10_udp_encap_supported, /* eto_udp_encap_supported */
31 ef10_tunnel_reconfigure, /* eto_reconfigure */
32};
33#endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
34
35static __checkReturn efx_rc_t
36efx_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;
9f95a23c
TL
43 EFX_MCDI_DECLARE_BUF(payload,
44 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LENMAX,
45 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN);
11fdf7f2
TL
46 efx_word_t flags;
47 efx_rc_t rc;
48 unsigned int i;
49 unsigned int entries_num;
50
51 if (etcp == NULL)
52 entries_num = 0;
53 else
54 entries_num = etcp->etc_udp_entries_num;
55
11fdf7f2
TL
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
122fail3:
123 EFSYS_PROBE(fail3);
124
125fail2:
126 EFSYS_PROBE(fail2);
127
128fail1:
129 EFSYS_PROBE1(fail1, efx_rc_t, rc);
130
131 return (rc);
132}
133
134 __checkReturn efx_rc_t
135efx_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_ef10_ops;
165 break;
166#endif /* EFSYS_OPT_MEDFORD */
167
168#if EFSYS_OPT_MEDFORD2
169 case EFX_FAMILY_MEDFORD2:
170 etop = &__efx_tunnel_ef10_ops;
171 break;
172#endif /* EFSYS_OPT_MEDFORD2 */
173
174 default:
175 EFSYS_ASSERT(0);
176 rc = ENOTSUP;
177 goto fail1;
178 }
179
180 memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries));
181 etcp->etc_udp_entries_num = 0;
182
183 enp->en_etop = etop;
184 enp->en_mod_flags |= EFX_MOD_TUNNEL;
185
186 return (0);
187
188fail1:
189 EFSYS_PROBE1(fail1, efx_rc_t, rc);
190
191 enp->en_etop = NULL;
192 enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
193
194 return (rc);
195}
196
197 void
198efx_tunnel_fini(
199 __in efx_nic_t *enp)
200{
201 boolean_t resetting;
202
203 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
204 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
205 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
206
207 if ((enp->en_etop->eto_udp_encap_supported != NULL) &&
208 enp->en_etop->eto_udp_encap_supported(enp)) {
209 /*
210 * The UNLOADING flag allows the MC to suppress the datapath
211 * reset if it was set on the last call to
212 * MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS by all functions
213 */
214 (void) efx_mcdi_set_tunnel_encap_udp_ports(enp, NULL, B_TRUE,
215 &resetting);
216 }
217
218 enp->en_etop = NULL;
219 enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
220}
221
222static __checkReturn efx_rc_t
223efx_tunnel_config_find_udp_tunnel_entry(
224 __in efx_tunnel_cfg_t *etcp,
225 __in uint16_t port,
226 __out unsigned int *entryp)
227{
228 unsigned int i;
229
230 for (i = 0; i < etcp->etc_udp_entries_num; ++i) {
231 efx_tunnel_udp_entry_t *p = &etcp->etc_udp_entries[i];
232
233 if (p->etue_port == port) {
234 *entryp = i;
235 return (0);
236 }
237 }
238
239 return (ENOENT);
240}
241
242 __checkReturn efx_rc_t
243efx_tunnel_config_udp_add(
244 __in efx_nic_t *enp,
245 __in uint16_t port /* host/cpu-endian */,
246 __in efx_tunnel_protocol_t protocol)
247{
248 const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
249 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
250 efsys_lock_state_t state;
251 efx_rc_t rc;
252 unsigned int entry;
253
254 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
255
256 if (protocol >= EFX_TUNNEL_NPROTOS) {
257 rc = EINVAL;
258 goto fail1;
259 }
260
261 if ((encp->enc_tunnel_encapsulations_supported &
262 (1u << protocol)) == 0) {
263 rc = ENOTSUP;
264 goto fail2;
265 }
266
267 EFSYS_LOCK(enp->en_eslp, state);
268
269 rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
270 if (rc == 0) {
271 rc = EEXIST;
272 goto fail3;
273 }
274
275 if (etcp->etc_udp_entries_num ==
276 encp->enc_tunnel_config_udp_entries_max) {
277 rc = ENOSPC;
278 goto fail4;
279 }
280
281 etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_port = port;
282 etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_protocol =
283 protocol;
284
285 etcp->etc_udp_entries_num++;
286
287 EFSYS_UNLOCK(enp->en_eslp, state);
288
289 return (0);
290
291fail4:
292 EFSYS_PROBE(fail4);
293
294fail3:
295 EFSYS_PROBE(fail3);
296 EFSYS_UNLOCK(enp->en_eslp, state);
297
298fail2:
299 EFSYS_PROBE(fail2);
300
301fail1:
302 EFSYS_PROBE1(fail1, efx_rc_t, rc);
303
304 return (rc);
305}
306
307 __checkReturn efx_rc_t
308efx_tunnel_config_udp_remove(
309 __in efx_nic_t *enp,
310 __in uint16_t port /* host/cpu-endian */,
311 __in efx_tunnel_protocol_t protocol)
312{
313 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
314 efsys_lock_state_t state;
315 unsigned int entry;
316 efx_rc_t rc;
317
318 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
319
320 EFSYS_LOCK(enp->en_eslp, state);
321
322 rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
323 if (rc != 0)
324 goto fail1;
325
326 if (etcp->etc_udp_entries[entry].etue_protocol != protocol) {
327 rc = EINVAL;
328 goto fail2;
329 }
330
331 EFSYS_ASSERT3U(etcp->etc_udp_entries_num, >, 0);
332 etcp->etc_udp_entries_num--;
333
334 if (entry < etcp->etc_udp_entries_num) {
335 memmove(&etcp->etc_udp_entries[entry],
336 &etcp->etc_udp_entries[entry + 1],
337 (etcp->etc_udp_entries_num - entry) *
338 sizeof (etcp->etc_udp_entries[0]));
339 }
340
341 memset(&etcp->etc_udp_entries[etcp->etc_udp_entries_num], 0,
342 sizeof (etcp->etc_udp_entries[0]));
343
344 EFSYS_UNLOCK(enp->en_eslp, state);
345
346 return (0);
347
348fail2:
349 EFSYS_PROBE(fail2);
350
351fail1:
352 EFSYS_PROBE1(fail1, efx_rc_t, rc);
353 EFSYS_UNLOCK(enp->en_eslp, state);
354
355 return (rc);
356}
357
358 void
359efx_tunnel_config_clear(
360 __in efx_nic_t *enp)
361{
362 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
363 efsys_lock_state_t state;
364
365 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
366
367 EFSYS_LOCK(enp->en_eslp, state);
368
369 etcp->etc_udp_entries_num = 0;
370 memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries));
371
372 EFSYS_UNLOCK(enp->en_eslp, state);
373}
374
375 __checkReturn efx_rc_t
376efx_tunnel_reconfigure(
377 __in efx_nic_t *enp)
378{
379 const efx_tunnel_ops_t *etop = enp->en_etop;
380 efx_rc_t rc;
381
382 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
383
384 if (etop->eto_reconfigure == NULL) {
385 rc = ENOTSUP;
386 goto fail1;
387 }
388
389 if ((rc = enp->en_etop->eto_reconfigure(enp)) != 0)
390 goto fail2;
391
392 return (0);
393
394fail2:
395 EFSYS_PROBE(fail2);
396
397fail1:
398 EFSYS_PROBE1(fail1, efx_rc_t, rc);
399
400 return (rc);
401}
402
403#if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
404static __checkReturn boolean_t
405ef10_udp_encap_supported(
406 __in efx_nic_t *enp)
407{
408 const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
409 uint32_t udp_tunnels_mask = 0;
410
411 udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_VXLAN);
412 udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_GENEVE);
413
414 return ((encp->enc_tunnel_encapsulations_supported &
415 udp_tunnels_mask) == 0 ? B_FALSE : B_TRUE);
416}
417
418static __checkReturn efx_rc_t
419ef10_tunnel_reconfigure(
420 __in efx_nic_t *enp)
421{
422 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
423 efx_rc_t rc;
424 boolean_t resetting;
425 efsys_lock_state_t state;
426 efx_tunnel_cfg_t etc;
427
428 EFSYS_LOCK(enp->en_eslp, state);
429 memcpy(&etc, etcp, sizeof (etc));
430 EFSYS_UNLOCK(enp->en_eslp, state);
431
432 if (ef10_udp_encap_supported(enp) == B_FALSE) {
433 /*
434 * It is OK to apply empty UDP tunnel ports when UDP
435 * tunnel encapsulations are not supported - just nothing
436 * should be done.
437 */
438 if (etc.etc_udp_entries_num == 0)
439 return (0);
440 rc = ENOTSUP;
441 goto fail1;
442 } else {
443 /*
444 * All PCI functions can see a reset upon the
445 * MCDI request completion
446 */
447 rc = efx_mcdi_set_tunnel_encap_udp_ports(enp, &etc, B_FALSE,
448 &resetting);
449 if (rc != 0)
450 goto fail2;
451
452 /*
453 * Although the caller should be able to handle MC reboot,
454 * it might come in handy to report the impending reboot
455 * by returning EAGAIN
456 */
457 return ((resetting) ? EAGAIN : 0);
458 }
459fail2:
460 EFSYS_PROBE(fail2);
461
462fail1:
463 EFSYS_PROBE1(fail1, efx_rc_t, rc);
464
465 return (rc);
466}
467#endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
468
469#endif /* EFSYS_OPT_TUNNEL */