patch-2.4.22 linux-2.4.22/drivers/net/e100/e100_main.c

Next file: linux-2.4.22/drivers/net/e100/e100_phy.c
Previous file: linux-2.4.22/drivers/net/e100/e100.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/drivers/net/e100/e100_main.c linux-2.4.22/drivers/net/e100/e100_main.c
@@ -46,36 +46,32 @@
 
 /* Change Log
  * 
- * 2.2.21	02/11/03
- * o Removed marketing brand strings. Instead, Using generic string 
- *   "Intel(R) PRO/100 Network Connection" for all adapters.
- * o Implemented ethtool -S option
- * o Strip /proc/net/PRO_LAN_Adapters files for kernel driver
- * o Bug fix: Read wrong byte in EEPROM when offset is odd number
- * o Bug fix: PHY loopback test fails on ICH devices
- * o Bug fix: System panic on e100_close when repeating Hot Remove and 
- *   Add in a team
- * o Bug fix: Linux Bonding driver claims adapter's link loss because of
- *   not updating last_rx field
- * o Bug fix: e100 does not check validity of MAC address
- * o New feature: added ICH5 support
+ * 2.3.18       07/08/03
+ * o Bug fix: read skb->len after freeing skb
+ *   [Andrew Morton] akpm@zip.com.au
+ * o Bug fix: 82557 (with National PHY) timeout during init
+ *   [Adam Kropelin] akropel1@rochester.rr.com
+ * o Feature add: allow to change Wake On LAN when EEPROM disabled
  * 
- * 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
+ * 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
  */
  
 #include <linux/config.h>
@@ -121,14 +117,13 @@
 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 +134,10 @@
 						  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.18-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 +150,7 @@
 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 +178,6 @@
 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 +187,6 @@
 static void e100intr(int, void *, struct pt_regs *);
 static void e100_print_brd_conf(struct e100_private *);
 static void e100_set_multi(struct net_device *);
-void e100_set_speed_duplex(struct e100_private *);
 
 static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
 static u8 e100_sw_init(struct e100_private *);
@@ -215,7 +208,6 @@
 
 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 +220,6 @@
 				 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
@@ -638,25 +629,7 @@
 	} else {
 		bdp->rfd_size = 16;
 	}
-	e100_check_options(e100nics, bdp);
 
-	if (!e100_init(bdp)) {
-		printk(KERN_ERR "e100: Failed to initialize, instance #%d\n",
-		       e100nics);
-		rc = -ENODEV;
-		goto err_pci;
-	}
-
-	/* Check if checksum is valid */
-	cal_checksum = e100_eeprom_calculate_chksum(bdp);
-	read_checksum = e100_eeprom_read(bdp, (bdp->eeprom_size - 1));
-	if (cal_checksum != read_checksum) {
-                printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n",
-		       e100nics);
-                rc = -ENODEV;
-                goto err_pci;
-	}
-	
 	dev->vlan_rx_register = e100_vlan_rx_register;
 	dev->vlan_rx_add_vid = e100_vlan_rx_add_vid;
 	dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid;
@@ -674,15 +647,32 @@
 	dev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
 			NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 		
-	e100nics++;
-
-	e100_get_speed_duplex_caps(bdp);
-
 	if ((rc = register_netdev(dev)) != 0) {
 		goto err_pci;
 	}
-        memcpy(bdp->ifname, dev->name, IFNAMSIZ);
-        bdp->ifname[IFNAMSIZ-1] = 0;	
+
+	e100_check_options(e100nics, bdp);
+
+	if (!e100_init(bdp)) {
+		printk(KERN_ERR "e100: Failed to initialize, instance #%d\n",
+		       e100nics);
+		rc = -ENODEV;
+		goto err_unregister_netdev;
+	}
+
+	/* Check if checksum is valid */
+	cal_checksum = e100_eeprom_calculate_chksum(bdp);
+	read_checksum = e100_eeprom_read(bdp, (bdp->eeprom_size - 1));
+	if (cal_checksum != read_checksum) {
+                printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n",
+		       e100nics);
+                rc = -ENODEV;
+                goto err_unregister_netdev;
+	}
+	
+	e100nics++;
+
+	e100_get_speed_duplex_caps(bdp);
 
 	printk(KERN_NOTICE
 	       "e100: %s: %s\n", 
@@ -691,23 +681,24 @@
 
 	bdp->wolsupported = 0;
 	bdp->wolopts = 0;
+	if (bdp->rev_id >= D101A4_REV_ID)
+		bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
+	if (bdp->rev_id >= D101MA_REV_ID)
+		bdp->wolsupported |= WAKE_UCAST | WAKE_ARP;
 	
 	/* Check if WoL is enabled on EEPROM */
 	if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) {
 		/* Magic Packet WoL is enabled on device by default */
 		/* if EEPROM WoL bit is TRUE                        */
-		bdp->wolsupported = WAKE_MAGIC;
 		bdp->wolopts = WAKE_MAGIC;
-		if (bdp->rev_id >= D101A4_REV_ID)
-			bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
-		if (bdp->rev_id >= D101MA_REV_ID)
-			bdp->wolsupported |= WAKE_UCAST | WAKE_ARP;
 	}
 
 	printk(KERN_NOTICE "\n");
 
 	goto out;
 
+err_unregister_netdev:
+	unregister_netdev(dev);
 err_pci:
 	iounmap(bdp->scb);
 	pci_release_regions(pcid);
@@ -973,7 +964,7 @@
 	}
 }
 
-static int
+int
 e100_open(struct net_device *dev)
 {
 	struct e100_private *bdp;
@@ -1011,7 +1002,11 @@
 
 	mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
 
-	netif_start_queue(dev);
+	if (dev->flags & IFF_UP)
+		/* Otherwise process may sleep forever */
+		netif_wake_queue(dev);
+	else
+		netif_start_queue(dev);
 
 	e100_start_ru(bdp);
 	if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ,
@@ -1032,7 +1027,7 @@
 	return rc;
 }
 
-static int
+int
 e100_close(struct net_device *dev)
 {
 	struct e100_private *bdp = dev->priv;
@@ -1073,17 +1068,18 @@
 		goto exit2;
 	}
 
-	if (!TCBS_AVAIL(bdp->tcb_pool) ||
+	/* tcb list may be empty temporarily during releasing resources */
+	if (!TCBS_AVAIL(bdp->tcb_pool) || (bdp->tcb_phys == 0) ||
 	    (bdp->non_tx_command_state != E100_NON_TX_IDLE)) {
 		notify_stop = true;
 		rc = 1;
 		goto exit1;
 	}
 
-	e100_prepare_xmit_buff(bdp, skb);
-
 	bdp->drv_stats.net_stats.tx_bytes += skb->len;
 
+	e100_prepare_xmit_buff(bdp, skb);
+
 	dev->trans_start = jiffies;
 
 exit1:
@@ -1284,10 +1280,8 @@
 	/* 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);
 
@@ -1329,6 +1323,8 @@
 	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;
 }
@@ -1383,11 +1379,11 @@
  *      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);
 
@@ -1397,27 +1393,25 @@
 
 	/* 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
@@ -1430,6 +1424,9 @@
 	}
 
 	return true;
+err:
+	printk(KERN_ERR "e100: hw init failed\n");
+	return false;
 }
 
 /**
@@ -1590,9 +1587,22 @@
 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;
 }
 
@@ -1746,12 +1756,10 @@
 				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();
 
@@ -2050,13 +2058,14 @@
 			skb->ip_summed = CHECKSUM_NONE;
 		}
 
+		bdp->drv_stats.net_stats.rx_bytes += skb->len;
+
 		if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) {
 			vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid));
 		} else {
 			netif_rx(skb);
 		}
 		dev->last_rx = jiffies;
-		bdp->drv_stats.net_stats.rx_bytes += skb->len;
 		
 		rfd_cnt++;
 	}			/* end of rfd loop */
@@ -2199,10 +2208,10 @@
 
 		(tcb->tbd_ptr)->tbd_buf_addr =
 			cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
-						   (skb->len - skb->data_len),
+						   skb_headlen(skb),
 						   PCI_DMA_TODEVICE));
 		(tcb->tbd_ptr)->tbd_buf_cnt =
-			cpu_to_le16(skb->len - skb->data_len);
+			cpu_to_le16(skb_headlen(skb));
 
 		for (i = 0; i < skb_shinfo(skb)->nr_frags;
 		     i++, tbd_arr_ptr++, frag++) {
@@ -2542,6 +2551,7 @@
 	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;
 	}
 
@@ -3039,23 +3049,6 @@
 	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)
 {
@@ -3211,6 +3204,144 @@
 	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
@@ -3284,10 +3415,6 @@
 	int ethtool_new_speed_duplex;
 	struct ethtool_cmd ecmd;
 
-	if (!capable(CAP_NET_ADMIN)) {
-		return -EPERM;
-	}
-
 	bdp = dev->priv;
 	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) {
 		return -EFAULT;
@@ -3296,7 +3423,13 @@
 	if ((ecmd.autoneg == AUTONEG_ENABLE)
 	    && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) {
 		bdp->params.e100_speed_duplex = E100_AUTONEG;
-		e100_set_speed_duplex(bdp);
+		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);
+		}
 	} else {
 		if (ecmd.speed == SPEED_10) {
 			if (ecmd.duplex == DUPLEX_HALF) {
@@ -3327,7 +3460,13 @@
 		if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
 			bdp->params.e100_speed_duplex =
 				e100_new_speed_duplex;
-			e100_set_speed_duplex(bdp);
+			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);
+			}
 		} else {
 			return -EOPNOTSUPP;
 		} 
@@ -3362,14 +3501,14 @@
 	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;
@@ -3377,7 +3516,7 @@
 	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);
@@ -3391,9 +3530,8 @@
 	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;
 	bdp = dev->priv;
 
 	if(copy_from_user(&regs, addr, sizeof(regs)))
@@ -3403,6 +3541,8 @@
 	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;
@@ -3419,14 +3559,17 @@
 {
 	struct e100_private *bdp;
 
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
 	bdp = dev->priv;
 
 	if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) &&
 	    (bdp->params.e100_speed_duplex == E100_AUTONEG)) {
-		e100_set_speed_duplex(bdp);
+		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);
+		}
 	} else {
 		return -EFAULT;
 	}
@@ -3452,7 +3595,7 @@
 	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;
 
@@ -3471,9 +3614,6 @@
 	void *ptr;
 	u8 *eeprom_data_bytes = (u8 *)eeprom_data;
 
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
 	bdp = dev->priv;
 
 	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
@@ -3751,9 +3891,6 @@
 	struct ethtool_wolinfo wolinfo;
 	int res = 0;
 
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
 	bdp = dev->priv;
 
 	if (copy_from_user(&wolinfo, ifr->ifr_data, sizeof (wolinfo))) {
@@ -3802,15 +3939,15 @@
 	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)))
@@ -3879,7 +4016,13 @@
 					bdp->params.e100_speed_duplex = E100_SPEED_10_FULL;
 				else
 					bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
-				e100_set_speed_duplex(bdp);
+				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);
+				}
 		}
 		else 
 			/* Only allows changing speed/duplex */
@@ -4105,13 +4248,13 @@
 static int
 e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
 {
-        struct pci_dev *pdev;
+        struct pci_dev *pdev = NULL;
 	
         switch(event) {
         case SYS_DOWN:
         case SYS_HALT:
         case SYS_POWER_OFF:
-                pci_for_each_dev(pdev) {
+		while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
                         if(pci_dev_driver(pdev) == &e100_driver) {
 				/* If net_device struct is allocated? */
                                 if (pci_get_drvdata(pdev))
@@ -4162,7 +4305,6 @@
 
 	return 0;
 }
-#endif /* CONFIG_PM */
 
 /**
  * e100_asf_enabled - checks if ASF is configured on the current adaper
@@ -4188,6 +4330,7 @@
 	}
 	return false;
 }
+#endif /* CONFIG_PM */
 
 #ifdef E100_CU_DEBUG
 unsigned char

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)