5563 lines
		
	
	
		
			151 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			5563 lines
		
	
	
		
			151 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/******************************************************************************/
 | 
						|
/*                                                                            */
 | 
						|
/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2005 Broadcom  */
 | 
						|
/* Corporation.                                                               */
 | 
						|
/* All rights reserved.                                                       */
 | 
						|
/*                                                                            */
 | 
						|
/* 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, located in the file LICENSE.                 */
 | 
						|
/*                                                                            */
 | 
						|
/******************************************************************************/
 | 
						|
 | 
						|
 | 
						|
char bcm5700_driver[] = "bcm57xx";
 | 
						|
char bcm5700_version[] = "8.3.14";
 | 
						|
char bcm5700_date[] = "(11/2/05)";
 | 
						|
 | 
						|
#define B57UM
 | 
						|
#include "mm.h"
 | 
						|
#include "linux/mii.h" //@.@jack add it 2006/06/28.
 | 
						|
#include "typedefs.h"
 | 
						|
#include "osl.h"
 | 
						|
#include "bcmdefs.h"
 | 
						|
#include "bcmdevs.h"
 | 
						|
#include "sbconfig.h"
 | 
						|
#include "sbutils.h"
 | 
						|
#include "hndgige.h"
 | 
						|
#include "bcmrobo.h"
 | 
						|
#include "robo_register.c"
 | 
						|
 | 
						|
#include "bcmendian.h"
 | 
						|
#include "bcmnvram.h"
 | 
						|
#include "proto/ethernet.h"
 | 
						|
#include "proto/vlan.h"
 | 
						|
#include "proto/bcmtcp.h"
 | 
						|
#include "proto/bcmip.h"
 | 
						|
#define	PKTDATA(osh, skb)		(((struct sk_buff*)(skb))->data)
 | 
						|
 | 
						|
/* this is needed to get good and stable performances */
 | 
						|
#define EXTRA_HDR BCMEXTRAHDROOM
 | 
						|
 | 
						|
#define SIOCGREG_STATUS  0x8996          /* Read Switch register (for debug)*/
 | 
						|
#define SIOCSREG_STATUS  0x8997          /* Write Switch register(for debug)*/
 | 
						|
 | 
						|
/* This structure is used in SIOCXREG_STATUS ioctl calls*/
 | 
						|
struct reg_ioctl_data {
 | 
						|
        u16             page_num;
 | 
						|
        u16             addr_num;
 | 
						|
        u16             len;
 | 
						|
	u16		val_in[4];
 | 
						|
	u16		val_out[4];
 | 
						|
};
 | 
						|
 | 
						|
/* A few user-configurable values. */
 | 
						|
 | 
						|
#define MAX_UNITS 16
 | 
						|
/* Used to pass the full-duplex flag, etc. */
 | 
						|
static int line_speed[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 | 
						|
static int auto_speed[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 | 
						|
static int full_duplex[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 | 
						|
static int rx_flow_control[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 | 
						|
static int tx_flow_control[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 | 
						|
static int auto_flow_control[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
static int mtu[MAX_UNITS] = {1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500};	/* Jumbo MTU for interfaces. */
 | 
						|
#endif
 | 
						|
static int tx_checksum[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 | 
						|
static int rx_checksum[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 | 
						|
static int scatter_gather[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 | 
						|
static int activate_gpio = -1;
 | 
						|
 | 
						|
#define TX_DESC_CNT DEFAULT_TX_PACKET_DESC_COUNT
 | 
						|
static unsigned int tx_pkt_desc_cnt[MAX_UNITS] =
 | 
						|
	{TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,
 | 
						|
	TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,
 | 
						|
	TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,
 | 
						|
	TX_DESC_CNT};
 | 
						|
 | 
						|
#define RX_DESC_CNT DEFAULT_STD_RCV_DESC_COUNT
 | 
						|
static unsigned int rx_std_desc_cnt[MAX_UNITS] =
 | 
						|
	{RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,
 | 
						|
	RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,
 | 
						|
	RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,
 | 
						|
	RX_DESC_CNT };
 | 
						|
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
#define JBO_DESC_CNT DEFAULT_JUMBO_RCV_DESC_COUNT
 | 
						|
static unsigned int rx_jumbo_desc_cnt[MAX_UNITS] =
 | 
						|
	{JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,
 | 
						|
	JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,
 | 
						|
	JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,
 | 
						|
	JBO_DESC_CNT };
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef BCM_INT_COAL
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
static unsigned int adaptive_coalesce[MAX_UNITS] =
 | 
						|
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 | 
						|
#else
 | 
						|
static unsigned int adaptive_coalesce[MAX_UNITS] =
 | 
						|
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 | 
						|
#endif
 | 
						|
 | 
						|
#define RX_COAL_TK DEFAULT_RX_COALESCING_TICKS
 | 
						|
static unsigned int rx_coalesce_ticks[MAX_UNITS] =
 | 
						|
	{RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,
 | 
						|
	RX_COAL_TK, RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,
 | 
						|
	RX_COAL_TK,RX_COAL_TK, RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,
 | 
						|
	RX_COAL_TK};
 | 
						|
 | 
						|
#define RX_COAL_FM DEFAULT_RX_MAX_COALESCED_FRAMES
 | 
						|
static unsigned int rx_max_coalesce_frames[MAX_UNITS] =
 | 
						|
	{RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,
 | 
						|
	RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,
 | 
						|
	RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,
 | 
						|
	RX_COAL_FM};
 | 
						|
 | 
						|
#define TX_COAL_TK DEFAULT_TX_COALESCING_TICKS
 | 
						|
static unsigned int tx_coalesce_ticks[MAX_UNITS] =
 | 
						|
	{TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,
 | 
						|
	TX_COAL_TK, TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,
 | 
						|
	TX_COAL_TK,TX_COAL_TK, TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,
 | 
						|
	TX_COAL_TK};
 | 
						|
 | 
						|
#define TX_COAL_FM DEFAULT_TX_MAX_COALESCED_FRAMES
 | 
						|
static unsigned int tx_max_coalesce_frames[MAX_UNITS] =
 | 
						|
	{TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,
 | 
						|
	TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,
 | 
						|
	TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,
 | 
						|
	TX_COAL_FM};
 | 
						|
 | 
						|
#define ST_COAL_TK DEFAULT_STATS_COALESCING_TICKS
 | 
						|
static unsigned int stats_coalesce_ticks[MAX_UNITS] =
 | 
						|
	{ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,
 | 
						|
	ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,
 | 
						|
	ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,
 | 
						|
	ST_COAL_TK,};
 | 
						|
 | 
						|
#endif
 | 
						|
#ifdef BCM_WOL
 | 
						|
static int enable_wol[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 | 
						|
#endif
 | 
						|
#ifdef BCM_TSO
 | 
						|
static int enable_tso[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
 | 
						|
#endif
 | 
						|
#ifdef BCM_NIC_SEND_BD
 | 
						|
static int nic_tx_bd[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 | 
						|
#endif
 | 
						|
#ifdef BCM_ASF
 | 
						|
static int vlan_tag_mode[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 | 
						|
#endif
 | 
						|
static int delay_link[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 | 
						|
static int disable_d3hot[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 | 
						|
 | 
						|
#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR)
 | 
						|
static int disable_msi[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 | 
						|
static int bcm_msi_chipset_bug = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
#define BCM_TIMER_GRANULARITY  (1000000 / HZ)
 | 
						|
 | 
						|
/* Hack to hook the data path to the BCM WL dirver */
 | 
						|
#ifdef BCM_WL_EMULATOR
 | 
						|
#include "bcmnvram.h"
 | 
						|
#include "wl_bcm57emu.h" 
 | 
						|
#ifdef SKB_MANAGER
 | 
						|
int skb_old_alloc = 0;
 | 
						|
#endif
 | 
						|
#endif /* BCM_WL_EMULATOR */
 | 
						|
 | 
						|
/* Operational parameters that usually are not changed. */
 | 
						|
/* Time in jiffies before concluding the transmitter is hung. */
 | 
						|
#define TX_TIMEOUT  (2*HZ)
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x02030d)
 | 
						|
#define pci_resource_start(dev, bar)	(dev->base_address[bar] & PCI_BASE_ADDRESS_MEM_MASK)
 | 
						|
#elif (LINUX_VERSION_CODE < 0x02032b)
 | 
						|
#define pci_resource_start(dev, bar)	(dev->resource[bar] & PCI_BASE_ADDRESS_MEM_MASK)
 | 
						|
#endif
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x02032b)
 | 
						|
#define dev_kfree_skb_irq(skb)  dev_kfree_skb(skb)
 | 
						|
#define netif_wake_queue(dev)	clear_bit(0, &dev->tbusy); mark_bh(NET_BH)
 | 
						|
#define netif_stop_queue(dev)	set_bit(0, &dev->tbusy)
 | 
						|
 | 
						|
static inline void netif_start_queue(struct net_device *dev)
 | 
						|
{
 | 
						|
	dev->tbusy = 0;
 | 
						|
	dev->interrupt = 0;
 | 
						|
	dev->start = 1;
 | 
						|
}
 | 
						|
 | 
						|
#define netif_queue_stopped(dev)	dev->tbusy
 | 
						|
#define netif_running(dev)		dev->start
 | 
						|
 | 
						|
static inline void tasklet_schedule(struct tasklet_struct *tasklet)
 | 
						|
{
 | 
						|
	queue_task(tasklet, &tq_immediate);
 | 
						|
	mark_bh(IMMEDIATE_BH);
 | 
						|
}
 | 
						|
 | 
						|
static inline void tasklet_init(struct tasklet_struct *tasklet,
 | 
						|
				void (*func)(unsigned long),
 | 
						|
				unsigned long data)
 | 
						|
{
 | 
						|
		tasklet->next = NULL;
 | 
						|
		tasklet->sync = 0;
 | 
						|
		tasklet->routine = (void (*)(void *))func;
 | 
						|
		tasklet->data = (void *)data;
 | 
						|
}
 | 
						|
 | 
						|
#define tasklet_kill(tasklet)
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x020300)
 | 
						|
struct pci_device_id {
 | 
						|
	unsigned int vendor, device;		/* Vendor and device ID or PCI_ANY_ID */
 | 
						|
	unsigned int subvendor, subdevice;	/* Subsystem ID's or PCI_ANY_ID */
 | 
						|
	unsigned int class, class_mask;		/* (class,subclass,prog-if) triplet */
 | 
						|
	unsigned long driver_data;		/* Data private to the driver */
 | 
						|
};
 | 
						|
 | 
						|
#define PCI_ANY_ID		0
 | 
						|
 | 
						|
#define pci_set_drvdata(pdev, dev)
 | 
						|
#define pci_get_drvdata(pdev) 0
 | 
						|
 | 
						|
#define pci_enable_device(pdev) 0
 | 
						|
 | 
						|
#define __devinit		__init
 | 
						|
#define __devinitdata		__initdata
 | 
						|
#define __devexit
 | 
						|
 | 
						|
#define SET_MODULE_OWNER(dev)
 | 
						|
#define MODULE_DEVICE_TABLE(pci, pci_tbl)
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x020411)
 | 
						|
#ifndef __devexit_p
 | 
						|
#define __devexit_p(x)	x
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef MODULE_LICENSE
 | 
						|
#define MODULE_LICENSE(license)
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef IRQ_RETVAL
 | 
						|
typedef void irqreturn_t;
 | 
						|
#define IRQ_RETVAL(x)
 | 
						|
#endif
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x02032a)
 | 
						|
static inline void *pci_alloc_consistent(struct pci_dev *pdev, size_t size,
 | 
						|
					 dma_addr_t *dma_handle)
 | 
						|
{
 | 
						|
	void *virt_ptr;
 | 
						|
 | 
						|
	/* Maximum in slab.c */
 | 
						|
	if (size > 131072)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	virt_ptr = kmalloc(size, GFP_KERNEL);
 | 
						|
	*dma_handle = virt_to_bus(virt_ptr);
 | 
						|
	return virt_ptr;
 | 
						|
}
 | 
						|
#define pci_free_consistent(dev, size, ptr, dma_ptr)	kfree(ptr)
 | 
						|
 | 
						|
#endif /*#if (LINUX_VERSION_CODE < 0x02032a) */
 | 
						|
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x02040d)
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x020409) && defined(RED_HAT_LINUX_KERNEL)
 | 
						|
 | 
						|
#define BCM_32BIT_DMA_MASK ((u64) 0x00000000ffffffffULL)
 | 
						|
#define BCM_64BIT_DMA_MASK ((u64) 0xffffffffffffffffULL)
 | 
						|
 | 
						|
#else
 | 
						|
/* pci_set_dma_mask is using dma_addr_t */
 | 
						|
 | 
						|
#define BCM_32BIT_DMA_MASK ((dma_addr_t) 0xffffffff)
 | 
						|
#define BCM_64BIT_DMA_MASK ((dma_addr_t) 0xffffffff)
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
#else /* (LINUX_VERSION_CODE < 0x02040d) */
 | 
						|
 | 
						|
#define BCM_32BIT_DMA_MASK ((u64) 0x00000000ffffffffULL)
 | 
						|
#define BCM_64BIT_DMA_MASK ((u64) 0xffffffffffffffffULL)
 | 
						|
#endif
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x020329)
 | 
						|
#define pci_set_dma_mask(pdev, mask) (0)
 | 
						|
#else
 | 
						|
#if (LINUX_VERSION_CODE < 0x020403)
 | 
						|
int
 | 
						|
pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask)
 | 
						|
{
 | 
						|
    if(! pci_dma_supported(dev, mask))
 | 
						|
        return -EIO;
 | 
						|
 | 
						|
    dev->dma_mask = mask;
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x020547)
 | 
						|
#define pci_set_consistent_dma_mask(pdev, mask) (0)
 | 
						|
#endif
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x020402)
 | 
						|
#define pci_request_regions(pdev, name) (0)
 | 
						|
#define pci_release_regions(pdev)
 | 
						|
#endif
 | 
						|
 | 
						|
#if !defined(spin_is_locked)
 | 
						|
#define spin_is_locked(lock)    (test_bit(0,(lock)))
 | 
						|
#endif
 | 
						|
 | 
						|
#define BCM5700_LOCK(pUmDevice, flags)					\
 | 
						|
	if ((pUmDevice)->do_global_lock) {				\
 | 
						|
		spin_lock_irqsave(&(pUmDevice)->global_lock, flags);	\
 | 
						|
	}
 | 
						|
 | 
						|
#define BCM5700_UNLOCK(pUmDevice, flags)				\
 | 
						|
	if ((pUmDevice)->do_global_lock) {				\
 | 
						|
		spin_unlock_irqrestore(&(pUmDevice)->global_lock, flags);\
 | 
						|
	}
 | 
						|
 | 
						|
inline void
 | 
						|
bcm5700_intr_lock(PUM_DEVICE_BLOCK pUmDevice)
 | 
						|
{
 | 
						|
	if (pUmDevice->do_global_lock) {
 | 
						|
		spin_lock(&pUmDevice->global_lock);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
inline void
 | 
						|
bcm5700_intr_unlock(PUM_DEVICE_BLOCK pUmDevice)
 | 
						|
{
 | 
						|
	if (pUmDevice->do_global_lock) {
 | 
						|
		spin_unlock(&pUmDevice->global_lock);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
bcm5700_intr_off(PUM_DEVICE_BLOCK pUmDevice)
 | 
						|
{
 | 
						|
	atomic_inc(&pUmDevice->intr_sem);
 | 
						|
	LM_DisableInterrupt(&pUmDevice->lm_dev);
 | 
						|
#if (LINUX_VERSION_CODE >= 0x2051c)
 | 
						|
	synchronize_irq(pUmDevice->dev->irq);
 | 
						|
#else
 | 
						|
	synchronize_irq();
 | 
						|
#endif
 | 
						|
	LM_DisableInterrupt(&pUmDevice->lm_dev);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
bcm5700_intr_on(PUM_DEVICE_BLOCK pUmDevice)
 | 
						|
{
 | 
						|
	if (atomic_dec_and_test(&pUmDevice->intr_sem)) {
 | 
						|
		LM_EnableInterrupt(&pUmDevice->lm_dev);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int MM_Packet_Desc_Size = sizeof(UM_PACKET);
 | 
						|
 | 
						|
#if defined(MODULE)
 | 
						|
MODULE_AUTHOR("Michael Chan <mchan at broadcom dot com> and Gary Zambrano <zambrano at broadcom dot com>");
 | 
						|
MODULE_DESCRIPTION("BCM5700 Driver");
 | 
						|
MODULE_LICENSE("GPL");
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x020605)
 | 
						|
 | 
						|
MODULE_PARM(debug, "i");
 | 
						|
MODULE_PARM(msglevel, "i");
 | 
						|
MODULE_PARM(activate_gpio, "0-15i");
 | 
						|
MODULE_PARM(line_speed, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(auto_speed, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(rx_flow_control, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(tx_flow_control, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(auto_flow_control, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
MODULE_PARM(mtu, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
#endif
 | 
						|
MODULE_PARM(tx_checksum, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(rx_checksum, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(scatter_gather, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(tx_pkt_desc_cnt, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(rx_std_desc_cnt, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
MODULE_PARM(rx_jumbo_desc_cnt, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
#endif
 | 
						|
#ifdef BCM_INT_COAL
 | 
						|
MODULE_PARM(adaptive_coalesce, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(rx_coalesce_ticks, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(rx_max_coalesce_frames, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(tx_coalesce_ticks, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(tx_max_coalesce_frames, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(stats_coalesce_ticks, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
#endif
 | 
						|
#ifdef BCM_WOL
 | 
						|
MODULE_PARM(enable_wol, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
#endif
 | 
						|
#ifdef BCM_TSO
 | 
						|
MODULE_PARM(enable_tso, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
#endif
 | 
						|
#ifdef BCM_NIC_SEND_BD
 | 
						|
MODULE_PARM(nic_tx_bd, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
#endif
 | 
						|
#ifdef BCM_ASF
 | 
						|
MODULE_PARM(vlan_tag_mode, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
#endif
 | 
						|
MODULE_PARM(delay_link, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
MODULE_PARM(disable_d3hot, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
 | 
						|
#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR)
 | 
						|
MODULE_PARM(disable_msi, "1-" __MODULE_STRING(MAX_UNITS) "i");
 | 
						|
#endif
 | 
						|
 | 
						|
#else /* parms*/
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x020605) && (LINUX_VERSION_CODE < 0x02060a)
 | 
						|
 | 
						|
static int var;
 | 
						|
 | 
						|
#define numvar var
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x2060a)
 | 
						|
 | 
						|
#define numvar NULL
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
module_param_array(line_speed, int, numvar, 0);
 | 
						|
module_param_array(auto_speed, int, numvar, 0);
 | 
						|
module_param_array(full_duplex, int, numvar, 0);
 | 
						|
module_param_array(rx_flow_control, int, numvar, 0);
 | 
						|
module_param_array(tx_flow_control, int, numvar, 0);
 | 
						|
module_param_array(auto_flow_control, int, numvar, 0);
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
module_param_array(mtu, int, numvar, 0);
 | 
						|
#endif
 | 
						|
module_param_array(tx_checksum, int, numvar, 0);
 | 
						|
module_param_array(rx_checksum, int, numvar, 0);
 | 
						|
module_param_array(scatter_gather, int, numvar, 0);
 | 
						|
module_param_array(tx_pkt_desc_cnt, int, numvar, 0);
 | 
						|
module_param_array(rx_std_desc_cnt, int, numvar, 0);
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
module_param_array(rx_jumbo_desc_cnt, int, numvar, 0);
 | 
						|
#endif
 | 
						|
#ifdef BCM_INT_COAL
 | 
						|
module_param_array(adaptive_coalesce, int, numvar, 0);
 | 
						|
module_param_array(rx_coalesce_ticks, int, numvar, 0);
 | 
						|
module_param_array(rx_max_coalesce_frames, int, numvar, 0);
 | 
						|
module_param_array(tx_coalesce_ticks, int, numvar, 0);
 | 
						|
module_param_array(tx_max_coalesce_frames, int, numvar, 0);
 | 
						|
module_param_array(stats_coalesce_ticks, int, numvar, 0);
 | 
						|
#endif
 | 
						|
#ifdef BCM_WOL
 | 
						|
module_param_array(enable_wol, int, numvar, 0);
 | 
						|
#endif
 | 
						|
#ifdef BCM_TSO
 | 
						|
module_param_array(enable_tso, int, numvar, 0);
 | 
						|
#endif
 | 
						|
#ifdef BCM_NIC_SEND_BD
 | 
						|
module_param_array(nic_tx_bd, int, numvar, 0);
 | 
						|
#endif
 | 
						|
#ifdef BCM_ASF
 | 
						|
module_param_array(vlan_tag_mode, int, numvar, 0);
 | 
						|
#endif
 | 
						|
module_param_array(delay_link, int, numvar, 0);
 | 
						|
module_param_array(disable_d3hot, int, numvar, 0);
 | 
						|
 | 
						|
#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR)
 | 
						|
module_param_array(disable_msi, int, numvar, 0);
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#endif /* params */
 | 
						|
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
#define RUN_AT(x) (jiffies + (x))
 | 
						|
 | 
						|
char kernel_version[] = UTS_RELEASE;
 | 
						|
 | 
						|
#define PCI_SUPPORT_VER2
 | 
						|
 | 
						|
#if !defined(CAP_NET_ADMIN)
 | 
						|
#define capable(CAP_XXX) (suser())
 | 
						|
#endif
 | 
						|
 | 
						|
#define tigon3_debug debug
 | 
						|
#if TIGON3_DEBUG
 | 
						|
static int tigon3_debug = TIGON3_DEBUG;
 | 
						|
#else
 | 
						|
static int tigon3_debug = 0;
 | 
						|
#endif
 | 
						|
static int msglevel = 0xdeadbeef;
 | 
						|
int b57_msg_level;
 | 
						|
 | 
						|
int bcm5700_open(struct net_device *dev);
 | 
						|
STATIC void bcm5700_timer(unsigned long data);
 | 
						|
STATIC void bcm5700_stats_timer(unsigned long data);
 | 
						|
STATIC void bcm5700_reset(struct net_device *dev);
 | 
						|
STATIC int bcm5700_start_xmit(struct sk_buff *skb, struct net_device *dev);
 | 
						|
STATIC irqreturn_t bcm5700_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 | 
						|
#ifdef BCM_TASKLET
 | 
						|
STATIC void bcm5700_tasklet(unsigned long data);
 | 
						|
#endif
 | 
						|
STATIC int bcm5700_close(struct net_device *dev);
 | 
						|
STATIC struct net_device_stats *bcm5700_get_stats(struct net_device *dev);
 | 
						|
STATIC int bcm5700_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 | 
						|
STATIC void bcm5700_do_rx_mode(struct net_device *dev);
 | 
						|
STATIC void bcm5700_set_rx_mode(struct net_device *dev);
 | 
						|
STATIC int bcm5700_set_mac_addr(struct net_device *dev, void *p);
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
STATIC int bcm5700_change_mtu(struct net_device *dev, int new_mtu);
 | 
						|
#endif
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
STATIC int bcm5700_poll(struct net_device *dev, int *budget);
 | 
						|
#endif
 | 
						|
STATIC int replenish_rx_buffers(PUM_DEVICE_BLOCK pUmDevice, int max);
 | 
						|
STATIC int bcm5700_freemem(struct net_device *dev);
 | 
						|
#ifdef BCM_INT_COAL
 | 
						|
#ifndef BCM_NAPI_RXPOLL
 | 
						|
STATIC int bcm5700_adapt_coalesce(PUM_DEVICE_BLOCK pUmDevice);
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
STATIC void bcm5700_set_vlan_mode(UM_DEVICE_BLOCK *pUmDevice);
 | 
						|
STATIC int bcm5700_init_counters(PUM_DEVICE_BLOCK pUmDevice);
 | 
						|
#ifdef BCM_VLAN
 | 
						|
STATIC void bcm5700_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp);
 | 
						|
STATIC void bcm5700_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid);
 | 
						|
#endif
 | 
						|
void bcm5700_shutdown(UM_DEVICE_BLOCK *pUmDevice);
 | 
						|
void bcm5700_free_remaining_rx_bufs(UM_DEVICE_BLOCK *pUmDevice);
 | 
						|
void bcm5700_validate_param_range(UM_DEVICE_BLOCK *pUmDevice, int *param,
 | 
						|
	char *param_name, int min, int max, int deflt);
 | 
						|
 | 
						|
static int bcm5700_notify_reboot(struct notifier_block *this, unsigned long event, void *unused);
 | 
						|
static struct notifier_block bcm5700_reboot_notifier = {
 | 
						|
	bcm5700_notify_reboot,
 | 
						|
	NULL,
 | 
						|
	0
 | 
						|
};
 | 
						|
 | 
						|
#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
 | 
						|
STATIC void poll_bcm5700(struct net_device *dev);
 | 
						|
#endif
 | 
						|
 | 
						|
/* A list of all installed bcm5700 devices. */
 | 
						|
static struct net_device *root_tigon3_dev = NULL;
 | 
						|
 | 
						|
#if defined(CONFIG_SPARC64) || defined(CONFIG_X86_64) ||defined(CONFIG_PPC64)
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
typedef enum {
 | 
						|
	BCM5700A6 = 0,
 | 
						|
	BCM5700T6,
 | 
						|
	BCM5700A9,
 | 
						|
	BCM5700T9,
 | 
						|
	BCM5700,
 | 
						|
	BCM5701A5,
 | 
						|
	BCM5701T1,
 | 
						|
	BCM5701T8,
 | 
						|
	BCM5701A7,
 | 
						|
	BCM5701A10,
 | 
						|
	BCM5701A12,
 | 
						|
	BCM5701,
 | 
						|
	BCM5702,
 | 
						|
	BCM5703,
 | 
						|
	BCM5703A31,
 | 
						|
	BCM5703ARBUCKLE,
 | 
						|
	TC996T,
 | 
						|
	TC996ST,
 | 
						|
	TC996SSX,
 | 
						|
	TC996SX,
 | 
						|
	TC996BT,
 | 
						|
	TC997T,
 | 
						|
	TC997SX,
 | 
						|
	TC1000T,
 | 
						|
	TC1000BT,
 | 
						|
	TC940BR01,
 | 
						|
	TC942BR01,
 | 
						|
	TC998T,
 | 
						|
	TC998SX,
 | 
						|
	TC999T,
 | 
						|
	NC6770,
 | 
						|
	NC1020,
 | 
						|
	NC150T,
 | 
						|
	NC7760,
 | 
						|
	NC7761,
 | 
						|
	NC7770,
 | 
						|
	NC7771,
 | 
						|
	NC7780,
 | 
						|
	NC7781,
 | 
						|
	NC7772,
 | 
						|
	NC7782,
 | 
						|
	NC7783,
 | 
						|
	NC320T,
 | 
						|
	NC320I,
 | 
						|
	NC325I,
 | 
						|
	NC324I,
 | 
						|
	NC326I,
 | 
						|
	BCM5704CIOBE,
 | 
						|
	BCM5704,
 | 
						|
	BCM5704S,
 | 
						|
	BCM5705,
 | 
						|
	BCM5705M,
 | 
						|
	BCM5705F,
 | 
						|
	BCM5901,
 | 
						|
	BCM5782,
 | 
						|
	BCM5788,
 | 
						|
	BCM5789,
 | 
						|
	BCM5750,
 | 
						|
	BCM5750M,
 | 
						|
	BCM5720,
 | 
						|
	BCM5751,
 | 
						|
	BCM5751M,
 | 
						|
	BCM5751F,
 | 
						|
	BCM5721,
 | 
						|
	BCM5753,
 | 
						|
	BCM5753M,
 | 
						|
	BCM5753F,
 | 
						|
	BCM5781,
 | 
						|
	BCM5752,
 | 
						|
	BCM5752M,
 | 
						|
	BCM5714,
 | 
						|
	BCM5780,
 | 
						|
	BCM5780S,
 | 
						|
	BCM5715,
 | 
						|
	BCM4785,
 | 
						|
	BCM5903M,
 | 
						|
	UNK5788
 | 
						|
} board_t;
 | 
						|
 | 
						|
 | 
						|
/* indexed by board_t, above */
 | 
						|
static struct {
 | 
						|
	char *name;
 | 
						|
} board_info[] __devinitdata = {
 | 
						|
	{ "Broadcom BCM5700 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5700 1000Base-SX" },
 | 
						|
	{ "Broadcom BCM5700 1000Base-SX" },
 | 
						|
	{ "Broadcom BCM5700 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5700" },
 | 
						|
	{ "Broadcom BCM5701 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5701 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5701 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5701 1000Base-SX" },
 | 
						|
	{ "Broadcom BCM5701 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5701 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5701" },
 | 
						|
	{ "Broadcom BCM5702 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5703 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5703 1000Base-SX" },
 | 
						|
	{ "Broadcom B5703 1000Base-SX" },
 | 
						|
	{ "3Com 3C996 10/100/1000 Server NIC" },
 | 
						|
	{ "3Com 3C996 10/100/1000 Server NIC" },
 | 
						|
	{ "3Com 3C996 Gigabit Fiber-SX Server NIC" },
 | 
						|
	{ "3Com 3C996 Gigabit Fiber-SX Server NIC" },
 | 
						|
	{ "3Com 3C996B Gigabit Server NIC" },
 | 
						|
	{ "3Com 3C997 Gigabit Server NIC" },
 | 
						|
	{ "3Com 3C997 Gigabit Fiber-SX Server NIC" },
 | 
						|
	{ "3Com 3C1000 Gigabit NIC" },
 | 
						|
	{ "3Com 3C1000B-T 10/100/1000 PCI" },
 | 
						|
	{ "3Com 3C940 Gigabit LOM (21X21)" },
 | 
						|
	{ "3Com 3C942 Gigabit LOM (31X31)" },
 | 
						|
	{ "3Com 3C998-T Dual Port 10/100/1000 PCI-X Server NIC" },
 | 
						|
	{ "3Com 3C998-SX Dual Port 1000-SX PCI-X Server NIC" },
 | 
						|
	{ "3Com 3C999-T Quad Port 10/100/1000 PCI-X Server NIC" },
 | 
						|
	{ "HP NC6770 Gigabit Server Adapter" },
 | 
						|
	{ "NC1020 HP ProLiant Gigabit Server Adapter 32 PCI" },
 | 
						|
	{ "HP ProLiant NC 150T PCI 4-port Gigabit Combo Switch Adapter" },
 | 
						|
	{ "HP NC7760 Gigabit Server Adapter" },
 | 
						|
	{ "HP NC7761 Gigabit Server Adapter" },
 | 
						|
	{ "HP NC7770 Gigabit Server Adapter" },
 | 
						|
	{ "HP NC7771 Gigabit Server Adapter" },
 | 
						|
	{ "HP NC7780 Gigabit Server Adapter" },
 | 
						|
	{ "HP NC7781 Gigabit Server Adapter" },
 | 
						|
	{ "HP NC7772 Gigabit Server Adapter" },
 | 
						|
	{ "HP NC7782 Gigabit Server Adapter" },
 | 
						|
	{ "HP NC7783 Gigabit Server Adapter" },
 | 
						|
	{ "HP ProLiant NC 320T PCI Express Gigabit Server Adapter" },
 | 
						|
	{ "HP ProLiant NC 320i PCI Express Gigabit Server Adapter" },
 | 
						|
	{ "HP NC325i Integrated Dual Port PCI Express Gigabit Server Adapter" },
 | 
						|
	{ "HP NC324i Integrated Dual Port PCI Express Gigabit Server Adapter" },
 | 
						|
	{ "HP NC326i Integrated Dual Port PCI Express Gigabit Server Adapter" },
 | 
						|
	{ "Broadcom BCM5704 CIOB-E 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5704 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5704 1000Base-SX" },
 | 
						|
	{ "Broadcom BCM5705 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5705M 1000Base-T" },
 | 
						|
	{ "Broadcom 570x 10/100 Integrated Controller" },
 | 
						|
	{ "Broadcom BCM5901 100Base-TX" },
 | 
						|
	{ "Broadcom NetXtreme Gigabit Ethernet for hp" },
 | 
						|
	{ "Broadcom BCM5788 NetLink 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5789 NetLink 1000Base-T PCI Express" },
 | 
						|
	{ "Broadcom BCM5750 1000Base-T PCI" },
 | 
						|
	{ "Broadcom BCM5750M 1000Base-T PCI" },
 | 
						|
	{ "Broadcom BCM5720 1000Base-T PCI" },
 | 
						|
	{ "Broadcom BCM5751 1000Base-T PCI Express" },
 | 
						|
	{ "Broadcom BCM5751M 1000Base-T PCI Express" },
 | 
						|
	{ "Broadcom BCM5751F 100Base-TX PCI Express" },
 | 
						|
	{ "Broadcom BCM5721 1000Base-T PCI Express" },
 | 
						|
	{ "Broadcom BCM5753 1000Base-T PCI Express" },
 | 
						|
	{ "Broadcom BCM5753M 1000Base-T PCI Express" },
 | 
						|
	{ "Broadcom BCM5753F 100Base-TX PCI Express" },
 | 
						|
	{ "Broadcom BCM5781 NetLink 1000Base-T PCI Express" },
 | 
						|
	{ "Broadcom BCM5752 1000Base-T PCI Express" },
 | 
						|
	{ "Broadcom BCM5752M 1000Base-T PCI Express" },
 | 
						|
	{ "Broadcom BCM5714 1000Base-T " },
 | 
						|
	{ "Broadcom BCM5780 1000Base-T" },
 | 
						|
	{ "Broadcom BCM5780S 1000Base-SX" },
 | 
						|
	{ "Broadcom BCM5715 1000Base-T " },
 | 
						|
	{ "Broadcom BCM4785 10/100/1000 Integrated Controller" },
 | 
						|
	{ "Broadcom BCM5903M Gigabit Ethernet " },
 | 
						|
	{ "Unknown BCM5788 Gigabit Ethernet " },
 | 
						|
	{ 0 }
 | 
						|
	};
 | 
						|
 | 
						|
static struct pci_device_id bcm5700_pci_tbl[] __devinitdata = {
 | 
						|
	{0x14e4, 0x1644, 0x14e4, 0x1644, 0, 0, BCM5700A6 },
 | 
						|
	{0x14e4, 0x1644, 0x14e4, 0x2, 0, 0, BCM5700T6 },
 | 
						|
	{0x14e4, 0x1644, 0x14e4, 0x3, 0, 0, BCM5700A9 },
 | 
						|
	{0x14e4, 0x1644, 0x14e4, 0x4, 0, 0, BCM5700T9 },
 | 
						|
	{0x14e4, 0x1644, 0x1028, 0xd1, 0, 0, BCM5700 },
 | 
						|
	{0x14e4, 0x1644, 0x1028, 0x0106, 0, 0, BCM5700 },
 | 
						|
	{0x14e4, 0x1644, 0x1028, 0x0109, 0, 0, BCM5700 },
 | 
						|
	{0x14e4, 0x1644, 0x1028, 0x010a, 0, 0, BCM5700 },
 | 
						|
	{0x14e4, 0x1644, 0x10b7, 0x1000, 0, 0, TC996T },
 | 
						|
	{0x14e4, 0x1644, 0x10b7, 0x1001, 0, 0, TC996ST },
 | 
						|
	{0x14e4, 0x1644, 0x10b7, 0x1002, 0, 0, TC996SSX },
 | 
						|
	{0x14e4, 0x1644, 0x10b7, 0x1003, 0, 0, TC997T },
 | 
						|
	{0x14e4, 0x1644, 0x10b7, 0x1005, 0, 0, TC997SX },
 | 
						|
	{0x14e4, 0x1644, 0x10b7, 0x1008, 0, 0, TC942BR01 },
 | 
						|
	{0x14e4, 0x1644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5700 },
 | 
						|
	{0x14e4, 0x1645, 0x14e4, 1, 0, 0, BCM5701A5 },
 | 
						|
	{0x14e4, 0x1645, 0x14e4, 5, 0, 0, BCM5701T1 },
 | 
						|
	{0x14e4, 0x1645, 0x14e4, 6, 0, 0, BCM5701T8 },
 | 
						|
	{0x14e4, 0x1645, 0x14e4, 7, 0, 0, BCM5701A7 },
 | 
						|
	{0x14e4, 0x1645, 0x14e4, 8, 0, 0, BCM5701A10 },
 | 
						|
	{0x14e4, 0x1645, 0x14e4, 0x8008, 0, 0, BCM5701A12 },
 | 
						|
	{0x14e4, 0x1645, 0x0e11, 0xc1, 0, 0, NC6770 },
 | 
						|
	{0x14e4, 0x1645, 0x0e11, 0x7c, 0, 0, NC7770 },
 | 
						|
	{0x14e4, 0x1645, 0x0e11, 0x85, 0, 0, NC7780 },
 | 
						|
	{0x14e4, 0x1645, 0x1028, 0x0121, 0, 0, BCM5701 },
 | 
						|
	{0x14e4, 0x1645, 0x10b7, 0x1004, 0, 0, TC996SX },
 | 
						|
	{0x14e4, 0x1645, 0x10b7, 0x1006, 0, 0, TC996BT },
 | 
						|
	{0x14e4, 0x1645, 0x10b7, 0x1007, 0, 0, TC1000T },
 | 
						|
	{0x14e4, 0x1645, 0x10b7, 0x1008, 0, 0, TC940BR01 },
 | 
						|
	{0x14e4, 0x1645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5701 },
 | 
						|
	{0x14e4, 0x1646, 0x14e4, 0x8009, 0, 0, BCM5702 },
 | 
						|
	{0x14e4, 0x1646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 },
 | 
						|
	{0x14e4, 0x16a6, 0x14e4, 0x8009, 0, 0, BCM5702 },
 | 
						|
	{0x14e4, 0x16a6, 0x14e4, 0x000c, 0, 0, BCM5702 },
 | 
						|
	{0x14e4, 0x16a6, 0x0e11, 0xbb, 0, 0, NC7760 },
 | 
						|
	{0x14e4, 0x16a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 },
 | 
						|
	{0x14e4, 0x16c6, 0x10b7, 0x1100, 0, 0, TC1000BT },
 | 
						|
	{0x14e4, 0x16c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 },
 | 
						|
	{0x14e4, 0x1647, 0x14e4, 0x0009, 0, 0, BCM5703 },
 | 
						|
	{0x14e4, 0x1647, 0x14e4, 0x000a, 0, 0, BCM5703A31 },
 | 
						|
	{0x14e4, 0x1647, 0x14e4, 0x000b, 0, 0, BCM5703 },
 | 
						|
	{0x14e4, 0x1647, 0x14e4, 0x800a, 0, 0, BCM5703 },
 | 
						|
	{0x14e4, 0x1647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 },
 | 
						|
	{0x14e4, 0x16a7, 0x14e4, 0x0009, 0, 0, BCM5703 },
 | 
						|
	{0x14e4, 0x16a7, 0x14e4, 0x000a, 0, 0, BCM5703A31 },
 | 
						|
	{0x14e4, 0x16a7, 0x14e4, 0x000b, 0, 0, BCM5703 },
 | 
						|
	{0x14e4, 0x16a7, 0x14e4, 0x800a, 0, 0, BCM5703 },
 | 
						|
	{0x14e4, 0x16a7, 0x0e11, 0xca, 0, 0, NC7771 },
 | 
						|
	{0x14e4, 0x16a7, 0x0e11, 0xcb, 0, 0, NC7781 },
 | 
						|
	{0x14e4, 0x16a7, 0x1014, 0x0281, 0, 0, BCM5703ARBUCKLE },
 | 
						|
	{0x14e4, 0x16a7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 },
 | 
						|
	{0x14e4, 0x16c7, 0x14e4, 0x000a, 0, 0, BCM5703A31 },
 | 
						|
	{0x14e4, 0x16c7, 0x0e11, 0xca, 0, 0, NC7771 },
 | 
						|
	{0x14e4, 0x16c7, 0x0e11, 0xcb, 0, 0, NC7781 },
 | 
						|
	{0x14e4, 0x16c7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 },
 | 
						|
	{0x14e4, 0x1648, 0x0e11, 0xcf, 0, 0, NC7772 },
 | 
						|
	{0x14e4, 0x1648, 0x0e11, 0xd0, 0, 0, NC7782 },
 | 
						|
	{0x14e4, 0x1648, 0x0e11, 0xd1, 0, 0, NC7783 },
 | 
						|
	{0x14e4, 0x1648, 0x10b7, 0x2000, 0, 0, TC998T },
 | 
						|
	{0x14e4, 0x1648, 0x10b7, 0x3000, 0, 0, TC999T },
 | 
						|
	{0x14e4, 0x1648, 0x1166, 0x1648, 0, 0, BCM5704CIOBE },
 | 
						|
	{0x14e4, 0x1648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5704 },
 | 
						|
	{0x14e4, 0x1649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5704S },
 | 
						|
	{0x14e4, 0x16a8, 0x14e4, 0x16a8, 0, 0, BCM5704S },
 | 
						|
	{0x14e4, 0x16a8, 0x10b7, 0x2001, 0, 0, TC998SX },
 | 
						|
	{0x14e4, 0x16a8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5704S },
 | 
						|
	{0x14e4, 0x1653, 0x0e11, 0x00e3, 0, 0, NC7761 },
 | 
						|
	{0x14e4, 0x1653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705 },
 | 
						|
	{0x14e4, 0x1654, 0x0e11, 0x00e3, 0, 0, NC7761 },
 | 
						|
	{0x14e4, 0x1654, 0x103c, 0x3100, 0, 0, NC1020 },
 | 
						|
	{0x14e4, 0x1654, 0x103c, 0x3226, 0, 0, NC150T },
 | 
						|
	{0x14e4, 0x1654, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705 },
 | 
						|
	{0x14e4, 0x165d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705M },
 | 
						|
	{0x14e4, 0x165e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705M },
 | 
						|
	{0x14e4, 0x166e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705F },
 | 
						|
	{0x14e4, 0x1696, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5782 },
 | 
						|
	{0x14e4, 0x169c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5788 },
 | 
						|
	{0x14e4, 0x169d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5789 },
 | 
						|
	{0x14e4, 0x170d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5901 },
 | 
						|
	{0x14e4, 0x170e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5901 },
 | 
						|
	{0x14e4, 0x1676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5750 },
 | 
						|
	{0x14e4, 0x167c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5750M },
 | 
						|
	{0x14e4, 0x1677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5751 },
 | 
						|
	{0x14e4, 0x167d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5751M },
 | 
						|
	{0x14e4, 0x167e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5751F },
 | 
						|
	{0x14e4, 0x1658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5720 },
 | 
						|
	{0x14e4, 0x1659, 0x103c, 0x7031, 0, 0, NC320T },
 | 
						|
	{0x14e4, 0x1659, 0x103c, 0x7032, 0, 0, NC320T },
 | 
						|
	{0x14e4, 0x166a, 0x103c, 0x7035, 0, 0, NC325I },
 | 
						|
	{0x14e4, 0x166b, 0x103c, 0x7036, 0, 0, NC325I },
 | 
						|
	{0x14e4, 0x1668, 0x103c, 0x7039, 0, 0, NC324I },
 | 
						|
	{0x14e4, 0x1669, 0x103c, 0x703a, 0, 0, NC324I },
 | 
						|
	{0x14e4, 0x1678, 0x103c, 0x703e, 0, 0, NC326I },
 | 
						|
	{0x14e4, 0x1679, 0x103c, 0x703c, 0, 0, NC326I },
 | 
						|
	{0x14e4, 0x1659, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5721 },
 | 
						|
	{0x14e4, 0x16f7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5753 },
 | 
						|
	{0x14e4, 0x16fd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5753M },
 | 
						|
	{0x14e4, 0x16fe, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5753F },
 | 
						|
	{0x14e4, 0x16dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5781 },
 | 
						|
	{0x14e4, 0x1600, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5752 },
 | 
						|
	{0x14e4, 0x1601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5752M },
 | 
						|
	{0x14e4, 0x1668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5714 },
 | 
						|
	{0x14e4, 0x166a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5780 },
 | 
						|
	{0x14e4, 0x166b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5780S },
 | 
						|
	{0x14e4, 0x1678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5715 },
 | 
						|
	{0x14e4, 0x471f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM4785 },
 | 
						|
	{0x14e4, 0x16ff, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5903M },
 | 
						|
	{0x173b, 0x03ed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, UNK5788 },
 | 
						|
	{0,}
 | 
						|
	};
 | 
						|
 | 
						|
MODULE_DEVICE_TABLE(pci, bcm5700_pci_tbl);
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x2060a)
 | 
						|
	static struct pci_device_id pci_AMD762id[]={
 | 
						|
		{ PCI_DEVICE(PCI_VENDOR_ID_AMD,
 | 
						|
			PCI_DEVICE_ID_AMD_FE_GATE_700C) },
 | 
						|
		{ }
 | 
						|
	};
 | 
						|
#endif
 | 
						|
 | 
						|
static int sbgige = -1;
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
 *******************************************************************************
 | 
						|
*/
 | 
						|
 | 
						|
int get_csum_flag(LM_UINT32 ChipRevId)
 | 
						|
{
 | 
						|
        return NETIF_F_IP_CSUM;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
 *******************************************************************************
 | 
						|
 | 
						|
   This function returns true if the device passed to it is attached to an
 | 
						|
   ICH-ICH4. If the chip is not attached to an ICH, or is attached to an ICH5
 | 
						|
   or newer, it returns false.
 | 
						|
 | 
						|
   This function determines which bridge it is attached to by scaning the pci
 | 
						|
   bus looking for bridge chips (hdr_type=1). When a bridge chip is detected,
 | 
						|
   the bridge's subordinate's secondary bus number is compared with this
 | 
						|
   devices bus number. If they match, then the device is attached to this
 | 
						|
   bridge. The bridge's device id is compared to a list of known device ids for
 | 
						|
   ICH-ICH4. Since many older ICH's (ICH2-ICH7) share the same device id, the
 | 
						|
   chip revision must also be checked to determine if the chip is older than an
 | 
						|
   ICH5.
 | 
						|
 | 
						|
   To scan the bus, one of two functions is used depending on the kernel
 | 
						|
   version. For 2.4 kernels, the pci_find_device function is used. This
 | 
						|
   function has been depricated in the 2.6 kernel and replaced with the
 | 
						|
   fucntion pci_get_device. The macro walk_pci_bus determines which function to
 | 
						|
   use when the driver is built.
 | 
						|
*/
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x2060a)
 | 
						|
#define walk_pci_bus(d)		while ((d = pci_get_device( \
 | 
						|
					PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
 | 
						|
 | 
						|
#define unwalk_pci_bus(d)	pci_dev_put(d)
 | 
						|
 | 
						|
#else
 | 
						|
#define walk_pci_bus(d)		while ((d = pci_find_device( \
 | 
						|
					PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
 | 
						|
#define unwalk_pci_bus(d)
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
#define ICH5_CHIP_VERSION	0xc0
 | 
						|
 | 
						|
static struct pci_device_id pci_ICHtable[] = {
 | 
						|
	{0x8086, 0x2418}, /* PCI_DEVICE_ID_INTEL_82801AA_8  */
 | 
						|
	{0x8086, 0x2428}, /* PCI_DEVICE_ID_INTEL_82801AB_8  */
 | 
						|
	{0x8086, 0x244e}, /* PCI_DEVICE_ID_INTEL_82801BA_6  */
 | 
						|
	{0x8086, 0x2448}, /* PCI_DEVICE_ID_INTEL_82801BA_11 */
 | 
						|
	{0, 0}
 | 
						|
};
 | 
						|
 | 
						|
int attached_to_ICH4_or_older( struct pci_dev *pdev)
 | 
						|
{
 | 
						|
	struct pci_dev *tmp_pdev = NULL;
 | 
						|
	struct pci_device_id *ich_table;
 | 
						|
	u8 chip_rev;
 | 
						|
 | 
						|
	walk_pci_bus (tmp_pdev) {
 | 
						|
		if ((tmp_pdev->hdr_type == 1) &&
 | 
						|
		   (tmp_pdev->subordinate != NULL) &&
 | 
						|
		   (tmp_pdev->subordinate->secondary == pdev->bus->number)) {
 | 
						|
 | 
						|
			ich_table = pci_ICHtable;
 | 
						|
 | 
						|
			while (ich_table->vendor) {
 | 
						|
				if ((ich_table->vendor == tmp_pdev->vendor) &&
 | 
						|
				    (ich_table->device == tmp_pdev->device)) {
 | 
						|
 | 
						|
					pci_read_config_byte( tmp_pdev,
 | 
						|
						PCI_REVISION_ID, &chip_rev);
 | 
						|
 | 
						|
					if (chip_rev < ICH5_CHIP_VERSION) {
 | 
						|
						unwalk_pci_bus( tmp_pdev);
 | 
						|
						return 1;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				ich_table++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void robo_set_power_mode(void *h)
 | 
						|
{
 | 
						|
	//int status = 0;
 | 
						|
	int i;
 | 
						|
	//uint8 mode8;
 | 
						|
	//uint16 mode16;
 | 
						|
	uint32 flags = 0, temp32 = 0,val32 = 0, savephyaddr = 0;
 | 
						|
	PUM_DEVICE_BLOCK pudev = (PUM_DEVICE_BLOCK)h;
 | 
						|
	PLM_DEVICE_BLOCK pdev = &pudev->lm_dev;
 | 
						|
 | 
						|
	/*Brcm,Alex,2006.7.20. Adding Phy power mode setting*/
 | 
						|
	BCM5700_PHY_LOCK(pudev, flags);
 | 
						|
	savephyaddr = pdev->PhyAddr;
 | 
						|
 | 
						|
	for(i = 0; i < 8; i++)
 | 
						|
	{
 | 
						|
		pdev->PhyAddr = i;
 | 
						|
		temp32 = 0x2007;
 | 
						|
		LM_WritePhy(pdev, 0x18, temp32);
 | 
						|
		LM_ReadPhy(pdev, 0x18, &val32);
 | 
						|
//		printk(KERN_DEBUG "Alex: port = %x, read value =%x\n",i, val32);
 | 
						|
		temp32 = 0xc042;
 | 
						|
		LM_WritePhy(pdev, 0x18, temp32);
 | 
						|
		/*Read back*/
 | 
						|
		temp32 = 0x2007;
 | 
						|
		val32 = 0;
 | 
						|
		LM_WritePhy(pdev, 0x18, temp32);
 | 
						|
		LM_ReadPhy(pdev, 0x18, &val32);
 | 
						|
//		printk(KERN_ERR "Alex: read back value =%x\n",val32);
 | 
						|
	}
 | 
						|
 | 
						|
	pdev->PhyAddr = savephyaddr;
 | 
						|
	BCM5700_PHY_UNLOCK(pudev, flags);
 | 
						|
 | 
						|
	/*end of Brcm,Alex,2006.7.20. Adding Phy power mode setting*/
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
__devinit bcm5700_init_board(struct pci_dev *pdev, struct net_device **dev_out, int board_idx)
 | 
						|
{
 | 
						|
	struct net_device *dev;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice;
 | 
						|
	PLM_DEVICE_BLOCK pDevice;
 | 
						|
	bool rgmii = FALSE;
 | 
						|
	sb_t *sbh = NULL;
 | 
						|
	int rc;
 | 
						|
 | 
						|
	*dev_out = NULL;
 | 
						|
 | 
						|
	/* dev zeroed in init_etherdev */
 | 
						|
#if (LINUX_VERSION_CODE >= 0x20600)
 | 
						|
	dev = alloc_etherdev(sizeof(*pUmDevice));
 | 
						|
#else
 | 
						|
	dev = init_etherdev(NULL, sizeof(*pUmDevice));
 | 
						|
#endif
 | 
						|
	if (dev == NULL) {
 | 
						|
		printk(KERN_ERR "%s: unable to alloc new ethernet\n", bcm5700_driver);
 | 
						|
		return -ENOMEM;
 | 
						|
	}
 | 
						|
	SET_MODULE_OWNER(dev);
 | 
						|
#if (LINUX_VERSION_CODE >= 0x20600)
 | 
						|
	SET_NETDEV_DEV(dev, &pdev->dev);
 | 
						|
#endif
 | 
						|
	pUmDevice = (PUM_DEVICE_BLOCK) dev->priv;
 | 
						|
 | 
						|
	/* enable device (incl. PCI PM wakeup), and bus-mastering */
 | 
						|
	rc = pci_enable_device(pdev);
 | 
						|
	if (rc)
 | 
						|
		goto err_out;
 | 
						|
 | 
						|
	/* init core specific stuff */
 | 
						|
	if (pdev->device == T3_PCI_DEVICE_ID(T3_PCI_ID_BCM471F)) {
 | 
						|
		sbh = sb_kattach(SB_OSH);
 | 
						|
		sb_gige_init(sbh, ++sbgige, &rgmii);
 | 
						|
	}
 | 
						|
 | 
						|
	rc = pci_request_regions(pdev, bcm5700_driver);
 | 
						|
	if (rc) {
 | 
						|
		if (!sbh)
 | 
						|
			goto err_out;
 | 
						|
		printk(KERN_INFO "bcm5700_init_board: pci_request_regions returned error %d\n"
 | 
						|
				 "This may be because the region is already requested by"
 | 
						|
				 " the SMBus driver. Ignore the PCI error messages.\n", rc);
 | 
						|
	}
 | 
						|
 | 
						|
	pci_set_master(pdev);
 | 
						|
 | 
						|
	if (pci_set_dma_mask(pdev, BCM_64BIT_DMA_MASK) == 0) {
 | 
						|
		pUmDevice->using_dac = 1;
 | 
						|
		if (pci_set_consistent_dma_mask(pdev, BCM_64BIT_DMA_MASK) != 0) {
 | 
						|
			printk(KERN_ERR "pci_set_consistent_dma_mask failed\n");
 | 
						|
			pci_release_regions(pdev);
 | 
						|
			goto err_out;
 | 
						|
		}
 | 
						|
	} else if (pci_set_dma_mask(pdev, BCM_32BIT_DMA_MASK) == 0) {
 | 
						|
		pUmDevice->using_dac = 0;
 | 
						|
	} else {
 | 
						|
		printk(KERN_ERR "System does not support DMA\n");
 | 
						|
		pci_release_regions(pdev);
 | 
						|
		goto err_out;
 | 
						|
	}
 | 
						|
 | 
						|
	pUmDevice->dev = dev;
 | 
						|
	pUmDevice->pdev = pdev;
 | 
						|
	pUmDevice->mem_list_num = 0;
 | 
						|
	pUmDevice->next_module = root_tigon3_dev;
 | 
						|
	pUmDevice->index = board_idx;
 | 
						|
	pUmDevice->sbh = (void *)sbh;
 | 
						|
	root_tigon3_dev = dev;
 | 
						|
 | 
						|
	spin_lock_init(&pUmDevice->global_lock);
 | 
						|
 | 
						|
	spin_lock_init(&pUmDevice->undi_lock);
 | 
						|
 | 
						|
	spin_lock_init(&pUmDevice->phy_lock);
 | 
						|
 | 
						|
	pDevice = &pUmDevice->lm_dev;
 | 
						|
	pDevice->Flags = 0;
 | 
						|
	pDevice->FunctNum = PCI_FUNC(pUmDevice->pdev->devfn);
 | 
						|
	pUmDevice->boardflags = getintvar(NULL, "boardflags");
 | 
						|
	if (sbh) {
 | 
						|
		if (pUmDevice->boardflags & BFL_ENETROBO)
 | 
						|
			pDevice->Flags |= ROBO_SWITCH_FLAG;
 | 
						|
		pDevice->Flags |= rgmii ? RGMII_MODE_FLAG : 0;
 | 
						|
		if (sb_chip(sbh) == BCM4785_CHIP_ID && sb_chiprev(sbh) < 2)
 | 
						|
			pDevice->Flags |= ONE_DMA_AT_ONCE_FLAG;
 | 
						|
		pDevice->Flags |= SB_CORE_FLAG;
 | 
						|
		if (sb_chip(sbh) == BCM4785_CHIP_ID)
 | 
						|
			pDevice->Flags |= FLUSH_POSTED_WRITE_FLAG;
 | 
						|
	}
 | 
						|
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
	if (board_idx < MAX_UNITS) {
 | 
						|
		bcm5700_validate_param_range(pUmDevice, &mtu[board_idx], "mtu", 1500, 9000, 1500);
 | 
						|
		dev->mtu = mtu[board_idx];
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	if (attached_to_ICH4_or_older(pdev)) {
 | 
						|
		pDevice->Flags |= UNDI_FIX_FLAG;
 | 
						|
	}
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x2060a)
 | 
						|
	if (pci_dev_present(pci_AMD762id)) {
 | 
						|
		pDevice->Flags |= FLUSH_POSTED_WRITE_FLAG;
 | 
						|
		pDevice->Flags &= ~NIC_SEND_BD_FLAG;
 | 
						|
	}
 | 
						|
#else
 | 
						|
	if (pci_find_device(0x1022, 0x700c, NULL)) {
 | 
						|
		/* AMD762 writes I/O out of order */
 | 
						|
		/* Setting bit 1 in 762's register 0x4C still doesn't work */
 | 
						|
		/* in all cases */
 | 
						|
		pDevice->Flags |= FLUSH_POSTED_WRITE_FLAG;
 | 
						|
		pDevice->Flags &= ~NIC_SEND_BD_FLAG;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	if (LM_GetAdapterInfo(pDevice) != LM_STATUS_SUCCESS) {
 | 
						|
		rc = -ENODEV;
 | 
						|
		goto err_out_unmap;
 | 
						|
	}
 | 
						|
 | 
						|
	if (pDevice->Flags & ROBO_SWITCH_FLAG) {
 | 
						|
		robo_info_t	*robo;
 | 
						|
 | 
						|
		if ((robo = bcm_robo_attach(sbh, pDevice, dev->name, NULL,
 | 
						|
		                            robo_miird, robo_miiwr)) == NULL) {
 | 
						|
			B57_ERR(("robo_setup: failed to attach robo switch \n"));
 | 
						|
			goto robo_fail;
 | 
						|
		}
 | 
						|
 | 
						|
		if (bcm_robo_enable_device(robo)) {
 | 
						|
			B57_ERR(("robo_setup: failed to enable robo switch \n"));
 | 
						|
robo_fail:
 | 
						|
			bcm_robo_detach(robo);
 | 
						|
			rc = -ENODEV;
 | 
						|
			goto err_out_unmap;
 | 
						|
		}
 | 
						|
 | 
						|
		/* 5397 power mode setting */
 | 
						|
		robo_set_power_mode(robo->h);
 | 
						|
 | 
						|
		pUmDevice->robo = (void *)robo;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((pDevice->Flags & JUMBO_CAPABLE_FLAG) == 0) {
 | 
						|
		if (dev->mtu > 1500) {
 | 
						|
			dev->mtu = 1500;
 | 
						|
			printk(KERN_WARNING
 | 
						|
			       "%s-%d: Jumbo mtu sizes not supported, using mtu=1500\n",
 | 
						|
			       bcm5700_driver, pUmDevice->index);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	pUmDevice->do_global_lock = 0;
 | 
						|
	if (T3_ASIC_REV(pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) {
 | 
						|
		/* The 5700 chip works best without interleaved register */
 | 
						|
		/* accesses on certain machines. */
 | 
						|
		pUmDevice->do_global_lock = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((T3_ASIC_REV(pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5701) &&
 | 
						|
		((pDevice->PciState & T3_PCI_STATE_NOT_PCI_X_BUS) == 0)) {
 | 
						|
 | 
						|
		pUmDevice->rx_buf_align = 0;
 | 
						|
	} else {
 | 
						|
		pUmDevice->rx_buf_align = 2;
 | 
						|
	}
 | 
						|
	dev->mem_start = pci_resource_start(pdev, 0);
 | 
						|
	dev->mem_end = dev->mem_start + sizeof(T3_STD_MEM_MAP);
 | 
						|
	dev->irq = pdev->irq;
 | 
						|
 | 
						|
	*dev_out = dev;
 | 
						|
	return 0;
 | 
						|
 | 
						|
err_out_unmap:
 | 
						|
	pci_release_regions(pdev);
 | 
						|
	bcm5700_freemem(dev);
 | 
						|
 | 
						|
err_out:
 | 
						|
#if (LINUX_VERSION_CODE < 0x020600)
 | 
						|
	unregister_netdev(dev);
 | 
						|
	kfree(dev);
 | 
						|
#else
 | 
						|
	free_netdev(dev);
 | 
						|
#endif
 | 
						|
	return rc;
 | 
						|
}
 | 
						|
 | 
						|
static int __devinit
 | 
						|
bcm5700_print_ver(void)
 | 
						|
{
 | 
						|
	printk(KERN_INFO "Broadcom Gigabit Ethernet Driver %s ",
 | 
						|
		bcm5700_driver);
 | 
						|
	printk("ver. %s %s\n", bcm5700_version, bcm5700_date);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int __devinit
 | 
						|
bcm5700_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 | 
						|
{
 | 
						|
	struct net_device *dev = NULL;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice;
 | 
						|
	PLM_DEVICE_BLOCK pDevice;
 | 
						|
	int i;
 | 
						|
	static int board_idx = -1;
 | 
						|
	static int printed_version = 0;
 | 
						|
	struct pci_dev *pci_dev;
 | 
						|
 | 
						|
	board_idx++;
 | 
						|
 | 
						|
	if (!printed_version) {
 | 
						|
		bcm5700_print_ver();
 | 
						|
		printed_version = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	i = bcm5700_init_board(pdev, &dev, board_idx);
 | 
						|
	if (i < 0) {
 | 
						|
		return i;
 | 
						|
	}
 | 
						|
 | 
						|
	if (dev == NULL)
 | 
						|
		return -ENOMEM;
 | 
						|
 | 
						|
#ifdef BCM_IOCTL32
 | 
						|
	if (atomic_read(&bcm5700_load_count) == 0) {
 | 
						|
		register_ioctl32_conversion(SIOCNICE, bcm5700_ioctl32);
 | 
						|
	}
 | 
						|
	atomic_inc(&bcm5700_load_count);
 | 
						|
#endif
 | 
						|
	dev->open = bcm5700_open;
 | 
						|
	dev->hard_start_xmit = bcm5700_start_xmit;
 | 
						|
	dev->stop = bcm5700_close;
 | 
						|
	dev->get_stats = bcm5700_get_stats;
 | 
						|
	dev->set_multicast_list = bcm5700_set_rx_mode;
 | 
						|
	dev->do_ioctl = bcm5700_ioctl;
 | 
						|
	dev->set_mac_address = &bcm5700_set_mac_addr;
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
	dev->change_mtu = &bcm5700_change_mtu;
 | 
						|
#endif
 | 
						|
#if (LINUX_VERSION_CODE >= 0x20400)
 | 
						|
	dev->tx_timeout = bcm5700_reset;
 | 
						|
	dev->watchdog_timeo = TX_TIMEOUT;
 | 
						|
#endif
 | 
						|
#ifdef BCM_VLAN
 | 
						|
	dev->vlan_rx_register = &bcm5700_vlan_rx_register;
 | 
						|
	dev->vlan_rx_kill_vid = &bcm5700_vlan_rx_kill_vid;
 | 
						|
#endif
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
	dev->poll = bcm5700_poll;
 | 
						|
	dev->weight = 64;
 | 
						|
#endif
 | 
						|
 | 
						|
	pUmDevice = (PUM_DEVICE_BLOCK) dev->priv;
 | 
						|
	pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
 | 
						|
	dev->base_addr = pci_resource_start(pdev, 0);
 | 
						|
	dev->irq = pdev->irq;
 | 
						|
#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
 | 
						|
	dev->poll_controller = poll_bcm5700;
 | 
						|
#endif
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x20600)
 | 
						|
	if ((i = register_netdev(dev))) {
 | 
						|
		printk(KERN_ERR "%s: Cannot register net device\n",
 | 
						|
			bcm5700_driver);
 | 
						|
		if (pUmDevice->lm_dev.pMappedMemBase)
 | 
						|
			iounmap(pUmDevice->lm_dev.pMappedMemBase);
 | 
						|
		pci_release_regions(pdev);
 | 
						|
		bcm5700_freemem(dev);
 | 
						|
		free_netdev(dev);
 | 
						|
		return i;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
	pci_set_drvdata(pdev, dev);
 | 
						|
 | 
						|
	memcpy(dev->dev_addr, pDevice->NodeAddress, 6);
 | 
						|
	pUmDevice->name = board_info[ent->driver_data].name,
 | 
						|
	printk(KERN_INFO "%s: %s found at mem %lx, IRQ %d, ",
 | 
						|
		dev->name, pUmDevice->name, dev->base_addr,
 | 
						|
		dev->irq);
 | 
						|
	printk("node addr ");
 | 
						|
	for (i = 0; i < 6; i++) {
 | 
						|
		printk("%2.2x", dev->dev_addr[i]);
 | 
						|
	}
 | 
						|
	printk("\n");
 | 
						|
 | 
						|
	printk(KERN_INFO "%s: ", dev->name);
 | 
						|
	if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5400_PHY_ID)
 | 
						|
		printk("Broadcom BCM5400 Copper ");
 | 
						|
	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID)
 | 
						|
		printk("Broadcom BCM5401 Copper ");
 | 
						|
	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5411_PHY_ID)
 | 
						|
		printk("Broadcom BCM5411 Copper ");
 | 
						|
	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5461_PHY_ID)
 | 
						|
		printk("Broadcom BCM5461 Copper ");
 | 
						|
	else if (((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5701_PHY_ID) &&
 | 
						|
		!(pDevice->TbiFlags & ENABLE_TBI_FLAG)) {
 | 
						|
		printk("Broadcom BCM5701 Integrated Copper ");
 | 
						|
	}
 | 
						|
	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5703_PHY_ID) {
 | 
						|
		printk("Broadcom BCM5703 Integrated ");
 | 
						|
		if (pDevice->TbiFlags & ENABLE_TBI_FLAG)
 | 
						|
			printk("SerDes ");
 | 
						|
		else
 | 
						|
			printk("Copper ");
 | 
						|
	}
 | 
						|
	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5704_PHY_ID) {
 | 
						|
		printk("Broadcom BCM5704 Integrated ");
 | 
						|
		if (pDevice->TbiFlags & ENABLE_TBI_FLAG)
 | 
						|
			printk("SerDes ");
 | 
						|
		else
 | 
						|
			printk("Copper ");
 | 
						|
	}
 | 
						|
        else if (pDevice->PhyFlags & PHY_IS_FIBER){
 | 
						|
            if(( pDevice->PhyId & PHY_ID_MASK ) == PHY_BCM5780_PHY_ID)
 | 
						|
                printk("Broadcom BCM5780S Integrated Serdes ");
 | 
						|
 | 
						|
        }        
 | 
						|
	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5705_PHY_ID)
 | 
						|
		printk("Broadcom BCM5705 Integrated Copper ");
 | 
						|
	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5750_PHY_ID)
 | 
						|
		printk("Broadcom BCM5750 Integrated Copper ");
 | 
						|
 | 
						|
        else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5714_PHY_ID)
 | 
						|
                printk("Broadcom BCM5714 Integrated Copper ");
 | 
						|
        else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5780_PHY_ID)
 | 
						|
                printk("Broadcom BCM5780 Integrated Copper ");
 | 
						|
 | 
						|
	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5752_PHY_ID)
 | 
						|
		printk("Broadcom BCM5752 Integrated Copper ");
 | 
						|
	else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM8002_PHY_ID)
 | 
						|
		printk("Broadcom BCM8002 SerDes ");
 | 
						|
	else if (pDevice->TbiFlags & ENABLE_TBI_FLAG) {
 | 
						|
		if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) {
 | 
						|
			printk("Broadcom BCM5703 Integrated SerDes ");
 | 
						|
		}
 | 
						|
		else if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) {
 | 
						|
			printk("Broadcom BCM5704 Integrated SerDes ");
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			printk("Agilent HDMP-1636 SerDes ");
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		printk("Unknown ");
 | 
						|
	}
 | 
						|
	printk("transceiver found\n");
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x20400)
 | 
						|
	if (scatter_gather[board_idx]) {
 | 
						|
		dev->features |= NETIF_F_SG;
 | 
						|
		if (pUmDevice->using_dac && !(pDevice->Flags & BCM5788_FLAG))
 | 
						|
			dev->features |= NETIF_F_HIGHDMA;
 | 
						|
	}
 | 
						|
	if ((pDevice->TaskOffloadCap & LM_TASK_OFFLOAD_TX_TCP_CHECKSUM) &&
 | 
						|
		tx_checksum[board_idx]) {
 | 
						|
 | 
						|
		dev->features |= get_csum_flag( pDevice->ChipRevId);
 | 
						|
	}
 | 
						|
#ifdef BCM_VLAN
 | 
						|
	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 | 
						|
#endif
 | 
						|
#ifdef BCM_TSO
 | 
						|
	/* On 5714/15/80 chips, Jumbo Frames and TSO cannot both be enabled at
 | 
						|
	   the same time. Since only one of these features can be enable at a
 | 
						|
           time, we'll enable only Jumbo Frames and disable TSO when the user
 | 
						|
	   tries to enable both.
 | 
						|
	*/
 | 
						|
	dev->features &= ~NETIF_F_TSO;
 | 
						|
 | 
						|
	if ((pDevice->TaskToOffload & LM_TASK_OFFLOAD_TCP_SEGMENTATION) &&
 | 
						|
	    (enable_tso[board_idx])) {
 | 
						|
		if (T3_ASIC_5714_FAMILY(pDevice->ChipRevId) &&
 | 
						|
		   (dev->mtu > 1500)) {
 | 
						|
			printk(KERN_ALERT "%s: Jumbo Frames and TSO cannot simultaneously be enabled. Jumbo Frames enabled. TSO disabled.\n", dev->name);
 | 
						|
		} else {
 | 
						|
			dev->features |= NETIF_F_TSO;
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	printk(KERN_INFO "%s: Scatter-gather %s, 64-bit DMA %s, Tx Checksum %s, ",
 | 
						|
			dev->name,
 | 
						|
			(char *) ((dev->features & NETIF_F_SG) ? "ON" : "OFF"),
 | 
						|
			(char *) ((dev->features & NETIF_F_HIGHDMA) ? "ON" : "OFF"),
 | 
						|
			(char *) ((dev->features & get_csum_flag( pDevice->ChipRevId)) ? "ON" : "OFF"));
 | 
						|
#endif
 | 
						|
	if ((pDevice->ChipRevId != T3_CHIP_ID_5700_B0) &&
 | 
						|
		rx_checksum[board_idx])
 | 
						|
		printk("Rx Checksum ON");
 | 
						|
	else
 | 
						|
		printk("Rx Checksum OFF");
 | 
						|
#ifdef BCM_VLAN
 | 
						|
	printk(", 802.1Q VLAN ON");
 | 
						|
#endif
 | 
						|
#ifdef BCM_TSO
 | 
						|
	if (dev->features & NETIF_F_TSO) {
 | 
						|
		printk(", TSO ON");
 | 
						|
	}
 | 
						|
	else
 | 
						|
#endif
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
	printk(", NAPI ON");
 | 
						|
#endif
 | 
						|
	printk("\n");
 | 
						|
 | 
						|
	register_reboot_notifier(&bcm5700_reboot_notifier);
 | 
						|
#ifdef BCM_TASKLET
 | 
						|
	tasklet_init(&pUmDevice->tasklet, bcm5700_tasklet,
 | 
						|
		(unsigned long) pUmDevice);
 | 
						|
#endif
 | 
						|
	if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) {
 | 
						|
		if ((REG_RD(pDevice, PciCfg.DualMacCtrl) &
 | 
						|
			T3_DUAL_MAC_CH_CTRL_MASK) == 3) {
 | 
						|
 | 
						|
printk(KERN_WARNING "%s: Device is configured for Hardware Based Teaming which is not supported with this operating system. Please consult the user diagnostic guide to disable Turbo Teaming.\n", dev->name);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE > 0x20605)
 | 
						|
 | 
						|
	if ((pci_dev = pci_get_device(0x1022, 0x700c, NULL)))
 | 
						|
#else
 | 
						|
	if ((pci_dev = pci_find_device(0x1022, 0x700c, NULL)))
 | 
						|
#endif
 | 
						|
	{
 | 
						|
		u32 val;
 | 
						|
 | 
						|
		/* Found AMD 762 North bridge */
 | 
						|
		pci_read_config_dword(pci_dev, 0x4c, &val);
 | 
						|
		if ((val & 0x02) == 0) {
 | 
						|
			pci_write_config_dword(pci_dev, 0x4c, val | 0x02);
 | 
						|
			printk(KERN_INFO "%s: Setting AMD762 Northbridge to enable PCI ordering compliance\n", bcm5700_driver);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE > 0x20605)
 | 
						|
 | 
						|
	pci_dev_put(pci_dev);
 | 
						|
 | 
						|
#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR)
 | 
						|
 | 
						|
	if ((pci_dev = pci_get_device(0x1066, 0x0017, NULL))) {
 | 
						|
		bcm_msi_chipset_bug = 1;
 | 
						|
	}
 | 
						|
	pci_dev_put(pci_dev);
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void __devexit
 | 
						|
bcm5700_remove_one (struct pci_dev *pdev)
 | 
						|
{
 | 
						|
	struct net_device *dev = pci_get_drvdata (pdev);
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
 | 
						|
#ifdef BCM_IOCTL32
 | 
						|
	atomic_dec(&bcm5700_load_count);
 | 
						|
	if (atomic_read(&bcm5700_load_count) == 0)
 | 
						|
		unregister_ioctl32_conversion(SIOCNICE);
 | 
						|
#endif
 | 
						|
	unregister_netdev(dev);
 | 
						|
 | 
						|
	if (pUmDevice->lm_dev.pMappedMemBase)
 | 
						|
		iounmap(pUmDevice->lm_dev.pMappedMemBase);
 | 
						|
 | 
						|
	pci_release_regions(pdev);
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x020600)
 | 
						|
	kfree(dev);
 | 
						|
#else
 | 
						|
	free_netdev(dev);
 | 
						|
#endif
 | 
						|
 | 
						|
	pci_set_drvdata(pdev, NULL);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
int b57_test_intr(UM_DEVICE_BLOCK *pUmDevice);
 | 
						|
 
 | 
						|
#ifdef BCM_WL_EMULATOR
 | 
						|
/* new transmit callback  */ 
 | 
						|
static int bcm5700emu_start_xmit(struct sk_buff *skb, struct net_device *dev);
 | 
						|
/* keep track of the 2 gige devices */ 
 | 
						|
static PLM_DEVICE_BLOCK pDev1;
 | 
						|
static PLM_DEVICE_BLOCK pDev2;
 | 
						|
 | 
						|
static void 
 | 
						|
bcm5700emu_open(struct net_device *dev)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;       
 | 
						|
	static int instance = 0;
 | 
						|
	static char *wlemu_if = NULL;
 | 
						|
	char *wlemu_mode = NULL;
 | 
						|
	//int wlemu_idx = 0;
 | 
						|
	static int rx_enable = 0;
 | 
						|
	static int tx_enable = 0;
 | 
						|
	
 | 
						|
	/* which interface is the emulator ? */
 | 
						|
	if(instance == 0) {
 | 
						|
		wlemu_if = nvram_get("wlemu_if");
 | 
						|
		/* do we emulate rx, tx or both  */
 | 
						|
		wlemu_mode = nvram_get("wlemu_mode");
 | 
						|
		if(wlemu_mode) {
 | 
						|
			if (!strcmp(wlemu_mode,"rx"))
 | 
						|
			{
 | 
						|
				rx_enable = 1;
 | 
						|
			} 
 | 
						|
			else if (!strcmp(wlemu_mode,"tx"))
 | 
						|
			{
 | 
						|
				
 | 
						|
				tx_enable = 1;
 | 
						|
				
 | 
						|
			}
 | 
						|
			else if (!strcmp(wlemu_mode,"rx_tx"))
 | 
						|
			{
 | 
						|
				
 | 
						|
				rx_enable = 1;
 | 
						|
				tx_enable = 1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
	instance++;
 | 
						|
 | 
						|
	/* The context is used for accessing the OSL for emulating devices */
 | 
						|
	pDevice->wlc = NULL;
 | 
						|
	
 | 
						|
	/* determines if this device is an emulator */
 | 
						|
	pDevice->wl_emulate_rx = 0;
 | 
						|
	pDevice->wl_emulate_tx = 0;
 | 
						|
 | 
						|
	if(wlemu_if && !strcmp(dev->name,wlemu_if))
 | 
						|
	{
 | 
						|
		/* create an emulator context. */
 | 
						|
		pDevice->wlc = (void *)wlcemu_wlccreate((void *)dev);
 | 
						|
		B57_INFO(("Using %s for wl emulation \n", dev->name));
 | 
						|
		if(rx_enable)
 | 
						|
		{
 | 
						|
			B57_INFO(("Enabling wl RX emulation \n"));
 | 
						|
			pDevice->wl_emulate_rx = 1;
 | 
						|
		}
 | 
						|
		/* re-direct transmit callback to emulator */
 | 
						|
		if(tx_enable)
 | 
						|
		{
 | 
						|
			pDevice->wl_emulate_tx = 1;
 | 
						|
			dev->hard_start_xmit = bcm5700emu_start_xmit;
 | 
						|
			B57_INFO(("Enabling wl TX emulation \n"));
 | 
						|
		}  
 | 
						|
	}
 | 
						|
	/* for debug access to configured devices only */
 | 
						|
	if(instance == 1)
 | 
						|
		pDev1 = pDevice;
 | 
						|
	else if (instance == 2)
 | 
						|
		pDev2 = pDevice;	
 | 
						|
}	
 | 
						|
 | 
						|
/* Public API to get current emulation info */
 | 
						|
int bcm5700emu_get_info(char *buf)
 | 
						|
{
 | 
						|
	int len = 0;
 | 
						|
	PLM_DEVICE_BLOCK p;
 | 
						|
	
 | 
						|
	/* look for an emulating device */
 | 
						|
	if(pDev1->wlc) {
 | 
						|
		p = pDev1;
 | 
						|
		len += sprintf(buf+len,"emulation device : eth0\n");
 | 
						|
	}
 | 
						|
	else if (pDev2->wlc) {
 | 
						|
		p = pDev2;
 | 
						|
		len += sprintf(buf+len,"emulation device : eth1\n");
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		len += sprintf(buf+len,"emulation not activated\n");
 | 
						|
		return len;
 | 
						|
	}
 | 
						|
	if(p->wl_emulate_rx)
 | 
						|
		len += sprintf(buf+len,"RX emulation enabled\n");
 | 
						|
	else 
 | 
						|
		len += sprintf(buf+len,"RX emulation disabled\n");
 | 
						|
	if(p->wl_emulate_tx)
 | 
						|
		len += sprintf(buf+len,"TX emulation enabled\n");
 | 
						|
	else 
 | 
						|
		len += sprintf(buf+len,"TX emulation disabled\n");
 | 
						|
	return len;
 | 
						|
	
 | 
						|
} 
 | 
						|
 | 
						|
 | 
						|
/* Public API to access the bcm5700_start_xmit callback */
 | 
						|
 | 
						|
int 
 | 
						|
bcm5700emu_forward_xmit(struct sk_buff *skb, struct net_device *dev)
 | 
						|
{
 | 
						|
  return bcm5700_start_xmit(skb, dev);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* hook to kernel txmit callback */
 | 
						|
STATIC int
 | 
						|
bcm5700emu_start_xmit(struct sk_buff *skb, struct net_device *dev)
 | 
						|
{
 | 
						|
 | 
						|
  PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
  PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
  return wlcemu_start_xmit(skb,pDevice->wlc);
 | 
						|
}	
 | 
						|
	 
 | 
						|
#endif /* BCM_WL_EMULATOR */
 | 
						|
 
 | 
						|
int
 | 
						|
bcm5700_open(struct net_device *dev)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
	int rc;
 | 
						|
 | 
						|
	if (pUmDevice->suspended){
 | 
						|
            return -EAGAIN;
 | 
						|
        }
 | 
						|
 | 
						|
#ifdef BCM_WL_EMULATOR
 | 
						|
	bcm5700emu_open(dev);
 | 
						|
#endif
 | 
						|
 | 
						|
	/* delay for 6 seconds */
 | 
						|
	pUmDevice->delayed_link_ind = (6 * HZ) / pUmDevice->timer_interval;
 | 
						|
 | 
						|
#ifdef BCM_INT_COAL
 | 
						|
#ifndef BCM_NAPI_RXPOLL
 | 
						|
	pUmDevice->adaptive_expiry = HZ / pUmDevice->timer_interval;
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef INCLUDE_TBI_SUPPORT
 | 
						|
	if ((pDevice->TbiFlags & ENABLE_TBI_FLAG) &&
 | 
						|
		(pDevice->TbiFlags & TBI_POLLING_FLAGS)) {
 | 
						|
		pUmDevice->poll_tbi_interval = HZ / pUmDevice->timer_interval;
 | 
						|
		if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) {
 | 
						|
			pUmDevice->poll_tbi_interval /= 4;
 | 
						|
		}
 | 
						|
		pUmDevice->poll_tbi_expiry = pUmDevice->poll_tbi_interval;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	/* set this timer for 2 seconds */
 | 
						|
	pUmDevice->asf_heartbeat = (2 * HZ) / pUmDevice->timer_interval;
 | 
						|
 | 
						|
#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR)
 | 
						|
 | 
						|
 | 
						|
	if ( (  (T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId) ) &&
 | 
						|
		(T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5714_A0 ) &&
 | 
						|
		(T3_CHIP_REV(pDevice->ChipRevId) != T3_CHIP_REV_5750_AX ) &&
 | 
						|
		(T3_CHIP_REV(pDevice->ChipRevId) != T3_CHIP_REV_5750_BX ) ) &&
 | 
						|
		!bcm_msi_chipset_bug	){
 | 
						|
 | 
						|
		if (disable_msi[pUmDevice->index]==1){
 | 
						|
			/* do nothing-it's not turned on */
 | 
						|
		}else{
 | 
						|
			pDevice->Flags |= USING_MSI_FLAG;
 | 
						|
 | 
						|
                        REG_WR(pDevice, Msi.Mode,  2 );
 | 
						|
 | 
						|
			rc = pci_enable_msi(pUmDevice->pdev);
 | 
						|
 | 
						|
			if(rc!=0){
 | 
						|
				pDevice->Flags &= ~ USING_MSI_FLAG;
 | 
						|
                        	REG_WR(pDevice, Msi.Mode,  1 );
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
	if ((rc= request_irq(pUmDevice->pdev->irq, &bcm5700_interrupt, SA_SHIRQ, dev->name, dev)))
 | 
						|
	{
 | 
						|
 | 
						|
#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR)
 | 
						|
 | 
						|
		if(pDevice->Flags & USING_MSI_FLAG)  {
 | 
						|
 | 
						|
			pci_disable_msi(pUmDevice->pdev);
 | 
						|
			pDevice->Flags &= ~USING_MSI_FLAG;
 | 
						|
                       	REG_WR(pDevice, Msi.Mode,  1 );
 | 
						|
 | 
						|
		}
 | 
						|
#endif
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	pUmDevice->opened = 1;
 | 
						|
	if (LM_InitializeAdapter(pDevice) != LM_STATUS_SUCCESS) {
 | 
						|
		pUmDevice->opened = 0;
 | 
						|
		free_irq(dev->irq, dev);
 | 
						|
		bcm5700_freemem(dev);
 | 
						|
		return -EAGAIN;
 | 
						|
	}
 | 
						|
 | 
						|
	bcm5700_set_vlan_mode(pUmDevice);
 | 
						|
	bcm5700_init_counters(pUmDevice);
 | 
						|
 | 
						|
	if (pDevice->Flags & UNDI_FIX_FLAG) {
 | 
						|
		printk(KERN_INFO "%s: Using indirect register access\n", dev->name);
 | 
						|
	}
 | 
						|
 | 
						|
	if (memcmp(dev->dev_addr, pDevice->NodeAddress, 6))
 | 
						|
	{
 | 
						|
		/* Do not use invalid eth addrs: any multicast & all zeros */
 | 
						|
		if( is_valid_ether_addr(dev->dev_addr) ){
 | 
						|
			LM_SetMacAddress(pDevice, dev->dev_addr);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			printk(KERN_INFO "%s: Invalid administered node address\n",dev->name);
 | 
						|
			memcpy(dev->dev_addr, pDevice->NodeAddress, 6);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (tigon3_debug > 1)
 | 
						|
		printk(KERN_DEBUG "%s: tigon3_open() irq %d.\n", dev->name, dev->irq);
 | 
						|
 | 
						|
	QQ_InitQueue(&pUmDevice->rx_out_of_buf_q.Container,
 | 
						|
        MAX_RX_PACKET_DESC_COUNT);
 | 
						|
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x020300)
 | 
						|
	MOD_INC_USE_COUNT;
 | 
						|
#endif
 | 
						|
 | 
						|
	atomic_set(&pUmDevice->intr_sem, 0);
 | 
						|
 | 
						|
	LM_EnableInterrupt(pDevice);
 | 
						|
 | 
						|
#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR)
 | 
						|
 | 
						|
	if (pDevice->Flags & USING_MSI_FLAG){
 | 
						|
 | 
						|
		/* int test to check support on older machines */
 | 
						|
		if (b57_test_intr(pUmDevice) != 1) {
 | 
						|
 | 
						|
			LM_DisableInterrupt(pDevice);
 | 
						|
			free_irq(pUmDevice->pdev->irq, dev);
 | 
						|
			pci_disable_msi(pUmDevice->pdev);
 | 
						|
                        REG_WR(pDevice, Msi.Mode,  1 );
 | 
						|
			pDevice->Flags &= ~USING_MSI_FLAG;
 | 
						|
 | 
						|
			rc = LM_ResetAdapter(pDevice);
 | 
						|
printk(KERN_ALERT " The MSI support in this system is not functional.\n");
 | 
						|
 | 
						|
			if (rc == LM_STATUS_SUCCESS)
 | 
						|
				rc = 0;
 | 
						|
			else
 | 
						|
				rc = -ENODEV;
 | 
						|
 | 
						|
			if(rc == 0){
 | 
						|
				rc = request_irq(pUmDevice->pdev->irq, &bcm5700_interrupt,
 | 
						|
					    SA_SHIRQ, dev->name, dev);
 | 
						|
			}
 | 
						|
 | 
						|
			if(rc){
 | 
						|
				LM_Halt(pDevice);
 | 
						|
				bcm5700_freemem(dev);
 | 
						|
				pUmDevice->opened = 0;
 | 
						|
				return rc;
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			pDevice->InitDone = TRUE;
 | 
						|
			atomic_set(&pUmDevice->intr_sem, 0);
 | 
						|
			LM_EnableInterrupt(pDevice);
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	init_timer(&pUmDevice->timer);
 | 
						|
	pUmDevice->timer.expires = RUN_AT(pUmDevice->timer_interval);
 | 
						|
	pUmDevice->timer.data = (unsigned long)dev;
 | 
						|
	pUmDevice->timer.function = &bcm5700_timer;
 | 
						|
	add_timer(&pUmDevice->timer);
 | 
						|
 | 
						|
	if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) {
 | 
						|
		init_timer(&pUmDevice->statstimer);
 | 
						|
		pUmDevice->statstimer.expires = RUN_AT(pUmDevice->statstimer_interval);
 | 
						|
		pUmDevice->statstimer.data = (unsigned long)dev;
 | 
						|
		pUmDevice->statstimer.function = &bcm5700_stats_timer;
 | 
						|
		add_timer(&pUmDevice->statstimer);
 | 
						|
	}
 | 
						|
 | 
						|
	if(pDevice->Flags & USING_MSI_FLAG)
 | 
						|
		printk(KERN_INFO "%s: Using Message Signaled Interrupt (MSI)  \n", dev->name);
 | 
						|
	else
 | 
						|
		printk(KERN_INFO "%s: Using PCI INTX interrupt \n", dev->name);
 | 
						|
 | 
						|
	netif_start_queue(dev);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
STATIC void
 | 
						|
bcm5700_stats_timer(unsigned long data)
 | 
						|
{
 | 
						|
	struct net_device *dev = (struct net_device *)data;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
	unsigned long flags = 0;
 | 
						|
 | 
						|
	if (!pUmDevice->opened)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (!atomic_read(&pUmDevice->intr_sem) &&
 | 
						|
	    !pUmDevice->suspended              &&
 | 
						|
	   (pDevice->LinkStatus == LM_STATUS_LINK_ACTIVE)) {
 | 
						|
		BCM5700_LOCK(pUmDevice, flags);
 | 
						|
		LM_GetStats(pDevice);
 | 
						|
		BCM5700_UNLOCK(pUmDevice, flags);
 | 
						|
	}
 | 
						|
 | 
						|
	pUmDevice->statstimer.expires = RUN_AT(pUmDevice->statstimer_interval);
 | 
						|
 | 
						|
	add_timer(&pUmDevice->statstimer);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
STATIC void
 | 
						|
bcm5700_timer(unsigned long data)
 | 
						|
{
 | 
						|
	struct net_device *dev = (struct net_device *)data;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
	unsigned long flags = 0;
 | 
						|
	LM_UINT32 value32;
 | 
						|
 | 
						|
	if (!pUmDevice->opened)
 | 
						|
		return;
 | 
						|
 | 
						|
	/* BCM4785: Flush posted writes from GbE to host memory. */
 | 
						|
	if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG)
 | 
						|
		REG_RD(pDevice, HostCoalesce.Mode);
 | 
						|
 | 
						|
	if (atomic_read(&pUmDevice->intr_sem) || pUmDevice->suspended) {
 | 
						|
		pUmDevice->timer.expires = RUN_AT(pUmDevice->timer_interval);
 | 
						|
		add_timer(&pUmDevice->timer);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
#ifdef INCLUDE_TBI_SUPPORT
 | 
						|
	if ((pDevice->TbiFlags & TBI_POLLING_FLAGS) &&
 | 
						|
		(--pUmDevice->poll_tbi_expiry <= 0)) {
 | 
						|
 | 
						|
		BCM5700_PHY_LOCK(pUmDevice, flags);
 | 
						|
		value32 = REG_RD(pDevice, MacCtrl.Status);
 | 
						|
		if (((pDevice->LinkStatus == LM_STATUS_LINK_ACTIVE) &&
 | 
						|
			((value32 & (MAC_STATUS_LINK_STATE_CHANGED |
 | 
						|
				MAC_STATUS_CFG_CHANGED)) ||
 | 
						|
			!(value32 & MAC_STATUS_PCS_SYNCED)))
 | 
						|
			||
 | 
						|
			((pDevice->LinkStatus != LM_STATUS_LINK_ACTIVE) &&
 | 
						|
			(value32 & (MAC_STATUS_PCS_SYNCED |
 | 
						|
				MAC_STATUS_SIGNAL_DETECTED))))
 | 
						|
		{
 | 
						|
			LM_SetupPhy(pDevice);
 | 
						|
		}
 | 
						|
		BCM5700_PHY_UNLOCK(pUmDevice, flags);
 | 
						|
		pUmDevice->poll_tbi_expiry = pUmDevice->poll_tbi_interval;
 | 
						|
 | 
						|
        }
 | 
						|
#endif
 | 
						|
 | 
						|
	if (pUmDevice->delayed_link_ind > 0) {
 | 
						|
		if (pUmDevice->delayed_link_ind == 1)
 | 
						|
			MM_IndicateStatus(pDevice, pDevice->LinkStatus);
 | 
						|
		else
 | 
						|
			pUmDevice->delayed_link_ind--;
 | 
						|
	}
 | 
						|
 | 
						|
	if (pUmDevice->crc_counter_expiry > 0)
 | 
						|
		pUmDevice->crc_counter_expiry--;
 | 
						|
 | 
						|
	if (!pUmDevice->interrupt) {
 | 
						|
		if (!(pDevice->Flags & USE_TAGGED_STATUS_FLAG)) {
 | 
						|
			BCM5700_LOCK(pUmDevice, flags);
 | 
						|
			if (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) {
 | 
						|
				/* This will generate an interrupt */
 | 
						|
				REG_WR(pDevice, Grc.LocalCtrl,
 | 
						|
					pDevice->GrcLocalCtrl |
 | 
						|
					GRC_MISC_LOCAL_CTRL_SET_INT);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				REG_WR(pDevice, HostCoalesce.Mode,
 | 
						|
					pDevice->CoalesceMode |
 | 
						|
					HOST_COALESCE_ENABLE |
 | 
						|
					HOST_COALESCE_NOW);
 | 
						|
			}
 | 
						|
			if (!(REG_RD(pDevice, DmaWrite.Mode) &
 | 
						|
				DMA_WRITE_MODE_ENABLE)) {
 | 
						|
				BCM5700_UNLOCK(pUmDevice, flags);
 | 
						|
				bcm5700_reset(dev);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				BCM5700_UNLOCK(pUmDevice, flags);
 | 
						|
			}
 | 
						|
			if (pUmDevice->tx_queued) {
 | 
						|
				pUmDevice->tx_queued = 0;
 | 
						|
				netif_wake_queue(dev);
 | 
						|
			}
 | 
						|
		}
 | 
						|
#if (LINUX_VERSION_CODE < 0x02032b)
 | 
						|
		if ((QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) !=
 | 
						|
			pDevice->TxPacketDescCnt) &&
 | 
						|
			((jiffies - dev->trans_start) > TX_TIMEOUT)) {
 | 
						|
 | 
						|
			printk(KERN_WARNING "%s: Tx hung\n", dev->name);
 | 
						|
			bcm5700_reset(dev);
 | 
						|
		}
 | 
						|
#endif
 | 
						|
	}
 | 
						|
#ifdef BCM_INT_COAL
 | 
						|
#ifndef BCM_NAPI_RXPOLL
 | 
						|
	if (pUmDevice->adaptive_coalesce) {
 | 
						|
		pUmDevice->adaptive_expiry--;
 | 
						|
		if (pUmDevice->adaptive_expiry == 0) {
 | 
						|
			pUmDevice->adaptive_expiry = HZ /
 | 
						|
				pUmDevice->timer_interval;
 | 
						|
			bcm5700_adapt_coalesce(pUmDevice);
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
	if (QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container) >
 | 
						|
		(unsigned int) pUmDevice->rx_buf_repl_panic_thresh) {
 | 
						|
		/* Generate interrupt and let isr allocate buffers */
 | 
						|
		REG_WR(pDevice, HostCoalesce.Mode, pDevice->CoalesceMode |
 | 
						|
			HOST_COALESCE_ENABLE | HOST_COALESCE_NOW);
 | 
						|
	}
 | 
						|
 | 
						|
#ifdef BCM_ASF
 | 
						|
	if (pDevice->AsfFlags & ASF_ENABLED) {
 | 
						|
		pUmDevice->asf_heartbeat--;
 | 
						|
		if (pUmDevice->asf_heartbeat == 0) {
 | 
						|
			if( (pDevice->Flags & UNDI_FIX_FLAG) || 
 | 
						|
			    (pDevice->Flags & ENABLE_PCIX_FIX_FLAG)) {
 | 
						|
				MEM_WR_OFFSET(pDevice, T3_CMD_MAILBOX,
 | 
						|
					T3_CMD_NICDRV_ALIVE2);
 | 
						|
				MEM_WR_OFFSET(pDevice, T3_CMD_LENGTH_MAILBOX,
 | 
						|
					4);
 | 
						|
				MEM_WR_OFFSET(pDevice, T3_CMD_DATA_MAILBOX, 5);
 | 
						|
			} else {
 | 
						|
				LM_RegWr(pDevice, 
 | 
						|
					 (T3_NIC_MBUF_POOL_ADDR + 
 | 
						|
					  T3_CMD_MAILBOX), 
 | 
						|
					 T3_CMD_NICDRV_ALIVE2, 1);
 | 
						|
				LM_RegWr(pDevice, 
 | 
						|
					 (T3_NIC_MBUF_POOL_ADDR + 
 | 
						|
					  T3_CMD_LENGTH_MAILBOX),4,1);
 | 
						|
				LM_RegWr(pDevice, 
 | 
						|
					 (T3_NIC_MBUF_POOL_ADDR + 
 | 
						|
					  T3_CMD_DATA_MAILBOX),5,1);
 | 
						|
 			}
 | 
						|
 | 
						|
			value32 = REG_RD(pDevice, Grc.RxCpuEvent);
 | 
						|
			REG_WR(pDevice, Grc.RxCpuEvent, value32 | BIT_14);
 | 
						|
			pUmDevice->asf_heartbeat = (2 * HZ) /
 | 
						|
				pUmDevice->timer_interval;
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	if (pDevice->PhyFlags & PHY_IS_FIBER){
 | 
						|
		BCM5700_PHY_LOCK(pUmDevice, flags);
 | 
						|
		LM_5714_FamFiberCheckLink(pDevice);
 | 
						|
		BCM5700_PHY_UNLOCK(pUmDevice, flags);
 | 
						|
	}
 | 
						|
 | 
						|
	pUmDevice->timer.expires = RUN_AT(pUmDevice->timer_interval);
 | 
						|
	add_timer(&pUmDevice->timer);
 | 
						|
}
 | 
						|
 | 
						|
STATIC int
 | 
						|
bcm5700_init_counters(PUM_DEVICE_BLOCK pUmDevice)
 | 
						|
{
 | 
						|
#ifdef BCM_INT_COAL
 | 
						|
#ifndef BCM_NAPI_RXPOLL
 | 
						|
	LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev;
 | 
						|
 | 
						|
	pUmDevice->rx_curr_coalesce_frames = pDevice->RxMaxCoalescedFrames;
 | 
						|
	pUmDevice->rx_curr_coalesce_ticks = pDevice->RxCoalescingTicks;
 | 
						|
	pUmDevice->tx_curr_coalesce_frames = pDevice->TxMaxCoalescedFrames;
 | 
						|
	pUmDevice->rx_last_cnt = 0;
 | 
						|
	pUmDevice->tx_last_cnt = 0;
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
	pUmDevice->phy_crc_count = 0;
 | 
						|
#if TIGON3_DEBUG
 | 
						|
	pUmDevice->tx_zc_count = 0;
 | 
						|
	pUmDevice->tx_chksum_count = 0;
 | 
						|
	pUmDevice->tx_himem_count = 0;
 | 
						|
	pUmDevice->rx_good_chksum_count = 0;
 | 
						|
	pUmDevice->rx_bad_chksum_count = 0;
 | 
						|
#endif
 | 
						|
#ifdef BCM_TSO
 | 
						|
	pUmDevice->tso_pkt_count = 0;
 | 
						|
#endif
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef BCM_INT_COAL
 | 
						|
#ifndef BCM_NAPI_RXPOLL
 | 
						|
STATIC int
 | 
						|
bcm5700_do_adapt_coalesce(PUM_DEVICE_BLOCK pUmDevice,
 | 
						|
	int rx_frames, int rx_ticks, int tx_frames, int rx_frames_intr)
 | 
						|
{
 | 
						|
	unsigned long flags = 0;
 | 
						|
	LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev;
 | 
						|
 | 
						|
	if (pUmDevice->do_global_lock) {
 | 
						|
		if (spin_is_locked(&pUmDevice->global_lock))
 | 
						|
			return 0;
 | 
						|
		spin_lock_irqsave(&pUmDevice->global_lock, flags);
 | 
						|
	}
 | 
						|
	pUmDevice->rx_curr_coalesce_frames = rx_frames;
 | 
						|
	pUmDevice->rx_curr_coalesce_ticks = rx_ticks;
 | 
						|
	pUmDevice->tx_curr_coalesce_frames = tx_frames;
 | 
						|
	pUmDevice->rx_curr_coalesce_frames_intr = rx_frames_intr;
 | 
						|
	REG_WR(pDevice, HostCoalesce.RxMaxCoalescedFrames, rx_frames);
 | 
						|
 | 
						|
	REG_WR(pDevice, HostCoalesce.RxCoalescingTicks, rx_ticks);
 | 
						|
 | 
						|
	REG_WR(pDevice, HostCoalesce.TxMaxCoalescedFrames, tx_frames);
 | 
						|
 | 
						|
	REG_WR(pDevice, HostCoalesce.RxMaxCoalescedFramesDuringInt,
 | 
						|
		rx_frames_intr);
 | 
						|
 | 
						|
	BCM5700_UNLOCK(pUmDevice, flags);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
STATIC int
 | 
						|
bcm5700_adapt_coalesce(PUM_DEVICE_BLOCK pUmDevice)
 | 
						|
{
 | 
						|
	PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev;
 | 
						|
	uint rx_curr_cnt, tx_curr_cnt, rx_delta, tx_delta, total_delta;
 | 
						|
 | 
						|
	rx_curr_cnt = pDevice->pStatsBlkVirt->ifHCInUcastPkts.Low;
 | 
						|
	tx_curr_cnt = pDevice->pStatsBlkVirt->ifHCOutUcastPkts.Low;
 | 
						|
	if ((rx_curr_cnt <= pUmDevice->rx_last_cnt) ||
 | 
						|
		(tx_curr_cnt < pUmDevice->tx_last_cnt)) {
 | 
						|
 | 
						|
		/* skip if there is counter rollover */
 | 
						|
		pUmDevice->rx_last_cnt = rx_curr_cnt;
 | 
						|
		pUmDevice->tx_last_cnt = tx_curr_cnt;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	rx_delta = rx_curr_cnt - pUmDevice->rx_last_cnt;
 | 
						|
	tx_delta = tx_curr_cnt - pUmDevice->tx_last_cnt;
 | 
						|
	total_delta = (((rx_delta + rx_delta) + tx_delta) / 3) << 1;
 | 
						|
 | 
						|
	pUmDevice->rx_last_cnt = rx_curr_cnt;
 | 
						|
	pUmDevice->tx_last_cnt = tx_curr_cnt;
 | 
						|
 | 
						|
	if (total_delta < ADAPTIVE_LO_PKT_THRESH) {
 | 
						|
		if (pUmDevice->rx_curr_coalesce_frames !=
 | 
						|
			ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES) {
 | 
						|
 | 
						|
			bcm5700_do_adapt_coalesce(pUmDevice,
 | 
						|
				ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES,
 | 
						|
				ADAPTIVE_LO_RX_COALESCING_TICKS,
 | 
						|
				ADAPTIVE_LO_TX_MAX_COALESCED_FRAMES,
 | 
						|
				ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES_DURING_INT);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (total_delta < ADAPTIVE_HI_PKT_THRESH) {
 | 
						|
		if (pUmDevice->rx_curr_coalesce_frames !=
 | 
						|
			DEFAULT_RX_MAX_COALESCED_FRAMES) {
 | 
						|
 | 
						|
			bcm5700_do_adapt_coalesce(pUmDevice,
 | 
						|
				DEFAULT_RX_MAX_COALESCED_FRAMES,
 | 
						|
				DEFAULT_RX_COALESCING_TICKS,
 | 
						|
				DEFAULT_TX_MAX_COALESCED_FRAMES,
 | 
						|
				DEFAULT_RX_MAX_COALESCED_FRAMES_DURING_INT);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		if (pUmDevice->rx_curr_coalesce_frames !=
 | 
						|
			ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES) {
 | 
						|
 | 
						|
			bcm5700_do_adapt_coalesce(pUmDevice,
 | 
						|
				ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES,
 | 
						|
				ADAPTIVE_HI_RX_COALESCING_TICKS,
 | 
						|
				ADAPTIVE_HI_TX_MAX_COALESCED_FRAMES,
 | 
						|
				ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES_DURING_INT);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
STATIC void
 | 
						|
bcm5700_reset(struct net_device *dev)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
#ifdef BCM_TSO
 | 
						|
 | 
						|
	if( (dev->features & NETIF_F_TSO) &&
 | 
						|
		(pUmDevice->tx_full) )	   {
 | 
						|
 | 
						|
		dev->features &= ~NETIF_F_TSO;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	netif_stop_queue(dev);
 | 
						|
	bcm5700_intr_off(pUmDevice);
 | 
						|
	BCM5700_PHY_LOCK(pUmDevice, flags);
 | 
						|
	LM_ResetAdapter(pDevice);
 | 
						|
	pDevice->InitDone = TRUE;
 | 
						|
	bcm5700_do_rx_mode(dev);
 | 
						|
	bcm5700_set_vlan_mode(pUmDevice);
 | 
						|
	bcm5700_init_counters(pUmDevice);
 | 
						|
	if (memcmp(dev->dev_addr, pDevice->NodeAddress, 6)) {
 | 
						|
		LM_SetMacAddress(pDevice, dev->dev_addr);
 | 
						|
	}
 | 
						|
	BCM5700_PHY_UNLOCK(pUmDevice, flags);
 | 
						|
	atomic_set(&pUmDevice->intr_sem, 1);
 | 
						|
	bcm5700_intr_on(pUmDevice);
 | 
						|
	netif_wake_queue(dev);
 | 
						|
}
 | 
						|
 | 
						|
STATIC void
 | 
						|
bcm5700_set_vlan_mode(UM_DEVICE_BLOCK *pUmDevice)
 | 
						|
{
 | 
						|
	LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev;
 | 
						|
	LM_UINT32 ReceiveMask = pDevice->ReceiveMask;
 | 
						|
	int vlan_tag_mode = pUmDevice->vlan_tag_mode;
 | 
						|
 | 
						|
	if (vlan_tag_mode == VLAN_TAG_MODE_AUTO_STRIP) {
 | 
						|
	        if (pDevice->AsfFlags & ASF_ENABLED) {
 | 
						|
			vlan_tag_mode = VLAN_TAG_MODE_FORCED_STRIP;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			vlan_tag_mode = VLAN_TAG_MODE_NORMAL_STRIP;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (vlan_tag_mode == VLAN_TAG_MODE_NORMAL_STRIP) {
 | 
						|
		ReceiveMask |= LM_KEEP_VLAN_TAG;
 | 
						|
#ifdef BCM_VLAN
 | 
						|
		if (pUmDevice->vlgrp)
 | 
						|
			ReceiveMask &= ~LM_KEEP_VLAN_TAG;
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	else if (vlan_tag_mode == VLAN_TAG_MODE_FORCED_STRIP) {
 | 
						|
		ReceiveMask &= ~LM_KEEP_VLAN_TAG;
 | 
						|
	}
 | 
						|
	if (ReceiveMask != pDevice->ReceiveMask)
 | 
						|
	{
 | 
						|
		LM_SetReceiveMask(pDevice, ReceiveMask);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
bcm5700_poll_wait(UM_DEVICE_BLOCK *pUmDevice)
 | 
						|
{
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
	while (pUmDevice->lm_dev.RxPoll) {
 | 
						|
		current->state = TASK_INTERRUPTIBLE;
 | 
						|
		schedule_timeout(1);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef BCM_VLAN
 | 
						|
STATIC void
 | 
						|
bcm5700_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv;
 | 
						|
 | 
						|
	bcm5700_intr_off(pUmDevice);
 | 
						|
	bcm5700_poll_wait(pUmDevice);
 | 
						|
	pUmDevice->vlgrp = vlgrp;
 | 
						|
	bcm5700_set_vlan_mode(pUmDevice);
 | 
						|
	bcm5700_intr_on(pUmDevice);
 | 
						|
}
 | 
						|
 | 
						|
STATIC void
 | 
						|
bcm5700_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv;
 | 
						|
 | 
						|
	bcm5700_intr_off(pUmDevice);
 | 
						|
	bcm5700_poll_wait(pUmDevice);
 | 
						|
	if (pUmDevice->vlgrp) {
 | 
						|
		pUmDevice->vlgrp->vlan_devices[vid] = NULL;
 | 
						|
	}
 | 
						|
	bcm5700_intr_on(pUmDevice);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
STATIC int
 | 
						|
bcm5700_start_xmit(struct sk_buff *skb, struct net_device *dev)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
	PLM_PACKET pPacket;
 | 
						|
	PUM_PACKET pUmPacket;
 | 
						|
	unsigned long flags = 0;
 | 
						|
	int frag_no;
 | 
						|
#ifdef BCM_TSO
 | 
						|
	LM_UINT32 mss = 0 ;
 | 
						|
	uint16_t ip_tcp_len, tcp_opt_len, tcp_seg_flags;
 | 
						|
#endif
 | 
						|
 | 
						|
	if ((pDevice->LinkStatus == LM_STATUS_LINK_DOWN) ||
 | 
						|
		!pDevice->InitDone || pUmDevice->suspended)
 | 
						|
	{
 | 
						|
		dev_kfree_skb(skb);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x02032b)
 | 
						|
	if (test_and_set_bit(0, &dev->tbusy)) {
 | 
						|
	    return 1;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	if (pUmDevice->do_global_lock && pUmDevice->interrupt) {
 | 
						|
		netif_stop_queue(dev);
 | 
						|
		pUmDevice->tx_queued = 1;
 | 
						|
		if (!pUmDevice->interrupt) {
 | 
						|
			netif_wake_queue(dev);
 | 
						|
			pUmDevice->tx_queued = 0;
 | 
						|
		}
 | 
						|
	    return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	pPacket = (PLM_PACKET)
 | 
						|
		QQ_PopHead(&pDevice->TxPacketFreeQ.Container);
 | 
						|
	if (pPacket == 0) {
 | 
						|
		netif_stop_queue(dev);
 | 
						|
		pUmDevice->tx_full = 1;
 | 
						|
		if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container)) {
 | 
						|
			netif_wake_queue(dev);
 | 
						|
			pUmDevice->tx_full = 0;
 | 
						|
		}
 | 
						|
	    return 1;
 | 
						|
	}
 | 
						|
	pUmPacket = (PUM_PACKET) pPacket;
 | 
						|
	pUmPacket->skbuff = skb;
 | 
						|
	pUmDevice->stats.tx_bytes += skb->len; 
 | 
						|
 | 
						|
	if (skb->ip_summed == CHECKSUM_HW) {
 | 
						|
		pPacket->Flags = SND_BD_FLAG_TCP_UDP_CKSUM;
 | 
						|
#if TIGON3_DEBUG
 | 
						|
		pUmDevice->tx_chksum_count++;
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		pPacket->Flags = 0;
 | 
						|
	}
 | 
						|
#if MAX_SKB_FRAGS
 | 
						|
	frag_no = skb_shinfo(skb)->nr_frags;
 | 
						|
#else
 | 
						|
	frag_no = 0;
 | 
						|
#endif
 | 
						|
	if (atomic_read(&pDevice->SendBdLeft) < (frag_no + 1)) {
 | 
						|
		netif_stop_queue(dev);
 | 
						|
		pUmDevice->tx_full = 1;
 | 
						|
		QQ_PushHead(&pDevice->TxPacketFreeQ.Container, pPacket);
 | 
						|
		if (atomic_read(&pDevice->SendBdLeft) >= (frag_no + 1)) {
 | 
						|
			netif_wake_queue(dev);
 | 
						|
			pUmDevice->tx_full = 0;
 | 
						|
		}
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	pPacket->u.Tx.FragCount = frag_no + 1;
 | 
						|
#if TIGON3_DEBUG
 | 
						|
	if (pPacket->u.Tx.FragCount > 1)
 | 
						|
		pUmDevice->tx_zc_count++;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef BCM_VLAN
 | 
						|
	if (pUmDevice->vlgrp && vlan_tx_tag_present(skb)) {
 | 
						|
		pPacket->VlanTag = vlan_tx_tag_get(skb);
 | 
						|
		pPacket->Flags |= SND_BD_FLAG_VLAN_TAG;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef BCM_TSO
 | 
						|
	if ((mss = (LM_UINT32) skb_shinfo(skb)->tso_size) &&
 | 
						|
		(skb->len > pDevice->TxMtu)) {
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x02060c)
 | 
						|
 | 
						|
		if (skb_header_cloned(skb) &&
 | 
						|
			pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
 | 
						|
 | 
						|
			dev_kfree_skb(skb);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
#endif
 | 
						|
		pUmDevice->tso_pkt_count++;
 | 
						|
 | 
						|
		pPacket->Flags |= SND_BD_FLAG_CPU_PRE_DMA |
 | 
						|
			SND_BD_FLAG_CPU_POST_DMA;
 | 
						|
 | 
						|
		tcp_opt_len = 0;
 | 
						|
		if (skb->h.th->doff > 5) {
 | 
						|
			tcp_opt_len = (skb->h.th->doff - 5) << 2;
 | 
						|
		}
 | 
						|
		ip_tcp_len = (skb->nh.iph->ihl << 2) + sizeof(struct tcphdr);
 | 
						|
		skb->nh.iph->check = 0;
 | 
						|
 | 
						|
		if ( T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId) ){
 | 
						|
			skb->h.th->check = 0;
 | 
						|
			pPacket->Flags &= ~SND_BD_FLAG_TCP_UDP_CKSUM;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			skb->h.th->check = ~csum_tcpudp_magic(
 | 
						|
				skb->nh.iph->saddr, skb->nh.iph->daddr,
 | 
						|
				0, IPPROTO_TCP, 0);
 | 
						|
		}
 | 
						|
 | 
						|
		skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
 | 
						|
		tcp_seg_flags = 0;
 | 
						|
 | 
						|
		if (tcp_opt_len || (skb->nh.iph->ihl > 5)) {
 | 
						|
			if ( T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId) ){
 | 
						|
				tcp_seg_flags =
 | 
						|
					((skb->nh.iph->ihl - 5) +
 | 
						|
					(tcp_opt_len >> 2)) << 11;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				pPacket->Flags |=
 | 
						|
					((skb->nh.iph->ihl - 5) +
 | 
						|
					(tcp_opt_len >> 2)) << 12;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		pPacket->u.Tx.MaxSegmentSize = mss | tcp_seg_flags;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		pPacket->u.Tx.MaxSegmentSize = 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	BCM5700_LOCK(pUmDevice, flags);
 | 
						|
	LM_SendPacket(pDevice, pPacket);
 | 
						|
	BCM5700_UNLOCK(pUmDevice, flags);
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x02032b)
 | 
						|
	netif_wake_queue(dev);
 | 
						|
#endif
 | 
						|
	dev->trans_start = jiffies;
 | 
						|
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
STATIC int
 | 
						|
bcm5700_poll(struct net_device *dev, int *budget)
 | 
						|
{
 | 
						|
	int orig_budget = *budget;
 | 
						|
	int work_done;
 | 
						|
	UM_DEVICE_BLOCK *pUmDevice = (UM_DEVICE_BLOCK *) dev->priv;
 | 
						|
	LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev;
 | 
						|
	unsigned long flags = 0;
 | 
						|
	LM_UINT32 tag;
 | 
						|
 | 
						|
	if (orig_budget > dev->quota)
 | 
						|
		orig_budget = dev->quota;
 | 
						|
 | 
						|
	BCM5700_LOCK(pUmDevice, flags);
 | 
						|
	/* BCM4785: Flush posted writes from GbE to host memory. */
 | 
						|
	if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG)
 | 
						|
		REG_RD(pDevice, HostCoalesce.Mode);
 | 
						|
	work_done = LM_ServiceRxPoll(pDevice, orig_budget);
 | 
						|
	*budget -= work_done;
 | 
						|
	dev->quota -= work_done;
 | 
						|
 | 
						|
	if (QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container)) {
 | 
						|
		replenish_rx_buffers(pUmDevice, 0);
 | 
						|
	}
 | 
						|
	BCM5700_UNLOCK(pUmDevice, flags);
 | 
						|
	if (work_done) {
 | 
						|
		MM_IndicateRxPackets(pDevice);
 | 
						|
		BCM5700_LOCK(pUmDevice, flags);
 | 
						|
		LM_QueueRxPackets(pDevice);
 | 
						|
		BCM5700_UNLOCK(pUmDevice, flags);
 | 
						|
	}
 | 
						|
	if ((work_done < orig_budget) || atomic_read(&pUmDevice->intr_sem) ||
 | 
						|
		pUmDevice->suspended) {
 | 
						|
 | 
						|
		netif_rx_complete(dev);
 | 
						|
		BCM5700_LOCK(pUmDevice, flags);
 | 
						|
		REG_WR(pDevice, Grc.Mode, pDevice->GrcMode);
 | 
						|
		pDevice->RxPoll = FALSE;
 | 
						|
		if (pDevice->RxPoll) {
 | 
						|
			BCM5700_UNLOCK(pUmDevice, flags);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		/* Take care of possible missed rx interrupts */
 | 
						|
		REG_RD_BACK(pDevice, Grc.Mode);	/* flush the register write */
 | 
						|
		tag = pDevice->pStatusBlkVirt->StatusTag;
 | 
						|
		if ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) ||
 | 
						|
			(pDevice->pStatusBlkVirt->Idx[0].RcvProdIdx !=
 | 
						|
			pDevice->RcvRetConIdx)) {
 | 
						|
 | 
						|
			REG_WR(pDevice, HostCoalesce.Mode,
 | 
						|
				pDevice->CoalesceMode | HOST_COALESCE_ENABLE |
 | 
						|
				HOST_COALESCE_NOW);
 | 
						|
		}
 | 
						|
		/* If a new status block is pending in the WDMA state machine */
 | 
						|
		/* before the register write to enable the rx interrupt,      */
 | 
						|
		/* the new status block may DMA with no interrupt. In this    */
 | 
						|
		/* scenario, the tag read above will be older than the tag in */
 | 
						|
		/* the pending status block and writing the older tag will    */
 | 
						|
		/* cause interrupt to be generated.                           */
 | 
						|
		else if (pDevice->Flags & USE_TAGGED_STATUS_FLAG) {
 | 
						|
			MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low,
 | 
						|
				tag << 24);
 | 
						|
			/* Make sure we service tx in case some tx interrupts */
 | 
						|
			/* are cleared */
 | 
						|
			if (atomic_read(&pDevice->SendBdLeft) <
 | 
						|
				(T3_SEND_RCB_ENTRY_COUNT / 2)) {
 | 
						|
				REG_WR(pDevice, HostCoalesce.Mode,
 | 
						|
					pDevice->CoalesceMode |
 | 
						|
					HOST_COALESCE_ENABLE |
 | 
						|
					HOST_COALESCE_NOW);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		BCM5700_UNLOCK(pUmDevice, flags);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
#endif /* BCM_NAPI_RXPOLL */
 | 
						|
 | 
						|
STATIC irqreturn_t
 | 
						|
bcm5700_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 | 
						|
{
 | 
						|
	struct net_device *dev = (struct net_device *)dev_instance;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
	LM_UINT32 oldtag, newtag;
 | 
						|
	int i, max_intr_loop;
 | 
						|
#ifdef BCM_TASKLET
 | 
						|
	int repl_buf_count;
 | 
						|
#endif
 | 
						|
	unsigned int handled = 1;
 | 
						|
 | 
						|
	if (!pDevice->InitDone) {
 | 
						|
		handled = 0;
 | 
						|
		return IRQ_RETVAL(handled);
 | 
						|
	}
 | 
						|
 | 
						|
	bcm5700_intr_lock(pUmDevice);
 | 
						|
	if (atomic_read(&pUmDevice->intr_sem)) {
 | 
						|
		MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1);
 | 
						|
		bcm5700_intr_unlock(pUmDevice);
 | 
						|
		handled = 0;
 | 
						|
		return IRQ_RETVAL(handled);
 | 
						|
	}
 | 
						|
 | 
						|
	if (test_and_set_bit(0, (void*)&pUmDevice->interrupt)) {
 | 
						|
		printk(KERN_ERR "%s: Duplicate entry of the interrupt handler\n",
 | 
						|
			dev->name);
 | 
						|
		bcm5700_intr_unlock(pUmDevice);
 | 
						|
		handled = 0;
 | 
						|
		return IRQ_RETVAL(handled);
 | 
						|
	}
 | 
						|
 | 
						|
	/* BCM4785: Flush posted writes from GbE to host memory. */
 | 
						|
	if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG)
 | 
						|
		REG_RD(pDevice, HostCoalesce.Mode);
 | 
						|
 | 
						|
	if ((pDevice->Flags & USING_MSI_FLAG) ||
 | 
						|
		(pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) ||
 | 
						|
		!(REG_RD(pDevice,PciCfg.PciState) & T3_PCI_STATE_INTERRUPT_NOT_ACTIVE) )
 | 
						|
	{
 | 
						|
 | 
						|
		if (pUmDevice->intr_test) {
 | 
						|
			if (!(REG_RD(pDevice, PciCfg.PciState) &
 | 
						|
					T3_PCI_STATE_INTERRUPT_NOT_ACTIVE) ||
 | 
						|
						pDevice->Flags & USING_MSI_FLAG ) {
 | 
						|
				pUmDevice->intr_test_result = 1;
 | 
						|
			}
 | 
						|
			pUmDevice->intr_test = 0;
 | 
						|
		}
 | 
						|
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
		max_intr_loop = 1;
 | 
						|
#else
 | 
						|
		max_intr_loop = 50;
 | 
						|
#endif
 | 
						|
		if (pDevice->Flags & USE_TAGGED_STATUS_FLAG) {
 | 
						|
			MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1);
 | 
						|
			oldtag = pDevice->pStatusBlkVirt->StatusTag;
 | 
						|
 | 
						|
			for (i = 0; ; i++) {
 | 
						|
				pDevice->pStatusBlkVirt->Status &= ~STATUS_BLOCK_UPDATED;
 | 
						|
 | 
						|
				LM_ServiceInterrupts(pDevice);
 | 
						|
				/* BCM4785: Flush GbE posted writes to host memory. */
 | 
						|
				if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG)
 | 
						|
					MB_REG_RD(pDevice, Mailbox.Interrupt[0].Low);
 | 
						|
				newtag = pDevice->pStatusBlkVirt->StatusTag;
 | 
						|
				if ((newtag == oldtag) || (i > max_intr_loop)) {
 | 
						|
					MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, oldtag << 24);
 | 
						|
					pDevice->LastTag = oldtag;
 | 
						|
					if (pDevice->Flags & UNDI_FIX_FLAG) {
 | 
						|
						REG_WR(pDevice, Grc.LocalCtrl,
 | 
						|
						pDevice->GrcLocalCtrl | 0x2);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				}
 | 
						|
				oldtag = newtag;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			i = 0;
 | 
						|
			do {
 | 
						|
				uint dummy;
 | 
						|
 | 
						|
				MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1);
 | 
						|
				pDevice->pStatusBlkVirt->Status &= ~STATUS_BLOCK_UPDATED;
 | 
						|
				LM_ServiceInterrupts(pDevice);
 | 
						|
				MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 0);
 | 
						|
				dummy = MB_REG_RD(pDevice, Mailbox.Interrupt[0].Low);
 | 
						|
				i++;
 | 
						|
			}
 | 
						|
			while ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) &&
 | 
						|
				(i < max_intr_loop));
 | 
						|
 | 
						|
			if (pDevice->Flags & UNDI_FIX_FLAG) {
 | 
						|
				REG_WR(pDevice, Grc.LocalCtrl,
 | 
						|
				pDevice->GrcLocalCtrl | 0x2);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		/* not my interrupt */
 | 
						|
		handled = 0;
 | 
						|
	}
 | 
						|
 | 
						|
#ifdef BCM_TASKLET
 | 
						|
	repl_buf_count = QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container);
 | 
						|
	if (((repl_buf_count > pUmDevice->rx_buf_repl_panic_thresh) ||
 | 
						|
		pDevice->QueueAgain) &&
 | 
						|
		(!test_and_set_bit(0, &pUmDevice->tasklet_busy))) {
 | 
						|
 | 
						|
		replenish_rx_buffers(pUmDevice, pUmDevice->rx_buf_repl_isr_limit);
 | 
						|
		clear_bit(0, (void*)&pUmDevice->tasklet_busy);
 | 
						|
	}
 | 
						|
	else if ((repl_buf_count > pUmDevice->rx_buf_repl_thresh) &&
 | 
						|
		!pUmDevice->tasklet_pending) {
 | 
						|
 | 
						|
		pUmDevice->tasklet_pending = 1;
 | 
						|
		tasklet_schedule(&pUmDevice->tasklet);
 | 
						|
	}
 | 
						|
#else
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
	if (!pDevice->RxPoll &&
 | 
						|
		QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container)) {
 | 
						|
		pDevice->RxPoll = 1;
 | 
						|
		MM_ScheduleRxPoll(pDevice);
 | 
						|
	}
 | 
						|
#else
 | 
						|
	if (QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container)) {
 | 
						|
		replenish_rx_buffers(pUmDevice, 0);
 | 
						|
	}
 | 
						|
 | 
						|
	if (QQ_GetEntryCnt(&pDevice->RxPacketFreeQ.Container) ||
 | 
						|
		pDevice->QueueAgain) {
 | 
						|
 | 
						|
		LM_QueueRxPackets(pDevice);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
	clear_bit(0, (void*)&pUmDevice->interrupt);
 | 
						|
	bcm5700_intr_unlock(pUmDevice);
 | 
						|
	if (pUmDevice->tx_queued) {
 | 
						|
		pUmDevice->tx_queued = 0;
 | 
						|
		netif_wake_queue(dev);
 | 
						|
	}
 | 
						|
	return IRQ_RETVAL(handled);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef BCM_TASKLET
 | 
						|
STATIC void
 | 
						|
bcm5700_tasklet(unsigned long data)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)data;
 | 
						|
	unsigned long flags = 0;
 | 
						|
 | 
						|
	/* RH 7.2 Beta 3 tasklets are reentrant */
 | 
						|
	if (test_and_set_bit(0, &pUmDevice->tasklet_busy)) {
 | 
						|
		pUmDevice->tasklet_pending = 0;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	pUmDevice->tasklet_pending = 0;
 | 
						|
	if (pUmDevice->opened && !pUmDevice->suspended) {
 | 
						|
		BCM5700_LOCK(pUmDevice, flags);
 | 
						|
		replenish_rx_buffers(pUmDevice, 0);
 | 
						|
		BCM5700_UNLOCK(pUmDevice, flags);
 | 
						|
	}
 | 
						|
 | 
						|
	clear_bit(0, &pUmDevice->tasklet_busy);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
STATIC int
 | 
						|
bcm5700_close(struct net_device *dev)
 | 
						|
{
 | 
						|
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x02032b)
 | 
						|
	dev->start = 0;
 | 
						|
#endif
 | 
						|
	netif_stop_queue(dev);
 | 
						|
	pUmDevice->opened = 0;
 | 
						|
 | 
						|
#ifdef BCM_ASF
 | 
						|
	if( !(pDevice->AsfFlags & ASF_ENABLED) )
 | 
						|
#endif
 | 
						|
#ifdef BCM_WOL
 | 
						|
		if( enable_wol[pUmDevice->index] == 0 )
 | 
						|
#endif
 | 
						|
			B57_INFO(("%s: %s NIC Link is DOWN\n", bcm5700_driver, dev->name));
 | 
						|
 | 
						|
	if (tigon3_debug > 1)
 | 
						|
		printk(KERN_DEBUG "%s: Shutting down Tigon3\n",
 | 
						|
			   dev->name);
 | 
						|
 | 
						|
	LM_MulticastClear(pDevice);
 | 
						|
	bcm5700_shutdown(pUmDevice);
 | 
						|
 | 
						|
	if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) {
 | 
						|
		del_timer_sync(&pUmDevice->statstimer);
 | 
						|
	}
 | 
						|
 | 
						|
	del_timer_sync(&pUmDevice->timer);
 | 
						|
 | 
						|
	free_irq(pUmDevice->pdev->irq, dev);
 | 
						|
 | 
						|
#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR)
 | 
						|
 | 
						|
	if(pDevice->Flags & USING_MSI_FLAG) {
 | 
						|
		pci_disable_msi(pUmDevice->pdev);
 | 
						|
                REG_WR(pDevice, Msi.Mode,  1 );
 | 
						|
		pDevice->Flags &= ~USING_MSI_FLAG;
 | 
						|
	}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x020300)
 | 
						|
	MOD_DEC_USE_COUNT;
 | 
						|
#endif
 | 
						|
	{
 | 
						|
	/* BCM4785: Don't go to low-power state because it will power down the smbus block. */
 | 
						|
	if (!(pDevice->Flags & SB_CORE_FLAG))
 | 
						|
		LM_SetPowerState(pDevice, LM_POWER_STATE_D3);
 | 
						|
	}
 | 
						|
 | 
						|
	bcm5700_freemem(dev);
 | 
						|
 | 
						|
	QQ_InitQueue(&pDevice->RxPacketFreeQ.Container,
 | 
						|
        		MAX_RX_PACKET_DESC_COUNT);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
STATIC int
 | 
						|
bcm5700_freemem(struct net_device *dev)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	LM_DEVICE_BLOCK	 *pDevice = &pUmDevice->lm_dev;
 | 
						|
 | 
						|
	for (i = 0; i < pUmDevice->mem_list_num; i++) {
 | 
						|
		if (pUmDevice->mem_size_list[i] == 0) {
 | 
						|
			kfree(pUmDevice->mem_list[i]);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			pci_free_consistent(pUmDevice->pdev,
 | 
						|
				(size_t) pUmDevice->mem_size_list[i],
 | 
						|
				pUmDevice->mem_list[i],
 | 
						|
				pUmDevice->dma_list[i]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	pDevice->pStatusBlkVirt = 0;
 | 
						|
	pDevice->pStatsBlkVirt  = 0;
 | 
						|
	pUmDevice->mem_list_num = 0;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
uint64_t
 | 
						|
bcm5700_crc_count(PUM_DEVICE_BLOCK pUmDevice)
 | 
						|
{
 | 
						|
	PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev;
 | 
						|
	LM_UINT32 Value32;
 | 
						|
	PT3_STATS_BLOCK pStats = (PT3_STATS_BLOCK) pDevice->pStatsBlkVirt;
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 ||
 | 
						|
		T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) &&
 | 
						|
		!(pDevice->TbiFlags & ENABLE_TBI_FLAG)) {
 | 
						|
 | 
						|
		if (!pUmDevice->opened || !pDevice->InitDone)
 | 
						|
		{
 | 
						|
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
 | 
						|
		/* regulate MDIO access during run time */
 | 
						|
		if (pUmDevice->crc_counter_expiry > 0)
 | 
						|
			return pUmDevice->phy_crc_count;
 | 
						|
 | 
						|
		pUmDevice->crc_counter_expiry = (5 * HZ) /
 | 
						|
			pUmDevice->timer_interval;
 | 
						|
 | 
						|
		BCM5700_PHY_LOCK(pUmDevice, flags);
 | 
						|
		LM_ReadPhy(pDevice, 0x1e, &Value32);
 | 
						|
		if ((Value32 & 0x8000) == 0)
 | 
						|
			LM_WritePhy(pDevice, 0x1e, Value32 | 0x8000);
 | 
						|
		LM_ReadPhy(pDevice, 0x14, &Value32);
 | 
						|
		BCM5700_PHY_UNLOCK(pUmDevice, flags);
 | 
						|
		/* Sometimes data on the MDIO bus can be corrupted */
 | 
						|
		if (Value32 != 0xffff)
 | 
						|
			pUmDevice->phy_crc_count += Value32;
 | 
						|
		return pUmDevice->phy_crc_count;
 | 
						|
	}
 | 
						|
	else if (pStats == 0) {
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		return (MM_GETSTATS64(pStats->dot3StatsFCSErrors));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
uint64_t
 | 
						|
bcm5700_rx_err_count(UM_DEVICE_BLOCK *pUmDevice)
 | 
						|
{
 | 
						|
	LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev;
 | 
						|
	T3_STATS_BLOCK *pStats = (T3_STATS_BLOCK *) pDevice->pStatsBlkVirt;
 | 
						|
 | 
						|
	if (pStats == 0)
 | 
						|
		return 0;
 | 
						|
	return (bcm5700_crc_count(pUmDevice) +
 | 
						|
		MM_GETSTATS64(pStats->dot3StatsAlignmentErrors) +
 | 
						|
		MM_GETSTATS64(pStats->etherStatsUndersizePkts) +
 | 
						|
		MM_GETSTATS64(pStats->etherStatsFragments) +
 | 
						|
		MM_GETSTATS64(pStats->dot3StatsFramesTooLong) +
 | 
						|
		MM_GETSTATS64(pStats->etherStatsJabbers));
 | 
						|
}
 | 
						|
 | 
						|
STATIC struct net_device_stats *
 | 
						|
bcm5700_get_stats(struct net_device *dev)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
	PT3_STATS_BLOCK pStats = (PT3_STATS_BLOCK) pDevice->pStatsBlkVirt;
 | 
						|
	struct net_device_stats *p_netstats = &pUmDevice->stats;
 | 
						|
 | 
						|
	if (pStats == 0)
 | 
						|
		return p_netstats;
 | 
						|
 | 
						|
	/* Get stats from LM */
 | 
						|
	p_netstats->rx_packets =
 | 
						|
		MM_GETSTATS(pStats->ifHCInUcastPkts) +
 | 
						|
		MM_GETSTATS(pStats->ifHCInMulticastPkts) +
 | 
						|
		MM_GETSTATS(pStats->ifHCInBroadcastPkts);
 | 
						|
	p_netstats->tx_packets =
 | 
						|
		MM_GETSTATS(pStats->ifHCOutUcastPkts) +
 | 
						|
		MM_GETSTATS(pStats->ifHCOutMulticastPkts) +
 | 
						|
		MM_GETSTATS(pStats->ifHCOutBroadcastPkts);
 | 
						|
	/* There counters seem to be innacurate. Use byte number accumulation 
 | 
						|
	   instead.
 | 
						|
	   p_netstats->rx_bytes = MM_GETSTATS(pStats->ifHCInOctets);
 | 
						|
	   p_netstats->tx_bytes = MM_GETSTATS(pStats->ifHCOutOctets);
 | 
						|
	*/
 | 
						|
	p_netstats->tx_errors =
 | 
						|
		MM_GETSTATS(pStats->dot3StatsInternalMacTransmitErrors) +
 | 
						|
		MM_GETSTATS(pStats->dot3StatsCarrierSenseErrors) +
 | 
						|
		MM_GETSTATS(pStats->ifOutDiscards) +
 | 
						|
		MM_GETSTATS(pStats->ifOutErrors);
 | 
						|
	p_netstats->multicast = MM_GETSTATS(pStats->ifHCInMulticastPkts);
 | 
						|
	p_netstats->collisions = MM_GETSTATS(pStats->etherStatsCollisions);
 | 
						|
	p_netstats->rx_length_errors =
 | 
						|
		MM_GETSTATS(pStats->dot3StatsFramesTooLong) +
 | 
						|
		MM_GETSTATS(pStats->etherStatsUndersizePkts);
 | 
						|
	p_netstats->rx_over_errors = MM_GETSTATS(pStats->nicNoMoreRxBDs);
 | 
						|
	p_netstats->rx_frame_errors =
 | 
						|
		MM_GETSTATS(pStats->dot3StatsAlignmentErrors);
 | 
						|
	p_netstats->rx_crc_errors = (unsigned long)
 | 
						|
		bcm5700_crc_count(pUmDevice);
 | 
						|
	p_netstats->rx_errors = (unsigned long)
 | 
						|
		bcm5700_rx_err_count(pUmDevice);
 | 
						|
 | 
						|
	p_netstats->tx_aborted_errors = MM_GETSTATS(pStats->ifOutDiscards);
 | 
						|
	p_netstats->tx_carrier_errors =
 | 
						|
		MM_GETSTATS(pStats->dot3StatsCarrierSenseErrors);
 | 
						|
 | 
						|
	return p_netstats;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
b57_suspend_chip(UM_DEVICE_BLOCK *pUmDevice)
 | 
						|
{
 | 
						|
	LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev;
 | 
						|
 | 
						|
	if (pUmDevice->opened) {
 | 
						|
		bcm5700_intr_off(pUmDevice);
 | 
						|
		netif_carrier_off(pUmDevice->dev);
 | 
						|
		netif_stop_queue(pUmDevice->dev);
 | 
						|
#ifdef BCM_TASKLET
 | 
						|
		tasklet_kill(&pUmDevice->tasklet);
 | 
						|
#endif
 | 
						|
		bcm5700_poll_wait(pUmDevice);
 | 
						|
	}
 | 
						|
	pUmDevice->suspended = 1;
 | 
						|
	LM_ShutdownChip(pDevice, LM_SUSPEND_RESET);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
b57_resume_chip(UM_DEVICE_BLOCK *pUmDevice)
 | 
						|
{
 | 
						|
	LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev;
 | 
						|
 | 
						|
	if (pUmDevice->suspended) {
 | 
						|
		pUmDevice->suspended = 0;
 | 
						|
		if (pUmDevice->opened) {
 | 
						|
			bcm5700_reset(pUmDevice->dev);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			LM_ShutdownChip(pDevice, LM_SHUTDOWN_RESET);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* Returns 0 on failure, 1 on success */
 | 
						|
int
 | 
						|
b57_test_intr(UM_DEVICE_BLOCK *pUmDevice)
 | 
						|
{
 | 
						|
	LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev;
 | 
						|
	int j;
 | 
						|
 | 
						|
	if (!pUmDevice->opened)
 | 
						|
		return 0;
 | 
						|
	pUmDevice->intr_test_result = 0;
 | 
						|
	pUmDevice->intr_test = 1;
 | 
						|
 | 
						|
	REG_WR(pDevice, HostCoalesce.Mode,
 | 
						|
		pDevice->CoalesceMode | HOST_COALESCE_ENABLE |
 | 
						|
		HOST_COALESCE_NOW);
 | 
						|
 | 
						|
	for (j = 0; j < 10; j++) {
 | 
						|
		if (pUmDevice->intr_test_result){
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		REG_WR(pDevice, HostCoalesce.Mode,
 | 
						|
		pDevice->CoalesceMode | HOST_COALESCE_ENABLE |
 | 
						|
		HOST_COALESCE_NOW);
 | 
						|
 | 
						|
		MM_Sleep(pDevice, 1);
 | 
						|
	}
 | 
						|
 | 
						|
	return pUmDevice->intr_test_result;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#ifdef SIOCETHTOOL
 | 
						|
 | 
						|
#ifdef ETHTOOL_GSTRINGS
 | 
						|
 | 
						|
#define ETH_NUM_STATS 30
 | 
						|
#define RX_CRC_IDX 5
 | 
						|
#define RX_MAC_ERR_IDX 14
 | 
						|
 | 
						|
struct {
 | 
						|
	char string[ETH_GSTRING_LEN];
 | 
						|
} bcm5700_stats_str_arr[ETH_NUM_STATS] = {
 | 
						|
	{ "rx_unicast_packets" },
 | 
						|
	{ "rx_multicast_packets" },
 | 
						|
	{ "rx_broadcast_packets" },
 | 
						|
	{ "rx_bytes" },
 | 
						|
	{ "rx_fragments" },
 | 
						|
	{ "rx_crc_errors" },	/* this needs to be calculated */
 | 
						|
	{ "rx_align_errors" },
 | 
						|
	{ "rx_xon_frames" },
 | 
						|
	{ "rx_xoff_frames" },
 | 
						|
	{ "rx_long_frames" },
 | 
						|
	{ "rx_short_frames" },
 | 
						|
	{ "rx_jabber" },
 | 
						|
	{ "rx_discards" },
 | 
						|
	{ "rx_errors" },
 | 
						|
	{ "rx_mac_errors" },	/* this needs to be calculated */
 | 
						|
	{ "tx_unicast_packets" },
 | 
						|
	{ "tx_multicast_packets" },
 | 
						|
	{ "tx_broadcast_packets" },
 | 
						|
	{ "tx_bytes" },
 | 
						|
	{ "tx_deferred" },
 | 
						|
	{ "tx_single_collisions" },
 | 
						|
	{ "tx_multi_collisions" },
 | 
						|
	{ "tx_total_collisions" },
 | 
						|
	{ "tx_excess_collisions" },
 | 
						|
	{ "tx_late_collisions" },
 | 
						|
	{ "tx_xon_frames" },
 | 
						|
	{ "tx_xoff_frames" },
 | 
						|
	{ "tx_internal_mac_errors" },
 | 
						|
	{ "tx_carrier_errors" },
 | 
						|
	{ "tx_errors" },
 | 
						|
};
 | 
						|
 | 
						|
#define STATS_OFFSET(offset_name) ((OFFSETOF(T3_STATS_BLOCK, offset_name)) / sizeof(uint64_t))
 | 
						|
 | 
						|
#ifdef __BIG_ENDIAN
 | 
						|
#define SWAP_DWORD_64(x) (x)
 | 
						|
#else
 | 
						|
#define SWAP_DWORD_64(x) ((x << 32) | (x >> 32))
 | 
						|
#endif
 | 
						|
 | 
						|
unsigned long bcm5700_stats_offset_arr[ETH_NUM_STATS] = {
 | 
						|
	STATS_OFFSET(ifHCInUcastPkts),
 | 
						|
	STATS_OFFSET(ifHCInMulticastPkts),
 | 
						|
	STATS_OFFSET(ifHCInBroadcastPkts),
 | 
						|
	STATS_OFFSET(ifHCInOctets),
 | 
						|
	STATS_OFFSET(etherStatsFragments),
 | 
						|
	0,
 | 
						|
	STATS_OFFSET(dot3StatsAlignmentErrors),
 | 
						|
	STATS_OFFSET(xonPauseFramesReceived),
 | 
						|
	STATS_OFFSET(xoffPauseFramesReceived),
 | 
						|
	STATS_OFFSET(dot3StatsFramesTooLong),
 | 
						|
	STATS_OFFSET(etherStatsUndersizePkts),
 | 
						|
	STATS_OFFSET(etherStatsJabbers),
 | 
						|
	STATS_OFFSET(ifInDiscards),
 | 
						|
	STATS_OFFSET(ifInErrors),
 | 
						|
	0,
 | 
						|
	STATS_OFFSET(ifHCOutUcastPkts),
 | 
						|
	STATS_OFFSET(ifHCOutMulticastPkts),
 | 
						|
	STATS_OFFSET(ifHCOutBroadcastPkts),
 | 
						|
	STATS_OFFSET(ifHCOutOctets),
 | 
						|
	STATS_OFFSET(dot3StatsDeferredTransmissions),
 | 
						|
	STATS_OFFSET(dot3StatsSingleCollisionFrames),
 | 
						|
	STATS_OFFSET(dot3StatsMultipleCollisionFrames),
 | 
						|
	STATS_OFFSET(etherStatsCollisions),
 | 
						|
	STATS_OFFSET(dot3StatsExcessiveCollisions),
 | 
						|
	STATS_OFFSET(dot3StatsLateCollisions),
 | 
						|
	STATS_OFFSET(outXonSent),
 | 
						|
	STATS_OFFSET(outXoffSent),
 | 
						|
	STATS_OFFSET(dot3StatsInternalMacTransmitErrors),
 | 
						|
	STATS_OFFSET(dot3StatsCarrierSenseErrors),
 | 
						|
	STATS_OFFSET(ifOutErrors),
 | 
						|
};
 | 
						|
 | 
						|
#endif /* ETHTOOL_GSTRINGS */
 | 
						|
 | 
						|
 | 
						|
#ifdef ETHTOOL_GREGS
 | 
						|
#if (LINUX_VERSION_CODE >= 0x02040f)
 | 
						|
static void
 | 
						|
bcm5700_get_reg_blk(UM_DEVICE_BLOCK *pUmDevice, u32 **buf, u32 start, u32 end,
 | 
						|
		int reserved)
 | 
						|
{
 | 
						|
	u32 offset;
 | 
						|
	LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev;
 | 
						|
 | 
						|
	if (reserved) {
 | 
						|
		memset(*buf, 0, end - start);
 | 
						|
		*buf = *buf + (end - start)/4;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	for (offset = start; offset < end; offset+=4, *buf = *buf + 1) {
 | 
						|
		if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)){
 | 
						|
			if (((offset >= 0x3400) && (offset < 0x3c00)) ||
 | 
						|
				((offset >= 0x5400) && (offset < 0x5800)) ||
 | 
						|
				((offset >= 0x6400) && (offset < 0x6800))) {
 | 
						|
				**buf = 0;
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		**buf = REG_RD_OFFSET(pDevice, offset);
 | 
						|
	}
 | 
						|
}
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
 | 
						|
{
 | 
						|
	struct ethtool_cmd ethcmd;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
 | 
						|
	if (mm_copy_from_user(ðcmd, useraddr, sizeof(ethcmd)))
 | 
						|
		return -EFAULT;
 | 
						|
 | 
						|
        switch (ethcmd.cmd) {
 | 
						|
#ifdef ETHTOOL_GDRVINFO
 | 
						|
        case ETHTOOL_GDRVINFO: {
 | 
						|
		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
 | 
						|
 | 
						|
		strcpy(info.driver,  bcm5700_driver);
 | 
						|
#ifdef INCLUDE_5701_AX_FIX
 | 
						|
		if(pDevice->ChipRevId == T3_CHIP_ID_5701_A0) {
 | 
						|
			extern int t3FwReleaseMajor;
 | 
						|
			extern int t3FwReleaseMinor;
 | 
						|
			extern int t3FwReleaseFix;
 | 
						|
 | 
						|
			sprintf(info.fw_version, "%i.%i.%i",
 | 
						|
				t3FwReleaseMajor, t3FwReleaseMinor,
 | 
						|
				t3FwReleaseFix);
 | 
						|
		}
 | 
						|
#endif
 | 
						|
		strcpy(info.fw_version, pDevice->BootCodeVer);
 | 
						|
		strcpy(info.version, bcm5700_version);
 | 
						|
#if (LINUX_VERSION_CODE <= 0x020422)
 | 
						|
		strcpy(info.bus_info, pUmDevice->pdev->slot_name);
 | 
						|
#else
 | 
						|
		strcpy(info.bus_info, pci_name(pUmDevice->pdev));
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifdef ETHTOOL_GEEPROM
 | 
						|
		BCM_EEDUMP_LEN(&info, pDevice->NvramSize);
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_GREGS
 | 
						|
		/* dump everything, including holes in the register space */
 | 
						|
		info.regdump_len = 0x6c00;
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_GSTATS
 | 
						|
		info.n_stats = ETH_NUM_STATS;
 | 
						|
#endif
 | 
						|
		if (mm_copy_to_user(useraddr, &info, sizeof(info)))
 | 
						|
			return -EFAULT;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
        case ETHTOOL_GSET: {
 | 
						|
		if ((pDevice->TbiFlags & ENABLE_TBI_FLAG)||
 | 
						|
			(pDevice->PhyFlags & PHY_IS_FIBER)) {
 | 
						|
			ethcmd.supported =
 | 
						|
				(SUPPORTED_1000baseT_Full |
 | 
						|
				SUPPORTED_Autoneg);
 | 
						|
			ethcmd.supported |= SUPPORTED_FIBRE;
 | 
						|
			ethcmd.port = PORT_FIBRE;
 | 
						|
		} else {
 | 
						|
			ethcmd.supported =
 | 
						|
				(SUPPORTED_10baseT_Half |
 | 
						|
				SUPPORTED_10baseT_Full |
 | 
						|
				SUPPORTED_100baseT_Half |
 | 
						|
				SUPPORTED_100baseT_Full |
 | 
						|
				SUPPORTED_1000baseT_Half |
 | 
						|
				SUPPORTED_1000baseT_Full |
 | 
						|
				SUPPORTED_Autoneg);
 | 
						|
			ethcmd.supported |= SUPPORTED_TP;
 | 
						|
			ethcmd.port = PORT_TP;
 | 
						|
		}
 | 
						|
 | 
						|
		ethcmd.transceiver = XCVR_INTERNAL;
 | 
						|
		ethcmd.phy_address = 0;
 | 
						|
 | 
						|
		if (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS)
 | 
						|
			ethcmd.speed = SPEED_1000;
 | 
						|
		else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS)
 | 
						|
			ethcmd.speed = SPEED_100;
 | 
						|
		else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS)
 | 
						|
			ethcmd.speed = SPEED_10;
 | 
						|
		else
 | 
						|
			ethcmd.speed = 0;
 | 
						|
 | 
						|
		if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL)
 | 
						|
			ethcmd.duplex = DUPLEX_FULL;
 | 
						|
		else
 | 
						|
			ethcmd.duplex = DUPLEX_HALF;
 | 
						|
 | 
						|
		if (pDevice->DisableAutoNeg == FALSE) {
 | 
						|
			ethcmd.autoneg = AUTONEG_ENABLE;
 | 
						|
			ethcmd.advertising = ADVERTISED_Autoneg;
 | 
						|
			if ((pDevice->TbiFlags & ENABLE_TBI_FLAG) ||
 | 
						|
				(pDevice->PhyFlags & PHY_IS_FIBER)) {
 | 
						|
				ethcmd.advertising |=
 | 
						|
					ADVERTISED_1000baseT_Full |
 | 
						|
					ADVERTISED_FIBRE;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				ethcmd.advertising |=
 | 
						|
					ADVERTISED_TP;
 | 
						|
				if (pDevice->advertising &
 | 
						|
					PHY_AN_AD_10BASET_HALF) {
 | 
						|
 | 
						|
					ethcmd.advertising |=
 | 
						|
						ADVERTISED_10baseT_Half;
 | 
						|
				}
 | 
						|
				if (pDevice->advertising &
 | 
						|
					PHY_AN_AD_10BASET_FULL) {
 | 
						|
 | 
						|
					ethcmd.advertising |=
 | 
						|
						ADVERTISED_10baseT_Full;
 | 
						|
				}
 | 
						|
				if (pDevice->advertising &
 | 
						|
					PHY_AN_AD_100BASETX_HALF) {
 | 
						|
 | 
						|
					ethcmd.advertising |=
 | 
						|
						ADVERTISED_100baseT_Half;
 | 
						|
				}
 | 
						|
				if (pDevice->advertising &
 | 
						|
					PHY_AN_AD_100BASETX_FULL) {
 | 
						|
 | 
						|
					ethcmd.advertising |=
 | 
						|
						ADVERTISED_100baseT_Full;
 | 
						|
				}
 | 
						|
				if (pDevice->advertising1000 &
 | 
						|
					BCM540X_AN_AD_1000BASET_HALF) {
 | 
						|
 | 
						|
					ethcmd.advertising |=
 | 
						|
						ADVERTISED_1000baseT_Half;
 | 
						|
				}
 | 
						|
				if (pDevice->advertising1000 &
 | 
						|
					BCM540X_AN_AD_1000BASET_FULL) {
 | 
						|
 | 
						|
					ethcmd.advertising |=
 | 
						|
						ADVERTISED_1000baseT_Full;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			ethcmd.autoneg = AUTONEG_DISABLE;
 | 
						|
			ethcmd.advertising = 0;
 | 
						|
		}
 | 
						|
 | 
						|
		ethcmd.maxtxpkt = pDevice->TxMaxCoalescedFrames;
 | 
						|
		ethcmd.maxrxpkt = pDevice->RxMaxCoalescedFrames;
 | 
						|
 | 
						|
		if(mm_copy_to_user(useraddr, ðcmd, sizeof(ethcmd)))
 | 
						|
			return -EFAULT;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	case ETHTOOL_SSET: {
 | 
						|
		unsigned long flags;
 | 
						|
 | 
						|
		if(!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (ethcmd.autoneg == AUTONEG_ENABLE) {
 | 
						|
			pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO;
 | 
						|
			pDevice->RequestedDuplexMode = LM_DUPLEX_MODE_UNKNOWN;
 | 
						|
			pDevice->DisableAutoNeg = FALSE;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			if (ethcmd.speed == SPEED_1000 &&
 | 
						|
				pDevice->PhyFlags & PHY_NO_GIGABIT)
 | 
						|
					return -EINVAL;
 | 
						|
 | 
						|
			if (ethcmd.speed == SPEED_1000 &&
 | 
						|
			    (pDevice->TbiFlags & ENABLE_TBI_FLAG ||
 | 
						|
			     pDevice->PhyFlags & PHY_IS_FIBER ) ) {
 | 
						|
 | 
						|
				pDevice->RequestedLineSpeed =
 | 
						|
					LM_LINE_SPEED_1000MBPS;
 | 
						|
 | 
						|
				pDevice->RequestedDuplexMode =
 | 
						|
					LM_DUPLEX_MODE_FULL;
 | 
						|
			}
 | 
						|
			else if (ethcmd.speed == SPEED_100 &&
 | 
						|
			        !(pDevice->TbiFlags & ENABLE_TBI_FLAG) &&
 | 
						|
			     	!(pDevice->PhyFlags & PHY_IS_FIBER)) {
 | 
						|
 | 
						|
				pDevice->RequestedLineSpeed =
 | 
						|
					LM_LINE_SPEED_100MBPS;
 | 
						|
			}
 | 
						|
			else if (ethcmd.speed == SPEED_10  &&
 | 
						|
			        !(pDevice->TbiFlags & ENABLE_TBI_FLAG) &&
 | 
						|
			     	!(pDevice->PhyFlags & PHY_IS_FIBER)) {
 | 
						|
 | 
						|
                                pDevice->RequestedLineSpeed =
 | 
						|
					LM_LINE_SPEED_10MBPS;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				return -EINVAL;
 | 
						|
			}
 | 
						|
 | 
						|
			pDevice->DisableAutoNeg = TRUE;
 | 
						|
			if (ethcmd.duplex == DUPLEX_FULL) {
 | 
						|
				pDevice->RequestedDuplexMode =
 | 
						|
					LM_DUPLEX_MODE_FULL;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				if (!(pDevice->TbiFlags & ENABLE_TBI_FLAG) &&
 | 
						|
			     	    !(pDevice->PhyFlags & PHY_IS_FIBER)  ) {
 | 
						|
 | 
						|
					pDevice->RequestedDuplexMode =
 | 
						|
							LM_DUPLEX_MODE_HALF;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (netif_running(dev)) {
 | 
						|
			BCM5700_PHY_LOCK(pUmDevice, flags);
 | 
						|
			LM_SetupPhy(pDevice);
 | 
						|
			BCM5700_PHY_UNLOCK(pUmDevice, flags);
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#ifdef ETHTOOL_GWOL
 | 
						|
#ifdef BCM_WOL
 | 
						|
	case ETHTOOL_GWOL: {
 | 
						|
		struct ethtool_wolinfo wol = {ETHTOOL_GWOL};
 | 
						|
 | 
						|
		if (((pDevice->TbiFlags & ENABLE_TBI_FLAG) &&
 | 
						|
			!(pDevice->Flags & FIBER_WOL_CAPABLE_FLAG)) ||
 | 
						|
			(pDevice->Flags & DISABLE_D3HOT_FLAG)) {
 | 
						|
			wol.supported = 0;
 | 
						|
			wol.wolopts = 0;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			wol.supported = WAKE_MAGIC;
 | 
						|
			if (pDevice->WakeUpMode == LM_WAKE_UP_MODE_MAGIC_PACKET)
 | 
						|
			{
 | 
						|
				wol.wolopts = WAKE_MAGIC;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				wol.wolopts = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (mm_copy_to_user(useraddr, &wol, sizeof(wol)))
 | 
						|
			return -EFAULT;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	case ETHTOOL_SWOL: {
 | 
						|
		struct ethtool_wolinfo wol;
 | 
						|
 | 
						|
		if(!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (mm_copy_from_user(&wol, useraddr, sizeof(wol)))
 | 
						|
			return -EFAULT;
 | 
						|
		if ((((pDevice->TbiFlags & ENABLE_TBI_FLAG) &&
 | 
						|
			!(pDevice->Flags & FIBER_WOL_CAPABLE_FLAG)) ||
 | 
						|
			(pDevice->Flags & DISABLE_D3HOT_FLAG)) &&
 | 
						|
			wol.wolopts) {
 | 
						|
			return -EINVAL;
 | 
						|
		}
 | 
						|
 | 
						|
		if ((wol.wolopts & ~WAKE_MAGIC) != 0) {
 | 
						|
			return -EINVAL;
 | 
						|
		}
 | 
						|
		if (wol.wolopts & WAKE_MAGIC) {
 | 
						|
			pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET;
 | 
						|
			pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_NONE;
 | 
						|
			pDevice->WakeUpMode = LM_WAKE_UP_MODE_NONE;
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
        }
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_GLINK
 | 
						|
	case ETHTOOL_GLINK: {
 | 
						|
		struct ethtool_value edata = {ETHTOOL_GLINK};
 | 
						|
 | 
						|
		/* ifup only waits for 5 seconds for link up */
 | 
						|
		/* NIC may take more than 5 seconds to establish link */
 | 
						|
		if ((pUmDevice->delayed_link_ind > 0) &&
 | 
						|
			delay_link[pUmDevice->index])
 | 
						|
			return -EOPNOTSUPP;
 | 
						|
 | 
						|
		if (pDevice->LinkStatus == LM_STATUS_LINK_ACTIVE) {
 | 
						|
			edata.data =  1;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			edata.data =  0;
 | 
						|
		}
 | 
						|
		if (mm_copy_to_user(useraddr, &edata, sizeof(edata)))
 | 
						|
			return -EFAULT;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_NWAY_RST
 | 
						|
	case ETHTOOL_NWAY_RST: {
 | 
						|
		LM_UINT32 phyctrl;
 | 
						|
		unsigned long flags;
 | 
						|
 | 
						|
		if(!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (pDevice->DisableAutoNeg) {
 | 
						|
			return -EINVAL;
 | 
						|
		}
 | 
						|
		if (!netif_running(dev))
 | 
						|
			return -EAGAIN;
 | 
						|
		BCM5700_PHY_LOCK(pUmDevice, flags);
 | 
						|
		if (pDevice->TbiFlags & ENABLE_TBI_FLAG) { 
 | 
						|
			pDevice->RequestedLineSpeed = LM_LINE_SPEED_1000MBPS;
 | 
						|
			pDevice->DisableAutoNeg = TRUE;
 | 
						|
			LM_SetupPhy(pDevice);
 | 
						|
 | 
						|
			pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO;
 | 
						|
			pDevice->DisableAutoNeg = FALSE;
 | 
						|
			LM_SetupPhy(pDevice);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			if ((T3_ASIC_REV(pDevice->ChipRevId) ==
 | 
						|
					T3_ASIC_REV_5703) ||
 | 
						|
				(T3_ASIC_REV(pDevice->ChipRevId) ==
 | 
						|
					T3_ASIC_REV_5704) ||
 | 
						|
				(T3_ASIC_REV(pDevice->ChipRevId) ==
 | 
						|
					T3_ASIC_REV_5705))
 | 
						|
			{
 | 
						|
				LM_ResetPhy(pDevice);
 | 
						|
				LM_SetupPhy(pDevice);
 | 
						|
			}
 | 
						|
			pDevice->PhyFlags &= ~PHY_FIBER_FALLBACK;
 | 
						|
			LM_ReadPhy(pDevice, PHY_CTRL_REG, &phyctrl);
 | 
						|
			LM_WritePhy(pDevice, PHY_CTRL_REG, phyctrl |
 | 
						|
				PHY_CTRL_AUTO_NEG_ENABLE |
 | 
						|
				PHY_CTRL_RESTART_AUTO_NEG);
 | 
						|
		}
 | 
						|
		BCM5700_PHY_UNLOCK(pUmDevice, flags);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_GEEPROM
 | 
						|
	case ETHTOOL_GEEPROM: {
 | 
						|
		struct ethtool_eeprom eeprom;
 | 
						|
		LM_UINT32 *buf = 0;
 | 
						|
		LM_UINT32 buf1[64/4];
 | 
						|
		int i, j, offset, len;
 | 
						|
 | 
						|
		if (mm_copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
 | 
						|
			return -EFAULT;
 | 
						|
 | 
						|
		if (eeprom.offset >= pDevice->NvramSize)
 | 
						|
			return -EFAULT;
 | 
						|
 | 
						|
		/* maximum data limited */
 | 
						|
		/* to read more, call again with a different offset */
 | 
						|
		if (eeprom.len > 0x800) {
 | 
						|
			eeprom.len = 0x800;
 | 
						|
			if (mm_copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
 | 
						|
				return -EFAULT;
 | 
						|
		}
 | 
						|
 | 
						|
		if (eeprom.len > 64) {
 | 
						|
			buf = kmalloc(eeprom.len, GFP_KERNEL);
 | 
						|
			if (!buf)
 | 
						|
				return -ENOMEM;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			buf = buf1;
 | 
						|
		}
 | 
						|
		useraddr += offsetof(struct ethtool_eeprom, data);
 | 
						|
 | 
						|
		offset = eeprom.offset;
 | 
						|
		len = eeprom.len;
 | 
						|
		if (offset & 3) {
 | 
						|
			offset &= 0xfffffffc;
 | 
						|
			len += (offset & 3);
 | 
						|
		}
 | 
						|
		len = (len + 3) & 0xfffffffc;
 | 
						|
		for (i = 0, j = 0; j < len; i++, j += 4) {
 | 
						|
			if (LM_NvramRead(pDevice, offset + j, buf + i) !=
 | 
						|
				LM_STATUS_SUCCESS) {
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (j >= len) {
 | 
						|
			buf += (eeprom.offset & 3);
 | 
						|
			i = mm_copy_to_user(useraddr, buf, eeprom.len);
 | 
						|
		}
 | 
						|
		if (eeprom.len > 64) {
 | 
						|
			kfree(buf);
 | 
						|
		}
 | 
						|
		if ((j < len) || i)
 | 
						|
			return -EFAULT;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	case ETHTOOL_SEEPROM: {
 | 
						|
		struct ethtool_eeprom eeprom;
 | 
						|
		LM_UINT32 buf[64/4];
 | 
						|
		int i, offset, len;
 | 
						|
 | 
						|
		if(!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (mm_copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
 | 
						|
			return -EFAULT;
 | 
						|
 | 
						|
		if ((eeprom.offset & 3) || (eeprom.len & 3) ||
 | 
						|
			(eeprom.offset >= pDevice->NvramSize)) {
 | 
						|
			return -EFAULT;
 | 
						|
		}
 | 
						|
 | 
						|
		if ((eeprom.offset + eeprom.len) >= pDevice->NvramSize) {
 | 
						|
			eeprom.len = pDevice->NvramSize - eeprom.offset;
 | 
						|
		}
 | 
						|
 | 
						|
		useraddr += offsetof(struct ethtool_eeprom, data);
 | 
						|
 | 
						|
		len = eeprom.len;
 | 
						|
		offset = eeprom.offset;
 | 
						|
		for (; len > 0; ) {
 | 
						|
			if (len < 64)
 | 
						|
				i = len;
 | 
						|
			else
 | 
						|
				i = 64;
 | 
						|
			if (mm_copy_from_user(&buf, useraddr, i))
 | 
						|
				return -EFAULT;
 | 
						|
 | 
						|
			bcm5700_intr_off(pUmDevice);
 | 
						|
			/* Prevent race condition on Grc.Mode register */
 | 
						|
			bcm5700_poll_wait(pUmDevice);
 | 
						|
 | 
						|
			if (LM_NvramWriteBlock(pDevice, offset, buf, i/4) !=
 | 
						|
				LM_STATUS_SUCCESS) {
 | 
						|
				bcm5700_intr_on(pUmDevice);
 | 
						|
				return -EFAULT;
 | 
						|
			}
 | 
						|
			bcm5700_intr_on(pUmDevice);
 | 
						|
			len -= i;
 | 
						|
			offset += i;
 | 
						|
			useraddr += i;
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_GREGS
 | 
						|
#if (LINUX_VERSION_CODE >= 0x02040f)
 | 
						|
	case ETHTOOL_GREGS: {
 | 
						|
		struct ethtool_regs eregs;
 | 
						|
		LM_UINT32 *buf, *buf1;
 | 
						|
		unsigned int i;
 | 
						|
 | 
						|
		if(!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (pDevice->Flags & UNDI_FIX_FLAG)
 | 
						|
			return -EOPNOTSUPP;
 | 
						|
		if (mm_copy_from_user(&eregs, useraddr, sizeof(eregs)))
 | 
						|
			return -EFAULT;
 | 
						|
		if (eregs.len > 0x6c00)
 | 
						|
			eregs.len = 0x6c00;
 | 
						|
		eregs.version = 0x0;
 | 
						|
		if (mm_copy_to_user(useraddr, &eregs, sizeof(eregs)))
 | 
						|
			return -EFAULT;
 | 
						|
		buf = buf1 = kmalloc(eregs.len, GFP_KERNEL);
 | 
						|
		if (!buf)
 | 
						|
			return -ENOMEM;
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0,      0xb0,   0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0xb0,   0x200,  1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x200,  0x8f0,  0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x8f0,  0xc00,  1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0xc00,  0xce0,  0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0xce0,  0x1000, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x1000, 0x1004, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x1004, 0x1400, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x1400, 0x1480, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x1480, 0x1800, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x1800, 0x1848, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x1848, 0x1c00, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x1c00, 0x1c04, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x1c04, 0x2000, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x2000, 0x225c, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x225c, 0x2400, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x2400, 0x24c4, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x24c4, 0x2800, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x2800, 0x2804, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x2804, 0x2c00, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x2c00, 0x2c20, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x2c20, 0x3000, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x3000, 0x3014, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x3014, 0x3400, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x3400, 0x3408, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x3408, 0x3800, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x3800, 0x3808, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x3808, 0x3c00, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x3c00, 0x3d00, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x3d00, 0x4000, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x4000, 0x4010, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x4010, 0x4400, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x4400, 0x4458, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x4458, 0x4800, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x4800, 0x4808, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x4808, 0x4c00, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x4c00, 0x4c08, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x4c08, 0x5000, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x5000, 0x5050, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x5050, 0x5400, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x5400, 0x5450, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x5450, 0x5800, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x5800, 0x5a10, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x5a10, 0x6000, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x6000, 0x600c, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x600c, 0x6400, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x6400, 0x6404, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x6404, 0x6800, 1);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x6800, 0x6848, 0);
 | 
						|
		bcm5700_get_reg_blk(pUmDevice, &buf, 0x6848, 0x6c00, 1);
 | 
						|
 | 
						|
		i = mm_copy_to_user(useraddr + sizeof(eregs), buf1, eregs.len);
 | 
						|
		kfree(buf1);
 | 
						|
		if (i)
 | 
						|
			return -EFAULT;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_GPAUSEPARAM
 | 
						|
	case ETHTOOL_GPAUSEPARAM: {
 | 
						|
		struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM };
 | 
						|
 | 
						|
		if (!pDevice->DisableAutoNeg) {
 | 
						|
			epause.autoneg = (pDevice->FlowControlCap &
 | 
						|
				LM_FLOW_CONTROL_AUTO_PAUSE) != 0;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			epause.autoneg = 0;
 | 
						|
		}
 | 
						|
		epause.rx_pause =
 | 
						|
			(pDevice->FlowControl &
 | 
						|
			LM_FLOW_CONTROL_RECEIVE_PAUSE) != 0;
 | 
						|
		epause.tx_pause =
 | 
						|
			(pDevice->FlowControl &
 | 
						|
			LM_FLOW_CONTROL_TRANSMIT_PAUSE) != 0;
 | 
						|
		if (mm_copy_to_user(useraddr, &epause, sizeof(epause)))
 | 
						|
			return -EFAULT;
 | 
						|
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	case ETHTOOL_SPAUSEPARAM: {
 | 
						|
		struct ethtool_pauseparam epause;
 | 
						|
		unsigned long flags;
 | 
						|
 | 
						|
		if(!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (mm_copy_from_user(&epause, useraddr, sizeof(epause)))
 | 
						|
			return -EFAULT;
 | 
						|
		pDevice->FlowControlCap = 0;
 | 
						|
		if (epause.autoneg && !pDevice->DisableAutoNeg) {
 | 
						|
			pDevice->FlowControlCap |= LM_FLOW_CONTROL_AUTO_PAUSE;
 | 
						|
		}
 | 
						|
		if (epause.rx_pause)  {
 | 
						|
			pDevice->FlowControlCap |=
 | 
						|
				LM_FLOW_CONTROL_RECEIVE_PAUSE;
 | 
						|
		}
 | 
						|
		if (epause.tx_pause)  {
 | 
						|
			pDevice->FlowControlCap |=
 | 
						|
				LM_FLOW_CONTROL_TRANSMIT_PAUSE;
 | 
						|
		}
 | 
						|
		if (netif_running(dev)) {
 | 
						|
			BCM5700_PHY_LOCK(pUmDevice, flags);
 | 
						|
			LM_SetupPhy(pDevice);
 | 
						|
			BCM5700_PHY_UNLOCK(pUmDevice, flags);
 | 
						|
		}
 | 
						|
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_GRXCSUM
 | 
						|
	case ETHTOOL_GRXCSUM: {
 | 
						|
		struct ethtool_value edata = { ETHTOOL_GRXCSUM };
 | 
						|
 | 
						|
		edata.data =
 | 
						|
			(pDevice->TaskToOffload &
 | 
						|
			LM_TASK_OFFLOAD_RX_TCP_CHECKSUM) != 0;
 | 
						|
		if (mm_copy_to_user(useraddr, &edata, sizeof(edata)))
 | 
						|
			return -EFAULT;
 | 
						|
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	case ETHTOOL_SRXCSUM: {
 | 
						|
		struct ethtool_value edata;
 | 
						|
 | 
						|
		if(!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (mm_copy_from_user(&edata, useraddr, sizeof(edata)))
 | 
						|
			return -EFAULT;
 | 
						|
		if (edata.data) {
 | 
						|
			if (!(pDevice->TaskOffloadCap &
 | 
						|
				LM_TASK_OFFLOAD_TX_TCP_CHECKSUM)) {
 | 
						|
 | 
						|
				return -EINVAL;
 | 
						|
			}
 | 
						|
			pDevice->TaskToOffload |=
 | 
						|
				LM_TASK_OFFLOAD_RX_TCP_CHECKSUM |
 | 
						|
				LM_TASK_OFFLOAD_RX_UDP_CHECKSUM;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			pDevice->TaskToOffload &=
 | 
						|
				~(LM_TASK_OFFLOAD_RX_TCP_CHECKSUM |
 | 
						|
				LM_TASK_OFFLOAD_RX_UDP_CHECKSUM);
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	case ETHTOOL_GTXCSUM: {
 | 
						|
		struct ethtool_value edata = { ETHTOOL_GTXCSUM };
 | 
						|
 | 
						|
		edata.data =
 | 
						|
			(dev->features & get_csum_flag( pDevice->ChipRevId)) != 0;
 | 
						|
		if (mm_copy_to_user(useraddr, &edata, sizeof(edata)))
 | 
						|
			return -EFAULT;
 | 
						|
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	case ETHTOOL_STXCSUM: {
 | 
						|
		struct ethtool_value edata;
 | 
						|
 | 
						|
		if(!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (mm_copy_from_user(&edata, useraddr, sizeof(edata)))
 | 
						|
			return -EFAULT;
 | 
						|
		if (edata.data) {
 | 
						|
			if (!(pDevice->TaskOffloadCap &
 | 
						|
				LM_TASK_OFFLOAD_TX_TCP_CHECKSUM)) {
 | 
						|
 | 
						|
				return -EINVAL;
 | 
						|
			}
 | 
						|
			dev->features |= get_csum_flag( pDevice->ChipRevId);
 | 
						|
			pDevice->TaskToOffload |=
 | 
						|
				LM_TASK_OFFLOAD_TX_TCP_CHECKSUM |
 | 
						|
				LM_TASK_OFFLOAD_TX_UDP_CHECKSUM;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			dev->features &= ~get_csum_flag( pDevice->ChipRevId);
 | 
						|
			pDevice->TaskToOffload &=
 | 
						|
				~(LM_TASK_OFFLOAD_TX_TCP_CHECKSUM |
 | 
						|
				LM_TASK_OFFLOAD_TX_UDP_CHECKSUM);
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	case ETHTOOL_GSG: {
 | 
						|
		struct ethtool_value edata = { ETHTOOL_GSG };
 | 
						|
 | 
						|
		edata.data =
 | 
						|
			(dev->features & NETIF_F_SG) != 0;
 | 
						|
		if (mm_copy_to_user(useraddr, &edata, sizeof(edata)))
 | 
						|
			return -EFAULT;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	case ETHTOOL_SSG: {
 | 
						|
		struct ethtool_value edata;
 | 
						|
 | 
						|
		if(!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (mm_copy_from_user(&edata, useraddr, sizeof(edata)))
 | 
						|
			return -EFAULT;
 | 
						|
		if (edata.data) {
 | 
						|
			dev->features |= NETIF_F_SG;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			dev->features &= ~NETIF_F_SG;
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_GRINGPARAM
 | 
						|
	case ETHTOOL_GRINGPARAM: {
 | 
						|
		struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
 | 
						|
 | 
						|
		ering.rx_max_pending = T3_STD_RCV_RCB_ENTRY_COUNT - 1;
 | 
						|
		ering.rx_pending = pDevice->RxStdDescCnt;
 | 
						|
		ering.rx_mini_max_pending = 0;
 | 
						|
		ering.rx_mini_pending = 0;
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
		ering.rx_jumbo_max_pending = T3_JUMBO_RCV_RCB_ENTRY_COUNT - 1;
 | 
						|
		ering.rx_jumbo_pending = pDevice->RxJumboDescCnt;
 | 
						|
#else
 | 
						|
		ering.rx_jumbo_max_pending = 0;
 | 
						|
		ering.rx_jumbo_pending = 0;
 | 
						|
#endif
 | 
						|
		ering.tx_max_pending = MAX_TX_PACKET_DESC_COUNT - 1;
 | 
						|
		ering.tx_pending = pDevice->TxPacketDescCnt;
 | 
						|
		if (mm_copy_to_user(useraddr, &ering, sizeof(ering)))
 | 
						|
			return -EFAULT;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_PHYS_ID
 | 
						|
	case ETHTOOL_PHYS_ID: {
 | 
						|
		struct ethtool_value edata;
 | 
						|
 | 
						|
		if(!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
		if (mm_copy_from_user(&edata, useraddr, sizeof(edata)))
 | 
						|
			return -EFAULT;
 | 
						|
		if (LM_BlinkLED(pDevice, edata.data) == LM_STATUS_SUCCESS)
 | 
						|
			return 0;
 | 
						|
		return -EINTR;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_GSTRINGS
 | 
						|
	case ETHTOOL_GSTRINGS: {
 | 
						|
		struct ethtool_gstrings egstr = { ETHTOOL_GSTRINGS };
 | 
						|
 | 
						|
		if (mm_copy_from_user(&egstr, useraddr, sizeof(egstr)))
 | 
						|
			return -EFAULT;
 | 
						|
		switch(egstr.string_set) {
 | 
						|
#ifdef ETHTOOL_GSTATS
 | 
						|
		case ETH_SS_STATS:
 | 
						|
			egstr.len = ETH_NUM_STATS;
 | 
						|
			if (mm_copy_to_user(useraddr, &egstr, sizeof(egstr)))
 | 
						|
				return -EFAULT;
 | 
						|
			if (mm_copy_to_user(useraddr + sizeof(egstr),
 | 
						|
				bcm5700_stats_str_arr,
 | 
						|
				sizeof(bcm5700_stats_str_arr)))
 | 
						|
				return -EFAULT;
 | 
						|
			return 0;
 | 
						|
#endif
 | 
						|
		default:
 | 
						|
			return -EOPNOTSUPP;
 | 
						|
		}
 | 
						|
		}
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_GSTATS
 | 
						|
	case ETHTOOL_GSTATS: {
 | 
						|
		struct ethtool_stats estats = { ETHTOOL_GSTATS };
 | 
						|
		uint64_t stats[ETH_NUM_STATS];
 | 
						|
		int i;
 | 
						|
		uint64_t *pStats =
 | 
						|
			(uint64_t *) pDevice->pStatsBlkVirt;
 | 
						|
 | 
						|
		estats.n_stats = ETH_NUM_STATS;
 | 
						|
		if (pStats == 0) {
 | 
						|
			memset(stats, 0, sizeof(stats));
 | 
						|
		}
 | 
						|
		else {
 | 
						|
 | 
						|
			for (i = 0; i < ETH_NUM_STATS; i++) {
 | 
						|
				if (bcm5700_stats_offset_arr[i] != 0) {
 | 
						|
					stats[i] = SWAP_DWORD_64(*(pStats +
 | 
						|
						bcm5700_stats_offset_arr[i]));
 | 
						|
				}
 | 
						|
				else if (i == RX_CRC_IDX) {
 | 
						|
					stats[i] =
 | 
						|
						bcm5700_crc_count(pUmDevice);
 | 
						|
				}
 | 
						|
				else if (i == RX_MAC_ERR_IDX) {
 | 
						|
					stats[i] =
 | 
						|
						bcm5700_rx_err_count(pUmDevice);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (mm_copy_to_user(useraddr, &estats, sizeof(estats))) {
 | 
						|
			return -EFAULT;
 | 
						|
		}
 | 
						|
		if (mm_copy_to_user(useraddr + sizeof(estats), &stats,
 | 
						|
			sizeof(stats))) {
 | 
						|
			return -EFAULT;
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_GTSO
 | 
						|
	case ETHTOOL_GTSO: {
 | 
						|
		struct ethtool_value edata = { ETHTOOL_GTSO };
 | 
						|
 | 
						|
#ifdef BCM_TSO
 | 
						|
		edata.data =
 | 
						|
			(dev->features & NETIF_F_TSO) != 0;
 | 
						|
#else
 | 
						|
		edata.data = 0;
 | 
						|
#endif
 | 
						|
		if (mm_copy_to_user(useraddr, &edata, sizeof(edata)))
 | 
						|
			return -EFAULT;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef ETHTOOL_STSO
 | 
						|
	case ETHTOOL_STSO: {
 | 
						|
#ifdef BCM_TSO
 | 
						|
		struct ethtool_value edata;
 | 
						|
 | 
						|
		if (!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
 | 
						|
		if (mm_copy_from_user(&edata, useraddr, sizeof(edata)))
 | 
						|
			return -EFAULT;
 | 
						|
 | 
						|
		if (!(pDevice->TaskToOffload &
 | 
						|
			LM_TASK_OFFLOAD_TCP_SEGMENTATION)) {
 | 
						|
			return -EINVAL;
 | 
						|
		}
 | 
						|
 | 
						|
		dev->features &= ~NETIF_F_TSO;
 | 
						|
 | 
						|
		if (edata.data) {
 | 
						|
			if (T3_ASIC_5714_FAMILY(pDevice->ChipRevId) &&
 | 
						|
			   (dev->mtu > 1500)) {
 | 
						|
				printk(KERN_ALERT "%s: Jumbo Frames and TSO cannot simultaneously be enabled. Jumbo Frames enabled. TSO disabled.\n", dev->name);
 | 
						|
			return -EINVAL;
 | 
						|
			} else {
 | 
						|
				dev->features |= NETIF_F_TSO;
 | 
						|
			}
 | 
						|
	        }
 | 
						|
		return 0;
 | 
						|
#else
 | 
						|
		return -EINVAL;
 | 
						|
#endif
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	return -EOPNOTSUPP;
 | 
						|
}
 | 
						|
#endif /* #ifdef SIOCETHTOOL */
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x20400) && (LINUX_VERSION_CODE < 0x20600)
 | 
						|
#include <linux/iobuf.h>
 | 
						|
#endif
 | 
						|
 | 
						|
/* Provide ioctl() calls to examine the MII xcvr state. */
 | 
						|
STATIC int bcm5700_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
	u16 *data = (u16 *)&rq->ifr_data;
 | 
						|
	u32 value = 0;
 | 
						|
	u16 page_num =0, addr_num =0, len =0;
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	switch(cmd) {
 | 
						|
	case SIOCGREG_STATUS: //Get register
 | 
						|
	{
 | 
						|
		struct reg_ioctl_data *rdata =(struct reg_ioctl_data *)rq->ifr_data;
 | 
						|
                robo_info_t *robo = (robo_info_t *)pUmDevice->robo;
 | 
						|
		page_num = rdata->page_num;
 | 
						|
		addr_num = rdata->addr_num;
 | 
						|
		len = rdata->len;
 | 
						|
                printk("b57um SIOCGREG_STATUS cmd page[0x%x]addr[0x%x]len[%d].\n",page_num,addr_num,len);
 | 
						|
		if (len == 6)
 | 
						|
		{
 | 
						|
			ReadDataFromRegister(robo,page_num,addr_num,len,(void *)&rdata->val_out);
 | 
						|
			printk("val[0x%04x-0x%04x-0x%04x].\n",rdata->val_out[0],rdata->val_out[1],rdata->val_out[2]);
 | 
						|
		}
 | 
						|
		else if (len == 8)
 | 
						|
		{
 | 
						|
			ReadDataFromRegister(robo,page_num,addr_num,len,(void *)&rdata->val_out);
 | 
						|
                        printk("val[0x%04x%04x-0x%04x%04x].\n",rdata->val_out[0],rdata->val_out[1],
 | 
						|
				rdata->val_out[2],rdata->val_out[3]);
 | 
						|
		}
 | 
						|
		else if (len == 4) 
 | 
						|
		{
 | 
						|
			ReadDataFromRegister(robo,page_num,addr_num,len,(void *)&rdata->val_out);
 | 
						|
                        printk("val[0x%04x%04x].\n",rdata->val_out[0],rdata->val_out[1]);
 | 
						|
		}
 | 
						|
		else 
 | 
						|
		{
 | 
						|
                        ReadDataFromRegister(robo,page_num,addr_num,len,(void *)&rdata->val_out);
 | 
						|
                        printk("val[0x%04x].\n",rdata->val_out[0]);
 | 
						|
 | 
						|
		}
 | 
						|
                if (mm_copy_to_user(rq->ifr_data, rdata, sizeof(struct reg_ioctl_data)))
 | 
						|
		{
 | 
						|
			printk("Fail mm_copy_to_user.\n");
 | 
						|
                        return -EFAULT;
 | 
						|
		}
 | 
						|
                return 0;
 | 
						|
	}
 | 
						|
	break;
 | 
						|
	case SIOCSREG_STATUS://Set register
 | 
						|
	{
 | 
						|
                struct reg_ioctl_data * wdata =(struct reg_ioctl_data *)rq->ifr_data;
 | 
						|
		len = wdata->len;
 | 
						|
		page_num = wdata->page_num;
 | 
						|
		addr_num = wdata->addr_num;
 | 
						|
                robo_info_t *robo = (robo_info_t *)pUmDevice->robo;
 | 
						|
                if (len == 6)
 | 
						|
                {
 | 
						|
                        WriteDataToRegister(robo,page_num,addr_num,len,(void *)&wdata->val_in);
 | 
						|
                        //printk("val[0x%04x-0x%04x-0x%04x].\n",val48[0],val48[1],val48[2]);
 | 
						|
                }
 | 
						|
                else if (len == 8)
 | 
						|
                {
 | 
						|
                        WriteDataToRegister(robo,page_num,addr_num,len,(void *)&wdata->val_in);
 | 
						|
                        //printk("val[0x%04x-0x%04x-0x%04x-0x%04x].\n",val64[0],val64[1],val64[2],val64[3]);
 | 
						|
                }
 | 
						|
                else if (len == 4)
 | 
						|
                {
 | 
						|
                        WriteDataToRegister(robo,page_num,addr_num,len,(void *)&wdata->val_in);
 | 
						|
                        //printk("val[0x%08x].\n",value);
 | 
						|
                }
 | 
						|
		else
 | 
						|
		{
 | 
						|
                        WriteDataToRegister(robo,page_num,addr_num,len,(void *)&wdata->val_in);
 | 
						|
                        //printk("len[%d] val[0x%04x].\n",len,val16);
 | 
						|
		}
 | 
						|
 | 
						|
                return 0;
 | 
						|
	}
 | 
						|
	break;
 | 
						|
#ifdef SIOCGMIIPHY
 | 
						|
	case SIOCGMIIPHY:		/* Get the address of the PHY in use. */
 | 
						|
 | 
						|
		data[0] = pDevice->PhyAddr;
 | 
						|
		return 0;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef SIOCGMIIREG
 | 
						|
	case SIOCGMIIREG:		/* Read the specified MII register. */
 | 
						|
	{
 | 
						|
		uint32 savephyaddr = 0;
 | 
						|
 | 
						|
		if (pDevice->TbiFlags & ENABLE_TBI_FLAG)
 | 
						|
			return -EOPNOTSUPP;
 | 
						|
 | 
						|
		/* ifup only waits for 5 seconds for link up */
 | 
						|
		/* NIC may take more than 5 seconds to establish link */
 | 
						|
		if ((pUmDevice->delayed_link_ind > 0) &&
 | 
						|
			delay_link[pUmDevice->index]) {
 | 
						|
			return -EAGAIN;
 | 
						|
		}
 | 
						|
 | 
						|
		BCM5700_PHY_LOCK(pUmDevice, flags);
 | 
						|
		if (data[0] != 0xffff) {
 | 
						|
			savephyaddr = pDevice->PhyAddr;
 | 
						|
			pDevice->PhyAddr = data[0];
 | 
						|
		}
 | 
						|
		LM_ReadPhy(pDevice, data[1] & 0x1f, (LM_UINT32 *)&value);
 | 
						|
		if (data[0] != 0xffff)
 | 
						|
			pDevice->PhyAddr = savephyaddr;
 | 
						|
		BCM5700_PHY_UNLOCK(pUmDevice, flags);
 | 
						|
		data[3] = value & 0xffff;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef SIOCSMIIREG
 | 
						|
	case SIOCSMIIREG:		/* Write the specified MII register */
 | 
						|
	{
 | 
						|
		uint32 savephyaddr = 0;
 | 
						|
 | 
						|
		if (!capable(CAP_NET_ADMIN))
 | 
						|
			return -EPERM;
 | 
						|
 | 
						|
		if (pDevice->TbiFlags & ENABLE_TBI_FLAG)
 | 
						|
			return -EOPNOTSUPP;
 | 
						|
 | 
						|
		BCM5700_PHY_LOCK(pUmDevice, flags);
 | 
						|
		if (data[0] != 0xffff) {
 | 
						|
			savephyaddr = pDevice->PhyAddr;
 | 
						|
			pDevice->PhyAddr = data[0];
 | 
						|
		}
 | 
						|
		LM_WritePhy(pDevice, data[1] & 0x1f, data[2]);
 | 
						|
		if (data[0] != 0xffff)
 | 
						|
			pDevice->PhyAddr = savephyaddr;
 | 
						|
		BCM5700_PHY_UNLOCK(pUmDevice, flags);
 | 
						|
		data[3] = 0;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef SIOCETHTOOL
 | 
						|
	case SIOCETHTOOL:
 | 
						|
		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 | 
						|
#endif
 | 
						|
	default:
 | 
						|
		return -EOPNOTSUPP;
 | 
						|
	}
 | 
						|
	return -EOPNOTSUPP;
 | 
						|
}
 | 
						|
 | 
						|
STATIC void bcm5700_do_rx_mode(struct net_device *dev)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
	int i;
 | 
						|
	struct dev_mc_list *mclist;
 | 
						|
 | 
						|
	LM_MulticastClear(pDevice);
 | 
						|
	for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 | 
						|
			 i++, mclist = mclist->next) {
 | 
						|
		LM_MulticastAdd(pDevice, (PLM_UINT8) &mclist->dmi_addr);
 | 
						|
	}
 | 
						|
	if (dev->flags & IFF_ALLMULTI) {
 | 
						|
		if (!(pDevice->ReceiveMask & LM_ACCEPT_ALL_MULTICAST)) {
 | 
						|
			LM_SetReceiveMask(pDevice,
 | 
						|
				pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (pDevice->ReceiveMask & LM_ACCEPT_ALL_MULTICAST) {
 | 
						|
		LM_SetReceiveMask(pDevice,
 | 
						|
			pDevice->ReceiveMask & ~LM_ACCEPT_ALL_MULTICAST);
 | 
						|
	}
 | 
						|
	if (dev->flags & IFF_PROMISC) {
 | 
						|
		if (!(pDevice->ReceiveMask & LM_PROMISCUOUS_MODE)) {
 | 
						|
			LM_SetReceiveMask(pDevice,
 | 
						|
				pDevice->ReceiveMask | LM_PROMISCUOUS_MODE);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (pDevice->ReceiveMask & LM_PROMISCUOUS_MODE) {
 | 
						|
		LM_SetReceiveMask(pDevice,
 | 
						|
			pDevice->ReceiveMask & ~LM_PROMISCUOUS_MODE);
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
STATIC void bcm5700_set_rx_mode(struct net_device *dev)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
	int i;
 | 
						|
	struct dev_mc_list *mclist;
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	BCM5700_PHY_LOCK(pUmDevice, flags);
 | 
						|
 | 
						|
	LM_MulticastClear(pDevice);
 | 
						|
	for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 | 
						|
			 i++, mclist = mclist->next) {
 | 
						|
		LM_MulticastAdd(pDevice, (PLM_UINT8) &mclist->dmi_addr);
 | 
						|
	}
 | 
						|
	if (dev->flags & IFF_ALLMULTI) {
 | 
						|
		if (!(pDevice->ReceiveMask & LM_ACCEPT_ALL_MULTICAST)) {
 | 
						|
			LM_SetReceiveMask(pDevice,
 | 
						|
				pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (pDevice->ReceiveMask & LM_ACCEPT_ALL_MULTICAST) {
 | 
						|
		LM_SetReceiveMask(pDevice,
 | 
						|
			pDevice->ReceiveMask & ~LM_ACCEPT_ALL_MULTICAST);
 | 
						|
	}
 | 
						|
	if (dev->flags & IFF_PROMISC) {
 | 
						|
		if (!(pDevice->ReceiveMask & LM_PROMISCUOUS_MODE)) {
 | 
						|
			LM_SetReceiveMask(pDevice,
 | 
						|
				pDevice->ReceiveMask | LM_PROMISCUOUS_MODE);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (pDevice->ReceiveMask & LM_PROMISCUOUS_MODE) {
 | 
						|
		LM_SetReceiveMask(pDevice,
 | 
						|
			pDevice->ReceiveMask & ~LM_PROMISCUOUS_MODE);
 | 
						|
	}
 | 
						|
 | 
						|
	BCM5700_PHY_UNLOCK(pUmDevice, flags);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Set the hardware MAC address.
 | 
						|
 */
 | 
						|
STATIC int bcm5700_set_mac_addr(struct net_device *dev, void *p)
 | 
						|
{
 | 
						|
	struct sockaddr *addr=p;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) dev->priv;
 | 
						|
	UM_DEVICE_BLOCK *pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
 | 
						|
 | 
						|
	if(is_valid_ether_addr(addr->sa_data)){
 | 
						|
 | 
						|
	    memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
 | 
						|
	    if (pUmDevice->opened)
 | 
						|
	        LM_SetMacAddress(pDevice, dev->dev_addr);
 | 
						|
			bcm_robo_set_macaddr(pUmDevice->robo, dev->dev_addr);
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
	return -EINVAL;
 | 
						|
}
 | 
						|
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
STATIC int bcm5700_change_mtu(struct net_device *dev, int new_mtu)
 | 
						|
{
 | 
						|
	int pkt_size = new_mtu + ETHERNET_PACKET_HEADER_SIZE;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev;
 | 
						|
	unsigned long flags;
 | 
						|
	int reinit = 0;
 | 
						|
 | 
						|
	if ((pkt_size < MIN_ETHERNET_PACKET_SIZE_NO_CRC) ||
 | 
						|
		(pkt_size > MAX_ETHERNET_JUMBO_PACKET_SIZE_NO_CRC)) {
 | 
						|
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
	if ( !(pDevice->Flags & JUMBO_CAPABLE_FLAG)    &&
 | 
						|
		(pkt_size > MAX_ETHERNET_PACKET_SIZE_NO_CRC) ) {
 | 
						|
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
	if (pUmDevice->suspended)
 | 
						|
		return -EAGAIN;
 | 
						|
 | 
						|
	if (pUmDevice->opened && (new_mtu != dev->mtu) &&
 | 
						|
		(pDevice->Flags & JUMBO_CAPABLE_FLAG)) {
 | 
						|
		reinit = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	BCM5700_PHY_LOCK(pUmDevice, flags);
 | 
						|
	if (reinit) {
 | 
						|
		netif_stop_queue(dev);
 | 
						|
		bcm5700_shutdown(pUmDevice);
 | 
						|
		bcm5700_freemem(dev);
 | 
						|
	}
 | 
						|
 | 
						|
	dev->mtu = new_mtu;
 | 
						|
	if (pkt_size < MAX_ETHERNET_PACKET_SIZE_NO_CRC) {
 | 
						|
		pDevice->RxMtu = pDevice->TxMtu =
 | 
						|
			MAX_ETHERNET_PACKET_SIZE_NO_CRC;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		pDevice->RxMtu = pDevice->TxMtu = pkt_size;
 | 
						|
	}
 | 
						|
 | 
						|
	if (dev->mtu <= 1514)  {
 | 
						|
		pDevice->RxJumboDescCnt = 0;
 | 
						|
	}
 | 
						|
	else if (pDevice->Flags & JUMBO_CAPABLE_FLAG){
 | 
						|
		pDevice->RxJumboDescCnt =
 | 
						|
			rx_jumbo_desc_cnt[pUmDevice->index];
 | 
						|
	}
 | 
						|
	pDevice->RxPacketDescCnt = pDevice->RxJumboDescCnt +
 | 
						|
		pDevice->RxStdDescCnt;
 | 
						|
 | 
						|
	pDevice->RxJumboBufferSize = (pDevice->RxMtu + 8 /* CRC + VLAN */ +
 | 
						|
		COMMON_CACHE_LINE_SIZE-1) & ~COMMON_CACHE_LINE_MASK;
 | 
						|
 | 
						|
#ifdef BCM_TSO
 | 
						|
	if (T3_ASIC_5714_FAMILY(pDevice->ChipRevId) &&
 | 
						|
	   (dev->mtu > 1514) ) {
 | 
						|
		if (dev->features & NETIF_F_TSO) {
 | 
						|
			dev->features &= ~NETIF_F_TSO;
 | 
						|
			printk(KERN_ALERT "%s: TSO previously enabled. Jumbo Frames and TSO cannot simultaneously be enabled. Jumbo Frames enabled. TSO disabled.\n", dev->name);
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	if (reinit) {
 | 
						|
		LM_InitializeAdapter(pDevice);
 | 
						|
		bcm5700_do_rx_mode(dev);
 | 
						|
		bcm5700_set_vlan_mode(pUmDevice);
 | 
						|
		bcm5700_init_counters(pUmDevice);
 | 
						|
		if (memcmp(dev->dev_addr, pDevice->NodeAddress, 6)) {
 | 
						|
			LM_SetMacAddress(pDevice, dev->dev_addr);
 | 
						|
		}
 | 
						|
		netif_start_queue(dev);
 | 
						|
		bcm5700_intr_on(pUmDevice);
 | 
						|
	}
 | 
						|
	BCM5700_PHY_UNLOCK(pUmDevice, flags);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE < 0x020300)
 | 
						|
int
 | 
						|
bcm5700_probe(struct net_device *dev)
 | 
						|
{
 | 
						|
	int cards_found = 0;
 | 
						|
	struct pci_dev *pdev = NULL;
 | 
						|
	struct pci_device_id *pci_tbl;
 | 
						|
	u16 ssvid, ssid;
 | 
						|
 | 
						|
	if ( ! pci_present())
 | 
						|
		return -ENODEV;
 | 
						|
 | 
						|
	pci_tbl = bcm5700_pci_tbl;
 | 
						|
	while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) {
 | 
						|
		int idx;
 | 
						|
 | 
						|
		pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &ssvid);
 | 
						|
		pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &ssid);
 | 
						|
		for (idx = 0; pci_tbl[idx].vendor; idx++) {
 | 
						|
			if ((pci_tbl[idx].vendor == PCI_ANY_ID ||
 | 
						|
				pci_tbl[idx].vendor == pdev->vendor) &&
 | 
						|
				(pci_tbl[idx].device == PCI_ANY_ID ||
 | 
						|
				pci_tbl[idx].device == pdev->device) &&
 | 
						|
				(pci_tbl[idx].subvendor == PCI_ANY_ID ||
 | 
						|
				pci_tbl[idx].subvendor == ssvid) &&
 | 
						|
				(pci_tbl[idx].subdevice == PCI_ANY_ID ||
 | 
						|
				pci_tbl[idx].subdevice == ssid))
 | 
						|
			{
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (pci_tbl[idx].vendor == 0)
 | 
						|
			continue;
 | 
						|
 | 
						|
 | 
						|
		if (bcm5700_init_one(pdev, &pci_tbl[idx]) == 0)
 | 
						|
			cards_found++;
 | 
						|
	}
 | 
						|
 | 
						|
	return cards_found ? 0 : -ENODEV;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef MODULE
 | 
						|
int init_module(void)
 | 
						|
{
 | 
						|
	return bcm5700_probe(NULL);
 | 
						|
}
 | 
						|
 | 
						|
void cleanup_module(void)
 | 
						|
{
 | 
						|
	struct net_device *next_dev;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice;
 | 
						|
 | 
						|
	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 | 
						|
	while (root_tigon3_dev) {
 | 
						|
		pUmDevice = (PUM_DEVICE_BLOCK)root_tigon3_dev->priv;
 | 
						|
		next_dev = pUmDevice->next_module;
 | 
						|
		unregister_netdev(root_tigon3_dev);
 | 
						|
		if (pUmDevice->lm_dev.pMappedMemBase)
 | 
						|
			iounmap(pUmDevice->lm_dev.pMappedMemBase);
 | 
						|
#if (LINUX_VERSION_CODE < 0x020600)
 | 
						|
		kfree(root_tigon3_dev);
 | 
						|
#else
 | 
						|
		free_netdev(root_tigon3_dev);
 | 
						|
#endif
 | 
						|
		root_tigon3_dev = next_dev;
 | 
						|
	}
 | 
						|
#ifdef BCM_IOCTL32
 | 
						|
	unregister_ioctl32_conversion(SIOCNICE);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
#endif  /* MODULE */
 | 
						|
#else	/* LINUX_VERSION_CODE < 0x020300 */
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x020406)
 | 
						|
static int bcm5700_suspend (struct pci_dev *pdev, u32 state)
 | 
						|
#else
 | 
						|
static void bcm5700_suspend (struct pci_dev *pdev)
 | 
						|
#endif
 | 
						|
{
 | 
						|
	struct net_device *dev = (struct net_device *) pci_get_drvdata(pdev);
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev;
 | 
						|
 | 
						|
	if (!netif_running(dev))
 | 
						|
#if (LINUX_VERSION_CODE >= 0x020406)
 | 
						|
		return 0;
 | 
						|
#else
 | 
						|
		return;
 | 
						|
#endif
 | 
						|
 | 
						|
	netif_device_detach (dev);
 | 
						|
	bcm5700_shutdown(pUmDevice);
 | 
						|
 | 
						|
	LM_SetPowerState(pDevice, LM_POWER_STATE_D3);
 | 
						|
 | 
						|
/*	pci_power_off(pdev, -1);*/
 | 
						|
#if (LINUX_VERSION_CODE >= 0x020406)
 | 
						|
	return 0;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if (LINUX_VERSION_CODE >= 0x020406)
 | 
						|
static int bcm5700_resume(struct pci_dev *pdev)
 | 
						|
#else
 | 
						|
static void bcm5700_resume(struct pci_dev *pdev)
 | 
						|
#endif
 | 
						|
{
 | 
						|
	struct net_device *dev = (struct net_device *) pci_get_drvdata(pdev);
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev;
 | 
						|
 | 
						|
	if (!netif_running(dev))
 | 
						|
#if (LINUX_VERSION_CODE >= 0x020406)
 | 
						|
		return 0;
 | 
						|
#else
 | 
						|
		return;
 | 
						|
#endif
 | 
						|
/*	pci_power_on(pdev);*/
 | 
						|
	netif_device_attach(dev);
 | 
						|
	LM_SetPowerState(pDevice, LM_POWER_STATE_D0);
 | 
						|
	MM_InitializeUmPackets(pDevice);
 | 
						|
	bcm5700_reset(dev);
 | 
						|
#if (LINUX_VERSION_CODE >= 0x020406)
 | 
						|
	return 0;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static struct pci_driver bcm5700_pci_driver = {
 | 
						|
	name:		bcm5700_driver,
 | 
						|
	id_table:	bcm5700_pci_tbl,
 | 
						|
	probe:		bcm5700_init_one,
 | 
						|
	remove:		__devexit_p(bcm5700_remove_one),
 | 
						|
	suspend:	bcm5700_suspend,
 | 
						|
	resume:		bcm5700_resume,
 | 
						|
};
 | 
						|
 | 
						|
static int
 | 
						|
bcm5700_notify_reboot(struct notifier_block *this, unsigned long event, void *unused)
 | 
						|
{
 | 
						|
	switch (event) {
 | 
						|
	case SYS_HALT:
 | 
						|
	case SYS_POWER_OFF:
 | 
						|
	case SYS_RESTART:
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		return NOTIFY_DONE;
 | 
						|
	}
 | 
						|
 | 
						|
	B57_INFO(("bcm5700 reboot notification\n"));
 | 
						|
	pci_unregister_driver(&bcm5700_pci_driver);
 | 
						|
	return NOTIFY_DONE;
 | 
						|
}
 | 
						|
 | 
						|
static int __init bcm5700_init_module (void)
 | 
						|
{
 | 
						|
	int pin = 1 << 2;
 | 
						|
 | 
						|
	if (nvram_match("disabled_5397", "1") || (activate_gpio != -1)) {
 | 
						|
		if ( activate_gpio != -1 ) pin = activate_gpio;
 | 
						|
		printk("5397 switch GPIO-Reset (pin %d)\n", pin);
 | 
						|
		sb_t *gpio_sbh;
 | 
						|
		if (!(gpio_sbh = sb_kattach(SB_OSH))) return -ENODEV;
 | 
						|
		sb_gpiosetcore(gpio_sbh);
 | 
						|
//		sb_gpioreserve(gpio_sbh, 0x4, GPIO_HI_PRIORITY);
 | 
						|
		sb_gpioouten(gpio_sbh, 0x4, 0x4, GPIO_HI_PRIORITY);
 | 
						|
		sb_gpioout(gpio_sbh, 0x4, 0x4, GPIO_HI_PRIORITY);
 | 
						|
		sb_detach(gpio_sbh);
 | 
						|
	}
 | 
						|
 | 
						|
	if (msglevel != 0xdeadbeef) {
 | 
						|
		b57_msg_level = msglevel;
 | 
						|
		printf("%s: msglevel set to 0x%x\n", __FUNCTION__, b57_msg_level);
 | 
						|
	} else
 | 
						|
		b57_msg_level = B57_ERR_VAL;
 | 
						|
 | 
						|
	return pci_module_init(&bcm5700_pci_driver);
 | 
						|
}
 | 
						|
 | 
						|
static void __exit bcm5700_cleanup_module (void)
 | 
						|
{
 | 
						|
	unregister_reboot_notifier(&bcm5700_reboot_notifier);
 | 
						|
	pci_unregister_driver(&bcm5700_pci_driver);
 | 
						|
}
 | 
						|
 | 
						|
module_init(bcm5700_init_module);
 | 
						|
module_exit(bcm5700_cleanup_module);
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * Middle Module
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
LM_STATUS
 | 
						|
MM_ScheduleRxPoll(LM_DEVICE_BLOCK *pDevice)
 | 
						|
{
 | 
						|
	struct net_device *dev = ((UM_DEVICE_BLOCK *) pDevice)->dev;
 | 
						|
 | 
						|
	if (netif_rx_schedule_prep(dev)) {
 | 
						|
		__netif_rx_schedule(dev);
 | 
						|
		return LM_STATUS_SUCCESS;
 | 
						|
	}
 | 
						|
	return LM_STATUS_FAILURE;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_ReadConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
 | 
						|
	LM_UINT16 *pValue16)
 | 
						|
{
 | 
						|
	UM_DEVICE_BLOCK *pUmDevice;
 | 
						|
 | 
						|
	pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
 | 
						|
	pci_read_config_word(pUmDevice->pdev, Offset, (u16 *) pValue16);
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_ReadConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
 | 
						|
	LM_UINT32 *pValue32)
 | 
						|
{
 | 
						|
	UM_DEVICE_BLOCK *pUmDevice;
 | 
						|
 | 
						|
	pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
 | 
						|
	pci_read_config_dword(pUmDevice->pdev, Offset, (u32 *) pValue32);
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_WriteConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
 | 
						|
	LM_UINT16 Value16)
 | 
						|
{
 | 
						|
	UM_DEVICE_BLOCK *pUmDevice;
 | 
						|
 | 
						|
	pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
 | 
						|
	pci_write_config_word(pUmDevice->pdev, Offset, Value16);
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_WriteConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset,
 | 
						|
	LM_UINT32 Value32)
 | 
						|
{
 | 
						|
	UM_DEVICE_BLOCK *pUmDevice;
 | 
						|
 | 
						|
	pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
 | 
						|
	pci_write_config_dword(pUmDevice->pdev, Offset, Value32);
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_AllocateSharedMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
 | 
						|
	PLM_VOID *pMemoryBlockVirt, PLM_PHYSICAL_ADDRESS pMemoryBlockPhy,
 | 
						|
	LM_BOOL Cached)
 | 
						|
{
 | 
						|
	PLM_VOID pvirt;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
 | 
						|
	dma_addr_t mapping;
 | 
						|
 | 
						|
	pvirt = pci_alloc_consistent(pUmDevice->pdev, BlockSize,
 | 
						|
					       &mapping);
 | 
						|
	if (!pvirt) {
 | 
						|
		return LM_STATUS_FAILURE;
 | 
						|
	}
 | 
						|
	pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
 | 
						|
	pUmDevice->dma_list[pUmDevice->mem_list_num] = mapping;
 | 
						|
	pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize;
 | 
						|
	memset(pvirt, 0, BlockSize);
 | 
						|
	*pMemoryBlockVirt = (PLM_VOID) pvirt;
 | 
						|
	MM_SetAddr(pMemoryBlockPhy, mapping);
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_AllocateMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
 | 
						|
	PLM_VOID *pMemoryBlockVirt)
 | 
						|
{
 | 
						|
	PLM_VOID pvirt;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
 | 
						|
 | 
						|
 | 
						|
	/* Maximum in slab.c */
 | 
						|
	if (BlockSize > 131072) {
 | 
						|
		goto MM_Alloc_error;
 | 
						|
	}
 | 
						|
 | 
						|
	pvirt = kmalloc(BlockSize, GFP_ATOMIC);
 | 
						|
	if (!pvirt) {
 | 
						|
		goto MM_Alloc_error;
 | 
						|
	}
 | 
						|
	pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
 | 
						|
	pUmDevice->dma_list[pUmDevice->mem_list_num] = 0;
 | 
						|
	pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = 0;
 | 
						|
	/* mem_size_list[i] == 0 indicates that the memory should be freed */
 | 
						|
	/* using kfree */
 | 
						|
	memset(pvirt, 0, BlockSize);
 | 
						|
	*pMemoryBlockVirt = pvirt;
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
 | 
						|
MM_Alloc_error:
 | 
						|
	printk(KERN_WARNING "%s: Memory allocation failed - buffer parameters may be set too high\n", pUmDevice->dev->name);
 | 
						|
	return LM_STATUS_FAILURE;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_MapMemBase(PLM_DEVICE_BLOCK pDevice)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
 | 
						|
 | 
						|
	pDevice->pMappedMemBase = ioremap_nocache(
 | 
						|
		pci_resource_start(pUmDevice->pdev, 0), sizeof(T3_STD_MEM_MAP));
 | 
						|
	if (pDevice->pMappedMemBase == 0)
 | 
						|
		return LM_STATUS_FAILURE;
 | 
						|
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_InitializeUmPackets(PLM_DEVICE_BLOCK pDevice)
 | 
						|
{
 | 
						|
	unsigned int i;
 | 
						|
	struct sk_buff *skb;
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
 | 
						|
	PUM_PACKET pUmPacket;
 | 
						|
	PLM_PACKET pPacket;
 | 
						|
 | 
						|
	for (i = 0; i < pDevice->RxPacketDescCnt; i++) {
 | 
						|
		pPacket = QQ_PopHead(&pDevice->RxPacketFreeQ.Container);
 | 
						|
		pUmPacket = (PUM_PACKET) pPacket;
 | 
						|
		if (pPacket == 0) {
 | 
						|
			printk(KERN_DEBUG "Bad RxPacketFreeQ\n");
 | 
						|
		}
 | 
						|
		if (pUmPacket->skbuff == 0) {
 | 
						|
#ifdef BCM_WL_EMULATOR
 | 
						|
			skb = (struct sk_buff *)wlcemu_pktget(pDevice->wlc,pPacket->u.Rx.RxBufferSize + 2);
 | 
						|
#else
 | 
						|
			skb = dev_alloc_skb(pPacket->u.Rx.RxBufferSize + 2 + EXTRA_HDR);
 | 
						|
#endif
 | 
						|
			if (skb == 0) {
 | 
						|
				pUmPacket->skbuff = 0;
 | 
						|
				QQ_PushTail(
 | 
						|
					&pUmDevice->rx_out_of_buf_q.Container,
 | 
						|
					pPacket);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			pUmPacket->skbuff = skb;
 | 
						|
			skb->dev = pUmDevice->dev;
 | 
						|
#ifndef BCM_WL_EMULATOR
 | 
						|
			skb_reserve(skb, EXTRA_HDR - pUmDevice->rx_buf_align);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
		QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
 | 
						|
	}
 | 
						|
	if (T3_ASIC_REV(pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) {
 | 
						|
		/* reallocate buffers in the ISR */
 | 
						|
		pUmDevice->rx_buf_repl_thresh = 0;
 | 
						|
		pUmDevice->rx_buf_repl_panic_thresh = 0;
 | 
						|
		pUmDevice->rx_buf_repl_isr_limit = 0;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		pUmDevice->rx_buf_repl_thresh = pDevice->RxPacketDescCnt / 8;
 | 
						|
		pUmDevice->rx_buf_repl_panic_thresh =
 | 
						|
			pDevice->RxPacketDescCnt  * 7 / 8;
 | 
						|
 | 
						|
		/* This limits the time spent in the ISR when the receiver */
 | 
						|
		/* is in a steady state of being overrun. */
 | 
						|
		pUmDevice->rx_buf_repl_isr_limit = pDevice->RxPacketDescCnt / 8;
 | 
						|
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
		if (pDevice->RxJumboDescCnt != 0) {
 | 
						|
			if (pUmDevice->rx_buf_repl_thresh >=
 | 
						|
				pDevice->RxJumboDescCnt) {
 | 
						|
 | 
						|
				pUmDevice->rx_buf_repl_thresh =
 | 
						|
				pUmDevice->rx_buf_repl_panic_thresh =
 | 
						|
					pDevice->RxJumboDescCnt - 1;
 | 
						|
			}
 | 
						|
			if (pUmDevice->rx_buf_repl_thresh >=
 | 
						|
				pDevice->RxStdDescCnt) {
 | 
						|
 | 
						|
				pUmDevice->rx_buf_repl_thresh =
 | 
						|
				pUmDevice->rx_buf_repl_panic_thresh =
 | 
						|
					pDevice->RxStdDescCnt - 1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_GetConfig(PLM_DEVICE_BLOCK pDevice)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
 | 
						|
	int index = pUmDevice->index;
 | 
						|
	struct net_device *dev = pUmDevice->dev;
 | 
						|
 | 
						|
	if (index >= MAX_UNITS)
 | 
						|
		return LM_STATUS_SUCCESS;
 | 
						|
 | 
						|
#if LINUX_KERNEL_VERSION < 0x0020609
 | 
						|
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &auto_speed[index], "auto_speed",
 | 
						|
		0, 1, 1);
 | 
						|
	if (auto_speed[index] == 0)
 | 
						|
		pDevice->DisableAutoNeg = TRUE;
 | 
						|
	else
 | 
						|
		pDevice->DisableAutoNeg = FALSE;
 | 
						|
 | 
						|
	if (line_speed[index] == 0) {
 | 
						|
		pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO;
 | 
						|
		pDevice->DisableAutoNeg = FALSE;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		bcm5700_validate_param_range(pUmDevice, &full_duplex[index],
 | 
						|
			"full_duplex", 0, 1, 1);
 | 
						|
		if (full_duplex[index]) {
 | 
						|
			pDevice->RequestedDuplexMode = LM_DUPLEX_MODE_FULL;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			pDevice->RequestedDuplexMode = LM_DUPLEX_MODE_HALF;
 | 
						|
		}
 | 
						|
 | 
						|
		if (line_speed[index] == 1000) {
 | 
						|
			pDevice->RequestedLineSpeed = LM_LINE_SPEED_1000MBPS;
 | 
						|
			if (pDevice->PhyFlags & PHY_NO_GIGABIT) {
 | 
						|
				pDevice->RequestedLineSpeed =
 | 
						|
					LM_LINE_SPEED_100MBPS;
 | 
						|
				printk(KERN_WARNING "%s-%d: Invalid line_speed parameter (1000), using 100\n", bcm5700_driver, index);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				if ((pDevice->TbiFlags & ENABLE_TBI_FLAG) &&
 | 
						|
					!full_duplex[index]) {
 | 
						|
					printk(KERN_WARNING "%s-%d: Invalid full_duplex parameter (0) for fiber, using 1\n", bcm5700_driver, index);
 | 
						|
					pDevice->RequestedDuplexMode =
 | 
						|
						LM_DUPLEX_MODE_FULL;
 | 
						|
				}
 | 
						|
 | 
						|
				if (!(pDevice->TbiFlags & ENABLE_TBI_FLAG) &&
 | 
						|
					!auto_speed[index] && !(pDevice->PhyFlags & PHY_IS_FIBER) ) {
 | 
						|
					printk(KERN_WARNING "%s-%d: Invalid auto_speed parameter (0) for copper, using 1\n", bcm5700_driver, index);
 | 
						|
					pDevice->DisableAutoNeg = FALSE;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if ((pDevice->TbiFlags & ENABLE_TBI_FLAG) ||
 | 
						|
                         (pDevice->PhyFlags & PHY_IS_FIBER)){
 | 
						|
			 pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO;
 | 
						|
			 pDevice->RequestedDuplexMode = LM_DUPLEX_MODE_FULL;
 | 
						|
			 pDevice->DisableAutoNeg = FALSE;
 | 
						|
			 printk(KERN_WARNING "%s-%d: Invalid line_speed parameter (%d), using auto\n", bcm5700_driver, index, line_speed[index]);
 | 
						|
		}
 | 
						|
		else if (line_speed[index] == 100) {
 | 
						|
 | 
						|
                        pDevice->RequestedLineSpeed = LM_LINE_SPEED_100MBPS;
 | 
						|
		}
 | 
						|
		else if (line_speed[index] == 10) {
 | 
						|
 | 
						|
			pDevice->RequestedLineSpeed = LM_LINE_SPEED_10MBPS;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO;
 | 
						|
			pDevice->DisableAutoNeg = FALSE;
 | 
						|
			printk(KERN_WARNING "%s-%d: Invalid line_speed parameter (%d), using 0\n", bcm5700_driver, index, line_speed[index]);
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
#endif /* LINUX_KERNEL_VERSION */
 | 
						|
 | 
						|
	/* This is an unmanageable switch nic and will have link problems if
 | 
						|
	   not set to auto
 | 
						|
	*/
 | 
						|
	if(pDevice->SubsystemVendorId==0x103c && pDevice->SubsystemId==0x3226)
 | 
						|
	{
 | 
						|
	    if(pDevice->RequestedLineSpeed != LM_LINE_SPEED_AUTO)
 | 
						|
	    {
 | 
						|
		printk(KERN_WARNING "%s-%d: Invalid line_speed parameter (%d), using 0\n",
 | 
						|
			bcm5700_driver, index, line_speed[index]);
 | 
						|
	    }
 | 
						|
	    pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO;
 | 
						|
	    pDevice->DisableAutoNeg = FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
#if LINUX_KERNEL_VERSION < 0x0020609
 | 
						|
 | 
						|
	pDevice->FlowControlCap = 0;
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &rx_flow_control[index],
 | 
						|
		"rx_flow_control", 0, 1, 0);
 | 
						|
	if (rx_flow_control[index] != 0) {
 | 
						|
		pDevice->FlowControlCap |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
 | 
						|
	}
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &tx_flow_control[index],
 | 
						|
		"tx_flow_control", 0, 1, 0);
 | 
						|
	if (tx_flow_control[index] != 0) {
 | 
						|
		pDevice->FlowControlCap |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
 | 
						|
	}
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &auto_flow_control[index],
 | 
						|
		"auto_flow_control", 0, 1, 0);
 | 
						|
	if (auto_flow_control[index] != 0) {
 | 
						|
		if (pDevice->DisableAutoNeg == FALSE) {
 | 
						|
 | 
						|
			pDevice->FlowControlCap |= LM_FLOW_CONTROL_AUTO_PAUSE;
 | 
						|
			if ((tx_flow_control[index] == 0) &&
 | 
						|
				(rx_flow_control[index] == 0)) {
 | 
						|
 | 
						|
				pDevice->FlowControlCap |=
 | 
						|
					LM_FLOW_CONTROL_TRANSMIT_PAUSE |
 | 
						|
					LM_FLOW_CONTROL_RECEIVE_PAUSE;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (dev->mtu > 1500) {
 | 
						|
#ifdef BCM_TSO
 | 
						|
		if (T3_ASIC_5714_FAMILY(pDevice->ChipRevId) &&
 | 
						|
		   (dev->features & NETIF_F_TSO)) {
 | 
						|
				dev->features &= ~NETIF_F_TSO;
 | 
						|
				printk(KERN_ALERT "%s: TSO previously enabled. Jumbo Frames and TSO cannot simultaneously be enabled. Jumbo Frames enabled. TSO disabled.\n", dev->name);
 | 
						|
		}
 | 
						|
#endif
 | 
						|
		pDevice->RxMtu = dev->mtu + 14;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700) &&
 | 
						|
		!(pDevice->Flags & BCM5788_FLAG)) {
 | 
						|
		pDevice->Flags |= USE_TAGGED_STATUS_FLAG;
 | 
						|
		pUmDevice->timer_interval = HZ;
 | 
						|
		if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) &&
 | 
						|
			(pDevice->TbiFlags & ENABLE_TBI_FLAG)) {
 | 
						|
			pUmDevice->timer_interval = HZ/4;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		pUmDevice->timer_interval = HZ/10;
 | 
						|
	}
 | 
						|
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &tx_pkt_desc_cnt[index],
 | 
						|
		"tx_pkt_desc_cnt", 1, MAX_TX_PACKET_DESC_COUNT-1, TX_DESC_CNT);
 | 
						|
	pDevice->TxPacketDescCnt = tx_pkt_desc_cnt[index];
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &rx_std_desc_cnt[index],
 | 
						|
		"rx_std_desc_cnt", 1, T3_STD_RCV_RCB_ENTRY_COUNT-1,
 | 
						|
		RX_DESC_CNT);
 | 
						|
	pDevice->RxStdDescCnt = rx_std_desc_cnt[index];
 | 
						|
 | 
						|
#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &rx_jumbo_desc_cnt[index],
 | 
						|
		"rx_jumbo_desc_cnt", 1, T3_JUMBO_RCV_RCB_ENTRY_COUNT-1,
 | 
						|
		JBO_DESC_CNT);
 | 
						|
 | 
						|
	if (mtu[index] <= 1514)
 | 
						|
		pDevice->RxJumboDescCnt = 0;
 | 
						|
	else if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)){
 | 
						|
		pDevice->RxJumboDescCnt = rx_jumbo_desc_cnt[index];
 | 
						|
        }
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef BCM_INT_COAL
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &adaptive_coalesce[index],
 | 
						|
		"adaptive_coalesce", 0, 1, 1);
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
	if (adaptive_coalesce[index]) {
 | 
						|
		printk(KERN_WARNING "%s-%d: adaptive_coalesce not used in NAPI mode\n", bcm5700_driver, index);
 | 
						|
		adaptive_coalesce[index] = 0;
 | 
						|
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	pUmDevice->adaptive_coalesce = adaptive_coalesce[index];
 | 
						|
	if (!pUmDevice->adaptive_coalesce) {
 | 
						|
		bcm5700_validate_param_range(pUmDevice,
 | 
						|
			&rx_coalesce_ticks[index], "rx_coalesce_ticks", 0,
 | 
						|
			MAX_RX_COALESCING_TICKS, RX_COAL_TK);
 | 
						|
		if ((rx_coalesce_ticks[index] == 0) &&
 | 
						|
			(rx_max_coalesce_frames[index] == 0)) {
 | 
						|
 | 
						|
			printk(KERN_WARNING "%s-%d: Conflicting rx_coalesce_ticks (0) and rx_max_coalesce_frames (0) parameters, using %d and %d respectively\n",
 | 
						|
				bcm5700_driver, index, RX_COAL_TK, RX_COAL_FM);
 | 
						|
 | 
						|
			rx_coalesce_ticks[index] = RX_COAL_TK;
 | 
						|
			rx_max_coalesce_frames[index] = RX_COAL_FM;
 | 
						|
		}
 | 
						|
		pDevice->RxCoalescingTicks = pUmDevice->rx_curr_coalesce_ticks =
 | 
						|
			rx_coalesce_ticks[index];
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
		pDevice->RxCoalescingTicksDuringInt = rx_coalesce_ticks[index];
 | 
						|
#endif
 | 
						|
 | 
						|
		bcm5700_validate_param_range(pUmDevice,
 | 
						|
			&rx_max_coalesce_frames[index],
 | 
						|
			"rx_max_coalesce_frames", 0,
 | 
						|
			MAX_RX_MAX_COALESCED_FRAMES, RX_COAL_FM);
 | 
						|
 | 
						|
		pDevice->RxMaxCoalescedFrames =
 | 
						|
			pUmDevice->rx_curr_coalesce_frames =
 | 
						|
			rx_max_coalesce_frames[index];
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
		pDevice->RxMaxCoalescedFramesDuringInt =
 | 
						|
			rx_max_coalesce_frames[index];
 | 
						|
#endif
 | 
						|
 | 
						|
		bcm5700_validate_param_range(pUmDevice,
 | 
						|
			&tx_coalesce_ticks[index], "tx_coalesce_ticks", 0,
 | 
						|
			MAX_TX_COALESCING_TICKS, TX_COAL_TK);
 | 
						|
		if ((tx_coalesce_ticks[index] == 0) &&
 | 
						|
			(tx_max_coalesce_frames[index] == 0)) {
 | 
						|
 | 
						|
			printk(KERN_WARNING "%s-%d: Conflicting tx_coalesce_ticks (0) and tx_max_coalesce_frames (0) parameters, using %d and %d respectively\n",
 | 
						|
				bcm5700_driver, index, TX_COAL_TK, TX_COAL_FM);
 | 
						|
 | 
						|
			tx_coalesce_ticks[index] = TX_COAL_TK;
 | 
						|
			tx_max_coalesce_frames[index] = TX_COAL_FM;
 | 
						|
		}
 | 
						|
		pDevice->TxCoalescingTicks = tx_coalesce_ticks[index];
 | 
						|
		bcm5700_validate_param_range(pUmDevice,
 | 
						|
			&tx_max_coalesce_frames[index],
 | 
						|
			"tx_max_coalesce_frames", 0,
 | 
						|
			MAX_TX_MAX_COALESCED_FRAMES, TX_COAL_FM);
 | 
						|
		pDevice->TxMaxCoalescedFrames = tx_max_coalesce_frames[index];
 | 
						|
		pUmDevice->tx_curr_coalesce_frames =
 | 
						|
			pDevice->TxMaxCoalescedFrames;
 | 
						|
 | 
						|
		bcm5700_validate_param_range(pUmDevice,
 | 
						|
			&stats_coalesce_ticks[index], "stats_coalesce_ticks",
 | 
						|
			0, MAX_STATS_COALESCING_TICKS, ST_COAL_TK);
 | 
						|
		if (adaptive_coalesce[index]) {
 | 
						|
			printk(KERN_WARNING "%s-%d: Invalid stats_coalesce_ticks parameter set with with adaptive_coalesce parameter. Using adaptive_coalesce.\n", bcm5700_driver, index);
 | 
						|
		}else{
 | 
						|
			if ((stats_coalesce_ticks[index] > 0) &&
 | 
						|
				(stats_coalesce_ticks[index] < 100)) {
 | 
						|
				printk(KERN_WARNING "%s-%d: Invalid stats_coalesce_ticks parameter (%u), using 100\n", bcm5700_driver, index, (unsigned int) stats_coalesce_ticks[index]);
 | 
						|
				stats_coalesce_ticks[index] = 100;
 | 
						|
				pDevice->StatsCoalescingTicks = stats_coalesce_ticks[index];
 | 
						|
				pDevice->StatsCoalescingTicks = stats_coalesce_ticks[index];
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		pUmDevice->rx_curr_coalesce_frames = RX_COAL_FM;
 | 
						|
		pUmDevice->rx_curr_coalesce_ticks = RX_COAL_TK;
 | 
						|
		pUmDevice->tx_curr_coalesce_frames = TX_COAL_FM;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) {
 | 
						|
		unsigned int tmpvar;
 | 
						|
 | 
						|
		tmpvar = pDevice->StatsCoalescingTicks / BCM_TIMER_GRANULARITY;
 | 
						|
 | 
						|
		/*
 | 
						|
		 * If the result is zero, the request is too demanding.
 | 
						|
		 */
 | 
						|
		if (tmpvar == 0) {
 | 
						|
			tmpvar = 1;
 | 
						|
		}
 | 
						|
 | 
						|
		pDevice->StatsCoalescingTicks = tmpvar * BCM_TIMER_GRANULARITY;
 | 
						|
 | 
						|
		pUmDevice->statstimer_interval = tmpvar;
 | 
						|
	}
 | 
						|
 | 
						|
#ifdef BCM_WOL
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &enable_wol[index],
 | 
						|
		"enable_wol", 0, 1, 0);
 | 
						|
	if (enable_wol[index]) {
 | 
						|
		pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET;
 | 
						|
		pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef INCLUDE_TBI_SUPPORT
 | 
						|
	if (pDevice->TbiFlags & ENABLE_TBI_FLAG) {
 | 
						|
		if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) ||
 | 
						|
			(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703)) {
 | 
						|
			/* just poll since we have hardware autoneg. in 5704 */
 | 
						|
			pDevice->TbiFlags |= TBI_PURE_POLLING_FLAG;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			pDevice->TbiFlags |= TBI_POLLING_INTR_FLAG;
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &scatter_gather[index],
 | 
						|
		"scatter_gather", 0, 1, 1);
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &tx_checksum[index],
 | 
						|
		"tx_checksum", 0, 1, 1);
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &rx_checksum[index],
 | 
						|
		"rx_checksum", 0, 1, 1);
 | 
						|
	if (!(pDevice->TaskOffloadCap & LM_TASK_OFFLOAD_TX_TCP_CHECKSUM)) {
 | 
						|
		if (tx_checksum[index] || rx_checksum[index]) {
 | 
						|
 | 
						|
			pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
 | 
						|
			printk(KERN_WARNING "%s-%d: Checksum offload not available on this NIC\n", bcm5700_driver, index);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		if (rx_checksum[index]) {
 | 
						|
			pDevice->TaskToOffload |=
 | 
						|
				LM_TASK_OFFLOAD_RX_TCP_CHECKSUM |
 | 
						|
				LM_TASK_OFFLOAD_RX_UDP_CHECKSUM;
 | 
						|
		}
 | 
						|
		if (tx_checksum[index]) {
 | 
						|
			pDevice->TaskToOffload |=
 | 
						|
				LM_TASK_OFFLOAD_TX_TCP_CHECKSUM |
 | 
						|
				LM_TASK_OFFLOAD_TX_UDP_CHECKSUM;
 | 
						|
			pDevice->Flags |= NO_TX_PSEUDO_HDR_CSUM_FLAG;
 | 
						|
		}
 | 
						|
	}
 | 
						|
#ifdef BCM_TSO
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &enable_tso[index],
 | 
						|
		"enable_tso", 0, 1, 1);
 | 
						|
 | 
						|
	/* Always enable TSO firmware if supported */
 | 
						|
	/* This way we can turn it on or off on the fly */
 | 
						|
	if (pDevice->TaskOffloadCap & LM_TASK_OFFLOAD_TCP_SEGMENTATION)
 | 
						|
	{
 | 
						|
		pDevice->TaskToOffload |=
 | 
						|
			LM_TASK_OFFLOAD_TCP_SEGMENTATION;
 | 
						|
	}
 | 
						|
	if (enable_tso[index] &&
 | 
						|
		!(pDevice->TaskToOffload & LM_TASK_OFFLOAD_TCP_SEGMENTATION))
 | 
						|
	{
 | 
						|
		printk(KERN_WARNING "%s-%d: TSO not available on this NIC\n", bcm5700_driver, index);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#ifdef BCM_ASF
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &vlan_tag_mode[index],
 | 
						|
		"vlan_strip_mode", 0, 2, 0);
 | 
						|
	pUmDevice->vlan_tag_mode = vlan_tag_mode[index];
 | 
						|
#else
 | 
						|
	pUmDevice->vlan_tag_mode = VLAN_TAG_MODE_NORMAL_STRIP;
 | 
						|
#endif
 | 
						|
 | 
						|
#endif /* LINUX_KERNEL_VERSION */
 | 
						|
 | 
						|
#ifdef BCM_NIC_SEND_BD
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &nic_tx_bd[index], "nic_tx_bd",
 | 
						|
		0, 1, 0);
 | 
						|
	if (nic_tx_bd[index])
 | 
						|
		pDevice->Flags |= NIC_SEND_BD_FLAG;
 | 
						|
	if ((pDevice->Flags & ENABLE_PCIX_FIX_FLAG) ||
 | 
						|
		(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705)) {
 | 
						|
		if (pDevice->Flags & NIC_SEND_BD_FLAG) {
 | 
						|
			pDevice->Flags &= ~NIC_SEND_BD_FLAG;
 | 
						|
			printk(KERN_WARNING "%s-%d: Nic Send BDs not available on this NIC or not possible on this system\n", bcm5700_driver, index);
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR)
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &disable_msi[pUmDevice->index],
 | 
						|
		"disable_msi", 0, 1, 0);
 | 
						|
#endif
 | 
						|
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &delay_link[index],
 | 
						|
		"delay_link", 0, 1, 0);
 | 
						|
 | 
						|
	bcm5700_validate_param_range(pUmDevice, &disable_d3hot[index],
 | 
						|
		"disable_d3hot", 0, 1, 0);
 | 
						|
	if (disable_d3hot[index]) {
 | 
						|
 | 
						|
#ifdef BCM_WOL
 | 
						|
		if (enable_wol[index]) {
 | 
						|
			pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_NONE;
 | 
						|
			pDevice->WakeUpMode = LM_WAKE_UP_MODE_NONE;
 | 
						|
			printk(KERN_WARNING "%s-%d: Wake-On-Lan disabled because D3Hot is disabled\n", bcm5700_driver, index);
 | 
						|
		}
 | 
						|
#endif
 | 
						|
		pDevice->Flags |= DISABLE_D3HOT_FLAG;
 | 
						|
	}
 | 
						|
 | 
						|
    return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/* From include/proto/ethernet.h */
 | 
						|
#define ETHER_TYPE_8021Q	0x8100		/* 802.1Q */
 | 
						|
 | 
						|
/* From include/proto/vlan.h */
 | 
						|
#define VLAN_PRI_MASK		7	/* 3 bits of priority */
 | 
						|
#define VLAN_PRI_SHIFT		13
 | 
						|
 | 
						|
/* Replace the priority in a vlan tag */
 | 
						|
#define	UPD_VLANTAG_PRIO(tag, prio) do { \
 | 
						|
	tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); \
 | 
						|
	tag |= prio << VLAN_PRI_SHIFT; \
 | 
						|
} while (0)
 | 
						|
 | 
						|
/* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
 | 
						|
 * Also updates the inplace vlan tag if requested.
 | 
						|
 * For debugging, it returns an indication of what it did.
 | 
						|
 */
 | 
						|
#define	PKTPRIO_VDSCP	0x100		/* DSCP prio found after VLAN tag */
 | 
						|
#define	PKTPRIO_VLAN	0x200		/* VLAN prio found */
 | 
						|
#define	PKTPRIO_UPD	0x400		/* DSCP used to update VLAN prio */
 | 
						|
#define	PKTPRIO_DSCP	0x800		/* DSCP prio found */
 | 
						|
#define	PKTSETPRIO(skb, x)		(((struct sk_buff*)(skb))->priority = (x))
 | 
						|
static uint
 | 
						|
pktsetprio(void *pkt, bool update_vtag)
 | 
						|
{
 | 
						|
	struct ether_header *eh;
 | 
						|
	struct ethervlan_header *evh;
 | 
						|
	uint8 *pktdata;
 | 
						|
	int priority = 0;
 | 
						|
	int rc = 0;
 | 
						|
 | 
						|
	pktdata = (uint8 *) PKTDATA(NULL, pkt);
 | 
						|
	ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
 | 
						|
 | 
						|
	eh = (struct ether_header *) pktdata;
 | 
						|
 | 
						|
	if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
 | 
						|
		uint16 vlan_tag;
 | 
						|
		int vlan_prio, dscp_prio = 0;
 | 
						|
 | 
						|
		evh = (struct ethervlan_header *)eh;
 | 
						|
 | 
						|
		vlan_tag = ntoh16(evh->vlan_tag);
 | 
						|
		vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
 | 
						|
 | 
						|
		if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
 | 
						|
			uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
 | 
						|
			uint8 tos_tc = IP_TOS(ip_body);
 | 
						|
			dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
 | 
						|
			if ((IP_VER(ip_body) == IP_VER_4) && (IPV4_PROT(ip_body) == IP_PROT_TCP)) {
 | 
						|
				int ip_len;
 | 
						|
				int src_port;
 | 
						|
				bool src_port_exc;
 | 
						|
				uint8 *tcp_hdr;
 | 
						|
 | 
						|
				ip_len = IPV4_PAYLOAD_LEN(ip_body);
 | 
						|
				tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD(ip_body);
 | 
						|
				src_port = TCP_SRC_PORT(tcp_hdr);
 | 
						|
				src_port_exc = (src_port == 10110) || (src_port == 10120) ||
 | 
						|
					(src_port == 10130) || (src_port == 10140);
 | 
						|
 | 
						|
				if ((ip_len == 40) && src_port_exc && TCP_IS_ACK(tcp_hdr)) {
 | 
						|
					dscp_prio = 7;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* DSCP priority gets precedence over 802.1P (vlan tag) */
 | 
						|
		if (dscp_prio != 0) {
 | 
						|
			priority = dscp_prio;
 | 
						|
			rc |= PKTPRIO_VDSCP;
 | 
						|
		} else {
 | 
						|
			priority = vlan_prio;
 | 
						|
			rc |= PKTPRIO_VLAN;
 | 
						|
		}
 | 
						|
		/* 
 | 
						|
		 * If the DSCP priority is not the same as the VLAN priority,
 | 
						|
		 * then overwrite the priority field in the vlan tag, with the
 | 
						|
		 * DSCP priority value. This is required for Linux APs because
 | 
						|
		 * the VLAN driver on Linux, overwrites the skb->priority field
 | 
						|
		 * with the priority value in the vlan tag
 | 
						|
		 */
 | 
						|
		if (update_vtag && (priority != vlan_prio)) {
 | 
						|
			vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
 | 
						|
			vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
 | 
						|
			evh->vlan_tag = hton16(vlan_tag);
 | 
						|
			rc |= PKTPRIO_UPD;
 | 
						|
		}
 | 
						|
	} else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
 | 
						|
		uint8 *ip_body = pktdata + sizeof(struct ether_header);
 | 
						|
		uint8 tos_tc = IP_TOS(ip_body);
 | 
						|
		priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
 | 
						|
		rc |= PKTPRIO_DSCP;
 | 
						|
		if ((IP_VER(ip_body) == IP_VER_4) && (IPV4_PROT(ip_body) == IP_PROT_TCP)) {
 | 
						|
			int ip_len;
 | 
						|
			int src_port;
 | 
						|
			bool src_port_exc;
 | 
						|
			uint8 *tcp_hdr;
 | 
						|
 | 
						|
			ip_len = IPV4_PAYLOAD_LEN(ip_body);
 | 
						|
			tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD(ip_body);
 | 
						|
			src_port = TCP_SRC_PORT(tcp_hdr);
 | 
						|
			src_port_exc = (src_port == 10110) || (src_port == 10120) ||
 | 
						|
				(src_port == 10130) || (src_port == 10140);
 | 
						|
 | 
						|
			if ((ip_len == 40) && src_port_exc && TCP_IS_ACK(tcp_hdr)) {
 | 
						|
				priority = 7;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	ASSERT(priority >= 0 && priority <= MAXPRIO);
 | 
						|
	PKTSETPRIO(pkt, priority);
 | 
						|
	return (rc | priority);
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_IndicateRxPackets(PLM_DEVICE_BLOCK pDevice)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
 | 
						|
	PLM_PACKET pPacket;
 | 
						|
	PUM_PACKET pUmPacket;
 | 
						|
	struct sk_buff *skb;
 | 
						|
	int size;
 | 
						|
	int vlan_tag_size = 0;
 | 
						|
	uint16 dscp_prio;
 | 
						|
 | 
						|
	if (pDevice->ReceiveMask & LM_KEEP_VLAN_TAG)
 | 
						|
		vlan_tag_size = 4;
 | 
						|
 | 
						|
	while (1) {
 | 
						|
		pPacket = (PLM_PACKET)
 | 
						|
			QQ_PopHead(&pDevice->RxPacketReceivedQ.Container);
 | 
						|
		if (pPacket == 0)
 | 
						|
			break;
 | 
						|
		pUmPacket = (PUM_PACKET) pPacket;
 | 
						|
#if !defined(NO_PCI_UNMAP)
 | 
						|
		pci_unmap_single(pUmDevice->pdev,
 | 
						|
				pci_unmap_addr(pUmPacket, map[0]),
 | 
						|
				pPacket->u.Rx.RxBufferSize,
 | 
						|
				PCI_DMA_FROMDEVICE);
 | 
						|
#endif
 | 
						|
		if ((pPacket->PacketStatus != LM_STATUS_SUCCESS) ||
 | 
						|
			((size = pPacket->PacketSize) >
 | 
						|
			(pDevice->RxMtu + vlan_tag_size))) {
 | 
						|
 | 
						|
			/* reuse skb */
 | 
						|
#ifdef BCM_TASKLET
 | 
						|
			QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket);
 | 
						|
#else
 | 
						|
			QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
 | 
						|
#endif
 | 
						|
			pUmDevice->rx_misc_errors++;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		skb = pUmPacket->skbuff;
 | 
						|
		skb_put(skb, size);
 | 
						|
		skb->pkt_type = 0;
 | 
						|
		/* Extract priority from payload and put it in skb->priority */
 | 
						|
		dscp_prio = 0;
 | 
						|
		if (pUmDevice->qos) {
 | 
						|
			uint rc;
 | 
						|
 | 
						|
			rc = pktsetprio(skb, TRUE);
 | 
						|
			if (rc & (PKTPRIO_VDSCP | PKTPRIO_DSCP))
 | 
						|
				dscp_prio = rc & VLAN_PRI_MASK;
 | 
						|
			if (rc != 0)
 | 
						|
				B57_INFO(("pktsetprio returned 0x%x, skb->priority: %d\n",
 | 
						|
				          rc, skb->priority));
 | 
						|
		}
 | 
						|
		skb->protocol = eth_type_trans(skb, skb->dev);
 | 
						|
		if (size > pDevice->RxMtu) {
 | 
						|
			/* Make sure we have a valid VLAN tag */
 | 
						|
			if (htons(skb->protocol) != ETHER_TYPE_8021Q) {
 | 
						|
				dev_kfree_skb_irq(skb);
 | 
						|
				pUmDevice->rx_misc_errors++;
 | 
						|
				goto drop_rx;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		pUmDevice->stats.rx_bytes += skb->len;
 | 
						|
 | 
						|
		if ((pPacket->Flags & RCV_BD_FLAG_TCP_UDP_CHKSUM_FIELD) &&
 | 
						|
			(pDevice->TaskToOffload &
 | 
						|
				LM_TASK_OFFLOAD_RX_TCP_CHECKSUM)) {
 | 
						|
			if (pPacket->u.Rx.TcpUdpChecksum == 0xffff) {
 | 
						|
 | 
						|
				skb->ip_summed = CHECKSUM_UNNECESSARY;
 | 
						|
#if TIGON3_DEBUG
 | 
						|
				pUmDevice->rx_good_chksum_count++;
 | 
						|
#endif
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				skb->ip_summed = CHECKSUM_NONE;
 | 
						|
				pUmDevice->rx_bad_chksum_count++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			skb->ip_summed = CHECKSUM_NONE;
 | 
						|
		}
 | 
						|
		{
 | 
						|
#ifdef BCM_VLAN
 | 
						|
			if (pUmDevice->vlgrp &&
 | 
						|
				(pPacket->Flags & RCV_BD_FLAG_VLAN_TAG)) {
 | 
						|
				/* Override vlan priority with dscp priority */
 | 
						|
				if (dscp_prio)
 | 
						|
					UPD_VLANTAG_PRIO(pPacket->VlanTag, dscp_prio);
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
				vlan_hwaccel_receive_skb(skb, pUmDevice->vlgrp,
 | 
						|
					pPacket->VlanTag);
 | 
						|
#else
 | 
						|
				vlan_hwaccel_rx(skb, pUmDevice->vlgrp,
 | 
						|
					pPacket->VlanTag);
 | 
						|
#endif
 | 
						|
			} else
 | 
						|
#endif
 | 
						|
			{
 | 
						|
#ifdef BCM_WL_EMULATOR
 | 
						|
				if(pDevice->wl_emulate_rx) {
 | 
						|
					/* bcmstats("emu recv %d %d"); */
 | 
						|
					wlcemu_receive_skb(pDevice->wlc, skb);
 | 
						|
					/* bcmstats("emu recv end %d %d"); */
 | 
						|
				}
 | 
						|
				else 
 | 
						|
#endif /* BCM_WL_EMULATOR  */
 | 
						|
				{
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
				netif_receive_skb(skb);
 | 
						|
#else
 | 
						|
				netif_rx(skb);
 | 
						|
#endif
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		pUmDevice->dev->last_rx = jiffies;
 | 
						|
 | 
						|
drop_rx:
 | 
						|
#ifdef BCM_TASKLET
 | 
						|
		pUmPacket->skbuff = 0;
 | 
						|
		QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket);
 | 
						|
#else
 | 
						|
#ifdef BCM_WL_EMULATOR
 | 
						|
		skb = (struct sk_buff *)wlcemu_pktget(pDevice->wlc,pPacket->u.Rx.RxBufferSize + 2);
 | 
						|
#else
 | 
						|
		skb = dev_alloc_skb(pPacket->u.Rx.RxBufferSize + 2 + EXTRA_HDR);
 | 
						|
#endif /* BCM_WL_EMULATOR  */
 | 
						|
		if (skb == 0) {
 | 
						|
			pUmPacket->skbuff = 0;
 | 
						|
			QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			pUmPacket->skbuff = skb;
 | 
						|
			skb->dev = pUmDevice->dev;
 | 
						|
#ifndef BCM_WL_EMULATOR
 | 
						|
			skb_reserve(skb, EXTRA_HDR - pUmDevice->rx_buf_align);
 | 
						|
#endif
 | 
						|
			QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
 | 
						|
		}
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_CoalesceTxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
 | 
						|
{
 | 
						|
	PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
 | 
						|
	struct sk_buff *skb = pUmPacket->skbuff;
 | 
						|
	struct sk_buff *nskb;
 | 
						|
#if !defined(NO_PCI_UNMAP)
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
 | 
						|
 | 
						|
	pci_unmap_single(pUmDevice->pdev,
 | 
						|
			pci_unmap_addr(pUmPacket, map[0]),
 | 
						|
			pci_unmap_len(pUmPacket, map_len[0]),
 | 
						|
			PCI_DMA_TODEVICE);
 | 
						|
#if MAX_SKB_FRAGS
 | 
						|
	{
 | 
						|
		int i;
 | 
						|
 | 
						|
		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
 | 
						|
			pci_unmap_page(pUmDevice->pdev,
 | 
						|
				pci_unmap_addr(pUmPacket, map[i + 1]),
 | 
						|
				pci_unmap_len(pUmPacket, map_len[i + 1]),
 | 
						|
				PCI_DMA_TODEVICE);
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
	if ((nskb = skb_copy(skb, GFP_ATOMIC))) {
 | 
						|
		pUmPacket->lm_packet.u.Tx.FragCount = 1;
 | 
						|
		dev_kfree_skb(skb);
 | 
						|
		pUmPacket->skbuff = nskb;
 | 
						|
		return LM_STATUS_SUCCESS;
 | 
						|
	}
 | 
						|
	dev_kfree_skb(skb);
 | 
						|
	pUmPacket->skbuff = 0;
 | 
						|
	return LM_STATUS_FAILURE;
 | 
						|
}
 | 
						|
 | 
						|
/* Returns 1 if not all buffers are allocated */
 | 
						|
STATIC int
 | 
						|
replenish_rx_buffers(PUM_DEVICE_BLOCK pUmDevice, int max)
 | 
						|
{
 | 
						|
	PLM_PACKET pPacket;
 | 
						|
	PUM_PACKET pUmPacket;
 | 
						|
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
 | 
						|
	struct sk_buff *skb;
 | 
						|
	int queue_rx = 0;
 | 
						|
	int alloc_cnt = 0;
 | 
						|
	int ret = 0;
 | 
						|
 | 
						|
	while ((pUmPacket = (PUM_PACKET)
 | 
						|
		QQ_PopHead(&pUmDevice->rx_out_of_buf_q.Container)) != 0) {
 | 
						|
		pPacket = (PLM_PACKET) pUmPacket;
 | 
						|
		if (pUmPacket->skbuff) {
 | 
						|
			/* reuse an old skb */
 | 
						|
			QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
 | 
						|
			queue_rx = 1;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
#ifdef BCM_WL_EMULATOR
 | 
						|
		if ((skb = (struct sk_buff *)wlcemu_pktget(pDevice->wlc,pPacket->u.Rx.RxBufferSize + 2)) == 0)
 | 
						|
#else 
 | 
						|
	       if ((skb = dev_alloc_skb(pPacket->u.Rx.RxBufferSize + 2 + EXTRA_HDR)) == 0)
 | 
						|
#endif /* BCM_WL_EMULATOR  */
 | 
						|
	       {
 | 
						|
		       QQ_PushHead(&pUmDevice->rx_out_of_buf_q.Container,
 | 
						|
		                   pPacket);
 | 
						|
		       ret = 1;
 | 
						|
		       break;
 | 
						|
	       }
 | 
						|
		pUmPacket->skbuff = skb;
 | 
						|
		skb->dev = pUmDevice->dev;
 | 
						|
#ifndef BCM_WL_EMULATOR
 | 
						|
			skb_reserve(skb, EXTRA_HDR - pUmDevice->rx_buf_align);
 | 
						|
#endif
 | 
						|
		QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
 | 
						|
		queue_rx = 1;
 | 
						|
		if (max > 0) {
 | 
						|
			alloc_cnt++;
 | 
						|
			if (alloc_cnt >= max)
 | 
						|
				break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (queue_rx || pDevice->QueueAgain) {
 | 
						|
		LM_QueueRxPackets(pDevice);
 | 
						|
	}
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_IndicateTxPackets(PLM_DEVICE_BLOCK pDevice)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
 | 
						|
	PLM_PACKET pPacket;
 | 
						|
	PUM_PACKET pUmPacket;
 | 
						|
	struct sk_buff *skb;
 | 
						|
#if !defined(NO_PCI_UNMAP) && MAX_SKB_FRAGS
 | 
						|
	int i;
 | 
						|
#endif
 | 
						|
 | 
						|
	while (1) {
 | 
						|
		pPacket = (PLM_PACKET)
 | 
						|
			QQ_PopHead(&pDevice->TxPacketXmittedQ.Container);
 | 
						|
		if (pPacket == 0)
 | 
						|
			break;
 | 
						|
		pUmPacket = (PUM_PACKET) pPacket;
 | 
						|
		skb = pUmPacket->skbuff;
 | 
						|
#if !defined(NO_PCI_UNMAP)
 | 
						|
		pci_unmap_single(pUmDevice->pdev,
 | 
						|
				pci_unmap_addr(pUmPacket, map[0]),
 | 
						|
				pci_unmap_len(pUmPacket, map_len[0]),
 | 
						|
				PCI_DMA_TODEVICE);
 | 
						|
#if MAX_SKB_FRAGS
 | 
						|
		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
 | 
						|
			pci_unmap_page(pUmDevice->pdev,
 | 
						|
				pci_unmap_addr(pUmPacket, map[i + 1]),
 | 
						|
				pci_unmap_len(pUmPacket, map_len[i + 1]),
 | 
						|
				PCI_DMA_TODEVICE);
 | 
						|
		}
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
		dev_kfree_skb_irq(skb);
 | 
						|
		pUmPacket->skbuff = 0;
 | 
						|
		QQ_PushTail(&pDevice->TxPacketFreeQ.Container, pPacket);
 | 
						|
	}
 | 
						|
	if (pUmDevice->tx_full) {
 | 
						|
		if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) >=
 | 
						|
			(pDevice->TxPacketDescCnt >> 1)) {
 | 
						|
 | 
						|
			pUmDevice->tx_full = 0;
 | 
						|
			netif_wake_queue(pUmDevice->dev);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_IndicateStatus(PLM_DEVICE_BLOCK pDevice, LM_STATUS Status)
 | 
						|
{
 | 
						|
	PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
 | 
						|
	struct net_device *dev = pUmDevice->dev;
 | 
						|
	LM_FLOW_CONTROL flow_control;
 | 
						|
	int speed = 0;
 | 
						|
 | 
						|
	if (!pUmDevice->opened)
 | 
						|
		return LM_STATUS_SUCCESS;
 | 
						|
 | 
						|
	if (!pUmDevice->suspended) {
 | 
						|
		if (Status == LM_STATUS_LINK_DOWN) {
 | 
						|
			netif_carrier_off(dev);
 | 
						|
		}
 | 
						|
		else if (Status == LM_STATUS_LINK_ACTIVE) {
 | 
						|
			netif_carrier_on(dev);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (pUmDevice->delayed_link_ind > 0) {
 | 
						|
		pUmDevice->delayed_link_ind = 0;
 | 
						|
		if (Status == LM_STATUS_LINK_DOWN) {
 | 
						|
			B57_INFO(("%s: %s NIC Link is DOWN\n", bcm5700_driver, dev->name));
 | 
						|
		}
 | 
						|
		else if (Status == LM_STATUS_LINK_ACTIVE) {
 | 
						|
			B57_INFO(("%s: %s NIC Link is UP, ", bcm5700_driver, dev->name));
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		if (Status == LM_STATUS_LINK_DOWN) {
 | 
						|
			B57_INFO(("%s: %s NIC Link is Down\n", bcm5700_driver, dev->name));
 | 
						|
		}
 | 
						|
		else if (Status == LM_STATUS_LINK_ACTIVE) {
 | 
						|
			B57_INFO(("%s: %s NIC Link is Up, ", bcm5700_driver, dev->name));
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (Status == LM_STATUS_LINK_ACTIVE) {
 | 
						|
		if (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS)
 | 
						|
			speed = 1000;
 | 
						|
		else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS)
 | 
						|
			speed = 100;
 | 
						|
		else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS)
 | 
						|
			speed = 10;
 | 
						|
 | 
						|
		B57_INFO(("%d Mbps ", speed));
 | 
						|
 | 
						|
		if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL)
 | 
						|
			B57_INFO(("full duplex"));
 | 
						|
		else
 | 
						|
			B57_INFO(("half duplex"));
 | 
						|
 | 
						|
		flow_control = pDevice->FlowControl &
 | 
						|
			(LM_FLOW_CONTROL_RECEIVE_PAUSE |
 | 
						|
			LM_FLOW_CONTROL_TRANSMIT_PAUSE);
 | 
						|
		if (flow_control) {
 | 
						|
			if (flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE) {
 | 
						|
				B57_INFO((", receive "));
 | 
						|
				if (flow_control & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
 | 
						|
					B57_INFO(("& transmit "));
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				B57_INFO((", transmit "));
 | 
						|
			}
 | 
						|
			B57_INFO(("flow control ON"));
 | 
						|
		}
 | 
						|
		B57_INFO(("\n"));
 | 
						|
	}
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
MM_UnmapRxDma(LM_DEVICE_BLOCK *pDevice, LM_PACKET *pPacket)
 | 
						|
{
 | 
						|
#if !defined(NO_PCI_UNMAP)
 | 
						|
	UM_DEVICE_BLOCK *pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
 | 
						|
	UM_PACKET *pUmPacket = (UM_PACKET *) pPacket;
 | 
						|
 | 
						|
	if (!pUmPacket->skbuff)
 | 
						|
		return;
 | 
						|
 | 
						|
	pci_unmap_single(pUmDevice->pdev,
 | 
						|
			pci_unmap_addr(pUmPacket, map[0]),
 | 
						|
			pPacket->u.Rx.RxBufferSize,
 | 
						|
			PCI_DMA_FROMDEVICE);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_FreeRxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
 | 
						|
{
 | 
						|
	PUM_PACKET pUmPacket;
 | 
						|
	struct sk_buff *skb;
 | 
						|
 | 
						|
	if (pPacket == 0)
 | 
						|
		return LM_STATUS_SUCCESS;
 | 
						|
	pUmPacket = (PUM_PACKET) pPacket;
 | 
						|
	if ((skb = pUmPacket->skbuff)) {
 | 
						|
		/* DMA address already unmapped */
 | 
						|
		dev_kfree_skb(skb);
 | 
						|
	}
 | 
						|
	pUmPacket->skbuff = 0;
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
LM_STATUS
 | 
						|
MM_Sleep(LM_DEVICE_BLOCK *pDevice, LM_UINT32 msec)
 | 
						|
{
 | 
						|
	current->state = TASK_INTERRUPTIBLE;
 | 
						|
	if (schedule_timeout(HZ * msec / 1000) != 0) {
 | 
						|
		return LM_STATUS_FAILURE;
 | 
						|
	}
 | 
						|
	if (signal_pending(current))
 | 
						|
		return LM_STATUS_FAILURE;
 | 
						|
 | 
						|
	return LM_STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
bcm5700_shutdown(UM_DEVICE_BLOCK *pUmDevice)
 | 
						|
{
 | 
						|
	LM_DEVICE_BLOCK *pDevice = (LM_DEVICE_BLOCK *) pUmDevice;
 | 
						|
 | 
						|
	bcm5700_intr_off(pUmDevice);
 | 
						|
	netif_carrier_off(pUmDevice->dev);
 | 
						|
#ifdef BCM_TASKLET
 | 
						|
	tasklet_kill(&pUmDevice->tasklet);
 | 
						|
#endif
 | 
						|
	bcm5700_poll_wait(pUmDevice);
 | 
						|
 | 
						|
	LM_Halt(pDevice);
 | 
						|
 | 
						|
	pDevice->InitDone = 0;
 | 
						|
	bcm5700_free_remaining_rx_bufs(pUmDevice);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
bcm5700_free_remaining_rx_bufs(UM_DEVICE_BLOCK *pUmDevice)
 | 
						|
{
 | 
						|
	LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev;
 | 
						|
	UM_PACKET *pUmPacket;
 | 
						|
	int cnt, i;
 | 
						|
 | 
						|
	cnt = QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container);
 | 
						|
	for (i = 0; i < cnt; i++) {
 | 
						|
		if ((pUmPacket =
 | 
						|
			QQ_PopHead(&pUmDevice->rx_out_of_buf_q.Container))
 | 
						|
			!= 0) {
 | 
						|
 | 
						|
			MM_UnmapRxDma(pDevice, (LM_PACKET *) pUmPacket);
 | 
						|
			MM_FreeRxBuffer(pDevice, &pUmPacket->lm_packet);
 | 
						|
			QQ_PushTail(&pDevice->RxPacketFreeQ.Container,
 | 
						|
				pUmPacket);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
bcm5700_validate_param_range(UM_DEVICE_BLOCK *pUmDevice, int *param,
 | 
						|
	char *param_name, int min, int max, int deflt)
 | 
						|
{
 | 
						|
	if (((unsigned int) *param < (unsigned int) min) ||
 | 
						|
		((unsigned int) *param > (unsigned int) max)) {
 | 
						|
 | 
						|
		printk(KERN_WARNING "%s-%d: Invalid %s parameter (%u), using %u\n", bcm5700_driver, pUmDevice->index, param_name, (unsigned int) *param, (unsigned int) deflt);
 | 
						|
		*param = deflt;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
struct net_device *
 | 
						|
bcm5700_find_peer(struct net_device *dev)
 | 
						|
{
 | 
						|
	struct net_device *tmp_dev;
 | 
						|
	UM_DEVICE_BLOCK *pUmDevice, *pUmTmp;
 | 
						|
	LM_DEVICE_BLOCK *pDevice;
 | 
						|
 | 
						|
	tmp_dev = 0;
 | 
						|
	pUmDevice = (UM_DEVICE_BLOCK *) dev->priv;
 | 
						|
	pDevice = &pUmDevice->lm_dev;
 | 
						|
	if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) {
 | 
						|
		tmp_dev = root_tigon3_dev;
 | 
						|
		while (tmp_dev) {
 | 
						|
			pUmTmp = (PUM_DEVICE_BLOCK) tmp_dev->priv;
 | 
						|
			if ((tmp_dev != dev) &&
 | 
						|
				(pUmDevice->pdev->bus->number ==
 | 
						|
				pUmTmp->pdev->bus->number) &&
 | 
						|
				PCI_SLOT(pUmDevice->pdev->devfn) ==
 | 
						|
				PCI_SLOT(pUmTmp->pdev->devfn)) {
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			tmp_dev = pUmTmp->next_module;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return tmp_dev;
 | 
						|
}
 | 
						|
 | 
						|
LM_DEVICE_BLOCK *
 | 
						|
MM_FindPeerDev(LM_DEVICE_BLOCK *pDevice)
 | 
						|
{
 | 
						|
	UM_DEVICE_BLOCK *pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
 | 
						|
	struct net_device *dev = pUmDevice->dev;
 | 
						|
	struct net_device *peer_dev;
 | 
						|
 | 
						|
	peer_dev = bcm5700_find_peer(dev);
 | 
						|
	if (!peer_dev)
 | 
						|
		return 0;
 | 
						|
	return ((LM_DEVICE_BLOCK *) peer_dev->priv);
 | 
						|
}
 | 
						|
 | 
						|
int MM_FindCapability(LM_DEVICE_BLOCK *pDevice, int capability)
 | 
						|
{
 | 
						|
	UM_DEVICE_BLOCK *pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
 | 
						|
	return (pci_find_capability(pUmDevice->pdev, capability));
 | 
						|
}
 | 
						|
 | 
						|
#if defined(HAVE_POLL_CONTROLLER)||defined(CONFIG_NET_POLL_CONTROLLER)
 | 
						|
STATIC void
 | 
						|
poll_bcm5700(struct net_device *dev)
 | 
						|
{
 | 
						|
	UM_DEVICE_BLOCK *pUmDevice = dev->priv;
 | 
						|
 | 
						|
#if defined(RED_HAT_LINUX_KERNEL) && (LINUX_VERSION_CODE < 0x020605)
 | 
						|
	if (netdump_mode) {
 | 
						|
		bcm5700_interrupt(pUmDevice->pdev->irq, dev, NULL);
 | 
						|
#ifdef BCM_NAPI_RXPOLL
 | 
						|
		if (dev->poll_list.prev) {
 | 
						|
			int budget = 64;
 | 
						|
 | 
						|
			bcm5700_poll(dev, &budget);
 | 
						|
		}
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	else
 | 
						|
#endif
 | 
						|
	{
 | 
						|
		disable_irq(pUmDevice->pdev->irq);
 | 
						|
		bcm5700_interrupt(pUmDevice->pdev->irq, dev, NULL);
 | 
						|
		enable_irq(pUmDevice->pdev->irq);
 | 
						|
	}
 | 
						|
}
 | 
						|
#endif
 |