net/nfp: fix memory leak
[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         int secondary_lock;
118         char busdev[BUSDEV_SZ];
119         int barsz;
120         char *cfg;
121 };
122
123 static uint32_t
124 nfp_bar_maptype(struct nfp_bar *bar)
125 {
126         return NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_OF(bar->barcfg);
127 }
128
129 #define TARGET_WIDTH_32    4
130 #define TARGET_WIDTH_64    8
131
132 static int
133 nfp_compute_bar(const struct nfp_bar *bar, uint32_t *bar_config,
134                 uint64_t *bar_base, int tgt, int act, int tok,
135                 uint64_t offset, size_t size, int width)
136 {
137         uint32_t bitsize;
138         uint32_t newcfg;
139         uint64_t mask;
140
141         if (tgt >= 16)
142                 return -EINVAL;
143
144         switch (width) {
145         case 8:
146                 newcfg =
147                     NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
148                     (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_64BIT);
149                 break;
150         case 4:
151                 newcfg =
152                     NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
153                     (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_32BIT);
154                 break;
155         case 0:
156                 newcfg =
157                     NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
158                     (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_0BYTE);
159                 break;
160         default:
161                 return -EINVAL;
162         }
163
164         if (act != NFP_CPP_ACTION_RW && act != 0) {
165                 /* Fixed CPP mapping with specific action */
166                 mask = ~(NFP_PCIE_P2C_FIXED_SIZE(bar) - 1);
167
168                 newcfg |=
169                     NFP_PCIE_BAR_PCIE2CPP_MAPTYPE
170                     (NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_FIXED);
171                 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS(tgt);
172                 newcfg |= NFP_PCIE_BAR_PCIE2CPP_ACTION_BASEADDRESS(act);
173                 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS(tok);
174
175                 if ((offset & mask) != ((offset + size - 1) & mask)) {
176                         printf("BAR%d: Won't use for Fixed mapping\n",
177                                 bar->index);
178                         printf("\t<%#llx,%#llx>, action=%d\n",
179                                 (unsigned long long)offset,
180                                 (unsigned long long)(offset + size), act);
181                         printf("\tBAR too small (0x%llx).\n",
182                                 (unsigned long long)mask);
183                         return -EINVAL;
184                 }
185                 offset &= mask;
186
187 #ifdef DEBUG
188                 printf("BAR%d: Created Fixed mapping\n", bar->index);
189                 printf("\t%d:%d:%d:0x%#llx-0x%#llx>\n", tgt, act, tok,
190                         (unsigned long long)offset,
191                         (unsigned long long)(offset + mask));
192 #endif
193
194                 bitsize = 40 - 16;
195         } else {
196                 mask = ~(NFP_PCIE_P2C_BULK_SIZE(bar) - 1);
197
198                 /* Bulk mapping */
199                 newcfg |=
200                     NFP_PCIE_BAR_PCIE2CPP_MAPTYPE
201                     (NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_BULK);
202
203                 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS(tgt);
204                 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS(tok);
205
206                 if ((offset & mask) != ((offset + size - 1) & mask)) {
207                         printf("BAR%d: Won't use for bulk mapping\n",
208                                 bar->index);
209                         printf("\t<%#llx,%#llx>\n", (unsigned long long)offset,
210                                 (unsigned long long)(offset + size));
211                         printf("\ttarget=%d, token=%d\n", tgt, tok);
212                         printf("\tBAR too small (%#llx) - (%#llx != %#llx).\n",
213                                 (unsigned long long)mask,
214                                 (unsigned long long)(offset & mask),
215                                 (unsigned long long)(offset + size - 1) & mask);
216
217                         return -EINVAL;
218                 }
219
220                 offset &= mask;
221
222 #ifdef DEBUG
223                 printf("BAR%d: Created bulk mapping %d:x:%d:%#llx-%#llx\n",
224                         bar->index, tgt, tok, (unsigned long long)offset,
225                         (unsigned long long)(offset + ~mask));
226 #endif
227
228                 bitsize = 40 - 21;
229         }
230
231         if (bar->bitsize < bitsize) {
232                 printf("BAR%d: Too small for %d:%d:%d\n", bar->index, tgt, tok,
233                         act);
234                 return -EINVAL;
235         }
236
237         newcfg |= offset >> bitsize;
238
239         if (bar_base)
240                 *bar_base = offset;
241
242         if (bar_config)
243                 *bar_config = newcfg;
244
245         return 0;
246 }
247
248 static int
249 nfp_bar_write(struct nfp_pcie_user *nfp, struct nfp_bar *bar,
250                   uint32_t newcfg)
251 {
252         int base, slot;
253
254         base = bar->index >> 3;
255         slot = bar->index & 7;
256
257         if (!nfp->cfg)
258                 return (-ENOMEM);
259
260         bar->csr = nfp->cfg +
261                    NFP_PCIE_CFG_BAR_PCIETOCPPEXPBAR(base, slot);
262
263         *(uint32_t *)(bar->csr) = newcfg;
264
265         bar->barcfg = newcfg;
266 #ifdef DEBUG
267         printf("BAR%d: updated to 0x%08x\n", bar->index, newcfg);
268 #endif
269
270         return 0;
271 }
272
273 static int
274 nfp_reconfigure_bar(struct nfp_pcie_user *nfp, struct nfp_bar *bar, int tgt,
275                 int act, int tok, uint64_t offset, size_t size, int width)
276 {
277         uint64_t newbase;
278         uint32_t newcfg;
279         int err;
280
281         err = nfp_compute_bar(bar, &newcfg, &newbase, tgt, act, tok, offset,
282                               size, width);
283         if (err)
284                 return err;
285
286         bar->base = newbase;
287
288         return nfp_bar_write(nfp, bar, newcfg);
289 }
290
291 /*
292  * Map all PCI bars. We assume that the BAR with the PCIe config block is
293  * already mapped.
294  *
295  * BAR0.0: Reserved for General Mapping (for MSI-X access to PCIe SRAM)
296  *
297  *         Halving PCItoCPPBars for primary and secondary processes.
298  *         NFP PMD just requires two fixed slots, one for configuration BAR,
299  *         and another for accessing the hw queues. Another slot is needed
300  *         for setting the link up or down. Secondary processes do not need
301  *         to map the first two slots again, but it requires one slot for
302  *         accessing the link, even if it is not likely the secondary process
303  *         starting the port. This implies a limit of secondary processes
304  *         supported. Due to this requirement and future extensions requiring
305  *         new slots per process, only one secondary process is supported by
306  *         now.
307  */
308 static int
309 nfp_enable_bars(struct nfp_pcie_user *nfp)
310 {
311         struct nfp_bar *bar;
312         int x, start, end;
313
314         if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
315                 start = 4;
316                 end = 1;
317         } else {
318                 start = 7;
319                 end = 4;
320         }
321         for (x = start; x > end; x--) {
322                 bar = &nfp->bar[x - 1];
323                 bar->barcfg = 0;
324                 bar->nfp = nfp;
325                 bar->index = x;
326                 bar->mask = (1 << (nfp->barsz - 3)) - 1;
327                 bar->bitsize = nfp->barsz - 3;
328                 bar->base = 0;
329                 bar->iomem = NULL;
330                 bar->lock = 0;
331                 bar->csr = nfp->cfg +
332                            NFP_PCIE_CFG_BAR_PCIETOCPPEXPBAR(bar->index >> 3,
333                                                            bar->index & 7);
334
335                 bar->iomem = nfp->cfg + (bar->index << bar->bitsize);
336         }
337         return 0;
338 }
339
340 static struct nfp_bar *
341 nfp_alloc_bar(struct nfp_pcie_user *nfp)
342 {
343         struct nfp_bar *bar;
344         int x, start, end;
345
346         if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
347                 start = 4;
348                 end = 1;
349         } else {
350                 start = 7;
351                 end = 4;
352         }
353         for (x = start; x > end; x--) {
354                 bar = &nfp->bar[x - 1];
355                 if (!bar->lock) {
356                         bar->lock = 1;
357                         return bar;
358                 }
359         }
360         return NULL;
361 }
362
363 static void
364 nfp_disable_bars(struct nfp_pcie_user *nfp)
365 {
366         struct nfp_bar *bar;
367         int x, start, end;
368
369         if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
370                 start = 4;
371                 end = 1;
372         } else {
373                 start = 7;
374                 end = 4;
375         }
376
377         for (x = start; x > end; x--) {
378                 bar = &nfp->bar[x - 1];
379                 if (bar->iomem) {
380                         bar->iomem = NULL;
381                         bar->lock = 0;
382                 }
383         }
384 }
385
386 /*
387  * Generic CPP bus access interface.
388  */
389
390 struct nfp6000_area_priv {
391         struct nfp_bar *bar;
392         uint32_t bar_offset;
393
394         uint32_t target;
395         uint32_t action;
396         uint32_t token;
397         uint64_t offset;
398         struct {
399                 int read;
400                 int write;
401                 int bar;
402         } width;
403         size_t size;
404         char *iomem;
405 };
406
407 static int
408 nfp6000_area_init(struct nfp_cpp_area *area, uint32_t dest,
409                   unsigned long long address, unsigned long size)
410 {
411         struct nfp_pcie_user *nfp = nfp_cpp_priv(nfp_cpp_area_cpp(area));
412         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
413         uint32_t target = NFP_CPP_ID_TARGET_of(dest);
414         uint32_t action = NFP_CPP_ID_ACTION_of(dest);
415         uint32_t token = NFP_CPP_ID_TOKEN_of(dest);
416         int pp, ret = 0;
417
418         pp = nfp6000_target_pushpull(NFP_CPP_ID(target, action, token),
419                                      address);
420         if (pp < 0)
421                 return pp;
422
423         priv->width.read = PUSH_WIDTH(pp);
424         priv->width.write = PULL_WIDTH(pp);
425
426         if (priv->width.read > 0 &&
427             priv->width.write > 0 && priv->width.read != priv->width.write)
428                 return -EINVAL;
429
430         if (priv->width.read > 0)
431                 priv->width.bar = priv->width.read;
432         else
433                 priv->width.bar = priv->width.write;
434
435         priv->bar = nfp_alloc_bar(nfp);
436         if (priv->bar == NULL)
437                 return -ENOMEM;
438
439         priv->target = target;
440         priv->action = action;
441         priv->token = token;
442         priv->offset = address;
443         priv->size = size;
444
445         ret = nfp_reconfigure_bar(nfp, priv->bar, priv->target, priv->action,
446                                   priv->token, priv->offset, priv->size,
447                                   priv->width.bar);
448
449         return ret;
450 }
451
452 static int
453 nfp6000_area_acquire(struct nfp_cpp_area *area)
454 {
455         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
456
457         /* Calculate offset into BAR. */
458         if (nfp_bar_maptype(priv->bar) ==
459             NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_GENERAL) {
460                 priv->bar_offset = priv->offset &
461                         (NFP_PCIE_P2C_GENERAL_SIZE(priv->bar) - 1);
462                 priv->bar_offset +=
463                         NFP_PCIE_P2C_GENERAL_TARGET_OFFSET(priv->bar,
464                                                            priv->target);
465                 priv->bar_offset +=
466                     NFP_PCIE_P2C_GENERAL_TOKEN_OFFSET(priv->bar, priv->token);
467         } else {
468                 priv->bar_offset = priv->offset & priv->bar->mask;
469         }
470
471         /* Must have been too big. Sub-allocate. */
472         if (!priv->bar->iomem)
473                 return (-ENOMEM);
474
475         priv->iomem = priv->bar->iomem + priv->bar_offset;
476
477         return 0;
478 }
479
480 static void *
481 nfp6000_area_mapped(struct nfp_cpp_area *area)
482 {
483         struct nfp6000_area_priv *area_priv = nfp_cpp_area_priv(area);
484
485         if (!area_priv->iomem)
486                 return NULL;
487
488         return area_priv->iomem;
489 }
490
491 static void
492 nfp6000_area_release(struct nfp_cpp_area *area)
493 {
494         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
495         priv->bar->lock = 0;
496         priv->bar = NULL;
497         priv->iomem = NULL;
498 }
499
500 static void *
501 nfp6000_area_iomem(struct nfp_cpp_area *area)
502 {
503         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
504         return priv->iomem;
505 }
506
507 static int
508 nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr,
509                   unsigned long offset, unsigned int length)
510 {
511         uint64_t *wrptr64 = kernel_vaddr;
512         const volatile uint64_t *rdptr64;
513         struct nfp6000_area_priv *priv;
514         uint32_t *wrptr32 = kernel_vaddr;
515         const volatile uint32_t *rdptr32;
516         int width;
517         unsigned int n;
518         bool is_64;
519
520         priv = nfp_cpp_area_priv(area);
521         rdptr64 = (uint64_t *)(priv->iomem + offset);
522         rdptr32 = (uint32_t *)(priv->iomem + offset);
523
524         if (offset + length > priv->size)
525                 return -EFAULT;
526
527         width = priv->width.read;
528
529         if (width <= 0)
530                 return -EINVAL;
531
532         /* Unaligned? Translate to an explicit access */
533         if ((priv->offset + offset) & (width - 1)) {
534                 printf("aread_read unaligned!!!\n");
535                 return -EINVAL;
536         }
537
538         is_64 = width == TARGET_WIDTH_64;
539
540         /* MU reads via a PCIe2CPP BAR supports 32bit (and other) lengths */
541         if (priv->target == (NFP_CPP_TARGET_ID_MASK & NFP_CPP_TARGET_MU) &&
542             priv->action == NFP_CPP_ACTION_RW) {
543                 is_64 = false;
544         }
545
546         if (is_64) {
547                 if (offset % sizeof(uint64_t) != 0 ||
548                     length % sizeof(uint64_t) != 0)
549                         return -EINVAL;
550         } else {
551                 if (offset % sizeof(uint32_t) != 0 ||
552                     length % sizeof(uint32_t) != 0)
553                         return -EINVAL;
554         }
555
556         if (!priv->bar)
557                 return -EFAULT;
558
559         if (is_64)
560                 for (n = 0; n < length; n += sizeof(uint64_t)) {
561                         *wrptr64 = *rdptr64;
562                         wrptr64++;
563                         rdptr64++;
564                 }
565         else
566                 for (n = 0; n < length; n += sizeof(uint32_t)) {
567                         *wrptr32 = *rdptr32;
568                         wrptr32++;
569                         rdptr32++;
570                 }
571
572         return n;
573 }
574
575 static int
576 nfp6000_area_write(struct nfp_cpp_area *area, const void *kernel_vaddr,
577                    unsigned long offset, unsigned int length)
578 {
579         const uint64_t *rdptr64 = kernel_vaddr;
580         uint64_t *wrptr64;
581         const uint32_t *rdptr32 = kernel_vaddr;
582         struct nfp6000_area_priv *priv;
583         uint32_t *wrptr32;
584         int width;
585         unsigned int n;
586         bool is_64;
587
588         priv = nfp_cpp_area_priv(area);
589         wrptr64 = (uint64_t *)(priv->iomem + offset);
590         wrptr32 = (uint32_t *)(priv->iomem + offset);
591
592         if (offset + length > priv->size)
593                 return -EFAULT;
594
595         width = priv->width.write;
596
597         if (width <= 0)
598                 return -EINVAL;
599
600         /* Unaligned? Translate to an explicit access */
601         if ((priv->offset + offset) & (width - 1))
602                 return -EINVAL;
603
604         is_64 = width == TARGET_WIDTH_64;
605
606         /* MU writes via a PCIe2CPP BAR supports 32bit (and other) lengths */
607         if (priv->target == (NFP_CPP_TARGET_ID_MASK & NFP_CPP_TARGET_MU) &&
608             priv->action == NFP_CPP_ACTION_RW)
609                 is_64 = false;
610
611         if (is_64) {
612                 if (offset % sizeof(uint64_t) != 0 ||
613                     length % sizeof(uint64_t) != 0)
614                         return -EINVAL;
615         } else {
616                 if (offset % sizeof(uint32_t) != 0 ||
617                     length % sizeof(uint32_t) != 0)
618                         return -EINVAL;
619         }
620
621         if (!priv->bar)
622                 return -EFAULT;
623
624         if (is_64)
625                 for (n = 0; n < length; n += sizeof(uint64_t)) {
626                         *wrptr64 = *rdptr64;
627                         wrptr64++;
628                         rdptr64++;
629                 }
630         else
631                 for (n = 0; n < length; n += sizeof(uint32_t)) {
632                         *wrptr32 = *rdptr32;
633                         wrptr32++;
634                         rdptr32++;
635                 }
636
637         return n;
638 }
639
640 #define PCI_DEVICES "/sys/bus/pci/devices"
641
642 static int
643 nfp_acquire_process_lock(struct nfp_pcie_user *desc)
644 {
645         int rc;
646         struct flock lock;
647         char lockname[30];
648
649         memset(&lock, 0, sizeof(lock));
650
651         snprintf(lockname, sizeof(lockname), "/var/lock/nfp_%s", desc->busdev);
652         desc->lock = open(lockname, O_RDWR | O_CREAT, 0666);
653         if (desc->lock < 0)
654                 return desc->lock;
655
656         lock.l_type = F_WRLCK;
657         lock.l_whence = SEEK_SET;
658         rc = -1;
659         while (rc != 0) {
660                 rc = fcntl(desc->lock, F_SETLKW, &lock);
661                 if (rc < 0) {
662                         if (errno != EAGAIN && errno != EACCES) {
663                                 close(desc->lock);
664                                 return rc;
665                         }
666                 }
667         }
668
669         return 0;
670 }
671
672 static int
673 nfp_acquire_secondary_process_lock(struct nfp_pcie_user *desc)
674 {
675         int rc;
676         struct flock lock;
677         const char *lockname = "/.lock_nfp_secondary";
678         char *home_path;
679         char *lockfile;
680
681         memset(&lock, 0, sizeof(lock));
682
683         /*
684          * Using user's home directory. Note this can be called in a DPDK app
685          * being executed as non-root. This is not the case for the previous
686          * function nfp_acquire_process_lock which is invoked only when UIO
687          * driver is used because that implies root user.
688          */
689         home_path = getenv("HOME");
690         lockfile = calloc(strlen(home_path) + strlen(lockname) + 1,
691                           sizeof(char));
692
693         strcat(lockfile, home_path);
694         strcat(lockfile, "/.lock_nfp_secondary");
695         desc->secondary_lock = open(lockfile, O_RDWR | O_CREAT | O_NONBLOCK,
696                                     0666);
697         if (desc->secondary_lock < 0) {
698                 RTE_LOG(ERR, PMD, "NFP lock for secondary process failed\n");
699                 return desc->secondary_lock;
700         }
701
702         lock.l_type = F_WRLCK;
703         lock.l_whence = SEEK_SET;
704         rc = fcntl(desc->secondary_lock, F_SETLK, &lock);
705         if (rc < 0) {
706                 RTE_LOG(ERR, PMD, "NFP lock for secondary process failed\n");
707                 close(desc->secondary_lock);
708         }
709
710         return rc;
711 }
712
713 static int
714 nfp6000_set_model(struct rte_pci_device *dev, struct nfp_cpp *cpp)
715 {
716         uint32_t model;
717
718         if (rte_pci_read_config(dev, &model, 4, 0x2e) < 0) {
719                 printf("nfp set model failed\n");
720                 return -1;
721         }
722
723         model  = model << 16;
724         nfp_cpp_model_set(cpp, model);
725
726         return 0;
727 }
728
729 static int
730 nfp6000_set_interface(struct rte_pci_device *dev, struct nfp_cpp *cpp)
731 {
732         uint16_t interface;
733
734         if (rte_pci_read_config(dev, &interface, 2, 0x154) < 0) {
735                 printf("nfp set interface failed\n");
736                 return -1;
737         }
738
739         nfp_cpp_interface_set(cpp, interface);
740
741         return 0;
742 }
743
744 #define PCI_CFG_SPACE_SIZE      256
745 #define PCI_CFG_SPACE_EXP_SIZE  4096
746 #define PCI_EXT_CAP_ID(header)          (int)(header & 0x0000ffff)
747 #define PCI_EXT_CAP_NEXT(header)        ((header >> 20) & 0xffc)
748 #define PCI_EXT_CAP_ID_DSN      0x03
749 static int
750 nfp_pci_find_next_ext_capability(struct rte_pci_device *dev, int cap)
751 {
752         uint32_t header;
753         int ttl;
754         int pos = PCI_CFG_SPACE_SIZE;
755
756         /* minimum 8 bytes per capability */
757         ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
758
759         if (rte_pci_read_config(dev, &header, 4, pos) < 0) {
760                 printf("nfp error reading extended capabilities\n");
761                 return -1;
762         }
763
764         /*
765          * If we have no capabilities, this is indicated by cap ID,
766          * cap version and next pointer all being 0.
767          */
768         if (header == 0)
769                 return 0;
770
771         while (ttl-- > 0) {
772                 if (PCI_EXT_CAP_ID(header) == cap)
773                         return pos;
774
775                 pos = PCI_EXT_CAP_NEXT(header);
776                 if (pos < PCI_CFG_SPACE_SIZE)
777                         break;
778
779                 if (rte_pci_read_config(dev, &header, 4, pos) < 0) {
780                         printf("nfp error reading extended capabilities\n");
781                         return -1;
782                 }
783         }
784
785         return 0;
786 }
787
788 static int
789 nfp6000_set_serial(struct rte_pci_device *dev, struct nfp_cpp *cpp)
790 {
791         uint16_t tmp;
792         uint8_t serial[6];
793         int serial_len = 6;
794         int pos;
795
796         pos = nfp_pci_find_next_ext_capability(dev, PCI_EXT_CAP_ID_DSN);
797         if (pos <= 0) {
798                 printf("PCI_EXT_CAP_ID_DSN not found. nfp set serial failed\n");
799                 return -1;
800         } else {
801                 pos += 6;
802         }
803
804         if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
805                 printf("nfp set serial failed\n");
806                 return -1;
807         }
808
809         serial[4] = (uint8_t)((tmp >> 8) & 0xff);
810         serial[5] = (uint8_t)(tmp & 0xff);
811
812         pos += 2;
813         if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
814                 printf("nfp set serial failed\n");
815                 return -1;
816         }
817
818         serial[2] = (uint8_t)((tmp >> 8) & 0xff);
819         serial[3] = (uint8_t)(tmp & 0xff);
820
821         pos += 2;
822         if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
823                 printf("nfp set serial failed\n");
824                 return -1;
825         }
826
827         serial[0] = (uint8_t)((tmp >> 8) & 0xff);
828         serial[1] = (uint8_t)(tmp & 0xff);
829
830         nfp_cpp_serial_set(cpp, serial, serial_len);
831
832         return 0;
833 }
834
835 static int
836 nfp6000_set_barsz(struct rte_pci_device *dev, struct nfp_pcie_user *desc)
837 {
838         unsigned long tmp;
839         int i = 0;
840
841         tmp = dev->mem_resource[0].len;
842
843         while (tmp >>= 1)
844                 i++;
845
846         desc->barsz = i;
847         return 0;
848 }
849
850 static int
851 nfp6000_init(struct nfp_cpp *cpp, struct rte_pci_device *dev)
852 {
853         int ret = 0;
854         struct nfp_pcie_user *desc;
855
856         desc = malloc(sizeof(*desc));
857         if (!desc)
858                 return -1;
859
860
861         memset(desc->busdev, 0, BUSDEV_SZ);
862         strlcpy(desc->busdev, dev->device.name, sizeof(desc->busdev));
863
864         if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
865             cpp->driver_lock_needed) {
866                 ret = nfp_acquire_process_lock(desc);
867                 if (ret)
868                         goto error;
869         }
870
871         /* Just support for one secondary process */
872         if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
873                 ret = nfp_acquire_secondary_process_lock(desc);
874                 if (ret)
875                         goto error;
876         }
877
878         if (nfp6000_set_model(dev, cpp) < 0)
879                 goto error;
880         if (nfp6000_set_interface(dev, cpp) < 0)
881                 goto error;
882         if (nfp6000_set_serial(dev, cpp) < 0)
883                 goto error;
884         if (nfp6000_set_barsz(dev, desc) < 0)
885                 goto error;
886
887         desc->cfg = (char *)dev->mem_resource[0].addr;
888
889         nfp_enable_bars(desc);
890
891         nfp_cpp_priv_set(cpp, desc);
892
893         return 0;
894
895 error:
896         free(desc);
897         return -1;
898 }
899
900 static void
901 nfp6000_free(struct nfp_cpp *cpp)
902 {
903         struct nfp_pcie_user *desc = nfp_cpp_priv(cpp);
904
905         nfp_disable_bars(desc);
906         if (cpp->driver_lock_needed)
907                 close(desc->lock);
908         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
909                 close(desc->secondary_lock);
910         close(desc->device);
911         free(desc);
912 }
913
914 static const struct nfp_cpp_operations nfp6000_pcie_ops = {
915         .init = nfp6000_init,
916         .free = nfp6000_free,
917
918         .area_priv_size = sizeof(struct nfp6000_area_priv),
919         .area_init = nfp6000_area_init,
920         .area_acquire = nfp6000_area_acquire,
921         .area_release = nfp6000_area_release,
922         .area_mapped = nfp6000_area_mapped,
923         .area_read = nfp6000_area_read,
924         .area_write = nfp6000_area_write,
925         .area_iomem = nfp6000_area_iomem,
926 };
927
928 const struct
929 nfp_cpp_operations *nfp_cpp_transport_operations(void)
930 {
931         return &nfp6000_pcie_ops;
932 }