patch-2.4.23 linux-2.4.23/drivers/net/e1000/e1000_main.c

Next file: linux-2.4.23/drivers/net/e1000/e1000_osdep.h
Previous file: linux-2.4.23/drivers/net/e1000/e1000_hw.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/drivers/net/e1000/e1000_main.c linux-2.4.23/drivers/net/e1000/e1000_main.c
@@ -30,27 +30,41 @@
 
 /* Change Log
  *
- * 5.1.13	5/28/03
- *   o Bug fix: request_irq() failure resulted in freeing resources twice!
- *     [Don Fry (brazilnut@us.ibm.com)]
- *   o Bug fix: fix VLAN support on ppc64 [Mark Rakes (mrakes@vivato.net)]
- *   o Bug fix: missing Tx cleanup opportunities during interrupt handling.
- *   o Bug fix: alloc_etherdev failure didn't cleanup regions in probe.
- *   o Cleanup: s/int/unsigned int/ for descriptor ring indexes.
+ * 5.2.20	9/30/03
+ *   o Bug fix: SERDES devices might be connected to a back-plane
+ *     switch that doesn't support auto-neg, so add the capability
+ *     to force 1000/Full.
+ *   o Bug fix: Flow control settings for hi/lo watermark didn't
+ *     consider changes in the Rx FIFO size, which could occur with
+ *     Jumbo Frames or with the reduced FIFO in 82547.
+ *   o Better propagation of error codes. [Janice Girouard 
+ *     (janiceg@us.ibm.com)].
+ *   o Bug fix: hang under heavy Tx stress when running out of Tx
+ *     descriptors; wasn't clearing context descriptor when backing
+ *     out of send because of no-resource condition.
+ *
+ * 5.2.16	8/8/03
+ *   o Added support for new controllers: 82545GM, 82546GB, 82541/7_B1
+ *   o Bug fix: reset h/w before first EEPROM read because we don't know
+ *     who may have been messing with the device before we got there.
+ *     [Dave Johnson (ddj -a-t- cascv.brown.edu)]
+ *   o Bug fix: read the correct work from EEPROM to detect programmed
+ *     WoL settings.
+ *   o Bug fix: TSO would hang if space left in FIFO was being miscalculated
+ *     when mss dropped without a correspoding drop in the DMA buffer size.
+ *   o ASF for Fiber nics isn't supported.
+ *   o Bug fix: Workaround added for potential hang with 82544 running in
+ *     PCI-X if send buffer terminates within an evenly-aligned dword.
+ *   o Feature: Add support for ethtool flow control setting.
+ *   o Feature: Add support for ethtool TSO setting.
+ *   o Feature: Increase default Tx Descriptor count to 1024 for >= 82544.
  *   
- * 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
+ * 5.1.13	5/28/03
  */
 
 char e1000_driver_name[] = "e1000";
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "5.1.13-k1";
+char e1000_driver_version[] = "5.2.20-k1";
 char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -61,7 +75,7 @@
  * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
  *   Class, Class Mask, private data (not used) }
  */
-static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
+static struct pci_device_id e1000_pci_tbl[] = {
 	{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},
@@ -71,15 +85,28 @@
 	{0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{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, 0x1018, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1075, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1076, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1077, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1078, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1079, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x107A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x107B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	/* required last entry */
 	{0,}
 };
@@ -120,7 +147,7 @@
 static void e1000_update_stats(struct e1000_adapter *adapter);
 static inline void e1000_irq_disable(struct e1000_adapter *adapter);
 static inline void e1000_irq_enable(struct e1000_adapter *adapter);
-static void e1000_intr(int irq, void *data, struct pt_regs *regs);
+static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs);
 static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter);
 #ifdef CONFIG_E1000_NAPI
 static int e1000_clean(struct net_device *netdev, int *budget);
@@ -228,6 +255,7 @@
 e1000_up(struct e1000_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
+	int err;
 
 	/* hardware has been reset, we need to reload some things */
 
@@ -240,9 +268,10 @@
 	e1000_configure_rx(adapter);
 	e1000_alloc_rx_buffers(adapter);
 
-	if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM,
-		       netdev->name, netdev))
-		return -1;
+	if((err = request_irq(netdev->irq, &e1000_intr,
+		              SA_SHIRQ | SA_SAMPLE_RANDOM,
+		              netdev->name, netdev)))
+		return err;
 
 	mod_timer(&adapter->watchdog_timer, jiffies);
 	e1000_irq_enable(adapter);
@@ -296,7 +325,13 @@
 	}
 	E1000_WRITE_REG(&adapter->hw, PBA, pba);
 
+	/* flow control settings */
+	adapter->hw.fc_high_water = pba - E1000_FC_HIGH_DIFF;
+	adapter->hw.fc_low_water = pba - E1000_FC_LOW_DIFF;
+	adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME;
+	adapter->hw.fc_send_xon = 1;
 	adapter->hw.fc = adapter->hw.original_fc;
+
 	e1000_reset_hw(&adapter->hw);
 	if(adapter->hw.mac_type >= e1000_82544)
 		E1000_WRITE_REG(&adapter->hw, WUC, 0);
@@ -328,29 +363,32 @@
 	int mmio_len;
 	int pci_using_dac;
 	int i;
+	int err;
 	uint16_t eeprom_data;
 
-	if((i = pci_enable_device(pdev)))
-		return i;
+	if((err = pci_enable_device(pdev)))
+		return err;
 
-	if(!(i = pci_set_dma_mask(pdev, PCI_DMA_64BIT))) {
+	if(!(err = pci_set_dma_mask(pdev, PCI_DMA_64BIT))) {
 		pci_using_dac = 1;
 	} else {
-		if((i = pci_set_dma_mask(pdev, PCI_DMA_32BIT))) {
+		if((err = pci_set_dma_mask(pdev, PCI_DMA_32BIT))) {
 			E1000_ERR("No usable DMA configuration, aborting\n");
-			return i;
+			return err;
 		}
 		pci_using_dac = 0;
 	}
 
-	if((i = pci_request_regions(pdev, e1000_driver_name)))
-		return i;
+	if((err = pci_request_regions(pdev, e1000_driver_name)))
+		return err;
 
 	pci_set_master(pdev);
 
 	netdev = alloc_etherdev(sizeof(struct e1000_adapter));
-	if(!netdev)
+	if(!netdev) {
+		err = -ENOMEM;
 		goto err_alloc_etherdev;
+	}
 
 	SET_MODULE_OWNER(netdev);
 
@@ -364,8 +402,10 @@
 	mmio_len = pci_resource_len(pdev, BAR_0);
 
 	adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
-	if(!adapter->hw.hw_addr)
+	if(!adapter->hw.hw_addr) {
+		err = -EIO;
 		goto err_ioremap;
+	}
 
 	for(i = BAR_1; i <= BAR_5; i++) {
 		if(pci_resource_len(pdev, i) == 0)
@@ -403,7 +443,7 @@
 
 	/* setup the private structure */
 
-	if(e1000_sw_init(adapter))
+	if((err = e1000_sw_init(adapter)))
 		goto err_sw_init;
 
 	if(adapter->hw.mac_type >= e1000_82543) {
@@ -425,10 +465,16 @@
 	if(pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
+	/* before reading the EEPROM, reset the controller to 
+	 * put the device in a known good starting state */
+	
+	e1000_reset_hw(&adapter->hw);
+
 	/* make sure the EEPROM is good */
 
 	if(e1000_validate_eeprom_checksum(&adapter->hw) < 0) {
 		printk(KERN_ERR "The EEPROM Checksum Is Not Valid\n");
+		err = -EIO;
 		goto err_eeprom;
 	}
 
@@ -437,8 +483,10 @@
 	e1000_read_mac_addr(&adapter->hw);
 	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
 
-	if(!is_valid_ether_addr(netdev->dev_addr))
+	if(!is_valid_ether_addr(netdev->dev_addr)) {
+		err = -EIO;
 		goto err_eeprom;
+	}
 
 	e1000_read_part_num(&adapter->hw, &(adapter->part_num));
 
@@ -475,12 +523,28 @@
 	 * enable the ACPI Magic Packet filter
 	 */
 
-	e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL2_REG,1, &eeprom_data);
-	if((adapter->hw.mac_type >= e1000_82544) &&
-	   (eeprom_data & E1000_EEPROM_APME))
+	switch(adapter->hw.mac_type) {
+	case e1000_82542_rev2_0:
+	case e1000_82542_rev2_1:
+	case e1000_82543:
+		break;
+	case e1000_82546:
+	case e1000_82546_rev_3:
+		if((E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1)
+		   && (adapter->hw.media_type == e1000_media_type_copper)) {
+			e1000_read_eeprom(&adapter->hw,
+				EEPROM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
+			break;
+		}
+		/* Fall Through */
+	default:
+		e1000_read_eeprom(&adapter->hw,
+			EEPROM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
+		break;
+	}
+	if(eeprom_data & E1000_EEPROM_APME)
 		adapter->wol |= E1000_WUFC_MAG;
 
-
 	/* reset the hardware with the new settings */
 
 	e1000_reset(adapter);
@@ -492,10 +556,10 @@
 err_eeprom:
 	iounmap(adapter->hw.hw_addr);
 err_ioremap:
-	kfree(netdev);
+	free_netdev(netdev);
 err_alloc_etherdev:
 	pci_release_regions(pdev);
-	return -ENOMEM;
+	return err;
 }
 
 /**
@@ -515,7 +579,8 @@
 	struct e1000_adapter *adapter = netdev->priv;
 	uint32_t manc;
 
-	if(adapter->hw.mac_type >= e1000_82540) {
+	if(adapter->hw.mac_type >= e1000_82540 &&
+	   adapter->hw.media_type == e1000_media_type_copper) {
 		manc = E1000_READ_REG(&adapter->hw, MANC);
 		if(manc & E1000_MANC_SMBUS_EN) {
 			manc |= E1000_MANC_ARP_EN;
@@ -530,7 +595,7 @@
 	iounmap(adapter->hw.hw_addr);
 	pci_release_regions(pdev);
 
-	kfree(netdev);
+	free_netdev(netdev);
 }
 
 /**
@@ -569,35 +634,20 @@
 
 	if (e1000_set_mac_type(hw)) {
 		E1000_ERR("Unknown MAC Type\n");
-		return -1;
+		return -EIO;
 	}
 
 	/* initialize eeprom parameters */
 
 	e1000_init_eeprom_params(hw);
 
-	/* flow control settings */
-
-	hw->fc_high_water = E1000_FC_HIGH_THRESH;
-	hw->fc_low_water = E1000_FC_LOW_THRESH;
-	hw->fc_pause_time = E1000_FC_PAUSE_TIME;
-	hw->fc_send_xon = 1;
-
-	if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547))
+	if((hw->mac_type == e1000_82541) ||
+	   (hw->mac_type == e1000_82547) ||
+	   (hw->mac_type == e1000_82541_rev_2) ||
+	   (hw->mac_type == e1000_82547_rev_2))
 		hw->phy_init_script = 1;
 
-	/* Media type - copper or fiber */
-
-	if(hw->mac_type >= e1000_82543) {
-		uint32_t status = E1000_READ_REG(hw, STATUS);
-
-		if(status & E1000_STATUS_TBIMODE)
-			hw->media_type = e1000_media_type_fiber;
-		else
-			hw->media_type = e1000_media_type_copper;
-	} else {
-		hw->media_type = e1000_media_type_fiber;
-	}
+	e1000_set_media_type(hw);
 
 	if(hw->mac_type < e1000_82543)
 		hw->report_tx_early = 0;
@@ -613,6 +663,7 @@
 	if(hw->media_type == e1000_media_type_copper) {
 		hw->mdix = AUTO_ALL_MODES;
 		hw->disable_polarity_correction = FALSE;
+		hw->master_slave = E1000_MASTER_SLAVE;
 	}
 
 	atomic_set(&adapter->irq_sem, 1);
@@ -638,18 +689,19 @@
 e1000_open(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev->priv;
+	int err;
 
 	/* allocate transmit descriptors */
 
-	if(e1000_setup_tx_resources(adapter))
+	if((err = e1000_setup_tx_resources(adapter)))
 		goto err_setup_tx;
 
 	/* allocate receive descriptors */
 
-	if(e1000_setup_rx_resources(adapter))
+	if((err = e1000_setup_rx_resources(adapter)))
 		goto err_setup_rx;
 
-	if(e1000_up(adapter))
+	if((err = e1000_up(adapter)))
 		goto err_up;
 
 	return 0;
@@ -661,7 +713,7 @@
 err_setup_tx:
 	e1000_reset(adapter);
 
-	return -EBUSY;
+	return err;
 }
 
 /**
@@ -762,7 +814,8 @@
 		tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
 		break;
 	default:
-		if(adapter->hw.media_type == e1000_media_type_fiber)
+		if(adapter->hw.media_type == e1000_media_type_fiber ||
+		   adapter->hw.media_type == e1000_media_type_internal_serdes)
 			tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
 		else
 			tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
@@ -797,6 +850,12 @@
 		adapter->txd_cmd |= E1000_TXD_CMD_RS;
 	else
 		adapter->txd_cmd |= E1000_TXD_CMD_RPS;
+
+	/* Cache if we're 82544 running in PCI-X because we'll
+	 * need this to apply a workaround later in the send path. */
+	if(adapter->hw.mac_type == e1000_82544 &&
+	   adapter->hw.bus_type == e1000_bus_type_pcix)
+		adapter->pcix_82544 = 1;
 }
 
 /**
@@ -1488,28 +1547,48 @@
 	unsigned int first)
 {
 	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+	struct e1000_tx_desc *tx_desc;
 	struct e1000_buffer *buffer_info;
-	int len = skb->len;
+	unsigned int len = skb->len, max_per_txd = E1000_MAX_DATA_PER_TXD;
 	unsigned int offset = 0, size, count = 0, i;
-
 #ifdef NETIF_F_TSO
-	unsigned int tso = skb_shinfo(skb)->tso_size;
+	unsigned int mss;
 #endif
-	unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+	unsigned int nr_frags;
 	unsigned int f;
+
+#ifdef NETIF_F_TSO
+	mss = skb_shinfo(skb)->tso_size;
+	/* The controller does a simple calculation to 
+	 * make sure there is enough room in the FIFO before
+	 * initiating the DMA for each buffer.  The calc is:
+	 * 4 = ceil(buffer len/mss).  To make sure we don't
+	 * overrun the FIFO, adjust the max buffer len if mss
+	 * drops. */
+	if(mss)
+		max_per_txd = min(mss << 2, max_per_txd);
+#endif
+	nr_frags = skb_shinfo(skb)->nr_frags;
 	len -= skb->data_len;
 
 	i = tx_ring->next_to_use;
 
 	while(len) {
 		buffer_info = &tx_ring->buffer_info[i];
-		size = min(len, E1000_MAX_DATA_PER_TXD);
+		size = min(len, max_per_txd);
 #ifdef NETIF_F_TSO
 		/* Workaround for premature desc write-backs
 		 * in TSO mode.  Append 4-byte sentinel desc */
-		if(tso && !nr_frags && size == len && size > 4)
+		if(mss && !nr_frags && size == len && size > 8)
 			size -= 4;
 #endif
+		/* Workaround for potential 82544 hang in PCI-X.  Avoid
+		 * terminating buffers within evenly-aligned dwords. */
+		if(adapter->pcix_82544 &&
+		   !((unsigned long)(skb->data + offset + size - 1) & 4) &&
+		   size > 4)
+			size -= 4;
+
 		buffer_info->length = size;
 		buffer_info->dma =
 			pci_map_single(adapter->pdev,
@@ -1529,22 +1608,30 @@
 
 		frag = &skb_shinfo(skb)->frags[f];
 		len = frag->size;
-		offset = 0;
+		offset = frag->page_offset;
 
 		while(len) {
 			buffer_info = &tx_ring->buffer_info[i];
-			size = min(len, E1000_MAX_DATA_PER_TXD);
+			size = min(len, max_per_txd);
 #ifdef NETIF_F_TSO
 			/* Workaround for premature desc write-backs
 			 * in TSO mode.  Append 4-byte sentinel desc */
-			if(tso && f == (nr_frags-1) && size == len && size > 4)
+			if(mss && f == (nr_frags-1) && size == len && size > 8)
 				size -= 4;
 #endif
+			/* Workaround for potential 82544 hang in PCI-X.
+			 * Avoid terminating buffers within evenly-aligned
+			 * dwords. */
+			if(adapter->pcix_82544 &&
+			   !((unsigned long)(frag->page+offset+size-1) & 4) &&
+			   size > 4)
+				size -= 4;
+
 			buffer_info->length = size;
 			buffer_info->dma =
 				pci_map_page(adapter->pdev,
 					frag->page,
-					frag->page_offset + offset,
+					offset,
 					size,
 					PCI_DMA_TODEVICE);
 			buffer_info->time_stamp = jiffies;
@@ -1555,6 +1642,46 @@
 			if(++i == tx_ring->count) i = 0;
 		}
 	}
+
+	if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2) {
+
+		/* There aren't enough descriptors available to queue up
+		 * this send (need: count + 1 context desc + 1 desc gap
+		 * to keep tail from touching head), so undo the mapping
+		 * and abort the send.  We could have done the check before
+		 * we mapped the skb, but because of all the workarounds
+		 * (above), it's too difficult to predict how many we're
+		 * going to need.*/
+		i = adapter->tx_ring.next_to_use;
+
+		if(i == first) {
+			/* Cleanup after e1000_tx_[csum|tso] scribbling
+			 * on descriptors. */
+			tx_desc = E1000_TX_DESC(*tx_ring, first);
+			tx_desc->buffer_addr = 0;
+			tx_desc->lower.data = 0;
+			tx_desc->upper.data = 0;
+		}
+
+		while(count--) {
+			buffer_info = &tx_ring->buffer_info[i];
+
+			if(buffer_info->dma) {
+				pci_unmap_page(adapter->pdev,
+					       buffer_info->dma,
+					       buffer_info->length,
+					       PCI_DMA_TODEVICE);
+				buffer_info->dma = 0;
+			}
+
+			if(++i == tx_ring->count) i = 0;
+		}
+
+		adapter->tx_ring.next_to_use = first;
+
+		return 0;
+	}
+
 	i = (i == 0) ? tx_ring->count - 1 : i - 1;
 	tx_ring->buffer_info[i].skb = skb;
 	tx_ring->buffer_info[first].next_to_watch = i;
@@ -1649,29 +1776,19 @@
 	return 0;
 }
 
-/* Tx Descriptors needed, worst case */
-#define TXD_USE_COUNT(S) (((S) >> E1000_MAX_TXD_PWR) + \
-			 (((S) & (E1000_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
-#define DESC_NEEDED TXD_USE_COUNT(MAX_JUMBO_FRAME_SIZE) + \
-	MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1
-
 static int
 e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev->priv;
 	unsigned int first;
 	unsigned int tx_flags = 0;
+	int count;
 
 	if(skb->len <= 0) {
 		dev_kfree_skb_any(skb);
 		return 0;
 	}
 
-	if(E1000_DESC_UNUSED(&adapter->tx_ring) < DESC_NEEDED) {
-		netif_stop_queue(netdev);
-		return 1;
-	}
-
 	if(adapter->hw.mac_type == e1000_82547) {
 		if(e1000_82547_fifo_workaround(adapter, skb)) {
 			netif_stop_queue(netdev);
@@ -1692,7 +1809,12 @@
 	else if(e1000_tx_csum(adapter, skb))
 		tx_flags |= E1000_TX_FLAGS_CSUM;
 
-	e1000_tx_queue(adapter, e1000_tx_map(adapter, skb, first), tx_flags);
+	if((count = e1000_tx_map(adapter, skb, first)))
+		e1000_tx_queue(adapter, count, tx_flags);
+	else {
+		netif_stop_queue(netdev);
+		return 1;
+	}
 
 	netdev->trans_start = jiffies;
 
@@ -1965,7 +2087,7 @@
  * @pt_regs: CPU registers structure
  **/
 
-static void
+static irqreturn_t
 e1000_intr(int irq, void *data, struct pt_regs *regs)
 {
 	struct net_device *netdev = data;
@@ -1976,7 +2098,7 @@
 #endif
 
 	if(!icr)
-		return;  /* Not our interrupt */
+		return IRQ_NONE;  /* Not our interrupt */
 
 	if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
 		adapter->hw.get_link_status = 1;
@@ -2000,6 +2122,8 @@
 		   !e1000_clean_tx_irq(adapter))
 			break;
 #endif
+
+	return IRQ_HANDLED;
 }
 
 #ifdef CONFIG_E1000_NAPI
@@ -2229,7 +2353,7 @@
 
 /**
  * e1000_alloc_rx_buffers - Replace used receive buffers
- * @data: address of board private structure
+ * @adapter: address of board private structure
  **/
 
 static void
@@ -2385,7 +2509,7 @@
 	uint16_t mii_reg;
 	uint16_t spddplx;
 
-	if(adapter->hw.media_type == e1000_media_type_fiber)
+	if(adapter->hw.media_type != e1000_media_type_copper)
 		return -EOPNOTSUPP;
 
 	switch (cmd) {
@@ -2657,7 +2781,7 @@
 	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))) {
 			if(pci_dev_driver(pdev) == &e1000_driver)
 				e1000_suspend(pdev, 3);
 		}
@@ -2704,7 +2828,8 @@
 			E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
 		}
 
-		if(adapter->hw.media_type == e1000_media_type_fiber) {
+		if(adapter->hw.media_type == e1000_media_type_fiber ||
+		   adapter->hw.media_type == e1000_media_type_internal_serdes) {
 			/* keep the laser running in D3 */
 			ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
 			ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
@@ -2724,7 +2849,8 @@
 
 	pci_save_state(pdev, adapter->pci_state);
 
-	if(adapter->hw.mac_type >= e1000_82540) {
+	if(adapter->hw.mac_type >= e1000_82540 &&
+	   adapter->hw.media_type == e1000_media_type_copper) {
 		manc = E1000_READ_REG(&adapter->hw, MANC);
 		if(manc & E1000_MANC_SMBUS_EN) {
 			manc |= E1000_MANC_ARP_EN;
@@ -2762,7 +2888,8 @@
 
 	netif_device_attach(netdev);
 
-	if(adapter->hw.mac_type >= e1000_82540) {
+	if(adapter->hw.mac_type >= e1000_82540 &&
+	   adapter->hw.media_type == e1000_media_type_copper) {
 		manc = E1000_READ_REG(&adapter->hw, MANC);
 		manc &= ~(E1000_MANC_ARP_EN);
 		E1000_WRITE_REG(&adapter->hw, MANC, manc);

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