xref: /dpdk/drivers/net/nfp/nfpcore/nfp_cppcore.c (revision fd5baf09cdf9170e0f92a112fd0ef19c29649330)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Netronome Systems, Inc.
3  * All rights reserved.
4  */
5 
6 #include <assert.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 #include <sys/types.h>
13 
14 #include <rte_byteorder.h>
15 
16 #include "nfp_cpp.h"
17 #include "nfp_target.h"
18 #include "nfp6000/nfp6000.h"
19 #include "nfp6000/nfp_xpb.h"
20 #include "nfp_nffw.h"
21 
22 #define NFP_PL_DEVICE_ID                        0x00000004
23 #define NFP_PL_DEVICE_ID_MASK                   0xff
24 
25 #define NFP6000_ARM_GCSR_SOFTMODEL0             0x00400144
26 
27 void
28 nfp_cpp_priv_set(struct nfp_cpp *cpp, void *priv)
29 {
30 	cpp->priv = priv;
31 }
32 
33 void *
34 nfp_cpp_priv(struct nfp_cpp *cpp)
35 {
36 	return cpp->priv;
37 }
38 
39 void
40 nfp_cpp_model_set(struct nfp_cpp *cpp, uint32_t model)
41 {
42 	cpp->model = model;
43 }
44 
45 uint32_t
46 nfp_cpp_model(struct nfp_cpp *cpp)
47 {
48 	if (!cpp)
49 		return NFP_CPP_MODEL_INVALID;
50 
51 	if (cpp->model == 0)
52 		cpp->model = __nfp_cpp_model_autodetect(cpp);
53 
54 	return cpp->model;
55 }
56 
57 void
58 nfp_cpp_interface_set(struct nfp_cpp *cpp, uint32_t interface)
59 {
60 	cpp->interface = interface;
61 }
62 
63 int
64 nfp_cpp_serial(struct nfp_cpp *cpp, const uint8_t **serial)
65 {
66 	*serial = cpp->serial;
67 	return cpp->serial_len;
68 }
69 
70 int
71 nfp_cpp_serial_set(struct nfp_cpp *cpp, const uint8_t *serial,
72 		   size_t serial_len)
73 {
74 	if (cpp->serial_len)
75 		free(cpp->serial);
76 
77 	cpp->serial = malloc(serial_len);
78 	if (!cpp->serial)
79 		return -1;
80 
81 	memcpy(cpp->serial, serial, serial_len);
82 	cpp->serial_len = serial_len;
83 
84 	return 0;
85 }
86 
87 uint16_t
88 nfp_cpp_interface(struct nfp_cpp *cpp)
89 {
90 	if (!cpp)
91 		return NFP_CPP_INTERFACE(NFP_CPP_INTERFACE_TYPE_INVALID, 0, 0);
92 
93 	return cpp->interface;
94 }
95 
96 void *
97 nfp_cpp_area_priv(struct nfp_cpp_area *cpp_area)
98 {
99 	return &cpp_area[1];
100 }
101 
102 struct nfp_cpp *
103 nfp_cpp_area_cpp(struct nfp_cpp_area *cpp_area)
104 {
105 	return cpp_area->cpp;
106 }
107 
108 const char *
109 nfp_cpp_area_name(struct nfp_cpp_area *cpp_area)
110 {
111 	return cpp_area->name;
112 }
113 
114 /*
115  * nfp_cpp_area_alloc - allocate a new CPP area
116  * @cpp:    CPP handle
117  * @dest:   CPP id
118  * @address:    start address on CPP target
119  * @size:   size of area in bytes
120  *
121  * Allocate and initialize a CPP area structure.  The area must later
122  * be locked down with an 'acquire' before it can be safely accessed.
123  *
124  * NOTE: @address and @size must be 32-bit aligned values.
125  */
126 struct nfp_cpp_area *
127 nfp_cpp_area_alloc_with_name(struct nfp_cpp *cpp, uint32_t dest,
128 			      const char *name, unsigned long long address,
129 			      unsigned long size)
130 {
131 	struct nfp_cpp_area *area;
132 	uint64_t tmp64 = (uint64_t)address;
133 	int tmp, err;
134 
135 	if (!cpp)
136 		return NULL;
137 
138 	/* CPP bus uses only a 40-bit address */
139 	if ((address + size) > (1ULL << 40))
140 		return NFP_ERRPTR(EFAULT);
141 
142 	/* Remap from cpp_island to cpp_target */
143 	err = nfp_target_cpp(dest, tmp64, &dest, &tmp64, cpp->imb_cat_table);
144 	if (err < 0)
145 		return NULL;
146 
147 	address = (unsigned long long)tmp64;
148 
149 	if (!name)
150 		name = "";
151 
152 	area = calloc(1, sizeof(*area) + cpp->op->area_priv_size +
153 		      strlen(name) + 1);
154 	if (!area)
155 		return NULL;
156 
157 	area->cpp = cpp;
158 	area->name = ((char *)area) + sizeof(*area) + cpp->op->area_priv_size;
159 	memcpy(area->name, name, strlen(name) + 1);
160 
161 	/*
162 	 * Preserve errno around the call to area_init, since most
163 	 * implementations will blindly call nfp_target_action_width()for both
164 	 * read or write modes, and that will set errno to EINVAL.
165 	 */
166 	tmp = errno;
167 
168 	err = cpp->op->area_init(area, dest, address, size);
169 	if (err < 0) {
170 		free(area);
171 		return NULL;
172 	}
173 
174 	/* Restore errno */
175 	errno = tmp;
176 
177 	area->offset = address;
178 	area->size = size;
179 
180 	return area;
181 }
182 
183 struct nfp_cpp_area *
184 nfp_cpp_area_alloc(struct nfp_cpp *cpp, uint32_t dest,
185 		    unsigned long long address, unsigned long size)
186 {
187 	return nfp_cpp_area_alloc_with_name(cpp, dest, NULL, address, size);
188 }
189 
190 /*
191  * nfp_cpp_area_alloc_acquire - allocate a new CPP area and lock it down
192  *
193  * @cpp:    CPP handle
194  * @dest:   CPP id
195  * @address:    start address on CPP target
196  * @size:   size of area
197  *
198  * Allocate and initilizae a CPP area structure, and lock it down so
199  * that it can be accessed directly.
200  *
201  * NOTE: @address and @size must be 32-bit aligned values.
202  *
203  * NOTE: The area must also be 'released' when the structure is freed.
204  */
205 struct nfp_cpp_area *
206 nfp_cpp_area_alloc_acquire(struct nfp_cpp *cpp, uint32_t destination,
207 			    unsigned long long address, unsigned long size)
208 {
209 	struct nfp_cpp_area *area;
210 
211 	area = nfp_cpp_area_alloc(cpp, destination, address, size);
212 	if (!area)
213 		return NULL;
214 
215 	if (nfp_cpp_area_acquire(area)) {
216 		nfp_cpp_area_free(area);
217 		return NULL;
218 	}
219 
220 	return area;
221 }
222 
223 /*
224  * nfp_cpp_area_free - free up the CPP area
225  * area:    CPP area handle
226  *
227  * Frees up memory resources held by the CPP area.
228  */
229 void
230 nfp_cpp_area_free(struct nfp_cpp_area *area)
231 {
232 	if (area->cpp->op->area_cleanup)
233 		area->cpp->op->area_cleanup(area);
234 	free(area);
235 }
236 
237 /*
238  * nfp_cpp_area_release_free - release CPP area and free it
239  * area:    CPP area handle
240  *
241  * Releases CPP area and frees up memory resources held by the it.
242  */
243 void
244 nfp_cpp_area_release_free(struct nfp_cpp_area *area)
245 {
246 	nfp_cpp_area_release(area);
247 	nfp_cpp_area_free(area);
248 }
249 
250 /*
251  * nfp_cpp_area_acquire - lock down a CPP area for access
252  * @area:   CPP area handle
253  *
254  * Locks down the CPP area for a potential long term activity.  Area
255  * must always be locked down before being accessed.
256  */
257 int
258 nfp_cpp_area_acquire(struct nfp_cpp_area *area)
259 {
260 	if (area->cpp->op->area_acquire) {
261 		int err = area->cpp->op->area_acquire(area);
262 
263 		if (err < 0)
264 			return -1;
265 	}
266 
267 	return 0;
268 }
269 
270 /*
271  * nfp_cpp_area_release - release a locked down CPP area
272  * @area:   CPP area handle
273  *
274  * Releases a previously locked down CPP area.
275  */
276 void
277 nfp_cpp_area_release(struct nfp_cpp_area *area)
278 {
279 	if (area->cpp->op->area_release)
280 		area->cpp->op->area_release(area);
281 }
282 
283 /*
284  * nfp_cpp_area_iomem() - get IOMEM region for CPP area
285  *
286  * @area:       CPP area handle
287  *
288  * Returns an iomem pointer for use with readl()/writel() style operations.
289  *
290  * NOTE: Area must have been locked down with an 'acquire'.
291  *
292  * Return: pointer to the area, or NULL
293  */
294 void *
295 nfp_cpp_area_iomem(struct nfp_cpp_area *area)
296 {
297 	void *iomem = NULL;
298 
299 	if (area->cpp->op->area_iomem)
300 		iomem = area->cpp->op->area_iomem(area);
301 
302 	return iomem;
303 }
304 
305 /*
306  * nfp_cpp_area_read - read data from CPP area
307  *
308  * @area:       CPP area handle
309  * @offset:     offset into CPP area
310  * @kernel_vaddr:   kernel address to put data into
311  * @length:     number of bytes to read
312  *
313  * Read data from indicated CPP region.
314  *
315  * NOTE: @offset and @length must be 32-bit aligned values.
316  *
317  * NOTE: Area must have been locked down with an 'acquire'.
318  */
319 int
320 nfp_cpp_area_read(struct nfp_cpp_area *area, unsigned long offset,
321 		  void *kernel_vaddr, size_t length)
322 {
323 	if ((offset + length) > area->size)
324 		return NFP_ERRNO(EFAULT);
325 
326 	return area->cpp->op->area_read(area, kernel_vaddr, offset, length);
327 }
328 
329 /*
330  * nfp_cpp_area_write - write data to CPP area
331  *
332  * @area:       CPP area handle
333  * @offset:     offset into CPP area
334  * @kernel_vaddr:   kernel address to read data from
335  * @length:     number of bytes to write
336  *
337  * Write data to indicated CPP region.
338  *
339  * NOTE: @offset and @length must be 32-bit aligned values.
340  *
341  * NOTE: Area must have been locked down with an 'acquire'.
342  */
343 int
344 nfp_cpp_area_write(struct nfp_cpp_area *area, unsigned long offset,
345 		   const void *kernel_vaddr, size_t length)
346 {
347 	if ((offset + length) > area->size)
348 		return NFP_ERRNO(EFAULT);
349 
350 	return area->cpp->op->area_write(area, kernel_vaddr, offset, length);
351 }
352 
353 void *
354 nfp_cpp_area_mapped(struct nfp_cpp_area *area)
355 {
356 	if (area->cpp->op->area_mapped)
357 		return area->cpp->op->area_mapped(area);
358 	return NULL;
359 }
360 
361 /*
362  * nfp_cpp_area_check_range - check if address range fits in CPP area
363  *
364  * @area:   CPP area handle
365  * @offset: offset into CPP area
366  * @length: size of address range in bytes
367  *
368  * Check if address range fits within CPP area.  Return 0 if area fits
369  * or -1 on error.
370  */
371 int
372 nfp_cpp_area_check_range(struct nfp_cpp_area *area, unsigned long long offset,
373 			 unsigned long length)
374 {
375 	if (((offset + length) > area->size))
376 		return NFP_ERRNO(EFAULT);
377 
378 	return 0;
379 }
380 
381 /*
382  * Return the correct CPP address, and fixup xpb_addr as needed,
383  * based upon NFP model.
384  */
385 static uint32_t
386 nfp_xpb_to_cpp(struct nfp_cpp *cpp, uint32_t *xpb_addr)
387 {
388 	uint32_t xpb;
389 	int island;
390 
391 	if (!NFP_CPP_MODEL_IS_6000(cpp->model))
392 		return 0;
393 
394 	xpb = NFP_CPP_ID(14, NFP_CPP_ACTION_RW, 0);
395 
396 	/*
397 	 * Ensure that non-local XPB accesses go out through the
398 	 * global XPBM bus.
399 	 */
400 	island = ((*xpb_addr) >> 24) & 0x3f;
401 
402 	if (!island)
403 		return xpb;
404 
405 	if (island == 1) {
406 		/*
407 		 * Accesses to the ARM Island overlay uses Island 0
408 		 * Global Bit
409 		 */
410 		(*xpb_addr) &= ~0x7f000000;
411 		if (*xpb_addr < 0x60000)
412 			*xpb_addr |= (1 << 30);
413 		else
414 			/* And only non-ARM interfaces use island id = 1 */
415 			if (NFP_CPP_INTERFACE_TYPE_of(nfp_cpp_interface(cpp)) !=
416 			    NFP_CPP_INTERFACE_TYPE_ARM)
417 				*xpb_addr |= (1 << 24);
418 	} else {
419 		(*xpb_addr) |= (1 << 30);
420 	}
421 
422 	return xpb;
423 }
424 
425 int
426 nfp_cpp_area_readl(struct nfp_cpp_area *area, unsigned long offset,
427 		   uint32_t *value)
428 {
429 	int sz;
430 	uint32_t tmp = 0;
431 
432 	sz = nfp_cpp_area_read(area, offset, &tmp, sizeof(tmp));
433 	*value = rte_le_to_cpu_32(tmp);
434 
435 	return (sz == sizeof(*value)) ? 0 : -1;
436 }
437 
438 int
439 nfp_cpp_area_writel(struct nfp_cpp_area *area, unsigned long offset,
440 		    uint32_t value)
441 {
442 	int sz;
443 
444 	value = rte_cpu_to_le_32(value);
445 	sz = nfp_cpp_area_write(area, offset, &value, sizeof(value));
446 	return (sz == sizeof(value)) ? 0 : -1;
447 }
448 
449 int
450 nfp_cpp_area_readq(struct nfp_cpp_area *area, unsigned long offset,
451 		   uint64_t *value)
452 {
453 	int sz;
454 	uint64_t tmp = 0;
455 
456 	sz = nfp_cpp_area_read(area, offset, &tmp, sizeof(tmp));
457 	*value = rte_le_to_cpu_64(tmp);
458 
459 	return (sz == sizeof(*value)) ? 0 : -1;
460 }
461 
462 int
463 nfp_cpp_area_writeq(struct nfp_cpp_area *area, unsigned long offset,
464 		    uint64_t value)
465 {
466 	int sz;
467 
468 	value = rte_cpu_to_le_64(value);
469 	sz = nfp_cpp_area_write(area, offset, &value, sizeof(value));
470 
471 	return (sz == sizeof(value)) ? 0 : -1;
472 }
473 
474 int
475 nfp_cpp_readl(struct nfp_cpp *cpp, uint32_t cpp_id, unsigned long long address,
476 	      uint32_t *value)
477 {
478 	int sz;
479 	uint32_t tmp;
480 
481 	sz = nfp_cpp_read(cpp, cpp_id, address, &tmp, sizeof(tmp));
482 	*value = rte_le_to_cpu_32(tmp);
483 
484 	return (sz == sizeof(*value)) ? 0 : -1;
485 }
486 
487 int
488 nfp_cpp_writel(struct nfp_cpp *cpp, uint32_t cpp_id, unsigned long long address,
489 	       uint32_t value)
490 {
491 	int sz;
492 
493 	value = rte_cpu_to_le_32(value);
494 	sz = nfp_cpp_write(cpp, cpp_id, address, &value, sizeof(value));
495 
496 	return (sz == sizeof(value)) ? 0 : -1;
497 }
498 
499 int
500 nfp_cpp_readq(struct nfp_cpp *cpp, uint32_t cpp_id, unsigned long long address,
501 	      uint64_t *value)
502 {
503 	int sz;
504 	uint64_t tmp;
505 
506 	sz = nfp_cpp_read(cpp, cpp_id, address, &tmp, sizeof(tmp));
507 	*value = rte_le_to_cpu_64(tmp);
508 
509 	return (sz == sizeof(*value)) ? 0 : -1;
510 }
511 
512 int
513 nfp_cpp_writeq(struct nfp_cpp *cpp, uint32_t cpp_id, unsigned long long address,
514 	       uint64_t value)
515 {
516 	int sz;
517 
518 	value = rte_cpu_to_le_64(value);
519 	sz = nfp_cpp_write(cpp, cpp_id, address, &value, sizeof(value));
520 
521 	return (sz == sizeof(value)) ? 0 : -1;
522 }
523 
524 int
525 nfp_xpb_writel(struct nfp_cpp *cpp, uint32_t xpb_addr, uint32_t value)
526 {
527 	uint32_t cpp_dest;
528 
529 	cpp_dest = nfp_xpb_to_cpp(cpp, &xpb_addr);
530 
531 	return nfp_cpp_writel(cpp, cpp_dest, xpb_addr, value);
532 }
533 
534 int
535 nfp_xpb_readl(struct nfp_cpp *cpp, uint32_t xpb_addr, uint32_t *value)
536 {
537 	uint32_t cpp_dest;
538 
539 	cpp_dest = nfp_xpb_to_cpp(cpp, &xpb_addr);
540 
541 	return nfp_cpp_readl(cpp, cpp_dest, xpb_addr, value);
542 }
543 
544 static struct nfp_cpp *
545 nfp_cpp_alloc(const char *devname)
546 {
547 	const struct nfp_cpp_operations *ops;
548 	struct nfp_cpp *cpp;
549 	int err;
550 
551 	ops = nfp_cpp_transport_operations();
552 
553 	if (!ops || !ops->init)
554 		return NFP_ERRPTR(EINVAL);
555 
556 	cpp = calloc(1, sizeof(*cpp));
557 	if (!cpp)
558 		return NULL;
559 
560 	cpp->op = ops;
561 
562 	if (cpp->op->init) {
563 		err = cpp->op->init(cpp, devname);
564 		if (err < 0) {
565 			free(cpp);
566 			return NULL;
567 		}
568 	}
569 
570 	if (NFP_CPP_MODEL_IS_6000(nfp_cpp_model(cpp))) {
571 		uint32_t xpbaddr;
572 		size_t tgt;
573 
574 		for (tgt = 0; tgt < ARRAY_SIZE(cpp->imb_cat_table); tgt++) {
575 			/* Hardcoded XPB IMB Base, island 0 */
576 			xpbaddr = 0x000a0000 + (tgt * 4);
577 			err = nfp_xpb_readl(cpp, xpbaddr,
578 				(uint32_t *)&cpp->imb_cat_table[tgt]);
579 			if (err < 0) {
580 				free(cpp);
581 				return NULL;
582 			}
583 		}
584 	}
585 
586 	return cpp;
587 }
588 
589 /*
590  * nfp_cpp_free - free the CPP handle
591  * @cpp:    CPP handle
592  */
593 void
594 nfp_cpp_free(struct nfp_cpp *cpp)
595 {
596 	if (cpp->op && cpp->op->free)
597 		cpp->op->free(cpp);
598 
599 	if (cpp->serial_len)
600 		free(cpp->serial);
601 
602 	free(cpp);
603 }
604 
605 struct nfp_cpp *
606 nfp_cpp_from_device_name(const char *devname)
607 {
608 	return nfp_cpp_alloc(devname);
609 }
610 
611 /*
612  * Modify bits of a 32-bit value from the XPB bus
613  *
614  * @param cpp           NFP CPP device handle
615  * @param xpb_tgt       XPB target and address
616  * @param mask          mask of bits to alter
617  * @param value         value to modify
618  *
619  * @return 0 on success, or -1 on failure (and set errno accordingly).
620  */
621 int
622 nfp_xpb_writelm(struct nfp_cpp *cpp, uint32_t xpb_tgt, uint32_t mask,
623 		uint32_t value)
624 {
625 	int err;
626 	uint32_t tmp;
627 
628 	err = nfp_xpb_readl(cpp, xpb_tgt, &tmp);
629 	if (err < 0)
630 		return err;
631 
632 	tmp &= ~mask;
633 	tmp |= (mask & value);
634 	return nfp_xpb_writel(cpp, xpb_tgt, tmp);
635 }
636 
637 /*
638  * Modify bits of a 32-bit value from the XPB bus
639  *
640  * @param cpp           NFP CPP device handle
641  * @param xpb_tgt       XPB target and address
642  * @param mask          mask of bits to alter
643  * @param value         value to monitor for
644  * @param timeout_us    maximum number of us to wait (-1 for forever)
645  *
646  * @return >= 0 on success, or -1 on failure (and set errno accordingly).
647  */
648 int
649 nfp_xpb_waitlm(struct nfp_cpp *cpp, uint32_t xpb_tgt, uint32_t mask,
650 	       uint32_t value, int timeout_us)
651 {
652 	uint32_t tmp;
653 	int err;
654 
655 	do {
656 		err = nfp_xpb_readl(cpp, xpb_tgt, &tmp);
657 		if (err < 0)
658 			goto exit;
659 
660 		if ((tmp & mask) == (value & mask)) {
661 			if (timeout_us < 0)
662 				timeout_us = 0;
663 			break;
664 		}
665 
666 		if (timeout_us < 0)
667 			continue;
668 
669 		timeout_us -= 100;
670 		usleep(100);
671 	} while (timeout_us >= 0);
672 
673 	if (timeout_us < 0)
674 		err = NFP_ERRNO(ETIMEDOUT);
675 	else
676 		err = timeout_us;
677 
678 exit:
679 	return err;
680 }
681 
682 /*
683  * nfp_cpp_read - read from CPP target
684  * @cpp:        CPP handle
685  * @destination:    CPP id
686  * @address:        offset into CPP target
687  * @kernel_vaddr:   kernel buffer for result
688  * @length:     number of bytes to read
689  */
690 int
691 nfp_cpp_read(struct nfp_cpp *cpp, uint32_t destination,
692 	     unsigned long long address, void *kernel_vaddr, size_t length)
693 {
694 	struct nfp_cpp_area *area;
695 	int err;
696 
697 	area = nfp_cpp_area_alloc_acquire(cpp, destination, address, length);
698 	if (!area) {
699 		printf("Area allocation/acquire failed\n");
700 		return -1;
701 	}
702 
703 	err = nfp_cpp_area_read(area, 0, kernel_vaddr, length);
704 
705 	nfp_cpp_area_release_free(area);
706 	return err;
707 }
708 
709 /*
710  * nfp_cpp_write - write to CPP target
711  * @cpp:        CPP handle
712  * @destination:    CPP id
713  * @address:        offset into CPP target
714  * @kernel_vaddr:   kernel buffer to read from
715  * @length:     number of bytes to write
716  */
717 int
718 nfp_cpp_write(struct nfp_cpp *cpp, uint32_t destination,
719 	      unsigned long long address, const void *kernel_vaddr,
720 	      size_t length)
721 {
722 	struct nfp_cpp_area *area;
723 	int err;
724 
725 	area = nfp_cpp_area_alloc_acquire(cpp, destination, address, length);
726 	if (!area)
727 		return -1;
728 
729 	err = nfp_cpp_area_write(area, 0, kernel_vaddr, length);
730 
731 	nfp_cpp_area_release_free(area);
732 	return err;
733 }
734 
735 /*
736  * nfp_cpp_area_fill - fill a CPP area with a value
737  * @area:       CPP area
738  * @offset:     offset into CPP area
739  * @value:      value to fill with
740  * @length:     length of area to fill
741  */
742 int
743 nfp_cpp_area_fill(struct nfp_cpp_area *area, unsigned long offset,
744 		  uint32_t value, size_t length)
745 {
746 	int err;
747 	size_t i;
748 	uint64_t value64;
749 
750 	value = rte_cpu_to_le_32(value);
751 	value64 = ((uint64_t)value << 32) | value;
752 
753 	if ((offset + length) > area->size)
754 		return NFP_ERRNO(EINVAL);
755 
756 	if ((area->offset + offset) & 3)
757 		return NFP_ERRNO(EINVAL);
758 
759 	if (((area->offset + offset) & 7) == 4 && length >= 4) {
760 		err = nfp_cpp_area_write(area, offset, &value, sizeof(value));
761 		if (err < 0)
762 			return err;
763 		if (err != sizeof(value))
764 			return NFP_ERRNO(ENOSPC);
765 		offset += sizeof(value);
766 		length -= sizeof(value);
767 	}
768 
769 	for (i = 0; (i + sizeof(value)) < length; i += sizeof(value64)) {
770 		err =
771 		    nfp_cpp_area_write(area, offset + i, &value64,
772 				       sizeof(value64));
773 		if (err < 0)
774 			return err;
775 		if (err != sizeof(value64))
776 			return NFP_ERRNO(ENOSPC);
777 	}
778 
779 	if ((i + sizeof(value)) <= length) {
780 		err =
781 		    nfp_cpp_area_write(area, offset + i, &value, sizeof(value));
782 		if (err < 0)
783 			return err;
784 		if (err != sizeof(value))
785 			return NFP_ERRNO(ENOSPC);
786 		i += sizeof(value);
787 	}
788 
789 	return (int)i;
790 }
791 
792 /*
793  * NOTE: This code should not use nfp_xpb_* functions,
794  * as those are model-specific
795  */
796 uint32_t
797 __nfp_cpp_model_autodetect(struct nfp_cpp *cpp)
798 {
799 	uint32_t arm_id = NFP_CPP_ID(NFP_CPP_TARGET_ARM, 0, 0);
800 	uint32_t model = 0;
801 
802 	nfp_cpp_readl(cpp, arm_id, NFP6000_ARM_GCSR_SOFTMODEL0, &model);
803 
804 	if (NFP_CPP_MODEL_IS_6000(model)) {
805 		uint32_t tmp;
806 
807 		nfp_cpp_model_set(cpp, model);
808 
809 		/* The PL's PluDeviceID revision code is authoratative */
810 		model &= ~0xff;
811 		nfp_xpb_readl(cpp, NFP_XPB_DEVICE(1, 1, 16) +
812 				   NFP_PL_DEVICE_ID, &tmp);
813 		model |= (NFP_PL_DEVICE_ID_MASK & tmp) - 0x10;
814 	}
815 
816 	return model;
817 }
818 
819 /*
820  * nfp_cpp_map_area() - Helper function to map an area
821  * @cpp:    NFP CPP handler
822  * @domain: CPP domain
823  * @target: CPP target
824  * @addr:   CPP address
825  * @size:   Size of the area
826  * @area:   Area handle (output)
827  *
828  * Map an area of IOMEM access.  To undo the effect of this function call
829  * @nfp_cpp_area_release_free(*area).
830  *
831  * Return: Pointer to memory mapped area or ERR_PTR
832  */
833 uint8_t *
834 nfp_cpp_map_area(struct nfp_cpp *cpp, int domain, int target, uint64_t addr,
835 		 unsigned long size, struct nfp_cpp_area **area)
836 {
837 	uint8_t *res;
838 	uint32_t dest;
839 
840 	dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, domain);
841 
842 	*area = nfp_cpp_area_alloc_acquire(cpp, dest, addr, size);
843 	if (!*area)
844 		goto err_eio;
845 
846 	res = nfp_cpp_area_iomem(*area);
847 	if (!res)
848 		goto err_release_free;
849 
850 	return res;
851 
852 err_release_free:
853 	nfp_cpp_area_release_free(*area);
854 err_eio:
855 	return NULL;
856 }
857