+ goto fail_kvarg_rx_datapath;
+
+ if (rx_name != NULL) {
+ dp_rx = sfc_dp_find_rx_by_name(&sfc_dp_head, rx_name);
+ if (dp_rx == NULL) {
+ sfc_err(sa, "Rx datapath %s not found", rx_name);
+ rc = ENOENT;
+ goto fail_dp_rx;
+ }
+ if (!sfc_dp_match_hw_fw_caps(&dp_rx->dp, avail_caps)) {
+ sfc_err(sa,
+ "Insufficient Hw/FW capabilities to use Rx datapath %s",
+ rx_name);
+ rc = EINVAL;
+ goto fail_dp_rx_caps;
+ }
+ } else {
+ dp_rx = sfc_dp_find_rx_by_caps(&sfc_dp_head, avail_caps);
+ if (dp_rx == NULL) {
+ sfc_err(sa, "Rx datapath by caps %#x not found",
+ avail_caps);
+ rc = ENOENT;
+ goto fail_dp_rx;
+ }
+ }
+
+ sas->dp_rx_name = sfc_strdup(dp_rx->dp.name);
+ if (sas->dp_rx_name == NULL) {
+ rc = ENOMEM;
+ goto fail_dp_rx_name;
+ }
+
+ sfc_notice(sa, "use %s Rx datapath", sas->dp_rx_name);
+
+ 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) {
+ dp_tx = sfc_dp_find_tx_by_name(&sfc_dp_head, tx_name);
+ if (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(&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 {
+ dp_tx = sfc_dp_find_tx_by_caps(&sfc_dp_head, avail_caps);
+ if (dp_tx == NULL) {
+ sfc_err(sa, "Tx datapath by caps %#x not found",
+ avail_caps);
+ rc = ENOENT;
+ goto fail_dp_tx;
+ }
+ }
+
+ sas->dp_tx_name = sfc_strdup(dp_tx->dp.name);
+ if (sas->dp_tx_name == NULL) {
+ rc = ENOMEM;
+ goto fail_dp_tx_name;
+ }
+
+ sfc_notice(sa, "use %s Tx datapath", sas->dp_tx_name);
+
+ sa->priv.dp_rx = dp_rx;
+ sa->priv.dp_tx = dp_tx;
+
+ dev->rx_pkt_burst = dp_rx->pkt_burst;
+ dev->tx_pkt_prepare = dp_tx->pkt_prepare;
+ dev->tx_pkt_burst = dp_tx->pkt_burst;
+
+ dev->rx_queue_count = sfc_rx_queue_count;
+ dev->rx_descriptor_status = sfc_rx_descriptor_status;
+ dev->tx_descriptor_status = sfc_tx_descriptor_status;
+ dev->dev_ops = &sfc_eth_dev_ops;
+
+ return 0;
+
+fail_dp_tx_name:
+fail_dp_tx_caps:
+fail_dp_tx:
+fail_kvarg_tx_datapath:
+ rte_free(sas->dp_rx_name);
+ sas->dp_rx_name = NULL;
+
+fail_dp_rx_name:
+fail_dp_rx_caps:
+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 = sfc_adapter_by_eth_dev(dev);
+ struct sfc_adapter_shared *sas = sfc_adapter_shared_by_eth_dev(dev);
+
+ dev->dev_ops = NULL;
+ dev->tx_pkt_prepare = NULL;
+ dev->rx_pkt_burst = NULL;
+ dev->tx_pkt_burst = NULL;
+
+ rte_free(sas->dp_tx_name);
+ sas->dp_tx_name = NULL;
+ sa->priv.dp_tx = NULL;
+
+ rte_free(sas->dp_rx_name);
+ sas->dp_rx_name = NULL;
+ sa->priv.dp_rx = NULL;
+}
+
+static const struct eth_dev_ops sfc_eth_dev_secondary_ops = {
+ .dev_supported_ptypes_get = sfc_dev_supported_ptypes_get,
+ .reta_query = sfc_dev_rss_reta_query,
+ .rss_hash_conf_get = sfc_dev_rss_hash_conf_get,
+ .rxq_info_get = sfc_rx_queue_info_get,
+ .txq_info_get = sfc_tx_queue_info_get,
+};
+
+static int
+sfc_eth_dev_secondary_init(struct rte_eth_dev *dev, uint32_t logtype_main)
+{
+ struct sfc_adapter_shared *sas = sfc_adapter_shared_by_eth_dev(dev);
+ struct sfc_adapter_priv *sap;
+ const struct sfc_dp_rx *dp_rx;
+ const struct sfc_dp_tx *dp_tx;
+ int rc;
+
+ /*
+ * Allocate process private data from heap, since it should not
+ * be located in shared memory allocated using rte_malloc() API.
+ */
+ sap = calloc(1, sizeof(*sap));
+ if (sap == NULL) {
+ rc = ENOMEM;
+ goto fail_alloc_priv;
+ }
+
+ sap->logtype_main = logtype_main;
+
+ dp_rx = sfc_dp_find_rx_by_name(&sfc_dp_head, sas->dp_rx_name);
+ if (dp_rx == NULL) {
+ SFC_LOG(sas, RTE_LOG_ERR, logtype_main,
+ "cannot find %s Rx datapath", sas->dp_rx_name);
+ rc = ENOENT;
+ goto fail_dp_rx;
+ }
+ if (~dp_rx->features & SFC_DP_RX_FEAT_MULTI_PROCESS) {
+ SFC_LOG(sas, RTE_LOG_ERR, logtype_main,
+ "%s Rx datapath does not support multi-process",
+ sas->dp_rx_name);
+ rc = EINVAL;
+ goto fail_dp_rx_multi_process;
+ }
+
+ dp_tx = sfc_dp_find_tx_by_name(&sfc_dp_head, sas->dp_tx_name);
+ if (dp_tx == NULL) {
+ SFC_LOG(sas, RTE_LOG_ERR, logtype_main,
+ "cannot find %s Tx datapath", sas->dp_tx_name);
+ rc = ENOENT;
+ goto fail_dp_tx;
+ }
+ if (~dp_tx->features & SFC_DP_TX_FEAT_MULTI_PROCESS) {
+ SFC_LOG(sas, RTE_LOG_ERR, logtype_main,
+ "%s Tx datapath does not support multi-process",
+ sas->dp_tx_name);
+ rc = EINVAL;
+ goto fail_dp_tx_multi_process;
+ }
+
+ sap->dp_rx = dp_rx;
+ sap->dp_tx = dp_tx;
+
+ dev->process_private = sap;
+ dev->rx_pkt_burst = dp_rx->pkt_burst;
+ dev->tx_pkt_prepare = dp_tx->pkt_prepare;
+ dev->tx_pkt_burst = dp_tx->pkt_burst;
+ dev->rx_queue_count = sfc_rx_queue_count;
+ dev->rx_descriptor_status = sfc_rx_descriptor_status;
+ dev->tx_descriptor_status = sfc_tx_descriptor_status;
+ 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:
+ free(sap);
+
+fail_alloc_priv:
+ return rc;
+}
+
+static void
+sfc_register_dp(void)
+{
+ /* Register once */
+ if (TAILQ_EMPTY(&sfc_dp_head)) {
+ /* Prefer EF10 datapath */
+ sfc_dp_register(&sfc_dp_head, &sfc_ef100_rx.dp);
+ sfc_dp_register(&sfc_dp_head, &sfc_ef10_essb_rx.dp);
+ 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_ef100_tx.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);
+ }
+}
+
+static int
+sfc_parse_switch_mode(struct sfc_adapter *sa, bool has_representors)
+{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
+ const char *switch_mode = NULL;
+ int rc;