Skip to content

Commit

Permalink
net: hinic: fix bug that ethtool get wrong stats
Browse files Browse the repository at this point in the history
Function hinic_get_stats64() will do two operations:
1. reads stats from every hinic_rxq/txq and accumulates them
2. calls hinic_rxq/txq_clean_stats() to clean every rxq/txq's stats

For hinic_get_stats64(), it could get right data, because it sums all
data to nic_dev->rx_stats/tx_stats.
But it is wrong for get_drv_queue_stats(), this function will read
hinic_rxq's stats, which have been cleared to zero by hinic_get_stats64().

I have observed hinic's cleanup operation by using such command:
> watch -n 1 "cat ethtool -S eth4 | tail -40"

Result before:
     ...
     rxq7_pkts: 1
     rxq7_bytes: 90
     rxq7_errors: 0
     rxq7_csum_errors: 0
     rxq7_other_errors: 0
     ...
     rxq9_pkts: 11
     rxq9_bytes: 726
     rxq9_errors: 0
     rxq9_csum_errors: 0
     rxq9_other_errors: 0
     ...
     rxq11_pkts: 0
     rxq11_bytes: 0
     rxq11_errors: 0
     rxq11_csum_errors: 0
     rxq11_other_errors: 0

Result after a few seconds:
     ...
     rxq7_pkts: 0
     rxq7_bytes: 0
     rxq7_errors: 0
     rxq7_csum_errors: 0
     rxq7_other_errors: 0
     ...
     rxq9_pkts: 2
     rxq9_bytes: 132
     rxq9_errors: 0
     rxq9_csum_errors: 0
     rxq9_other_errors: 0
     ...
     rxq11_pkts: 1
     rxq11_bytes: 170
     rxq11_errors: 0
     rxq11_csum_errors: 0
     rxq11_other_errors: 0

To solve this problem, we just keep every queue's total stats in their own
queue (aka hinic_{rxq|txq}), and simply sum all per-queue stats every time
calling hinic_get_stats64().
With that solution, there is no need to clean per-queue stats now,
and there is no need to maintain global hinic_dev.{tx|rx}_stats, too.

Fixes: edd384f ("net-next/hinic: Add ethtool and stats")
Signed-off-by: Qiao Ma <mqaio@linux.alibaba.com>
  • Loading branch information
maqiao-mq authored and intel-lab-lkp committed Jul 4, 2022
1 parent d0bf1fe commit 223573d
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 39 deletions.
3 changes: 0 additions & 3 deletions drivers/net/ethernet/huawei/hinic/hinic_dev.h
Expand Up @@ -95,9 +95,6 @@ struct hinic_dev {
u16 sq_depth;
u16 rq_depth;

struct hinic_txq_stats tx_stats;
struct hinic_rxq_stats rx_stats;

u8 rss_tmpl_idx;
u8 rss_hash_engine;
u16 num_rss;
Expand Down
54 changes: 18 additions & 36 deletions drivers/net/ethernet/huawei/hinic/hinic_main.c
Expand Up @@ -80,56 +80,48 @@ static int set_features(struct hinic_dev *nic_dev,
netdev_features_t pre_features,
netdev_features_t features, bool force_change);

static void update_rx_stats(struct hinic_dev *nic_dev, struct hinic_rxq *rxq)
static void gather_rx_stats(struct hinic_rxq_stats *nic_rx_stats, struct hinic_rxq *rxq)
{
struct hinic_rxq_stats *nic_rx_stats = &nic_dev->rx_stats;
struct hinic_rxq_stats rx_stats;

u64_stats_init(&rx_stats.syncp);

hinic_rxq_get_stats(rxq, &rx_stats);

u64_stats_update_begin(&nic_rx_stats->syncp);
nic_rx_stats->bytes += rx_stats.bytes;
nic_rx_stats->pkts += rx_stats.pkts;
nic_rx_stats->errors += rx_stats.errors;
nic_rx_stats->csum_errors += rx_stats.csum_errors;
nic_rx_stats->other_errors += rx_stats.other_errors;
u64_stats_update_end(&nic_rx_stats->syncp);

hinic_rxq_clean_stats(rxq);
}

static void update_tx_stats(struct hinic_dev *nic_dev, struct hinic_txq *txq)
static void gather_tx_stats(struct hinic_txq_stats *nic_tx_stats, struct hinic_txq *txq)
{
struct hinic_txq_stats *nic_tx_stats = &nic_dev->tx_stats;
struct hinic_txq_stats tx_stats;

u64_stats_init(&tx_stats.syncp);

hinic_txq_get_stats(txq, &tx_stats);

u64_stats_update_begin(&nic_tx_stats->syncp);
nic_tx_stats->bytes += tx_stats.bytes;
nic_tx_stats->pkts += tx_stats.pkts;
nic_tx_stats->tx_busy += tx_stats.tx_busy;
nic_tx_stats->tx_wake += tx_stats.tx_wake;
nic_tx_stats->tx_dropped += tx_stats.tx_dropped;
nic_tx_stats->big_frags_pkts += tx_stats.big_frags_pkts;
u64_stats_update_end(&nic_tx_stats->syncp);

hinic_txq_clean_stats(txq);
}

static void update_nic_stats(struct hinic_dev *nic_dev)
static void gather_nic_stats(struct hinic_dev *nic_dev,
struct hinic_rxq_stats *nic_rx_stats,
struct hinic_txq_stats *nic_tx_stats)
{
int i, num_qps = hinic_hwdev_num_qps(nic_dev->hwdev);

for (i = 0; i < num_qps; i++)
update_rx_stats(nic_dev, &nic_dev->rxqs[i]);
gather_rx_stats(nic_rx_stats, &nic_dev->rxqs[i]);

for (i = 0; i < num_qps; i++)
update_tx_stats(nic_dev, &nic_dev->txqs[i]);
gather_tx_stats(nic_tx_stats, &nic_dev->txqs[i]);
}

/**
Expand Down Expand Up @@ -558,8 +550,6 @@ int hinic_close(struct net_device *netdev)
netif_carrier_off(netdev);
netif_tx_disable(netdev);

update_nic_stats(nic_dev);

up(&nic_dev->mgmt_lock);

if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
Expand Down Expand Up @@ -853,26 +843,24 @@ static void hinic_get_stats64(struct net_device *netdev,
struct rtnl_link_stats64 *stats)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
struct hinic_rxq_stats *nic_rx_stats;
struct hinic_txq_stats *nic_tx_stats;
struct hinic_rxq_stats nic_rx_stats = {};
struct hinic_txq_stats nic_tx_stats = {};

nic_rx_stats = &nic_dev->rx_stats;
nic_tx_stats = &nic_dev->tx_stats;
u64_stats_init(&nic_rx_stats.syncp);
u64_stats_init(&nic_tx_stats.syncp);

down(&nic_dev->mgmt_lock);

if (nic_dev->flags & HINIC_INTF_UP)
update_nic_stats(nic_dev);

gather_nic_stats(nic_dev, &nic_rx_stats, &nic_tx_stats);
up(&nic_dev->mgmt_lock);

stats->rx_bytes = nic_rx_stats->bytes;
stats->rx_packets = nic_rx_stats->pkts;
stats->rx_errors = nic_rx_stats->errors;
stats->rx_bytes = nic_rx_stats.bytes;
stats->rx_packets = nic_rx_stats.pkts;
stats->rx_errors = nic_rx_stats.errors;

stats->tx_bytes = nic_tx_stats->bytes;
stats->tx_packets = nic_tx_stats->pkts;
stats->tx_errors = nic_tx_stats->tx_dropped;
stats->tx_bytes = nic_tx_stats.bytes;
stats->tx_packets = nic_tx_stats.pkts;
stats->tx_errors = nic_tx_stats.tx_dropped;
}

static int hinic_set_features(struct net_device *netdev,
Expand Down Expand Up @@ -1234,12 +1222,6 @@ static int nic_dev_init(struct pci_dev *pdev)

sema_init(&nic_dev->mgmt_lock, 1);

tx_stats = &nic_dev->tx_stats;
rx_stats = &nic_dev->rx_stats;

u64_stats_init(&tx_stats->syncp);
u64_stats_init(&rx_stats->syncp);

nic_dev->vlan_bitmap = devm_bitmap_zalloc(&pdev->dev, VLAN_N_VID,
GFP_KERNEL);
if (!nic_dev->vlan_bitmap) {
Expand Down

0 comments on commit 223573d

Please sign in to comment.