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
_nic_mask64(int msb,int lsb,int at0)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
_nfp6000_encode_basic(uint64_t * addr,int dest_island,int cpp_tgt,int mode,int addr40,int isld1,int isld0)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
_nfp6000_decode_basic(uint64_t addr,int * dest_island,int cpp_tgt,int mode,int addr40,int isld1,int isld0)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
_nfp6000_cppat_mu_locality_lsb(int mode,int addr40)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
_nfp6000_encode_mu(uint64_t * addr,int dest_island,int mode,int addr40,int isld1,int isld0)358 _nfp6000_encode_mu(uint64_t *addr, int dest_island, int mode, int addr40,
359 		   int isld1, int isld0)
360 {
361 	uint64_t _u64;
362 	int iid_lsb, idx_lsb, locality_lsb;
363 	int i, v;
364 	int isld[2];
365 	int da;
366 
367 	isld[0] = isld0;
368 	isld[1] = isld1;
369 	locality_lsb = _nfp6000_cppat_mu_locality_lsb(mode, addr40);
370 
371 	if (locality_lsb < 0)
372 		return NFP_ERRNO(EINVAL);
373 
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
_nfp6000_decode_mu(uint64_t addr,int * dest_island,int mode,int addr40,int isld1,int isld0)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
_nfp6000_cppat_addr_encode(uint64_t * addr,int dest_island,int cpp_tgt,int mode,int addr40,int isld1,int isld0)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
_nfp6000_cppat_addr_decode(uint64_t addr,int * dest_island,int cpp_tgt,int mode,int addr40,int isld1,int isld0)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
_nfp6000_cppat_addr_iid_clear(uint64_t * addr,int cpp_tgt,int mode,int addr40)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__ */
726