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