1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2022 Corigine, Inc.
3 * All rights reserved.
4 */
5
6 #include "nfp_target.h"
7
8 #include "nfp_cpp.h"
9 #include "nfp6000/nfp6000.h"
10
11 #define P32 1
12 #define P64 2
13
14 /*
15 * All magic NFP-6xxx IMB 'mode' numbers here are from:
16 * Databook (1 August 2013)
17 * - System Overview and Connectivity
18 * -- Internal Connectivity
19 * --- Distributed Switch Fabric - Command Push/Pull (DSF-CPP) Bus
20 * ---- CPP addressing
21 * ----- Table 3.6. CPP Address Translation Mode Commands
22 */
23 #define NFP6000_MU_LOCALITY_DIRECT 2
24
25 static int
target_rw(uint32_t cpp_id,int pp,int start,int len)26 target_rw(uint32_t cpp_id,
27 int pp,
28 int start,
29 int len)
30 {
31 uint8_t island;
32
33 island = NFP_CPP_ID_ISLAND_of(cpp_id);
34 if (island != 0 && (island < start || island > (start + len)))
35 return -EINVAL;
36
37 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
38 case NFP_CPP_ID(0, 0, 0):
39 return PUSHPULL(0, pp);
40 case NFP_CPP_ID(0, 1, 0):
41 return PUSHPULL(pp, 0);
42 case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0):
43 return PUSHPULL(pp, pp);
44 default:
45 return -EINVAL;
46 }
47 }
48
49 static int
nfp6000_nbi_dma(uint32_t cpp_id)50 nfp6000_nbi_dma(uint32_t cpp_id)
51 {
52 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
53 case NFP_CPP_ID(0, 0, 0): /* Read NBI DMA */
54 return PUSHPULL(0, P64);
55 case NFP_CPP_ID(0, 1, 0): /* Write NBI DMA */
56 return PUSHPULL(P64, 0);
57 case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0):
58 return PUSHPULL(P64, P64);
59 default:
60 return -EINVAL;
61 }
62 }
63
64 static int
nfp6000_nbi_stats(uint32_t cpp_id)65 nfp6000_nbi_stats(uint32_t cpp_id)
66 {
67 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
68 case NFP_CPP_ID(0, 0, 0): /* Read NBI Stats */
69 return PUSHPULL(0, P32);
70 case NFP_CPP_ID(0, 1, 0): /* Write NBI Stats */
71 return PUSHPULL(P32, 0);
72 case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0):
73 return PUSHPULL(P32, P32);
74 default:
75 return -EINVAL;
76 }
77 }
78
79 static int
nfp6000_nbi_tm(uint32_t cpp_id)80 nfp6000_nbi_tm(uint32_t cpp_id)
81 {
82 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
83 case NFP_CPP_ID(0, 0, 0): /* Read NBI TM */
84 return PUSHPULL(0, P64);
85 case NFP_CPP_ID(0, 1, 0): /* Write NBI TM */
86 return PUSHPULL(P64, 0);
87 case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0):
88 return PUSHPULL(P64, P64);
89 default:
90 return -EINVAL;
91 }
92 }
93
94 static int
nfp6000_nbi_ppc(uint32_t cpp_id)95 nfp6000_nbi_ppc(uint32_t cpp_id)
96 {
97 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
98 case NFP_CPP_ID(0, 0, 0): /* Read NBI Preclassifier */
99 return PUSHPULL(0, P64);
100 case NFP_CPP_ID(0, 1, 0): /* Write NBI Preclassifier */
101 return PUSHPULL(P64, 0);
102 case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0):
103 return PUSHPULL(P64, P64);
104 default:
105 return -EINVAL;
106 }
107 }
108
109 static int
nfp6000_nbi(uint32_t cpp_id,uint64_t address)110 nfp6000_nbi(uint32_t cpp_id,
111 uint64_t address)
112 {
113 uint8_t island;
114 uint64_t rel_addr;
115
116 island = NFP_CPP_ID_ISLAND_of(cpp_id);
117 if (island != 8 && island != 9)
118 return -EINVAL;
119
120 rel_addr = address & 0x3FFFFF;
121 if (rel_addr < (1 << 20)) /* [0x000000, 0x100000) */
122 return nfp6000_nbi_dma(cpp_id);
123 else if (rel_addr < (2 << 20)) /* [0x100000, 0x200000) */
124 return nfp6000_nbi_stats(cpp_id);
125 else if (rel_addr < (3 << 20)) /* [0x200000, 0x300000) */
126 return nfp6000_nbi_tm(cpp_id);
127 else /* [0x300000, 0x400000) */
128 return nfp6000_nbi_ppc(cpp_id);
129 }
130
131 /*
132 * This structure ONLY includes items that can be done with a read or write of
133 * 32-bit or 64-bit words. All others are not listed.
134 */
135 static int
nfp6000_mu_common(uint32_t cpp_id)136 nfp6000_mu_common(uint32_t cpp_id)
137 {
138 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
139 case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0): /* read_be/write_be */
140 return PUSHPULL(P64, P64);
141 case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 1): /* read_le/write_le */
142 return PUSHPULL(P64, P64);
143 case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 2): /* read_swap_be/write_swap_be */
144 return PUSHPULL(P64, P64);
145 case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 3): /* read_swap_le/write_swap_le */
146 return PUSHPULL(P64, P64);
147 case NFP_CPP_ID(0, 0, 0): /* read_be */
148 return PUSHPULL(0, P64);
149 case NFP_CPP_ID(0, 0, 1): /* read_le */
150 return PUSHPULL(0, P64);
151 case NFP_CPP_ID(0, 0, 2): /* read_swap_be */
152 return PUSHPULL(0, P64);
153 case NFP_CPP_ID(0, 0, 3): /* read_swap_le */
154 return PUSHPULL(0, P64);
155 case NFP_CPP_ID(0, 1, 0): /* write_be */
156 return PUSHPULL(P64, 0);
157 case NFP_CPP_ID(0, 1, 1): /* write_le */
158 return PUSHPULL(P64, 0);
159 case NFP_CPP_ID(0, 1, 2): /* write_swap_be */
160 return PUSHPULL(P64, 0);
161 case NFP_CPP_ID(0, 1, 3): /* write_swap_le */
162 return PUSHPULL(P64, 0);
163 case NFP_CPP_ID(0, 3, 0): /* atomic_read */
164 return PUSHPULL(0, P32);
165 case NFP_CPP_ID(0, 3, 2): /* mask_compare_write */
166 return PUSHPULL(P32, 0);
167 case NFP_CPP_ID(0, 4, 0): /* atomic_write */
168 return PUSHPULL(P32, 0);
169 case NFP_CPP_ID(0, 4, 2): /* atomic_write_imm */
170 return PUSHPULL(0, 0);
171 case NFP_CPP_ID(0, 4, 3): /* swap_imm */
172 return PUSHPULL(0, P32);
173 case NFP_CPP_ID(0, 5, 0): /* set */
174 return PUSHPULL(P32, 0);
175 case NFP_CPP_ID(0, 5, 3): /* test_set_imm */
176 return PUSHPULL(0, P32);
177 case NFP_CPP_ID(0, 6, 0): /* clr */
178 return PUSHPULL(P32, 0);
179 case NFP_CPP_ID(0, 6, 3): /* test_clr_imm */
180 return PUSHPULL(0, P32);
181 case NFP_CPP_ID(0, 7, 0): /* add */
182 return PUSHPULL(P32, 0);
183 case NFP_CPP_ID(0, 7, 3): /* test_add_imm */
184 return PUSHPULL(0, P32);
185 case NFP_CPP_ID(0, 8, 0): /* addsat */
186 return PUSHPULL(P32, 0);
187 case NFP_CPP_ID(0, 8, 3): /* test_subsat_imm */
188 return PUSHPULL(0, P32);
189 case NFP_CPP_ID(0, 9, 0): /* sub */
190 return PUSHPULL(P32, 0);
191 case NFP_CPP_ID(0, 9, 3): /* test_sub_imm */
192 return PUSHPULL(0, P32);
193 case NFP_CPP_ID(0, 10, 0): /* subsat */
194 return PUSHPULL(P32, 0);
195 case NFP_CPP_ID(0, 10, 3): /* test_subsat_imm */
196 return PUSHPULL(0, P32);
197 case NFP_CPP_ID(0, 13, 0): /* microq128_get */
198 return PUSHPULL(0, P32);
199 case NFP_CPP_ID(0, 13, 1): /* microq128_pop */
200 return PUSHPULL(0, P32);
201 case NFP_CPP_ID(0, 13, 2): /* microq128_put */
202 return PUSHPULL(P32, 0);
203 case NFP_CPP_ID(0, 15, 0): /* xor */
204 return PUSHPULL(P32, 0);
205 case NFP_CPP_ID(0, 15, 3): /* test_xor_imm */
206 return PUSHPULL(0, P32);
207 case NFP_CPP_ID(0, 28, 0): /* read32_be */
208 return PUSHPULL(0, P32);
209 case NFP_CPP_ID(0, 28, 1): /* read32_le */
210 return PUSHPULL(0, P32);
211 case NFP_CPP_ID(0, 28, 2): /* read32_swap_be */
212 return PUSHPULL(0, P32);
213 case NFP_CPP_ID(0, 28, 3): /* read32_swap_le */
214 return PUSHPULL(0, P32);
215 case NFP_CPP_ID(0, 31, 0): /* write32_be */
216 return PUSHPULL(P32, 0);
217 case NFP_CPP_ID(0, 31, 1): /* write32_le */
218 return PUSHPULL(P32, 0);
219 case NFP_CPP_ID(0, 31, 2): /* write32_swap_be */
220 return PUSHPULL(P32, 0);
221 case NFP_CPP_ID(0, 31, 3): /* write32_swap_le */
222 return PUSHPULL(P32, 0);
223 default:
224 return -EINVAL;
225 }
226 }
227
228 static int
nfp6000_mu_ctm(uint32_t cpp_id)229 nfp6000_mu_ctm(uint32_t cpp_id)
230 {
231 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
232 case NFP_CPP_ID(0, 16, 1): /* packet_read_packet_status */
233 return PUSHPULL(0, P32);
234 case NFP_CPP_ID(0, 17, 1): /* packet_credit_get */
235 return PUSHPULL(0, P32);
236 case NFP_CPP_ID(0, 17, 3): /* packet_add_thread */
237 return PUSHPULL(0, P64);
238 case NFP_CPP_ID(0, 18, 2): /* packet_free_and_return_pointer */
239 return PUSHPULL(0, P64);
240 case NFP_CPP_ID(0, 18, 3): /* packet_return_pointer */
241 return PUSHPULL(0, P64);
242 case NFP_CPP_ID(0, 21, 0): /* pe_dma_to_memory_indirect */
243 return PUSHPULL(0, P64);
244 case NFP_CPP_ID(0, 21, 1): /* pe_dma_to_memory_indirect_swap */
245 return PUSHPULL(0, P64);
246 case NFP_CPP_ID(0, 21, 2): /* pe_dma_to_memory_indirect_free */
247 return PUSHPULL(0, P64);
248 case NFP_CPP_ID(0, 21, 3): /* pe_dma_to_memory_indirect_free_swap */
249 return PUSHPULL(0, P64);
250 default:
251 return nfp6000_mu_common(cpp_id);
252 }
253 }
254
255 static int
nfp6000_mu_emu(uint32_t cpp_id)256 nfp6000_mu_emu(uint32_t cpp_id)
257 {
258 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
259 case NFP_CPP_ID(0, 18, 0): /* read_queue */
260 return PUSHPULL(0, P32);
261 case NFP_CPP_ID(0, 18, 1): /* read_queue_ring */
262 return PUSHPULL(0, P32);
263 case NFP_CPP_ID(0, 18, 2): /* write_queue */
264 return PUSHPULL(P32, 0);
265 case NFP_CPP_ID(0, 18, 3): /* write_queue_ring */
266 return PUSHPULL(P32, 0);
267 case NFP_CPP_ID(0, 20, 0): /* put */
268 return PUSHPULL(P32, 0);
269 case NFP_CPP_ID(0, 20, 2): /* journal */
270 return PUSHPULL(P32, 0);
271 case NFP_CPP_ID(0, 21, 0): /* get */
272 return PUSHPULL(0, P32);
273 case NFP_CPP_ID(0, 21, 1): /* get_eop */
274 return PUSHPULL(0, P32);
275 case NFP_CPP_ID(0, 21, 2): /* get_freely */
276 return PUSHPULL(0, P32);
277 case NFP_CPP_ID(0, 22, 0): /* pop */
278 return PUSHPULL(0, P32);
279 case NFP_CPP_ID(0, 22, 1): /* pop_eop */
280 return PUSHPULL(0, P32);
281 case NFP_CPP_ID(0, 22, 2): /* pop_freely */
282 return PUSHPULL(0, P32);
283 default:
284 return nfp6000_mu_common(cpp_id);
285 }
286 }
287
288 static int
nfp6000_mu_imu(uint32_t cpp_id)289 nfp6000_mu_imu(uint32_t cpp_id)
290 {
291 return nfp6000_mu_common(cpp_id);
292 }
293
294 static int
nfp6000_mu(uint32_t cpp_id,uint64_t address)295 nfp6000_mu(uint32_t cpp_id,
296 uint64_t address)
297 {
298 int pp;
299 uint8_t island;
300
301 island = NFP_CPP_ID_ISLAND_of(cpp_id);
302 if (island == 0) {
303 if (address < 0x2000000000ULL)
304 pp = nfp6000_mu_ctm(cpp_id);
305 else if (address < 0x8000000000ULL)
306 pp = nfp6000_mu_emu(cpp_id);
307 else if (address < 0x9800000000ULL)
308 pp = nfp6000_mu_ctm(cpp_id);
309 else if (address < 0x9C00000000ULL)
310 pp = nfp6000_mu_emu(cpp_id);
311 else if (address < 0xA000000000ULL)
312 pp = nfp6000_mu_imu(cpp_id);
313 else
314 pp = nfp6000_mu_ctm(cpp_id);
315 } else if (island >= 24 && island <= 27) {
316 pp = nfp6000_mu_emu(cpp_id);
317 } else if (island >= 28 && island <= 31) {
318 pp = nfp6000_mu_imu(cpp_id);
319 } else if (island == 1 ||
320 (island >= 4 && island <= 7) ||
321 (island >= 12 && island <= 13) ||
322 (island >= 32 && island <= 51)) {
323 pp = nfp6000_mu_ctm(cpp_id);
324 } else {
325 pp = -EINVAL;
326 }
327
328 return pp;
329 }
330
331 static int
nfp6000_ila(uint32_t cpp_id)332 nfp6000_ila(uint32_t cpp_id)
333 {
334 uint8_t island;
335
336 island = NFP_CPP_ID_ISLAND_of(cpp_id);
337 if (island != 0 && (island < 48 || island > 51))
338 return -EINVAL;
339
340 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
341 case NFP_CPP_ID(0, 0, 1): /* read_check_error */
342 return PUSHPULL(0, P32);
343 case NFP_CPP_ID(0, 2, 0): /* read_int */
344 return PUSHPULL(0, P32);
345 case NFP_CPP_ID(0, 3, 0): /* write_int */
346 return PUSHPULL(P32, 0);
347 default:
348 return target_rw(cpp_id, P32, 48, 4);
349 }
350 }
351
352 static int
nfp6000_pci(uint32_t cpp_id)353 nfp6000_pci(uint32_t cpp_id)
354 {
355 uint8_t island;
356
357 island = NFP_CPP_ID_ISLAND_of(cpp_id);
358 if (island != 0 && (island < 4 || island > 7))
359 return -EINVAL;
360
361 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
362 case NFP_CPP_ID(0, 2, 0):
363 return PUSHPULL(0, P32);
364 case NFP_CPP_ID(0, 3, 0):
365 return PUSHPULL(P32, 0);
366 default:
367 return target_rw(cpp_id, P32, 4, 4);
368 }
369 }
370
371 static int
nfp6000_crypto(uint32_t cpp_id)372 nfp6000_crypto(uint32_t cpp_id)
373 {
374 uint8_t island;
375
376 island = NFP_CPP_ID_ISLAND_of(cpp_id);
377 if (island != 0 && (island < 12 || island > 15))
378 return -EINVAL;
379
380 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
381 case NFP_CPP_ID(0, 2, 0):
382 return PUSHPULL(P64, 0);
383 default:
384 return target_rw(cpp_id, P64, 12, 4);
385 }
386 }
387
388 static int
nfp6000_cap_xpb(uint32_t cpp_id)389 nfp6000_cap_xpb(uint32_t cpp_id)
390 {
391 uint8_t island;
392
393 island = NFP_CPP_ID_ISLAND_of(cpp_id);
394 if (island > 63)
395 return -EINVAL;
396
397 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
398 case NFP_CPP_ID(0, 0, 1): /* RingGet */
399 return PUSHPULL(0, P32);
400 case NFP_CPP_ID(0, 0, 2): /* Interthread Signal */
401 return PUSHPULL(P32, 0);
402 case NFP_CPP_ID(0, 1, 1): /* RingPut */
403 return PUSHPULL(P32, 0);
404 case NFP_CPP_ID(0, 1, 2): /* CTNNWr */
405 return PUSHPULL(P32, 0);
406 case NFP_CPP_ID(0, 2, 0): /* ReflectRd, signal none */
407 return PUSHPULL(0, P32);
408 case NFP_CPP_ID(0, 2, 1): /* ReflectRd, signal self */
409 return PUSHPULL(0, P32);
410 case NFP_CPP_ID(0, 2, 2): /* ReflectRd, signal remote */
411 return PUSHPULL(0, P32);
412 case NFP_CPP_ID(0, 2, 3): /* ReflectRd, signal both */
413 return PUSHPULL(0, P32);
414 case NFP_CPP_ID(0, 3, 0): /* ReflectWr, signal none */
415 return PUSHPULL(P32, 0);
416 case NFP_CPP_ID(0, 3, 1): /* ReflectWr, signal self */
417 return PUSHPULL(P32, 0);
418 case NFP_CPP_ID(0, 3, 2): /* ReflectWr, signal remote */
419 return PUSHPULL(P32, 0);
420 case NFP_CPP_ID(0, 3, 3): /* ReflectWr, signal both */
421 return PUSHPULL(P32, 0);
422 case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 1):
423 return PUSHPULL(P32, P32);
424 default:
425 return target_rw(cpp_id, P32, 1, 63);
426 }
427 }
428
429 static int
nfp6000_cls(uint32_t cpp_id)430 nfp6000_cls(uint32_t cpp_id)
431 {
432 uint8_t island;
433
434 island = NFP_CPP_ID_ISLAND_of(cpp_id);
435 if (island > 63)
436 return -EINVAL;
437
438 switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
439 case NFP_CPP_ID(0, 0, 3): /* xor */
440 return PUSHPULL(P32, 0);
441 case NFP_CPP_ID(0, 2, 0): /* set */
442 return PUSHPULL(P32, 0);
443 case NFP_CPP_ID(0, 2, 1): /* clr */
444 return PUSHPULL(P32, 0);
445 case NFP_CPP_ID(0, 4, 0): /* add */
446 return PUSHPULL(P32, 0);
447 case NFP_CPP_ID(0, 4, 1): /* add64 */
448 return PUSHPULL(P32, 0);
449 case NFP_CPP_ID(0, 6, 0): /* sub */
450 return PUSHPULL(P32, 0);
451 case NFP_CPP_ID(0, 6, 1): /* sub64 */
452 return PUSHPULL(P32, 0);
453 case NFP_CPP_ID(0, 6, 2): /* subsat */
454 return PUSHPULL(P32, 0);
455 case NFP_CPP_ID(0, 8, 2): /* hash_mask */
456 return PUSHPULL(P32, 0);
457 case NFP_CPP_ID(0, 8, 3): /* hash_clear */
458 return PUSHPULL(P32, 0);
459 case NFP_CPP_ID(0, 9, 0): /* ring_get */
460 return PUSHPULL(0, P32);
461 case NFP_CPP_ID(0, 9, 1): /* ring_pop */
462 return PUSHPULL(0, P32);
463 case NFP_CPP_ID(0, 9, 2): /* ring_get_freely */
464 return PUSHPULL(0, P32);
465 case NFP_CPP_ID(0, 9, 3): /* ring_pop_freely */
466 return PUSHPULL(0, P32);
467 case NFP_CPP_ID(0, 10, 0): /* ring_put */
468 return PUSHPULL(P32, 0);
469 case NFP_CPP_ID(0, 10, 2): /* ring_journal */
470 return PUSHPULL(P32, 0);
471 case NFP_CPP_ID(0, 14, 0): /* reflect_write_sig_local */
472 return PUSHPULL(P32, 0);
473 case NFP_CPP_ID(0, 15, 1): /* reflect_read_sig_local */
474 return PUSHPULL(0, P32);
475 case NFP_CPP_ID(0, 17, 2): /* statistic */
476 return PUSHPULL(P32, 0);
477 case NFP_CPP_ID(0, 24, 0): /* ring_read */
478 return PUSHPULL(0, P32);
479 case NFP_CPP_ID(0, 24, 1): /* ring_write */
480 return PUSHPULL(P32, 0);
481 case NFP_CPP_ID(0, 25, 0): /* ring_workq_add_thread */
482 return PUSHPULL(0, P32);
483 case NFP_CPP_ID(0, 25, 1): /* ring_workq_add_work */
484 return PUSHPULL(P32, 0);
485 default:
486 return target_rw(cpp_id, P32, 0, 64);
487 }
488 }
489
490 int
nfp_target_pushpull(uint32_t cpp_id,uint64_t address)491 nfp_target_pushpull(uint32_t cpp_id,
492 uint64_t address)
493 {
494 switch (NFP_CPP_ID_TARGET_of(cpp_id)) {
495 case NFP_CPP_TARGET_NBI:
496 return nfp6000_nbi(cpp_id, address);
497 case NFP_CPP_TARGET_QDR:
498 return target_rw(cpp_id, P32, 24, 4);
499 case NFP_CPP_TARGET_ILA:
500 return nfp6000_ila(cpp_id);
501 case NFP_CPP_TARGET_MU:
502 return nfp6000_mu(cpp_id, address);
503 case NFP_CPP_TARGET_PCIE:
504 return nfp6000_pci(cpp_id);
505 case NFP_CPP_TARGET_ARM:
506 if (address < 0x10000)
507 return target_rw(cpp_id, P64, 1, 1);
508 else
509 return target_rw(cpp_id, P32, 1, 1);
510 case NFP_CPP_TARGET_CRYPTO:
511 return nfp6000_crypto(cpp_id);
512 case NFP_CPP_TARGET_CT_XPB:
513 return nfp6000_cap_xpb(cpp_id);
514 case NFP_CPP_TARGET_CLS:
515 return nfp6000_cls(cpp_id);
516 case NFP_CPP_TARGET_INVALID:
517 return target_rw(cpp_id, P32, 4, 4);
518 default:
519 return -EINVAL;
520 }
521 }
522
523 static uint64_t
nfp_mask64(int msb,int lsb)524 nfp_mask64(int msb,
525 int lsb)
526 {
527 int width;
528
529 if (msb < 0 || lsb < 0)
530 return 0;
531
532 width = msb - lsb + 1;
533 if (width <= 0)
534 return 0;
535
536 if (width == 64)
537 return ~(uint64_t)0;
538
539 if ((lsb + width) > 64)
540 return 0;
541
542 return (RTE_BIT64(width) - 1) << lsb;
543 }
544
545 static int
nfp_decode_basic(uint64_t addr,int * dest_island,int cpp_tgt,int mode,int addr40,int isld1,int isld0)546 nfp_decode_basic(uint64_t addr,
547 int *dest_island,
548 int cpp_tgt,
549 int mode,
550 int addr40,
551 int isld1,
552 int isld0)
553 {
554 int iid_lsb;
555 int idx_lsb;
556
557 /* This function doesn't handle MU or CTXBP */
558 if (cpp_tgt == NFP_CPP_TARGET_MU || cpp_tgt == NFP_CPP_TARGET_CT_XPB)
559 return -EINVAL;
560
561 switch (mode) {
562 case 0:
563 /*
564 * For VQDR, in this mode for 32-bit addressing it would be
565 * islands 0, 16, 32 and 48 depending on channel and upper
566 * address bits. Since those are not all valid islands, most
567 * decode cases would result in bad island IDs, but we do them
568 * anyway since this is decoding an address that is already
569 * assumed to be used as-is to get to sram.
570 */
571 iid_lsb = (addr40) ? 34 : 26;
572 *dest_island = (int)(addr >> iid_lsb) & 0x3F;
573
574 return 0;
575 case 1:
576 /*
577 * For VQDR 32-bit, this would decode as:
578 * Channel 0: island#0
579 * Channel 1: island#0
580 * Channel 2: island#1
581 * Channel 3: island#1
582 *
583 * That would be valid as long as both islands have VQDR.
584 * Let's allow this.
585 */
586 idx_lsb = (addr40) ? 39 : 31;
587 if ((addr & nfp_mask64(idx_lsb, idx_lsb)) != 0)
588 *dest_island = isld1;
589 else
590 *dest_island = isld0;
591
592 return 0;
593 case 2:
594 /*
595 * For VQDR 32-bit:
596 * Channel 0: (island#0 | 0)
597 * Channel 1: (island#0 | 1)
598 * Channel 2: (island#1 | 0)
599 * Channel 3: (island#1 | 1)
600 *
601 * Make sure we compare against isldN values by clearing the
602 * LSB. This is what the silicon does.
603 */
604 isld0 &= ~1;
605 isld1 &= ~1;
606
607 idx_lsb = (addr40) ? 39 : 31;
608 iid_lsb = idx_lsb - 1;
609
610 if ((addr & nfp_mask64(idx_lsb, idx_lsb)) != 0)
611 *dest_island = isld1 | (int)((addr >> iid_lsb) & 1);
612 else
613 *dest_island = isld0 | (int)((addr >> iid_lsb) & 1);
614
615 return 0;
616 case 3:
617 /*
618 * In this mode the data address starts to affect the island ID
619 * so rather not allow it. In some really specific case one
620 * could use this to send the upper half of the VQDR channel to
621 * another MU, but this is getting very specific. However, as
622 * above for mode 0, this is the decoder and the caller should
623 * validate the resulting IID. This blindly does what the
624 * silicon would do.
625 */
626 isld0 &= ~3;
627 isld1 &= ~3;
628
629 idx_lsb = (addr40) ? 39 : 31;
630 iid_lsb = idx_lsb - 2;
631
632 if ((addr & nfp_mask64(idx_lsb, idx_lsb)) != 0)
633 *dest_island = isld1 | (int)((addr >> iid_lsb) & 3);
634 else
635 *dest_island = isld0 | (int)((addr >> iid_lsb) & 3);
636
637 return 0;
638 default:
639 return -EINVAL;
640 }
641 }
642
643 static int
nfp_encode_basic_qdr(uint64_t addr,int dest_island,int cpp_tgt,int mode,int addr40,int isld1,int isld0)644 nfp_encode_basic_qdr(uint64_t addr,
645 int dest_island,
646 int cpp_tgt,
647 int mode,
648 int addr40,
649 int isld1,
650 int isld0)
651 {
652 int v;
653 int ret;
654
655 /* Full Island ID and channel bits overlap? */
656 ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0);
657 if (ret != 0)
658 return ret;
659
660 /* The current address won't go where expected? */
661 if (dest_island != -1 && dest_island != v)
662 return -EINVAL;
663
664 /* If dest_island was -1, we don't care where it goes. */
665 return 0;
666 }
667
668 /*
669 * Try each option, take first one that fits.
670 * Not sure if we would want to do some smarter
671 * searching and prefer 0 or non-0 island IDs.
672 */
673 static int
nfp_encode_basic_search(uint64_t * addr,int dest_island,int * isld,int iid_lsb,int idx_lsb,int v_max)674 nfp_encode_basic_search(uint64_t *addr,
675 int dest_island,
676 int *isld,
677 int iid_lsb,
678 int idx_lsb,
679 int v_max)
680 {
681 int i;
682 int v;
683
684 for (i = 0; i < 2; i++)
685 for (v = 0; v < v_max; v++) {
686 if (dest_island != (isld[i] | v))
687 continue;
688
689 *addr &= ~nfp_mask64(idx_lsb, iid_lsb);
690 *addr |= ((uint64_t)i << idx_lsb);
691 *addr |= ((uint64_t)v << iid_lsb);
692 return 0;
693 }
694
695 return -ENODEV;
696 }
697
698 /*
699 * For VQDR, we may not modify the Channel bits, which might overlap
700 * with the Index bit. When it does, we need to ensure that isld0 == isld1.
701 */
702 static int
nfp_encode_basic(uint64_t * addr,int dest_island,int cpp_tgt,int mode,int addr40,int isld1,int isld0)703 nfp_encode_basic(uint64_t *addr,
704 int dest_island,
705 int cpp_tgt,
706 int mode,
707 int addr40,
708 int isld1,
709 int isld0)
710 {
711 int iid_lsb;
712 int idx_lsb;
713 int isld[2];
714 uint64_t value;
715
716 isld[0] = isld0;
717 isld[1] = isld1;
718
719 /* This function doesn't handle MU or CTXBP */
720 if (cpp_tgt == NFP_CPP_TARGET_MU || cpp_tgt == NFP_CPP_TARGET_CT_XPB)
721 return -EINVAL;
722
723 switch (mode) {
724 case 0:
725 if (cpp_tgt == NFP_CPP_TARGET_QDR && addr40 == 0) {
726 /*
727 * In this specific mode we'd rather not modify the
728 * address but we can verify if the existing contents
729 * will point to a valid island.
730 */
731 return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
732 mode, addr40, isld1, isld0);
733 }
734
735 iid_lsb = (addr40) ? 34 : 26;
736
737 /* <39:34> or <31:26> */
738 value = nfp_mask64((iid_lsb + 5), iid_lsb);
739 *addr &= ~value;
740 *addr |= (((uint64_t)dest_island) << iid_lsb) & value;
741 return 0;
742 case 1:
743 if (cpp_tgt == NFP_CPP_TARGET_QDR && addr40 == 0) {
744 return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
745 mode, addr40, isld1, isld0);
746 }
747
748 idx_lsb = (addr40) ? 39 : 31;
749 if (dest_island == isld0) {
750 /* Only need to clear the Index bit */
751 *addr &= ~nfp_mask64(idx_lsb, idx_lsb);
752 return 0;
753 }
754
755 if (dest_island == isld1) {
756 /* Only need to set the Index bit */
757 *addr |= (UINT64_C(1) << idx_lsb);
758 return 0;
759 }
760
761 return -ENODEV;
762 case 2:
763 if (cpp_tgt == NFP_CPP_TARGET_QDR && addr40 == 0) {
764 /* iid<0> = addr<30> = channel<0> */
765 /* channel<1> = addr<31> = Index */
766 return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
767 mode, addr40, isld1, isld0);
768 }
769
770 /*
771 * Make sure we compare against isldN values by clearing the
772 * LSB. This is what the silicon does.
773 */
774 isld[0] &= ~1;
775 isld[1] &= ~1;
776
777 idx_lsb = (addr40) ? 39 : 31;
778 iid_lsb = idx_lsb - 1;
779
780 return nfp_encode_basic_search(addr, dest_island, isld,
781 iid_lsb, idx_lsb, 2);
782 case 3:
783 if (cpp_tgt == NFP_CPP_TARGET_QDR && addr40 == 0) {
784 /*
785 * iid<0> = addr<29> = data
786 * iid<1> = addr<30> = channel<0>
787 * channel<1> = addr<31> = Index
788 */
789 return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
790 mode, addr40, isld1, isld0);
791 }
792
793 isld[0] &= ~3;
794 isld[1] &= ~3;
795
796 idx_lsb = (addr40) ? 39 : 31;
797 iid_lsb = idx_lsb - 2;
798
799 return nfp_encode_basic_search(addr, dest_island, isld,
800 iid_lsb, idx_lsb, 4);
801 default:
802 return -EINVAL;
803 }
804 }
805
806 static int
nfp_encode_mu(uint64_t * addr,int dest_island,int mode,int addr40,int isld1,int isld0)807 nfp_encode_mu(uint64_t *addr,
808 int dest_island,
809 int mode,
810 int addr40,
811 int isld1,
812 int isld0)
813 {
814 int da;
815 int iid_lsb;
816 int idx_lsb;
817 int isld[2];
818 uint64_t value;
819 int locality_lsb;
820
821 isld[0] = isld0;
822 isld[1] = isld1;
823
824 locality_lsb = nfp_cppat_mu_locality_lsb(mode, addr40);
825 if (locality_lsb < 0)
826 return -EINVAL;
827
828 if (((*addr >> locality_lsb) & 3) == NFP6000_MU_LOCALITY_DIRECT)
829 da = 1;
830 else
831 da = 0;
832
833 switch (mode) {
834 case 0:
835 iid_lsb = (addr40 != 0) ? 32 : 24;
836 value = nfp_mask64((iid_lsb + 5), iid_lsb);
837 *addr &= ~value;
838 *addr |= (((uint64_t)dest_island) << iid_lsb) & value;
839 return 0;
840 case 1:
841 if (da == 1) {
842 iid_lsb = (addr40 != 0) ? 32 : 24;
843 value = nfp_mask64((iid_lsb + 5), iid_lsb);
844 *addr &= ~value;
845 *addr |= (((uint64_t)dest_island) << iid_lsb) & value;
846 return 0;
847 }
848
849 idx_lsb = (addr40 != 0) ? 37 : 29;
850 if (dest_island == isld0) {
851 *addr &= ~nfp_mask64(idx_lsb, idx_lsb);
852 return 0;
853 }
854
855 if (dest_island == isld1) {
856 *addr |= (UINT64_C(1) << idx_lsb);
857 return 0;
858 }
859
860 return -ENODEV;
861 case 2:
862 if (da == 1) {
863 iid_lsb = (addr40 != 0) ? 32 : 24;
864 value = nfp_mask64((iid_lsb + 5), iid_lsb);
865 *addr &= ~value;
866 *addr |= (((uint64_t)dest_island) << iid_lsb) & value;
867 return 0;
868 }
869
870 /*
871 * Make sure we compare against isldN values by clearing the
872 * LSB. This is what the silicon does.
873 */
874 isld[0] &= ~1;
875 isld[1] &= ~1;
876
877 idx_lsb = (addr40 != 0) ? 37 : 29;
878 iid_lsb = idx_lsb - 1;
879
880 return nfp_encode_basic_search(addr, dest_island, isld,
881 iid_lsb, idx_lsb, 2);
882 case 3:
883 /*
884 * Only the EMU will use 40 bit addressing. Silently set the
885 * direct locality bit for everyone else. The SDK toolchain
886 * uses dest_island <= 0 to test for atypical address encodings
887 * to support access to local-island CTM with a 32-but address
888 * (high-locality is effectively ignored and just used for
889 * routing to island #0).
890 */
891 if (dest_island > 0 && (dest_island < 24 || dest_island > 26)) {
892 *addr |= ((uint64_t)NFP6000_MU_LOCALITY_DIRECT)
893 << locality_lsb;
894 da = 1;
895 }
896
897 if (da == 1) {
898 iid_lsb = (addr40 != 0) ? 32 : 24;
899 value = nfp_mask64((iid_lsb + 5), iid_lsb);
900 *addr &= ~value;
901 *addr |= (((uint64_t)dest_island) << iid_lsb) & value;
902 return 0;
903 }
904
905 isld[0] &= ~3;
906 isld[1] &= ~3;
907
908 idx_lsb = (addr40 != 0) ? 37 : 29;
909 iid_lsb = idx_lsb - 2;
910
911 return nfp_encode_basic_search(addr, dest_island, isld,
912 iid_lsb, idx_lsb, 4);
913 default:
914 return -EINVAL;
915 }
916 }
917
918 static int
nfp_cppat_addr_encode(uint64_t * addr,int dest_island,int cpp_tgt,int mode,int addr40,int isld1,int isld0)919 nfp_cppat_addr_encode(uint64_t *addr,
920 int dest_island,
921 int cpp_tgt,
922 int mode,
923 int addr40,
924 int isld1,
925 int isld0)
926 {
927 uint64_t value;
928
929 switch (cpp_tgt) {
930 case NFP_CPP_TARGET_NBI:
931 case NFP_CPP_TARGET_QDR:
932 case NFP_CPP_TARGET_ILA:
933 case NFP_CPP_TARGET_PCIE:
934 case NFP_CPP_TARGET_ARM:
935 case NFP_CPP_TARGET_CRYPTO:
936 case NFP_CPP_TARGET_CLS:
937 return nfp_encode_basic(addr, dest_island, cpp_tgt, mode,
938 addr40, isld1, isld0);
939 case NFP_CPP_TARGET_MU:
940 return nfp_encode_mu(addr, dest_island, mode, addr40,
941 isld1, isld0);
942 case NFP_CPP_TARGET_CT_XPB:
943 if (mode != 1 || addr40 != 0)
944 return -EINVAL;
945
946 value = nfp_mask64(29, 24);
947 *addr &= ~value;
948 *addr |= (((uint64_t)dest_island) << 24) & value;
949 return 0;
950 default:
951 return -EINVAL;
952 }
953 }
954
955 int
nfp_target_cpp(uint32_t cpp_island_id,uint64_t cpp_island_address,uint32_t * cpp_target_id,uint64_t * cpp_target_address,const uint32_t * imb_table)956 nfp_target_cpp(uint32_t cpp_island_id,
957 uint64_t cpp_island_address,
958 uint32_t *cpp_target_id,
959 uint64_t *cpp_target_address,
960 const uint32_t *imb_table)
961 {
962 int err;
963 uint32_t imb;
964 uint8_t island;
965 uint8_t target;
966
967 target = NFP_CPP_ID_TARGET_of(cpp_island_id);
968 if (target >= 16)
969 return -EINVAL;
970
971 island = NFP_CPP_ID_ISLAND_of(cpp_island_id);
972 if (island == 0) {
973 /* Already translated */
974 *cpp_target_id = cpp_island_id;
975 *cpp_target_address = cpp_island_address;
976 return 0;
977 }
978
979 /* CPP + Island only allowed on systems with IMB tables */
980 if (imb_table == NULL)
981 return -EINVAL;
982
983 imb = imb_table[target];
984
985 *cpp_target_address = cpp_island_address;
986 err = nfp_cppat_addr_encode(cpp_target_address, island, target,
987 ((imb >> 13) & 7), ((imb >> 12) & 1),
988 ((imb >> 6) & 0x3f), ((imb >> 0) & 0x3f));
989 if (err != 0)
990 return err;
991
992 *cpp_target_id = NFP_CPP_ID(target,
993 NFP_CPP_ID_ACTION_of(cpp_island_id),
994 NFP_CPP_ID_TOKEN_of(cpp_island_id));
995
996 return 0;
997 }
998