changeset 11020:e0feef27b61a

6893285 e1000g 'pciex8086,105e' with PHY type igp I/O devices have been retired 6895459 e1000g share code update v3-1-10-1
author Miles Xu, Sun Microsystems <Min.Xu@Sun.COM>
date Tue, 10 Nov 2009 11:52:20 +0800
parents 133bd84ab259
children c5323cd5fa92
files 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_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_main.c
diffstat 27 files changed, 891 insertions(+), 328 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/e1000g/README	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/README	Tue Nov 10 11:52:20 2009 +0800
@@ -714,3 +714,8 @@
    6881588 e1000g functions should return when e1000g_check_dma_handle() fails
    6888320 e1000g emits scary mutex message on the console
 
+5.3.17
+======
+  This version has the following fixes:
+   6893285 e1000g 'pciex8086,105e' with PHY type igp I/O devices have been retired
+   6895459 e1000g share code update v3-1-10-1
--- a/usr/src/uts/common/io/e1000g/e1000_80003es2lan.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_80003es2lan.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.86 v3-1-3_2009-8-20
+ * IntelVersion: 1.86 v3-1-10-1_2009-9-18_Release14-6
  */
 /*
  * 80003ES2LAN Gigabit Ethernet Controller (Copper)
--- a/usr/src/uts/common/io/e1000g/e1000_80003es2lan.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_80003es2lan.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.10 v3-1-3_2009-8-20
+ * IntelVersion: 1.10 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_80003ES2LAN_H_
 #define	_E1000_80003ES2LAN_H_
--- a/usr/src/uts/common/io/e1000g/e1000_82540.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82540.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.57 v3-1-3_2009-8-20
+ * IntelVersion: 1.57 v3-1-10-1_2009-9-18_Release14-6
  */
 
 /*
--- a/usr/src/uts/common/io/e1000g/e1000_82541.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82541.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.68 v3-1-3_2009-8-20
+ * IntelVersion: 1.68 v3-1-10-1_2009-9-18_Release14-6
  */
 
 /*
--- a/usr/src/uts/common/io/e1000g/e1000_82541.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82541.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.9 v3-1-3_2009-8-20
+ * IntelVersion: 1.9 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_82541_H_
 #define	_E1000_82541_H_
--- a/usr/src/uts/common/io/e1000g/e1000_82542.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82542.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.53 v3-1-3_2009-8-20
+ * IntelVersion: 1.53 v3-1-10-1_2009-9-18_Release14-6
  */
 
 /*
--- a/usr/src/uts/common/io/e1000g/e1000_82543.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82543.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.68 v3-1-3_2009-8-20
+ * IntelVersion: 1.68 v3-1-10-1_2009-9-18_Release14-6
  */
 
 /*
--- a/usr/src/uts/common/io/e1000g/e1000_82543.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82543.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.8 v3-1-3_2009-8-20
+ * IntelVersion: 1.8 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_82543_H_
 #define	_E1000_82543_H_
--- a/usr/src/uts/common/io/e1000g/e1000_82571.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82571.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.113 v3-1-3_2009-8-20
+ * IntelVersion: 1.113 v3-1-10-1_2009-9-18_Release14-6
  */
 
 /*
@@ -845,7 +845,6 @@
 	}
 	if (!timeout) {
 		DEBUGOUT("MNG configuration cycle has not completed.\n");
-		ret_val = -E1000_ERR_RESET;
 		goto out;
 	}
 
--- a/usr/src/uts/common/io/e1000g/e1000_82571.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_82571.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.16 v3-1-3_2009-8-20
+ * IntelVersion: 1.16 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_82571_H_
 #define	_E1000_82571_H_
--- a/usr/src/uts/common/io/e1000g/e1000_api.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_api.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.124 v3-1-3_2009-8-20
+ * IntelVersion: 1.125 v3-1-10-1_2009-9-18_Release14-6
  */
 
 #include "e1000_api.h"
--- a/usr/src/uts/common/io/e1000g/e1000_api.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_api.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.53 v3-1-3_2009-8-20
+ * IntelVersion: 1.53 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_API_H_
 #define	_E1000_API_H_
--- a/usr/src/uts/common/io/e1000g/e1000_defines.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_defines.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.116 v3-1-3_2009-8-20
+ * IntelVersion: 1.118 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_DEFINES_H_
 #define	_E1000_DEFINES_H_
@@ -691,6 +691,7 @@
 /* Extended Configuration Control and Size */
 #define	E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP	0x00000020
 #define	E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE	0x00000001
+#define	E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE	0x00000008
 #define	E1000_EXTCNF_CTRL_SWFLAG		0x00000020
 #define	E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK	0x00FF0000
 #define	E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT	16
--- a/usr/src/uts/common/io/e1000g/e1000_hw.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_hw.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.432 v3-1-3_2009-8-20
+ * IntelVersion: 1.439 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_HW_H_
 #define	_E1000_HW_H_
@@ -603,11 +603,13 @@
 	s32 (*get_cable_length)(struct e1000_hw *);
 	s32 (*get_info)(struct e1000_hw *);
 	s32 (*read_reg)(struct e1000_hw *, u32, u16 *);
+	s32 (*read_reg_locked)(struct e1000_hw *, u32, u16 *);
 	void (*release)(struct e1000_hw *);
 	s32 (*reset)(struct e1000_hw *);
 	s32 (*set_d0_lplu_state)(struct e1000_hw *, bool);
 	s32 (*set_d3_lplu_state)(struct e1000_hw *, bool);
 	s32 (*write_reg)(struct e1000_hw *, u32, u16);
+	s32 (*write_reg_locked)(struct e1000_hw *, u32, u16);
 	void (*power_up)(struct e1000_hw *);
 	void (*power_down)(struct e1000_hw *);
 };
@@ -774,6 +776,8 @@
 	struct e1000_shadow_ram shadow_ram[E1000_SHADOW_RAM_WORDS];
 	E1000_MUTEX nvm_mutex;
 	E1000_MUTEX swflag_mutex;
+	bool nvm_k1_enabled;
+	bool nvm_lcd_config_enabled;
 };
 
 struct e1000_hw {
--- a/usr/src/uts/common/io/e1000g/e1000_ich8lan.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_ich8lan.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.180 v3-1-3_2009-8-20
+ * IntelVersion: 1.186.2.1 v3-1-10-1_2009-9-18_Release14-6
  */
 
 /*
@@ -69,6 +69,7 @@
 static s32 e1000_check_reset_block_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_lplu_state_pchlan(struct e1000_hw *hw, bool active);
 static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
     bool active);
 static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
@@ -92,10 +93,11 @@
 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 s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
+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);
@@ -118,6 +120,8 @@
 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);
+static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
+static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw);
 
 /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
 /* Offset 04h HSFSTS */
@@ -185,11 +189,13 @@
 	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.read_reg_locked = e1000_read_phy_reg_hv_locked;
 	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.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
+	phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
 	phy->ops.write_reg = e1000_write_phy_reg_hv;
+	phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked;
 	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;
@@ -273,6 +279,8 @@
 	case IGP03E1000_E_PHY_ID:
 		phy->type = e1000_phy_igp_3;
 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+		phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked;
+		phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked;
 		break;
 	case IFE_E_PHY_ID:
 	case IFE_PLUS_E_PHY_ID:
@@ -491,14 +499,6 @@
 		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
@@ -508,6 +508,12 @@
 	if (ret_val)
 		goto out;
 
+	if (hw->mac.type == e1000_pchlan) {
+		ret_val = e1000_k1_gig_workaround_hv(hw, link);
+		if (ret_val)
+			goto out;
+	}
+
 	if (!link)
 		goto out; /* No link detected */
 
@@ -616,9 +622,8 @@
  * e1000_acquire_swflag_ich8lan - Acquire software control flag
  * @hw: pointer to the HW structure
  *
- * Acquires the software control flag for performing NVM and PHY
- * operations.  This is a function pointer entry point only called by
- * read/write routines for the PHY and NVM parts.
+ * Acquires the software control flag for performing PHY and select
+ * MAC CSR accesses.
  */
 static s32
 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
@@ -652,9 +657,9 @@
 	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;
+		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+			break;
 
 		msec_delay_irq(1);
 		timeout--;
@@ -679,9 +684,8 @@
  * e1000_release_swflag_ich8lan - Release software control flag
  * @hw: pointer to the HW structure
  *
- * Releases the software control flag for performing NVM and PHY operations.
- * This is a function pointer entry point only called by read/write
- * routines for the PHY and NVM parts.
+ * Releases the software control flag for performing PHY and select
+ * MAC CSR accesses.
  */
 static void
 e1000_release_swflag_ich8lan(struct e1000_hw *hw)
@@ -740,6 +744,343 @@
 }
 
 /*
+ * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
+ * @hw: pointer to the HW structure
+ *
+ * SW should configure the LCD from the NVM extended configuration region
+ * as a workaround for certain parts.
+ */
+static s32
+e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
+	s32 ret_val;
+	u16 word_addr, reg_data, reg_addr, phy_page = 0;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return (ret_val);
+
+	/*
+	 * Initialize the PHY from the NVM on ICH platforms.  This
+	 * is needed due to an issue where the NVM configuration is
+	 * not properly autoloaded after power transitions.
+	 * Therefore, after each PHY reset, we will load the
+	 * configuration data out of the NVM manually.
+	 */
+	if ((hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) ||
+	    (hw->mac.type == e1000_pchlan)) {
+		/* Check if SW needs to configure the PHY */
+		if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
+		    (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) ||
+		    (hw->mac.type == e1000_pchlan))
+			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
+		else
+			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+
+		data = E1000_READ_REG(hw, E1000_FEXTNVM);
+		if (!(data & sw_cfg_mask))
+			goto out;
+
+		/* Wait for basic configuration completes before proceeding */
+		e1000_lan_init_done_ich8lan(hw);
+
+		/*
+		 * Make sure HW does not configure LCD from PHY
+		 * extended configuration before SW configuration
+		 */
+		data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+			goto out;
+
+		cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
+		cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
+		cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
+		if (!cnf_size)
+			goto out;
+
+		cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
+		cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
+
+		if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
+		    hw->mac.type == e1000_pchlan) {
+			/*
+			 * HW configures the SMBus address and LEDs when the
+			 * OEM and LCD Write Enable bits are set in the NVM.
+			 * When both NVM bits are cleared, SW will configure
+			 * them instead.
+			 */
+			data = E1000_READ_REG(hw, E1000_STRAP);
+			data &= E1000_STRAP_SMBUS_ADDRESS_MASK;
+			reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT;
+			reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
+			ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR,
+			    reg_data);
+			if (ret_val)
+				goto out;
+
+			data = E1000_READ_REG(hw, E1000_LEDCTL);
+			ret_val = e1000_write_phy_reg_hv_locked(hw,
+			    HV_LED_CONFIG, (u16)data);
+			if (ret_val)
+				goto out;
+
+			dev_spec->nvm_lcd_config_enabled = true;
+		}
+		/* Configure LCD from extended configuration region. */
+
+		/* cnf_base_addr is in DWORD */
+		word_addr = (u16)(cnf_base_addr << 1);
+
+		for (i = 0; i < cnf_size; i++) {
+			ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1,
+			    &reg_data);
+			if (ret_val)
+				goto out;
+
+			ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1),
+			    1, &reg_addr);
+			if (ret_val)
+				goto out;
+
+			/* Save off the PHY page for future writes. */
+			if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
+				phy_page = reg_data;
+				continue;
+			}
+			/*
+			 * Bit 5 in the LCD config word contains the phy
+			 * address for PCH
+			 */
+			if (hw->mac.type == e1000_pchlan) {
+				phy->addr = 1;
+				if (reg_addr & LCD_CFG_PHY_ADDR_BIT) {
+					phy->addr = 2;
+					reg_addr &= PHY_REG_MASK;
+				}
+			}
+
+			reg_addr |= phy_page;
+
+			ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
+			    reg_data);
+			if (ret_val)
+				goto out;
+		}
+
+		if (hw->mac.type == e1000_pchlan)
+			dev_spec->nvm_lcd_config_enabled = false;
+	}
+
+out:
+	hw->phy.ops.release(hw);
+	return (ret_val);
+}
+
+/*
+ * e1000_k1_gig_workaround_hv - K1 Si workaround
+ * @hw: pointer to the HW structure
+ * @link: link up bool flag
+ *
+ * If K1 is enabled for 1Gbps, the MAC might stall when transitioning
+ * from a lower speed.  This workaround disables K1 whenever link is at 1Gig
+ * If link is down, the function will restore the default K1 setting located
+ * in the NVM.
+ */
+static s32
+e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 status_reg = 0;
+	bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
+
+	DEBUGFUNC("e1000_k1_gig_workaround_hv");
+
+	if (hw->mac.type != e1000_pchlan)
+		goto out;
+
+	/* Wrap the whole flow with the sw flag */
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	/* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
+	if (link) {
+		if (hw->phy.type == e1000_phy_82578) {
+			ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
+			    &status_reg);
+			if (ret_val)
+				goto release;
+
+			status_reg &= BM_CS_STATUS_LINK_UP |
+			    BM_CS_STATUS_RESOLVED |
+			    BM_CS_STATUS_SPEED_MASK;
+
+			if (status_reg == (BM_CS_STATUS_LINK_UP |
+			    BM_CS_STATUS_RESOLVED |
+			    BM_CS_STATUS_SPEED_1000))
+				k1_enable = false;
+		}
+
+		if (hw->phy.type == e1000_phy_82577) {
+			ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
+			    &status_reg);
+			if (ret_val)
+				goto release;
+
+			status_reg &= HV_M_STATUS_LINK_UP |
+			    HV_M_STATUS_AUTONEG_COMPLETE |
+			    HV_M_STATUS_SPEED_MASK;
+
+			if (status_reg == (HV_M_STATUS_LINK_UP |
+			    HV_M_STATUS_AUTONEG_COMPLETE |
+			    HV_M_STATUS_SPEED_1000))
+				k1_enable = false;
+		}
+
+		/* Link stall fix for link up */
+		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
+		    0x0100);
+		if (ret_val)
+			goto release;
+
+	} else {
+		/* Link stall fix for link down */
+		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
+		    0x4100);
+		if (ret_val)
+			goto release;
+	}
+
+	ret_val = e1000_configure_k1_ich8lan(hw, k1_enable);
+
+release:
+	hw->phy.ops.release(hw);
+out:
+	return (ret_val);
+}
+
+/*
+ * e1000_configure_k1_ich8lan - Configure K1 power state
+ * @hw: pointer to the HW structure
+ * @enable: K1 state to configure
+ *
+ * Configure the K1 power state based on the provided parameter.
+ * Assumes semaphore already acquired.
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ */
+s32
+e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u32 ctrl_reg = 0;
+	u32 ctrl_ext = 0;
+	u32 reg = 0;
+	u16 kmrn_reg = 0;
+
+	ret_val = e1000_read_kmrn_reg_locked(hw,
+	    E1000_KMRNCTRLSTA_K1_CONFIG,
+	    &kmrn_reg);
+	if (ret_val)
+		goto out;
+
+	if (k1_enable)
+		kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
+	else
+		kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
+
+	ret_val = e1000_write_kmrn_reg_locked(hw,
+	    E1000_KMRNCTRLSTA_K1_CONFIG,
+	    kmrn_reg);
+	if (ret_val)
+		goto out;
+
+	usec_delay(20);
+	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
+
+	reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+	reg |= E1000_CTRL_FRCSPD;
+	E1000_WRITE_REG(hw, E1000_CTRL, reg);
+
+	E1000_WRITE_REG(hw,
+	    E1000_CTRL_EXT,
+	    ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
+	usec_delay(20);
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+	usec_delay(20);
+
+out:
+	return (ret_val);
+}
+
+/*
+ * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration
+ * @hw: pointer to the HW structure
+ * @d0_state: boolean if entering d0 or d3 device state
+ *
+ * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
+ * collectively called OEM bits.  The OEM Write Enable bit and SW Config bit
+ * in NVM determines whether HW should configure LPLU and Gbe Disable.
+ */
+s32
+e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
+{
+	s32 ret_val = 0;
+	u32 mac_reg;
+	u16 oem_reg;
+
+	if (hw->mac.type != e1000_pchlan)
+		return (ret_val);
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return (ret_val);
+
+	mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+	if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
+		goto out;
+
+	mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM);
+	if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
+		goto out;
+
+	mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
+
+	ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
+	if (ret_val)
+		goto out;
+
+	oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
+
+	if (d0_state) {
+		if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
+			oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+		if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
+			oem_reg |= HV_OEM_BITS_LPLU;
+	} else {
+		if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE)
+			oem_reg |= HV_OEM_BITS_GBE_DIS;
+
+		if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU)
+			oem_reg |= HV_OEM_BITS_LPLU;
+	}
+	/* Restart auto-neg to activate the bits */
+	oem_reg |= HV_OEM_BITS_RESTART_AN;
+	ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
+
+out:
+	hw->phy.ops.release(hw);
+
+	return (ret_val);
+}
+
+/*
  * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
  * done after every PHY reset.
  */
@@ -749,7 +1090,7 @@
 	s32 ret_val = E1000_SUCCESS;
 
 	if (hw->mac.type != e1000_pchlan)
-		return (ret_val);
+		goto out;
 
 	if (((hw->phy.type == e1000_phy_82577) &&
 	    ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
@@ -757,12 +1098,12 @@
 		/* Disable generation of early preamble */
 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
 		if (ret_val)
-			return (ret_val);
+			goto out;
 
 		/* Preamble tuning for SSC */
 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204);
 		if (ret_val)
-			return (ret_val);
+			goto out;
 	}
 
 	if (hw->phy.type == e1000_phy_82578) {
@@ -780,12 +1121,21 @@
 	/* Select page 0 */
 	ret_val = hw->phy.ops.acquire(hw);
 	if (ret_val)
-		return (ret_val);
+		goto out;
 
 	hw->phy.addr = 1;
-	e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
+	ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
+	if (ret_val)
+		goto out;
 	hw->phy.ops.release(hw);
 
+	/*
+	 * Configure the K1 Si workaround during phy reset assuming there is
+	 * link so that it disables K1 if link is in 1Gbps.
+	 */
+	ret_val = e1000_k1_gig_workaround_hv(hw, true);
+
+out:
 	return (ret_val);
 }
 
@@ -862,10 +1212,8 @@
 static s32
 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
 {
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
-	s32 ret_val;
-	u16 word_addr, reg_data, reg_addr, phy_page = 0;
+	s32 ret_val = E1000_SUCCESS;
+	u16 reg;
 
 	DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
 
@@ -888,86 +1236,22 @@
 			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
-	 * autoloaded after power transitions. Therefore, after each PHY
-	 * reset, we will load the configuration data out of the NVM manually.
-	 */
-	if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) {
-		/* Check if SW needs configure the PHY */
-		if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
-		    (hw->device_id == E1000_DEV_ID_ICH8_IGP_M))
-			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
-		else
-			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
-
-		data = E1000_READ_REG(hw, E1000_FEXTNVM);
-		if (!(data & sw_cfg_mask))
-			goto out;
-
-		/* Wait for basic configuration completes before proceeding */
-		e1000_lan_init_done_ich8lan(hw);
-
-		/*
-		 * Make sure HW does not configure LCD from PHY extended
-		 * configuration before SW configuration
-		 */
-		data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
-		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
-			goto out;
-
-		cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
-		cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
-		cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
-		if (!cnf_size)
-			goto out;
-
-		cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
-		cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
-
-		/*
-		 * Configure LCD from extended configuration region.
-		 */
-
-		/* cnf_base_addr is in DWORD */
-		word_addr = (u16)(cnf_base_addr << 1);
-
-		for (i = 0; i < cnf_size; i++) {
-			ret_val = hw->nvm.ops.read(hw,
-			    (word_addr + i * 2),
-			    1,
-			    &reg_data);
-			if (ret_val)
-				goto out;
-
-			ret_val = hw->nvm.ops.read(hw,
-			    (word_addr + i * 2 + 1),
-			    1,
-			    &reg_addr);
-			if (ret_val)
-				goto out;
-
-			/* Save off the PHY page for future writes. */
-			if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
-				phy_page = reg_data;
-				continue;
-			}
-
-			reg_addr |= phy_page;
-
-			ret_val = phy->ops.write_reg(hw,
-			    (u32)reg_addr,
-			    reg_data);
-			if (ret_val)
-				goto out;
-		}
-	}
+	/* Dummy read to clear the phy wakeup bit after lcd reset */
+	if (hw->mac.type == e1000_pchlan)
+		hw->phy.ops.read_reg(hw, BM_WUC, &reg);
+
+	/* Configure the LCD with the extended configuration region in NVM */
+	ret_val = e1000_sw_lcd_config_ich8lan(hw);
+	if (ret_val)
+		goto out;
+
+	/* Configure the LCD with the OEM bits in NVM */
+	if (hw->mac.type == e1000_pchlan)
+		ret_val = e1000_oem_bits_config_ich8lan(hw, true);
 
 out:
 	return (ret_val);
 }
-
 /*
  * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
  * @hw: pointer to the HW structure
@@ -1059,6 +1343,41 @@
 }
 
 /*
+ * e1000_set_lplu_state_pchlan - Set Low Power Link Up state
+ * @hw: pointer to the HW structure
+ * @active: true to enable LPLU, false to disable
+ *
+ * Sets the LPLU state according to the active flag.  For PCH, if OEM write
+ * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
+ * the phy speed. This function will manually set the LPLU bit and restart
+ * auto-neg as hw would do. D3 and D0 LPLU will call the same function
+ * since it configures the same bit.
+ */
+static s32
+e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 oem_reg;
+
+	DEBUGFUNC("e1000_set_lplu_state_pchlan");
+
+	ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg);
+	if (ret_val)
+		goto out;
+
+	if (active)
+		oem_reg |= HV_OEM_BITS_LPLU;
+	else
+		oem_reg &= ~HV_OEM_BITS_LPLU;
+
+	oem_reg |= HV_OEM_BITS_RESTART_AN;
+	ret_val = hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg);
+
+out:
+	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
@@ -2288,6 +2607,8 @@
 static s32
 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
 {
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	u16 reg;
 	u32 ctrl, kab;
 	s32 ret_val;
 
@@ -2323,6 +2644,18 @@
 		E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
 	}
 
+	if (hw->mac.type == e1000_pchlan) {
+		/* Save the NVM K1 bit setting */
+		ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &reg);
+		if (ret_val)
+			return (ret_val);
+
+		if (reg & E1000_NVM_K1_ENABLE)
+			dev_spec->nvm_k1_enabled = true;
+		else
+			dev_spec->nvm_k1_enabled = false;
+	}
+
 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
 
 	if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) {
@@ -2367,6 +2700,20 @@
 		}
 	}
 
+	/* Dummy read to clear the phy wakeup bit after lcd reset */
+	if (hw->mac.type == e1000_pchlan)
+		hw->phy.ops.read_reg(hw, BM_WUC, &reg);
+
+	ret_val = e1000_sw_lcd_config_ich8lan(hw);
+	if (ret_val)
+		goto out;
+
+	if (hw->mac.type == e1000_pchlan) {
+		ret_val = e1000_oem_bits_config_ich8lan(hw, true);
+		if (ret_val)
+			goto out;
+	}
+
 	/*
 	 * For PCH, this write will make sure that any noise
 	 * will be detected as a CRC error and be dropped rather than show up
@@ -2712,14 +3059,6 @@
 	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)) {
@@ -2951,9 +3290,8 @@
 		    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);
+		e1000_phy_hw_reset_ich8lan(hw);
 	default:
 		break;
 	}
--- a/usr/src/uts/common/io/e1000g/e1000_ich8lan.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_ich8lan.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.37 v3-1-3_2009-8-20
+ * IntelVersion: 1.41 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_ICH8LAN_H_
 #define	_E1000_ICH8LAN_H_
@@ -140,6 +140,28 @@
 
 /* PCH Flow Control Refresh Timer Value */
 #define	E1000_FCRTV_PCH		0x05F40
+
+#define	E1000_NVM_K1_CONFIG	0x1B	/* NVM K1 Config Word */
+#define	E1000_NVM_K1_ENABLE	0x1	/* NVM Enable K1 bit */
+
+/* SMBus Address Phy Register */
+#define	HV_SMB_ADDR	PHY_REG(768, 26)
+#define	HV_SMB_ADDR_PEC_EN	0x0200
+#define	HV_SMB_ADDR_VALID	0x0080
+
+/* Strapping Option Register - RO */
+#define	E1000_STRAP	0x0000C
+#define	E1000_STRAP_SMBUS_ADDRESS_MASK	0x00FE0000
+#define	E1000_STRAP_SMBUS_ADDRESS_SHIFT	17
+
+/* OEM Bits Phy Register */
+#define	HV_OEM_BITS	PHY_REG(768, 25)
+#define	HV_OEM_BITS_LPLU	0x0004	/* Low Power Link Up */
+#define	HV_OEM_BITS_GBE_DIS	0x0040	/* Gigabit Disable */
+#define	HV_OEM_BITS_RESTART_AN	0x0400	/* Restart Auto-negotiation */
+/* Phy address bit from LCD Config word */
+#define	LCD_CFG_PHY_ADDR_BIT	0x0020
+
 /* SW Semaphore flag timeout in milliseconds */
 #define	SW_FLAG_TIMEOUT		400
 
@@ -172,6 +194,8 @@
 void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
 void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
 void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw);
+s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
+s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_config);
 
 #ifdef __cplusplus
 }
--- a/usr/src/uts/common/io/e1000g/e1000_mac.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_mac.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.108 v3-1-3_2009-8-20
+ * IntelVersion: 1.108 v3-1-10-1_2009-9-18_Release14-6
  */
 #include "e1000_api.h"
 
@@ -2184,7 +2184,7 @@
  * Verify that when not using auto-negotiation that MDI/MDIx is correctly
  * set, which is forced to MDI mode only.
  */
-s32
+static s32
 e1000_validate_mdi_setting_generic(struct e1000_hw *hw)
 {
 	s32 ret_val = E1000_SUCCESS;
--- a/usr/src/uts/common/io/e1000g/e1000_mac.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_mac.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.32 v3-1-3_2009-8-20
+ * IntelVersion: 1.32 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_MAC_H_
 #define	_E1000_MAC_H_
--- a/usr/src/uts/common/io/e1000g/e1000_manage.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_manage.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.27 v3-1-3_2009-8-20
+ * IntelVersion: 1.27 v3-1-10-1_2009-9-18_Release14-6
  */
 
 #include "e1000_api.h"
--- a/usr/src/uts/common/io/e1000g/e1000_manage.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_manage.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.18 v3-1-3_2009-8-20
+ * IntelVersion: 1.18 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_MANAGE_H_
 #define	_E1000_MANAGE_H_
--- a/usr/src/uts/common/io/e1000g/e1000_nvm.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_nvm.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.49 v3-1-3_2009-8-20
+ * IntelVersion: 1.49 v3-1-10-1_2009-9-18_Release14-6
  */
 #include "e1000_api.h"
 
--- a/usr/src/uts/common/io/e1000g/e1000_nvm.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_nvm.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.18 v3-1-3_2009-8-20
+ * IntelVersion: 1.18 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_NVM_H_
 #define	_E1000_NVM_H_
--- a/usr/src/uts/common/io/e1000g/e1000_phy.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_phy.c	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.143 v3-1-3_2009-8-20
+ * IntelVersion: 1.151 v3-1-10-1_2009-9-18_Release14-6
  */
 #include "e1000_api.h"
 
@@ -81,11 +81,13 @@
 	phy->ops.get_cable_length = e1000_null_ops_generic;
 	phy->ops.get_info = e1000_null_ops_generic;
 	phy->ops.read_reg = e1000_null_read_reg;
+	phy->ops.read_reg_locked = e1000_null_read_reg;
 	phy->ops.release = e1000_null_phy_generic;
 	phy->ops.reset = e1000_null_ops_generic;
 	phy->ops.set_d0_lplu_state = e1000_null_lplu_state;
 	phy->ops.set_d3_lplu_state = e1000_null_lplu_state;
 	phy->ops.write_reg = e1000_null_write_reg;
+	phy->ops.write_reg_locked = e1000_null_write_reg;
 	phy->ops.power_up = e1000_null_phy_generic;
 	phy->ops.power_down = e1000_null_phy_generic;
 	phy->ops.cfg_on_link_up = e1000_null_ops_generic;
@@ -197,21 +199,30 @@
 			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
+		 * 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 = phy->ops.acquire(hw);
+		if (ret_val)
+			goto out;
 		ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
 		if (ret_val)
 			goto out;
+		phy->ops.release(hw);
 
 		retry_count++;
 	}
 out:
 	/* Revert to MDIO fast mode, if applicable */
-	if (retry_count)
+	if (retry_count) {
+		ret_val = phy->ops.acquire(hw);
+		if (ret_val)
+			return (ret_val);
 		ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
+		phy->ops.release(hw);
+	}
 
 	return (ret_val);
 }
@@ -425,39 +436,117 @@
  * @hw: pointer to the HW structure
  * @offset: register offset to be read
  * @data: pointer to the read data
+ * @locked: semaphore has already been acquired or not
  *
  * Acquires semaphore, if necessary, then reads the PHY register at offset
- * and storing the retrieved information in data.  Release any acquired
+ * and stores the retrieved information in data.  Release any acquired
  * semaphores before exiting.
  */
+static s32
+__e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data,
+    bool locked)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("__e1000_read_phy_reg_igp");
+
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = e1000_write_phy_reg_mdic(hw,
+		    IGP01E1000_PHY_PAGE_SELECT, (u16)offset);
+		if (ret_val)
+			goto release;
+	}
+
+	ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	    data);
+
+release:
+	if (!locked)
+		hw->phy.ops.release(hw);
+out:
+	return (ret_val);
+}
+
+/*
+ * e1000_read_phy_reg_igp - Read igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore then reads the PHY register at offset and stores the
+ * retrieved information in data.
+ * Release the acquired semaphore before exiting.
+ */
 s32
 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
 {
+	return (__e1000_read_phy_reg_igp(hw, offset, data, false));
+}
+
+/*
+ * e1000_read_phy_reg_igp_locked - Read igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset and stores the retrieved information
+ * in data.  Assumes semaphore already acquired.
+ */
+s32
+e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return (__e1000_read_phy_reg_igp(hw, offset, data, true));
+}
+
+/*
+ * e1000_write_phy_reg_igp - Write igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset.  Release any acquired semaphores before exiting.
+ */
+static s32
+__e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data,
+    bool locked)
+{
 	s32 ret_val = E1000_SUCCESS;
 
-	DEBUGFUNC("e1000_read_phy_reg_igp");
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
+	DEBUGFUNC("e1000_write_phy_reg_igp");
+
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
 
 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
 		ret_val = e1000_write_phy_reg_mdic(hw,
-		    IGP01E1000_PHY_PAGE_SELECT,
-		    (u16)offset);
-		if (ret_val) {
-			hw->phy.ops.release(hw);
-			goto out;
-		}
+		    IGP01E1000_PHY_PAGE_SELECT, (u16)offset);
+		if (ret_val)
+			goto release;
 	}
-	ret_val = e1000_read_phy_reg_mdic(hw,
-	    MAX_PHY_REG_ADDRESS & offset,
+
+	ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
 	    data);
 
-	hw->phy.ops.release(hw);
+release:
+	if (!locked)
+		hw->phy.ops.release(hw);
 
 out:
 	return (ret_val);
@@ -469,67 +558,57 @@
  * @offset: register offset to write to
  * @data: data to write at register offset
  *
- * Acquires semaphore, if necessary, then writes the data to PHY register
+ * Acquires semaphore then writes the data to PHY register
  * at the offset.  Release any acquired semaphores before exiting.
  */
 s32
 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
 {
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_write_phy_reg_igp");
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		ret_val = e1000_write_phy_reg_mdic(hw,
-		    IGP01E1000_PHY_PAGE_SELECT,
-		    (u16)offset);
-		if (ret_val) {
-			hw->phy.ops.release(hw);
-			goto out;
-		}
-	}
-
-	ret_val = e1000_write_phy_reg_mdic(hw,
-	    MAX_PHY_REG_ADDRESS & offset,
-	    data);
-
-	hw->phy.ops.release(hw);
-
-out:
-	return (ret_val);
+	return (__e1000_write_phy_reg_igp(hw, offset, data, false));
+}
+
+/*
+ * e1000_write_phy_reg_igp_locked - Write igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset.
+ * Assumes semaphore already acquired.
+ */
+s32
+e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return (__e1000_write_phy_reg_igp(hw, offset, data, true));
 }
 
 /*
- * e1000_read_kmrn_reg_generic - Read kumeran register
+ * __e1000_read_kmrn_reg - Read kumeran register
  * @hw: pointer to the HW structure
  * @offset: register offset to be read
  * @data: pointer to the read data
+ * @locked: semaphore has already been acquired or not
  *
- * Acquires semaphore, if necessary.  Then reads the PHY register at offset
- * using the kumeran interface.  The information retrieved is stored in data.
+ * Acquires semaphore, if necessary. Then reads the PHY register at offset
+ * using the kumeran interface. The information retrieved is stored in data.
  * Release any acquired semaphores before exiting.
  */
-s32
-e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data)
+static s32
+__e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data, bool locked)
 {
 	u32 kmrnctrlsta;
 	s32 ret_val = E1000_SUCCESS;
 
-	DEBUGFUNC("e1000_read_kmrn_reg_generic");
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
+	DEBUGFUNC("__e1000_read_kmrn_reg");
+
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
 
 	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
 	    E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
@@ -540,49 +619,117 @@
 	kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
 	*data = (u16)kmrnctrlsta;
 
-	hw->phy.ops.release(hw);
+	if (!locked)
+		hw->phy.ops.release(hw);
 
 out:
 	return (ret_val);
 }
 
 /*
- * e1000_write_kmrn_reg_generic - Write kumeran register
+ * e1000_read_kmrn_reg_generic -  Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore then reads the PHY register at offset using the
+ * kumeran interface.  The information retrieved is stored in data.
+ * Release the acquired semaphore before exiting.
+ */
+s32
+e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return (__e1000_read_kmrn_reg(hw, offset, data, false));
+}
+
+/*
+ * e1000_read_kmrn_reg_locked -  Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset using the kumeran interface.  The
+ * information retrieved is stored in data.
+ * Assumes semaphore already acquired.
+ */
+s32
+e1000_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return (__e1000_read_kmrn_reg(hw, offset, data, true));
+}
+
+/*
+ * __e1000_write_kmrn_reg - Write kumeran register
  * @hw: pointer to the HW structure
  * @offset: register offset to write to
  * @data: data to write at register offset
+ * @locked: semaphore has already been acquired or not
  *
  * Acquires semaphore, if necessary.  Then write the data to PHY register
  * at the offset using the kumeran interface.  Release any acquired semaphores
  * before exiting.
  */
-s32
-e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data)
+static s32
+__e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data, bool locked)
 {
 	u32 kmrnctrlsta;
 	s32 ret_val = E1000_SUCCESS;
 
 	DEBUGFUNC("e1000_write_kmrn_reg_generic");
 
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
+	if (!locked) {
+		if (!(hw->phy.ops.acquire))
+			goto out;
+
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			goto out;
+	}
 
 	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
 	    E1000_KMRNCTRLSTA_OFFSET) | data;
 	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
 
 	usec_delay(2);
-	hw->phy.ops.release(hw);
+
+	if (!locked)
+		hw->phy.ops.release(hw);
 
 out:
 	return (ret_val);
 }
 
 /*
+ * e1000_write_kmrn_reg_generic -  Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore then writes the data to the PHY register at the offset
+ * using the kumeran interface.  Release the acquired semaphore before exiting.
+ */
+s32
+e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return (__e1000_write_kmrn_reg(hw, offset, data, false));
+}
+
+/*
+ * e1000_write_kmrn_reg_locked -  Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Write the data to PHY register at the offset using the kumeran interface.
+ * Assumes semaphore already acquired.
+ */
+s32
+e1000_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return (__e1000_write_kmrn_reg(hw, offset, data, true));
+}
+
+/*
  * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link
  * @hw: pointer to the HW structure
  *
@@ -1863,8 +2010,7 @@
 			 */
 			usec_delay(usec_interval);
 		}
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
-		    &phy_status);
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
 		if (ret_val)
 			break;
 		if (phy_status & MII_SR_LINK_STATUS)
@@ -2460,15 +2606,16 @@
 
 	DEBUGFUNC("e1000_write_phy_reg_bm");
 
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
 	/* 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;
 	}
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
 
 	hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
 
@@ -2489,19 +2636,16 @@
 		/* Page is shifted left, PHY expects (page x 32) */
 		ret_val = e1000_write_phy_reg_mdic(hw, page_select,
 		    (page << page_shift));
-		if (ret_val) {
-			hw->phy.ops.release(hw);
+		if (ret_val)
 			goto out;
-		}
 	}
 
 	ret_val = e1000_write_phy_reg_mdic(hw,
 	    MAX_PHY_REG_ADDRESS & offset,
 	    data);
 
+out:
 	hw->phy.ops.release(hw);
-
-out:
 	return (ret_val);
 }
 
@@ -2525,15 +2669,16 @@
 
 	DEBUGFUNC("e1000_read_phy_reg_bm");
 
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
 	/* 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;
 	}
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
 
 	hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
 
@@ -2554,18 +2699,16 @@
 		/* Page is shifted left, PHY expects (page x 32) */
 		ret_val = e1000_write_phy_reg_mdic(hw, page_select,
 		    (page << page_shift));
-		if (ret_val) {
-			hw->phy.ops.release(hw);
+		if (ret_val)
 			goto out;
-		}
 	}
 
 	ret_val = e1000_read_phy_reg_mdic(hw,
 	    MAX_PHY_REG_ADDRESS & offset,
 	    data);
-	hw->phy.ops.release(hw);
 
 out:
+	hw->phy.ops.release(hw);
 	return (ret_val);
 }
 
@@ -2587,6 +2730,10 @@
 
 	DEBUGFUNC("e1000_write_phy_reg_bm2");
 
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
 	/* 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,
@@ -2594,10 +2741,6 @@
 		goto out;
 	}
 
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
 	hw->phy.addr = 1;
 
 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
@@ -2606,17 +2749,15 @@
 		ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
 		    page);
 
-		if (ret_val) {
-			hw->phy.ops.release(hw);
+		if (ret_val)
 			goto out;
-		}
 	}
 
 	ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
 	    data);
-	hw->phy.ops.release(hw);
 
 out:
+	hw->phy.ops.release(hw);
 	return (ret_val);
 }
 
@@ -2637,6 +2778,10 @@
 
 	DEBUGFUNC("e1000_write_phy_reg_bm2");
 
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
 	/* 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,
@@ -2644,10 +2789,6 @@
 		goto out;
 	}
 
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
 	hw->phy.addr = 1;
 
 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
@@ -2655,18 +2796,15 @@
 		ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
 		    page);
 
-		if (ret_val) {
-			hw->phy.ops.release(hw);
+		if (ret_val)
 			goto out;
-		}
 	}
 
 	ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
 	    data);
 
+out:
 	hw->phy.ops.release(hw);
-
-out:
 	return (ret_val);
 }
 
@@ -2686,6 +2824,8 @@
  * 3) Write the address using the address opcode (0x11)
  * 4) Read or write the data using the data opcode (0x12)
  * 5) Restore 769_17.2 to its original value
+ *
+ * Assumes semaphore already acquired.
  */
 static s32
 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw,
@@ -2694,7 +2834,6 @@
 	s32 ret_val;
 	u16 reg = BM_PHY_REG_NUM(offset);
 	u16 phy_reg = 0;
-	u8 phy_acquired = 1;
 
 	DEBUGFUNC("e1000_access_phy_wakeup_reg_bm");
 
@@ -2704,13 +2843,6 @@
 	    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) {
-		DEBUGOUT("Could not acquire PHY\n");
-		phy_acquired = 0;
-		goto out;
-	}
-
 	/* All operations in this function are phy address 1 */
 	hw->phy.addr = 1;
 
@@ -2781,8 +2913,6 @@
 	}
 
 out:
-	if (phy_acquired == 1)
-		hw->phy.ops.release(hw);
 	return (ret_val);
 }
 
@@ -2825,16 +2955,19 @@
 	msec_delay(1);
 }
 
+/*
+ * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
+ * @hw: pointer to the HW structure
+ * @slow: true for slow mode, false for normal mode
+ *
+ * Assumes semaphore already acquired.
+ */
 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,
@@ -2853,22 +2986,23 @@
 		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
+ * __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
+ * @locked: semaphore has already been acquired or not
  *
  * Acquires semaphore, if necessary, then reads the PHY register at offset
- * and storing the retrieved information in data.  Release any acquired
+ * and stores 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)
+static s32
+__e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data,
+    bool locked)
 {
 	s32 ret_val;
 	u16 page = BM_PHY_REG_PAGE(offset);
@@ -2877,6 +3011,12 @@
 
 	DEBUGFUNC("e1000_read_phy_reg_hv");
 
+	if (!locked) {
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			return (ret_val);
+	}
+
 	/* 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)) {
@@ -2900,10 +3040,6 @@
 		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)
@@ -2911,51 +3047,86 @@
 
 	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));
+		    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);
-
+	ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, data);
 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);
 
+	if (!locked)
+		hw->phy.ops.release(hw);
+
 	return (ret_val);
 }
 
 /*
- * e1000_write_phy_reg_hv - Write HV PHY register
+ * 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 then reads the PHY register at offset and stores
+ * the retrieved information in data.  Release the acquired semaphore
+ * before exiting.
+ */
+s32
+e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return (__e1000_read_phy_reg_hv(hw, offset, data, false));
+}
+
+/*
+ * e1000_read_phy_reg_hv_locked -  Read HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset and stores the retrieved information
+ * in data.  Assumes semaphore already acquired.
+ */
+s32
+e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return (__e1000_read_phy_reg_hv(hw, offset, data, true));
+}
+
+/*
+ * __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
+ * @locked: semaphore has already been acquired or not
  *
  * 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)
+static s32
+__e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
+    bool locked)
 {
 	s32 ret_val;
 	u16 page = BM_PHY_REG_PAGE(offset);
 	u16 reg = BM_PHY_REG_NUM(offset);
 	bool in_slow_mode = false;
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
 
 	DEBUGFUNC("e1000_write_phy_reg_hv");
 
+	if (!locked) {
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			return (ret_val);
+	}
+
 	/* 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)) {
@@ -2979,11 +3150,9 @@
 		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);
+	/* The LCD Config workaround provides the phy address to use */
+	if (dev_spec->nvm_lcd_config_enabled == false)
+		hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
 
 	if (page == HV_INTC_FC_PAGE_START)
 		page = 0;
@@ -2998,46 +3167,68 @@
 	    ((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));
+		    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);
 
+	if (!locked)
+		hw->phy.ops.release(hw);
+
 	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 then writes the data to PHY register at the offset.
+ * Release the acquired semaphores before exiting.
+ */
+s32
+e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return (__e1000_write_phy_reg_hv(hw, offset, data, false));
+}
+
+/*
+ * e1000_write_phy_reg_hv_locked - Write HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset.  Assumes semaphore
+ * already acquired.
+ */
+s32
+e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return (__e1000_write_phy_reg_hv(hw, offset, data, true));
+}
+
+/*
  * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page
  * @page: page to be accessed
  */
@@ -3059,10 +3250,9 @@
  * @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.
+ * Reads the PHY register at offset and stores the retreived information
+ * in data.  Assumes semaphore already acquired.  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,
@@ -3071,7 +3261,6 @@
 	s32 ret_val;
 	u32 addr_reg = 0;
 	u32 data_reg = 0;
-	u8  phy_acquired = 1;
 
 	DEBUGFUNC("e1000_access_phy_debug_regs_hv");
 
@@ -3080,13 +3269,6 @@
 	    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;
 
@@ -3109,8 +3291,6 @@
 	}
 
 out:
-	if (phy_acquired == 1)
-		hw->phy.ops.release(hw);
 	return (ret_val);
 }
 
--- a/usr/src/uts/common/io/e1000g/e1000_phy.h	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_phy.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.70 v3-1-3_2009-8-20
+ * IntelVersion: 1.74 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_PHY_H_
 #define	_E1000_PHY_H_
@@ -61,13 +61,17 @@
 s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw);
 s32 e1000_phy_setup_autoneg(struct e1000_hw *hw);
 s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data);
 s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data);
 s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
 s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active);
 s32 e1000_setup_copper_link_generic(struct e1000_hw *hw);
 s32 e1000_wait_autoneg_generic(struct e1000_hw *hw);
 s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data);
 s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data);
 s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
 s32 e1000_phy_reset_dsp(struct e1000_hw *hw);
 s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
@@ -84,7 +88,9 @@
 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_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data);
 s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_write_phy_reg_hv_locked(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);
@@ -173,6 +179,13 @@
 #define	BM_CS_STATUS_SPEED_MASK		0xC000
 #define	BM_CS_STATUS_SPEED_1000		0x8000
 
+/* 82577 Mobile Phy Status Register */
+#define	HV_M_STATUS			26
+#define	HV_M_STATUS_AUTONEG_COMPLETE	0x1000
+#define	HV_M_STATUS_SPEED_MASK		0x0300
+#define	HV_M_STATUS_SPEED_1000		0x0200
+#define	HV_M_STATUS_LINK_UP		0x0040
+
 #define	IGP01E1000_PHY_PCS_INIT_REG	0x00B4
 #define	IGP01E1000_PHY_POLARITY_MASK	0x0078
 
@@ -219,8 +232,7 @@
 #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	E1000_KMRNCTRLSTA_K1_ENABLE	0x0002
 
 #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	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000_regs.h	Tue Nov 10 11:52:20 2009 +0800
@@ -24,7 +24,7 @@
  */
 
 /*
- * IntelVersion: 1.76 v3-1-3_2009-8-20
+ * IntelVersion: 1.76 v3-1-10-1_2009-9-18_Release14-6
  */
 #ifndef _E1000_REGS_H_
 #define	_E1000_REGS_H_
--- a/usr/src/uts/common/io/e1000g/e1000g_main.c	Mon Nov 09 19:46:46 2009 -0800
+++ b/usr/src/uts/common/io/e1000g/e1000g_main.c	Tue Nov 10 11:52:20 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.16";
+static char e1000g_version[] = "Driver Ver. 5.3.17";
 
 /*
  * Proto types for DDI entry points