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