get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/96207/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 96207,
    "url": "http://patchwork.dpdk.org/api/patches/96207/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20210722095433.1898589-11-andrew.rybchenko@oktetlabs.ru/",
    "project": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20210722095433.1898589-11-andrew.rybchenko@oktetlabs.ru>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210722095433.1898589-11-andrew.rybchenko@oktetlabs.ru",
    "date": "2021-07-22T09:54:32",
    "name": "[v2,10/11] net/sfc: add xstats for Rx/Tx doorbells",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "a4b7d79dbbf3ab80b8c8c224e778a71472e9084f",
    "submitter": {
        "id": 2013,
        "url": "http://patchwork.dpdk.org/api/people/2013/?format=api",
        "name": "Andrew Rybchenko",
        "email": "Andrew.Rybchenko@oktetlabs.ru"
    },
    "delegate": {
        "id": 24651,
        "url": "http://patchwork.dpdk.org/api/users/24651/?format=api",
        "username": "dmarchand",
        "first_name": "David",
        "last_name": "Marchand",
        "email": "david.marchand@redhat.com"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/20210722095433.1898589-11-andrew.rybchenko@oktetlabs.ru/mbox/",
    "series": [
        {
            "id": 17954,
            "url": "http://patchwork.dpdk.org/api/series/17954/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=17954",
            "date": "2021-07-22T09:54:22",
            "name": "net/sfc: provide Rx/Tx doorbells stats",
            "version": 2,
            "mbox": "http://patchwork.dpdk.org/series/17954/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/96207/comments/",
    "check": "warning",
    "checks": "http://patchwork.dpdk.org/api/patches/96207/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 2BF88A0C4E;\n\tThu, 22 Jul 2021 11:55:52 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 3773B41142;\n\tThu, 22 Jul 2021 11:55:24 +0200 (CEST)",
            "from shelob.oktetlabs.ru (shelob.oktetlabs.ru [91.220.146.113])\n by mails.dpdk.org (Postfix) with ESMTP id 2F322410FC\n for <dev@dpdk.org>; Thu, 22 Jul 2021 11:55:23 +0200 (CEST)",
            "by shelob.oktetlabs.ru (Postfix, from userid 122)\n id 03B677F6E2; Thu, 22 Jul 2021 12:55:23 +0300 (MSK)",
            "from aros.oktetlabs.ru (aros.oktetlabs.ru [192.168.38.17])\n by shelob.oktetlabs.ru (Postfix) with ESMTP id 75F057F6CD;\n Thu, 22 Jul 2021 12:54:46 +0300 (MSK)"
        ],
        "X-Spam-Checker-Version": "SpamAssassin 3.4.2 (2018-09-13) on shelob.oktetlabs.ru",
        "X-Spam-Level": "",
        "X-Spam-Status": "No, score=0.8 required=5.0 tests=ALL_TRUSTED,\n DKIM_ADSP_DISCARD,\n URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2",
        "DKIM-Filter": "OpenDKIM Filter v2.11.0 shelob.oktetlabs.ru 75F057F6CD",
        "Authentication-Results": "shelob.oktetlabs.ru/75F057F6CD; dkim=none;\n dkim-atps=neutral",
        "From": "Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>",
        "To": "dev@dpdk.org",
        "Cc": "David Marchand <david.marchand@redhat.com>,\n Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>,\n Andy Moreton <amoreton@xilinx.com>",
        "Date": "Thu, 22 Jul 2021 12:54:32 +0300",
        "Message-Id": "<20210722095433.1898589-11-andrew.rybchenko@oktetlabs.ru>",
        "X-Mailer": "git-send-email 2.30.2",
        "In-Reply-To": "<20210722095433.1898589-1-andrew.rybchenko@oktetlabs.ru>",
        "References": "<20210604144225.287678-1-andrew.rybchenko@oktetlabs.ru>\n <20210722095433.1898589-1-andrew.rybchenko@oktetlabs.ru>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v2 10/11] net/sfc: add xstats for Rx/Tx doorbells",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>\n\nRx/Tx doorbells statistics are collected in software and\navailable per queue. These stats are useful for performance\ninvestigation.\n\nSigned-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>\nSigned-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>\nReviewed-by: Andy Moreton <amoreton@xilinx.com>\n---\n drivers/net/sfc/meson.build        |   1 +\n drivers/net/sfc/sfc.c              |  16 +\n drivers/net/sfc/sfc.h              |   9 +\n drivers/net/sfc/sfc_dp.h           |  10 +\n drivers/net/sfc/sfc_ef10.h         |   3 +-\n drivers/net/sfc/sfc_ef100_rx.c     |   1 +\n drivers/net/sfc/sfc_ef100_tx.c     |   1 +\n drivers/net/sfc/sfc_ef10_essb_rx.c |   3 +-\n drivers/net/sfc/sfc_ef10_rx.c      |   3 +-\n drivers/net/sfc/sfc_ef10_tx.c      |   1 +\n drivers/net/sfc/sfc_ethdev.c       | 124 +++++--\n drivers/net/sfc/sfc_port.c         |  10 +-\n drivers/net/sfc/sfc_rx.c           |   1 +\n drivers/net/sfc/sfc_sw_stats.c     | 572 +++++++++++++++++++++++++++++\n drivers/net/sfc/sfc_sw_stats.h     |  49 +++\n drivers/net/sfc/sfc_tx.c           |   4 +-\n 16 files changed, 772 insertions(+), 36 deletions(-)\n create mode 100644 drivers/net/sfc/sfc_sw_stats.c\n create mode 100644 drivers/net/sfc/sfc_sw_stats.h",
    "diff": "diff --git a/drivers/net/sfc/meson.build b/drivers/net/sfc/meson.build\nindex 4625859077..a912cdccfa 100644\n--- a/drivers/net/sfc/meson.build\n+++ b/drivers/net/sfc/meson.build\n@@ -70,6 +70,7 @@ sources = files(\n         'sfc.c',\n         'sfc_mcdi.c',\n         'sfc_sriov.c',\n+        'sfc_sw_stats.c',\n         'sfc_intr.c',\n         'sfc_ev.c',\n         'sfc_port.c',\ndiff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c\nindex 4097cf39de..274a98e228 100644\n--- a/drivers/net/sfc/sfc.c\n+++ b/drivers/net/sfc/sfc.c\n@@ -24,6 +24,7 @@\n #include \"sfc_tx.h\"\n #include \"sfc_kvargs.h\"\n #include \"sfc_tweak.h\"\n+#include \"sfc_sw_stats.h\"\n \n \n int\n@@ -636,10 +637,17 @@ sfc_configure(struct sfc_adapter *sa)\n \tif (rc != 0)\n \t\tgoto fail_tx_configure;\n \n+\trc = sfc_sw_xstats_configure(sa);\n+\tif (rc != 0)\n+\t\tgoto fail_sw_xstats_configure;\n+\n \tsa->state = SFC_ADAPTER_CONFIGURED;\n \tsfc_log_init(sa, \"done\");\n \treturn 0;\n \n+fail_sw_xstats_configure:\n+\tsfc_tx_close(sa);\n+\n fail_tx_configure:\n \tsfc_rx_close(sa);\n \n@@ -666,6 +674,7 @@ sfc_close(struct sfc_adapter *sa)\n \tSFC_ASSERT(sa->state == SFC_ADAPTER_CONFIGURED);\n \tsa->state = SFC_ADAPTER_CLOSING;\n \n+\tsfc_sw_xstats_close(sa);\n \tsfc_tx_close(sa);\n \tsfc_rx_close(sa);\n \tsfc_port_close(sa);\n@@ -891,6 +900,10 @@ sfc_attach(struct sfc_adapter *sa)\n \n \tsfc_flow_init(sa);\n \n+\trc = sfc_sw_xstats_init(sa);\n+\tif (rc != 0)\n+\t\tgoto fail_sw_xstats_init;\n+\n \t/*\n \t * Create vSwitch to be able to use VFs when PF is not started yet\n \t * as DPDK port. VFs should be able to talk to each other even\n@@ -906,6 +919,9 @@ sfc_attach(struct sfc_adapter *sa)\n \treturn 0;\n \n fail_sriov_vswitch_create:\n+\tsfc_sw_xstats_close(sa);\n+\n+fail_sw_xstats_init:\n \tsfc_flow_fini(sa);\n \tsfc_mae_detach(sa);\n \ndiff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h\nindex 58b8c2c2ad..331e06bac6 100644\n--- a/drivers/net/sfc/sfc.h\n+++ b/drivers/net/sfc/sfc.h\n@@ -217,6 +217,14 @@ struct sfc_counter_rxq {\n \tstruct rte_mempool\t\t*mp;\n };\n \n+struct sfc_sw_xstats {\n+\tuint64_t\t\t\t*reset_vals;\n+\n+\trte_spinlock_t\t\t\tqueues_bitmap_lock;\n+\tvoid\t\t\t\t*queues_bitmap_mem;\n+\tstruct rte_bitmap\t\t*queues_bitmap;\n+};\n+\n /* Adapter private data */\n struct sfc_adapter {\n \t/*\n@@ -249,6 +257,7 @@ struct sfc_adapter {\n \tstruct sfc_sriov\t\tsriov;\n \tstruct sfc_intr\t\t\tintr;\n \tstruct sfc_port\t\t\tport;\n+\tstruct sfc_sw_xstats\t\tsw_xstats;\n \tstruct sfc_filter\t\tfilter;\n \tstruct sfc_mae\t\t\tmae;\n \ndiff --git a/drivers/net/sfc/sfc_dp.h b/drivers/net/sfc/sfc_dp.h\nindex 61c1a3fbac..7fd8f34b0f 100644\n--- a/drivers/net/sfc/sfc_dp.h\n+++ b/drivers/net/sfc/sfc_dp.h\n@@ -42,6 +42,16 @@ enum sfc_dp_type {\n \n /** Datapath queue run-time information */\n struct sfc_dp_queue {\n+\t/*\n+\t * Typically the structure is located at the end of Rx/Tx queue\n+\t * data structure and not used on datapath. So, it is not a\n+\t * problem to have extra fields even if not used. However,\n+\t * put stats at top of the structure to be closer to fields\n+\t * used on datapath or reap to have more chances to be cache-hot.\n+\t */\n+\tuint32_t\t\t\trx_dbells;\n+\tuint32_t\t\t\ttx_dbells;\n+\n \tuint16_t\t\t\tport_id;\n \tuint16_t\t\t\tqueue_id;\n \tstruct rte_pci_addr\t\tpci_addr;\ndiff --git a/drivers/net/sfc/sfc_ef10.h b/drivers/net/sfc/sfc_ef10.h\nindex ad4c1fdbef..e9bb72e28b 100644\n--- a/drivers/net/sfc/sfc_ef10.h\n+++ b/drivers/net/sfc/sfc_ef10.h\n@@ -99,7 +99,7 @@ sfc_ef10_ev_present(const efx_qword_t ev)\n \n static inline void\n sfc_ef10_rx_qpush(volatile void *doorbell, unsigned int added,\n-\t\t  unsigned int ptr_mask)\n+\t\t  unsigned int ptr_mask, uint32_t *dbell_counter)\n {\n \tefx_dword_t dword;\n \n@@ -118,6 +118,7 @@ sfc_ef10_rx_qpush(volatile void *doorbell, unsigned int added,\n \t * operations that follow it (i.e. doorbell write).\n \t */\n \trte_write32(dword.ed_u32[0], doorbell);\n+\t(*dbell_counter)++;\n }\n \n static inline void\ndiff --git a/drivers/net/sfc/sfc_ef100_rx.c b/drivers/net/sfc/sfc_ef100_rx.c\nindex 10c74aa118..d4cb96881c 100644\n--- a/drivers/net/sfc/sfc_ef100_rx.c\n+++ b/drivers/net/sfc/sfc_ef100_rx.c\n@@ -119,6 +119,7 @@ sfc_ef100_rx_qpush(struct sfc_ef100_rxq *rxq, unsigned int added)\n \t * operations that follow it (i.e. doorbell write).\n \t */\n \trte_write32(dword.ed_u32[0], rxq->doorbell);\n+\trxq->dp.dpq.rx_dbells++;\n \n \tsfc_ef100_rx_debug(rxq, \"RxQ pushed doorbell at pidx %u (added=%u)\",\n \t\t\t   EFX_DWORD_FIELD(dword, ERF_GZ_RX_RING_PIDX),\ndiff --git a/drivers/net/sfc/sfc_ef100_tx.c b/drivers/net/sfc/sfc_ef100_tx.c\nindex f9ad6f7b73..522e9a0d34 100644\n--- a/drivers/net/sfc/sfc_ef100_tx.c\n+++ b/drivers/net/sfc/sfc_ef100_tx.c\n@@ -489,6 +489,7 @@ sfc_ef100_tx_qpush(struct sfc_ef100_txq *txq, unsigned int added)\n \t * operations that follow it (i.e. doorbell write).\n \t */\n \trte_write32(dword.ed_u32[0], txq->doorbell);\n+\ttxq->dp.dpq.tx_dbells++;\n \n \tsfc_ef100_tx_debug(txq, \"TxQ pushed doorbell at pidx %u (added=%u)\",\n \t\t\t   EFX_DWORD_FIELD(dword, ERF_GZ_TX_RING_PIDX),\ndiff --git a/drivers/net/sfc/sfc_ef10_essb_rx.c b/drivers/net/sfc/sfc_ef10_essb_rx.c\nindex 3c246eb149..991329e86f 100644\n--- a/drivers/net/sfc/sfc_ef10_essb_rx.c\n+++ b/drivers/net/sfc/sfc_ef10_essb_rx.c\n@@ -220,7 +220,8 @@ sfc_ef10_essb_rx_qrefill(struct sfc_ef10_essb_rxq *rxq)\n \n \tSFC_ASSERT(rxq->added != added);\n \trxq->added = added;\n-\tsfc_ef10_rx_qpush(rxq->doorbell, added, rxq_ptr_mask);\n+\tsfc_ef10_rx_qpush(rxq->doorbell, added, rxq_ptr_mask,\n+\t\t\t  &rxq->dp.dpq.rx_dbells);\n }\n \n static bool\ndiff --git a/drivers/net/sfc/sfc_ef10_rx.c b/drivers/net/sfc/sfc_ef10_rx.c\nindex 2b4393d232..49a7d4fb42 100644\n--- a/drivers/net/sfc/sfc_ef10_rx.c\n+++ b/drivers/net/sfc/sfc_ef10_rx.c\n@@ -171,7 +171,8 @@ sfc_ef10_rx_qrefill(struct sfc_ef10_rxq *rxq)\n \n \tSFC_ASSERT(rxq->added != added);\n \trxq->added = added;\n-\tsfc_ef10_rx_qpush(rxq->doorbell, added, ptr_mask);\n+\tsfc_ef10_rx_qpush(rxq->doorbell, added, ptr_mask,\n+\t\t\t  &rxq->dp.dpq.rx_dbells);\n }\n \n static void\ndiff --git a/drivers/net/sfc/sfc_ef10_tx.c b/drivers/net/sfc/sfc_ef10_tx.c\nindex a8d34ead33..ed43adb4ca 100644\n--- a/drivers/net/sfc/sfc_ef10_tx.c\n+++ b/drivers/net/sfc/sfc_ef10_tx.c\n@@ -248,6 +248,7 @@ sfc_ef10_tx_qpush(struct sfc_ef10_txq *txq, unsigned int added,\n \trte_io_wmb();\n \n \t*(volatile efsys_uint128_t *)txq->doorbell = oword.eo_u128[0];\n+\ttxq->dp.dpq.tx_dbells++;\n }\n \n static unsigned int\ndiff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c\nindex dd7e5c253a..2db0d000c3 100644\n--- a/drivers/net/sfc/sfc_ethdev.c\n+++ b/drivers/net/sfc/sfc_ethdev.c\n@@ -28,6 +28,10 @@\n #include \"sfc_flow.h\"\n #include \"sfc_dp.h\"\n #include \"sfc_dp_rx.h\"\n+#include \"sfc_sw_stats.h\"\n+\n+#define SFC_XSTAT_ID_INVALID_VAL  UINT64_MAX\n+#define SFC_XSTAT_ID_INVALID_NAME '\\0'\n \n uint32_t sfc_logtype_driver;\n \n@@ -714,29 +718,49 @@ sfc_stats_reset(struct rte_eth_dev *dev)\n \tif (rc != 0)\n \t\tsfc_err(sa, \"failed to reset statistics (rc = %d)\", rc);\n \n+\tsfc_sw_xstats_reset(sa);\n+\n \tsfc_adapter_unlock(sa);\n \n \tSFC_ASSERT(rc >= 0);\n \treturn -rc;\n }\n \n+static unsigned int\n+sfc_xstats_get_nb_supported(struct sfc_adapter *sa)\n+{\n+\tstruct sfc_port *port = &sa->port;\n+\tunsigned int nb_supported;\n+\n+\tsfc_adapter_lock(sa);\n+\tnb_supported = port->mac_stats_nb_supported +\n+\t\t       sfc_sw_xstats_get_nb_supported(sa);\n+\tsfc_adapter_unlock(sa);\n+\n+\treturn nb_supported;\n+}\n+\n static int\n sfc_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,\n \t       unsigned int xstats_count)\n {\n \tstruct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);\n-\tstruct sfc_port *port = &sa->port;\n \tunsigned int nb_written = 0;\n-\tunsigned int nb_supp;\n+\tunsigned int nb_supported = 0;\n+\tint rc;\n \n-\tif (unlikely(xstats == NULL)) {\n-\t\tsfc_adapter_lock(sa);\n-\t\tnb_supp = port->mac_stats_nb_supported;\n-\t\tsfc_adapter_unlock(sa);\n-\t\treturn nb_supp;\n-\t}\n+\tif (unlikely(xstats == NULL))\n+\t\treturn sfc_xstats_get_nb_supported(sa);\n+\n+\trc = sfc_port_get_mac_stats(sa, xstats, xstats_count, &nb_written);\n+\tif (rc < 0)\n+\t\treturn rc;\n \n-\treturn sfc_port_get_mac_stats(sa, xstats, xstats_count, &nb_written);\n+\tnb_supported = rc;\n+\tsfc_sw_xstats_get_vals(sa, xstats, xstats_count, &nb_written,\n+\t\t\t       &nb_supported);\n+\n+\treturn nb_supported;\n }\n \n static int\n@@ -748,24 +772,31 @@ sfc_xstats_get_names(struct rte_eth_dev *dev,\n \tstruct sfc_port *port = &sa->port;\n \tunsigned int i;\n \tunsigned int nstats = 0;\n+\tunsigned int nb_written = 0;\n+\tint ret;\n \n-\tif (unlikely(xstats_names == NULL)) {\n-\t\tsfc_adapter_lock(sa);\n-\t\tnstats = port->mac_stats_nb_supported;\n-\t\tsfc_adapter_unlock(sa);\n-\t\treturn nstats;\n-\t}\n+\tif (unlikely(xstats_names == NULL))\n+\t\treturn sfc_xstats_get_nb_supported(sa);\n \n \tfor (i = 0; i < EFX_MAC_NSTATS; ++i) {\n \t\tif (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {\n-\t\t\tif (nstats < xstats_count)\n+\t\t\tif (nstats < xstats_count) {\n \t\t\t\tstrlcpy(xstats_names[nstats].name,\n \t\t\t\t\tefx_mac_stat_name(sa->nic, i),\n \t\t\t\t\tsizeof(xstats_names[0].name));\n+\t\t\t\tnb_written++;\n+\t\t\t}\n \t\t\tnstats++;\n \t\t}\n \t}\n \n+\tret = sfc_sw_xstats_get_names(sa, xstats_names, xstats_count,\n+\t\t\t\t      &nb_written, &nstats);\n+\tif (ret != 0) {\n+\t\tSFC_ASSERT(ret < 0);\n+\t\treturn ret;\n+\t}\n+\n \treturn nstats;\n }\n \n@@ -774,11 +805,35 @@ sfc_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,\n \t\t     uint64_t *values, unsigned int n)\n {\n \tstruct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);\n+\tstruct sfc_port *port = &sa->port;\n+\tunsigned int nb_supported;\n+\tunsigned int i;\n+\tint rc;\n \n \tif (unlikely(ids == NULL || values == NULL))\n \t\treturn -EINVAL;\n \n-\treturn sfc_port_get_mac_stats_by_id(sa, ids, values, n);\n+\t/*\n+\t * Values array could be filled in nonsequential order. Fill values with\n+\t * constant indicating invalid ID first.\n+\t */\n+\tfor (i = 0; i < n; i++)\n+\t\tvalues[i] = SFC_XSTAT_ID_INVALID_VAL;\n+\n+\trc = sfc_port_get_mac_stats_by_id(sa, ids, values, n);\n+\tif (rc != 0)\n+\t\treturn rc;\n+\n+\tnb_supported = port->mac_stats_nb_supported;\n+\tsfc_sw_xstats_get_vals_by_id(sa, ids, values, n, &nb_supported);\n+\n+\t/* Return number of written stats before invalid ID is encountered. */\n+\tfor (i = 0; i < n; i++) {\n+\t\tif (values[i] == SFC_XSTAT_ID_INVALID_VAL)\n+\t\t\treturn i;\n+\t}\n+\n+\treturn n;\n }\n \n static int\n@@ -790,18 +845,23 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,\n \tstruct sfc_port *port = &sa->port;\n \tunsigned int nb_supported;\n \tunsigned int i;\n+\tint ret;\n \n \tif (unlikely(xstats_names == NULL && ids != NULL) ||\n \t    unlikely(xstats_names != NULL && ids == NULL))\n \t\treturn -EINVAL;\n \n-\tsfc_adapter_lock(sa);\n+\tif (unlikely(xstats_names == NULL && ids == NULL))\n+\t\treturn sfc_xstats_get_nb_supported(sa);\n \n-\tif (unlikely(xstats_names == NULL && ids == NULL)) {\n-\t\tnb_supported = port->mac_stats_nb_supported;\n-\t\tsfc_adapter_unlock(sa);\n-\t\treturn nb_supported;\n-\t}\n+\t/*\n+\t * Names array could be filled in nonsequential order. Fill names with\n+\t * string indicating invalid ID first.\n+\t */\n+\tfor (i = 0; i < size; i++)\n+\t\txstats_names[i].name[0] = SFC_XSTAT_ID_INVALID_NAME;\n+\n+\tsfc_adapter_lock(sa);\n \n \tSFC_ASSERT(port->mac_stats_nb_supported <=\n \t\t   RTE_DIM(port->mac_stats_by_id));\n@@ -812,14 +872,26 @@ sfc_xstats_get_names_by_id(struct rte_eth_dev *dev,\n \t\t\t\tefx_mac_stat_name(sa->nic,\n \t\t\t\t\t\t port->mac_stats_by_id[ids[i]]),\n \t\t\t\tsizeof(xstats_names[0].name));\n-\t\t} else {\n-\t\t\tsfc_adapter_unlock(sa);\n-\t\t\treturn i;\n \t\t}\n \t}\n \n+\tnb_supported = port->mac_stats_nb_supported;\n+\n \tsfc_adapter_unlock(sa);\n \n+\tret = sfc_sw_xstats_get_names_by_id(sa, ids, xstats_names, size,\n+\t\t\t\t\t    &nb_supported);\n+\tif (ret != 0) {\n+\t\tSFC_ASSERT(ret < 0);\n+\t\treturn ret;\n+\t}\n+\n+\t/* Return number of written names before invalid ID is encountered. */\n+\tfor (i = 0; i < size; i++) {\n+\t\tif (xstats_names[i].name[0] == SFC_XSTAT_ID_INVALID_NAME)\n+\t\t\treturn i;\n+\t}\n+\n \treturn size;\n }\n \ndiff --git a/drivers/net/sfc/sfc_port.c b/drivers/net/sfc/sfc_port.c\nindex f6689a17c0..adb2b2cb81 100644\n--- a/drivers/net/sfc/sfc_port.c\n+++ b/drivers/net/sfc/sfc_port.c\n@@ -7,6 +7,8 @@\n  * for Solarflare) and Solarflare Communications, Inc.\n  */\n \n+#include <rte_bitmap.h>\n+\n #include \"efx.h\"\n \n #include \"sfc.h\"\n@@ -701,15 +703,11 @@ sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,\n \t\t   RTE_DIM(port->mac_stats_by_id));\n \n \tfor (i = 0; i < n; i++) {\n-\t\tif (ids[i] < port->mac_stats_nb_supported) {\n+\t\tif (ids[i] < port->mac_stats_nb_supported)\n \t\t\tvalues[i] = mac_stats[port->mac_stats_by_id[ids[i]]];\n-\t\t} else {\n-\t\t\tret = i;\n-\t\t\tgoto unlock;\n-\t\t}\n \t}\n \n-\tret = n;\n+\tret = 0;\n \n unlock:\n \tsfc_adapter_unlock(sa);\ndiff --git a/drivers/net/sfc/sfc_rx.c b/drivers/net/sfc/sfc_rx.c\nindex f6a8ac68e8..280e8a61f9 100644\n--- a/drivers/net/sfc/sfc_rx.c\n+++ b/drivers/net/sfc/sfc_rx.c\n@@ -138,6 +138,7 @@ sfc_efx_rx_qrefill(struct sfc_efx_rxq *rxq)\n \tSFC_ASSERT(added != rxq->added);\n \trxq->added = added;\n \tefx_rx_qpush(rxq->common, added, &rxq->pushed);\n+\trxq->dp.dpq.rx_dbells++;\n }\n \n static uint64_t\ndiff --git a/drivers/net/sfc/sfc_sw_stats.c b/drivers/net/sfc/sfc_sw_stats.c\nnew file mode 100644\nindex 0000000000..8489b603f5\n--- /dev/null\n+++ b/drivers/net/sfc/sfc_sw_stats.c\n@@ -0,0 +1,572 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ *\n+ * Copyright(c) 2021 Xilinx, Inc.\n+ */\n+#include <rte_dev.h>\n+#include <rte_bitmap.h>\n+\n+#include \"sfc.h\"\n+#include \"sfc_rx.h\"\n+#include \"sfc_tx.h\"\n+#include \"sfc_sw_stats.h\"\n+\n+enum sfc_sw_stats_type {\n+\tSFC_SW_STATS_RX,\n+\tSFC_SW_STATS_TX,\n+};\n+\n+typedef uint64_t sfc_get_sw_xstat_val_t(struct sfc_adapter *sa, uint16_t qid);\n+\n+struct sfc_sw_xstat_descr {\n+\tconst char *name;\n+\tenum sfc_sw_stats_type type;\n+\tsfc_get_sw_xstat_val_t *get_val;\n+};\n+\n+static sfc_get_sw_xstat_val_t sfc_get_sw_xstat_val_rx_dbells;\n+static uint64_t\n+sfc_get_sw_xstat_val_rx_dbells(struct sfc_adapter *sa, uint16_t qid)\n+{\n+\tstruct sfc_adapter_shared *sas = sfc_sa2shared(sa);\n+\tstruct sfc_rxq_info *rxq_info;\n+\n+\trxq_info = sfc_rxq_info_by_ethdev_qid(sas, qid);\n+\tif (rxq_info->state & SFC_RXQ_INITIALIZED)\n+\t\treturn rxq_info->dp->dpq.rx_dbells;\n+\treturn 0;\n+}\n+\n+static sfc_get_sw_xstat_val_t sfc_get_sw_xstat_val_tx_dbells;\n+static uint64_t\n+sfc_get_sw_xstat_val_tx_dbells(struct sfc_adapter *sa, uint16_t qid)\n+{\n+\tstruct sfc_adapter_shared *sas = sfc_sa2shared(sa);\n+\tstruct sfc_txq_info *txq_info;\n+\n+\ttxq_info = sfc_txq_info_by_ethdev_qid(sas, qid);\n+\tif (txq_info->state & SFC_TXQ_INITIALIZED)\n+\t\treturn txq_info->dp->dpq.tx_dbells;\n+\treturn 0;\n+}\n+\n+struct sfc_sw_xstat_descr sfc_sw_xstats[] = {\n+\t{\n+\t\t.name = \"dbells\",\n+\t\t.type = SFC_SW_STATS_RX,\n+\t\t.get_val  = sfc_get_sw_xstat_val_rx_dbells,\n+\t},\n+\t{\n+\t\t.name = \"dbells\",\n+\t\t.type = SFC_SW_STATS_TX,\n+\t\t.get_val  = sfc_get_sw_xstat_val_tx_dbells,\n+\t}\n+};\n+\n+static int\n+sfc_sw_stat_get_name(struct sfc_adapter *sa,\n+\t\t     const struct sfc_sw_xstat_descr *sw_xstat, char *name,\n+\t\t     size_t name_size, unsigned int id_off)\n+{\n+\tconst char *prefix;\n+\tint ret;\n+\n+\tswitch (sw_xstat->type) {\n+\tcase SFC_SW_STATS_RX:\n+\t\tprefix = \"rx\";\n+\t\tbreak;\n+\tcase SFC_SW_STATS_TX:\n+\t\tprefix = \"tx\";\n+\t\tbreak;\n+\tdefault:\n+\t\tsfc_err(sa, \"%s: unknown software statistics type %d\",\n+\t\t\t__func__, sw_xstat->type);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (id_off == 0) {\n+\t\tret = snprintf(name, name_size, \"%s_%s\", prefix,\n+\t\t\t\t\t\t\t sw_xstat->name);\n+\t\tif (ret < 0 || ret >= (int)name_size) {\n+\t\t\tsfc_err(sa, \"%s: failed to fill xstat name %s_%s, err %d\",\n+\t\t\t\t__func__, prefix, sw_xstat->name, ret);\n+\t\t\treturn ret > 0 ? -EINVAL : ret;\n+\t\t}\n+\t} else {\n+\t\tuint16_t qid = id_off - 1;\n+\t\tret = snprintf(name, name_size, \"%s_q%u_%s\", prefix, qid,\n+\t\t\t\t\t\t\tsw_xstat->name);\n+\t\tif (ret < 0 || ret >= (int)name_size) {\n+\t\t\tsfc_err(sa, \"%s: failed to fill xstat name %s_q%u_%s, err %d\",\n+\t\t\t\t__func__, prefix, qid, sw_xstat->name, ret);\n+\t\t\treturn ret > 0 ? -EINVAL : ret;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static unsigned int\n+sfc_sw_stat_get_queue_count(struct sfc_adapter *sa,\n+\t\t\t    const struct sfc_sw_xstat_descr *sw_xstat)\n+{\n+\tstruct sfc_adapter_shared *sas = sfc_sa2shared(sa);\n+\n+\tswitch (sw_xstat->type) {\n+\tcase SFC_SW_STATS_RX:\n+\t\treturn sas->ethdev_rxq_count;\n+\tcase SFC_SW_STATS_TX:\n+\t\treturn sas->ethdev_txq_count;\n+\tdefault:\n+\t\tsfc_err(sa, \"%s: unknown software statistics type %d\",\n+\t\t\t__func__, sw_xstat->type);\n+\t\treturn 0;\n+\t}\n+}\n+\n+static unsigned int\n+sfc_sw_xstat_per_queue_get_count(unsigned int nb_queues)\n+{\n+\t/* Take into account the accumulative xstat of all queues */\n+\treturn nb_queues > 0 ? 1 + nb_queues : 0;\n+}\n+\n+static unsigned int\n+sfc_sw_xstat_get_nb_supported(struct sfc_adapter *sa,\n+\t\t\t      const struct sfc_sw_xstat_descr *sw_xstat)\n+{\n+\tunsigned int nb_queues;\n+\n+\tnb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);\n+\treturn sfc_sw_xstat_per_queue_get_count(nb_queues);\n+}\n+\n+static int\n+sfc_sw_stat_get_names(struct sfc_adapter *sa,\n+\t\t      const struct sfc_sw_xstat_descr *sw_xstat,\n+\t\t      struct rte_eth_xstat_name *xstats_names,\n+\t\t      unsigned int xstats_names_sz,\n+\t\t      unsigned int *nb_written,\n+\t\t      unsigned int *nb_supported)\n+{\n+\tconst size_t name_size = sizeof(xstats_names[0].name);\n+\tunsigned int id_base = *nb_supported;\n+\tunsigned int nb_queues;\n+\tunsigned int qid;\n+\tint rc;\n+\n+\tnb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);\n+\tif (nb_queues == 0)\n+\t\treturn 0;\n+\t*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);\n+\n+\t/*\n+\t * The order of each software xstat type is the accumulative xstat\n+\t * followed by per-queue xstats.\n+\t */\n+\tif (*nb_written < xstats_names_sz) {\n+\t\trc = sfc_sw_stat_get_name(sa, sw_xstat,\n+\t\t\t\t\t  xstats_names[*nb_written].name,\n+\t\t\t\t\t  name_size, *nb_written - id_base);\n+\t\tif (rc != 0)\n+\t\t\treturn rc;\n+\t\t(*nb_written)++;\n+\t}\n+\n+\tfor (qid = 0; qid < nb_queues; ++qid) {\n+\t\tif (*nb_written < xstats_names_sz) {\n+\t\t\trc = sfc_sw_stat_get_name(sa, sw_xstat,\n+\t\t\t\t\t      xstats_names[*nb_written].name,\n+\t\t\t\t\t      name_size, *nb_written - id_base);\n+\t\t\tif (rc != 0)\n+\t\t\t\treturn rc;\n+\t\t\t(*nb_written)++;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sfc_sw_xstat_get_names_by_id(struct sfc_adapter *sa,\n+\t\t\t     const struct sfc_sw_xstat_descr *sw_xstat,\n+\t\t\t     const uint64_t *ids,\n+\t\t\t     struct rte_eth_xstat_name *xstats_names,\n+\t\t\t     unsigned int size,\n+\t\t\t     unsigned int *nb_supported)\n+{\n+\tconst size_t name_size = sizeof(xstats_names[0].name);\n+\tunsigned int id_base = *nb_supported;\n+\tunsigned int nb_queues;\n+\tunsigned int i;\n+\tint rc;\n+\n+\tnb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);\n+\tif (nb_queues == 0)\n+\t\treturn 0;\n+\t*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);\n+\n+\t/*\n+\t * The order of each software xstat type is the accumulative xstat\n+\t * followed by per-queue xstats.\n+\t */\n+\tfor (i = 0; i < size; i++) {\n+\t\tif (id_base <= ids[i] && ids[i] <= id_base + nb_queues) {\n+\t\t\trc = sfc_sw_stat_get_name(sa, sw_xstat,\n+\t\t\t\t\t\t  xstats_names[i].name,\n+\t\t\t\t\t\t  name_size, ids[i] - id_base);\n+\t\t\tif (rc != 0)\n+\t\t\t\treturn rc;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void\n+sfc_sw_xstat_get_values(struct sfc_adapter *sa,\n+\t\t\tconst struct sfc_sw_xstat_descr *sw_xstat,\n+\t\t\tstruct rte_eth_xstat *xstats,\n+\t\t\tunsigned int xstats_size,\n+\t\t\tunsigned int *nb_written,\n+\t\t\tunsigned int *nb_supported)\n+{\n+\tunsigned int qid;\n+\tuint64_t value;\n+\tstruct rte_eth_xstat *accum_xstat;\n+\tbool count_accum_value = false;\n+\tunsigned int nb_queues;\n+\n+\tnb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);\n+\tif (nb_queues == 0)\n+\t\treturn;\n+\t*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);\n+\n+\t/*\n+\t * The order of each software xstat type is the accumulative xstat\n+\t * followed by per-queue xstats.\n+\t */\n+\tif (*nb_written < xstats_size) {\n+\t\tcount_accum_value = true;\n+\t\taccum_xstat = &xstats[*nb_written];\n+\t\txstats[*nb_written].id = *nb_written;\n+\t\txstats[*nb_written].value = 0;\n+\t\t(*nb_written)++;\n+\t}\n+\n+\tfor (qid = 0; qid < nb_queues; ++qid) {\n+\t\tvalue = sw_xstat->get_val(sa, qid);\n+\n+\t\tif (*nb_written < xstats_size) {\n+\t\t\txstats[*nb_written].id = *nb_written;\n+\t\t\txstats[*nb_written].value = value;\n+\t\t\t(*nb_written)++;\n+\t\t}\n+\n+\t\tif (count_accum_value)\n+\t\t\taccum_xstat->value += value;\n+\t}\n+}\n+\n+static void\n+sfc_sw_xstat_get_values_by_id(struct sfc_adapter *sa,\n+\t\t\t      const struct sfc_sw_xstat_descr *sw_xstat,\n+\t\t\t      const uint64_t *ids,\n+\t\t\t      uint64_t *values,\n+\t\t\t      unsigned int ids_size,\n+\t\t\t      unsigned int *nb_supported)\n+{\n+\trte_spinlock_t *bmp_lock = &sa->sw_xstats.queues_bitmap_lock;\n+\tstruct rte_bitmap *bmp = sa->sw_xstats.queues_bitmap;\n+\tunsigned int id_base = *nb_supported;\n+\tbool count_accum_value = false;\n+\tunsigned int accum_value_idx;\n+\tuint64_t accum_value = 0;\n+\tunsigned int i, qid;\n+\tunsigned int nb_queues;\n+\n+\n+\trte_spinlock_lock(bmp_lock);\n+\trte_bitmap_reset(bmp);\n+\n+\tnb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);\n+\tif (nb_queues == 0)\n+\t\tgoto unlock;\n+\t*nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);\n+\n+\t/*\n+\t * The order of each software xstat type is the accumulative xstat\n+\t * followed by per-queue xstats.\n+\t */\n+\tfor (i = 0; i < ids_size; i++) {\n+\t\tif (id_base <= ids[i] && ids[i] <= (id_base + nb_queues)) {\n+\t\t\tif (ids[i] == id_base) { /* Accumulative value */\n+\t\t\t\tcount_accum_value = true;\n+\t\t\t\taccum_value_idx = i;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tqid = ids[i] - id_base - 1;\n+\t\t\tvalues[i] = sw_xstat->get_val(sa, qid);\n+\t\t\taccum_value += values[i];\n+\n+\t\t\trte_bitmap_set(bmp, qid);\n+\t\t}\n+\t}\n+\n+\tif (count_accum_value) {\n+\t\tfor (qid = 0; qid < nb_queues; ++qid) {\n+\t\t\tif (rte_bitmap_get(bmp, qid) != 0)\n+\t\t\t\tcontinue;\n+\t\t\tvalues[accum_value_idx] += sw_xstat->get_val(sa, qid);\n+\t\t}\n+\t\tvalues[accum_value_idx] += accum_value;\n+\t}\n+\n+unlock:\n+\trte_spinlock_unlock(bmp_lock);\n+}\n+\n+unsigned int\n+sfc_sw_xstats_get_nb_supported(struct sfc_adapter *sa)\n+{\n+\tunsigned int nb_supported = 0;\n+\tunsigned int i;\n+\n+\tSFC_ASSERT(sfc_adapter_is_locked(sa));\n+\n+\tfor (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {\n+\t\tnb_supported += sfc_sw_xstat_get_nb_supported(sa,\n+\t\t\t\t\t\t\t     &sfc_sw_xstats[i]);\n+\t}\n+\n+\treturn nb_supported;\n+}\n+\n+void\n+sfc_sw_xstats_get_vals(struct sfc_adapter *sa,\n+\t\t       struct rte_eth_xstat *xstats,\n+\t\t       unsigned int xstats_count,\n+\t\t       unsigned int *nb_written,\n+\t\t       unsigned int *nb_supported)\n+{\n+\tuint64_t *reset_vals = sa->sw_xstats.reset_vals;\n+\tunsigned int sw_xstats_offset;\n+\tunsigned int i;\n+\n+\tsfc_adapter_lock(sa);\n+\n+\tsw_xstats_offset = *nb_supported;\n+\n+\tfor (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {\n+\t\tsfc_sw_xstat_get_values(sa, &sfc_sw_xstats[i], xstats,\n+\t\t\t\t\txstats_count, nb_written, nb_supported);\n+\t}\n+\n+\tfor (i = sw_xstats_offset; i < *nb_written; i++)\n+\t\txstats[i].value -= reset_vals[i - sw_xstats_offset];\n+\n+\tsfc_adapter_unlock(sa);\n+}\n+\n+int\n+sfc_sw_xstats_get_names(struct sfc_adapter *sa,\n+\t\t\tstruct rte_eth_xstat_name *xstats_names,\n+\t\t\tunsigned int xstats_count,\n+\t\t\tunsigned int *nb_written,\n+\t\t\tunsigned int *nb_supported)\n+{\n+\tunsigned int i;\n+\tint ret;\n+\n+\tsfc_adapter_lock(sa);\n+\n+\tfor (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {\n+\t\tret = sfc_sw_stat_get_names(sa, &sfc_sw_xstats[i],\n+\t\t\t\t\t    xstats_names, xstats_count,\n+\t\t\t\t\t    nb_written, nb_supported);\n+\t\tif (ret != 0) {\n+\t\t\tsfc_adapter_unlock(sa);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\tsfc_adapter_unlock(sa);\n+\n+\treturn 0;\n+}\n+\n+void\n+sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa,\n+\t\t\t     const uint64_t *ids,\n+\t\t\t     uint64_t *values,\n+\t\t\t     unsigned int n,\n+\t\t\t     unsigned int *nb_supported)\n+{\n+\tuint64_t *reset_vals = sa->sw_xstats.reset_vals;\n+\tunsigned int sw_xstats_offset;\n+\tunsigned int i;\n+\n+\tsfc_adapter_lock(sa);\n+\n+\tsw_xstats_offset = *nb_supported;\n+\n+\tfor (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {\n+\t\tsfc_sw_xstat_get_values_by_id(sa, &sfc_sw_xstats[i], ids,\n+\t\t\t\t\t      values, n, nb_supported);\n+\t}\n+\n+\tfor (i = 0; i < n; i++) {\n+\t\tif (sw_xstats_offset <= ids[i] && ids[i] < *nb_supported)\n+\t\t\tvalues[i] -= reset_vals[ids[i] - sw_xstats_offset];\n+\t}\n+\n+\tsfc_adapter_unlock(sa);\n+}\n+\n+int\n+sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa,\n+\t\t\t      const uint64_t *ids,\n+\t\t\t      struct rte_eth_xstat_name *xstats_names,\n+\t\t\t      unsigned int size,\n+\t\t\t      unsigned int *nb_supported)\n+{\n+\tunsigned int i;\n+\tint ret;\n+\n+\tsfc_adapter_lock(sa);\n+\n+\tfor (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {\n+\t\tret = sfc_sw_xstat_get_names_by_id(sa, &sfc_sw_xstats[i], ids,\n+\t\t\t\t\t\t   xstats_names, size,\n+\t\t\t\t\t\t   nb_supported);\n+\t\tif (ret != 0) {\n+\t\t\tsfc_adapter_unlock(sa);\n+\t\t\tSFC_ASSERT(ret < 0);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\tsfc_adapter_unlock(sa);\n+\n+\treturn 0;\n+}\n+\n+static void\n+sfc_sw_xstat_reset(struct sfc_adapter *sa, struct sfc_sw_xstat_descr *sw_xstat,\n+\t\t   uint64_t *reset_vals)\n+{\n+\tunsigned int nb_queues;\n+\tunsigned int qid;\n+\tuint64_t *accum_xstat_reset;\n+\n+\tSFC_ASSERT(sfc_adapter_is_locked(sa));\n+\n+\tnb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);\n+\tif (nb_queues == 0)\n+\t\treturn;\n+\n+\t/*\n+\t * The order of each software xstat type is the accumulative xstat\n+\t * followed by per-queue xstats.\n+\t */\n+\taccum_xstat_reset = reset_vals;\n+\t*accum_xstat_reset = 0;\n+\treset_vals++;\n+\n+\tfor (qid = 0; qid < nb_queues; ++qid) {\n+\t\treset_vals[qid] = sw_xstat->get_val(sa, qid);\n+\t\t*accum_xstat_reset += reset_vals[qid];\n+\t}\n+}\n+\n+void\n+sfc_sw_xstats_reset(struct sfc_adapter *sa)\n+{\n+\tuint64_t *reset_vals = sa->sw_xstats.reset_vals;\n+\tstruct sfc_sw_xstat_descr *sw_xstat;\n+\tunsigned int i;\n+\n+\tSFC_ASSERT(sfc_adapter_is_locked(sa));\n+\n+\tfor (i = 0; i < RTE_DIM(sfc_sw_xstats); i++) {\n+\t\tsw_xstat = &sfc_sw_xstats[i];\n+\t\tsfc_sw_xstat_reset(sa, sw_xstat, reset_vals);\n+\t\treset_vals += sfc_sw_xstat_get_nb_supported(sa, sw_xstat);\n+\t}\n+}\n+\n+int\n+sfc_sw_xstats_configure(struct sfc_adapter *sa)\n+{\n+\tuint64_t **reset_vals = &sa->sw_xstats.reset_vals;\n+\tsize_t nb_supported = 0;\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < RTE_DIM(sfc_sw_xstats); i++)\n+\t\tnb_supported += sfc_sw_xstat_get_nb_supported(sa,\n+\t\t\t\t\t\t\t&sfc_sw_xstats[i]);\n+\n+\t*reset_vals = rte_realloc(*reset_vals,\n+\t\t\t\t  nb_supported * sizeof(**reset_vals), 0);\n+\tif (*reset_vals == NULL)\n+\t\treturn ENOMEM;\n+\n+\tmemset(*reset_vals, 0, nb_supported * sizeof(**reset_vals));\n+\n+\treturn 0;\n+}\n+\n+static void\n+sfc_sw_xstats_free_queues_bitmap(struct sfc_adapter *sa)\n+{\n+\trte_bitmap_free(sa->sw_xstats.queues_bitmap);\n+\trte_free(sa->sw_xstats.queues_bitmap_mem);\n+}\n+\n+static int\n+sfc_sw_xstats_alloc_queues_bitmap(struct sfc_adapter *sa)\n+{\n+\tstruct rte_bitmap **queues_bitmap = &sa->sw_xstats.queues_bitmap;\n+\tvoid **queues_bitmap_mem = &sa->sw_xstats.queues_bitmap_mem;\n+\tuint32_t bmp_size;\n+\tint rc;\n+\n+\tbmp_size = rte_bitmap_get_memory_footprint(RTE_MAX_QUEUES_PER_PORT);\n+\t*queues_bitmap_mem = NULL;\n+\t*queues_bitmap = NULL;\n+\n+\t*queues_bitmap_mem = rte_calloc_socket(\"bitmap_mem\", bmp_size, 1, 0,\n+\t\t\t\t\t       sa->socket_id);\n+\tif (*queues_bitmap_mem == NULL)\n+\t\treturn ENOMEM;\n+\n+\t*queues_bitmap = rte_bitmap_init(RTE_MAX_QUEUES_PER_PORT,\n+\t\t\t\t\t *queues_bitmap_mem, bmp_size);\n+\tif (*queues_bitmap == NULL) {\n+\t\trc = EINVAL;\n+\t\tgoto fail;\n+\t}\n+\n+\trte_spinlock_init(&sa->sw_xstats.queues_bitmap_lock);\n+\treturn 0;\n+\n+fail:\n+\tsfc_sw_xstats_free_queues_bitmap(sa);\n+\treturn rc;\n+}\n+\n+int\n+sfc_sw_xstats_init(struct sfc_adapter *sa)\n+{\n+\tsa->sw_xstats.reset_vals = NULL;\n+\n+\treturn sfc_sw_xstats_alloc_queues_bitmap(sa);\n+}\n+\n+void\n+sfc_sw_xstats_close(struct sfc_adapter *sa)\n+{\n+\trte_free(sa->sw_xstats.reset_vals);\n+\tsa->sw_xstats.reset_vals = NULL;\n+\n+\tsfc_sw_xstats_free_queues_bitmap(sa);\n+}\ndiff --git a/drivers/net/sfc/sfc_sw_stats.h b/drivers/net/sfc/sfc_sw_stats.h\nnew file mode 100644\nindex 0000000000..1abded8018\n--- /dev/null\n+++ b/drivers/net/sfc/sfc_sw_stats.h\n@@ -0,0 +1,49 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ *\n+ * Copyright(c) 2021 Xilinx, Inc.\n+ */\n+#ifndef _SFC_SW_STATS_H\n+#define _SFC_SW_STATS_H\n+\n+#include <rte_dev.h>\n+\n+#include \"sfc.h\"\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+void sfc_sw_xstats_get_vals(struct sfc_adapter *sa,\n+\t\t\t    struct rte_eth_xstat *xstats,\n+\t\t\t    unsigned int xstats_count, unsigned int *nb_written,\n+\t\t\t    unsigned int *nb_supported);\n+\n+int sfc_sw_xstats_get_names(struct sfc_adapter *sa,\n+\t\t\t    struct rte_eth_xstat_name *xstats_names,\n+\t\t\t    unsigned int xstats_count, unsigned int *nb_written,\n+\t\t\t    unsigned int *nb_supported);\n+\n+void sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa, const uint64_t *ids,\n+\t\t\t\t  uint64_t *values, unsigned int n,\n+\t\t\t\t  unsigned int *nb_supported);\n+\n+int sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa, const uint64_t *ids,\n+\t\t\t\t  struct rte_eth_xstat_name *xstats_names,\n+\t\t\t\t  unsigned int size,\n+\t\t\t\t  unsigned int *nb_supported);\n+\n+unsigned int sfc_sw_xstats_get_nb_supported(struct sfc_adapter *sa);\n+\n+int sfc_sw_xstats_configure(struct sfc_adapter *sa);\n+\n+void sfc_sw_xstats_reset(struct sfc_adapter *sa);\n+\n+int sfc_sw_xstats_init(struct sfc_adapter *sa);\n+\n+void sfc_sw_xstats_close(struct sfc_adapter *sa);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif  /* _SFC_SW_STATS_H */\ndiff --git a/drivers/net/sfc/sfc_tx.c b/drivers/net/sfc/sfc_tx.c\nindex ce2a9a6a4f..49b239f4d2 100644\n--- a/drivers/net/sfc/sfc_tx.c\n+++ b/drivers/net/sfc/sfc_tx.c\n@@ -980,8 +980,10 @@ sfc_efx_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)\n \t\t\t\t       txq->completed, &txq->added);\n \t\tSFC_ASSERT(rc == 0);\n \n-\t\tif (likely(pushed != txq->added))\n+\t\tif (likely(pushed != txq->added)) {\n \t\t\tefx_tx_qpush(txq->common, txq->added, pushed);\n+\t\t\ttxq->dp.dpq.tx_dbells++;\n+\t\t}\n \t}\n \n #if SFC_TX_XMIT_PKTS_REAP_AT_LEAST_ONCE\n",
    "prefixes": [
        "v2",
        "10/11"
    ]
}