+ snprintf(name, sizeof(name), "%s port %u",
+ mlx4_glue->get_device_name(ibv_dev), port);
+ if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
+ eth_dev = rte_eth_dev_attach_secondary(name);
+ if (eth_dev == NULL) {
+ ERROR("can not attach rte ethdev");
+ rte_errno = ENOMEM;
+ err = rte_errno;
+ goto err_secondary;
+ }
+ priv = eth_dev->data->dev_private;
+ if (!priv->verbs_alloc_ctx.enabled) {
+ ERROR("secondary process is not supported"
+ " due to lack of external allocator"
+ " from Verbs");
+ rte_errno = ENOTSUP;
+ err = rte_errno;
+ goto err_secondary;
+ }
+ eth_dev->device = &pci_dev->device;
+ eth_dev->dev_ops = &mlx4_dev_sec_ops;
+ err = mlx4_proc_priv_init(eth_dev);
+ if (err)
+ goto err_secondary;
+ /* Receive command fd from primary process. */
+ err = mlx4_mp_req_verbs_cmd_fd(eth_dev);
+ if (err < 0) {
+ err = rte_errno;
+ goto err_secondary;
+ }
+ /* Remap UAR for Tx queues. */
+ err = mlx4_tx_uar_init_secondary(eth_dev, err);
+ if (err) {
+ err = rte_errno;
+ goto err_secondary;
+ }
+ /*
+ * Ethdev pointer is still required as input since
+ * the primary device is not accessible from the
+ * secondary process.
+ */
+ eth_dev->tx_pkt_burst = mlx4_tx_burst;
+ eth_dev->rx_pkt_burst = mlx4_rx_burst;
+ claim_zero(mlx4_glue->close_device(ctx));
+ rte_eth_copy_pci_info(eth_dev, pci_dev);
+ rte_eth_dev_probing_finish(eth_dev);
+ prev_dev = eth_dev;
+ continue;
+err_secondary:
+ claim_zero(mlx4_glue->close_device(ctx));
+ rte_eth_dev_release_port(eth_dev);
+ if (prev_dev)
+ rte_eth_dev_release_port(prev_dev);
+ break;
+ }