aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/cxgb3/xgmac.c
diff options
context:
space:
mode:
authorDivy Le Ray <divy@chelsio.com>2007-03-18 16:10:12 -0400
committerJeff Garzik <jeff@garzik.org>2007-03-23 01:48:34 -0400
commitfc90664e3438c990d280f179ccb0642711d5c553 (patch)
tree8ece58a4eec002186f1c569385830f03336b50af /drivers/net/cxgb3/xgmac.c
parent2e2839627a957714808f98a802d137a7a2a1df46 (diff)
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/xgmac.c')
-rw-r--r--drivers/net/cxgb3/xgmac.c133
1 files changed, 118 insertions, 15 deletions
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index 907a272ae32..2b42c13ba8e 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -124,9 +124,6 @@ int t3_mac_reset(struct cmac *mac)
124 xaui_serdes_reset(mac); 124 xaui_serdes_reset(mac);
125 } 125 }
126 126
127 if (adap->params.rev > 0)
128 t3_write_reg(adap, A_XGM_PAUSE_TIMER + oft, 0xf000);
129
130 val = F_MAC_RESET_; 127 val = F_MAC_RESET_;
131 if (is_10G(adap)) 128 if (is_10G(adap))
132 val |= F_PCS_RESET_; 129 val |= F_PCS_RESET_;
@@ -145,6 +142,58 @@ int t3_mac_reset(struct cmac *mac)
145 return 0; 142 return 0;
146} 143}
147 144
145int t3b2_mac_reset(struct cmac *mac)
146{
147 struct adapter *adap = mac->adapter;
148 unsigned int oft = mac->offset;
149 u32 val;
150
151 if (!macidx(mac))
152 t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
153 else
154 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
155
156 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
157 t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
158
159 msleep(10);
160
161 /* Check for xgm Rx fifo empty */
162 if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
163 0x80000000, 1, 5, 2)) {
164 CH_ERR(adap, "MAC %d Rx fifo drain failed\n",
165 macidx(mac));
166 return -1;
167 }
168
169 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0);
170 t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
171
172 val = F_MAC_RESET_;
173 if (is_10G(adap))
174 val |= F_PCS_RESET_;
175 else if (uses_xaui(adap))
176 val |= F_PCS_RESET_ | F_XG2G_RESET_;
177 else
178 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
179 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
180 t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
181 if ((val & F_PCS_RESET_) && adap->params.rev) {
182 msleep(1);
183 t3b_pcs_reset(mac);
184 }
185 t3_write_reg(adap, A_XGM_RX_CFG + oft,
186 F_DISPAUSEFRAMES | F_EN1536BFRAMES |
187 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST);
188
189 if (!macidx(mac))
190 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
191 else
192 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
193
194 return 0;
195}
196
148/* 197/*
149 * Set the exact match register 'idx' to recognize the given Ethernet address. 198 * Set the exact match register 'idx' to recognize the given Ethernet address.
150 */ 199 */
@@ -251,9 +300,11 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
251 * Adjust the PAUSE frame watermarks. We always set the LWM, and the 300 * Adjust the PAUSE frame watermarks. We always set the LWM, and the
252 * HWM only if flow-control is enabled. 301 * HWM only if flow-control is enabled.
253 */ 302 */
254 hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, MAC_RXFIFO_SIZE / 2U); 303 hwm = max_t(unsigned int, MAC_RXFIFO_SIZE - 3 * mtu,
255 hwm = min(hwm, 3 * MAC_RXFIFO_SIZE / 4 + 1024); 304 MAC_RXFIFO_SIZE * 38 / 100);
256 lwm = hwm - 1024; 305 hwm = min(hwm, MAC_RXFIFO_SIZE - 8192);
306 lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4);
307
257 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); 308 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
258 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); 309 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
259 v |= V_RXFIFOPAUSELWM(lwm / 8); 310 v |= V_RXFIFOPAUSELWM(lwm / 8);
@@ -270,7 +321,15 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
270 thres = mtu > thres ? (mtu - thres + 7) / 8 : 0; 321 thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
271 thres = max(thres, 8U); /* need at least 8 */ 322 thres = max(thres, 8U); /* need at least 8 */
272 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, 323 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
273 V_TXFIFOTHRESH(M_TXFIFOTHRESH), V_TXFIFOTHRESH(thres)); 324 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
325 V_TXFIFOTHRESH(thres) | V_TXIPG(1));
326
327 if (adap->params.rev > 0)
328 t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
329 (hwm - lwm) * 4 / 8);
330 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
331 MAC_RXFIFO_SIZE * 4 * 8 / 512);
332
274 return 0; 333 return 0;
275} 334}
276 335
@@ -298,12 +357,6 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
298 V_PORTSPEED(M_PORTSPEED), val); 357 V_PORTSPEED(M_PORTSPEED), val);
299 } 358 }
300 359
301 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
302 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
303 if (fc & PAUSE_TX)
304 val |= V_RXFIFOPAUSEHWM(G_RXFIFOPAUSELWM(val) + 128); /* +1KB */
305 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
306
307 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 360 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
308 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); 361 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
309 return 0; 362 return 0;
@@ -318,9 +371,17 @@ int t3_mac_enable(struct cmac *mac, int which)
318 if (which & MAC_DIRECTION_TX) { 371 if (which & MAC_DIRECTION_TX) {
319 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); 372 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
320 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 373 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
321 t3_write_reg(adap, A_TP_PIO_DATA, 0xbf000001); 374 t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401);
322 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); 375 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
323 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx); 376 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
377
378 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
379 mac->tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
380 A_TP_PIO_DATA)));
381 mac->xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
382 A_XGM_TX_SPI4_SOP_EOP_CNT)));
383 mac->txen = F_TXEN;
384 mac->toggle_cnt = 0;
324 } 385 }
325 if (which & MAC_DIRECTION_RX) 386 if (which & MAC_DIRECTION_RX)
326 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); 387 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
@@ -337,13 +398,50 @@ int t3_mac_disable(struct cmac *mac, int which)
337 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 398 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
338 t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f); 399 t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f);
339 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); 400 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
340 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 0); 401 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
402 mac->txen = 0;
341 } 403 }
342 if (which & MAC_DIRECTION_RX) 404 if (which & MAC_DIRECTION_RX)
343 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); 405 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
344 return 0; 406 return 0;
345} 407}
346 408
409int t3b2_mac_watchdog_task(struct cmac *mac)
410{
411 struct adapter *adap = mac->adapter;
412 unsigned int tcnt, xcnt;
413 int status;
414
415 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + macidx(mac));
416 tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, A_TP_PIO_DATA)));
417 xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
418 A_XGM_TX_SPI4_SOP_EOP_CNT +
419 mac->offset)));
420
421 if (tcnt != mac->tcnt && xcnt == 0 && mac->xcnt == 0) {
422 if (mac->toggle_cnt > 4) {
423 t3b2_mac_reset(mac);
424 mac->toggle_cnt = 0;
425 status = 2;
426 } else {
427 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
428 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);
429 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset,
430 mac->txen);
431 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);
432 mac->toggle_cnt++;
433 status = 1;
434 }
435 } else {
436 mac->toggle_cnt = 0;
437 status = 0;
438 }
439 mac->tcnt = tcnt;
440 mac->xcnt = xcnt;
441
442 return status;
443}
444
347/* 445/*
348 * This function is called periodically to accumulate the current values of the 446 * This function is called periodically to accumulate the current values of the
349 * RMON counters into the port statistics. Since the packet counters are only 447 * RMON counters into the port statistics. Since the packet counters are only
@@ -375,6 +473,11 @@ const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
375 RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES); 473 RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
376 mac->stats.rx_too_long += RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); 474 mac->stats.rx_too_long += RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
377 475
476 v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
477 if (mac->adapter->params.rev == T3_REV_B2)
478 v &= 0x7fffffff;
479 mac->stats.rx_too_long += v;
480
378 RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES); 481 RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
379 RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES); 482 RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
380 RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES); 483 RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);