changeset 10680:45bda3640f27

6797885 need to add support for network device (8086,10ea) in a new Intel system 6803799 need to add network device support (8086,10ef) for a new Intel system 6808388 e1000g inteface experience packet lost when switch between joining and leaving a multicast stream
author Miles Xu, Sun Microsystems <Min.Xu@Sun.COM>
date Tue, 29 Sep 2009 12:12:23 +0800
parents c7ca3a4d76d9
children 39bfab5e595b
files usr/src/pkgdefs/SUNWintgige/postinstall usr/src/uts/common/io/e1000g/README usr/src/uts/common/io/e1000g/e1000_80003es2lan.c usr/src/uts/common/io/e1000g/e1000_80003es2lan.h usr/src/uts/common/io/e1000g/e1000_82540.c usr/src/uts/common/io/e1000g/e1000_82541.c usr/src/uts/common/io/e1000g/e1000_82541.h usr/src/uts/common/io/e1000g/e1000_82542.c usr/src/uts/common/io/e1000g/e1000_82543.c usr/src/uts/common/io/e1000g/e1000_82543.h usr/src/uts/common/io/e1000g/e1000_82571.c usr/src/uts/common/io/e1000g/e1000_82571.h usr/src/uts/common/io/e1000g/e1000_api.c usr/src/uts/common/io/e1000g/e1000_api.h usr/src/uts/common/io/e1000g/e1000_defines.h usr/src/uts/common/io/e1000g/e1000_hw.h usr/src/uts/common/io/e1000g/e1000_ich8lan.c usr/src/uts/common/io/e1000g/e1000_ich8lan.h usr/src/uts/common/io/e1000g/e1000_mac.c usr/src/uts/common/io/e1000g/e1000_mac.h usr/src/uts/common/io/e1000g/e1000_manage.c usr/src/uts/common/io/e1000g/e1000_manage.h usr/src/uts/common/io/e1000g/e1000_nvm.c usr/src/uts/common/io/e1000g/e1000_nvm.h usr/src/uts/common/io/e1000g/e1000_osdep.c usr/src/uts/common/io/e1000g/e1000_osdep.h usr/src/uts/common/io/e1000g/e1000_phy.c usr/src/uts/common/io/e1000g/e1000_phy.h usr/src/uts/common/io/e1000g/e1000_regs.h usr/src/uts/common/io/e1000g/e1000g.conf usr/src/uts/common/io/e1000g/e1000g_debug.c usr/src/uts/common/io/e1000g/e1000g_main.c usr/src/uts/common/io/e1000g/e1000g_rx.c usr/src/uts/common/io/e1000g/e1000g_stat.c usr/src/uts/common/io/e1000g/e1000g_sw.h
diffstat 35 files changed, 3054 insertions(+), 875 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/pkgdefs/SUNWintgige/postinstall	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/pkgdefs/SUNWintgige/postinstall	Tue Sep 29 12:12:23 2009 +0800
@@ -208,8 +208,15 @@
 	"pci8086,10de"
 	"pci8086,10df"
 	"pci8086,10e5"
+	"pci8086,10ea"
+	"pci8086,10eb"
+	"pci8086,10ef"
+	"pci8086,10f0"
 	"pci8086,10f5"
+	"pci8086,10f6"
+	"pci8086,150c"
 	"pci8086,294c"
+	"pci8086,f0fe"
 	"pciex8086,1049"
 	"pciex8086,104a"
 	"pciex8086,104b"
@@ -250,6 +257,13 @@
 	"pciex8086,10de"
 	"pciex8086,10df"
 	"pciex8086,10e5"
+	"pciex8086,10ea"
+	"pciex8086,10eb"
+	"pciex8086,10ef"
+	"pciex8086,10f0"
 	"pciex8086,10f5"
-	"pciex8086,294c"' \
+	"pciex8086,10f6"
+	"pciex8086,150c"
+	"pciex8086,294c"
+	"pciex8086,f0fe"' \
 	-m '* 0666 root sys' e1000g
--- a/usr/src/uts/common/io/e1000g/README	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/README	Tue Sep 29 12:12:23 2009 +0800
@@ -685,9 +685,9 @@
 
 5.3.12
 ====
-   This version has the following fix:
-    6846262 T2000 fma shows fault.io.pciex.device-interr in snv_115
-    6870404 e1000g_reset can call e1000g_start after releasing dma resources
+  This version has the following fix:
+   6846262 T2000 fma shows fault.io.pciex.device-interr in snv_115
+   6870404 e1000g_reset can call e1000g_start after releasing dma resources
 
 5.3.13
 ====
@@ -700,3 +700,10 @@
   This version has the following fix:
    6820747 kstat output incorrect for MMF version of e1000g making it impossible to troubleshoot
    6847888 HW initialization updates for 82541 and 82547 chips
+
+5.3.15
+======
+  This version has the following fix:
+   6797885 need to add support for network device (8086,10ea) in a new Intel system
+   6803799 need to add network device support (8086,10ef) for a new Intel system
+   6808388 e1000g inteface experience packet lost when switch between joining and leaving a multicast stream
--- a/usr/src/uts/common/io/e1000g/e1000_80003es2lan.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_80003es2lan.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.76 sol_anvik_patch
+ * IntelVersion: 1.86 v3-1-3_2009-8-20
  */
 /*
  * 80003ES2LAN Gigabit Ethernet Controller (Copper)
@@ -37,9 +37,7 @@
 static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw);
 static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw);
 static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw);
-static s32  e1000_acquire_mac_csr_80003es2lan(struct e1000_hw *hw);
 static void e1000_release_phy_80003es2lan(struct e1000_hw *hw);
-static void e1000_release_mac_csr_80003es2lan(struct e1000_hw *hw);
 static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw);
 static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw);
 static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
@@ -177,6 +175,7 @@
 	 * for setting word_size.
 	 */
 	size += NVM_WORD_SIZE_BASE_SHIFT;
+
 	/* EEPROM access above 16k is unsupported */
 	if (size > 14)
 		size = 14;
@@ -269,6 +268,8 @@
 	mac->ops.mta_set = e1000_mta_set_generic;
 	/* read mac address */
 	mac->ops.read_mac_addr = e1000_read_mac_addr_80003es2lan;
+	/* ID LED init */
+	mac->ops.id_led_init = e1000_id_led_init_generic;
 	/* blink LED */
 	mac->ops.blink_led = e1000_blink_led_generic;
 	/* setup LED */
@@ -283,6 +284,8 @@
 	/* link info */
 	mac->ops.get_link_up_info = e1000_get_link_up_info_80003es2lan;
 
+	/* set lan id for port to determine which phy lock to use */
+	hw->mac.ops.set_lan_id(hw);
 out:
 	return (ret_val);
 }
@@ -301,7 +304,6 @@
 	hw->mac.ops.init_params = e1000_init_mac_params_80003es2lan;
 	hw->nvm.ops.init_params = e1000_init_nvm_params_80003es2lan;
 	hw->phy.ops.init_params = e1000_init_phy_params_80003es2lan;
-	(void) e1000_get_bus_info_pcie_generic(hw);
 }
 
 /*
@@ -536,29 +538,35 @@
 		goto out;
 	}
 
-	/*
-	 * The "ready" bit in the MDIC register may be incorrectly set
-	 * before the device has completed the "Page Select" MDI
-	 * transaction.  So we wait 200us after each MDI command...
-	 */
-	usec_delay(200);
+	if (hw->dev_spec._80003es2lan.mdic_wa_enable == true) {
+		/*
+		 * The "ready" bit in the MDIC register may be incorrectly set
+		 * before the device has completed the "Page Select" MDI
+		 * transaction.  So we wait 200us after each MDI command...
+		 */
+		usec_delay(200);
 
-	/* ...and verify the command was successful. */
-	ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
+		/* ...and verify the command was successful. */
+		ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
 
-	if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
-		ret_val = -E1000_ERR_PHY;
-		e1000_release_phy_80003es2lan(hw);
-		goto out;
-	}
+		if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
+			ret_val = -E1000_ERR_PHY;
+			e1000_release_phy_80003es2lan(hw);
+			goto out;
+		}
+
+		usec_delay(200);
 
-	usec_delay(200);
+		ret_val = e1000_read_phy_reg_mdic(hw,
+		    MAX_PHY_REG_ADDRESS & offset,
+		    data);
 
-	ret_val = e1000_read_phy_reg_mdic(hw,
-	    MAX_PHY_REG_ADDRESS & offset,
-	    data);
+		usec_delay(200);
+	} else
+		ret_val = e1000_read_phy_reg_mdic(hw,
+		    MAX_PHY_REG_ADDRESS & offset,
+		    data);
 
-	usec_delay(200);
 	e1000_release_phy_80003es2lan(hw);
 
 out:
@@ -605,29 +613,35 @@
 		goto out;
 	}
 
-	/*
-	 * The "ready" bit in the MDIC register may be incorrectly set
-	 * before the device has completed the "Page Select" MDI
-	 * transaction.  So we wait 200us after each MDI command...
-	 */
-	usec_delay(200);
+	if (hw->dev_spec._80003es2lan.mdic_wa_enable == true) {
+		/*
+		 * The "ready" bit in the MDIC register may be incorrectly set
+		 * before the device has completed the "Page Select" MDI
+		 * transaction.  So we wait 200us after each MDI command...
+		 */
+		usec_delay(200);
 
-	/* ...and verify the command was successful. */
-	ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
+		/* ...and verify the command was successful. */
+		ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
 
-	if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
-		ret_val = -E1000_ERR_PHY;
-		e1000_release_phy_80003es2lan(hw);
-		goto out;
-	}
+		if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
+			ret_val = -E1000_ERR_PHY;
+			e1000_release_phy_80003es2lan(hw);
+			goto out;
+		}
+
+		usec_delay(200);
 
-	usec_delay(200);
+		ret_val = e1000_write_phy_reg_mdic(hw,
+		    MAX_PHY_REG_ADDRESS & offset,
+		    data);
 
-	ret_val = e1000_write_phy_reg_mdic(hw,
-	    MAX_PHY_REG_ADDRESS & offset,
-	    data);
+		usec_delay(200);
+	} else
+		ret_val = e1000_write_phy_reg_mdic(hw,
+		    MAX_PHY_REG_ADDRESS & offset,
+		    data);
 
-	usec_delay(200);
 	e1000_release_phy_80003es2lan(hw);
 
 out:
@@ -697,7 +711,7 @@
 static s32
 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
 {
-	s32 ret_val;
+	s32 ret_val = E1000_SUCCESS;
 	u16 phy_data;
 	bool link;
 
@@ -814,16 +828,15 @@
 
 	index = phy_data & GG82563_DSPD_CABLE_LENGTH;
 
-	if (index < GG82563_CABLE_LENGTH_TABLE_SIZE + 5) {
-		phy->min_cable_length = e1000_gg82563_cable_length_table[index];
-		phy->max_cable_length =
-		    e1000_gg82563_cable_length_table[index+5];
+	if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5) {
+		ret_val = E1000_ERR_PHY;
+		goto out;
+	}
 
-		phy->cable_length = (phy->min_cable_length +
-		    phy->max_cable_length) / 2;
-	} else {
-		ret_val = E1000_ERR_PHY;
-	}
+	phy->min_cable_length = e1000_gg82563_cable_length_table[index];
+	phy->max_cable_length = e1000_gg82563_cable_length_table[index + 5];
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
 
 out:
 	return (ret_val);
@@ -905,7 +918,7 @@
 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
 	(void) E1000_READ_REG(hw, E1000_ICR);
 
-	(void) e1000_check_alt_mac_addr_generic(hw);
+	ret_val = e1000_check_alt_mac_addr_generic(hw);
 
 out:
 	return (ret_val);
@@ -930,7 +943,7 @@
 	e1000_initialize_hw_bits_80003es2lan(hw);
 
 	/* Initialize identification LED */
-	ret_val = e1000_id_led_init_generic(hw);
+	ret_val = mac->ops.id_led_init(hw);
 	if (ret_val) {
 		DEBUGOUT("Error initializing identification LED\n");
 		/* This is not fatal and we should not stop init due to this */
@@ -984,6 +997,19 @@
 	reg_data &= ~0x00100000;
 	E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data);
 
+	/* default to true to enable the MDIC W/A */
+	hw->dev_spec._80003es2lan.mdic_wa_enable = true;
+
+	ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
+	    E1000_KMRNCTRLSTA_OFFSET >>
+	    E1000_KMRNCTRLSTA_OFFSET_SHIFT,
+	    &i);
+	if (!ret_val) {
+		if ((i & E1000_KMRNCTRLSTA_OPMODE_MASK) ==
+		    E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO)
+			hw->dev_spec._80003es2lan.mdic_wa_enable = false;
+	}
+
 	/*
 	 * Clear all of the statistics registers (clear on read).  It is
 	 * important that we do this after we have tried to establish link
@@ -1164,21 +1190,18 @@
 	if (!(hw->mac.ops.check_mng_mode(hw))) {
 		/* Enable Electrical Idle on the PHY */
 		data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
-		ret_val = hw->phy.ops.write_reg(hw,
-		    GG82563_PHY_PWR_MGMT_CTRL,
+		ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_PWR_MGMT_CTRL,
 		    data);
 		if (ret_val)
 			goto out;
-		ret_val = hw->phy.ops.read_reg(hw,
-		    GG82563_PHY_KMRN_MODE_CTRL,
+		ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
 		    &data);
 
 		if (ret_val)
 			goto out;
 
 		data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
-		ret_val = hw->phy.ops.write_reg(hw,
-		    GG82563_PHY_KMRN_MODE_CTRL,
+		ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
 		    data);
 
 		if (ret_val)
@@ -1417,7 +1440,7 @@
  * using the kumeran interface.  The information retrieved is stored in data.
  * Release the semaphore before exiting.
  */
-s32
+static s32
 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 *data)
 {
 	u32 kmrnctrlsta;
@@ -1454,7 +1477,7 @@
  * at the offset using the kumeran interface.  Release semaphore
  * before exiting.
  */
-s32
+static s32
 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 data)
 {
 	u32 kmrnctrlsta;
@@ -1488,9 +1511,18 @@
 	s32 ret_val = E1000_SUCCESS;
 
 	DEBUGFUNC("e1000_read_mac_addr_80003es2lan");
-	if (e1000_check_alt_mac_addr_generic(hw))
-		ret_val = e1000_read_mac_addr_generic(hw);
+	/*
+	 * If there's an alternate MAC address place it in RAR0
+	 * so that it will override the Si installed default perm
+	 * address.
+	 */
+	ret_val = e1000_check_alt_mac_addr_generic(hw);
+	if (ret_val)
+		goto out;
 
+	ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
 	return (ret_val);
 }
 
--- a/usr/src/uts/common/io/e1000g/e1000_80003es2lan.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_80003es2lan.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.9 sol_anvik_patch
+ * IntelVersion: 1.10 v3-1-3_2009-8-20
  */
 #ifndef _E1000_80003ES2LAN_H_
 #define	_E1000_80003ES2LAN_H_
@@ -46,8 +46,11 @@
 #define	E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT	0x0000
 #define	E1000_KMRNCTRLSTA_OPMODE_E_IDLE		0x2000
 
+#define	E1000_KMRNCTRLSTA_OPMODE_MASK		0x000C
+#define	E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO	0x0004
+
 /* Gigabit Carry Extend Padding */
-#define	E1000_TCTL_EXT_GCEX_MASK		0x000FFC00
+#define	E1000_TCTL_EXT_GCEX_MASK	0x000FFC00
 
 #define	DEFAULT_TCTL_EXT_GCEX_80003ES2LAN	0x00010000
 
--- a/usr/src/uts/common/io/e1000g/e1000_82540.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82540.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.54 sol_anvik_patch
+ * IntelVersion: 1.57 v3-1-3_2009-8-20
  */
 
 /*
@@ -52,6 +52,7 @@
 static s32 e1000_setup_copper_link_82540(struct e1000_hw *hw);
 static s32 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw);
 static void e1000_power_down_phy_copper_82540(struct e1000_hw *hw);
+static s32 e1000_read_mac_addr_82540(struct e1000_hw *hw);
 
 /*
  * e1000_init_phy_params_82540 - Init PHY func ptrs.
@@ -184,6 +185,8 @@
 
 	/* bus type/speed/width */
 	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
+	/* function id */
+	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
 	/* reset */
 	mac->ops.reset_hw = e1000_reset_hw_82540;
 	/* hw initialization */
@@ -223,8 +226,12 @@
 	mac->ops.clear_vfta = e1000_clear_vfta_generic;
 	/* setting MTA */
 	mac->ops.mta_set = e1000_mta_set_generic;
+	/* ID LED init */
+	mac->ops.id_led_init = e1000_id_led_init_generic;
 	/* setup LED */
 	mac->ops.setup_led = e1000_setup_led_generic;
+	/* read mac address */
+	mac->ops.read_mac_addr = e1000_read_mac_addr_82540;
 	/* cleanup LED */
 	mac->ops.cleanup_led = e1000_cleanup_led_generic;
 	/* turn on/off LED */
@@ -254,10 +261,10 @@
 }
 
 /*
- *  e1000_reset_hw_82540 - Reset hardware
- *  @hw: pointer to the HW structure
+ * e1000_reset_hw_82540 - Reset hardware
+ * @hw: pointer to the HW structure
  *
- *  This resets the hardware into a known state.
+ * This resets the hardware into a known state.
  */
 static s32
 e1000_reset_hw_82540(struct e1000_hw *hw)
@@ -313,10 +320,10 @@
 }
 
 /*
- *  e1000_init_hw_82540 - Initialize hardware
- *  @hw: pointer to the HW structure
+ * e1000_init_hw_82540 - Initialize hardware
+ * @hw: pointer to the HW structure
  *
- *  This inits the hardware readying it for operation.
+ * This inits the hardware readying it for operation.
  */
 static s32
 e1000_init_hw_82540(struct e1000_hw *hw)
@@ -329,7 +336,7 @@
 	DEBUGFUNC("e1000_init_hw_82540");
 
 	/* Initialize identification LED */
-	ret_val = e1000_id_led_init_generic(hw);
+	ret_val = mac->ops.id_led_init(hw);
 	if (ret_val) {
 		DEBUGOUT("Error initializing identification LED\n");
 		/* This is not fatal and we should not stop init due to this */
@@ -393,13 +400,13 @@
 }
 
 /*
- *  e1000_setup_copper_link_82540 - Configure copper link settings
- *  @hw: pointer to the HW structure
+ * e1000_setup_copper_link_82540 - Configure copper link settings
+ * @hw: pointer to the HW structure
  *
- *  Calls the appropriate function to configure the link for auto-neg or forced
- *  speed and duplex.  Then we check for link, once link is established calls
- *  to configure collision distance and flow control are called.  If link is
- *  not established, we return -E1000_ERR_PHY (-2).
+ * Calls the appropriate function to configure the link for auto-neg or forced
+ * speed and duplex.  Then we check for link, once link is established calls
+ * to configure collision distance and flow control are called.  If link is
+ * not established, we return -E1000_ERR_PHY (-2).
  */
 static s32
 e1000_setup_copper_link_82540(struct e1000_hw *hw)
@@ -442,13 +449,13 @@
 }
 
 /*
- *  e1000_setup_fiber_serdes_link_82540 - Setup link for fiber/serdes
- *  @hw: pointer to the HW structure
+ * e1000_setup_fiber_serdes_link_82540 - Setup link for fiber/serdes
+ * @hw: pointer to the HW structure
  *
- *  Set the output amplitude to the value in the EEPROM and adjust the VCO
- *  speed to improve Bit Error Rate (BER) performance.  Configures collision
- *  distance and flow control for fiber and serdes links.  Upon successful
- *  setup, poll for link.
+ * Set the output amplitude to the value in the EEPROM and adjust the VCO
+ * speed to improve Bit Error Rate (BER) performance.  Configures collision
+ * distance and flow control for fiber and serdes links.  Upon successful
+ * setup, poll for link.
  */
 static s32
 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw)
@@ -485,10 +492,10 @@
 }
 
 /*
- *  e1000_adjust_serdes_amplitude_82540 - Adjust amplitude based on EEPROM
- *  @hw: pointer to the HW structure
+ * e1000_adjust_serdes_amplitude_82540 - Adjust amplitude based on EEPROM
+ * @hw: pointer to the HW structure
  *
- *  Adjust the SERDES output amplitude based on the EEPROM settings.
+ * Adjust the SERDES output amplitude based on the EEPROM settings.
  */
 static s32
 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw)
@@ -516,10 +523,10 @@
 }
 
 /*
- *  e1000_set_vco_speed_82540 - Set VCO speed for better performance
- *  @hw: pointer to the HW structure
+ * e1000_set_vco_speed_82540 - Set VCO speed for better performance
+ * @hw: pointer to the HW structure
  *
- *  Set the VCO speed to improve Bit Error Rate (BER) performance.
+ * Set the VCO speed to improve Bit Error Rate (BER) performance.
  */
 static s32
 e1000_set_vco_speed_82540(struct e1000_hw *hw)
@@ -574,13 +581,13 @@
 }
 
 /*
- *  e1000_set_phy_mode_82540 - Set PHY to class A mode
- *  @hw: pointer to the HW structure
+ * e1000_set_phy_mode_82540 - Set PHY to class A mode
+ * @hw: pointer to the HW structure
  *
- *  Sets the PHY to class A mode and assumes the following operations will
- *  follow to enable the new class mode:
- *    1.  Do a PHY soft reset.
- *    2.  Restart auto-negotiation or force link.
+ * Sets the PHY to class A mode and assumes the following operations will
+ * follow to enable the new class mode:
+ * 1.  Do a PHY soft reset.
+ * 2.  Restart auto-negotiation or force link.
  */
 static s32
 e1000_set_phy_mode_82540(struct e1000_hw *hw)
@@ -638,10 +645,10 @@
 }
 
 /*
- *  e1000_clear_hw_cntrs_82540 - Clear device specific hardware counters
- *  @hw: pointer to the HW structure
+ * e1000_clear_hw_cntrs_82540 - Clear device specific hardware counters
+ * @hw: pointer to the HW structure
  *
- *  Clears the hardware counters by reading the counter registers.
+ * Clears the hardware counters by reading the counter registers.
  */
 static void
 e1000_clear_hw_cntrs_82540(struct e1000_hw *hw)
@@ -674,3 +681,47 @@
 	(void) E1000_READ_REG(hw, E1000_MGTPDC);
 	(void) E1000_READ_REG(hw, E1000_MGTPTC);
 }
+
+/*
+ * e1000_read_mac_addr_82540 - Read device MAC address
+ * @hw: pointer to the HW structure
+ *
+ * Reads the device MAC address from the EEPROM and stores the value.
+ * Since devices with two ports use the same EEPROM, we increment the
+ * last bit in the MAC address for the second port.
+ *
+ * This version is being used over generic because of customer issues
+ * with VmWare and Virtual Box when using generic. It seems in
+ * the emulated 82545, RAR[0] does NOT have a valid address after a
+ * reset, this older method works and using this breaks nothing for
+ * these legacy adapters.
+ */
+s32
+e1000_read_mac_addr_82540(struct e1000_hw *hw)
+{
+	s32  ret_val = E1000_SUCCESS;
+	u16 offset, nvm_data, i;
+
+	DEBUGFUNC("e1000_read_mac_addr");
+
+	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
+		offset = i >> 1;
+		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			goto out;
+		}
+		hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
+		hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
+	}
+
+	/* Flip last bit of mac address if we're on second port */
+	if (hw->bus.func == E1000_FUNC_1)
+		hw->mac.perm_addr[5] ^= 1;
+
+	for (i = 0; i < ETH_ADDR_LEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+out:
+	return (ret_val);
+}
--- a/usr/src/uts/common/io/e1000g/e1000_82541.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82541.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.64 sol_anvik_patch
+ * IntelVersion: 1.68 v3-1-3_2009-8-20
  */
 
 /*
@@ -112,6 +112,7 @@
 		ret_val = -E1000_ERR_PHY;
 		goto out;
 	}
+
 out:
 	return (ret_val);
 }
@@ -237,6 +238,8 @@
 
 	/* bus type/speed/width */
 	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
+	/* function id */
+	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
 	/* reset */
 	mac->ops.reset_hw = e1000_reset_hw_82541;
 	/* hw initialization */
@@ -257,6 +260,8 @@
 	mac->ops.clear_vfta = e1000_clear_vfta_generic;
 	/* setting MTA */
 	mac->ops.mta_set = e1000_mta_set_generic;
+	/* ID LED init */
+	mac->ops.id_led_init = e1000_id_led_init_generic;
 	/* setup LED */
 	mac->ops.setup_led = e1000_setup_led_82541;
 	/* cleanup LED */
@@ -385,20 +390,17 @@
 	DEBUGFUNC("e1000_init_hw_82541");
 
 	/* Initialize identification LED */
-	ret_val = e1000_id_led_init_generic(hw);
+	ret_val = mac->ops.id_led_init(hw);
 	if (ret_val) {
 		DEBUGOUT("Error initializing identification LED\n");
 		/* This is not fatal and we should not stop init due to this */
 	}
 
-	/*
-	 * workaround - Store Default value in dev_spec->spd_default for
-	 * later use
-	 */
-	ret_val = hw->phy.ops.read_reg(hw,
-	    IGP01E1000_GMII_FIFO,
-	    &dev_spec->spd_default);
-	if (ret_val)
+	/* Storing the Speed Power Down  value for later use */
+	ret_val = hw->phy.ops.read_reg(hw,
+	    IGP01E1000_GMII_FIFO,
+	    &dev_spec->spd_default);
+	if (ret_val)
 		goto out;
 
 	pba = E1000_READ_REG(hw, E1000_PBA);
--- a/usr/src/uts/common/io/e1000g/e1000_82541.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82541.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.9 sol_anvik_patch
+ * IntelVersion: 1.9 v3-1-3_2009-8-20
  */
 #ifndef _E1000_82541_H_
 #define	_E1000_82541_H_
--- a/usr/src/uts/common/io/e1000g/e1000_82542.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82542.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.50 sol_anvik_patch
+ * IntelVersion: 1.53 v3-1-3_2009-8-20
  */
 
 /*
@@ -44,6 +44,7 @@
 static s32 e1000_led_off_82542(struct e1000_hw *hw);
 static void e1000_rar_set_82542(struct e1000_hw *hw, u8 *addr, u32 index);
 static void e1000_clear_hw_cntrs_82542(struct e1000_hw *hw);
+static s32  e1000_read_mac_addr_82542(struct e1000_hw *hw);
 
 /*
  * e1000_init_phy_params_82542 - Init PHY func ptrs.
@@ -112,6 +113,8 @@
 
 	/* bus type/speed/width */
 	mac->ops.get_bus_info = e1000_get_bus_info_82542;
+	/* function id */
+	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
 	/* reset */
 	mac->ops.reset_hw = e1000_reset_hw_82542;
 	/* hw initialization */
@@ -131,6 +134,8 @@
 	mac->ops.clear_vfta = e1000_clear_vfta_generic;
 	/* setting MTA */
 	mac->ops.mta_set = e1000_mta_set_generic;
+	/* read mac address */
+	mac->ops.read_mac_addr = e1000_read_mac_addr_82542;
 	/* set RAR */
 	mac->ops.rar_set = e1000_rar_set_82542;
 	/* turn on/off LED */
@@ -561,3 +566,35 @@
 	(void) E1000_READ_REG(hw, E1000_PTC1023);
 	(void) E1000_READ_REG(hw, E1000_PTC1522);
 }
+
+/*
+ * e1000_read_mac_addr_82542 - Read device MAC address
+ * @hw: pointer to the HW structure
+ *
+ * Reads the device MAC address from the EEPROM and stores the value.
+ */
+s32
+e1000_read_mac_addr_82542(struct e1000_hw *hw)
+{
+	s32  ret_val = E1000_SUCCESS;
+	u16 offset, nvm_data, i;
+
+	DEBUGFUNC("e1000_read_mac_addr");
+
+	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
+		offset = i >> 1;
+		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			goto out;
+		}
+		hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
+		hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
+	}
+
+	for (i = 0; i < ETH_ADDR_LEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+	out:
+		return (ret_val);
+}
--- a/usr/src/uts/common/io/e1000g/e1000_82543.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82543.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.67 sol_anvik_patch
+ * IntelVersion: 1.68 v3-1-3_2009-8-20
  */
 
 /*
@@ -212,6 +212,8 @@
 
 	/* bus type/speed/width */
 	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
+	/* function id */
+	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
 	/* reset */
 	mac->ops.reset_hw = e1000_reset_hw_82543;
 	/* hw initialization */
--- a/usr/src/uts/common/io/e1000g/e1000_82543.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82543.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.8 sol_anvik_patch
+ * IntelVersion: 1.8 v3-1-3_2009-8-20
  */
 #ifndef _E1000_82543_H_
 #define	_E1000_82543_H_
--- a/usr/src/uts/common/io/e1000g/e1000_82571.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82571.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.94 sol_anvik_patch
+ * IntelVersion: 1.113 v3-1-3_2009-8-20
  */
 
 /*
@@ -41,6 +41,7 @@
  * 82573E Gigabit Ethernet Controller (Copper)
  * 82573L Gigabit Ethernet Controller
  * 82574L Gigabit Network Connection
+ * 82583V Gigabit Network Connection
  */
 
 #include "e1000_api.h"
@@ -62,15 +63,13 @@
 static void e1000_clear_vfta_82571(struct e1000_hw *hw);
 static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
 static s32 e1000_led_on_82574(struct e1000_hw *hw);
-static void e1000_update_mc_addr_list_82571(struct e1000_hw *hw,
-    u8 *mc_addr_list, u32 mc_addr_count,
-    u32 rar_used_count, u32 rar_count);
 static s32 e1000_setup_link_82571(struct e1000_hw *hw);
 static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
+static s32  e1000_check_for_serdes_link_82571(struct e1000_hw *hw);
 static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
 static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data);
 static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
-static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw);
+static s32  e1000_get_hw_semaphore_82571(struct e1000_hw *hw);
 static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
 static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
 static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw);
@@ -152,6 +151,7 @@
 		}
 		break;
 	case e1000_82574:
+	case e1000_82583:
 		phy->type = e1000_phy_bm;
 		phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
 		phy->ops.get_info = e1000_get_phy_info_m88;
@@ -212,6 +212,7 @@
 	switch (hw->mac.type) {
 	case e1000_82573:
 	case e1000_82574:
+	case e1000_82583:
 		if (((eecd >> 15) & 0x3) == 0x3) {
 			nvm->type = e1000_nvm_flash_hw;
 			nvm->word_size = 2048;
@@ -262,6 +263,9 @@
 {
 	struct e1000_mac_info *mac = &hw->mac;
 	s32 ret_val = E1000_SUCCESS;
+	u32 swsm  = 0;
+	u32 swsm2  = 0;
+	bool force_clear_smbi = false;
 
 	DEBUGFUNC("e1000_init_mac_params_82571");
 
@@ -298,6 +302,16 @@
 
 	/* bus type/speed/width */
 	mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic;
+	/* function id */
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
+		mac->ops.set_lan_id = e1000_set_lan_id_single_port;
+		break;
+	default:
+		break;
+	}
 	/* reset */
 	mac->ops.reset_hw = e1000_reset_hw_82571;
 	/* hw initialization */
@@ -318,7 +332,7 @@
 		mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
 		break;
 	case e1000_media_type_internal_serdes:
-		mac->ops.check_for_link = e1000_check_for_serdes_link_generic;
+		mac->ops.check_for_link = e1000_check_for_serdes_link_82571;
 		break;
 	default:
 		ret_val = -E1000_ERR_CONFIG;
@@ -327,6 +341,7 @@
 	/* check management mode */
 	switch (hw->mac.type) {
 	case e1000_82574:
+	case e1000_82583:
 		mac->ops.check_mng_mode = e1000_check_mng_mode_82574;
 		break;
 	default:
@@ -334,7 +349,7 @@
 		break;
 	}
 	/* multicast address update */
-	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_82571;
+	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
 	/* writing VFTA */
 	mac->ops.write_vfta = e1000_write_vfta_generic;
 	/* clearing VFTA */
@@ -343,6 +358,8 @@
 	mac->ops.mta_set = e1000_mta_set_generic;
 	/* read mac address */
 	mac->ops.read_mac_addr = e1000_read_mac_addr_82571;
+	/* ID LED init */
+	mac->ops.id_led_init = e1000_id_led_init_generic;
 	/* blink LED */
 	mac->ops.blink_led = e1000_blink_led_generic;
 	/* setup LED */
@@ -352,6 +369,7 @@
 	/* turn on/off LED */
 	switch (hw->mac.type) {
 	case e1000_82574:
+	case e1000_82583:
 		mac->ops.led_on = e1000_led_on_82574;
 		break;
 	default:
@@ -367,6 +385,51 @@
 	    ? e1000_get_speed_and_duplex_copper_generic
 	    : e1000_get_speed_and_duplex_fiber_serdes_generic;
 
+	/*
+	 * Ensure that the inter-port SWSM.SMBI lock bit is clear before
+	 * first NVM or PHY acess. This should be done for single-port
+	 * devices, and for one port only on dual-port devices so that
+	 * for those devices we can still use the SMBI lock to synchronize
+	 * inter-port accesses to the PHY & NVM.
+	 */
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		swsm2 = E1000_READ_REG(hw, E1000_SWSM2);
+
+		if (!(swsm2 & E1000_SWSM2_LOCK)) {
+			/* Only do this for the first interface on this card */
+			E1000_WRITE_REG(hw, E1000_SWSM2,
+			    swsm2 | E1000_SWSM2_LOCK);
+				force_clear_smbi = true;
+			} else
+				force_clear_smbi = false;
+		break;
+	default:
+		force_clear_smbi = true;
+		break;
+	}
+
+	if (force_clear_smbi) {
+		/* Make sure SWSM.SMBI is clear */
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		if (swsm & E1000_SWSM_SMBI) {
+			/*
+			 * This bit should not be set on a first interface, and
+			 * indicates that the bootagent or EFI code has
+			 * improperly left this bit enabled
+			 */
+			DEBUGOUT("Please update your 82571 Bootagent\n");
+		}
+		E1000_WRITE_REG(hw, E1000_SWSM, swsm & ~E1000_SWSM_SMBI);
+	}
+
+	/*
+	 * Initialze device specific counter of SMBI acquisition
+	 * timeouts.
+	 */
+	hw->dev_spec._82571.smb_counter = 0;
+
 out:
 	return (ret_val);
 }
@@ -417,6 +480,7 @@
 		ret_val = e1000_get_phy_id(hw);
 		break;
 	case e1000_82574:
+	case e1000_82583:
 		ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
 		if (ret_val)
 			goto out;
@@ -445,18 +509,44 @@
  *
  * Acquire the HW semaphore to access the PHY or NVM
  */
-static s32
+s32
 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
 {
 	u32 swsm;
 	s32 ret_val = E1000_SUCCESS;
-	s32 timeout = hw->nvm.word_size + 1;
+	s32 sw_timeout = hw->nvm.word_size + 1;
+	s32 fw_timeout = hw->nvm.word_size + 1;
 	s32 i = 0;
 
 	DEBUGFUNC("e1000_get_hw_semaphore_82571");
 
+	/*
+	 * If we have timedout 3 times on trying to acquire
+	 * the inter-port SMBI semaphore, there is old code
+	 * operating on the other port, and it is not
+	 * releasing SMBI. Modify the number of times that
+	 * we try for the semaphore to interwork with this
+	 * older code.
+	 */
+	if (hw->dev_spec._82571.smb_counter > 2)
+		sw_timeout = 1;
+
+	/* Get the SW semaphore */
+	while (i < sw_timeout) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		if (!(swsm & E1000_SWSM_SMBI))
+			break;
+
+		usec_delay(50);
+		i++;
+	}
+
+	if (i == sw_timeout) {
+		DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+		hw->dev_spec._82571.smb_counter++;
+	}
 	/* Get the FW semaphore. */
-	for (i = 0; i < timeout; i++) {
+	for (i = 0; i < fw_timeout; i++) {
 		swsm = E1000_READ_REG(hw, E1000_SWSM);
 		E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
 
@@ -467,9 +557,9 @@
 		usec_delay(50);
 	}
 
-	if (i == timeout) {
+	if (i == fw_timeout) {
 		/* Release semaphores */
-		e1000_put_hw_semaphore_generic(hw);
+		e1000_put_hw_semaphore_82571(hw);
 		DEBUGOUT("Driver can't access the NVM\n");
 		ret_val = -E1000_ERR_NVM;
 		goto out;
@@ -485,16 +575,16 @@
  *
  * Release hardware semaphore used to access the PHY or NVM
  */
-static void
+void
 e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
 {
 	u32 swsm;
 
-	DEBUGFUNC("e1000_put_hw_semaphore_82571");
+	DEBUGFUNC("e1000_put_hw_semaphore_generic");
 
 	swsm = E1000_READ_REG(hw, E1000_SWSM);
 
-	swsm &= ~E1000_SWSM_SWESMBI;
+	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
 
 	E1000_WRITE_REG(hw, E1000_SWSM, swsm);
 }
@@ -519,8 +609,15 @@
 	if (ret_val)
 		goto out;
 
-	if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574)
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
+		break;
+	default:
 		ret_val = e1000_acquire_nvm_generic(hw);
+		break;
+	}
 
 	if (ret_val)
 		e1000_put_hw_semaphore_82571(hw);
@@ -567,6 +664,7 @@
 	switch (hw->mac.type) {
 	case e1000_82573:
 	case e1000_82574:
+	case e1000_82583:
 		ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
 		break;
 	case e1000_82571:
@@ -747,6 +845,7 @@
 	}
 	if (!timeout) {
 		DEBUGOUT("MNG configuration cycle has not completed.\n");
+		ret_val = -E1000_ERR_RESET;
 		goto out;
 	}
 
@@ -875,7 +974,10 @@
 	 * Must acquire the MDIO ownership before MAC reset. Ownership
 	 * defaults to firmware after a reset.
 	 */
-	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
 		extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
 
@@ -891,6 +993,9 @@
 			msec_delay(2);
 			i++;
 		} while (i < MDIO_OWNERSHIP_TIMEOUT);
+		break;
+	default:
+		break;
 	}
 
 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
@@ -916,15 +1021,30 @@
 	 * Need to wait for Phy configuration completion before accessing
 	 * NVM and Phy.
 	 */
-	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574)
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
 		msec_delay(25);
+		break;
+	default:
+		break;
+	}
 
 	/* Clear any pending interrupt events. */
 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
 	(void) E1000_READ_REG(hw, E1000_ICR);
 
-	if (!(e1000_check_alt_mac_addr_generic(hw)))
-		e1000_set_laa_state_82571(hw, true);
+	/* Install any alternate MAC address into RAR0 */
+	ret_val = e1000_check_alt_mac_addr_generic(hw);
+	if (ret_val)
+		goto out;
+
+	e1000_set_laa_state_82571(hw, true);
+
+	/* Reinitialize the 82571 serdes link state machine */
+	if (hw->phy.media_type == e1000_media_type_internal_serdes)
+		hw->mac.serdes_link_state = e1000_serdes_link_down;
 
 out:
 	return (ret_val);
@@ -949,7 +1069,7 @@
 	e1000_initialize_hw_bits_82571(hw);
 
 	/* Initialize identification LED */
-	ret_val = e1000_id_led_init_generic(hw);
+	ret_val = mac->ops.id_led_init(hw);
 	if (ret_val) {
 		DEBUGOUT("Error initializing identification LED\n");
 		/* This is not fatal and we should not stop init due to this */
@@ -985,17 +1105,22 @@
 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data);
 
 	/* ...for both queues. */
-	if (mac->type != e1000_82573 && mac->type != e1000_82574) {
+	switch (mac->type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
+		e1000_enable_tx_pkt_filtering_generic(hw);
+		reg_data = E1000_READ_REG(hw, E1000_GCR);
+		reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+		E1000_WRITE_REG(hw, E1000_GCR, reg_data);
+		break;
+	default:
 		reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1));
 		reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
 		    E1000_TXDCTL_FULL_TX_DESC_WB |
 		    E1000_TXDCTL_COUNT_DESC;
 		E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data);
-	} else {
-		(void) e1000_enable_tx_pkt_filtering_generic(hw);
-		reg_data = E1000_READ_REG(hw, E1000_GCR);
-		reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
-		E1000_WRITE_REG(hw, E1000_GCR, reg_data);
+		break;
 	}
 
 	/*
@@ -1063,25 +1188,69 @@
 	}
 
 	/* Device Control */
-	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
 		reg = E1000_READ_REG(hw, E1000_CTRL);
 		reg &= ~(1 << 29);
 		E1000_WRITE_REG(hw, E1000_CTRL, reg);
+		break;
+	default:
+		break;
 	}
 
 	/* Extended Device Control */
-	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
 		reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
 		reg &= ~(1 << 23);
 		reg |= (1 << 22);
 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+		break;
+	default:
+		break;
+	}
+
+	if (hw->mac.type == e1000_82571) {
+		reg = E1000_READ_REG(hw, E1000_PBA_ECC);
+		reg |= E1000_PBA_ECC_CORR_EN;
+		E1000_WRITE_REG(hw, E1000_PBA_ECC, reg);
 	}
 
-	/* PCI-Ex Control Register */
-	if (hw->mac.type == e1000_82574) {
+	/*
+	 * Workaround for hardware errata.
+	 * Ensure that DMA Dynamic Clock gating is disabled on 82571 and 82572
+	 */
+	if ((hw->mac.type == e1000_82571) ||
+	    (hw->mac.type == e1000_82572)) {
+		reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+		reg &= ~E1000_CTRL_EXT_DMA_DYN_CLK_EN;
+		E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+	}
+
+	/* PCI-Ex Control Registers */
+	switch (hw->mac.type) {
+	case e1000_82574:
+	case e1000_82583:
 		reg = E1000_READ_REG(hw, E1000_GCR);
 		reg |= (1 << 22);
 		E1000_WRITE_REG(hw, E1000_GCR, reg);
+		/*
+		 * Workaround for hardware errata.
+		 * apply workaround for hardware errata documented in errata
+		 * docs Fixes issue where some error prone or unreliable PCIe
+		 * completions are occurring, particularly with ASPM enabled.
+		 * Without fix, issue can cause tx timeouts.
+		 */
+		reg = E1000_READ_REG(hw, E1000_GCR2);
+		reg |= 1;
+		E1000_WRITE_REG(hw, E1000_GCR2, reg);
+		break;
+	default:
+		break;
 	}
 }
 
@@ -1102,31 +1271,41 @@
 
 	DEBUGFUNC("e1000_clear_vfta_82571");
 
-	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
 		if (hw->mng_cookie.vlan_id != 0) {
 			/*
-			 * The VFTA is a 4096b bit-field, each identifying a
-			 * single VLAN ID.  The following operations determine
-			 * which 32b entry (i.e. offset) into the array we
-			 * want to set the VLAN ID (i.e. bit) of the
-			 * manageability unit.
+			 * The VFTA is a 4096b bit-field, each identifying
+			 * a single VLAN ID.  The following operations
+			 * determine which 32b entry (i.e. offset) into the
+			 * array we want to set the VLAN ID (i.e. bit) of
+			 * the manageability unit.
 			 */
 			vfta_offset = (hw->mng_cookie.vlan_id >>
-			    E1000_VFTA_ENTRY_SHIFT) &
-			    E1000_VFTA_ENTRY_MASK;
+			    E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK;
+
 			vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
 			    E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
 		}
-	}
-	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
-		/*
-		 * If the offset we want to clear is the same offset of the
-		 * manageability VLAN ID, then clear all bits except that of
-		 * the manageability unit.
-		 */
-		vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
-		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value);
-		E1000_WRITE_FLUSH(hw);
+
+		for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE;
+		    offset ++) {
+			/*
+			 * If the offset we want to clear is the same offset of
+			 * the manageability VLAN ID, then clear all bits except
+			 * that of the manageability unit
+			 */
+			vfta_value = (offset == vfta_offset) ?
+			    vfta_bit_in_reg : 0;
+			E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset,
+			    vfta_value);
+			E1000_WRITE_FLUSH(hw);
+		}
+		break;
+	default:
+		break;
 	}
 }
 
@@ -1179,33 +1358,6 @@
 }
 
 /*
- * e1000_update_mc_addr_list_82571 - Update Multicast addresses
- * @hw: pointer to the HW structure
- * @mc_addr_list: array of multicast addresses to program
- * @mc_addr_count: number of multicast addresses to program
- * @rar_used_count: the first RAR register free to program
- * @rar_count: total number of supported Receive Address Registers
- *
- * Updates the Receive Address Registers and Multicast Table Array.
- * The caller must have a packed mc_addr_list of multicast addresses.
- * The parameter rar_count will usually be hw->mac.rar_entry_count
- * unless there are workarounds that change this.
- */
-static void
-e1000_update_mc_addr_list_82571(struct e1000_hw *hw,
-    u8 *mc_addr_list, u32 mc_addr_count,
-    u32 rar_used_count, u32 rar_count)
-{
-	DEBUGFUNC("e1000_update_mc_addr_list_82571");
-
-	if (e1000_get_laa_state_82571(hw))
-		rar_count--;
-
-	e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count,
-	    rar_used_count, rar_count);
-}
-
-/*
  * e1000_setup_link_82571 - Setup flow control and link settings
  * @hw: pointer to the HW structure
  *
@@ -1224,10 +1376,16 @@
 	 * 82573 does not have a word in the NVM to determine the default flow
 	 * control setting, so we explicitly set it to full.
 	 */
-	if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
-	    hw->fc.requested_mode == e1000_fc_default)
-		hw->fc.requested_mode = e1000_fc_full;
-
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
+		if (hw->fc.requested_mode == e1000_fc_default)
+			hw->fc.requested_mode = e1000_fc_full;
+		break;
+	default:
+		break;
+	}
 	return (e1000_setup_link_generic(hw));
 }
 
@@ -1242,7 +1400,7 @@
 static s32
 e1000_setup_copper_link_82571(struct e1000_hw *hw)
 {
-	u32 ctrl, led_ctrl;
+	u32 ctrl;
 	s32 ret_val;
 
 	DEBUGFUNC("e1000_setup_copper_link_82571");
@@ -1259,11 +1417,6 @@
 		break;
 	case e1000_phy_igp_2:
 		ret_val = e1000_copper_link_setup_igp(hw);
-		/* Setup activity LED */
-		led_ctrl = E1000_READ_REG(hw, E1000_LEDCTL);
-		led_ctrl &= IGP_ACTIVITY_LED_MASK;
-		led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
-		E1000_WRITE_REG(hw, E1000_LEDCTL, led_ctrl);
 		break;
 	default:
 		ret_val = -E1000_ERR_PHY;
@@ -1312,6 +1465,157 @@
 }
 
 /*
+ * e1000_check_for_serdes_link_82571 - Check for link (Serdes)
+ * @hw: pointer to the HW structure
+ *
+ * Reports the link state as up or down.
+ *
+ * If autonegotiation is supported by the link partner, the link state is
+ * determined by the result of autongotiation. This is the most likely case.
+ * If autonegotiation is not supported by the link partner, and the link
+ * has a valid signal, force the link up.
+ *
+ * The link state is represented internally here by 4 states:
+ *
+ * 1) down
+ * 2) autoneg_progress
+ * 3) autoneg_complete (the link sucessfully autonegotiated)
+ * 4) forced_up (the link has been forced up, it did not autonegotiate)
+ */
+s32
+e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_check_for_serdes_link_82571");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+	if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) {
+
+		/* Receiver is synchronized with no invalid bits.  */
+		switch (mac->serdes_link_state) {
+		case e1000_serdes_link_autoneg_complete:
+			if (!(status & E1000_STATUS_LU)) {
+				/*
+				 * We have lost link, retry autoneg before
+				 * reporting link failure
+				 */
+				mac->serdes_link_state =
+				    e1000_serdes_link_autoneg_progress;
+				mac->serdes_has_link = false;
+				DEBUGOUT("AN_UP     -> AN_PROG\n");
+			}
+			break;
+
+		case e1000_serdes_link_forced_up:
+			/*
+			 * If we are receiving /C/ ordered sets, re-enable
+			 * auto-negotiation in the TXCW register and disable
+			 * forced link in the Device Control register in an
+			 * attempt to auto-negotiate with our link partner.
+			 */
+			if (rxcw & E1000_RXCW_C) {
+				/* Enable autoneg, and unforce link up */
+				E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+				E1000_WRITE_REG(hw, E1000_CTRL,
+				    (ctrl & ~E1000_CTRL_SLU));
+				mac->serdes_link_state =
+				    e1000_serdes_link_autoneg_progress;
+				mac->serdes_has_link = false;
+				DEBUGOUT("FORCED_UP -> AN_PROG\n");
+			}
+			break;
+
+		case e1000_serdes_link_autoneg_progress:
+			if (rxcw & E1000_RXCW_C) {
+				/*
+				 * We received /C/ ordered sets, meaning the
+				 * link partner has autonegotiated, and we can
+				 * trust the Link Up (LU) status bit
+				 */
+				if (status & E1000_STATUS_LU) {
+					mac->serdes_link_state =
+					    e1000_serdes_link_autoneg_complete;
+					DEBUGOUT("AN_PROG   -> AN_UP\n");
+					mac->serdes_has_link = true;
+				} else {
+					/* Autoneg completed, but failed */
+					mac->serdes_link_state =
+					    e1000_serdes_link_down;
+					DEBUGOUT("AN_PROG   -> DOWN\n");
+				}
+			} else {
+				/*
+				 * The link partner did not autoneg.
+				 * Force link up and full duplex, and change
+				 * state to forced.
+				 */
+				E1000_WRITE_REG(hw, E1000_TXCW,
+				    (mac->txcw & ~E1000_TXCW_ANE));
+				ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+				E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+				/* Configure Flow Control after link up. */
+				ret_val =
+				    e1000_config_fc_after_link_up_generic(hw);
+				if (ret_val) {
+					DEBUGOUT("Error config flow control\n");
+					break;
+				}
+				mac->serdes_link_state =
+				    e1000_serdes_link_forced_up;
+				mac->serdes_has_link = true;
+				DEBUGOUT("AN_PROG   -> FORCED_UP\n");
+			}
+			break;
+
+		case e1000_serdes_link_down:
+		default:
+			/*
+			 * The link was down but the receiver has now gained
+			 * valid sync, so lets see if we can bring the link
+			 * up.
+			 */
+			E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+			E1000_WRITE_REG(hw, E1000_CTRL,
+			    (ctrl & ~E1000_CTRL_SLU));
+			mac->serdes_link_state =
+			    e1000_serdes_link_autoneg_progress;
+			DEBUGOUT("DOWN      -> AN_PROG\n");
+			break;
+		}
+	} else {
+		if (!(rxcw & E1000_RXCW_SYNCH)) {
+			mac->serdes_has_link = false;
+			mac->serdes_link_state = e1000_serdes_link_down;
+			DEBUGOUT("ANYSTATE  -> DOWN\n");
+		} else {
+			/*
+			 * We have sync, and can tolerate one
+			 * invalid (IV) codeword before declaring
+			 * link down, so reread to look again
+			 */
+			usec_delay(10);
+			rxcw = E1000_READ_REG(hw, E1000_RXCW);
+			if (rxcw & E1000_RXCW_IV) {
+				mac->serdes_link_state = e1000_serdes_link_down;
+				mac->serdes_has_link = false;
+				DEBUGOUT("ANYSTATE  -> DOWN\n");
+			}
+		}
+	}
+
+	return (ret_val);
+}
+
+/*
  * e1000_valid_led_default_82571 - Verify a valid default LED config
  * @hw: pointer to the HW structure
  * @data: pointer to the NVM (EEPROM)
@@ -1332,11 +1636,19 @@
 		goto out;
 	}
 
-	if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
-	    *data == ID_LED_RESERVED_F746)
-		*data = ID_LED_DEFAULT_82573;
-	else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
-		*data = ID_LED_DEFAULT;
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
+		if (*data == ID_LED_RESERVED_F746)
+			*data = ID_LED_DEFAULT_82573;
+		break;
+	default:
+		if (*data == ID_LED_RESERVED_0000 ||
+		    *data == ID_LED_RESERVED_FFFF)
+			*data = ID_LED_DEFAULT;
+		break;
+	}
 
 out:
 	return (ret_val);
@@ -1455,9 +1767,19 @@
 	s32 ret_val = E1000_SUCCESS;
 
 	DEBUGFUNC("e1000_read_mac_addr_82571");
-	if (e1000_check_alt_mac_addr_generic(hw))
-		ret_val = e1000_read_mac_addr_generic(hw);
 
+	/*
+	 * If there's an alternate MAC address place it in RAR0
+	 * so that it will override the Si installed default perm
+	 * address.
+	 */
+	ret_val = e1000_check_alt_mac_addr_generic(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
 	return (ret_val);
 }
 
@@ -1494,6 +1816,7 @@
 	DEBUGFUNC("e1000_clear_hw_cntrs_82571");
 
 	e1000_clear_hw_cntrs_base_generic(hw);
+
 	(void) E1000_READ_REG(hw, E1000_PRC64);
 	(void) E1000_READ_REG(hw, E1000_PRC127);
 	(void) E1000_READ_REG(hw, E1000_PRC255);
--- a/usr/src/uts/common/io/e1000g/e1000_82571.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82571.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.16 sol_anvik_patch
+ * IntelVersion: 1.16 v3-1-3_2009-8-20
  */
 #ifndef _E1000_82571_H_
 #define	_E1000_82571_H_
--- a/usr/src/uts/common/io/e1000g/e1000_api.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_api.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.107 sol_anvik_patch
+ * IntelVersion: 1.124 v3-1-3_2009-8-20
  */
 
 #include "e1000_api.h"
@@ -211,8 +211,12 @@
 		mac->type = e1000_82573;
 		break;
 	case E1000_DEV_ID_82574L:
+	case E1000_DEV_ID_82574LA:
 		mac->type = e1000_82574;
 		break;
+	case E1000_DEV_ID_82583V:
+		mac->type = e1000_82583;
+		break;
 	case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
 	case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
 	case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
@@ -244,8 +248,15 @@
 		break;
 	case E1000_DEV_ID_ICH10_D_BM_LM:
 	case E1000_DEV_ID_ICH10_D_BM_LF:
+	case E1000_DEV_ID_ICH10_HANKSVILLE:
 		mac->type = e1000_ich10lan;
 		break;
+	case E1000_DEV_ID_PCH_D_HV_DM:
+	case E1000_DEV_ID_PCH_D_HV_DC:
+	case E1000_DEV_ID_PCH_M_HV_LM:
+	case E1000_DEV_ID_PCH_M_HV_LC:
+		mac->type = e1000_pchlan;
+		break;
 	default:
 		/* Should never have loaded on this device */
 		ret_val = -E1000_ERR_MAC_INIT;
@@ -278,6 +289,7 @@
 		DEBUGOUT("ERROR: MAC type could not be set properly.\n");
 		goto out;
 	}
+
 	if (!hw->hw_addr) {
 		DEBUGOUT("ERROR: Registers not mapped\n");
 		ret_val = -E1000_ERR_CONFIG;
@@ -322,6 +334,7 @@
 	case e1000_82572:
 	case e1000_82573:
 	case e1000_82574:
+	case e1000_82583:
 		e1000_init_function_pointers_82571(hw);
 		break;
 	case e1000_80003es2lan:
@@ -330,6 +343,7 @@
 	case e1000_ich8lan:
 	case e1000_ich9lan:
 	case e1000_ich10lan:
+	case e1000_pchlan:
 		e1000_init_function_pointers_ich8lan(hw);
 		break;
 	default:
@@ -354,7 +368,6 @@
 		ret_val = e1000_init_phy_params(hw);
 		if (ret_val)
 			goto out;
-
 	}
 
 out:
@@ -413,26 +426,17 @@
  * @hw: pointer to the HW structure
  * @mc_addr_list: array of multicast addresses to program
  * @mc_addr_count: number of multicast addresses to program
- * @rar_used_count: the first RAR register free to program
- * @rar_count: total number of supported Receive Address Registers
  *
- * Updates the Receive Address Registers and Multicast Table Array.
+ * Updates the Multicast Table Array.
  * The caller must have a packed mc_addr_list of multicast addresses.
- * The parameter rar_count will usually be hw->mac.rar_entry_count
- * unless there are workarounds that change this.  Currently no func pointer
- * exists and all implementations are handled in the generic version of this
- * function.
  */
 void
 e1000_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list,
-    u32 mc_addr_count, u32 rar_used_count, u32 rar_count)
+    u32 mc_addr_count)
 {
 	if (hw->mac.ops.update_mc_addr_list)
-		hw->mac.ops.update_mc_addr_list(hw,
-		    mc_addr_list,
-		    mc_addr_count,
-		    rar_used_count,
-		    rar_count);
+		hw->mac.ops.update_mc_addr_list(hw, mc_addr_list,
+		    mc_addr_count);
 }
 
 /*
@@ -615,6 +619,22 @@
 }
 
 /*
+ *  e1000_id_led_init - store LED configurations in SW
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the LED config in SW. This is a function pointer entry point
+ *  called by drivers.
+ */
+s32
+e1000_id_led_init(struct e1000_hw *hw)
+{
+	if (hw->mac.ops.id_led_init)
+		return (hw->mac.ops.id_led_init(hw));
+
+	return (E1000_SUCCESS);
+}
+
+/*
  * e1000_led_on - Turn on SW controllable LED
  * @hw: pointer to the HW structure
  *
--- a/usr/src/uts/common/io/e1000g/e1000_api.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_api.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.50 sol_anvik_patch
+ * IntelVersion: 1.53 v3-1-3_2009-8-20
  */
 #ifndef _E1000_API_H_
 #define	_E1000_API_H_
@@ -63,14 +63,14 @@
 void e1000_mta_set(struct e1000_hw *hw, u32 hash_value);
 u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr);
 void e1000_update_mc_addr_list(struct e1000_hw *hw,
-    u8 *mc_addr_list, u32 mc_addr_count,
-    u32 rar_used_count, u32 rar_count);
+    u8 *mc_addr_list, u32 mc_addr_count);
 s32 e1000_setup_led(struct e1000_hw *hw);
 s32 e1000_cleanup_led(struct e1000_hw *hw);
 s32 e1000_check_reset_block(struct e1000_hw *hw);
 s32 e1000_blink_led(struct e1000_hw *hw);
 s32 e1000_led_on(struct e1000_hw *hw);
 s32 e1000_led_off(struct e1000_hw *hw);
+s32 e1000_id_led_init(struct e1000_hw *hw);
 void e1000_reset_adaptive(struct e1000_hw *hw);
 void e1000_update_adaptive(struct e1000_hw *hw);
 s32 e1000_get_cable_length(struct e1000_hw *hw);
@@ -86,7 +86,7 @@
 void e1000_power_up_phy(struct e1000_hw *hw);
 void e1000_power_down_phy(struct e1000_hw *hw);
 s32 e1000_read_mac_addr(struct e1000_hw *hw);
-s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
+s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *part_num);
 void e1000_reload_nvm(struct e1000_hw *hw);
 s32 e1000_update_nvm_checksum(struct e1000_hw *hw);
 s32 e1000_validate_nvm_checksum(struct e1000_hw *hw);
--- a/usr/src/uts/common/io/e1000g/e1000_defines.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_defines.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,15 +24,11 @@
  */
 
 /*
- * IntelVersion: 1.79 sol_anvik_patch
+ * IntelVersion: 1.116 v3-1-3_2009-8-20
  */
 #ifndef _E1000_DEFINES_H_
 #define	_E1000_DEFINES_H_
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Number of Transmit and Receive Descriptors must be a multiple of 8 */
 #define	REQ_TX_DESCRIPTOR_MULTIPLE	8
 #define	REQ_RX_DESCRIPTOR_MULTIPLE	8
@@ -62,19 +58,33 @@
 #define	E1000_WUFC_FLX1_PHY	0x00002000 /* Flexible Filter 1 Enable */
 #define	E1000_WUFC_FLX2_PHY	0x00004000 /* Flexible Filter 2 Enable */
 #define	E1000_WUFC_FLX3_PHY	0x00008000 /* Flexible Filter 3 Enable */
+#define	E1000_WUFC_FLX4_PHY	0x00000200 /* Flexible Filter 4 Enable */
+#define	E1000_WUFC_FLX5_PHY	0x00000400 /* Flexible Filter 5 Enable */
 #define	E1000_WUFC_IGNORE_TCO	0x00008000 /* Ignore WakeOn TCO packets */
 #define	E1000_WUFC_FLX0	0x00010000	/* Flexible Filter 0 Enable */
 #define	E1000_WUFC_FLX1	0x00020000	/* Flexible Filter 1 Enable */
 #define	E1000_WUFC_FLX2	0x00040000	/* Flexible Filter 2 Enable */
 #define	E1000_WUFC_FLX3	0x00080000	/* Flexible Filter 3 Enable */
+#define	E1000_WUFC_FLX4 0x00100000	/* Flexible Filter 4 Enable */
+#define	E1000_WUFC_FLX5 0x00200000	/* Flexible Filter 5 Enable */
 /* Mask for all wakeup filters */
 #define	E1000_WUFC_ALL_FILTERS_PHY_4 0x0000F0FF
 #define	E1000_WUFC_FLX_OFFSET_PHY 12 /* Offset to the Flexible Filters bits */
 /* Mask for 4 flexible filters */
-#define	E1000_WUFC_FLX_FILTERS_PHY_4 0x0000F000
+#define	E1000_WUFC_FLX_FILTERS_PHY_4	0x0000F000
+/* Mask for 6 wakeup filters */
+#define	E1000_WUFC_ALL_FILTERS_PHY_6	0x0000F6FF
+/* Mask for 6 flexible filters */
+#define	E1000_WUFC_FLX_FILTERS_PHY_6	0x0000F600
 #define	E1000_WUFC_ALL_FILTERS	0x000F00FF /* Mask for all wakeup filters */
-#define	E1000_WUFC_FLX_OFFSET	16 /* Offset to the Flexible Filters bits */
-#define	E1000_WUFC_FLX_FILTERS	0x000F0000 /* Mask for the 4 flexible filters */
+/* Mask for all 6 wakeup filters */
+#define	E1000_WUFC_ALL_FILTERS_6	0x003F00FF
+/* Offset to the Flexible Filters bits */
+#define	E1000_WUFC_FLX_OFFSET	16
+/* Mask for the 4 flexible filters */
+#define	E1000_WUFC_FLX_FILTERS	0x000F0000
+/* Mask for 6 flexible filters */
+#define	E1000_WUFC_FLX_FILTERS_6  0x003F0000
 
 /* Wake Up Status */
 #define	E1000_WUS_LNKC			E1000_WUFC_LNKC
@@ -89,23 +99,34 @@
 #define	E1000_WUS_FLX1_PHY		E1000_WUFC_FLX1_PHY
 #define	E1000_WUS_FLX2_PHY		E1000_WUFC_FLX2_PHY
 #define	E1000_WUS_FLX3_PHY		E1000_WUFC_FLX3_PHY
+#define	E1000_WUS_FLX4_PHY		E1000_WUFC_FLX4_PHY
+#define	E1000_WUS_FLX5_PHY		E1000_WUFC_FLX5_PHY
+
 #define	E1000_WUS_FLX_FILTERS_PHY_4	E1000_WUFC_FLX_FILTERS_PHY_4
 #define	E1000_WUS_FLX0			E1000_WUFC_FLX0
 #define	E1000_WUS_FLX1			E1000_WUFC_FLX1
 #define	E1000_WUS_FLX2			E1000_WUFC_FLX2
 #define	E1000_WUS_FLX3			E1000_WUFC_FLX3
+#define	E1000_WUS_FLX4			E1000_WUFC_FLX4
+#define	E1000_WUS_FLX5			E1000_WUFC_FLX5
+
 #define	E1000_WUS_FLX_FILTERS		E1000_WUFC_FLX_FILTERS
+#define	E1000_WUS_FLX_FILTERS_6		E1000_WUFC_FLX_FILTERS_6
+#define	E1000_WUS_FLX_FILTERS_PHY_6	E1000_WUFC_FLX_FILTERS_PHY_6
 
 /* Wake Up Packet Length */
 #define	E1000_WUPL_LENGTH_MASK	0x0FFF	/* Only the lower 12 bits are valid */
 
 /* Four Flexible Filters are supported */
 #define	E1000_FLEXIBLE_FILTER_COUNT_MAX	4
+/* Six Flexible Filters are supported */
+#define	E1000_FLEXIBLE_FILTER_COUNT_MAX_6   6
 
 /* Each Flexible Filter is at most 128 (0x80) bytes in length */
 #define	E1000_FLEXIBLE_FILTER_SIZE_MAX	128
 
 #define	E1000_FFLT_SIZE	E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define	E1000_FFLT_SIZE_6 E1000_FLEXIBLE_FILTER_COUNT_MAX_6
 #define	E1000_FFMT_SIZE	E1000_FLEXIBLE_FILTER_SIZE_MAX
 #define	E1000_FFVT_SIZE	E1000_FLEXIBLE_FILTER_SIZE_MAX
 
@@ -120,17 +141,19 @@
 #define	E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */
 #define	E1000_CTRL_EXT_PHY_INT	E1000_CTRL_EXT_SDP5_DATA
 #define	E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */
-#define	E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */
+#define	E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
 /* SDP 4/5 (bits 8,9) are reserved in >= 82575 */
 #define	E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
 #define	E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
 #define	E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
-#define	E1000_CTRL_EXT_SDP7_DIR  0x00000800 /* Direction of SDP7 0=in 1=out */
+#define	E1000_CTRL_EXT_SDP3_DIR  0x00000800 /* Direction of SDP3 0=in 1=out */
 #define	E1000_CTRL_EXT_ASDCHK	0x00001000  /* Initiate an ASD sequence */
 #define	E1000_CTRL_EXT_EE_RST	0x00002000  /* Reinitialize from EEPROM */
 #define	E1000_CTRL_EXT_IPS	0x00004000  /* Invert Power State */
 #define	E1000_CTRL_EXT_SPD_BYPS	0x00008000  /* Speed Select Bypass */
 #define	E1000_CTRL_EXT_RO_DIS	0x00020000  /* Relaxed Ordering disable */
+/* DMA Dynamic Clock Gating */
+#define	E1000_CTRL_EXT_DMA_DYN_CLK_EN	0x00080000
 #define	E1000_CTRL_EXT_LINK_MODE_MASK	0x00C00000
 #define	E1000_CTRL_EXT_LINK_MODE_GMII	0x00000000
 #define	E1000_CTRL_EXT_LINK_MODE_TBI	0x00C00000
@@ -149,8 +172,6 @@
 #define	E1000_CTRL_EXT_DRV_LOAD	0x10000000 /* Driver loaded bit for FW */
 /* IAME enable bit (27) was removed in >= 82575 */
 #define	E1000_CTRL_EXT_IAME	0x08000000 /* Int acknowledge Auto-mask */
-/* Clear Interrupt timers after IMS clear */
-#define	E1000_CTRL_EXT_INT_TIMER_CLR	0x20000000
 /* packet buffer parity error detection enabled */
 #define	E1000_CRTL_EXT_PB_PAREN		0x01000000
 /* descriptor FIFO parity error detection enable */
@@ -158,6 +179,7 @@
 #define	E1000_CTRL_EXT_GHOST_PAREN	0x40000000
 #define	E1000_CTRL_EXT_PBA_CLR		0x80000000	/* PBA Clear */
 #define	E1000_CTRL_EXT_LSECCK		0x00001000
+#define	E1000_CTRL_EXT_PHYPDEN		0x00100000
 #define	E1000_I2CCMD_REG_ADDR_SHIFT	16
 #define	E1000_I2CCMD_REG_ADDR		0x00FF0000
 #define	E1000_I2CCMD_PHY_ADDR_SHIFT	24
@@ -283,8 +305,8 @@
 #define	E1000_RCTL_RST		0x00000001	/* Software reset */
 #define	E1000_RCTL_EN		0x00000002	/* enable */
 #define	E1000_RCTL_SBP		0x00000004	/* store bad packet */
-#define	E1000_RCTL_UPE		0x00000008	/* unicast promiscuous enable */
-#define	E1000_RCTL_MPE		0x00000010	/* multicast promiscuous enab */
+#define	E1000_RCTL_UPE		0x00000008	/* unicast promisc enable */
+#define	E1000_RCTL_MPE		0x00000010	/* multicast promisc enable */
 #define	E1000_RCTL_LPE		0x00000020	/* long packet enable */
 #define	E1000_RCTL_LBM_NO	0x00000000	/* no loopback mode */
 #define	E1000_RCTL_LBM_MAC	0x00000040	/* MAC loopback mode */
@@ -292,9 +314,9 @@
 #define	E1000_RCTL_LBM_TCVR	0x000000C0	/* tcvr loopback mode */
 #define	E1000_RCTL_DTYP_MASK	0x00000C00	/* Descriptor type mask */
 #define	E1000_RCTL_DTYP_PS	0x00000400	/* Packet Split descriptor */
-#define	E1000_RCTL_RDMTS_HALF	0x00000000	/* rx desc min threshold size */
-#define	E1000_RCTL_RDMTS_QUAT	0x00000100	/* rx desc min threshold size */
-#define	E1000_RCTL_RDMTS_EIGTH	0x00000200	/* rx desc min threshold size */
+#define	E1000_RCTL_RDMTS_HALF	0x00000000	/* rx desc min thresh size */
+#define	E1000_RCTL_RDMTS_QUAT	0x00000100	/* rx desc min thresh size */
+#define	E1000_RCTL_RDMTS_EIGTH	0x00000200	/* rx desc min thresh size */
 #define	E1000_RCTL_MO_SHIFT	12		/* multicast offset shift */
 #define	E1000_RCTL_MO_0		0x00000000	/* multicast offset 11:0 */
 #define	E1000_RCTL_MO_1		0x00001000	/* multicast offset 12:1 */
@@ -349,10 +371,10 @@
 #define	E1000_PSRCTL_BSIZE3_SHIFT	14	/* Shift _left_ 14 */
 
 /* SWFW_SYNC Definitions */
-#define	E1000_SWFW_EEP_SM	0x1
-#define	E1000_SWFW_PHY0_SM	0x2
-#define	E1000_SWFW_PHY1_SM	0x4
-#define	E1000_SWFW_CSR_SM	0x8
+#define	E1000_SWFW_EEP_SM	0x01
+#define	E1000_SWFW_PHY0_SM	0x02
+#define	E1000_SWFW_PHY1_SM	0x04
+#define	E1000_SWFW_CSR_SM	0x08
 
 /* FACTPS Definitions */
 #define	E1000_FACTPS_LFS	0x40000000	/* LAN Function Select */
@@ -360,7 +382,7 @@
 #define	E1000_CTRL_FD	0x00000001	/* Full duplex.0=half; 1=full */
 #define	E1000_CTRL_BEM	0x00000002	/* Endian Mode.0=little,1=big */
 #define	E1000_CTRL_PRIOR 0x00000004	/* Priority on PCI. 0=rx,1=fair */
-#define	E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /* Block new Master requests */
+#define	E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /* Block new Master reqs */
 #define	E1000_CTRL_LRST	0x00000008	/* Link reset. 0=normal,1=reset */
 #define	E1000_CTRL_TME	0x00000010	/* Test mode. 0=normal,1=test */
 #define	E1000_CTRL_SLE	0x00000020	/* Serial Link on 0=dis,1=en */
@@ -460,6 +482,7 @@
 #define	E1000_STATUS_SPEED_1000	0x00000080	/* Speed 1000Mb/s */
 #define	E1000_STATUS_LAN_INIT_DONE 0x00000200	/* Lan Init Completion by NVM */
 #define	E1000_STATUS_ASDV	0x00000300	/* Auto	speed detect value */
+#define	E1000_STATUS_PHYRA	0x00000400	/* PHY Reset Asserted */
 /* Change in Dock/Undock state. Clear on write '0'. */
 #define	E1000_STATUS_DOCK_CI	0x00000800
 /* Master request status */
@@ -519,6 +542,11 @@
 #define	AUTONEG_ADVERTISE_SPEED_DEFAULT	E1000_ALL_SPEED_DUPLEX
 
 /* LED Control */
+#define	E1000_PHY_LED0_MODE_MASK	0x00000007
+#define	E1000_PHY_LED0_IVRT		0x00000008
+#define	E1000_PHY_LED0_BLINK		0x00000010
+#define	E1000_PHY_LED0_MASK		0x0000001F
+
 #define	E1000_LEDCTL_LED0_MODE_MASK	0x0000000F
 #define	E1000_LEDCTL_LED0_MODE_SHIFT	0
 #define	E1000_LEDCTL_LED0_BLINK_RATE	0x00000020
@@ -680,14 +708,19 @@
 /* PBA constants */
 #define	E1000_PBA_6K	0x0006	/* 6KB */
 #define	E1000_PBA_8K	0x0008	/* 8KB */
+#define	E1000_PBA_10K	0x000A	/* 10KB */
 #define	E1000_PBA_12K	0x000C	/* 12KB */
+#define	E1000_PBA_14K	0x000E	/* 14KB */
 #define	E1000_PBA_16K	0x0010	/* 16KB */
+#define	E1000_PBA_18K	0x0012
 #define	E1000_PBA_20K	0x0014
 #define	E1000_PBA_22K	0x0016
 #define	E1000_PBA_24K	0x0018
+#define	E1000_PBA_26K	0x001A
 #define	E1000_PBA_30K	0x001E
 #define	E1000_PBA_32K	0x0020
 #define	E1000_PBA_34K	0x0022
+#define	E1000_PBA_35K	0x0023
 #define	E1000_PBA_38K	0x0026
 #define	E1000_PBA_40K	0x0028
 #define	E1000_PBA_48K	0x0030	/* 48KB */
@@ -708,6 +741,9 @@
 #define	E1000_SWSM_WMNG		0x00000004	/* Wake MNG Clock */
 #define	E1000_SWSM_DRV_LOAD	0x00000008	/* Driver Loaded Bit */
 
+/* Secondary driver semaphore bit */
+#define	E1000_SWSM2_LOCK	0x00000002
+
 /* Interrupt Cause Read */
 #define	E1000_ICR_TXDW		0x00000001	/* Transmit desc written back */
 #define	E1000_ICR_TXQE		0x00000002	/* Transmit Queue empty */
@@ -758,6 +794,15 @@
 #define	E1000_ICR_TXQ1		0x00800000	/* Tx Queue 1 Interrupt */
 #define	E1000_ICR_OTHER		0x01000000	/* Other Interrupts */
 
+/* PBA ECC Register */
+#define	E1000_PBA_ECC_COUNTER_MASK	0xFFF00000 /* ECC counter mask */
+#define	E1000_PBA_ECC_COUNTER_SHIFT	20	/* ECC counter shift value */
+/* Enable ECC error correction */
+#define	E1000_PBA_ECC_CORR_EN		0x00000001
+#define	E1000_PBA_ECC_STAT_CLR		0x00000002 /* Clear ECC error counter */
+/* Enable ICR bit 5 on ECC error */
+#define	E1000_PBA_ECC_INT_EN		0x00000004
+
 /*
  * This defines the bits that are set in the Interrupt Mask
  * Set/Read Register.  Each bit is documented below:
@@ -785,7 +830,7 @@
     E1000_IMS_LSC)
 
 /* Interrupt Mask Set */
-#define	E1000_IMS_TXDW		E1000_ICR_TXDW	/* Transmit desc written back */
+#define	E1000_IMS_TXDW		E1000_ICR_TXDW	/* Tx desc written back */
 #define	E1000_IMS_TXQE		E1000_ICR_TXQE	/* Transmit Queue empty */
 #define	E1000_IMS_LSC		E1000_ICR_LSC	/* Link Status Change */
 #define	E1000_IMS_VMMB		E1000_ICR_VMMB	/* Mail box activity */
@@ -827,7 +872,7 @@
 #define	E1000_IMS_OTHER		E1000_ICR_OTHER	/* Other Interrupts */
 
 /* Interrupt Cause Set */
-#define	E1000_ICS_TXDW		E1000_ICR_TXDW	/* Transmit desc written back */
+#define	E1000_ICS_TXDW		E1000_ICR_TXDW	/* Tx desc written back */
 #define	E1000_ICS_TXQE		E1000_ICR_TXQE	/* Transmit Queue empty */
 #define	E1000_ICS_LSC		E1000_ICR_LSC	/* Link Status Change */
 #define	E1000_ICS_RXSEQ		E1000_ICR_RXSEQ	/* rx sequence error */
@@ -892,6 +937,10 @@
  */
 #define	E1000_RAR_ENTRIES	15
 #define	E1000_RAH_AV		0x80000000	/* Receive descriptor valid */
+#define	E1000_RAL_MAC_ADDR_LEN	4
+#define	E1000_RAH_MAC_ADDR_LEN	2
+#define	E1000_RAH_POOL_MASK	0x03FC0000
+#define	E1000_RAH_POOL_1	0x00040000
 
 /* Error Codes */
 #define	E1000_SUCCESS		0
@@ -907,6 +956,7 @@
 #define	E1000_BLK_PHY_RESET	12
 #define	E1000_ERR_SWFW_SYNC	13
 #define	E1000_NOT_IMPLEMENTED	14
+#define	E1000_ERR_MBX		15
 
 /* Loop limit on how long we wait for auto-negotiation to complete */
 #define	FIBER_LINK_UP_LIMIT	50
@@ -956,6 +1006,10 @@
 #define	E1000_GCR_TXD_NO_SNOOP		0x00000008
 #define	E1000_GCR_TXDSCW_NO_SNOOP	0x00000010
 #define	E1000_GCR_TXDSCR_NO_SNOOP	0x00000020
+#define	E1000_GCR_CMPL_TMOUT_MASK	0x0000F000
+#define	E1000_GCR_CMPL_TMOUT_10ms	0x00001000
+#define	E1000_GCR_CMPL_TMOUT_RESEND	0x00010000
+#define	E1000_GCR_CAP_VER2		0x00040000
 
 #define	PCIE_NO_SNOOP_ALL	(E1000_GCR_RXD_NO_SNOOP	| \
 				E1000_GCR_RXDSCW_NO_SNOOP | \
@@ -1071,6 +1125,8 @@
 #define	PHY_1000T_STATUS	0x0A	/* 1000Base-T Status Reg */
 #define	PHY_EXT_STATUS		0x0F	/* Extended Status Reg */
 
+#define	PHY_CONTROL_LB		0x4000	/* PHY Loopback bit */
+
 /* NVM Control */
 #define	E1000_EECD_SK		0x00000001 /* NVM Clock */
 #define	E1000_EECD_CS		0x00000002 /* NVM Chip Select */
@@ -1101,6 +1157,7 @@
 #define	E1000_EECD_SHADV	0x00200000 /* Shadow RAM Data Valid */
 #define	E1000_EECD_SEC1VAL	0x00400000 /* Sector One Valid */
 #define	E1000_EECD_SECVAL_SHIFT		22
+#define	E1000_EECD_SEC1VAL_VALID_MASK	(E1000_EECD_AUTO_RD | E1000_EECD_PRES)
 
 #define	E1000_NVM_SWDPIN0	0x0001	/* SWDPIN 0 NVM Value */
 #define	E1000_NVM_LED_LOGIC	0x0020	/* Led Logic Word */
@@ -1132,8 +1189,10 @@
 #define	NVM_ALT_MAC_ADDR_PTR		0x0037
 #define	NVM_CHECKSUM_REG		0x003F
 
-#define	E1000_NVM_CFG_DONE_PORT_0	0x40000	/* MNG config cycle done */
-#define	E1000_NVM_CFG_DONE_PORT_1	0x80000	/* ...for second port */
+/* MNG config cycle done */
+#define	E1000_NVM_CFG_DONE_PORT_0	0x040000
+/* ...for second port */
+#define	E1000_NVM_CFG_DONE_PORT_1	0x080000
 
 /* Mask bits for fields in Word 0x0f of the NVM */
 #define	NVM_WORD0F_PAUSE_MASK		0x3000
@@ -1211,6 +1270,7 @@
 #define	PCIX_STATUS_REGISTER_HI		0xEA
 #define	PCI_HEADER_TYPE_REGISTER	0x0E
 #define	PCIE_LINK_STATUS		0x12
+#define	PCIE_DEVICE_CONTROL2		0x28
 
 #define	PCIX_COMMAND_MMRBC_MASK		0x000C
 #define	PCIX_COMMAND_MMRBC_SHIFT	0x2
@@ -1222,6 +1282,7 @@
 #define	PCI_HEADER_TYPE_MULTIFUNC	0x80
 #define	PCIE_LINK_WIDTH_MASK		0x3F0
 #define	PCIE_LINK_WIDTH_SHIFT		4
+#define	PCIE_DEVICE_CONTROL2_16ms	0x0005
 
 #ifndef ETH_ADDR_LEN
 #define	ETH_ADDR_LEN		6
@@ -1249,6 +1310,8 @@
 #define	IFE_C_E_PHY_ID		0x02A80310
 #define	BME1000_E_PHY_ID	0x01410CB0
 #define	BME1000_E_PHY_ID_R2	0x01410CB1
+#define	I82577_E_PHY_ID		0x01540050
+#define	I82578_E_PHY_ID		0x004DD040
 #define	M88_VENDOR		0x0141
 
 /* M88E1000 Specific Registers */
@@ -1267,7 +1330,7 @@
 
 /* M88E1000 PHY Specific Control Register */
 #define	M88E1000_PSCR_JABBER_DISABLE	0x0001 /* 1=Jabber Function disabled */
-#define	M88E1000_PSCR_POLARITY_REVERSAL	0x0002 /* 1=Polarity Reversal enabled */
+#define	M88E1000_PSCR_POLARITY_REVERSAL	0x0002 /* 1=Polarity Reverse enabled */
 #define	M88E1000_PSCR_SQE_TEST		0x0004 /* 1=SQE Test enabled */
 /* 1=CLK125 low, 0=CLK125 toggling */
 #define	M88E1000_PSCR_CLK125_DISABLE	0x0010
@@ -1287,7 +1350,7 @@
 #define	M88E1000_PSCR_MII_5BIT_ENABLE	0x0100
 #define	M88E1000_PSCR_SCRAMBLER_DISABLE	0x0200	/* 1=Scrambler disable */
 #define	M88E1000_PSCR_FORCE_LINK_GOOD	0x0400	/* 1=Force link good */
-#define	M88E1000_PSCR_ASSERT_CRS_ON_TX	0x0800	/* 1=Assert CRS on Transmit */
+#define	M88E1000_PSCR_ASSERT_CRS_ON_TX	0x0800	/* 1=Assert CRS on Tx */
 
 /* M88E1000 PHY Specific Status Register */
 #define	M88E1000_PSSR_JABBER		0x0001	/* 1=Jabber */
@@ -1355,6 +1418,9 @@
 #define	M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X	0x0C00
 #define	M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X	0x0E00
 
+#define	I82578_EPSCR_DOWNSHIFT_ENABLE		0x0020
+#define	I82578_EPSCR_DOWNSHIFT_COUNTER_MASK	0x001C
+
 /* BME1000 PHY Specific Control Register */
 #define	BME1000_PSCR_ENABLE_DOWNSHIFT	0x0800	/* 1 = enable downshift */
 
@@ -1449,8 +1515,4 @@
 #define	E1000_GEN_CTL_ADDRESS_SHIFT	8
 #define	E1000_GEN_POLL_TIMEOUT		640
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif	/* _E1000_DEFINES_H_ */
--- a/usr/src/uts/common/io/e1000g/e1000_hw.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_hw.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.398 sol_anvik_patch
+ * IntelVersion: 1.432 v3-1-3_2009-8-20
  */
 #ifndef _E1000_HW_H_
 #define	_E1000_HW_H_
@@ -92,6 +92,8 @@
 #define	E1000_DEV_ID_82573E_IAMT		0x108C
 #define	E1000_DEV_ID_82573L			0x109A
 #define	E1000_DEV_ID_82574L			0x10D3
+#define	E1000_DEV_ID_82574LA			0x10F6
+#define	E1000_DEV_ID_82583V			0x150C
 #define	E1000_DEV_ID_80003ES2LAN_COPPER_DPT	0x1096
 #define	E1000_DEV_ID_80003ES2LAN_SERDES_DPT	0x1098
 #define	E1000_DEV_ID_80003ES2LAN_COPPER_SPT	0x10BA
@@ -115,8 +117,13 @@
 #define	E1000_DEV_ID_ICH10_R_BM_LM		0x10CC
 #define	E1000_DEV_ID_ICH10_R_BM_LF		0x10CD
 #define	E1000_DEV_ID_ICH10_R_BM_V		0x10CE
+#define	E1000_DEV_ID_ICH10_HANKSVILLE		0xF0FE
 #define	E1000_DEV_ID_ICH10_D_BM_LM		0x10DE
 #define	E1000_DEV_ID_ICH10_D_BM_LF		0x10DF
+#define	E1000_DEV_ID_PCH_M_HV_LM		0x10EA
+#define	E1000_DEV_ID_PCH_M_HV_LC		0x10EB
+#define	E1000_DEV_ID_PCH_D_HV_DM		0x10EF
+#define	E1000_DEV_ID_PCH_D_HV_DC		0x10F0
 
 #define	E1000_REVISION_0	0
 #define	E1000_REVISION_1	1
@@ -127,6 +134,12 @@
 #define	E1000_FUNC_0	0
 #define	E1000_FUNC_1	1
 
+#define	E1000_ALT_MAC_ADDRESS_OFFSET_LAN0	0
+#define	E1000_ALT_MAC_ADDRESS_OFFSET_LAN1	3
+
+/* Maximum size of the MTA register table in all supported adapters */
+#define	MAX_MTA_REG 128
+
 enum e1000_mac_type {
 	e1000_undefined = 0,
 	e1000_82542,
@@ -145,10 +158,12 @@
 	e1000_82572,
 	e1000_82573,
 	e1000_82574,
+	e1000_82583,
 	e1000_80003es2lan,
 	e1000_ich8lan,
 	e1000_ich9lan,
 	e1000_ich10lan,
+	e1000_pchlan,
 	e1000_num_macs	/* List is 1-based, so subtract 1 for true count. */
 };
 
@@ -187,7 +202,8 @@
 	e1000_phy_igp_3,
 	e1000_phy_ife,
 	e1000_phy_bm,
-	e1000_phy_vf
+	e1000_phy_82578,
+	e1000_phy_82577,
 };
 
 enum e1000_bus_type {
@@ -267,6 +283,13 @@
 	e1000_smart_speed_off
 };
 
+enum e1000_serdes_link_state {
+	e1000_serdes_link_down = 0,
+	e1000_serdes_link_autoneg_progress,
+	e1000_serdes_link_autoneg_complete,
+	e1000_serdes_link_forced_up
+};
+
 /* Receive Descriptor */
 struct e1000_rx_desc {
 	__le64 buffer_addr;	/* Address of the descriptor's data buffer */
@@ -537,6 +560,7 @@
 struct e1000_mac_operations {
 	/* Function pointers for the MAC. */
 	s32 (*init_params)(struct e1000_hw *);
+	s32 (*id_led_init)(struct e1000_hw *);
 	s32 (*blink_led)(struct e1000_hw *);
 	s32 (*check_for_link)(struct e1000_hw *);
 	bool (*check_mng_mode)(struct e1000_hw *hw);
@@ -544,10 +568,11 @@
 	void (*clear_hw_cntrs)(struct e1000_hw *);
 	void (*clear_vfta)(struct e1000_hw *);
 	s32 (*get_bus_info)(struct e1000_hw *);
+	void (*set_lan_id)(struct e1000_hw *);
 	s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
 	s32 (*led_on)(struct e1000_hw *);
 	s32 (*led_off)(struct e1000_hw *);
-	void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32, u32, u32);
+	void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
 	s32 (*reset_hw)(struct e1000_hw *);
 	s32 (*init_hw)(struct e1000_hw *);
 	s32 (*setup_link)(struct e1000_hw *);
@@ -620,6 +645,7 @@
 	u16 ifs_ratio;
 	u16 ifs_step_size;
 	u16 mta_reg_count;
+	u32 mta_shadow[MAX_MTA_REG];
 	u16 rar_entry_count;
 
 	u8 forced_speed_duplex;
@@ -632,6 +658,7 @@
 	bool get_link_status;
 	bool in_ifs_mode;
 	bool report_tx_early;
+	enum e1000_serdes_link_state serdes_link_state;
 	bool serdes_has_link;
 	bool tx_pkt_filtering;
 };
@@ -728,6 +755,11 @@
 
 struct e1000_dev_spec_82571 {
 	bool laa_is_present;
+	u32 smb_counter;
+};
+
+struct e1000_dev_spec_80003es2lan {
+	bool  mdic_wa_enable;
 };
 
 struct e1000_shadow_ram {
@@ -740,6 +772,8 @@
 struct e1000_dev_spec_ich8lan {
 	bool kmrn_lock_loss_workaround_enabled;
 	struct e1000_shadow_ram shadow_ram[E1000_SHADOW_RAM_WORDS];
+	E1000_MUTEX nvm_mutex;
+	E1000_MUTEX swflag_mutex;
 };
 
 struct e1000_hw {
@@ -761,6 +795,7 @@
 		struct e1000_dev_spec_82542	_82542;
 		struct e1000_dev_spec_82543	_82543;
 		struct e1000_dev_spec_82571	_82571;
+		struct e1000_dev_spec_80003es2lan _80003es2lan;
 		struct e1000_dev_spec_ich8lan	ich8lan;
 	} dev_spec;
 
@@ -782,6 +817,7 @@
 void e1000_pci_clear_mwi(struct e1000_hw *hw);
 void e1000_pci_set_mwi(struct e1000_hw *hw);
 s32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
+s32 e1000_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
 void e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value);
 void e1000_write_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value);
 
--- a/usr/src/uts/common/io/e1000g/e1000_ich8lan.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_ich8lan.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.136 sol_anvik_patch
+ * IntelVersion: 1.180 v3-1-3_2009-8-20
  */
 
 /*
@@ -49,19 +49,24 @@
  * 82567LF-3 Gigabit Network Connection
  * 82567LM-3 Gigabit Network Connection
  * 82567LM-4 Gigabit Network Connection
+ * 82577LM Gigabit Network Connection
+ * 82577LC Gigabit Network Connection
+ * 82578DM Gigabit Network Connection
+ * 82578DC Gigabit Network Connection
  */
 
 #include "e1000_api.h"
 
 static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw);
+static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw);
 static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw);
 static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw);
 static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw);
 static void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
+static s32  e1000_acquire_nvm_ich8lan(struct e1000_hw *hw);
+static void e1000_release_nvm_ich8lan(struct e1000_hw *hw);
 static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
-static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw);
 static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
-static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw);
 static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
 static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw);
 static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
@@ -76,6 +81,7 @@
 static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
 static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
     u16 *data);
+static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
 static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
 static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw);
 static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw);
@@ -86,6 +92,10 @@
 static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
 static s32 e1000_led_on_ich8lan(struct e1000_hw *hw);
 static s32 e1000_led_off_ich8lan(struct e1000_hw *hw);
+static s32  e1000_setup_led_pchlan(struct e1000_hw *hw);
+static s32  e1000_cleanup_led_pchlan(struct e1000_hw *hw);
+static s32  e1000_led_on_pchlan(struct e1000_hw *hw);
+static s32  e1000_led_off_pchlan(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
 static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
 static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout);
@@ -107,6 +117,7 @@
     u8 size, u16 data);
 static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
 static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
+static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
 
 /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
 /* Offset 04h HSFSTS */
@@ -150,6 +161,56 @@
 };
 
 /*
+ * e1000_init_phy_params_pchlan - Initialize PHY function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific PHY parameters and function pointers.
+ */
+static s32
+e1000_init_phy_params_pchlan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_init_phy_params_pchlan");
+
+	phy->addr = 1;
+	phy->reset_delay_us = 100;
+
+	phy->ops.acquire = e1000_acquire_swflag_ich8lan;
+	phy->ops.check_polarity = e1000_check_polarity_ife;
+	phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
+	phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
+	phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
+	phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan;
+	phy->ops.get_info = e1000_get_phy_info_ich8lan;
+	phy->ops.read_reg = e1000_read_phy_reg_hv;
+	phy->ops.release = e1000_release_swflag_ich8lan;
+	phy->ops.reset = e1000_phy_hw_reset_ich8lan;
+	phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan;
+	phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan;
+	phy->ops.write_reg = e1000_write_phy_reg_hv;
+	phy->ops.power_up = e1000_power_up_phy_copper;
+	phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
+	phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+	phy->id = e1000_phy_unknown;
+	e1000_get_phy_id(hw);
+	phy->type = e1000_get_phy_type_from_id(phy->id);
+
+	if (phy->type == e1000_phy_82577) {
+		phy->ops.check_polarity = e1000_check_polarity_82577;
+		phy->ops.force_speed_duplex =
+		    e1000_phy_force_speed_duplex_82577;
+		phy->ops.get_cable_length   = e1000_get_cable_length_82577;
+		phy->ops.get_info = e1000_get_phy_info_82577;
+		phy->ops.commit = e1000_phy_sw_reset_generic;
+	}
+
+	return (ret_val);
+}
+
+/*
  * e1000_init_phy_params_ich8lan - Initialize PHY function pointers
  * @hw: pointer to the HW structure
  *
@@ -168,9 +229,9 @@
 	phy->reset_delay_us = 100;
 
 	phy->ops.acquire = e1000_acquire_swflag_ich8lan;
-	phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan;
+	phy->ops.check_polarity = e1000_check_polarity_ife;
 	phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
-	phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan;
+	phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
 	phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
 	phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan;
 	phy->ops.get_info = e1000_get_phy_info_ich8lan;
@@ -292,10 +353,13 @@
 		dev_spec->shadow_ram[i].value = 0xFFFF;
 	}
 
+	E1000_MUTEX_INIT(&dev_spec->nvm_mutex);
+	E1000_MUTEX_INIT(&dev_spec->swflag_mutex);
+
 	/* Function Pointers */
-	nvm->ops.acquire = e1000_acquire_swflag_ich8lan;
+	nvm->ops.acquire = e1000_acquire_nvm_ich8lan;
+	nvm->ops.release = e1000_release_nvm_ich8lan;
 	nvm->ops.read = e1000_read_nvm_ich8lan;
-	nvm->ops.release = e1000_release_swflag_ich8lan;
 	nvm->ops.update = e1000_update_nvm_checksum_ich8lan;
 	nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
 	nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan;
@@ -337,6 +401,8 @@
 
 	/* bus type/speed/width */
 	mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
+	/* function id */
+	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
 	/* reset */
 	mac->ops.reset_hw = e1000_reset_hw_ich8lan;
 	/* hw initialization */
@@ -346,7 +412,7 @@
 	/* physical interface setup */
 	mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
 	/* check for link */
-	mac->ops.check_for_link = e1000_check_for_copper_link_generic;
+	mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan;
 	/* check management mode */
 	mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
 	/* link info */
@@ -355,18 +421,41 @@
 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
 	/* setting MTA */
 	mac->ops.mta_set = e1000_mta_set_generic;
-	/* blink LED */
-	mac->ops.blink_led = e1000_blink_led_generic;
-	/* setup LED */
-	mac->ops.setup_led = e1000_setup_led_generic;
-	/* cleanup LED */
-	mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
-	/* turn on/off LED */
-	mac->ops.led_on = e1000_led_on_ich8lan;
-	mac->ops.led_off = e1000_led_off_ich8lan;
 	/* clear hardware counters */
 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
 
+	/* LED operations */
+	switch (mac->type) {
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+	case e1000_ich10lan:
+		/* ID LED init */
+		mac->ops.id_led_init = e1000_id_led_init_generic;
+		/* blink LED */
+		mac->ops.blink_led = e1000_blink_led_generic;
+		/* setup LED */
+		mac->ops.setup_led = e1000_setup_led_generic;
+		/* cleanup LED */
+		mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
+		/* turn on/off LED */
+		mac->ops.led_on = e1000_led_on_ich8lan;
+		mac->ops.led_off = e1000_led_off_ich8lan;
+		break;
+	case e1000_pchlan:
+		/* ID LED init */
+		mac->ops.id_led_init = e1000_id_led_init_pchlan;
+		/* setup LED */
+		mac->ops.setup_led = e1000_setup_led_pchlan;
+		/* cleanup LED */
+		mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
+		/* turn on/off LED */
+		mac->ops.led_on = e1000_led_on_pchlan;
+		mac->ops.led_off = e1000_led_off_pchlan;
+		break;
+	default:
+		break;
+	}
+
 	/* Enable PCS Lock-loss workaround for ICH8 */
 	if (mac->type == e1000_ich8lan)
 		e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
@@ -375,6 +464,98 @@
 }
 
 /*
+ * e1000_check_for_copper_link_ich8lan - Check for link (Copper)
+ * @hw: pointer to the HW structure
+ *
+ * Checks to see of the link status of the hardware has changed.  If a
+ * change in link status has been detected, then we read the PHY registers
+ * to get the current speed/duplex if link exists.
+ */
+static s32
+e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	bool link;
+
+	DEBUGFUNC("e1000_check_for_copper_link_ich8lan");
+
+	/*
+	 * We only want to go out to the PHY registers to see if Auto-Neg
+	 * has completed and/or if our link status has changed.  The
+	 * get_link_status flag is set upon receiving a Link Status
+	 * Change or Rx Sequence Error interrupt.
+	 */
+	if (!mac->get_link_status) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	if (hw->mac.type == e1000_pchlan) {
+		ret_val = e1000_write_kmrn_reg_generic(hw,
+		    E1000_KMRNCTRLSTA_K1_CONFIG,
+		    E1000_KMRNCTRLSTA_K1_ENABLE);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * First we want to see if the MII Status Register reports
+	 * link.  If so, then we want to get the current speed/duplex
+	 * of the PHY.
+	 */
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link)
+		goto out; /* No link detected */
+
+	mac->get_link_status = false;
+
+	if (hw->phy.type == e1000_phy_82578) {
+		ret_val = e1000_link_stall_workaround_hv(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Check if there was DownShift, must be checked
+	 * immediately after link-up
+	 */
+	e1000_check_downshift_generic(hw);
+
+	/*
+	 * If we are forcing speed/duplex, then we simply return since
+	 * we have already determined whether we have link or not.
+	 */
+	if (!mac->autoneg) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/*
+	 * Auto-Neg is enabled.  Auto Speed Detection takes care
+	 * of MAC speed/duplex configuration.  So we only need to
+	 * configure Collision Distance in the MAC.
+	 */
+	e1000_config_collision_dist_generic(hw);
+
+	/*
+	 * Configure Flow Control now that Auto-Neg has completed.
+	 * First, we need to restore the desired flow control
+	 * settings because we may have had to re-autoneg with a
+	 * different link partner.
+	 */
+	ret_val = e1000_config_fc_after_link_up_generic(hw);
+	if (ret_val)
+		DEBUGOUT("Error configuring flow control\n");
+
+out:
+	return (ret_val);
+}
+
+/*
  * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
  * @hw: pointer to the HW structure
  *
@@ -387,7 +568,48 @@
 
 	hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
 	hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
-	hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
+	switch (hw->mac.type) {
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+	case e1000_ich10lan:
+		hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
+		break;
+	case e1000_pchlan:
+		hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * e1000_acquire_nvm_ich8lan - Acquire NVM mutex
+ * @hw: pointer to the HW structure
+ *
+ * Acquires the mutex for performing NVM operations.
+ */
+static s32
+e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_acquire_nvm_ich8lan");
+
+	E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex);
+
+	return (E1000_SUCCESS);
+}
+
+/*
+ * e1000_release_nvm_ich8lan - Release NVM mutex
+ * @hw: pointer to the HW structure
+ *
+ * Releases the mutex used while performing NVM operations.
+ */
+static void
+e1000_release_nvm_ich8lan(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_release_nvm_ich8lan");
+
+	E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex);
 }
 
 /*
@@ -406,20 +628,40 @@
 
 	DEBUGFUNC("e1000_acquire_swflag_ich8lan");
 
+	E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex);
+
 	while (timeout) {
 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
-		extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
-		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
-
-		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
-		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+		if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
 			break;
+
 		msec_delay_irq(1);
 		timeout--;
 	}
 
 	if (!timeout) {
-		DEBUGOUT("FW or HW has locked the resource for too long.\n");
+		DEBUGOUT("SW/FW/HW has locked the resource for too long.\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/* In some cases, hardware will take up to 400ms to set the SW flag. */
+	timeout = SW_FLAG_TIMEOUT;
+
+	extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+
+	while (timeout) {
+			extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+			if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+				break;
+
+		msec_delay_irq(1);
+		timeout--;
+	}
+
+	if (!timeout) {
+		DEBUGOUT("Failed to acquire the semaphore.\n");
 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
 		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
 		ret_val = -E1000_ERR_CONFIG;
@@ -427,6 +669,9 @@
 	}
 
 out:
+	if (ret_val)
+		E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
+
 	return (ret_val);
 }
 
@@ -448,6 +693,8 @@
 	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
 	extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+
+	E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
 }
 
 /*
@@ -493,80 +740,118 @@
 }
 
 /*
- * e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex
- * @hw: pointer to the HW structure
- *
- * Forces the speed and duplex settings of the PHY.
- * This is a function pointer entry point only called by
- * PHY setup routines.
+ * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ * done after every PHY reset.
  */
 static s32
-e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw)
+e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
 {
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	DEBUGFUNC("e1000_phy_force_speed_duplex_ich8lan");
-
-	if (phy->type != e1000_phy_ife) {
-		ret_val = e1000_phy_force_speed_duplex_igp(hw);
-		goto out;
+	s32 ret_val = E1000_SUCCESS;
+
+	if (hw->mac.type != e1000_pchlan)
+		return (ret_val);
+
+	if (((hw->phy.type == e1000_phy_82577) &&
+	    ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
+	    ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
+		/* Disable generation of early preamble */
+		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
+		if (ret_val)
+			return (ret_val);
+
+		/* Preamble tuning for SSC */
+		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204);
+		if (ret_val)
+			return (ret_val);
 	}
-	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
+
+	if (hw->phy.type == e1000_phy_82578) {
+		/*
+		 * Return registers to default by doing a soft reset then
+		 * writing 0x3140 to the control register.
+		 */
+		if (hw->phy.revision < 2) {
+			e1000_phy_sw_reset_generic(hw);
+			ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL,
+			    0x3140);
+		}
+	}
+
+	/* Select page 0 */
+	ret_val = hw->phy.ops.acquire(hw);
 	if (ret_val)
-		goto out;
-
-	e1000_phy_force_speed_duplex_setup(hw, &data);
-
-	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
+		return (ret_val);
+
+	hw->phy.addr = 1;
+	e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
+	hw->phy.ops.release(hw);
+
+	return (ret_val);
+}
+
+/*
+ * e1000_hv_phy_tuning_workaround_ich8lan - This is a Phy tuning work around
+ * needed for Nahum3 + Hanksville testing, requested by HW team
+ */
+static s32
+e1000_hv_phy_tuning_workaround_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
 	if (ret_val)
 		goto out;
 
-	/* Disable MDI-X support for 10/100 */
-	ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
-	if (ret_val)
-		goto out;
-
-	data &= ~IFE_PMC_AUTO_MDIX;
-	data &= ~IFE_PMC_FORCE_MDIX;
-
-	ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
+	ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204);
 	if (ret_val)
 		goto out;
 
-	DEBUGOUT1("IFE PMC: %X\n", data);
-
-	usec_delay(1);
-
-	if (phy->autoneg_wait_to_complete) {
-		DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
-
-		ret_val = e1000_phy_has_link_generic(hw,
-		    PHY_FORCE_LIMIT,
-		    100000,
-		    &link);
-		if (ret_val)
-			goto out;
-
-		if (!link)
-			DEBUGOUT("Link taking longer than expected.\n");
-
-		/* Try once more */
-		ret_val = e1000_phy_has_link_generic(hw,
-		    PHY_FORCE_LIMIT,
-		    100000,
-		    &link);
-		if (ret_val)
-			goto out;
-	}
+	ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x29, 0x66C0);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x1E, 0xFFFF);
 
 out:
 	return (ret_val);
 }
 
 /*
+ * e1000_lan_init_done_ich8lan - Check for PHY config completion
+ * @hw: pointer to the HW structure
+ *
+ * Check the appropriate indication the MAC has finished configuring the
+ * PHY after a software reset.
+ */
+static void
+e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
+{
+	u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
+
+	DEBUGFUNC("e1000_lan_init_done_ich8lan");
+
+	/* Wait for basic configuration completes before proceeding */
+	do {
+		data = E1000_READ_REG(hw, E1000_STATUS);
+		data &= E1000_STATUS_LAN_INIT_DONE;
+		usec_delay(100);
+	} while ((!data) && --loop);
+
+	/*
+	 * If basic configuration is incomplete before the above loop
+	 * count reaches 0, loading the configuration from NVM will
+	 * leave the PHY in a bad state possibly resulting in no link.
+	 */
+	if (loop == 0)
+		DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
+
+	/* Clear the Init Done bit for the next init event */
+	data = E1000_READ_REG(hw, E1000_STATUS);
+	data &= ~E1000_STATUS_LAN_INIT_DONE;
+	E1000_WRITE_REG(hw, E1000_STATUS, data);
+}
+
+/*
  * e1000_phy_hw_reset_ich8lan - Performs a PHY reset
  * @hw: pointer to the HW structure
  *
@@ -580,7 +865,6 @@
 	struct e1000_phy_info *phy = &hw->phy;
 	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
 	s32 ret_val;
-	u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT;
 	u16 word_addr, reg_data, reg_addr, phy_page = 0;
 
 	DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
@@ -589,6 +873,21 @@
 	if (ret_val)
 		goto out;
 
+	/* Allow time for h/w to get to a quiescent state after reset */
+	msec_delay(10);
+
+	if (hw->mac.type == e1000_pchlan) {
+		ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	if (hw->device_id == E1000_DEV_ID_ICH10_HANKSVILLE) {
+		ret_val = e1000_hv_phy_tuning_workaround_ich8lan(hw);
+		if (ret_val)
+			goto out;
+	}
+
 	/*
 	 * Initialize the PHY from the NVM on ICH platforms.  This is needed
 	 * due to an issue where the NVM configuration is not properly
@@ -608,24 +907,7 @@
 			goto out;
 
 		/* Wait for basic configuration completes before proceeding */
-		do {
-			data = E1000_READ_REG(hw, E1000_STATUS);
-			data &= E1000_STATUS_LAN_INIT_DONE;
-			usec_delay(100);
-		} while ((!data) && --loop);
-
-		/*
-		 * If basic configuration is incomplete before the above loop
-		 * count reaches 0, loading the configuration from NVM will
-		 * leave the PHY in a bad state possibly resulting in no link.
-		 */
-		if (loop == 0)
-			DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
-
-		/* Clear the Init Done bit for the next init event */
-		data = E1000_READ_REG(hw, E1000_STATUS);
-		data &= ~E1000_STATUS_LAN_INIT_DONE;
-		E1000_WRITE_REG(hw, E1000_STATUS, data);
+		e1000_lan_init_done_ich8lan(hw);
 
 		/*
 		 * Make sure HW does not configure LCD from PHY extended
@@ -705,6 +987,8 @@
 		break;
 	case e1000_phy_igp_3:
 	case e1000_phy_bm:
+	case e1000_phy_82578:
+	case e1000_phy_82577:
 		ret_val = e1000_get_phy_info_igp(hw);
 		break;
 	default:
@@ -749,7 +1033,7 @@
 	    ? false : true;
 
 	if (phy->polarity_correction) {
-		ret_val = e1000_check_polarity_ife_ich8lan(hw);
+		ret_val = e1000_check_polarity_ife(hw);
 		if (ret_val)
 			goto out;
 	} else {
@@ -775,44 +1059,6 @@
 }
 
 /*
- * e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY
- * @hw: pointer to the HW structure
- *
- * Polarity is determined on the polarity reversal feature being enabled.
- * This function is only called by other family-specific
- * routines.
- */
-static s32
-e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, offset, mask;
-
-	DEBUGFUNC("e1000_check_polarity_ife_ich8lan");
-
-	/*
-	 * Polarity is determined based on the reversal feature being enabled.
-	 */
-	if (phy->polarity_correction) {
-		offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
-		mask = IFE_PESC_POLARITY_REVERSED;
-	} else {
-		offset = IFE_PHY_SPECIAL_CONTROL;
-		mask = IFE_PSC_FORCE_POLARITY;
-	}
-
-	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
-
-	if (!ret_val)
-		phy->cable_polarity = (phy_data & mask)
-		    ? e1000_rev_polarity_reversed
-		    : e1000_rev_polarity_normal;
-
-	return (ret_val);
-}
-
-/*
  * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
  * @hw: pointer to the HW structure
  * @active: true to enable LPLU, false to disable
@@ -844,12 +1090,14 @@
 		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
 
+		if (phy->type != e1000_phy_igp_3)
+			goto out;
+
 		/*
 		 * Call gig speed drop workaround on LPLU before accessing any
 		 * PHY registers
 		 */
-		if ((hw->mac.type == e1000_ich8lan) &&
-		    (hw->phy.type == e1000_phy_igp_3))
+		if (hw->mac.type == e1000_ich8lan)
 			e1000_gig_downshift_workaround_ich8lan(hw);
 
 		/* When LPLU is enabled, we should disable SmartSpeed */
@@ -866,6 +1114,9 @@
 		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
 
+		if (phy->type != e1000_phy_igp_3)
+			goto out;
+
 		/*
 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
 		 * during Dx states where the power conservation is most
@@ -933,6 +1184,10 @@
 	if (!active) {
 		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+		if (phy->type != e1000_phy_igp_3)
+			goto out;
+
 		/*
 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
 		 * during Dx states where the power conservation is most
@@ -972,12 +1227,14 @@
 		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
 
+		if (phy->type != e1000_phy_igp_3)
+			goto out;
+
 		/*
 		 * Call gig speed drop workaround on LPLU before accessing any
 		 * PHY registers
 		 */
-		if ((hw->mac.type == e1000_ich8lan) &&
-		    (hw->phy.type == e1000_phy_igp_3))
+		if (hw->mac.type == e1000_ich8lan)
 			e1000_gig_downshift_workaround_ich8lan(hw);
 
 		/* When LPLU is enabled, we should disable SmartSpeed */
@@ -1003,50 +1260,65 @@
  * @bank:  pointer to the variable that returns the active bank
  *
  * Reads signature byte from the NVM using the flash access registers.
+ * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
  */
 static s32
 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
 {
-	s32 ret_val = E1000_SUCCESS;
+	u32 eecd;
 	struct e1000_nvm_info *nvm = &hw->nvm;
-	/* flash bank size is in words */
 	u32 bank1_offset = nvm->flash_bank_size * sizeof (u16);
 	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
-	u8 bank_high_byte = 0;
-
-	if (hw->mac.type != e1000_ich10lan) {
-		if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_SEC1VAL)
-			*bank = 1;
-		else
-			*bank = 0;
-	} else {
-		/*
-		 * Make sure the signature for bank 0 is valid,
-		 * if not check for bank1
-		 */
-		(void) e1000_read_flash_byte_ich8lan(hw,
-		    act_offset, &bank_high_byte);
-		if ((bank_high_byte & 0xC0) == 0x80) {
+	u8 sig_byte = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	switch (hw->mac.type) {
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+		eecd = E1000_READ_REG(hw, E1000_EECD);
+		if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
+		    E1000_EECD_SEC1VAL_VALID_MASK) {
+			if (eecd & E1000_EECD_SEC1VAL)
+				*bank = 1;
+			else
+				*bank = 0;
+
+			goto out;
+		}
+		DEBUGOUT("Unable to determine valid NVM bank via EEC - "
+		    "reading flash signature\n");
+		/* fall-thru */
+	default:
+		/* set bank to 0 in case flash read fails */
+		*bank = 0;
+
+		/* Check bank 0 */
+		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
+		    &sig_byte);
+		if (ret_val)
+			goto out;
+		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+		    E1000_ICH_NVM_SIG_VALUE) {
 			*bank = 0;
-		} else {
-			/*
-			 * find if segment 1 is valid by verifying
-			 * bit 15:14 = 10b in word 0x13
-			 */
-			(void) e1000_read_flash_byte_ich8lan(hw,
-			    act_offset + bank1_offset,
-			    &bank_high_byte);
-
-			/* bank1 has a valid signature equivalent to SEC1V */
-			if ((bank_high_byte & 0xC0) == 0x80) {
-				*bank = 1;
-			} else {
-				DEBUGOUT("ERROR: EEPROM not present\n");
-				ret_val = -E1000_ERR_NVM;
-			}
+			goto out;
 		}
+
+		/* Check bank 1 */
+		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
+		    bank1_offset, &sig_byte);
+		if (ret_val)
+			goto out;
+		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+		    E1000_ICH_NVM_SIG_VALUE) {
+			*bank = 1;
+			goto out;
+		}
+
+		DEBUGOUT("ERROR: No valid NVM bank present\n");
+		ret_val = -E1000_ERR_NVM;
+		break;
 	}
-
+out:
 	return (ret_val);
 }
 
@@ -1079,17 +1351,18 @@
 		goto out;
 	}
 
-	ret_val = nvm->ops.acquire(hw);
-	if (ret_val)
-		goto out;
+	nvm->ops.acquire(hw);
 
 	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
-	if (ret_val != E1000_SUCCESS)
-		goto out;
+	if (ret_val != E1000_SUCCESS) {
+		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
+		bank = 0;
+	}
 
 	act_offset = (bank) ? nvm->flash_bank_size : 0;
 	act_offset += offset;
 
+	ret_val = E1000_SUCCESS;
 	for (i = 0; i < words; i++) {
 		if ((dev_spec->shadow_ram) &&
 		    (dev_spec->shadow_ram[offset + i].modified)) {
@@ -1107,6 +1380,9 @@
 	nvm->ops.release(hw);
 
 out:
+	if (ret_val)
+		DEBUGOUT1("NVM read error: %d\n", ret_val);
+
 	return (ret_val);
 }
 
@@ -1388,9 +1664,7 @@
 		goto out;
 	}
 
-	ret_val = nvm->ops.acquire(hw);
-	if (ret_val)
-		goto out;
+	nvm->ops.acquire(hw);
 
 	for (i = 0; i < words; i++) {
 		dev_spec->shadow_ram[offset + i].modified = true;
@@ -1432,9 +1706,7 @@
 	if (nvm->type != e1000_nvm_flash_sw)
 		goto out;
 
-	ret_val = nvm->ops.acquire(hw);
-	if (ret_val)
-		goto out;
+	nvm->ops.acquire(hw);
 
 	/*
 	 * We're writing to the opposite bank so if we're on bank 1, write to
@@ -1442,17 +1714,27 @@
 	 * written
 	 */
 	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
-	if (ret_val != E1000_SUCCESS)
-		goto out;
+	if (ret_val != E1000_SUCCESS) {
+		DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
+		bank = 0;
+	}
 
 	if (bank == 0) {
 		new_bank_offset = nvm->flash_bank_size;
 		old_bank_offset = 0;
-		(void) e1000_erase_flash_bank_ich8lan(hw, 1);
+		ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
+		if (ret_val) {
+			nvm->ops.release(hw);
+			goto out;
+		}
 	} else {
 		old_bank_offset = nvm->flash_bank_size;
 		new_bank_offset = 0;
-		(void) e1000_erase_flash_bank_ich8lan(hw, 0);
+		ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
+		if (ret_val) {
+			nvm->ops.release(hw);
+			goto out;
+		}
 	}
 
 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
@@ -1463,9 +1745,11 @@
 		if (dev_spec->shadow_ram[i].modified) {
 			data = dev_spec->shadow_ram[i].value;
 		} else {
-			(void) e1000_read_flash_word_ich8lan(hw,
+			ret_val = e1000_read_flash_word_ich8lan(hw,
 			    i + old_bank_offset,
 			    &data);
+			if (ret_val)
+				break;
 		}
 
 		/*
@@ -1514,7 +1798,12 @@
 	 * bits are 11 to start with and we need to change bit 14 to 0b
 	 */
 	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
-	(void) e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+	ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+	if (ret_val) {
+		nvm->ops.release(hw);
+		goto out;
+	}
+
 	data &= 0xBFFF;
 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
 	    act_offset * 2 + 1,
@@ -1553,6 +1842,9 @@
 	msec_delay(10);
 
 out:
+	if (ret_val)
+		DEBUGOUT1("NVM update error: %d\n", ret_val);
+
 	return (ret_val);
 }
 
@@ -1782,20 +2074,15 @@
 		break;
 	case 1:
 		sector_size = ICH_FLASH_SEG_SIZE_4K;
-		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K;
+		iteration = 1;
 		break;
 	case 2:
-		if (hw->mac.type == e1000_ich9lan) {
 			sector_size = ICH_FLASH_SEG_SIZE_8K;
-			iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K;
-		} else {
-			ret_val = -E1000_ERR_NVM;
-			goto out;
-		}
+			iteration = 1;
 		break;
 	case 3:
 		sector_size = ICH_FLASH_SEG_SIZE_64K;
-		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K;
+		iteration = 1;
 		break;
 	default:
 		ret_val = -E1000_ERR_NVM;
@@ -1804,7 +2091,7 @@
 
 	/* Start with the base address, then add the sector offset. */
 	flash_linear_addr = hw->nvm.flash_base_addr;
-	flash_linear_addr += (bank) ? (sector_size * iteration) : 0;
+	flash_linear_addr += (bank) ? flash_bank_size : 0;
 
 	for (j = 0; j < iteration; j++) {
 		do {
@@ -1888,6 +2175,82 @@
 }
 
 /*
+ * e1000_id_led_init_pchlan - store LED configurations
+ * @hw: pointer to the HW structure
+ *
+ * PCH does not control LEDs via the LEDCTL register, rather it uses
+ * the PHY LED configuration register.
+ *
+ * PCH also does not have an "always on" or "always off" mode which
+ * complicates the ID feature.  Instead of using the "on" mode to indicate
+ * in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()),
+ * use "link_up" mode.  The LEDs will still ID on request if there is no
+ * link based on logic in e1000_led_[on|off]_pchlan().
+ */
+static s32
+e1000_id_led_init_pchlan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
+	const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
+	u16 data, i, temp, shift;
+
+	DEBUGFUNC("e1000_id_led_init_pchlan");
+
+	/* Get default ID LED modes */
+	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+	if (ret_val)
+		goto out;
+
+	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
+	mac->ledctl_mode1 = mac->ledctl_default;
+	mac->ledctl_mode2 = mac->ledctl_default;
+
+	for (i = 0; i < 4; i++) {
+		temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
+		shift = (i * 5);
+		switch (temp) {
+		case ID_LED_ON1_DEF2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_ON1_OFF2:
+			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+			mac->ledctl_mode1 |= (ledctl_on << shift);
+			break;
+		case ID_LED_OFF1_DEF2:
+		case ID_LED_OFF1_ON2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+			mac->ledctl_mode1 |= (ledctl_off << shift);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+		switch (temp) {
+		case ID_LED_DEF1_ON2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_OFF1_ON2:
+			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+			mac->ledctl_mode2 |= (ledctl_on << shift);
+			break;
+		case ID_LED_DEF1_OFF2:
+		case ID_LED_ON1_OFF2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+			mac->ledctl_mode2 |= (ledctl_off << shift);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+	}
+
+out:
+	return (ret_val);
+}
+
+/*
  * e1000_get_bus_info_ich8lan - Get/Set the bus type and width
  * @hw: pointer to the HW structure
  *
@@ -1963,6 +2326,13 @@
 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
 
 	if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) {
+		/* Clear PHY Reset Asserted bit */
+		if (hw->mac.type >= e1000_pchlan) {
+			u32 status = E1000_READ_REG(hw, E1000_STATUS);
+			E1000_WRITE_REG(hw, E1000_STATUS, status &
+			    ~E1000_STATUS_PHYRA);
+		}
+
 		/*
 		 * PHY HW reset requires MAC CORE reset at the same time to
 		 * make sure the interface between MAC and the external PHY is
@@ -1972,20 +2342,39 @@
 	}
 
 	ret_val = e1000_acquire_swflag_ich8lan(hw);
-	DEBUGOUT("Issuing a global reset to ich8lan");
+
+	DEBUGOUT("Issuing a global reset to ich8lan\n");
 	E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
 	msec_delay(20);
 
-	ret_val = e1000_get_auto_rd_done_generic(hw);
-	if (ret_val) {
-		/*
-		 * When auto config read does not complete, do not return with
-		 * an error. This can happen in situations where there is no
-		 * eeprom and prevents getting link.
-		 */
-		DEBUGOUT("Auto Read Done did not complete\n");
+	if (!ret_val)
+		e1000_release_swflag_ich8lan(hw);
+
+	if (ctrl & E1000_CTRL_PHY_RST)
+		ret_val = hw->phy.ops.get_cfg_done(hw);
+
+	if (hw->mac.type >= e1000_ich10lan) {
+		e1000_lan_init_done_ich8lan(hw);
+	} else {
+		ret_val = e1000_get_auto_rd_done_generic(hw);
+		if (ret_val) {
+			/*
+			 * When auto config read does not complete, do not
+			 * return with an error. This can happen in situations
+			 * where there is no eeprom and prevents getting link.
+			 */
+			DEBUGOUT("Auto Read Done did not complete\n");
+		}
 	}
 
+	/*
+	 * For PCH, this write will make sure that any noise
+	 * will be detected as a CRC error and be dropped rather than show up
+	 * as a bad packet to the DMA engine.
+	 */
+	if (hw->mac.type == e1000_pchlan)
+		E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565);
+
 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
 	(void) E1000_READ_REG(hw, E1000_ICR);
 
@@ -1993,6 +2382,16 @@
 	kab |= E1000_KABGTXD_BGSQLBIAS;
 	E1000_WRITE_REG(hw, E1000_KABGTXD, kab);
 
+	if (hw->mac.type == e1000_pchlan)
+		ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
+
+	if (ret_val)
+		goto out;
+
+	if (hw->device_id == E1000_DEV_ID_ICH10_HANKSVILLE)
+		ret_val = e1000_hv_phy_tuning_workaround_ich8lan(hw);
+
+out:
 	return (ret_val);
 }
 
@@ -2001,12 +2400,12 @@
  * @hw: pointer to the HW structure
  *
  * Prepares the hardware for transmit and receive by doing the following:
- *  - initialize hardware bits
- *  - initialize LED identification
- *  - setup receive address registers
- *  - setup flow control
- *  - setup transmit descriptors
- *  - clear statistics
+ * - initialize hardware bits
+ * - initialize LED identification
+ * - setup receive address registers
+ * - setup flow control
+ * - setup transmit descriptors
+ * - clear statistics
  */
 static s32
 e1000_init_hw_ich8lan(struct e1000_hw *hw)
@@ -2021,11 +2420,10 @@
 	e1000_initialize_hw_bits_ich8lan(hw);
 
 	/* Initialize identification LED */
-	ret_val = e1000_id_led_init_generic(hw);
-	if (ret_val) {
+	ret_val = mac->ops.id_led_init(hw);
+	if (ret_val)
+		/* This is not fatal and we should not stop init due to this */
 		DEBUGOUT("Error initializing identification LED\n");
-		/* This is not fatal and we should not stop init due to this */
-	}
 
 	/* Setup the receive address. */
 	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
@@ -2035,6 +2433,18 @@
 	for (i = 0; i < mac->mta_reg_count; i++)
 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
 
+	/*
+	 * The 82578 Rx buffer will stall if wakeup is enabled in host and
+	 * the ME.  Reading the BM_WUC register will clear the host wakeup bit.
+	 * Reset the phy after disabling host wakeup to reset the Rx buffer.
+	 */
+	if (hw->phy.type == e1000_phy_82578) {
+		hw->phy.ops.read_reg(hw, BM_WUC, &i);
+		ret_val = e1000_phy_hw_reset_ich8lan(hw);
+		if (ret_val)
+			return (ret_val);
+	}
+
 	/* Setup link and flow control */
 	ret_val = mac->ops.setup_link(hw);
 
@@ -2094,6 +2504,9 @@
 	/* Extended Device Control */
 	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
 	reg |= (1 << 22);
+	/* Enable PHY low-power state when MAC is at D3 w/o WoL */
+	if (hw->mac.type >= e1000_pchlan)
+		reg |= E1000_CTRL_EXT_PHYPDEN;
 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
 
 	/* Transmit Descriptor Control 0 */
@@ -2171,6 +2584,14 @@
 		goto out;
 
 	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
+	if ((hw->phy.type == e1000_phy_82578) ||
+	    (hw->phy.type == e1000_phy_82577)) {
+		ret_val = hw->phy.ops.write_reg(hw,
+		    PHY_REG(BM_PORT_CTRL_PAGE, 27),
+		    hw->fc.pause_time);
+		if (ret_val)
+			goto out;
+	}
 
 	ret_val = e1000_set_fc_watermarks_generic(hw);
 
@@ -2205,31 +2626,38 @@
 	 * increase the max iterations when polling the phy; this fixes
 	 * erroneous timeouts at 10Mbps.
 	 */
-	ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 4),
-	    0xFFFF);
+	ret_val = e1000_write_kmrn_reg_generic(hw,
+	    E1000_KMRNCTRLSTA_TIMEOUTS, 0xFFFF);
 	if (ret_val)
 		goto out;
-	ret_val = e1000_read_kmrn_reg_generic(hw, GG82563_REG(0x34, 9),
-	    &reg_data);
+	ret_val = e1000_read_kmrn_reg_generic(hw,
+	    E1000_KMRNCTRLSTA_INBAND_PARAM, &reg_data);
 	if (ret_val)
 		goto out;
 	reg_data |= 0x3F;
-	ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 9),
-	    reg_data);
+	ret_val = e1000_write_kmrn_reg_generic(hw,
+	    E1000_KMRNCTRLSTA_INBAND_PARAM, reg_data);
 	if (ret_val)
 		goto out;
 
-	if (hw->phy.type == e1000_phy_igp_3) {
+	switch (hw->phy.type) {
+	case e1000_phy_igp_3:
 		ret_val = e1000_copper_link_setup_igp(hw);
 		if (ret_val)
 			goto out;
-	} else if (hw->phy.type == e1000_phy_bm) {
+		break;
+	case e1000_phy_bm:
+	case e1000_phy_82578:
 		ret_val = e1000_copper_link_setup_m88(hw);
 		if (ret_val)
 			goto out;
-	}
-
-	if (hw->phy.type == e1000_phy_ife) {
+		break;
+	case e1000_phy_82577:
+		ret_val = e1000_copper_link_setup_82577(hw);
+		if (ret_val)
+			goto out;
+		break;
+	case e1000_phy_ife:
 		ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
 		    &reg_data);
 		if (ret_val)
@@ -2253,6 +2681,9 @@
 		    reg_data);
 		if (ret_val)
 			goto out;
+		break;
+	default:
+		break;
 	}
 	ret_val = e1000_setup_copper_link_generic(hw);
 
@@ -2281,6 +2712,14 @@
 	if (ret_val)
 		goto out;
 
+	if ((hw->mac.type == e1000_pchlan) && (*speed == SPEED_1000)) {
+		ret_val = e1000_write_kmrn_reg_generic(hw,
+		    E1000_KMRNCTRLSTA_K1_CONFIG,
+		    E1000_KMRNCTRLSTA_K1_DISABLE);
+		if (ret_val)
+			goto out;
+	}
+
 	if ((hw->mac.type == e1000_ich8lan) &&
 	    (hw->phy.type == e1000_phy_igp_3) &&
 	    (*speed == SPEED_1000)) {
@@ -2298,12 +2737,12 @@
  * 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
+ * 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.
  */
 static s32
@@ -2398,9 +2837,9 @@
  * @hw: pointer to the HW structure
  *
  * Workaround for 82566 power-down on D3 entry:
- *   1) disable gigabit link
- *   2) write VR power-down enable
- *   3) read it back
+ * 1) disable gigabit link
+ * 2) write VR power-down enable
+ * 3) read it back
  * Continue if successful, else issue LCD reset and repeat
  */
 void
@@ -2455,8 +2894,8 @@
  *
  * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
  * LPLU, Gig disable, MDIC PHY reset):
- *   1) Set Kumeran Near-end loopback
- *   2) Clear Kumeran Near-end loopback
+ * 1) Set Kumeran Near-end loopback
+ * 2) Clear Kumeran Near-end loopback
  * Should only be called for ICH8[m] devices with IGP_3 Phy.
  */
 void
@@ -2496,19 +2935,27 @@
  * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
  * to a lower speed.
  *
- * Should only be called for ICH9 and ICH10 devices.
+ * Should only be called for applicable parts.
  */
 void
 e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw)
 {
 	u32 phy_ctrl;
 
-	if ((hw->mac.type == e1000_ich10lan) ||
-	    (hw->mac.type == e1000_ich9lan)) {
+	switch (hw->mac.type) {
+	case e1000_ich9lan:
+	case e1000_ich10lan:
+	case e1000_pchlan:
 		phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
 		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
 		    E1000_PHY_CTRL_GBE_DISABLE;
 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+	/* Workaround SWFLAG unexpectedly set during S0->Sx */
+	if (hw->mac.type == e1000_pchlan)
+		usec_delay(500);
+	default:
+		break;
 	}
 }
 
@@ -2581,6 +3028,104 @@
 }
 
 /*
+ * e1000_setup_led_pchlan - Configures SW controllable LED
+ * @hw: pointer to the HW structure
+ *
+ * This prepares the SW controllable LED for use.
+ */
+static s32
+e1000_setup_led_pchlan(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_setup_led_pchlan");
+
+	return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
+	    (u16)hw->mac.ledctl_mode1));
+}
+
+/*
+ * e1000_cleanup_led_pchlan - Restore the default LED operation
+ * @hw: pointer to the HW structure
+ *
+ * Return the LED back to the default configuration.
+ */
+static s32
+e1000_cleanup_led_pchlan(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_cleanup_led_pchlan");
+
+	return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
+	    (u16)hw->mac.ledctl_default));
+}
+
+/*
+ * e1000_led_on_pchlan - Turn LEDs on
+ * @hw: pointer to the HW structure
+ *
+ * Turn on the LEDs.
+ */
+static s32
+e1000_led_on_pchlan(struct e1000_hw *hw)
+{
+	u16 data = (u16)hw->mac.ledctl_mode2;
+	u32 i, led;
+
+	DEBUGFUNC("e1000_led_on_pchlan");
+
+	/*
+	 * If no link, then turn LED on by setting the invert bit
+	 * for each LED that's mode is "link_up" in ledctl_mode2.
+	 */
+	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
+		for (i = 0; i < 3; i++) {
+			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+			if ((led & E1000_PHY_LED0_MODE_MASK) !=
+			    E1000_LEDCTL_MODE_LINK_UP)
+				continue;
+			if (led & E1000_PHY_LED0_IVRT)
+				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+			else
+				data |= (E1000_PHY_LED0_IVRT << (i * 5));
+		}
+	}
+
+	return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data));
+}
+
+/*
+ * e1000_led_off_pchlan - Turn LEDs off
+ * @hw: pointer to the HW structure
+ *
+ * Turn off the LEDs.
+ */
+static s32
+e1000_led_off_pchlan(struct e1000_hw *hw)
+{
+	u16 data = (u16)hw->mac.ledctl_mode1;
+	u32 i, led;
+
+	DEBUGFUNC("e1000_led_off_pchlan");
+
+	/*
+	 * If no link, then turn LED off by clearing the invert bit
+	 * for each LED that's mode is "link_up" in ledctl_mode1.
+	 */
+	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
+		for (i = 0; i < 3; i++) {
+			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+			if ((led & E1000_PHY_LED0_MODE_MASK) !=
+			    E1000_LEDCTL_MODE_LINK_UP)
+				continue;
+			if (led & E1000_PHY_LED0_IVRT)
+				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+			else
+				data |= (E1000_PHY_LED0_IVRT << (i * 5));
+		}
+	}
+
+	return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data));
+}
+
+/*
  * e1000_get_cfg_done_ich8lan - Read config done bit
  * @hw: pointer to the HW structure
  *
@@ -2596,10 +3141,21 @@
 	s32 ret_val = E1000_SUCCESS;
 	u32 bank = 0;
 
+	if (hw->mac.type >= e1000_pchlan) {
+		u32 status = E1000_READ_REG(hw, E1000_STATUS);
+
+		if (status & E1000_STATUS_PHYRA) {
+			E1000_WRITE_REG(hw, E1000_STATUS, status &
+			    ~E1000_STATUS_PHYRA);
+		} else
+		DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
+	}
+
 	(void) e1000_get_cfg_done_generic(hw);
 
 	/* If EEPROM is not marked present, init the IGP 3 PHY manually */
-	if (hw->mac.type != e1000_ich10lan) {
+	if ((hw->mac.type != e1000_ich10lan) &&
+	    (hw->mac.type != e1000_pchlan)) {
 		if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
 		    (hw->phy.type == e1000_phy_igp_3)) {
 			(void) e1000_phy_init_script_igp3(hw);
@@ -2641,6 +3197,8 @@
 static void
 e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
 {
+	u16 phy_data;
+
 	DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
 
 	e1000_clear_hw_cntrs_base_generic(hw);
@@ -2658,4 +3216,23 @@
 
 	(void) E1000_READ_REG(hw, E1000_IAC);
 	(void) E1000_READ_REG(hw, E1000_ICRXOC);
+
+	/* Clear PHY statistics registers */
+	if ((hw->phy.type == e1000_phy_82578) ||
+	    (hw->phy.type == e1000_phy_82577)) {
+		(void) hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_ECOL_UPPER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_ECOL_LOWER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_MCC_UPPER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_MCC_LOWER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_LATECOL_UPPER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_LATECOL_LOWER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_COLC_UPPER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_COLC_LOWER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_DC_UPPER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_DC_LOWER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_TNCRS_UPPER, &phy_data);
+		(void) hw->phy.ops.read_reg(hw, HV_TNCRS_LOWER, &phy_data);
+	}
 }
--- a/usr/src/uts/common/io/e1000g/e1000_ich8lan.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_ich8lan.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.25 sol_anvik_patch
+ * IntelVersion: 1.37 v3-1-3_2009-8-20
  */
 #ifndef _E1000_ICH8LAN_H_
 #define	_E1000_ICH8LAN_H_
@@ -39,9 +39,10 @@
 #define	ICH_FLASH_FADDR			0x0008
 #define	ICH_FLASH_FDATA0		0x0010
 
-#define	ICH_FLASH_READ_COMMAND_TIMEOUT	500
-#define	ICH_FLASH_WRITE_COMMAND_TIMEOUT	500
-#define	ICH_FLASH_ERASE_COMMAND_TIMEOUT	3000000
+/* Requires up to 10 seconds when MNG might be accessing part. */
+#define	ICH_FLASH_READ_COMMAND_TIMEOUT	10000000
+#define	ICH_FLASH_WRITE_COMMAND_TIMEOUT	10000000
+#define	ICH_FLASH_ERASE_COMMAND_TIMEOUT	10000000
 #define	ICH_FLASH_LINEAR_ADDR_MASK	0x00FFFFFF
 #define	ICH_FLASH_CYCLE_REPEAT_COUNT	10
 
@@ -68,12 +69,14 @@
 #define	E1000_ICH_MNG_IAMT_MODE		0x2
 
 #define	ID_LED_DEFAULT_ICH8LAN	((ID_LED_DEF1_DEF2 << 12) | \
-				(ID_LED_DEF1_OFF2 << 8) | \
-				(ID_LED_DEF1_ON2 << 4) | \
+				(ID_LED_OFF1_OFF2 << 8) | \
+				(ID_LED_OFF1_ON2 << 4) | \
 				(ID_LED_DEF1_DEF2))
 
 #define	E1000_ICH_NVM_SIG_WORD		0x13
 #define	E1000_ICH_NVM_SIG_MASK		0xC000
+#define	E1000_ICH_NVM_VALID_SIG_MASK	0xC0
+#define	E1000_ICH_NVM_SIG_VALUE		0x80
 
 #define	E1000_ICH8_LAN_INIT_TIMEOUT	1500
 
@@ -97,6 +100,49 @@
 #define	IGP3_VR_CTRL_MODE_SHUTDOWN		0x0200
 #define	IGP3_PM_CTRL_FORCE_PWR_DOWN		0x0020
 
+/* PHY Wakeup Registers and defines */
+#define	BM_RCTL		PHY_REG(BM_WUC_PAGE, 0)
+#define	BM_WUC		PHY_REG(BM_WUC_PAGE, 1)
+#define	BM_WUFC		PHY_REG(BM_WUC_PAGE, 2)
+#define	BM_WUS		PHY_REG(BM_WUC_PAGE, 3)
+#define	BM_RAR_L(_i)	(BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
+#define	BM_RAR_M(_i)    (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
+#define	BM_RAR_H(_i)    (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
+#define	BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
+#define	BM_MTA(_i)	(BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
+
+#define	BM_RCTL_UPE	0x0001	/* Unicast Promiscuous Mode */
+#define	BM_RCTL_MPE	0x0002	/* Multicast Promiscuous Mode */
+#define	BM_RCTL_MO_SHIFT	3	/* Multicast Offset Shift */
+#define	BM_RCTL_MO_MASK	(3 << 3)	/* Multicast Offset Mask */
+#define	BM_RCTL_BAM	0x0020	/* Broadcast Accept Mode */
+#define	BM_RCTL_PMCF	0x0040	/* Pass MAC Control Frames */
+#define	BM_RCTL_RFCE	0x0080	/* Rx Flow Control Enable */
+
+#define	HV_LED_CONFIG		PHY_REG(768, 30) /* LED Configuration */
+#define	HV_MUX_DATA_CTRL	PHY_REG(776, 16)
+#define	HV_MUX_DATA_CTRL_GEN_TO_MAC	0x0400
+#define	HV_MUX_DATA_CTRL_FORCE_SPEED	0x0004
+#define	HV_SCC_UPPER		PHY_REG(778, 16) /* Single Collision Count */
+#define	HV_SCC_LOWER		PHY_REG(778, 17)
+#define	HV_ECOL_UPPER		PHY_REG(778, 18) /* Excessive Collision Count */
+#define	HV_ECOL_LOWER		PHY_REG(778, 19)
+#define	HV_MCC_UPPER		PHY_REG(778, 20) /* Multiple Collision Count */
+#define	HV_MCC_LOWER		PHY_REG(778, 21)
+#define	HV_LATECOL_UPPER	PHY_REG(778, 23) /* Late Collision Count */
+#define	HV_LATECOL_LOWER	PHY_REG(778, 24)
+#define	HV_COLC_UPPER		PHY_REG(778, 25) /* Collision Count */
+#define	HV_COLC_LOWER		PHY_REG(778, 26)
+#define	HV_DC_UPPER		PHY_REG(778, 27) /* Defer Count */
+#define	HV_DC_LOWER		PHY_REG(778, 28)
+#define	HV_TNCRS_UPPER		PHY_REG(778, 29) /* Transmit with no CRS */
+#define	HV_TNCRS_LOWER		PHY_REG(778, 30)
+
+/* PCH Flow Control Refresh Timer Value */
+#define	E1000_FCRTV_PCH		0x05F40
+/* SW Semaphore flag timeout in milliseconds */
+#define	SW_FLAG_TIMEOUT		400
+
 /*
  * Additional interrupts need to be handled for ICH family:
  *  DSW = The FW changed the status of the DISSW bit in FWSM
--- a/usr/src/uts/common/io/e1000g/e1000_mac.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_mac.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,11 +24,12 @@
  */
 
 /*
- * IntelVersion: 1.92.4.1 sol_anvik_patch
+ * IntelVersion: 1.108 v3-1-3_2009-8-20
  */
 #include "e1000_api.h"
 
 static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw);
+static void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
 
 /*
  * e1000_init_mac_ops_generic - Initialize MAC function pointers
@@ -48,6 +49,7 @@
 	mac->ops.reset_hw = e1000_null_ops_generic;
 	mac->ops.setup_physical_interface = e1000_null_ops_generic;
 	mac->ops.get_bus_info = e1000_null_ops_generic;
+	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pcie;
 	mac->ops.read_mac_addr = e1000_read_mac_addr_generic;
 	mac->ops.config_collision_dist = e1000_config_collision_dist_generic;
 	mac->ops.clear_hw_cntrs = e1000_null_mac_generic;
@@ -128,10 +130,10 @@
  * @hw: pointer to the HW structure
  */
 void
-e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a, u32 b, u32 c)
+e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a)
 {
 	DEBUGFUNC("e1000_null_update_mc");
-	UNREFERENCED_5PARAMETER(hw, h, a, b, c);
+	UNREFERENCED_3PARAMETER(hw, h, a);
 }
 
 /*
@@ -178,10 +180,10 @@
 s32
 e1000_get_bus_info_pci_generic(struct e1000_hw *hw)
 {
+	struct e1000_mac_info *mac = &hw->mac;
 	struct e1000_bus_info *bus = &hw->bus;
 	u32 status = E1000_READ_REG(hw, E1000_STATUS);
 	s32 ret_val = E1000_SUCCESS;
-	u16 pci_header_type;
 
 	DEBUGFUNC("e1000_get_bus_info_pci_generic");
 
@@ -218,12 +220,7 @@
 	    : e1000_bus_width_32;
 
 	/* Which PCI(-X) function? */
-	e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type);
-	if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC)
-		bus->func = (status & E1000_STATUS_FUNC_MASK)
-		    >> E1000_STATUS_FUNC_SHIFT;
-	else
-		bus->func = 0;
+	mac->ops.set_lan_id(hw);
 
 	return (ret_val);
 }
@@ -239,10 +236,10 @@
 s32
 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw)
 {
+	struct e1000_mac_info *mac = &hw->mac;
 	struct e1000_bus_info *bus = &hw->bus;
 	s32 ret_val;
-	u32 status;
-	u16 pcie_link_status, pci_header_type;
+	u16 pcie_link_status;
 
 	DEBUGFUNC("e1000_get_bus_info_pcie_generic");
 
@@ -259,6 +256,46 @@
 		    PCIE_LINK_WIDTH_MASK) >>
 		    PCIE_LINK_WIDTH_SHIFT);
 
+	mac->ops.set_lan_id(hw);
+
+	return (E1000_SUCCESS);
+}
+
+/*
+ * e1000_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
+ *
+ * @hw: pointer to the HW structure
+ *
+ * Determines the LAN function id by reading memory-mapped registers
+ * and swaps the port value if requested.
+ */
+static void
+e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	u32 reg;
+
+	/*
+	 * The status register reports the correct function number
+	 * for the device regardless of function swap state.
+	 */
+	reg = E1000_READ_REG(hw, E1000_STATUS);
+	bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
+}
+
+/*
+ * e1000_set_lan_id_multi_port_pci - Set LAN id for PCI multiple port devices
+ * @hw: pointer to the HW structure
+ *
+ * Determines the LAN function id by reading PCI config space.
+ */
+void
+e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	u16 pci_header_type;
+	u32 status;
+
 	e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type);
 	if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
 		status = E1000_READ_REG(hw, E1000_STATUS);
@@ -267,8 +304,20 @@
 	} else {
 		bus->func = 0;
 	}
+}
 
-	return (E1000_SUCCESS);
+/*
+ * e1000_set_lan_id_single_port - Set LAN id for a single port device
+ * @hw: pointer to the HW structure
+ *
+ * Sets the LAN function id to zero for a single port device.
+ */
+void
+e1000_set_lan_id_single_port(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+
+	bus->func = 0;
 }
 
 /*
@@ -322,6 +371,7 @@
 e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count)
 {
 	u32 i;
+	u8 mac_addr[ETH_ADDR_LEN] = {0};
 
 	DEBUGFUNC("e1000_init_rx_addrs_generic");
 
@@ -332,12 +382,9 @@
 
 	/* Zero out the other (rar_entry_count - 1) receive addresses */
 	DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count - 1);
-	for (i = 1; i < rar_count; i++) {
-		E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1), 0);
-		E1000_WRITE_FLUSH(hw);
-		E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((i << 1) + 1), 0);
-		E1000_WRITE_FLUSH(hw);
-	}
+	for (i = 1; i < rar_count; i++)
+		hw->mac.ops.rar_set(hw, mac_addr, i);
+
 }
 
 /*
@@ -347,9 +394,10 @@
  * Checks the nvm for an alternate MAC address.  An alternate MAC address
  * can be setup by pre-boot software and must be treated like a permanent
  * address and must override the actual permanent MAC address.  If an
- * alternate MAC address is found it is saved in the hw struct and
- * programmed into RAR0 and the function returns success, otherwise the
- * function returns an error.
+ * alternate MAC address is found it is programmed into RAR0, replacing
+ * the permanent address that was installed into RAR0 by the Si on reset.
+ * This function will return SUCCESS unless it encounters an error while
+ * reading the EEPROM.
  */
 s32
 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
@@ -369,12 +417,12 @@
 	}
 
 	if (nvm_alt_mac_addr_offset == 0xFFFF) {
-		ret_val = -(E1000_NOT_IMPLEMENTED);
+		/* There is no Alternate MAC Address */
 		goto out;
 	}
 
 	if (hw->bus.func == E1000_FUNC_1)
-		nvm_alt_mac_addr_offset += ETH_ADDR_LEN / sizeof (u16);
+		nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
 
 	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
 		offset = nvm_alt_mac_addr_offset + (i >> 1);
@@ -390,14 +438,16 @@
 
 	/* if multicast bit is set, the alternate address will not be used */
 	if (alt_mac_addr[0] & 0x01) {
-		ret_val = -(E1000_NOT_IMPLEMENTED);
+		DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n");
 		goto out;
 	}
 
-	for (i = 0; i < ETH_ADDR_LEN; i++)
-		hw->mac.addr[i] = hw->mac.perm_addr[i] = alt_mac_addr[i];
-
-	hw->mac.ops.rar_set(hw, hw->mac.perm_addr, 0);
+	/*
+	 * We have a valid alternate MAC address, and we want to treat it the
+	 * same as the normal permanent MAC address stored by the HW into the
+	 * RAR. Do this by mapping this address into RAR0.
+	 */
+	hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
 
 out:
 	return (ret_val);
@@ -435,12 +485,13 @@
 
 	/*
 	 * Some bridges will combine consecutive 32-bit writes into
-	 * a single burst write, which will malfunction on some
-	 * 82546 parts.  The flush avoids this.
+	 * a single burst write, which will malfunction on some parts.
+	 * The flushes avoid this.
 	 */
 	E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
 	E1000_WRITE_FLUSH(hw);
 	E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
+	E1000_WRITE_FLUSH(hw);
 }
 
 /*
@@ -485,56 +536,37 @@
  * @hw: pointer to the HW structure
  * @mc_addr_list: array of multicast addresses to program
  * @mc_addr_count: number of multicast addresses to program
- * @rar_used_count: the first RAR register free to program
- * @rar_count: total number of supported Receive Address Registers
  *
- * Updates the Receive Address Registers and Multicast Table Array.
+ * Updates entire Multicast Table Array.
  * The caller must have a packed mc_addr_list of multicast addresses.
- * The parameter rar_count will usually be hw->mac.rar_entry_count
- * unless there are workarounds that change this.
  */
 void
 e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
-    u8 *mc_addr_list, u32 mc_addr_count,
-    u32 rar_used_count, u32 rar_count)
+    u8 *mc_addr_list, u32 mc_addr_count)
 {
-	u32 hash_value;
-	u32 i;
+	u32 hash_value, hash_bit, hash_reg;
+	int i;
 
 	DEBUGFUNC("e1000_update_mc_addr_list_generic");
 
-	/*
-	 * Load the first set of multicast addresses into the exact filters
-	 * (RAR).  If there are not enough to fill the RAR array, clear the
-	 * filters.
-	 */
-	for (i = rar_used_count; i < rar_count; i++) {
-		if (mc_addr_count) {
-			hw->mac.ops.rar_set(hw, mc_addr_list, i);
-			mc_addr_count--;
-			mc_addr_list += ETH_ADDR_LEN;
-		} else {
-			E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0);
-			E1000_WRITE_FLUSH(hw);
-			E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0);
-			E1000_WRITE_FLUSH(hw);
-		}
+	/* clear mta_shadow */
+	memset(&hw->mac.mta_shadow, 0, sizeof (hw->mac.mta_shadow));
+
+	/* update mta_shadow from mc_addr_list */
+	for (i = 0; (u32) i < mc_addr_count; i++) {
+		hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list);
+
+		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+		hash_bit = hash_value & 0x1F;
+
+		hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+		mc_addr_list += (ETH_ADDR_LEN);
 	}
 
-	/* Clear the old settings from the MTA */
-	DEBUGOUT("Clearing MTA\n");
-	for (i = 0; i < hw->mac.mta_reg_count; i++) {
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-		E1000_WRITE_FLUSH(hw);
-	}
-
-	/* Load any remaining multicast addresses into the hash table. */
-	for (; mc_addr_count > 0; mc_addr_count--) {
-		hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list);
-		DEBUGOUT1("Hash value = 0x%03X\n", hash_value);
-		hw->mac.ops.mta_set(hw, hash_value);
-		mc_addr_list += ETH_ADDR_LEN;
-	}
+	/* replace the entire MTA table */
+	for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
+	E1000_WRITE_FLUSH(hw);
 }
 
 /*
--- a/usr/src/uts/common/io/e1000g/e1000_mac.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_mac.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.29 sol_anvik_patch
+ * IntelVersion: 1.32 v3-1-3_2009-8-20
  */
 #ifndef _E1000_MAC_H_
 #define	_E1000_MAC_H_
@@ -42,7 +42,7 @@
 s32 e1000_null_ops_generic(struct e1000_hw *hw);
 s32 e1000_null_link_info(struct e1000_hw *hw, u16 *s, u16 *d);
 bool e1000_null_mng_mode(struct e1000_hw *hw);
-void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a, u32 b, u32 c);
+void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a);
 void e1000_null_write_vfta(struct e1000_hw *hw, u32 a, u32 b);
 void e1000_null_mta_set(struct e1000_hw *hw, u32 a);
 void e1000_null_rar_set(struct e1000_hw *hw, u8 *h, u32 a);
@@ -59,6 +59,8 @@
 s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw);
 s32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw);
 s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw);
+void e1000_set_lan_id_single_port(struct e1000_hw *hw);
+void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw);
 s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw);
 s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
     u16 *duplex);
@@ -68,8 +70,7 @@
 s32 e1000_led_on_generic(struct e1000_hw *hw);
 s32 e1000_led_off_generic(struct e1000_hw *hw);
 void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
-    u8 *mc_addr_list, u32 mc_addr_count,
-    u32 rar_used_count, u32 rar_count);
+    u8 *mc_addr_list, u32 mc_addr_count);
 s32 e1000_set_default_fc_generic(struct e1000_hw *hw);
 s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw);
 s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw);
--- a/usr/src/uts/common/io/e1000g/e1000_manage.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_manage.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.27 sol_anvik_patch
+ * IntelVersion: 1.27 v3-1-3_2009-8-20
  */
 
 #include "e1000_api.h"
--- a/usr/src/uts/common/io/e1000g/e1000_manage.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_manage.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.18 sol_anvik_patch
+ * IntelVersion: 1.18 v3-1-3_2009-8-20
  */
 #ifndef _E1000_MANAGE_H_
 #define	_E1000_MANAGE_H_
--- a/usr/src/uts/common/io/e1000g/e1000_nvm.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_nvm.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.46 sol_anvik_patch
+ * IntelVersion: 1.49 v3-1-3_2009-8-20
  */
 #include "e1000_api.h"
 
@@ -831,31 +831,23 @@
 s32
 e1000_read_mac_addr_generic(struct e1000_hw *hw)
 {
-	s32 ret_val = E1000_SUCCESS;
-	u16 offset, nvm_data, i;
-
-	DEBUGFUNC("e1000_read_mac_addr");
+	u32 rar_high;
+	u32 rar_low;
+	u16 i;
 
-	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
-		offset = i >> 1;
-		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
-		if (ret_val) {
-			DEBUGOUT("NVM Read Error\n");
-			goto out;
-		}
-		hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
-		hw->mac.perm_addr[i + 1] = (u8)(nvm_data >> 8);
-	}
+	rar_high = E1000_READ_REG(hw, E1000_RAH(0));
+	rar_low = E1000_READ_REG(hw, E1000_RAL(0));
 
-	/* Flip last bit of mac address if we're on second port */
-	if (hw->bus.func == E1000_FUNC_1)
-		hw->mac.perm_addr[5] ^= 1;
+	for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
+		hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
+
+	for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
+		hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
 
 	for (i = 0; i < ETH_ADDR_LEN; i++)
 		hw->mac.addr[i] = hw->mac.perm_addr[i];
 
-out:
-	return (ret_val);
+	return (E1000_SUCCESS);
 }
 
 /*
--- a/usr/src/uts/common/io/e1000g/e1000_nvm.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_nvm.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.18 sol_anvik_patch
+ * IntelVersion: 1.18 v3-1-3_2009-8-20
  */
 #ifndef _E1000_NVM_H_
 #define	_E1000_NVM_H_
--- a/usr/src/uts/common/io/e1000g/e1000_osdep.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_osdep.c	Tue Sep 29 12:12:23 2009 +0800
@@ -58,7 +58,7 @@
 /*
  * phy_spd_state - set smart-power-down (SPD) state
  *
- * This only acts on the 82541/47 family and the 82571/72 family.
+ * This only acts on the silicon families that have the SPD feature.
  * For any others, return without doing anything.
  */
 void
@@ -78,6 +78,9 @@
 		break;
 	case e1000_82571:
 	case e1000_82572:
+	case e1000_82573:
+	case e1000_82574:
+	case e1000_82583:
 		offset = IGP02E1000_PHY_POWER_MGMT;
 		spd_bit = IGP02E1000_PM_SPD;
 		break;
@@ -112,21 +115,27 @@
 }
 
 /*
- * Enables PCI-Express master access.
- *
- * hw: Struct containing variables accessed by shared code
- *
- * returns: - none.
+ * For some hardware types, access to NVM & PHY need to be serialized by mutex.
+ * The necessary mutexes will have been created by shared code.  Here we destroy
+ * that mutexes for just the hardware types that need it.
  */
 void
-e1000_enable_pciex_master(struct e1000_hw *hw)
+e1000_destroy_hw_mutex(struct e1000_hw *hw)
 {
-	uint32_t ctrl;
+	struct e1000_dev_spec_ich8lan *dev_spec;
 
-	if (hw->bus.type != e1000_bus_type_pci_express)
-		return;
+	switch (hw->mac.type) {
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+	case e1000_ich10lan:
+	case e1000_pchlan:
+		cmn_err(CE_WARN, "destroy mutexes in e1000_destroy_hw_mutex\n");
+		dev_spec = &hw->dev_spec.ich8lan;
+		E1000_MUTEX_DESTROY(&dev_spec->nvm_mutex);
+		E1000_MUTEX_DESTROY(&dev_spec->swflag_mutex);
+		break;
 
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+	default:
+		break;	/* no action */
+	}
 }
--- a/usr/src/uts/common/io/e1000g/e1000_osdep.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_osdep.h	Tue Sep 29 12:12:23 2009 +0800
@@ -46,6 +46,7 @@
 #include <sys/pci.h>
 #include <sys/atomic.h>
 #include <sys/note.h>
+#include <sys/mutex.h>
 #include "e1000g_debug.h"
 
 #define	usec_delay(x)		drv_usecwait(x)
@@ -75,6 +76,7 @@
 
 #define	false		0
 #define	true		1
+
 #define	CMD_MEM_WRT_INVALIDATE	0x0010	/* BIT_4 */
 #define	PCI_COMMAND_REGISTER	0x04
 #define	PCI_EX_CONF_CAP		0xE0
@@ -193,6 +195,16 @@
 	struct e1000g *adapter;
 };
 
+/* Shared Code Mutex Defines */
+#define	E1000_MUTEX			kmutex_t
+#define	E1000_MUTEX_INIT(mutex)		mutex_init(mutex, NULL, \
+	MUTEX_DRIVER, NULL)
+#define	E1000_MUTEX_DESTROY(mutex)	mutex_destroy(mutex)
+
+#define	E1000_MUTEX_LOCK(mutex)		mutex_enter(mutex)
+#define	E1000_MUTEX_TRYLOCK(mutex)	mutex_tryenter(mutex)
+#define	E1000_MUTEX_UNLOCK(mutex)	mutex_exit(mutex)
+
 #ifdef __sparc	/* on SPARC, use only memory-mapped routines */
 #define	E1000_WRITE_REG_IO	E1000_WRITE_REG
 #else	/* on x86, use port io routines */
--- a/usr/src/uts/common/io/e1000g/e1000_phy.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_phy.c	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.112 sol_anvik_patch
+ * IntelVersion: 1.143 v3-1-3_2009-8-20
  */
 #include "e1000_api.h"
 
@@ -32,6 +32,10 @@
 static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
     u16 *data, bool read);
 
+static u32 e1000_get_phy_addr_for_hv_page(u32 page);
+static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
+    u16 *data, bool read);
+
 /* Cable length tables */
 static const u16 e1000_m88_cable_length_table[] =
 	{0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED};
@@ -168,26 +172,47 @@
 	struct e1000_phy_info *phy = &hw->phy;
 	s32 ret_val = E1000_SUCCESS;
 	u16 phy_id;
+	u16 retry_count = 0;
 
 	DEBUGFUNC("e1000_get_phy_id");
 
 	if (!(phy->ops.read_reg))
 		goto out;
 
-	ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
-	if (ret_val)
-		goto out;
-
-	phy->id = (u32)(phy_id << 16);
-	usec_delay(20);
-	ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
-	if (ret_val)
-		goto out;
-
-	phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
-	phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
-
+	while (retry_count < 2) {
+		ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id = (u32)(phy_id << 16);
+		usec_delay(20);
+		ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+		if (phy->id != 0 && phy->id != PHY_REVISION_MASK)
+			goto out;
+
+		/*
+		 * If the PHY ID is still unknown, we may have an 82577 without
+		 * link. We will try again after setting Slow MDIC mode. No
+		 * harm in trying again in this case since the PHY ID is
+		 * unknown at this point anyway
+		 */
+		ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
+		if (ret_val)
+			goto out;
+
+		retry_count++;
+	}
 out:
+	/* Revert to MDIO fast mode, if applicable */
+	if (retry_count)
+		ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
+
 	return (ret_val);
 }
 
@@ -558,6 +583,51 @@
 }
 
 /*
+ * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up Carrier-sense on Transmit and downshift values.
+ */
+s32
+e1000_copper_link_setup_82577(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+
+	DEBUGFUNC("e1000_copper_link_setup_82577");
+
+	if (phy->reset_disable) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/* Enable CRS on TX. This must be set for half-duplex operation. */
+	ret_val = phy->ops.read_reg(hw, I82577_CFG_REG, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
+
+	/* Enable downshift */
+	phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
+
+	ret_val = phy->ops.write_reg(hw, I82577_CFG_REG, phy_data);
+	if (ret_val)
+		goto out;
+
+	/* Set number of link attempts before downshift */
+	ret_val = phy->ops.read_reg(hw, I82577_CTRL_REG, &phy_data);
+	if (ret_val)
+		goto out;
+	phy_data &= ~I82577_CTRL_DOWNSHIFT_MASK;
+	ret_val = phy->ops.write_reg(hw, I82577_CTRL_REG, phy_data);
+
+out:
+	return (ret_val);
+}
+
+/*
  * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
  * @hw: pointer to the HW structure
  *
@@ -583,8 +653,8 @@
 	if (ret_val)
 		goto out;
 
-	/* For newer PHYs this bit is downshift enable */
-	if (phy->type == e1000_phy_m88)
+	/* For BM PHY this bit is downshift enable */
+	if (phy->type != e1000_phy_bm)
 		phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
 
 	/*
@@ -685,6 +755,21 @@
 		goto out;
 	}
 
+	if (phy->type == e1000_phy_82578) {
+		ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+		    &phy_data);
+		if (ret_val)
+			goto out;
+
+		/* 82578 PHY - set the downshift count to 1x. */
+		phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE;
+		phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK;
+		ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+		    phy_data);
+		if (ret_val)
+			goto out;
+}
+
 out:
 	return (ret_val);
 }
@@ -1315,6 +1400,77 @@
 }
 
 /*
+ * e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex
+ * @hw: pointer to the HW structure
+ *
+ * Forces the speed and duplex settings of the PHY.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ */
+s32
+e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_ife");
+
+	if (phy->type != e1000_phy_ife) {
+		ret_val = e1000_phy_force_speed_duplex_igp(hw);
+		goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	e1000_phy_force_speed_duplex_setup(hw, &data);
+
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
+	if (ret_val)
+		goto out;
+
+	/* Disable MDI-X support for 10/100 */
+	ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~IFE_PMC_AUTO_MDIX;
+	data &= ~IFE_PMC_FORCE_MDIX;
+
+	ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("IFE PMC: %X\n", data);
+
+	usec_delay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
+
+		ret_val = e1000_phy_has_link_generic(hw,
+		    PHY_FORCE_LIMIT, 100000, &link);
+		if (ret_val)
+			goto out;
+
+		if (!link)
+			DEBUGOUT("Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = e1000_phy_has_link_generic(hw,
+		    PHY_FORCE_LIMIT, 100000, &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return (ret_val);
+}
+
+/*
  * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
  * @hw: pointer to the HW structure
  * @phy_ctrl: pointer to current value of PHY_CONTROL
@@ -1367,8 +1523,7 @@
 		DEBUGOUT("Forcing 100mb\n");
 	} else {
 		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
-		/* OR 0x0000 constant for documenting intent */
-		/* LINTED E_EXPR_NULL_EFFECT */
+		/* LINTED */
 		*phy_ctrl |= MII_CR_SPEED_10;
 		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
 		DEBUGOUT("Forcing 10mb\n");
@@ -1497,6 +1652,7 @@
 	case e1000_phy_m88:
 	case e1000_phy_gg82563:
 	case e1000_phy_bm:
+	case e1000_phy_82578:
 		offset = M88E1000_PHY_SPEC_STATUS;
 		mask = M88E1000_PSSR_DOWNSHIFT;
 		break;
@@ -1599,6 +1755,41 @@
 }
 
 /*
+ * e1000_check_polarity_ife - Check cable polarity for IFE PHY
+ * @hw: pointer to the HW structure
+ *
+ * Polarity is determined on the polarity reversal feature being enabled.
+ */
+s32
+e1000_check_polarity_ife(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	DEBUGFUNC("e1000_check_polarity_ife");
+
+	/*
+	 * Polarity is determined based on the reversal feature being enabled.
+	 */
+	if (phy->polarity_correction) {
+		offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
+		mask = IFE_PESC_POLARITY_REVERSED;
+	} else {
+		offset = IFE_PHY_SPECIAL_CONTROL;
+		mask = IFE_PSC_FORCE_POLARITY;
+	}
+
+	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->cable_polarity = (phy_data & mask)
+		    ? e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
+
+	return (ret_val);
+}
+
+/*
  * e1000_wait_autoneg_generic - Wait for auto-neg completion
  * @hw: pointer to the HW structure
  *
@@ -1664,9 +1855,16 @@
 		 * the board.
 		 */
 		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val) {
+			/*
+			 * If the first read fails, another entity may have
+			 * ownership of the resources, wait and try again to
+			 * see if they have relinquished the resources yet.
+			 */
+			usec_delay(usec_interval);
+		}
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
+		    &phy_status);
 		if (ret_val)
 			break;
 		if (phy_status & MII_SR_LINK_STATUS)
@@ -1713,15 +1911,14 @@
 	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
 	    M88E1000_PSSR_CABLE_LENGTH_SHIFT;
 
-	if (index < M88E1000_CABLE_LENGTH_TABLE_SIZE + 1) {
-		phy->min_cable_length = e1000_m88_cable_length_table[index];
-		phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
-
-		phy->cable_length = (phy->min_cable_length +
-		    phy->max_cable_length) / 2;
-	} else {
+	if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
 		ret_val = E1000_ERR_PHY;
+		goto out;
 	}
+	phy->min_cable_length = e1000_m88_cable_length_table[index];
+	phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
 
 out:
 	return (ret_val);
@@ -2171,6 +2368,12 @@
 	case BME1000_E_PHY_ID_R2:
 		phy_type = e1000_phy_bm;
 		break;
+	case I82578_E_PHY_ID:
+		phy_type = e1000_phy_82578;
+		break;
+	case I82577_E_PHY_ID:
+		phy_type = e1000_phy_82577;
+		break;
 	default:
 		phy_type = e1000_phy_unknown;
 		break;
@@ -2194,6 +2397,8 @@
 	u32 i;
 	enum e1000_phy_type phy_type = e1000_phy_unknown;
 
+	hw->phy.id = phy_type;
+
 	for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
 		hw->phy.addr = phy_addr;
 		i = 0;
@@ -2487,11 +2692,17 @@
     u32 offset, u16 *data, bool read)
 {
 	s32 ret_val;
-	u16 reg = ((u16)offset);
+	u16 reg = BM_PHY_REG_NUM(offset);
 	u16 phy_reg = 0;
 	u8 phy_acquired = 1;
 
-	DEBUGFUNC("e1000_read_phy_wakeup_reg_bm");
+	DEBUGFUNC("e1000_access_phy_wakeup_reg_bm");
+
+	/* Gig must be disabled for MDIO accesses to page 800 */
+	if ((hw->mac.type == e1000_pchlan) &&
+	    (!(E1000_READ_REG(hw, E1000_PHY_CTRL) &
+	    E1000_PHY_CTRL_GBE_DISABLE)))
+		DEBUGOUT("Attempting to access page 800 while gig enabled.\n");
 
 	ret_val = hw->phy.ops.acquire(hw);
 	if (ret_val) {
@@ -2546,13 +2757,13 @@
 		ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
 		    data);
 	} else {
-		/* Read the page 800 value using opcode 0x12 */
+		/* Write the page 800 value using opcode 0x12 */
 		ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
 		    *data);
 	}
 
 	if (ret_val) {
-		DEBUGOUT("Could not read data value from page 800\n");
+		DEBUGOUT("Could not access data value from page 800\n");
 		goto out;
 	}
 
@@ -2613,3 +2824,542 @@
 	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
 	msec_delay(1);
 }
+
+s32
+e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 data = 0;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return (ret_val);
+
+	/* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */
+	hw->phy.addr = 1;
+	ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+	    (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_write_phy_reg_mdic(hw, BM_CS_CTRL1,
+	    (0x2180 | (slow << 10)));
+
+	if (ret_val)
+		goto out;
+
+	/* dummy read when reverting to fast mode - throw away result */
+	if (!slow)
+		ret_val = e1000_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data);
+
+out:
+	hw->phy.ops.release(hw);
+	return (ret_val);
+}
+
+/*
+ * e1000_read_phy_reg_hv -  Read HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data.  Release any acquired
+ * semaphore before exiting.
+ */
+s32
+e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val;
+	u16 page = BM_PHY_REG_PAGE(offset);
+	u16 reg = BM_PHY_REG_NUM(offset);
+	bool in_slow_mode = false;
+
+	DEBUGFUNC("e1000_read_phy_reg_hv");
+
+	/* Workaround failure in MDIO access while cable is disconnected */
+	if ((hw->phy.type == e1000_phy_82577) &&
+	    !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
+		ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
+		if (ret_val)
+			goto out;
+
+		in_slow_mode = true;
+	}
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
+		    data, true);
+		goto out;
+	}
+
+	if (page > 0 && page < HV_INTC_FC_PAGE_START) {
+		ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
+		    data, true);
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
+
+	if (page == HV_INTC_FC_PAGE_START)
+		page = 0;
+
+	if (reg > MAX_PHY_MULTI_PAGE_REG) {
+		u32 phy_addr = hw->phy.addr;
+		hw->phy.addr = 1;
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000_write_phy_reg_mdic(hw,
+		    IGP01E1000_PHY_PAGE_SELECT,
+		    (page << IGP_PAGE_SHIFT));
+		hw->phy.addr = phy_addr;
+
+		if (ret_val) {
+			hw->phy.ops.release(hw);
+			goto out;
+		}
+	}
+
+	ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
+	    data);
+	hw->phy.ops.release(hw);
+
+out:
+	/* Revert to MDIO fast mode, if applicable */
+	if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
+		ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
+
+	return (ret_val);
+}
+
+/*
+ * e1000_write_phy_reg_hv - Write HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset.  Release any acquired semaphores before exiting.
+ */
+s32
+e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val;
+	u16 page = BM_PHY_REG_PAGE(offset);
+	u16 reg = BM_PHY_REG_NUM(offset);
+	bool in_slow_mode = false;
+
+	DEBUGFUNC("e1000_write_phy_reg_hv");
+
+	/* Workaround failure in MDIO access while cable is disconnected */
+	if ((hw->phy.type == e1000_phy_82577) &&
+	    !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
+		ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
+		if (ret_val)
+			goto out;
+
+		in_slow_mode = true;
+	}
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
+		    &data, false);
+		goto out;
+	}
+
+	if (page > 0 && page < HV_INTC_FC_PAGE_START) {
+		ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
+		    &data, false);
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
+
+	if (page == HV_INTC_FC_PAGE_START)
+		page = 0;
+
+	/*
+	 * Workaround MDIO accesses being disabled after entering IEEE Power
+	 * Down (whenever bit 11 of the PHY Control register is set)
+	 */
+	if ((hw->phy.type == e1000_phy_82578) &&
+	    (hw->phy.revision >= 1) &&
+	    (hw->phy.addr == 2) &&
+	    ((MAX_PHY_REG_ADDRESS & reg) == 0) &&
+	    (data & (1 << 11))) {
+		u16 data2 = 0x7EFF;
+		hw->phy.ops.release(hw);
+		ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3,
+		    &data2, false);
+		if (ret_val)
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	if (reg > MAX_PHY_MULTI_PAGE_REG) {
+		u32 phy_addr = hw->phy.addr;
+		hw->phy.addr = 1;
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000_write_phy_reg_mdic(hw,
+		    IGP01E1000_PHY_PAGE_SELECT,
+		    (page << IGP_PAGE_SHIFT));
+		hw->phy.addr = phy_addr;
+
+		if (ret_val) {
+			hw->phy.ops.release(hw);
+			goto out;
+		}
+	}
+
+	ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
+	    data);
+	hw->phy.ops.release(hw);
+
+out:
+	/* Revert to MDIO fast mode, if applicable */
+	if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
+		ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
+
+	return (ret_val);
+}
+
+/*
+ * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page
+ * @page: page to be accessed
+ */
+static u32
+e1000_get_phy_addr_for_hv_page(u32 page)
+{
+	u32 phy_addr = 2;
+
+	if (page >= HV_INTC_FC_PAGE_START)
+		phy_addr = 1;
+
+	return (phy_addr);
+}
+
+/*
+ * e1000_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read or written
+ * @data: pointer to the data to be read or written
+ * @read: determines if operation is read or written
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retreived information in data.  Release any acquired
+ * semaphores before exiting.  Note that the procedure to read these regs
+ * uses the address port and data port to read/write.
+ */
+static s32
+e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
+    u16 *data, bool read)
+{
+	s32 ret_val;
+	u32 addr_reg = 0;
+	u32 data_reg = 0;
+	u8  phy_acquired = 1;
+
+	DEBUGFUNC("e1000_access_phy_debug_regs_hv");
+
+	/* This takes care of the difference with desktop vs mobile phy */
+	addr_reg = (hw->phy.type == e1000_phy_82578) ?
+	    I82578_ADDR_REG : I82577_ADDR_REG;
+	data_reg = addr_reg + 1;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val) {
+		DEBUGOUT("Could not acquire PHY\n");
+		phy_acquired = 0;
+		goto out;
+	}
+
+	/* All operations in this function are phy address 2 */
+	hw->phy.addr = 2;
+
+	/* masking with 0x3F to remove the page from offset */
+	ret_val = e1000_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F);
+	if (ret_val) {
+		DEBUGOUT("Could not write PHY the HV address register\n");
+		goto out;
+	}
+
+	/* Read or write the data value next */
+	if (read)
+		ret_val = e1000_read_phy_reg_mdic(hw, data_reg, data);
+	else
+		ret_val = e1000_write_phy_reg_mdic(hw, data_reg, *data);
+
+	if (ret_val) {
+		DEBUGOUT("Could not read data value from HV data register\n");
+		goto out;
+	}
+
+out:
+	if (phy_acquired == 1)
+		hw->phy.ops.release(hw);
+	return (ret_val);
+}
+
+/*
+ * e1000_link_stall_workaround_hv - Si workaround
+ * @hw: pointer to the HW structure
+ *
+ * This function works around a Si bug where the link partner can get
+ * a link up indication before the PHY does.  If small packets are sent
+ * by the link partner they can be placed in the packet buffer without
+ * being properly accounted for by the PHY and will stall preventing
+ * further packets from being received.  The workaround is to clear the
+ * packet buffer after the PHY detects link up.
+ */
+s32
+e1000_link_stall_workaround_hv(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	DEBUGFUNC("e1000_link_stall_workaround_hv");
+
+	if (hw->phy.type != e1000_phy_82578)
+		goto out;
+
+	/* Do not apply workaround if in PHY loopback bit 14 set */
+	hw->phy.ops.read_reg(hw, PHY_CONTROL, &data);
+	if (data & PHY_CONTROL_LB)
+		goto out;
+
+	/* check if link is up and at 1Gbps */
+	ret_val = hw->phy.ops.read_reg(hw, BM_CS_STATUS, &data);
+	if (ret_val)
+		goto out;
+
+	data &= BM_CS_STATUS_LINK_UP |
+	    BM_CS_STATUS_RESOLVED |
+	    BM_CS_STATUS_SPEED_MASK;
+
+	if (data != (BM_CS_STATUS_LINK_UP |
+	    BM_CS_STATUS_RESOLVED |
+	    BM_CS_STATUS_SPEED_1000))
+		goto out;
+
+	msec_delay(200);
+
+	/* flush the packets in the fifo buffer */
+	ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
+	    HV_MUX_DATA_CTRL_GEN_TO_MAC | HV_MUX_DATA_CTRL_FORCE_SPEED);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
+	    HV_MUX_DATA_CTRL_GEN_TO_MAC);
+
+out:
+	return (ret_val);
+}
+
+/*
+ * e1000_check_polarity_82577 - Checks the polarity.
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ * Polarity is determined based on the PHY specific status register.
+ */
+s32
+e1000_check_polarity_82577(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	DEBUGFUNC("e1000_check_polarity_82577");
+
+	ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
+		    ? e1000_rev_polarity_reversed
+		    : e1000_rev_polarity_normal;
+
+	return (ret_val);
+}
+
+/*
+ * e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex.  Clears the
+ * auto-crossover to force MDI manually.  Waits for link and returns
+ * successful if link up is successful, else -E1000_ERR_PHY (-2).
+ */
+s32
+e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_82577");
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  82577 requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = phy->ops.read_reg(hw, I82577_PHY_CTRL_2, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX;
+	phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX;
+
+	ret_val = phy->ops.write_reg(hw, I82577_PHY_CTRL_2, phy_data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("I82577_PHY_CTRL_2: %X\n", phy_data);
+
+	usec_delay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link on 82577 phy\n");
+
+		ret_val = e1000_phy_has_link_generic(hw,
+		    PHY_FORCE_LIMIT, 100000, &link);
+		if (ret_val)
+			goto out;
+
+		if (!link)
+			DEBUGOUT("Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = e1000_phy_has_link_generic(hw,
+		    PHY_FORCE_LIMIT, 100000, &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return (ret_val);
+}
+
+/*
+ * e1000_get_phy_info_82577 - Retrieve I82577 PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Read PHY status to determine if link is up.  If link is up, then
+ * set/determine 10base-T extended distance and polarity correction.  Read
+ * PHY port status to determine MDI/MDIx and speed.  Based on the speed,
+ * determine on the cable length, local and remote receiver.
+ */
+s32
+e1000_get_phy_info_82577(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	DEBUGFUNC("e1000_get_phy_info_82577");
+
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		DEBUGOUT("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	phy->polarity_correction = true;
+
+	ret_val = e1000_check_polarity_82577(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false;
+
+	if ((data & I82577_PHY_STATUS2_SPEED_MASK) ==
+	    I82577_PHY_STATUS2_SPEED_1000MBPS) {
+		ret_val = hw->phy.ops.get_cable_length(hw);
+		if (ret_val)
+			goto out;
+
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+		    ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+		    ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
+	} else {
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+
+out:
+	return (ret_val);
+}
+
+/*
+ * e1000_get_cable_length_82577 - Determine cable length for 82577 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Reads the diagnostic status register and verifies result is valid before
+ * placing it in the phy_cable_length field.
+ */
+s32
+e1000_get_cable_length_82577(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, length;
+
+	DEBUGFUNC("e1000_get_cable_length_82577");
+
+	ret_val = phy->ops.read_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data);
+	if (ret_val)
+		goto out;
+
+	length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
+	    I82577_DSTATUS_CABLE_LENGTH_SHIFT;
+
+	if (length == E1000_CABLE_LENGTH_UNDEFINED)
+		ret_val = E1000_ERR_PHY;
+
+	phy->cable_length = length;
+
+out:
+	return (ret_val);
+}
--- a/usr/src/uts/common/io/e1000g/e1000_phy.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_phy.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.55 sol_anvik_patch
+ * IntelVersion: 1.70 v3-1-3_2009-8-20
  */
 #ifndef _E1000_PHY_H_
 #define	_E1000_PHY_H_
@@ -41,12 +41,14 @@
 s32 e1000_check_downshift_generic(struct e1000_hw *hw);
 s32 e1000_check_polarity_m88(struct e1000_hw *hw);
 s32 e1000_check_polarity_igp(struct e1000_hw *hw);
+s32 e1000_check_polarity_ife(struct e1000_hw *hw);
 s32 e1000_check_reset_block_generic(struct e1000_hw *hw);
 s32 e1000_copper_link_autoneg(struct e1000_hw *hw);
 s32 e1000_copper_link_setup_igp(struct e1000_hw *hw);
 s32 e1000_copper_link_setup_m88(struct e1000_hw *hw);
 s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw);
 s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw);
 s32 e1000_get_cable_length_m88(struct e1000_hw *hw);
 s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw);
 s32 e1000_get_cfg_done_generic(struct e1000_hw *hw);
@@ -81,6 +83,15 @@
 void e1000_power_down_phy_copper(struct e1000_hw *hw);
 s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
 s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow);
+s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw);
+s32 e1000_copper_link_setup_82577(struct e1000_hw *hw);
+s32 e1000_check_polarity_82577(struct e1000_hw *hw);
+s32 e1000_get_phy_info_82577(struct e1000_hw *hw);
+s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw);
+s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
 
 #define	E1000_MAX_PHY_ADDR		4
 
@@ -97,21 +108,70 @@
 #define	IGP_PAGE_SHIFT			5
 #define	PHY_REG_MASK			0x1F
 
+/* BM/HV Specific Registers */
+#define	BM_PORT_CTRL_PAGE		769
+#define	BM_PCIE_PAGE			770
 #define	BM_WUC_PAGE			800
 #define	BM_WUC_ADDRESS_OPCODE		0x11
 #define	BM_WUC_DATA_OPCODE		0x12
-#define	BM_WUC_ENABLE_PAGE		769
+#define	BM_WUC_ENABLE_PAGE		BM_PORT_CTRL_PAGE
 #define	BM_WUC_ENABLE_REG		17
 #define	BM_WUC_ENABLE_BIT		(1 << 2)
 #define	BM_WUC_HOST_WU_BIT		(1 << 4)
 
+#define	PHY_UPPER_SHIFT			21
+#define	BM_PHY_REG(page, reg) \
+	(((reg) & MAX_PHY_REG_ADDRESS) |\
+	(((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
+	(((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))
+#define	BM_PHY_REG_PAGE(offset) \
+	((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF))
+#define	BM_PHY_REG_NUM(offset) \
+	((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\
+	(((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\
+	~MAX_PHY_REG_ADDRESS)))
+
+#define	HV_INTC_FC_PAGE_START		768
+#define	I82578_ADDR_REG			29
+#define	I82577_ADDR_REG			16
+#define	I82577_CFG_REG			22
+#define	I82577_CFG_ASSERT_CRS_ON_TX	(1 << 15)
+#define	I82577_CFG_ENABLE_DOWNSHIFT	(3 << 10) /* auto downshift 100/10 */
+#define	I82577_CTRL_REG			23
+#define	I82577_CTRL_DOWNSHIFT_MASK	(7 << 10)
+
+/* 82577 specific PHY registers */
+#define	I82577_PHY_CTRL_2		18
+#define	I82577_PHY_LBK_CTRL		19
+#define	I82577_PHY_STATUS_2		26
+#define	I82577_PHY_DIAG_STATUS		31
+
+/* I82577 PHY Status 2 */
+#define	I82577_PHY_STATUS2_REV_POLARITY		0x0400
+#define	I82577_PHY_STATUS2_MDIX			0x0800
+#define	I82577_PHY_STATUS2_SPEED_MASK		0x0300
+#define	I82577_PHY_STATUS2_SPEED_1000MBPS	0x0200
+#define	I82577_PHY_STATUS2_SPEED_100MBPS	0x0100
+
+/* I82577 PHY Control 2 */
+#define	I82577_PHY_CTRL2_AUTO_MDIX		0x0400
+#define	I82577_PHY_CTRL2_FORCE_MDI_MDIX		0x0200
+
+/* I82577 PHY Diagnostics Status */
+#define	I82577_DSTATUS_CABLE_LENGTH		0x03FC
+#define	I82577_DSTATUS_CABLE_LENGTH_SHIFT	2
+
 /* BM PHY Copper Specific Control 1 */
 #define	BM_CS_CTRL1			16
 #define	BM_CS_CTRL1_ENERGY_DETECT	0x0300	/* Enable Energy Detect */
 
-/* BM PHY Copper Specific States */
+/* BM PHY Copper Specific Status */
 #define	BM_CS_STATUS			17
 #define	BM_CS_STATUS_ENERGY_DETECT	0x0010	/* Energy Detect Status */
+#define	BM_CS_STATUS_LINK_UP		0x0400
+#define	BM_CS_STATUS_RESOLVED		0x0800
+#define	BM_CS_STATUS_SPEED_MASK		0xC000
+#define	BM_CS_STATUS_SPEED_1000		0x8000
 
 #define	IGP01E1000_PHY_PCS_INIT_REG	0x00B4
 #define	IGP01E1000_PHY_POLARITY_MASK	0x0078
@@ -132,7 +192,7 @@
 #define	IGP01E1000_PLHR_SS_DOWNGRADE	0x8000
 
 #define	IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
-#define	IGP01E1000_PSSR_MDIX		0x0008
+#define	IGP01E1000_PSSR_MDIX		0x0800
 #define	IGP01E1000_PSSR_SPEED_MASK	0xC000
 #define	IGP01E1000_PSSR_SPEED_1000MBPS	0xC000
 
@@ -155,7 +215,12 @@
 #define	E1000_KMRNCTRLSTA_OFFSET_SHIFT	16
 #define	E1000_KMRNCTRLSTA_REN		0x00200000
 #define	E1000_KMRNCTRLSTA_DIAG_OFFSET	0x3	/* Kumeran Diagnostic */
+#define	E1000_KMRNCTRLSTA_TIMEOUTS	0x4	/* Kumeran Timeouts */
+#define	E1000_KMRNCTRLSTA_INBAND_PARAM	0x9	/* Kumeran InBand Parameters */
 #define	E1000_KMRNCTRLSTA_DIAG_NELPBK	0x1000	/* Nearend Loopback mode */
+#define	E1000_KMRNCTRLSTA_K1_CONFIG	0x7
+#define	E1000_KMRNCTRLSTA_K1_ENABLE	0x140E
+#define	E1000_KMRNCTRLSTA_K1_DISABLE	0x1400
 
 #define	IFE_PHY_EXTENDED_STATUS_CONTROL	0x10
 #define	IFE_PHY_SPECIAL_CONTROL		0x11 /* 100BaseTx PHY Special Control */
--- a/usr/src/uts/common/io/e1000g/e1000_regs.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000_regs.h	Tue Sep 29 12:12:23 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.61 sol_anvik_patch
+ * IntelVersion: 1.76 v3-1-3_2009-8-20
  */
 #ifndef _E1000_REGS_H_
 #define	_E1000_REGS_H_
@@ -56,10 +56,13 @@
 #define	E1000_IMC	0x000D8  /* Interrupt Mask Clear - WO */
 #define	E1000_IAM	0x000E0  /* Interrupt Acknowledge Auto Mask */
 #define	E1000_IVAR	0x000E4  /* Interrupt Vector Allocation Register - RW */
+#define	E1000_SVCR	0x000F0
+#define	E1000_SVT	0x000F4
 #define	E1000_RCTL	0x00100  /* Rx Control - RW */
 #define	E1000_FCTTV	0x00170  /* Flow Control Transmit Timer Value - RW */
 #define	E1000_TXCW	0x00178  /* Tx Configuration Word - RW */
 #define	E1000_RXCW	0x00180  /* Rx Configuration Word - RO */
+#define	E1000_PBA_ECC	0x01100  /* PBA ECC Register */
 #define	E1000_TCTL	0x00400  /* Tx Control - RW */
 #define	E1000_TCTL_EXT	0x00404  /* Extended Tx Control - RW */
 #define	E1000_TIPG	0x00410  /* Tx Inter-packet gap -RW */
@@ -247,6 +250,8 @@
 /* Interrupt Cause Receiver Overrun Count */
 #define	E1000_ICRXOC	0x04124
 
+#define	E1000_CRC_OFFSET	0x05F50	/* CRC Offset register */
+
 #define	E1000_PCS_CFG0	0x04200  /* PCS Configuration 0 - RW */
 #define	E1000_PCS_LCTL	0x04208  /* PCS Link Control - RW */
 #define	E1000_PCS_LSTAT	0x0420C  /* PCS Link Status - RO */
@@ -301,6 +306,7 @@
 #define	E1000_GIOCTL	0x05B44 /* GIO Analog Control Register */
 #define	E1000_SCCTL	0x05B4C /* PCIc PLL Configuration Register */
 #define	E1000_GCR	0x05B00 /* PCI-Ex Control */
+#define	E1000_GCR2	0x05B64 /* PCI-Ex Control #2 */
 #define	E1000_GSCL_1	0x05B10 /* PCI-Ex Statistic Control #1 */
 #define	E1000_GSCL_2	0x05B14 /* PCI-Ex Statistic Control #2 */
 #define	E1000_GSCL_3	0x05B18 /* PCI-Ex Statistic Control #3 */
@@ -308,6 +314,8 @@
 #define	E1000_FACTPS	0x05B30 /* Function Active and Power State to MNG */
 #define	E1000_SWSM	0x05B50 /* SW Semaphore */
 #define	E1000_FWSM	0x05B54 /* FW Semaphore */
+/* Driver-only SW semaphore (not used by BOOT agents) */
+#define	E1000_SWSM2	0x05B58
 #define	E1000_DCA_ID	0x05B70 /* DCA Requester ID Information - RO */
 #define	E1000_DCA_CTRL	0x05B74 /* DCA Control - RW */
 #define	E1000_FFLT_DBG	0x05F04 /* Debug Register */
--- a/usr/src/uts/common/io/e1000g/e1000g.conf	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000g.conf	Tue Sep 29 12:12:23 2009 +0800
@@ -6,7 +6,7 @@
 #
 # CDDL LICENSE SUMMARY
 #
-# Copyright(c) 1999 - 2007 Intel Corporation. All rights reserved.
+# Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
 #
 # The contents of this file are subject to the terms of Version
 # 1.0 of the Common Development and Distribution License (the "License").
@@ -18,12 +18,10 @@
 # and limitations under the License.
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms of the CDDLv1.
 #
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 # Driver.conf file for Intel e1000g Gigabit Ethernet Adapter
 #
 ForceSpeedDuplex=7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7;
@@ -54,11 +52,17 @@
         # 1 is for upto 4k size frames.
         # 2 is for upto 8k size frames.
         # 3 is for upto 16k size frames.
-        # These are maximum frame limits, not the actual ethernet frame
-        # size. Your actual ethernet frame size would be determined by
-        # protocol stack configuration (please refer to ndd command man pages)
-        # For Jumbo Frame Support (9k ethernet packet) 
-        # use 3 (upto 16k size frames)
+	#
+	# These are maximum frame limits, not the ethernet payload size
+	# (usually called MTU).  Your actual ethernet MTU is determined by frame
+	# size limit and protocol stack configuration (please refer to ndd
+	# command man pages)
+	#
+	# For Jumbo Frame Support (9k ethernet packet) use 3 (upto 16k size
+	# frames).  On PCH adapter type (82577 and 82578) you can configure up
+	# to 4k size frames.  The 4k size is only allowed at 1gig speed, so if
+	# you select 4k frames size, you cannot force or autonegotiate the
+	# 10/100 speed options.
 FlowControl=3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3;
         # 0:  Flow control is completely disabled
         # 1:  Rx flow control is enabled (we can receive pause frames
--- a/usr/src/uts/common/io/e1000g/e1000g_debug.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000g_debug.c	Tue Sep 29 12:12:23 2009 +0800
@@ -6,7 +6,7 @@
  *
  * CDDL LICENSE SUMMARY
  *
- * Copyright(c) 1999 - 2008 Intel Corporation. All rights reserved.
+ * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
  *
  * The contents of this file are subject to the terms of Version
  * 1.0 of the Common Development and Distribution License (the "License").
@@ -19,7 +19,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms of the CDDLv1.
  */
 
@@ -56,8 +56,9 @@
 	char		name[10];
 	uint32_t	offset;
 } Regi_t;
+
 int e1000g_debug = E1000G_WARN_LEVEL;
-#endif
+#endif	/* E1000G_DEBUG */
 int e1000g_log_mode = E1000G_LOG_PRINT;
 
 void
@@ -595,4 +596,4 @@
 		    name, base, tag_type, size, tag_mem);
 	}
 }
-#endif
+#endif	/* E1000G_DEBUG */
--- a/usr/src/uts/common/io/e1000g/e1000g_main.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000g_main.c	Tue Sep 29 12:12:23 2009 +0800
@@ -46,7 +46,7 @@
 
 static char ident[] = "Intel PRO/1000 Ethernet";
 static char e1000g_string[] = "Intel(R) PRO/1000 Network Connection";
-static char e1000g_version[] = "Driver Ver. 5.3.14";
+static char e1000g_version[] = "Driver Ver. 5.3.15";
 
 /*
  * Proto types for DDI entry points
@@ -94,6 +94,8 @@
 static int e1000g_unicst_set(struct e1000g *, const uint8_t *, int);
 static int e1000g_alloc_rx_data(struct e1000g *);
 static void e1000g_release_multicast(struct e1000g *);
+static void e1000g_pch_limits(struct e1000g *);
+static uint32_t e1000g_mtu2maxframe(uint32_t);
 
 /*
  * Local routines
@@ -116,6 +118,7 @@
 static void stop_link_timer(struct e1000g *);
 static void stop_82547_timer(e1000g_tx_ring_t *);
 static void e1000g_force_speed_duplex(struct e1000g *);
+static void e1000g_setup_max_mtu(struct e1000g *);
 static void e1000g_get_max_frame_size(struct e1000g *);
 static boolean_t is_valid_mac_addr(uint8_t *);
 static void e1000g_unattach(dev_info_t *, struct e1000g *);
@@ -668,7 +671,8 @@
 	/* ICH needs to map flash memory */
 	if (hw->mac.type == e1000_ich8lan ||
 	    hw->mac.type == e1000_ich9lan ||
-	    hw->mac.type == e1000_ich10lan) {
+	    hw->mac.type == e1000_ich10lan ||
+	    hw->mac.type == e1000_pchlan) {
 		/* get flash size */
 		if (ddi_dev_regsize(devinfo, ICH_FLASH_REG_SET,
 		    &mem_size) != DDI_SUCCESS) {
@@ -766,6 +770,9 @@
 	Adapter->strip_crc = B_FALSE;
 #endif
 
+	/* setup the maximum MTU size of the chip */
+	e1000g_setup_max_mtu(Adapter);
+
 	/* Get conf file properties */
 	e1000g_get_conf(Adapter);
 
@@ -777,6 +784,9 @@
 	/* Get Jumbo Frames settings in conf file */
 	e1000g_get_max_frame_size(Adapter);
 
+	/* enforce PCH limits */
+	e1000g_pch_limits(Adapter);
+
 	/* Set Rx/Tx buffer size */
 	e1000g_set_bufsize(Adapter);
 
@@ -810,6 +820,47 @@
 }
 
 static void
+e1000g_setup_max_mtu(struct e1000g *Adapter)
+{
+	struct e1000_mac_info *mac = &Adapter->shared.mac;
+	struct e1000_phy_info *phy = &Adapter->shared.phy;
+
+	switch (mac->type) {
+	/* types that do not support jumbo frames */
+	case e1000_ich8lan:
+	case e1000_82573:
+	case e1000_82583:
+		Adapter->max_mtu = ETHERMTU;
+		break;
+	/* ich9 supports jumbo frames except on one phy type */
+	case e1000_ich9lan:
+		if (phy->type == e1000_phy_ife)
+			Adapter->max_mtu = ETHERMTU;
+		else
+			Adapter->max_mtu = MAXIMUM_MTU_9K;
+		break;
+	/* pch can do jumbo frames up to 4K */
+	case e1000_pchlan:
+		Adapter->max_mtu = MAXIMUM_MTU_4K;
+		break;
+	/* types with a special limit */
+	case e1000_82571:
+	case e1000_82572:
+	case e1000_82574:
+	case e1000_80003es2lan:
+	case e1000_ich10lan:
+		Adapter->max_mtu = MAXIMUM_MTU_9K;
+		break;
+	/* default limit is 16K */
+	default:
+		Adapter->max_mtu = FRAME_SIZE_UPTO_16K -
+		    sizeof (struct ether_vlan_header) - ETHERFCSL -
+		    E1000G_IPALIGNPRESERVEROOM;
+		break;
+	}
+}
+
+static void
 e1000g_set_bufsize(struct e1000g *Adapter)
 {
 	struct e1000_mac_info *mac = &Adapter->shared.mac;
@@ -1099,6 +1150,9 @@
 	mutex_destroy(&Adapter->link_lock);
 	mutex_destroy(&Adapter->watchdog_lock);
 	rw_destroy(&Adapter->chip_lock);
+
+	/* destory mutex initialized in shared code */
+	e1000_destroy_hw_mutex(&Adapter->shared);
 }
 
 static int
@@ -1280,6 +1334,8 @@
 		pba = E1000_PBA_10K;
 	} else if (hw->mac.type == e1000_ich10lan) {
 		pba = E1000_PBA_10K;
+	} else if (hw->mac.type == e1000_pchlan) {
+		pba = E1000_PBA_26K;
 	} else {
 		/*
 		 * Total FIFO is 40K
@@ -1378,7 +1434,8 @@
 	 * Setup and initialize the mctable structures.  After this routine
 	 * completes  Multicast table will be set
 	 */
-	e1000g_setup_multicast(Adapter);
+	e1000_update_mc_addr_list(hw,
+	    (uint8_t *)Adapter->mcast_table, Adapter->mcast_count);
 	msec_delay(5);
 
 	/*
@@ -1408,11 +1465,6 @@
 	}
 	mutex_exit(&Adapter->link_lock);
 
-	/* Enable PCI-Ex master */
-	if (hw->bus.type == e1000_bus_type_pci_express) {
-		e1000_enable_pciex_master(hw);
-	}
-
 	/* Save the state of the phy */
 	e1000g_get_phy_state(Adapter);
 
@@ -1497,20 +1549,33 @@
 static boolean_t
 e1000g_link_up(struct e1000g *Adapter)
 {
-	struct e1000_hw *hw;
-	boolean_t link_up;
-
-	hw = &Adapter->shared;
-
-	(void) e1000_check_for_link(hw);
-
-	if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU) ||
-	    ((!hw->mac.get_link_status) && (hw->mac.type == e1000_82543)) ||
-	    ((hw->phy.media_type == e1000_media_type_internal_serdes) &&
-	    (hw->mac.serdes_has_link))) {
-		link_up = B_TRUE;
-	} else {
-		link_up = B_FALSE;
+	struct e1000_hw *hw = &Adapter->shared;
+	boolean_t link_up = B_FALSE;
+
+	/*
+	 * get_link_status is set in the interrupt handler on link-status-change
+	 * or rx sequence error interrupt.  get_link_status will stay
+	 * false until the e1000_check_for_link establishes link only
+	 * for copper adapters.
+	 */
+	switch (hw->phy.media_type) {
+	case e1000_media_type_copper:
+		if (hw->mac.get_link_status) {
+			(void) e1000_check_for_link(hw);
+			link_up = !hw->mac.get_link_status;
+		} else {
+			link_up = B_TRUE;
+		}
+		break;
+	case e1000_media_type_fiber:
+		(void) e1000_check_for_link(hw);
+		link_up = (E1000_READ_REG(hw, E1000_STATUS) &
+		    E1000_STATUS_LU);
+		break;
+	case e1000_media_type_internal_serdes:
+		(void) e1000_check_for_link(hw);
+		link_up = hw->mac.serdes_has_link;
+		break;
 	}
 
 	return (link_up);
@@ -2403,11 +2468,8 @@
 	 */
 	e1000g_clear_interrupt(Adapter);
 
-	e1000g_setup_multicast(Adapter);
-
-	if ((hw->mac.type == e1000_82542) &&
-	    (hw->revision_id == E1000_REVISION_2))
-		e1000g_rx_setup(Adapter);
+	e1000_update_mc_addr_list(hw,
+	    (uint8_t *)Adapter->mcast_table, Adapter->mcast_count);
 
 	e1000g_mask_interrupt(Adapter);
 
@@ -2463,11 +2525,8 @@
 	 */
 	e1000g_clear_interrupt(Adapter);
 
-	e1000g_setup_multicast(Adapter);
-
-	if ((hw->mac.type == e1000_82542) &&
-	    (hw->revision_id == E1000_REVISION_2))
-		e1000g_rx_setup(Adapter);
+	e1000_update_mc_addr_list(hw,
+	    (uint8_t *)Adapter->mcast_table, Adapter->mcast_count);
 
 	e1000g_mask_interrupt(Adapter);
 
@@ -2489,98 +2548,6 @@
 	}
 }
 
-/*
- * e1000g_setup_multicast - setup multicast data structures
- *
- * This routine initializes all of the multicast related structures.
- */
-void
-e1000g_setup_multicast(struct e1000g *Adapter)
-{
-	uint8_t *mc_addr_list;
-	uint32_t mc_addr_count;
-	uint32_t rctl;
-	struct e1000_hw *hw;
-
-	hw = &Adapter->shared;
-
-	/*
-	 * The e1000g has the ability to do perfect filtering of 16
-	 * addresses. The driver uses one of the e1000g's 16 receive
-	 * address registers for its node/network/mac/individual address.
-	 * So, we have room for up to 15 multicast addresses in the CAM,
-	 * additional MC addresses are handled by the MTA (Multicast Table
-	 * Array)
-	 */
-
-	rctl = E1000_READ_REG(hw, E1000_RCTL);
-
-	mc_addr_list = (uint8_t *)Adapter->mcast_table;
-
-	ASSERT(Adapter->mcast_count <= Adapter->mcast_max_num);
-
-	mc_addr_count = Adapter->mcast_count;
-	/*
-	 * The Wiseman 2.0 silicon has an errata by which the receiver will
-	 * hang  while writing to the receive address registers if the receiver
-	 * is not in reset before writing to the registers. Updating the RAR
-	 * is done during the setting up of the multicast table, hence the
-	 * receiver has to be put in reset before updating the multicast table
-	 * and then taken out of reset at the end
-	 */
-	/*
-	 * if WMI was enabled then dis able it before issueing the global
-	 * reset to the hardware.
-	 */
-	/*
-	 * Only required for WISEMAN_2_0
-	 */
-	if ((hw->mac.type == e1000_82542) &&
-	    (hw->revision_id == E1000_REVISION_2)) {
-		e1000_pci_clear_mwi(hw);
-		/*
-		 * The e1000g must be in reset before changing any RA
-		 * registers. Reset receive unit.  The chip will remain in
-		 * the reset state until software explicitly restarts it.
-		 */
-		E1000_WRITE_REG(hw, E1000_RCTL, E1000_RCTL_RST);
-		/* Allow receiver time to go in to reset */
-		msec_delay(5);
-	}
-
-	e1000_update_mc_addr_list(hw, mc_addr_list, mc_addr_count,
-	    Adapter->unicst_total, hw->mac.rar_entry_count);
-
-	/*
-	 * Only for Wiseman_2_0
-	 * If MWI was enabled then re-enable it after issueing (as we
-	 * disabled it up there) the receive reset command.
-	 * Wainwright does not have a receive reset command and only thing
-	 * close to it is global reset which will require tx setup also
-	 */
-	if ((hw->mac.type == e1000_82542) &&
-	    (hw->revision_id == E1000_REVISION_2)) {
-		/*
-		 * if WMI was enabled then reenable it after issueing the
-		 * global or receive reset to the hardware.
-		 */
-
-		/*
-		 * Take receiver out of reset
-		 * clear E1000_RCTL_RST bit (and all others)
-		 */
-		E1000_WRITE_REG(hw, E1000_RCTL, 0);
-		msec_delay(5);
-		if (hw->bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
-			e1000_pci_set_mwi(hw);
-	}
-
-	/*
-	 * Restore original value
-	 */
-	E1000_WRITE_REG(hw, E1000_RCTL, rctl);
-}
-
 int
 e1000g_m_multicst(void *arg, boolean_t add, const uint8_t *addr)
 {
@@ -2995,14 +2962,11 @@
     uint_t pr_valsize, const void *pr_val)
 {
 	struct e1000g *Adapter = arg;
-	struct e1000_mac_info *mac = &Adapter->shared.mac;
-	struct e1000_phy_info *phy = &Adapter->shared.phy;
 	struct e1000_hw *hw = &Adapter->shared;
 	struct e1000_fc_info *fc = &Adapter->shared.fc;
 	int err = 0;
 	link_flowctrl_t flowctrl;
 	uint32_t cur_mtu, new_mtu;
-	uint64_t tmp = 0;
 
 	rw_enter(&Adapter->chip_lock, RW_WRITER);
 
@@ -3092,6 +3056,8 @@
 			}
 reset:
 			if (err == 0) {
+				/* check PCH limits & reset the link */
+				e1000g_pch_limits(Adapter);
 				if (e1000g_reset_link(Adapter) != DDI_SUCCESS)
 					err = EINVAL;
 			}
@@ -3109,43 +3075,40 @@
 			err = ENOTSUP; /* read-only prop. Can't set this. */
 			break;
 		case MAC_PROP_MTU:
+			/* adapter must be stopped for an MTU change */
+			if (Adapter->e1000g_state & E1000G_STARTED) {
+				err = EBUSY;
+				break;
+			}
+
 			cur_mtu = Adapter->default_mtu;
+
+			/* get new requested MTU */
 			bcopy(pr_val, &new_mtu, sizeof (new_mtu));
 			if (new_mtu == cur_mtu) {
 				err = 0;
 				break;
 			}
 
-			tmp = new_mtu + sizeof (struct ether_vlan_header) +
-			    ETHERFCSL;
-			if ((tmp < DEFAULT_FRAME_SIZE) ||
-			    (tmp > MAXIMUM_FRAME_SIZE)) {
-				err = EINVAL;
-				break;
-			}
-
-			/* ich8 does not support jumbo frames */
-			if ((mac->type == e1000_ich8lan) &&
-			    (tmp > DEFAULT_FRAME_SIZE)) {
+			if ((new_mtu < DEFAULT_MTU) ||
+			    (new_mtu > Adapter->max_mtu)) {
 				err = EINVAL;
 				break;
 			}
-			/* ich9 does not do jumbo frames on one phy type */
-			if ((mac->type == e1000_ich9lan) &&
-			    (phy->type == e1000_phy_ife) &&
-			    (tmp > DEFAULT_FRAME_SIZE)) {
-				err = EINVAL;
-				break;
-			}
-			if (Adapter->e1000g_state & E1000G_STARTED) {
-				err = EBUSY;
-				break;
-			}
-
+
+			/* inform MAC framework of new MTU */
 			err = mac_maxsdu_update(Adapter->mh, new_mtu);
+
 			if (err == 0) {
-				Adapter->max_frame_size = (uint32_t)tmp;
 				Adapter->default_mtu = new_mtu;
+				Adapter->max_frame_size =
+				    e1000g_mtu2maxframe(new_mtu);
+
+				/*
+				 * check PCH limits & set buffer sizes to
+				 * match new MTU
+				 */
+				e1000g_pch_limits(Adapter);
 				e1000g_set_bufsize(Adapter);
 			}
 			break;
@@ -3299,7 +3262,7 @@
 			range.mpr_count = 1;
 			range.mpr_type = MAC_PROPVAL_UINT32;
 			range.range_uint32[0].mpur_min = DEFAULT_MTU;
-			range.range_uint32[0].mpur_max = MAXIMUM_MTU;
+			range.range_uint32[0].mpur_max = Adapter->max_mtu;
 			/* following MAC type do not support jumbo frames */
 			if ((mac->type == e1000_ich8lan) ||
 			    ((mac->type == e1000_ich9lan) && (phy->type ==
@@ -4016,12 +3979,10 @@
 
 	if (invalid) {
 		e1000g_log(Adapter, CE_WARN,
-		    "Invalid link sets. Setup link to"
+		    "Invalid link settings. Setup link to "
 		    "support autonegotiation with all link capabilities.");
 		mac->autoneg = B_TRUE;
-		phy->autoneg_advertised = ADVERTISE_1000_FULL |
-		    ADVERTISE_100_FULL | ADVERTISE_100_HALF |
-		    ADVERTISE_10_FULL | ADVERTISE_10_HALF;
+		phy->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
 	}
 
 out:
@@ -4259,8 +4220,6 @@
 e1000g_get_max_frame_size(struct e1000g *Adapter)
 {
 	int max_frame;
-	struct e1000_mac_info *mac = &Adapter->shared.mac;
-	struct e1000_phy_info *phy = &Adapter->shared.phy;
 
 	/*
 	 * get value out of config file
@@ -4286,35 +4245,68 @@
 		    E1000G_IPALIGNPRESERVEROOM;
 		break;
 	case 3:
-		if (mac->type >= e1000_82571)
-			Adapter->default_mtu = MAXIMUM_MTU;
-		else
-			Adapter->default_mtu = FRAME_SIZE_UPTO_16K -
-			    sizeof (struct ether_vlan_header) - ETHERFCSL -
-			    E1000G_IPALIGNPRESERVEROOM;
+		Adapter->default_mtu = FRAME_SIZE_UPTO_16K -
+		    sizeof (struct ether_vlan_header) - ETHERFCSL -
+		    E1000G_IPALIGNPRESERVEROOM;
 		break;
 	default:
 		Adapter->default_mtu = ETHERMTU;
 		break;
 	}	/* switch */
 
-	Adapter->max_frame_size = Adapter->default_mtu +
-	    sizeof (struct ether_vlan_header) + ETHERFCSL;
-
-	/* ich8 does not do jumbo frames */
-	if (mac->type == e1000_ich8lan) {
-		Adapter->default_mtu = ETHERMTU;
-		Adapter->max_frame_size = ETHERMTU +
-		    sizeof (struct ether_vlan_header) + ETHERFCSL;
-	}
-
-	/* ich9 does not do jumbo frames on one phy type */
-	if ((mac->type == e1000_ich9lan) &&
-	    (phy->type == e1000_phy_ife)) {
-		Adapter->default_mtu = ETHERMTU;
-		Adapter->max_frame_size = ETHERMTU +
-		    sizeof (struct ether_vlan_header) + ETHERFCSL;
-	}
+	/*
+	 * If the user configed MTU is larger than the deivce's maximum MTU,
+	 * the MTU is set to the deivce's maximum value.
+	 */
+	if (Adapter->default_mtu > Adapter->max_mtu)
+		Adapter->default_mtu = Adapter->max_mtu;
+
+	Adapter->max_frame_size = e1000g_mtu2maxframe(Adapter->default_mtu);
+}
+
+/*
+ * e1000g_pch_limits - Apply limits of the PCH silicon type
+ *
+ * At any frame size larger than the ethernet default,
+ * prevent linking at 10/100 speeds.
+ */
+static void
+e1000g_pch_limits(struct e1000g *Adapter)
+{
+	struct e1000_hw *hw = &Adapter->shared;
+
+	/* only applies to PCH silicon type */
+	if (hw->mac.type != e1000_pchlan)
+		return;
+
+	/* only applies to frames larger than ethernet default */
+	if (Adapter->max_frame_size > DEFAULT_FRAME_SIZE) {
+		hw->mac.autoneg = B_TRUE;
+		hw->phy.autoneg_advertised = ADVERTISE_1000_FULL;
+
+		Adapter->param_adv_autoneg = 1;
+		Adapter->param_adv_1000fdx = 1;
+
+		Adapter->param_adv_100fdx = 0;
+		Adapter->param_adv_100hdx = 0;
+		Adapter->param_adv_10fdx = 0;
+		Adapter->param_adv_10hdx = 0;
+
+		e1000g_param_sync(Adapter);
+	}
+}
+
+/*
+ * e1000g_mtu2maxframe - convert given MTU to maximum frame size
+ */
+static uint32_t
+e1000g_mtu2maxframe(uint32_t mtu)
+{
+	uint32_t maxframe;
+
+	maxframe = mtu + sizeof (struct ether_vlan_header) + ETHERFCSL;
+
+	return (maxframe);
 }
 
 static void
@@ -5290,10 +5282,10 @@
 			ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
 			ctrl_ext |= (E1000_CTRL_EXT_SDP4_DATA |
 			    E1000_CTRL_EXT_SDP6_DATA |
-			    E1000_CTRL_EXT_SDP7_DATA |
+			    E1000_CTRL_EXT_SDP3_DATA |
 			    E1000_CTRL_EXT_SDP4_DIR |
 			    E1000_CTRL_EXT_SDP6_DIR |
-			    E1000_CTRL_EXT_SDP7_DIR);	/* 0x0DD0 */
+			    E1000_CTRL_EXT_SDP3_DIR);	/* 0x0DD0 */
 			E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
 
 			/*
@@ -6204,6 +6196,7 @@
 	case e1000_ich8lan:
 	case e1000_ich9lan:
 	case e1000_ich10lan:
+	case e1000_pchlan:
 		ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
 		E1000_WRITE_REG(hw, E1000_CTRL_EXT,
 		    ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
@@ -6237,6 +6230,7 @@
 	case e1000_ich8lan:
 	case e1000_ich9lan:
 	case e1000_ich10lan:
+	case e1000_pchlan:
 		ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
 		E1000_WRITE_REG(hw, E1000_CTRL_EXT,
 		    ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
--- a/usr/src/uts/common/io/e1000g/e1000g_rx.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000g_rx.c	Tue Sep 29 12:12:23 2009 +0800
@@ -149,6 +149,7 @@
 	uint32_t rctl;
 	uint32_t rxdctl;
 	uint32_t ert;
+	uint16_t phy_data;
 	int i;
 	int size;
 	e1000g_rx_data_t *rx_data;
@@ -320,6 +321,25 @@
 		E1000_WRITE_REG(hw, E1000_ERT, ert);
 	}
 
+	/* Workaround errata on 82577/8 adapters with large frames */
+	if ((hw->mac.type == e1000_pchlan) &&
+	    (Adapter->default_mtu > ETHERMTU)) {
+
+		e1000_read_phy_reg(hw, PHY_REG(770, 26), &phy_data);
+		phy_data &= 0xfff8;
+		phy_data |= (1 << 2);
+		e1000_write_phy_reg(hw, PHY_REG(770, 26), phy_data);
+
+		if (hw->phy.type == e1000_phy_82577) {
+			e1000_read_phy_reg(hw, 22, &phy_data);
+			phy_data &= 0x0fff;
+			phy_data |= (1 << 14);
+			e1000_write_phy_reg(hw, 0x10, 0x2823);
+			e1000_write_phy_reg(hw, 0x11, 0x0003);
+			e1000_write_phy_reg(hw, 22, phy_data);
+		}
+	}
+
 	reg_val =
 	    E1000_RXCSUM_TUOFL |	/* TCP/UDP checksum offload Enable */
 	    E1000_RXCSUM_IPOFL;		/* IP checksum offload Enable */
--- a/usr/src/uts/common/io/e1000g/e1000g_stat.c	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000g_stat.c	Tue Sep 29 12:12:23 2009 +0800
@@ -36,6 +36,7 @@
 #include "e1000g_debug.h"
 
 static int e1000g_update_stats(kstat_t *ksp, int rw);
+static uint32_t e1000g_read_phy_stat(struct e1000_hw *hw, int reg);
 
 /*
  * e1000_tbi_adjust_stats
@@ -217,7 +218,8 @@
 
 	if ((hw->mac.type != e1000_ich8lan) &&
 	    (hw->mac.type != e1000_ich9lan) &&
-	    (hw->mac.type != e1000_ich10lan)) {
+	    (hw->mac.type != e1000_ich10lan) &&
+	    (hw->mac.type != e1000_pchlan)) {
 		e1000g_ksp->Symerrs.value.ul +=
 		    E1000_READ_REG(hw, E1000_SYMERRS);
 #ifdef E1000G_DEBUG
@@ -256,7 +258,7 @@
 	e1000g_ksp->Roc.value.ul += E1000_READ_REG(hw, E1000_ROC);
 	e1000g_ksp->Rjc.value.ul += E1000_READ_REG(hw, E1000_RJC);
 	e1000g_ksp->Tpr.value.ul += E1000_READ_REG(hw, E1000_TPR);
-	e1000g_ksp->Tncrs.value.ul += E1000_READ_REG(hw, E1000_TNCRS);
+	e1000g_ksp->Tncrs.value.ul += e1000g_read_phy_stat(hw, E1000_TNCRS);
 	e1000g_ksp->Tsctc.value.ul += E1000_READ_REG(hw, E1000_TSCTC);
 	e1000g_ksp->Tsctfc.value.ul += E1000_READ_REG(hw, E1000_TSCTFC);
 
@@ -387,13 +389,13 @@
 
 	case MAC_STAT_OERRORS:
 		e1000g_ksp->Ecol.value.ul +=
-		    E1000_READ_REG(hw, E1000_ECOL);
+		    e1000g_read_phy_stat(hw, E1000_ECOL);
 		*val = e1000g_ksp->Ecol.value.ul;
 		break;
 
 	case MAC_STAT_COLLISIONS:
 		e1000g_ksp->Colc.value.ul +=
-		    E1000_READ_REG(hw, E1000_COLC);
+		    e1000g_read_phy_stat(hw, E1000_COLC);
 		*val = e1000g_ksp->Colc.value.ul;
 		break;
 
@@ -467,31 +469,31 @@
 
 	case ETHER_STAT_EX_COLLISIONS:
 		e1000g_ksp->Ecol.value.ul +=
-		    E1000_READ_REG(hw, E1000_ECOL);
+		    e1000g_read_phy_stat(hw, E1000_ECOL);
 		*val = e1000g_ksp->Ecol.value.ul;
 		break;
 
 	case ETHER_STAT_TX_LATE_COLLISIONS:
 		e1000g_ksp->Latecol.value.ul +=
-		    E1000_READ_REG(hw, E1000_LATECOL);
+		    e1000g_read_phy_stat(hw, E1000_LATECOL);
 		*val = e1000g_ksp->Latecol.value.ul;
 		break;
 
 	case ETHER_STAT_DEFER_XMTS:
 		e1000g_ksp->Dc.value.ul +=
-		    E1000_READ_REG(hw, E1000_DC);
+		    e1000g_read_phy_stat(hw, E1000_DC);
 		*val = e1000g_ksp->Dc.value.ul;
 		break;
 
 	case ETHER_STAT_FIRST_COLLISIONS:
 		e1000g_ksp->Scc.value.ul +=
-		    E1000_READ_REG(hw, E1000_SCC);
+		    e1000g_read_phy_stat(hw, E1000_SCC);
 		*val = e1000g_ksp->Scc.value.ul;
 		break;
 
 	case ETHER_STAT_MULTI_COLLISIONS:
 		e1000g_ksp->Mcc.value.ul +=
-		    E1000_READ_REG(hw, E1000_MCC);
+		    e1000g_read_phy_stat(hw, E1000_MCC);
 		*val = e1000g_ksp->Mcc.value.ul;
 		break;
 
@@ -503,7 +505,7 @@
 
 	case ETHER_STAT_MACXMT_ERRORS:
 		e1000g_ksp->Ecol.value.ul +=
-		    E1000_READ_REG(hw, E1000_ECOL);
+		    e1000g_read_phy_stat(hw, E1000_ECOL);
 		*val = e1000g_ksp->Ecol.value.ul;
 		break;
 
@@ -885,3 +887,79 @@
 
 	return (DDI_SUCCESS);
 }
+
+/*
+ * e1000g_read_phy_stat - read certain PHY statistics
+ *
+ * Certain statistics are read from MAC registers on some silicon types
+ * but are read from the PHY on other silicon types.  This routine
+ * handles that difference as needed.
+ */
+static uint32_t
+e1000g_read_phy_stat(struct e1000_hw *hw, int reg)
+{
+	uint16_t phy_low, phy_high;
+	uint32_t val;
+
+	/* get statistic from PHY in these cases */
+	if ((hw->phy.type == e1000_phy_82578) ||
+	    (hw->phy.type == e1000_phy_82577)) {
+
+		switch (reg) {
+		case E1000_SCC:
+			(void) e1000_read_phy_reg(hw, HV_SCC_UPPER, &phy_high);
+			(void) e1000_read_phy_reg(hw, HV_SCC_LOWER, &phy_low);
+			val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low;
+			break;
+
+		case E1000_MCC:
+			(void) e1000_read_phy_reg(hw, HV_MCC_UPPER, &phy_high);
+			(void) e1000_read_phy_reg(hw, HV_MCC_LOWER, &phy_low);
+			val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low;
+			break;
+
+		case E1000_ECOL:
+			(void) e1000_read_phy_reg(hw, HV_ECOL_UPPER, &phy_high);
+			(void) e1000_read_phy_reg(hw, HV_ECOL_LOWER, &phy_low);
+			val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low;
+			break;
+
+		case E1000_COLC:
+			(void) e1000_read_phy_reg(hw, HV_COLC_UPPER, &phy_high);
+			(void) e1000_read_phy_reg(hw, HV_COLC_LOWER, &phy_low);
+			val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low;
+			break;
+
+		case E1000_LATECOL:
+			(void) e1000_read_phy_reg(hw, HV_LATECOL_UPPER,
+			    &phy_high);
+			(void) e1000_read_phy_reg(hw, HV_LATECOL_LOWER,
+			    &phy_low);
+			val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low;
+			break;
+
+		case E1000_DC:
+			(void) e1000_read_phy_reg(hw, HV_DC_UPPER, &phy_high);
+			(void) e1000_read_phy_reg(hw, HV_DC_LOWER, &phy_low);
+			val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low;
+			break;
+
+		case E1000_TNCRS:
+			(void) e1000_read_phy_reg(hw, HV_TNCRS_UPPER,
+			    &phy_high);
+			(void) e1000_read_phy_reg(hw, HV_TNCRS_LOWER,
+			    &phy_low);
+			val = ((uint32_t)phy_high << 16) | (uint32_t)phy_low;
+			break;
+
+		default:
+			break;
+		}
+
+	/* get statistic from MAC otherwise */
+	} else {
+		val = E1000_READ_REG(hw, reg);
+	}
+
+	return (val);
+}
--- a/usr/src/uts/common/io/e1000g/e1000g_sw.h	Tue Sep 29 11:19:43 2009 +0800
+++ b/usr/src/uts/common/io/e1000g/e1000g_sw.h	Tue Sep 29 12:12:23 2009 +0800
@@ -102,7 +102,6 @@
 /*
  * constants used in setting flow control thresholds
  */
-#define	E1000_PBA_10K		0x000A
 #define	E1000_PBA_MASK		0xffff
 #define	E1000_PBA_SHIFT		10
 #define	E1000_FC_HIGH_DIFF	0x1638 /* High: 5688 bytes below Rx FIFO size */
@@ -266,8 +265,9 @@
 #define	FRAME_SIZE_UPTO_16K	16384
 #define	FRAME_SIZE_UPTO_9K	9234
 
-#define	MAXIMUM_MTU		9216
 #define	DEFAULT_MTU		ETHERMTU
+#define	MAXIMUM_MTU_4K		4096
+#define	MAXIMUM_MTU_9K		9216
 
 #define	DEFAULT_FRAME_SIZE	\
 	(DEFAULT_MTU + sizeof (struct ether_vlan_header) + ETHERFCSL)
@@ -878,6 +878,7 @@
 	uint32_t intr_throttling_rate;
 
 	uint32_t default_mtu;
+	uint32_t max_mtu;
 	uint32_t max_frame_size;
 	uint32_t min_frame_size;
 
@@ -1018,7 +1019,6 @@
 void e1000g_free_rx_sw_packet(p_rx_sw_packet_t packet, boolean_t full_release);
 void e1000g_tx_setup(struct e1000g *Adapter);
 void e1000g_rx_setup(struct e1000g *Adapter);
-void e1000g_setup_multicast(struct e1000g *Adapter);
 
 int e1000g_recycle(e1000g_tx_ring_t *tx_ring);
 void e1000g_free_tx_swpkt(p_tx_sw_packet_t packet);
@@ -1039,6 +1039,7 @@
 void e1000g_clear_tx_interrupt(struct e1000g *Adapter);
 void e1000g_mask_tx_interrupt(struct e1000g *Adapter);
 void phy_spd_state(struct e1000_hw *hw, boolean_t enable);
+void e1000_destroy_hw_mutex(struct e1000_hw *hw);
 void e1000_enable_pciex_master(struct e1000_hw *hw);
 int e1000g_check_acc_handle(ddi_acc_handle_t handle);
 int e1000g_check_dma_handle(ddi_dma_handle_t handle);