patch-2.4.21 linux-2.4.21/drivers/net/e100/e100_main.c
Next file: linux-2.4.21/drivers/net/e100/e100_phy.c
Previous file: linux-2.4.21/drivers/net/e100/e100_eeprom.c
Back to the patch index
Back to the overall index
- Lines: 1834
- Date:
2003-06-13 07:51:34.000000000 -0700
- Orig file:
linux-2.4.20/drivers/net/e100/e100_main.c
- Orig date:
2002-11-28 15:53:13.000000000 -0800
diff -urN linux-2.4.20/drivers/net/e100/e100_main.c linux-2.4.21/drivers/net/e100/e100_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2003 Intel 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
@@ -45,32 +45,37 @@
**********************************************************************/
/* Change Log
+ *
+ * 2.2.21 02/11/03
+ * o Removed marketing brand strings. Instead, Using generic string
+ * "Intel(R) PRO/100 Network Connection" for all adapters.
+ * o Implemented ethtool -S option
+ * o Strip /proc/net/PRO_LAN_Adapters files for kernel driver
+ * o Bug fix: Read wrong byte in EEPROM when offset is odd number
+ * o Bug fix: PHY loopback test fails on ICH devices
+ * o Bug fix: System panic on e100_close when repeating Hot Remove and
+ * Add in a team
+ * o Bug fix: Linux Bonding driver claims adapter's link loss because of
+ * not updating last_rx field
+ * o Bug fix: e100 does not check validity of MAC address
+ * o New feature: added ICH5 support
+ *
+ * 2.1.27 11/20/02
+ * o Bug fix: Device command timeout due to SMBus processing during init
+ * o Bug fix: Not setting/clearing I (Interrupt) bit in tcb correctly
+ * o Bug fix: Not using EEPROM WoL setting as default in ethtool
+ * o Bug fix: Not able to set autoneg on using ethtool when interface down
+ * o Bug fix: Not able to change speed/duplex using ethtool/mii
+ * when interface up
+ * o Bug fix: Ethtool shows autoneg on when forced to 100/Full
+ * o Bug fix: Compiler error when CONFIG_PROC_FS not defined
+ * o Bug fix: 2.5.44 e100 doesn't load with preemptive kernel enabled
+ * (sleep while holding spinlock)
+ * o Bug fix: 2.1.24-k1 doesn't display complete statistics
+ * o Bug fix: System panic due to NULL watchdog timer dereference during
+ * ifconfig down, rmmod and insmod
*
* 2.1.24 10/7/02
- * o Bug fix: Wrong files under /proc/net/PRO_LAN_Adapters/ when interface
- * name is changed
- * o Bug fix: Rx skb corruption when Rx polling code and Rx interrupt code
- * are executing during stress traffic at shared interrupt system.
- * Removed Rx polling code
- * o Added detailed printk if selftest failed when insmod
- * o Removed misleading printks
- *
- * 2.1.12 8/2/02
- * o Feature: ethtool register dump
- * o Bug fix: Driver passes wrong name to /proc/interrupts
- * o Bug fix: Ethernet bridging not working
- * o Bug fix: Promiscuous mode is not working
- * o Bug fix: Checked return value from copy_from_user (William Stinson,
- * wstinson@infonie.fr)
- * o Bug fix: ARP wake on LAN fails
- * o Bug fix: mii-diag does not update driver level's speed, duplex and
- * re-configure flow control
- * o Bug fix: Ethtool shows wrong speed/duplex when not connected
- * o Bug fix: Ethtool shows wrong speed/duplex when reconnected if forced
- * speed/duplex
- * o Bug fix: PHY loopback diagnostic fails
- *
- * 2.1.6 7/5/02
*/
#include <linux/config.h>
@@ -81,15 +86,18 @@
#include "e100_ucode.h"
#include "e100_config.h"
#include "e100_phy.h"
-#include "e100_vendor.h"
-#ifdef CONFIG_PROC_FS
-extern int e100_create_proc_subdir(struct e100_private *, char *);
-extern void e100_remove_proc_subdir(struct e100_private *, char *);
-#else
-#define e100_create_proc_subdir(X) 0
-#define e100_remove_proc_subdir(X) do {} while(0)
-#endif
+extern void e100_force_speed_duplex_to_phy(struct e100_private *bdp);
+
+static char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
+ "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+ "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+ "rx_length_errors", "rx_over_errors", "rx_crc_errors",
+ "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+ "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+ "tx_heartbeat_errors", "tx_window_errors",
+};
+#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *);
static void e100_get_speed_duplex_caps(struct e100_private *);
@@ -125,7 +133,6 @@
static int e100_ethtool_led_blink(struct net_device *, struct ifreq *);
-#include <linux/mii.h>
static int e100_mii_ioctl(struct net_device *, struct ifreq *, int);
static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,
@@ -134,31 +141,26 @@
static void e100_non_tx_background(unsigned long);
/* Global Data structures and variables */
-char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-char e100_driver_version[]="2.1.24-k1";
+char e100_copyright[] __devinitdata = "Copyright (c) 2003 Intel Corporation";
+char e100_driver_version[]="2.2.21-k1";
const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
char e100_short_driver_name[] = "e100";
static int e100nics = 0;
+static void e100_vlan_rx_register(struct net_device *netdev, struct vlan_group
+ *grp);
+static void e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
+static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
#ifdef CONFIG_PM
static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
static int e100_suspend(struct pci_dev *pcid, u32 state);
static int e100_resume(struct pci_dev *pcid);
struct notifier_block e100_notifier_reboot = {
- notifier_call: e100_notify_reboot,
- next: NULL,
- priority: 0
+ .notifier_call = e100_notify_reboot,
+ .next = NULL,
+ .priority = 0
};
#endif
-static int e100_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
-
-struct notifier_block e100_notifier_netdev = {
- notifier_call: e100_notify_netdev,
- next: NULL,
- priority: 0
-};
-
-static void e100_get_mdix_status(struct e100_private *bdp);
/*********************************************************************/
/*! This is a GCC extension to ANSI C.
@@ -193,9 +195,9 @@
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 *);
static u8 e100_sw_init(struct e100_private *);
+static void e100_tco_workaround(struct e100_private *);
static unsigned char e100_alloc_space(struct e100_private *);
static void e100_dealloc_space(struct e100_private *);
static int e100_alloc_tcb_pool(struct e100_private *);
@@ -213,7 +215,7 @@
static unsigned char e100_clr_cntrs(struct e100_private *);
static unsigned char e100_load_microcode(struct e100_private *);
-static unsigned char e100_hw_init(struct e100_private *, u32);
+static unsigned char e100_hw_init(struct e100_private *);
static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);
static unsigned char e100_update_stats(struct e100_private *bdp);
@@ -224,8 +226,9 @@
static void e100_set_int_option(int *, int, int, int, int, char *);
static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,
char *);
-unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8);
+unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8);
void e100_exec_cmplx(struct e100_private *, u32, u8);
+static unsigned char e100_asf_enabled(struct e100_private *bdp);
/**
* e100_get_rx_struct - retrieve cell to hold skb buff from the pool
@@ -349,8 +352,6 @@
u32 e100_rx_srv(struct e100_private *);
void e100_watchdog(struct net_device *);
-static void e100_do_hwi(struct net_device *);
-static void e100_hwi_restore(struct e100_private *);
void e100_refresh_txthld(struct e100_private *);
void e100_manage_adaptive_ifs(struct e100_private *);
void e100_clear_pools(struct e100_private *);
@@ -443,9 +444,21 @@
if (!e100_wait_scb(bdp)) {
printk(KERN_DEBUG "e100: %s: e100_wait_exec_simple: failed\n",
bdp->device->name);
+#ifdef E100_CU_DEBUG
+ printk(KERN_ERR "e100: %s: Last command (%x/%x) "
+ "timeout\n", bdp->device->name,
+ bdp->last_cmd, bdp->last_sub_cmd);
+ printk(KERN_ERR "e100: %s: Current simple command (%x) "
+ "can't be executed\n",
+ bdp->device->name, scb_cmd_low);
+#endif
return false;
}
e100_exec_cmd(bdp, scb_cmd_low);
+#ifdef E100_CU_DEBUG
+ bdp->last_cmd = scb_cmd_low;
+ bdp->last_sub_cmd = 0;
+#endif
return true;
}
@@ -458,12 +471,24 @@
}
unsigned char
-e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd)
+e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd, u8 sub_cmd)
{
if (!e100_wait_scb(bdp)) {
+#ifdef E100_CU_DEBUG
+ printk(KERN_ERR "e100: %s: Last command (%x/%x) "
+ "timeout\n", bdp->device->name,
+ bdp->last_cmd, bdp->last_sub_cmd);
+ printk(KERN_ERR "e100: %s: Current complex command "
+ "(%x/%x) can't be executed\n",
+ bdp->device->name, cmd, sub_cmd);
+#endif
return false;
}
e100_exec_cmplx(bdp, phys_addr, cmd);
+#ifdef E100_CU_DEBUG
+ bdp->last_cmd = cmd;
+ bdp->last_sub_cmd = sub_cmd;
+#endif
return true;
}
@@ -494,18 +519,23 @@
}
/**
- * e100_dis_intr - disable interrupts
+ * e100_disable_clear_intr - disable and clear/ack interrupts
* @bdp: atapter's private data struct
*
* This routine disables interrupts at the hardware, by setting
* the M (mask) bit in the adapter's CSR SCB command word.
+ * It also clear/ack interrupts.
*/
static inline void
-e100_dis_intr(struct e100_private *bdp)
+e100_disable_clear_intr(struct e100_private *bdp)
{
+ u16 intr_status;
/* 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 */
+ intr_status = readw(&bdp->scb->scb_status);
+ /* ack and clear intrs */
+ writew(intr_status, &bdp->scb->scb_status);
+ readw(&bdp->scb->scb_status);
}
/**
@@ -581,16 +611,14 @@
bdp->watchdog_timer.data = (unsigned long) dev;
bdp->watchdog_timer.function = (void *) &e100_watchdog;
- init_timer(&bdp->hwi_timer);
- bdp->hwi_timer.data = (unsigned long) dev;
- bdp->hwi_timer.function = (void *) &e100_do_hwi;
-
if ((rc = e100_pci_setup(pcid, bdp)) != 0) {
goto err_dealloc;
}
if (((bdp->pdev->device > 0x1030)
- && (bdp->pdev->device < 0x103F))
+ && (bdp->pdev->device < 0x103F))
+ || ((bdp->pdev->device >= 0x1050)
+ && (bdp->pdev->device <= 0x1057))
|| (bdp->pdev->device == 0x2449)
|| (bdp->pdev->device == 0x2459)
|| (bdp->pdev->device == 0x245D)) {
@@ -623,12 +651,15 @@
cal_checksum = e100_eeprom_calculate_chksum(bdp);
read_checksum = e100_eeprom_read(bdp, (bdp->eeprom_size - 1));
if (cal_checksum != read_checksum) {
- printk(KERN_ERR "e100: Corrupted EERPROM on instance #%d\n",
+ printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n",
e100nics);
rc = -ENODEV;
goto err_pci;
}
+ dev->vlan_rx_register = e100_vlan_rx_register;
+ dev->vlan_rx_add_vid = e100_vlan_rx_add_vid;
+ dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid;
dev->irq = pcid->irq;
dev->open = &e100_open;
dev->hard_start_xmit = &e100_xmit_frame;
@@ -638,9 +669,11 @@
dev->set_multicast_list = &e100_set_multi;
dev->set_mac_address = &e100_set_mac;
dev->do_ioctl = &e100_ioctl;
- if (bdp->flags & USE_IPCB) {
- dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
- }
+
+ if (bdp->flags & USE_IPCB)
+ dev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+
e100nics++;
e100_get_speed_duplex_caps(bdp);
@@ -651,35 +684,24 @@
memcpy(bdp->ifname, dev->name, IFNAMSIZ);
bdp->ifname[IFNAMSIZ-1] = 0;
- bdp->device_type = ent->driver_data;
printk(KERN_NOTICE
"e100: %s: %s\n",
- bdp->device->name, e100_get_brand_msg(bdp));
+ bdp->device->name, "Intel(R) PRO/100 Network Connection");
e100_print_brd_conf(bdp);
- bdp->id_string = e100_get_brand_msg(bdp);
- e100_get_mdix_status(bdp);
- if (netif_carrier_ok(bdp->device))
- bdp->cable_status = "Cable OK";
- else {
- if (bdp->rev_id < D102_REV_ID)
- bdp->cable_status = "Not supported";
- else
- bdp->cable_status = "Not available";
- }
-
- if (e100_create_proc_subdir(bdp, bdp->ifname) < 0) {
- printk(KERN_ERR "e100: Failed to create proc dir for %s\n",
- bdp->device->name);
- }
-
- /* Disabling all WOLs as initialization */
- bdp->wolsupported = bdp->wolopts = 0;
- if (bdp->rev_id >= D101A4_REV_ID) {
- bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
+ bdp->wolsupported = 0;
+ bdp->wolopts = 0;
+
+ /* Check if WoL is enabled on EEPROM */
+ if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) {
+ /* Magic Packet WoL is enabled on device by default */
+ /* if EEPROM WoL bit is TRUE */
+ bdp->wolsupported = WAKE_MAGIC;
+ bdp->wolopts = WAKE_MAGIC;
+ if (bdp->rev_id >= D101A4_REV_ID)
+ bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
if (bdp->rev_id >= D101MA_REV_ID)
bdp->wolsupported |= WAKE_UCAST | WAKE_ARP;
- bdp->wolopts = WAKE_MAGIC;
}
printk(KERN_NOTICE "\n");
@@ -732,8 +754,6 @@
unregister_netdev(dev);
- e100_remove_proc_subdir(bdp, bdp->ifname);
-
e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
@@ -747,6 +767,34 @@
--e100nics;
}
+static struct pci_device_id e100_id_table[] __devinitdata = {
+ {0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ {0,} /* This has to be the last entry*/
+};
MODULE_DEVICE_TABLE(pci, e100_id_table);
static struct pci_driver e100_driver = {
@@ -770,7 +818,6 @@
#ifdef CONFIG_PM
register_reboot_notifier(&e100_notifier_reboot);
#endif
- register_netdevice_notifier(&e100_notifier_netdev);
}
return ret;
@@ -782,7 +829,6 @@
#ifdef CONFIG_PM
unregister_reboot_notifier(&e100_notifier_reboot);
#endif
- unregister_netdevice_notifier(&e100_notifier_netdev);
pci_unregister_driver(&e100_driver);
}
@@ -935,13 +981,6 @@
bdp = dev->priv;
- read_lock(&(bdp->isolate_lock));
-
- if (bdp->driver_isolated) {
- rc = -EBUSY;
- goto exit;
- }
-
/* setup the tcb pool */
if (!e100_alloc_tcb_pool(bdp)) {
rc = -ENOMEM;
@@ -960,12 +999,12 @@
goto err_exit;
}
- if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) {
+ if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) {
rc = -EAGAIN;
goto err_exit;
}
- if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) {
+ if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) {
rc = -EAGAIN;
goto err_exit;
}
@@ -990,7 +1029,6 @@
err_exit:
e100_clear_pools(bdp);
exit:
- read_unlock(&(bdp->isolate_lock));
return rc;
}
@@ -999,18 +1037,16 @@
{
struct e100_private *bdp = dev->priv;
+ e100_disable_clear_intr(bdp);
+ free_irq(dev->irq, dev);
bdp->intr_mask = SCB_INT_MASK;
e100_isolate_driver(bdp);
netif_carrier_off(bdp->device);
bdp->cur_line_speed = 0;
bdp->cur_dplx_mode = 0;
- free_irq(dev->irq, dev);
e100_clear_pools(bdp);
- /* set the isolate flag to false, so e100_open can be called */
- bdp->driver_isolated = false;
-
return 0;
}
@@ -1031,13 +1067,6 @@
int notify_stop = false;
struct e100_private *bdp = dev->priv;
- read_lock(&(bdp->isolate_lock));
-
- if (bdp->driver_isolated) {
- rc = -EBUSY;
- goto exit2;
- }
-
if (!spin_trylock(&bdp->bd_non_tx_lock)) {
notify_stop = true;
rc = 1;
@@ -1060,7 +1089,6 @@
exit1:
spin_unlock(&bdp->bd_non_tx_lock);
exit2:
- read_unlock(&(bdp->isolate_lock));
if (notify_stop) {
netif_stop_queue(dev);
}
@@ -1113,20 +1141,15 @@
int rc = -1;
struct sockaddr *p_sockaddr = (struct sockaddr *) addr;
+ if (!is_valid_ether_addr(p_sockaddr->sa_data))
+ return -EADDRNOTAVAIL;
bdp = dev->priv;
- read_lock(&(bdp->isolate_lock));
-
- if (bdp->driver_isolated) {
- goto exit;
- }
if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) {
memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN);
rc = 0;
}
-exit:
- read_unlock(&(bdp->isolate_lock));
return rc;
}
@@ -1180,10 +1203,6 @@
unsigned char promisc_enbl;
unsigned char mulcast_enbl;
- read_lock(&(bdp->isolate_lock));
- if (bdp->driver_isolated) {
- goto exit;
- }
promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC);
mulcast_enbl = ((dev->flags & IFF_ALLMULTI) ||
(dev->mc_count > MAX_MULTICAST_ADDRS));
@@ -1195,14 +1214,11 @@
e100_config(bdp);
if (promisc_enbl || mulcast_enbl) {
- goto exit; /* no need for Multicast Cmd */
+ return; /* no need for Multicast Cmd */
}
/* get the multicast CB */
e100_set_multi_exec(dev);
-
-exit:
- read_unlock(&(bdp->isolate_lock));
}
static int
@@ -1261,14 +1277,19 @@
/* read the MAC address from the eprom */
e100_rd_eaddr(bdp);
+ if (!is_valid_ether_addr(bdp->device->dev_addr)) {
+ printk(KERN_ERR "e100: Invalid Ethernet address\n");
+ return false;
+ }
/* read NIC's part number */
e100_rd_pwa_no(bdp);
- if (!e100_hw_init(bdp, PORT_SOFTWARE_RESET)) {
+ if (!e100_hw_init(bdp)) {
printk(KERN_ERR "e100: hw init failed\n");
return false;
}
- e100_dis_intr(bdp);
+ /* Interrupts are enabled after device reset */
+ e100_disable_clear_intr(bdp);
return true;
}
@@ -1308,16 +1329,50 @@
spin_lock_init(&(bdp->bd_non_tx_lock));
spin_lock_init(&(bdp->config_lock));
spin_lock_init(&(bdp->mdi_access_lock));
- bdp->isolate_lock = RW_LOCK_UNLOCKED;
- bdp->driver_isolated = false;
return 1;
}
+static void __devinit
+e100_tco_workaround(struct e100_private *bdp)
+{
+ int i;
+
+ /* Do software reset */
+ e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
+
+ /* Do a dummy LOAD CU BASE command. */
+ /* This gets us out of pre-driver to post-driver. */
+ e100_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE);
+
+ /* Wait 20 msec for reset to take effect */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ / 50 + 1);
+
+ /* disable interrupts since they are enabled */
+ /* after device reset */
+ e100_disable_clear_intr(bdp);
+
+ /* Wait for command to be cleared up to 1 sec */
+ for (i=0; i<100; i++) {
+ if (!readb(&bdp->scb->scb_cmd_low))
+ break;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ / 100 + 1);
+ }
+
+ /* Wait for TCO request bit in PMDR register to be clear */
+ for (i=0; i<50; i++) {
+ if (!(readb(&bdp->scb->scb_ext.d101m_scb.scb_pmdr) & BIT_1))
+ break;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ / 100 + 1);
+ }
+}
+
/**
* e100_hw_init - initialized tthe hardware
* @bdp: atapter's private data struct
- * @reset_cmd: s/w reset or selective reset
*
* This routine performs a reset on the adapter, and configures the adapter.
* This includes configuring the 82557 LAN controller, validating and setting
@@ -1329,19 +1384,22 @@
* false - If the adapter failed initialization
*/
unsigned char __devinit
-e100_hw_init(struct e100_private *bdp, u32 reset_cmd)
+e100_hw_init(struct e100_private *bdp)
{
if (!e100_phy_init(bdp))
return false;
- /* Issue a software reset to the e100 */
- e100_sw_reset(bdp, reset_cmd);
+ e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
+
+ /* Only 82559 or above needs TCO workaround */
+ if (bdp->rev_id >= D101MA_REV_ID)
+ e100_tco_workaround(bdp);
/* Load the CU BASE (set to 0, because we use linear mode) */
- if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE))
+ if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
return false;
- if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE))
+ if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
return false;
/* Load interrupt microcode */
@@ -1391,6 +1449,7 @@
u32 next_phys; /* the next phys addr */
u16 txcommand = CB_S_BIT | CB_TX_SF_BIT;
+ bdp->tx_count = 0;
if (bdp->flags & USE_IPCB) {
txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT;
} else if (bdp->flags & IS_BACHELOR) {
@@ -1625,14 +1684,15 @@
{
struct e100_private *bdp = dev->priv;
- read_lock(&(bdp->isolate_lock));
- if (bdp->driver_isolated) {
- goto exit;
+#ifdef E100_CU_DEBUG
+ if (e100_cu_unknown_state(bdp)) {
+ printk(KERN_ERR "e100: %s: CU unknown state in e100_watchdog\n",
+ dev->name);
}
+#endif
if (!netif_running(dev)) {
- goto exit;
+ return;
}
- e100_get_mdix_status(bdp);
/* check if link state has changed */
if (e100_phy_check(bdp)) {
@@ -1645,37 +1705,10 @@
e100_config_fc(bdp);
e100_config(bdp);
- bdp->cable_status = "Cable OK";
} else {
printk(KERN_ERR "e100: %s NIC Link is Down\n",
bdp->device->name);
- if (bdp->rev_id < D102_REV_ID)
- bdp->cable_status = "Not supported";
- else {
- /* Initiate hwi, ie, cable diagnostic */
- bdp->saved_open_circut = 0xffff;
- bdp->saved_short_circut = 0xffff;
- bdp->saved_distance = 0xffff;
- bdp->saved_i = 0;
- bdp->saved_same = 0;
- bdp->hwi_started = 1;
-
- /* Disable MDI/MDI-X auto switching */
- e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
- MDI_MDIX_RESET_ALL_MASK);
-
- /* Set to 100 Full as required by hwi test */
- e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
- BMCR_SPEED100 | BMCR_FULLDPLX);
-
- /* Enable and execute HWI test */
- e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
- (HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
-
- /* Launch hwi timer in 1 msec */
- mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
- }
}
}
@@ -1685,7 +1718,13 @@
if (netif_running(dev))
netif_wake_queue(dev);
} else {
- netif_stop_queue(dev);
+ if (netif_running(dev))
+ netif_stop_queue(dev);
+ /* When changing to non-autoneg, device may lose */
+ /* link with some switches. e100 will try to */
+ /* revover link by sending command to PHY layer */
+ if (bdp->params.e100_speed_duplex != E100_AUTONEG)
+ e100_force_speed_duplex_to_phy(bdp);
}
rmb();
@@ -1721,9 +1760,6 @@
if (list_empty(&bdp->active_rx_list))
e100_trigger_SWI(bdp);
-
-exit:
- read_unlock(&(bdp->isolate_lock));
}
/**
@@ -1812,15 +1848,13 @@
bdp = dev->priv;
intr_status = readw(&bdp->scb->scb_status);
- if (!intr_status || (intr_status == 0xffff)) {
+ /* If not my interrupt, just return */
+ if (!(intr_status & SCB_STATUS_ACK_MASK) || (intr_status == 0xffff)) {
return;
}
- /* disable intr before we ack & after identifying the intr as ours */
- e100_dis_intr(bdp);
-
- writew(intr_status, &bdp->scb->scb_status); /* ack intrs */
- readw(&bdp->scb->scb_status);
+ /* disable and ack intr */
+ e100_disable_clear_intr(bdp);
/* the device is closed, don't continue or else bad things may happen. */
if (!netif_running(dev)) {
@@ -1828,11 +1862,6 @@
return;
}
- read_lock(&(bdp->isolate_lock));
- if (bdp->driver_isolated) {
- goto exit;
- }
-
/* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */
if (intr_status & SCB_STATUS_ACK_SWI) {
e100_alloc_skbs(bdp);
@@ -1844,14 +1873,10 @@
bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp);
/* clean up after tx'ed packets */
- if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) {
- bdp->tx_count = 0; /* restart tx interrupt batch count */
+ if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX))
e100_tx_srv(bdp);
- }
-exit:
e100_set_intr_mask(bdp);
- read_unlock(&(bdp->isolate_lock));
}
/**
@@ -1861,7 +1886,7 @@
*
* This routine frees resources of TX skbs.
*/
-static void inline
+static inline void
e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb)
{
if (tcb->tcb_skb) {
@@ -1980,7 +2005,7 @@
/* to allow manipulation with current skb we need to unlink it */
list_del(&(rx_struct->list_elem));
- /* do not free & unmap badly recieved packet.
+ /* do not free & unmap badly received packet.
* move it to the end of skb list for reuse */
if (!(rfd_status & RFD_STATUS_OK)) {
e100_add_skb_to_end(bdp, rx_struct);
@@ -2024,17 +2049,15 @@
} else {
skb->ip_summed = CHECKSUM_NONE;
}
- switch (netif_rx(skb)) {
- case NET_RX_BAD:
- case NET_RX_DROP:
- case NET_RX_CN_MOD:
- case NET_RX_CN_HIGH:
- break;
- default:
- bdp->drv_stats.net_stats.rx_bytes += skb->len;
- break;
- }
+ if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) {
+ vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid));
+ } else {
+ netif_rx(skb);
+ }
+ dev->last_rx = jiffies;
+ bdp->drv_stats.net_stats.rx_bytes += skb->len;
+
rfd_cnt++;
} /* end of rfd loop */
@@ -2102,32 +2125,6 @@
}
/**
- * 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);
-}
-
-/**
* e100_prepare_xmit_buff - prepare a buffer for transmission
* @bdp: atapter's private data struct
* @skb: skb to send
@@ -2153,15 +2150,21 @@
tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE;
}
+ if(bdp->vlgrp && vlan_tx_tag_present(skb)) {
+ (tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE;
+ (tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb));
+ }
+
tcb->tcb_hdr.cb_status = 0;
tcb->tcb_thrshld = bdp->tx_thld;
tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
- /* set the I bit on the modulo tcbs, so we will get an interrupt * to
- * clean things up */
- if (!(++bdp->tx_count % TX_FRAME_CNT)) {
+ /* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */
+ if (!(++bdp->tx_count % TX_FRAME_CNT))
tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT);
- }
+ else
+ /* Clear I bit on other packets */
+ tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT);
tcb->tcb_skb = skb;
@@ -2170,27 +2173,14 @@
if ((ip->protocol == IPPROTO_TCP) ||
(ip->protocol == IPPROTO_UDP)) {
- u16 *chksum;
- tcb->tcbu.ipcb.ip_activation_high =
+ tcb->tcbu.ipcb.ip_activation_high |=
IPCB_HARDWAREPARSING_ENABLE;
tcb->tcbu.ipcb.ip_schedule |=
IPCB_TCPUDP_CHECKSUM_ENABLE;
- if (ip->protocol == IPPROTO_TCP) {
- struct tcphdr *tcp;
-
- tcp = (struct tcphdr *) ((u32 *) ip + ip->ihl);
- chksum = &(tcp->check);
+ if (ip->protocol == IPPROTO_TCP)
tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET;
- } else {
- struct udphdr *udp;
-
- udp = (struct udphdr *) ((u32 *) ip + ip->ihl);
- chksum = &(udp->check);
- }
-
- *chksum = e100_pseudo_hdr_csum(ip);
}
}
@@ -2257,15 +2247,16 @@
*
* e100_start_cu must be called while holding the tx_lock !
*/
-void
+u8
e100_start_cu(struct e100_private *bdp, tcb_t *tcb)
{
unsigned long lock_flag;
+ u8 ret = true;
spin_lock_irqsave(&(bdp->bd_lock), lock_flag);
switch (bdp->next_cu_cmd) {
case RESUME_NO_WAIT:
- /*last cu command was a CU_RESMUE if this is a 558 or newer we dont need to
+ /*last cu command was a CU_RESMUE if this is a 558 or newer we don't need to
* wait for command word to clear, we reach here only if we are bachlor
*/
e100_exec_cmd(bdp, SCB_CUC_RESUME);
@@ -2291,12 +2282,13 @@
"e100: %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, CB_TRANSMIT)) {
printk(KERN_DEBUG
"e100: %s: cu_start: timeout waiting for scb\n",
bdp->device->name);
e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
SCB_CUC_START);
+ ret = false;
}
bdp->next_cu_cmd = RESUME_WAIT;
@@ -2308,6 +2300,7 @@
bdp->last_tcb = tcb;
spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+ return ret;
}
/* ====================================================================== */
@@ -2355,8 +2348,9 @@
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ / 100 + 1);
- /* disable interrupts since the're now enabled */
- e100_dis_intr(bdp);
+ /* disable interrupts since they are enabled */
+ /* after device reset during selftest */
+ e100_disable_clear_intr(bdp);
/* if The First Self Test DWORD Still Zero, We've timed out. If the
* second DWORD is not zero then we have an error. */
@@ -2454,7 +2448,7 @@
spin_lock(&bdp->bd_lock);
- if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START)) {
+ if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START, 0)) {
printk(KERN_DEBUG
"e100: %s: start_ru: wait_scb failed\n",
bdp->device->name);
@@ -2522,7 +2516,7 @@
*pcmd_complete = 0;
wmb();
- if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR))
+ if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0))
return false;
/* wait 10 microseconds for the command to complete */
@@ -2644,8 +2638,10 @@
unsigned long lock_flag;
unsigned long expiration_time;
unsigned char rc = true;
+ u8 sub_cmd;
ntcb_hdr = (cb_header_t *) command->non_tx_cmd; /* get hdr of non tcb cmd */
+ sub_cmd = cpu_to_le16(ntcb_hdr->cb_cmd);
/* Set the Command Block to be the last command block */
ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT);
@@ -2656,7 +2652,7 @@
if (in_interrupt())
return e100_delayed_exec_non_cu_cmd(bdp, command);
- if (netif_running(bdp->device) && (!bdp->driver_isolated))
+ if (netif_running(bdp->device) && netif_carrier_ok(bdp->device))
return e100_delayed_exec_non_cu_cmd(bdp, command);
spin_lock_bh(&(bdp->bd_non_tx_lock));
@@ -2678,7 +2674,7 @@
spin_lock_irqsave(&bdp->bd_lock, lock_flag);
- if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START)) {
+ if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START, sub_cmd)) {
spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
rc = false;
goto exit;
@@ -2698,6 +2694,10 @@
yield();
spin_lock_bh(&(bdp->bd_non_tx_lock));
} else {
+#ifdef E100_CU_DEBUG
+ printk(KERN_ERR "e100: %s: non-TX command (%x) "
+ "timeout\n", bdp->device->name, sub_cmd);
+#endif
rc = false;
goto exit;
}
@@ -2742,8 +2742,12 @@
udelay(20);
}
- /* Mask off our interrupt line -- its unmasked after reset */
- e100_dis_intr(bdp);
+ /* Mask off our interrupt line -- it is unmasked after reset */
+ e100_disable_clear_intr(bdp);
+#ifdef E100_CU_DEBUG
+ bdp->last_cmd = 0;
+ bdp->last_sub_cmd = 0;
+#endif
}
/**
@@ -2943,19 +2947,6 @@
void __devinit
e100_print_brd_conf(struct e100_private *bdp)
{
- if (netif_carrier_ok(bdp->device)) {
- printk(KERN_NOTICE
- " Mem:0x%08lx IRQ:%d Speed:%d Mbps Dx:%s\n",
- (unsigned long) bdp->device->mem_start,
- bdp->device->irq, bdp->cur_line_speed,
- (bdp->cur_dplx_mode == FULL_DUPLEX) ? "Full" : "Half");
- } else {
- printk(KERN_NOTICE
- " Mem:0x%08lx IRQ:%d Speed:%d Mbps Dx:%s\n",
- (unsigned long) bdp->device->mem_start,
- bdp->device->irq, 0, "N/A");
- }
-
/* Print the string if checksum Offloading was enabled */
if (bdp->flags & DF_CSUM_OFFLOAD)
printk(KERN_NOTICE " Hardware receive checksums enabled\n");
@@ -2969,27 +2960,6 @@
}
/**
- * e100_get_brand_msg
- * @bdp: atapter's private data struct
- *
- * This routine checks if there is specified branding message for a given board
- * type and returns a pointer to the string containing the branding message.
- */
-char *
-e100_get_brand_msg(struct e100_private *bdp)
-{
- int i;
-
- for (i = 0; e100_vendor_info_array[i].idstr != NULL; i++) {
- if (e100_vendor_info_array[i].device_type == bdp->device_type) {
- return e100_vendor_info_array[i].idstr;
- }
- }
-
- return e100_vendor_info_array[E100_ALL_BOARDS].idstr;
-}
-
-/**
* e100_pci_setup - setup the adapter's PCI information
* @pcid: adapter's pci_dev struct
* @bdp: atapter's private data struct
@@ -3054,33 +3024,36 @@
void
e100_isolate_driver(struct e100_private *bdp)
{
- write_lock_irq(&(bdp->isolate_lock));
- bdp->driver_isolated = true;
- write_unlock_irq(&(bdp->isolate_lock));
-
- del_timer_sync(&bdp->watchdog_timer);
-
- del_timer_sync(&bdp->hwi_timer);
- /* If in middle of cable diag, */
- if (bdp->hwi_started) {
- bdp->hwi_started = 0;
- e100_hwi_restore(bdp);
- }
-
- if (netif_running(bdp->device))
- netif_stop_queue(bdp->device);
-
- bdp->last_tcb = NULL;
+ /* Check if interface is up */
+ /* NOTE: Can't use netif_running(bdp->device) because */
+ /* dev_close clears __LINK_STATE_START before calling */
+ /* e100_close (aka dev->stop) */
+ if (bdp->device->flags & IFF_UP) {
+ e100_disable_clear_intr(bdp);
+ del_timer_sync(&bdp->watchdog_timer);
+ netif_carrier_off(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)
{
+ int carrier_ok;
+ /* Device may lose link with some siwtches when */
+ /* changing speed/duplex to non-autoneg. e100 */
+ /* needs to remember carrier state in order to */
+ /* start watchdog timer for recovering link */
+ if ((carrier_ok = netif_carrier_ok(bdp->device)))
+ e100_isolate_driver(bdp);
e100_phy_set_speed_duplex(bdp, true);
e100_config_fc(bdp); /* re-config flow-control if necessary */
e100_config(bdp);
+ if (carrier_ok)
+ e100_deisolate_driver(bdp, false);
}
static void
@@ -3095,63 +3068,51 @@
}
/*
- * Procedure: e100_hw_reset_recover
+ * Procedure: e100_configure_device
*
- * Description: This routine will recover the hw after reset.
+ * Description: This routine will configure device
*
* 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)
+e100_configure_device(struct e100_private *bdp)
{
- 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;
- }
+ /*load CU & RU base */
+ if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
+ return false;
- if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) {
- return false;
- }
+ if (e100_load_microcode(bdp))
+ bdp->flags |= DF_UCODE_LOADED;
- /* 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_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
+ return false;
- if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) {
- printk(KERN_ERR
- "e100: e100_hw_reset_recover: "
- "setup iaaddr failed\n");
- return false;
- }
+ /* Issue the load dump counters address command */
+ if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0))
+ return false;
- e100_set_multi_exec(bdp->device);
+ if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) {
+ printk(KERN_ERR "e100: e100_configure_device: "
+ "setup iaaddr failed\n");
+ return false;
+ }
- /* 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_set_multi_exec(bdp->device);
+ /* Change for 82558 enhancement */
+ /* If 82558/9 and if the user has enabled flow control, set up */
+ /* 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);
@@ -3160,29 +3121,21 @@
}
void
-e100_deisolate_driver(struct e100_private *bdp, u8 recover, u8 full_init)
+e100_deisolate_driver(struct e100_private *bdp, u8 full_reset)
{
- if (full_init) {
- e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
- if (!e100_hw_reset_recover(bdp, PORT_SOFTWARE_RESET))
- printk(KERN_ERR "e100: e100_deisolate_driver:"
- " HW SOFTWARE reset recover failed\n");
- }
+ u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET;
+ e100_sw_reset(bdp, cmd);
+ if (cmd == PORT_SOFTWARE_RESET) {
+ if (!e100_configure_device(bdp))
+ printk(KERN_ERR "e100: e100_deisolate_driver:"
+ " device configuration failed\n");
+ }
- if (recover) {
+ if (netif_running(bdp->device)) {
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: e100_deisolate_driver:"
- " HW reset recover failed\n");
- }
- }
e100_start_ru(bdp);
/* relaunch watchdog timer in 2 sec */
@@ -3192,14 +3145,9 @@
// or have unsent frames on the tcb chain
e100_tcb_add_C_bit(bdp);
e100_tx_srv(bdp);
-
+ netif_wake_queue(bdp->device);
e100_set_intr_mask(bdp);
-
- if (netif_running(bdp->device))
- netif_wake_queue(bdp->device);
}
-
- bdp->driver_isolated = false;
}
static int
@@ -3234,6 +3182,22 @@
case ETHTOOL_SEEPROM:
rc = e100_ethtool_eeprom(dev, ifr);
break;
+ case ETHTOOL_GSTATS: {
+ struct {
+ struct ethtool_stats cmd;
+ uint64_t data[E100_STATS_LEN];
+ } stats = { {ETHTOOL_GSTATS, E100_STATS_LEN} };
+ struct e100_private *bdp = dev->priv;
+ void *addr = ifr->ifr_data;
+ int i;
+
+ for(i = 0; i < E100_STATS_LEN; i++)
+ stats.data[i] =
+ ((unsigned long *)&bdp->drv_stats.net_stats)[i];
+ if(copy_to_user(addr, &stats, sizeof(stats)))
+ return -EFAULT;
+ return 0;
+ }
case ETHTOOL_GWOL:
case ETHTOOL_SWOL:
rc = e100_ethtool_wol(dev, ifr);
@@ -3316,10 +3280,8 @@
e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr)
{
struct e100_private *bdp;
- int current_duplex;
int e100_new_speed_duplex;
int ethtool_new_speed_duplex;
- int speed_duplex_change_required;
struct ethtool_cmd ecmd;
if (!capable(CAP_NET_ADMIN)) {
@@ -3327,64 +3289,48 @@
}
bdp = dev->priv;
- if (netif_running(dev)) {
- return -EBUSY;
- }
if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) {
return -EFAULT;
}
- current_duplex =
- (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
- speed_duplex_change_required = (ecmd.speed != bdp->cur_line_speed)
- || (ecmd.duplex != current_duplex);
-
- if ((ecmd.autoneg == AUTONEG_ENABLE) && speed_duplex_change_required) {
- return -EINVAL;
- }
if ((ecmd.autoneg == AUTONEG_ENABLE)
&& (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) {
bdp->params.e100_speed_duplex = E100_AUTONEG;
e100_set_speed_duplex(bdp);
} else {
- if (speed_duplex_change_required) {
- if (ecmd.speed == SPEED_10) {
- if (ecmd.duplex == DUPLEX_HALF) {
- e100_new_speed_duplex =
- E100_SPEED_10_HALF;
- ethtool_new_speed_duplex =
- SUPPORTED_10baseT_Half;
-
- } else {
- e100_new_speed_duplex =
- E100_SPEED_10_FULL;
- ethtool_new_speed_duplex =
- SUPPORTED_10baseT_Full;
- }
-
- } else {
- if (ecmd.duplex == DUPLEX_HALF) {
- e100_new_speed_duplex =
- E100_SPEED_100_HALF;
- ethtool_new_speed_duplex =
- SUPPORTED_100baseT_Half;
-
- } else {
- e100_new_speed_duplex =
- E100_SPEED_100_FULL;
- ethtool_new_speed_duplex =
- SUPPORTED_100baseT_Full;
- }
- }
-
- if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
- bdp->params.e100_speed_duplex =
- e100_new_speed_duplex;
- e100_set_speed_duplex(bdp);
- } else {
- return -EOPNOTSUPP;
- }
- }
+ if (ecmd.speed == SPEED_10) {
+ if (ecmd.duplex == DUPLEX_HALF) {
+ e100_new_speed_duplex =
+ E100_SPEED_10_HALF;
+ ethtool_new_speed_duplex =
+ SUPPORTED_10baseT_Half;
+ } else {
+ e100_new_speed_duplex =
+ E100_SPEED_10_FULL;
+ ethtool_new_speed_duplex =
+ SUPPORTED_10baseT_Full;
+ }
+ } else {
+ if (ecmd.duplex == DUPLEX_HALF) {
+ e100_new_speed_duplex =
+ E100_SPEED_100_HALF;
+ ethtool_new_speed_duplex =
+ SUPPORTED_100baseT_Half;
+ } else {
+ e100_new_speed_duplex =
+ E100_SPEED_100_FULL;
+ ethtool_new_speed_duplex =
+ SUPPORTED_100baseT_Full;
+ }
+ }
+
+ if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
+ bdp->params.e100_speed_duplex =
+ e100_new_speed_duplex;
+ e100_set_speed_duplex(bdp);
+ } else {
+ return -EOPNOTSUPP;
+ }
}
return 0;
@@ -3503,6 +3449,7 @@
sizeof (info.fw_version) - 1);
strncpy(info.bus_info, bdp->pdev->slot_name,
sizeof (info.bus_info) - 1);
+ info.n_stats = E100_STATS_LEN;
info.regdump_len = E100_REGS_LEN * sizeof(u32);
info.eedump_len = (bdp->eeprom_size << 1);
info.testinfo_len = E100_MAX_TEST_RES;
@@ -3522,6 +3469,7 @@
u16 first_word, last_word;
int i, max_len;
void *ptr;
+ u8 *eeprom_data_bytes = (u8 *)eeprom_data;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -3557,7 +3505,9 @@
if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
return -EFAULT;
- if (copy_to_user(usr_eeprom_ptr, eeprom_data, ecmd.len))
+ if(ecmd.offset & 1)
+ eeprom_data_bytes++;
+ if (copy_to_user(usr_eeprom_ptr, eeprom_data_bytes, ecmd.len))
return -EFAULT;
} else {
if (ecmd.magic != E100_EEPROM_MAGIC)
@@ -3850,7 +3800,8 @@
return -EFAULT;
switch (info.string_set) {
- case ETH_SS_TEST:
+ case ETH_SS_TEST: {
+ int ret = 0;
if (info.len > E100_MAX_TEST_RES)
info.len = E100_MAX_TEST_RES;
strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
@@ -3862,19 +3813,29 @@
sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
test_strings[i]);
}
- break;
+ if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+ ret = -EFAULT;
+ if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
+ ret = -EFAULT;
+ kfree(strings);
+ return ret;
+ }
+ case ETH_SS_STATS: {
+ char *strings = NULL;
+ void *addr = ifr->ifr_data;
+ info.len = E100_STATS_LEN;
+ strings = *e100_gstrings_stats;
+ if(copy_to_user(ifr->ifr_data, &info, sizeof(info)))
+ return -EFAULT;
+ addr += offsetof(struct ethtool_gstrings, data);
+ if(copy_to_user(addr, strings,
+ info.len * ETH_GSTRING_LEN))
+ return -EFAULT;
+ return 0;
+ }
default:
return -EOPNOTSUPP;
}
-
- if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
- return -EFAULT;
-
- if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
- return -EFAULT;
-
- kfree(strings);
- return 0;
}
static int
@@ -3901,9 +3862,6 @@
case SIOCSMIIREG:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (netif_running(dev)) {
- return -EBUSY;
- }
/* If reg = 0 && change speed/duplex */
if (data_ptr->reg_num == 0 &&
(data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */
@@ -3923,10 +3881,9 @@
bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
e100_set_speed_duplex(bdp);
}
- else {
- e100_mdi_write(bdp, data_ptr->reg_num, bdp->phy_addr,
- data_ptr->val_in);
- }
+ else
+ /* Only allows changing speed/duplex */
+ return -EINVAL;
break;
@@ -4023,6 +3980,8 @@
struct e100_private *bdp = (struct e100_private *) ptr;
nxmit_cb_entry_t *active_command;
int restart = true;
+ cb_header_t *non_tx_cmd;
+ u8 sub_cmd;
spin_lock_bh(&(bdp->bd_non_tx_lock));
@@ -4050,6 +4009,15 @@
&& time_before(jiffies, active_command->expiration_time)) {
goto exit;
} else {
+ non_tx_cmd = (cb_header_t *) active_command->non_tx_cmd;
+ sub_cmd = CB_CMD_MASK & le16_to_cpu(non_tx_cmd->cb_cmd);
+#ifdef E100_CU_DEBUG
+ if (!(non_tx_cmd->cb_status
+ & __constant_cpu_to_le16(CB_STATUS_COMPLETE)))
+ printk(KERN_ERR "e100: %s: Queued "
+ "command (%x) timeout\n",
+ bdp->device->name, sub_cmd);
+#endif
list_del(&(active_command->list_elem));
e100_free_non_tx_cmd(bdp, active_command);
}
@@ -4072,9 +4040,10 @@
bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH;
active_command = list_entry(bdp->non_tx_cmd_list.next,
nxmit_cb_entry_t, list_elem);
+ sub_cmd = ((cb_header_t *) active_command->non_tx_cmd)->cb_cmd;
spin_lock_irq(&(bdp->bd_lock));
e100_wait_exec_cmplx(bdp, active_command->dma_addr,
- SCB_CUC_START);
+ SCB_CUC_START, sub_cmd);
spin_unlock_irq(&(bdp->bd_lock));
active_command->expiration_time = jiffies + HZ;
cmd_type = CB_CMD_MASK &
@@ -4093,27 +4062,43 @@
spin_unlock_bh(&(bdp->bd_non_tx_lock));
}
-int e100_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
+static void
+e100_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
{
- struct e100_private *bdp;
- struct net_device *netdev = p;
-
- if(netdev == NULL)
- return NOTIFY_DONE;
-
- switch(event) {
- case NETDEV_CHANGENAME:
- if(netdev->open == e100_open) {
- bdp = netdev->priv;
- /* rename the proc nodes the easy way */
- e100_remove_proc_subdir(bdp, bdp->ifname);
- memcpy(bdp->ifname, netdev->name, IFNAMSIZ);
- bdp->ifname[IFNAMSIZ-1] = 0;
- e100_create_proc_subdir(bdp, bdp->ifname);
- }
- break;
+ struct e100_private *bdp = netdev->priv;
+
+ e100_disable_clear_intr(bdp);
+ bdp->vlgrp = grp;
+
+ if(grp) {
+ /* enable VLAN tag insert/strip */
+ e100_config_vlan_drop(bdp, true);
+
+ } else {
+ /* disable VLAN tag insert/strip */
+ e100_config_vlan_drop(bdp, false);
}
- return NOTIFY_DONE;
+
+ e100_config(bdp);
+ e100_set_intr_mask(bdp);
+}
+
+static void
+e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+ /* We don't do Vlan filtering */
+ return;
+}
+
+static void
+e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+ struct e100_private *bdp = netdev->priv;
+
+ if(bdp->vlgrp)
+ bdp->vlgrp->vlan_devices[vid] = NULL;
+ /* We don't do Vlan filtering */
+ return;
}
#ifdef CONFIG_PM
@@ -4147,9 +4132,11 @@
e100_isolate_driver(bdp);
pci_save_state(pcid, bdp->pci_state);
+ /* Enable or disable WoL */
+ e100_do_wol(pcid, bdp);
+
/* If wol is enabled */
- if (bdp->wolopts) {
- e100_do_wol(pcid, bdp);
+ if (bdp->wolopts || e100_asf_enabled(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 {
@@ -4165,145 +4152,56 @@
{
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;
- }
-
- if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) {
- full_init = true;
- }
-
- e100_deisolate_driver(bdp, recover, full_init);
+ /* Also do device full reset because device was in D3 state */
+ e100_deisolate_driver(bdp, true);
return 0;
}
#endif /* CONFIG_PM */
-static void
-e100_get_mdix_status(struct e100_private *bdp)
-{
- if (bdp->rev_id < D102_REV_ID) {
- if (netif_carrier_ok(bdp->device))
- bdp->mdix_status = "MDI";
- else
- bdp->mdix_status = "None";
- } else {
- u16 ctrl_reg;
- /* Read the MDIX control register */
- e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &ctrl_reg);
- if (ctrl_reg & MDI_MDIX_CONFIG_IS_OK) {
- if (ctrl_reg & MDI_MDIX_STATUS)
- bdp->mdix_status = "MDI-X";
- else
- bdp->mdix_status = "MDI";
- } else
- bdp->mdix_status = "None";
- }
-}
-
-static void
-e100_do_hwi(struct net_device *dev)
+/**
+ * e100_asf_enabled - checks if ASF is configured on the current adaper
+ * by reading registers 0xD and 0x90 in the EEPROM
+ * @bdp: atapter's private data struct
+ *
+ * Returns: true if ASF is enabled
+ */
+static unsigned char
+e100_asf_enabled(struct e100_private *bdp)
{
- struct e100_private *bdp = dev->priv;
- u16 ctrl_reg;
- int distance, open_circut, short_circut;
-
- e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg);
-
- distance = ctrl_reg & HWI_TEST_DISTANCE;
- open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM;
- short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM;
-
- if ((distance == bdp->saved_distance) &&
- (open_circut == bdp->saved_open_circut) &&
- (short_circut == bdp->saved_short_circut))
- bdp->saved_same++;
- else {
- bdp->saved_same = 0;
- bdp->saved_distance = distance;
- bdp->saved_open_circut = open_circut;
- bdp->saved_short_circut = short_circut;
- }
-
- if (bdp->saved_same == MAX_SAME_RESULTS) {
- if ((open_circut && !(short_circut)) ||
- (!(open_circut) && short_circut)) {
-
- u8 near_end = ((distance * HWI_REGISTER_GRANULARITY) <
- HWI_NEAR_END_BOUNDARY);
- if (open_circut) {
- if (near_end)
- bdp->cable_status = "Open Circut Near End";
- else
- bdp->cable_status = "Open Circut Far End";
- } else {
- if (near_end)
- bdp->cable_status = "Short Circut Near End";
- else
- bdp->cable_status = "Short Circut Far End";
- }
- goto done;
+ u16 asf_reg;
+ u16 smbus_addr_reg;
+ if ((bdp->pdev->device >= 0x1050) && (bdp->pdev->device <= 0x1055)) {
+ asf_reg = e100_eeprom_read(bdp, EEPROM_CONFIG_ASF);
+ if ((asf_reg & EEPROM_FLAG_ASF)
+ && !(asf_reg & EEPROM_FLAG_GCL)) {
+ smbus_addr_reg =
+ e100_eeprom_read(bdp, EEPROM_SMBUS_ADDR);
+ if ((smbus_addr_reg & 0xFF) != 0xFE)
+ return true;
}
}
- else if (bdp->saved_i == HWI_MAX_LOOP) {
- bdp->cable_status = "Test failed";
- goto done;
- }
-
- /* Do another hwi test */
- e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
- (HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
- bdp->saved_i++;
- /* relaunch hwi timer in 1 msec */
- mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
- return;
-
-done:
- e100_hwi_restore(bdp);
- bdp->hwi_started = 0;
- return;
+ return false;
}
-static void e100_hwi_restore(struct e100_private *bdp)
+#ifdef E100_CU_DEBUG
+unsigned char
+e100_cu_unknown_state(struct e100_private *bdp)
{
- u16 control = 0;
-
- /* Restore speed, duplex and autoneg before */
- /* hwi test, i.e., cable diagnostic */
-
- /* Reset hwi test */
- e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK);
-
- if ((bdp->params.e100_speed_duplex == E100_AUTONEG) &&
- (bdp->rev_id >= D102_REV_ID))
- /* Enable MDI/MDI-X auto switching */
- e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
- MDI_MDIX_AUTO_SWITCH_ENABLE);
-
- switch (bdp->params.e100_speed_duplex) {
- case E100_SPEED_10_HALF:
- break;
- case E100_SPEED_10_FULL:
- control = BMCR_FULLDPLX;
- break;
- case E100_SPEED_100_HALF:
- control = BMCR_SPEED100;
- break;
- case E100_SPEED_100_FULL:
- control = BMCR_SPEED100 | BMCR_FULLDPLX;
- break;
- case E100_AUTONEG:
- control = BMCR_ANENABLE | BMCR_ANRESTART;
- break;
- }
- /* Restore original speed/duplex */
- e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
- return;
+ u8 scb_cmd_low;
+ u16 scb_status;
+ scb_cmd_low = bdp->scb->scb_cmd_low;
+ scb_status = le16_to_cpu(bdp->scb->scb_status);
+ /* If CU is active and executing unknown cmd */
+ if (scb_status & SCB_CUS_ACTIVE && scb_cmd_low & SCB_CUC_UNKNOWN)
+ return true;
+ else
+ return false;
}
+#endif
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)