1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Netronome Systems, Inc.
6 #ifndef __NFP_CPPAT_H__
7 #define __NFP_CPPAT_H__
9 #include "nfp_platform.h"
10 #include "nfp_resid.h"
12 /* This file contains helpers for creating CPP commands
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
20 * ----- Table 3.6. CPP Address Translation Mode Commands
23 #define _NIC_NFP6000_MU_LOCALITY_DIRECT 2
26 _nfp6000_decode_basic(uint64_t addr, int *dest_island, int cpp_tgt, int mode,
27 int addr40, int isld1, int isld0);
30 _nic_mask64(int msb, int lsb, int at0)
33 int w = msb - lsb + 1;
41 v = (UINT64_C(1) << w) - 1;
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.
53 _nfp6000_encode_basic(uint64_t *addr, int dest_island, int cpp_tgt, int mode,
54 int addr40, int isld1, int isld0)
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);
77 if (cpp_tgt == NFP6000_CPPTGT_VQDR && !addr40) {
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.
83 i = _nfp6000_decode_basic(*addr, &v, cpp_tgt, mode,
87 /* Full Island ID and channel bits overlap */
91 * If dest_island is invalid, the current address won't
94 if (dest_island != -1 && dest_island != v)
95 return NFP_ERRNO(EINVAL);
97 /* If dest_island was -1, we don't care */
101 iid_lsb = (addr40) ? 34 : 26;
103 /* <39:34> or <31:26> */
104 _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0);
106 *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64;
109 if (cpp_tgt == NFP6000_CPPTGT_VQDR && !addr40) {
110 i = _nfp6000_decode_basic(*addr, &v, cpp_tgt, mode,
111 addr40, isld1, isld0);
113 /* Full Island ID and channel bits overlap */
117 * If dest_island is invalid, the current address won't
120 if (dest_island != -1 && dest_island != v)
121 return NFP_ERRNO(EINVAL);
123 /* If dest_island was -1, we don't care */
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);
134 if (dest_island == isld1) {
135 /* Only need to set the Index bit */
136 *addr |= (UINT64_C(1) << idx_lsb);
140 return NFP_ERRNO(ENODEV);
142 if (cpp_tgt == NFP6000_CPPTGT_VQDR && !addr40) {
143 /* iid<0> = addr<30> = channel<0> */
144 /* channel<1> = addr<31> = Index */
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.
151 i = _nfp6000_decode_basic(*addr, &v, cpp_tgt, mode,
152 addr40, isld1, isld0);
154 /* Full Island ID and channel bits overlap */
158 * If dest_island is invalid, the current address won't
161 if (dest_island != -1 && dest_island != v)
162 return NFP_ERRNO(EINVAL);
164 /* If dest_island was -1, we don't care */
169 * Make sure we compare against isldN values by clearing the
170 * LSB. This is what the silicon does.
175 idx_lsb = (addr40) ? 39 : 31;
176 iid_lsb = idx_lsb - 1;
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
184 for (i = 0; i < 2; i++) {
185 for (v = 0; v < 2; v++) {
186 if (dest_island != (isld[i] | v))
188 *addr &= ~_nic_mask64(idx_lsb, iid_lsb, 0);
189 *addr |= (((uint64_t)i) << idx_lsb);
190 *addr |= (((uint64_t)v) << iid_lsb);
195 return NFP_ERRNO(ENODEV);
197 if (cpp_tgt == NFP6000_CPPTGT_VQDR && !addr40) {
199 * iid<0> = addr<29> = data
200 * iid<1> = addr<30> = channel<0>
201 * channel<1> = addr<31> = Index
203 i = _nfp6000_decode_basic(*addr, &v, cpp_tgt, mode,
204 addr40, isld1, isld0);
206 /* Full Island ID and channel bits overlap */
209 if (dest_island != -1 && dest_island != v)
210 return NFP_ERRNO(EINVAL);
212 /* If dest_island was -1, we don't care */
219 idx_lsb = (addr40) ? 39 : 31;
220 iid_lsb = idx_lsb - 2;
222 for (i = 0; i < 2; i++) {
223 for (v = 0; v < 4; v++) {
224 if (dest_island != (isld[i] | v))
226 *addr &= ~_nic_mask64(idx_lsb, iid_lsb, 0);
227 *addr |= (((uint64_t)i) << idx_lsb);
228 *addr |= (((uint64_t)v) << iid_lsb);
232 return NFP_ERRNO(ENODEV);
237 return NFP_ERRNO(EINVAL);
241 _nfp6000_decode_basic(uint64_t addr, int *dest_island, int cpp_tgt, int mode,
242 int addr40, int isld1, int isld0)
244 int iid_lsb, idx_lsb;
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);
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.
267 iid_lsb = (addr40) ? 34 : 26;
268 *dest_island = (int)(addr >> iid_lsb) & 0x3F;
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
278 * That would be valid as long as both islands have VQDR.
282 idx_lsb = (addr40) ? 39 : 31;
283 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
284 *dest_island = isld1;
286 *dest_island = isld0;
292 * Channel 0: (island#0 | 0)
293 * Channel 1: (island#0 | 1)
294 * Channel 2: (island#1 | 0)
295 * Channel 3: (island#1 | 1)
297 * Make sure we compare against isldN values by clearing the
298 * LSB. This is what the silicon does.
303 idx_lsb = (addr40) ? 39 : 31;
304 iid_lsb = idx_lsb - 1;
306 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
307 *dest_island = isld1 | (int)((addr >> iid_lsb) & 1);
309 *dest_island = isld0 | (int)((addr >> iid_lsb) & 1);
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
326 idx_lsb = (addr40) ? 39 : 31;
327 iid_lsb = idx_lsb - 2;
329 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
330 *dest_island = isld1 | (int)((addr >> iid_lsb) & 3);
332 *dest_island = isld0 | (int)((addr >> iid_lsb) & 3);
339 return NFP_ERRNO(EINVAL);
343 _nfp6000_cppat_mu_locality_lsb(int mode, int addr40)
350 return (addr40) ? 38 : 30;
354 return NFP_ERRNO(EINVAL);
358 _nfp6000_encode_mu(uint64_t *addr, int dest_island, int mode, int addr40,
359 int isld1, int isld0)
362 int iid_lsb, idx_lsb, locality_lsb;
369 locality_lsb = _nfp6000_cppat_mu_locality_lsb(mode, addr40);
371 if (((*addr >> locality_lsb) & 3) == _NIC_NFP6000_MU_LOCALITY_DIRECT)
378 iid_lsb = (addr40) ? 32 : 24;
379 _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0);
381 *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64;
385 iid_lsb = (addr40) ? 32 : 24;
386 _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0);
388 *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64;
392 idx_lsb = (addr40) ? 37 : 29;
393 if (dest_island == isld0) {
394 *addr &= ~_nic_mask64(idx_lsb, idx_lsb, 0);
398 if (dest_island == isld1) {
399 *addr |= (UINT64_C(1) << idx_lsb);
403 return NFP_ERRNO(ENODEV);
406 iid_lsb = (addr40) ? 32 : 24;
407 _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0);
409 *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64;
414 * Make sure we compare against isldN values by clearing the
415 * LSB. This is what the silicon does.
420 idx_lsb = (addr40) ? 37 : 29;
421 iid_lsb = idx_lsb - 1;
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
429 for (i = 0; i < 2; i++) {
430 for (v = 0; v < 2; v++) {
431 if (dest_island != (isld[i] | v))
433 *addr &= ~_nic_mask64(idx_lsb, iid_lsb, 0);
434 *addr |= (((uint64_t)i) << idx_lsb);
435 *addr |= (((uint64_t)v) << iid_lsb);
439 return NFP_ERRNO(ENODEV);
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).
449 if (dest_island > 0 &&
450 (dest_island < 24 || dest_island > 26)) {
451 *addr |= ((uint64_t)_NIC_NFP6000_MU_LOCALITY_DIRECT)
457 iid_lsb = (addr40) ? 32 : 24;
458 _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0);
460 *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64;
467 idx_lsb = (addr40) ? 37 : 29;
468 iid_lsb = idx_lsb - 2;
470 for (i = 0; i < 2; i++) {
471 for (v = 0; v < 4; v++) {
472 if (dest_island != (isld[i] | v))
474 *addr &= ~_nic_mask64(idx_lsb, iid_lsb, 0);
475 *addr |= (((uint64_t)i) << idx_lsb);
476 *addr |= (((uint64_t)v) << iid_lsb);
481 return NFP_ERRNO(ENODEV);
486 return NFP_ERRNO(EINVAL);
490 _nfp6000_decode_mu(uint64_t addr, int *dest_island, int mode, int addr40,
491 int isld1, int isld0)
493 int iid_lsb, idx_lsb, locality_lsb;
496 locality_lsb = _nfp6000_cppat_mu_locality_lsb(mode, addr40);
498 if (((addr >> locality_lsb) & 3) == _NIC_NFP6000_MU_LOCALITY_DIRECT)
505 iid_lsb = (addr40) ? 32 : 24;
506 *dest_island = (int)(addr >> iid_lsb) & 0x3F;
510 iid_lsb = (addr40) ? 32 : 24;
511 *dest_island = (int)(addr >> iid_lsb) & 0x3F;
515 idx_lsb = (addr40) ? 37 : 29;
517 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
518 *dest_island = isld1;
520 *dest_island = isld0;
525 iid_lsb = (addr40) ? 32 : 24;
526 *dest_island = (int)(addr >> iid_lsb) & 0x3F;
530 * Make sure we compare against isldN values by clearing the
531 * LSB. This is what the silicon does.
536 idx_lsb = (addr40) ? 37 : 29;
537 iid_lsb = idx_lsb - 1;
539 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
540 *dest_island = isld1 | (int)((addr >> iid_lsb) & 1);
542 *dest_island = isld0 | (int)((addr >> iid_lsb) & 1);
547 iid_lsb = (addr40) ? 32 : 24;
548 *dest_island = (int)(addr >> iid_lsb) & 0x3F;
555 idx_lsb = (addr40) ? 37 : 29;
556 iid_lsb = idx_lsb - 2;
558 if (addr & _nic_mask64(idx_lsb, idx_lsb, 0))
559 *dest_island = isld1 | (int)((addr >> iid_lsb) & 3);
561 *dest_island = isld0 | (int)((addr >> iid_lsb) & 3);
568 return NFP_ERRNO(EINVAL);
572 _nfp6000_cppat_addr_encode(uint64_t *addr, int dest_island, int cpp_tgt,
573 int mode, int addr40, int isld1, int isld0)
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);
586 case NFP6000_CPPTGT_MU:
587 return _nfp6000_encode_mu(addr, dest_island, mode, addr40,
590 case NFP6000_CPPTGT_CTXPB:
591 if (mode != 1 || addr40 != 0)
592 return NFP_ERRNO(EINVAL);
594 *addr &= ~_nic_mask64(29, 24, 0);
595 *addr |= (((uint64_t)dest_island) << 24) &
596 _nic_mask64(29, 24, 0);
602 return NFP_ERRNO(EINVAL);
606 _nfp6000_cppat_addr_decode(uint64_t addr, int *dest_island, int cpp_tgt,
607 int mode, int addr40, int isld1, int isld0)
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);
620 case NFP6000_CPPTGT_MU:
621 return _nfp6000_decode_mu(addr, dest_island, mode, addr40,
624 case NFP6000_CPPTGT_CTXPB:
625 if (mode != 1 || addr40 != 0)
627 *dest_island = (int)(addr >> 24) & 0x3F;
637 _nfp6000_cppat_addr_iid_clear(uint64_t *addr, int cpp_tgt, int mode, int addr40)
639 int iid_lsb, locality_lsb, da;
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:
651 iid_lsb = (addr40) ? 34 : 26;
652 *addr &= ~(UINT64_C(0x3F) << iid_lsb);
655 iid_lsb = (addr40) ? 39 : 31;
656 *addr &= ~_nic_mask64(iid_lsb, iid_lsb, 0);
659 iid_lsb = (addr40) ? 38 : 30;
660 *addr &= ~_nic_mask64(iid_lsb + 1, iid_lsb, 0);
663 iid_lsb = (addr40) ? 37 : 29;
664 *addr &= ~_nic_mask64(iid_lsb + 2, iid_lsb, 0);
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);
675 iid_lsb = (addr40) ? 32 : 24;
676 *addr &= ~(UINT64_C(0x3F) << iid_lsb);
680 iid_lsb = (addr40) ? 32 : 24;
681 *addr &= ~(UINT64_C(0x3F) << iid_lsb);
684 iid_lsb = (addr40) ? 37 : 29;
685 *addr &= ~_nic_mask64(iid_lsb, iid_lsb, 0);
689 iid_lsb = (addr40) ? 32 : 24;
690 *addr &= ~(UINT64_C(0x3F) << iid_lsb);
694 iid_lsb = (addr40) ? 36 : 28;
695 *addr &= ~_nic_mask64(iid_lsb + 1, iid_lsb, 0);
699 iid_lsb = (addr40) ? 32 : 24;
700 *addr &= ~(UINT64_C(0x3F) << iid_lsb);
704 iid_lsb = (addr40) ? 35 : 27;
705 *addr &= ~_nic_mask64(iid_lsb + 2, iid_lsb, 0);
710 case NFP6000_CPPTGT_CTXPB:
711 if (mode != 1 || addr40 != 0)
713 *addr &= ~(UINT64_C(0x3F) << 24);
719 return NFP_ERRNO(EINVAL);
722 #endif /* __NFP_CPPAT_H__ */