diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2012-02-28 18:33:37 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-02-29 13:46:05 -0500 |
commit | 65ec698d1368fc64d0b93fb703783d25ec550577 (patch) | |
tree | 3823115e31e764ca677d7198873dc4da95b0b69f /drivers/net | |
parent | 4c90d3b30334833450ccbb02f452d4972a3c3c3f (diff) |
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: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 45 |
1 files changed, 23 insertions, 22 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index a1f2e0fed78b..423d0235a878 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c | |||
@@ -7886,10 +7886,8 @@ static int tg3_chip_reset(struct tg3 *tp) | |||
7886 | return 0; | 7886 | return 0; |
7887 | } | 7887 | } |
7888 | 7888 | ||
7889 | static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *, | 7889 | static void tg3_get_nstats(struct tg3 *, struct rtnl_link_stats64 *); |
7890 | struct rtnl_link_stats64 *); | 7890 | static void tg3_get_estats(struct tg3 *, struct tg3_ethtool_stats *); |
7891 | static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *, | ||
7892 | struct tg3_ethtool_stats *); | ||
7893 | 7891 | ||
7894 | /* tp->lock is held. */ | 7892 | /* tp->lock is held. */ |
7895 | static int tg3_halt(struct tg3 *tp, int kind, int silent) | 7893 | 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 | 7908 | ||
7911 | if (tp->hw_stats) { | 7909 | if (tp->hw_stats) { |
7912 | /* Save the stats across chip resets... */ | 7910 | /* Save the stats across chip resets... */ |
7913 | tg3_get_stats64(tp->dev, &tp->net_stats_prev), | 7911 | tg3_get_nstats(tp, &tp->net_stats_prev), |
7914 | tg3_get_estats(tp, &tp->estats_prev); | 7912 | tg3_get_estats(tp, &tp->estats_prev); |
7915 | 7913 | ||
7916 | /* And make sure the next sample is new data */ | 7914 | /* And make sure the next sample is new data */ |
@@ -9847,7 +9845,7 @@ static inline u64 get_stat64(tg3_stat64_t *val) | |||
9847 | return ((u64)val->high << 32) | ((u64)val->low); | 9845 | return ((u64)val->high << 32) | ((u64)val->low); |
9848 | } | 9846 | } |
9849 | 9847 | ||
9850 | static u64 calc_crc_errors(struct tg3 *tp) | 9848 | static u64 tg3_calc_crc_errors(struct tg3 *tp) |
9851 | { | 9849 | { |
9852 | struct tg3_hw_stats *hw_stats = tp->hw_stats; | 9850 | struct tg3_hw_stats *hw_stats = tp->hw_stats; |
9853 | 9851 | ||
@@ -9856,14 +9854,12 @@ static u64 calc_crc_errors(struct tg3 *tp) | |||
9856 | GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { | 9854 | GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { |
9857 | u32 val; | 9855 | u32 val; |
9858 | 9856 | ||
9859 | spin_lock_bh(&tp->lock); | ||
9860 | if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) { | 9857 | if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) { |
9861 | tg3_writephy(tp, MII_TG3_TEST1, | 9858 | tg3_writephy(tp, MII_TG3_TEST1, |
9862 | val | MII_TG3_TEST1_CRC_EN); | 9859 | val | MII_TG3_TEST1_CRC_EN); |
9863 | tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &val); | 9860 | tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &val); |
9864 | } else | 9861 | } else |
9865 | val = 0; | 9862 | val = 0; |
9866 | spin_unlock_bh(&tp->lock); | ||
9867 | 9863 | ||
9868 | tp->phy_crc_errors += val; | 9864 | tp->phy_crc_errors += val; |
9869 | 9865 | ||
@@ -9877,14 +9873,13 @@ static u64 calc_crc_errors(struct tg3 *tp) | |||
9877 | estats->member = old_estats->member + \ | 9873 | estats->member = old_estats->member + \ |
9878 | get_stat64(&hw_stats->member) | 9874 | get_stat64(&hw_stats->member) |
9879 | 9875 | ||
9880 | static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp, | 9876 | static void tg3_get_estats(struct tg3 *tp, struct tg3_ethtool_stats *estats) |
9881 | struct tg3_ethtool_stats *estats) | ||
9882 | { | 9877 | { |
9883 | struct tg3_ethtool_stats *old_estats = &tp->estats_prev; | 9878 | struct tg3_ethtool_stats *old_estats = &tp->estats_prev; |
9884 | struct tg3_hw_stats *hw_stats = tp->hw_stats; | 9879 | struct tg3_hw_stats *hw_stats = tp->hw_stats; |
9885 | 9880 | ||
9886 | if (!hw_stats) | 9881 | if (!hw_stats) |
9887 | return old_estats; | 9882 | return; |
9888 | 9883 | ||
9889 | ESTAT_ADD(rx_octets); | 9884 | ESTAT_ADD(rx_octets); |
9890 | ESTAT_ADD(rx_fragments); | 9885 | ESTAT_ADD(rx_fragments); |
@@ -9963,20 +9958,13 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp, | |||
9963 | ESTAT_ADD(nic_tx_threshold_hit); | 9958 | ESTAT_ADD(nic_tx_threshold_hit); |
9964 | 9959 | ||
9965 | ESTAT_ADD(mbuf_lwm_thresh_hit); | 9960 | ESTAT_ADD(mbuf_lwm_thresh_hit); |
9966 | |||
9967 | return estats; | ||
9968 | } | 9961 | } |
9969 | 9962 | ||
9970 | static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, | 9963 | static void tg3_get_nstats(struct tg3 *tp, struct rtnl_link_stats64 *stats) |
9971 | struct rtnl_link_stats64 *stats) | ||
9972 | { | 9964 | { |
9973 | struct tg3 *tp = netdev_priv(dev); | ||
9974 | struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev; | 9965 | struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev; |
9975 | struct tg3_hw_stats *hw_stats = tp->hw_stats; | 9966 | struct tg3_hw_stats *hw_stats = tp->hw_stats; |
9976 | 9967 | ||
9977 | if (!hw_stats) | ||
9978 | return old_stats; | ||
9979 | |||
9980 | stats->rx_packets = old_stats->rx_packets + | 9968 | stats->rx_packets = old_stats->rx_packets + |
9981 | get_stat64(&hw_stats->rx_ucast_packets) + | 9969 | get_stat64(&hw_stats->rx_ucast_packets) + |
9982 | get_stat64(&hw_stats->rx_mcast_packets) + | 9970 | get_stat64(&hw_stats->rx_mcast_packets) + |
@@ -10019,15 +10007,13 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, | |||
10019 | get_stat64(&hw_stats->tx_carrier_sense_errors); | 10007 | get_stat64(&hw_stats->tx_carrier_sense_errors); |
10020 | 10008 | ||
10021 | stats->rx_crc_errors = old_stats->rx_crc_errors + | 10009 | stats->rx_crc_errors = old_stats->rx_crc_errors + |
10022 | calc_crc_errors(tp); | 10010 | tg3_calc_crc_errors(tp); |
10023 | 10011 | ||
10024 | stats->rx_missed_errors = old_stats->rx_missed_errors + | 10012 | stats->rx_missed_errors = old_stats->rx_missed_errors + |
10025 | get_stat64(&hw_stats->rx_discards); | 10013 | get_stat64(&hw_stats->rx_discards); |
10026 | 10014 | ||
10027 | stats->rx_dropped = tp->rx_dropped; | 10015 | stats->rx_dropped = tp->rx_dropped; |
10028 | stats->tx_dropped = tp->tx_dropped; | 10016 | stats->tx_dropped = tp->tx_dropped; |
10029 | |||
10030 | return stats; | ||
10031 | } | 10017 | } |
10032 | 10018 | ||
10033 | static inline u32 calc_crc(unsigned char *buf, int len) | 10019 | static inline u32 calc_crc(unsigned char *buf, int len) |
@@ -15409,6 +15395,21 @@ static void __devinit tg3_init_coal(struct tg3 *tp) | |||
15409 | } | 15395 | } |
15410 | } | 15396 | } |
15411 | 15397 | ||
15398 | static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, | ||
15399 | struct rtnl_link_stats64 *stats) | ||
15400 | { | ||
15401 | struct tg3 *tp = netdev_priv(dev); | ||
15402 | |||
15403 | if (!tp->hw_stats) | ||
15404 | return &tp->net_stats_prev; | ||
15405 | |||
15406 | spin_lock_bh(&tp->lock); | ||
15407 | tg3_get_nstats(tp, stats); | ||
15408 | spin_unlock_bh(&tp->lock); | ||
15409 | |||
15410 | return stats; | ||
15411 | } | ||
15412 | |||
15412 | static const struct net_device_ops tg3_netdev_ops = { | 15413 | static const struct net_device_ops tg3_netdev_ops = { |
15413 | .ndo_open = tg3_open, | 15414 | .ndo_open = tg3_open, |
15414 | .ndo_stop = tg3_close, | 15415 | .ndo_stop = tg3_close, |