]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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 | ||
9f95a23c TL |
371 | if (locality_lsb < 0) |
372 | return NFP_ERRNO(EINVAL); | |
373 | ||
11fdf7f2 TL |
374 | if (((*addr >> locality_lsb) & 3) == _NIC_NFP6000_MU_LOCALITY_DIRECT) |
375 | da = 1; | |
376 | else | |
377 | da = 0; | |
378 | ||
379 | switch (mode) { | |
380 | case 0: | |
381 | iid_lsb = (addr40) ? 32 : 24; | |
382 | _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0); | |
383 | *addr &= ~_u64; | |
384 | *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64; | |
385 | return 0; | |
386 | case 1: | |
387 | if (da) { | |
388 | iid_lsb = (addr40) ? 32 : 24; | |
389 | _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0); | |
390 | *addr &= ~_u64; | |
391 | *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64; | |
392 | return 0; | |
393 | } | |
394 | ||
395 | idx_lsb = (addr40) ? 37 : 29; | |
396 | if (dest_island == isld0) { | |
397 | *addr &= ~_nic_mask64(idx_lsb, idx_lsb, 0); | |
398 | return 0; | |
399 | } | |
400 | ||
401 | if (dest_island == isld1) { | |
402 | *addr |= (UINT64_C(1) << idx_lsb); | |
403 | return 0; | |
404 | } | |
405 | ||
406 | return NFP_ERRNO(ENODEV); | |
407 | case 2: | |
408 | if (da) { | |
409 | iid_lsb = (addr40) ? 32 : 24; | |
410 | _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0); | |
411 | *addr &= ~_u64; | |
412 | *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64; | |
413 | return 0; | |
414 | } | |
415 | ||
416 | /* | |
417 | * Make sure we compare against isldN values by clearing the | |
418 | * LSB. This is what the silicon does. | |
419 | */ | |
420 | isld[0] &= ~1; | |
421 | isld[1] &= ~1; | |
422 | ||
423 | idx_lsb = (addr40) ? 37 : 29; | |
424 | iid_lsb = idx_lsb - 1; | |
425 | ||
426 | /* | |
427 | * Try each option, take first one that fits. Not sure if we | |
428 | * would want to do some smarter searching and prefer 0 or | |
429 | * non-0 island IDs. | |
430 | */ | |
431 | ||
432 | for (i = 0; i < 2; i++) { | |
433 | for (v = 0; v < 2; v++) { | |
434 | if (dest_island != (isld[i] | v)) | |
435 | continue; | |
436 | *addr &= ~_nic_mask64(idx_lsb, iid_lsb, 0); | |
437 | *addr |= (((uint64_t)i) << idx_lsb); | |
438 | *addr |= (((uint64_t)v) << iid_lsb); | |
439 | return 0; | |
440 | } | |
441 | } | |
442 | return NFP_ERRNO(ENODEV); | |
443 | case 3: | |
444 | /* | |
445 | * Only the EMU will use 40 bit addressing. Silently set the | |
446 | * direct locality bit for everyone else. The SDK toolchain | |
447 | * uses dest_island <= 0 to test for atypical address encodings | |
448 | * to support access to local-island CTM with a 32-but address | |
449 | * (high-locality is effectively ignored and just used for | |
450 | * routing to island #0). | |
451 | */ | |
452 | if (dest_island > 0 && | |
453 | (dest_island < 24 || dest_island > 26)) { | |
454 | *addr |= ((uint64_t)_NIC_NFP6000_MU_LOCALITY_DIRECT) | |
455 | << locality_lsb; | |
456 | da = 1; | |
457 | } | |
458 | ||
459 | if (da) { | |
460 | iid_lsb = (addr40) ? 32 : 24; | |
461 | _u64 = _nic_mask64((iid_lsb + 5), iid_lsb, 0); | |
462 | *addr &= ~_u64; | |
463 | *addr |= (((uint64_t)dest_island) << iid_lsb) & _u64; | |
464 | return 0; | |
465 | } | |
466 | ||
467 | isld[0] &= ~3; | |
468 | isld[1] &= ~3; | |
469 | ||
470 | idx_lsb = (addr40) ? 37 : 29; | |
471 | iid_lsb = idx_lsb - 2; | |
472 | ||
473 | for (i = 0; i < 2; i++) { | |
474 | for (v = 0; v < 4; v++) { | |
475 | if (dest_island != (isld[i] | v)) | |
476 | continue; | |
477 | *addr &= ~_nic_mask64(idx_lsb, iid_lsb, 0); | |
478 | *addr |= (((uint64_t)i) << idx_lsb); | |
479 | *addr |= (((uint64_t)v) << iid_lsb); | |
480 | return 0; | |
481 | } | |
482 | } | |
483 | ||
484 | return NFP_ERRNO(ENODEV); | |
485 | default: | |
486 | break; | |
487 | } | |
488 | ||
489 | return NFP_ERRNO(EINVAL); | |
490 | } | |
491 | ||
492 | static inline int | |
493 | _nfp6000_decode_mu(uint64_t addr, int *dest_island, int mode, int addr40, | |
494 | int isld1, int isld0) | |
495 | { | |
496 | int iid_lsb, idx_lsb, locality_lsb; | |
497 | int da; | |
498 | ||
499 | locality_lsb = _nfp6000_cppat_mu_locality_lsb(mode, addr40); | |
500 | ||
501 | if (((addr >> locality_lsb) & 3) == _NIC_NFP6000_MU_LOCALITY_DIRECT) | |
502 | da = 1; | |
503 | else | |
504 | da = 0; | |
505 | ||
506 | switch (mode) { | |
507 | case 0: | |
508 | iid_lsb = (addr40) ? 32 : 24; | |
509 | *dest_island = (int)(addr >> iid_lsb) & 0x3F; | |
510 | return 0; | |
511 | case 1: | |
512 | if (da) { | |
513 | iid_lsb = (addr40) ? 32 : 24; | |
514 | *dest_island = (int)(addr >> iid_lsb) & 0x3F; | |
515 | return 0; | |
516 | } | |
517 | ||
518 | idx_lsb = (addr40) ? 37 : 29; | |
519 | ||
520 | if (addr & _nic_mask64(idx_lsb, idx_lsb, 0)) | |
521 | *dest_island = isld1; | |
522 | else | |
523 | *dest_island = isld0; | |
524 | ||
525 | return 0; | |
526 | case 2: | |
527 | if (da) { | |
528 | iid_lsb = (addr40) ? 32 : 24; | |
529 | *dest_island = (int)(addr >> iid_lsb) & 0x3F; | |
530 | return 0; | |
531 | } | |
532 | /* | |
533 | * Make sure we compare against isldN values by clearing the | |
534 | * LSB. This is what the silicon does. | |
535 | */ | |
536 | isld0 &= ~1; | |
537 | isld1 &= ~1; | |
538 | ||
539 | idx_lsb = (addr40) ? 37 : 29; | |
540 | iid_lsb = idx_lsb - 1; | |
541 | ||
542 | if (addr & _nic_mask64(idx_lsb, idx_lsb, 0)) | |
543 | *dest_island = isld1 | (int)((addr >> iid_lsb) & 1); | |
544 | else | |
545 | *dest_island = isld0 | (int)((addr >> iid_lsb) & 1); | |
546 | ||
547 | return 0; | |
548 | case 3: | |
549 | if (da) { | |
550 | iid_lsb = (addr40) ? 32 : 24; | |
551 | *dest_island = (int)(addr >> iid_lsb) & 0x3F; | |
552 | return 0; | |
553 | } | |
554 | ||
555 | isld0 &= ~3; | |
556 | isld1 &= ~3; | |
557 | ||
558 | idx_lsb = (addr40) ? 37 : 29; | |
559 | iid_lsb = idx_lsb - 2; | |
560 | ||
561 | if (addr & _nic_mask64(idx_lsb, idx_lsb, 0)) | |
562 | *dest_island = isld1 | (int)((addr >> iid_lsb) & 3); | |
563 | else | |
564 | *dest_island = isld0 | (int)((addr >> iid_lsb) & 3); | |
565 | ||
566 | return 0; | |
567 | default: | |
568 | break; | |
569 | } | |
570 | ||
571 | return NFP_ERRNO(EINVAL); | |
572 | } | |
573 | ||
574 | static inline int | |
575 | _nfp6000_cppat_addr_encode(uint64_t *addr, int dest_island, int cpp_tgt, | |
576 | int mode, int addr40, int isld1, int isld0) | |
577 | { | |
578 | switch (cpp_tgt) { | |
579 | case NFP6000_CPPTGT_NBI: | |
580 | case NFP6000_CPPTGT_VQDR: | |
581 | case NFP6000_CPPTGT_ILA: | |
582 | case NFP6000_CPPTGT_PCIE: | |
583 | case NFP6000_CPPTGT_ARM: | |
584 | case NFP6000_CPPTGT_CRYPTO: | |
585 | case NFP6000_CPPTGT_CLS: | |
586 | return _nfp6000_encode_basic(addr, dest_island, cpp_tgt, mode, | |
587 | addr40, isld1, isld0); | |
588 | ||
589 | case NFP6000_CPPTGT_MU: | |
590 | return _nfp6000_encode_mu(addr, dest_island, mode, addr40, | |
591 | isld1, isld0); | |
592 | ||
593 | case NFP6000_CPPTGT_CTXPB: | |
594 | if (mode != 1 || addr40 != 0) | |
595 | return NFP_ERRNO(EINVAL); | |
596 | ||
597 | *addr &= ~_nic_mask64(29, 24, 0); | |
598 | *addr |= (((uint64_t)dest_island) << 24) & | |
599 | _nic_mask64(29, 24, 0); | |
600 | return 0; | |
601 | default: | |
602 | break; | |
603 | } | |
604 | ||
605 | return NFP_ERRNO(EINVAL); | |
606 | } | |
607 | ||
608 | static inline int | |
609 | _nfp6000_cppat_addr_decode(uint64_t addr, int *dest_island, int cpp_tgt, | |
610 | int mode, int addr40, int isld1, int isld0) | |
611 | { | |
612 | switch (cpp_tgt) { | |
613 | case NFP6000_CPPTGT_NBI: | |
614 | case NFP6000_CPPTGT_VQDR: | |
615 | case NFP6000_CPPTGT_ILA: | |
616 | case NFP6000_CPPTGT_PCIE: | |
617 | case NFP6000_CPPTGT_ARM: | |
618 | case NFP6000_CPPTGT_CRYPTO: | |
619 | case NFP6000_CPPTGT_CLS: | |
620 | return _nfp6000_decode_basic(addr, dest_island, cpp_tgt, mode, | |
621 | addr40, isld1, isld0); | |
622 | ||
623 | case NFP6000_CPPTGT_MU: | |
624 | return _nfp6000_decode_mu(addr, dest_island, mode, addr40, | |
625 | isld1, isld0); | |
626 | ||
627 | case NFP6000_CPPTGT_CTXPB: | |
628 | if (mode != 1 || addr40 != 0) | |
629 | return -EINVAL; | |
630 | *dest_island = (int)(addr >> 24) & 0x3F; | |
631 | return 0; | |
632 | default: | |
633 | break; | |
634 | } | |
635 | ||
636 | return -EINVAL; | |
637 | } | |
638 | ||
639 | static inline int | |
640 | _nfp6000_cppat_addr_iid_clear(uint64_t *addr, int cpp_tgt, int mode, int addr40) | |
641 | { | |
642 | int iid_lsb, locality_lsb, da; | |
643 | ||
644 | switch (cpp_tgt) { | |
645 | case NFP6000_CPPTGT_NBI: | |
646 | case NFP6000_CPPTGT_VQDR: | |
647 | case NFP6000_CPPTGT_ILA: | |
648 | case NFP6000_CPPTGT_PCIE: | |
649 | case NFP6000_CPPTGT_ARM: | |
650 | case NFP6000_CPPTGT_CRYPTO: | |
651 | case NFP6000_CPPTGT_CLS: | |
652 | switch (mode) { | |
653 | case 0: | |
654 | iid_lsb = (addr40) ? 34 : 26; | |
655 | *addr &= ~(UINT64_C(0x3F) << iid_lsb); | |
656 | return 0; | |
657 | case 1: | |
658 | iid_lsb = (addr40) ? 39 : 31; | |
659 | *addr &= ~_nic_mask64(iid_lsb, iid_lsb, 0); | |
660 | return 0; | |
661 | case 2: | |
662 | iid_lsb = (addr40) ? 38 : 30; | |
663 | *addr &= ~_nic_mask64(iid_lsb + 1, iid_lsb, 0); | |
664 | return 0; | |
665 | case 3: | |
666 | iid_lsb = (addr40) ? 37 : 29; | |
667 | *addr &= ~_nic_mask64(iid_lsb + 2, iid_lsb, 0); | |
668 | return 0; | |
669 | default: | |
670 | break; | |
671 | } | |
672 | case NFP6000_CPPTGT_MU: | |
673 | locality_lsb = _nfp6000_cppat_mu_locality_lsb(mode, addr40); | |
674 | da = (((*addr >> locality_lsb) & 3) == | |
675 | _NIC_NFP6000_MU_LOCALITY_DIRECT); | |
676 | switch (mode) { | |
677 | case 0: | |
678 | iid_lsb = (addr40) ? 32 : 24; | |
679 | *addr &= ~(UINT64_C(0x3F) << iid_lsb); | |
680 | return 0; | |
681 | case 1: | |
682 | if (da) { | |
683 | iid_lsb = (addr40) ? 32 : 24; | |
684 | *addr &= ~(UINT64_C(0x3F) << iid_lsb); | |
685 | return 0; | |
686 | } | |
687 | iid_lsb = (addr40) ? 37 : 29; | |
688 | *addr &= ~_nic_mask64(iid_lsb, iid_lsb, 0); | |
689 | return 0; | |
690 | case 2: | |
691 | if (da) { | |
692 | iid_lsb = (addr40) ? 32 : 24; | |
693 | *addr &= ~(UINT64_C(0x3F) << iid_lsb); | |
694 | return 0; | |
695 | } | |
696 | ||
697 | iid_lsb = (addr40) ? 36 : 28; | |
698 | *addr &= ~_nic_mask64(iid_lsb + 1, iid_lsb, 0); | |
699 | return 0; | |
700 | case 3: | |
701 | if (da) { | |
702 | iid_lsb = (addr40) ? 32 : 24; | |
703 | *addr &= ~(UINT64_C(0x3F) << iid_lsb); | |
704 | return 0; | |
705 | } | |
706 | ||
707 | iid_lsb = (addr40) ? 35 : 27; | |
708 | *addr &= ~_nic_mask64(iid_lsb + 2, iid_lsb, 0); | |
709 | return 0; | |
710 | default: | |
711 | break; | |
712 | } | |
713 | case NFP6000_CPPTGT_CTXPB: | |
714 | if (mode != 1 || addr40 != 0) | |
715 | return 0; | |
716 | *addr &= ~(UINT64_C(0x3F) << 24); | |
717 | return 0; | |
718 | default: | |
719 | break; | |
720 | } | |
721 | ||
722 | return NFP_ERRNO(EINVAL); | |
723 | } | |
724 | ||
725 | #endif /* __NFP_CPPAT_H__ */ |