New upstream version 18.08
[deb_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
314                 bar->iomem = nfp->cfg + (bar->index << bar->bitsize);
315         }
316         return 0;
317 }
318
319 static struct nfp_bar *
320 nfp_alloc_bar(struct nfp_pcie_user *nfp)
321 {
322         struct nfp_bar *bar;
323         int x;
324
325         for (x = ARRAY_SIZE(nfp->bar); x > 0; x--) {
326                 bar = &nfp->bar[x - 1];
327                 if (!bar->lock) {
328                         bar->lock = 1;
329                         return bar;
330                 }
331         }
332         return NULL;
333 }
334
335 static void
336 nfp_disable_bars(struct nfp_pcie_user *nfp)
337 {
338         struct nfp_bar *bar;
339         int x;
340
341         for (x = ARRAY_SIZE(nfp->bar); x > 0; x--) {
342                 bar = &nfp->bar[x - 1];
343                 if (bar->iomem) {
344                         bar->iomem = NULL;
345                         bar->lock = 0;
346                 }
347         }
348 }
349
350 /*
351  * Generic CPP bus access interface.
352  */
353
354 struct nfp6000_area_priv {
355         struct nfp_bar *bar;
356         uint32_t bar_offset;
357
358         uint32_t target;
359         uint32_t action;
360         uint32_t token;
361         uint64_t offset;
362         struct {
363                 int read;
364                 int write;
365                 int bar;
366         } width;
367         size_t size;
368         char *iomem;
369 };
370
371 static int
372 nfp6000_area_init(struct nfp_cpp_area *area, uint32_t dest,
373                   unsigned long long address, unsigned long size)
374 {
375         struct nfp_pcie_user *nfp = nfp_cpp_priv(nfp_cpp_area_cpp(area));
376         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
377         uint32_t target = NFP_CPP_ID_TARGET_of(dest);
378         uint32_t action = NFP_CPP_ID_ACTION_of(dest);
379         uint32_t token = NFP_CPP_ID_TOKEN_of(dest);
380         int pp, ret = 0;
381
382         pp = nfp6000_target_pushpull(NFP_CPP_ID(target, action, token),
383                                      address);
384         if (pp < 0)
385                 return pp;
386
387         priv->width.read = PUSH_WIDTH(pp);
388         priv->width.write = PULL_WIDTH(pp);
389
390         if (priv->width.read > 0 &&
391             priv->width.write > 0 && priv->width.read != priv->width.write)
392                 return -EINVAL;
393
394         if (priv->width.read > 0)
395                 priv->width.bar = priv->width.read;
396         else
397                 priv->width.bar = priv->width.write;
398
399         priv->bar = nfp_alloc_bar(nfp);
400         if (priv->bar == NULL)
401                 return -ENOMEM;
402
403         priv->target = target;
404         priv->action = action;
405         priv->token = token;
406         priv->offset = address;
407         priv->size = size;
408
409         ret = nfp_reconfigure_bar(nfp, priv->bar, priv->target, priv->action,
410                                   priv->token, priv->offset, priv->size,
411                                   priv->width.bar);
412
413         return ret;
414 }
415
416 static int
417 nfp6000_area_acquire(struct nfp_cpp_area *area)
418 {
419         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
420
421         /* Calculate offset into BAR. */
422         if (nfp_bar_maptype(priv->bar) ==
423             NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_GENERAL) {
424                 priv->bar_offset = priv->offset &
425                         (NFP_PCIE_P2C_GENERAL_SIZE(priv->bar) - 1);
426                 priv->bar_offset +=
427                         NFP_PCIE_P2C_GENERAL_TARGET_OFFSET(priv->bar,
428                                                            priv->target);
429                 priv->bar_offset +=
430                     NFP_PCIE_P2C_GENERAL_TOKEN_OFFSET(priv->bar, priv->token);
431         } else {
432                 priv->bar_offset = priv->offset & priv->bar->mask;
433         }
434
435         /* Must have been too big. Sub-allocate. */
436         if (!priv->bar->iomem)
437                 return (-ENOMEM);
438
439         priv->iomem = priv->bar->iomem + priv->bar_offset;
440
441         return 0;
442 }
443
444 static void *
445 nfp6000_area_mapped(struct nfp_cpp_area *area)
446 {
447         struct nfp6000_area_priv *area_priv = nfp_cpp_area_priv(area);
448
449         if (!area_priv->iomem)
450                 return NULL;
451
452         return area_priv->iomem;
453 }
454
455 static void
456 nfp6000_area_release(struct nfp_cpp_area *area)
457 {
458         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
459         priv->bar->lock = 0;
460         priv->bar = NULL;
461         priv->iomem = NULL;
462 }
463
464 static void *
465 nfp6000_area_iomem(struct nfp_cpp_area *area)
466 {
467         struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
468         return priv->iomem;
469 }
470
471 static int
472 nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr,
473                   unsigned long offset, unsigned int length)
474 {
475         uint64_t *wrptr64 = kernel_vaddr;
476         const volatile uint64_t *rdptr64;
477         struct nfp6000_area_priv *priv;
478         uint32_t *wrptr32 = kernel_vaddr;
479         const volatile uint32_t *rdptr32;
480         int width;
481         unsigned int n;
482         bool is_64;
483
484         priv = nfp_cpp_area_priv(area);
485         rdptr64 = (uint64_t *)(priv->iomem + offset);
486         rdptr32 = (uint32_t *)(priv->iomem + offset);
487
488         if (offset + length > priv->size)
489                 return -EFAULT;
490
491         width = priv->width.read;
492
493         if (width <= 0)
494                 return -EINVAL;
495
496         /* Unaligned? Translate to an explicit access */
497         if ((priv->offset + offset) & (width - 1)) {
498                 printf("aread_read unaligned!!!\n");
499                 return -EINVAL;
500         }
501
502         is_64 = width == TARGET_WIDTH_64;
503
504         /* MU reads via a PCIe2CPP BAR supports 32bit (and other) lengths */
505         if (priv->target == (NFP_CPP_TARGET_ID_MASK & NFP_CPP_TARGET_MU) &&
506             priv->action == NFP_CPP_ACTION_RW) {
507                 is_64 = false;
508         }
509
510         if (is_64) {
511                 if (offset % sizeof(uint64_t) != 0 ||
512                     length % sizeof(uint64_t) != 0)
513                         return -EINVAL;
514         } else {
515                 if (offset % sizeof(uint32_t) != 0 ||
516                     length % sizeof(uint32_t) != 0)
517                         return -EINVAL;
518         }
519
520         if (!priv->bar)
521                 return -EFAULT;
522
523         if (is_64)
524                 for (n = 0; n < length; n += sizeof(uint64_t)) {
525                         *wrptr64 = *rdptr64;
526                         wrptr64++;
527                         rdptr64++;
528                 }
529         else
530                 for (n = 0; n < length; n += sizeof(uint32_t)) {
531                         *wrptr32 = *rdptr32;
532                         wrptr32++;
533                         rdptr32++;
534                 }
535
536         return n;
537 }
538
539 static int
540 nfp6000_area_write(struct nfp_cpp_area *area, const void *kernel_vaddr,
541                    unsigned long offset, unsigned int length)
542 {
543         const uint64_t *rdptr64 = kernel_vaddr;
544         uint64_t *wrptr64;
545         const uint32_t *rdptr32 = kernel_vaddr;
546         struct nfp6000_area_priv *priv;
547         uint32_t *wrptr32;
548         int width;
549         unsigned int n;
550         bool is_64;
551
552         priv = nfp_cpp_area_priv(area);
553         wrptr64 = (uint64_t *)(priv->iomem + offset);
554         wrptr32 = (uint32_t *)(priv->iomem + offset);
555
556         if (offset + length > priv->size)
557                 return -EFAULT;
558
559         width = priv->width.write;
560
561         if (width <= 0)
562                 return -EINVAL;
563
564         /* Unaligned? Translate to an explicit access */
565         if ((priv->offset + offset) & (width - 1))
566                 return -EINVAL;
567
568         is_64 = width == TARGET_WIDTH_64;
569
570         /* MU writes via a PCIe2CPP BAR supports 32bit (and other) lengths */
571         if (priv->target == (NFP_CPP_TARGET_ID_MASK & NFP_CPP_TARGET_MU) &&
572             priv->action == NFP_CPP_ACTION_RW)
573                 is_64 = false;
574
575         if (is_64) {
576                 if (offset % sizeof(uint64_t) != 0 ||
577                     length % sizeof(uint64_t) != 0)
578                         return -EINVAL;
579         } else {
580                 if (offset % sizeof(uint32_t) != 0 ||
581                     length % sizeof(uint32_t) != 0)
582                         return -EINVAL;
583         }
584
585         if (!priv->bar)
586                 return -EFAULT;
587
588         if (is_64)
589                 for (n = 0; n < length; n += sizeof(uint64_t)) {
590                         *wrptr64 = *rdptr64;
591                         wrptr64++;
592                         rdptr64++;
593                 }
594         else
595                 for (n = 0; n < length; n += sizeof(uint32_t)) {
596                         *wrptr32 = *rdptr32;
597                         wrptr32++;
598                         rdptr32++;
599                 }
600
601         return n;
602 }
603
604 #define PCI_DEVICES "/sys/bus/pci/devices"
605
606 static int
607 nfp_acquire_process_lock(struct nfp_pcie_user *desc)
608 {
609         int rc;
610         struct flock lock;
611         char lockname[30];
612
613         memset(&lock, 0, sizeof(lock));
614
615         snprintf(lockname, sizeof(lockname), "/var/lock/nfp_%s", desc->busdev);
616         desc->lock = open(lockname, O_RDWR | O_CREAT, 0666);
617         if (desc->lock < 0)
618                 return desc->lock;
619
620         lock.l_type = F_WRLCK;
621         lock.l_whence = SEEK_SET;
622         rc = -1;
623         while (rc != 0) {
624                 rc = fcntl(desc->lock, F_SETLKW, &lock);
625                 if (rc < 0) {
626                         if (errno != EAGAIN && errno != EACCES) {
627                                 close(desc->lock);
628                                 return rc;
629                         }
630                 }
631         }
632
633         return 0;
634 }
635
636 static int
637 nfp6000_set_model(struct rte_pci_device *dev, struct nfp_cpp *cpp)
638 {
639         uint32_t model;
640
641         if (rte_pci_read_config(dev, &model, 4, 0x2e) < 0) {
642                 printf("nfp set model failed\n");
643                 return -1;
644         }
645
646         model  = model << 16;
647         nfp_cpp_model_set(cpp, model);
648
649         return 0;
650 }
651
652 static int
653 nfp6000_set_interface(struct rte_pci_device *dev, struct nfp_cpp *cpp)
654 {
655         uint16_t interface;
656
657         if (rte_pci_read_config(dev, &interface, 2, 0x154) < 0) {
658                 printf("nfp set interface failed\n");
659                 return -1;
660         }
661
662         nfp_cpp_interface_set(cpp, interface);
663
664         return 0;
665 }
666
667 #define PCI_CFG_SPACE_SIZE      256
668 #define PCI_CFG_SPACE_EXP_SIZE  4096
669 #define PCI_EXT_CAP_ID(header)          (int)(header & 0x0000ffff)
670 #define PCI_EXT_CAP_NEXT(header)        ((header >> 20) & 0xffc)
671 #define PCI_EXT_CAP_ID_DSN      0x03
672 static int
673 nfp_pci_find_next_ext_capability(struct rte_pci_device *dev, int cap)
674 {
675         uint32_t header;
676         int ttl;
677         int pos = PCI_CFG_SPACE_SIZE;
678
679         /* minimum 8 bytes per capability */
680         ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
681
682         if (rte_pci_read_config(dev, &header, 4, pos) < 0) {
683                 printf("nfp error reading extended capabilities\n");
684                 return -1;
685         }
686
687         /*
688          * If we have no capabilities, this is indicated by cap ID,
689          * cap version and next pointer all being 0.
690          */
691         if (header == 0)
692                 return 0;
693
694         while (ttl-- > 0) {
695                 if (PCI_EXT_CAP_ID(header) == cap)
696                         return pos;
697
698                 pos = PCI_EXT_CAP_NEXT(header);
699                 if (pos < PCI_CFG_SPACE_SIZE)
700                         break;
701
702                 if (rte_pci_read_config(dev, &header, 4, pos) < 0) {
703                         printf("nfp error reading extended capabilities\n");
704                         return -1;
705                 }
706         }
707
708         return 0;
709 }
710
711 static int
712 nfp6000_set_serial(struct rte_pci_device *dev, struct nfp_cpp *cpp)
713 {
714         uint16_t tmp;
715         uint8_t serial[6];
716         int serial_len = 6;
717         int pos;
718
719         pos = nfp_pci_find_next_ext_capability(dev, PCI_EXT_CAP_ID_DSN);
720         if (pos <= 0) {
721                 printf("PCI_EXT_CAP_ID_DSN not found. nfp set serial failed\n");
722                 return -1;
723         } else {
724                 pos += 6;
725         }
726
727         if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
728                 printf("nfp set serial failed\n");
729                 return -1;
730         }
731
732         serial[4] = (uint8_t)((tmp >> 8) & 0xff);
733         serial[5] = (uint8_t)(tmp & 0xff);
734
735         pos += 2;
736         if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
737                 printf("nfp set serial failed\n");
738                 return -1;
739         }
740
741         serial[2] = (uint8_t)((tmp >> 8) & 0xff);
742         serial[3] = (uint8_t)(tmp & 0xff);
743
744         pos += 2;
745         if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
746                 printf("nfp set serial failed\n");
747                 return -1;
748         }
749
750         serial[0] = (uint8_t)((tmp >> 8) & 0xff);
751         serial[1] = (uint8_t)(tmp & 0xff);
752
753         nfp_cpp_serial_set(cpp, serial, serial_len);
754
755         return 0;
756 }
757
758 static int
759 nfp6000_set_barsz(struct rte_pci_device *dev, struct nfp_pcie_user *desc)
760 {
761         unsigned long tmp;
762         int i = 0;
763
764         tmp = dev->mem_resource[0].len;
765
766         while (tmp >>= 1)
767                 i++;
768
769         desc->barsz = i;
770         return 0;
771 }
772
773 static int
774 nfp6000_init(struct nfp_cpp *cpp, struct rte_pci_device *dev)
775 {
776         int ret = 0;
777         uint32_t model;
778         struct nfp_pcie_user *desc;
779
780         desc = malloc(sizeof(*desc));
781         if (!desc)
782                 return -1;
783
784
785         memset(desc->busdev, 0, BUSDEV_SZ);
786         strlcpy(desc->busdev, dev->device.name, sizeof(desc->busdev));
787
788         if (cpp->driver_lock_needed) {
789                 ret = nfp_acquire_process_lock(desc);
790                 if (ret)
791                         return -1;
792         }
793
794         if (nfp6000_set_model(dev, cpp) < 0)
795                 return -1;
796         if (nfp6000_set_interface(dev, cpp) < 0)
797                 return -1;
798         if (nfp6000_set_serial(dev, cpp) < 0)
799                 return -1;
800         if (nfp6000_set_barsz(dev, desc) < 0)
801                 return -1;
802
803         desc->cfg = (char *)dev->mem_resource[0].addr;
804
805         nfp_enable_bars(desc);
806
807         nfp_cpp_priv_set(cpp, desc);
808
809         model = __nfp_cpp_model_autodetect(cpp);
810         nfp_cpp_model_set(cpp, model);
811
812         return ret;
813 }
814
815 static void
816 nfp6000_free(struct nfp_cpp *cpp)
817 {
818         struct nfp_pcie_user *desc = nfp_cpp_priv(cpp);
819
820         nfp_disable_bars(desc);
821         if (cpp->driver_lock_needed)
822                 close(desc->lock);
823         close(desc->device);
824         free(desc);
825 }
826
827 static const struct nfp_cpp_operations nfp6000_pcie_ops = {
828         .init = nfp6000_init,
829         .free = nfp6000_free,
830
831         .area_priv_size = sizeof(struct nfp6000_area_priv),
832         .area_init = nfp6000_area_init,
833         .area_acquire = nfp6000_area_acquire,
834         .area_release = nfp6000_area_release,
835         .area_mapped = nfp6000_area_mapped,
836         .area_read = nfp6000_area_read,
837         .area_write = nfp6000_area_write,
838         .area_iomem = nfp6000_area_iomem,
839 };
840
841 const struct
842 nfp_cpp_operations *nfp_cpp_transport_operations(void)
843 {
844         return &nfp6000_pcie_ops;
845 }