2006-10-21 23:33:03 +04:00
/*
* Copyright ( C ) 2003 - 2006 NetXen , Inc .
* All rights reserved .
2006-12-04 20:18:00 +03:00
*
2006-10-21 23:33:03 +04:00
* 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 .
2006-12-04 20:18:00 +03:00
*
2006-10-21 23:33:03 +04:00
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2006-12-04 20:18:00 +03:00
*
2006-10-21 23:33:03 +04:00
* 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 . , 59 Temple Place - Suite 330 , Boston ,
* MA 02111 - 1307 , USA .
2006-12-04 20:18:00 +03:00
*
2006-10-21 23:33:03 +04:00
* The full GNU General Public License is included in this distribution
* in the file called LICENSE .
2006-12-04 20:18:00 +03:00
*
2006-10-21 23:33:03 +04:00
* Contact Information :
* info @ netxen . com
* NetXen ,
* 3965 Freedom Circle , Fourth floor ,
* Santa Clara , CA 95054
*
*
* Main source file for NetXen NIC Driver on Linux
*
*/
2006-11-29 20:00:10 +03:00
# include <linux/vmalloc.h>
2006-12-04 20:23:25 +03:00
# include <linux/highmem.h>
2006-10-21 23:33:03 +04:00
# include "netxen_nic_hw.h"
# include "netxen_nic.h"
# include "netxen_nic_phan_reg.h"
2006-11-07 13:12:16 +03:00
# include <linux/dma-mapping.h>
# include <linux/vmalloc.h>
2007-03-13 02:09:15 +03:00
# include <net/ip.h>
2006-11-07 13:12:16 +03:00
2006-10-21 23:33:03 +04:00
MODULE_DESCRIPTION ( " NetXen Multi port (1/10) Gigabit Network Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( NETXEN_NIC_LINUX_VERSIONID ) ;
2006-12-04 20:23:25 +03:00
char netxen_nic_driver_name [ ] = " netxen-nic " ;
2006-10-21 23:33:03 +04:00
static char netxen_nic_driver_string [ ] = " NetXen Network Driver version "
2006-11-29 20:00:10 +03:00
NETXEN_NIC_LINUX_VERSIONID ;
2006-10-21 23:33:03 +04:00
# define NETXEN_NETDEV_WEIGHT 120
# define NETXEN_ADAPTER_UP_MAGIC 777
2006-11-29 20:00:10 +03:00
# define NETXEN_NIC_PEG_TUNE 0
2006-10-21 23:33:03 +04:00
2006-12-04 20:23:25 +03:00
u8 nx_p2_id = NX_P2_C0 ;
# define DMA_32BIT_MASK 0x00000000ffffffffULL
# define DMA_35BIT_MASK 0x00000007ffffffffULL
2006-10-21 23:33:03 +04:00
/* Local functions to NetXen NIC driver */
static int __devinit netxen_nic_probe ( struct pci_dev * pdev ,
const struct pci_device_id * ent ) ;
static void __devexit netxen_nic_remove ( struct pci_dev * pdev ) ;
static int netxen_nic_open ( struct net_device * netdev ) ;
static int netxen_nic_close ( struct net_device * netdev ) ;
static int netxen_nic_xmit_frame ( struct sk_buff * , struct net_device * ) ;
static void netxen_tx_timeout ( struct net_device * netdev ) ;
2006-12-05 22:36:26 +03:00
static void netxen_tx_timeout_task ( struct work_struct * work ) ;
2006-10-21 23:33:03 +04:00
static void netxen_watchdog ( unsigned long ) ;
static int netxen_handle_int ( struct netxen_adapter * , struct net_device * ) ;
static int netxen_nic_poll ( struct net_device * dev , int * budget ) ;
# ifdef CONFIG_NET_POLL_CONTROLLER
static void netxen_nic_poll_controller ( struct net_device * netdev ) ;
# endif
2006-11-07 13:12:16 +03:00
static irqreturn_t netxen_intr ( int irq , void * data ) ;
2006-10-21 23:33:03 +04:00
/* PCI Device ID Table */
static struct pci_device_id netxen_pci_tbl [ ] __devinitdata = {
{ PCI_DEVICE ( 0x4040 , 0x0001 ) } ,
{ PCI_DEVICE ( 0x4040 , 0x0002 ) } ,
{ PCI_DEVICE ( 0x4040 , 0x0003 ) } ,
{ PCI_DEVICE ( 0x4040 , 0x0004 ) } ,
{ PCI_DEVICE ( 0x4040 , 0x0005 ) } ,
2006-12-18 16:50:59 +03:00
{ PCI_DEVICE ( 0x4040 , 0x0024 ) } ,
{ PCI_DEVICE ( 0x4040 , 0x0025 ) } ,
2006-10-21 23:33:03 +04:00
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , netxen_pci_tbl ) ;
2006-12-04 20:23:25 +03:00
struct workqueue_struct * netxen_workq ;
static void netxen_watchdog ( unsigned long ) ;
2007-04-20 18:52:37 +04:00
static inline void netxen_nic_update_cmd_producer ( struct netxen_adapter * adapter ,
uint32_t crb_producer )
{
switch ( adapter - > portnum ) {
case 0 :
writel ( crb_producer , NETXEN_CRB_NORMALIZE
( adapter , CRB_CMD_PRODUCER_OFFSET ) ) ;
return ;
case 1 :
writel ( crb_producer , NETXEN_CRB_NORMALIZE
( adapter , CRB_CMD_PRODUCER_OFFSET_1 ) ) ;
return ;
case 2 :
writel ( crb_producer , NETXEN_CRB_NORMALIZE
( adapter , CRB_CMD_PRODUCER_OFFSET_2 ) ) ;
return ;
case 3 :
writel ( crb_producer , NETXEN_CRB_NORMALIZE
( adapter , CRB_CMD_PRODUCER_OFFSET_3 ) ) ;
return ;
default :
printk ( KERN_WARNING " We tried to update "
" CRB_CMD_PRODUCER_OFFSET for invalid "
" PCI function id %d \n " ,
adapter - > portnum ) ;
return ;
}
}
static inline void netxen_nic_update_cmd_consumer ( struct netxen_adapter * adapter ,
u32 crb_consumer )
{
switch ( adapter - > portnum ) {
case 0 :
writel ( crb_consumer , NETXEN_CRB_NORMALIZE
( adapter , CRB_CMD_CONSUMER_OFFSET ) ) ;
return ;
case 1 :
writel ( crb_consumer , NETXEN_CRB_NORMALIZE
( adapter , CRB_CMD_CONSUMER_OFFSET_1 ) ) ;
return ;
case 2 :
writel ( crb_consumer , NETXEN_CRB_NORMALIZE
( adapter , CRB_CMD_CONSUMER_OFFSET_2 ) ) ;
return ;
case 3 :
writel ( crb_consumer , NETXEN_CRB_NORMALIZE
( adapter , CRB_CMD_CONSUMER_OFFSET_3 ) ) ;
return ;
default :
printk ( KERN_WARNING " We tried to update "
" CRB_CMD_PRODUCER_OFFSET for invalid "
" PCI function id %d \n " ,
adapter - > portnum ) ;
return ;
}
}
# define ADAPTER_LIST_SIZE 12
int netxen_cards_found ;
2006-10-21 23:33:03 +04:00
/*
* netxen_nic_probe ( )
*
* The Linux system will invoke this after identifying the vendor ID and
* device Id in the pci_tbl supported by this module .
*
* A quad port card has one operational PCI config space , ( function 0 ) ,
* which is used to access all four ports .
*
* This routine will initialize the adapter , and setup the global parameters
* along with the port ' s specific structure .
*/
static int __devinit
netxen_nic_probe ( struct pci_dev * pdev , const struct pci_device_id * ent )
{
struct net_device * netdev = NULL ;
struct netxen_adapter * adapter = NULL ;
2006-12-04 20:23:25 +03:00
void __iomem * mem_ptr0 = NULL ;
void __iomem * mem_ptr1 = NULL ;
void __iomem * mem_ptr2 = NULL ;
2006-11-29 20:00:10 +03:00
2007-01-02 13:39:10 +03:00
u8 __iomem * db_ptr = NULL ;
2006-12-04 20:23:25 +03:00
unsigned long mem_base , mem_len , db_base , db_len ;
2007-04-20 18:52:37 +04:00
int pci_using_dac , i = 0 , err ;
2006-10-21 23:33:03 +04:00
int ring ;
struct netxen_recv_context * recv_ctx = NULL ;
struct netxen_rcv_desc_ctx * rcv_desc = NULL ;
struct netxen_cmd_buffer * cmd_buf_arr = NULL ;
u64 mac_addr [ FLASH_NUM_PORTS + 1 ] ;
2007-04-20 18:52:37 +04:00
static int valid_mac = 0 ;
static int netxen_probe_flag ;
int pci_func_id = PCI_FUNC ( pdev - > devfn ) ;
2006-10-21 23:33:03 +04:00
2006-11-29 20:00:10 +03:00
printk ( KERN_INFO " %s \n " , netxen_nic_driver_string ) ;
2007-04-20 18:52:37 +04:00
if ( pdev - > class ! = 0x020000 ) {
printk ( KERN_ERR " NetXen function %d, class %x will not "
" be enabled. \n " , pci_func_id , pdev - > class ) ;
2006-12-04 20:23:25 +03:00
return - ENODEV ;
}
2006-10-21 23:33:03 +04:00
if ( ( err = pci_enable_device ( pdev ) ) )
return err ;
if ( ! ( pci_resource_flags ( pdev , 0 ) & IORESOURCE_MEM ) ) {
err = - ENODEV ;
goto err_out_disable_pdev ;
}
if ( ( err = pci_request_regions ( pdev , netxen_nic_driver_name ) ) )
goto err_out_disable_pdev ;
pci_set_master ( pdev ) ;
2006-12-04 20:23:25 +03:00
pci_read_config_byte ( pdev , PCI_REVISION_ID , & nx_p2_id ) ;
if ( nx_p2_id = = NX_P2_C1 & &
( pci_set_dma_mask ( pdev , DMA_35BIT_MASK ) = = 0 ) & &
( pci_set_consistent_dma_mask ( pdev , DMA_35BIT_MASK ) = = 0 ) ) {
2006-10-21 23:33:03 +04:00
pci_using_dac = 1 ;
2006-12-04 20:23:25 +03:00
} else {
2006-10-21 23:33:03 +04:00
if ( ( err = pci_set_dma_mask ( pdev , DMA_32BIT_MASK ) ) | |
( err = pci_set_consistent_dma_mask ( pdev , DMA_32BIT_MASK ) ) )
goto err_out_free_res ;
pci_using_dac = 0 ;
}
2007-04-20 18:52:37 +04:00
netdev = alloc_etherdev ( sizeof ( struct netxen_adapter ) ) ;
if ( ! netdev ) {
printk ( KERN_ERR " %s: Failed to allocate memory for the "
" device block.Check system memory resource "
" usage. \n " , netxen_nic_driver_name ) ;
goto err_out_free_res ;
}
SET_MODULE_OWNER ( netdev ) ;
SET_NETDEV_DEV ( netdev , & pdev - > dev ) ;
adapter = netdev - > priv ;
memset ( adapter , 0 , sizeof ( struct netxen_adapter ) ) ;
adapter - > ahw . pdev = pdev ;
2007-04-20 18:53:05 +04:00
adapter - > ahw . pci_func = pci_func_id ;
2006-10-21 23:33:03 +04:00
/* remap phys address */
mem_base = pci_resource_start ( pdev , 0 ) ; /* 0 is for BAR 0 */
mem_len = pci_resource_len ( pdev , 0 ) ;
/* 128 Meg of memory */
2006-11-29 20:00:10 +03:00
mem_ptr0 = ioremap ( mem_base , FIRST_PAGE_GROUP_SIZE ) ;
mem_ptr1 =
ioremap ( mem_base + SECOND_PAGE_GROUP_START , SECOND_PAGE_GROUP_SIZE ) ;
mem_ptr2 =
ioremap ( mem_base + THIRD_PAGE_GROUP_START , THIRD_PAGE_GROUP_SIZE ) ;
if ( ( mem_ptr0 = = 0UL ) | | ( mem_ptr1 = = 0UL ) | | ( mem_ptr2 = = 0UL ) ) {
2006-12-04 20:23:25 +03:00
DPRINTK ( ERR ,
2006-11-29 20:00:10 +03:00
" Cannot remap adapter memory aborting.: "
" 0 -> %p, 1 -> %p, 2 -> %p \n " ,
mem_ptr0 , mem_ptr1 , mem_ptr2 ) ;
2006-10-21 23:33:03 +04:00
err = - EIO ;
2006-12-04 20:23:25 +03:00
goto err_out_iounmap ;
}
db_base = pci_resource_start ( pdev , 4 ) ; /* doorbell is on bar 4 */
db_len = pci_resource_len ( pdev , 4 ) ;
if ( db_len = = 0 ) {
printk ( KERN_ERR " %s: doorbell is disabled \n " ,
netxen_nic_driver_name ) ;
err = - EIO ;
goto err_out_iounmap ;
}
DPRINTK ( INFO , " doorbell ioremap from %lx a size of %lx \n " , db_base ,
db_len ) ;
db_ptr = ioremap ( db_base , NETXEN_DB_MAPSIZE_BYTES ) ;
2007-01-02 13:39:10 +03:00
if ( ! db_ptr ) {
2006-12-04 20:23:25 +03:00
printk ( KERN_ERR " %s: Failed to allocate doorbell map. " ,
netxen_nic_driver_name ) ;
err = - EIO ;
goto err_out_iounmap ;
2006-10-21 23:33:03 +04:00
}
2006-12-04 20:23:25 +03:00
DPRINTK ( INFO , " doorbell ioremaped at %p \n " , db_ptr ) ;
2006-10-21 23:33:03 +04:00
adapter - > max_tx_desc_count = MAX_CMD_DESCRIPTORS ;
2007-04-20 18:53:05 +04:00
if ( ( adapter - > ahw . boardcfg . board_type = = NETXEN_BRDTYPE_P2_SB35_4G ) | |
( adapter - > ahw . boardcfg . board_type = =
NETXEN_BRDTYPE_P2_SB31_2G ) )
adapter - > max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G ;
else
adapter - > max_rx_desc_count = MAX_RCV_DESCRIPTORS ;
2006-10-21 23:33:03 +04:00
adapter - > max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS ;
2006-12-04 20:23:25 +03:00
adapter - > max_lro_rx_desc_count = MAX_LRO_RCV_DESCRIPTORS ;
2006-10-21 23:33:03 +04:00
2007-04-20 18:53:52 +04:00
pci_set_drvdata ( pdev , netdev ) ;
2006-10-21 23:33:03 +04:00
2007-04-20 18:52:37 +04:00
adapter - > netdev = netdev ;
adapter - > pdev = pdev ;
adapter - > portnum = pci_func_id ;
netdev - > open = netxen_nic_open ;
netdev - > stop = netxen_nic_close ;
netdev - > hard_start_xmit = netxen_nic_xmit_frame ;
netdev - > set_multicast_list = netxen_nic_set_multi ;
netdev - > set_mac_address = netxen_nic_set_mac ;
netdev - > change_mtu = netxen_nic_change_mtu ;
netdev - > tx_timeout = netxen_tx_timeout ;
netdev - > watchdog_timeo = HZ ;
netxen_nic_change_mtu ( netdev , netdev - > mtu ) ;
SET_ETHTOOL_OPS ( netdev , & netxen_nic_ethtool_ops ) ;
netdev - > poll = netxen_nic_poll ;
netdev - > weight = NETXEN_NETDEV_WEIGHT ;
# ifdef CONFIG_NET_POLL_CONTROLLER
netdev - > poll_controller = netxen_nic_poll_controller ;
# endif
/* ScatterGather support */
netdev - > features = NETIF_F_SG ;
netdev - > features | = NETIF_F_IP_CSUM ;
netdev - > features | = NETIF_F_TSO ;
if ( pci_using_dac )
netdev - > features | = NETIF_F_HIGHDMA ;
if ( pci_enable_msi ( pdev ) ) {
adapter - > flags & = ~ NETXEN_NIC_MSI_ENABLED ;
printk ( KERN_WARNING " %s: unable to allocate MSI interrupt "
" error \n " , netxen_nic_driver_name ) ;
} else
adapter - > flags | = NETXEN_NIC_MSI_ENABLED ;
2006-10-21 23:33:03 +04:00
cmd_buf_arr = ( struct netxen_cmd_buffer * ) vmalloc ( TX_RINGSIZE ) ;
if ( cmd_buf_arr = = NULL ) {
2006-12-04 20:23:25 +03:00
printk ( KERN_ERR
" %s: Could not allocate cmd_buf_arr memory:%d \n " ,
netxen_nic_driver_name , ( int ) TX_RINGSIZE ) ;
2006-10-21 23:33:03 +04:00
err = - ENOMEM ;
goto err_out_free_adapter ;
}
memset ( cmd_buf_arr , 0 , TX_RINGSIZE ) ;
for ( i = 0 ; i < MAX_RCV_CTX ; + + i ) {
recv_ctx = & adapter - > recv_ctx [ i ] ;
for ( ring = 0 ; ring < NUM_RCV_DESC_RINGS ; ring + + ) {
rcv_desc = & recv_ctx - > rcv_desc [ ring ] ;
switch ( RCV_DESC_TYPE ( ring ) ) {
case RCV_DESC_NORMAL :
rcv_desc - > max_rx_desc_count =
adapter - > max_rx_desc_count ;
rcv_desc - > flags = RCV_DESC_NORMAL ;
rcv_desc - > dma_size = RX_DMA_MAP_LEN ;
rcv_desc - > skb_size = MAX_RX_BUFFER_LENGTH ;
break ;
case RCV_DESC_JUMBO :
rcv_desc - > max_rx_desc_count =
adapter - > max_jumbo_rx_desc_count ;
rcv_desc - > flags = RCV_DESC_JUMBO ;
rcv_desc - > dma_size = RX_JUMBO_DMA_MAP_LEN ;
rcv_desc - > skb_size = MAX_RX_JUMBO_BUFFER_LENGTH ;
break ;
2006-12-04 20:23:25 +03:00
case RCV_RING_LRO :
rcv_desc - > max_rx_desc_count =
adapter - > max_lro_rx_desc_count ;
rcv_desc - > flags = RCV_DESC_LRO ;
rcv_desc - > dma_size = RX_LRO_DMA_MAP_LEN ;
rcv_desc - > skb_size = MAX_RX_LRO_BUFFER_LENGTH ;
break ;
2006-10-21 23:33:03 +04:00
}
rcv_desc - > rx_buf_arr = ( struct netxen_rx_buffer * )
vmalloc ( RCV_BUFFSIZE ) ;
if ( rcv_desc - > rx_buf_arr = = NULL ) {
2006-12-04 20:23:25 +03:00
printk ( KERN_ERR " %s: Could not allocate "
" rcv_desc->rx_buf_arr memory:%d \n " ,
netxen_nic_driver_name ,
( int ) RCV_BUFFSIZE ) ;
2006-10-21 23:33:03 +04:00
err = - ENOMEM ;
goto err_out_free_rx_buffer ;
}
memset ( rcv_desc - > rx_buf_arr , 0 , RCV_BUFFSIZE ) ;
}
}
adapter - > cmd_buf_arr = cmd_buf_arr ;
2006-11-29 20:00:10 +03:00
adapter - > ahw . pci_base0 = mem_ptr0 ;
adapter - > ahw . pci_base1 = mem_ptr1 ;
adapter - > ahw . pci_base2 = mem_ptr2 ;
2006-12-04 20:23:25 +03:00
adapter - > ahw . db_base = db_ptr ;
adapter - > ahw . db_len = db_len ;
2006-10-21 23:33:03 +04:00
spin_lock_init ( & adapter - > tx_lock ) ;
spin_lock_init ( & adapter - > lock ) ;
2007-04-20 18:53:52 +04:00
/* initialize the adapter */
netxen_initialize_adapter_hw ( adapter ) ;
netxen_initialize_adapter_ops ( adapter ) ;
2006-12-04 20:23:25 +03:00
netxen_initialize_adapter_sw ( adapter ) ; /* initialize the buffers in adapter */
2007-04-20 18:53:05 +04:00
/* Mezz cards have PCI function 0,2,3 enabled */
if ( adapter - > ahw . boardcfg . board_type = = NETXEN_BRDTYPE_P2_SB31_10G_IMEZ )
if ( pci_func_id > = 2 )
adapter - > portnum = pci_func_id - 2 ;
2006-11-29 20:00:10 +03:00
# ifdef CONFIG_IA64
2007-04-20 18:53:05 +04:00
if ( adapter - > portnum = = 0 ) {
2007-04-20 18:52:37 +04:00
netxen_pinit_from_rom ( adapter , 0 ) ;
udelay ( 500 ) ;
netxen_load_firmware ( adapter ) ;
}
2006-11-29 20:00:10 +03:00
# endif
2006-10-21 23:33:03 +04:00
/*
* Set the CRB window to invalid . If any register in window 0 is
* accessed it should set the window to 0 and then reset it to 1.
*/
adapter - > curr_window = 255 ;
/*
* Adapter in our case is quad port so initialize it before
* initializing the ports
*/
init_timer ( & adapter - > watchdog_timer ) ;
adapter - > ahw . xg_linkup = 0 ;
adapter - > watchdog_timer . function = & netxen_watchdog ;
adapter - > watchdog_timer . data = ( unsigned long ) adapter ;
2006-12-05 22:36:26 +03:00
INIT_WORK ( & adapter - > watchdog_task , netxen_watchdog_task ) ;
2006-10-21 23:33:03 +04:00
adapter - > ahw . pdev = pdev ;
adapter - > proc_cmd_buf_counter = 0 ;
2006-12-04 20:23:25 +03:00
adapter - > ahw . revision_id = nx_p2_id ;
2006-10-21 23:33:03 +04:00
2007-04-20 18:52:37 +04:00
netxen_nic_update_cmd_producer ( adapter , 0 ) ;
netxen_nic_update_cmd_consumer ( adapter , 0 ) ;
2006-10-21 23:33:03 +04:00
if ( netxen_is_flash_supported ( adapter ) = = 0 & &
netxen_get_flash_mac_addr ( adapter , mac_addr ) = = 0 )
valid_mac = 1 ;
else
valid_mac = 0 ;
2007-04-20 18:52:37 +04:00
if ( valid_mac ) {
2007-04-20 18:53:05 +04:00
unsigned char * p = ( unsigned char * ) & mac_addr [ adapter - > portnum ] ;
2007-04-20 18:52:37 +04:00
netdev - > dev_addr [ 0 ] = * ( p + 5 ) ;
netdev - > dev_addr [ 1 ] = * ( p + 4 ) ;
netdev - > dev_addr [ 2 ] = * ( p + 3 ) ;
netdev - > dev_addr [ 3 ] = * ( p + 2 ) ;
netdev - > dev_addr [ 4 ] = * ( p + 1 ) ;
netdev - > dev_addr [ 5 ] = * ( p + 0 ) ;
memcpy ( netdev - > perm_addr , netdev - > dev_addr ,
netdev - > addr_len ) ;
if ( ! is_valid_ether_addr ( netdev - > perm_addr ) ) {
printk ( KERN_ERR " %s: Bad MAC address "
" %02x:%02x:%02x:%02x:%02x:%02x. \n " ,
netxen_nic_driver_name ,
netdev - > dev_addr [ 0 ] ,
netdev - > dev_addr [ 1 ] ,
netdev - > dev_addr [ 2 ] ,
netdev - > dev_addr [ 3 ] ,
netdev - > dev_addr [ 4 ] ,
netdev - > dev_addr [ 5 ] ) ;
} else {
if ( adapter - > macaddr_set )
adapter - > macaddr_set ( adapter ,
netdev - > dev_addr ) ;
}
}
2006-11-29 20:00:10 +03:00
/*
* Initialize all the CRB registers here .
*/
writel ( 0 , NETXEN_CRB_NORMALIZE ( adapter , CRB_CMD_PRODUCER_OFFSET ) ) ;
writel ( 0 , NETXEN_CRB_NORMALIZE ( adapter , CRB_CMD_CONSUMER_OFFSET ) ) ;
writel ( 0 , NETXEN_CRB_NORMALIZE ( adapter , CRB_HOST_CMD_ADDR_LO ) ) ;
2006-12-04 20:23:25 +03:00
/* do this before waking up pegs so that we have valid dummy dma addr */
2007-04-20 18:53:05 +04:00
if ( adapter - > portnum = = 0 )
err = netxen_initialize_adapter_offload ( adapter ) ;
2007-04-20 18:52:37 +04:00
if ( err )
2006-12-04 20:23:25 +03:00
goto err_out_free_dev ;
2006-10-21 23:33:03 +04:00
2007-04-20 18:52:37 +04:00
if ( netxen_probe_flag = = 0 ) {
/* Unlock the HW, prompting the boot sequence */
writel ( 1 ,
NETXEN_CRB_NORMALIZE ( adapter ,
NETXEN_ROMUSB_GLB_PEGTUNE_DONE ) ) ;
/* Handshake with the card before we register the devices. */
netxen_phantom_init ( adapter , NETXEN_NIC_PEG_TUNE ) ;
}
2006-10-21 23:33:03 +04:00
2007-04-20 18:52:37 +04:00
if ( netxen_probe_flag = = 0 ) {
writel ( 0 , NETXEN_CRB_NORMALIZE ( adapter , CRB_CMDPEG_STATE ) ) ;
netxen_pinit_from_rom ( adapter , 0 ) ;
udelay ( 500 ) ;
netxen_load_firmware ( adapter ) ;
netxen_phantom_init ( adapter , NETXEN_NIC_PEG_TUNE ) ;
2006-10-21 23:33:03 +04:00
}
/*
* delay a while to ensure that the Pegs are up & running .
* Otherwise , we might see some flaky behaviour .
*/
udelay ( 100 ) ;
2007-04-20 18:52:37 +04:00
INIT_WORK ( & adapter - > tx_timeout_task , netxen_tx_timeout_task ) ;
2007-04-20 18:53:05 +04:00
netxen_nic_erase_pxe ( adapter ) ;
2007-04-20 18:52:37 +04:00
netif_carrier_off ( netdev ) ;
netif_stop_queue ( netdev ) ;
if ( ( err = register_netdev ( netdev ) ) )
DPRINTK ( 1 , ERR , " register_netdev failed port #%d "
" aborting \n " , i + 1 ) ;
2006-10-21 23:33:03 +04:00
switch ( adapter - > ahw . board_type ) {
2007-04-20 18:52:37 +04:00
case NETXEN_NIC_GBE :
printk ( KERN_INFO " %s: QUAD GbE board initialized \n " ,
netxen_nic_driver_name ) ;
break ;
2006-10-21 23:33:03 +04:00
2007-04-20 18:52:37 +04:00
case NETXEN_NIC_XGBE :
printk ( KERN_INFO " %s: XGbE board initialized \n " ,
netxen_nic_driver_name ) ;
break ;
2006-10-21 23:33:03 +04:00
}
adapter - > driver_mismatch = 0 ;
2007-04-20 18:52:37 +04:00
if ( netxen_probe_flag = = 0 )
netxen_probe_flag + + ;
2006-10-21 23:33:03 +04:00
return 0 ;
err_out_free_dev :
if ( adapter - > flags & NETXEN_NIC_MSI_ENABLED )
pci_disable_msi ( pdev ) ;
2007-04-20 18:52:37 +04:00
unregister_netdev ( adapter - > netdev ) ;
free_netdev ( adapter - > netdev ) ;
2006-10-21 23:33:03 +04:00
2006-12-04 20:23:25 +03:00
netxen_free_adapter_offload ( adapter ) ;
2006-10-21 23:33:03 +04:00
err_out_free_rx_buffer :
for ( i = 0 ; i < MAX_RCV_CTX ; + + i ) {
recv_ctx = & adapter - > recv_ctx [ i ] ;
for ( ring = 0 ; ring < NUM_RCV_DESC_RINGS ; ring + + ) {
rcv_desc = & recv_ctx - > rcv_desc [ ring ] ;
if ( rcv_desc - > rx_buf_arr ! = NULL ) {
vfree ( rcv_desc - > rx_buf_arr ) ;
rcv_desc - > rx_buf_arr = NULL ;
}
}
}
vfree ( cmd_buf_arr ) ;
err_out_free_adapter :
pci_set_drvdata ( pdev , NULL ) ;
kfree ( adapter ) ;
2006-12-04 20:23:25 +03:00
if ( db_ptr )
iounmap ( db_ptr ) ;
2006-10-21 23:33:03 +04:00
err_out_iounmap :
2006-12-04 20:23:25 +03:00
if ( mem_ptr0 )
iounmap ( mem_ptr0 ) ;
if ( mem_ptr1 )
iounmap ( mem_ptr1 ) ;
if ( mem_ptr2 )
iounmap ( mem_ptr2 ) ;
2006-11-29 20:00:10 +03:00
2006-10-21 23:33:03 +04:00
err_out_free_res :
pci_release_regions ( pdev ) ;
err_out_disable_pdev :
pci_disable_device ( pdev ) ;
return err ;
}
static void __devexit netxen_nic_remove ( struct pci_dev * pdev )
{
struct netxen_adapter * adapter ;
2007-04-20 18:52:37 +04:00
struct net_device * netdev ;
2006-10-21 23:33:03 +04:00
struct netxen_rx_buffer * buffer ;
struct netxen_recv_context * recv_ctx ;
struct netxen_rcv_desc_ctx * rcv_desc ;
int i ;
int ctxid , ring ;
2007-04-20 18:53:52 +04:00
netdev = pci_get_drvdata ( pdev ) ;
adapter = netdev_priv ( netdev ) ;
2006-10-21 23:33:03 +04:00
if ( adapter = = NULL )
return ;
2007-04-20 18:52:37 +04:00
if ( adapter - > stop_port )
adapter - > stop_port ( adapter ) ;
2007-02-21 17:54:06 +03:00
if ( adapter - > irq )
free_irq ( adapter - > irq , adapter ) ;
2007-04-20 18:53:52 +04:00
if ( adapter - > portnum = = 0 ) {
/* leave the hw in the same state as reboot */
writel ( 0 , NETXEN_CRB_NORMALIZE ( adapter , CRB_CMDPEG_STATE ) ) ;
netxen_pinit_from_rom ( adapter , 0 ) ;
netxen_load_firmware ( adapter ) ;
netxen_free_adapter_offload ( adapter ) ;
}
2006-10-21 23:33:03 +04:00
2007-04-20 18:52:37 +04:00
udelay ( 500 ) ;
2006-10-21 23:33:03 +04:00
if ( ( adapter - > flags & NETXEN_NIC_MSI_ENABLED ) )
pci_disable_msi ( pdev ) ;
if ( adapter - > is_up = = NETXEN_ADAPTER_UP_MAGIC )
netxen_free_hw_resources ( adapter ) ;
2006-12-04 20:23:25 +03:00
iounmap ( adapter - > ahw . db_base ) ;
2006-11-29 20:00:10 +03:00
iounmap ( adapter - > ahw . pci_base0 ) ;
iounmap ( adapter - > ahw . pci_base1 ) ;
iounmap ( adapter - > ahw . pci_base2 ) ;
2006-10-21 23:33:03 +04:00
for ( ctxid = 0 ; ctxid < MAX_RCV_CTX ; + + ctxid ) {
recv_ctx = & adapter - > recv_ctx [ ctxid ] ;
for ( ring = 0 ; ring < NUM_RCV_DESC_RINGS ; ring + + ) {
rcv_desc = & recv_ctx - > rcv_desc [ ring ] ;
for ( i = 0 ; i < rcv_desc - > max_rx_desc_count ; + + i ) {
buffer = & ( rcv_desc - > rx_buf_arr [ i ] ) ;
if ( buffer - > state = = NETXEN_BUFFER_FREE )
continue ;
pci_unmap_single ( pdev , buffer - > dma ,
rcv_desc - > dma_size ,
PCI_DMA_FROMDEVICE ) ;
if ( buffer - > skb ! = NULL )
dev_kfree_skb_any ( buffer - > skb ) ;
}
vfree ( rcv_desc - > rx_buf_arr ) ;
}
}
vfree ( adapter - > cmd_buf_arr ) ;
2007-04-20 18:53:52 +04:00
unregister_netdev ( netdev ) ;
free_netdev ( netdev ) ;
pci_release_regions ( pdev ) ;
pci_disable_device ( pdev ) ;
pci_set_drvdata ( pdev , NULL ) ;
2006-10-21 23:33:03 +04:00
}
/*
* Called when a network interface is made active
* @ returns 0 on success , negative value on failure
*/
static int netxen_nic_open ( struct net_device * netdev )
{
2007-04-20 18:52:37 +04:00
struct netxen_adapter * adapter = ( struct netxen_adapter * ) netdev - > priv ;
2006-10-21 23:33:03 +04:00
int err = 0 ;
int ctx , ring ;
if ( adapter - > is_up ! = NETXEN_ADAPTER_UP_MAGIC ) {
err = netxen_init_firmware ( adapter ) ;
if ( err ! = 0 ) {
printk ( KERN_ERR " Failed to init firmware \n " ) ;
return - EIO ;
}
netxen_nic_flash_print ( adapter ) ;
/* setup all the resources for the Phantom... */
/* this include the descriptors for rcv, tx, and status */
netxen_nic_clear_stats ( adapter ) ;
err = netxen_nic_hw_resources ( adapter ) ;
if ( err ) {
printk ( KERN_ERR " Error in setting hw resources:%d \n " ,
err ) ;
return err ;
}
for ( ctx = 0 ; ctx < MAX_RCV_CTX ; + + ctx ) {
2006-11-29 20:00:10 +03:00
for ( ring = 0 ; ring < NUM_RCV_DESC_RINGS ; ring + + )
2006-10-21 23:33:03 +04:00
netxen_post_rx_buffers ( adapter , ctx , ring ) ;
}
2006-12-04 20:23:25 +03:00
adapter - > irq = adapter - > ahw . pdev - > irq ;
2006-10-21 23:33:03 +04:00
err = request_irq ( adapter - > ahw . pdev - > irq , & netxen_intr ,
2007-02-14 11:33:16 +03:00
IRQF_SHARED | IRQF_SAMPLE_RANDOM ,
netdev - > name , adapter ) ;
2006-10-21 23:33:03 +04:00
if ( err ) {
printk ( KERN_ERR " request_irq failed with: %d \n " , err ) ;
2006-12-04 20:23:25 +03:00
netxen_free_hw_resources ( adapter ) ;
2006-10-21 23:33:03 +04:00
return err ;
}
2006-12-04 20:23:25 +03:00
adapter - > is_up = NETXEN_ADAPTER_UP_MAGIC ;
}
2007-04-20 18:52:37 +04:00
if ( ! adapter - > driver_mismatch )
mod_timer ( & adapter - > watchdog_timer , jiffies ) ;
2006-10-21 23:33:03 +04:00
2007-04-20 18:52:37 +04:00
netxen_nic_enable_int ( adapter ) ;
2006-10-21 23:33:03 +04:00
/* Done here again so that even if phantom sw overwrote it,
* we set it */
2006-12-04 20:18:00 +03:00
if ( adapter - > macaddr_set )
2007-04-20 18:52:37 +04:00
adapter - > macaddr_set ( adapter , netdev - > dev_addr ) ;
2007-04-20 18:53:52 +04:00
if ( adapter - > init_port
& & adapter - > init_port ( adapter , adapter - > portnum ) ! = 0 ) {
printk ( KERN_ERR " %s: Failed to initialize port %d \n " ,
netxen_nic_driver_name , adapter - > portnum ) ;
free_irq ( adapter - > irq , adapter ) ;
netxen_free_hw_resources ( adapter ) ;
return - EIO ;
}
2007-04-20 18:52:37 +04:00
netxen_nic_set_link_parameters ( adapter ) ;
2006-10-21 23:33:03 +04:00
netxen_nic_set_multi ( netdev ) ;
2006-12-04 20:23:25 +03:00
if ( adapter - > set_mtu )
2007-04-20 18:52:37 +04:00
adapter - > set_mtu ( adapter , netdev - > mtu ) ;
2006-12-04 20:23:25 +03:00
2006-10-21 23:33:03 +04:00
if ( ! adapter - > driver_mismatch )
netif_start_queue ( netdev ) ;
return 0 ;
}
/*
* netxen_nic_close - Disables a network interface entry point
*/
static int netxen_nic_close ( struct net_device * netdev )
{
2007-04-20 18:52:37 +04:00
struct netxen_adapter * adapter = netdev_priv ( netdev ) ;
2006-10-21 23:33:03 +04:00
int i , j ;
struct netxen_cmd_buffer * cmd_buff ;
struct netxen_skb_frag * buffrag ;
netif_carrier_off ( netdev ) ;
netif_stop_queue ( netdev ) ;
2007-04-20 18:52:37 +04:00
netxen_nic_disable_int ( adapter ) ;
if ( adapter - > irq )
free_irq ( adapter - > irq , adapter ) ;
cmd_buff = adapter - > cmd_buf_arr ;
for ( i = 0 ; i < adapter - > max_tx_desc_count ; i + + ) {
buffrag = cmd_buff - > frag_array ;
if ( buffrag - > dma ) {
pci_unmap_single ( adapter - > pdev , buffrag - > dma ,
buffrag - > length , PCI_DMA_TODEVICE ) ;
buffrag - > dma = ( u64 ) NULL ;
}
for ( j = 0 ; j < cmd_buff - > frag_count ; j + + ) {
buffrag + + ;
2006-10-21 23:33:03 +04:00
if ( buffrag - > dma ) {
2007-04-20 18:52:37 +04:00
pci_unmap_page ( adapter - > pdev , buffrag - > dma ,
buffrag - > length ,
PCI_DMA_TODEVICE ) ;
2006-10-21 23:33:03 +04:00
buffrag - > dma = ( u64 ) NULL ;
}
}
2007-04-20 18:52:37 +04:00
/* Free the skb we received in netxen_nic_xmit_frame */
if ( cmd_buff - > skb ) {
dev_kfree_skb_any ( cmd_buff - > skb ) ;
cmd_buff - > skb = NULL ;
}
cmd_buff + + ;
2006-10-21 23:33:03 +04:00
}
2007-04-20 18:52:37 +04:00
FLUSH_SCHEDULED_WORK ( ) ;
del_timer_sync ( & adapter - > watchdog_timer ) ;
2006-10-21 23:33:03 +04:00
return 0 ;
}
static int netxen_nic_xmit_frame ( struct sk_buff * skb , struct net_device * netdev )
{
2007-04-20 18:52:37 +04:00
struct netxen_adapter * adapter = netdev_priv ( netdev ) ;
2006-10-21 23:33:03 +04:00
struct netxen_hardware_context * hw = & adapter - > ahw ;
unsigned int first_seg_len = skb - > len - skb - > data_len ;
struct netxen_skb_frag * buffrag ;
unsigned int i ;
u32 producer = 0 ;
u32 saved_producer = 0 ;
struct cmd_desc_type0 * hwdesc ;
int k ;
struct netxen_cmd_buffer * pbuf = NULL ;
static int dropped_packet = 0 ;
int frag_count ;
u32 local_producer = 0 ;
u32 max_tx_desc_count = 0 ;
u32 last_cmd_consumer = 0 ;
int no_of_desc ;
2007-04-20 18:52:37 +04:00
adapter - > stats . xmitcalled + + ;
2006-10-21 23:33:03 +04:00
frag_count = skb_shinfo ( skb ) - > nr_frags + 1 ;
if ( unlikely ( skb - > len < = 0 ) ) {
dev_kfree_skb_any ( skb ) ;
2007-04-20 18:52:37 +04:00
adapter - > stats . badskblen + + ;
2006-10-21 23:33:03 +04:00
return NETDEV_TX_OK ;
}
if ( frag_count > MAX_BUFFERS_PER_CMD ) {
printk ( " %s: %s netxen_nic_xmit_frame: frag_count (%d) "
" too large, can handle only %d frags \n " ,
netxen_nic_driver_name , netdev - > name ,
frag_count , MAX_BUFFERS_PER_CMD ) ;
2007-04-20 18:52:37 +04:00
adapter - > stats . txdropped + + ;
2006-10-21 23:33:03 +04:00
if ( ( + + dropped_packet & 0xff ) = = 0xff )
printk ( " %s: %s droppped packets = %d \n " ,
netxen_nic_driver_name , netdev - > name ,
dropped_packet ) ;
return NETDEV_TX_OK ;
}
/*
* Everything is set up . Now , we just need to transmit it out .
* Note that we have to copy the contents of buffer over to
* right place . Later on , this can be optimized out by de - coupling the
* producer index from the buffer index .
*/
retry_getting_window :
spin_lock_bh ( & adapter - > tx_lock ) ;
2007-04-20 18:52:37 +04:00
if ( adapter - > total_threads > = MAX_XMIT_PRODUCERS ) {
2006-10-21 23:33:03 +04:00
spin_unlock_bh ( & adapter - > tx_lock ) ;
/*
* Yield CPU
*/
if ( ! in_atomic ( ) )
schedule ( ) ;
else {
for ( i = 0 ; i < 20 ; i + + )
cpu_relax ( ) ; /*This a nop instr on i386 */
}
goto retry_getting_window ;
}
local_producer = adapter - > cmd_producer ;
/* There 4 fragments per descriptor */
no_of_desc = ( frag_count + 3 ) > > 2 ;
2006-11-29 20:00:10 +03:00
if ( netdev - > features & NETIF_F_TSO ) {
if ( skb_shinfo ( skb ) - > gso_size > 0 ) {
2006-10-21 23:33:03 +04:00
no_of_desc + + ;
2007-03-19 03:43:48 +03:00
if ( ( ip_hdrlen ( skb ) + tcp_hdrlen ( skb ) +
2007-03-13 02:09:15 +03:00
sizeof ( struct ethhdr ) ) >
2006-12-04 20:23:25 +03:00
( sizeof ( struct cmd_desc_type0 ) - 2 ) ) {
2006-11-29 20:00:10 +03:00
no_of_desc + + ;
}
2006-10-21 23:33:03 +04:00
}
}
k = adapter - > cmd_producer ;
max_tx_desc_count = adapter - > max_tx_desc_count ;
last_cmd_consumer = adapter - > last_cmd_consumer ;
if ( ( k + no_of_desc ) > =
( ( last_cmd_consumer < = k ) ? last_cmd_consumer + max_tx_desc_count :
last_cmd_consumer ) ) {
2006-12-04 20:23:25 +03:00
netif_stop_queue ( netdev ) ;
2007-04-20 18:52:37 +04:00
adapter - > flags | = NETXEN_NETDEV_STATUS ;
2006-10-21 23:33:03 +04:00
spin_unlock_bh ( & adapter - > tx_lock ) ;
2006-12-04 20:23:25 +03:00
return NETDEV_TX_BUSY ;
2006-10-21 23:33:03 +04:00
}
k = get_index_range ( k , max_tx_desc_count , no_of_desc ) ;
adapter - > cmd_producer = k ;
adapter - > total_threads + + ;
adapter - > num_threads + + ;
spin_unlock_bh ( & adapter - > tx_lock ) ;
/* Copy the descriptors into the hardware */
producer = local_producer ;
saved_producer = producer ;
hwdesc = & hw - > cmd_desc_head [ producer ] ;
memset ( hwdesc , 0 , sizeof ( struct cmd_desc_type0 ) ) ;
/* Take skb->data itself */
pbuf = & adapter - > cmd_buf_arr [ producer ] ;
2006-11-29 20:00:10 +03:00
if ( ( netdev - > features & NETIF_F_TSO ) & & skb_shinfo ( skb ) - > gso_size > 0 ) {
2007-01-02 13:39:10 +03:00
pbuf - > mss = skb_shinfo ( skb ) - > gso_size ;
2006-12-18 16:53:59 +03:00
hwdesc - > mss = cpu_to_le16 ( skb_shinfo ( skb ) - > gso_size ) ;
2006-10-21 23:33:03 +04:00
} else {
pbuf - > mss = 0 ;
hwdesc - > mss = 0 ;
}
pbuf - > total_length = skb - > len ;
pbuf - > skb = skb ;
pbuf - > cmd = TX_ETHER_PKT ;
pbuf - > frag_count = frag_count ;
2007-04-20 18:52:37 +04:00
pbuf - > port = adapter - > portnum ;
2006-10-21 23:33:03 +04:00
buffrag = & pbuf - > frag_array [ 0 ] ;
2007-04-20 18:52:37 +04:00
buffrag - > dma = pci_map_single ( adapter - > pdev , skb - > data , first_seg_len ,
2006-10-21 23:33:03 +04:00
PCI_DMA_TODEVICE ) ;
buffrag - > length = first_seg_len ;
2006-12-04 20:23:25 +03:00
netxen_set_cmd_desc_totallength ( hwdesc , skb - > len ) ;
netxen_set_cmd_desc_num_of_buff ( hwdesc , frag_count ) ;
netxen_set_cmd_desc_opcode ( hwdesc , TX_ETHER_PKT ) ;
2006-10-21 23:33:03 +04:00
2007-04-20 18:52:37 +04:00
netxen_set_cmd_desc_port ( hwdesc , adapter - > portnum ) ;
2006-10-21 23:33:03 +04:00
hwdesc - > buffer1_length = cpu_to_le16 ( first_seg_len ) ;
hwdesc - > addr_buffer1 = cpu_to_le64 ( buffrag - > dma ) ;
for ( i = 1 , k = 1 ; i < frag_count ; i + + , k + + ) {
struct skb_frag_struct * frag ;
int len , temp_len ;
unsigned long offset ;
dma_addr_t temp_dma ;
/* move to next desc. if there is a need */
if ( ( i & 0x3 ) = = 0 ) {
k = 0 ;
producer = get_next_index ( producer ,
adapter - > max_tx_desc_count ) ;
hwdesc = & hw - > cmd_desc_head [ producer ] ;
memset ( hwdesc , 0 , sizeof ( struct cmd_desc_type0 ) ) ;
}
frag = & skb_shinfo ( skb ) - > frags [ i - 1 ] ;
len = frag - > size ;
offset = frag - > page_offset ;
temp_len = len ;
2007-04-20 18:52:37 +04:00
temp_dma = pci_map_page ( adapter - > pdev , frag - > page , offset ,
2006-10-21 23:33:03 +04:00
len , PCI_DMA_TODEVICE ) ;
buffrag + + ;
buffrag - > dma = temp_dma ;
buffrag - > length = temp_len ;
DPRINTK ( INFO , " for loop. i=%d k=%d \n " , i , k ) ;
switch ( k ) {
case 0 :
hwdesc - > buffer1_length = cpu_to_le16 ( temp_len ) ;
hwdesc - > addr_buffer1 = cpu_to_le64 ( temp_dma ) ;
break ;
case 1 :
hwdesc - > buffer2_length = cpu_to_le16 ( temp_len ) ;
hwdesc - > addr_buffer2 = cpu_to_le64 ( temp_dma ) ;
break ;
case 2 :
hwdesc - > buffer3_length = cpu_to_le16 ( temp_len ) ;
hwdesc - > addr_buffer3 = cpu_to_le64 ( temp_dma ) ;
break ;
case 3 :
2007-01-02 13:39:10 +03:00
hwdesc - > buffer4_length = cpu_to_le16 ( temp_len ) ;
2006-10-21 23:33:03 +04:00
hwdesc - > addr_buffer4 = cpu_to_le64 ( temp_dma ) ;
break ;
}
frag + + ;
}
producer = get_next_index ( producer , adapter - > max_tx_desc_count ) ;
/* might change opcode to TX_TCP_LSO */
netxen_tso_check ( adapter , & hw - > cmd_desc_head [ saved_producer ] , skb ) ;
/* For LSO, we need to copy the MAC/IP/TCP headers into
* the descriptor ring
*/
2006-12-04 20:23:25 +03:00
if ( netxen_get_cmd_desc_opcode ( & hw - > cmd_desc_head [ saved_producer ] )
= = TX_TCP_LSO ) {
2006-10-21 23:33:03 +04:00
int hdr_len , first_hdr_len , more_hdr ;
hdr_len = hw - > cmd_desc_head [ saved_producer ] . total_hdr_length ;
2006-12-04 20:23:25 +03:00
if ( hdr_len > ( sizeof ( struct cmd_desc_type0 ) - 2 ) ) {
first_hdr_len = sizeof ( struct cmd_desc_type0 ) - 2 ;
2006-10-21 23:33:03 +04:00
more_hdr = 1 ;
} else {
first_hdr_len = hdr_len ;
more_hdr = 0 ;
}
/* copy the MAC/IP/TCP headers to the cmd descriptor list */
hwdesc = & hw - > cmd_desc_head [ producer ] ;
/* copy the first 64 bytes */
2006-12-04 20:23:25 +03:00
memcpy ( ( ( void * ) hwdesc ) + 2 ,
2006-10-21 23:33:03 +04:00
( void * ) ( skb - > data ) , first_hdr_len ) ;
producer = get_next_index ( producer , max_tx_desc_count ) ;
if ( more_hdr ) {
hwdesc = & hw - > cmd_desc_head [ producer ] ;
/* copy the next 64 bytes - should be enough except
* for pathological case
*/
2007-03-28 01:55:52 +04:00
skb_copy_from_linear_data_offset ( skb , first_hdr_len ,
hwdesc ,
( hdr_len -
first_hdr_len ) ) ;
2006-10-21 23:33:03 +04:00
producer = get_next_index ( producer , max_tx_desc_count ) ;
}
}
spin_lock_bh ( & adapter - > tx_lock ) ;
2007-04-20 18:52:37 +04:00
adapter - > stats . txbytes + =
2006-12-04 20:23:25 +03:00
netxen_get_cmd_desc_totallength ( & hw - > cmd_desc_head [ saved_producer ] ) ;
2006-10-21 23:33:03 +04:00
/* Code to update the adapter considering how many producer threads
are currently working */
if ( ( - - adapter - > num_threads ) = = 0 ) {
/* This is the last thread */
u32 crb_producer = adapter - > cmd_producer ;
2007-04-20 18:52:37 +04:00
netxen_nic_update_cmd_producer ( adapter , crb_producer ) ;
2006-10-21 23:33:03 +04:00
wmb ( ) ;
adapter - > total_threads = 0 ;
}
2007-04-20 18:52:37 +04:00
adapter - > stats . xmitfinished + + ;
2006-10-21 23:33:03 +04:00
spin_unlock_bh ( & adapter - > tx_lock ) ;
netdev - > trans_start = jiffies ;
DPRINTK ( INFO , " wrote CMD producer %x to phantom \n " , producer ) ;
DPRINTK ( INFO , " Done. Send \n " ) ;
return NETDEV_TX_OK ;
}
static void netxen_watchdog ( unsigned long v )
{
struct netxen_adapter * adapter = ( struct netxen_adapter * ) v ;
2006-12-04 20:23:25 +03:00
SCHEDULE_WORK ( & adapter - > watchdog_task ) ;
2006-10-21 23:33:03 +04:00
}
static void netxen_tx_timeout ( struct net_device * netdev )
{
2007-04-20 18:52:37 +04:00
struct netxen_adapter * adapter = ( struct netxen_adapter * )
netdev_priv ( netdev ) ;
SCHEDULE_WORK ( & adapter - > tx_timeout_task ) ;
2006-10-21 23:33:03 +04:00
}
2006-12-05 22:36:26 +03:00
static void netxen_tx_timeout_task ( struct work_struct * work )
2006-10-21 23:33:03 +04:00
{
2007-04-20 18:52:37 +04:00
struct netxen_adapter * adapter =
container_of ( work , struct netxen_adapter , tx_timeout_task ) ;
struct net_device * netdev = adapter - > netdev ;
2006-10-21 23:33:03 +04:00
unsigned long flags ;
printk ( KERN_ERR " %s %s: transmit timeout, resetting. \n " ,
netxen_nic_driver_name , netdev - > name ) ;
2007-04-20 18:52:37 +04:00
spin_lock_irqsave ( & adapter - > lock , flags ) ;
2006-10-21 23:33:03 +04:00
netxen_nic_close ( netdev ) ;
netxen_nic_open ( netdev ) ;
2007-04-20 18:52:37 +04:00
spin_unlock_irqrestore ( & adapter - > lock , flags ) ;
2006-10-21 23:33:03 +04:00
netdev - > trans_start = jiffies ;
netif_wake_queue ( netdev ) ;
}
static int
netxen_handle_int ( struct netxen_adapter * adapter , struct net_device * netdev )
{
u32 ret = 0 ;
DPRINTK ( INFO , " Entered handle ISR \n " ) ;
2007-04-20 18:53:52 +04:00
adapter - > stats . ints + + ;
2006-10-21 23:33:03 +04:00
if ( ! ( adapter - > flags & NETXEN_NIC_MSI_ENABLED ) ) {
int count = 0 ;
u32 mask ;
2007-04-20 18:52:37 +04:00
u32 our_int = 0 ;
our_int = readl ( NETXEN_CRB_NORMALIZE ( adapter , CRB_INT_VECTOR ) ) ;
/* not our interrupt */
if ( ( our_int & ( 0x80 < < adapter - > portnum ) ) = = 0 )
2006-12-04 20:23:25 +03:00
return ret ;
2006-10-21 23:33:03 +04:00
netxen_nic_disable_int ( adapter ) ;
/* Window = 0 or 1 */
do {
2006-12-01 16:36:22 +03:00
writel ( 0xffffffff , PCI_OFFSET_SECOND_RANGE ( adapter ,
ISR_INT_TARGET_STATUS ) ) ;
mask = readl ( pci_base_offset ( adapter , ISR_INT_VECTOR ) ) ;
2006-10-21 23:33:03 +04:00
} while ( ( ( mask & 0x80 ) ! = 0 ) & & ( + + count < 32 ) ) ;
if ( ( mask & 0x80 ) ! = 0 )
printk ( " Could not disable interrupt completely \n " ) ;
}
if ( netxen_nic_rx_has_work ( adapter ) | | netxen_nic_tx_has_work ( adapter ) ) {
if ( netif_rx_schedule_prep ( netdev ) ) {
/*
* Interrupts are already disabled .
*/
__netif_rx_schedule ( netdev ) ;
} else {
static unsigned int intcount = 0 ;
if ( ( + + intcount & 0xfff ) = = 0xfff )
printk ( KERN_ERR
" %s: %s interrupt %d while in poll \n " ,
netxen_nic_driver_name , netdev - > name ,
intcount ) ;
}
ret = 1 ;
}
if ( ret = = 0 ) {
netxen_nic_enable_int ( adapter ) ;
}
return ret ;
}
/*
* netxen_intr - Interrupt Handler
* @ irq : interrupt number
* data points to adapter stucture ( which may be handling more than 1 port
*/
2006-11-07 13:12:16 +03:00
irqreturn_t netxen_intr ( int irq , void * data )
2006-10-21 23:33:03 +04:00
{
struct netxen_adapter * adapter ;
struct net_device * netdev ;
if ( unlikely ( ! irq ) ) {
return IRQ_NONE ; /* Not our interrupt */
}
adapter = ( struct netxen_adapter * ) data ;
2007-04-20 18:52:37 +04:00
netdev = adapter - > netdev ;
/* process our status queue (for all 4 ports) */
if ( netif_running ( netdev ) )
netxen_handle_int ( adapter , netdev ) ;
2006-10-21 23:33:03 +04:00
return IRQ_HANDLED ;
}
static int netxen_nic_poll ( struct net_device * netdev , int * budget )
{
2007-04-20 18:52:37 +04:00
struct netxen_adapter * adapter = netdev_priv ( netdev ) ;
2006-10-21 23:33:03 +04:00
int work_to_do = min ( * budget , netdev - > quota ) ;
int done = 1 ;
int ctx ;
int this_work_done ;
2006-12-04 20:18:00 +03:00
int work_done = 0 ;
2006-10-21 23:33:03 +04:00
DPRINTK ( INFO , " polling for %d descriptors \n " , * budget ) ;
2006-12-04 20:18:00 +03:00
work_done = 0 ;
2006-10-21 23:33:03 +04:00
for ( ctx = 0 ; ctx < MAX_RCV_CTX ; + + ctx ) {
/*
* Fairness issue . This will give undue weight to the
* receive context 0.
*/
/*
* To avoid starvation , we give each of our receivers ,
* a fraction of the quota . Sometimes , it might happen that we
* have enough quota to process every packet , but since all the
* packets are on one context , it gets only half of the quota ,
* and ends up not processing it .
*/
this_work_done = netxen_process_rcv_ring ( adapter , ctx ,
work_to_do /
MAX_RCV_CTX ) ;
2006-12-04 20:18:00 +03:00
work_done + = this_work_done ;
2006-10-21 23:33:03 +04:00
}
2006-12-04 20:18:00 +03:00
netdev - > quota - = work_done ;
* budget - = work_done ;
2006-10-21 23:33:03 +04:00
2006-12-04 20:23:25 +03:00
if ( work_done > = work_to_do & & netxen_nic_rx_has_work ( adapter ) ! = 0 )
2006-10-21 23:33:03 +04:00
done = 0 ;
2006-12-04 20:23:25 +03:00
if ( netxen_process_cmd_ring ( ( unsigned long ) adapter ) = = 0 )
done = 0 ;
2006-10-21 23:33:03 +04:00
DPRINTK ( INFO , " new work_done: %d work_to_do: %d \n " ,
2006-12-04 20:18:00 +03:00
work_done , work_to_do ) ;
2006-10-21 23:33:03 +04:00
if ( done ) {
netif_rx_complete ( netdev ) ;
netxen_nic_enable_int ( adapter ) ;
}
2006-11-29 19:58:11 +03:00
return ! done ;
2006-10-21 23:33:03 +04:00
}
# ifdef CONFIG_NET_POLL_CONTROLLER
static void netxen_nic_poll_controller ( struct net_device * netdev )
{
2007-04-20 18:52:37 +04:00
struct netxen_adapter * adapter = netdev_priv ( netdev ) ;
2006-10-21 23:33:03 +04:00
disable_irq ( adapter - > irq ) ;
2006-11-07 13:12:16 +03:00
netxen_intr ( adapter - > irq , adapter ) ;
2006-10-21 23:33:03 +04:00
enable_irq ( adapter - > irq ) ;
}
# endif
static struct pci_driver netxen_driver = {
. name = netxen_nic_driver_name ,
. id_table = netxen_pci_tbl ,
. probe = netxen_nic_probe ,
. remove = __devexit_p ( netxen_nic_remove )
} ;
/* Driver Registration on NetXen card */
static int __init netxen_init_module ( void )
{
2006-12-04 20:23:25 +03:00
if ( ( netxen_workq = create_singlethread_workqueue ( " netxen " ) ) = = 0 )
return - ENOMEM ;
2007-01-22 17:52:53 +03:00
return pci_register_driver ( & netxen_driver ) ;
2006-10-21 23:33:03 +04:00
}
module_init ( netxen_init_module ) ;
static void __exit netxen_exit_module ( void )
{
/*
* Wait for some time to allow the dma to drain , if any .
*/
pci_unregister_driver ( & netxen_driver ) ;
2007-02-21 17:37:06 +03:00
destroy_workqueue ( netxen_workq ) ;
2006-10-21 23:33:03 +04:00
}
module_exit ( netxen_exit_module ) ;