aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDivy Le Ray <divy@chelsio.com>2009-03-12 17:14:19 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-13 14:30:47 -0400
commitbf792094ef830117312b3990b63474320ec864c0 (patch)
treedb47894a787ec8eee78b34c500661fd17231229f
parentcd40658a616050df0a50d0a3ded06e3ebcc0a04a (diff)
cxgb3: detect mac link faults.
The driver currently ignores the local or remote link faults raised at the mac layer. This patch fixes it. Our mac however only advertizes link events, so wait for the phy to stabilize the link, then enable mac link events interrupts. Signed-off-by: Divy Le Ray <divy@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/cxgb3/adapter.h5
-rw-r--r--drivers/net/cxgb3/common.h6
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c123
-rw-r--r--drivers/net/cxgb3/regs.h13
-rw-r--r--drivers/net/cxgb3/t3_hw.c134
-rw-r--r--drivers/net/cxgb3/xgmac.c13
6 files changed, 285 insertions, 9 deletions
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 66ce456614a8..71eaa431371d 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -68,6 +68,8 @@ struct port_info {
68 struct net_device_stats netstats; 68 struct net_device_stats netstats;
69 int activity; 69 int activity;
70 __be32 iscsi_ipv4addr; 70 __be32 iscsi_ipv4addr;
71
72 int link_fault; /* link fault was detected */
71}; 73};
72 74
73enum { /* adapter flags */ 75enum { /* adapter flags */
@@ -241,6 +243,7 @@ struct adapter {
241 struct delayed_work adap_check_task; 243 struct delayed_work adap_check_task;
242 struct work_struct ext_intr_handler_task; 244 struct work_struct ext_intr_handler_task;
243 struct work_struct fatal_error_handler_task; 245 struct work_struct fatal_error_handler_task;
246 struct work_struct link_fault_handler_task;
244 247
245 struct dentry *debugfs_root; 248 struct dentry *debugfs_root;
246 249
@@ -283,6 +286,8 @@ void t3_os_ext_intr_handler(struct adapter *adapter);
283void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status, 286void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status,
284 int speed, int duplex, int fc); 287 int speed, int duplex, int fc);
285void t3_os_phymod_changed(struct adapter *adap, int port_id); 288void t3_os_phymod_changed(struct adapter *adap, int port_id);
289void t3_os_link_fault(struct adapter *adapter, int port_id, int state);
290void t3_os_link_fault_handler(struct adapter *adapter, int port_id);
286 291
287void t3_sge_start(struct adapter *adap); 292void t3_sge_start(struct adapter *adap);
288void t3_sge_stop(struct adapter *adap); 293void t3_sge_stop(struct adapter *adap);
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index db4f4f575b6a..9ee021e750c8 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -280,6 +280,7 @@ struct mac_stats {
280 unsigned long num_toggled; /* # times toggled TxEn due to stuck TX */ 280 unsigned long num_toggled; /* # times toggled TxEn due to stuck TX */
281 unsigned long num_resets; /* # times reset due to stuck TX */ 281 unsigned long num_resets; /* # times reset due to stuck TX */
282 282
283 unsigned long link_faults; /* # detected link faults */
283}; 284};
284 285
285struct tp_mib_stats { 286struct tp_mib_stats {
@@ -701,6 +702,8 @@ int t3_phy_lasi_intr_handler(struct cphy *phy);
701void t3_intr_enable(struct adapter *adapter); 702void t3_intr_enable(struct adapter *adapter);
702void t3_intr_disable(struct adapter *adapter); 703void t3_intr_disable(struct adapter *adapter);
703void t3_intr_clear(struct adapter *adapter); 704void t3_intr_clear(struct adapter *adapter);
705void t3_xgm_intr_enable(struct adapter *adapter, int idx);
706void t3_xgm_intr_disable(struct adapter *adapter, int idx);
704void t3_port_intr_enable(struct adapter *adapter, int idx); 707void t3_port_intr_enable(struct adapter *adapter, int idx);
705void t3_port_intr_disable(struct adapter *adapter, int idx); 708void t3_port_intr_disable(struct adapter *adapter, int idx);
706void t3_port_intr_clear(struct adapter *adapter, int idx); 709void t3_port_intr_clear(struct adapter *adapter, int idx);
@@ -708,6 +711,7 @@ int t3_slow_intr_handler(struct adapter *adapter);
708int t3_phy_intr_handler(struct adapter *adapter); 711int t3_phy_intr_handler(struct adapter *adapter);
709 712
710void t3_link_changed(struct adapter *adapter, int port_id); 713void t3_link_changed(struct adapter *adapter, int port_id);
714void t3_link_fault(struct adapter *adapter, int port_id);
711int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); 715int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
712const struct adapter_info *t3_get_adapter_info(unsigned int board_id); 716const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
713int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data); 717int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data);
@@ -744,6 +748,8 @@ int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
744 748
745int t3_mac_reset(struct cmac *mac); 749int t3_mac_reset(struct cmac *mac);
746void t3b_pcs_reset(struct cmac *mac); 750void t3b_pcs_reset(struct cmac *mac);
751void t3_mac_disable_exact_filters(struct cmac *mac);
752void t3_mac_enable_exact_filters(struct cmac *mac);
747int t3_mac_enable(struct cmac *mac, int which); 753int t3_mac_enable(struct cmac *mac, int which);
748int t3_mac_disable(struct cmac *mac, int which); 754int t3_mac_disable(struct cmac *mac, int which);
749int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu); 755int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 9ff0452fcddd..d8be89621bf7 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -170,6 +170,40 @@ static void link_report(struct net_device *dev)
170 } 170 }
171} 171}
172 172
173void t3_os_link_fault(struct adapter *adap, int port_id, int state)
174{
175 struct net_device *dev = adap->port[port_id];
176 struct port_info *pi = netdev_priv(dev);
177
178 if (state == netif_carrier_ok(dev))
179 return;
180
181 if (state) {
182 struct cmac *mac = &pi->mac;
183
184 netif_carrier_on(dev);
185
186 /* Clear local faults */
187 t3_xgm_intr_disable(adap, pi->port_id);
188 t3_read_reg(adap, A_XGM_INT_STATUS +
189 pi->mac.offset);
190 t3_write_reg(adap,
191 A_XGM_INT_CAUSE + pi->mac.offset,
192 F_XGM_INT);
193
194 t3_set_reg_field(adap,
195 A_XGM_INT_ENABLE +
196 pi->mac.offset,
197 F_XGM_INT, F_XGM_INT);
198 t3_xgm_intr_enable(adap, pi->port_id);
199
200 t3_mac_enable(mac, MAC_DIRECTION_TX);
201 } else
202 netif_carrier_off(dev);
203
204 link_report(dev);
205}
206
173/** 207/**
174 * t3_os_link_changed - handle link status changes 208 * t3_os_link_changed - handle link status changes
175 * @adapter: the adapter associated with the link change 209 * @adapter: the adapter associated with the link change
@@ -197,10 +231,34 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
197 if (link_stat != netif_carrier_ok(dev)) { 231 if (link_stat != netif_carrier_ok(dev)) {
198 if (link_stat) { 232 if (link_stat) {
199 t3_mac_enable(mac, MAC_DIRECTION_RX); 233 t3_mac_enable(mac, MAC_DIRECTION_RX);
234
235 /* Clear local faults */
236 t3_xgm_intr_disable(adapter, pi->port_id);
237 t3_read_reg(adapter, A_XGM_INT_STATUS +
238 pi->mac.offset);
239 t3_write_reg(adapter,
240 A_XGM_INT_CAUSE + pi->mac.offset,
241 F_XGM_INT);
242
243 t3_set_reg_field(adapter,
244 A_XGM_INT_ENABLE + pi->mac.offset,
245 F_XGM_INT, F_XGM_INT);
246 t3_xgm_intr_enable(adapter, pi->port_id);
247
200 netif_carrier_on(dev); 248 netif_carrier_on(dev);
201 } else { 249 } else {
202 netif_carrier_off(dev); 250 netif_carrier_off(dev);
203 pi->phy.ops->power_down(&pi->phy, 1); 251
252 t3_xgm_intr_disable(adapter, pi->port_id);
253 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
254 t3_set_reg_field(adapter,
255 A_XGM_INT_ENABLE + pi->mac.offset,
256 F_XGM_INT, 0);
257
258 if (is_10G(adapter))
259 pi->phy.ops->power_down(&pi->phy, 1);
260
261 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
204 t3_mac_disable(mac, MAC_DIRECTION_RX); 262 t3_mac_disable(mac, MAC_DIRECTION_RX);
205 t3_link_start(&pi->phy, mac, &pi->link_config); 263 t3_link_start(&pi->phy, mac, &pi->link_config);
206 } 264 }
@@ -1173,6 +1231,10 @@ static int cxgb_close(struct net_device *dev)
1173 struct port_info *pi = netdev_priv(dev); 1231 struct port_info *pi = netdev_priv(dev);
1174 struct adapter *adapter = pi->adapter; 1232 struct adapter *adapter = pi->adapter;
1175 1233
1234 /* Stop link fault interrupts */
1235 t3_xgm_intr_disable(adapter, pi->port_id);
1236 t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
1237
1176 t3_port_intr_disable(adapter, pi->port_id); 1238 t3_port_intr_disable(adapter, pi->port_id);
1177 netif_tx_stop_all_queues(dev); 1239 netif_tx_stop_all_queues(dev);
1178 pi->phy.ops->power_down(&pi->phy, 1); 1240 pi->phy.ops->power_down(&pi->phy, 1);
@@ -1299,6 +1361,7 @@ static char stats_strings[][ETH_GSTRING_LEN] = {
1299 "CheckTXEnToggled ", 1361 "CheckTXEnToggled ",
1300 "CheckResets ", 1362 "CheckResets ",
1301 1363
1364 "LinkFaults ",
1302}; 1365};
1303 1366
1304static int get_sset_count(struct net_device *dev, int sset) 1367static int get_sset_count(struct net_device *dev, int sset)
@@ -1431,6 +1494,8 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
1431 1494
1432 *data++ = s->num_toggled; 1495 *data++ = s->num_toggled;
1433 *data++ = s->num_resets; 1496 *data++ = s->num_resets;
1497
1498 *data++ = s->link_faults;
1434} 1499}
1435 1500
1436static inline void reg_block_dump(struct adapter *ap, void *buf, 1501static inline void reg_block_dump(struct adapter *ap, void *buf,
@@ -2425,8 +2490,20 @@ static void check_link_status(struct adapter *adapter)
2425 struct net_device *dev = adapter->port[i]; 2490 struct net_device *dev = adapter->port[i];
2426 struct port_info *p = netdev_priv(dev); 2491 struct port_info *p = netdev_priv(dev);
2427 2492
2428 if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) 2493 spin_lock_irq(&adapter->work_lock);
2494 if (p->link_fault) {
2495 spin_unlock_irq(&adapter->work_lock);
2496 continue;
2497 }
2498 spin_unlock_irq(&adapter->work_lock);
2499
2500 if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) {
2501 t3_xgm_intr_disable(adapter, i);
2502 t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
2503
2429 t3_link_changed(adapter, i); 2504 t3_link_changed(adapter, i);
2505 t3_xgm_intr_enable(adapter, i);
2506 }
2430 } 2507 }
2431} 2508}
2432 2509
@@ -2553,9 +2630,23 @@ static void ext_intr_task(struct work_struct *work)
2553{ 2630{
2554 struct adapter *adapter = container_of(work, struct adapter, 2631 struct adapter *adapter = container_of(work, struct adapter,
2555 ext_intr_handler_task); 2632 ext_intr_handler_task);
2633 int i;
2634
2635 /* Disable link fault interrupts */
2636 for_each_port(adapter, i) {
2637 struct net_device *dev = adapter->port[i];
2638 struct port_info *p = netdev_priv(dev);
2639
2640 t3_xgm_intr_disable(adapter, i);
2641 t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
2642 }
2556 2643
2644 /* Re-enable link fault interrupts */
2557 t3_phy_intr_handler(adapter); 2645 t3_phy_intr_handler(adapter);
2558 2646
2647 for_each_port(adapter, i)
2648 t3_xgm_intr_enable(adapter, i);
2649
2559 /* Now reenable external interrupts */ 2650 /* Now reenable external interrupts */
2560 spin_lock_irq(&adapter->work_lock); 2651 spin_lock_irq(&adapter->work_lock);
2561 if (adapter->slow_intr_mask) { 2652 if (adapter->slow_intr_mask) {
@@ -2588,6 +2679,32 @@ void t3_os_ext_intr_handler(struct adapter *adapter)
2588 spin_unlock(&adapter->work_lock); 2679 spin_unlock(&adapter->work_lock);
2589} 2680}
2590 2681
2682static void link_fault_task(struct work_struct *work)
2683{
2684 struct adapter *adapter = container_of(work, struct adapter,
2685 link_fault_handler_task);
2686 int i;
2687
2688 for_each_port(adapter, i) {
2689 struct net_device *netdev = adapter->port[i];
2690 struct port_info *pi = netdev_priv(netdev);
2691
2692 if (pi->link_fault)
2693 t3_link_fault(adapter, i);
2694 }
2695}
2696
2697void t3_os_link_fault_handler(struct adapter *adapter, int port_id)
2698{
2699 struct net_device *netdev = adapter->port[port_id];
2700 struct port_info *pi = netdev_priv(netdev);
2701
2702 spin_lock(&adapter->work_lock);
2703 pi->link_fault = 1;
2704 queue_work(cxgb3_wq, &adapter->link_fault_handler_task);
2705 spin_unlock(&adapter->work_lock);
2706}
2707
2591static int t3_adapter_error(struct adapter *adapter, int reset) 2708static int t3_adapter_error(struct adapter *adapter, int reset)
2592{ 2709{
2593 int i, ret = 0; 2710 int i, ret = 0;
@@ -2704,7 +2821,6 @@ void t3_fatal_err(struct adapter *adapter)
2704 CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n", 2821 CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
2705 fw_status[0], fw_status[1], 2822 fw_status[0], fw_status[1],
2706 fw_status[2], fw_status[3]); 2823 fw_status[2], fw_status[3]);
2707
2708} 2824}
2709 2825
2710/** 2826/**
@@ -2962,6 +3078,7 @@ static int __devinit init_one(struct pci_dev *pdev,
2962 3078
2963 INIT_LIST_HEAD(&adapter->adapter_list); 3079 INIT_LIST_HEAD(&adapter->adapter_list);
2964 INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); 3080 INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
3081 INIT_WORK(&adapter->link_fault_handler_task, link_fault_task);
2965 INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task); 3082 INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
2966 INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); 3083 INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
2967 3084
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index aa08550ee998..1b5327b5a965 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -2215,6 +2215,15 @@
2215 2215
2216#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854 2216#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854
2217 2217
2218#define A_XGM_INT_STATUS 0x86c
2219
2220#define S_LINKFAULTCHANGE 9
2221#define V_LINKFAULTCHANGE(x) ((x) << S_LINKFAULTCHANGE)
2222#define F_LINKFAULTCHANGE V_LINKFAULTCHANGE(1U)
2223
2224#define A_XGM_XGM_INT_ENABLE 0x874
2225#define A_XGM_XGM_INT_DISABLE 0x878
2226
2218#define A_XGM_STAT_CTRL 0x880 2227#define A_XGM_STAT_CTRL 0x880
2219 2228
2220#define S_CLRSTATS 2 2229#define S_CLRSTATS 2
@@ -2413,6 +2422,10 @@
2413#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE) 2422#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE)
2414#define F_XAUIPCSALIGNCHANGE V_XAUIPCSALIGNCHANGE(1U) 2423#define F_XAUIPCSALIGNCHANGE V_XAUIPCSALIGNCHANGE(1U)
2415 2424
2425#define S_XGM_INT 0
2426#define V_XGM_INT(x) ((x) << S_XGM_INT)
2427#define F_XGM_INT V_XGM_INT(1U)
2428
2416#define A_XGM_INT_CAUSE 0x8d8 2429#define A_XGM_INT_CAUSE 0x8d8
2417 2430
2418#define A_XGM_XAUI_ACT_CTRL 0x8dc 2431#define A_XGM_XAUI_ACT_CTRL 0x8dc
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 7c6ee0c9b6fc..ff262a04ded0 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -1153,6 +1153,38 @@ int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
1153 return ret; 1153 return ret;
1154} 1154}
1155 1155
1156static void t3_gate_rx_traffic(struct cmac *mac, u32 *rx_cfg,
1157 u32 *rx_hash_high, u32 *rx_hash_low)
1158{
1159 /* stop Rx unicast traffic */
1160 t3_mac_disable_exact_filters(mac);
1161
1162 /* stop broadcast, multicast, promiscuous mode traffic */
1163 *rx_cfg = t3_read_reg(mac->adapter, A_XGM_RX_CFG);
1164 t3_set_reg_field(mac->adapter, A_XGM_RX_CFG,
1165 F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES,
1166 F_DISBCAST);
1167
1168 *rx_hash_high = t3_read_reg(mac->adapter, A_XGM_RX_HASH_HIGH);
1169 t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, 0);
1170
1171 *rx_hash_low = t3_read_reg(mac->adapter, A_XGM_RX_HASH_LOW);
1172 t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, 0);
1173
1174 /* Leave time to drain max RX fifo */
1175 msleep(1);
1176}
1177
1178static void t3_open_rx_traffic(struct cmac *mac, u32 rx_cfg,
1179 u32 rx_hash_high, u32 rx_hash_low)
1180{
1181 t3_mac_enable_exact_filters(mac);
1182 t3_set_reg_field(mac->adapter, A_XGM_RX_CFG,
1183 F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES,
1184 rx_cfg);
1185 t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, rx_hash_high);
1186 t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, rx_hash_low);
1187}
1156 1188
1157/** 1189/**
1158 * t3_link_changed - handle interface link changes 1190 * t3_link_changed - handle interface link changes
@@ -1170,9 +1202,32 @@ void t3_link_changed(struct adapter *adapter, int port_id)
1170 struct cphy *phy = &pi->phy; 1202 struct cphy *phy = &pi->phy;
1171 struct cmac *mac = &pi->mac; 1203 struct cmac *mac = &pi->mac;
1172 struct link_config *lc = &pi->link_config; 1204 struct link_config *lc = &pi->link_config;
1205 int force_link_down = 0;
1173 1206
1174 phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); 1207 phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
1175 1208
1209 if (!lc->link_ok && link_ok) {
1210 u32 rx_cfg, rx_hash_high, rx_hash_low;
1211 u32 status;
1212
1213 t3_xgm_intr_enable(adapter, port_id);
1214 t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low);
1215 t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
1216 t3_mac_enable(mac, MAC_DIRECTION_RX);
1217
1218 status = t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset);
1219 if (status & F_LINKFAULTCHANGE) {
1220 mac->stats.link_faults++;
1221 force_link_down = 1;
1222 }
1223 t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low);
1224
1225 if (force_link_down) {
1226 t3_os_link_fault_handler(adapter, port_id);
1227 return;
1228 }
1229 }
1230
1176 if (lc->requested_fc & PAUSE_AUTONEG) 1231 if (lc->requested_fc & PAUSE_AUTONEG)
1177 fc &= lc->requested_fc; 1232 fc &= lc->requested_fc;
1178 else 1233 else
@@ -1202,6 +1257,57 @@ void t3_link_changed(struct adapter *adapter, int port_id)
1202 t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc); 1257 t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
1203} 1258}
1204 1259
1260void t3_link_fault(struct adapter *adapter, int port_id)
1261{
1262 struct port_info *pi = adap2pinfo(adapter, port_id);
1263 struct cmac *mac = &pi->mac;
1264 struct cphy *phy = &pi->phy;
1265 struct link_config *lc = &pi->link_config;
1266 int link_ok, speed, duplex, fc, link_fault;
1267 u32 rx_cfg, rx_hash_high, rx_hash_low;
1268
1269 t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low);
1270
1271 if (adapter->params.rev > 0 && uses_xaui(adapter))
1272 t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, 0);
1273
1274 t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
1275 t3_mac_enable(mac, MAC_DIRECTION_RX);
1276
1277 t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low);
1278
1279 link_fault = t3_read_reg(adapter,
1280 A_XGM_INT_STATUS + mac->offset);
1281 link_fault &= F_LINKFAULTCHANGE;
1282
1283 phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
1284
1285 if (link_fault) {
1286 lc->link_ok = 0;
1287 lc->speed = SPEED_INVALID;
1288 lc->duplex = DUPLEX_INVALID;
1289
1290 t3_os_link_fault(adapter, port_id, 0);
1291
1292 /* Account link faults only when the phy reports a link up */
1293 if (link_ok)
1294 mac->stats.link_faults++;
1295
1296 msleep(1000);
1297 t3_os_link_fault_handler(adapter, port_id);
1298 } else {
1299 if (link_ok)
1300 t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
1301 F_TXACTENABLE | F_RXEN);
1302
1303 pi->link_fault = 0;
1304 lc->link_ok = (unsigned char)link_ok;
1305 lc->speed = speed < 0 ? SPEED_INVALID : speed;
1306 lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
1307 t3_os_link_fault(adapter, port_id, link_ok);
1308 }
1309}
1310
1205/** 1311/**
1206 * t3_link_start - apply link configuration to MAC/PHY 1312 * t3_link_start - apply link configuration to MAC/PHY
1207 * @phy: the PHY to setup 1313 * @phy: the PHY to setup
@@ -1360,11 +1466,11 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
1360 V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \ 1466 V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
1361 V_RXTPPARERRENB(M_RXTPPARERRENB) | \ 1467 V_RXTPPARERRENB(M_RXTPPARERRENB) | \
1362 V_MCAPARERRENB(M_MCAPARERRENB)) 1468 V_MCAPARERRENB(M_MCAPARERRENB))
1469#define XGM_EXTRA_INTR_MASK (F_LINKFAULTCHANGE)
1363#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \ 1470#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
1364 F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \ 1471 F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
1365 F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \ 1472 F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
1366 F_MPS0 | F_CPL_SWITCH) 1473 F_MPS0 | F_CPL_SWITCH)
1367
1368/* 1474/*
1369 * Interrupt handler for the PCIX1 module. 1475 * Interrupt handler for the PCIX1 module.
1370 */ 1476 */
@@ -1722,10 +1828,20 @@ static int mac_intr_handler(struct adapter *adap, unsigned int idx)
1722 mac->stats.xaui_pcs_ctc_err++; 1828 mac->stats.xaui_pcs_ctc_err++;
1723 if (cause & F_XAUIPCSALIGNCHANGE) 1829 if (cause & F_XAUIPCSALIGNCHANGE)
1724 mac->stats.xaui_pcs_align_change++; 1830 mac->stats.xaui_pcs_align_change++;
1831 if (cause & F_XGM_INT) {
1832 t3_set_reg_field(adap,
1833 A_XGM_INT_ENABLE + mac->offset,
1834 F_XGM_INT, 0);
1835 mac->stats.link_faults++;
1836
1837 t3_os_link_fault_handler(adap, idx);
1838 }
1725 1839
1726 t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause); 1840 t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
1841
1727 if (cause & XGM_INTR_FATAL) 1842 if (cause & XGM_INTR_FATAL)
1728 t3_fatal_err(adap); 1843 t3_fatal_err(adap);
1844
1729 return cause != 0; 1845 return cause != 0;
1730} 1846}
1731 1847
@@ -1931,6 +2047,22 @@ void t3_intr_clear(struct adapter *adapter)
1931 t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ 2047 t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
1932} 2048}
1933 2049
2050void t3_xgm_intr_enable(struct adapter *adapter, int idx)
2051{
2052 struct port_info *pi = adap2pinfo(adapter, idx);
2053
2054 t3_write_reg(adapter, A_XGM_XGM_INT_ENABLE + pi->mac.offset,
2055 XGM_EXTRA_INTR_MASK);
2056}
2057
2058void t3_xgm_intr_disable(struct adapter *adapter, int idx)
2059{
2060 struct port_info *pi = adap2pinfo(adapter, idx);
2061
2062 t3_write_reg(adapter, A_XGM_XGM_INT_DISABLE + pi->mac.offset,
2063 0x7ff);
2064}
2065
1934/** 2066/**
1935 * t3_port_intr_enable - enable port-specific interrupts 2067 * t3_port_intr_enable - enable port-specific interrupts
1936 * @adapter: associated adapter 2068 * @adapter: associated adapter
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index 4bd0901a97a6..f87f9435049f 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -218,6 +218,9 @@ static int t3b2_mac_reset(struct cmac *mac)
218 /* re-enable nic traffic */ 218 /* re-enable nic traffic */
219 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1); 219 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1);
220 220
221 /* Set: re-enable NIC traffic */
222 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1);
223
221 return 0; 224 return 0;
222} 225}
223 226
@@ -258,7 +261,7 @@ int t3_mac_set_num_ucast(struct cmac *mac, int n)
258 return 0; 261 return 0;
259} 262}
260 263
261static void disable_exact_filters(struct cmac *mac) 264void t3_mac_disable_exact_filters(struct cmac *mac)
262{ 265{
263 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1; 266 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
264 267
@@ -269,7 +272,7 @@ static void disable_exact_filters(struct cmac *mac)
269 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */ 272 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
270} 273}
271 274
272static void enable_exact_filters(struct cmac *mac) 275void t3_mac_enable_exact_filters(struct cmac *mac)
273{ 276{
274 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1; 277 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
275 278
@@ -356,7 +359,7 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
356 359
357 if (adap->params.rev >= T3_REV_B2 && 360 if (adap->params.rev >= T3_REV_B2 &&
358 (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { 361 (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
359 disable_exact_filters(mac); 362 t3_mac_disable_exact_filters(mac);
360 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset); 363 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
361 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset, 364 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
362 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST); 365 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
@@ -368,14 +371,14 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
368 if (t3_wait_op_done(adap, reg + mac->offset, 371 if (t3_wait_op_done(adap, reg + mac->offset,
369 F_RXFIFO_EMPTY, 1, 20, 5)) { 372 F_RXFIFO_EMPTY, 1, 20, 5)) {
370 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); 373 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
371 enable_exact_filters(mac); 374 t3_mac_enable_exact_filters(mac);
372 return -EIO; 375 return -EIO;
373 } 376 }
374 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, 377 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
375 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), 378 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
376 V_RXMAXPKTSIZE(mtu)); 379 V_RXMAXPKTSIZE(mtu));
377 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); 380 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
378 enable_exact_filters(mac); 381 t3_mac_enable_exact_filters(mac);
379 } else 382 } else
380 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, 383 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
381 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), 384 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),