aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-02-13 13:18:20 -0500
committerDavid S. Miller <davem@davemloft.net>2013-02-13 13:18:20 -0500
commitd0023f820e003857248d14f2213ac3930283f16c (patch)
tree8a821bff0bc791e23441e90835db6e348ffa407e
parent959d5fdee7aa32fa04bc2c37e3d3871ad266fe97 (diff)
parent212079df6d77c0daada96b1d906f4b7749871411 (diff)
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: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c26
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h39
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c17
3 files changed, 37 insertions, 45 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index ab32bd0be8ff..c82f67727f43 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -2648,7 +2648,7 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
2648 if (status & RXBD_TRUNCATED) { 2648 if (status & RXBD_TRUNCATED) {
2649 stats->rx_length_errors++; 2649 stats->rx_length_errors++;
2650 2650
2651 estats->rx_trunc++; 2651 atomic64_inc(&estats->rx_trunc);
2652 2652
2653 return; 2653 return;
2654 } 2654 }
@@ -2657,20 +2657,20 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
2657 stats->rx_length_errors++; 2657 stats->rx_length_errors++;
2658 2658
2659 if (status & RXBD_LARGE) 2659 if (status & RXBD_LARGE)
2660 estats->rx_large++; 2660 atomic64_inc(&estats->rx_large);
2661 else 2661 else
2662 estats->rx_short++; 2662 atomic64_inc(&estats->rx_short);
2663 } 2663 }
2664 if (status & RXBD_NONOCTET) { 2664 if (status & RXBD_NONOCTET) {
2665 stats->rx_frame_errors++; 2665 stats->rx_frame_errors++;
2666 estats->rx_nonoctet++; 2666 atomic64_inc(&estats->rx_nonoctet);
2667 } 2667 }
2668 if (status & RXBD_CRCERR) { 2668 if (status & RXBD_CRCERR) {
2669 estats->rx_crcerr++; 2669 atomic64_inc(&estats->rx_crcerr);
2670 stats->rx_crc_errors++; 2670 stats->rx_crc_errors++;
2671 } 2671 }
2672 if (status & RXBD_OVERRUN) { 2672 if (status & RXBD_OVERRUN) {
2673 estats->rx_overrun++; 2673 atomic64_inc(&estats->rx_overrun);
2674 stats->rx_crc_errors++; 2674 stats->rx_crc_errors++;
2675 } 2675 }
2676} 2676}
@@ -2744,7 +2744,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
2744 ret = napi_gro_receive(napi, skb); 2744 ret = napi_gro_receive(napi, skb);
2745 2745
2746 if (GRO_DROP == ret) 2746 if (GRO_DROP == ret)
2747 priv->extra_stats.kernel_dropped++; 2747 atomic64_inc(&priv->extra_stats.kernel_dropped);
2748 2748
2749 return 0; 2749 return 0;
2750} 2750}
@@ -2812,7 +2812,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
2812 } else { 2812 } else {
2813 netif_warn(priv, rx_err, dev, "Missing skb!\n"); 2813 netif_warn(priv, rx_err, dev, "Missing skb!\n");
2814 rx_queue->stats.rx_dropped++; 2814 rx_queue->stats.rx_dropped++;
2815 priv->extra_stats.rx_skbmissing++; 2815 atomic64_inc(&priv->extra_stats.rx_skbmissing);
2816 } 2816 }
2817 2817
2818 } 2818 }
@@ -3245,7 +3245,7 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
3245 netif_dbg(priv, tx_err, dev, 3245 netif_dbg(priv, tx_err, dev,
3246 "TX FIFO underrun, packet dropped\n"); 3246 "TX FIFO underrun, packet dropped\n");
3247 dev->stats.tx_dropped++; 3247 dev->stats.tx_dropped++;
3248 priv->extra_stats.tx_underrun++; 3248 atomic64_inc(&priv->extra_stats.tx_underrun);
3249 3249
3250 local_irq_save(flags); 3250 local_irq_save(flags);
3251 lock_tx_qs(priv); 3251 lock_tx_qs(priv);
@@ -3260,7 +3260,7 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
3260 } 3260 }
3261 if (events & IEVENT_BSY) { 3261 if (events & IEVENT_BSY) {
3262 dev->stats.rx_errors++; 3262 dev->stats.rx_errors++;
3263 priv->extra_stats.rx_bsy++; 3263 atomic64_inc(&priv->extra_stats.rx_bsy);
3264 3264
3265 gfar_receive(irq, grp_id); 3265 gfar_receive(irq, grp_id);
3266 3266
@@ -3269,19 +3269,19 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
3269 } 3269 }
3270 if (events & IEVENT_BABR) { 3270 if (events & IEVENT_BABR) {
3271 dev->stats.rx_errors++; 3271 dev->stats.rx_errors++;
3272 priv->extra_stats.rx_babr++; 3272 atomic64_inc(&priv->extra_stats.rx_babr);
3273 3273
3274 netif_dbg(priv, rx_err, dev, "babbling RX error\n"); 3274 netif_dbg(priv, rx_err, dev, "babbling RX error\n");
3275 } 3275 }
3276 if (events & IEVENT_EBERR) { 3276 if (events & IEVENT_EBERR) {
3277 priv->extra_stats.eberr++; 3277 atomic64_inc(&priv->extra_stats.eberr);
3278 netif_dbg(priv, rx_err, dev, "bus error\n"); 3278 netif_dbg(priv, rx_err, dev, "bus error\n");
3279 } 3279 }
3280 if (events & IEVENT_RXC) 3280 if (events & IEVENT_RXC)
3281 netif_dbg(priv, rx_status, dev, "control frame\n"); 3281 netif_dbg(priv, rx_status, dev, "control frame\n");
3282 3282
3283 if (events & IEVENT_BABT) { 3283 if (events & IEVENT_BABT) {
3284 priv->extra_stats.tx_babt++; 3284 atomic64_inc(&priv->extra_stats.tx_babt);
3285 netif_dbg(priv, tx_err, dev, "babbling TX error\n"); 3285 netif_dbg(priv, tx_err, dev, "babbling TX error\n");
3286 } 3286 }
3287 return IRQ_HANDLED; 3287 return IRQ_HANDLED;
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 71793f4fca32..78125f1f870e 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -627,34 +627,29 @@ struct rmon_mib
627}; 627};
628 628
629struct gfar_extra_stats { 629struct gfar_extra_stats {
630 u64 kernel_dropped; 630 atomic64_t kernel_dropped;
631 u64 rx_large; 631 atomic64_t rx_large;
632 u64 rx_short; 632 atomic64_t rx_short;
633 u64 rx_nonoctet; 633 atomic64_t rx_nonoctet;
634 u64 rx_crcerr; 634 atomic64_t rx_crcerr;
635 u64 rx_overrun; 635 atomic64_t rx_overrun;
636 u64 rx_bsy; 636 atomic64_t rx_bsy;
637 u64 rx_babr; 637 atomic64_t rx_babr;
638 u64 rx_trunc; 638 atomic64_t rx_trunc;
639 u64 eberr; 639 atomic64_t eberr;
640 u64 tx_babt; 640 atomic64_t tx_babt;
641 u64 tx_underrun; 641 atomic64_t tx_underrun;
642 u64 rx_skbmissing; 642 atomic64_t rx_skbmissing;
643 u64 tx_timeout; 643 atomic64_t tx_timeout;
644}; 644};
645 645
646#define GFAR_RMON_LEN ((sizeof(struct rmon_mib) - 16)/sizeof(u32)) 646#define GFAR_RMON_LEN ((sizeof(struct rmon_mib) - 16)/sizeof(u32))
647#define GFAR_EXTRA_STATS_LEN (sizeof(struct gfar_extra_stats)/sizeof(u64)) 647#define GFAR_EXTRA_STATS_LEN \
648 (sizeof(struct gfar_extra_stats)/sizeof(atomic64_t))
648 649
649/* Number of stats in the stats structure (ignore car and cam regs)*/ 650/* Number of stats exported via ethtool */
650#define GFAR_STATS_LEN (GFAR_RMON_LEN + GFAR_EXTRA_STATS_LEN) 651#define GFAR_STATS_LEN (GFAR_RMON_LEN + GFAR_EXTRA_STATS_LEN)
651 652
652struct gfar_stats {
653 u64 extra[GFAR_EXTRA_STATS_LEN];
654 u64 rmon[GFAR_RMON_LEN];
655};
656
657
658struct gfar { 653struct gfar {
659 u32 tsec_id; /* 0x.000 - Controller ID register */ 654 u32 tsec_id; /* 0x.000 - Controller ID register */
660 u32 tsec_id2; /* 0x.004 - Controller ID2 register */ 655 u32 tsec_id2; /* 0x.004 - Controller ID2 register */
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 45e59d5c071f..75e89acf4912 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -149,20 +149,17 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
149 int i; 149 int i;
150 struct gfar_private *priv = netdev_priv(dev); 150 struct gfar_private *priv = netdev_priv(dev);
151 struct gfar __iomem *regs = priv->gfargrp[0].regs; 151 struct gfar __iomem *regs = priv->gfargrp[0].regs;
152 u64 *extra = (u64 *) & priv->extra_stats; 152 atomic64_t *extra = (atomic64_t *)&priv->extra_stats;
153
154 for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
155 buf[i] = atomic64_read(&extra[i]);
153 156
154 if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { 157 if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
155 u32 __iomem *rmon = (u32 __iomem *) &regs->rmon; 158 u32 __iomem *rmon = (u32 __iomem *) &regs->rmon;
156 struct gfar_stats *stats = (struct gfar_stats *) buf;
157
158 for (i = 0; i < GFAR_RMON_LEN; i++)
159 stats->rmon[i] = (u64) gfar_read(&rmon[i]);
160 159
161 for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) 160 for (; i < GFAR_STATS_LEN; i++, rmon++)
162 stats->extra[i] = extra[i]; 161 buf[i] = (u64) gfar_read(rmon);
163 } else 162 }
164 for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
165 buf[i] = extra[i];
166} 163}
167 164
168static int gfar_sset_count(struct net_device *dev, int sset) 165static int gfar_sset_count(struct net_device *dev, int sset)