cxgb_xgmac.c revision 199239
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: head/sys/dev/cxgb/common/cxgb_xgmac.c 199239 2009-11-13 00:34:28Z np $"); 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); 100167514Skmacy udelay(20); 101167514Skmacy t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0, 102167514Skmacy F_PCS_RESET_); 103167514Skmacy} 104167514Skmacy 105176472Skmacy/** 106197791Snp * t3_mac_init - initialize a MAC 107197791Snp * @mac: the MAC to initialize 108176472Skmacy * 109197791Snp * Initialize the given MAC. 110176472Skmacy */ 111197791Snpint t3_mac_init(struct cmac *mac) 112167514Skmacy{ 113167514Skmacy static struct addr_val_pair mac_reset_avp[] = { 114167514Skmacy { A_XGM_TX_CTRL, 0 }, 115167514Skmacy { A_XGM_RX_CTRL, 0 }, 116167514Skmacy { A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES | 117167514Skmacy F_RMFCS | F_ENJUMBO | F_ENHASHMCAST }, 118167514Skmacy { A_XGM_RX_HASH_LOW, 0 }, 119167514Skmacy { A_XGM_RX_HASH_HIGH, 0 }, 120167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_1, 0 }, 121167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_2, 0 }, 122167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_3, 0 }, 123167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_4, 0 }, 124167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_5, 0 }, 125167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_6, 0 }, 126167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_7, 0 }, 127167514Skmacy { A_XGM_RX_EXACT_MATCH_LOW_8, 0 }, 128167514Skmacy { A_XGM_STAT_CTRL, F_CLRSTATS } 129167514Skmacy }; 130167514Skmacy u32 val; 131167514Skmacy adapter_t *adap = mac->adapter; 132167514Skmacy unsigned int oft = mac->offset; 133167514Skmacy 134167514Skmacy t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); 135167514Skmacy (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 136167514Skmacy 137167514Skmacy t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft); 138167514Skmacy t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft, 139167514Skmacy F_RXSTRFRWRD | F_DISERRFRAMES, 140167514Skmacy uses_xaui(adap) ? 0 : F_RXSTRFRWRD); 141176472Skmacy t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX); 142167514Skmacy 143167514Skmacy if (uses_xaui(adap)) { 144167514Skmacy if (adap->params.rev == 0) { 145167514Skmacy t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, 146167514Skmacy F_RXENABLE | F_TXENABLE); 147167514Skmacy if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft, 148167514Skmacy F_CMULOCK, 1, 5, 2)) { 149167514Skmacy CH_ERR(adap, 150167514Skmacy "MAC %d XAUI SERDES CMU lock failed\n", 151167514Skmacy macidx(mac)); 152167514Skmacy return -1; 153167514Skmacy } 154167514Skmacy t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, 155167514Skmacy F_SERDESRESET_); 156167514Skmacy } else 157167514Skmacy xaui_serdes_reset(mac); 158167514Skmacy } 159167514Skmacy 160170654Skmacy 161170654Skmacy if (mac->multiport) { 162170654Skmacy t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft, 163197791Snp V_RXMAXPKTSIZE(MAX_FRAME_SIZE - 4)); 164170654Skmacy t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, 165170654Skmacy F_DISPREAMBLE); 166170654Skmacy t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE | 167170654Skmacy F_ENNON802_3PREAMBLE); 168170654Skmacy t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 169170654Skmacy V_TXFIFOTHRESH(M_TXFIFOTHRESH), 170170654Skmacy V_TXFIFOTHRESH(64)); 171170654Skmacy t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); 172170654Skmacy t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); 173170654Skmacy } 174180583Skmacy 175176472Skmacy t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft, 176176472Skmacy V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE), 177176472Skmacy V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER); 178180583Skmacy 179197791Snp val = xgm_reset_ctrl(mac); 180167514Skmacy t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); 181167514Skmacy (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 182167514Skmacy if ((val & F_PCS_RESET_) && adap->params.rev) { 183171471Skmacy msleep(1); 184167514Skmacy t3b_pcs_reset(mac); 185167514Skmacy } 186167514Skmacy 187167514Skmacy memset(&mac->stats, 0, sizeof(mac->stats)); 188167514Skmacy return 0; 189167514Skmacy} 190167514Skmacy 191197791Snpstatic int t3_mac_reset(struct cmac *mac, int portspeed) 192167746Skmacy{ 193197791Snp u32 val, store_mps; 194167746Skmacy adapter_t *adap = mac->adapter; 195167746Skmacy unsigned int oft = mac->offset; 196181614Skmacy int idx = macidx(mac); 197181614Skmacy unsigned int store; 198167746Skmacy 199167746Skmacy /* Stop egress traffic to xgm*/ 200197791Snp store_mps = t3_read_reg(adap, A_MPS_CFG); 201197791Snp if (!idx) 202180583Skmacy t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); 203167746Skmacy else 204180583Skmacy t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); 205167746Skmacy 206189643Sgnn /* This will reduce the number of TXTOGGLES */ 207189643Sgnn /* Clear: to stop the NIC traffic */ 208189643Sgnn t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0); 209189643Sgnn /* Ensure TX drains */ 210189643Sgnn t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0); 211189643Sgnn 212167746Skmacy /* PCS in reset */ 213167746Skmacy t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); 214167746Skmacy (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 215167746Skmacy 216181614Skmacy /* Store A_TP_TX_DROP_CFG_CH0 */ 217181614Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 218197791Snp store = t3_read_reg(adap, A_TP_PIO_DATA); 219181614Skmacy 220171471Skmacy msleep(10); 221167746Skmacy 222181614Skmacy /* Change DROP_CFG to 0xc0000011 */ 223181614Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 224181614Skmacy t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011); 225181614Skmacy 226167746Skmacy /* Check for xgm Rx fifo empty */ 227181614Skmacy /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */ 228167746Skmacy if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, 229197791Snp 0x80000000, 1, 1000, 2) && portspeed < 0) { 230197791Snp CH_ERR(adap, "MAC %d Rx fifo drain failed\n", idx); 231167746Skmacy return -1; 232167746Skmacy } 233167746Skmacy 234197791Snp if (portspeed >= 0) { 235197791Snp u32 intr = t3_read_reg(adap, A_XGM_INT_ENABLE + oft); 236167746Skmacy 237197791Snp /* 238197791Snp * safespeedchange: wipes out pretty much all XGMAC registers. 239197791Snp */ 240197791Snp 241197791Snp t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, 242197791Snp V_PORTSPEED(M_PORTSPEED) | F_SAFESPEEDCHANGE, 243197791Snp portspeed | F_SAFESPEEDCHANGE); 244197791Snp (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); 245197791Snp t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, 246197791Snp F_SAFESPEEDCHANGE, 0); 247197791Snp (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); 248197791Snp t3_mac_init(mac); 249197791Snp 250197791Snp t3_write_reg(adap, A_XGM_INT_ENABLE + oft, intr); 251197791Snp } else { 252197791Snp 253197791Snp t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/ 254197791Snp (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 255197791Snp 256197791Snp val = xgm_reset_ctrl(mac); 257197791Snp t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); 258197791Snp (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 259197791Snp if ((val & F_PCS_RESET_) && adap->params.rev) { 260197791Snp msleep(1); 261197791Snp t3b_pcs_reset(mac); 262197791Snp } 263197791Snp t3_write_reg(adap, A_XGM_RX_CFG + oft, 264197791Snp F_DISPAUSEFRAMES | F_EN1536BFRAMES | 265197791Snp F_RMFCS | F_ENJUMBO | F_ENHASHMCAST ); 266167746Skmacy } 267167746Skmacy 268181614Skmacy /* Restore the DROP_CFG */ 269181614Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 270181614Skmacy t3_write_reg(adap, A_TP_PIO_DATA, store); 271181614Skmacy 272181614Skmacy /* Resume egress traffic to xgm */ 273197791Snp t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE, 274197791Snp store_mps); 275167746Skmacy 276189643Sgnn /* Set: re-enable NIC traffic */ 277197791Snp t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, F_ENFORCEPKT); 278189643Sgnn 279167746Skmacy return 0; 280167746Skmacy} 281167746Skmacy 282167514Skmacy/* 283167514Skmacy * Set the exact match register 'idx' to recognize the given Ethernet address. 284167514Skmacy */ 285167514Skmacystatic void set_addr_filter(struct cmac *mac, int idx, const u8 *addr) 286167514Skmacy{ 287167514Skmacy u32 addr_lo, addr_hi; 288167514Skmacy unsigned int oft = mac->offset + idx * 8; 289167514Skmacy 290167514Skmacy addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; 291167514Skmacy addr_hi = (addr[5] << 8) | addr[4]; 292167514Skmacy 293167514Skmacy t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo); 294167514Skmacy t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi); 295167514Skmacy} 296167514Skmacy 297176472Skmacy/** 298176472Skmacy * t3_mac_set_address - set one of the station's unicast MAC addresses 299176472Skmacy * @mac: the MAC handle 300176472Skmacy * @idx: index of the exact address match filter to use 301176472Skmacy * @addr: the Ethernet address 302176472Skmacy * 303176472Skmacy * Set one of the station's unicast MAC addresses. 304176472Skmacy */ 305167514Skmacyint t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]) 306167514Skmacy{ 307170654Skmacy if (mac->multiport) 308170654Skmacy idx = mac->ext_port + idx * mac->adapter->params.nports; 309167514Skmacy if (idx >= mac->nucast) 310167514Skmacy return -EINVAL; 311167514Skmacy set_addr_filter(mac, idx, addr); 312170654Skmacy if (mac->multiport && idx < mac->adapter->params.nports) 313170654Skmacy t3_vsc7323_set_addr(mac->adapter, addr, idx); 314167514Skmacy return 0; 315167514Skmacy} 316167514Skmacy 317176472Skmacy/** 318176472Skmacy * t3_mac_set_num_ucast - set the number of unicast addresses needed 319176472Skmacy * @mac: the MAC handle 320176472Skmacy * @n: number of unicast addresses needed 321176472Skmacy * 322176472Skmacy * Specify the number of exact address filters that should be reserved for 323176472Skmacy * unicast addresses. Caller should reload the unicast and multicast 324176472Skmacy * addresses after calling this. 325180583Skmacy * 326180583Skmacy * Generally, this is 1 with the first one used for the station address, 327180583Skmacy * and the rest are available for multicast addresses. 328167514Skmacy */ 329170654Skmacyint t3_mac_set_num_ucast(struct cmac *mac, unsigned char n) 330167514Skmacy{ 331167514Skmacy if (n > EXACT_ADDR_FILTERS) 332167514Skmacy return -EINVAL; 333167514Skmacy mac->nucast = n; 334167514Skmacy return 0; 335167514Skmacy} 336167514Skmacy 337189643Sgnnvoid t3_mac_disable_exact_filters(struct cmac *mac) 338170654Skmacy{ 339170654Skmacy unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1; 340170654Skmacy 341170654Skmacy for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { 342170654Skmacy u32 v = t3_read_reg(mac->adapter, reg); 343170654Skmacy t3_write_reg(mac->adapter, reg, v); 344170654Skmacy } 345170654Skmacy t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */ 346170654Skmacy} 347170654Skmacy 348189643Sgnnvoid t3_mac_enable_exact_filters(struct cmac *mac) 349170654Skmacy{ 350170654Skmacy unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1; 351170654Skmacy 352170654Skmacy for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { 353170654Skmacy u32 v = t3_read_reg(mac->adapter, reg); 354170654Skmacy t3_write_reg(mac->adapter, reg, v); 355170654Skmacy } 356170654Skmacy t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */ 357170654Skmacy} 358170654Skmacy 359167514Skmacy/* Calculate the RX hash filter index of an Ethernet address */ 360167514Skmacystatic int hash_hw_addr(const u8 *addr) 361167514Skmacy{ 362167514Skmacy int hash = 0, octet, bit, i = 0, c; 363167514Skmacy 364167514Skmacy for (octet = 0; octet < 6; ++octet) 365167514Skmacy for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) { 366167514Skmacy hash ^= (c & 1) << i; 367167514Skmacy if (++i == 6) 368167514Skmacy i = 0; 369167514Skmacy } 370167514Skmacy return hash; 371167514Skmacy} 372167514Skmacy 373176472Skmacy/** 374176472Skmacy * t3_mac_set_rx_mode - set the Rx mode and address filters 375176472Skmacy * @mac: the MAC to configure 376176472Skmacy * @rm: structure containing the Rx mode and MAC addresses needed 377176472Skmacy * 378176472Skmacy * Configures the MAC Rx mode (promiscuity, etc) and exact and hash 379176472Skmacy * address filters. 380176472Skmacy */ 381167514Skmacyint t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm) 382167514Skmacy{ 383170654Skmacy u32 hash_lo, hash_hi; 384167514Skmacy adapter_t *adap = mac->adapter; 385167514Skmacy unsigned int oft = mac->offset; 386167514Skmacy 387167514Skmacy if (promisc_rx_mode(rm)) 388170654Skmacy mac->promisc_map |= 1 << mac->ext_port; 389170654Skmacy else 390170654Skmacy mac->promisc_map &= ~(1 << mac->ext_port); 391170654Skmacy t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES, 392170654Skmacy mac->promisc_map ? F_COPYALLFRAMES : 0); 393167514Skmacy 394170654Skmacy if (allmulti_rx_mode(rm) || mac->multiport) 395167514Skmacy hash_lo = hash_hi = 0xffffffff; 396167514Skmacy else { 397167514Skmacy u8 *addr; 398167514Skmacy int exact_addr_idx = mac->nucast; 399167514Skmacy 400167514Skmacy hash_lo = hash_hi = 0; 401167514Skmacy while ((addr = t3_get_next_mcaddr(rm))) 402167514Skmacy if (exact_addr_idx < EXACT_ADDR_FILTERS) 403167514Skmacy set_addr_filter(mac, exact_addr_idx++, addr); 404167514Skmacy else { 405167514Skmacy int hash = hash_hw_addr(addr); 406167514Skmacy 407167514Skmacy if (hash < 32) 408167514Skmacy hash_lo |= (1 << hash); 409167514Skmacy else 410167514Skmacy hash_hi |= (1 << (hash - 32)); 411167514Skmacy } 412167514Skmacy } 413167514Skmacy 414167514Skmacy t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); 415167514Skmacy t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); 416167514Skmacy return 0; 417167514Skmacy} 418167514Skmacy 419170654Skmacystatic int rx_fifo_hwm(int mtu) 420167514Skmacy{ 421170654Skmacy int hwm; 422170654Skmacy 423170654Skmacy hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100); 424170654Skmacy return min(hwm, MAC_RXFIFO_SIZE - 8192); 425170654Skmacy} 426170654Skmacy 427176472Skmacy/** 428176472Skmacy * t3_mac_set_mtu - set the MAC MTU 429176472Skmacy * @mac: the MAC to configure 430176472Skmacy * @mtu: the MTU 431176472Skmacy * 432176472Skmacy * Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly. 433176472Skmacy */ 434180583Skmacyint t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) 435170654Skmacy{ 436176472Skmacy int hwm, lwm, divisor; 437176472Skmacy int ipg; 438176472Skmacy unsigned int thres, v, reg; 439167514Skmacy adapter_t *adap = mac->adapter; 440197791Snp unsigned port_type = adap->params.vpd.port_type[macidx(mac)]; 441197791Snp unsigned int orig_mtu=mtu; 442167514Skmacy 443167514Skmacy /* 444167514Skmacy * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max 445167514Skmacy * packet size register includes header, but not FCS. 446167514Skmacy */ 447167514Skmacy mtu += 14; 448170654Skmacy if (mac->multiport) 449170654Skmacy mtu += 8; /* for preamble */ 450167514Skmacy if (mtu > MAX_FRAME_SIZE - 4) 451167514Skmacy return -EINVAL; 452170654Skmacy if (mac->multiport) 453170654Skmacy return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port); 454167514Skmacy 455197791Snp /* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */ 456197791Snp if (port_type == 2) { 457197791Snp int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac)); 458197791Snp 459197791Snp if (err) 460197791Snp return err; 461197791Snp } 462197791Snp 463176472Skmacy if (adap->params.rev >= T3_REV_B2 && 464170654Skmacy (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { 465189643Sgnn t3_mac_disable_exact_filters(mac); 466170654Skmacy v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset); 467170654Skmacy t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset, 468170654Skmacy F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST); 469170654Skmacy 470176472Skmacy reg = adap->params.rev == T3_REV_B2 ? 471176472Skmacy A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG; 472180583Skmacy 473176472Skmacy /* drain RX FIFO */ 474176472Skmacy if (t3_wait_op_done(adap, reg + mac->offset, 475176472Skmacy F_RXFIFO_EMPTY, 1, 20, 5)) { 476170654Skmacy t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); 477189643Sgnn t3_mac_enable_exact_filters(mac); 478170654Skmacy return -EIO; 479170654Skmacy } 480176472Skmacy t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, 481176472Skmacy V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), 482176472Skmacy V_RXMAXPKTSIZE(mtu)); 483170654Skmacy t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); 484189643Sgnn t3_mac_enable_exact_filters(mac); 485170654Skmacy } else 486176472Skmacy t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, 487180583Skmacy V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), 488180583Skmacy V_RXMAXPKTSIZE(mtu)); 489167514Skmacy /* 490167514Skmacy * Adjust the PAUSE frame watermarks. We always set the LWM, and the 491167514Skmacy * HWM only if flow-control is enabled. 492167514Skmacy */ 493170654Skmacy hwm = rx_fifo_hwm(mtu); 494167746Skmacy lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4); 495167514Skmacy v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); 496167514Skmacy v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); 497167514Skmacy v |= V_RXFIFOPAUSELWM(lwm / 8); 498167514Skmacy if (G_RXFIFOPAUSEHWM(v)) 499167514Skmacy v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) | 500167514Skmacy V_RXFIFOPAUSEHWM(hwm / 8); 501170654Skmacy 502167514Skmacy t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v); 503167514Skmacy 504167514Skmacy /* Adjust the TX FIFO threshold based on the MTU */ 505167514Skmacy thres = (adap->params.vpd.cclk * 1000) / 15625; 506167514Skmacy thres = (thres * mtu) / 1000; 507167514Skmacy if (is_10G(adap)) 508167514Skmacy thres /= 10; 509167514Skmacy thres = mtu > thres ? (mtu - thres + 7) / 8 : 0; 510167514Skmacy thres = max(thres, 8U); /* need at least 8 */ 511199239Snp ipg = (port_type == 9 || adap->params.rev != T3_REV_C) ? 1 : 0; 512167514Skmacy t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, 513169978Skmacy V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG), 514176472Skmacy V_TXFIFOTHRESH(thres) | V_TXIPG(ipg)); 515167746Skmacy 516167746Skmacy /* Assuming a minimum drain rate of 2.5Gbps... 517167746Skmacy */ 518176472Skmacy if (adap->params.rev > 0) { 519176472Skmacy divisor = (adap->params.rev == T3_REV_C) ? 64 : 8; 520180583Skmacy t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset, 521180583Skmacy (hwm - lwm) * 4 / divisor); 522176472Skmacy } 523180583Skmacy t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, 524167746Skmacy MAC_RXFIFO_SIZE * 4 * 8 / 512); 525167514Skmacy return 0; 526167514Skmacy} 527167514Skmacy 528176472Skmacy/** 529176472Skmacy * t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control 530176472Skmacy * @mac: the MAC to configure 531176472Skmacy * @speed: the desired speed (10/100/1000/10000) 532176472Skmacy * @duplex: the desired duplex 533176472Skmacy * @fc: desired Tx/Rx PAUSE configuration 534176472Skmacy * 535176472Skmacy * Set the MAC speed, duplex (actually only full-duplex is supported), and 536176472Skmacy * flow control. If a parameter value is negative the corresponding 537176472Skmacy * MAC setting is left at its current value. 538176472Skmacy */ 539167514Skmacyint t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) 540167514Skmacy{ 541167514Skmacy u32 val; 542167514Skmacy adapter_t *adap = mac->adapter; 543167514Skmacy unsigned int oft = mac->offset; 544167514Skmacy 545167514Skmacy if (duplex >= 0 && duplex != DUPLEX_FULL) 546167514Skmacy return -EINVAL; 547180583Skmacy if (mac->multiport) { 548197791Snp u32 rx_max_pkt_size = 549197791Snp G_RXMAXPKTSIZE(t3_read_reg(adap, 550197791Snp A_XGM_RX_MAX_PKT_SIZE + oft)); 551171471Skmacy val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); 552171471Skmacy val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); 553197791Snp val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); 554171471Skmacy t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); 555171471Skmacy 556171471Skmacy t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 557171471Skmacy F_TXPAUSEEN); 558170654Skmacy return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port); 559171471Skmacy } 560167514Skmacy if (speed >= 0) { 561167514Skmacy if (speed == SPEED_10) 562167514Skmacy val = V_PORTSPEED(0); 563167514Skmacy else if (speed == SPEED_100) 564167514Skmacy val = V_PORTSPEED(1); 565167514Skmacy else if (speed == SPEED_1000) 566167514Skmacy val = V_PORTSPEED(2); 567167514Skmacy else if (speed == SPEED_10000) 568167514Skmacy val = V_PORTSPEED(3); 569167514Skmacy else 570167514Skmacy return -EINVAL; 571167514Skmacy 572197791Snp if (!uses_xaui(adap)) /* T302 */ 573197791Snp t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, 574197791Snp V_PORTSPEED(M_PORTSPEED), val); 575197791Snp else { 576197791Snp u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft); 577197791Snp 578197791Snp if ((old & V_PORTSPEED(M_PORTSPEED)) != val) { 579197791Snp t3_mac_reset(mac, val); 580197791Snp mac->was_reset = 1; 581197791Snp } 582197791Snp } 583167514Skmacy } 584170654Skmacy 585167514Skmacy val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); 586167514Skmacy val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); 587197791Snp if (fc & PAUSE_TX) { 588197791Snp u32 rx_max_pkt_size = 589197791Snp G_RXMAXPKTSIZE(t3_read_reg(adap, 590197791Snp A_XGM_RX_MAX_PKT_SIZE + oft)); 591197791Snp val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); 592197791Snp } 593167514Skmacy t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); 594170654Skmacy 595167514Skmacy t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 596171471Skmacy (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); 597167514Skmacy return 0; 598167514Skmacy} 599167514Skmacy 600176472Skmacy/** 601176472Skmacy * t3_mac_enable - enable the MAC in the given directions 602176472Skmacy * @mac: the MAC to configure 603176472Skmacy * @which: bitmap indicating which directions to enable 604176472Skmacy * 605176472Skmacy * Enables the MAC for operation in the given directions. 606176472Skmacy * %MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX 607176472Skmacy * enables the Rx one. 608176472Skmacy */ 609167514Skmacyint t3_mac_enable(struct cmac *mac, int which) 610167514Skmacy{ 611167514Skmacy int idx = macidx(mac); 612167514Skmacy adapter_t *adap = mac->adapter; 613167514Skmacy unsigned int oft = mac->offset; 614169978Skmacy struct mac_stats *s = &mac->stats; 615167514Skmacy 616170654Skmacy if (mac->multiport) 617170654Skmacy return t3_vsc7323_enable(adap, mac->ext_port, which); 618170654Skmacy 619167514Skmacy if (which & MAC_DIRECTION_TX) { 620167514Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 621176472Skmacy t3_write_reg(adap, A_TP_PIO_DATA, 622176472Skmacy adap->params.rev == T3_REV_C ? 623176472Skmacy 0xc4ffff01 : 0xc0ede401); 624167514Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); 625176472Skmacy t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 626176472Skmacy adap->params.rev == T3_REV_C ? 627176472Skmacy 0 : 1 << idx); 628167746Skmacy 629171471Skmacy t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); 630171471Skmacy 631167746Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx); 632169978Skmacy mac->tx_mcnt = s->tx_frames; 633169978Skmacy mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, 634169978Skmacy A_TP_PIO_DATA))); 635169978Skmacy mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 636169978Skmacy A_XGM_TX_SPI4_SOP_EOP_CNT + 637169978Skmacy oft))); 638169978Skmacy mac->rx_mcnt = s->rx_frames; 639172096Skmacy mac->rx_pause = s->rx_pause; 640169978Skmacy mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 641169978Skmacy A_XGM_RX_SPI4_SOP_EOP_CNT + 642169978Skmacy oft))); 643172096Skmacy mac->rx_ocnt = s->rx_fifo_ovfl; 644167746Skmacy mac->txen = F_TXEN; 645167746Skmacy mac->toggle_cnt = 0; 646167514Skmacy } 647180583Skmacy if (which & MAC_DIRECTION_RX) 648167514Skmacy t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); 649167514Skmacy return 0; 650167514Skmacy} 651167514Skmacy 652176472Skmacy/** 653176472Skmacy * t3_mac_disable - disable the MAC in the given directions 654176472Skmacy * @mac: the MAC to configure 655176472Skmacy * @which: bitmap indicating which directions to disable 656176472Skmacy * 657176472Skmacy * Disables the MAC in the given directions. 658176472Skmacy * %MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX 659176472Skmacy * disables the Rx one. 660176472Skmacy */ 661167514Skmacyint t3_mac_disable(struct cmac *mac, int which) 662167514Skmacy{ 663167514Skmacy adapter_t *adap = mac->adapter; 664167514Skmacy 665170654Skmacy if (mac->multiport) 666170654Skmacy return t3_vsc7323_disable(adap, mac->ext_port, which); 667170654Skmacy 668167514Skmacy if (which & MAC_DIRECTION_TX) { 669167514Skmacy t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); 670167746Skmacy mac->txen = 0; 671167514Skmacy } 672169978Skmacy if (which & MAC_DIRECTION_RX) { 673197791Snp int val = xgm_reset_ctrl(mac); 674172096Skmacy 675169978Skmacy t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 676169978Skmacy F_PCS_RESET_, 0); 677171471Skmacy msleep(100); 678167514Skmacy t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); 679169978Skmacy t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val); 680169978Skmacy } 681167514Skmacy return 0; 682167514Skmacy} 683167514Skmacy 684167746Skmacyint t3b2_mac_watchdog_task(struct cmac *mac) 685167746Skmacy{ 686167746Skmacy int status; 687169978Skmacy unsigned int tx_tcnt, tx_xcnt; 688167746Skmacy adapter_t *adap = mac->adapter; 689169978Skmacy struct mac_stats *s = &mac->stats; 690189643Sgnn u64 tx_mcnt = s->tx_frames; 691167746Skmacy 692189643Sgnn if (mac->multiport) 693189643Sgnn tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW); 694189643Sgnn 695169978Skmacy status = 0; 696169978Skmacy tx_xcnt = 1; /* By default tx_xcnt is making progress*/ 697169978Skmacy tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/ 698172096Skmacy if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) { 699197791Snp u32 cfg, active, enforcepkt; 700197791Snp 701169978Skmacy tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 702189643Sgnn A_XGM_TX_SPI4_SOP_EOP_CNT + 703189643Sgnn mac->offset))); 704197791Snp cfg = t3_read_reg(adap, A_MPS_CFG); 705197791Snp active = macidx(mac) ? cfg & F_PORT1ACTIVE : cfg & F_PORT0ACTIVE; 706197791Snp enforcepkt = cfg & F_ENFORCEPKT; 707197791Snp if (active && enforcepkt && (tx_xcnt == 0)) { 708169978Skmacy t3_write_reg(adap, A_TP_PIO_ADDR, 709169978Skmacy A_TP_TX_DROP_CNT_CH0 + macidx(mac)); 710169978Skmacy tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, 711169978Skmacy A_TP_PIO_DATA))); 712189643Sgnn } else 713185564Sgnn goto out; 714189643Sgnn 715169978Skmacy } else { 716169978Skmacy mac->toggle_cnt = 0; 717185564Sgnn goto out; 718169978Skmacy } 719169978Skmacy 720172096Skmacy if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) { 721167746Skmacy if (mac->toggle_cnt > 4) { 722167746Skmacy status = 2; 723169978Skmacy goto out; 724167746Skmacy } else { 725167746Skmacy status = 1; 726169978Skmacy goto out; 727169978Skmacy } 728167746Skmacy } else { 729167746Skmacy mac->toggle_cnt = 0; 730169978Skmacy goto out; 731169978Skmacy } 732180583Skmacy 733180583Skmacyout: 734169978Skmacy mac->tx_tcnt = tx_tcnt; 735169978Skmacy mac->tx_xcnt = tx_xcnt; 736169978Skmacy mac->tx_mcnt = s->tx_frames; 737172096Skmacy mac->rx_pause = s->rx_pause; 738169978Skmacy if (status == 1) { 739169978Skmacy t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); 740169978Skmacy t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ 741169978Skmacy t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen); 742169978Skmacy t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ 743169978Skmacy mac->toggle_cnt++; 744169978Skmacy } else if (status == 2) { 745197791Snp t3_mac_reset(mac, -1); 746169978Skmacy mac->toggle_cnt = 0; 747169978Skmacy } 748167746Skmacy return status; 749167746Skmacy} 750167746Skmacy 751176472Skmacy/** 752176472Skmacy * t3_mac_update_stats - accumulate MAC statistics 753176472Skmacy * @mac: the MAC handle 754176472Skmacy * 755176472Skmacy * This function is called periodically to accumulate the current values 756176472Skmacy * of the RMON counters into the port statistics. Since the packet 757176472Skmacy * counters are only 32 bits they can overflow in ~286 secs at 10G, so the 758176472Skmacy * function should be called more frequently than that. The byte counters 759176472Skmacy * are 45-bit wide, they would overflow in ~7.8 hours. 760167514Skmacy */ 761167514Skmacyconst struct mac_stats *t3_mac_update_stats(struct cmac *mac) 762167514Skmacy{ 763167514Skmacy#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset) 764167514Skmacy#define RMON_UPDATE(mac, name, reg) \ 765167514Skmacy (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg) 766167514Skmacy#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \ 767167514Skmacy (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \ 768167514Skmacy ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32) 769167514Skmacy 770167514Skmacy u32 v, lo; 771167514Skmacy 772171471Skmacy if (mac->multiport) 773171471Skmacy return t3_vsc7323_update_stats(mac); 774171471Skmacy 775167514Skmacy RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH); 776167514Skmacy RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH); 777167514Skmacy RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES); 778167514Skmacy RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES); 779167514Skmacy RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES); 780167514Skmacy RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES); 781167514Skmacy RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES); 782167514Skmacy RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES); 783167514Skmacy RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES); 784167514Skmacy 785167514Skmacy RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES); 786167514Skmacy 787167746Skmacy v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); 788167746Skmacy if (mac->adapter->params.rev == T3_REV_B2) 789167746Skmacy v &= 0x7fffffff; 790167746Skmacy mac->stats.rx_too_long += v; 791167746Skmacy 792167514Skmacy RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES); 793167514Skmacy RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES); 794167514Skmacy RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES); 795167514Skmacy RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES); 796167514Skmacy RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES); 797167514Skmacy RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES); 798167514Skmacy RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES); 799167514Skmacy 800167514Skmacy RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH); 801167514Skmacy RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH); 802167514Skmacy RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST); 803167514Skmacy RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST); 804167514Skmacy RMON_UPDATE(mac, tx_pause, TX_PAUSE); 805167514Skmacy /* This counts error frames in general (bad FCS, underrun, etc). */ 806167514Skmacy RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES); 807167514Skmacy 808167514Skmacy RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES); 809167514Skmacy RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES); 810167514Skmacy RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES); 811167514Skmacy RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES); 812167514Skmacy RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES); 813167514Skmacy RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES); 814167514Skmacy RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES); 815167514Skmacy 816167514Skmacy /* The next stat isn't clear-on-read. */ 817167514Skmacy t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50); 818167514Skmacy v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA); 819167514Skmacy lo = (u32)mac->stats.rx_cong_drops; 820167514Skmacy mac->stats.rx_cong_drops += (u64)(v - lo); 821167514Skmacy 822167514Skmacy return &mac->stats; 823167514Skmacy} 824