diff options
-rw-r--r-- | drivers/net/cxgb3/adapter.h | 5 | ||||
-rw-r--r-- | drivers/net/cxgb3/common.h | 6 | ||||
-rw-r--r-- | drivers/net/cxgb3/cxgb3_main.c | 123 | ||||
-rw-r--r-- | drivers/net/cxgb3/regs.h | 13 | ||||
-rw-r--r-- | drivers/net/cxgb3/t3_hw.c | 134 | ||||
-rw-r--r-- | drivers/net/cxgb3/xgmac.c | 13 |
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 | ||
73 | enum { /* adapter flags */ | 75 | enum { /* 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); | |||
283 | void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status, | 286 | void 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); |
285 | void t3_os_phymod_changed(struct adapter *adap, int port_id); | 288 | void t3_os_phymod_changed(struct adapter *adap, int port_id); |
289 | void t3_os_link_fault(struct adapter *adapter, int port_id, int state); | ||
290 | void t3_os_link_fault_handler(struct adapter *adapter, int port_id); | ||
286 | 291 | ||
287 | void t3_sge_start(struct adapter *adap); | 292 | void t3_sge_start(struct adapter *adap); |
288 | void t3_sge_stop(struct adapter *adap); | 293 | void 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 | ||
285 | struct tp_mib_stats { | 286 | struct tp_mib_stats { |
@@ -701,6 +702,8 @@ int t3_phy_lasi_intr_handler(struct cphy *phy); | |||
701 | void t3_intr_enable(struct adapter *adapter); | 702 | void t3_intr_enable(struct adapter *adapter); |
702 | void t3_intr_disable(struct adapter *adapter); | 703 | void t3_intr_disable(struct adapter *adapter); |
703 | void t3_intr_clear(struct adapter *adapter); | 704 | void t3_intr_clear(struct adapter *adapter); |
705 | void t3_xgm_intr_enable(struct adapter *adapter, int idx); | ||
706 | void t3_xgm_intr_disable(struct adapter *adapter, int idx); | ||
704 | void t3_port_intr_enable(struct adapter *adapter, int idx); | 707 | void t3_port_intr_enable(struct adapter *adapter, int idx); |
705 | void t3_port_intr_disable(struct adapter *adapter, int idx); | 708 | void t3_port_intr_disable(struct adapter *adapter, int idx); |
706 | void t3_port_intr_clear(struct adapter *adapter, int idx); | 709 | void t3_port_intr_clear(struct adapter *adapter, int idx); |
@@ -708,6 +711,7 @@ int t3_slow_intr_handler(struct adapter *adapter); | |||
708 | int t3_phy_intr_handler(struct adapter *adapter); | 711 | int t3_phy_intr_handler(struct adapter *adapter); |
709 | 712 | ||
710 | void t3_link_changed(struct adapter *adapter, int port_id); | 713 | void t3_link_changed(struct adapter *adapter, int port_id); |
714 | void t3_link_fault(struct adapter *adapter, int port_id); | ||
711 | int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); | 715 | int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); |
712 | const struct adapter_info *t3_get_adapter_info(unsigned int board_id); | 716 | const struct adapter_info *t3_get_adapter_info(unsigned int board_id); |
713 | int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data); | 717 | int 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 | ||
745 | int t3_mac_reset(struct cmac *mac); | 749 | int t3_mac_reset(struct cmac *mac); |
746 | void t3b_pcs_reset(struct cmac *mac); | 750 | void t3b_pcs_reset(struct cmac *mac); |
751 | void t3_mac_disable_exact_filters(struct cmac *mac); | ||
752 | void t3_mac_enable_exact_filters(struct cmac *mac); | ||
747 | int t3_mac_enable(struct cmac *mac, int which); | 753 | int t3_mac_enable(struct cmac *mac, int which); |
748 | int t3_mac_disable(struct cmac *mac, int which); | 754 | int t3_mac_disable(struct cmac *mac, int which); |
749 | int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu); | 755 | int 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 | ||
173 | void 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 | ||
1304 | static int get_sset_count(struct net_device *dev, int sset) | 1367 | static 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 | ||
1436 | static inline void reg_block_dump(struct adapter *ap, void *buf, | 1501 | static 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 | ||
2682 | static 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 | |||
2697 | void 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 | |||
2591 | static int t3_adapter_error(struct adapter *adapter, int reset) | 2708 | static 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 | ||
1156 | static 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 | |||
1178 | static 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 | ||
1260 | void 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 | ||
2050 | void 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 | |||
2058 | void 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 | ||
261 | static void disable_exact_filters(struct cmac *mac) | 264 | void 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 | ||
272 | static void enable_exact_filters(struct cmac *mac) | 275 | void 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), |