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
nfp_cpp_priv_set(struct nfp_cpp * cpp,void * priv)29 nfp_cpp_priv_set(struct nfp_cpp *cpp, void *priv)
30 {
31 cpp->priv = priv;
32 }
33
34 void *
nfp_cpp_priv(struct nfp_cpp * cpp)35 nfp_cpp_priv(struct nfp_cpp *cpp)
36 {
37 return cpp->priv;
38 }
39
40 void
nfp_cpp_model_set(struct nfp_cpp * cpp,uint32_t model)41 nfp_cpp_model_set(struct nfp_cpp *cpp, uint32_t model)
42 {
43 cpp->model = model;
44 }
45
46 uint32_t
nfp_cpp_model(struct nfp_cpp * cpp)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
nfp_cpp_interface_set(struct nfp_cpp * cpp,uint32_t interface)59 nfp_cpp_interface_set(struct nfp_cpp *cpp, uint32_t interface)
60 {
61 cpp->interface = interface;
62 }
63
64 int
nfp_cpp_serial(struct nfp_cpp * cpp,const uint8_t ** serial)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
nfp_cpp_serial_set(struct nfp_cpp * cpp,const uint8_t * serial,size_t serial_len)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
nfp_cpp_interface(struct nfp_cpp * cpp)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 *
nfp_cpp_area_priv(struct nfp_cpp_area * cpp_area)98 nfp_cpp_area_priv(struct nfp_cpp_area *cpp_area)
99 {
100 return &cpp_area[1];
101 }
102
103 struct nfp_cpp *
nfp_cpp_area_cpp(struct nfp_cpp_area * cpp_area)104 nfp_cpp_area_cpp(struct nfp_cpp_area *cpp_area)
105 {
106 return cpp_area->cpp;
107 }
108
109 const char *
nfp_cpp_area_name(struct nfp_cpp_area * cpp_area)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 *
nfp_cpp_area_alloc_with_name(struct nfp_cpp * cpp,uint32_t dest,const char * name,unsigned long long address,unsigned long size)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 *
nfp_cpp_area_alloc(struct nfp_cpp * cpp,uint32_t dest,unsigned long long address,unsigned long size)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 *
nfp_cpp_area_alloc_acquire(struct nfp_cpp * cpp,uint32_t destination,unsigned long long address,unsigned long size)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
nfp_cpp_area_free(struct nfp_cpp_area * area)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
nfp_cpp_area_release_free(struct nfp_cpp_area * area)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
nfp_cpp_area_acquire(struct nfp_cpp_area * area)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
nfp_cpp_area_release(struct nfp_cpp_area * area)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 *
nfp_cpp_area_iomem(struct nfp_cpp_area * area)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
nfp_cpp_area_read(struct nfp_cpp_area * area,unsigned long offset,void * kernel_vaddr,size_t length)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
nfp_cpp_area_write(struct nfp_cpp_area * area,unsigned long offset,const void * kernel_vaddr,size_t length)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 *
nfp_cpp_area_mapped(struct nfp_cpp_area * area)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
nfp_cpp_area_check_range(struct nfp_cpp_area * area,unsigned long long offset,unsigned long length)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
nfp_xpb_to_cpp(struct nfp_cpp * cpp,uint32_t * xpb_addr)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
nfp_cpp_area_readl(struct nfp_cpp_area * area,unsigned long offset,uint32_t * value)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
nfp_cpp_area_writel(struct nfp_cpp_area * area,unsigned long offset,uint32_t value)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
nfp_cpp_area_readq(struct nfp_cpp_area * area,unsigned long offset,uint64_t * value)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
nfp_cpp_area_writeq(struct nfp_cpp_area * area,unsigned long offset,uint64_t value)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
nfp_cpp_readl(struct nfp_cpp * cpp,uint32_t cpp_id,unsigned long long address,uint32_t * value)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
nfp_cpp_writel(struct nfp_cpp * cpp,uint32_t cpp_id,unsigned long long address,uint32_t value)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
nfp_cpp_readq(struct nfp_cpp * cpp,uint32_t cpp_id,unsigned long long address,uint64_t * value)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
nfp_cpp_writeq(struct nfp_cpp * cpp,uint32_t cpp_id,unsigned long long address,uint64_t value)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
nfp_xpb_writel(struct nfp_cpp * cpp,uint32_t xpb_addr,uint32_t value)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
nfp_xpb_readl(struct nfp_cpp * cpp,uint32_t xpb_addr,uint32_t * value)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 *
nfp_cpp_alloc(struct rte_pci_device * dev,int driver_lock_needed)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
nfp_cpp_free(struct nfp_cpp * cpp)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 *
nfp_cpp_from_device_name(struct rte_pci_device * dev,int driver_lock_needed)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
nfp_xpb_writelm(struct nfp_cpp * cpp,uint32_t xpb_tgt,uint32_t mask,uint32_t value)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
nfp_xpb_waitlm(struct nfp_cpp * cpp,uint32_t xpb_tgt,uint32_t mask,uint32_t value,int timeout_us)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
nfp_cpp_read(struct nfp_cpp * cpp,uint32_t destination,unsigned long long address,void * kernel_vaddr,size_t length)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
nfp_cpp_write(struct nfp_cpp * cpp,uint32_t destination,unsigned long long address,const void * kernel_vaddr,size_t length)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
nfp_cpp_area_fill(struct nfp_cpp_area * area,unsigned long offset,uint32_t value,size_t length)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
__nfp_cpp_model_autodetect(struct nfp_cpp * cpp)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 *
nfp_cpp_map_area(struct nfp_cpp * cpp,int domain,int target,uint64_t addr,unsigned long size,struct nfp_cpp_area ** area)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