X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fsfc%2Fsfc_ethdev.c;h=2f5f86f84877457b61fea9462ff634812c0b639e;hb=8999f8f679418cbb41637731f934e18f00cab3bd;hp=010641b9195feb749e54e85ac369738b7fff8863;hpb=638bddc99faafd3d91fbbd5703467233e28da29b;p=dpdk.git diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c index 010641b919..2f5f86f848 100644 --- a/drivers/net/sfc/sfc_ethdev.c +++ b/drivers/net/sfc/sfc_ethdev.c @@ -31,7 +31,9 @@ #include #include +#include #include +#include #include #include "efx.h" @@ -106,7 +108,7 @@ sfc_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) sfc_log_init(sa, "entry"); - dev_info->pci_dev = RTE_DEV_TO_PCI(dev->device); + dev_info->pci_dev = RTE_ETH_DEV_TO_PCI(dev); dev_info->max_rx_pktlen = EFX_MAC_PDU_MAX; /* Autonegotiation may be disabled */ @@ -135,15 +137,25 @@ sfc_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) DEV_TX_OFFLOAD_TCP_CKSUM; dev_info->default_txconf.txq_flags = ETH_TXQ_FLAGS_NOXSUMSCTP; - if (!encp->enc_hw_tx_insert_vlan_enabled) + if ((~sa->dp_tx->features & SFC_DP_TX_FEAT_VLAN_INSERT) || + !encp->enc_hw_tx_insert_vlan_enabled) dev_info->default_txconf.txq_flags |= ETH_TXQ_FLAGS_NOVLANOFFL; else dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_VLAN_INSERT; + if (~sa->dp_tx->features & SFC_DP_TX_FEAT_MULTI_SEG) + dev_info->default_txconf.txq_flags |= ETH_TXQ_FLAGS_NOMULTSEGS; + + if (~sa->dp_tx->features & SFC_DP_TX_FEAT_MULTI_POOL) + dev_info->default_txconf.txq_flags |= ETH_TXQ_FLAGS_NOMULTMEMP; + + if (~sa->dp_tx->features & SFC_DP_TX_FEAT_REFCNT) + dev_info->default_txconf.txq_flags |= ETH_TXQ_FLAGS_NOREFCOUNT; + #if EFSYS_OPT_RX_SCALE if (sa->rss_support != EFX_RX_SCALE_UNAVAILABLE) { dev_info->reta_size = EFX_RSS_TBL_SIZE; - dev_info->hash_key_size = SFC_RSS_KEY_SIZE; + dev_info->hash_key_size = EFX_RSS_KEY_SIZE; dev_info->flow_type_rss_offloads = SFC_RSS_OFFLOADS; } #endif @@ -188,8 +200,6 @@ sfc_dev_configure(struct rte_eth_dev *dev) sfc_adapter_lock(sa); switch (sa->state) { case SFC_ADAPTER_CONFIGURED: - sfc_close(sa); - SFC_ASSERT(sa->state == SFC_ADAPTER_INITIALIZED); /* FALLTHROUGH */ case SFC_ADAPTER_INITIALIZED: rc = sfc_configure(sa); @@ -358,8 +368,13 @@ sfc_dev_filter_set(struct rte_eth_dev *dev, enum sfc_dev_filter_mode mode, if (*toggle != enabled) { *toggle = enabled; - if ((sa->state == SFC_ADAPTER_STARTED) && - (sfc_set_rx_mode(sa) != 0)) { + if (port->isolated) { + sfc_warn(sa, "isolated mode is active on the port"); + sfc_warn(sa, "the change is to be applied on the next " + "start provided that isolated mode is " + "disabled prior the next start"); + } else if ((sa->state == SFC_ADAPTER_STARTED) && + (sfc_set_rx_mode(sa) != 0)) { *toggle = !(enabled); sfc_warn(sa, "Failed to %s %s mode", ((enabled) ? "enable" : "disable"), desc); @@ -467,7 +482,7 @@ sfc_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id, if (rc != 0) goto fail_tx_qinit; - dev->data->tx_queues[tx_queue_id] = sa->txq_info[tx_queue_id].txq; + dev->data->tx_queues[tx_queue_id] = sa->txq_info[tx_queue_id].txq->dp; sfc_adapter_unlock(sa); return 0; @@ -481,13 +496,15 @@ fail_tx_qinit: static void sfc_tx_queue_release(void *queue) { - struct sfc_txq *txq = queue; + struct sfc_dp_txq *dp_txq = queue; + struct sfc_txq *txq; unsigned int sw_index; struct sfc_adapter *sa; - if (txq == NULL) + if (dp_txq == NULL) return; + txq = sfc_txq_by_dp_txq(dp_txq); sw_index = sfc_txq_sw_index(txq); SFC_ASSERT(txq->evq != NULL); @@ -505,16 +522,18 @@ sfc_tx_queue_release(void *queue) sfc_adapter_unlock(sa); } -static void +static int sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) { struct sfc_adapter *sa = dev->data->dev_private; struct sfc_port *port = &sa->port; uint64_t *mac_stats; + int ret; rte_spinlock_lock(&port->mac_stats_lock); - if (sfc_port_update_mac_stats(sa) != 0) + ret = sfc_port_update_mac_stats(sa); + if (ret != 0) goto unlock; mac_stats = port->mac_stats_buf; @@ -571,6 +590,8 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) unlock: rte_spinlock_unlock(&port->mac_stats_lock); + SFC_ASSERT(ret >= 0); + return -ret; } static void @@ -655,6 +676,85 @@ sfc_xstats_get_names(struct rte_eth_dev *dev, return nstats; } +static int +sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids, + uint64_t *values, unsigned int n) +{ + struct sfc_adapter *sa = dev->data->dev_private; + struct sfc_port *port = &sa->port; + uint64_t *mac_stats; + unsigned int nb_supported = 0; + unsigned int nb_written = 0; + unsigned int i; + int ret; + int rc; + + if (unlikely(values == NULL) || + unlikely((ids == NULL) && (n < port->mac_stats_nb_supported))) + return port->mac_stats_nb_supported; + + rte_spinlock_lock(&port->mac_stats_lock); + + rc = sfc_port_update_mac_stats(sa); + if (rc != 0) { + SFC_ASSERT(rc > 0); + ret = -rc; + goto unlock; + } + + mac_stats = port->mac_stats_buf; + + for (i = 0; (i < EFX_MAC_NSTATS) && (nb_written < n); ++i) { + if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) + continue; + + if ((ids == NULL) || (ids[nb_written] == nb_supported)) + values[nb_written++] = mac_stats[i]; + + ++nb_supported; + } + + ret = nb_written; + +unlock: + rte_spinlock_unlock(&port->mac_stats_lock); + + return ret; +} + +static int +sfc_xstats_get_names_by_id(struct rte_eth_dev *dev, + struct rte_eth_xstat_name *xstats_names, + const uint64_t *ids, unsigned int size) +{ + struct sfc_adapter *sa = dev->data->dev_private; + struct sfc_port *port = &sa->port; + unsigned int nb_supported = 0; + unsigned int nb_written = 0; + unsigned int i; + + if (unlikely(xstats_names == NULL) || + unlikely((ids == NULL) && (size < port->mac_stats_nb_supported))) + return port->mac_stats_nb_supported; + + for (i = 0; (i < EFX_MAC_NSTATS) && (nb_written < size); ++i) { + if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) + continue; + + if ((ids == NULL) || (ids[nb_written] == nb_supported)) { + char *name = xstats_names[nb_written++].name; + + strncpy(name, efx_mac_stat_name(sa->nic, i), + sizeof(xstats_names[0].name)); + name[sizeof(xstats_names[0].name) - 1] = '\0'; + } + + ++nb_supported; + } + + return nb_written; +} + static int sfc_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) { @@ -821,10 +921,17 @@ sfc_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr) { struct sfc_adapter *sa = dev->data->dev_private; const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic); + struct sfc_port *port = &sa->port; int rc; sfc_adapter_lock(sa); + if (port->isolated) { + sfc_err(sa, "isolated mode is active on the port"); + sfc_err(sa, "will not set MAC address"); + goto unlock; + } + if (sa->state != SFC_ADAPTER_STARTED) { sfc_info(sa, "the port is not started"); sfc_info(sa, "the new MAC address will be set on port start"); @@ -879,6 +986,12 @@ sfc_set_mc_addr_list(struct rte_eth_dev *dev, struct ether_addr *mc_addr_set, int rc; unsigned int i; + if (port->isolated) { + sfc_err(sa, "isolated mode is active on the port"); + sfc_err(sa, "will not set multicast address list"); + return -ENOTSUP; + } + if (mc_addrs == NULL) return -ENOBUFS; @@ -889,7 +1002,7 @@ sfc_set_mc_addr_list(struct rte_eth_dev *dev, struct ether_addr *mc_addr_set, } for (i = 0; i < nb_mc_addr; ++i) { - (void)rte_memcpy(mc_addrs, mc_addr_set[i].addr_bytes, + rte_memcpy(mc_addrs, mc_addr_set[i].addr_bytes, EFX_MAC_ADDR_LEN); mc_addrs += EFX_MAC_ADDR_LEN; } @@ -908,6 +1021,10 @@ sfc_set_mc_addr_list(struct rte_eth_dev *dev, struct ether_addr *mc_addr_set, return -rc; } +/* + * The function is used by the secondary process as well. It must not + * use any process-local pointers from the adapter data. + */ static void sfc_rx_queue_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id, struct rte_eth_rxq_info *qinfo) @@ -934,6 +1051,10 @@ sfc_rx_queue_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id, sfc_adapter_unlock(sa); } +/* + * The function is used by the secondary process as well. It must not + * use any process-local pointers from the adapter data. + */ static void sfc_tx_queue_info_get(struct rte_eth_dev *dev, uint16_t tx_queue_id, struct rte_eth_txq_info *qinfo) @@ -976,6 +1097,24 @@ sfc_rx_descriptor_done(void *queue, uint16_t offset) return sfc_rx_qdesc_done(dp_rxq, offset); } +static int +sfc_rx_descriptor_status(void *queue, uint16_t offset) +{ + struct sfc_dp_rxq *dp_rxq = queue; + struct sfc_rxq *rxq = sfc_rxq_by_dp_rxq(dp_rxq); + + return rxq->evq->sa->dp_rx->qdesc_status(dp_rxq, offset); +} + +static int +sfc_tx_descriptor_status(void *queue, uint16_t offset) +{ + struct sfc_dp_txq *dp_txq = queue; + struct sfc_txq *txq = sfc_txq_by_dp_txq(dp_txq); + + return txq->evq->sa->dp_tx->qdesc_status(dp_txq, offset); +} + static int sfc_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queue_id) { @@ -1078,11 +1217,14 @@ sfc_dev_rss_hash_conf_get(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf) { struct sfc_adapter *sa = dev->data->dev_private; + struct sfc_port *port = &sa->port; - if ((sa->rss_channels == 1) || - (sa->rss_support != EFX_RX_SCALE_EXCLUSIVE)) + if ((sa->rss_support != EFX_RX_SCALE_EXCLUSIVE) || port->isolated) return -ENOTSUP; + if (sa->rss_channels == 0) + return -EINVAL; + sfc_adapter_lock(sa); /* @@ -1092,9 +1234,9 @@ sfc_dev_rss_hash_conf_get(struct rte_eth_dev *dev, * locally in 'sfc_adapter' and kept up-to-date */ rss_conf->rss_hf = sfc_efx_to_rte_hash_type(sa->rss_hash_types); - rss_conf->rss_key_len = SFC_RSS_KEY_SIZE; + rss_conf->rss_key_len = EFX_RSS_KEY_SIZE; if (rss_conf->rss_key != NULL) - rte_memcpy(rss_conf->rss_key, sa->rss_key, SFC_RSS_KEY_SIZE); + rte_memcpy(rss_conf->rss_key, sa->rss_key, EFX_RSS_KEY_SIZE); sfc_adapter_unlock(sa); @@ -1106,15 +1248,23 @@ sfc_dev_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf) { struct sfc_adapter *sa = dev->data->dev_private; + struct sfc_port *port = &sa->port; unsigned int efx_hash_types; int rc = 0; - if ((sa->rss_channels == 1) || - (sa->rss_support != EFX_RX_SCALE_EXCLUSIVE)) { + if (port->isolated) + return -ENOTSUP; + + if (sa->rss_support != EFX_RX_SCALE_EXCLUSIVE) { sfc_err(sa, "RSS is not available"); return -ENOTSUP; } + if (sa->rss_channels == 0) { + sfc_err(sa, "RSS is not configured"); + return -EINVAL; + } + if ((rss_conf->rss_key != NULL) && (rss_conf->rss_key_len != sizeof(sa->rss_key))) { sfc_err(sa, "RSS key size is wrong (should be %lu)", @@ -1131,14 +1281,17 @@ sfc_dev_rss_hash_update(struct rte_eth_dev *dev, efx_hash_types = sfc_rte_to_efx_hash_type(rss_conf->rss_hf); - rc = efx_rx_scale_mode_set(sa->nic, EFX_RX_HASHALG_TOEPLITZ, + rc = efx_rx_scale_mode_set(sa->nic, EFX_RSS_CONTEXT_DEFAULT, + EFX_RX_HASHALG_TOEPLITZ, efx_hash_types, B_TRUE); if (rc != 0) goto fail_scale_mode_set; if (rss_conf->rss_key != NULL) { if (sa->state == SFC_ADAPTER_STARTED) { - rc = efx_rx_scale_key_set(sa->nic, rss_conf->rss_key, + rc = efx_rx_scale_key_set(sa->nic, + EFX_RSS_CONTEXT_DEFAULT, + rss_conf->rss_key, sizeof(sa->rss_key)); if (rc != 0) goto fail_scale_key_set; @@ -1154,7 +1307,8 @@ sfc_dev_rss_hash_update(struct rte_eth_dev *dev, return 0; fail_scale_key_set: - if (efx_rx_scale_mode_set(sa->nic, EFX_RX_HASHALG_TOEPLITZ, + if (efx_rx_scale_mode_set(sa->nic, EFX_RSS_CONTEXT_DEFAULT, + EFX_RX_HASHALG_TOEPLITZ, sa->rss_hash_types, B_TRUE) != 0) sfc_err(sa, "failed to restore RSS mode"); @@ -1169,12 +1323,15 @@ sfc_dev_rss_reta_query(struct rte_eth_dev *dev, uint16_t reta_size) { struct sfc_adapter *sa = dev->data->dev_private; + struct sfc_port *port = &sa->port; int entry; - if ((sa->rss_channels == 1) || - (sa->rss_support != EFX_RX_SCALE_EXCLUSIVE)) + if ((sa->rss_support != EFX_RX_SCALE_EXCLUSIVE) || port->isolated) return -ENOTSUP; + if (sa->rss_channels == 0) + return -EINVAL; + if (reta_size != EFX_RSS_TBL_SIZE) return -EINVAL; @@ -1199,17 +1356,25 @@ sfc_dev_rss_reta_update(struct rte_eth_dev *dev, uint16_t reta_size) { struct sfc_adapter *sa = dev->data->dev_private; + struct sfc_port *port = &sa->port; unsigned int *rss_tbl_new; uint16_t entry; - int rc; + int rc = 0; - if ((sa->rss_channels == 1) || - (sa->rss_support != EFX_RX_SCALE_EXCLUSIVE)) { + if (port->isolated) + return -ENOTSUP; + + if (sa->rss_support != EFX_RX_SCALE_EXCLUSIVE) { sfc_err(sa, "RSS is not available"); return -ENOTSUP; } + if (sa->rss_channels == 0) { + sfc_err(sa, "RSS is not configured"); + return -EINVAL; + } + if (reta_size != EFX_RSS_TBL_SIZE) { sfc_err(sa, "RETA size is wrong (should be %u)", EFX_RSS_TBL_SIZE); @@ -1239,10 +1404,16 @@ sfc_dev_rss_reta_update(struct rte_eth_dev *dev, } } - rc = efx_rx_scale_tbl_set(sa->nic, rss_tbl_new, EFX_RSS_TBL_SIZE); - if (rc == 0) - rte_memcpy(sa->rss_tbl, rss_tbl_new, sizeof(sa->rss_tbl)); + if (sa->state == SFC_ADAPTER_STARTED) { + rc = efx_rx_scale_tbl_set(sa->nic, EFX_RSS_CONTEXT_DEFAULT, + rss_tbl_new, EFX_RSS_TBL_SIZE); + if (rc != 0) + goto fail_scale_tbl_set; + } + + rte_memcpy(sa->rss_tbl, rss_tbl_new, sizeof(sa->rss_tbl)); +fail_scale_tbl_set: bad_reta_entry: sfc_adapter_unlock(sa); @@ -1337,6 +1508,8 @@ static const struct eth_dev_ops sfc_eth_dev_ops = { .rx_queue_release = sfc_rx_queue_release, .rx_queue_count = sfc_rx_queue_count, .rx_descriptor_done = sfc_rx_descriptor_done, + .rx_descriptor_status = sfc_rx_descriptor_status, + .tx_descriptor_status = sfc_tx_descriptor_status, .tx_queue_setup = sfc_tx_queue_setup, .tx_queue_release = sfc_tx_queue_release, .flow_ctrl_get = sfc_flow_ctrl_get, @@ -1353,19 +1526,42 @@ static const struct eth_dev_ops sfc_eth_dev_ops = { .rxq_info_get = sfc_rx_queue_info_get, .txq_info_get = sfc_tx_queue_info_get, .fw_version_get = sfc_fw_version_get, + .xstats_get_by_id = sfc_xstats_get_by_id, + .xstats_get_names_by_id = sfc_xstats_get_names_by_id, }; +/** + * Duplicate a string in potentially shared memory required for + * multi-process support. + * + * strdup() allocates from process-local heap/memory. + */ +static char * +sfc_strdup(const char *str) +{ + size_t size; + char *copy; + + if (str == NULL) + return NULL; + + size = strlen(str) + 1; + copy = rte_malloc(__func__, size, 0); + if (copy != NULL) + rte_memcpy(copy, str, size); + + return copy; +} + static int sfc_eth_dev_set_ops(struct rte_eth_dev *dev) { struct sfc_adapter *sa = dev->data->dev_private; unsigned int avail_caps = 0; const char *rx_name = NULL; + const char *tx_name = NULL; int rc; - if (sa == NULL || sa->state == SFC_ADAPTER_UNINITIALIZED) - return -E_RTE_SECONDARY; - switch (sa->family) { case EFX_FAMILY_HUNTINGTON: case EFX_FAMILY_MEDFORD: @@ -1392,7 +1588,7 @@ sfc_eth_dev_set_ops(struct rte_eth_dev *dev) "Insufficient Hw/FW capabilities to use Rx datapath %s", rx_name); rc = EINVAL; - goto fail_dp_rx; + goto fail_dp_rx_caps; } } else { sa->dp_rx = sfc_dp_find_rx_by_caps(&sfc_dp_head, avail_caps); @@ -1404,21 +1600,160 @@ sfc_eth_dev_set_ops(struct rte_eth_dev *dev) } } - sfc_info(sa, "use %s Rx datapath", sa->dp_rx->dp.name); + sa->dp_rx_name = sfc_strdup(sa->dp_rx->dp.name); + if (sa->dp_rx_name == NULL) { + rc = ENOMEM; + goto fail_dp_rx_name; + } + + sfc_info(sa, "use %s Rx datapath", sa->dp_rx_name); dev->rx_pkt_burst = sa->dp_rx->pkt_burst; - dev->tx_pkt_burst = sfc_xmit_pkts; + rc = sfc_kvargs_process(sa, SFC_KVARG_TX_DATAPATH, + sfc_kvarg_string_handler, &tx_name); + if (rc != 0) + goto fail_kvarg_tx_datapath; + + if (tx_name != NULL) { + sa->dp_tx = sfc_dp_find_tx_by_name(&sfc_dp_head, tx_name); + if (sa->dp_tx == NULL) { + sfc_err(sa, "Tx datapath %s not found", tx_name); + rc = ENOENT; + goto fail_dp_tx; + } + if (!sfc_dp_match_hw_fw_caps(&sa->dp_tx->dp, avail_caps)) { + sfc_err(sa, + "Insufficient Hw/FW capabilities to use Tx datapath %s", + tx_name); + rc = EINVAL; + goto fail_dp_tx_caps; + } + } else { + sa->dp_tx = sfc_dp_find_tx_by_caps(&sfc_dp_head, avail_caps); + if (sa->dp_tx == NULL) { + sfc_err(sa, "Tx datapath by caps %#x not found", + avail_caps); + rc = ENOENT; + goto fail_dp_tx; + } + } + + sa->dp_tx_name = sfc_strdup(sa->dp_tx->dp.name); + if (sa->dp_tx_name == NULL) { + rc = ENOMEM; + goto fail_dp_tx_name; + } + + sfc_info(sa, "use %s Tx datapath", sa->dp_tx_name); + + dev->tx_pkt_burst = sa->dp_tx->pkt_burst; dev->dev_ops = &sfc_eth_dev_ops; return 0; +fail_dp_tx_name: +fail_dp_tx_caps: + sa->dp_tx = NULL; + +fail_dp_tx: +fail_kvarg_tx_datapath: + rte_free(sa->dp_rx_name); + sa->dp_rx_name = NULL; + +fail_dp_rx_name: +fail_dp_rx_caps: + sa->dp_rx = NULL; + fail_dp_rx: fail_kvarg_rx_datapath: return rc; } +static void +sfc_eth_dev_clear_ops(struct rte_eth_dev *dev) +{ + struct sfc_adapter *sa = dev->data->dev_private; + + dev->dev_ops = NULL; + dev->rx_pkt_burst = NULL; + dev->tx_pkt_burst = NULL; + + rte_free(sa->dp_tx_name); + sa->dp_tx_name = NULL; + sa->dp_tx = NULL; + + rte_free(sa->dp_rx_name); + sa->dp_rx_name = NULL; + sa->dp_rx = NULL; +} + +static const struct eth_dev_ops sfc_eth_dev_secondary_ops = { + .rxq_info_get = sfc_rx_queue_info_get, + .txq_info_get = sfc_tx_queue_info_get, +}; + +static int +sfc_eth_dev_secondary_set_ops(struct rte_eth_dev *dev) +{ + /* + * Device private data has really many process-local pointers. + * Below code should be extremely careful to use data located + * in shared memory only. + */ + struct sfc_adapter *sa = dev->data->dev_private; + const struct sfc_dp_rx *dp_rx; + const struct sfc_dp_tx *dp_tx; + int rc; + + dp_rx = sfc_dp_find_rx_by_name(&sfc_dp_head, sa->dp_rx_name); + if (dp_rx == NULL) { + sfc_err(sa, "cannot find %s Rx datapath", sa->dp_tx_name); + rc = ENOENT; + goto fail_dp_rx; + } + if (~dp_rx->features & SFC_DP_RX_FEAT_MULTI_PROCESS) { + sfc_err(sa, "%s Rx datapath does not support multi-process", + sa->dp_tx_name); + rc = EINVAL; + goto fail_dp_rx_multi_process; + } + + dp_tx = sfc_dp_find_tx_by_name(&sfc_dp_head, sa->dp_tx_name); + if (dp_tx == NULL) { + sfc_err(sa, "cannot find %s Tx datapath", sa->dp_tx_name); + rc = ENOENT; + goto fail_dp_tx; + } + if (~dp_tx->features & SFC_DP_TX_FEAT_MULTI_PROCESS) { + sfc_err(sa, "%s Tx datapath does not support multi-process", + sa->dp_tx_name); + rc = EINVAL; + goto fail_dp_tx_multi_process; + } + + dev->rx_pkt_burst = dp_rx->pkt_burst; + dev->tx_pkt_burst = dp_tx->pkt_burst; + dev->dev_ops = &sfc_eth_dev_secondary_ops; + + return 0; + +fail_dp_tx_multi_process: +fail_dp_tx: +fail_dp_rx_multi_process: +fail_dp_rx: + return rc; +} + +static void +sfc_eth_dev_secondary_clear_ops(struct rte_eth_dev *dev) +{ + dev->dev_ops = NULL; + dev->tx_pkt_burst = NULL; + dev->rx_pkt_burst = NULL; +} + static void sfc_register_dp(void) { @@ -1427,6 +1762,10 @@ sfc_register_dp(void) /* Prefer EF10 datapath */ sfc_dp_register(&sfc_dp_head, &sfc_ef10_rx.dp); sfc_dp_register(&sfc_dp_head, &sfc_efx_rx.dp); + + sfc_dp_register(&sfc_dp_head, &sfc_ef10_tx.dp); + sfc_dp_register(&sfc_dp_head, &sfc_efx_tx.dp); + sfc_dp_register(&sfc_dp_head, &sfc_ef10_simple_tx.dp); } } @@ -1434,14 +1773,20 @@ static int sfc_eth_dev_init(struct rte_eth_dev *dev) { struct sfc_adapter *sa = dev->data->dev_private; - struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(dev); + struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); int rc; const efx_nic_cfg_t *encp; const struct ether_addr *from; sfc_register_dp(); + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return -sfc_eth_dev_secondary_set_ops(dev); + /* Required for logging */ + sa->pci_addr = pci_dev->addr; + sa->port_id = dev->data->port_id; + sa->eth_dev = dev; /* Copy PCI device info to the dev->data */ @@ -1467,6 +1812,16 @@ sfc_eth_dev_init(struct rte_eth_dev *dev) sfc_adapter_lock_init(sa); sfc_adapter_lock(sa); + sfc_log_init(sa, "probing"); + rc = sfc_probe(sa); + if (rc != 0) + goto fail_probe; + + sfc_log_init(sa, "set device ops"); + rc = sfc_eth_dev_set_ops(dev); + if (rc != 0) + goto fail_set_ops; + sfc_log_init(sa, "attaching"); rc = sfc_attach(sa); if (rc != 0) @@ -1483,12 +1838,16 @@ sfc_eth_dev_init(struct rte_eth_dev *dev) sfc_adapter_unlock(sa); - sfc_eth_dev_set_ops(dev); - sfc_log_init(sa, "done"); return 0; fail_attach: + sfc_eth_dev_clear_ops(dev); + +fail_set_ops: + sfc_unprobe(sa); + +fail_probe: sfc_adapter_unlock(sa); sfc_adapter_lock_fini(sa); rte_free(dev->data->mac_addrs); @@ -1507,21 +1866,26 @@ fail_kvargs_parse: static int sfc_eth_dev_uninit(struct rte_eth_dev *dev) { - struct sfc_adapter *sa = dev->data->dev_private; + struct sfc_adapter *sa; + if (rte_eal_process_type() != RTE_PROC_PRIMARY) { + sfc_eth_dev_secondary_clear_ops(dev); + return 0; + } + + sa = dev->data->dev_private; sfc_log_init(sa, "entry"); sfc_adapter_lock(sa); + sfc_eth_dev_clear_ops(dev); + sfc_detach(sa); + sfc_unprobe(sa); rte_free(dev->data->mac_addrs); dev->data->mac_addrs = NULL; - dev->dev_ops = NULL; - dev->rx_pkt_burst = NULL; - dev->tx_pkt_burst = NULL; - sfc_kvargs_cleanup(sa); sfc_adapter_unlock(sa); @@ -1544,25 +1908,33 @@ static const struct rte_pci_id pci_id_sfc_efx_map[] = { { .vendor_id = 0 /* sentinel */ } }; -static struct eth_driver sfc_efx_pmd = { - .pci_drv = { - .id_table = pci_id_sfc_efx_map, - .drv_flags = - RTE_PCI_DRV_INTR_LSC | - RTE_PCI_DRV_NEED_MAPPING, - .probe = rte_eth_dev_pci_probe, - .remove = rte_eth_dev_pci_remove, - }, - .eth_dev_init = sfc_eth_dev_init, - .eth_dev_uninit = sfc_eth_dev_uninit, - .dev_private_size = sizeof(struct sfc_adapter), +static int sfc_eth_dev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *pci_dev) +{ + return rte_eth_dev_pci_generic_probe(pci_dev, + sizeof(struct sfc_adapter), sfc_eth_dev_init); +} + +static int sfc_eth_dev_pci_remove(struct rte_pci_device *pci_dev) +{ + return rte_eth_dev_pci_generic_remove(pci_dev, sfc_eth_dev_uninit); +} + +static struct rte_pci_driver sfc_efx_pmd = { + .id_table = pci_id_sfc_efx_map, + .drv_flags = + RTE_PCI_DRV_INTR_LSC | + RTE_PCI_DRV_NEED_MAPPING, + .probe = sfc_eth_dev_pci_probe, + .remove = sfc_eth_dev_pci_remove, }; -RTE_PMD_REGISTER_PCI(net_sfc_efx, sfc_efx_pmd.pci_drv); +RTE_PMD_REGISTER_PCI(net_sfc_efx, sfc_efx_pmd); RTE_PMD_REGISTER_PCI_TABLE(net_sfc_efx, pci_id_sfc_efx_map); -RTE_PMD_REGISTER_KMOD_DEP(net_sfc_efx, "* igb_uio | uio_pci_generic | vfio"); +RTE_PMD_REGISTER_KMOD_DEP(net_sfc_efx, "* igb_uio | uio_pci_generic | vfio-pci"); RTE_PMD_REGISTER_PARAM_STRING(net_sfc_efx, SFC_KVARG_RX_DATAPATH "=" SFC_KVARG_VALUES_RX_DATAPATH " " + SFC_KVARG_TX_DATAPATH "=" SFC_KVARG_VALUES_TX_DATAPATH " " SFC_KVARG_PERF_PROFILE "=" SFC_KVARG_VALUES_PERF_PROFILE " " SFC_KVARG_STATS_UPDATE_PERIOD_MS "= " SFC_KVARG_MCDI_LOGGING "=" SFC_KVARG_VALUES_BOOL " "