#include <assert.h>
#include <stdio.h>
+#if defined(RTE_BACKTRACE)
#include <execinfo.h>
+#endif
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/file.h>
#include <sys/stat.h>
+#include <ethdev_pci.h>
#include <rte_string_fns.h>
#include "nfp_cpp.h"
int device;
int lock;
+ int secondary_lock;
char busdev[BUSDEV_SZ];
int barsz;
char *cfg;
* already mapped.
*
* BAR0.0: Reserved for General Mapping (for MSI-X access to PCIe SRAM)
+ *
+ * Halving PCItoCPPBars for primary and secondary processes.
+ * NFP PMD just requires two fixed slots, one for configuration BAR,
+ * and another for accessing the hw queues. Another slot is needed
+ * for setting the link up or down. Secondary processes do not need
+ * to map the first two slots again, but it requires one slot for
+ * accessing the link, even if it is not likely the secondary process
+ * starting the port. This implies a limit of secondary processes
+ * supported. Due to this requirement and future extensions requiring
+ * new slots per process, only one secondary process is supported by
+ * now.
*/
static int
nfp_enable_bars(struct nfp_pcie_user *nfp)
{
struct nfp_bar *bar;
- int x;
+ int x, start, end;
- for (x = ARRAY_SIZE(nfp->bar); x > 0; x--) {
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+ start = 4;
+ end = 1;
+ } else {
+ start = 7;
+ end = 4;
+ }
+ for (x = start; x > end; x--) {
bar = &nfp->bar[x - 1];
bar->barcfg = 0;
bar->nfp = nfp;
bar->csr = nfp->cfg +
NFP_PCIE_CFG_BAR_PCIETOCPPEXPBAR(bar->index >> 3,
bar->index & 7);
- bar->iomem =
- (char *)mmap(0, 1 << bar->bitsize, PROT_READ | PROT_WRITE,
- MAP_SHARED, nfp->device,
- bar->index << bar->bitsize);
- if (bar->iomem == MAP_FAILED)
- return (-ENOMEM);
+ bar->iomem = nfp->cfg + (bar->index << bar->bitsize);
}
return 0;
}
nfp_alloc_bar(struct nfp_pcie_user *nfp)
{
struct nfp_bar *bar;
- int x;
+ int x, start, end;
- for (x = ARRAY_SIZE(nfp->bar); x > 0; x--) {
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+ start = 4;
+ end = 1;
+ } else {
+ start = 7;
+ end = 4;
+ }
+ for (x = start; x > end; x--) {
bar = &nfp->bar[x - 1];
if (!bar->lock) {
bar->lock = 1;
nfp_disable_bars(struct nfp_pcie_user *nfp)
{
struct nfp_bar *bar;
- int x;
+ int x, start, end;
- for (x = ARRAY_SIZE(nfp->bar); x > 0; x--) {
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+ start = 4;
+ end = 1;
+ } else {
+ start = 7;
+ end = 4;
+ }
+
+ for (x = start; x > end; x--) {
bar = &nfp->bar[x - 1];
if (bar->iomem) {
- munmap(bar->iomem, 1 << (nfp->barsz - 3));
bar->iomem = NULL;
bar->lock = 0;
}
}
static int
-nfp6000_set_model(struct nfp_pcie_user *desc, struct nfp_cpp *cpp)
+nfp_acquire_secondary_process_lock(struct nfp_pcie_user *desc)
{
- char tmp_str[80];
- uint32_t tmp;
- int fp;
+ int rc;
+ struct flock lock;
+ const char *lockname = "/.lock_nfp_secondary";
+ char *home_path;
+ char *lockfile;
- snprintf(tmp_str, sizeof(tmp_str), "%s/%s/config", PCI_DEVICES,
- desc->busdev);
+ memset(&lock, 0, sizeof(lock));
- fp = open(tmp_str, O_RDONLY);
- if (!fp)
- return -1;
+ /*
+ * Using user's home directory. Note this can be called in a DPDK app
+ * being executed as non-root. This is not the case for the previous
+ * function nfp_acquire_process_lock which is invoked only when UIO
+ * driver is used because that implies root user.
+ */
+ home_path = getenv("HOME");
+ lockfile = calloc(strlen(home_path) + strlen(lockname) + 1,
+ sizeof(char));
- lseek(fp, 0x2e, SEEK_SET);
+ if (!lockfile)
+ return -ENOMEM;
- if (read(fp, &tmp, sizeof(tmp)) != sizeof(tmp)) {
- printf("Error reading config file for model\n");
- return -1;
+ strcat(lockfile, home_path);
+ strcat(lockfile, "/.lock_nfp_secondary");
+ desc->secondary_lock = open(lockfile, O_RDWR | O_CREAT | O_NONBLOCK,
+ 0666);
+ if (desc->secondary_lock < 0) {
+ RTE_LOG(ERR, PMD, "NFP lock for secondary process failed\n");
+ free(lockfile);
+ return desc->secondary_lock;
}
- tmp = tmp << 16;
-
- if (close(fp) == -1)
- return -1;
-
- nfp_cpp_model_set(cpp, tmp);
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ rc = fcntl(desc->secondary_lock, F_SETLK, &lock);
+ if (rc < 0) {
+ RTE_LOG(ERR, PMD, "NFP lock for secondary process failed\n");
+ close(desc->secondary_lock);
+ }
- return 0;
+ free(lockfile);
+ return rc;
}
static int
-nfp6000_set_interface(struct nfp_pcie_user *desc, struct nfp_cpp *cpp)
+nfp6000_set_model(struct rte_pci_device *dev, struct nfp_cpp *cpp)
{
- char tmp_str[80];
- uint16_t tmp;
- int fp;
-
- snprintf(tmp_str, sizeof(tmp_str), "%s/%s/config", PCI_DEVICES,
- desc->busdev);
-
- fp = open(tmp_str, O_RDONLY);
- if (!fp)
- return -1;
-
- lseek(fp, 0x154, SEEK_SET);
+ uint32_t model;
- if (read(fp, &tmp, sizeof(tmp)) != sizeof(tmp)) {
- printf("error reading config file for interface\n");
+ if (rte_pci_read_config(dev, &model, 4, 0x2e) < 0) {
+ printf("nfp set model failed\n");
return -1;
}
- if (close(fp) == -1)
- return -1;
-
- nfp_cpp_interface_set(cpp, tmp);
+ model = model << 16;
+ nfp_cpp_model_set(cpp, model);
return 0;
}
-#define PCI_CFG_SPACE_SIZE 256
-#define PCI_CFG_SPACE_EXP_SIZE 4096
-#define PCI_EXT_CAP_ID(header) (int)(header & 0x0000ffff)
-#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc)
-#define PCI_EXT_CAP_ID_DSN 0x03
static int
-nfp_pci_find_next_ext_capability(int fp, int cap)
+nfp6000_set_interface(struct rte_pci_device *dev, struct nfp_cpp *cpp)
{
- uint32_t header;
- int ttl;
- int pos = PCI_CFG_SPACE_SIZE;
+ uint16_t interface;
- /* minimum 8 bytes per capability */
- ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
-
- lseek(fp, pos, SEEK_SET);
- if (read(fp, &header, sizeof(header)) != sizeof(header)) {
- printf("error reading config file for serial\n");
+ if (rte_pci_read_config(dev, &interface, 2, 0x154) < 0) {
+ printf("nfp set interface failed\n");
return -1;
}
- /*
- * If we have no capabilities, this is indicated by cap ID,
- * cap version and next pointer all being 0.
- */
- if (header == 0)
- return 0;
-
- while (ttl-- > 0) {
- if (PCI_EXT_CAP_ID(header) == cap)
- return pos;
-
- pos = PCI_EXT_CAP_NEXT(header);
- if (pos < PCI_CFG_SPACE_SIZE)
- break;
-
- lseek(fp, pos, SEEK_SET);
- if (read(fp, &header, sizeof(header)) != sizeof(header)) {
- printf("error reading config file for serial\n");
- return -1;
- }
- }
+ nfp_cpp_interface_set(cpp, interface);
return 0;
}
static int
-nfp6000_set_serial(struct nfp_pcie_user *desc, struct nfp_cpp *cpp)
+nfp6000_set_serial(struct rte_pci_device *dev, struct nfp_cpp *cpp)
{
- char tmp_str[80];
uint16_t tmp;
uint8_t serial[6];
int serial_len = 6;
- int fp, pos;
-
- snprintf(tmp_str, sizeof(tmp_str), "%s/%s/config", PCI_DEVICES,
- desc->busdev);
-
- fp = open(tmp_str, O_RDONLY);
- if (!fp)
- return -1;
+ off_t pos;
- pos = nfp_pci_find_next_ext_capability(fp, PCI_EXT_CAP_ID_DSN);
+ pos = rte_pci_find_ext_capability(dev, RTE_PCI_EXT_CAP_ID_DSN);
if (pos <= 0) {
- printf("PCI_EXT_CAP_ID_DSN not found. Using default offset\n");
- lseek(fp, 0x156, SEEK_SET);
+ printf("PCI_EXT_CAP_ID_DSN not found. nfp set serial failed\n");
+ return -1;
} else {
- lseek(fp, pos + 6, SEEK_SET);
+ pos += 6;
}
- if (read(fp, &tmp, sizeof(tmp)) != sizeof(tmp)) {
- printf("error reading config file for serial\n");
+ if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
+ printf("nfp set serial failed\n");
return -1;
}
serial[4] = (uint8_t)((tmp >> 8) & 0xff);
serial[5] = (uint8_t)(tmp & 0xff);
- if (read(fp, &tmp, sizeof(tmp)) != sizeof(tmp)) {
- printf("error reading config file for serial\n");
+ pos += 2;
+ if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
+ printf("nfp set serial failed\n");
return -1;
}
serial[2] = (uint8_t)((tmp >> 8) & 0xff);
serial[3] = (uint8_t)(tmp & 0xff);
- if (read(fp, &tmp, sizeof(tmp)) != sizeof(tmp)) {
- printf("error reading config file for serial\n");
+ pos += 2;
+ if (rte_pci_read_config(dev, &tmp, 2, pos) < 0) {
+ printf("nfp set serial failed\n");
return -1;
}
serial[0] = (uint8_t)((tmp >> 8) & 0xff);
serial[1] = (uint8_t)(tmp & 0xff);
- if (close(fp) == -1)
- return -1;
-
nfp_cpp_serial_set(cpp, serial, serial_len);
return 0;
}
static int
-nfp6000_set_barsz(struct nfp_pcie_user *desc)
+nfp6000_set_barsz(struct rte_pci_device *dev, struct nfp_pcie_user *desc)
{
- char tmp_str[80];
- unsigned long start, end, flags, tmp;
- int i;
- FILE *fp;
+ unsigned long tmp;
+ int i = 0;
- snprintf(tmp_str, sizeof(tmp_str), "%s/%s/resource", PCI_DEVICES,
- desc->busdev);
-
- fp = fopen(tmp_str, "r");
- if (!fp)
- return -1;
+ tmp = dev->mem_resource[0].len;
- if (fscanf(fp, "0x%lx 0x%lx 0x%lx", &start, &end, &flags) == 0) {
- printf("error reading resource file for bar size\n");
- fclose(fp);
- return -1;
- }
-
- if (fclose(fp) == -1)
- return -1;
-
- tmp = (end - start) + 1;
- i = 0;
while (tmp >>= 1)
i++;
+
desc->barsz = i;
return 0;
}
static int
-nfp6000_init(struct nfp_cpp *cpp, const char *devname)
+nfp6000_init(struct nfp_cpp *cpp, struct rte_pci_device *dev)
{
- char link[120];
- char tmp_str[80];
- ssize_t size;
int ret = 0;
- uint32_t model;
struct nfp_pcie_user *desc;
desc = malloc(sizeof(*desc));
memset(desc->busdev, 0, BUSDEV_SZ);
- strlcpy(desc->busdev, devname, sizeof(desc->busdev));
-
- ret = nfp_acquire_process_lock(desc);
- if (ret)
- return -1;
+ strlcpy(desc->busdev, dev->device.name, sizeof(desc->busdev));
- snprintf(tmp_str, sizeof(tmp_str), "%s/%s/driver", PCI_DEVICES,
- desc->busdev);
-
- size = readlink(tmp_str, link, sizeof(link));
-
- if (size == -1)
- tmp_str[0] = '\0';
-
- if (size == sizeof(link))
- tmp_str[0] = '\0';
-
- snprintf(tmp_str, sizeof(tmp_str), "%s/%s/resource0", PCI_DEVICES,
- desc->busdev);
-
- desc->device = open(tmp_str, O_RDWR);
- if (desc->device == -1)
- return -1;
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
+ cpp->driver_lock_needed) {
+ ret = nfp_acquire_process_lock(desc);
+ if (ret)
+ goto error;
+ }
- if (nfp6000_set_model(desc, cpp) < 0)
- return -1;
- if (nfp6000_set_interface(desc, cpp) < 0)
- return -1;
- if (nfp6000_set_serial(desc, cpp) < 0)
- return -1;
- if (nfp6000_set_barsz(desc) < 0)
- return -1;
+ /* Just support for one secondary process */
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+ ret = nfp_acquire_secondary_process_lock(desc);
+ if (ret)
+ goto error;
+ }
- desc->cfg = (char *)mmap(0, 1 << (desc->barsz - 3),
- PROT_READ | PROT_WRITE,
- MAP_SHARED, desc->device, 0);
+ if (nfp6000_set_model(dev, cpp) < 0)
+ goto error;
+ if (nfp6000_set_interface(dev, cpp) < 0)
+ goto error;
+ if (nfp6000_set_serial(dev, cpp) < 0)
+ goto error;
+ if (nfp6000_set_barsz(dev, desc) < 0)
+ goto error;
- if (desc->cfg == MAP_FAILED)
- return -1;
+ desc->cfg = (char *)dev->mem_resource[0].addr;
nfp_enable_bars(desc);
nfp_cpp_priv_set(cpp, desc);
- model = __nfp_cpp_model_autodetect(cpp);
- nfp_cpp_model_set(cpp, model);
+ return 0;
- return ret;
+error:
+ free(desc);
+ return -1;
}
static void
nfp6000_free(struct nfp_cpp *cpp)
{
struct nfp_pcie_user *desc = nfp_cpp_priv(cpp);
- int x;
- /* Unmap may cause if there are any pending transaxctions */
nfp_disable_bars(desc);
- munmap(desc->cfg, 1 << (desc->barsz - 3));
-
- for (x = ARRAY_SIZE(desc->bar); x > 0; x--) {
- if (desc->bar[x - 1].iomem)
- munmap(desc->bar[x - 1].iomem, 1 << (desc->barsz - 3));
- }
- close(desc->lock);
+ if (cpp->driver_lock_needed)
+ close(desc->lock);
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ close(desc->secondary_lock);
close(desc->device);
free(desc);
}