aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/cxgb3/t3_hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/cxgb3/t3_hw.c')
-rw-r--r--drivers/net/cxgb3/t3_hw.c134
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
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