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 --- .../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 #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