162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#include "common.h" 3362306a36Sopenharmony_ci#include "regs.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * # of exact address filters. The first one is used for the station address, 3762306a36Sopenharmony_ci * the rest are available for multicast addresses. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci#define EXACT_ADDR_FILTERS 8 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic inline int macidx(const struct cmac *mac) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void xaui_serdes_reset(struct cmac *mac) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci static const unsigned int clear[] = { 4962306a36Sopenharmony_ci F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1, 5062306a36Sopenharmony_ci F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3 5162306a36Sopenharmony_ci }; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci int i; 5462306a36Sopenharmony_ci struct adapter *adap = mac->adapter; 5562306a36Sopenharmony_ci u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] | 5862306a36Sopenharmony_ci F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 | 5962306a36Sopenharmony_ci F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 | 6062306a36Sopenharmony_ci F_RESETPLL23 | F_RESETPLL01); 6162306a36Sopenharmony_ci t3_read_reg(adap, ctrl); 6262306a36Sopenharmony_ci udelay(15); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(clear); i++) { 6562306a36Sopenharmony_ci t3_set_reg_field(adap, ctrl, clear[i], 0); 6662306a36Sopenharmony_ci udelay(15); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_civoid t3b_pcs_reset(struct cmac *mac) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 7362306a36Sopenharmony_ci F_PCS_RESET_, 0); 7462306a36Sopenharmony_ci udelay(20); 7562306a36Sopenharmony_ci t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0, 7662306a36Sopenharmony_ci F_PCS_RESET_); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciint t3_mac_reset(struct cmac *mac) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci static const struct addr_val_pair mac_reset_avp[] = { 8262306a36Sopenharmony_ci {A_XGM_TX_CTRL, 0}, 8362306a36Sopenharmony_ci {A_XGM_RX_CTRL, 0}, 8462306a36Sopenharmony_ci {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES | 8562306a36Sopenharmony_ci F_RMFCS | F_ENJUMBO | F_ENHASHMCAST}, 8662306a36Sopenharmony_ci {A_XGM_RX_HASH_LOW, 0}, 8762306a36Sopenharmony_ci {A_XGM_RX_HASH_HIGH, 0}, 8862306a36Sopenharmony_ci {A_XGM_RX_EXACT_MATCH_LOW_1, 0}, 8962306a36Sopenharmony_ci {A_XGM_RX_EXACT_MATCH_LOW_2, 0}, 9062306a36Sopenharmony_ci {A_XGM_RX_EXACT_MATCH_LOW_3, 0}, 9162306a36Sopenharmony_ci {A_XGM_RX_EXACT_MATCH_LOW_4, 0}, 9262306a36Sopenharmony_ci {A_XGM_RX_EXACT_MATCH_LOW_5, 0}, 9362306a36Sopenharmony_ci {A_XGM_RX_EXACT_MATCH_LOW_6, 0}, 9462306a36Sopenharmony_ci {A_XGM_RX_EXACT_MATCH_LOW_7, 0}, 9562306a36Sopenharmony_ci {A_XGM_RX_EXACT_MATCH_LOW_8, 0}, 9662306a36Sopenharmony_ci {A_XGM_STAT_CTRL, F_CLRSTATS} 9762306a36Sopenharmony_ci }; 9862306a36Sopenharmony_ci u32 val; 9962306a36Sopenharmony_ci struct adapter *adap = mac->adapter; 10062306a36Sopenharmony_ci unsigned int oft = mac->offset; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); 10362306a36Sopenharmony_ci t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft); 10662306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft, 10762306a36Sopenharmony_ci F_RXSTRFRWRD | F_DISERRFRAMES, 10862306a36Sopenharmony_ci uses_xaui(adap) ? 0 : F_RXSTRFRWRD); 10962306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (uses_xaui(adap)) { 11262306a36Sopenharmony_ci if (adap->params.rev == 0) { 11362306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, 11462306a36Sopenharmony_ci F_RXENABLE | F_TXENABLE); 11562306a36Sopenharmony_ci if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft, 11662306a36Sopenharmony_ci F_CMULOCK, 1, 5, 2)) { 11762306a36Sopenharmony_ci CH_ERR(adap, 11862306a36Sopenharmony_ci "MAC %d XAUI SERDES CMU lock failed\n", 11962306a36Sopenharmony_ci macidx(mac)); 12062306a36Sopenharmony_ci return -1; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, 12362306a36Sopenharmony_ci F_SERDESRESET_); 12462306a36Sopenharmony_ci } else 12562306a36Sopenharmony_ci xaui_serdes_reset(mac); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft, 12962306a36Sopenharmony_ci V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE), 13062306a36Sopenharmony_ci V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER); 13162306a36Sopenharmony_ci val = F_MAC_RESET_ | F_XGMAC_STOP_EN; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (is_10G(adap)) 13462306a36Sopenharmony_ci val |= F_PCS_RESET_; 13562306a36Sopenharmony_ci else if (uses_xaui(adap)) 13662306a36Sopenharmony_ci val |= F_PCS_RESET_ | F_XG2G_RESET_; 13762306a36Sopenharmony_ci else 13862306a36Sopenharmony_ci val |= F_RGMII_RESET_ | F_XG2G_RESET_; 13962306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); 14062306a36Sopenharmony_ci t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 14162306a36Sopenharmony_ci if ((val & F_PCS_RESET_) && adap->params.rev) { 14262306a36Sopenharmony_ci msleep(1); 14362306a36Sopenharmony_ci t3b_pcs_reset(mac); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci memset(&mac->stats, 0, sizeof(mac->stats)); 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int t3b2_mac_reset(struct cmac *mac) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct adapter *adap = mac->adapter; 15362306a36Sopenharmony_ci unsigned int oft = mac->offset, store; 15462306a36Sopenharmony_ci int idx = macidx(mac); 15562306a36Sopenharmony_ci u32 val; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (!macidx(mac)) 15862306a36Sopenharmony_ci t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); 15962306a36Sopenharmony_ci else 16062306a36Sopenharmony_ci t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Stop NIC traffic to reduce the number of TXTOGGLES */ 16362306a36Sopenharmony_ci t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0); 16462306a36Sopenharmony_ci /* Ensure TX drains */ 16562306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); 16862306a36Sopenharmony_ci t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Store A_TP_TX_DROP_CFG_CH0 */ 17162306a36Sopenharmony_ci t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 17262306a36Sopenharmony_ci store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci msleep(10); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* Change DROP_CFG to 0xc0000011 */ 17762306a36Sopenharmony_ci t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 17862306a36Sopenharmony_ci t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Check for xgm Rx fifo empty */ 18162306a36Sopenharmony_ci /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */ 18262306a36Sopenharmony_ci if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, 18362306a36Sopenharmony_ci 0x80000000, 1, 1000, 2)) { 18462306a36Sopenharmony_ci CH_ERR(adap, "MAC %d Rx fifo drain failed\n", 18562306a36Sopenharmony_ci macidx(mac)); 18662306a36Sopenharmony_ci return -1; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); 19062306a36Sopenharmony_ci t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci val = F_MAC_RESET_; 19362306a36Sopenharmony_ci if (is_10G(adap)) 19462306a36Sopenharmony_ci val |= F_PCS_RESET_; 19562306a36Sopenharmony_ci else if (uses_xaui(adap)) 19662306a36Sopenharmony_ci val |= F_PCS_RESET_ | F_XG2G_RESET_; 19762306a36Sopenharmony_ci else 19862306a36Sopenharmony_ci val |= F_RGMII_RESET_ | F_XG2G_RESET_; 19962306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); 20062306a36Sopenharmony_ci t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ 20162306a36Sopenharmony_ci if ((val & F_PCS_RESET_) && adap->params.rev) { 20262306a36Sopenharmony_ci msleep(1); 20362306a36Sopenharmony_ci t3b_pcs_reset(mac); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RX_CFG + oft, 20662306a36Sopenharmony_ci F_DISPAUSEFRAMES | F_EN1536BFRAMES | 20762306a36Sopenharmony_ci F_RMFCS | F_ENJUMBO | F_ENHASHMCAST); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* Restore the DROP_CFG */ 21062306a36Sopenharmony_ci t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 21162306a36Sopenharmony_ci t3_write_reg(adap, A_TP_PIO_DATA, store); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (!idx) 21462306a36Sopenharmony_ci t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE); 21562306a36Sopenharmony_ci else 21662306a36Sopenharmony_ci t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* re-enable nic traffic */ 21962306a36Sopenharmony_ci t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* Set: re-enable NIC traffic */ 22262306a36Sopenharmony_ci t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* 22862306a36Sopenharmony_ci * Set the exact match register 'idx' to recognize the given Ethernet address. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_cistatic void set_addr_filter(struct cmac *mac, int idx, const u8 * addr) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci u32 addr_lo, addr_hi; 23362306a36Sopenharmony_ci unsigned int oft = mac->offset + idx * 8; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; 23662306a36Sopenharmony_ci addr_hi = (addr[5] << 8) | addr[4]; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo); 23962306a36Sopenharmony_ci t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* Set one of the station's unicast MAC addresses. */ 24362306a36Sopenharmony_ciint t3_mac_set_address(struct cmac *mac, unsigned int idx, const u8 addr[6]) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci if (idx >= mac->nucast) 24662306a36Sopenharmony_ci return -EINVAL; 24762306a36Sopenharmony_ci set_addr_filter(mac, idx, addr); 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/* 25262306a36Sopenharmony_ci * Specify the number of exact address filters that should be reserved for 25362306a36Sopenharmony_ci * unicast addresses. Caller should reload the unicast and multicast addresses 25462306a36Sopenharmony_ci * after calling this. 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ciint t3_mac_set_num_ucast(struct cmac *mac, int n) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci if (n > EXACT_ADDR_FILTERS) 25962306a36Sopenharmony_ci return -EINVAL; 26062306a36Sopenharmony_ci mac->nucast = n; 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_civoid t3_mac_disable_exact_filters(struct cmac *mac) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { 26962306a36Sopenharmony_ci u32 v = t3_read_reg(mac->adapter, reg); 27062306a36Sopenharmony_ci t3_write_reg(mac->adapter, reg, v); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */ 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_civoid t3_mac_enable_exact_filters(struct cmac *mac) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { 28062306a36Sopenharmony_ci u32 v = t3_read_reg(mac->adapter, reg); 28162306a36Sopenharmony_ci t3_write_reg(mac->adapter, reg, v); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */ 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/* Calculate the RX hash filter index of an Ethernet address */ 28762306a36Sopenharmony_cistatic int hash_hw_addr(const u8 * addr) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci int hash = 0, octet, bit, i = 0, c; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci for (octet = 0; octet < 6; ++octet) 29262306a36Sopenharmony_ci for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) { 29362306a36Sopenharmony_ci hash ^= (c & 1) << i; 29462306a36Sopenharmony_ci if (++i == 6) 29562306a36Sopenharmony_ci i = 0; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci return hash; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ciint t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci u32 val, hash_lo, hash_hi; 30362306a36Sopenharmony_ci struct adapter *adap = mac->adapter; 30462306a36Sopenharmony_ci unsigned int oft = mac->offset; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES; 30762306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) 30862306a36Sopenharmony_ci val |= F_COPYALLFRAMES; 30962306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RX_CFG + oft, val); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (dev->flags & IFF_ALLMULTI) 31262306a36Sopenharmony_ci hash_lo = hash_hi = 0xffffffff; 31362306a36Sopenharmony_ci else { 31462306a36Sopenharmony_ci struct netdev_hw_addr *ha; 31562306a36Sopenharmony_ci int exact_addr_idx = mac->nucast; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci hash_lo = hash_hi = 0; 31862306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) 31962306a36Sopenharmony_ci if (exact_addr_idx < EXACT_ADDR_FILTERS) 32062306a36Sopenharmony_ci set_addr_filter(mac, exact_addr_idx++, 32162306a36Sopenharmony_ci ha->addr); 32262306a36Sopenharmony_ci else { 32362306a36Sopenharmony_ci int hash = hash_hw_addr(ha->addr); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (hash < 32) 32662306a36Sopenharmony_ci hash_lo |= (1 << hash); 32762306a36Sopenharmony_ci else 32862306a36Sopenharmony_ci hash_hi |= (1 << (hash - 32)); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); 33362306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); 33462306a36Sopenharmony_ci return 0; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic int rx_fifo_hwm(int mtu) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci int hwm; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100); 34262306a36Sopenharmony_ci return min(hwm, MAC_RXFIFO_SIZE - 8192); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ciint t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci int hwm, lwm, divisor; 34862306a36Sopenharmony_ci int ipg; 34962306a36Sopenharmony_ci unsigned int thres, v, reg; 35062306a36Sopenharmony_ci struct adapter *adap = mac->adapter; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* 35362306a36Sopenharmony_ci * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max 35462306a36Sopenharmony_ci * packet size register includes header, but not FCS. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_ci mtu += 14; 35762306a36Sopenharmony_ci if (mtu > 1536) 35862306a36Sopenharmony_ci mtu += 4; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (mtu > MAX_FRAME_SIZE - 4) 36162306a36Sopenharmony_ci return -EINVAL; 36262306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (adap->params.rev >= T3_REV_B2 && 36562306a36Sopenharmony_ci (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { 36662306a36Sopenharmony_ci t3_mac_disable_exact_filters(mac); 36762306a36Sopenharmony_ci v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset); 36862306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset, 36962306a36Sopenharmony_ci F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci reg = adap->params.rev == T3_REV_B2 ? 37262306a36Sopenharmony_ci A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* drain RX FIFO */ 37562306a36Sopenharmony_ci if (t3_wait_op_done(adap, reg + mac->offset, 37662306a36Sopenharmony_ci F_RXFIFO_EMPTY, 1, 20, 5)) { 37762306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); 37862306a36Sopenharmony_ci t3_mac_enable_exact_filters(mac); 37962306a36Sopenharmony_ci return -EIO; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, 38262306a36Sopenharmony_ci V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), 38362306a36Sopenharmony_ci V_RXMAXPKTSIZE(mtu)); 38462306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); 38562306a36Sopenharmony_ci t3_mac_enable_exact_filters(mac); 38662306a36Sopenharmony_ci } else 38762306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, 38862306a36Sopenharmony_ci V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), 38962306a36Sopenharmony_ci V_RXMAXPKTSIZE(mtu)); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* 39262306a36Sopenharmony_ci * Adjust the PAUSE frame watermarks. We always set the LWM, and the 39362306a36Sopenharmony_ci * HWM only if flow-control is enabled. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci hwm = rx_fifo_hwm(mtu); 39662306a36Sopenharmony_ci lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4); 39762306a36Sopenharmony_ci v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); 39862306a36Sopenharmony_ci v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); 39962306a36Sopenharmony_ci v |= V_RXFIFOPAUSELWM(lwm / 8); 40062306a36Sopenharmony_ci if (G_RXFIFOPAUSEHWM(v)) 40162306a36Sopenharmony_ci v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) | 40262306a36Sopenharmony_ci V_RXFIFOPAUSEHWM(hwm / 8); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Adjust the TX FIFO threshold based on the MTU */ 40762306a36Sopenharmony_ci thres = (adap->params.vpd.cclk * 1000) / 15625; 40862306a36Sopenharmony_ci thres = (thres * mtu) / 1000; 40962306a36Sopenharmony_ci if (is_10G(adap)) 41062306a36Sopenharmony_ci thres /= 10; 41162306a36Sopenharmony_ci thres = mtu > thres ? (mtu - thres + 7) / 8 : 0; 41262306a36Sopenharmony_ci thres = max(thres, 8U); /* need at least 8 */ 41362306a36Sopenharmony_ci ipg = (adap->params.rev == T3_REV_C) ? 0 : 1; 41462306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, 41562306a36Sopenharmony_ci V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG), 41662306a36Sopenharmony_ci V_TXFIFOTHRESH(thres) | V_TXIPG(ipg)); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (adap->params.rev > 0) { 41962306a36Sopenharmony_ci divisor = (adap->params.rev == T3_REV_C) ? 64 : 8; 42062306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset, 42162306a36Sopenharmony_ci (hwm - lwm) * 4 / divisor); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, 42462306a36Sopenharmony_ci MAC_RXFIFO_SIZE * 4 * 8 / 512); 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ciint t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci u32 val; 43162306a36Sopenharmony_ci struct adapter *adap = mac->adapter; 43262306a36Sopenharmony_ci unsigned int oft = mac->offset; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (duplex >= 0 && duplex != DUPLEX_FULL) 43562306a36Sopenharmony_ci return -EINVAL; 43662306a36Sopenharmony_ci if (speed >= 0) { 43762306a36Sopenharmony_ci if (speed == SPEED_10) 43862306a36Sopenharmony_ci val = V_PORTSPEED(0); 43962306a36Sopenharmony_ci else if (speed == SPEED_100) 44062306a36Sopenharmony_ci val = V_PORTSPEED(1); 44162306a36Sopenharmony_ci else if (speed == SPEED_1000) 44262306a36Sopenharmony_ci val = V_PORTSPEED(2); 44362306a36Sopenharmony_ci else if (speed == SPEED_10000) 44462306a36Sopenharmony_ci val = V_PORTSPEED(3); 44562306a36Sopenharmony_ci else 44662306a36Sopenharmony_ci return -EINVAL; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, 44962306a36Sopenharmony_ci V_PORTSPEED(M_PORTSPEED), val); 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); 45362306a36Sopenharmony_ci val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); 45462306a36Sopenharmony_ci if (fc & PAUSE_TX) { 45562306a36Sopenharmony_ci u32 rx_max_pkt_size = 45662306a36Sopenharmony_ci G_RXMAXPKTSIZE(t3_read_reg(adap, 45762306a36Sopenharmony_ci A_XGM_RX_MAX_PKT_SIZE + oft)); 45862306a36Sopenharmony_ci val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 46362306a36Sopenharmony_ci (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); 46462306a36Sopenharmony_ci return 0; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ciint t3_mac_enable(struct cmac *mac, int which) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci int idx = macidx(mac); 47062306a36Sopenharmony_ci struct adapter *adap = mac->adapter; 47162306a36Sopenharmony_ci unsigned int oft = mac->offset; 47262306a36Sopenharmony_ci struct mac_stats *s = &mac->stats; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (which & MAC_DIRECTION_TX) { 47562306a36Sopenharmony_ci t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); 47662306a36Sopenharmony_ci t3_write_reg(adap, A_TP_PIO_DATA, 47762306a36Sopenharmony_ci adap->params.rev == T3_REV_C ? 47862306a36Sopenharmony_ci 0xc4ffff01 : 0xc0ede401); 47962306a36Sopenharmony_ci t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); 48062306a36Sopenharmony_ci t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 48162306a36Sopenharmony_ci adap->params.rev == T3_REV_C ? 0 : 1 << idx); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx); 48662306a36Sopenharmony_ci mac->tx_mcnt = s->tx_frames; 48762306a36Sopenharmony_ci mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, 48862306a36Sopenharmony_ci A_TP_PIO_DATA))); 48962306a36Sopenharmony_ci mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 49062306a36Sopenharmony_ci A_XGM_TX_SPI4_SOP_EOP_CNT + 49162306a36Sopenharmony_ci oft))); 49262306a36Sopenharmony_ci mac->rx_mcnt = s->rx_frames; 49362306a36Sopenharmony_ci mac->rx_pause = s->rx_pause; 49462306a36Sopenharmony_ci mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 49562306a36Sopenharmony_ci A_XGM_RX_SPI4_SOP_EOP_CNT + 49662306a36Sopenharmony_ci oft))); 49762306a36Sopenharmony_ci mac->rx_ocnt = s->rx_fifo_ovfl; 49862306a36Sopenharmony_ci mac->txen = F_TXEN; 49962306a36Sopenharmony_ci mac->toggle_cnt = 0; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci if (which & MAC_DIRECTION_RX) 50262306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); 50362306a36Sopenharmony_ci return 0; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ciint t3_mac_disable(struct cmac *mac, int which) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct adapter *adap = mac->adapter; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (which & MAC_DIRECTION_TX) { 51162306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); 51262306a36Sopenharmony_ci mac->txen = 0; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci if (which & MAC_DIRECTION_RX) { 51562306a36Sopenharmony_ci int val = F_MAC_RESET_; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 51862306a36Sopenharmony_ci F_PCS_RESET_, 0); 51962306a36Sopenharmony_ci msleep(100); 52062306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); 52162306a36Sopenharmony_ci if (is_10G(adap)) 52262306a36Sopenharmony_ci val |= F_PCS_RESET_; 52362306a36Sopenharmony_ci else if (uses_xaui(adap)) 52462306a36Sopenharmony_ci val |= F_PCS_RESET_ | F_XG2G_RESET_; 52562306a36Sopenharmony_ci else 52662306a36Sopenharmony_ci val |= F_RGMII_RESET_ | F_XG2G_RESET_; 52762306a36Sopenharmony_ci t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val); 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ciint t3b2_mac_watchdog_task(struct cmac *mac) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct adapter *adap = mac->adapter; 53562306a36Sopenharmony_ci struct mac_stats *s = &mac->stats; 53662306a36Sopenharmony_ci unsigned int tx_tcnt, tx_xcnt; 53762306a36Sopenharmony_ci u64 tx_mcnt = s->tx_frames; 53862306a36Sopenharmony_ci int status; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci status = 0; 54162306a36Sopenharmony_ci tx_xcnt = 1; /* By default tx_xcnt is making progress */ 54262306a36Sopenharmony_ci tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt */ 54362306a36Sopenharmony_ci if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) { 54462306a36Sopenharmony_ci tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 54562306a36Sopenharmony_ci A_XGM_TX_SPI4_SOP_EOP_CNT + 54662306a36Sopenharmony_ci mac->offset))); 54762306a36Sopenharmony_ci if (tx_xcnt == 0) { 54862306a36Sopenharmony_ci t3_write_reg(adap, A_TP_PIO_ADDR, 54962306a36Sopenharmony_ci A_TP_TX_DROP_CNT_CH0 + macidx(mac)); 55062306a36Sopenharmony_ci tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, 55162306a36Sopenharmony_ci A_TP_PIO_DATA))); 55262306a36Sopenharmony_ci } else { 55362306a36Sopenharmony_ci goto out; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci } else { 55662306a36Sopenharmony_ci mac->toggle_cnt = 0; 55762306a36Sopenharmony_ci goto out; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) { 56162306a36Sopenharmony_ci if (mac->toggle_cnt > 4) { 56262306a36Sopenharmony_ci status = 2; 56362306a36Sopenharmony_ci goto out; 56462306a36Sopenharmony_ci } else { 56562306a36Sopenharmony_ci status = 1; 56662306a36Sopenharmony_ci goto out; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci } else { 56962306a36Sopenharmony_ci mac->toggle_cnt = 0; 57062306a36Sopenharmony_ci goto out; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ciout: 57462306a36Sopenharmony_ci mac->tx_tcnt = tx_tcnt; 57562306a36Sopenharmony_ci mac->tx_xcnt = tx_xcnt; 57662306a36Sopenharmony_ci mac->tx_mcnt = s->tx_frames; 57762306a36Sopenharmony_ci mac->rx_pause = s->rx_pause; 57862306a36Sopenharmony_ci if (status == 1) { 57962306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); 58062306a36Sopenharmony_ci t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ 58162306a36Sopenharmony_ci t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen); 58262306a36Sopenharmony_ci t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ 58362306a36Sopenharmony_ci mac->toggle_cnt++; 58462306a36Sopenharmony_ci } else if (status == 2) { 58562306a36Sopenharmony_ci t3b2_mac_reset(mac); 58662306a36Sopenharmony_ci mac->toggle_cnt = 0; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci return status; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci/* 59262306a36Sopenharmony_ci * This function is called periodically to accumulate the current values of the 59362306a36Sopenharmony_ci * RMON counters into the port statistics. Since the packet counters are only 59462306a36Sopenharmony_ci * 32 bits they can overflow in ~286 secs at 10G, so the function should be 59562306a36Sopenharmony_ci * called more frequently than that. The byte counters are 45-bit wide, they 59662306a36Sopenharmony_ci * would overflow in ~7.8 hours. 59762306a36Sopenharmony_ci */ 59862306a36Sopenharmony_ciconst struct mac_stats *t3_mac_update_stats(struct cmac *mac) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset) 60162306a36Sopenharmony_ci#define RMON_UPDATE(mac, name, reg) \ 60262306a36Sopenharmony_ci (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg) 60362306a36Sopenharmony_ci#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \ 60462306a36Sopenharmony_ci (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \ 60562306a36Sopenharmony_ci ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32) 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci u32 v, lo; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH); 61062306a36Sopenharmony_ci RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH); 61162306a36Sopenharmony_ci RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES); 61262306a36Sopenharmony_ci RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES); 61362306a36Sopenharmony_ci RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES); 61462306a36Sopenharmony_ci RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES); 61562306a36Sopenharmony_ci RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES); 61662306a36Sopenharmony_ci RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES); 61762306a36Sopenharmony_ci RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); 62262306a36Sopenharmony_ci if (mac->adapter->params.rev == T3_REV_B2) 62362306a36Sopenharmony_ci v &= 0x7fffffff; 62462306a36Sopenharmony_ci mac->stats.rx_too_long += v; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES); 62762306a36Sopenharmony_ci RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES); 62862306a36Sopenharmony_ci RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES); 62962306a36Sopenharmony_ci RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES); 63062306a36Sopenharmony_ci RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES); 63162306a36Sopenharmony_ci RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES); 63262306a36Sopenharmony_ci RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH); 63562306a36Sopenharmony_ci RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH); 63662306a36Sopenharmony_ci RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST); 63762306a36Sopenharmony_ci RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST); 63862306a36Sopenharmony_ci RMON_UPDATE(mac, tx_pause, TX_PAUSE); 63962306a36Sopenharmony_ci /* This counts error frames in general (bad FCS, underrun, etc). */ 64062306a36Sopenharmony_ci RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES); 64362306a36Sopenharmony_ci RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES); 64462306a36Sopenharmony_ci RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES); 64562306a36Sopenharmony_ci RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES); 64662306a36Sopenharmony_ci RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES); 64762306a36Sopenharmony_ci RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES); 64862306a36Sopenharmony_ci RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* The next stat isn't clear-on-read. */ 65162306a36Sopenharmony_ci t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50); 65262306a36Sopenharmony_ci v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA); 65362306a36Sopenharmony_ci lo = (u32) mac->stats.rx_cong_drops; 65462306a36Sopenharmony_ci mac->stats.rx_cong_drops += (u64) (v - lo); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci return &mac->stats; 65762306a36Sopenharmony_ci} 658