xref: /dpdk/drivers/net/nfp/nfpcore/nfp_cppcore.c (revision d80e42cce4c7017ed8c99dabb8ae444a492acc1c)
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, int driver_lock_needed)
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 	cpp->driver_lock_needed = driver_lock_needed;
562 
563 	if (cpp->op->init) {
564 		err = cpp->op->init(cpp, devname);
565 		if (err < 0) {
566 			free(cpp);
567 			return NULL;
568 		}
569 	}
570 
571 	if (NFP_CPP_MODEL_IS_6000(nfp_cpp_model(cpp))) {
572 		uint32_t xpbaddr;
573 		size_t tgt;
574 
575 		for (tgt = 0; tgt < ARRAY_SIZE(cpp->imb_cat_table); tgt++) {
576 			/* Hardcoded XPB IMB Base, island 0 */
577 			xpbaddr = 0x000a0000 + (tgt * 4);
578 			err = nfp_xpb_readl(cpp, xpbaddr,
579 				(uint32_t *)&cpp->imb_cat_table[tgt]);
580 			if (err < 0) {
581 				free(cpp);
582 				return NULL;
583 			}
584 		}
585 	}
586 
587 	return cpp;
588 }
589 
590 /*
591  * nfp_cpp_free - free the CPP handle
592  * @cpp:    CPP handle
593  */
594 void
595 nfp_cpp_free(struct nfp_cpp *cpp)
596 {
597 	if (cpp->op && cpp->op->free)
598 		cpp->op->free(cpp);
599 
600 	if (cpp->serial_len)
601 		free(cpp->serial);
602 
603 	free(cpp);
604 }
605 
606 struct nfp_cpp *
607 nfp_cpp_from_device_name(const char *devname, int driver_lock_needed)
608 {
609 	return nfp_cpp_alloc(devname, driver_lock_needed);
610 }
611 
612 /*
613  * Modify bits of a 32-bit value from the XPB bus
614  *
615  * @param cpp           NFP CPP device handle
616  * @param xpb_tgt       XPB target and address
617  * @param mask          mask of bits to alter
618  * @param value         value to modify
619  *
620  * @return 0 on success, or -1 on failure (and set errno accordingly).
621  */
622 int
623 nfp_xpb_writelm(struct nfp_cpp *cpp, uint32_t xpb_tgt, uint32_t mask,
624 		uint32_t value)
625 {
626 	int err;
627 	uint32_t tmp;
628 
629 	err = nfp_xpb_readl(cpp, xpb_tgt, &tmp);
630 	if (err < 0)
631 		return err;
632 
633 	tmp &= ~mask;
634 	tmp |= (mask & value);
635 	return nfp_xpb_writel(cpp, xpb_tgt, tmp);
636 }
637 
638 /*
639  * Modify bits of a 32-bit value from the XPB bus
640  *
641  * @param cpp           NFP CPP device handle
642  * @param xpb_tgt       XPB target and address
643  * @param mask          mask of bits to alter
644  * @param value         value to monitor for
645  * @param timeout_us    maximum number of us to wait (-1 for forever)
646  *
647  * @return >= 0 on success, or -1 on failure (and set errno accordingly).
648  */
649 int
650 nfp_xpb_waitlm(struct nfp_cpp *cpp, uint32_t xpb_tgt, uint32_t mask,
651 	       uint32_t value, int timeout_us)
652 {
653 	uint32_t tmp;
654 	int err;
655 
656 	do {
657 		err = nfp_xpb_readl(cpp, xpb_tgt, &tmp);
658 		if (err < 0)
659 			goto exit;
660 
661 		if ((tmp & mask) == (value & mask)) {
662 			if (timeout_us < 0)
663 				timeout_us = 0;
664 			break;
665 		}
666 
667 		if (timeout_us < 0)
668 			continue;
669 
670 		timeout_us -= 100;
671 		usleep(100);
672 	} while (timeout_us >= 0);
673 
674 	if (timeout_us < 0)
675 		err = NFP_ERRNO(ETIMEDOUT);
676 	else
677 		err = timeout_us;
678 
679 exit:
680 	return err;
681 }
682 
683 /*
684  * nfp_cpp_read - read from CPP target
685  * @cpp:        CPP handle
686  * @destination:    CPP id
687  * @address:        offset into CPP target
688  * @kernel_vaddr:   kernel buffer for result
689  * @length:     number of bytes to read
690  */
691 int
692 nfp_cpp_read(struct nfp_cpp *cpp, uint32_t destination,
693 	     unsigned long long address, void *kernel_vaddr, size_t length)
694 {
695 	struct nfp_cpp_area *area;
696 	int err;
697 
698 	area = nfp_cpp_area_alloc_acquire(cpp, destination, address, length);
699 	if (!area) {
700 		printf("Area allocation/acquire failed\n");
701 		return -1;
702 	}
703 
704 	err = nfp_cpp_area_read(area, 0, kernel_vaddr, length);
705 
706 	nfp_cpp_area_release_free(area);
707 	return err;
708 }
709 
710 /*
711  * nfp_cpp_write - write to CPP target
712  * @cpp:        CPP handle
713  * @destination:    CPP id
714  * @address:        offset into CPP target
715  * @kernel_vaddr:   kernel buffer to read from
716  * @length:     number of bytes to write
717  */
718 int
719 nfp_cpp_write(struct nfp_cpp *cpp, uint32_t destination,
720 	      unsigned long long address, const void *kernel_vaddr,
721 	      size_t length)
722 {
723 	struct nfp_cpp_area *area;
724 	int err;
725 
726 	area = nfp_cpp_area_alloc_acquire(cpp, destination, address, length);
727 	if (!area)
728 		return -1;
729 
730 	err = nfp_cpp_area_write(area, 0, kernel_vaddr, length);
731 
732 	nfp_cpp_area_release_free(area);
733 	return err;
734 }
735 
736 /*
737  * nfp_cpp_area_fill - fill a CPP area with a value
738  * @area:       CPP area
739  * @offset:     offset into CPP area
740  * @value:      value to fill with
741  * @length:     length of area to fill
742  */
743 int
744 nfp_cpp_area_fill(struct nfp_cpp_area *area, unsigned long offset,
745 		  uint32_t value, size_t length)
746 {
747 	int err;
748 	size_t i;
749 	uint64_t value64;
750 
751 	value = rte_cpu_to_le_32(value);
752 	value64 = ((uint64_t)value << 32) | value;
753 
754 	if ((offset + length) > area->size)
755 		return NFP_ERRNO(EINVAL);
756 
757 	if ((area->offset + offset) & 3)
758 		return NFP_ERRNO(EINVAL);
759 
760 	if (((area->offset + offset) & 7) == 4 && length >= 4) {
761 		err = nfp_cpp_area_write(area, offset, &value, sizeof(value));
762 		if (err < 0)
763 			return err;
764 		if (err != sizeof(value))
765 			return NFP_ERRNO(ENOSPC);
766 		offset += sizeof(value);
767 		length -= sizeof(value);
768 	}
769 
770 	for (i = 0; (i + sizeof(value)) < length; i += sizeof(value64)) {
771 		err =
772 		    nfp_cpp_area_write(area, offset + i, &value64,
773 				       sizeof(value64));
774 		if (err < 0)
775 			return err;
776 		if (err != sizeof(value64))
777 			return NFP_ERRNO(ENOSPC);
778 	}
779 
780 	if ((i + sizeof(value)) <= length) {
781 		err =
782 		    nfp_cpp_area_write(area, offset + i, &value, sizeof(value));
783 		if (err < 0)
784 			return err;
785 		if (err != sizeof(value))
786 			return NFP_ERRNO(ENOSPC);
787 		i += sizeof(value);
788 	}
789 
790 	return (int)i;
791 }
792 
793 /*
794  * NOTE: This code should not use nfp_xpb_* functions,
795  * as those are model-specific
796  */
797 uint32_t
798 __nfp_cpp_model_autodetect(struct nfp_cpp *cpp)
799 {
800 	uint32_t arm_id = NFP_CPP_ID(NFP_CPP_TARGET_ARM, 0, 0);
801 	uint32_t model = 0;
802 
803 	nfp_cpp_readl(cpp, arm_id, NFP6000_ARM_GCSR_SOFTMODEL0, &model);
804 
805 	if (NFP_CPP_MODEL_IS_6000(model)) {
806 		uint32_t tmp;
807 
808 		nfp_cpp_model_set(cpp, model);
809 
810 		/* The PL's PluDeviceID revision code is authoratative */
811 		model &= ~0xff;
812 		nfp_xpb_readl(cpp, NFP_XPB_DEVICE(1, 1, 16) +
813 				   NFP_PL_DEVICE_ID, &tmp);
814 		model |= (NFP_PL_DEVICE_ID_MASK & tmp) - 0x10;
815 	}
816 
817 	return model;
818 }
819 
820 /*
821  * nfp_cpp_map_area() - Helper function to map an area
822  * @cpp:    NFP CPP handler
823  * @domain: CPP domain
824  * @target: CPP target
825  * @addr:   CPP address
826  * @size:   Size of the area
827  * @area:   Area handle (output)
828  *
829  * Map an area of IOMEM access.  To undo the effect of this function call
830  * @nfp_cpp_area_release_free(*area).
831  *
832  * Return: Pointer to memory mapped area or ERR_PTR
833  */
834 uint8_t *
835 nfp_cpp_map_area(struct nfp_cpp *cpp, int domain, int target, uint64_t addr,
836 		 unsigned long size, struct nfp_cpp_area **area)
837 {
838 	uint8_t *res;
839 	uint32_t dest;
840 
841 	dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, domain);
842 
843 	*area = nfp_cpp_area_alloc_acquire(cpp, dest, addr, size);
844 	if (!*area)
845 		goto err_eio;
846 
847 	res = nfp_cpp_area_iomem(*area);
848 	if (!res)
849 		goto err_release_free;
850 
851 	return res;
852 
853 err_release_free:
854 	nfp_cpp_area_release_free(*area);
855 err_eio:
856 	return NULL;
857 }
858