From: Mengyuan Lou <mengyuanlou@net-swift.com>
To: netdev@vger.kernel.org
Cc: jiawenwu@trustnetic.com, duanqiangwen@net-swift.com,
horms@kernel.org, kuba@kernel.org, pabeni@redhat.com,
Mengyuan Lou <mengyuanlou@net-swift.com>
Subject: [PATCH net-next v6 3/3] net: libwx: support vf per-queue statistics via ethtool -S
Date: Wed, 1 Jul 2026 18:01:45 +0800 [thread overview]
Message-ID: <20260701100145.23738-4-mengyuanlou@net-swift.com> (raw)
In-Reply-To: <20260701100145.23738-1-mengyuanlou@net-swift.com>
Add per-queue TX/RX packet and byte counters to the VF ethtool stats
table.
Convert WX_NUM_{RX,TX}_QUEUES macros to take explicit netdev parameter.
Then replace both WX_GLOBAL_STATS_LEN and WX_STATS_LEN macros with
type-safe static helpers wx_global_stats_len() and wx_stats_len().
The stats length is now dynamically determined based on whether the
device is a VF or PF via wx_stats_len().
Add ring access protection in wx_update_stats.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
.../net/ethernet/wangxun/libwx/wx_ethtool.c | 71 +++++++++++++------
drivers/net/ethernet/wangxun/libwx/wx_hw.c | 8 +++
.../net/ethernet/wangxun/libwx/wx_vf_common.c | 2 +
3 files changed, 60 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
index 22037f015ded..f72908630ea4 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
@@ -48,6 +48,10 @@ static const struct wx_stats wx_gstrings_stats[] = {
WX_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
};
+static const struct wx_stats wx_gstrings_stats_vf[] = {
+ WX_STAT("non_eop_descs", non_eop_descs),
+};
+
static const struct wx_stats wx_gstrings_fdir_stats[] = {
WX_STAT("fdir_match", stats.fdirmatch),
WX_STAT("fdir_miss", stats.fdirmiss),
@@ -63,21 +67,33 @@ static const struct wx_stats wx_gstrings_rsc_stats[] = {
* used because we do not have a good way to get the max number of
* rx queues with CONFIG_RPS disabled.
*/
-#define WX_NUM_RX_QUEUES netdev->num_tx_queues
-#define WX_NUM_TX_QUEUES netdev->num_tx_queues
-
-#define WX_QUEUE_STATS_LEN ( \
- (WX_NUM_TX_QUEUES + WX_NUM_RX_QUEUES) * \
- (sizeof(struct wx_queue_stats) / sizeof(u64)))
-#define WX_GLOBAL_STATS_LEN ARRAY_SIZE(wx_gstrings_stats)
+#define WX_NUM_RX_QUEUES(netdev) ((netdev)->num_tx_queues)
+#define WX_NUM_TX_QUEUES(netdev) ((netdev)->num_tx_queues)
#define WX_FDIR_STATS_LEN ARRAY_SIZE(wx_gstrings_fdir_stats)
#define WX_RSC_STATS_LEN ARRAY_SIZE(wx_gstrings_rsc_stats)
-#define WX_STATS_LEN (WX_GLOBAL_STATS_LEN + WX_QUEUE_STATS_LEN)
+
+static unsigned int wx_global_stats_len(const struct wx *wx)
+{
+ return wx->pdev->is_virtfn ?
+ ARRAY_SIZE(wx_gstrings_stats_vf) : ARRAY_SIZE(wx_gstrings_stats);
+}
+
+static unsigned int wx_stats_len(const struct wx *wx)
+{
+ struct net_device *netdev = wx->netdev;
+ unsigned int queue_stats_len;
+
+ queue_stats_len = (WX_NUM_TX_QUEUES(netdev) +
+ WX_NUM_RX_QUEUES(netdev)) *
+ (sizeof(struct wx_queue_stats) / sizeof(u64));
+
+ return wx_global_stats_len(wx) + queue_stats_len;
+}
int wx_get_sset_count(struct net_device *netdev, int sset)
{
struct wx *wx = netdev_priv(netdev);
- int len = WX_STATS_LEN;
+ int len = wx_stats_len(wx);
switch (sset) {
case ETH_SS_STATS:
@@ -100,8 +116,11 @@ void wx_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
switch (stringset) {
case ETH_SS_STATS:
- for (i = 0; i < WX_GLOBAL_STATS_LEN; i++)
- ethtool_puts(&p, wx_gstrings_stats[i].stat_string);
+ for (i = 0; i < wx_global_stats_len(wx); i++)
+ if (wx->pdev->is_virtfn)
+ ethtool_puts(&p, wx_gstrings_stats_vf[i].stat_string);
+ else
+ ethtool_puts(&p, wx_gstrings_stats[i].stat_string);
if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags)) {
for (i = 0; i < WX_FDIR_STATS_LEN; i++)
ethtool_puts(&p, wx_gstrings_fdir_stats[i].stat_string);
@@ -114,7 +133,7 @@ void wx_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
ethtool_sprintf(&p, "tx_queue_%u_packets", i);
ethtool_sprintf(&p, "tx_queue_%u_bytes", i);
}
- for (i = 0; i < WX_NUM_RX_QUEUES; i++) {
+ for (i = 0; i < WX_NUM_RX_QUEUES(netdev); i++) {
ethtool_sprintf(&p, "rx_queue_%u_packets", i);
ethtool_sprintf(&p, "rx_queue_%u_bytes", i);
}
@@ -134,10 +153,16 @@ void wx_get_ethtool_stats(struct net_device *netdev,
wx_update_stats(wx);
- for (i = 0; i < WX_GLOBAL_STATS_LEN; i++) {
- p = (char *)wx + wx_gstrings_stats[i].stat_offset;
- data[i] = (wx_gstrings_stats[i].sizeof_stat ==
- sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ for (i = 0; i < wx_global_stats_len(wx); i++) {
+ if (wx->pdev->is_virtfn) {
+ p = (char *)wx + wx_gstrings_stats_vf[i].stat_offset;
+ data[i] = (wx_gstrings_stats_vf[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ } else {
+ p = (char *)wx + wx_gstrings_stats[i].stat_offset;
+ data[i] = (wx_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
}
if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags)) {
@@ -169,7 +194,7 @@ void wx_get_ethtool_stats(struct net_device *netdev,
} while (u64_stats_fetch_retry(&ring->syncp, start));
i += 2;
}
- for (j = 0; j < WX_NUM_RX_QUEUES; j++) {
+ for (j = 0; j < WX_NUM_RX_QUEUES(netdev); j++) {
ring = wx->rx_ring[j];
if (!ring) {
data[i++] = 0;
@@ -219,19 +244,20 @@ EXPORT_SYMBOL(wx_get_pause_stats);
void wx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
{
- unsigned int stats_len = WX_STATS_LEN;
struct wx *wx = netdev_priv(netdev);
+ unsigned int stats_len;
+ stats_len = wx_stats_len(wx);
if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags))
stats_len += WX_FDIR_STATS_LEN;
strscpy(info->driver, wx->driver_name, sizeof(info->driver));
strscpy(info->fw_version, wx->eeprom_id, sizeof(info->fw_version));
strscpy(info->bus_info, pci_name(wx->pdev), sizeof(info->bus_info));
- if (wx->num_tx_queues <= WX_NUM_TX_QUEUES) {
+ if (wx->num_tx_queues <= WX_NUM_TX_QUEUES(netdev)) {
info->n_stats = stats_len -
- (WX_NUM_TX_QUEUES - wx->num_tx_queues) *
- (sizeof(struct wx_queue_stats) / sizeof(u64)) * 2;
+ (WX_NUM_TX_QUEUES(netdev) - wx->num_tx_queues) *
+ (sizeof(struct wx_queue_stats) / sizeof(u64)) * 2;
} else {
info->n_stats = stats_len;
}
@@ -852,6 +878,9 @@ static const struct ethtool_ops wx_ethtool_ops_vf = {
.set_coalesce = wx_set_coalesce,
.get_ts_info = ethtool_op_get_ts_info,
.get_link_ksettings = wx_get_link_ksettings_vf,
+ .get_sset_count = wx_get_sset_count,
+ .get_strings = wx_get_strings,
+ .get_ethtool_stats = wx_get_ethtool_stats,
};
void wx_set_ethtool_ops_vf(struct net_device *netdev)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 260e14d5d541..349afbe60132 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -2886,6 +2886,8 @@ void wx_update_stats(struct wx *wx)
for (i = 0; i < wx->num_rx_queues; i++) {
struct wx_ring *rx_ring = wx->rx_ring[i];
+ if (!rx_ring)
+ continue;
non_eop_descs += rx_ring->rx_stats.non_eop_descs;
alloc_rx_buff_failed += rx_ring->rx_stats.alloc_rx_buff_failed;
hw_csum_rx_good += rx_ring->rx_stats.csum_good_cnt;
@@ -2911,12 +2913,17 @@ void wx_update_stats(struct wx *wx)
for (i = 0; i < wx->num_tx_queues; i++) {
struct wx_ring *tx_ring = wx->tx_ring[i];
+ if (!tx_ring)
+ continue;
restart_queue += tx_ring->tx_stats.restart_queue;
tx_busy += tx_ring->tx_stats.tx_busy;
}
wx->restart_queue = restart_queue;
wx->tx_busy = tx_busy;
+ if (wx->pdev->is_virtfn)
+ goto skip_hw_stats;
+
wx_update_xoff_rx_lfc(wx);
hwstats->gprc += rd32(wx, WX_RDM_PKT_CNT);
@@ -2956,6 +2963,7 @@ void wx_update_stats(struct wx *wx)
hwstats->qmprc += rd32_wrap(wx, WX_PX_MPRC(i),
&wx->last_stats.qmprc[i]);
+skip_hw_stats:
spin_unlock(&wx->hw_stats_lock);
}
EXPORT_SYMBOL(wx_update_stats);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
index 26de78e9a69e..1d84fe35d7d9 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
@@ -5,6 +5,7 @@
#include <linux/pci.h>
#include "wx_type.h"
+#include "wx_hw.h"
#include "wx_mbx.h"
#include "wx_lib.h"
#include "wx_vf.h"
@@ -409,6 +410,7 @@ static void wxvf_service_task(struct work_struct *work)
wxvf_link_config_subtask(wx);
wxvf_reset_subtask(wx);
+ wx_update_stats(wx);
wx_service_event_complete(wx);
}
--
2.30.1
prev parent reply other threads:[~2026-07-01 10:02 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-01 10:01 [PATCH net-next v6 0/3] net: libwx: improve VF ethtool support Mengyuan Lou
2026-07-01 10:01 ` [PATCH net-next v6 1/3] net: libwx: add support for set_ringparam in wx_ethtool_ops_vf Mengyuan Lou
2026-07-01 10:01 ` [PATCH net-next v6 2/3] net: libwx: add support for set_coalesce " Mengyuan Lou
2026-07-01 10:01 ` Mengyuan Lou [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260701100145.23738-4-mengyuanlou@net-swift.com \
--to=mengyuanlou@net-swift.com \
--cc=duanqiangwen@net-swift.com \
--cc=horms@kernel.org \
--cc=jiawenwu@trustnetic.com \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox