summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@redhat.com>2003-05-25 11:49:53 -0400
committerJeff Garzik <jgarzik@redhat.com>2003-05-25 11:49:53 -0400
commit3b9fb4e8dc9b6080805ce397c74ef1f0f7cda076 (patch)
treefba64b9463c149d01f1c39de9585b100661718b2
parentdc2f9764e8784817355504b5a78bed08578e2d46 (diff)
parent26da9f9f2dbf72da5c90f28f50d1821405c040e2 (diff)
Merge redhat.com:/garz/repo/linus-2.5
into redhat.com:/garz/repo/net-drivers-2.5
-rw-r--r--drivers/net/arcnet/arcnet.c5
-rw-r--r--drivers/net/e100/e100.h30
-rw-r--r--drivers/net/e100/e100_main.c301
-rw-r--r--drivers/net/e100/e100_phy.c7
-rw-r--r--drivers/net/e100/e100_test.c155
-rw-r--r--drivers/net/e1000/Makefile2
-rw-r--r--drivers/net/e1000/e1000.h5
-rw-r--r--drivers/net/e1000/e1000_ethtool.c959
-rw-r--r--drivers/net/e1000/e1000_hw.c23
-rw-r--r--drivers/net/e1000/e1000_hw.h8
-rw-r--r--drivers/net/e1000/e1000_main.c145
-rw-r--r--drivers/net/fc/iph5526.c18
-rw-r--r--drivers/net/fec.c18
-rw-r--r--drivers/net/fmv18x.c6
-rw-r--r--drivers/net/hamradio/scc.c7
-rw-r--r--drivers/net/myri_sbus.c4
-rw-r--r--drivers/net/seeq8005.c9
-rw-r--r--drivers/net/sunqe.c1
-rw-r--r--drivers/net/tokenring/lanstreamer.c5
-rw-r--r--drivers/net/tulip/de4x5.c2
-rw-r--r--drivers/net/wan/lmc/lmc_main.c8
-rw-r--r--include/linux/arcdevice.h2
22 files changed, 1425 insertions, 295 deletions
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 3a77c6b81664..199bcfbdc1cd 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -671,7 +671,7 @@ static void arcnet_timeout(struct net_device *dev)
* interrupts. Establish which device needs attention, and call the correct
* chipset interrupt handler.
*/
-void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct arcnet_local *lp;
@@ -696,7 +696,7 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ACOMMAND(CFLAGScmd | RESETclear);
AINTMASK(0);
spin_unlock(&arcnet_lock);
- return;
+ return IRQ_HANDLED;
}
BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
@@ -864,6 +864,7 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
AINTMASK(lp->intmask);
spin_unlock(&arcnet_lock);
+ return IRQ_RETVAL(didsomething);
}
diff --git a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h
index aa58407de02d..188bd6e19a21 100644
--- a/drivers/net/e100/e100.h
+++ b/drivers/net/e100/e100.h
@@ -60,7 +60,14 @@
#include <linux/if_vlan.h>
#include <linux/mii.h>
-#define E100_REGS_LEN 1
+#define E100_CABLE_UNKNOWN 0
+#define E100_CABLE_OK 1
+#define E100_CABLE_OPEN_NEAR 2 /* Open Circuit Near End */
+#define E100_CABLE_OPEN_FAR 3 /* Open Circuit Far End */
+#define E100_CABLE_SHORT_NEAR 4 /* Short Circuit Near End */
+#define E100_CABLE_SHORT_FAR 5 /* Short Circuit Far End */
+
+#define E100_REGS_LEN 2
/*
* Configure parameters for buffers per controller.
* If the machine this is being used on is a faster machine (i.e. > 150MHz)
@@ -105,8 +112,6 @@
#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 */
@@ -942,7 +947,6 @@ struct e100_private {
#ifdef CONFIG_PM
u32 pci_state[16];
#endif
- char ifname[IFNAMSIZ];
#ifdef E100_CU_DEBUG
u8 last_cmd;
u8 last_sub_cmd;
@@ -956,7 +960,10 @@ struct e100_private {
#define E100_SPEED_100_FULL 4
/********* function prototypes *************/
+extern int e100_open(struct net_device *);
+extern int e100_close(struct net_device *);
extern void e100_isolate_driver(struct e100_private *bdp);
+extern unsigned char e100_hw_init(struct e100_private *);
extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd);
extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb);
extern void e100_free_non_tx_cmd(struct e100_private *bdp,
@@ -981,14 +988,13 @@ extern unsigned char e100_cu_unknown_state(struct e100_private *bdp);
#define TEST_TIMEOUT 0x08
enum test_offsets {
- E100_EEPROM_TEST_FAIL = 0,
- E100_CHIP_TIMEOUT,
- E100_ROM_TEST_FAIL,
- E100_REG_TEST_FAIL,
- E100_MAC_TEST_FAIL,
- E100_LPBK_MAC_FAIL,
- E100_LPBK_PHY_FAIL,
- E100_MAX_TEST_RES
+ test_link,
+ test_eeprom,
+ test_self_test,
+ test_loopback_mac,
+ test_loopback_phy,
+ cable_diag,
+ max_test_res, /* must be last */
};
#endif
diff --git a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
index 070c9fb9f0f4..bdaa1743ea46 100644
--- a/drivers/net/e100/e100_main.c
+++ b/drivers/net/e100/e100_main.c
@@ -46,6 +46,24 @@
/* Change Log
*
+ * 2.3.13 05/08/03
+ * o Feature remove: /proc/net/PRO_LAN_Adapters support gone completely
+ * o Feature remove: IDIAG support (use ethtool -t instead)
+ * o Cleanup: fixed spelling mistakes found by community
+ * o Feature add: ethtool cable diag test
+ * o Feature add: ethtool parameter support (ring size, xsum, flow ctrl)
+ * o Cleanup: move e100_asf_enable under CONFIG_PM to avoid warning
+ * [Stephen Rothwell (sfr@canb.auug.org.au)]
+ * o Bug fix: don't call any netif_carrier_* until netdev registered.
+ * [Andrew Morton (akpm@digeo.com)]
+ * o Cleanup: replace (skb->len - skb->data_len) with skb_headlen(skb)
+ * [jmorris@intercode.com.au]
+ * o Bug fix: cleanup of Tx skbs after running ethtool diags
+ * o Bug fix: incorrect reporting of ethtool diag overall results
+ * o Bug fix: must hold xmit_lock before stopping queue in ethtool
+ * operations that require reset h/w and driver structures.
+ * o Bug fix: statistic command failure would stop statistic collection.
+ *
* 2.2.21 02/11/03
* o Removed marketing brand strings. Instead, Using generic string
* "Intel(R) PRO/100 Network Connection" for all adapters.
@@ -61,21 +79,6 @@
* 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
*/
#include <linux/config.h>
@@ -121,14 +124,13 @@ extern void e100_config_wol(struct e100_private *bdp);
extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags);
static int e100_ethtool_test(struct net_device *, struct ifreq *);
static int e100_ethtool_gstrings(struct net_device *, struct ifreq *);
-static char *test_strings[] = {
- "E100_EEPROM_TEST_FAIL",
- "E100_CHIP_TIMEOUT",
- "E100_ROM_TEST_FAIL",
- "E100_REG_TEST_FAIL",
- "E100_MAC_TEST_FAIL",
- "E100_LPBK_MAC_FAIL",
- "E100_LPBK_PHY_FAIL"
+static char test_strings[][ETH_GSTRING_LEN] = {
+ "Link test (on/offline)",
+ "Eeprom test (on/offline)",
+ "Self test (offline)",
+ "Mac loopback (offline)",
+ "Phy loopback (offline)",
+ "Cable diagnostic (offline)"
};
static int e100_ethtool_led_blink(struct net_device *, struct ifreq *);
@@ -139,10 +141,10 @@ static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,
nxmit_cb_entry_t *);
static void e100_free_nontx_list(struct e100_private *);
static void e100_non_tx_background(unsigned long);
-
+static inline void e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb);
/* Global Data structures and variables */
char e100_copyright[] __devinitdata = "Copyright (c) 2003 Intel Corporation";
-char e100_driver_version[]="2.2.21-k1";
+char e100_driver_version[]="2.3.13-k1";
const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
char e100_short_driver_name[] = "e100";
static int e100nics = 0;
@@ -155,6 +157,7 @@ static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
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);
+static unsigned char e100_asf_enabled(struct e100_private *bdp);
struct notifier_block e100_notifier_reboot = {
.notifier_call = e100_notify_reboot,
.next = NULL,
@@ -182,8 +185,6 @@ struct notifier_block e100_notifier_reboot = {
static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *);
static u8 e100_D102_check_checksum(rfd_t *);
static int e100_ioctl(struct net_device *, struct ifreq *, int);
-static int e100_open(struct net_device *);
-static int e100_close(struct net_device *);
static int e100_change_mtu(struct net_device *, int);
static int e100_xmit_frame(struct sk_buff *, struct net_device *);
static unsigned char e100_init(struct e100_private *);
@@ -193,7 +194,6 @@ struct net_device_stats *e100_get_stats(struct net_device *);
static irqreturn_t 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 *);
static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
static u8 e100_sw_init(struct e100_private *);
@@ -215,7 +215,6 @@ 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 *);
-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);
@@ -228,7 +227,6 @@ 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, 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
@@ -616,6 +614,10 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
goto err_dealloc;
}
+ if ((rc = register_netdev(dev)) != 0) {
+ goto err_pci;
+ }
+
if (((bdp->pdev->device > 0x1030)
&& (bdp->pdev->device < 0x103F))
|| ((bdp->pdev->device >= 0x1050)
@@ -645,7 +647,7 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
printk(KERN_ERR "e100: Failed to initialize, instance #%d\n",
e100nics);
rc = -ENODEV;
- goto err_pci;
+ goto err_unregister_netdev;
}
/* Check if checksum is valid */
@@ -655,7 +657,7 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n",
e100nics);
rc = -ENODEV;
- goto err_pci;
+ goto err_unregister_netdev;
}
dev->vlan_rx_register = e100_vlan_rx_register;
@@ -679,12 +681,6 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
e100_get_speed_duplex_caps(bdp);
- if ((rc = register_netdev(dev)) != 0) {
- goto err_pci;
- }
- memcpy(bdp->ifname, dev->name, IFNAMSIZ);
- bdp->ifname[IFNAMSIZ-1] = 0;
-
printk(KERN_NOTICE
"e100: %s: %s\n",
bdp->device->name, "Intel(R) PRO/100 Network Connection");
@@ -709,6 +705,8 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
goto out;
+err_unregister_netdev:
+ unregister_netdev(dev);
err_pci:
iounmap(bdp->scb);
pci_release_regions(pcid);
@@ -974,7 +972,7 @@ e100_set_bool_option(struct e100_private *bdp, int val, u32 mask,
}
}
-static int
+int
e100_open(struct net_device *dev)
{
struct e100_private *bdp;
@@ -1033,7 +1031,7 @@ exit:
return rc;
}
-static int
+int
e100_close(struct net_device *dev)
{
struct e100_private *bdp = dev->priv;
@@ -1285,10 +1283,8 @@ e100_init(struct e100_private *bdp)
/* read NIC's part number */
e100_rd_pwa_no(bdp);
- if (!e100_hw_init(bdp)) {
- printk(KERN_ERR "e100: hw init failed\n");
+ if (!e100_hw_init(bdp))
return false;
- }
/* Interrupts are enabled after device reset */
e100_disable_clear_intr(bdp);
@@ -1330,6 +1326,8 @@ e100_sw_init(struct e100_private *bdp)
spin_lock_init(&(bdp->bd_non_tx_lock));
spin_lock_init(&(bdp->config_lock));
spin_lock_init(&(bdp->mdi_access_lock));
+ /* Initialize configuration data */
+ e100_config_init(bdp);
return 1;
}
@@ -1384,11 +1382,11 @@ e100_tco_workaround(struct e100_private *bdp)
* true - If the adapter was initialized
* false - If the adapter failed initialization
*/
-unsigned char __devinit
+unsigned char
e100_hw_init(struct e100_private *bdp)
{
if (!e100_phy_init(bdp))
- return false;
+ goto err;
e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
@@ -1398,27 +1396,25 @@ e100_hw_init(struct e100_private *bdp)
/* Load the CU BASE (set to 0, because we use linear mode) */
if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
- return false;
+ goto err;
if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
- return false;
+ goto err;
/* Load interrupt microcode */
if (e100_load_microcode(bdp)) {
bdp->flags |= DF_UCODE_LOADED;
}
- e100_config_init(bdp);
- if (!e100_config(bdp)) {
- return false;
- }
+ if (!e100_config(bdp))
+ goto err;
if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr))
- return false;
+ goto err;
/* Clear the internal counters */
if (!e100_clr_cntrs(bdp))
- return false;
+ goto err;
/* Change for 82558 enhancement */
/* If 82558/9 and if the user has enabled flow control, set up the
@@ -1431,6 +1427,9 @@ e100_hw_init(struct e100_private *bdp)
}
return true;
+err:
+ printk(KERN_ERR "e100: hw init failed\n");
+ return false;
}
/**
@@ -1591,9 +1590,22 @@ e100_alloc_tcb_pool(struct e100_private *bdp)
void
e100_free_tcb_pool(struct e100_private *bdp)
{
+ tcb_t *tcb;
+ int i;
+ /* Return tx skbs */
+ for (i = 0; i < bdp->params.TxDescriptors; i++) {
+ tcb = bdp->tcb_pool.data;
+ tcb += bdp->tcb_pool.head;
+ e100_tx_skb_free(bdp, tcb);
+ if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail)
+ break;
+ bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head);
+ }
pci_free_consistent(bdp->pdev,
sizeof (tcb_t) * bdp->params.TxDescriptors,
bdp->tcb_pool.data, bdp->tcb_phys);
+ bdp->tcb_pool.head = 0;
+ bdp->tcb_pool.tail = 1;
bdp->tcb_phys = 0;
}
@@ -1747,12 +1759,10 @@ e100_watchdog(struct net_device *dev)
e100_set_multi(dev);
}
}
-
- /* Update the statistics needed by the upper interface */
- /* This should be the last statistic related command
- * as it's async. now */
- e100_dump_stats_cntrs(bdp);
}
+ /* Issue command to dump statistics from device. */
+ /* Check for command completion on next watchdog timer. */
+ e100_dump_stats_cntrs(bdp);
wmb();
@@ -2544,6 +2554,7 @@ e100_update_stats(struct e100_private *bdp)
pcmd_complete = e100_cmd_complete_location(bdp);
if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) &&
*pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) {
+ *pcmd_complete = 0;
return false;
}
@@ -3041,23 +3052,6 @@ e100_isolate_driver(struct e100_private *bdp)
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
e100_tcb_add_C_bit(struct e100_private *bdp)
{
@@ -3213,6 +3207,144 @@ e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
case ETHTOOL_PHYS_ID:
rc = e100_ethtool_led_blink(dev,ifr);
break;
+#ifdef ETHTOOL_GRINGPARAM
+ case ETHTOOL_GRINGPARAM: {
+ struct ethtool_ringparam ering;
+ struct e100_private *bdp = dev->priv;
+ memset((void *) &ering, 0, sizeof(ering));
+ ering.rx_max_pending = E100_MAX_RFD;
+ ering.tx_max_pending = E100_MAX_TCB;
+ ering.rx_pending = bdp->params.RxDescriptors;
+ ering.tx_pending = bdp->params.TxDescriptors;
+ rc = copy_to_user(ifr->ifr_data, &ering, sizeof(ering))
+ ? -EFAULT : 0;
+ return rc;
+ }
+#endif
+#ifdef ETHTOOL_SRINGPARAM
+ case ETHTOOL_SRINGPARAM: {
+ struct ethtool_ringparam ering;
+ struct e100_private *bdp = dev->priv;
+ if (copy_from_user(&ering, ifr->ifr_data, sizeof(ering)))
+ return -EFAULT;
+ if (ering.rx_pending > E100_MAX_RFD
+ || ering.rx_pending < E100_MIN_RFD)
+ return -EINVAL;
+ if (ering.tx_pending > E100_MAX_TCB
+ || ering.tx_pending < E100_MIN_TCB)
+ return -EINVAL;
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ /* Use new values to open interface */
+ bdp->params.RxDescriptors = ering.rx_pending;
+ bdp->params.TxDescriptors = ering.tx_pending;
+ e100_hw_init(bdp);
+ e100_open(dev);
+ }
+ else {
+ bdp->params.RxDescriptors = ering.rx_pending;
+ bdp->params.TxDescriptors = ering.tx_pending;
+ }
+ return 0;
+ }
+#endif
+#ifdef ETHTOOL_GPAUSEPARAM
+ case ETHTOOL_GPAUSEPARAM: {
+ struct ethtool_pauseparam epause;
+ struct e100_private *bdp = dev->priv;
+ memset((void *) &epause, 0, sizeof(epause));
+ if ((bdp->flags & IS_BACHELOR)
+ && (bdp->params.b_params & PRM_FC)) {
+ epause.autoneg = 1;
+ if (bdp->flags && DF_LINK_FC_CAP) {
+ epause.rx_pause = 1;
+ epause.tx_pause = 1;
+ }
+ if (bdp->flags && DF_LINK_FC_TX_ONLY)
+ epause.tx_pause = 1;
+ }
+ rc = copy_to_user(ifr->ifr_data, &epause, sizeof(epause))
+ ? -EFAULT : 0;
+ return rc;
+ }
+#endif
+#ifdef ETHTOOL_SPAUSEPARAM
+ case ETHTOOL_SPAUSEPARAM: {
+ struct ethtool_pauseparam epause;
+ struct e100_private *bdp = dev->priv;
+ if (!(bdp->flags & IS_BACHELOR))
+ return -EINVAL;
+ if (copy_from_user(&epause, ifr->ifr_data, sizeof(epause)))
+ return -EFAULT;
+ if (epause.autoneg == 1)
+ bdp->params.b_params |= PRM_FC;
+ else
+ bdp->params.b_params &= ~PRM_FC;
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ e100_hw_init(bdp);
+ e100_open(dev);
+ }
+ return 0;
+ }
+#endif
+#ifdef ETHTOOL_GRXCSUM
+ case ETHTOOL_GRXCSUM:
+ case ETHTOOL_GTXCSUM:
+ case ETHTOOL_GSG:
+ { struct ethtool_value eval;
+ struct e100_private *bdp = dev->priv;
+ memset((void *) &eval, 0, sizeof(eval));
+ if ((ecmd.cmd == ETHTOOL_GRXCSUM)
+ && (bdp->params.b_params & PRM_XSUMRX))
+ eval.data = 1;
+ else
+ eval.data = 0;
+ rc = copy_to_user(ifr->ifr_data, &eval, sizeof(eval))
+ ? -EFAULT : 0;
+ return rc;
+ }
+#endif
+#ifdef ETHTOOL_SRXCSUM
+ case ETHTOOL_SRXCSUM:
+ case ETHTOOL_STXCSUM:
+ case ETHTOOL_SSG:
+ { struct ethtool_value eval;
+ struct e100_private *bdp = dev->priv;
+ if (copy_from_user(&eval, ifr->ifr_data, sizeof(eval)))
+ return -EFAULT;
+ if (ecmd.cmd == ETHTOOL_SRXCSUM) {
+ if (eval.data == 1) {
+ if (bdp->rev_id >= D101MA_REV_ID)
+ bdp->params.b_params |= PRM_XSUMRX;
+ else
+ return -EINVAL;
+ } else {
+ if (bdp->rev_id >= D101MA_REV_ID)
+ bdp->params.b_params &= ~PRM_XSUMRX;
+ else
+ return 0;
+ }
+ } else {
+ if (eval.data == 1)
+ return -EINVAL;
+ else
+ return 0;
+ }
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ e100_hw_init(bdp);
+ e100_open(dev);
+ }
+ return 0;
+ }
+#endif
default:
break;
} //switch
@@ -3364,14 +3496,14 @@ e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
struct ethtool_test *info;
int rc = -EFAULT;
- info = kmalloc(sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64),
+ info = kmalloc(sizeof(*info) + max_test_res * sizeof(u64),
GFP_ATOMIC);
if (!info)
return -ENOMEM;
memset((void *) info, 0, sizeof(*info) +
- E100_MAX_TEST_RES * sizeof(u64));
+ max_test_res * sizeof(u64));
if (copy_from_user(info, ifr->ifr_data, sizeof(*info)))
goto exit;
@@ -3379,7 +3511,7 @@ e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
info->flags = e100_run_diag(dev, info->data, info->flags);
if (!copy_to_user(ifr->ifr_data, info,
- sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64)))
+ sizeof(*info) + max_test_res * sizeof(u64)))
rc = 0;
exit:
kfree(info);
@@ -3393,6 +3525,7 @@ e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr)
u32 regs_buff[E100_REGS_LEN];
struct ethtool_regs regs = {ETHTOOL_GREGS};
void *addr = ifr->ifr_data;
+ u16 mdi_reg;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -3405,6 +3538,8 @@ e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr)
regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 |
readb(&(bdp->scb->scb_cmd_low)) << 16 |
readw(&(bdp->scb->scb_status));
+ e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &mdi_reg);
+ regs_buff[1] = mdi_reg;
if(copy_to_user(addr, &regs, sizeof(regs)))
return -EFAULT;
@@ -3454,7 +3589,7 @@ e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
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;
+ info.testinfo_len = max_test_res;
if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
return -EFAULT;
@@ -3804,15 +3939,15 @@ static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
switch (info.string_set) {
case ETH_SS_TEST: {
int ret = 0;
- if (info.len > E100_MAX_TEST_RES)
- info.len = E100_MAX_TEST_RES;
+ if (info.len > max_test_res)
+ info.len = max_test_res;
strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
if (!strings)
return -ENOMEM;
memset(strings, 0, info.len * ETH_GSTRING_LEN);
for (i = 0; i < info.len; i++) {
- sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
+ sprintf(strings + i * ETH_GSTRING_LEN, "%s",
test_strings[i]);
}
if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
@@ -4164,7 +4299,6 @@ e100_resume(struct pci_dev *pcid)
return 0;
}
-#endif /* CONFIG_PM */
/**
* e100_asf_enabled - checks if ASF is configured on the current adaper
@@ -4190,6 +4324,7 @@ e100_asf_enabled(struct e100_private *bdp)
}
return false;
}
+#endif /* CONFIG_PM */
#ifdef E100_CU_DEBUG
unsigned char
diff --git a/drivers/net/e100/e100_phy.c b/drivers/net/e100/e100_phy.c
index 08782934bdf6..e1473e816f1c 100644
--- a/drivers/net/e100/e100_phy.c
+++ b/drivers/net/e100/e100_phy.c
@@ -628,8 +628,6 @@ e100_force_speed_duplex(struct e100_private *bdp)
u16 control;
unsigned long expires;
- e100_phy_reset(bdp);
-
bdp->flags |= DF_SPEED_FORCED;
e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
@@ -912,6 +910,10 @@ e100_phy_reset(struct e100_private *bdp)
u16 ctrl_reg;
ctrl_reg = BMCR_RESET;
e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+ /* ieee 802.3 : The reset process shall be completed */
+ /* within 0.5 seconds from the settting of PHY reset bit. */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ / 2);
}
unsigned char __devinit
@@ -928,6 +930,7 @@ e100_phy_init(struct e100_private *bdp)
bdp->PhyDelay = 0;
bdp->zlock_state = ZLOCK_INITIAL;
+ e100_phy_reset(bdp);
e100_phy_set_speed_duplex(bdp, false);
e100_fix_polarity(bdp);
diff --git a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c
index 0ff7266ef8e2..208a92049f19 100644
--- a/drivers/net/e100/e100_test.c
+++ b/drivers/net/e100/e100_test.c
@@ -25,7 +25,7 @@
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
-#include "e100.h"
+#include "e100_phy.h"
#include "e100_config.h"
extern u16 e100_eeprom_read(struct e100_private *, u16);
@@ -46,6 +46,7 @@ static u8 e100_diag_loopback_alloc(struct e100_private *);
static void e100_diag_loopback_cu_ru_exec(struct e100_private *);
static u8 e100_diag_check_pkt(u8 *);
static void e100_diag_loopback_free(struct e100_private *);
+static int e100_cable_diag(struct e100_private *bdp);
#define LB_PACKET_SIZE 1500
@@ -60,46 +61,52 @@ u32
e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags)
{
struct e100_private* bdp = dev->priv;
- u8 test_result = true;
-
- e100_isolate_driver(bdp);
+ u8 test_result = 0;
+ if (!e100_get_link_state(bdp)) {
+ test_result = ETH_TEST_FL_FAILED;
+ test_info[test_link] = true;
+ }
+ if (!e100_diag_eeprom(dev)) {
+ test_result = ETH_TEST_FL_FAILED;
+ test_info[test_eeprom] = true;
+ }
if (flags & ETH_TEST_FL_OFFLINE) {
u8 fail_mask;
-
- fail_mask = e100_diag_selftest(dev);
- if (fail_mask) {
- test_result = false;
- if (fail_mask & REGISTER_TEST_FAIL)
- test_info [E100_REG_TEST_FAIL] = true;
- if (fail_mask & ROM_TEST_FAIL)
- test_info [E100_ROM_TEST_FAIL] = true;
- if (fail_mask & SELF_TEST_FAIL)
- test_info [E100_MAC_TEST_FAIL] = true;
- if (fail_mask & TEST_TIMEOUT)
- test_info [E100_CHIP_TIMEOUT] = true;
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ }
+ if (e100_diag_selftest(dev)) {
+ test_result = ETH_TEST_FL_FAILED;
+ test_info[test_self_test] = true;
}
fail_mask = e100_diag_loopback(dev);
if (fail_mask) {
- test_result = false;
+ test_result = ETH_TEST_FL_FAILED;
if (fail_mask & PHY_LOOPBACK)
- test_info [E100_LPBK_PHY_FAIL] = true;
+ test_info[test_loopback_phy] = true;
if (fail_mask & MAC_LOOPBACK)
- test_info [E100_LPBK_MAC_FAIL] = true;
+ test_info[test_loopback_mac] = true;
}
- }
- if (!e100_diag_eeprom(dev)) {
- test_result = false;
- test_info [E100_EEPROM_TEST_FAIL] = true;
+ test_info[cable_diag] = e100_cable_diag(bdp);
+ /* Need hw init regardless of netif_running */
+ e100_hw_init(bdp);
+ if (netif_running(dev)) {
+ e100_open(dev);
+ }
+ }
+ else {
+ test_info[test_self_test] = false;
+ test_info[test_loopback_phy] = false;
+ test_info[test_loopback_mac] = false;
+ test_info[cable_diag] = false;
}
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ * 2);
- e100_deisolate_driver(bdp, false);
-
- return flags | (test_result ? 0 : ETH_TEST_FL_FAILED);
+ return flags | test_result;
}
/**
@@ -126,8 +133,6 @@ e100_diag_selftest(struct net_device *dev)
}
}
- e100_configure_device(bdp);
-
return retval;
}
@@ -165,14 +170,14 @@ e100_diag_loopback (struct net_device *dev)
u8 rc = 0;
printk(KERN_DEBUG "%s: PHY loopback test starts\n", dev->name);
- e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET);
+ e100_hw_init(dev->priv);
if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) {
rc |= PHY_LOOPBACK;
}
printk(KERN_DEBUG "%s: PHY loopback test ends\n", dev->name);
printk(KERN_DEBUG "%s: MAC loopback test starts\n", dev->name);
- e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET);
+ e100_hw_init(dev->priv);
if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) {
rc |= MAC_LOOPBACK;
}
@@ -257,15 +262,10 @@ e100_diag_config_loopback(struct e100_private* bdp,
if (set_loopback)
/* Set PHY loopback mode */
e100_phy_set_loopback(bdp);
- else { /* Back to normal speed and duplex */
- if (bdp->params.e100_speed_duplex == E100_AUTONEG)
- /* Reset PHY and do autoneg */
- e100_phy_autoneg(bdp);
- else
- /* Reset PHY and force speed and duplex */
- e100_force_speed_duplex(bdp);
- }
- /* Wait for PHY state change */
+ else
+ /* Reset PHY loopback mode */
+ e100_phy_reset(bdp);
+ /* Wait for PHY state change */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
} else { /* For MAC loopback wait 500 msec to take effect */
@@ -348,10 +348,6 @@ static void
e100_diag_loopback_cu_ru_exec(struct e100_private *bdp)
{
/*load CU & RU base */
- if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
- printk(KERN_ERR "e100: SCB_CUC_LOAD_BASE failed\n");
- if(!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
- printk(KERN_ERR "e100: SCB_RUC_LOAD_BASE failed!\n");
if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START, 0))
printk(KERN_ERR "e100: SCB_RUC_START failed!\n");
@@ -433,3 +429,72 @@ e100_diag_loopback_free (struct e100_private *bdp)
bdp->loopback.dma_handle);
}
+static int
+e100_cable_diag(struct e100_private *bdp)
+{
+ int saved_open_circut = 0xffff;
+ int saved_short_circut = 0xffff;
+ int saved_distance = 0xffff;
+ int saved_same = 0;
+ int cable_status = E100_CABLE_UNKNOWN;
+ int i;
+
+ /* If we have link, */
+ if (e100_get_link_state(bdp))
+ return E100_CABLE_OK;
+
+ if (bdp->rev_id < D102_REV_ID)
+ return E100_CABLE_UNKNOWN;
+
+ /* 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 cable test */
+ e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
+ BMCR_SPEED100 | BMCR_FULLDPLX);
+
+ /* Test up to 100 times */
+ for (i = 0; i < 100; i++) {
+ u16 ctrl_reg;
+ int distance, open_circut, short_circut, near_end;
+
+ /* Enable and execute cable test */
+ e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
+ (HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
+ /* Wait for cable test finished */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/100 + 1);
+ /* Read results */
+ 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 == saved_distance) &&
+ (open_circut == saved_open_circut) &&
+ (short_circut == saved_short_circut))
+ saved_same++;
+ else {
+ saved_same = 0;
+ saved_distance = distance;
+ saved_open_circut = open_circut;
+ saved_short_circut = short_circut;
+ }
+ /* If results are the same 3 times */
+ if (saved_same == 3) {
+ near_end = ((distance * HWI_REGISTER_GRANULARITY) <
+ HWI_NEAR_END_BOUNDARY);
+ if (open_circut)
+ cable_status = (near_end) ?
+ E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR;
+ if (short_circut)
+ cable_status = (near_end) ?
+ E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR;
+ break;
+ }
+ }
+ /* Reset cable test */
+ e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK);
+ return cable_status;
+}
+
diff --git a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile
index 898c6a3a2c09..ca9f89552da3 100644
--- a/drivers/net/e1000/Makefile
+++ b/drivers/net/e1000/Makefile
@@ -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
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 307a2b1b22ad..8891f273269e 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -134,6 +134,7 @@ struct e1000_buffer {
uint64_t dma;
unsigned long length;
unsigned long time_stamp;
+ unsigned int next_to_watch;
};
struct e1000_desc_ring {
@@ -169,7 +170,6 @@ struct e1000_adapter {
struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
struct vlan_group *vlgrp;
- char *id_string;
uint32_t bd_number;
uint32_t rx_buffer_len;
uint32_t part_num;
@@ -218,6 +218,9 @@ struct e1000_adapter {
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
+ uint32_t test_icr;
+ struct e1000_desc_ring test_tx_ring;
+ struct e1000_desc_ring test_rx_ring;
uint32_t pci_state[16];
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index c64530107467..43b60a55ed58 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -40,15 +40,60 @@ extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
-static char e1000_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",
+struct e1000_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
};
-#define E1000_STATS_LEN sizeof(e1000_gstrings_stats) / ETH_GSTRING_LEN
+
+#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
+ offsetof(struct e1000_adapter, m)
+static struct e1000_stats e1000_gstrings_stats[] = {
+ { "rx_packets", E1000_STAT(net_stats.rx_packets) },
+ { "tx_packets", E1000_STAT(net_stats.tx_packets) },
+ { "rx_bytes", E1000_STAT(net_stats.rx_bytes) },
+ { "tx_bytes", E1000_STAT(net_stats.tx_bytes) },
+ { "rx_errors", E1000_STAT(net_stats.rx_errors) },
+ { "tx_errors", E1000_STAT(net_stats.tx_errors) },
+ { "rx_dropped", E1000_STAT(net_stats.rx_dropped) },
+ { "tx_dropped", E1000_STAT(net_stats.tx_dropped) },
+ { "multicast", E1000_STAT(net_stats.multicast) },
+ { "collisions", E1000_STAT(net_stats.collisions) },
+ { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) },
+ { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) },
+ { "rx_crc_errors", E1000_STAT(net_stats.rx_crc_errors) },
+ { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
+ { "rx_fifo_errors", E1000_STAT(net_stats.rx_fifo_errors) },
+ { "rx_missed_errors", E1000_STAT(net_stats.rx_missed_errors) },
+ { "tx_aborted_errors", E1000_STAT(net_stats.tx_aborted_errors) },
+ { "tx_carrier_errors", E1000_STAT(net_stats.tx_carrier_errors) },
+ { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) },
+ { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) },
+ { "tx_window_errors", E1000_STAT(net_stats.tx_window_errors) },
+ { "tx_abort_late_coll", E1000_STAT(stats.latecol) },
+ { "tx_deferred_ok", E1000_STAT(stats.dc) },
+ { "tx_single_coll_ok", E1000_STAT(stats.scc) },
+ { "tx_multi_coll_ok", E1000_STAT(stats.mcc) },
+ { "rx_long_length_errors", E1000_STAT(stats.roc) },
+ { "rx_short_length_errors", E1000_STAT(stats.ruc) },
+ { "rx_align_errors", E1000_STAT(stats.algnerrc) },
+ { "tx_tcp_seg_good", E1000_STAT(stats.tsctc) },
+ { "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) },
+ { "rx_flow_control_xon", E1000_STAT(stats.xonrxc) },
+ { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) },
+ { "tx_flow_control_xon", E1000_STAT(stats.xontxc) },
+ { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
+ { "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
+ { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }
+};
+#define E1000_STATS_LEN \
+ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
+static char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
+ "Register test (offline)", "Eeprom test (offline)",
+ "Interrupt test (offline)", "Loopback test (offline)",
+ "Link test (on/offline)"
+};
+#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN
static void
e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
@@ -154,6 +199,7 @@ e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
strncpy(drvinfo->fw_version, "N/A", 32);
strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
drvinfo->n_stats = E1000_STATS_LEN;
+ drvinfo->testinfo_len = E1000_TEST_LEN;
#define E1000_REGS_LEN 32
drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t);
drvinfo->eedump_len = adapter->hw.eeprom.word_size * 2;
@@ -164,6 +210,7 @@ e1000_ethtool_gregs(struct e1000_adapter *adapter,
struct ethtool_regs *regs, uint32_t *regs_buff)
{
struct e1000_hw *hw = &adapter->hw;
+ uint16_t phy_data;
regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
@@ -182,6 +229,62 @@ e1000_ethtool_gregs(struct e1000_adapter *adapter,
regs_buff[10] = E1000_READ_REG(hw, TDT);
regs_buff[11] = E1000_READ_REG(hw, TIDV);
+ regs_buff[12] = adapter->hw.phy_type; /* PHY type (IGP=1, M88=0) */
+ if(hw->phy_type == e1000_phy_igp) {
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ IGP01E1000_PHY_AGC_A);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_A &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[13] = (uint32_t)phy_data; /* cable length */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ IGP01E1000_PHY_AGC_B);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_B &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[14] = (uint32_t)phy_data; /* cable length */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ IGP01E1000_PHY_AGC_C);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_C &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[15] = (uint32_t)phy_data; /* cable length */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ IGP01E1000_PHY_AGC_D);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_D &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[16] = (uint32_t)phy_data; /* cable length */
+ regs_buff[17] = 0; /* extended 10bt distance (not needed) */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[18] = (uint32_t)phy_data; /* cable polarity */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ IGP01E1000_PHY_PCS_INIT_REG);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[19] = (uint32_t)phy_data; /* cable polarity */
+ regs_buff[20] = 0; /* polarity correction enabled (always) */
+ regs_buff[22] = 0; /* phy receive errors (unavailable) */
+ regs_buff[23] = regs_buff[18]; /* mdix mode */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0);
+ } else {
+ e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ regs_buff[13] = (uint32_t)phy_data; /* cable length */
+ regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ regs_buff[17] = (uint32_t)phy_data; /* extended 10bt distance */
+ regs_buff[18] = regs_buff[13]; /* cable polarity */
+ regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[20] = regs_buff[17]; /* polarity correction */
+ /* phy receive errors */
+ regs_buff[22] = adapter->phy_stats.receive_errors;
+ regs_buff[23] = regs_buff[13]; /* mdix mode */
+ }
+ regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */
+ e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+ regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */
+ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */
+
return;
}
@@ -219,7 +322,7 @@ e1000_ethtool_geeprom(struct e1000_adapter *adapter,
uint16_t i;
for (i = 0; i < last_word - first_word + 1; i++)
if((ret_val = e1000_read_eeprom(hw, first_word + i, 1,
- &eeprom_buff[i])))
+ &eeprom_buff[i])))
break;
}
geeprom_error:
@@ -249,7 +352,7 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter,
first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
eeprom_buff = kmalloc(max_len, GFP_KERNEL);
- if(eeprom_buff == NULL)
+ if(!eeprom_buff)
return -ENOMEM;
ptr = (void *)eeprom_buff;
@@ -284,6 +387,765 @@ seeprom_error:
return ret_val;
}
+#define REG_PATTERN_TEST(R, M, W) \
+{ \
+ uint32_t pat, value; \
+ uint32_t test[] = \
+ {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
+ for(pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \
+ E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \
+ value = E1000_READ_REG(&adapter->hw, R); \
+ if(value != (test[pat] & W & M)) { \
+ *data = (adapter->hw.mac_type < e1000_82543) ? \
+ E1000_82542_##R : E1000_##R; \
+ return 1; \
+ } \
+ } \
+}
+
+#define REG_SET_AND_CHECK(R, M, W) \
+{ \
+ uint32_t value; \
+ E1000_WRITE_REG(&adapter->hw, R, W & M); \
+ value = E1000_READ_REG(&adapter->hw, R); \
+ if ((W & M) != (value & M)) { \
+ *data = (adapter->hw.mac_type < e1000_82543) ? \
+ E1000_82542_##R : E1000_##R; \
+ return 1; \
+ } \
+}
+
+static int
+e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
+{
+ uint32_t value;
+ uint32_t i;
+
+ /* The status register is Read Only, so a write should fail.
+ * Some bits that get toggled are ignored.
+ */
+ value = (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833));
+ E1000_WRITE_REG(&adapter->hw, STATUS, (0xFFFFFFFF));
+ if(value != (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833))) {
+ *data = 1;
+ return 1;
+ }
+
+ REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(RDTR, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(RDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(RDLEN, 0x000FFF80, 0x000FFFFF);
+ REG_PATTERN_TEST(RDH, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(RDT, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(FCRTH, 0x0000FFF8, 0x0000FFF8);
+ REG_PATTERN_TEST(FCTTV, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(TIPG, 0x3FFFFFFF, 0x3FFFFFFF);
+ REG_PATTERN_TEST(TDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(TDLEN, 0x000FFF80, 0x000FFFFF);
+
+ REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x00000000);
+ REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0x003FFFFB);
+ REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000);
+
+ if(adapter->hw.mac_type >= e1000_82543) {
+
+ REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0xFFFFFFFF);
+ REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
+ REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
+ REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF);
+
+ for(i = 0; i < E1000_RAR_ENTRIES; i++) {
+ REG_PATTERN_TEST(RA + ((i << 1) << 2), 0xFFFFFFFF,
+ 0xFFFFFFFF);
+ REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF,
+ 0xFFFFFFFF);
+ }
+
+ } else {
+
+ REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x01FFFFFF);
+ REG_PATTERN_TEST(RDBAL, 0xFFFFF000, 0xFFFFFFFF);
+ REG_PATTERN_TEST(TXCW, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(TDBAL, 0xFFFFF000, 0xFFFFFFFF);
+
+ }
+
+ for(i = 0; i < E1000_MC_TBL_SIZE; i++)
+ REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF);
+
+ return 0;
+}
+
+static int
+e1000_eeprom_test(struct e1000_adapter *adapter, uint64_t *data)
+{
+ uint16_t temp;
+ uint16_t checksum = 0;
+ uint16_t i;
+
+ *data = 0;
+ /* Read and add up the contents of the EEPROM */
+ for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+ if((e1000_read_eeprom(&adapter->hw, i, 1, &temp)) < 0) {
+ *data = 1;
+ break;
+ }
+ checksum += temp;
+ }
+
+ /* If Checksum is not Correct return error else test passed */
+ if((checksum != (uint16_t) EEPROM_SUM) && !(*data))
+ *data = 2;
+
+ return *data;
+}
+
+static irqreturn_t
+e1000_test_intr(int irq,
+ void *data,
+ struct pt_regs *regs)
+{
+ struct net_device *netdev = (struct net_device *) data;
+ struct e1000_adapter *adapter = netdev->priv;
+
+ adapter->test_icr |= E1000_READ_REG(&adapter->hw, ICR);
+
+ return IRQ_HANDLED;
+}
+
+static int
+e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
+{
+ struct net_device *netdev = adapter->netdev;
+ uint32_t icr, mask, i=0;
+
+ *data = 0;
+
+ /* Hook up test interrupt handler just for this test */
+ if(request_irq
+ (netdev->irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)) {
+ *data = 1;
+ return -1;
+ }
+
+ /* Disable all the interrupts */
+ E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
+ msec_delay(10);
+
+ /* Interrupts are disabled, so read interrupt cause
+ * register (icr) twice to verify that there are no interrupts
+ * pending. icr is clear on read.
+ */
+ icr = E1000_READ_REG(&adapter->hw, ICR);
+ icr = E1000_READ_REG(&adapter->hw, ICR);
+
+ if(icr != 0) {
+ /* if icr is non-zero, there is no point
+ * running other interrupt tests.
+ */
+ *data = 2;
+ i = 10;
+ }
+
+ /* Test each interrupt */
+ for(; i < 10; i++) {
+
+ /* Interrupt to test */
+ mask = 1 << i;
+
+ /* Disable the interrupt to be reported in
+ * the cause register and then force the same
+ * interrupt and see if one gets posted. If
+ * an interrupt was posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ E1000_WRITE_REG(&adapter->hw, IMC, mask);
+ E1000_WRITE_REG(&adapter->hw, ICS, mask);
+ msec_delay(10);
+
+ if(adapter->test_icr & mask) {
+ *data = 3;
+ break;
+ }
+
+ /* Enable the interrupt to be reported in
+ * the cause register and then force the same
+ * interrupt and see if one gets posted. If
+ * an interrupt was not posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ E1000_WRITE_REG(&adapter->hw, IMS, mask);
+ E1000_WRITE_REG(&adapter->hw, ICS, mask);
+ msec_delay(10);
+
+ if(!(adapter->test_icr & mask)) {
+ *data = 4;
+ break;
+ }
+
+ /* Disable the other interrupts to be reported in
+ * the cause register and then force the other
+ * interrupts and see if any get posted. If
+ * an interrupt was posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ E1000_WRITE_REG(&adapter->hw, IMC, ~mask);
+ E1000_WRITE_REG(&adapter->hw, ICS, ~mask);
+ msec_delay(10);
+
+ if(adapter->test_icr) {
+ *data = 5;
+ break;
+ }
+ }
+
+ /* Disable all the interrupts */
+ E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
+ msec_delay(10);
+
+ /* Unhook test interrupt handler */
+ free_irq(netdev->irq, netdev);
+
+ return *data;
+}
+
+static void
+e1000_free_desc_rings(struct e1000_adapter *adapter)
+{
+ struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ int i;
+
+ if(txdr->desc && txdr->buffer_info) {
+ for(i = 0; i < txdr->count; i++) {
+ if(txdr->buffer_info[i].dma)
+ pci_unmap_single(pdev, txdr->buffer_info[i].dma,
+ txdr->buffer_info[i].length,
+ PCI_DMA_TODEVICE);
+ if(txdr->buffer_info[i].skb)
+ dev_kfree_skb(txdr->buffer_info[i].skb);
+ }
+ }
+
+ if(rxdr->desc && rxdr->buffer_info) {
+ for(i = 0; i < rxdr->count; i++) {
+ if(rxdr->buffer_info[i].dma)
+ pci_unmap_single(pdev, rxdr->buffer_info[i].dma,
+ rxdr->buffer_info[i].length,
+ PCI_DMA_FROMDEVICE);
+ if(rxdr->buffer_info[i].skb)
+ dev_kfree_skb(rxdr->buffer_info[i].skb);
+ }
+ }
+
+ if(txdr->desc)
+ pci_free_consistent(pdev, txdr->size, txdr->desc, txdr->dma);
+ if(rxdr->desc)
+ pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma);
+
+ if(txdr->buffer_info)
+ kfree(txdr->buffer_info);
+ if(rxdr->buffer_info)
+ kfree(rxdr->buffer_info);
+
+ return;
+}
+
+static int
+e1000_setup_desc_rings(struct e1000_adapter *adapter)
+{
+ struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ uint32_t rctl;
+ int size, i, ret_val;
+
+ /* Setup Tx descriptor ring and Tx buffers */
+
+ txdr->count = 80;
+
+ size = txdr->count * sizeof(struct e1000_buffer);
+ if(!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+ ret_val = 1;
+ goto err_nomem;
+ }
+ memset(txdr->buffer_info, 0, size);
+
+ txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
+ E1000_ROUNDUP(txdr->size, 4096);
+ if(!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) {
+ ret_val = 2;
+ goto err_nomem;
+ }
+ memset(txdr->desc, 0, txdr->size);
+ txdr->next_to_use = txdr->next_to_clean = 0;
+
+ E1000_WRITE_REG(&adapter->hw, TDBAL,
+ ((uint64_t) txdr->dma & 0x00000000FFFFFFFF));
+ E1000_WRITE_REG(&adapter->hw, TDBAH, ((uint64_t) txdr->dma >> 32));
+ E1000_WRITE_REG(&adapter->hw, TDLEN,
+ txdr->count * sizeof(struct e1000_tx_desc));
+ E1000_WRITE_REG(&adapter->hw, TDH, 0);
+ E1000_WRITE_REG(&adapter->hw, TDT, 0);
+ E1000_WRITE_REG(&adapter->hw, TCTL,
+ E1000_TCTL_PSP | E1000_TCTL_EN |
+ E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT |
+ E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT);
+
+ for(i = 0; i < txdr->count; i++) {
+ struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*txdr, i);
+ struct sk_buff *skb;
+ unsigned int size = 1024;
+
+ if(!(skb = alloc_skb(size, GFP_KERNEL))) {
+ ret_val = 3;
+ goto err_nomem;
+ }
+ skb_put(skb, size);
+ txdr->buffer_info[i].skb = skb;
+ txdr->buffer_info[i].length = skb->len;
+ txdr->buffer_info[i].dma =
+ pci_map_single(pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma);
+ tx_desc->lower.data = cpu_to_le32(skb->len);
+ tx_desc->lower.data |= E1000_TXD_CMD_EOP;
+ tx_desc->lower.data |= E1000_TXD_CMD_IFCS;
+ tx_desc->lower.data |= E1000_TXD_CMD_RPS;
+ tx_desc->upper.data = 0;
+ }
+
+ /* Setup Rx descriptor ring and Rx buffers */
+
+ rxdr->count = 80;
+
+ size = rxdr->count * sizeof(struct e1000_buffer);
+ if(!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+ ret_val = 4;
+ goto err_nomem;
+ }
+ memset(rxdr->buffer_info, 0, size);
+
+ rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
+ if(!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) {
+ ret_val = 5;
+ goto err_nomem;
+ }
+ memset(rxdr->desc, 0, rxdr->size);
+ rxdr->next_to_use = rxdr->next_to_clean = 0;
+
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN);
+ E1000_WRITE_REG(&adapter->hw, RDBAL,
+ ((uint64_t) rxdr->dma & 0xFFFFFFFF));
+ E1000_WRITE_REG(&adapter->hw, RDBAH, ((uint64_t) rxdr->dma >> 32));
+ E1000_WRITE_REG(&adapter->hw, RDLEN, rxdr->size);
+ E1000_WRITE_REG(&adapter->hw, RDH, 0);
+ E1000_WRITE_REG(&adapter->hw, RDT, 0);
+ rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
+ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+ (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+
+ for(i = 0; i < rxdr->count; i++) {
+ struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rxdr, i);
+ struct sk_buff *skb;
+
+ if(!(skb = alloc_skb(E1000_RXBUFFER_2048 + 2, GFP_KERNEL))) {
+ ret_val = 6;
+ goto err_nomem;
+ }
+ skb_reserve(skb, 2);
+ rxdr->buffer_info[i].skb = skb;
+ rxdr->buffer_info[i].length = E1000_RXBUFFER_2048;
+ rxdr->buffer_info[i].dma =
+ pci_map_single(pdev, skb->data, E1000_RXBUFFER_2048,
+ PCI_DMA_FROMDEVICE);
+ rx_desc->buffer_addr = cpu_to_le64(rxdr->buffer_info[i].dma);
+ memset(skb->data, 0x00, skb->len);
+ }
+
+ return 0;
+
+ err_nomem:
+ e1000_free_desc_rings(adapter);
+ return ret_val;
+}
+
+static void
+e1000_phy_disable_receiver(struct e1000_adapter *adapter)
+{
+ /* Write out to PHY registers 29 and 30 to disable the Receiver. */
+ e1000_write_phy_reg(&adapter->hw, 29, 0x001F);
+ e1000_write_phy_reg(&adapter->hw, 30, 0x8FFC);
+ e1000_write_phy_reg(&adapter->hw, 29, 0x001A);
+ e1000_write_phy_reg(&adapter->hw, 30, 0x8FF0);
+
+ return;
+}
+
+static void
+e1000_phy_reset_clk_and_crs(struct e1000_adapter *adapter)
+{
+ uint16_t phy_reg;
+
+ /* Because we reset the PHY above, we need to re-force TX_CLK in the
+ * Extended PHY Specific Control Register to 25MHz clock. This
+ * value defaults back to a 2.5MHz clock when the PHY is reset.
+ */
+ e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg);
+ phy_reg |= M88E1000_EPSCR_TX_CLK_25;
+ e1000_write_phy_reg(&adapter->hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, phy_reg);
+
+ /* In addition, because of the s/w reset above, we need to enable
+ * CRS on TX. This must be set for both full and half duplex
+ * operation.
+ */
+ e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg);
+ phy_reg |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ e1000_write_phy_reg(&adapter->hw,
+ M88E1000_PHY_SPEC_CTRL, phy_reg);
+}
+
+static int
+e1000_nonintegrated_phy_loopback(struct e1000_adapter *adapter)
+{
+ uint32_t ctrl_reg;
+ uint16_t phy_reg;
+
+ /* Setup the Device Control Register for PHY loopback test. */
+
+ ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl_reg |= (E1000_CTRL_ILOS | /* Invert Loss-Of-Signal */
+ E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg);
+
+ /* Read the PHY Specific Control Register (0x10) */
+ e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg);
+
+ /* Clear Auto-Crossover bits in PHY Specific Control Register
+ * (bits 6:5).
+ */
+ phy_reg &= ~M88E1000_PSCR_AUTO_X_MODE;
+ e1000_write_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, phy_reg);
+
+ /* Perform software reset on the PHY */
+ e1000_phy_reset(&adapter->hw);
+
+ /* Have to setup TX_CLK and TX_CRS after software reset */
+ e1000_phy_reset_clk_and_crs(adapter);
+
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8100);
+
+ /* Wait for reset to complete. */
+ udelay(500);
+
+ /* Have to setup TX_CLK and TX_CRS after software reset */
+ e1000_phy_reset_clk_and_crs(adapter);
+
+ /* Write out to PHY registers 29 and 30 to disable the Receiver. */
+ e1000_phy_disable_receiver(adapter);
+
+ /* Set the loopback bit in the PHY control register. */
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
+ phy_reg |= MII_CR_LOOPBACK;
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
+
+ /* Setup TX_CLK and TX_CRS one more time. */
+ e1000_phy_reset_clk_and_crs(adapter);
+
+ /* Check Phy Configuration */
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
+ if(phy_reg != 0x4100)
+ return 9;
+
+ e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg);
+ if(phy_reg != 0x0070)
+ return 10;
+
+ e1000_read_phy_reg(&adapter->hw, 29, &phy_reg);
+ if(phy_reg != 0x001A)
+ return 11;
+
+ return 0;
+}
+
+static int
+e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
+{
+ uint32_t ctrl_reg = 0;
+ uint32_t stat_reg = 0;
+
+ adapter->hw.autoneg = FALSE;
+
+ if(adapter->hw.phy_type == e1000_phy_m88) {
+ /* Auto-MDI/MDIX Off */
+ e1000_write_phy_reg(&adapter->hw,
+ M88E1000_PHY_SPEC_CTRL, 0x0808);
+ /* reset to update Auto-MDI/MDIX */
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x9140);
+ /* autoneg off */
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8140);
+ }
+ /* force 1000, set loopback */
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140);
+
+ /* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ if(adapter->hw.media_type == e1000_media_type_copper &&
+ adapter->hw.phy_type == e1000_phy_m88) {
+ ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
+ } else {
+ /* Set the ILOS bit on the fiber Nic is half
+ * duplex link is detected. */
+ stat_reg = E1000_READ_REG(&adapter->hw, STATUS);
+ if((stat_reg & E1000_STATUS_FD) == 0)
+ ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
+ }
+
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg);
+
+ /* Disable the receiver on the PHY so when a cable is plugged in, the
+ * PHY does not begin to autoneg when a cable is reconnected to the NIC.
+ */
+ if(adapter->hw.phy_type == e1000_phy_m88)
+ e1000_phy_disable_receiver(adapter);
+
+ udelay(500);
+
+ return 0;
+}
+
+static int
+e1000_set_phy_loopback(struct e1000_adapter *adapter)
+{
+ uint16_t phy_reg = 0;
+ uint16_t count = 0;
+
+ switch (adapter->hw.mac_type) {
+ case e1000_82543:
+ if(adapter->hw.media_type == e1000_media_type_copper) {
+ /* Attempt to setup Loopback mode on Non-integrated PHY.
+ * Some PHY registers get corrupted at random, so
+ * attempt this 10 times.
+ */
+ while(e1000_nonintegrated_phy_loopback(adapter) &&
+ count++ < 10);
+ if(count < 11)
+ return 0;
+ }
+ break;
+
+ case e1000_82544:
+ case e1000_82540:
+ case e1000_82545:
+ case e1000_82546:
+ case e1000_82541:
+ case e1000_82547:
+ return e1000_integrated_phy_loopback(adapter);
+ break;
+
+ default:
+ /* Default PHY loopback work is to read the MII
+ * control register and assert bit 14 (loopback mode).
+ */
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
+ phy_reg |= MII_CR_LOOPBACK;
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
+ return 0;
+ break;
+ }
+
+ return 8;
+}
+
+static int
+e1000_setup_loopback_test(struct e1000_adapter *adapter)
+{
+ uint32_t rctl;
+
+ if(adapter->hw.media_type == e1000_media_type_fiber) {
+ if(adapter->hw.mac_type == e1000_82545 ||
+ adapter->hw.mac_type == e1000_82546)
+ return e1000_set_phy_loopback(adapter);
+ else {
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ rctl |= E1000_RCTL_LBM_TCVR;
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+ return 0;
+ }
+ } else if(adapter->hw.media_type == e1000_media_type_copper)
+ return e1000_set_phy_loopback(adapter);
+
+ return 7;
+}
+
+static void
+e1000_loopback_cleanup(struct e1000_adapter *adapter)
+{
+ uint32_t rctl;
+ uint16_t phy_reg;
+
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+
+ if(adapter->hw.media_type == e1000_media_type_copper ||
+ (adapter->hw.media_type == e1000_media_type_fiber &&
+ (adapter->hw.mac_type == e1000_82545 ||
+ adapter->hw.mac_type == e1000_82546))) {
+ adapter->hw.autoneg = TRUE;
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
+ if(phy_reg & MII_CR_LOOPBACK) {
+ phy_reg &= ~MII_CR_LOOPBACK;
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
+ e1000_phy_reset(&adapter->hw);
+ }
+ }
+}
+
+static void
+e1000_create_lbtest_frame(struct sk_buff *skb, unsigned int frame_size)
+{
+ memset(skb->data, 0xFF, frame_size);
+ frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size;
+ memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
+ memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
+ memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
+}
+
+static int
+e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size)
+{
+ frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size;
+ if(*(skb->data + 3) == 0xFF) {
+ if((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
+ (*(skb->data + frame_size / 2 + 12) == 0xAF)) {
+ return 0;
+ }
+ }
+ return 13;
+}
+
+static int
+e1000_run_loopback_test(struct e1000_adapter *adapter)
+{
+ struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ int i;
+
+ E1000_WRITE_REG(&adapter->hw, RDT, rxdr->count - 1);
+
+ for(i = 0; i < 64; i++) {
+ e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024);
+ pci_dma_sync_single(pdev, txdr->buffer_info[i].dma,
+ txdr->buffer_info[i].length,
+ PCI_DMA_TODEVICE);
+ }
+ E1000_WRITE_REG(&adapter->hw, TDT, i);
+
+ msec_delay(200);
+
+ pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma,
+ rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE);
+
+ return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024);
+}
+
+static int
+e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data)
+{
+ if((*data = e1000_setup_desc_rings(adapter))) goto err_loopback;
+ if((*data = e1000_setup_loopback_test(adapter))) goto err_loopback;
+ *data = e1000_run_loopback_test(adapter);
+ e1000_loopback_cleanup(adapter);
+ e1000_free_desc_rings(adapter);
+err_loopback:
+ return *data;
+}
+
+static int
+e1000_link_test(struct e1000_adapter *adapter, uint64_t *data)
+{
+ *data = 0;
+ e1000_check_for_link(&adapter->hw);
+
+ if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
+ *data = 1;
+ }
+ return *data;
+}
+
+static int
+e1000_ethtool_test(struct e1000_adapter *adapter,
+ struct ethtool_test *eth_test, uint64_t *data)
+{
+ boolean_t if_running = netif_running(adapter->netdev);
+
+ if(eth_test->flags == ETH_TEST_FL_OFFLINE) {
+ /* Offline tests */
+
+ /* Link test performed before hardware reset so autoneg doesn't
+ * interfere with test result */
+ if(e1000_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ if(if_running)
+ e1000_down(adapter);
+
+ e1000_reset(adapter);
+ if(e1000_reg_test(adapter, &data[0]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000_reset(adapter);
+ if(e1000_eeprom_test(adapter, &data[1]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000_reset(adapter);
+ if(e1000_intr_test(adapter, &data[2]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000_reset(adapter);
+ if(e1000_loopback_test(adapter, &data[3]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000_reset(adapter);
+ if(if_running)
+ e1000_up(adapter);
+ } else {
+ /* Online tests */
+ if(e1000_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ /* Offline tests aren't run; pass by default */
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0;
+ }
+ return 0;
+}
+
static void
e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
{
@@ -443,24 +1305,46 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
case ETHTOOL_GSTRINGS: {
struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };
char *strings = NULL;
+ int err = 0;
if(copy_from_user(&gstrings, addr, sizeof(gstrings)))
return -EFAULT;
switch(gstrings.string_set) {
- case ETH_SS_STATS:
+ case ETH_SS_TEST:
+ gstrings.len = E1000_TEST_LEN;
+ strings = kmalloc(E1000_TEST_LEN * ETH_GSTRING_LEN,
+ GFP_KERNEL);
+ if(!strings)
+ return -ENOMEM;
+ memcpy(strings, e1000_gstrings_test, E1000_TEST_LEN *
+ ETH_GSTRING_LEN);
+ break;
+ case ETH_SS_STATS: {
+ int i;
gstrings.len = E1000_STATS_LEN;
- strings = *e1000_gstrings_stats;
+ strings = kmalloc(E1000_STATS_LEN * ETH_GSTRING_LEN,
+ GFP_KERNEL);
+ if(!strings)
+ return -ENOMEM;
+ for(i=0; i < E1000_STATS_LEN; i++) {
+ memcpy(&strings[i * ETH_GSTRING_LEN],
+ e1000_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ }
break;
+ }
default:
return -EOPNOTSUPP;
}
if(copy_to_user(addr, &gstrings, sizeof(gstrings)))
- return -EFAULT;
+ err = -EFAULT;
addr += offsetof(struct ethtool_gstrings, data);
- if(copy_to_user(addr, strings,
+ if(!err && copy_to_user(addr, strings,
gstrings.len * ETH_GSTRING_LEN))
- return -EFAULT;
- return 0;
+ err = -EFAULT;
+
+ kfree(strings);
+ return err;
}
case ETHTOOL_GREGS: {
struct ethtool_regs regs = {ETHTOOL_GREGS};
@@ -522,16 +1406,14 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
void *ptr;
int err = 0;
+ if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
+ return -EFAULT;
+
eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL);
- if(eeprom_buff == NULL)
+ if(!eeprom_buff)
return -ENOMEM;
- if(copy_from_user(&eeprom, addr, sizeof(eeprom))) {
- err = -EFAULT;
- goto err_geeprom_ioctl;
- }
-
if((err = e1000_ethtool_geeprom(adapter, &eeprom,
eeprom_buff)))
goto err_geeprom_ioctl;
@@ -565,18 +1447,45 @@ err_geeprom_ioctl:
}
case ETHTOOL_GSTATS: {
struct {
- struct ethtool_stats cmd;
+ struct ethtool_stats eth_stats;
uint64_t data[E1000_STATS_LEN];
} stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} };
int i;
for(i = 0; i < E1000_STATS_LEN; i++)
- stats.data[i] =
- ((unsigned long *)&adapter->net_stats)[i];
+ stats.data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
+ sizeof(uint64_t)) ?
+ *(uint64_t *)((char *)adapter +
+ e1000_gstrings_stats[i].stat_offset) :
+ *(uint32_t *)((char *)adapter +
+ e1000_gstrings_stats[i].stat_offset);
if(copy_to_user(addr, &stats, sizeof(stats)))
return -EFAULT;
return 0;
}
+ case ETHTOOL_TEST: {
+ struct {
+ struct ethtool_test eth_test;
+ uint64_t data[E1000_TEST_LEN];
+ } test = { {ETHTOOL_TEST} };
+ int err;
+
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if(copy_from_user(&test.eth_test, addr, sizeof(test.eth_test)))
+ return -EFAULT;
+
+ test.eth_test.len = E1000_TEST_LEN;
+
+ if((err = e1000_ethtool_test(adapter, &test.eth_test,
+ test.data)))
+ return err;
+
+ if(copy_to_user(addr, &test, sizeof(test)) != 0)
+ return -EFAULT;
+ return 0;
+ }
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 3527e7794635..539533515e20 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -185,6 +185,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_FIBER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
hw->mac_type = e1000_82546;
break;
case E1000_DEV_ID_82541EI:
@@ -288,9 +289,7 @@ e1000_reset_hw(struct e1000_hw *hw)
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
- led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
- if(hw->mac_type == e1000_82547)
- led_ctrl |= IGP_LED3_MODE;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
}
@@ -737,9 +736,7 @@ e1000_setup_copper_link(struct e1000_hw *hw)
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
- led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
- if(hw->mac_type == e1000_82547)
- led_ctrl |= IGP_LED3_MODE;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
@@ -2293,9 +2290,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
- led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
- if(hw->mac_type == e1000_82547)
- led_ctrl |= IGP_LED3_MODE;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
}
}
@@ -3801,6 +3796,7 @@ e1000_setup_led(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
@@ -3842,6 +3838,7 @@ e1000_cleanup_led(struct e1000_hw *hw)
case E1000_DEV_ID_82545EM_FIBER:
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_FIBER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
@@ -3896,6 +3893,7 @@ e1000_led_on(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
@@ -3949,6 +3947,7 @@ e1000_led_off(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
@@ -4206,7 +4205,11 @@ e1000_get_bus_info(struct e1000_hw *hw)
status = E1000_READ_REG(hw, STATUS);
hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
e1000_bus_type_pcix : e1000_bus_type_pci;
- if(hw->bus_type == e1000_bus_type_pci) {
+
+ if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
+ hw->bus_speed = (hw->bus_type == e1000_bus_type_pci) ?
+ e1000_bus_speed_66 : e1000_bus_speed_120;
+ } else if(hw->bus_type == e1000_bus_type_pci) {
hw->bus_speed = (status & E1000_STATUS_PCI66) ?
e1000_bus_speed_66 : e1000_bus_speed_33;
} else {
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 3fe0febaa7e7..bfb91bc5d8a2 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -99,6 +99,7 @@ typedef enum {
e1000_bus_speed_33,
e1000_bus_speed_66,
e1000_bus_speed_100,
+ e1000_bus_speed_120,
e1000_bus_speed_133,
e1000_bus_speed_reserved
} e1000_bus_speed;
@@ -314,10 +315,11 @@ void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
#define E1000_DEV_ID_82545EM_FIBER 0x1011
#define E1000_DEV_ID_82546EB_COPPER 0x1010
#define E1000_DEV_ID_82546EB_FIBER 0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
#define E1000_DEV_ID_82541EI 0x1013
#define E1000_DEV_ID_82541EP 0x1018
#define E1000_DEV_ID_82547EI 0x1019
-#define NUM_DEV_IDS 19
+#define NUM_DEV_IDS 20
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
@@ -601,7 +603,7 @@ struct e1000_ffvt_entry {
#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
#define E1000_EERD 0x00014 /* EEPROM Read - RW */
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
-#define E1000_FLA 0x0001C /* Flash Access Register - RW */
+#define E1000_FLA 0x0001C /* Flash Access - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
@@ -730,6 +732,7 @@ struct e1000_ffvt_entry {
* the registers function in the same manner.
*/
#define E1000_82542_CTRL E1000_CTRL
+#define E1000_82542_CTRL_DUP E1000_CTRL_DUP
#define E1000_82542_STATUS E1000_STATUS
#define E1000_82542_EECD E1000_EECD
#define E1000_82542_EERD E1000_EERD
@@ -1485,7 +1488,6 @@ struct e1000_hw {
#define E1000_COLLISION_DISTANCE 64
#define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
#define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
-#define E1000_GB_HDX_COLLISION_DISTANCE 512
#define E1000_COLD_SHIFT 12
/* The number of Transmit and Receive Descriptors must be a multiple of 8 */
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 86f15dbb0a21..377596f3f443 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -30,7 +30,14 @@
/* Change Log
*
- * 5.0.43 3/5/03
+ * 5.1.11 5/6/03
+ * o Feature: Added support for 82546EB (Quad-port) hardware.
+ * o Feature: Added support for Diagnostics through Ethtool.
+ * o Cleanup: Removed /proc support.
+ * o Cleanup: Removed proprietary IDIAG interface.
+ * o Bug fix: TSO bug fixes.
+ *
+ * 5.0.42 3/5/03
* o Feature: Added support for 82541 and 82547 hardware.
* o Feature: Added support for Intel Gigabit PHY (IGP) and a variety of
* eeproms.
@@ -46,51 +53,22 @@
* shared interrupt instances.
*
* 4.4.18 11/27/02
- * o Feature: Added user-settable knob for interrupt throttle rate (ITR).
- * o Cleanup: removed large static array allocations.
- * o Cleanup: C99 struct initializer format.
- * o Bug fix: restore VLAN settings when interface is brought up.
- * o Bug fix: return cleanly in probe if error in detecting MAC type.
- * o Bug fix: Wake up on magic packet by default only if enabled in eeprom.
- * o Bug fix: Validate MAC address in set_mac.
- * o Bug fix: Throw away zero-length Tx skbs.
- * o Bug fix: Make ethtool EEPROM acceses work on older versions of ethtool.
- *
- * 4.4.12 10/15/02
*/
char e1000_driver_name[] = "e1000";
char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "5.0.43-k3";
+char e1000_driver_version[] = "5.1.11-k1";
char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
*
- * Private driver_data field (last one) stores an index into e1000_strings
* Wildcard entries (PCI_ANY_ID) should come last
* Last entry must be all 0s
*
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
- * Class, Class Mask, String Index }
+ * Class, Class Mask, private data (not used) }
*/
static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
- /* Intel(R) PRO/1000 Network Connection */
- {0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0},
- {0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0},
- {0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0},
- {0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0},
- {0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0},
- {0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0},
- {0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0},
- /* Compaq Gigabit Ethernet Server Adapter */
- {0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1},
- {0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1},
- {0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1},
- /* IBM Mobile, Desktop & Server Adapters */
- {0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2},
- {0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2},
- {0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2},
- /* Generic */
{0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -106,6 +84,7 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
{0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
/* required last entry */
@@ -114,12 +93,6 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
-static char *e1000_strings[] = {
- "Intel(R) PRO/1000 Network Connection",
- "HP Gigabit Ethernet Server Adapter",
- "IBM Mobile, Desktop & Server Adapters"
-};
-
/* Local Function Prototypes */
int e1000_up(struct e1000_adapter *adapter);
@@ -130,7 +103,7 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
static int e1000_init_module(void);
static void e1000_exit_module(void);
static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
-static void e1000_remove(struct pci_dev *pdev);
+static void __devexit e1000_remove(struct pci_dev *pdev);
static int e1000_sw_init(struct e1000_adapter *adapter);
static int e1000_open(struct net_device *netdev);
static int e1000_close(struct net_device *netdev);
@@ -195,7 +168,6 @@ struct notifier_block e1000_notifier_reboot = {
.priority = 0
};
-
/* Exported from other modules */
extern void e1000_check_options(struct e1000_adapter *adapter);
@@ -234,8 +206,9 @@ e1000_init_module(void)
printk(KERN_INFO "%s\n", e1000_copyright);
ret = pci_module_init(&e1000_driver);
- if(ret >= 0)
+ if(ret >= 0) {
register_reboot_notifier(&e1000_notifier_reboot);
+ }
return ret;
}
@@ -439,7 +412,6 @@ e1000_probe(struct pci_dev *pdev,
netdev->base_addr = adapter->hw.io_base;
adapter->bd_number = cards_found;
- adapter->id_string = e1000_strings[ent->driver_data];
/* setup the private structure */
@@ -500,15 +472,14 @@ e1000_probe(struct pci_dev *pdev,
(void (*)(void *))e1000_tx_timeout_task, netdev);
register_netdev(netdev);
- memcpy(adapter->ifname, netdev->name, IFNAMSIZ);
- adapter->ifname[IFNAMSIZ-1] = 0;
/* we're going to reset, so assume we have no link for now */
netif_carrier_off(netdev);
netif_stop_queue(netdev);
- printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string);
+ printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Connection\n",
+ netdev->name);
e1000_check_options(adapter);
/* Initial Wake on LAN setting
@@ -568,7 +539,6 @@ e1000_remove(struct pci_dev *pdev)
e1000_phy_hw_reset(&adapter->hw);
-
iounmap(adapter->hw.hw_addr);
pci_release_regions(pdev);
@@ -831,8 +801,9 @@ e1000_configure_tx(struct e1000_adapter *adapter)
e1000_config_collision_dist(&adapter->hw);
- /* Setup Transmit Descriptor Settings for this adapter */
- adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE;
+ /* Setup Transmit Descriptor Settings for eop descriptor */
+ adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP |
+ E1000_TXD_CMD_IFCS;
if(adapter->hw.report_tx_early == 1)
adapter->txd_cmd |= E1000_TXD_CMD_RS;
@@ -1435,7 +1406,7 @@ e1000_watchdog(unsigned long data)
#define E1000_TX_FLAGS_VLAN_SHIFT 16
static inline boolean_t
-e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags)
+e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
{
#ifdef NETIF_F_TSO
struct e1000_context_desc *context_desc;
@@ -1471,7 +1442,7 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags)
context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse);
context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss);
context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
- context_desc->cmd_and_length = cpu_to_le32(adapter->txd_cmd |
+ context_desc->cmd_and_length = cpu_to_le32(
E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP |
(skb->len - (hdr_len)));
@@ -1504,8 +1475,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
context_desc->upper_setup.tcp_fields.tucso = cso;
context_desc->upper_setup.tcp_fields.tucse = 0;
context_desc->tcp_seg_setup.data = 0;
- context_desc->cmd_and_length =
- cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
+ context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
if(++i == adapter->tx_ring.count) i = 0;
adapter->tx_ring.next_to_use = i;
@@ -1520,7 +1490,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
#define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR)
static inline int
-e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
+e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb,
+ unsigned int first)
{
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
int len = skb->len, offset = 0, size, count = 0, i;
@@ -1588,6 +1559,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
}
if(--i < 0) i = tx_ring->count - 1;
tx_ring->buffer_info[i].skb = skb;
+ tx_ring->buffer_info[first].next_to_watch = i;
return count;
}
@@ -1597,12 +1569,9 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
{
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct e1000_tx_desc *tx_desc = NULL;
- uint32_t txd_upper, txd_lower;
+ uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS;
int i;
- txd_upper = 0;
- txd_lower = adapter->txd_cmd;
-
if(tx_flags & E1000_TX_FLAGS_TSO) {
txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
E1000_TXD_CMD_TSE;
@@ -1630,7 +1599,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
if(++i == tx_ring->count) i = 0;
}
- tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
+ tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
@@ -1690,6 +1659,7 @@ static int
e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev->priv;
+ unsigned int first;
int tx_flags = 0;
if(skb->len <= 0) {
@@ -1715,12 +1685,14 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
}
- if(e1000_tso(adapter, skb, tx_flags))
+ first = adapter->tx_ring.next_to_use;
+
+ if(e1000_tso(adapter, skb))
tx_flags |= E1000_TX_FLAGS_TSO;
else if(e1000_tx_csum(adapter, skb))
tx_flags |= E1000_TX_FLAGS_CSUM;
- e1000_tx_queue(adapter, e1000_tx_map(adapter, skb), tx_flags);
+ e1000_tx_queue(adapter, e1000_tx_map(adapter, skb, first), tx_flags);
netdev->trans_start = jiffies;
@@ -1952,6 +1924,7 @@ e1000_update_stats(struct e1000_adapter *adapter)
}
if((hw->mac_type <= e1000_82546) &&
+ (hw->phy_type == e1000_phy_m88) &&
!e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
adapter->phy_stats.receive_errors += phy_tmp;
}
@@ -2069,39 +2042,47 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
- struct e1000_tx_desc *tx_desc;
- int i, cleaned = FALSE;
+ struct e1000_tx_desc *tx_desc, *eop_desc;
+ struct e1000_buffer *buffer_info;
+ int i, eop, cleaned = FALSE;
i = tx_ring->next_to_clean;
- tx_desc = E1000_TX_DESC(*tx_ring, i);
+ eop = tx_ring->buffer_info[i].next_to_watch;
+ eop_desc = E1000_TX_DESC(*tx_ring, eop);
- while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+ while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
- cleaned = TRUE;
+ for(cleaned = FALSE; !cleaned; ) {
+ tx_desc = E1000_TX_DESC(*tx_ring, i);
+ buffer_info = &tx_ring->buffer_info[i];
- if(tx_ring->buffer_info[i].dma) {
+ if(buffer_info->dma) {
- pci_unmap_page(pdev,
- tx_ring->buffer_info[i].dma,
- tx_ring->buffer_info[i].length,
- PCI_DMA_TODEVICE);
+ pci_unmap_page(pdev,
+ buffer_info->dma,
+ buffer_info->length,
+ PCI_DMA_TODEVICE);
- tx_ring->buffer_info[i].dma = 0;
- }
+ buffer_info->dma = 0;
+ }
- if(tx_ring->buffer_info[i].skb) {
+ if(buffer_info->skb) {
- dev_kfree_skb_any(tx_ring->buffer_info[i].skb);
+ dev_kfree_skb_any(buffer_info->skb);
- tx_ring->buffer_info[i].skb = NULL;
- }
+ buffer_info->skb = NULL;
+ }
- tx_desc->buffer_addr = 0;
- tx_desc->lower.data = 0;
- tx_desc->upper.data = 0;
+ tx_desc->buffer_addr = 0;
+ tx_desc->lower.data = 0;
+ tx_desc->upper.data = 0;
- if(++i == tx_ring->count) i = 0;
- tx_desc = E1000_TX_DESC(*tx_ring, i);
+ cleaned = (i == eop);
+ if(++i == tx_ring->count) i = 0;
+ }
+
+ eop = tx_ring->buffer_info[i].next_to_watch;
+ eop_desc = E1000_TX_DESC(*tx_ring, eop);
}
tx_ring->next_to_clean = i;
@@ -2224,7 +2205,6 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
netif_rx(skb);
}
#endif /* CONFIG_E1000_NAPI */
-
netdev->last_rx = jiffies;
rx_desc->status = 0;
@@ -2677,7 +2657,6 @@ e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
return NOTIFY_DONE;
}
-
static int
e1000_suspend(struct pci_dev *pdev, uint32_t state)
{
diff --git a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c
index ded48bef9f82..7ce83879b811 100644
--- a/drivers/net/fc/iph5526.c
+++ b/drivers/net/fc/iph5526.c
@@ -134,7 +134,7 @@ clone_list[] __initdata = {
{0,}
};
-static void tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs);
static int initialize_register_pointers(struct fc_info *fi);
@@ -623,7 +623,7 @@ u_int bus_addr, bus_indx_addr, i;
}
-static void tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs)
+static irqreturn_t tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs)
{
struct Scsi_Host *host = dev_id;
struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
@@ -632,6 +632,7 @@ u_long flags;
spin_lock_irqsave(&fi->fc_lock, flags);
tachyon_interrupt_handler(irq, dev_id, regs);
spin_unlock_irqrestore(&fi->fc_lock, flags);
+ return IRQ_HANDLED;
}
static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs)
@@ -3720,12 +3721,13 @@ struct fc_info *fi = (struct fc_info*)dev->priv;
int iph5526_detect(Scsi_Host_Template *tmpt)
{
-struct Scsi_Host *host = NULL;
-struct iph5526_hostdata *hostdata;
-struct fc_info *fi = NULL;
-int no_of_hosts = 0, timeout, i, j, count = 0;
-u_int pci_maddr = 0;
-struct pci_dev *pdev = NULL;
+ struct Scsi_Host *host = NULL;
+ struct iph5526_hostdata *hostdata;
+ struct fc_info *fi = NULL;
+ int no_of_hosts = 0, i, j, count = 0;
+ u_int pci_maddr = 0;
+ struct pci_dev *pdev = NULL;
+ unsigned long timeout;
tmpt->proc_name = "iph5526";
if (pci_present() == 0) {
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 539e9d434d10..47ce93a052f2 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -188,7 +188,7 @@ struct fec_enet_private {
static int fec_enet_open(struct net_device *dev);
static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void fec_enet_mii(struct net_device *dev);
-static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
+static irqreturn_t fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
static void fec_enet_tx(struct net_device *dev);
static void fec_enet_rx(struct net_device *dev);
static int fec_enet_close(struct net_device *dev);
@@ -393,12 +393,13 @@ fec_timeout(struct net_device *dev)
/* The interrupt handler.
* This is called from the MPC core interrupt.
*/
-static void
+static irqreturn_t
fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
volatile fec_t *fecp;
uint int_events;
+ int handled = 0;
fecp = (volatile fec_t*)dev->base_addr;
@@ -413,20 +414,27 @@ fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
/* Handle receive event in its own function.
*/
- if (int_events & FEC_ENET_RXF)
+ if (int_events & FEC_ENET_RXF) {
+ handled = 1;
fec_enet_rx(dev);
+ }
/* Transmit OK, or non-fatal error. Update the buffer
descriptors. FEC handles all errors, we just discover
them as part of the transmit process.
*/
- if (int_events & FEC_ENET_TXF)
+ if (int_events & FEC_ENET_TXF) {
+ handled = 1;
fec_enet_tx(dev);
+ }
- if (int_events & FEC_ENET_MII)
+ if (int_events & FEC_ENET_MII) {
+ handled = 1;
fec_enet_mii(dev);
+ }
}
+ return IRQ_RETVAL(handled);
}
diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c
index 1e79b90e3718..be537a80fce7 100644
--- a/drivers/net/fmv18x.c
+++ b/drivers/net/fmv18x.c
@@ -114,7 +114,7 @@ extern int fmv18x_probe(struct net_device *dev);
static int fmv18x_probe1(struct net_device *dev, short ioaddr);
static int net_open(struct net_device *dev);
static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void net_rx(struct net_device *dev);
static void net_timeout(struct net_device *dev);
static int net_close(struct net_device *dev);
@@ -423,7 +423,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
-static void
+static irqreturn_t
net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
@@ -476,7 +476,7 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock(&lp->lock);
}
}
- return;
+ return IRQ_RETVAL(status);
}
/* We have a good packet(s), get it/them out of the buffers. */
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 538e35c128e8..1c5de989caaf 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -199,7 +199,7 @@ static void z8530_init(void);
static void init_channel(struct scc_channel *scc);
static void scc_key_trx (struct scc_channel *scc, char tx);
-static void scc_isr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs);
static void scc_init_timer(struct scc_channel *scc);
static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev);
@@ -625,7 +625,7 @@ static void scc_isr_dispatch(struct scc_channel *scc, int vector)
#define SCC_IRQTIMEOUT 30000
-static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned char vector;
struct scc_channel *scc;
@@ -653,7 +653,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
if (k == SCC_IRQTIMEOUT)
printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n");
- return;
+ return IRQ_HANDLED;
}
/* Find the SCC generating the interrupt by polling all attached SCCs
@@ -701,6 +701,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
} else
ctrl++;
}
+ return IRQ_HANDLED;
}
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 9f10842ab0dd..7f4e64360f15 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -541,6 +541,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct myri_channel *chan = &mp->shmem->channel;
unsigned long flags;
u32 status;
+ int handled = 0;
spin_lock_irqsave(&mp->irq_lock, flags);
@@ -549,6 +550,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & ISTAT_HOST) {
u32 softstate;
+ handled = 1;
DIRQ(("IRQ_DISAB "));
myri_disable_irq(lregs, mp->cregs);
softstate = sbus_readl(&chan->state);
@@ -568,7 +570,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock_irqrestore(&mp->irq_lock, flags);
- return IRQ_HANDLED;
+ return IRQ_RETVAL(handled);
}
static int myri_open(struct net_device *dev)
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index d0b1dc9ffa1a..08cd543eda47 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -84,7 +84,7 @@ static int seeq8005_probe1(struct net_device *dev, int ioaddr);
static int seeq8005_open(struct net_device *dev);
static void seeq8005_timeout(struct net_device *dev);
static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void seeq8005_rx(struct net_device *dev);
static int seeq8005_close(struct net_device *dev);
static struct net_device_stats *seeq8005_get_stats(struct net_device *dev);
@@ -400,11 +400,12 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
-static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
struct net_local *lp;
int ioaddr, status, boguscount = 0;
+ int handled = 0;
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
@@ -416,17 +417,20 @@ static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
if (status & SEEQSTAT_WINDOW_INT) {
+ handled = 1;
outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
if (net_debug) {
printk("%s: window int!\n",dev->name);
}
}
if (status & SEEQSTAT_TX_INT) {
+ handled = 1;
outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
lp->stats.tx_packets++;
netif_wake_queue(dev); /* Inform upper layers. */
}
if (status & SEEQSTAT_RX_INT) {
+ handled = 1;
/* Got a packet(s). */
seeq8005_rx(dev);
}
@@ -436,6 +440,7 @@ static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if(net_debug>2) {
printk("%s: eoi\n",dev->name);
}
+ return IRQ_RETVAL(handled);
}
/* We have a good packet(s), get it/them out of the buffers. */
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index a80a2f87c3e1..93949db1e758 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -124,6 +124,7 @@ static void qe_init_rings(struct sunqe *qep)
qb->qe_rxd[i].rx_flags =
(RXD_OWN | ((RXD_PKT_SZ) & RXD_LENGTH));
}
+ return IRQ_HANDLED;
}
static int qe_init(struct sunqe *qep, int from_irq)
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 455702a8cd18..d74cb55dc3d9 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -201,7 +201,7 @@ static int streamer_open(struct net_device *dev);
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);
static int streamer_close(struct net_device *dev);
static void streamer_set_rx_mode(struct net_device *dev);
-static void streamer_interrupt(int irq, void *dev_id,
+static irqreturn_t streamer_interrupt(int irq, void *dev_id,
struct pt_regs *regs);
static struct net_device_stats *streamer_get_stats(struct net_device *dev);
static int streamer_set_mac_address(struct net_device *dev, void *addr);
@@ -1021,7 +1021,7 @@ static void streamer_rx(struct net_device *dev)
} /* end for all completed rx descriptors */
}
-static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
struct streamer_private *streamer_priv =
@@ -1142,6 +1142,7 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} /* while() */
spin_unlock(&streamer_priv->streamer_lock) ;
+ return IRQ_HANDLED;
}
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 9a534bb64557..8a74d3280e73 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -2027,7 +2027,7 @@ set_multicast_list(struct net_device *dev)
}
}
- return;
+ return IRQ_HANDLED;
}
/*
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index d94ceadfcb9e..8685e91d5a9c 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -117,7 +117,7 @@ static int lmc_rx (struct net_device *dev);
static int lmc_open(struct net_device *dev);
static int lmc_close(struct net_device *dev);
static struct net_device_stats *lmc_get_stats(struct net_device *dev);
-static void lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static int lmc_set_config(struct net_device *dev, struct ifmap *map);
static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size);
static void lmc_softreset(lmc_softc_t * const);
@@ -1388,7 +1388,7 @@ static int lmc_ifdown (struct net_device *dev) /*fold00*/
/* Interrupt handling routine. This will take an incoming packet, or clean
* up after a trasmit.
*/
-static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
+static irqreturn_t lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
{
struct net_device *dev = (struct net_device *) dev_instance;
lmc_softc_t *sc;
@@ -1398,6 +1398,7 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
unsigned int badtx;
u32 firstcsr;
int max_work = LMC_RXDESCS;
+ int handled = 0;
lmc_trace(dev, "lmc_interrupt in");
@@ -1421,6 +1422,8 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
/* always go through this loop at least once */
while (csr & sc->lmc_intrmask) {
+ handled = 1;
+
/*
* Clear interrupt bits, we handle all case below
*/
@@ -1580,6 +1583,7 @@ lmc_int_fail_out:
spin_unlock(&sc->lmc_lock);
lmc_trace(dev, "lmc_interrupt out");
+ return IRQ_RETVAL(handled);
}
static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/
diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h
index 8ddb454c85b5..b706151a0003 100644
--- a/include/linux/arcdevice.h
+++ b/include/linux/arcdevice.h
@@ -329,7 +329,7 @@ void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc);
#endif
void arcnet_unregister_proto(struct ArcProto *proto);
-void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
void arcdev_setup(struct net_device *dev);
void arcnet_rx(struct net_device *dev, int bufnum);