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