net: systemport: Fix 64-bit statistics dependency

There are several problems with commit 10377ba767 ("net: systemport:
Support 64bit statistics", first one got fixed in 7095c97345 ("net:
systemport: Fix 64-bit stats deadlock").

The second problem is that this specific code updates the
stats64.tx_{packets,bytes} from ndo_get_stats64() and that is what we
are returning to ethtool -S. If we are not running a tool that involves
calling ndo_get_stats64(), then we won't get updated ethtool stats.

The solution to this is to update the stats from both call sites,
factoring that into a specific function, While at it, don't just check
the sizeof() but also the type of the statistics in order to use the
64-bit stats seqlock.

Fixes: 10377ba767 ("net: systemport: Support 64bit statistics")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Florian Fainelli 2017-09-18 16:31:30 -07:00 committed by David S. Miller
parent 129c6cda2d
commit 8ecb1a29e1
1 changed files with 32 additions and 20 deletions

View File

@ -432,6 +432,27 @@ static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv)
netif_dbg(priv, hw, priv->netdev, "updated MIB counters\n");
}
static void bcm_sysport_update_tx_stats(struct bcm_sysport_priv *priv,
u64 *tx_bytes, u64 *tx_packets)
{
struct bcm_sysport_tx_ring *ring;
u64 bytes = 0, packets = 0;
unsigned int start;
unsigned int q;
for (q = 0; q < priv->netdev->num_tx_queues; q++) {
ring = &priv->tx_rings[q];
do {
start = u64_stats_fetch_begin_irq(&priv->syncp);
bytes = ring->bytes;
packets = ring->packets;
} while (u64_stats_fetch_retry_irq(&priv->syncp, start));
*tx_bytes += bytes;
*tx_packets += packets;
}
}
static void bcm_sysport_get_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
@ -439,11 +460,16 @@ static void bcm_sysport_get_stats(struct net_device *dev,
struct bcm_sysport_stats64 *stats64 = &priv->stats64;
struct u64_stats_sync *syncp = &priv->syncp;
struct bcm_sysport_tx_ring *ring;
u64 tx_bytes = 0, tx_packets = 0;
unsigned int start;
int i, j;
if (netif_running(dev))
if (netif_running(dev)) {
bcm_sysport_update_mib_counters(priv);
bcm_sysport_update_tx_stats(priv, &tx_bytes, &tx_packets);
stats64->tx_bytes = tx_bytes;
stats64->tx_packets = tx_packets;
}
for (i = 0, j = 0; i < BCM_SYSPORT_STATS_LEN; i++) {
const struct bcm_sysport_stats *s;
@ -461,12 +487,13 @@ static void bcm_sysport_get_stats(struct net_device *dev,
continue;
p += s->stat_offset;
if (s->stat_sizeof == sizeof(u64))
if (s->stat_sizeof == sizeof(u64) &&
s->type == BCM_SYSPORT_STAT_NETDEV64) {
do {
start = u64_stats_fetch_begin_irq(syncp);
data[i] = *(u64 *)p;
} while (u64_stats_fetch_retry_irq(syncp, start));
else
} else
data[i] = *(u32 *)p;
j++;
}
@ -1716,27 +1743,12 @@ static void bcm_sysport_get_stats64(struct net_device *dev,
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
struct bcm_sysport_stats64 *stats64 = &priv->stats64;
struct bcm_sysport_tx_ring *ring;
u64 tx_packets = 0, tx_bytes = 0;
unsigned int start;
unsigned int q;
netdev_stats_to_stats64(stats, &dev->stats);
for (q = 0; q < dev->num_tx_queues; q++) {
ring = &priv->tx_rings[q];
do {
start = u64_stats_fetch_begin_irq(&priv->syncp);
tx_bytes = ring->bytes;
tx_packets = ring->packets;
} while (u64_stats_fetch_retry_irq(&priv->syncp, start));
stats->tx_bytes += tx_bytes;
stats->tx_packets += tx_packets;
}
stats64->tx_bytes = stats->tx_bytes;
stats64->tx_packets = stats->tx_packets;
bcm_sysport_update_tx_stats(priv, &stats->tx_bytes,
&stats->tx_packets);
do {
start = u64_stats_fetch_begin_irq(&priv->syncp);