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>

authored by Divy Le Ray and committed by Jeff Garzik 7b581a0f c706bfb5

+70 -1
+4
drivers/net/cxgb3/regs.h
··· 1882 1882 #define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES) 1883 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 1889 #define A_XGM_RX_HASH_LOW 0x814 1886 1890 1887 1891 #define A_XGM_RX_HASH_HIGH 0x818
+66 -1
drivers/net/cxgb3/xgmac.c
··· 231 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 256 /* Calculate the RX hash filter index of an Ethernet address */ 235 257 static int hash_hw_addr(const u8 * addr) 236 258 { ··· 303 281 return 0; 304 282 } 305 283 284 + static int rx_fifo_hwm(int mtu) 285 + { 286 + int hwm; 287 + 288 + hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100); 289 + return min(hwm, MAC_RXFIFO_SIZE - 8192); 290 + } 291 + 306 292 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) 307 293 { 308 294 int hwm, lwm; ··· 336 306 lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4); 337 307 338 308 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); 309 + if (adap->params.rev == T3_REV_B2 && 310 + (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { 311 + disable_exact_filters(mac); 312 + t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + mac->offset, 313 + F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST); 314 + 315 + /* drain rx FIFO */ 316 + if (t3_wait_op_done(adap, 317 + A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + 318 + mac->offset, 319 + 1 << 31, 1, 20, 5)) { 320 + t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v); 321 + enable_exact_filters(mac); 322 + return -EIO; 323 + } 324 + t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); 325 + enable_exact_filters(mac); 326 + } else 327 + t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); 328 + 329 + /* 330 + * Adjust the PAUSE frame watermarks. We always set the LWM, and the 331 + * HWM only if flow-control is enabled. 332 + */ 333 + hwm = rx_fifo_hwm(mtu); 334 + lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4); 339 335 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); 340 336 v |= V_RXFIFOPAUSELWM(lwm / 8); 341 337 if (G_RXFIFOPAUSEHWM(v)) 342 338 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) | 343 339 V_RXFIFOPAUSEHWM(hwm / 8); 340 + 344 341 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v); 345 342 346 343 /* Adjust the TX FIFO threshold based on the MTU */ ··· 386 329 (hwm - lwm) * 4 / 8); 387 330 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, 388 331 MAC_RXFIFO_SIZE * 4 * 8 / 512); 389 - 390 332 return 0; 391 333 } 392 334 ··· 412 356 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, 413 357 V_PORTSPEED(M_PORTSPEED), val); 414 358 } 359 + 360 + val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); 361 + val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); 362 + if (fc & PAUSE_TX) 363 + val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm( 364 + t3_read_reg(adap, 365 + A_XGM_RX_MAX_PKT_SIZE 366 + + oft)) / 8); 367 + t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); 415 368 416 369 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 417 370 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);