Commit 65ec698d authored by Matt Carlson's avatar Matt Carlson Committed by David S. Miller

tg3: Fix tg3_get_stats64 for 5700 / 5701 devs

tg3_get_stats64() takes tp->lock when dealing with non-serdes bcm5700
and bcm5701 devices.  However, functions that call tg3_halt() have
already acquired tp->lock.  When tg3_get_stats64() is called in
tg3_halt(), deadlock will occur.

This patch fixes the problem by separating the stat gathering code into
a new tg3_get_nstats() function.  tg3_get_stats64() is recoded to call
this function and take tp->lock.  The code that takes tp->lock in
tg3_calc_crc_errors() has been removed.  Function signatures have been
cleaned up too.
Signed-off-by: default avatarMatt Carlson <mcarlson@broadcom.com>
Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4c90d3b3
...@@ -7886,10 +7886,8 @@ static int tg3_chip_reset(struct tg3 *tp) ...@@ -7886,10 +7886,8 @@ static int tg3_chip_reset(struct tg3 *tp)
return 0; return 0;
} }
static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *, static void tg3_get_nstats(struct tg3 *, struct rtnl_link_stats64 *);
struct rtnl_link_stats64 *); static void tg3_get_estats(struct tg3 *, struct tg3_ethtool_stats *);
static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *,
struct tg3_ethtool_stats *);
/* tp->lock is held. */ /* tp->lock is held. */
static int tg3_halt(struct tg3 *tp, int kind, int silent) static int tg3_halt(struct tg3 *tp, int kind, int silent)
...@@ -7910,7 +7908,7 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent) ...@@ -7910,7 +7908,7 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent)
if (tp->hw_stats) { if (tp->hw_stats) {
/* Save the stats across chip resets... */ /* Save the stats across chip resets... */
tg3_get_stats64(tp->dev, &tp->net_stats_prev), tg3_get_nstats(tp, &tp->net_stats_prev),
tg3_get_estats(tp, &tp->estats_prev); tg3_get_estats(tp, &tp->estats_prev);
/* And make sure the next sample is new data */ /* And make sure the next sample is new data */
...@@ -9847,7 +9845,7 @@ static inline u64 get_stat64(tg3_stat64_t *val) ...@@ -9847,7 +9845,7 @@ static inline u64 get_stat64(tg3_stat64_t *val)
return ((u64)val->high << 32) | ((u64)val->low); return ((u64)val->high << 32) | ((u64)val->low);
} }
static u64 calc_crc_errors(struct tg3 *tp) static u64 tg3_calc_crc_errors(struct tg3 *tp)
{ {
struct tg3_hw_stats *hw_stats = tp->hw_stats; struct tg3_hw_stats *hw_stats = tp->hw_stats;
...@@ -9856,14 +9854,12 @@ static u64 calc_crc_errors(struct tg3 *tp) ...@@ -9856,14 +9854,12 @@ static u64 calc_crc_errors(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
u32 val; u32 val;
spin_lock_bh(&tp->lock);
if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) { if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) {
tg3_writephy(tp, MII_TG3_TEST1, tg3_writephy(tp, MII_TG3_TEST1,
val | MII_TG3_TEST1_CRC_EN); val | MII_TG3_TEST1_CRC_EN);
tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &val); tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &val);
} else } else
val = 0; val = 0;
spin_unlock_bh(&tp->lock);
tp->phy_crc_errors += val; tp->phy_crc_errors += val;
...@@ -9877,14 +9873,13 @@ static u64 calc_crc_errors(struct tg3 *tp) ...@@ -9877,14 +9873,13 @@ static u64 calc_crc_errors(struct tg3 *tp)
estats->member = old_estats->member + \ estats->member = old_estats->member + \
get_stat64(&hw_stats->member) get_stat64(&hw_stats->member)
static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp, static void tg3_get_estats(struct tg3 *tp, struct tg3_ethtool_stats *estats)
struct tg3_ethtool_stats *estats)
{ {
struct tg3_ethtool_stats *old_estats = &tp->estats_prev; struct tg3_ethtool_stats *old_estats = &tp->estats_prev;
struct tg3_hw_stats *hw_stats = tp->hw_stats; struct tg3_hw_stats *hw_stats = tp->hw_stats;
if (!hw_stats) if (!hw_stats)
return old_estats; return;
ESTAT_ADD(rx_octets); ESTAT_ADD(rx_octets);
ESTAT_ADD(rx_fragments); ESTAT_ADD(rx_fragments);
...@@ -9963,20 +9958,13 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp, ...@@ -9963,20 +9958,13 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp,
ESTAT_ADD(nic_tx_threshold_hit); ESTAT_ADD(nic_tx_threshold_hit);
ESTAT_ADD(mbuf_lwm_thresh_hit); ESTAT_ADD(mbuf_lwm_thresh_hit);
return estats;
} }
static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, static void tg3_get_nstats(struct tg3 *tp, struct rtnl_link_stats64 *stats)
struct rtnl_link_stats64 *stats)
{ {
struct tg3 *tp = netdev_priv(dev);
struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev; struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev;
struct tg3_hw_stats *hw_stats = tp->hw_stats; struct tg3_hw_stats *hw_stats = tp->hw_stats;
if (!hw_stats)
return old_stats;
stats->rx_packets = old_stats->rx_packets + stats->rx_packets = old_stats->rx_packets +
get_stat64(&hw_stats->rx_ucast_packets) + get_stat64(&hw_stats->rx_ucast_packets) +
get_stat64(&hw_stats->rx_mcast_packets) + get_stat64(&hw_stats->rx_mcast_packets) +
...@@ -10019,15 +10007,13 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, ...@@ -10019,15 +10007,13 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
get_stat64(&hw_stats->tx_carrier_sense_errors); get_stat64(&hw_stats->tx_carrier_sense_errors);
stats->rx_crc_errors = old_stats->rx_crc_errors + stats->rx_crc_errors = old_stats->rx_crc_errors +
calc_crc_errors(tp); tg3_calc_crc_errors(tp);
stats->rx_missed_errors = old_stats->rx_missed_errors + stats->rx_missed_errors = old_stats->rx_missed_errors +
get_stat64(&hw_stats->rx_discards); get_stat64(&hw_stats->rx_discards);
stats->rx_dropped = tp->rx_dropped; stats->rx_dropped = tp->rx_dropped;
stats->tx_dropped = tp->tx_dropped; stats->tx_dropped = tp->tx_dropped;
return stats;
} }
static inline u32 calc_crc(unsigned char *buf, int len) static inline u32 calc_crc(unsigned char *buf, int len)
...@@ -15409,6 +15395,21 @@ static void __devinit tg3_init_coal(struct tg3 *tp) ...@@ -15409,6 +15395,21 @@ static void __devinit tg3_init_coal(struct tg3 *tp)
} }
} }
static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
struct rtnl_link_stats64 *stats)
{
struct tg3 *tp = netdev_priv(dev);
if (!tp->hw_stats)
return &tp->net_stats_prev;
spin_lock_bh(&tp->lock);
tg3_get_nstats(tp, stats);
spin_unlock_bh(&tp->lock);
return stats;
}
static const struct net_device_ops tg3_netdev_ops = { static const struct net_device_ops tg3_netdev_ops = {
.ndo_open = tg3_open, .ndo_open = tg3_open,
.ndo_stop = tg3_close, .ndo_stop = tg3_close,
......
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