xref: /dpdk/drivers/net/nfp/nfpcore/nfp_target.c (revision 3da59f30a23f2e795d2315f3d949e1b3e0ce0c3d)
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
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
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
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
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
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
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
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
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
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, 2): /* journal */
268 		return PUSHPULL(P32, 0);
269 	case NFP_CPP_ID(0, 21, 0): /* get */
270 		return PUSHPULL(0, P32);
271 	case NFP_CPP_ID(0, 21, 1): /* get_eop */
272 		return PUSHPULL(0, P32);
273 	case NFP_CPP_ID(0, 21, 2): /* get_freely */
274 		return PUSHPULL(0, P32);
275 	case NFP_CPP_ID(0, 22, 0): /* pop */
276 		return PUSHPULL(0, P32);
277 	case NFP_CPP_ID(0, 22, 1): /* pop_eop */
278 		return PUSHPULL(0, P32);
279 	case NFP_CPP_ID(0, 22, 2): /* pop_freely */
280 		return PUSHPULL(0, P32);
281 	default:
282 		return nfp6000_mu_common(cpp_id);
283 	}
284 }
285 
286 static int
287 nfp6000_mu_imu(uint32_t cpp_id)
288 {
289 	return nfp6000_mu_common(cpp_id);
290 }
291 
292 static int
293 nfp6000_mu(uint32_t cpp_id,
294 		uint64_t address)
295 {
296 	int pp;
297 	uint8_t island;
298 
299 	island = NFP_CPP_ID_ISLAND_of(cpp_id);
300 	if (island == 0) {
301 		if (address < 0x2000000000ULL)
302 			pp = nfp6000_mu_ctm(cpp_id);
303 		else if (address < 0x8000000000ULL)
304 			pp = nfp6000_mu_emu(cpp_id);
305 		else if (address < 0x9800000000ULL)
306 			pp = nfp6000_mu_ctm(cpp_id);
307 		else if (address < 0x9C00000000ULL)
308 			pp = nfp6000_mu_emu(cpp_id);
309 		else if (address < 0xA000000000ULL)
310 			pp = nfp6000_mu_imu(cpp_id);
311 		else
312 			pp = nfp6000_mu_ctm(cpp_id);
313 	} else if (island >= 24 && island <= 27) {
314 		pp = nfp6000_mu_emu(cpp_id);
315 	} else if (island >= 28 && island <= 31) {
316 		pp = nfp6000_mu_imu(cpp_id);
317 	} else if (island == 1 ||
318 			(island >= 4 && island <= 7) ||
319 			(island >= 12 && island <= 13) ||
320 			(island >= 32 && island <= 51)) {
321 		pp = nfp6000_mu_ctm(cpp_id);
322 	} else {
323 		pp = -EINVAL;
324 	}
325 
326 	return pp;
327 }
328 
329 static int
330 nfp6000_ila(uint32_t cpp_id)
331 {
332 	uint8_t island;
333 
334 	island = NFP_CPP_ID_ISLAND_of(cpp_id);
335 	if (island != 0 && (island < 48 || island > 51))
336 		return -EINVAL;
337 
338 	switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
339 	case NFP_CPP_ID(0, 0, 1): /* read_check_error */
340 		return PUSHPULL(0, P32);
341 	case NFP_CPP_ID(0, 2, 0): /* read_int */
342 		return PUSHPULL(0, P32);
343 	case NFP_CPP_ID(0, 3, 0): /* write_int */
344 		return PUSHPULL(P32, 0);
345 	default:
346 		return target_rw(cpp_id, P32, 48, 4);
347 	}
348 }
349 
350 static int
351 nfp6000_pci(uint32_t cpp_id)
352 {
353 	uint8_t island;
354 
355 	island = NFP_CPP_ID_ISLAND_of(cpp_id);
356 	if (island != 0 && (island < 4 || island > 7))
357 		return -EINVAL;
358 
359 	switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
360 	case NFP_CPP_ID(0, 2, 0):
361 		return PUSHPULL(0, P32);
362 	case NFP_CPP_ID(0, 3, 0):
363 		return PUSHPULL(P32, 0);
364 	default:
365 		return target_rw(cpp_id, P32, 4, 4);
366 	}
367 }
368 
369 static int
370 nfp6000_crypto(uint32_t cpp_id)
371 {
372 	uint8_t island;
373 
374 	island = NFP_CPP_ID_ISLAND_of(cpp_id);
375 	if (island != 0 && (island < 12 || island > 15))
376 		return -EINVAL;
377 
378 	switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
379 	case NFP_CPP_ID(0, 2, 0):
380 		return PUSHPULL(P64, 0);
381 	default:
382 		return target_rw(cpp_id, P64, 12, 4);
383 	}
384 }
385 
386 static int
387 nfp6000_cap_xpb(uint32_t cpp_id)
388 {
389 	uint8_t island;
390 
391 	island = NFP_CPP_ID_ISLAND_of(cpp_id);
392 	if (island > 63)
393 		return -EINVAL;
394 
395 	switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
396 	case NFP_CPP_ID(0, 0, 1): /* RingGet */
397 		return PUSHPULL(0, P32);
398 	case NFP_CPP_ID(0, 0, 2): /* Interthread Signal */
399 		return PUSHPULL(P32, 0);
400 	case NFP_CPP_ID(0, 1, 1): /* RingPut */
401 		return PUSHPULL(P32, 0);
402 	case NFP_CPP_ID(0, 1, 2): /* CTNNWr */
403 		return PUSHPULL(P32, 0);
404 	case NFP_CPP_ID(0, 2, 0): /* ReflectRd, signal none */
405 		return PUSHPULL(0, P32);
406 	case NFP_CPP_ID(0, 2, 1): /* ReflectRd, signal self */
407 		return PUSHPULL(0, P32);
408 	case NFP_CPP_ID(0, 2, 2): /* ReflectRd, signal remote */
409 		return PUSHPULL(0, P32);
410 	case NFP_CPP_ID(0, 2, 3): /* ReflectRd, signal both */
411 		return PUSHPULL(0, P32);
412 	case NFP_CPP_ID(0, 3, 0): /* ReflectWr, signal none */
413 		return PUSHPULL(P32, 0);
414 	case NFP_CPP_ID(0, 3, 1): /* ReflectWr, signal self */
415 		return PUSHPULL(P32, 0);
416 	case NFP_CPP_ID(0, 3, 2): /* ReflectWr, signal remote */
417 		return PUSHPULL(P32, 0);
418 	case NFP_CPP_ID(0, 3, 3): /* ReflectWr, signal both */
419 		return PUSHPULL(P32, 0);
420 	case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 1):
421 		return PUSHPULL(P32, P32);
422 	default:
423 		return target_rw(cpp_id, P32, 1, 63);
424 	}
425 }
426 
427 static int
428 nfp6000_cls(uint32_t cpp_id)
429 {
430 	uint8_t island;
431 
432 	island = NFP_CPP_ID_ISLAND_of(cpp_id);
433 	if (island > 63)
434 		return -EINVAL;
435 
436 	switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
437 	case NFP_CPP_ID(0, 0, 3): /* xor */
438 		return PUSHPULL(P32, 0);
439 	case NFP_CPP_ID(0, 2, 0): /* set */
440 		return PUSHPULL(P32, 0);
441 	case NFP_CPP_ID(0, 2, 1): /* clr */
442 		return PUSHPULL(P32, 0);
443 	case NFP_CPP_ID(0, 4, 0): /* add */
444 		return PUSHPULL(P32, 0);
445 	case NFP_CPP_ID(0, 4, 1): /* add64 */
446 		return PUSHPULL(P32, 0);
447 	case NFP_CPP_ID(0, 6, 0): /* sub */
448 		return PUSHPULL(P32, 0);
449 	case NFP_CPP_ID(0, 6, 1): /* sub64 */
450 		return PUSHPULL(P32, 0);
451 	case NFP_CPP_ID(0, 6, 2): /* subsat */
452 		return PUSHPULL(P32, 0);
453 	case NFP_CPP_ID(0, 8, 2): /* hash_mask */
454 		return PUSHPULL(P32, 0);
455 	case NFP_CPP_ID(0, 8, 3): /* hash_clear */
456 		return PUSHPULL(P32, 0);
457 	case NFP_CPP_ID(0, 9, 0): /* ring_get */
458 		return PUSHPULL(0, P32);
459 	case NFP_CPP_ID(0, 9, 1): /* ring_pop */
460 		return PUSHPULL(0, P32);
461 	case NFP_CPP_ID(0, 9, 2): /* ring_get_freely */
462 		return PUSHPULL(0, P32);
463 	case NFP_CPP_ID(0, 9, 3): /* ring_pop_freely */
464 		return PUSHPULL(0, P32);
465 	case NFP_CPP_ID(0, 10, 0): /* ring_put */
466 		return PUSHPULL(P32, 0);
467 	case NFP_CPP_ID(0, 10, 2): /* ring_journal */
468 		return PUSHPULL(P32, 0);
469 	case NFP_CPP_ID(0, 14, 0): /* reflect_write_sig_local */
470 		return PUSHPULL(P32, 0);
471 	case NFP_CPP_ID(0, 15, 1):  /* reflect_read_sig_local */
472 		return PUSHPULL(0, P32);
473 	case NFP_CPP_ID(0, 17, 2): /* statistic */
474 		return PUSHPULL(P32, 0);
475 	case NFP_CPP_ID(0, 24, 0): /* ring_read */
476 		return PUSHPULL(0, P32);
477 	case NFP_CPP_ID(0, 24, 1): /* ring_write */
478 		return PUSHPULL(P32, 0);
479 	case NFP_CPP_ID(0, 25, 0): /* ring_workq_add_thread */
480 		return PUSHPULL(0, P32);
481 	case NFP_CPP_ID(0, 25, 1): /* ring_workq_add_work */
482 		return PUSHPULL(P32, 0);
483 	default:
484 		return target_rw(cpp_id, P32, 0, 64);
485 	}
486 }
487 
488 int
489 nfp_target_pushpull(uint32_t cpp_id,
490 		uint64_t address)
491 {
492 	switch (NFP_CPP_ID_TARGET_of(cpp_id)) {
493 	case NFP_CPP_TARGET_NBI:
494 		return nfp6000_nbi(cpp_id, address);
495 	case NFP_CPP_TARGET_QDR:
496 		return target_rw(cpp_id, P32, 24, 4);
497 	case NFP_CPP_TARGET_ILA:
498 		return nfp6000_ila(cpp_id);
499 	case NFP_CPP_TARGET_MU:
500 		return nfp6000_mu(cpp_id, address);
501 	case NFP_CPP_TARGET_PCIE:
502 		return nfp6000_pci(cpp_id);
503 	case NFP_CPP_TARGET_ARM:
504 		if (address < 0x10000)
505 			return target_rw(cpp_id, P64, 1, 1);
506 		else
507 			return target_rw(cpp_id, P32, 1, 1);
508 	case NFP_CPP_TARGET_CRYPTO:
509 		return nfp6000_crypto(cpp_id);
510 	case NFP_CPP_TARGET_CT_XPB:
511 		return nfp6000_cap_xpb(cpp_id);
512 	case NFP_CPP_TARGET_CLS:
513 		return nfp6000_cls(cpp_id);
514 	case NFP_CPP_TARGET_INVALID:
515 		return target_rw(cpp_id, P32, 4, 4);
516 	default:
517 		return -EINVAL;
518 	}
519 }
520 
521 static uint64_t
522 nfp_mask64(int msb,
523 		int lsb)
524 {
525 	int width;
526 
527 	if (msb < 0 || lsb < 0)
528 		return 0;
529 
530 	width = msb - lsb + 1;
531 	if (width <= 0)
532 		return 0;
533 
534 	if (width == 64)
535 		return ~(uint64_t)0;
536 
537 	if ((lsb + width) > 64)
538 		return 0;
539 
540 	return (RTE_BIT64(width) - 1) << lsb;
541 }
542 
543 static int
544 nfp_decode_basic(uint64_t addr,
545 		int *dest_island,
546 		int cpp_tgt,
547 		int mode,
548 		int addr40,
549 		int isld1,
550 		int isld0)
551 {
552 	int iid_lsb;
553 	int idx_lsb;
554 
555 	/* This function doesn't handle MU or CTXBP */
556 	if (cpp_tgt == NFP_CPP_TARGET_MU || cpp_tgt == NFP_CPP_TARGET_CT_XPB)
557 		return -EINVAL;
558 
559 	switch (mode) {
560 	case 0:
561 		/*
562 		 * For VQDR, in this mode for 32-bit addressing it would be
563 		 * islands 0, 16, 32 and 48 depending on channel and upper
564 		 * address bits. Since those are not all valid islands, most
565 		 * decode cases would result in bad island IDs, but we do them
566 		 * anyway since this is decoding an address that is already
567 		 * assumed to be used as-is to get to sram.
568 		 */
569 		iid_lsb = (addr40) ? 34 : 26;
570 		*dest_island = (int)(addr >> iid_lsb) & 0x3F;
571 
572 		return 0;
573 	case 1:
574 		/*
575 		 * For VQDR 32-bit, this would decode as:
576 		 *	Channel 0: island#0
577 		 *	Channel 1: island#0
578 		 *	Channel 2: island#1
579 		 *	Channel 3: island#1
580 		 *
581 		 * That would be valid as long as both islands have VQDR.
582 		 * Let's allow this.
583 		 */
584 		idx_lsb = (addr40) ? 39 : 31;
585 		if ((addr & nfp_mask64(idx_lsb, idx_lsb)) != 0)
586 			*dest_island = isld1;
587 		else
588 			*dest_island = isld0;
589 
590 		return 0;
591 	case 2:
592 		/*
593 		 * For VQDR 32-bit:
594 		 *	Channel 0: (island#0 | 0)
595 		 *	Channel 1: (island#0 | 1)
596 		 *	Channel 2: (island#1 | 0)
597 		 *	Channel 3: (island#1 | 1)
598 		 *
599 		 * Make sure we compare against isldN values by clearing the
600 		 * LSB. This is what the silicon does.
601 		 */
602 		isld0 &= ~1;
603 		isld1 &= ~1;
604 
605 		idx_lsb = (addr40) ? 39 : 31;
606 		iid_lsb = idx_lsb - 1;
607 
608 		if ((addr & nfp_mask64(idx_lsb, idx_lsb)) != 0)
609 			*dest_island = isld1 | (int)((addr >> iid_lsb) & 1);
610 		else
611 			*dest_island = isld0 | (int)((addr >> iid_lsb) & 1);
612 
613 		return 0;
614 	case 3:
615 		/*
616 		 * In this mode the data address starts to affect the island ID
617 		 * so rather not allow it. In some really specific case one
618 		 * could use this to send the upper half of the VQDR channel to
619 		 * another MU, but this is getting very specific. However, as
620 		 * above for mode 0, this is the decoder and the caller should
621 		 * validate the resulting IID. This blindly does what the
622 		 * silicon would do.
623 		 */
624 		isld0 &= ~3;
625 		isld1 &= ~3;
626 
627 		idx_lsb = (addr40) ? 39 : 31;
628 		iid_lsb = idx_lsb - 2;
629 
630 		if ((addr & nfp_mask64(idx_lsb, idx_lsb)) != 0)
631 			*dest_island = isld1 | (int)((addr >> iid_lsb) & 3);
632 		else
633 			*dest_island = isld0 | (int)((addr >> iid_lsb) & 3);
634 
635 		return 0;
636 	default:
637 		return -EINVAL;
638 	}
639 }
640 
641 static int
642 nfp_encode_basic_qdr(uint64_t addr,
643 		int dest_island,
644 		int cpp_tgt,
645 		int mode,
646 		int addr40,
647 		int isld1,
648 		int isld0)
649 {
650 	int v;
651 	int ret;
652 
653 	/* Full Island ID and channel bits overlap? */
654 	ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0);
655 	if (ret != 0)
656 		return ret;
657 
658 	/* The current address won't go where expected? */
659 	if (dest_island != -1 && dest_island != v)
660 		return -EINVAL;
661 
662 	/* If dest_island was -1, we don't care where it goes. */
663 	return 0;
664 }
665 
666 /*
667  * Try each option, take first one that fits.
668  * Not sure if we would want to do some smarter
669  * searching and prefer 0 or non-0 island IDs.
670  */
671 static int
672 nfp_encode_basic_search(uint64_t *addr,
673 		int dest_island,
674 		int *isld,
675 		int iid_lsb,
676 		int idx_lsb,
677 		int v_max)
678 {
679 	int i;
680 	int v;
681 
682 	for (i = 0; i < 2; i++)
683 		for (v = 0; v < v_max; v++) {
684 			if (dest_island != (isld[i] | v))
685 				continue;
686 
687 			*addr &= ~nfp_mask64(idx_lsb, iid_lsb);
688 			*addr |= ((uint64_t)i << idx_lsb);
689 			*addr |= ((uint64_t)v << iid_lsb);
690 			return 0;
691 		}
692 
693 	return -ENODEV;
694 }
695 
696 /*
697  * For VQDR, we may not modify the Channel bits, which might overlap
698  * with the Index bit. When it does, we need to ensure that isld0 == isld1.
699  */
700 static int
701 nfp_encode_basic(uint64_t *addr,
702 		int dest_island,
703 		int cpp_tgt,
704 		int mode,
705 		int addr40,
706 		int isld1,
707 		int isld0)
708 {
709 	int iid_lsb;
710 	int idx_lsb;
711 	int isld[2];
712 	uint64_t value;
713 
714 	isld[0] = isld0;
715 	isld[1] = isld1;
716 
717 	/* This function doesn't handle MU or CTXBP */
718 	if (cpp_tgt == NFP_CPP_TARGET_MU || cpp_tgt == NFP_CPP_TARGET_CT_XPB)
719 		return -EINVAL;
720 
721 	switch (mode) {
722 	case 0:
723 		if (cpp_tgt == NFP_CPP_TARGET_QDR && addr40 == 0) {
724 			/*
725 			 * In this specific mode we'd rather not modify the
726 			 * address but we can verify if the existing contents
727 			 * will point to a valid island.
728 			 */
729 			return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
730 					mode, addr40, isld1, isld0);
731 		}
732 
733 		iid_lsb = (addr40) ? 34 : 26;
734 
735 		/* <39:34> or <31:26> */
736 		value = nfp_mask64((iid_lsb + 5), iid_lsb);
737 		*addr &= ~value;
738 		*addr |= (((uint64_t)dest_island) << iid_lsb) & value;
739 		return 0;
740 	case 1:
741 		if (cpp_tgt == NFP_CPP_TARGET_QDR && addr40 == 0) {
742 			return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
743 					mode, addr40, isld1, isld0);
744 		}
745 
746 		idx_lsb = (addr40) ? 39 : 31;
747 		if (dest_island == isld0) {
748 			/* Only need to clear the Index bit */
749 			*addr &= ~nfp_mask64(idx_lsb, idx_lsb);
750 			return 0;
751 		}
752 
753 		if (dest_island == isld1) {
754 			/* Only need to set the Index bit */
755 			*addr |= (UINT64_C(1) << idx_lsb);
756 			return 0;
757 		}
758 
759 		return -ENODEV;
760 	case 2:
761 		if (cpp_tgt == NFP_CPP_TARGET_QDR && addr40 == 0) {
762 			/* iid<0> = addr<30> = channel<0> */
763 			/* channel<1> = addr<31> = Index */
764 			return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
765 					mode, addr40, isld1, isld0);
766 		}
767 
768 		/*
769 		 * Make sure we compare against isldN values by clearing the
770 		 * LSB. This is what the silicon does.
771 		 */
772 		isld[0] &= ~1;
773 		isld[1] &= ~1;
774 
775 		idx_lsb = (addr40) ? 39 : 31;
776 		iid_lsb = idx_lsb - 1;
777 
778 		return nfp_encode_basic_search(addr, dest_island, isld,
779 				iid_lsb, idx_lsb, 2);
780 	case 3:
781 		if (cpp_tgt == NFP_CPP_TARGET_QDR && addr40 == 0) {
782 			/*
783 			 * iid<0> = addr<29> = data
784 			 * iid<1> = addr<30> = channel<0>
785 			 * channel<1> = addr<31> = Index
786 			 */
787 			return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
788 					mode, addr40, isld1, isld0);
789 		}
790 
791 		isld[0] &= ~3;
792 		isld[1] &= ~3;
793 
794 		idx_lsb = (addr40) ? 39 : 31;
795 		iid_lsb = idx_lsb - 2;
796 
797 		return nfp_encode_basic_search(addr, dest_island, isld,
798 				iid_lsb, idx_lsb, 4);
799 	default:
800 		return -EINVAL;
801 	}
802 }
803 
804 static int
805 nfp_encode_mu(uint64_t *addr,
806 		int dest_island,
807 		int mode,
808 		int addr40,
809 		int isld1,
810 		int isld0)
811 {
812 	int da;
813 	int iid_lsb;
814 	int idx_lsb;
815 	int isld[2];
816 	uint64_t value;
817 	int locality_lsb;
818 
819 	isld[0] = isld0;
820 	isld[1] = isld1;
821 
822 	locality_lsb = nfp_cppat_mu_locality_lsb(mode, addr40);
823 	if (locality_lsb < 0)
824 		return -EINVAL;
825 
826 	if (((*addr >> locality_lsb) & 3) == NFP6000_MU_LOCALITY_DIRECT)
827 		da = 1;
828 	else
829 		da = 0;
830 
831 	switch (mode) {
832 	case 0:
833 		iid_lsb = (addr40 != 0) ? 32 : 24;
834 		value = nfp_mask64((iid_lsb + 5), iid_lsb);
835 		*addr &= ~value;
836 		*addr |= (((uint64_t)dest_island) << iid_lsb) & value;
837 		return 0;
838 	case 1:
839 		if (da == 1) {
840 			iid_lsb = (addr40 != 0) ? 32 : 24;
841 			value = nfp_mask64((iid_lsb + 5), iid_lsb);
842 			*addr &= ~value;
843 			*addr |= (((uint64_t)dest_island) << iid_lsb) & value;
844 			return 0;
845 		}
846 
847 		idx_lsb = (addr40 != 0) ? 37 : 29;
848 		if (dest_island == isld0) {
849 			*addr &= ~nfp_mask64(idx_lsb, idx_lsb);
850 			return 0;
851 		}
852 
853 		if (dest_island == isld1) {
854 			*addr |= (UINT64_C(1) << idx_lsb);
855 			return 0;
856 		}
857 
858 		return -ENODEV;
859 	case 2:
860 		if (da == 1) {
861 			iid_lsb = (addr40 != 0) ? 32 : 24;
862 			value = nfp_mask64((iid_lsb + 5), iid_lsb);
863 			*addr &= ~value;
864 			*addr |= (((uint64_t)dest_island) << iid_lsb) & value;
865 			return 0;
866 		}
867 
868 		/*
869 		 * Make sure we compare against isldN values by clearing the
870 		 * LSB. This is what the silicon does.
871 		 */
872 		isld[0] &= ~1;
873 		isld[1] &= ~1;
874 
875 		idx_lsb = (addr40 != 0) ? 37 : 29;
876 		iid_lsb = idx_lsb - 1;
877 
878 		return nfp_encode_basic_search(addr, dest_island, isld,
879 				iid_lsb, idx_lsb, 2);
880 	case 3:
881 		/*
882 		 * Only the EMU will use 40 bit addressing. Silently set the
883 		 * direct locality bit for everyone else. The SDK toolchain
884 		 * uses dest_island <= 0 to test for atypical address encodings
885 		 * to support access to local-island CTM with a 32-but address
886 		 * (high-locality is effectively ignored and just used for
887 		 * routing to island #0).
888 		 */
889 		if (dest_island > 0 && (dest_island < 24 || dest_island > 26)) {
890 			*addr |= ((uint64_t)NFP6000_MU_LOCALITY_DIRECT)
891 					<< locality_lsb;
892 			da = 1;
893 		}
894 
895 		if (da == 1) {
896 			iid_lsb = (addr40 != 0) ? 32 : 24;
897 			value = nfp_mask64((iid_lsb + 5), iid_lsb);
898 			*addr &= ~value;
899 			*addr |= (((uint64_t)dest_island) << iid_lsb) & value;
900 			return 0;
901 		}
902 
903 		isld[0] &= ~3;
904 		isld[1] &= ~3;
905 
906 		idx_lsb = (addr40 != 0) ? 37 : 29;
907 		iid_lsb = idx_lsb - 2;
908 
909 		return nfp_encode_basic_search(addr, dest_island, isld,
910 				iid_lsb, idx_lsb, 4);
911 	default:
912 		return -EINVAL;
913 	}
914 }
915 
916 static int
917 nfp_cppat_addr_encode(uint64_t *addr,
918 		int dest_island,
919 		int cpp_tgt,
920 		int mode,
921 		int addr40,
922 		int isld1,
923 		int isld0)
924 {
925 	uint64_t value;
926 
927 	switch (cpp_tgt) {
928 	case NFP_CPP_TARGET_NBI:
929 	case NFP_CPP_TARGET_QDR:
930 	case NFP_CPP_TARGET_ILA:
931 	case NFP_CPP_TARGET_PCIE:
932 	case NFP_CPP_TARGET_ARM:
933 	case NFP_CPP_TARGET_CRYPTO:
934 	case NFP_CPP_TARGET_CLS:
935 		return nfp_encode_basic(addr, dest_island, cpp_tgt, mode,
936 				addr40, isld1, isld0);
937 	case NFP_CPP_TARGET_MU:
938 		return nfp_encode_mu(addr, dest_island, mode, addr40,
939 				isld1, isld0);
940 	case NFP_CPP_TARGET_CT_XPB:
941 		if (mode != 1 || addr40 != 0)
942 			return -EINVAL;
943 
944 		value = nfp_mask64(29, 24);
945 		*addr &= ~value;
946 		*addr |= (((uint64_t)dest_island) << 24) & value;
947 		return 0;
948 	default:
949 		return -EINVAL;
950 	}
951 }
952 
953 int
954 nfp_target_cpp(uint32_t cpp_island_id,
955 		uint64_t cpp_island_address,
956 		uint32_t *cpp_target_id,
957 		uint64_t *cpp_target_address,
958 		const uint32_t *imb_table)
959 {
960 	int err;
961 	uint32_t imb;
962 	uint8_t island;
963 	uint8_t target;
964 
965 	target = NFP_CPP_ID_TARGET_of(cpp_island_id);
966 	if (target >= 16)
967 		return -EINVAL;
968 
969 	island = NFP_CPP_ID_ISLAND_of(cpp_island_id);
970 	if (island == 0) {
971 		/* Already translated */
972 		*cpp_target_id = cpp_island_id;
973 		*cpp_target_address = cpp_island_address;
974 		return 0;
975 	}
976 
977 	/* CPP + Island only allowed on systems with IMB tables */
978 	if (imb_table == NULL)
979 		return -EINVAL;
980 
981 	imb = imb_table[target];
982 
983 	*cpp_target_address = cpp_island_address;
984 	err = nfp_cppat_addr_encode(cpp_target_address, island, target,
985 			((imb >> 13) & 7), ((imb >> 12) & 1),
986 			((imb >> 6) & 0x3f), ((imb >> 0) & 0x3f));
987 	if (err != 0)
988 		return err;
989 
990 	*cpp_target_id = NFP_CPP_ID(target,
991 			NFP_CPP_ID_ACTION_of(cpp_island_id),
992 			NFP_CPP_ID_TOKEN_of(cpp_island_id));
993 
994 	return 0;
995 }
996