diff options
author | stephen hemminger <shemminger@vyatta.com> | 2010-12-31 15:34:27 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-01-01 14:02:24 -0800 |
commit | 0885a30b699a2c96d892b61cc48e8ba68fe87bfc (patch) | |
tree | 870ab51f527bc7369190075682e739b274f01803 /drivers/net/sky2.h | |
parent | a016892cd6eb8d3dd9769021b088917ac7371abd (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>
Diffstat (limited to 'drivers/net/sky2.h')
-rw-r--r-- | drivers/net/sky2.h | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 61891a6cacc..80bdc404f1e 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2200,6 +2200,12 @@ enum flow_control { FC_BOTH = 3, }; +struct sky2_stats { + struct u64_stats_sync syncp; + u64 packets; + u64 bytes; +}; + struct sky2_port { struct sky2_hw *hw; struct net_device *netdev; @@ -2209,6 +2215,8 @@ struct sky2_port { struct tx_ring_info *tx_ring; struct sky2_tx_le *tx_le; + struct sky2_stats tx_stats; + u16 tx_ring_size; u16 tx_cons; /* next le to check */ u16 tx_prod; /* next le to use */ @@ -2221,6 +2229,7 @@ struct sky2_port { struct rx_ring_info *rx_ring ____cacheline_aligned_in_smp; struct sky2_rx_le *rx_le; + struct sky2_stats rx_stats; u16 rx_next; /* next re to check */ 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) | (u32) sky2_read16(hw, base+4) << 16; } +static inline u64 gma_read64(struct sky2_hw *hw, unsigned port, unsigned reg) +{ + unsigned base = SK_GMAC_REG(port, reg); + + return (u64) sky2_read16(hw, base) + | (u64) sky2_read16(hw, base+4) << 16 + | (u64) sky2_read16(hw, base+8) << 32 + | (u64) sky2_read16(hw, base+12) << 48; +} + +/* There is no way to atomically read32 bit values from PHY, so retry */ +static inline u32 get_stats32(struct sky2_hw *hw, unsigned port, unsigned reg) +{ + u32 val; + + do { + val = gma_read32(hw, port, reg); + } while (gma_read32(hw, port, reg) != val); + + return val; +} + +static inline u64 get_stats64(struct sky2_hw *hw, unsigned port, unsigned reg) +{ + u64 val; + + do { + val = gma_read64(hw, port, reg); + } while (gma_read64(hw, port, reg) != val); + + return val; +} + static inline void gma_write16(const struct sky2_hw *hw, unsigned port, int r, u16 v) { sky2_write16(hw, SK_GMAC_REG(port,r), v); |