diff options
author | Divy Le Ray <divy@chelsio.com> | 2007-05-30 13:01:44 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-06-20 19:16:59 -0400 |
commit | 7b581a0fa85464f7f765b9a66f612e7ec4ab17f9 (patch) | |
tree | 17aa5f829935d35d64edcf63dfdde135e517c0ae /drivers/net/cxgb3 | |
parent | c706bfb52afc9b5d115f61a8e1c0c30540feb3f4 (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')
-rw-r--r-- | drivers/net/cxgb3/regs.h | 4 | ||||
-rw-r--r-- | drivers/net/cxgb3/xgmac.c | 67 |
2 files changed, 70 insertions, 1 deletions
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h index bf9d6be7f214..020859c855d7 100644 --- a/drivers/net/cxgb3/regs.h +++ b/drivers/net/cxgb3/regs.h | |||
@@ -1882,6 +1882,10 @@ | |||
1882 | #define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES) | 1882 | #define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES) |
1883 | #define F_COPYALLFRAMES V_COPYALLFRAMES(1U) | 1883 | #define F_COPYALLFRAMES V_COPYALLFRAMES(1U) |
1884 | 1884 | ||
1885 | #define S_DISBCAST 1 | ||
1886 | #define V_DISBCAST(x) ((x) << S_DISBCAST) | ||
1887 | #define F_DISBCAST V_DISBCAST(1U) | ||
1888 | |||
1885 | #define A_XGM_RX_HASH_LOW 0x814 | 1889 | #define A_XGM_RX_HASH_LOW 0x814 |
1886 | 1890 | ||
1887 | #define A_XGM_RX_HASH_HIGH 0x818 | 1891 | #define A_XGM_RX_HASH_HIGH 0x818 |
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 | ||
234 | static 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 | |||
245 | static 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 */ |
235 | static int hash_hw_addr(const u8 * addr) | 257 | static 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 | ||
306 | static 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 | |||
284 | int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) | 314 | int 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; |