2005-08-16 16:36:49 -07:00
/*
* New driver for Marvell Yukon 2 chipset .
* Based on earlier sk98lin , and skge driver .
*
* This driver intentionally does not support all the features
* of the original driver such as link fail - over and link management because
* those should be done at higher levels .
*
* Copyright ( C ) 2005 Stephen Hemminger < shemminger @ osdl . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2005-09-14 16:06:14 -07:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2005-08-16 16:36:49 -07:00
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2005-09-14 16:06:14 -07:00
# include <linux/crc32.h>
2005-08-16 16:36:49 -07:00
# include <linux/kernel.h>
# include <linux/version.h>
# include <linux/module.h>
# include <linux/netdevice.h>
2005-11-10 15:29:27 -08:00
# include <linux/dma-mapping.h>
2005-08-16 16:36:49 -07:00
# include <linux/etherdevice.h>
# include <linux/ethtool.h>
# include <linux/pci.h>
# include <linux/ip.h>
# include <linux/tcp.h>
# include <linux/in.h>
# include <linux/delay.h>
2005-12-09 11:34:57 -08:00
# include <linux/workqueue.h>
2005-09-27 15:02:57 -07:00
# include <linux/if_vlan.h>
2005-12-09 11:35:09 -08:00
# include <linux/prefetch.h>
2005-11-30 11:45:12 -08:00
# include <linux/mii.h>
2005-08-16 16:36:49 -07:00
# include <asm/irq.h>
2005-09-27 15:02:57 -07:00
# if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
# define SKY2_VLAN_TAG_USED 1
# endif
2005-08-16 16:36:49 -07:00
# include "sky2.h"
# define DRV_NAME "sky2"
2006-08-28 10:00:53 -07:00
# define DRV_VERSION "1.7"
2005-08-16 16:36:49 -07:00
# define PFX DRV_NAME " "
/*
* The Yukon II chipset takes 64 bit command blocks ( called list elements )
* that are organized into three ( receive , transmit , status ) different rings
* similar to Tigon3 . A transmit can require several elements ;
* a receive requires one ( or two if using 64 bit dma ) .
*/
2005-11-30 11:45:14 -08:00
# define RX_LE_SIZE 512
2005-08-16 16:36:49 -07:00
# define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le))
2005-10-26 12:16:10 -07:00
# define RX_MAX_PENDING (RX_LE_SIZE / 2 - 2)
2005-11-30 11:45:14 -08:00
# define RX_DEF_PENDING RX_MAX_PENDING
2006-01-17 13:43:10 -08:00
# define RX_SKB_ALIGN 8
2006-07-12 15:23:48 -07:00
# define RX_BUF_WRITE 16
2005-09-14 16:06:14 -07:00
# define TX_RING_SIZE 512
# define TX_DEF_PENDING (TX_RING_SIZE - 1)
# define TX_MIN_PENDING 64
2006-03-07 11:06:36 -08:00
# define MAX_SKB_TX_LE (4 + (sizeof(dma_addr_t) / sizeof(u32))*MAX_SKB_FRAGS)
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
# define STATUS_RING_SIZE 2048 /* 2 ports * (TX + 2*RX) */
2005-08-16 16:36:49 -07:00
# define STATUS_LE_BYTES (STATUS_RING_SIZE*sizeof(struct sky2_status_le))
# define ETH_JUMBO_MTU 9000
# define TX_WATCHDOG (5 * HZ)
# define NAPI_WEIGHT 64
# define PHY_RETRIES 1000
2006-05-08 15:11:29 -07:00
# define RING_NEXT(x,s) (((x)+1) & ((s)-1))
2005-08-16 16:36:49 -07:00
static const u32 default_msg =
2005-09-14 16:06:14 -07:00
NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
| NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR
2006-01-17 13:43:17 -08:00
| NETIF_MSG_IFUP | NETIF_MSG_IFDOWN ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
static int debug = - 1 ; /* defaults above */
2005-08-16 16:36:49 -07:00
module_param ( debug , int , 0 ) ;
MODULE_PARM_DESC ( debug , " Debug level (0=none,...,16=all) " ) ;
2005-12-09 11:34:55 -08:00
static int copybreak __read_mostly = 256 ;
module_param ( copybreak , int , 0 ) ;
MODULE_PARM_DESC ( copybreak , " Receive copy threshold " ) ;
2006-03-20 15:48:19 -08:00
static int disable_msi = 0 ;
module_param ( disable_msi , int , 0 ) ;
MODULE_PARM_DESC ( disable_msi , " Disable Message Signaled Interrupt (MSI) " ) ;
2006-05-08 15:11:30 -07:00
static int idle_timeout = 100 ;
module_param ( idle_timeout , int , 0 ) ;
MODULE_PARM_DESC ( idle_timeout , " Idle timeout workaround for lost interrupts (ms) " ) ;
2005-08-16 16:36:49 -07:00
static const struct pci_device_id sky2_id_table [ ] = {
2005-09-14 16:06:14 -07:00
{ PCI_DEVICE ( PCI_VENDOR_ID_SYSKONNECT , 0x9000 ) } ,
2005-08-16 16:36:49 -07:00
{ PCI_DEVICE ( PCI_VENDOR_ID_SYSKONNECT , 0x9E00 ) } ,
2006-05-17 14:37:04 -07:00
{ PCI_DEVICE ( PCI_VENDOR_ID_DLINK , 0x4b00 ) } , /* DGE-560T */
2006-09-01 14:52:04 -07:00
{ PCI_DEVICE ( PCI_VENDOR_ID_DLINK , 0x4001 ) } , /* DGE-550SX */
2005-08-16 16:36:49 -07:00
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4340 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4341 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4342 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4343 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4344 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4345 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4346 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4347 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4350 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4351 ) } ,
2005-11-30 11:45:15 -08:00
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4352 ) } ,
2006-09-01 14:52:04 -07:00
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4353 ) } ,
2005-08-16 16:36:49 -07:00
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4360 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4361 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4362 ) } ,
2005-11-30 11:45:15 -08:00
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4363 ) } ,
2006-07-17 15:38:32 -04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4364 ) } ,
2006-07-29 17:21:55 -07:00
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4365 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4366 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4367 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4368 ) } ,
2006-09-01 14:52:04 -07:00
{ PCI_DEVICE ( PCI_VENDOR_ID_MARVELL , 0x4369 ) } ,
2005-08-16 16:36:49 -07:00
{ 0 }
} ;
2005-09-14 16:06:14 -07:00
2005-08-16 16:36:49 -07:00
MODULE_DEVICE_TABLE ( pci , sky2_id_table ) ;
/* Avoid conditionals by using array */
static const unsigned txqaddr [ ] = { Q_XA1 , Q_XA2 } ;
static const unsigned rxqaddr [ ] = { Q_R1 , Q_R2 } ;
2006-05-09 14:46:54 -07:00
static const u32 portirq_msk [ ] = { Y2_IS_PORT_1 , Y2_IS_PORT_2 } ;
2005-08-16 16:36:49 -07:00
2005-12-09 11:34:53 -08:00
/* This driver supports yukon2 chipset only */
static const char * yukon2_name [ ] = {
" XL " , /* 0xb3 */
" EC Ultra " , /* 0xb4 */
" UNKNOWN " , /* 0xb5 */
" EC " , /* 0xb6 */
" FE " , /* 0xb7 */
2005-09-14 16:06:14 -07:00
} ;
/* Access to external PHY */
2005-11-30 11:45:12 -08:00
static int gm_phy_write ( struct sky2_hw * hw , unsigned port , u16 reg , u16 val )
2005-08-16 16:36:49 -07:00
{
int i ;
gma_write16 ( hw , port , GM_SMI_DATA , val ) ;
gma_write16 ( hw , port , GM_SMI_CTRL ,
GM_SMI_CT_PHY_AD ( PHY_ADDR_MARV ) | GM_SMI_CT_REG_AD ( reg ) ) ;
for ( i = 0 ; i < PHY_RETRIES ; i + + ) {
if ( ! ( gma_read16 ( hw , port , GM_SMI_CTRL ) & GM_SMI_CT_BUSY ) )
2005-11-30 11:45:12 -08:00
return 0 ;
2005-09-14 16:06:14 -07:00
udelay ( 1 ) ;
2005-08-16 16:36:49 -07:00
}
2005-11-30 11:45:12 -08:00
2005-09-14 16:06:14 -07:00
printk ( KERN_WARNING PFX " %s: phy write timeout \n " , hw - > dev [ port ] - > name ) ;
2005-11-30 11:45:12 -08:00
return - ETIMEDOUT ;
2005-08-16 16:36:49 -07:00
}
2005-11-30 11:45:12 -08:00
static int __gm_phy_read ( struct sky2_hw * hw , unsigned port , u16 reg , u16 * val )
2005-08-16 16:36:49 -07:00
{
int i ;
2005-09-14 16:06:14 -07:00
gma_write16 ( hw , port , GM_SMI_CTRL , GM_SMI_CT_PHY_AD ( PHY_ADDR_MARV )
2005-08-16 16:36:49 -07:00
| GM_SMI_CT_REG_AD ( reg ) | GM_SMI_CT_OP_RD ) ;
for ( i = 0 ; i < PHY_RETRIES ; i + + ) {
2005-11-30 11:45:12 -08:00
if ( gma_read16 ( hw , port , GM_SMI_CTRL ) & GM_SMI_CT_RD_VAL ) {
* val = gma_read16 ( hw , port , GM_SMI_DATA ) ;
return 0 ;
}
2005-09-14 16:06:14 -07:00
udelay ( 1 ) ;
2005-08-16 16:36:49 -07:00
}
2005-11-30 11:45:12 -08:00
return - ETIMEDOUT ;
}
static u16 gm_phy_read ( struct sky2_hw * hw , unsigned port , u16 reg )
{
u16 v ;
if ( __gm_phy_read ( hw , port , reg , & v ) ! = 0 )
printk ( KERN_WARNING PFX " %s: phy read timeout \n " , hw - > dev [ port ] - > name ) ;
return v ;
2005-08-16 16:36:49 -07:00
}
2006-06-13 17:17:27 +09:00
static void sky2_set_power_state ( struct sky2_hw * hw , pci_power_t state )
2005-09-27 15:03:00 -07:00
{
u16 power_control ;
int vaux ;
pr_debug ( " sky2_set_power_state %d \n " , state ) ;
sky2_write8 ( hw , B2_TST_CTRL1 , TST_CFG_WRITE_ON ) ;
2006-02-22 11:45:02 -08:00
power_control = sky2_pci_read16 ( hw , hw - > pm_cap + PCI_PM_PMC ) ;
2006-01-30 11:37:54 -08:00
vaux = ( sky2_read16 ( hw , B0_CTST ) & Y2_VAUX_AVAIL ) & &
2005-09-27 15:03:00 -07:00
( power_control & PCI_PM_CAP_PME_D3cold ) ;
2006-02-22 11:45:02 -08:00
power_control = sky2_pci_read16 ( hw , hw - > pm_cap + PCI_PM_CTRL ) ;
2005-09-27 15:03:00 -07:00
power_control | = PCI_PM_CTRL_PME_STATUS ;
power_control & = ~ ( PCI_PM_CTRL_STATE_MASK ) ;
switch ( state ) {
case PCI_D0 :
/* switch power to VCC (WA for VAUX problem) */
sky2_write8 ( hw , B0_POWER_CTRL ,
PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON ) ;
/* disable Core Clock Division, */
sky2_write32 ( hw , B2_Y2_CLK_CTRL , Y2_CLK_DIV_DIS ) ;
if ( hw - > chip_id = = CHIP_ID_YUKON_XL & & hw - > chip_rev > 1 )
/* enable bits are inverted */
sky2_write8 ( hw , B2_Y2_CLK_GATE ,
Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS ) ;
else
sky2_write8 ( hw , B2_Y2_CLK_GATE , 0 ) ;
2006-02-22 11:44:58 -08:00
if ( hw - > chip_id = = CHIP_ID_YUKON_EC_U ) {
2006-08-28 10:00:51 -07:00
u32 reg1 ;
2006-02-22 11:45:02 -08:00
sky2_pci_write32 ( hw , PCI_DEV_REG3 , 0 ) ;
reg1 = sky2_pci_read32 ( hw , PCI_DEV_REG4 ) ;
2006-02-22 11:44:58 -08:00
reg1 & = P_ASPM_CONTROL_MSK ;
2006-02-22 11:45:02 -08:00
sky2_pci_write32 ( hw , PCI_DEV_REG4 , reg1 ) ;
sky2_pci_write32 ( hw , PCI_DEV_REG5 , 0 ) ;
2006-02-22 11:44:58 -08:00
}
2005-09-27 15:03:00 -07:00
break ;
case PCI_D3hot :
case PCI_D3cold :
if ( hw - > chip_id = = CHIP_ID_YUKON_XL & & hw - > chip_rev > 1 )
sky2_write8 ( hw , B2_Y2_CLK_GATE , 0 ) ;
else
/* enable bits are inverted */
sky2_write8 ( hw , B2_Y2_CLK_GATE ,
Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS ) ;
/* switch power to VAUX */
if ( vaux & & state ! = PCI_D3cold )
sky2_write8 ( hw , B0_POWER_CTRL ,
( PC_VAUX_ENA | PC_VCC_ENA |
PC_VAUX_ON | PC_VCC_OFF ) ) ;
break ;
default :
printk ( KERN_ERR PFX " Unknown power state %d \n " , state ) ;
}
2006-02-22 11:45:02 -08:00
sky2_pci_write16 ( hw , hw - > pm_cap + PCI_PM_CTRL , power_control ) ;
2005-09-27 15:03:00 -07:00
sky2_write8 ( hw , B2_TST_CTRL1 , TST_CFG_WRITE_OFF ) ;
}
2006-08-28 10:00:51 -07:00
static void sky2_gmac_reset ( struct sky2_hw * hw , unsigned port )
2005-08-16 16:36:49 -07:00
{
u16 reg ;
/* disable all GMAC IRQ's */
sky2_write8 ( hw , SK_REG ( port , GMAC_IRQ_MSK ) , 0 ) ;
/* disable PHY IRQs */
gm_phy_write ( hw , port , PHY_MARV_INT_MASK , 0 ) ;
2005-09-14 16:06:14 -07:00
2005-08-16 16:36:49 -07:00
gma_write16 ( hw , port , GM_MC_ADDR_H1 , 0 ) ; /* clear MC hash */
gma_write16 ( hw , port , GM_MC_ADDR_H2 , 0 ) ;
gma_write16 ( hw , port , GM_MC_ADDR_H3 , 0 ) ;
gma_write16 ( hw , port , GM_MC_ADDR_H4 , 0 ) ;
reg = gma_read16 ( hw , port , GM_RX_CTRL ) ;
reg | = GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA ;
gma_write16 ( hw , port , GM_RX_CTRL , reg ) ;
}
static void sky2_phy_init ( struct sky2_hw * hw , unsigned port )
{
struct sky2_port * sky2 = netdev_priv ( hw - > dev [ port ] ) ;
2006-09-06 12:44:47 -07:00
u16 ctrl , ct1000 , adv , pg , ledctrl , ledover , reg ;
2005-08-16 16:36:49 -07:00
2006-05-08 15:11:33 -07:00
if ( sky2 - > autoneg = = AUTONEG_ENABLE & &
2006-05-17 14:37:05 -07:00
! ( hw - > chip_id = = CHIP_ID_YUKON_XL | | hw - > chip_id = = CHIP_ID_YUKON_EC_U ) ) {
2005-08-16 16:36:49 -07:00
u16 ectrl = gm_phy_read ( hw , port , PHY_MARV_EXT_CTRL ) ;
ectrl & = ~ ( PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
2005-09-14 16:06:14 -07:00
PHY_M_EC_MAC_S_MSK ) ;
2005-08-16 16:36:49 -07:00
ectrl | = PHY_M_EC_MAC_S ( MAC_TX_CLK_25_MHZ ) ;
if ( hw - > chip_id = = CHIP_ID_YUKON_EC )
ectrl | = PHY_M_EC_DSC_2 ( 2 ) | PHY_M_EC_DOWN_S_ENA ;
else
ectrl | = PHY_M_EC_M_DSC ( 2 ) | PHY_M_EC_S_DSC ( 3 ) ;
gm_phy_write ( hw , port , PHY_MARV_EXT_CTRL , ectrl ) ;
}
ctrl = gm_phy_read ( hw , port , PHY_MARV_PHY_CTRL ) ;
2006-09-06 12:44:53 -07:00
if ( sky2_is_copper ( hw ) ) {
2005-08-16 16:36:49 -07:00
if ( hw - > chip_id = = CHIP_ID_YUKON_FE ) {
/* enable automatic crossover */
ctrl | = PHY_M_PC_MDI_XMODE ( PHY_M_PC_ENA_AUTO ) > > 1 ;
} else {
/* disable energy detect */
ctrl & = ~ PHY_M_PC_EN_DET_MSK ;
/* enable automatic crossover */
ctrl | = PHY_M_PC_MDI_XMODE ( PHY_M_PC_ENA_AUTO ) ;
if ( sky2 - > autoneg = = AUTONEG_ENABLE & &
2006-05-08 15:11:33 -07:00
( hw - > chip_id = = CHIP_ID_YUKON_XL | | hw - > chip_id = = CHIP_ID_YUKON_EC_U ) ) {
2005-08-16 16:36:49 -07:00
ctrl & = ~ PHY_M_PC_DSC_MSK ;
ctrl | = PHY_M_PC_DSC ( 2 ) | PHY_M_PC_DOWN_S_ENA ;
}
}
} else {
/* workaround for deviation #4.88 (CRC errors) */
/* disable Automatic Crossover */
ctrl & = ~ PHY_M_PC_MDIX_MSK ;
2006-09-06 12:44:53 -07:00
}
2005-08-16 16:36:49 -07:00
2006-09-06 12:44:53 -07:00
gm_phy_write ( hw , port , PHY_MARV_PHY_CTRL , ctrl ) ;
/* special setup for PHY 88E1112 Fiber */
if ( hw - > chip_id = = CHIP_ID_YUKON_XL & & ! sky2_is_copper ( hw ) ) {
pg = gm_phy_read ( hw , port , PHY_MARV_EXT_ADR ) ;
2005-08-16 16:36:49 -07:00
2006-09-06 12:44:53 -07:00
/* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , 2 ) ;
ctrl = gm_phy_read ( hw , port , PHY_MARV_PHY_CTRL ) ;
ctrl & = ~ PHY_M_MAC_MD_MSK ;
ctrl | = PHY_M_MAC_MODE_SEL ( PHY_M_MAC_MD_1000BX ) ;
gm_phy_write ( hw , port , PHY_MARV_PHY_CTRL , ctrl ) ;
if ( hw - > pmd_type = = ' P ' ) {
2005-08-16 16:36:49 -07:00
/* select page 1 to access Fiber registers */
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , 1 ) ;
2006-09-06 12:44:53 -07:00
/* for SFP-module set SIGDET polarity to low */
ctrl = gm_phy_read ( hw , port , PHY_MARV_PHY_CTRL ) ;
ctrl | = PHY_M_FIB_SIGD_POL ;
gm_phy_write ( hw , port , PHY_MARV_CTRL , ctrl ) ;
2005-08-16 16:36:49 -07:00
}
2006-09-06 12:44:53 -07:00
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , pg ) ;
2005-08-16 16:36:49 -07:00
}
ctrl = gm_phy_read ( hw , port , PHY_MARV_CTRL ) ;
if ( sky2 - > autoneg = = AUTONEG_DISABLE )
ctrl & = ~ PHY_CT_ANE ;
else
ctrl | = PHY_CT_ANE ;
ctrl | = PHY_CT_RESET ;
gm_phy_write ( hw , port , PHY_MARV_CTRL , ctrl ) ;
ctrl = 0 ;
ct1000 = 0 ;
adv = PHY_AN_CSMA ;
2006-09-06 12:44:47 -07:00
reg = 0 ;
2005-08-16 16:36:49 -07:00
if ( sky2 - > autoneg = = AUTONEG_ENABLE ) {
2006-09-06 12:44:53 -07:00
if ( sky2_is_copper ( hw ) ) {
2005-08-16 16:36:49 -07:00
if ( sky2 - > advertising & ADVERTISED_1000baseT_Full )
ct1000 | = PHY_M_1000C_AFD ;
if ( sky2 - > advertising & ADVERTISED_1000baseT_Half )
ct1000 | = PHY_M_1000C_AHD ;
if ( sky2 - > advertising & ADVERTISED_100baseT_Full )
adv | = PHY_M_AN_100_FD ;
if ( sky2 - > advertising & ADVERTISED_100baseT_Half )
adv | = PHY_M_AN_100_HD ;
if ( sky2 - > advertising & ADVERTISED_10baseT_Full )
adv | = PHY_M_AN_10_FD ;
if ( sky2 - > advertising & ADVERTISED_10baseT_Half )
adv | = PHY_M_AN_10_HD ;
2006-09-06 12:44:53 -07:00
} else { /* special defines for FIBER (88E1040S only) */
if ( sky2 - > advertising & ADVERTISED_1000baseT_Full )
adv | = PHY_M_AN_1000X_AFD ;
if ( sky2 - > advertising & ADVERTISED_1000baseT_Half )
adv | = PHY_M_AN_1000X_AHD ;
}
2005-08-16 16:36:49 -07:00
/* Set Flow-control capabilities */
if ( sky2 - > tx_pause & & sky2 - > rx_pause )
2005-09-14 16:06:14 -07:00
adv | = PHY_AN_PAUSE_CAP ; /* symmetric */
2005-08-16 16:36:49 -07:00
else if ( sky2 - > rx_pause & & ! sky2 - > tx_pause )
2005-09-14 16:06:14 -07:00
adv | = PHY_AN_PAUSE_ASYM | PHY_AN_PAUSE_CAP ;
2005-08-16 16:36:49 -07:00
else if ( ! sky2 - > rx_pause & & sky2 - > tx_pause )
adv | = PHY_AN_PAUSE_ASYM ; /* local */
/* Restart Auto-negotiation */
ctrl | = PHY_CT_ANE | PHY_CT_RE_CFG ;
} else {
/* forced speed/duplex settings */
ct1000 = PHY_M_1000C_MSE ;
2006-09-06 12:44:47 -07:00
/* Disable auto update for duplex flow control and speed */
reg | = GM_GPCR_AU_ALL_DIS ;
2005-08-16 16:36:49 -07:00
switch ( sky2 - > speed ) {
case SPEED_1000 :
ctrl | = PHY_CT_SP1000 ;
2006-09-06 12:44:47 -07:00
reg | = GM_GPCR_SPEED_1000 ;
2005-08-16 16:36:49 -07:00
break ;
case SPEED_100 :
ctrl | = PHY_CT_SP100 ;
2006-09-06 12:44:47 -07:00
reg | = GM_GPCR_SPEED_100 ;
2005-08-16 16:36:49 -07:00
break ;
}
2006-09-06 12:44:47 -07:00
if ( sky2 - > duplex = = DUPLEX_FULL ) {
reg | = GM_GPCR_DUP_FULL ;
ctrl | = PHY_CT_DUP_MD ;
} else if ( sky2 - > speed ! = SPEED_1000 & & hw - > chip_id ! = CHIP_ID_YUKON_EC_U ) {
/* Turn off flow control for 10/100mbps */
sky2 - > rx_pause = 0 ;
sky2 - > tx_pause = 0 ;
}
if ( ! sky2 - > rx_pause )
reg | = GM_GPCR_FC_RX_DIS ;
if ( ! sky2 - > tx_pause )
reg | = GM_GPCR_FC_TX_DIS ;
/* Forward pause packets to GMAC? */
if ( sky2 - > tx_pause | | sky2 - > rx_pause )
sky2_write8 ( hw , SK_REG ( port , GMAC_CTRL ) , GMC_PAUSE_ON ) ;
else
sky2_write8 ( hw , SK_REG ( port , GMAC_CTRL ) , GMC_PAUSE_OFF ) ;
2005-08-16 16:36:49 -07:00
ctrl | = PHY_CT_RESET ;
}
2006-09-06 12:44:47 -07:00
gma_write16 ( hw , port , GM_GP_CTRL , reg ) ;
2005-08-16 16:36:49 -07:00
if ( hw - > chip_id ! = CHIP_ID_YUKON_FE )
gm_phy_write ( hw , port , PHY_MARV_1000T_CTRL , ct1000 ) ;
gm_phy_write ( hw , port , PHY_MARV_AUNE_ADV , adv ) ;
gm_phy_write ( hw , port , PHY_MARV_CTRL , ctrl ) ;
/* Setup Phy LED's */
ledctrl = PHY_M_LED_PULS_DUR ( PULS_170MS ) ;
ledover = 0 ;
switch ( hw - > chip_id ) {
case CHIP_ID_YUKON_FE :
/* on 88E3082 these bits are at 11..9 (shifted left) */
ledctrl | = PHY_M_LED_BLINK_RT ( BLINK_84MS ) < < 1 ;
ctrl = gm_phy_read ( hw , port , PHY_MARV_FE_LED_PAR ) ;
/* delete ACT LED control bits */
ctrl & = ~ PHY_M_FELP_LED1_MSK ;
/* change ACT LED control to blink mode */
ctrl | = PHY_M_FELP_LED1_CTRL ( LED_PAR_CTRL_ACT_BL ) ;
gm_phy_write ( hw , port , PHY_MARV_FE_LED_PAR , ctrl ) ;
break ;
case CHIP_ID_YUKON_XL :
2005-09-14 16:06:14 -07:00
pg = gm_phy_read ( hw , port , PHY_MARV_EXT_ADR ) ;
2005-08-16 16:36:49 -07:00
/* select page 3 to access LED control register */
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , 3 ) ;
/* set LED Function Control register */
2006-05-08 15:11:33 -07:00
gm_phy_write ( hw , port , PHY_MARV_PHY_CTRL ,
( PHY_M_LEDC_LOS_CTRL ( 1 ) | /* LINK/ACT */
PHY_M_LEDC_INIT_CTRL ( 7 ) | /* 10 Mbps */
PHY_M_LEDC_STA1_CTRL ( 7 ) | /* 100 Mbps */
PHY_M_LEDC_STA0_CTRL ( 7 ) ) ) ; /* 1000 Mbps */
2005-08-16 16:36:49 -07:00
/* set Polarity Control register */
gm_phy_write ( hw , port , PHY_MARV_PHY_STAT ,
2005-09-14 16:06:14 -07:00
( PHY_M_POLC_LS1_P_MIX ( 4 ) |
PHY_M_POLC_IS0_P_MIX ( 4 ) |
PHY_M_POLC_LOS_CTRL ( 2 ) |
PHY_M_POLC_INIT_CTRL ( 2 ) |
PHY_M_POLC_STA1_CTRL ( 2 ) |
PHY_M_POLC_STA0_CTRL ( 2 ) ) ) ;
2005-08-16 16:36:49 -07:00
/* restore page register */
2005-09-14 16:06:14 -07:00
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , pg ) ;
2005-08-16 16:36:49 -07:00
break ;
2006-05-08 15:11:33 -07:00
case CHIP_ID_YUKON_EC_U :
pg = gm_phy_read ( hw , port , PHY_MARV_EXT_ADR ) ;
/* select page 3 to access LED control register */
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , 3 ) ;
/* set LED Function Control register */
gm_phy_write ( hw , port , PHY_MARV_PHY_CTRL ,
( PHY_M_LEDC_LOS_CTRL ( 1 ) | /* LINK/ACT */
PHY_M_LEDC_INIT_CTRL ( 8 ) | /* 10 Mbps */
PHY_M_LEDC_STA1_CTRL ( 7 ) | /* 100 Mbps */
PHY_M_LEDC_STA0_CTRL ( 7 ) ) ) ; /* 1000 Mbps */
/* set Blink Rate in LED Timer Control Register */
gm_phy_write ( hw , port , PHY_MARV_INT_MASK ,
ledctrl | PHY_M_LED_BLINK_RT ( BLINK_84MS ) ) ;
/* restore page register */
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , pg ) ;
break ;
2005-08-16 16:36:49 -07:00
default :
/* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
ledctrl | = PHY_M_LED_BLINK_RT ( BLINK_84MS ) | PHY_M_LEDC_TX_CTRL ;
/* turn off the Rx LED (LED_RX) */
ledover | = PHY_M_LED_MO_RX ( MO_LED_OFF ) ;
}
2006-05-08 15:11:33 -07:00
if ( hw - > chip_id = = CHIP_ID_YUKON_EC_U & & hw - > chip_rev = = CHIP_REV_YU_EC_A1 ) {
2006-02-22 11:44:58 -08:00
/* apply fixes in PHY AFE */
2006-05-08 15:11:33 -07:00
pg = gm_phy_read ( hw , port , PHY_MARV_EXT_ADR ) ;
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , 255 ) ;
2006-02-22 11:44:58 -08:00
/* increase differential signal amplitude in 10BASE-T */
2006-05-08 15:11:33 -07:00
gm_phy_write ( hw , port , 0x18 , 0xaa99 ) ;
gm_phy_write ( hw , port , 0x17 , 0x2011 ) ;
2005-08-16 16:36:49 -07:00
2006-02-22 11:44:58 -08:00
/* fix for IEEE A/B Symmetry failure in 1000BASE-T */
2006-05-08 15:11:33 -07:00
gm_phy_write ( hw , port , 0x18 , 0xa204 ) ;
gm_phy_write ( hw , port , 0x17 , 0x2002 ) ;
2006-02-22 11:44:58 -08:00
/* set page register to 0 */
2006-05-08 15:11:33 -07:00
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , pg ) ;
2006-02-22 11:44:58 -08:00
} else {
gm_phy_write ( hw , port , PHY_MARV_LED_CTRL , ledctrl ) ;
2005-08-16 16:36:49 -07:00
2006-02-22 11:44:58 -08:00
if ( sky2 - > autoneg = = AUTONEG_DISABLE | | sky2 - > speed = = SPEED_100 ) {
/* turn on 100 Mbps LED (LED_LINK100) */
ledover | = PHY_M_LED_MO_100 ( MO_LED_ON ) ;
}
2005-08-16 16:36:49 -07:00
2006-02-22 11:44:58 -08:00
if ( ledover )
gm_phy_write ( hw , port , PHY_MARV_LED_OVER , ledover ) ;
}
2006-09-06 12:44:47 -07:00
2005-10-26 12:16:09 -07:00
/* Enable phy interrupt on auto-negotiation complete (or link up) */
2005-08-16 16:36:49 -07:00
if ( sky2 - > autoneg = = AUTONEG_ENABLE )
gm_phy_write ( hw , port , PHY_MARV_INT_MASK , PHY_M_IS_AN_COMPL ) ;
else
gm_phy_write ( hw , port , PHY_MARV_INT_MASK , PHY_M_DEF_MSK ) ;
}
2006-08-28 10:00:51 -07:00
static void sky2_phy_power ( struct sky2_hw * hw , unsigned port , int onoff )
{
u32 reg1 ;
static const u32 phy_power [ ]
= { PCI_Y2_PHY1_POWD , PCI_Y2_PHY2_POWD } ;
/* looks like this XL is back asswards .. */
if ( hw - > chip_id = = CHIP_ID_YUKON_XL & & hw - > chip_rev > 1 )
onoff = ! onoff ;
reg1 = sky2_pci_read32 ( hw , PCI_DEV_REG1 ) ;
if ( onoff )
/* Turn off phy power saving */
reg1 & = ~ phy_power [ port ] ;
else
reg1 | = phy_power [ port ] ;
sky2_pci_write32 ( hw , PCI_DEV_REG1 , reg1 ) ;
2006-08-28 10:00:52 -07:00
sky2_pci_read32 ( hw , PCI_DEV_REG1 ) ;
2006-08-28 10:00:51 -07:00
udelay ( 100 ) ;
}
2005-12-20 15:08:07 -08:00
/* Force a renegotiation */
static void sky2_phy_reinit ( struct sky2_port * sky2 )
{
2006-03-20 15:48:17 -08:00
spin_lock_bh ( & sky2 - > phy_lock ) ;
2005-12-20 15:08:07 -08:00
sky2_phy_init ( sky2 - > hw , sky2 - > port ) ;
2006-03-20 15:48:17 -08:00
spin_unlock_bh ( & sky2 - > phy_lock ) ;
2005-12-20 15:08:07 -08:00
}
2005-08-16 16:36:49 -07:00
static void sky2_mac_init ( struct sky2_hw * hw , unsigned port )
{
struct sky2_port * sky2 = netdev_priv ( hw - > dev [ port ] ) ;
u16 reg ;
int i ;
const u8 * addr = hw - > dev [ port ] - > dev_addr ;
2005-11-30 11:45:13 -08:00
sky2_write32 ( hw , SK_REG ( port , GPHY_CTRL ) , GPC_RST_SET ) ;
sky2_write32 ( hw , SK_REG ( port , GPHY_CTRL ) , GPC_RST_CLR | GPC_ENA_PAUSE ) ;
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , SK_REG ( port , GMAC_CTRL ) , GMC_RST_CLR ) ;
2005-09-14 16:06:14 -07:00
if ( hw - > chip_id = = CHIP_ID_YUKON_XL & & hw - > chip_rev = = 0 & & port = = 1 ) {
2005-08-16 16:36:49 -07:00
/* WA DEV_472 -- looks like crossed wires on port 2 */
/* clear GMAC 1 Control reset */
sky2_write8 ( hw , SK_REG ( 0 , GMAC_CTRL ) , GMC_RST_CLR ) ;
do {
sky2_write8 ( hw , SK_REG ( 1 , GMAC_CTRL ) , GMC_RST_SET ) ;
sky2_write8 ( hw , SK_REG ( 1 , GMAC_CTRL ) , GMC_RST_CLR ) ;
} while ( gm_phy_read ( hw , 1 , PHY_MARV_ID0 ) ! = PHY_MARV_ID0_VAL | |
gm_phy_read ( hw , 1 , PHY_MARV_ID1 ) ! = PHY_MARV_ID1_Y2 | |
gm_phy_read ( hw , 1 , PHY_MARV_INT_MASK ) ! = 0 ) ;
}
2005-09-14 16:06:14 -07:00
sky2_read16 ( hw , SK_REG ( port , GMAC_IRQ_SRC ) ) ;
2005-08-16 16:36:49 -07:00
2006-09-06 12:44:47 -07:00
/* Enable Transmit FIFO Underrun */
sky2_write8 ( hw , SK_REG ( port , GMAC_IRQ_MSK ) , GMAC_DEF_MSK ) ;
2006-03-20 15:48:17 -08:00
spin_lock_bh ( & sky2 - > phy_lock ) ;
2005-08-16 16:36:49 -07:00
sky2_phy_init ( hw , port ) ;
2006-03-20 15:48:17 -08:00
spin_unlock_bh ( & sky2 - > phy_lock ) ;
2005-08-16 16:36:49 -07:00
/* MIB clear */
reg = gma_read16 ( hw , port , GM_PHY_ADDR ) ;
gma_write16 ( hw , port , GM_PHY_ADDR , reg | GM_PAR_MIB_CLR ) ;
2006-04-05 17:47:15 -07:00
for ( i = GM_MIB_CNT_BASE ; i < = GM_MIB_CNT_END ; i + = 4 )
gma_read16 ( hw , port , i ) ;
2005-08-16 16:36:49 -07:00
gma_write16 ( hw , port , GM_PHY_ADDR , reg ) ;
/* transmit control */
gma_write16 ( hw , port , GM_TX_CTRL , TX_COL_THR ( TX_COL_DEF ) ) ;
/* receive control reg: unicast + multicast + no FCS */
gma_write16 ( hw , port , GM_RX_CTRL ,
2005-09-14 16:06:14 -07:00
GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA ) ;
2005-08-16 16:36:49 -07:00
/* transmit flow control */
gma_write16 ( hw , port , GM_TX_FLOW_CTRL , 0xffff ) ;
/* transmit parameter */
gma_write16 ( hw , port , GM_TX_PARAM ,
TX_JAM_LEN_VAL ( TX_JAM_LEN_DEF ) |
TX_JAM_IPG_VAL ( TX_JAM_IPG_DEF ) |
TX_IPG_JAM_DATA ( TX_IPG_JAM_DEF ) |
TX_BACK_OFF_LIM ( TX_BOF_LIM_DEF ) ) ;
/* serial mode register */
reg = DATA_BLIND_VAL ( DATA_BLIND_DEF ) |
2005-09-27 15:02:55 -07:00
GM_SMOD_VLAN_ENA | IPG_DATA_VAL ( IPG_DATA_DEF ) ;
2005-08-16 16:36:49 -07:00
2005-09-27 15:02:55 -07:00
if ( hw - > dev [ port ] - > mtu > ETH_DATA_LEN )
2005-08-16 16:36:49 -07:00
reg | = GM_SMOD_JUMBO_ENA ;
gma_write16 ( hw , port , GM_SERIAL_MODE , reg ) ;
/* virtual address for data */
gma_set_addr ( hw , port , GM_SRC_ADDR_2L , addr ) ;
2005-09-14 16:06:14 -07:00
/* physical address: used for pause frames */
gma_set_addr ( hw , port , GM_SRC_ADDR_1L , addr ) ;
/* ignore counter overflows */
2005-08-16 16:36:49 -07:00
gma_write16 ( hw , port , GM_TX_IRQ_MSK , 0 ) ;
gma_write16 ( hw , port , GM_RX_IRQ_MSK , 0 ) ;
gma_write16 ( hw , port , GM_TR_IRQ_MSK , 0 ) ;
/* Configure Rx MAC FIFO */
sky2_write8 ( hw , SK_REG ( port , RX_GMF_CTRL_T ) , GMF_RST_CLR ) ;
2006-03-07 11:06:37 -08:00
sky2_write32 ( hw , SK_REG ( port , RX_GMF_CTRL_T ) ,
GMF_OPER_ON | GMF_RX_F_FL_ON ) ;
2005-08-16 16:36:49 -07:00
2005-10-26 12:16:09 -07:00
/* Flush Rx MAC FIFO on any flow control or error */
2005-11-30 11:45:13 -08:00
sky2_write16 ( hw , SK_REG ( port , RX_GMF_FL_MSK ) , GMR_FS_ANY_ERR ) ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
/* Set threshold to 0xa (64 bytes)
* ASF disabled so no need to do WA dev # 4.30
2005-08-16 16:36:49 -07:00
*/
sky2_write16 ( hw , SK_REG ( port , RX_GMF_FL_THR ) , RX_GMF_FL_THR_DEF ) ;
/* Configure Tx MAC FIFO */
sky2_write8 ( hw , SK_REG ( port , TX_GMF_CTRL_T ) , GMF_RST_CLR ) ;
sky2_write16 ( hw , SK_REG ( port , TX_GMF_CTRL_T ) , GMF_OPER_ON ) ;
2005-11-30 11:45:15 -08:00
if ( hw - > chip_id = = CHIP_ID_YUKON_EC_U ) {
sky2_write8 ( hw , SK_REG ( port , RX_GMF_LP_THR ) , 768 / 8 ) ;
sky2_write8 ( hw , SK_REG ( port , RX_GMF_UP_THR ) , 1024 / 8 ) ;
if ( hw - > dev [ port ] - > mtu > ETH_DATA_LEN ) {
/* set Tx GMAC FIFO Almost Empty Threshold */
sky2_write32 ( hw , SK_REG ( port , TX_GMF_AE_THR ) , 0x180 ) ;
/* Disable Store & Forward mode for TX */
sky2_write32 ( hw , SK_REG ( port , TX_GMF_CTRL_T ) , TX_STFW_DIS ) ;
}
}
2005-08-16 16:36:49 -07:00
}
2006-01-17 13:43:13 -08:00
/* Assign Ram Buffer allocation.
* start and end are in units of 4 k bytes
* ram registers are in units of 64 bit words
*/
static void sky2_ramset ( struct sky2_hw * hw , u16 q , u8 startk , u8 endk )
2005-08-16 16:36:49 -07:00
{
2006-01-17 13:43:13 -08:00
u32 start , end ;
2005-08-16 16:36:49 -07:00
2006-01-17 13:43:13 -08:00
start = startk * 4096 / 8 ;
end = ( endk * 4096 / 8 ) - 1 ;
2005-09-14 16:06:14 -07:00
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , RB_ADDR ( q , RB_CTRL ) , RB_RST_CLR ) ;
sky2_write32 ( hw , RB_ADDR ( q , RB_START ) , start ) ;
sky2_write32 ( hw , RB_ADDR ( q , RB_END ) , end ) ;
sky2_write32 ( hw , RB_ADDR ( q , RB_WP ) , start ) ;
sky2_write32 ( hw , RB_ADDR ( q , RB_RP ) , start ) ;
if ( q = = Q_R1 | | q = = Q_R2 ) {
2006-01-17 13:43:13 -08:00
u32 space = ( endk - startk ) * 4096 / 8 ;
u32 tp = space - space / 4 ;
2005-09-14 16:06:14 -07:00
2006-01-17 13:43:13 -08:00
/* On receive queue's set the thresholds
* give receiver priority when > 3 / 4 full
* send pause when down to 2 K
*/
sky2_write32 ( hw , RB_ADDR ( q , RB_RX_UTHP ) , tp ) ;
sky2_write32 ( hw , RB_ADDR ( q , RB_RX_LTHP ) , space / 2 ) ;
2005-09-14 16:06:14 -07:00
2006-01-17 13:43:13 -08:00
tp = space - 2048 / 8 ;
sky2_write32 ( hw , RB_ADDR ( q , RB_RX_UTPP ) , tp ) ;
sky2_write32 ( hw , RB_ADDR ( q , RB_RX_LTPP ) , space / 4 ) ;
2005-08-16 16:36:49 -07:00
} else {
/* Enable store & forward on Tx queue's because
* Tx FIFO is only 1 K on Yukon
*/
sky2_write8 ( hw , RB_ADDR ( q , RB_CTRL ) , RB_ENA_STFWD ) ;
}
sky2_write8 ( hw , RB_ADDR ( q , RB_CTRL ) , RB_ENA_OP_MD ) ;
2005-09-14 16:06:14 -07:00
sky2_read8 ( hw , RB_ADDR ( q , RB_CTRL ) ) ;
2005-08-16 16:36:49 -07:00
}
/* Setup Bus Memory Interface */
2005-11-30 11:45:21 -08:00
static void sky2_qset ( struct sky2_hw * hw , u16 q )
2005-08-16 16:36:49 -07:00
{
sky2_write32 ( hw , Q_ADDR ( q , Q_CSR ) , BMU_CLR_RESET ) ;
sky2_write32 ( hw , Q_ADDR ( q , Q_CSR ) , BMU_OPER_INIT ) ;
sky2_write32 ( hw , Q_ADDR ( q , Q_CSR ) , BMU_FIFO_OP_ON ) ;
2005-11-30 11:45:21 -08:00
sky2_write32 ( hw , Q_ADDR ( q , Q_WM ) , BMU_WM_DEFAULT ) ;
2005-08-16 16:36:49 -07:00
}
/* Setup prefetch unit registers. This is the interface between
* hardware and driver list elements
*/
2005-12-09 11:35:07 -08:00
static void sky2_prefetch_init ( struct sky2_hw * hw , u32 qaddr ,
2005-08-16 16:36:49 -07:00
u64 addr , u32 last )
{
sky2_write32 ( hw , Y2_QADDR ( qaddr , PREF_UNIT_CTRL ) , PREF_UNIT_RST_SET ) ;
sky2_write32 ( hw , Y2_QADDR ( qaddr , PREF_UNIT_CTRL ) , PREF_UNIT_RST_CLR ) ;
sky2_write32 ( hw , Y2_QADDR ( qaddr , PREF_UNIT_ADDR_HI ) , addr > > 32 ) ;
sky2_write32 ( hw , Y2_QADDR ( qaddr , PREF_UNIT_ADDR_LO ) , ( u32 ) addr ) ;
sky2_write16 ( hw , Y2_QADDR ( qaddr , PREF_UNIT_LAST_IDX ) , last ) ;
sky2_write32 ( hw , Y2_QADDR ( qaddr , PREF_UNIT_CTRL ) , PREF_UNIT_OP_ON ) ;
2005-09-14 16:06:14 -07:00
sky2_read32 ( hw , Y2_QADDR ( qaddr , PREF_UNIT_CTRL ) ) ;
2005-08-16 16:36:49 -07:00
}
2005-09-14 16:06:14 -07:00
static inline struct sky2_tx_le * get_tx_le ( struct sky2_port * sky2 )
{
struct sky2_tx_le * le = sky2 - > tx_le + sky2 - > tx_prod ;
2006-05-08 15:11:29 -07:00
sky2 - > tx_prod = RING_NEXT ( sky2 - > tx_prod , TX_RING_SIZE ) ;
2005-09-14 16:06:14 -07:00
return le ;
}
2005-08-16 16:36:49 -07:00
2006-03-20 15:48:15 -08:00
/* Update chip's next pointer */
static inline void sky2_put_idx ( struct sky2_hw * hw , unsigned q , u16 idx )
2005-08-16 16:36:49 -07:00
{
2006-08-28 10:00:52 -07:00
q = Y2_QADDR ( q , PREF_UNIT_PUT_IDX ) ;
2006-01-17 13:43:14 -08:00
wmb ( ) ;
2006-08-28 10:00:52 -07:00
sky2_write16 ( hw , q , idx ) ;
sky2_read16 ( hw , q ) ;
2005-08-16 16:36:49 -07:00
}
2005-09-14 16:06:14 -07:00
2005-08-16 16:36:49 -07:00
static inline struct sky2_rx_le * sky2_next_rx ( struct sky2_port * sky2 )
{
struct sky2_rx_le * le = sky2 - > rx_le + sky2 - > rx_put ;
2006-05-08 15:11:29 -07:00
sky2 - > rx_put = RING_NEXT ( sky2 - > rx_put , RX_LE_SIZE ) ;
2005-08-16 16:36:49 -07:00
return le ;
}
2005-11-30 11:45:16 -08:00
/* Return high part of DMA address (could be 32 or 64 bit) */
static inline u32 high32 ( dma_addr_t a )
{
2006-01-17 13:43:16 -08:00
return sizeof ( a ) > sizeof ( u32 ) ? ( a > > 16 ) > > 16 : 0 ;
2005-11-30 11:45:16 -08:00
}
2005-09-14 16:06:14 -07:00
/* Build description to hardware about buffer */
2006-01-17 13:43:19 -08:00
static void sky2_rx_add ( struct sky2_port * sky2 , dma_addr_t map )
2005-08-16 16:36:49 -07:00
{
struct sky2_rx_le * le ;
2005-12-09 11:35:00 -08:00
u32 hi = high32 ( map ) ;
u16 len = sky2 - > rx_bufsize ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
if ( sky2 - > rx_addr64 ! = hi ) {
2005-08-16 16:36:49 -07:00
le = sky2_next_rx ( sky2 ) ;
2005-09-14 16:06:14 -07:00
le - > addr = cpu_to_le32 ( hi ) ;
2005-08-16 16:36:49 -07:00
le - > ctrl = 0 ;
le - > opcode = OP_ADDR64 | HW_OWNER ;
2005-12-09 11:35:00 -08:00
sky2 - > rx_addr64 = high32 ( map + len ) ;
2005-08-16 16:36:49 -07:00
}
2005-09-14 16:06:14 -07:00
2005-08-16 16:36:49 -07:00
le = sky2_next_rx ( sky2 ) ;
2005-12-09 11:35:00 -08:00
le - > addr = cpu_to_le32 ( ( u32 ) map ) ;
le - > length = cpu_to_le16 ( len ) ;
2005-08-16 16:36:49 -07:00
le - > ctrl = 0 ;
le - > opcode = OP_PACKET | HW_OWNER ;
}
2005-09-14 16:06:14 -07:00
2005-08-16 16:36:49 -07:00
/* Tell chip where to start receive checksum.
* Actually has two checksums , but set both same to avoid possible byte
* order problems .
*/
2005-09-14 16:06:14 -07:00
static void rx_set_checksum ( struct sky2_port * sky2 )
2005-08-16 16:36:49 -07:00
{
struct sky2_rx_le * le ;
le = sky2_next_rx ( sky2 ) ;
2006-09-06 12:45:02 -07:00
le - > addr = cpu_to_le32 ( ( ETH_HLEN < < 16 ) | ETH_HLEN ) ;
2005-08-16 16:36:49 -07:00
le - > ctrl = 0 ;
le - > opcode = OP_TCPSTART | HW_OWNER ;
2005-09-14 16:06:14 -07:00
sky2_write32 ( sky2 - > hw ,
Q_ADDR ( rxqaddr [ sky2 - > port ] , Q_CSR ) ,
sky2 - > rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM ) ;
2005-08-16 16:36:49 -07:00
}
2005-09-27 15:02:55 -07:00
/*
* The RX Stop command will not work for Yukon - 2 if the BMU does not
* reach the end of packet and since we can ' t make sure that we have
* incoming data , we must reset the BMU while it is not doing a DMA
* transfer . Since it is possible that the RX path is still active ,
* the RX RAM buffer will be stopped first , so any possible incoming
* data will not trigger a DMA . After the RAM buffer is stopped , the
* BMU is polled until any DMA in progress is ended and only then it
* will be reset .
*/
static void sky2_rx_stop ( struct sky2_port * sky2 )
{
struct sky2_hw * hw = sky2 - > hw ;
unsigned rxq = rxqaddr [ sky2 - > port ] ;
int i ;
/* disable the RAM Buffer receive queue */
sky2_write8 ( hw , RB_ADDR ( rxq , RB_CTRL ) , RB_DIS_OP_MD ) ;
for ( i = 0 ; i < 0xffff ; i + + )
if ( sky2_read8 ( hw , RB_ADDR ( rxq , Q_RSL ) )
= = sky2_read8 ( hw , RB_ADDR ( rxq , Q_RL ) ) )
goto stopped ;
printk ( KERN_WARNING PFX " %s: receiver stop failed \n " ,
sky2 - > netdev - > name ) ;
stopped :
sky2_write32 ( hw , Q_ADDR ( rxq , Q_CSR ) , BMU_RST_SET | BMU_FIFO_RST ) ;
/* reset the Rx prefetch unit */
sky2_write32 ( hw , Y2_QADDR ( rxq , PREF_UNIT_CTRL ) , PREF_UNIT_RST_SET ) ;
}
2005-09-14 16:06:14 -07:00
2005-10-26 12:16:09 -07:00
/* Clean out receive buffer area, assumes receiver hardware stopped */
2005-08-16 16:36:49 -07:00
static void sky2_rx_clean ( struct sky2_port * sky2 )
{
unsigned i ;
memset ( sky2 - > rx_le , 0 , RX_LE_BYTES ) ;
2005-09-14 16:06:14 -07:00
for ( i = 0 ; i < sky2 - > rx_pending ; i + + ) {
2005-08-16 16:36:49 -07:00
struct ring_info * re = sky2 - > rx_ring + i ;
if ( re - > skb ) {
2005-09-14 16:06:14 -07:00
pci_unmap_single ( sky2 - > hw - > pdev ,
2005-12-09 11:35:00 -08:00
re - > mapaddr , sky2 - > rx_bufsize ,
2005-08-16 16:36:49 -07:00
PCI_DMA_FROMDEVICE ) ;
kfree_skb ( re - > skb ) ;
re - > skb = NULL ;
}
}
}
2005-11-30 11:45:12 -08:00
/* Basic MII support */
static int sky2_ioctl ( struct net_device * dev , struct ifreq * ifr , int cmd )
{
struct mii_ioctl_data * data = if_mii ( ifr ) ;
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
int err = - EOPNOTSUPP ;
if ( ! netif_running ( dev ) )
return - ENODEV ; /* Phy still in reset */
2006-03-20 15:48:20 -08:00
switch ( cmd ) {
2005-11-30 11:45:12 -08:00
case SIOCGMIIPHY :
data - > phy_id = PHY_ADDR_MARV ;
/* fallthru */
case SIOCGMIIREG : {
u16 val = 0 ;
2005-12-09 11:34:57 -08:00
2006-03-20 15:48:17 -08:00
spin_lock_bh ( & sky2 - > phy_lock ) ;
2005-11-30 11:45:12 -08:00
err = __gm_phy_read ( hw , sky2 - > port , data - > reg_num & 0x1f , & val ) ;
2006-03-20 15:48:17 -08:00
spin_unlock_bh ( & sky2 - > phy_lock ) ;
2005-12-09 11:34:57 -08:00
2005-11-30 11:45:12 -08:00
data - > val_out = val ;
break ;
}
case SIOCSMIIREG :
if ( ! capable ( CAP_NET_ADMIN ) )
return - EPERM ;
2006-03-20 15:48:17 -08:00
spin_lock_bh ( & sky2 - > phy_lock ) ;
2005-11-30 11:45:12 -08:00
err = gm_phy_write ( hw , sky2 - > port , data - > reg_num & 0x1f ,
data - > val_in ) ;
2006-03-20 15:48:17 -08:00
spin_unlock_bh ( & sky2 - > phy_lock ) ;
2005-11-30 11:45:12 -08:00
break ;
}
return err ;
}
2005-09-27 15:02:57 -07:00
# ifdef SKY2_VLAN_TAG_USED
static void sky2_vlan_rx_register ( struct net_device * dev , struct vlan_group * grp )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
u16 port = sky2 - > port ;
2006-01-17 13:43:20 -08:00
spin_lock_bh ( & sky2 - > tx_lock ) ;
2005-09-27 15:02:57 -07:00
sky2_write32 ( hw , SK_REG ( port , RX_GMF_CTRL_T ) , RX_VLAN_STRIP_ON ) ;
sky2_write32 ( hw , SK_REG ( port , TX_GMF_CTRL_T ) , TX_VLAN_TAG_ON ) ;
sky2 - > vlgrp = grp ;
2006-01-17 13:43:20 -08:00
spin_unlock_bh ( & sky2 - > tx_lock ) ;
2005-09-27 15:02:57 -07:00
}
static void sky2_vlan_rx_kill_vid ( struct net_device * dev , unsigned short vid )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
u16 port = sky2 - > port ;
2006-01-17 13:43:20 -08:00
spin_lock_bh ( & sky2 - > tx_lock ) ;
2005-09-27 15:02:57 -07:00
sky2_write32 ( hw , SK_REG ( port , RX_GMF_CTRL_T ) , RX_VLAN_STRIP_OFF ) ;
sky2_write32 ( hw , SK_REG ( port , TX_GMF_CTRL_T ) , TX_VLAN_TAG_OFF ) ;
if ( sky2 - > vlgrp )
sky2 - > vlgrp - > vlan_devices [ vid ] = NULL ;
2006-01-17 13:43:20 -08:00
spin_unlock_bh ( & sky2 - > tx_lock ) ;
2005-09-27 15:02:57 -07:00
}
# endif
2006-01-17 13:43:10 -08:00
/*
* It appears the hardware has a bug in the FIFO logic that
* cause it to hang if the FIFO gets overrun and the receive buffer
2006-08-28 10:00:46 -07:00
* is not 64 byte aligned . The buffer returned from netdev_alloc_skb is
* aligned except if slab debugging is enabled .
2006-01-17 13:43:10 -08:00
*/
2006-08-28 10:00:46 -07:00
static inline struct sk_buff * sky2_alloc_skb ( struct net_device * dev ,
unsigned int length ,
gfp_t gfp_mask )
2006-01-17 13:43:10 -08:00
{
struct sk_buff * skb ;
2006-08-28 10:00:46 -07:00
skb = __netdev_alloc_skb ( dev , length + RX_SKB_ALIGN , gfp_mask ) ;
2006-01-17 13:43:10 -08:00
if ( likely ( skb ) ) {
unsigned long p = ( unsigned long ) skb - > data ;
2006-04-25 10:58:52 -07:00
skb_reserve ( skb , ALIGN ( p , RX_SKB_ALIGN ) - p ) ;
2006-01-17 13:43:10 -08:00
}
return skb ;
}
2005-08-16 16:36:49 -07:00
/*
* Allocate and setup receiver buffer pool .
* In case of 64 bit dma , there are 2 X as many list elements
* available as ring entries
* and need to reserve one list element so we don ' t wrap around .
*/
2005-09-27 15:02:55 -07:00
static int sky2_rx_start ( struct sky2_port * sky2 )
2005-08-16 16:36:49 -07:00
{
2005-09-27 15:02:55 -07:00
struct sky2_hw * hw = sky2 - > hw ;
unsigned rxq = rxqaddr [ sky2 - > port ] ;
int i ;
2006-05-22 12:03:42 -07:00
unsigned thresh ;
2005-08-16 16:36:49 -07:00
2005-09-27 15:02:55 -07:00
sky2 - > rx_put = sky2 - > rx_next = 0 ;
2005-11-30 11:45:21 -08:00
sky2_qset ( hw , rxq ) ;
2006-02-22 11:44:58 -08:00
if ( hw - > chip_id = = CHIP_ID_YUKON_EC_U & & hw - > chip_rev > = 2 ) {
/* MAC Rx RAM Read is controlled by hardware */
sky2_write32 ( hw , Q_ADDR ( rxq , Q_F ) , F_M_RX_RAM_DIS ) ;
}
2005-09-27 15:02:55 -07:00
sky2_prefetch_init ( hw , rxq , sky2 - > rx_le_map , RX_LE_SIZE - 1 ) ;
rx_set_checksum ( sky2 ) ;
2005-09-14 16:06:14 -07:00
for ( i = 0 ; i < sky2 - > rx_pending ; i + + ) {
2005-08-16 16:36:49 -07:00
struct ring_info * re = sky2 - > rx_ring + i ;
2006-08-28 10:00:46 -07:00
re - > skb = sky2_alloc_skb ( sky2 - > netdev , sky2 - > rx_bufsize ,
GFP_KERNEL ) ;
2005-08-16 16:36:49 -07:00
if ( ! re - > skb )
goto nomem ;
2005-09-27 15:02:55 -07:00
re - > mapaddr = pci_map_single ( hw - > pdev , re - > skb - > data ,
2005-12-09 11:35:00 -08:00
sky2 - > rx_bufsize , PCI_DMA_FROMDEVICE ) ;
sky2_rx_add ( sky2 , re - > mapaddr ) ;
2005-08-16 16:36:49 -07:00
}
2006-05-22 12:03:42 -07:00
/*
* The receiver hangs if it receives frames larger than the
* packet buffer . As a workaround , truncate oversize frames , but
* the register is limited to 9 bits , so if you do frames > 2052
* you better get the MTU right !
*/
thresh = ( sky2 - > rx_bufsize - 8 ) / sizeof ( u32 ) ;
if ( thresh > 0x1ff )
sky2_write32 ( hw , SK_REG ( sky2 - > port , RX_GMF_CTRL_T ) , RX_TRUNC_OFF ) ;
else {
sky2_write16 ( hw , SK_REG ( sky2 - > port , RX_GMF_TR_THR ) , thresh ) ;
sky2_write32 ( hw , SK_REG ( sky2 - > port , RX_GMF_CTRL_T ) , RX_TRUNC_ON ) ;
}
2006-03-07 11:06:37 -08:00
2005-09-27 15:02:55 -07:00
/* Tell chip about available buffers */
sky2_write16 ( hw , Y2_QADDR ( rxq , PREF_UNIT_PUT_IDX ) , sky2 - > rx_put ) ;
2005-08-16 16:36:49 -07:00
return 0 ;
nomem :
sky2_rx_clean ( sky2 ) ;
return - ENOMEM ;
}
/* Bring up network interface. */
static int sky2_up ( struct net_device * dev )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
unsigned port = sky2 - > port ;
2006-03-20 15:48:17 -08:00
u32 ramsize , rxspace , imask ;
2006-05-18 11:16:21 -07:00
int cap , err = - ENOMEM ;
2006-05-11 15:07:28 -07:00
struct net_device * otherdev = hw - > dev [ sky2 - > port ^ 1 ] ;
2005-08-16 16:36:49 -07:00
2006-05-18 11:16:21 -07:00
/*
* On dual port PCI - X card , there is an problem where status
* can be received out of order due to split transactions
2006-05-11 15:07:28 -07:00
*/
2006-05-18 11:16:21 -07:00
if ( otherdev & & netif_running ( otherdev ) & &
( cap = pci_find_capability ( hw - > pdev , PCI_CAP_ID_PCIX ) ) ) {
struct sky2_port * osky2 = netdev_priv ( otherdev ) ;
u16 cmd ;
cmd = sky2_pci_read16 ( hw , cap + PCI_X_CMD ) ;
cmd & = ~ PCI_X_CMD_MAX_SPLIT ;
sky2_pci_write16 ( hw , cap + PCI_X_CMD , cmd ) ;
sky2 - > rx_csum = 0 ;
osky2 - > rx_csum = 0 ;
}
2006-05-11 15:07:28 -07:00
2005-08-16 16:36:49 -07:00
if ( netif_msg_ifup ( sky2 ) )
printk ( KERN_INFO PFX " %s: enabling interface \n " , dev - > name ) ;
/* must be power of 2 */
sky2 - > tx_le = pci_alloc_consistent ( hw - > pdev ,
2005-09-14 16:06:14 -07:00
TX_RING_SIZE *
sizeof ( struct sky2_tx_le ) ,
2005-08-16 16:36:49 -07:00
& sky2 - > tx_le_map ) ;
if ( ! sky2 - > tx_le )
goto err_out ;
2005-12-09 11:35:01 -08:00
sky2 - > tx_ring = kcalloc ( TX_RING_SIZE , sizeof ( struct tx_ring_info ) ,
2005-08-16 16:36:49 -07:00
GFP_KERNEL ) ;
if ( ! sky2 - > tx_ring )
goto err_out ;
sky2 - > tx_prod = sky2 - > tx_cons = 0 ;
sky2 - > rx_le = pci_alloc_consistent ( hw - > pdev , RX_LE_BYTES ,
& sky2 - > rx_le_map ) ;
if ( ! sky2 - > rx_le )
goto err_out ;
memset ( sky2 - > rx_le , 0 , RX_LE_BYTES ) ;
2005-12-09 11:35:01 -08:00
sky2 - > rx_ring = kcalloc ( sky2 - > rx_pending , sizeof ( struct ring_info ) ,
2005-08-16 16:36:49 -07:00
GFP_KERNEL ) ;
if ( ! sky2 - > rx_ring )
goto err_out ;
2006-08-28 10:00:51 -07:00
sky2_phy_power ( hw , port , 1 ) ;
2005-08-16 16:36:49 -07:00
sky2_mac_init ( hw , port ) ;
2006-01-17 13:43:13 -08:00
/* Determine available ram buffer space (in 4K blocks).
* Note : not sure about the FE setting below yet
*/
if ( hw - > chip_id = = CHIP_ID_YUKON_FE )
ramsize = 4 ;
else
ramsize = sky2_read8 ( hw , B2_E_0 ) ;
/* Give transmitter one third (rounded up) */
rxspace = ramsize - ( ramsize + 2 ) / 3 ;
2005-08-16 16:36:49 -07:00
sky2_ramset ( hw , rxqaddr [ port ] , 0 , rxspace ) ;
2006-01-17 13:43:13 -08:00
sky2_ramset ( hw , txqaddr [ port ] , rxspace , ramsize ) ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
/* Make sure SyncQ is disabled */
sky2_write8 ( hw , RB_ADDR ( port = = 0 ? Q_XS1 : Q_XS2 , RB_CTRL ) ,
RB_RST_SET ) ;
2005-11-30 11:45:21 -08:00
sky2_qset ( hw , txqaddr [ port ] ) ;
2005-11-30 11:45:15 -08:00
2006-02-22 11:44:58 -08:00
/* Set almost empty threshold */
2006-09-26 11:57:39 -07:00
if ( hw - > chip_id = = CHIP_ID_YUKON_EC_U
& & hw - > chip_rev = = CHIP_REV_YU_EC_U_A0 )
2006-02-22 11:44:58 -08:00
sky2_write16 ( hw , Q_ADDR ( txqaddr [ port ] , Q_AL ) , 0x1a0 ) ;
2005-11-30 11:45:15 -08:00
2005-09-27 15:02:55 -07:00
sky2_prefetch_init ( hw , txqaddr [ port ] , sky2 - > tx_le_map ,
TX_RING_SIZE - 1 ) ;
2005-08-16 16:36:49 -07:00
2005-09-27 15:02:55 -07:00
err = sky2_rx_start ( sky2 ) ;
2005-08-16 16:36:49 -07:00
if ( err )
goto err_out ;
/* Enable interrupts from phy/mac for port */
2006-03-20 15:48:17 -08:00
imask = sky2_read32 ( hw , B0_IMSK ) ;
2006-05-09 14:46:54 -07:00
imask | = portirq_msk [ port ] ;
2006-03-20 15:48:17 -08:00
sky2_write32 ( hw , B0_IMSK , imask ) ;
2005-08-16 16:36:49 -07:00
return 0 ;
err_out :
2005-12-20 15:08:07 -08:00
if ( sky2 - > rx_le ) {
2005-08-16 16:36:49 -07:00
pci_free_consistent ( hw - > pdev , RX_LE_BYTES ,
sky2 - > rx_le , sky2 - > rx_le_map ) ;
2005-12-20 15:08:07 -08:00
sky2 - > rx_le = NULL ;
}
if ( sky2 - > tx_le ) {
2005-08-16 16:36:49 -07:00
pci_free_consistent ( hw - > pdev ,
TX_RING_SIZE * sizeof ( struct sky2_tx_le ) ,
sky2 - > tx_le , sky2 - > tx_le_map ) ;
2005-12-20 15:08:07 -08:00
sky2 - > tx_le = NULL ;
}
kfree ( sky2 - > tx_ring ) ;
kfree ( sky2 - > rx_ring ) ;
2005-08-16 16:36:49 -07:00
2005-12-20 15:08:07 -08:00
sky2 - > tx_ring = NULL ;
sky2 - > rx_ring = NULL ;
2005-08-16 16:36:49 -07:00
return err ;
}
2005-09-14 16:06:14 -07:00
/* Modular subtraction in ring */
static inline int tx_dist ( unsigned tail , unsigned head )
{
2006-05-08 15:11:29 -07:00
return ( head - tail ) & ( TX_RING_SIZE - 1 ) ;
2005-09-14 16:06:14 -07:00
}
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
/* Number of list elements available for next tx */
static inline int tx_avail ( const struct sky2_port * sky2 )
2005-08-16 16:36:49 -07:00
{
2005-09-14 16:06:14 -07:00
return sky2 - > tx_pending - tx_dist ( sky2 - > tx_cons , sky2 - > tx_prod ) ;
2005-08-16 16:36:49 -07:00
}
2005-09-14 16:06:14 -07:00
/* Estimate of number of transmit list elements required */
2006-01-17 13:43:19 -08:00
static unsigned tx_le_req ( const struct sk_buff * skb )
2005-08-16 16:36:49 -07:00
{
2005-09-14 16:06:14 -07:00
unsigned count ;
count = sizeof ( dma_addr_t ) / sizeof ( u32 ) ;
count + = skb_shinfo ( skb ) - > nr_frags * count ;
2006-07-08 13:34:32 -07:00
if ( skb_is_gso ( skb ) )
2005-09-14 16:06:14 -07:00
+ + count ;
2006-08-29 16:44:56 -07:00
if ( skb - > ip_summed = = CHECKSUM_PARTIAL )
2005-09-14 16:06:14 -07:00
+ + count ;
return count ;
2005-08-16 16:36:49 -07:00
}
2005-09-14 16:06:14 -07:00
/*
* Put one packet in ring for transmit .
* A single packet can generate multiple list elements , and
* the number of ring elements will probably be less than the number
* of list elements used .
2005-12-09 11:34:58 -08:00
*
* No BH disabling for tx_lock here ( like tg3 )
2005-09-14 16:06:14 -07:00
*/
2005-08-16 16:36:49 -07:00
static int sky2_xmit_frame ( struct sk_buff * skb , struct net_device * dev )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
2005-09-27 15:02:57 -07:00
struct sky2_tx_le * le = NULL ;
2005-12-09 11:35:01 -08:00
struct tx_ring_info * re ;
2005-08-16 16:36:49 -07:00
unsigned i , len ;
dma_addr_t mapping ;
u32 addr64 ;
u16 mss ;
u8 ctrl ;
2006-01-17 13:43:20 -08:00
/* No BH disabling for tx_lock here. We are running in BH disabled
* context and TX reclaim runs via poll inside of a software
* interrupt , and no related locks in IRQ processing .
*/
2005-12-09 11:34:58 -08:00
if ( ! spin_trylock ( & sky2 - > tx_lock ) )
2005-08-16 16:36:49 -07:00
return NETDEV_TX_LOCKED ;
2005-09-14 16:06:14 -07:00
if ( unlikely ( tx_avail ( sky2 ) < tx_le_req ( skb ) ) ) {
2005-12-09 11:35:08 -08:00
/* There is a known but harmless race with lockless tx
* and netif_stop_queue .
*/
if ( ! netif_queue_stopped ( dev ) ) {
netif_stop_queue ( dev ) ;
2006-01-17 13:43:17 -08:00
if ( net_ratelimit ( ) )
printk ( KERN_WARNING PFX " %s: ring full when queue awake! \n " ,
dev - > name ) ;
2005-12-09 11:35:08 -08:00
}
2005-12-09 11:34:58 -08:00
spin_unlock ( & sky2 - > tx_lock ) ;
2005-08-16 16:36:49 -07:00
return NETDEV_TX_BUSY ;
}
2005-09-14 16:06:14 -07:00
if ( unlikely ( netif_msg_tx_queued ( sky2 ) ) )
2005-08-16 16:36:49 -07:00
printk ( KERN_DEBUG " %s: tx queued, slot %u, len %d \n " ,
dev - > name , sky2 - > tx_prod , skb - > len ) ;
len = skb_headlen ( skb ) ;
mapping = pci_map_single ( hw - > pdev , skb - > data , len , PCI_DMA_TODEVICE ) ;
2005-11-30 11:45:16 -08:00
addr64 = high32 ( mapping ) ;
2005-09-14 16:06:14 -07:00
re = sky2 - > tx_ring + sky2 - > tx_prod ;
2005-11-30 11:45:16 -08:00
/* Send high bits if changed or crosses boundary */
if ( addr64 ! = sky2 - > tx_addr64 | | high32 ( mapping + len ) ! = sky2 - > tx_addr64 ) {
2005-09-14 16:06:14 -07:00
le = get_tx_le ( sky2 ) ;
2006-09-06 12:45:02 -07:00
le - > addr = cpu_to_le32 ( addr64 ) ;
2005-09-14 16:06:14 -07:00
le - > ctrl = 0 ;
le - > opcode = OP_ADDR64 | HW_OWNER ;
2005-11-30 11:45:16 -08:00
sky2 - > tx_addr64 = high32 ( mapping + len ) ;
2005-09-14 16:06:14 -07:00
}
2005-08-16 16:36:49 -07:00
/* Check for TCP Segmentation Offload */
2006-06-22 02:40:14 -07:00
mss = skb_shinfo ( skb ) - > gso_size ;
2005-09-14 16:06:14 -07:00
if ( mss ! = 0 ) {
2005-08-16 16:36:49 -07:00
mss + = ( ( skb - > h . th - > doff - 5 ) * 4 ) ; /* TCP options */
mss + = ( skb - > nh . iph - > ihl * 4 ) + sizeof ( struct tcphdr ) ;
mss + = ETH_HLEN ;
2006-08-28 10:00:49 -07:00
if ( mss ! = sky2 - > tx_last_mss ) {
le = get_tx_le ( sky2 ) ;
2006-09-06 12:45:02 -07:00
le - > addr = cpu_to_le32 ( mss ) ;
2006-08-28 10:00:49 -07:00
le - > opcode = OP_LRGLEN | HW_OWNER ;
le - > ctrl = 0 ;
sky2 - > tx_last_mss = mss ;
}
2005-08-16 16:36:49 -07:00
}
ctrl = 0 ;
2005-09-27 15:02:57 -07:00
# ifdef SKY2_VLAN_TAG_USED
/* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */
if ( sky2 - > vlgrp & & vlan_tx_tag_present ( skb ) ) {
if ( ! le ) {
le = get_tx_le ( sky2 ) ;
2006-09-06 12:45:02 -07:00
le - > addr = 0 ;
2005-09-27 15:02:57 -07:00
le - > opcode = OP_VLAN | HW_OWNER ;
le - > ctrl = 0 ;
} else
le - > opcode | = OP_VLAN ;
le - > length = cpu_to_be16 ( vlan_tx_tag_get ( skb ) ) ;
ctrl | = INS_VLAN ;
}
# endif
/* Handle TCP checksum offload */
2006-08-29 16:44:56 -07:00
if ( skb - > ip_summed = = CHECKSUM_PARTIAL ) {
2006-09-06 12:45:02 -07:00
unsigned offset = skb - > h . raw - skb - > data ;
u32 tcpsum ;
tcpsum = offset < < 16 ; /* sum start */
tcpsum | = offset + skb - > csum ; /* sum write */
2005-08-16 16:36:49 -07:00
ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM ;
if ( skb - > nh . iph - > protocol = = IPPROTO_UDP )
ctrl | = UDPTCP ;
2006-09-06 12:45:02 -07:00
if ( tcpsum ! = sky2 - > tx_tcpsum ) {
sky2 - > tx_tcpsum = tcpsum ;
2006-08-28 10:00:50 -07:00
le = get_tx_le ( sky2 ) ;
2006-09-06 12:45:02 -07:00
le - > addr = cpu_to_le32 ( tcpsum ) ;
2006-08-28 10:00:50 -07:00
le - > length = 0 ; /* initial checksum value */
le - > ctrl = 1 ; /* one packet */
le - > opcode = OP_TCPLISW | HW_OWNER ;
}
2005-08-16 16:36:49 -07:00
}
le = get_tx_le ( sky2 ) ;
2006-09-06 12:45:02 -07:00
le - > addr = cpu_to_le32 ( ( u32 ) mapping ) ;
2005-08-16 16:36:49 -07:00
le - > length = cpu_to_le16 ( len ) ;
le - > ctrl = ctrl ;
2005-09-14 16:06:14 -07:00
le - > opcode = mss ? ( OP_LARGESEND | HW_OWNER ) : ( OP_PACKET | HW_OWNER ) ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
/* Record the transmit mapping info */
2005-08-16 16:36:49 -07:00
re - > skb = skb ;
2005-12-09 11:35:01 -08:00
pci_unmap_addr_set ( re , mapaddr , mapping ) ;
2005-08-16 16:36:49 -07:00
for ( i = 0 ; i < skb_shinfo ( skb ) - > nr_frags ; i + + ) {
skb_frag_t * frag = & skb_shinfo ( skb ) - > frags [ i ] ;
2005-12-09 11:35:01 -08:00
struct tx_ring_info * fre ;
2005-08-16 16:36:49 -07:00
mapping = pci_map_page ( hw - > pdev , frag - > page , frag - > page_offset ,
frag - > size , PCI_DMA_TODEVICE ) ;
2006-01-17 13:43:16 -08:00
addr64 = high32 ( mapping ) ;
2005-09-14 16:06:14 -07:00
if ( addr64 ! = sky2 - > tx_addr64 ) {
le = get_tx_le ( sky2 ) ;
2006-09-06 12:45:02 -07:00
le - > addr = cpu_to_le32 ( addr64 ) ;
2005-09-14 16:06:14 -07:00
le - > ctrl = 0 ;
le - > opcode = OP_ADDR64 | HW_OWNER ;
sky2 - > tx_addr64 = addr64 ;
2005-08-16 16:36:49 -07:00
}
le = get_tx_le ( sky2 ) ;
2006-09-06 12:45:02 -07:00
le - > addr = cpu_to_le32 ( ( u32 ) mapping ) ;
2005-08-16 16:36:49 -07:00
le - > length = cpu_to_le16 ( frag - > size ) ;
le - > ctrl = ctrl ;
2005-09-14 16:06:14 -07:00
le - > opcode = OP_BUFFER | HW_OWNER ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
fre = sky2 - > tx_ring
2006-08-28 10:00:49 -07:00
+ RING_NEXT ( ( re - sky2 - > tx_ring ) + i , TX_RING_SIZE ) ;
2005-12-09 11:35:01 -08:00
pci_unmap_addr_set ( fre , mapaddr , mapping ) ;
2005-08-16 16:36:49 -07:00
}
2005-12-09 11:35:01 -08:00
2005-09-14 16:06:14 -07:00
re - > idx = sky2 - > tx_prod ;
2005-08-16 16:36:49 -07:00
le - > ctrl | = EOP ;
2006-08-28 10:00:47 -07:00
if ( tx_avail ( sky2 ) < = MAX_SKB_TX_LE )
netif_stop_queue ( dev ) ;
2006-03-07 11:06:36 -08:00
2006-03-20 15:48:15 -08:00
sky2_put_idx ( hw , txqaddr [ sky2 - > port ] , sky2 - > tx_prod ) ;
2005-08-16 16:36:49 -07:00
2005-12-09 11:34:58 -08:00
spin_unlock ( & sky2 - > tx_lock ) ;
2005-08-16 16:36:49 -07:00
dev - > trans_start = jiffies ;
return NETDEV_TX_OK ;
}
/*
2005-09-14 16:06:14 -07:00
* Free ring elements from starting at tx_cons until " done "
*
* NB : the hardware will tell us about partial completion of multi - part
2005-10-26 12:16:09 -07:00
* buffers ; these are deferred until completion .
2005-08-16 16:36:49 -07:00
*/
2005-09-27 15:02:56 -07:00
static void sky2_tx_complete ( struct sky2_port * sky2 , u16 done )
2005-08-16 16:36:49 -07:00
{
2005-09-27 15:02:56 -07:00
struct net_device * dev = sky2 - > netdev ;
2005-12-09 11:35:04 -08:00
struct pci_dev * pdev = sky2 - > hw - > pdev ;
u16 nxt , put ;
2005-09-14 16:06:14 -07:00
unsigned i ;
2005-08-16 16:36:49 -07:00
2005-12-09 11:35:02 -08:00
BUG_ON ( done > = TX_RING_SIZE ) ;
2005-11-30 11:45:19 -08:00
2005-09-27 15:02:56 -07:00
if ( unlikely ( netif_msg_tx_done ( sky2 ) ) )
2005-10-26 12:16:09 -07:00
printk ( KERN_DEBUG " %s: tx done, up to %u \n " ,
2005-09-27 15:02:56 -07:00
dev - > name , done ) ;
2005-08-16 16:36:49 -07:00
2005-12-09 11:35:04 -08:00
for ( put = sky2 - > tx_cons ; put ! = done ; put = nxt ) {
struct tx_ring_info * re = sky2 - > tx_ring + put ;
struct sk_buff * skb = re - > skb ;
2005-08-16 16:36:49 -07:00
2006-03-20 15:48:20 -08:00
nxt = re - > idx ;
2005-12-09 11:35:04 -08:00
BUG_ON ( nxt > = TX_RING_SIZE ) ;
2005-12-09 11:35:09 -08:00
prefetch ( sky2 - > tx_ring + nxt ) ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
/* Check for partial status */
2005-12-09 11:35:04 -08:00
if ( tx_dist ( put , done ) < tx_dist ( put , nxt ) )
break ;
2005-09-14 16:06:14 -07:00
skb = re - > skb ;
2005-12-09 11:35:04 -08:00
pci_unmap_single ( pdev , pci_unmap_addr ( re , mapaddr ) ,
2005-12-09 11:35:00 -08:00
skb_headlen ( skb ) , PCI_DMA_TODEVICE ) ;
2005-09-14 16:06:14 -07:00
for ( i = 0 ; i < skb_shinfo ( skb ) - > nr_frags ; i + + ) {
2005-12-09 11:35:01 -08:00
struct tx_ring_info * fre ;
2006-05-08 15:11:29 -07:00
fre = sky2 - > tx_ring + RING_NEXT ( put + i , TX_RING_SIZE ) ;
2005-12-09 11:35:04 -08:00
pci_unmap_page ( pdev , pci_unmap_addr ( fre , mapaddr ) ,
2006-03-20 15:48:20 -08:00
skb_shinfo ( skb ) - > frags [ i ] . size ,
2005-12-09 11:35:00 -08:00
PCI_DMA_TODEVICE ) ;
2005-08-16 16:36:49 -07:00
}
2006-03-23 08:51:38 -08:00
dev_kfree_skb ( skb ) ;
2005-09-14 16:06:14 -07:00
}
2005-12-09 11:35:04 -08:00
sky2 - > tx_cons = put ;
2006-07-12 15:23:48 -07:00
if ( tx_avail ( sky2 ) > MAX_SKB_TX_LE + 4 )
2005-08-16 16:36:49 -07:00
netif_wake_queue ( dev ) ;
}
/* Cleanup all untransmitted buffers, assume transmitter not running */
2005-12-09 11:35:03 -08:00
static void sky2_tx_clean ( struct sky2_port * sky2 )
2005-08-16 16:36:49 -07:00
{
2006-01-17 13:43:20 -08:00
spin_lock_bh ( & sky2 - > tx_lock ) ;
2005-09-27 15:02:56 -07:00
sky2_tx_complete ( sky2 , sky2 - > tx_prod ) ;
2006-01-17 13:43:20 -08:00
spin_unlock_bh ( & sky2 - > tx_lock ) ;
2005-08-16 16:36:49 -07:00
}
/* Network shutdown */
static int sky2_down ( struct net_device * dev )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
unsigned port = sky2 - > port ;
u16 ctrl ;
2006-03-20 15:48:17 -08:00
u32 imask ;
2005-08-16 16:36:49 -07:00
2005-12-20 15:08:07 -08:00
/* Never really got started! */
if ( ! sky2 - > tx_le )
return 0 ;
2005-08-16 16:36:49 -07:00
if ( netif_msg_ifdown ( sky2 ) )
printk ( KERN_INFO PFX " %s: disabling interface \n " , dev - > name ) ;
2005-11-30 11:45:18 -08:00
/* Stop more packets from being queued */
2005-08-16 16:36:49 -07:00
netif_stop_queue ( dev ) ;
2006-08-28 10:00:51 -07:00
sky2_gmac_reset ( hw , port ) ;
2005-09-14 16:06:14 -07:00
2005-08-16 16:36:49 -07:00
/* Stop transmitter */
sky2_write32 ( hw , Q_ADDR ( txqaddr [ port ] , Q_CSR ) , BMU_STOP ) ;
sky2_read32 ( hw , Q_ADDR ( txqaddr [ port ] , Q_CSR ) ) ;
sky2_write32 ( hw , RB_ADDR ( txqaddr [ port ] , RB_CTRL ) ,
2005-09-14 16:06:14 -07:00
RB_RST_SET | RB_DIS_OP_MD ) ;
2005-08-16 16:36:49 -07:00
2006-09-26 11:57:39 -07:00
/* WA for dev. #4.209 */
if ( hw - > chip_id = = CHIP_ID_YUKON_EC_U
& & hw - > chip_rev = = CHIP_REV_YU_EC_U_A1 )
sky2_write32 ( hw , SK_REG ( port , TX_GMF_CTRL_T ) ,
sky2 - > speed ! = SPEED_1000 ?
TX_STFW_ENA : TX_STFW_DIS ) ;
2005-08-16 16:36:49 -07:00
ctrl = gma_read16 ( hw , port , GM_GP_CTRL ) ;
2005-09-14 16:06:14 -07:00
ctrl & = ~ ( GM_GPCR_TX_ENA | GM_GPCR_RX_ENA ) ;
2005-08-16 16:36:49 -07:00
gma_write16 ( hw , port , GM_GP_CTRL , ctrl ) ;
sky2_write8 ( hw , SK_REG ( port , GPHY_CTRL ) , GPC_RST_SET ) ;
/* Workaround shared GMAC reset */
2005-09-14 16:06:14 -07:00
if ( ! ( hw - > chip_id = = CHIP_ID_YUKON_XL & & hw - > chip_rev = = 0
& & port = = 0 & & hw - > dev [ 1 ] & & netif_running ( hw - > dev [ 1 ] ) ) )
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , SK_REG ( port , GMAC_CTRL ) , GMC_RST_SET ) ;
/* Disable Force Sync bit and Enable Alloc bit */
sky2_write8 ( hw , SK_REG ( port , TXA_CTRL ) ,
TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC ) ;
/* Stop Interval Timer and Limit Counter of Tx Arbiter */
sky2_write32 ( hw , SK_REG ( port , TXA_ITI_INI ) , 0L ) ;
sky2_write32 ( hw , SK_REG ( port , TXA_LIM_INI ) , 0L ) ;
/* Reset the PCI FIFO of the async Tx queue */
2005-09-14 16:06:14 -07:00
sky2_write32 ( hw , Q_ADDR ( txqaddr [ port ] , Q_CSR ) ,
BMU_RST_SET | BMU_FIFO_RST ) ;
2005-08-16 16:36:49 -07:00
/* Reset the Tx prefetch units */
sky2_write32 ( hw , Y2_QADDR ( txqaddr [ port ] , PREF_UNIT_CTRL ) ,
PREF_UNIT_RST_SET ) ;
sky2_write32 ( hw , RB_ADDR ( txqaddr [ port ] , RB_CTRL ) , RB_RST_SET ) ;
2005-09-27 15:02:55 -07:00
sky2_rx_stop ( sky2 ) ;
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , SK_REG ( port , RX_GMF_CTRL_T ) , GMF_RST_SET ) ;
sky2_write8 ( hw , SK_REG ( port , TX_GMF_CTRL_T ) , GMF_RST_SET ) ;
2006-03-20 15:48:17 -08:00
/* Disable port IRQ */
imask = sky2_read32 ( hw , B0_IMSK ) ;
2006-05-09 14:46:54 -07:00
imask & = ~ portirq_msk [ port ] ;
2006-03-20 15:48:17 -08:00
sky2_write32 ( hw , B0_IMSK , imask ) ;
2006-08-28 10:00:51 -07:00
sky2_phy_power ( hw , port , 0 ) ;
2005-10-26 12:16:09 -07:00
/* turn off LED's */
2005-08-16 16:36:49 -07:00
sky2_write16 ( hw , B0_Y2LED , LED_STAT_OFF ) ;
2005-11-30 11:45:18 -08:00
synchronize_irq ( hw - > pdev - > irq ) ;
2005-08-16 16:36:49 -07:00
sky2_tx_clean ( sky2 ) ;
sky2_rx_clean ( sky2 ) ;
pci_free_consistent ( hw - > pdev , RX_LE_BYTES ,
sky2 - > rx_le , sky2 - > rx_le_map ) ;
kfree ( sky2 - > rx_ring ) ;
pci_free_consistent ( hw - > pdev ,
TX_RING_SIZE * sizeof ( struct sky2_tx_le ) ,
sky2 - > tx_le , sky2 - > tx_le_map ) ;
kfree ( sky2 - > tx_ring ) ;
2005-12-20 15:08:07 -08:00
sky2 - > tx_le = NULL ;
sky2 - > rx_le = NULL ;
sky2 - > rx_ring = NULL ;
sky2 - > tx_ring = NULL ;
2005-08-16 16:36:49 -07:00
return 0 ;
}
static u16 sky2_phy_speed ( const struct sky2_hw * hw , u16 aux )
{
2006-09-06 12:44:53 -07:00
if ( ! sky2_is_copper ( hw ) )
2005-09-14 16:06:14 -07:00
return SPEED_1000 ;
2005-08-16 16:36:49 -07:00
if ( hw - > chip_id = = CHIP_ID_YUKON_FE )
return ( aux & PHY_M_PS_SPEED_100 ) ? SPEED_100 : SPEED_10 ;
switch ( aux & PHY_M_PS_SPEED_MSK ) {
case PHY_M_PS_SPEED_1000 :
return SPEED_1000 ;
case PHY_M_PS_SPEED_100 :
return SPEED_100 ;
default :
return SPEED_10 ;
}
}
static void sky2_link_up ( struct sky2_port * sky2 )
{
struct sky2_hw * hw = sky2 - > hw ;
unsigned port = sky2 - > port ;
u16 reg ;
/* enable Rx/Tx */
2006-09-06 12:44:47 -07:00
reg = gma_read16 ( hw , port , GM_GP_CTRL ) ;
2005-08-16 16:36:49 -07:00
reg | = GM_GPCR_RX_ENA | GM_GPCR_TX_ENA ;
gma_write16 ( hw , port , GM_GP_CTRL , reg ) ;
gm_phy_write ( hw , port , PHY_MARV_INT_MASK , PHY_M_DEF_MSK ) ;
netif_carrier_on ( sky2 - > netdev ) ;
netif_wake_queue ( sky2 - > netdev ) ;
/* Turn on link LED */
2005-09-14 16:06:14 -07:00
sky2_write8 ( hw , SK_REG ( port , LNK_LED_REG ) ,
2005-08-16 16:36:49 -07:00
LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF ) ;
2006-05-08 15:11:33 -07:00
if ( hw - > chip_id = = CHIP_ID_YUKON_XL | | hw - > chip_id = = CHIP_ID_YUKON_EC_U ) {
2005-09-14 16:06:14 -07:00
u16 pg = gm_phy_read ( hw , port , PHY_MARV_EXT_ADR ) ;
2006-05-08 15:11:33 -07:00
u16 led = PHY_M_LEDC_LOS_CTRL ( 1 ) ; /* link active */
switch ( sky2 - > speed ) {
case SPEED_10 :
led | = PHY_M_LEDC_INIT_CTRL ( 7 ) ;
break ;
case SPEED_100 :
led | = PHY_M_LEDC_STA1_CTRL ( 7 ) ;
break ;
case SPEED_1000 :
led | = PHY_M_LEDC_STA0_CTRL ( 7 ) ;
break ;
}
2005-09-14 16:06:14 -07:00
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , 3 ) ;
2006-05-08 15:11:33 -07:00
gm_phy_write ( hw , port , PHY_MARV_PHY_CTRL , led ) ;
2005-09-14 16:06:14 -07:00
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , pg ) ;
}
2005-08-16 16:36:49 -07:00
if ( netif_msg_link ( sky2 ) )
printk ( KERN_INFO PFX
2005-10-26 12:16:09 -07:00
" %s: Link is up at %d Mbps, %s duplex, flow control %s \n " ,
2005-08-16 16:36:49 -07:00
sky2 - > netdev - > name , sky2 - > speed ,
sky2 - > duplex = = DUPLEX_FULL ? " full " : " half " ,
( sky2 - > tx_pause & & sky2 - > rx_pause ) ? " both " :
2005-09-14 16:06:14 -07:00
sky2 - > tx_pause ? " tx " : sky2 - > rx_pause ? " rx " : " none " ) ;
2005-08-16 16:36:49 -07:00
}
static void sky2_link_down ( struct sky2_port * sky2 )
{
struct sky2_hw * hw = sky2 - > hw ;
unsigned port = sky2 - > port ;
u16 reg ;
gm_phy_write ( hw , port , PHY_MARV_INT_MASK , 0 ) ;
reg = gma_read16 ( hw , port , GM_GP_CTRL ) ;
reg & = ~ ( GM_GPCR_RX_ENA | GM_GPCR_TX_ENA ) ;
gma_write16 ( hw , port , GM_GP_CTRL , reg ) ;
if ( sky2 - > rx_pause & & ! sky2 - > tx_pause ) {
/* restore Asymmetric Pause bit */
gm_phy_write ( hw , port , PHY_MARV_AUNE_ADV ,
2005-09-14 16:06:14 -07:00
gm_phy_read ( hw , port , PHY_MARV_AUNE_ADV )
| PHY_M_AN_ASP ) ;
2005-08-16 16:36:49 -07:00
}
netif_carrier_off ( sky2 - > netdev ) ;
netif_stop_queue ( sky2 - > netdev ) ;
/* Turn on link LED */
sky2_write8 ( hw , SK_REG ( port , LNK_LED_REG ) , LINKLED_OFF ) ;
if ( netif_msg_link ( sky2 ) )
printk ( KERN_INFO PFX " %s: Link is down. \n " , sky2 - > netdev - > name ) ;
2006-09-06 12:44:47 -07:00
2005-08-16 16:36:49 -07:00
sky2_phy_init ( hw , port ) ;
}
2005-09-14 16:06:14 -07:00
static int sky2_autoneg_done ( struct sky2_port * sky2 , u16 aux )
{
struct sky2_hw * hw = sky2 - > hw ;
unsigned port = sky2 - > port ;
u16 lpa ;
lpa = gm_phy_read ( hw , port , PHY_MARV_AUNE_LP ) ;
if ( lpa & PHY_M_AN_RF ) {
printk ( KERN_ERR PFX " %s: remote fault " , sky2 - > netdev - > name ) ;
return - 1 ;
}
if ( ! ( aux & PHY_M_PS_SPDUP_RES ) ) {
printk ( KERN_ERR PFX " %s: speed/duplex mismatch " ,
sky2 - > netdev - > name ) ;
return - 1 ;
}
sky2 - > speed = sky2_phy_speed ( hw , aux ) ;
2006-09-26 11:57:37 -07:00
if ( sky2 - > speed = = SPEED_1000 ) {
u16 ctl2 = gm_phy_read ( hw , port , PHY_MARV_1000T_CTRL ) ;
u16 lpa2 = gm_phy_read ( hw , port , PHY_MARV_1000T_STAT ) ;
if ( lpa2 & PHY_B_1000S_MSF ) {
printk ( KERN_ERR PFX " %s: master/slave fault " ,
sky2 - > netdev - > name ) ;
return - 1 ;
}
if ( ( ctl2 & PHY_M_1000C_AFD ) & & ( lpa2 & PHY_B_1000S_LP_FD ) )
sky2 - > duplex = DUPLEX_FULL ;
else
sky2 - > duplex = DUPLEX_HALF ;
} else {
u16 adv = gm_phy_read ( hw , port , PHY_MARV_AUNE_ADV ) ;
if ( ( aux & adv ) & PHY_AN_FULL )
sky2 - > duplex = DUPLEX_FULL ;
else
sky2 - > duplex = DUPLEX_HALF ;
}
2005-09-14 16:06:14 -07:00
/* Pause bits are offset (9..8) */
2006-05-08 15:11:33 -07:00
if ( hw - > chip_id = = CHIP_ID_YUKON_XL | | hw - > chip_id = = CHIP_ID_YUKON_EC_U )
2005-09-14 16:06:14 -07:00
aux > > = 6 ;
sky2 - > rx_pause = ( aux & PHY_M_PS_RX_P_EN ) ! = 0 ;
sky2 - > tx_pause = ( aux & PHY_M_PS_TX_P_EN ) ! = 0 ;
2006-09-06 12:44:47 -07:00
if ( sky2 - > duplex = = DUPLEX_HALF & & sky2 - > speed ! = SPEED_1000
& & hw - > chip_id ! = CHIP_ID_YUKON_EC_U )
sky2 - > rx_pause = sky2 - > tx_pause = 0 ;
if ( sky2 - > rx_pause | | sky2 - > tx_pause )
2005-09-14 16:06:14 -07:00
sky2_write8 ( hw , SK_REG ( port , GMAC_CTRL ) , GMC_PAUSE_ON ) ;
else
sky2_write8 ( hw , SK_REG ( port , GMAC_CTRL ) , GMC_PAUSE_OFF ) ;
return 0 ;
}
2005-08-16 16:36:49 -07:00
2006-03-20 15:48:17 -08:00
/* Interrupt from PHY */
static void sky2_phy_intr ( struct sky2_hw * hw , unsigned port )
2005-08-16 16:36:49 -07:00
{
2006-03-20 15:48:17 -08:00
struct net_device * dev = hw - > dev [ port ] ;
struct sky2_port * sky2 = netdev_priv ( dev ) ;
2005-08-16 16:36:49 -07:00
u16 istatus , phystat ;
2006-03-20 15:48:17 -08:00
spin_lock ( & sky2 - > phy_lock ) ;
istatus = gm_phy_read ( hw , port , PHY_MARV_INT_STAT ) ;
phystat = gm_phy_read ( hw , port , PHY_MARV_PHY_STAT ) ;
if ( ! netif_running ( dev ) )
goto out ;
2005-08-16 16:36:49 -07:00
if ( netif_msg_intr ( sky2 ) )
printk ( KERN_INFO PFX " %s: phy interrupt status 0x%x 0x%x \n " ,
sky2 - > netdev - > name , istatus , phystat ) ;
2006-09-06 12:44:47 -07:00
if ( sky2 - > autoneg = = AUTONEG_ENABLE & & ( istatus & PHY_M_IS_AN_COMPL ) ) {
2005-09-14 16:06:14 -07:00
if ( sky2_autoneg_done ( sky2 , phystat ) = = 0 )
sky2_link_up ( sky2 ) ;
goto out ;
}
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
if ( istatus & PHY_M_IS_LSP_CHANGE )
sky2 - > speed = sky2_phy_speed ( hw , phystat ) ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
if ( istatus & PHY_M_IS_DUP_CHANGE )
sky2 - > duplex =
( phystat & PHY_M_PS_FULL_DUP ) ? DUPLEX_FULL : DUPLEX_HALF ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
if ( istatus & PHY_M_IS_LST_CHANGE ) {
if ( phystat & PHY_M_PS_LINK_UP )
2005-08-16 16:36:49 -07:00
sky2_link_up ( sky2 ) ;
2005-09-14 16:06:14 -07:00
else
sky2_link_down ( sky2 ) ;
2005-08-16 16:36:49 -07:00
}
2005-09-14 16:06:14 -07:00
out :
2006-03-20 15:48:17 -08:00
spin_unlock ( & sky2 - > phy_lock ) ;
2005-08-16 16:36:49 -07:00
}
2006-01-17 13:43:20 -08:00
/* Transmit timeout is only called if we are running, carries is up
* and tx queue is full ( stopped ) .
*/
2005-08-16 16:36:49 -07:00
static void sky2_tx_timeout ( struct net_device * dev )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
2005-12-09 11:35:07 -08:00
struct sky2_hw * hw = sky2 - > hw ;
unsigned txq = txqaddr [ sky2 - > port ] ;
2006-03-20 15:48:21 -08:00
u16 report , done ;
2005-08-16 16:36:49 -07:00
if ( netif_msg_timer ( sky2 ) )
printk ( KERN_ERR PFX " %s: tx timeout \n " , dev - > name ) ;
2006-03-20 15:48:21 -08:00
report = sky2_read16 ( hw , sky2 - > port = = 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX ) ;
done = sky2_read16 ( hw , Q_ADDR ( txq , Q_DONE ) ) ;
2005-08-16 16:36:49 -07:00
2006-03-20 15:48:21 -08:00
printk ( KERN_DEBUG PFX " %s: transmit ring %u .. %u report=%u done=%u \n " ,
dev - > name ,
sky2 - > tx_cons , sky2 - > tx_prod , report , done ) ;
if ( report ! = done ) {
printk ( KERN_INFO PFX " status burst pending (irq moderation?) \n " ) ;
sky2_write8 ( hw , STAT_TX_TIMER_CTRL , TIM_STOP ) ;
sky2_write8 ( hw , STAT_TX_TIMER_CTRL , TIM_START ) ;
} else if ( report ! = sky2 - > tx_cons ) {
printk ( KERN_INFO PFX " status report lost? \n " ) ;
spin_lock_bh ( & sky2 - > tx_lock ) ;
sky2_tx_complete ( sky2 , report ) ;
spin_unlock_bh ( & sky2 - > tx_lock ) ;
} else {
printk ( KERN_INFO PFX " hardware hung? flushing \n " ) ;
2005-12-09 11:35:07 -08:00
2006-03-20 15:48:21 -08:00
sky2_write32 ( hw , Q_ADDR ( txq , Q_CSR ) , BMU_STOP ) ;
sky2_write32 ( hw , Y2_QADDR ( txq , PREF_UNIT_CTRL ) , PREF_UNIT_RST_SET ) ;
sky2_tx_clean ( sky2 ) ;
sky2_qset ( hw , txq ) ;
sky2_prefetch_init ( hw , txq , sky2 - > tx_le_map , TX_RING_SIZE - 1 ) ;
}
2005-08-16 16:36:49 -07:00
}
2005-12-09 11:35:00 -08:00
2006-03-07 11:06:37 -08:00
/* Want receive buffer size to be multiple of 64 bits
* and incl room for vlan and truncation
*/
2005-12-09 11:35:00 -08:00
static inline unsigned sky2_buf_size ( int mtu )
{
2006-04-25 10:58:52 -07:00
return ALIGN ( mtu + ETH_HLEN + VLAN_HLEN , 8 ) + 8 ;
2005-12-09 11:35:00 -08:00
}
2005-08-16 16:36:49 -07:00
static int sky2_change_mtu ( struct net_device * dev , int new_mtu )
{
2005-09-27 15:02:55 -07:00
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
int err ;
u16 ctl , mode ;
2006-03-20 15:48:17 -08:00
u32 imask ;
2005-08-16 16:36:49 -07:00
if ( new_mtu < ETH_ZLEN | | new_mtu > ETH_JUMBO_MTU )
return - EINVAL ;
2005-11-30 11:45:15 -08:00
if ( hw - > chip_id = = CHIP_ID_YUKON_EC_U & & new_mtu > ETH_DATA_LEN )
return - EINVAL ;
2005-09-27 15:02:55 -07:00
if ( ! netif_running ( dev ) ) {
dev - > mtu = new_mtu ;
return 0 ;
}
2006-03-20 15:48:17 -08:00
imask = sky2_read32 ( hw , B0_IMSK ) ;
2005-09-27 15:02:55 -07:00
sky2_write32 ( hw , B0_IMSK , 0 ) ;
2005-11-30 11:45:18 -08:00
dev - > trans_start = jiffies ; /* prevent tx timeout */
netif_stop_queue ( dev ) ;
netif_poll_disable ( hw - > dev [ 0 ] ) ;
2006-03-20 15:48:17 -08:00
synchronize_irq ( hw - > pdev - > irq ) ;
2005-09-27 15:02:55 -07:00
ctl = gma_read16 ( hw , sky2 - > port , GM_GP_CTRL ) ;
gma_write16 ( hw , sky2 - > port , GM_GP_CTRL , ctl & ~ GM_GPCR_RX_ENA ) ;
sky2_rx_stop ( sky2 ) ;
sky2_rx_clean ( sky2 ) ;
2005-08-16 16:36:49 -07:00
dev - > mtu = new_mtu ;
2005-12-09 11:35:00 -08:00
sky2 - > rx_bufsize = sky2_buf_size ( new_mtu ) ;
2005-09-27 15:02:55 -07:00
mode = DATA_BLIND_VAL ( DATA_BLIND_DEF ) |
GM_SMOD_VLAN_ENA | IPG_DATA_VAL ( IPG_DATA_DEF ) ;
if ( dev - > mtu > ETH_DATA_LEN )
mode | = GM_SMOD_JUMBO_ENA ;
gma_write16 ( hw , sky2 - > port , GM_SERIAL_MODE , mode ) ;
2005-08-16 16:36:49 -07:00
2005-09-27 15:02:55 -07:00
sky2_write8 ( hw , RB_ADDR ( rxqaddr [ sky2 - > port ] , RB_CTRL ) , RB_ENA_OP_MD ) ;
2005-08-16 16:36:49 -07:00
2005-09-27 15:02:55 -07:00
err = sky2_rx_start ( sky2 ) ;
2006-03-20 15:48:17 -08:00
sky2_write32 ( hw , B0_IMSK , imask ) ;
2005-11-30 11:45:18 -08:00
2005-12-20 15:08:07 -08:00
if ( err )
dev_close ( dev ) ;
else {
gma_write16 ( hw , sky2 - > port , GM_GP_CTRL , ctl ) ;
netif_poll_enable ( hw - > dev [ 0 ] ) ;
netif_wake_queue ( dev ) ;
}
2005-08-16 16:36:49 -07:00
return err ;
}
/*
* Receive one packet .
* For small packets or errors , just reuse existing skb .
2005-10-26 12:16:09 -07:00
* For larger packets , get new buffer .
2005-08-16 16:36:49 -07:00
*/
2006-08-28 10:00:46 -07:00
static struct sk_buff * sky2_receive ( struct net_device * dev ,
2005-08-16 16:36:49 -07:00
u16 length , u32 status )
{
2006-08-28 10:00:46 -07:00
struct sky2_port * sky2 = netdev_priv ( dev ) ;
2005-08-16 16:36:49 -07:00
struct ring_info * re = sky2 - > rx_ring + sky2 - > rx_next ;
2005-09-19 15:42:33 -07:00
struct sk_buff * skb = NULL ;
2005-08-16 16:36:49 -07:00
if ( unlikely ( netif_msg_rx_status ( sky2 ) ) )
printk ( KERN_DEBUG PFX " %s: rx slot %u status 0x%x len %d \n " ,
2006-08-28 10:00:46 -07:00
dev - > name , sky2 - > rx_next , status , length ) ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
sky2 - > rx_next = ( sky2 - > rx_next + 1 ) % sky2 - > rx_pending ;
2005-12-09 11:35:09 -08:00
prefetch ( sky2 - > rx_ring + sky2 - > rx_next ) ;
2005-08-16 16:36:49 -07:00
2005-11-30 11:45:13 -08:00
if ( status & GMR_FS_ANY_ERR )
2005-08-16 16:36:49 -07:00
goto error ;
2005-11-30 11:45:13 -08:00
if ( ! ( status & GMR_FS_RX_OK ) )
goto resubmit ;
2006-08-28 10:00:46 -07:00
if ( length > dev - > mtu + ETH_HLEN )
2005-12-20 15:08:09 -08:00
goto oversize ;
2005-12-09 11:34:55 -08:00
if ( length < copybreak ) {
2006-08-28 10:00:46 -07:00
skb = netdev_alloc_skb ( dev , length + 2 ) ;
2005-09-19 15:42:33 -07:00
if ( ! skb )
2005-09-14 16:06:14 -07:00
goto resubmit ;
2005-09-19 15:42:33 -07:00
skb_reserve ( skb , 2 ) ;
2005-09-14 16:06:14 -07:00
pci_dma_sync_single_for_cpu ( sky2 - > hw - > pdev , re - > mapaddr ,
length , PCI_DMA_FROMDEVICE ) ;
2005-09-19 15:42:33 -07:00
memcpy ( skb - > data , re - > skb - > data , length ) ;
2005-09-27 15:02:56 -07:00
skb - > ip_summed = re - > skb - > ip_summed ;
skb - > csum = re - > skb - > csum ;
2005-09-14 16:06:14 -07:00
pci_dma_sync_single_for_device ( sky2 - > hw - > pdev , re - > mapaddr ,
length , PCI_DMA_FROMDEVICE ) ;
} else {
2005-09-19 15:42:33 -07:00
struct sk_buff * nskb ;
2006-08-28 10:00:46 -07:00
nskb = sky2_alloc_skb ( dev , sky2 - > rx_bufsize , GFP_ATOMIC ) ;
2005-09-14 16:06:14 -07:00
if ( ! nskb )
goto resubmit ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
skb = re - > skb ;
2005-09-19 15:42:33 -07:00
re - > skb = nskb ;
2005-09-14 16:06:14 -07:00
pci_unmap_single ( sky2 - > hw - > pdev , re - > mapaddr ,
2005-12-09 11:35:00 -08:00
sky2 - > rx_bufsize , PCI_DMA_FROMDEVICE ) ;
2005-09-14 16:06:14 -07:00
prefetch ( skb - > data ) ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
re - > mapaddr = pci_map_single ( sky2 - > hw - > pdev , nskb - > data ,
2005-12-09 11:35:00 -08:00
sky2 - > rx_bufsize , PCI_DMA_FROMDEVICE ) ;
2005-09-14 16:06:14 -07:00
}
2005-08-16 16:36:49 -07:00
2005-09-19 15:42:33 -07:00
skb_put ( skb , length ) ;
2005-09-14 16:06:14 -07:00
resubmit :
2005-09-27 15:02:56 -07:00
re - > skb - > ip_summed = CHECKSUM_NONE ;
2005-12-09 11:35:00 -08:00
sky2_rx_add ( sky2 , re - > mapaddr ) ;
2005-09-19 15:42:33 -07:00
2005-08-16 16:36:49 -07:00
return skb ;
2005-12-20 15:08:09 -08:00
oversize :
+ + sky2 - > net_stats . rx_over_errors ;
goto resubmit ;
2005-08-16 16:36:49 -07:00
error :
2005-12-20 15:08:09 -08:00
+ + sky2 - > net_stats . rx_errors ;
2006-01-17 13:43:17 -08:00
if ( netif_msg_rx_err ( sky2 ) & & net_ratelimit ( ) )
2005-08-16 16:36:49 -07:00
printk ( KERN_INFO PFX " %s: rx error, status 0x%x length %d \n " ,
2006-08-28 10:00:46 -07:00
dev - > name , status , length ) ;
2005-09-14 16:06:14 -07:00
if ( status & ( GMR_FS_LONG_ERR | GMR_FS_UN_SIZE ) )
2005-08-16 16:36:49 -07:00
sky2 - > net_stats . rx_length_errors + + ;
if ( status & GMR_FS_FRAGMENT )
sky2 - > net_stats . rx_frame_errors + + ;
if ( status & GMR_FS_CRC_ERR )
sky2 - > net_stats . rx_crc_errors + + ;
2005-09-14 16:06:14 -07:00
if ( status & GMR_FS_RX_FF_OV )
sky2 - > net_stats . rx_fifo_errors + + ;
2005-09-19 15:42:33 -07:00
2005-09-14 16:06:14 -07:00
goto resubmit ;
2005-08-16 16:36:49 -07:00
}
2006-03-20 15:48:17 -08:00
/* Transmit complete */
static inline void sky2_tx_done ( struct net_device * dev , u16 last )
2005-12-09 11:35:03 -08:00
{
2006-03-20 15:48:17 -08:00
struct sky2_port * sky2 = netdev_priv ( dev ) ;
2006-01-17 13:43:20 -08:00
2006-03-20 15:48:17 -08:00
if ( netif_running ( dev ) ) {
spin_lock ( & sky2 - > tx_lock ) ;
sky2_tx_complete ( sky2 , last ) ;
spin_unlock ( & sky2 - > tx_lock ) ;
2005-11-30 11:45:19 -08:00
}
2005-08-16 16:36:49 -07:00
}
2006-03-20 15:48:17 -08:00
/* Process status response ring */
static int sky2_status_intr ( struct sky2_hw * hw , int to_do )
2005-08-16 16:36:49 -07:00
{
2006-07-12 15:23:48 -07:00
struct sky2_port * sky2 ;
2006-03-20 15:48:17 -08:00
int work_done = 0 ;
2006-07-12 15:23:48 -07:00
unsigned buf_write [ 2 ] = { 0 , 0 } ;
2006-05-08 15:11:31 -07:00
u16 hwidx = sky2_read16 ( hw , STAT_PUT_IDX ) ;
2006-02-22 11:45:00 -08:00
2005-12-09 11:35:04 -08:00
rmb ( ) ;
2005-10-26 12:16:10 -07:00
2006-05-08 15:11:31 -07:00
while ( hw - > st_idx ! = hwidx ) {
2005-11-30 11:45:14 -08:00
struct sky2_status_le * le = hw - > st_le + hw - > st_idx ;
struct net_device * dev ;
2005-08-16 16:36:49 -07:00
struct sk_buff * skb ;
u32 status ;
u16 length ;
2006-05-08 15:11:29 -07:00
hw - > st_idx = RING_NEXT ( hw - > st_idx , STATUS_RING_SIZE ) ;
2005-10-26 12:16:10 -07:00
2006-05-08 15:11:31 -07:00
BUG_ON ( le - > link > = 2 ) ;
dev = hw - > dev [ le - > link ] ;
2005-11-30 11:45:14 -08:00
sky2 = netdev_priv ( dev ) ;
2006-09-06 12:45:02 -07:00
length = le16_to_cpu ( le - > length ) ;
status = le32_to_cpu ( le - > status ) ;
2005-08-16 16:36:49 -07:00
2006-05-08 15:11:31 -07:00
switch ( le - > opcode & ~ HW_OWNER ) {
2005-08-16 16:36:49 -07:00
case OP_RXSTAT :
2006-08-28 10:00:46 -07:00
skb = sky2_receive ( dev , length , status ) ;
2005-09-27 15:02:57 -07:00
if ( ! skb )
break ;
2005-11-30 11:45:14 -08:00
skb - > protocol = eth_type_trans ( skb , dev ) ;
dev - > last_rx = jiffies ;
2005-09-27 15:02:57 -07:00
# ifdef SKY2_VLAN_TAG_USED
if ( sky2 - > vlgrp & & ( status & GMR_FS_VLAN ) ) {
vlan_hwaccel_receive_skb ( skb ,
sky2 - > vlgrp ,
be16_to_cpu ( sky2 - > rx_tag ) ) ;
} else
# endif
2005-08-16 16:36:49 -07:00
netif_receive_skb ( skb ) ;
2005-11-30 11:45:14 -08:00
2006-07-12 15:23:48 -07:00
/* Update receiver after 16 frames */
if ( + + buf_write [ le - > link ] = = RX_BUF_WRITE ) {
sky2_put_idx ( hw , rxqaddr [ le - > link ] ,
sky2 - > rx_put ) ;
buf_write [ le - > link ] = 0 ;
}
/* Stop after net poll weight */
2005-11-30 11:45:14 -08:00
if ( + + work_done > = to_do )
goto exit_loop ;
2005-08-16 16:36:49 -07:00
break ;
2005-09-27 15:02:57 -07:00
# ifdef SKY2_VLAN_TAG_USED
case OP_RXVLAN :
sky2 - > rx_tag = length ;
break ;
case OP_RXCHKSVLAN :
sky2 - > rx_tag = length ;
/* fall through */
# endif
2005-08-16 16:36:49 -07:00
case OP_RXCHKS :
2005-09-27 15:02:56 -07:00
skb = sky2 - > rx_ring [ sky2 - > rx_next ] . skb ;
2006-08-29 16:44:56 -07:00
skb - > ip_summed = CHECKSUM_COMPLETE ;
2006-09-06 12:45:02 -07:00
skb - > csum = status & 0xffff ;
2005-08-16 16:36:49 -07:00
break ;
case OP_TXINDEXLE :
2005-12-09 11:35:03 -08:00
/* TX index reports status for both ports */
2006-05-08 15:11:28 -07:00
BUILD_BUG_ON ( TX_RING_SIZE > 0x1000 ) ;
sky2_tx_done ( hw - > dev [ 0 ] , status & 0xfff ) ;
2006-03-20 15:48:17 -08:00
if ( hw - > dev [ 1 ] )
sky2_tx_done ( hw - > dev [ 1 ] ,
( ( status > > 24 ) & 0xff )
| ( u16 ) ( length & 0xf ) < < 8 ) ;
2005-08-16 16:36:49 -07:00
break ;
default :
if ( net_ratelimit ( ) )
2005-09-14 16:06:14 -07:00
printk ( KERN_WARNING PFX
2006-05-08 15:11:31 -07:00
" unknown status opcode 0x%x \n " , le - > opcode ) ;
goto exit_loop ;
2005-08-16 16:36:49 -07:00
}
2005-11-30 11:45:14 -08:00
}
2005-08-16 16:36:49 -07:00
2006-08-01 11:55:23 -07:00
/* Fully processed status ring so clear irq */
sky2_write32 ( hw , STAT_CTRL , SC_STAT_CLR_IRQ ) ;
2005-11-30 11:45:14 -08:00
exit_loop :
2006-07-12 15:23:48 -07:00
if ( buf_write [ 0 ] ) {
sky2 = netdev_priv ( hw - > dev [ 0 ] ) ;
sky2_put_idx ( hw , Q_R1 , sky2 - > rx_put ) ;
}
if ( buf_write [ 1 ] ) {
sky2 = netdev_priv ( hw - > dev [ 1 ] ) ;
sky2_put_idx ( hw , Q_R2 , sky2 - > rx_put ) ;
}
2006-03-20 15:48:17 -08:00
return work_done ;
2005-08-16 16:36:49 -07:00
}
static void sky2_hw_error ( struct sky2_hw * hw , unsigned port , u32 status )
{
struct net_device * dev = hw - > dev [ port ] ;
2006-01-17 13:43:17 -08:00
if ( net_ratelimit ( ) )
printk ( KERN_INFO PFX " %s: hw error interrupt status 0x%x \n " ,
dev - > name , status ) ;
2005-08-16 16:36:49 -07:00
if ( status & Y2_IS_PAR_RD1 ) {
2006-01-17 13:43:17 -08:00
if ( net_ratelimit ( ) )
printk ( KERN_ERR PFX " %s: ram data read parity error \n " ,
dev - > name ) ;
2005-08-16 16:36:49 -07:00
/* Clear IRQ */
sky2_write16 ( hw , RAM_BUFFER ( port , B3_RI_CTRL ) , RI_CLR_RD_PERR ) ;
}
if ( status & Y2_IS_PAR_WR1 ) {
2006-01-17 13:43:17 -08:00
if ( net_ratelimit ( ) )
printk ( KERN_ERR PFX " %s: ram data write parity error \n " ,
dev - > name ) ;
2005-08-16 16:36:49 -07:00
sky2_write16 ( hw , RAM_BUFFER ( port , B3_RI_CTRL ) , RI_CLR_WR_PERR ) ;
}
if ( status & Y2_IS_PAR_MAC1 ) {
2006-01-17 13:43:17 -08:00
if ( net_ratelimit ( ) )
printk ( KERN_ERR PFX " %s: MAC parity error \n " , dev - > name ) ;
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , SK_REG ( port , TX_GMF_CTRL_T ) , GMF_CLI_TX_PE ) ;
}
if ( status & Y2_IS_PAR_RX1 ) {
2006-01-17 13:43:17 -08:00
if ( net_ratelimit ( ) )
printk ( KERN_ERR PFX " %s: RX parity error \n " , dev - > name ) ;
2005-08-16 16:36:49 -07:00
sky2_write32 ( hw , Q_ADDR ( rxqaddr [ port ] , Q_CSR ) , BMU_CLR_IRQ_PAR ) ;
}
if ( status & Y2_IS_TCP_TXA1 ) {
2006-01-17 13:43:17 -08:00
if ( net_ratelimit ( ) )
printk ( KERN_ERR PFX " %s: TCP segmentation error \n " ,
dev - > name ) ;
2005-08-16 16:36:49 -07:00
sky2_write32 ( hw , Q_ADDR ( txqaddr [ port ] , Q_CSR ) , BMU_CLR_IRQ_TCP ) ;
}
}
static void sky2_hw_intr ( struct sky2_hw * hw )
{
u32 status = sky2_read32 ( hw , B0_HWE_ISRC ) ;
2005-09-14 16:06:14 -07:00
if ( status & Y2_IS_TIST_OV )
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , GMAC_TI_ST_CTRL , GMT_ST_CLR_IRQ ) ;
if ( status & ( Y2_IS_MST_ERR | Y2_IS_IRQ_STAT ) ) {
2005-09-14 16:06:14 -07:00
u16 pci_err ;
2006-02-22 11:45:02 -08:00
pci_err = sky2_pci_read16 ( hw , PCI_STATUS ) ;
2006-01-17 13:43:17 -08:00
if ( net_ratelimit ( ) )
printk ( KERN_ERR PFX " %s: pci hw error (0x%x) \n " ,
pci_name ( hw - > pdev ) , pci_err ) ;
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , B2_TST_CTRL1 , TST_CFG_WRITE_ON ) ;
2006-02-22 11:45:02 -08:00
sky2_pci_write16 ( hw , PCI_STATUS ,
2006-09-26 11:57:38 -07:00
pci_err | PCI_STATUS_ERROR_BITS ) ;
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , B2_TST_CTRL1 , TST_CFG_WRITE_OFF ) ;
}
if ( status & Y2_IS_PCI_EXP ) {
2005-10-26 12:16:09 -07:00
/* PCI-Express uncorrectable Error occurred */
2005-09-14 16:06:14 -07:00
u32 pex_err ;
2006-09-26 11:57:38 -07:00
pex_err = sky2_pci_read32 ( hw ,
hw - > err_cap + PCI_ERR_UNCOR_STATUS ) ;
2005-08-16 16:36:49 -07:00
2006-01-17 13:43:17 -08:00
if ( net_ratelimit ( ) )
printk ( KERN_ERR PFX " %s: pci express error (0x%x) \n " ,
pci_name ( hw - > pdev ) , pex_err ) ;
2005-08-16 16:36:49 -07:00
/* clear the interrupt */
sky2_write32 ( hw , B2_TST_CTRL1 , TST_CFG_WRITE_ON ) ;
2006-09-26 11:57:38 -07:00
sky2_pci_write32 ( hw ,
hw - > err_cap + PCI_ERR_UNCOR_STATUS ,
0xffffffffUL ) ;
2005-08-16 16:36:49 -07:00
sky2_write32 ( hw , B2_TST_CTRL1 , TST_CFG_WRITE_OFF ) ;
2006-09-26 11:57:38 -07:00
/* In case of fatal error mask off to keep from getting stuck */
if ( pex_err & ( PCI_ERR_UNC_POISON_TLP | PCI_ERR_UNC_FCP
| PCI_ERR_UNC_DLP ) ) {
2005-08-16 16:36:49 -07:00
u32 hwmsk = sky2_read32 ( hw , B0_HWE_IMSK ) ;
hwmsk & = ~ Y2_IS_PCI_EXP ;
sky2_write32 ( hw , B0_HWE_IMSK , hwmsk ) ;
}
2006-09-26 11:57:38 -07:00
2005-08-16 16:36:49 -07:00
}
if ( status & Y2_HWE_L1_MASK )
sky2_hw_error ( hw , 0 , status ) ;
status > > = 8 ;
if ( status & Y2_HWE_L1_MASK )
sky2_hw_error ( hw , 1 , status ) ;
}
static void sky2_mac_intr ( struct sky2_hw * hw , unsigned port )
{
struct net_device * dev = hw - > dev [ port ] ;
struct sky2_port * sky2 = netdev_priv ( dev ) ;
u8 status = sky2_read8 ( hw , SK_REG ( port , GMAC_IRQ_SRC ) ) ;
if ( netif_msg_intr ( sky2 ) )
printk ( KERN_INFO PFX " %s: mac interrupt status 0x%x \n " ,
dev - > name , status ) ;
if ( status & GM_IS_RX_FF_OR ) {
+ + sky2 - > net_stats . rx_fifo_errors ;
sky2_write8 ( hw , SK_REG ( port , RX_GMF_CTRL_T ) , GMF_CLI_RX_FO ) ;
}
if ( status & GM_IS_TX_FF_UR ) {
+ + sky2 - > net_stats . tx_fifo_errors ;
sky2_write8 ( hw , SK_REG ( port , TX_GMF_CTRL_T ) , GMF_CLI_TX_FU ) ;
}
}
2006-03-20 15:48:22 -08:00
/* This should never happen it is a fatal situation */
static void sky2_descriptor_error ( struct sky2_hw * hw , unsigned port ,
const char * rxtx , u32 mask )
{
struct net_device * dev = hw - > dev [ port ] ;
struct sky2_port * sky2 = netdev_priv ( dev ) ;
u32 imask ;
printk ( KERN_ERR PFX " %s: %s descriptor error (hardware problem) \n " ,
dev ? dev - > name : " <not registered> " , rxtx ) ;
imask = sky2_read32 ( hw , B0_IMSK ) ;
imask & = ~ mask ;
sky2_write32 ( hw , B0_IMSK , imask ) ;
if ( dev ) {
spin_lock ( & sky2 - > phy_lock ) ;
sky2_link_down ( sky2 ) ;
spin_unlock ( & sky2 - > phy_lock ) ;
}
}
2005-08-16 16:36:49 -07:00
2006-04-25 10:58:51 -07:00
/* If idle then force a fake soft NAPI poll once a second
* to work around cases where sharing an edge triggered interrupt .
*/
2006-06-13 17:17:31 +09:00
static inline void sky2_idle_start ( struct sky2_hw * hw )
{
if ( idle_timeout > 0 )
mod_timer ( & hw - > idle_timer ,
jiffies + msecs_to_jiffies ( idle_timeout ) ) ;
}
2006-04-25 10:58:51 -07:00
static void sky2_idle ( unsigned long arg )
{
2006-05-08 15:11:30 -07:00
struct sky2_hw * hw = ( struct sky2_hw * ) arg ;
struct net_device * dev = hw - > dev [ 0 ] ;
2006-04-25 10:58:51 -07:00
if ( __netif_rx_schedule_prep ( dev ) )
__netif_rx_schedule ( dev ) ;
2006-05-08 15:11:30 -07:00
mod_timer ( & hw - > idle_timer , jiffies + msecs_to_jiffies ( idle_timeout ) ) ;
2006-04-25 10:58:51 -07:00
}
2006-03-20 15:48:17 -08:00
static int sky2_poll ( struct net_device * dev0 , int * budget )
2005-08-16 16:36:49 -07:00
{
2006-03-20 15:48:17 -08:00
struct sky2_hw * hw = ( ( struct sky2_port * ) netdev_priv ( dev0 ) ) - > hw ;
int work_limit = min ( dev0 - > quota , * budget ) ;
int work_done = 0 ;
2006-03-20 15:48:19 -08:00
u32 status = sky2_read32 ( hw , B0_Y2_SP_EISR ) ;
2005-08-16 16:36:49 -07:00
2006-05-08 15:11:27 -07:00
if ( status & Y2_IS_HW_ERR )
sky2_hw_intr ( hw ) ;
2006-03-20 15:48:22 -08:00
2006-05-08 15:11:27 -07:00
if ( status & Y2_IS_IRQ_PHY1 )
sky2_phy_intr ( hw , 0 ) ;
2005-08-16 16:36:49 -07:00
2006-05-08 15:11:27 -07:00
if ( status & Y2_IS_IRQ_PHY2 )
sky2_phy_intr ( hw , 1 ) ;
2005-08-16 16:36:49 -07:00
2006-05-08 15:11:27 -07:00
if ( status & Y2_IS_IRQ_MAC1 )
sky2_mac_intr ( hw , 0 ) ;
2005-08-16 16:36:49 -07:00
2006-05-08 15:11:27 -07:00
if ( status & Y2_IS_IRQ_MAC2 )
sky2_mac_intr ( hw , 1 ) ;
2005-08-16 16:36:49 -07:00
2006-05-08 15:11:27 -07:00
if ( status & Y2_IS_CHK_RX1 )
sky2_descriptor_error ( hw , 0 , " receive " , Y2_IS_CHK_RX1 ) ;
2006-03-20 15:48:22 -08:00
2006-05-08 15:11:27 -07:00
if ( status & Y2_IS_CHK_RX2 )
sky2_descriptor_error ( hw , 1 , " receive " , Y2_IS_CHK_RX2 ) ;
2006-03-20 15:48:22 -08:00
2006-05-08 15:11:27 -07:00
if ( status & Y2_IS_CHK_TXA1 )
sky2_descriptor_error ( hw , 0 , " transmit " , Y2_IS_CHK_TXA1 ) ;
2006-03-20 15:48:22 -08:00
2006-05-08 15:11:27 -07:00
if ( status & Y2_IS_CHK_TXA2 )
sky2_descriptor_error ( hw , 1 , " transmit " , Y2_IS_CHK_TXA2 ) ;
2005-08-16 16:36:49 -07:00
2006-05-08 15:11:27 -07:00
work_done = sky2_status_intr ( hw , work_limit ) ;
2006-08-01 11:55:23 -07:00
if ( work_done < work_limit ) {
netif_rx_complete ( dev0 ) ;
2006-05-17 14:37:06 -07:00
2006-08-01 11:55:23 -07:00
sky2_read32 ( hw , B0_Y2_SP_LISR ) ;
return 0 ;
} else {
* budget - = work_done ;
dev0 - > quota - = work_done ;
2006-05-08 15:11:27 -07:00
return 1 ;
2006-08-01 11:55:23 -07:00
}
2006-03-20 15:48:17 -08:00
}
static irqreturn_t sky2_intr ( int irq , void * dev_id , struct pt_regs * regs )
{
struct sky2_hw * hw = dev_id ;
struct net_device * dev0 = hw - > dev [ 0 ] ;
u32 status ;
/* Reading this mask interrupts as side effect */
status = sky2_read32 ( hw , B0_Y2_SP_ISRC2 ) ;
if ( status = = 0 | | status = = ~ 0 )
return IRQ_NONE ;
2005-09-14 16:06:14 -07:00
2006-03-20 15:48:17 -08:00
prefetch ( & hw - > st_le [ hw - > st_idx ] ) ;
if ( likely ( __netif_rx_schedule_prep ( dev0 ) ) )
__netif_rx_schedule ( dev0 ) ;
2005-09-14 16:06:14 -07:00
2005-08-16 16:36:49 -07:00
return IRQ_HANDLED ;
}
# ifdef CONFIG_NET_POLL_CONTROLLER
static void sky2_netpoll ( struct net_device * dev )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
2006-06-16 12:10:46 -07:00
struct net_device * dev0 = sky2 - > hw - > dev [ 0 ] ;
2005-08-16 16:36:49 -07:00
2006-06-16 12:10:46 -07:00
if ( netif_running ( dev ) & & __netif_rx_schedule_prep ( dev0 ) )
__netif_rx_schedule ( dev0 ) ;
2005-08-16 16:36:49 -07:00
}
# endif
/* Chip internal frequency for clock calculations */
2005-12-09 11:34:56 -08:00
static inline u32 sky2_mhz ( const struct sky2_hw * hw )
2005-08-16 16:36:49 -07:00
{
2005-09-14 16:06:14 -07:00
switch ( hw - > chip_id ) {
2005-08-16 16:36:49 -07:00
case CHIP_ID_YUKON_EC :
2005-11-30 11:45:15 -08:00
case CHIP_ID_YUKON_EC_U :
2005-12-09 11:34:56 -08:00
return 125 ; /* 125 Mhz */
2005-08-16 16:36:49 -07:00
case CHIP_ID_YUKON_FE :
2005-12-09 11:34:56 -08:00
return 100 ; /* 100 Mhz */
2005-09-14 16:06:14 -07:00
default : /* YUKON_XL */
2005-12-09 11:34:56 -08:00
return 156 ; /* 156 Mhz */
2005-08-16 16:36:49 -07:00
}
}
2005-12-09 11:34:56 -08:00
static inline u32 sky2_us2clk ( const struct sky2_hw * hw , u32 us )
2005-08-16 16:36:49 -07:00
{
2005-12-09 11:34:56 -08:00
return sky2_mhz ( hw ) * us ;
2005-08-16 16:36:49 -07:00
}
2005-12-09 11:34:56 -08:00
static inline u32 sky2_clk2us ( const struct sky2_hw * hw , u32 clk )
2005-08-16 16:36:49 -07:00
{
2005-12-09 11:34:56 -08:00
return clk / sky2_mhz ( hw ) ;
2005-08-16 16:36:49 -07:00
}
2005-12-09 11:34:56 -08:00
2006-07-12 15:23:45 -07:00
static int sky2_reset ( struct sky2_hw * hw )
2005-08-16 16:36:49 -07:00
{
u16 status ;
2006-09-06 12:44:53 -07:00
u8 t8 ;
2006-02-22 11:45:02 -08:00
int i ;
2006-09-26 11:57:38 -07:00
u32 msk ;
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , B0_CTST , CS_RST_CLR ) ;
2006-01-30 11:37:54 -08:00
2005-08-16 16:36:49 -07:00
hw - > chip_id = sky2_read8 ( hw , B2_CHIP_ID ) ;
if ( hw - > chip_id < CHIP_ID_YUKON_XL | | hw - > chip_id > CHIP_ID_YUKON_FE ) {
printk ( KERN_ERR PFX " %s: unsupported chip type 0x%x \n " ,
pci_name ( hw - > pdev ) , hw - > chip_id ) ;
return - EOPNOTSUPP ;
}
2006-03-20 15:48:15 -08:00
hw - > chip_rev = ( sky2_read8 ( hw , B2_MAC_CFG ) & CFG_CHIP_R_MSK ) > > 4 ;
/* This rev is really old, and requires untested workarounds */
if ( hw - > chip_id = = CHIP_ID_YUKON_EC & & hw - > chip_rev = = CHIP_REV_YU_EC_A1 ) {
printk ( KERN_ERR PFX " %s: unsupported revision Yukon-%s (0x%x) rev %d \n " ,
pci_name ( hw - > pdev ) , yukon2_name [ hw - > chip_id - CHIP_ID_YUKON_XL ] ,
hw - > chip_id , hw - > chip_rev ) ;
return - EOPNOTSUPP ;
}
2005-08-16 16:36:49 -07:00
/* disable ASF */
if ( hw - > chip_id < = CHIP_ID_YUKON_EC ) {
sky2_write8 ( hw , B28_Y2_ASF_STAT_CMD , Y2_ASF_RESET ) ;
sky2_write16 ( hw , B0_CTST , Y2_ASF_DISABLE ) ;
}
/* do a SW reset */
sky2_write8 ( hw , B0_CTST , CS_RST_SET ) ;
sky2_write8 ( hw , B0_CTST , CS_RST_CLR ) ;
/* clear PCI errors, if any */
2006-02-22 11:45:02 -08:00
status = sky2_pci_read16 ( hw , PCI_STATUS ) ;
2006-01-30 11:37:55 -08:00
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , B2_TST_CTRL1 , TST_CFG_WRITE_ON ) ;
2006-02-22 11:45:02 -08:00
sky2_pci_write16 ( hw , PCI_STATUS , status | PCI_STATUS_ERROR_BITS ) ;
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , B0_CTST , CS_MRST_CLR ) ;
/* clear any PEX errors */
2006-09-26 11:57:38 -07:00
if ( pci_find_capability ( hw - > pdev , PCI_CAP_ID_EXP ) ) {
hw - > err_cap = pci_find_ext_capability ( hw - > pdev , PCI_EXT_CAP_ID_ERR ) ;
if ( hw - > err_cap )
sky2_pci_write32 ( hw ,
hw - > err_cap + PCI_ERR_UNCOR_STATUS ,
0xffffffffUL ) ;
}
2005-08-16 16:36:49 -07:00
2006-09-06 12:44:53 -07:00
hw - > pmd_type = sky2_read8 ( hw , B2_PMD_TYP ) ;
2005-08-16 16:36:49 -07:00
hw - > ports = 1 ;
t8 = sky2_read8 ( hw , B2_Y2_HW_RES ) ;
if ( ( t8 & CFG_DUAL_MAC_MSK ) = = CFG_DUAL_MAC_MSK ) {
if ( ! ( sky2_read8 ( hw , B2_Y2_CLK_GATE ) & Y2_STATUS_LNK2_INAC ) )
+ + hw - > ports ;
}
2005-09-27 15:03:00 -07:00
sky2_set_power_state ( hw , PCI_D0 ) ;
2005-08-16 16:36:49 -07:00
for ( i = 0 ; i < hw - > ports ; i + + ) {
sky2_write8 ( hw , SK_REG ( i , GMAC_LINK_CTRL ) , GMLC_RST_SET ) ;
sky2_write8 ( hw , SK_REG ( i , GMAC_LINK_CTRL ) , GMLC_RST_CLR ) ;
}
sky2_write8 ( hw , B2_TST_CTRL1 , TST_CFG_WRITE_OFF ) ;
2005-09-14 16:06:14 -07:00
/* Clear I2C IRQ noise */
sky2_write32 ( hw , B2_I2C_IRQ , 1 ) ;
2005-08-16 16:36:49 -07:00
/* turn off hardware timer (unused) */
sky2_write8 ( hw , B2_TI_CTRL , TIM_STOP ) ;
sky2_write8 ( hw , B2_TI_CTRL , TIM_CLR_IRQ ) ;
2005-09-14 16:06:14 -07:00
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , B0_Y2LED , LED_STAT_ON ) ;
2005-12-09 11:35:06 -08:00
/* Turn off descriptor polling */
sky2_write32 ( hw , B28_DPT_CTRL , DPT_STOP ) ;
2005-08-16 16:36:49 -07:00
/* Turn off receive timestamp */
sky2_write8 ( hw , GMAC_TI_ST_CTRL , GMT_ST_STOP ) ;
2005-09-14 16:06:14 -07:00
sky2_write8 ( hw , GMAC_TI_ST_CTRL , GMT_ST_CLR_IRQ ) ;
2005-08-16 16:36:49 -07:00
/* enable the Tx Arbiters */
for ( i = 0 ; i < hw - > ports ; i + + )
sky2_write8 ( hw , SK_REG ( i , TXA_CTRL ) , TXA_ENA_ARB ) ;
/* Initialize ram interface */
for ( i = 0 ; i < hw - > ports ; i + + ) {
2005-09-14 16:06:14 -07:00
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_CTRL ) , RI_RST_CLR ) ;
2005-08-16 16:36:49 -07:00
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_WTO_R1 ) , SK_RI_TO_53 ) ;
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_WTO_XA1 ) , SK_RI_TO_53 ) ;
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_WTO_XS1 ) , SK_RI_TO_53 ) ;
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_RTO_R1 ) , SK_RI_TO_53 ) ;
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_RTO_XA1 ) , SK_RI_TO_53 ) ;
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_RTO_XS1 ) , SK_RI_TO_53 ) ;
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_WTO_R2 ) , SK_RI_TO_53 ) ;
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_WTO_XA2 ) , SK_RI_TO_53 ) ;
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_WTO_XS2 ) , SK_RI_TO_53 ) ;
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_RTO_R2 ) , SK_RI_TO_53 ) ;
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_RTO_XA2 ) , SK_RI_TO_53 ) ;
sky2_write8 ( hw , RAM_BUFFER ( i , B3_RI_RTO_XS2 ) , SK_RI_TO_53 ) ;
}
2006-09-26 11:57:38 -07:00
msk = Y2_HWE_ALL_MASK ;
if ( ! hw - > err_cap )
msk & = ~ Y2_IS_PCI_EXP ;
sky2_write32 ( hw , B0_HWE_IMSK , msk ) ;
2005-08-16 16:36:49 -07:00
for ( i = 0 ; i < hw - > ports ; i + + )
2006-08-28 10:00:51 -07:00
sky2_gmac_reset ( hw , i ) ;
2005-08-16 16:36:49 -07:00
memset ( hw - > st_le , 0 , STATUS_LE_BYTES ) ;
hw - > st_idx = 0 ;
sky2_write32 ( hw , STAT_CTRL , SC_STAT_RST_SET ) ;
sky2_write32 ( hw , STAT_CTRL , SC_STAT_RST_CLR ) ;
sky2_write32 ( hw , STAT_LIST_ADDR_LO , hw - > st_dma ) ;
2005-09-14 16:06:14 -07:00
sky2_write32 ( hw , STAT_LIST_ADDR_HI , ( u64 ) hw - > st_dma > > 32 ) ;
2005-08-16 16:36:49 -07:00
/* Set the list last index */
2005-09-14 16:06:14 -07:00
sky2_write16 ( hw , STAT_LAST_IDX , STATUS_RING_SIZE - 1 ) ;
2005-08-16 16:36:49 -07:00
2006-03-20 15:48:15 -08:00
sky2_write16 ( hw , STAT_TX_IDX_TH , 10 ) ;
sky2_write8 ( hw , STAT_FIFO_WM , 16 ) ;
2005-08-16 16:36:49 -07:00
2006-03-20 15:48:15 -08:00
/* set Status-FIFO ISR watermark */
if ( hw - > chip_id = = CHIP_ID_YUKON_XL & & hw - > chip_rev = = 0 )
sky2_write8 ( hw , STAT_FIFO_ISR_WM , 4 ) ;
else
sky2_write8 ( hw , STAT_FIFO_ISR_WM , 16 ) ;
2005-08-16 16:36:49 -07:00
2006-03-20 15:48:15 -08:00
sky2_write32 ( hw , STAT_TX_TIMER_INI , sky2_us2clk ( hw , 1000 ) ) ;
2006-03-20 15:48:18 -08:00
sky2_write32 ( hw , STAT_ISR_TIMER_INI , sky2_us2clk ( hw , 20 ) ) ;
sky2_write32 ( hw , STAT_LEV_TIMER_INI , sky2_us2clk ( hw , 100 ) ) ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
/* enable status unit */
2005-08-16 16:36:49 -07:00
sky2_write32 ( hw , STAT_CTRL , SC_STAT_OP_ON ) ;
sky2_write8 ( hw , STAT_TX_TIMER_CTRL , TIM_START ) ;
sky2_write8 ( hw , STAT_LEV_TIMER_CTRL , TIM_START ) ;
sky2_write8 ( hw , STAT_ISR_TIMER_CTRL , TIM_START ) ;
return 0 ;
}
2006-01-17 13:43:19 -08:00
static u32 sky2_supported_modes ( const struct sky2_hw * hw )
2005-08-16 16:36:49 -07:00
{
2006-09-06 12:44:53 -07:00
if ( sky2_is_copper ( hw ) ) {
u32 modes = SUPPORTED_10baseT_Half
| SUPPORTED_10baseT_Full
| SUPPORTED_100baseT_Half
| SUPPORTED_100baseT_Full
| SUPPORTED_Autoneg | SUPPORTED_TP ;
2005-08-16 16:36:49 -07:00
if ( hw - > chip_id ! = CHIP_ID_YUKON_FE )
modes | = SUPPORTED_1000baseT_Half
2006-09-06 12:44:53 -07:00
| SUPPORTED_1000baseT_Full ;
return modes ;
2005-08-16 16:36:49 -07:00
} else
2006-09-06 12:44:53 -07:00
return SUPPORTED_1000baseT_Half
| SUPPORTED_1000baseT_Full
| SUPPORTED_Autoneg
| SUPPORTED_FIBRE ;
2005-08-16 16:36:49 -07:00
}
2005-09-14 16:06:14 -07:00
static int sky2_get_settings ( struct net_device * dev , struct ethtool_cmd * ecmd )
2005-08-16 16:36:49 -07:00
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
ecmd - > transceiver = XCVR_INTERNAL ;
ecmd - > supported = sky2_supported_modes ( hw ) ;
ecmd - > phy_address = PHY_ADDR_MARV ;
2006-09-06 12:44:53 -07:00
if ( sky2_is_copper ( hw ) ) {
2005-08-16 16:36:49 -07:00
ecmd - > supported = SUPPORTED_10baseT_Half
2005-09-14 16:06:14 -07:00
| SUPPORTED_10baseT_Full
| SUPPORTED_100baseT_Half
| SUPPORTED_100baseT_Full
| SUPPORTED_1000baseT_Half
| SUPPORTED_1000baseT_Full
| SUPPORTED_Autoneg | SUPPORTED_TP ;
2005-08-16 16:36:49 -07:00
ecmd - > port = PORT_TP ;
2006-09-06 12:44:53 -07:00
ecmd - > speed = sky2 - > speed ;
} else {
ecmd - > speed = SPEED_1000 ;
2005-08-16 16:36:49 -07:00
ecmd - > port = PORT_FIBRE ;
2006-09-06 12:44:53 -07:00
}
2005-08-16 16:36:49 -07:00
ecmd - > advertising = sky2 - > advertising ;
ecmd - > autoneg = sky2 - > autoneg ;
ecmd - > duplex = sky2 - > duplex ;
return 0 ;
}
static int sky2_set_settings ( struct net_device * dev , struct ethtool_cmd * ecmd )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
const struct sky2_hw * hw = sky2 - > hw ;
u32 supported = sky2_supported_modes ( hw ) ;
if ( ecmd - > autoneg = = AUTONEG_ENABLE ) {
ecmd - > advertising = supported ;
sky2 - > duplex = - 1 ;
sky2 - > speed = - 1 ;
} else {
u32 setting ;
2005-09-14 16:06:14 -07:00
switch ( ecmd - > speed ) {
2005-08-16 16:36:49 -07:00
case SPEED_1000 :
if ( ecmd - > duplex = = DUPLEX_FULL )
setting = SUPPORTED_1000baseT_Full ;
else if ( ecmd - > duplex = = DUPLEX_HALF )
setting = SUPPORTED_1000baseT_Half ;
else
return - EINVAL ;
break ;
case SPEED_100 :
if ( ecmd - > duplex = = DUPLEX_FULL )
setting = SUPPORTED_100baseT_Full ;
else if ( ecmd - > duplex = = DUPLEX_HALF )
setting = SUPPORTED_100baseT_Half ;
else
return - EINVAL ;
break ;
case SPEED_10 :
if ( ecmd - > duplex = = DUPLEX_FULL )
setting = SUPPORTED_10baseT_Full ;
else if ( ecmd - > duplex = = DUPLEX_HALF )
setting = SUPPORTED_10baseT_Half ;
else
return - EINVAL ;
break ;
default :
return - EINVAL ;
}
if ( ( setting & supported ) = = 0 )
return - EINVAL ;
sky2 - > speed = ecmd - > speed ;
sky2 - > duplex = ecmd - > duplex ;
}
sky2 - > autoneg = ecmd - > autoneg ;
sky2 - > advertising = ecmd - > advertising ;
2005-12-20 15:08:07 -08:00
if ( netif_running ( dev ) )
sky2_phy_reinit ( sky2 ) ;
2005-08-16 16:36:49 -07:00
return 0 ;
}
static void sky2_get_drvinfo ( struct net_device * dev ,
struct ethtool_drvinfo * info )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
strcpy ( info - > driver , DRV_NAME ) ;
strcpy ( info - > version , DRV_VERSION ) ;
strcpy ( info - > fw_version , " N/A " ) ;
strcpy ( info - > bus_info , pci_name ( sky2 - > hw - > pdev ) ) ;
}
static const struct sky2_stat {
2005-09-14 16:06:14 -07:00
char name [ ETH_GSTRING_LEN ] ;
u16 offset ;
2005-08-16 16:36:49 -07:00
} sky2_stats [ ] = {
{ " tx_bytes " , GM_TXO_OK_HI } ,
{ " rx_bytes " , GM_RXO_OK_HI } ,
{ " tx_broadcast " , GM_TXF_BC_OK } ,
{ " rx_broadcast " , GM_RXF_BC_OK } ,
{ " tx_multicast " , GM_TXF_MC_OK } ,
{ " rx_multicast " , GM_RXF_MC_OK } ,
{ " tx_unicast " , GM_TXF_UC_OK } ,
{ " rx_unicast " , GM_RXF_UC_OK } ,
{ " tx_mac_pause " , GM_TXF_MPAUSE } ,
{ " rx_mac_pause " , GM_RXF_MPAUSE } ,
2006-03-22 10:38:45 -08:00
{ " collisions " , GM_TXF_COL } ,
2005-08-16 16:36:49 -07:00
{ " late_collision " , GM_TXF_LAT_COL } ,
{ " aborted " , GM_TXF_ABO_COL } ,
2006-03-22 10:38:45 -08:00
{ " single_collisions " , GM_TXF_SNG_COL } ,
2005-08-16 16:36:49 -07:00
{ " multi_collisions " , GM_TXF_MUL_COL } ,
2006-03-22 10:38:45 -08:00
2006-03-23 08:51:36 -08:00
{ " rx_short " , GM_RXF_SHT } ,
2005-08-16 16:36:49 -07:00
{ " rx_runt " , GM_RXE_FRAG } ,
2006-03-22 10:38:45 -08:00
{ " rx_64_byte_packets " , GM_RXF_64B } ,
{ " rx_65_to_127_byte_packets " , GM_RXF_127B } ,
{ " rx_128_to_255_byte_packets " , GM_RXF_255B } ,
{ " rx_256_to_511_byte_packets " , GM_RXF_511B } ,
{ " rx_512_to_1023_byte_packets " , GM_RXF_1023B } ,
{ " rx_1024_to_1518_byte_packets " , GM_RXF_1518B } ,
{ " rx_1518_to_max_byte_packets " , GM_RXF_MAX_SZ } ,
2005-08-16 16:36:49 -07:00
{ " rx_too_long " , GM_RXF_LNG_ERR } ,
2006-03-22 10:38:45 -08:00
{ " rx_fifo_overflow " , GM_RXE_FIFO_OV } ,
{ " rx_jabber " , GM_RXF_JAB_PKT } ,
2005-08-16 16:36:49 -07:00
{ " rx_fcs_error " , GM_RXF_FCS_ERR } ,
2006-03-22 10:38:45 -08:00
{ " tx_64_byte_packets " , GM_TXF_64B } ,
{ " tx_65_to_127_byte_packets " , GM_TXF_127B } ,
{ " tx_128_to_255_byte_packets " , GM_TXF_255B } ,
{ " tx_256_to_511_byte_packets " , GM_TXF_511B } ,
{ " tx_512_to_1023_byte_packets " , GM_TXF_1023B } ,
{ " tx_1024_to_1518_byte_packets " , GM_TXF_1518B } ,
{ " tx_1519_to_max_byte_packets " , GM_TXF_MAX_SZ } ,
{ " tx_fifo_underrun " , GM_TXE_FIFO_UR } ,
2005-08-16 16:36:49 -07:00
} ;
static u32 sky2_get_rx_csum ( struct net_device * dev )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
return sky2 - > rx_csum ;
}
static int sky2_set_rx_csum ( struct net_device * dev , u32 data )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
sky2 - > rx_csum = data ;
2005-09-14 16:06:14 -07:00
2005-08-16 16:36:49 -07:00
sky2_write32 ( sky2 - > hw , Q_ADDR ( rxqaddr [ sky2 - > port ] , Q_CSR ) ,
data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM ) ;
return 0 ;
}
static u32 sky2_get_msglevel ( struct net_device * netdev )
{
struct sky2_port * sky2 = netdev_priv ( netdev ) ;
return sky2 - > msg_enable ;
}
2005-09-27 15:28:42 -07:00
static int sky2_nway_reset ( struct net_device * dev )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
if ( sky2 - > autoneg ! = AUTONEG_ENABLE )
return - EINVAL ;
2005-12-20 15:08:07 -08:00
sky2_phy_reinit ( sky2 ) ;
2005-09-27 15:28:42 -07:00
return 0 ;
}
2005-09-14 16:06:14 -07:00
static void sky2_phy_stats ( struct sky2_port * sky2 , u64 * data , unsigned count )
2005-08-16 16:36:49 -07:00
{
struct sky2_hw * hw = sky2 - > hw ;
unsigned port = sky2 - > port ;
int i ;
data [ 0 ] = ( u64 ) gma_read32 ( hw , port , GM_TXO_OK_HI ) < < 32
2005-09-14 16:06:14 -07:00
| ( u64 ) gma_read32 ( hw , port , GM_TXO_OK_LO ) ;
2005-08-16 16:36:49 -07:00
data [ 1 ] = ( u64 ) gma_read32 ( hw , port , GM_RXO_OK_HI ) < < 32
2005-09-14 16:06:14 -07:00
| ( u64 ) gma_read32 ( hw , port , GM_RXO_OK_LO ) ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
for ( i = 2 ; i < count ; i + + )
2005-08-16 16:36:49 -07:00
data [ i ] = ( u64 ) gma_read32 ( hw , port , sky2_stats [ i ] . offset ) ;
}
static void sky2_set_msglevel ( struct net_device * netdev , u32 value )
{
struct sky2_port * sky2 = netdev_priv ( netdev ) ;
sky2 - > msg_enable = value ;
}
static int sky2_get_stats_count ( struct net_device * dev )
{
return ARRAY_SIZE ( sky2_stats ) ;
}
static void sky2_get_ethtool_stats ( struct net_device * dev ,
2005-09-14 16:06:14 -07:00
struct ethtool_stats * stats , u64 * data )
2005-08-16 16:36:49 -07:00
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
2005-09-14 16:06:14 -07:00
sky2_phy_stats ( sky2 , data , ARRAY_SIZE ( sky2_stats ) ) ;
2005-08-16 16:36:49 -07:00
}
2005-09-14 16:06:14 -07:00
static void sky2_get_strings ( struct net_device * dev , u32 stringset , u8 * data )
2005-08-16 16:36:49 -07:00
{
int i ;
switch ( stringset ) {
case ETH_SS_STATS :
for ( i = 0 ; i < ARRAY_SIZE ( sky2_stats ) ; i + + )
memcpy ( data + i * ETH_GSTRING_LEN ,
sky2_stats [ i ] . name , ETH_GSTRING_LEN ) ;
break ;
}
}
/* Use hardware MIB variables for critical path statistics and
* transmit feedback not reported at interrupt .
* Other errors are accounted for in interrupt handler .
*/
static struct net_device_stats * sky2_get_stats ( struct net_device * dev )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
2005-09-14 16:06:14 -07:00
u64 data [ 13 ] ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
sky2_phy_stats ( sky2 , data , ARRAY_SIZE ( data ) ) ;
2005-08-16 16:36:49 -07:00
sky2 - > net_stats . tx_bytes = data [ 0 ] ;
sky2 - > net_stats . rx_bytes = data [ 1 ] ;
sky2 - > net_stats . tx_packets = data [ 2 ] + data [ 4 ] + data [ 6 ] ;
sky2 - > net_stats . rx_packets = data [ 3 ] + data [ 5 ] + data [ 7 ] ;
2006-03-23 08:51:37 -08:00
sky2 - > net_stats . multicast = data [ 3 ] + data [ 5 ] ;
2005-08-16 16:36:49 -07:00
sky2 - > net_stats . collisions = data [ 10 ] ;
sky2 - > net_stats . tx_aborted_errors = data [ 12 ] ;
return & sky2 - > net_stats ;
}
static int sky2_set_mac_address ( struct net_device * dev , void * p )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
2006-01-30 11:37:57 -08:00
struct sky2_hw * hw = sky2 - > hw ;
unsigned port = sky2 - > port ;
const struct sockaddr * addr = p ;
2005-08-16 16:36:49 -07:00
if ( ! is_valid_ether_addr ( addr - > sa_data ) )
return - EADDRNOTAVAIL ;
memcpy ( dev - > dev_addr , addr - > sa_data , ETH_ALEN ) ;
2006-01-30 11:37:57 -08:00
memcpy_toio ( hw - > regs + B2_MAC_1 + port * 8 ,
2005-08-16 16:36:49 -07:00
dev - > dev_addr , ETH_ALEN ) ;
2006-01-30 11:37:57 -08:00
memcpy_toio ( hw - > regs + B2_MAC_2 + port * 8 ,
2005-08-16 16:36:49 -07:00
dev - > dev_addr , ETH_ALEN ) ;
2005-12-20 15:08:07 -08:00
2006-01-30 11:37:57 -08:00
/* virtual address for data */
gma_set_addr ( hw , port , GM_SRC_ADDR_2L , dev - > dev_addr ) ;
/* physical address: used for pause frames */
gma_set_addr ( hw , port , GM_SRC_ADDR_1L , dev - > dev_addr ) ;
2005-12-20 15:08:07 -08:00
return 0 ;
2005-08-16 16:36:49 -07:00
}
static void sky2_set_multicast ( struct net_device * dev )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
unsigned port = sky2 - > port ;
struct dev_mc_list * list = dev - > mc_list ;
u16 reg ;
u8 filter [ 8 ] ;
memset ( filter , 0 , sizeof ( filter ) ) ;
reg = gma_read16 ( hw , port , GM_RX_CTRL ) ;
reg | = GM_RXCR_UCF_ENA ;
2005-10-26 12:16:09 -07:00
if ( dev - > flags & IFF_PROMISC ) /* promiscuous */
2005-08-16 16:36:49 -07:00
reg & = ~ ( GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA ) ;
2005-09-14 16:06:14 -07:00
else if ( ( dev - > flags & IFF_ALLMULTI ) | | dev - > mc_count > 16 ) /* all multicast */
2005-08-16 16:36:49 -07:00
memset ( filter , 0xff , sizeof ( filter ) ) ;
2005-09-14 16:06:14 -07:00
else if ( dev - > mc_count = = 0 ) /* no multicast */
2005-08-16 16:36:49 -07:00
reg & = ~ GM_RXCR_MCF_ENA ;
else {
int i ;
reg | = GM_RXCR_MCF_ENA ;
for ( i = 0 ; list & & i < dev - > mc_count ; i + + , list = list - > next ) {
u32 bit = ether_crc ( ETH_ALEN , list - > dmi_addr ) & 0x3f ;
2005-09-14 16:06:14 -07:00
filter [ bit / 8 ] | = 1 < < ( bit % 8 ) ;
2005-08-16 16:36:49 -07:00
}
}
gma_write16 ( hw , port , GM_MC_ADDR_H1 ,
2005-09-14 16:06:14 -07:00
( u16 ) filter [ 0 ] | ( ( u16 ) filter [ 1 ] < < 8 ) ) ;
2005-08-16 16:36:49 -07:00
gma_write16 ( hw , port , GM_MC_ADDR_H2 ,
2005-09-14 16:06:14 -07:00
( u16 ) filter [ 2 ] | ( ( u16 ) filter [ 3 ] < < 8 ) ) ;
2005-08-16 16:36:49 -07:00
gma_write16 ( hw , port , GM_MC_ADDR_H3 ,
2005-09-14 16:06:14 -07:00
( u16 ) filter [ 4 ] | ( ( u16 ) filter [ 5 ] < < 8 ) ) ;
2005-08-16 16:36:49 -07:00
gma_write16 ( hw , port , GM_MC_ADDR_H4 ,
2005-09-14 16:06:14 -07:00
( u16 ) filter [ 6 ] | ( ( u16 ) filter [ 7 ] < < 8 ) ) ;
2005-08-16 16:36:49 -07:00
gma_write16 ( hw , port , GM_RX_CTRL , reg ) ;
}
/* Can have one global because blinking is controlled by
* ethtool and that is always under RTNL mutex
*/
2005-12-09 11:34:57 -08:00
static void sky2_led ( struct sky2_hw * hw , unsigned port , int on )
2005-08-16 16:36:49 -07:00
{
2005-09-14 16:06:14 -07:00
u16 pg ;
switch ( hw - > chip_id ) {
case CHIP_ID_YUKON_XL :
pg = gm_phy_read ( hw , port , PHY_MARV_EXT_ADR ) ;
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , 3 ) ;
gm_phy_write ( hw , port , PHY_MARV_PHY_CTRL ,
on ? ( PHY_M_LEDC_LOS_CTRL ( 1 ) |
PHY_M_LEDC_INIT_CTRL ( 7 ) |
PHY_M_LEDC_STA1_CTRL ( 7 ) |
PHY_M_LEDC_STA0_CTRL ( 7 ) )
: 0 ) ;
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , pg ) ;
break ;
default :
gm_phy_write ( hw , port , PHY_MARV_LED_CTRL , 0 ) ;
2005-08-16 16:36:49 -07:00
gm_phy_write ( hw , port , PHY_MARV_LED_OVER ,
2005-09-14 16:06:14 -07:00
on ? PHY_M_LED_MO_DUP ( MO_LED_ON ) |
PHY_M_LED_MO_10 ( MO_LED_ON ) |
PHY_M_LED_MO_100 ( MO_LED_ON ) |
2005-08-16 16:36:49 -07:00
PHY_M_LED_MO_1000 ( MO_LED_ON ) |
2005-09-14 16:06:14 -07:00
PHY_M_LED_MO_RX ( MO_LED_ON )
: PHY_M_LED_MO_DUP ( MO_LED_OFF ) |
PHY_M_LED_MO_10 ( MO_LED_OFF ) |
PHY_M_LED_MO_100 ( MO_LED_OFF ) |
2005-08-16 16:36:49 -07:00
PHY_M_LED_MO_1000 ( MO_LED_OFF ) |
PHY_M_LED_MO_RX ( MO_LED_OFF ) ) ;
2005-09-14 16:06:14 -07:00
}
2005-08-16 16:36:49 -07:00
}
/* blink LED's for finding board */
static int sky2_phys_id ( struct net_device * dev , u32 data )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
unsigned port = sky2 - > port ;
2005-09-14 16:06:14 -07:00
u16 ledctrl , ledover = 0 ;
2005-08-16 16:36:49 -07:00
long ms ;
2005-12-09 11:34:57 -08:00
int interrupted ;
2005-08-16 16:36:49 -07:00
int onoff = 1 ;
2005-09-14 16:06:14 -07:00
if ( ! data | | data > ( u32 ) ( MAX_SCHEDULE_TIMEOUT / HZ ) )
2005-08-16 16:36:49 -07:00
ms = jiffies_to_msecs ( MAX_SCHEDULE_TIMEOUT ) ;
else
ms = data * 1000 ;
/* save initial values */
2006-03-20 15:48:17 -08:00
spin_lock_bh ( & sky2 - > phy_lock ) ;
2005-09-14 16:06:14 -07:00
if ( hw - > chip_id = = CHIP_ID_YUKON_XL ) {
u16 pg = gm_phy_read ( hw , port , PHY_MARV_EXT_ADR ) ;
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , 3 ) ;
ledctrl = gm_phy_read ( hw , port , PHY_MARV_PHY_CTRL ) ;
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , pg ) ;
} else {
ledctrl = gm_phy_read ( hw , port , PHY_MARV_LED_CTRL ) ;
ledover = gm_phy_read ( hw , port , PHY_MARV_LED_OVER ) ;
}
2005-08-16 16:36:49 -07:00
2005-12-09 11:34:57 -08:00
interrupted = 0 ;
while ( ! interrupted & & ms > 0 ) {
2005-08-16 16:36:49 -07:00
sky2_led ( hw , port , onoff ) ;
onoff = ! onoff ;
2006-03-20 15:48:17 -08:00
spin_unlock_bh ( & sky2 - > phy_lock ) ;
2005-12-09 11:34:57 -08:00
interrupted = msleep_interruptible ( 250 ) ;
2006-03-20 15:48:17 -08:00
spin_lock_bh ( & sky2 - > phy_lock ) ;
2005-12-09 11:34:57 -08:00
2005-08-16 16:36:49 -07:00
ms - = 250 ;
}
/* resume regularly scheduled programming */
2005-09-14 16:06:14 -07:00
if ( hw - > chip_id = = CHIP_ID_YUKON_XL ) {
u16 pg = gm_phy_read ( hw , port , PHY_MARV_EXT_ADR ) ;
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , 3 ) ;
gm_phy_write ( hw , port , PHY_MARV_PHY_CTRL , ledctrl ) ;
gm_phy_write ( hw , port , PHY_MARV_EXT_ADR , pg ) ;
} else {
gm_phy_write ( hw , port , PHY_MARV_LED_CTRL , ledctrl ) ;
gm_phy_write ( hw , port , PHY_MARV_LED_OVER , ledover ) ;
}
2006-03-20 15:48:17 -08:00
spin_unlock_bh ( & sky2 - > phy_lock ) ;
2005-08-16 16:36:49 -07:00
return 0 ;
}
static void sky2_get_pauseparam ( struct net_device * dev ,
struct ethtool_pauseparam * ecmd )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
ecmd - > tx_pause = sky2 - > tx_pause ;
ecmd - > rx_pause = sky2 - > rx_pause ;
ecmd - > autoneg = sky2 - > autoneg ;
}
static int sky2_set_pauseparam ( struct net_device * dev ,
struct ethtool_pauseparam * ecmd )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
sky2 - > autoneg = ecmd - > autoneg ;
sky2 - > tx_pause = ecmd - > tx_pause ! = 0 ;
sky2 - > rx_pause = ecmd - > rx_pause ! = 0 ;
2005-12-20 15:08:07 -08:00
sky2_phy_reinit ( sky2 ) ;
2005-08-16 16:36:49 -07:00
2006-09-06 12:44:47 -07:00
return 0 ;
2005-08-16 16:36:49 -07:00
}
2005-12-09 11:34:56 -08:00
static int sky2_get_coalesce ( struct net_device * dev ,
struct ethtool_coalesce * ecmd )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
if ( sky2_read8 ( hw , STAT_TX_TIMER_CTRL ) = = TIM_STOP )
ecmd - > tx_coalesce_usecs = 0 ;
else {
u32 clks = sky2_read32 ( hw , STAT_TX_TIMER_INI ) ;
ecmd - > tx_coalesce_usecs = sky2_clk2us ( hw , clks ) ;
}
ecmd - > tx_max_coalesced_frames = sky2_read16 ( hw , STAT_TX_IDX_TH ) ;
if ( sky2_read8 ( hw , STAT_LEV_TIMER_CTRL ) = = TIM_STOP )
ecmd - > rx_coalesce_usecs = 0 ;
else {
u32 clks = sky2_read32 ( hw , STAT_LEV_TIMER_INI ) ;
ecmd - > rx_coalesce_usecs = sky2_clk2us ( hw , clks ) ;
}
ecmd - > rx_max_coalesced_frames = sky2_read8 ( hw , STAT_FIFO_WM ) ;
if ( sky2_read8 ( hw , STAT_ISR_TIMER_CTRL ) = = TIM_STOP )
ecmd - > rx_coalesce_usecs_irq = 0 ;
else {
u32 clks = sky2_read32 ( hw , STAT_ISR_TIMER_INI ) ;
ecmd - > rx_coalesce_usecs_irq = sky2_clk2us ( hw , clks ) ;
}
ecmd - > rx_max_coalesced_frames_irq = sky2_read8 ( hw , STAT_FIFO_ISR_WM ) ;
return 0 ;
}
/* Note: this affect both ports */
static int sky2_set_coalesce ( struct net_device * dev ,
struct ethtool_coalesce * ecmd )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
struct sky2_hw * hw = sky2 - > hw ;
2006-03-20 15:48:18 -08:00
const u32 tmax = sky2_clk2us ( hw , 0x0ffffff ) ;
2005-12-09 11:34:56 -08:00
2006-03-20 15:48:18 -08:00
if ( ecmd - > tx_coalesce_usecs > tmax | |
ecmd - > rx_coalesce_usecs > tmax | |
ecmd - > rx_coalesce_usecs_irq > tmax )
2005-12-09 11:34:56 -08:00
return - EINVAL ;
2006-02-22 11:44:59 -08:00
if ( ecmd - > tx_max_coalesced_frames > = TX_RING_SIZE - 1 )
2005-12-09 11:34:56 -08:00
return - EINVAL ;
2006-02-22 11:44:59 -08:00
if ( ecmd - > rx_max_coalesced_frames > RX_MAX_PENDING )
2005-12-09 11:34:56 -08:00
return - EINVAL ;
2006-02-22 11:44:59 -08:00
if ( ecmd - > rx_max_coalesced_frames_irq > RX_MAX_PENDING )
2005-12-09 11:34:56 -08:00
return - EINVAL ;
if ( ecmd - > tx_coalesce_usecs = = 0 )
sky2_write8 ( hw , STAT_TX_TIMER_CTRL , TIM_STOP ) ;
else {
sky2_write32 ( hw , STAT_TX_TIMER_INI ,
sky2_us2clk ( hw , ecmd - > tx_coalesce_usecs ) ) ;
sky2_write8 ( hw , STAT_TX_TIMER_CTRL , TIM_START ) ;
}
sky2_write16 ( hw , STAT_TX_IDX_TH , ecmd - > tx_max_coalesced_frames ) ;
if ( ecmd - > rx_coalesce_usecs = = 0 )
sky2_write8 ( hw , STAT_LEV_TIMER_CTRL , TIM_STOP ) ;
else {
sky2_write32 ( hw , STAT_LEV_TIMER_INI ,
sky2_us2clk ( hw , ecmd - > rx_coalesce_usecs ) ) ;
sky2_write8 ( hw , STAT_LEV_TIMER_CTRL , TIM_START ) ;
}
sky2_write8 ( hw , STAT_FIFO_WM , ecmd - > rx_max_coalesced_frames ) ;
if ( ecmd - > rx_coalesce_usecs_irq = = 0 )
sky2_write8 ( hw , STAT_ISR_TIMER_CTRL , TIM_STOP ) ;
else {
2006-01-30 11:37:56 -08:00
sky2_write32 ( hw , STAT_ISR_TIMER_INI ,
2005-12-09 11:34:56 -08:00
sky2_us2clk ( hw , ecmd - > rx_coalesce_usecs_irq ) ) ;
sky2_write8 ( hw , STAT_ISR_TIMER_CTRL , TIM_START ) ;
}
sky2_write8 ( hw , STAT_FIFO_ISR_WM , ecmd - > rx_max_coalesced_frames_irq ) ;
return 0 ;
}
2005-09-14 16:06:14 -07:00
static void sky2_get_ringparam ( struct net_device * dev ,
struct ethtool_ringparam * ering )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
ering - > rx_max_pending = RX_MAX_PENDING ;
ering - > rx_mini_max_pending = 0 ;
ering - > rx_jumbo_max_pending = 0 ;
ering - > tx_max_pending = TX_RING_SIZE - 1 ;
ering - > rx_pending = sky2 - > rx_pending ;
ering - > rx_mini_pending = 0 ;
ering - > rx_jumbo_pending = 0 ;
ering - > tx_pending = sky2 - > tx_pending ;
}
static int sky2_set_ringparam ( struct net_device * dev ,
struct ethtool_ringparam * ering )
{
struct sky2_port * sky2 = netdev_priv ( dev ) ;
int err = 0 ;
if ( ering - > rx_pending > RX_MAX_PENDING | |
ering - > rx_pending < 8 | |
ering - > tx_pending < MAX_SKB_TX_LE | |
ering - > tx_pending > TX_RING_SIZE - 1 )
return - EINVAL ;
if ( netif_running ( dev ) )
sky2_down ( dev ) ;
sky2 - > rx_pending = ering - > rx_pending ;
sky2 - > tx_pending = ering - > tx_pending ;
2005-12-20 15:08:07 -08:00
if ( netif_running ( dev ) ) {
2005-09-14 16:06:14 -07:00
err = sky2_up ( dev ) ;
2005-12-20 15:08:07 -08:00
if ( err )
dev_close ( dev ) ;
2005-12-20 15:08:08 -08:00
else
sky2_set_multicast ( dev ) ;
2005-12-20 15:08:07 -08:00
}
2005-09-14 16:06:14 -07:00
return err ;
}
static int sky2_get_regs_len ( struct net_device * dev )
{
2005-09-19 15:47:57 -07:00
return 0x4000 ;
2005-09-14 16:06:14 -07:00
}
/*
* Returns copy of control register region
2005-09-19 15:47:57 -07:00
* Note : access to the RAM address register set will cause timeouts .
2005-09-14 16:06:14 -07:00
*/
static void sky2_get_regs ( struct net_device * dev , struct ethtool_regs * regs ,
void * p )
{
const struct sky2_port * sky2 = netdev_priv ( dev ) ;
const void __iomem * io = sky2 - > hw - > regs ;
2005-09-19 15:47:57 -07:00
BUG_ON ( regs - > len < B3_RI_WTO_R1 ) ;
2005-09-14 16:06:14 -07:00
regs - > version = 1 ;
2005-09-19 15:47:57 -07:00
memset ( p , 0 , regs - > len ) ;
2005-09-14 16:06:14 -07:00
2005-09-19 15:47:57 -07:00
memcpy_fromio ( p , io , B3_RAM_ADDR ) ;
memcpy_fromio ( p + B3_RI_WTO_R1 ,
io + B3_RI_WTO_R1 ,
regs - > len - B3_RI_WTO_R1 ) ;
2005-09-14 16:06:14 -07:00
}
2005-08-16 16:36:49 -07:00
2006-09-13 14:30:00 -04:00
static const struct ethtool_ops sky2_ethtool_ops = {
2005-09-14 16:06:14 -07:00
. get_settings = sky2_get_settings ,
. set_settings = sky2_set_settings ,
. get_drvinfo = sky2_get_drvinfo ,
. get_msglevel = sky2_get_msglevel ,
. set_msglevel = sky2_set_msglevel ,
2005-09-27 15:28:42 -07:00
. nway_reset = sky2_nway_reset ,
2005-09-14 16:06:14 -07:00
. get_regs_len = sky2_get_regs_len ,
. get_regs = sky2_get_regs ,
. get_link = ethtool_op_get_link ,
. get_sg = ethtool_op_get_sg ,
. set_sg = ethtool_op_set_sg ,
. get_tx_csum = ethtool_op_get_tx_csum ,
. set_tx_csum = ethtool_op_set_tx_csum ,
. get_tso = ethtool_op_get_tso ,
. set_tso = ethtool_op_set_tso ,
. get_rx_csum = sky2_get_rx_csum ,
. set_rx_csum = sky2_set_rx_csum ,
. get_strings = sky2_get_strings ,
2005-12-09 11:34:56 -08:00
. get_coalesce = sky2_get_coalesce ,
. set_coalesce = sky2_set_coalesce ,
2005-09-14 16:06:14 -07:00
. get_ringparam = sky2_get_ringparam ,
. set_ringparam = sky2_set_ringparam ,
2005-08-16 16:36:49 -07:00
. get_pauseparam = sky2_get_pauseparam ,
. set_pauseparam = sky2_set_pauseparam ,
2005-09-14 16:06:14 -07:00
. phys_id = sky2_phys_id ,
2005-08-16 16:36:49 -07:00
. get_stats_count = sky2_get_stats_count ,
. get_ethtool_stats = sky2_get_ethtool_stats ,
2005-09-28 10:01:03 -07:00
. get_perm_addr = ethtool_op_get_perm_addr ,
2005-08-16 16:36:49 -07:00
} ;
/* Initialize network device */
static __devinit struct net_device * sky2_init_netdev ( struct sky2_hw * hw ,
unsigned port , int highmem )
{
struct sky2_port * sky2 ;
struct net_device * dev = alloc_etherdev ( sizeof ( * sky2 ) ) ;
if ( ! dev ) {
printk ( KERN_ERR " sky2 etherdev alloc failed " ) ;
return NULL ;
}
SET_MODULE_OWNER ( dev ) ;
SET_NETDEV_DEV ( dev , & hw - > pdev - > dev ) ;
2005-11-30 11:45:12 -08:00
dev - > irq = hw - > pdev - > irq ;
2005-08-16 16:36:49 -07:00
dev - > open = sky2_up ;
dev - > stop = sky2_down ;
2005-11-30 11:45:12 -08:00
dev - > do_ioctl = sky2_ioctl ;
2005-08-16 16:36:49 -07:00
dev - > hard_start_xmit = sky2_xmit_frame ;
dev - > get_stats = sky2_get_stats ;
dev - > set_multicast_list = sky2_set_multicast ;
dev - > set_mac_address = sky2_set_mac_address ;
dev - > change_mtu = sky2_change_mtu ;
SET_ETHTOOL_OPS ( dev , & sky2_ethtool_ops ) ;
dev - > tx_timeout = sky2_tx_timeout ;
dev - > watchdog_timeo = TX_WATCHDOG ;
if ( port = = 0 )
dev - > poll = sky2_poll ;
dev - > weight = NAPI_WEIGHT ;
# ifdef CONFIG_NET_POLL_CONTROLLER
dev - > poll_controller = sky2_netpoll ;
# endif
sky2 = netdev_priv ( dev ) ;
sky2 - > netdev = dev ;
sky2 - > hw = hw ;
sky2 - > msg_enable = netif_msg_init ( debug , default_msg ) ;
spin_lock_init ( & sky2 - > tx_lock ) ;
/* Auto speed and flow control */
sky2 - > autoneg = AUTONEG_ENABLE ;
2005-12-09 11:35:10 -08:00
sky2 - > tx_pause = 1 ;
2005-08-16 16:36:49 -07:00
sky2 - > rx_pause = 1 ;
sky2 - > duplex = - 1 ;
sky2 - > speed = - 1 ;
sky2 - > advertising = sky2_supported_modes ( hw ) ;
2006-05-18 11:16:21 -07:00
sky2 - > rx_csum = 1 ;
2005-12-09 11:35:11 -08:00
2006-03-20 15:48:17 -08:00
spin_lock_init ( & sky2 - > phy_lock ) ;
2005-09-14 16:06:14 -07:00
sky2 - > tx_pending = TX_DEF_PENDING ;
2006-03-20 15:48:15 -08:00
sky2 - > rx_pending = RX_DEF_PENDING ;
2005-12-09 11:35:00 -08:00
sky2 - > rx_bufsize = sky2_buf_size ( ETH_DATA_LEN ) ;
2005-08-16 16:36:49 -07:00
hw - > dev [ port ] = dev ;
sky2 - > port = port ;
2005-11-30 11:45:15 -08:00
dev - > features | = NETIF_F_LLTX ;
if ( hw - > chip_id ! = CHIP_ID_YUKON_EC_U )
dev - > features | = NETIF_F_TSO ;
2005-08-16 16:36:49 -07:00
if ( highmem )
dev - > features | = NETIF_F_HIGHDMA ;
2005-09-14 16:06:14 -07:00
dev - > features | = NETIF_F_IP_CSUM | NETIF_F_SG ;
2005-08-16 16:36:49 -07:00
2005-09-27 15:02:57 -07:00
# ifdef SKY2_VLAN_TAG_USED
dev - > features | = NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX ;
dev - > vlan_rx_register = sky2_vlan_rx_register ;
dev - > vlan_rx_kill_vid = sky2_vlan_rx_kill_vid ;
# endif
2005-08-16 16:36:49 -07:00
/* read the mac address */
2005-09-14 16:06:14 -07:00
memcpy_fromio ( dev - > dev_addr , hw - > regs + B2_MAC_1 + port * 8 , ETH_ALEN ) ;
2005-09-28 10:01:03 -07:00
memcpy ( dev - > perm_addr , dev - > dev_addr , dev - > addr_len ) ;
2005-08-16 16:36:49 -07:00
/* device is off until link detection */
netif_carrier_off ( dev ) ;
netif_stop_queue ( dev ) ;
return dev ;
}
2006-01-17 13:43:19 -08:00
static void __devinit sky2_show_addr ( struct net_device * dev )
2005-08-16 16:36:49 -07:00
{
const struct sky2_port * sky2 = netdev_priv ( dev ) ;
if ( netif_msg_probe ( sky2 ) )
printk ( KERN_INFO PFX " %s: addr %02x:%02x:%02x:%02x:%02x:%02x \n " ,
dev - > name ,
dev - > dev_addr [ 0 ] , dev - > dev_addr [ 1 ] , dev - > dev_addr [ 2 ] ,
dev - > dev_addr [ 3 ] , dev - > dev_addr [ 4 ] , dev - > dev_addr [ 5 ] ) ;
}
2006-03-20 15:48:19 -08:00
/* Handle software interrupt used during MSI test */
static irqreturn_t __devinit sky2_test_intr ( int irq , void * dev_id ,
struct pt_regs * regs )
{
struct sky2_hw * hw = dev_id ;
u32 status = sky2_read32 ( hw , B0_Y2_SP_ISRC2 ) ;
if ( status = = 0 )
return IRQ_NONE ;
if ( status & Y2_IS_IRQ_SW ) {
hw - > msi_detected = 1 ;
wake_up ( & hw - > msi_wait ) ;
sky2_write8 ( hw , B0_CTST , CS_CL_SW_IRQ ) ;
}
sky2_write32 ( hw , B0_Y2_SP_ICR , 2 ) ;
return IRQ_HANDLED ;
}
/* Test interrupt path by forcing a a software IRQ */
static int __devinit sky2_test_msi ( struct sky2_hw * hw )
{
struct pci_dev * pdev = hw - > pdev ;
int err ;
2006-08-28 10:00:48 -07:00
init_waitqueue_head ( & hw - > msi_wait ) ;
2006-03-20 15:48:19 -08:00
sky2_write32 ( hw , B0_IMSK , Y2_IS_IRQ_SW ) ;
2006-07-01 19:29:39 -07:00
err = request_irq ( pdev - > irq , sky2_test_intr , IRQF_SHARED , DRV_NAME , hw ) ;
2006-03-20 15:48:19 -08:00
if ( err ) {
printk ( KERN_ERR PFX " %s: cannot assign irq %d \n " ,
pci_name ( pdev ) , pdev - > irq ) ;
return err ;
}
sky2_write8 ( hw , B0_CTST , CS_ST_SW_IRQ ) ;
2006-08-28 10:00:48 -07:00
sky2_read8 ( hw , B0_CTST ) ;
2006-03-20 15:48:19 -08:00
wait_event_timeout ( hw - > msi_wait , hw - > msi_detected , HZ / 10 ) ;
if ( ! hw - > msi_detected ) {
/* MSI test failed, go back to INTx mode */
printk ( KERN_WARNING PFX " %s: No interrupt was generated using MSI, "
" switching to INTx mode. Please report this failure to "
" the PCI maintainer and include system chipset information. \n " ,
pci_name ( pdev ) ) ;
err = - EOPNOTSUPP ;
sky2_write8 ( hw , B0_CTST , CS_CL_SW_IRQ ) ;
}
sky2_write32 ( hw , B0_IMSK , 0 ) ;
free_irq ( pdev - > irq , hw ) ;
return err ;
}
2005-08-16 16:36:49 -07:00
static int __devinit sky2_probe ( struct pci_dev * pdev ,
const struct pci_device_id * ent )
{
2005-09-14 16:06:14 -07:00
struct net_device * dev , * dev1 = NULL ;
2005-08-16 16:36:49 -07:00
struct sky2_hw * hw ;
2005-09-27 15:03:00 -07:00
int err , pm_cap , using_dac = 0 ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
err = pci_enable_device ( pdev ) ;
if ( err ) {
2005-08-16 16:36:49 -07:00
printk ( KERN_ERR PFX " %s cannot enable PCI device \n " ,
pci_name ( pdev ) ) ;
goto err_out ;
}
2005-09-14 16:06:14 -07:00
err = pci_request_regions ( pdev , DRV_NAME ) ;
if ( err ) {
2005-08-16 16:36:49 -07:00
printk ( KERN_ERR PFX " %s cannot obtain PCI resources \n " ,
pci_name ( pdev ) ) ;
2005-09-14 16:06:14 -07:00
goto err_out ;
2005-08-16 16:36:49 -07:00
}
pci_set_master ( pdev ) ;
2005-09-27 15:03:00 -07:00
/* Find power-management capability. */
pm_cap = pci_find_capability ( pdev , PCI_CAP_ID_PM ) ;
if ( pm_cap = = 0 ) {
printk ( KERN_ERR PFX " Cannot find PowerManagement capability, "
" aborting. \n " ) ;
err = - EIO ;
goto err_out_free_regions ;
}
2006-01-17 13:43:11 -08:00
if ( sizeof ( dma_addr_t ) > sizeof ( u32 ) & &
! ( err = pci_set_dma_mask ( pdev , DMA_64BIT_MASK ) ) ) {
using_dac = 1 ;
err = pci_set_consistent_dma_mask ( pdev , DMA_64BIT_MASK ) ;
if ( err < 0 ) {
printk ( KERN_ERR PFX " %s unable to obtain 64 bit DMA "
" for consistent allocations \n " , pci_name ( pdev ) ) ;
goto err_out_free_regions ;
}
2005-08-16 16:36:49 -07:00
2006-01-17 13:43:11 -08:00
} else {
2005-08-16 16:36:49 -07:00
err = pci_set_dma_mask ( pdev , DMA_32BIT_MASK ) ;
if ( err ) {
printk ( KERN_ERR PFX " %s no usable DMA configuration \n " ,
pci_name ( pdev ) ) ;
goto err_out_free_regions ;
}
}
2006-01-17 13:43:11 -08:00
2005-08-16 16:36:49 -07:00
err = - ENOMEM ;
2006-01-17 13:43:18 -08:00
hw = kzalloc ( sizeof ( * hw ) , GFP_KERNEL ) ;
2005-08-16 16:36:49 -07:00
if ( ! hw ) {
printk ( KERN_ERR PFX " %s: cannot allocate hardware struct \n " ,
pci_name ( pdev ) ) ;
goto err_out_free_regions ;
}
hw - > pdev = pdev ;
hw - > regs = ioremap_nocache ( pci_resource_start ( pdev , 0 ) , 0x4000 ) ;
if ( ! hw - > regs ) {
printk ( KERN_ERR PFX " %s: cannot map device registers \n " ,
pci_name ( pdev ) ) ;
goto err_out_free_hw ;
}
2005-09-27 15:03:00 -07:00
hw - > pm_cap = pm_cap ;
2005-08-16 16:36:49 -07:00
2006-02-22 11:45:02 -08:00
# ifdef __BIG_ENDIAN
2006-09-06 12:45:02 -07:00
/* The sk98lin vendor driver uses hardware byte swapping but
* this driver uses software swapping .
*/
2006-02-22 11:45:02 -08:00
{
u32 reg ;
reg = sky2_pci_read32 ( hw , PCI_DEV_REG2 ) ;
2006-09-06 12:45:02 -07:00
reg & = ~ PCI_REV_DESC ;
2006-02-22 11:45:02 -08:00
sky2_pci_write32 ( hw , PCI_DEV_REG2 , reg ) ;
}
# endif
2006-01-30 11:37:54 -08:00
/* ring for status responses */
hw - > st_le = pci_alloc_consistent ( hw - > pdev , STATUS_LE_BYTES ,
& hw - > st_dma ) ;
if ( ! hw - > st_le )
goto err_out_iounmap ;
2005-08-16 16:36:49 -07:00
err = sky2_reset ( hw ) ;
if ( err )
2005-09-14 16:06:14 -07:00
goto err_out_iounmap ;
2005-08-16 16:36:49 -07:00
2006-06-12 15:13:08 -07:00
printk ( KERN_INFO PFX " v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d \n " ,
DRV_VERSION , ( unsigned long long ) pci_resource_start ( pdev , 0 ) ,
pdev - > irq , yukon2_name [ hw - > chip_id - CHIP_ID_YUKON_XL ] ,
2005-09-14 16:06:14 -07:00
hw - > chip_id , hw - > chip_rev ) ;
2005-08-16 16:36:49 -07:00
2005-09-14 16:06:14 -07:00
dev = sky2_init_netdev ( hw , 0 , using_dac ) ;
if ( ! dev )
2005-08-16 16:36:49 -07:00
goto err_out_free_pci ;
2006-09-26 11:57:40 -07:00
if ( ! disable_msi & & pci_enable_msi ( pdev ) = = 0 ) {
err = sky2_test_msi ( hw ) ;
if ( err = = - EOPNOTSUPP )
pci_disable_msi ( pdev ) ;
else if ( err )
goto err_out_free_netdev ;
}
2005-09-14 16:06:14 -07:00
err = register_netdev ( dev ) ;
if ( err ) {
2005-08-16 16:36:49 -07:00
printk ( KERN_ERR PFX " %s: cannot register net device \n " ,
pci_name ( pdev ) ) ;
goto err_out_free_netdev ;
}
2006-09-26 11:57:40 -07:00
err = request_irq ( pdev - > irq , sky2_intr , IRQF_SHARED , dev - > name , hw ) ;
if ( err ) {
printk ( KERN_ERR PFX " %s: cannot assign irq %d \n " ,
pci_name ( pdev ) , pdev - > irq ) ;
goto err_out_unregister ;
}
sky2_write32 ( hw , B0_IMSK , Y2_IS_BASE ) ;
2005-08-16 16:36:49 -07:00
sky2_show_addr ( dev ) ;
if ( hw - > ports > 1 & & ( dev1 = sky2_init_netdev ( hw , 1 , using_dac ) ) ) {
if ( register_netdev ( dev1 ) = = 0 )
sky2_show_addr ( dev1 ) ;
else {
/* Failure to register second port need not be fatal */
2005-09-14 16:06:14 -07:00
printk ( KERN_WARNING PFX
" register of second port failed \n " ) ;
2005-08-16 16:36:49 -07:00
hw - > dev [ 1 ] = NULL ;
free_netdev ( dev1 ) ;
}
}
2006-05-08 15:11:30 -07:00
setup_timer ( & hw - > idle_timer , sky2_idle , ( unsigned long ) hw ) ;
2006-06-13 17:17:31 +09:00
sky2_idle_start ( hw ) ;
2006-04-25 10:58:51 -07:00
2005-09-14 16:06:14 -07:00
pci_set_drvdata ( pdev , hw ) ;
2005-08-16 16:36:49 -07:00
return 0 ;
2005-09-14 16:06:14 -07:00
err_out_unregister :
2006-03-20 15:48:19 -08:00
pci_disable_msi ( pdev ) ;
2005-09-14 16:06:14 -07:00
unregister_netdev ( dev ) ;
2005-08-16 16:36:49 -07:00
err_out_free_netdev :
free_netdev ( dev ) ;
err_out_free_pci :
2005-09-14 16:06:14 -07:00
sky2_write8 ( hw , B0_CTST , CS_RST_SET ) ;
2005-08-16 16:36:49 -07:00
pci_free_consistent ( hw - > pdev , STATUS_LE_BYTES , hw - > st_le , hw - > st_dma ) ;
err_out_iounmap :
iounmap ( hw - > regs ) ;
err_out_free_hw :
kfree ( hw ) ;
err_out_free_regions :
pci_release_regions ( pdev ) ;
pci_disable_device ( pdev ) ;
err_out :
return err ;
}
static void __devexit sky2_remove ( struct pci_dev * pdev )
{
2005-09-14 16:06:14 -07:00
struct sky2_hw * hw = pci_get_drvdata ( pdev ) ;
2005-08-16 16:36:49 -07:00
struct net_device * dev0 , * dev1 ;
2005-09-14 16:06:14 -07:00
if ( ! hw )
2005-08-16 16:36:49 -07:00
return ;
2006-04-25 10:58:51 -07:00
del_timer_sync ( & hw - > idle_timer ) ;
sky2_write32 ( hw , B0_IMSK , 0 ) ;
2006-05-08 15:11:32 -07:00
synchronize_irq ( hw - > pdev - > irq ) ;
2005-08-16 16:36:49 -07:00
dev0 = hw - > dev [ 0 ] ;
2005-09-14 16:06:14 -07:00
dev1 = hw - > dev [ 1 ] ;
if ( dev1 )
unregister_netdev ( dev1 ) ;
2005-08-16 16:36:49 -07:00
unregister_netdev ( dev0 ) ;
2005-09-27 15:03:00 -07:00
sky2_set_power_state ( hw , PCI_D3hot ) ;
2005-08-16 16:36:49 -07:00
sky2_write16 ( hw , B0_Y2LED , LED_STAT_OFF ) ;
2005-09-14 16:06:14 -07:00
sky2_write8 ( hw , B0_CTST , CS_RST_SET ) ;
2005-09-27 15:03:00 -07:00
sky2_read8 ( hw , B0_CTST ) ;
2005-08-16 16:36:49 -07:00
free_irq ( pdev - > irq , hw ) ;
2006-03-20 15:48:19 -08:00
pci_disable_msi ( pdev ) ;
2005-09-14 16:06:14 -07:00
pci_free_consistent ( pdev , STATUS_LE_BYTES , hw - > st_le , hw - > st_dma ) ;
2005-08-16 16:36:49 -07:00
pci_release_regions ( pdev ) ;
pci_disable_device ( pdev ) ;
2005-09-14 16:06:14 -07:00
2005-08-16 16:36:49 -07:00
if ( dev1 )
free_netdev ( dev1 ) ;
free_netdev ( dev0 ) ;
iounmap ( hw - > regs ) ;
kfree ( hw ) ;
2005-09-27 15:03:00 -07:00
2005-08-16 16:36:49 -07:00
pci_set_drvdata ( pdev , NULL ) ;
}
# ifdef CONFIG_PM
static int sky2_suspend ( struct pci_dev * pdev , pm_message_t state )
{
2005-09-14 16:06:14 -07:00
struct sky2_hw * hw = pci_get_drvdata ( pdev ) ;
2005-09-27 15:03:00 -07:00
int i ;
2006-06-13 17:17:27 +09:00
pci_power_t pstate = pci_choose_state ( pdev , state ) ;
if ( ! ( pstate = = PCI_D3hot | | pstate = = PCI_D3cold ) )
return - EINVAL ;
2005-08-16 16:36:49 -07:00
2006-06-13 17:17:31 +09:00
del_timer_sync ( & hw - > idle_timer ) ;
2006-07-12 15:23:46 -07:00
netif_poll_disable ( hw - > dev [ 0 ] ) ;
2006-06-13 17:17:31 +09:00
2006-06-13 17:17:28 +09:00
for ( i = 0 ; i < hw - > ports ; i + + ) {
2005-08-16 16:36:49 -07:00
struct net_device * dev = hw - > dev [ i ] ;
2006-07-12 15:23:46 -07:00
if ( netif_running ( dev ) ) {
2005-09-27 15:03:00 -07:00
sky2_down ( dev ) ;
2005-08-16 16:36:49 -07:00
netif_device_detach ( dev ) ;
}
}
2006-06-13 17:17:30 +09:00
sky2_write32 ( hw , B0_IMSK , 0 ) ;
2006-06-12 12:53:27 -07:00
pci_save_state ( pdev ) ;
2006-06-13 17:17:27 +09:00
sky2_set_power_state ( hw , pstate ) ;
return 0 ;
2005-08-16 16:36:49 -07:00
}
static int sky2_resume ( struct pci_dev * pdev )
{
2005-09-14 16:06:14 -07:00
struct sky2_hw * hw = pci_get_drvdata ( pdev ) ;
2006-01-30 11:37:54 -08:00
int i , err ;
2005-08-16 16:36:49 -07:00
pci_restore_state ( pdev ) ;
pci_enable_wake ( pdev , PCI_D0 , 0 ) ;
2006-06-13 17:17:27 +09:00
sky2_set_power_state ( hw , PCI_D0 ) ;
2005-08-16 16:36:49 -07:00
2006-01-30 11:37:54 -08:00
err = sky2_reset ( hw ) ;
if ( err )
goto out ;
2005-08-16 16:36:49 -07:00
2006-06-13 17:17:30 +09:00
sky2_write32 ( hw , B0_IMSK , Y2_IS_BASE ) ;
2006-06-13 17:17:28 +09:00
for ( i = 0 ; i < hw - > ports ; i + + ) {
2005-08-16 16:36:49 -07:00
struct net_device * dev = hw - > dev [ i ] ;
2006-07-12 15:23:46 -07:00
if ( netif_running ( dev ) ) {
2006-01-30 11:37:54 -08:00
netif_device_attach ( dev ) ;
2006-06-16 12:10:46 -07:00
2006-01-30 11:37:54 -08:00
err = sky2_up ( dev ) ;
if ( err ) {
printk ( KERN_ERR PFX " %s: could not up: %d \n " ,
dev - > name , err ) ;
dev_close ( dev ) ;
2006-06-13 17:17:31 +09:00
goto out ;
2005-09-27 15:03:00 -07:00
}
2005-08-16 16:36:49 -07:00
}
}
2006-06-13 17:17:31 +09:00
2006-07-12 15:23:46 -07:00
netif_poll_enable ( hw - > dev [ 0 ] ) ;
2006-06-13 17:17:31 +09:00
sky2_idle_start ( hw ) ;
2006-01-30 11:37:54 -08:00
out :
return err ;
2005-08-16 16:36:49 -07:00
}
# endif
static struct pci_driver sky2_driver = {
2005-09-14 16:06:14 -07:00
. name = DRV_NAME ,
. id_table = sky2_id_table ,
. probe = sky2_probe ,
. remove = __devexit_p ( sky2_remove ) ,
2005-08-16 16:36:49 -07:00
# ifdef CONFIG_PM
2005-09-14 16:06:14 -07:00
. suspend = sky2_suspend ,
. resume = sky2_resume ,
2005-08-16 16:36:49 -07:00
# endif
} ;
static int __init sky2_init_module ( void )
{
2005-11-30 11:45:22 -08:00
return pci_register_driver ( & sky2_driver ) ;
2005-08-16 16:36:49 -07:00
}
static void __exit sky2_cleanup_module ( void )
{
pci_unregister_driver ( & sky2_driver ) ;
}
module_init ( sky2_init_module ) ;
module_exit ( sky2_cleanup_module ) ;
MODULE_DESCRIPTION ( " Marvell Yukon 2 Gigabit Ethernet driver " ) ;
MODULE_AUTHOR ( " Stephen Hemminger <shemminger@osdl.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;
2005-11-30 11:45:23 -08:00
MODULE_VERSION ( DRV_VERSION ) ;