net/sfc: support flow item TCP in transfer rules
[dpdk.git] / drivers / net / sfc / sfc_ethdev.c
index 013b6bb..107dd0f 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  *
- * Copyright (c) 2016-2018 Solarflare Communications Inc.
- * All rights reserved.
+ * Copyright(c) 2019-2020 Xilinx, Inc.
+ * Copyright(c) 2016-2019 Solarflare Communications Inc.
  *
  * This software was jointly developed between OKTET Labs (under contract
  * for Solarflare) and Solarflare Communications, Inc.
@@ -93,6 +93,7 @@ sfc_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        struct sfc_adapter_shared *sas = sfc_adapter_shared_by_eth_dev(dev);
        struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
        struct sfc_rss *rss = &sas->rss;
+       struct sfc_mae *mae = &sa->mae;
        uint64_t txq_offloads_def = 0;
 
        sfc_log_init(sa, "entry");
@@ -102,6 +103,8 @@ sfc_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 
        dev_info->max_rx_pktlen = EFX_MAC_PDU_MAX;
 
+       dev_info->max_vfs = sa->sriov.num_vfs;
+
        /* Autonegotiation may be disabled */
        dev_info->speed_capa = ETH_LINK_SPEED_FIXED;
        if (sa->port.phy_adv_cap_mask & (1u << EFX_PHY_CAP_1000FDX))
@@ -185,6 +188,12 @@ sfc_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        dev_info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
                             RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
 
+       if (mae->status == SFC_MAE_STATUS_SUPPORTED) {
+               dev_info->switch_info.name = dev->device->driver->name;
+               dev_info->switch_info.domain_id = mae->switch_domain_id;
+               dev_info->switch_info.port_id = mae->switch_port_id;
+       }
+
        return 0;
 }
 
@@ -274,7 +283,7 @@ sfc_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete)
        return ret;
 }
 
-static void
+static int
 sfc_dev_stop(struct rte_eth_dev *dev)
 {
        struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
@@ -286,6 +295,8 @@ sfc_dev_stop(struct rte_eth_dev *dev)
        sfc_adapter_unlock(sa);
 
        sfc_log_init(sa, "done");
+
+       return 0;
 }
 
 static int
@@ -319,12 +330,24 @@ sfc_dev_set_link_down(struct rte_eth_dev *dev)
 }
 
 static void
+sfc_eth_dev_secondary_clear_ops(struct rte_eth_dev *dev)
+{
+       free(dev->process_private);
+       rte_eth_dev_release_port(dev);
+}
+
+static int
 sfc_dev_close(struct rte_eth_dev *dev)
 {
        struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 
        sfc_log_init(sa, "entry");
 
+       if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+               sfc_eth_dev_secondary_clear_ops(dev);
+               return 0;
+       }
+
        sfc_adapter_lock(sa);
        switch (sa->state) {
        case SFC_ADAPTER_STARTED:
@@ -343,7 +366,7 @@ sfc_dev_close(struct rte_eth_dev *dev)
        }
 
        /*
-        * Cleanup all resources in accordance with RTE_ETH_DEV_CLOSE_REMOVE.
+        * Cleanup all resources.
         * Rollback primary process sfc_eth_dev_init() below.
         */
 
@@ -362,11 +385,12 @@ sfc_dev_close(struct rte_eth_dev *dev)
        /* Required for logging, so cleanup last */
        sa->eth_dev = NULL;
 
-       dev->process_private = NULL;
        free(sa);
+
+       return 0;
 }
 
-static void
+static int
 sfc_dev_filter_set(struct rte_eth_dev *dev, enum sfc_dev_filter_mode mode,
                   boolean_t enabled)
 {
@@ -375,6 +399,7 @@ sfc_dev_filter_set(struct rte_eth_dev *dev, enum sfc_dev_filter_mode mode,
        struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
        boolean_t allmulti = (mode == SFC_DEV_FILTER_MODE_ALLMULTI);
        const char *desc = (allmulti) ? "all-multi" : "promiscuous";
+       int rc = 0;
 
        sfc_adapter_lock(sa);
 
@@ -390,38 +415,59 @@ sfc_dev_filter_set(struct rte_eth_dev *dev, enum sfc_dev_filter_mode mode,
                                     "start provided that isolated mode is "
                                     "disabled prior the next start");
                } else if ((sa->state == SFC_ADAPTER_STARTED) &&
-                          (sfc_set_rx_mode(sa) != 0)) {
+                          ((rc = sfc_set_rx_mode(sa)) != 0)) {
                        *toggle = !(enabled);
-                       sfc_warn(sa, "Failed to %s %s mode",
-                                ((enabled) ? "enable" : "disable"), desc);
+                       sfc_warn(sa, "Failed to %s %s mode, rc = %d",
+                                ((enabled) ? "enable" : "disable"), desc, rc);
+
+                       /*
+                        * For promiscuous and all-multicast filters a
+                        * permission failure should be reported as an
+                        * unsupported filter.
+                        */
+                       if (rc == EPERM)
+                               rc = ENOTSUP;
                }
        }
 
        sfc_adapter_unlock(sa);
+       return rc;
 }
 
-static void
+static int
 sfc_dev_promisc_enable(struct rte_eth_dev *dev)
 {
-       sfc_dev_filter_set(dev, SFC_DEV_FILTER_MODE_PROMISC, B_TRUE);
+       int rc = sfc_dev_filter_set(dev, SFC_DEV_FILTER_MODE_PROMISC, B_TRUE);
+
+       SFC_ASSERT(rc >= 0);
+       return -rc;
 }
 
-static void
+static int
 sfc_dev_promisc_disable(struct rte_eth_dev *dev)
 {
-       sfc_dev_filter_set(dev, SFC_DEV_FILTER_MODE_PROMISC, B_FALSE);
+       int rc = sfc_dev_filter_set(dev, SFC_DEV_FILTER_MODE_PROMISC, B_FALSE);
+
+       SFC_ASSERT(rc >= 0);
+       return -rc;
 }
 
-static void
+static int
 sfc_dev_allmulti_enable(struct rte_eth_dev *dev)
 {
-       sfc_dev_filter_set(dev, SFC_DEV_FILTER_MODE_ALLMULTI, B_TRUE);
+       int rc = sfc_dev_filter_set(dev, SFC_DEV_FILTER_MODE_ALLMULTI, B_TRUE);
+
+       SFC_ASSERT(rc >= 0);
+       return -rc;
 }
 
-static void
+static int
 sfc_dev_allmulti_disable(struct rte_eth_dev *dev)
 {
-       sfc_dev_filter_set(dev, SFC_DEV_FILTER_MODE_ALLMULTI, B_FALSE);
+       int rc = sfc_dev_filter_set(dev, SFC_DEV_FILTER_MODE_ALLMULTI, B_FALSE);
+
+       SFC_ASSERT(rc >= 0);
+       return -rc;
 }
 
 static int
@@ -635,7 +681,7 @@ unlock:
        return -ret;
 }
 
-static void
+static int
 sfc_stats_reset(struct rte_eth_dev *dev)
 {
        struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
@@ -648,12 +694,15 @@ sfc_stats_reset(struct rte_eth_dev *dev)
                 * will be scheduled to be done during the next port start
                 */
                port->mac_stats_reset_pending = B_TRUE;
-               return;
+               return 0;
        }
 
        rc = sfc_port_reset_mac_stats(sa);
        if (rc != 0)
                sfc_err(sa, "failed to reset statistics (rc = %d)", rc);
+
+       SFC_ASSERT(rc >= 0);
+       return -rc;
 }
 
 static int
@@ -909,7 +958,8 @@ sfc_check_scatter_on_all_rx_queues(struct sfc_adapter *sa, size_t pdu)
 
                if (!sfc_rx_check_scatter(pdu, sa->rxq_ctrl[i].buf_size,
                                          encp->enc_rx_prefix_size,
-                                         scatter_enabled, &error)) {
+                                         scatter_enabled,
+                                         encp->enc_rx_scatter_max, &error)) {
                        sfc_err(sa, "MTU check for RxQ %u failed: %s", i,
                                error);
                        return EINVAL;
@@ -1005,6 +1055,9 @@ sfc_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 
        sfc_adapter_lock(sa);
 
+       if (rte_is_same_ether_addr(mac_addr, &port->default_mac_addr))
+               goto unlock;
+
        /*
         * Copy the address to the device private data so that
         * it could be recalled in the case of adapter restart.
@@ -1043,12 +1096,12 @@ sfc_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
                 * has no effect on received traffic, therefore
                 * we also need to update unicast filters
                 */
-               rc = sfc_set_rx_mode(sa);
+               rc = sfc_set_rx_mode_unchecked(sa);
                if (rc != 0) {
                        sfc_err(sa, "cannot set filter (rc = %u)", rc);
                        /* Rollback the old address */
                        (void)efx_mac_addr_set(sa->nic, old_addr->addr_bytes);
-                       (void)sfc_set_rx_mode(sa);
+                       (void)sfc_set_rx_mode_unchecked(sa);
                }
        } else {
                sfc_warn(sa, "cannot set MAC address with filters installed");
@@ -1498,8 +1551,15 @@ sfc_dev_rss_hash_update(struct rte_eth_dev *dev,
        struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
        struct sfc_rss *rss = &sfc_sa2shared(sa)->rss;
        unsigned int efx_hash_types;
+       uint32_t contexts[] = {EFX_RSS_CONTEXT_DEFAULT, rss->dummy_rss_context};
+       unsigned int n_contexts;
+       unsigned int mode_i = 0;
+       unsigned int key_i = 0;
+       unsigned int i = 0;
        int rc = 0;
 
+       n_contexts = rss->dummy_rss_context == EFX_RSS_CONTEXT_DEFAULT ? 1 : 2;
+
        if (sfc_sa2shared(sa)->isolated)
                return -ENOTSUP;
 
@@ -1515,7 +1575,7 @@ sfc_dev_rss_hash_update(struct rte_eth_dev *dev,
 
        if ((rss_conf->rss_key != NULL) &&
            (rss_conf->rss_key_len != sizeof(rss->key))) {
-               sfc_err(sa, "RSS key size is wrong (should be %lu)",
+               sfc_err(sa, "RSS key size is wrong (should be %zu)",
                        sizeof(rss->key));
                return -EINVAL;
        }
@@ -1526,19 +1586,24 @@ sfc_dev_rss_hash_update(struct rte_eth_dev *dev,
        if (rc != 0)
                goto fail_rx_hf_rte_to_efx;
 
-       rc = efx_rx_scale_mode_set(sa->nic, EFX_RSS_CONTEXT_DEFAULT,
-                                  rss->hash_alg, efx_hash_types, B_TRUE);
-       if (rc != 0)
-               goto fail_scale_mode_set;
+       for (mode_i = 0; mode_i < n_contexts; mode_i++) {
+               rc = efx_rx_scale_mode_set(sa->nic, contexts[mode_i],
+                                          rss->hash_alg, 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,
-                                                 EFX_RSS_CONTEXT_DEFAULT,
-                                                 rss_conf->rss_key,
-                                                 sizeof(rss->key));
-                       if (rc != 0)
-                               goto fail_scale_key_set;
+                       for (key_i = 0; key_i < n_contexts; key_i++) {
+                               rc = efx_rx_scale_key_set(sa->nic,
+                                                         contexts[key_i],
+                                                         rss_conf->rss_key,
+                                                         sizeof(rss->key));
+                               if (rc != 0)
+                                       goto fail_scale_key_set;
+                       }
                }
 
                rte_memcpy(rss->key, rss_conf->rss_key, sizeof(rss->key));
@@ -1551,12 +1616,20 @@ 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_RSS_CONTEXT_DEFAULT,
-                                 EFX_RX_HASHALG_TOEPLITZ,
-                                 rss->hash_types, B_TRUE) != 0)
-               sfc_err(sa, "failed to restore RSS mode");
+       for (i = 0; i < key_i; i++) {
+               if (efx_rx_scale_key_set(sa->nic, contexts[i], rss->key,
+                                        sizeof(rss->key)) != 0)
+                       sfc_err(sa, "failed to restore RSS key");
+       }
 
 fail_scale_mode_set:
+       for (i = 0; i < mode_i; i++) {
+               if (efx_rx_scale_mode_set(sa->nic, contexts[i],
+                                         EFX_RX_HASHALG_TOEPLITZ,
+                                         rss->hash_types, B_TRUE) != 0)
+                       sfc_err(sa, "failed to restore RSS mode");
+       }
+
 fail_rx_hf_rte_to_efx:
        sfc_adapter_unlock(sa);
        return -rc;
@@ -1791,10 +1864,6 @@ static const struct eth_dev_ops sfc_eth_dev_ops = {
        .tx_queue_stop                  = sfc_tx_queue_stop,
        .rx_queue_setup                 = sfc_rx_queue_setup,
        .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,
        .rx_queue_intr_enable           = sfc_rx_queue_intr_enable,
        .rx_queue_intr_disable          = sfc_rx_queue_intr_disable,
        .tx_queue_setup                 = sfc_tx_queue_setup,
@@ -1859,6 +1928,11 @@ sfc_eth_dev_set_ops(struct rte_eth_dev *dev)
        case EFX_FAMILY_MEDFORD:
        case EFX_FAMILY_MEDFORD2:
                avail_caps |= SFC_DP_HW_FW_CAP_EF10;
+               avail_caps |= SFC_DP_HW_FW_CAP_RX_EFX;
+               avail_caps |= SFC_DP_HW_FW_CAP_TX_EFX;
+               break;
+       case EFX_FAMILY_RIVERHEAD:
+               avail_caps |= SFC_DP_HW_FW_CAP_EF100;
                break;
        default:
                break;
@@ -1949,6 +2023,10 @@ sfc_eth_dev_set_ops(struct rte_eth_dev *dev)
        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_done = sfc_rx_descriptor_done;
+       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;
@@ -1989,10 +2067,6 @@ sfc_eth_dev_clear_ops(struct rte_eth_dev *dev)
 
 static const struct eth_dev_ops sfc_eth_dev_secondary_ops = {
        .dev_supported_ptypes_get       = sfc_dev_supported_ptypes_get,
-       .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,
        .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,
@@ -2057,6 +2131,10 @@ sfc_eth_dev_secondary_init(struct rte_eth_dev *dev, uint32_t logtype_main)
        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_done = sfc_rx_descriptor_done;
+       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;
@@ -2071,27 +2149,18 @@ fail_alloc_priv:
        return rc;
 }
 
-static void
-sfc_eth_dev_secondary_clear_ops(struct rte_eth_dev *dev)
-{
-       free(dev->process_private);
-       dev->process_private = NULL;
-       dev->dev_ops = NULL;
-       dev->tx_pkt_prepare = NULL;
-       dev->tx_pkt_burst = NULL;
-       dev->rx_pkt_burst = NULL;
-}
-
 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);
@@ -2108,6 +2177,7 @@ sfc_eth_dev_init(struct rte_eth_dev *dev)
        int rc;
        const efx_nic_cfg_t *encp;
        const struct rte_ether_addr *from;
+       int ret;
 
        sfc_register_dp();
 
@@ -2119,6 +2189,18 @@ sfc_eth_dev_init(struct rte_eth_dev *dev)
                return -sfc_eth_dev_secondary_init(dev, logtype_main);
 
        /* Required for logging */
+       ret = snprintf(sas->log_prefix, sizeof(sas->log_prefix),
+                       "PMD: sfc_efx " PCI_PRI_FMT " #%" PRIu16 ": ",
+                       pci_dev->addr.domain, pci_dev->addr.bus,
+                       pci_dev->addr.devid, pci_dev->addr.function,
+                       dev->data->port_id);
+       if (ret < 0 || ret >= (int)sizeof(sas->log_prefix)) {
+               SFC_GENERIC_LOG(ERR,
+                       "reserved log prefix is too short for " PCI_PRI_FMT,
+                       pci_dev->addr.domain, pci_dev->addr.bus,
+                       pci_dev->addr.devid, pci_dev->addr.function);
+               return -EINVAL;
+       }
        sas->pci_addr = pci_dev->addr;
        sas->port_id = dev->data->port_id;
 
@@ -2142,6 +2224,7 @@ sfc_eth_dev_init(struct rte_eth_dev *dev)
 
        /* Copy PCI device info to the dev->data */
        rte_eth_copy_pci_info(dev, pci_dev);
+       dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
 
        rc = sfc_kvargs_parse(sa);
        if (rc != 0)
@@ -2149,8 +2232,6 @@ sfc_eth_dev_init(struct rte_eth_dev *dev)
 
        sfc_log_init(sa, "entry");
 
-       dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
-
        dev->data->mac_addrs = rte_zmalloc("sfc", RTE_ETHER_ADDR_LEN, 0);
        if (dev->data->mac_addrs == NULL) {
                rc = ENOMEM;
@@ -2217,11 +2298,6 @@ fail_alloc_sa:
 static int
 sfc_eth_dev_uninit(struct rte_eth_dev *dev)
 {
-       if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
-               sfc_eth_dev_secondary_clear_ops(dev);
-               return 0;
-       }
-
        sfc_dev_close(dev);
 
        return 0;
@@ -2236,6 +2312,7 @@ static const struct rte_pci_id pci_id_sfc_efx_map[] = {
        { RTE_PCI_DEVICE(EFX_PCI_VENID_SFC, EFX_PCI_DEVID_MEDFORD_VF) },
        { RTE_PCI_DEVICE(EFX_PCI_VENID_SFC, EFX_PCI_DEVID_MEDFORD2) },
        { RTE_PCI_DEVICE(EFX_PCI_VENID_SFC, EFX_PCI_DEVID_MEDFORD2_VF) },
+       { RTE_PCI_DEVICE(EFX_PCI_VENID_XILINX, EFX_PCI_DEVID_RIVERHEAD) },
        { .vendor_id = 0 /* sentinel */ }
 };