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