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