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