aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/cxgb3/xgmac.c
diff options
context:
space:
mode:
authorDivy Le Ray <divy@chelsio.com>2007-05-30 13:01:44 -0400
committerJeff Garzik <jeff@garzik.org>2007-06-20 19:16:59 -0400
commit7b581a0fa85464f7f765b9a66f612e7ec4ab17f9 (patch)
tree17aa5f829935d35d64edcf63dfdde135e517c0ae /drivers/net/cxgb3/xgmac.c
parentc706bfb52afc9b5d115f61a8e1c0c30540feb3f4 (diff)
cxgb3 - Stop mac RX when changing MTU
Rx traffic needs to be halted when the MTU is changed to avoid a potential chip hang. Reset/restore MAC filters around a MTU change. Also fix the pause frames high materwark setting. 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.c67
1 files changed, 66 insertions, 1 deletions
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index a506792f9575..16cadba88ed5 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -231,6 +231,28 @@ int t3_mac_set_num_ucast(struct cmac *mac, int n)
231 return 0; 231 return 0;
232} 232}
233 233
234static void disable_exact_filters(struct cmac *mac)
235{
236 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
237
238 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
239 u32 v = t3_read_reg(mac->adapter, reg);
240 t3_write_reg(mac->adapter, reg, v);
241 }
242 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
243}
244
245static void enable_exact_filters(struct cmac *mac)
246{
247 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
248
249 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
250 u32 v = t3_read_reg(mac->adapter, reg);
251 t3_write_reg(mac->adapter, reg, v);
252 }
253 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
254}
255
234/* Calculate the RX hash filter index of an Ethernet address */ 256/* Calculate the RX hash filter index of an Ethernet address */
235static int hash_hw_addr(const u8 * addr) 257static int hash_hw_addr(const u8 * addr)
236{ 258{
@@ -281,6 +303,14 @@ int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
281 return 0; 303 return 0;
282} 304}
283 305
306static int rx_fifo_hwm(int mtu)
307{
308 int hwm;
309
310 hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
311 return min(hwm, MAC_RXFIFO_SIZE - 8192);
312}
313
284int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) 314int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
285{ 315{
286 int hwm, lwm; 316 int hwm, lwm;
@@ -306,11 +336,38 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
306 lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4); 336 lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4);
307 337
308 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); 338 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
339 if (adap->params.rev == T3_REV_B2 &&
340 (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
341 disable_exact_filters(mac);
342 t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + mac->offset,
343 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
344
345 /* drain rx FIFO */
346 if (t3_wait_op_done(adap,
347 A_XGM_RX_MAX_PKT_SIZE_ERR_CNT +
348 mac->offset,
349 1 << 31, 1, 20, 5)) {
350 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
351 enable_exact_filters(mac);
352 return -EIO;
353 }
354 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
355 enable_exact_filters(mac);
356 } else
357 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
358
359 /*
360 * Adjust the PAUSE frame watermarks. We always set the LWM, and the
361 * HWM only if flow-control is enabled.
362 */
363 hwm = rx_fifo_hwm(mtu);
364 lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4);
309 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); 365 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
310 v |= V_RXFIFOPAUSELWM(lwm / 8); 366 v |= V_RXFIFOPAUSELWM(lwm / 8);
311 if (G_RXFIFOPAUSEHWM(v)) 367 if (G_RXFIFOPAUSEHWM(v))
312 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) | 368 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
313 V_RXFIFOPAUSEHWM(hwm / 8); 369 V_RXFIFOPAUSEHWM(hwm / 8);
370
314 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v); 371 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
315 372
316 /* Adjust the TX FIFO threshold based on the MTU */ 373 /* Adjust the TX FIFO threshold based on the MTU */
@@ -329,7 +386,6 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
329 (hwm - lwm) * 4 / 8); 386 (hwm - lwm) * 4 / 8);
330 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, 387 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
331 MAC_RXFIFO_SIZE * 4 * 8 / 512); 388 MAC_RXFIFO_SIZE * 4 * 8 / 512);
332
333 return 0; 389 return 0;
334} 390}
335 391
@@ -357,6 +413,15 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
357 V_PORTSPEED(M_PORTSPEED), val); 413 V_PORTSPEED(M_PORTSPEED), val);
358 } 414 }
359 415
416 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
417 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
418 if (fc & PAUSE_TX)
419 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(
420 t3_read_reg(adap,
421 A_XGM_RX_MAX_PKT_SIZE
422 + oft)) / 8);
423 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
424
360 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 425 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
361 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); 426 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
362 return 0; 427 return 0;