net/bnxt: support port representor data path
[dpdk.git] / drivers / net / bnxt / bnxt_ethdev.c
index 7022f6d..a1c213e 100644 (file)
@@ -18,6 +18,7 @@
 #include "bnxt_filter.h"
 #include "bnxt_hwrm.h"
 #include "bnxt_irq.h"
+#include "bnxt_reps.h"
 #include "bnxt_ring.h"
 #include "bnxt_rxq.h"
 #include "bnxt_rxr.h"
@@ -31,7 +32,6 @@
 #define DRV_MODULE_NAME                "bnxt"
 static const char bnxt_version[] =
        "Broadcom NetXtreme driver " DRV_MODULE_NAME;
-int bnxt_logtype_driver;
 
 /*
  * The set of PCI devices this driver supports
@@ -93,40 +93,6 @@ static const struct rte_pci_id bnxt_pci_id_map[] = {
        { .vendor_id = 0, /* sentinel */ },
 };
 
-#define BNXT_ETH_RSS_SUPPORT ( \
-       ETH_RSS_IPV4 |          \
-       ETH_RSS_NONFRAG_IPV4_TCP |      \
-       ETH_RSS_NONFRAG_IPV4_UDP |      \
-       ETH_RSS_IPV6 |          \
-       ETH_RSS_NONFRAG_IPV6_TCP |      \
-       ETH_RSS_NONFRAG_IPV6_UDP)
-
-#define BNXT_DEV_TX_OFFLOAD_SUPPORT (DEV_TX_OFFLOAD_VLAN_INSERT | \
-                                    DEV_TX_OFFLOAD_IPV4_CKSUM | \
-                                    DEV_TX_OFFLOAD_TCP_CKSUM | \
-                                    DEV_TX_OFFLOAD_UDP_CKSUM | \
-                                    DEV_TX_OFFLOAD_TCP_TSO | \
-                                    DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM | \
-                                    DEV_TX_OFFLOAD_VXLAN_TNL_TSO | \
-                                    DEV_TX_OFFLOAD_GRE_TNL_TSO | \
-                                    DEV_TX_OFFLOAD_IPIP_TNL_TSO | \
-                                    DEV_TX_OFFLOAD_GENEVE_TNL_TSO | \
-                                    DEV_TX_OFFLOAD_QINQ_INSERT | \
-                                    DEV_TX_OFFLOAD_MULTI_SEGS)
-
-#define BNXT_DEV_RX_OFFLOAD_SUPPORT (DEV_RX_OFFLOAD_VLAN_FILTER | \
-                                    DEV_RX_OFFLOAD_VLAN_STRIP | \
-                                    DEV_RX_OFFLOAD_IPV4_CKSUM | \
-                                    DEV_RX_OFFLOAD_UDP_CKSUM | \
-                                    DEV_RX_OFFLOAD_TCP_CKSUM | \
-                                    DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM | \
-                                    DEV_RX_OFFLOAD_JUMBO_FRAME | \
-                                    DEV_RX_OFFLOAD_KEEP_CRC | \
-                                    DEV_RX_OFFLOAD_VLAN_EXTEND | \
-                                    DEV_RX_OFFLOAD_TCP_LRO | \
-                                    DEV_RX_OFFLOAD_SCATTER | \
-                                    DEV_RX_OFFLOAD_RSS_HASH)
-
 #define BNXT_DEVARG_TRUFLOW    "host-based-truflow"
 #define BNXT_DEVARG_FLOW_XSTAT "flow-xstat"
 #define BNXT_DEVARG_MAX_NUM_KFLOWS  "max-num-kflows"
@@ -163,7 +129,6 @@ static int bnxt_devarg_max_num_kflow_invalid(uint16_t max_num_kflows)
 }
 
 static int bnxt_vlan_offload_set_op(struct rte_eth_dev *dev, int mask);
-static void bnxt_print_link_info(struct rte_eth_dev *eth_dev);
 static int bnxt_dev_uninit(struct rte_eth_dev *eth_dev);
 static int bnxt_init_resources(struct bnxt *bp, bool reconfig_dev);
 static int bnxt_uninit_resources(struct bnxt *bp, bool reconfig_dev);
@@ -171,6 +136,7 @@ static void bnxt_cancel_fw_health_check(struct bnxt *bp);
 static int bnxt_restore_vlan_filters(struct bnxt *bp);
 static void bnxt_dev_recover(void *arg);
 static void bnxt_free_error_recovery_info(struct bnxt *bp);
+static void bnxt_free_rep_info(struct bnxt *bp);
 
 int is_bnxt_in_error(struct bnxt *bp)
 {
@@ -198,7 +164,7 @@ static uint16_t bnxt_rss_ctxts(const struct bnxt *bp)
                                    BNXT_RSS_ENTRIES_PER_CTX_THOR;
 }
 
-static uint16_t  bnxt_rss_hash_tbl_size(const struct bnxt *bp)
+uint16_t bnxt_rss_hash_tbl_size(const struct bnxt *bp)
 {
        if (!BNXT_CHIP_THOR(bp))
                return HW_HASH_INDEX_SIZE;
@@ -1047,7 +1013,7 @@ resource_error:
        return -ENOSPC;
 }
 
-static void bnxt_print_link_info(struct rte_eth_dev *eth_dev)
+void bnxt_print_link_info(struct rte_eth_dev *eth_dev)
 {
        struct rte_eth_link *link = &eth_dev->data->dev_link;
 
@@ -1273,6 +1239,12 @@ static int bnxt_dev_set_link_down_op(struct rte_eth_dev *eth_dev)
        return 0;
 }
 
+static void bnxt_free_switch_domain(struct bnxt *bp)
+{
+       if (bp->switch_domain_id)
+               rte_eth_switch_domain_free(bp->switch_domain_id);
+}
+
 /* Unload the driver, release resources */
 static void bnxt_dev_stop_op(struct rte_eth_dev *eth_dev)
 {
@@ -1341,6 +1313,8 @@ static void bnxt_dev_close_op(struct rte_eth_dev *eth_dev)
        if (eth_dev->data->dev_started)
                bnxt_dev_stop_op(eth_dev);
 
+       bnxt_free_switch_domain(bp);
+
        bnxt_uninit_resources(bp, false);
 
        bnxt_free_leds_info(bp);
@@ -1522,8 +1496,8 @@ out:
        return rc;
 }
 
-static int bnxt_link_update_op(struct rte_eth_dev *eth_dev,
-                              int wait_to_complete)
+int bnxt_link_update_op(struct rte_eth_dev *eth_dev,
+                       int wait_to_complete)
 {
        return bnxt_link_update(eth_dev, wait_to_complete, ETH_LINK_UP);
 }
@@ -5269,7 +5243,7 @@ bnxt_init_locks(struct bnxt *bp)
 
 static int bnxt_init_resources(struct bnxt *bp, bool reconfig_dev)
 {
-       int rc;
+       int rc = 0;
 
        rc = bnxt_init_fw(bp);
        if (rc)
@@ -5477,8 +5451,26 @@ bnxt_parse_dev_args(struct bnxt *bp, struct rte_devargs *devargs)
        rte_kvargs_free(kvlist);
 }
 
+static int bnxt_alloc_switch_domain(struct bnxt *bp)
+{
+       int rc = 0;
+
+       if (BNXT_PF(bp) || BNXT_VF_IS_TRUSTED(bp)) {
+               rc = rte_eth_switch_domain_alloc(&bp->switch_domain_id);
+               if (rc)
+                       PMD_DRV_LOG(ERR,
+                                   "Failed to alloc switch domain: %d\n", rc);
+               else
+                       PMD_DRV_LOG(INFO,
+                                   "Switch domain allocated %d\n",
+                                   bp->switch_domain_id);
+       }
+
+       return rc;
+}
+
 static int
-bnxt_dev_init(struct rte_eth_dev *eth_dev)
+bnxt_dev_init(struct rte_eth_dev *eth_dev, void *params __rte_unused)
 {
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
        static int version_printed;
@@ -5557,6 +5549,8 @@ bnxt_dev_init(struct rte_eth_dev *eth_dev)
        if (rc)
                goto error_free;
 
+       bnxt_alloc_switch_domain(bp);
+
        /* Pass the information to the rte_eth_dev_close() that it should also
         * release the private port resources.
         */
@@ -5648,6 +5642,8 @@ bnxt_uninit_locks(struct bnxt *bp)
 {
        pthread_mutex_destroy(&bp->flow_lock);
        pthread_mutex_destroy(&bp->def_cp_lock);
+       if (bp->rep_info)
+               pthread_mutex_destroy(&bp->rep_info->vfr_lock);
 }
 
 static int
@@ -5670,6 +5666,7 @@ bnxt_uninit_resources(struct bnxt *bp, bool reconfig_dev)
 
        bnxt_uninit_locks(bp);
        bnxt_free_flow_stats_info(bp);
+       bnxt_free_rep_info(bp);
        rte_free(bp->ptp_cfg);
        bp->ptp_cfg = NULL;
        return rc;
@@ -5689,25 +5686,224 @@ bnxt_dev_uninit(struct rte_eth_dev *eth_dev)
        return 0;
 }
 
+static int bnxt_pci_remove_dev_with_reps(struct rte_eth_dev *eth_dev)
+{
+       struct bnxt *bp = eth_dev->data->dev_private;
+       struct rte_eth_dev *vf_rep_eth_dev;
+       int ret = 0, i;
+
+       if (!bp)
+               return -EINVAL;
+
+       for (i = 0; i < bp->num_reps; i++) {
+               vf_rep_eth_dev = bp->rep_info[i].vfr_eth_dev;
+               if (!vf_rep_eth_dev)
+                       continue;
+               rte_eth_dev_destroy(vf_rep_eth_dev, bnxt_vf_representor_uninit);
+       }
+       ret = rte_eth_dev_destroy(eth_dev, bnxt_dev_uninit);
+
+       return ret;
+}
+
+static void bnxt_free_rep_info(struct bnxt *bp)
+{
+       rte_free(bp->rep_info);
+       bp->rep_info = NULL;
+       rte_free(bp->cfa_code_map);
+       bp->cfa_code_map = NULL;
+}
+
+static int bnxt_init_rep_info(struct bnxt *bp)
+{
+       int i = 0, rc;
+
+       if (bp->rep_info)
+               return 0;
+
+       bp->rep_info = rte_zmalloc("bnxt_rep_info",
+                                  sizeof(bp->rep_info[0]) * BNXT_MAX_VF_REPS,
+                                  0);
+       if (!bp->rep_info) {
+               PMD_DRV_LOG(ERR, "Failed to alloc memory for rep info\n");
+               return -ENOMEM;
+       }
+       bp->cfa_code_map = rte_zmalloc("bnxt_cfa_code_map",
+                                      sizeof(*bp->cfa_code_map) *
+                                      BNXT_MAX_CFA_CODE, 0);
+       if (!bp->cfa_code_map) {
+               PMD_DRV_LOG(ERR, "Failed to alloc memory for cfa_code_map\n");
+               bnxt_free_rep_info(bp);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < BNXT_MAX_CFA_CODE; i++)
+               bp->cfa_code_map[i] = BNXT_VF_IDX_INVALID;
+
+       rc = pthread_mutex_init(&bp->rep_info->vfr_lock, NULL);
+       if (rc) {
+               PMD_DRV_LOG(ERR, "Unable to initialize vfr_lock\n");
+               bnxt_free_rep_info(bp);
+               return rc;
+       }
+       return rc;
+}
+
+static int bnxt_rep_port_probe(struct rte_pci_device *pci_dev,
+                              struct rte_eth_devargs eth_da,
+                              struct rte_eth_dev *backing_eth_dev)
+{
+       struct rte_eth_dev *vf_rep_eth_dev;
+       char name[RTE_ETH_NAME_MAX_LEN];
+       struct bnxt *backing_bp;
+       uint16_t num_rep;
+       int i, ret = 0;
+
+       num_rep = eth_da.nb_representor_ports;
+       if (num_rep > BNXT_MAX_VF_REPS) {
+               PMD_DRV_LOG(ERR, "nb_representor_ports = %d > %d MAX VF REPS\n",
+                           num_rep, BNXT_MAX_VF_REPS);
+               return -EINVAL;
+       }
+
+       if (num_rep > RTE_MAX_ETHPORTS) {
+               PMD_DRV_LOG(ERR,
+                           "nb_representor_ports = %d > %d MAX ETHPORTS\n",
+                           num_rep, RTE_MAX_ETHPORTS);
+               return -EINVAL;
+       }
+
+       backing_bp = backing_eth_dev->data->dev_private;
+
+       if (!(BNXT_PF(backing_bp) || BNXT_VF_IS_TRUSTED(backing_bp))) {
+               PMD_DRV_LOG(ERR,
+                           "Not a PF or trusted VF. No Representor support\n");
+               /* Returning an error is not an option.
+                * Applications are not handling this correctly
+                */
+               return 0;
+       }
+
+       if (bnxt_init_rep_info(backing_bp))
+               return 0;
+
+       for (i = 0; i < num_rep; i++) {
+               struct bnxt_vf_representor representor = {
+                       .vf_id = eth_da.representor_ports[i],
+                       .switch_domain_id = backing_bp->switch_domain_id,
+                       .parent_dev = backing_eth_dev
+               };
+
+               if (representor.vf_id >= BNXT_MAX_VF_REPS) {
+                       PMD_DRV_LOG(ERR, "VF-Rep id %d >= %d MAX VF ID\n",
+                                   representor.vf_id, BNXT_MAX_VF_REPS);
+                       continue;
+               }
+
+               /* representor port net_bdf_port */
+               snprintf(name, sizeof(name), "net_%s_representor_%d",
+                        pci_dev->device.name, eth_da.representor_ports[i]);
+
+               ret = rte_eth_dev_create(&pci_dev->device, name,
+                                        sizeof(struct bnxt_vf_representor),
+                                        NULL, NULL,
+                                        bnxt_vf_representor_init,
+                                        &representor);
+
+               if (!ret) {
+                       vf_rep_eth_dev = rte_eth_dev_allocated(name);
+                       if (!vf_rep_eth_dev) {
+                               PMD_DRV_LOG(ERR, "Failed to find the eth_dev"
+                                           " for VF-Rep: %s.", name);
+                               bnxt_pci_remove_dev_with_reps(backing_eth_dev);
+                               ret = -ENODEV;
+                               return ret;
+                       }
+                       backing_bp->rep_info[representor.vf_id].vfr_eth_dev =
+                               vf_rep_eth_dev;
+                       backing_bp->num_reps++;
+               } else {
+                       PMD_DRV_LOG(ERR, "failed to create bnxt vf "
+                                   "representor %s.", name);
+                       bnxt_pci_remove_dev_with_reps(backing_eth_dev);
+               }
+       }
+
+       return ret;
+}
+
 static int bnxt_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
-       struct rte_pci_device *pci_dev)
+                         struct rte_pci_device *pci_dev)
 {
-       return rte_eth_dev_pci_generic_probe(pci_dev, sizeof(struct bnxt),
-               bnxt_dev_init);
+       struct rte_eth_devargs eth_da = { .nb_representor_ports = 0 };
+       struct rte_eth_dev *backing_eth_dev;
+       uint16_t num_rep;
+       int ret = 0;
+
+       if (pci_dev->device.devargs) {
+               ret = rte_eth_devargs_parse(pci_dev->device.devargs->args,
+                                           &eth_da);
+               if (ret)
+                       return ret;
+       }
+
+       num_rep = eth_da.nb_representor_ports;
+       PMD_DRV_LOG(DEBUG, "nb_representor_ports = %d\n",
+                   num_rep);
+
+       /* We could come here after first level of probe is already invoked
+        * as part of an application bringup(OVS-DPDK vswitchd), so first check
+        * for already allocated eth_dev for the backing device (PF/Trusted VF)
+        */
+       backing_eth_dev = rte_eth_dev_allocated(pci_dev->device.name);
+       if (backing_eth_dev == NULL) {
+               ret = rte_eth_dev_create(&pci_dev->device, pci_dev->device.name,
+                                        sizeof(struct bnxt),
+                                        eth_dev_pci_specific_init, pci_dev,
+                                        bnxt_dev_init, NULL);
+
+               if (ret || !num_rep)
+                       return ret;
+
+               backing_eth_dev = rte_eth_dev_allocated(pci_dev->device.name);
+       }
+
+       /* probe representor ports now */
+       ret = bnxt_rep_port_probe(pci_dev, eth_da, backing_eth_dev);
+
+       return ret;
 }
 
 static int bnxt_pci_remove(struct rte_pci_device *pci_dev)
 {
-       if (rte_eal_process_type() == RTE_PROC_PRIMARY)
-               return rte_eth_dev_pci_generic_remove(pci_dev,
-                               bnxt_dev_uninit);
-       else
+       struct rte_eth_dev *eth_dev;
+
+       eth_dev = rte_eth_dev_allocated(pci_dev->device.name);
+       if (!eth_dev)
+               return 0; /* Invoked typically only by OVS-DPDK, by the
+                          * time it comes here the eth_dev is already
+                          * deleted by rte_eth_dev_close(), so returning
+                          * +ve value will at least help in proper cleanup
+                          */
+
+       if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+               if (eth_dev->data->dev_flags & RTE_ETH_DEV_REPRESENTOR)
+                       return rte_eth_dev_destroy(eth_dev,
+                                                  bnxt_vf_representor_uninit);
+               else
+                       return rte_eth_dev_destroy(eth_dev,
+                                                  bnxt_dev_uninit);
+       } else {
                return rte_eth_dev_pci_generic_remove(pci_dev, NULL);
+       }
 }
 
 static struct rte_pci_driver bnxt_rte_pmd = {
        .id_table = bnxt_pci_id_map,
-       .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
+       .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
+                       RTE_PCI_DRV_PROBE_AGAIN, /* Needed in case of VF-REPs
+                                                 * and OVS-DPDK
+                                                 */
        .probe = bnxt_pci_probe,
        .remove = bnxt_pci_remove,
 };
@@ -5726,13 +5922,7 @@ bool is_bnxt_supported(struct rte_eth_dev *dev)
        return is_device_supported(dev, &bnxt_rte_pmd);
 }
 
-RTE_INIT(bnxt_init_log)
-{
-       bnxt_logtype_driver = rte_log_register("pmd.net.bnxt.driver");
-       if (bnxt_logtype_driver >= 0)
-               rte_log_set_level(bnxt_logtype_driver, RTE_LOG_NOTICE);
-}
-
+RTE_LOG_REGISTER(bnxt_logtype_driver, pmd.net.bnxt.driver, NOTICE);
 RTE_PMD_REGISTER_PCI(net_bnxt, bnxt_rte_pmd);
 RTE_PMD_REGISTER_PCI_TABLE(net_bnxt, bnxt_pci_id_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_bnxt, "* igb_uio | uio_pci_generic | vfio-pci");