Commit c0e1c9e4 authored by Scott Feldman's avatar Scott Feldman Committed by David Mosberger

Update e100 net driver:

o Added device ID support for Dell LOM.
o Added device ID support for 82511QM mobile nics.
o Bug fix: ethtool get/set EEPROM routines modified to use byte
  addressing rather than word addressing.
o Feature: added MDIX mode support for 82550 and up.
o Bug fix: added reboot notifier to setup WOL settings when
  shutting system down.
o Cleanup: removed yield() redefinition (Andrew Morton,
  akpm@zip.com.au).
o Bug fix: flow control now working when link partner is
  autoneg capable but not flow control capable.
o Bug fix: added check for corrupted EEPROM
o Bug fix: don't report checksum offloading for the older
  controllers that don't support the feature.
o Bug fix: calculate cable diagnostics when link goes down
  rather than when queuering /proc file.
o Cleanup: move mdi_access_lock to local get/set mdi routines.
parent f54cb1a1
......@@ -91,6 +91,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <linux/version.h>
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/reboot.h>
#include <asm/io.h>
#include <asm/unaligned.h>
#include <asm/processor.h>
......@@ -147,6 +148,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define E100_MAX_SCB_WAIT 100 /* Max udelays in wait_scb */
#define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */
/* HWI feature related constant */
#define HWI_MAX_LOOP 100
#define MAX_SAME_RESULTS 3
#define HWI_REGISTER_GRANULARITY 80 /* register granularity = 80 Cm */
#define HWI_NEAR_END_BOUNDARY 1000 /* Near end is defined as < 10 meters */
/* CPUSAVER_BUNDLE_MAX: Sets the maximum number of frames that will be bundled.
* In some situations, such as the TCP windowing algorithm, it may be
* better to limit the growth of the bundle size than let it go as
......@@ -504,6 +511,7 @@ enum led_state_e {
#define IS_ICH 0x00000020
#define DF_SPEED_FORCED 0x00000040 /* set if speed is forced */
#define LED_IS_ON 0x00000080 /* LED is turned ON by the driver */
#define DF_LINK_FC_TX_ONLY 0x00000100 /* Received PAUSE frames are honored*/
typedef struct net_device_stats net_dev_stats_t;
......@@ -987,6 +995,18 @@ struct e100_private {
rwlock_t isolate_lock;
int driver_isolated;
char *id_string;
char *cable_status;
char *mdix_status;
/* Variables for HWI */
int saved_open_circut;
int saved_short_circut;
int saved_distance;
int saved_i;
int saved_same;
unsigned char hwi_started;
struct timer_list hwi_timer; /* hwi timer id */
u32 speed_duplex_caps; /* adapter's speed/duplex capabilities */
......
......@@ -86,10 +86,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* operating system. *
* *
**********************************************************************/
#ifdef SIOCETHTOOL
#include <linux/ethtool.h>
#endif
#include "e100_config.h"
static void e100_config_long_rx(struct e100_private *bdp, unsigned char enable);
......@@ -308,85 +304,58 @@ e100_config(struct e100_private *bdp)
/**
* e100_config_fc - config flow-control state
* @bdp: atapter's private data struct
* @bdp: adapter's private data struct
*
* This routine will enable or disable flow control support in the adapter's
* config block. Flow control will be enable only if requested using the command
* line option, and if the link is flow-contorl capable (both us and the link
* partner).
*
* Returns:
* true: if then option was indeed changed
* false: if no change was needed
* partner). But, if link partner is capable of autoneg, but not capable of
* flow control, received PAUSE frames are still honored.
*/
unsigned char
void
e100_config_fc(struct e100_private *bdp)
{
unsigned char enable = false;
unsigned char changed = false;
/* 82557 doesn't support fc. Don't touch this option */
if (!(bdp->flags & IS_BACHELOR))
return false;
return;
/* Enable fc if requested and if the link supports it */
if ((bdp->params.b_params & PRM_FC) && (bdp->flags & DF_LINK_FC_CAP)) {
if ((bdp->params.b_params & PRM_FC) && (bdp->flags &
(DF_LINK_FC_CAP | DF_LINK_FC_TX_ONLY))) {
enable = true;
}
spin_lock_bh(&(bdp->config_lock));
if (enable) {
if (bdp->config[16] != DFLT_FC_DELAY_LSB) {
if (bdp->flags & DF_LINK_FC_TX_ONLY) {
/* If link partner is capable of autoneg, but */
/* not capable of flow control, Received PAUSE */
/* frames are still honored, i.e., */
/* transmitted frames would be paused by */
/* incoming PAUSE frames */
bdp->config[16] = DFLT_NO_FC_DELAY_LSB;
bdp->config[17] = DFLT_NO_FC_DELAY_MSB;
bdp->config[19] &= ~(CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART);
bdp->config[19] |= CB_CFIG_FC_REJECT;
bdp->config[19] &= ~CB_CFIG_TX_FC_DIS;
} else {
bdp->config[16] = DFLT_FC_DELAY_LSB;
E100_CONFIG(bdp, 16);
changed = true;
}
if (bdp->config[17] != DFLT_FC_DELAY_LSB) {
bdp->config[17] = DFLT_FC_DELAY_MSB;
E100_CONFIG(bdp, 17);
changed = true;
}
/* check if *all* fc config options were already set */
if (((bdp->config[19] & CB_CFIG_FC_OPTS) != CB_CFIG_FC_OPTS) ||
(bdp->config[19] & CB_CFIG_TX_FC_DIS)) {
bdp->config[19] |= CB_CFIG_FC_OPTS;
bdp->config[19] &= ~CB_CFIG_TX_FC_DIS;
E100_CONFIG(bdp, 19);
changed = true;
}
} else {
if (bdp->config[16] != DFLT_NO_FC_DELAY_LSB) {
bdp->config[16] = DFLT_NO_FC_DELAY_LSB;
E100_CONFIG(bdp, 16);
changed = true;
}
if (bdp->config[17] != DFLT_NO_FC_DELAY_MSB) {
bdp->config[17] = DFLT_NO_FC_DELAY_MSB;
E100_CONFIG(bdp, 17);
changed = true;
}
/* check if *any* fc config options was already set */
if ((bdp->config[19] & CB_CFIG_FC_OPTS) ||
!(bdp->config[19] & CB_CFIG_TX_FC_DIS)) {
bdp->config[19] &= ~CB_CFIG_FC_OPTS;
bdp->config[19] |= CB_CFIG_TX_FC_DIS;
E100_CONFIG(bdp, 19);
changed = true;
}
bdp->config[16] = DFLT_NO_FC_DELAY_LSB;
bdp->config[17] = DFLT_NO_FC_DELAY_MSB;
bdp->config[19] &= ~CB_CFIG_FC_OPTS;
bdp->config[19] |= CB_CFIG_TX_FC_DIS;
}
E100_CONFIG(bdp, 19);
spin_unlock_bh(&(bdp->config_lock));
return changed;
return;
}
/**
......
......@@ -198,7 +198,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
extern void e100_config_init(struct e100_private *bdp);
extern unsigned char e100_force_config(struct e100_private *bdp);
extern unsigned char e100_config(struct e100_private *bdp);
extern unsigned char e100_config_fc(struct e100_private *bdp);
extern void e100_config_fc(struct e100_private *bdp);
extern void e100_config_promisc(struct e100_private *bdp, unsigned char enable);
extern void e100_config_brdcast_dsbl(struct e100_private *bdp);
extern void e100_config_mulcast_enbl(struct e100_private *bdp,
......
......@@ -93,6 +93,30 @@ Portions (C) 2002 Red Hat, Inc. under the terms of the GNU GPL v2.
* *
**********************************************************************/
/* Change Log
*
* 2.1.6 7/5/02
* o Added device ID support for Dell LOM.
* o Added device ID support for 82511QM mobile nics.
* o Bug fix: ethtool get/set EEPROM routines modified to use byte
* addressing rather than word addressing.
* o Feature: added MDIX mode support for 82550 and up.
* o Bug fix: added reboot notifer to setup WOL settings when
* shutting system down.
* o Cleanup: removed yield() redefinition (Andrew Morton,
* akpm@zip.com.au).
* o Bug fix: flow control now working when link partner is
* autoneg capable but not flow control capable.
* o Bug fix: added check for corrupted EEPROM
* o Bug fix: don't report checksum offloading for the older
* controllers that don't support the feature.
* o Bug fix: calculate cable diagnostics when link goes down
* rather than when queuering /proc file.
* o Cleanup: move mdi_access_lock to local get/set mdi routines.
*
* 2.0.30 5/30/02
*/
#undef __NO_VERSION__
#include <linux/config.h>
......@@ -184,23 +208,24 @@ 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.30-k1"
#define E100_FULL_DRIVER_NAME "Intel(R) PRO/100 Fast Ethernet Adapter - Loadable driver, ver "
const char *e100_version = E100_VERSION;
const char *e100_full_driver_name = E100_FULL_DRIVER_NAME E100_VERSION;
char *e100_short_driver_name = "e100";
char e100_driver_version[]="2.1.6-k1";
const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
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_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
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);
struct notifier_block e100_notifier = {
notifier_call: e100_notify_reboot,
next: NULL,
priority: 0
};
#endif
static void e100_get_mdix_status(struct e100_private *bdp);
/*********************************************************************/
/*! This is a GCC extension to ANSI C.
* See the item "Labeled Elements in Initializers" in the section
......@@ -250,6 +275,7 @@ static void e100_rd_pwa_no(struct e100_private *);
extern u16 e100_eeprom_read(struct e100_private *, u16);
extern void e100_eeprom_write_block(struct e100_private *, u16, u16 *, u16);
extern u16 e100_eeprom_size(struct e100_private *);
u16 e100_eeprom_calculate_chksum(struct e100_private *adapter);
static unsigned char e100_clr_cntrs(struct e100_private *);
static unsigned char e100_load_microcode(struct e100_private *);
......@@ -391,6 +417,8 @@ u32 e100_rx_srv(struct e100_private *, u32, int *);
void e100_polling_tasklet(unsigned long);
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 *);
......@@ -400,7 +428,7 @@ static inline tcb_t *e100_prepare_xmit_buff(struct e100_private *,
static void e100_set_multi_exec(struct net_device *dev);
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION(E100_FULL_DRIVER_NAME E100_VERSION);
MODULE_DESCRIPTION("Intel(R) PRO/100 Network Driver");
MODULE_LICENSE("Dual BSD/GPL");
E100_PARAM(TxDescriptors, "Number of transmit descriptors");
......@@ -580,6 +608,7 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
struct net_device *dev = NULL;
struct e100_private *bdp = NULL;
int rc = 0;
u16 cal_checksum, read_checksum;
dev = alloc_etherdev(sizeof (struct e100_private));
if (dev == NULL) {
......@@ -592,7 +621,8 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
if (first_time) {
first_time = false;
printk(KERN_NOTICE "%s\n", e100_full_driver_name);
printk(KERN_NOTICE "%s - version %s\n",
e100_full_driver_name, e100_driver_version);
printk(KERN_NOTICE "%s\n", e100_copyright);
printk(KERN_NOTICE "\n");
}
......@@ -622,6 +652,10 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
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;
}
......@@ -657,6 +691,16 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
goto err_pci;
}
/* Check if checksum is valid */
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",
e100nics);
rc = -ENODEV;
goto err_pci;
}
dev->irq = pcid->irq;
dev->open = &e100_open;
dev->hard_start_xmit = &e100_xmit_frame;
......@@ -685,6 +729,17 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
printk(KERN_NOTICE
"%s: %s\n", bdp->device->name, e100_get_brand_msg(bdp));
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) < 0) {
printk(KERN_ERR "Failed to create proc directory for %s\n",
......@@ -786,27 +841,33 @@ static struct pci_driver e100_driver = {
id_table: e100_id_table,
probe: e100_found1,
remove: __devexit_p(e100_remove1),
#ifdef CONFIG_PM
#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
e100_init_module(void)
{
return pci_module_init(&e100_driver);
int ret;
ret = pci_module_init(&e100_driver);
#ifdef CONFIG_PM
if(ret >= 0)
register_reboot_notifier(&e100_notifier);
#endif
return ret;
}
static void __exit
e100_cleanup_module(void)
{
#ifdef CONFIG_PM
unregister_reboot_notifier(&e100_notifier);
#endif
pci_unregister_driver(&e100_driver);
}
......@@ -1665,7 +1726,7 @@ e100_watchdog(struct net_device *dev)
if (!netif_running(dev)) {
goto exit;
}
spin_lock_bh(&(bdp->mdi_access_lock));
e100_get_mdix_status(bdp);
/* check if link state has changed */
if (e100_phy_check(bdp)) {
......@@ -1677,11 +1738,38 @@ e100_watchdog(struct net_device *dev)
"Half" : "Full");
e100_config_fc(bdp);
e100_config(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) );
}
}
}
......@@ -1722,8 +1810,6 @@ e100_watchdog(struct net_device *dev)
wmb();
spin_unlock_bh(&(bdp->mdi_access_lock));
/* relaunch watchdog timer in 2 sec */
mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
......@@ -3051,8 +3137,10 @@ e100_print_brd_conf(struct e100_private *bdp)
/* Print the string if checksum Offloading was enabled */
if (bdp->flags & DF_CSUM_OFFLOAD)
printk(KERN_NOTICE " Hardware receive checksums enabled\n");
else
printk(KERN_NOTICE " Hardware receive checksums disabled\n");
else {
if (bdp->rev_id >= D101MA_REV_ID)
printk(KERN_NOTICE " Hardware receive checksums disabled\n");
}
if ((bdp->flags & DF_UCODE_LOADED))
printk(KERN_NOTICE " cpu cycle saver enabled\n");
......@@ -3151,6 +3239,13 @@ e100_isolate_driver(struct e100_private *bdp)
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);
......@@ -3382,9 +3477,7 @@ e100_ethtool_get_settings(struct net_device *dev, struct ifreq *ifr)
}
if (bdp->speed_duplex_caps & SUPPORTED_MII) {
spin_lock_bh(&(bdp->mdi_access_lock));
e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &advert);
spin_unlock_bh(&(bdp->mdi_access_lock));
if (advert & ADVERTISE_10HALF)
ecmd.advertising |= ADVERTISED_10baseT_Half;
......@@ -3495,9 +3588,7 @@ e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr)
bdp = dev->priv;
info.cmd = ETHTOOL_GLINK;
spin_lock_bh(&(bdp->mdi_access_lock));
info.data = e100_get_link_state(bdp);
spin_unlock_bh(&(bdp->mdi_access_lock));
if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
return -EFAULT;
......@@ -3569,7 +3660,7 @@ e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
bdp = dev->priv;
strncpy(info.driver, e100_short_driver_name, sizeof (info.driver) - 1);
strncpy(info.version, e100_version, sizeof (info.version) - 1);
strncpy(info.version, e100_driver_version, sizeof (info.version) - 1);
strncpy(info.fw_version, e100_get_brand_msg(bdp),
sizeof (info.fw_version) - 1);
strncpy(info.bus_info, bdp->pdev->slot_name,
......@@ -3595,8 +3686,9 @@ e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr)
struct ethtool_eeprom ecmd;
u16 eeprom_data[256];
u16 *usr_eeprom_ptr;
u16 word_length, word_offset;
int i;
u16 first_word, last_word;
int i, max_len;
void *ptr;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
......@@ -3609,39 +3701,49 @@ e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr)
usr_eeprom_ptr =
(u16 *) (ifr->ifr_data + offsetof(struct ethtool_eeprom, data));
word_offset = (ecmd.offset >> 1);
if (word_offset >= bdp->eeprom_size)
return -EFAULT;
max_len = bdp->eeprom_size * 2;
if ((ecmd.offset + ecmd.len) > max_len)
ecmd.len = (max_len - ecmd.offset);
word_length =
min_t(u32, (ecmd.len >> 1), (bdp->eeprom_size - word_offset));
first_word = ecmd.offset >> 1;
last_word = (ecmd.offset + ecmd.len - 1) >> 1;
if (first_word >= bdp->eeprom_size)
return -EFAULT;
if (ecmd.cmd == ETHTOOL_GEEPROM) {
for (i = word_offset; i < (word_length + word_offset); i++)
eeprom_data[i] = e100_eeprom_read(bdp, i);
for(i = 0; i <= (last_word - first_word); i++)
eeprom_data[i] = e100_eeprom_read(bdp, first_word + i);
ecmd.len = (word_length << 1);
ecmd.magic = E100_EEPROM_MAGIC;
if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
return -EFAULT;
if (copy_to_user(usr_eeprom_ptr, &(eeprom_data[word_offset]),
(ecmd.len << 1)))
if (copy_to_user(usr_eeprom_ptr, eeprom_data, ecmd.len))
return -EFAULT;
} else {
if (ecmd.magic != E100_EEPROM_MAGIC)
return -EFAULT;
if (copy_from_user(&(eeprom_data[word_offset]), usr_eeprom_ptr,
(ecmd.len << 1)))
return -EFAULT;
e100_eeprom_write_block(bdp, word_offset,
&(eeprom_data[word_offset]),
word_length);
ptr = (void *)eeprom_data;
if(ecmd.offset & 1) {
/* need modification of first changed EEPROM word */
/* only the second byte of the word is being modified */
eeprom_data[0] = e100_eeprom_read(bdp, first_word);
ptr++;
}
if((ecmd.offset + ecmd.len) & 1) {
/* need modification of last changed EEPROM word */
/* only the first byte of the word is being modified */
eeprom_data[last_word - first_word] =
e100_eeprom_read(bdp, last_word);
}
if(copy_from_user(ptr, usr_eeprom_ptr, ecmd.len))
return -EFAULT;
ecmd.len = (word_length << 1);
e100_eeprom_write_block(bdp, first_word, eeprom_data,
last_word - first_word + 1);
if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
return -EFAULT;
......@@ -3663,12 +3765,9 @@ e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr)
static void
e100_led_control(struct e100_private *bdp, u16 led_mdi_op)
{
spin_lock_bh(&bdp->mdi_access_lock);
e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
bdp->phy_addr, led_mdi_op);
spin_unlock_bh(&bdp->mdi_access_lock);
}
/**
* e100_led_blink_callback
......@@ -3965,10 +4064,8 @@ e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGMIIREG:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
spin_lock_bh(&(bdp->mdi_access_lock));
e100_mdi_read(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr,
&(data_ptr->val_out));
spin_unlock_bh(&(bdp->mdi_access_lock));
break;
case SIOCSMIIREG:
......@@ -3977,10 +4074,8 @@ e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (netif_running(dev)) {
return -EBUSY;
}
spin_lock_bh(&(bdp->mdi_access_lock));
e100_mdi_write(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr,
data_ptr->val_in);
spin_unlock_bh(&(bdp->mdi_access_lock));
break;
default:
......@@ -4149,17 +4244,22 @@ e100_non_tx_background(unsigned long ptr)
#ifdef CONFIG_PM
static int
e100_save_state(struct pci_dev *pcid, u32 state)
e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
{
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;
struct pci_dev *pdev = NULL;
switch(event) {
case SYS_DOWN:
case SYS_HALT:
case SYS_POWER_OFF:
pci_for_each_dev(pdev) {
if(pci_dev_driver(pdev) == &e100_driver) {
/* If net_device struct is allocated? */
if (pci_get_drvdata(pdev))
e100_suspend(pdev, 3);
}
}
}
return NOTIFY_DONE;
}
static int
......@@ -4169,7 +4269,7 @@ e100_suspend(struct pci_dev *pcid, u32 state)
struct e100_private *bdp = netdev->priv;
e100_isolate_driver(bdp);
e100_save_state(pcid, state);
pci_save_state(pcid, bdp->pci_state);
/* If wol is enabled */
#ifdef ETHTOOL_GWOL
......@@ -4218,12 +4318,126 @@ e100_resume(struct pci_dev *pcid)
return 0;
}
static int
e100_enable_wake(struct pci_dev *pcid, u32 state, int enable)
#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)
{
/* Driver doesn't need to do anything because it will enable */
/* wol when suspended. */
/* Actually, PCI PM does NOT call this entry. */
return 0;
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;
}
}
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;
}
static void e100_hwi_restore(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;
}
#endif /* CONFIG_PM */
......@@ -96,6 +96,7 @@ e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data)
int e100_retry;
u32 temp_val;
spin_lock_bh(&bdp->mdi_access_lock);
temp_val = (((u32) data) | (reg_addr << 16) |
(phy_addr << 21) | (MDI_WRITE << 26));
writel(temp_val, &bdp->scb->scb_mdi_cntrl);
......@@ -111,6 +112,7 @@ e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data)
udelay(20);
e100_retry--;
}
spin_unlock_bh(&bdp->mdi_access_lock);
}
/*
......@@ -138,6 +140,7 @@ e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data)
int e100_retry;
u32 temp_val;
spin_lock_bh(&bdp->mdi_access_lock);
/* Issue the read command to the MDI control register. */
temp_val = ((reg_addr << 16) | (phy_addr << 21) | (MDI_READ << 26));
writel(temp_val, &bdp->scb->scb_mdi_cntrl);
......@@ -156,6 +159,7 @@ e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data)
// return the lower word
*data = (u16) readl(&bdp->scb->scb_mdi_cntrl);
spin_unlock_bh(&bdp->mdi_access_lock);
}
static unsigned char __devinit
......@@ -657,8 +661,6 @@ e100_force_speed_duplex(struct e100_private *bdp)
bdp->flags |= DF_SPEED_FORCED;
spin_lock_bh(&(bdp->mdi_access_lock));
e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
control &= ~BMCR_ANENABLE;
......@@ -702,14 +704,10 @@ e100_force_speed_duplex(struct e100_private *bdp)
time_after(jiffies, expires)) {
break;
} else {
spin_unlock_bh(&(bdp->mdi_access_lock));
yield();
spin_lock_bh(&(bdp->mdi_access_lock));
}
} while (true);
spin_unlock_bh(&(bdp->mdi_access_lock));
}
/*
......@@ -753,7 +751,12 @@ e100_set_fc(struct e100_private *bdp)
if (ad_reg & NWAY_AD_FC_SUPPORTED)
bdp->flags |= DF_LINK_FC_CAP;
else
bdp->flags &= ~DF_LINK_FC_CAP;
/* If link partner is capable of autoneg, but */
/* not capable of flow control, Received PAUSE */
/* frames are still honored, i.e., */
/* transmitted frames would be paused */
/* by incoming PAUSE frames */
bdp->flags |= DF_LINK_FC_TX_ONLY;
} else {
bdp->flags &= ~DF_LINK_FC_CAP;
......@@ -821,8 +824,6 @@ e100_auto_neg(struct e100_private *bdp, unsigned char force_restart)
bdp->flags &= ~DF_SPEED_FORCED;
spin_lock_bh(&(bdp->mdi_access_lock));
e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
......@@ -848,25 +849,30 @@ e100_auto_neg(struct e100_private *bdp, unsigned char force_restart)
time_after(jiffies, expires) ) {
goto exit;
} else {
spin_unlock_bh(&(bdp->mdi_access_lock));
yield();
spin_lock_bh(&(bdp->mdi_access_lock));
}
} while (true);
}
exit:
e100_find_speed_duplex(bdp);
spin_unlock_bh(&(bdp->mdi_access_lock));
}
void
e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart)
{
if (bdp->params.e100_speed_duplex == E100_AUTONEG) {
if (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);
e100_auto_neg(bdp, force_restart);
} else {
if (bdp->rev_id >= D102_REV_ID)
/* Disable MDI/MDI-X auto switching */
e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
MDI_MDIX_RESET_ALL_MASK);
e100_force_speed_duplex(bdp);
}
......
......@@ -124,6 +124,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define NSC_CONG_CONTROL_REG 0x17 /* National (TX) congestion control */
#define NSC_SPEED_IND_REG 0x19 /* National (TX) speed indication */
#define HWI_CONTROL_REG 0x1D /* HWI Control register */
/* MDI/MDI-X Control Register bit definitions */
#define MDI_MDIX_RES_TIMER BIT_0_3 /* minimum slot time for resolution timer */
#define MDI_MDIX_CONFIG_IS_OK BIT_4 /* 1 = resolution algorithm completes OK */
#define MDI_MDIX_STATUS BIT_5 /* 1 = MDIX (croos over), 0 = MDI (straight through) */
#define MDI_MDIX_SWITCH BIT_6 /* 1 = Forces to MDIX, 0 = Forces to MDI */
#define MDI_MDIX_AUTO_SWITCH_ENABLE BIT_7 /* 1 = MDI/MDI-X feature enabled */
#define MDI_MDIX_CONCT_CONFIG BIT_8 /* Sets the MDI/MDI-X connectivity configuration (test prupose only) */
#define MDI_MDIX_CONCT_TEST_ENABLE BIT_9 /* 1 = Enables connectivity testing */
#define MDI_MDIX_RESET_ALL_MASK 0x0000
/* HWI Control Register bit definitions */
#define HWI_TEST_DISTANCE BIT_0_8 /* distance to cable problem */
#define HWI_TEST_HIGHZ_PROBLEM BIT_9 /* 1 = Open Circuit */
#define HWI_TEST_LOWZ_PROBLEM BIT_10 /* 1 = Short Circuit */
#define HWI_TEST_RESERVED (BIT_11 | BIT_12) /* reserved */
#define HWI_TEST_EXECUTE BIT_13 /* 1 = Execute the HWI test on the PHY */
#define HWI_TEST_ABILITY BIT_14 /* 1 = test passed */
#define HWI_TEST_ENABLE BIT_15 /* 1 = Enables the HWI feature */
#define HWI_RESET_ALL_MASK 0x0000
/* ############Start of 82555 specific defines################## */
/* Intel 82555 specific registers */
......
......@@ -106,8 +106,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
static struct proc_dir_entry *adapters_proc_dir = 0;
/* externs from e100_main.c */
extern const char *e100_short_driver_name;
extern const char *e100_version;
extern char e100_short_driver_name[];
extern char e100_driver_version[];
extern struct net_device_stats *e100_get_stats(struct net_device *dev);
extern char *e100_get_brand_msg(struct e100_private *bdp);
extern void e100_mdi_write(struct e100_private *, u32, u32, u16);
......@@ -191,7 +191,7 @@ read_descr(char *page, char **start, off_t off, int count, int *eof, void *data)
struct e100_private *bdp = data;
int len;
len = sprintf(page, "%s\n", e100_get_brand_msg(bdp));
len = sprintf(page, "%s\n", bdp->id_string);
return generic_read(page, start, off, count, eof, len);
}
......@@ -223,23 +223,15 @@ read_part_number(char *page, char **start, off_t off,
static void
set_led(struct e100_private *bdp, u16 led_mdi_op)
{
spin_lock_bh(&bdp->mdi_access_lock);
e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
bdp->phy_addr, led_mdi_op);
spin_unlock_bh(&bdp->mdi_access_lock);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(MDI_SLEEP_TIME);
spin_lock_bh(&bdp->mdi_access_lock);
/* turn led ownership to the chip */
e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
bdp->phy_addr, PHY_82555_LED_NORMAL_CONTROL);
spin_unlock_bh(&bdp->mdi_access_lock);
}
static int
......@@ -351,6 +343,7 @@ read_info(char *page, char **start, off_t off, int count, int *eof, void *data)
}
#ifdef E100_EOU
#ifdef MODULE
/**********************
* parameter entries
**********************/
......@@ -677,6 +670,7 @@ static e100_proc_entry e100_proc_params[] = {
{"PollingMaxWork.val", read_gen_prm, 0, bdp_prm_off(PollingMaxWork)},
{"", 0, 0, 0}
};
#endif /* MODULE */
#endif /* E100_EOU */
static struct proc_dir_entry * __devinit
......@@ -706,6 +700,7 @@ create_proc_rw(char *name, void *data, struct proc_dir_entry *parent,
}
#ifdef E100_EOU
#ifdef MODULE
static int __devinit
create_proc_param_subdir(struct e100_private *bdp,
struct proc_dir_entry *dev_dir)
......@@ -755,7 +750,8 @@ remove_proc_param_subdir(struct proc_dir_entry *parent)
remove_proc_entry("LoadParameters", parent);
}
#endif /* E100_EOU */
#endif /* MODULE */
#endif
void
e100_remove_proc_subdir(struct e100_private *bdp)
......@@ -781,9 +777,11 @@ e100_remove_proc_subdir(struct e100_private *bdp)
remove_proc_entry(pe->name, bdp->proc_parent);
}
#ifdef E100_EOU
#ifdef E100_EOU
#ifdef MODULE
remove_proc_param_subdir(bdp->proc_parent);
#endif
#endif
remove_proc_entry(bdp->device->name, adapters_proc_dir);
bdp->proc_parent = NULL;
}
......@@ -844,12 +842,14 @@ e100_create_proc_subdir(struct e100_private *bdp)
}
}
#ifdef E100_EOU
#ifdef E100_EOU
#ifdef MODULE
if (create_proc_param_subdir(bdp, dev_dir)) {
e100_remove_proc_subdir(bdp);
return -ENOMEM;
}
#endif
#endif
return 0;
}
......
......@@ -125,6 +125,7 @@ enum e100_device_type {
E100_82559_LOM,
E100_82559_LOM_AOL,
E100_82559_LOM_AOL2,
E100_82559_LOM_DELL,
E100_IBM_MDS,
E100_CMPQ_S,
E100_PROVE_DA,
......@@ -132,7 +133,8 @@ enum e100_device_type {
E100_PROVE_LOM,
E100_PROVE_NET,
E100_82562,
E100_ALL_BOARDS,
E100_82551QM,
E100_ALL_BOARDS
};
struct e100_vendor_info e100_vendor_info_array[] = {
......@@ -147,6 +149,7 @@ struct e100_vendor_info e100_vendor_info_array[] = {
{ E100_BRD_100, "Intel(R) PRO/100+ PCI Adapter"},
{ E100_BRD_100M, "Intel(R) PRO/100+ Management Adapter"},
{ E100_BRD_AOL2, "Intel(R) PRO/100+ Alert on LAN* 2 Management Adapter"},
{ E100_82559_LOM_DELL, "Intel(R) 8255x Based Network Connection"},
{ E100_BRD_AOL, "Intel(R) PRO/100+ Alert on LAN* Management Adapter"},
{ E100_PROS_M, "Intel(R) PRO/100 S Management Adapter"},
{ E100_PROS_AM, "Intel(R) PRO/100 S Advanced Management Adapter"},
......@@ -186,6 +189,7 @@ struct e100_vendor_info e100_vendor_info_array[] = {
{ E100_PROVE_LOM, "Intel(R) PRO/100 VE Network ConnectionPLC LOM" },
{ E100_PROVE_NET, "Intel(R) PRO/100 VE Network Connection"},
{ E100_82562, "Intel(R)82562 based Fast Ethernet Connection"},
{ E100_82551QM, "Intel(R) PRO/100 M Mobile Connection"},
{ E100_ALL_BOARDS, "Intel(R) 8255x-based Ethernet Adapter"},
{0,NULL}
};
......@@ -309,6 +313,7 @@ static struct pci_device_id e100_id_table[] __devinitdata = {
{0x8086, 0x1229, 0x0E11, 0xB144, 0, 0, E100_CMPQ_S},
{0x8086, 0x1229, 0x0E11, 0xB163, 0, 0, E100_CMPQ_S},
{0x8086, 0x1229, 0x0E11, 0xB164, 0, 0, E100_CMPQ_S},
{0x8086, 0x1229, 0x1028, PCI_ANY_ID, 0, 0, E100_82559_LOM_DELL},
{0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
{0x8086, 0x2449, 0x1014, 0x0265, 0, 0, E100_PROVE_D},
......@@ -324,7 +329,11 @@ static struct pci_device_id e100_id_table[] __devinitdata = {
{0x8086, 0x2449, 0x0E11, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
{0x8086, 0x2449, 0x1014, PCI_ANY_ID, 0, 0, E100_PROVE_D},
{0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
{0x8086, 0x1059, 0x1179, 0x0005, 0, 0, E100_82551QM},
{0x8086, 0x1059, 0x1033, 0x8191, 0, 0, E100_82551QM},
{0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82551QM},
{0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
{0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
{0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
......
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