cxgb_xgmac.c revision 197791
1/************************************************************************** 2 3Copyright (c) 2007-2009 Chelsio Inc. 4All rights reserved. 5 6Redistribution and use in source and binary forms, with or without 7modification, are permitted provided that the following conditions are met: 8 9 1. Redistributions of source code must retain the above copyright notice, 10 this list of conditions and the following disclaimer. 11 12 2. Neither the name of the Chelsio Corporation nor the names of its 13 contributors may be used to endorse or promote products derived from 14 this software without specific prior written permission. 15 16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26POSSIBILITY OF SUCH DAMAGE. 27 28***************************************************************************/ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/sys/dev/cxgb/common/cxgb_xgmac.c 197791 2009-10-05 20:21:41Z np $"); 32 33#include <cxgb_include.h> 34 35#undef msleep 36#define msleep t3_os_sleep 37 38 39static inline int macidx(const struct cmac *mac) 40{ 41 return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR); 42} 43 44/* 45 * Returns a reasonable A_XGM_RESET_CTRL value for the mac specified. 46 */ 47static inline int xgm_reset_ctrl(const struct cmac *mac) 48{ 49 adapter_t *adap = mac->adapter; 50 int val = F_MAC_RESET_ | F_XGMAC_STOP_EN; 51 52 if (is_10G(adap)) { 53 int cfg = t3_read_reg(adap, A_XGM_PORT_CFG + mac->offset); 54 55 val |= F_PCS_RESET_; 56 if (G_PORTSPEED(cfg) != 3) /* not running at 10G */ 57 val |= F_XG2G_RESET_; 58 } else if (uses_xaui(adap)) 59 val |= F_PCS_RESET_ | F_XG2G_RESET_; 60 else 61 val |= F_RGMII_RESET_ | F_XG2G_RESET_; 62 63 return (val); 64} 65 66static void xaui_serdes_reset(struct cmac *mac) 67{ 68 static const unsigned int clear[] = { 69 F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1, 70 F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3 71 }; 72 73 int i; 74 adapter_t *adap = mac->adapter; 75 u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset; 76 77 t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] | 78 F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 | 79 F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 | 80 F_RESETPLL23 | F_RESETPLL01); 81 (void)t3_read_reg(adap, ctrl); 82 udelay(15); 83 84 for (i = 0; i < ARRAY_SIZE(clear); i++) { 85 t3_set_reg_field(adap, ctrl, clear[i], 0); 86 udelay(15); 87 } 88} 89 90/** 91 * t3b_pcs_reset - reset the PCS on T3B+ adapters 92 * @mac: the XGMAC handle 93 * 94 * Reset the XGMAC PCS block on T3B+ adapters. 95 */ 96void t3b_pcs_reset(struct cmac *mac) 97{ 98 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 99 F_PCS_RESET_, 0); 100 udelay(20); 101 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0, 102 F_PCS_RESET_); 103} 104 105/** 106 * t3_mac_init - initialize a MAC 107 * @mac: the MAC to initialize 108 * 109 * Initialize the given MAC. 110 */ 111int t3_mac_init(struct cmac *mac) 112{ 113 static struct addr_val_pair mac_reset_avp[] = { 114 { A_XGM_TX_CTRL, 0 }, 115 { A_XGM_RX_CTRL, 0 }, 116 { A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES | 117 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST }, 118 { A_XGM_RX_HASH_LOW, 0 }, 119 { A_XGM_RX_HASH_HIGH, 0 }, 120 { A_XGM_RX_EXACT_MATCH_LOW_1, 0 }, 121 { A_XGM_RX_EXACT_MATCH_LOW_2, 0 }, 122 { A_XGM_RX_EXACT_MATCH_LOW_3, 0 }, 123 { A_XGM_RX_EXACT_MATCH_LOW_4, 0 }, 124 { A_XGM_RX_EXACT_MATCH_LOW_5, 0 }, 125 { A_XGM_RX_EXACT_MATCH_LOW_6, 0 }, 126 { A_XGM_RX_EXACT_MATCH_LOW_7, 0 }, 127 { A_XGM_RX_EXACT_MATCH_LOW_8, 0 }, 128 { A_XGM_STAT_CTRL, F_CLRSTATS } 129 }; 130 u32 val; 131 adapter_t *adap = mac->adapter; 132 unsigned int oft = mac->offset; 133 134 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); 135 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 136 137 t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft); 138 t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft, 139 F_RXSTRFRWRD | F_DISERRFRAMES, 140 uses_xaui(adap) ? 0 : F_RXSTRFRWRD); 141 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX); 142 143 if (uses_xaui(adap)) { 144 if (adap->params.rev == 0) { 145 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, 146 F_RXENABLE | F_TXENABLE); 147 if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft, 148 F_CMULOCK, 1, 5, 2)) { 149 CH_ERR(adap, 150 "MAC %d XAUI SERDES CMU lock failed\n", 151 macidx(mac)); 152 return -1; 153 } 154 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, 155 F_SERDESRESET_); 156 } else 157 xaui_serdes_reset(mac); 158 } 159 160 161 if (mac->multiport) { 162 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft, 163 V_RXMAXPKTSIZE(MAX_FRAME_SIZE - 4)); 164 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, 165 F_DISPREAMBLE); 166 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE | 167 F_ENNON802_3PREAMBLE); 168 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 169 V_TXFIFOTHRESH(M_TXFIFOTHRESH), 170 V_TXFIFOTHRESH(64)); 171 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); 172 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); 173 } 174 175 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft, 176 V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE), 177 V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER); 178 179 val = xgm_reset_ctrl(mac); 180 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); 181 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 182 if ((val & F_PCS_RESET_) && adap->params.rev) { 183 msleep(1); 184 t3b_pcs_reset(mac); 185 } 186 187 memset(&mac->stats, 0, sizeof(mac->stats)); 188 return 0; 189} 190 191static int t3_mac_reset(struct cmac *mac, int portspeed) 192{ 193 u32 val, store_mps; 194 adapter_t *adap = mac->adapter; 195 unsigned int oft = mac->offset; 196 int idx = macidx(mac); 197 unsigned int store; 198 199 /* Stop egress traffic to xgm*/ 200 store_mps = t3_read_reg(adap, A_MPS_CFG); 201 if (!idx) 202 t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); 203 else 204 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); 205 206 /* This will reduce the number of TXTOGGLES */ 207 /* Clear: to stop the NIC traffic */ 208 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0); 209 /* Ensure TX drains */ 210 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0); 211 212 /* PCS in reset */ 213 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); 214 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 215 216 /* Store A_TP_TX_DROP_CFG_CH0 */ 217 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 218 store = t3_read_reg(adap, A_TP_PIO_DATA); 219 220 msleep(10); 221 222 /* Change DROP_CFG to 0xc0000011 */ 223 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 224 t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011); 225 226 /* Check for xgm Rx fifo empty */ 227 /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */ 228 if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, 229 0x80000000, 1, 1000, 2) && portspeed < 0) { 230 CH_ERR(adap, "MAC %d Rx fifo drain failed\n", idx); 231 return -1; 232 } 233 234 if (portspeed >= 0) { 235 u32 intr = t3_read_reg(adap, A_XGM_INT_ENABLE + oft); 236 237 /* 238 * safespeedchange: wipes out pretty much all XGMAC registers. 239 */ 240 241 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, 242 V_PORTSPEED(M_PORTSPEED) | F_SAFESPEEDCHANGE, 243 portspeed | F_SAFESPEEDCHANGE); 244 (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); 245 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, 246 F_SAFESPEEDCHANGE, 0); 247 (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); 248 t3_mac_init(mac); 249 250 t3_write_reg(adap, A_XGM_INT_ENABLE + oft, intr); 251 } else { 252 253 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/ 254 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 255 256 val = xgm_reset_ctrl(mac); 257 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); 258 (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 259 if ((val & F_PCS_RESET_) && adap->params.rev) { 260 msleep(1); 261 t3b_pcs_reset(mac); 262 } 263 t3_write_reg(adap, A_XGM_RX_CFG + oft, 264 F_DISPAUSEFRAMES | F_EN1536BFRAMES | 265 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST ); 266 } 267 268 /* Restore the DROP_CFG */ 269 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 270 t3_write_reg(adap, A_TP_PIO_DATA, store); 271 272 /* Resume egress traffic to xgm */ 273 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE, 274 store_mps); 275 276 /* Set: re-enable NIC traffic */ 277 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, F_ENFORCEPKT); 278 279 return 0; 280} 281 282/* 283 * Set the exact match register 'idx' to recognize the given Ethernet address. 284 */ 285static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr) 286{ 287 u32 addr_lo, addr_hi; 288 unsigned int oft = mac->offset + idx * 8; 289 290 addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; 291 addr_hi = (addr[5] << 8) | addr[4]; 292 293 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo); 294 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi); 295} 296 297/** 298 * t3_mac_set_address - set one of the station's unicast MAC addresses 299 * @mac: the MAC handle 300 * @idx: index of the exact address match filter to use 301 * @addr: the Ethernet address 302 * 303 * Set one of the station's unicast MAC addresses. 304 */ 305int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]) 306{ 307 if (mac->multiport) 308 idx = mac->ext_port + idx * mac->adapter->params.nports; 309 if (idx >= mac->nucast) 310 return -EINVAL; 311 set_addr_filter(mac, idx, addr); 312 if (mac->multiport && idx < mac->adapter->params.nports) 313 t3_vsc7323_set_addr(mac->adapter, addr, idx); 314 return 0; 315} 316 317/** 318 * t3_mac_set_num_ucast - set the number of unicast addresses needed 319 * @mac: the MAC handle 320 * @n: number of unicast addresses needed 321 * 322 * Specify the number of exact address filters that should be reserved for 323 * unicast addresses. Caller should reload the unicast and multicast 324 * addresses after calling this. 325 * 326 * Generally, this is 1 with the first one used for the station address, 327 * and the rest are available for multicast addresses. 328 */ 329int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n) 330{ 331 if (n > EXACT_ADDR_FILTERS) 332 return -EINVAL; 333 mac->nucast = n; 334 return 0; 335} 336 337void t3_mac_disable_exact_filters(struct cmac *mac) 338{ 339 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1; 340 341 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { 342 u32 v = t3_read_reg(mac->adapter, reg); 343 t3_write_reg(mac->adapter, reg, v); 344 } 345 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */ 346} 347 348void t3_mac_enable_exact_filters(struct cmac *mac) 349{ 350 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1; 351 352 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { 353 u32 v = t3_read_reg(mac->adapter, reg); 354 t3_write_reg(mac->adapter, reg, v); 355 } 356 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */ 357} 358 359/* Calculate the RX hash filter index of an Ethernet address */ 360static int hash_hw_addr(const u8 *addr) 361{ 362 int hash = 0, octet, bit, i = 0, c; 363 364 for (octet = 0; octet < 6; ++octet) 365 for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) { 366 hash ^= (c & 1) << i; 367 if (++i == 6) 368 i = 0; 369 } 370 return hash; 371} 372 373/** 374 * t3_mac_set_rx_mode - set the Rx mode and address filters 375 * @mac: the MAC to configure 376 * @rm: structure containing the Rx mode and MAC addresses needed 377 * 378 * Configures the MAC Rx mode (promiscuity, etc) and exact and hash 379 * address filters. 380 */ 381int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm) 382{ 383 u32 hash_lo, hash_hi; 384 adapter_t *adap = mac->adapter; 385 unsigned int oft = mac->offset; 386 387 if (promisc_rx_mode(rm)) 388 mac->promisc_map |= 1 << mac->ext_port; 389 else 390 mac->promisc_map &= ~(1 << mac->ext_port); 391 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES, 392 mac->promisc_map ? F_COPYALLFRAMES : 0); 393 394 if (allmulti_rx_mode(rm) || mac->multiport) 395 hash_lo = hash_hi = 0xffffffff; 396 else { 397 u8 *addr; 398 int exact_addr_idx = mac->nucast; 399 400 hash_lo = hash_hi = 0; 401 while ((addr = t3_get_next_mcaddr(rm))) 402 if (exact_addr_idx < EXACT_ADDR_FILTERS) 403 set_addr_filter(mac, exact_addr_idx++, addr); 404 else { 405 int hash = hash_hw_addr(addr); 406 407 if (hash < 32) 408 hash_lo |= (1 << hash); 409 else 410 hash_hi |= (1 << (hash - 32)); 411 } 412 } 413 414 t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); 415 t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); 416 return 0; 417} 418 419static int rx_fifo_hwm(int mtu) 420{ 421 int hwm; 422 423 hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100); 424 return min(hwm, MAC_RXFIFO_SIZE - 8192); 425} 426 427/** 428 * t3_mac_set_mtu - set the MAC MTU 429 * @mac: the MAC to configure 430 * @mtu: the MTU 431 * 432 * Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly. 433 */ 434int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) 435{ 436 int hwm, lwm, divisor; 437 int ipg; 438 unsigned int thres, v, reg; 439 adapter_t *adap = mac->adapter; 440 unsigned port_type = adap->params.vpd.port_type[macidx(mac)]; 441 unsigned int orig_mtu=mtu; 442 443 /* 444 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max 445 * packet size register includes header, but not FCS. 446 */ 447 mtu += 14; 448 if (mac->multiport) 449 mtu += 8; /* for preamble */ 450 if (mtu > MAX_FRAME_SIZE - 4) 451 return -EINVAL; 452 if (mac->multiport) 453 return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port); 454 455 /* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */ 456 if (port_type == 2) { 457 int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac)); 458 459 if (err) 460 return err; 461 } 462 463 if (adap->params.rev >= T3_REV_B2 && 464 (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { 465 t3_mac_disable_exact_filters(mac); 466 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset); 467 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset, 468 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST); 469 470 reg = adap->params.rev == T3_REV_B2 ? 471 A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG; 472 473 /* drain RX FIFO */ 474 if (t3_wait_op_done(adap, reg + mac->offset, 475 F_RXFIFO_EMPTY, 1, 20, 5)) { 476 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); 477 t3_mac_enable_exact_filters(mac); 478 return -EIO; 479 } 480 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, 481 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), 482 V_RXMAXPKTSIZE(mtu)); 483 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); 484 t3_mac_enable_exact_filters(mac); 485 } else 486 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, 487 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), 488 V_RXMAXPKTSIZE(mtu)); 489 /* 490 * Adjust the PAUSE frame watermarks. We always set the LWM, and the 491 * HWM only if flow-control is enabled. 492 */ 493 hwm = rx_fifo_hwm(mtu); 494 lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4); 495 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); 496 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); 497 v |= V_RXFIFOPAUSELWM(lwm / 8); 498 if (G_RXFIFOPAUSEHWM(v)) 499 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) | 500 V_RXFIFOPAUSEHWM(hwm / 8); 501 502 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v); 503 504 /* Adjust the TX FIFO threshold based on the MTU */ 505 thres = (adap->params.vpd.cclk * 1000) / 15625; 506 thres = (thres * mtu) / 1000; 507 if (is_10G(adap)) 508 thres /= 10; 509 thres = mtu > thres ? (mtu - thres + 7) / 8 : 0; 510 thres = max(thres, 8U); /* need at least 8 */ 511 ipg = (adap->params.rev == T3_REV_C) ? 0 : 1; 512 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, 513 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG), 514 V_TXFIFOTHRESH(thres) | V_TXIPG(ipg)); 515 516 /* Assuming a minimum drain rate of 2.5Gbps... 517 */ 518 if (adap->params.rev > 0) { 519 divisor = (adap->params.rev == T3_REV_C) ? 64 : 8; 520 t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset, 521 (hwm - lwm) * 4 / divisor); 522 } 523 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, 524 MAC_RXFIFO_SIZE * 4 * 8 / 512); 525 return 0; 526} 527 528/** 529 * t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control 530 * @mac: the MAC to configure 531 * @speed: the desired speed (10/100/1000/10000) 532 * @duplex: the desired duplex 533 * @fc: desired Tx/Rx PAUSE configuration 534 * 535 * Set the MAC speed, duplex (actually only full-duplex is supported), and 536 * flow control. If a parameter value is negative the corresponding 537 * MAC setting is left at its current value. 538 */ 539int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) 540{ 541 u32 val; 542 adapter_t *adap = mac->adapter; 543 unsigned int oft = mac->offset; 544 545 if (duplex >= 0 && duplex != DUPLEX_FULL) 546 return -EINVAL; 547 if (mac->multiport) { 548 u32 rx_max_pkt_size = 549 G_RXMAXPKTSIZE(t3_read_reg(adap, 550 A_XGM_RX_MAX_PKT_SIZE + oft)); 551 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); 552 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); 553 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); 554 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); 555 556 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 557 F_TXPAUSEEN); 558 return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port); 559 } 560 if (speed >= 0) { 561 if (speed == SPEED_10) 562 val = V_PORTSPEED(0); 563 else if (speed == SPEED_100) 564 val = V_PORTSPEED(1); 565 else if (speed == SPEED_1000) 566 val = V_PORTSPEED(2); 567 else if (speed == SPEED_10000) 568 val = V_PORTSPEED(3); 569 else 570 return -EINVAL; 571 572 if (!uses_xaui(adap)) /* T302 */ 573 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, 574 V_PORTSPEED(M_PORTSPEED), val); 575 else { 576 u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft); 577 578 if ((old & V_PORTSPEED(M_PORTSPEED)) != val) { 579 t3_mac_reset(mac, val); 580 mac->was_reset = 1; 581 } 582 } 583 } 584 585 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); 586 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); 587 if (fc & PAUSE_TX) { 588 u32 rx_max_pkt_size = 589 G_RXMAXPKTSIZE(t3_read_reg(adap, 590 A_XGM_RX_MAX_PKT_SIZE + oft)); 591 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); 592 } 593 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); 594 595 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 596 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); 597 return 0; 598} 599 600/** 601 * t3_mac_enable - enable the MAC in the given directions 602 * @mac: the MAC to configure 603 * @which: bitmap indicating which directions to enable 604 * 605 * Enables the MAC for operation in the given directions. 606 * %MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX 607 * enables the Rx one. 608 */ 609int t3_mac_enable(struct cmac *mac, int which) 610{ 611 int idx = macidx(mac); 612 adapter_t *adap = mac->adapter; 613 unsigned int oft = mac->offset; 614 struct mac_stats *s = &mac->stats; 615 616 if (mac->multiport) 617 return t3_vsc7323_enable(adap, mac->ext_port, which); 618 619 if (which & MAC_DIRECTION_TX) { 620 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 621 t3_write_reg(adap, A_TP_PIO_DATA, 622 adap->params.rev == T3_REV_C ? 623 0xc4ffff01 : 0xc0ede401); 624 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); 625 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 626 adap->params.rev == T3_REV_C ? 627 0 : 1 << idx); 628 629 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); 630 631 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx); 632 mac->tx_mcnt = s->tx_frames; 633 mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, 634 A_TP_PIO_DATA))); 635 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 636 A_XGM_TX_SPI4_SOP_EOP_CNT + 637 oft))); 638 mac->rx_mcnt = s->rx_frames; 639 mac->rx_pause = s->rx_pause; 640 mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 641 A_XGM_RX_SPI4_SOP_EOP_CNT + 642 oft))); 643 mac->rx_ocnt = s->rx_fifo_ovfl; 644 mac->txen = F_TXEN; 645 mac->toggle_cnt = 0; 646 } 647 if (which & MAC_DIRECTION_RX) 648 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); 649 return 0; 650} 651 652/** 653 * t3_mac_disable - disable the MAC in the given directions 654 * @mac: the MAC to configure 655 * @which: bitmap indicating which directions to disable 656 * 657 * Disables the MAC in the given directions. 658 * %MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX 659 * disables the Rx one. 660 */ 661int t3_mac_disable(struct cmac *mac, int which) 662{ 663 adapter_t *adap = mac->adapter; 664 665 if (mac->multiport) 666 return t3_vsc7323_disable(adap, mac->ext_port, which); 667 668 if (which & MAC_DIRECTION_TX) { 669 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); 670 mac->txen = 0; 671 } 672 if (which & MAC_DIRECTION_RX) { 673 int val = xgm_reset_ctrl(mac); 674 675 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 676 F_PCS_RESET_, 0); 677 msleep(100); 678 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); 679 t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val); 680 } 681 return 0; 682} 683 684int t3b2_mac_watchdog_task(struct cmac *mac) 685{ 686 int status; 687 unsigned int tx_tcnt, tx_xcnt; 688 adapter_t *adap = mac->adapter; 689 struct mac_stats *s = &mac->stats; 690 u64 tx_mcnt = s->tx_frames; 691 692 if (mac->multiport) 693 tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW); 694 695 status = 0; 696 tx_xcnt = 1; /* By default tx_xcnt is making progress*/ 697 tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/ 698 if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) { 699 u32 cfg, active, enforcepkt; 700 701 tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 702 A_XGM_TX_SPI4_SOP_EOP_CNT + 703 mac->offset))); 704 cfg = t3_read_reg(adap, A_MPS_CFG); 705 active = macidx(mac) ? cfg & F_PORT1ACTIVE : cfg & F_PORT0ACTIVE; 706 enforcepkt = cfg & F_ENFORCEPKT; 707 if (active && enforcepkt && (tx_xcnt == 0)) { 708 t3_write_reg(adap, A_TP_PIO_ADDR, 709 A_TP_TX_DROP_CNT_CH0 + macidx(mac)); 710 tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, 711 A_TP_PIO_DATA))); 712 } else 713 goto out; 714 715 } else { 716 mac->toggle_cnt = 0; 717 goto out; 718 } 719 720 if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) { 721 if (mac->toggle_cnt > 4) { 722 status = 2; 723 goto out; 724 } else { 725 status = 1; 726 goto out; 727 } 728 } else { 729 mac->toggle_cnt = 0; 730 goto out; 731 } 732 733out: 734 mac->tx_tcnt = tx_tcnt; 735 mac->tx_xcnt = tx_xcnt; 736 mac->tx_mcnt = s->tx_frames; 737 mac->rx_pause = s->rx_pause; 738 if (status == 1) { 739 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); 740 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ 741 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen); 742 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ 743 mac->toggle_cnt++; 744 } else if (status == 2) { 745 t3_mac_reset(mac, -1); 746 mac->toggle_cnt = 0; 747 } 748 return status; 749} 750 751/** 752 * t3_mac_update_stats - accumulate MAC statistics 753 * @mac: the MAC handle 754 * 755 * This function is called periodically to accumulate the current values 756 * of the RMON counters into the port statistics. Since the packet 757 * counters are only 32 bits they can overflow in ~286 secs at 10G, so the 758 * function should be called more frequently than that. The byte counters 759 * are 45-bit wide, they would overflow in ~7.8 hours. 760 */ 761const struct mac_stats *t3_mac_update_stats(struct cmac *mac) 762{ 763#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset) 764#define RMON_UPDATE(mac, name, reg) \ 765 (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg) 766#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \ 767 (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \ 768 ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32) 769 770 u32 v, lo; 771 772 if (mac->multiport) 773 return t3_vsc7323_update_stats(mac); 774 775 RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH); 776 RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH); 777 RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES); 778 RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES); 779 RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES); 780 RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES); 781 RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES); 782 RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES); 783 RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES); 784 785 RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES); 786 787 v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); 788 if (mac->adapter->params.rev == T3_REV_B2) 789 v &= 0x7fffffff; 790 mac->stats.rx_too_long += v; 791 792 RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES); 793 RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES); 794 RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES); 795 RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES); 796 RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES); 797 RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES); 798 RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES); 799 800 RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH); 801 RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH); 802 RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST); 803 RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST); 804 RMON_UPDATE(mac, tx_pause, TX_PAUSE); 805 /* This counts error frames in general (bad FCS, underrun, etc). */ 806 RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES); 807 808 RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES); 809 RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES); 810 RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES); 811 RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES); 812 RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES); 813 RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES); 814 RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES); 815 816 /* The next stat isn't clear-on-read. */ 817 t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50); 818 v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA); 819 lo = (u32)mac->stats.rx_cong_drops; 820 mac->stats.rx_cong_drops += (u64)(v - lo); 821 822 return &mac->stats; 823} 824