Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/93910/?format=api
http://patches.dpdk.org/api/patches/93910/?format=api", "web_url": "http://patches.dpdk.org/project/dpdk/patch/20210604144225.287678-11-andrew.rybchenko@oktetlabs.ru/", "project": { "id": 1, "url": "http://patches.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": "<20210604144225.287678-11-andrew.rybchenko@oktetlabs.ru>", "list_archive_url": "https://inbox.dpdk.org/dev/20210604144225.287678-11-andrew.rybchenko@oktetlabs.ru", "date": "2021-06-04T14:42:24", "name": "[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://patches.dpdk.org/api/people/2013/?format=api", "name": "Andrew Rybchenko", "email": "Andrew.Rybchenko@oktetlabs.ru" }, "delegate": { "id": 24651, "url": "http://patches.dpdk.org/api/users/24651/?format=api", "username": "dmarchand", "first_name": "David", "last_name": "Marchand", "email": "david.marchand@redhat.com" }, "mbox": "http://patches.dpdk.org/project/dpdk/patch/20210604144225.287678-11-andrew.rybchenko@oktetlabs.ru/mbox/", "series": [ { "id": 17239, "url": "http://patches.dpdk.org/api/series/17239/?format=api", "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=17239", "date": "2021-06-04T14:42:14", "name": "net/sfc: provide Rx/Tx doorbells stats", "version": 1, "mbox": "http://patches.dpdk.org/series/17239/mbox/" } ], "comments": "http://patches.dpdk.org/api/patches/93910/comments/", "check": "warning", "checks": "http://patches.dpdk.org/api/patches/93910/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 3F819A0A0F;\n\tFri, 4 Jun 2021 16:43:48 +0200 (CEST)", "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 538E14111F;\n\tFri, 4 Jun 2021 16:43:24 +0200 (CEST)", "from shelob.oktetlabs.ru (shelob.oktetlabs.ru [91.220.146.113])\n by mails.dpdk.org (Postfix) with ESMTP id 3CBD0410F0\n for <dev@dpdk.org>; Fri, 4 Jun 2021 16:43:21 +0200 (CEST)", "by shelob.oktetlabs.ru (Postfix, from userid 122)\n id 025277F684; Fri, 4 Jun 2021 17:43:20 +0300 (MSK)", "from aros.oktetlabs.ru (aros.oktetlabs.ru [192.168.38.17])\n by shelob.oktetlabs.ru (Postfix) with ESMTP id C381D7F688;\n Fri, 4 Jun 2021 17:42:36 +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 C381D7F688", "Authentication-Results": "shelob.oktetlabs.ru/C381D7F688; dkim=none;\n dkim-atps=neutral", "From": "Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>", "To": "dev@dpdk.org", "Cc": "Ivan Ilchenko <ivan.ilchenko@oktetlabs.ru>,\n Andy Moreton <amoreton@xilinx.com>", "Date": "Fri, 4 Jun 2021 17:42:24 +0300", "Message-Id": "<20210604144225.287678-11-andrew.rybchenko@oktetlabs.ru>", "X-Mailer": "git-send-email 2.30.2", "In-Reply-To": "<20210604144225.287678-1-andrew.rybchenko@oktetlabs.ru>", "References": "<20210604144225.287678-1-andrew.rybchenko@oktetlabs.ru>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[dpdk-dev] [PATCH 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 32b58e3d76..c40c8e12fe 100644\n--- a/drivers/net/sfc/meson.build\n+++ b/drivers/net/sfc/meson.build\n@@ -56,6 +56,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 7447f8b9de..832236a6d0 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": [ "10/11" ] }{ "id": 93910, "url": "