2007-01-18 22:04:14 -05:00
/*
2008-10-13 18:47:30 -07:00
* Copyright ( c ) 2005 - 2008 Chelsio , Inc . All rights reserved .
2007-01-18 22:04:14 -05:00
*
2007-01-30 19:44:35 -08:00
* 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 :
2007-01-18 22:04:14 -05:00
*
2007-01-30 19:44:35 -08:00
* 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 .
2007-01-18 22:04:14 -05:00
*/
# 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 ) ;
2007-12-05 10:15:01 -08:00
t3_set_reg_field ( adap , A_XGM_TXFIFO_CFG + oft , 0 , F_UNDERUNFIX ) ;
2007-01-18 22:04:14 -05:00
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 ) ;
}
2007-12-05 10:15:01 -08:00
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 ;
2007-01-18 22:04:14 -05:00
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 ;
}
2007-10-08 16:22:29 -07:00
static int t3b2_mac_reset ( struct cmac * mac )
2007-03-18 13:10:12 -07:00
{
struct adapter * adap = mac - > adapter ;
2009-03-12 21:14:14 +00:00
unsigned int oft = mac - > offset , store ;
int idx = macidx ( mac ) ;
2007-03-18 13:10:12 -07:00
u32 val ;
2007-11-23 21:59:45 -05:00
if ( ! macidx ( mac ) )
2007-03-18 13:10:12 -07:00
t3_set_reg_field ( adap , A_MPS_CFG , F_PORT0ACTIVE , 0 ) ;
else
t3_set_reg_field ( adap , A_MPS_CFG , F_PORT1ACTIVE , 0 ) ;
2009-03-12 21:14:14 +00:00
/* 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 ) ;
2007-03-18 13:10:12 -07:00
t3_write_reg ( adap , A_XGM_RESET_CTRL + oft , F_MAC_RESET_ ) ;
t3_read_reg ( adap , A_XGM_RESET_CTRL + oft ) ; /* flush */
2009-03-12 21:14:14 +00:00
/* 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 ) ;
2007-03-18 13:10:12 -07:00
msleep ( 10 ) ;
2009-03-12 21:14:14 +00:00
/* 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 , 0xc0000011 ) ;
2007-03-18 13:10:12 -07:00
/* Check for xgm Rx fifo empty */
2009-03-12 21:14:14 +00:00
/* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
2007-03-18 13:10:12 -07:00
if ( t3_wait_op_done ( adap , A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft ,
2009-03-12 21:14:14 +00:00
0x80000000 , 1 , 1000 , 2 ) ) {
2007-03-18 13:10:12 -07:00
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 ) ;
}
2007-11-23 21:59:45 -05:00
t3_write_reg ( adap , A_XGM_RX_CFG + oft ,
2007-03-18 13:10:12 -07:00
F_DISPAUSEFRAMES | F_EN1536BFRAMES |
F_RMFCS | F_ENJUMBO | F_ENHASHMCAST ) ;
2009-03-12 21:14:14 +00:00
/* 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 )
2007-03-18 13:10:12 -07:00
t3_set_reg_field ( adap , A_MPS_CFG , 0 , F_PORT0ACTIVE ) ;
else
t3_set_reg_field ( adap , A_MPS_CFG , 0 , F_PORT1ACTIVE ) ;
2009-03-12 21:14:14 +00:00
/* re-enable nic traffic */
t3_set_reg_field ( adap , A_MPS_CFG , F_ENFORCEPKT , 1 ) ;
2009-03-12 21:14:19 +00:00
/* Set: re-enable NIC traffic */
t3_set_reg_field ( adap , A_MPS_CFG , F_ENFORCEPKT , 1 ) ;
2007-03-18 13:10:12 -07:00
return 0 ;
}
2007-01-18 22:04:14 -05:00
/*
* 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 , 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 ;
}
2009-03-12 21:14:19 +00:00
void t3_mac_disable_exact_filters ( struct cmac * mac )
2007-05-30 10:01:44 -07:00
{
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 */
}
2009-03-12 21:14:19 +00:00
void t3_mac_enable_exact_filters ( struct cmac * mac )
2007-05-30 10:01:44 -07:00
{
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 */
}
2007-01-18 22:04:14 -05:00
/* 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 t3_rx_mode * rm )
{
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 ( rm - > dev - > flags & IFF_PROMISC )
val | = F_COPYALLFRAMES ;
t3_write_reg ( adap , A_XGM_RX_CFG + oft , val ) ;
if ( rm - > dev - > flags & IFF_ALLMULTI )
hash_lo = hash_hi = 0xffffffff ;
else {
u8 * addr ;
int exact_addr_idx = mac - > nucast ;
hash_lo = hash_hi = 0 ;
while ( ( addr = t3_get_next_mcaddr ( rm ) ) )
if ( exact_addr_idx < EXACT_ADDR_FILTERS )
set_addr_filter ( mac , exact_addr_idx + + , addr ) ;
else {
int hash = hash_hw_addr ( 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 ;
}
2007-05-30 10:01:44 -07:00
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 ) ;
}
2007-01-18 22:04:14 -05:00
int t3_mac_set_mtu ( struct cmac * mac , unsigned int mtu )
{
2007-12-05 10:15:01 -08:00
int hwm , lwm , divisor ;
int ipg ;
unsigned int thres , v , reg ;
2007-01-18 22:04:14 -05:00
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 > MAX_FRAME_SIZE - 4 )
return - EINVAL ;
t3_write_reg ( adap , A_XGM_RX_MAX_PKT_SIZE + mac - > offset , mtu ) ;
2007-12-05 10:15:01 -08:00
if ( adap - > params . rev > = T3_REV_B2 & &
2007-05-30 10:01:44 -07:00
( t3_read_reg ( adap , A_XGM_RX_CTRL + mac - > offset ) & F_RXEN ) ) {
2009-03-12 21:14:19 +00:00
t3_mac_disable_exact_filters ( mac ) ;
2007-06-25 15:19:30 -07:00
v = t3_read_reg ( adap , A_XGM_RX_CFG + mac - > offset ) ;
t3_set_reg_field ( adap , A_XGM_RX_CFG + mac - > offset ,
2007-05-30 10:01:44 -07:00
F_ENHASHMCAST | F_COPYALLFRAMES , F_DISBCAST ) ;
2007-12-05 10:15:01 -08:00
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 ) ) {
2007-06-25 15:19:30 -07:00
t3_write_reg ( adap , A_XGM_RX_CFG + mac - > offset , v ) ;
2009-03-12 21:14:19 +00:00
t3_mac_enable_exact_filters ( mac ) ;
2007-05-30 10:01:44 -07:00
return - EIO ;
}
2007-12-05 10:15:01 -08:00
t3_set_reg_field ( adap , A_XGM_RX_MAX_PKT_SIZE + mac - > offset ,
V_RXMAXPKTSIZE ( M_RXMAXPKTSIZE ) ,
V_RXMAXPKTSIZE ( mtu ) ) ;
2007-06-25 15:19:30 -07:00
t3_write_reg ( adap , A_XGM_RX_CFG + mac - > offset , v ) ;
2009-03-12 21:14:19 +00:00
t3_mac_enable_exact_filters ( mac ) ;
2007-05-30 10:01:44 -07:00
} else
2007-12-05 10:15:01 -08:00
t3_set_reg_field ( adap , A_XGM_RX_MAX_PKT_SIZE + mac - > offset ,
V_RXMAXPKTSIZE ( M_RXMAXPKTSIZE ) ,
V_RXMAXPKTSIZE ( mtu ) ) ;
2007-05-30 10:01:44 -07:00
/*
* 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 ) ;
2007-06-25 15:19:30 -07:00
v = t3_read_reg ( adap , A_XGM_RXFIFO_CFG + mac - > offset ) ;
2007-01-18 22:04:14 -05:00
v & = ~ V_RXFIFOPAUSELWM ( M_RXFIFOPAUSELWM ) ;
v | = V_RXFIFOPAUSELWM ( lwm / 8 ) ;
if ( G_RXFIFOPAUSEHWM ( v ) )
v = ( v & ~ V_RXFIFOPAUSEHWM ( M_RXFIFOPAUSEHWM ) ) |
V_RXFIFOPAUSEHWM ( hwm / 8 ) ;
2007-05-30 10:01:44 -07:00
2007-01-18 22:04:14 -05:00
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 , 8U ) ; /* need at least 8 */
2007-12-05 10:15:01 -08:00
ipg = ( adap - > params . rev = = T3_REV_C ) ? 0 : 1 ;
2007-01-18 22:04:14 -05:00
t3_set_reg_field ( adap , A_XGM_TXFIFO_CFG + mac - > offset ,
2007-03-18 13:10:12 -07:00
V_TXFIFOTHRESH ( M_TXFIFOTHRESH ) | V_TXIPG ( M_TXIPG ) ,
2007-12-05 10:15:01 -08:00
V_TXFIFOTHRESH ( thres ) | V_TXIPG ( ipg ) ) ;
2007-03-18 13:10:12 -07:00
2007-12-05 10:15:01 -08:00
if ( adap - > params . rev > 0 ) {
divisor = ( adap - > params . rev = = T3_REV_C ) ? 64 : 8 ;
2007-03-18 13:10:12 -07:00
t3_write_reg ( adap , A_XGM_PAUSE_TIMER + mac - > offset ,
2007-12-05 10:15:01 -08:00
( hwm - lwm ) * 4 / divisor ) ;
}
2007-03-18 13:10:12 -07:00
t3_write_reg ( adap , A_XGM_TX_PAUSE_QUANTA + mac - > offset ,
MAC_RXFIFO_SIZE * 4 * 8 / 512 ) ;
2007-01-18 22:04:14 -05:00
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 ) ;
}
2007-05-30 10:01:44 -07:00
val = t3_read_reg ( adap , A_XGM_RXFIFO_CFG + oft ) ;
val & = ~ V_RXFIFOPAUSEHWM ( M_RXFIFOPAUSEHWM ) ;
2009-07-07 19:48:38 +00:00
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 ) ;
}
2007-05-30 10:01:44 -07:00
t3_write_reg ( adap , A_XGM_RXFIFO_CFG + oft , val ) ;
2007-01-18 22:04:14 -05:00
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 ;
2007-04-09 20:10:27 -07:00
struct mac_stats * s = & mac - > stats ;
2007-11-23 21:59:45 -05:00
2007-01-18 22:04:14 -05:00
if ( which & MAC_DIRECTION_TX ) {
t3_write_reg ( adap , A_TP_PIO_ADDR , A_TP_TX_DROP_CFG_CH0 + idx ) ;
2009-03-12 21:14:14 +00:00
t3_write_reg ( adap , A_TP_PIO_DATA ,
adap - > params . rev = = T3_REV_C ?
0xc4ffff01 : 0xc0ede401 ) ;
2007-01-18 22:04:14 -05:00
t3_write_reg ( adap , A_TP_PIO_ADDR , A_TP_TX_DROP_MODE ) ;
2009-03-12 21:14:14 +00:00
t3_set_reg_field ( adap , A_TP_PIO_DATA , 1 < < idx ,
adap - > params . rev = = T3_REV_C ? 0 : 1 < < idx ) ;
2007-03-18 13:10:12 -07:00
2007-08-10 23:29:33 -07:00
t3_write_reg ( adap , A_XGM_TX_CTRL + oft , F_TXEN ) ;
2007-03-18 13:10:12 -07:00
t3_write_reg ( adap , A_TP_PIO_ADDR , A_TP_TX_DROP_CNT_CH0 + idx ) ;
2007-04-09 20:10:27 -07:00
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 ;
2007-09-05 15:58:20 -07:00
mac - > rx_pause = s - > rx_pause ;
2007-04-09 20:10:27 -07:00
mac - > rx_xcnt = ( G_TXSPI4SOPCNT ( t3_read_reg ( adap ,
A_XGM_RX_SPI4_SOP_EOP_CNT +
oft ) ) ) ;
2007-08-10 23:29:33 -07:00
mac - > rx_ocnt = s - > rx_fifo_ovfl ;
2007-03-18 13:10:12 -07:00
mac - > txen = F_TXEN ;
mac - > toggle_cnt = 0 ;
2007-01-18 22:04:14 -05:00
}
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 ) ;
2007-03-18 13:10:12 -07:00
mac - > txen = 0 ;
2007-01-18 22:04:14 -05:00
}
2007-04-09 20:10:27 -07:00
if ( which & MAC_DIRECTION_RX ) {
2007-08-10 23:29:33 -07:00
int val = F_MAC_RESET_ ;
2007-04-09 20:10:27 -07:00
t3_set_reg_field ( mac - > adapter , A_XGM_RESET_CTRL + mac - > offset ,
F_PCS_RESET_ , 0 ) ;
msleep ( 100 ) ;
2007-01-18 22:04:14 -05:00
t3_write_reg ( adap , A_XGM_RX_CTRL + mac - > offset , 0 ) ;
2007-04-09 20:10:27 -07:00
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 ) ;
}
2007-01-18 22:04:14 -05:00
return 0 ;
}
2007-03-18 13:10:12 -07:00
int t3b2_mac_watchdog_task ( struct cmac * mac )
{
struct adapter * adap = mac - > adapter ;
2007-04-09 20:10:27 -07:00
struct mac_stats * s = & mac - > stats ;
unsigned int tx_tcnt , tx_xcnt ;
2009-03-12 21:14:14 +00:00
u64 tx_mcnt = s - > tx_frames ;
2007-03-18 13:10:12 -07:00
int status ;
2007-05-30 10:01:50 -07:00
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 */
2007-09-05 15:58:20 -07:00
if ( tx_mcnt = = mac - > tx_mcnt & & mac - > rx_pause = = s - > rx_pause ) {
2007-04-09 20:10:27 -07:00
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 {
2009-03-12 21:14:14 +00:00
goto out ;
2007-04-09 20:10:27 -07:00
}
} else {
mac - > toggle_cnt = 0 ;
2009-03-12 21:14:14 +00:00
goto out ;
2007-04-09 20:10:27 -07:00
}
2007-12-05 10:15:01 -08:00
if ( ( tx_tcnt ! = mac - > tx_tcnt ) & & ( mac - > tx_xcnt = = 0 ) ) {
2007-05-30 10:01:50 -07:00
if ( mac - > toggle_cnt > 4 ) {
2007-03-18 13:10:12 -07:00
status = 2 ;
2007-05-30 10:01:50 -07:00
goto out ;
} else {
2007-03-18 13:10:12 -07:00
status = 1 ;
2007-05-30 10:01:50 -07:00
goto out ;
}
2007-03-18 13:10:12 -07:00
} else {
mac - > toggle_cnt = 0 ;
2007-05-30 10:01:50 -07:00
goto out ;
}
out :
2007-04-09 20:10:27 -07:00
mac - > tx_tcnt = tx_tcnt ;
mac - > tx_xcnt = tx_xcnt ;
mac - > tx_mcnt = s - > tx_frames ;
2007-09-05 15:58:20 -07:00
mac - > rx_pause = s - > rx_pause ;
2007-04-09 20:10:27 -07:00
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 ;
}
2007-03-18 13:10:12 -07:00
return status ;
}
2007-01-18 22:04:14 -05:00
/*
* 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 ) ;
2007-03-18 13:10:12 -07:00
v = RMON_READ ( mac , A_XGM_RX_MAX_PKT_SIZE_ERR_CNT ) ;
if ( mac - > adapter - > params . rev = = T3_REV_B2 )
v & = 0x7fffffff ;
mac - > stats . rx_too_long + = v ;
2007-01-18 22:04:14 -05:00
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 ;
}