]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/dpdk/drivers/net/nfp/nfpcore/nfp-common/nfp_cppat.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / spdk / dpdk / drivers / net / nfp / nfpcore / nfp-common / nfp_cppat.h
1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Netronome Systems, Inc.
3 * All rights reserved.
4 */
5
6 #ifndef __NFP_CPPAT_H__
7 #define __NFP_CPPAT_H__
8
9 #include "nfp_platform.h"
10 #include "nfp_resid.h"
11
12 /* This file contains helpers for creating CPP commands
13 *
14 * All magic NFP-6xxx IMB 'mode' numbers here are from:
15 * Databook (1 August 2013)
16 * - System Overview and Connectivity
17 * -- Internal Connectivity
18 * --- Distributed Switch Fabric - Command Push/Pull (DSF-CPP) Bus
19 * ---- CPP addressing
20 * ----- Table 3.6. CPP Address Translation Mode Commands
21 */
22
23 #define _NIC_NFP6000_MU_LOCALITY_DIRECT 2
24
25 static inline int
26 _nfp6000_decode_basic(uint64_t addr, int *dest_island, int cpp_tgt, int mode,
27 int addr40, int isld1, int isld0);
28
29 static uint64_t
30 _nic_mask64(int msb, int lsb, int at0)
31 {
32 uint64_t v;
33 int w = msb - lsb + 1;
34
35 if (w == 64)
36 return ~(uint64_t)0;
37
38 if ((lsb + w) > 64)
39 return 0;
40
41 v = (UINT64_C(1) << w) - 1;
42
43 if (at0)
44 return v;
45
46 return v << lsb;
47 }
48
49 /* For VQDR, we may not modify the Channel bits, which might overlap
50 * with the Index bit. When it does, we need to ensure that isld0 == isld1.
51 */
52 static inline int
53 _nfp6000_encode_basic(uint64_t *addr, int dest_island, int cpp_tgt, int mode,
54 int addr40, int isld1, int isld0)
55 {
56 uint64_t _u64;
57 int iid_lsb, idx_lsb;
58 int i, v = 0;
59 int isld[2];
60
61 isld[0] = isld0;
62 isld[1] = isld1;
63
64 switch (cpp_tgt) {
65 case NFP6000_CPPTGT_MU:
66 /* This function doesn't handle MU */
67 return NFP_ERRNO(EINVAL);
68 case NFP6000_CPPTGT_CTXPB:
69 /* This function doesn't handle CTXPB */
70 return NFP_ERRNO(EINVAL);
71 default:
72 break;
73 }
74
75 switch (mode) {
76 case 0:
77 if (cpp_tgt == NFP6000_CPPTGT_VQDR && !addr40) {
78 /*
79 * In this specific mode we'd rather not modify the
80 * address but we can verify if the existing contents
81 * will point to a valid island.
82 */
83 i = _nfp6000_decode_basic(*addr, &v, cpp_tgt, mode,
84 addr40, isld1,
85 isld0);
86 if (i != 0)
87 /* Full Island ID and channel bits overlap */
88 return i;
89
90 /*
91 * If dest_island is invalid, the current address won't
92 * go where expected.
93 */
94 if (dest_island != -1 && dest_island != v)
95 return NFP_ERRNO(EINVAL);
96
97 /* If dest_island was -1, we don't care */
98 return 0;
99 }
100
101 iid_lsb = (addr40) ? 34 : 26;
102
103 /* <39:34> or <31:26> */
104 _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0);
105 *addr &= ~_u64;
106 *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64;
107 return 0;
108 case 1:
109 if (cpp_tgt == NFP6000_CPPTGT_VQDR && !addr40) {
110 i = _nfp6000_decode_basic(*addr, &v, cpp_tgt, mode,
111 addr40, isld1, isld0);
112 if (i != 0)
113 /* Full Island ID and channel bits overlap */
114 return i;
115
116 /*
117 * If dest_island is invalid, the current address won't
118 * go where expected.
119 */
120 if (dest_island != -1 && dest_island != v)
121 return NFP_ERRNO(EINVAL);
122
123 /* If dest_island was -1, we don't care */
124 return 0;
125 }
126
127 idx_lsb = (addr40) ? 39 : 31;
128 if (dest_island == isld0) {
129 /* Only need to clear the Index bit */
130 *addr &= ~_nic_mask64(idx_lsb, idx_lsb, 0);
131 return 0;
132 }
133
134 if (dest_island == isld1) {
135 /* Only need to set the Index bit */
136 *addr |= (UINT64_C(1) << idx_lsb);
137 return 0;
138 }
139
140 return NFP_ERRNO(ENODEV);
141 case 2:
142 if (cpp_tgt == NFP6000_CPPTGT_VQDR && !addr40) {
143 /* iid<0> = addr<30> = channel<0> */
144 /* channel<1> = addr<31> = Index */
145
146 /*
147 * Special case where we allow channel bits to be set
148 * before hand and with them select an island.
149 * So we need to confirm that it's at least plausible.
150 */
151 i = _nfp6000_decode_basic(*addr, &v, cpp_tgt, mode,
152 addr40, isld1, isld0);
153 if (i != 0)
154 /* Full Island ID and channel bits overlap */
155 return i;
156
157 /*
158 * If dest_island is invalid, the current address won't
159 * go where expected.
160 */
161 if (dest_island != -1 && dest_island != v)
162 return NFP_ERRNO(EINVAL);
163
164 /* If dest_island was -1, we don't care */
165 return 0;
166 }
167
168 /*
169 * Make sure we compare against isldN values by clearing the
170 * LSB. This is what the silicon does.
171 **/
172 isld[0] &= ~1;
173 isld[1] &= ~1;
174
175 idx_lsb = (addr40) ? 39 : 31;
176 iid_lsb = idx_lsb - 1;
177
178 /*
179 * Try each option, take first one that fits. Not sure if we
180 * would want to do some smarter searching and prefer 0 or non-0
181 * island IDs.
182 */
183
184 for (i = 0; i < 2; i++) {
185 for (v = 0; v < 2; v++) {
186 if (dest_island != (isld[i] | v))
187 continue;
188 *addr &= ~_nic_mask64(idx_lsb, iid_lsb, 0);
189 *addr |= (((uint64_t)i) << idx_lsb);
190 *addr |= (((uint64_t)v) << iid_lsb);
191 return 0;
192 }
193 }
194
195 return NFP_ERRNO(ENODEV);
196 case 3:
197 if (cpp_tgt == NFP6000_CPPTGT_VQDR && !addr40) {
198 /*
199 * iid<0> = addr<29> = data
200 * iid<1> = addr<30> = channel<0>
201 * channel<1> = addr<31> = Index
202 */
203 i = _nfp6000_decode_basic(*addr, &v, cpp_tgt, mode,
204 addr40, isld1, isld0);
205 if (i != 0)
206 /* Full Island ID and channel bits overlap */
207 return i;
208
209 if (dest_island != -1 && dest_island != v)
210 return NFP_ERRNO(EINVAL);
211
212 /* If dest_island was -1, we don't care */
213 return 0;
214 }
215
216 isld[0] &= ~3;
217 isld[1] &= ~3;
218
219 idx_lsb = (addr40) ? 39 : 31;
220 iid_lsb = idx_lsb - 2;
221
222 for (i = 0; i < 2; i++) {
223 for (v = 0; v < 4; v++) {
224 if (dest_island != (isld[i] | v))
225 continue;
226 *addr &= ~_nic_mask64(idx_lsb, iid_lsb, 0);
227 *addr |= (((uint64_t)i) << idx_lsb);
228 *addr |= (((uint64_t)v) << iid_lsb);
229 return 0;
230 }
231 }
232 return NFP_ERRNO(ENODEV);
233 default:
234 break;
235 }
236
237 return NFP_ERRNO(EINVAL);
238 }
239
240 static inline int
241 _nfp6000_decode_basic(uint64_t addr, int *dest_island, int cpp_tgt, int mode,
242 int addr40, int isld1, int isld0)
243 {
244 int iid_lsb, idx_lsb;
245
246 switch (cpp_tgt) {
247 case NFP6000_CPPTGT_MU:
248 /* This function doesn't handle MU */
249 return NFP_ERRNO(EINVAL);
250 case NFP6000_CPPTGT_CTXPB:
251 /* This function doesn't handle CTXPB */
252 return NFP_ERRNO(EINVAL);
253 default:
254 break;
255 }
256
257 switch (mode) {
258 case 0:
259 /*
260 * For VQDR, in this mode for 32-bit addressing it would be
261 * islands 0, 16, 32 and 48 depending on channel and upper
262 * address bits. Since those are not all valid islands, most
263 * decode cases would result in bad island IDs, but we do them
264 * anyway since this is decoding an address that is already
265 * assumed to be used as-is to get to sram.
266 */
267 iid_lsb = (addr40) ? 34 : 26;
268 *dest_island = (int)(addr >> iid_lsb) & 0x3F;
269 return 0;
270 case 1:
271 /*
272 * For VQDR 32-bit, this would decode as:
273 * Channel 0: island#0
274 * Channel 1: island#0
275 * Channel 2: island#1
276 * Channel 3: island#1
277 *
278 * That would be valid as long as both islands have VQDR.
279 * Let's allow this.
280 */
281
282 idx_lsb = (addr40) ? 39 : 31;
283 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
284 *dest_island = isld1;
285 else
286 *dest_island = isld0;
287
288 return 0;
289 case 2:
290 /*
291 * For VQDR 32-bit:
292 * Channel 0: (island#0 | 0)
293 * Channel 1: (island#0 | 1)
294 * Channel 2: (island#1 | 0)
295 * Channel 3: (island#1 | 1)
296 *
297 * Make sure we compare against isldN values by clearing the
298 * LSB. This is what the silicon does.
299 */
300 isld0 &= ~1;
301 isld1 &= ~1;
302
303 idx_lsb = (addr40) ? 39 : 31;
304 iid_lsb = idx_lsb - 1;
305
306 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
307 *dest_island = isld1 | (int)((addr >> iid_lsb) & 1);
308 else
309 *dest_island = isld0 | (int)((addr >> iid_lsb) & 1);
310
311 return 0;
312 case 3:
313 /*
314 * In this mode the data address starts to affect the island ID
315 * so rather not allow it. In some really specific case one
316 * could use this to send the upper half of the VQDR channel to
317 * another MU, but this is getting very specific. However, as
318 * above for mode 0, this is the decoder and the caller should
319 * validate the resulting IID. This blindly does what the
320 * silicon would do.
321 */
322
323 isld0 &= ~3;
324 isld1 &= ~3;
325
326 idx_lsb = (addr40) ? 39 : 31;
327 iid_lsb = idx_lsb - 2;
328
329 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
330 *dest_island = isld1 | (int)((addr >> iid_lsb) & 3);
331 else
332 *dest_island = isld0 | (int)((addr >> iid_lsb) & 3);
333
334 return 0;
335 default:
336 break;
337 }
338
339 return NFP_ERRNO(EINVAL);
340 }
341
342 static inline int
343 _nfp6000_cppat_mu_locality_lsb(int mode, int addr40)
344 {
345 switch (mode) {
346 case 0:
347 case 1:
348 case 2:
349 case 3:
350 return (addr40) ? 38 : 30;
351 default:
352 break;
353 }
354 return NFP_ERRNO(EINVAL);
355 }
356
357 static inline int
358 _nfp6000_encode_mu(uint64_t *addr, int dest_island, int mode, int addr40,
359 int isld1, int isld0)
360 {
361 uint64_t _u64;
362 int iid_lsb, idx_lsb, locality_lsb;
363 int i, v;
364 int isld[2];
365 int da;
366
367 isld[0] = isld0;
368 isld[1] = isld1;
369 locality_lsb = _nfp6000_cppat_mu_locality_lsb(mode, addr40);
370
371 if (((*addr >> locality_lsb) & 3) == _NIC_NFP6000_MU_LOCALITY_DIRECT)
372 da = 1;
373 else
374 da = 0;
375
376 switch (mode) {
377 case 0:
378 iid_lsb = (addr40) ? 32 : 24;
379 _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0);
380 *addr &= ~_u64;
381 *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64;
382 return 0;
383 case 1:
384 if (da) {
385 iid_lsb = (addr40) ? 32 : 24;
386 _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0);
387 *addr &= ~_u64;
388 *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64;
389 return 0;
390 }
391
392 idx_lsb = (addr40) ? 37 : 29;
393 if (dest_island == isld0) {
394 *addr &= ~_nic_mask64(idx_lsb, idx_lsb, 0);
395 return 0;
396 }
397
398 if (dest_island == isld1) {
399 *addr |= (UINT64_C(1) << idx_lsb);
400 return 0;
401 }
402
403 return NFP_ERRNO(ENODEV);
404 case 2:
405 if (da) {
406 iid_lsb = (addr40) ? 32 : 24;
407 _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0);
408 *addr &= ~_u64;
409 *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64;
410 return 0;
411 }
412
413 /*
414 * Make sure we compare against isldN values by clearing the
415 * LSB. This is what the silicon does.
416 */
417 isld[0] &= ~1;
418 isld[1] &= ~1;
419
420 idx_lsb = (addr40) ? 37 : 29;
421 iid_lsb = idx_lsb - 1;
422
423 /*
424 * Try each option, take first one that fits. Not sure if we
425 * would want to do some smarter searching and prefer 0 or
426 * non-0 island IDs.
427 */
428
429 for (i = 0; i < 2; i++) {
430 for (v = 0; v < 2; v++) {
431 if (dest_island != (isld[i] | v))
432 continue;
433 *addr &= ~_nic_mask64(idx_lsb, iid_lsb, 0);
434 *addr |= (((uint64_t)i) << idx_lsb);
435 *addr |= (((uint64_t)v) << iid_lsb);
436 return 0;
437 }
438 }
439 return NFP_ERRNO(ENODEV);
440 case 3:
441 /*
442 * Only the EMU will use 40 bit addressing. Silently set the
443 * direct locality bit for everyone else. The SDK toolchain
444 * uses dest_island <= 0 to test for atypical address encodings
445 * to support access to local-island CTM with a 32-but address
446 * (high-locality is effectively ignored and just used for
447 * routing to island #0).
448 */
449 if (dest_island > 0 &&
450 (dest_island < 24 || dest_island > 26)) {
451 *addr |= ((uint64_t)_NIC_NFP6000_MU_LOCALITY_DIRECT)
452 << locality_lsb;
453 da = 1;
454 }
455
456 if (da) {
457 iid_lsb = (addr40) ? 32 : 24;
458 _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0);
459 *addr &= ~_u64;
460 *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64;
461 return 0;
462 }
463
464 isld[0] &= ~3;
465 isld[1] &= ~3;
466
467 idx_lsb = (addr40) ? 37 : 29;
468 iid_lsb = idx_lsb - 2;
469
470 for (i = 0; i < 2; i++) {
471 for (v = 0; v < 4; v++) {
472 if (dest_island != (isld[i] | v))
473 continue;
474 *addr &= ~_nic_mask64(idx_lsb, iid_lsb, 0);
475 *addr |= (((uint64_t)i) << idx_lsb);
476 *addr |= (((uint64_t)v) << iid_lsb);
477 return 0;
478 }
479 }
480
481 return NFP_ERRNO(ENODEV);
482 default:
483 break;
484 }
485
486 return NFP_ERRNO(EINVAL);
487 }
488
489 static inline int
490 _nfp6000_decode_mu(uint64_t addr, int *dest_island, int mode, int addr40,
491 int isld1, int isld0)
492 {
493 int iid_lsb, idx_lsb, locality_lsb;
494 int da;
495
496 locality_lsb = _nfp6000_cppat_mu_locality_lsb(mode, addr40);
497
498 if (((addr >> locality_lsb) & 3) == _NIC_NFP6000_MU_LOCALITY_DIRECT)
499 da = 1;
500 else
501 da = 0;
502
503 switch (mode) {
504 case 0:
505 iid_lsb = (addr40) ? 32 : 24;
506 *dest_island = (int)(addr >> iid_lsb) & 0x3F;
507 return 0;
508 case 1:
509 if (da) {
510 iid_lsb = (addr40) ? 32 : 24;
511 *dest_island = (int)(addr >> iid_lsb) & 0x3F;
512 return 0;
513 }
514
515 idx_lsb = (addr40) ? 37 : 29;
516
517 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
518 *dest_island = isld1;
519 else
520 *dest_island = isld0;
521
522 return 0;
523 case 2:
524 if (da) {
525 iid_lsb = (addr40) ? 32 : 24;
526 *dest_island = (int)(addr >> iid_lsb) & 0x3F;
527 return 0;
528 }
529 /*
530 * Make sure we compare against isldN values by clearing the
531 * LSB. This is what the silicon does.
532 */
533 isld0 &= ~1;
534 isld1 &= ~1;
535
536 idx_lsb = (addr40) ? 37 : 29;
537 iid_lsb = idx_lsb - 1;
538
539 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
540 *dest_island = isld1 | (int)((addr >> iid_lsb) & 1);
541 else
542 *dest_island = isld0 | (int)((addr >> iid_lsb) & 1);
543
544 return 0;
545 case 3:
546 if (da) {
547 iid_lsb = (addr40) ? 32 : 24;
548 *dest_island = (int)(addr >> iid_lsb) & 0x3F;
549 return 0;
550 }
551
552 isld0 &= ~3;
553 isld1 &= ~3;
554
555 idx_lsb = (addr40) ? 37 : 29;
556 iid_lsb = idx_lsb - 2;
557
558 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
559 *dest_island = isld1 | (int)((addr >> iid_lsb) & 3);
560 else
561 *dest_island = isld0 | (int)((addr >> iid_lsb) & 3);
562
563 return 0;
564 default:
565 break;
566 }
567
568 return NFP_ERRNO(EINVAL);
569 }
570
571 static inline int
572 _nfp6000_cppat_addr_encode(uint64_t *addr, int dest_island, int cpp_tgt,
573 int mode, int addr40, int isld1, int isld0)
574 {
575 switch (cpp_tgt) {
576 case NFP6000_CPPTGT_NBI:
577 case NFP6000_CPPTGT_VQDR:
578 case NFP6000_CPPTGT_ILA:
579 case NFP6000_CPPTGT_PCIE:
580 case NFP6000_CPPTGT_ARM:
581 case NFP6000_CPPTGT_CRYPTO:
582 case NFP6000_CPPTGT_CLS:
583 return _nfp6000_encode_basic(addr, dest_island, cpp_tgt, mode,
584 addr40, isld1, isld0);
585
586 case NFP6000_CPPTGT_MU:
587 return _nfp6000_encode_mu(addr, dest_island, mode, addr40,
588 isld1, isld0);
589
590 case NFP6000_CPPTGT_CTXPB:
591 if (mode != 1 || addr40 != 0)
592 return NFP_ERRNO(EINVAL);
593
594 *addr &= ~_nic_mask64(29, 24, 0);
595 *addr |= (((uint64_t)dest_island) << 24) &
596 _nic_mask64(29, 24, 0);
597 return 0;
598 default:
599 break;
600 }
601
602 return NFP_ERRNO(EINVAL);
603 }
604
605 static inline int
606 _nfp6000_cppat_addr_decode(uint64_t addr, int *dest_island, int cpp_tgt,
607 int mode, int addr40, int isld1, int isld0)
608 {
609 switch (cpp_tgt) {
610 case NFP6000_CPPTGT_NBI:
611 case NFP6000_CPPTGT_VQDR:
612 case NFP6000_CPPTGT_ILA:
613 case NFP6000_CPPTGT_PCIE:
614 case NFP6000_CPPTGT_ARM:
615 case NFP6000_CPPTGT_CRYPTO:
616 case NFP6000_CPPTGT_CLS:
617 return _nfp6000_decode_basic(addr, dest_island, cpp_tgt, mode,
618 addr40, isld1, isld0);
619
620 case NFP6000_CPPTGT_MU:
621 return _nfp6000_decode_mu(addr, dest_island, mode, addr40,
622 isld1, isld0);
623
624 case NFP6000_CPPTGT_CTXPB:
625 if (mode != 1 || addr40 != 0)
626 return -EINVAL;
627 *dest_island = (int)(addr >> 24) & 0x3F;
628 return 0;
629 default:
630 break;
631 }
632
633 return -EINVAL;
634 }
635
636 static inline int
637 _nfp6000_cppat_addr_iid_clear(uint64_t *addr, int cpp_tgt, int mode, int addr40)
638 {
639 int iid_lsb, locality_lsb, da;
640
641 switch (cpp_tgt) {
642 case NFP6000_CPPTGT_NBI:
643 case NFP6000_CPPTGT_VQDR:
644 case NFP6000_CPPTGT_ILA:
645 case NFP6000_CPPTGT_PCIE:
646 case NFP6000_CPPTGT_ARM:
647 case NFP6000_CPPTGT_CRYPTO:
648 case NFP6000_CPPTGT_CLS:
649 switch (mode) {
650 case 0:
651 iid_lsb = (addr40) ? 34 : 26;
652 *addr &= ~(UINT64_C(0x3F) << iid_lsb);
653 return 0;
654 case 1:
655 iid_lsb = (addr40) ? 39 : 31;
656 *addr &= ~_nic_mask64(iid_lsb, iid_lsb, 0);
657 return 0;
658 case 2:
659 iid_lsb = (addr40) ? 38 : 30;
660 *addr &= ~_nic_mask64(iid_lsb + 1, iid_lsb, 0);
661 return 0;
662 case 3:
663 iid_lsb = (addr40) ? 37 : 29;
664 *addr &= ~_nic_mask64(iid_lsb + 2, iid_lsb, 0);
665 return 0;
666 default:
667 break;
668 }
669 case NFP6000_CPPTGT_MU:
670 locality_lsb = _nfp6000_cppat_mu_locality_lsb(mode, addr40);
671 da = (((*addr >> locality_lsb) & 3) ==
672 _NIC_NFP6000_MU_LOCALITY_DIRECT);
673 switch (mode) {
674 case 0:
675 iid_lsb = (addr40) ? 32 : 24;
676 *addr &= ~(UINT64_C(0x3F) << iid_lsb);
677 return 0;
678 case 1:
679 if (da) {
680 iid_lsb = (addr40) ? 32 : 24;
681 *addr &= ~(UINT64_C(0x3F) << iid_lsb);
682 return 0;
683 }
684 iid_lsb = (addr40) ? 37 : 29;
685 *addr &= ~_nic_mask64(iid_lsb, iid_lsb, 0);
686 return 0;
687 case 2:
688 if (da) {
689 iid_lsb = (addr40) ? 32 : 24;
690 *addr &= ~(UINT64_C(0x3F) << iid_lsb);
691 return 0;
692 }
693
694 iid_lsb = (addr40) ? 36 : 28;
695 *addr &= ~_nic_mask64(iid_lsb + 1, iid_lsb, 0);
696 return 0;
697 case 3:
698 if (da) {
699 iid_lsb = (addr40) ? 32 : 24;
700 *addr &= ~(UINT64_C(0x3F) << iid_lsb);
701 return 0;
702 }
703
704 iid_lsb = (addr40) ? 35 : 27;
705 *addr &= ~_nic_mask64(iid_lsb + 2, iid_lsb, 0);
706 return 0;
707 default:
708 break;
709 }
710 case NFP6000_CPPTGT_CTXPB:
711 if (mode != 1 || addr40 != 0)
712 return 0;
713 *addr &= ~(UINT64_C(0x3F) << 24);
714 return 0;
715 default:
716 break;
717 }
718
719 return NFP_ERRNO(EINVAL);
720 }
721
722 #endif /* __NFP_CPPAT_H__ */