diff -Nuarp linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_main.c linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_main.c
--- linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_main.c	Mon Aug 26 19:32:44 2002
+++ linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_main.c	Mon Aug 26 20:25:18 2002
@@ -46,6 +46,21 @@
 
 /* Change Log
  *
+ * 2.1.12       8/2/02
+ *   o Feature: ethtool register dump
+ *   o Bug fix: Driver passes wrong name to /proc/interrupts
+ *   o Bug fix: Ethernet bridging not working 
+ *   o Bug fix: Promiscuous mode is not working
+ *   o Bug fix: Checked return value from copy_from_user (William Stinson,
+ *     wstinson@infonie.fr)
+ *   o Bug fix: ARP wake on LAN fails
+ *   o Bug fix: mii-diag does not update driver level's speed, duplex and
+ *     re-configure flow control
+ *   o Bug fix: Ethtool shows wrong speed/duplex when not connected
+ *   o Bug fix: Ethtool shows wrong speed/duplex when reconnected if forced 
+ *     speed/duplex
+ *   o Bug fix: PHY loopback diagnostic fails
+ *
  * 2.1.6        7/5/02
  *   o Added device ID support for Dell LOM.
  *   o Added device ID support for 82511QM mobile nics.
@@ -128,7 +143,7 @@ static void e100_non_tx_background(unsig
 
 /* Global Data structures and variables */
 char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-char e100_driver_version[]="2.1.6-k1";
+char e100_driver_version[]="2.1.15-k1";
 const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
 char e100_short_driver_name[] = "e100";
 static int e100nics = 0;
@@ -731,16 +746,6 @@ e100_remove1(struct pci_dev *pcid)
 		bdp->non_tx_command_state = E100_NON_TX_IDLE;
 	}
 
-	/* Set up wol options and enable PME if wol is enabled */
-	if (bdp->wolopts) {
-		e100_do_wol(pcid, bdp);
-		/* Enable PME for power state D3 */
-		pci_enable_wake(pcid, 3, 1);
-		/* Set power state to D1 in case driver is RELOADED */
-		/* If system powers down, device is switched from D1 to D3 */
-		pci_set_power_state(pcid, 1);
-	}
-
 	e100_clear_structs(dev);
 
 	--e100nics;
@@ -1011,7 +1016,9 @@ e100_close(struct net_device *dev)
 	bdp->intr_mask = SCB_INT_MASK;
 	e100_isolate_driver(bdp);
 
-	bdp->ip_lbytes = e100_get_ip_lbytes(dev);
+	netif_carrier_off(bdp->device);
+	bdp->cur_line_speed = 0;
+	bdp->cur_dplx_mode = 0;
 	free_irq(dev->irq, dev);
 	e100_clear_pools(bdp);
 
@@ -3345,9 +3352,15 @@ e100_ethtool_get_settings(struct net_dev
 	ecmd.transceiver = XCVR_INTERNAL;
 	ecmd.phy_address = bdp->phy_addr;
 
-	ecmd.speed = bdp->cur_line_speed;
-	ecmd.duplex =
-		(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
+	if (netif_carrier_ok(bdp->device)) {
+		ecmd.speed = bdp->cur_line_speed;
+		ecmd.duplex =
+			(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
+	}
+	else {
+		ecmd.speed = -1;
+		ecmd.duplex = -1;
+	}
 
 	ecmd.advertising = ADVERTISED_TP;
 
@@ -3469,7 +3482,8 @@ e100_ethtool_glink(struct net_device *de
 	bdp = dev->priv;
 	info.cmd = ETHTOOL_GLINK;
 
-	info.data = e100_get_link_state(bdp);
+	/* Consider both PHY link and netif_running */
+	info.data = e100_update_link_state(bdp);
 
 	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
 		return -EFAULT;
@@ -3882,7 +3896,6 @@ e100_ethtool_wol(struct net_device *dev,
 		if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo)))
 			res = -EFAULT;
 		break;
-
 	case ETHTOOL_SWOL:
 		/* If ALL requests are supported or request is DISABLE wol */
 		if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts)
@@ -3891,6 +3904,8 @@ e100_ethtool_wol(struct net_device *dev,
 		} else {
 			res = -EOPNOTSUPP;
 		}
+		if (wolinfo.wolopts & WAKE_ARP)
+			bdp->ip_lbytes = e100_get_ip_lbytes(dev);
 		break;
 	default:
 		break;
@@ -3968,8 +3983,30 @@ e100_mii_ioctl(struct net_device *dev, s
 		if (netif_running(dev)) {
 			return -EBUSY;
 		}
-		e100_mdi_write(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr,
+		/* If reg = 0 && change speed/duplex */
+		if (data_ptr->reg_num == 0 && 
+			(data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */
+			|| data_ptr->val_in == (BMCR_RESET) /* reset cmd */ 
+			|| data_ptr->val_in & (BMCR_SPEED100 | BMCR_FULLDPLX) 
+			|| data_ptr->val_in == 0)) {
+				if (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART)
+					|| data_ptr->val_in == (BMCR_RESET))
+					bdp->params.e100_speed_duplex = E100_AUTONEG;
+				else if (data_ptr->val_in == (BMCR_SPEED100 | BMCR_FULLDPLX))
+					bdp->params.e100_speed_duplex = E100_SPEED_100_FULL;
+				else if (data_ptr->val_in == (BMCR_SPEED100))
+					bdp->params.e100_speed_duplex = E100_SPEED_100_HALF;
+				else if (data_ptr->val_in == (BMCR_FULLDPLX))
+					bdp->params.e100_speed_duplex = E100_SPEED_10_FULL;
+				else
+					bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
+				e100_set_speed_duplex(bdp);
+		}
+		else {
+			e100_mdi_write(bdp, data_ptr->reg_num, bdp->phy_addr,
 			       data_ptr->val_in);
+		}
+		
 		break;
 
 	default:
@@ -4140,8 +4177,6 @@ static int
 e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
 {
         struct pci_dev *pdev = NULL;
-	struct net_device *netdev;
-	struct e100_private *bdp;
 	
         switch(event) {
         case SYS_DOWN:
@@ -4149,18 +4184,10 @@ e100_notify_reboot(struct notifier_block
         case SYS_POWER_OFF:
                 pci_for_each_dev(pdev) {
                         if(pci_dev_driver(pdev) == &e100_driver) {
-				netdev = pci_get_drvdata(pdev);
 				/* If net_device struct is allocated? */
-                                if (netdev) {
-					bdp = netdev->priv;
-					if (bdp->wolopts) {
-						bdp->ip_lbytes = 
-							e100_get_ip_lbytes(netdev);
-						e100_do_wol(pdev, bdp);
-						pci_enable_wake(pdev, 3, 1);
-						pci_set_power_state(pdev, 3);
-					}
-				}
+                                if (pci_get_drvdata(pdev))
+					e100_suspend(pdev, 3);
+
 			}
 		}
         }
@@ -4178,7 +4205,6 @@ e100_suspend(struct pci_dev *pcid, u32 s
 
 	/* If wol is enabled */
 	if (bdp->wolopts) {
-		bdp->ip_lbytes = e100_get_ip_lbytes(netdev);
 		e100_do_wol(pcid, bdp);
 		pci_enable_wake(pcid, 3, 1);	/* Enable PME for power state D3 */
 		pci_set_power_state(pcid, 3);	/* Set power state to D3.        */
@@ -4187,7 +4213,6 @@ e100_suspend(struct pci_dev *pcid, u32 s
 		pci_disable_device(pcid);
 		pci_set_power_state(pcid, state);
 	}
-
 	return 0;
 }
 
@@ -4215,7 +4240,6 @@ e100_resume(struct pci_dev *pcid)
 
 	return 0;
 }
-
 #endif /* CONFIG_PM */
 
 static void
diff -Nuarp linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_phy.c linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_phy.c
--- linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_phy.c	Mon Aug 26 19:21:14 2002
+++ linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_phy.c	Mon Aug 26 20:21:24 2002
@@ -45,11 +45,12 @@ void e100_handle_zlock(struct e100_priva
  * Returns:
  *	NOTHING
  */
-void
+int
 e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data)
 {
 	int e100_retry;
 	u32 temp_val;
+	unsigned int mdi_cntrl;
 
 	spin_lock_bh(&bdp->mdi_access_lock);
 	temp_val = (((u32) data) | (reg_addr << 16) |
@@ -62,13 +63,18 @@ e100_mdi_write(struct e100_private *bdp,
 
 	/* poll for the mdi write to complete */
 	e100_retry = E100_CMD_WAIT;
-	while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) &&
-	       (e100_retry)) {
+	while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {
 
 		udelay(20);
 		e100_retry--;
 	}
 	spin_unlock_bh(&bdp->mdi_access_lock);
+	if (mdi_cntrl & MDI_PHY_READY) 
+		return 0;
+	else {
+		printk(KERN_ERR "e100: MDI write timeout\n");
+		return 1;
+	}
 }
 
 /* 
@@ -90,11 +96,12 @@ e100_mdi_write(struct e100_private *bdp,
  * Returns:
  *	NOTHING
  */
-void
+int
 e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data)
 {
 	int e100_retry;
 	u32 temp_val;
+	unsigned int mdi_cntrl;
 
 	spin_lock_bh(&bdp->mdi_access_lock);
 	/* Issue the read command to the MDI control register. */
@@ -107,16 +114,22 @@ e100_mdi_read(struct e100_private *bdp, 
 
 	/* poll for the mdi read to complete */
 	e100_retry = E100_CMD_WAIT;
-	while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) &&
-	       (e100_retry)) {
+	while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {
 
 		udelay(20);
 		e100_retry--;
 	}
 
-	// return the lower word
-	*data = (u16) readl(&bdp->scb->scb_mdi_cntrl);
 	spin_unlock_bh(&bdp->mdi_access_lock);
+	if (mdi_cntrl & MDI_PHY_READY) {
+		/* return the lower word */
+		*data = (u16) mdi_cntrl;
+		return 0;
+	}
+	else {
+		printk(KERN_ERR "e100: MDI read timeout\n");
+		return 1;
+	}
 }
 
 static unsigned char __devinit
@@ -480,10 +493,8 @@ e100_find_speed_duplex(struct e100_priva
 	/* First we should check to see if we have link */
 	/* If we don't have a link no reason to print a speed and duplex */
 	if (!e100_update_link_state(bdp)) {
-		return;
-	}
-
-	if (bdp->flags & DF_SPEED_FORCED) {
+		bdp->cur_line_speed = 0;
+		bdp->cur_dplx_mode = 0;
 		return;
 	}
 
@@ -617,10 +628,13 @@ e100_force_speed_duplex(struct e100_priv
 	u16 control;
 	unsigned long expires;
 
+	e100_phy_reset(bdp);
+
 	bdp->flags |= DF_SPEED_FORCED;
 
 	e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
 	control &= ~BMCR_ANENABLE;
+	control &= ~BMCR_LOOPBACK;
 
 	/* Check e100.c values */
 	switch (bdp->params.e100_speed_duplex) {
@@ -838,7 +852,7 @@ e100_phy_set_speed_duplex(struct e100_pr
 }
 
 void
-e100_phy_reset(struct e100_private *bdp)
+e100_phy_autoneg(struct e100_private *bdp)
 {
 	u16 ctrl_reg;
 
@@ -849,6 +863,23 @@ e100_phy_reset(struct e100_private *bdp)
 	udelay(100);
 }
 
+void
+e100_phy_set_loopback(struct e100_private *bdp)
+{
+	u16 ctrl_reg;
+	ctrl_reg = BMCR_LOOPBACK;
+	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+		udelay(100);
+}
+	
+void
+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);
+}
+
 unsigned char __devinit
 e100_phy_init(struct e100_private *bdp)
 {
@@ -915,7 +946,8 @@ e100_get_link_state(struct e100_private 
 /* 
  * Procedure: e100_update_link_state
  * 
- * Description: This routine updates the link status of the adapter
+ * Description: This routine updates the link status of the adapter,
+ * 		also considering netif_running
  *
  * Arguments:  bdp - Pointer to the e100_private structure for the board
  *		    
@@ -929,7 +961,8 @@ e100_update_link_state(struct e100_priva
 {
 	unsigned char link;
 
-	link = e100_get_link_state(bdp);
+	/* Logical AND PHY link & netif_running */
+	link = e100_get_link_state(bdp) && netif_running(bdp->device);
 
 	if (link) {
 		if (!netif_carrier_ok(bdp->device))
diff -Nuarp linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_phy.h linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_phy.h
--- linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_phy.h	Mon Aug 26 19:21:14 2002
+++ linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_phy.h	Mon Aug 26 20:21:24 2002
@@ -151,8 +151,10 @@ extern unsigned char e100_update_link_st
 extern unsigned char e100_phy_check(struct e100_private *bdp);
 extern void e100_phy_set_speed_duplex(struct e100_private *bdp,
 				      unsigned char force_restart);
+extern void e100_phy_autoneg(struct e100_private *bdp);
 extern void e100_phy_reset(struct e100_private *bdp);
-extern void e100_mdi_write(struct e100_private *, u32, u32, u16);
-extern void e100_mdi_read(struct e100_private *, u32, u32, u16 *);
+extern void e100_phy_set_loopback(struct e100_private *bdp);
+extern int e100_mdi_write(struct e100_private *, u32, u32, u16);
+extern int e100_mdi_read(struct e100_private *, u32, u32, u16 *);
 
 #endif
diff -Nuarp linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_proc.c linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_proc.c
--- linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_proc.c	Mon Aug 26 19:21:14 2002
+++ linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_proc.c	Mon Aug 26 20:21:24 2002
@@ -61,7 +61,7 @@ extern char e100_short_driver_name[];
 extern char e100_driver_version[];
 extern struct net_device_stats *e100_get_stats(struct net_device *dev);
 extern char *e100_get_brand_msg(struct e100_private *bdp);
-extern void e100_mdi_write(struct e100_private *, u32, u32, u16);
+extern int e100_mdi_write(struct e100_private *, u32, u32, u16);
 
 static void e100_proc_cleanup(void);
 static unsigned char e100_init_proc_dir(void);
diff -Nuarp linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_test.c linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_test.c
--- linux-2.4.20-pre4-e100-3/drivers/net/e100/e100_test.c	Mon Aug 26 19:21:14 2002
+++ linux-2.4.20-pre4-e100-4/drivers/net/e100/e100_test.c	Mon Aug 26 20:21:24 2002
@@ -31,6 +31,9 @@
 extern u16 e100_eeprom_read(struct e100_private *, u16);
 extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8);
 extern void e100_phy_reset(struct e100_private *bdp);
+extern void e100_phy_autoneg(struct e100_private *bdp);
+extern void e100_phy_set_loopback(struct e100_private *bdp);
+extern void e100_force_speed_duplex(struct e100_private *bdp);
 
 static u8 e100_diag_selftest(struct net_device *);
 static u8 e100_diag_eeprom(struct net_device *);
@@ -239,6 +242,7 @@ e100_diag_config_loopback(struct e100_pr
 		 *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd);
 
 	if (set_loopback) {
+		/* Configure loopback on MAC */
 		e100_config_loopback_mode(bdp,loopback_mode);
 	} else {
 		e100_config_loopback_mode(bdp,NO_LOOPBACK);
@@ -247,16 +251,20 @@ e100_diag_config_loopback(struct e100_pr
 	e100_config(bdp);
 
 	if (loopback_mode == PHY_LOOPBACK) {
-		unsigned long expires = jiffies + HZ * 5;
-
 		if (set_loopback)
-			e100_phy_reset(bdp);
-
-		/* wait up to 5 secs for PHY loopback ON/OFF to take effect */
-		while ((e100_get_link_state(bdp) != set_loopback) &&
-		       time_before(jiffies, expires)) {
-			yield();
+                        /* 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 */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+                schedule_timeout(HZ);
 	} else { /* For MAC loopback wait 500 msec to take effect */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(HZ / 2);
@@ -276,6 +284,7 @@ e100_diag_loopback_alloc(struct e100_pri
 	rfd_t *rfd;
 	tbd_t *tbd;
 
+	/* tcb, tbd and transmit buffer are allocated */
 	tcb = pci_alloc_consistent(bdp->pdev,
 				   (sizeof (tcb_t) + sizeof (tbd_t) +
 				    LB_PACKET_SIZE),
@@ -283,22 +292,26 @@ e100_diag_loopback_alloc(struct e100_pri
         if (tcb == NULL)
 		return false;
 
-	memset(tcb, 0x00, sizeof (tcb_t) + LB_PACKET_SIZE);
+	memset(tcb, 0x00, sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE);
 	tcb->tcb_phys = dma_handle;
 	tcb->tcb_hdr.cb_status = 0;
 	tcb->tcb_hdr.cb_cmd =
 		cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT);
-	tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(tcb->tcb_phys);
-	tcb->tcb_tbd_ptr = cpu_to_le32(0xffffffff);
+	/* Next command is null */
+	tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(0xffffffff);
 	tcb->tcb_cnt = 0;
 	tcb->tcb_thrshld = bdp->tx_thld;
 	tcb->tcb_tbd_num = 1;
+	/* Set up tcb tbd pointer */
 	tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t));
 	tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t));
+	/* Set up tbd transmit buffer */
 	tbd->tbd_buf_addr =
 		cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t));
 	tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024);
-	memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 1024);
+	/* The value of first 512 bytes is FF */
+	memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 512);
+	/* The value of second 512 bytes is BA */
 	memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512);
 	wmb();
 	rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle);
@@ -313,10 +326,9 @@ e100_diag_loopback_alloc(struct e100_pri
 	memset(rfd, 0x00, sizeof (rfd_t));
 
 	/* init all fields in rfd */
-	rfd->rfd_header.cb_status = 0;
 	rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT);
-	rfd->rfd_act_cnt = 0;
 	rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE);
+	/* dma_handle is physical address of rfd */
 	bdp->loopback.dma_handle = dma_handle;
 	bdp->loopback.tcb = tcb;
 	bdp->loopback.rfd = rfd;
@@ -354,12 +366,15 @@ e100_diag_loopback_cu_ru_exec(struct e10
 static u8
 e100_diag_check_pkt(u8 *datap)
 {
-        if( (*datap)==0xFF) {
-                if(*(datap + 600) == 0xBA) {
-                        return true;
-                }
-        }
-        return false;
+	int i;
+	for (i = 0; i<512; i++) {
+		if( !((*datap)==0xFF && (*(datap + 512) == 0xBA)) ) {
+			printk (KERN_ERR "e100: check loopback packet failed at: %x\n", i);
+			return false;
+			}
+	}
+	printk (KERN_DEBUG "e100: Check received loopback packet OK\n");
+	return true;
 }
 
 /**
@@ -389,10 +404,14 @@ e100_diag_rcv_loopback_pkt(struct e100_p
 		}
         }
 
-        if (rfd_status & RFD_STATUS_COMPLETE)
+        if (rfd_status & RFD_STATUS_COMPLETE) {
+		printk(KERN_DEBUG "e100: Loopback packet received\n");
                 return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size));
-	else
+	}
+	else {
+		printk(KERN_ERR "e100: Loopback packet not received\n");
 		return false;
+	}
 }
 
 /**
