658 lines · c
1/*2 * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.3 *4 * This software is available to you under a choice of one of two5 * licenses. You may choose to be licensed under the terms of the GNU6 * General Public License (GPL) Version 2, available from the file7 * COPYING in the main directory of this source tree, or the8 * OpenIB.org BSD license below:9 *10 * Redistribution and use in source and binary forms, with or11 * without modification, are permitted provided that the following12 * conditions are met:13 *14 * - Redistributions of source code must retain the above15 * copyright notice, this list of conditions and the following16 * disclaimer.17 *18 * - Redistributions in binary form must reproduce the above19 * copyright notice, this list of conditions and the following20 * disclaimer in the documentation and/or other materials21 * provided with the distribution.22 *23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30 * SOFTWARE.31 */32#include "common.h"33#include "regs.h"34 35/*36 * # of exact address filters. The first one is used for the station address,37 * the rest are available for multicast addresses.38 */39#define EXACT_ADDR_FILTERS 840 41static inline int macidx(const struct cmac *mac)42{43 return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);44}45 46static void xaui_serdes_reset(struct cmac *mac)47{48 static const unsigned int clear[] = {49 F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,50 F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET351 };52 53 int i;54 struct adapter *adap = mac->adapter;55 u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;56 57 t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |58 F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |59 F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |60 F_RESETPLL23 | F_RESETPLL01);61 t3_read_reg(adap, ctrl);62 udelay(15);63 64 for (i = 0; i < ARRAY_SIZE(clear); i++) {65 t3_set_reg_field(adap, ctrl, clear[i], 0);66 udelay(15);67 }68}69 70void t3b_pcs_reset(struct cmac *mac)71{72 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,73 F_PCS_RESET_, 0);74 udelay(20);75 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,76 F_PCS_RESET_);77}78 79int t3_mac_reset(struct cmac *mac)80{81 static const struct addr_val_pair mac_reset_avp[] = {82 {A_XGM_TX_CTRL, 0},83 {A_XGM_RX_CTRL, 0},84 {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |85 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST},86 {A_XGM_RX_HASH_LOW, 0},87 {A_XGM_RX_HASH_HIGH, 0},88 {A_XGM_RX_EXACT_MATCH_LOW_1, 0},89 {A_XGM_RX_EXACT_MATCH_LOW_2, 0},90 {A_XGM_RX_EXACT_MATCH_LOW_3, 0},91 {A_XGM_RX_EXACT_MATCH_LOW_4, 0},92 {A_XGM_RX_EXACT_MATCH_LOW_5, 0},93 {A_XGM_RX_EXACT_MATCH_LOW_6, 0},94 {A_XGM_RX_EXACT_MATCH_LOW_7, 0},95 {A_XGM_RX_EXACT_MATCH_LOW_8, 0},96 {A_XGM_STAT_CTRL, F_CLRSTATS}97 };98 u32 val;99 struct adapter *adap = mac->adapter;100 unsigned int oft = mac->offset;101 102 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);103 t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */104 105 t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);106 t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,107 F_RXSTRFRWRD | F_DISERRFRAMES,108 uses_xaui(adap) ? 0 : F_RXSTRFRWRD);109 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX);110 111 if (uses_xaui(adap)) {112 if (adap->params.rev == 0) {113 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,114 F_RXENABLE | F_TXENABLE);115 if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,116 F_CMULOCK, 1, 5, 2)) {117 CH_ERR(adap,118 "MAC %d XAUI SERDES CMU lock failed\n",119 macidx(mac));120 return -1;121 }122 t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,123 F_SERDESRESET_);124 } else125 xaui_serdes_reset(mac);126 }127 128 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,129 V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),130 V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);131 val = F_MAC_RESET_ | F_XGMAC_STOP_EN;132 133 if (is_10G(adap))134 val |= F_PCS_RESET_;135 else if (uses_xaui(adap))136 val |= F_PCS_RESET_ | F_XG2G_RESET_;137 else138 val |= F_RGMII_RESET_ | F_XG2G_RESET_;139 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);140 t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */141 if ((val & F_PCS_RESET_) && adap->params.rev) {142 msleep(1);143 t3b_pcs_reset(mac);144 }145 146 memset(&mac->stats, 0, sizeof(mac->stats));147 return 0;148}149 150static int t3b2_mac_reset(struct cmac *mac)151{152 struct adapter *adap = mac->adapter;153 unsigned int oft = mac->offset, store;154 int idx = macidx(mac);155 u32 val;156 157 if (!macidx(mac))158 t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);159 else160 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);161 162 /* Stop NIC traffic to reduce the number of TXTOGGLES */163 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0);164 /* Ensure TX drains */165 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0);166 167 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);168 t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */169 170 /* Store A_TP_TX_DROP_CFG_CH0 */171 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);172 store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx);173 174 msleep(10);175 176 /* Change DROP_CFG to 0xc0000011 */177 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);178 t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011);179 180 /* Check for xgm Rx fifo empty */181 /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */182 if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,183 0x80000000, 1, 1000, 2)) {184 CH_ERR(adap, "MAC %d Rx fifo drain failed\n",185 macidx(mac));186 return -1;187 }188 189 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0);190 t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */191 192 val = F_MAC_RESET_;193 if (is_10G(adap))194 val |= F_PCS_RESET_;195 else if (uses_xaui(adap))196 val |= F_PCS_RESET_ | F_XG2G_RESET_;197 else198 val |= F_RGMII_RESET_ | F_XG2G_RESET_;199 t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);200 t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */201 if ((val & F_PCS_RESET_) && adap->params.rev) {202 msleep(1);203 t3b_pcs_reset(mac);204 }205 t3_write_reg(adap, A_XGM_RX_CFG + oft,206 F_DISPAUSEFRAMES | F_EN1536BFRAMES |207 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST);208 209 /* Restore the DROP_CFG */210 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);211 t3_write_reg(adap, A_TP_PIO_DATA, store);212 213 if (!idx)214 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);215 else216 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);217 218 /* re-enable nic traffic */219 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1);220 221 /* Set: re-enable NIC traffic */222 t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1);223 224 return 0;225}226 227/*228 * Set the exact match register 'idx' to recognize the given Ethernet address.229 */230static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr)231{232 u32 addr_lo, addr_hi;233 unsigned int oft = mac->offset + idx * 8;234 235 addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];236 addr_hi = (addr[5] << 8) | addr[4];237 238 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);239 t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);240}241 242/* Set one of the station's unicast MAC addresses. */243int t3_mac_set_address(struct cmac *mac, unsigned int idx, const u8 addr[6])244{245 if (idx >= mac->nucast)246 return -EINVAL;247 set_addr_filter(mac, idx, addr);248 return 0;249}250 251/*252 * Specify the number of exact address filters that should be reserved for253 * unicast addresses. Caller should reload the unicast and multicast addresses254 * after calling this.255 */256int t3_mac_set_num_ucast(struct cmac *mac, int n)257{258 if (n > EXACT_ADDR_FILTERS)259 return -EINVAL;260 mac->nucast = n;261 return 0;262}263 264void t3_mac_disable_exact_filters(struct cmac *mac)265{266 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;267 268 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {269 u32 v = t3_read_reg(mac->adapter, reg);270 t3_write_reg(mac->adapter, reg, v);271 }272 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */273}274 275void t3_mac_enable_exact_filters(struct cmac *mac)276{277 unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;278 279 for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {280 u32 v = t3_read_reg(mac->adapter, reg);281 t3_write_reg(mac->adapter, reg, v);282 }283 t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */284}285 286/* Calculate the RX hash filter index of an Ethernet address */287static int hash_hw_addr(const u8 * addr)288{289 int hash = 0, octet, bit, i = 0, c;290 291 for (octet = 0; octet < 6; ++octet)292 for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {293 hash ^= (c & 1) << i;294 if (++i == 6)295 i = 0;296 }297 return hash;298}299 300int t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev)301{302 u32 val, hash_lo, hash_hi;303 struct adapter *adap = mac->adapter;304 unsigned int oft = mac->offset;305 306 val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES;307 if (dev->flags & IFF_PROMISC)308 val |= F_COPYALLFRAMES;309 t3_write_reg(adap, A_XGM_RX_CFG + oft, val);310 311 if (dev->flags & IFF_ALLMULTI)312 hash_lo = hash_hi = 0xffffffff;313 else {314 struct netdev_hw_addr *ha;315 int exact_addr_idx = mac->nucast;316 317 hash_lo = hash_hi = 0;318 netdev_for_each_mc_addr(ha, dev)319 if (exact_addr_idx < EXACT_ADDR_FILTERS)320 set_addr_filter(mac, exact_addr_idx++,321 ha->addr);322 else {323 int hash = hash_hw_addr(ha->addr);324 325 if (hash < 32)326 hash_lo |= (1 << hash);327 else328 hash_hi |= (1 << (hash - 32));329 }330 }331 332 t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);333 t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);334 return 0;335}336 337static int rx_fifo_hwm(int mtu)338{339 int hwm;340 341 hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);342 return min(hwm, MAC_RXFIFO_SIZE - 8192);343}344 345int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)346{347 int hwm, lwm, divisor;348 int ipg;349 unsigned int thres, v, reg;350 struct adapter *adap = mac->adapter;351 352 /*353 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max354 * packet size register includes header, but not FCS.355 */356 mtu += 14;357 if (mtu > 1536)358 mtu += 4;359 360 if (mtu > MAX_FRAME_SIZE - 4)361 return -EINVAL;362 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);363 364 if (adap->params.rev >= T3_REV_B2 &&365 (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {366 t3_mac_disable_exact_filters(mac);367 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);368 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,369 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);370 371 reg = adap->params.rev == T3_REV_B2 ?372 A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;373 374 /* drain RX FIFO */375 if (t3_wait_op_done(adap, reg + mac->offset,376 F_RXFIFO_EMPTY, 1, 20, 5)) {377 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);378 t3_mac_enable_exact_filters(mac);379 return -EIO;380 }381 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,382 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),383 V_RXMAXPKTSIZE(mtu));384 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);385 t3_mac_enable_exact_filters(mac);386 } else387 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,388 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),389 V_RXMAXPKTSIZE(mtu));390 391 /*392 * Adjust the PAUSE frame watermarks. We always set the LWM, and the393 * HWM only if flow-control is enabled.394 */395 hwm = rx_fifo_hwm(mtu);396 lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4);397 v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);398 v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);399 v |= V_RXFIFOPAUSELWM(lwm / 8);400 if (G_RXFIFOPAUSEHWM(v))401 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |402 V_RXFIFOPAUSEHWM(hwm / 8);403 404 t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);405 406 /* Adjust the TX FIFO threshold based on the MTU */407 thres = (adap->params.vpd.cclk * 1000) / 15625;408 thres = (thres * mtu) / 1000;409 if (is_10G(adap))410 thres /= 10;411 thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;412 thres = max(thres, 8U); /* need at least 8 */413 ipg = (adap->params.rev == T3_REV_C) ? 0 : 1;414 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,415 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),416 V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));417 418 if (adap->params.rev > 0) {419 divisor = (adap->params.rev == T3_REV_C) ? 64 : 8;420 t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,421 (hwm - lwm) * 4 / divisor);422 }423 t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,424 MAC_RXFIFO_SIZE * 4 * 8 / 512);425 return 0;426}427 428int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)429{430 u32 val;431 struct adapter *adap = mac->adapter;432 unsigned int oft = mac->offset;433 434 if (duplex >= 0 && duplex != DUPLEX_FULL)435 return -EINVAL;436 if (speed >= 0) {437 if (speed == SPEED_10)438 val = V_PORTSPEED(0);439 else if (speed == SPEED_100)440 val = V_PORTSPEED(1);441 else if (speed == SPEED_1000)442 val = V_PORTSPEED(2);443 else if (speed == SPEED_10000)444 val = V_PORTSPEED(3);445 else446 return -EINVAL;447 448 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,449 V_PORTSPEED(M_PORTSPEED), val);450 }451 452 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);453 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);454 if (fc & PAUSE_TX) {455 u32 rx_max_pkt_size =456 G_RXMAXPKTSIZE(t3_read_reg(adap,457 A_XGM_RX_MAX_PKT_SIZE + oft));458 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);459 }460 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);461 462 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,463 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);464 return 0;465}466 467int t3_mac_enable(struct cmac *mac, int which)468{469 int idx = macidx(mac);470 struct adapter *adap = mac->adapter;471 unsigned int oft = mac->offset;472 struct mac_stats *s = &mac->stats;473 474 if (which & MAC_DIRECTION_TX) {475 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);476 t3_write_reg(adap, A_TP_PIO_DATA,477 adap->params.rev == T3_REV_C ?478 0xc4ffff01 : 0xc0ede401);479 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);480 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,481 adap->params.rev == T3_REV_C ? 0 : 1 << idx);482 483 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);484 485 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);486 mac->tx_mcnt = s->tx_frames;487 mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,488 A_TP_PIO_DATA)));489 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,490 A_XGM_TX_SPI4_SOP_EOP_CNT +491 oft)));492 mac->rx_mcnt = s->rx_frames;493 mac->rx_pause = s->rx_pause;494 mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,495 A_XGM_RX_SPI4_SOP_EOP_CNT +496 oft)));497 mac->rx_ocnt = s->rx_fifo_ovfl;498 mac->txen = F_TXEN;499 mac->toggle_cnt = 0;500 }501 if (which & MAC_DIRECTION_RX)502 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);503 return 0;504}505 506int t3_mac_disable(struct cmac *mac, int which)507{508 struct adapter *adap = mac->adapter;509 510 if (which & MAC_DIRECTION_TX) {511 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);512 mac->txen = 0;513 }514 if (which & MAC_DIRECTION_RX) {515 int val = F_MAC_RESET_;516 517 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,518 F_PCS_RESET_, 0);519 msleep(100);520 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);521 if (is_10G(adap))522 val |= F_PCS_RESET_;523 else if (uses_xaui(adap))524 val |= F_PCS_RESET_ | F_XG2G_RESET_;525 else526 val |= F_RGMII_RESET_ | F_XG2G_RESET_;527 t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);528 }529 return 0;530}531 532int t3b2_mac_watchdog_task(struct cmac *mac)533{534 struct adapter *adap = mac->adapter;535 struct mac_stats *s = &mac->stats;536 unsigned int tx_tcnt, tx_xcnt;537 u64 tx_mcnt = s->tx_frames;538 int status;539 540 status = 0;541 tx_xcnt = 1; /* By default tx_xcnt is making progress */542 tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt */543 if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {544 tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,545 A_XGM_TX_SPI4_SOP_EOP_CNT +546 mac->offset)));547 if (tx_xcnt == 0) {548 t3_write_reg(adap, A_TP_PIO_ADDR,549 A_TP_TX_DROP_CNT_CH0 + macidx(mac));550 tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,551 A_TP_PIO_DATA)));552 } else {553 goto out;554 }555 } else {556 mac->toggle_cnt = 0;557 goto out;558 }559 560 if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {561 if (mac->toggle_cnt > 4) {562 status = 2;563 goto out;564 } else {565 status = 1;566 goto out;567 }568 } else {569 mac->toggle_cnt = 0;570 goto out;571 }572 573out:574 mac->tx_tcnt = tx_tcnt;575 mac->tx_xcnt = tx_xcnt;576 mac->tx_mcnt = s->tx_frames;577 mac->rx_pause = s->rx_pause;578 if (status == 1) {579 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);580 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */581 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);582 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */583 mac->toggle_cnt++;584 } else if (status == 2) {585 t3b2_mac_reset(mac);586 mac->toggle_cnt = 0;587 }588 return status;589}590 591/*592 * This function is called periodically to accumulate the current values of the593 * RMON counters into the port statistics. Since the packet counters are only594 * 32 bits they can overflow in ~286 secs at 10G, so the function should be595 * called more frequently than that. The byte counters are 45-bit wide, they596 * would overflow in ~7.8 hours.597 */598const struct mac_stats *t3_mac_update_stats(struct cmac *mac)599{600#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)601#define RMON_UPDATE(mac, name, reg) \602 (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)603#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \604 (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \605 ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)606 607 u32 v, lo;608 609 RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);610 RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);611 RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);612 RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);613 RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);614 RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);615 RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);616 RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);617 RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);618 619 RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);620 621 v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);622 if (mac->adapter->params.rev == T3_REV_B2)623 v &= 0x7fffffff;624 mac->stats.rx_too_long += v;625 626 RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);627 RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);628 RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);629 RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);630 RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);631 RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);632 RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);633 634 RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);635 RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);636 RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);637 RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);638 RMON_UPDATE(mac, tx_pause, TX_PAUSE);639 /* This counts error frames in general (bad FCS, underrun, etc). */640 RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);641 642 RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);643 RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);644 RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);645 RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);646 RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);647 RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);648 RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);649 650 /* The next stat isn't clear-on-read. */651 t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);652 v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);653 lo = (u32) mac->stats.rx_cong_drops;654 mac->stats.rx_cong_drops += (u64) (v - lo);655 656 return &mac->stats;657}658