net/nfp: support multiprocess

This patch introduces changes for supporting multiprocess support.
This is trivial for VFs but comes with some limitations for the PF.

Due to restrictions when using NFP CPP interface, just one secondary
process is supported by now for the PF.

Signed-off-by: Alejandro Lucero <alejandro.lucero@netronome.com>
This commit is contained in:
Alejandro Lucero 2018-12-11 12:01:59 +00:00 committed by Ferruh Yigit
parent 8d49699534
commit ef28aa96e5
5 changed files with 189 additions and 61 deletions

View File

@ -24,5 +24,6 @@ Basic stats = Y
Stats per queue = Y Stats per queue = Y
Linux UIO = Y Linux UIO = Y
Linux VFIO = Y Linux VFIO = Y
Multiprocess aware = Y
x86-64 = Y x86-64 = Y
Usage doc = Y Usage doc = Y

View File

@ -24,5 +24,6 @@ Basic stats = Y
Stats per queue = Y Stats per queue = Y
Linux UIO = Y Linux UIO = Y
Linux VFIO = Y Linux VFIO = Y
Multiprocess aware = Y
x86-64 = Y x86-64 = Y
Usage doc = Y Usage doc = Y

View File

@ -145,6 +145,18 @@ is no support for RX interrupts and it is not possible either to use those PF
ports with the device hotplug functionality. ports with the device hotplug functionality.
PF multiprocess support
-----------------------
Due to how the driver needs to access the NFP through a CPP interface, which implies
to use specific registers inside the chip, the number of secondary proceses with PF
ports is limitted to only one.
This limitation will be solved in future versions but having basic multiprocess support
is important for allowing development and debugging through the PF using a secondary
process which will create a CPP bridge for user space tools accessing the NFP.
System configuration System configuration
-------------------- --------------------

View File

@ -766,9 +766,12 @@ nfp_net_start(struct rte_eth_dev *dev)
goto error; goto error;
} }
if (hw->is_pf) if (hw->is_pf && rte_eal_process_type() == RTE_PROC_PRIMARY)
/* Configure the physical port up */ /* Configure the physical port up */
nfp_eth_set_configured(hw->cpp, hw->pf_port_idx, 1); nfp_eth_set_configured(hw->cpp, hw->pf_port_idx, 1);
else
nfp_eth_set_configured(dev->process_private,
hw->pf_port_idx, 1);
hw->ctrl = new_ctrl; hw->ctrl = new_ctrl;
@ -817,9 +820,12 @@ nfp_net_stop(struct rte_eth_dev *dev)
(struct nfp_net_rxq *)dev->data->rx_queues[i]); (struct nfp_net_rxq *)dev->data->rx_queues[i]);
} }
if (hw->is_pf) if (hw->is_pf && rte_eal_process_type() == RTE_PROC_PRIMARY)
/* Configure the physical port down */ /* Configure the physical port down */
nfp_eth_set_configured(hw->cpp, hw->pf_port_idx, 0); nfp_eth_set_configured(hw->cpp, hw->pf_port_idx, 0);
else
nfp_eth_set_configured(dev->process_private,
hw->pf_port_idx, 0);
} }
/* Reset and stop device. The device can not be restarted. */ /* Reset and stop device. The device can not be restarted. */
@ -2918,16 +2924,16 @@ nfp_net_init(struct rte_eth_dev *eth_dev)
hw->mac_addr[0], hw->mac_addr[1], hw->mac_addr[2], hw->mac_addr[0], hw->mac_addr[1], hw->mac_addr[2],
hw->mac_addr[3], hw->mac_addr[4], hw->mac_addr[5]); hw->mac_addr[3], hw->mac_addr[4], hw->mac_addr[5]);
/* Registering LSC interrupt handler */ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
rte_intr_callback_register(&pci_dev->intr_handle, /* Registering LSC interrupt handler */
nfp_net_dev_interrupt_handler, rte_intr_callback_register(&pci_dev->intr_handle,
(void *)eth_dev); nfp_net_dev_interrupt_handler,
(void *)eth_dev);
/* Telling the firmware about the LSC interrupt entry */ /* Telling the firmware about the LSC interrupt entry */
nn_cfg_writeb(hw, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX); nn_cfg_writeb(hw, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX);
/* Recording current stats counters values */
/* Recording current stats counters values */ nfp_net_stats_reset(eth_dev);
nfp_net_stats_reset(eth_dev); }
return 0; return 0;
@ -2947,7 +2953,7 @@ nfp_pf_create_dev(struct rte_pci_device *dev, int port, int ports,
struct rte_eth_dev *eth_dev; struct rte_eth_dev *eth_dev;
struct nfp_net_hw *hw; struct nfp_net_hw *hw;
char *port_name; char *port_name;
int ret; int retval;
port_name = rte_zmalloc("nfp_pf_port_name", 100, 0); port_name = rte_zmalloc("nfp_pf_port_name", 100, 0);
if (!port_name) if (!port_name)
@ -2958,51 +2964,76 @@ nfp_pf_create_dev(struct rte_pci_device *dev, int port, int ports,
else else
sprintf(port_name, "%s", dev->device.name); sprintf(port_name, "%s", dev->device.name);
eth_dev = rte_eth_dev_allocate(port_name);
if (!eth_dev)
return -ENOMEM;
if (port == 0) { if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
*priv = rte_zmalloc(port_name, eth_dev = rte_eth_dev_allocate(port_name);
sizeof(struct nfp_net_adapter) * ports, if (!eth_dev) {
RTE_CACHE_LINE_SIZE); rte_free(port_name);
if (!*priv) { return -ENODEV;
rte_eth_dev_release_port(eth_dev);
return -ENOMEM;
} }
if (port == 0) {
*priv = rte_zmalloc(port_name,
sizeof(struct nfp_net_adapter) *
ports, RTE_CACHE_LINE_SIZE);
if (!*priv) {
rte_free(port_name);
rte_eth_dev_release_port(eth_dev);
return -ENOMEM;
}
}
eth_dev->data->dev_private = *priv;
/*
* dev_private pointing to port0 dev_private because we need
* to configure vNIC bars based on port0 at nfp_net_init.
* Then dev_private is adjusted per port.
*/
hw = (struct nfp_net_hw *)(eth_dev->data->dev_private) + port;
hw->cpp = cpp;
hw->hwinfo = hwinfo;
hw->sym_tbl = sym_tbl;
hw->pf_port_idx = phys_port;
hw->is_pf = 1;
if (ports > 1)
hw->pf_multiport_enabled = 1;
hw->total_ports = ports;
} else {
eth_dev = rte_eth_dev_attach_secondary(port_name);
if (!eth_dev) {
RTE_LOG(ERR, EAL, "secondary process attach failed, "
"ethdev doesn't exist");
rte_free(port_name);
return -ENODEV;
}
eth_dev->process_private = cpp;
} }
eth_dev->data->dev_private = *priv;
/*
* dev_private pointing to port0 dev_private because we need
* to configure vNIC bars based on port0 at nfp_net_init.
* Then dev_private is adjusted per port.
*/
hw = (struct nfp_net_hw *)(eth_dev->data->dev_private) + port;
hw->cpp = cpp;
hw->hwinfo = hwinfo;
hw->sym_tbl = sym_tbl;
hw->pf_port_idx = phys_port;
hw->is_pf = 1;
if (ports > 1)
hw->pf_multiport_enabled = 1;
hw->total_ports = ports;
eth_dev->device = &dev->device; eth_dev->device = &dev->device;
rte_eth_copy_pci_info(eth_dev, dev); rte_eth_copy_pci_info(eth_dev, dev);
ret = nfp_net_init(eth_dev); retval = nfp_net_init(eth_dev);
if (ret) if (retval) {
rte_eth_dev_release_port(eth_dev); retval = -ENODEV;
else goto probe_failed;
} else {
rte_eth_dev_probing_finish(eth_dev); rte_eth_dev_probing_finish(eth_dev);
}
rte_free(port_name); rte_free(port_name);
return ret; return retval;
probe_failed:
rte_free(port_name);
/* free ports private data if primary process */
if (rte_eal_process_type() == RTE_PROC_PRIMARY)
rte_free(eth_dev->data->dev_private);
rte_eth_dev_release_port(eth_dev);
return retval;
} }
#define DEFAULT_FW_PATH "/lib/firmware/netronome" #define DEFAULT_FW_PATH "/lib/firmware/netronome"
@ -3180,10 +3211,12 @@ static int nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
return -EIO; return -EIO;
} }
if (nfp_fw_setup(dev, cpp, nfp_eth_table, hwinfo)) { if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
PMD_DRV_LOG(INFO, "Error when uploading firmware"); if (nfp_fw_setup(dev, cpp, nfp_eth_table, hwinfo)) {
ret = -EIO; PMD_DRV_LOG(INFO, "Error when uploading firmware");
goto error; ret = -EIO;
goto error;
}
} }
/* Now the symbol table should be there */ /* Now the symbol table should be there */

View File

@ -112,6 +112,7 @@ struct nfp_pcie_user {
int device; int device;
int lock; int lock;
int secondary_lock;
char busdev[BUSDEV_SZ]; char busdev[BUSDEV_SZ];
int barsz; int barsz;
char *cfg; char *cfg;
@ -290,14 +291,32 @@ nfp_reconfigure_bar(struct nfp_pcie_user *nfp, struct nfp_bar *bar, int tgt,
* already mapped. * already mapped.
* *
* BAR0.0: Reserved for General Mapping (for MSI-X access to PCIe SRAM) * 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 static int
nfp_enable_bars(struct nfp_pcie_user *nfp) nfp_enable_bars(struct nfp_pcie_user *nfp)
{ {
struct nfp_bar *bar; 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 = &nfp->bar[x - 1];
bar->barcfg = 0; bar->barcfg = 0;
bar->nfp = nfp; bar->nfp = nfp;
@ -320,9 +339,16 @@ static struct nfp_bar *
nfp_alloc_bar(struct nfp_pcie_user *nfp) nfp_alloc_bar(struct nfp_pcie_user *nfp)
{ {
struct nfp_bar *bar; 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 = &nfp->bar[x - 1];
if (!bar->lock) { if (!bar->lock) {
bar->lock = 1; bar->lock = 1;
@ -336,9 +362,17 @@ static void
nfp_disable_bars(struct nfp_pcie_user *nfp) nfp_disable_bars(struct nfp_pcie_user *nfp)
{ {
struct nfp_bar *bar; 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 = &nfp->bar[x - 1];
if (bar->iomem) { if (bar->iomem) {
bar->iomem = NULL; bar->iomem = NULL;
@ -633,6 +667,47 @@ nfp_acquire_process_lock(struct nfp_pcie_user *desc)
return 0; return 0;
} }
static int
nfp_acquire_secondary_process_lock(struct nfp_pcie_user *desc)
{
int rc;
struct flock lock;
const char *lockname = "/.lock_nfp_secondary";
char *home_path;
char *lockfile;
memset(&lock, 0, sizeof(lock));
/*
* 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));
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");
return desc->secondary_lock;
}
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 rc;
}
static int static int
nfp6000_set_model(struct rte_pci_device *dev, struct nfp_cpp *cpp) nfp6000_set_model(struct rte_pci_device *dev, struct nfp_cpp *cpp)
{ {
@ -774,7 +849,6 @@ static int
nfp6000_init(struct nfp_cpp *cpp, struct rte_pci_device *dev) nfp6000_init(struct nfp_cpp *cpp, struct rte_pci_device *dev)
{ {
int ret = 0; int ret = 0;
uint32_t model;
struct nfp_pcie_user *desc; struct nfp_pcie_user *desc;
desc = malloc(sizeof(*desc)); desc = malloc(sizeof(*desc));
@ -785,12 +859,20 @@ nfp6000_init(struct nfp_cpp *cpp, struct rte_pci_device *dev)
memset(desc->busdev, 0, BUSDEV_SZ); memset(desc->busdev, 0, BUSDEV_SZ);
strlcpy(desc->busdev, dev->device.name, sizeof(desc->busdev)); strlcpy(desc->busdev, dev->device.name, sizeof(desc->busdev));
if (cpp->driver_lock_needed) { if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
cpp->driver_lock_needed) {
ret = nfp_acquire_process_lock(desc); ret = nfp_acquire_process_lock(desc);
if (ret) if (ret)
return -1; 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)
return -1;
}
if (nfp6000_set_model(dev, cpp) < 0) if (nfp6000_set_model(dev, cpp) < 0)
return -1; return -1;
if (nfp6000_set_interface(dev, cpp) < 0) if (nfp6000_set_interface(dev, cpp) < 0)
@ -806,9 +888,6 @@ nfp6000_init(struct nfp_cpp *cpp, struct rte_pci_device *dev)
nfp_cpp_priv_set(cpp, desc); nfp_cpp_priv_set(cpp, desc);
model = __nfp_cpp_model_autodetect(cpp);
nfp_cpp_model_set(cpp, model);
return ret; return ret;
} }
@ -820,6 +899,8 @@ nfp6000_free(struct nfp_cpp *cpp)
nfp_disable_bars(desc); nfp_disable_bars(desc);
if (cpp->driver_lock_needed) if (cpp->driver_lock_needed)
close(desc->lock); close(desc->lock);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
close(desc->secondary_lock);
close(desc->device); close(desc->device);
free(desc); free(desc);
} }