Commit d0023f82 authored by David S. Miller's avatar David S. Miller

Merge branch 'gfar-ethtool-atomic' of git://git.kernel.org/pub/scm/linux/kernel/git/paulg/linux

Paul Gortmaker says:

====================
Eric noticed that the handling of local u64 ethtool counters for
this driver commonly found on Freescale ppc-32 boards was racy.

However, before converting them over to atomic64_t, I noticed
that an internal struct was being used to determine the offsets
for exporting this data into the ethtool buffer, and in doing
so, it assumed that the counters would always be u64.  Rather
than keep this implicit assumption, a simple code cleanup gets
rid of the struct completely, and leaves less conversion sites.

The alternative solution would have been to take advantage of
the fact that the counters are all relating to error conditions,
and hence make them internally u32.  In doing so, we'd be assuming
that U32_MAX of any particular error condition is highly unlikely.
This might have made sense if any increments were in a hot path.

Tested with "ethtool -S eth0" on sbc8548 board.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 959d5fde 212079df
......@@ -2648,7 +2648,7 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
if (status & RXBD_TRUNCATED) {
stats->rx_length_errors++;
estats->rx_trunc++;
atomic64_inc(&estats->rx_trunc);
return;
}
......@@ -2657,20 +2657,20 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
stats->rx_length_errors++;
if (status & RXBD_LARGE)
estats->rx_large++;
atomic64_inc(&estats->rx_large);
else
estats->rx_short++;
atomic64_inc(&estats->rx_short);
}
if (status & RXBD_NONOCTET) {
stats->rx_frame_errors++;
estats->rx_nonoctet++;
atomic64_inc(&estats->rx_nonoctet);
}
if (status & RXBD_CRCERR) {
estats->rx_crcerr++;
atomic64_inc(&estats->rx_crcerr);
stats->rx_crc_errors++;
}
if (status & RXBD_OVERRUN) {
estats->rx_overrun++;
atomic64_inc(&estats->rx_overrun);
stats->rx_crc_errors++;
}
}
......@@ -2744,7 +2744,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
ret = napi_gro_receive(napi, skb);
if (GRO_DROP == ret)
priv->extra_stats.kernel_dropped++;
atomic64_inc(&priv->extra_stats.kernel_dropped);
return 0;
}
......@@ -2812,7 +2812,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
} else {
netif_warn(priv, rx_err, dev, "Missing skb!\n");
rx_queue->stats.rx_dropped++;
priv->extra_stats.rx_skbmissing++;
atomic64_inc(&priv->extra_stats.rx_skbmissing);
}
}
......@@ -3245,7 +3245,7 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
netif_dbg(priv, tx_err, dev,
"TX FIFO underrun, packet dropped\n");
dev->stats.tx_dropped++;
priv->extra_stats.tx_underrun++;
atomic64_inc(&priv->extra_stats.tx_underrun);
local_irq_save(flags);
lock_tx_qs(priv);
......@@ -3260,7 +3260,7 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
}
if (events & IEVENT_BSY) {
dev->stats.rx_errors++;
priv->extra_stats.rx_bsy++;
atomic64_inc(&priv->extra_stats.rx_bsy);
gfar_receive(irq, grp_id);
......@@ -3269,19 +3269,19 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
}
if (events & IEVENT_BABR) {
dev->stats.rx_errors++;
priv->extra_stats.rx_babr++;
atomic64_inc(&priv->extra_stats.rx_babr);
netif_dbg(priv, rx_err, dev, "babbling RX error\n");
}
if (events & IEVENT_EBERR) {
priv->extra_stats.eberr++;
atomic64_inc(&priv->extra_stats.eberr);
netif_dbg(priv, rx_err, dev, "bus error\n");
}
if (events & IEVENT_RXC)
netif_dbg(priv, rx_status, dev, "control frame\n");
if (events & IEVENT_BABT) {
priv->extra_stats.tx_babt++;
atomic64_inc(&priv->extra_stats.tx_babt);
netif_dbg(priv, tx_err, dev, "babbling TX error\n");
}
return IRQ_HANDLED;
......
......@@ -627,34 +627,29 @@ struct rmon_mib
};
struct gfar_extra_stats {
u64 kernel_dropped;
u64 rx_large;
u64 rx_short;
u64 rx_nonoctet;
u64 rx_crcerr;
u64 rx_overrun;
u64 rx_bsy;
u64 rx_babr;
u64 rx_trunc;
u64 eberr;
u64 tx_babt;
u64 tx_underrun;
u64 rx_skbmissing;
u64 tx_timeout;
atomic64_t kernel_dropped;
atomic64_t rx_large;
atomic64_t rx_short;
atomic64_t rx_nonoctet;
atomic64_t rx_crcerr;
atomic64_t rx_overrun;
atomic64_t rx_bsy;
atomic64_t rx_babr;
atomic64_t rx_trunc;
atomic64_t eberr;
atomic64_t tx_babt;
atomic64_t tx_underrun;
atomic64_t rx_skbmissing;
atomic64_t tx_timeout;
};
#define GFAR_RMON_LEN ((sizeof(struct rmon_mib) - 16)/sizeof(u32))
#define GFAR_EXTRA_STATS_LEN (sizeof(struct gfar_extra_stats)/sizeof(u64))
#define GFAR_EXTRA_STATS_LEN \
(sizeof(struct gfar_extra_stats)/sizeof(atomic64_t))
/* Number of stats in the stats structure (ignore car and cam regs)*/
/* Number of stats exported via ethtool */
#define GFAR_STATS_LEN (GFAR_RMON_LEN + GFAR_EXTRA_STATS_LEN)
struct gfar_stats {
u64 extra[GFAR_EXTRA_STATS_LEN];
u64 rmon[GFAR_RMON_LEN];
};
struct gfar {
u32 tsec_id; /* 0x.000 - Controller ID register */
u32 tsec_id2; /* 0x.004 - Controller ID2 register */
......
......@@ -149,20 +149,17 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
int i;
struct gfar_private *priv = netdev_priv(dev);
struct gfar __iomem *regs = priv->gfargrp[0].regs;
u64 *extra = (u64 *) & priv->extra_stats;
atomic64_t *extra = (atomic64_t *)&priv->extra_stats;
for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
buf[i] = atomic64_read(&extra[i]);
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
u32 __iomem *rmon = (u32 __iomem *) &regs->rmon;
struct gfar_stats *stats = (struct gfar_stats *) buf;
for (i = 0; i < GFAR_RMON_LEN; i++)
stats->rmon[i] = (u64) gfar_read(&rmon[i]);
for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
stats->extra[i] = extra[i];
} else
for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
buf[i] = extra[i];
for (; i < GFAR_STATS_LEN; i++, rmon++)
buf[i] = (u64) gfar_read(rmon);
}
}
static int gfar_sset_count(struct net_device *dev, int sset)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment