1167514Skmacy/************************************************************************** 2167514Skmacy 3189643SgnnCopyright (c) 2007-2009 Chelsio Inc. 4167514SkmacyAll rights reserved. 5167514Skmacy 6167514SkmacyRedistribution and use in source and binary forms, with or without 7167514Skmacymodification, are permitted provided that the following conditions are met: 8167514Skmacy 9167514Skmacy 1. Redistributions of source code must retain the above copyright notice, 10167514Skmacy this list of conditions and the following disclaimer. 11167514Skmacy 12170076Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its 13167514Skmacy contributors may be used to endorse or promote products derived from 14167514Skmacy this software without specific prior written permission. 15167514Skmacy 16167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26167514SkmacyPOSSIBILITY OF SUCH DAMAGE. 27167514Skmacy 28167514Skmacy***************************************************************************/ 29167514Skmacy 30167514Skmacy#include <sys/cdefs.h> 31167514Skmacy__FBSDID("$FreeBSD$"); 32167514Skmacy 33170076Skmacy#include <cxgb_include.h> 34167514Skmacy 35171471Skmacy#undef msleep 36171471Skmacy#define msleep t3_os_sleep 37171471Skmacy 38167514Skmacy 39167514Skmacystatic inline int macidx(const struct cmac *mac) 40167514Skmacy{ 41167514Skmacy return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR); 42167514Skmacy} 43167514Skmacy 44197791Snp/* 45197791Snp * Returns a reasonable A_XGM_RESET_CTRL value for the mac specified. 46197791Snp */ 47197791Snpstatic inline int xgm_reset_ctrl(const struct cmac *mac) 48197791Snp{ 49197791Snp adapter_t *adap = mac->adapter; 50197791Snp int val = F_MAC_RESET_ | F_XGMAC_STOP_EN; 51197791Snp 52197791Snp if (is_10G(adap)) { 53197791Snp int cfg = t3_read_reg(adap, A_XGM_PORT_CFG + mac->offset); 54197791Snp 55197791Snp val |= F_PCS_RESET_; 56197791Snp if (G_PORTSPEED(cfg) != 3) /* not running at 10G */ 57197791Snp val |= F_XG2G_RESET_; 58197791Snp } else if (uses_xaui(adap)) 59197791Snp val |= F_PCS_RESET_ | F_XG2G_RESET_; 60197791Snp else 61197791Snp val |= F_RGMII_RESET_ | F_XG2G_RESET_; 62197791Snp 63197791Snp return (val); 64197791Snp} 65197791Snp 66167514Skmacystatic void xaui_serdes_reset(struct cmac *mac) 67167514Skmacy{ 68167514Skmacy static const unsigned int clear[] = { 69167514Skmacy F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1, 70167514Skmacy F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3 71167514Skmacy }; 72167514Skmacy 73167514Skmacy int i; 74167514Skmacy adapter_t *adap = mac->adapter; 75167514Skmacy u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset; 76167514Skmacy 77167514Skmacy t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] | 78167514Skmacy F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 | 79167514Skmacy F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 | 80167514Skmacy F_RESETPLL23 | F_RESETPLL01); 81167514Skmacy (void)t3_read_reg(adap, ctrl); 82167514Skmacy udelay(15); 83167514Skmacy 84167514Skmacy for (i = 0; i < ARRAY_SIZE(clear); i++) { 85167514Skmacy t3_set_reg_field(adap, ctrl, clear[i], 0); 86167514Skmacy udelay(15); 87167514Skmacy } 88167514Skmacy} 89167514Skmacy 90176472Skmacy/** 91176472Skmacy * t3b_pcs_reset - reset the PCS on T3B+ adapters 92176472Skmacy * @mac: the XGMAC handle 93176472Skmacy * 94176472Skmacy * Reset the XGMAC PCS block on T3B+ adapters. 95176472Skmacy */ 96167514Skmacyvoid t3b_pcs_reset(struct cmac *mac) 97167514Skmacy{ 98167514Skmacy t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 99167514Skmacy F_PCS_RESET_, 0); 100211346Snp 101211346Snp /* No delay required */ 102211346Snp 103167514Skmacy t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0, 104167514Skmacy F_PCS_RESET_); 105167514Skmacy} 106167514Skmacy 107211346Snpvoid t3c_pcs_force_los(struct cmac *mac) 108211346Snp{ 109211346Snp t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT0 + mac->offset, 110211346Snp F_LOWSIGFORCEEN0 | F_LOWSIGFORCEVALUE0, 111211346Snp F_LOWSIGFORCEEN0 | F_LOWSIGFORCEVALUE0); 112211346Snp t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT1 + mac->offset, 113211346Snp F_LOWSIGFORCEEN1 | F_LOWSIGFORCEVALUE1, 114211346Snp F_LOWSIGFORCEEN1 | F_LOWSIGFORCEVALUE1); 115211346Snp t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT2 + mac->offset, 116211346Snp F_LOWSIGFORCEEN2 | F_LOWSIGFORCEVALUE2, 117211346Snp F_LOWSIGFORCEEN2 | F_LOWSIGFORCEVALUE2); 118211346Snp t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT3 + mac->offset, 119211346Snp F_LOWSIGFORCEEN3 | F_LOWSIGFORCEVALUE3, 120211346Snp F_LOWSIGFORCEEN3 | F_LOWSIGFORCEVALUE3); 121211346Snp 122211346Snp /* No delay required */ 123211346Snp 124211346Snp t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT0 + mac->offset, 125211346Snp F_LOWSIGFORCEEN0, 0); 126211346Snp t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT1 + mac->offset, 127211346Snp F_LOWSIGFORCEEN1, 0); 128211346Snp t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT2 + mac->offset, 129211346Snp F_LOWSIGFORCEEN2, 0); 130211346Snp t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT3 + mac->offset, 131211346Snp F_LOWSIGFORCEEN3, 0); 132211346Snp} 133211346Snp 134176472Skmacy/** 135197791Snp * t3_mac_init - initialize a MAC 136197791Snp * @mac: the MAC to initialize 137176472Skmacy * 138197791Snp * Initialize the given MAC. 139176472Skmacy */ 140197791Snpint t3_mac_init(struct cmac *mac) 141167514Skmacy{ 142167514Skmacy static struct addr_val_pair mac_reset_avp[] = { 143167514Skmacy { A_XGM_TX_CTRL, 0 }, 144167514Skmacy { A_XGM_RX_CTRL, 0 }, 145167514Skmacy { A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES | 146167514Skmacy F_RMFCS | F_ENJUMBO | F_ENHASHMCAST }, 147167514Skmacy { A_XGM_RX_HASH_LOW, 0 }, 148167514Skmacy { A_XGM_RX_HASH_HIGH, 0 }, 149167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_1, 0 }, 150167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_2, 0 }, 151167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_3, 0 }, 152167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_4, 0 }, 153167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_5, 0 }, 154167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_6, 0 }, 155167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_7, 0 }, 156167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_8, 0 }, 157167514Skmacy { A_XGM_STAT_CTRL, F_CLRSTATS } 158167514Skmacy }; 159167514Skmacy u32 val; 160167514Skmacy adapter_t *adap = mac->adapter; 161167514Skmacy unsigned int oft = mac->offset; 162167514Skmacy 163167514Skmacy t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); 164167514Skmacy (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 165167514Skmacy 166167514Skmacy t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft); 167167514Skmacy t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft, 168167514Skmacy F_RXSTRFRWRD | F_DISERRFRAMES, 169167514Skmacy uses_xaui(adap) ? 0 : F_RXSTRFRWRD); 170176472Skmacy t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX); 171167514Skmacy 172167514Skmacy if (uses_xaui(adap)) { 173167514Skmacy if (adap->params.rev == 0) { 174167514Skmacy t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, 175167514Skmacy F_RXENABLE | F_TXENABLE); 176167514Skmacy if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft, 177167514Skmacy F_CMULOCK, 1, 5, 2)) { 178167514Skmacy CH_ERR(adap, 179167514Skmacy "MAC %d XAUI SERDES CMU lock failed\n", 180167514Skmacy macidx(mac)); 181167514Skmacy return -1; 182167514Skmacy } 183167514Skmacy t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, 184167514Skmacy F_SERDESRESET_); 185167514Skmacy } else 186167514Skmacy xaui_serdes_reset(mac); 187167514Skmacy } 188167514Skmacy 189170654Skmacy 190170654Skmacy if (mac->multiport) { 191170654Skmacy t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft, 192197791Snp V_RXMAXPKTSIZE(MAX_FRAME_SIZE - 4)); 193170654Skmacy t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, 194170654Skmacy F_DISPREAMBLE); 195170654Skmacy t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE | 196170654Skmacy F_ENNON802_3PREAMBLE); 197170654Skmacy t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 198170654Skmacy V_TXFIFOTHRESH(M_TXFIFOTHRESH), 199170654Skmacy V_TXFIFOTHRESH(64)); 200170654Skmacy t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); 201170654Skmacy t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); 202170654Skmacy } 203180583Skmacy 204176472Skmacy t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft, 205176472Skmacy V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE), 206176472Skmacy V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER); 207180583Skmacy 208197791Snp val = xgm_reset_ctrl(mac); 209167514Skmacy t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); 210167514Skmacy (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 211167514Skmacy if ((val & F_PCS_RESET_) && adap->params.rev) { 212171471Skmacy msleep(1); 213167514Skmacy t3b_pcs_reset(mac); 214167514Skmacy } 215167514Skmacy 216167514Skmacy memset(&mac->stats, 0, sizeof(mac->stats)); 217167514Skmacy return 0; 218167514Skmacy} 219167514Skmacy 220197791Snpstatic int t3_mac_reset(struct cmac *mac, int portspeed) 221167746Skmacy{ 222197791Snp u32 val, store_mps; 223167746Skmacy adapter_t *adap = mac->adapter; 224167746Skmacy unsigned int oft = mac->offset; 225181614Skmacy int idx = macidx(mac); 226181614Skmacy unsigned int store; 227167746Skmacy 228167746Skmacy /* Stop egress traffic to xgm*/ 229197791Snp store_mps = t3_read_reg(adap, A_MPS_CFG); 230197791Snp if (!idx) 231180583Skmacy t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); 232167746Skmacy else 233180583Skmacy t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); 234167746Skmacy 235189643Sgnn /* This will reduce the number of TXTOGGLES */ 236189643Sgnn /* Clear: to stop the NIC traffic */ 237189643Sgnn t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0); 238189643Sgnn /* Ensure TX drains */ 239189643Sgnn t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0); 240189643Sgnn 241167746Skmacy /* PCS in reset */ 242167746Skmacy t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); 243167746Skmacy (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 244167746Skmacy 245181614Skmacy /* Store A_TP_TX_DROP_CFG_CH0 */ 246181614Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 247197791Snp store = t3_read_reg(adap, A_TP_PIO_DATA); 248181614Skmacy 249171471Skmacy msleep(10); 250167746Skmacy 251181614Skmacy /* Change DROP_CFG to 0xc0000011 */ 252181614Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 253181614Skmacy t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011); 254181614Skmacy 255167746Skmacy /* Check for xgm Rx fifo empty */ 256181614Skmacy /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */ 257167746Skmacy if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, 258197791Snp 0x80000000, 1, 1000, 2) && portspeed < 0) { 259197791Snp CH_ERR(adap, "MAC %d Rx fifo drain failed\n", idx); 260167746Skmacy return -1; 261167746Skmacy } 262167746Skmacy 263197791Snp if (portspeed >= 0) { 264197791Snp u32 intr = t3_read_reg(adap, A_XGM_INT_ENABLE + oft); 265167746Skmacy 266197791Snp /* 267197791Snp * safespeedchange: wipes out pretty much all XGMAC registers. 268197791Snp */ 269197791Snp 270197791Snp t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, 271197791Snp V_PORTSPEED(M_PORTSPEED) | F_SAFESPEEDCHANGE, 272197791Snp portspeed | F_SAFESPEEDCHANGE); 273197791Snp (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); 274197791Snp t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, 275197791Snp F_SAFESPEEDCHANGE, 0); 276197791Snp (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); 277197791Snp t3_mac_init(mac); 278197791Snp 279197791Snp t3_write_reg(adap, A_XGM_INT_ENABLE + oft, intr); 280197791Snp } else { 281197791Snp 282197791Snp t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/ 283197791Snp (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 284197791Snp 285197791Snp val = xgm_reset_ctrl(mac); 286197791Snp t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); 287197791Snp (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 288197791Snp if ((val & F_PCS_RESET_) && adap->params.rev) { 289197791Snp msleep(1); 290197791Snp t3b_pcs_reset(mac); 291197791Snp } 292197791Snp t3_write_reg(adap, A_XGM_RX_CFG + oft, 293197791Snp F_DISPAUSEFRAMES | F_EN1536BFRAMES | 294197791Snp F_RMFCS | F_ENJUMBO | F_ENHASHMCAST ); 295167746Skmacy } 296167746Skmacy 297181614Skmacy /* Restore the DROP_CFG */ 298181614Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 299181614Skmacy t3_write_reg(adap, A_TP_PIO_DATA, store); 300181614Skmacy 301181614Skmacy /* Resume egress traffic to xgm */ 302197791Snp t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE, 303197791Snp store_mps); 304167746Skmacy 305189643Sgnn /* Set: re-enable NIC traffic */ 306197791Snp t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, F_ENFORCEPKT); 307189643Sgnn 308167746Skmacy return 0; 309167746Skmacy} 310167746Skmacy 311167514Skmacy/* 312167514Skmacy * Set the exact match register 'idx' to recognize the given Ethernet address. 313167514Skmacy */ 314167514Skmacystatic void set_addr_filter(struct cmac *mac, int idx, const u8 *addr) 315167514Skmacy{ 316167514Skmacy u32 addr_lo, addr_hi; 317167514Skmacy unsigned int oft = mac->offset + idx * 8; 318167514Skmacy 319167514Skmacy addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; 320167514Skmacy addr_hi = (addr[5] << 8) | addr[4]; 321167514Skmacy 322167514Skmacy t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo); 323167514Skmacy t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi); 324167514Skmacy} 325167514Skmacy 326176472Skmacy/** 327176472Skmacy * t3_mac_set_address - set one of the station's unicast MAC addresses 328176472Skmacy * @mac: the MAC handle 329176472Skmacy * @idx: index of the exact address match filter to use 330176472Skmacy * @addr: the Ethernet address 331176472Skmacy * 332176472Skmacy * Set one of the station's unicast MAC addresses. 333176472Skmacy */ 334167514Skmacyint t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]) 335167514Skmacy{ 336170654Skmacy if (mac->multiport) 337170654Skmacy idx = mac->ext_port + idx * mac->adapter->params.nports; 338167514Skmacy if (idx >= mac->nucast) 339167514Skmacy return -EINVAL; 340167514Skmacy set_addr_filter(mac, idx, addr); 341170654Skmacy if (mac->multiport && idx < mac->adapter->params.nports) 342170654Skmacy t3_vsc7323_set_addr(mac->adapter, addr, idx); 343167514Skmacy return 0; 344167514Skmacy} 345167514Skmacy 346176472Skmacy/** 347176472Skmacy * t3_mac_set_num_ucast - set the number of unicast addresses needed 348176472Skmacy * @mac: the MAC handle 349176472Skmacy * @n: number of unicast addresses needed 350176472Skmacy * 351176472Skmacy * Specify the number of exact address filters that should be reserved for 352176472Skmacy * unicast addresses. Caller should reload the unicast and multicast 353176472Skmacy * addresses after calling this. 354180583Skmacy * 355180583Skmacy * Generally, this is 1 with the first one used for the station address, 356180583Skmacy * and the rest are available for multicast addresses. 357167514Skmacy */ 358170654Skmacyint t3_mac_set_num_ucast(struct cmac *mac, unsigned char n) 359167514Skmacy{ 360167514Skmacy if (n > EXACT_ADDR_FILTERS) 361167514Skmacy return -EINVAL; 362167514Skmacy mac->nucast = n; 363167514Skmacy return 0; 364167514Skmacy} 365167514Skmacy 366189643Sgnnvoid t3_mac_disable_exact_filters(struct cmac *mac) 367170654Skmacy{ 368170654Skmacy unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1; 369170654Skmacy 370170654Skmacy for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { 371170654Skmacy u32 v = t3_read_reg(mac->adapter, reg); 372170654Skmacy t3_write_reg(mac->adapter, reg, v); 373170654Skmacy } 374170654Skmacy t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */ 375170654Skmacy} 376170654Skmacy 377189643Sgnnvoid t3_mac_enable_exact_filters(struct cmac *mac) 378170654Skmacy{ 379170654Skmacy unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1; 380170654Skmacy 381170654Skmacy for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { 382170654Skmacy u32 v = t3_read_reg(mac->adapter, reg); 383170654Skmacy t3_write_reg(mac->adapter, reg, v); 384170654Skmacy } 385170654Skmacy t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */ 386170654Skmacy} 387170654Skmacy 388167514Skmacy/* Calculate the RX hash filter index of an Ethernet address */ 389167514Skmacystatic int hash_hw_addr(const u8 *addr) 390167514Skmacy{ 391167514Skmacy int hash = 0, octet, bit, i = 0, c; 392167514Skmacy 393167514Skmacy for (octet = 0; octet < 6; ++octet) 394167514Skmacy for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) { 395167514Skmacy hash ^= (c & 1) << i; 396167514Skmacy if (++i == 6) 397167514Skmacy i = 0; 398167514Skmacy } 399167514Skmacy return hash; 400167514Skmacy} 401167514Skmacy 402176472Skmacy/** 403176472Skmacy * t3_mac_set_rx_mode - set the Rx mode and address filters 404176472Skmacy * @mac: the MAC to configure 405176472Skmacy * @rm: structure containing the Rx mode and MAC addresses needed 406176472Skmacy * 407176472Skmacy * Configures the MAC Rx mode (promiscuity, etc) and exact and hash 408176472Skmacy * address filters. 409176472Skmacy */ 410167514Skmacyint t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm) 411167514Skmacy{ 412170654Skmacy u32 hash_lo, hash_hi; 413167514Skmacy adapter_t *adap = mac->adapter; 414167514Skmacy unsigned int oft = mac->offset; 415167514Skmacy 416167514Skmacy if (promisc_rx_mode(rm)) 417170654Skmacy mac->promisc_map |= 1 << mac->ext_port; 418170654Skmacy else 419170654Skmacy mac->promisc_map &= ~(1 << mac->ext_port); 420170654Skmacy t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES, 421170654Skmacy mac->promisc_map ? F_COPYALLFRAMES : 0); 422167514Skmacy 423170654Skmacy if (allmulti_rx_mode(rm) || mac->multiport) 424167514Skmacy hash_lo = hash_hi = 0xffffffff; 425167514Skmacy else { 426167514Skmacy u8 *addr; 427167514Skmacy int exact_addr_idx = mac->nucast; 428167514Skmacy 429167514Skmacy hash_lo = hash_hi = 0; 430167514Skmacy while ((addr = t3_get_next_mcaddr(rm))) 431167514Skmacy if (exact_addr_idx < EXACT_ADDR_FILTERS) 432167514Skmacy set_addr_filter(mac, exact_addr_idx++, addr); 433167514Skmacy else { 434167514Skmacy int hash = hash_hw_addr(addr); 435167514Skmacy 436167514Skmacy if (hash < 32) 437167514Skmacy hash_lo |= (1 << hash); 438167514Skmacy else 439167514Skmacy hash_hi |= (1 << (hash - 32)); 440167514Skmacy } 441167514Skmacy } 442167514Skmacy 443167514Skmacy t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); 444167514Skmacy t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); 445167514Skmacy return 0; 446167514Skmacy} 447167514Skmacy 448170654Skmacystatic int rx_fifo_hwm(int mtu) 449167514Skmacy{ 450170654Skmacy int hwm; 451170654Skmacy 452170654Skmacy hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100); 453170654Skmacy return min(hwm, MAC_RXFIFO_SIZE - 8192); 454170654Skmacy} 455170654Skmacy 456176472Skmacy/** 457176472Skmacy * t3_mac_set_mtu - set the MAC MTU 458176472Skmacy * @mac: the MAC to configure 459176472Skmacy * @mtu: the MTU 460176472Skmacy * 461176472Skmacy * Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly. 462176472Skmacy */ 463180583Skmacyint t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) 464170654Skmacy{ 465211347Snp int hwm, lwm; 466176472Skmacy int ipg; 467176472Skmacy unsigned int thres, v, reg; 468167514Skmacy adapter_t *adap = mac->adapter; 469197791Snp unsigned port_type = adap->params.vpd.port_type[macidx(mac)]; 470197791Snp unsigned int orig_mtu=mtu; 471167514Skmacy 472167514Skmacy /* 473167514Skmacy * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max 474167514Skmacy * packet size register includes header, but not FCS. 475167514Skmacy */ 476167514Skmacy mtu += 14; 477170654Skmacy if (mac->multiport) 478170654Skmacy mtu += 8; /* for preamble */ 479167514Skmacy if (mtu > MAX_FRAME_SIZE - 4) 480167514Skmacy return -EINVAL; 481170654Skmacy if (mac->multiport) 482170654Skmacy return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port); 483167514Skmacy 484197791Snp /* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */ 485197791Snp if (port_type == 2) { 486197791Snp int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac)); 487197791Snp 488197791Snp if (err) 489197791Snp return err; 490197791Snp } 491197791Snp 492176472Skmacy if (adap->params.rev >= T3_REV_B2 && 493170654Skmacy (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { 494189643Sgnn t3_mac_disable_exact_filters(mac); 495170654Skmacy v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset); 496170654Skmacy t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset, 497170654Skmacy F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST); 498170654Skmacy 499176472Skmacy reg = adap->params.rev == T3_REV_B2 ? 500176472Skmacy A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG; 501180583Skmacy 502176472Skmacy /* drain RX FIFO */ 503176472Skmacy if (t3_wait_op_done(adap, reg + mac->offset, 504176472Skmacy F_RXFIFO_EMPTY, 1, 20, 5)) { 505170654Skmacy t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); 506189643Sgnn t3_mac_enable_exact_filters(mac); 507170654Skmacy return -EIO; 508170654Skmacy } 509176472Skmacy t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, 510176472Skmacy V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), 511176472Skmacy V_RXMAXPKTSIZE(mtu)); 512170654Skmacy t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); 513189643Sgnn t3_mac_enable_exact_filters(mac); 514170654Skmacy } else 515176472Skmacy t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, 516180583Skmacy V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), 517180583Skmacy V_RXMAXPKTSIZE(mtu)); 518167514Skmacy /* 519167514Skmacy * Adjust the PAUSE frame watermarks. We always set the LWM, and the 520167514Skmacy * HWM only if flow-control is enabled. 521167514Skmacy */ 522170654Skmacy hwm = rx_fifo_hwm(mtu); 523167746Skmacy lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4); 524167514Skmacy v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); 525167514Skmacy v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); 526167514Skmacy v |= V_RXFIFOPAUSELWM(lwm / 8); 527167514Skmacy if (G_RXFIFOPAUSEHWM(v)) 528167514Skmacy v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) | 529167514Skmacy V_RXFIFOPAUSEHWM(hwm / 8); 530170654Skmacy 531167514Skmacy t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v); 532167514Skmacy 533167514Skmacy /* Adjust the TX FIFO threshold based on the MTU */ 534167514Skmacy thres = (adap->params.vpd.cclk * 1000) / 15625; 535167514Skmacy thres = (thres * mtu) / 1000; 536167514Skmacy if (is_10G(adap)) 537167514Skmacy thres /= 10; 538167514Skmacy thres = mtu > thres ? (mtu - thres + 7) / 8 : 0; 539167514Skmacy thres = max(thres, 8U); /* need at least 8 */ 540199239Snp ipg = (port_type == 9 || adap->params.rev != T3_REV_C) ? 1 : 0; 541167514Skmacy t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, 542169978Skmacy V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG), 543176472Skmacy V_TXFIFOTHRESH(thres) | V_TXIPG(ipg)); 544167514Skmacy return 0; 545167514Skmacy} 546167514Skmacy 547176472Skmacy/** 548176472Skmacy * t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control 549176472Skmacy * @mac: the MAC to configure 550176472Skmacy * @speed: the desired speed (10/100/1000/10000) 551176472Skmacy * @duplex: the desired duplex 552176472Skmacy * @fc: desired Tx/Rx PAUSE configuration 553176472Skmacy * 554176472Skmacy * Set the MAC speed, duplex (actually only full-duplex is supported), and 555176472Skmacy * flow control. If a parameter value is negative the corresponding 556176472Skmacy * MAC setting is left at its current value. 557176472Skmacy */ 558167514Skmacyint t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) 559167514Skmacy{ 560167514Skmacy u32 val; 561167514Skmacy adapter_t *adap = mac->adapter; 562167514Skmacy unsigned int oft = mac->offset; 563211347Snp unsigned int pause_bits; 564167514Skmacy 565167514Skmacy if (duplex >= 0 && duplex != DUPLEX_FULL) 566167514Skmacy return -EINVAL; 567211347Snp 568211347Snp pause_bits = MAC_RXFIFO_SIZE * 4 * 8; 569211347Snp t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, 570211347Snp pause_bits / 512); 571211347Snp t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset, 572211347Snp (pause_bits >> (adap->params.rev == T3_REV_C ? 10 : 7))); 573211347Snp 574180583Skmacy if (mac->multiport) { 575197791Snp u32 rx_max_pkt_size = 576197791Snp G_RXMAXPKTSIZE(t3_read_reg(adap, 577197791Snp A_XGM_RX_MAX_PKT_SIZE + oft)); 578171471Skmacy val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); 579171471Skmacy val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); 580197791Snp val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); 581171471Skmacy t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); 582171471Skmacy t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 583171471Skmacy F_TXPAUSEEN); 584211347Snp 585170654Skmacy return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port); 586171471Skmacy } 587167514Skmacy if (speed >= 0) { 588167514Skmacy if (speed == SPEED_10) 589167514Skmacy val = V_PORTSPEED(0); 590167514Skmacy else if (speed == SPEED_100) 591167514Skmacy val = V_PORTSPEED(1); 592167514Skmacy else if (speed == SPEED_1000) 593167514Skmacy val = V_PORTSPEED(2); 594167514Skmacy else if (speed == SPEED_10000) 595167514Skmacy val = V_PORTSPEED(3); 596167514Skmacy else 597167514Skmacy return -EINVAL; 598167514Skmacy 599197791Snp if (!uses_xaui(adap)) /* T302 */ 600197791Snp t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, 601197791Snp V_PORTSPEED(M_PORTSPEED), val); 602197791Snp else { 603197791Snp u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft); 604197791Snp 605197791Snp if ((old & V_PORTSPEED(M_PORTSPEED)) != val) { 606197791Snp t3_mac_reset(mac, val); 607197791Snp mac->was_reset = 1; 608197791Snp } 609197791Snp } 610167514Skmacy } 611170654Skmacy 612167514Skmacy val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); 613167514Skmacy val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); 614197791Snp if (fc & PAUSE_TX) { 615197791Snp u32 rx_max_pkt_size = 616197791Snp G_RXMAXPKTSIZE(t3_read_reg(adap, 617197791Snp A_XGM_RX_MAX_PKT_SIZE + oft)); 618197791Snp val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); 619197791Snp } 620167514Skmacy t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); 621170654Skmacy 622167514Skmacy t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 623171471Skmacy (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); 624167514Skmacy return 0; 625167514Skmacy} 626167514Skmacy 627176472Skmacy/** 628176472Skmacy * t3_mac_enable - enable the MAC in the given directions 629176472Skmacy * @mac: the MAC to configure 630176472Skmacy * @which: bitmap indicating which directions to enable 631176472Skmacy * 632176472Skmacy * Enables the MAC for operation in the given directions. 633176472Skmacy * %MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX 634176472Skmacy * enables the Rx one. 635176472Skmacy */ 636167514Skmacyint t3_mac_enable(struct cmac *mac, int which) 637167514Skmacy{ 638167514Skmacy int idx = macidx(mac); 639167514Skmacy adapter_t *adap = mac->adapter; 640167514Skmacy unsigned int oft = mac->offset; 641169978Skmacy struct mac_stats *s = &mac->stats; 642167514Skmacy 643170654Skmacy if (mac->multiport) 644170654Skmacy return t3_vsc7323_enable(adap, mac->ext_port, which); 645170654Skmacy 646167514Skmacy if (which & MAC_DIRECTION_TX) { 647167514Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 648176472Skmacy t3_write_reg(adap, A_TP_PIO_DATA, 649176472Skmacy adap->params.rev == T3_REV_C ? 650176472Skmacy 0xc4ffff01 : 0xc0ede401); 651167514Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); 652176472Skmacy t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 653176472Skmacy adap->params.rev == T3_REV_C ? 654176472Skmacy 0 : 1 << idx); 655167746Skmacy 656171471Skmacy t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); 657171471Skmacy 658167746Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx); 659169978Skmacy mac->tx_mcnt = s->tx_frames; 660169978Skmacy mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, 661169978Skmacy A_TP_PIO_DATA))); 662169978Skmacy mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 663169978Skmacy A_XGM_TX_SPI4_SOP_EOP_CNT + 664169978Skmacy oft))); 665169978Skmacy mac->rx_mcnt = s->rx_frames; 666172096Skmacy mac->rx_pause = s->rx_pause; 667169978Skmacy mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 668169978Skmacy A_XGM_RX_SPI4_SOP_EOP_CNT + 669169978Skmacy oft))); 670172096Skmacy mac->rx_ocnt = s->rx_fifo_ovfl; 671167746Skmacy mac->txen = F_TXEN; 672167746Skmacy mac->toggle_cnt = 0; 673167514Skmacy } 674180583Skmacy if (which & MAC_DIRECTION_RX) 675167514Skmacy t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); 676167514Skmacy return 0; 677167514Skmacy} 678167514Skmacy 679176472Skmacy/** 680176472Skmacy * t3_mac_disable - disable the MAC in the given directions 681176472Skmacy * @mac: the MAC to configure 682176472Skmacy * @which: bitmap indicating which directions to disable 683176472Skmacy * 684176472Skmacy * Disables the MAC in the given directions. 685176472Skmacy * %MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX 686176472Skmacy * disables the Rx one. 687176472Skmacy */ 688167514Skmacyint t3_mac_disable(struct cmac *mac, int which) 689167514Skmacy{ 690167514Skmacy adapter_t *adap = mac->adapter; 691167514Skmacy 692170654Skmacy if (mac->multiport) 693170654Skmacy return t3_vsc7323_disable(adap, mac->ext_port, which); 694170654Skmacy 695167514Skmacy if (which & MAC_DIRECTION_TX) { 696167514Skmacy t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); 697167746Skmacy mac->txen = 0; 698167514Skmacy } 699169978Skmacy if (which & MAC_DIRECTION_RX) { 700197791Snp int val = xgm_reset_ctrl(mac); 701172096Skmacy 702169978Skmacy t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 703169978Skmacy F_PCS_RESET_, 0); 704171471Skmacy msleep(100); 705167514Skmacy t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); 706169978Skmacy t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val); 707169978Skmacy } 708167514Skmacy return 0; 709167514Skmacy} 710167514Skmacy 711167746Skmacyint t3b2_mac_watchdog_task(struct cmac *mac) 712167746Skmacy{ 713167746Skmacy int status; 714169978Skmacy unsigned int tx_tcnt, tx_xcnt; 715167746Skmacy adapter_t *adap = mac->adapter; 716169978Skmacy struct mac_stats *s = &mac->stats; 717189643Sgnn u64 tx_mcnt = s->tx_frames; 718167746Skmacy 719189643Sgnn if (mac->multiport) 720189643Sgnn tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW); 721189643Sgnn 722169978Skmacy status = 0; 723169978Skmacy tx_xcnt = 1; /* By default tx_xcnt is making progress*/ 724169978Skmacy tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/ 725172096Skmacy if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) { 726197791Snp u32 cfg, active, enforcepkt; 727197791Snp 728169978Skmacy tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 729189643Sgnn A_XGM_TX_SPI4_SOP_EOP_CNT + 730189643Sgnn mac->offset))); 731197791Snp cfg = t3_read_reg(adap, A_MPS_CFG); 732197791Snp active = macidx(mac) ? cfg & F_PORT1ACTIVE : cfg & F_PORT0ACTIVE; 733197791Snp enforcepkt = cfg & F_ENFORCEPKT; 734197791Snp if (active && enforcepkt && (tx_xcnt == 0)) { 735169978Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, 736169978Skmacy A_TP_TX_DROP_CNT_CH0 + macidx(mac)); 737169978Skmacy tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, 738169978Skmacy A_TP_PIO_DATA))); 739189643Sgnn } else 740185564Sgnn goto out; 741189643Sgnn 742169978Skmacy } else { 743169978Skmacy mac->toggle_cnt = 0; 744185564Sgnn goto out; 745169978Skmacy } 746169978Skmacy 747172096Skmacy if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) { 748167746Skmacy if (mac->toggle_cnt > 4) { 749167746Skmacy status = 2; 750169978Skmacy goto out; 751167746Skmacy } else { 752167746Skmacy status = 1; 753169978Skmacy goto out; 754169978Skmacy } 755167746Skmacy } else { 756167746Skmacy mac->toggle_cnt = 0; 757169978Skmacy goto out; 758169978Skmacy } 759180583Skmacy 760180583Skmacyout: 761169978Skmacy mac->tx_tcnt = tx_tcnt; 762169978Skmacy mac->tx_xcnt = tx_xcnt; 763169978Skmacy mac->tx_mcnt = s->tx_frames; 764172096Skmacy mac->rx_pause = s->rx_pause; 765169978Skmacy if (status == 1) { 766169978Skmacy t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); 767169978Skmacy t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ 768169978Skmacy t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen); 769169978Skmacy t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ 770169978Skmacy mac->toggle_cnt++; 771169978Skmacy } else if (status == 2) { 772197791Snp t3_mac_reset(mac, -1); 773169978Skmacy mac->toggle_cnt = 0; 774169978Skmacy } 775167746Skmacy return status; 776167746Skmacy} 777167746Skmacy 778176472Skmacy/** 779176472Skmacy * t3_mac_update_stats - accumulate MAC statistics 780176472Skmacy * @mac: the MAC handle 781176472Skmacy * 782176472Skmacy * This function is called periodically to accumulate the current values 783176472Skmacy * of the RMON counters into the port statistics. Since the packet 784176472Skmacy * counters are only 32 bits they can overflow in ~286 secs at 10G, so the 785176472Skmacy * function should be called more frequently than that. The byte counters 786176472Skmacy * are 45-bit wide, they would overflow in ~7.8 hours. 787167514Skmacy */ 788167514Skmacyconst struct mac_stats *t3_mac_update_stats(struct cmac *mac) 789167514Skmacy{ 790167514Skmacy#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset) 791167514Skmacy#define RMON_UPDATE(mac, name, reg) \ 792167514Skmacy (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg) 793167514Skmacy#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \ 794167514Skmacy (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \ 795167514Skmacy ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32) 796167514Skmacy 797167514Skmacy u32 v, lo; 798167514Skmacy 799171471Skmacy if (mac->multiport) 800171471Skmacy return t3_vsc7323_update_stats(mac); 801171471Skmacy 802167514Skmacy RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH); 803167514Skmacy RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH); 804167514Skmacy RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES); 805167514Skmacy RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES); 806167514Skmacy RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES); 807167514Skmacy RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES); 808167514Skmacy RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES); 809167514Skmacy RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES); 810167514Skmacy RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES); 811167514Skmacy 812167514Skmacy RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES); 813167514Skmacy 814167746Skmacy v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); 815167746Skmacy if (mac->adapter->params.rev == T3_REV_B2) 816167746Skmacy v &= 0x7fffffff; 817167746Skmacy mac->stats.rx_too_long += v; 818167746Skmacy 819167514Skmacy RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES); 820167514Skmacy RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES); 821167514Skmacy RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES); 822167514Skmacy RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES); 823167514Skmacy RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES); 824167514Skmacy RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES); 825167514Skmacy RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES); 826167514Skmacy 827167514Skmacy RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH); 828167514Skmacy RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH); 829167514Skmacy RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST); 830167514Skmacy RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST); 831167514Skmacy RMON_UPDATE(mac, tx_pause, TX_PAUSE); 832167514Skmacy /* This counts error frames in general (bad FCS, underrun, etc). */ 833167514Skmacy RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES); 834167514Skmacy 835167514Skmacy RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES); 836167514Skmacy RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES); 837167514Skmacy RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES); 838167514Skmacy RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES); 839167514Skmacy RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES); 840167514Skmacy RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES); 841167514Skmacy RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES); 842167514Skmacy 843167514Skmacy /* The next stat isn't clear-on-read. */ 844167514Skmacy t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50); 845167514Skmacy v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA); 846167514Skmacy lo = (u32)mac->stats.rx_cong_drops; 847167514Skmacy mac->stats.rx_cong_drops += (u64)(v - lo); 848167514Skmacy 849167514Skmacy return &mac->stats; 850167514Skmacy} 851