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
*
*
* Source file for NIC routines to initialize the Phantom Hardware
*
*/
# include <linux/netdevice.h>
# include <linux/delay.h>
# include "netxen_nic.h"
# include "netxen_nic_hw.h"
# include "netxen_nic_phan_reg.h"
struct crb_addr_pair {
long addr ;
long data ;
} ;
# define NETXEN_MAX_CRB_XFORM 60
static unsigned int crb_addr_xform [ NETXEN_MAX_CRB_XFORM ] ;
# define NETXEN_ADDR_ERROR ((unsigned long ) 0xffffffff )
# define crb_addr_transform(name) \
crb_addr_xform [ NETXEN_HW_PX_MAP_CRB_ # # name ] = \
NETXEN_HW_CRB_HUB_AGT_ADR_ # # name < < 20
2006-11-29 20:00:10 +03:00
# define NETXEN_NIC_XDMA_RESET 0x8000ff
2006-10-21 23:33:03 +04:00
static inline void
netxen_nic_locked_write_reg ( struct netxen_adapter * adapter ,
unsigned long off , int * data )
{
2006-11-29 20:00:10 +03:00
void __iomem * addr = pci_base_offset ( adapter , off ) ;
2006-10-21 23:33:03 +04:00
writel ( * data , addr ) ;
}
static void crb_addr_transform_setup ( void )
{
crb_addr_transform ( XDMA ) ;
crb_addr_transform ( TIMR ) ;
crb_addr_transform ( SRE ) ;
crb_addr_transform ( SQN3 ) ;
crb_addr_transform ( SQN2 ) ;
crb_addr_transform ( SQN1 ) ;
crb_addr_transform ( SQN0 ) ;
crb_addr_transform ( SQS3 ) ;
crb_addr_transform ( SQS2 ) ;
crb_addr_transform ( SQS1 ) ;
crb_addr_transform ( SQS0 ) ;
crb_addr_transform ( RPMX7 ) ;
crb_addr_transform ( RPMX6 ) ;
crb_addr_transform ( RPMX5 ) ;
crb_addr_transform ( RPMX4 ) ;
crb_addr_transform ( RPMX3 ) ;
crb_addr_transform ( RPMX2 ) ;
crb_addr_transform ( RPMX1 ) ;
crb_addr_transform ( RPMX0 ) ;
crb_addr_transform ( ROMUSB ) ;
crb_addr_transform ( SN ) ;
crb_addr_transform ( QMN ) ;
crb_addr_transform ( QMS ) ;
crb_addr_transform ( PGNI ) ;
crb_addr_transform ( PGND ) ;
crb_addr_transform ( PGN3 ) ;
crb_addr_transform ( PGN2 ) ;
crb_addr_transform ( PGN1 ) ;
crb_addr_transform ( PGN0 ) ;
crb_addr_transform ( PGSI ) ;
crb_addr_transform ( PGSD ) ;
crb_addr_transform ( PGS3 ) ;
crb_addr_transform ( PGS2 ) ;
crb_addr_transform ( PGS1 ) ;
crb_addr_transform ( PGS0 ) ;
crb_addr_transform ( PS ) ;
crb_addr_transform ( PH ) ;
crb_addr_transform ( NIU ) ;
crb_addr_transform ( I2Q ) ;
crb_addr_transform ( EG ) ;
crb_addr_transform ( MN ) ;
crb_addr_transform ( MS ) ;
crb_addr_transform ( CAS2 ) ;
crb_addr_transform ( CAS1 ) ;
crb_addr_transform ( CAS0 ) ;
crb_addr_transform ( CAM ) ;
crb_addr_transform ( C2C1 ) ;
crb_addr_transform ( C2C0 ) ;
}
int netxen_init_firmware ( struct netxen_adapter * adapter )
{
u32 state = 0 , loops = 0 , err = 0 ;
/* Window 1 call */
state = readl ( NETXEN_CRB_NORMALIZE ( adapter , CRB_CMDPEG_STATE ) ) ;
if ( state = = PHAN_INITIALIZE_ACK )
return 0 ;
while ( state ! = PHAN_INITIALIZE_COMPLETE & & loops < 2000 ) {
udelay ( 100 ) ;
/* Window 1 call */
state = readl ( NETXEN_CRB_NORMALIZE ( adapter , CRB_CMDPEG_STATE ) ) ;
loops + + ;
}
if ( loops > = 2000 ) {
printk ( KERN_ERR " Cmd Peg initialization not complete:%x. \n " ,
state ) ;
err = - EIO ;
return err ;
}
/* Window 1 call */
2006-12-04 20:23:25 +03:00
writel ( MPORT_SINGLE_FUNCTION_MODE ,
NETXEN_CRB_NORMALIZE ( adapter , CRB_MPORT_MODE ) ) ;
2006-10-21 23:33:03 +04:00
writel ( PHAN_INITIALIZE_ACK ,
NETXEN_CRB_NORMALIZE ( adapter , CRB_CMDPEG_STATE ) ) ;
return err ;
}
2006-11-29 20:00:10 +03:00
# define NETXEN_ADDR_LIMIT 0xffffffffULL
void * netxen_alloc ( struct pci_dev * pdev , size_t sz , dma_addr_t * ptr ,
struct pci_dev * * used_dev )
{
void * addr ;
addr = pci_alloc_consistent ( pdev , sz , ptr ) ;
if ( ( unsigned long long ) ( * ptr ) < NETXEN_ADDR_LIMIT ) {
* used_dev = pdev ;
return addr ;
}
pci_free_consistent ( pdev , sz , addr , * ptr ) ;
addr = pci_alloc_consistent ( NULL , sz , ptr ) ;
* used_dev = NULL ;
return addr ;
}
2006-10-21 23:33:03 +04:00
void netxen_initialize_adapter_sw ( struct netxen_adapter * adapter )
{
int ctxid , ring ;
u32 i ;
u32 num_rx_bufs = 0 ;
struct netxen_rcv_desc_ctx * rcv_desc ;
DPRINTK ( INFO , " initializing some queues: %p \n " , adapter ) ;
for ( ctxid = 0 ; ctxid < MAX_RCV_CTX ; + + ctxid ) {
for ( ring = 0 ; ring < NUM_RCV_DESC_RINGS ; ring + + ) {
struct netxen_rx_buffer * rx_buf ;
rcv_desc = & adapter - > recv_ctx [ ctxid ] . rcv_desc [ ring ] ;
rcv_desc - > rcv_free = rcv_desc - > max_rx_desc_count ;
rcv_desc - > begin_alloc = 0 ;
rx_buf = rcv_desc - > rx_buf_arr ;
num_rx_bufs = rcv_desc - > max_rx_desc_count ;
/*
* Now go through all of them , set reference handles
* and put them in the queues .
*/
for ( i = 0 ; i < num_rx_bufs ; i + + ) {
rx_buf - > ref_handle = i ;
rx_buf - > state = NETXEN_BUFFER_FREE ;
DPRINTK ( INFO , " Rx buf:ctx%d i(%d) rx_buf: "
" %p \n " , ctxid , i , rx_buf ) ;
rx_buf + + ;
}
}
}
}
void netxen_initialize_adapter_hw ( struct netxen_adapter * adapter )
{
2006-11-29 20:00:10 +03:00
int ports = 0 ;
struct netxen_board_info * board_info = & ( adapter - > ahw . boardcfg ) ;
2006-10-21 23:33:03 +04:00
if ( netxen_nic_get_board_info ( adapter ) ! = 0 )
printk ( " %s: Error getting board config info. \n " ,
netxen_nic_driver_name ) ;
2006-11-29 20:00:10 +03:00
get_brd_port_by_type ( board_info - > board_type , & ports ) ;
if ( ports = = 0 )
2006-10-21 23:33:03 +04:00
printk ( KERN_ERR " %s: Unknown board type \n " ,
netxen_nic_driver_name ) ;
2006-11-29 20:00:10 +03:00
adapter - > ahw . max_ports = ports ;
2006-10-21 23:33:03 +04:00
}
void netxen_initialize_adapter_ops ( struct netxen_adapter * adapter )
{
switch ( adapter - > ahw . board_type ) {
case NETXEN_NIC_GBE :
2006-12-04 20:18:00 +03:00
adapter - > enable_phy_interrupts =
2006-10-21 23:33:03 +04:00
netxen_niu_gbe_enable_phy_interrupts ;
2006-12-04 20:18:00 +03:00
adapter - > disable_phy_interrupts =
2006-10-21 23:33:03 +04:00
netxen_niu_gbe_disable_phy_interrupts ;
2006-12-04 20:18:00 +03:00
adapter - > handle_phy_intr = netxen_nic_gbe_handle_phy_intr ;
adapter - > macaddr_set = netxen_niu_macaddr_set ;
adapter - > set_mtu = netxen_nic_set_mtu_gb ;
adapter - > set_promisc = netxen_niu_set_promiscuous_mode ;
adapter - > unset_promisc = netxen_niu_set_promiscuous_mode ;
adapter - > phy_read = netxen_niu_gbe_phy_read ;
adapter - > phy_write = netxen_niu_gbe_phy_write ;
adapter - > init_port = netxen_niu_gbe_init_port ;
adapter - > init_niu = netxen_nic_init_niu_gb ;
adapter - > stop_port = netxen_niu_disable_gbe_port ;
2006-10-21 23:33:03 +04:00
break ;
case NETXEN_NIC_XGBE :
2006-12-04 20:18:00 +03:00
adapter - > enable_phy_interrupts =
2006-10-21 23:33:03 +04:00
netxen_niu_xgbe_enable_phy_interrupts ;
2006-12-04 20:18:00 +03:00
adapter - > disable_phy_interrupts =
2006-10-21 23:33:03 +04:00
netxen_niu_xgbe_disable_phy_interrupts ;
2006-12-04 20:18:00 +03:00
adapter - > handle_phy_intr = netxen_nic_xgbe_handle_phy_intr ;
adapter - > macaddr_set = netxen_niu_xg_macaddr_set ;
adapter - > set_mtu = netxen_nic_set_mtu_xgb ;
adapter - > init_port = netxen_niu_xg_init_port ;
adapter - > set_promisc = netxen_niu_xg_set_promiscuous_mode ;
adapter - > unset_promisc = netxen_niu_xg_set_promiscuous_mode ;
adapter - > stop_port = netxen_niu_disable_xg_port ;
2006-10-21 23:33:03 +04:00
break ;
default :
break ;
}
}
/*
* netxen_decode_crb_addr ( 0 - utility to translate from internal Phantom CRB
* address to external PCI CRB address .
*/
unsigned long netxen_decode_crb_addr ( unsigned long addr )
{
int i ;
unsigned long base_addr , offset , pci_base ;
crb_addr_transform_setup ( ) ;
pci_base = NETXEN_ADDR_ERROR ;
base_addr = addr & 0xfff00000 ;
offset = addr & 0x000fffff ;
for ( i = 0 ; i < NETXEN_MAX_CRB_XFORM ; i + + ) {
if ( crb_addr_xform [ i ] = = base_addr ) {
pci_base = i < < 20 ;
break ;
}
}
if ( pci_base = = NETXEN_ADDR_ERROR )
return pci_base ;
else
return ( pci_base + offset ) ;
}
static long rom_max_timeout = 10000 ;
static long rom_lock_timeout = 1000000 ;
static inline int rom_lock ( struct netxen_adapter * adapter )
{
int iter ;
u32 done = 0 ;
int timeout = 0 ;
while ( ! done ) {
/* acquire semaphore2 from PCI HW block */
netxen_nic_read_w0 ( adapter , NETXEN_PCIE_REG ( PCIE_SEM2_LOCK ) ,
& done ) ;
if ( done = = 1 )
break ;
if ( timeout > = rom_lock_timeout )
return - EIO ;
timeout + + ;
/*
* Yield CPU
*/
if ( ! in_atomic ( ) )
schedule ( ) ;
else {
for ( iter = 0 ; iter < 20 ; iter + + )
cpu_relax ( ) ; /*This a nop instr on i386 */
}
}
netxen_nic_reg_write ( adapter , NETXEN_ROM_LOCK_ID , ROM_LOCK_DRIVER ) ;
return 0 ;
}
int netxen_wait_rom_done ( struct netxen_adapter * adapter )
{
long timeout = 0 ;
long done = 0 ;
while ( done = = 0 ) {
done = netxen_nic_reg_read ( adapter , NETXEN_ROMUSB_GLB_STATUS ) ;
done & = 2 ;
timeout + + ;
if ( timeout > = rom_max_timeout ) {
printk ( " Timeout reached waiting for rom done " ) ;
return - EIO ;
}
}
return 0 ;
}
2006-11-29 20:00:10 +03:00
static inline int netxen_rom_wren ( struct netxen_adapter * adapter )
{
/* Set write enable latch in ROM status register */
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_ABYTE_CNT , 0 ) ;
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_INSTR_OPCODE ,
M25P_INSTR_WREN ) ;
if ( netxen_wait_rom_done ( adapter ) ) {
return - 1 ;
}
return 0 ;
}
static inline unsigned int netxen_rdcrbreg ( struct netxen_adapter * adapter ,
unsigned int addr )
{
unsigned int data = 0xdeaddead ;
data = netxen_nic_reg_read ( adapter , addr ) ;
return data ;
}
static inline int netxen_do_rom_rdsr ( struct netxen_adapter * adapter )
{
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_INSTR_OPCODE ,
M25P_INSTR_RDSR ) ;
if ( netxen_wait_rom_done ( adapter ) ) {
return - 1 ;
}
return netxen_rdcrbreg ( adapter , NETXEN_ROMUSB_ROM_RDATA ) ;
}
static inline void netxen_rom_unlock ( struct netxen_adapter * adapter )
{
u32 val ;
/* release semaphore2 */
netxen_nic_read_w0 ( adapter , NETXEN_PCIE_REG ( PCIE_SEM2_UNLOCK ) , & val ) ;
}
int netxen_rom_wip_poll ( struct netxen_adapter * adapter )
{
long timeout = 0 ;
long wip = 1 ;
int val ;
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_ABYTE_CNT , 0 ) ;
while ( wip ! = 0 ) {
val = netxen_do_rom_rdsr ( adapter ) ;
wip = val & 1 ;
timeout + + ;
if ( timeout > rom_max_timeout ) {
return - 1 ;
}
}
return 0 ;
}
2006-12-04 20:18:00 +03:00
static inline int do_rom_fast_write ( struct netxen_adapter * adapter , int addr ,
int data )
2006-11-29 20:00:10 +03:00
{
if ( netxen_rom_wren ( adapter ) ) {
return - 1 ;
}
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_WDATA , data ) ;
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_ADDRESS , addr ) ;
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_ABYTE_CNT , 3 ) ;
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_INSTR_OPCODE ,
M25P_INSTR_PP ) ;
if ( netxen_wait_rom_done ( adapter ) ) {
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_ABYTE_CNT , 0 ) ;
return - 1 ;
}
return netxen_rom_wip_poll ( adapter ) ;
}
2006-10-21 23:33:03 +04:00
static inline int
do_rom_fast_read ( struct netxen_adapter * adapter , int addr , int * valp )
{
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_ADDRESS , addr ) ;
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_ABYTE_CNT , 3 ) ;
udelay ( 100 ) ; /* prevent bursting on CRB */
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT , 0 ) ;
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_INSTR_OPCODE , 0xb ) ;
if ( netxen_wait_rom_done ( adapter ) ) {
printk ( " Error waiting for rom done \n " ) ;
return - EIO ;
}
/* reset abyte_cnt and dummy_byte_cnt */
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_ABYTE_CNT , 0 ) ;
udelay ( 100 ) ; /* prevent bursting on CRB */
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT , 0 ) ;
* valp = netxen_nic_reg_read ( adapter , NETXEN_ROMUSB_ROM_RDATA ) ;
return 0 ;
}
int netxen_rom_fast_read ( struct netxen_adapter * adapter , int addr , int * valp )
{
int ret ;
if ( rom_lock ( adapter ) ! = 0 )
return - EIO ;
ret = do_rom_fast_read ( adapter , addr , valp ) ;
2006-11-29 20:00:10 +03:00
netxen_rom_unlock ( adapter ) ;
return ret ;
}
int netxen_rom_fast_write ( struct netxen_adapter * adapter , int addr , int data )
{
int ret = 0 ;
if ( rom_lock ( adapter ) ! = 0 ) {
return - 1 ;
}
ret = do_rom_fast_write ( adapter , addr , data ) ;
netxen_rom_unlock ( adapter ) ;
return ret ;
}
int netxen_do_rom_se ( struct netxen_adapter * adapter , int addr )
{
netxen_rom_wren ( adapter ) ;
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_ADDRESS , addr ) ;
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_ABYTE_CNT , 3 ) ;
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_INSTR_OPCODE ,
M25P_INSTR_SE ) ;
if ( netxen_wait_rom_done ( adapter ) ) {
netxen_nic_reg_write ( adapter , NETXEN_ROMUSB_ROM_ABYTE_CNT , 0 ) ;
return - 1 ;
}
return netxen_rom_wip_poll ( adapter ) ;
}
int netxen_rom_se ( struct netxen_adapter * adapter , int addr )
{
int ret = 0 ;
if ( rom_lock ( adapter ) ! = 0 ) {
return - 1 ;
}
ret = netxen_do_rom_se ( adapter , addr ) ;
netxen_rom_unlock ( adapter ) ;
2006-10-21 23:33:03 +04:00
return ret ;
}
# define NETXEN_BOARDTYPE 0x4008
# define NETXEN_BOARDNUM 0x400c
# define NETXEN_CHIPNUM 0x4010
# define NETXEN_ROMBUS_RESET 0xFFFFFFFF
# define NETXEN_ROM_FIRST_BARRIER 0x800000000ULL
# define NETXEN_ROM_FOUND_INIT 0x400
int netxen_pinit_from_rom ( struct netxen_adapter * adapter , int verbose )
{
int addr , val , status ;
int n , i ;
int init_delay = 0 ;
struct crb_addr_pair * buf ;
unsigned long off ;
/* resetall */
status = netxen_nic_get_board_info ( adapter ) ;
if ( status )
2006-11-29 20:00:10 +03:00
printk ( " %s: netxen_pinit_from_rom: Error getting board info \n " ,
2006-10-21 23:33:03 +04:00
netxen_nic_driver_name ) ;
netxen_crb_writelit_adapter ( adapter , NETXEN_ROMUSB_GLB_SW_RESET ,
NETXEN_ROMBUS_RESET ) ;
if ( verbose ) {
int val ;
if ( netxen_rom_fast_read ( adapter , NETXEN_BOARDTYPE , & val ) = = 0 )
printk ( " P2 ROM board type: 0x%08x \n " , val ) ;
else
printk ( " Could not read board type \n " ) ;
if ( netxen_rom_fast_read ( adapter , NETXEN_BOARDNUM , & val ) = = 0 )
printk ( " P2 ROM board num: 0x%08x \n " , val ) ;
else
printk ( " Could not read board number \n " ) ;
if ( netxen_rom_fast_read ( adapter , NETXEN_CHIPNUM , & val ) = = 0 )
printk ( " P2 ROM chip num: 0x%08x \n " , val ) ;
else
printk ( " Could not read chip number \n " ) ;
}
if ( netxen_rom_fast_read ( adapter , 0 , & n ) = = 0
& & ( n & NETXEN_ROM_FIRST_BARRIER ) ) {
n & = ~ NETXEN_ROM_ROUNDUP ;
if ( n < NETXEN_ROM_FOUND_INIT ) {
if ( verbose )
printk ( " %s: %d CRB init values found "
" in ROM. \n " , netxen_nic_driver_name , n ) ;
} else {
printk ( " %s:n=0x%x Error! NetXen card flash not "
" initialized. \n " , __FUNCTION__ , n ) ;
return - EIO ;
}
buf = kcalloc ( n , sizeof ( struct crb_addr_pair ) , GFP_KERNEL ) ;
if ( buf = = NULL ) {
2006-11-29 20:00:10 +03:00
printk ( " %s: netxen_pinit_from_rom: Unable to calloc "
" memory. \n " , netxen_nic_driver_name ) ;
2006-10-21 23:33:03 +04:00
return - ENOMEM ;
}
for ( i = 0 ; i < n ; i + + ) {
if ( netxen_rom_fast_read ( adapter , 8 * i + 4 , & val ) ! = 0
| | netxen_rom_fast_read ( adapter , 8 * i + 8 ,
& addr ) ! = 0 )
return - EIO ;
buf [ i ] . addr = addr ;
buf [ i ] . data = val ;
if ( verbose )
printk ( " %s: PCI: 0x%08x == 0x%08x \n " ,
netxen_nic_driver_name , ( unsigned int )
netxen_decode_crb_addr ( ( unsigned long )
addr ) , val ) ;
}
for ( i = 0 ; i < n ; i + + ) {
off =
netxen_decode_crb_addr ( ( unsigned long ) buf [ i ] . addr ) +
NETXEN_PCI_CRBSPACE ;
/* skipping cold reboot MAGIC */
if ( off = = NETXEN_CAM_RAM ( 0x1fc ) )
continue ;
/* After writing this register, HW needs time for CRB */
/* to quiet down (else crb_window returns 0xffffffff) */
if ( off = = NETXEN_ROMUSB_GLB_SW_RESET ) {
init_delay = 1 ;
/* hold xdma in reset also */
2006-11-29 20:00:10 +03:00
buf [ i ] . data = NETXEN_NIC_XDMA_RESET ;
2006-10-21 23:33:03 +04:00
}
if ( ADDR_IN_WINDOW1 ( off ) ) {
writel ( buf [ i ] . data ,
NETXEN_CRB_NORMALIZE ( adapter , off ) ) ;
} else {
netxen_nic_pci_change_crbwindow ( adapter , 0 ) ;
writel ( buf [ i ] . data ,
2006-11-29 20:00:10 +03:00
pci_base_offset ( adapter , off ) ) ;
2006-10-21 23:33:03 +04:00
netxen_nic_pci_change_crbwindow ( adapter , 1 ) ;
}
if ( init_delay = = 1 ) {
ssleep ( 1 ) ;
init_delay = 0 ;
}
msleep ( 1 ) ;
}
kfree ( buf ) ;
/* disable_peg_cache_all */
/* unreset_net_cache */
netxen_nic_hw_read_wx ( adapter , NETXEN_ROMUSB_GLB_SW_RESET , & val ,
4 ) ;
netxen_crb_writelit_adapter ( adapter , NETXEN_ROMUSB_GLB_SW_RESET ,
( val & 0xffffff0f ) ) ;
/* p2dn replyCount */
netxen_crb_writelit_adapter ( adapter ,
NETXEN_CRB_PEG_NET_D + 0xec , 0x1e ) ;
/* disable_peg_cache 0 */
netxen_crb_writelit_adapter ( adapter ,
NETXEN_CRB_PEG_NET_D + 0x4c , 8 ) ;
/* disable_peg_cache 1 */
netxen_crb_writelit_adapter ( adapter ,
NETXEN_CRB_PEG_NET_I + 0x4c , 8 ) ;
/* peg_clr_all */
/* peg_clr 0 */
netxen_crb_writelit_adapter ( adapter , NETXEN_CRB_PEG_NET_0 + 0x8 ,
0 ) ;
netxen_crb_writelit_adapter ( adapter , NETXEN_CRB_PEG_NET_0 + 0xc ,
0 ) ;
/* peg_clr 1 */
netxen_crb_writelit_adapter ( adapter , NETXEN_CRB_PEG_NET_1 + 0x8 ,
0 ) ;
netxen_crb_writelit_adapter ( adapter , NETXEN_CRB_PEG_NET_1 + 0xc ,
0 ) ;
/* peg_clr 2 */
netxen_crb_writelit_adapter ( adapter , NETXEN_CRB_PEG_NET_2 + 0x8 ,
0 ) ;
netxen_crb_writelit_adapter ( adapter , NETXEN_CRB_PEG_NET_2 + 0xc ,
0 ) ;
/* peg_clr 3 */
netxen_crb_writelit_adapter ( adapter , NETXEN_CRB_PEG_NET_3 + 0x8 ,
0 ) ;
netxen_crb_writelit_adapter ( adapter , NETXEN_CRB_PEG_NET_3 + 0xc ,
0 ) ;
}
return 0 ;
}
2006-12-04 20:23:25 +03:00
int netxen_initialize_adapter_offload ( struct netxen_adapter * adapter )
{
uint64_t addr ;
uint32_t hi ;
uint32_t lo ;
adapter - > dummy_dma . addr =
pci_alloc_consistent ( adapter - > ahw . pdev ,
NETXEN_HOST_DUMMY_DMA_SIZE ,
& adapter - > dummy_dma . phys_addr ) ;
if ( adapter - > dummy_dma . addr = = NULL ) {
printk ( " %s: ERROR: Could not allocate dummy DMA memory \n " ,
__FUNCTION__ ) ;
return - ENOMEM ;
}
addr = ( uint64_t ) adapter - > dummy_dma . phys_addr ;
hi = ( addr > > 32 ) & 0xffffffff ;
lo = addr & 0xffffffff ;
writel ( hi , NETXEN_CRB_NORMALIZE ( adapter , CRB_HOST_DUMMY_BUF_ADDR_HI ) ) ;
writel ( lo , NETXEN_CRB_NORMALIZE ( adapter , CRB_HOST_DUMMY_BUF_ADDR_LO ) ) ;
return 0 ;
}
void netxen_free_adapter_offload ( struct netxen_adapter * adapter )
{
if ( adapter - > dummy_dma . addr ) {
pci_free_consistent ( adapter - > ahw . pdev ,
NETXEN_HOST_DUMMY_DMA_SIZE ,
adapter - > dummy_dma . addr ,
adapter - > dummy_dma . phys_addr ) ;
adapter - > dummy_dma . addr = NULL ;
}
}
2006-11-29 20:00:10 +03:00
void netxen_phantom_init ( struct netxen_adapter * adapter , int pegtune_val )
2006-10-21 23:33:03 +04:00
{
u32 val = 0 ;
int loops = 0 ;
2006-11-29 20:00:10 +03:00
if ( ! pegtune_val ) {
2006-10-21 23:33:03 +04:00
while ( val ! = PHAN_INITIALIZE_COMPLETE & & loops < 200000 ) {
udelay ( 100 ) ;
2006-11-29 20:00:10 +03:00
schedule ( ) ;
2006-10-21 23:33:03 +04:00
val =
readl ( NETXEN_CRB_NORMALIZE
( adapter , CRB_CMDPEG_STATE ) ) ;
loops + + ;
}
if ( val ! = PHAN_INITIALIZE_COMPLETE )
printk ( " WARNING: Initial boot wait loop failed... \n " ) ;
}
}
int netxen_nic_rx_has_work ( struct netxen_adapter * adapter )
{
int ctx ;
for ( ctx = 0 ; ctx < MAX_RCV_CTX ; + + ctx ) {
struct netxen_recv_context * recv_ctx =
& ( adapter - > recv_ctx [ ctx ] ) ;
u32 consumer ;
struct status_desc * desc_head ;
2006-11-29 20:00:10 +03:00
struct status_desc * desc ;
2006-10-21 23:33:03 +04:00
consumer = recv_ctx - > status_rx_consumer ;
desc_head = recv_ctx - > rcv_status_desc_head ;
desc = & desc_head [ consumer ] ;
2007-01-02 13:39:10 +03:00
if ( netxen_get_sts_owner ( desc ) & STATUS_OWNER_HOST )
2006-10-21 23:33:03 +04:00
return 1 ;
}
return 0 ;
}
2006-11-29 20:00:10 +03:00
static inline int netxen_nic_check_temp ( struct netxen_adapter * adapter )
{
int port_num ;
struct netxen_port * port ;
struct net_device * netdev ;
uint32_t temp , temp_state , temp_val ;
int rv = 0 ;
temp = readl ( NETXEN_CRB_NORMALIZE ( adapter , CRB_TEMP_STATE ) ) ;
temp_state = nx_get_temp_state ( temp ) ;
temp_val = nx_get_temp_val ( temp ) ;
if ( temp_state = = NX_TEMP_PANIC ) {
printk ( KERN_ALERT
" %s: Device temperature %d degrees C exceeds "
" maximum allowed. Hardware has been shut down. \n " ,
netxen_nic_driver_name , temp_val ) ;
for ( port_num = 0 ; port_num < adapter - > ahw . max_ports ;
port_num + + ) {
port = adapter - > port [ port_num ] ;
netdev = port - > netdev ;
netif_carrier_off ( netdev ) ;
netif_stop_queue ( netdev ) ;
}
rv = 1 ;
} else if ( temp_state = = NX_TEMP_WARN ) {
if ( adapter - > temp = = NX_TEMP_NORMAL ) {
printk ( KERN_ALERT
" %s: Device temperature %d degrees C "
" exceeds operating range. "
" Immediate action needed. \n " ,
netxen_nic_driver_name , temp_val ) ;
}
} else {
if ( adapter - > temp = = NX_TEMP_WARN ) {
printk ( KERN_INFO
" %s: Device temperature is now %d degrees C "
" in normal range. \n " , netxen_nic_driver_name ,
temp_val ) ;
}
}
adapter - > temp = temp_state ;
return rv ;
}
2006-12-05 22:36:26 +03:00
void netxen_watchdog_task ( struct work_struct * work )
2006-10-21 23:33:03 +04:00
{
int port_num ;
struct netxen_port * port ;
struct net_device * netdev ;
2006-12-05 22:36:26 +03:00
struct netxen_adapter * adapter =
container_of ( work , struct netxen_adapter , watchdog_task ) ;
2006-10-21 23:33:03 +04:00
2006-11-29 20:00:10 +03:00
if ( netxen_nic_check_temp ( adapter ) )
return ;
2006-10-21 23:33:03 +04:00
for ( port_num = 0 ; port_num < adapter - > ahw . max_ports ; port_num + + ) {
port = adapter - > port [ port_num ] ;
netdev = port - > netdev ;
if ( ( netif_running ( netdev ) ) & & ! netif_carrier_ok ( netdev ) ) {
printk ( KERN_INFO " %s port %d, %s carrier is now ok \n " ,
netxen_nic_driver_name , port_num , netdev - > name ) ;
netif_carrier_on ( netdev ) ;
}
if ( netif_queue_stopped ( netdev ) )
netif_wake_queue ( netdev ) ;
}
2006-12-04 20:18:00 +03:00
if ( adapter - > handle_phy_intr )
adapter - > handle_phy_intr ( adapter ) ;
2006-10-21 23:33:03 +04:00
mod_timer ( & adapter - > watchdog_timer , jiffies + 2 * HZ ) ;
}
/*
* netxen_process_rcv ( ) send the received packet to the protocol stack .
* and if the number of receives exceeds RX_BUFFERS_REFILL , then we
* invoke the routine to send more rx buffers to the Phantom . . .
*/
void
netxen_process_rcv ( struct netxen_adapter * adapter , int ctxid ,
struct status_desc * desc )
{
2006-12-04 20:23:25 +03:00
struct netxen_port * port = adapter - > port [ netxen_get_sts_port ( desc ) ] ;
2006-10-21 23:33:03 +04:00
struct pci_dev * pdev = port - > pdev ;
struct net_device * netdev = port - > netdev ;
2007-01-02 13:39:10 +03:00
int index = netxen_get_sts_refhandle ( desc ) ;
2006-10-21 23:33:03 +04:00
struct netxen_recv_context * recv_ctx = & ( adapter - > recv_ctx [ ctxid ] ) ;
struct netxen_rx_buffer * buffer ;
struct sk_buff * skb ;
2007-01-02 13:39:10 +03:00
u32 length = netxen_get_sts_totallength ( desc ) ;
2006-10-21 23:33:03 +04:00
u32 desc_ctx ;
struct netxen_rcv_desc_ctx * rcv_desc ;
int ret ;
2006-12-04 20:23:25 +03:00
desc_ctx = netxen_get_sts_type ( desc ) ;
2006-10-21 23:33:03 +04:00
if ( unlikely ( desc_ctx > = NUM_RCV_DESC_RINGS ) ) {
printk ( " %s: %s Bad Rcv descriptor ring \n " ,
netxen_nic_driver_name , netdev - > name ) ;
return ;
}
rcv_desc = & recv_ctx - > rcv_desc [ desc_ctx ] ;
2006-12-04 20:23:25 +03:00
if ( unlikely ( index > rcv_desc - > max_rx_desc_count ) ) {
DPRINTK ( ERR , " Got a buffer index:%x Max is %x \n " ,
index , rcv_desc - > max_rx_desc_count ) ;
return ;
}
2006-10-21 23:33:03 +04:00
buffer = & rcv_desc - > rx_buf_arr [ index ] ;
2006-12-04 20:23:25 +03:00
if ( desc_ctx = = RCV_DESC_LRO_CTXID ) {
buffer - > lro_current_frags + + ;
if ( netxen_get_sts_desc_lro_last_frag ( desc ) ) {
buffer - > lro_expected_frags =
netxen_get_sts_desc_lro_cnt ( desc ) ;
buffer - > lro_length = length ;
}
if ( buffer - > lro_current_frags ! = buffer - > lro_expected_frags ) {
if ( buffer - > lro_expected_frags ! = 0 ) {
printk ( " LRO: (refhandle:%x) recv frag. "
" wait for last. flags: %x expected:%d "
" have:%d \n " , index ,
netxen_get_sts_desc_lro_last_frag ( desc ) ,
buffer - > lro_expected_frags ,
buffer - > lro_current_frags ) ;
}
return ;
}
}
2006-10-21 23:33:03 +04:00
pci_unmap_single ( pdev , buffer - > dma , rcv_desc - > dma_size ,
PCI_DMA_FROMDEVICE ) ;
skb = ( struct sk_buff * ) buffer - > skb ;
2006-12-04 20:23:25 +03:00
if ( likely ( netxen_get_sts_status ( desc ) = = STATUS_CKSUM_OK ) ) {
2006-10-21 23:33:03 +04:00
port - > stats . csummed + + ;
skb - > ip_summed = CHECKSUM_UNNECESSARY ;
2006-12-04 20:23:25 +03:00
}
2006-10-21 23:33:03 +04:00
skb - > dev = netdev ;
2006-12-04 20:23:25 +03:00
if ( desc_ctx = = RCV_DESC_LRO_CTXID ) {
/* True length was only available on the last pkt */
skb_put ( skb , buffer - > lro_length ) ;
} else {
skb_put ( skb , length ) ;
}
2006-10-21 23:33:03 +04:00
skb - > protocol = eth_type_trans ( skb , netdev ) ;
ret = netif_receive_skb ( skb ) ;
/*
* RH : Do we need these stats on a regular basis . Can we get it from
* Linux stats .
*/
switch ( ret ) {
case NET_RX_SUCCESS :
port - > stats . uphappy + + ;
break ;
case NET_RX_CN_LOW :
port - > stats . uplcong + + ;
break ;
case NET_RX_CN_MOD :
port - > stats . upmcong + + ;
break ;
case NET_RX_CN_HIGH :
port - > stats . uphcong + + ;
break ;
case NET_RX_DROP :
port - > stats . updropped + + ;
break ;
default :
port - > stats . updunno + + ;
break ;
}
netdev - > last_rx = jiffies ;
rcv_desc - > rcv_free + + ;
rcv_desc - > rcv_pending - - ;
/*
* We just consumed one buffer so post a buffer .
*/
adapter - > stats . post_called + + ;
buffer - > skb = NULL ;
buffer - > state = NETXEN_BUFFER_FREE ;
2006-12-04 20:23:25 +03:00
buffer - > lro_current_frags = 0 ;
buffer - > lro_expected_frags = 0 ;
2006-10-21 23:33:03 +04:00
port - > stats . no_rcv + + ;
port - > stats . rxbytes + = length ;
}
/* Process Receive status ring */
u32 netxen_process_rcv_ring ( struct netxen_adapter * adapter , int ctxid , int max )
{
struct netxen_recv_context * recv_ctx = & ( adapter - > recv_ctx [ ctxid ] ) ;
struct status_desc * desc_head = recv_ctx - > rcv_status_desc_head ;
struct status_desc * desc ; /* used to read status desc here */
u32 consumer = recv_ctx - > status_rx_consumer ;
2006-12-04 20:23:25 +03:00
u32 producer = 0 ;
2006-10-21 23:33:03 +04:00
int count = 0 , ring ;
DPRINTK ( INFO , " procesing receive \n " ) ;
/*
* we assume in this case that there is only one port and that is
* port # 1. . . changes need to be done in firmware to indicate port
* number as part of the descriptor . This way we will be able to get
* the netdev which is associated with that device .
*/
while ( count < max ) {
desc = & desc_head [ consumer ] ;
2007-01-02 13:39:10 +03:00
if ( ! ( netxen_get_sts_owner ( desc ) & STATUS_OWNER_HOST ) ) {
2006-12-04 20:23:25 +03:00
DPRINTK ( ERR , " desc %p ownedby %x \n " , desc ,
netxen_get_sts_owner ( desc ) ) ;
2006-10-21 23:33:03 +04:00
break ;
}
netxen_process_rcv ( adapter , ctxid , desc ) ;
2006-12-04 20:23:25 +03:00
netxen_clear_sts_owner ( desc ) ;
2007-01-02 13:39:10 +03:00
netxen_set_sts_owner ( desc , STATUS_OWNER_PHANTOM ) ;
2006-10-21 23:33:03 +04:00
consumer = ( consumer + 1 ) & ( adapter - > max_rx_desc_count - 1 ) ;
count + + ;
}
if ( count ) {
for ( ring = 0 ; ring < NUM_RCV_DESC_RINGS ; ring + + ) {
2006-12-04 20:23:25 +03:00
netxen_post_rx_buffers_nodb ( adapter , ctxid , ring ) ;
2006-10-21 23:33:03 +04:00
}
}
/* update the consumer index in phantom */
if ( count ) {
adapter - > stats . process_rcv + + ;
recv_ctx - > status_rx_consumer = consumer ;
2006-12-04 20:23:25 +03:00
recv_ctx - > status_rx_producer = producer ;
2006-10-21 23:33:03 +04:00
/* Window = 1 */
writel ( consumer ,
NETXEN_CRB_NORMALIZE ( adapter ,
recv_crb_registers [ ctxid ] .
crb_rcv_status_consumer ) ) ;
}
return count ;
}
/* Process Command status ring */
2006-12-04 20:23:25 +03:00
int netxen_process_cmd_ring ( unsigned long data )
2006-10-21 23:33:03 +04:00
{
u32 last_consumer ;
u32 consumer ;
struct netxen_adapter * adapter = ( struct netxen_adapter * ) data ;
2006-12-04 20:23:25 +03:00
int count1 = 0 ;
int count2 = 0 ;
2006-10-21 23:33:03 +04:00
struct netxen_cmd_buffer * buffer ;
struct netxen_port * port ; /* port #1 */
struct netxen_port * nport ;
struct pci_dev * pdev ;
struct netxen_skb_frag * frag ;
u32 i ;
struct sk_buff * skb = NULL ;
int p ;
2006-12-04 20:23:25 +03:00
int done ;
2006-10-21 23:33:03 +04:00
spin_lock ( & adapter - > tx_lock ) ;
last_consumer = adapter - > last_cmd_consumer ;
DPRINTK ( INFO , " procesing xmit complete \n " ) ;
/* we assume in this case that there is only one port and that is
* port # 1. . . changes need to be done in firmware to indicate port
* number as part of the descriptor . This way we will be able to get
* the netdev which is associated with that device .
*/
2006-12-04 20:23:25 +03:00
consumer = * ( adapter - > cmd_consumer ) ;
2006-10-21 23:33:03 +04:00
if ( last_consumer = = consumer ) { /* Ring is empty */
DPRINTK ( INFO , " last_consumer %d == consumer %d \n " ,
last_consumer , consumer ) ;
spin_unlock ( & adapter - > tx_lock ) ;
2006-12-04 20:23:25 +03:00
return 1 ;
2006-10-21 23:33:03 +04:00
}
adapter - > proc_cmd_buf_counter + + ;
adapter - > stats . process_xmit + + ;
/*
* Not needed - does not seem to be used anywhere .
* adapter - > cmd_consumer = consumer ;
*/
spin_unlock ( & adapter - > tx_lock ) ;
2006-12-04 20:23:25 +03:00
while ( ( last_consumer ! = consumer ) & & ( count1 < MAX_STATUS_HANDLE ) ) {
2006-10-21 23:33:03 +04:00
buffer = & adapter - > cmd_buf_arr [ last_consumer ] ;
port = adapter - > port [ buffer - > port ] ;
pdev = port - > pdev ;
frag = & buffer - > frag_array [ 0 ] ;
skb = buffer - > skb ;
if ( skb & & ( cmpxchg ( & buffer - > skb , skb , 0 ) = = skb ) ) {
pci_unmap_single ( pdev , frag - > dma , frag - > length ,
PCI_DMA_TODEVICE ) ;
for ( i = 1 ; i < buffer - > frag_count ; i + + ) {
DPRINTK ( INFO , " getting fragment no %d \n " , i ) ;
frag + + ; /* Get the next frag */
pci_unmap_page ( pdev , frag - > dma , frag - > length ,
PCI_DMA_TODEVICE ) ;
}
port - > stats . skbfreed + + ;
dev_kfree_skb_any ( skb ) ;
skb = NULL ;
} else if ( adapter - > proc_cmd_buf_counter = = 1 ) {
port - > stats . txnullskb + + ;
}
if ( unlikely ( netif_queue_stopped ( port - > netdev )
& & netif_carrier_ok ( port - > netdev ) )
& & ( ( jiffies - port - > netdev - > trans_start ) >
port - > netdev - > watchdog_timeo ) ) {
2006-12-18 16:53:36 +03:00
SCHEDULE_WORK ( & port - > tx_timeout_task ) ;
2006-10-21 23:33:03 +04:00
}
last_consumer = get_next_index ( last_consumer ,
adapter - > max_tx_desc_count ) ;
2006-12-04 20:23:25 +03:00
count1 + + ;
2006-10-21 23:33:03 +04:00
}
2006-12-04 20:23:25 +03:00
adapter - > stats . noxmitdone + = count1 ;
2006-10-21 23:33:03 +04:00
2006-12-04 20:23:25 +03:00
count2 = 0 ;
2006-10-21 23:33:03 +04:00
spin_lock ( & adapter - > tx_lock ) ;
if ( ( - - adapter - > proc_cmd_buf_counter ) = = 0 ) {
adapter - > last_cmd_consumer = last_consumer ;
while ( ( adapter - > last_cmd_consumer ! = consumer )
2006-12-04 20:23:25 +03:00
& & ( count2 < MAX_STATUS_HANDLE ) ) {
2006-10-21 23:33:03 +04:00
buffer =
& adapter - > cmd_buf_arr [ adapter - > last_cmd_consumer ] ;
2006-12-04 20:23:25 +03:00
count2 + + ;
2006-10-21 23:33:03 +04:00
if ( buffer - > skb )
break ;
else
adapter - > last_cmd_consumer =
get_next_index ( adapter - > last_cmd_consumer ,
adapter - > max_tx_desc_count ) ;
}
}
2006-12-04 20:23:25 +03:00
if ( count1 | | count2 ) {
2006-10-21 23:33:03 +04:00
for ( p = 0 ; p < adapter - > ahw . max_ports ; p + + ) {
nport = adapter - > port [ p ] ;
if ( netif_queue_stopped ( nport - > netdev )
& & ( nport - > flags & NETXEN_NETDEV_STATUS ) ) {
netif_wake_queue ( nport - > netdev ) ;
nport - > flags & = ~ NETXEN_NETDEV_STATUS ;
}
}
}
2006-12-04 20:23:25 +03:00
/*
* If everything is freed up to consumer then check if the ring is full
* If the ring is full then check if more needs to be freed and
* schedule the call back again .
*
* This happens when there are 2 CPUs . One could be freeing and the
* other filling it . If the ring is full when we get out of here and
* the card has already interrupted the host then the host can miss the
* interrupt .
*
* There is still a possible race condition and the host could miss an
* interrupt . The card has to take care of this .
*/
if ( adapter - > last_cmd_consumer = = consumer & &
( ( ( adapter - > cmd_producer + 1 ) %
adapter - > max_tx_desc_count ) = = adapter - > last_cmd_consumer ) ) {
consumer = * ( adapter - > cmd_consumer ) ;
}
done = ( adapter - > last_cmd_consumer = = consumer ) ;
2006-10-21 23:33:03 +04:00
spin_unlock ( & adapter - > tx_lock ) ;
DPRINTK ( INFO , " last consumer is %d in %s \n " , last_consumer ,
__FUNCTION__ ) ;
2006-12-04 20:23:25 +03:00
return ( done ) ;
2006-10-21 23:33:03 +04:00
}
/*
* netxen_post_rx_buffers puts buffer in the Phantom memory
*/
void netxen_post_rx_buffers ( struct netxen_adapter * adapter , u32 ctx , u32 ringid )
{
struct pci_dev * pdev = adapter - > ahw . pdev ;
struct sk_buff * skb ;
struct netxen_recv_context * recv_ctx = & ( adapter - > recv_ctx [ ctx ] ) ;
struct netxen_rcv_desc_ctx * rcv_desc = NULL ;
2006-12-04 20:23:25 +03:00
uint producer ;
2006-10-21 23:33:03 +04:00
struct rcv_desc * pdesc ;
struct netxen_rx_buffer * buffer ;
int count = 0 ;
int index = 0 ;
2006-12-04 20:23:25 +03:00
netxen_ctx_msg msg = 0 ;
dma_addr_t dma ;
2006-10-21 23:33:03 +04:00
adapter - > stats . post_called + + ;
rcv_desc = & recv_ctx - > rcv_desc [ ringid ] ;
producer = rcv_desc - > producer ;
index = rcv_desc - > begin_alloc ;
buffer = & rcv_desc - > rx_buf_arr [ index ] ;
/* We can start writing rx descriptors into the phantom memory. */
while ( buffer - > state = = NETXEN_BUFFER_FREE ) {
skb = dev_alloc_skb ( rcv_desc - > skb_size ) ;
if ( unlikely ( ! skb ) ) {
/*
2006-12-04 20:23:25 +03:00
* TODO
2006-10-21 23:33:03 +04:00
* We need to schedule the posting of buffers to the pegs .
*/
rcv_desc - > begin_alloc = index ;
2006-11-29 20:00:10 +03:00
DPRINTK ( ERR , " netxen_post_rx_buffers: "
2006-10-21 23:33:03 +04:00
" allocated only %d buffers \n " , count ) ;
break ;
}
2006-12-04 20:23:25 +03:00
count + + ; /* now there should be no failure */
pdesc = & rcv_desc - > desc_head [ producer ] ;
# if defined(XGB_DEBUG)
* ( unsigned long * ) ( skb - > head ) = 0xc0debabe ;
if ( skb_is_nonlinear ( skb ) ) {
printk ( " Allocated SKB @%p is nonlinear \n " ) ;
}
# endif
skb_reserve ( skb , 2 ) ;
/* This will be setup when we receive the
* buffer after it has been filled FSL TBD TBD
* skb - > dev = netdev ;
*/
dma = pci_map_single ( pdev , skb - > data , rcv_desc - > dma_size ,
PCI_DMA_FROMDEVICE ) ;
2006-12-18 16:53:59 +03:00
pdesc - > addr_buffer = cpu_to_le64 ( dma ) ;
2006-12-04 20:23:25 +03:00
buffer - > skb = skb ;
buffer - > state = NETXEN_BUFFER_BUSY ;
buffer - > dma = dma ;
/* make a rcv descriptor */
2006-12-18 16:53:59 +03:00
pdesc - > reference_handle = cpu_to_le16 ( buffer - > ref_handle ) ;
pdesc - > buffer_length = cpu_to_le32 ( rcv_desc - > dma_size ) ;
2006-12-04 20:23:25 +03:00
DPRINTK ( INFO , " done writing descripter \n " ) ;
producer =
get_next_index ( producer , rcv_desc - > max_rx_desc_count ) ;
index = get_next_index ( index , rcv_desc - > max_rx_desc_count ) ;
buffer = & rcv_desc - > rx_buf_arr [ index ] ;
}
/* if we did allocate buffers, then write the count to Phantom */
if ( count ) {
rcv_desc - > begin_alloc = index ;
rcv_desc - > rcv_pending + = count ;
adapter - > stats . lastposted = count ;
adapter - > stats . posted + = count ;
rcv_desc - > producer = producer ;
if ( rcv_desc - > rcv_free > = 32 ) {
rcv_desc - > rcv_free = 0 ;
/* Window = 1 */
writel ( ( producer - 1 ) &
( rcv_desc - > max_rx_desc_count - 1 ) ,
NETXEN_CRB_NORMALIZE ( adapter ,
recv_crb_registers [ 0 ] .
rcv_desc_crb [ ringid ] .
crb_rcv_producer_offset ) ) ;
/*
* Write a doorbell msg to tell phanmon of change in
* receive ring producer
*/
netxen_set_msg_peg_id ( msg , NETXEN_RCV_PEG_DB_ID ) ;
netxen_set_msg_privid ( msg ) ;
netxen_set_msg_count ( msg ,
( ( producer -
1 ) & ( rcv_desc - >
max_rx_desc_count - 1 ) ) ) ;
netxen_set_msg_ctxid ( msg , 0 ) ;
netxen_set_msg_opcode ( msg , NETXEN_RCV_PRODUCER ( ringid ) ) ;
writel ( msg ,
DB_NORMALIZE ( adapter ,
NETXEN_RCV_PRODUCER_OFFSET ) ) ;
}
}
}
void netxen_post_rx_buffers_nodb ( struct netxen_adapter * adapter , uint32_t ctx ,
uint32_t ringid )
{
struct pci_dev * pdev = adapter - > ahw . pdev ;
struct sk_buff * skb ;
struct netxen_recv_context * recv_ctx = & ( adapter - > recv_ctx [ ctx ] ) ;
struct netxen_rcv_desc_ctx * rcv_desc = NULL ;
u32 producer ;
struct rcv_desc * pdesc ;
struct netxen_rx_buffer * buffer ;
int count = 0 ;
int index = 0 ;
adapter - > stats . post_called + + ;
rcv_desc = & recv_ctx - > rcv_desc [ ringid ] ;
producer = rcv_desc - > producer ;
index = rcv_desc - > begin_alloc ;
buffer = & rcv_desc - > rx_buf_arr [ index ] ;
/* We can start writing rx descriptors into the phantom memory. */
while ( buffer - > state = = NETXEN_BUFFER_FREE ) {
skb = dev_alloc_skb ( rcv_desc - > skb_size ) ;
if ( unlikely ( ! skb ) ) {
/*
* We need to schedule the posting of buffers to the pegs .
*/
rcv_desc - > begin_alloc = index ;
DPRINTK ( ERR , " netxen_post_rx_buffers_nodb: "
" allocated only %d buffers \n " , count ) ;
break ;
}
2006-10-21 23:33:03 +04:00
count + + ; /* now there should be no failure */
pdesc = & rcv_desc - > desc_head [ producer ] ;
2006-12-04 20:23:25 +03:00
skb_reserve ( skb , 2 ) ;
2006-10-21 23:33:03 +04:00
/*
* This will be setup when we receive the
* buffer after it has been filled
* skb - > dev = netdev ;
*/
buffer - > skb = skb ;
buffer - > state = NETXEN_BUFFER_BUSY ;
buffer - > dma = pci_map_single ( pdev , skb - > data ,
rcv_desc - > dma_size ,
PCI_DMA_FROMDEVICE ) ;
2006-12-04 20:23:25 +03:00
2006-10-21 23:33:03 +04:00
/* make a rcv descriptor */
2006-12-18 16:53:59 +03:00
pdesc - > reference_handle = cpu_to_le16 ( buffer - > ref_handle ) ;
2007-01-02 13:39:10 +03:00
pdesc - > buffer_length = cpu_to_le32 ( rcv_desc - > dma_size ) ;
2006-10-21 23:33:03 +04:00
pdesc - > addr_buffer = cpu_to_le64 ( buffer - > dma ) ;
DPRINTK ( INFO , " done writing descripter \n " ) ;
producer =
get_next_index ( producer , rcv_desc - > max_rx_desc_count ) ;
index = get_next_index ( index , rcv_desc - > max_rx_desc_count ) ;
buffer = & rcv_desc - > rx_buf_arr [ index ] ;
}
/* if we did allocate buffers, then write the count to Phantom */
if ( count ) {
rcv_desc - > begin_alloc = index ;
rcv_desc - > rcv_pending + = count ;
adapter - > stats . lastposted = count ;
adapter - > stats . posted + = count ;
rcv_desc - > producer = producer ;
if ( rcv_desc - > rcv_free > = 32 ) {
rcv_desc - > rcv_free = 0 ;
/* Window = 1 */
writel ( ( producer - 1 ) &
( rcv_desc - > max_rx_desc_count - 1 ) ,
NETXEN_CRB_NORMALIZE ( adapter ,
2006-12-04 20:23:25 +03:00
recv_crb_registers [ 0 ] .
rcv_desc_crb [ ringid ] .
2006-10-21 23:33:03 +04:00
crb_rcv_producer_offset ) ) ;
wmb ( ) ;
}
}
}
int netxen_nic_tx_has_work ( struct netxen_adapter * adapter )
{
if ( find_diff_among ( adapter - > last_cmd_consumer ,
adapter - > cmd_producer ,
adapter - > max_tx_desc_count ) > 0 )
return 1 ;
return 0 ;
}
void netxen_nic_clear_stats ( struct netxen_adapter * adapter )
{
struct netxen_port * port ;
int port_num ;
memset ( & adapter - > stats , 0 , sizeof ( adapter - > stats ) ) ;
for ( port_num = 0 ; port_num < adapter - > ahw . max_ports ; port_num + + ) {
port = adapter - > port [ port_num ] ;
memset ( & port - > stats , 0 , sizeof ( port - > stats ) ) ;
}
}