New upstream version 18.11.2
[deb_dpdk.git] / drivers / net / nfp / nfpcore / nfp_cpp_pcie_ops.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Netronome Systems, Inc.
3  * All rights reserved.
4  */
5
6 /*
7  * nfp_cpp_pcie_ops.c
8  * Authors: Vinayak Tammineedi <vinayak.tammineedi@netronome.com>
9  *
10  * Multiplexes the NFP BARs between NFP internal resources and
11  * implements the PCIe specific interface for generic CPP bus access.
12  *
13  * The BARs are managed and allocated if they are available.
14  * The generic CPP bus abstraction builds upon this BAR interface.
15  */
16
17 #include <assert.h>
18 #include <stdio.h>
19 #if defined(RTE_BACKTRACE)
20 #include <execinfo.h>
21 #endif
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <stdint.h>
25 #include <stdbool.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <dirent.h>
30 #include <libgen.h>
31
32 #include <sys/mman.h>
33 #include <sys/file.h>
34 #include <sys/stat.h>
35
36 #include <rte_ethdev_pci.h>
37 #include <rte_string_fns.h>
38
39 #include "nfp_cpp.h"
40 #include "nfp_target.h"
41 #include "nfp6000/nfp6000.h"
42
43 #define NFP_PCIE_BAR(_pf)       (0x30000 + ((_pf) & 7) * 0xc0)
44
45 #define NFP_PCIE_BAR_PCIE2CPP_ACTION_BASEADDRESS(_x)  (((_x) & 0x1f) << 16)
46 #define NFP_PCIE_BAR_PCIE2CPP_BASEADDRESS(_x)         (((_x) & 0xffff) << 0)
47 #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT(_x)        (((_x) & 0x3) << 27)
48 #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_32BIT    0
49 #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_64BIT    1
50 #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_0BYTE    3
51 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE(_x)             (((_x) & 0x7) << 29)
52 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_OF(_x)          (((_x) >> 29) & 0x7)
53 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_FIXED         0
54 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_BULK          1
55 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_TARGET        2
56 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_GENERAL       3
57 #define NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS(_x)  (((_x) & 0xf) << 23)
58 #define NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS(_x)   (((_x) & 0x3) << 21)
59
60 /*
61  * Minimal size of the PCIe cfg memory we depend on being mapped,
62  * queue controller and DMA controller don't have to be covered.
63  */
64 #define NFP_PCI_MIN_MAP_SIZE                            0x080000
65
66 #define NFP_PCIE_P2C_FIXED_SIZE(bar)               (1 << (bar)->bitsize)
67 #define NFP_PCIE_P2C_BULK_SIZE(bar)                (1 << (bar)->bitsize)
68 #define NFP_PCIE_P2C_GENERAL_TARGET_OFFSET(bar, x) ((x) << ((bar)->bitsize - 2))
69 #define NFP_PCIE_P2C_GENERAL_TOKEN_OFFSET(bar, x) ((x) << ((bar)->bitsize - 4))
70 #define NFP_PCIE_P2C_GENERAL_SIZE(bar)             (1 << ((bar)->bitsize - 4))
71
72 #define NFP_PCIE_CFG_BAR_PCIETOCPPEXPBAR(bar, slot) \
73         (NFP_PCIE_BAR(0) + ((bar) * 8 + (slot)) * 4)
74
75 #define NFP_PCIE_CPP_BAR_PCIETOCPPEXPBAR(bar, slot) \
76         (((bar) * 8 + (slot)) * 4)
77
78 /*
79  * Define to enable a bit more verbose debug output.
80  * Set to 1 to enable a bit more verbose debug output.
81  */
82 struct nfp_pcie_user;
83 struct nfp6000_area_priv;
84
85 /*
86  * struct nfp_bar - describes BAR configuration and usage
87  * @nfp:        backlink to owner
88  * @barcfg:     cached contents of BAR config CSR
89  * @base:       the BAR's base CPP offset
90  * @mask:       mask for the BAR aperture (read only)
91  * @bitsize:    bitsize of BAR aperture (read only)
92  * @index:      index of the BAR
93  * @lock:       lock to specify if bar is in use
94  * @refcnt:     number of current users
95  * @iomem:      mapped IO memory
96  */
97 #define NFP_BAR_MAX 7
98 struct nfp_bar {
99         struct nfp_pcie_user *nfp;
100         uint32_t barcfg;
101         uint64_t base;          /* CPP address base */
102         uint64_t mask;          /* Bit mask of the bar */
103         uint32_t bitsize;       /* Bit size of the bar */
104         int index;
105         int lock;
106
107         char *csr;
108         char *iomem;
109 };
110
111 #define BUSDEV_SZ       13
112 struct nfp_pcie_user {
113         struct nfp_bar bar[NFP_BAR_MAX];
114
115         int device;
116         int lock;
117         char busdev[BUSDEV_SZ];
118         int barsz;
119         char *cfg;
120 };
121
122 static uint32_t
123 nfp_bar_maptype(struct nfp_bar *bar)
124 {
125         return NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_OF(bar->barcfg);
126 }
127
128 #define TARGET_WIDTH_32    4
129 #define TARGET_WIDTH_64    8
130
131 static int
132 nfp_compute_bar(const struct nfp_bar *bar, uint32_t *bar_config,
133                 uint64_t *bar_base, int tgt, int act, int tok,
134                 uint64_t offset, size_t size, int width)
135 {
136         uint32_t bitsize;
137         uint32_t newcfg;
138         uint64_t mask;
139
140         if (tgt >= 16)
141                 return -EINVAL;
142
143         switch (width) {
144         case 8:
145                 newcfg =
146                     NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
147                     (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_64BIT);
148                 break;
149         case 4:
150                 newcfg =
151                     NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
152                     (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_32BIT);
153                 break;
154         case 0:
155                 newcfg =
156                     NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
157                     (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_0BYTE);
158                 break;
159         default:
160                 return -EINVAL;
161         }
162
163         if (act != NFP_CPP_ACTION_RW && act != 0) {
164                 /* Fixed CPP mapping with specific action */
165                 mask = ~(NFP_PCIE_P2C_FIXED_SIZE(bar) - 1);
166
167                 newcfg |=
168                     NFP_PCIE_BAR_PCIE2CPP_MAPTYPE
169                     (NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_FIXED);
170                 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS(tgt);
171                 newcfg |= NFP_PCIE_BAR_PCIE2CPP_ACTION_BASEADDRESS(act);
172                 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS(tok);
173
174                 if ((offset & mask) != ((offset + size - 1) & mask)) {
175                         printf("BAR%d: Won't use for Fixed mapping\n",
176                                 bar->index);
177                         printf("\t<%#llx,%#llx>, action=%d\n",
178                                 (unsigned long long)offset,
179                                 (unsigned long long)(offset + size), act);
180                         printf("\tBAR too small (0x%llx).\n",
181                                 (unsigned long long)mask);
182                         return -EINVAL;
183                 }
184                 offset &= mask;
185
186 #ifdef DEBUG
187                 printf("BAR%d: Created Fixed mapping\n", bar->index);
188                 printf("\t%d:%d:%d:0x%#llx-0x%#llx>\n", tgt, act, tok,
189                         (unsigned long long)offset,
190                         (unsigned long long)(offset + mask));
191 #endif
192
193                 bitsize = 40 - 16;
194         } else {
195                 mask = ~(NFP_PCIE_P2C_BULK_SIZE(bar) - 1);
196
197                 /* Bulk mapping */
198                 newcfg |=
199                     NFP_PCIE_BAR_PCIE2CPP_MAPTYPE
200                     (NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_BULK);
201
202                 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS(tgt);
203                 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS(tok);
204
205                 if ((offset & mask) != ((offset + size - 1) & mask)) {
206                         printf("BAR%d: Won't use for bulk mapping\n",
207                                 bar->index);
208                         printf("\t<%#llx,%#llx>\n", (unsigned long long)offset,
209                                 (unsigned long long)(offset + size));
210                         printf("\ttarget=%d, token=%d\n", tgt, tok);
211                         printf("\tBAR too small (%#llx) - (%#llx != %#llx).\n",
212                                 (unsigned long long)mask,
213                                 (unsigned long long)(offset & mask),
214                                 (unsigned long long)(offset + size - 1) & mask);
215
216                         return -EINVAL;
217                 }
218
219                 offset &= mask;
220
221 #ifdef DEBUG
222                 printf("BAR%d: Created bulk mapping %d:x:%d:%#llx-%#llx\n",
223                         bar->index, tgt, tok, (unsigned long long)offset,
224                         (unsigned long long)(offset + ~mask));
225 #endif
226
227                 bitsize = 40 - 21;
228         }
229
230         if (bar->bitsize < bitsize) {
231                 printf("BAR%d: Too small for %d:%d:%d\n", bar->index, tgt, tok,
232                         act);
233                 return -EINVAL;
234         }
235
236         newcfg |= offset >> bitsize;
237
238         if (bar_base)
239                 *bar_base = offset;
240
241         if (bar_config)
242                 *bar_config = newcfg;
243
244         return 0;
245 }
246
247 static int
248 nfp_bar_write(struct nfp_pcie_user *nfp, struct nfp_bar *bar,
249                   uint32_t newcfg)
250 {
251         int base, slot;
252
253         base = bar->index >> 3;
254         slot = bar->index & 7;
255
256         if (!nfp->cfg)
257                 return (-ENOMEM);
258
259         bar->csr = nfp->cfg +
260                    NFP_PCIE_CFG_BAR_PCIETOCPPEXPBAR(base, slot);
261
262         *(uint32_t *)(bar->csr) = newcfg;
263
264         bar->barcfg = newcfg;
265 #ifdef DEBUG
266         printf("BAR%d: updated to 0x%08x\n", bar->index, newcfg);
267 #endif
268
269         return 0;
270 }
271
272 static int
273 nfp_reconfigure_bar(struct nfp_pcie_user *nfp, struct nfp_bar *bar, int tgt,
274                 int act, int tok, uint64_t offset, size_t size, int width)
275 {
276         uint64_t newbase;
277         uint32_t newcfg;
278         int err;
279
280         err = nfp_compute_bar(bar, &newcfg, &newbase, tgt, act, tok, offset,
281                               size, width);
282         if (err)
283                 return err;
284
285         bar->base = newbase;
286
287         return nfp_bar_write(nfp, bar, newcfg);
288 }
289
290 /*
291  * Map all PCI bars. We assume that the BAR with the PCIe config block is
292  * already mapped.
293  *
294  * BAR0.0: Reserved for General Mapping (for MSI-X access to PCIe SRAM)
295  */
296 static int
297 nfp_enable_bars(struct nfp_pcie_user *nfp)
298 {
299         struct nfp_bar *bar;
300         int x;
301
302         for (x = ARRAY_SIZE(nfp->bar); x > 0; x--) {
303                 bar = &nfp->bar[x - 1];
304                 bar->barcfg = 0;
305                 bar->nfp = nfp;
306                 bar->index = x;
307                 bar->mask = (1 << (nfp->barsz - 3)) - 1;
308                 bar->bitsize = nfp->barsz - 3;
309                 bar->base = 0;
310                 bar->iomem = NULL;
311                 bar->lock = 0;
312                 bar->csr = nfp->cfg +
313                            NFP_PCIE_CFG_BAR_PCIETOCPPEXPBAR(bar->index >> 3,
314                                                            bar->index & 7);
315
316                 bar->iomem = nfp->cfg + (bar->index << bar->bitsize);
317         }
318         return 0;
319 }
320
321 static struct nfp_bar *
322 nfp_alloc_bar(struct nfp_pcie_user *nfp)
323 {
324         struct nfp_bar *bar;
325         int x;
326
327         for (x = ARRAY_SIZE(nfp->bar); x > 0; x--) {
328                 bar = &nfp->bar[x - 1];
329                 if (!bar->lock) {
330                         bar->lock = 1;
331                         return bar;
332                 }
333         }
334         return NULL;
335 }
336
337 static void
338 nfp_disable_bars(struct nfp_pcie_user *nfp)
339 {
340         struct nfp_bar *bar;
341         int x;
342
343         for (x = ARRAY_SIZE(nfp->bar); x > 0; x--) {
344                 bar = &nfp->bar[x - 1];
345                 if (bar->iomem) {
346                         bar->iomem = NULL;
347                         bar->lock = 0;
348                 }
349         }
350 }
351
352 /*
353  * Generic CPP bus access interface.
354  */
355
356 struct nfp6000_area_priv {
357         struct nfp_bar *bar;
358         uint32_t bar_offset;
359
360         uint32_t target;
361         uint32_t action;
362         uint32_t token;
363         uint64_t offset;
364         struct {
365                 int read;
366                 int write;
367                 int bar;
368         } width;
369         size_t size;
370         char *iomem;
371 };
372
373 static int
374 nfp6000_area_init(struct nfp_cpp_area *area, uint32_t dest,
375                   unsigned long long address, unsigned long size)
376 {
377         struct nfp_pcie_user *nfp = nfp_cpp_priv(nfp_cpp_area_cpp(area));
378         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
379         uint32_t target = NFP_CPP_ID_TARGET_of(dest);
380         uint32_t action = NFP_CPP_ID_ACTION_of(dest);
381         uint32_t token = NFP_CPP_ID_TOKEN_of(dest);
382         int pp, ret = 0;
383
384         pp = nfp6000_target_pushpull(NFP_CPP_ID(target, action, token),
385                                      address);
386         if (pp < 0)
387                 return pp;
388
389         priv->width.read = PUSH_WIDTH(pp);
390         priv->width.write = PULL_WIDTH(pp);
391
392         if (priv->width.read > 0 &&
393             priv->width.write > 0 && priv->width.read != priv->width.write)
394                 return -EINVAL;
395
396         if (priv->width.read > 0)
397                 priv->width.bar = priv->width.read;
398         else
399                 priv->width.bar = priv->width.write;
400
401         priv->bar = nfp_alloc_bar(nfp);
402         if (priv->bar == NULL)
403                 return -ENOMEM;
404
405         priv->target = target;
406         priv->action = action;
407         priv->token = token;
408         priv->offset = address;
409         priv->size = size;
410
411         ret = nfp_reconfigure_bar(nfp, priv->bar, priv->target, priv->action,
412                                   priv->token, priv->offset, priv->size,
413                                   priv->width.bar);
414
415         return ret;
416 }
417
418 static int
419 nfp6000_area_acquire(struct nfp_cpp_area *area)
420 {
421         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
422
423         /* Calculate offset into BAR. */
424         if (nfp_bar_maptype(priv->bar) ==
425             NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_GENERAL) {
426                 priv->bar_offset = priv->offset &
427                         (NFP_PCIE_P2C_GENERAL_SIZE(priv->bar) - 1);
428                 priv->bar_offset +=
429                         NFP_PCIE_P2C_GENERAL_TARGET_OFFSET(priv->bar,
430                                                            priv->target);
431                 priv->bar_offset +=
432                     NFP_PCIE_P2C_GENERAL_TOKEN_OFFSET(priv->bar, priv->token);
433         } else {
434                 priv->bar_offset = priv->offset & priv->bar->mask;
435         }
436
437         /* Must have been too big. Sub-allocate. */
438         if (!priv->bar->iomem)
439                 return (-ENOMEM);
440
441         priv->iomem = priv->bar->iomem + priv->bar_offset;
442
443         return 0;
444 }
445
446 static void *
447 nfp6000_area_mapped(struct nfp_cpp_area *area)
448 {
449         struct nfp6000_area_priv *area_priv = nfp_cpp_area_priv(area);
450
451         if (!area_priv->iomem)
452                 return NULL;
453
454         return area_priv->iomem;
455 }
456
457 static void
458 nfp6000_area_release(struct nfp_cpp_area *area)
459 {
460         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
461         priv->bar->lock = 0;
462         priv->bar = NULL;
463         priv->iomem = NULL;
464 }
465
466 static void *
467 nfp6000_area_iomem(struct nfp_cpp_area *area)
468 {
469         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
470         return priv->iomem;
471 }
472
473 static int
474 nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr,
475                   unsigned long offset, unsigned int length)
476 {
477         uint64_t *wrptr64 = kernel_vaddr;
478         const volatile uint64_t *rdptr64;
479         struct nfp6000_area_priv *priv;
480         uint32_t *wrptr32 = kernel_vaddr;
481         const volatile uint32_t *rdptr32;
482         int width;
483         unsigned int n;
484         bool is_64;
485
486         priv = nfp_cpp_area_priv(area);
487         rdptr64 = (uint64_t *)(priv->iomem + offset);
488         rdptr32 = (uint32_t *)(priv->iomem + offset);
489
490         if (offset + length > priv->size)
491                 return -EFAULT;
492
493         width = priv->width.read;
494
495         if (width <= 0)
496                 return -EINVAL;
497
498         /* Unaligned? Translate to an explicit access */
499         if ((priv->offset + offset) & (width - 1)) {
500                 printf("aread_read unaligned!!!\n");
501                 return -EINVAL;
502         }
503
504         is_64 = width == TARGET_WIDTH_64;
505
506         /* MU reads via a PCIe2CPP BAR supports 32bit (and other) lengths */
507         if (priv->target == (NFP_CPP_TARGET_ID_MASK & NFP_CPP_TARGET_MU) &&
508             priv->action == NFP_CPP_ACTION_RW) {
509                 is_64 = false;
510         }
511
512         if (is_64) {
513                 if (offset % sizeof(uint64_t) != 0 ||
514                     length % sizeof(uint64_t) != 0)
515                         return -EINVAL;
516         } else {
517                 if (offset % sizeof(uint32_t) != 0 ||
518                     length % sizeof(uint32_t) != 0)
519                         return -EINVAL;
520         }
521
522         if (!priv->bar)
523                 return -EFAULT;
524
525         if (is_64)
526                 for (n = 0; n < length; n += sizeof(uint64_t)) {
527                         *wrptr64 = *rdptr64;
528                         wrptr64++;
529                         rdptr64++;
530                 }
531         else
532                 for (n = 0; n < length; n += sizeof(uint32_t)) {
533                         *wrptr32 = *rdptr32;
534                         wrptr32++;
535                         rdptr32++;
536                 }
537
538         return n;
539 }
540
541 static int
542 nfp6000_area_write(struct nfp_cpp_area *area, const void *kernel_vaddr,
543                    unsigned long offset, unsigned int length)
544 {
545         const uint64_t *rdptr64 = kernel_vaddr;
546         uint64_t *wrptr64;
547         const uint32_t *rdptr32 = kernel_vaddr;
548         struct nfp6000_area_priv *priv;
549         uint32_t *wrptr32;
550         int width;
551         unsigned int n;
552         bool is_64;
553
554         priv = nfp_cpp_area_priv(area);
555         wrptr64 = (uint64_t *)(priv->iomem + offset);
556         wrptr32 = (uint32_t *)(priv->iomem + offset);
557
558         if (offset + length > priv->size)
559                 return -EFAULT;
560
561         width = priv->width.write;
562
563         if (width <= 0)
564                 return -EINVAL;
565
566         /* Unaligned? Translate to an explicit access */
567         if ((priv->offset + offset) & (width - 1))
568                 return -EINVAL;
569
570         is_64 = width == TARGET_WIDTH_64;
571
572         /* MU writes via a PCIe2CPP BAR supports 32bit (and other) lengths */
573         if (priv->target == (NFP_CPP_TARGET_ID_MASK & NFP_CPP_TARGET_MU) &&
574             priv->action == NFP_CPP_ACTION_RW)
575                 is_64 = false;
576
577         if (is_64) {
578                 if (offset % sizeof(uint64_t) != 0 ||
579                     length % sizeof(uint64_t) != 0)
580                         return -EINVAL;
581         } else {
582                 if (offset % sizeof(uint32_t) != 0 ||
583                     length % sizeof(uint32_t) != 0)
584                         return -EINVAL;
585         }
586
587         if (!priv->bar)
588                 return -EFAULT;
589
590         if (is_64)
591                 for (n = 0; n < length; n += sizeof(uint64_t)) {
592                         *wrptr64 = *rdptr64;
593                         wrptr64++;
594                         rdptr64++;
595                 }
596         else
597                 for (n = 0; n < length; n += sizeof(uint32_t)) {
598                         *wrptr32 = *rdptr32;
599                         wrptr32++;
600                         rdptr32++;
601                 }
602
603         return n;
604 }
605
606 #define PCI_DEVICES "/sys/bus/pci/devices"
607
608 static int
609 nfp_acquire_process_lock(struct nfp_pcie_user *desc)
610 {
611         int rc;
612         struct flock lock;
613         char lockname[30];
614
615         memset(&lock, 0, sizeof(lock));
616
617         snprintf(lockname, sizeof(lockname), "/var/lock/nfp_%s", desc->busdev);
618         desc->lock = open(lockname, O_RDWR | O_CREAT, 0666);
619         if (desc->lock < 0)
620                 return desc->lock;
621
622         lock.l_type = F_WRLCK;
623         lock.l_whence = SEEK_SET;
624         rc = -1;
625         while (rc != 0) {
626                 rc = fcntl(desc->lock, F_SETLKW, &lock);
627                 if (rc < 0) {
628                         if (errno != EAGAIN && errno != EACCES) {
629                                 close(desc->lock);
630                                 return rc;
631                         }
632                 }
633         }
634
635         return 0;
636 }
637
638 static int
639 nfp6000_set_model(struct rte_pci_device *dev, struct nfp_cpp *cpp)
640 {
641         uint32_t model;
642
643         if (rte_pci_read_config(dev, &model, 4, 0x2e) < 0) {
644                 printf("nfp set model failed\n");
645                 return -1;
646         }
647
648         model  = model << 16;
649         nfp_cpp_model_set(cpp, model);
650
651         return 0;
652 }
653
654 static int
655 nfp6000_set_interface(struct rte_pci_device *dev, struct nfp_cpp *cpp)
656 {
657         uint16_t interface;
658
659         if (rte_pci_read_config(dev, &interface, 2, 0x154) < 0) {
660                 printf("nfp set interface failed\n");
661                 return -1;
662         }
663
664         nfp_cpp_interface_set(cpp, interface);
665
666         return 0;
667 }
668
669 #define PCI_CFG_SPACE_SIZE      256
670 #define PCI_CFG_SPACE_EXP_SIZE  4096
671 #define PCI_EXT_CAP_ID(header)          (int)(header & 0x0000ffff)
672 #define PCI_EXT_CAP_NEXT(header)        ((header >> 20) & 0xffc)
673 #define PCI_EXT_CAP_ID_DSN      0x03
674 static int
675 nfp_pci_find_next_ext_capability(struct rte_pci_device *dev, int cap)
676 {
677         uint32_t header;
678         int ttl;
679         int pos = PCI_CFG_SPACE_SIZE;
680
681         /* minimum 8 bytes per capability */
682         ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
683
684         if (rte_pci_read_config(dev, &header, 4, pos) < 0) {
685                 printf("nfp error reading extended capabilities\n");
686                 return -1;
687         }
688
689         /*
690          * If we have no capabilities, this is indicated by cap ID,
691          * cap version and next pointer all being 0.
692          */
693         if (header == 0)
694                 return 0;
695
696         while (ttl-- > 0) {
697                 if (PCI_EXT_CAP_ID(header) == cap)
698                         return pos;
699
700                 pos = PCI_EXT_CAP_NEXT(header);
701                 if (pos < PCI_CFG_SPACE_SIZE)
702                         break;
703
704                 if (rte_pci_read_config(dev, &header, 4, pos) < 0) {
705                         printf("nfp error reading extended capabilities\n");
706                         return -1;
707                 }
708         }
709
710         return 0;
711 }
712
713 static int
714 nfp6000_set_serial(struct rte_pci_device *dev, struct nfp_cpp *cpp)
715 {
716         uint16_t tmp;
717         uint8_t serial[6];
718         int serial_len = 6;
719         int pos;
720
721         pos = nfp_pci_find_next_ext_capability(dev, PCI_EXT_CAP_ID_DSN);
722         if (pos <= 0) {
723                 printf("PCI_EXT_CAP_ID_DSN not found. nfp set serial failed\n");
724                 return -1;
725         } else {
726                 pos += 6;
727         }
728
729         if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
730                 printf("nfp set serial failed\n");
731                 return -1;
732         }
733
734         serial[4] = (uint8_t)((tmp >> 8) & 0xff);
735         serial[5] = (uint8_t)(tmp & 0xff);
736
737         pos += 2;
738         if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
739                 printf("nfp set serial failed\n");
740                 return -1;
741         }
742
743         serial[2] = (uint8_t)((tmp >> 8) & 0xff);
744         serial[3] = (uint8_t)(tmp & 0xff);
745
746         pos += 2;
747         if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
748                 printf("nfp set serial failed\n");
749                 return -1;
750         }
751
752         serial[0] = (uint8_t)((tmp >> 8) & 0xff);
753         serial[1] = (uint8_t)(tmp & 0xff);
754
755         nfp_cpp_serial_set(cpp, serial, serial_len);
756
757         return 0;
758 }
759
760 static int
761 nfp6000_set_barsz(struct rte_pci_device *dev, struct nfp_pcie_user *desc)
762 {
763         unsigned long tmp;
764         int i = 0;
765
766         tmp = dev->mem_resource[0].len;
767
768         while (tmp >>= 1)
769                 i++;
770
771         desc->barsz = i;
772         return 0;
773 }
774
775 static int
776 nfp6000_init(struct nfp_cpp *cpp, struct rte_pci_device *dev)
777 {
778         int ret = 0;
779         uint32_t model;
780         struct nfp_pcie_user *desc;
781
782         desc = malloc(sizeof(*desc));
783         if (!desc)
784                 return -1;
785
786
787         memset(desc->busdev, 0, BUSDEV_SZ);
788         strlcpy(desc->busdev, dev->device.name, sizeof(desc->busdev));
789
790         if (cpp->driver_lock_needed) {
791                 ret = nfp_acquire_process_lock(desc);
792                 if (ret)
793                         goto error;
794         }
795
796         if (nfp6000_set_model(dev, cpp) < 0)
797                 goto error;
798         if (nfp6000_set_interface(dev, cpp) < 0)
799                 goto error;
800         if (nfp6000_set_serial(dev, cpp) < 0)
801                 goto error;
802         if (nfp6000_set_barsz(dev, desc) < 0)
803                 goto error;
804
805         desc->cfg = (char *)dev->mem_resource[0].addr;
806
807         nfp_enable_bars(desc);
808
809         nfp_cpp_priv_set(cpp, desc);
810
811         model = __nfp_cpp_model_autodetect(cpp);
812         nfp_cpp_model_set(cpp, model);
813
814         return 0;
815
816 error:
817         free(desc);
818         return -1;
819 }
820
821 static void
822 nfp6000_free(struct nfp_cpp *cpp)
823 {
824         struct nfp_pcie_user *desc = nfp_cpp_priv(cpp);
825
826         nfp_disable_bars(desc);
827         if (cpp->driver_lock_needed)
828                 close(desc->lock);
829         close(desc->device);
830         free(desc);
831 }
832
833 static const struct nfp_cpp_operations nfp6000_pcie_ops = {
834         .init = nfp6000_init,
835         .free = nfp6000_free,
836
837         .area_priv_size = sizeof(struct nfp6000_area_priv),
838         .area_init = nfp6000_area_init,
839         .area_acquire = nfp6000_area_acquire,
840         .area_release = nfp6000_area_release,
841         .area_mapped = nfp6000_area_mapped,
842         .area_read = nfp6000_area_read,
843         .area_write = nfp6000_area_write,
844         .area_iomem = nfp6000_area_iomem,
845 };
846
847 const struct
848 nfp_cpp_operations *nfp_cpp_transport_operations(void)
849 {
850         return &nfp6000_pcie_ops;
851 }