diff options
Diffstat (limited to 'drivers/net/cxgb3/t3_hw.c')
-rw-r--r-- | drivers/net/cxgb3/t3_hw.c | 134 |
1 files changed, 133 insertions, 1 deletions
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 |