Commit ed492288 authored by Jeff Garzik's avatar Jeff Garzik

Merge mandrakesoft.com:/home/jgarzik/vanilla/linus-2.5

into mandrakesoft.com:/home/jgarzik/repo/net-drivers-2.5
parents d9f2d50e 77d28a4f
......@@ -65,9 +65,15 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define CP_VLAN_TAG_USED 1
#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
do { (tx_desc)->opts2 = (vlan_tag_value); } while (0)
#else
#define CP_VLAN_TAG_USED 0
#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
do { (tx_desc)->opts2 = 0; } while (0)
#endif
/* These identify the driver base version and may not be removed. */
static char version[] __devinitdata =
......@@ -643,7 +649,7 @@ static void cp_tx (struct cp_private *cp)
cp->tx_tail = tx_tail;
if (netif_queue_stopped(cp->dev) && (TX_BUFFS_AVAIL(cp) > 1))
if (netif_queue_stopped(cp->dev) && (TX_BUFFS_AVAIL(cp) > (MAX_SKB_FRAGS + 1)))
netif_wake_queue(cp->dev);
}
......@@ -658,9 +664,12 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&cp->lock);
/* This is a hard error, log it. */
if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
spin_unlock_irq(&cp->lock);
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
dev->name);
return 1;
}
......@@ -760,9 +769,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
if (netif_msg_tx_queued(cp))
printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n",
dev->name, entry, skb->len);
if (TX_BUFFS_AVAIL(cp) < 0)
BUG();
if (TX_BUFFS_AVAIL(cp) == 0)
if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
spin_unlock_irq(&cp->lock);
......@@ -773,6 +780,9 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
return 0;
}
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked. */
static void __cp_set_rx_mode (struct net_device *dev)
{
struct cp_private *cp = dev->priv;
......@@ -1072,6 +1082,7 @@ static int cp_change_mtu(struct net_device *dev, int new_mtu)
/* if network interface not up, no need for complexity */
if (!netif_running(dev)) {
dev->mtu = new_mtu;
cp_set_rxbufsize(cp); /* set new rx buf size */
return 0;
}
......@@ -1081,6 +1092,7 @@ static int cp_change_mtu(struct net_device *dev, int new_mtu)
cp_stop_hw(cp); /* stop h/w and free rings */
cp_clean_rings(cp);
dev->mtu = new_mtu;
cp_set_rxbufsize(cp); /* set new rx buf size */
rc = cp_init_rings(cp); /* realloc and restart h/w */
......@@ -1226,7 +1238,7 @@ static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
}
#if CP_VLAN_TAG_USED
static int cp_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
static void cp_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
{
struct cp_private *cp = dev->priv;
......@@ -1234,8 +1246,6 @@ static int cp_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
cp->vlgrp = grp;
cpw16(CpCmd, cpr16(CpCmd) | RxVlanOn);
spin_unlock_irq(&cp->lock);
return 0;
}
static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
......
......@@ -17,6 +17,7 @@
#include <linux/timer.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/crc32.h>
#include <asm/prom.h>
#include <asm/dbdma.h>
#include <asm/io.h>
......
......@@ -128,12 +128,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define E100_DEFAULT_TCB MAX_TCB
#define E100_MIN_TCB 2*TX_FRAME_CNT + 3 /* make room for at least 2 interrupts */
#ifdef __ia64__
/* We can't use too many DMAble buffers on IA64 machines with >4 GB mem */
#define E100_MAX_TCB 64
#else
#define E100_MAX_TCB 1024
#endif /* __ia64__ */
#define E100_DEFAULT_RFD MAX_RFD
#define E100_MIN_RFD 8
......@@ -766,6 +761,8 @@ typedef enum _non_tx_cmd_state_t {
#define IPCB_INSERTVLAN_ENABLE BIT_1
#define IPCB_IP_ACTIVATION_DEFAULT IPCB_HARDWAREPARSING_ENABLE
#define FOLD_CSUM(_XSUM) ((((_XSUM << 16) | (_XSUM >> 16)) + _XSUM) >> 16)
/* Transmit Buffer Descriptor (TBD)*/
typedef struct _tbd_t {
u32 tbd_buf_addr; /* Physical Transmit Buffer Address */
......@@ -1008,6 +1005,11 @@ struct e100_private {
u32 wolopts;
u16 ip_lbytes;
#endif
#ifdef CONFIG_PM
u32 pci_state[16];
#endif
};
#define E100_AUTONEG 0
......@@ -1030,4 +1032,9 @@ extern unsigned char e100_selftest(struct e100_private *bdp, u32 *st_timeout,
extern unsigned char e100_get_link_state(struct e100_private *bdp);
extern unsigned char e100_wait_scb(struct e100_private *bdp);
extern void e100_deisolate_driver(struct e100_private *bdp,
u8 recover, u8 full_reset);
extern unsigned char e100_hw_reset_recover(struct e100_private *bdp,
u32 reset_cmd);
#endif
......@@ -69,6 +69,10 @@ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************
Portions (C) 2002 Red Hat, Inc. under the terms of the GNU GPL v2.
*******************************************************************************/
/**********************************************************************
......@@ -152,7 +156,7 @@ eeprom_set_semaphore(struct e100_private *adapter)
}
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
schedule_timeout(1+(HZ-1)/100);
}
return false;
}
......@@ -252,19 +256,12 @@ e100_eeprom_size(struct e100_private *adapter)
// Returns: bits in an address for that size eeprom
//----------------------------------------------------------------------------------------
static u16
static inline int
eeprom_address_size(u16 size)
{
switch (size) {
case 64:
return 6;
case 128:
return 7;
case 256:
return 8;
}
return 0; //fix compiler warning or error!
int isize = size;
return ffs(isize);
}
//----------------------------------------------------------------------------------------
......@@ -348,6 +345,7 @@ shift_out_bits(struct e100_private *adapter, u16 data, u16 count)
x |= EEDI;
writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
readw(&(adapter->scb->scb_status)); /* flush command to card */
udelay(EEPROM_STALL_TIME);
raise_clock(adapter, &x);
lower_clock(adapter, &x);
......@@ -374,6 +372,7 @@ raise_clock(struct e100_private *adapter, u16 *x)
{
*x = *x | EESK;
writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter));
readw(&(adapter->scb->scb_status)); /* flush command to card */
udelay(EEPROM_STALL_TIME);
}
......@@ -393,6 +392,7 @@ lower_clock(struct e100_private *adapter, u16 *x)
{
*x = *x & ~EESK;
writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter));
readw(&(adapter->scb->scb_status)); /* flush command to card */
udelay(EEPROM_STALL_TIME);
}
......@@ -498,7 +498,7 @@ e100_eeprom_write_word(struct e100_private *adapter, u16 reg, u16 data)
x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
x &= ~(EEDI | EEDO | EESK);
writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
wmb();
readw(&(adapter->scb->scb_status)); /* flush command to card */
udelay(EEPROM_STALL_TIME);
x |= EECS;
writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
......@@ -587,7 +587,7 @@ eeprom_wait_cmd_done(struct e100_private *adapter)
return true;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
schedule_timeout(1+(HZ-1)/100);
}
return false;
......@@ -606,9 +606,10 @@ eeprom_stand_by(struct e100_private *adapter)
x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
x &= ~(EECS | EESK);
writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
wmb();
readw(&(adapter->scb->scb_status)); /* flush command to card */
udelay(EEPROM_STALL_TIME);
x |= EECS;
writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
readw(&(adapter->scb->scb_status)); /* flush command to card */
udelay(EEPROM_STALL_TIME);
}
......@@ -69,6 +69,10 @@ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************
Portions (C) 2002 Red Hat, Inc. under the terms of the GNU GPL v2.
*******************************************************************************/
/**********************************************************************
......@@ -122,7 +126,6 @@ static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *);
static void e100_get_speed_duplex_caps(struct e100_private *);
static int e100_ethtool_get_settings(struct net_device *, struct ifreq *);
static int e100_ethtool_set_settings(struct net_device *, struct ifreq *);
static void e100_set_speed_duplex(struct e100_private *);
#ifdef ETHTOOL_GDRVINFO
static int e100_ethtool_get_drvinfo(struct net_device *, struct ifreq *);
......@@ -163,7 +166,8 @@ static void e100_non_tx_background(unsigned long);
/* Global Data structures and variables */
char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
#define E100_VERSION "2.0.20-pre1"
#define E100_VERSION "2.0.22-pre1"
#define E100_FULL_DRIVER_NAME "Intel(R) PRO/100 Fast Ethernet Adapter - Loadable driver, ver "
const char *e100_version = E100_VERSION;
......@@ -171,6 +175,13 @@ const char *e100_full_driver_name = E100_FULL_DRIVER_NAME E100_VERSION;
char *e100_short_driver_name = "e100";
static int e100nics = 0;
#ifdef CONFIG_PM
static int e100_save_state(struct pci_dev *pcid, u32 state);
static int e100_suspend(struct pci_dev *pcid, u32 state);
static int e100_enable_wake(struct pci_dev *pcid, u32 state, int enable);
static int e100_resume(struct pci_dev *pcid);
#endif
/*********************************************************************/
/*! This is a GCC extension to ANSI C.
* See the item "Labeled Elements in Initializers" in the section
......@@ -203,6 +214,7 @@ struct net_device_stats *e100_get_stats(struct net_device *);
static void e100intr(int, void *, struct pt_regs *);
static void e100_print_brd_conf(struct e100_private *);
static void e100_set_multi(struct net_device *);
void e100_set_speed_duplex(struct e100_private *);
char *e100_get_brand_msg(struct e100_private *);
static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
......@@ -517,6 +529,7 @@ e100_dis_intr(struct e100_private *bdp)
{
/* Disable interrupts on our PCI board by setting the mask bit */
writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi);
readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */
}
/**
......@@ -537,6 +550,7 @@ e100_trigger_SWI(struct e100_private *bdp)
{
/* Trigger interrupt on our PCI board by asserting SWI bit */
writeb(SCB_SOFT_INT, &bdp->scb->scb_cmd_hi);
readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */
}
static int __devinit
......@@ -728,8 +742,15 @@ e100_remove1(struct pci_dev *pcid)
}
#ifdef ETHTOOL_GWOL
/* Set up wol options and enable PME */
e100_do_wol(pcid, bdp);
/* Set up wol options and enable PME if wol is enabled */
if (bdp->wolopts) {
e100_do_wol(pcid, bdp);
/* Enable PME for power state D3 */
pci_enable_wake(pcid, 3, 1);
/* Set power state to D1 in case driver is RELOADED */
/* If system powers down, device is switched from D1 to D3 */
pci_set_power_state(pcid, 1);
}
#endif
e100_clear_structs(dev);
......@@ -744,8 +765,15 @@ static struct pci_driver e100_driver = {
id_table: e100_id_table,
probe: e100_found1,
remove: __devexit_p(e100_remove1),
#ifdef CONFIG_PM
suspend: e100_suspend,
resume: e100_resume,
save_state: e100_save_state,
enable_wake: e100_enable_wake,
#else
suspend: NULL,
resume: NULL,
#endif
};
static int __init
......@@ -1194,7 +1222,7 @@ e100_set_multi(struct net_device *dev)
/* reconfigure the chip if something has changed in its config space */
e100_config(bdp);
if ((promisc_enbl) || (mulcast_enbl)) {
if (promisc_enbl || mulcast_enbl) {
goto exit; /* no need for Multicast Cmd */
}
......@@ -1996,8 +2024,9 @@ e100_rx_srv(struct e100_private *bdp, u32 max_number_of_rfds,
if (max_number_of_rfds && (rfd_cnt >= max_number_of_rfds)) {
break;
}
if (list_empty(&(bdp->active_rx_list)))
if (list_empty(&(bdp->active_rx_list))) {
break;
}
rx_struct = list_entry(bdp->active_rx_list.next,
struct rx_list_elem, list_elem);
......@@ -2030,10 +2059,8 @@ e100_rx_srv(struct e100_private *bdp, u32 max_number_of_rfds,
(data_sz + bdp->rfd_size),
PCI_DMA_FROMDEVICE);
// we unmap using DMA_TODEVICE to avoid another memcpy from the
// bounce buffer
pci_unmap_single(bdp->pdev, rx_struct->dma_addr,
sizeof (rfd_t), PCI_DMA_TODEVICE);
sizeof (rfd_t), PCI_DMA_FROMDEVICE);
list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool));
......@@ -2146,6 +2173,34 @@ e100_refresh_txthld(struct e100_private *bdp)
} /* end underrun check */
}
#ifdef E100_ZEROCOPY
/**
* e100_pseudo_hdr_csum - compute IP pseudo-header checksum
* @ip: points to the header of the IP packet
*
* Return the 16 bit checksum of the IP pseudo-header.,which is computed
* on the fields: IP src, IP dst, next protocol, payload length.
* The checksum vaule is returned in network byte order.
*/
static inline u16
e100_pseudo_hdr_csum(const struct iphdr *ip)
{
u32 pseudo = 0;
u32 payload_len = 0;
payload_len = ntohs(ip->tot_len) - (ip->ihl * 4);
pseudo += htons(payload_len);
pseudo += (ip->protocol << 8);
pseudo += ip->saddr & 0x0000ffff;
pseudo += (ip->saddr & 0xffff0000) >> 16;
pseudo += ip->daddr & 0x0000ffff;
pseudo += (ip->daddr & 0xffff0000) >> 16;
return FOLD_CSUM(pseudo);
}
#endif /* E100_ZEROCOPY */
/**
* e100_prepare_xmit_buff - prepare a buffer for transmission
* @bdp: atapter's private data struct
......@@ -2204,10 +2259,9 @@ e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb)
chksum = &(udp->check);
}
*chksum = csum_tcpudp_magic(ip->daddr, ip->saddr,
sizeof (struct tcphdr),
ip->protocol, 0);
*chksum = e100_pseudo_hdr_csum(ip);
}
} else {
if (bdp->flags & USE_IPCB) {
tcb->tcbu.ipcb.ip_activation_high =
......@@ -2319,9 +2373,8 @@ e100_start_cu(struct e100_private *bdp, tcb_t *tcb)
if (!e100_wait_cus_idle(bdp))
printk("%s cu_start: timeout waiting for cu\n",
bdp->device->name);
if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
SCB_CUC_START)) {
SCB_CUC_START)) {
printk("%s cu_start: timeout waiting for scb\n",
bdp->device->name);
e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
......@@ -2378,6 +2431,7 @@ e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result)
/* Do the port command */
writel(selftest_cmd, &bdp->scb->scb_port);
readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */
/* Wait at least 10 milliseconds for the self-test to complete */
set_current_state(TASK_UNINTERRUPTIBLE);
......@@ -2386,8 +2440,6 @@ e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result)
/* disable interrupts since the're now enabled */
e100_dis_intr(bdp);
rmb();
/* if The First Self Test DWORD Still Zero, We've timed out. If the
* second DWORD is not zero then we have an error. */
if ((bdp->selftest->st_sign == 0) || (bdp->selftest->st_result != 0)) {
......@@ -2681,7 +2733,7 @@ e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command)
wmb();
if (in_interrupt())
if (in_interrupt() || netif_running(bdp->device))
return e100_delayed_exec_non_cu_cmd(bdp, command);
spin_lock_bh(&(bdp->bd_non_tx_lock));
......@@ -2711,7 +2763,7 @@ e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command)
bdp->next_cu_cmd = START_WAIT;
spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
/* now wait for completion of non-cu CB up to 20 msec*/
/* now wait for completion of non-cu CB up to 20 msec */
expiration_time = jiffies + HZ / 50 + 1;
while (time_before(jiffies, expiration_time)) {
rmb();
......@@ -2754,6 +2806,7 @@ e100_sw_reset(struct e100_private *bdp, u32 reset_cmd)
{
/* Do a selective reset first to avoid a potential PCI hang */
writel(PORT_SELECTIVE_RESET, &bdp->scb->scb_port);
readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */
/* wait for the reset to take effect */
udelay(20);
......@@ -3086,13 +3139,140 @@ e100_isolate_driver(struct e100_private *bdp)
del_timer_sync(&bdp->watchdog_timer);
netif_stop_queue(bdp->device);
if (netif_running(bdp->device))
netif_stop_queue(bdp->device);
bdp->last_tcb = NULL;
e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
}
void
e100_set_speed_duplex(struct e100_private *bdp)
{
e100_phy_set_speed_duplex(bdp, true);
e100_config_fc(bdp); /* re-config flow-control if necessary */
e100_config(bdp);
}
static void
e100_tcb_add_C_bit(struct e100_private *bdp)
{
tcb_t *tcb = (tcb_t *) bdp->tcb_pool.data;
int i;
for (i = 0; i < bdp->params.TxDescriptors; i++, tcb++) {
tcb->tcb_hdr.cb_status |= cpu_to_le16(CB_STATUS_COMPLETE);
}
}
/*
* Procedure: e100_hw_reset_recover
*
* Description: This routine will recover the hw after reset.
*
* Arguments:
* bdp - Ptr to this card's e100_bdconfig structure
* reset_cmd - s/w reset or selective reset.
*
* Returns:
* true upon success
* false upon failure
*/
unsigned char
e100_hw_reset_recover(struct e100_private *bdp, u32 reset_cmd)
{
bdp->last_tcb = NULL;
if (reset_cmd == PORT_SOFTWARE_RESET) {
/*load CU & RU base */
if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) {
return false;
}
if (e100_load_microcode(bdp)) {
bdp->flags |= DF_UCODE_LOADED;
}
if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) {
return false;
}
/* Issue the load dump counters address command */
if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys,
SCB_CUC_DUMP_ADDR)) {
return false;
}
if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) {
printk(KERN_ERR
"e100_hw_reset_recover: setup iaaddr failed\n");
return false;
}
e100_set_multi_exec(bdp->device);
/* Change for 82558 enhancement */
/* If 82558/9 and if the user has enabled flow control, set up * the
* Flow Control Reg. in the CSR */
if ((bdp->flags & IS_BACHELOR)
&& (bdp->params.b_params & PRM_FC)) {
writeb(DFLT_FC_THLD,
&bdp->scb->scb_ext.d101_scb.scb_fc_thld);
writeb(DFLT_FC_CMD,
&bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
}
}
e100_force_config(bdp);
return true;
}
void
e100_deisolate_driver(struct e100_private *bdp, u8 recover, u8 full_init)
{
if (full_init) {
e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
if (!e100_hw_reset_recover(bdp, PORT_SOFTWARE_RESET))
printk(KERN_ERR "e100_deisolate_driver:"
" HW SOFTWARE reset recover failed\n");
}
if (recover) {
bdp->next_cu_cmd = START_WAIT;
bdp->last_tcb = NULL;
/* lets reset the chip */
if (!full_init) {
e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
if (!e100_hw_reset_recover(bdp, PORT_SELECTIVE_RESET)) {
printk(KERN_ERR "e100_deisolate_driver:"
" HW reset recover failed\n");
}
}
e100_start_ru(bdp);
/* relaunch watchdog timer in 2 sec */
mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
// we must clear tcbs since we may have lost Tx intrrupt
// or have unsent frames on the tcb chain
e100_tcb_add_C_bit(bdp);
e100_tx_srv(bdp);
e100_set_intr_mask(bdp);
if (netif_running(bdp->device))
netif_wake_queue(bdp->device);
}
bdp->driver_isolated = false;
}
#ifdef E100_ETHTOOL_IOCTL
static int
e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
......@@ -3458,14 +3638,6 @@ e100_get_speed_duplex_caps(struct e100_private *bdp)
}
static void
e100_set_speed_duplex(struct e100_private *bdp)
{
e100_phy_set_speed_duplex(bdp, true);
e100_config_fc(bdp); /* re-config flow-control if necessary */
e100_config(bdp);
}
#ifdef ETHTOOL_GWOL
static unsigned char
e100_setup_filter(struct e100_private *bdp)
......@@ -3510,32 +3682,19 @@ e100_setup_filter(struct e100_private *bdp)
static void
e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp)
{
int enable = 0;
u32 state = 0;
if (bdp->wolopts) {
e100_config_wol(bdp);
e100_config_wol(bdp);
if (!e100_config(bdp)) {
printk("e100_config WOL options failed\n");
goto exit;
}
if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) {
if (!e100_setup_filter(bdp)) {
printk("e100_config WOL options failed\n");
goto exit;
}
state = 1;
pci_set_power_state(pcid, state);
}
enable = 1;
if (e100_config(bdp)) {
if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP))
if (!e100_setup_filter(bdp))
printk(KERN_ERR
"e100_config WOL options failed\n");
} else {
printk(KERN_ERR "e100_config WOL failed\n");
}
exit:
pci_enable_wake(pcid, state, enable);
}
static u16
static u16
e100_get_ip_lbytes(struct net_device *dev)
{
struct in_ifaddr *ifa;
......@@ -3795,3 +3954,84 @@ e100_non_tx_background(unsigned long ptr)
}
spin_unlock_bh(&(bdp->bd_non_tx_lock));
}
#ifdef CONFIG_PM
static int
e100_save_state(struct pci_dev *pcid, u32 state)
{
struct net_device *dev;
struct e100_private *bdp;
/* Actually, PCI PM does NOT call this entry */
if (!(dev = (struct net_device *) pci_get_drvdata(pcid)))
return -1;
bdp = dev->priv;
pci_save_state(pcid, bdp->pci_state);
return 0;
}
static int
e100_suspend(struct pci_dev *pcid, u32 state)
{
struct net_device *netdev = pci_get_drvdata(pcid);
struct e100_private *bdp = netdev->priv;
e100_isolate_driver(bdp);
e100_save_state(pcid, state);
/* If wol is enabled */
#ifdef ETHTOOL_GWOL
if (bdp->wolopts) {
bdp->ip_lbytes = e100_get_ip_lbytes(netdev);
e100_do_wol(pcid, bdp);
pci_enable_wake(pcid, 3, 1); /* Enable PME for power state D3 */
pci_set_power_state(pcid, 3); /* Set power state to D3. */
} else {
/* Disable bus mastering */
pci_disable_device(pcid);
pci_set_power_state(pcid, state);
}
#else
pci_disable_device(pcid);
pci_set_power_state(pcid, state);
#endif
return 0;
}
static int
e100_resume(struct pci_dev *pcid)
{
struct net_device *netdev = pci_get_drvdata(pcid);
struct e100_private *bdp = netdev->priv;
u8 recover = false;
u8 full_init = false;
pci_set_power_state(pcid, 0);
pci_enable_wake(pcid, 0, 0); /* Clear PME status and disable PME */
pci_restore_state(pcid, bdp->pci_state);
if (netif_running(netdev)) {
recover = true;
}
#ifdef ETHTOOL_GWOL
if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) {
full_init = true;
}
#endif
e100_deisolate_driver(bdp, recover, full_init);
return 0;
}
static int
e100_enable_wake(struct pci_dev *pcid, u32 state, int enable)
{
/* Driver doesn't need to do anything because it will enable */
/* wol when suspended. */
/* Actually, PCI PM does NOT call this entry. */
return 0;
}
#endif /* CONFIG_PM */
......@@ -769,7 +769,7 @@ e100_set_fc(struct e100_private *bdp)
* Arguments: bdp - Pointer to the e100_private structure for the board
*
* Returns: true if link state was changed
* B_FLASE otherwise
* false otherwise
*
*/
unsigned char
......
......@@ -64,8 +64,8 @@ static int debug = -1; /* The debug level */
/* A few values that may be tweaked. */
/* The ring sizes should be a power of two for efficiency. */
#define TX_RING_SIZE 32
#define RX_RING_SIZE 32
#define TX_RING_SIZE 64
#define RX_RING_SIZE 64
/* How much slots multicast filter setup may take.
Do not descrease without changing set_rx_mode() implementaion. */
#define TX_MULTICAST_SIZE 2
......@@ -570,6 +570,19 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
if (speedo_debug > 0 && did_version++ == 0)
printk(version);
/* save power state before pci_enable_device overwrites it */
pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (pm) {
u16 pwr_command;
pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
}
if (pci_enable_device(pdev))
goto err_out_free_mmio_region;
pci_set_master(pdev);
if (!request_region(pci_resource_start(pdev, 1),
pci_resource_len(pdev, 1), "eepro100")) {
printk (KERN_ERR "eepro100: cannot reserve I/O ports\n");
......@@ -600,18 +613,6 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
pci_resource_start(pdev, 0), irq);
#endif
/* save power state b4 pci_enable_device overwrites it */
pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (pm) {
u16 pwr_command;
pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
}
if (pci_enable_device(pdev))
goto err_out_free_mmio_region;
pci_set_master(pdev);
if (speedo_found1(pdev, ioaddr, cards_found, acpi_idle_state) == 0)
cards_found++;
......@@ -1074,6 +1075,51 @@ static void speedo_resume(struct net_device *dev)
outw(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd);
}
/*
* Sometimes the receiver stops making progress. This routine knows how to
* get it going again, without losing packets or being otherwise nasty like
* a chip reset would be. Previously the driver had a whole sequence
* of if RxSuspended, if it's no buffers do one thing, if it's no resources,
* do another, etc. But those things don't really matter. Separate logic
* in the ISR provides for allocating buffers--the other half of operation
* is just making sure the receiver is active. speedo_rx_soft_reset does that.
* This problem with the old, more involved algorithm is shown up under
* ping floods on the order of 60K packets/second on a 100Mbps fdx network.
*/
static void
speedo_rx_soft_reset(struct net_device *dev)
{
struct speedo_private *sp = dev->priv;
struct RxFD *rfd;
long ioaddr;
ioaddr = dev->base_addr;
wait_for_cmd_done(ioaddr + SCBCmd);
if (inb(ioaddr + SCBCmd) != 0) {
printk("%s: previous command stalled\n", dev->name);
return;
}
/*
* Put the hardware into a known state.
*/
outb(RxAbort, ioaddr + SCBCmd);
rfd = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
rfd->rx_buf_addr = 0xffffffff;
wait_for_cmd_done(ioaddr + SCBCmd);
if (inb(ioaddr + SCBCmd) != 0) {
printk("%s: RxAbort command stalled\n", dev->name);
return;
}
outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
ioaddr + SCBPointer);
outb(RxStart, ioaddr + SCBCmd);
}
/* Media monitoring and control. */
static void speedo_timer(unsigned long data)
{
......@@ -1377,9 +1423,10 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* workaround for hardware bug on 10 mbit half duplex */
if ((sp->partner == 0) || (sp->chip_id == 1)) {
if ((sp->partner == 0) && (sp->chip_id == 1)) {
wait_for_cmd_done(ioaddr + SCBCmd);
outb(0 , ioaddr + SCBCmd);
udelay(1);
}
/* Trigger the command unit resume. */
......@@ -1507,82 +1554,39 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
if ((status & 0xfc00) == 0)
break;
/* Always check if all rx buffers are allocated. --SAW */
speedo_refill_rx_buffers(dev, 0);
if ((status & 0x5000) || /* Packet received, or Rx error. */
(sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed)
/* Need to gather the postponed packet. */
speedo_rx(dev);
if (status & 0x1000) {
spin_lock(&sp->lock);
if ((status & 0x003c) == 0x0028) { /* No more Rx buffers. */
struct RxFD *rxf;
printk(KERN_WARNING "%s: card reports no RX buffers.\n",
dev->name);
rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
if (rxf == NULL) {
if (speedo_debug > 2)
printk(KERN_DEBUG
"%s: NULL cur_rx in speedo_interrupt().\n",
dev->name);
sp->rx_ring_state |= RrNoMem|RrNoResources;
} else if (rxf == sp->last_rxf) {
if (speedo_debug > 2)
printk(KERN_DEBUG
"%s: cur_rx is last in speedo_interrupt().\n",
dev->name);
sp->rx_ring_state |= RrNoMem|RrNoResources;
} else
outb(RxResumeNoResources, ioaddr + SCBCmd);
} else if ((status & 0x003c) == 0x0008) { /* No resources. */
struct RxFD *rxf;
printk(KERN_WARNING "%s: card reports no resources.\n",
dev->name);
rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
if (rxf == NULL) {
if (speedo_debug > 2)
printk(KERN_DEBUG
"%s: NULL cur_rx in speedo_interrupt().\n",
dev->name);
sp->rx_ring_state |= RrNoMem|RrNoResources;
} else if (rxf == sp->last_rxf) {
if (speedo_debug > 2)
printk(KERN_DEBUG
"%s: cur_rx is last in speedo_interrupt().\n",
dev->name);
sp->rx_ring_state |= RrNoMem|RrNoResources;
} else {
/* Restart the receiver. */
outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
ioaddr + SCBPointer);
outb(RxStart, ioaddr + SCBCmd);
}
}
sp->stats.rx_errors++;
spin_unlock(&sp->lock);
}
if ((sp->rx_ring_state&(RrNoMem|RrNoResources)) == RrNoResources) {
printk(KERN_WARNING
"%s: restart the receiver after a possible hang.\n",
dev->name);
spin_lock(&sp->lock);
/* Restart the receiver.
I'm not sure if it's always right to restart the receiver
here but I don't know another way to prevent receiver hangs.
1999/12/25 SAW */
outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
ioaddr + SCBPointer);
outb(RxStart, ioaddr + SCBCmd);
sp->rx_ring_state &= ~RrNoResources;
spin_unlock(&sp->lock);
/* Always check if all rx buffers are allocated. --SAW */
speedo_refill_rx_buffers(dev, 0);
spin_lock(&sp->lock);
/*
* The chip may have suspended reception for various reasons.
* Check for that, and re-prime it should this be the case.
*/
switch ((status >> 2) & 0xf) {
case 0: /* Idle */
break;
case 1: /* Suspended */
case 2: /* No resources (RxFDs) */
case 9: /* Suspended with no more RBDs */
case 10: /* No resources due to no RBDs */
case 12: /* Ready with no RBDs */
speedo_rx_soft_reset(dev);
break;
case 3: case 5: case 6: case 7: case 8:
case 11: case 13: case 14: case 15:
/* these are all reserved values */
break;
}
/* User interrupt, Command/Tx unit interrupt or CU not active. */
if (status & 0xA400) {
spin_lock(&sp->lock);
speedo_tx_buffer_gc(dev);
if (sp->tx_full
&& (int)(sp->cur_tx - sp->dirty_tx) < TX_QUEUE_UNFULL) {
......@@ -1590,8 +1594,9 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
sp->tx_full = 0;
netif_wake_queue(dev); /* Attention: under a spinlock. --SAW */
}
spin_unlock(&sp->lock);
}
spin_unlock(&sp->lock);
if (--boguscnt < 0) {
printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
......@@ -2202,6 +2207,8 @@ static int eepro100_suspend(struct pci_dev *pdev, u32 state)
if (!netif_running(dev))
return 0;
del_timer_sync(&sp->timer);
netif_device_detach(dev);
outl(PortPartialReset, ioaddr + SCBPort);
......@@ -2234,6 +2241,8 @@ static int eepro100_resume(struct pci_dev *pdev)
sp->rx_mode = -1;
sp->flow_ctrl = sp->partner = 0;
set_rx_mode(dev);
sp->timer.expires = RUN_AT(2*HZ);
add_timer(&sp->timer);
return 0;
}
#endif /* CONFIG_PM */
......
/* $Id: tg3.c,v 1.43.2.74 2002/03/06 22:22:29 davem Exp $
/* $Id: tg3.c,v 1.43.2.79 2002/03/12 07:11:17 davem Exp $
* tg3.c: Broadcom Tigon3 ethernet driver.
*
* Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
......@@ -42,7 +42,11 @@
*/
#define TG3_MINI_RING_WORKS 0
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define TG3_VLAN_TAG_USED 1
#else
#define TG3_VLAN_TAG_USED 0
#endif
#include "tg3.h"
......@@ -78,15 +82,16 @@
* them in the NIC onboard memory.
*/
#define TG3_RX_RING_SIZE 512
#define TG3_RX_RING_PENDING 200
#define TG3_DEF_RX_RING_PENDING 200
#if TG3_MINI_RING_WORKS
#define TG3_RX_MINI_RING_SIZE 256 /* ??? */
#define TG3_RX_MINI_RING_PENDING 100
#define TG3_DEF_RX_MINI_RING_PENDING 100
#endif
#define TG3_RX_JUMBO_RING_SIZE 256
#define TG3_RX_JUMBO_RING_PENDING 100
#define TG3_DEF_RX_JUMBO_RING_PENDING 100
#define TG3_RX_RCB_RING_SIZE 1024
#define TG3_TX_RING_SIZE 512
#define TG3_DEF_TX_RING_PENDING (TG3_TX_RING_SIZE - 1)
#define TG3_RX_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \
TG3_RX_RING_SIZE)
......@@ -100,10 +105,12 @@
TG3_RX_RCB_RING_SIZE)
#define TG3_TX_RING_BYTES (sizeof(struct tg3_tx_buffer_desc) * \
TG3_TX_RING_SIZE)
#define TX_RING_GAP(TP) \
(TG3_TX_RING_SIZE - (TP)->tx_pending)
#define TX_BUFFS_AVAIL(TP) \
(((TP)->tx_cons <= (TP)->tx_prod) ? \
(TP)->tx_cons + (TG3_TX_RING_SIZE - 1) - (TP)->tx_prod : \
(TP)->tx_cons - (TP)->tx_prod - 1)
(TP)->tx_cons + (TP)->tx_pending - (TP)->tx_prod : \
(TP)->tx_cons - (TP)->tx_prod - TX_RING_GAP(TP))
#define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1))
#define RX_PKT_BUF_SZ (1536 + tp->rx_offset + 64)
......@@ -1346,6 +1353,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
aninfo.flags |= (MR_AN_ENABLE);
for (i = 0; i < 6; i++) {
unsigned int tick;
u32 tmp;
tw32(MAC_TX_AUTO_NEG, 0);
......@@ -1358,7 +1366,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
aninfo.state = ANEG_STATE_UNKNOWN;
aninfo.cur_time = 0;
while (aninfo.cur_time < 95000) {
tick = 0;
while (++tick < 95000) {
status = tg3_fiber_aneg_smachine(tp, &aninfo);
if (status == ANEG_DONE ||
status == ANEG_FAILED)
......@@ -1782,7 +1791,7 @@ static void tg3_rx(struct tg3 *tp)
skb = copy_skb;
}
if (!(tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) &&
if ((tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) &&
(desc->type_flags & RXD_FLAG_TCPUDP_CSUM)) {
skb->csum = htons((desc->ip_tcp_csum & RXD_TCPCSUM_MASK)
>> RXD_TCPCSUM_SHIFT);
......@@ -1835,61 +1844,99 @@ static void tg3_rx(struct tg3 *tp)
#endif
}
#define RATE_SAMPLE_INTERVAL (1 * HZ)
#define PKT_RATE_LOW 22000
#define PKT_RATE_HIGH 61000
static void tg3_rate_sample(struct tg3 *tp, unsigned long ticks)
{
u32 delta, rx_now, tx_now;
int new_vals;
int new_vals, do_tx, do_rx;
rx_now = tp->hw_stats->rx_ucast_packets.low;
tx_now = tp->hw_stats->COS_out_packets[0].low;
delta = (rx_now - tp->last_rx_count);
delta += (tx_now - tp->last_tx_count);
delta /= (ticks / RATE_SAMPLE_INTERVAL);
delta /= (ticks / tp->coalesce_config.rate_sample_jiffies);
tp->last_rx_count = rx_now;
tp->last_tx_count = tx_now;
new_vals = 0;
if (delta < PKT_RATE_LOW) {
if (tp->coalesce_config.rx_max_coalesced_frames !=
LOW_RXMAX_FRAMES) {
do_tx = (tp->tg3_flags & TG3_FLAG_ADAPTIVE_TX) != 0;
do_rx = (tp->tg3_flags & TG3_FLAG_ADAPTIVE_RX) != 0;
if (delta < tp->coalesce_config.pkt_rate_low) {
if (do_rx &&
tp->coalesce_config.rx_max_coalesced_frames !=
tp->coalesce_config.rx_max_coalesced_frames_low) {
tp->coalesce_config.rx_max_coalesced_frames =
LOW_RXMAX_FRAMES;
tp->coalesce_config.rx_coalesce_ticks =
LOW_RXCOL_TICKS;
new_vals = 1;
}
} else if (delta < PKT_RATE_HIGH) {
if (tp->coalesce_config.rx_max_coalesced_frames !=
DEFAULT_RXMAX_FRAMES) {
if (do_tx &&
tp->coalesce_config.tx_max_coalesced_frames !=
tp->coalesce_config.tx_max_coalesced_frames_low) {
tp->coalesce_config.tx_max_coalesced_frames =
tp->coalesce_config.tx_max_coalesced_frames_low;
tp->coalesce_config.tx_coalesce_ticks =
tp->coalesce_config.tx_coalesce_ticks_low;
new_vals = 1;
}
} else if (delta < tp->coalesce_config.pkt_rate_high) {
if (do_rx &&
tp->coalesce_config.rx_max_coalesced_frames !=
tp->coalesce_config.rx_max_coalesced_frames_def) {
tp->coalesce_config.rx_max_coalesced_frames =
DEFAULT_RXMAX_FRAMES;
tp->coalesce_config.rx_max_coalesced_frames_def;
tp->coalesce_config.rx_coalesce_ticks =
DEFAULT_RXCOL_TICKS;
tp->coalesce_config.rx_coalesce_ticks_def;
new_vals = 1;
}
if (do_tx &&
tp->coalesce_config.tx_max_coalesced_frames !=
tp->coalesce_config.tx_max_coalesced_frames_def) {
tp->coalesce_config.tx_max_coalesced_frames =
tp->coalesce_config.tx_max_coalesced_frames_def;
tp->coalesce_config.tx_coalesce_ticks =
tp->coalesce_config.tx_coalesce_ticks_def;
new_vals = 1;
}
} else {
if (tp->coalesce_config.rx_max_coalesced_frames !=
HIGH_RXMAX_FRAMES) {
if (do_rx &&
tp->coalesce_config.rx_max_coalesced_frames !=
tp->coalesce_config.rx_max_coalesced_frames_high) {
tp->coalesce_config.rx_max_coalesced_frames =
HIGH_RXMAX_FRAMES;
tp->coalesce_config.rx_max_coalesced_frames_high;
tp->coalesce_config.rx_coalesce_ticks =
HIGH_RXCOL_TICKS;
tp->coalesce_config.rx_coalesce_ticks_high;
new_vals = 1;
}
if (do_tx &&
tp->coalesce_config.tx_max_coalesced_frames !=
tp->coalesce_config.tx_max_coalesced_frames_high) {
tp->coalesce_config.tx_max_coalesced_frames =
tp->coalesce_config.tx_max_coalesced_frames_high;
tp->coalesce_config.tx_coalesce_ticks =
tp->coalesce_config.tx_coalesce_ticks_high;
new_vals = 1;
}
}
if (new_vals) {
tw32(HOSTCC_RXCOL_TICKS,
tp->coalesce_config.rx_coalesce_ticks);
tw32(HOSTCC_RXMAX_FRAMES,
tp->coalesce_config.rx_max_coalesced_frames);
if (do_rx) {
tw32(HOSTCC_RXCOL_TICKS,
tp->coalesce_config.rx_coalesce_ticks);
tw32(HOSTCC_RXMAX_FRAMES,
tp->coalesce_config.rx_max_coalesced_frames);
}
if (do_tx) {
tw32(HOSTCC_TXCOL_TICKS,
tp->coalesce_config.tx_coalesce_ticks);
tw32(HOSTCC_TXMAX_FRAMES,
tp->coalesce_config.tx_max_coalesced_frames);
}
}
tp->last_rate_sample = jiffies;
......@@ -1919,10 +1966,11 @@ static void tg3_interrupt_main_work(struct tg3 *tp)
did_pkts = 1;
}
if (did_pkts) {
if (did_pkts &&
(tp->tg3_flags & (TG3_FLAG_ADAPTIVE_RX | TG3_FLAG_ADAPTIVE_TX))) {
unsigned long ticks = jiffies - tp->last_rate_sample;
if (ticks >= RATE_SAMPLE_INTERVAL)
if (ticks >= tp->coalesce_config.rate_sample_jiffies)
tg3_rate_sample(tp, ticks);
}
}
......@@ -2590,14 +2638,14 @@ static void tg3_init_rings(struct tg3 *tp)
}
/* Now allocate fresh SKBs for each rx ring. */
for (i = 0; i < TG3_RX_RING_PENDING; i++) {
for (i = 0; i < tp->rx_pending; i++) {
if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD,
-1, i) < 0)
break;
}
#if TG3_MINI_RING_WORKS
for (i = 0; i < TG3_RX_MINI_RING_PENDING; i++) {
for (i = 0; i < tp->rx_mini_pending; i++) {
if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_MINI,
-1, i) < 0)
break;
......@@ -2605,7 +2653,7 @@ static void tg3_init_rings(struct tg3 *tp)
#endif
if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
for (i = 0; i < TG3_RX_JUMBO_RING_PENDING; i++) {
for (i = 0; i < tp->rx_jumbo_pending; i++) {
if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO,
-1, i) < 0)
break;
......@@ -3420,11 +3468,11 @@ static int tg3_reset_hw(struct tg3 *tp)
}
/* Setup replenish thresholds. */
tw32(RCVBDI_STD_THRESH, TG3_RX_RING_PENDING / 8);
tw32(RCVBDI_STD_THRESH, tp->rx_pending / 8);
#if TG3_MINI_RING_WORKS
tw32(RCVBDI_MINI_THRESH, TG3_RX_MINI_RING_PENDING / 8);
tw32(RCVBDI_MINI_THRESH, tp->rx_mini_pending / 8);
#endif
tw32(RCVBDI_JUMBO_THRESH, TG3_RX_JUMBO_RING_PENDING / 8);
tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8);
/* Clear out send RCB ring in SRAM. */
for (i = NIC_SRAM_SEND_RCB; i < NIC_SRAM_RCV_RET_RCB; i += TG3_BDINFO_SIZE)
......@@ -3462,17 +3510,17 @@ static int tg3_reset_hw(struct tg3 *tp)
BDINFO_FLAGS_MAXLEN_SHIFT),
0);
tp->rx_std_ptr = TG3_RX_RING_PENDING;
tp->rx_std_ptr = tp->rx_pending;
tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
tp->rx_std_ptr);
#if TG3_MINI_RING_WORKS
tp->rx_mini_ptr = TG3_RX_MINI_RING_PENDING;
tp->rx_mini_ptr = tp->rx_mini_pending;
tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
tp->rx_mini_ptr);
#endif
if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)
tp->rx_jumbo_ptr = TG3_RX_JUMBO_RING_PENDING;
tp->rx_jumbo_ptr = tp->rx_jumbo_pending;
else
tp->rx_jumbo_ptr = 0;
tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW,
......@@ -3608,6 +3656,9 @@ static int tg3_reset_hw(struct tg3 *tp)
udelay(10);
tw32(MAC_RX_MODE, tp->rx_mode);
if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
tw32(MAC_SERDES_CFG, 0x616000);
err = tg3_setup_phy(tp);
if (err)
return err;
......@@ -4050,6 +4101,8 @@ static int tg3_open(struct net_device *dev)
}
#endif
static struct net_device_stats *tg3_get_stats(struct net_device *);
static int tg3_close(struct net_device *dev)
{
struct tg3 *tp = dev->priv;
......@@ -4073,6 +4126,9 @@ static int tg3_close(struct net_device *dev)
free_irq(dev->irq, dev);
memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev),
sizeof(tp->net_stats_prev));
tg3_free_consistent(tp);
return 0;
......@@ -4121,46 +4177,53 @@ static struct net_device_stats *tg3_get_stats(struct net_device *dev)
{
struct tg3 *tp = dev->priv;
struct net_device_stats *stats = &tp->net_stats;
struct net_device_stats *old_stats = &tp->net_stats_prev;
struct tg3_hw_stats *hw_stats = tp->hw_stats;
/* XXX Fix this... this is wrong because
* XXX it means every open/close we lose the stats.
*/
if (!hw_stats)
return stats;
return old_stats;
stats->rx_packets =
stats->rx_packets = old_stats->rx_packets +
get_stat64(&hw_stats->rx_ucast_packets) +
get_stat64(&hw_stats->rx_mcast_packets) +
get_stat64(&hw_stats->rx_bcast_packets);
stats->tx_packets =
stats->tx_packets = old_stats->tx_packets +
get_stat64(&hw_stats->COS_out_packets[0]);
stats->rx_bytes = get_stat64(&hw_stats->rx_octets);
stats->tx_bytes = get_stat64(&hw_stats->tx_octets);
stats->rx_bytes = old_stats->rx_bytes +
get_stat64(&hw_stats->rx_octets);
stats->tx_bytes = old_stats->tx_bytes +
get_stat64(&hw_stats->tx_octets);
stats->rx_errors = get_stat64(&hw_stats->rx_errors);
stats->tx_errors =
stats->rx_errors = old_stats->rx_errors +
get_stat64(&hw_stats->rx_errors);
stats->tx_errors = old_stats->tx_errors +
get_stat64(&hw_stats->tx_errors) +
get_stat64(&hw_stats->tx_mac_errors) +
get_stat64(&hw_stats->tx_carrier_sense_errors) +
get_stat64(&hw_stats->tx_discards);
stats->multicast = get_stat64(&hw_stats->rx_mcast_packets);
stats->collisions = get_stat64(&hw_stats->tx_collisions);
stats->multicast = old_stats->multicast +
get_stat64(&hw_stats->rx_mcast_packets);
stats->collisions = old_stats->collisions +
get_stat64(&hw_stats->tx_collisions);
stats->rx_length_errors =
stats->rx_length_errors = old_stats->rx_length_errors +
get_stat64(&hw_stats->rx_frame_too_long_errors) +
get_stat64(&hw_stats->rx_undersize_packets);
stats->rx_over_errors = get_stat64(&hw_stats->rxbds_empty);
stats->rx_frame_errors = get_stat64(&hw_stats->rx_align_errors);
stats->tx_aborted_errors = get_stat64(&hw_stats->tx_discards);
stats->tx_carrier_errors =
stats->rx_over_errors = old_stats->rx_over_errors +
get_stat64(&hw_stats->rxbds_empty);
stats->rx_frame_errors = old_stats->rx_frame_errors +
get_stat64(&hw_stats->rx_align_errors);
stats->tx_aborted_errors = old_stats->tx_aborted_errors +
get_stat64(&hw_stats->tx_discards);
stats->tx_carrier_errors = old_stats->tx_carrier_errors +
get_stat64(&hw_stats->tx_carrier_sense_errors);
stats->rx_crc_errors = calc_crc_errors(tp);
stats->rx_crc_errors = old_stats->rx_crc_errors +
calc_crc_errors(tp);
return stats;
}
......@@ -4255,16 +4318,18 @@ static void tg3_set_rx_mode(struct net_device *dev)
spin_unlock_irq(&tp->lock);
}
#define TG3_REGDUMP_LEN (32 * 1024)
static u8 *tg3_get_regs(struct tg3 *tp)
{
u8 *orig_p = kmalloc((32 * 1024), GFP_KERNEL);
u8 *orig_p = kmalloc(TG3_REGDUMP_LEN, GFP_KERNEL);
u8 *p;
int i;
if (orig_p == NULL)
return NULL;
memset(orig_p, 0, (32 * 1024));
memset(orig_p, 0, TG3_REGDUMP_LEN);
spin_lock_irq(&tp->lock);
......@@ -4320,6 +4385,177 @@ do { p = orig_p + (reg); \
return orig_p;
}
static void tg3_to_ethtool_coal(struct tg3 *tp,
struct ethtool_coalesce *ecoal)
{
ecoal->rx_coalesce_usecs =
tp->coalesce_config.rx_coalesce_ticks_def;
ecoal->rx_max_coalesced_frames =
tp->coalesce_config.rx_max_coalesced_frames_def;
ecoal->rx_coalesce_usecs_irq =
tp->coalesce_config.rx_coalesce_ticks_during_int_def;
ecoal->rx_max_coalesced_frames_irq =
tp->coalesce_config.rx_max_coalesced_frames_during_int_def;
ecoal->tx_coalesce_usecs =
tp->coalesce_config.tx_coalesce_ticks_def;
ecoal->tx_max_coalesced_frames =
tp->coalesce_config.tx_max_coalesced_frames_def;
ecoal->tx_coalesce_usecs_irq =
tp->coalesce_config.tx_coalesce_ticks_during_int_def;
ecoal->tx_max_coalesced_frames_irq =
tp->coalesce_config.tx_max_coalesced_frames_during_int_def;
ecoal->stats_block_coalesce_usecs =
tp->coalesce_config.stats_coalesce_ticks_def;
ecoal->use_adaptive_rx_coalesce =
(tp->tg3_flags & TG3_FLAG_ADAPTIVE_RX) != 0;
ecoal->use_adaptive_tx_coalesce =
(tp->tg3_flags & TG3_FLAG_ADAPTIVE_TX) != 0;
ecoal->pkt_rate_low =
tp->coalesce_config.pkt_rate_low;
ecoal->rx_coalesce_usecs_low =
tp->coalesce_config.rx_coalesce_ticks_low;
ecoal->rx_max_coalesced_frames_low =
tp->coalesce_config.rx_max_coalesced_frames_low;
ecoal->tx_coalesce_usecs_low =
tp->coalesce_config.tx_coalesce_ticks_low;
ecoal->tx_max_coalesced_frames_low =
tp->coalesce_config.tx_max_coalesced_frames_low;
ecoal->pkt_rate_high =
tp->coalesce_config.pkt_rate_high;
ecoal->rx_coalesce_usecs_high =
tp->coalesce_config.rx_coalesce_ticks_high;
ecoal->rx_max_coalesced_frames_high =
tp->coalesce_config.rx_max_coalesced_frames_high;
ecoal->tx_coalesce_usecs_high =
tp->coalesce_config.tx_coalesce_ticks_high;
ecoal->tx_max_coalesced_frames_high =
tp->coalesce_config.tx_max_coalesced_frames_high;
ecoal->rate_sample_interval =
tp->coalesce_config.rate_sample_jiffies / HZ;
}
static int tg3_from_ethtool_coal(struct tg3 *tp,
struct ethtool_coalesce *ecoal)
{
/* Make sure we are not getting garbage. */
if ((ecoal->rx_coalesce_usecs == 0 &&
ecoal->rx_max_coalesced_frames == 0) ||
(ecoal->tx_coalesce_usecs == 0 &&
ecoal->tx_max_coalesced_frames == 0) ||
ecoal->stats_block_coalesce_usecs == 0)
return -EINVAL;
if (ecoal->use_adaptive_rx_coalesce ||
ecoal->use_adaptive_tx_coalesce) {
if (ecoal->pkt_rate_low > ecoal->pkt_rate_high)
return -EINVAL;
if (ecoal->rate_sample_interval == 0)
return -EINVAL;
if (ecoal->use_adaptive_rx_coalesce &&
((ecoal->rx_coalesce_usecs_low == 0 &&
ecoal->rx_max_coalesced_frames_low == 0) ||
(ecoal->rx_coalesce_usecs_high == 0 &&
ecoal->rx_max_coalesced_frames_high == 0)))
return -EINVAL;
if (ecoal->use_adaptive_tx_coalesce &&
((ecoal->tx_coalesce_usecs_low == 0 &&
ecoal->tx_max_coalesced_frames_low == 0) ||
(ecoal->tx_coalesce_usecs_high == 0 &&
ecoal->tx_max_coalesced_frames_high == 0)))
return -EINVAL;
}
/* Looks good, let it rip. */
spin_lock_irq(&tp->lock);
tp->coalesce_config.rx_coalesce_ticks =
tp->coalesce_config.rx_coalesce_ticks_def =
ecoal->rx_coalesce_usecs;
tp->coalesce_config.rx_max_coalesced_frames =
tp->coalesce_config.rx_max_coalesced_frames_def =
ecoal->rx_max_coalesced_frames;
tp->coalesce_config.rx_coalesce_ticks_during_int =
tp->coalesce_config.rx_coalesce_ticks_during_int_def =
ecoal->rx_coalesce_usecs_irq;
tp->coalesce_config.rx_max_coalesced_frames_during_int =
tp->coalesce_config.rx_max_coalesced_frames_during_int_def =
ecoal->rx_max_coalesced_frames_irq;
tp->coalesce_config.tx_coalesce_ticks =
tp->coalesce_config.tx_coalesce_ticks_def =
ecoal->tx_coalesce_usecs;
tp->coalesce_config.tx_max_coalesced_frames =
tp->coalesce_config.tx_max_coalesced_frames_def =
ecoal->tx_max_coalesced_frames;
tp->coalesce_config.tx_coalesce_ticks_during_int =
tp->coalesce_config.tx_coalesce_ticks_during_int_def =
ecoal->tx_coalesce_usecs_irq;
tp->coalesce_config.tx_max_coalesced_frames_during_int =
tp->coalesce_config.tx_max_coalesced_frames_during_int_def =
ecoal->tx_max_coalesced_frames_irq;
tp->coalesce_config.stats_coalesce_ticks =
tp->coalesce_config.stats_coalesce_ticks_def =
ecoal->stats_block_coalesce_usecs;
if (ecoal->use_adaptive_rx_coalesce)
tp->tg3_flags |= TG3_FLAG_ADAPTIVE_RX;
else
tp->tg3_flags &= ~TG3_FLAG_ADAPTIVE_RX;
if (ecoal->use_adaptive_tx_coalesce)
tp->tg3_flags |= TG3_FLAG_ADAPTIVE_TX;
else
tp->tg3_flags &= ~TG3_FLAG_ADAPTIVE_TX;
tp->coalesce_config.pkt_rate_low = ecoal->pkt_rate_low;
tp->coalesce_config.pkt_rate_high = ecoal->pkt_rate_high;
tp->coalesce_config.rate_sample_jiffies =
ecoal->rate_sample_interval * HZ;
tp->coalesce_config.rx_coalesce_ticks_low =
ecoal->rx_coalesce_usecs_low;
tp->coalesce_config.rx_max_coalesced_frames_low =
ecoal->rx_max_coalesced_frames_low;
tp->coalesce_config.tx_coalesce_ticks_low =
ecoal->tx_coalesce_usecs_low;
tp->coalesce_config.tx_max_coalesced_frames_low =
ecoal->tx_max_coalesced_frames_low;
tp->coalesce_config.rx_coalesce_ticks_high =
ecoal->rx_coalesce_usecs_high;
tp->coalesce_config.rx_max_coalesced_frames_high =
ecoal->rx_max_coalesced_frames_high;
tp->coalesce_config.tx_coalesce_ticks_high =
ecoal->tx_coalesce_usecs_high;
tp->coalesce_config.tx_max_coalesced_frames_high =
ecoal->tx_max_coalesced_frames_high;
tw32(HOSTCC_RXCOL_TICKS,
tp->coalesce_config.rx_coalesce_ticks_def);
tw32(HOSTCC_RXMAX_FRAMES,
tp->coalesce_config.rx_max_coalesced_frames_def);
tw32(HOSTCC_RXCOAL_TICK_INT,
tp->coalesce_config.rx_coalesce_ticks_during_int_def);
tw32(HOSTCC_RXCOAL_MAXF_INT,
tp->coalesce_config.rx_max_coalesced_frames_during_int_def);
tw32(HOSTCC_TXCOL_TICKS,
tp->coalesce_config.tx_coalesce_ticks_def);
tw32(HOSTCC_TXMAX_FRAMES,
tp->coalesce_config.tx_max_coalesced_frames_def);
tw32(HOSTCC_TXCOAL_TICK_INT,
tp->coalesce_config.tx_coalesce_ticks_during_int_def);
tw32(HOSTCC_TXCOAL_MAXF_INT,
tp->coalesce_config.tx_max_coalesced_frames_during_int_def);
tw32(HOSTCC_STAT_COAL_TICKS,
tp->coalesce_config.stats_coalesce_ticks_def);
spin_unlock_irq(&tp->lock);
return 0;
}
static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
{
struct tg3 *tp = dev->priv;
......@@ -4334,7 +4570,10 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strcpy (info.driver, DRV_MODULE_NAME);
strcpy (info.version, DRV_MODULE_VERSION);
memset(&info.fw_version, 0, sizeof(info.fw_version));
strcpy (info.bus_info, pci_dev->slot_name);
info.eedump_len = 0;
info.regdump_len = TG3_REGDUMP_LEN;
if (copy_to_user (useraddr, &info, sizeof (info)))
return -EFAULT;
return 0;
......@@ -4368,8 +4607,8 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
cmd.phy_address = PHY_ADDR;
cmd.transceiver = 0;
cmd.autoneg = tp->link_config.autoneg;
cmd.maxtxpkt = tp->coalesce_config.tx_max_coalesced_frames;
cmd.maxrxpkt = tp->coalesce_config.rx_max_coalesced_frames;
cmd.maxtxpkt = tp->coalesce_config.tx_max_coalesced_frames_def;
cmd.maxrxpkt = tp->coalesce_config.rx_max_coalesced_frames_def;
if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
return -EFAULT;
return 0;
......@@ -4422,9 +4661,11 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
}
if (cmd.maxtxpkt || cmd.maxrxpkt) {
tp->coalesce_config.tx_max_coalesced_frames =
tp->coalesce_config.tx_max_coalesced_frames_def =
tp->coalesce_config.tx_max_coalesced_frames =
cmd.maxtxpkt;
tp->coalesce_config.rx_max_coalesced_frames =
tp->coalesce_config.rx_max_coalesced_frames_def =
tp->coalesce_config.rx_max_coalesced_frames =
cmd.maxrxpkt;
/* Coalescing config bits can be updated without
......@@ -4448,8 +4689,8 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
if (copy_from_user(&regs, useraddr, sizeof(regs)))
return -EFAULT;
if (regs.len > (32 * 1024))
regs.len = (32 * 1024);
if (regs.len > TG3_REGDUMP_LEN)
regs.len = TG3_REGDUMP_LEN;
regs.version = 0;
if (copy_to_user(useraddr, &regs, sizeof(regs)))
return -EFAULT;
......@@ -4530,6 +4771,196 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
}
case ETHTOOL_GCOALESCE: {
struct ethtool_coalesce ecoal = { ETHTOOL_GCOALESCE };
tg3_to_ethtool_coal(tp, &ecoal);
if (copy_to_user(useraddr, &ecoal, sizeof(ecoal)))
return -EFAULT;
return 0;
}
case ETHTOOL_SCOALESCE: {
struct ethtool_coalesce ecoal;
if (copy_from_user(&ecoal, useraddr, sizeof(ecoal)))
return -EINVAL;
return tg3_from_ethtool_coal(tp, &ecoal);
}
case ETHTOOL_GRINGPARAM: {
struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
ering.rx_max_pending = TG3_RX_RING_SIZE - 1;
#if TG3_MINI_RING_WORKS
ering.rx_mini_max_pending = TG3_RX_MINI_RING_SIZE - 1;
#else
ering.rx_mini_max_pending = 0;
#endif
ering.rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1;
ering.rx_pending = tp->rx_pending;
#if TG3_MINI_RING_WORKS
ering.rx_mini_pending = tp->rx_mini_pending;
#else
ering.rx_mini_pending = 0;
#endif
ering.rx_jumbo_pending = tp->rx_jumbo_pending;
ering.tx_pending = tp->tx_pending;
if (copy_to_user(useraddr, &ering, sizeof(ering)))
return -EFAULT;
return 0;
}
case ETHTOOL_SRINGPARAM: {
struct ethtool_ringparam ering;
if (copy_from_user(&ering, useraddr, sizeof(ering)))
return -EFAULT;
if ((ering.rx_pending > TG3_RX_RING_SIZE - 1) ||
#if TG3_MINI_RING_WORKS
(ering.rx_mini_pending > TG3_RX_MINI_RING_SIZE - 1) ||
#endif
(ering.rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
(ering.tx_pending > TG3_TX_RING_SIZE - 1))
return -EINVAL;
spin_lock_irq(&tp->lock);
tp->rx_pending = ering.rx_pending;
#if TG3_MINI_RING_WORKS
tp->rx_mini_pending = ering.rx_mini_pending;
#endif
tp->rx_jumbo_pending = ering.rx_jumbo_pending;
tp->tx_pending = ering.tx_pending;
tg3_halt(tp);
tg3_init_rings(tp);
tg3_init_hw(tp);
netif_wake_queue(tp->dev);
spin_unlock_irq(&tp->lock);
return 0;
}
case ETHTOOL_GPAUSEPARAM: {
struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM };
epause.autoneg =
(tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
epause.rx_pause =
(tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0;
epause.tx_pause =
(tp->tg3_flags & TG3_FLAG_PAUSE_TX) != 0;
if (copy_to_user(useraddr, &epause, sizeof(epause)))
return -EFAULT;
return 0;
}
case ETHTOOL_SPAUSEPARAM: {
struct ethtool_pauseparam epause;
if (copy_from_user(&epause, useraddr, sizeof(epause)))
return -EFAULT;
spin_lock_irq(&tp->lock);
if (epause.autoneg)
tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
else
tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
if (epause.rx_pause)
tp->tg3_flags |= TG3_FLAG_PAUSE_RX;
else
tp->tg3_flags &= ~TG3_FLAG_PAUSE_RX;
if (epause.tx_pause)
tp->tg3_flags |= TG3_FLAG_PAUSE_TX;
else
tp->tg3_flags &= ~TG3_FLAG_PAUSE_TX;
tg3_halt(tp);
tg3_init_rings(tp);
tg3_init_hw(tp);
spin_unlock_irq(&tp->lock);
return 0;
}
case ETHTOOL_GRXCSUM: {
struct ethtool_value edata = { ETHTOOL_GRXCSUM };
edata.data =
(tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
case ETHTOOL_SRXCSUM: {
struct ethtool_value edata;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
if (edata.data != 0)
return -EINVAL;
return 0;
}
spin_lock_irq(&tp->lock);
if (edata.data)
tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
else
tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
spin_unlock_irq(&tp->lock);
return 0;
}
case ETHTOOL_GTXCSUM: {
struct ethtool_value edata = { ETHTOOL_GTXCSUM };
edata.data =
(tp->dev->features & NETIF_F_IP_CSUM) != 0;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
case ETHTOOL_STXCSUM: {
struct ethtool_value edata;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
if (edata.data != 0)
return -EINVAL;
return 0;
}
if (edata.data)
tp->dev->features |= NETIF_F_IP_CSUM;
else
tp->dev->features &= ~NETIF_F_IP_CSUM;
return 0;
}
case ETHTOOL_GSG: {
struct ethtool_value edata = { ETHTOOL_GSG };
edata.data =
(tp->dev->features & NETIF_F_SG) != 0;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
case ETHTOOL_SSG: {
struct ethtool_value edata;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
if (edata.data)
tp->dev->features |= NETIF_F_SG;
else
tp->dev->features &= ~NETIF_F_SG;
return 0;
}
};
return -EOPNOTSUPP;
......@@ -5126,10 +5557,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* If not using tagged status, set the *_during_int
* coalesce default config values to zero.
*/
tp->coalesce_config.rx_coalesce_ticks_during_int = 0;
tp->coalesce_config.rx_max_coalesced_frames_during_int = 0;
tp->coalesce_config.tx_coalesce_ticks_during_int = 0;
tp->coalesce_config.tx_max_coalesced_frames_during_int = 0;
tp->coalesce_config.rx_coalesce_ticks_during_int_def = 0;
tp->coalesce_config.rx_max_coalesced_frames_during_int_def = 0;
tp->coalesce_config.tx_coalesce_ticks_during_int_def = 0;
tp->coalesce_config.tx_max_coalesced_frames_during_int_def = 0;
}
if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
......@@ -5566,20 +5997,57 @@ static void __devinit tg3_init_link_config(struct tg3 *tp)
static void __devinit tg3_init_coalesce_config(struct tg3 *tp)
{
tp->coalesce_config.rx_coalesce_ticks = DEFAULT_RXCOL_TICKS;
tp->coalesce_config.rx_max_coalesced_frames = DEFAULT_RXMAX_FRAMES;
tp->coalesce_config.rx_coalesce_ticks_during_int =
tp->coalesce_config.rx_coalesce_ticks_def = DEFAULT_RXCOL_TICKS;
tp->coalesce_config.rx_max_coalesced_frames_def = DEFAULT_RXMAX_FRAMES;
tp->coalesce_config.rx_coalesce_ticks_during_int_def =
DEFAULT_RXCOAL_TICK_INT;
tp->coalesce_config.rx_max_coalesced_frames_during_int =
tp->coalesce_config.rx_max_coalesced_frames_during_int_def =
DEFAULT_RXCOAL_MAXF_INT;
tp->coalesce_config.tx_coalesce_ticks = DEFAULT_TXCOL_TICKS;
tp->coalesce_config.tx_max_coalesced_frames = DEFAULT_TXMAX_FRAMES;
tp->coalesce_config.tx_coalesce_ticks_during_int =
tp->coalesce_config.tx_coalesce_ticks_def = DEFAULT_TXCOL_TICKS;
tp->coalesce_config.tx_max_coalesced_frames_def = DEFAULT_TXMAX_FRAMES;
tp->coalesce_config.tx_coalesce_ticks_during_int_def =
DEFAULT_TXCOAL_TICK_INT;
tp->coalesce_config.tx_max_coalesced_frames_during_int =
tp->coalesce_config.tx_max_coalesced_frames_during_int_def =
DEFAULT_TXCOAL_MAXF_INT;
tp->coalesce_config.stats_coalesce_ticks =
tp->coalesce_config.stats_coalesce_ticks_def =
DEFAULT_STAT_COAL_TICKS;
tp->coalesce_config.rx_coalesce_ticks_low =
LOW_RXCOL_TICKS;
tp->coalesce_config.rx_max_coalesced_frames_low =
LOW_RXMAX_FRAMES;
tp->coalesce_config.tx_coalesce_ticks_low =
LOW_TXCOL_TICKS;
tp->coalesce_config.tx_max_coalesced_frames_low =
LOW_TXMAX_FRAMES;
tp->coalesce_config.rx_coalesce_ticks_high =
HIGH_RXCOL_TICKS;
tp->coalesce_config.rx_max_coalesced_frames_high =
HIGH_RXMAX_FRAMES;
tp->coalesce_config.tx_coalesce_ticks_high =
HIGH_TXCOL_TICKS;
tp->coalesce_config.tx_max_coalesced_frames_high =
HIGH_TXMAX_FRAMES;
/* Active == default */
tp->coalesce_config.rx_coalesce_ticks =
tp->coalesce_config.rx_coalesce_ticks_def;
tp->coalesce_config.rx_max_coalesced_frames =
tp->coalesce_config.rx_max_coalesced_frames_def;
tp->coalesce_config.tx_coalesce_ticks =
tp->coalesce_config.tx_coalesce_ticks_def;
tp->coalesce_config.tx_max_coalesced_frames =
tp->coalesce_config.tx_max_coalesced_frames_def;
tp->coalesce_config.stats_coalesce_ticks =
tp->coalesce_config.stats_coalesce_ticks_def;
tp->coalesce_config.rate_sample_jiffies = (1 * HZ);
tp->coalesce_config.pkt_rate_low = 22000;
tp->coalesce_config.pkt_rate_high = 61000;
tp->tg3_flags |= TG3_FLAG_ADAPTIVE_RX;
tp->tg3_flags &= ~(TG3_FLAG_ADAPTIVE_TX);
}
static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
......@@ -5743,6 +6211,13 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tg3_init_bufmgr_config(tp);
tp->rx_pending = TG3_DEF_RX_RING_PENDING;
#if TG3_MINI_RING_WORKS
tp->rx_mini_pending = TG3_DEF_RX_MINI_RING_PENDING;
#endif
tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
tp->tx_pending = TG3_DEF_TX_RING_PENDING;
dev->open = tg3_open;
dev->stop = tg3_close;
dev->get_stats = tg3_get_stats;
......@@ -5777,8 +6252,11 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
/* Tigon3 can do ipv4 only... and some chips have buggy
* checksumming.
*/
if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0)
if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) {
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
} else
tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
err = register_netdev(dev);
if (err) {
......
/* $Id: tg3.h,v 1.37.2.30 2002/03/05 10:08:39 davem Exp $
/* $Id: tg3.h,v 1.37.2.32 2002/03/11 12:18:18 davem Exp $
* tg3.h: Definitions for Broadcom Tigon3 ethernet driver.
*
* Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
......@@ -713,13 +713,17 @@
#define DEFAULT_RXCOL_TICKS 0x00000048
#define HIGH_RXCOL_TICKS 0x00000096
#define HOSTCC_TXCOL_TICKS 0x00003c0c
#define LOW_TXCOL_TICKS 0x00000096
#define DEFAULT_TXCOL_TICKS 0x0000012c
#define HIGH_TXCOL_TICKS 0x00000145
#define HOSTCC_RXMAX_FRAMES 0x00003c10
#define LOW_RXMAX_FRAMES 0x00000005
#define DEFAULT_RXMAX_FRAMES 0x00000008
#define HIGH_RXMAX_FRAMES 0x00000012
#define HOSTCC_TXMAX_FRAMES 0x00003c14
#define LOW_TXMAX_FRAMES 0x00000035
#define DEFAULT_TXMAX_FRAMES 0x0000004b
#define HIGH_TXMAX_FRAMES 0x00000052
#define HOSTCC_RXCOAL_TICK_INT 0x00003c18
#define DEFAULT_RXCOAL_TICK_INT 0x00000019
#define HOSTCC_TXCOAL_TICK_INT 0x00003c1c
......@@ -1681,17 +1685,42 @@ struct tg3_link_config {
};
struct tg3_coalesce_config {
/* Current settings. */
u32 rx_coalesce_ticks;
u32 rx_max_coalesced_frames;
u32 rx_coalesce_ticks_during_int;
u32 rx_max_coalesced_frames_during_int;
u32 tx_coalesce_ticks;
u32 tx_max_coalesced_frames;
u32 tx_coalesce_ticks_during_int;
u32 tx_max_coalesced_frames_during_int;
u32 stats_coalesce_ticks;
/* Default settings. */
u32 rx_coalesce_ticks_def;
u32 rx_max_coalesced_frames_def;
u32 rx_coalesce_ticks_during_int_def;
u32 rx_max_coalesced_frames_during_int_def;
u32 tx_coalesce_ticks_def;
u32 tx_max_coalesced_frames_def;
u32 tx_coalesce_ticks_during_int_def;
u32 tx_max_coalesced_frames_during_int_def;
u32 stats_coalesce_ticks_def;
/* Adaptive RX/TX coalescing parameters. */
u32 rate_sample_jiffies;
u32 pkt_rate_low;
u32 pkt_rate_high;
u32 rx_coalesce_ticks_low;
u32 rx_max_coalesced_frames_low;
u32 tx_coalesce_ticks_low;
u32 tx_max_coalesced_frames_low;
u32 rx_coalesce_ticks_high;
u32 rx_max_coalesced_frames_high;
u32 tx_coalesce_ticks_high;
u32 tx_max_coalesced_frames_high;
};
struct tg3_bufmgr_config {
......@@ -1720,6 +1749,7 @@ struct tg3 {
spinlock_t indirect_lock;
struct net_device_stats net_stats;
struct net_device_stats net_stats_prev;
unsigned long phy_crc_errors;
/* Adaptive coalescing engine. */
......@@ -1731,9 +1761,11 @@ struct tg3 {
u32 tg3_flags;
#define TG3_FLAG_HOST_TXDS 0x00000001
#define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002
#define TG3_FLAG_BROKEN_CHECKSUMS 0x00000004
#define TG3_FLAG_RX_CHECKSUMS 0x00000004
#define TG3_FLAG_USE_LINKCHG_REG 0x00000008
#define TG3_FLAG_USE_MI_INTERRUPT 0x00000010
#define TG3_FLAG_ADAPTIVE_RX 0x00000020
#define TG3_FLAG_ADAPTIVE_TX 0x00000040
#define TG3_FLAG_PHY_RESET_ON_INIT 0x00000100
#define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200
#define TG3_FLAG_TAGGED_IRQ_STATUS 0x00000400
......@@ -1751,6 +1783,10 @@ struct tg3 {
#define TG3_FLAG_AUTONEG_DISABLE 0x00400000
#define TG3_FLAG_JUMBO_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000
#define TG3_FLAG_PAUSE_AUTONEG 0x02000000
#define TG3_FLAG_PAUSE_RX 0x04000000
#define TG3_FLAG_PAUSE_TX 0x08000000
#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
#define TG3_FLAG_INIT_COMPLETE 0x80000000
u32 msg_enable;
......@@ -1764,6 +1800,13 @@ struct tg3 {
struct tg3_coalesce_config coalesce_config;
struct tg3_bufmgr_config bufmgr_config;
u32 rx_pending;
#if TG3_MINI_RING_WORKS
u32 rx_mini_pending;
#endif
u32 rx_jumbo_pending;
u32 tx_pending;
/* cache h/w values, often passed straight to h/w */
u32 rx_mode;
u32 tx_mode;
......
......@@ -72,6 +72,144 @@ struct ethtool_eeprom {
u32 len; /* in bytes */
u8 data[0];
};
/* for configuring coalescing parameters of chip */
struct ethtool_coalesce {
u32 cmd; /* ETHTOOL_{G,S}COALESCE */
/* How many usecs to delay an RX interrupt after
* a packet arrives. If 0, only rx_max_coalesced_frames
* is used.
*/
u32 rx_coalesce_usecs;
/* How many packets to delay an RX interrupt after
* a packet arrives. If 0, only rx_coalesce_usecs is
* used. It is illegal to set both usecs and max frames
* to zero as this would cause RX interrupts to never be
* generated.
*/
u32 rx_max_coalesced_frames;
/* Same as above two parameters, except that these values
* apply while an IRQ is being services by the host. Not
* all cards support this feature and the values are ignored
* in that case.
*/
u32 rx_coalesce_usecs_irq;
u32 rx_max_coalesced_frames_irq;
/* How many usecs to delay a TX interrupt after
* a packet is sent. If 0, only tx_max_coalesced_frames
* is used.
*/
u32 tx_coalesce_usecs;
/* How many packets to delay a TX interrupt after
* a packet is sent. If 0, only tx_coalesce_usecs is
* used. It is illegal to set both usecs and max frames
* to zero as this would cause TX interrupts to never be
* generated.
*/
u32 tx_max_coalesced_frames;
/* Same as above two parameters, except that these values
* apply while an IRQ is being services by the host. Not
* all cards support this feature and the values are ignored
* in that case.
*/
u32 tx_coalesce_usecs_irq;
u32 tx_max_coalesced_frames_irq;
/* How many usecs to delay in-memory statistics
* block updates. Some drivers do not have an in-memory
* statistic block, and in such cases this value is ignored.
* This value must not be zero.
*/
u32 stats_block_coalesce_usecs;
/* Adaptive RX/TX coalescing is an algorithm implemented by
* some drivers to improve latency under low packet rates and
* improve throughput under high packet rates. Some drivers
* only implement one of RX or TX adaptive coalescing. Anything
* not implemented by the driver causes these values to be
* silently ignored.
*/
u32 use_adaptive_rx_coalesce;
u32 use_adaptive_tx_coalesce;
/* When the packet rate (measured in packets per second)
* is below pkt_rate_low, the {rx,tx}_*_low parameters are
* used.
*/
u32 pkt_rate_low;
u32 rx_coalesce_usecs_low;
u32 rx_max_coalesced_frames_low;
u32 tx_coalesce_usecs_low;
u32 tx_max_coalesced_frames_low;
/* When the packet rate is below pkt_rate_high but above
* pkt_rate_low (both measured in packets per second) the
* normal {rx,tx}_* coalescing parameters are used.
*/
/* When the packet rate is (measured in packets per second)
* is above pkt_rate_high, the {rx,tx}_*_high parameters are
* used.
*/
u32 pkt_rate_high;
u32 rx_coalesce_usecs_high;
u32 rx_max_coalesced_frames_high;
u32 tx_coalesce_usecs_high;
u32 tx_max_coalesced_frames_high;
/* How often to do adaptive coalescing packet rate sampling,
* measured in seconds. Must not be zero.
*/
u32 rate_sample_interval;
};
/* for configuring RX/TX ring parameters */
struct ethtool_ringparam {
u32 cmd; /* ETHTOOL_{G,S}RINGPARAM */
/* Read only attributes. These indicate the maximum number
* of pending RX/TX ring entries the driver will allow the
* user to set.
*/
u32 rx_max_pending;
u32 rx_mini_max_pending;
u32 rx_jumbo_max_pending;
u32 tx_max_pending;
/* Values changeable by the user. The valid values are
* in the range 1 to the "*_max_pending" counterpart above.
*/
u32 rx_pending;
u32 rx_mini_pending;
u32 rx_jumbo_pending;
u32 tx_pending;
};
/* for configuring link flow control parameters */
struct ethtool_pauseparam {
u32 cmd; /* ETHTOOL_{G,S}PAUSEPARAM */
/* If the link is being auto-negotiated (via ethtool_cmd.autoneg
* being true) the user may set 'autonet' here non-zero to have the
* pause parameters be auto-negotiated too. In such a case, the
* {rx,tx}_pause values below determine what capabilities are
* advertised.
*
* If 'autoneg' is zero or the link is not being auto-negotiated,
* then {rx,tx}_pause force the driver to use/not-use pause
* flow control.
*/
u32 autoneg;
u32 rx_pause;
u32 tx_pause;
};
/* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001 /* Get settings. */
#define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */
......@@ -82,9 +220,23 @@ struct ethtool_eeprom {
#define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */
#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level, priv. */
#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv. */
#define ETHTOOL_GLINK 0x0000000a /* Get link status */
#define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */
#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */
#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data */
#define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */
#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config */
#define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */
#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters */
#define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */
#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters */
#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */
#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */
#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */
#define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */
#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable
* (ethtool_value) */
#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable
* (ethtool_value) */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment