/*
* Copyright ( c ) 2005 - 2008 Chelsio , Inc . All rights reserved .
*
* This software is available to you under a choice of one of two
* licenses . You may choose to be licensed under the terms of the GNU
* General Public License ( GPL ) Version 2 , available from the file
* COPYING in the main directory of this source tree , or the
* OpenIB . org BSD license below :
*
* Redistribution and use in source and binary forms , with or
* without modification , are permitted provided that the following
* conditions are met :
*
* - Redistributions of source code must retain the above
* copyright notice , this list of conditions and the following
* disclaimer .
*
* - Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the following
* disclaimer in the documentation and / or other materials
* provided with the distribution .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
#include "common.h"
#include "regs.h"
/*
* # of exact address filters . The first one is used for the station address ,
* the rest are available for multicast addresses .
*/
#define EXACT_ADDR_FILTERS 8
static inline int macidx(const struct cmac *mac)
{
return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
}
static void xaui_serdes_reset(struct cmac *mac)
{
static const unsigned int clear[] = {
F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,
F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3
};
int i;
struct adapter *adap = mac->adapter;
u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
F_RESETPLL23 | F_RESETPLL01);
t3_read_reg(adap, ctrl);
udelay(15 );
for (i = 0 ; i < ARRAY_SIZE(clear); i++) {
t3_set_reg_field(adap, ctrl, clear[i], 0 );
udelay(15 );
}
}
void t3b_pcs_reset(struct cmac *mac)
{
t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
F_PCS_RESET_, 0 );
udelay(20 );
t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0 ,
F_PCS_RESET_);
}
int t3_mac_reset(struct cmac *mac)
{
static const struct addr_val_pair mac_reset_avp[] = {
{A_XGM_TX_CTRL, 0 },
{A_XGM_RX_CTRL, 0 },
{A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
F_RMFCS | F_ENJUMBO | F_ENHASHMCAST},
{A_XGM_RX_HASH_LOW, 0 },
{A_XGM_RX_HASH_HIGH, 0 },
{A_XGM_RX_EXACT_MATCH_LOW_1, 0 },
{A_XGM_RX_EXACT_MATCH_LOW_2, 0 },
{A_XGM_RX_EXACT_MATCH_LOW_3, 0 },
{A_XGM_RX_EXACT_MATCH_LOW_4, 0 },
{A_XGM_RX_EXACT_MATCH_LOW_5, 0 },
{A_XGM_RX_EXACT_MATCH_LOW_6, 0 },
{A_XGM_RX_EXACT_MATCH_LOW_7, 0 },
{A_XGM_RX_EXACT_MATCH_LOW_8, 0 },
{A_XGM_STAT_CTRL, F_CLRSTATS}
};
u32 val;
struct adapter *adap = mac->adapter;
unsigned int oft = mac->offset;
t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
F_RXSTRFRWRD | F_DISERRFRAMES,
uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0 , F_UNDERUNFIX);
if (uses_xaui(adap)) {
if (adap->params.rev == 0 ) {
t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0 ,
F_RXENABLE | F_TXENABLE);
if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
F_CMULOCK, 1 , 5 , 2 )) {
CH_ERR(adap,
"MAC %d XAUI SERDES CMU lock failed\n" ,
macidx(mac));
return -1 ;
}
t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0 ,
F_SERDESRESET_);
} else
xaui_serdes_reset(mac);
}
t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);
val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
if (is_10G(adap))
val |= F_PCS_RESET_;
else if (uses_xaui(adap))
val |= F_PCS_RESET_ | F_XG2G_RESET_;
else
val |= F_RGMII_RESET_ | F_XG2G_RESET_;
t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
if ((val & F_PCS_RESET_) && adap->params.rev) {
msleep(1 );
t3b_pcs_reset(mac);
}
memset(&mac->stats, 0 , sizeof (mac->stats));
return 0 ;
}
static int t3b2_mac_reset(struct cmac *mac)
{
struct adapter *adap = mac->adapter;
unsigned int oft = mac->offset, store;
int idx = macidx(mac);
u32 val;
if (!macidx(mac))
t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0 );
else
t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0 );
/* Stop NIC traffic to reduce the number of TXTOGGLES */
t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0 );
/* Ensure TX drains */
t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0 );
t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
/* Store A_TP_TX_DROP_CFG_CH0 */
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx);
msleep(10 );
/* Change DROP_CFG to 0xc0000011 */
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
t3_write_reg(adap, A_TP_PIO_DATA, 0 xc0000011);
/* Check for xgm Rx fifo empty */
/* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
0 x80000000, 1 , 1000 , 2 )) {
CH_ERR(adap, "MAC %d Rx fifo drain failed\n" ,
macidx(mac));
return -1 ;
}
t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0 );
t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
val = F_MAC_RESET_;
if (is_10G(adap))
val |= F_PCS_RESET_;
else if (uses_xaui(adap))
val |= F_PCS_RESET_ | F_XG2G_RESET_;
else
val |= F_RGMII_RESET_ | F_XG2G_RESET_;
t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
if ((val & F_PCS_RESET_) && adap->params.rev) {
msleep(1 );
t3b_pcs_reset(mac);
}
t3_write_reg(adap, A_XGM_RX_CFG + oft,
F_DISPAUSEFRAMES | F_EN1536BFRAMES |
F_RMFCS | F_ENJUMBO | F_ENHASHMCAST);
/* Restore the DROP_CFG */
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
t3_write_reg(adap, A_TP_PIO_DATA, store);
if (!idx)
t3_set_reg_field(adap, A_MPS_CFG, 0 , F_PORT0ACTIVE);
else
t3_set_reg_field(adap, A_MPS_CFG, 0 , F_PORT1ACTIVE);
/* re-enable nic traffic */
t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1 );
/* Set: re-enable NIC traffic */
t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1 );
return 0 ;
}
/*
* Set the exact match register ' idx ' to recognize the given Ethernet address .
*/
static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr)
{
u32 addr_lo, addr_hi;
unsigned int oft = mac->offset + idx * 8 ;
addr_lo = (addr[3 ] << 24 ) | (addr[2 ] << 16 ) | (addr[1 ] << 8 ) | addr[0 ];
addr_hi = (addr[5 ] << 8 ) | addr[4 ];
t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
}
/* Set one of the station's unicast MAC addresses. */
int t3_mac_set_address(struct cmac *mac, unsigned int idx, const u8 addr[6 ])
{
if (idx >= mac->nucast)
return -EINVAL;
set_addr_filter(mac, idx, addr);
return 0 ;
}
/*
* Specify the number of exact address filters that should be reserved for
* unicast addresses . Caller should reload the unicast and multicast addresses
* after calling this .
*/
int t3_mac_set_num_ucast(struct cmac *mac, int n)
{
if (n > EXACT_ADDR_FILTERS)
return -EINVAL;
mac->nucast = n;
return 0 ;
}
void t3_mac_disable_exact_filters(struct cmac *mac)
{
unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
for (i = 0 ; i < EXACT_ADDR_FILTERS; i++, reg += 8 ) {
u32 v = t3_read_reg(mac->adapter, reg);
t3_write_reg(mac->adapter, reg, v);
}
t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
}
void t3_mac_enable_exact_filters(struct cmac *mac)
{
unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
for (i = 0 ; i < EXACT_ADDR_FILTERS; i++, reg += 8 ) {
u32 v = t3_read_reg(mac->adapter, reg);
t3_write_reg(mac->adapter, reg, v);
}
t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
}
/* Calculate the RX hash filter index of an Ethernet address */
static int hash_hw_addr(const u8 * addr)
{
int hash = 0 , octet, bit, i = 0 , c;
for (octet = 0 ; octet < 6 ; ++octet)
for (c = addr[octet], bit = 0 ; bit < 8 ; c >>= 1 , ++bit) {
hash ^= (c & 1 ) << i;
if (++i == 6 )
i = 0 ;
}
return hash;
}
int t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev)
{
u32 val, hash_lo, hash_hi;
struct adapter *adap = mac->adapter;
unsigned int oft = mac->offset;
val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES;
if (dev->flags & IFF_PROMISC)
val |= F_COPYALLFRAMES;
t3_write_reg(adap, A_XGM_RX_CFG + oft, val);
if (dev->flags & IFF_ALLMULTI)
hash_lo = hash_hi = 0 xffffffff;
else {
struct netdev_hw_addr *ha;
int exact_addr_idx = mac->nucast;
hash_lo = hash_hi = 0 ;
netdev_for_each_mc_addr(ha, dev)
if (exact_addr_idx < EXACT_ADDR_FILTERS)
set_addr_filter(mac, exact_addr_idx++,
ha->addr);
else {
int hash = hash_hw_addr(ha->addr);
if (hash < 32 )
hash_lo |= (1 << hash);
else
hash_hi |= (1 << (hash - 32 ));
}
}
t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
return 0 ;
}
static int rx_fifo_hwm(int mtu)
{
int hwm;
hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38 ) / 100 );
return min(hwm, MAC_RXFIFO_SIZE - 8192 );
}
int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
{
int hwm, lwm, divisor;
int ipg;
unsigned int thres, v, reg;
struct adapter *adap = mac->adapter;
/*
* MAX_FRAME_SIZE inludes header + FCS , mtu doesn ' t . The HW max
* packet size register includes header , but not FCS .
*/
mtu += 14 ;
if (mtu > 1536 )
mtu += 4 ;
if (mtu > MAX_FRAME_SIZE - 4 )
return -EINVAL;
t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
if (adap->params.rev >= T3_REV_B2 &&
(t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
t3_mac_disable_exact_filters(mac);
v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
reg = adap->params.rev == T3_REV_B2 ?
A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
/* drain RX FIFO */
if (t3_wait_op_done(adap, reg + mac->offset,
F_RXFIFO_EMPTY, 1 , 20 , 5 )) {
t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
t3_mac_enable_exact_filters(mac);
return -EIO;
}
t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
V_RXMAXPKTSIZE(mtu));
t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
t3_mac_enable_exact_filters(mac);
} else
t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
V_RXMAXPKTSIZE(mtu));
/*
* Adjust the PAUSE frame watermarks . We always set the LWM , and the
* HWM only if flow - control is enabled .
* /
hwm = rx_fifo_hwm ( mtu ) ;
lwm = min ( 3 * ( int ) mtu , MAC_RXFIFO_SIZE / 4 ) ;
v = t3_read_reg ( adap , A_XGM_RXFIFO_CFG + mac - > offset ) ;
v & = ~ V_RXFIFOPAUSELWM ( M_RXFIFOPAUSELWM ) ;
v | = V_RXFIFOPAUSELWM ( lwm / 8 ) ;
if ( G_RXFIFOPAUSEHWM ( v ) )
v = ( v & ~ V_RXFIFOPAUSEHWM ( M_RXFIFOPAUSEHWM ) ) |
V_RXFIFOPAUSEHWM ( hwm / 8 ) ;
t3_write_reg ( adap , A_XGM_RXFIFO_CFG + mac - > offset , v ) ;
/ * Adjust the TX FIFO threshold based on the MTU * /
thres = ( adap - > params . vpd . cclk * 1000 ) / 15625 ;
thres = ( thres * mtu ) / 1000 ;
if ( is_10G ( adap ) )
thres / = 10 ;
thres = mtu > thres ? ( mtu - thres + 7 ) / 8 : 0 ;
thres = max ( thres , 8 U ) ; / * need at least 8 * /
ipg = ( adap - > params . rev = = T3_REV_C ) ? 0 : 1 ;
t3_set_reg_field ( adap , A_XGM_TXFIFO_CFG + mac - > offset ,
V_TXFIFOTHRESH ( M_TXFIFOTHRESH ) | V_TXIPG ( M_TXIPG ) ,
V_TXFIFOTHRESH ( thres ) | V_TXIPG ( ipg ) ) ;
if ( adap - > params . rev > 0 ) {
divisor = ( adap - > params . rev = = T3_REV_C ) ? 64 : 8 ;
t3_write_reg ( adap , A_XGM_PAUSE_TIMER + mac - > offset ,
( hwm - lwm ) * 4 / divisor ) ;
}
t3_write_reg ( adap , A_XGM_TX_PAUSE_QUANTA + mac - > offset ,
MAC_RXFIFO_SIZE * 4 * 8 / 512 ) ;
return 0 ;
}
int t3_mac_set_speed_duplex_fc ( struct cmac * mac , int speed , int duplex , int fc )
{
u32 val ;
struct adapter * adap = mac - > adapter ;
unsigned int oft = mac - > offset ;
if ( duplex > = 0 & & duplex ! = DUPLEX_FULL )
return - EINVAL ;
if ( speed > = 0 ) {
if ( speed = = SPEED_10 )
val = V_PORTSPEED ( 0 ) ;
else if ( speed = = SPEED_100 )
val = V_PORTSPEED ( 1 ) ;
else if ( speed = = SPEED_1000 )
val = V_PORTSPEED ( 2 ) ;
else if ( speed = = SPEED_10000 )
val = V_PORTSPEED ( 3 ) ;
else
return - EINVAL ;
t3_set_reg_field ( adap , A_XGM_PORT_CFG + oft ,
V_PORTSPEED ( M_PORTSPEED ) , val ) ;
}
val = t3_read_reg ( adap , A_XGM_RXFIFO_CFG + oft ) ;
val & = ~ V_RXFIFOPAUSEHWM ( M_RXFIFOPAUSEHWM ) ;
if ( fc & PAUSE_TX ) {
u32 rx_max_pkt_size =
G_RXMAXPKTSIZE ( t3_read_reg ( adap ,
A_XGM_RX_MAX_PKT_SIZE + oft ) ) ;
val | = V_RXFIFOPAUSEHWM ( rx_fifo_hwm ( rx_max_pkt_size ) / 8 ) ;
}
t3_write_reg ( adap , A_XGM_RXFIFO_CFG + oft , val ) ;
t3_set_reg_field ( adap , A_XGM_TX_CFG + oft , F_TXPAUSEEN ,
( fc & PAUSE_RX ) ? F_TXPAUSEEN : 0 ) ;
return 0 ;
}
int t3_mac_enable ( struct cmac * mac , int which )
{
int idx = macidx ( mac ) ;
struct adapter * adap = mac - > adapter ;
unsigned int oft = mac - > offset ;
struct mac_stats * s = & mac - > stats ;
if ( which & MAC_DIRECTION_TX ) {
t3_write_reg ( adap , A_TP_PIO_ADDR , A_TP_TX_DROP_CFG_CH0 + idx ) ;
t3_write_reg ( adap , A_TP_PIO_DATA ,
adap - > params . rev = = T3_REV_C ?
0 xc4ffff01 : 0 xc0ede401 ) ;
t3_write_reg ( adap , A_TP_PIO_ADDR , A_TP_TX_DROP_MODE ) ;
t3_set_reg_field ( adap , A_TP_PIO_DATA , 1 < < idx ,
adap - > params . rev = = T3_REV_C ? 0 : 1 < < idx ) ;
t3_write_reg ( adap , A_XGM_TX_CTRL + oft , F_TXEN ) ;
t3_write_reg ( adap , A_TP_PIO_ADDR , A_TP_TX_DROP_CNT_CH0 + idx ) ;
mac - > tx_mcnt = s - > tx_frames ;
mac - > tx_tcnt = ( G_TXDROPCNTCH0RCVD ( t3_read_reg ( adap ,
A_TP_PIO_DATA ) ) ) ;
mac - > tx_xcnt = ( G_TXSPI4SOPCNT ( t3_read_reg ( adap ,
A_XGM_TX_SPI4_SOP_EOP_CNT +
oft ) ) ) ;
mac - > rx_mcnt = s - > rx_frames ;
mac - > rx_pause = s - > rx_pause ;
mac - > rx_xcnt = ( G_TXSPI4SOPCNT ( t3_read_reg ( adap ,
A_XGM_RX_SPI4_SOP_EOP_CNT +
oft ) ) ) ;
mac - > rx_ocnt = s - > rx_fifo_ovfl ;
mac - > txen = F_TXEN ;
mac - > toggle_cnt = 0 ;
}
if ( which & MAC_DIRECTION_RX )
t3_write_reg ( adap , A_XGM_RX_CTRL + oft , F_RXEN ) ;
return 0 ;
}
int t3_mac_disable ( struct cmac * mac , int which )
{
struct adapter * adap = mac - > adapter ;
if ( which & MAC_DIRECTION_TX ) {
t3_write_reg ( adap , A_XGM_TX_CTRL + mac - > offset , 0 ) ;
mac - > txen = 0 ;
}
if ( which & MAC_DIRECTION_RX ) {
int val = F_MAC_RESET_ ;
t3_set_reg_field ( mac - > adapter , A_XGM_RESET_CTRL + mac - > offset ,
F_PCS_RESET_ , 0 ) ;
msleep ( 100 ) ;
t3_write_reg ( adap , A_XGM_RX_CTRL + mac - > offset , 0 ) ;
if ( is_10G ( adap ) )
val | = F_PCS_RESET_ ;
else if ( uses_xaui ( adap ) )
val | = F_PCS_RESET_ | F_XG2G_RESET_ ;
else
val | = F_RGMII_RESET_ | F_XG2G_RESET_ ;
t3_write_reg ( mac - > adapter , A_XGM_RESET_CTRL + mac - > offset , val ) ;
}
return 0 ;
}
int t3b2_mac_watchdog_task ( struct cmac * mac )
{
struct adapter * adap = mac - > adapter ;
struct mac_stats * s = & mac - > stats ;
unsigned int tx_tcnt , tx_xcnt ;
u64 tx_mcnt = s - > tx_frames ;
int status ;
status = 0 ;
tx_xcnt = 1 ; / * By default tx_xcnt is making progress * /
tx_tcnt = mac - > tx_tcnt ; / * If tx_mcnt is progressing ignore tx_tcnt * /
if ( tx_mcnt = = mac - > tx_mcnt & & mac - > rx_pause = = s - > rx_pause ) {
tx_xcnt = ( G_TXSPI4SOPCNT ( t3_read_reg ( adap ,
A_XGM_TX_SPI4_SOP_EOP_CNT +
mac - > offset ) ) ) ;
if ( tx_xcnt = = 0 ) {
t3_write_reg ( adap , A_TP_PIO_ADDR ,
A_TP_TX_DROP_CNT_CH0 + macidx ( mac ) ) ;
tx_tcnt = ( G_TXDROPCNTCH0RCVD ( t3_read_reg ( adap ,
A_TP_PIO_DATA ) ) ) ;
} else {
goto out ;
}
} else {
mac - > toggle_cnt = 0 ;
goto out ;
}
if ( ( tx_tcnt ! = mac - > tx_tcnt ) & & ( mac - > tx_xcnt = = 0 ) ) {
if ( mac - > toggle_cnt > 4 ) {
status = 2 ;
goto out ;
} else {
status = 1 ;
goto out ;
}
} else {
mac - > toggle_cnt = 0 ;
goto out ;
}
out :
mac - > tx_tcnt = tx_tcnt ;
mac - > tx_xcnt = tx_xcnt ;
mac - > tx_mcnt = s - > tx_frames ;
mac - > rx_pause = s - > rx_pause ;
if ( status = = 1 ) {
t3_write_reg ( adap , A_XGM_TX_CTRL + mac - > offset , 0 ) ;
t3_read_reg ( adap , A_XGM_TX_CTRL + mac - > offset ) ; / * flush * /
t3_write_reg ( adap , A_XGM_TX_CTRL + mac - > offset , mac - > txen ) ;
t3_read_reg ( adap , A_XGM_TX_CTRL + mac - > offset ) ; / * flush * /
mac - > toggle_cnt + + ;
} else if ( status = = 2 ) {
t3b2_mac_reset ( mac ) ;
mac - > toggle_cnt = 0 ;
}
return status ;
}
/ *
* This function is called periodically to accumulate the current values of the
* RMON counters into the port statistics . Since the packet counters are only
* 32 bits they can overflow in ~ 286 secs at 10 G , so the function should be
* called more frequently than that . The byte counters are 45 - bit wide , they
* would overflow in ~ 7 . 8 hours .
* /
const struct mac_stats * t3_mac_update_stats ( struct cmac * mac )
{
# define RMON_READ ( mac , addr ) t3_read_reg ( mac - > adapter , addr + mac - > offset )
# define RMON_UPDATE ( mac , name , reg ) \
( mac ) - > stats . name + = ( u64 ) RMON_READ ( mac , A_XGM_STAT_ # # reg )
# define RMON_UPDATE64 ( mac , name , reg_lo , reg_hi ) \
( mac ) - > stats . name + = RMON_READ ( mac , A_XGM_STAT_ # # reg_lo ) + \
( ( u64 ) RMON_READ ( mac , A_XGM_STAT_ # # reg_hi ) < < 32 )
u32 v , lo ;
RMON_UPDATE64 ( mac , rx_octets , RX_BYTES_LOW , RX_BYTES_HIGH ) ;
RMON_UPDATE64 ( mac , rx_frames , RX_FRAMES_LOW , RX_FRAMES_HIGH ) ;
RMON_UPDATE ( mac , rx_mcast_frames , RX_MCAST_FRAMES ) ;
RMON_UPDATE ( mac , rx_bcast_frames , RX_BCAST_FRAMES ) ;
RMON_UPDATE ( mac , rx_fcs_errs , RX_CRC_ERR_FRAMES ) ;
RMON_UPDATE ( mac , rx_pause , RX_PAUSE_FRAMES ) ;
RMON_UPDATE ( mac , rx_jabber , RX_JABBER_FRAMES ) ;
RMON_UPDATE ( mac , rx_short , RX_SHORT_FRAMES ) ;
RMON_UPDATE ( mac , rx_symbol_errs , RX_SYM_CODE_ERR_FRAMES ) ;
RMON_UPDATE ( mac , rx_too_long , RX_OVERSIZE_FRAMES ) ;
v = RMON_READ ( mac , A_XGM_RX_MAX_PKT_SIZE_ERR_CNT ) ;
if ( mac - > adapter - > params . rev = = T3_REV_B2 )
v & = 0 x7fffffff ;
mac - > stats . rx_too_long + = v ;
RMON_UPDATE ( mac , rx_frames_64 , RX_64B_FRAMES ) ;
RMON_UPDATE ( mac , rx_frames_65_127 , RX_65_127B_FRAMES ) ;
RMON_UPDATE ( mac , rx_frames_128_255 , RX_128_255B_FRAMES ) ;
RMON_UPDATE ( mac , rx_frames_256_511 , RX_256_511B_FRAMES ) ;
RMON_UPDATE ( mac , rx_frames_512_1023 , RX_512_1023B_FRAMES ) ;
RMON_UPDATE ( mac , rx_frames_1024_1518 , RX_1024_1518B_FRAMES ) ;
RMON_UPDATE ( mac , rx_frames_1519_max , RX_1519_MAXB_FRAMES ) ;
RMON_UPDATE64 ( mac , tx_octets , TX_BYTE_LOW , TX_BYTE_HIGH ) ;
RMON_UPDATE64 ( mac , tx_frames , TX_FRAME_LOW , TX_FRAME_HIGH ) ;
RMON_UPDATE ( mac , tx_mcast_frames , TX_MCAST ) ;
RMON_UPDATE ( mac , tx_bcast_frames , TX_BCAST ) ;
RMON_UPDATE ( mac , tx_pause , TX_PAUSE ) ;
/ * This counts error frames in general ( bad FCS , underrun , etc ) . * /
RMON_UPDATE ( mac , tx_underrun , TX_ERR_FRAMES ) ;
RMON_UPDATE ( mac , tx_frames_64 , TX_64B_FRAMES ) ;
RMON_UPDATE ( mac , tx_frames_65_127 , TX_65_127B_FRAMES ) ;
RMON_UPDATE ( mac , tx_frames_128_255 , TX_128_255B_FRAMES ) ;
RMON_UPDATE ( mac , tx_frames_256_511 , TX_256_511B_FRAMES ) ;
RMON_UPDATE ( mac , tx_frames_512_1023 , TX_512_1023B_FRAMES ) ;
RMON_UPDATE ( mac , tx_frames_1024_1518 , TX_1024_1518B_FRAMES ) ;
RMON_UPDATE ( mac , tx_frames_1519_max , TX_1519_MAXB_FRAMES ) ;
/ * The next stat isn ' t clear - on - read . * /
t3_write_reg ( mac - > adapter , A_TP_MIB_INDEX , mac - > offset ? 51 : 50 ) ;
v = t3_read_reg ( mac - > adapter , A_TP_MIB_RDATA ) ;
lo = ( u32 ) mac - > stats . rx_cong_drops ;
mac - > stats . rx_cong_drops + = ( u64 ) ( v - lo ) ;
return & mac - > stats ;
}
Messung V0.5 in Prozent C=97 H=93 G=94
¤ Dauer der Verarbeitung: 0.4 Sekunden
(vorverarbeitet am 2026-10-12)
¤
*© Formatika GbR, Deutschland