aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstephen hemminger <shemminger@vyatta.com>2010-12-31 10:34:27 -0500
committerDavid S. Miller <davem@davemloft.net>2011-01-01 17:02:24 -0500
commit0885a30b699a2c96d892b61cc48e8ba68fe87bfc (patch)
tree870ab51f527bc7369190075682e739b274f01803
parenta016892cd6eb8d3dd9769021b088917ac7371abd (diff)
sky2: implement 64 bit stats
This implements 64 bit statistics support and fixes races when reading counter values. The PHY counters can only be accessed 16 bits at a time, so they are subject to carry races. NB: * TX/RX counters are maintained in software because the the hardware packet count is only a 32 bit value. * Error counters are really only 32 bit. * Old 32 bit counter fields in dev->stats still used for some software counters Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/sky2.c103
-rw-r--r--drivers/net/sky2.h42
2 files changed, 109 insertions, 36 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 0d4a236c3bb3..39996bf3b247 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1917,8 +1917,10 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
1917 netif_printk(sky2, tx_done, KERN_DEBUG, dev, 1917 netif_printk(sky2, tx_done, KERN_DEBUG, dev,
1918 "tx done %u\n", idx); 1918 "tx done %u\n", idx);
1919 1919
1920 dev->stats.tx_packets++; 1920 u64_stats_update_begin(&sky2->tx_stats.syncp);
1921 dev->stats.tx_bytes += skb->len; 1921 ++sky2->tx_stats.packets;
1922 sky2->tx_stats.bytes += skb->len;
1923 u64_stats_update_end(&sky2->tx_stats.syncp);
1922 1924
1923 re->skb = NULL; 1925 re->skb = NULL;
1924 dev_kfree_skb_any(skb); 1926 dev_kfree_skb_any(skb);
@@ -2460,7 +2462,7 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
2460 2462
2461 /* if length reported by DMA does not match PHY, packet was truncated */ 2463 /* if length reported by DMA does not match PHY, packet was truncated */
2462 if (length != count) 2464 if (length != count)
2463 goto len_error; 2465 goto error;
2464 2466
2465okay: 2467okay:
2466 if (length < copybreak) 2468 if (length < copybreak)
@@ -2475,34 +2477,13 @@ resubmit:
2475 2477
2476 return skb; 2478 return skb;
2477 2479
2478len_error:
2479 /* Truncation of overlength packets
2480 causes PHY length to not match MAC length */
2481 ++dev->stats.rx_length_errors;
2482 if (net_ratelimit())
2483 netif_info(sky2, rx_err, dev,
2484 "rx length error: status %#x length %d\n",
2485 status, length);
2486 goto resubmit;
2487
2488error: 2480error:
2489 ++dev->stats.rx_errors; 2481 ++dev->stats.rx_errors;
2490 if (status & GMR_FS_RX_FF_OV) {
2491 dev->stats.rx_over_errors++;
2492 goto resubmit;
2493 }
2494 2482
2495 if (net_ratelimit()) 2483 if (net_ratelimit())
2496 netif_info(sky2, rx_err, dev, 2484 netif_info(sky2, rx_err, dev,
2497 "rx error, status 0x%x length %d\n", status, length); 2485 "rx error, status 0x%x length %d\n", status, length);
2498 2486
2499 if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE))
2500 dev->stats.rx_length_errors++;
2501 if (status & GMR_FS_FRAGMENT)
2502 dev->stats.rx_frame_errors++;
2503 if (status & GMR_FS_CRC_ERR)
2504 dev->stats.rx_crc_errors++;
2505
2506 goto resubmit; 2487 goto resubmit;
2507} 2488}
2508 2489
@@ -2543,14 +2524,19 @@ static inline void sky2_skb_rx(const struct sky2_port *sky2,
2543static inline void sky2_rx_done(struct sky2_hw *hw, unsigned port, 2524static inline void sky2_rx_done(struct sky2_hw *hw, unsigned port,
2544 unsigned packets, unsigned bytes) 2525 unsigned packets, unsigned bytes)
2545{ 2526{
2546 if (packets) { 2527 struct net_device *dev = hw->dev[port];
2547 struct net_device *dev = hw->dev[port]; 2528 struct sky2_port *sky2 = netdev_priv(dev);
2548 2529
2549 dev->stats.rx_packets += packets; 2530 if (packets == 0)
2550 dev->stats.rx_bytes += bytes; 2531 return;
2551 dev->last_rx = jiffies; 2532
2552 sky2_rx_update(netdev_priv(dev), rxqaddr[port]); 2533 u64_stats_update_begin(&sky2->rx_stats.syncp);
2553 } 2534 sky2->rx_stats.packets += packets;
2535 sky2->rx_stats.bytes += bytes;
2536 u64_stats_update_end(&sky2->rx_stats.syncp);
2537
2538 dev->last_rx = jiffies;
2539 sky2_rx_update(netdev_priv(dev), rxqaddr[port]);
2554} 2540}
2555 2541
2556static void sky2_rx_checksum(struct sky2_port *sky2, u32 status) 2542static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)
@@ -3626,13 +3612,11 @@ static void sky2_phy_stats(struct sky2_port *sky2, u64 * data, unsigned count)
3626 unsigned port = sky2->port; 3612 unsigned port = sky2->port;
3627 int i; 3613 int i;
3628 3614
3629 data[0] = (u64) gma_read32(hw, port, GM_TXO_OK_HI) << 32 3615 data[0] = get_stats64(hw, port, GM_TXO_OK_LO);
3630 | (u64) gma_read32(hw, port, GM_TXO_OK_LO); 3616 data[1] = get_stats64(hw, port, GM_RXO_OK_LO);
3631 data[1] = (u64) gma_read32(hw, port, GM_RXO_OK_HI) << 32
3632 | (u64) gma_read32(hw, port, GM_RXO_OK_LO);
3633 3617
3634 for (i = 2; i < count; i++) 3618 for (i = 2; i < count; i++)
3635 data[i] = (u64) gma_read32(hw, port, sky2_stats[i].offset); 3619 data[i] = get_stats32(hw, port, sky2_stats[i].offset);
3636} 3620}
3637 3621
3638static void sky2_set_msglevel(struct net_device *netdev, u32 value) 3622static void sky2_set_msglevel(struct net_device *netdev, u32 value)
@@ -3750,6 +3734,51 @@ static void sky2_set_multicast(struct net_device *dev)
3750 gma_write16(hw, port, GM_RX_CTRL, reg); 3734 gma_write16(hw, port, GM_RX_CTRL, reg);
3751} 3735}
3752 3736
3737static struct rtnl_link_stats64 *sky2_get_stats(struct net_device *dev,
3738 struct rtnl_link_stats64 *stats)
3739{
3740 struct sky2_port *sky2 = netdev_priv(dev);
3741 struct sky2_hw *hw = sky2->hw;
3742 unsigned port = sky2->port;
3743 unsigned int start;
3744 u64 _bytes, _packets;
3745
3746 do {
3747 start = u64_stats_fetch_begin_bh(&sky2->rx_stats.syncp);
3748 _bytes = sky2->rx_stats.bytes;
3749 _packets = sky2->rx_stats.packets;
3750 } while (u64_stats_fetch_retry_bh(&sky2->rx_stats.syncp, start));
3751
3752 stats->rx_packets = _packets;
3753 stats->rx_bytes = _bytes;
3754
3755 do {
3756 start = u64_stats_fetch_begin_bh(&sky2->tx_stats.syncp);
3757 _bytes = sky2->tx_stats.bytes;
3758 _packets = sky2->tx_stats.packets;
3759 } while (u64_stats_fetch_retry_bh(&sky2->tx_stats.syncp, start));
3760
3761 stats->tx_packets = _packets;
3762 stats->tx_bytes = _bytes;
3763
3764 stats->multicast = get_stats32(hw, port, GM_RXF_MC_OK)
3765 + get_stats32(hw, port, GM_RXF_BC_OK);
3766
3767 stats->collisions = get_stats32(hw, port, GM_TXF_COL);
3768
3769 stats->rx_length_errors = get_stats32(hw, port, GM_RXF_LNG_ERR);
3770 stats->rx_crc_errors = get_stats32(hw, port, GM_RXF_FCS_ERR);
3771 stats->rx_frame_errors = get_stats32(hw, port, GM_RXF_SHT)
3772 + get_stats32(hw, port, GM_RXE_FRAG);
3773 stats->rx_over_errors = get_stats32(hw, port, GM_RXE_FIFO_OV);
3774
3775 stats->rx_dropped = dev->stats.rx_dropped;
3776 stats->rx_fifo_errors = dev->stats.rx_fifo_errors;
3777 stats->tx_fifo_errors = dev->stats.tx_fifo_errors;
3778
3779 return stats;
3780}
3781
3753/* Can have one global because blinking is controlled by 3782/* Can have one global because blinking is controlled by
3754 * ethtool and that is always under RTNL mutex 3783 * ethtool and that is always under RTNL mutex
3755 */ 3784 */
@@ -4524,6 +4553,7 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
4524 .ndo_set_multicast_list = sky2_set_multicast, 4553 .ndo_set_multicast_list = sky2_set_multicast,
4525 .ndo_change_mtu = sky2_change_mtu, 4554 .ndo_change_mtu = sky2_change_mtu,
4526 .ndo_tx_timeout = sky2_tx_timeout, 4555 .ndo_tx_timeout = sky2_tx_timeout,
4556 .ndo_get_stats64 = sky2_get_stats,
4527#ifdef SKY2_VLAN_TAG_USED 4557#ifdef SKY2_VLAN_TAG_USED
4528 .ndo_vlan_rx_register = sky2_vlan_rx_register, 4558 .ndo_vlan_rx_register = sky2_vlan_rx_register,
4529#endif 4559#endif
@@ -4541,6 +4571,7 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
4541 .ndo_set_multicast_list = sky2_set_multicast, 4571 .ndo_set_multicast_list = sky2_set_multicast,
4542 .ndo_change_mtu = sky2_change_mtu, 4572 .ndo_change_mtu = sky2_change_mtu,
4543 .ndo_tx_timeout = sky2_tx_timeout, 4573 .ndo_tx_timeout = sky2_tx_timeout,
4574 .ndo_get_stats64 = sky2_get_stats,
4544#ifdef SKY2_VLAN_TAG_USED 4575#ifdef SKY2_VLAN_TAG_USED
4545 .ndo_vlan_rx_register = sky2_vlan_rx_register, 4576 .ndo_vlan_rx_register = sky2_vlan_rx_register,
4546#endif 4577#endif
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 61891a6cacc2..80bdc404f1ea 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -2200,6 +2200,12 @@ enum flow_control {
2200 FC_BOTH = 3, 2200 FC_BOTH = 3,
2201}; 2201};
2202 2202
2203struct sky2_stats {
2204 struct u64_stats_sync syncp;
2205 u64 packets;
2206 u64 bytes;
2207};
2208
2203struct sky2_port { 2209struct sky2_port {
2204 struct sky2_hw *hw; 2210 struct sky2_hw *hw;
2205 struct net_device *netdev; 2211 struct net_device *netdev;
@@ -2209,6 +2215,8 @@ struct sky2_port {
2209 2215
2210 struct tx_ring_info *tx_ring; 2216 struct tx_ring_info *tx_ring;
2211 struct sky2_tx_le *tx_le; 2217 struct sky2_tx_le *tx_le;
2218 struct sky2_stats tx_stats;
2219
2212 u16 tx_ring_size; 2220 u16 tx_ring_size;
2213 u16 tx_cons; /* next le to check */ 2221 u16 tx_cons; /* next le to check */
2214 u16 tx_prod; /* next le to use */ 2222 u16 tx_prod; /* next le to use */
@@ -2221,6 +2229,7 @@ struct sky2_port {
2221 2229
2222 struct rx_ring_info *rx_ring ____cacheline_aligned_in_smp; 2230 struct rx_ring_info *rx_ring ____cacheline_aligned_in_smp;
2223 struct sky2_rx_le *rx_le; 2231 struct sky2_rx_le *rx_le;
2232 struct sky2_stats rx_stats;
2224 2233
2225 u16 rx_next; /* next re to check */ 2234 u16 rx_next; /* next re to check */
2226 u16 rx_put; /* next le index to use */ 2235 u16 rx_put; /* next le index to use */
@@ -2346,6 +2355,39 @@ static inline u32 gma_read32(struct sky2_hw *hw, unsigned port, unsigned reg)
2346 | (u32) sky2_read16(hw, base+4) << 16; 2355 | (u32) sky2_read16(hw, base+4) << 16;
2347} 2356}
2348 2357
2358static inline u64 gma_read64(struct sky2_hw *hw, unsigned port, unsigned reg)
2359{
2360 unsigned base = SK_GMAC_REG(port, reg);
2361
2362 return (u64) sky2_read16(hw, base)
2363 | (u64) sky2_read16(hw, base+4) << 16
2364 | (u64) sky2_read16(hw, base+8) << 32
2365 | (u64) sky2_read16(hw, base+12) << 48;
2366}
2367
2368/* There is no way to atomically read32 bit values from PHY, so retry */
2369static inline u32 get_stats32(struct sky2_hw *hw, unsigned port, unsigned reg)
2370{
2371 u32 val;
2372
2373 do {
2374 val = gma_read32(hw, port, reg);
2375 } while (gma_read32(hw, port, reg) != val);
2376
2377 return val;
2378}
2379
2380static inline u64 get_stats64(struct sky2_hw *hw, unsigned port, unsigned reg)
2381{
2382 u64 val;
2383
2384 do {
2385 val = gma_read64(hw, port, reg);
2386 } while (gma_read64(hw, port, reg) != val);
2387
2388 return val;
2389}
2390
2349static inline void gma_write16(const struct sky2_hw *hw, unsigned port, int r, u16 v) 2391static inline void gma_write16(const struct sky2_hw *hw, unsigned port, int r, u16 v)
2350{ 2392{
2351 sky2_write16(hw, SK_GMAC_REG(port,r), v); 2393 sky2_write16(hw, SK_GMAC_REG(port,r), v);