]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/spdk/dpdk/drivers/net/bnxt/bnxt_stats.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / dpdk / drivers / net / bnxt / bnxt_stats.c
index cae3b9ea27f72b959a360e59611c9e88df6744e9..cfe19328497ff23817c1c781d7cea412fcf5fea2 100644 (file)
 
 #include "bnxt.h"
 #include "bnxt_cpr.h"
+#include "bnxt_filter.h"
 #include "bnxt_hwrm.h"
 #include "bnxt_rxq.h"
 #include "bnxt_stats.h"
 #include "bnxt_txq.h"
+#include "bnxt_vnic.h"
 #include "hsi_struct_def_dpdk.h"
 
 static const struct bnxt_xstats_name_off bnxt_rx_stats_strings[] = {
@@ -55,32 +57,100 @@ static const struct bnxt_xstats_name_off bnxt_rx_stats_strings[] = {
                                rx_pause_frames)},
        {"rx_pfc_frames", offsetof(struct rx_port_stats,
                                rx_pfc_frames)},
+       {"rx_unsupported_opcode_frames", offsetof(struct rx_port_stats,
+                               rx_unsupported_opcode_frames)},
+       {"rx_unsupported_da_pausepfc_frames", offsetof(struct rx_port_stats,
+                               rx_unsupported_da_pausepfc_frames)},
+       {"rx_wrong_sa_frames", offsetof(struct rx_port_stats,
+                               rx_wrong_sa_frames)},
        {"rx_align_err_frames", offsetof(struct rx_port_stats,
                                rx_align_err_frames)},
+       {"rx_oor_len_frames", offsetof(struct rx_port_stats,
+                               rx_oor_len_frames)},
+       {"rx_code_err_frames", offsetof(struct rx_port_stats,
+                               rx_code_err_frames)},
+       {"rx_false_carrier_frames", offsetof(struct rx_port_stats,
+                               rx_false_carrier_frames)},
        {"rx_ovrsz_frames", offsetof(struct rx_port_stats,
                                rx_ovrsz_frames)},
        {"rx_jbr_frames", offsetof(struct rx_port_stats,
                                rx_jbr_frames)},
        {"rx_mtu_err_frames", offsetof(struct rx_port_stats,
                                rx_mtu_err_frames)},
+       {"rx_match_crc_frames", offsetof(struct rx_port_stats,
+                               rx_match_crc_frames)},
+       {"rx_promiscuous_frames", offsetof(struct rx_port_stats,
+                               rx_promiscuous_frames)},
        {"rx_tagged_frames", offsetof(struct rx_port_stats,
                                rx_tagged_frames)},
        {"rx_double_tagged_frames", offsetof(struct rx_port_stats,
                                rx_double_tagged_frames)},
+       {"rx_trunc_frames", offsetof(struct rx_port_stats,
+                               rx_trunc_frames)},
        {"rx_good_frames", offsetof(struct rx_port_stats,
                                rx_good_frames)},
+       {"rx_sch_crc_err_frames", offsetof(struct rx_port_stats,
+                               rx_sch_crc_err_frames)},
        {"rx_undrsz_frames", offsetof(struct rx_port_stats,
                                rx_undrsz_frames)},
+       {"rx_frag_frames", offsetof(struct rx_port_stats,
+                               rx_frag_frames)},
        {"rx_eee_lpi_events", offsetof(struct rx_port_stats,
                                rx_eee_lpi_events)},
        {"rx_eee_lpi_duration", offsetof(struct rx_port_stats,
                                rx_eee_lpi_duration)},
+       {"rx_llfc_physical_msgs", offsetof(struct rx_port_stats,
+                               rx_llfc_physical_msgs)},
+       {"rx_llfc_logical_msgs", offsetof(struct rx_port_stats,
+                               rx_llfc_logical_msgs)},
+       {"rx_llfc_msgs_with_crc_err", offsetof(struct rx_port_stats,
+                               rx_llfc_msgs_with_crc_err)},
+       {"rx_hcfc_msgs", offsetof(struct rx_port_stats,
+                               rx_hcfc_msgs)},
+       {"rx_hcfc_msgs_with_crc_err", offsetof(struct rx_port_stats,
+                               rx_hcfc_msgs_with_crc_err)},
        {"rx_bytes", offsetof(struct rx_port_stats,
                                rx_bytes)},
        {"rx_runt_bytes", offsetof(struct rx_port_stats,
                                rx_runt_bytes)},
        {"rx_runt_frames", offsetof(struct rx_port_stats,
                                rx_runt_frames)},
+       {"rx_pfc_xon2xoff_frames_pri0", offsetof(struct rx_port_stats,
+                               rx_pfc_xon2xoff_frames_pri0)},
+       {"rx_pfc_xon2xoff_frames_pri1", offsetof(struct rx_port_stats,
+                               rx_pfc_xon2xoff_frames_pri1)},
+       {"rx_pfc_xon2xoff_frames_pri2", offsetof(struct rx_port_stats,
+                               rx_pfc_xon2xoff_frames_pri2)},
+       {"rx_pfc_xon2xoff_frames_pri3", offsetof(struct rx_port_stats,
+                               rx_pfc_xon2xoff_frames_pri3)},
+       {"rx_pfc_xon2xoff_frames_pri4", offsetof(struct rx_port_stats,
+                               rx_pfc_xon2xoff_frames_pri4)},
+       {"rx_pfc_xon2xoff_frames_pri5", offsetof(struct rx_port_stats,
+                               rx_pfc_xon2xoff_frames_pri5)},
+       {"rx_pfc_xon2xoff_frames_pri6", offsetof(struct rx_port_stats,
+                               rx_pfc_xon2xoff_frames_pri6)},
+       {"rx_pfc_xon2xoff_frames_pri7", offsetof(struct rx_port_stats,
+                               rx_pfc_xon2xoff_frames_pri7)},
+       {"rx_pfc_ena_frames_pri0", offsetof(struct rx_port_stats,
+                               rx_pfc_ena_frames_pri0)},
+       {"rx_pfc_ena_frames_pri1", offsetof(struct rx_port_stats,
+                               rx_pfc_ena_frames_pri1)},
+       {"rx_pfc_ena_frames_pri2", offsetof(struct rx_port_stats,
+                               rx_pfc_ena_frames_pri2)},
+       {"rx_pfc_ena_frames_pri3", offsetof(struct rx_port_stats,
+                               rx_pfc_ena_frames_pri3)},
+       {"rx_pfc_ena_frames_pri4", offsetof(struct rx_port_stats,
+                               rx_pfc_ena_frames_pri4)},
+       {"rx_pfc_ena_frames_pri5", offsetof(struct rx_port_stats,
+                               rx_pfc_ena_frames_pri5)},
+       {"rx_pfc_ena_frames_pri6", offsetof(struct rx_port_stats,
+                               rx_pfc_ena_frames_pri6)},
+       {"rx_pfc_ena_frames_pri7", offsetof(struct rx_port_stats,
+                               rx_pfc_ena_frames_pri7)},
+       {"rx_stat_discard", offsetof(struct rx_port_stats,
+                               rx_stat_discard)},
+       {"rx_stat_err", offsetof(struct rx_port_stats,
+                               rx_stat_err)},
 };
 
 static const struct bnxt_xstats_name_off bnxt_tx_stats_strings[] = {
@@ -124,8 +194,32 @@ static const struct bnxt_xstats_name_off bnxt_tx_stats_strings[] = {
                                tx_jabber_frames)},
        {"tx_fcs_err_frames", offsetof(struct tx_port_stats,
                                tx_fcs_err_frames)},
+       {"tx_control_frames", offsetof(struct tx_port_stats,
+                               tx_control_frames)},
+       {"tx_oversz_frames", offsetof(struct tx_port_stats,
+                               tx_oversz_frames)},
+       {"tx_single_dfrl_frames", offsetof(struct tx_port_stats,
+                               tx_single_dfrl_frames)},
+       {"tx_multi_dfrl_frames", offsetof(struct tx_port_stats,
+                               tx_multi_dfrl_frames)},
+       {"tx_single_coll_frames", offsetof(struct tx_port_stats,
+                               tx_single_coll_frames)},
+       {"tx_multi_coll_frames", offsetof(struct tx_port_stats,
+                               tx_multi_coll_frames)},
+       {"tx_late_coll_frames", offsetof(struct tx_port_stats,
+                               tx_late_coll_frames)},
+       {"tx_excessive_coll_frames", offsetof(struct tx_port_stats,
+                               tx_excessive_coll_frames)},
+       {"tx_frag_frames", offsetof(struct tx_port_stats,
+                               tx_frag_frames)},
        {"tx_err", offsetof(struct tx_port_stats,
                                tx_err)},
+       {"tx_tagged_frames", offsetof(struct tx_port_stats,
+                               tx_tagged_frames)},
+       {"tx_dbl_tagged_frames", offsetof(struct tx_port_stats,
+                               tx_dbl_tagged_frames)},
+       {"tx_runt_frames", offsetof(struct tx_port_stats,
+                               tx_runt_frames)},
        {"tx_fifo_underruns", offsetof(struct tx_port_stats,
                                tx_fifo_underruns)},
        {"tx_eee_lpi_events", offsetof(struct tx_port_stats,
@@ -136,6 +230,32 @@ static const struct bnxt_xstats_name_off bnxt_tx_stats_strings[] = {
                                tx_total_collisions)},
        {"tx_bytes", offsetof(struct tx_port_stats,
                                tx_bytes)},
+       {"tx_pfc_ena_frames_pri0", offsetof(struct tx_port_stats,
+                               tx_pfc_ena_frames_pri0)},
+       {"tx_pfc_ena_frames_pri1", offsetof(struct tx_port_stats,
+                               tx_pfc_ena_frames_pri1)},
+       {"tx_pfc_ena_frames_pri2", offsetof(struct tx_port_stats,
+                               tx_pfc_ena_frames_pri2)},
+       {"tx_pfc_ena_frames_pri3", offsetof(struct tx_port_stats,
+                               tx_pfc_ena_frames_pri3)},
+       {"tx_pfc_ena_frames_pri4", offsetof(struct tx_port_stats,
+                               tx_pfc_ena_frames_pri4)},
+       {"tx_pfc_ena_frames_pri5", offsetof(struct tx_port_stats,
+                               tx_pfc_ena_frames_pri5)},
+       {"tx_pfc_ena_frames_pri6", offsetof(struct tx_port_stats,
+                               tx_pfc_ena_frames_pri6)},
+       {"tx_pfc_ena_frames_pri7", offsetof(struct tx_port_stats,
+                               tx_pfc_ena_frames_pri7)},
+       {"tx_llfc_logical_msgs", offsetof(struct tx_port_stats,
+                               tx_llfc_logical_msgs)},
+       {"tx_hcfc_msgs", offsetof(struct tx_port_stats,
+                               tx_hcfc_msgs)},
+       {"tx_xthol_frames", offsetof(struct tx_port_stats,
+                               tx_xthol_frames)},
+       {"tx_stat_discard", offsetof(struct tx_port_stats,
+                               tx_stat_discard)},
+       {"tx_stat_error", offsetof(struct tx_port_stats,
+                               tx_stat_error)},
 };
 
 static const struct bnxt_xstats_name_off bnxt_func_stats_strings[] = {
@@ -181,6 +301,7 @@ static const struct bnxt_xstats_name_off bnxt_func_stats_strings[] = {
                                rx_agg_aborts)},
 };
 
+
 static const struct bnxt_xstats_name_off bnxt_rx_ext_stats_strings[] = {
        {"link_down_events", offsetof(struct rx_port_stats_ext,
                                link_down_events)},
@@ -256,6 +377,46 @@ static const struct bnxt_xstats_name_off bnxt_rx_ext_stats_strings[] = {
                                pfc_pri7_rx_duration_us)},
        {"pfc_pri7_rx_transitions", offsetof(struct rx_port_stats_ext,
                                pfc_pri7_rx_transitions)},
+       {"rx_bits",             offsetof(struct rx_port_stats_ext,
+                               rx_bits)},
+       {"rx_buffer_passed_threshold", offsetof(struct rx_port_stats_ext,
+                               rx_buffer_passed_threshold)},
+       {"rx_pcs_symbol_err",   offsetof(struct rx_port_stats_ext,
+                               rx_pcs_symbol_err)},
+       {"rx_corrected_bits",   offsetof(struct rx_port_stats_ext,
+                               rx_corrected_bits)},
+       {"rx_discard_bytes_cos0", offsetof(struct rx_port_stats_ext,
+                               rx_discard_bytes_cos0)},
+       {"rx_discard_bytes_cos1", offsetof(struct rx_port_stats_ext,
+                               rx_discard_bytes_cos1)},
+       {"rx_discard_bytes_cos2", offsetof(struct rx_port_stats_ext,
+                               rx_discard_bytes_cos2)},
+       {"rx_discard_bytes_cos3", offsetof(struct rx_port_stats_ext,
+                               rx_discard_bytes_cos3)},
+       {"rx_discard_bytes_cos4", offsetof(struct rx_port_stats_ext,
+                               rx_discard_bytes_cos4)},
+       {"rx_discard_bytes_cos5", offsetof(struct rx_port_stats_ext,
+                               rx_discard_bytes_cos5)},
+       {"rx_discard_bytes_cos6", offsetof(struct rx_port_stats_ext,
+                               rx_discard_bytes_cos6)},
+       {"rx_discard_bytes_cos7", offsetof(struct rx_port_stats_ext,
+                               rx_discard_bytes_cos7)},
+       {"rx_discard_packets_cos0", offsetof(struct rx_port_stats_ext,
+                               rx_discard_packets_cos0)},
+       {"rx_discard_packets_cos1", offsetof(struct rx_port_stats_ext,
+                               rx_discard_packets_cos1)},
+       {"rx_discard_packets_cos2", offsetof(struct rx_port_stats_ext,
+                               rx_discard_packets_cos2)},
+       {"rx_discard_packets_cos3", offsetof(struct rx_port_stats_ext,
+                               rx_discard_packets_cos3)},
+       {"rx_discard_packets_cos4", offsetof(struct rx_port_stats_ext,
+                               rx_discard_packets_cos4)},
+       {"rx_discard_packets_cos5", offsetof(struct rx_port_stats_ext,
+                               rx_discard_packets_cos5)},
+       {"rx_discard_packets_cos6", offsetof(struct rx_port_stats_ext,
+                               rx_discard_packets_cos6)},
+       {"rx_discard_packets_cos7", offsetof(struct rx_port_stats_ext,
+                               rx_discard_packets_cos7)},
 };
 
 static const struct bnxt_xstats_name_off bnxt_tx_ext_stats_strings[] = {
@@ -351,14 +512,19 @@ int bnxt_stats_get_op(struct rte_eth_dev *eth_dev,
        int rc = 0;
        unsigned int i;
        struct bnxt *bp = eth_dev->data->dev_private;
+       unsigned int num_q_stats;
 
-       memset(bnxt_stats, 0, sizeof(*bnxt_stats));
-       if (!(bp->flags & BNXT_FLAG_INIT_DONE)) {
-               PMD_DRV_LOG(ERR, "Device Initialization not complete!\n");
-               return -1;
-       }
+       rc = is_bnxt_in_error(bp);
+       if (rc)
+               return rc;
 
-       for (i = 0; i < bp->rx_cp_nr_rings; i++) {
+       if (!eth_dev->data->dev_started)
+               return -EIO;
+
+       num_q_stats = RTE_MIN(bp->rx_cp_nr_rings,
+                             (unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS);
+
+       for (i = 0; i < num_q_stats; i++) {
                struct bnxt_rx_queue *rxq = bp->rx_queues[i];
                struct bnxt_cp_ring_info *cpr = rxq->cp_ring;
 
@@ -370,7 +536,10 @@ int bnxt_stats_get_op(struct rte_eth_dev *eth_dev,
                                rte_atomic64_read(&rxq->rx_mbuf_alloc_fail);
        }
 
-       for (i = 0; i < bp->tx_cp_nr_rings; i++) {
+       num_q_stats = RTE_MIN(bp->tx_cp_nr_rings,
+                             (unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS);
+
+       for (i = 0; i < num_q_stats; i++) {
                struct bnxt_tx_queue *txq = bp->tx_queues[i];
                struct bnxt_cp_ring_info *cpr = txq->cp_ring;
 
@@ -379,52 +548,74 @@ int bnxt_stats_get_op(struct rte_eth_dev *eth_dev,
                if (unlikely(rc))
                        return rc;
        }
-       rc = bnxt_hwrm_func_qstats(bp, 0xffff, bnxt_stats);
-       if (unlikely(rc))
-               return rc;
+
+       rc = bnxt_hwrm_func_qstats(bp, 0xffff, bnxt_stats, NULL);
        return rc;
 }
 
-void bnxt_stats_reset_op(struct rte_eth_dev *eth_dev)
+int bnxt_stats_reset_op(struct rte_eth_dev *eth_dev)
 {
-       struct bnxt *bp = (struct bnxt *)eth_dev->data->dev_private;
+       struct bnxt *bp = eth_dev->data->dev_private;
        unsigned int i;
+       int ret;
 
-       if (!(bp->flags & BNXT_FLAG_INIT_DONE)) {
+       ret = is_bnxt_in_error(bp);
+       if (ret)
+               return ret;
+
+       if (!eth_dev->data->dev_started) {
                PMD_DRV_LOG(ERR, "Device Initialization not complete!\n");
-               return;
+               return -EINVAL;
        }
 
-       bnxt_clear_all_hwrm_stat_ctxs(bp);
+       ret = bnxt_clear_all_hwrm_stat_ctxs(bp);
        for (i = 0; i < bp->rx_cp_nr_rings; i++) {
                struct bnxt_rx_queue *rxq = bp->rx_queues[i];
 
                rte_atomic64_clear(&rxq->rx_mbuf_alloc_fail);
        }
+
+       return ret;
 }
 
 int bnxt_dev_xstats_get_op(struct rte_eth_dev *eth_dev,
                           struct rte_eth_xstat *xstats, unsigned int n)
 {
-       struct bnxt *bp = (struct bnxt *)eth_dev->data->dev_private;
-
+       struct bnxt *bp = eth_dev->data->dev_private;
        unsigned int count, i;
-       uint64_t tx_drop_pkts;
        unsigned int rx_port_stats_ext_cnt;
        unsigned int tx_port_stats_ext_cnt;
        unsigned int stat_size = sizeof(uint64_t);
+       struct hwrm_func_qstats_output func_qstats = {0};
        unsigned int stat_count;
+       int rc;
+
+       rc = is_bnxt_in_error(bp);
+       if (rc)
+               return rc;
 
+       if (xstats == NULL)
+               return 0;
+
+       memset(xstats, 0, sizeof(*xstats));
+
+       bnxt_hwrm_func_qstats(bp, 0xffff, NULL, &func_qstats);
        bnxt_hwrm_port_qstats(bp);
-       bnxt_hwrm_func_qstats_tx_drop(bp, 0xffff, &tx_drop_pkts);
        bnxt_hwrm_ext_port_qstats(bp);
-       rx_port_stats_ext_cnt = bp->fw_rx_port_stats_ext_size / stat_size;
-       tx_port_stats_ext_cnt = bp->fw_tx_port_stats_ext_size / stat_size;
+       rx_port_stats_ext_cnt = RTE_MIN(RTE_DIM(bnxt_rx_ext_stats_strings),
+                                       (bp->fw_rx_port_stats_ext_size /
+                                        stat_size));
+       tx_port_stats_ext_cnt = RTE_MIN(RTE_DIM(bnxt_tx_ext_stats_strings),
+                                       (bp->fw_tx_port_stats_ext_size /
+                                        stat_size));
 
        count = RTE_DIM(bnxt_rx_stats_strings) +
-               RTE_DIM(bnxt_tx_stats_strings) + 1/* For tx_drop_pkts */ +
+               RTE_DIM(bnxt_tx_stats_strings) +
+               RTE_DIM(bnxt_func_stats_strings) +
                RTE_DIM(bnxt_rx_ext_stats_strings) +
-               RTE_DIM(bnxt_tx_ext_stats_strings);
+               RTE_DIM(bnxt_tx_ext_stats_strings) +
+               bnxt_flow_stats_cnt(bp);
+
        stat_count = count;
 
        if (n < count)
@@ -449,10 +640,23 @@ int bnxt_dev_xstats_get_op(struct rte_eth_dev *eth_dev,
                count++;
        }
 
-       /* The Tx drop pkts aka the Anti spoof coounter */
-       xstats[count].id = count;
-       xstats[count].value = rte_le_to_cpu_64(tx_drop_pkts);
-       count++;
+       for (i = 0; i < RTE_DIM(bnxt_func_stats_strings); i++) {
+               xstats[count].id = count;
+               xstats[count].value =
+               rte_le_to_cpu_64(((uint64_t *)&func_qstats)[i]);
+               count++;
+       }
+
+
+       for (i = 0; i < rx_port_stats_ext_cnt; i++) {
+               uint64_t *rx_stats_ext = (uint64_t *)bp->hw_rx_port_stats_ext;
+
+               xstats[count].value = rte_le_to_cpu_64
+                                       (*(uint64_t *)((char *)rx_stats_ext +
+                                        bnxt_rx_ext_stats_strings[i].offset));
+
+               count++;
+       }
 
        for (i = 0; i < tx_port_stats_ext_cnt; i++) {
                uint64_t *tx_stats_ext = (uint64_t *)bp->hw_tx_port_stats_ext;
@@ -460,33 +664,82 @@ int bnxt_dev_xstats_get_op(struct rte_eth_dev *eth_dev,
                xstats[count].value = rte_le_to_cpu_64
                                        (*(uint64_t *)((char *)tx_stats_ext +
                                         bnxt_tx_ext_stats_strings[i].offset));
-
                count++;
        }
 
-       for (i = 0; i < rx_port_stats_ext_cnt; i++) {
-               uint64_t *rx_stats_ext = (uint64_t *)bp->hw_rx_port_stats_ext;
+       if (bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_COUNTERS &&
+           bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_MGMT &&
+           BNXT_FLOW_XSTATS_EN(bp)) {
+               int j;
 
-               xstats[count].value = rte_le_to_cpu_64
-                                       (*(uint64_t *)((char *)rx_stats_ext +
-                                        bnxt_rx_ext_stats_strings[i].offset));
+               i = 0;
+               for (j = 0; j < bp->max_vnics; j++) {
+                       struct bnxt_filter_info *filter;
+                       struct bnxt_vnic_info *vnic;
+                       struct rte_flow *flow;
 
-               count++;
+                       vnic = &bp->vnic_info[j];
+                       if (vnic && vnic->fw_vnic_id == INVALID_VNIC_ID)
+                               continue;
+
+                       if (STAILQ_EMPTY(&vnic->flow_list))
+                               continue;
+
+                       STAILQ_FOREACH(flow, &vnic->flow_list, next) {
+                               if (!flow || !flow->filter)
+                                       continue;
+
+                               filter = flow->filter;
+                               xstats[count].id = count;
+                               xstats[count].value =
+                                       filter->hw_stats.bytes;
+                               count++;
+                               xstats[count].id = count;
+                               xstats[count].value =
+                                       filter->hw_stats.packets;
+                               count++;
+                               if (++i > bp->max_l2_ctx)
+                                       break;
+                       }
+                       if (i > bp->max_l2_ctx)
+                               break;
+               }
        }
 
        return stat_count;
 }
 
-int bnxt_dev_xstats_get_names_op(__rte_unused struct rte_eth_dev *eth_dev,
-       struct rte_eth_xstat_name *xstats_names,
-       __rte_unused unsigned int limit)
+int bnxt_flow_stats_cnt(struct bnxt *bp)
+{
+       if (bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_COUNTERS &&
+           bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_MGMT &&
+           BNXT_FLOW_XSTATS_EN(bp)) {
+               struct bnxt_xstats_name_off flow_bytes[bp->max_l2_ctx];
+               struct bnxt_xstats_name_off flow_pkts[bp->max_l2_ctx];
+
+               return RTE_DIM(flow_bytes) + RTE_DIM(flow_pkts);
+       }
+
+       return 0;
+}
+
+int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
+               struct rte_eth_xstat_name *xstats_names,
+               __rte_unused unsigned int limit)
 {
-       /* Account for the Tx drop pkts aka the Anti spoof counter */
+       struct bnxt *bp = (struct bnxt *)eth_dev->data->dev_private;
        const unsigned int stat_cnt = RTE_DIM(bnxt_rx_stats_strings) +
-                               RTE_DIM(bnxt_tx_stats_strings) + 1 +
+                               RTE_DIM(bnxt_tx_stats_strings) +
+                               RTE_DIM(bnxt_func_stats_strings) +
                                RTE_DIM(bnxt_rx_ext_stats_strings) +
-                               RTE_DIM(bnxt_tx_ext_stats_strings);
-       unsigned int i, count;
+                               RTE_DIM(bnxt_tx_ext_stats_strings) +
+                               bnxt_flow_stats_cnt(bp);
+       unsigned int i, count = 0;
+       int rc;
+
+       rc = is_bnxt_in_error(bp);
+       if (rc)
+               return rc;
 
        if (xstats_names != NULL) {
                count = 0;
@@ -505,10 +758,12 @@ int bnxt_dev_xstats_get_names_op(__rte_unused struct rte_eth_dev *eth_dev,
                        count++;
                }
 
-               strlcpy(xstats_names[count].name,
-                       bnxt_func_stats_strings[4].name,
-                       sizeof(xstats_names[count].name));
-               count++;
+               for (i = 0; i < RTE_DIM(bnxt_func_stats_strings); i++) {
+                       strlcpy(xstats_names[count].name,
+                               bnxt_func_stats_strings[i].name,
+                               sizeof(xstats_names[count].name));
+                       count++;
+               }
 
                for (i = 0; i < RTE_DIM(bnxt_rx_ext_stats_strings); i++) {
                        strlcpy(xstats_names[count].name,
@@ -526,36 +781,70 @@ int bnxt_dev_xstats_get_names_op(__rte_unused struct rte_eth_dev *eth_dev,
                        count++;
                }
 
+               if (bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_COUNTERS &&
+                   bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_MGMT &&
+                   BNXT_FLOW_XSTATS_EN(bp)) {
+                       for (i = 0; i < bp->max_l2_ctx; i++) {
+                               char buf[RTE_ETH_XSTATS_NAME_SIZE];
+
+                               sprintf(buf, "flow_%d_bytes", i);
+                               strlcpy(xstats_names[count].name, buf,
+                                       sizeof(xstats_names[count].name));
+                               count++;
+
+                               sprintf(buf, "flow_%d_packets", i);
+                               strlcpy(xstats_names[count].name, buf,
+                                       sizeof(xstats_names[count].name));
+
+                               count++;
+                       }
+               }
        }
+
        return stat_cnt;
 }
 
-void bnxt_dev_xstats_reset_op(struct rte_eth_dev *eth_dev)
+int bnxt_dev_xstats_reset_op(struct rte_eth_dev *eth_dev)
 {
-       struct bnxt *bp = (struct bnxt *)eth_dev->data->dev_private;
+       struct bnxt *bp = eth_dev->data->dev_private;
+       int ret;
 
-       if (bp->flags & BNXT_FLAG_PORT_STATS && BNXT_SINGLE_PF(bp))
-               bnxt_hwrm_port_clr_stats(bp);
+       ret = is_bnxt_in_error(bp);
+       if (ret)
+               return ret;
 
-       if (BNXT_VF(bp))
-               PMD_DRV_LOG(ERR, "Operation not supported on a VF device\n");
-       if (!BNXT_SINGLE_PF(bp))
-               PMD_DRV_LOG(ERR, "Operation not supported on a MF device\n");
-       if (!(bp->flags & BNXT_FLAG_PORT_STATS))
+       if (BNXT_VF(bp) || !BNXT_SINGLE_PF(bp) ||
+           !(bp->flags & BNXT_FLAG_PORT_STATS)) {
                PMD_DRV_LOG(ERR, "Operation not supported\n");
+               return -ENOTSUP;
+       }
+
+       ret = bnxt_hwrm_port_clr_stats(bp);
+       if (ret != 0)
+               PMD_DRV_LOG(ERR, "Failed to reset xstats: %s\n",
+                           strerror(-ret));
+
+       return ret;
 }
 
 int bnxt_dev_xstats_get_by_id_op(struct rte_eth_dev *dev, const uint64_t *ids,
                uint64_t *values, unsigned int limit)
 {
-       /* Account for the Tx drop pkts aka the Anti spoof counter */
+       struct bnxt *bp = dev->data->dev_private;
        const unsigned int stat_cnt = RTE_DIM(bnxt_rx_stats_strings) +
-                               RTE_DIM(bnxt_tx_stats_strings) + 1 +
+                               RTE_DIM(bnxt_tx_stats_strings) +
+                               RTE_DIM(bnxt_func_stats_strings) +
                                RTE_DIM(bnxt_rx_ext_stats_strings) +
-                               RTE_DIM(bnxt_tx_ext_stats_strings);
+                               RTE_DIM(bnxt_tx_ext_stats_strings) +
+                               bnxt_flow_stats_cnt(bp);
        struct rte_eth_xstat xstats[stat_cnt];
        uint64_t values_copy[stat_cnt];
        uint16_t i;
+       int rc;
+
+       rc = is_bnxt_in_error(bp);
+       if (rc)
+               return rc;
 
        if (!ids)
                return bnxt_dev_xstats_get_op(dev, xstats, stat_cnt);
@@ -564,7 +853,7 @@ int bnxt_dev_xstats_get_by_id_op(struct rte_eth_dev *dev, const uint64_t *ids,
        for (i = 0; i < limit; i++) {
                if (ids[i] >= stat_cnt) {
                        PMD_DRV_LOG(ERR, "id value isn't valid");
-                       return -1;
+                       return -EINVAL;
                }
                values[i] = values_copy[ids[i]];
        }
@@ -575,13 +864,20 @@ int bnxt_dev_xstats_get_names_by_id_op(struct rte_eth_dev *dev,
                                struct rte_eth_xstat_name *xstats_names,
                                const uint64_t *ids, unsigned int limit)
 {
-       /* Account for the Tx drop pkts aka the Anti spoof counter */
+       struct bnxt *bp = dev->data->dev_private;
        const unsigned int stat_cnt = RTE_DIM(bnxt_rx_stats_strings) +
-                               RTE_DIM(bnxt_tx_stats_strings) + 1 +
+                               RTE_DIM(bnxt_tx_stats_strings) +
+                               RTE_DIM(bnxt_func_stats_strings) +
                                RTE_DIM(bnxt_rx_ext_stats_strings) +
-                               RTE_DIM(bnxt_tx_ext_stats_strings);
+                               RTE_DIM(bnxt_tx_ext_stats_strings) +
+                               bnxt_flow_stats_cnt(bp);
        struct rte_eth_xstat_name xstats_names_copy[stat_cnt];
        uint16_t i;
+       int rc;
+
+       rc = is_bnxt_in_error(bp);
+       if (rc)
+               return rc;
 
        if (!ids)
                return bnxt_dev_xstats_get_names_op(dev, xstats_names,
@@ -592,10 +888,142 @@ int bnxt_dev_xstats_get_names_by_id_op(struct rte_eth_dev *dev,
        for (i = 0; i < limit; i++) {
                if (ids[i] >= stat_cnt) {
                        PMD_DRV_LOG(ERR, "id value isn't valid");
-                       return -1;
+                       return -EINVAL;
                }
                strcpy(xstats_names[i].name,
                                xstats_names_copy[ids[i]].name);
        }
        return stat_cnt;
 }
+
+/* Update the input context memory with the flow counter IDs
+ * of the flows that we are interested in.
+ * Also, update the output tables with the current local values
+ * since that is what will be used by FW to accumulate
+ */
+static void bnxt_update_fc_pre_qstat(uint32_t *in_tbl,
+                                    uint64_t *out_tbl,
+                                    struct bnxt_filter_info *filter,
+                                    uint32_t *ptbl_cnt)
+{
+       uint32_t in_tbl_cnt = *ptbl_cnt;
+
+       in_tbl[in_tbl_cnt] = filter->flow_id;
+       out_tbl[2 * in_tbl_cnt] = filter->hw_stats.packets;
+       out_tbl[2 * in_tbl_cnt + 1] = filter->hw_stats.bytes;
+       in_tbl_cnt++;
+       *ptbl_cnt = in_tbl_cnt;
+}
+
+/* Post issuing counter_qstats cmd, update the driver's local stat
+ * entries with the values DMA-ed by FW in the output table
+ */
+static void bnxt_update_fc_post_qstat(struct bnxt_filter_info *filter,
+                                     uint64_t *out_tbl,
+                                     uint32_t out_tbl_idx)
+{
+       filter->hw_stats.packets = out_tbl[2 * out_tbl_idx];
+       filter->hw_stats.bytes = out_tbl[(2 * out_tbl_idx) + 1];
+}
+
+static int bnxt_update_fc_tbl(struct bnxt *bp, uint16_t ctr,
+                             struct bnxt_filter_info *en_tbl[],
+                             uint16_t in_flow_cnt)
+{
+       uint32_t *in_rx_tbl;
+       uint64_t *out_rx_tbl;
+       uint32_t in_rx_tbl_cnt = 0;
+       uint32_t out_rx_tbl_cnt = 0;
+       int i, rc = 0;
+
+       in_rx_tbl = (uint32_t *)bp->flow_stat->rx_fc_in_tbl.va;
+       out_rx_tbl = (uint64_t *)bp->flow_stat->rx_fc_out_tbl.va;
+
+       for (i = 0; i < in_flow_cnt; i++) {
+               if (!en_tbl[i])
+                       continue;
+
+               /* Currently only ingress/Rx flows are supported anyway. */
+               bnxt_update_fc_pre_qstat(in_rx_tbl, out_rx_tbl,
+                                        en_tbl[i], &in_rx_tbl_cnt);
+       }
+
+       /* Currently only ingress/Rx flows are supported */
+       if (in_rx_tbl_cnt) {
+               rc = bnxt_hwrm_cfa_counter_qstats(bp, BNXT_DIR_RX, ctr,
+                                                 in_rx_tbl_cnt);
+               if (rc)
+                       return rc;
+       }
+
+       for (i = 0; i < in_flow_cnt; i++) {
+               if (!en_tbl[i])
+                       continue;
+
+               /* Currently only ingress/Rx flows are supported */
+               bnxt_update_fc_post_qstat(en_tbl[i], out_rx_tbl,
+                                         out_rx_tbl_cnt);
+               out_rx_tbl_cnt++;
+       }
+
+       return rc;
+}
+
+/* Walks through the list which has all the flows
+ * requesting for explicit flow counters.
+ */
+int bnxt_flow_stats_req(struct bnxt *bp)
+{
+       int i;
+       int rc = 0;
+       struct rte_flow *flow;
+       uint16_t in_flow_tbl_cnt = 0;
+       struct bnxt_vnic_info *vnic = NULL;
+       struct bnxt_filter_info *valid_en_tbl[bp->flow_stat->max_fc];
+       uint16_t counter_type = CFA_COUNTER_CFG_IN_COUNTER_TYPE_FC;
+
+       bnxt_acquire_flow_lock(bp);
+       for (i = 0; i < bp->max_vnics; i++) {
+               vnic = &bp->vnic_info[i];
+               if (vnic && vnic->fw_vnic_id == INVALID_VNIC_ID)
+                       continue;
+
+               if (STAILQ_EMPTY(&vnic->flow_list))
+                       continue;
+
+               STAILQ_FOREACH(flow, &vnic->flow_list, next) {
+                       if (!flow || !flow->filter)
+                               continue;
+
+                       valid_en_tbl[in_flow_tbl_cnt++] = flow->filter;
+                       if (in_flow_tbl_cnt >= bp->flow_stat->max_fc) {
+                               rc = bnxt_update_fc_tbl(bp, counter_type,
+                                                       valid_en_tbl,
+                                                       in_flow_tbl_cnt);
+                               if (rc)
+                                       goto err;
+                               in_flow_tbl_cnt = 0;
+                               continue;
+                       }
+               }
+       }
+
+       if (!in_flow_tbl_cnt)
+               goto out;
+
+       rc = bnxt_update_fc_tbl(bp, counter_type, valid_en_tbl,
+                               in_flow_tbl_cnt);
+       if (!rc) {
+               bnxt_release_flow_lock(bp);
+               return 0;
+       }
+
+err:
+       /* If cmd fails once, no need of
+        * invoking again every second
+        */
+       bnxt_release_flow_lock(bp);
+       bnxt_cancel_fc_thread(bp);
+out:
+       return rc;
+}