Skip to content

Commit

Permalink
Merge branch 'gfar-ethtool-atomic' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/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: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Feb 13, 2013
2 parents 959d5fd + 212079d commit d0023f8
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 45 deletions.
26 changes: 13 additions & 13 deletions drivers/net/ethernet/freescale/gianfar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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++;
}
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}

}
Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand All @@ -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;
Expand Down
39 changes: 17 additions & 22 deletions drivers/net/ethernet/freescale/gianfar.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
17 changes: 7 additions & 10 deletions drivers/net/ethernet/freescale/gianfar_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit d0023f8

Please sign in to comment.