2007-01-18 22:04:14 -05:00
/*
* This file is part of the Chelsio T3 Ethernet driver .
*
* Copyright ( C ) 2003 - 2006 Chelsio Communications . All rights reserved .
*
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the LICENSE file included in this
* release for licensing terms and conditions .
*/
# include "common.h"
# include "regs.h"
# include "sge_defs.h"
# include "firmware_exports.h"
/**
* t3_wait_op_done_val - wait until an operation is completed
* @ adapter : the adapter performing the operation
* @ reg : the register to check for completion
* @ mask : a single - bit field within @ reg that indicates completion
* @ polarity : the value of the field when the operation is completed
* @ attempts : number of check iterations
* @ delay : delay in usecs between iterations
* @ valp : where to store the value of the register at completion time
*
* Wait until an operation is completed by checking a bit in a register
* up to @ attempts times . If @ valp is not NULL the value of the register
* at the time it indicated completion is stored there . Returns 0 if the
* operation completes and - EAGAIN otherwise .
*/
int t3_wait_op_done_val ( struct adapter * adapter , int reg , u32 mask ,
int polarity , int attempts , int delay , u32 * valp )
{
while ( 1 ) {
u32 val = t3_read_reg ( adapter , reg ) ;
if ( ! ! ( val & mask ) = = polarity ) {
if ( valp )
* valp = val ;
return 0 ;
}
if ( - - attempts = = 0 )
return - EAGAIN ;
if ( delay )
udelay ( delay ) ;
}
}
/**
* t3_write_regs - write a bunch of registers
* @ adapter : the adapter to program
* @ p : an array of register address / register value pairs
* @ n : the number of address / value pairs
* @ offset : register address offset
*
* Takes an array of register address / register value pairs and writes each
* value to the corresponding register . Register addresses are adjusted
* by the supplied offset .
*/
void t3_write_regs ( struct adapter * adapter , const struct addr_val_pair * p ,
int n , unsigned int offset )
{
while ( n - - ) {
t3_write_reg ( adapter , p - > reg_addr + offset , p - > val ) ;
p + + ;
}
}
/**
* t3_set_reg_field - set a register field to a value
* @ adapter : the adapter to program
* @ addr : the register address
* @ mask : specifies the portion of the register to modify
* @ val : the new value for the register field
*
* Sets a register field specified by the supplied mask to the
* given value .
*/
void t3_set_reg_field ( struct adapter * adapter , unsigned int addr , u32 mask ,
u32 val )
{
u32 v = t3_read_reg ( adapter , addr ) & ~ mask ;
t3_write_reg ( adapter , addr , v | val ) ;
t3_read_reg ( adapter , addr ) ; /* flush */
}
/**
* t3_read_indirect - read indirectly addressed registers
* @ adap : the adapter
* @ addr_reg : register holding the indirect address
* @ data_reg : register holding the value of the indirect register
* @ vals : where the read register values are stored
* @ start_idx : index of first indirect register to read
* @ nregs : how many indirect registers to read
*
* Reads registers that are accessed indirectly through an address / data
* register pair .
*/
void t3_read_indirect ( struct adapter * adap , unsigned int addr_reg ,
unsigned int data_reg , u32 * vals , unsigned int nregs ,
unsigned int start_idx )
{
while ( nregs - - ) {
t3_write_reg ( adap , addr_reg , start_idx ) ;
* vals + + = t3_read_reg ( adap , data_reg ) ;
start_idx + + ;
}
}
/**
* t3_mc7_bd_read - read from MC7 through backdoor accesses
* @ mc7 : identifies MC7 to read from
* @ start : index of first 64 - bit word to read
* @ n : number of 64 - bit words to read
* @ buf : where to store the read result
*
* Read n 64 - bit words from MC7 starting at word start , using backdoor
* accesses .
*/
int t3_mc7_bd_read ( struct mc7 * mc7 , unsigned int start , unsigned int n ,
u64 * buf )
{
static const int shift [ ] = { 0 , 0 , 16 , 24 } ;
static const int step [ ] = { 0 , 32 , 16 , 8 } ;
unsigned int size64 = mc7 - > size / 8 ; /* # of 64-bit words */
struct adapter * adap = mc7 - > adapter ;
if ( start > = size64 | | start + n > size64 )
return - EINVAL ;
start * = ( 8 < < mc7 - > width ) ;
while ( n - - ) {
int i ;
u64 val64 = 0 ;
for ( i = ( 1 < < mc7 - > width ) - 1 ; i > = 0 ; - - i ) {
int attempts = 10 ;
u32 val ;
t3_write_reg ( adap , mc7 - > offset + A_MC7_BD_ADDR , start ) ;
t3_write_reg ( adap , mc7 - > offset + A_MC7_BD_OP , 0 ) ;
val = t3_read_reg ( adap , mc7 - > offset + A_MC7_BD_OP ) ;
while ( ( val & F_BUSY ) & & attempts - - )
val = t3_read_reg ( adap ,
mc7 - > offset + A_MC7_BD_OP ) ;
if ( val & F_BUSY )
return - EIO ;
val = t3_read_reg ( adap , mc7 - > offset + A_MC7_BD_DATA1 ) ;
if ( mc7 - > width = = 0 ) {
val64 = t3_read_reg ( adap ,
mc7 - > offset +
A_MC7_BD_DATA0 ) ;
val64 | = ( u64 ) val < < 32 ;
} else {
if ( mc7 - > width > 1 )
val > > = shift [ mc7 - > width ] ;
val64 | = ( u64 ) val < < ( step [ mc7 - > width ] * i ) ;
}
start + = 8 ;
}
* buf + + = val64 ;
}
return 0 ;
}
/*
* Initialize MI1 .
*/
static void mi1_init ( struct adapter * adap , const struct adapter_info * ai )
{
u32 clkdiv = adap - > params . vpd . cclk / ( 2 * adap - > params . vpd . mdc ) - 1 ;
u32 val = F_PREEN | V_MDIINV ( ai - > mdiinv ) | V_MDIEN ( ai - > mdien ) |
V_CLKDIV ( clkdiv ) ;
if ( ! ( ai - > caps & SUPPORTED_10000baseT_Full ) )
val | = V_ST ( 1 ) ;
t3_write_reg ( adap , A_MI1_CFG , val ) ;
}
# define MDIO_ATTEMPTS 10
/*
* MI1 read / write operations for direct - addressed PHYs .
*/
static int mi1_read ( struct adapter * adapter , int phy_addr , int mmd_addr ,
int reg_addr , unsigned int * valp )
{
int ret ;
u32 addr = V_REGADDR ( reg_addr ) | V_PHYADDR ( phy_addr ) ;
if ( mmd_addr )
return - EINVAL ;
mutex_lock ( & adapter - > mdio_lock ) ;
t3_write_reg ( adapter , A_MI1_ADDR , addr ) ;
t3_write_reg ( adapter , A_MI1_OP , V_MDI_OP ( 2 ) ) ;
ret = t3_wait_op_done ( adapter , A_MI1_OP , F_BUSY , 0 , MDIO_ATTEMPTS , 20 ) ;
if ( ! ret )
* valp = t3_read_reg ( adapter , A_MI1_DATA ) ;
mutex_unlock ( & adapter - > mdio_lock ) ;
return ret ;
}
static int mi1_write ( struct adapter * adapter , int phy_addr , int mmd_addr ,
int reg_addr , unsigned int val )
{
int ret ;
u32 addr = V_REGADDR ( reg_addr ) | V_PHYADDR ( phy_addr ) ;
if ( mmd_addr )
return - EINVAL ;
mutex_lock ( & adapter - > mdio_lock ) ;
t3_write_reg ( adapter , A_MI1_ADDR , addr ) ;
t3_write_reg ( adapter , A_MI1_DATA , val ) ;
t3_write_reg ( adapter , A_MI1_OP , V_MDI_OP ( 1 ) ) ;
ret = t3_wait_op_done ( adapter , A_MI1_OP , F_BUSY , 0 , MDIO_ATTEMPTS , 20 ) ;
mutex_unlock ( & adapter - > mdio_lock ) ;
return ret ;
}
static const struct mdio_ops mi1_mdio_ops = {
mi1_read ,
mi1_write
} ;
/*
* MI1 read / write operations for indirect - addressed PHYs .
*/
static int mi1_ext_read ( struct adapter * adapter , int phy_addr , int mmd_addr ,
int reg_addr , unsigned int * valp )
{
int ret ;
u32 addr = V_REGADDR ( mmd_addr ) | V_PHYADDR ( phy_addr ) ;
mutex_lock ( & adapter - > mdio_lock ) ;
t3_write_reg ( adapter , A_MI1_ADDR , addr ) ;
t3_write_reg ( adapter , A_MI1_DATA , reg_addr ) ;
t3_write_reg ( adapter , A_MI1_OP , V_MDI_OP ( 0 ) ) ;
ret = t3_wait_op_done ( adapter , A_MI1_OP , F_BUSY , 0 , MDIO_ATTEMPTS , 20 ) ;
if ( ! ret ) {
t3_write_reg ( adapter , A_MI1_OP , V_MDI_OP ( 3 ) ) ;
ret = t3_wait_op_done ( adapter , A_MI1_OP , F_BUSY , 0 ,
MDIO_ATTEMPTS , 20 ) ;
if ( ! ret )
* valp = t3_read_reg ( adapter , A_MI1_DATA ) ;
}
mutex_unlock ( & adapter - > mdio_lock ) ;
return ret ;
}
static int mi1_ext_write ( struct adapter * adapter , int phy_addr , int mmd_addr ,
int reg_addr , unsigned int val )
{
int ret ;
u32 addr = V_REGADDR ( mmd_addr ) | V_PHYADDR ( phy_addr ) ;
mutex_lock ( & adapter - > mdio_lock ) ;
t3_write_reg ( adapter , A_MI1_ADDR , addr ) ;
t3_write_reg ( adapter , A_MI1_DATA , reg_addr ) ;
t3_write_reg ( adapter , A_MI1_OP , V_MDI_OP ( 0 ) ) ;
ret = t3_wait_op_done ( adapter , A_MI1_OP , F_BUSY , 0 , MDIO_ATTEMPTS , 20 ) ;
if ( ! ret ) {
t3_write_reg ( adapter , A_MI1_DATA , val ) ;
t3_write_reg ( adapter , A_MI1_OP , V_MDI_OP ( 1 ) ) ;
ret = t3_wait_op_done ( adapter , A_MI1_OP , F_BUSY , 0 ,
MDIO_ATTEMPTS , 20 ) ;
}
mutex_unlock ( & adapter - > mdio_lock ) ;
return ret ;
}
static const struct mdio_ops mi1_mdio_ext_ops = {
mi1_ext_read ,
mi1_ext_write
} ;
/**
* t3_mdio_change_bits - modify the value of a PHY register
* @ phy : the PHY to operate on
* @ mmd : the device address
* @ reg : the register address
* @ clear : what part of the register value to mask off
* @ set : what part of the register value to set
*
* Changes the value of a PHY register by applying a mask to its current
* value and ORing the result with a new value .
*/
int t3_mdio_change_bits ( struct cphy * phy , int mmd , int reg , unsigned int clear ,
unsigned int set )
{
int ret ;
unsigned int val ;
ret = mdio_read ( phy , mmd , reg , & val ) ;
if ( ! ret ) {
val & = ~ clear ;
ret = mdio_write ( phy , mmd , reg , val | set ) ;
}
return ret ;
}
/**
* t3_phy_reset - reset a PHY block
* @ phy : the PHY to operate on
* @ mmd : the device address of the PHY block to reset
* @ wait : how long to wait for the reset to complete in 1 ms increments
*
* Resets a PHY block and optionally waits for the reset to complete .
* @ mmd should be 0 for 10 / 100 / 1000 PHYs and the device address to reset
* for 10 G PHYs .
*/
int t3_phy_reset ( struct cphy * phy , int mmd , int wait )
{
int err ;
unsigned int ctl ;
err = t3_mdio_change_bits ( phy , mmd , MII_BMCR , BMCR_PDOWN , BMCR_RESET ) ;
if ( err | | ! wait )
return err ;
do {
err = mdio_read ( phy , mmd , MII_BMCR , & ctl ) ;
if ( err )
return err ;
ctl & = BMCR_RESET ;
if ( ctl )
msleep ( 1 ) ;
} while ( ctl & & - - wait ) ;
return ctl ? - 1 : 0 ;
}
/**
* t3_phy_advertise - set the PHY advertisement registers for autoneg
* @ phy : the PHY to operate on
* @ advert : bitmap of capabilities the PHY should advertise
*
* Sets a 10 / 100 / 1000 PHY ' s advertisement registers to advertise the
* requested capabilities .
*/
int t3_phy_advertise ( struct cphy * phy , unsigned int advert )
{
int err ;
unsigned int val = 0 ;
err = mdio_read ( phy , 0 , MII_CTRL1000 , & val ) ;
if ( err )
return err ;
val & = ~ ( ADVERTISE_1000HALF | ADVERTISE_1000FULL ) ;
if ( advert & ADVERTISED_1000baseT_Half )
val | = ADVERTISE_1000HALF ;
if ( advert & ADVERTISED_1000baseT_Full )
val | = ADVERTISE_1000FULL ;
err = mdio_write ( phy , 0 , MII_CTRL1000 , val ) ;
if ( err )
return err ;
val = 1 ;
if ( advert & ADVERTISED_10baseT_Half )
val | = ADVERTISE_10HALF ;
if ( advert & ADVERTISED_10baseT_Full )
val | = ADVERTISE_10FULL ;
if ( advert & ADVERTISED_100baseT_Half )
val | = ADVERTISE_100HALF ;
if ( advert & ADVERTISED_100baseT_Full )
val | = ADVERTISE_100FULL ;
if ( advert & ADVERTISED_Pause )
val | = ADVERTISE_PAUSE_CAP ;
if ( advert & ADVERTISED_Asym_Pause )
val | = ADVERTISE_PAUSE_ASYM ;
return mdio_write ( phy , 0 , MII_ADVERTISE , val ) ;
}
/**
* t3_set_phy_speed_duplex - force PHY speed and duplex
* @ phy : the PHY to operate on
* @ speed : requested PHY speed
* @ duplex : requested PHY duplex
*
* Force a 10 / 100 / 1000 PHY ' s speed and duplex . This also disables
* auto - negotiation except for GigE , where auto - negotiation is mandatory .
*/
int t3_set_phy_speed_duplex ( struct cphy * phy , int speed , int duplex )
{
int err ;
unsigned int ctl ;
err = mdio_read ( phy , 0 , MII_BMCR , & ctl ) ;
if ( err )
return err ;
if ( speed > = 0 ) {
ctl & = ~ ( BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE ) ;
if ( speed = = SPEED_100 )
ctl | = BMCR_SPEED100 ;
else if ( speed = = SPEED_1000 )
ctl | = BMCR_SPEED1000 ;
}
if ( duplex > = 0 ) {
ctl & = ~ ( BMCR_FULLDPLX | BMCR_ANENABLE ) ;
if ( duplex = = DUPLEX_FULL )
ctl | = BMCR_FULLDPLX ;
}
if ( ctl & BMCR_SPEED1000 ) /* auto-negotiation required for GigE */
ctl | = BMCR_ANENABLE ;
return mdio_write ( phy , 0 , MII_BMCR , ctl ) ;
}
static const struct adapter_info t3_adap_info [ ] = {
{ 2 , 0 , 0 , 0 ,
F_GPIO2_OEN | F_GPIO4_OEN |
F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL , F_GPIO3 | F_GPIO5 ,
SUPPORTED_OFFLOAD ,
& mi1_mdio_ops , " Chelsio PE9000 " } ,
{ 2 , 0 , 0 , 0 ,
F_GPIO2_OEN | F_GPIO4_OEN |
F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL , F_GPIO3 | F_GPIO5 ,
SUPPORTED_OFFLOAD ,
& mi1_mdio_ops , " Chelsio T302 " } ,
{ 1 , 0 , 0 , 0 ,
F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL , 0 ,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD ,
& mi1_mdio_ext_ops , " Chelsio T310 " } ,
{ 2 , 0 , 0 , 0 ,
F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL , 0 ,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD ,
& mi1_mdio_ext_ops , " Chelsio T320 " } ,
} ;
/*
* Return the adapter_info structure with a given index . Out - of - range indices
* return NULL .
*/
const struct adapter_info * t3_get_adapter_info ( unsigned int id )
{
return id < ARRAY_SIZE ( t3_adap_info ) ? & t3_adap_info [ id ] : NULL ;
}
# define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \
SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII )
# define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI)
static const struct port_type_info port_types [ ] = {
{ NULL } ,
{ t3_ael1002_phy_prep , CAPS_10G | SUPPORTED_FIBRE ,
" 10GBASE-XR " } ,
{ t3_vsc8211_phy_prep , CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ ,
" 10/100/1000BASE-T " } ,
{ NULL , CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ ,
" 10/100/1000BASE-T " } ,
{ t3_xaui_direct_phy_prep , CAPS_10G | SUPPORTED_TP , " 10GBASE-CX4 " } ,
{ NULL , CAPS_10G , " 10GBASE-KX4 " } ,
{ t3_qt2045_phy_prep , CAPS_10G | SUPPORTED_TP , " 10GBASE-CX4 " } ,
{ t3_ael1006_phy_prep , CAPS_10G | SUPPORTED_FIBRE ,
" 10GBASE-SR " } ,
{ NULL , CAPS_10G | SUPPORTED_TP , " 10GBASE-CX4 " } ,
} ;
# undef CAPS_1G
# undef CAPS_10G
# define VPD_ENTRY(name, len) \
u8 name # # _kword [ 2 ] ; u8 name # # _len ; u8 name # # _data [ len ]
/*
* Partial EEPROM Vital Product Data structure . Includes only the ID and
* VPD - R sections .
*/
struct t3_vpd {
u8 id_tag ;
u8 id_len [ 2 ] ;
u8 id_data [ 16 ] ;
u8 vpdr_tag ;
u8 vpdr_len [ 2 ] ;
VPD_ENTRY ( pn , 16 ) ; /* part number */
VPD_ENTRY ( ec , 16 ) ; /* EC level */
VPD_ENTRY ( sn , 16 ) ; /* serial number */
VPD_ENTRY ( na , 12 ) ; /* MAC address base */
VPD_ENTRY ( cclk , 6 ) ; /* core clock */
VPD_ENTRY ( mclk , 6 ) ; /* mem clock */
VPD_ENTRY ( uclk , 6 ) ; /* uP clk */
VPD_ENTRY ( mdc , 6 ) ; /* MDIO clk */
VPD_ENTRY ( mt , 2 ) ; /* mem timing */
VPD_ENTRY ( xaui0cfg , 6 ) ; /* XAUI0 config */
VPD_ENTRY ( xaui1cfg , 6 ) ; /* XAUI1 config */
VPD_ENTRY ( port0 , 2 ) ; /* PHY0 complex */
VPD_ENTRY ( port1 , 2 ) ; /* PHY1 complex */
VPD_ENTRY ( port2 , 2 ) ; /* PHY2 complex */
VPD_ENTRY ( port3 , 2 ) ; /* PHY3 complex */
VPD_ENTRY ( rv , 1 ) ; /* csum */
u32 pad ; /* for multiple-of-4 sizing and alignment */
} ;
# define EEPROM_MAX_POLL 4
# define EEPROM_STAT_ADDR 0x4000
# define VPD_BASE 0xc00
/**
* t3_seeprom_read - read a VPD EEPROM location
* @ adapter : adapter to read
* @ addr : EEPROM address
* @ data : where to store the read data
*
* Read a 32 - bit word from a location in VPD EEPROM using the card ' s PCI
* VPD ROM capability . A zero is written to the flag bit when the
* addres is written to the control register . The hardware device will
* set the flag to 1 when 4 bytes have been read into the data register .
*/
int t3_seeprom_read ( struct adapter * adapter , u32 addr , u32 * data )
{
u16 val ;
int attempts = EEPROM_MAX_POLL ;
unsigned int base = adapter - > params . pci . vpd_cap_addr ;
if ( ( addr > = EEPROMSIZE & & addr ! = EEPROM_STAT_ADDR ) | | ( addr & 3 ) )
return - EINVAL ;
pci_write_config_word ( adapter - > pdev , base + PCI_VPD_ADDR , addr ) ;
do {
udelay ( 10 ) ;
pci_read_config_word ( adapter - > pdev , base + PCI_VPD_ADDR , & val ) ;
} while ( ! ( val & PCI_VPD_ADDR_F ) & & - - attempts ) ;
if ( ! ( val & PCI_VPD_ADDR_F ) ) {
CH_ERR ( adapter , " reading EEPROM address 0x%x failed \n " , addr ) ;
return - EIO ;
}
pci_read_config_dword ( adapter - > pdev , base + PCI_VPD_DATA , data ) ;
* data = le32_to_cpu ( * data ) ;
return 0 ;
}
/**
* t3_seeprom_write - write a VPD EEPROM location
* @ adapter : adapter to write
* @ addr : EEPROM address
* @ data : value to write
*
* Write a 32 - bit word to a location in VPD EEPROM using the card ' s PCI
* VPD ROM capability .
*/
int t3_seeprom_write ( struct adapter * adapter , u32 addr , u32 data )
{
u16 val ;
int attempts = EEPROM_MAX_POLL ;
unsigned int base = adapter - > params . pci . vpd_cap_addr ;
if ( ( addr > = EEPROMSIZE & & addr ! = EEPROM_STAT_ADDR ) | | ( addr & 3 ) )
return - EINVAL ;
pci_write_config_dword ( adapter - > pdev , base + PCI_VPD_DATA ,
cpu_to_le32 ( data ) ) ;
pci_write_config_word ( adapter - > pdev , base + PCI_VPD_ADDR ,
addr | PCI_VPD_ADDR_F ) ;
do {
msleep ( 1 ) ;
pci_read_config_word ( adapter - > pdev , base + PCI_VPD_ADDR , & val ) ;
} while ( ( val & PCI_VPD_ADDR_F ) & & - - attempts ) ;
if ( val & PCI_VPD_ADDR_F ) {
CH_ERR ( adapter , " write to EEPROM address 0x%x failed \n " , addr ) ;
return - EIO ;
}
return 0 ;
}
/**
* t3_seeprom_wp - enable / disable EEPROM write protection
* @ adapter : the adapter
* @ enable : 1 to enable write protection , 0 to disable it
*
* Enables or disables write protection on the serial EEPROM .
*/
int t3_seeprom_wp ( struct adapter * adapter , int enable )
{
return t3_seeprom_write ( adapter , EEPROM_STAT_ADDR , enable ? 0xc : 0 ) ;
}
/*
* Convert a character holding a hex digit to a number .
*/
static unsigned int hex2int ( unsigned char c )
{
return isdigit ( c ) ? c - ' 0 ' : toupper ( c ) - ' A ' + 10 ;
}
/**
* get_vpd_params - read VPD parameters from VPD EEPROM
* @ adapter : adapter to read
* @ p : where to store the parameters
*
* Reads card parameters stored in VPD EEPROM .
*/
static int get_vpd_params ( struct adapter * adapter , struct vpd_params * p )
{
int i , addr , ret ;
struct t3_vpd vpd ;
/*
* Card information is normally at VPD_BASE but some early cards had
* it at 0.
*/
ret = t3_seeprom_read ( adapter , VPD_BASE , ( u32 * ) & vpd ) ;
if ( ret )
return ret ;
addr = vpd . id_tag = = 0x82 ? VPD_BASE : 0 ;
for ( i = 0 ; i < sizeof ( vpd ) ; i + = 4 ) {
ret = t3_seeprom_read ( adapter , addr + i ,
( u32 * ) ( ( u8 * ) & vpd + i ) ) ;
if ( ret )
return ret ;
}
p - > cclk = simple_strtoul ( vpd . cclk_data , NULL , 10 ) ;
p - > mclk = simple_strtoul ( vpd . mclk_data , NULL , 10 ) ;
p - > uclk = simple_strtoul ( vpd . uclk_data , NULL , 10 ) ;
p - > mdc = simple_strtoul ( vpd . mdc_data , NULL , 10 ) ;
p - > mem_timing = simple_strtoul ( vpd . mt_data , NULL , 10 ) ;
/* Old eeproms didn't have port information */
if ( adapter - > params . rev = = 0 & & ! vpd . port0_data [ 0 ] ) {
p - > port_type [ 0 ] = uses_xaui ( adapter ) ? 1 : 2 ;
p - > port_type [ 1 ] = uses_xaui ( adapter ) ? 6 : 2 ;
} else {
p - > port_type [ 0 ] = hex2int ( vpd . port0_data [ 0 ] ) ;
p - > port_type [ 1 ] = hex2int ( vpd . port1_data [ 0 ] ) ;
p - > xauicfg [ 0 ] = simple_strtoul ( vpd . xaui0cfg_data , NULL , 16 ) ;
p - > xauicfg [ 1 ] = simple_strtoul ( vpd . xaui1cfg_data , NULL , 16 ) ;
}
for ( i = 0 ; i < 6 ; i + + )
p - > eth_base [ i ] = hex2int ( vpd . na_data [ 2 * i ] ) * 16 +
hex2int ( vpd . na_data [ 2 * i + 1 ] ) ;
return 0 ;
}
/* serial flash and firmware constants */
enum {
SF_ATTEMPTS = 5 , /* max retries for SF1 operations */
SF_SEC_SIZE = 64 * 1024 , /* serial flash sector size */
SF_SIZE = SF_SEC_SIZE * 8 , /* serial flash size */
/* flash command opcodes */
SF_PROG_PAGE = 2 , /* program page */
SF_WR_DISABLE = 4 , /* disable writes */
SF_RD_STATUS = 5 , /* read status register */
SF_WR_ENABLE = 6 , /* enable writes */
SF_RD_DATA_FAST = 0xb , /* read flash */
SF_ERASE_SECTOR = 0xd8 , /* erase sector */
FW_FLASH_BOOT_ADDR = 0x70000 , /* start address of FW in flash */
FW_VERS_ADDR = 0x77ffc /* flash address holding FW version */
} ;
/**
* sf1_read - read data from the serial flash
* @ adapter : the adapter
* @ byte_cnt : number of bytes to read
* @ cont : whether another operation will be chained
* @ valp : where to store the read data
*
* Reads up to 4 bytes of data from the serial flash . The location of
* the read needs to be specified prior to calling this by issuing the
* appropriate commands to the serial flash .
*/
static int sf1_read ( struct adapter * adapter , unsigned int byte_cnt , int cont ,
u32 * valp )
{
int ret ;
if ( ! byte_cnt | | byte_cnt > 4 )
return - EINVAL ;
if ( t3_read_reg ( adapter , A_SF_OP ) & F_BUSY )
return - EBUSY ;
t3_write_reg ( adapter , A_SF_OP , V_CONT ( cont ) | V_BYTECNT ( byte_cnt - 1 ) ) ;
ret = t3_wait_op_done ( adapter , A_SF_OP , F_BUSY , 0 , SF_ATTEMPTS , 10 ) ;
if ( ! ret )
* valp = t3_read_reg ( adapter , A_SF_DATA ) ;
return ret ;
}
/**
* sf1_write - write data to the serial flash
* @ adapter : the adapter
* @ byte_cnt : number of bytes to write
* @ cont : whether another operation will be chained
* @ val : value to write
*
* Writes up to 4 bytes of data to the serial flash . The location of
* the write needs to be specified prior to calling this by issuing the
* appropriate commands to the serial flash .
*/
static int sf1_write ( struct adapter * adapter , unsigned int byte_cnt , int cont ,
u32 val )
{
if ( ! byte_cnt | | byte_cnt > 4 )
return - EINVAL ;
if ( t3_read_reg ( adapter , A_SF_OP ) & F_BUSY )
return - EBUSY ;
t3_write_reg ( adapter , A_SF_DATA , val ) ;
t3_write_reg ( adapter , A_SF_OP ,
V_CONT ( cont ) | V_BYTECNT ( byte_cnt - 1 ) | V_OP ( 1 ) ) ;
return t3_wait_op_done ( adapter , A_SF_OP , F_BUSY , 0 , SF_ATTEMPTS , 10 ) ;
}
/**
* flash_wait_op - wait for a flash operation to complete
* @ adapter : the adapter
* @ attempts : max number of polls of the status register
* @ delay : delay between polls in ms
*
* Wait for a flash operation to complete by polling the status register .
*/
static int flash_wait_op ( struct adapter * adapter , int attempts , int delay )
{
int ret ;
u32 status ;
while ( 1 ) {
if ( ( ret = sf1_write ( adapter , 1 , 1 , SF_RD_STATUS ) ) ! = 0 | |
( ret = sf1_read ( adapter , 1 , 0 , & status ) ) ! = 0 )
return ret ;
if ( ! ( status & 1 ) )
return 0 ;
if ( - - attempts = = 0 )
return - EAGAIN ;
if ( delay )
msleep ( delay ) ;
}
}
/**
* t3_read_flash - read words from serial flash
* @ adapter : the adapter
* @ addr : the start address for the read
* @ nwords : how many 32 - bit words to read
* @ data : where to store the read data
* @ byte_oriented : whether to store data as bytes or as words
*
* Read the specified number of 32 - bit words from the serial flash .
* If @ byte_oriented is set the read data is stored as a byte array
* ( i . e . , big - endian ) , otherwise as 32 - bit words in the platform ' s
* natural endianess .
*/
int t3_read_flash ( struct adapter * adapter , unsigned int addr ,
unsigned int nwords , u32 * data , int byte_oriented )
{
int ret ;
if ( addr + nwords * sizeof ( u32 ) > SF_SIZE | | ( addr & 3 ) )
return - EINVAL ;
addr = swab32 ( addr ) | SF_RD_DATA_FAST ;
if ( ( ret = sf1_write ( adapter , 4 , 1 , addr ) ) ! = 0 | |
( ret = sf1_read ( adapter , 1 , 1 , data ) ) ! = 0 )
return ret ;
for ( ; nwords ; nwords - - , data + + ) {
ret = sf1_read ( adapter , 4 , nwords > 1 , data ) ;
if ( ret )
return ret ;
if ( byte_oriented )
* data = htonl ( * data ) ;
}
return 0 ;
}
/**
* t3_write_flash - write up to a page of data to the serial flash
* @ adapter : the adapter
* @ addr : the start address to write
* @ n : length of data to write
* @ data : the data to write
*
* Writes up to a page of data ( 256 bytes ) to the serial flash starting
* at the given address .
*/
static int t3_write_flash ( struct adapter * adapter , unsigned int addr ,
unsigned int n , const u8 * data )
{
int ret ;
u32 buf [ 64 ] ;
unsigned int i , c , left , val , offset = addr & 0xff ;
if ( addr + n > SF_SIZE | | offset + n > 256 )
return - EINVAL ;
val = swab32 ( addr ) | SF_PROG_PAGE ;
if ( ( ret = sf1_write ( adapter , 1 , 0 , SF_WR_ENABLE ) ) ! = 0 | |
( ret = sf1_write ( adapter , 4 , 1 , val ) ) ! = 0 )
return ret ;
for ( left = n ; left ; left - = c ) {
c = min ( left , 4U ) ;
for ( val = 0 , i = 0 ; i < c ; + + i )
val = ( val < < 8 ) + * data + + ;
ret = sf1_write ( adapter , c , c ! = left , val ) ;
if ( ret )
return ret ;
}
if ( ( ret = flash_wait_op ( adapter , 5 , 1 ) ) ! = 0 )
return ret ;
/* Read the page to verify the write succeeded */
ret = t3_read_flash ( adapter , addr & ~ 0xff , ARRAY_SIZE ( buf ) , buf , 1 ) ;
if ( ret )
return ret ;
if ( memcmp ( data - n , ( u8 * ) buf + offset , n ) )
return - EIO ;
return 0 ;
}
2007-01-30 19:43:45 -08:00
enum fw_version_type {
FW_VERSION_N3 ,
FW_VERSION_T3
} ;
2007-01-18 22:04:14 -05:00
/**
* t3_get_fw_version - read the firmware version
* @ adapter : the adapter
* @ vers : where to place the version
*
* Reads the FW version from flash .
*/
int t3_get_fw_version ( struct adapter * adapter , u32 * vers )
{
return t3_read_flash ( adapter , FW_VERS_ADDR , 1 , vers , 0 ) ;
}
/**
* t3_check_fw_version - check if the FW is compatible with this driver
* @ adapter : the adapter
*
* Checks if an adapter ' s FW is compatible with the driver . Returns 0
* if the versions are compatible , a negative error otherwise .
*/
int t3_check_fw_version ( struct adapter * adapter )
{
int ret ;
u32 vers ;
2007-01-30 19:43:45 -08:00
unsigned int type , major , minor ;
2007-01-18 22:04:14 -05:00
ret = t3_get_fw_version ( adapter , & vers ) ;
if ( ret )
return ret ;
2007-01-30 19:43:45 -08:00
type = G_FW_VERSION_TYPE ( vers ) ;
major = G_FW_VERSION_MAJOR ( vers ) ;
minor = G_FW_VERSION_MINOR ( vers ) ;
2007-01-18 22:04:14 -05:00
2007-01-30 19:43:45 -08:00
if ( type = = FW_VERSION_T3 & & major = = 3 & & minor = = 1 )
2007-01-18 22:04:14 -05:00
return 0 ;
2007-01-30 19:43:45 -08:00
CH_ERR ( adapter , " found wrong FW version(%u.%u), "
" driver needs version 3.1 \n " , major , minor ) ;
2007-01-18 22:04:14 -05:00
return - EINVAL ;
}
/**
* t3_flash_erase_sectors - erase a range of flash sectors
* @ adapter : the adapter
* @ start : the first sector to erase
* @ end : the last sector to erase
*
* Erases the sectors in the given range .
*/
static int t3_flash_erase_sectors ( struct adapter * adapter , int start , int end )
{
while ( start < = end ) {
int ret ;
if ( ( ret = sf1_write ( adapter , 1 , 0 , SF_WR_ENABLE ) ) ! = 0 | |
( ret = sf1_write ( adapter , 4 , 0 ,
SF_ERASE_SECTOR | ( start < < 8 ) ) ) ! = 0 | |
( ret = flash_wait_op ( adapter , 5 , 500 ) ) ! = 0 )
return ret ;
start + + ;
}
return 0 ;
}
/*
* t3_load_fw - download firmware
* @ adapter : the adapter
* @ fw_data : the firrware image to write
* @ size : image size
*
* Write the supplied firmware image to the card ' s serial flash .
* The FW image has the following sections : @ size - 8 bytes of code and
* data , followed by 4 bytes of FW version , followed by the 32 - bit
* 1 ' s complement checksum of the whole image .
*/
int t3_load_fw ( struct adapter * adapter , const u8 * fw_data , unsigned int size )
{
u32 csum ;
unsigned int i ;
const u32 * p = ( const u32 * ) fw_data ;
int ret , addr , fw_sector = FW_FLASH_BOOT_ADDR > > 16 ;
if ( size & 3 )
return - EINVAL ;
if ( size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR )
return - EFBIG ;
for ( csum = 0 , i = 0 ; i < size / sizeof ( csum ) ; i + + )
csum + = ntohl ( p [ i ] ) ;
if ( csum ! = 0xffffffff ) {
CH_ERR ( adapter , " corrupted firmware image, checksum %u \n " ,
csum ) ;
return - EINVAL ;
}
ret = t3_flash_erase_sectors ( adapter , fw_sector , fw_sector ) ;
if ( ret )
goto out ;
size - = 8 ; /* trim off version and checksum */
for ( addr = FW_FLASH_BOOT_ADDR ; size ; ) {
unsigned int chunk_size = min ( size , 256U ) ;
ret = t3_write_flash ( adapter , addr , chunk_size , fw_data ) ;
if ( ret )
goto out ;
addr + = chunk_size ;
fw_data + = chunk_size ;
size - = chunk_size ;
}
ret = t3_write_flash ( adapter , FW_VERS_ADDR , 4 , fw_data ) ;
out :
if ( ret )
CH_ERR ( adapter , " firmware download failed, error %d \n " , ret ) ;
return ret ;
}
# define CIM_CTL_BASE 0x2000
/**
* t3_cim_ctl_blk_read - read a block from CIM control region
*
* @ adap : the adapter
* @ addr : the start address within the CIM control region
* @ n : number of words to read
* @ valp : where to store the result
*
* Reads a block of 4 - byte words from the CIM control region .
*/
int t3_cim_ctl_blk_read ( struct adapter * adap , unsigned int addr ,
unsigned int n , unsigned int * valp )
{
int ret = 0 ;
if ( t3_read_reg ( adap , A_CIM_HOST_ACC_CTRL ) & F_HOSTBUSY )
return - EBUSY ;
for ( ; ! ret & & n - - ; addr + = 4 ) {
t3_write_reg ( adap , A_CIM_HOST_ACC_CTRL , CIM_CTL_BASE + addr ) ;
ret = t3_wait_op_done ( adap , A_CIM_HOST_ACC_CTRL , F_HOSTBUSY ,
0 , 5 , 2 ) ;
if ( ! ret )
* valp + + = t3_read_reg ( adap , A_CIM_HOST_ACC_DATA ) ;
}
return ret ;
}
/**
* t3_link_changed - handle interface link changes
* @ adapter : the adapter
* @ port_id : the port index that changed link state
*
* Called when a port ' s link settings change to propagate the new values
* to the associated PHY and MAC . After performing the common tasks it
* invokes an OS - specific handler .
*/
void t3_link_changed ( struct adapter * adapter , int port_id )
{
int link_ok , speed , duplex , fc ;
struct port_info * pi = adap2pinfo ( adapter , port_id ) ;
struct cphy * phy = & pi - > phy ;
struct cmac * mac = & pi - > mac ;
struct link_config * lc = & pi - > link_config ;
phy - > ops - > get_link_status ( phy , & link_ok , & speed , & duplex , & fc ) ;
if ( link_ok ! = lc - > link_ok & & adapter - > params . rev > 0 & &
uses_xaui ( adapter ) ) {
if ( link_ok )
t3b_pcs_reset ( mac ) ;
t3_write_reg ( adapter , A_XGM_XAUI_ACT_CTRL + mac - > offset ,
link_ok ? F_TXACTENABLE | F_RXEN : 0 ) ;
}
lc - > link_ok = link_ok ;
lc - > speed = speed < 0 ? SPEED_INVALID : speed ;
lc - > duplex = duplex < 0 ? DUPLEX_INVALID : duplex ;
if ( lc - > requested_fc & PAUSE_AUTONEG )
fc & = lc - > requested_fc ;
else
fc = lc - > requested_fc & ( PAUSE_RX | PAUSE_TX ) ;
if ( link_ok & & speed > = 0 & & lc - > autoneg = = AUTONEG_ENABLE ) {
/* Set MAC speed, duplex, and flow control to match PHY. */
t3_mac_set_speed_duplex_fc ( mac , speed , duplex , fc ) ;
lc - > fc = fc ;
}
t3_os_link_changed ( adapter , port_id , link_ok , speed , duplex , fc ) ;
}
/**
* t3_link_start - apply link configuration to MAC / PHY
* @ phy : the PHY to setup
* @ mac : the MAC to setup
* @ lc : the requested link configuration
*
* Set up a port ' s MAC and PHY according to a desired link configuration .
* - If the PHY can auto - negotiate first decide what to advertise , then
* enable / disable auto - negotiation as desired , and reset .
* - If the PHY does not auto - negotiate just reset it .
* - If auto - negotiation is off set the MAC to the proper speed / duplex / FC ,
* otherwise do it later based on the outcome of auto - negotiation .
*/
int t3_link_start ( struct cphy * phy , struct cmac * mac , struct link_config * lc )
{
unsigned int fc = lc - > requested_fc & ( PAUSE_RX | PAUSE_TX ) ;
lc - > link_ok = 0 ;
if ( lc - > supported & SUPPORTED_Autoneg ) {
lc - > advertising & = ~ ( ADVERTISED_Asym_Pause | ADVERTISED_Pause ) ;
if ( fc ) {
lc - > advertising | = ADVERTISED_Asym_Pause ;
if ( fc & PAUSE_RX )
lc - > advertising | = ADVERTISED_Pause ;
}
phy - > ops - > advertise ( phy , lc - > advertising ) ;
if ( lc - > autoneg = = AUTONEG_DISABLE ) {
lc - > speed = lc - > requested_speed ;
lc - > duplex = lc - > requested_duplex ;
lc - > fc = ( unsigned char ) fc ;
t3_mac_set_speed_duplex_fc ( mac , lc - > speed , lc - > duplex ,
fc ) ;
/* Also disables autoneg */
phy - > ops - > set_speed_duplex ( phy , lc - > speed , lc - > duplex ) ;
phy - > ops - > reset ( phy , 0 ) ;
} else
phy - > ops - > autoneg_enable ( phy ) ;
} else {
t3_mac_set_speed_duplex_fc ( mac , - 1 , - 1 , fc ) ;
lc - > fc = ( unsigned char ) fc ;
phy - > ops - > reset ( phy , 0 ) ;
}
return 0 ;
}
/**
* t3_set_vlan_accel - control HW VLAN extraction
* @ adapter : the adapter
* @ ports : bitmap of adapter ports to operate on
* @ on : enable ( 1 ) or disable ( 0 ) HW VLAN extraction
*
* Enables or disables HW extraction of VLAN tags for the given port .
*/
void t3_set_vlan_accel ( struct adapter * adapter , unsigned int ports , int on )
{
t3_set_reg_field ( adapter , A_TP_OUT_CONFIG ,
ports < < S_VLANEXTRACTIONENABLE ,
on ? ( ports < < S_VLANEXTRACTIONENABLE ) : 0 ) ;
}
struct intr_info {
unsigned int mask ; /* bits to check in interrupt status */
const char * msg ; /* message to print or NULL */
short stat_idx ; /* stat counter to increment or -1 */
unsigned short fatal : 1 ; /* whether the condition reported is fatal */
} ;
/**
* t3_handle_intr_status - table driven interrupt handler
* @ adapter : the adapter that generated the interrupt
* @ reg : the interrupt status register to process
* @ mask : a mask to apply to the interrupt status
* @ acts : table of interrupt actions
* @ stats : statistics counters tracking interrupt occurences
*
* A table driven interrupt handler that applies a set of masks to an
* interrupt status word and performs the corresponding actions if the
* interrupts described by the mask have occured . The actions include
* optionally printing a warning or alert message , and optionally
* incrementing a stat counter . The table is terminated by an entry
* specifying mask 0. Returns the number of fatal interrupt conditions .
*/
static int t3_handle_intr_status ( struct adapter * adapter , unsigned int reg ,
unsigned int mask ,
const struct intr_info * acts ,
unsigned long * stats )
{
int fatal = 0 ;
unsigned int status = t3_read_reg ( adapter , reg ) & mask ;
for ( ; acts - > mask ; + + acts ) {
if ( ! ( status & acts - > mask ) )
continue ;
if ( acts - > fatal ) {
fatal + + ;
CH_ALERT ( adapter , " %s (0x%x) \n " ,
acts - > msg , status & acts - > mask ) ;
} else if ( acts - > msg )
CH_WARN ( adapter , " %s (0x%x) \n " ,
acts - > msg , status & acts - > mask ) ;
if ( acts - > stat_idx > = 0 )
stats [ acts - > stat_idx ] + + ;
}
if ( status ) /* clear processed interrupts */
t3_write_reg ( adapter , reg , status ) ;
return fatal ;
}
# define SGE_INTR_MASK (F_RSPQDISABLED)
# define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
F_NFASRCHFAIL )
# define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
# define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
V_RXFIFO_PRTY_ERR ( M_RXFIFO_PRTY_ERR ) | \
F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW )
# define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
V_WFPARERR ( M_WFPARERR ) | V_RFPARERR ( M_RFPARERR ) | \
V_CFPARERR ( M_CFPARERR ) /* | V_MSIXPARERR(M_MSIXPARERR) */ )
# define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
/* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
V_BISTERR ( M_BISTERR ) | F_PEXERR )
# define ULPRX_INTR_MASK F_PARERR
# define ULPTX_INTR_MASK 0
# define CPLSW_INTR_MASK (F_TP_FRAMING_ERROR | \
F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
F_ZERO_SWITCH_ERROR )
# define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT )
# define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
V_ICSPI_PAR_ERROR ( M_ICSPI_PAR_ERROR ) | \
V_OESPI_PAR_ERROR ( M_OESPI_PAR_ERROR ) )
# define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
V_IESPI_PAR_ERROR ( M_IESPI_PAR_ERROR ) | \
V_OCSPI_PAR_ERROR ( M_OCSPI_PAR_ERROR ) )
# define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
V_TX1TPPARERRENB ( M_TX1TPPARERRENB ) | \
V_RXTPPARERRENB ( M_RXTPPARERRENB ) | \
V_MCAPARERRENB ( M_MCAPARERRENB ) )
# define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
F_MPS0 | F_CPL_SWITCH )
/*
* Interrupt handler for the PCIX1 module .
*/
static void pci_intr_handler ( struct adapter * adapter )
{
static const struct intr_info pcix1_intr_info [ ] = {
{ F_PEXERR , " PCI PEX error " , - 1 , 1 } ,
{ F_MSTDETPARERR , " PCI master detected parity error " , - 1 , 1 } ,
{ F_SIGTARABT , " PCI signaled target abort " , - 1 , 1 } ,
{ F_RCVTARABT , " PCI received target abort " , - 1 , 1 } ,
{ F_RCVMSTABT , " PCI received master abort " , - 1 , 1 } ,
{ F_SIGSYSERR , " PCI signaled system error " , - 1 , 1 } ,
{ F_DETPARERR , " PCI detected parity error " , - 1 , 1 } ,
{ F_SPLCMPDIS , " PCI split completion discarded " , - 1 , 1 } ,
{ F_UNXSPLCMP , " PCI unexpected split completion error " , - 1 , 1 } ,
{ F_RCVSPLCMPERR , " PCI received split completion error " , - 1 ,
1 } ,
{ F_DETCORECCERR , " PCI correctable ECC error " ,
STAT_PCI_CORR_ECC , 0 } ,
{ F_DETUNCECCERR , " PCI uncorrectable ECC error " , - 1 , 1 } ,
{ F_PIOPARERR , " PCI PIO FIFO parity error " , - 1 , 1 } ,
{ V_WFPARERR ( M_WFPARERR ) , " PCI write FIFO parity error " , - 1 ,
1 } ,
{ V_RFPARERR ( M_RFPARERR ) , " PCI read FIFO parity error " , - 1 ,
1 } ,
{ V_CFPARERR ( M_CFPARERR ) , " PCI command FIFO parity error " , - 1 ,
1 } ,
{ V_MSIXPARERR ( M_MSIXPARERR ) , " PCI MSI-X table/PBA parity "
" error " , - 1 , 1 } ,
{ 0 }
} ;
if ( t3_handle_intr_status ( adapter , A_PCIX_INT_CAUSE , PCIX_INTR_MASK ,
pcix1_intr_info , adapter - > irq_stats ) )
t3_fatal_err ( adapter ) ;
}
/*
* Interrupt handler for the PCIE module .
*/
static void pcie_intr_handler ( struct adapter * adapter )
{
static const struct intr_info pcie_intr_info [ ] = {
{ F_UNXSPLCPLERRR ,
" PCI unexpected split completion DMA read error " , - 1 , 1 } ,
{ F_UNXSPLCPLERRC ,
" PCI unexpected split completion DMA command error " , - 1 , 1 } ,
{ F_PCIE_PIOPARERR , " PCI PIO FIFO parity error " , - 1 , 1 } ,
{ F_PCIE_WFPARERR , " PCI write FIFO parity error " , - 1 , 1 } ,
{ F_PCIE_RFPARERR , " PCI read FIFO parity error " , - 1 , 1 } ,
{ F_PCIE_CFPARERR , " PCI command FIFO parity error " , - 1 , 1 } ,
{ V_PCIE_MSIXPARERR ( M_PCIE_MSIXPARERR ) ,
" PCI MSI-X table/PBA parity error " , - 1 , 1 } ,
{ V_BISTERR ( M_BISTERR ) , " PCI BIST error " , - 1 , 1 } ,
{ 0 }
} ;
if ( t3_handle_intr_status ( adapter , A_PCIE_INT_CAUSE , PCIE_INTR_MASK ,
pcie_intr_info , adapter - > irq_stats ) )
t3_fatal_err ( adapter ) ;
}
/*
* TP interrupt handler .
*/
static void tp_intr_handler ( struct adapter * adapter )
{
static const struct intr_info tp_intr_info [ ] = {
{ 0xffffff , " TP parity error " , - 1 , 1 } ,
{ 0x1000000 , " TP out of Rx pages " , - 1 , 1 } ,
{ 0x2000000 , " TP out of Tx pages " , - 1 , 1 } ,
{ 0 }
} ;
if ( t3_handle_intr_status ( adapter , A_TP_INT_CAUSE , 0xffffffff ,
tp_intr_info , NULL ) )
t3_fatal_err ( adapter ) ;
}
/*
* CIM interrupt handler .
*/
static void cim_intr_handler ( struct adapter * adapter )
{
static const struct intr_info cim_intr_info [ ] = {
{ F_RSVDSPACEINT , " CIM reserved space write " , - 1 , 1 } ,
{ F_SDRAMRANGEINT , " CIM SDRAM address out of range " , - 1 , 1 } ,
{ F_FLASHRANGEINT , " CIM flash address out of range " , - 1 , 1 } ,
{ F_BLKWRBOOTINT , " CIM block write to boot space " , - 1 , 1 } ,
{ F_WRBLKFLASHINT , " CIM write to cached flash space " , - 1 , 1 } ,
{ F_SGLWRFLASHINT , " CIM single write to flash space " , - 1 , 1 } ,
{ F_BLKRDFLASHINT , " CIM block read from flash space " , - 1 , 1 } ,
{ F_BLKWRFLASHINT , " CIM block write to flash space " , - 1 , 1 } ,
{ F_BLKRDCTLINT , " CIM block read from CTL space " , - 1 , 1 } ,
{ F_BLKWRCTLINT , " CIM block write to CTL space " , - 1 , 1 } ,
{ F_BLKRDPLINT , " CIM block read from PL space " , - 1 , 1 } ,
{ F_BLKWRPLINT , " CIM block write to PL space " , - 1 , 1 } ,
{ 0 }
} ;
if ( t3_handle_intr_status ( adapter , A_CIM_HOST_INT_CAUSE , 0xffffffff ,
cim_intr_info , NULL ) )
t3_fatal_err ( adapter ) ;
}
/*
* ULP RX interrupt handler .
*/
static void ulprx_intr_handler ( struct adapter * adapter )
{
static const struct intr_info ulprx_intr_info [ ] = {
{ F_PARERR , " ULP RX parity error " , - 1 , 1 } ,
{ 0 }
} ;
if ( t3_handle_intr_status ( adapter , A_ULPRX_INT_CAUSE , 0xffffffff ,
ulprx_intr_info , NULL ) )
t3_fatal_err ( adapter ) ;
}
/*
* ULP TX interrupt handler .
*/
static void ulptx_intr_handler ( struct adapter * adapter )
{
static const struct intr_info ulptx_intr_info [ ] = {
{ F_PBL_BOUND_ERR_CH0 , " ULP TX channel 0 PBL out of bounds " ,
STAT_ULP_CH0_PBL_OOB , 0 } ,
{ F_PBL_BOUND_ERR_CH1 , " ULP TX channel 1 PBL out of bounds " ,
STAT_ULP_CH1_PBL_OOB , 0 } ,
{ 0 }
} ;
if ( t3_handle_intr_status ( adapter , A_ULPTX_INT_CAUSE , 0xffffffff ,
ulptx_intr_info , adapter - > irq_stats ) )
t3_fatal_err ( adapter ) ;
}
# define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
F_ICSPI1_TX_FRAMING_ERROR )
# define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
F_OESPI1_OFIFO2X_TX_FRAMING_ERROR )
/*
* PM TX interrupt handler .
*/
static void pmtx_intr_handler ( struct adapter * adapter )
{
static const struct intr_info pmtx_intr_info [ ] = {
{ F_ZERO_C_CMD_ERROR , " PMTX 0-length pcmd " , - 1 , 1 } ,
{ ICSPI_FRM_ERR , " PMTX ispi framing error " , - 1 , 1 } ,
{ OESPI_FRM_ERR , " PMTX ospi framing error " , - 1 , 1 } ,
{ V_ICSPI_PAR_ERROR ( M_ICSPI_PAR_ERROR ) ,
" PMTX ispi parity error " , - 1 , 1 } ,
{ V_OESPI_PAR_ERROR ( M_OESPI_PAR_ERROR ) ,
" PMTX ospi parity error " , - 1 , 1 } ,
{ 0 }
} ;
if ( t3_handle_intr_status ( adapter , A_PM1_TX_INT_CAUSE , 0xffffffff ,
pmtx_intr_info , NULL ) )
t3_fatal_err ( adapter ) ;
}
# define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
F_IESPI1_TX_FRAMING_ERROR )
# define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR )
/*
* PM RX interrupt handler .
*/
static void pmrx_intr_handler ( struct adapter * adapter )
{
static const struct intr_info pmrx_intr_info [ ] = {
{ F_ZERO_E_CMD_ERROR , " PMRX 0-length pcmd " , - 1 , 1 } ,
{ IESPI_FRM_ERR , " PMRX ispi framing error " , - 1 , 1 } ,
{ OCSPI_FRM_ERR , " PMRX ospi framing error " , - 1 , 1 } ,
{ V_IESPI_PAR_ERROR ( M_IESPI_PAR_ERROR ) ,
" PMRX ispi parity error " , - 1 , 1 } ,
{ V_OCSPI_PAR_ERROR ( M_OCSPI_PAR_ERROR ) ,
" PMRX ospi parity error " , - 1 , 1 } ,
{ 0 }
} ;
if ( t3_handle_intr_status ( adapter , A_PM1_RX_INT_CAUSE , 0xffffffff ,
pmrx_intr_info , NULL ) )
t3_fatal_err ( adapter ) ;
}
/*
* CPL switch interrupt handler .
*/
static void cplsw_intr_handler ( struct adapter * adapter )
{
static const struct intr_info cplsw_intr_info [ ] = {
/* { F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, */
{ F_TP_FRAMING_ERROR , " CPL switch TP framing error " , - 1 , 1 } ,
{ F_SGE_FRAMING_ERROR , " CPL switch SGE framing error " , - 1 , 1 } ,
{ F_CIM_FRAMING_ERROR , " CPL switch CIM framing error " , - 1 , 1 } ,
{ F_ZERO_SWITCH_ERROR , " CPL switch no-switch error " , - 1 , 1 } ,
{ 0 }
} ;
if ( t3_handle_intr_status ( adapter , A_CPL_INTR_CAUSE , 0xffffffff ,
cplsw_intr_info , NULL ) )
t3_fatal_err ( adapter ) ;
}
/*
* MPS interrupt handler .
*/
static void mps_intr_handler ( struct adapter * adapter )
{
static const struct intr_info mps_intr_info [ ] = {
{ 0x1ff , " MPS parity error " , - 1 , 1 } ,
{ 0 }
} ;
if ( t3_handle_intr_status ( adapter , A_MPS_INT_CAUSE , 0xffffffff ,
mps_intr_info , NULL ) )
t3_fatal_err ( adapter ) ;
}
# define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
/*
* MC7 interrupt handler .
*/
static void mc7_intr_handler ( struct mc7 * mc7 )
{
struct adapter * adapter = mc7 - > adapter ;
u32 cause = t3_read_reg ( adapter , mc7 - > offset + A_MC7_INT_CAUSE ) ;
if ( cause & F_CE ) {
mc7 - > stats . corr_err + + ;
CH_WARN ( adapter , " %s MC7 correctable error at addr 0x%x, "
" data 0x%x 0x%x 0x%x \n " , mc7 - > name ,
t3_read_reg ( adapter , mc7 - > offset + A_MC7_CE_ADDR ) ,
t3_read_reg ( adapter , mc7 - > offset + A_MC7_CE_DATA0 ) ,
t3_read_reg ( adapter , mc7 - > offset + A_MC7_CE_DATA1 ) ,
t3_read_reg ( adapter , mc7 - > offset + A_MC7_CE_DATA2 ) ) ;
}
if ( cause & F_UE ) {
mc7 - > stats . uncorr_err + + ;
CH_ALERT ( adapter , " %s MC7 uncorrectable error at addr 0x%x, "
" data 0x%x 0x%x 0x%x \n " , mc7 - > name ,
t3_read_reg ( adapter , mc7 - > offset + A_MC7_UE_ADDR ) ,
t3_read_reg ( adapter , mc7 - > offset + A_MC7_UE_DATA0 ) ,
t3_read_reg ( adapter , mc7 - > offset + A_MC7_UE_DATA1 ) ,
t3_read_reg ( adapter , mc7 - > offset + A_MC7_UE_DATA2 ) ) ;
}
if ( G_PE ( cause ) ) {
mc7 - > stats . parity_err + + ;
CH_ALERT ( adapter , " %s MC7 parity error 0x%x \n " ,
mc7 - > name , G_PE ( cause ) ) ;
}
if ( cause & F_AE ) {
u32 addr = 0 ;
if ( adapter - > params . rev > 0 )
addr = t3_read_reg ( adapter ,
mc7 - > offset + A_MC7_ERR_ADDR ) ;
mc7 - > stats . addr_err + + ;
CH_ALERT ( adapter , " %s MC7 address error: 0x%x \n " ,
mc7 - > name , addr ) ;
}
if ( cause & MC7_INTR_FATAL )
t3_fatal_err ( adapter ) ;
t3_write_reg ( adapter , mc7 - > offset + A_MC7_INT_CAUSE , cause ) ;
}
# define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
V_RXFIFO_PRTY_ERR ( M_RXFIFO_PRTY_ERR ) )
/*
* XGMAC interrupt handler .
*/
static int mac_intr_handler ( struct adapter * adap , unsigned int idx )
{
struct cmac * mac = & adap2pinfo ( adap , idx ) - > mac ;
u32 cause = t3_read_reg ( adap , A_XGM_INT_CAUSE + mac - > offset ) ;
if ( cause & V_TXFIFO_PRTY_ERR ( M_TXFIFO_PRTY_ERR ) ) {
mac - > stats . tx_fifo_parity_err + + ;
CH_ALERT ( adap , " port%d: MAC TX FIFO parity error \n " , idx ) ;
}
if ( cause & V_RXFIFO_PRTY_ERR ( M_RXFIFO_PRTY_ERR ) ) {
mac - > stats . rx_fifo_parity_err + + ;
CH_ALERT ( adap , " port%d: MAC RX FIFO parity error \n " , idx ) ;
}
if ( cause & F_TXFIFO_UNDERRUN )
mac - > stats . tx_fifo_urun + + ;
if ( cause & F_RXFIFO_OVERFLOW )
mac - > stats . rx_fifo_ovfl + + ;
if ( cause & V_SERDES_LOS ( M_SERDES_LOS ) )
mac - > stats . serdes_signal_loss + + ;
if ( cause & F_XAUIPCSCTCERR )
mac - > stats . xaui_pcs_ctc_err + + ;
if ( cause & F_XAUIPCSALIGNCHANGE )
mac - > stats . xaui_pcs_align_change + + ;
t3_write_reg ( adap , A_XGM_INT_CAUSE + mac - > offset , cause ) ;
if ( cause & XGM_INTR_FATAL )
t3_fatal_err ( adap ) ;
return cause ! = 0 ;
}
/*
* Interrupt handler for PHY events .
*/
int t3_phy_intr_handler ( struct adapter * adapter )
{
static const int intr_gpio_bits [ ] = { 8 , 0x20 } ;
u32 i , cause = t3_read_reg ( adapter , A_T3DBG_INT_CAUSE ) ;
for_each_port ( adapter , i ) {
if ( cause & intr_gpio_bits [ i ] ) {
struct cphy * phy = & adap2pinfo ( adapter , i ) - > phy ;
int phy_cause = phy - > ops - > intr_handler ( phy ) ;
if ( phy_cause & cphy_cause_link_change )
t3_link_changed ( adapter , i ) ;
if ( phy_cause & cphy_cause_fifo_error )
phy - > fifo_errors + + ;
}
}
t3_write_reg ( adapter , A_T3DBG_INT_CAUSE , cause ) ;
return 0 ;
}
/*
* T3 slow path ( non - data ) interrupt handler .
*/
int t3_slow_intr_handler ( struct adapter * adapter )
{
u32 cause = t3_read_reg ( adapter , A_PL_INT_CAUSE0 ) ;
cause & = adapter - > slow_intr_mask ;
if ( ! cause )
return 0 ;
if ( cause & F_PCIM0 ) {
if ( is_pcie ( adapter ) )
pcie_intr_handler ( adapter ) ;
else
pci_intr_handler ( adapter ) ;
}
if ( cause & F_SGE3 )
t3_sge_err_intr_handler ( adapter ) ;
if ( cause & F_MC7_PMRX )
mc7_intr_handler ( & adapter - > pmrx ) ;
if ( cause & F_MC7_PMTX )
mc7_intr_handler ( & adapter - > pmtx ) ;
if ( cause & F_MC7_CM )
mc7_intr_handler ( & adapter - > cm ) ;
if ( cause & F_CIM )
cim_intr_handler ( adapter ) ;
if ( cause & F_TP1 )
tp_intr_handler ( adapter ) ;
if ( cause & F_ULP2_RX )
ulprx_intr_handler ( adapter ) ;
if ( cause & F_ULP2_TX )
ulptx_intr_handler ( adapter ) ;
if ( cause & F_PM1_RX )
pmrx_intr_handler ( adapter ) ;
if ( cause & F_PM1_TX )
pmtx_intr_handler ( adapter ) ;
if ( cause & F_CPL_SWITCH )
cplsw_intr_handler ( adapter ) ;
if ( cause & F_MPS0 )
mps_intr_handler ( adapter ) ;
if ( cause & F_MC5A )
t3_mc5_intr_handler ( & adapter - > mc5 ) ;
if ( cause & F_XGMAC0_0 )
mac_intr_handler ( adapter , 0 ) ;
if ( cause & F_XGMAC0_1 )
mac_intr_handler ( adapter , 1 ) ;
if ( cause & F_T3DBG )
t3_os_ext_intr_handler ( adapter ) ;
/* Clear the interrupts just processed. */
t3_write_reg ( adapter , A_PL_INT_CAUSE0 , cause ) ;
t3_read_reg ( adapter , A_PL_INT_CAUSE0 ) ; /* flush */
return 1 ;
}
/**
* t3_intr_enable - enable interrupts
* @ adapter : the adapter whose interrupts should be enabled
*
* Enable interrupts by setting the interrupt enable registers of the
* various HW modules and then enabling the top - level interrupt
* concentrator .
*/
void t3_intr_enable ( struct adapter * adapter )
{
static const struct addr_val_pair intr_en_avp [ ] = {
{ A_SG_INT_ENABLE , SGE_INTR_MASK } ,
{ A_MC7_INT_ENABLE , MC7_INTR_MASK } ,
{ A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR ,
MC7_INTR_MASK } ,
{ A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR ,
MC7_INTR_MASK } ,
{ A_MC5_DB_INT_ENABLE , MC5_INTR_MASK } ,
{ A_ULPRX_INT_ENABLE , ULPRX_INTR_MASK } ,
{ A_TP_INT_ENABLE , 0x3bfffff } ,
{ A_PM1_TX_INT_ENABLE , PMTX_INTR_MASK } ,
{ A_PM1_RX_INT_ENABLE , PMRX_INTR_MASK } ,
{ A_CIM_HOST_INT_ENABLE , CIM_INTR_MASK } ,
{ A_MPS_INT_ENABLE , MPS_INTR_MASK } ,
} ;
adapter - > slow_intr_mask = PL_INTR_MASK ;
t3_write_regs ( adapter , intr_en_avp , ARRAY_SIZE ( intr_en_avp ) , 0 ) ;
if ( adapter - > params . rev > 0 ) {
t3_write_reg ( adapter , A_CPL_INTR_ENABLE ,
CPLSW_INTR_MASK | F_CIM_OVFL_ERROR ) ;
t3_write_reg ( adapter , A_ULPTX_INT_ENABLE ,
ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
F_PBL_BOUND_ERR_CH1 ) ;
} else {
t3_write_reg ( adapter , A_CPL_INTR_ENABLE , CPLSW_INTR_MASK ) ;
t3_write_reg ( adapter , A_ULPTX_INT_ENABLE , ULPTX_INTR_MASK ) ;
}
t3_write_reg ( adapter , A_T3DBG_GPIO_ACT_LOW ,
adapter_info ( adapter ) - > gpio_intr ) ;
t3_write_reg ( adapter , A_T3DBG_INT_ENABLE ,
adapter_info ( adapter ) - > gpio_intr ) ;
if ( is_pcie ( adapter ) )
t3_write_reg ( adapter , A_PCIE_INT_ENABLE , PCIE_INTR_MASK ) ;
else
t3_write_reg ( adapter , A_PCIX_INT_ENABLE , PCIX_INTR_MASK ) ;
t3_write_reg ( adapter , A_PL_INT_ENABLE0 , adapter - > slow_intr_mask ) ;
t3_read_reg ( adapter , A_PL_INT_ENABLE0 ) ; /* flush */
}
/**
* t3_intr_disable - disable a card ' s interrupts
* @ adapter : the adapter whose interrupts should be disabled
*
* Disable interrupts . We only disable the top - level interrupt
* concentrator and the SGE data interrupts .
*/
void t3_intr_disable ( struct adapter * adapter )
{
t3_write_reg ( adapter , A_PL_INT_ENABLE0 , 0 ) ;
t3_read_reg ( adapter , A_PL_INT_ENABLE0 ) ; /* flush */
adapter - > slow_intr_mask = 0 ;
}
/**
* t3_intr_clear - clear all interrupts
* @ adapter : the adapter whose interrupts should be cleared
*
* Clears all interrupts .
*/
void t3_intr_clear ( struct adapter * adapter )
{
static const unsigned int cause_reg_addr [ ] = {
A_SG_INT_CAUSE ,
A_SG_RSPQ_FL_STATUS ,
A_PCIX_INT_CAUSE ,
A_MC7_INT_CAUSE ,
A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR ,
A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR ,
A_CIM_HOST_INT_CAUSE ,
A_TP_INT_CAUSE ,
A_MC5_DB_INT_CAUSE ,
A_ULPRX_INT_CAUSE ,
A_ULPTX_INT_CAUSE ,
A_CPL_INTR_CAUSE ,
A_PM1_TX_INT_CAUSE ,
A_PM1_RX_INT_CAUSE ,
A_MPS_INT_CAUSE ,
A_T3DBG_INT_CAUSE ,
} ;
unsigned int i ;
/* Clear PHY and MAC interrupts for each port. */
for_each_port ( adapter , i )
t3_port_intr_clear ( adapter , i ) ;
for ( i = 0 ; i < ARRAY_SIZE ( cause_reg_addr ) ; + + i )
t3_write_reg ( adapter , cause_reg_addr [ i ] , 0xffffffff ) ;
t3_write_reg ( adapter , A_PL_INT_CAUSE0 , 0xffffffff ) ;
t3_read_reg ( adapter , A_PL_INT_CAUSE0 ) ; /* flush */
}
/**
* t3_port_intr_enable - enable port - specific interrupts
* @ adapter : associated adapter
* @ idx : index of port whose interrupts should be enabled
*
* Enable port - specific ( i . e . , MAC and PHY ) interrupts for the given
* adapter port .
*/
void t3_port_intr_enable ( struct adapter * adapter , int idx )
{
struct cphy * phy = & adap2pinfo ( adapter , idx ) - > phy ;
t3_write_reg ( adapter , XGM_REG ( A_XGM_INT_ENABLE , idx ) , XGM_INTR_MASK ) ;
t3_read_reg ( adapter , XGM_REG ( A_XGM_INT_ENABLE , idx ) ) ; /* flush */
phy - > ops - > intr_enable ( phy ) ;
}
/**
* t3_port_intr_disable - disable port - specific interrupts
* @ adapter : associated adapter
* @ idx : index of port whose interrupts should be disabled
*
* Disable port - specific ( i . e . , MAC and PHY ) interrupts for the given
* adapter port .
*/
void t3_port_intr_disable ( struct adapter * adapter , int idx )
{
struct cphy * phy = & adap2pinfo ( adapter , idx ) - > phy ;
t3_write_reg ( adapter , XGM_REG ( A_XGM_INT_ENABLE , idx ) , 0 ) ;
t3_read_reg ( adapter , XGM_REG ( A_XGM_INT_ENABLE , idx ) ) ; /* flush */
phy - > ops - > intr_disable ( phy ) ;
}
/**
* t3_port_intr_clear - clear port - specific interrupts
* @ adapter : associated adapter
* @ idx : index of port whose interrupts to clear
*
* Clear port - specific ( i . e . , MAC and PHY ) interrupts for the given
* adapter port .
*/
void t3_port_intr_clear ( struct adapter * adapter , int idx )
{
struct cphy * phy = & adap2pinfo ( adapter , idx ) - > phy ;
t3_write_reg ( adapter , XGM_REG ( A_XGM_INT_CAUSE , idx ) , 0xffffffff ) ;
t3_read_reg ( adapter , XGM_REG ( A_XGM_INT_CAUSE , idx ) ) ; /* flush */
phy - > ops - > intr_clear ( phy ) ;
}
/**
* t3_sge_write_context - write an SGE context
* @ adapter : the adapter
* @ id : the context id
* @ type : the context type
*
* Program an SGE context with the values already loaded in the
* CONTEXT_DATA ? registers .
*/
static int t3_sge_write_context ( struct adapter * adapter , unsigned int id ,
unsigned int type )
{
t3_write_reg ( adapter , A_SG_CONTEXT_MASK0 , 0xffffffff ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK1 , 0xffffffff ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK2 , 0xffffffff ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK3 , 0xffffffff ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_CMD ,
V_CONTEXT_CMD_OPCODE ( 1 ) | type | V_CONTEXT ( id ) ) ;
return t3_wait_op_done ( adapter , A_SG_CONTEXT_CMD , F_CONTEXT_CMD_BUSY ,
0 , 5 , 1 ) ;
}
/**
* t3_sge_init_ecntxt - initialize an SGE egress context
* @ adapter : the adapter to configure
* @ id : the context id
* @ gts_enable : whether to enable GTS for the context
* @ type : the egress context type
* @ respq : associated response queue
* @ base_addr : base address of queue
* @ size : number of queue entries
* @ token : uP token
* @ gen : initial generation value for the context
* @ cidx : consumer pointer
*
* Initialize an SGE egress context and make it ready for use . If the
* platform allows concurrent context operations , the caller is
* responsible for appropriate locking .
*/
int t3_sge_init_ecntxt ( struct adapter * adapter , unsigned int id , int gts_enable ,
enum sge_context_type type , int respq , u64 base_addr ,
unsigned int size , unsigned int token , int gen ,
unsigned int cidx )
{
unsigned int credits = type = = SGE_CNTXT_OFLD ? 0 : FW_WR_NUM ;
if ( base_addr & 0xfff ) /* must be 4K aligned */
return - EINVAL ;
if ( t3_read_reg ( adapter , A_SG_CONTEXT_CMD ) & F_CONTEXT_CMD_BUSY )
return - EBUSY ;
base_addr > > = 12 ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA0 , V_EC_INDEX ( cidx ) |
V_EC_CREDITS ( credits ) | V_EC_GTS ( gts_enable ) ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA1 , V_EC_SIZE ( size ) |
V_EC_BASE_LO ( base_addr & 0xffff ) ) ;
base_addr > > = 16 ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA2 , base_addr ) ;
base_addr > > = 32 ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA3 ,
V_EC_BASE_HI ( base_addr & 0xf ) | V_EC_RESPQ ( respq ) |
V_EC_TYPE ( type ) | V_EC_GEN ( gen ) | V_EC_UP_TOKEN ( token ) |
F_EC_VALID ) ;
return t3_sge_write_context ( adapter , id , F_EGRESS ) ;
}
/**
* t3_sge_init_flcntxt - initialize an SGE free - buffer list context
* @ adapter : the adapter to configure
* @ id : the context id
* @ gts_enable : whether to enable GTS for the context
* @ base_addr : base address of queue
* @ size : number of queue entries
* @ bsize : size of each buffer for this queue
* @ cong_thres : threshold to signal congestion to upstream producers
* @ gen : initial generation value for the context
* @ cidx : consumer pointer
*
* Initialize an SGE free list context and make it ready for use . The
* caller is responsible for ensuring only one context operation occurs
* at a time .
*/
int t3_sge_init_flcntxt ( struct adapter * adapter , unsigned int id ,
int gts_enable , u64 base_addr , unsigned int size ,
unsigned int bsize , unsigned int cong_thres , int gen ,
unsigned int cidx )
{
if ( base_addr & 0xfff ) /* must be 4K aligned */
return - EINVAL ;
if ( t3_read_reg ( adapter , A_SG_CONTEXT_CMD ) & F_CONTEXT_CMD_BUSY )
return - EBUSY ;
base_addr > > = 12 ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA0 , base_addr ) ;
base_addr > > = 32 ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA1 ,
V_FL_BASE_HI ( ( u32 ) base_addr ) |
V_FL_INDEX_LO ( cidx & M_FL_INDEX_LO ) ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA2 , V_FL_SIZE ( size ) |
V_FL_GEN ( gen ) | V_FL_INDEX_HI ( cidx > > 12 ) |
V_FL_ENTRY_SIZE_LO ( bsize & M_FL_ENTRY_SIZE_LO ) ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA3 ,
V_FL_ENTRY_SIZE_HI ( bsize > > ( 32 - S_FL_ENTRY_SIZE_LO ) ) |
V_FL_CONG_THRES ( cong_thres ) | V_FL_GTS ( gts_enable ) ) ;
return t3_sge_write_context ( adapter , id , F_FREELIST ) ;
}
/**
* t3_sge_init_rspcntxt - initialize an SGE response queue context
* @ adapter : the adapter to configure
* @ id : the context id
* @ irq_vec_idx : MSI - X interrupt vector index , 0 if no MSI - X , - 1 if no IRQ
* @ base_addr : base address of queue
* @ size : number of queue entries
* @ fl_thres : threshold for selecting the normal or jumbo free list
* @ gen : initial generation value for the context
* @ cidx : consumer pointer
*
* Initialize an SGE response queue context and make it ready for use .
* The caller is responsible for ensuring only one context operation
* occurs at a time .
*/
int t3_sge_init_rspcntxt ( struct adapter * adapter , unsigned int id ,
int irq_vec_idx , u64 base_addr , unsigned int size ,
unsigned int fl_thres , int gen , unsigned int cidx )
{
unsigned int intr = 0 ;
if ( base_addr & 0xfff ) /* must be 4K aligned */
return - EINVAL ;
if ( t3_read_reg ( adapter , A_SG_CONTEXT_CMD ) & F_CONTEXT_CMD_BUSY )
return - EBUSY ;
base_addr > > = 12 ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA0 , V_CQ_SIZE ( size ) |
V_CQ_INDEX ( cidx ) ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA1 , base_addr ) ;
base_addr > > = 32 ;
if ( irq_vec_idx > = 0 )
intr = V_RQ_MSI_VEC ( irq_vec_idx ) | F_RQ_INTR_EN ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA2 ,
V_CQ_BASE_HI ( ( u32 ) base_addr ) | intr | V_RQ_GEN ( gen ) ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA3 , fl_thres ) ;
return t3_sge_write_context ( adapter , id , F_RESPONSEQ ) ;
}
/**
* t3_sge_init_cqcntxt - initialize an SGE completion queue context
* @ adapter : the adapter to configure
* @ id : the context id
* @ base_addr : base address of queue
* @ size : number of queue entries
* @ rspq : response queue for async notifications
* @ ovfl_mode : CQ overflow mode
* @ credits : completion queue credits
* @ credit_thres : the credit threshold
*
* Initialize an SGE completion queue context and make it ready for use .
* The caller is responsible for ensuring only one context operation
* occurs at a time .
*/
int t3_sge_init_cqcntxt ( struct adapter * adapter , unsigned int id , u64 base_addr ,
unsigned int size , int rspq , int ovfl_mode ,
unsigned int credits , unsigned int credit_thres )
{
if ( base_addr & 0xfff ) /* must be 4K aligned */
return - EINVAL ;
if ( t3_read_reg ( adapter , A_SG_CONTEXT_CMD ) & F_CONTEXT_CMD_BUSY )
return - EBUSY ;
base_addr > > = 12 ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA0 , V_CQ_SIZE ( size ) ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA1 , base_addr ) ;
base_addr > > = 32 ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA2 ,
V_CQ_BASE_HI ( ( u32 ) base_addr ) | V_CQ_RSPQ ( rspq ) |
V_CQ_GEN ( 1 ) | V_CQ_OVERFLOW_MODE ( ovfl_mode ) ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA3 , V_CQ_CREDITS ( credits ) |
V_CQ_CREDIT_THRES ( credit_thres ) ) ;
return t3_sge_write_context ( adapter , id , F_CQ ) ;
}
/**
* t3_sge_enable_ecntxt - enable / disable an SGE egress context
* @ adapter : the adapter
* @ id : the egress context id
* @ enable : enable ( 1 ) or disable ( 0 ) the context
*
* Enable or disable an SGE egress context . The caller is responsible for
* ensuring only one context operation occurs at a time .
*/
int t3_sge_enable_ecntxt ( struct adapter * adapter , unsigned int id , int enable )
{
if ( t3_read_reg ( adapter , A_SG_CONTEXT_CMD ) & F_CONTEXT_CMD_BUSY )
return - EBUSY ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK0 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK1 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK2 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK3 , F_EC_VALID ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA3 , V_EC_VALID ( enable ) ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_CMD ,
V_CONTEXT_CMD_OPCODE ( 1 ) | F_EGRESS | V_CONTEXT ( id ) ) ;
return t3_wait_op_done ( adapter , A_SG_CONTEXT_CMD , F_CONTEXT_CMD_BUSY ,
0 , 5 , 1 ) ;
}
/**
* t3_sge_disable_fl - disable an SGE free - buffer list
* @ adapter : the adapter
* @ id : the free list context id
*
* Disable an SGE free - buffer list . The caller is responsible for
* ensuring only one context operation occurs at a time .
*/
int t3_sge_disable_fl ( struct adapter * adapter , unsigned int id )
{
if ( t3_read_reg ( adapter , A_SG_CONTEXT_CMD ) & F_CONTEXT_CMD_BUSY )
return - EBUSY ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK0 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK1 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK2 , V_FL_SIZE ( M_FL_SIZE ) ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK3 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA2 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_CMD ,
V_CONTEXT_CMD_OPCODE ( 1 ) | F_FREELIST | V_CONTEXT ( id ) ) ;
return t3_wait_op_done ( adapter , A_SG_CONTEXT_CMD , F_CONTEXT_CMD_BUSY ,
0 , 5 , 1 ) ;
}
/**
* t3_sge_disable_rspcntxt - disable an SGE response queue
* @ adapter : the adapter
* @ id : the response queue context id
*
* Disable an SGE response queue . The caller is responsible for
* ensuring only one context operation occurs at a time .
*/
int t3_sge_disable_rspcntxt ( struct adapter * adapter , unsigned int id )
{
if ( t3_read_reg ( adapter , A_SG_CONTEXT_CMD ) & F_CONTEXT_CMD_BUSY )
return - EBUSY ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK0 , V_CQ_SIZE ( M_CQ_SIZE ) ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK1 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK2 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK3 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA0 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_CMD ,
V_CONTEXT_CMD_OPCODE ( 1 ) | F_RESPONSEQ | V_CONTEXT ( id ) ) ;
return t3_wait_op_done ( adapter , A_SG_CONTEXT_CMD , F_CONTEXT_CMD_BUSY ,
0 , 5 , 1 ) ;
}
/**
* t3_sge_disable_cqcntxt - disable an SGE completion queue
* @ adapter : the adapter
* @ id : the completion queue context id
*
* Disable an SGE completion queue . The caller is responsible for
* ensuring only one context operation occurs at a time .
*/
int t3_sge_disable_cqcntxt ( struct adapter * adapter , unsigned int id )
{
if ( t3_read_reg ( adapter , A_SG_CONTEXT_CMD ) & F_CONTEXT_CMD_BUSY )
return - EBUSY ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK0 , V_CQ_SIZE ( M_CQ_SIZE ) ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK1 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK2 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_MASK3 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA0 , 0 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_CMD ,
V_CONTEXT_CMD_OPCODE ( 1 ) | F_CQ | V_CONTEXT ( id ) ) ;
return t3_wait_op_done ( adapter , A_SG_CONTEXT_CMD , F_CONTEXT_CMD_BUSY ,
0 , 5 , 1 ) ;
}
/**
* t3_sge_cqcntxt_op - perform an operation on a completion queue context
* @ adapter : the adapter
* @ id : the context id
* @ op : the operation to perform
*
* Perform the selected operation on an SGE completion queue context .
* The caller is responsible for ensuring only one context operation
* occurs at a time .
*/
int t3_sge_cqcntxt_op ( struct adapter * adapter , unsigned int id , unsigned int op ,
unsigned int credits )
{
u32 val ;
if ( t3_read_reg ( adapter , A_SG_CONTEXT_CMD ) & F_CONTEXT_CMD_BUSY )
return - EBUSY ;
t3_write_reg ( adapter , A_SG_CONTEXT_DATA0 , credits < < 16 ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_CMD , V_CONTEXT_CMD_OPCODE ( op ) |
V_CONTEXT ( id ) | F_CQ ) ;
if ( t3_wait_op_done_val ( adapter , A_SG_CONTEXT_CMD , F_CONTEXT_CMD_BUSY ,
0 , 5 , 1 , & val ) )
return - EIO ;
if ( op > = 2 & & op < 7 ) {
if ( adapter - > params . rev > 0 )
return G_CQ_INDEX ( val ) ;
t3_write_reg ( adapter , A_SG_CONTEXT_CMD ,
V_CONTEXT_CMD_OPCODE ( 0 ) | F_CQ | V_CONTEXT ( id ) ) ;
if ( t3_wait_op_done ( adapter , A_SG_CONTEXT_CMD ,
F_CONTEXT_CMD_BUSY , 0 , 5 , 1 ) )
return - EIO ;
return G_CQ_INDEX ( t3_read_reg ( adapter , A_SG_CONTEXT_DATA0 ) ) ;
}
return 0 ;
}
/**
* t3_sge_read_context - read an SGE context
* @ type : the context type
* @ adapter : the adapter
* @ id : the context id
* @ data : holds the retrieved context
*
* Read an SGE egress context . The caller is responsible for ensuring
* only one context operation occurs at a time .
*/
static int t3_sge_read_context ( unsigned int type , struct adapter * adapter ,
unsigned int id , u32 data [ 4 ] )
{
if ( t3_read_reg ( adapter , A_SG_CONTEXT_CMD ) & F_CONTEXT_CMD_BUSY )
return - EBUSY ;
t3_write_reg ( adapter , A_SG_CONTEXT_CMD ,
V_CONTEXT_CMD_OPCODE ( 0 ) | type | V_CONTEXT ( id ) ) ;
if ( t3_wait_op_done ( adapter , A_SG_CONTEXT_CMD , F_CONTEXT_CMD_BUSY , 0 ,
5 , 1 ) )
return - EIO ;
data [ 0 ] = t3_read_reg ( adapter , A_SG_CONTEXT_DATA0 ) ;
data [ 1 ] = t3_read_reg ( adapter , A_SG_CONTEXT_DATA1 ) ;
data [ 2 ] = t3_read_reg ( adapter , A_SG_CONTEXT_DATA2 ) ;
data [ 3 ] = t3_read_reg ( adapter , A_SG_CONTEXT_DATA3 ) ;
return 0 ;
}
/**
* t3_sge_read_ecntxt - read an SGE egress context
* @ adapter : the adapter
* @ id : the context id
* @ data : holds the retrieved context
*
* Read an SGE egress context . The caller is responsible for ensuring
* only one context operation occurs at a time .
*/
int t3_sge_read_ecntxt ( struct adapter * adapter , unsigned int id , u32 data [ 4 ] )
{
if ( id > = 65536 )
return - EINVAL ;
return t3_sge_read_context ( F_EGRESS , adapter , id , data ) ;
}
/**
* t3_sge_read_cq - read an SGE CQ context
* @ adapter : the adapter
* @ id : the context id
* @ data : holds the retrieved context
*
* Read an SGE CQ context . The caller is responsible for ensuring
* only one context operation occurs at a time .
*/
int t3_sge_read_cq ( struct adapter * adapter , unsigned int id , u32 data [ 4 ] )
{
if ( id > = 65536 )
return - EINVAL ;
return t3_sge_read_context ( F_CQ , adapter , id , data ) ;
}
/**
* t3_sge_read_fl - read an SGE free - list context
* @ adapter : the adapter
* @ id : the context id
* @ data : holds the retrieved context
*
* Read an SGE free - list context . The caller is responsible for ensuring
* only one context operation occurs at a time .
*/
int t3_sge_read_fl ( struct adapter * adapter , unsigned int id , u32 data [ 4 ] )
{
if ( id > = SGE_QSETS * 2 )
return - EINVAL ;
return t3_sge_read_context ( F_FREELIST , adapter , id , data ) ;
}
/**
* t3_sge_read_rspq - read an SGE response queue context
* @ adapter : the adapter
* @ id : the context id
* @ data : holds the retrieved context
*
* Read an SGE response queue context . The caller is responsible for
* ensuring only one context operation occurs at a time .
*/
int t3_sge_read_rspq ( struct adapter * adapter , unsigned int id , u32 data [ 4 ] )
{
if ( id > = SGE_QSETS )
return - EINVAL ;
return t3_sge_read_context ( F_RESPONSEQ , adapter , id , data ) ;
}
/**
* t3_config_rss - configure Rx packet steering
* @ adapter : the adapter
* @ rss_config : RSS settings ( written to TP_RSS_CONFIG )
* @ cpus : values for the CPU lookup table ( 0xff terminated )
* @ rspq : values for the response queue lookup table ( 0xffff terminated )
*
* Programs the receive packet steering logic . @ cpus and @ rspq provide
* the values for the CPU and response queue lookup tables . If they
* provide fewer values than the size of the tables the supplied values
* are used repeatedly until the tables are fully populated .
*/
void t3_config_rss ( struct adapter * adapter , unsigned int rss_config ,
const u8 * cpus , const u16 * rspq )
{
int i , j , cpu_idx = 0 , q_idx = 0 ;
if ( cpus )
for ( i = 0 ; i < RSS_TABLE_SIZE ; + + i ) {
u32 val = i < < 16 ;
for ( j = 0 ; j < 2 ; + + j ) {
val | = ( cpus [ cpu_idx + + ] & 0x3f ) < < ( 8 * j ) ;
if ( cpus [ cpu_idx ] = = 0xff )
cpu_idx = 0 ;
}
t3_write_reg ( adapter , A_TP_RSS_LKP_TABLE , val ) ;
}
if ( rspq )
for ( i = 0 ; i < RSS_TABLE_SIZE ; + + i ) {
t3_write_reg ( adapter , A_TP_RSS_MAP_TABLE ,
( i < < 16 ) | rspq [ q_idx + + ] ) ;
if ( rspq [ q_idx ] = = 0xffff )
q_idx = 0 ;
}
t3_write_reg ( adapter , A_TP_RSS_CONFIG , rss_config ) ;
}
/**
* t3_read_rss - read the contents of the RSS tables
* @ adapter : the adapter
* @ lkup : holds the contents of the RSS lookup table
* @ map : holds the contents of the RSS map table
*
* Reads the contents of the receive packet steering tables .
*/
int t3_read_rss ( struct adapter * adapter , u8 * lkup , u16 * map )
{
int i ;
u32 val ;
if ( lkup )
for ( i = 0 ; i < RSS_TABLE_SIZE ; + + i ) {
t3_write_reg ( adapter , A_TP_RSS_LKP_TABLE ,
0xffff0000 | i ) ;
val = t3_read_reg ( adapter , A_TP_RSS_LKP_TABLE ) ;
if ( ! ( val & 0x80000000 ) )
return - EAGAIN ;
* lkup + + = val ;
* lkup + + = ( val > > 8 ) ;
}
if ( map )
for ( i = 0 ; i < RSS_TABLE_SIZE ; + + i ) {
t3_write_reg ( adapter , A_TP_RSS_MAP_TABLE ,
0xffff0000 | i ) ;
val = t3_read_reg ( adapter , A_TP_RSS_MAP_TABLE ) ;
if ( ! ( val & 0x80000000 ) )
return - EAGAIN ;
* map + + = val ;
}
return 0 ;
}
/**
* t3_tp_set_offload_mode - put TP in NIC / offload mode
* @ adap : the adapter
* @ enable : 1 to select offload mode , 0 for regular NIC
*
* Switches TP to NIC / offload mode .
*/
void t3_tp_set_offload_mode ( struct adapter * adap , int enable )
{
if ( is_offload ( adap ) | | ! enable )
t3_set_reg_field ( adap , A_TP_IN_CONFIG , F_NICMODE ,
V_NICMODE ( ! enable ) ) ;
}
/**
* pm_num_pages - calculate the number of pages of the payload memory
* @ mem_size : the size of the payload memory
* @ pg_size : the size of each payload memory page
*
* Calculate the number of pages , each of the given size , that fit in a
* memory of the specified size , respecting the HW requirement that the
* number of pages must be a multiple of 24.
*/
static inline unsigned int pm_num_pages ( unsigned int mem_size ,
unsigned int pg_size )
{
unsigned int n = mem_size / pg_size ;
return n - n % 24 ;
}
# define mem_region(adap, start, size, reg) \
t3_write_reg ( ( adap ) , A_ # # reg , ( start ) ) ; \
start + = size
/*
* partition_mem - partition memory and configure TP memory settings
* @ adap : the adapter
* @ p : the TP parameters
*
* Partitions context and payload memory and configures TP ' s memory
* registers .
*/
static void partition_mem ( struct adapter * adap , const struct tp_params * p )
{
unsigned int m , pstructs , tids = t3_mc5_size ( & adap - > mc5 ) ;
unsigned int timers = 0 , timers_shift = 22 ;
if ( adap - > params . rev > 0 ) {
if ( tids < = 16 * 1024 ) {
timers = 1 ;
timers_shift = 16 ;
} else if ( tids < = 64 * 1024 ) {
timers = 2 ;
timers_shift = 18 ;
} else if ( tids < = 256 * 1024 ) {
timers = 3 ;
timers_shift = 20 ;
}
}
t3_write_reg ( adap , A_TP_PMM_SIZE ,
p - > chan_rx_size | ( p - > chan_tx_size > > 16 ) ) ;
t3_write_reg ( adap , A_TP_PMM_TX_BASE , 0 ) ;
t3_write_reg ( adap , A_TP_PMM_TX_PAGE_SIZE , p - > tx_pg_size ) ;
t3_write_reg ( adap , A_TP_PMM_TX_MAX_PAGE , p - > tx_num_pgs ) ;
t3_set_reg_field ( adap , A_TP_PARA_REG3 , V_TXDATAACKIDX ( M_TXDATAACKIDX ) ,
V_TXDATAACKIDX ( fls ( p - > tx_pg_size ) - 12 ) ) ;
t3_write_reg ( adap , A_TP_PMM_RX_BASE , 0 ) ;
t3_write_reg ( adap , A_TP_PMM_RX_PAGE_SIZE , p - > rx_pg_size ) ;
t3_write_reg ( adap , A_TP_PMM_RX_MAX_PAGE , p - > rx_num_pgs ) ;
pstructs = p - > rx_num_pgs + p - > tx_num_pgs ;
/* Add a bit of headroom and make multiple of 24 */
pstructs + = 48 ;
pstructs - = pstructs % 24 ;
t3_write_reg ( adap , A_TP_CMM_MM_MAX_PSTRUCT , pstructs ) ;
m = tids * TCB_SIZE ;
mem_region ( adap , m , ( 64 < < 10 ) * 64 , SG_EGR_CNTX_BADDR ) ;
mem_region ( adap , m , ( 64 < < 10 ) * 64 , SG_CQ_CONTEXT_BADDR ) ;
t3_write_reg ( adap , A_TP_CMM_TIMER_BASE , V_CMTIMERMAXNUM ( timers ) | m ) ;
m + = ( ( p - > ntimer_qs - 1 ) < < timers_shift ) + ( 1 < < 22 ) ;
mem_region ( adap , m , pstructs * 64 , TP_CMM_MM_BASE ) ;
mem_region ( adap , m , 64 * ( pstructs / 24 ) , TP_CMM_MM_PS_FLST_BASE ) ;
mem_region ( adap , m , 64 * ( p - > rx_num_pgs / 24 ) , TP_CMM_MM_RX_FLST_BASE ) ;
mem_region ( adap , m , 64 * ( p - > tx_num_pgs / 24 ) , TP_CMM_MM_TX_FLST_BASE ) ;
m = ( m + 4095 ) & ~ 0xfff ;
t3_write_reg ( adap , A_CIM_SDRAM_BASE_ADDR , m ) ;
t3_write_reg ( adap , A_CIM_SDRAM_ADDR_SIZE , p - > cm_size - m ) ;
tids = ( p - > cm_size - m - ( 3 < < 20 ) ) / 3072 - 32 ;
m = t3_mc5_size ( & adap - > mc5 ) - adap - > params . mc5 . nservers -
adap - > params . mc5 . nfilters - adap - > params . mc5 . nroutes ;
if ( tids < m )
adap - > params . mc5 . nservers + = m - tids ;
}
static inline void tp_wr_indirect ( struct adapter * adap , unsigned int addr ,
u32 val )
{
t3_write_reg ( adap , A_TP_PIO_ADDR , addr ) ;
t3_write_reg ( adap , A_TP_PIO_DATA , val ) ;
}
static void tp_config ( struct adapter * adap , const struct tp_params * p )
{
unsigned int v ;
t3_write_reg ( adap , A_TP_GLOBAL_CONFIG , F_TXPACINGENABLE | F_PATHMTU |
F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
F_TCPCHECKSUMOFFLOAD | V_IPTTL ( 64 ) ) ;
t3_write_reg ( adap , A_TP_TCP_OPTIONS , V_MTUDEFAULT ( 576 ) |
F_MTUENABLE | V_WINDOWSCALEMODE ( 1 ) |
V_TIMESTAMPSMODE ( 1 ) | V_SACKMODE ( 1 ) | V_SACKRX ( 1 ) ) ;
t3_write_reg ( adap , A_TP_DACK_CONFIG , V_AUTOSTATE3 ( 1 ) |
V_AUTOSTATE2 ( 1 ) | V_AUTOSTATE1 ( 0 ) |
V_BYTETHRESHOLD ( 16384 ) | V_MSSTHRESHOLD ( 2 ) |
F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE ( 1 ) ) ;
t3_set_reg_field ( adap , A_TP_IN_CONFIG , F_IPV6ENABLE | F_NICMODE ,
F_IPV6ENABLE | F_NICMODE ) ;
t3_write_reg ( adap , A_TP_TX_RESOURCE_LIMIT , 0x18141814 ) ;
t3_write_reg ( adap , A_TP_PARA_REG4 , 0x5050105 ) ;
t3_set_reg_field ( adap , A_TP_PARA_REG6 ,
adap - > params . rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND ,
0 ) ;
v = t3_read_reg ( adap , A_TP_PC_CONFIG ) ;
v & = ~ ( F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL ) ;
t3_write_reg ( adap , A_TP_PC_CONFIG , v | F_TXDEFERENABLE |
F_MODULATEUNIONMODE | F_HEARBEATDACK |
F_TXCONGESTIONMODE | F_RXCONGESTIONMODE ) ;
v = t3_read_reg ( adap , A_TP_PC_CONFIG2 ) ;
v & = ~ F_CHDRAFULL ;
t3_write_reg ( adap , A_TP_PC_CONFIG2 , v ) ;
if ( adap - > params . rev > 0 ) {
tp_wr_indirect ( adap , A_TP_EGRESS_CONFIG , F_REWRITEFORCETOSIZE ) ;
t3_set_reg_field ( adap , A_TP_PARA_REG3 , F_TXPACEAUTO ,
F_TXPACEAUTO ) ;
t3_set_reg_field ( adap , A_TP_PC_CONFIG , F_LOCKTID , F_LOCKTID ) ;
t3_set_reg_field ( adap , A_TP_PARA_REG3 , 0 , F_TXPACEAUTOSTRICT ) ;
} else
t3_set_reg_field ( adap , A_TP_PARA_REG3 , 0 , F_TXPACEFIXED ) ;
t3_write_reg ( adap , A_TP_TX_MOD_QUEUE_WEIGHT1 , 0x12121212 ) ;
t3_write_reg ( adap , A_TP_TX_MOD_QUEUE_WEIGHT0 , 0x12121212 ) ;
t3_write_reg ( adap , A_TP_MOD_CHANNEL_WEIGHT , 0x1212 ) ;
}
/* Desired TP timer resolution in usec */
# define TP_TMR_RES 50
/* TCP timer values in ms */
# define TP_DACK_TIMER 50
# define TP_RTO_MIN 250
/**
* tp_set_timers - set TP timing parameters
* @ adap : the adapter to set
* @ core_clk : the core clock frequency in Hz
*
* Set TP ' s timing parameters , such as the various timer resolutions and
* the TCP timer values .
*/
static void tp_set_timers ( struct adapter * adap , unsigned int core_clk )
{
unsigned int tre = fls ( core_clk / ( 1000000 / TP_TMR_RES ) ) - 1 ;
unsigned int dack_re = fls ( core_clk / 5000 ) - 1 ; /* 200us */
unsigned int tstamp_re = fls ( core_clk / 1000 ) ; /* 1ms, at least */
unsigned int tps = core_clk > > tre ;
t3_write_reg ( adap , A_TP_TIMER_RESOLUTION , V_TIMERRESOLUTION ( tre ) |
V_DELAYEDACKRESOLUTION ( dack_re ) |
V_TIMESTAMPRESOLUTION ( tstamp_re ) ) ;
t3_write_reg ( adap , A_TP_DACK_TIMER ,
( core_clk > > dack_re ) / ( 1000 / TP_DACK_TIMER ) ) ;
t3_write_reg ( adap , A_TP_TCP_BACKOFF_REG0 , 0x3020100 ) ;
t3_write_reg ( adap , A_TP_TCP_BACKOFF_REG1 , 0x7060504 ) ;
t3_write_reg ( adap , A_TP_TCP_BACKOFF_REG2 , 0xb0a0908 ) ;
t3_write_reg ( adap , A_TP_TCP_BACKOFF_REG3 , 0xf0e0d0c ) ;
t3_write_reg ( adap , A_TP_SHIFT_CNT , V_SYNSHIFTMAX ( 6 ) |
V_RXTSHIFTMAXR1 ( 4 ) | V_RXTSHIFTMAXR2 ( 15 ) |
V_PERSHIFTBACKOFFMAX ( 8 ) | V_PERSHIFTMAX ( 8 ) |
V_KEEPALIVEMAX ( 9 ) ) ;
# define SECONDS * tps
t3_write_reg ( adap , A_TP_MSL , adap - > params . rev > 0 ? 0 : 2 SECONDS ) ;
t3_write_reg ( adap , A_TP_RXT_MIN , tps / ( 1000 / TP_RTO_MIN ) ) ;
t3_write_reg ( adap , A_TP_RXT_MAX , 64 SECONDS ) ;
t3_write_reg ( adap , A_TP_PERS_MIN , 5 SECONDS ) ;
t3_write_reg ( adap , A_TP_PERS_MAX , 64 SECONDS ) ;
t3_write_reg ( adap , A_TP_KEEP_IDLE , 7200 SECONDS ) ;
t3_write_reg ( adap , A_TP_KEEP_INTVL , 75 SECONDS ) ;
t3_write_reg ( adap , A_TP_INIT_SRTT , 3 SECONDS ) ;
t3_write_reg ( adap , A_TP_FINWAIT2_TIMER , 600 SECONDS ) ;
# undef SECONDS
}
/**
* t3_tp_set_coalescing_size - set receive coalescing size
* @ adap : the adapter
* @ size : the receive coalescing size
* @ psh : whether a set PSH bit should deliver coalesced data
*
* Set the receive coalescing size and PSH bit handling .
*/
int t3_tp_set_coalescing_size ( struct adapter * adap , unsigned int size , int psh )
{
u32 val ;
if ( size > MAX_RX_COALESCING_LEN )
return - EINVAL ;
val = t3_read_reg ( adap , A_TP_PARA_REG3 ) ;
val & = ~ ( F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN ) ;
if ( size ) {
val | = F_RXCOALESCEENABLE ;
if ( psh )
val | = F_RXCOALESCEPSHEN ;
t3_write_reg ( adap , A_TP_PARA_REG2 , V_RXCOALESCESIZE ( size ) |
V_MAXRXDATA ( MAX_RX_COALESCING_LEN ) ) ;
}
t3_write_reg ( adap , A_TP_PARA_REG3 , val ) ;
return 0 ;
}
/**
* t3_tp_set_max_rxsize - set the max receive size
* @ adap : the adapter
* @ size : the max receive size
*
* Set TP ' s max receive size . This is the limit that applies when
* receive coalescing is disabled .
*/
void t3_tp_set_max_rxsize ( struct adapter * adap , unsigned int size )
{
t3_write_reg ( adap , A_TP_PARA_REG7 ,
V_PMMAXXFERLEN0 ( size ) | V_PMMAXXFERLEN1 ( size ) ) ;
}
static void __devinit init_mtus ( unsigned short mtus [ ] )
{
/*
* See draft - mathis - plpmtud - 00. txt for the values . The min is 88 so
* it can accomodate max size TCP / IP headers when SACK and timestamps
* are enabled and still have at least 8 bytes of payload .
*/
mtus [ 0 ] = 88 ;
mtus [ 1 ] = 256 ;
mtus [ 2 ] = 512 ;
mtus [ 3 ] = 576 ;
mtus [ 4 ] = 808 ;
mtus [ 5 ] = 1024 ;
mtus [ 6 ] = 1280 ;
mtus [ 7 ] = 1492 ;
mtus [ 8 ] = 1500 ;
mtus [ 9 ] = 2002 ;
mtus [ 10 ] = 2048 ;
mtus [ 11 ] = 4096 ;
mtus [ 12 ] = 4352 ;
mtus [ 13 ] = 8192 ;
mtus [ 14 ] = 9000 ;
mtus [ 15 ] = 9600 ;
}
/*
* Initial congestion control parameters .
*/
static void __devinit init_cong_ctrl ( unsigned short * a , unsigned short * b )
{
a [ 0 ] = a [ 1 ] = a [ 2 ] = a [ 3 ] = a [ 4 ] = a [ 5 ] = a [ 6 ] = a [ 7 ] = a [ 8 ] = 1 ;
a [ 9 ] = 2 ;
a [ 10 ] = 3 ;
a [ 11 ] = 4 ;
a [ 12 ] = 5 ;
a [ 13 ] = 6 ;
a [ 14 ] = 7 ;
a [ 15 ] = 8 ;
a [ 16 ] = 9 ;
a [ 17 ] = 10 ;
a [ 18 ] = 14 ;
a [ 19 ] = 17 ;
a [ 20 ] = 21 ;
a [ 21 ] = 25 ;
a [ 22 ] = 30 ;
a [ 23 ] = 35 ;
a [ 24 ] = 45 ;
a [ 25 ] = 60 ;
a [ 26 ] = 80 ;
a [ 27 ] = 100 ;
a [ 28 ] = 200 ;
a [ 29 ] = 300 ;
a [ 30 ] = 400 ;
a [ 31 ] = 500 ;
b [ 0 ] = b [ 1 ] = b [ 2 ] = b [ 3 ] = b [ 4 ] = b [ 5 ] = b [ 6 ] = b [ 7 ] = b [ 8 ] = 0 ;
b [ 9 ] = b [ 10 ] = 1 ;
b [ 11 ] = b [ 12 ] = 2 ;
b [ 13 ] = b [ 14 ] = b [ 15 ] = b [ 16 ] = 3 ;
b [ 17 ] = b [ 18 ] = b [ 19 ] = b [ 20 ] = b [ 21 ] = 4 ;
b [ 22 ] = b [ 23 ] = b [ 24 ] = b [ 25 ] = b [ 26 ] = b [ 27 ] = 5 ;
b [ 28 ] = b [ 29 ] = 6 ;
b [ 30 ] = b [ 31 ] = 7 ;
}
/* The minimum additive increment value for the congestion control table */
# define CC_MIN_INCR 2U
/**
* t3_load_mtus - write the MTU and congestion control HW tables
* @ adap : the adapter
* @ mtus : the unrestricted values for the MTU table
* @ alphs : the values for the congestion control alpha parameter
* @ beta : the values for the congestion control beta parameter
* @ mtu_cap : the maximum permitted effective MTU
*
* Write the MTU table with the supplied MTUs capping each at & mtu_cap .
* Update the high - speed congestion control table with the supplied alpha ,
* beta , and MTUs .
*/
void t3_load_mtus ( struct adapter * adap , unsigned short mtus [ NMTUS ] ,
unsigned short alpha [ NCCTRL_WIN ] ,
unsigned short beta [ NCCTRL_WIN ] , unsigned short mtu_cap )
{
static const unsigned int avg_pkts [ NCCTRL_WIN ] = {
2 , 6 , 10 , 14 , 20 , 28 , 40 , 56 , 80 , 112 , 160 , 224 , 320 , 448 , 640 ,
896 , 1281 , 1792 , 2560 , 3584 , 5120 , 7168 , 10240 , 14336 , 20480 ,
28672 , 40960 , 57344 , 81920 , 114688 , 163840 , 229376
} ;
unsigned int i , w ;
for ( i = 0 ; i < NMTUS ; + + i ) {
unsigned int mtu = min ( mtus [ i ] , mtu_cap ) ;
unsigned int log2 = fls ( mtu ) ;
if ( ! ( mtu & ( ( 1 < < log2 ) > > 2 ) ) ) /* round */
log2 - - ;
t3_write_reg ( adap , A_TP_MTU_TABLE ,
( i < < 24 ) | ( log2 < < 16 ) | mtu ) ;
for ( w = 0 ; w < NCCTRL_WIN ; + + w ) {
unsigned int inc ;
inc = max ( ( ( mtu - 40 ) * alpha [ w ] ) / avg_pkts [ w ] ,
CC_MIN_INCR ) ;
t3_write_reg ( adap , A_TP_CCTRL_TABLE , ( i < < 21 ) |
( w < < 16 ) | ( beta [ w ] < < 13 ) | inc ) ;
}
}
}
/**
* t3_read_hw_mtus - returns the values in the HW MTU table
* @ adap : the adapter
* @ mtus : where to store the HW MTU values
*
* Reads the HW MTU table .
*/
void t3_read_hw_mtus ( struct adapter * adap , unsigned short mtus [ NMTUS ] )
{
int i ;
for ( i = 0 ; i < NMTUS ; + + i ) {
unsigned int val ;
t3_write_reg ( adap , A_TP_MTU_TABLE , 0xff000000 | i ) ;
val = t3_read_reg ( adap , A_TP_MTU_TABLE ) ;
mtus [ i ] = val & 0x3fff ;
}
}
/**
* t3_get_cong_cntl_tab - reads the congestion control table
* @ adap : the adapter
* @ incr : where to store the alpha values
*
* Reads the additive increments programmed into the HW congestion
* control table .
*/
void t3_get_cong_cntl_tab ( struct adapter * adap ,
unsigned short incr [ NMTUS ] [ NCCTRL_WIN ] )
{
unsigned int mtu , w ;
for ( mtu = 0 ; mtu < NMTUS ; + + mtu )
for ( w = 0 ; w < NCCTRL_WIN ; + + w ) {
t3_write_reg ( adap , A_TP_CCTRL_TABLE ,
0xffff0000 | ( mtu < < 5 ) | w ) ;
incr [ mtu ] [ w ] = t3_read_reg ( adap , A_TP_CCTRL_TABLE ) &
0x1fff ;
}
}
/**
* t3_tp_get_mib_stats - read TP ' s MIB counters
* @ adap : the adapter
* @ tps : holds the returned counter values
*
* Returns the values of TP ' s MIB counters .
*/
void t3_tp_get_mib_stats ( struct adapter * adap , struct tp_mib_stats * tps )
{
t3_read_indirect ( adap , A_TP_MIB_INDEX , A_TP_MIB_RDATA , ( u32 * ) tps ,
sizeof ( * tps ) / sizeof ( u32 ) , 0 ) ;
}
# define ulp_region(adap, name, start, len) \
t3_write_reg ( ( adap ) , A_ULPRX_ # # name # # _LLIMIT , ( start ) ) ; \
t3_write_reg ( ( adap ) , A_ULPRX_ # # name # # _ULIMIT , \
( start ) + ( len ) - 1 ) ; \
start + = len
# define ulptx_region(adap, name, start, len) \
t3_write_reg ( ( adap ) , A_ULPTX_ # # name # # _LLIMIT , ( start ) ) ; \
t3_write_reg ( ( adap ) , A_ULPTX_ # # name # # _ULIMIT , \
( start ) + ( len ) - 1 )
static void ulp_config ( struct adapter * adap , const struct tp_params * p )
{
unsigned int m = p - > chan_rx_size ;
ulp_region ( adap , ISCSI , m , p - > chan_rx_size / 8 ) ;
ulp_region ( adap , TDDP , m , p - > chan_rx_size / 8 ) ;
ulptx_region ( adap , TPT , m , p - > chan_rx_size / 4 ) ;
ulp_region ( adap , STAG , m , p - > chan_rx_size / 4 ) ;
ulp_region ( adap , RQ , m , p - > chan_rx_size / 4 ) ;
ulptx_region ( adap , PBL , m , p - > chan_rx_size / 4 ) ;
ulp_region ( adap , PBL , m , p - > chan_rx_size / 4 ) ;
t3_write_reg ( adap , A_ULPRX_TDDP_TAGMASK , 0xffffffff ) ;
}
void t3_config_trace_filter ( struct adapter * adapter ,
const struct trace_params * tp , int filter_index ,
int invert , int enable )
{
u32 addr , key [ 4 ] , mask [ 4 ] ;
key [ 0 ] = tp - > sport | ( tp - > sip < < 16 ) ;
key [ 1 ] = ( tp - > sip > > 16 ) | ( tp - > dport < < 16 ) ;
key [ 2 ] = tp - > dip ;
key [ 3 ] = tp - > proto | ( tp - > vlan < < 8 ) | ( tp - > intf < < 20 ) ;
mask [ 0 ] = tp - > sport_mask | ( tp - > sip_mask < < 16 ) ;
mask [ 1 ] = ( tp - > sip_mask > > 16 ) | ( tp - > dport_mask < < 16 ) ;
mask [ 2 ] = tp - > dip_mask ;
mask [ 3 ] = tp - > proto_mask | ( tp - > vlan_mask < < 8 ) | ( tp - > intf_mask < < 20 ) ;
if ( invert )
key [ 3 ] | = ( 1 < < 29 ) ;
if ( enable )
key [ 3 ] | = ( 1 < < 28 ) ;
addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0 ;
tp_wr_indirect ( adapter , addr + + , key [ 0 ] ) ;
tp_wr_indirect ( adapter , addr + + , mask [ 0 ] ) ;
tp_wr_indirect ( adapter , addr + + , key [ 1 ] ) ;
tp_wr_indirect ( adapter , addr + + , mask [ 1 ] ) ;
tp_wr_indirect ( adapter , addr + + , key [ 2 ] ) ;
tp_wr_indirect ( adapter , addr + + , mask [ 2 ] ) ;
tp_wr_indirect ( adapter , addr + + , key [ 3 ] ) ;
tp_wr_indirect ( adapter , addr , mask [ 3 ] ) ;
t3_read_reg ( adapter , A_TP_PIO_DATA ) ;
}
/**
* t3_config_sched - configure a HW traffic scheduler
* @ adap : the adapter
* @ kbps : target rate in Kbps
* @ sched : the scheduler index
*
* Configure a HW scheduler for the target rate
*/
int t3_config_sched ( struct adapter * adap , unsigned int kbps , int sched )
{
unsigned int v , tps , cpt , bpt , delta , mindelta = ~ 0 ;
unsigned int clk = adap - > params . vpd . cclk * 1000 ;
unsigned int selected_cpt = 0 , selected_bpt = 0 ;
if ( kbps > 0 ) {
kbps * = 125 ; /* -> bytes */
for ( cpt = 1 ; cpt < = 255 ; cpt + + ) {
tps = clk / cpt ;
bpt = ( kbps + tps / 2 ) / tps ;
if ( bpt > 0 & & bpt < = 255 ) {
v = bpt * tps ;
delta = v > = kbps ? v - kbps : kbps - v ;
if ( delta < = mindelta ) {
mindelta = delta ;
selected_cpt = cpt ;
selected_bpt = bpt ;
}
} else if ( selected_cpt )
break ;
}
if ( ! selected_cpt )
return - EINVAL ;
}
t3_write_reg ( adap , A_TP_TM_PIO_ADDR ,
A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2 ) ;
v = t3_read_reg ( adap , A_TP_TM_PIO_DATA ) ;
if ( sched & 1 )
v = ( v & 0xffff ) | ( selected_cpt < < 16 ) | ( selected_bpt < < 24 ) ;
else
v = ( v & 0xffff0000 ) | selected_cpt | ( selected_bpt < < 8 ) ;
t3_write_reg ( adap , A_TP_TM_PIO_DATA , v ) ;
return 0 ;
}
static int tp_init ( struct adapter * adap , const struct tp_params * p )
{
int busy = 0 ;
tp_config ( adap , p ) ;
t3_set_vlan_accel ( adap , 3 , 0 ) ;
if ( is_offload ( adap ) ) {
tp_set_timers ( adap , adap - > params . vpd . cclk * 1000 ) ;
t3_write_reg ( adap , A_TP_RESET , F_FLSTINITENABLE ) ;
busy = t3_wait_op_done ( adap , A_TP_RESET , F_FLSTINITENABLE ,
0 , 1000 , 5 ) ;
if ( busy )
CH_ERR ( adap , " TP initialization timed out \n " ) ;
}
if ( ! busy )
t3_write_reg ( adap , A_TP_RESET , F_TPRESET ) ;
return busy ;
}
int t3_mps_set_active_ports ( struct adapter * adap , unsigned int port_mask )
{
if ( port_mask & ~ ( ( 1 < < adap - > params . nports ) - 1 ) )
return - EINVAL ;
t3_set_reg_field ( adap , A_MPS_CFG , F_PORT1ACTIVE | F_PORT0ACTIVE ,
port_mask < < S_PORT0ACTIVE ) ;
return 0 ;
}
/*
* Perform the bits of HW initialization that are dependent on the number
* of available ports .
*/
static void init_hw_for_avail_ports ( struct adapter * adap , int nports )
{
int i ;
if ( nports = = 1 ) {
t3_set_reg_field ( adap , A_ULPRX_CTL , F_ROUND_ROBIN , 0 ) ;
t3_set_reg_field ( adap , A_ULPTX_CONFIG , F_CFG_RR_ARB , 0 ) ;
t3_write_reg ( adap , A_MPS_CFG , F_TPRXPORTEN | F_TPTXPORT0EN |
F_PORT0ACTIVE | F_ENFORCEPKT ) ;
t3_write_reg ( adap , A_PM1_TX_CFG , 0xc000c000 ) ;
} else {
t3_set_reg_field ( adap , A_ULPRX_CTL , 0 , F_ROUND_ROBIN ) ;
t3_set_reg_field ( adap , A_ULPTX_CONFIG , 0 , F_CFG_RR_ARB ) ;
t3_write_reg ( adap , A_ULPTX_DMA_WEIGHT ,
V_D1_WEIGHT ( 16 ) | V_D0_WEIGHT ( 16 ) ) ;
t3_write_reg ( adap , A_MPS_CFG , F_TPTXPORT0EN | F_TPTXPORT1EN |
F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
F_ENFORCEPKT ) ;
t3_write_reg ( adap , A_PM1_TX_CFG , 0x80008000 ) ;
t3_set_reg_field ( adap , A_TP_PC_CONFIG , 0 , F_TXTOSQUEUEMAPMODE ) ;
t3_write_reg ( adap , A_TP_TX_MOD_QUEUE_REQ_MAP ,
V_TX_MOD_QUEUE_REQ_MAP ( 0xaa ) ) ;
for ( i = 0 ; i < 16 ; i + + )
t3_write_reg ( adap , A_TP_TX_MOD_QUE_TABLE ,
( i < < 16 ) | 0x1010 ) ;
}
}
static int calibrate_xgm ( struct adapter * adapter )
{
if ( uses_xaui ( adapter ) ) {
unsigned int v , i ;
for ( i = 0 ; i < 5 ; + + i ) {
t3_write_reg ( adapter , A_XGM_XAUI_IMP , 0 ) ;
t3_read_reg ( adapter , A_XGM_XAUI_IMP ) ;
msleep ( 1 ) ;
v = t3_read_reg ( adapter , A_XGM_XAUI_IMP ) ;
if ( ! ( v & ( F_XGM_CALFAULT | F_CALBUSY ) ) ) {
t3_write_reg ( adapter , A_XGM_XAUI_IMP ,
V_XAUIIMP ( G_CALIMP ( v ) > > 2 ) ) ;
return 0 ;
}
}
CH_ERR ( adapter , " MAC calibration failed \n " ) ;
return - 1 ;
} else {
t3_write_reg ( adapter , A_XGM_RGMII_IMP ,
V_RGMIIIMPPD ( 2 ) | V_RGMIIIMPPU ( 3 ) ) ;
t3_set_reg_field ( adapter , A_XGM_RGMII_IMP , F_XGM_IMPSETUPDATE ,
F_XGM_IMPSETUPDATE ) ;
}
return 0 ;
}
static void calibrate_xgm_t3b ( struct adapter * adapter )
{
if ( ! uses_xaui ( adapter ) ) {
t3_write_reg ( adapter , A_XGM_RGMII_IMP , F_CALRESET |
F_CALUPDATE | V_RGMIIIMPPD ( 2 ) | V_RGMIIIMPPU ( 3 ) ) ;
t3_set_reg_field ( adapter , A_XGM_RGMII_IMP , F_CALRESET , 0 ) ;
t3_set_reg_field ( adapter , A_XGM_RGMII_IMP , 0 ,
F_XGM_IMPSETUPDATE ) ;
t3_set_reg_field ( adapter , A_XGM_RGMII_IMP , F_XGM_IMPSETUPDATE ,
0 ) ;
t3_set_reg_field ( adapter , A_XGM_RGMII_IMP , F_CALUPDATE , 0 ) ;
t3_set_reg_field ( adapter , A_XGM_RGMII_IMP , 0 , F_CALUPDATE ) ;
}
}
struct mc7_timing_params {
unsigned char ActToPreDly ;
unsigned char ActToRdWrDly ;
unsigned char PreCyc ;
unsigned char RefCyc [ 5 ] ;
unsigned char BkCyc ;
unsigned char WrToRdDly ;
unsigned char RdToWrDly ;
} ;
/*
* Write a value to a register and check that the write completed . These
* writes normally complete in a cycle or two , so one read should suffice .
* The very first read exists to flush the posted write to the device .
*/
static int wrreg_wait ( struct adapter * adapter , unsigned int addr , u32 val )
{
t3_write_reg ( adapter , addr , val ) ;
t3_read_reg ( adapter , addr ) ; /* flush */
if ( ! ( t3_read_reg ( adapter , addr ) & F_BUSY ) )
return 0 ;
CH_ERR ( adapter , " write to MC7 register 0x%x timed out \n " , addr ) ;
return - EIO ;
}
static int mc7_init ( struct mc7 * mc7 , unsigned int mc7_clock , int mem_type )
{
static const unsigned int mc7_mode [ ] = {
0x632 , 0x642 , 0x652 , 0x432 , 0x442
} ;
static const struct mc7_timing_params mc7_timings [ ] = {
{ 12 , 3 , 4 , { 20 , 28 , 34 , 52 , 0 } , 15 , 6 , 4 } ,
{ 12 , 4 , 5 , { 20 , 28 , 34 , 52 , 0 } , 16 , 7 , 4 } ,
{ 12 , 5 , 6 , { 20 , 28 , 34 , 52 , 0 } , 17 , 8 , 4 } ,
{ 9 , 3 , 4 , { 15 , 21 , 26 , 39 , 0 } , 12 , 6 , 4 } ,
{ 9 , 4 , 5 , { 15 , 21 , 26 , 39 , 0 } , 13 , 7 , 4 }
} ;
u32 val ;
unsigned int width , density , slow , attempts ;
struct adapter * adapter = mc7 - > adapter ;
const struct mc7_timing_params * p = & mc7_timings [ mem_type ] ;
val = t3_read_reg ( adapter , mc7 - > offset + A_MC7_CFG ) ;
slow = val & F_SLOW ;
width = G_WIDTH ( val ) ;
density = G_DEN ( val ) ;
t3_write_reg ( adapter , mc7 - > offset + A_MC7_CFG , val | F_IFEN ) ;
val = t3_read_reg ( adapter , mc7 - > offset + A_MC7_CFG ) ; /* flush */
msleep ( 1 ) ;
if ( ! slow ) {
t3_write_reg ( adapter , mc7 - > offset + A_MC7_CAL , F_SGL_CAL_EN ) ;
t3_read_reg ( adapter , mc7 - > offset + A_MC7_CAL ) ;
msleep ( 1 ) ;
if ( t3_read_reg ( adapter , mc7 - > offset + A_MC7_CAL ) &
( F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT ) ) {
CH_ERR ( adapter , " %s MC7 calibration timed out \n " ,
mc7 - > name ) ;
goto out_fail ;
}
}
t3_write_reg ( adapter , mc7 - > offset + A_MC7_PARM ,
V_ACTTOPREDLY ( p - > ActToPreDly ) |
V_ACTTORDWRDLY ( p - > ActToRdWrDly ) | V_PRECYC ( p - > PreCyc ) |
V_REFCYC ( p - > RefCyc [ density ] ) | V_BKCYC ( p - > BkCyc ) |
V_WRTORDDLY ( p - > WrToRdDly ) | V_RDTOWRDLY ( p - > RdToWrDly ) ) ;
t3_write_reg ( adapter , mc7 - > offset + A_MC7_CFG ,
val | F_CLKEN | F_TERM150 ) ;
t3_read_reg ( adapter , mc7 - > offset + A_MC7_CFG ) ; /* flush */
if ( ! slow )
t3_set_reg_field ( adapter , mc7 - > offset + A_MC7_DLL , F_DLLENB ,
F_DLLENB ) ;
udelay ( 1 ) ;
val = slow ? 3 : 6 ;
if ( wrreg_wait ( adapter , mc7 - > offset + A_MC7_PRE , 0 ) | |
wrreg_wait ( adapter , mc7 - > offset + A_MC7_EXT_MODE2 , 0 ) | |
wrreg_wait ( adapter , mc7 - > offset + A_MC7_EXT_MODE3 , 0 ) | |
wrreg_wait ( adapter , mc7 - > offset + A_MC7_EXT_MODE1 , val ) )
goto out_fail ;
if ( ! slow ) {
t3_write_reg ( adapter , mc7 - > offset + A_MC7_MODE , 0x100 ) ;
t3_set_reg_field ( adapter , mc7 - > offset + A_MC7_DLL , F_DLLRST , 0 ) ;
udelay ( 5 ) ;
}
if ( wrreg_wait ( adapter , mc7 - > offset + A_MC7_PRE , 0 ) | |
wrreg_wait ( adapter , mc7 - > offset + A_MC7_REF , 0 ) | |
wrreg_wait ( adapter , mc7 - > offset + A_MC7_REF , 0 ) | |
wrreg_wait ( adapter , mc7 - > offset + A_MC7_MODE ,
mc7_mode [ mem_type ] ) | |
wrreg_wait ( adapter , mc7 - > offset + A_MC7_EXT_MODE1 , val | 0x380 ) | |
wrreg_wait ( adapter , mc7 - > offset + A_MC7_EXT_MODE1 , val ) )
goto out_fail ;
/* clock value is in KHz */
mc7_clock = mc7_clock * 7812 + mc7_clock / 2 ; /* ns */
mc7_clock / = 1000000 ; /* KHz->MHz, ns->us */
t3_write_reg ( adapter , mc7 - > offset + A_MC7_REF ,
F_PERREFEN | V_PREREFDIV ( mc7_clock ) ) ;
t3_read_reg ( adapter , mc7 - > offset + A_MC7_REF ) ; /* flush */
t3_write_reg ( adapter , mc7 - > offset + A_MC7_ECC , F_ECCGENEN | F_ECCCHKEN ) ;
t3_write_reg ( adapter , mc7 - > offset + A_MC7_BIST_DATA , 0 ) ;
t3_write_reg ( adapter , mc7 - > offset + A_MC7_BIST_ADDR_BEG , 0 ) ;
t3_write_reg ( adapter , mc7 - > offset + A_MC7_BIST_ADDR_END ,
( mc7 - > size < < width ) - 1 ) ;
t3_write_reg ( adapter , mc7 - > offset + A_MC7_BIST_OP , V_OP ( 1 ) ) ;
t3_read_reg ( adapter , mc7 - > offset + A_MC7_BIST_OP ) ; /* flush */
attempts = 50 ;
do {
msleep ( 250 ) ;
val = t3_read_reg ( adapter , mc7 - > offset + A_MC7_BIST_OP ) ;
} while ( ( val & F_BUSY ) & & - - attempts ) ;
if ( val & F_BUSY ) {
CH_ERR ( adapter , " %s MC7 BIST timed out \n " , mc7 - > name ) ;
goto out_fail ;
}
/* Enable normal memory accesses. */
t3_set_reg_field ( adapter , mc7 - > offset + A_MC7_CFG , 0 , F_RDY ) ;
return 0 ;
out_fail :
return - 1 ;
}
static void config_pcie ( struct adapter * adap )
{
static const u16 ack_lat [ 4 ] [ 6 ] = {
{ 237 , 416 , 559 , 1071 , 2095 , 4143 } ,
{ 128 , 217 , 289 , 545 , 1057 , 2081 } ,
{ 73 , 118 , 154 , 282 , 538 , 1050 } ,
{ 67 , 107 , 86 , 150 , 278 , 534 }
} ;
static const u16 rpl_tmr [ 4 ] [ 6 ] = {
{ 711 , 1248 , 1677 , 3213 , 6285 , 12429 } ,
{ 384 , 651 , 867 , 1635 , 3171 , 6243 } ,
{ 219 , 354 , 462 , 846 , 1614 , 3150 } ,
{ 201 , 321 , 258 , 450 , 834 , 1602 }
} ;
u16 val ;
unsigned int log2_width , pldsize ;
unsigned int fst_trn_rx , fst_trn_tx , acklat , rpllmt ;
pci_read_config_word ( adap - > pdev ,
adap - > params . pci . pcie_cap_addr + PCI_EXP_DEVCTL ,
& val ) ;
pldsize = ( val & PCI_EXP_DEVCTL_PAYLOAD ) > > 5 ;
pci_read_config_word ( adap - > pdev ,
adap - > params . pci . pcie_cap_addr + PCI_EXP_LNKCTL ,
& val ) ;
fst_trn_tx = G_NUMFSTTRNSEQ ( t3_read_reg ( adap , A_PCIE_PEX_CTRL0 ) ) ;
fst_trn_rx = adap - > params . rev = = 0 ? fst_trn_tx :
G_NUMFSTTRNSEQRX ( t3_read_reg ( adap , A_PCIE_MODE ) ) ;
log2_width = fls ( adap - > params . pci . width ) - 1 ;
acklat = ack_lat [ log2_width ] [ pldsize ] ;
if ( val & 1 ) /* check LOsEnable */
acklat + = fst_trn_tx * 4 ;
rpllmt = rpl_tmr [ log2_width ] [ pldsize ] + fst_trn_rx * 4 ;
if ( adap - > params . rev = = 0 )
t3_set_reg_field ( adap , A_PCIE_PEX_CTRL1 ,
V_T3A_ACKLAT ( M_T3A_ACKLAT ) ,
V_T3A_ACKLAT ( acklat ) ) ;
else
t3_set_reg_field ( adap , A_PCIE_PEX_CTRL1 , V_ACKLAT ( M_ACKLAT ) ,
V_ACKLAT ( acklat ) ) ;
t3_set_reg_field ( adap , A_PCIE_PEX_CTRL0 , V_REPLAYLMT ( M_REPLAYLMT ) ,
V_REPLAYLMT ( rpllmt ) ) ;
t3_write_reg ( adap , A_PCIE_PEX_ERR , 0xffffffff ) ;
t3_set_reg_field ( adap , A_PCIE_CFG , F_PCIE_CLIDECEN , F_PCIE_CLIDECEN ) ;
}
/*
* Initialize and configure T3 HW modules . This performs the
* initialization steps that need to be done once after a card is reset .
* MAC and PHY initialization is handled separarely whenever a port is enabled .
*
* fw_params are passed to FW and their value is platform dependent . Only the
* top 8 bits are available for use , the rest must be 0.
*/
int t3_init_hw ( struct adapter * adapter , u32 fw_params )
{
int err = - EIO , attempts = 100 ;
const struct vpd_params * vpd = & adapter - > params . vpd ;
if ( adapter - > params . rev > 0 )
calibrate_xgm_t3b ( adapter ) ;
else if ( calibrate_xgm ( adapter ) )
goto out_err ;
if ( vpd - > mclk ) {
partition_mem ( adapter , & adapter - > params . tp ) ;
if ( mc7_init ( & adapter - > pmrx , vpd - > mclk , vpd - > mem_timing ) | |
mc7_init ( & adapter - > pmtx , vpd - > mclk , vpd - > mem_timing ) | |
mc7_init ( & adapter - > cm , vpd - > mclk , vpd - > mem_timing ) | |
t3_mc5_init ( & adapter - > mc5 , adapter - > params . mc5 . nservers ,
adapter - > params . mc5 . nfilters ,
adapter - > params . mc5 . nroutes ) )
goto out_err ;
}
if ( tp_init ( adapter , & adapter - > params . tp ) )
goto out_err ;
t3_tp_set_coalescing_size ( adapter ,
min ( adapter - > params . sge . max_pkt_size ,
MAX_RX_COALESCING_LEN ) , 1 ) ;
t3_tp_set_max_rxsize ( adapter ,
min ( adapter - > params . sge . max_pkt_size , 16384U ) ) ;
ulp_config ( adapter , & adapter - > params . tp ) ;
if ( is_pcie ( adapter ) )
config_pcie ( adapter ) ;
else
t3_set_reg_field ( adapter , A_PCIX_CFG , 0 , F_CLIDECEN ) ;
t3_write_reg ( adapter , A_PM1_RX_CFG , 0xf000f000 ) ;
init_hw_for_avail_ports ( adapter , adapter - > params . nports ) ;
t3_sge_init ( adapter , & adapter - > params . sge ) ;
t3_write_reg ( adapter , A_CIM_HOST_ACC_DATA , vpd - > uclk | fw_params ) ;
t3_write_reg ( adapter , A_CIM_BOOT_CFG ,
V_BOOTADDR ( FW_FLASH_BOOT_ADDR > > 2 ) ) ;
t3_read_reg ( adapter , A_CIM_BOOT_CFG ) ; /* flush */
do { /* wait for uP to initialize */
msleep ( 20 ) ;
} while ( t3_read_reg ( adapter , A_CIM_HOST_ACC_DATA ) & & - - attempts ) ;
if ( ! attempts )
goto out_err ;
err = 0 ;
out_err :
return err ;
}
/**
* get_pci_mode - determine a card ' s PCI mode
* @ adapter : the adapter
* @ p : where to store the PCI settings
*
* Determines a card ' s PCI mode and associated parameters , such as speed
* and width .
*/
static void __devinit get_pci_mode ( struct adapter * adapter ,
struct pci_params * p )
{
static unsigned short speed_map [ ] = { 33 , 66 , 100 , 133 } ;
u32 pci_mode , pcie_cap ;
pcie_cap = pci_find_capability ( adapter - > pdev , PCI_CAP_ID_EXP ) ;
if ( pcie_cap ) {
u16 val ;
p - > variant = PCI_VARIANT_PCIE ;
p - > pcie_cap_addr = pcie_cap ;
pci_read_config_word ( adapter - > pdev , pcie_cap + PCI_EXP_LNKSTA ,
& val ) ;
p - > width = ( val > > 4 ) & 0x3f ;
return ;
}
pci_mode = t3_read_reg ( adapter , A_PCIX_MODE ) ;
p - > speed = speed_map [ G_PCLKRANGE ( pci_mode ) ] ;
p - > width = ( pci_mode & F_64BIT ) ? 64 : 32 ;
pci_mode = G_PCIXINITPAT ( pci_mode ) ;
if ( pci_mode = = 0 )
p - > variant = PCI_VARIANT_PCI ;
else if ( pci_mode < 4 )
p - > variant = PCI_VARIANT_PCIX_MODE1_PARITY ;
else if ( pci_mode < 8 )
p - > variant = PCI_VARIANT_PCIX_MODE1_ECC ;
else
p - > variant = PCI_VARIANT_PCIX_266_MODE2 ;
}
/**
* init_link_config - initialize a link ' s SW state
* @ lc : structure holding the link state
* @ ai : information about the current card
*
* Initializes the SW state maintained for each link , including the link ' s
* capabilities and default speed / duplex / flow - control / autonegotiation
* settings .
*/
static void __devinit init_link_config ( struct link_config * lc ,
unsigned int caps )
{
lc - > supported = caps ;
lc - > requested_speed = lc - > speed = SPEED_INVALID ;
lc - > requested_duplex = lc - > duplex = DUPLEX_INVALID ;
lc - > requested_fc = lc - > fc = PAUSE_RX | PAUSE_TX ;
if ( lc - > supported & SUPPORTED_Autoneg ) {
lc - > advertising = lc - > supported ;
lc - > autoneg = AUTONEG_ENABLE ;
lc - > requested_fc | = PAUSE_AUTONEG ;
} else {
lc - > advertising = 0 ;
lc - > autoneg = AUTONEG_DISABLE ;
}
}
/**
* mc7_calc_size - calculate MC7 memory size
* @ cfg : the MC7 configuration
*
* Calculates the size of an MC7 memory in bytes from the value of its
* configuration register .
*/
static unsigned int __devinit mc7_calc_size ( u32 cfg )
{
unsigned int width = G_WIDTH ( cfg ) ;
unsigned int banks = ! ! ( cfg & F_BKS ) + 1 ;
unsigned int org = ! ! ( cfg & F_ORG ) + 1 ;
unsigned int density = G_DEN ( cfg ) ;
unsigned int MBs = ( ( 256 < < density ) * banks ) / ( org < < width ) ;
return MBs < < 20 ;
}
static void __devinit mc7_prep ( struct adapter * adapter , struct mc7 * mc7 ,
unsigned int base_addr , const char * name )
{
u32 cfg ;
mc7 - > adapter = adapter ;
mc7 - > name = name ;
mc7 - > offset = base_addr - MC7_PMRX_BASE_ADDR ;
cfg = t3_read_reg ( adapter , mc7 - > offset + A_MC7_CFG ) ;
mc7 - > size = mc7_calc_size ( cfg ) ;
mc7 - > width = G_WIDTH ( cfg ) ;
}
void mac_prep ( struct cmac * mac , struct adapter * adapter , int index )
{
mac - > adapter = adapter ;
mac - > offset = ( XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR ) * index ;
mac - > nucast = 1 ;
if ( adapter - > params . rev = = 0 & & uses_xaui ( adapter ) ) {
t3_write_reg ( adapter , A_XGM_SERDES_CTRL + mac - > offset ,
is_10G ( adapter ) ? 0x2901c04 : 0x2301c04 ) ;
t3_set_reg_field ( adapter , A_XGM_PORT_CFG + mac - > offset ,
F_ENRGMII , 0 ) ;
}
}
void early_hw_init ( struct adapter * adapter , const struct adapter_info * ai )
{
u32 val = V_PORTSPEED ( is_10G ( adapter ) ? 3 : 2 ) ;
mi1_init ( adapter , ai ) ;
t3_write_reg ( adapter , A_I2C_CFG , /* set for 80KHz */
V_I2C_CLKDIV ( adapter - > params . vpd . cclk / 80 - 1 ) ) ;
t3_write_reg ( adapter , A_T3DBG_GPIO_EN ,
ai - > gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL ) ;
if ( adapter - > params . rev = = 0 | | ! uses_xaui ( adapter ) )
val | = F_ENRGMII ;
/* Enable MAC clocks so we can access the registers */
t3_write_reg ( adapter , A_XGM_PORT_CFG , val ) ;
t3_read_reg ( adapter , A_XGM_PORT_CFG ) ;
val | = F_CLKDIVRESET_ ;
t3_write_reg ( adapter , A_XGM_PORT_CFG , val ) ;
t3_read_reg ( adapter , A_XGM_PORT_CFG ) ;
t3_write_reg ( adapter , XGM_REG ( A_XGM_PORT_CFG , 1 ) , val ) ;
t3_read_reg ( adapter , A_XGM_PORT_CFG ) ;
}
/*
* Reset the adapter . PCIe cards lose their config space during reset , PCI - X
* ones don ' t .
*/
int t3_reset_adapter ( struct adapter * adapter )
{
int i ;
uint16_t devid = 0 ;
if ( is_pcie ( adapter ) )
pci_save_state ( adapter - > pdev ) ;
t3_write_reg ( adapter , A_PL_RST , F_CRSTWRM | F_CRSTWRMMODE ) ;
/*
* Delay . Give Some time to device to reset fully .
* XXX The delay time should be modified .
*/
for ( i = 0 ; i < 10 ; i + + ) {
msleep ( 50 ) ;
pci_read_config_word ( adapter - > pdev , 0x00 , & devid ) ;
if ( devid = = 0x1425 )
break ;
}
if ( devid ! = 0x1425 )
return - 1 ;
if ( is_pcie ( adapter ) )
pci_restore_state ( adapter - > pdev ) ;
return 0 ;
}
/*
* Initialize adapter SW state for the various HW modules , set initial values
* for some adapter tunables , take PHYs out of reset , and initialize the MDIO
* interface .
*/
int __devinit t3_prep_adapter ( struct adapter * adapter ,
const struct adapter_info * ai , int reset )
{
int ret ;
unsigned int i , j = 0 ;
get_pci_mode ( adapter , & adapter - > params . pci ) ;
adapter - > params . info = ai ;
adapter - > params . nports = ai - > nports ;
adapter - > params . rev = t3_read_reg ( adapter , A_PL_REV ) ;
adapter - > params . linkpoll_period = 0 ;
adapter - > params . stats_update_period = is_10G ( adapter ) ?
MAC_STATS_ACCUM_SECS : ( MAC_STATS_ACCUM_SECS * 10 ) ;
adapter - > params . pci . vpd_cap_addr =
pci_find_capability ( adapter - > pdev , PCI_CAP_ID_VPD ) ;
ret = get_vpd_params ( adapter , & adapter - > params . vpd ) ;
if ( ret < 0 )
return ret ;
if ( reset & & t3_reset_adapter ( adapter ) )
return - 1 ;
t3_sge_prep ( adapter , & adapter - > params . sge ) ;
if ( adapter - > params . vpd . mclk ) {
struct tp_params * p = & adapter - > params . tp ;
mc7_prep ( adapter , & adapter - > pmrx , MC7_PMRX_BASE_ADDR , " PMRX " ) ;
mc7_prep ( adapter , & adapter - > pmtx , MC7_PMTX_BASE_ADDR , " PMTX " ) ;
mc7_prep ( adapter , & adapter - > cm , MC7_CM_BASE_ADDR , " CM " ) ;
p - > nchan = ai - > nports ;
p - > pmrx_size = t3_mc7_size ( & adapter - > pmrx ) ;
p - > pmtx_size = t3_mc7_size ( & adapter - > pmtx ) ;
p - > cm_size = t3_mc7_size ( & adapter - > cm ) ;
p - > chan_rx_size = p - > pmrx_size / 2 ; /* only 1 Rx channel */
p - > chan_tx_size = p - > pmtx_size / p - > nchan ;
p - > rx_pg_size = 64 * 1024 ;
p - > tx_pg_size = is_10G ( adapter ) ? 64 * 1024 : 16 * 1024 ;
p - > rx_num_pgs = pm_num_pages ( p - > chan_rx_size , p - > rx_pg_size ) ;
p - > tx_num_pgs = pm_num_pages ( p - > chan_tx_size , p - > tx_pg_size ) ;
p - > ntimer_qs = p - > cm_size > = ( 128 < < 20 ) | |
adapter - > params . rev > 0 ? 12 : 6 ;
adapter - > params . mc5 . nservers = DEFAULT_NSERVERS ;
adapter - > params . mc5 . nfilters = adapter - > params . rev > 0 ?
DEFAULT_NFILTERS : 0 ;
adapter - > params . mc5 . nroutes = 0 ;
t3_mc5_prep ( adapter , & adapter - > mc5 , MC5_MODE_144_BIT ) ;
init_mtus ( adapter - > params . mtus ) ;
init_cong_ctrl ( adapter - > params . a_wnd , adapter - > params . b_wnd ) ;
}
early_hw_init ( adapter , ai ) ;
for_each_port ( adapter , i ) {
u8 hw_addr [ 6 ] ;
struct port_info * p = adap2pinfo ( adapter , i ) ;
while ( ! adapter - > params . vpd . port_type [ j ] )
+ + j ;
p - > port_type = & port_types [ adapter - > params . vpd . port_type [ j ] ] ;
p - > port_type - > phy_prep ( & p - > phy , adapter , ai - > phy_base_addr + j ,
ai - > mdio_ops ) ;
mac_prep ( & p - > mac , adapter , j ) ;
+ + j ;
/*
* The VPD EEPROM stores the base Ethernet address for the
* card . A port ' s address is derived from the base by adding
* the port ' s index to the base ' s low octet .
*/
memcpy ( hw_addr , adapter - > params . vpd . eth_base , 5 ) ;
hw_addr [ 5 ] = adapter - > params . vpd . eth_base [ 5 ] + i ;
memcpy ( adapter - > port [ i ] - > dev_addr , hw_addr ,
ETH_ALEN ) ;
memcpy ( adapter - > port [ i ] - > perm_addr , hw_addr ,
ETH_ALEN ) ;
init_link_config ( & p - > link_config , p - > port_type - > caps ) ;
p - > phy . ops - > power_down ( & p - > phy , 1 ) ;
if ( ! ( p - > port_type - > caps & SUPPORTED_IRQ ) )
adapter - > params . linkpoll_period = 10 ;
}
return 0 ;
}
void t3_led_ready ( struct adapter * adapter )
{
t3_set_reg_field ( adapter , A_T3DBG_GPIO_EN , F_GPIO0_OUT_VAL ,
F_GPIO0_OUT_VAL ) ;
}