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