net/bnxt: add flow stats in extended stats
[dpdk.git] / drivers / net / bnxt / bnxt_ethdev.c
index 5378209..6c1234b 100644 (file)
@@ -12,6 +12,7 @@
 #include <rte_malloc.h>
 #include <rte_cycles.h>
 #include <rte_alarm.h>
+#include <rte_kvargs.h>
 
 #include "bnxt.h"
 #include "bnxt_filter.h"
@@ -126,6 +127,26 @@ static const struct rte_pci_id bnxt_pci_id_map[] = {
                                     DEV_RX_OFFLOAD_SCATTER | \
                                     DEV_RX_OFFLOAD_RSS_HASH)
 
+#define BNXT_DEVARG_TRUFLOW    "host-based-truflow"
+#define BNXT_DEVARG_FLOW_XSTAT "flow-xstat"
+static const char *const bnxt_dev_args[] = {
+       BNXT_DEVARG_TRUFLOW,
+       BNXT_DEVARG_FLOW_XSTAT,
+       NULL
+};
+
+/*
+ * truflow == false to disable the feature
+ * truflow == true to enable the feature
+ */
+#define        BNXT_DEVARG_TRUFLOW_INVALID(truflow)    ((truflow) > 1)
+
+/*
+ * flow_xstat == false to disable the feature
+ * flow_xstat == true to enable the feature
+ */
+#define        BNXT_DEVARG_FLOW_XSTAT_INVALID(flow_xstat)      ((flow_xstat) > 1)
+
 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);
@@ -133,6 +154,7 @@ static int bnxt_init_resources(struct bnxt *bp, bool reconfig_dev);
 static int bnxt_uninit_resources(struct bnxt *bp, bool reconfig_dev);
 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);
 
 int is_bnxt_in_error(struct bnxt *bp)
 {
@@ -150,7 +172,7 @@ int is_bnxt_in_error(struct bnxt *bp)
  * High level utility functions
  */
 
-uint16_t bnxt_rss_ctxts(const struct bnxt *bp)
+static uint16_t bnxt_rss_ctxts(const struct bnxt *bp)
 {
        if (!BNXT_CHIP_THOR(bp))
                return 1;
@@ -319,6 +341,154 @@ err_out:
        return rc;
 }
 
+static int bnxt_register_fc_ctx_mem(struct bnxt *bp)
+{
+       int rc = 0;
+
+       rc = bnxt_hwrm_ctx_rgtr(bp, bp->rx_fc_in_tbl.dma,
+                               &bp->rx_fc_in_tbl.ctx_id);
+       if (rc)
+               return rc;
+
+       PMD_DRV_LOG(DEBUG,
+                   "rx_fc_in_tbl.va = %p rx_fc_in_tbl.dma = %p"
+                   " rx_fc_in_tbl.ctx_id = %d\n",
+                   bp->rx_fc_in_tbl.va,
+                   (void *)((uintptr_t)bp->rx_fc_in_tbl.dma),
+                   bp->rx_fc_in_tbl.ctx_id);
+
+       rc = bnxt_hwrm_ctx_rgtr(bp, bp->rx_fc_out_tbl.dma,
+                               &bp->rx_fc_out_tbl.ctx_id);
+       if (rc)
+               return rc;
+
+       PMD_DRV_LOG(DEBUG,
+                   "rx_fc_out_tbl.va = %p rx_fc_out_tbl.dma = %p"
+                   " rx_fc_out_tbl.ctx_id = %d\n",
+                   bp->rx_fc_out_tbl.va,
+                   (void *)((uintptr_t)bp->rx_fc_out_tbl.dma),
+                   bp->rx_fc_out_tbl.ctx_id);
+
+       rc = bnxt_hwrm_ctx_rgtr(bp, bp->tx_fc_in_tbl.dma,
+                               &bp->tx_fc_in_tbl.ctx_id);
+       if (rc)
+               return rc;
+
+       PMD_DRV_LOG(DEBUG,
+                   "tx_fc_in_tbl.va = %p tx_fc_in_tbl.dma = %p"
+                   " tx_fc_in_tbl.ctx_id = %d\n",
+                   bp->tx_fc_in_tbl.va,
+                   (void *)((uintptr_t)bp->tx_fc_in_tbl.dma),
+                   bp->tx_fc_in_tbl.ctx_id);
+
+       rc = bnxt_hwrm_ctx_rgtr(bp, bp->tx_fc_out_tbl.dma,
+                               &bp->tx_fc_out_tbl.ctx_id);
+       if (rc)
+               return rc;
+
+       PMD_DRV_LOG(DEBUG,
+                   "tx_fc_out_tbl.va = %p tx_fc_out_tbl.dma = %p"
+                   " tx_fc_out_tbl.ctx_id = %d\n",
+                   bp->tx_fc_out_tbl.va,
+                   (void *)((uintptr_t)bp->tx_fc_out_tbl.dma),
+                   bp->tx_fc_out_tbl.ctx_id);
+
+       memset(bp->rx_fc_out_tbl.va, 0, bp->rx_fc_out_tbl.size);
+       rc = bnxt_hwrm_cfa_counter_cfg(bp, BNXT_DIR_RX,
+                                      CFA_COUNTER_CFG_IN_COUNTER_TYPE_FC,
+                                      bp->rx_fc_out_tbl.ctx_id,
+                                      bp->max_fc,
+                                      true);
+       if (rc)
+               return rc;
+
+       memset(bp->tx_fc_out_tbl.va, 0, bp->tx_fc_out_tbl.size);
+       rc = bnxt_hwrm_cfa_counter_cfg(bp, BNXT_DIR_TX,
+                                      CFA_COUNTER_CFG_IN_COUNTER_TYPE_FC,
+                                      bp->tx_fc_out_tbl.ctx_id,
+                                      bp->max_fc,
+                                      true);
+
+       return rc;
+}
+
+static int bnxt_alloc_ctx_mem_buf(char *type, size_t size,
+                                 struct bnxt_ctx_mem_buf_info *ctx)
+{
+       if (!ctx)
+               return -EINVAL;
+
+       ctx->va = rte_zmalloc(type, size, 0);
+       if (ctx->va == NULL)
+               return -ENOMEM;
+       rte_mem_lock_page(ctx->va);
+       ctx->size = size;
+       ctx->dma = rte_mem_virt2iova(ctx->va);
+       if (ctx->dma == RTE_BAD_IOVA)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
+{
+       struct rte_pci_device *pdev = bp->pdev;
+       char type[RTE_MEMZONE_NAMESIZE];
+       uint16_t max_fc;
+       int rc = 0;
+
+       max_fc = bp->max_fc;
+
+       sprintf(type, "bnxt_rx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
+               pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+       /* 4 bytes for each counter-id */
+       rc = bnxt_alloc_ctx_mem_buf(type, max_fc * 4, &bp->rx_fc_in_tbl);
+       if (rc)
+               return rc;
+
+       sprintf(type, "bnxt_rx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
+               pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+       /* 16 bytes for each counter - 8 bytes pkt_count, 8 bytes byte_count */
+       rc = bnxt_alloc_ctx_mem_buf(type, max_fc * 16, &bp->rx_fc_out_tbl);
+       if (rc)
+               return rc;
+
+       sprintf(type, "bnxt_tx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
+               pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+       /* 4 bytes for each counter-id */
+       rc = bnxt_alloc_ctx_mem_buf(type, max_fc * 4, &bp->tx_fc_in_tbl);
+       if (rc)
+               return rc;
+
+       sprintf(type, "bnxt_tx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
+               pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+       /* 16 bytes for each counter - 8 bytes pkt_count, 8 bytes byte_count */
+       rc = bnxt_alloc_ctx_mem_buf(type, max_fc * 16, &bp->tx_fc_out_tbl);
+       if (rc)
+               return rc;
+
+       rc = bnxt_register_fc_ctx_mem(bp);
+
+       return rc;
+}
+
+static int bnxt_init_ctx_mem(struct bnxt *bp)
+{
+       int rc = 0;
+
+       if (!(bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_COUNTERS) ||
+           !(BNXT_PF(bp) || BNXT_VF_IS_TRUSTED(bp)))
+               return 0;
+
+       rc = bnxt_hwrm_cfa_counter_qcaps(bp, &bp->max_fc);
+       if (rc)
+               return rc;
+
+       rc = bnxt_init_fc_ctx_mem(bp);
+
+       return rc;
+}
+
 static int bnxt_init_chip(struct bnxt *bp)
 {
        struct rte_eth_link new;
@@ -774,7 +944,8 @@ bnxt_receive_function(struct rte_eth_dev *eth_dev)
                DEV_RX_OFFLOAD_TCP_CKSUM |
                DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM |
                DEV_RX_OFFLOAD_RSS_HASH |
-               DEV_RX_OFFLOAD_VLAN_FILTER))) {
+               DEV_RX_OFFLOAD_VLAN_FILTER)) &&
+           !bp->truflow) {
                PMD_DRV_LOG(INFO, "Using vector mode receive for port %d\n",
                            eth_dev->data->port_id);
                bp->flags |= BNXT_FLAG_RX_VECTOR_PKT_MODE;
@@ -890,6 +1061,10 @@ static int bnxt_dev_start_op(struct rte_eth_dev *eth_dev)
        pthread_mutex_lock(&bp->def_cp_lock);
        bnxt_schedule_fw_health_check(bp);
        pthread_mutex_unlock(&bp->def_cp_lock);
+
+       if (bp->truflow)
+               bnxt_ulp_init(bp);
+
        return 0;
 
 error:
@@ -933,6 +1108,9 @@ static void bnxt_dev_stop_op(struct rte_eth_dev *eth_dev)
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
+       if (bp->truflow)
+               bnxt_ulp_deinit(bp);
+
        eth_dev->data->dev_started = 0;
        /* Prevent crashes when queues are still in use */
        eth_dev->rx_pkt_burst = &bnxt_dummy_recv_pkts;
@@ -980,6 +1158,11 @@ static void bnxt_dev_close_op(struct rte_eth_dev *eth_dev)
 {
        struct bnxt *bp = eth_dev->data->dev_private;
 
+       /* cancel the recovery handler before remove dev */
+       rte_eal_alarm_cancel(bnxt_dev_reset_and_resume, (void *)bp);
+       rte_eal_alarm_cancel(bnxt_dev_recover, (void *)bp);
+       bnxt_cancel_fc_thread(bp);
+
        if (eth_dev->data->dev_started)
                bnxt_dev_stop_op(eth_dev);
 
@@ -1103,6 +1286,10 @@ static int bnxt_mac_addr_add_op(struct rte_eth_dev *eth_dev,
                return -EINVAL;
        }
 
+       /* Filter settings will get applied when port is started */
+       if (!eth_dev->data->dev_started)
+               return 0;
+
        rc = bnxt_add_mac_filter(bp, vnic, mac_addr, index, pool);
 
        return rc;
@@ -2094,6 +2281,10 @@ bnxt_set_default_mac_addr_op(struct rte_eth_dev *dev,
        if (rte_is_zero_ether_addr(addr))
                return -EINVAL;
 
+       /* Filter settings will get applied when port is started */
+       if (!dev->data->dev_started)
+               return 0;
+
        /* Check if the requested MAC is already added */
        if (memcmp(addr, bp->mac_addr, RTE_ETHER_ADDR_LEN) == 0)
                return 0;
@@ -3255,6 +3446,7 @@ bnxt_filter_ctrl_op(struct rte_eth_dev *dev,
                    enum rte_filter_type filter_type,
                    enum rte_filter_op filter_op, void *arg)
 {
+       struct bnxt *bp = dev->data->dev_private;
        int ret = 0;
 
        ret = is_bnxt_in_error(dev->data->dev_private);
@@ -3278,7 +3470,10 @@ bnxt_filter_ctrl_op(struct rte_eth_dev *dev,
        case RTE_ETH_FILTER_GENERIC:
                if (filter_op != RTE_ETH_FILTER_GET)
                        return -EINVAL;
-               *(const void **)arg = &bnxt_flow_ops;
+               if (bp->truflow)
+                       *(const void **)arg = &bnxt_ulp_rte_flow_ops;
+               else
+                       *(const void **)arg = &bnxt_flow_ops;
                break;
        default:
                PMD_DRV_LOG(ERR,
@@ -3998,7 +4193,7 @@ static void bnxt_dev_recover(void *arg)
        bp->flags &= ~BNXT_FLAG_FATAL_ERROR;
 
        do {
-               rc = bnxt_hwrm_ver_get(bp);
+               rc = bnxt_hwrm_ver_get(bp, SHORT_HWRM_CMD_TIMEOUT);
                if (rc == 0)
                        break;
                rte_delay_ms(BNXT_FW_READY_WAIT_INTERVAL);
@@ -4022,15 +4217,17 @@ static void bnxt_dev_recover(void *arg)
        rc = bnxt_dev_start_op(bp->eth_dev);
        if (rc) {
                PMD_DRV_LOG(ERR, "Failed to start port after reset\n");
-               goto err;
+               goto err_start;
        }
 
        rc = bnxt_restore_filters(bp);
        if (rc)
-               goto err;
+               goto err_start;
 
        PMD_DRV_LOG(INFO, "Recovered from FW reset\n");
        return;
+err_start:
+       bnxt_dev_stop_op(bp->eth_dev);
 err:
        bp->flags |= BNXT_FLAG_FATAL_ERROR;
        bnxt_uninit_resources(bp, false);
@@ -4681,6 +4878,33 @@ static void bnxt_config_vf_req_fwd(struct bnxt *bp)
        ALLOW_FUNC(HWRM_VNIC_TPA_CFG);
 }
 
+uint16_t
+bnxt_get_svif(uint16_t port_id, bool func_svif)
+{
+       struct rte_eth_dev *eth_dev;
+       struct bnxt *bp;
+
+       eth_dev = &rte_eth_devices[port_id];
+       bp = eth_dev->data->dev_private;
+
+       return func_svif ? bp->func_svif : bp->port_svif;
+}
+
+uint16_t
+bnxt_get_vnic_id(uint16_t port)
+{
+       struct rte_eth_dev *eth_dev;
+       struct bnxt_vnic_info *vnic;
+       struct bnxt *bp;
+
+       eth_dev = &rte_eth_devices[port];
+       bp = eth_dev->data->dev_private;
+
+       vnic = BNXT_GET_DEFAULT_VNIC(bp);
+
+       return vnic->fw_vnic_id;
+}
+
 static int bnxt_init_fw(struct bnxt *bp)
 {
        uint16_t mtu;
@@ -4688,7 +4912,7 @@ static int bnxt_init_fw(struct bnxt *bp)
 
        bp->fw_cap = 0;
 
-       rc = bnxt_hwrm_ver_get(bp);
+       rc = bnxt_hwrm_ver_get(bp, DFLT_HWRM_CMD_TIMEOUT);
        if (rc)
                return rc;
 
@@ -4716,6 +4940,8 @@ static int bnxt_init_fw(struct bnxt *bp)
        if (rc)
                return rc;
 
+       bnxt_hwrm_port_mac_qcfg(bp);
+
        rc = bnxt_hwrm_cfa_adv_flow_mgmt_qcaps(bp);
        if (rc)
                return rc;
@@ -4802,6 +5028,12 @@ static int bnxt_init_resources(struct bnxt *bp, bool reconfig_dev)
        if (rc)
                return rc;
 
+       rc = bnxt_init_ctx_mem(bp);
+       if (rc) {
+               PMD_DRV_LOG(ERR, "Failed to init adv_flow_counters\n");
+               return rc;
+       }
+
        rc = bnxt_init_locks(bp);
        if (rc)
                return rc;
@@ -4809,6 +5041,105 @@ static int bnxt_init_resources(struct bnxt *bp, bool reconfig_dev)
        return 0;
 }
 
+static int
+bnxt_parse_devarg_truflow(__rte_unused const char *key,
+                         const char *value, void *opaque_arg)
+{
+       struct bnxt *bp = opaque_arg;
+       unsigned long truflow;
+       char *end = NULL;
+
+       if (!value || !opaque_arg) {
+               PMD_DRV_LOG(ERR,
+                           "Invalid parameter passed to truflow devargs.\n");
+               return -EINVAL;
+       }
+
+       truflow = strtoul(value, &end, 10);
+       if (end == NULL || *end != '\0' ||
+           (truflow == ULONG_MAX && errno == ERANGE)) {
+               PMD_DRV_LOG(ERR,
+                           "Invalid parameter passed to truflow devargs.\n");
+               return -EINVAL;
+       }
+
+       if (BNXT_DEVARG_TRUFLOW_INVALID(truflow)) {
+               PMD_DRV_LOG(ERR,
+                           "Invalid value passed to truflow devargs.\n");
+               return -EINVAL;
+       }
+
+       bp->truflow = truflow;
+       if (bp->truflow)
+               PMD_DRV_LOG(INFO, "Host-based truflow feature enabled.\n");
+
+       return 0;
+}
+
+static int
+bnxt_parse_devarg_flow_xstat(__rte_unused const char *key,
+                            const char *value, void *opaque_arg)
+{
+       struct bnxt *bp = opaque_arg;
+       unsigned long flow_xstat;
+       char *end = NULL;
+
+       if (!value || !opaque_arg) {
+               PMD_DRV_LOG(ERR,
+                           "Invalid parameter passed to flow_xstat devarg.\n");
+               return -EINVAL;
+       }
+
+       flow_xstat = strtoul(value, &end, 10);
+       if (end == NULL || *end != '\0' ||
+           (flow_xstat == ULONG_MAX && errno == ERANGE)) {
+               PMD_DRV_LOG(ERR,
+                           "Invalid parameter passed to flow_xstat devarg.\n");
+               return -EINVAL;
+       }
+
+       if (BNXT_DEVARG_FLOW_XSTAT_INVALID(flow_xstat)) {
+               PMD_DRV_LOG(ERR,
+                           "Invalid value passed to flow_xstat devarg.\n");
+               return -EINVAL;
+       }
+
+       bp->flow_xstat = flow_xstat;
+       if (bp->flow_xstat)
+               PMD_DRV_LOG(INFO, "flow_xstat feature enabled.\n");
+
+       return 0;
+}
+
+static void
+bnxt_parse_dev_args(struct bnxt *bp, struct rte_devargs *devargs)
+{
+       struct rte_kvargs *kvlist;
+
+       if (devargs == NULL)
+               return;
+
+       kvlist = rte_kvargs_parse(devargs->args, bnxt_dev_args);
+       if (kvlist == NULL)
+               return;
+
+       /*
+        * Handler for "truflow" devarg.
+        * Invoked as for ex: "-w 0000:00:0d.0,host-based-truflow=1”
+        */
+       rte_kvargs_process(kvlist, BNXT_DEVARG_TRUFLOW,
+                          bnxt_parse_devarg_truflow, bp);
+
+       /*
+        * Handler for "flow_xstat" devarg.
+        * Invoked as for ex: "-w 0000:00:0d.0,flow_xstat=1”
+        */
+       rte_kvargs_process(kvlist, BNXT_DEVARG_FLOW_XSTAT,
+                          bnxt_parse_devarg_flow_xstat, bp);
+
+       rte_kvargs_free(kvlist);
+}
+
 static int
 bnxt_dev_init(struct rte_eth_dev *eth_dev)
 {
@@ -4835,6 +5166,9 @@ bnxt_dev_init(struct rte_eth_dev *eth_dev)
 
        bp = eth_dev->data->dev_private;
 
+       /* Parse dev arguments passed on when starting the DPDK application. */
+       bnxt_parse_dev_args(bp, pci_dev->device.devargs);
+
        bp->flags &= ~BNXT_FLAG_RX_VECTOR_PKT_MODE;
 
        if (bnxt_vf_pciid(pci_dev->id.device_id))
@@ -4887,6 +5221,66 @@ error_free:
        return rc;
 }
 
+
+static void bnxt_free_ctx_mem_buf(struct bnxt_ctx_mem_buf_info *ctx)
+{
+       if (!ctx)
+               return;
+
+       if (ctx->va)
+               rte_free(ctx->va);
+
+       ctx->va = NULL;
+       ctx->dma = RTE_BAD_IOVA;
+       ctx->ctx_id = BNXT_CTX_VAL_INVAL;
+}
+
+static void bnxt_unregister_fc_ctx_mem(struct bnxt *bp)
+{
+       bnxt_hwrm_cfa_counter_cfg(bp, BNXT_DIR_RX,
+                                 CFA_COUNTER_CFG_IN_COUNTER_TYPE_FC,
+                                 bp->rx_fc_out_tbl.ctx_id,
+                                 bp->max_fc,
+                                 false);
+
+       bnxt_hwrm_cfa_counter_cfg(bp, BNXT_DIR_TX,
+                                 CFA_COUNTER_CFG_IN_COUNTER_TYPE_FC,
+                                 bp->tx_fc_out_tbl.ctx_id,
+                                 bp->max_fc,
+                                 false);
+
+       if (bp->rx_fc_in_tbl.ctx_id != BNXT_CTX_VAL_INVAL)
+               bnxt_hwrm_ctx_unrgtr(bp, bp->rx_fc_in_tbl.ctx_id);
+       bp->rx_fc_in_tbl.ctx_id = BNXT_CTX_VAL_INVAL;
+
+       if (bp->rx_fc_out_tbl.ctx_id != BNXT_CTX_VAL_INVAL)
+               bnxt_hwrm_ctx_unrgtr(bp, bp->rx_fc_out_tbl.ctx_id);
+       bp->rx_fc_out_tbl.ctx_id = BNXT_CTX_VAL_INVAL;
+
+       if (bp->tx_fc_in_tbl.ctx_id != BNXT_CTX_VAL_INVAL)
+               bnxt_hwrm_ctx_unrgtr(bp, bp->tx_fc_in_tbl.ctx_id);
+       bp->tx_fc_in_tbl.ctx_id = BNXT_CTX_VAL_INVAL;
+
+       if (bp->tx_fc_out_tbl.ctx_id != BNXT_CTX_VAL_INVAL)
+               bnxt_hwrm_ctx_unrgtr(bp, bp->tx_fc_out_tbl.ctx_id);
+       bp->tx_fc_out_tbl.ctx_id = BNXT_CTX_VAL_INVAL;
+}
+
+static void bnxt_uninit_fc_ctx_mem(struct bnxt *bp)
+{
+       bnxt_unregister_fc_ctx_mem(bp);
+
+       bnxt_free_ctx_mem_buf(&bp->rx_fc_in_tbl);
+       bnxt_free_ctx_mem_buf(&bp->rx_fc_out_tbl);
+       bnxt_free_ctx_mem_buf(&bp->tx_fc_in_tbl);
+       bnxt_free_ctx_mem_buf(&bp->tx_fc_out_tbl);
+}
+
+static void bnxt_uninit_ctx_mem(struct bnxt *bp)
+{
+       bnxt_uninit_fc_ctx_mem(bp);
+}
+
 static void
 bnxt_uninit_locks(struct bnxt *bp)
 {
@@ -4914,6 +5308,8 @@ bnxt_uninit_resources(struct bnxt *bp, bool reconfig_dev)
                }
        }
 
+       bnxt_uninit_ctx_mem(bp);
+
        bnxt_uninit_locks(bp);
        rte_free(bp->ptp_cfg);
        bp->ptp_cfg = NULL;