1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Netronome Systems, Inc.
8 * Authors: Vinayak Tammineedi <vinayak.tammineedi@netronome.com>
10 * Multiplexes the NFP BARs between NFP internal resources and
11 * implements the PCIe specific interface for generic CPP bus access.
13 * The BARs are managed and allocated if they are available.
14 * The generic CPP bus abstraction builds upon this BAR interface.
34 #include <rte_string_fns.h>
37 #include "nfp_target.h"
38 #include "nfp6000/nfp6000.h"
40 #define NFP_PCIE_BAR(_pf) (0x30000 + ((_pf) & 7) * 0xc0)
42 #define NFP_PCIE_BAR_PCIE2CPP_ACTION_BASEADDRESS(_x) (((_x) & 0x1f) << 16)
43 #define NFP_PCIE_BAR_PCIE2CPP_BASEADDRESS(_x) (((_x) & 0xffff) << 0)
44 #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT(_x) (((_x) & 0x3) << 27)
45 #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_32BIT 0
46 #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_64BIT 1
47 #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_0BYTE 3
48 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE(_x) (((_x) & 0x7) << 29)
49 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_OF(_x) (((_x) >> 29) & 0x7)
50 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_FIXED 0
51 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_BULK 1
52 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_TARGET 2
53 #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_GENERAL 3
54 #define NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS(_x) (((_x) & 0xf) << 23)
55 #define NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS(_x) (((_x) & 0x3) << 21)
58 * Minimal size of the PCIe cfg memory we depend on being mapped,
59 * queue controller and DMA controller don't have to be covered.
61 #define NFP_PCI_MIN_MAP_SIZE 0x080000
63 #define NFP_PCIE_P2C_FIXED_SIZE(bar) (1 << (bar)->bitsize)
64 #define NFP_PCIE_P2C_BULK_SIZE(bar) (1 << (bar)->bitsize)
65 #define NFP_PCIE_P2C_GENERAL_TARGET_OFFSET(bar, x) ((x) << ((bar)->bitsize - 2))
66 #define NFP_PCIE_P2C_GENERAL_TOKEN_OFFSET(bar, x) ((x) << ((bar)->bitsize - 4))
67 #define NFP_PCIE_P2C_GENERAL_SIZE(bar) (1 << ((bar)->bitsize - 4))
69 #define NFP_PCIE_CFG_BAR_PCIETOCPPEXPBAR(bar, slot) \
70 (NFP_PCIE_BAR(0) + ((bar) * 8 + (slot)) * 4)
72 #define NFP_PCIE_CPP_BAR_PCIETOCPPEXPBAR(bar, slot) \
73 (((bar) * 8 + (slot)) * 4)
76 * Define to enable a bit more verbose debug output.
77 * Set to 1 to enable a bit more verbose debug output.
80 struct nfp6000_area_priv;
83 * struct nfp_bar - describes BAR configuration and usage
84 * @nfp: backlink to owner
85 * @barcfg: cached contents of BAR config CSR
86 * @base: the BAR's base CPP offset
87 * @mask: mask for the BAR aperture (read only)
88 * @bitsize: bitsize of BAR aperture (read only)
89 * @index: index of the BAR
90 * @lock: lock to specify if bar is in use
91 * @refcnt: number of current users
92 * @iomem: mapped IO memory
96 struct nfp_pcie_user *nfp;
98 uint64_t base; /* CPP address base */
99 uint64_t mask; /* Bit mask of the bar */
100 uint32_t bitsize; /* Bit size of the bar */
109 struct nfp_pcie_user {
110 struct nfp_bar bar[NFP_BAR_MAX];
114 char busdev[BUSDEV_SZ];
120 nfp_bar_maptype(struct nfp_bar *bar)
122 return NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_OF(bar->barcfg);
125 #define TARGET_WIDTH_32 4
126 #define TARGET_WIDTH_64 8
129 nfp_compute_bar(const struct nfp_bar *bar, uint32_t *bar_config,
130 uint64_t *bar_base, int tgt, int act, int tok,
131 uint64_t offset, size_t size, int width)
143 NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
144 (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_64BIT);
148 NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
149 (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_32BIT);
153 NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
154 (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_0BYTE);
160 if (act != NFP_CPP_ACTION_RW && act != 0) {
161 /* Fixed CPP mapping with specific action */
162 mask = ~(NFP_PCIE_P2C_FIXED_SIZE(bar) - 1);
165 NFP_PCIE_BAR_PCIE2CPP_MAPTYPE
166 (NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_FIXED);
167 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS(tgt);
168 newcfg |= NFP_PCIE_BAR_PCIE2CPP_ACTION_BASEADDRESS(act);
169 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS(tok);
171 if ((offset & mask) != ((offset + size - 1) & mask)) {
172 printf("BAR%d: Won't use for Fixed mapping\n",
174 printf("\t<%#llx,%#llx>, action=%d\n",
175 (unsigned long long)offset,
176 (unsigned long long)(offset + size), act);
177 printf("\tBAR too small (0x%llx).\n",
178 (unsigned long long)mask);
184 printf("BAR%d: Created Fixed mapping\n", bar->index);
185 printf("\t%d:%d:%d:0x%#llx-0x%#llx>\n", tgt, act, tok,
186 (unsigned long long)offset,
187 (unsigned long long)(offset + mask));
192 mask = ~(NFP_PCIE_P2C_BULK_SIZE(bar) - 1);
196 NFP_PCIE_BAR_PCIE2CPP_MAPTYPE
197 (NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_BULK);
199 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS(tgt);
200 newcfg |= NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS(tok);
202 if ((offset & mask) != ((offset + size - 1) & mask)) {
203 printf("BAR%d: Won't use for bulk mapping\n",
205 printf("\t<%#llx,%#llx>\n", (unsigned long long)offset,
206 (unsigned long long)(offset + size));
207 printf("\ttarget=%d, token=%d\n", tgt, tok);
208 printf("\tBAR too small (%#llx) - (%#llx != %#llx).\n",
209 (unsigned long long)mask,
210 (unsigned long long)(offset & mask),
211 (unsigned long long)(offset + size - 1) & mask);
219 printf("BAR%d: Created bulk mapping %d:x:%d:%#llx-%#llx\n",
220 bar->index, tgt, tok, (unsigned long long)offset,
221 (unsigned long long)(offset + ~mask));
227 if (bar->bitsize < bitsize) {
228 printf("BAR%d: Too small for %d:%d:%d\n", bar->index, tgt, tok,
233 newcfg |= offset >> bitsize;
239 *bar_config = newcfg;
245 nfp_bar_write(struct nfp_pcie_user *nfp, struct nfp_bar *bar,
250 base = bar->index >> 3;
251 slot = bar->index & 7;
256 bar->csr = nfp->cfg +
257 NFP_PCIE_CFG_BAR_PCIETOCPPEXPBAR(base, slot);
259 *(uint32_t *)(bar->csr) = newcfg;
261 bar->barcfg = newcfg;
263 printf("BAR%d: updated to 0x%08x\n", bar->index, newcfg);
270 nfp_reconfigure_bar(struct nfp_pcie_user *nfp, struct nfp_bar *bar, int tgt,
271 int act, int tok, uint64_t offset, size_t size, int width)
277 err = nfp_compute_bar(bar, &newcfg, &newbase, tgt, act, tok, offset,
284 return nfp_bar_write(nfp, bar, newcfg);
288 * Map all PCI bars. We assume that the BAR with the PCIe config block is
291 * BAR0.0: Reserved for General Mapping (for MSI-X access to PCIe SRAM)
294 nfp_enable_bars(struct nfp_pcie_user *nfp)
299 for (x = ARRAY_SIZE(nfp->bar); x > 0; x--) {
300 bar = &nfp->bar[x - 1];
304 bar->mask = (1 << (nfp->barsz - 3)) - 1;
305 bar->bitsize = nfp->barsz - 3;
309 bar->csr = nfp->cfg +
310 NFP_PCIE_CFG_BAR_PCIETOCPPEXPBAR(bar->index >> 3,
313 (char *)mmap(0, 1 << bar->bitsize, PROT_READ | PROT_WRITE,
314 MAP_SHARED, nfp->device,
315 bar->index << bar->bitsize);
317 if (bar->iomem == MAP_FAILED)
323 static struct nfp_bar *
324 nfp_alloc_bar(struct nfp_pcie_user *nfp)
329 for (x = ARRAY_SIZE(nfp->bar); x > 0; x--) {
330 bar = &nfp->bar[x - 1];
340 nfp_disable_bars(struct nfp_pcie_user *nfp)
345 for (x = ARRAY_SIZE(nfp->bar); x > 0; x--) {
346 bar = &nfp->bar[x - 1];
348 munmap(bar->iomem, 1 << (nfp->barsz - 3));
356 * Generic CPP bus access interface.
359 struct nfp6000_area_priv {
377 nfp6000_area_init(struct nfp_cpp_area *area, uint32_t dest,
378 unsigned long long address, unsigned long size)
380 struct nfp_pcie_user *nfp = nfp_cpp_priv(nfp_cpp_area_cpp(area));
381 struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
382 uint32_t target = NFP_CPP_ID_TARGET_of(dest);
383 uint32_t action = NFP_CPP_ID_ACTION_of(dest);
384 uint32_t token = NFP_CPP_ID_TOKEN_of(dest);
387 pp = nfp6000_target_pushpull(NFP_CPP_ID(target, action, token),
392 priv->width.read = PUSH_WIDTH(pp);
393 priv->width.write = PULL_WIDTH(pp);
395 if (priv->width.read > 0 &&
396 priv->width.write > 0 && priv->width.read != priv->width.write)
399 if (priv->width.read > 0)
400 priv->width.bar = priv->width.read;
402 priv->width.bar = priv->width.write;
404 priv->bar = nfp_alloc_bar(nfp);
405 if (priv->bar == NULL)
408 priv->target = target;
409 priv->action = action;
411 priv->offset = address;
414 ret = nfp_reconfigure_bar(nfp, priv->bar, priv->target, priv->action,
415 priv->token, priv->offset, priv->size,
422 nfp6000_area_acquire(struct nfp_cpp_area *area)
424 struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
426 /* Calculate offset into BAR. */
427 if (nfp_bar_maptype(priv->bar) ==
428 NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_GENERAL) {
429 priv->bar_offset = priv->offset &
430 (NFP_PCIE_P2C_GENERAL_SIZE(priv->bar) - 1);
432 NFP_PCIE_P2C_GENERAL_TARGET_OFFSET(priv->bar,
435 NFP_PCIE_P2C_GENERAL_TOKEN_OFFSET(priv->bar, priv->token);
437 priv->bar_offset = priv->offset & priv->bar->mask;
440 /* Must have been too big. Sub-allocate. */
441 if (!priv->bar->iomem)
444 priv->iomem = priv->bar->iomem + priv->bar_offset;
450 nfp6000_area_mapped(struct nfp_cpp_area *area)
452 struct nfp6000_area_priv *area_priv = nfp_cpp_area_priv(area);
454 if (!area_priv->iomem)
457 return area_priv->iomem;
461 nfp6000_area_release(struct nfp_cpp_area *area)
463 struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
470 nfp6000_area_iomem(struct nfp_cpp_area *area)
472 struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
477 nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr,
478 unsigned long offset, unsigned int length)
480 uint64_t *wrptr64 = kernel_vaddr;
481 const volatile uint64_t *rdptr64;
482 struct nfp6000_area_priv *priv;
483 uint32_t *wrptr32 = kernel_vaddr;
484 const volatile uint32_t *rdptr32;
489 priv = nfp_cpp_area_priv(area);
490 rdptr64 = (uint64_t *)(priv->iomem + offset);
491 rdptr32 = (uint32_t *)(priv->iomem + offset);
493 if (offset + length > priv->size)
496 width = priv->width.read;
501 /* Unaligned? Translate to an explicit access */
502 if ((priv->offset + offset) & (width - 1)) {
503 printf("aread_read unaligned!!!\n");
507 is_64 = width == TARGET_WIDTH_64;
509 /* MU reads via a PCIe2CPP BAR supports 32bit (and other) lengths */
510 if (priv->target == (NFP_CPP_TARGET_ID_MASK & NFP_CPP_TARGET_MU) &&
511 priv->action == NFP_CPP_ACTION_RW) {
516 if (offset % sizeof(uint64_t) != 0 ||
517 length % sizeof(uint64_t) != 0)
520 if (offset % sizeof(uint32_t) != 0 ||
521 length % sizeof(uint32_t) != 0)
529 for (n = 0; n < length; n += sizeof(uint64_t)) {
535 for (n = 0; n < length; n += sizeof(uint32_t)) {
545 nfp6000_area_write(struct nfp_cpp_area *area, const void *kernel_vaddr,
546 unsigned long offset, unsigned int length)
548 const uint64_t *rdptr64 = kernel_vaddr;
550 const uint32_t *rdptr32 = kernel_vaddr;
551 struct nfp6000_area_priv *priv;
557 priv = nfp_cpp_area_priv(area);
558 wrptr64 = (uint64_t *)(priv->iomem + offset);
559 wrptr32 = (uint32_t *)(priv->iomem + offset);
561 if (offset + length > priv->size)
564 width = priv->width.write;
569 /* Unaligned? Translate to an explicit access */
570 if ((priv->offset + offset) & (width - 1))
573 is_64 = width == TARGET_WIDTH_64;
575 /* MU writes via a PCIe2CPP BAR supports 32bit (and other) lengths */
576 if (priv->target == (NFP_CPP_TARGET_ID_MASK & NFP_CPP_TARGET_MU) &&
577 priv->action == NFP_CPP_ACTION_RW)
581 if (offset % sizeof(uint64_t) != 0 ||
582 length % sizeof(uint64_t) != 0)
585 if (offset % sizeof(uint32_t) != 0 ||
586 length % sizeof(uint32_t) != 0)
594 for (n = 0; n < length; n += sizeof(uint64_t)) {
600 for (n = 0; n < length; n += sizeof(uint32_t)) {
609 #define PCI_DEVICES "/sys/bus/pci/devices"
612 nfp_acquire_process_lock(struct nfp_pcie_user *desc)
618 memset(&lock, 0, sizeof(lock));
620 snprintf(lockname, sizeof(lockname), "/var/lock/nfp_%s", desc->busdev);
621 desc->lock = open(lockname, O_RDWR | O_CREAT, 0666);
625 lock.l_type = F_WRLCK;
626 lock.l_whence = SEEK_SET;
629 rc = fcntl(desc->lock, F_SETLKW, &lock);
631 if (errno != EAGAIN && errno != EACCES) {
642 nfp6000_set_model(struct nfp_pcie_user *desc, struct nfp_cpp *cpp)
648 snprintf(tmp_str, sizeof(tmp_str), "%s/%s/config", PCI_DEVICES,
651 fp = open(tmp_str, O_RDONLY);
655 lseek(fp, 0x2e, SEEK_SET);
657 if (read(fp, &tmp, sizeof(tmp)) != sizeof(tmp)) {
658 printf("Error reading config file for model\n");
667 nfp_cpp_model_set(cpp, tmp);
673 nfp6000_set_interface(struct nfp_pcie_user *desc, struct nfp_cpp *cpp)
679 snprintf(tmp_str, sizeof(tmp_str), "%s/%s/config", PCI_DEVICES,
682 fp = open(tmp_str, O_RDONLY);
686 lseek(fp, 0x154, SEEK_SET);
688 if (read(fp, &tmp, sizeof(tmp)) != sizeof(tmp)) {
689 printf("error reading config file for interface\n");
696 nfp_cpp_interface_set(cpp, tmp);
701 #define PCI_CFG_SPACE_SIZE 256
702 #define PCI_CFG_SPACE_EXP_SIZE 4096
703 #define PCI_EXT_CAP_ID(header) (int)(header & 0x0000ffff)
704 #define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc)
705 #define PCI_EXT_CAP_ID_DSN 0x03
707 nfp_pci_find_next_ext_capability(int fp, int cap)
711 int pos = PCI_CFG_SPACE_SIZE;
713 /* minimum 8 bytes per capability */
714 ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
716 lseek(fp, pos, SEEK_SET);
717 if (read(fp, &header, sizeof(header)) != sizeof(header)) {
718 printf("error reading config file for serial\n");
723 * If we have no capabilities, this is indicated by cap ID,
724 * cap version and next pointer all being 0.
730 if (PCI_EXT_CAP_ID(header) == cap)
733 pos = PCI_EXT_CAP_NEXT(header);
734 if (pos < PCI_CFG_SPACE_SIZE)
737 lseek(fp, pos, SEEK_SET);
738 if (read(fp, &header, sizeof(header)) != sizeof(header)) {
739 printf("error reading config file for serial\n");
748 nfp6000_set_serial(struct nfp_pcie_user *desc, struct nfp_cpp *cpp)
756 snprintf(tmp_str, sizeof(tmp_str), "%s/%s/config", PCI_DEVICES,
759 fp = open(tmp_str, O_RDONLY);
763 pos = nfp_pci_find_next_ext_capability(fp, PCI_EXT_CAP_ID_DSN);
765 printf("PCI_EXT_CAP_ID_DSN not found. Using default offset\n");
766 lseek(fp, 0x156, SEEK_SET);
768 lseek(fp, pos + 6, SEEK_SET);
771 if (read(fp, &tmp, sizeof(tmp)) != sizeof(tmp)) {
772 printf("error reading config file for serial\n");
776 serial[4] = (uint8_t)((tmp >> 8) & 0xff);
777 serial[5] = (uint8_t)(tmp & 0xff);
779 if (read(fp, &tmp, sizeof(tmp)) != sizeof(tmp)) {
780 printf("error reading config file for serial\n");
784 serial[2] = (uint8_t)((tmp >> 8) & 0xff);
785 serial[3] = (uint8_t)(tmp & 0xff);
787 if (read(fp, &tmp, sizeof(tmp)) != sizeof(tmp)) {
788 printf("error reading config file for serial\n");
792 serial[0] = (uint8_t)((tmp >> 8) & 0xff);
793 serial[1] = (uint8_t)(tmp & 0xff);
798 nfp_cpp_serial_set(cpp, serial, serial_len);
804 nfp6000_set_barsz(struct nfp_pcie_user *desc)
807 unsigned long start, end, flags, tmp;
811 snprintf(tmp_str, sizeof(tmp_str), "%s/%s/resource", PCI_DEVICES,
814 fp = fopen(tmp_str, "r");
818 if (fscanf(fp, "0x%lx 0x%lx 0x%lx", &start, &end, &flags) == 0) {
819 printf("error reading resource file for bar size\n");
824 if (fclose(fp) == -1)
827 tmp = (end - start) + 1;
836 nfp6000_init(struct nfp_cpp *cpp, const char *devname)
843 struct nfp_pcie_user *desc;
845 desc = malloc(sizeof(*desc));
850 memset(desc->busdev, 0, BUSDEV_SZ);
851 strlcpy(desc->busdev, devname, sizeof(desc->busdev));
853 ret = nfp_acquire_process_lock(desc);
857 snprintf(tmp_str, sizeof(tmp_str), "%s/%s/driver", PCI_DEVICES,
860 size = readlink(tmp_str, link, sizeof(link));
865 if (size == sizeof(link))
868 snprintf(tmp_str, sizeof(tmp_str), "%s/%s/resource0", PCI_DEVICES,
871 desc->device = open(tmp_str, O_RDWR);
872 if (desc->device == -1)
875 if (nfp6000_set_model(desc, cpp) < 0)
877 if (nfp6000_set_interface(desc, cpp) < 0)
879 if (nfp6000_set_serial(desc, cpp) < 0)
881 if (nfp6000_set_barsz(desc) < 0)
884 desc->cfg = (char *)mmap(0, 1 << (desc->barsz - 3),
885 PROT_READ | PROT_WRITE,
886 MAP_SHARED, desc->device, 0);
888 if (desc->cfg == MAP_FAILED)
891 nfp_enable_bars(desc);
893 nfp_cpp_priv_set(cpp, desc);
895 model = __nfp_cpp_model_autodetect(cpp);
896 nfp_cpp_model_set(cpp, model);
902 nfp6000_free(struct nfp_cpp *cpp)
904 struct nfp_pcie_user *desc = nfp_cpp_priv(cpp);
907 /* Unmap may cause if there are any pending transaxctions */
908 nfp_disable_bars(desc);
909 munmap(desc->cfg, 1 << (desc->barsz - 3));
911 for (x = ARRAY_SIZE(desc->bar); x > 0; x--) {
912 if (desc->bar[x - 1].iomem)
913 munmap(desc->bar[x - 1].iomem, 1 << (desc->barsz - 3));
920 static const struct nfp_cpp_operations nfp6000_pcie_ops = {
921 .init = nfp6000_init,
922 .free = nfp6000_free,
924 .area_priv_size = sizeof(struct nfp6000_area_priv),
925 .area_init = nfp6000_area_init,
926 .area_acquire = nfp6000_area_acquire,
927 .area_release = nfp6000_area_release,
928 .area_mapped = nfp6000_area_mapped,
929 .area_read = nfp6000_area_read,
930 .area_write = nfp6000_area_write,
931 .area_iomem = nfp6000_area_iomem,
935 nfp_cpp_operations *nfp_cpp_transport_operations(void)
937 return &nfp6000_pcie_ops;