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