netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/21] e1000: driver update to 7.1.9-k2
@ 2006-06-22  5:18 Kok, Auke
  2006-06-22  5:20 ` [PATCH 01/21] e1000: fix loopback ethtool test Kok, Auke
                   ` (21 more replies)
  0 siblings, 22 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:18 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


Hi,

A large number of e1000 patches this update, including the release of
the integrated NIC in the ICH8 motherboard chipset, which has been
officially released into the public. Also known as i965, the lan
chipset on this motherboard is fully supported by this driver.

The motherboard actually comes with two different PHY's, one that
supports gigabit speeds and one that only does 10/100. This driver
supports both of them.

All of these changes correspond with the 7.1.9 release on SF this
week, and have been tested and validated by our team, who did and
an excellent job ;^).

Furthermore, the patches included also fixes included in the 7.0.38
and 7.0.41 releases, which were not yet merged into the kernel. This
patch series brings the kernel driver up to current.


---

Summary of patches:

[01]: fix loopback ethtool test
[02]: rework driver hardware reset locking
[03]: Make PHY powerup/down a function
[04]: fix CONFIG_PM blocks
[05]: small performance tweak by removing double code
[06]: add smart power down code
[07]: change printk into DPRINTK
[08]: recycle skb
[09]: rework module param code with uninitialized values
[10]: force register write flushes to circumvent broken platforms
[11]: disable CRC stripping workaround
[12]: fix adapter led blinking inconsistency
[13]: add E1000_BIG_ENDIAN symbol
[14]: M88 PHY workaround
[15]: check return value of _get_speed_and_duplex
[16]: disable ERT
[17]: add ich8lan core functions
[18]: integrate ich8 support into driver
[19]: allow user to disable ich8 lock loss workaround
[20]: add ich8lan device ID's
[21]: increase version to 7.1.9-k2


---

Since these patches are rather large together, they are also available
over http here:
    http://foo-projects.org/~sofar/e1000-7.1.9-k2/
And in a tarball:
    http://foo-projects.org/~sofar/e1000-7.1.9-k2/e1000-patches-7.1.9-k2.tar.bz2
---

Jeff, please pull from our git repository:

git://lost.foo-projects.org/~ahkok/git/netdev-2.6 upstream


These patches are against
    netdev-2.6#upstream 612eff0e3715a6faff5ba1b74873b99e036c59fe
(Brian Haley <brian.haley@hp.com> / [PATCH] s2io: netpoll support)

Cheers,

Auke


---
 drivers/net/e1000/e1000.h         |   10 
 drivers/net/e1000/e1000_ethtool.c |  143 +--
 drivers/net/e1000/e1000_hw.c      | 1770 +++++++++++++++++++++++++++++++++++---
 drivers/net/e1000/e1000_hw.h      |  400 ++++++++
 drivers/net/e1000/e1000_main.c    |  386 +++++---
 drivers/net/e1000/e1000_osdep.h   |   16 
 drivers/net/e1000/e1000_param.c   |  213 ++--
 7 files changed, 2539 insertions(+), 399 deletions(-)


--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH 01/21] e1000: fix loopback ethtool test
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 02/21] e1000: rework driver hardware reset locking Kok, Auke
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


Ethtool was reporting that loopback failed randomly on esb2
systems. Upon study it was found that the phy manual was changed
with respect to the loopback mode bits. The new value fixes it.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_ethtool.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 6ed7f59..845d293 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -1246,7 +1246,7 @@ e1000_integrated_phy_loopback(struct e10
 	} else if (adapter->hw.phy_type == e1000_phy_gg82563) {
 		e1000_write_phy_reg(&adapter->hw,
 		                    GG82563_PHY_KMRN_MODE_CTRL,
-		                    0x1CE);
+		                    0x1CC);
 	}
 	/* force 1000, set loopback */
 	e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140);



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 02/21] e1000: rework driver hardware reset locking
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
  2006-06-22  5:20 ` [PATCH 01/21] e1000: fix loopback ethtool test Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-27  1:42   ` Jeff Garzik
  2006-06-22  5:20 ` [PATCH 03/21] e1000: Make PHY powerup/down a function Kok, Auke
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


After studying the driver mac reset code it was found that there
were multiple race conditions possible to reset the unit twice or
bring it e1000_up() double. This fixes all occurences where the
driver needs to reset the mac.

We also remove irq requesting/releasing into _open and _close so
that while the device is _up we will never touch the irq's. This fixes
the double free irq bug that people saw.

To make sure that the watchdog task doesn't cause another race we let
it run as a non-scheduled task.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000.h         |    8 ++
 drivers/net/e1000/e1000_ethtool.c |   46 ++++++++------
 drivers/net/e1000/e1000_main.c    |  126 +++++++++++++++++++++----------------
 3 files changed, 105 insertions(+), 75 deletions(-)

diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 2bc34fb..2b96ad0 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -69,7 +69,6 @@
 #ifdef NETIF_F_TSO
 #include <net/checksum.h>
 #endif
-#include <linux/workqueue.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
@@ -255,7 +254,6 @@ struct e1000_adapter {
 	spinlock_t tx_queue_lock;
 #endif
 	atomic_t irq_sem;
-	struct work_struct watchdog_task;
 	struct work_struct reset_task;
 	uint8_t fc_autoneg;
 
@@ -340,8 +338,13 @@ struct e1000_adapter {
 #ifdef NETIF_F_TSO
 	boolean_t tso_force;
 #endif
+	unsigned long flags;
 };
 
+enum e1000_state_t {
+	__E1000_DRIVER_TESTING,
+	__E1000_RESETTING,
+};
 
 /*  e1000_main.c  */
 extern char e1000_driver_name[];
@@ -349,6 +352,7 @@ extern char e1000_driver_version[];
 int e1000_up(struct e1000_adapter *adapter);
 void e1000_down(struct e1000_adapter *adapter);
 void e1000_reset(struct e1000_adapter *adapter);
+void e1000_reinit_locked(struct e1000_adapter *adapter);
 int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
 void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
 int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 845d293..cf5c5f4 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -203,11 +203,9 @@ e1000_set_settings(struct net_device *ne
 
 	/* reset the link */
 
-	if (netif_running(adapter->netdev)) {
-		e1000_down(adapter);
-		e1000_reset(adapter);
-		e1000_up(adapter);
-	} else
+	if (netif_running(adapter->netdev))
+		e1000_reinit_locked(adapter);
+	else
 		e1000_reset(adapter);
 
 	return 0;
@@ -254,10 +252,9 @@ e1000_set_pauseparam(struct net_device *
 	hw->original_fc = hw->fc;
 
 	if (adapter->fc_autoneg == AUTONEG_ENABLE) {
-		if (netif_running(adapter->netdev)) {
-			e1000_down(adapter);
-			e1000_up(adapter);
-		} else
+		if (netif_running(adapter->netdev))
+			e1000_reinit_locked(adapter);
+		else
 			e1000_reset(adapter);
 	} else
 		return ((hw->media_type == e1000_media_type_fiber) ?
@@ -279,10 +276,9 @@ e1000_set_rx_csum(struct net_device *net
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	adapter->rx_csum = data;
 
-	if (netif_running(netdev)) {
-		e1000_down(adapter);
-		e1000_up(adapter);
-	} else
+	if (netif_running(netdev))
+		e1000_reinit_locked(adapter);
+	else
 		e1000_reset(adapter);
 	return 0;
 }
@@ -631,6 +627,9 @@ e1000_set_ringparam(struct net_device *n
 	tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
 	rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
 
+	while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
+		msleep(1);
+
 	if (netif_running(adapter->netdev))
 		e1000_down(adapter);
 
@@ -691,9 +690,11 @@ e1000_set_ringparam(struct net_device *n
 		adapter->rx_ring = rx_new;
 		adapter->tx_ring = tx_new;
 		if ((err = e1000_up(adapter)))
-			return err;
+			goto err_setup;
 	}
 
+	clear_bit(__E1000_RESETTING, &adapter->flags);
+
 	return 0;
 err_setup_tx:
 	e1000_free_all_rx_resources(adapter);
@@ -701,6 +702,8 @@ err_setup_rx:
 	adapter->rx_ring = rx_old;
 	adapter->tx_ring = tx_old;
 	e1000_up(adapter);
+err_setup:
+	clear_bit(__E1000_RESETTING, &adapter->flags);
 	return err;
 }
 
@@ -1568,6 +1571,7 @@ e1000_diag_test(struct net_device *netde
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	boolean_t if_running = netif_running(netdev);
 
+	set_bit(__E1000_DRIVER_TESTING, &adapter->flags);
 	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
 		/* Offline tests */
 
@@ -1582,7 +1586,8 @@ e1000_diag_test(struct net_device *netde
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
 		if (if_running)
-			e1000_down(adapter);
+			/* indicate we're in test mode */
+			dev_close(netdev);
 		else
 			e1000_reset(adapter);
 
@@ -1607,8 +1612,9 @@ e1000_diag_test(struct net_device *netde
 		adapter->hw.autoneg = autoneg;
 
 		e1000_reset(adapter);
+		clear_bit(__E1000_DRIVER_TESTING, &adapter->flags);
 		if (if_running)
-			e1000_up(adapter);
+			dev_open(netdev);
 	} else {
 		/* Online tests */
 		if (e1000_link_test(adapter, &data[4]))
@@ -1619,6 +1625,8 @@ e1000_diag_test(struct net_device *netde
 		data[1] = 0;
 		data[2] = 0;
 		data[3] = 0;
+
+		clear_bit(__E1000_DRIVER_TESTING, &adapter->flags);
 	}
 	msleep_interruptible(4 * 1000);
 }
@@ -1807,10 +1815,8 @@ static int
 e1000_nway_reset(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
-	if (netif_running(netdev)) {
-		e1000_down(adapter);
-		e1000_up(adapter);
-	}
+	if (netif_running(netdev))
+		e1000_reinit_locked(adapter);
 	return 0;
 }
 
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index a373ccb..52d698b 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -133,7 +133,6 @@ static void e1000_clean_rx_ring(struct e
 static void e1000_set_multi(struct net_device *netdev);
 static void e1000_update_phy_info(unsigned long data);
 static void e1000_watchdog(unsigned long data);
-static void e1000_watchdog_task(struct e1000_adapter *adapter);
 static void e1000_82547_tx_fifo_stall(unsigned long data);
 static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
@@ -261,6 +260,44 @@ e1000_exit_module(void)
 
 module_exit(e1000_exit_module);
 
+static int e1000_request_irq(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int flags, err = 0;
+
+	flags = SA_SHIRQ | SA_SAMPLE_RANDOM;
+#ifdef CONFIG_PCI_MSI
+	if (adapter->hw.mac_type > e1000_82547_rev_2) {
+		adapter->have_msi = TRUE;
+		if ((err = pci_enable_msi(adapter->pdev))) {
+			DPRINTK(PROBE, ERR,
+			 "Unable to allocate MSI interrupt Error: %d\n", err);
+			adapter->have_msi = FALSE;
+		}
+	}
+	if (adapter->have_msi)
+		flags &= ~SA_SHIRQ;
+#endif
+	if ((err = request_irq(adapter->pdev->irq, &e1000_intr, flags,
+	                       netdev->name, netdev)))
+		DPRINTK(PROBE, ERR,
+		        "Unable to allocate interrupt Error: %d\n", err);
+
+	return err;
+}
+
+static void e1000_free_irq(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	free_irq(adapter->pdev->irq, netdev);
+
+#ifdef CONFIG_PCI_MSI
+	if (adapter->have_msi)
+		pci_disable_msi(adapter->pdev);
+#endif
+}
+
 /**
  * e1000_irq_disable - Mask off interrupt generation on the NIC
  * @adapter: board private structure
@@ -387,7 +424,7 @@ int
 e1000_up(struct e1000_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
-	int i, err;
+	int i;
 
 	/* hardware has been reset, we need to reload some things */
 
@@ -415,24 +452,6 @@ e1000_up(struct e1000_adapter *adapter)
 		                      E1000_DESC_UNUSED(ring));
 	}
 
-#ifdef CONFIG_PCI_MSI
-	if (adapter->hw.mac_type > e1000_82547_rev_2) {
-		adapter->have_msi = TRUE;
-		if ((err = pci_enable_msi(adapter->pdev))) {
-			DPRINTK(PROBE, ERR,
-			 "Unable to allocate MSI interrupt Error: %d\n", err);
-			adapter->have_msi = FALSE;
-		}
-	}
-#endif
-	if ((err = request_irq(adapter->pdev->irq, &e1000_intr,
-		              SA_SHIRQ | SA_SAMPLE_RANDOM,
-		              netdev->name, netdev))) {
-		DPRINTK(PROBE, ERR,
-		    "Unable to allocate interrupt Error: %d\n", err);
-		return err;
-	}
-
 	adapter->tx_queue_len = netdev->tx_queue_len;
 
 	mod_timer(&adapter->watchdog_timer, jiffies);
@@ -450,16 +469,10 @@ e1000_down(struct e1000_adapter *adapter
 {
 	struct net_device *netdev = adapter->netdev;
 	boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) &&
-				     e1000_check_mng_mode(&adapter->hw);
+	                              e1000_check_mng_mode(&adapter->hw);
 
 	e1000_irq_disable(adapter);
 
-	free_irq(adapter->pdev->irq, netdev);
-#ifdef CONFIG_PCI_MSI
-	if (adapter->hw.mac_type > e1000_82547_rev_2 &&
-	   adapter->have_msi == TRUE)
-		pci_disable_msi(adapter->pdev);
-#endif
 	del_timer_sync(&adapter->tx_fifo_stall_timer);
 	del_timer_sync(&adapter->watchdog_timer);
 	del_timer_sync(&adapter->phy_info_timer);
@@ -496,6 +509,17 @@ e1000_down(struct e1000_adapter *adapter
 }
 
 void
+e1000_reinit_locked(struct e1000_adapter *adapter)
+{
+	WARN_ON(in_interrupt());
+	while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
+		msleep(1);
+	e1000_down(adapter);
+	e1000_up(adapter);
+	clear_bit(__E1000_RESETTING, &adapter->flags);
+}
+
+void
 e1000_reset(struct e1000_adapter *adapter)
 {
 	uint32_t pba, manc;
@@ -758,9 +782,6 @@ e1000_probe(struct pci_dev *pdev,
 	adapter->watchdog_timer.function = &e1000_watchdog;
 	adapter->watchdog_timer.data = (unsigned long) adapter;
 
-	INIT_WORK(&adapter->watchdog_task,
-		(void (*)(void *))e1000_watchdog_task, adapter);
-
 	init_timer(&adapter->phy_info_timer);
 	adapter->phy_info_timer.function = &e1000_update_phy_info;
 	adapter->phy_info_timer.data = (unsigned long) adapter;
@@ -1078,6 +1099,10 @@ e1000_open(struct net_device *netdev)
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	int err;
 
+	/* disallow open during test */
+	if (test_bit(__E1000_DRIVER_TESTING, &adapter->flags))
+		return -EBUSY;
+
 	/* allocate transmit descriptors */
 
 	if ((err = e1000_setup_all_tx_resources(adapter)))
@@ -1088,6 +1113,10 @@ e1000_open(struct net_device *netdev)
 	if ((err = e1000_setup_all_rx_resources(adapter)))
 		goto err_setup_rx;
 
+	err = e1000_request_irq(adapter);
+	if (err)
+		goto err_up;
+
 	if ((err = e1000_up(adapter)))
 		goto err_up;
 	adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
@@ -1131,7 +1160,9 @@ e1000_close(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 
+	WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags));
 	e1000_down(adapter);
+	e1000_free_irq(adapter);
 
 	e1000_free_all_tx_resources(adapter);
 	e1000_free_all_rx_resources(adapter);
@@ -2201,14 +2232,6 @@ static void
 e1000_watchdog(unsigned long data)
 {
 	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
-
-	/* Do the rest outside of interrupt context */
-	schedule_work(&adapter->watchdog_task);
-}
-
-static void
-e1000_watchdog_task(struct e1000_adapter *adapter)
-{
 	struct net_device *netdev = adapter->netdev;
 	struct e1000_tx_ring *txdr = adapter->tx_ring;
 	uint32_t link, tctl;
@@ -2919,8 +2942,7 @@ e1000_reset_task(struct net_device *netd
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 
-	e1000_down(adapter);
-	e1000_up(adapter);
+	e1000_reinit_locked(adapter);
 }
 
 /**
@@ -3026,10 +3048,8 @@ e1000_change_mtu(struct net_device *netd
 
 	netdev->mtu = new_mtu;
 
-	if (netif_running(netdev)) {
-		e1000_down(adapter);
-		e1000_up(adapter);
-	}
+	if (netif_running(netdev))
+		e1000_reinit_locked(adapter);
 
 	adapter->hw.max_frame_size = max_frame;
 
@@ -4180,10 +4200,9 @@ e1000_mii_ioctl(struct net_device *netde
 						return retval;
 					}
 				}
-				if (netif_running(adapter->netdev)) {
-					e1000_down(adapter);
-					e1000_up(adapter);
-				} else
+				if (netif_running(adapter->netdev))
+					e1000_reinit_locked(adapter);
+				else
 					e1000_reset(adapter);
 				break;
 			case M88E1000_PHY_SPEC_CTRL:
@@ -4200,10 +4219,9 @@ e1000_mii_ioctl(struct net_device *netde
 			case PHY_CTRL:
 				if (mii_reg & MII_CR_POWER_DOWN)
 					break;
-				if (netif_running(adapter->netdev)) {
-					e1000_down(adapter);
-					e1000_up(adapter);
-				} else
+				if (netif_running(adapter->netdev))
+					e1000_reinit_locked(adapter);
+				else
 					e1000_reset(adapter);
 				break;
 			}
@@ -4462,8 +4480,10 @@ e1000_suspend(struct pci_dev *pdev, pm_m
 
 	netif_device_detach(netdev);
 
-	if (netif_running(netdev))
+	if (netif_running(netdev)) {
+		WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags));
 		e1000_down(adapter);
+	}
 
 #ifdef CONFIG_PM
 	/* Implement our own version of pci_save_state(pdev) because pci-



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 03/21] e1000: Make PHY powerup/down a function
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
  2006-06-22  5:20 ` [PATCH 01/21] e1000: fix loopback ethtool test Kok, Auke
  2006-06-22  5:20 ` [PATCH 02/21] e1000: rework driver hardware reset locking Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 04/21] e1000: fix CONFIG_PM blocks Kok, Auke
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


In relation to the irq work done earlier we also move the PHY powerup
and powerdown functions into separate functions and move the calls to
_close and _open, making the PHY stay in it's power state as long as
the device is _up.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_main.c |   76 ++++++++++++++++++++++++++--------------
 1 files changed, 49 insertions(+), 27 deletions(-)

diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 52d698b..813d5e0 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -428,14 +428,6 @@ e1000_up(struct e1000_adapter *adapter)
 
 	/* hardware has been reset, we need to reload some things */
 
-	/* Reset the PHY if it was previously powered down */
-	if (adapter->hw.media_type == e1000_media_type_copper) {
-		uint16_t mii_reg;
-		e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
-		if (mii_reg & MII_CR_POWER_DOWN)
-			e1000_phy_hw_reset(&adapter->hw);
-	}
-
 	e1000_set_multi(netdev);
 
 	e1000_restore_vlan(adapter);
@@ -464,12 +456,56 @@ e1000_up(struct e1000_adapter *adapter)
 	return 0;
 }
 
+/**
+ * e1000_power_up_phy - restore link in case the phy was powered down
+ * @adapter: address of board private structure
+ *
+ * The phy may be powered down to save power and turn off link when the
+ * driver is unloaded and wake on lan is not enabled (among others)
+ * *** this routine MUST be followed by a call to e1000_reset ***
+ *
+ **/
+
+static void e1000_power_up_phy(struct e1000_adapter *adapter)
+{
+	uint16_t mii_reg = 0;
+
+	/* Just clear the power down bit to wake the phy back up */
+	if (adapter->hw.media_type == e1000_media_type_copper) {
+		/* according to the manual, the phy will retain its
+		 * settings across a power-down/up cycle */
+		e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
+		mii_reg &= ~MII_CR_POWER_DOWN;
+		e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
+	}
+}
+
+static void e1000_power_down_phy(struct e1000_adapter *adapter)
+{
+	boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) &&
+	                              e1000_check_mng_mode(&adapter->hw);
+	/* Power down the PHY so no link is implied when interface is down
+	 * The PHY cannot be powered down if any of the following is TRUE
+	 * (a) WoL is enabled
+	 * (b) AMT is active
+	 * (c) SoL/IDER session is active */
+	if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
+	    adapter->hw.media_type == e1000_media_type_copper &&
+	    !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) &&
+	    !mng_mode_enabled &&
+	    !e1000_check_phy_reset_block(&adapter->hw)) {
+		uint16_t mii_reg = 0;
+		e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
+		mii_reg |= MII_CR_POWER_DOWN;
+		e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
+		mdelay(1);
+	}
+}
+
 void
 e1000_down(struct e1000_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
-	boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) &&
-	                              e1000_check_mng_mode(&adapter->hw);
 
 	e1000_irq_disable(adapter);
 
@@ -489,23 +525,6 @@ e1000_down(struct e1000_adapter *adapter
 	e1000_reset(adapter);
 	e1000_clean_all_tx_rings(adapter);
 	e1000_clean_all_rx_rings(adapter);
-
-	/* Power down the PHY so no link is implied when interface is down *
-	 * The PHY cannot be powered down if any of the following is TRUE *
-	 * (a) WoL is enabled
-	 * (b) AMT is active
-	 * (c) SoL/IDER session is active */
-	if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
-	   adapter->hw.media_type == e1000_media_type_copper &&
-	   !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) &&
-	   !mng_mode_enabled &&
-	   !e1000_check_phy_reset_block(&adapter->hw)) {
-		uint16_t mii_reg;
-		e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
-		mii_reg |= MII_CR_POWER_DOWN;
-		e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
-		mdelay(1);
-	}
 }
 
 void
@@ -1117,6 +1136,8 @@ e1000_open(struct net_device *netdev)
 	if (err)
 		goto err_up;
 
+	e1000_power_up_phy(adapter);
+
 	if ((err = e1000_up(adapter)))
 		goto err_up;
 	adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
@@ -1162,6 +1183,7 @@ e1000_close(struct net_device *netdev)
 
 	WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags));
 	e1000_down(adapter);
+	e1000_power_down_phy(adapter);
 	e1000_free_irq(adapter);
 
 	e1000_free_all_tx_resources(adapter);



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 04/21] e1000: fix CONFIG_PM blocks
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (2 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 03/21] e1000: Make PHY powerup/down a function Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 05/21] e1000: small performance tweak by removing double code Kok, Auke
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


e1000_suspend is called even when !CONFIG_PM. The non-PM code inside of it
is properly #ifdef'd. This fixes the compiler warnings when !CONFIG_PM.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_main.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 813d5e0..7cf5e5d 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -177,8 +177,8 @@ static void e1000_vlan_rx_add_vid(struct
 static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
 static void e1000_restore_vlan(struct e1000_adapter *adapter);
 
-#ifdef CONFIG_PM
 static int e1000_suspend(struct pci_dev *pdev, pm_message_t state);
+#ifdef CONFIG_PM
 static int e1000_resume(struct pci_dev *pdev);
 #endif
 static void e1000_shutdown(struct pci_dev *pdev);
@@ -205,8 +205,8 @@ static struct pci_driver e1000_driver = 
 	.probe    = e1000_probe,
 	.remove   = __devexit_p(e1000_remove),
 	/* Power Managment Hooks */
-#ifdef CONFIG_PM
 	.suspend  = e1000_suspend,
+#ifdef CONFIG_PM
 	.resume   = e1000_resume,
 #endif
 	.shutdown = e1000_shutdown,
@@ -4498,7 +4498,9 @@ e1000_suspend(struct pci_dev *pdev, pm_m
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	uint32_t ctrl, ctrl_ext, rctl, manc, status;
 	uint32_t wufc = adapter->wol;
+#ifdef CONFIG_PM
 	int retval = 0;
+#endif
 
 	netif_device_detach(netdev);
 



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 05/21] e1000: small performance tweak by removing double code
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (3 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 04/21] e1000: fix CONFIG_PM blocks Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 06/21] e1000: add smart power down code Kok, Auke
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


buffer_info is already filled at the end of this while() loop.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_main.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 7cf5e5d..76e36a4 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -3717,7 +3717,6 @@ e1000_clean_rx_irq_ps(struct e1000_adapt
 	buffer_info = &rx_ring->buffer_info[i];
 
 	while (staterr & E1000_RXD_STAT_DD) {
-		buffer_info = &rx_ring->buffer_info[i];
 		ps_page = &rx_ring->ps_page[i];
 		ps_page_dma = &rx_ring->ps_page_dma[i];
 #ifdef CONFIG_E1000_NAPI



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 06/21] e1000: add smart power down code
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (4 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 05/21] e1000: small performance tweak by removing double code Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-27  1:43   ` Jeff Garzik
  2006-06-22  5:20 ` [PATCH 07/21] e1000: change printk into DPRINTK Kok, Auke
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


Smart Power Down is a power saving feature in newer e1000 hardware. We
disable it because it causes time to link to be long, but make it a
user choice.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000.h       |    1 +
 drivers/net/e1000/e1000_main.c  |   15 +++++++++++++++
 drivers/net/e1000/e1000_param.c |   25 +++++++++++++++++++++++++
 3 files changed, 41 insertions(+), 0 deletions(-)

diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 2b96ad0..dbdaa33 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -338,6 +338,7 @@ struct e1000_adapter {
 #ifdef NETIF_F_TSO
 	boolean_t tso_force;
 #endif
+	boolean_t smart_power_down;	/* phy smart power down */
 	unsigned long flags;
 };
 
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 76e36a4..ea18f30 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -607,6 +607,21 @@ e1000_reset(struct e1000_adapter *adapte
 
 	e1000_reset_adaptive(&adapter->hw);
 	e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
+
+	if (!adapter->smart_power_down &&
+	    (adapter->hw.mac_type == e1000_82571 ||
+	     adapter->hw.mac_type == e1000_82572)) {
+		uint16_t phy_data = 0;
+		/* speed up time to link by disabling smart power down, ignore
+		 * the return value of this function because there is nothing
+		 * different we would do if it failed */
+		e1000_read_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT,
+		                   &phy_data);
+		phy_data &= ~IGP02E1000_PM_SPD;
+		e1000_write_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT,
+		                    phy_data);
+	}
+
 	if (adapter->en_mng_pt) {
 		manc = E1000_READ_REG(&adapter->hw, MANC);
 		manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST);
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index e55f896..a8d9295 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -183,6 +183,15 @@ E1000_PARAM(RxAbsIntDelay, "Receive Abso
 
 E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
 
+/* Enable Smart Power Down of the PHY
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 0 (disabled)
+ */
+
+E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
+
 #define AUTONEG_ADV_DEFAULT  0x2F
 #define AUTONEG_ADV_MASK     0x2F
 #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
@@ -494,6 +503,22 @@ e1000_check_options(struct e1000_adapter
 			adapter->itr = opt.def;
 		}
 	}
+	{ /* Smart Power Down */
+		struct e1000_option opt = {
+			.type = enable_option,
+			.name = "PHY Smart Power Down",
+			.err  = "defaulting to Disabled",
+			.def  = OPTION_DISABLED
+		};
+
+		if (num_SmartPowerDownEnable > bd) {
+			int spd = SmartPowerDownEnable[bd];
+			e1000_validate_option(&spd, &opt, adapter);
+			adapter->smart_power_down = spd;
+		} else {
+			adapter->smart_power_down = opt.def;
+		}
+	}
 
 	switch (adapter->hw.media_type) {
 	case e1000_media_type_fiber:



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 07/21] e1000: change printk into DPRINTK
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (5 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 06/21] e1000: add smart power down code Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 08/21] e1000: recycle skb Kok, Auke
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


Changing a printk message to make clear that this message is originating
from e1000.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_main.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index ea18f30..fc39cbc 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -2841,7 +2841,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
 			case e1000_82573:
 				pull_size = min((unsigned int)4, skb->data_len);
 				if (!__pskb_pull_tail(skb, pull_size)) {
-					printk(KERN_ERR
+					DPRINTK(DRV, ERR,
 						"__pskb_pull_tail failed.\n");
 					dev_kfree_skb_any(skb);
 					return NETDEV_TX_OK;



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 08/21] e1000: recycle skb
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (6 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 07/21] e1000: change printk into DPRINTK Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 09/21] e1000: rework module param code with uninitialized values Kok, Auke
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


Recycle an skb to improve performance a bit.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_main.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index fc39cbc..c58fafd 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -3604,7 +3604,8 @@ e1000_clean_rx_irq(struct e1000_adapter 
 			/* All receives must fit into a single buffer */
 			E1000_DBG("%s: Receive packet consumed multiple"
 				  " buffers\n", netdev->name);
-			dev_kfree_skb_irq(skb);
+			/* recycle */
+			buffer_info-> skb = skb;
 			goto next_desc;
 		}
 



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 09/21] e1000: rework module param code with uninitialized values
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (7 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 08/21] e1000: recycle skb Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 10/21] e1000: force register write flushes to circumvent broken platforms Kok, Auke
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


We can take uninitialized values into account which minimizes code
and allows us to simplify the parameter checking code greatly.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_param.c |  167 ++++++++++++++-------------------------
 1 files changed, 61 insertions(+), 106 deletions(-)

diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index a8d9295..bd6c040 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -45,6 +45,16 @@
  */
 
 #define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
+/* Module Parameters are always initialized to -1, so that the driver
+ * can tell the difference between no user specified value or the
+ * user asking for the default value.
+ * The true default values are loaded in when e1000_check_options is called.
+ *
+ * This is a GCC extension to ANSI C.
+ * See the item "Labeled Elements in Initializers" in the section
+ * "Extensions to the C Language Family" of the GCC documentation.
+ */
+
 #define E1000_PARAM(X, desc) \
 	static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
 	static int num_##X = 0; \
@@ -305,6 +315,7 @@ e1000_check_options(struct e1000_adapter
 		DPRINTK(PROBE, NOTICE,
 		       "Warning: no configuration for board #%i\n", bd);
 		DPRINTK(PROBE, NOTICE, "Using defaults for all values\n");
+		bd = E1000_MAX_NIC;
 	}
 
 	{ /* Transmit Descriptor Count */
@@ -322,14 +333,9 @@ e1000_check_options(struct e1000_adapter
 		opt.arg.r.max = mac_type < e1000_82544 ?
 			E1000_MAX_TXD : E1000_MAX_82544_TXD;
 
-		if (num_TxDescriptors > bd) {
-			tx_ring->count = TxDescriptors[bd];
-			e1000_validate_option(&tx_ring->count, &opt, adapter);
-			E1000_ROUNDUP(tx_ring->count,
-						REQ_TX_DESCRIPTOR_MULTIPLE);
-		} else {
-			tx_ring->count = opt.def;
-		}
+		tx_ring->count = TxDescriptors[bd];
+		e1000_validate_option(&tx_ring->count, &opt, adapter);
+		E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE);
 		for (i = 0; i < adapter->num_tx_queues; i++)
 			tx_ring[i].count = tx_ring->count;
 	}
@@ -348,14 +354,9 @@ e1000_check_options(struct e1000_adapter
 		opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD :
 			E1000_MAX_82544_RXD;
 
-		if (num_RxDescriptors > bd) {
-			rx_ring->count = RxDescriptors[bd];
-			e1000_validate_option(&rx_ring->count, &opt, adapter);
-			E1000_ROUNDUP(rx_ring->count,
-						REQ_RX_DESCRIPTOR_MULTIPLE);
-		} else {
-			rx_ring->count = opt.def;
-		}
+		rx_ring->count = RxDescriptors[bd];
+		e1000_validate_option(&rx_ring->count, &opt, adapter);
+		E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE);
 		for (i = 0; i < adapter->num_rx_queues; i++)
 			rx_ring[i].count = rx_ring->count;
 	}
@@ -367,13 +368,9 @@ e1000_check_options(struct e1000_adapter
 			.def  = OPTION_ENABLED
 		};
 
-		if (num_XsumRX > bd) {
-			int rx_csum = XsumRX[bd];
-			e1000_validate_option(&rx_csum, &opt, adapter);
-			adapter->rx_csum = rx_csum;
-		} else {
-			adapter->rx_csum = opt.def;
-		}
+		int rx_csum = XsumRX[bd];
+		e1000_validate_option(&rx_csum, &opt, adapter);
+		adapter->rx_csum = rx_csum;
 	}
 	{ /* Flow Control */
 
@@ -393,13 +390,9 @@ e1000_check_options(struct e1000_adapter
 					 .p = fc_list }}
 		};
 
-		if (num_FlowControl > bd) {
-			int fc = FlowControl[bd];
-			e1000_validate_option(&fc, &opt, adapter);
-			adapter->hw.fc = adapter->hw.original_fc = fc;
-		} else {
-			adapter->hw.fc = adapter->hw.original_fc = opt.def;
-		}
+		int fc = FlowControl[bd];
+		e1000_validate_option(&fc, &opt, adapter);
+		adapter->hw.fc = adapter->hw.original_fc = fc;
 	}
 	{ /* Transmit Interrupt Delay */
 		struct e1000_option opt = {
@@ -411,13 +404,8 @@ e1000_check_options(struct e1000_adapter
 					 .max = MAX_TXDELAY }}
 		};
 
-		if (num_TxIntDelay > bd) {
-			adapter->tx_int_delay = TxIntDelay[bd];
-			e1000_validate_option(&adapter->tx_int_delay, &opt,
-								adapter);
-		} else {
-			adapter->tx_int_delay = opt.def;
-		}
+		adapter->tx_int_delay = TxIntDelay[bd];
+		e1000_validate_option(&adapter->tx_int_delay, &opt, adapter);
 	}
 	{ /* Transmit Absolute Interrupt Delay */
 		struct e1000_option opt = {
@@ -429,13 +417,9 @@ e1000_check_options(struct e1000_adapter
 					 .max = MAX_TXABSDELAY }}
 		};
 
-		if (num_TxAbsIntDelay > bd) {
-			adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
-			e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
-								adapter);
-		} else {
-			adapter->tx_abs_int_delay = opt.def;
-		}
+		adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
+		e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
+		                      adapter);
 	}
 	{ /* Receive Interrupt Delay */
 		struct e1000_option opt = {
@@ -447,13 +431,8 @@ e1000_check_options(struct e1000_adapter
 					 .max = MAX_RXDELAY }}
 		};
 
-		if (num_RxIntDelay > bd) {
-			adapter->rx_int_delay = RxIntDelay[bd];
-			e1000_validate_option(&adapter->rx_int_delay, &opt,
-								adapter);
-		} else {
-			adapter->rx_int_delay = opt.def;
-		}
+		adapter->rx_int_delay = RxIntDelay[bd];
+		e1000_validate_option(&adapter->rx_int_delay, &opt, adapter);
 	}
 	{ /* Receive Absolute Interrupt Delay */
 		struct e1000_option opt = {
@@ -465,13 +444,9 @@ e1000_check_options(struct e1000_adapter
 					 .max = MAX_RXABSDELAY }}
 		};
 
-		if (num_RxAbsIntDelay > bd) {
-			adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
-			e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
-								adapter);
-		} else {
-			adapter->rx_abs_int_delay = opt.def;
-		}
+		adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
+		e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
+		                      adapter);
 	}
 	{ /* Interrupt Throttling Rate */
 		struct e1000_option opt = {
@@ -483,24 +458,18 @@ e1000_check_options(struct e1000_adapter
 					 .max = MAX_ITR }}
 		};
 
-		if (num_InterruptThrottleRate > bd) {
-			adapter->itr = InterruptThrottleRate[bd];
-			switch (adapter->itr) {
-			case 0:
-				DPRINTK(PROBE, INFO, "%s turned off\n",
-					opt.name);
-				break;
-			case 1:
-				DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
-					opt.name);
-				break;
-			default:
-				e1000_validate_option(&adapter->itr, &opt,
-					adapter);
-				break;
-			}
-		} else {
-			adapter->itr = opt.def;
+		adapter->itr = InterruptThrottleRate[bd];
+		switch (adapter->itr) {
+		case 0:
+			DPRINTK(PROBE, INFO, "%s turned off\n", opt.name);
+			break;
+		case 1:
+			DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
+				opt.name);
+			break;
+		default:
+			e1000_validate_option(&adapter->itr, &opt, adapter);
+			break;
 		}
 	}
 	{ /* Smart Power Down */
@@ -511,13 +480,9 @@ e1000_check_options(struct e1000_adapter
 			.def  = OPTION_DISABLED
 		};
 
-		if (num_SmartPowerDownEnable > bd) {
-			int spd = SmartPowerDownEnable[bd];
-			e1000_validate_option(&spd, &opt, adapter);
-			adapter->smart_power_down = spd;
-		} else {
-			adapter->smart_power_down = opt.def;
-		}
+		int spd = SmartPowerDownEnable[bd];
+		e1000_validate_option(&spd, &opt, adapter);
+		adapter->smart_power_down = spd;
 	}
 
 	switch (adapter->hw.media_type) {
@@ -544,17 +509,18 @@ static void __devinit
 e1000_check_fiber_options(struct e1000_adapter *adapter)
 {
 	int bd = adapter->bd_number;
-	if (num_Speed > bd) {
+	bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd;
+	if ((Speed[bd] != OPTION_UNSET)) {
 		DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, "
 		       "parameter ignored\n");
 	}
 
-	if (num_Duplex > bd) {
+	if ((Duplex[bd] != OPTION_UNSET)) {
 		DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, "
 		       "parameter ignored\n");
 	}
 
-	if ((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) {
+	if ((AutoNeg[bd] != OPTION_UNSET) && (AutoNeg[bd] != 0x20)) {
 		DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is "
 				 "not valid for fiber adapters, "
 				 "parameter ignored\n");
@@ -573,6 +539,7 @@ e1000_check_copper_options(struct e1000_
 {
 	int speed, dplx, an;
 	int bd = adapter->bd_number;
+	bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd;
 
 	{ /* Speed */
 		struct e1000_opt_list speed_list[] = {{          0, "" },
@@ -589,12 +556,8 @@ e1000_check_copper_options(struct e1000_
 					 .p = speed_list }}
 		};
 
-		if (num_Speed > bd) {
-			speed = Speed[bd];
-			e1000_validate_option(&speed, &opt, adapter);
-		} else {
-			speed = opt.def;
-		}
+		speed = Speed[bd];
+		e1000_validate_option(&speed, &opt, adapter);
 	}
 	{ /* Duplex */
 		struct e1000_opt_list dplx_list[] = {{           0, "" },
@@ -616,15 +579,11 @@ e1000_check_copper_options(struct e1000_
 			        "Speed/Duplex/AutoNeg parameter ignored.\n");
 			return;
 		}
-		if (num_Duplex > bd) {
-			dplx = Duplex[bd];
-			e1000_validate_option(&dplx, &opt, adapter);
-		} else {
-			dplx = opt.def;
-		}
+		dplx = Duplex[bd];
+		e1000_validate_option(&dplx, &opt, adapter);
 	}
 
-	if ((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) {
+	if (AutoNeg[bd] != OPTION_UNSET && (speed != 0 || dplx != 0)) {
 		DPRINTK(PROBE, INFO,
 		       "AutoNeg specified along with Speed or Duplex, "
 		       "parameter ignored\n");
@@ -673,19 +632,15 @@ e1000_check_copper_options(struct e1000_
 					 .p = an_list }}
 		};
 
-		if (num_AutoNeg > bd) {
-			an = AutoNeg[bd];
-			e1000_validate_option(&an, &opt, adapter);
-		} else {
-			an = opt.def;
-		}
+		an = AutoNeg[bd];
+		e1000_validate_option(&an, &opt, adapter);
 		adapter->hw.autoneg_advertised = an;
 	}
 
 	switch (speed + dplx) {
 	case 0:
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
-		if ((num_Speed > bd) && (speed != 0 || dplx != 0))
+		if (Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET)
 			DPRINTK(PROBE, INFO,
 			       "Speed and duplex autonegotiation enabled\n");
 		break;



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 10/21] e1000: force register write flushes to circumvent broken platforms
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (8 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 09/21] e1000: rework module param code with uninitialized values Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-27  1:47   ` Jeff Garzik
  2006-06-22  5:20 ` [PATCH 11/21] e1000: disable CRC stripping workaround Kok, Auke
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


A certain AMD64 bridge (8132) has an option to turn on write combining
which breaks our adapter. To circumvent this we need to flush every write.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_hw.c   |   24 ++++++++++++++++++++++--
 drivers/net/e1000/e1000_main.c |   18 +++++++++++-------
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 3959039..749d621 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -705,8 +705,12 @@ e1000_init_hw(struct e1000_hw *hw)
     /* Zero out the Multicast HASH table */
     DEBUGOUT("Zeroing the MTA\n");
     mta_size = E1000_MC_TBL_SIZE;
-    for(i = 0; i < mta_size; i++)
+    for(i = 0; i < mta_size; i++) {
         E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+        /* use write flush to prevent Memory Write Block (MWB) from
+         * occuring when accessing our register space */
+        E1000_WRITE_FLUSH(hw);
+    }
 
     /* Set the PCI priority bit correctly in the CTRL register.  This
      * determines if the adapter gives priority to receives, or if it
@@ -5106,7 +5110,9 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
     DEBUGOUT("Clearing RAR[1-15]\n");
     for(i = 1; i < rar_num; i++) {
         E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+        E1000_WRITE_FLUSH(hw);
         E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+        E1000_WRITE_FLUSH(hw);
     }
 }
 
@@ -5153,7 +5159,9 @@ e1000_mc_addr_list_update(struct e1000_h
 
     for(i = rar_used_count; i < num_rar_entry; i++) {
         E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+        E1000_WRITE_FLUSH(hw);
         E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+        E1000_WRITE_FLUSH(hw);
     }
 
     /* Clear the MTA */
@@ -5161,6 +5169,7 @@ e1000_mc_addr_list_update(struct e1000_h
     num_mta_entry = E1000_NUM_MTA_REGISTERS;
     for(i = 0; i < num_mta_entry; i++) {
         E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+        E1000_WRITE_FLUSH(hw);
     }
 
     /* Add the new addresses */
@@ -5275,9 +5284,12 @@ e1000_mta_set(struct e1000_hw *hw,
     if((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
         temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1));
         E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+        E1000_WRITE_FLUSH(hw);
         E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp);
+        E1000_WRITE_FLUSH(hw);
     } else {
         E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+        E1000_WRITE_FLUSH(hw);
     }
 }
 
@@ -5334,7 +5346,9 @@ e1000_rar_set(struct e1000_hw *hw,
     }
 
     E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low);
+    E1000_WRITE_FLUSH(hw);
     E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high);
+    E1000_WRITE_FLUSH(hw);
 }
 
 /******************************************************************************
@@ -5354,9 +5368,12 @@ e1000_write_vfta(struct e1000_hw *hw,
     if((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
         temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1));
         E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+        E1000_WRITE_FLUSH(hw);
         E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp);
+        E1000_WRITE_FLUSH(hw);
     } else {
         E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+        E1000_WRITE_FLUSH(hw);
     }
 }
 
@@ -5392,6 +5409,7 @@ e1000_clear_vfta(struct e1000_hw *hw)
          * manageability unit */
         vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
         E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value);
+        E1000_WRITE_FLUSH(hw);
     }
 }
 
@@ -6928,8 +6946,10 @@ e1000_mng_write_cmd_header(struct e1000_
 
     length >>= 2;
     /* The device driver writes the relevant command block into the ram area. */
-    for (i = 0; i < length; i++)
+    for (i = 0; i < length; i++) {
         E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i));
+        E1000_WRITE_FLUSH(hw);
+    }
 
     return E1000_SUCCESS;
 }
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index c58fafd..c44ed6f 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1370,11 +1370,11 @@ e1000_configure_tx(struct e1000_adapter 
 		tdba = adapter->tx_ring[0].dma;
 		tdlen = adapter->tx_ring[0].count *
 			sizeof(struct e1000_tx_desc);
-		E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL));
-		E1000_WRITE_REG(hw, TDBAH, (tdba >> 32));
 		E1000_WRITE_REG(hw, TDLEN, tdlen);
-		E1000_WRITE_REG(hw, TDH, 0);
+		E1000_WRITE_REG(hw, TDBAH, (tdba >> 32));
+		E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL));
 		E1000_WRITE_REG(hw, TDT, 0);
+		E1000_WRITE_REG(hw, TDH, 0);
 		adapter->tx_ring[0].tdh = E1000_TDH;
 		adapter->tx_ring[0].tdt = E1000_TDT;
 		break;
@@ -1780,11 +1780,11 @@ e1000_configure_rx(struct e1000_adapter 
 	case 1:
 	default:
 		rdba = adapter->rx_ring[0].dma;
-		E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL));
-		E1000_WRITE_REG(hw, RDBAH, (rdba >> 32));
 		E1000_WRITE_REG(hw, RDLEN, rdlen);
-		E1000_WRITE_REG(hw, RDH, 0);
+		E1000_WRITE_REG(hw, RDBAH, (rdba >> 32));
+		E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL));
 		E1000_WRITE_REG(hw, RDT, 0);
+		E1000_WRITE_REG(hw, RDH, 0);
 		adapter->rx_ring[0].rdh = E1000_RDH;
 		adapter->rx_ring[0].rdt = E1000_RDT;
 		break;
@@ -2189,14 +2189,18 @@ e1000_set_multi(struct net_device *netde
 			mc_ptr = mc_ptr->next;
 		} else {
 			E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0);
+			E1000_WRITE_FLUSH(hw);
 			E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0);
+			E1000_WRITE_FLUSH(hw);
 		}
 	}
 
 	/* clear the old settings from the multicast hash table */
 
-	for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++)
+	for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
 		E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+		E1000_WRITE_FLUSH(hw);
+	}
 
 	/* load any remaining addresses into the hash table */
 



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 11/21] e1000: disable CRC stripping workaround
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (9 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 10/21] e1000: force register write flushes to circumvent broken platforms Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:31   ` Ben Greear
  2006-06-27  1:48   ` Jeff Garzik
  2006-06-22  5:20 ` [PATCH 12/21] e1000: fix adapter led blinking inconsistency Kok, Auke
                   ` (10 subsequent siblings)
  21 siblings, 2 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


CRC stripping is breaking SMBUS-connected BMC's. We disable this
feature to make it work. This fixes related bugs regarding SOL.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_main.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index c44ed6f..7787299 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1628,8 +1628,11 @@ e1000_setup_rctl(struct e1000_adapter *a
 		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
 		(adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
 
+	/* disable hardware stripping of CRC because it breaks
+	 * BMC firmware connected over SMBUS
 	if (adapter->hw.mac_type > e1000_82543)
 		rctl |= E1000_RCTL_SECRC;
+	 */
 
 	if (adapter->hw.tbi_compatibility_on == 1)
 		rctl |= E1000_RCTL_SBP;
@@ -1696,7 +1699,9 @@ e1000_setup_rctl(struct e1000_adapter *a
 		rfctl |= E1000_RFCTL_IPV6_DIS;
 		E1000_WRITE_REG(&adapter->hw, RFCTL, rfctl);
 
-		rctl |= E1000_RCTL_DTYP_PS | E1000_RCTL_SECRC;
+		/* disable the stripping of CRC because it breaks
+		 * BMC firmware connected over SMBUS */
+		rctl |= E1000_RCTL_DTYP_PS /* | E1000_RCTL_SECRC */;
 
 		psrctl |= adapter->rx_ps_bsize0 >>
 			E1000_PSRCTL_BSIZE0_SHIFT;



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 12/21] e1000: fix adapter led blinking inconsistency
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (10 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 11/21] e1000: disable CRC stripping workaround Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 13/21] e1000: add E1000_BIG_ENDIAN symbol Kok, Auke
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


Several e1000 adapters were not blinking correctly or inconsistently. This
patch cleans this up and makes them all behave the same as far as possible.

Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_ethtool.c |   15 +--------------
 drivers/net/e1000/e1000_hw.c      |   38 +++++++++++++++++++++++++++++++++++++
 drivers/net/e1000/e1000_hw.h      |    1 +
 3 files changed, 40 insertions(+), 14 deletions(-)

diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index cf5c5f4..0609155 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -1786,21 +1786,8 @@ e1000_phys_id(struct net_device *netdev,
 		mod_timer(&adapter->blink_timer, jiffies);
 		msleep_interruptible(data * 1000);
 		del_timer_sync(&adapter->blink_timer);
-	} else if (adapter->hw.mac_type < e1000_82573) {
-		E1000_WRITE_REG(&adapter->hw, LEDCTL,
-			(E1000_LEDCTL_LED2_BLINK_RATE |
-			 E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED2_BLINK |
-			 (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
-			 (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED0_MODE_SHIFT) |
-			 (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED1_MODE_SHIFT)));
-		msleep_interruptible(data * 1000);
 	} else {
-		E1000_WRITE_REG(&adapter->hw, LEDCTL,
-			(E1000_LEDCTL_LED2_BLINK_RATE |
-			 E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK |
-			 (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
-			 (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) |
-			 (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT)));
+		e1000_blink_led_start(&adapter->hw);
 		msleep_interruptible(data * 1000);
 	}
 
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 749d621..1c5b184 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -5537,6 +5537,44 @@ e1000_setup_led(struct e1000_hw *hw)
 }
 
 /******************************************************************************
+ * Used on 82571 and later Si that has LED blink bits.
+ * Callers must use their own timer and should have already called
+ * e1000_id_led_init()
+ * Call e1000_cleanup led() to stop blinking
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_blink_led_start(struct e1000_hw *hw)
+{
+    int16_t  i;
+    uint32_t ledctl_blink = 0;
+
+    DEBUGFUNC("e1000_id_led_blink_on");
+
+    if (hw->mac_type < e1000_82571) {
+        /* Nothing to do */
+        return E1000_SUCCESS;
+    }
+    if (hw->media_type == e1000_media_type_fiber) {
+        /* always blink LED0 for PCI-E fiber */
+        ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+                     (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+    } else {
+        /* set the blink bit for each LED that's "on" (0x0E) in ledctl_mode2 */
+        ledctl_blink = hw->ledctl_mode2;
+        for (i=0; i < 4; i++)
+            if (((hw->ledctl_mode2 >> (i * 8)) & 0xFF) ==
+                E1000_LEDCTL_MODE_LED_ON)
+                ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << (i * 8));
+    }
+
+    E1000_WRITE_REG(hw, LEDCTL, ledctl_blink);
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
  * Restores the saved state of the SW controlable LED.
  *
  * hw - Struct containing variables accessed by shared code
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 467c9ed..941b47d 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -401,6 +401,7 @@ int32_t e1000_setup_led(struct e1000_hw 
 int32_t e1000_cleanup_led(struct e1000_hw *hw);
 int32_t e1000_led_on(struct e1000_hw *hw);
 int32_t e1000_led_off(struct e1000_hw *hw);
+int32_t e1000_blink_led_start(struct e1000_hw *hw);
 
 /* Adaptive IFS Functions */
 



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 13/21] e1000: add E1000_BIG_ENDIAN symbol
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (11 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 12/21] e1000: fix adapter led blinking inconsistency Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-27  1:49   ` Jeff Garzik
  2006-06-22  5:20 ` [PATCH 14/21] e1000: M88 PHY workaround Kok, Auke
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


This adds a private symbol to signify endianess in our driver.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_hw.h    |    2 +-
 drivers/net/e1000/e1000_osdep.h |    3 +++
 2 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 941b47d..376a2ef 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -351,7 +351,7 @@ struct e1000_host_mng_command_info {
     struct e1000_host_mng_command_header command_header;  /* Command Head/Command Result Head has 4 bytes */
     uint8_t command_data[E1000_HI_MAX_MNG_DATA_LENGTH];   /* Command data can length 0..0x658*/
 };
-#ifdef __BIG_ENDIAN
+#ifdef E1000_BIG_ENDIAN
 struct e1000_host_mng_dhcp_cookie{
     uint32_t signature;
     uint16_t vlan_id;
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index 048d052..6130a42 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -83,6 +83,9 @@ typedef enum {
 #define DEBUGOUT3 DEBUGOUT2
 #define DEBUGOUT7 DEBUGOUT3
 
+#ifdef __BIG_ENDIAN
+#define E1000_BIG_ENDIAN __BIG_ENDIAN
+#endif
 
 #define E1000_WRITE_REG(a, reg, value) ( \
     writel((value), ((a)->hw_addr + \



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 14/21] e1000: M88 PHY workaround
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (12 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 13/21] e1000: add E1000_BIG_ENDIAN symbol Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 15/21] e1000: check return value of _get_speed_and_duplex Kok, Auke
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


M88 rev 2 PHY needs a longer downshift to function properly. This adds
a much longer downshift counter for this specific device.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_hw.c |   46 ++++++++++++++++++++++++++----------------
 drivers/net/e1000/e1000_hw.h |   11 ++++++++++
 2 files changed, 40 insertions(+), 17 deletions(-)

diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 1c5b184..37eb351 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -1565,28 +1565,40 @@ e1000_copper_link_mgp_setup(struct e1000
     phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
     if(hw->disable_polarity_correction == 1)
         phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
-        ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-        if(ret_val)
-            return ret_val;
-
-    /* Force TX_CLK in the Extended PHY Specific Control Register
-     * to 25MHz clock.
-     */
-    ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
-    if(ret_val)
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+    if (ret_val)
         return ret_val;
 
-    phy_data |= M88E1000_EPSCR_TX_CLK_25;
-
     if (hw->phy_revision < M88E1011_I_REV_4) {
-        /* Configure Master and Slave downshift values */
-        phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+        /* Force TX_CLK in the Extended PHY Specific Control Register
+         * to 25MHz clock.
+         */
+        ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+        if (ret_val)
+            return ret_val;
+
+        phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+        if ((hw->phy_revision == E1000_REVISION_2) &&
+            (hw->phy_id == M88E1111_I_PHY_ID)) {
+            /* Vidalia Phy, set the downshift counter to 5x */
+            phy_data &= ~(M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK);
+            phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+            ret_val = e1000_write_phy_reg(hw,
+                                        M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+            if (ret_val)
+                return ret_val;
+        } else {
+            /* Configure Master and Slave downshift values */
+            phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
                               M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
-        phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+            phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
                              M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
-        ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
-        if(ret_val)
-            return ret_val;
+            ret_val = e1000_write_phy_reg(hw,
+                                        M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+            if (ret_val)
+               return ret_val;
+        }
     }
 
     /* SW Reset the PHY so all changes take effect */
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 376a2ef..bfbc7d8 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -2765,6 +2765,17 @@ struct e1000_host_command_info {
 #define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
 #define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
 
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X    0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X    0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X    0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X    0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X    0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X    0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X    0x0E00
+
 /* IGP01E1000 Specific Port Config Register - R/W */
 #define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT  0x0010
 #define IGP01E1000_PSCFR_PRE_EN                0x0020



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 15/21] e1000: check return value of _get_speed_and_duplex
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (13 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 14/21] e1000: M88 PHY workaround Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 16/21] e1000: disable ERT Kok, Auke
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


We were not checking the return value of get_speed_and_duplex
properly, whih may contain an error value.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_hw.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 37eb351..784f950 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -2737,8 +2737,12 @@ e1000_check_for_link(struct e1000_hw *hw
          */
         if(hw->tbi_compatibility_en) {
             uint16_t speed, duplex;
-            e1000_get_speed_and_duplex(hw, &speed, &duplex);
-            if(speed != SPEED_1000) {
+            ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);
+            if (ret_val) {
+                DEBUGOUT("Error getting link speed and duplex\n");
+                return ret_val;
+            }
+            if (speed != SPEED_1000) {
                 /* If link speed is not set to gigabit speed, we do not need
                  * to enable TBI compatibility.
                  */



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 16/21] e1000: disable ERT
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (14 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 15/21] e1000: check return value of _get_speed_and_duplex Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 17/21] e1000: add ich8lan core functions Kok, Auke
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


Hardware is reported to have problems with ERT. We disable it for
all hardware to make sure we are not seeing unexplainable user
problems.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_main.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 7787299..f5689fa 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1814,9 +1814,6 @@ e1000_configure_rx(struct e1000_adapter 
 		E1000_WRITE_REG(hw, RXCSUM, rxcsum);
 	}
 
-	if (hw->mac_type == e1000_82573)
-		E1000_WRITE_REG(hw, ERT, 0x0100);
-
 	/* Enable Receives */
 	E1000_WRITE_REG(hw, RCTL, rctl);
 }



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 17/21] e1000: add ich8lan core functions
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (15 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 16/21] e1000: disable ERT Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-27  1:52   ` Jeff Garzik
  2006-06-22  5:20 ` [PATCH 18/21] e1000: integrate ich8 support into driver Kok, Auke
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


This implements the core new functions needed for ich8's internal
NIC. This includes:

* ich8 specific read/write code
* flash/nvm access code
* software semaphore flag functions
* 10/100 PHY (fe - no gigabit speed) support for low-end versions
* A workaround for a powerdown sequence problem discovered that
affects a small number of motherboard.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_hw.c    | 1000 +++++++++++++++++++++++++++++++++++++++
 drivers/net/e1000/e1000_hw.h    |  386 +++++++++++++++
 drivers/net/e1000/e1000_osdep.h |   13 +
 3 files changed, 1392 insertions(+), 7 deletions(-)

diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 784f950..a3f5ccd 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -3617,11 +3617,120 @@ e1000_phy_reset(struct e1000_hw *hw)
 }
 
 /******************************************************************************
+* Work-around for 82566 power-down: on D3 entry-
+* 1) disable gigabit link
+* 2) write VR power-down enable
+* 3) read it back
+* if successful continue, else issue LCD reset and repeat
+*
+* hw - struct containing variables accessed by shared code
+******************************************************************************/
+void
+e1000_phy_powerdown_workaround(struct e1000_hw *hw)
+{
+    int32_t reg;
+    uint16_t phy_data;
+    int32_t retry = 0;
+
+    DEBUGFUNC("e1000_phy_powerdown_workaround");
+
+    if (hw->phy_type != e1000_phy_igp_3)
+        return;
+
+    do {
+        /* Disable link */
+        reg = E1000_READ_REG(hw, PHY_CTRL);
+        E1000_WRITE_REG(hw, PHY_CTRL, reg | E1000_PHY_CTRL_GBE_DISABLE |
+                        E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+
+        /* Write VR power-down enable */
+        e1000_read_phy_reg(hw, IGP3_VR_CTRL, &phy_data);
+        e1000_write_phy_reg(hw, IGP3_VR_CTRL, phy_data |
+                            IGP3_VR_CTRL_MODE_SHUT);
+
+        /* Read it back and test */
+        e1000_read_phy_reg(hw, IGP3_VR_CTRL, &phy_data);
+        if ((phy_data & IGP3_VR_CTRL_MODE_SHUT) || retry)
+            break;
+
+        /* Issue PHY reset and repeat at most one more time */
+        reg = E1000_READ_REG(hw, CTRL);
+        E1000_WRITE_REG(hw, CTRL, reg | E1000_CTRL_PHY_RST);
+        retry++;
+    } while (retry);
+
+    return;
+
+}
+
+/******************************************************************************
+* Work-around for 82566 Kumeran PCS lock loss:
+* On link status change (i.e. PCI reset, speed change) and link is up and
+* speed is gigabit-
+* 0) if workaround is optionally disabled do nothing
+* 1) wait 1ms for Kumeran link to come up
+* 2) check Kumeran Diagnostic register PCS lock loss bit
+* 3) if not set the link is locked (all is good), otherwise...
+* 4) reset the PHY
+* 5) repeat up to 10 times
+* Note: this is only called for IGP3 copper when speed is 1gb.
+*
+* hw - struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw)
+{
+    int32_t ret_val;
+    int32_t reg;
+    int32_t cnt;
+    uint16_t phy_data;
+
+    if (hw->kmrn_lock_loss_workaround_disabled)
+        return E1000_SUCCESS;
+
+    /* Make sure link is up before proceeding. If not just return.
+     * Attempting this while link is negotiating fouls up link
+     * stability */
+    ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+    ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+
+    if (phy_data & MII_SR_LINK_STATUS) {
+        for (cnt = 0; cnt < 10; cnt++) {
+            /* read once to clear */
+            ret_val = e1000_read_phy_reg(hw, IGP3_KMRN_DIAG, &phy_data);
+            if (ret_val)
+                return ret_val;
+            /* and again to get new status */
+            ret_val = e1000_read_phy_reg(hw, IGP3_KMRN_DIAG, &phy_data);
+            if (ret_val)
+                return ret_val;
+
+            /* check for PCS lock */
+            if (!(phy_data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS))
+                return E1000_SUCCESS;
+
+            /* Issue PHY reset */
+            e1000_phy_hw_reset(hw);
+            msec_delay_irq(5);
+        }
+        /* Disable GigE link negotiation */
+        reg = E1000_READ_REG(hw, PHY_CTRL);
+        E1000_WRITE_REG(hw, PHY_CTRL, reg | E1000_PHY_CTRL_GBE_DISABLE |
+                        E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+
+        /* unable to acquire PCS lock */
+        return E1000_ERR_PHY;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
 * Probes the expected PHY address for known PHY IDs
 *
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
-static int32_t
+int32_t
 e1000_detect_gig_phy(struct e1000_hw *hw)
 {
     int32_t phy_init_status, ret_val;
@@ -3804,6 +3913,53 @@ e1000_phy_igp_get_info(struct e1000_hw *
 }
 
 /******************************************************************************
+* Get PHY information from various PHY registers for ife PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+e1000_phy_ife_get_info(struct e1000_hw *hw,
+                       struct e1000_phy_info *phy_info)
+{
+    int32_t ret_val;
+    uint16_t phy_data, polarity;
+
+    DEBUGFUNC("e1000_phy_ife_get_info");
+
+    phy_info->downshift = (e1000_downshift)hw->speed_downgraded;
+    phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_normal;
+
+    ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
+    if (ret_val)
+        return ret_val;
+    phy_info->polarity_correction =
+                        (phy_data & IFE_PSC_AUTO_POLARITY_DISABLE) >>
+                        IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT;
+
+    if (phy_info->polarity_correction == e1000_polarity_reversal_enabled) {
+        ret_val = e1000_check_polarity(hw, &polarity);
+        if (ret_val)
+            return ret_val;
+    } else {
+        /* Polarity is forced. */
+        polarity = (phy_data & IFE_PSC_FORCE_POLARITY) >>
+                       IFE_PSC_FORCE_POLARITY_SHIFT;
+    }
+    phy_info->cable_polarity = polarity;
+
+    ret_val = e1000_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data);
+    if (ret_val)
+        return ret_val;
+
+    phy_info->mdix_mode =
+                     (phy_data & (IFE_PMC_AUTO_MDIX | IFE_PMC_FORCE_MDIX)) >>
+                     IFE_PMC_MDIX_MODE_SHIFT;
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
 * Get PHY information from various PHY registers fot m88 PHY only.
 *
 * hw - Struct containing variables accessed by shared code
@@ -7630,4 +7786,846 @@ e1000_arc_subsystem_valid(struct e1000_h
 }
 
 
+/******************************************************************************
+ * Configure PCI-Ex no-snoop
+ *
+ * hw - Struct containing variables accessed by shared code.
+ * no_snoop - Bitmap of no-snoop events.
+ *
+ * returns: E1000_SUCCESS
+ *
+ *****************************************************************************/
+int32_t
+e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop)
+{
+    uint32_t gcr_reg = 0;
+
+    DEBUGFUNC("e1000_set_pci_ex_no_snoop");
+
+    if (hw->bus_type == e1000_bus_type_unknown)
+        e1000_get_bus_info(hw);
+
+    if (hw->bus_type != e1000_bus_type_pci_express)
+        return E1000_SUCCESS;
+
+    if (no_snoop) {
+        gcr_reg = E1000_READ_REG(hw, GCR);
+        gcr_reg &= ~(PCI_EX_NO_SNOOP_ALL);
+        gcr_reg |= no_snoop;
+        E1000_WRITE_REG(hw, GCR, gcr_reg);
+    }
+    if (hw->mac_type == e1000_ich8lan) {
+        uint32_t ctrl_ext;
+
+        E1000_WRITE_REG(hw, GCR, PCI_EX_82566_SNOOP_ALL);
+
+        ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+        ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+    }
+
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Get software semaphore FLAG bit (SWFLAG).
+ * SWFLAG is used to synchronize the access to all shared resource between
+ * SW, FW and HW.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+int32_t
+e1000_get_software_flag(struct e1000_hw *hw)
+{
+    int32_t timeout = PHY_CFG_TIMEOUT;
+    uint32_t extcnf_ctrl;
+
+    DEBUGFUNC("e1000_get_software_flag");
+
+    if (hw->mac_type == e1000_ich8lan) {
+        while (timeout) {
+            extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+            extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+            E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
+
+            extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+            if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+                break;
+            msec_delay_irq(1);
+            timeout--;
+        }
+
+        if (!timeout) {
+            DEBUGOUT("FW or HW locks the resource too long.\n");
+            return -E1000_ERR_CONFIG;
+        }
+    }
+
+    return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Release software semaphore FLAG bit (SWFLAG).
+ * SWFLAG is used to synchronize the access to all shared resource between
+ * SW, FW and HW.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+void
+e1000_release_software_flag(struct e1000_hw *hw)
+{
+    uint32_t extcnf_ctrl;
+
+    DEBUGFUNC("e1000_release_software_flag");
+
+    if (hw->mac_type == e1000_ich8lan) {
+        extcnf_ctrl= E1000_READ_REG(hw, EXTCNF_CTRL);
+        extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+        E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
+    }
+
+    return;
+}
+
+/***************************************************************************
+ *
+ * Disable dynamic power down mode in ife PHY.
+ * It can be used to workaround band-gap problem.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+int32_t
+e1000_ife_disable_dynamic_power_down(struct e1000_hw *hw)
+{
+    uint16_t phy_data;
+    int32_t ret_val = E1000_SUCCESS;
+
+    DEBUGFUNC("e1000_ife_disable_dynamic_power_down");
+
+    if (hw->phy_type == e1000_phy_ife) {
+        ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
+        if (ret_val)
+            return ret_val;
+
+        phy_data |=  IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN;
+        ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data);
+    }
+
+    return ret_val;
+}
+
+/***************************************************************************
+ *
+ * Enable dynamic power down mode in ife PHY.
+ * It can be used to workaround band-gap problem.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+int32_t
+e1000_ife_enable_dynamic_power_down(struct e1000_hw *hw)
+{
+    uint16_t phy_data;
+    int32_t ret_val = E1000_SUCCESS;
+
+    DEBUGFUNC("e1000_ife_enable_dynamic_power_down");
+
+    if (hw->phy_type == e1000_phy_ife) {
+        ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
+        if (ret_val)
+            return ret_val;
+
+        phy_data &=  ~IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN;
+        ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data);
+    }
+
+    return ret_val;
+}
+
+/******************************************************************************
+ * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access
+ * register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words,
+                       uint16_t *data)
+{
+    int32_t  error = E1000_SUCCESS;
+    uint32_t flash_bank = 0;
+    uint32_t act_offset = 0;
+    uint32_t bank_offset = 0;
+    uint16_t word = 0;
+    uint16_t i = 0;
+
+    /* We need to know which is the valid flash bank.  In the event
+     * that we didn't allocate eeprom_shadow_ram, we may not be
+     * managing flash_bank.  So it cannot be trusted and needs
+     * to be updated with each read.
+     */
+    /* Value of bit 22 corresponds to the flash bank we're on. */
+    flash_bank = (E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL) ? 1 : 0;
+
+    /* Adjust offset appropriately if we're on bank 1 - adjust for word size */
+    bank_offset = flash_bank * (hw->flash_bank_size * 2);
+
+    error = e1000_get_software_flag(hw);
+    if (error != E1000_SUCCESS)
+        return error;
+
+    for (i = 0; i < words; i++) {
+        if (hw->eeprom_shadow_ram != NULL &&
+            hw->eeprom_shadow_ram[offset+i].modified == TRUE) {
+            data[i] = hw->eeprom_shadow_ram[offset+i].eeprom_word;
+        } else {
+            /* The NVM part needs a byte offset, hence * 2 */
+            act_offset = bank_offset + ((offset + i) * 2);
+            error = e1000_read_ich8_word(hw, act_offset, &word);
+            if (error != E1000_SUCCESS)
+                break;
+            data[i] = word;
+        }
+    }
+
+    e1000_release_software_flag(hw);
+
+    return error;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word or words to the EEPROM using the ICH8's flash access
+ * register.  Actually, writes are written to the shadow ram cache in the hw
+ * structure hw->e1000_shadow_ram.  e1000_commit_shadow_ram flushes this to
+ * the NVM, which occurs when the NVM checksum is updated.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to write
+ * words - number of words to write
+ * data - words to write to the EEPROM
+ *****************************************************************************/
+int32_t
+e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words,
+                        uint16_t *data)
+{
+    uint32_t i = 0;
+    int32_t error = E1000_SUCCESS;
+
+    error = e1000_get_software_flag(hw);
+    if (error != E1000_SUCCESS)
+        return error;
+
+    /* A driver can write to the NVM only if it has eeprom_shadow_ram
+     * allocated.  Subsequent reads to the modified words are read from
+     * this cached structure as well.  Writes will only go into this
+     * cached structure unless it's followed by a call to
+     * e1000_update_eeprom_checksum() where it will commit the changes
+     * and clear the "modified" field.
+     */
+    if (hw->eeprom_shadow_ram != NULL) {
+        for (i = 0; i < words; i++) {
+            if ((offset + i) < E1000_SHADOW_RAM_WORDS) {
+                hw->eeprom_shadow_ram[offset+i].modified = TRUE;
+                hw->eeprom_shadow_ram[offset+i].eeprom_word = data[i];
+            } else {
+                error = -E1000_ERR_EEPROM;
+                break;
+            }
+        }
+    } else {
+        /* Drivers have the option to not allocate eeprom_shadow_ram as long
+         * as they don't perform any NVM writes.  An attempt in doing so
+         * will result in this error.
+         */
+        error = -E1000_ERR_EEPROM;
+    }
+
+    e1000_release_software_flag(hw);
+
+    return error;
+}
+
+/******************************************************************************
+ * This function does initial flash setup so that a new read/write/erase cycle
+ * can be started.
+ *
+ * hw - The pointer to the hw structure
+ ****************************************************************************/
+int32_t
+e1000_ich8_cycle_init(struct e1000_hw *hw)
+{
+    union ich8_hws_flash_status hsfsts;
+    int32_t error = E1000_ERR_EEPROM;
+    int32_t i     = 0;
+
+    DEBUGFUNC("e1000_ich8_cycle_init");
+
+    hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+
+    /* May be check the Flash Des Valid bit in Hw status */
+    if (hsfsts.hsf_status.fldesvalid == 0) {
+        DEBUGOUT("Flash descriptor invalid.  SW Sequencing must be used.");
+        return error;
+    }
+
+    /* Clear FCERR in Hw status by writing 1 */
+    /* Clear DAEL in Hw status by writing a 1 */
+    hsfsts.hsf_status.flcerr = 1;
+    hsfsts.hsf_status.dael = 1;
+
+    E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval);
+
+    /* Either we should have a hardware SPI cycle in progress bit to check
+     * against, in order to start a new cycle or FDONE bit should be changed
+     * in the hardware so that it is 1 after harware reset, which can then be
+     * used as an indication whether a cycle is in progress or has been
+     * completed .. we should also have some software semaphore mechanism to
+     * guard FDONE or the cycle in progress bit so that two threads access to
+     * those bits can be sequentiallized or a way so that 2 threads dont
+     * start the cycle at the same time */
+
+    if (hsfsts.hsf_status.flcinprog == 0) {
+        /* There is no cycle running at present, so we can start a cycle */
+        /* Begin by setting Flash Cycle Done. */
+        hsfsts.hsf_status.flcdone = 1;
+        E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval);
+        error = E1000_SUCCESS;
+    } else {
+        /* otherwise poll for sometime so the current cycle has a chance
+         * to end before giving up. */
+        for (i = 0; i < ICH8_FLASH_COMMAND_TIMEOUT; i++) {
+            hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+            if (hsfsts.hsf_status.flcinprog == 0) {
+                error = E1000_SUCCESS;
+                break;
+            }
+            udelay(1);
+        }
+        if (error == E1000_SUCCESS) {
+            /* Successful in waiting for previous cycle to timeout,
+             * now set the Flash Cycle Done. */
+            hsfsts.hsf_status.flcdone = 1;
+            E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval);
+        } else {
+            DEBUGOUT("Flash controller busy, cannot get access");
+        }
+    }
+    return error;
+}
+
+/******************************************************************************
+ * This function starts a flash cycle and waits for its completion
+ *
+ * hw - The pointer to the hw structure
+ ****************************************************************************/
+int32_t
+e1000_ich8_flash_cycle(struct e1000_hw *hw, uint32_t timeout)
+{
+    union ich8_hws_flash_ctrl hsflctl;
+    union ich8_hws_flash_status hsfsts;
+    int32_t error = E1000_ERR_EEPROM;
+    uint32_t i = 0;
+
+    /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
+    hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+    hsflctl.hsf_ctrl.flcgo = 1;
+    E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+    /* wait till FDONE bit is set to 1 */
+    do {
+        hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+        if (hsfsts.hsf_status.flcdone == 1)
+            break;
+        udelay(1);
+        i++;
+    } while (i < timeout);
+    if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) {
+        error = E1000_SUCCESS;
+    }
+    return error;
+}
+
+/******************************************************************************
+ * Reads a byte or word from the NVM using the ICH8 flash access registers.
+ *
+ * hw - The pointer to the hw structure
+ * index - The index of the byte or word to read.
+ * size - Size of data to read, 1=byte 2=word
+ * data - Pointer to the word to store the value read.
+ *****************************************************************************/
+int32_t
+e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index,
+                     uint32_t size, uint16_t* data)
+{
+    union ich8_hws_flash_status hsfsts;
+    union ich8_hws_flash_ctrl hsflctl;
+    uint32_t flash_linear_address;
+    uint32_t flash_data = 0;
+    int32_t error = -E1000_ERR_EEPROM;
+    int32_t count = 0;
+
+    DEBUGFUNC("e1000_read_ich8_data");
+
+    if (size < 1  || size > 2 || data == 0x0 ||
+        index > ICH8_FLASH_LINEAR_ADDR_MASK)
+        return error;
+
+    flash_linear_address = (ICH8_FLASH_LINEAR_ADDR_MASK & index) +
+                           hw->flash_base_addr;
+
+    do {
+        udelay(1);
+        /* Steps */
+        error = e1000_ich8_cycle_init(hw);
+        if (error != E1000_SUCCESS)
+            break;
+
+        hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+        /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+        hsflctl.hsf_ctrl.fldbcount = size - 1;
+        hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_READ;
+        E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+        /* Write the last 24 bits of index into Flash Linear address field in
+         * Flash Address */
+        /* TODO: TBD maybe check the index against the size of flash */
+
+        E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address);
+
+        error = e1000_ich8_flash_cycle(hw, ICH8_FLASH_COMMAND_TIMEOUT);
+
+        /* Check if FCERR is set to 1, if set to 1, clear it and try the whole
+         * sequence a few more times, else read in (shift in) the Flash Data0,
+         * the order is least significant byte first msb to lsb */
+        if (error == E1000_SUCCESS) {
+            flash_data = E1000_READ_ICH8_REG(hw, ICH8_FLASH_FDATA0);
+            if (size == 1) {
+                *data = (uint8_t)(flash_data & 0x000000FF);
+            } else if (size == 2) {
+                *data = (uint16_t)(flash_data & 0x0000FFFF);
+            }
+            break;
+        } else {
+            /* If we've gotten here, then things are probably completely hosed,
+             * but if the error condition is detected, it won't hurt to give
+             * it another try...ICH8_FLASH_CYCLE_REPEAT_COUNT times.
+             */
+            hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+            if (hsfsts.hsf_status.flcerr == 1) {
+                /* Repeat for some time before giving up. */
+                continue;
+            } else if (hsfsts.hsf_status.flcdone == 0) {
+                DEBUGOUT("Timeout error - flash cycle did not complete.");
+                break;
+            }
+        }
+    } while (count++ < ICH8_FLASH_CYCLE_REPEAT_COUNT);
+
+    return error;
+}
+
+/******************************************************************************
+ * Writes One /two bytes to the NVM using the ICH8 flash access registers.
+ *
+ * hw - The pointer to the hw structure
+ * index - The index of the byte/word to read.
+ * size - Size of data to read, 1=byte 2=word
+ * data - The byte(s) to write to the NVM.
+ *****************************************************************************/
+int32_t
+e1000_write_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size,
+                      uint16_t data)
+{
+    union ich8_hws_flash_status hsfsts;
+    union ich8_hws_flash_ctrl hsflctl;
+    uint32_t flash_linear_address;
+    uint32_t flash_data = 0;
+    int32_t error = -E1000_ERR_EEPROM;
+    int32_t count = 0;
+
+    DEBUGFUNC("e1000_write_ich8_data");
+
+    if (size < 1  || size > 2 || data > size * 0xff ||
+        index > ICH8_FLASH_LINEAR_ADDR_MASK)
+        return error;
+
+    flash_linear_address = (ICH8_FLASH_LINEAR_ADDR_MASK & index) +
+                           hw->flash_base_addr;
+
+    do {
+        udelay(1);
+        /* Steps */
+        error = e1000_ich8_cycle_init(hw);
+        if (error != E1000_SUCCESS)
+            break;
+
+        hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+        /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+        hsflctl.hsf_ctrl.fldbcount = size -1;
+        hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_WRITE;
+        E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+        /* Write the last 24 bits of index into Flash Linear address field in
+         * Flash Address */
+        E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address);
+
+        if (size == 1)
+            flash_data = (uint32_t)data & 0x00FF;
+        else
+            flash_data = (uint32_t)data;
+
+        E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FDATA0, flash_data);
+
+        /* check if FCERR is set to 1 , if set to 1, clear it and try the whole
+         * sequence a few more times else done */
+        error = e1000_ich8_flash_cycle(hw, ICH8_FLASH_COMMAND_TIMEOUT);
+        if (error == E1000_SUCCESS) {
+            break;
+        } else {
+            /* If we're here, then things are most likely completely hosed,
+             * but if the error condition is detected, it won't hurt to give
+             * it another try...ICH8_FLASH_CYCLE_REPEAT_COUNT times.
+             */
+            hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+            if (hsfsts.hsf_status.flcerr == 1) {
+                /* Repeat for some time before giving up. */
+                continue;
+            } else if (hsfsts.hsf_status.flcdone == 0) {
+                DEBUGOUT("Timeout error - flash cycle did not complete.");
+                break;
+            }
+        }
+    } while (count++ < ICH8_FLASH_CYCLE_REPEAT_COUNT);
+
+    return error;
+}
+
+/******************************************************************************
+ * Reads a single byte from the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The index of the byte to read.
+ * data - Pointer to a byte to store the value read.
+ *****************************************************************************/
+int32_t
+e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t* data)
+{
+    int32_t status = E1000_SUCCESS;
+    uint16_t word = 0;
+
+    status = e1000_read_ich8_data(hw, index, 1, &word);
+    if (status == E1000_SUCCESS) {
+        *data = (uint8_t)word;
+    }
+
+    return status;
+}
+
+/******************************************************************************
+ * Writes a single byte to the NVM using the ICH8 flash access registers.
+ * Performs verification by reading back the value and then going through
+ * a retry algorithm before giving up.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The index of the byte to write.
+ * byte - The byte to write to the NVM.
+ *****************************************************************************/
+int32_t
+e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte)
+{
+    int32_t error = E1000_SUCCESS;
+    int32_t program_retries;
+    uint8_t temp_byte;
+
+    e1000_write_ich8_byte(hw, index, byte);
+    udelay(100);
+
+    for (program_retries = 0; program_retries < 100; program_retries++) {
+        e1000_read_ich8_byte(hw, index, &temp_byte);
+        if (temp_byte == byte)
+            break;
+        udelay(10);
+        e1000_write_ich8_byte(hw, index, byte);
+        udelay(100);
+    }
+    if (program_retries == 100)
+        error = E1000_ERR_EEPROM;
+
+    return error;
+}
+
+/******************************************************************************
+ * Writes a single byte to the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The index of the byte to read.
+ * data - The byte to write to the NVM.
+ *****************************************************************************/
+int32_t
+e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t data)
+{
+    int32_t status = E1000_SUCCESS;
+    uint16_t word = (uint16_t)data;
+
+    status = e1000_write_ich8_data(hw, index, 1, word);
+
+    return status;
+}
+
+/******************************************************************************
+ * Reads a word from the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The starting byte index of the word to read.
+ * data - Pointer to a word to store the value read.
+ *****************************************************************************/
+int32_t
+e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t *data)
+{
+    int32_t status = E1000_SUCCESS;
+    status = e1000_read_ich8_data(hw, index, 2, data);
+    return status;
+}
+
+/******************************************************************************
+ * Writes a word to the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The starting byte index of the word to read.
+ * data - The word to write to the NVM.
+ *****************************************************************************/
+int32_t
+e1000_write_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t data)
+{
+    int32_t status = E1000_SUCCESS;
+    status = e1000_write_ich8_data(hw, index, 2, data);
+    return status;
+}
+
+/******************************************************************************
+ * Erases the bank specified. Each bank is a 4k block. Segments are 0 based.
+ * segment N is 4096 * N + flash_reg_addr.
+ *
+ * hw - pointer to e1000_hw structure
+ * segment - 0 for first segment, 1 for second segment, etc.
+ *****************************************************************************/
+int32_t
+e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment)
+{
+    union ich8_hws_flash_status hsfsts;
+    union ich8_hws_flash_ctrl hsflctl;
+    uint32_t flash_linear_address;
+    int32_t  count = 0;
+    int32_t  error = E1000_ERR_EEPROM;
+    int32_t  iteration, seg_size;
+    int32_t  sector_size;
+    int32_t  j = 0;
+    int32_t  error_flag = 0;
+
+    hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+
+    /* Determine HW Sector size: Read BERASE bits of Hw flash Status register */
+    /* 00: The Hw sector is 256 bytes, hence we need to erase 16
+     *     consecutive sectors.  The start index for the nth Hw sector can be
+     *     calculated as = segment * 4096 + n * 256
+     * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
+     *     The start index for the nth Hw sector can be calculated
+     *     as = segment * 4096
+     * 10: Error condition
+     * 11: The Hw sector size is much bigger than the size asked to
+     *     erase...error condition */
+    if (hsfsts.hsf_status.berasesz == 0x0) {
+        /* Hw sector size 256 */
+        sector_size = seg_size = ICH8_FLASH_SEG_SIZE_256;
+        iteration = ICH8_FLASH_SECTOR_SIZE / ICH8_FLASH_SEG_SIZE_256;
+    } else if (hsfsts.hsf_status.berasesz == 0x1) {
+        sector_size = seg_size = ICH8_FLASH_SEG_SIZE_4K;
+        iteration = 1;
+    } else if (hsfsts.hsf_status.berasesz == 0x3) {
+        sector_size = seg_size = ICH8_FLASH_SEG_SIZE_64K;
+        iteration = 1;
+    } else {
+        return error;
+    }
+
+    for (j = 0; j < iteration ; j++) {
+        do {
+            count++;
+            /* Steps */
+            error = e1000_ich8_cycle_init(hw);
+            if (error != E1000_SUCCESS) {
+                error_flag = 1;
+                break;
+            }
+
+            /* Write a value 11 (block Erase) in Flash Cycle field in Hw flash
+             * Control */
+            hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+            hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_ERASE;
+            E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+            /* Write the last 24 bits of an index within the block into Flash
+             * Linear address field in Flash Address.  This probably needs to
+             * be calculated here based off the on-chip segment size and the
+             * software segment size assumed (4K) */
+            /* TBD */
+            flash_linear_address = segment * sector_size + j * seg_size;
+            flash_linear_address &= ICH8_FLASH_LINEAR_ADDR_MASK;
+            flash_linear_address += hw->flash_base_addr;
+
+            E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address);
+
+            error = e1000_ich8_flash_cycle(hw, 1000000);
+            /* Check if FCERR is set to 1.  If 1, clear it and try the whole
+             * sequence a few more times else Done */
+            if (error == E1000_SUCCESS) {
+                break;
+            } else {
+                hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+                if (hsfsts.hsf_status.flcerr == 1) {
+                    /* repeat for some time before giving up */
+                    continue;
+                } else if (hsfsts.hsf_status.flcdone == 0) {
+                    error_flag = 1;
+                    break;
+                }
+            }
+        } while ((count < ICH8_FLASH_CYCLE_REPEAT_COUNT) && !error_flag);
+        if (error_flag == 1)
+            break;
+    }
+    if (error_flag != 1)
+        error = E1000_SUCCESS;
+    return error;
+}
+
+/******************************************************************************
+ *
+ * Reverse duplex setting without breaking the link.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ *****************************************************************************/
+int32_t
+e1000_duplex_reversal(struct e1000_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t phy_data;
+
+    if (hw->phy_type != e1000_phy_igp_3)
+        return E1000_SUCCESS;
+
+    ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+    if (ret_val)
+        return ret_val;
+
+    phy_data ^= MII_CR_FULL_DUPLEX;
+
+    ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+    if (ret_val)
+        return ret_val;
+
+    ret_val = e1000_read_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, &phy_data);
+    if (ret_val)
+        return ret_val;
+
+    phy_data |= IGP3_PHY_MISC_DUPLEX_MANUAL_SET;
+    ret_val = e1000_write_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, phy_data);
+
+    return ret_val;
+}
+
+int32_t
+e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw,
+                                      uint32_t cnf_base_addr, uint32_t cnf_size)
+{
+    uint32_t ret_val = E1000_SUCCESS;
+    uint16_t word_addr, reg_data, reg_addr;
+    uint16_t i;
+
+    /* cnf_base_addr is in DWORD */
+    word_addr = (uint16_t)(cnf_base_addr << 1);
+
+    /* cnf_size is returned in size of dwords */
+    for (i = 0; i < cnf_size; i++) {
+        ret_val = e1000_read_eeprom(hw, (word_addr + i*2), 1, &reg_data);
+        if (ret_val)
+            return ret_val;
+
+        ret_val = e1000_read_eeprom(hw, (word_addr + i*2 + 1), 1, &reg_addr);
+        if (ret_val)
+            return ret_val;
+
+        ret_val = e1000_get_software_flag(hw);
+        if (ret_val != E1000_SUCCESS)
+            return ret_val;
+
+        ret_val = e1000_write_phy_reg_ex(hw, (uint32_t)reg_addr, reg_data);
+
+        e1000_release_software_flag(hw);
+    }
+
+    return ret_val;
+}
+
+
+int32_t
+e1000_init_lcd_from_nvm(struct e1000_hw *hw)
+{
+    uint32_t reg_data, cnf_base_addr, cnf_size, ret_val, loop;
+
+    if (hw->phy_type != e1000_phy_igp_3)
+          return E1000_SUCCESS;
+
+    /* Check if SW needs configure the PHY */
+    reg_data = E1000_READ_REG(hw, FEXTNVM);
+    if (!(reg_data & FEXTNVM_SW_CONFIG))
+        return E1000_SUCCESS;
+
+    /* Wait for basic configuration completes before proceeding*/
+    loop = 0;
+    do {
+        reg_data = E1000_READ_REG(hw, STATUS) & E1000_STATUS_LAN_INIT_DONE;
+        udelay(100);
+        loop++;
+    } while ((!reg_data) && (loop < 50));
+
+    /* Clear the Init Done bit for the next init event */
+    reg_data = E1000_READ_REG(hw, STATUS);
+    reg_data &= ~E1000_STATUS_LAN_INIT_DONE;
+    E1000_WRITE_REG(hw, STATUS, reg_data);
+
+    /* Make sure HW does not configure LCD from PHY extended configuration
+       before SW configuration */
+    reg_data = E1000_READ_REG(hw, EXTCNF_CTRL);
+    if ((reg_data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) == 0x0000) {
+        reg_data = E1000_READ_REG(hw, EXTCNF_SIZE);
+        cnf_size = reg_data & E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH;
+        cnf_size >>= 16;
+        if (cnf_size) {
+            reg_data = E1000_READ_REG(hw, EXTCNF_CTRL);
+            cnf_base_addr = reg_data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER;
+            /* cnf_base_addr is in DWORD */
+            cnf_base_addr >>= 16;
+
+            /* Configure LCD from extended configuration region. */
+            ret_val = e1000_init_lcd_from_nvm_config_region(hw, cnf_base_addr,
+                                                            cnf_size);
+            if (ret_val)
+                return ret_val;
+        }
+    }
+
+    return E1000_SUCCESS;
+}
+
+
 
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index bfbc7d8..8961e07 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -62,6 +62,7 @@ typedef enum {
     e1000_82572,
     e1000_82573,
     e1000_80003es2lan,
+    e1000_ich8lan,
     e1000_num_macs
 } e1000_mac_type;
 
@@ -70,6 +71,7 @@ typedef enum {
     e1000_eeprom_spi,
     e1000_eeprom_microwire,
     e1000_eeprom_flash,
+    e1000_eeprom_ich8,
     e1000_eeprom_none, /* No NVM support */
     e1000_num_eeprom_types
 } e1000_eeprom_type;
@@ -98,6 +100,11 @@ typedef enum {
     e1000_fc_default = 0xFF
 } e1000_fc_type;
 
+struct e1000_shadow_ram {
+    uint16_t    eeprom_word;
+    boolean_t   modified;
+};
+
 /* PCI bus types */
 typedef enum {
     e1000_bus_type_unknown = 0,
@@ -218,6 +225,8 @@ typedef enum {
     e1000_phy_igp,
     e1000_phy_igp_2,
     e1000_phy_gg82563,
+    e1000_phy_igp_3,
+    e1000_phy_ife,
     e1000_phy_undefined = 0xFF
 } e1000_phy_type;
 
@@ -313,6 +322,10 @@ int32_t e1000_read_phy_reg(struct e1000_
 int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
 int32_t e1000_phy_hw_reset(struct e1000_hw *hw);
 int32_t e1000_phy_reset(struct e1000_hw *hw);
+void e1000_phy_powerdown_workaround(struct e1000_hw *hw);
+int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw);
+int32_t e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw, uint32_t cnf_base_addr, uint32_t cnf_size);
+int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw);
 int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
 int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
 int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data);
@@ -331,6 +344,7 @@ uint32_t e1000_enable_mng_pass_thru(stru
 #define E1000_MNG_DHCP_COOKIE_OFFSET	0x6F0   /* Cookie offset */
 #define E1000_MNG_DHCP_COOKIE_LENGTH	0x10    /* Cookie length */
 #define E1000_MNG_IAMT_MODE		0x3
+#define E1000_MNG_ICH_IAMT_MODE         0x2
 #define E1000_IAMT_SIGNATURE            0x544D4149 /* Intel(R) Active Management Technology signature */
 
 #define E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT 0x1 /* DHCP parsing enabled */
@@ -388,6 +402,8 @@ int32_t e1000_read_part_num(struct e1000
 int32_t e1000_read_mac_addr(struct e1000_hw * hw);
 int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask);
 void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask);
+void e1000_release_software_flag(struct e1000_hw *hw);
+int32_t e1000_get_software_flag(struct e1000_hw *hw);
 
 /* Filters (multicast, vlan, receive) */
 void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count);
@@ -423,6 +439,29 @@ int32_t e1000_disable_pciex_master(struc
 int32_t e1000_get_software_semaphore(struct e1000_hw *hw);
 void e1000_release_software_semaphore(struct e1000_hw *hw);
 int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
+int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop);
+
+int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index,
+                             uint8_t *data);
+int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index,
+                                     uint8_t byte);
+int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index,
+                              uint8_t byte);
+int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index,
+                             uint16_t *data);
+int32_t e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index,
+                             uint32_t size, uint16_t *data);
+int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset,
+                               uint16_t words, uint16_t *data);
+int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset,
+                                uint16_t words, uint16_t *data);
+int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment);
+
+
+#define E1000_READ_REG_IO(a, reg) \
+    e1000_read_reg_io((a), E1000_##reg)
+#define E1000_WRITE_REG_IO(a, reg, val) \
+    e1000_write_reg_io((a), E1000_##reg, val)
 
 /* PCI Device IDs */
 #define E1000_DEV_ID_82542               0x1000
@@ -447,6 +486,7 @@ int32_t e1000_check_phy_reset_block(stru
 #define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
 #define E1000_DEV_ID_82541EI             0x1013
 #define E1000_DEV_ID_82541EI_MOBILE      0x1018
+#define E1000_DEV_ID_82541ER_LOM         0x1014
 #define E1000_DEV_ID_82541ER             0x1078
 #define E1000_DEV_ID_82547GI             0x1075
 #define E1000_DEV_ID_82541GI             0x1076
@@ -458,18 +498,28 @@ int32_t e1000_check_phy_reset_block(stru
 #define E1000_DEV_ID_82546GB_PCIE        0x108A
 #define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
 #define E1000_DEV_ID_82547EI             0x1019
+#define E1000_DEV_ID_82547EI_MOBILE      0x101A
 #define E1000_DEV_ID_82571EB_COPPER      0x105E
 #define E1000_DEV_ID_82571EB_FIBER       0x105F
 #define E1000_DEV_ID_82571EB_SERDES      0x1060
 #define E1000_DEV_ID_82572EI_COPPER      0x107D
 #define E1000_DEV_ID_82572EI_FIBER       0x107E
 #define E1000_DEV_ID_82572EI_SERDES      0x107F
+#define E1000_DEV_ID_82572EI             0x10B9
 #define E1000_DEV_ID_82573E              0x108B
 #define E1000_DEV_ID_82573E_IAMT         0x108C
 #define E1000_DEV_ID_82573L              0x109A
 #define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
 #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT     0x1096
 #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT     0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT     0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT     0x10BB
+
+#define E1000_DEV_ID_ICH8_IGP_M_AMT      0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT        0x104A
+#define E1000_DEV_ID_ICH8_IGP_C          0x104B
+#define E1000_DEV_ID_ICH8_IFE            0x104C
+#define E1000_DEV_ID_ICH8_IGP_M          0x104D
 
 
 #define NODE_ADDRESS_SIZE 6
@@ -540,6 +590,14 @@ int32_t e1000_check_phy_reset_block(stru
     E1000_IMS_RXSEQ  |    \
     E1000_IMS_LSC)
 
+/* Additional interrupts need to be handled for e1000_ich8lan:
+    DSW = The FW changed the status of the DISSW bit in FWSM
+    PHYINT = The LAN connected device generates an interrupt
+    EPRST = Manageability reset event */
+#define IMS_ICH8LAN_ENABLE_MASK (\
+    E1000_IMS_DSW   | \
+    E1000_IMS_PHYINT | \
+    E1000_IMS_EPRST)
 
 /* Number of high/low register pairs in the RAR. The RAR (Receive Address
  * Registers) holds the directed and multicast addresses that we monitor. We
@@ -547,6 +605,7 @@ int32_t e1000_check_phy_reset_block(stru
  * E1000_RAR_ENTRIES - 1 multicast addresses.
  */
 #define E1000_RAR_ENTRIES 15
+#define E1000_RAR_ENTRIES_ICH8LAN  7
 
 #define MIN_NUMBER_OF_DESCRIPTORS 8
 #define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
@@ -768,6 +827,9 @@ struct e1000_data_desc {
 #define E1000_MC_TBL_SIZE          128  /* Multicast Filter Table (4096 bits) */
 #define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
 
+#define E1000_NUM_UNICAST_ICH8LAN  7
+#define E1000_MC_TBL_SIZE_ICH8LAN  32
+
 
 /* Receive Address Register */
 struct e1000_rar {
@@ -777,6 +839,7 @@ struct e1000_rar {
 
 /* Number of entries in the Multicast Table Array (MTA). */
 #define E1000_NUM_MTA_REGISTERS 128
+#define E1000_NUM_MTA_REGISTERS_ICH8LAN 32
 
 /* IPv4 Address Table Entry */
 struct e1000_ipv4_at_entry {
@@ -787,6 +850,7 @@ struct e1000_ipv4_at_entry {
 /* Four wakeup IP addresses are supported */
 #define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4
 #define E1000_IP4AT_SIZE                  E1000_WAKEUP_IP_ADDRESS_COUNT_MAX
+#define E1000_IP4AT_SIZE_ICH8LAN          3
 #define E1000_IP6AT_SIZE                  1
 
 /* IPv6 Address Table Entry */
@@ -845,6 +909,7 @@ struct e1000_ffvt_entry {
 #define E1000_FLA      0x0001C  /* Flash Access - RW */
 #define E1000_MDIC     0x00020  /* MDI Control - RW */
 #define E1000_SCTL     0x00024  /* SerDes Control - RW */
+#define E1000_FEXTNVM  0x00028  /* Future Extended NVM register */
 #define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
 #define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
 #define E1000_FCT      0x00030  /* Flow Control Type - RW */
@@ -873,6 +938,8 @@ struct e1000_ffvt_entry {
 #define E1000_LEDCTL   0x00E00  /* LED Control - RW */
 #define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
 #define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
+#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
+#define FEXTNVM_SW_CONFIG  0x0001
 #define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
 #define E1000_PBS      0x01008  /* Packet Buffer Size */
 #define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
@@ -900,11 +967,13 @@ struct e1000_ffvt_entry {
 #define E1000_RDH0     E1000_RDH   /* RX Desc Head (0) - RW */
 #define E1000_RDT0     E1000_RDT   /* RX Desc Tail (0) - RW */
 #define E1000_RDTR0    E1000_RDTR  /* RX Delay Timer (0) - RW */
-#define E1000_RXDCTL   0x02828  /* RX Descriptor Control - RW */
+#define E1000_RXDCTL   0x02828  /* RX Descriptor Control queue 0 - RW */
+#define E1000_RXDCTL1  0x02928  /* RX Descriptor Control queue 1 - RW */
 #define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
 #define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
 #define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
 #define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
+#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
 #define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
 #define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
 #define E1000_TDFHS    0x03420  /* TX Data FIFO Head Saved - RW */
@@ -1051,6 +1120,7 @@ struct e1000_ffvt_entry {
 #define E1000_82542_FLA      E1000_FLA
 #define E1000_82542_MDIC     E1000_MDIC
 #define E1000_82542_SCTL     E1000_SCTL
+#define E1000_82542_FEXTNVM  E1000_FEXTNVM
 #define E1000_82542_FCAL     E1000_FCAL
 #define E1000_82542_FCAH     E1000_FCAH
 #define E1000_82542_FCT      E1000_FCT
@@ -1074,6 +1144,19 @@ struct e1000_ffvt_entry {
 #define E1000_82542_RDLEN0   E1000_82542_RDLEN
 #define E1000_82542_RDH0     E1000_82542_RDH
 #define E1000_82542_RDT0     E1000_82542_RDT
+#define E1000_82542_SRRCTL(_n) (0x280C + ((_n) << 8)) /* Split and Replication
+                                                       * RX Control - RW */
+#define E1000_82542_DCA_RXCTRL(_n) (0x02814 + ((_n) << 8))
+#define E1000_82542_RDBAH3   0x02B04 /* RX Desc Base High Queue 3 - RW */
+#define E1000_82542_RDBAL3   0x02B00 /* RX Desc Low Queue 3 - RW */
+#define E1000_82542_RDLEN3   0x02B08 /* RX Desc Length Queue 3 - RW */
+#define E1000_82542_RDH3     0x02B10 /* RX Desc Head Queue 3 - RW */
+#define E1000_82542_RDT3     0x02B18 /* RX Desc Tail Queue 3 - RW */
+#define E1000_82542_RDBAL2   0x02A00 /* RX Desc Base Low Queue 2 - RW */
+#define E1000_82542_RDBAH2   0x02A04 /* RX Desc Base High Queue 2 - RW */
+#define E1000_82542_RDLEN2   0x02A08 /* RX Desc Length Queue 2 - RW */
+#define E1000_82542_RDH2     0x02A10 /* RX Desc Head Queue 2 - RW */
+#define E1000_82542_RDT2     0x02A18 /* RX Desc Tail Queue 2 - RW */
 #define E1000_82542_RDTR1    0x00130
 #define E1000_82542_RDBAL1   0x00138
 #define E1000_82542_RDBAH1   0x0013C
@@ -1111,11 +1194,14 @@ struct e1000_ffvt_entry {
 #define E1000_82542_FLOP     E1000_FLOP
 #define E1000_82542_EXTCNF_CTRL  E1000_EXTCNF_CTRL
 #define E1000_82542_EXTCNF_SIZE  E1000_EXTCNF_SIZE
+#define E1000_82542_PHY_CTRL E1000_PHY_CTRL
 #define E1000_82542_ERT      E1000_ERT
 #define E1000_82542_RXDCTL   E1000_RXDCTL
+#define E1000_82542_RXDCTL1  E1000_RXDCTL1
 #define E1000_82542_RADV     E1000_RADV
 #define E1000_82542_RSRPD    E1000_RSRPD
 #define E1000_82542_TXDMAC   E1000_TXDMAC
+#define E1000_82542_KABGTXD  E1000_KABGTXD
 #define E1000_82542_TDFHS    E1000_TDFHS
 #define E1000_82542_TDFTS    E1000_TDFTS
 #define E1000_82542_TDFPC    E1000_TDFPC
@@ -1311,13 +1397,16 @@ struct e1000_hw_stats {
 
 /* Structure containing variables used by the shared code (e1000_hw.c) */
 struct e1000_hw {
-    uint8_t __iomem *hw_addr;
+    uint8_t *hw_addr;
     uint8_t *flash_address;
     e1000_mac_type mac_type;
     e1000_phy_type phy_type;
     uint32_t phy_init_script;
     e1000_media_type media_type;
     void *back;
+    struct e1000_shadow_ram *eeprom_shadow_ram;
+    uint32_t flash_bank_size;
+    uint32_t flash_base_addr;
     e1000_fc_type fc;
     e1000_bus_speed bus_speed;
     e1000_bus_width bus_width;
@@ -1329,6 +1418,7 @@ struct e1000_hw {
     uint32_t asf_firmware_present;
     uint32_t eeprom_semaphore_present;
     uint32_t swfw_sync_present;
+    uint32_t swfwhw_semaphore_present;
     unsigned long io_base;
     uint32_t phy_id;
     uint32_t phy_revision;
@@ -1388,6 +1478,7 @@ struct e1000_hw {
     boolean_t in_ifs_mode;
     boolean_t mng_reg_access_disabled;
     boolean_t leave_av_bit_off;
+    boolean_t kmrn_lock_loss_workaround_disabled;
 };
 
 
@@ -1436,6 +1527,7 @@ struct e1000_hw {
 #define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
 #define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
 #define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000  /* Initiate an interrupt to manageability engine */
 
 /* Device Status */
 #define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
@@ -1450,6 +1542,8 @@ struct e1000_hw {
 #define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
 #define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
 #define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200   /* Lan Init Completion
+                                                   by EEPROM/Flash */
 #define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
 #define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state. Clear on write '0'. */
 #define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
@@ -1507,6 +1601,10 @@ struct e1000_hw {
 #define E1000_STM_OPCODE     0xDB00
 #define E1000_HICR_FW_RESET  0xC0
 
+#define E1000_SHADOW_RAM_WORDS     2048
+#define E1000_ICH8_NVM_SIG_WORD    0x13
+#define E1000_ICH8_NVM_SIG_MASK    0xC0
+
 /* EEPROM Read */
 #define E1000_EERD_START      0x00000001 /* Start Read */
 #define E1000_EERD_DONE       0x00000010 /* Read Done */
@@ -1552,7 +1650,6 @@ struct e1000_hw {
 #define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
 #define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
 #define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
-#define E1000_CTRL_EXT_CANC           0x04000000  /* Interrupt delay cancellation */
 #define E1000_CTRL_EXT_DRV_LOAD       0x10000000  /* Driver loaded bit for FW */
 #define E1000_CTRL_EXT_IAME           0x08000000  /* Interrupt acknowledge Auto-mask */
 #define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000  /* Clear Interrupt timers after IMS clear */
@@ -1592,12 +1689,31 @@ struct e1000_hw {
 #define E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS   0x00000800
 
 /* In-Band Control */
+#define E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT    0x00000500
 #define E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING  0x00000010
 
 /* Half-Duplex Control */
 #define E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT 0x00000004
 #define E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT  0x00000000
 
+#define E1000_KUMCTRLSTA_OFFSET_K0S_CTRL       0x0000001E
+
+#define E1000_KUMCTRLSTA_DIAG_FELPBK           0x2000
+#define E1000_KUMCTRLSTA_DIAG_NELPBK           0x1000
+
+#define E1000_KUMCTRLSTA_K0S_100_EN            0x2000
+#define E1000_KUMCTRLSTA_K0S_GBE_EN            0x1000
+#define E1000_KUMCTRLSTA_K0S_ENTRY_LATENCY_MASK   0x0003
+
+#define E1000_KABGTXD_BGSQLBIAS                0x00050000
+
+#define E1000_PHY_CTRL_SPD_EN                  0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU                0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU             0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE      0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE             0x00000040
+#define E1000_PHY_CTRL_B2B_EN                  0x00000080
+
 /* LED Control */
 #define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
 #define E1000_LEDCTL_LED0_MODE_SHIFT      0
@@ -1667,6 +1783,9 @@ struct e1000_hw {
 #define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */
 #define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */
 #define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW bit in the FWSM */
+#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates an interrupt */
+#define E1000_ICR_EPRST         0x00100000 /* ME handware reset occurs */
 
 /* Interrupt Cause Set */
 #define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
@@ -1693,6 +1812,9 @@ struct e1000_hw {
 #define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
 #define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
 #define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICS_DSW       E1000_ICR_DSW
+#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
+#define E1000_ICS_EPRST     E1000_ICR_EPRST
 
 /* Interrupt Mask Set */
 #define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
@@ -1719,6 +1841,9 @@ struct e1000_hw {
 #define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
 #define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
 #define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMS_DSW       E1000_ICR_DSW
+#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMS_EPRST     E1000_ICR_EPRST
 
 /* Interrupt Mask Clear */
 #define E1000_IMC_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
@@ -1745,6 +1870,9 @@ struct e1000_hw {
 #define E1000_IMC_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
 #define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
 #define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMC_DSW       E1000_ICR_DSW
+#define E1000_IMC_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMC_EPRST     E1000_ICR_EPRST
 
 /* Receive Control */
 #define E1000_RCTL_RST            0x00000001    /* Software reset */
@@ -1919,9 +2047,10 @@ struct e1000_hw {
 #define E1000_MRQC_RSS_FIELD_MASK           0xFFFF0000
 #define E1000_MRQC_RSS_FIELD_IPV4_TCP       0x00010000
 #define E1000_MRQC_RSS_FIELD_IPV4           0x00020000
-#define E1000_MRQC_RSS_FIELD_IPV6_TCP       0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX    0x00040000
 #define E1000_MRQC_RSS_FIELD_IPV6_EX        0x00080000
 #define E1000_MRQC_RSS_FIELD_IPV6           0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP       0x00200000
 
 /* Definitions for power management and wakeup registers */
 /* Wake Up Control */
@@ -2011,6 +2140,15 @@ struct e1000_hw {
 #define E1000_FWSM_MODE_SHIFT            1
 #define E1000_FWSM_FW_VALID     0x00008000 /* FW established a valid mode */
 
+#define E1000_FWSM_RSPCIPHY        0x00000040 /* Reset PHY on PCI reset */
+#define E1000_FWSM_DISSW           0x10000000 /* FW disable SW Write Access */
+#define E1000_FWSM_SKUSEL_MASK     0x60000000 /* LAN SKU select */
+#define E1000_FWSM_SKUEL_SHIFT     29
+#define E1000_FWSM_SKUSEL_EMB      0x0 /* Embedded SKU */
+#define E1000_FWSM_SKUSEL_CONS     0x1 /* Consumer SKU */
+#define E1000_FWSM_SKUSEL_PERF_100 0x2 /* Perf & Corp 10/100 SKU */
+#define E1000_FWSM_SKUSEL_PERF_GBE 0x3 /* Perf & Copr GbE SKU */
+
 /* FFLT Debug Register */
 #define E1000_FFLT_DBG_INVC     0x00100000 /* Invalid /C/ code handling */
 
@@ -2083,6 +2221,8 @@ struct e1000_host_command_info {
                              E1000_GCR_TXDSCW_NO_SNOOP      | \
                              E1000_GCR_TXDSCR_NO_SNOOP)
 
+#define PCI_EX_82566_SNOOP_ALL PCI_EX_NO_SNOOP_ALL
+
 #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
 /* Function Active and Power State to MNG */
 #define E1000_FACTPS_FUNC0_POWER_STATE_MASK         0x00000003
@@ -2141,8 +2281,10 @@ struct e1000_host_command_info {
 #define EEPROM_PHY_CLASS_WORD         0x0007
 #define EEPROM_INIT_CONTROL1_REG      0x000A
 #define EEPROM_INIT_CONTROL2_REG      0x000F
+#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
 #define EEPROM_INIT_CONTROL3_PORT_B   0x0014
 #define EEPROM_INIT_3GIO_3            0x001A
+#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
 #define EEPROM_INIT_CONTROL3_PORT_A   0x0024
 #define EEPROM_CFG                    0x0012
 #define EEPROM_FLASH_VERSION          0x0032
@@ -2154,10 +2296,16 @@ struct e1000_host_command_info {
 /* Word definitions for ID LED Settings */
 #define ID_LED_RESERVED_0000 0x0000
 #define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_RESERVED_82573  0xF746
+#define ID_LED_DEFAULT_82573   0x1811
 #define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2 << 12) | \
                               (ID_LED_OFF1_OFF2 << 8) | \
                               (ID_LED_DEF1_DEF2 << 4) | \
                               (ID_LED_DEF1_DEF2))
+#define ID_LED_DEFAULT_ICH8LAN  ((ID_LED_DEF1_DEF2 << 12) | \
+                                 (ID_LED_DEF1_OFF2 <<  8) | \
+                                 (ID_LED_DEF1_ON2  <<  4) | \
+                                 (ID_LED_DEF1_DEF2))
 #define ID_LED_DEF1_DEF2     0x1
 #define ID_LED_DEF1_ON2      0x2
 #define ID_LED_DEF1_OFF2     0x3
@@ -2192,6 +2340,11 @@ struct e1000_host_command_info {
 #define EEPROM_WORD0F_ASM_DIR    0x2000
 #define EEPROM_WORD0F_ANE        0x0800
 #define EEPROM_WORD0F_SWPDIO_EXT 0x00F0
+#define EEPROM_WORD0F_LPLU       0x0001
+
+/* Mask bits for fields in Word 0x10/0x20 of the EEPROM */
+#define EEPROM_WORD1020_GIGA_DISABLE         0x0010
+#define EEPROM_WORD1020_GIGA_DISABLE_NON_D0A 0x0008
 
 /* Mask bits for fields in Word 0x1a of the EEPROM */
 #define EEPROM_WORD1A_ASPM_MASK  0x000C
@@ -2266,23 +2419,29 @@ struct e1000_host_command_info {
 #define E1000_EXTCNF_CTRL_D_UD_OWNER        0x00000010
 #define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
 #define E1000_EXTCNF_CTRL_MDIO_HW_OWNERSHIP 0x00000040
-#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER   0x1FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER   0x0FFF0000
 
 #define E1000_EXTCNF_SIZE_EXT_PHY_LENGTH    0x000000FF
 #define E1000_EXTCNF_SIZE_EXT_DOCK_LENGTH   0x0000FF00
 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH   0x00FF0000
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE  0x00000001
+#define E1000_EXTCNF_CTRL_SWFLAG            0x00000020
 
 /* PBA constants */
+#define E1000_PBA_8K 0x0008    /* 8KB, default Rx allocation */
 #define E1000_PBA_12K 0x000C    /* 12KB, default Rx allocation */
 #define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
 #define E1000_PBA_22K 0x0016
 #define E1000_PBA_24K 0x0018
 #define E1000_PBA_30K 0x001E
 #define E1000_PBA_32K 0x0020
+#define E1000_PBA_34K 0x0022
 #define E1000_PBA_38K 0x0026
 #define E1000_PBA_40K 0x0028
 #define E1000_PBA_48K 0x0030    /* 48KB, default RX allocation */
 
+#define E1000_PBS_16K E1000_PBA_16K
+
 /* Flow Control Constants */
 #define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
 #define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
@@ -2337,7 +2496,7 @@ struct e1000_host_command_info {
 /* Number of milliseconds we wait for Eeprom auto read bit done after MAC reset */
 #define AUTO_READ_DONE_TIMEOUT      10
 /* Number of milliseconds we wait for PHY configuration done after MAC reset */
-#define PHY_CFG_TIMEOUT             40
+#define PHY_CFG_TIMEOUT             100
 
 #define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
 
@@ -3002,6 +3161,221 @@ struct e1000_host_command_info {
 #define L1LXT971A_PHY_ID   0x001378E0
 #define GG82563_E_PHY_ID   0x01410CA0
 
+
+/* Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define PHY_PAGE_SHIFT        5
+#define PHY_REG(page, reg)    \
+        (((page) << PHY_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+
+#define IGP3_PHY_PORT_CTRL           \
+        PHY_REG(769, 17) /* Port General Configuration */
+#define IGP3_PHY_RATE_ADAPT_CTRL \
+        PHY_REG(769, 25) /* Rate Adapter Control Register */
+
+#define IGP3_KMRN_FIFO_CTRL_STATS \
+        PHY_REG(770, 16) /* KMRN FIFO's control/status register */
+#define IGP3_KMRN_POWER_MNG_CTRL \
+        PHY_REG(770, 17) /* KMRN Power Management Control Register */
+#define IGP3_KMRN_INBAND_CTRL \
+        PHY_REG(770, 18) /* KMRN Inband Control Register */
+#define IGP3_KMRN_DIAG \
+        PHY_REG(770, 19) /* KMRN Diagnostic register */
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002 /* RX PCS is not synced */
+#define IGP3_KMRN_ACK_TIMEOUT \
+        PHY_REG(770, 20) /* KMRN Acknowledge Timeouts register */
+
+#define IGP3_VR_CTRL \
+        PHY_REG(776, 18) /* Voltage regulator control register */
+#define IGP3_VR_CTRL_MODE_SHUT       0x0200 /* Enter powerdown, shutdown VRs */
+
+#define IGP3_CAPABILITY \
+        PHY_REG(776, 19) /* IGP3 Capability Register */
+
+/* Capabilities for SKU Control  */
+#define IGP3_CAP_INITIATE_TEAM       0x0001 /* Able to initiate a team */
+#define IGP3_CAP_WFM                 0x0002 /* Support WoL and PXE */
+#define IGP3_CAP_ASF                 0x0004 /* Support ASF */
+#define IGP3_CAP_LPLU                0x0008 /* Support Low Power Link Up */
+#define IGP3_CAP_DC_AUTO_SPEED       0x0010 /* Support AC/DC Auto Link Speed */
+#define IGP3_CAP_SPD                 0x0020 /* Support Smart Power Down */
+#define IGP3_CAP_MULT_QUEUE          0x0040 /* Support 2 tx & 2 rx queues */
+#define IGP3_CAP_RSS                 0x0080 /* Support RSS */
+#define IGP3_CAP_8021PQ              0x0100 /* Support 802.1Q & 802.1p */
+#define IGP3_CAP_AMT_CB              0x0200 /* Support active manageability and circuit breaker */
+
+#define IGP3_PPC_JORDAN_EN           0x0001
+#define IGP3_PPC_JORDAN_GIGA_SPEED   0x0002
+
+#define IGP3_KMRN_PMC_EE_IDLE_LINK_DIS         0x0001
+#define IGP3_KMRN_PMC_K0S_ENTRY_LATENCY_MASK   0x001E
+#define IGP3_KMRN_PMC_K0S_MODE1_EN_GIGA        0x0020
+#define IGP3_KMRN_PMC_K0S_MODE1_EN_100         0x0040
+
+#define IGP3E1000_PHY_MISC_CTRL                0x1B   /* Misc. Ctrl register */
+#define IGP3_PHY_MISC_DUPLEX_MANUAL_SET        0x1000 /* Duplex Manual Set */
+
+#define IGP3_KMRN_EXT_CTRL  PHY_REG(770, 18)
+#define IGP3_KMRN_EC_DIS_INBAND    0x0080
+
+#define IGP03E1000_E_PHY_ID  0x02A80390
+#define IFE_E_PHY_ID         0x02A80330 /* 10/100 PHY */
+#define IFE_PLUS_E_PHY_ID    0x02A80320
+#define IFE_C_E_PHY_ID       0x02A80310
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL   0x10  /* 100BaseTx Extended Status, Control and Address */
+#define IFE_PHY_SPECIAL_CONTROL           0x11  /* 100BaseTx PHY special control register */
+#define IFE_PHY_RCV_FALSE_CARRIER         0x13  /* 100BaseTx Receive False Carrier Counter */
+#define IFE_PHY_RCV_DISCONNECT            0x14  /* 100BaseTx Receive Disconnet Counter */
+#define IFE_PHY_RCV_ERROT_FRAME           0x15  /* 100BaseTx Receive Error Frame Counter */
+#define IFE_PHY_RCV_SYMBOL_ERR            0x16  /* Receive Symbol Error Counter */
+#define IFE_PHY_PREM_EOF_ERR              0x17  /* 100BaseTx Receive Premature End Of Frame Error Counter */
+#define IFE_PHY_RCV_EOF_ERR               0x18  /* 10BaseT Receive End Of Frame Error Counter */
+#define IFE_PHY_TX_JABBER_DETECT          0x19  /* 10BaseT Transmit Jabber Detect Counter */
+#define IFE_PHY_EQUALIZER                 0x1A  /* PHY Equalizer Control and Status */
+#define IFE_PHY_SPECIAL_CONTROL_LED       0x1B  /* PHY special control and LED configuration */
+#define IFE_PHY_MDIX_CONTROL              0x1C  /* MDI/MDI-X Control register */
+#define IFE_PHY_HWI_CONTROL               0x1D  /* Hardware Integrity Control (HWI) */
+
+#define IFE_PESC_REDUCED_POWER_DOWN_DISABLE  0x2000  /* Defaut 1 = Disable auto reduced power down */
+#define IFE_PESC_100BTX_POWER_DOWN           0x0400  /* Indicates the power state of 100BASE-TX */
+#define IFE_PESC_10BTX_POWER_DOWN            0x0200  /* Indicates the power state of 10BASE-T */
+#define IFE_PESC_POLARITY_REVERSED           0x0100  /* Indicates 10BASE-T polarity */
+#define IFE_PESC_PHY_ADDR_MASK               0x007C  /* Bit 6:2 for sampled PHY address */
+#define IFE_PESC_SPEED                       0x0002  /* Auto-negotiation speed result 1=100Mbs, 0=10Mbs */
+#define IFE_PESC_DUPLEX                      0x0001  /* Auto-negotiation duplex result 1=Full, 0=Half */
+#define IFE_PESC_POLARITY_REVERSED_SHIFT     8
+
+#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN   0x0100  /* 1 = Dyanmic Power Down disabled */
+#define IFE_PSC_FORCE_POLARITY               0x0020  /* 1=Reversed Polarity, 0=Normal */
+#define IFE_PSC_AUTO_POLARITY_DISABLE        0x0010  /* 1=Auto Polarity Disabled, 0=Enabled */
+#define IFE_PSC_JABBER_FUNC_DISABLE          0x0001  /* 1=Jabber Disabled, 0=Normal Jabber Operation */
+#define IFE_PSC_FORCE_POLARITY_SHIFT         5
+#define IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT  4
+
+#define IFE_PMC_AUTO_MDIX                    0x0080  /* 1=enable MDI/MDI-X feature, default 0=disabled */
+#define IFE_PMC_FORCE_MDIX                   0x0040  /* 1=force MDIX-X, 0=force MDI */
+#define IFE_PMC_MDIX_STATUS                  0x0020  /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_AUTO_MDIX_COMPLETE           0x0010  /* Resolution algorthm is completed */
+#define IFE_PMC_MDIX_MODE_SHIFT              6
+#define IFE_PHC_MDIX_RESET_ALL_MASK          0x0000  /* Disable auto MDI-X */
+
+#define IFE_PHC_HWI_ENABLE                   0x8000  /* Enable the HWI feature */
+#define IFE_PHC_ABILITY_CHECK                0x4000  /* 1= Test Passed, 0=failed */
+#define IFE_PHC_TEST_EXEC                    0x2000  /* PHY launch test pulses on the wire */
+#define IFE_PHC_HIGHZ                        0x0200  /* 1 = Open Circuit */
+#define IFE_PHC_LOWZ                         0x0400  /* 1 = Short Circuit */
+#define IFE_PHC_LOW_HIGH_Z_MASK              0x0600  /* Mask for indication type of problem on the line */
+#define IFE_PHC_DISTANCE_MASK                0x01FF  /* Mask for distance to the cable problem, in 80cm granularity */
+#define IFE_PHC_RESET_ALL_MASK               0x0000  /* Disable HWI */
+#define IFE_PSCL_PROBE_MODE                  0x0020  /* LED Probe mode */
+#define IFE_PSCL_PROBE_LEDS_OFF              0x0006  /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON               0x0007  /* Force LEDs 0 and 2 on */
+
+#define ICH8_FLASH_COMMAND_TIMEOUT           500   /* 500 ms , should be adjusted */
+#define ICH8_FLASH_CYCLE_REPEAT_COUNT        10    /* 10 cycles , should be adjusted */
+#define ICH8_FLASH_SEG_SIZE_256              256
+#define ICH8_FLASH_SEG_SIZE_4K               4096
+#define ICH8_FLASH_SEG_SIZE_64K              65536
+
+#define ICH8_CYCLE_READ                      0x0
+#define ICH8_CYCLE_RESERVED                  0x1
+#define ICH8_CYCLE_WRITE                     0x2
+#define ICH8_CYCLE_ERASE                     0x3
+
+#define ICH8_FLASH_GFPREG   0x0000
+#define ICH8_FLASH_HSFSTS   0x0004
+#define ICH8_FLASH_HSFCTL   0x0006
+#define ICH8_FLASH_FADDR    0x0008
+#define ICH8_FLASH_FDATA0   0x0010
+#define ICH8_FLASH_FRACC    0x0050
+#define ICH8_FLASH_FREG0    0x0054
+#define ICH8_FLASH_FREG1    0x0058
+#define ICH8_FLASH_FREG2    0x005C
+#define ICH8_FLASH_FREG3    0x0060
+#define ICH8_FLASH_FPR0     0x0074
+#define ICH8_FLASH_FPR1     0x0078
+#define ICH8_FLASH_SSFSTS   0x0090
+#define ICH8_FLASH_SSFCTL   0x0092
+#define ICH8_FLASH_PREOP    0x0094
+#define ICH8_FLASH_OPTYPE   0x0096
+#define ICH8_FLASH_OPMENU   0x0098
+
+#define ICH8_FLASH_REG_MAPSIZE      0x00A0
+#define ICH8_FLASH_SECTOR_SIZE      4096
+#define ICH8_GFPREG_BASE_MASK       0x1FFF
+#define ICH8_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
+
+/* ICH8 GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
+/* Offset 04h HSFSTS */
+union ich8_hws_flash_status {
+    struct ich8_hsfsts {
+#ifdef E1000_BIG_ENDIAN
+        uint16_t reserved2      :6;
+        uint16_t fldesvalid     :1;
+        uint16_t flockdn        :1;
+        uint16_t flcdone        :1;
+        uint16_t flcerr         :1;
+        uint16_t dael           :1;
+        uint16_t berasesz       :2;
+        uint16_t flcinprog      :1;
+        uint16_t reserved1      :2;
+#else
+        uint16_t flcdone        :1;   /* bit 0 Flash Cycle Done */
+        uint16_t flcerr         :1;   /* bit 1 Flash Cycle Error */
+        uint16_t dael           :1;   /* bit 2 Direct Access error Log */
+        uint16_t berasesz       :2;   /* bit 4:3 Block/Sector Erase Size */
+        uint16_t flcinprog      :1;   /* bit 5 flash SPI cycle in Progress */
+        uint16_t reserved1      :2;   /* bit 13:6 Reserved */
+        uint16_t reserved2      :6;   /* bit 13:6 Reserved */
+        uint16_t fldesvalid     :1;   /* bit 14 Flash Descriptor Valid */
+        uint16_t flockdn        :1;   /* bit 15 Flash Configuration Lock-Down */
+#endif
+    } hsf_status;
+    uint16_t regval;
+};
+
+/* ICH8 GbE Flash Hardware Sequencing Flash control Register bit breakdown */
+/* Offset 06h FLCTL */
+union ich8_hws_flash_ctrl {
+    struct ich8_hsflctl {
+#ifdef E1000_BIG_ENDIAN
+        uint16_t fldbcount      :2;
+        uint16_t flockdn        :6;
+        uint16_t flcgo          :1;
+        uint16_t flcycle        :2;
+        uint16_t reserved       :5;
+#else
+        uint16_t flcgo          :1;   /* 0 Flash Cycle Go */
+        uint16_t flcycle        :2;   /* 2:1 Flash Cycle */
+        uint16_t reserved       :5;   /* 7:3 Reserved  */
+        uint16_t fldbcount      :2;   /* 9:8 Flash Data Byte Count */
+        uint16_t flockdn        :6;   /* 15:10 Reserved */
+#endif
+    } hsf_ctrl;
+    uint16_t regval;
+};
+
+/* ICH8 Flash Region Access Permissions */
+union ich8_hws_flash_regacc {
+    struct ich8_flracc {
+#ifdef E1000_BIG_ENDIAN
+        uint32_t gmwag          :8;
+        uint32_t gmrag          :8;
+        uint32_t grwa           :8;
+        uint32_t grra           :8;
+#else
+        uint32_t grra           :8;   /* 0:7 GbE region Read Access */
+        uint32_t grwa           :8;   /* 8:15 GbE region Write Access */
+        uint32_t gmrag          :8;   /* 23:16 GbE Master Read Access Grant  */
+        uint32_t gmwag          :8;   /* 31:24 GbE Master Write Access Grant */
+#endif
+    } hsf_flregacc;
+    uint16_t regval;
+};
+
 /* Miscellaneous PHY bit definitions. */
 #define PHY_PREAMBLE        0xFFFFFFFF
 #define PHY_SOF             0x01
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index 6130a42..78f54e3 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -130,4 +130,17 @@ typedef enum {
 
 #define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
 
+#define E1000_WRITE_ICH8_REG(a, reg, value) ( \
+    writel((value), ((a)->flash_address + reg)))
+
+#define E1000_READ_ICH8_REG(a, reg) ( \
+    readl((a)->flash_address + reg))
+
+#define E1000_WRITE_ICH8_REG16(a, reg, value) ( \
+    writew((value), ((a)->flash_address + reg)))
+
+#define E1000_READ_ICH8_REG16(a, reg) ( \
+    readw((a)->flash_address + reg))
+
+
 #endif /* _E1000_OSDEP_H_ */



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 18/21] e1000: integrate ich8 support into driver
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (16 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 17/21] e1000: add ich8lan core functions Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-27  1:54   ` Jeff Garzik
  2006-06-22  5:20 ` [PATCH 19/21] e1000: allow user to disable ich8 lock loss workaround Kok, Auke
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


This hooks up the ich8 structure into the driver itself.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000.h         |    1 
 drivers/net/e1000/e1000_ethtool.c |   80 +++--
 drivers/net/e1000/e1000_hw.c      |  654 ++++++++++++++++++++++++++++++++-----
 drivers/net/e1000/e1000_main.c    |  118 ++++++-
 4 files changed, 724 insertions(+), 129 deletions(-)

diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index dbdaa33..323a268 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -143,6 +143,7 @@ struct e1000_adapter;
 
 #define AUTO_ALL_MODES            0
 #define E1000_EEPROM_82544_APM    0x0004
+#define E1000_EEPROM_ICH8_APME    0x0004
 #define E1000_EEPROM_APME         0x0400
 
 #ifndef E1000_MASTER_SLAVE
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 0609155..3a0b847 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -109,7 +109,8 @@ e1000_get_settings(struct net_device *ne
 		                   SUPPORTED_1000baseT_Full|
 		                   SUPPORTED_Autoneg |
 		                   SUPPORTED_TP);
-
+		if (hw->phy_type == e1000_phy_ife)
+			ecmd->supported &= ~SUPPORTED_1000baseT_Full;
 		ecmd->advertising = ADVERTISED_TP;
 
 		if (hw->autoneg == 1) {
@@ -573,6 +574,7 @@ e1000_get_drvinfo(struct net_device *net
 	case e1000_82572:
 	case e1000_82573:
 	case e1000_80003es2lan:
+	case e1000_ich8lan:
 		sprintf(firmware_version, "%d.%d-%d",
 			(eeprom_data & 0xF000) >> 12,
 			(eeprom_data & 0x0FF0) >> 4,
@@ -757,6 +759,7 @@ e1000_reg_test(struct e1000_adapter *ada
 		toggle = 0x7FFFF3FF;
 		break;
 	case e1000_82573:
+	case e1000_ich8lan:
 		toggle = 0x7FFFF033;
 		break;
 	default:
@@ -776,11 +779,12 @@ e1000_reg_test(struct e1000_adapter *ada
 	}
 	/* restore previous status */
 	E1000_WRITE_REG(&adapter->hw, STATUS, before);
-
-	REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
-	REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
-	REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF);
-	REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF);
+	if (adapter->hw.mac_type != e1000_ich8lan) {
+		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);
@@ -793,20 +797,22 @@ e1000_reg_test(struct e1000_adapter *ada
 	REG_PATTERN_TEST(TDLEN, 0x000FFF80, 0x000FFFFF);
 
 	REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x00000000);
-	REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0x003FFFFB);
+	before = (adapter->hw.mac_type == e1000_ich8lan ?
+			0x06C3B33E : 0x06DFB3FE);
+	REG_SET_AND_CHECK(RCTL, before, 0x003FFFFB);
 	REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000);
 
 	if (adapter->hw.mac_type >= e1000_82543) {
 
-		REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0xFFFFFFFF);
+		REG_SET_AND_CHECK(RCTL, before, 0xFFFFFFFF);
 		REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
-		REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
+		if (adapter->hw.mac_type != e1000_ich8lan)
+			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);
+		value = (adapter->hw.mac_type == e1000_ich8lan ?
+				E1000_RAR_ENTRIES_ICH8LAN : E1000_RAR_ENTRIES);
+		for (i = 0; i < value; i++) {
 			REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF,
 					 0xFFFFFFFF);
 		}
@@ -820,7 +826,9 @@ e1000_reg_test(struct e1000_adapter *ada
 
 	}
 
-	for (i = 0; i < E1000_MC_TBL_SIZE; i++)
+	value = (adapter->hw.mac_type == e1000_ich8lan ?
+			E1000_MC_TBL_SIZE_ICH8LAN : E1000_MC_TBL_SIZE);
+	for (i = 0; i < value; i++)
 		REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF);
 
 	*data = 0;
@@ -892,6 +900,8 @@ e1000_intr_test(struct e1000_adapter *ad
 	/* Test each interrupt */
 	for (; i < 10; i++) {
 
+		if (adapter->hw.mac_type == e1000_ich8lan && i == 8)
+			continue;
 		/* Interrupt to test */
 		mask = 1 << i;
 
@@ -1251,16 +1261,31 @@ e1000_integrated_phy_loopback(struct e10
 		                    GG82563_PHY_KMRN_MODE_CTRL,
 		                    0x1CC);
 	}
-	/* 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.phy_type == e1000_phy_ife) {
+		/* force 100, set loopback */
+		e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x6100);
+
+		/* Now set up the MAC to the same speed/duplex as the PHY. */
+		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_100 |/* Force Speed to 100 */
+			     E1000_CTRL_FD);	 /* Force Duplex to FULL */
+	} else {
+		/* 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) {
@@ -1320,6 +1345,7 @@ e1000_set_phy_loopback(struct e1000_adap
 	case e1000_82572:
 	case e1000_82573:
 	case e1000_80003es2lan:
+	case e1000_ich8lan:
 		return e1000_integrated_phy_loopback(adapter);
 		break;
 
@@ -1786,6 +1812,16 @@ e1000_phys_id(struct net_device *netdev,
 		mod_timer(&adapter->blink_timer, jiffies);
 		msleep_interruptible(data * 1000);
 		del_timer_sync(&adapter->blink_timer);
+	} else if (adapter->hw.phy_type == e1000_phy_ife) {
+		if (!adapter->blink_timer.function) {
+			init_timer(&adapter->blink_timer);
+			adapter->blink_timer.function = e1000_led_blink_callback;
+			adapter->blink_timer.data = (unsigned long) adapter;
+		}
+		mod_timer(&adapter->blink_timer, jiffies);
+		msleep_interruptible(data * 1000);
+		del_timer_sync(&adapter->blink_timer);
+		e1000_write_phy_reg(&(adapter->hw), IFE_PHY_SPECIAL_CONTROL_LED, 0);
 	} else {
 		e1000_blink_led_start(&adapter->hw);
 		msleep_interruptible(data * 1000);
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index a3f5ccd..583518a 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -101,7 +101,8 @@ static void e1000_write_reg_io(struct e1
 
 #define E1000_WRITE_REG_IO(a, reg, val) \
 	    e1000_write_reg_io((a), E1000_##reg, val)
-static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw);
+static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw,
+                                               uint16_t duplex);
 static int32_t e1000_configure_kmrn_for_1000(struct e1000_hw *hw);
 
 /* IGP cable length table */
@@ -156,6 +157,14 @@ e1000_set_phy_type(struct e1000_hw *hw)
             hw->phy_type = e1000_phy_igp;
             break;
         }
+    case IGP03E1000_E_PHY_ID:
+        hw->phy_type = e1000_phy_igp_3;
+        break;
+    case IFE_E_PHY_ID:
+    case IFE_PLUS_E_PHY_ID:
+    case IFE_C_E_PHY_ID:
+        hw->phy_type = e1000_phy_ife;
+        break;
     case GG82563_E_PHY_ID:
         if (hw->mac_type == e1000_80003es2lan) {
             hw->phy_type = e1000_phy_gg82563;
@@ -332,6 +341,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
         break;
     case E1000_DEV_ID_82541EI:
     case E1000_DEV_ID_82541EI_MOBILE:
+    case E1000_DEV_ID_82541ER_LOM:
         hw->mac_type = e1000_82541;
         break;
     case E1000_DEV_ID_82541ER:
@@ -341,6 +351,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
         hw->mac_type = e1000_82541_rev_2;
         break;
     case E1000_DEV_ID_82547EI:
+    case E1000_DEV_ID_82547EI_MOBILE:
         hw->mac_type = e1000_82547;
         break;
     case E1000_DEV_ID_82547GI:
@@ -354,6 +365,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
     case E1000_DEV_ID_82572EI_COPPER:
     case E1000_DEV_ID_82572EI_FIBER:
     case E1000_DEV_ID_82572EI_SERDES:
+    case E1000_DEV_ID_82572EI:
         hw->mac_type = e1000_82572;
         break;
     case E1000_DEV_ID_82573E:
@@ -361,16 +373,29 @@ e1000_set_mac_type(struct e1000_hw *hw)
     case E1000_DEV_ID_82573L:
         hw->mac_type = e1000_82573;
         break;
+    case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
+    case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
     case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
     case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
         hw->mac_type = e1000_80003es2lan;
         break;
+    case E1000_DEV_ID_ICH8_IGP_M_AMT:
+    case E1000_DEV_ID_ICH8_IGP_AMT:
+    case E1000_DEV_ID_ICH8_IGP_C:
+    case E1000_DEV_ID_ICH8_IFE:
+    case E1000_DEV_ID_ICH8_IGP_M:
+        hw->mac_type = e1000_ich8lan;
+        break;
     default:
         /* Should never have loaded on this device */
         return -E1000_ERR_MAC_TYPE;
     }
 
     switch(hw->mac_type) {
+    case e1000_ich8lan:
+        hw->swfwhw_semaphore_present = TRUE;
+        hw->asf_firmware_present = TRUE;
+        break;
     case e1000_80003es2lan:
         hw->swfw_sync_present = TRUE;
         /* fall through */
@@ -423,6 +448,7 @@ e1000_set_media_type(struct e1000_hw *hw
         case e1000_82542_rev2_1:
             hw->media_type = e1000_media_type_fiber;
             break;
+        case e1000_ich8lan:
         case e1000_82573:
             /* The STATUS_TBIMODE bit is reserved or reused for the this
              * device.
@@ -527,6 +553,14 @@ e1000_reset_hw(struct e1000_hw *hw)
         } while(timeout);
     }
 
+    /* Workaround for ICH8 bit corruption issue in FIFO memory */
+    if (hw->mac_type == e1000_ich8lan) {
+        /* Set Tx and Rx buffer allocation to 8k apiece. */
+        E1000_WRITE_REG(hw, PBA, E1000_PBA_8K);
+        /* Set Packet Buffer Size to 16k. */
+        E1000_WRITE_REG(hw, PBS, E1000_PBS_16K);
+    }
+
     /* Issue a global reset to the MAC.  This will reset the chip's
      * transmit, receive, DMA, and link units.  It will not effect
      * the current PCI configuration.  The global reset bit is self-
@@ -550,6 +584,20 @@ e1000_reset_hw(struct e1000_hw *hw)
             /* Reset is performed on a shadow of the control register */
             E1000_WRITE_REG(hw, CTRL_DUP, (ctrl | E1000_CTRL_RST));
             break;
+        case e1000_ich8lan:
+            if (!hw->phy_reset_disable &&
+                e1000_check_phy_reset_block(hw) == E1000_SUCCESS) {
+                /* e1000_ich8lan PHY HW reset requires MAC CORE reset
+                 * at the same time to make sure the interface between
+                 * MAC and the external PHY is reset.
+                 */
+                ctrl |= E1000_CTRL_PHY_RST;
+            }
+
+            e1000_get_software_flag(hw);
+            E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+            msec_delay(5);
+            break;
         default:
             E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
             break;
@@ -591,6 +639,7 @@ e1000_reset_hw(struct e1000_hw *hw)
             /* fall through */
         case e1000_82571:
         case e1000_82572:
+        case e1000_ich8lan:
         case e1000_80003es2lan:
             ret_val = e1000_get_auto_rd_done(hw);
             if(ret_val)
@@ -633,6 +682,12 @@ e1000_reset_hw(struct e1000_hw *hw)
             e1000_pci_set_mwi(hw);
     }
 
+    if (hw->mac_type == e1000_ich8lan) {
+        uint32_t kab = E1000_READ_REG(hw, KABGTXD);
+        kab |= E1000_KABGTXD_BGSQLBIAS;
+        E1000_WRITE_REG(hw, KABGTXD, kab);
+    }
+
     return E1000_SUCCESS;
 }
 
@@ -675,9 +730,12 @@ e1000_init_hw(struct e1000_hw *hw)
 
     /* Disabling VLAN filtering. */
     DEBUGOUT("Initializing the IEEE VLAN\n");
-    if (hw->mac_type < e1000_82545_rev_3)
-        E1000_WRITE_REG(hw, VET, 0);
-    e1000_clear_vfta(hw);
+    /* VET hardcoded to standard value and VFTA removed in ICH8 LAN */
+    if (hw->mac_type != e1000_ich8lan) {
+        if (hw->mac_type < e1000_82545_rev_3)
+            E1000_WRITE_REG(hw, VET, 0);
+        e1000_clear_vfta(hw);
+    }
 
     /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
     if(hw->mac_type == e1000_82542_rev2_0) {
@@ -705,6 +763,8 @@ e1000_init_hw(struct e1000_hw *hw)
     /* Zero out the Multicast HASH table */
     DEBUGOUT("Zeroing the MTA\n");
     mta_size = E1000_MC_TBL_SIZE;
+    if (hw->mac_type == e1000_ich8lan)
+        mta_size = E1000_MC_TBL_SIZE_ICH8LAN;
     for(i = 0; i < mta_size; i++) {
         E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
         /* use write flush to prevent Memory Write Block (MWB) from
@@ -748,6 +808,10 @@ e1000_init_hw(struct e1000_hw *hw)
         break;
     }
 
+    /* More time needed for PHY to initialize */
+    if (hw->mac_type == e1000_ich8lan)
+        msec_delay(15);
+
     /* Call a subroutine to configure the link and setup flow control. */
     ret_val = e1000_setup_link(hw);
 
@@ -761,6 +825,7 @@ e1000_init_hw(struct e1000_hw *hw)
         case e1000_82571:
         case e1000_82572:
         case e1000_82573:
+        case e1000_ich8lan:
         case e1000_80003es2lan:
             ctrl |= E1000_TXDCTL_COUNT_DESC;
             break;
@@ -799,6 +864,7 @@ e1000_init_hw(struct e1000_hw *hw)
         /* Fall through */
     case e1000_82571:
     case e1000_82572:
+    case e1000_ich8lan:
         ctrl = E1000_READ_REG(hw, TXDCTL1);
         ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
         if(hw->mac_type >= e1000_82571)
@@ -822,6 +888,11 @@ e1000_init_hw(struct e1000_hw *hw)
      */
     e1000_clear_hw_cntrs(hw);
 
+    /* ICH8 No-snoop bits are opposite polarity.
+     * Set to snoop by default after reset. */
+    if (hw->mac_type == e1000_ich8lan)
+        e1000_set_pci_ex_no_snoop(hw, PCI_EX_82566_SNOOP_ALL);
+
     if (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER ||
         hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3) {
         ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
@@ -909,6 +980,7 @@ e1000_setup_link(struct e1000_hw *hw)
      */
     if (hw->fc == e1000_fc_default) {
         switch (hw->mac_type) {
+        case e1000_ich8lan:
         case e1000_82573:
             hw->fc = e1000_fc_full;
             break;
@@ -975,9 +1047,12 @@ e1000_setup_link(struct e1000_hw *hw)
      */
     DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
 
-    E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
-    E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
-    E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+    /* FCAL/H and FCT are hardcoded to standard values in e1000_ich8lan. */
+    if (hw->mac_type != e1000_ich8lan) {
+        E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+        E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+        E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+    }
 
     E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
 
@@ -1241,12 +1316,13 @@ e1000_copper_link_igp_setup(struct e1000
 
     /* Wait 10ms for MAC to configure PHY from eeprom settings */
     msec_delay(15);
-
+    if (hw->mac_type != e1000_ich8lan) {
     /* 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 | IGP_LED3_MODE);
     E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+    }
 
     /* disable lplu d3 during driver init */
     ret_val = e1000_set_d3_lplu_state(hw, FALSE);
@@ -1482,8 +1558,7 @@ e1000_copper_link_ggp_setup(struct e1000
             if (ret_val)
                 return ret_val;
 
-            /* Enable Pass False Carrier on the PHY */
-            phy_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+            phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
 
             ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
                                           phy_data);
@@ -1636,6 +1711,10 @@ e1000_copper_link_autoneg(struct e1000_h
     if(hw->autoneg_advertised == 0)
         hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
 
+    /* IFE phy only supports 10/100 */
+    if (hw->phy_type == e1000_phy_ife)
+        hw->autoneg_advertised &= AUTONEG_ADVERTISE_10_100_ALL;
+
     DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
     ret_val = e1000_phy_setup_autoneg(hw);
     if(ret_val) {
@@ -1733,6 +1812,26 @@ e1000_setup_copper_link(struct e1000_hw 
 
     DEBUGFUNC("e1000_setup_copper_link");
 
+    switch (hw->mac_type) {
+    case e1000_80003es2lan:
+    case e1000_ich8lan:
+        /* Set the mac to wait the maximum time between each
+         * iteration and increase the max iterations when
+         * polling the phy; this fixes erroneous timeouts at 10Mbps. */
+        ret_val = e1000_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
+        if (ret_val)
+            return ret_val;
+        ret_val = e1000_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
+        if (ret_val)
+            return ret_val;
+        reg_data |= 0x3F;
+        ret_val = e1000_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
+        if (ret_val)
+            return ret_val;
+    default:
+        break;
+    }
+
     /* Check if it is a valid PHY and set PHY mode if necessary. */
     ret_val = e1000_copper_link_preconfig(hw);
     if(ret_val)
@@ -1740,10 +1839,8 @@ e1000_setup_copper_link(struct e1000_hw 
 
     switch (hw->mac_type) {
     case e1000_80003es2lan:
-        ret_val = e1000_read_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL,
-                                      &reg_data);
-        if (ret_val)
-            return ret_val;
+        /* Kumeran registers are written-only */
+        reg_data = E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT;
         reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING;
         ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL,
                                        reg_data);
@@ -1755,6 +1852,7 @@ e1000_setup_copper_link(struct e1000_hw 
     }
 
     if (hw->phy_type == e1000_phy_igp ||
+        hw->phy_type == e1000_phy_igp_3 ||
         hw->phy_type == e1000_phy_igp_2) {
         ret_val = e1000_copper_link_igp_setup(hw);
         if(ret_val)
@@ -1819,7 +1917,7 @@ e1000_setup_copper_link(struct e1000_hw 
 * hw - Struct containing variables accessed by shared code
 ******************************************************************************/
 static int32_t
-e1000_configure_kmrn_for_10_100(struct e1000_hw *hw)
+e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, uint16_t duplex)
 {
     int32_t ret_val = E1000_SUCCESS;
     uint32_t tipg;
@@ -1839,6 +1937,18 @@ e1000_configure_kmrn_for_10_100(struct e
     tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_10_100;
     E1000_WRITE_REG(hw, TIPG, tipg);
 
+    ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+    if (ret_val)
+        return ret_val;
+
+    if (duplex == HALF_DUPLEX)
+        reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+    else
+        reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+    ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
     return ret_val;
 }
 
@@ -1863,6 +1973,14 @@ e1000_configure_kmrn_for_1000(struct e10
     tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000;
     E1000_WRITE_REG(hw, TIPG, tipg);
 
+    ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+    if (ret_val)
+        return ret_val;
+
+    reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+    ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
     return ret_val;
 }
 
@@ -1885,10 +2003,13 @@ e1000_phy_setup_autoneg(struct e1000_hw 
     if(ret_val)
         return ret_val;
 
-    /* Read the MII 1000Base-T Control Register (Address 9). */
-    ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
-    if(ret_val)
-        return ret_val;
+    if (hw->phy_type != e1000_phy_ife) {
+        /* Read the MII 1000Base-T Control Register (Address 9). */
+        ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+        if (ret_val)
+            return ret_val;
+    } else
+        mii_1000t_ctrl_reg=0;
 
     /* Need to parse both autoneg_advertised and fc and set up
      * the appropriate PHY registers.  First we will parse for
@@ -1939,6 +2060,9 @@ e1000_phy_setup_autoneg(struct e1000_hw 
     if(hw->autoneg_advertised & ADVERTISE_1000_FULL) {
         DEBUGOUT("Advertise 1000mb Full duplex\n");
         mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+        if (hw->phy_type == e1000_phy_ife) {
+            DEBUGOUT("e1000_phy_ife is a 10/100 PHY. Gigabit speed is not supported.\n");
+        }
     }
 
     /* Check for a software override of the flow control settings, and
@@ -2000,9 +2124,11 @@ e1000_phy_setup_autoneg(struct e1000_hw 
 
     DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
 
-    ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
-    if(ret_val)
-        return ret_val;
+    if (hw->phy_type != e1000_phy_ife) {
+        ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+        if (ret_val)
+            return ret_val;
+    }
 
     return E1000_SUCCESS;
 }
@@ -2105,6 +2231,18 @@ e1000_phy_force_speed_duplex(struct e100
 
         /* Need to reset the PHY or these changes will be ignored */
         mii_ctrl_reg |= MII_CR_RESET;
+    /* Disable MDI-X support for 10/100 */
+    } else if (hw->phy_type == e1000_phy_ife) {
+        ret_val = e1000_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data);
+        if (ret_val)
+            return ret_val;
+
+        phy_data &= ~IFE_PMC_AUTO_MDIX;
+        phy_data &= ~IFE_PMC_FORCE_MDIX;
+
+        ret_val = e1000_write_phy_reg(hw, IFE_PHY_MDIX_CONTROL, phy_data);
+        if (ret_val)
+            return ret_val;
     } else {
         /* Clear Auto-Crossover to force MDI manually.  IGP requires MDI
          * forced whenever speed or duplex are forced.
@@ -2909,7 +3047,13 @@ e1000_get_speed_and_duplex(struct e1000_
         if (*speed == SPEED_1000)
             ret_val = e1000_configure_kmrn_for_1000(hw);
         else
-            ret_val = e1000_configure_kmrn_for_10_100(hw);
+            ret_val = e1000_configure_kmrn_for_10_100(hw, *duplex);
+        if (ret_val)
+            return ret_val;
+    }
+
+    if ((hw->phy_type == e1000_phy_igp_3) && (*speed == SPEED_1000)) {
+        ret_val = e1000_kumeran_lock_loss_workaround(hw);
         if (ret_val)
             return ret_val;
     }
@@ -3099,6 +3243,9 @@ e1000_swfw_sync_acquire(struct e1000_hw 
 
     DEBUGFUNC("e1000_swfw_sync_acquire");
 
+    if (hw->swfwhw_semaphore_present)
+        return e1000_get_software_flag(hw);
+
     if (!hw->swfw_sync_present)
         return e1000_get_hw_eeprom_semaphore(hw);
 
@@ -3138,6 +3285,11 @@ e1000_swfw_sync_release(struct e1000_hw 
 
     DEBUGFUNC("e1000_swfw_sync_release");
 
+    if (hw->swfwhw_semaphore_present) {
+        e1000_release_software_flag(hw);
+        return;
+    }
+
     if (!hw->swfw_sync_present) {
         e1000_put_hw_eeprom_semaphore(hw);
         return;
@@ -3180,7 +3332,8 @@ e1000_read_phy_reg(struct e1000_hw *hw,
     if (e1000_swfw_sync_acquire(hw, swfw))
         return -E1000_ERR_SWFW_SYNC;
 
-    if((hw->phy_type == e1000_phy_igp ||
+    if ((hw->phy_type == e1000_phy_igp ||
+        hw->phy_type == e1000_phy_igp_3 ||
         hw->phy_type == e1000_phy_igp_2) &&
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
         ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
@@ -3319,7 +3472,8 @@ e1000_write_phy_reg(struct e1000_hw *hw,
     if (e1000_swfw_sync_acquire(hw, swfw))
         return -E1000_ERR_SWFW_SYNC;
 
-    if((hw->phy_type == e1000_phy_igp ||
+    if ((hw->phy_type == e1000_phy_igp ||
+        hw->phy_type == e1000_phy_igp_3 ||
         hw->phy_type == e1000_phy_igp_2) &&
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
         ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
@@ -3534,7 +3688,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
         E1000_WRITE_FLUSH(hw);
 
         if (hw->mac_type >= e1000_82571)
-            msec_delay(10);
+            msec_delay_irq(10);
         e1000_swfw_sync_release(hw, swfw);
     } else {
         /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
@@ -3564,6 +3718,12 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
     ret_val = e1000_get_phy_cfg_done(hw);
     e1000_release_software_semaphore(hw);
 
+        if ((hw->mac_type == e1000_ich8lan) &&
+            (hw->phy_type == e1000_phy_igp_3)) {
+            ret_val = e1000_init_lcd_from_nvm(hw);
+            if (ret_val)
+                return ret_val;
+        }
     return ret_val;
 }
 
@@ -3592,9 +3752,11 @@ e1000_phy_reset(struct e1000_hw *hw)
     case e1000_82541_rev_2:
     case e1000_82571:
     case e1000_82572:
+    case e1000_ich8lan:
         ret_val = e1000_phy_hw_reset(hw);
         if(ret_val)
             return ret_val;
+
         break;
     default:
         ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
@@ -3742,8 +3904,8 @@ e1000_detect_gig_phy(struct e1000_hw *hw
     /* The 82571 firmware may still be configuring the PHY.  In this
      * case, we cannot access the PHY until the configuration is done.  So
      * we explicitly set the PHY values. */
-    if(hw->mac_type == e1000_82571 ||
-       hw->mac_type == e1000_82572) {
+    if (hw->mac_type == e1000_82571 ||
+        hw->mac_type == e1000_82572) {
         hw->phy_id = IGP01E1000_I_PHY_ID;
         hw->phy_type = e1000_phy_igp_2;
         return E1000_SUCCESS;
@@ -3760,7 +3922,7 @@ e1000_detect_gig_phy(struct e1000_hw *hw
 
     /* Read the PHY ID Registers to identify which PHY is onboard. */
     ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high);
-    if(ret_val)
+    if (ret_val)
         return ret_val;
 
     hw->phy_id = (uint32_t) (phy_id_high << 16);
@@ -3798,6 +3960,12 @@ e1000_detect_gig_phy(struct e1000_hw *hw
     case e1000_80003es2lan:
         if (hw->phy_id == GG82563_E_PHY_ID) match = TRUE;
         break;
+    case e1000_ich8lan:
+        if (hw->phy_id == IGP03E1000_E_PHY_ID) match = TRUE;
+        if (hw->phy_id == IFE_E_PHY_ID) match = TRUE;
+        if (hw->phy_id == IFE_PLUS_E_PHY_ID) match = TRUE;
+        if (hw->phy_id == IFE_C_E_PHY_ID) match = TRUE;
+        break;
     default:
         DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
         return -E1000_ERR_CONFIG;
@@ -4074,9 +4242,12 @@ e1000_phy_get_info(struct e1000_hw *hw,
         return -E1000_ERR_CONFIG;
     }
 
-    if(hw->phy_type == e1000_phy_igp ||
+    if (hw->phy_type == e1000_phy_igp ||
+        hw->phy_type == e1000_phy_igp_3 ||
         hw->phy_type == e1000_phy_igp_2)
         return e1000_phy_igp_get_info(hw, phy_info);
+    else if (hw->phy_type == e1000_phy_ife)
+        return e1000_phy_ife_get_info(hw, phy_info);
     else
         return e1000_phy_m88_get_info(hw, phy_info);
 }
@@ -4225,6 +4396,35 @@ e1000_init_eeprom_params(struct e1000_hw
         eeprom->use_eerd = TRUE;
         eeprom->use_eewr = FALSE;
         break;
+    case e1000_ich8lan:
+    {
+        int32_t  i = 0;
+        uint32_t flash_size = E1000_READ_ICH8_REG(hw, ICH8_FLASH_GFPREG);
+
+        eeprom->type = e1000_eeprom_ich8;
+        eeprom->use_eerd = FALSE;
+        eeprom->use_eewr = FALSE;
+        eeprom->word_size = E1000_SHADOW_RAM_WORDS;
+
+        /* Zero the shadow RAM structure. But don't load it from NVM
+         * so as to save time for driver init */
+        if (hw->eeprom_shadow_ram != NULL) {
+            for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+                hw->eeprom_shadow_ram[i].modified = FALSE;
+                hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
+            }
+        }
+
+        hw->flash_base_addr = (flash_size & ICH8_GFPREG_BASE_MASK) *
+                              ICH8_FLASH_SECTOR_SIZE;
+
+        hw->flash_bank_size = ((flash_size >> 16) & ICH8_GFPREG_BASE_MASK) + 1;
+        hw->flash_bank_size -= (flash_size & ICH8_GFPREG_BASE_MASK);
+        hw->flash_bank_size *= ICH8_FLASH_SECTOR_SIZE;
+        hw->flash_bank_size /= 2 * sizeof(uint16_t);
+
+        break;
+    }
     default:
         break;
     }
@@ -4645,7 +4845,10 @@ e1000_read_eeprom(struct e1000_hw *hw,
         return ret_val;
     }
 
-    if(eeprom->type == e1000_eeprom_spi) {
+    if (eeprom->type == e1000_eeprom_ich8)
+        return e1000_read_eeprom_ich8(hw, offset, words, data);
+
+    if (eeprom->type == e1000_eeprom_spi) {
         uint16_t word_in;
         uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
 
@@ -4812,7 +5015,10 @@ e1000_is_onboard_nvm_eeprom(struct e1000
 
     DEBUGFUNC("e1000_is_onboard_nvm_eeprom");
 
-    if(hw->mac_type == e1000_82573) {
+    if (hw->mac_type == e1000_ich8lan)
+        return FALSE;
+
+    if (hw->mac_type == e1000_82573) {
         eecd = E1000_READ_REG(hw, EECD);
 
         /* Isolate bits 15 & 16 */
@@ -4862,8 +5068,22 @@ e1000_validate_eeprom_checksum(struct e1
         }
     }
 
-    for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
-        if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
+    if (hw->mac_type == e1000_ich8lan) {
+        /* Drivers must allocate the shadow ram structure for the
+         * EEPROM checksum to be updated.  Otherwise, this bit as well
+         * as the checksum must both be set correctly for this
+         * validation to pass.
+         */
+        e1000_read_eeprom(hw, 0x19, 1, &eeprom_data);
+        if ((eeprom_data & 0x40) == 0) {
+            eeprom_data |= 0x40;
+            e1000_write_eeprom(hw, 0x19, 1, &eeprom_data);
+            e1000_update_eeprom_checksum(hw);
+        }
+    }
+
+    for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+        if (e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
             DEBUGOUT("EEPROM Read Error\n");
             return -E1000_ERR_EEPROM;
         }
@@ -4889,6 +5109,7 @@ e1000_validate_eeprom_checksum(struct e1
 int32_t
 e1000_update_eeprom_checksum(struct e1000_hw *hw)
 {
+    uint32_t ctrl_ext;
     uint16_t checksum = 0;
     uint16_t i, eeprom_data;
 
@@ -4907,6 +5128,14 @@ e1000_update_eeprom_checksum(struct e100
         return -E1000_ERR_EEPROM;
     } else if (hw->eeprom.type == e1000_eeprom_flash) {
         e1000_commit_shadow_ram(hw);
+    } else if (hw->eeprom.type == e1000_eeprom_ich8) {
+        e1000_commit_shadow_ram(hw);
+        /* Reload the EEPROM, or else modifications will not appear
+         * until after next adapter reset. */
+        ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+        ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        msec_delay(10);
     }
     return E1000_SUCCESS;
 }
@@ -4946,6 +5175,9 @@ e1000_write_eeprom(struct e1000_hw *hw,
     if(eeprom->use_eewr == TRUE)
         return e1000_write_eeprom_eewr(hw, offset, words, data);
 
+    if (eeprom->type == e1000_eeprom_ich8)
+        return e1000_write_eeprom_ich8(hw, offset, words, data);
+
     /* Prepare the EEPROM for writing  */
     if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
         return -E1000_ERR_EEPROM;
@@ -5133,11 +5365,17 @@ e1000_commit_shadow_ram(struct e1000_hw 
     uint32_t flop = 0;
     uint32_t i = 0;
     int32_t error = E1000_SUCCESS;
-
-    /* The flop register will be used to determine if flash type is STM */
-    flop = E1000_READ_REG(hw, FLOP);
+    uint32_t old_bank_offset = 0;
+    uint32_t new_bank_offset = 0;
+    uint32_t sector_retries = 0;
+    uint8_t low_byte = 0;
+    uint8_t high_byte = 0;
+    uint8_t temp_byte = 0;
+    boolean_t sector_write_failed = FALSE;
 
     if (hw->mac_type == e1000_82573) {
+        /* The flop register will be used to determine if flash type is STM */
+        flop = E1000_READ_REG(hw, FLOP);
         for (i=0; i < attempts; i++) {
             eecd = E1000_READ_REG(hw, EECD);
             if ((eecd & E1000_EECD_FLUPD) == 0) {
@@ -5171,6 +5409,106 @@ e1000_commit_shadow_ram(struct e1000_hw 
         }
     }
 
+    if (hw->mac_type == e1000_ich8lan && hw->eeprom_shadow_ram != NULL) {
+        /* We're writing to the opposite bank so if we're on bank 1,
+         * write to bank 0 etc.  We also need to erase the segment that
+         * is going to be written */
+        if (!(E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL)) {
+            new_bank_offset = hw->flash_bank_size * 2;
+            old_bank_offset = 0;
+            e1000_erase_ich8_4k_segment(hw, 1);
+        } else {
+            old_bank_offset = hw->flash_bank_size * 2;
+            new_bank_offset = 0;
+            e1000_erase_ich8_4k_segment(hw, 0);
+        }
+
+        do {
+            sector_write_failed = FALSE;
+            /* Loop for every byte in the shadow RAM,
+             * which is in units of words. */
+            for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+                /* Determine whether to write the value stored
+                 * in the other NVM bank or a modified value stored
+                 * in the shadow RAM */
+                if (hw->eeprom_shadow_ram[i].modified == TRUE) {
+                    low_byte = (uint8_t)hw->eeprom_shadow_ram[i].eeprom_word;
+                    e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
+                                         &temp_byte);
+                    udelay(100);
+                    error = e1000_verify_write_ich8_byte(hw,
+                                                 (i << 1) + new_bank_offset,
+                                                 low_byte);
+                    if (error != E1000_SUCCESS)
+                        sector_write_failed = TRUE;
+                    high_byte =
+                        (uint8_t)(hw->eeprom_shadow_ram[i].eeprom_word >> 8);
+                    e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
+                                         &temp_byte);
+                    udelay(100);
+                } else {
+                    e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
+                                         &low_byte);
+                    udelay(100);
+                    error = e1000_verify_write_ich8_byte(hw,
+                                 (i << 1) + new_bank_offset, low_byte);
+                    if (error != E1000_SUCCESS)
+                        sector_write_failed = TRUE;
+                    e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
+                                         &high_byte);
+                }
+
+                /* If the word is 0x13, then make sure the signature bits
+                 * (15:14) are 11b until the commit has completed.
+                 * This will allow us to write 10b which indicates the
+                 * signature is valid.  We want to do this after the write
+                 * has completed so that we don't mark the segment valid
+                 * while the write is still in progress */
+                if (i == E1000_ICH8_NVM_SIG_WORD)
+                    high_byte = E1000_ICH8_NVM_SIG_MASK | high_byte;
+
+                error = e1000_verify_write_ich8_byte(hw,
+                             (i << 1) + new_bank_offset + 1, high_byte);
+                if (error != E1000_SUCCESS)
+                    sector_write_failed = TRUE;
+
+                if (sector_write_failed == FALSE) {
+                    /* Clear the now not used entry in the cache */
+                    hw->eeprom_shadow_ram[i].modified = FALSE;
+                    hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
+                }
+            }
+
+            /* Don't bother writing the segment valid bits if sector
+             * programming failed. */
+            if (sector_write_failed == FALSE) {
+                /* Finally validate the new segment by setting bit 15:14
+                 * to 10b in word 0x13 , this can be done without an
+                 * erase as well since these bits are 11 to start with
+                 * and we need to change bit 14 to 0b */
+                e1000_read_ich8_byte(hw,
+                    E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
+                    &high_byte);
+                high_byte &= 0xBF;
+                error = e1000_verify_write_ich8_byte(hw,
+                            E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
+                            high_byte);
+                if (error != E1000_SUCCESS)
+                    sector_write_failed = TRUE;
+
+                /* And invalidate the previously valid segment by setting
+                 * its signature word (0x13) high_byte to 0b. This can be
+                 * done without an erase because flash erase sets all bits
+                 * to 1's. We can write 1's to 0's without an erase */
+                error = e1000_verify_write_ich8_byte(hw,
+                            E1000_ICH8_NVM_SIG_WORD * 2 + 1 + old_bank_offset,
+                            0);
+                if (error != E1000_SUCCESS)
+                    sector_write_failed = TRUE;
+            }
+        } while (++sector_retries < 10 && sector_write_failed == TRUE);
+    }
+
     return error;
 }
 
@@ -5278,6 +5616,9 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
      * the other port. */
     if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE))
         rar_num -= 1;
+    if (hw->mac_type == e1000_ich8lan)
+        rar_num = E1000_RAR_ENTRIES_ICH8LAN;
+
     /* Zero out the other 15 receive addresses. */
     DEBUGOUT("Clearing RAR[1-15]\n");
     for(i = 1; i < rar_num; i++) {
@@ -5288,7 +5629,6 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
     }
 }
 
-#if 0
 /******************************************************************************
  * Updates the MAC's list of multicast addresses.
  *
@@ -5323,6 +5663,8 @@ e1000_mc_addr_list_update(struct e1000_h
     /* Clear RAR[1-15] */
     DEBUGOUT(" Clearing RAR[1-15]\n");
     num_rar_entry = E1000_RAR_ENTRIES;
+    if (hw->mac_type == e1000_ich8lan)
+        num_rar_entry = E1000_RAR_ENTRIES_ICH8LAN;
     /* Reserve a spot for the Locally Administered Address to work around
      * an 82571 issue in which a reset on one port will reload the MAC on
      * the other port. */
@@ -5339,6 +5681,8 @@ e1000_mc_addr_list_update(struct e1000_h
     /* Clear the MTA */
     DEBUGOUT(" Clearing MTA\n");
     num_mta_entry = E1000_NUM_MTA_REGISTERS;
+    if (hw->mac_type == e1000_ich8lan)
+        num_mta_entry = E1000_NUM_MTA_REGISTERS_ICH8LAN;
     for(i = 0; i < num_mta_entry; i++) {
         E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
         E1000_WRITE_FLUSH(hw);
@@ -5375,7 +5719,6 @@ e1000_mc_addr_list_update(struct e1000_h
     }
     DEBUGOUT("MC Update Complete\n");
 }
-#endif  /*  0  */
 
 /******************************************************************************
  * Hashes an address to determine its location in the multicast table
@@ -5398,24 +5741,46 @@ e1000_hash_mc_addr(struct e1000_hw *hw,
      * LSB                 MSB
      */
     case 0:
-        /* [47:36] i.e. 0x563 for above example address */
-        hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+        if (hw->mac_type == e1000_ich8lan) {
+            /* [47:38] i.e. 0x158 for above example address */
+            hash_value = ((mc_addr[4] >> 6) | (((uint16_t) mc_addr[5]) << 2));
+        } else {
+            /* [47:36] i.e. 0x563 for above example address */
+            hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+        }
         break;
     case 1:
-        /* [46:35] i.e. 0xAC6 for above example address */
-        hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+        if (hw->mac_type == e1000_ich8lan) {
+            /* [46:37] i.e. 0x2B1 for above example address */
+            hash_value = ((mc_addr[4] >> 5) | (((uint16_t) mc_addr[5]) << 3));
+        } else {
+            /* [46:35] i.e. 0xAC6 for above example address */
+            hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+        }
         break;
     case 2:
-        /* [45:34] i.e. 0x5D8 for above example address */
-        hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+        if (hw->mac_type == e1000_ich8lan) {
+            /*[45:36] i.e. 0x163 for above example address */
+            hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+        } else {
+            /* [45:34] i.e. 0x5D8 for above example address */
+            hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+        }
         break;
     case 3:
-        /* [43:32] i.e. 0x634 for above example address */
-        hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+        if (hw->mac_type == e1000_ich8lan) {
+            /* [43:34] i.e. 0x18D for above example address */
+            hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+        } else {
+            /* [43:32] i.e. 0x634 for above example address */
+            hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+        }
         break;
     }
 
     hash_value &= 0xFFF;
+    if (hw->mac_type == e1000_ich8lan)
+        hash_value &= 0x3FF;
 
     return hash_value;
 }
@@ -5443,6 +5808,8 @@ e1000_mta_set(struct e1000_hw *hw,
      * register are determined by the lower 5 bits of the value.
      */
     hash_reg = (hash_value >> 5) & 0x7F;
+    if (hw->mac_type == e1000_ich8lan)
+        hash_reg &= 0x1F;
     hash_bit = hash_value & 0x1F;
 
     mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg);
@@ -5537,7 +5904,10 @@ e1000_write_vfta(struct e1000_hw *hw,
 {
     uint32_t temp;
 
-    if((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
+    if (hw->mac_type == e1000_ich8lan)
+        return;
+
+    if ((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
         temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1));
         E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
         E1000_WRITE_FLUSH(hw);
@@ -5562,6 +5932,9 @@ e1000_clear_vfta(struct e1000_hw *hw)
     uint32_t vfta_offset = 0;
     uint32_t vfta_bit_in_reg = 0;
 
+    if (hw->mac_type == e1000_ich8lan)
+        return;
+
     if (hw->mac_type == e1000_82573) {
         if (hw->mng_cookie.vlan_id != 0) {
             /* The VFTA is a 4096b bit-field, each identifying a single VLAN
@@ -5611,9 +5984,18 @@ e1000_id_led_init(struct e1000_hw * hw)
         DEBUGOUT("EEPROM Read Error\n");
         return -E1000_ERR_EEPROM;
     }
-    if((eeprom_data== ID_LED_RESERVED_0000) ||
-       (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT;
-    for(i = 0; i < 4; i++) {
+
+    if ((hw->mac_type == e1000_82573) &&
+        (eeprom_data == ID_LED_RESERVED_82573))
+        eeprom_data = ID_LED_DEFAULT_82573;
+    else if ((eeprom_data == ID_LED_RESERVED_0000) ||
+            (eeprom_data == ID_LED_RESERVED_FFFF)) {
+        if (hw->mac_type == e1000_ich8lan)
+            eeprom_data = ID_LED_DEFAULT_ICH8LAN;
+        else
+            eeprom_data = ID_LED_DEFAULT;
+    }
+    for (i = 0; i < 4; i++) {
         temp = (eeprom_data >> (i << 2)) & led_mask;
         switch(temp) {
         case ID_LED_ON1_DEF2:
@@ -5776,6 +6158,10 @@ e1000_cleanup_led(struct e1000_hw *hw)
             return ret_val;
         /* Fall Through */
     default:
+        if (hw->phy_type == e1000_phy_ife) {
+            e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
+            break;
+        }
         /* Restore LEDCTL settings */
         E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
         break;
@@ -5820,7 +6206,10 @@ e1000_led_on(struct e1000_hw *hw)
             /* Clear SW Defineable Pin 0 to turn on the LED */
             ctrl &= ~E1000_CTRL_SWDPIN0;
             ctrl |= E1000_CTRL_SWDPIO0;
-        } else if(hw->media_type == e1000_media_type_copper) {
+        } else if (hw->phy_type == e1000_phy_ife) {
+            e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+                 (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
+        } else if (hw->media_type == e1000_media_type_copper) {
             E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
             return E1000_SUCCESS;
         }
@@ -5868,7 +6257,10 @@ e1000_led_off(struct e1000_hw *hw)
             /* Set SW Defineable Pin 0 to turn off the LED */
             ctrl |= E1000_CTRL_SWDPIN0;
             ctrl |= E1000_CTRL_SWDPIO0;
-        } else if(hw->media_type == e1000_media_type_copper) {
+        } else if (hw->phy_type == e1000_phy_ife) {
+            e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+                 (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
+        } else if (hw->media_type == e1000_media_type_copper) {
             E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
             return E1000_SUCCESS;
         }
@@ -5906,12 +6298,16 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw
     temp = E1000_READ_REG(hw, XOFFRXC);
     temp = E1000_READ_REG(hw, XOFFTXC);
     temp = E1000_READ_REG(hw, FCRUC);
+
+    if (hw->mac_type != e1000_ich8lan) {
     temp = E1000_READ_REG(hw, PRC64);
     temp = E1000_READ_REG(hw, PRC127);
     temp = E1000_READ_REG(hw, PRC255);
     temp = E1000_READ_REG(hw, PRC511);
     temp = E1000_READ_REG(hw, PRC1023);
     temp = E1000_READ_REG(hw, PRC1522);
+    }
+
     temp = E1000_READ_REG(hw, GPRC);
     temp = E1000_READ_REG(hw, BPRC);
     temp = E1000_READ_REG(hw, MPRC);
@@ -5931,12 +6327,16 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw
     temp = E1000_READ_REG(hw, TOTH);
     temp = E1000_READ_REG(hw, TPR);
     temp = E1000_READ_REG(hw, TPT);
+
+    if (hw->mac_type != e1000_ich8lan) {
     temp = E1000_READ_REG(hw, PTC64);
     temp = E1000_READ_REG(hw, PTC127);
     temp = E1000_READ_REG(hw, PTC255);
     temp = E1000_READ_REG(hw, PTC511);
     temp = E1000_READ_REG(hw, PTC1023);
     temp = E1000_READ_REG(hw, PTC1522);
+    }
+
     temp = E1000_READ_REG(hw, MPTC);
     temp = E1000_READ_REG(hw, BPTC);
 
@@ -5959,6 +6359,9 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw
 
     temp = E1000_READ_REG(hw, IAC);
     temp = E1000_READ_REG(hw, ICRXOC);
+
+    if (hw->mac_type == e1000_ich8lan) return;
+
     temp = E1000_READ_REG(hw, ICRXPTC);
     temp = E1000_READ_REG(hw, ICRXATC);
     temp = E1000_READ_REG(hw, ICTXPTC);
@@ -6139,6 +6542,7 @@ e1000_get_bus_info(struct e1000_hw *hw)
         hw->bus_width = e1000_bus_width_pciex_1;
         break;
     case e1000_82571:
+    case e1000_ich8lan:
     case e1000_80003es2lan:
         hw->bus_type = e1000_bus_type_pci_express;
         hw->bus_speed = e1000_bus_speed_2500;
@@ -6176,8 +6580,6 @@ e1000_get_bus_info(struct e1000_hw *hw)
         break;
     }
 }
-
-#if 0
 /******************************************************************************
  * Reads a value from one of the devices registers using port I/O (as opposed
  * memory mapped I/O). Only 82544 and newer devices support port I/O.
@@ -6195,7 +6597,6 @@ e1000_read_reg_io(struct e1000_hw *hw,
     e1000_io_write(hw, io_addr, offset);
     return e1000_io_read(hw, io_data);
 }
-#endif  /*  0  */
 
 /******************************************************************************
  * Writes a value to one of the devices registers using port I/O (as opposed to
@@ -6240,8 +6641,6 @@ e1000_get_cable_length(struct e1000_hw *
 {
     int32_t ret_val;
     uint16_t agc_value = 0;
-    uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
-    uint16_t max_agc = 0;
     uint16_t i, phy_data;
     uint16_t cable_length;
 
@@ -6314,6 +6713,8 @@ e1000_get_cable_length(struct e1000_hw *
             break;
         }
     } else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */
+        uint16_t cur_agc_value;
+        uint16_t min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
         uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
                                                          {IGP01E1000_PHY_AGC_A,
                                                           IGP01E1000_PHY_AGC_B,
@@ -6326,23 +6727,23 @@ e1000_get_cable_length(struct e1000_hw *
             if(ret_val)
                 return ret_val;
 
-            cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
+            cur_agc_value = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
 
-            /* Array bound check. */
-            if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
-               (cur_agc == 0))
+            /* Value bound check. */
+            if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
+                (cur_agc_value == 0))
                 return -E1000_ERR_PHY;
 
-            agc_value += cur_agc;
+            agc_value += cur_agc_value;
 
             /* Update minimal AGC value. */
-            if(min_agc > cur_agc)
-                min_agc = cur_agc;
+            if (min_agc_value > cur_agc_value)
+                min_agc_value = cur_agc_value;
         }
 
         /* Remove the minimal AGC result for length < 50m */
-        if(agc_value < IGP01E1000_PHY_CHANNEL_NUM * e1000_igp_cable_length_50) {
-            agc_value -= min_agc;
+        if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * e1000_igp_cable_length_50) {
+            agc_value -= min_agc_value;
 
             /* Get the average length of the remaining 3 channels */
             agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
@@ -6358,7 +6759,10 @@ e1000_get_cable_length(struct e1000_hw *
                        IGP01E1000_AGC_RANGE) : 0;
         *max_length = e1000_igp_cable_length_table[agc_value] +
                       IGP01E1000_AGC_RANGE;
-    } else if (hw->phy_type == e1000_phy_igp_2) {
+    } else if (hw->phy_type == e1000_phy_igp_2 ||
+               hw->phy_type == e1000_phy_igp_3) {
+        uint16_t cur_agc_index, max_agc_index = 0;
+        uint16_t min_agc_index = IGP02E1000_AGC_LENGTH_TABLE_SIZE - 1;
         uint16_t agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
                                                          {IGP02E1000_PHY_AGC_A,
                                                           IGP02E1000_PHY_AGC_B,
@@ -6373,19 +6777,27 @@ e1000_get_cable_length(struct e1000_hw *
 	    /* Getting bits 15:9, which represent the combination of course and
              * fine gain values.  The result is a number that can be put into
              * the lookup table to obtain the approximate cable length. */
-            cur_agc = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
-                      IGP02E1000_AGC_LENGTH_MASK;
+            cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+                            IGP02E1000_AGC_LENGTH_MASK;
+
+            /* Array index bound check. */
+            if ((cur_agc_index >= IGP02E1000_AGC_LENGTH_TABLE_SIZE) ||
+                (cur_agc_index == 0))
+                return -E1000_ERR_PHY;
 
             /* Remove min & max AGC values from calculation. */
-            if (e1000_igp_2_cable_length_table[min_agc] > e1000_igp_2_cable_length_table[cur_agc])
-                min_agc = cur_agc;
-	    if (e1000_igp_2_cable_length_table[max_agc] < e1000_igp_2_cable_length_table[cur_agc])
-                max_agc = cur_agc;
+            if (e1000_igp_2_cable_length_table[min_agc_index] >
+                e1000_igp_2_cable_length_table[cur_agc_index])
+                min_agc_index = cur_agc_index;
+            if (e1000_igp_2_cable_length_table[max_agc_index] <
+                e1000_igp_2_cable_length_table[cur_agc_index])
+                max_agc_index = cur_agc_index;
 
-            agc_value += e1000_igp_2_cable_length_table[cur_agc];
+            agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
         }
 
-        agc_value -= (e1000_igp_2_cable_length_table[min_agc] + e1000_igp_2_cable_length_table[max_agc]);
+        agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+                      e1000_igp_2_cable_length_table[max_agc_index]);
         agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
 
         /* Calculate cable length with the error range of +/- 10 meters. */
@@ -6431,7 +6843,8 @@ e1000_check_polarity(struct e1000_hw *hw
             return ret_val;
         *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
                     M88E1000_PSSR_REV_POLARITY_SHIFT;
-    } else if(hw->phy_type == e1000_phy_igp ||
+    } else if (hw->phy_type == e1000_phy_igp ||
+              hw->phy_type == e1000_phy_igp_3 ||
               hw->phy_type == e1000_phy_igp_2) {
         /* Read the Status register to check the speed */
         ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
@@ -6457,6 +6870,13 @@ e1000_check_polarity(struct e1000_hw *hw
              * 100 Mbps this bit is always 0) */
             *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED;
         }
+    } else if (hw->phy_type == e1000_phy_ife) {
+        ret_val = e1000_read_phy_reg(hw, IFE_PHY_EXTENDED_STATUS_CONTROL,
+                                     &phy_data);
+        if (ret_val)
+            return ret_val;
+        *polarity = (phy_data & IFE_PESC_POLARITY_REVERSED) >>
+                           IFE_PESC_POLARITY_REVERSED_SHIFT;
     }
     return E1000_SUCCESS;
 }
@@ -6484,7 +6904,8 @@ e1000_check_downshift(struct e1000_hw *h
 
     DEBUGFUNC("e1000_check_downshift");
 
-    if(hw->phy_type == e1000_phy_igp ||
+    if (hw->phy_type == e1000_phy_igp ||
+        hw->phy_type == e1000_phy_igp_3 ||
         hw->phy_type == e1000_phy_igp_2) {
         ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
                                      &phy_data);
@@ -6501,6 +6922,9 @@ e1000_check_downshift(struct e1000_hw *h
 
         hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
                                M88E1000_PSSR_DOWNSHIFT_SHIFT;
+    } else if (hw->phy_type == e1000_phy_ife) {
+        /* e1000_phy_ife supports 10/100 speed only */
+        hw->speed_downgraded = FALSE;
     }
 
     return E1000_SUCCESS;
@@ -6545,7 +6969,9 @@ e1000_config_dsp_after_link_change(struc
 
         if(speed == SPEED_1000) {
 
-            e1000_get_cable_length(hw, &min_length, &max_length);
+            ret_val = e1000_get_cable_length(hw, &min_length, &max_length);
+            if (ret_val)
+                return ret_val;
 
             if((hw->dsp_config_state == e1000_dsp_config_enabled) &&
                 min_length >= e1000_igp_cable_length_50) {
@@ -6753,20 +7179,27 @@ static int32_t
 e1000_set_d3_lplu_state(struct e1000_hw *hw,
                         boolean_t active)
 {
+    uint32_t phy_ctrl = 0;
     int32_t ret_val;
     uint16_t phy_data;
     DEBUGFUNC("e1000_set_d3_lplu_state");
 
-    if(hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2)
+    if (hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2
+        && hw->phy_type != e1000_phy_igp_3)
         return E1000_SUCCESS;
 
     /* During driver activity LPLU should not be used or it will attain link
      * from the lowest speeds starting from 10Mbps. The capability is used for
      * Dx transitions and states */
-    if(hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) {
+    if (hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) {
         ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data);
-        if(ret_val)
+        if (ret_val)
             return ret_val;
+    } else if (hw->mac_type == e1000_ich8lan) {
+        /* MAC writes into PHY register based on the state transition
+         * and start auto-negotiation. SW driver can overwrite the settings
+         * in CSR PHY power control E1000_PHY_CTRL register. */
+        phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
     } else {
         ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
         if(ret_val)
@@ -6781,11 +7214,16 @@ e1000_set_d3_lplu_state(struct e1000_hw 
             if(ret_val)
                 return ret_val;
         } else {
+            if (hw->mac_type == e1000_ich8lan) {
+                phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+                E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+            } else {
                 phy_data &= ~IGP02E1000_PM_D3_LPLU;
                 ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
                                               phy_data);
                 if (ret_val)
                     return ret_val;
+            }
         }
 
         /* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
@@ -6821,17 +7259,22 @@ e1000_set_d3_lplu_state(struct e1000_hw 
               (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
 
         if(hw->mac_type == e1000_82541_rev_2 ||
-           hw->mac_type == e1000_82547_rev_2) {
+            hw->mac_type == e1000_82547_rev_2) {
             phy_data |= IGP01E1000_GMII_FLEX_SPD;
             ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
             if(ret_val)
                 return ret_val;
         } else {
+            if (hw->mac_type == e1000_ich8lan) {
+                phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+                E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+            } else {
                 phy_data |= IGP02E1000_PM_D3_LPLU;
                 ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
                                               phy_data);
                 if (ret_val)
                     return ret_val;
+            }
         }
 
         /* When LPLU is enabled we should disable SmartSpeed */
@@ -6866,6 +7309,7 @@ static int32_t
 e1000_set_d0_lplu_state(struct e1000_hw *hw,
                         boolean_t active)
 {
+    uint32_t phy_ctrl = 0;
     int32_t ret_val;
     uint16_t phy_data;
     DEBUGFUNC("e1000_set_d0_lplu_state");
@@ -6873,15 +7317,24 @@ e1000_set_d0_lplu_state(struct e1000_hw 
     if(hw->mac_type <= e1000_82547_rev_2)
         return E1000_SUCCESS;
 
+    if (hw->mac_type == e1000_ich8lan) {
+        phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
+    } else {
         ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
         if(ret_val)
             return ret_val;
+    }
 
     if (!active) {
+        if (hw->mac_type == e1000_ich8lan) {
+            phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+            E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+        } else {
             phy_data &= ~IGP02E1000_PM_D0_LPLU;
             ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
             if (ret_val)
                 return ret_val;
+        }
 
         /* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
          * Dx states where the power conservation is most important.  During
@@ -6914,10 +7367,15 @@ e1000_set_d0_lplu_state(struct e1000_hw 
 
     } else {
 
+        if (hw->mac_type == e1000_ich8lan) {
+            phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+            E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+        } else {
             phy_data |= IGP02E1000_PM_D0_LPLU;
             ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
             if (ret_val)
                 return ret_val;
+        }
 
         /* When LPLU is enabled we should disable SmartSpeed */
         ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
@@ -7191,15 +7649,18 @@ e1000_mng_write_commit(
  * returns  - TRUE when the mode is IAMT or FALSE.
  ****************************************************************************/
 boolean_t
-e1000_check_mng_mode(
-    struct e1000_hw *hw)
+e1000_check_mng_mode(struct e1000_hw *hw)
 {
     uint32_t fwsm;
 
     fwsm = E1000_READ_REG(hw, FWSM);
 
-    if((fwsm & E1000_FWSM_MODE_MASK) ==
-        (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+    if (hw->mac_type == e1000_ich8lan) {
+        if ((fwsm & E1000_FWSM_MODE_MASK) ==
+            (E1000_MNG_ICH_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+            return TRUE;
+    } else if ((fwsm & E1000_FWSM_MODE_MASK) ==
+               (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
         return TRUE;
 
     return FALSE;
@@ -7439,7 +7900,6 @@ e1000_set_pci_express_master_disable(str
     E1000_WRITE_REG(hw, CTRL, ctrl);
 }
 
-#if 0
 /***************************************************************************
  *
  * Enables PCI-Express master access.
@@ -7463,7 +7923,6 @@ e1000_enable_pciex_master(struct e1000_h
     ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
     E1000_WRITE_REG(hw, CTRL, ctrl);
 }
-#endif  /*  0  */
 
 /*******************************************************************************
  *
@@ -7529,8 +7988,10 @@ e1000_get_auto_rd_done(struct e1000_hw *
     case e1000_82572:
     case e1000_82573:
     case e1000_80003es2lan:
-        while(timeout) {
-            if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break;
+    case e1000_ich8lan:
+        while (timeout) {
+            if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD)
+                break;
             else msec_delay(1);
             timeout--;
         }
@@ -7570,7 +8031,7 @@ e1000_get_phy_cfg_done(struct e1000_hw *
 
     switch (hw->mac_type) {
     default:
-        msec_delay(10);
+        msec_delay_irq(10);
         break;
     case e1000_80003es2lan:
         /* Separate *_CFG_DONE_* bit for each port */
@@ -7753,6 +8214,13 @@ int32_t
 e1000_check_phy_reset_block(struct e1000_hw *hw)
 {
     uint32_t manc = 0;
+    uint32_t fwsm = 0;
+
+    if (hw->mac_type == e1000_ich8lan) {
+        fwsm = E1000_READ_REG(hw, FWSM);
+        return (fwsm & E1000_FWSM_RSPCIPHY) ? E1000_SUCCESS
+                                            : E1000_BLK_PHY_RESET;
+    }
 
     if (hw->mac_type > e1000_82547_rev_2)
         manc = E1000_READ_REG(hw, MANC);
@@ -7779,6 +8247,8 @@ e1000_arc_subsystem_valid(struct e1000_h
         if((fwsm & E1000_FWSM_MODE_MASK) != 0)
             return TRUE;
         break;
+    case e1000_ich8lan:
+        return TRUE;
     default:
         break;
     }
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index f5689fa..95f4435 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -366,6 +366,7 @@ e1000_release_hw_control(struct e1000_ad
 {
 	uint32_t ctrl_ext;
 	uint32_t swsm;
+	uint32_t extcnf;
 
 	/* Let firmware taken over control of h/w */
 	switch (adapter->hw.mac_type) {
@@ -380,6 +381,11 @@ e1000_release_hw_control(struct e1000_ad
 		swsm = E1000_READ_REG(&adapter->hw, SWSM);
 		E1000_WRITE_REG(&adapter->hw, SWSM,
 				swsm & ~E1000_SWSM_DRV_LOAD);
+	case e1000_ich8lan:
+		extcnf = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+		E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+				extcnf & ~E1000_CTRL_EXT_DRV_LOAD);
+		break;
 	default:
 		break;
 	}
@@ -401,6 +407,7 @@ e1000_get_hw_control(struct e1000_adapte
 {
 	uint32_t ctrl_ext;
 	uint32_t swsm;
+	uint32_t extcnf;
 	/* Let firmware know the driver has taken over */
 	switch (adapter->hw.mac_type) {
 	case e1000_82571:
@@ -415,6 +422,11 @@ e1000_get_hw_control(struct e1000_adapte
 		E1000_WRITE_REG(&adapter->hw, SWSM,
 				swsm | E1000_SWSM_DRV_LOAD);
 		break;
+	case e1000_ich8lan:
+		extcnf = E1000_READ_REG(&adapter->hw, EXTCNF_CTRL);
+		E1000_WRITE_REG(&adapter->hw, EXTCNF_CTRL,
+				extcnf | E1000_EXTCNF_CTRL_SWFLAG);
+		break;
 	default:
 		break;
 	}
@@ -490,6 +502,7 @@ static void e1000_power_down_phy(struct 
 	 * (b) AMT is active
 	 * (c) SoL/IDER session is active */
 	if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
+	    adapter->hw.mac_type != e1000_ich8lan &&
 	    adapter->hw.media_type == e1000_media_type_copper &&
 	    !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) &&
 	    !mng_mode_enabled &&
@@ -561,6 +574,9 @@ e1000_reset(struct e1000_adapter *adapte
 	case e1000_82573:
 		pba = E1000_PBA_12K;
 		break;
+	case e1000_ich8lan:
+		pba = E1000_PBA_8K;
+		break;
 	default:
 		pba = E1000_PBA_48K;
 		break;
@@ -585,6 +601,12 @@ e1000_reset(struct e1000_adapter *adapte
 	/* Set the FC high water mark to 90% of the FIFO size.
 	 * Required to clear last 3 LSB */
 	fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8;
+	/* We can't use 90% on small FIFOs because the remainder
+	 * would be less than 1 full frame.  In this case, we size
+	 * it to allow at least a full frame above the high water
+	 *  mark. */
+	if (pba < E1000_PBA_16K)
+		fc_high_water_mark = (pba * 1024) - 1600;
 
 	adapter->hw.fc_high_water = fc_high_water_mark;
 	adapter->hw.fc_low_water = fc_high_water_mark - 8;
@@ -622,6 +644,8 @@ e1000_reset(struct e1000_adapter *adapte
 		                    phy_data);
 	}
 
+	if (adapter->hw.mac_type < e1000_ich8lan)
+	/* FIXME: this code is duplicate and wrong for PCI Express */
 	if (adapter->en_mng_pt) {
 		manc = E1000_READ_REG(&adapter->hw, MANC);
 		manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST);
@@ -648,6 +672,7 @@ e1000_probe(struct pci_dev *pdev,
 	struct net_device *netdev;
 	struct e1000_adapter *adapter;
 	unsigned long mmio_start, mmio_len;
+	unsigned long flash_start, flash_len;
 
 	static int cards_found = 0;
 	static int e1000_ksp3_port_a = 0; /* global ksp3 port a indication */
@@ -657,10 +682,12 @@ e1000_probe(struct pci_dev *pdev,
 	if ((err = pci_enable_device(pdev)))
 		return err;
 
-	if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
+	if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) &&
+	    !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) {
 		pci_using_dac = 1;
 	} else {
-		if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
+		if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) &&
+		    (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) {
 			E1000_ERR("No usable DMA configuration, aborting\n");
 			return err;
 		}
@@ -740,6 +767,19 @@ e1000_probe(struct pci_dev *pdev,
 	if ((err = e1000_sw_init(adapter)))
 		goto err_sw_init;
 
+	/* Flash BAR mapping must happen after e1000_sw_init
+	 * because it depends on mac_type */
+	if ((adapter->hw.mac_type == e1000_ich8lan) &&
+	   (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
+		flash_start = pci_resource_start(pdev, 1);
+		flash_len = pci_resource_len(pdev, 1);
+		adapter->hw.flash_address = ioremap(flash_start, flash_len);
+		if (!adapter->hw.flash_address) {
+			err = -EIO;
+			goto err_flashmap;
+		}
+	}
+
 	if ((err = e1000_check_phy_reset_block(&adapter->hw)))
 		DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n");
 
@@ -758,6 +798,8 @@ e1000_probe(struct pci_dev *pdev,
 				   NETIF_F_HW_VLAN_TX |
 				   NETIF_F_HW_VLAN_RX |
 				   NETIF_F_HW_VLAN_FILTER;
+		if (adapter->hw.mac_type == e1000_ich8lan)
+			netdev->features &= ~NETIF_F_HW_VLAN_FILTER;
 	}
 
 #ifdef NETIF_F_TSO
@@ -773,11 +815,17 @@ e1000_probe(struct pci_dev *pdev,
 	if (pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
-	/* hard_start_xmit is safe against parallel locking */
 	netdev->features |= NETIF_F_LLTX;
 
 	adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw);
 
+	/* initialize eeprom parameters */
+
+	if (e1000_init_eeprom_params(&adapter->hw)) {
+		E1000_ERR("EEPROM initialization failed\n");
+		return -EIO;
+	}
+
 	/* before reading the EEPROM, reset the controller to
 	 * put the device in a known good starting state */
 
@@ -845,6 +893,11 @@ e1000_probe(struct pci_dev *pdev,
 			EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data);
 		eeprom_apme_mask = E1000_EEPROM_82544_APM;
 		break;
+	case e1000_ich8lan:
+		e1000_read_eeprom(&adapter->hw,
+			EEPROM_INIT_CONTROL1_REG, 1, &eeprom_data);
+		eeprom_apme_mask = E1000_EEPROM_ICH8_APME;
+		break;
 	case e1000_82546:
 	case e1000_82546_rev_3:
 	case e1000_82571:
@@ -904,6 +957,9 @@ e1000_probe(struct pci_dev *pdev,
 	return 0;
 
 err_register:
+	if (adapter->hw.flash_address)
+		iounmap(adapter->hw.flash_address);
+err_flashmap:
 err_sw_init:
 err_eeprom:
 	iounmap(adapter->hw.hw_addr);
@@ -937,6 +993,7 @@ e1000_remove(struct pci_dev *pdev)
 	flush_scheduled_work();
 
 	if (adapter->hw.mac_type >= e1000_82540 &&
+	   adapter->hw.mac_type != e1000_ich8lan &&
 	   adapter->hw.media_type == e1000_media_type_copper) {
 		manc = E1000_READ_REG(&adapter->hw, MANC);
 		if (manc & E1000_MANC_SMBUS_EN) {
@@ -965,6 +1022,8 @@ e1000_remove(struct pci_dev *pdev)
 #endif
 
 	iounmap(adapter->hw.hw_addr);
+	if (adapter->hw.flash_address)
+		iounmap(adapter->hw.flash_address);
 	pci_release_regions(pdev);
 
 	free_netdev(netdev);
@@ -1015,13 +1074,6 @@ e1000_sw_init(struct e1000_adapter *adap
 		return -EIO;
 	}
 
-	/* initialize eeprom parameters */
-
-	if (e1000_init_eeprom_params(hw)) {
-		E1000_ERR("EEPROM initialization failed\n");
-		return -EIO;
-	}
-
 	switch (hw->mac_type) {
 	default:
 		break;
@@ -1257,8 +1309,7 @@ e1000_setup_tx_resources(struct e1000_ad
 	int size;
 
 	size = sizeof(struct e1000_buffer) * txdr->count;
-
-	txdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus));
+	txdr->buffer_info = vmalloc(size);
 	if (!txdr->buffer_info) {
 		DPRINTK(PROBE, ERR,
 		"Unable to allocate memory for the transmit descriptor ring\n");
@@ -1486,7 +1537,7 @@ e1000_setup_rx_resources(struct e1000_ad
 	int size, desc_len;
 
 	size = sizeof(struct e1000_buffer) * rxdr->count;
-	rxdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus));
+	rxdr->buffer_info = vmalloc(size);
 	if (!rxdr->buffer_info) {
 		DPRINTK(PROBE, ERR,
 		"Unable to allocate memory for the receive descriptor ring\n");
@@ -2153,6 +2204,12 @@ e1000_set_multi(struct net_device *netde
 	uint32_t rctl;
 	uint32_t hash_value;
 	int i, rar_entries = E1000_RAR_ENTRIES;
+	int mta_reg_count = (hw->mac_type == e1000_ich8lan) ?
+				E1000_NUM_MTA_REGISTERS_ICH8LAN :
+				E1000_NUM_MTA_REGISTERS;
+
+	if (adapter->hw.mac_type == e1000_ich8lan)
+		rar_entries = E1000_RAR_ENTRIES_ICH8LAN;
 
 	/* reserve RAR[14] for LAA over-write work-around */
 	if (adapter->hw.mac_type == e1000_82571)
@@ -2199,7 +2256,7 @@ e1000_set_multi(struct net_device *netde
 
 	/* clear the old settings from the multicast hash table */
 
-	for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
+	for (i = 0; i < mta_reg_count; i++) {
 		E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
 		E1000_WRITE_FLUSH(hw);
 	}
@@ -2278,8 +2335,16 @@ e1000_watchdog(unsigned long data)
 	struct net_device *netdev = adapter->netdev;
 	struct e1000_tx_ring *txdr = adapter->tx_ring;
 	uint32_t link, tctl;
+	int32_t ret_val;
 
-	e1000_check_for_link(&adapter->hw);
+	ret_val = e1000_check_for_link(&adapter->hw);
+	if ((ret_val == E1000_ERR_PHY) &&
+	    (adapter->hw.phy_type == e1000_phy_igp_3) &&
+	    (E1000_READ_REG(&adapter->hw, CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) {
+		/* See e1000_kumeran_lock_loss_workaround() */
+		DPRINTK(LINK, INFO,
+			"Gigabit has been disabled, downgrading speed\n");
+	}
 	if (adapter->hw.mac_type == e1000_82573) {
 		e1000_enable_tx_pkt_filtering(&adapter->hw);
 		if (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id)
@@ -2845,6 +2910,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
 			case e1000_82571:
 			case e1000_82572:
 			case e1000_82573:
+			case e1000_ich8lan:
 				pull_size = min((unsigned int)4, skb->data_len);
 				if (!__pskb_pull_tail(skb, pull_size)) {
 					DPRINTK(DRV, ERR,
@@ -3029,6 +3095,7 @@ e1000_change_mtu(struct net_device *netd
 	/* Adapter-specific max frame size limits. */
 	switch (adapter->hw.mac_type) {
 	case e1000_undefined ... e1000_82542_rev2_1:
+	case e1000_ich8lan:
 		if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
 			DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n");
 			return -EINVAL;
@@ -3137,12 +3204,15 @@ e1000_update_stats(struct e1000_adapter 
 	adapter->stats.bprc += E1000_READ_REG(hw, BPRC);
 	adapter->stats.mprc += E1000_READ_REG(hw, MPRC);
 	adapter->stats.roc += E1000_READ_REG(hw, ROC);
+
+	if (adapter->hw.mac_type != e1000_ich8lan) {
 	adapter->stats.prc64 += E1000_READ_REG(hw, PRC64);
 	adapter->stats.prc127 += E1000_READ_REG(hw, PRC127);
 	adapter->stats.prc255 += E1000_READ_REG(hw, PRC255);
 	adapter->stats.prc511 += E1000_READ_REG(hw, PRC511);
 	adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023);
 	adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522);
+	}
 
 	adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS);
 	adapter->stats.mpc += E1000_READ_REG(hw, MPC);
@@ -3170,12 +3240,16 @@ e1000_update_stats(struct e1000_adapter 
 	adapter->stats.totl += E1000_READ_REG(hw, TOTL);
 	adapter->stats.toth += E1000_READ_REG(hw, TOTH);
 	adapter->stats.tpr += E1000_READ_REG(hw, TPR);
+
+	if (adapter->hw.mac_type != e1000_ich8lan) {
 	adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64);
 	adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127);
 	adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255);
 	adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511);
 	adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023);
 	adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522);
+	}
+
 	adapter->stats.mptc += E1000_READ_REG(hw, MPTC);
 	adapter->stats.bptc += E1000_READ_REG(hw, BPTC);
 
@@ -3197,6 +3271,8 @@ e1000_update_stats(struct e1000_adapter 
 	if (hw->mac_type > e1000_82547_rev_2) {
 		adapter->stats.iac += E1000_READ_REG(hw, IAC);
 		adapter->stats.icrxoc += E1000_READ_REG(hw, ICRXOC);
+
+		if (adapter->hw.mac_type != e1000_ich8lan) {
 		adapter->stats.icrxptc += E1000_READ_REG(hw, ICRXPTC);
 		adapter->stats.icrxatc += E1000_READ_REG(hw, ICRXATC);
 		adapter->stats.ictxptc += E1000_READ_REG(hw, ICTXPTC);
@@ -3204,6 +3280,7 @@ e1000_update_stats(struct e1000_adapter 
 		adapter->stats.ictxqec += E1000_READ_REG(hw, ICTXQEC);
 		adapter->stats.ictxqmtc += E1000_READ_REG(hw, ICTXQMTC);
 		adapter->stats.icrxdmtc += E1000_READ_REG(hw, ICRXDMTC);
+		}
 	}
 
 	/* Fill out the OS statistics structure */
@@ -4338,18 +4415,21 @@ e1000_vlan_rx_register(struct net_device
 		ctrl |= E1000_CTRL_VME;
 		E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
 
+		if (adapter->hw.mac_type != e1000_ich8lan) {
 		/* enable VLAN receive filtering */
 		rctl = E1000_READ_REG(&adapter->hw, RCTL);
 		rctl |= E1000_RCTL_VFE;
 		rctl &= ~E1000_RCTL_CFIEN;
 		E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
 		e1000_update_mng_vlan(adapter);
+		}
 	} else {
 		/* disable VLAN tag insert/strip */
 		ctrl = E1000_READ_REG(&adapter->hw, CTRL);
 		ctrl &= ~E1000_CTRL_VME;
 		E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
 
+		if (adapter->hw.mac_type != e1000_ich8lan) {
 		/* disable VLAN filtering */
 		rctl = E1000_READ_REG(&adapter->hw, RCTL);
 		rctl &= ~E1000_RCTL_VFE;
@@ -4358,6 +4438,7 @@ e1000_vlan_rx_register(struct net_device
 			e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
 			adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
 		}
+		}
 	}
 
 	e1000_irq_enable(adapter);
@@ -4586,7 +4667,9 @@ e1000_suspend(struct pci_dev *pdev, pm_m
 		pci_enable_wake(pdev, PCI_D3cold, 0);
 	}
 
+	/* FIXME: this code is incorrect for PCI Express */
 	if (adapter->hw.mac_type >= e1000_82540 &&
+	   adapter->hw.mac_type != e1000_ich8lan &&
 	   adapter->hw.media_type == e1000_media_type_copper) {
 		manc = E1000_READ_REG(&adapter->hw, MANC);
 		if (manc & E1000_MANC_SMBUS_EN) {
@@ -4597,6 +4680,9 @@ e1000_suspend(struct pci_dev *pdev, pm_m
 		}
 	}
 
+	if (adapter->hw.phy_type == e1000_phy_igp_3)
+		e1000_phy_powerdown_workaround(&adapter->hw);
+
 	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
 	 * would have already happened in close and is redundant. */
 	e1000_release_hw_control(adapter);
@@ -4632,7 +4718,9 @@ e1000_resume(struct pci_dev *pdev)
 
 	netif_device_attach(netdev);
 
+	/* FIXME: this code is incorrect for PCI Express */
 	if (adapter->hw.mac_type >= e1000_82540 &&
+	   adapter->hw.mac_type != e1000_ich8lan &&
 	   adapter->hw.media_type == e1000_media_type_copper) {
 		manc = E1000_READ_REG(&adapter->hw, MANC);
 		manc &= ~(E1000_MANC_ARP_EN);



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 19/21] e1000: allow user to disable ich8 lock loss workaround
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (17 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 18/21] e1000: integrate ich8 support into driver Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-27  1:55   ` Jeff Garzik
  2006-06-22  5:20 ` [PATCH 20/21] e1000: add ich8lan device ID's Kok, Auke
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


The workaround for the ich8 lock loss problem is only needed for
a very small amount of systems. This adds an option for the user
to disable the workaround.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_param.c |   21 +++++++++++++++++++++
 1 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index bd6c040..0ef4131 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -202,6 +202,15 @@ E1000_PARAM(InterruptThrottleRate, "Inte
 
 E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
 
+/* Enable Kumeran Lock Loss workaround
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 1 (enabled)
+ */
+
+E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
+
 #define AUTONEG_ADV_DEFAULT  0x2F
 #define AUTONEG_ADV_MASK     0x2F
 #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
@@ -484,6 +493,18 @@ e1000_check_options(struct e1000_adapter
 		e1000_validate_option(&spd, &opt, adapter);
 		adapter->smart_power_down = spd;
 	}
+	{ /* Kumeran Lock Loss Workaround */
+		struct e1000_option opt = {
+			.type = enable_option,
+			.name = "Kumeran Lock Loss Workaround",
+			.err  = "defaulting to Enabled",
+			.def  = OPTION_ENABLED
+		};
+
+			int kmrn_lock_loss = KumeranLockLoss[bd];
+			e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
+			adapter->hw.kmrn_lock_loss_workaround_disabled = !kmrn_lock_loss;
+	}
 
 	switch (adapter->hw.media_type) {
 	case e1000_media_type_fiber:



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 20/21] e1000: add ich8lan device ID's
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (18 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 19/21] e1000: allow user to disable ich8 lock loss workaround Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-22  5:20 ` [PATCH 21/21] e1000: increase version to 7.1.9-k2 Kok, Auke
  2006-06-27 22:48 ` [PATCH 00/21] e1000: driver update " Auke Kok
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


Add the device ID's of the supported ICH8 LAN devices.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_main.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 95f4435..4fdc564 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -73,6 +73,11 @@ static struct pci_device_id e1000_pci_tb
 	INTEL_E1000_ETHERNET_DEVICE(0x1026),
 	INTEL_E1000_ETHERNET_DEVICE(0x1027),
 	INTEL_E1000_ETHERNET_DEVICE(0x1028),
+	INTEL_E1000_ETHERNET_DEVICE(0x1049),
+	INTEL_E1000_ETHERNET_DEVICE(0x104A),
+	INTEL_E1000_ETHERNET_DEVICE(0x104B),
+	INTEL_E1000_ETHERNET_DEVICE(0x104C),
+	INTEL_E1000_ETHERNET_DEVICE(0x104D),
 	INTEL_E1000_ETHERNET_DEVICE(0x105E),
 	INTEL_E1000_ETHERNET_DEVICE(0x105F),
 	INTEL_E1000_ETHERNET_DEVICE(0x1060),
@@ -96,6 +101,8 @@ static struct pci_device_id e1000_pci_tb
 	INTEL_E1000_ETHERNET_DEVICE(0x109A),
 	INTEL_E1000_ETHERNET_DEVICE(0x10B5),
 	INTEL_E1000_ETHERNET_DEVICE(0x10B9),
+	INTEL_E1000_ETHERNET_DEVICE(0x10BA),
+	INTEL_E1000_ETHERNET_DEVICE(0x10BB),
 	/* required last entry */
 	{0,}
 };



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 21/21] e1000: increase version to 7.1.9-k2
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (19 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 20/21] e1000: add ich8lan device ID's Kok, Auke
@ 2006-06-22  5:20 ` Kok, Auke
  2006-06-27 22:48 ` [PATCH 00/21] e1000: driver update " Auke Kok
  21 siblings, 0 replies; 47+ messages in thread
From: Kok, Auke @ 2006-06-22  5:20 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: netdev, Brandeburg, Jesse, Kok, Auke, Kok, Auke, Ronciak, John


Increment the version to 7.1.9-k2

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000/e1000_main.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 4fdc564..f238700 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -36,7 +36,7 @@ static char e1000_driver_string[] = "Int
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-#define DRV_VERSION "7.0.38-k4"DRIVERNAPI
+#define DRV_VERSION "7.1.9-k2"DRIVERNAPI
 char e1000_driver_version[] = DRV_VERSION;
 static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
 



--
Auke Kok <auke-jan.h.kok@intel.com>

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/21] e1000: disable CRC stripping workaround
  2006-06-22  5:20 ` [PATCH 11/21] e1000: disable CRC stripping workaround Kok, Auke
@ 2006-06-22  5:31   ` Ben Greear
  2006-06-22 15:36     ` Auke Kok
  2006-06-22 15:39     ` Jesse Brandeburg
  2006-06-27  1:48   ` Jeff Garzik
  1 sibling, 2 replies; 47+ messages in thread
From: Ben Greear @ 2006-06-22  5:31 UTC (permalink / raw)
  To: Kok, Auke
  Cc: Garzik, Jeff, netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Kok, Auke wrote:
> CRC stripping is breaking SMBUS-connected BMC's. We disable this
> feature to make it work. This fixes related bugs regarding SOL.

Shouldn't you also have to subtract 4 bytes when setting the skb len
in the receive logic?  Perhaps when setting the rx-bytes counter as well?

Ben


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/21] e1000: disable CRC stripping workaround
  2006-06-22  5:31   ` Ben Greear
@ 2006-06-22 15:36     ` Auke Kok
  2006-06-22 15:39     ` Jesse Brandeburg
  1 sibling, 0 replies; 47+ messages in thread
From: Auke Kok @ 2006-06-22 15:36 UTC (permalink / raw)
  To: Ben Greear
  Cc: Garzik, Jeff, netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Ben Greear wrote:
> Kok, Auke wrote:
>> CRC stripping is breaking SMBUS-connected BMC's. We disable this
>> feature to make it work. This fixes related bugs regarding SOL.
> 
> Shouldn't you also have to subtract 4 bytes when setting the skb len
> in the receive logic?  Perhaps when setting the rx-bytes counter as well?

the hardware corrects for the size properly when we disable CRC stripping. The 
end result is the same.

Cheers,

Auke

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/21] e1000: disable CRC stripping workaround
  2006-06-22  5:31   ` Ben Greear
  2006-06-22 15:36     ` Auke Kok
@ 2006-06-22 15:39     ` Jesse Brandeburg
  2006-06-22 15:55       ` Ben Greear
  2006-06-22 15:57       ` Lennert Buytenhek
  1 sibling, 2 replies; 47+ messages in thread
From: Jesse Brandeburg @ 2006-06-22 15:39 UTC (permalink / raw)
  To: Ben Greear
  Cc: Kok, Auke, Garzik, Jeff, netdev, Brandeburg, Jesse, Kok, Auke,
	Ronciak, John

On 6/21/06, Ben Greear <greearb@candelatech.com> wrote:
> Kok, Auke wrote:
> > CRC stripping is breaking SMBUS-connected BMC's. We disable this
> > feature to make it work. This fixes related bugs regarding SOL.
>
> Shouldn't you also have to subtract 4 bytes when setting the skb len
> in the receive logic?  Perhaps when setting the rx-bytes counter as well?

we thought about this, but most drivers don't strip the CRC, and we
couldn't find any tests including bridging that cared if the CRC was
there in the indicated packet.

If you can find me a failing case I'll fix it.  It was much simpler to
leave it out, especially when we add back in the multiple descriptor
receive code in the future (think about the case when subtracting the
CRC makes the last descriptor disappear)

Once again, let me know if you have info I don't :-)

Thanks for the review,
  Jesse

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/21] e1000: disable CRC stripping workaround
  2006-06-22 15:39     ` Jesse Brandeburg
@ 2006-06-22 15:55       ` Ben Greear
  2006-06-22 16:01         ` Jesse Brandeburg
  2006-06-22 15:57       ` Lennert Buytenhek
  1 sibling, 1 reply; 47+ messages in thread
From: Ben Greear @ 2006-06-22 15:55 UTC (permalink / raw)
  To: Jesse Brandeburg
  Cc: Kok, Auke, Garzik, Jeff, netdev, Brandeburg, Jesse, Kok, Auke,
	Ronciak, John

Jesse Brandeburg wrote:
> On 6/21/06, Ben Greear <greearb@candelatech.com> wrote:
> 
>> Kok, Auke wrote:
>> > CRC stripping is breaking SMBUS-connected BMC's. We disable this
>> > feature to make it work. This fixes related bugs regarding SOL.
>>
>> Shouldn't you also have to subtract 4 bytes when setting the skb len
>> in the receive logic?  Perhaps when setting the rx-bytes counter as well?
> 
> 
> we thought about this, but most drivers don't strip the CRC, and we
> couldn't find any tests including bridging that cared if the CRC was
> there in the indicated packet.
> 
> If you can find me a failing case I'll fix it.  It was much simpler to
> leave it out, especially when we add back in the multiple descriptor
> receive code in the future (think about the case when subtracting the
> CRC makes the last descriptor disappear)
> 
> Once again, let me know if you have info I don't :-)

It should only be a problem if skb->len includes the extra 4 bytes for 
the crc.  Then, if I transmit that skb to another interface, I am afraid 
that the crc will be seen as data in the packet.  In the 2.6.13 days, 
the e1000 did not strip the CRC, but it subtracted 4 before it did the 
skb_put.  So, the crc was correctly stripped/ignored.  The e100 
functioned similarly I believe.

If you skb_put the extra 4 bytes, I believe this will break my 
(proprietary) app because on transmit it will append the extra 4 crc 
bytes, but that isn't your problem..and I can work around it.  If the 
receiving NIC can handle pkts 4 bytes bigger than normal, it will 
probably still receive the packet w/out problem, but in truth, the frame 
will not be exactly correct.

When you did your bridging tests, did you sniff the packets on the far 
side of the bridge to see if they were the right size?

Thanks,
Ben

> 
> Thanks for the review,
>  Jesse
> 


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/21] e1000: disable CRC stripping workaround
  2006-06-22 15:39     ` Jesse Brandeburg
  2006-06-22 15:55       ` Ben Greear
@ 2006-06-22 15:57       ` Lennert Buytenhek
  1 sibling, 0 replies; 47+ messages in thread
From: Lennert Buytenhek @ 2006-06-22 15:57 UTC (permalink / raw)
  To: Jesse Brandeburg
  Cc: Ben Greear, Kok, Auke, Garzik, Jeff, netdev, Brandeburg, Jesse,
	Kok, Auke, Ronciak, John

On Thu, Jun 22, 2006 at 08:39:10AM -0700, Jesse Brandeburg wrote:

> >> CRC stripping is breaking SMBUS-connected BMC's. We disable this
> >> feature to make it work. This fixes related bugs regarding SOL.
> >
> >Shouldn't you also have to subtract 4 bytes when setting the skb len
> >in the receive logic?  Perhaps when setting the rx-bytes counter as well?
> 
> we thought about this, but most drivers don't strip the CRC,

Really?


> and we couldn't find any tests including bridging that cared if the
> CRC was there in the indicated packet.

Bridging definitely cares -- some years ago there was a case where
8139too NICs would pass packets up the stack with 4 bytes of FCS, and
that causes frames received on 8139too interfaces not to be forwarded
to other interfaces because on TX, the frame would be too long.

Maybe e1000 is okay with sending oversized frames, but other NIC
drivers might not be.

(Did you test without bridge-netfilter enabled?  bridge-nf might trim
incoming IP packets even in the bridging case.)


cheers,
Lennert

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/21] e1000: disable CRC stripping workaround
  2006-06-22 15:55       ` Ben Greear
@ 2006-06-22 16:01         ` Jesse Brandeburg
  0 siblings, 0 replies; 47+ messages in thread
From: Jesse Brandeburg @ 2006-06-22 16:01 UTC (permalink / raw)
  To: Ben Greear
  Cc: Kok, Auke, Garzik, Jeff, netdev, Brandeburg, Jesse, Kok, Auke,
	Ronciak, John

On 6/22/06, Ben Greear <greearb@candelatech.com> wrote:
> Jesse Brandeburg wrote:
> > On 6/21/06, Ben Greear <greearb@candelatech.com> wrote:
> >
> >> Kok, Auke wrote:
> >> > CRC stripping is breaking SMBUS-connected BMC's. We disable this
> >> > feature to make it work. This fixes related bugs regarding SOL.
> >>
> >> Shouldn't you also have to subtract 4 bytes when setting the skb len
> >> in the receive logic?  Perhaps when setting the rx-bytes counter as well?
> >
> >
> > we thought about this, but most drivers don't strip the CRC, and we
> > couldn't find any tests including bridging that cared if the CRC was
> > there in the indicated packet.
> >
> > If you can find me a failing case I'll fix it.  It was much simpler to
> > leave it out, especially when we add back in the multiple descriptor
> > receive code in the future (think about the case when subtracting the
> > CRC makes the last descriptor disappear)
> >
> > Once again, let me know if you have info I don't :-)
>
> It should only be a problem if skb->len includes the extra 4 bytes for
> the crc.  Then, if I transmit that skb to another interface, I am afraid
> that the crc will be seen as data in the packet.  In the 2.6.13 days,
> the e1000 did not strip the CRC, but it subtracted 4 before it did the
> skb_put.  So, the crc was correctly stripped/ignored.  The e100
> functioned similarly I believe.

currently the e100 driver in 2.6.X strips the CRC in hardware.

> If you skb_put the extra 4 bytes, I believe this will break my
> (proprietary) app because on transmit it will append the extra 4 crc
> bytes, but that isn't your problem..and I can work around it.  If the
> receiving NIC can handle pkts 4 bytes bigger than normal, it will
> probably still receive the packet w/out problem, but in truth, the frame
> will not be exactly correct.
>
> When you did your bridging tests, did you sniff the packets on the far
> side of the bridge to see if they were the right size?

hm, probably not, we touch tested bridging (probably with TCP), and
have completed several internal testing passes, to make sure it worked
but I don't think we went so far as to   sniff the traffic at the
other end of the bridge.  I'll look into it.

Jesse

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 02/21] e1000: rework driver hardware reset locking
  2006-06-22  5:20 ` [PATCH 02/21] e1000: rework driver hardware reset locking Kok, Auke
@ 2006-06-27  1:42   ` Jeff Garzik
  2006-06-27 14:42     ` Auke Kok
  0 siblings, 1 reply; 47+ messages in thread
From: Jeff Garzik @ 2006-06-27  1:42 UTC (permalink / raw)
  To: Kok, Auke; +Cc: netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Kok, Auke wrote:
> @@ -631,6 +627,9 @@ e1000_set_ringparam(struct net_device *n
>  	tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
>  	rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
>  
> +	while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
> +		msleep(1);

This is a bit worrying, but no outright objection.  We don't want to see 
these accumulate.


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 06/21] e1000: add smart power down code
  2006-06-22  5:20 ` [PATCH 06/21] e1000: add smart power down code Kok, Auke
@ 2006-06-27  1:43   ` Jeff Garzik
  2006-06-27  8:49     ` Florian Reitmeir
  2006-06-27 14:40     ` Auke Kok
  0 siblings, 2 replies; 47+ messages in thread
From: Jeff Garzik @ 2006-06-27  1:43 UTC (permalink / raw)
  To: Kok, Auke; +Cc: netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Kok, Auke wrote:
> Smart Power Down is a power saving feature in newer e1000 hardware. We
> disable it because it causes time to link to be long, but make it a
> user choice.
> 
> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
> ---
> 
>  drivers/net/e1000/e1000.h       |    1 +
>  drivers/net/e1000/e1000_main.c  |   15 +++++++++++++++
>  drivers/net/e1000/e1000_param.c |   25 +++++++++++++++++++++++++
>  3 files changed, 41 insertions(+), 0 deletions(-)

Since it's not default, who will actually use this?  Particularly since 
it is only a module option, and not supported through ethtool (frown).

	Jeff




^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 10/21] e1000: force register write flushes to circumvent broken platforms
  2006-06-22  5:20 ` [PATCH 10/21] e1000: force register write flushes to circumvent broken platforms Kok, Auke
@ 2006-06-27  1:47   ` Jeff Garzik
  2006-06-27 14:36     ` Auke Kok
  0 siblings, 1 reply; 47+ messages in thread
From: Jeff Garzik @ 2006-06-27  1:47 UTC (permalink / raw)
  To: Kok, Auke; +Cc: netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Kok, Auke wrote:
> A certain AMD64 bridge (8132) has an option to turn on write combining
> which breaks our adapter. To circumvent this we need to flush every write.
> 
> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
> ---
> 
>  drivers/net/e1000/e1000_hw.c   |   24 ++++++++++++++++++++++--
>  drivers/net/e1000/e1000_main.c |   18 +++++++++++-------
>  2 files changed, 33 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
> index 3959039..749d621 100644
> --- a/drivers/net/e1000/e1000_hw.c
> +++ b/drivers/net/e1000/e1000_hw.c
> @@ -705,8 +705,12 @@ e1000_init_hw(struct e1000_hw *hw)
>      /* Zero out the Multicast HASH table */
>      DEBUGOUT("Zeroing the MTA\n");
>      mta_size = E1000_MC_TBL_SIZE;
> -    for(i = 0; i < mta_size; i++)
> +    for(i = 0; i < mta_size; i++) {
>          E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
> +        /* use write flush to prevent Memory Write Block (MWB) from
> +         * occuring when accessing our register space */
> +        E1000_WRITE_FLUSH(hw);
> +    }

NAK.  We can't crap up every driver just for one weird piece of hardware.

If this problem falls outside the grounds of mmiowb() [see 
Documentation/memory-barriers.txt], then other solutions need to be 
looked into... ioremap_nocache() ?  Tweaking the MTRR for this region? 
Chipset quirk?  ...

	Jeff




^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/21] e1000: disable CRC stripping workaround
  2006-06-22  5:20 ` [PATCH 11/21] e1000: disable CRC stripping workaround Kok, Auke
  2006-06-22  5:31   ` Ben Greear
@ 2006-06-27  1:48   ` Jeff Garzik
  2006-06-27 14:29     ` Auke Kok
  1 sibling, 1 reply; 47+ messages in thread
From: Jeff Garzik @ 2006-06-27  1:48 UTC (permalink / raw)
  To: Kok, Auke; +Cc: netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Kok, Auke wrote:
> CRC stripping is breaking SMBUS-connected BMC's. We disable this
> feature to make it work. This fixes related bugs regarding SOL.
> 
> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
> ---
> 
>  drivers/net/e1000/e1000_main.c |    7 ++++++-
>  1 files changed, 6 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
> index c44ed6f..7787299 100644
> --- a/drivers/net/e1000/e1000_main.c
> +++ b/drivers/net/e1000/e1000_main.c
> @@ -1628,8 +1628,11 @@ e1000_setup_rctl(struct e1000_adapter *a
>  		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
>  		(adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
>  
> +	/* disable hardware stripping of CRC because it breaks
> +	 * BMC firmware connected over SMBUS
>  	if (adapter->hw.mac_type > e1000_82543)
>  		rctl |= E1000_RCTL_SECRC;
> +	 */
>  
>  	if (adapter->hw.tbi_compatibility_on == 1)
>  		rctl |= E1000_RCTL_SBP;
> @@ -1696,7 +1699,9 @@ e1000_setup_rctl(struct e1000_adapter *a
>  		rfctl |= E1000_RFCTL_IPV6_DIS;
>  		E1000_WRITE_REG(&adapter->hw, RFCTL, rfctl);
>  
> -		rctl |= E1000_RCTL_DTYP_PS | E1000_RCTL_SECRC;
> +		/* disable the stripping of CRC because it breaks
> +		 * BMC firmware connected over SMBUS */
> +		rctl |= E1000_RCTL_DTYP_PS /* | E1000_RCTL_SECRC */;

This is quite ugly.  You are basically bloating the code with historic, 
dead code, no different than filling the e1000/*.c with '#if 0' regions.

Just delete it, and explain why in the patch description.

	Jeff




^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 13/21] e1000: add E1000_BIG_ENDIAN symbol
  2006-06-22  5:20 ` [PATCH 13/21] e1000: add E1000_BIG_ENDIAN symbol Kok, Auke
@ 2006-06-27  1:49   ` Jeff Garzik
  2006-06-27 14:25     ` Auke Kok
  0 siblings, 1 reply; 47+ messages in thread
From: Jeff Garzik @ 2006-06-27  1:49 UTC (permalink / raw)
  To: Kok, Auke; +Cc: netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Kok, Auke wrote:
> This adds a private symbol to signify endianess in our driver.
> 
> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
> ---
> 
>  drivers/net/e1000/e1000_hw.h    |    2 +-
>  drivers/net/e1000/e1000_osdep.h |    3 +++
>  2 files changed, 4 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
> index 941b47d..376a2ef 100644
> --- a/drivers/net/e1000/e1000_hw.h
> +++ b/drivers/net/e1000/e1000_hw.h
> @@ -351,7 +351,7 @@ struct e1000_host_mng_command_info {
>      struct e1000_host_mng_command_header command_header;  /* Command Head/Command Result Head has 4 bytes */
>      uint8_t command_data[E1000_HI_MAX_MNG_DATA_LENGTH];   /* Command data can length 0..0x658*/
>  };
> -#ifdef __BIG_ENDIAN
> +#ifdef E1000_BIG_ENDIAN
>  struct e1000_host_mng_dhcp_cookie{
>      uint32_t signature;
>      uint16_t vlan_id;
> diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
> index 048d052..6130a42 100644
> --- a/drivers/net/e1000/e1000_osdep.h
> +++ b/drivers/net/e1000/e1000_osdep.h
> @@ -83,6 +83,9 @@ typedef enum {
>  #define DEBUGOUT3 DEBUGOUT2
>  #define DEBUGOUT7 DEBUGOUT3
>  
> +#ifdef __BIG_ENDIAN
> +#define E1000_BIG_ENDIAN __BIG_ENDIAN
> +#endif

NAK.  This is backwards:  We don't need wrappers for symbols that the 
kernel already provides.

	Jeff



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 17/21] e1000: add ich8lan core functions
  2006-06-22  5:20 ` [PATCH 17/21] e1000: add ich8lan core functions Kok, Auke
@ 2006-06-27  1:52   ` Jeff Garzik
  2006-06-27 16:12     ` Auke Kok
  0 siblings, 1 reply; 47+ messages in thread
From: Jeff Garzik @ 2006-06-27  1:52 UTC (permalink / raw)
  To: Kok, Auke; +Cc: netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Kok, Auke wrote:
> This implements the core new functions needed for ich8's internal
> NIC. This includes:
> 
> * ich8 specific read/write code
> * flash/nvm access code
> * software semaphore flag functions
> * 10/100 PHY (fe - no gigabit speed) support for low-end versions
> * A workaround for a powerdown sequence problem discovered that
> affects a small number of motherboard.
> 
> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
> ---
> 
>  drivers/net/e1000/e1000_hw.c    | 1000 +++++++++++++++++++++++++++++++++++++++
>  drivers/net/e1000/e1000_hw.h    |  386 +++++++++++++++
>  drivers/net/e1000/e1000_osdep.h |   13 +
>  3 files changed, 1392 insertions(+), 7 deletions(-)

If it takes this much code to support ICH8, it seems like a e1000-ich8.c 
would be warranted...

	Jeff




^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 18/21] e1000: integrate ich8 support into driver
  2006-06-22  5:20 ` [PATCH 18/21] e1000: integrate ich8 support into driver Kok, Auke
@ 2006-06-27  1:54   ` Jeff Garzik
  0 siblings, 0 replies; 47+ messages in thread
From: Jeff Garzik @ 2006-06-27  1:54 UTC (permalink / raw)
  To: Kok, Auke; +Cc: netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Kok, Auke wrote:
> @@ -4225,6 +4396,35 @@ e1000_init_eeprom_params(struct e1000_hw
>          eeprom->use_eerd = TRUE;
>          eeprom->use_eewr = FALSE;
>          break;
> +    case e1000_ich8lan:
> +    {
> +        int32_t  i = 0;
> +        uint32_t flash_size = E1000_READ_ICH8_REG(hw, ICH8_FLASH_GFPREG);
> +
> +        eeprom->type = e1000_eeprom_ich8;
> +        eeprom->use_eerd = FALSE;
> +        eeprom->use_eewr = FALSE;
> +        eeprom->word_size = E1000_SHADOW_RAM_WORDS;
> +
> +        /* Zero the shadow RAM structure. But don't load it from NVM
> +         * so as to save time for driver init */
> +        if (hw->eeprom_shadow_ram != NULL) {
> +            for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
> +                hw->eeprom_shadow_ram[i].modified = FALSE;
> +                hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
> +            }
> +        }
> +
> +        hw->flash_base_addr = (flash_size & ICH8_GFPREG_BASE_MASK) *
> +                              ICH8_FLASH_SECTOR_SIZE;
> +
> +        hw->flash_bank_size = ((flash_size >> 16) & ICH8_GFPREG_BASE_MASK) + 1;
> +        hw->flash_bank_size -= (flash_size & ICH8_GFPREG_BASE_MASK);
> +        hw->flash_bank_size *= ICH8_FLASH_SECTOR_SIZE;
> +        hw->flash_bank_size /= 2 * sizeof(uint16_t);
> +
> +        break;
> +    }

seems to warrant a separate function, called from this callsite (perhaps 
stored in e1000-ich8.c?)


> @@ -4645,7 +4845,10 @@ e1000_read_eeprom(struct e1000_hw *hw,
>          return ret_val;
>      }
>  
> -    if(eeprom->type == e1000_eeprom_spi) {
> +    if (eeprom->type == e1000_eeprom_ich8)
> +        return e1000_read_eeprom_ich8(hw, offset, words, data);
> +
> +    if (eeprom->type == e1000_eeprom_spi) {
>          uint16_t word_in;
>          uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
>  
> @@ -4812,7 +5015,10 @@ e1000_is_onboard_nvm_eeprom(struct e1000
>  
>      DEBUGFUNC("e1000_is_onboard_nvm_eeprom");
>  
> -    if(hw->mac_type == e1000_82573) {
> +    if (hw->mac_type == e1000_ich8lan)
> +        return FALSE;
> +
> +    if (hw->mac_type == e1000_82573) {
>          eecd = E1000_READ_REG(hw, EECD);
>  
>          /* Isolate bits 15 & 16 */
> @@ -4862,8 +5068,22 @@ e1000_validate_eeprom_checksum(struct e1
>          }
>      }
>  
> -    for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
> -        if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
> +    if (hw->mac_type == e1000_ich8lan) {
> +        /* Drivers must allocate the shadow ram structure for the
> +         * EEPROM checksum to be updated.  Otherwise, this bit as well
> +         * as the checksum must both be set correctly for this
> +         * validation to pass.
> +         */
> +        e1000_read_eeprom(hw, 0x19, 1, &eeprom_data);
> +        if ((eeprom_data & 0x40) == 0) {
> +            eeprom_data |= 0x40;
> +            e1000_write_eeprom(hw, 0x19, 1, &eeprom_data);
> +            e1000_update_eeprom_checksum(hw);
> +        }
> +    }
> +
> +    for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
> +        if (e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
>              DEBUGOUT("EEPROM Read Error\n");
>              return -E1000_ERR_EEPROM;
>          }
> @@ -4889,6 +5109,7 @@ e1000_validate_eeprom_checksum(struct e1
>  int32_t
>  e1000_update_eeprom_checksum(struct e1000_hw *hw)
>  {
> +    uint32_t ctrl_ext;
>      uint16_t checksum = 0;
>      uint16_t i, eeprom_data;
>  
> @@ -4907,6 +5128,14 @@ e1000_update_eeprom_checksum(struct e100
>          return -E1000_ERR_EEPROM;
>      } else if (hw->eeprom.type == e1000_eeprom_flash) {
>          e1000_commit_shadow_ram(hw);
> +    } else if (hw->eeprom.type == e1000_eeprom_ich8) {
> +        e1000_commit_shadow_ram(hw);
> +        /* Reload the EEPROM, or else modifications will not appear
> +         * until after next adapter reset. */
> +        ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
> +        ctrl_ext |= E1000_CTRL_EXT_EE_RST;
> +        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
> +        msec_delay(10);
>      }
>      return E1000_SUCCESS;
>  }
> @@ -4946,6 +5175,9 @@ e1000_write_eeprom(struct e1000_hw *hw,
>      if(eeprom->use_eewr == TRUE)
>          return e1000_write_eeprom_eewr(hw, offset, words, data);
>  
> +    if (eeprom->type == e1000_eeprom_ich8)
> +        return e1000_write_eeprom_ich8(hw, offset, words, data);
> +
>      /* Prepare the EEPROM for writing  */
>      if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
>          return -E1000_ERR_EEPROM;
> @@ -5133,11 +5365,17 @@ e1000_commit_shadow_ram(struct e1000_hw 
>      uint32_t flop = 0;
>      uint32_t i = 0;
>      int32_t error = E1000_SUCCESS;
> -
> -    /* The flop register will be used to determine if flash type is STM */
> -    flop = E1000_READ_REG(hw, FLOP);
> +    uint32_t old_bank_offset = 0;
> +    uint32_t new_bank_offset = 0;
> +    uint32_t sector_retries = 0;
> +    uint8_t low_byte = 0;
> +    uint8_t high_byte = 0;
> +    uint8_t temp_byte = 0;
> +    boolean_t sector_write_failed = FALSE;
>  
>      if (hw->mac_type == e1000_82573) {
> +        /* The flop register will be used to determine if flash type is STM */
> +        flop = E1000_READ_REG(hw, FLOP);
>          for (i=0; i < attempts; i++) {
>              eecd = E1000_READ_REG(hw, EECD);
>              if ((eecd & E1000_EECD_FLUPD) == 0) {
> @@ -5171,6 +5409,106 @@ e1000_commit_shadow_ram(struct e1000_hw 
>          }
>      }
>  
> +    if (hw->mac_type == e1000_ich8lan && hw->eeprom_shadow_ram != NULL) {
> +        /* We're writing to the opposite bank so if we're on bank 1,
> +         * write to bank 0 etc.  We also need to erase the segment that
> +         * is going to be written */
> +        if (!(E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL)) {
> +            new_bank_offset = hw->flash_bank_size * 2;
> +            old_bank_offset = 0;
> +            e1000_erase_ich8_4k_segment(hw, 1);
> +        } else {
> +            old_bank_offset = hw->flash_bank_size * 2;
> +            new_bank_offset = 0;
> +            e1000_erase_ich8_4k_segment(hw, 0);
> +        }
> +
> +        do {
> +            sector_write_failed = FALSE;
> +            /* Loop for every byte in the shadow RAM,
> +             * which is in units of words. */
> +            for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
> +                /* Determine whether to write the value stored
> +                 * in the other NVM bank or a modified value stored
> +                 * in the shadow RAM */
> +                if (hw->eeprom_shadow_ram[i].modified == TRUE) {
> +                    low_byte = (uint8_t)hw->eeprom_shadow_ram[i].eeprom_word;
> +                    e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
> +                                         &temp_byte);
> +                    udelay(100);
> +                    error = e1000_verify_write_ich8_byte(hw,
> +                                                 (i << 1) + new_bank_offset,
> +                                                 low_byte);
> +                    if (error != E1000_SUCCESS)
> +                        sector_write_failed = TRUE;
> +                    high_byte =
> +                        (uint8_t)(hw->eeprom_shadow_ram[i].eeprom_word >> 8);
> +                    e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
> +                                         &temp_byte);
> +                    udelay(100);
> +                } else {
> +                    e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
> +                                         &low_byte);
> +                    udelay(100);
> +                    error = e1000_verify_write_ich8_byte(hw,
> +                                 (i << 1) + new_bank_offset, low_byte);
> +                    if (error != E1000_SUCCESS)
> +                        sector_write_failed = TRUE;
> +                    e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
> +                                         &high_byte);
> +                }
> +
> +                /* If the word is 0x13, then make sure the signature bits
> +                 * (15:14) are 11b until the commit has completed.
> +                 * This will allow us to write 10b which indicates the
> +                 * signature is valid.  We want to do this after the write
> +                 * has completed so that we don't mark the segment valid
> +                 * while the write is still in progress */
> +                if (i == E1000_ICH8_NVM_SIG_WORD)
> +                    high_byte = E1000_ICH8_NVM_SIG_MASK | high_byte;
> +
> +                error = e1000_verify_write_ich8_byte(hw,
> +                             (i << 1) + new_bank_offset + 1, high_byte);
> +                if (error != E1000_SUCCESS)
> +                    sector_write_failed = TRUE;
> +
> +                if (sector_write_failed == FALSE) {
> +                    /* Clear the now not used entry in the cache */
> +                    hw->eeprom_shadow_ram[i].modified = FALSE;
> +                    hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
> +                }
> +            }
> +
> +            /* Don't bother writing the segment valid bits if sector
> +             * programming failed. */
> +            if (sector_write_failed == FALSE) {
> +                /* Finally validate the new segment by setting bit 15:14
> +                 * to 10b in word 0x13 , this can be done without an
> +                 * erase as well since these bits are 11 to start with
> +                 * and we need to change bit 14 to 0b */
> +                e1000_read_ich8_byte(hw,
> +                    E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
> +                    &high_byte);
> +                high_byte &= 0xBF;
> +                error = e1000_verify_write_ich8_byte(hw,
> +                            E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
> +                            high_byte);
> +                if (error != E1000_SUCCESS)
> +                    sector_write_failed = TRUE;
> +
> +                /* And invalidate the previously valid segment by setting
> +                 * its signature word (0x13) high_byte to 0b. This can be
> +                 * done without an erase because flash erase sets all bits
> +                 * to 1's. We can write 1's to 0's without an erase */
> +                error = e1000_verify_write_ich8_byte(hw,
> +                            E1000_ICH8_NVM_SIG_WORD * 2 + 1 + old_bank_offset,
> +                            0);
> +                if (error != E1000_SUCCESS)
> +                    sector_write_failed = TRUE;
> +            }
> +        } while (++sector_retries < 10 && sector_write_failed == TRUE);
> +    }
> +

obviously warrants a separate function for new ich8 code...




^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 19/21] e1000: allow user to disable ich8 lock loss workaround
  2006-06-22  5:20 ` [PATCH 19/21] e1000: allow user to disable ich8 lock loss workaround Kok, Auke
@ 2006-06-27  1:55   ` Jeff Garzik
  2006-06-27 14:21     ` Auke Kok
  0 siblings, 1 reply; 47+ messages in thread
From: Jeff Garzik @ 2006-06-27  1:55 UTC (permalink / raw)
  To: Kok, Auke; +Cc: netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Kok, Auke wrote:
> The workaround for the ich8 lock loss problem is only needed for
> a very small amount of systems. This adds an option for the user
> to disable the workaround.

Does "very small amount" equate to "never in real production machines"?



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 06/21] e1000: add smart power down code
  2006-06-27  1:43   ` Jeff Garzik
@ 2006-06-27  8:49     ` Florian Reitmeir
  2006-06-27 14:40     ` Auke Kok
  1 sibling, 0 replies; 47+ messages in thread
From: Florian Reitmeir @ 2006-06-27  8:49 UTC (permalink / raw)
  To: Jeff Garzik, netdev

On Mon, 26 Jun 2006, Jeff Garzik wrote:

> Kok, Auke wrote:
> >Smart Power Down is a power saving feature in newer e1000 hardware. We
> >disable it because it causes time to link to be long, but make it a
> >user choice.
> >
> >Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
> >Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
> >---
> >
> > drivers/net/e1000/e1000.h       |    1 +
> > drivers/net/e1000/e1000_main.c  |   15 +++++++++++++++
> > drivers/net/e1000/e1000_param.c |   25 +++++++++++++++++++++++++
> > 3 files changed, 41 insertions(+), 0 deletions(-)
> 
> Since it's not default, who will actually use this?  Particularly since 
> it is only a module option, and not supported through ethtool (frown).
i would use it, i always wanted the feature on my laptop (ibm thinkpad)

-- 
Florian Reitmeir

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 19/21] e1000: allow user to disable ich8 lock loss workaround
  2006-06-27  1:55   ` Jeff Garzik
@ 2006-06-27 14:21     ` Auke Kok
  0 siblings, 0 replies; 47+ messages in thread
From: Auke Kok @ 2006-06-27 14:21 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Kok, Auke, netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Jeff Garzik wrote:
> Kok, Auke wrote:
>> The workaround for the ich8 lock loss problem is only needed for
>> a very small amount of systems. This adds an option for the user
>> to disable the workaround.
> 
> Does "very small amount" equate to "never in real production machines"?

Unfortunately not.


Cheers,

Auke

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 13/21] e1000: add E1000_BIG_ENDIAN symbol
  2006-06-27  1:49   ` Jeff Garzik
@ 2006-06-27 14:25     ` Auke Kok
  0 siblings, 0 replies; 47+ messages in thread
From: Auke Kok @ 2006-06-27 14:25 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Kok, Auke, netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Jeff Garzik wrote:
> Kok, Auke wrote:
>> This adds a private symbol to signify endianess in our driver.
>>
>> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
>> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
>> ---
>>
>>  drivers/net/e1000/e1000_hw.h    |    2 +-
>>  drivers/net/e1000/e1000_osdep.h |    3 +++
>>  2 files changed, 4 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
>> index 941b47d..376a2ef 100644
>> --- a/drivers/net/e1000/e1000_hw.h
>> +++ b/drivers/net/e1000/e1000_hw.h
>> @@ -351,7 +351,7 @@ struct e1000_host_mng_command_info {
>>      struct e1000_host_mng_command_header command_header;  /* Command 
>> Head/Command Result Head has 4 bytes */
>>      uint8_t command_data[E1000_HI_MAX_MNG_DATA_LENGTH];   /* Command 
>> data can length 0..0x658*/
>>  };
>> -#ifdef __BIG_ENDIAN
>> +#ifdef E1000_BIG_ENDIAN
>>  struct e1000_host_mng_dhcp_cookie{
>>      uint32_t signature;
>>      uint16_t vlan_id;
>> diff --git a/drivers/net/e1000/e1000_osdep.h 
>> b/drivers/net/e1000/e1000_osdep.h
>> index 048d052..6130a42 100644
>> --- a/drivers/net/e1000/e1000_osdep.h
>> +++ b/drivers/net/e1000/e1000_osdep.h
>> @@ -83,6 +83,9 @@ typedef enum {
>>  #define DEBUGOUT3 DEBUGOUT2
>>  #define DEBUGOUT7 DEBUGOUT3
>>  
>> +#ifdef __BIG_ENDIAN
>> +#define E1000_BIG_ENDIAN __BIG_ENDIAN
>> +#endif
> 
> NAK.  This is backwards:  We don't need wrappers for symbols that the 
> kernel already provides.

Agreed, I deleted it from our git server.

Auke

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/21] e1000: disable CRC stripping workaround
  2006-06-27  1:48   ` Jeff Garzik
@ 2006-06-27 14:29     ` Auke Kok
  0 siblings, 0 replies; 47+ messages in thread
From: Auke Kok @ 2006-06-27 14:29 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Kok, Auke, netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Jeff Garzik wrote:
> Kok, Auke wrote:
>> CRC stripping is breaking SMBUS-connected BMC's. We disable this
>> feature to make it work. This fixes related bugs regarding SOL.
>>
>> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
>> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
>> ---
>>
>>  drivers/net/e1000/e1000_main.c |    7 ++++++-
>>  1 files changed, 6 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/net/e1000/e1000_main.c 
>> b/drivers/net/e1000/e1000_main.c
>> index c44ed6f..7787299 100644
>> --- a/drivers/net/e1000/e1000_main.c
>> +++ b/drivers/net/e1000/e1000_main.c
>> @@ -1628,8 +1628,11 @@ e1000_setup_rctl(struct e1000_adapter *a
>>          E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
>>          (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
>>  
>> +    /* disable hardware stripping of CRC because it breaks
>> +     * BMC firmware connected over SMBUS
>>      if (adapter->hw.mac_type > e1000_82543)
>>          rctl |= E1000_RCTL_SECRC;
>> +     */
>>  
>>      if (adapter->hw.tbi_compatibility_on == 1)
>>          rctl |= E1000_RCTL_SBP;
>> @@ -1696,7 +1699,9 @@ e1000_setup_rctl(struct e1000_adapter *a
>>          rfctl |= E1000_RFCTL_IPV6_DIS;
>>          E1000_WRITE_REG(&adapter->hw, RFCTL, rfctl);
>>  
>> -        rctl |= E1000_RCTL_DTYP_PS | E1000_RCTL_SECRC;
>> +        /* disable the stripping of CRC because it breaks
>> +         * BMC firmware connected over SMBUS */
>> +        rctl |= E1000_RCTL_DTYP_PS /* | E1000_RCTL_SECRC */;
> 
> This is quite ugly.  You are basically bloating the code with historic, 
> dead code, no different than filling the e1000/*.c with '#if 0' regions.
> 
> Just delete it, and explain why in the patch description.


Adjusted the patch on our git server to this:


diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index c44ed6f..a9e55dc 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1628,9 +1628,6 @@ e1000_setup_rctl(struct e1000_adapter *a
                 E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
                 (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);

-       if (adapter->hw.mac_type > e1000_82543)
-               rctl |= E1000_RCTL_SECRC;
-
         if (adapter->hw.tbi_compatibility_on == 1)
                 rctl |= E1000_RCTL_SBP;
         else
@@ -1696,7 +1693,7 @@ e1000_setup_rctl(struct e1000_adapter *a
                 rfctl |= E1000_RFCTL_IPV6_DIS;
                 E1000_WRITE_REG(&adapter->hw, RFCTL, rfctl);

-               rctl |= E1000_RCTL_DTYP_PS | E1000_RCTL_SECRC;
+               rctl |= E1000_RCTL_DTYP_PS;

                 psrctl |= adapter->rx_ps_bsize0 >>
                         E1000_PSRCTL_BSIZE0_SHIFT;

Cheers,

Auke

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [PATCH 10/21] e1000: force register write flushes to circumvent broken platforms
  2006-06-27  1:47   ` Jeff Garzik
@ 2006-06-27 14:36     ` Auke Kok
  2006-06-27 15:41       ` Jeff Garzik
  2006-06-27 15:56       ` Auke Kok
  0 siblings, 2 replies; 47+ messages in thread
From: Auke Kok @ 2006-06-27 14:36 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Kok, Auke, netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Jeff Garzik wrote:
> Kok, Auke wrote:
>> A certain AMD64 bridge (8132) has an option to turn on write combining
>> which breaks our adapter. To circumvent this we need to flush every 
>> write.
>>
>> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
>> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
>> ---
>>
>>  drivers/net/e1000/e1000_hw.c   |   24 ++++++++++++++++++++++--
>>  drivers/net/e1000/e1000_main.c |   18 +++++++++++-------
>>  2 files changed, 33 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
>> index 3959039..749d621 100644
>> --- a/drivers/net/e1000/e1000_hw.c
>> +++ b/drivers/net/e1000/e1000_hw.c
>> @@ -705,8 +705,12 @@ e1000_init_hw(struct e1000_hw *hw)
>>      /* Zero out the Multicast HASH table */
>>      DEBUGOUT("Zeroing the MTA\n");
>>      mta_size = E1000_MC_TBL_SIZE;
>> -    for(i = 0; i < mta_size; i++)
>> +    for(i = 0; i < mta_size; i++) {
>>          E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
>> +        /* use write flush to prevent Memory Write Block (MWB) from
>> +         * occuring when accessing our register space */
>> +        E1000_WRITE_FLUSH(hw);
>> +    }
> 
> NAK.  We can't crap up every driver just for one weird piece of hardware.
> 
> If this problem falls outside the grounds of mmiowb() [see 
> Documentation/memory-barriers.txt], then other solutions need to be 
> looked into... ioremap_nocache() ?  Tweaking the MTRR for this region? 
> Chipset quirk?  ...

If there is an in-kernel fix for this that would make these flushes obsolete I 
would certainly prefer it too, unfortunately we can't fix already released 
kernels and our driver still needs to work there too, so that's why I queued 
it. It can be dropped from this series if that's preferred.

Cheers,

Auke

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 06/21] e1000: add smart power down code
  2006-06-27  1:43   ` Jeff Garzik
  2006-06-27  8:49     ` Florian Reitmeir
@ 2006-06-27 14:40     ` Auke Kok
  1 sibling, 0 replies; 47+ messages in thread
From: Auke Kok @ 2006-06-27 14:40 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Kok, Auke, netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Jeff Garzik wrote:
> Kok, Auke wrote:
>> Smart Power Down is a power saving feature in newer e1000 hardware. We
>> disable it because it causes time to link to be long, but make it a
>> user choice.
>>
>> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
>> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
>> ---
>>
>>  drivers/net/e1000/e1000.h       |    1 +
>>  drivers/net/e1000/e1000_main.c  |   15 +++++++++++++++
>>  drivers/net/e1000/e1000_param.c |   25 +++++++++++++++++++++++++
>>  3 files changed, 41 insertions(+), 0 deletions(-)
> 
> Since it's not default, who will actually use this?  Particularly since 
> it is only a module option, and not supported through ethtool (frown).

laptop users that frequently re-connect their cables might enable this 
function since it saves battery life.

Auke

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 02/21] e1000: rework driver hardware reset locking
  2006-06-27  1:42   ` Jeff Garzik
@ 2006-06-27 14:42     ` Auke Kok
  0 siblings, 0 replies; 47+ messages in thread
From: Auke Kok @ 2006-06-27 14:42 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Kok, Auke, netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Jeff Garzik wrote:
> Kok, Auke wrote:
>> @@ -631,6 +627,9 @@ e1000_set_ringparam(struct net_device *n
>>      tx_ring_size = sizeof(struct e1000_tx_ring) * 
>> adapter->num_tx_queues;
>>      rx_ring_size = sizeof(struct e1000_rx_ring) * 
>> adapter->num_rx_queues;
>>  
>> +    while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
>> +        msleep(1);
> 
> This is a bit worrying, but no outright objection.  We don't want to see 
> these accumulate.

Agreed but at least we removed the opportunity to panic the driver as easy as 
with 2 commandline commands (in several ways) - we're still looking into 
improving this - any comments would be appreciated.

Cheers,

Auke

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 10/21] e1000: force register write flushes to circumvent broken platforms
  2006-06-27 14:36     ` Auke Kok
@ 2006-06-27 15:41       ` Jeff Garzik
  2006-06-27 15:56       ` Auke Kok
  1 sibling, 0 replies; 47+ messages in thread
From: Jeff Garzik @ 2006-06-27 15:41 UTC (permalink / raw)
  To: Auke Kok; +Cc: netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Auke Kok wrote:
> If there is an in-kernel fix for this that would make these flushes 
> obsolete I would certainly prefer it too, unfortunately we can't fix 
> already released kernels and our driver still needs to work there too, 
> so that's why I queued it. It can be dropped from this series if that's 
> preferred.

Yes, definitely drop it from the series...

	Jeff



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 10/21] e1000: force register write flushes to circumvent broken platforms
  2006-06-27 14:36     ` Auke Kok
  2006-06-27 15:41       ` Jeff Garzik
@ 2006-06-27 15:56       ` Auke Kok
  1 sibling, 0 replies; 47+ messages in thread
From: Auke Kok @ 2006-06-27 15:56 UTC (permalink / raw)
  To: Auke Kok; +Cc: Jeff Garzik, netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Auke Kok wrote:
> Jeff Garzik wrote:
>> Kok, Auke wrote:
>>> A certain AMD64 bridge (8132) has an option to turn on write combining
>>> which breaks our adapter. To circumvent this we need to flush every 
>>> write.
>>>
>>> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
>>> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
>>> ---
>>>
>>>  drivers/net/e1000/e1000_hw.c   |   24 ++++++++++++++++++++++--
>>>  drivers/net/e1000/e1000_main.c |   18 +++++++++++-------
>>>  2 files changed, 33 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
>>> index 3959039..749d621 100644
>>> --- a/drivers/net/e1000/e1000_hw.c
>>> +++ b/drivers/net/e1000/e1000_hw.c
>>> @@ -705,8 +705,12 @@ e1000_init_hw(struct e1000_hw *hw)
>>>      /* Zero out the Multicast HASH table */
>>>      DEBUGOUT("Zeroing the MTA\n");
>>>      mta_size = E1000_MC_TBL_SIZE;
>>> -    for(i = 0; i < mta_size; i++)
>>> +    for(i = 0; i < mta_size; i++) {
>>>          E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
>>> +        /* use write flush to prevent Memory Write Block (MWB) from
>>> +         * occuring when accessing our register space */
>>> +        E1000_WRITE_FLUSH(hw);
>>> +    }
>>
>> NAK.  We can't crap up every driver just for one weird piece of hardware.
>>
>> If this problem falls outside the grounds of mmiowb() [see 
>> Documentation/memory-barriers.txt], then other solutions need to be 
>> looked into... ioremap_nocache() ?  Tweaking the MTRR for this region? 
>> Chipset quirk?  ...
> 
> If there is an in-kernel fix for this that would make these flushes 
> obsolete I would certainly prefer it too, unfortunately we can't fix 
> already released kernels and our driver still needs to work there too, 
> so that's why I queued it. It can be dropped from this series if that's 
> preferred.

I have to get back on that - it's not as simple as "the platform is broken". 
e1000's don't support write-combining in hardware but the problem only shows 
itself during initialization. This patch makes it work on AMD platforms with 
write-combining enabled, the platform itself isn't broken - technically the 
NIC is (ixgb doesn't have this problem for instance).

The added write flushes are at initialization only, and fix the problem for 
any other case. I don't see much harm in that.

Auke

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 17/21] e1000: add ich8lan core functions
  2006-06-27  1:52   ` Jeff Garzik
@ 2006-06-27 16:12     ` Auke Kok
  0 siblings, 0 replies; 47+ messages in thread
From: Auke Kok @ 2006-06-27 16:12 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Kok, Auke, netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John

Jeff Garzik wrote:
> Kok, Auke wrote:
>> This implements the core new functions needed for ich8's internal
>> NIC. This includes:
>>
>> * ich8 specific read/write code
>> * flash/nvm access code
>> * software semaphore flag functions
>> * 10/100 PHY (fe - no gigabit speed) support for low-end versions
>> * A workaround for a powerdown sequence problem discovered that
>> affects a small number of motherboard.
>>
>> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
>> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
>> ---
>>
>>  drivers/net/e1000/e1000_hw.c    | 1000 
>> +++++++++++++++++++++++++++++++++++++++
>>  drivers/net/e1000/e1000_hw.h    |  386 +++++++++++++++
>>  drivers/net/e1000/e1000_osdep.h |   13 +
>>  3 files changed, 1392 insertions(+), 7 deletions(-)
> 
> If it takes this much code to support ICH8, it seems like a e1000-ich8.c 
> would be warranted...

that's work in progress - Jeb Cramer has been working on this for a while now 
but unfortunately it's not ready, and getting ich8 supported in a way that we 
know that doesn't introduce new bugs is more important. This patch adds tested 
and validated support for these chipsets that has been hammered by our test team.

We are planning (working) on cleaning it all up (including whitespace!) - but 
getting the ich8 support out is more important - people can buy the hardware 
today.

Cheers,

Auke

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/21] e1000: driver update to 7.1.9-k2
  2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
                   ` (20 preceding siblings ...)
  2006-06-22  5:20 ` [PATCH 21/21] e1000: increase version to 7.1.9-k2 Kok, Auke
@ 2006-06-27 22:48 ` Auke Kok
  21 siblings, 0 replies; 47+ messages in thread
From: Auke Kok @ 2006-06-27 22:48 UTC (permalink / raw)
  To: Garzik, Jeff
  Cc: Kok, Auke, netdev, Brandeburg, Jesse, Kok, Auke, Ronciak, John


Jeff,

after comments I've made some adjustments. I'll list them below against the 
old summary. The changes are available from our git-server:

Please pull from:

git://lost.foo-projects.org/~ahkok/git/netdev-2.6 upstream

These patches are against
     netdev-2.6#upstream 612eff0e3715a6faff5ba1b74873b99e036c59fe
(Brian Haley <brian.haley@hp.com> / [PATCH] s2io: netpoll support)


> Summary of patches:
> 
> [01]: fix loopback ethtool test
> [02]: rework driver hardware reset locking
> [03]: Make PHY powerup/down a function
> [04]: fix CONFIG_PM blocks
> [05]: small performance tweak by removing double code
> [06]: add smart power down code
> [07]: change printk into DPRINTK
> [08]: recycle skb
> [09]: rework module param code with uninitialized values
> [10]: force register write flushes to circumvent broken platforms

Unmodified. See comments here:
http://marc.theaimsgroup.com/?l=linux-netdev&m=115142459725123&w=2 [1]

> [11]: disable CRC stripping workaround

Removed all references to SECRC (crc stripping) instead of leaving it commented.

> [12]: fix adapter led blinking inconsistency
> [13]: add E1000_BIG_ENDIAN symbol

Dropped this patch entirely

> [14]: M88 PHY workaround
> [15]: check return value of _get_speed_and_duplex
> [16]: disable ERT
> [17]: add ich8lan core functions
> [18]: integrate ich8 support into driver
> [19]: allow user to disable ich8 lock loss workaround
> [20]: add ich8lan device ID's
> [21]: increase version to 7.1.9-k2


[1] I can drop #11 in case someone throws a fit ;) - as everyone I'd really 
like to see patches 17->20 queued for 2.6.18 for obvious reasons - this is the 
most important section of these patches!

Cheers,

Auke


---
  drivers/net/e1000/e1000.h         |   10
  drivers/net/e1000/e1000_ethtool.c |  143 +--
  drivers/net/e1000/e1000_hw.c      | 1770 +++++++++++++++++++++++++++++++++++---
  drivers/net/e1000/e1000_hw.h      |  398 ++++++++
  drivers/net/e1000/e1000_main.c    |  384 +++++---
  drivers/net/e1000/e1000_osdep.h   |   13
  drivers/net/e1000/e1000_param.c   |  213 ++--
  7 files changed, 2530 insertions(+), 401 deletions(-)

^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2006-06-27 22:48 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-06-22  5:18 [PATCH 00/21] e1000: driver update to 7.1.9-k2 Kok, Auke
2006-06-22  5:20 ` [PATCH 01/21] e1000: fix loopback ethtool test Kok, Auke
2006-06-22  5:20 ` [PATCH 02/21] e1000: rework driver hardware reset locking Kok, Auke
2006-06-27  1:42   ` Jeff Garzik
2006-06-27 14:42     ` Auke Kok
2006-06-22  5:20 ` [PATCH 03/21] e1000: Make PHY powerup/down a function Kok, Auke
2006-06-22  5:20 ` [PATCH 04/21] e1000: fix CONFIG_PM blocks Kok, Auke
2006-06-22  5:20 ` [PATCH 05/21] e1000: small performance tweak by removing double code Kok, Auke
2006-06-22  5:20 ` [PATCH 06/21] e1000: add smart power down code Kok, Auke
2006-06-27  1:43   ` Jeff Garzik
2006-06-27  8:49     ` Florian Reitmeir
2006-06-27 14:40     ` Auke Kok
2006-06-22  5:20 ` [PATCH 07/21] e1000: change printk into DPRINTK Kok, Auke
2006-06-22  5:20 ` [PATCH 08/21] e1000: recycle skb Kok, Auke
2006-06-22  5:20 ` [PATCH 09/21] e1000: rework module param code with uninitialized values Kok, Auke
2006-06-22  5:20 ` [PATCH 10/21] e1000: force register write flushes to circumvent broken platforms Kok, Auke
2006-06-27  1:47   ` Jeff Garzik
2006-06-27 14:36     ` Auke Kok
2006-06-27 15:41       ` Jeff Garzik
2006-06-27 15:56       ` Auke Kok
2006-06-22  5:20 ` [PATCH 11/21] e1000: disable CRC stripping workaround Kok, Auke
2006-06-22  5:31   ` Ben Greear
2006-06-22 15:36     ` Auke Kok
2006-06-22 15:39     ` Jesse Brandeburg
2006-06-22 15:55       ` Ben Greear
2006-06-22 16:01         ` Jesse Brandeburg
2006-06-22 15:57       ` Lennert Buytenhek
2006-06-27  1:48   ` Jeff Garzik
2006-06-27 14:29     ` Auke Kok
2006-06-22  5:20 ` [PATCH 12/21] e1000: fix adapter led blinking inconsistency Kok, Auke
2006-06-22  5:20 ` [PATCH 13/21] e1000: add E1000_BIG_ENDIAN symbol Kok, Auke
2006-06-27  1:49   ` Jeff Garzik
2006-06-27 14:25     ` Auke Kok
2006-06-22  5:20 ` [PATCH 14/21] e1000: M88 PHY workaround Kok, Auke
2006-06-22  5:20 ` [PATCH 15/21] e1000: check return value of _get_speed_and_duplex Kok, Auke
2006-06-22  5:20 ` [PATCH 16/21] e1000: disable ERT Kok, Auke
2006-06-22  5:20 ` [PATCH 17/21] e1000: add ich8lan core functions Kok, Auke
2006-06-27  1:52   ` Jeff Garzik
2006-06-27 16:12     ` Auke Kok
2006-06-22  5:20 ` [PATCH 18/21] e1000: integrate ich8 support into driver Kok, Auke
2006-06-27  1:54   ` Jeff Garzik
2006-06-22  5:20 ` [PATCH 19/21] e1000: allow user to disable ich8 lock loss workaround Kok, Auke
2006-06-27  1:55   ` Jeff Garzik
2006-06-27 14:21     ` Auke Kok
2006-06-22  5:20 ` [PATCH 20/21] e1000: add ich8lan device ID's Kok, Auke
2006-06-22  5:20 ` [PATCH 21/21] e1000: increase version to 7.1.9-k2 Kok, Auke
2006-06-27 22:48 ` [PATCH 00/21] e1000: driver update " Auke Kok

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).