#include <rte_spinlock.h>
#include <rte_service_component.h>
+#include "eal_firmware.h"
+
#include "nfpcore/nfp_cpp.h"
#include "nfpcore/nfp_nffw.h"
#include "nfpcore/nfp_hwinfo.h"
static int nfp_net_infos_get(struct rte_eth_dev *dev,
struct rte_eth_dev_info *dev_info);
static int nfp_net_init(struct rte_eth_dev *eth_dev);
-static int nfp_pf_init(struct rte_eth_dev *eth_dev);
+static int nfp_pf_init(struct rte_pci_device *pci_dev);
+static int nfp_pf_secondary_init(struct rte_pci_device *pci_dev);
static int nfp_pci_uninit(struct rte_eth_dev *eth_dev);
static int nfp_init_phyports(struct nfp_pf_dev *pf_dev);
static int nfp_net_link_update(struct rte_eth_dev *dev, int wait_to_complete);
static int nfp_set_mac_addr(struct rte_eth_dev *dev,
struct rte_ether_addr *mac_addr);
static int32_t nfp_cpp_bridge_service_func(void *args);
+static void nfp_register_cpp_service(struct nfp_cpp *cpp);
static int nfp_fw_setup(struct rte_pci_device *dev,
struct nfp_cpp *cpp,
struct nfp_eth_table *nfp_eth_table,
if (hw->is_phyport) {
if (rte_eal_process_type() == RTE_PROC_PRIMARY)
/* Configure the physical port up */
- nfp_eth_set_configured(hw->cpp, hw->idx, 1);
+ nfp_eth_set_configured(hw->cpp, hw->nfp_idx, 1);
else
nfp_eth_set_configured(dev->process_private,
- hw->idx, 1);
+ hw->nfp_idx, 1);
}
hw->ctrl = new_ctrl;
if (hw->is_phyport) {
if (rte_eal_process_type() == RTE_PROC_PRIMARY)
/* Configure the physical port down */
- nfp_eth_set_configured(hw->cpp, hw->idx, 0);
+ nfp_eth_set_configured(hw->cpp, hw->nfp_idx, 0);
else
nfp_eth_set_configured(dev->process_private,
- hw->idx, 0);
+ hw->nfp_idx, 0);
}
return 0;
if (rte_eal_process_type() == RTE_PROC_PRIMARY)
/* Configure the physical port down */
- return nfp_eth_set_configured(hw->cpp, hw->idx, 1);
+ return nfp_eth_set_configured(hw->cpp, hw->nfp_idx, 1);
else
return nfp_eth_set_configured(dev->process_private,
- hw->idx, 1);
+ hw->nfp_idx, 1);
}
/* Set the link down. */
if (rte_eal_process_type() == RTE_PROC_PRIMARY)
/* Configure the physical port down */
- return nfp_eth_set_configured(hw->cpp, hw->idx, 0);
+ return nfp_eth_set_configured(hw->cpp, hw->nfp_idx, 0);
else
return nfp_eth_set_configured(dev->process_private,
- hw->idx, 0);
+ hw->nfp_idx, 0);
}
/* Reset and stop device. The device can not be restarted. */
return -ENODEV;
}
- /* This points to the specific port private data */
- PMD_INIT_LOG(DEBUG, "Working with physical port number %d",
- port);
-
/* Use PF array of physical ports to get pointer to
* this specific port
*/
hw = pf_dev->ports[port];
+ PMD_INIT_LOG(DEBUG, "Working with physical port number: %d, "
+ "NFP internal port number: %d",
+ port, hw->nfp_idx);
+
} else {
hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
}
nfp_fw_upload(struct rte_pci_device *dev, struct nfp_nsp *nsp, char *card)
{
struct nfp_cpp *cpp = nsp->cpp;
- int fw_f;
- char *fw_buf;
+ void *fw_buf;
char fw_name[125];
char serial[40];
- struct stat file_stat;
- off_t fsize, bytes;
+ size_t fsize;
/* Looking for firmware file in order of priority */
snprintf(fw_name, sizeof(fw_name), "%s/%s.nffw", DEFAULT_FW_PATH,
serial);
-
PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name);
- fw_f = open(fw_name, O_RDONLY);
- if (fw_f >= 0)
- goto read_fw;
+ if (rte_firmware_read(fw_name, &fw_buf, &fsize) == 0)
+ goto load_fw;
/* Then try the PCI name */
snprintf(fw_name, sizeof(fw_name), "%s/pci-%s.nffw", DEFAULT_FW_PATH,
dev->device.name);
-
PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name);
- fw_f = open(fw_name, O_RDONLY);
- if (fw_f >= 0)
- goto read_fw;
+ if (rte_firmware_read(fw_name, &fw_buf, &fsize) == 0)
+ goto load_fw;
/* Finally try the card type and media */
snprintf(fw_name, sizeof(fw_name), "%s/%s", DEFAULT_FW_PATH, card);
PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name);
- fw_f = open(fw_name, O_RDONLY);
- if (fw_f < 0) {
+ if (rte_firmware_read(fw_name, &fw_buf, &fsize) < 0) {
PMD_DRV_LOG(INFO, "Firmware file %s not found.", fw_name);
return -ENOENT;
}
-read_fw:
- if (fstat(fw_f, &file_stat) < 0) {
- PMD_DRV_LOG(INFO, "Firmware file %s size is unknown", fw_name);
- close(fw_f);
- return -ENOENT;
- }
-
- fsize = file_stat.st_size;
- PMD_DRV_LOG(INFO, "Firmware file found at %s with size: %" PRIu64 "",
- fw_name, (uint64_t)fsize);
-
- fw_buf = malloc((size_t)fsize);
- if (!fw_buf) {
- PMD_DRV_LOG(INFO, "malloc failed for fw buffer");
- close(fw_f);
- return -ENOMEM;
- }
- memset(fw_buf, 0, fsize);
-
- bytes = read(fw_f, fw_buf, fsize);
- if (bytes != fsize) {
- PMD_DRV_LOG(INFO, "Reading fw to buffer failed."
- "Just %" PRIu64 " of %" PRIu64 " bytes read",
- (uint64_t)bytes, (uint64_t)fsize);
- free(fw_buf);
- close(fw_f);
- return -EIO;
- }
+load_fw:
+ PMD_DRV_LOG(INFO, "Firmware file found at %s with size: %zu",
+ fw_name, fsize);
PMD_DRV_LOG(INFO, "Uploading the firmware ...");
- nfp_nsp_load_fw(nsp, fw_buf, bytes);
+ nfp_nsp_load_fw(nsp, fw_buf, fsize);
PMD_DRV_LOG(INFO, "Done");
free(fw_buf);
- close(fw_f);
-
return 0;
}
{
struct nfp_net_hw *hw;
struct rte_eth_dev *eth_dev;
+ struct nfp_eth_table *nfp_eth_table = NULL;
int ret = 0;
int i;
+ nfp_eth_table = nfp_eth_read_ports(pf_dev->cpp);
+ if (!nfp_eth_table) {
+ PMD_INIT_LOG(ERR, "Error reading NFP ethernet table");
+ ret = -EIO;
+ goto error;
+ }
+
/* Loop through all physical ports on PF */
for (i = 0; i < pf_dev->total_phyports; i++) {
const unsigned int numa_node = rte_socket_id();
snprintf(port_name, sizeof(port_name), "%s_port%d",
pf_dev->pci_dev->device.name, i);
- if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
- eth_dev = rte_eth_dev_attach_secondary(port_name);
- if (!eth_dev) {
- RTE_LOG(ERR, EAL,
- "secondary process attach failed, "
- "ethdev doesn't exist");
- ret = -ENODEV;
- goto error;
- }
-
- eth_dev->process_private = pf_dev->cpp;
- goto nfp_net_init;
- }
-
- /* First port has already been initialized */
- if (i == 0) {
- eth_dev = pf_dev->eth_dev;
- goto skip_dev_alloc;
- }
-
- /* Allocate a eth_dev for remaining ports */
+ /* Allocate a eth_dev for this phyport */
eth_dev = rte_eth_dev_allocate(port_name);
if (!eth_dev) {
ret = -ENODEV;
goto port_cleanup;
}
- /* Allocate memory for remaining ports */
+ /* Allocate memory for this phyport */
eth_dev->data->dev_private =
rte_zmalloc_socket(port_name, sizeof(struct nfp_net_hw),
RTE_CACHE_LINE_SIZE, numa_node);
goto port_cleanup;
}
-skip_dev_alloc:
hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
/* Add this device to the PF's array of physical ports */
hw->cpp = pf_dev->cpp;
hw->eth_dev = eth_dev;
hw->idx = i;
+ hw->nfp_idx = nfp_eth_table->ports[i].index;
hw->is_phyport = true;
-nfp_net_init:
eth_dev->device = &pf_dev->pci_dev->device;
/* ctrl/tx/rx BAR mappings and remaining init happens in
rte_eth_dev_probing_finish(eth_dev);
} /* End loop, all ports on this PF */
- return 0;
+ ret = 0;
+ goto eth_table_cleanup;
port_cleanup:
for (i = 0; i < pf_dev->total_phyports; i++) {
pf_dev->ports[i] = NULL;
}
}
+eth_table_cleanup:
+ free(nfp_eth_table);
error:
return ret;
}
-static int nfp_pf_init(struct rte_eth_dev *eth_dev)
+static void nfp_register_cpp_service(struct nfp_cpp *cpp)
+{
+ uint32_t *cpp_service_id = NULL;
+ struct rte_service_spec service;
+
+ memset(&service, 0, sizeof(struct rte_service_spec));
+ snprintf(service.name, sizeof(service.name), "nfp_cpp_service");
+ service.callback = nfp_cpp_bridge_service_func;
+ service.callback_userdata = (void *)cpp;
+
+ if (rte_service_component_register(&service,
+ cpp_service_id))
+ RTE_LOG(WARNING, PMD, "NFP CPP bridge service register() failed");
+ else
+ RTE_LOG(DEBUG, PMD, "NFP CPP bridge service registered");
+}
+
+static int nfp_pf_init(struct rte_pci_device *pci_dev)
{
- struct rte_pci_device *pci_dev;
- struct nfp_net_hw *hw = NULL;
struct nfp_pf_dev *pf_dev = NULL;
struct nfp_cpp *cpp;
struct nfp_hwinfo *hwinfo;
struct nfp_rtsym_table *sym_tbl;
struct nfp_eth_table *nfp_eth_table = NULL;
- struct rte_service_spec service;
char name[RTE_ETH_NAME_MAX_LEN];
int total_ports;
int ret = -ENODEV;
int err;
- pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
- hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev);
-
if (!pci_dev)
return ret;
goto hwinfo_cleanup;
}
- if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
- if (nfp_fw_setup(pci_dev, cpp, nfp_eth_table, hwinfo)) {
- PMD_INIT_LOG(ERR, "Error when uploading firmware");
- ret = -EIO;
- goto eth_table_cleanup;
- }
+ if (nfp_fw_setup(pci_dev, cpp, nfp_eth_table, hwinfo)) {
+ PMD_INIT_LOG(ERR, "Error when uploading firmware");
+ ret = -EIO;
+ goto eth_table_cleanup;
}
/* Now the symbol table should be there */
goto sym_tbl_cleanup;
}
/* Allocate memory for the PF "device" */
- snprintf(name, sizeof(name), "nfp_pf%d", eth_dev->data->port_id);
+ snprintf(name, sizeof(name), "nfp_pf%d", 0);
pf_dev = rte_zmalloc(name, sizeof(*pf_dev), 0);
if (!pf_dev) {
ret = -ENOMEM;
pf_dev->pci_dev = pci_dev;
- /* The first eth_dev is part of the PF struct */
- pf_dev->eth_dev = eth_dev;
-
/* Map the symbol table */
pf_dev->ctrl_bar = nfp_rtsym_map(pf_dev->sym_tbl, "_pf0_net_bar0",
pf_dev->total_phyports * 32768,
goto hwqueues_cleanup;
}
- /*
- * The rte_service needs to be created just once per PMD.
- * And the cpp handler needs to be linked to the service.
- * Secondary processes will be used for debugging DPDK apps
- * when requiring to use the CPP interface for accessing NFP
- * components. And the cpp handler for secondary processes is
- * available at this point.
- */
- memset(&service, 0, sizeof(struct rte_service_spec));
- snprintf(service.name, sizeof(service.name), "nfp_cpp_service");
- service.callback = nfp_cpp_bridge_service_func;
- service.callback_userdata = (void *)cpp;
-
- if (rte_service_component_register(&service,
- &hw->nfp_cpp_service_id))
- RTE_LOG(ERR, PMD, "NFP CPP bridge service register() failed");
- else
- RTE_LOG(DEBUG, PMD, "NFP CPP bridge service registered");
+ /* register the CPP bridge service here for primary use */
+ nfp_register_cpp_service(pf_dev->cpp);
return 0;
return ret;
}
+/*
+ * When attaching to the NFP4000/6000 PF on a secondary process there
+ * is no need to initialize the PF again. Only minimal work is required
+ * here
+ */
+static int nfp_pf_secondary_init(struct rte_pci_device *pci_dev)
+{
+ struct nfp_cpp *cpp;
+ struct nfp_rtsym_table *sym_tbl;
+ int total_ports;
+ int i;
+ int err;
+
+ if (!pci_dev)
+ return -ENODEV;
+
+ /*
+ * When device bound to UIO, the device could be used, by mistake,
+ * by two DPDK apps, and the UIO driver does not avoid it. This
+ * could lead to a serious problem when configuring the NFP CPP
+ * interface. Here we avoid this telling to the CPP init code to
+ * use a lock file if UIO is being used.
+ */
+ if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO)
+ cpp = nfp_cpp_from_device_name(pci_dev, 0);
+ else
+ cpp = nfp_cpp_from_device_name(pci_dev, 1);
+
+ if (!cpp) {
+ PMD_INIT_LOG(ERR, "A CPP handle can not be obtained");
+ return -EIO;
+ }
+
+ /*
+ * We don't have access to the PF created in the primary process
+ * here so we have to read the number of ports from firmware
+ */
+ sym_tbl = nfp_rtsym_table_read(cpp);
+ if (!sym_tbl) {
+ PMD_INIT_LOG(ERR, "Something is wrong with the firmware"
+ " symbol table");
+ return -EIO;
+ }
+
+ total_ports = nfp_rtsym_read_le(sym_tbl, "nfd_cfg_pf0_num_ports", &err);
+
+ for (i = 0; i < total_ports; i++) {
+ struct rte_eth_dev *eth_dev;
+ char port_name[RTE_ETH_NAME_MAX_LEN];
+
+ snprintf(port_name, sizeof(port_name), "%s_port%d",
+ pci_dev->device.name, i);
+
+ PMD_DRV_LOG(DEBUG, "Secondary attaching to port %s",
+ port_name);
+ eth_dev = rte_eth_dev_attach_secondary(port_name);
+ if (!eth_dev) {
+ RTE_LOG(ERR, EAL,
+ "secondary process attach failed, "
+ "ethdev doesn't exist");
+ return -ENODEV;
+ }
+ eth_dev->process_private = cpp;
+ eth_dev->dev_ops = &nfp_net_eth_dev_ops;
+ eth_dev->rx_queue_count = nfp_net_rx_queue_count;
+ eth_dev->rx_pkt_burst = &nfp_net_recv_pkts;
+ eth_dev->tx_pkt_burst = &nfp_net_xmit_pkts;
+ rte_eth_dev_probing_finish(eth_dev);
+ }
+
+ /* Register the CPP bridge service for the secondary too */
+ nfp_register_cpp_service(cpp);
+
+ return 0;
+}
+
static int nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
struct rte_pci_device *dev)
{
- return rte_eth_dev_pci_generic_probe(dev,
- sizeof(struct nfp_net_hw), nfp_pf_init);
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+ return nfp_pf_init(dev);
+ else
+ return nfp_pf_secondary_init(dev);
}
static const struct rte_pci_id pci_id_nfp_pf_net_map[] = {