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