summaryrefslogtreecommitdiffstats
path: root/drivers/net/cxgb3/cxgb3_main.c
diff options
context:
space:
mode:
authorDivy Le Ray <divy@chelsio.com>2007-03-18 13:10:12 -0700
committerJeff Garzik <jeff@garzik.org>2007-03-23 01:48:34 -0400
commitfc90664e3438c990d280f179ccb0642711d5c553 (patch)
tree8ece58a4eec002186f1c569385830f03336b50af /drivers/net/cxgb3/cxgb3_main.c
parent2e2839627a957714808f98a802d137a7a2a1df46 (diff)
downloadlinux-fc90664e3438c990d280f179ccb0642711d5c553.tar.bz2
cxgb3 - Fix potential MAC hang
Under rare conditions, the MAC might hang while generating a pause frame. This patch fine tunes the MAC settings to avoid the issue, allows for periodic MAC state check, and triggers a recovery if hung. Also fix one MAC statistics counter for the rev board T3B2. Signed-off-by: Divy Le Ray <divy@chelsio.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/cxgb3/cxgb3_main.c')
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c46
1 files changed, 45 insertions, 1 deletions
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index b9bcda821f7c..d55383610559 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -1056,7 +1056,11 @@ static char stats_strings[][ETH_GSTRING_LEN] = {
"VLANinsertions ",
"TxCsumOffload ",
"RxCsumGood ",
- "RxDrops "
+ "RxDrops ",
+
+ "CheckTXEnToggled ",
+ "CheckResets ",
+
};
static int get_stats_count(struct net_device *dev)
@@ -1170,6 +1174,9 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
*data++ = s->rx_cong_drops;
+
+ *data++ = s->num_toggled;
+ *data++ = s->num_resets;
}
static inline void reg_block_dump(struct adapter *ap, void *buf,
@@ -2095,6 +2102,40 @@ static void check_link_status(struct adapter *adapter)
}
}
+static void check_t3b2_mac(struct adapter *adapter)
+{
+ int i;
+
+ rtnl_lock(); /* synchronize with ifdown */
+ for_each_port(adapter, i) {
+ struct net_device *dev = adapter->port[i];
+ struct port_info *p = netdev_priv(dev);
+ int status;
+
+ if (!netif_running(dev))
+ continue;
+
+ status = 0;
+ if (netif_running(dev))
+ status = t3b2_mac_watchdog_task(&p->mac);
+ if (status == 1)
+ p->mac.stats.num_toggled++;
+ else if (status == 2) {
+ struct cmac *mac = &p->mac;
+
+ t3_mac_set_mtu(mac, dev->mtu);
+ t3_mac_set_address(mac, 0, dev->dev_addr);
+ cxgb_set_rxmode(dev);
+ t3_link_start(&p->phy, mac, &p->link_config);
+ t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
+ t3_port_intr_enable(adapter, p->port_id);
+ p->mac.stats.num_resets++;
+ }
+ }
+ rtnl_unlock();
+}
+
+
static void t3_adap_check_task(struct work_struct *work)
{
struct adapter *adapter = container_of(work, struct adapter,
@@ -2115,6 +2156,9 @@ static void t3_adap_check_task(struct work_struct *work)
adapter->check_task_cnt = 0;
}
+ if (p->rev == T3_REV_B2)
+ check_t3b2_mac(adapter);
+
/* Schedule the next check update if any port is active. */
spin_lock(&adapter->work_lock);
if (adapter->open_device_map & PORT_MASK)